Exemplo n.º 1
0
def HighOrderMeshTet_SEMISTABLE(C,
                                mesh,
                                Decimals=10,
                                equally_spaced=False,
                                check_duplicates=True,
                                parallelise=False,
                                nCPU=1,
                                compute_boundary_info=True):

    from Florence.FunctionSpace import Tet
    from Florence.QuadratureRules.FeketePointsTet import FeketePointsTet
    from Florence.MeshGeneration.NodeArrangement import NodeArrangementTet

    # SWITCH OFF MULTI-PROCESSING FOR SMALLER PROBLEMS WITHOUT GIVING A MESSAGE
    Parallel = parallelise
    if (mesh.elements.shape[0] < 500) and (C < 5):
        Parallel = False
        nCPU = 1

    if not equally_spaced:
        eps = FeketePointsTet(C)
        # COMPUTE BASES FUNCTIONS AT ALL NODAL POINTS
        Neval = np.zeros((4, eps.shape[0]), dtype=np.float64)
        hpBases = Tet.hpNodal.hpBases
        for i in range(4, eps.shape[0]):
            Neval[:, i] = hpBases(0,
                                  eps[i, 0],
                                  eps[i, 1],
                                  eps[i, 2],
                                  Transform=1,
                                  EvalOpt=1)[0]
    else:
        from Florence.QuadratureRules.EquallySpacedPoints import EquallySpacedPointsTet
        eps = EquallySpacedPointsTet(C)
        # COMPUTE BASES FUNCTIONS AT ALL NODAL POINTS
        hpBases = Tet.hpNodal.hpBases
        Neval = np.zeros((4, eps.shape[0]), dtype=np.float64)
        for i in range(4, eps.shape[0]):
            Neval[:, i] = hpBases(0,
                                  eps[i, 0],
                                  eps[i, 1],
                                  eps[i, 2],
                                  Transform=1,
                                  EvalOpt=1,
                                  equally_spaced=True)[0]

    # THIS IS NECESSARY FOR REMOVING DUPLICATES
    makezero(Neval, tol=1e-12)

    nodeperelem = mesh.elements.shape[1]
    renodeperelem = int((C + 2.) * (C + 3.) * (C + 4.) / 6.)
    left_over_nodes = renodeperelem - nodeperelem

    reelements = -1 * np.ones(
        (mesh.elements.shape[0], renodeperelem), dtype=np.int64)
    reelements[:, :4] = mesh.elements
    # TOTAL NUMBER OF (INTERIOR+EDGE+FACE) NODES
    iesize = np.int64(C * (C - 1) * (C - 2) / 6. + 6. * C + 2 * C * (C - 1))
    repoints = np.zeros(
        (mesh.points.shape[0] + iesize * mesh.elements.shape[0], 3),
        dtype=np.float64)
    repoints[:mesh.points.shape[0], :] = mesh.points

    telements = time()

    xycoord_higher = []
    ParallelTuple1 = []
    if Parallel:
        # GET HIGHER ORDER COORDINATES - PARALLEL
        ParallelTuple1 = parmap.map(ElementLoopTet,
                                    np.arange(0, mesh.elements.shape[0]),
                                    mesh.elements,
                                    mesh.points,
                                    'tet',
                                    eps,
                                    Neval,
                                    pool=MP.Pool(processes=nCPU))

    maxNode = np.max(reelements)
    for elem in range(0, mesh.elements.shape[0]):
        # maxNode = np.max(reelements) # BIG BOTTLENECK
        if Parallel:
            xycoord_higher = ParallelTuple1[elem]
        else:
            xycoord = mesh.points[mesh.elements[elem, :], :]
            # GET HIGHER ORDER COORDINATES
            xycoord_higher = GetInteriorNodesCoordinates(
                xycoord, 'tet', elem, eps, Neval)

        # EXPAND THE ELEMENT CONNECTIVITY
        newElements = np.arange(maxNode + 1, maxNode + 1 + left_over_nodes)
        reelements[elem, 4:] = newElements
        # INSTEAD COMPUTE maxNode BY INDEXING
        maxNode = newElements[-1]

        repoints[mesh.points.shape[0] + elem * iesize:mesh.points.shape[0] +
                 (elem + 1) * iesize] = xycoord_higher[4:, :]

    if Parallel:
        del ParallelTuple1

    telements = time() - telements
    #--------------------------------------------------------------------------------------
    # NOW REMOVE DUPLICATED POINTS
    tnodes = time()

    nnode_linear = mesh.points.shape[0]
    # KEEP ZEROFY ON, OTHERWISE YOU GET STRANGE BEHVAIOUR
    # rounded_repoints = makezero(repoints[nnode_linear:,:].copy())
    rounded_repoints = repoints[nnode_linear:, :].copy()
    makezero(rounded_repoints)
    rounded_repoints = np.round(rounded_repoints, decimals=Decimals)

    _, idx_repoints, inv_repoints = unique2d(rounded_repoints,
                                             order=False,
                                             consider_sort=False,
                                             return_index=True,
                                             return_inverse=True)
    # idx_repoints.sort()
    del rounded_repoints

    idx_repoints = np.concatenate(
        (np.arange(nnode_linear), idx_repoints + nnode_linear))
    repoints = repoints[idx_repoints, :]

    unique_reelements, inv_reelements = np.unique(reelements[:, 4:],
                                                  return_inverse=True)
    unique_reelements = unique_reelements[inv_repoints]
    reelements = unique_reelements[inv_reelements]
    reelements = reelements.reshape(mesh.elements.shape[0], renodeperelem - 4)
    reelements = np.concatenate((mesh.elements, reelements), axis=1)

    # SANITY CHECK fOR DUPLICATES
    #---------------------------------------------------------------------#
    # NOTE THAT THIS REMAPS THE ELEMENT CONNECTIVITY FOR THE WHOLE MESH
    # AND AS A RESULT THE FIRST FEW COLUMNS WOULD NO LONGER CORRESPOND TO
    # LINEAR CONNECTIVITY
    if check_duplicates:
        last_shape = repoints.shape[0]
        deci = int(Decimals) - 2
        if Decimals < 6:
            deci = Decimals
        repoints, idx_repoints, inv_repoints = remove_duplicates_2D(
            repoints, decimals=deci)
        unique_reelements, inv_reelements = np.unique(reelements,
                                                      return_inverse=True)
        unique_reelements = unique_reelements[inv_repoints]
        reelements = unique_reelements[inv_reelements]
        reelements = reelements.reshape(mesh.elements.shape[0], renodeperelem)
        if last_shape != repoints.shape[0]:
            warn(
                'Duplicated points generated in high order mesh. Lower the "Decimals". I have fixed it for now'
            )
    #---------------------------------------------------------------------#

    tnodes = time() - tnodes
    #------------------------------------------------------------------------------------------

    #------------------------------------------------------------------------------------------
    if compute_boundary_info:
        # BUILD FACES NOW
        tfaces = time()
        # GET MESH EDGES AND FACES
        fsize = int((C + 2.) * (C + 3.) / 2.)
        refaces = np.zeros((mesh.faces.shape[0], fsize),
                           dtype=mesh.faces.dtype)

        refaces = np.zeros((mesh.faces.shape[0], fsize))
        # DO NOT CHANGE THE FACES, BY RECOMPUTING THEM, AS THE LINEAR FACES CAN COME FROM
        # AN EXTERNAL MESH GENERATOR, WHOSE ORDERING MAY NOT BE THE SAME, SO JUST FIND WHICH
        # ELEMENTS CONTAIN THESE FACES
        face_to_elements = mesh.GetElementsWithBoundaryFacesTet()
        node_arranger = NodeArrangementTet(C)[0]

        refaces = reelements[face_to_elements[:, 0][:, None],
                             node_arranger[face_to_elements[:, 1], :]].astype(
                                 mesh.faces.dtype)

        tfaces = time() - tfaces
        #------------------------------------------------------------------------------------------

        #------------------------------------------------------------------------------------------
        # BUILD EDGES NOW
        tedges = time()

        # BUILD A 2D MESH
        from Florence import Mesh
        tmesh = Mesh()
        tmesh.element_type = "tri"
        tmesh.elements = refaces
        tmesh.nelem = tmesh.elements.shape[0]
        # GET BOUNDARY EDGES
        reedges = tmesh.GetEdgesTri()
        del tmesh

        tedges = time() - tedges
    #------------------------------------------------------------------------------------------

    class nmesh(object):
        # """Construct pMesh"""
        points = repoints
        elements = reelements
        edges = np.array([[], []])
        faces = np.array([[], []])
        nnode = repoints.shape[0]
        nelem = reelements.shape[0]
        info = 'tet'

    if compute_boundary_info:
        nmesh.edges = reedges
        nmesh.faces = refaces

    gc.collect()

    # print '\nHigh order meshing timing:\n\t\tElement loop:\t '+str(telements)+' seconds\n\t\tNode loop:\t\t '+str(tnodes)+\
    #  ' seconds'+'\n\t\tEdge loop:\t\t '+str(tedges)+' seconds'+\
    #  '\n\t\tFace loop:\t\t '+str(tfaces)+' seconds\n'

    return nmesh
