コード例 #1
0
    void SetupParameters() throw (Exception)
    {
        HeartConfig::Instance()->Reset();
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(5.0));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(1.0));

        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.1,0.1,10.0);

        //HeartConfig::Instance()->SetKSPSolver("gmres");
        HeartConfig::Instance()->SetUseAbsoluteTolerance(1e-5);
        HeartConfig::Instance()->SetKSPPreconditioner("bjacobi");
    }
    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();
    }
コード例 #3
0
    ////////////////////////////////////////////////////////////
    // 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);
        }
    }
コード例 #4
0
ファイル: TestNeumannStimulus.hpp プロジェクト: Chaste/Chaste
    // Solve on a 1D string of cells, 1mm long with a space step of 0.1mm.
    void TestMonodomainConstantStimulus()
    {
        // this parameters are a bit arbitrary, and chosen to get a good spread of voltages
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75));
        HeartConfig::Instance()->SetSimulationDuration(2); //ms
        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/1D_0_to_1mm_10_elements");
        HeartConfig::Instance()->SetOutputDirectory("MonoNeumannConst");
        HeartConfig::Instance()->SetOutputFilenamePrefix("MonodomainLR91_1d");

        ZeroStimulusCellFactory<CellLuoRudy1991FromCellML, 1> cell_factory;
        MonodomainProblem<1> monodomain_problem( &cell_factory );

        monodomain_problem.Initialise();
        HeartConfig::Instance()->SetSurfaceAreaToVolumeRatio(1*1.75/0.0005);

        // create boundary conditions container
        boost::shared_ptr<BoundaryConditionsContainer<1,1,1> > p_bcc(new BoundaryConditionsContainer<1,1,1>);
        ConstBoundaryCondition<1>* p_bc_stim = new ConstBoundaryCondition<1>(2*1.75/0.0005);

        // get mesh
        AbstractTetrahedralMesh<1,1> &mesh = monodomain_problem.rGetMesh();
        // loop over boundary elements
        AbstractTetrahedralMesh<1, 1>::BoundaryElementIterator iter;
        iter = mesh.GetBoundaryElementIteratorBegin();
        while (iter != mesh.GetBoundaryElementIteratorEnd())
        {
            // if the element is on the left of the mesh, add a stimulus to the bcc
            if (((*iter)->GetNodeLocation(0))[0]==0.0)
            {
                p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim);
            }
            iter++;
        }

        // pass the bcc to the monodomain problem
        monodomain_problem.SetBoundaryConditionsContainer(p_bcc);

        monodomain_problem.Solve();

        // check some voltages
        ReplicatableVector voltage_replicated(monodomain_problem.GetSolution());
        double atol=5e-3;

        TS_ASSERT_DELTA(voltage_replicated[1], 94.6426, atol);
        TS_ASSERT_DELTA(voltage_replicated[3], 49.7867, atol);
        TS_ASSERT_DELTA(voltage_replicated[5], 30.5954, atol);
        TS_ASSERT_DELTA(voltage_replicated[7], 21.6782, atol);
        TS_ASSERT_DELTA(voltage_replicated[9], -33.9983, atol);
        TS_ASSERT_DELTA(voltage_replicated[10], -52.2396, atol);

    }
コード例 #5
0
    void RunBenchMark(double h, double dt, double endTime, bool useSvi)
    {
        TetrahedralMesh<3,3> mesh;

        mesh.ConstructRegularSlabMesh(h, 2.0, 0.7, 0.3);

        std::stringstream output_dir;
        output_dir << "Benchmark" << "_h" << h << "_dt" << dt;

        HeartConfig::Instance()->SetOutputDirectory(output_dir.str());
        HeartConfig::Instance()->SetOutputFilenamePrefix("results");
        HeartConfig::Instance()->SetSimulationDuration(endTime); //ms

        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.005, dt, 0.1);
        HeartConfig::Instance()->SetSurfaceAreaToVolumeRatio(1400); // 1400 1/cm
        HeartConfig::Instance()->SetCapacitance(1); // 1uF/cm^2

        HeartConfig::Instance()->SetVisualizeWithMeshalyzer(false);

        // The Chaste results for the benchmark paper use STATE-VARIABLE INTERPOLATION switched on
        // (see comments above)
        HeartConfig::Instance()->SetUseStateVariableInterpolation(useSvi);

        // Regarding the second paper described above, to run the simulations with ICI, comment out the
        // above line. To run the simulation with operator splitting, or with (full) mass-lumping,
        // comment out the above SVI line and uncomment one of the below. (Note: half-lumping is not
        // available).
        //HeartConfig::Instance()->SetUseMassLumping(true); // what is described as full-lumping in this paper
        //HeartConfig::Instance()->SetUseReactionDiffusionOperatorSplitting(true);

        double long_conductance = 0.17 * 0.62/(0.17+0.62) * 10;    // harmonic mean of 0.17, 0.62 S/m converted to mS/cm
        double trans_conductance = 0.019 * 0.24/(0.019+0.24) * 10; // harmonic mean of 0.019,0.24 S/m converted to mS/cm

        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(long_conductance, trans_conductance, trans_conductance));

        BenchmarkCellFactory cell_factory;

        MonodomainProblem<3> problem( &cell_factory );
        problem.SetMesh(&mesh);

        problem.Initialise();
        problem.SetWriteInfo();
        problem.Solve();
    }
コード例 #6
0
    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(...)?");
    }
コード例 #7
0
    // Solve with a space step of 0.5mm.
    //
    // Note that this space step ought to be too big!
    //
    // NOTE: This test uses NON-PHYSIOLOGICAL parameters values (conductivities,
    // surface-area-to-volume ratio, capacitance, stimulus amplitude). Essentially,
    // the equations have been divided through by the surface-area-to-volume ratio.
    // (Historical reasons...)
    void TestMonodomainFailing()
    {
        if (PetscTools::GetNumProcs() > 3u)
        {
            TS_TRACE("This test is not suitable for more than 3 processes.");
            return;
        }
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(0.0005));
        HeartConfig::Instance()->SetSimulationDuration(1); //ms
//        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/1D_0_to_1_20_elements");
//        HeartConfig::Instance()->SetSpaceDimension(1);
//        HeartConfig::Instance()->SetFibreLength(1.0, 1.0/20.0);
        HeartConfig::Instance()->SetSpaceDimension(3);
        HeartConfig::Instance()->SetSlabDimensions(0.2, 0.1, 0.1, 0.05);
        HeartConfig::Instance()->SetOutputDirectory("MonoFailing");
        HeartConfig::Instance()->SetOutputFilenamePrefix("MonodomainLR91_SVI");
        HeartConfig::Instance()->SetUseStateVariableInterpolation(true);

        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 3> cell_factory;
        MonodomainProblem<3> monodomain_problem(&cell_factory);

        monodomain_problem.Initialise();

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

        // the mesh is too coarse, and this simulation will result in cell gating
        // variables going out of range. An exception should be thrown in the
        // EvaluateYDerivatives() method of the cell model


        TS_ASSERT_THROWS_CONTAINS(monodomain_problem.Solve(),
#ifndef NDEBUG
            // VerifyStateVariables is only called when debug is on
            "State variable fast_sodium_current_m_gate__m has gone out of range. "
            "Check numerical parameters, for example time and space stepsizes");
#else
            // This test hits a later assert(!isnan) if we do a ndebug build.
            "Assertion tripped: !std::isnan(i_ionic)");
#endif // NDEBUG
    }
コード例 #8
0
    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
