def boundary_conditions(geometry, **bcs_parameters): try: pericardium_spring = bcs_parameters['pericardium_spring'] base_spring = bcs_parameters['base_spring'] base_bc = bcs_parameters['base_bc'] except KeyError: msg = "Not all boundary conditions have been set. You have provided "\ "{}".format(bcs_parameters.keys()) raise KeyError(msg) # Neumann BCs lv_pressure = pulse.NeumannBC(traction=Constant(0.0, name="lv_pressure"), marker=geometry.get_lv_marker(), name="lv") neumann_bc = [lv_pressure] if geometry.has_rv(): rv_pressure = pulse.NeumannBC(traction=Constant(0.0, name="rv_pressure"), marker=geometry.get_rv_marker(), name="rv") neumann_bc += [rv_pressure] # Robin BC robin_bc = [] if pericardium_spring > 0.0: robin_bc += [ pulse.RobinBC(value=Constant(pericardium_spring), marker=geometry.get_epi_marker()) ] if base_spring > 0.0: robin_bc += [ pulse.RobinBC(value=Constant(base_spring), marker=geometry.get_base_marker()) ] # Dirichlet BC if base_bc == "fixed": dirichlet_bc = [ partial( dirichlet_fix_base, ffun=geometry.ffun, marker=geometry.get_base_marker(), ) ] elif base_bc == "fix_x": dirichlet_bc = [ partial(dirichlet_fix_base_directional, ffun=geometry.ffun, marker=geometry.get_base_marker()) ] return pulse.BoundaryConditions(dirichlet=dirichlet_bc, neumann=neumann_bc, robin=robin_bc)
def mechanics_bcs(geometry): # LV Pressure 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] bcs = pulse.BoundaryConditions(dirichlet=dirichlet_bc, neumann=neumann_bc, robin=robin_bc) return bcs
def test_boundary_observation(): bc = pulse.NeumannBC(traction=dolfin_adjoint.Constant(0.0), marker=0, name="test bc") pressures = (0.0, 0.1, 0.2) bcs = BoundaryObservation(bc=bc, data=pressures) for i, b in enumerate(bcs): b.assign_bc() assert abs(float(b.bc.traction) - pressures[i]) < 1e-12
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
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, ), 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]
# Create material material = pulse.HolzapfelOgden( active_model=active_model, parameters=material_parameters, activation=activation, ) # Make Dirichlet boundary conditions 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)), fixed) # Make Neumann boundary conditions neumann_bc = pulse.NeumannBC(traction=Constant(0.0), marker=free_marker) # 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, activation, 0.1) # Get displacement and hydrostatic pressure u, p = problem.state.split(deepcopy=True) V = dolfin.VectorFunctionSpace(mesh, "CG", 1) u_int = interpolate(u, V)
activation = dolfin.Constant(0.1) # Create material material = pulse.HolzapfelOgden(active_model=active_model, params=material_parameters, activation=activation) # Make Dirichlet boundary conditions 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)), fixed) # Make Neumann boundary conditions neumann_bc = pulse.NeumannBC(traction=dolfin.Constant(0.0), marker=free_marker.value) # Collect Boundary Conditions bcs = pulse.BoundaryConditions(dirichlet=(dirichlet_bc, ), neumann=(neumann_bc, )) # Create problem problem = pulse.MechanicsProblem(geometry, material, bcs) # Solve problem problem.solve() # Get displacement and hydrostatic pressure u, p = problem.state.split(deepcopy=True) # Plot
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 robin_bc = [ pulse.RobinBC(value=Constant(base_spring), marker=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 = DirichletBC(V.sub(0), Constant(0.0), geometry.ffun, markers["BASE"][0])
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
material_parameters['bf'] = 8.0 material_parameters['bfs'] = 4.0 material_parameters['bt'] = 2.0 material = pulse.Guccione(params=material_parameters) # Define Dirichlet boundary. Fix at the left boundary 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)), left) # Traction at the bottom of the beam p_bottom = dolfin.Constant(0.004) neumann_bc = pulse.NeumannBC(traction=p_bottom, marker=bottom_marker.value) # Collect Boundary Conditions bcs = pulse.BoundaryConditions(dirichlet=(dirichlet_bc, ), neumann=(neumann_bc, )) # Create problem problem = pulse.MechanicsProblem(geometry, material, bcs) # Solve problem problem.solve() # Get displacement and hydrostatic pressure u, p = problem.state.split(deepcopy=True) point = np.array([10.0, 0.5, 1.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)))