def setup(self): self.mesh = UnitCubeMesh(5, 5, 5) # Create time self.time = Constant(0.0) # Create stimulus self.stimulus = Expression("2.0*t", t=self.time, degree=1) # Create ac self.applied_current = Expression("sin(2*pi*x[0])*t", t=self.time, degree=3) # Create conductivity "tensors" self.M_i = 1.0 self.M_e = 2.0 self.cell_model = FitzHughNagumoManual() self.cardiac_model = CardiacModel(self.mesh, self.time, self.M_i, self.M_e, self.cell_model, self.stimulus, self.applied_current) dt = 0.1 self.t0 = 0.0 self.dt = [(0.0, dt), (dt * 2, dt / 2), (dt * 4, dt)] # Test using variable dt interval but using the same dt. self.T = self.t0 + 5 * dt self.ics = self.cell_model.initial_conditions()
def __init__(self): self.mesh = UnitCubeMesh(5, 5, 5) # Create time self.time = Constant(0.0) # Create stimulus self.stimulus = Expression("2.0*t", t=self.time, degree=1) # Create ac self.applied_current = Expression("sin(2*pi*x[0])*t", t=self.time, degree=3) # Create conductivity "tensors" self.M_i = 1.0 self.M_e = 2.0 self.cell_model = FitzHughNagumoManual() self.cardiac_model = CardiacModel(self.mesh, self.time, self.M_i, self.M_e, self.cell_model, self.stimulus, self.applied_current) dt = 0.1 self.t0 = 0.0 if Solver == SplittingSolver: # FIXME: Dolfin-adjoint fails with adaptive timestep and SplittingSolver self.dt = dt else: self.dt = [(0.0, dt), (dt * 2, dt / 2), (dt * 4, dt)] # Test using variable dt interval but using the same dt. self.T = self.t0 + 5 * dt # Create solver object params = Solver.default_parameters() if Solver == SplittingSolver: params.enable_adjoint = enable_adjoint params.BidomainSolver.linear_solver_type = solver_type params.BidomainSolver.petsc_krylov_solver.relative_tolerance = 1e-12 else: params.BasicBidomainSolver.linear_variational_solver.linear_solver = \ "gmres" if solver_type == "iterative" else "lu" params.BasicBidomainSolver.linear_variational_solver.krylov_solver.relative_tolerance = 1e-12 params.BasicBidomainSolver.linear_variational_solver.preconditioner = 'ilu' self.solver = Solver(self.cardiac_model, params=params) (vs_, vs, vur) = self.solver.solution_fields() if ics is None: self.ics = self.cell_model.initial_conditions() vs_.assign(self.ics) else: vs_.vector()[:] = ics.vector()
def setup_model(): "Set-up cardiac model based on a slightly non-standard set of parameters." # Define cell parameters k = 0.00004; Vrest = -85.; Vthreshold = -70.; Vpeak = 40.; v_amp = Vpeak - Vrest l = 0.63; b = 0.013; cell_parameters = {"c_1": k*v_amp**2, "c_2": k*v_amp, "c_3": b/l, "a": (Vthreshold - Vrest)/v_amp, "b": l, "v_rest":Vrest, "v_peak": Vpeak} cell = FitzHughNagumoManual(cell_parameters) # Define conductivities chi = 2000.0 # cm^{-1} s_il = 3.0/chi # mS s_it = 0.3/chi # mS s_el = 2.0/chi # mS s_et = 1.3/chi # mS M_i = as_tensor(((s_il, 0), (0, s_it))) M_e = as_tensor(((s_el, 0), (0, s_et))) # Define mesh domain = UnitSquareMesh(20, 20) time = Constant(0.0) heart = CardiacModel(domain, time, M_i, M_e, cell) return heart
def test_solver_with_domains(): mesh = UnitCubeMesh(5, 5, 5) time = Constant(0.0) stimulus = Expression("2.0*t", t=time, degree=1) # Create ac applied_current = Expression("sin(2*pi*x[0])*t", t=time, degree=3) # Create conductivity "tensors" M_i = 1.0 M_e = 2.0 cell_model = FitzHughNagumoManual() cardiac_model = CardiacModel(mesh, time, M_i, M_e, cell_model, stimulus, applied_current) dt = 0.1 t0 = 0.0 dt = dt T = t0 + 5*dt ics = cell_model.initial_conditions() # Create basic solver params = SplittingSolver.default_parameters() params["ode_solver_choice"] = "BasicCardiacODESolver" solver = SplittingSolver(cardiac_model, params=params) (vs_, vs, vur) = solver.solution_fields() vs_.assign(ics) # Solve solutions = solver.solve((t0, T), dt) for (interval, fields) in solutions: (vs_, vs, vur) = fields
def setup(self): self.mesh = UnitCubeMesh(2, 2, 2) self.cell_model = FitzHughNagumoManual() self.cardiac_model = CardiacModel(self.mesh, None, 1.0, 2.0, self.cell_model)
class TestSplittingSolver(object): "Test functionality for the splitting solvers." def setup(self): self.mesh = UnitCubeMesh(5, 5, 5) # Create time self.time = Constant(0.0) # Create stimulus self.stimulus = Expression("2.0*t", t=self.time, degree=1) # Create ac self.applied_current = Expression("sin(2*pi*x[0])*t", t=self.time, degree=3) # Create conductivity "tensors" self.M_i = 1.0 self.M_e = 2.0 self.cell_model = FitzHughNagumoManual() self.cardiac_model = CardiacModel(self.mesh, self.time, self.M_i, self.M_e, self.cell_model, self.stimulus, self.applied_current) dt = 0.1 self.t0 = 0.0 self.dt = [(0.0, dt), (dt * 2, dt / 2), (dt * 4, dt)] # Test using variable dt interval but using the same dt. self.T = self.t0 + 5 * dt self.ics = self.cell_model.initial_conditions() @medium @parametrize(("solver_type"), ["direct", "iterative"]) def test_basic_and_optimised_splitting_solver_exact(self, solver_type): """Test that basic and optimised splitting solvers yield very comparative results when configured identically.""" # Create basic solver params = BasicSplittingSolver.default_parameters() params["BasicCardiacODESolver"]["S_polynomial_family"] = "CG" params["BasicCardiacODESolver"]["S_polynomial_degree"] = 1 solver = BasicSplittingSolver(self.cardiac_model, params=params) (vs_, vs, vur) = solver.solution_fields() vs_.assign(self.ics) # Solve solutions = solver.solve((self.t0, self.T), self.dt) for (interval, fields) in solutions: (vs_, vs, vur) = fields a = vs.vector().norm("l2") c = vur.vector().norm("l2") assert_almost_equal(interval[1], self.T, 1e-10) if dolfin_adjoint: adj_reset() # Create optimised solver with direct solution algorithm params = SplittingSolver.default_parameters() params["BidomainSolver"]["linear_solver_type"] = solver_type params["enable_adjoint"] = False if solver_type == "direct": params["BidomainSolver"]["use_avg_u_constraint"] = True solver = SplittingSolver(self.cardiac_model, params=params) (vs_, vs, vur) = solver.solution_fields() vs_.assign(self.ics) # Solve again solutions = solver.solve((self.t0, self.T), self.dt) for (interval, fields) in solutions: (vs_, vs, vur) = fields assert_almost_equal(interval[1], self.T, 1e-10) b = vs.vector().norm("l2") d = vur.vector().norm("l2") print "a, b = ", a, b print "c, d = ", c, d print "a - b = ", (a - b) print "c - d = ", (c - d) # Compare results, discrepancy is in difference in ODE # solves. assert_almost_equal(a, b, tolerance=1.) assert_almost_equal(c, d, tolerance=1.)
def test_fitz_hugh_nagumo_modified(self): k = 0.00004 Vrest = -85. Vthreshold = -70. Vpeak = 40. k = 0.00004 l = 0.63 b = 0.013 class FHN2(CardiacCellModel): """ODE model: parameters(Vrest,Vthreshold,Vpeak,k,l,b,ist) input(u) output(g) default_states(v=-85, w=0) Vrest = -85; Vthreshold = -70; Vpeak = 40; k = 0.00004; l = 0.63; b = 0.013; ist = 0.0 v = u[0] w = u[1] g[0] = -k*(v-Vrest)*(w+(v-Vthreshold)*(v-Vpeak))-ist; g[1] = l*(v-Vrest) - b*w; [specified by G. T. Lines Sept 22 2012] Note the minus sign convention here in the specification of I (g[0]) !! """ def __init__(self): CardiacCellModel.__init__(self) def default_parameters(self): parameters = Parameters("FHN2") parameters.add("Vrest", Vrest) parameters.add("Vthreshold", Vthreshold) parameters.add("Vpeak", Vpeak) parameters.add("k", k) parameters.add("l", l) parameters.add("b", b) parameters.add("ist", 0.0) return parameters def I(self, v, w, time=None): k = self._parameters["k"] Vrest = self._parameters["Vrest"] Vthreshold = self._parameters["Vthreshold"] Vpeak = self._parameters["Vpeak"] ist = self._parameters["ist"] i = -k * (v - Vrest) * (w + (v - Vthreshold) * (v - Vpeak)) - ist return -i def F(self, v, w, time=None): l = self._parameters["l"] b = self._parameters["b"] Vrest = self._parameters["Vrest"] return l * (v - Vrest) - b * w def num_states(self): return 1 def __str__(self): return "Modified FitzHugh-Nagumo cardiac cell model" def _run(cell): if dolfin_adjoint: from dolfin_adjoint import adj_reset adj_reset() solver = BasicSingleCellSolver(cell, Constant(0.0)) # Setup initial condition (vs_, vs) = solver.solution_fields() vs_.vector()[0] = 30. # Non-resting state vs_.vector()[1] = 0. T = 2 solutions = solver.solve((0, T), 0.25) times = [] v_values = [] s_values = [] for ((t0, t1), vs) in solutions: times += [0.5 * (t0 + t1)] v_values.append(vs.vector()[0]) s_values.append(vs.vector()[1]) return (v_values, s_values, times) # Try the modified one cell_mod = FHN2() (v_values_mod, s_values_mod, times_mod) = _run(cell_mod) # Compare with our standard FitzHugh (reparametrized) v_amp = Vpeak - Vrest cell_parameters = { "c_1": k * v_amp**2, "c_2": k * v_amp, "c_3": b / l, "a": (Vthreshold - Vrest) / v_amp, "b": l, "v_rest": Vrest, "v_peak": Vpeak } cell = FitzHughNagumoManual(cell_parameters) (v_values, s_values, times) = _run(cell) msg = "Mismatch in %s value comparison, diff = %.16e" v_diff = abs(v_values[-1] - v_values_mod[-1]) s_diff = abs(s_values[-1] - s_values_mod[-1]) assert (v_diff < 1.e-12), msg % v_diff assert (s_diff < 1.e-12), msg % s_diff # Look at some plots import os if int(os.environ.get("DOLFIN_NOPLOT", 0)) != 1: import pylab pylab.title("Standard FitzHugh-Nagumo") pylab.plot(times, v_values, 'b*') pylab.plot(times, s_values, 'r-') pylab.figure() pylab.title("Modified FitzHugh-Nagumo") pylab.plot(times_mod, v_values_mod, 'b*') pylab.plot(times_mod, s_values_mod, 'r-')
def test_fitzhugh_nagumo_manual(self): """Test that the manually written FitzHugh-Nagumo model gives comparable results to a given reference from Sundnes et al, 2006.""" class Stimulus(Expression): def __init__(self, **kwargs): self.t = kwargs["t"] def eval(self, value, x): if float(self.t) >= 50 and float(self.t) < 60: v_amp = 125 value[0] = 0.05 * v_amp else: value[0] = 0.0 if dolfin_adjoint: from dolfin_adjoint import adj_reset adj_reset() cell = FitzHughNagumoManual() time = Constant(0.0) cell.stimulus = Stimulus(t=time, degree=0) solver = BasicSingleCellSolver(cell, time) # Setup initial condition (vs_, vs) = solver.solution_fields() ic = cell.initial_conditions() vs_.assign(ic) # Initial set-up interval = (0, 400) dt = 1.0 times = [] v_values = [] s_values = [] # Solve solutions = solver.solve(interval, dt=dt) for (timestep, vs) in solutions: (t0, t1) = timestep times += [(t0 + t1) / 2] v_values += [vs.vector()[0]] s_values += [vs.vector()[1]] # Regression test v_max_reference = 2.6883308148064152e+01 s_max_reference = 6.8660144687023219e+01 tolerance = 1.e-14 print "max(v_values) %.16e" % max(v_values) print "max(s_values) %.16e" % max(s_values) msg = "Maximal %s value does not match reference: diff is %.16e" v_diff = abs(max(v_values) - v_max_reference) s_diff = abs(max(s_values) - s_max_reference) assert (v_diff < tolerance), msg % ("v", v_diff) assert (s_diff < tolerance), msg % ("s", s_diff) # Correctness test import os if int(os.environ.get("DOLFIN_NOPLOT", 0)) != 1: import pylab pylab.plot(times, v_values, 'b*') pylab.plot(times, s_values, 'r-')