コード例 #9
0
    // Solve on a 2D 1mm by 1mm mesh (space step = 0.1mm), stimulating the left
    // edge.
    void TestMonodomainFitzHughNagumoWithEdgeStimulus( void ) throw (Exception)
    {
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(0.01, 0.01));
        HeartConfig::Instance()->SetSimulationDuration(1.2); //ms
        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/2D_0_to_1mm_400_elements");
        HeartConfig::Instance()->SetOutputDirectory("FhnWithEdgeStimulus");
        HeartConfig::Instance()->SetOutputFilenamePrefix("MonodomainFhn_2dWithEdgeStimulus");

        FhnEdgeStimulusCellFactory cell_factory;

        // using the criss-cross mesh so wave propagates properly
        MonodomainProblem<2> monodomain_problem( &cell_factory );

        monodomain_problem.Initialise();

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


        monodomain_problem.Solve();


        /*
        * Test the top right node against the right one in the 1D case,
        * comparing voltage, and then test all the nodes on the right hand
        * side of the square against the top right one, comparing voltage.
        */
        bool need_initialisation = true;
        double probe_voltage=0.0;

        DistributedVector voltage = monodomain_problem.GetSolutionDistributedVector();
        need_initialisation = true;

        // Test the RHS of the mesh
        for (DistributedVector::Iterator node_index = voltage.Begin();
             node_index != voltage.End();
             ++node_index)
        {
            if (monodomain_problem.rGetMesh().GetNode(node_index.Global)->GetPoint()[0] == 0.1)
            {
                // x = 0 is where the stimulus has been applied
                // x = 0.1cm is the other end of the mesh and where we want to
                //       to test the value of the nodes

                if (need_initialisation)
                {
                    probe_voltage = voltage[node_index];
                    need_initialisation = false;
                }
                else
                {
                    // Tests the final voltages for all the RHS edge nodes
                    // are close to each other.
                    // This works as we are using the 'criss-cross' mesh,
                    // the voltages would vary more with a mesh with all the
                    // triangles aligned in the same direction.

                    TS_ASSERT_DELTA(voltage[node_index], probe_voltage, 2e-4);
                }

                TS_ASSERT_DELTA(voltage[node_index], 0.139426, 2e-3);
             }
        }
    }
    //This test is identical to the test above, just that we use a model that requires an explicit solver
    void TestMechanicsWithBidomainAndBathExplicit() throw(Exception)
    {
        EntirelyStimulatedTissueCellFactory cell_factory;

        TetrahedralMesh<2,2> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(0.01, 0.05, 0.05);

        //make everything a bath node except for the x=0 line
        for (TetrahedralMesh<2,2>::ElementIterator iter=electrics_mesh.GetElementIteratorBegin();
             iter != electrics_mesh.GetElementIteratorEnd();
            ++iter)
        {
            if ((*iter).CalculateCentroid()[0] > 0.001)
            {
                (*iter).SetAttribute(HeartRegionCode::GetValidBathId());
            }
            else
            {
                (*iter).SetAttribute(HeartRegionCode::GetValidTissueId());
            }
        }

        QuadraticMesh<2> mechanics_mesh;
        mechanics_mesh.ConstructRegularSlabMesh(0.025, 0.05, 0.05);

        //store the original node positions
        std::vector<c_vector<double,2> > original_node_position;
        c_vector<double,2> pos = zero_vector<double>(2);
        for(unsigned i=0; i<mechanics_mesh.GetNumNodes(); i++)
        {
            pos(0) = mechanics_mesh.GetNode(i)->rGetLocation()[0];
            pos(1) = mechanics_mesh.GetNode(i)->rGetLocation()[1];
            original_node_position.push_back(pos);
        }

        std::vector<unsigned> fixed_nodes;
        std::vector<c_vector<double,2> > fixed_node_locations;

        // fix the node at the origin so that the solution is well-defined (ie unique)
        fixed_nodes.push_back(0);
        fixed_node_locations.push_back(zero_vector<double>(2));

        // for the rest of the nodes, if they lie on X=0, fix x=0 but leave y free.
        for(unsigned i=1 /*not 0*/; i<mechanics_mesh.GetNumNodes(); i++)
        {
            if(fabs(mechanics_mesh.GetNode(i)->rGetLocation()[0])<1e-6)
            {
                c_vector<double,2> new_position;
                new_position(0) = 0.0;
                new_position(1) = SolidMechanicsProblemDefinition<2>::FREE;
                fixed_nodes.push_back(i);
                fixed_node_locations.push_back(new_position);
            }
        }

        ElectroMechanicsProblemDefinition<2> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(NASH2004,1.0);
        problem_defn.SetUseDefaultCardiacMaterialLaw(INCOMPRESSIBLE);
        problem_defn.SetFixedNodes(fixed_nodes, fixed_node_locations);
        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.01,0.1,1.0);
        problem_defn.SetMechanicsSolveTimestep(1.0);

        HeartConfig::Instance()->SetSimulationDuration(10.0);
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(1500,1500,1500));
        CardiacElectroMechanicsProblem<2,2> problem(INCOMPRESSIBLE,
                                                    BIDOMAIN_WITH_BATH,
                                                    &electrics_mesh,
                                                    &mechanics_mesh,
                                                    &cell_factory,
                                                    &problem_defn,
                                                    "TestCardiacEmWithBath");

        problem.Solve();
        std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition();

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

        for(unsigned i=0; i<mechanics_mesh.GetNumNodes(); i++)
        {
            TS_ASSERT_DELTA( r_deformed_position[i](0), original_node_position[i](0), 1e-6);
            TS_ASSERT_DELTA( r_deformed_position[i](1), original_node_position[i](1), 1e-6);
        }
    }
    /* HOW_TO_TAG Cardiac/Electro-mechanics
     * Run electro-mechanical simulations using bidomain instead of monodomain
     *
     * This test is the same as above but with bidomain instead of monodomain.
     * Extracellular conductivities are set very high so the results should be the same.
     */
    void TestWithHomogeneousEverythingCompressibleBidomain() throw(Exception)
    {
        EntirelyStimulatedTissueCellFactory cell_factory;

        TetrahedralMesh<2,2> electrics_mesh;
        electrics_mesh.ConstructRegularSlabMesh(0.01, 0.05, 0.05);

        QuadraticMesh<2> mechanics_mesh;
        mechanics_mesh.ConstructRegularSlabMesh(0.025, 0.05, 0.05);

        std::vector<unsigned> fixed_nodes;
        std::vector<c_vector<double,2> > fixed_node_locations;

        // fix the node at the origin so that the solution is well-defined (ie unique)
        fixed_nodes.push_back(0);
        fixed_node_locations.push_back(zero_vector<double>(2));

        // for the rest of the nodes, if they lie on X=0, fix x=0 but leave y free.
        for(unsigned i=1 /*not 0*/; i<mechanics_mesh.GetNumNodes(); i++)
        {
            if(fabs(mechanics_mesh.GetNode(i)->rGetLocation()[0])<1e-6)
            {
                c_vector<double,2> new_position;
                new_position(0) = 0.0;
                new_position(1) = SolidMechanicsProblemDefinition<2>::FREE;
                fixed_nodes.push_back(i);
                fixed_node_locations.push_back(new_position);
            }
        }

        ElectroMechanicsProblemDefinition<2> problem_defn(mechanics_mesh);
        problem_defn.SetContractionModel(KERCHOFFS2003,1.0);
        problem_defn.SetUseDefaultCardiacMaterialLaw(COMPRESSIBLE);
        problem_defn.SetFixedNodes(fixed_nodes, fixed_node_locations);
        problem_defn.SetMechanicsSolveTimestep(1.0);

        // the following is just for coverage - applying a zero pressure so has no effect on deformation
        std::vector<BoundaryElement<1,2>*> boundary_elems;
        boundary_elems.push_back(* (mechanics_mesh.GetBoundaryElementIteratorBegin()));
        problem_defn.SetApplyNormalPressureOnDeformedSurface(boundary_elems, 0.0);

        HeartConfig::Instance()->SetSimulationDuration(10.0);
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(1500,1500,1500));
        //creates the EM problem with ELEC_PROB_DIM=2
        CardiacElectroMechanicsProblem<2,2> problem(COMPRESSIBLE,
                                                    BIDOMAIN,
                                                    &electrics_mesh,
                                                    &mechanics_mesh,
                                                    &cell_factory,
                                                    &problem_defn,
                                                    "TestCardiacEmHomogeneousEverythingCompressibleBidomain");

        problem.Solve();
        std::vector<c_vector<double,2> >& r_deformed_position = problem.rGetDeformedPosition();

        // not sure how easy is would be determine what the deformation should be
        // exactly, but it certainly should be constant squash in X direction, constant
        // stretch in Y.

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

        double X_scale_factor = r_deformed_position[8](0)/0.05;
        double Y_scale_factor = r_deformed_position[8](1)/0.05;

        std::cout << "Scale_factors = " << X_scale_factor << " " << Y_scale_factor << ", product = " << X_scale_factor*Y_scale_factor<<"\n";

        for(unsigned i=0; i<mechanics_mesh.GetNumNodes(); i++)
        {
            double X = mechanics_mesh.GetNode(i)->rGetLocation()[0];
            double Y = mechanics_mesh.GetNode(i)->rGetLocation()[1];

            TS_ASSERT_DELTA( r_deformed_position[i](0), X * X_scale_factor, 1e-6);
            TS_ASSERT_DELTA( r_deformed_position[i](1), Y * Y_scale_factor, 1e-6);
        }

        //check interpolated voltages and calcium

        unsigned quad_points = problem.mpCardiacMechSolver->GetTotalNumQuadPoints();
        TS_ASSERT_EQUALS(problem.mInterpolatedVoltages.size(), quad_points);
        TS_ASSERT_EQUALS(problem.mInterpolatedCalciumConcs.size(), quad_points);

        //two hardcoded values
        TS_ASSERT_DELTA(problem.mInterpolatedVoltages[0],9.267,1e-3);
        TS_ASSERT_DELTA(problem.mInterpolatedCalciumConcs[0],0.001464,1e-6);

        //for the rest, we check that, at the end of this simulation, all quad nodes have V and Ca above a certain threshold
        for(unsigned i = 0; i < quad_points; i++)
        {
            TS_ASSERT_LESS_THAN(9.2,problem.mInterpolatedVoltages[i]);
            TS_ASSERT_LESS_THAN(0.0014,problem.mInterpolatedCalciumConcs[i]);
        }

        //check default value of whether there is a bath or not
        TS_ASSERT_EQUALS(problem.mpElectricsProblem->GetHasBath(), false);

        //test the functionality of having phi_e on the mechanics mesh (values are tested somewhere else)
        Hdf5DataReader data_reader("TestCardiacEmHomogeneousEverythingCompressibleBidomain/electrics","voltage_mechanics_mesh");
        TS_ASSERT_THROWS_NOTHING(data_reader.GetVariableOverTime("Phi_e",0u));
    }
