/**
     * 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);
     }
    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);
    }
    void TestSMCmodelModified(void) throw (Exception)
    {
        // Set stimulus (no stimulus in this case)
        double magnitude_stimulus = 0.0;   // dimensionless
        double duration_stimulus = 0.05;  // ms
        double start_stimulus = 0.01;   // ms
        double period=1;//
        boost::shared_ptr<RegularStimulus> stimulus(new RegularStimulus(magnitude_stimulus,
                                                                        duration_stimulus,
                                                                        period,
                                                                        start_stimulus));

        boost::shared_ptr<EulerIvpOdeSolver> solver(new EulerIvpOdeSolver); //define the solver

        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.1,0.1,1);
        CorriasBuistSMCModified smc_ode_system(solver, stimulus);

        TS_ASSERT_EQUALS(smc_ode_system.GetCarbonMonoxideScaleFactor(), 1.0); //coverage
        smc_ode_system.SetCarbonMonoxideScaleFactor(1.0);//coverage
        // Solve and write to file
        RunOdeSolverWithIonicModel(&smc_ode_system,
                                   60000,/*end time, in milliseconds*/
                                   "SMCmodel_modified",
                                   1000);

        // Calculate APDs and compare with hardcoded values
        ColumnDataReader data_reader1("TestIonicModels", "SMCmodel_modified");
        std::vector<double> voltages = data_reader1.GetValues("Vm_SM");
        //create the times vector
        double k =0;
        std::vector<double> times;
        for (unsigned i=0; i<voltages.size(); i++)
        {
          times.push_back(k);
          k=k+100;
        }

        CellProperties cell_properties(voltages, times, -45.0);//note the lower threshold for SMC calculation of 'AP');

        TS_ASSERT_DELTA(cell_properties.GetLastActionPotentialDuration(50), 8331.3835, 0.1);
        TS_ASSERT_DELTA(cell_properties.GetLastActionPotentialDuration(70), 8571.1671, 0.1);
        TS_ASSERT_DELTA(cell_properties.GetLastActionPotentialDuration(80), 8722.6543, 0.1);
        TS_ASSERT_DELTA(cell_properties.GetLastActionPotentialDuration(90), 8955.8126, 0.1);

        CorriasBuistSMCModified smc_ode_system_no_stim(solver, stimulus);

        //check the default value of the presence of ICC stimulus
        TS_ASSERT_EQUALS(smc_ode_system_no_stim.GetFakeIccStimulusPresent(), true);
        //Switch off ICC stimulus and check the voltage is almost flat
        smc_ode_system_no_stim.SetFakeIccStimulusPresent(false);
        //check member variable was switched correctly
        TS_ASSERT_EQUALS(smc_ode_system_no_stim.GetFakeIccStimulusPresent(), false);
        // Solve and write to file
        RunOdeSolverWithIonicModel(&smc_ode_system_no_stim,
                                   60000,/*end time, in milliseconds*/
                                   "SMCmodel_modified_nostim",
                                   1000);

        // Calculate APDs and compare with hardcoded values
        ColumnDataReader data_reader2("TestIonicModels", "SMCmodel_modified_nostim");
        std::vector<double> voltages_flat = data_reader2.GetValues("Vm_SM");

        CellProperties  cell_properties_2(voltages_flat, times, -45.0);

        //it should be flat now, no AP and cell properties should throw
        TS_ASSERT_THROWS_THIS(cell_properties_2.GetLastActionPotentialDuration(90),
                            "AP did not occur, never exceeded threshold voltage.");

     }