예제 #1
0
def SubdivisionCircle(center=(0., 0.),
                      radius=1.,
                      nrad=16,
                      ncirc=40,
                      element_type="tri",
                      refinement=False,
                      refinement_level=2):
    """Creates a mesh on circle using midpoint subdivision.
        This function is internally called from Mesh.Circle if
        'midpoint_subdivision' algorithm is selected
    """

    r = float(radius)
    h_r = float(radius) / 2.
    nx = int(ncirc / 4.)
    ny = int(nrad / 2.)

    if nx < 3:
        warn("Number of division in circumferential direction too low")

    mesh = Mesh()
    mesh.Rectangle(element_type="quad",
                   lower_left_point=(-1., -1.),
                   upper_right_point=(1., 1.),
                   nx=nx,
                   ny=ny)

    uv = np.array([
        [-1., -1],
        [1., -1],
        [1., 1],
        [-1., 1],
    ])

    t = np.pi / 4
    end_points = np.array([
        [-h_r * np.cos(t), h_r * np.sin(t)],
        [h_r * np.cos(t), h_r * np.sin(t)],
        [r * np.cos(t), r * np.sin(t)],
        [-r * np.cos(t), r * np.sin(t)],
    ])

    edge_points = mesh.points[np.unique(mesh.edges), :]

    new_end_points = []
    new_end_points.append(end_points[0, :])
    new_end_points.append(end_points[1, :])
    new_end_points.append(end_points[2, :])

    tt = np.linspace(np.pi / 4, 3 * np.pi / 4, nx)
    x = r * np.cos(tt)
    y = r * np.sin(tt)
    interp_p = np.vstack((x, y)).T

    for i in range(1, len(x) - 1):
        new_end_points.append([x[i], y[i]])
    new_end_points.append(end_points[3, :])
    new_end_points = np.array(new_end_points)

    new_uv = []
    new_uv.append(uv[0, :])
    new_uv.append(uv[1, :])
    new_uv.append(uv[2, :])

    L = 0.
    for i in range(1, interp_p.shape[0]):
        L += np.linalg.norm(interp_p[i, :] - interp_p[i - 1, :])

    interp_uv = []
    last_uv = uv[2, :]
    for i in range(1, interp_p.shape[0] - 1):
        val = (uv[3, :] - uv[2, :]) * np.linalg.norm(
            interp_p[i, :] - interp_p[i - 1, :]) / L + last_uv
        last_uv = np.copy(val)
        interp_uv.append(val)
    interp_uv = np.array(interp_uv)

    new_uv = np.array(new_uv)
    if interp_uv.shape[0] != 0:
        new_uv = np.vstack((new_uv, interp_uv))
    new_uv = np.vstack((new_uv, uv[3, :]))

    from Florence.FunctionSpace import MeanValueCoordinateMapping
    new_points = np.zeros_like(mesh.points)
    for i in range(mesh.nnode):
        point = MeanValueCoordinateMapping(mesh.points[i, :], new_uv,
                                           new_end_points)
        new_points[i, :] = point
    mesh.points = new_points

    rmesh = deepcopy(mesh)
    rmesh.points = mesh.Rotate(angle=np.pi / 2., copy=True)
    mesh += rmesh
    rmesh.points = rmesh.Rotate(angle=np.pi / 2., copy=True)
    mesh += rmesh
    rmesh.points = rmesh.Rotate(angle=np.pi / 2., copy=True)
    mesh += rmesh

    mesh.LaplacianSmoothing(niter=10)
    qmesh = Mesh()
    qmesh.Rectangle(element_type="quad",
                    lower_left_point=(-h_r * np.cos(t), -h_r * np.sin(t)),
                    upper_right_point=(h_r * np.cos(t), h_r * np.sin(t)),
                    nx=nx,
                    ny=nx)
    mesh += qmesh

    mesh.LaplacianSmoothing(niter=20)

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]

    if refinement:
        mesh.Refine(level=refinement_level)

    if element_type == "tri":
        sys.stdout = open(os.devnull, "w")
        mesh.ConvertQuadsToTris()
        sys.stdout = sys.__stdout__

    return mesh
