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 QuadBall(center=(0., 0., 0.), radius=1., n=10, element_type="hex"): """Creates a fully hexahedral mesh on sphere using midpoint subdivision algorithm by creating a cube and spherifying it using PostMesh's projection schemes 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 n > 50: # Values beyond this result in >1M DoFs due to internal prime factoristaion splitting raise ValueError( "The value of n={} (division in each direction) is too high". format(str(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) # IGS file for sphere with radius 1000. 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.) # Keep the solver iterative for low memory consumption. All boundary points are Dirichlet BCs # so they will be exact anyway solver = LinearSolver(linear_solver="iterative", linear_solver_type="cg2", dont_switch_solver=True, iterative_solver_tolerance=1e-9) 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.GetHighOrderMesh(p=ps[it], equally_spaced=True) 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) formulation = DisplacementFormulation(mesh) fem_solver = FEMSolver(number_of_load_increments=1, analysis_nature="linear", force_not_computing_mesh_qualities=True, report_log_level=0, optimise=True) solution = fem_solver.Solve(formulation=formulation, mesh=mesh, material=material, boundary_condition=boundary_condition, solver=solver) mesh.points += solution.sol[:, :, -1] 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 == "tet": mesh.ConvertHexesToTets() sys.stdout = sys.__stdout__ return mesh