コード例 #12
0
    /**
     * Tests archiving of the tissue object.
     * It creates one, changes the default values of some member variables and saves.
     * Then it tries to load from the archive and checks that the member variables are with the right values.
     */
    void TestSaveAndLoadExtendedBidomainTissue() throw (Exception)
    {
        HeartConfig::Instance()->Reset();
        // Archive settings
        FileFinder archive_dir("extended_tissue_archive", RelativeTo::ChasteTestOutput);
        std::string archive_file = "extended_bidomain_tissue.arch";

        bool cache_replication_saved = false;
        double saved_printing_timestep = 2.0;
        double default_printing_timestep = HeartConfig::Instance()->GetPrintingTimeStep();

        c_matrix<double, 3, 3> intra_tensor_before_archiving;
        c_matrix<double, 3, 3> intra_tensor_second_cell_before_archiving;
        c_matrix<double, 3, 3> extra_tensor_before_archiving;

        //creation and save
        {
            // This call is required to set the appropriate conductivity media and to make sure that HeartConfig
            // knows the mesh filename despite we use our own mesh reader.
            HeartConfig::Instance()->SetMeshFileName("mesh/test/data/cube_136_elements");

            TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_136_elements");
            DistributedTetrahedralMesh<3,3> mesh;
            mesh.ConstructFromMeshReader(mesh_reader);

            UnStimulatedCellFactory first_cell;
            StimulatedCellFactory second_cell;
            ExtracellularStimulusFactory extra_factory;
            first_cell.SetMesh(&mesh);
            second_cell.SetMesh(&mesh);
            extra_factory.SetMesh(&mesh);
            ExtendedBidomainTissue<3> extended_tissue( &first_cell, &second_cell , &extra_factory);

            //set a value different from default for the conductivities of the second cell
            extended_tissue.SetIntracellularConductivitiesSecondCell(Create_c_vector(25.0,26.0,27.0));
            //this is normally done by the problem class, but in this test we do it manually
            extended_tissue.CreateIntracellularConductivityTensorSecondCell();
            extended_tissue.SetCacheReplication(cache_replication_saved); // Not the default to check it is archived...

            //shuffle default values to check if they get archived properly
            extended_tissue.SetAmFirstCell(11.0);
            extended_tissue.SetAmSecondCell(22.0);
            extended_tissue.SetAmGap(33.0);
            extended_tissue.SetCmFirstCell(44.0);
            extended_tissue.SetCmSecondCell(55.0);
            extended_tissue.SetGGap(66.0);

            //again, away from default value to check for archiving
            extended_tissue.SetUserSuppliedExtracellularStimulus(true);

            //set some heterogeneities in Ggap
            std::vector<boost::shared_ptr<AbstractChasteRegion<3> > > heterogeneity_areas;
            std::vector<double> Ggap_values;
            ChastePoint<3> cornerA(-1, -1, 0);
            ChastePoint<3> cornerB(0.001, 0.001, 0.001);
            boost::shared_ptr<ChasteCuboid<3> > p_cuboid_1(new ChasteCuboid<3>(cornerA, cornerB));
            heterogeneity_areas.push_back(p_cuboid_1);
            //within the first area
            Ggap_values.push_back(143.0);
            extended_tissue.SetGgapHeterogeneities(heterogeneity_areas, Ggap_values);
            extended_tissue.CreateGGapConductivities();

            // Some checks to make sure HeartConfig is being saved and loaded by this too.
            HeartConfig::Instance()->SetPrintingTimeStep(saved_printing_timestep);
            TS_ASSERT_DELTA(HeartConfig::Instance()->GetPrintingTimeStep(), saved_printing_timestep, 1e-9);

            intra_tensor_before_archiving = extended_tissue.rGetIntracellularConductivityTensor(0);
            intra_tensor_second_cell_before_archiving = extended_tissue.rGetIntracellularConductivityTensorSecondCell(0);
            extra_tensor_before_archiving = extended_tissue.rGetExtracellularConductivityTensor(0);

            // Save
            ArchiveOpener<boost::archive::text_oarchive, std::ofstream> arch_opener(archive_dir, archive_file);
            boost::archive::text_oarchive* p_arch = arch_opener.GetCommonArchive();

            AbstractCardiacTissue<3>* const p_archive_bidomain_tissue = &extended_tissue;
            (*p_arch) << p_archive_bidomain_tissue;

            HeartConfig::Reset();
            TS_ASSERT_DELTA(HeartConfig::Instance()->GetPrintingTimeStep(), default_printing_timestep, 1e-9);
            TS_ASSERT_DIFFERS(saved_printing_timestep, default_printing_timestep);
        }
        //load
        {
            ArchiveOpener<boost::archive::text_iarchive, std::ifstream> arch_opener(archive_dir, archive_file);
            boost::archive::text_iarchive* p_arch = arch_opener.GetCommonArchive();

            AbstractCardiacTissue<3>* p_abstract_tissue;
            (*p_arch) >> p_abstract_tissue;
            assert(p_abstract_tissue!=NULL);

            //dynamic cast so we are able to test specific variables of ExtendedBidomainTissue
            ExtendedBidomainTissue<3>* p_extended_tissue = dynamic_cast<ExtendedBidomainTissue<3>*>(p_abstract_tissue);
            assert(p_extended_tissue != NULL);

            const c_matrix<double, 3, 3>& intra_tensor_after_archiving = p_extended_tissue->rGetIntracellularConductivityTensor(0);
            const c_matrix<double, 3, 3>& intra_tensor_second_cell_after_archiving = p_extended_tissue->rGetIntracellularConductivityTensorSecondCell(0);
            const c_matrix<double, 3, 3>& extra_tensor_after_archiving = p_extended_tissue->rGetExtracellularConductivityTensor(0);

            //check before archiving = after archiving
            for(unsigned i=0; i<3; i++)
            {
                for(unsigned j=0; j<3; j++)
                {
                    TS_ASSERT_DELTA(intra_tensor_before_archiving(i,j), intra_tensor_after_archiving(i,j), 1e-9);
                    TS_ASSERT_DELTA(intra_tensor_second_cell_before_archiving(i,j), intra_tensor_second_cell_after_archiving(i,j), 1e-9);
                    TS_ASSERT_DELTA(extra_tensor_before_archiving(i,j), extra_tensor_after_archiving(i,j), 1e-9);
                }
            }

            //check that the member variable mIntracellularConductivitiesSecondCell was archived properly
            TS_ASSERT_EQUALS(p_extended_tissue->GetIntracellularConductivitiesSecondCell()(0),25.0);
            TS_ASSERT_EQUALS(p_extended_tissue->GetIntracellularConductivitiesSecondCell()(1),26.0);
            TS_ASSERT_EQUALS(p_extended_tissue->GetIntracellularConductivitiesSecondCell()(2),27.0);

            //check that we get the same values from the archive which are different from the default
            TS_ASSERT_EQUALS(p_extended_tissue->GetAmFirstCell(), 11.0);
            TS_ASSERT_EQUALS(p_extended_tissue->GetAmSecondCell(), 22.0);
            TS_ASSERT_EQUALS(p_extended_tissue->GetAmGap(), 33.0);
            TS_ASSERT_EQUALS(p_extended_tissue->GetCmFirstCell(), 44.0);
            TS_ASSERT_EQUALS(p_extended_tissue->GetCmSecondCell(), 55.0);
            TS_ASSERT_EQUALS(p_extended_tissue->GetGGap(), 66.0);

            // We shouldn't need to re-build the mesh, but we use it to check that the new tissue has the same mesh
            // Also, when testing in parallel, we use it to get the vector factory to loop over the nodes we own.
            // this is because  p_extended_tissue->pGetMesh()->GetDistributedVectorFactory() doesn't compile (discards qualifier stuff caused by use of const).
            TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_136_elements");
            DistributedTetrahedralMesh<3,3> mesh;
            mesh.ConstructFromMeshReader(mesh_reader);

            TS_ASSERT_EQUALS(mesh.GetNumNodes(), p_extended_tissue->pGetMesh()->GetNumNodes());//note: this is allowed because GetNumNodes has const in the signature

            //check archiving of stimulus for first cell at some random times (it is unstimulated everywhere at all times)
            for (unsigned i = 0; i < mesh.GetNumNodes(); i++)
            {
                if (mesh.GetDistributedVectorFactory()->IsGlobalIndexLocal(i))
                {
                    TS_ASSERT_EQUALS(p_extended_tissue->GetCardiacCell(i)->GetIntracellularStimulus(0.0), 0.0);
                    TS_ASSERT_EQUALS(p_extended_tissue->GetCardiacCell(i)->GetIntracellularStimulus(0.1), 0.0);
                    TS_ASSERT_EQUALS(p_extended_tissue->GetCardiacCell(i)->GetIntracellularStimulus(2.5), 0.0);
                    TS_ASSERT_EQUALS(p_extended_tissue->GetCardiacCell(i)->GetIntracellularStimulus(28.9), 0.0);
                }
            }

            //for second cell and other stuff, we probe nodes 0 and 1.
            unsigned node_0 = 0u;
            unsigned node_1 = 1u;
            //If the test is run in parallel, we need to work out the new indices
            const std::vector<unsigned>& r_permutation = mesh.rGetNodePermutation();
            if (!r_permutation.empty())
            {
                node_0 = r_permutation[0u];
                node_1 = r_permutation[1u];
            }

            //second cell is stimulated in the corner (node 0) from time 0 to 1. check it gets all this after loading
            if (mesh.GetDistributedVectorFactory()->IsGlobalIndexLocal(node_0))
            {
                TS_ASSERT_EQUALS(p_extended_tissue->GetCardiacSecondCell(node_0)->GetIntracellularStimulus(0.5), -105.0*1400);
                TS_ASSERT_EQUALS(p_extended_tissue->GetCardiacSecondCell(node_0)->GetIntracellularStimulus(2.5), 0.0);

                //find local index of (the new) node_0, it should be in the heterogeneity region
                unsigned ownership_range_low = mesh.GetDistributedVectorFactory()->GetLow();
                unsigned  local_index = node_0 - ownership_range_low;
                //std::cout<<local_index<<std::endl;
                TS_ASSERT_EQUALS(p_extended_tissue->rGetGapsDistributed()[local_index],143.0);//g_gap value inside heterogeneity region
            }

            //node 0 has extracellular stimulus (1 ms from 0.1)
            if (mesh.GetDistributedVectorFactory()->IsGlobalIndexLocal(node_0))
            {
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_0)->GetStimulus(0.0), 0);
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_0)->GetStimulus(0.5), -428000);
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_0)->GetStimulus(1.0), -428000);
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_0)->GetStimulus(1.15), 0);
            }

            //node 1 doesn't
            if (mesh.GetDistributedVectorFactory()->IsGlobalIndexLocal(node_1))
            {
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_1)->GetStimulus(0.0), 0);
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_1)->GetStimulus(0.5), 0);
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_1)->GetStimulus(1.0), 0);
                TS_ASSERT_EQUALS(p_extended_tissue->GetExtracellularStimulus(node_1)->GetStimulus(1.15), 0);

                //find local index of (the new) node_1, it should NOT be in the heterogeneity region
                unsigned ownership_range_low = mesh.GetDistributedVectorFactory()->GetLow();
                unsigned  local_index = node_1 - ownership_range_low;
                TS_ASSERT_EQUALS(p_extended_tissue->rGetGapsDistributed()[local_index],66.0);//standard g_gap value, outside heterogeneity region
            }

            //check the archiving of the flag (it would be false by default, but we set it to true before archiving)
            TS_ASSERT_EQUALS(p_extended_tissue->HasTheUserSuppliedExtracellularStimulus(),true);

            TS_ASSERT_EQUALS(cache_replication_saved, p_extended_tissue->GetDoCacheReplication());
            TS_ASSERT_DELTA(HeartConfig::Instance()->GetPrintingTimeStep(), saved_printing_timestep, 1e-9);
            TS_ASSERT_DIFFERS(saved_printing_timestep, default_printing_timestep); // Test we are testing something in case default changes

            delete p_extended_tissue;
        }
    }
