Chaste  Release::3.4
AbstractConvergenceTester.hpp
1 /*
2 
3 Copyright (c) 2005-2016, 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;
183  bool Converged;
184  StimulusType Stimulus;
188 
194  virtual void Converge(std::string nameOfTest)=0;
195 
197 };
198 
202 template<class CARDIAC_PROBLEM, unsigned DIM>
203 void SetConductivities(CARDIAC_PROBLEM& rCardiacProblem);
204 
205 template<unsigned DIM>
206 void SetConductivities(BidomainProblem<DIM>& rProblem)
207 {
208  c_vector<double, DIM> conductivities;
209  for (unsigned i=0; i<DIM; i++)
210  {
211  conductivities[i] = 1.75;
212  }
214 
215  for (unsigned i=0; i<DIM; i++)
216  {
217  conductivities[i] = 7.0;
218  }
220 }
221 
222 template<unsigned DIM>
223 void SetConductivities(MonodomainProblem<DIM>& rProblem)
224 {
225  c_vector<double, DIM> conductivities;
226  for (unsigned i=0; i<DIM; i++)
227  {
228  conductivities[i] = 1.75;
229  }
231 }
232 
237 template<class CELL, class CARDIAC_PROBLEM, unsigned DIM, unsigned PROBLEM_DIM>
239 {
240 public:
246  void Converge(std::string nameOfTest)
247  {
248  // Create the meshes on which the test will be based
249  const std::string mesh_dir = "ConvergenceMesh";
250  OutputFileHandler output_file_handler(mesh_dir);
251  ReplicatableVector voltage_replicated;
252 
253  unsigned file_num=0;
254 
255  // Create a file for storing conduction velocity and AP data and write the header
256  OutputFileHandler conv_info_handler("ConvergencePlots"+nameOfTest, false);
257  out_stream p_conv_info_file;
258  if (PetscTools::AmMaster())
259  {
260  std::cout << "=========================== Beginning Test...==================================\n";
261  p_conv_info_file = conv_info_handler.OpenOutputFile(nameOfTest+"_info.csv");
262  (*p_conv_info_file) << "#Abcisa\t"
263  << "l2-norm-full\t"
264  << "l2-norm-onset\t"
265  << "Max absolute err\t"
266  << "APD90_1st_quad\t"
267  << "APD90_3rd_quad\t"
268  << "Conduction velocity (relative diffs)" << std::endl;
269  }
271 
272  double prev_apd90_first_qn=0.0;
273  double prev_apd90_third_qn=0.0;
274  double prev_cond_velocity=0.0;
275  std::vector<double> prev_voltage;
276  std::vector<double> prev_times;
277  PopulateStandardResult(prev_voltage, prev_times);
278 
279  do
280  {
281  CuboidMeshConstructor<DIM> constructor;
282 
283  //If the printing time step is too fine, then simulations become I/O bound without much improvement in accuracy
284  double printing_step = this->PdeTimeStep;
285 #define COVERAGE_IGNORE
286  while (printing_step < 1.0e-4)
287  {
288  printing_step *= 2.0;
289  std::cout<<"Warning: PrintingTimeStep increased\n";
290  }
291 #undef COVERAGE_IGNORE
293 #define COVERAGE_IGNORE
295  {
297  }
298  else
299  {
301  }
302 #undef COVERAGE_IGNORE
303  HeartConfig::Instance()->SetOutputDirectory("Convergence"+nameOfTest);
305 
307  constructor.Construct(mesh, this->MeshNum, mMeshWidth);
308 
309  unsigned num_ele_across = SmallPow(2u, this->MeshNum+2); // number of elements in each dimension
310 
311  AbstractCardiacCellFactory<DIM>* p_cell_factory=NULL;
312 
313  switch (this->Stimulus)
314  {
315  case NEUMANN:
316  {
317  p_cell_factory = new ZeroStimulusCellFactory<CELL, DIM>();
318  break;
319  }
320  case PLANE:
321  {
322  if (this->UseAbsoluteStimulus)
323  {
324  #define COVERAGE_IGNORE
325  p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(0, this->AbsoluteStimulus, true);
326  #undef COVERAGE_IGNORE
327  }
328  else
329  {
330  p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(num_ele_across, constructor.GetWidth(), false, this->AbsoluteStimulus);
331  }
332  break;
333  }
334  case QUARTER:
335  {
337  p_cell_factory = new RampedQuarterStimulusCellFactory<CELL, DIM>(constructor.GetWidth(), num_ele_across, this->AbsoluteStimulus/10.0);
338  break;
339  }
340  default:
342  }
343 
344 
345  CARDIAC_PROBLEM cardiac_problem(p_cell_factory);
346  cardiac_problem.SetMesh(&mesh);
347 
348  // Calculate positions of nodes 1/4 and 3/4 through the mesh
349  unsigned third_quadrant_node;
350  unsigned first_quadrant_node;
351  switch(DIM)
352  {
353  case 1:
354  {
355  first_quadrant_node = (unsigned) (0.25*constructor.GetNumElements());
356  third_quadrant_node = (unsigned) (0.75*constructor.GetNumElements());
357  break;
358  }
359  case 2:
360  {
361  unsigned n= SmallPow (2u, this->MeshNum+2);
362  first_quadrant_node = (n+1)*(n/2)+ n/4 ;
363  third_quadrant_node = (n+1)*(n/2)+3*n/4 ;
364  break;
365  }
366  case 3:
367  {
368  const unsigned first_quadrant_nodes_3d[5]={61, 362, 2452, 17960, 137296};
369  const unsigned third_quadrant_nodes_3d[5]={63, 366, 2460, 17976, 137328};
370  assert(this->PdeTimeStep<5);
371  first_quadrant_node = first_quadrant_nodes_3d[this->MeshNum];
372  third_quadrant_node = third_quadrant_nodes_3d[this->MeshNum];
373  break;
374  }
375 
376  default:
378  }
379 
380  double mesh_width=constructor.GetWidth();
381 
382  // We only need the output of these two nodes
383  std::vector<unsigned> nodes_to_be_output;
384  nodes_to_be_output.push_back(first_quadrant_node);
385  nodes_to_be_output.push_back(third_quadrant_node);
386  cardiac_problem.SetOutputNodes(nodes_to_be_output);
387 
388  // The results of the tests were originally obtained with the following conductivity
389  // values. After implementing fibre orientation the defaults changed. Here we set
390  // the former ones to be used.
391  SetConductivities(cardiac_problem);
392 
393  cardiac_problem.Initialise();
394 
395  boost::shared_ptr<BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM> > p_bcc(new BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM>);
396  SimpleStimulus stim(NeumannStimulus, 0.5);
397  if (Stimulus==NEUMANN)
398  {
399 
401 
402  // get mesh
403  AbstractTetrahedralMesh<DIM, DIM> &r_mesh = cardiac_problem.rGetMesh();
404  // loop over boundary elements
406  iter = r_mesh.GetBoundaryElementIteratorBegin();
407  while (iter != r_mesh.GetBoundaryElementIteratorEnd())
408  {
409  double x = ((*iter)->CalculateCentroid())[0];
411  if (x*x<=1e-10)
412  {
413  p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim);
414  }
415  iter++;
416  }
417  // pass the bcc to the problem
418  cardiac_problem.SetBoundaryConditionsContainer(p_bcc);
419  }
420 
421  DisplayRun();
422  Timer::Reset();
424  //cardiac_problem.SetWriteInfo();
425 
426  try
427  {
428  cardiac_problem.Solve();
429  }
430  catch (Exception e)
431  {
432  WARNING("This run threw an exception. Check convergence results\n");
433  std::cout << e.GetMessage() << std::endl;
434  }
435 
436  if (PetscTools::AmMaster())
437  {
438  std::cout << "Time to solve = " << Timer::GetElapsedTime() << " seconds\n";
439  }
440 
441  OutputFileHandler results_handler("Convergence"+nameOfTest, false);
442  Hdf5DataReader results_reader = cardiac_problem.GetDataReader();
443 
444  {
445  std::vector<double> transmembrane_potential = results_reader.GetVariableOverTime("V", third_quadrant_node);
446  std::vector<double> time_series = results_reader.GetUnlimitedDimensionValues();
447 
448  OutputFileHandler plot_file_handler("ConvergencePlots"+nameOfTest, false);
449  if (PetscTools::AmMaster())
450  {
451  // Write out the time series for the node at third quadrant
452  {
453  std::stringstream plot_file_name_stream;
454  plot_file_name_stream<< nameOfTest << "_Third_quadrant_node_run_"<< file_num << ".csv";
455  out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
456  for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
457  {
458  (*p_plot_file) << time_series[data_point] << "\t" << transmembrane_potential[data_point] << "\n";
459  }
460  p_plot_file->close();
461  }
462  // Write time series for first quadrant node
463  {
464  std::vector<double> transmembrane_potential_1qd=results_reader.GetVariableOverTime("V", first_quadrant_node);
465  std::vector<double> time_series_1qd = results_reader.GetUnlimitedDimensionValues();
466  std::stringstream plot_file_name_stream;
467  plot_file_name_stream<< nameOfTest << "_First_quadrant_node_run_"<< file_num << ".csv";
468  out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
469  for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
470  {
471  (*p_plot_file) << time_series_1qd[data_point] << "\t" << transmembrane_potential_1qd[data_point] << "\n";
472  }
473  p_plot_file->close();
474  }
475  }
476  // calculate conduction velocity and APD90 error
477  PropagationPropertiesCalculator ppc(&results_reader);
478 
479  try
480  {
481  #define COVERAGE_IGNORE
483  {
484  Apd90FirstQn = ppc.CalculateActionPotentialDuration(90.0, first_quadrant_node);
485  Apd90ThirdQn = ppc.CalculateActionPotentialDuration(90.0, third_quadrant_node);
486  }
487  #undef COVERAGE_IGNORE
488  ConductionVelocity = ppc.CalculateConductionVelocity(first_quadrant_node,third_quadrant_node,0.5*mesh_width);
489  }
490  catch (Exception e)
491  {
492  #define COVERAGE_IGNORE
493  std::cout << "Warning - this run threw an exception in calculating propagation. Check convergence results\n";
494  std::cout << e.GetMessage() << std::endl;
495  #undef COVERAGE_IGNORE
496  }
497  double cond_velocity_error = 1e10;
498  double apd90_first_qn_error = 1e10;
499  double apd90_third_qn_error = 1e10;
500 
501  if (this->PopulatedResult)
502  {
503  if (prev_cond_velocity != 0.0)
504  {
505  cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity;
506  }
507 #define COVERAGE_IGNORE
508  if (prev_apd90_first_qn != 0.0)
509  {
510  apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn;
511  }
512  if (prev_apd90_third_qn != 0.0)
513  {
514  apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn;
515  }
516  if (apd90_first_qn_error == 0.0)
517  {
518  apd90_first_qn_error = DBL_EPSILON; //Avoid log zero on plot
519  }
520  if (apd90_third_qn_error == 0.0)
521  {
522  apd90_third_qn_error = DBL_EPSILON; //Avoid log zero on plot
523  }
524 #undef COVERAGE_IGNORE
525  if (cond_velocity_error == 0.0)
526  {
527  cond_velocity_error = DBL_EPSILON; //Avoid log zero on plot
528  }
529  }
530 
531  prev_cond_velocity = ConductionVelocity;
532  prev_apd90_first_qn = Apd90FirstQn;
533  prev_apd90_third_qn = Apd90ThirdQn;
534 
535  // calculate l2norm
536  double max_abs_error = 0;
537  double sum_sq_abs_error =0;
538  double sum_sq_prev_voltage = 0;
539  double sum_sq_abs_error_full =0;
540  double sum_sq_prev_voltage_full = 0;
541  if (this->PopulatedResult)
542  {
543  //If the PDE step is varying then we'll have twice as much data now as we use to have
544 
545  unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1);
546  assert (time_factor == 1 || time_factor == 2 || time_factor == 8);
547  //Iterate over the shorter time series data
548  for (unsigned data_point = 0; data_point<prev_times.size(); data_point++)
549  {
550  unsigned this_data_point=time_factor*data_point;
551 
552  assert(time_series[this_data_point] == prev_times[data_point]);
553  double abs_error = fabs(transmembrane_potential[this_data_point]-prev_voltage[data_point]);
554  max_abs_error = (abs_error > max_abs_error) ? abs_error : max_abs_error;
555  //Only do resolve the upstroke...
556  sum_sq_abs_error_full += abs_error*abs_error;
557  sum_sq_prev_voltage_full += prev_voltage[data_point] * prev_voltage[data_point];
558  if (time_series[this_data_point] <= 8.0)
559  {
560  //In most regular cases we always do this, since the simulation stops at ms
561  sum_sq_abs_error += abs_error*abs_error;
562  sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point];
563  }
564  }
565 
566  }
567  if (!this->PopulatedResult || !FixedResult)
568  {
569  prev_voltage = transmembrane_potential;
570  prev_times = time_series;
571  }
572 
573  if (this->PopulatedResult)
574  {
575  double l2_norm_upstroke = sqrt(sum_sq_abs_error/sum_sq_prev_voltage);
576  double l2_norm_full = sqrt(sum_sq_abs_error_full/sum_sq_prev_voltage_full);
577 
578  if (PetscTools::AmMaster())
579  {
580  (*p_conv_info_file) << std::setprecision(8)
581  << Abscissa() << "\t"
582  << l2_norm_full << "\t"
583  << l2_norm_upstroke << "\t"
584  << max_abs_error << "\t"
585  << Apd90FirstQn <<" "<< apd90_first_qn_error <<""<< "\t"
586  << Apd90ThirdQn <<" "<< apd90_third_qn_error <<""<< "\t"
587  << ConductionVelocity <<" "<< cond_velocity_error <<""<< std::endl;
588  }
589  // convergence criterion
590  this->Converged = l2_norm_full < this->RelativeConvergenceCriterion;
591  this->LastDifference = l2_norm_full;
592 #define COVERAGE_IGNORE
593  assert (time_series.size() != 1u);
594  if (time_series.back() == 0.0)
595  {
596  std::cout << "Failed after successful convergence - give up this convergence test\n";
597  break;
598  }
599 #undef COVERAGE_IGNORE
600 
601  }
602 
603  if ( time_series.back() != 0.0)
604  {
605  // Simulation ran to completion
606  this->PopulatedResult=true;
607 
608  }
609  }
610 
611  // Get ready for the next test by halving the time step
612  if (!this->Converged)
613  {
615  file_num++;
616  }
617  delete p_cell_factory;
618  }
619  while (!GiveUpConvergence() && !this->Converged);
620 
621 
622  if (PetscTools::AmMaster())
623  {
624  p_conv_info_file->close();
625 
626  std::cout << "Results: " << std::endl;
627  FileFinder info_finder = conv_info_handler.FindFile(nameOfTest + "_info.csv");
628  std::ifstream info_file(info_finder.GetAbsolutePath().c_str());
629  if (info_file)
630  {
631  std::cout << info_file.rdbuf();
632  info_file.close();
633  }
634  }
635 
636  }
637 
638  void DisplayRun()
639  {
640  if (!PetscTools::AmMaster())
641  {
642  return; //Only master displays this
643  }
644  unsigned num_ele_across = SmallPow(2u, this->MeshNum+2);// number of elements in each dimension
645  double scaling = mMeshWidth/(double) num_ele_across;
646 
647  std::cout<<"================================================================================"<<std::endl;
648  std::cout<<"Solving in " << DIM << "D\t";
649  std::cout<<"Space step " << scaling << " cm (mesh " << this->MeshNum << ")" << "\n";
650  std::cout<<"PDE step " << this->PdeTimeStep << " ms" << "\t";
651  std::cout<<"ODE step " << this->OdeTimeStep << " ms" << "\t";
653  {
654  std::cout<<"KSP absolute "<<HeartConfig::Instance()->GetAbsoluteTolerance()<<"\t";
655  }
656  else
657  {
658  std::cout<<"KSP relative "<<HeartConfig::Instance()->GetRelativeTolerance()<<"\t";
659  }
660  switch (this->Stimulus)
661  {
662  case PLANE:
663  std::cout<<"Stimulus = Plane\n";
664  break;
665 
666  case QUARTER:
667  std::cout<<"Stimulus = Ramped first quarter\n";
668  break;
669 
670  case NEUMANN:
671  std::cout<<"Stimulus = Neumann\n";
672  break;
673 
674  }
675  // Keep track of what Nightly things are doing
676  std::time_t rawtime;
677  std::time( &rawtime );
678  std::cout << std::ctime(&rawtime);
681  if (this->UseAbsoluteStimulus)
682  {
683  #define COVERAGE_IGNORE
684  std::cout<<"Using absolute stimulus of "<<this->AbsoluteStimulus<<std::endl;
685  #undef COVERAGE_IGNORE
686  }
687  std::cout << std::flush;
688  //HeartEventHandler::Headings();
689  //HeartEventHandler::Report();
690 
691  }
692 
693 public:
694  virtual ~AbstractConvergenceTester() {}
695 
697  virtual void SetInitialConvergenceParameters()=0;
699  virtual void UpdateConvergenceParameters()=0;
701  virtual bool GiveUpConvergence()=0;
703  virtual double Abscissa()=0;
710  virtual void PopulateStandardResult(std::vector<double> &result, std::vector<double> &times)
711  {
712  assert(this->PopulatedResult==false);
713  assert(result.size()==0);
714  assert(times.size()==0);
715  }
716 
720  bool IsConverged()
721  {
722  return Converged;
723  }
724 
728  void SetMeshWidth(double meshWidth)
729  {
730  mMeshWidth=meshWidth;
731  }
732 };
733 
734 #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
virtual void Converge(std::string nameOfTest)=0
virtual double Abscissa()=0
virtual bool GiveUpConvergence()=0
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:87
std::vector< double > GetUnlimitedDimensionValues()
virtual void SetInitialConvergenceParameters()=0
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:134
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()
virtual void UpdateConvergenceParameters()=0
RampedQuarterStimulusCellFactory(double meshWidth, unsigned numElemAcross, double fullStim=-1e7)
void SetOdePdeAndPrintingTimeSteps(double odeTimeStep, double pdeTimeStep, double printingTimeStep)