コード例 #1
0
    def assign_sub(self, f, i):
        """
        Assign subfunction

        :param f: The function you want to assign
        :param int i: The subspace number

        """
        f_ = Function(self.basespace)
        f_.assign(f)
        self.function_assigner[i].assign(self.split()[i], f_)
コード例 #2
0
class MechanicsProblem(object):
    """
    Base class for mechanics problem
    """
    def __init__(
        self,
        geometry: Geometry,
        material: Material,
        bcs=None,
        bcs_parameters=None,
        solver_parameters=None,
    ):

        logger.debug("Initialize mechanics problem")
        self.geometry = geometry
        self.material = material

        self._handle_bcs(bcs=bcs, bcs_parameters=bcs_parameters)

        # Make sure that the material has microstructure information
        for attr in ("f0", "s0", "n0"):
            setattr(self.material, attr, getattr(self.geometry, attr))

        self.solver_parameters = NonlinearSolver.default_solver_parameters()
        if solver_parameters is not None:
            self.solver_parameters.update(**solver_parameters)

        self._init_spaces()
        self._init_forms()

    def _handle_bcs(self, bcs, bcs_parameters):
        if bcs is None:
            if isinstance(self.geometry, HeartGeometry):
                self.bcs_parameters = MechanicsProblem.default_bcs_parameters()
                if bcs_parameters is not None:
                    self.bcs_parameters.update(**bcs_parameters)
            else:
                raise ValueError(("Please provive boundary conditions "
                                  "to MechanicsProblem"), )

            self.bcs = cardiac_boundary_conditions(self.geometry,
                                                   **self.bcs_parameters)

        else:
            self.bcs = bcs

            # TODO: FIX THIS or require this
            # Just store this as well in case both is provided
            self.bcs_parameters = MechanicsProblem.default_bcs_parameters()
            if bcs_parameters is not None:
                self.bcs_parameters.update(**bcs_parameters)

    @staticmethod
    def default_bcs_parameters():
        return dict(pericardium_spring=0.0, base_spring=0.0, base_bc="fixed")

    def _init_spaces(self):

        logger.debug("Initialize spaces for mechanics problem")
        mesh = self.geometry.mesh

        P2 = dolfin.VectorElement("Lagrange", mesh.ufl_cell(), 2)
        P1 = dolfin.FiniteElement("Lagrange", mesh.ufl_cell(), 1)

        # P2_space = FunctionSpace(mesh, P2)
        # P1_space = FunctionSpace(mesh, P1)
        self.state_space = dolfin.FunctionSpace(mesh, P2 * P1)

        self.state = Function(self.state_space, name="state")
        self.state_test = dolfin.TestFunction(self.state_space)

    def _init_forms(self):

        logger.debug("Initialize forms mechanics problem")
        # Displacement and hydrostatic_pressure
        u, p = dolfin.split(self.state)
        v, q = dolfin.split(self.state_test)

        # Some mechanical quantities
        F = dolfin.variable(kinematics.DeformationGradient(u))
        J = kinematics.Jacobian(F)
        dx = self.geometry.dx

        internal_energy = (self.material.strain_energy(F, ) +
                           self.material.compressibility(p, J))

        self._virtual_work = dolfin.derivative(
            internal_energy * dx,
            self.state,
            self.state_test,
        )

        external_work = self._external_work(u, v)
        if external_work is not None:
            self._virtual_work += external_work

        self._set_dirichlet_bc()
        self._jacobian = dolfin.derivative(
            self._virtual_work,
            self.state,
            dolfin.TrialFunction(self.state_space),
        )
        self._init_solver()

    def _init_solver(self):
        if has_dolfin_adjoint:
            self._problem = NonlinearVariationalProblem(
                J=self._jacobian,
                F=self._virtual_work,
                u=self.state,
                bcs=self._dirichlet_bc,
            )
            self.solver = NonlinearVariationalSolver(self._problem)
        else:
            self._problem = NonlinearProblem(
                J=self._jacobian,
                F=self._virtual_work,
                bcs=self._dirichlet_bc,
            )
            self.solver = NonlinearSolver(
                self._problem,
                self.state,
                parameters=self.solver_parameters,
            )

    def _set_dirichlet_bc(self):
        # DirichletBC
        for dirichlet_bc in self.bcs.dirichlet:

            msg = ("DirichletBC only implemented for as "
                   "callable. Please provide DirichletBC "
                   "as a callable with argument being the "
                   "state space only")

            if hasattr(dirichlet_bc, "__call__"):
                try:
                    self._dirichlet_bc = dirichlet_bc(self.state_space)
                except Exception as ex:
                    logger.error(msg)
                    raise ex
            else:

                raise NotImplementedError(msg)

    def _external_work(self, u, v):

        F = dolfin.variable(kinematics.DeformationGradient(u))

        N = self.geometry.facet_normal
        ds = self.geometry.ds
        dx = self.geometry.dx

        external_work = []

        for neumann in self.bcs.neumann:

            n = neumann.traction * ufl.cofac(F) * N
            external_work.append(dolfin.inner(v, n) * ds(neumann.marker))

        for robin in self.bcs.robin:

            external_work.append(
                dolfin.inner(robin.value * u, v) * ds(robin.marker))

        for body_force in self.bcs.body_force:

            external_work.append(
                -dolfin.derivative(dolfin.inner(body_force, u) * dx, u, v), )

        if len(external_work) > 0:
            return list_sum(external_work)

        return None

    def reinit(self, state, annotate=False):
        """Reinitialze state"""

        if has_dolfin_adjoint:
            try:
                self.state.assign(state, annotate=annotate)
            except Exception as ex:
                print(ex)
                self.state.assign(state)
        else:
            self.state.assign(state)

        self._init_forms()

    @staticmethod
    def default_solver_parameters():
        return NonlinearSolver.default_solver_parameters()

    def solve(self):
        r"""
        Solve the variational problem

        .. math::

           \delta W = 0

        """

        logger.debug("Solving variational problem")
        # Get old state in case of non-convergence
        if has_dolfin_adjoint:
            try:
                old_state = self.state.copy(deepcopy=True,
                                            name="Old state (pulse)")
            except TypeError:
                # In case this is a dolfin fuction and not a
                # dolfin-adjoint function
                old_state = self.state.copy(deepcopy=True)

        else:
            old_state = self.state.copy(deepcopy=True)

        try:
            logger.debug("Try to solve")
            nliter, nlconv = self.solver.solve()

            if not nlconv:
                logger.debug("Failed")
                raise SolverDidNotConverge("Solver did not converge...")

        except RuntimeError as ex:
            logger.debug("Failed")
            logger.debug("Reintialize old state and raise exception")

            self.reinit(old_state)

            raise SolverDidNotConverge(ex) from ex
        else:
            logger.debug("Sucess")

        return nliter, nlconv

    def get_displacement(self, annotate=False):

        D = self.state_space.sub(0)
        V = D.collapse()

        fa = FunctionAssigner(V, D)
        u = Function(V, name="displacement")

        if has_dolfin_adjoint:
            fa.assign(u, self.state.split()[0], annotate=annotate)
        else:
            fa.assign(u, self.state.split()[0])

        return u

    def SecondPiolaStress(self):
        u, p = self.state.split(deepcopy=True)
        F = kinematics.DeformationGradient(u)
        return self.material.SecondPiolaStress(F, p)

    def FirstPiolaStress(self):
        u, p = self.state.split(deepcopy=True)
        F = kinematics.DeformationGradient(u)
        return self.material.FirstPiolaStress(F, p)

    def ChachyStress(self):
        u, p = self.state.split(deepcopy=True)
        F = kinematics.DeformationGradient(u)
        return self.material.CauchyStress(F, p)

    def GreenLagrangeStrain(self):
        u, p = self.state.split(deepcopy=True)
        F = kinematics.DeformationGradient(u)
        return kinematics.GreenLagrangeStrain(F)