コード例 #13
0
    void TestExtendedTissueHeterogeneousConductivities2D() throw (Exception)
   {
       HeartConfig::Instance()->Reset();
       TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/square_4_elements");
       TetrahedralMesh<2,2> mesh;
       mesh.ConstructFromMeshReader(mesh_reader);

       //HeartConfig setup needs to be in 3D anyway (hardcoded in HeartConfig).
       std::vector<ChasteCuboid<3> > heterogeneity_area;
       std::vector< c_vector<double,3> > intra_conductivities;
       std::vector< c_vector<double,3> > extra_conductivities;

       //first cuboid includes element 0
       ChastePoint<3> cornerA(-1, -1,-1);
       ChastePoint<3> cornerB(0.48, 2.0, 0.48);
       ChasteCuboid<3> cuboid_1(cornerA, cornerB);

       heterogeneity_area.push_back(cuboid_1);

       //second cuboid includes element 2
       ChastePoint<3> cornerC(0.52, -1, 0.52);
       ChastePoint<3> cornerD(2, 2, 2);
       ChasteCuboid<3> cuboid_2(cornerC, cornerD);

       heterogeneity_area.push_back(cuboid_2);

       //within the first area
       intra_conductivities.push_back( Create_c_vector(1.0, 2.0, 3.0) );
       extra_conductivities.push_back( Create_c_vector(51.0, 52.0, 53.0) );

       //within the second area
       intra_conductivities.push_back( Create_c_vector(11.0, 22.0, 33.0) );
       extra_conductivities.push_back( Create_c_vector(151.0, 152.0, 153.0) );

       HeartConfig::Instance()->SetConductivityHeterogeneities(heterogeneity_area, intra_conductivities, extra_conductivities);

       //elsewhere
       double isotropic_intra_conductivity=15.0;
       double isotropic_extra_conductivity=65.0;
       HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(isotropic_intra_conductivity, isotropic_intra_conductivity, isotropic_intra_conductivity));
       HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(isotropic_extra_conductivity, isotropic_extra_conductivity, isotropic_extra_conductivity));

       PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory_1;
       PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 2> cell_factory_2;
       StimulusFactory2D extracellular_stimulus_factory;

       cell_factory_1.SetMesh(&mesh);
       cell_factory_2.SetMesh(&mesh);
       extracellular_stimulus_factory.SetMesh(&mesh);

       //2D tissue
       ExtendedBidomainTissue<2>  extended_bidomain_tissue( &cell_factory_1,  &cell_factory_2, &extracellular_stimulus_factory);

       // Do conductivity modifier here too (for coverage)
       SimpleConductivityModifier conductivity_modifier;
       extended_bidomain_tissue.SetConductivityModifier( &conductivity_modifier );

       extended_bidomain_tissue.SetIntracellularConductivitiesSecondCell(Create_c_vector(isotropic_intra_conductivity, isotropic_intra_conductivity));
       extended_bidomain_tissue.CreateIntracellularConductivityTensorSecondCell();

       //first cell
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(0u)(0,0),1.0);//within first cuboid
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(1u)(0,0),30.0);//within no cuboid (modified from 15 to 30!)
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(2u)(1,1),22.0);//within second cuboid
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(3u)(0,0),15.0);//within no cuboid

       //second cell, should be the same as first cell
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(0u)(0,0),1.0);//within first cuboid
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(1u)(0,0),30.0);//within no cuboid (modified from 15 to 30!)
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(2u)(1,1),22.0);//within second cuboid
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(3u)(0,0),15.0);//within no cuboid

       //sigma_e
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(0u)(0,0),51.0);//within first cuboid
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(1u)(0,0),130.0);//within no cuboid (modified from 65 to 130!)
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(2u)(1,1),152.0);//within second cuboid
       TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(3u)(0,0),65.0);//within no cuboid
   }
