void Test2dHardcodedResult() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-1000*1000);

        // run to 125 ms - about where the width is at its minimum (see figures
        // in "A numerical method for cardiac mechano–electric simulations", Annals of Biomed. Imaging

        HeartConfig::Instance()->SetSimulationDuration(125.0);

        CardiacElectroMechProbRegularGeom<2> problem(INCOMPRESSIBLE,
                                                     1.0,  /* width */
                                                     5,    /* mech mesh size */
                                                     60,   /* elec elem each dir */
                                                     &cell_factory,
                                                     NHS,
                                                     1.0,  /* mechanics solve timestep */
                                                     1.0,  /* contraction model ode dt */
                                                     "TestCardiacEmNhs2dLong");

        problem.SetNoElectricsOutput();
        problem.Solve();

        // test by checking the length of the tissue against hardcoded value
        std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition();
        TS_ASSERT_DELTA(r_deformed_position[5](0), 0.8257, 1e-3);

        MechanicsEventHandler::Headings();
        MechanicsEventHandler::Report();
    }
    // longer running, finer-mesh version of TestWithCompressibleApproach() in TestCardiacElectroMechanicsProblem.hpp
    void TestWithCompressibleApproachLong() throw(Exception)
    {
        HeartEventHandler::Disable();

        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-1000*1000);

        HeartConfig::Instance()->SetSimulationDuration(50.0);

        CardiacElectroMechProbRegularGeom<2> problem(COMPRESSIBLE,
                                                     0.05, /* width (cm) */
                                                     20,   /* mech mesh size*/
                                                     5,    /* elec elem each dir */
                                                     &cell_factory,
                                                     KERCHOFFS2003,
                                                     1.0,   /* mechanics solve timestep */
                                                     0.01,  /* Kerchoffs ode timestep */
                                                     "TestCompressibleWithKerchoffsLong");

        problem.Solve();

        // Mainly just testing no errors when Solve was called.
        // The results of this test can be visually compared with the results of the
        // equivalent incompressible simulation in TestWithKerchoffs.

        TS_ASSERT_DELTA(problem.rGetDeformedPosition()[20](0), 0.0438, 0.0002);
        TS_ASSERT_DELTA(problem.rGetDeformedPosition()[20](1),-0.0032, 0.0002);
    }
    void TestWithKerchoffs() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-1000*1000);

        HeartConfig::Instance()->SetSimulationDuration(20.0);

        CardiacElectroMechProbRegularGeom<2> problem(INCOMPRESSIBLE,
                                                     0.05, /* width (cm) */
                                                     1,    /* mech mesh size*/
                                                     5,    /* elec elem each dir */
                                                     &cell_factory,
                                                     KERCHOFFS2003,
                                                     1.0,   /* mechanics solve timestep */
                                                     0.01,  /* Kerchoffs ode timestep */
                                                     "TestCardiacEmWithKerchoffs");

        c_vector<double,2> pos;
        pos(0) = 0.05;
        pos(1) = 0.0;

        problem.SetWatchedPosition(pos);
        problem.SetNoElectricsOutput();
        problem.Initialise();

        problem.Solve();

        //visualise to verify

        // hardcoded result
        TS_ASSERT_EQUALS(problem.mWatchedMechanicsNodeIndex, 1u);
        TS_ASSERT_DELTA(problem.rGetDeformedPosition()[1](0), 0.0479, 0.0002);
        TS_ASSERT_DELTA(problem.rGetDeformedPosition()[1](1),-0.0003, 0.0002);
    }
    void TestWithCompressibleApproach() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-1000*1000);

        HeartConfig::Instance()->SetSimulationDuration(20.0);

        CardiacElectroMechProbRegularGeom<2> problem(COMPRESSIBLE,
                                                     0.05, /* width (cm) */
                                                     1,    /* mech mesh size*/
                                                     5,    /* elec elem each dir */
                                                     &cell_factory,
                                                     KERCHOFFS2003,
                                                     1.0,   /* mechanics solve timestep */
                                                     0.01,  /* Kerchoffs ode timestep */
                                                     "TestCompressibleWithKerchoffs");

        problem.Solve();

        // Mainly just testing no errors when Solve was called.
        // The results of this test can be visually compared with the results of the
        // equivalent incompressible simulation in TestWithKerchoffs.

        TS_ASSERT_DELTA(problem.rGetDeformedPosition()[1](0), 0.0472, 0.0002);
        TS_ASSERT_DELTA(problem.rGetDeformedPosition()[1](1),-0.0012, 0.0002);

        // create and initialise an incompressible NASH2004 problem, just for coverage..
        HeartConfig::Instance()->SetSimulationDuration(20.0);
        CardiacElectroMechProbRegularGeom<2> problem2(COMPRESSIBLE,0.05,1,5,&cell_factory,
                                                      NASH2004,
                                                      1.0, 0.01,"");
        problem2.Initialise();
    }
    void Test2dVariableFibres() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-1000*1000);

        TetrahedralMesh<2,2> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(1.0/96.0/*stepsize*/, 1.0/*length*/, 1.0/*width*/, 1.0/*depth*/);

        QuadraticMesh<2> mechanics_mesh;
        mechanics_mesh.ConstructRegularSlabMesh(0.2, 1.0, 1.0, 1.0 /*as above with a different stepsize*/);

        std::vector<unsigned> fixed_nodes
            = NonlinearElasticityTools<2>::GetNodesByComponentValue(mechanics_mesh, 0, 0.0); // all the X=0.0 nodes

        ElectroMechanicsProblemDefinition<2> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(NHS,1.0);
        problem_defn.SetUseDefaultCardiacMaterialLaw(INCOMPRESSIBLE);
        problem_defn.SetZeroDisplacementNodes(fixed_nodes);
        problem_defn.SetMechanicsSolveTimestep(1.0);

        FileFinder finder("heart/test/data/fibre_tests/5by5mesh_curving_fibres.ortho",RelativeTo::ChasteSourceRoot);
        problem_defn.SetVariableFibreSheetDirectionsFile(finder, false);

        HeartConfig::Instance()->SetSimulationDuration(125.0);

        CardiacElectroMechanicsProblem<2,1> problem(INCOMPRESSIBLE,
                                                  MONODOMAIN,
                                                  &electrics_mesh,
                                                  &mechanics_mesh,
                                                  &cell_factory,
                                                  &problem_defn,
                                                  "TestCardiacEmVaryingFibres");


//        // fibres going from (1,0) at X=0 to (1,1)-direction at X=1
//        // the fibres file was created with the code (inside a class that owns a mesh)
//        for(unsigned elem_index=0; elem_index<mechanics_mesh.GetNumElements(); elem_index++)
//        {
//            double X = mechanics_mesh.GetElement(elem_index)->CalculateCentroid()[0];
//            double theta = M_PI*X/4;
//            std::cout << cos(theta) << " " << sin(theta) << " " << -sin(theta) << " " << cos(theta) << "\n" << std::flush;
//        }
//        assert(0);

        // problem.SetNoElectricsOutput();
        problem.Solve();

        // test by checking the length of the tissue against hardcoded value
        std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition();
        // visualised, looks good - contracts in X-direction near the fixed surface,
        // but on the other side the fibres are in the (1,1) direction, so contraction
        // pulls the tissue downward a bit
        TS_ASSERT_DELTA(r_deformed_position[5](0), 0.9055, 2e-3);
        //IntelProduction differs by about 1.6e-3...

        MechanicsEventHandler::Headings();
        MechanicsEventHandler::Report();
    }
    void TestBathIntracellularStimulation() throw (Exception)
    {
        HeartConfig::Instance()->SetSimulationDuration(10.0);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath1d");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_1d");

        c_vector<double,1> centre;
        centre(0) = 0.5;
        BathCellFactory<1> cell_factory(-1e6, centre); // stimulates x=0.5 node

        BidomainWithBathProblem<1> bidomain_problem( &cell_factory );

        TrianglesMeshReader<1,1> reader("mesh/test/data/1D_0_to_1_100_elements");
        TetrahedralMesh<1,1> mesh;
        mesh.ConstructFromMeshReader(reader);

        // set the x<0.25 and x>0.75 regions as the bath region
        for(unsigned i=0; i<mesh.GetNumElements(); i++)
        {
            double x = mesh.GetElement(i)->CalculateCentroid()[0];
            if( (x<0.25) || (x>0.75) )
            {
                mesh.GetElement(i)->SetAttribute(HeartRegionCode::GetValidBathId());
            }
        }

        bidomain_problem.SetMesh(&mesh);
        bidomain_problem.Initialise();

        bidomain_problem.Solve();

        Vec sol = bidomain_problem.GetSolution();
        ReplicatableVector sol_repl(sol);

        // test V = 0 for all bath nodes
        for(unsigned i=0; i<mesh.GetNumNodes(); i++)
        {
            if(HeartRegionCode::IsRegionBath( mesh.GetNode(i)->GetRegion() )) // bath
            {
                TS_ASSERT_DELTA(sol_repl[2*i], 0.0, 1e-12);
            }
        }

        // test symmetry of V and phi_e
        for(unsigned i=0; i<=(mesh.GetNumNodes()-1)/2; i++)
        {
            unsigned opposite = mesh.GetNumNodes()-i-1;
            TS_ASSERT_DELTA(sol_repl[2*i], sol_repl[2*opposite], 2e-3);      // V
            TS_ASSERT_DELTA(sol_repl[2*i+1], sol_repl[2*opposite+1], 2e-3);  // phi_e
        }

        // a couple of hardcoded values
        TS_ASSERT_DELTA(sol_repl[2*50], 3.7684, 1e-3);
        TS_ASSERT_DELTA(sol_repl[2*70], 5.1777, 1e-3);
    }