Exemplo n.º 2
0
def test_BEM():
    """Unnecessary test for the ugly and non-working and legacy BEM
        for the sake of coverage
    """


    from Florence.BoundaryElements import GetBasesBEM2D
    from Florence.BoundaryElements import GenerateCoordinates
    from Florence.BoundaryElements import CoordsJacobianRadiusatGaussPoints, CoordsJacobianRadiusatGaussPoints_LM
    from Florence.BoundaryElements import AssemblyBEM2D
    from Florence.BoundaryElements.Assembly import AssemblyBEM2D_Sparse
    from Florence.BoundaryElements import Sort_BEM
    from Florence import QuadratureRule, FunctionSpace, Mesh

    # Unnecessary loop
    for i in range(10):

        mesh = Mesh()
        mesh.element_type = "line"
        mesh.points = np.array([
            [0.,0.],
            [1.,0.],
            [1.,1.],
            [0.,1.],
            ])
        mesh.elements = np.array([
            [0,1],
            [1,2],
            [2,3],
            [3,0],
            ])
        mesh.nelem = 4



        q = QuadratureRule(mesh_type="line")
        for C in range(10):
            N, dN = GetBasesBEM2D(C,q.points)

        N, dN = GetBasesBEM2D(2,q.points)
        global_coord = np.zeros((mesh.points.shape[0],3))
        global_coord[:,:2] = mesh.points
        Jacobian = 2*np.ones((q.weights.shape[0],mesh.nelem))
        nx = 4*np.ones((q.weights.shape[0],mesh.nelem))
        ny = 3*np.ones((q.weights.shape[0],mesh.nelem))
        XCO = 2*np.ones((q.weights.shape[0],mesh.nelem))
        YCO = np.ones((q.weights.shape[0],mesh.nelem))
        N = np.ones((mesh.elements.shape[1],q.weights.shape[0]))
        dN = 0.5*np.ones((mesh.elements.shape[1],q.weights.shape[0]))
        
        GenerateCoordinates(mesh.elements,mesh.points,0,q.points)
        CoordsJacobianRadiusatGaussPoints(mesh.elements,global_coord,0,N,dN,q.weights)
        # Not working
        # CoordsJacobianRadiusatGaussPoints_LM(mesh.elements,global_coord[:,:3],0,N,dN,q.weights,mesh.elements)

        class GeoArgs(object):
            Lagrange_Multipliers = "activated"
            def __init__(self):
                Lagrange_Multipliers = "activated"

        geo_args = GeoArgs()
        K1, K2 = AssemblyBEM2D(0,global_coord,mesh.elements,mesh.elements,dN,N,
            q.weights,q.points,Jacobian, nx, ny, XCO, YCO, geo_args)
        AssemblyBEM2D_Sparse(0,global_coord,mesh.elements,mesh.elements,dN,N,
            q.weights,q.points,Jacobian, nx, ny, XCO, YCO, geo_args)

        bdata = np.zeros((2*mesh.points.shape[0],2))
        bdata[:4,1] = -1
        bdata[4:,0] = -1
        Sort_BEM(bdata,K1, K2)
