Chaste  Release::2017.1
AbstractConvergenceTester.hpp
1 /*
2 
3 Copyright (c) 2005-2017, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 
37 #ifndef ABSTRACTCONVERGENCETESTER_HPP_
38 #define ABSTRACTCONVERGENCETESTER_HPP_
39 
40 #include "BidomainProblem.hpp"
41 #include "MonodomainProblem.hpp"
42 
43 #include <petscvec.h>
44 #include <vector>
45 #include <iostream>
46 #include <fstream>
47 #include <cmath>
48 #include <ctime>
49 
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"
63 
64 #include "Warnings.hpp"
65 #include "Timer.hpp"
66 
67 typedef enum StimulusType_
68 {
69  PLANE=0,
70  QUARTER,
71  NEUMANN
72 } StimulusType;
73 
78 template <class CELL, unsigned DIM>
80 {
81 private:
83  std::vector< boost::shared_ptr<SimpleStimulus> > mpStimuli;
85  double mMeshWidth;
87  double mStepSize;
91  unsigned mLevels;
92 public:
93 
100  RampedQuarterStimulusCellFactory(double meshWidth, unsigned numElemAcross, double fullStim=-1e7)
102  mMeshWidth(meshWidth),
103  mStepSize(meshWidth/numElemAcross),
104  mLevels(numElemAcross/4)
105  {
106  assert(numElemAcross%4 == 0); //numElemAcross is supposed to be a multiple of 4
107 
108  for (unsigned level=0; level<mLevels; level++)
109  {
110  double this_stim = fullStim - (level*fullStim)/mLevels;
111  //this_stim is full_stim at the zero level and would be zero at level=mLevels
112  mpStimuli.push_back((boost::shared_ptr<SimpleStimulus>)new SimpleStimulus(this_stim, 0.5));
113  }
114  }
115 
116 
123  {
124  double x = pNode->GetPoint()[0];
125  double d_level = x/mStepSize;
126  unsigned level = (unsigned) d_level;
127  assert(fabs(level-d_level) < DBL_MAX); //x ought to really be a multiple of the step size
128 
129  if (level < mLevels)
130  {
131  return new CELL(this->mpSolver, this->mpStimuli[level]);
132  }
133  else
134  {
135  return new CELL(this->mpSolver, this->mpZeroStimulus);
136  }
137  }
138 };
139 
140 
146 {
147 protected:
149  double mMeshWidth;
150 public:
152  double OdeTimeStep;
154  double PdeTimeStep;
159  unsigned MeshNum;
161  double LastDifference;
162  double Apd90FirstQn;
163  double Apd90ThirdQn;
173 
180  bool Converged;
181  StimulusType Stimulus;
185 
191  virtual void Converge(std::string nameOfTest)=0;
192 
194 };
195 
199 template<class CARDIAC_PROBLEM, unsigned DIM>
200 void SetConductivities(CARDIAC_PROBLEM& rCardiacProblem);
201 
202 template<unsigned DIM>
203 void SetConductivities(BidomainProblem<DIM>& rProblem)
204 {
205  c_vector<double, DIM> conductivities;
206  for (unsigned i=0; i<DIM; i++)
207  {
208  conductivities[i] = 1.75;
209  }
211 
212  for (unsigned i=0; i<DIM; i++)
213  {
214  conductivities[i] = 7.0;
215  }
217 }
218 
219 template<unsigned DIM>
220 void SetConductivities(MonodomainProblem<DIM>& rProblem)
221 {
222  c_vector<double, DIM> conductivities;
223  for (unsigned i=0; i<DIM; i++)
224  {
225  conductivities[i] = 1.75;
226  }
228 }
229 
234 template<class CELL, class CARDIAC_PROBLEM, unsigned DIM, unsigned PROBLEM_DIM>
236 {
237 public:
243  void Converge(std::string nameOfTest)
244  {
245  // Create the meshes on which the test will be based
246  const std::string mesh_dir = "ConvergenceMesh";
247  OutputFileHandler output_file_handler(mesh_dir);
248  ReplicatableVector voltage_replicated;
249 
250  unsigned file_num=0;
251 
252  // Create a file for storing conduction velocity and AP data and write the header
253  OutputFileHandler conv_info_handler("ConvergencePlots"+nameOfTest, false);
254  out_stream p_conv_info_file;
255  if (PetscTools::AmMaster())
256  {
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"
260  << "l2-norm-full\t"
261  << "l2-norm-onset\t"
262  << "Max absolute err\t"
263  << "APD90_1st_quad\t"
264  << "APD90_3rd_quad\t"
265  << "Conduction velocity (relative diffs)" << std::endl;
266  }
267  SetInitialConvergenceParameters();
268 
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);
275 
276  do
277  {
278  CuboidMeshConstructor<DIM> constructor;
279 
280  //If the printing time step is too fine, then simulations become I/O bound without much improvement in accuracy
281  double printing_step = this->PdeTimeStep;
282 // LCOV_EXCL_START
283  while (printing_step < 1.0e-4)
284  {
285  printing_step *= 2.0;
286  std::cout<<"Warning: PrintingTimeStep increased\n";
287  }
288 // LCOV_EXCL_STOP
289  HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(this->OdeTimeStep, this->PdeTimeStep, printing_step);
290 // LCOV_EXCL_START
291  if (SimulateFullActionPotential)
292  {
294  }
295  else
296  {
298  }
299 // LCOV_EXCL_STOP
300  HeartConfig::Instance()->SetOutputDirectory("Convergence"+nameOfTest);
302 
304  constructor.Construct(mesh, this->MeshNum, mMeshWidth);
305 
306  unsigned num_ele_across = SmallPow(2u, this->MeshNum+2); // number of elements in each dimension
307 
308  AbstractCardiacCellFactory<DIM>* p_cell_factory=NULL;
309 
310  switch (this->Stimulus)
311  {
312  case NEUMANN:
313  {
314  p_cell_factory = new ZeroStimulusCellFactory<CELL, DIM>();
315  break;
316  }
317  case PLANE:
318  {
319  p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(num_ele_across, constructor.GetWidth(), this->AbsoluteStimulus);
320  break;
321  }
322  case QUARTER:
323  {
325  p_cell_factory = new RampedQuarterStimulusCellFactory<CELL, DIM>(constructor.GetWidth(), num_ele_across, this->AbsoluteStimulus/10.0);
326  break;
327  }
328  default:
330  }
331 
332 
333  CARDIAC_PROBLEM cardiac_problem(p_cell_factory);
334  cardiac_problem.SetMesh(&mesh);
335 
336  // Calculate positions of nodes 1/4 and 3/4 through the mesh
337  unsigned third_quadrant_node;
338  unsigned first_quadrant_node;
339  switch(DIM)
340  {
341  case 1:
342  {
343  first_quadrant_node = (unsigned) (0.25*constructor.GetNumElements());
344  third_quadrant_node = (unsigned) (0.75*constructor.GetNumElements());
345  break;
346  }
347  case 2:
348  {
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 ;
352  break;
353  }
354  case 3:
355  {
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];
361  break;
362  }
363 
364  default:
366  }
367 
368  double mesh_width=constructor.GetWidth();
369 
370  // We only need the output of these two nodes
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);
375 
376  // The results of the tests were originally obtained with the following conductivity
377  // values. After implementing fibre orientation the defaults changed. Here we set
378  // the former ones to be used.
379  SetConductivities(cardiac_problem);
380 
381  cardiac_problem.Initialise();
382 
383  boost::shared_ptr<BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM> > p_bcc(new BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM>);
384  SimpleStimulus stim(NeumannStimulus, 0.5);
385  if (Stimulus==NEUMANN)
386  {
387 
389 
390  // get mesh
391  AbstractTetrahedralMesh<DIM, DIM> &r_mesh = cardiac_problem.rGetMesh();
392  // loop over boundary elements
394  iter = r_mesh.GetBoundaryElementIteratorBegin();
395  while (iter != r_mesh.GetBoundaryElementIteratorEnd())
396  {
397  double x = ((*iter)->CalculateCentroid())[0];
399  if (x*x<=1e-10)
400  {
401  p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim);
402  }
403  iter++;
404  }
405  // pass the bcc to the problem
406  cardiac_problem.SetBoundaryConditionsContainer(p_bcc);
407  }
408 
409  DisplayRun();
410  Timer::Reset();
412  //cardiac_problem.SetWriteInfo();
413 
414  try
415  {
416  cardiac_problem.Solve();
417  }
418  catch (Exception e)
419  {
420  WARNING("This run threw an exception. Check convergence results\n");
421  std::cout << e.GetMessage() << std::endl;
422  }
423 
424  if (PetscTools::AmMaster())
425  {
426  std::cout << "Time to solve = " << Timer::GetElapsedTime() << " seconds\n";
427  }
428 
429  OutputFileHandler results_handler("Convergence"+nameOfTest, false);
430  Hdf5DataReader results_reader = cardiac_problem.GetDataReader();
431 
432  {
433  std::vector<double> transmembrane_potential = results_reader.GetVariableOverTime("V", third_quadrant_node);
434  std::vector<double> time_series = results_reader.GetUnlimitedDimensionValues();
435 
436  OutputFileHandler plot_file_handler("ConvergencePlots"+nameOfTest, false);
437  if (PetscTools::AmMaster())
438  {
439  // Write out the time series for the node at third quadrant
440  {
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++)
445  {
446  (*p_plot_file) << time_series[data_point] << "\t" << transmembrane_potential[data_point] << "\n";
447  }
448  p_plot_file->close();
449  }
450  // Write time series for first quadrant node
451  {
452  std::vector<double> transmembrane_potential_1qd=results_reader.GetVariableOverTime("V", first_quadrant_node);
453  std::vector<double> time_series_1qd = results_reader.GetUnlimitedDimensionValues();
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++)
458  {
459  (*p_plot_file) << time_series_1qd[data_point] << "\t" << transmembrane_potential_1qd[data_point] << "\n";
460  }
461  p_plot_file->close();
462  }
463  }
464  // calculate conduction velocity and APD90 error
465  PropagationPropertiesCalculator ppc(&results_reader);
466 
467  try
468  {
469  // LCOV_EXCL_START
470  if (SimulateFullActionPotential)
471  {
472  Apd90FirstQn = ppc.CalculateActionPotentialDuration(90.0, first_quadrant_node);
473  Apd90ThirdQn = ppc.CalculateActionPotentialDuration(90.0, third_quadrant_node);
474  }
475  // LCOV_EXCL_STOP
476  ConductionVelocity = ppc.CalculateConductionVelocity(first_quadrant_node,third_quadrant_node,0.5*mesh_width);
477  }
478  // LCOV_EXCL_START
479  catch (Exception e)
480  {
481  std::cout << "Warning - this run threw an exception in calculating propagation. Check convergence results\n";
482  std::cout << e.GetMessage() << std::endl;
483  }
484  // LCOV_EXCL_STOP
485  double cond_velocity_error = 1e10;
486  double apd90_first_qn_error = 1e10;
487  double apd90_third_qn_error = 1e10;
488 
489  if (this->PopulatedResult)
490  {
491  if (prev_cond_velocity != 0.0)
492  {
493  cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity;
494  }
495 // LCOV_EXCL_START
496  if (prev_apd90_first_qn != 0.0)
497  {
498  apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn;
499  }
500  if (prev_apd90_third_qn != 0.0)
501  {
502  apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn;
503  }
504  if (apd90_first_qn_error == 0.0)
505  {
506  apd90_first_qn_error = DBL_EPSILON; //Avoid log zero on plot
507  }
508  if (apd90_third_qn_error == 0.0)
509  {
510  apd90_third_qn_error = DBL_EPSILON; //Avoid log zero on plot
511  }
512 // LCOV_EXCL_STOP
513  if (cond_velocity_error == 0.0)
514  {
515  cond_velocity_error = DBL_EPSILON; //Avoid log zero on plot
516  }
517  }
518 
519  prev_cond_velocity = ConductionVelocity;
520  prev_apd90_first_qn = Apd90FirstQn;
521  prev_apd90_third_qn = Apd90ThirdQn;
522 
523  // calculate l2norm
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)
530  {
531  //If the PDE step is varying then we'll have twice as much data now as we use to have
532 
533  unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1);
534  assert (time_factor == 1 || time_factor == 2 || time_factor == 8);
535  //Iterate over the shorter time series data
536  for (unsigned data_point = 0; data_point<prev_times.size(); data_point++)
537  {
538  unsigned this_data_point=time_factor*data_point;
539 
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;
543  //Only do resolve the upstroke...
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)
547  {
548  //In most regular cases we always do this, since the simulation stops at ms
549  sum_sq_abs_error += abs_error*abs_error;
550  sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point];
551  }
552  }
553 
554  }
555  if (!this->PopulatedResult || !FixedResult)
556  {
557  prev_voltage = transmembrane_potential;
558  prev_times = time_series;
559  }
560 
561  if (this->PopulatedResult)
562  {
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);
565 
566  if (PetscTools::AmMaster())
567  {
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;
576  }
577  // convergence criterion
578  this->Converged = l2_norm_full < this->RelativeConvergenceCriterion;
579  this->LastDifference = l2_norm_full;
580 // LCOV_EXCL_START
581  assert (time_series.size() != 1u);
582  if (time_series.back() == 0.0)
583  {
584  std::cout << "Failed after successful convergence - give up this convergence test\n";
585  break;
586  }
587 // LCOV_EXCL_STOP
588 
589  }
590 
591  if (time_series.back() != 0.0)
592  {
593  // Simulation ran to completion
594  this->PopulatedResult=true;
595 
596  }
597  }
598 
599  // Get ready for the next test by halving the time step
600  if (!this->Converged)
601  {
602  UpdateConvergenceParameters();
603  file_num++;
604  }
605  delete p_cell_factory;
606  }
607  while (!GiveUpConvergence() && !this->Converged);
608 
609 
610  if (PetscTools::AmMaster())
611  {
612  p_conv_info_file->close();
613 
614  std::cout << "Results: " << std::endl;
615  FileFinder info_finder = conv_info_handler.FindFile(nameOfTest + "_info.csv");
616  std::ifstream info_file(info_finder.GetAbsolutePath().c_str());
617  if (info_file)
618  {
619  std::cout << info_file.rdbuf();
620  info_file.close();
621  }
622  }
623  }
624 
628  void DisplayRun()
629  {
630  if (!PetscTools::AmMaster())
631  {
632  return; //Only master displays this
633  }
634  unsigned num_ele_across = SmallPow(2u, this->MeshNum+2);// number of elements in each dimension
635  double scaling = mMeshWidth/(double) num_ele_across;
636 
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";
643  {
644  std::cout<<"KSP absolute "<<HeartConfig::Instance()->GetAbsoluteTolerance()<<"\t";
645  }
646  else
647  {
648  std::cout<<"KSP relative "<<HeartConfig::Instance()->GetRelativeTolerance()<<"\t";
649  }
650  switch (this->Stimulus)
651  {
652  case PLANE:
653  std::cout<<"Stimulus = Plane\n";
654  break;
655 
656  case QUARTER:
657  std::cout<<"Stimulus = Ramped first quarter\n";
658  break;
659 
660  case NEUMANN:
661  std::cout<<"Stimulus = Neumann\n";
662  break;
663 
664  }
665  // Keep track of what Nightly things are doing
666  std::time_t rawtime;
667  std::time( &rawtime );
668  std::cout << std::ctime(&rawtime);
669  std::cout << std::flush;
670  //HeartEventHandler::Headings();
671  //HeartEventHandler::Report();
672 
673  }
674 
675 public:
676  virtual ~AbstractConvergenceTester() {}
677 
679  virtual void SetInitialConvergenceParameters()=0;
681  virtual void UpdateConvergenceParameters()=0;
683  virtual bool GiveUpConvergence()=0;
685  virtual double Abscissa()=0;
692  virtual void PopulateStandardResult(std::vector<double> &result, std::vector<double> &times)
693  {
694  assert(this->PopulatedResult==false);
695  assert(result.size()==0);
696  assert(times.size()==0);
697  }
698 
702  bool IsConverged()
703  {
704  return Converged;
705  }
706 
710  void SetMeshWidth(double meshWidth)
711  {
712  mMeshWidth=meshWidth;
713  }
714 };
715 
716 #endif /*ABSTRACTCONVERGENCETESTER_HPP_*/
bool GetUseAbsoluteTolerance() const
Definition: Node.hpp:58
void SetOutputDirectory(const std::string &rOutputDirectory)
double SmallPow(double x, unsigned exponent)
boost::shared_ptr< ZeroStimulus > mpZeroStimulus
std::string GetAbsolutePath() const
Definition: FileFinder.cpp:221
boost::shared_ptr< AbstractIvpOdeSolver > mpSolver
static bool AmMaster()
Definition: PetscTools.cpp:120
double GetAbsoluteTolerance() const
std::vector< boost::shared_ptr< SimpleStimulus > > mpStimuli
#define NEVER_REACHED
Definition: Exception.hpp:206
static double GetElapsedTime()
Definition: Timer.cpp:54
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 > &times)
FileFinder FindFile(std::string leafName) const
std::string GetMessage() const
Definition: Exception.cpp:83
std::vector< double > GetUnlimitedDimensionValues()
double CalculateConductionVelocity(unsigned globalNearNodeIndex, unsigned globalFarNodeIndex, const double euclideanDistance)
std::vector< double > GetVariableOverTime(const std::string &rVariableName, unsigned nodeIndex)
ChastePoint< SPACE_DIM > GetPoint() const
Definition: Node.cpp:133
void Converge(std::string nameOfTest)
void SetIntracellularConductivities(const c_vector< double, 3 > &rIntraConductivities)
static void Reset()
Definition: Timer.cpp:44
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)