Source code for fenicsx_pulse.cardiac_model

"""This module defines the cardiac model.

The cardiac model is a combination of a material model,
an active model, and a compressibility model.
"""

from dataclasses import dataclass, field
from typing import Protocol

import dolfinx

from . import kinematics
from .viscoelasticity import NoneViscoElasticity


[docs] class ActiveModel(Protocol): def strain_energy(self, F) -> dolfinx.fem.Form: ... def Fe(self, F) -> dolfinx.fem.Form: ...
[docs] class Compressibility(Protocol): def strain_energy(self, J) -> dolfinx.fem.Form: ... def is_compressible(self) -> bool: ...
[docs] def register(self, p: dolfinx.fem.Function | None) -> None: ...
[docs] class HyperElasticMaterial(Protocol): def strain_energy(self, F) -> dolfinx.fem.Form: ...
[docs] class ViscoElasticity(Protocol): def strain_energy(self, E_dot) -> dolfinx.fem.Form: ...
[docs] @dataclass(frozen=True, slots=True) class CardiacModel: material: HyperElasticMaterial active: ActiveModel compressibility: Compressibility viscoelasticity: ViscoElasticity = field(default_factory=NoneViscoElasticity) decouple_deviatoric_volumetric: bool = False def strain_energy(self, F, p: dolfinx.fem.Function | None = None): self.compressibility.register(p) # If active strain we would need to get the elastic # part of the deformation gradient Fe = self.active.Fe(F) J = kinematics.Jacobian(Fe) if self.decouple_deviatoric_volumetric: Jm13 = J ** (-1 / 3) else: Jm13 = 1.0 return ( self.material.strain_energy(Jm13 * Fe) + self.active.strain_energy(Jm13 * F) + self.compressibility.strain_energy(J) ) def viscoelastic_strain_energy(self, E_dot): return self.viscoelasticity.strain_energy(E_dot)