// Build a linked list and print it out
item * ll_sanity_check()
{
  item * head = cell_factory(0);
  item * tmp = NULL;
  item * curr = head;

  int i;
  for( i=1; i<10; i++)
  {
    tmp = cell_factory(i);
    tmp->next = NULL;
    curr->next = tmp;
    curr = curr->next;
  }

  printf("This should print from 0 to 9\n");
  print_list(head);
  printf("-----------------------------\n");

  return head;
}
    void Test3dBathIntracellularStimulation()
    {
        HeartConfig::Instance()->SetSimulationDuration(1);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath3d");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_3d");

        c_vector<double,3> centre;
        centre(0) = 0.05;
        centre(1) = 0.05;
        centre(2) = 0.05;
        BathCellFactory<3> cell_factory(-2.5e7, centre); // stimulates x=0.05 node

        BidomainProblem<3> bidomain_problem( &cell_factory, true );

        TetrahedralMesh<3,3> mesh;
        mesh.ConstructRegularSlabMesh(0.01, 0.1, 0.1, 0.1);

        // Set everything outside a central sphere (radius 0.4) to be bath
        for (unsigned i=0; i<mesh.GetNumElements(); i++)
        {
            double x = mesh.GetElement(i)->CalculateCentroid()[0];
            double y = mesh.GetElement(i)->CalculateCentroid()[1];
            double z = mesh.GetElement(i)->CalculateCentroid()[2];
            if (sqrt((x-0.05)*(x-0.05) + (y-0.05)*(y-0.05) + (z-0.05)*(z-0.05)) > 0.04)
            {
                mesh.GetElement(i)->SetAttribute(HeartRegionCode::GetValidBathId());
            }
        }

        bidomain_problem.SetMesh(&mesh);
        bidomain_problem.Initialise();

        bidomain_problem.Solve();

        Vec sol = bidomain_problem.GetSolution();
        ReplicatableVector sol_repl(sol);

        // test V = 0 for all bath nodes
        for (unsigned i=0; i<mesh.GetNumNodes(); i++)
        {
            if (HeartRegionCode::IsRegionBath( mesh.GetNode(i)->GetRegion() )) // bath
            {
                TS_ASSERT_DELTA(sol_repl[2*i], 0.0, 1e-12);
            }
        }

        // a hardcoded value
        TS_ASSERT_DELTA(sol_repl[2*404], 39.6833, 1e-3);
    }
    void TestSimulation() throw(Exception)
    {
        HeartConfig::Instance()->SetSimulationDuration(5.0);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainTutorialWithBathAndFibres");
        HeartConfig::Instance()->SetOutputFilenamePrefix("results");

        /* Bath problems seem to require decreased ODE timesteps. We use the
         * Backward Euler version of the Luo-Rudy model (see below) instead to
         * improve code performance.
         */
        HeartConfig::Instance()->SetOdeTimeStep(0.01);  //ms

        /* Use the {{{PlaneStimulusCellFactory}}} to define a set of Luo-Rudy cells, in this
         * case with a Backward Euler solver. We pass the stimulus magnitude as 0.0
         * as we don't want any stimulated cells.
         */
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellMLBackwardEuler,2> cell_factory(0.0);

        /*
         * Note that in the previous bath example, a mesh was read in and elements where then set to be
         * bath elements in the test. With fibres as well, in a bath simulation, it is better to read in a
         * mesh that has all the information: this mesh has bath elements defined as an extra column in the
         * .ele file, and a .ortho file which defines the fibre direction for each element. Note that the
         * .ortho file should include fibre information for bath elements as well, but they won't be used
         * in the simulation. (The fibres read here are the same 'kinked' fibres as in the previous fibre
         * tutorial).
         */
        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/2D_0_to_1mm_800_elements_bath_sides", cp::media_type::Orthotropic);

        /* Set anistropic conductivities.
         */
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75, 0.175));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(7.0, 0.7));

        /* and now we define the electrodes.. */
        double magnitude = -9.0e3; // uA/cm^2
        double start_time = 0.0;
        double duration = 2; //ms
        HeartConfig::Instance()->SetElectrodeParameters(false, 0, magnitude, start_time, duration);

        /* Now create the problem class, using the cell factory and passing
         * in `true` as the second argument to indicate we are solving a bath
         * problem, and solve.
         */
        BidomainProblem<2> bidomain_problem( &cell_factory, true );
        bidomain_problem.Initialise();
        bidomain_problem.Solve();
    }
    ////////////////////////////////////////////////////////////
    // Compare Mono and Bidomain Simulations
    ////////////////////////////////////////////////////////////
    void TestCompareBidomainProblemWithMonodomain3D()
    {
        // the bidomain equations reduce to the monodomain equations
        // if sigma_e is infinite (equivalent to saying the extra_cellular
        // space is grounded. sigma_e is set to be very large here:
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75, 1.75, 1.75));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(17500, 17500, 17500));
        HeartConfig::Instance()->SetSimulationDuration(1.0);  //ms
        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/3D_0_to_1mm_6000_elements");
        HeartConfig::Instance()->SetOutputDirectory("Monodomain3d");
        HeartConfig::Instance()->SetOutputFilenamePrefix("monodomain3d");

        ///////////////////////////////////////////////////////////////////
        // monodomain
        ///////////////////////////////////////////////////////////////////
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 3> cell_factory(-600.0*1000);
        MonodomainProblem<3> monodomain_problem( &cell_factory );

        monodomain_problem.Initialise();
        monodomain_problem.Solve();

        ///////////////////////////////////////////////////////////////////
        // bidomain
        ///////////////////////////////////////////////////////////////////
        HeartConfig::Instance()->SetOutputDirectory("Bidomain3d");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain3d");

        BidomainProblem<3> bidomain_problem( &cell_factory );
        bidomain_problem.Initialise();
        bidomain_problem.Solve();

        ///////////////////////////////////////////////////////////////////
        // compare
        ///////////////////////////////////////////////////////////////////
        DistributedVector monodomain_voltage = monodomain_problem.GetSolutionDistributedVector();
        DistributedVector bidomain_solution = bidomain_problem.GetSolutionDistributedVector();
        DistributedVector::Stripe bidomain_voltage(bidomain_solution,0);
        DistributedVector::Stripe extracellular_potential(bidomain_solution,1);
        for (DistributedVector::Iterator index = bidomain_solution.Begin();
             index != bidomain_solution.End();
             ++index)
        {
            TS_ASSERT_DELTA(monodomain_voltage[index], bidomain_voltage[index], 0.5);
            TS_ASSERT_DELTA(extracellular_potential[index], 0, 1.0);
        }
    }
    void Test3d() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 3> cell_factory(-1000*1000);

        // set up two meshes of 1mm by 1mm by 1mm
        TetrahedralMesh<3,3> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(0.01, 0.1, 0.1, 0.1);

        QuadraticMesh<3> mechanics_mesh(0.1, 0.1, 0.1, 0.1);

        // fix the nodes on x=0
        std::vector<unsigned> fixed_nodes
          = NonlinearElasticityTools<3>::GetNodesByComponentValue(mechanics_mesh,0,0);


        HeartConfig::Instance()->SetSimulationDuration(50.0);

        ElectroMechanicsProblemDefinition<3> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(NHS,1.0);
        problem_defn.SetUseDefaultCardiacMaterialLaw(INCOMPRESSIBLE);
        problem_defn.SetZeroDisplacementNodes(fixed_nodes);
        problem_defn.SetMechanicsSolveTimestep(1.0);

        CardiacElectroMechanicsProblem<3,1> problem(INCOMPRESSIBLE,
                                                  MONODOMAIN,
                                                  &electrics_mesh,
                                                  &mechanics_mesh,
                                                  &cell_factory,
                                                  &problem_defn,
                                                  "TestCardiacElectroMech3d");

        problem.SetNoElectricsOutput();
        problem.Solve();

        // test by checking the length of the tissue against hardcoded value
        c_vector<double,3> undeformed_node_1 = mechanics_mesh.GetNode(1)->rGetLocation();
        TS_ASSERT_DELTA(undeformed_node_1(0), 0.1, 1e-6);
        TS_ASSERT_DELTA(undeformed_node_1(1), 0.0, 1e-6);
        TS_ASSERT_DELTA(undeformed_node_1(2), 0.0, 1e-6);
        std::vector<c_vector<double,3> >& r_deformed_position = problem.rGetDeformedPosition();
        TS_ASSERT_DELTA(r_deformed_position[1](0), 0.0879, 1e-3);

        MechanicsEventHandler::Headings();
        MechanicsEventHandler::Report();
    }
    void Test2dBathIntracellularStimulation() throw (Exception)
    {
        HeartConfig::Instance()->SetSimulationDuration(1.0);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath2d");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_2d");

        c_vector<double,2> centre;
        centre(0) = 0.05;
        centre(1) = 0.05;
        BathCellFactory<2> cell_factory(-5e6, centre); // stimulates x=0.05 node

        BidomainWithBathProblem<2> bidomain_problem( &cell_factory );

        DistributedTetrahedralMesh<2,2>* p_mesh = Load2dMeshAndSetCircularTissue<DistributedTetrahedralMesh<2,2> >(
            "mesh/test/data/2D_0_to_1mm_400_elements", 0.05, 0.05, 0.04);

        bidomain_problem.SetMesh(p_mesh);
        bidomain_problem.Initialise();

        bidomain_problem.Solve();

        Vec sol = bidomain_problem.GetSolution();
        ReplicatableVector sol_repl(sol);

        // test V = 0 for all bath nodes
        for (AbstractTetrahedralMesh<2,2>::NodeIterator iter=p_mesh->GetNodeIteratorBegin();
             iter != p_mesh->GetNodeIteratorEnd(); ++iter)
        {
            if (HeartRegionCode::IsRegionBath( (*iter).GetRegion() )) // bath
            {
                unsigned index=(*iter).GetIndex();

                TS_ASSERT_DELTA(sol_repl[2*index], 0.0, 1e-12);
            }
        }

        // A couple of hardcoded values. We would normally have to look up the index in the
        // permutation vector when using a DistributedTetrahedralMesh, however the call to
        // Load2dMeshAndSetCircularTissue above imposes a DUMB partition, so no need.
        TS_ASSERT_DELTA(sol_repl[2*50], 28.3912, 1e-3); // node 50
        TS_ASSERT_DELTA(sol_repl[2*70], 28.3912, 1e-3); // node 70

        delete p_mesh;
    }
    void TestProblemChecksUsingBathWithMultipleBathConductivities()
    {
        TrianglesMeshReader<2,2> reader("mesh/test/data/2D_0_to_1mm_400_elements");
        TetrahedralMesh<2,2> mesh;
        mesh.ConstructFromMeshReader(reader);

        std::set<unsigned> tissue_ids;
        tissue_ids.insert(0);

        std::set<unsigned> bath_ids;
        bath_ids.insert(1);
        bath_ids.insert(2); // non-default identifier!

        HeartConfig::Instance()->SetTissueAndBathIdentifiers(tissue_ids, bath_ids);

        BathCellFactory<2> cell_factory( 0.0, Create_c_vector(0.0, 0.0) );
        BidomainProblem<2> bidomain_problem( &cell_factory ); // non-bath problem, despite specifying bath stuff above!
        bidomain_problem.SetMesh( &mesh );
        TS_ASSERT_THROWS_THIS( bidomain_problem.Initialise() , "User has set bath identifiers, but the BidomainProblem isn't expecting a bath. Did you mean to use BidomainProblem(..., true)? Or alternatively, BidomainWithBathProblem(...)?");
    }
    void TestSwitchesOffAtCorrectTime() throw(Exception)
    {
        // zero stim cell factory
        c_vector<double,2> centre;
        centre(0) = 0.05; // cm
        centre(1) = 0.05; // cm
        BathCellFactory<2> cell_factory( 0.0, centre);

        // boundary flux for Phi_e. -10e3 is under threshold, -14e3 crashes the cell model
        //
        // Will use printing dt = 0.01 in second run below, so choose start and end times of the
        // electrode which don't coincide with printing times
        double boundary_flux = -11.0e3;
        double start_time = 0.5;
        double duration = 2.001; // of the stimulus, in ms

        HeartConfig::Instance()->SetOutputDirectory("ElectrodesSwitchOffAtCorrectTime");
        HeartConfig::Instance()->SetOutputFilenamePrefix("results");
        HeartConfig::Instance()->SetSimulationDuration(5.0);  //ms

        //////////////////////////////////////////////////////
        // solve with printing_dt = 0.01
        //////////////////////////////////////////////////////
        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.001, 0.01, 0.01);  //ms

        BidomainWithBathProblem<2> bidomain_problem1( &cell_factory );
        TetrahedralMesh<2,2>* p_mesh1 = Load2dMeshAndSetCircularTissue<TetrahedralMesh<2,2> >(
           "mesh/test/data/2D_0_to_1mm_400_elements", 0.05, 0.05, 0.02);

        HeartConfig::Instance()->SetElectrodeParameters(false, 0, boundary_flux, start_time, duration);

        bidomain_problem1.SetMesh(p_mesh1);
        bidomain_problem1.PrintOutput(false);
        bidomain_problem1.Initialise();

        TS_ASSERT_THROWS_THIS(bidomain_problem1.Solve(), "Additional times are now deprecated.  Use only to check whether the given times are met: "
                                                          "e.g. Electrode events should only happen on printing steps.");
        delete p_mesh1;
    }
    /* NOTE: This test has a twin in heart/test/tutorials/TestCardiacElectroMechanicsTutorial.hpp
     * TestCardiacElectroMechanicsTutorial::dontTestTwistingCube()
     *
     * If you need to re-generate the fibres for this test
     * * Remove "dont" from the tutorial
     * * Rerun it
     * * Copy output
       cp /tmp/$USER/testoutput/TutorialFibreFiles/5by5by5_fibres.orthoquad heart/test/data/fibre_tests/5by5by5_fibres_by_quadpt.orthoquad
     */
    void TestTwistingCube() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 3> cell_factory(-1000*1000);

        // set up two meshes of 1mm by 1mm by 1mm
        TetrahedralMesh<3,3> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(0.01, 0.1, 0.1, 0.1);

        QuadraticMesh<3> mechanics_mesh(0.02, 0.1, 0.1, 0.1);

        // fix the nodes on Z=0
        std::vector<unsigned> fixed_nodes
          = NonlinearElasticityTools<3>::GetNodesByComponentValue(mechanics_mesh,2,0.0);

        HeartConfig::Instance()->SetSimulationDuration(50.0);

        ElectroMechanicsProblemDefinition<3> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(KERCHOFFS2003,1.0);
        problem_defn.SetUseDefaultCardiacMaterialLaw(INCOMPRESSIBLE);
        problem_defn.SetZeroDisplacementNodes(fixed_nodes);
        problem_defn.SetMechanicsSolveTimestep(1.0);
        FileFinder finder("heart/test/data/fibre_tests/5by5by5_fibres_by_quadpt.orthoquad",RelativeTo::ChasteSourceRoot);
        problem_defn.SetVariableFibreSheetDirectionsFile(finder, true);

        CardiacElectroMechanicsProblem<3,1> problem(INCOMPRESSIBLE,
                                                  MONODOMAIN,
                                                  &electrics_mesh,
                                                  &mechanics_mesh,
                                                  &cell_factory,
                                                  &problem_defn,
                                                  "TestCardiacElectroMech3dTwistingCube");



        problem.Solve();

        // verified that it twists by visualising, some hardcoded values here..
        {
            //Check that we are indexing the relevant corners of the cube
            c_vector<double, 3> undeformed_node1 = mechanics_mesh.GetNode(6*6*5)->rGetLocation();
            TS_ASSERT_DELTA(undeformed_node1(0),  0.0, 1e-6);
            TS_ASSERT_DELTA(undeformed_node1(1),  0.0, 1e-6);
            TS_ASSERT_DELTA(undeformed_node1(2),  0.1, 1e-6);
            c_vector<double, 3> undeformed_node2 = mechanics_mesh.GetNode(6*6*6-1)->rGetLocation();
            TS_ASSERT_DELTA(undeformed_node2(0), 0.1, 1e-6);
            TS_ASSERT_DELTA(undeformed_node2(1), 0.1, 1e-6);
            TS_ASSERT_DELTA(undeformed_node2(2), 0.1, 1e-6);
        }
        std::vector<c_vector<double,3> >& r_deformed_position = problem.rGetDeformedPosition();
        TS_ASSERT_DELTA(r_deformed_position[6*6*5](0),  0.0116, 1e-3);
        TS_ASSERT_DELTA(r_deformed_position[6*6*5](1), -0.0141, 1e-3);
        TS_ASSERT_DELTA(r_deformed_position[6*6*5](2),  0.1007, 1e-3);

        TS_ASSERT_DELTA(r_deformed_position[6*6*6-1](0), 0.0872, 1e-3);
        TS_ASSERT_DELTA(r_deformed_position[6*6*6-1](1), 0.1138, 1e-3);
        TS_ASSERT_DELTA(r_deformed_position[6*6*6-1](2), 0.1015, 1e-3);

        MechanicsEventHandler::Headings();
        MechanicsEventHandler::Report();

    }
    //
    //  BAD test - fails with HYPRE (for some reason HYPRE can't solve the one of the linear systems, and
    //  the search direction in the end doesn't decrease the residual), and also with ILU if you increase
    //  the number of elements (whether LR91 or N98 is used). Probably the active tension is too high.
    //
    //  Now removed
    //
    void removedTestExplicitSolverWithNash2004() throw(Exception)
    {
#ifdef MECH_USE_HYPRE
        TS_FAIL("This test is known to fail with HYPRE - see comments in test");
        return;
#endif

        PlaneStimulusCellFactory<CML_noble_varghese_kohl_noble_1998_basic_with_sac, 2> cell_factory(-1000*1000);

        HeartConfig::Instance()->SetSimulationDuration(20.0);

        CardiacElectroMechProbRegularGeom<2> problem(INCOMPRESSIBLE,
                                                     0.05, /* width (cm) */
                                                     1,    /* mech mesh size*/
                                                     5,    /* elec elem each dir */
                                                     &cell_factory,
                                                     NASH2004,
                                                     1.0,   /* mechanics solve timestep */
                                                     0.01,  /* nash ode timestep */
                                                     "TestExplicitWithNash");

        c_vector<double,2> pos;
        pos(0) = 0.05;
        pos(1) = 0.0;

        problem.SetWatchedPosition(pos);
        problem.SetNoElectricsOutput();
        problem.Initialise();

        problem.Solve();

        //visualise to verify

        // hardcoded result
        TS_ASSERT_EQUALS(problem.mWatchedMechanicsNodeIndex, 1u);
        TS_ASSERT_DELTA(problem.rGetDeformedPosition()[1](0), 0.0419, 0.0002);
    }
    // In this test we have no cardiac tissue, so that the equations are just sigma * phi_e''=0
    // throughout the domain (with a Neumann boundary condition on x=1 and a dirichlet boundary
    // condition (ie grounding) on x=0), so the exact solution can be calculated and compared
    // against.
    void Test1dProblemOnlyBathGroundedOneSide() throw (Exception)
    {
        HeartConfig::Instance()->SetSimulationDuration(0.5);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBathOnlyBath");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath");

        c_vector<double,1> centre;
        centre(0) = 0.5;
        BathCellFactory<1> cell_factory(-1e6, centre);

        TrianglesMeshReader<1,1> reader("mesh/test/data/1D_0_to_1_10_elements");
        TetrahedralMesh<1,1> mesh;
        mesh.ConstructFromMeshReader(reader);

        for(unsigned i=0; i<mesh.GetNumElements(); i++)
        {
            mesh.GetElement(i)->SetAttribute(HeartRegionCode::GetValidBathId());
        }

        // create boundary conditions container
        double boundary_val = 1.0;
        boost::shared_ptr<BoundaryConditionsContainer<1,1,2> > p_bcc(new BoundaryConditionsContainer<1,1,2>);
        ConstBoundaryCondition<1>* p_bc_stim = new ConstBoundaryCondition<1>(boundary_val);
        ConstBoundaryCondition<1>* p_zero_stim = new ConstBoundaryCondition<1>(0.0);

        // loop over boundary elements and set (sigma\gradphi).n = 1.0 on RHS edge
        for(TetrahedralMesh<1,1>::BoundaryElementIterator iter
              = mesh.GetBoundaryElementIteratorBegin();
           iter != mesh.GetBoundaryElementIteratorEnd();
           iter++)
        {
            if (((*iter)->GetNodeLocation(0))[0]==1.0)
            {
                /// \todo: I think you need to provide a boundary condition for unknown#1 if you are gonig to provide one for unknown#2?
                p_bcc->AddNeumannBoundaryCondition(*iter, p_zero_stim, 0);
                p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim,   1);
            }
        }

        BidomainWithBathProblem<1> bidomain_problem( &cell_factory );

        bidomain_problem.SetBoundaryConditionsContainer(p_bcc);
        bidomain_problem.SetMesh(&mesh);
        bidomain_problem.Initialise();

        // fix phi=0 on LHS edge
        std::vector<unsigned> fixed_nodes;
        fixed_nodes.push_back(0);
        bidomain_problem.SetFixedExtracellularPotentialNodes(fixed_nodes);

        bidomain_problem.Solve();

        Vec sol = bidomain_problem.GetSolution();
        ReplicatableVector sol_repl(sol);

        // test phi = x*boundary_val/sigma (solution of phi''=0, phi(0)=0, sigma*phi'(1)=boundary_val
        for(unsigned i=0; i<mesh.GetNumNodes(); i++)
        {
            double bath_cond = HeartConfig::Instance()->GetBathConductivity();
            double x = mesh.GetNode(i)->rGetLocation()[0];
            TS_ASSERT_DELTA(sol_repl[2*i],   0.0,   1e-12);               // V
            TS_ASSERT_DELTA(sol_repl[2*i+1], x*boundary_val/bath_cond, 1e-4);   // phi_e
        }
    }
    // These tests are older than the above tests..
    void TestImplicitNhs2dOneMechanicsElement() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-1000*1000);

        HeartConfig::Instance()->SetSimulationDuration(10.0);

        CardiacElectroMechProbRegularGeom<2> problem(INCOMPRESSIBLE,
                                                     0.05, /* width (cm) */
                                                     1,    /* mech mesh size*/
                                                     5,    /* elec elem each dir */
                                                     &cell_factory,
                                                     NHS,
                                                     1.0,  /* mechanics solve timestep */
                                                     0.01, /* contraction model ode timestep */
                                                     "TestCardiacElectroMechOneElement");
        c_vector<double,2> pos;
        pos(0) = 0.05;
        pos(1) = 0.0;

        problem.SetWatchedPosition(pos);



        TS_ASSERT_THROWS_CONTAINS(problem.SetOutputDeformationGradientsAndStress(3.4),"not a multiple");
        problem.SetOutputDeformationGradientsAndStress(3.0);

        problem.Solve();

        // test by checking the length of the tissue against hardcoded value
        std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition();
        TS_ASSERT_DELTA(r_deformed_position[1](0), 0.0497, 1e-4);

        OutputFileHandler handler("TestCardiacElectroMechOneElement",false);

        NumericFileComparison comparer(handler.GetOutputDirectoryFullPath() + "watched.txt","heart/test/data/good_watched.txt");
        TS_ASSERT(comparer.CompareFiles(1e-2));

        FileFinder electrics_dir = handler.FindFile("electrics");
        TS_ASSERT(electrics_dir.IsDir());


        // check electrics output was written
        TS_ASSERT(handler.FindFile("deformation/deformation_gradient_0.strain").Exists());
        TS_ASSERT(handler.FindFile("deformation/deformation_gradient_3.strain").Exists());
        TS_ASSERT(handler.FindFile("deformation/deformation_gradient_6.strain").Exists());
        TS_ASSERT(handler.FindFile("deformation/second_PK_0.stress").Exists());
        TS_ASSERT(handler.FindFile("deformation/second_PK_3.stress").Exists());
        TS_ASSERT(handler.FindFile("deformation/second_PK_6.stress").Exists());



        // coverage

        HeartConfig::Instance()->SetSimulationDuration(10.0); // has to be reset after a solve, it seems..

        // We can now #2370 put any model anywhere, so these checks don't make sense...