コード例 #14
0
    /**This test checks heterogeneous conductivities*/
    void TestExtendedTissueHeterogeneous3D() throw (Exception)
    {
        HeartConfig::Instance()->Reset();
        TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_2mm_12_elements");
        TetrahedralMesh<3,3> mesh;
        mesh.ConstructFromMeshReader(mesh_reader);

        std::vector<ChasteCuboid<3> > heterogeneity_area;
        std::vector< c_vector<double,3> > intra_conductivities;
        std::vector< c_vector<double,3> > extra_conductivities;

        //first cuboid include element 0
        ChastePoint<3> cornerA(-1, -1, 0);
        ChastePoint<3> cornerB(0.1, 0.2, 0.2);
        ChasteCuboid<3> cuboid_1(cornerA, cornerB);
        heterogeneity_area.push_back(cuboid_1);

        //second cuboid include element 4
        ChastePoint<3> cornerC(0.11, 0.0, 0);
        ChastePoint<3> cornerD(0.2, 0.11, 0.2);
        ChasteCuboid<3> cuboid_2(cornerC, cornerD);

        heterogeneity_area.push_back(cuboid_2);

        //within the first area
        intra_conductivities.push_back( Create_c_vector(1.0, 2.0, 3.0) );
        extra_conductivities.push_back( Create_c_vector(51.0, 52.0, 53.0) );

        //within the second area
        intra_conductivities.push_back( Create_c_vector(11.0, 22.0, 33.0) );
        extra_conductivities.push_back( Create_c_vector(151.0, 152.0, 153.0) );

        HeartConfig::Instance()->SetConductivityHeterogeneities(heterogeneity_area, intra_conductivities, extra_conductivities);

        //elsewhere
        double isotropic_intra_conductivity=15.0;
        double isotropic_extra_conductivity=65.0;

        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(isotropic_intra_conductivity, isotropic_intra_conductivity, isotropic_intra_conductivity));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(isotropic_extra_conductivity, isotropic_extra_conductivity, isotropic_extra_conductivity));

        StimulatedCellFactory stimulated_cell_factory;
        UnStimulatedCellFactory unstimulated_cell_factory;
        ExtracellularStimulusFactory extracellular_stimulus_factory;

        stimulated_cell_factory.SetMesh(&mesh);
        unstimulated_cell_factory.SetMesh(&mesh);
        extracellular_stimulus_factory.SetMesh(&mesh);

        ExtendedBidomainTissue<3>  extended_bidomain_tissue( &stimulated_cell_factory,  &unstimulated_cell_factory, &extracellular_stimulus_factory);

        extended_bidomain_tissue.SetIntracellularConductivitiesSecondCell(Create_c_vector(isotropic_intra_conductivity, isotropic_intra_conductivity, isotropic_intra_conductivity));
        extended_bidomain_tissue.CreateIntracellularConductivityTensorSecondCell();

        //first cell
//        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(0u)(0,0),1.0);//within first cuboid
        //Line above commented due to curious problem with IntelProduction interprocedural optimisation
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(4u)(0,0),11.0);//within second cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(4u)(1,1),22.0);//within second cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensor(8u)(0,0),15.0);//elsewhere, e.g. element 8

        //second cell, should be the same as first cell
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(0u)(0,0),1.0);//within first cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(4u)(0,0),11.0);//within second cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(4u)(1,1),22.0);//within second cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetIntracellularConductivityTensorSecondCell(8u)(0,0),15.0);//elsewhere, e.g. element 8

        //sigma_e
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(0u)(0,0),51.0);//within first cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(4u)(0,0),151.0);//within second cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(4u)(1,1),152.0);//within second cuboid
        TS_ASSERT_EQUALS(extended_bidomain_tissue.rGetExtracellularConductivityTensor(8u)(0,0),65.0);//elsewhere, e.g. element 8

    }
コード例 #15
0
    void TestBidomainWithBathWithSvi() throw(Exception)
    {
        /* Make a 4x4 node mesh and set two interior elements to be bath elements */
        DistributedTetrahedralMesh<2,2> mesh;
        mesh.ConstructRegularSlabMesh(0.04, 0.12, 0.12);

        for (AbstractTetrahedralMesh<2,2>::ElementIterator iter=mesh.GetElementIteratorBegin();
             iter != mesh.GetElementIteratorEnd();
             ++iter)
        {
            unsigned element_index = iter->GetIndex();

            if ( element_index==10 || element_index==17 )
            {
                iter->SetAttribute(HeartRegionCode::GetValidBathId());
            }
            else
            {
                iter->SetAttribute(HeartRegionCode::GetValidTissueId());
            }
        }

        HeartConfig::Instance()->SetSimulationDuration(10.0); // ms
        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.001, 0.025, 0.25);
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75, 0.17));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(7.0, 0.7));

        ReplicatableVector final_solution_ici;
        ReplicatableVector final_solution_svi;

        // ICI - ionic current interpolation (the default)
        {
            HeartConfig::Instance()->SetOutputDirectory("BidomainWithBathIci2d");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");
            HeartConfig::Instance()->SetUseStateVariableInterpolation(false);

            BathCellFactory cell_factory;
            BidomainWithBathProblem<2> bidomain_problem( &cell_factory );
            bidomain_problem.SetMesh(&mesh);
            bidomain_problem.Initialise();
            bidomain_problem.Solve();

            final_solution_ici.ReplicatePetscVector(bidomain_problem.GetSolution());
        }

        // SVI - state variable interpolation
        {
            HeartConfig::Instance()->SetOutputDirectory("BidomainWithBathSvi2d");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");
            HeartConfig::Instance()->SetUseStateVariableInterpolation(true);

            BathCellFactory cell_factory;
            BidomainWithBathProblem<2> bidomain_problem( &cell_factory );
            bidomain_problem.SetMesh(&mesh);
            bidomain_problem.Initialise();
            bidomain_problem.Solve();

            final_solution_svi.ReplicatePetscVector(bidomain_problem.GetSolution());
        }

        // ICI
        TS_ASSERT_DELTA(final_solution_ici[15*2], 7.0918, 2e-3); // Node 15 phi_i
        TS_ASSERT_DELTA(final_solution_ici[15*2+1], 0.0401, 1e-3); // Node 15 phi_e
        // SVI
        TS_ASSERT_DELTA(final_solution_svi[15*2], 10.6217, 2e-3); // Node 15 phi_i
        TS_ASSERT_DELTA(final_solution_svi[15*2+1], -0.0180, 1e-3); // Node 15 phi_e

    }
