Esempio n. 1
0
    def genericAuxiliaryProblem(self, Fload, Epsilon0):
        """
        This function compute the auxiliary problem of order N
        given the sources (of auxiliary problem N-1).

        It returns new localizations
        """

        U2 = []
        S2 = []
        E2 = []
        for i in range(len(Fload)):
            logger.info(f"Progression : load {i+1} / {len(Fload)}")
            L = (fe.dot(Fload[i], self.v) + fe.inner(
                -sigma(self.rve.C_per, Epsilon0[i]), epsilon(self.v))) * fe.dx

            # u_s = fe.Function(self.V)
            res = fe.assemble(L)
            # self.bc.apply(res) #TODO à tester. Pas nécessaire pour le moment, la ligne # K,res = fe.assemble_system(self.a,L,self.bc) était commentée.
            # self.solver.solve(K, u_s.vector(), res) #* Previous method
            self.solver.solve(self.w.vector(), res)
            # * More info : https://fenicsproject.org/docs/dolfin/1.5.0/python/programmers-reference/cpp/la/PETScLUSolver.html

            u_only = fe.interpolate(self.w.sub(0), self.V)
            # ? Essayer de faire fe.assign(self.u_only, self.w.sub(0)) ?
            # ? Pour le moment u_only vit dans V et V n'est pas extrait
            # ? de l'espace fonctionnel mixte. Est-ce que cela marcherait si V
            # ? est extrait de M ?
            U2.append(u_only)
            eps = epsilon(u_only) + Epsilon0[i]
            E2.append(local_project(eps, self.W))
            S2.append(local_project(sigma(self.rve.C_per, eps), self.W))
            # TODO : Comparer les options :
            # TODO         e2 = fe.Function(self.W); e2.assign(self.RVE.epsilon(u_s) + Epsilon0[i])
            # TODO         interpolation
            # TODO         projection (locale)

        return U2, S2, E2
Esempio n. 2
0
    def solve(self, results_file=None):
        if self.solver is None:
            logger.warning("The solver has to be set.")
        if self.load_integrals is not None:
            L_terms = []
            for contrib_list in self.load_integrals.values():
                L_terms += contrib_list
            L = sum(L_terms)
        else:
            zero = fe.Constant(np.zeros(shape=self.v.ufl_shape))
            L = fe.dot(zero, self.v) * self.measures[self.part.dim]

        logger.info("Assembling system...")
        K, res = fe.assemble_system(self.a, L, self.Dirichlet_bc)
        logger.info("Assembling system : done")
        self.u_sol = fe.Function(self.displ_fspace)
        logger.info("Solving system...")
        self.solver.solve(K, self.u_sol.vector(), res)
        logger.info("Solving system : done")
        logger.info("Computing strain solution...")
        eps = mat.epsilon(self.u_sol)
        self.eps_sol = local_project(eps,
                                     self.strain_fspace,
                                     solver_method="LU")
        logger.info("Saving results...")
        if results_file is not None:
            try:
                if results_file.suffix != ".xdmf":
                    results_file = results_file.with_suffix(".xdmf")
            except AttributeError:
                results_file = Path(results_file).with_suffix(".xdmf")
            with fe.XDMFFile(results_file.as_posix()) as ofile:
                ofile.parameters["flush_output"] = False
                ofile.parameters["functions_share_mesh"] = True
                self.u_sol.rename("displacement",
                                  "displacement solution, full scale problem")
                self.eps_sol.rename("strain",
                                    "strain solution, full scale problem")
                ofile.write(self.u_sol, 0.0)
                ofile.write(self.eps_sol, 0.0)
        return self.u_sol
