def __init__(self, geometry, material=None, mechanics_bcs=None, porous_bcs=None, parameters=None, solver_parameters=None): self.geometry = geometry self.pprob = PorousProblem(geometry, material, bcs=porous_bcs, parameters=parameters, solver_parameters=solver_parameters) if parameters['mechanics']: self.material = material self.mprob = pulse.MechanicsProblem( get_mechanics_geometry(geometry), material, bcs=mechanics_bcs) if solver_parameters is not None: self.mprob.solver_parameters.update(solver_parameters) # set pulse log level pulse.parameters.update({'log_level': df.get_log_level()}) self.previous_mechanics = df.Function(self.mprob.state_space)
def create_forward_problem( mesh, activation, active_value=0.0, active_model="active_stain", T_ref=1.0, ): ffun = df.MeshFunction("size_t", mesh, 2) ffun.set_all(0) left = df.CompiledSubDomain("on_boundary && near(x[0], 0)") left_marker = 1 left.mark(ffun, left_marker) # Collect the functions containing the markers marker_functions = pulse.MarkerFunctions(ffun=ffun) def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return da.DirichletBC(V, da.Constant((0.0, 0.0, 0.0)), left) bcs = pulse.BoundaryConditions(dirichlet=(dirichlet_bc, ), ) f0 = df.as_vector([1, 0, 0]) microstructure = pulse.Microstructure(f0=f0) geometry = pulse.Geometry( mesh=mesh, marker_functions=marker_functions, microstructure=microstructure, ) material_parameters = dict( a=2.28, a_f=1.686, b=9.726, b_f=15.779, a_s=0.0, b_s=0.0, a_fs=0.0, b_fs=0.0, ) material = pulse.HolzapfelOgden( active_model=active_model, parameters=material_parameters, activation=activation, T_ref=T_ref, ) problem = pulse.MechanicsProblem(geometry, material, bcs) problem.solve() if active_value > 0.0: pulse.iterate.iterate(problem, activation, active_value) return problem
def create_mechanics_problem(solver_parameters): import pulse # from pulse import (MechanicsProblem, HeartGeometry, BoundaryConditions, # NeumannBC, RobinBC, MarkerFunctions, Marker, CRLBasis) from pulse.material import HolzapfelOgden mfun = pulse.MarkerFunctions(ffun=solver_parameters['facet_function'], cfun=solver_parameters['mesh_function']) material = solver_parameters['material'] microstructure = pulse.Microstructure(f0=material.f0, s0=material.s0, n0=material.f0) crl_basis = pulse.CRLBasis( c0=solver_parameters['crl_basis']['circumferential'], r0=solver_parameters['crl_basis']['radial'], l0=solver_parameters['crl_basis']['longitudinal']) geometry = pulse.HeartGeometry(mesh=solver_parameters['mesh'], markers=solver_parameters['markers'], marker_functions=mfun, microstructure=microstructure, crl_basis=crl_basis) neumann = [] names = ['lv', 'rv'] for i, n in enumerate(solver_parameters['bc']['neumann']): neumann.append( pulse.NeumannBC(traction=n[0], marker=n[1], name=names[i])) robin = [] for i, n in enumerate(solver_parameters['bc']['robin']): robin.append(pulse.RobinBC(value=n[0], marker=n[1])) if hasattr(solver_parameters['bc']['dirichlet'], '__len__'): dirichlet = solver_parameters['bc']['dirichlet'] else: dirichlet = (solver_parameters['bc']['dirichlet'], ) bcs = pulse.BoundaryConditions(dirichlet=dirichlet, neumann=neumann, robin=robin) problem = pulse.MechanicsProblem(geometry, material, bcs) return problem
def main(): def fix_basal_plane(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) bc = dolfin.DirichletBC(V, dolfin.Constant((0.0, 0.0, 0.0)), geometry.ffun, geometry.markers["BASE"][0]) return bc dirichlet_bc = [fix_basal_plane] lvp = dolfin.Constant(0.0) lv_marker = geometry.markers['ENDO'][0] lv_pressure = pulse.NeumannBC(traction=lvp, marker=lv_marker, name='lv') neumann_bc = [lv_pressure] bcs = pulse.BoundaryConditions(dirichlet=dirichlet_bc, neumann=neumann_bc) fig, ax = plt.subplots() for material_model in ["neo_hookean", "guccione", "holzapfel_ogden"]: material = setup_material(material_model) problem = pulse.MechanicsProblem(geometry, material, bcs) pressures = [0.0] volumes = [geometry.cavity_volume()] for p in np.linspace(0, ED_pressure, 10)[1:]: pulse.iterate.iterate(problem, lvp, p) pressures.append(p) volumes.append(geometry.cavity_volume(u=problem.state.split()[0])) ax.plot(volumes, pressures, label=" ".join(material_model.split("_"))) # Reset pressure lvp.assign(dolfin.Constant(0.0)) vs, ps = klotz_curve() ax.plot(vs, ps, linestyle="--", label='Klotz curve') ax.legend(loc="best") ax.set_xlabel('Volume (ml)') ax.set_ylabel('Pressure (kPa)') # plt.show() plt.savefig('klotz_curve.png')
def build_problem(geometry, matparams): activation = dolfin.Function(dolfin.FunctionSpace(geometry.mesh, "R", 0)) material = pulse.HolzapfelOgden( activation=activation, parameters=matparams, f0=geometry.f0, s0=geometry.s0, n0=geometry.n0, ) # LV Pressure lvp = dolfin.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=dolfin.Constant(base_spring), marker=geometry.markers["BASE"][0] ) ] # 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] ) 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) return problem, activation, lvp
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, ), neumann=(neumann_bc, )) # Create problem problem = pulse.MechanicsProblem(geometry, material, bcs) # Solve problem pulse.iterate.iterate(problem, lvp, 10.0) # Get displacement and hydrostatic pressure u, p = problem.state.split(deepcopy=True) endo_apex_marker = geometry.markers['ENDOPT'][0] endo_apex_idx = geometry.vfun.array().tolist().index(endo_apex_marker) endo_apex = geometry.mesh.coordinates()[endo_apex_idx, :] endo_apex_pos = endo_apex + u(endo_apex) print(('\n\nGet longitudinal position of endocardial apex: {:.4f} mm' '').format(endo_apex_pos[0]))
import pulse geometry = pulse.HeartGeometry.from_file(pulse.mesh_paths["simple_ellipsoid"]) # geometry = pulse.geometries.prolate_ellipsoid_geometry(mesh_size_factor=3.0) material = pulse.NeoHookean() # material = pulse.Guccione() # Parameter for the cardiac boundary conditions bcs_parameters = pulse.MechanicsProblem.default_bcs_parameters() bcs_parameters["base_spring"] = 1.0 bcs_parameters["base_bc"] = "fix_x" # Create the problem problem = pulse.MechanicsProblem(geometry, material, bcs_parameters=bcs_parameters) # Suppose geometry is loaded with a pressure of 1 kPa # and create the unloader unloader = pulse.FixedPointUnloader(problem=problem, pressure=3.0) # Unload the geometry unloader.unload() # Get the unloaded geometry unloaded_geometry = unloader.unloaded_geometry fig = plot(geometry.mesh, opacity=0.0, show=False) fig.add_plot(plot(unloaded_geometry.mesh, color="red", show=False)) fig.show()
def create_problem(): geometry = pulse.HeartGeometry.from_file( pulse.mesh_paths["simple_ellipsoid"]) activation = dolfin_adjoint.Function(dolfin.FunctionSpace( geometry.mesh, "R", 0), name="activation") activation.assign(dolfin_adjoint.Constant(0.0)) matparams = pulse.HolzapfelOgden.default_parameters() V = dolfin.FunctionSpace(geometry.mesh, "R", 0) control = dolfin_adjoint.Function(V) control.assign(dolfin_adjoint.Constant(1.0)) # control = dolfin_adjoint.Constant(1.0, name="matparam control (a)") matparams["a"] = control f0 = dolfin_adjoint.Function(geometry.f0.function_space()) f0.assign(geometry.f0) s0 = dolfin_adjoint.Function(geometry.s0.function_space()) s0.assign(geometry.s0) n0 = dolfin_adjoint.Function(geometry.n0.function_space()) n0.assign(geometry.n0) material = pulse.HolzapfelOgden(activation=activation, parameters=matparams, f0=f0, s0=s0, n0=n0) # LV Pressure lvp = dolfin_adjoint.Constant(0.0, name="lvp") 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=dolfin_adjoint.Constant(base_spring, name="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_adjoint.DirichletBC( V.sub(0), dolfin.Constant(0.0, name="fix_base"), 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) return problem, control
def pulse_problem(geometry, material, mechanics_bcs): pulse_problem = pulse.MechanicsProblem(geometry, material, mechanics_bcs) return pulse_problem
def mechanics_problem(geometry, material): mech_geometry = get_mechanics_geometry(geometry) mechanics_problem = pulse.MechanicsProblem(mech_geometry, material, bcs=None, bcs_parameters={"": ""}) return mechanics_problem
def create_experiment(case): # noqa: C901 if case == "fs": def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return [ DirichletBC(V, zero, xlow), DirichletBC(V, x, xhigh), ] def increment(xi): return (0, xi, 0) def shear_component(T): return dolfin.assemble(T[0, 1] * dolfin.dx) elif case == "fn": def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return [ DirichletBC(V, zero, xlow), DirichletBC(V, x, xhigh), ] def increment(xi): return (0, 0, xi) def shear_component(T): return dolfin.assemble(T[0, 2] * dolfin.dx) elif case == "sf": def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return [ DirichletBC(V, zero, ylow), DirichletBC(V, x, yhigh), ] def increment(xi): return (xi, 0, 0) def shear_component(T): return dolfin.assemble(T[1, 0] * dolfin.dx) elif case == "sn": def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return [ DirichletBC(V, zero, ylow), DirichletBC(V, x, yhigh), ] def increment(xi): return (0, 0, xi) def shear_component(T): return dolfin.assemble(T[1, 2] * dolfin.dx) elif case == "nf": def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return [ DirichletBC(V, zero, zlow), DirichletBC(V, x, zhigh), ] def increment(xi): return (xi, 0, 0) def shear_component(T): return dolfin.assemble(T[2, 0] * dolfin.dx) elif case == "ns": def dirichlet_bc(W): V = W if W.sub(0).num_sub_spaces() == 0 else W.sub(0) return [ DirichletBC(V, zero, zlow), DirichletBC(V, x, zhigh), ] def increment(xi): return (0, xi, 0) def shear_component(T): return dolfin.assemble(T[2, 1] * dolfin.dx) else: raise ValueError(f"Unknown case {case}") # Collect Boundary Conditions bcs = pulse.BoundaryConditions(dirichlet=(dirichlet_bc, )) # Create problem return Experiment( problem=pulse.MechanicsProblem(geometry, material, bcs), increment=increment, shear_component=shear_component, )
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)))