コード例 #16
0
    void TestConductionVelocityInCrossFibreDirection2d()
    {

        ReplicatableVector final_voltage_ici;
        ReplicatableVector final_voltage_svi;
        ReplicatableVector final_voltage_svit;

        HeartConfig::Instance()->SetSimulationDuration(5.0); //ms
        //HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.0005, 0.01, 0.01); //See comment below
        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.005, 0.01, 0.01);

        // much lower conductivity in cross-fibre direction - ICI will struggle
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75, 0.17));

        TetrahedralMesh<2,2> mesh;
        mesh.ConstructRegularSlabMesh(0.02 /*h*/, 0.5, 0.3);

        // ICI - nodal current interpolation - the default
        {
            HeartConfig::Instance()->SetOutputDirectory("MonodomainIci2d");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");

            HeartConfig::Instance()->SetUseStateVariableInterpolation(false);

            BlockCellFactory<2> cell_factory;
            MonodomainProblem<2> monodomain_problem( &cell_factory );
            monodomain_problem.SetMesh(&mesh);
            monodomain_problem.Initialise();
            monodomain_problem.Solve();

            final_voltage_ici.ReplicatePetscVector(monodomain_problem.GetSolution());
        }

        // SVI - state variable interpolation
        {
            HeartConfig::Instance()->SetOutputDirectory("MonodomainSvi2d");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");

            HeartConfig::Instance()->SetUseStateVariableInterpolation();

            BlockCellFactory<2> cell_factory;
            MonodomainProblem<2> monodomain_problem( &cell_factory );
            monodomain_problem.SetMesh(&mesh);
            monodomain_problem.Initialise();

            monodomain_problem.Solve();

            final_voltage_svi.ReplicatePetscVector(monodomain_problem.GetSolution());
        }

#ifdef CHASTE_CVODE
        ReplicatableVector final_voltage_svi_cvode;
        // SVI - state variable interpolation with CVODE cells
        {
            HeartConfig::Instance()->SetOutputDirectory("MonodomainSvi2dCvode");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");

            HeartConfig::Instance()->SetUseStateVariableInterpolation();

            BlockCellFactoryCvode<2> cell_factory;
            MonodomainProblem<2> monodomain_problem( &cell_factory );
            monodomain_problem.SetMesh(&mesh);
            monodomain_problem.Initialise();

            monodomain_problem.Solve();

            final_voltage_svi_cvode.ReplicatePetscVector(monodomain_problem.GetSolution());
        }
#endif //CHASTE_CVODE

        // SVIT - state variable interpolation on non-distributed tetrahedral mesh
        {

            HeartConfig::Instance()->SetOutputDirectory("MonodomainSviTet2d");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");

            HeartConfig::Instance()->SetUseStateVariableInterpolation();

            BlockCellFactory<2> cell_factory;
            MonodomainProblem<2> monodomain_problem( &cell_factory );
            monodomain_problem.SetMesh(&mesh);
            monodomain_problem.Initialise();

            monodomain_problem.Solve();

            final_voltage_svit.ReplicatePetscVector(monodomain_problem.GetSolution());
        }

        // Visualised results with h=0.02 and h=0.01 - results looks sensible according to
        // paper:
        // 1. SVI h=0.01 and h=0.02 match more closely than ICI results - ie SVI converges faster
        // 2. CV in fibre direction faster for ICI (both values of h)
        // 3. CV in cross fibre direction: (i) h=0.01, faster for ICI; h=0.02 slower for ICI.
        // (Matches results in paper)

        double ici_20 = -17.1939; // These numbers are from a solve with ODE timestep of 0.0005,
        double svi_20 = -62.6336; // i.e. ten times smaller than that used in the test at present
        double ici_130 = 15.4282; // (for speed), hence large tolerances below.
        double svi_130 = 30.7389; // The tolerances are still nowhere near overlapping - i.e. ICI different to SVI

        // node 20 (for h=0.02) is on the x-axis (fibre direction), SVI CV is slower
        TS_ASSERT_DELTA(mesh.GetNode(20)->rGetLocation()[0],  0.4, 1e-9);
        TS_ASSERT_DELTA(mesh.GetNode(20)->rGetLocation()[1],  0.0, 1e-9);

        TS_ASSERT_DELTA(final_voltage_ici[20], ici_20, 8.0);  // These tolerances show difference in parallel,
        TS_ASSERT_DELTA(final_voltage_svi[20], svi_20, 3.0);  // note that SVI is more stable in the presence of multicore...
#ifdef CHASTE_CVODE
        TS_ASSERT_DELTA(final_voltage_svi_cvode[20], svi_20, 3.0);
#endif //Cvode
        TS_ASSERT_DELTA(final_voltage_svit[20], svi_20, 3.0);

        // node 130 (for h=0.02) is on the y-axis (cross-fibre direction), ICI CV is slower
        TS_ASSERT_DELTA(mesh.GetNode(130)->rGetLocation()[0], 0.0, 1e-9);
        TS_ASSERT_DELTA(mesh.GetNode(130)->rGetLocation()[1], 0.1, 1e-9);

        TS_ASSERT_DELTA(final_voltage_ici[130], ici_130, 1.0);
        TS_ASSERT_DELTA(final_voltage_svi[130], svi_130, 0.2);
#ifdef CHASTE_CVODE
        TS_ASSERT_DELTA(final_voltage_svi_cvode[130], svi_130, 0.3); // different CVODE versions = slightly different answer!
#endif //cvode
        TS_ASSERT_DELTA(final_voltage_svit[130], svi_130, 0.2);
    }
コード例 #17
0
    void TestBidomainTissueWithHeterogeneousConductivitiesEllipsoid() throw (Exception)
    {
        HeartConfig::Instance()->Reset();

        // This call is required to set the appropriate conductivity media and to make sure that
        // HeartConfig knows the mesh filename despite we use our own mesh reader.
        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/cube_2mm_12_elements", cp::media_type::NoFibreOrientation);

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

        /*
        * HOW_TO_TAG Cardiac/Problem definition
        * Set discrete '''ellipsoid''' areas to have heterogeneous (intra- and/or extra-cellular) conductivity tensors.
        */
        std::vector<ChasteEllipsoid<3> > heterogeneity_area;
        std::vector< c_vector<double,3> > intra_conductivities;
        std::vector< c_vector<double,3> > extra_conductivities;

        //first small ellipsoid including element 0 centroid
        ChastePoint<3> centre_1(0.025, 0.075, 0.05);
        ChastePoint<3> radii_1(0.1, 0.1, 0.1);
        ChasteEllipsoid<3> ellipsoid_1(centre_1, radii_1);
        heterogeneity_area.push_back(ellipsoid_1);

        //second small ellipsoid including element 4 centroid
        ChastePoint<3> centre_2(0.175, 0.025, 0.05);
        ChastePoint<3> radii_2(0.1, 0.1, 0.1);
        ChasteEllipsoid<3> ellipsoid_2(centre_2, radii_2);

        heterogeneity_area.push_back(ellipsoid_2);

        //within the first area
        intra_conductivities.push_back( Create_c_vector(1.0, 2.0, 3.0) );
        extra_conductivities.push_back( Create_c_vector(51.0, 52.0, 53.0) );

        //within the second area
        intra_conductivities.push_back( Create_c_vector(11.0, 22.0, 33.0) );
        extra_conductivities.push_back( Create_c_vector(151.0, 152.0, 153.0) );

        HeartConfig::Instance()->SetConductivityHeterogeneitiesEllipsoid(heterogeneity_area, intra_conductivities, extra_conductivities);


        //elsewhere
        double isotropic_intra_conductivity=15.0;
        double isotropic_extra_conductivity=65.0;
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(isotropic_intra_conductivity, isotropic_intra_conductivity, isotropic_intra_conductivity));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(isotropic_extra_conductivity, isotropic_extra_conductivity, isotropic_extra_conductivity));

        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML,3> cell_factory_for_het;
        cell_factory_for_het.SetMesh(&mesh);

        //CreateIntracellularConductivityTensor called in the constructor
        BidomainTissue<3> bidomain_tissue( &cell_factory_for_het );

        TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(0u)(0,0),1.0);//within first ellipsoid
        TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(4u)(0,0),11.0);//within second ellipsoid
        TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(4u)(1,1),22.0);//within second ellipsoid
        TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(8u)(0,0),15.0);//elsewhere, e.g. element 8

        TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(0u)(0,0),51.0);//within first ellipsoid
        TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(4u)(0,0),151.0);//within second ellipsoid
        TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(4u)(1,1),152.0);//within second ellipsoid
        TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(8u)(0,0),65.0);//elsewhere, e.g. element 8
    }
