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