def test_default_basic_single_cell_solver(self, cell_model, theta): "Test basic single cell solver." time = Constant(0.0) model = cell_model Model = cell_model.__class__ if Model == supported_cell_models[3] and theta > 0: pytest.xfail("failing configuration (but should work)") model.stimulus = Expression("1000*t", t=time, degree=1) info_green("\nTesting %s" % model) vec_solve = self._run_solve(model, time, theta) if Model == supported_cell_models[3] and theta == 0: pytest.xfail("failing configuration (but should work)") if Model in self.references and theta in self.references[Model]: ind, ref_value = self.references[Model][theta] print("vec_solve", vec_solve.get_local()) print("ind", ind, "ref", ref_value) assert_almost_equal(vec_solve[ind], ref_value, 1e-10) else: info_red("Missing references for %r, %r" % (Model, theta))
def test_compute_gradient(self): "Test that we can compute the gradient for some given functional" set_dolfin_parameters() model = Model() params = BasicSingleCellSolver.default_parameters() params["theta"] = theta time = Constant(0.0) solver = BasicSingleCellSolver(model, time, params=params) # Get initial conditions (Projection of expressions # don't get annotated, which is fine, because there is # no need.) ics = project(model.initial_conditions(), solver.VS) # Run forward model info_green("Running forward %s with theta %g" % (model, theta)) self._run(solver, model, ics) # Define functional (vs_, vs) = solver.solution_fields() J = Functional(inner(vs, vs) * dx * dt[FINISH_TIME]) # Compute gradient with respect to vs_. Highly unclear # why with respect to ics and vs fail. info_green("Computing gradient") dJdics = compute_gradient(J, Control(vs_)) assert (dJdics is not None), "Gradient is None (#fail)." print(dJdics.vector().array())
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_compute_adjoint(self): "Test that we can compute the adjoint for some given functional" set_dolfin_parameters() model = Model() params = BasicSingleCellSolver.default_parameters() params["theta"] = theta time = Constant(0.0) solver = BasicSingleCellSolver(model, time, params=params) # Get initial conditions (Projection of expressions # don't get annotated, which is fine, because there is # no need.) ics = project(model.initial_conditions(), solver.VS) # Run forward model info_green("Running forward %s with theta %g" % (model, theta)) self._run(solver, model, ics) (vs_, vs) = solver.solution_fields() # Define functional and compute gradient etc J = Functional(inner(vs_, vs_) * dx * dt[FINISH_TIME]) # Compute adjoint info_green("Computing adjoint") z = compute_adjoint(J) # Check that no vs_ adjoint is None (== 0.0!) for (value, var) in z: if var.name == "vs_": msg = "Adjoint solution for vs_ is None (#fail)." assert (value is not None), msg
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(self): self.mesh = UnitCubeMesh(5, 5, 5) self.time = Constant(0.0) # Create stimulus self.stimulus = Expression("2.0", degree=1) # Create conductivity "tensors" self.M_i = 1.0 self.t0 = 0.0 self.dt = 0.1
def test_compare_against_reference(self, Model, Scheme): ''' Runs the given cell model with the numerical scheme and compares the result with the reference value. ''' solver = self._setup_solver(Model, Scheme, time=Constant(0)) (vs_, vs) = solver.solution_fields() next_dt = 0.01 solver.step((0.0, next_dt)) vs_.assign(vs) solver.step((next_dt, 2 * next_dt)) self.compare_against_reference(vs.vector(), Model, Scheme)
def test_taylor_remainder(self): "Run Taylor remainder tests for selection of models and solvers." set_dolfin_parameters() model = Model() params = BasicSingleCellSolver.default_parameters() params["theta"] = theta time = Constant(0.0) solver = BasicSingleCellSolver(model, time, params=params) # Get initial conditions (Projection of expressions # don't get annotated, which is fine, because there is # no need.) ics = project(model.initial_conditions(), solver.VS) # Run forward model info_green("Running forward %s with theta %g" % (model, theta)) self._run(solver, model, ics) # Define functional (vs_, vs) = solver.solution_fields() form = lambda w: inner(w, w)*dx J = Functional(form(vs)*dt[FINISH_TIME]) # Compute value of functional with current ics Jics = assemble(form(vs)) # Compute gradient with respect to vs_ (ics?) dJdics = compute_gradient(J, Control(vs_), forget=False) # Stop annotating parameters["adjoint"]["stop_annotating"] = True # Set-up runner def Jhat(ics): self._run(solver, model, ics) (vs_, vs) = solver.solution_fields() return assemble(form(vs)) # Run taylor test if isinstance(model, Tentusscher_2004_mcell): seed=1.e-5 else: seed=None conv_rate = taylor_test(Jhat, Control(vs_), Jics, dJdics, seed=seed) # Check that minimal rate is greater than some given number assert_greater(conv_rate, 1.8)
def _setup_solver(self, model, Scheme, mesh): # Initialize time and stimulus (note t=time construction!) time = Constant(0.0) stim = Expression("(time >= stim_start) && (time < stim_start + stim_duration)" " ? stim_amplitude : 0.0 ", time=time, stim_amplitude=52.0, stim_start=0.0, stim_duration=1.0, name="stim", degree=1) # Initialize solver params = CardiacODESolver.default_parameters() params["scheme"] = Scheme solver = CardiacODESolver(mesh, time, model, I_s=stim, params=params) return solver
def main(N, dt, T, theta): if dolfin_adjoint: adj_reset() # Create cardiac model mesh = UnitSquareMesh(N, N) time = Constant(0.0) cell_model = NoCellModel() ac_str = "cos(t)*cos(2*pi*x[0])*cos(2*pi*x[1]) + 4*pow(pi, 2)*cos(2*pi*x[0])*cos(2*pi*x[1])*sin(t)" stimulus = Expression(ac_str, t=time, degree=3) heart = CardiacModel(mesh, time, 1.0, 1.0, cell_model, stimulus=stimulus) # Set-up solver ps = BasicSplittingSolver.default_parameters() ps["theta"] = theta ps["BasicBidomainSolver"]["linear_variational_solver"][ "linear_solver"] = "direct" solver = BasicSplittingSolver(heart, params=ps) # Define exact solution (Note: v is returned at end of time # interval(s), u is computed at somewhere in the time interval # depending on theta) v_exact = Expression("cos(2*pi*x[0])*cos(2*pi*x[1])*sin(t)", t=T, degree=3) u_exact = Expression("-cos(2*pi*x[0])*cos(2*pi*x[1])*sin(t)/2.0", t=T - (1 - theta) * dt, degree=3) # Define initial condition(s) vs0 = Function(solver.VS) (vs_, vs, vur) = solver.solution_fields() vs_.assign(vs0) # Solve solutions = solver.solve((0, T), dt) for (timestep, (vs_, vs, vur)) in solutions: continue # Compute errors (v, s) = vs.split(deepcopy=True) v_error = errornorm(v_exact, v, "L2", degree_rise=2) (v, u, r) = vur.split(deepcopy=True) u_error = errornorm(u_exact, u, "L2", degree_rise=2) return (v_error, u_error, mesh.hmin(), dt, T)
def setUp(self): self.mesh = UnitCubeMesh(5, 5, 5) self.time = Constant(0.0) # Create stimulus self.stimulus = Expression("2.0", 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.t0 = 0.0 self.dt = 0.1
def test_replay(self): "Test that replay reports success for basic single cell solver" set_dolfin_parameters() model = Model() # Initialize solver params = BasicSingleCellSolver.default_parameters() params["theta"] = theta time = Constant(0.0) solver = BasicSingleCellSolver(model, time, params=params) info_green("Running %s with theta %g" % (model, theta)) ics = project(model.initial_conditions(), solver.VS).copy(deepcopy=True, name="ics") self._run(solver, model, ics) info_green("Replaying") success = replay_dolfin(tol=0.0, stop=True) assert_true(success)
def test_compare_against_reference_constant(self, Model, Scheme): ''' Runs the given cell model with the numerical scheme and compares the result with the reference value. ''' Model = eval(Model) params = Model.default_parameters() self.replace_with_constants(params) solver = self._setup_solver(Model, Scheme, time=Constant(0), params=params) (vs_, vs) = solver.solution_fields() next_dt = 0.01 solver.step((0.0, next_dt)) vs_.assign(vs) solver.step((next_dt, 2 * next_dt)) self.compare_against_reference(vs.vector(), Model, Scheme)
def tlm_adj_setup_cellmodel_parameters(self, cell_model, Scheme): mesh = UnitIntervalMesh(3) Model = cell_model.__class__ # Initiate solver, with model and Scheme cell_params = Model.default_parameters() param_name = cellmodel_parameters_seeds[Model][0] cell_params[param_name] = Constant(cell_params[param_name], name=param_name) model = Model(params=cell_params) solver = self._setup_solver(model, Scheme, mesh) info_green("Running forward %s with %s (setup)" % (model, Scheme)) ics = Function(project(model.initial_conditions(), solver.VS), name="ics") self._run(solver, ics) # Define functional (vs_, vs) = solver.solution_fields() form = lambda w: inner(w, w) * dx J = Functional(form(vs) * dt[FINISH_TIME]) # Compute value of functional with current ics Jics = assemble(form(vs)) # Set-up runner def Jhat(val): cell_params[param_name].assign(val) ics = Function(project(model.initial_conditions(), solver.VS), name="ics") self._run(solver, ics) (vs_, vs) = solver.solution_fields() return assemble(form(vs)) # Stop annotating solver.parameters["enable_adjoint"] = False m = ConstantControl(cell_params[param_name]) return J, Jhat, m, Jics
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)
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 replace_with_constants(self, params): ''' Replace all float values in params by Constants. ''' for param_name in params.keys(): value = params[param_name] params[param_name] = Constant(value)
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-')
def long_run_compare(self): mesh = UnitIntervalMesh(5) # FIXME: We need to make this run in paralell. if MPI.size(mesh.mpi_comm()) > 1: return Model = Tentusscher_2004_mcell tstop = 10 ind_V = 0 dt_ref = 0.1 time_ref = np.linspace(0, tstop, int(tstop/dt_ref)+1) dir_path = os.path.dirname(__file__) Vm_reference = np.fromfile(os.path.join(dir_path, "Vm_reference.npy")) params = Model.default_parameters() time = Constant(0.0) stim = Expression("(time >= stim_start) && (time < stim_start + stim_duration)"\ " ? stim_amplitude : 0.0 ", time=time, stim_amplitude=52.0, \ stim_start=1.0, stim_duration=1.0, degree=1) # Initiate solver, with model and Scheme if dolfin_adjoint: adj_reset() solver = self._setup_solver(Model, Scheme, mesh, time, stim, params) solver._pi_solver.parameters["newton_solver"]["relative_tolerance"] = 1e-8 solver._pi_solver.parameters["newton_solver"]["maximum_iterations"] = 30 solver._pi_solver.parameters["newton_solver"]["report"] = False scheme = solver._scheme (vs_, vs) = solver.solution_fields() vs.assign(vs_) dof_to_vertex_map_values = dof_to_vertex_map(vs.function_space()) scheme.t().assign(0.0) vs_array = np.zeros(mesh.num_vertices()*\ vs.function_space().dofmap().num_entity_dofs(0)) vs_array[dof_to_vertex_map_values] = vs.vector().array() output = [vs_array[ind_V]] time_output = [0.0] dt = dt_org # Time step next_dt = max(min(tstop-float(scheme.t()), dt), 0.0) t0 = 0.0 while next_dt > 0.0: # Step solver solver.step((t0, t0 + next_dt)) vs_.assign(vs) # Collect plt output data vs_array[dof_to_vertex_map_values] = vs.vector().array() output.append(vs_array[ind_V]) time_output.append(float(scheme.t())) # Next time step t0 += next_dt next_dt = max(min(tstop-float(scheme.t()), dt), 0.0) # Compare solution from CellML run using opencell assert_almost_equal(output[-1], Vm_reference[-1], abs_tol) output = np.array(output) time_output = np.array(time_output) output = np.interp(time_ref, time_output, output) value = np.sqrt(np.sum(((Vm_reference-output)/Vm_reference)**2))/len(Vm_reference) assert_almost_equal(value, 0.0, rel_tol)