コード例 #18
0
    void TestBidomainTissueWithHeterogeneousConductivitiesDistributed() throw (Exception)
    {
        HeartConfig::Instance()->Reset();

        // This call is required to set the appropriate conductivity media and to make sure that
        // HeartConfig knows the mesh filename despite we use our own mesh reader.
        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/cube_2mm_12_elements", cp::media_type::NoFibreOrientation);

        TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_2mm_12_elements");

        // METIS_LIBRARY partition ensures that we have never own all the elements (even when there are as few as 2 processes)
        // DUMB and PARMETIS_LIBRARY may allow single process to see all the elements because it's a very small mesh
        DistributedTetrahedralMesh<3,3> mesh(DistributedTetrahedralMeshPartitionType::METIS_LIBRARY);
        mesh.ConstructFromMeshReader(mesh_reader);

        // Check that if we're in parallel no single process owns every element (to ensure that the conductivities
        // really are distributed).
        if (PetscTools::IsParallel())
        {
            TS_ASSERT_DIFFERS( mesh.GetNumElements(), mesh.GetNumLocalElements() );
        }

        std::vector<ChasteCuboid<3> > heterogeneity_area;
        std::vector< c_vector<double,3> > intra_conductivities;
        std::vector< c_vector<double,3> > extra_conductivities;

        //first cuboid include element 0
        ChastePoint<3> cornerA(-1, -1, 0);
        ChastePoint<3> cornerB(0.1, 0.2, 0.2);
        ChasteCuboid<3> cuboid_1(cornerA, cornerB);
        heterogeneity_area.push_back(cuboid_1);

        //second cuboid include element 4
        ChastePoint<3> cornerC(0.11, 0.0, 0);
        ChastePoint<3> cornerD(0.2, 0.11, 0.2);
        ChasteCuboid<3> cuboid_2(cornerC, cornerD);

        heterogeneity_area.push_back(cuboid_2);

        //within the first area
        intra_conductivities.push_back( Create_c_vector(1.0, 2.0, 3.0) );
        extra_conductivities.push_back( Create_c_vector(51.0, 52.0, 53.0) );

        //within the second area
        intra_conductivities.push_back( Create_c_vector(11.0, 22.0, 33.0) );
        extra_conductivities.push_back( Create_c_vector(151.0, 152.0, 153.0) );

        HeartConfig::Instance()->SetConductivityHeterogeneities(heterogeneity_area, intra_conductivities, extra_conductivities);


        //elsewhere
        double isotropic_intra_conductivity=15.0;
        double isotropic_extra_conductivity=65.0;
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(isotropic_intra_conductivity, isotropic_intra_conductivity, isotropic_intra_conductivity));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(isotropic_extra_conductivity, isotropic_extra_conductivity, isotropic_extra_conductivity));

        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML,3> cell_factory_for_het;
        cell_factory_for_het.SetMesh(&mesh);

        //CreateIntracellularConductivityTensor called in the constructor
        BidomainTissue<3> bidomain_tissue( &cell_factory_for_het );

        if (mesh.CalculateDesignatedOwnershipOfElement(0u))
        {
             TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(0u)(0,0),1.0);//within first cuboid
             TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(0u)(0,0),51.0);//within first cuboid
        }

        if (mesh.CalculateDesignatedOwnershipOfElement(4u))
        {
            TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(4u)(0,0),11.0);//within second cuboid
            TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(4u)(1,1),22.0);//within second cuboid
            TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(4u)(0,0),151.0);//within second cuboid
            TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(4u)(1,1),152.0);//within second cuboid
        }

        if (mesh.CalculateDesignatedOwnershipOfElement(8u))
        {
            TS_ASSERT_EQUALS(bidomain_tissue.rGetIntracellularConductivityTensor(8u)(0,0),15.0);//elsewhere, e.g. element 8
            TS_ASSERT_EQUALS(bidomain_tissue.rGetExtracellularConductivityTensor(8u)(0,0),65.0);//elsewhere, e.g. element 8
        }


    }
コード例 #19
0
    /**
     * This test is aimed at comparing the extended bidomain implementation in Chaste with
     * the original Finite Difference code developed by Martin Buist.
     *
     * All the parameters are chosen to replicate the same conditions as in his code.
     */
    void TestExtendedProblemVsMartincCode() throw (Exception)
    {
        SetupParameters();

        TetrahedralMesh<1,1> mesh;
        unsigned number_of_elements = 100;//this is nGrid in Martin's code
        double length = 10.0;//100mm as in Martin's code
        mesh.ConstructRegularSlabMesh(length/number_of_elements, length);
        TS_ASSERT_EQUALS(mesh.GetNumAllNodes(), number_of_elements + 1);

        double Am_icc = 1000.0;
        double Am_smc = 1000.0;
        double Am_gap = 1.0;
        double Cm_icc = 1.0;
        double Cm_smc = 1.0;
        double G_gap = 20.0;//mS/cm^2

        HeartConfig::Instance()->SetSimulationDuration(1000.0);  //ms.

        ICC_Cell_factory icc_factory;
        SMC_Cell_factory smc_factory;

        std::string dir = "ICCandSMC";
        std::string filename = "extended1d";
        HeartConfig::Instance()->SetOutputDirectory(dir);
        HeartConfig::Instance()->SetOutputFilenamePrefix(filename);

        ExtendedBidomainProblem<1> extended_problem( &icc_factory , &smc_factory);
        extended_problem.SetMesh(&mesh);

        extended_problem.SetExtendedBidomainParameters(Am_icc,Am_smc, Am_gap, Cm_icc, Cm_smc, G_gap);
        extended_problem.SetIntracellularConductivitiesForSecondCell(Create_c_vector(1.0));

        std::vector<unsigned> outputnodes;
        outputnodes.push_back(50u);
        HeartConfig::Instance()->SetRequestedNodalTimeTraces(outputnodes);

        extended_problem.Initialise();
        extended_problem.Solve();
        HeartEventHandler::Headings();
        HeartEventHandler::Report();

        /**
         * Compare with valid data.
         * As Martin's code is an FD code, results will never match exactly.
         * The comparison below is done against a 'valid' h5 file.
         *
         * The h5 file (1DValid.h5) is a Chaste (old phi_i formulation) file with is valid because, when extrapolating results from it, they look very similar
         * (except for a few points at the end of the upstroke) to the results taken
         * directly from Martin's code.
         * A plot of Chaste results versus Martin's result (at node 50) is stored
         * in the file 1DChasteVsMartin.eps for reference.
         *
         * A second plot comparing the old formulation (with phi_i) to the new formulation with V_m is contained in
         *.1DChasteNewFormulation.png
         *
         */
         TS_ASSERT( CompareFilesViaHdf5DataReader("heart/test/data/extendedbidomain", "1DValid", false,
                                                dir, filename, true,
                                                0.2));
         /*
          * Here we compare the new formulation (V_m1, V_m2, phi_e)
          *  with the previous formulation (phi_i1, phi_i2, phi_e) running with GMRES and an absolute KSP tolerance of 1e-8.
          */
         TS_ASSERT( CompareFilesViaHdf5DataReader("heart/test/data/extendedbidomain", "extended1d_previous_chaste_formulation_abs_tol_1e-8", false,
                                                dir, filename, true,
                                                1e-2));
    }