Exemplo n.º 3
0
def QuadBallSphericalArc(center=(0., 0., 0.),
                         inner_radius=9.,
                         outer_radius=10.,
                         n=10,
                         nthick=1,
                         element_type="hex",
                         cut_threshold=None,
                         portion=1. / 8.):
    """Similar to QuadBall but hollow and creates only 1/8th or 1/4th or 1/2th of the sphere.
        Starting and ending angles are not supported. Radial division (nthick: to be consistent
        with SphericalArc method of Mesh class) is supported

        input:
            cut_threshold               [float] cutting threshold for element removal since this function is based
                                        QuadBall. Ideal value is zero, so prescribe a value as close to zero
                                        as possible, however that might not always be possible as the cut
                                        might take remove some wanted elements [default = -0.01]
            portion                     [float] portion of the sphere to take. Can only be 1/8., 1/4., 1/2.
    """

    assert inner_radius < outer_radius

    mm = QuadBallSurface(n=n, element_type=element_type)

    offset = outer_radius * 2.
    if cut_threshold is None:
        cut_threshold = -0.01
    if portion == 1. / 8.:
        mm.RemoveElements(
            np.array([[cut_threshold, cut_threshold, cut_threshold],
                      [offset, offset, offset]]))
    elif portion == 1. / 4.:
        mm.RemoveElements(
            np.array([[cut_threshold, cut_threshold, -offset],
                      [offset, offset, offset]]))
    elif portion == 1. / 2.:
        mm.RemoveElements(
            np.array([[cut_threshold, -offset, -offset],
                      [offset, offset, offset]]))
    else:
        raise ValueError("The value of portion can only be 1/8., 1/4. or 1/2.")

    radii = np.linspace(inner_radius, outer_radius, nthick + 1)

    mesh = Mesh()
    mesh.element_type = "hex"
    mesh.nelem = 0
    mesh.nnode = 0

    for i in range(nthick):
        mm1, mm2 = deepcopy(mm), deepcopy(mm)
        if not np.isclose(radii[i], 1):
            mm1.points *= radii[i]
        if not np.isclose(radii[i + 1], 1):
            mm2.points *= radii[i + 1]

        if i == 0:
            elements = np.hstack(
                (mm1.elements, mm1.nnode + mm2.elements)).astype(np.int64)
            mesh.elements = np.copy(elements)
            mesh.points = np.vstack((mm1.points, mm2.points))
        else:
            elements = np.hstack(
                (mesh.elements[(i - 1) * mm2.nelem:i * mm2.nelem, 4:],
                 mesh.nnode + mm2.elements)).astype(np.int64)
            mesh.elements = np.vstack((mesh.elements, elements))
            mesh.points = np.vstack((mesh.points, mm2.points))
        mesh.nelem = mesh.elements.shape[0]
        mesh.nnode = mesh.points.shape[0]

    mesh.elements = np.ascontiguousarray(mesh.elements, dtype=np.int64)
    mesh.nelem = mesh.elements.shape[0]
    mesh.nnode = mesh.points.shape[0]
    mesh.GetBoundaryFaces()
    mesh.GetBoundaryEdges()

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

    return mesh
