Example #1
0
    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)
Example #3
0
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
Example #4
0
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