def setup_material(material_model): """ Choose parameters based on Hadjicharalambous, Myrianthi, et al. "Analysis of passive cardiac constitutive laws for parameter estimation using 3D tagged MRI." Biomechanics and modeling in mechanobiology 14.4 (2015): 807-828. These parameters did not really match the Klotz curve here. Perhaps they did some more tuning? """ if material_model == "guccione": matparams = pulse.Guccione.default_parameters() matparams["C"] = 0.18 # kPa matparams["bf"] = 27.75 matparams["bt"] = 5.37 matparams["bfs"] = 2.445 material = pulse.Guccione( parameters=matparams, f0=geometry.f0, s0=geometry.s0, n0=geometry.n0, ) elif material_model == "neo_hookean": matparams = pulse.NeoHookean.default_parameters() matparams["mu"] = 10.0 # kPa material = pulse.NeoHookean(parameters=matparams) elif material_model == "holzapfel_ogden": matparams = pulse.HolzapfelOgden.default_parameters() matparams["a"] = 4.0 # kPa matparams["a_f"] = 10.0 # kPa matparams["b"] = 5.0 matparams["b_f"] = 5.0 material = pulse.HolzapfelOgden( parameters=matparams, f0=geometry.f0, s0=geometry.s0, n0=geometry.n0, ) return material
behaviour. Proc. R. Soc. A. 2015 Dec 8;471(2184):20150641. """ import matplotlib.pyplot as plt import dolfin import pulse geometry = pulse.HeartGeometry.from_file(pulse.mesh_paths['benchmark']) # Create the material material_parameters = pulse.Guccione.default_parameters() material_parameters['CC'] = 10.0 material_parameters['bf'] = 1.0 material_parameters['bfs'] = 1.0 material_parameters['bt'] = 1.0 material = pulse.Guccione(params=material_parameters) # Define Dirichlet boundary. Fix the base_spring def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return dolfin.DirichletBC(V, dolfin.Constant((0.0, 0.0, 0.0)), geometry.ffun, geometry.markers['BASE'][0]) # Traction at the bottom of the beam lvp = dolfin.Constant(0.0) neumann_bc = pulse.NeumannBC(traction=lvp, marker=geometry.markers['ENDO'][0]) # Collect Boundary Conditions bcs = pulse.BoundaryConditions(dirichlet=(dirichlet_bc, ),
import matplotlib.pyplot as plt import dolfin import pulse from problem import Problem from force import ca_transient # pulse.parameters['log_level'] = dolfin.WARNING geometry = pulse.HeartGeometry.from_file(pulse.mesh_paths['simple_ellipsoid']) # Scale mesh to fit Windkessel parameters geometry.mesh.coordinates()[:] *= 2.4 activation = dolfin.Constant(0.0) matparams = pulse.Guccione.default_parameters() material = pulse.Guccione(activation=activation, parameters=matparams) # Add spring term at the base with stiffness 1.0 kPa/cm^2 base_spring = 1.0 robin_bc = [pulse.RobinBC(value=dolfin.Constant(base_spring), marker=geometry.markers["BASE"][0])] # Fix the basal plane in the longitudinal direction # 0 in V.sub(0) refers to x-direction, which is the longitudinal direction def fix_basal_plane(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) bc = dolfin.DirichletBC(V.sub(0), dolfin.Constant(0.0), geometry.ffun, geometry.markers["BASE"][0])
from fenics_plotly import plot geometry = pulse.HeartGeometry.from_file(pulse.mesh_paths["benchmark"]) # geometry = pulse.geometries.benchmark_ellipsoid_geometry() # Create the material material_parameters = pulse.Guccione.default_parameters() material_parameters["CC"] = 2.0 material_parameters["bf"] = 8.0 material_parameters["bfs"] = 4.0 material_parameters["bt"] = 2.0 activation = Constant(0.0) material = pulse.Guccione( parameters=material_parameters, active_model=pulse.ActiveModels.active_stress, activation=activation, ) # Define Dirichlet boundary. Fix the base_spring def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return DirichletBC( V, Constant((0.0, 0.0, 0.0)), geometry.ffun, geometry.markers["BASE"][0], )
def solve( geometry, EDP=1.0, ESP=15.0, Ta=60, material_parameters=None, ): """ Arguments --------- EDP : float End diastolic pressure ESP : float End systolic pressure Ta : float Peak active tension (at ES) material_parameters : dict A dictionart with parameter in the Guccione model. Default: {'C': 2.0, 'bf': 8.0, 'bt': 2.0, 'bfs': 4.0} filename : str Filname where to store the results """ # Create model activation = df.Function(df.FunctionSpace(geometry.mesh, "R", 0)) matparams = pulse.Guccione.default_parameters() if material_parameters is not None: matparams.update(material_parameters) material = pulse.Guccione(activation=activation, parameters=matparams, active_model="active_stress", f0=geometry.f0, s0=geometry.s0, n0=geometry.n0) lvp = df.Constant(0.0) lv_marker = geometry.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 robin_bc = [ pulse.RobinBC(value=df.Constant(base_spring), marker=geometry.markers["BASE"][0]) ] # Fix the basal plane in the longitudinal direction # 0 in V.sub(0) refers to x-direction, which is the longitudinal direction def fix_basal_plane(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) bc = df.DirichletBC(V.sub(0), df.Constant(0.0), geometry.ffun, geometry.markers["BASE"][0]) return bc dirichlet_bc = [fix_basal_plane] # Collect boundary conditions bcs = pulse.BoundaryConditions(dirichlet=dirichlet_bc, neumann=neumann_bc, robin=robin_bc) # Create the problem problem = pulse.MechanicsProblem(geometry, material, bcs) xdmf = df.XDMFFile(df.mpi_comm_world(), 'output.xdmf') # Solve the problem print(("Do an initial solve with pressure = 0 kPa " "and active tension = 0 kPa")) problem.solve() u, p = problem.state.split() xdmf.write(u, 0.0) print("LV cavity volume = {} ml".format(geometry.cavity_volume(u=u))) # Solve for ED print(("Solver for ED with pressure = {} kPa and active tension = 0 kPa" "".format(EDP))) pulse.iterate.iterate(problem, lvp, EDP, initial_number_of_steps=20) u, p = problem.state.split(deepcopy=True) xdmf.write(u, 1.0) df.File("ED_displacement.xml") << u print("LV cavity volume = {} ml".format(geometry.cavity_volume(u=u))) # Solve for ES print(("Solver for ES with pressure = {} kPa and active tension = {} kPa" "".format(ESP, Ta))) pulse.iterate.iterate(problem, lvp, ESP, initial_number_of_steps=50) pulse.iterate.iterate(problem, activation, Ta, adapt_step=False, max_iters=100, initial_number_of_steps=40) u, p = problem.state.split(deepcopy=True) xdmf.write(u, 2.0) df.File("ES_displacement.xml") << u print("LV cavity volume = {} ml".format(geometry.cavity_volume(u=u)))
import dolfin import pulse geometry = pulse.HeartGeometry.from_file(pulse.mesh_paths['benchmark']) # Create the material material_parameters = pulse.Guccione.default_parameters() material_parameters['CC'] = 2.0 material_parameters['bf'] = 8.0 material_parameters['bfs'] = 4.0 material_parameters['bt'] = 2.0 activation = dolfin.Constant(0.0) material = pulse.Guccione(params=material_parameters, active_model='active_stress', activation=activation) # Define Dirichlet boundary. Fix the base_spring def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return dolfin.DirichletBC(V, dolfin.Constant((0.0, 0.0, 0.0)), geometry.ffun, geometry.markers['BASE'][0]) # Traction at the bottom of the beam lvp = dolfin.Constant(0.0) neumann_bc = pulse.NeumannBC(traction=lvp, marker=geometry.markers['ENDO'][0])