Esempio n. 3
0
    def __init__(self, fenics_2d_part, loads, boundary_conditions, element):
        """

        The FacetFunction must be the same for all BC and facet loads. Its type of value must be 'size_t' (unsigned integers).

        Parameters
        ----------
        fenics_2d_part : FEnicsPart
            [description]
        loads : [type]
            [description]
        boundary_conditions : list or tuple
            All the boundary conditions.
            Each of them is describe by a tuple or a dictionnary.
            Only one periodic BC can be prescribed.
            Format:
                if Periodic BC :
                    {'type': 'Periodic', 'constraint': PeriodicDomain}
                    or
                    ('Periodic', PeriodicDomain)
                if Dirichlet BC :
                    {
                        'type': 'Dirichlet',
                        'constraint': the prescribed value,
                        'facet_function': facet function,
                        'facet_idx': facet function index}
                    or
                    ('Dirichlet', the prescribed value, facet function, facet function index)
                    or
                    ('Dirichlet', the prescribed value, indicator function)
                        where the indicator function is python function like :
                        def clamped(x, on_boundary):
                            return on_boundary and x[0] < tolerance
        element: tuple or dict
        Ex: ('CG', 2) or {'family':'Lagrange', degree:2}
        """
        self.part = fenics_2d_part

        # * Boundary conditions
        self.per_bc = None
        self.Dirichlet_bc = list()
        for bc in boundary_conditions:
            if isinstance(bc, dict):
                bc_ = bc
                bc = [bc_["type"], bc_["constraint"]]
                try:
                    bc.append(bc_["facet_function"])
                    bc.append(bc_["facet_idx"])
                except KeyError:
                    pass
            bc_type, *bc_data = bc
            if bc_type == "Periodic":
                if self.per_bc is not None:
                    raise AttributeError(
                        "Only one periodic boundary condition can be prescribed."
                    )
                self.per_bc = bc_data[0]
            elif bc_type == "Dirichlet":
                if len(bc_data) == 2 or len(bc_data) == 3:
                    bc_data = tuple(bc_data)
                else:
                    raise AttributeError(
                        "Too much parameter for the definition of a Dirichlet BC."
                    )
                self.Dirichlet_bc.append(bc_data)

        self.measures = {self.part.dim: fe.dx, self.part.dim - 1: fe.ds}

        # * Function spaces
        try:
            self.elmt_family = family = element["family"]
            self.elmt_degree = degree = element["degree"]
        except TypeError:  # Which means that element is not a dictionnary
            self.element_family, self.element_degree = element
            family, degree = element
        cell = self.part.mesh.ufl_cell()
        Voigt_strain_dim = int(self.part.dim * (self.part.dim + 1) / 2)
        strain_deg = degree - 1 if degree >= 1 else 0
        strain_FE = fe.VectorElement("DG",
                                     cell,
                                     strain_deg,
                                     dim=Voigt_strain_dim)
        self.scalar_fspace = fe.FunctionSpace(
            self.part.mesh,
            fe.FiniteElement(family, cell, degree),
            constrained_domain=self.per_bc,
        )
        self.displ_fspace = fe.FunctionSpace(
            self.part.mesh,
            fe.VectorElement(family, cell, degree, dim=self.part.dim),
            constrained_domain=self.per_bc,
        )
        self.strain_fspace = fe.FunctionSpace(self.part.mesh,
                                              strain_FE,
                                              constrained_domain=self.per_bc)

        self.v = fe.TestFunction(self.displ_fspace)
        self.u = fe.TrialFunction(self.displ_fspace)
        self.a = (fe.inner(
            mat.sigma(self.part.elasticity_tensor, mat.epsilon(self.u)),
            mat.epsilon(self.v),
        ) * self.measures[self.part.dim])
        self.K = fe.assemble(self.a)

        # * Create suitable objects for Dirichlet boundary conditions
        for i, bc_data in enumerate(self.Dirichlet_bc):
            self.Dirichlet_bc[i] = fe.DirichletBC(self.displ_fspace, *bc_data)
        # ? Vu comment les conditions aux limites de Dirichlet interviennent dans le problème, pas sûr que ce soit nécessaire que toutes soient définies avec la même facetfunction

        # * Taking into account the loads
        if loads:
            self.set_loads(loads)
        else:
            self.loads_data = None
            self.load_integrals = None
        # * Prepare attribute for the solver
        self.solver = None