コード例 #20
0
    void TestBidomain3d() throw (Exception)
    {
        HeartEventHandler::Reset();
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75, 1.75, 1.75));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(7.0, 7.0, 7.0));
        HeartConfig::Instance()->SetSimulationDuration(4.0);  //ms
        HeartConfig::Instance()->SetMeshFileName("mesh/test/data/3D_0_to_1mm_6000_elements");
        HeartConfig::Instance()->SetOutputDirectory("Bidomain3d");
        HeartConfig::Instance()->SetOutputFilenamePrefix("bidomain3d");

        // Check the linear system can be solved to a low tolerance (in particular, checks the null space
        // stuff was implemented correctly
        HeartConfig::Instance()->SetUseAbsoluteTolerance(1e-14);

        PlaneStimulusCellFactory<CellLuoRudy1991FromCellML, 3> bidomain_cell_factory(-600.0*1000);

        BidomainProblem<3> bidomain_problem( &bidomain_cell_factory );

        bidomain_problem.Initialise();

        //bidomain_problem.SetNodeForAverageOfPhiZeroed(1330);
        //bidomain_problem.SetFixedExtracellularPotentialNodes(1330);

        bidomain_problem.Solve();

        Vec voltage=bidomain_problem.GetSolution();
        ReplicatableVector voltage_replicated;
        voltage_replicated.ReplicatePetscVector(voltage);

        /*
         * Test the top right node against the right one in the 1D case,
         * comparing voltage, and then test all the nodes on the right hand
         * face of the cube against the top right one, comparing voltage.
         */
        bool need_initialisation = true;
        double probe_voltage=0;

        need_initialisation = true;

        // Test the RHF of the mesh
        for (AbstractTetrahedralMesh<3,3>::NodeIterator it = bidomain_problem.rGetMesh().GetNodeIteratorBegin();
             it != bidomain_problem.rGetMesh().GetNodeIteratorEnd();
             ++it)
        {
            if (it->GetPoint()[0] == 0.1)
            {
                // x = 0 is where the stimulus has been applied
                // x = 0.1cm is the other end of the mesh and where we want to
                //       to test the value of the nodes

                if (need_initialisation)
                {
                    probe_voltage = voltage_replicated[2*it->GetIndex()];
                    need_initialisation = false;
                }
                else
                {
                    // the voltage at the end face varies a little because
                    // of drift due to the orientation of the tets in the mesh,
                    // hence the tolerance of 0.2
                    TS_ASSERT_DELTA(voltage_replicated[2*it->GetIndex()], probe_voltage, 0.2);
                }

                // if a 1D simulation is run for 4ms on the 0_1mm_10elements mesh
                // the result at the end node is 20.0755
                TS_ASSERT_DELTA(voltage_replicated[2*it->GetIndex()], 20.0755, 1.3);
            }
        }

        /*
         * HOW_TO_TAG Cardiac/Output
         * Collect and print timings to benchmark different parts of the cardiac code.
         *
         * N.B. You may also want to use HeartEventHandler::Reset() if you call these again.
         */
        HeartEventHandler::Headings();
        HeartEventHandler::Report();
    }
    void TestBidomain3d() throw (Exception)
    {

        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75, 1.75, 1.75));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(7.0, 7.0, 7.0));
        HeartConfig::Instance()->SetSimulationDuration(150.0);  //ms
        //Note that we can only call the old permute nodes funcutionality on the sequential mesh object
        //HeartConfig::Instance()->SetMeshFileName("mesh/test/data/3D_0_to_.5mm_1889_elements_irregular");

        BidomainFaceStimulusCellFactory bidomain_cell_factory;

        BidomainProblem<3> bidomain_problem( &bidomain_cell_factory );
        TetrahedralMesh<3,3> mesh;
        TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/3D_0_to_.5mm_1889_elements_irregular");
        mesh.ConstructFromMeshReader(mesh_reader);
        bidomain_problem.SetMesh(&mesh);

        bidomain_problem.PrintOutput(false);

        HeartConfig::Instance()->SetKSPSolver("symmlq");
        HeartConfig::Instance()->SetKSPPreconditioner("bjacobi");
        PetscOptionsSetValue("-log_summary", "");

        bidomain_problem.Initialise();

        //Mesh isn't actually loaded until initialise method is called
        RandomNumberGenerator::Instance();
        bidomain_problem.rGetMesh().PermuteNodes();
        RandomNumberGenerator::Destroy();

        bidomain_problem.Solve();

        Vec voltage=bidomain_problem.GetSolution();
        ReplicatableVector voltage_replicated;
        voltage_replicated.ReplicatePetscVector(voltage);

        /*
         * Test the top right node against the right one in the 1D case,
         * comparing voltage, and then test all the nodes on the right hand
         * face of the cube against the top right one, comparing voltage.
         */
        bool need_initialisation = true;
        double probe_voltage=-9999.;

        need_initialisation = true;

        // Test the RHF of the mesh
        for (unsigned i = 0; i < bidomain_problem.rGetMesh().GetNumNodes(); i++)
        {
            if (bidomain_problem.rGetMesh().GetNode(i)->GetPoint()[0] == 0.05)
            {
                // x = 0 is where the stimulus has been applied
                // x = 0.05cm is the other end of the mesh and where we want to
                //       to test the value of the nodes

                if (need_initialisation)
                {
                    probe_voltage = voltage_replicated[2*i];
                    need_initialisation = false;
                }
                else
                {
                    // the voltage at the end face varies a little because
                    // of drift due to the orientation of the tets in the mesh,
                    // hence the tolerance of 0.02
                    TS_ASSERT_DELTA(voltage_replicated[2*i], probe_voltage, 0.02);
                }

                // Check against hard coded value
                // For 50 ms test TS_ASSERT_DELTA(voltage_replicated[2*i],  7.3, 0.2);
                // For 150 ms test
                TS_ASSERT_DELTA(voltage_replicated[2*i],  -1.735, 0.1);
            }
        }
    }
コード例 #22
0
    void TestConductionVelocityInCrossFibreDirection2d() throw(Exception)
    {
        ReplicatableVector final_solution_ici;
        ReplicatableVector final_solution_svi;

        HeartConfig::Instance()->SetSimulationDuration(4.0); //ms
        HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(0.005, 0.01, 0.01);

        // much lower conductivity in cross-fibre direction - ICI will struggle
        HeartConfig::Instance()->SetIntracellularConductivities(Create_c_vector(1.75, 0.17));
        HeartConfig::Instance()->SetExtracellularConductivities(Create_c_vector(7.0, 0.7));

        // ICI - nodal current interpolation - the default
        {
            TetrahedralMesh<2,2> mesh;
            mesh.ConstructRegularSlabMesh(0.02 /*h*/, 0.5, 0.3);

            HeartConfig::Instance()->SetOutputDirectory("BidomainIci2d");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");

            HeartConfig::Instance()->SetUseStateVariableInterpolation(false);

            BlockCellFactory<2> cell_factory;
            BidomainProblem<2> bidomain_problem( &cell_factory );
            bidomain_problem.SetMesh(&mesh);
            bidomain_problem.Initialise();
            bidomain_problem.Solve();

            final_solution_ici.ReplicatePetscVector(bidomain_problem.GetSolution());
        }

        // SVI - state variable interpolation
        {
            TetrahedralMesh<2,2> mesh;
            mesh.ConstructRegularSlabMesh(0.02 /*h*/, 0.5, 0.3);

            HeartConfig::Instance()->SetOutputDirectory("BidomainSvi2d");
            HeartConfig::Instance()->SetOutputFilenamePrefix("results");

            HeartConfig::Instance()->SetUseStateVariableInterpolation(true);

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

            bidomain_problem.Solve();

            final_solution_svi.ReplicatePetscVector(bidomain_problem.GetSolution());
        }

        // See comments in equivalent part of test/monodomain/TestMonodomainWithSvi.hpp
        // For bidomain with h=0.02, SVI CV is slower in both fibre and cross-fibre
        // directions

        // node 20 (for h=0.02) is on the x-axis (fibre direction)
        TS_ASSERT_DELTA(final_solution_ici[20*2], -64.1105, 1e-3); // Node 20 phi_i
        TS_ASSERT_DELTA(final_solution_svi[20*2], -78.0936, 1e-3); // Node 20 phi_i
        // node 234 (for h=0.02) is on the y-axis (cross-fibre direction)
        TS_ASSERT_DELTA(final_solution_ici[234*2], -57.7239, 1e-3); // Node 234 phi_i
        TS_ASSERT_DELTA(final_solution_svi[234*2], 38.9004, 1e-3); // Node 234 phi_i
    }