//        CardiacElectroMechProbRegularGeom<2> prob_with_bad_model(INCOMPRESSIBLE,0.05,1,5,&cell_factory,NONPHYSIOL1,1,0.01,"");
//        TS_ASSERT_THROWS_CONTAINS(prob_with_bad_model.Solve(),"Invalid contraction model");
//
//        CardiacElectroMechProbRegularGeom<2> prob_with_bad_model_comp(COMPRESSIBLE,0.05,1,5,&cell_factory,NONPHYSIOL1,1,0.01,"");
//        TS_ASSERT_THROWS_CONTAINS(prob_with_bad_model_comp.Solve(),"Invalid contraction model");

        CardiacElectroMechProbRegularGeom<2> prob_with_bad_timesteps(INCOMPRESSIBLE,0.05,1,5,&cell_factory,NHS,0.025,0.01,"");
        TS_ASSERT_THROWS_CONTAINS(prob_with_bad_timesteps.Initialise(),"does not divide");


        MechanicsEventHandler::Headings();
        MechanicsEventHandler::Report();
    }
示例#19
0
// see #1061
    void Test3dBathExtracellularStimulusOneEdgeGroundedOnOppositeEdge()
    {
        HeartConfig::Instance()->SetSimulationDuration(6);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath3dExtraStimGrounded");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_3d");

        HeartConfig::Instance()->SetOdeTimeStep(0.005);  //ms

        // need to create a cell factory but don't want any intra stim, so magnitude
        // of stim is zero.
        c_vector<double,3> centre;
        centre(0) = 0.1;
        centre(1) = 0.1;
        centre(2) = 0.1;
        BathCellFactory<3> cell_factory( 0.0, centre);

        BidomainProblem<3> bidomain_problem( &cell_factory, true );

        TrianglesMeshReader<3,3> reader("mesh/test/data/cube_2mm_1016_elements");
        TetrahedralMesh<3,3> mesh;
        mesh.ConstructFromMeshReader(reader);

        // Set everything outside a central sphere (radius 0.4) to be bath
        for (unsigned i=0; i<mesh.GetNumElements(); i++)
        {
            double x = mesh.GetElement(i)->CalculateCentroid()[0];
            double y = mesh.GetElement(i)->CalculateCentroid()[1];
            double z = mesh.GetElement(i)->CalculateCentroid()[2];
            if (sqrt((x-0.1)*(x-0.1) + (y-0.1)*(y-0.1) + (z-0.1)*(z-0.1)) > 0.03)
            {
                mesh.GetElement(i)->SetAttribute(1);
            }
        }

        bidomain_problem.SetMesh(&mesh);

        //boundary flux for Phi_e
        double boundary_flux = -4e3;
        double duration = 2.5; //ms

        HeartConfig::Instance()->SetElectrodeParameters(true,0,boundary_flux, 0.0, duration);
        bidomain_problem.Initialise();
        bidomain_problem.Solve();

        Vec sol = bidomain_problem.GetSolution();
        ReplicatableVector sol_repl(sol);

        bool ap_triggered = false;

        for (unsigned i=0; i<mesh.GetNumNodes(); i++)
        {
            // test V = 0 for all bath nodes
            if (HeartRegionCode::IsRegionBath( mesh.GetNode(i)->GetRegion() )) // bath
            {
                TS_ASSERT_DELTA(sol_repl[2*i], 0.0, 1e-12);
            }
            else if (sol_repl[2*i] > 0.0)
            {
                ap_triggered = true;
            }
        }
        TS_ASSERT(ap_triggered);
    }
