void TestAssigningModifiersToACellModel() throw(Exception) { boost::shared_ptr<ZeroStimulus> p_stimulus(new ZeroStimulus()); boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver); CellShannon2004FromCellML* p_shannon = new CellShannon2004FromCellML(p_solver, p_stimulus); TS_ASSERT_EQUALS(p_shannon->HasModifier("Alan"), false); TS_ASSERT_THROWS_THIS(p_shannon->GetModifier("Alan"), "There is no modifier called Alan in this model."); // Default modifier shouldn't do anything to the value inputted to calc() TS_ASSERT_EQUALS(p_shannon->HasModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance"), true); TS_ASSERT_DELTA(p_shannon->GetModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance")->Calc(123,0),123,1e-9); // Make a new modifier boost::shared_ptr<AbstractModifier> p_new_modifier(new FixedModifier(-90.0)); TS_ASSERT_THROWS_THIS(p_shannon->SetModifier("Alan",p_new_modifier), "There is no modifier called Alan in this model."); // Assign it to the Shannon model p_shannon->SetModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance",p_new_modifier); // We should now get a new answer to this. TS_ASSERT_DELTA(p_shannon->GetModifier("membrane_rapid_delayed_rectifier_potassium_current_conductance")->Calc(0,0),-90,1e-9); delete p_shannon; }
// Run normally up to stretch-time, then apply stretch and // run until stretch-off-time, then return to stretch=1 // and run until 1000ms. void RunModelWithSacRecruitment(double stretch, double stretchStartTime, double stretchEndTime, std::string directory, std::string filePrefix, bool clearDir) { boost::shared_ptr<SimpleStimulus> p_stimulus(new SimpleStimulus( -3 /*magnitude*/, 3 /*duration*/, 10.0 /*start time*/)); boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver); double time_step = 0.01; HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(time_step, time_step, 1.0); CML_noble_varghese_kohl_noble_1998_basic_with_sac n98_with_sac(p_solver, p_stimulus); OutputFileHandler handler(directory,clearDir); out_stream p_file = handler.OpenOutputFile(filePrefix+".dat"); *p_file << 0 << " " << n98_with_sac.GetVoltage() << "\n"; double printing_dt = 1; TimeStepper stepper(0, stretchStartTime, printing_dt); while ( !stepper.IsTimeAtEnd() ) { n98_with_sac.Compute(stepper.GetTime(), stepper.GetNextTime()); stepper.AdvanceOneTimeStep(); *p_file << stepper.GetTime() << " " << n98_with_sac.GetVoltage() << "\n"; } n98_with_sac.SetStretch(stretch); TimeStepper stepper2(stepper.GetTime(), stretchEndTime, printing_dt); while ( !stepper2.IsTimeAtEnd() ) { n98_with_sac.Compute(stepper2.GetTime(), stepper2.GetNextTime()); stepper2.AdvanceOneTimeStep(); *p_file << stepper2.GetTime() << " " << n98_with_sac.GetVoltage() << "\n"; } n98_with_sac.SetStretch(1.0); TimeStepper stepper3(stepper2.GetTime(), 1000, printing_dt); while ( !stepper3.IsTimeAtEnd() ) { n98_with_sac.Compute(stepper3.GetTime(), stepper3.GetNextTime()); stepper3.AdvanceOneTimeStep(); *p_file << stepper3.GetTime() << " " << n98_with_sac.GetVoltage() << "\n"; } p_file->close(); }
void TestOdeSolverForFox2002WithRegularStimulus(void) throw (Exception) { clock_t ck_start, ck_end; // Set stimulus double magnitude = -80.0; double duration = 1.0 ; // ms double start = 50.0; // ms double period = 500; // ms boost::shared_ptr<RegularStimulus> p_stimulus(new RegularStimulus(magnitude, duration, period, start)); double end_time = 1000.0; //One second in milliseconds HeartConfig::Instance()->SetOdeTimeStep(0.002); // 0.005 leads to NaNs. boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver); CellFoxModel2002FromCellML fox_ode_system(p_solver, p_stimulus); // Solve and write to file ck_start = clock(); RunOdeSolverWithIonicModel(&fox_ode_system, end_time, "FoxRegularStimLong", 500); ck_end = clock(); double forward = (double)(ck_end - ck_start)/CLOCKS_PER_SEC; CheckCellModelResults("FoxRegularStimLong"); // Solve using Backward Euler HeartConfig::Instance()->SetOdeTimeStep(0.01); CellFoxModel2002FromCellMLBackwardEuler backward_system(p_solver, p_stimulus); ck_start = clock(); RunOdeSolverWithIonicModel(&backward_system, end_time, "BackwardFoxRegularStimLong", 100); ck_end = clock(); double backward = (double)(ck_end - ck_start)/CLOCKS_PER_SEC; CompareCellModelResults("FoxRegularStimLong", "BackwardFoxRegularStimLong", 0.15); // Mainly for coverage, and to test consistency of GetIIonic TS_ASSERT_DELTA(fox_ode_system.GetIIonic(), backward_system.GetIIonic(), 1e-6); std::cout << "Run times:\n\tForward: " << forward << "\n\tBackward: " << backward << std::endl; }
void TestAccessingParametersWithoutModifiers() throw(Exception) { boost::shared_ptr<ZeroStimulus> p_stimulus(new ZeroStimulus()); boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver); CellShannon2004FromCellML* p_shannon = new CellShannon2004FromCellML(p_solver, p_stimulus); // We should now have all of the following methods available as an alternative to using 'modifiers' TS_ASSERT_DELTA(p_shannon->GetParameter("membrane_fast_sodium_current_conductance"),16.0,1e-5); TS_ASSERT_DELTA(p_shannon->GetParameter("membrane_L_type_calcium_current_conductance"),5.4e-4,1e-5); TS_ASSERT_DELTA(p_shannon->GetParameter("membrane_rapid_delayed_rectifier_potassium_current_conductance"),0.03,1e-5); TS_ASSERT_DELTA(p_shannon->GetParameter("membrane_slow_delayed_rectifier_potassium_current_conductance"),0.07,1e-5); delete p_shannon; }
void TestArchiving(void) throw(Exception) { //Archive OutputFileHandler handler("archive", false); handler.SetArchiveDirectory(); std::string archive_filename = ArchiveLocationInfo::GetProcessUniqueFilePath("GI.arch"); // Save { boost::shared_ptr<SimpleStimulus> p_stimulus(new SimpleStimulus(0.0,1.0,0.5)); boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver); double time_step = 0.01; HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(time_step, time_step, time_step); // icc and smc AbstractCardiacCell* const p_smc = new CorriasBuistSMCModified(p_solver, p_stimulus); AbstractCardiacCell* const p_icc = new CorriasBuistICCModified(p_solver, p_stimulus); std::ofstream ofs(archive_filename.c_str()); boost::archive::text_oarchive output_arch(ofs); output_arch << p_smc; output_arch << p_icc; delete p_smc; delete p_icc; } // Load { std::ifstream ifs(archive_filename.c_str(), std::ios::binary); boost::archive::text_iarchive input_arch(ifs); AbstractCardiacCell* p_smc; AbstractCardiacCell* p_icc; input_arch >> p_smc; input_arch >> p_icc; TS_ASSERT_EQUALS( p_smc->GetNumberOfStateVariables(), 14U ); TS_ASSERT_EQUALS( p_icc->GetNumberOfStateVariables(), 18U ); delete p_smc; delete p_icc; } }
void GenerateCells() throw (Exception) { // Do the conversions preserving generated sources CellMLToSharedLibraryConverter converter(true); std::string dirname = "TestGeneralizedRushLarsen"; std::string model = "LuoRudy1991"; boost::shared_ptr<AbstractIvpOdeSolver> p_solver; boost::shared_ptr<ZeroStimulus> p_stimulus(new ZeroStimulus()); std::vector<std::string> args; args.push_back("--grl1"); { // No opt // Copy CellML file into output dir OutputFileHandler handler(dirname + "/normal"); FileFinder cellml_file("heart/src/odes/cellml/" + model + ".cellml", RelativeTo::ChasteSourceRoot); FileFinder copied_file = handler.CopyFileTo(cellml_file); // Create options file & convert converter.CreateOptionsFile(handler, model, args); DynamicCellModelLoaderPtr p_loader = converter.Convert(copied_file); mpGeneralizedRushLarsenCell = dynamic_cast<AbstractCardiacCell*>(p_loader->CreateCell(p_solver, p_stimulus)); } }
boost::shared_ptr<AbstractStimulusFunction> CreateStimulusForNode(Node<2>* pNode) { boost::shared_ptr<SimpleStimulus> p_stimulus ( new SimpleStimulus(-428000, 1.0, 0.1) ); return p_stimulus; }
void TestHHModelAtSingularities() { /* * Set stimulus */ double magnitude_stimulus = 0.0; // uA/cm2 double duration_stimulus = 0.; // ms double start_stimulus = 0.0; // ms boost::shared_ptr<SimpleStimulus> p_stimulus(new SimpleStimulus( magnitude_stimulus, duration_stimulus, start_stimulus)); boost::shared_ptr<AbstractIvpOdeSolver> p_solver; // We don't actually need a solver CellHodgkinHuxley1952FromCellML hh52_ode_system(p_solver, p_stimulus); double v_singularity[2]; v_singularity[0]=-65; v_singularity[1]=-50; for (int i=0; i<2; i++) { std::vector<double> yleft; //mVariableNames.push_back("V"); //mVariableUnits.push_back("mV"); yleft.push_back(v_singularity[i]+0.1); //mVariableNames.push_back("n"); //mVariableUnits.push_back(""); yleft.push_back(0.325); //mVariableNames.push_back("h"); //mVariableUnits.push_back(""); yleft.push_back(0.6); //mVariableNames.push_back("m"); //mVariableUnits.push_back(""); yleft.push_back(0.05); std::vector<double> rhsleft(yleft.size()); hh52_ode_system.EvaluateYDerivatives (0.0, yleft, rhsleft); std::vector<double> yright; //mVariableNames.push_back("V"); //mVariableUnits.push_back("mV"); yright.push_back(v_singularity[i]-0.1); //mVariableNames.push_back("n"); //mVariableUnits.push_back(""); yright.push_back(0.325); //mVariableNames.push_back("h"); //mVariableUnits.push_back(""); yright.push_back(0.6); //mVariableNames.push_back("m"); //mVariableUnits.push_back(""); yright.push_back(0.05); std::vector<double> rhsright(yright.size()); hh52_ode_system.EvaluateYDerivatives (0.0, yright, rhsright); std::vector<double> y_at_singularity; //mVariableNames.push_back("V"); //mVariableUnits.push_back("mV"); y_at_singularity.push_back(v_singularity[i]); //mVariableNames.push_back("n"); //mVariableUnits.push_back(""); y_at_singularity.push_back(0.325); //mVariableNames.push_back("h"); //mVariableUnits.push_back(""); y_at_singularity.push_back(0.6); //mVariableNames.push_back("m"); //mVariableUnits.push_back(""); y_at_singularity.push_back(0.05); std::vector<double> rhs_at_singularity(y_at_singularity.size()); hh52_ode_system.EvaluateYDerivatives (0.0, y_at_singularity, rhs_at_singularity); for (int j=0; j<4; j++) { //std::cout << j << "\t" << rhsright[j] << "\t" << rhsleft[j] << "\t" << rhs_at_singularity[j] << std::endl; TS_ASSERT_DELTA((rhsright[j]+rhsleft[j])/2, rhs_at_singularity[j], 0.1); } } }
void TestTimingsWithAndWithoutJacobian() throw (Exception) { #ifdef CHASTE_CVODE // Set up a default solver and a stimulus boost::shared_ptr<AbstractIvpOdeSolver> p_solver; boost::shared_ptr<AbstractStimulusFunction> p_stimulus(new RegularStimulus(-25,5,1000,1)); double simulation_duration = 10000; // This increased to 1e6 to give the timings shown on #1795. double max_time_step = 1.0; for (unsigned i=0; i<10; i++) { boost::shared_ptr<CvodeAdaptor> p_cvode_adaptor(new CvodeAdaptor()); // moving this outside the loop causes seg-faults! p_cvode_adaptor->SetTolerances(1e-5, 1e-7); // Match AbstractCvodeCell boost::shared_ptr<AbstractCardiacCell> p_cell_cvode_adaptor; boost::shared_ptr<AbstractCvodeCell> p_cell_cvode; switch (i) { case 0: { // Fox model p_cell_cvode_adaptor.reset(new CellFoxModel2002FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellFoxModel2002FromCellMLCvode(p_solver,p_stimulus)); break; } case 1: { // Shannon model p_cell_cvode_adaptor.reset(new CellShannon2004FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellShannon2004FromCellMLCvode(p_solver,p_stimulus)); break; } case 2: { // HH1952 model p_cell_cvode_adaptor.reset(new CellHodgkinHuxley1952FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellHodgkinHuxley1952FromCellMLCvode(p_solver,p_stimulus)); break; } case 3: { // Luo Rudy model p_cell_cvode_adaptor.reset(new CellLuoRudy1991FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellLuoRudy1991FromCellMLCvode(p_solver,p_stimulus)); break; } case 4: { // Mahajan model p_cell_cvode_adaptor.reset(new CellMahajan2008FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellMahajan2008FromCellMLCvode(p_solver,p_stimulus)); break; } case 5: { // Maleckar model p_cell_cvode_adaptor.reset(new CellMaleckar2008FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellMaleckar2008FromCellMLCvode(p_solver,p_stimulus)); break; } case 6: { // FaberRudy2000 model p_cell_cvode_adaptor.reset(new CellFaberRudy2000FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellFaberRudy2000FromCellMLCvode(p_solver,p_stimulus)); break; } case 7: { // DiFrancescoNoble1985 model p_cell_cvode_adaptor.reset(new CellDiFrancescoNoble1985FromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellDiFrancescoNoble1985FromCellMLCvode(p_solver,p_stimulus)); break; } case 8: { // NobleVargheseKohlNoble1998a model p_cell_cvode_adaptor.reset(new CellNobleVargheseKohlNoble1998aFromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellNobleVargheseKohlNoble1998aFromCellMLCvode(p_solver,p_stimulus)); break; } case 9: { // TenTusscher2006Epi model p_cell_cvode_adaptor.reset(new CellTenTusscher2006EpiFromCellML(p_cvode_adaptor,p_stimulus)); p_cell_cvode.reset(new CellTenTusscher2006EpiFromCellMLCvode(p_solver,p_stimulus)); break; } default: EXCEPTION("No model"); } std::cout << p_cell_cvode_adaptor->GetSystemName() << ": " << p_cell_cvode_adaptor->GetNumberOfStateVariables() << " ODEs.\n"; // A standard CVODE adaptor solve p_cvode_adaptor->SetMaxSteps(0xffffffff); p_cell_cvode_adaptor->SetTimestep(max_time_step); Timer::Reset(); p_cell_cvode_adaptor->SolveAndUpdateState(0, simulation_duration); Timer::Print(" 1. CVODE adaptor (numeric Jacobian)"); // A standard native CVODE solve p_cell_cvode->SetMaxSteps(0xffffffff); p_cell_cvode->SetMaxTimestep(max_time_step); p_cell_cvode->ForceUseOfNumericalJacobian(true); TS_ASSERT(!p_cell_cvode->GetUseAnalyticJacobian()); Timer::Reset(); p_cell_cvode->SolveAndUpdateState(0, simulation_duration); Timer::Print(" 2. CVODE native with Numeric Jacobian"); // A jacobian native CVODE solve p_cell_cvode->ResetToInitialConditions(); p_cell_cvode->ForceUseOfNumericalJacobian(false); TS_ASSERT(p_cell_cvode->GetUseAnalyticJacobian()); Timer::Reset(); p_cell_cvode->SolveAndUpdateState(0, simulation_duration); Timer::Print(" 3. CVODE native with Analytic Jacobian"); } #else std::cout << "CVODE is not installed or Chaste hostconfig is not using it." << std::endl; #endif }
void TestLuoRudyGeneralizedRushLarsenMethod2() { EXIT_IF_PARALLEL; HeartConfig::Instance()->SetOdeTimeStep(0.01); GenerateCells2(); // Check the models really use Rush-Larsen TS_ASSERT_EQUALS(Warnings::Instance()->GetNumWarnings(), 0u); // Normal Luo-Rudy for comparison boost::shared_ptr<HeunIvpOdeSolver> p_heun_solver(new HeunIvpOdeSolver()); CellLuoRudy1991FromCellML reference_model(p_heun_solver, mpGeneralizedRushLarsenCell->GetStimulusFunction()); // Check GetIIonic is identical TS_ASSERT_DELTA(mpGeneralizedRushLarsenCell->GetIIonic(), reference_model.GetIIonic(), 1e-12); // Test non-stimulated cell (using ComputeExceptVoltage) mpGeneralizedRushLarsenCell->ComputeExceptVoltage(0.0, 1.0); reference_model.ComputeExceptVoltage(0.0, 1.0); TS_ASSERT_EQUALS(mpGeneralizedRushLarsenCell->GetNumberOfStateVariables(), reference_model.GetNumberOfStateVariables()); for (unsigned i=0; i<reference_model.GetNumberOfStateVariables(); i++) { TS_ASSERT_DELTA(mpGeneralizedRushLarsenCell->rGetStateVariables()[i], reference_model.rGetStateVariables()[i], 1e-6); } // Test stimulated cell (using Compute) boost::shared_ptr<SimpleStimulus> p_stimulus(new SimpleStimulus(-25.5, 1.99, 0.0)); mpGeneralizedRushLarsenCell->ResetToInitialConditions(); mpGeneralizedRushLarsenCell->SetStimulusFunction(p_stimulus); OdeSolution solutions_GRL2 = mpGeneralizedRushLarsenCell->Compute(0.0, 1.0, 0.01); TS_ASSERT_EQUALS(solutions_GRL2.GetNumberOfTimeSteps(), 100u); reference_model.ResetToInitialConditions(); reference_model.SetStimulusFunction(p_stimulus); OdeSolution solutions_ref = reference_model.Compute(0.0, 1.0, 0.01); for (unsigned i=0; i<reference_model.GetNumberOfStateVariables(); i++) { TS_ASSERT_DELTA(solutions_GRL2.rGetSolutions().back()[i], solutions_ref.rGetSolutions().back()[i], 1e-2); } //Compare LuoRudy solution with general GRL2 solver solution (should match) mpGeneralizedRushLarsenCell->ResetToInitialConditions(); boost::shared_ptr<ZeroStimulus> p_stimulus_zero(new ZeroStimulus()); mpGeneralizedRushLarsenCell->ResetToInitialConditions(); mpGeneralizedRushLarsenCell->SetStimulusFunction(p_stimulus_zero); mpGeneralizedRushLarsenCell->SetTimestep(1e-3); mpGeneralizedRushLarsenCell->SetVoltage(-30); OdeSolution solutions_GRL2_stimulated_cell_order2 = mpGeneralizedRushLarsenCell->Compute(0.0, 1e-3); boost::shared_ptr<GRL2IvpOdeSolver> p_grl2_solver(new GRL2IvpOdeSolver()); CellLuoRudy1991FromCellML reference_model_grl2(p_grl2_solver, mpGeneralizedRushLarsenCell->GetStimulusFunction()); // Compare with general GRL2 method reference_model_grl2.ResetToInitialConditions(); reference_model_grl2.SetStimulusFunction(p_stimulus_zero); reference_model_grl2.SetTimestep(1e-3); reference_model_grl2.SetVoltage(-30); OdeSolution ref_solution_grl2 = reference_model_grl2.Compute(0.0, 1e-3); for (unsigned i=0; i<reference_model_grl2.GetNumberOfStateVariables(); i++) { double error1 = solutions_GRL2_stimulated_cell_order2.rGetSolutions().back()[i] - ref_solution_grl2.rGetSolutions().back()[i]; TS_ASSERT_DELTA(fabs(error1),0,5e-7); } // Free memory delete mpGeneralizedRushLarsenCell; // delete mpGeneralizedRushLarsenCellOpt; }
void TestLuoRudyGeneralizedRushLarsenMethod() { EXIT_IF_PARALLEL; HeartConfig::Instance()->SetOdeTimeStep(0.01); GenerateCells(); // Check the models really use Rush-Larsen TS_ASSERT_EQUALS(Warnings::Instance()->GetNumWarnings(), 0u); // Some coverage AbstractGeneralizedRushLarsenCardiacCell* p_grl_cell = dynamic_cast<AbstractGeneralizedRushLarsenCardiacCell*>(mpGeneralizedRushLarsenCell); TS_ASSERT(p_grl_cell); TS_ASSERT(!p_grl_cell->HasAnalyticJacobian()); TS_ASSERT(!p_grl_cell->GetUseAnalyticJacobian()); TS_ASSERT_THROWS_THIS(p_grl_cell->ForceUseOfNumericalJacobian(false), "Using analytic Jacobian terms for generalised Rush-Larsen is not yet supported."); TS_ASSERT_THROWS_NOTHING(p_grl_cell->ForceUseOfNumericalJacobian(true)); // Normal Luo-Rudy for comparison boost::shared_ptr<HeunIvpOdeSolver> p_heun_solver(new HeunIvpOdeSolver()); CellLuoRudy1991FromCellML reference_model(p_heun_solver, mpGeneralizedRushLarsenCell->GetStimulusFunction()); // Check GetIIonic is identical TS_ASSERT_DELTA(mpGeneralizedRushLarsenCell->GetIIonic(), reference_model.GetIIonic(), 1e-12); // Test non-stimulated cell (using ComputeExceptVoltage) mpGeneralizedRushLarsenCell->ComputeExceptVoltage(0.0, 1.0); reference_model.ComputeExceptVoltage(0.0, 1.0); TS_ASSERT_EQUALS(mpGeneralizedRushLarsenCell->GetNumberOfStateVariables(), reference_model.GetNumberOfStateVariables()); for (unsigned i=0; i<reference_model.GetNumberOfStateVariables(); i++) { TS_ASSERT_DELTA(mpGeneralizedRushLarsenCell->rGetStateVariables()[i], reference_model.rGetStateVariables()[i], 1e-6); } // Test stimulated cell (using Compute) boost::shared_ptr<SimpleStimulus> p_stimulus(new SimpleStimulus(-25.5, 1.99, 0.0)); mpGeneralizedRushLarsenCell->ResetToInitialConditions(); mpGeneralizedRushLarsenCell->SetStimulusFunction(p_stimulus); OdeSolution solutions_GRL1 = mpGeneralizedRushLarsenCell->Compute(0.0, 1.0, 0.01); TS_ASSERT_EQUALS(solutions_GRL1.GetNumberOfTimeSteps(), 100u); reference_model.ResetToInitialConditions(); reference_model.SetStimulusFunction(p_stimulus); OdeSolution solutions_ref = reference_model.Compute(0.0, 1.0, 0.01); for (unsigned i=0; i<reference_model.GetNumberOfStateVariables(); i++) { TS_ASSERT_DELTA(solutions_GRL1.rGetSolutions().back()[i], solutions_ref.rGetSolutions().back()[i], 1e-2); } //Compare LuoRudy solution with general GRL1 solver solution (should match) mpGeneralizedRushLarsenCell->ResetToInitialConditions(); boost::shared_ptr<ZeroStimulus> p_stimulus_zero(new ZeroStimulus()); mpGeneralizedRushLarsenCell->SetStimulusFunction(p_stimulus_zero); mpGeneralizedRushLarsenCell->SetTimestep(1e-3); mpGeneralizedRushLarsenCell->SetVoltage(-30); OdeSolution solutions_GRL1_stimulated_cell_order1 = mpGeneralizedRushLarsenCell->Compute(0.0, 1e-3); // Compare with SolveAndUpdateState for coverage mpGeneralizedRushLarsenCell->ResetToInitialConditions(); mpGeneralizedRushLarsenCell->SetVoltage(-30); mpGeneralizedRushLarsenCell->SolveAndUpdateState(0.0, 1e-3); for (unsigned i=0; i<mpGeneralizedRushLarsenCell->GetNumberOfStateVariables(); i++) { TS_ASSERT_DELTA(mpGeneralizedRushLarsenCell->rGetStateVariables()[i], solutions_GRL1_stimulated_cell_order1.rGetSolutions().back()[i], 1e-12); } // Compare with general GRL1 method boost::shared_ptr<GRL1IvpOdeSolver> p_grl1_solver(new GRL1IvpOdeSolver()); CellLuoRudy1991FromCellML reference_model_grl1(p_grl1_solver, mpGeneralizedRushLarsenCell->GetStimulusFunction()); reference_model_grl1.ResetToInitialConditions(); reference_model_grl1.SetStimulusFunction(p_stimulus_zero); reference_model_grl1.SetTimestep(1e-3); reference_model_grl1.SetVoltage(-30); OdeSolution ref_solution_grl1 = reference_model_grl1.Compute(0.0, 1e-3); for (unsigned i=0; i<reference_model_grl1.GetNumberOfStateVariables(); i++) { double error1 = solutions_GRL1_stimulated_cell_order1.rGetSolutions().back()[i] - ref_solution_grl1.rGetSolutions().back()[i]; TS_ASSERT_DELTA(fabs(error1),0,5e-7); } // Test order of convergence (first-order method) // Get two solutions with halved stepsize mpGeneralizedRushLarsenCell->ResetToInitialConditions(); reference_model_grl1.SetStimulusFunction(p_stimulus_zero); reference_model_grl1.SetVoltage(-30); mpGeneralizedRushLarsenCell->SetTimestep(0.002); solutions_GRL1_stimulated_cell_order1 = mpGeneralizedRushLarsenCell->Compute(0.0, 1.0); mpGeneralizedRushLarsenCell->ResetToInitialConditions(); reference_model_grl1.SetStimulusFunction(p_stimulus_zero); reference_model_grl1.SetVoltage(-30); mpGeneralizedRushLarsenCell->SetTimestep(0.001); OdeSolution solutions_GRL1_stimulated_cell_order2 = mpGeneralizedRushLarsenCell->Compute(0.0, 1.0); // Get accurate solution to be used as reference solution //boost::shared_ptr<HeunIvpOdeSolver> p_heun_solver(new HeunIvpOdeSolver()); reference_model.SetStimulusFunction(p_stimulus_zero); reference_model.SetVoltage(-30); reference_model.ResetToInitialConditions(); reference_model.SetTimestep(1e-6); OdeSolution ref_solution = reference_model.Compute(0.0, 1.0); for (unsigned i=0; i<reference_model.GetNumberOfStateVariables(); i++) { double error1 = solutions_GRL1_stimulated_cell_order1.rGetSolutions().back()[i] - ref_solution.rGetSolutions().back()[i]; double error2 = solutions_GRL1_stimulated_cell_order2.rGetSolutions().back()[i] - ref_solution.rGetSolutions().back()[i]; TS_ASSERT_DELTA(error1/error2, 2, 0.1); } // Free memory delete mpGeneralizedRushLarsenCell; // delete mpGeneralizedRushLarsenCellOpt; }
void TestScaleFactorsMaleckar(void) throw (Exception) { double end_time =500; boost::shared_ptr<RegularStimulus> p_stimulus(new RegularStimulus(-5.6, 6, 1000, 4.0)); boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver); //define the solver HeartConfig::Instance()->SetOdeTimeStep(0.001); CellMaleckar2008FromCellML atrial_ode_system(p_solver, p_stimulus); const std::string control_file = "control"; const std::string first_set_file = "first_scale_factor_set"; const std::string second_set_file = "second_scale_factor_set"; const std::string AZD_file = "AZD_scale_factor_set"; OdeSolution control_solution; OdeSolution first_scale_factor_set_solution; OdeSolution second_scale_factor_set_solution; OdeSolution AZD_scale_factor_set_solution; double time_step=0.001; double sampling_time=0.001; std::vector<double> state_variables= atrial_ode_system.GetInitialConditions(); //default values atrial_ode_system.SetParameter("ScaleFactorGks",1.0); atrial_ode_system.SetParameter("ScaleFactorIto",1.0); atrial_ode_system.SetParameter("ScaleFactorGkr",1.0); atrial_ode_system.SetParameter("ScaleFactorGna",1.0); atrial_ode_system.SetParameter("ScaleFactorAch",1e-24); atrial_ode_system.SetParameter("ScaleFactorGNaK",1.0); atrial_ode_system.SetParameter("ScaleFactorGNaCa",1.0); atrial_ode_system.SetParameter("ScaleFactorGKur",1.0); atrial_ode_system.SetParameter("ScaleFactorGK1",1.0); atrial_ode_system.SetParameter("ScaleFactorGCaL",1.0); atrial_ode_system.SetParameter("ScaleFactorAZD",0.0); control_solution = p_solver->Solve(&atrial_ode_system, state_variables, 0, end_time, time_step, sampling_time); control_solution.WriteToFile("TestIonicModels", control_file, "ms",//time units 100,//steps per row false);/*true cleans the directory*/ //now apply the first scale factor set, decreases outward currents atrial_ode_system.SetParameter("ScaleFactorGks",0.8); atrial_ode_system.SetParameter("ScaleFactorIto",1.0); atrial_ode_system.SetParameter("ScaleFactorGkr",0.9); atrial_ode_system.SetParameter("ScaleFactorGna",1.0); atrial_ode_system.SetParameter("ScaleFactorAch",1e-24); atrial_ode_system.SetParameter("ScaleFactorGNaK",1.0); atrial_ode_system.SetParameter("ScaleFactorGNaCa",1.0); atrial_ode_system.SetParameter("ScaleFactorGKur",0.7); atrial_ode_system.SetParameter("ScaleFactorGK1",0.6); atrial_ode_system.SetParameter("ScaleFactorGCaL",1.0); atrial_ode_system.SetParameter("ScaleFactorAZD",0.0); state_variables= atrial_ode_system.GetInitialConditions(); first_scale_factor_set_solution = p_solver->Solve(&atrial_ode_system, state_variables, 0, end_time, time_step, sampling_time); first_scale_factor_set_solution.WriteToFile("TestIonicModels", first_set_file, "ms",//time units 100,//steps per row false);/*true cleans the directory*/ //now apply the secondscale factor set, this one increases inward currents atrial_ode_system.SetParameter("ScaleFactorGks",1.0); atrial_ode_system.SetParameter("ScaleFactorIto",1.0); atrial_ode_system.SetParameter("ScaleFactorGkr",1.0); atrial_ode_system.SetParameter("ScaleFactorGna",1.5); atrial_ode_system.SetParameter("ScaleFactorAch",1e-24); atrial_ode_system.SetParameter("ScaleFactorGNaK",1.0); atrial_ode_system.SetParameter("ScaleFactorGNaCa",2.0); atrial_ode_system.SetParameter("ScaleFactorGKur",1.0); atrial_ode_system.SetParameter("ScaleFactorGK1",1.0); atrial_ode_system.SetParameter("ScaleFactorGCaL",1.6); atrial_ode_system.SetParameter("ScaleFactorAZD",0.0); state_variables= atrial_ode_system.GetInitialConditions(); second_scale_factor_set_solution = p_solver->Solve(&atrial_ode_system, state_variables, 0, end_time, time_step, sampling_time); second_scale_factor_set_solution.WriteToFile("TestIonicModels", second_set_file, "ms",//time units 100,//steps per row false);/*true cleans the directory*/ //check the AZD scale factor (vs control) atrial_ode_system.SetParameter("ScaleFactorGks",1.0); atrial_ode_system.SetParameter("ScaleFactorIto",1.0); atrial_ode_system.SetParameter("ScaleFactorGkr",1.0); atrial_ode_system.SetParameter("ScaleFactorGna",1.0); atrial_ode_system.SetParameter("ScaleFactorAch",1e-24); atrial_ode_system.SetParameter("ScaleFactorGNaK",1.0); atrial_ode_system.SetParameter("ScaleFactorGNaCa",1.0); atrial_ode_system.SetParameter("ScaleFactorGKur",1.0); atrial_ode_system.SetParameter("ScaleFactorGK1",1.0); atrial_ode_system.SetParameter("ScaleFactorGCaL",1.0); atrial_ode_system.SetParameter("ScaleFactorAZD",5.0); AZD_scale_factor_set_solution = p_solver->Solve(&atrial_ode_system, state_variables, 0, end_time, time_step, sampling_time); AZD_scale_factor_set_solution.WriteToFile("TestIonicModels", AZD_file, "ms",//time units 100,//steps per row false);/*true cleans the directory*/ ColumnDataReader data_reader1("TestIonicModels", control_file); std::vector<double> voltages1 = GetVoltages(data_reader1); ColumnDataReader data_reader2("TestIonicModels", first_set_file); std::vector<double> voltages2 = GetVoltages(data_reader2); ColumnDataReader data_reader3("TestIonicModels", second_set_file); std::vector<double> voltages3 = GetVoltages(data_reader3); ColumnDataReader data_reader4("TestIonicModels", AZD_file); std::vector<double> voltages4 = GetVoltages(data_reader4); TS_ASSERT_EQUALS(voltages1.size(), voltages2.size()); TS_ASSERT_EQUALS(voltages2.size(), voltages3.size()); TS_ASSERT_EQUALS(voltages3.size(), voltages4.size()); //create the times vector std::vector<double> times; double k =0; for (unsigned i=0; i<voltages2.size(); i++) { times.push_back(k); k=k+0.1; } CellProperties cell_properties_control(voltages1, times); CellProperties cell_properties_first(voltages2, times); CellProperties cell_properties_second(voltages3, times); CellProperties cell_properties_AZD(voltages4, times); double control_APD = cell_properties_control.GetLastActionPotentialDuration(90); double first_APD = cell_properties_first.GetLastActionPotentialDuration(90); double second_APD = cell_properties_second.GetLastActionPotentialDuration(90); double AZD_APD = cell_properties_AZD.GetLastActionPotentialDuration(90); //test that the aps are actually longer than control (all interventions were meant to have that effect except the last one) TS_ASSERT_LESS_THAN(control_APD, first_APD); TS_ASSERT_LESS_THAN(control_APD, second_APD); TS_ASSERT_LESS_THAN(AZD_APD, control_APD); //leave some hardcoded value for testing TS_ASSERT_DELTA(control_APD, 206.1278, 0.1); TS_ASSERT_DELTA(first_APD, 403.8293, 0.1); TS_ASSERT_DELTA(second_APD, 320.0195, 0.1); TS_ASSERT_DELTA(AZD_APD , 187.8073, 0.1); }
/** * Here we test that the scale factors for the TT model do what they are expected to * We check that they modify APD in a way that is expected. */ void TestScaleFactorsForTT06(void) { double simulation_end=500;/*end time, in milliseconds for this model*/ // Set the stimulus, the following values are appropriate for single cell simulations of this model. double magnitude = -38.0; // pA/pF double duration = 1.0; // ms double start = 100; // ms boost::shared_ptr<SimpleStimulus> p_stimulus(new SimpleStimulus(magnitude, duration, start)); boost::shared_ptr<EulerIvpOdeSolver> p_solver(new EulerIvpOdeSolver); //define the solver HeartConfig::Instance()->SetOdeTimeStep(0.001);// with Forward Euler, this must be as small as 0.001. const std::string control_file = "TT_epi"; const std::string mid_file = "TT_mid"; const std::string endo_file = "TT_endo"; const std::string LQT_file = "TT_LQT"; CellTenTusscher2006EpiFromCellML TT_model_epi(p_solver, p_stimulus); TT_model_epi.SetParameter("ScaleFactorIto", 1.0); TT_model_epi.SetParameter("ScaleFactorGkr", 1.0); TT_model_epi.SetParameter("ScaleFactorGks", 1.0); //run the model RunOdeSolverWithIonicModel(&TT_model_epi, simulation_end, control_file, 100, false); CellTenTusscher2006EpiFromCellML TT_model_mid(p_solver, p_stimulus); TT_model_mid.SetParameter("ScaleFactorIto", 1.0); TT_model_mid.SetParameter("ScaleFactorGkr", 1.0); TT_model_mid.SetParameter("ScaleFactorGks", 0.25); RunOdeSolverWithIonicModel(&TT_model_mid, simulation_end, mid_file, 100, false); CellTenTusscher2006EpiFromCellML TT_model_endo(p_solver, p_stimulus); TT_model_endo.SetParameter("ScaleFactorIto", 0.165); TT_model_endo.SetParameter("ScaleFactorGkr", 1.0); TT_model_endo.SetParameter("ScaleFactorGks", 0.66); RunOdeSolverWithIonicModel(&TT_model_endo, simulation_end, endo_file, 100, false); CellTenTusscher2006EpiFromCellML TT_model_LQT(p_solver, p_stimulus); TT_model_LQT.SetParameter("ScaleFactorIto", 1.0); TT_model_LQT.SetParameter("ScaleFactorGkr", 0.0); TT_model_LQT.SetParameter("ScaleFactorGks", 1.0); RunOdeSolverWithIonicModel(&TT_model_LQT, simulation_end, LQT_file, 100, false); ColumnDataReader data_reader1("TestIonicModels", control_file); std::vector<double> voltages1 = GetVoltages(data_reader1); ColumnDataReader data_reader2("TestIonicModels", mid_file); std::vector<double> voltages2 = GetVoltages(data_reader2); ColumnDataReader data_reader3("TestIonicModels", endo_file); std::vector<double> voltages3 = GetVoltages(data_reader3); ColumnDataReader data_reader4("TestIonicModels", LQT_file); std::vector<double> voltages4 = GetVoltages(data_reader4); TS_ASSERT_EQUALS(voltages1.size(), voltages2.size()); TS_ASSERT_EQUALS(voltages2.size(), voltages3.size()); TS_ASSERT_EQUALS(voltages3.size(), voltages4.size()); //create the times vector std::vector<double> times; double k =0; for (unsigned i=0; i<voltages2.size(); i++) { times.push_back(k); k=k+0.1; } CellProperties cell_properties_control(voltages1, times); CellProperties cell_properties_mid(voltages2, times); CellProperties cell_properties_endo(voltages3, times); CellProperties cell_properties_LQT(voltages4, times); double control_APD = cell_properties_control.GetLastActionPotentialDuration(90); double mid_APD = cell_properties_mid.GetLastActionPotentialDuration(90); double endo_APD = cell_properties_endo.GetLastActionPotentialDuration(90); double LQT_APD = cell_properties_LQT.GetLastActionPotentialDuration(90); TS_ASSERT_DELTA(control_APD, 300.4789, 0.1); TS_ASSERT_DELTA(mid_APD, 392.1871, 0.1); TS_ASSERT_DELTA(endo_APD, 329.2048, 0.1); TS_ASSERT_DELTA(LQT_APD , 347.8374, 0.1); }
/** * Here we test the scale factors methiods for the mahajan model. * The idea is to set the scale factors for the 3 different cell types (epi, mid and endo) * and check that the rsulting APD makes sense if compared to experiemntal results */ void TestScaleFactorsForMahajanModel(void) throw(Exception) { double end_time=300; double time_step=0.01; double sampling_time=time_step; // Set stimulus double magnitude_stimulus = -70.0; // pA/pF double duration_stimulus = 1.0; // ms double start_stimulus = 10.0; // ms double period=1000;//here, this is ms boost::shared_ptr<RegularStimulus> p_stimulus(new RegularStimulus(magnitude_stimulus, duration_stimulus, period, start_stimulus)); boost::shared_ptr<EulerIvpOdeSolver> p_forward_solver(new EulerIvpOdeSolver); //define the solver CellMahajan2008FromCellML forward_model(p_forward_solver, p_stimulus); boost::shared_ptr<BackwardEulerIvpOdeSolver> p_backward_solver(new BackwardEulerIvpOdeSolver( forward_model.GetNumberOfStateVariables())); CellMahajan2008FromCellML epicardial_model(p_backward_solver, p_stimulus); CellMahajan2008FromCellML endocardial_model(p_backward_solver, p_stimulus); CellMahajan2008FromCellML midmyocardial_model(p_backward_solver, p_stimulus); epicardial_model.SetParameter("ScaleFactorGks",1.0); epicardial_model.SetParameter("ScaleFactorIto",1.0); epicardial_model.SetParameter("ScaleFactorGkr",1.0); midmyocardial_model.SetParameter("ScaleFactorGks",0.09); midmyocardial_model.SetParameter("ScaleFactorIto",1.0); midmyocardial_model.SetParameter("ScaleFactorGkr",1.0); endocardial_model.SetParameter("ScaleFactorGks",0.86); endocardial_model.SetParameter("ScaleFactorIto",0.2); endocardial_model.SetParameter("ScaleFactorGkr",1.0); std::vector<double> state_variables_epi = epicardial_model.GetInitialConditions(); std::vector<double> state_variables_endo = endocardial_model.GetInitialConditions(); std::vector<double> state_variables_mid = midmyocardial_model.GetInitialConditions(); const std::string mahajan_epi_file = "Mahajan_epi"; const std::string mahajan_mid_file = "Mahajan_mid"; const std::string mahajan_endo_file = "Mahajan_endo"; // Solve and write to file OdeSolution epi_solution; epi_solution = p_backward_solver->Solve(&epicardial_model, state_variables_epi, 0, end_time, time_step, sampling_time); epi_solution.WriteToFile("TestIonicModels", mahajan_epi_file, "ms",//time units 100,//steps per row false);/*true cleans the directory*/ OdeSolution mid_solution; mid_solution = p_backward_solver->Solve(&midmyocardial_model, state_variables_mid, 0, end_time, time_step, sampling_time); mid_solution.WriteToFile("TestIonicModels", mahajan_mid_file, "ms",//time units 100,//steps per row false);/*true cleans the directory*/ OdeSolution endo_solution; endo_solution = p_backward_solver->Solve(&endocardial_model, state_variables_endo, 0, end_time, time_step, sampling_time); endo_solution.WriteToFile("TestIonicModels", mahajan_endo_file, "ms",//time units 100,//steps per row false);/*true cleans the directory*/ ColumnDataReader data_reader_epi("TestIonicModels", mahajan_epi_file); ColumnDataReader data_reader_mid("TestIonicModels", mahajan_mid_file); ColumnDataReader data_reader_endo("TestIonicModels", mahajan_endo_file); std::vector<double> times = data_reader_epi.GetValues("Time"); std::vector<double> v_endo = data_reader_endo.GetValues("membrane_voltage"); std::vector<double> v_epi = data_reader_epi.GetValues("membrane_voltage"); std::vector<double> v_mid = data_reader_mid.GetValues("membrane_voltage"); CellProperties cell_properties_endo(v_endo, times); CellProperties cell_properties_epi(v_epi, times); CellProperties cell_properties_mid(v_mid, times); double epi_APD = cell_properties_epi.GetLastActionPotentialDuration(90); double endo_APD = cell_properties_endo.GetLastActionPotentialDuration(90); double mid_APD = cell_properties_mid.GetLastActionPotentialDuration(90); // Check that percentage increase from epi to mid and endo (roughly*) matches results // from McIntosh et al. Card Res, 45:397-409. 200 (Figure 1 and 2) // *this is cardiac modelling after all... TS_ASSERT_DELTA((mid_APD-epi_APD)*100/epi_APD, 48.6, 2); // new values because gtos and gtof were the wrong way round (in Mahajan paper - they copied and pasted from Shannon wrong!) TS_ASSERT_DELTA((endo_APD-epi_APD)*100/epi_APD, 15.7, 2); // "" }