Esempio n. 4
0
    def __init__(self, fenics_2d_rve, **kwargs):
        """[summary]

        Parameters
        ----------
        object : [type]
            [description]
        fenics_2d_rve : [type]
            [description]
        element : tuple or dict
            Type and degree of element for displacement FunctionSpace
            Ex: ('CG', 2) or {'family':'Lagrange', degree:2}
        solver : dict
            Choose the type of the solver, its method and the preconditioner.
            An up-to-date list of the available solvers and preconditioners
            can be obtained with dolfin.list_linear_solver_methods() and
            dolfin.list_krylov_solver_preconditioners().

        """
        self.rve = fenics_2d_rve
        self.topo_dim = topo_dim = fenics_2d_rve.dim
        try:
            bottom_left_corner = fenics_2d_rve.bottom_left_corner
        except AttributeError:
            logger.warning(
                "For the definition of the periodicity boundary conditions,"
                "the bottom left corner of the RVE is assumed to be on (0.,0.)"
            )
            bottom_left_corner = np.zeros(shape=(topo_dim, ))
        self.pbc = periodicity.PeriodicDomain.pbc_dual_base(
            fenics_2d_rve.gen_vect, "XY", bottom_left_corner, topo_dim)

        solver = kwargs.pop("solver", {})
        # {'type': solver_type, 'method': solver_method, 'preconditioner': preconditioner}
        s_type = solver.pop("type", None)
        s_method = solver.pop("method", SOLVER_METHOD)
        s_precond = solver.pop("preconditioner", None)
        if s_type is None:
            if s_method in DOLFIN_KRYLOV_METHODS.keys():
                s_type = "Krylov"
            elif s_method in DOLFIN_LU_METHODS.keys():
                s_type = "LU"
            else:
                raise RuntimeError("The indicated solver method is unknown.")
        self._solver = dict(type=s_type, method=s_method)
        if s_precond:
            self._solver["preconditioner"] = s_precond

        element = kwargs.pop("element", ("Lagrange", 2))
        if isinstance(element, dict):
            element = (element["family"], element["degree"])
        self._element = element

        # * Function spaces
        cell = self.rve.mesh.ufl_cell()
        self.scalar_FE = fe.FiniteElement(element[0], cell, element[1])
        self.displ_FE = fe.VectorElement(element[0], cell, element[1])
        strain_deg = element[1] - 1 if element[1] >= 1 else 0
        strain_dim = int(topo_dim * (topo_dim + 1) / 2)
        self.strain_FE = fe.VectorElement("DG",
                                          cell,
                                          strain_deg,
                                          dim=strain_dim)
        # Espace fonctionel scalaire
        self.X = fe.FunctionSpace(self.rve.mesh,
                                  self.scalar_FE,
                                  constrained_domain=self.pbc)
        # Espace fonctionnel 3D : deformations, notations de Voigt
        self.W = fe.FunctionSpace(self.rve.mesh, self.strain_FE)
        # Espace fonctionel 2D pour les champs de deplacement
        # TODO : reprendre le Ve défini pour l'espace fonctionnel mixte. Par ex: V = FunctionSpace(mesh, Ve)
        self.V = fe.VectorFunctionSpace(self.rve.mesh,
                                        element[0],
                                        element[1],
                                        constrained_domain=self.pbc)

        # * Espace fonctionel mixte pour la résolution :
        # * 2D pour les champs + scalaire pour multiplicateur de Lagrange

        # "R" : Real element with one global degree of freedom
        self.real_FE = fe.VectorElement("R", cell, 0)
        self.M = fe.FunctionSpace(
            self.rve.mesh,
            fe.MixedElement([self.displ_FE, self.real_FE]),
            constrained_domain=self.pbc,
        )

        # Define variational problem
        self.v, self.lamb_ = fe.TestFunctions(self.M)
        self.u, self.lamb = fe.TrialFunctions(self.M)
        self.w = fe.Function(self.M)

        # bilinear form
        self.a = (
            fe.inner(sigma(self.rve.C_per, epsilon(self.u)), epsilon(self.v)) *
            fe.dx + fe.dot(self.lamb_, self.u) * fe.dx +
            fe.dot(self.lamb, self.v) * fe.dx)
        self.K = fe.assemble(self.a)
        if self._solver["type"] == "Krylov":
            self.solver = fe.KrylovSolver(self.K, self._solver["method"])
        elif self._solver["type"] == "LU":
            self.solver = fe.LUSolver(self.K, self._solver["method"])
            self.solver.parameters["symmetric"] = True
        try:
            self.solver.parameters.preconditioner = self._solver[
                "preconditioner"]
        except KeyError:
            pass
        # fe.info(self.solver.parameters, True)

        self.localization = dict()
        # dictionary of localization field objects,
        # will be filled up when calling auxiliary problems (lazy evaluation)
        self.ConstitutiveTensors = dict()