示例#20
0
// see #1061
    void Test2dBathExtracellularStimulusOneEdgeGroundedOnOppositeEdge()
    {
        HeartConfig::Instance()->SetSimulationDuration(40);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath2dExtraStimGrounded");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_2d");

        HeartConfig::Instance()->SetOdeTimeStep(0.005);  //ms

        // need to create a cell factory but don't want any intra stim, so magnitude
        // of stim is zero.
        c_vector<double,2> centre;
        centre(0) = 0.05;
        centre(1) = 0.05;
        BathCellFactory<2> cell_factory( 0.0, centre);

        BidomainProblem<2> bidomain_problem( &cell_factory, true );

        TrianglesMeshReader<2,2> reader("mesh/test/data/2D_0_to_1mm_400_elements");
        TetrahedralMesh<2,2> mesh;
        mesh.ConstructFromMeshReader(reader);

        // Set everything outside a central circle (radius 0.4) to be bath
        for (unsigned i=0; i<mesh.GetNumElements(); i++)
        {
            double x = mesh.GetElement(i)->CalculateCentroid()[0];
            double y = mesh.GetElement(i)->CalculateCentroid()[1];
            if (sqrt((x-0.05)*(x-0.05) + (y-0.05)*(y-0.05)) > 0.02)
            {
                mesh.GetElement(i)->SetAttribute(HeartRegionCode::GetValidBathId());
            }
        }

        bidomain_problem.SetMesh(&mesh);

        //boundary flux for Phi_e
        //-4e3 is enough to trigger an action potential, -3e3 is below threshold, -5e3 crashes the cell model.
        double boundary_flux = -9e3;
        double duration = 2.5; //ms

        HeartConfig::Instance()->SetElectrodeParameters(true,0,boundary_flux, 0.0, duration);
        bidomain_problem.Initialise();
        bidomain_problem.Solve();

        Vec sol = bidomain_problem.GetSolution();
        ReplicatableVector sol_repl(sol);

        bool ap_triggered = false;
        /*
         * We are checking the last time step. This test will only make sure that an upstroke is triggered.
         * We ran longer simulation for 350 ms and a nice AP was observed.
         */
        for (unsigned i=0; i<mesh.GetNumNodes(); i++)
        {
            // test V = 0 for all bath nodes
            if (mesh.GetNode(i)->GetRegion()==1) // bath
            {
                TS_ASSERT_DELTA(sol_repl[2*i], 0.0, 1e-12);
            }
            else if (sol_repl[2*i] > 0.0)
            {
                ap_triggered = true;
            }
        }
        TS_ASSERT(ap_triggered);
    }
    void Test2dBathInputFluxEqualsOutputFlux() throw (Exception)
    {
        HeartConfig::Instance()->SetSimulationDuration(3.0);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath2dFluxCompare");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_2d_fluxes");

        // Coverage of Hdf5ToCmguiConverter with bath
        HeartConfig::Instance()->SetVisualizeWithCmgui(true);

        HeartConfig::Instance()->SetOdeTimeStep(0.001);  //ms

        // need to create a cell factory but don't want any intra stim, so magnitude
        // of stim is zero.
        c_vector<double,2> centre;
        centre(0) = 0.05; // cm
        centre(1) = 0.05; // cm
        BathCellFactory<2> cell_factory( 0.0, centre);

        BidomainWithBathProblem<2> bidomain_problem( &cell_factory );

        // Coverage
        TS_ASSERT(bidomain_problem.GetHasBath());

        TetrahedralMesh<2,2>* p_mesh = Load2dMeshAndSetCircularTissue<TetrahedralMesh<2,2> >(
            "mesh/test/data/2D_0_to_1mm_400_elements", 0.05, 0.05, 0.02);

        //boundary flux for Phi_e. -10e3 is under threshold, -14e3 crashes the cell model
        double boundary_flux = -11.0e3;
        double start_time = 0.5;
        double duration = 1.9; // of the stimulus, in ms

        HeartConfig::Instance()->SetElectrodeParameters(false,0, boundary_flux, start_time, duration);


        bidomain_problem.SetMesh(p_mesh);
        bidomain_problem.Initialise();

        bidomain_problem.Solve();

        Vec sol = bidomain_problem.GetSolution();
        ReplicatableVector sol_repl(sol);

        bool ap_triggered = false;
        /*
         * We are checking the last time step. This test will only make sure that an upstroke is triggered.
         * We ran longer simulation for 350 ms and a nice AP was observed.
         */

        for (unsigned i=0; i<p_mesh->GetNumNodes(); i++)
        {
            // test V = 0 for all bath nodes and that an AP is triggered in the tissue
            if (HeartRegionCode::IsRegionBath( p_mesh->GetNode(i)->GetRegion() )) // bath
            {
                TS_ASSERT_DELTA(sol_repl[2*i], 0.0, 1e-12);
            }
            else if (sol_repl[2*i] > 0.0)//at the last time step
            {
                ap_triggered = true;
            }
        }

        TS_ASSERT_EQUALS(bidomain_problem.mpElectrodes->mAreActive, false); // should be switched off by now..
        TS_ASSERT(ap_triggered);

        delete p_mesh;
    }
    void Test2dBathMultipleBathConductivities() throw (Exception)
    {
        HeartConfig::Instance()->SetSimulationDuration(2.0);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath2dMultipleBathConductivities");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_2d");

        HeartConfig::Instance()->SetOdeTimeStep(0.001);  //ms ???

        std::set<unsigned> tissue_ids;
        tissue_ids.insert(0); // Same as default value defined in HeartConfig

        std::set<unsigned> bath_ids;
        bath_ids.insert(2);
        bath_ids.insert(3);
        bath_ids.insert(4);
        HeartConfig::Instance()->SetTissueAndBathIdentifiers(tissue_ids, bath_ids);

        // need to create a cell factory but don't want any intra stim, so magnitude
        // of stim is zero.
        c_vector<double,2> centre;
        centre(0) = 0.05; // cm
        centre(1) = 0.05; // cm
        BathCellFactory<2> cell_factory( 0.0, centre);

        BidomainWithBathProblem<2> bidomain_problem( &cell_factory );

        DistributedTetrahedralMesh<2,2> mesh;

        mesh.ConstructRegularSlabMesh(0.05, 0.9, 0.9);

        // set the x<0.25 and x>0.75 regions as the bath region
        for (AbstractTetrahedralMesh<2,2>::ElementIterator iter = mesh.GetElementIteratorBegin();
             iter != mesh.GetElementIteratorEnd();
             ++iter)
        {
            double x = iter->CalculateCentroid()[0];
            double y = iter->CalculateCentroid()[1];
            if( (x>0.3) && (x<0.6) && (y>0.3) && (y<0.6) )
            {
                iter->SetAttribute(0);
            }
            else
            {
                if (y<0.2)
                {
                    iter->SetAttribute(2);
                }
                else if (y<0.7)
                {
                    iter->SetAttribute(3);
                }
                else if (y<0.9)
                {
                    iter->SetAttribute(4);
                }
            }
        }

        std::map<unsigned, double> multiple_bath_conductivities;
        multiple_bath_conductivities[2] = 7.0;
        multiple_bath_conductivities[3] = 1.0;
        multiple_bath_conductivities[4] = 0.001;

        HeartConfig::Instance()->SetBathMultipleConductivities(multiple_bath_conductivities);

        double boundary_flux = -3.0e3;
        double start_time = 0.0;
        double duration = 1.0; // of the stimulus, in ms

        HeartConfig::Instance()->SetElectrodeParameters(false, 0, boundary_flux, start_time, duration);

        bidomain_problem.SetMesh(&mesh);
        bidomain_problem.Initialise();

        bidomain_problem.Solve();

        DistributedVector distributed_solution = bidomain_problem.GetSolutionDistributedVector();
        DistributedVector::Stripe voltage(distributed_solution, 0);

        /*
         * We are checking the last time step. This test will only make sure that an AP is triggered.
         */
        bool ap_triggered = false;

        for (DistributedVector::Iterator index = distributed_solution.Begin();
             index!= distributed_solution.End();
             ++index)
        {
            // test V = 0 for all bath nodes and that an AP is triggered in the tissue
            if (HeartRegionCode::IsRegionBath( mesh.GetNode(index.Global)->GetRegion() )) // bath
            {
                TS_ASSERT_DELTA(voltage[index], 0.0, 1e-12);
            }
            else if (voltage[index] > 0.0)//at the last time step
            {
                ap_triggered = true;
            }
        }

        TS_ASSERT(PetscTools::ReplicateBool(ap_triggered));
    }
    // runs 5 different 3d tests with fibres read to be in various directions, and
    // checks contraction occurs in the right directions (and bulging occurs in the
    // other directions)
    void TestFibreRead() throw(Exception)
    {
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML,3> cell_factory(-5000*1000);

        double tissue_initial_size = 0.05;
        TetrahedralMesh<3,3> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(0.01/*stepsize*/, tissue_initial_size/*length*/, tissue_initial_size/*width*/, tissue_initial_size);

        QuadraticMesh<3> mechanics_mesh;
        mechanics_mesh.ConstructRegularSlabMesh(0.05, tissue_initial_size, tissue_initial_size, tissue_initial_size /*as above with a different stepsize*/);

        std::vector<unsigned> fixed_nodes
            = NonlinearElasticityTools<3>::GetNodesByComponentValue(mechanics_mesh, 2, 0.0);


        HeartConfig::Instance()->SetSimulationDuration(10.0);

        ElectroMechanicsProblemDefinition<3> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(KERCHOFFS2003,1.0);
        problem_defn.SetZeroDisplacementNodes(fixed_nodes);
        problem_defn.SetMechanicsSolveTimestep(1.0);
        problem_defn.SetUseDefaultCardiacMaterialLaw(COMPRESSIBLE);

        // This is how the fibres files that are used in the simulations are created.
        // alongX.ortho is:  fibres in X axis, sheet in XY
        //    -- same as default directions: should give shortening in X direction
        //       and identical results to default fibre setting
        // alongY1.ortho is: fibres in Y axis, sheet in YX
        // alongY2.ortho is: fibres in Y axis, sheet in YZ
        //    -- as material law is transversely isotropic, these two should
        //       give identical results, shortening in Y-direction
        // alongZ.ortho is:  fibres in Z axis, (sheet in XZ)
        //    -- should shorten in Z-direction
        OutputFileHandler handler("FibreFiles");
        out_stream p_X_file  = handler.OpenOutputFile("alongX.ortho");
        out_stream p_Y1_file = handler.OpenOutputFile("alongY1.ortho");
        out_stream p_Y2_file = handler.OpenOutputFile("alongY2.ortho");
        out_stream p_Z_file  = handler.OpenOutputFile("alongZ.ortho");
        *p_X_file  << mechanics_mesh.GetNumElements() << "\n";
        *p_Y1_file << mechanics_mesh.GetNumElements() << "\n";
        *p_Y2_file << mechanics_mesh.GetNumElements() << "\n";
        *p_Z_file  << mechanics_mesh.GetNumElements() << "\n";
        for(unsigned i=0; i<mechanics_mesh.GetNumElements(); i++)
        {
            //double X = mechanics_mesh.GetElement(i)->CalculateCentroid()(0);
            *p_X_file  << "1 0 0 0 1 0 0 0 1\n";
            *p_Y1_file << "0 1 0 1 0 0 0 0 1\n";
            *p_Y2_file << "0 1 0 0 0 1 1 0 0\n";
            *p_Z_file  << "0 0 1 1 0 0 0 1 0\n";
        }
        p_X_file->close();
        p_Y1_file->close();
        p_Y2_file->close();
        p_Z_file->close();


        //////////////////////////////////////////////////////////////////
        // Solve with no fibres read.
        //////////////////////////////////////////////////////////////////
        std::vector<c_vector<double,3> > r_deformed_position_no_fibres;
        {
            HeartConfig::Instance()->SetSimulationDuration(20.0);

            CardiacElectroMechanicsProblem<3,1> problem(COMPRESSIBLE,
                                                      MONODOMAIN,
                                                      &electrics_mesh,
                                                      &mechanics_mesh,
                                                      &cell_factory,
                                                      &problem_defn,
                                                      "TestCardiacEmFibreRead");


            problem.Solve();
            r_deformed_position_no_fibres = problem.rGetDeformedPosition();
        }

        //////////////////////////////////////////////////////////////////
        // Solve with fibres read: fibres in X-direction
        //////////////////////////////////////////////////////////////////
        std::vector<c_vector<double,3> > r_deformed_position_fibres_alongX;
        {
            HeartConfig::Instance()->SetSimulationDuration(20.0);
            FileFinder finder("heart/test/data/fibre_tests/alongX.ortho", RelativeTo::ChasteSourceRoot);
            problem_defn.SetVariableFibreSheetDirectionsFile(finder, false);

            CardiacElectroMechanicsProblem<3,1> problem(COMPRESSIBLE,
                                                      MONODOMAIN,
                                                      &electrics_mesh,
                                                      &mechanics_mesh,
                                                      &cell_factory,
                                                      &problem_defn,
                                                      "TestCardiacEmFibreRead");


            problem.Solve();
            r_deformed_position_fibres_alongX = problem.rGetDeformedPosition();
        }

        // test the two results are identical
        for(unsigned i=0; i<r_deformed_position_no_fibres.size(); i++)
        {
            for(unsigned j=0; j<3; j++)
            {
                TS_ASSERT_DELTA(r_deformed_position_no_fibres[i](j), r_deformed_position_fibres_alongX[i](j), 1e-8);
            }
        }

        // check node 7 starts is the far corner
        assert(fabs(mechanics_mesh.GetNode(7)->rGetLocation()[0] - tissue_initial_size)<1e-8);
        assert(fabs(mechanics_mesh.GetNode(7)->rGetLocation()[1] - tissue_initial_size)<1e-8);
        assert(fabs(mechanics_mesh.GetNode(7)->rGetLocation()[2] - tissue_initial_size)<1e-8);

        // Test that contraction occurred in the X-direction
        TS_ASSERT_LESS_THAN(r_deformed_position_fibres_alongX[7](0), tissue_initial_size);
        TS_ASSERT_LESS_THAN(tissue_initial_size, r_deformed_position_fibres_alongX[7](1));
        TS_ASSERT_LESS_THAN(tissue_initial_size, r_deformed_position_fibres_alongX[7](2));

        // hardcoded test to check nothing changes
        TS_ASSERT_DELTA(r_deformed_position_fibres_alongX[7](0), 0.0487, 1e-4);
        TS_ASSERT_DELTA(r_deformed_position_fibres_alongX[7](1), 0.0506, 1e-4);

        ////////////////////////////////////////////////////////////////////
        // Solve with fibres read: fibres in Y-direction, sheet in YX plane
        ////////////////////////////////////////////////////////////////////
        std::vector<c_vector<double,3> > r_deformed_position_fibres_alongY1;
        {
            HeartConfig::Instance()->SetSimulationDuration(20.0);
            FileFinder finder("heart/test/data/fibre_tests/alongY1.ortho", RelativeTo::ChasteSourceRoot);
            problem_defn.SetVariableFibreSheetDirectionsFile(finder, false);

            CardiacElectroMechanicsProblem<3,1> problem(COMPRESSIBLE,
                                                      MONODOMAIN,
                                                      &electrics_mesh,
                                                      &mechanics_mesh,
                                                      &cell_factory,
                                                      &problem_defn,
                                                      "TestCardiacEmFibreRead");


            problem.Solve();
            r_deformed_position_fibres_alongY1 = problem.rGetDeformedPosition();
        }


        ////////////////////////////////////////////////////////////////////
        // Solve with fibres read: fibres in Y-direction, sheet in YZ plane
        ////////////////////////////////////////////////////////////////////
        std::vector<c_vector<double,3> > r_deformed_position_fibres_alongY2;
        {
            HeartConfig::Instance()->SetSimulationDuration(20.0);
            FileFinder fibres_file("heart/test/data/fibre_tests/alongY2.ortho", RelativeTo::ChasteSourceRoot);
            problem_defn.SetVariableFibreSheetDirectionsFile(fibres_file, false);

            CardiacElectroMechanicsProblem<3,1> problem(COMPRESSIBLE,
                                                        MONODOMAIN,
                                                        &electrics_mesh,
                                                        &mechanics_mesh,
                                                        &cell_factory,
                                                        &problem_defn,
                                                        "TestCardiacEmFibreRead");

            problem.Solve();
            r_deformed_position_fibres_alongY2 = problem.rGetDeformedPosition();
        }


        // test the two results are identical
        for(unsigned i=0; i<r_deformed_position_no_fibres.size(); i++)
        {
            for(unsigned j=0; j<3; j++)
            {
                TS_ASSERT_DELTA(r_deformed_position_fibres_alongY1[i](j), r_deformed_position_fibres_alongY2[i](j), 1e-8);
            }
        }

        // Test that contraction occurred in the Y-direction
        TS_ASSERT_LESS_THAN(tissue_initial_size, r_deformed_position_fibres_alongY1[7](0));
        TS_ASSERT_LESS_THAN(r_deformed_position_fibres_alongY1[7](1), tissue_initial_size);
        TS_ASSERT_LESS_THAN(tissue_initial_size, r_deformed_position_fibres_alongY1[7](2));

        // hardcoded test to check nothing changes
        TS_ASSERT_DELTA(r_deformed_position_fibres_alongY1[7](1), 0.0487, 1e-4);
        TS_ASSERT_DELTA(r_deformed_position_fibres_alongY1[7](0), 0.0506, 1e-4);


        //////////////////////////////////////////////////////////////////
        // Solve with fibres read: fibres in Z-direction
        //////////////////////////////////////////////////////////////////
        std::vector<c_vector<double,3> > r_deformed_position_fibres_alongZ;
        {
            HeartConfig::Instance()->SetSimulationDuration(20.0);
            FileFinder finder("heart/test/data/fibre_tests/alongZ.ortho", RelativeTo::ChasteSourceRoot);
            problem_defn.SetVariableFibreSheetDirectionsFile(finder, false);

            CardiacElectroMechanicsProblem<3,1> problem(COMPRESSIBLE,
                                                      MONODOMAIN,
                                                      &electrics_mesh,
                                                      &mechanics_mesh,
                                                      &cell_factory,
                                                      &problem_defn,
                                                      "TestCardiacEmFibreRead");


            problem.Solve();
            r_deformed_position_fibres_alongZ = problem.rGetDeformedPosition();
        }

        // Test that contraction occurred in the X-direction
        TS_ASSERT_LESS_THAN(tissue_initial_size, r_deformed_position_fibres_alongZ[7](0));
        TS_ASSERT_LESS_THAN(tissue_initial_size, r_deformed_position_fibres_alongZ[7](1));
        TS_ASSERT_LESS_THAN(r_deformed_position_fibres_alongZ[7](2), tissue_initial_size);

        // hardcoded test to check nothing changes
        TS_ASSERT_DELTA(r_deformed_position_fibres_alongZ[7](2), 0.0466, 1e-4);
        TS_ASSERT_DELTA(r_deformed_position_fibres_alongZ[7](0), 0.0504, 1e-4);
    }
    void Test2dBathGroundedElectrodeStimulusSwitchesOnOff() throw (Exception)
    {
        // Total execution time is 5 ms. Electrodes are on in [1.0, 3.0]
        HeartConfig::Instance()->SetOutputDirectory("BidomainBath2dGroundedOnOff");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain_bath_2d_grounded_on_off");
        HeartConfig::Instance()->SetOdeTimeStep(0.001);  //ms

        // need to create a cell factory but don't want any intra stim, so magnitude
        // of stim is zero.
        c_vector<double,2> centre;
        centre(0) = 0.05; // cm
        centre(1) = 0.05; // cm
        BathCellFactory<2> cell_factory( 0.0, centre);

        BidomainWithBathProblem<2> bidomain_problem( &cell_factory );

        TetrahedralMesh<2,2>* p_mesh = Load2dMeshAndSetCircularTissue<TetrahedralMesh<2,2> >(
            "mesh/test/data/2D_0_to_1mm_400_elements", 0.05, 0.05, 0.02);

        //boundary flux for Phi_e. -10e3 is under threshold, -14e3 crashes the cell model
        double boundary_flux = -11.0e3;
        double start_time = 1.0;
        double duration = 2.0; // of the stimulus, in ms

        HeartConfig::Instance()->SetElectrodeParameters( true, 0, boundary_flux,start_time, duration );


        bidomain_problem.SetMesh(p_mesh);
        bidomain_problem.Initialise();

        /*
         *  While t in [0.0, 1.0) electrodes are off
         */
        {
            HeartConfig::Instance()->SetSimulationDuration(0.5);  //ms
            bidomain_problem.Solve();

            /// \todo: we don't need a ReplicatableVector here. Every processor can check locally
            Vec sol = bidomain_problem.GetSolution();
            ReplicatableVector sol_repl(sol);

            for (unsigned i=0; i<p_mesh->GetNumNodes(); i++)
            {
                // test phi_e close to 0 for all bath nodes since electrodes are off
                if (HeartRegionCode::IsRegionBath( p_mesh->GetNode(i)->GetRegion() )) // bath
                {
                    TS_ASSERT_DELTA(sol_repl[2*i+1], 0.0, 0.5);
                }
            }

            TS_ASSERT_EQUALS(bidomain_problem.mpElectrodes->mAreActive, false); // should be switched off by now..
        }


        /*
         *  At the end of the simulation AP has been triggered
         */
        {
            HeartConfig::Instance()->SetSimulationDuration(5.0);  //ms
            bidomain_problem.Solve();

            Vec sol = bidomain_problem.GetSolution();
            ReplicatableVector sol_repl(sol);

            bool ap_triggered = false;
            /*
             * We are checking the last time step. This test will only make sure that an upstroke is triggered.
             * We ran longer simulation for 350 ms and a nice AP was observed.
             */

            for (unsigned i=0; i<p_mesh->GetNumNodes(); i++)
            {
                // test V = 0 for all bath nodes and that an AP is triggered in the tissue
                if (HeartRegionCode::IsRegionBath( p_mesh->GetNode(i)->GetRegion() )) // bath
                {
                    TS_ASSERT_DELTA(sol_repl[2*i], 0.0, 1e-12);
                }
                else if (sol_repl[2*i] > 0.0)//at the last time step
                {
                    ap_triggered = true;
                }
            }

            // Check that grounded electrode has been successfully removed and therefore phi_e !=0.
            // Nodes defining grounded electrode are 10, 21, 32, 43, 54, ... , 120
            TS_ASSERT_DELTA(sol_repl[21], -80.2794, 1e-3);
            TS_ASSERT_DELTA(sol_repl[43], -80.2794, 1e-3);
            TS_ASSERT_DELTA(sol_repl[241], -80.2794, 1e-3);

            TS_ASSERT_EQUALS(bidomain_problem.mpElectrodes->mAreActive, false); // should be switched off by now..
            TS_ASSERT(ap_triggered);
        }

        delete p_mesh;
    }
    void TestWithBathAndElectrodes()
    {
        /* First, set the end time and output info. In this simulation
         * we'll explicitly read the mesh, alter it, then pass it
         * to the problem class, so we don't set the mesh file name.
         */
        HeartConfig::Instance()->SetSimulationDuration(3.0);  //ms
        HeartConfig::Instance()->SetOutputDirectory("BidomainTutorialWithBath");
        HeartConfig::Instance()->SetOutputFilenamePrefix("results");

        /* Bath problems seem to require decreased ODE timesteps.
         */
        HeartConfig::Instance()->SetOdeTimeStep(0.001);  //ms

        /* Use the {{{PlaneStimulusCellFactory}}} to define a set
         * of Luo-Rudy cells. We pass the stimulus magnitude as 0.0
         * as we don't want any stimulated cells.
         */
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellMLBackwardEuler,2> cell_factory(0.0);

        /*
         * Now, we load up a rectangular mesh (in triangle/tetgen format), done as follows,
         * using {{{TrianglesMeshReader}}}.  Note that we use a distributed mesh, so the data
         * is shared among processes if run in parallel.
         */
        TrianglesMeshReader<2,2> reader("mesh/test/data/2D_0_to_1mm_400_elements");
        DistributedTetrahedralMesh<2,2> mesh;
        mesh.ConstructFromMeshReader(reader);

        /*
         * In most simulations there is one valid tissue identifier and one valid bath identifier
         * (for elements).
         * One of these can be assigned to an element with
         *  * {{{mesh.GetElement(i)->SetAttribute(HeartRegionCode::GetValidTissueId());}}}
         *  * {{{mesh.GetElement(i)->SetAttribute(HeartRegionCode::GetValidBathId());}}}
         *
         * If we want heterogeneous conductivities outside the heart (for example for torso and blood)
         * then we will need different identifiers:
         */
        std::set<unsigned> tissue_ids;
        static unsigned tissue_id=0;
        tissue_ids.insert(tissue_id);

        std::set<unsigned> bath_ids;
        static unsigned bath_id1=1;
        bath_ids.insert(bath_id1);
        static unsigned bath_id2=2;
        bath_ids.insert(bath_id2);

        HeartConfig::Instance()->SetTissueAndBathIdentifiers(tissue_ids, bath_ids);

        /* In bath problems, each element has an attribute which must be set
         * to 0 (cardiac tissue) or 1 (bath). This can be done by having an
         * extra column in the element file (see the file formats documentation,
         * or for example
         * mesh/test/data/1D_0_to_1_10_elements_with_two_attributes.ele,
         * and note that the header in this file has 1 at the end to indicate that
         * the file defines an attribute for each element). We have read in a mesh
         * without this type of information set up, so we set it up manually,
         * by looping over elements and setting those more than 2mm from the centre
         * as bath elements (by default, the others are cardiac elements).
         */
        for (AbstractTetrahedralMesh<2,2>::ElementIterator iter = mesh.GetElementIteratorBegin();
             iter != mesh.GetElementIteratorEnd();
             ++iter)
        {
            double x = iter->CalculateCentroid()[0];
            double y = iter->CalculateCentroid()[1];
            if (sqrt((x-0.05)*(x-0.05) + (y-0.05)*(y-0.05)) > 0.02)
            {
                if (y<0.05)
                {
                    //Outside circle on the bottom
                    iter->SetAttribute(bath_id1);
                }
                else
                {
                    //Outside circle on the top
                    iter->SetAttribute(bath_id2);
                }
            }
            else
            {
                //IDs default to 0, but we want to be safe
                iter->SetAttribute(tissue_id);
            }
        }

        /* HOW_TO_TAG Cardiac/Problem definition
         * Tell Chaste that a mesh has been modified
         *
         * Since we have modified the mesh by setting element attributes, we need to inform Chaste of this fact.
         * If we do not, problems will arise when [wiki:UserTutorials/CardiacCheckpointingAndRestarting checkpointing],
         * since the code that saves the simulation state will assume that it can just reuse the original mesh files,
         * and thus won't save the new element attributes.
         *
         * (Some mesh modifications, that use methods on the mesh class directly, will automatically record that
         * the mesh has been modified.  Since we're just modifying elements, this information isn't propagated at
         * present.)
         */
        mesh.SetMeshHasChangedSinceLoading();

        /*
         * The external conductivity can set two ways:
         *  * the default conductivity in the bath is set with {{{SetBathConductivity(double)}}}
         *  * heterogeneous overides can be set with {{{SetBathMultipleConductivities(std::map<unsigned, double> )}}}
         */

        HeartConfig::Instance()->SetBathConductivity(7.0);  //bath_id1 tags will take the default value (actually 7.0 is the default)
        std::map<unsigned, double> multiple_bath_conductivities;
        multiple_bath_conductivities[bath_id2] = 6.5;  // mS/cm

        HeartConfig::Instance()->SetBathMultipleConductivities(multiple_bath_conductivities);


        /* Now we define the electrodes. First define the magnitude of the electrodes
         * (ie the magnitude of the boundary extracellular stimulus), and the duration
         * it lasts for. Currently, electrodes switch on at time 0 and have constant magnitude
         * until they are switched off. (Note that this test has a small range of
         * magnitudes that will work, perhaps because the electrodes are close to the tissue).
         */
        // For default conductivities and explicit cell model -1e4 is under threshold, -1.4e4 too high - crashes the cell model
        // For heterogeneous conductivities as given, -1e4 is under threshold
        double magnitude = -14.0e3; // uA/cm^2
        double start_time = 0.0;
        double duration = 1; //ms

        /* Electrodes work in two ways: the first electrode applies an input flux, and
         * the opposite electrode can either be grounded or apply an equal and opposite
         * flux (ie an output flux). The `false` here indicates the second electrode
         * is not grounded, ie has an equal and opposite flux. The "0" indicates
         * that the electrodes should be applied to the bounding surfaces in the x-direction
         * (1 would be y-direction, 2 z-direction), which are X=0.0 and X=0.1 in the given mesh.
         * (This explains why the full mesh ought to be rectangular/cuboid - the nodes on
         * x=xmin and x=xmax ought to be form two surfaces of equal area.
         */
        HeartConfig::Instance()->SetElectrodeParameters(false, 0, magnitude, start_time, duration);

        /* Now create the problem class, using the cell factory and passing
         * in `true` as the second argument to indicate we are solving a bath
         * problem..
         */
        BidomainProblem<2> bidomain_problem( &cell_factory, true );

        /* ..set the mesh and electrodes.. */
        bidomain_problem.SetMesh(&mesh);

        /* ..and solve as before. */
        bidomain_problem.Initialise();
        bidomain_problem.Solve();

        /* The results can be visualised as before. '''Note:''' The voltage is only
         * defined at cardiac nodes (a node contained in ''any'' cardiac element), but
         * for visualisation and computation a 'fake' value of ZERO is given for the
         * voltage at bath nodes.
         *
         * Finally, we can check that an AP was induced in any of the cardiac
         * cells. We use a `ReplicatableVector` as before, and make sure we
         * only check the voltage at cardiac cells.
         */
        Vec solution = bidomain_problem.GetSolution(); // the Vs and phi_e's, as a PetSc vector
        ReplicatableVector solution_repl(solution);

        bool ap_triggered = false;
        for (AbstractTetrahedralMesh<2,2>::NodeIterator iter = mesh.GetNodeIteratorBegin();
             iter != mesh.GetNodeIteratorEnd();
             ++iter)
        {
            if (HeartRegionCode::IsRegionTissue( iter->GetRegion() ))
            {
                if (solution_repl[2*iter->GetIndex()] > 0.0) // 2*i, ie the voltage for this node (would be 2*i+1 for phi_e for this node)
                {
                    ap_triggered = true;
                }
            }
        }
        TS_ASSERT(ap_triggered);
    }
    void Test2DSimulations() throw(Exception)
    {
        double conductivity_scale = 1;
        double h = 0.01; // cm
        double ode_time_step = 0.005; //ms
        double pde_time_step = 0.01; //ms
        unsigned num_stims = 1;

        TetrahedralMesh<2,2> mesh;
        unsigned num_elem_x = (unsigned)(0.5/h);  // num elements to make 5mm
        unsigned num_elem_y = (unsigned)(0.5/h);  // num elements to make 5mm
        //unsigned num_elem_z = (unsigned)(0.15/h);// Num elements to make 0.3cm
        double pacing_cycle_length = 350;
        double stim_mag = -500000;
        double stim_dur = 3;
        double area = 0.005;

        mesh.ConstructRectangularMesh(num_elem_x, num_elem_y);
        mesh.Scale(h,h); // Get mesh into units of cm.

        std::string archive_dir_base("LongPostprocessing_archives/archive");
        std::string archive_dir_current;

        // Setup
        HeartConfig::Instance()->SetSimulationDuration(pacing_cycle_length); //ms
        HeartConfig::Instance()->SetOutputDirectory("LongPostprocessing");
        HeartConfig::Instance()->SetOutputFilenamePrefix("results");

        // These lines make postprocessing fast or slow.
        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(ode_time_step, pde_time_step, 10); // Leads to 10MB VTK file
        //HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(ode_time_step, pde_time_step, 0.01); // Leads to 1GB VTK file

        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.4*conductivity_scale*1.171, 1.4*conductivity_scale*1.171));
        HeartConfig::Instance()->SetSurfaceAreaToVolumeRatio(1400.0); // 1/cm
        HeartConfig::Instance()->SetCapacitance(1.0); // uF/cm^2
        HeartConfig::Instance()->SetVisualizeWithMeshalyzer();