Exemplo n.º 4
0
        print("The problem requires 2D analyses. Solving", number_of_planar_surfaces, "2D problems")
        for niter in range(number_of_planar_surfaces):

            pmesh = Mesh()
            if mesh.element_type == "tet":
                pmesh.element_type = "tri"
                no_face_vertices = 3
            elif mesh.element_type == "hex":
                pmesh.element_type = "quad"
                no_face_vertices = 4
            else:
                raise ValueError("Curvilinear mesher for element type {} not yet implemented".format(mesh.element_type))

            pmesh.elements = mesh.faces[planar_mesh_faces[planar_mesh_faces[:,1]==surface_flags[niter,0],0],:]
            pmesh.nelem = np.int64(surface_flags[niter,1])
            pmesh.GetBoundaryEdges()
            unique_edges = np.unique(pmesh.edges).astype(nodesDBC.dtype)
            # Dirichlet2D = np.zeros((unique_edges.shape[0],3))
            # nodesDBC2D = np.zeros(unique_edges.shape[0]).astype(np.int64)

            unique_elements, inv  = np.unique(pmesh.elements, return_inverse=True)
            unique_elements = unique_elements.astype(nodesDBC.dtype)
            aranger = np.arange(unique_elements.shape[0],dtype=np.uint64)
            pmesh.elements = aranger[inv].reshape(pmesh.elements.shape)

            # counter = 0
            # for i in unique_edges:
            #     nodesDBC2D[counter] = np.where(nodesDBC==i)[0][0]
            #     Dirichlet2D[counter,:] = Dirichlet[nodesDBC2D[counter],:]
            #     counter += 1