예제 #2
0
def QuadBallSurface(center=(0., 0., 0.), radius=1., n=10, element_type="quad"):
    """Creates a surface quad mesh on sphere using midpoint subdivision algorithm
        by creating a cube and spherifying it using PostMesh's projection schemes.
        Unlike the volume QuadBall method there is no restriction on number of divisions
        here as no system of equations is solved

        inputs:

            n:                          [int] number of divsion in every direction.
                                        Given that this implementation is based on
                                        high order bases different divisions in
                                        different directions is not possible
    """

    try:
        from Florence import Mesh, BoundaryCondition, DisplacementFormulation, FEMSolver, LinearSolver
        from Florence import LinearElastic, NeoHookean
        from Florence.Tensor import prime_number_factorisation
    except ImportError:
        raise ImportError("This function needs Florence's core support")

    n = int(n)
    if not isinstance(center, tuple):
        raise ValueError(
            "The center of the circle should be given in a tuple with two elements (x,y,z)"
        )
    if len(center) != 3:
        raise ValueError(
            "The center of the circle should be given in a tuple with two elements (x,y,z)"
        )

    if n == 2 or n == 3 or n == 5 or n == 7:
        ps = [n]
    else:

        def factorise_all(n):
            if n < 2:
                n = 2
            factors = prime_number_factorisation(n)
            if len(factors) == 1 and n > 2:
                n += 1
                factors = prime_number_factorisation(n)
            return factors

        factors = factorise_all(n)
        ps = []
        for factor in factors:
            ps += factorise_all(factor)

    # Do high ps first
    ps = np.sort(ps)[::-1].tolist()
    niter = len(ps)

    sphere_igs_file_content = SphereIGS()
    with open("sphere_cad_file.igs", "w") as f:
        f.write(sphere_igs_file_content)

    sys.stdout = open(os.devnull, "w")

    ndim = 3
    scale = 1000.
    condition = 1.e020

    mesh = Mesh()
    material = LinearElastic(ndim, mu=1., lamb=4.)

    for it in range(niter):

        if it == 0:
            mesh.Parallelepiped(element_type="hex",
                                nx=1,
                                ny=1,
                                nz=1,
                                lower_left_rear_point=(-0.5, -0.5, -0.5),
                                upper_right_front_point=(0.5, 0.5, 0.5))
            mesh = mesh.CreateSurface2DMeshfrom3DMesh()
            mesh.GetHighOrderMesh(p=ps[it], equally_spaced=True)
            mesh = mesh.CreateDummy3DMeshfrom2DMesh()
            formulation = DisplacementFormulation(mesh)
        else:
            mesh.GetHighOrderMesh(p=ps[it], equally_spaced=True)
            mesh = mesh.CreateDummy3DMeshfrom2DMesh()

        boundary_condition = BoundaryCondition()
        boundary_condition.SetCADProjectionParameters(
            "sphere_cad_file.igs",
            scale=scale,
            condition=condition,
            project_on_curves=True,
            solve_for_planar_faces=True,
            modify_linear_mesh_on_projection=True,
            fix_dof_elsewhere=False)
        boundary_condition.GetProjectionCriteria(mesh)
        nodesDBC, Dirichlet = boundary_condition.PostMeshWrapper(
            formulation, mesh, None, None, FEMSolver())

        mesh.points[nodesDBC.ravel(), :] += Dirichlet
        mesh = mesh.CreateSurface2DMeshfrom3DMesh()
        mesh = mesh.ConvertToLinearMesh()

    os.remove("sphere_cad_file.igs")

    if not np.isclose(radius, 1):
        mesh.points *= radius

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]
    mesh.points[:, 2] += center[2]

    if element_type == "tri":
        mesh.ConvertQuadsToTris()

    sys.stdout = sys.__stdout__

    return mesh
