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
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)
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
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