Esempio n. 5
0
def test_get_domains_gmsh(plots=False):
    """ Get subdomains and partition of the boundary from a .msh file. """
    name = "test_domains"
    local_dir = Path(__file__).parent
    mesh_file = local_dir.joinpath(name + ".msh")
    gmsh.model.add(name)
    L_x, L_y = 2.0, 2.0
    H = 1.0
    vertices = [(0.0, 0.0), (0.0, L_y), (L_x, L_y), (L_x, 0.0)]
    contour = geo.LineLoop([geo.Point(np.array(c)) for c in vertices], False)
    surface = geo.PlaneSurface(contour)
    inclusion_vertices = list()
    for coord in [
        (H / 2, -H / 2, 0.0),
        (H / 2, H / 2, 0.0),
        (-H / 2, H / 2, 0.0),
        (-H / 2, -H / 2, 0.0),
    ]:
        vertex = geo.translation(geo.Point((L_x / 2, L_y / 2)), coord)
        inclusion_vertices.append(vertex)
    inclusion = geo.PlaneSurface(geo.LineLoop(inclusion_vertices, False))
    for s in [surface, inclusion]:
        s.add_gmsh()
    factory.synchronize()
    (stiff_s, ) = geo.surface_bool_cut(surface, inclusion)
    factory.synchronize()
    (soft_s, ) = geo.surface_bool_cut(surface, stiff_s)
    factory.synchronize()
    domains = {
        "stiff": geo.PhysicalGroup(stiff_s, 2),
        "soft": geo.PhysicalGroup(soft_s, 2),
    }
    boundaries = {
        "S": geo.PhysicalGroup(surface.ext_contour.sides[0], 1),
        "W": geo.PhysicalGroup(surface.ext_contour.sides[1], 1),
        "N": geo.PhysicalGroup(surface.ext_contour.sides[2], 1),
        "E": geo.PhysicalGroup(surface.ext_contour.sides[3], 1),
    }
    for group in domains.values():
        group.add_gmsh()
    for group in boundaries.values():
        group.add_gmsh()
    charact_field = mesh_tools.MathEvalField("0.05")
    mesh_tools.set_background_mesh(charact_field)
    geo.set_gmsh_option("Mesh.SaveAll", 0)
    model.mesh.generate(1)
    model.mesh.generate(2)
    gmsh.model.mesh.removeDuplicateNodes()
    gmsh.write(str(mesh_file))
    E_1, E_2, nu = 1, 3, 0.3
    materials = {
        domains["soft"].tag: mat.Material(E_1, nu, "cp"),
        domains["stiff"].tag: mat.Material(E_1, nu, "cp"),
    }
    test_part = part.FenicsPart.part_from_file(mesh_file,
                                               materials,
                                               subdomains_import=True)
    assert test_part.mat_area == approx(L_x * L_y)
    elem_type = "CG"
    degree = 2
    V = fe.VectorFunctionSpace(test_part.mesh, elem_type, degree)
    W = fe.FunctionSpace(
        test_part.mesh,
        fe.VectorElement(elem_type, test_part.mesh.ufl_cell(), degree, dim=3),
    )
    boundary_conditions = {
        boundaries["N"].tag: fe.Expression(("x[0]-1", "1"), degree=1),
        boundaries["S"].tag: fe.Expression(("x[0]-1", "-1"), degree=1),
        boundaries["E"].tag: fe.Expression(("1", "x[1]-1"), degree=1),
        boundaries["W"].tag: fe.Expression(("-1", "x[1]-1"), degree=1),
    }
    bcs = list()
    for tag, val in boundary_conditions.items():
        bcs.append(fe.DirichletBC(V, val, test_part.facet_regions, tag))
    ds = fe.Measure("ds",
                    domain=test_part.mesh,
                    subdomain_data=test_part.facet_regions)
    v = fe.TestFunctions(V)
    u = fe.TrialFunctions(V)
    F = (fe.inner(mat.sigma(test_part.elasticity_tensor, mat.epsilon(u)),
                  mat.epsilon(v)) * fe.dx)
    a, L = fe.lhs(F), fe.rhs(F)
    u_sol = fe.Function(V)
    fe.solve(a == L, u_sol, bcs)
    strain = fe.project(mat.epsilon(u_sol), W)
    if plots:
        import matplotlib.pyplot as plt

        plt.figure()
        plot = fe.plot(u_sol)
        plt.colorbar(plot)
        plt.figure()
        plot = fe.plot(strain[0])
        plt.colorbar(plot)
        plt.figure()
        plot = fe.plot(strain[1])
        plt.colorbar(plot)
        plt.figure()
        plot = fe.plot(strain[2])
        plt.colorbar(plot)
        plt.show()
    error = fe.errornorm(
        strain,
        fe.Expression(("1", "1", "0"), degree=0),
        degree_rise=3,
        mesh=test_part.mesh,
    )
    assert error == approx(0, abs=1e-12)

    materials = {
        domains["soft"].tag: mat.Material(E_1, nu, "cp"),
        domains["stiff"].tag: mat.Material(E_2, nu, "cp"),
    }
    test_part = part.FenicsPart.part_from_file(mesh_file,
                                               materials,
                                               subdomains_import=True)
    V = fe.VectorFunctionSpace(test_part.mesh, elem_type, degree)
    W = fe.FunctionSpace(
        test_part.mesh,
        fe.VectorElement(elem_type, test_part.mesh.ufl_cell(), degree, dim=3),
    )
    bcs = list()
    for tag, val in boundary_conditions.items():
        bcs.append(fe.DirichletBC(V, val, test_part.facet_regions, tag))
    v = fe.TestFunctions(V)
    u = fe.TrialFunctions(V)
    F = (fe.inner(mat.sigma(test_part.elasticity_tensor, mat.epsilon(u)),
                  mat.epsilon(v)) * fe.dx)
    a, L = fe.lhs(F), fe.rhs(F)
    u_sol = fe.Function(V)
    fe.solve(a == L, u_sol, bcs)
    strain = mat.epsilon(u_sol)
    stress = mat.sigma(test_part.elasticity_tensor, strain)
    energy = 0.5 * fe.assemble(
        fe.inner(stress, strain) * fe.dx(test_part.mesh))
    energy_abaqus = 12.8788939
    assert energy == approx(energy_abaqus, rel=1e-3)
    geo.reset()