예제 #3
0
def SubdivisionArc(center=(0., 0.),
                   radius=1.,
                   nrad=16,
                   ncirc=40,
                   start_angle=0.,
                   end_angle=np.pi / 2.,
                   element_type="tri",
                   refinement=False,
                   refinement_level=2):
    """Creates a mesh on circle using midpoint subdivision.
        This function is internally called from Mesh.Circle if
        'midpoint_subdivision' algorithm is selected
    """

    if start_angle != 0. and end_angle != np.pi / 2.:
        raise ValueError(
            "Subdivision based arc only produces meshes for a quarter-circle arc for now"
        )

    r = float(radius)
    h_r = float(radius) / 2.
    nx = int(ncirc / 4.)
    ny = int(nrad / 2.)

    if nx < 3:
        warn("Number of division in circumferential direction too low")

    mesh = Mesh()
    mesh.Rectangle(element_type="quad",
                   lower_left_point=(-1., -1.),
                   upper_right_point=(1., 1.),
                   nx=nx,
                   ny=ny)

    uv = np.array([
        [-1., -1],
        [1., -1],
        [1., 1],
        [-1., 1],
    ])

    t = np.pi / 4.
    end_points = np.array([
        [0., h_r * np.sin(t)],
        [h_r * np.cos(t), h_r * np.sin(t)],
        [r * np.cos(t), r * np.sin(t)],
        [0., radius],
    ])

    edge_points = mesh.points[np.unique(mesh.edges), :]

    new_end_points = []
    new_end_points.append(end_points[0, :])
    new_end_points.append(end_points[1, :])
    new_end_points.append(end_points[2, :])

    tt = np.linspace(np.pi / 4, np.pi / 2, nx)
    x = r * np.cos(tt)
    y = r * np.sin(tt)
    interp_p = np.vstack((x, y)).T

    for i in range(1, len(x) - 1):
        new_end_points.append([x[i], y[i]])
    new_end_points.append(end_points[3, :])
    new_end_points = np.array(new_end_points)

    new_uv = []
    new_uv.append(uv[0, :])
    new_uv.append(uv[1, :])
    new_uv.append(uv[2, :])

    L = 0.
    for i in range(1, interp_p.shape[0]):
        L += np.linalg.norm(interp_p[i, :] - interp_p[i - 1, :])

    interp_uv = []
    last_uv = uv[2, :]
    for i in range(1, interp_p.shape[0] - 1):
        val = (uv[3, :] - uv[2, :]) * np.linalg.norm(
            interp_p[i, :] - interp_p[i - 1, :]) / L + last_uv
        last_uv = np.copy(val)
        interp_uv.append(val)
    interp_uv = np.array(interp_uv)

    new_uv = np.array(new_uv)
    if interp_uv.shape[0] != 0:
        new_uv = np.vstack((new_uv, interp_uv))
    new_uv = np.vstack((new_uv, uv[3, :]))

    from Florence.FunctionSpace import MeanValueCoordinateMapping
    new_points = np.zeros_like(mesh.points)
    # All nodes barring the ones lying on the arc
    for i in range(mesh.nnode - nx - 1):
        point = MeanValueCoordinateMapping(mesh.points[i, :], new_uv,
                                           new_end_points)
        new_points[i, :] = point
    # The nodes on the arc are not exactly on the arc
    # so they need to be snapped/clipped
    tt = np.linspace(np.pi / 4, np.pi / 2, nx + 1)[::-1]
    x = r * np.cos(tt)
    y = r * np.sin(tt)
    new_points[mesh.nnode - nx - 1:, :] = np.vstack((x, y)).T
    mesh.points = new_points

    rmesh = deepcopy(mesh)
    rmesh.points = mesh.Rotate(angle=-np.pi / 2., copy=True)
    rmesh.points[:, 1] *= -1.
    mesh += rmesh

    mesh.LaplacianSmoothing(niter=10)
    qmesh = Mesh()
    qmesh.Rectangle(element_type="quad",
                    lower_left_point=(0.0, 0.0),
                    upper_right_point=(h_r * np.cos(t), h_r * np.sin(t)),
                    nx=nx,
                    ny=nx)
    mesh += qmesh

    # mesh.LaplacianSmoothing(niter=20)
    NodeSliderSmootherArc(mesh, niter=20)

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]

    if refinement:
        mesh.Refine(level=refinement_level)

    if element_type == "tri":
        sys.stdout = open(os.devnull, "w")
        mesh.ConvertQuadsToTris()
        sys.stdout = sys.__stdout__

    return mesh