def SetupElectrostaticsImplicit(self, mesh, formulation, boundary_condition, material, fem_solver, solver, Eulerx, Increment): """setup implicit electrostatic problem """ from Florence import BoundaryCondition, FEMSolver, LaplacianSolver, IdealDielectric, AnisotropicIdealDielectric from Florence.VariationalPrinciple import LaplacianFormulation, ExplicitPenaltyContactFormulation # EMULATE ELECTROSTATICS MODEL emesh = deepcopy(mesh) if fem_solver.activate_explicit_multigrid: # WE GET THE MAX EPS - NOT ELEGANT BUT SEEMINGLY WORKS WELL eps_s = [] for key, value in list(material.__dict__.items()): if "eps" in key: eps_s.append(value) max_eps = max(eps_s) ematerial = IdealDielectric(emesh.InferSpatialDimension(), eps_1=max_eps) eanalysis_nature = "linear" eoptimise = True else: ematerial = deepcopy(material) ematerial.Hessian = ematerial.Permittivity ematerial.KineticMeasures = ematerial.ElectrostaticMeasures ematerial.H_VoigtSize = formulation.ndim ematerial.nvar = 1 ematerial.fields = "electrostatics" eanalysis_nature = "nonlinear" eoptimise = False # SET UP BOUNDARY CONDITION DURING SOLUTION eboundary_condition = BoundaryCondition() eformulation = LaplacianFormulation(mesh) efem_solver = FEMSolver( number_of_load_increments=1, analysis_nature=eanalysis_nature, newton_raphson_tolerance=fem_solver.newton_raphson_tolerance, optimise=eoptimise) self.emesh = emesh self.ematerial = ematerial self.eformulation = eformulation self.eboundary_condition = eboundary_condition self.efem_solver = efem_solver
def Solve(self, formulation=None, mesh=None, material=None, boundary_condition=None, function_spaces=None, solver=None, contact_formulation=None, Eulerx=None, Eulerp=None): from multiprocessing import Process, Pool, Manager, Queue from contextlib import closing from Florence.Tensor import in2d # CHECK DATA CONSISTENCY #---------------------------------------------------------------------------# self.parallel = True function_spaces, solver = self.__checkdata__( material, boundary_condition, formulation, mesh, function_spaces, solver, contact_formulation=contact_formulation) # MORE CHECKES if boundary_condition.neumann_flags is not None: raise NotImplementedError( "Problems with Neumann BC are not supported yet by detached solver" ) if boundary_condition.applied_neumann is not None: raise NotImplementedError( "Problems with Neumann BC are not supported yet by detached solver" ) #---------------------------------------------------------------------------# #---------------------------------------------------------------------------# self.PrintPreAnalysisInfo(mesh, formulation) #---------------------------------------------------------------------------# self.PartitionMeshForParallelFEM(mesh, self.no_of_cpu_cores, formulation.nvar) pmesh, pelement_indices, pnode_indices, partitioned_maps = self.pmesh, self.pelement_indices, \ self.pnode_indices, self.partitioned_maps ndim = mesh.InferSpatialDimension() if ndim == 3: boundary = mesh.faces elif ndim == 2: boundary = mesh.edges pboundary_conditions = [] for proc in range(self.no_of_cpu_cores): imesh = pmesh[proc] if ndim == 3: imesh.GetBoundaryFaces() boundary_normals = imesh.FaceNormals() else: imesh.GetBoundaryEdges() unit_outward_normals = imesh.Normals() pnodes = pnode_indices[proc] # APPLY BOUNDARY CONDITION COMING FROM BIG PROBLEM pboundary_condition = BoundaryCondition() pboundary_condition.dirichlet_flags = boundary_condition.dirichlet_flags[ pnodes, :] # CHECK IF THERE ARE REGIONS WHERE BOUNDARY CONDITITION IS NOT APPLIED AT ALL bc_not_applied = np.isnan( pboundary_condition.dirichlet_flags).all() if bc_not_applied: if self.force_solution: warn( "There are regions where BC will not be applied properly. Detached solution can be incorrect" ) else: raise RuntimeError( "There are regions where BC will not be applied properly. Detached solution can be incorrect" ) # FIND PARTITIONED INTERFACES if ndim == 3: pboundary = imesh.faces elif ndim == 2: pboundary = imesh.edges pboundary_mapped = pnodes[pboundary] boundaries_not_in_big_mesh = ~in2d( pboundary_mapped, boundary, consider_sort=True) normals_of_boundaries_not_in_big_mesh = unit_outward_normals[ boundaries_not_in_big_mesh, :] # IF NORMALS ARE NOT ORIENTED WITH X/Y/Z WE NEED CONTACT FORMULATION if self.force_solution is False: for i in range(ndim): if not np.all( np.logical_or( np.isclose(unit_outward_normals[:, i], 0.), np.isclose(np.abs(unit_outward_normals[:, i]), 1.))): raise RuntimeError( "Cannot run detached parallel solver as a contact formulation is needed" ) return local_interface_boundary = pboundary[boundaries_not_in_big_mesh] interface_nodes = np.unique(local_interface_boundary) if self.fix_interface: # FIXED BC self.interface_fixity = np.array(self.interface_fixity).ravel() for i in self.interface_fixity: pboundary_condition.dirichlet_flags[interface_nodes, i] = 0. else: # SYMMETRY BC symmetry_direction_to_fix_boundaries = np.nonzero( normals_of_boundaries_not_in_big_mesh)[1] symmetry_nodes_to_fix = local_interface_boundary.ravel() symmetry_direction_to_fix_nodes = np.repeat( symmetry_direction_to_fix_boundaries, local_interface_boundary.shape[1]) pboundary_condition.dirichlet_flags[ symmetry_nodes_to_fix, symmetry_direction_to_fix_nodes] = 0. # # LOOP APPROACH # for i in range(local_interface_boundary.shape[0]): # pboundary_condition.dirichlet_flags[local_interface_boundary[i,:],symmetry_direction_to_fix_boundaries[i]] = 0. pboundary_conditions.append(pboundary_condition) # TURN OFF PARALLELISATION self.parallel = False if self.save_incremental_solution is True: fname = deepcopy(self.incremental_solution_filename) fnames = [] for proc in range(self.no_of_cpu_cores): fnames.append(fname.split(".")[0] + "_proc" + str(proc)) self.parallel_model = "context_manager" if self.parallel_model == "context_manager": procs = [] manager = Manager() solutions = manager.dict() # SPAWNS A NEW PROCESS for proc in range(self.no_of_cpu_cores): if self.save_incremental_solution is True: self.incremental_solution_filename = fnames[proc] proc = Process( target=self.__DetachedFEMRunner_ContextManager__, args=(formulation, pmesh[proc], material, pboundary_conditions[proc], function_spaces, solver, contact_formulation, Eulerx, Eulerp, proc, solutions)) procs.append(proc) proc.start() for proc in procs: proc.join() elif self.parallel_model == "pool": # with closing(Pool(processes=fem_solver.no_of_cpu_cores)) as pool: # tups = pool.map(super(DetachedParallelFEMSolver, self).Solve,funcs) # pool.terminate() raise RuntimeError( "Pool based detached parallelism not implemented yet") elif self.parallel_model == "mpi": raise RuntimeError( "MPI based detached parallelism not implemented yet") else: # SERIAL procs = [] solutions = [0] * self.no_of_cpu_cores for proc in range(self.no_of_cpu_cores): if self.save_incremental_solution is True: self.incremental_solution_filename = fnames[proc] self.__DetachedFEMRunner_ContextManager__( formulation, pmesh[proc], material, pboundary_conditions[proc], function_spaces, solver, contact_formulation, Eulerx, Eulerp, proc, solutions) if not self.do_not_sync: # FIND COMMON AVAILABLE SOLUTION ACROSS ALL PARTITIONS min_nincr = 1e20 for proc in range(self.no_of_cpu_cores): incr = solutions[proc].sol.shape[2] if incr < min_nincr: min_nincr = incr TotalDisp = np.zeros( (mesh.points.shape[0], formulation.nvar, min_nincr)) for proc in range(self.no_of_cpu_cores): pnodes = pnode_indices[proc] TotalDisp[pnodes, :, :] = solutions[proc].sol[:, :, :min_nincr] return self.__makeoutput__(mesh, TotalDisp, formulation, function_spaces, material) else: return self.__makeoutput__(mesh, np.zeros_like(mesh.points), formulation, function_spaces, material)
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
eanalysis_nature = "linear" eoptimise = True else: ematerial = deepcopy(material) ematerial.Hessian = ematerial.Permittivity ematerial.KineticMeasures = ematerial.ElectrostaticMeasures ematerial.H_VoigtSize = formulation.ndim ematerial.nvar = 1 ematerial.fields = "electrostatics" eanalysis_nature = "nonlinear" eoptimise = False >>>>>>> upstream/master # SET UP BOUNDARY CONDITION DURING SOLUTION eboundary_condition = BoundaryCondition() eformulation = LaplacianFormulation(mesh) <<<<<<< HEAD efem_solver = FEMSolver(number_of_load_increments=1,analysis_nature="nonlinear", newton_raphson_tolerance=fem_solver.newton_raphson_tolerance) ======= efem_solver = FEMSolver(number_of_load_increments=1,analysis_nature=eanalysis_nature, newton_raphson_tolerance=fem_solver.newton_raphson_tolerance,optimise=eoptimise) >>>>>>> upstream/master self.emesh = emesh self.ematerial = ematerial self.eformulation = eformulation self.eboundary_condition = eboundary_condition self.efem_solver = efem_solver