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(); }
//////////////////////////////////////////////////////////// // 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); } }
// 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); }
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(); }
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(...)?"); }
// 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 }
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
// 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)); }
/** * 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; } }
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 }
/**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 }
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 }
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); }
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 }
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 } }
/** * 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)); }
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); } } }
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 }