37 #ifndef ABSTRACTCONVERGENCETESTER_HPP_ 38 #define ABSTRACTCONVERGENCETESTER_HPP_ 40 #include "BidomainProblem.hpp" 41 #include "MonodomainProblem.hpp" 50 #include "AbstractTetrahedralMesh.hpp" 51 #include "TrianglesMeshReader.hpp" 52 #include "AbstractCardiacCellFactory.hpp" 53 #include "OutputFileHandler.hpp" 54 #include "TrianglesMeshWriter.hpp" 55 #include "PropagationPropertiesCalculator.hpp" 56 #include "Hdf5DataReader.hpp" 57 #include "GeneralPlaneStimulusCellFactory.hpp" 58 #include "CuboidMeshConstructor.hpp" 59 #include "ZeroStimulusCellFactory.hpp" 60 #include "SimpleStimulus.hpp" 61 #include "ConstBoundaryCondition.hpp" 62 #include "StimulusBoundaryCondition.hpp" 64 #include "Warnings.hpp" 67 typedef enum StimulusType_
78 template <
class CELL,
unsigned DIM>
83 std::vector< boost::shared_ptr<SimpleStimulus> >
mpStimuli;
102 mMeshWidth(meshWidth),
103 mStepSize(meshWidth/numElemAcross),
104 mLevels(numElemAcross/4)
106 assert(numElemAcross%4 == 0);
108 for (
unsigned level=0; level<
mLevels; level++)
110 double this_stim = fullStim - (level*fullStim)/mLevels;
112 mpStimuli.push_back((boost::shared_ptr<SimpleStimulus>)
new SimpleStimulus(this_stim, 0.5));
126 unsigned level = (
unsigned) d_level;
127 assert(fabs(level-d_level) < DBL_MAX);
131 return new CELL(this->
mpSolver, this->mpStimuli[level]);
191 virtual void Converge(std::string nameOfTest)=0;
199 template<
class CARDIAC_PROBLEM,
unsigned DIM>
200 void SetConductivities(CARDIAC_PROBLEM& rCardiacProblem);
202 template<
unsigned DIM>
205 c_vector<double, DIM> conductivities;
206 for (
unsigned i=0; i<DIM; i++)
208 conductivities[i] = 1.75;
212 for (
unsigned i=0; i<DIM; i++)
214 conductivities[i] = 7.0;
219 template<
unsigned DIM>
222 c_vector<double, DIM> conductivities;
223 for (
unsigned i=0; i<DIM; i++)
225 conductivities[i] = 1.75;
234 template<
class CELL,
class CARDIAC_PROBLEM,
unsigned DIM,
unsigned PROBLEM_DIM>
246 const std::string mesh_dir =
"ConvergenceMesh";
254 out_stream p_conv_info_file;
257 std::cout <<
"=========================== Beginning Test...==================================\n";
258 p_conv_info_file = conv_info_handler.
OpenOutputFile(nameOfTest+
"_info.csv");
259 (*p_conv_info_file) <<
"#Abcisa\t" 262 <<
"Max absolute err\t" 263 <<
"APD90_1st_quad\t" 264 <<
"APD90_3rd_quad\t" 265 <<
"Conduction velocity (relative diffs)" << std::endl;
267 SetInitialConvergenceParameters();
269 double prev_apd90_first_qn=0.0;
270 double prev_apd90_third_qn=0.0;
271 double prev_cond_velocity=0.0;
272 std::vector<double> prev_voltage;
273 std::vector<double> prev_times;
274 PopulateStandardResult(prev_voltage, prev_times);
281 double printing_step = this->PdeTimeStep;
283 while (printing_step < 1.0e-4)
285 printing_step *= 2.0;
286 std::cout<<
"Warning: PrintingTimeStep increased\n";
291 if (SimulateFullActionPotential)
306 unsigned num_ele_across =
SmallPow(2u, this->MeshNum+2);
310 switch (this->Stimulus)
333 CARDIAC_PROBLEM cardiac_problem(p_cell_factory);
334 cardiac_problem.SetMesh(&mesh);
337 unsigned third_quadrant_node;
338 unsigned first_quadrant_node;
349 unsigned n=
SmallPow (2u, this->MeshNum+2);
350 first_quadrant_node = (n+1)*(n/2)+ n/4 ;
351 third_quadrant_node = (n+1)*(n/2)+3*n/4 ;
356 const unsigned first_quadrant_nodes_3d[5]={61, 362, 2452, 17960, 137296};
357 const unsigned third_quadrant_nodes_3d[5]={63, 366, 2460, 17976, 137328};
358 assert(this->PdeTimeStep<5);
359 first_quadrant_node = first_quadrant_nodes_3d[this->MeshNum];
360 third_quadrant_node = third_quadrant_nodes_3d[this->MeshNum];
368 double mesh_width=constructor.
GetWidth();
371 std::vector<unsigned> nodes_to_be_output;
372 nodes_to_be_output.push_back(first_quadrant_node);
373 nodes_to_be_output.push_back(third_quadrant_node);
374 cardiac_problem.SetOutputNodes(nodes_to_be_output);
379 SetConductivities(cardiac_problem);
381 cardiac_problem.Initialise();
385 if (Stimulus==NEUMANN)
394 iter = r_mesh.GetBoundaryElementIteratorBegin();
395 while (iter != r_mesh.GetBoundaryElementIteratorEnd())
397 double x = ((*iter)->CalculateCentroid())[0];
401 p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim);
406 cardiac_problem.SetBoundaryConditionsContainer(p_bcc);
416 cardiac_problem.Solve();
420 WARNING(
"This run threw an exception. Check convergence results\n");
433 std::vector<double> transmembrane_potential = results_reader.
GetVariableOverTime(
"V", third_quadrant_node);
441 std::stringstream plot_file_name_stream;
442 plot_file_name_stream<< nameOfTest <<
"_Third_quadrant_node_run_"<< file_num <<
".csv";
443 out_stream p_plot_file = plot_file_handler.
OpenOutputFile(plot_file_name_stream.str());
444 for (
unsigned data_point = 0; data_point<time_series.size(); data_point++)
446 (*p_plot_file) << time_series[data_point] <<
"\t" << transmembrane_potential[data_point] <<
"\n";
448 p_plot_file->close();
452 std::vector<double> transmembrane_potential_1qd=results_reader.
GetVariableOverTime(
"V", first_quadrant_node);
454 std::stringstream plot_file_name_stream;
455 plot_file_name_stream<< nameOfTest <<
"_First_quadrant_node_run_"<< file_num <<
".csv";
456 out_stream p_plot_file = plot_file_handler.
OpenOutputFile(plot_file_name_stream.str());
457 for (
unsigned data_point = 0; data_point<time_series.size(); data_point++)
459 (*p_plot_file) << time_series_1qd[data_point] <<
"\t" << transmembrane_potential_1qd[data_point] <<
"\n";
461 p_plot_file->close();
470 if (SimulateFullActionPotential)
481 std::cout <<
"Warning - this run threw an exception in calculating propagation. Check convergence results\n";
485 double cond_velocity_error = 1e10;
486 double apd90_first_qn_error = 1e10;
487 double apd90_third_qn_error = 1e10;
489 if (this->PopulatedResult)
491 if (prev_cond_velocity != 0.0)
493 cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity;
496 if (prev_apd90_first_qn != 0.0)
498 apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn;
500 if (prev_apd90_third_qn != 0.0)
502 apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn;
504 if (apd90_first_qn_error == 0.0)
506 apd90_first_qn_error = DBL_EPSILON;
508 if (apd90_third_qn_error == 0.0)
510 apd90_third_qn_error = DBL_EPSILON;
513 if (cond_velocity_error == 0.0)
515 cond_velocity_error = DBL_EPSILON;
519 prev_cond_velocity = ConductionVelocity;
520 prev_apd90_first_qn = Apd90FirstQn;
521 prev_apd90_third_qn = Apd90ThirdQn;
524 double max_abs_error = 0;
525 double sum_sq_abs_error =0;
526 double sum_sq_prev_voltage = 0;
527 double sum_sq_abs_error_full =0;
528 double sum_sq_prev_voltage_full = 0;
529 if (this->PopulatedResult)
533 unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1);
534 assert (time_factor == 1 || time_factor == 2 || time_factor == 8);
536 for (
unsigned data_point = 0; data_point<prev_times.size(); data_point++)
538 unsigned this_data_point=time_factor*data_point;
540 assert(time_series[this_data_point] == prev_times[data_point]);
541 double abs_error = fabs(transmembrane_potential[this_data_point]-prev_voltage[data_point]);
542 max_abs_error = (abs_error > max_abs_error) ? abs_error : max_abs_error;
544 sum_sq_abs_error_full += abs_error*abs_error;
545 sum_sq_prev_voltage_full += prev_voltage[data_point] * prev_voltage[data_point];
546 if (time_series[this_data_point] <= 8.0)
549 sum_sq_abs_error += abs_error*abs_error;
550 sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point];
555 if (!this->PopulatedResult || !FixedResult)
557 prev_voltage = transmembrane_potential;
558 prev_times = time_series;
561 if (this->PopulatedResult)
563 double l2_norm_upstroke = sqrt(sum_sq_abs_error/sum_sq_prev_voltage);
564 double l2_norm_full = sqrt(sum_sq_abs_error_full/sum_sq_prev_voltage_full);
568 (*p_conv_info_file) << std::setprecision(8)
569 << Abscissa() <<
"\t" 570 << l2_norm_full <<
"\t" 571 << l2_norm_upstroke <<
"\t" 572 << max_abs_error <<
"\t" 573 << Apd90FirstQn <<
" "<< apd90_first_qn_error <<
""<<
"\t" 574 << Apd90ThirdQn <<
" "<< apd90_third_qn_error <<
""<<
"\t" 575 << ConductionVelocity <<
" "<< cond_velocity_error <<
""<< std::endl;
578 this->Converged = l2_norm_full < this->RelativeConvergenceCriterion;
579 this->LastDifference = l2_norm_full;
581 assert (time_series.size() != 1u);
582 if (time_series.back() == 0.0)
584 std::cout <<
"Failed after successful convergence - give up this convergence test\n";
591 if (time_series.back() != 0.0)
594 this->PopulatedResult=
true;
600 if (!this->Converged)
602 UpdateConvergenceParameters();
605 delete p_cell_factory;
607 while (!GiveUpConvergence() && !this->Converged);
612 p_conv_info_file->close();
614 std::cout <<
"Results: " << std::endl;
619 std::cout << info_file.rdbuf();
634 unsigned num_ele_across =
SmallPow(2u, this->MeshNum+2);
637 std::cout<<
"================================================================================"<<std::endl;
638 std::cout<<
"Solving in " << DIM <<
"D\t";
639 std::cout<<
"Space step " << scaling <<
" cm (mesh " << this->MeshNum <<
")" <<
"\n";
640 std::cout<<
"PDE step " << this->PdeTimeStep <<
" ms" <<
"\t";
641 std::cout<<
"ODE step " << this->OdeTimeStep <<
" ms" <<
"\t";
650 switch (this->Stimulus)
653 std::cout<<
"Stimulus = Plane\n";
657 std::cout<<
"Stimulus = Ramped first quarter\n";
661 std::cout<<
"Stimulus = Neumann\n";
667 std::time( &rawtime );
668 std::cout << std::ctime(&rawtime);
669 std::cout << std::flush;
679 virtual void SetInitialConvergenceParameters()=0;
681 virtual void UpdateConvergenceParameters()=0;
683 virtual bool GiveUpConvergence()=0;
685 virtual double Abscissa()=0;
694 assert(this->PopulatedResult==
false);
695 assert(result.size()==0);
696 assert(times.size()==0);
bool GetUseAbsoluteTolerance() const
void SetOutputDirectory(const std::string &rOutputDirectory)
double SmallPow(double x, unsigned exponent)
boost::shared_ptr< ZeroStimulus > mpZeroStimulus
std::string GetAbsolutePath() const
boost::shared_ptr< AbstractIvpOdeSolver > mpSolver
bool SimulateFullActionPotential
double GetAbsoluteTolerance() const
std::vector< boost::shared_ptr< SimpleStimulus > > mpStimuli
static double GetElapsedTime()
double GetRelativeTolerance() const
AbstractCardiacCellInterface * CreateCardiacCellForTissueNode(Node< DIM > *pNode)
void SetSimulationDuration(double simulationDuration)
out_stream OpenOutputFile(const std::string &rFileName, std::ios_base::openmode mode=std::ios::out|std::ios::trunc) const
void SetExtracellularConductivities(const c_vector< double, 3 > &rExtraConductivities)
void Construct(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, unsigned meshRefinementNum, double meshWidth)
double CalculateActionPotentialDuration(const double percentage, unsigned globalNodeIndex)
virtual void PopulateStandardResult(std::vector< double > &result, std::vector< double > ×)
FileFinder FindFile(std::string leafName) const
std::string GetMessage() const
double ConductionVelocity
std::vector< double > GetUnlimitedDimensionValues()
double RelativeConvergenceCriterion
double CalculateConductionVelocity(unsigned globalNearNodeIndex, unsigned globalFarNodeIndex, const double euclideanDistance)
std::vector< double > GetVariableOverTime(const std::string &rVariableName, unsigned nodeIndex)
ChastePoint< SPACE_DIM > GetPoint() const
void Converge(std::string nameOfTest)
void SetIntracellularConductivities(const c_vector< double, 3 > &rIntraConductivities)
unsigned GetNumElements()
void SetMeshWidth(double meshWidth)
void SetOutputFilenamePrefix(const std::string &rOutputFilenamePrefix)
static HeartConfig * Instance()
RampedQuarterStimulusCellFactory(double meshWidth, unsigned numElemAcross, double fullStim=-1e7)
void SetOdePdeAndPrintingTimeSteps(double odeTimeStep, double pdeTimeStep, double printingTimeStep)