#ifdef CHASTE_VTK
        HeartConfig::Instance()->SetVisualizeWithVtk();
#endif

        std::vector<std::pair<double,double> > apds_requested;
        apds_requested.push_back(std::pair<double, double>(90,-30)); //repolarisation percentage and threshold
        HeartConfig::Instance()->SetApdMaps(apds_requested);
//        std::vector<double> excitation_threshold;
//        excitation_threshold.push_back(-30.0);
//        HeartConfig::Instance()->SetUpstrokeTimeMaps(excitation_threshold);
//        HeartConfig::Instance()->SetMaxUpstrokeVelocityMaps(excitation_threshold);

        for (unsigned stim_counter=0; stim_counter < num_stims; stim_counter++ )
        {
            // Load problem
            MonodomainProblem<2> *p_monodomain_problem;
            if (stim_counter==0)
            {
                PointStimulusCellFactory<2> cell_factory(stim_mag, stim_dur, pacing_cycle_length, area);
                p_monodomain_problem = new MonodomainProblem<2>( &cell_factory );
                p_monodomain_problem->SetMesh(&mesh);
                p_monodomain_problem->Initialise();
            }
            else
            {
                p_monodomain_problem = CardiacSimulationArchiver<MonodomainProblem<2> >::Load(archive_dir_current);
            }

            HeartConfig::Instance()->SetSimulationDuration((double) (stim_counter+1)*pacing_cycle_length); //ms

            // set new directories to work from
            std::stringstream stringoutput;
            stringoutput << stim_counter;
            std::string stim_counter_string = stringoutput.str();

            archive_dir_current = archive_dir_base + "_" + stim_counter_string;
            OutputFileHandler archive_directory(archive_dir_current, true); // Clean a folder for new results
            HeartConfig::Instance()->SetOutputFilenamePrefix("results_" + stim_counter_string);

            // Solve problem (this does the postprocessing too when HeartConfig options are set).
            p_monodomain_problem->Solve();

            HeartEventHandler::Headings();
            HeartEventHandler::Report();

            // Save problem to archive
            CardiacSimulationArchiver<MonodomainProblem<2> >::Save(*p_monodomain_problem, archive_dir_current, false);
            std::cout << "Archived to " << archive_dir_current << "\n" << std::flush;

            // Copy the postprocessing results into the archive folders so they aren't wiped.
            std::vector<std::string> files;
            files.push_back("Apd_90_minus_30_Map");
//                files.push_back("MaxUpstrokeVelocityMap_-30");
//                files.push_back("UpstrokeTimeMap_-30");

            for (unsigned i=0; i<files.size(); i++)
            {
                FileFinder file_to_copy(HeartConfig::Instance()->GetOutputDirectory() + "/output/" + files[i] + ".dat", RelativeTo::ChasteTestOutput);
                TS_ASSERT(file_to_copy.IsFile());
                archive_directory.CopyFileTo(file_to_copy);
            }
        }// close for loop
    }//close void Test2dSimulations
    void TestMatrixBasedAssembledBath(void)
    {
        HeartConfig::Instance()->SetSimulationDuration(1.0);  //ms

        // need to create a cell factory but don't want any intra stim, so magnitude
        // of stim is zero.
        c_vector<double,2> centre;
        centre(0) = 0.05;
        centre(1) = 0.05;
        BathCellFactory<2> cell_factory( 0.0, centre);

        //boundary flux for Phi_e
        double boundary_flux = -4e2;
        double duration = 0.2; //ms

        DistributedTetrahedralMesh<2,2>* p_mesh = Load2dMeshAndSetCircularTissue<DistributedTetrahedralMesh<2,2> >(
            "mesh/test/data/2D_0_to_1mm_400_elements", 0.05, 0.05, 0.02);

        ///////////////////////////////////////////////////////////////////
        // matrix based
        ///////////////////////////////////////////////////////////////////
        HeartConfig::Instance()->SetOutputDirectory("BidomainBathMatrixBased");
        HeartConfig::Instance()->SetOutputFilenamePrefix("matrix_based");

        BidomainWithBathProblem<2> matrix_based_bido( &cell_factory );

        HeartConfig::Instance()->SetElectrodeParameters(true,0,boundary_flux, 0.0, duration);

        {
            Timer::Reset();

            matrix_based_bido.SetMesh(p_mesh);
            matrix_based_bido.Initialise();
            matrix_based_bido.Solve();

            Timer::Print("2D Matrix based");
        }

        ///////////////////////////////////////////////////////////////////
        // non matrix based
        ///////////////////////////////////////////////////////////////////
        HeartConfig::Instance()->SetOutputDirectory("BidomainBathNonMatrixBased");
        HeartConfig::Instance()->SetOutputFilenamePrefix("non_matrix_based");

        BidomainWithBathProblem<2> non_matrix_based_bido( &cell_factory);

        {
            Timer::Reset();

            non_matrix_based_bido.SetMesh(p_mesh);
            non_matrix_based_bido.Initialise();
            non_matrix_based_bido.Solve();

            Timer::Print("2D non matrix based");
        }

        ///////////////////////////////////////////////////////////////////
        // compare
        ///////////////////////////////////////////////////////////////////
        DistributedVector matrix_based_solution = matrix_based_bido.GetSolutionDistributedVector();
        DistributedVector non_matrix_based_solution = non_matrix_based_bido.GetSolutionDistributedVector();

        DistributedVector::Stripe matrix_based_voltage(matrix_based_solution, 0);
        DistributedVector::Stripe non_matrix_based_voltage(non_matrix_based_solution, 0);

        DistributedVector::Stripe matrix_based_ex_pot(matrix_based_solution, 1);
        DistributedVector::Stripe non_matrix_based_ex_pot(non_matrix_based_solution, 1);

        for (DistributedVector::Iterator index = matrix_based_solution.Begin();
             index != matrix_based_solution.End();
             ++index)
        {
            TS_ASSERT_DELTA(matrix_based_voltage[index], non_matrix_based_voltage[index], 1e-7);
            //TS_ASSERT_DELTA(matrix_based_ex_pot[index], non_matrix_based_ex_pot[index], 1e-7);
            //std::cout << matrix_based_voltage[index] << std::endl;
        }

        delete p_mesh;
    }
    void Test1dApd() throw(Exception)
    {
        HeartConfig::Instance()->SetPrintingTimeStep(1.0);
        HeartConfig::Instance()->SetSimulationDuration(400); //ms

        DistributedTetrahedralMesh<1,1> mesh;
        mesh.ConstructRegularSlabMesh(0.01, 1.0); // h=0.01cm, width=1cm

        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 1> cell_factory(-600.0*1000);

        //////////////////////////////////////////////////////////////////////////
        // run original simulation - no adaptivity, dt=0.01 all the way through
        //////////////////////////////////////////////////////////////////////////
        HeartConfig::Instance()->SetOutputDirectory("MonoWithTimeAdaptivity1dLong/OrigNoAdapt");
        MonodomainProblem<1> problem(&cell_factory);
        problem.SetMesh(&mesh);

        problem.Initialise();
        problem.Solve();

        HeartEventHandler::Headings();
        HeartEventHandler::Report();

        //////////////////////////////////////////////////////////////////////////
        // run adaptive simulation - dt=0.01 for first 2ms, then dt=1
        //////////////////////////////////////////////////////////////////////////
        HeartConfig::Instance()->SetOutputDirectory("MonoWithTimeAdaptivity1dLong/SimpleAdapt");
        MonodomainProblem<1> adaptive_problem(&cell_factory);
        adaptive_problem.SetMesh(&mesh);

        FixedTimeAdaptivityController controller(25);
        adaptive_problem.SetUseTimeAdaptivityController(true, &controller);
        adaptive_problem.Initialise();
        adaptive_problem.Solve();

        HeartEventHandler::Headings();
        HeartEventHandler::Report();

        Hdf5DataReader reader_no_adapt("MonoWithTimeAdaptivity1dLong/OrigNoAdapt","SimulationResults");
        Hdf5DataReader reader_adapt("MonoWithTimeAdaptivity1dLong/SimpleAdapt","SimulationResults");

        unsigned num_timesteps = reader_no_adapt.GetUnlimitedDimensionValues().size();
        assert(num_timesteps == reader_adapt.GetUnlimitedDimensionValues().size());

        DistributedVectorFactory factory(mesh.GetNumNodes());
        Vec voltage_no_adapt = factory.CreateVec();
        Vec voltage_adapt = factory.CreateVec();

        Vec difference;
        VecDuplicate(voltage_adapt, &difference);

        for (unsigned timestep=0; timestep<num_timesteps; timestep++)
        {
            reader_no_adapt.GetVariableOverNodes(voltage_no_adapt, "V", timestep);
            reader_adapt.GetVariableOverNodes(voltage_adapt, "V", timestep);

            PetscVecTools::WAXPY(difference, -1.0, voltage_adapt, voltage_no_adapt);
            double l_inf_norm;
            VecNorm(difference, NORM_INFINITY, &l_inf_norm);

            //std::cout << l_inf_norm << "\n";
            if (timestep < 25)
            {
                TS_ASSERT_DELTA(l_inf_norm, 0.0, 1e-10); // first 25 ms, there should be no difference
            }
            else
            {
                TS_ASSERT_DELTA(l_inf_norm, 0.0, 2.25); // the difference is at most ~2mv, which occurs during the downstroke
            }
        }

        PetscTools::Destroy(voltage_no_adapt);
        PetscTools::Destroy(voltage_adapt);
    }
    void TestBidomainProblemWithDistributedMesh2D() throw(Exception)
    {
        HeartConfig::Instance()->SetSimulationDuration(1);  //ms
        HeartConfig::Instance()->SetOutputDirectory("DistributedMesh2d");
        HeartConfig::Instance()->SetOutputFilenamePrefix("tetrahedral2d");

        // The default stimulus in PlaneStimulusCellFactory is not enough to generate propagation
        // here, increasing it an order of magnitude
        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory(-6000);

        // To avoid an issue with the Event handler only one simulation should be
        // in existance at a time: therefore monodomain simulation is defined in a block
        double seq_ave_voltage;
        {
            ///////////////////////////////////////////////////////////////////
            // TetrahedralMesh
            ///////////////////////////////////////////////////////////////////
            TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/2D_0_to_1mm_400_elements");
            TetrahedralMesh<2,2> mesh;
            mesh.ConstructFromMeshReader(mesh_reader);

            BidomainProblem<2> nondistributed_problem( &cell_factory );
            nondistributed_problem.SetMesh(&mesh);
            nondistributed_problem.Initialise();

            HeartConfig::Instance()->SetSurfaceAreaToVolumeRatio(1.0);
            HeartConfig::Instance()->SetCapacitance(1.0);

            nondistributed_problem.Solve();

            DistributedVector dist_nondistributed_voltage = nondistributed_problem.GetSolutionDistributedVector();
            DistributedVector::Stripe nondistributed_voltage(dist_nondistributed_voltage, 0);
            DistributedVector::Stripe nondistributed_potential(dist_nondistributed_voltage, 1);

            double seq_local_ave_voltage = 0.0;

            for (DistributedVector::Iterator index = dist_nondistributed_voltage.Begin();
                 index != dist_nondistributed_voltage.End();
                 ++index)
            {
                if (index.Global==0)
                {
                    TS_ASSERT_LESS_THAN(0, nondistributed_voltage[index]);
                }

                seq_local_ave_voltage += nondistributed_voltage[index];
            }

            MPI_Reduce(&seq_local_ave_voltage, &seq_ave_voltage, 1, MPI_DOUBLE, MPI_SUM, PetscTools::MASTER_RANK, PETSC_COMM_WORLD);
            seq_ave_voltage /= mesh.GetNumNodes();
        }


        ///////////////////////////////////////////////////////////////////
        // DistributedTetrahedralMesh
        ///////////////////////////////////////////////////////////////////
        HeartConfig::Instance()->SetOutputFilenamePrefix("distributed2d");

        TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/2D_0_to_1mm_400_elements");
        DistributedTetrahedralMesh<2,2> mesh(DistributedTetrahedralMeshPartitionType::DUMB);

        mesh.ConstructFromMeshReader(mesh_reader);

        BidomainProblem<2> distributed_problem( &cell_factory );

        distributed_problem.SetMesh(&mesh);

        distributed_problem.Initialise();

        HeartConfig::Instance()->SetSurfaceAreaToVolumeRatio(1.0);
        HeartConfig::Instance()->SetCapacitance(1.0);

        distributed_problem.Solve();

        DistributedVector dist_distributed_voltage = distributed_problem.GetSolutionDistributedVector();
        DistributedVector::Stripe distributed_voltage(dist_distributed_voltage, 0);
        DistributedVector::Stripe distributed_potential(dist_distributed_voltage, 1);

        double para_local_ave_voltage = 0.0;

        for (DistributedVector::Iterator index = dist_distributed_voltage.Begin();
             index != dist_distributed_voltage.End();
             ++index)
        {
            if (index.Global==0)
            {
                TS_ASSERT_LESS_THAN(0, distributed_voltage[index]);
            }

            para_local_ave_voltage += distributed_voltage[index];
        }


        double para_ave_voltage;
        MPI_Reduce(&para_local_ave_voltage, &para_ave_voltage, 1, MPI_DOUBLE, MPI_SUM, PetscTools::MASTER_RANK, PETSC_COMM_WORLD);
        para_ave_voltage /= mesh.GetNumNodes();

        ///////////////////////////////////////////////////////////////////
        // compare
        ///////////////////////////////////////////////////////////////////
        if (PetscTools::AmMaster())
        {
            std::cout << seq_ave_voltage << "  " << para_ave_voltage << std::endl;
            TS_ASSERT_DELTA(seq_ave_voltage, para_ave_voltage, 1.0);
        }

    }