コード例 #3
0
ファイル: from_xml.py プロジェクト: finsberg/pulse
)
fiber_space = dolfin.FunctionSpace(mesh, fiber_element)
fiber = Function(fiber_space, "data/fiber.xml")

microstructure = pulse.Microstructure(f0=fiber)

# Create the geometry
geometry = pulse.HeartGeometry(
    mesh=mesh,
    markers=markers,
    marker_functions=marker_functions,
    microstructure=microstructure,
)

activation = Function(dolfin.FunctionSpace(geometry.mesh, "R", 0))
activation.assign(Constant(0.0))
matparams = pulse.HolzapfelOgden.default_parameters()
material = pulse.HolzapfelOgden(
    activation=activation,
    parameters=matparams,
    f0=geometry.f0,
)

# LV Pressure
lvp = Constant(0.0)
lv_marker = markers["ENDO"][0]
lv_pressure = pulse.NeumannBC(traction=lvp, marker=lv_marker, name="lv")
neumann_bc = [lv_pressure]

# Add spring term at the base with stiffness 1.0 kPa/cm^2
base_spring = 1.0
コード例 #4
0
ファイル: shear_experiment.py プロジェクト: finsberg/pulse
# Loop over all modes and collect the stress values

modes = ["fs", "fn", "sf", "sn", "nf", "ns"]
stress: dict[str, dict[str, list[float]]] = {
    "cauchy": {m: []
               for m in modes},
    "pk1": {m: []
            for m in modes},
}
shear_values = np.linspace(0, 0.6, 10)
recompute = True
# Solve problem
results_file = Path("result.npy")
if recompute or not results_file.is_file():
    for mode in modes:
        x.assign(zero)
        experiment = create_experiment(mode)

        for shear in shear_values:
            pulse.iterate.iterate(
                experiment.problem,
                x,
                experiment.increment(shear),
                reinit_each_step=True,
            )
            stress["cauchy"][mode].append(
                experiment.shear_component(
                    experiment.problem.ChachyStress()), )
            stress["pk1"][mode].append(
                experiment.shear_component(
                    experiment.problem.FirstPiolaStress()), )