Chaste Release::3.1
AbstractConvergenceTester.hpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 
00037 #ifndef ABSTRACTCONVERGENCETESTER_HPP_
00038 #define ABSTRACTCONVERGENCETESTER_HPP_
00039 
00040 #include "BidomainProblem.hpp"
00041 #include "MonodomainProblem.hpp"
00042 
00043 #include <petscvec.h>
00044 #include <vector>
00045 #include <iostream>
00046 #include <fstream>
00047 #include <cmath>
00048 
00049 #include "AbstractTetrahedralMesh.hpp"
00050 #include "TrianglesMeshReader.hpp"
00051 #include "AbstractCardiacCellFactory.hpp"
00052 #include "OutputFileHandler.hpp"
00053 #include "TrianglesMeshWriter.hpp"
00054 #include "PropagationPropertiesCalculator.hpp"
00055 #include "Hdf5DataReader.hpp"
00056 #include "GeneralPlaneStimulusCellFactory.hpp"
00057 #include "CuboidMeshConstructor.hpp"
00058 #include "ZeroStimulusCellFactory.hpp"
00059 #include "SimpleStimulus.hpp"
00060 #include "ConstBoundaryCondition.hpp"
00061 #include "StimulusBoundaryCondition.hpp"
00062 
00063 #include "Warnings.hpp"
00064 
00065 typedef enum StimulusType_
00066 {
00067     PLANE=0,
00068     QUARTER,
00069     NEUMANN
00070 } StimulusType;
00071 
00076 template <class CELL, unsigned DIM>
00077 class RampedQuarterStimulusCellFactory : public AbstractCardiacCellFactory<DIM>
00078 {
00079 private:
00081     std::vector< boost::shared_ptr<SimpleStimulus> > mpStimuli;
00083     double mMeshWidth;
00085     double mStepSize;
00089     unsigned mLevels;
00090 public:
00091 
00098     RampedQuarterStimulusCellFactory(double meshWidth, unsigned numElemAcross, double fullStim=-1e7)
00099         : AbstractCardiacCellFactory<DIM>(),
00100           mMeshWidth(meshWidth),
00101           mStepSize(meshWidth/numElemAcross),
00102           mLevels(numElemAcross/4)
00103     {
00104         assert(numElemAcross%4 == 0); //numElemAcross is supposed to be a multiple of 4
00105 
00106         for (unsigned level=0; level<mLevels; level++)
00107         {
00108             double this_stim = fullStim - (level*fullStim)/mLevels;
00109             //this_stim is full_stim at the zero level and would be zero at level=mLevels
00110             mpStimuli.push_back((boost::shared_ptr<SimpleStimulus>)new SimpleStimulus(this_stim, 0.5));
00111         }
00112     }
00113 
00114 
00120     AbstractCardiacCellInterface* CreateCardiacCellForTissueNode(unsigned node)
00121     {
00122         double x = this->GetMesh()->GetNode(node)->GetPoint()[0];
00123         double d_level = x/mStepSize;
00124         unsigned level = (unsigned) d_level;
00125         assert(fabs(level-d_level) < DBL_MAX); //x ought to really be a multiple of the step size
00126 
00127         if (level < mLevels)
00128         {
00129             return new CELL(this->mpSolver, this->mpStimuli[level]);
00130         }
00131         else
00132         {
00133             return new CELL(this->mpSolver, this->mpZeroStimulus);
00134         }
00135     }
00136 };
00137 
00138 
00143 class AbstractUntemplatedConvergenceTester
00144 {
00145 protected:
00147     double mMeshWidth;
00148 public:
00150     double OdeTimeStep;
00152     double PdeTimeStep;
00157     unsigned MeshNum;
00158     double RelativeConvergenceCriterion; 
00159     double LastDifference; 
00160     double Apd90FirstQn; 
00161     double Apd90ThirdQn; 
00162     double ConductionVelocity;  
00166     bool PopulatedResult;
00170     bool FixedResult;
00174     bool UseAbsoluteStimulus;
00179     double AbsoluteStimulus;
00180     bool SimulateFullActionPotential; 
00181     bool Converged; 
00182     StimulusType Stimulus; 
00183     double NeumannStimulus; 
00185     AbstractUntemplatedConvergenceTester();
00186 
00192     virtual void Converge(std::string nameOfTest)=0;
00193 
00194     virtual ~AbstractUntemplatedConvergenceTester();
00195 };
00196 
00200 template<class CARDIAC_PROBLEM, unsigned DIM>
00201 void SetConductivities(CARDIAC_PROBLEM& rCardiacProblem);
00202 
00203 template<unsigned DIM>
00204 void SetConductivities(BidomainProblem<DIM>& rProblem)
00205 {
00206     c_vector<double, DIM> conductivities;
00207     for (unsigned i=0; i<DIM; i++)
00208     {
00209         conductivities[i] = 1.75;
00210     }
00211     HeartConfig::Instance()->SetIntracellularConductivities(conductivities);
00212 
00213     for (unsigned i=0; i<DIM; i++)
00214     {
00215         conductivities[i] = 7.0;
00216     }
00217     HeartConfig::Instance()->SetExtracellularConductivities(conductivities);
00218 }
00219 
00220 template<unsigned DIM>
00221 void SetConductivities(MonodomainProblem<DIM>& rProblem)
00222 {
00223     c_vector<double, DIM> conductivities;
00224     for (unsigned i=0; i<DIM; i++)
00225     {
00226         conductivities[i] = 1.75;
00227     }
00228     HeartConfig::Instance()->SetIntracellularConductivities(conductivities);
00229 }
00230 
00235 template<class CELL, class CARDIAC_PROBLEM, unsigned DIM, unsigned PROBLEM_DIM>
00236 class AbstractConvergenceTester : public AbstractUntemplatedConvergenceTester
00237 {
00238 public:
00243     void Converge(std::string nameOfTest)
00244     {
00245         std::cout << "=========================== Beginning Test...==================================\n";
00246         // Create the meshes on which the test will be based
00247         const std::string mesh_dir = "ConvergenceMesh";
00248         OutputFileHandler output_file_handler(mesh_dir);
00249         ReplicatableVector voltage_replicated;
00250 
00251         unsigned file_num=0;
00252 
00253         // Create a file for storing conduction velocity and AP data and write the header
00254         OutputFileHandler conv_info_handler("ConvergencePlots", false);
00255         out_stream p_conv_info_file;
00256         if (PetscTools::AmMaster())
00257         {
00258             p_conv_info_file = conv_info_handler.OpenOutputFile(nameOfTest+"_info.csv");
00259             (*p_conv_info_file) << "#Abcisa\t"
00260                                 << "l2-norm-full\t"
00261                                 << "l2-norm-onset\t"
00262                                 << "Max absolute err\t"
00263                                 << "APD90_1st_quad\t"
00264                                 << "APD90_3rd_quad\t"
00265                                 << "Conduction velocity (relative diffs)" << std::endl;
00266         }
00267         SetInitialConvergenceParameters();
00268 
00269         double prev_apd90_first_qn=0.0;
00270         double prev_apd90_third_qn=0.0;
00271         double prev_cond_velocity=0.0;
00272         std::vector<double> prev_voltage;
00273         std::vector<double> prev_times;
00274         PopulateStandardResult(prev_voltage, prev_times);
00275 
00276         do
00277         {
00278             CuboidMeshConstructor<DIM> constructor;
00279 
00280             //If the printing time step is too fine, then simulations become I/O bound without much improvement in accuracy
00281             double printing_step = this->PdeTimeStep;
00282 #define COVERAGE_IGNORE
00283             while (printing_step < 1.0e-4)
00284             {
00285                 printing_step *= 2.0;
00286                 std::cout<<"Warning: PrintingTimeStep increased\n";
00287             }
00288 #undef COVERAGE_IGNORE
00289             HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(this->OdeTimeStep, this->PdeTimeStep, printing_step);
00290 #define COVERAGE_IGNORE
00291             if (SimulateFullActionPotential)
00292             {
00293                 HeartConfig::Instance()->SetSimulationDuration(400.0);
00294             }
00295             else
00296             {
00297                 HeartConfig::Instance()->SetSimulationDuration(8.0);
00298             }
00299 #undef COVERAGE_IGNORE
00300             HeartConfig::Instance()->SetOutputDirectory("Convergence");
00301             HeartConfig::Instance()->SetOutputFilenamePrefix("Results");
00302 
00303             DistributedTetrahedralMesh<DIM, DIM> mesh;
00304             constructor.Construct(mesh, this->MeshNum, mMeshWidth);
00305 
00306             unsigned num_ele_across = (unsigned) SmallPow(2, this->MeshNum+2); // number of elements in each dimension
00307 
00308             AbstractCardiacCellFactory<DIM>* p_cell_factory=NULL;
00309 
00310             switch (this->Stimulus)
00311             {
00312                 case NEUMANN:
00313                 {
00314                     p_cell_factory = new ZeroStimulusCellFactory<CELL, DIM>();
00315                     break;
00316                 }
00317                 case PLANE:
00318                 {
00319                     if (this->UseAbsoluteStimulus)
00320                     {
00321                         #define COVERAGE_IGNORE
00322                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(0, this->AbsoluteStimulus, true);
00323                         #undef COVERAGE_IGNORE
00324                     }
00325                     else
00326                     {
00327                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(num_ele_across, constructor.GetWidth(), false, this->AbsoluteStimulus);
00328                     }
00329                     break;
00330                 }
00331                 case QUARTER:
00332                 {
00334                     p_cell_factory = new RampedQuarterStimulusCellFactory<CELL, DIM>(constructor.GetWidth(), num_ele_across, this->AbsoluteStimulus/10.0);
00335                     break;
00336                 }
00337             }
00338 
00339 
00340             CARDIAC_PROBLEM cardiac_problem(p_cell_factory);
00341             cardiac_problem.SetMesh(&mesh);
00342 
00343             // Calculate positions of nodes 1/4 and 3/4 through the mesh
00344             unsigned third_quadrant_node;
00345             unsigned first_quadrant_node;
00346             switch(DIM)
00347             {
00348                 case 1:
00349                 {
00350                     first_quadrant_node = (unsigned) (0.25*constructor.GetNumElements());
00351                     third_quadrant_node = (unsigned) (0.75*constructor.GetNumElements());
00352                     break;
00353                 }
00354                 case 2:
00355                 {
00356                     unsigned n= (unsigned) SmallPow (2, this->MeshNum+2);
00357                     first_quadrant_node =   (n+1)*(n/2)+  n/4 ;
00358                     third_quadrant_node =   (n+1)*(n/2)+3*n/4 ;
00359                     break;
00360                 }
00361                 case 3:
00362                 {
00363                     const unsigned first_quadrant_nodes_3d[5]={61, 362, 2452, 17960, 137296};
00364                     const unsigned third_quadrant_nodes_3d[5]={63, 366, 2460, 17976, 137328};
00365                     assert(this->PdeTimeStep<5);
00366                     first_quadrant_node = first_quadrant_nodes_3d[this->MeshNum];
00367                     third_quadrant_node = third_quadrant_nodes_3d[this->MeshNum];
00368                     break;
00369                 }
00370 
00371                 default:
00372                     NEVER_REACHED;
00373             }
00374 
00375             double mesh_width=constructor.GetWidth();
00376 
00377             // We only need the output of these two nodes
00378             std::vector<unsigned> nodes_to_be_output;
00379             nodes_to_be_output.push_back(first_quadrant_node);
00380             nodes_to_be_output.push_back(third_quadrant_node);
00381             cardiac_problem.SetOutputNodes(nodes_to_be_output);
00382 
00383             // The results of the tests were originally obtained with the following conductivity
00384             // values. After implementing fibre orientation the defaults changed. Here we set
00385             // the former ones to be used.
00386             SetConductivities(cardiac_problem);
00387 
00388             cardiac_problem.Initialise();
00389 
00390             boost::shared_ptr<BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM> > p_bcc(new BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM>);
00391             SimpleStimulus stim(NeumannStimulus, 0.5);
00392             if (Stimulus==NEUMANN)
00393             {
00394 
00395                 StimulusBoundaryCondition<DIM>* p_bc_stim = new StimulusBoundaryCondition<DIM>(&stim);
00396 
00397                 // get mesh
00398                 AbstractTetrahedralMesh<DIM, DIM> &r_mesh = cardiac_problem.rGetMesh();
00399                 // loop over boundary elements
00400                 typename AbstractTetrahedralMesh<DIM, DIM>::BoundaryElementIterator iter;
00401                 iter = r_mesh.GetBoundaryElementIteratorBegin();
00402                 while (iter != r_mesh.GetBoundaryElementIteratorEnd())
00403                 {
00404                     double x = ((*iter)->CalculateCentroid())[0];
00406                     if (x*x<=1e-10)
00407                     {
00408                         p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim);
00409                     }
00410                     iter++;
00411                 }
00412                 // pass the bcc to the problem
00413                 cardiac_problem.SetBoundaryConditionsContainer(p_bcc);
00414             }
00415 
00416             DisplayRun();
00417             double time_before=MPI_Wtime();
00419             //cardiac_problem.SetWriteInfo();
00420 
00421             try
00422             {
00423                 cardiac_problem.Solve();
00424             }
00425             catch (Exception e)
00426             {
00427                 WARNING("This run threw an exception.  Check convergence results\n");
00428                 std::cout << e.GetMessage() << std::endl;
00429             }
00430 
00431             std::cout << "Time to solve = " << MPI_Wtime()-time_before << " seconds\n";
00432 
00433             OutputFileHandler results_handler("Convergence", false);
00434             Hdf5DataReader results_reader = cardiac_problem.GetDataReader();
00435 
00436             {
00437                 std::vector<double> transmembrane_potential = results_reader.GetVariableOverTime("V", third_quadrant_node);
00438                 std::vector<double> time_series = results_reader.GetUnlimitedDimensionValues();
00439 
00440                 OutputFileHandler plot_file_handler("ConvergencePlots", false);
00441                 if (PetscTools::AmMaster())
00442                 {
00443                     // Write out the time series for the node at third quadrant
00444                     {
00445                         std::stringstream plot_file_name_stream;
00446                         plot_file_name_stream<< nameOfTest << "_Third_quadrant_node_run_"<< file_num << ".csv";
00447                         out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
00448                         for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
00449                         {
00450                             (*p_plot_file) << time_series[data_point] << "\t" << transmembrane_potential[data_point] << "\n";
00451                         }
00452                         p_plot_file->close();
00453                     }
00454                     // Write time series for first quadrant node
00455                     {
00456                         std::vector<double> transmembrane_potential_1qd=results_reader.GetVariableOverTime("V", first_quadrant_node);
00457                         std::vector<double> time_series_1qd = results_reader.GetUnlimitedDimensionValues();
00458                         std::stringstream plot_file_name_stream;
00459                         plot_file_name_stream<< nameOfTest << "_First_quadrant_node_run_"<< file_num << ".csv";
00460                         out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
00461                         for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
00462                         {
00463                             (*p_plot_file) << time_series_1qd[data_point] << "\t" << transmembrane_potential_1qd[data_point] << "\n";
00464                         }
00465                         p_plot_file->close();
00466                     }
00467                 }
00468                 // calculate conduction velocity and APD90 error
00469                 PropagationPropertiesCalculator ppc(&results_reader);
00470 
00471                 try
00472                 {
00473                     #define COVERAGE_IGNORE
00474                     if (SimulateFullActionPotential)
00475                     {
00476                         Apd90FirstQn = ppc.CalculateActionPotentialDuration(90.0, first_quadrant_node);
00477                         Apd90ThirdQn = ppc.CalculateActionPotentialDuration(90.0, third_quadrant_node);
00478                     }
00479                     #undef COVERAGE_IGNORE
00480                     ConductionVelocity  = ppc.CalculateConductionVelocity(first_quadrant_node,third_quadrant_node,0.5*mesh_width);
00481                 }
00482                 catch (Exception e)
00483                 {
00484                     #define COVERAGE_IGNORE
00485                     std::cout << "Warning - this run threw an exception in calculating propagation.  Check convergence results\n";
00486                     std::cout << e.GetMessage() << std::endl;
00487                     #undef COVERAGE_IGNORE
00488                 }
00489                 double cond_velocity_error = 1e10;
00490                 double apd90_first_qn_error = 1e10;
00491                 double apd90_third_qn_error = 1e10;
00492 
00493                 if (this->PopulatedResult)
00494                 {
00495                     if (prev_cond_velocity != 0.0)
00496                     {
00497                         cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity;
00498                     }
00499 #define COVERAGE_IGNORE
00500                     if (prev_apd90_first_qn != 0.0)
00501                     {
00502                         apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn;
00503                     }
00504                     if (prev_apd90_third_qn != 0.0)
00505                     {
00506                         apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn;
00507                     }
00508                     if (apd90_first_qn_error == 0.0)
00509                     {
00510                         apd90_first_qn_error = DBL_EPSILON; //Avoid log zero on plot
00511                     }
00512                     if (apd90_third_qn_error == 0.0)
00513                     {
00514                         apd90_third_qn_error = DBL_EPSILON; //Avoid log zero on plot
00515                     }
00516 #undef COVERAGE_IGNORE
00517                     if (cond_velocity_error == 0.0)
00518                     {
00519                         cond_velocity_error = DBL_EPSILON; //Avoid log zero on plot
00520                     }
00521                 }
00522 
00523                 prev_cond_velocity = ConductionVelocity;
00524                 prev_apd90_first_qn = Apd90FirstQn;
00525                 prev_apd90_third_qn = Apd90ThirdQn;
00526 
00527                 // calculate l2norm
00528                 double max_abs_error = 0;
00529                 double sum_sq_abs_error =0;
00530                 double sum_sq_prev_voltage = 0;
00531                 double sum_sq_abs_error_full =0;
00532                 double sum_sq_prev_voltage_full = 0;
00533                 if (this->PopulatedResult)
00534                 {
00535                     //If the PDE step is varying then we'll have twice as much data now as we use to have
00536 
00537                     unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1);
00538                     assert (time_factor == 1 || time_factor == 2 || time_factor == 8);
00539                     //Iterate over the shorter time series data
00540                     for (unsigned data_point = 0; data_point<prev_times.size(); data_point++)
00541                     {
00542                         unsigned this_data_point=time_factor*data_point;
00543 
00544                         assert(time_series[this_data_point] == prev_times[data_point]);
00545                         double abs_error = fabs(transmembrane_potential[this_data_point]-prev_voltage[data_point]);
00546                         max_abs_error = (abs_error > max_abs_error) ? abs_error : max_abs_error;
00547                         //Only do resolve the upstroke...
00548                         sum_sq_abs_error_full += abs_error*abs_error;
00549                         sum_sq_prev_voltage_full += prev_voltage[data_point] * prev_voltage[data_point];
00550                         if (time_series[this_data_point] <= 8.0)
00551                         {
00552                             //In most regular cases we always do this, since the simulation stops at ms
00553                             sum_sq_abs_error += abs_error*abs_error;
00554                             sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point];
00555                         }
00556                     }
00557 
00558                 }
00559                 if (!this->PopulatedResult || !FixedResult)
00560                 {
00561                     prev_voltage = transmembrane_potential;
00562                     prev_times = time_series;
00563                 }
00564 
00565                 if (this->PopulatedResult)
00566                 {
00567 
00568                     if (PetscTools::AmMaster())
00569                     {
00570                         (*p_conv_info_file) << std::setprecision(8)
00571                                             << Abscissa() << "\t"
00572                                             << sqrt(sum_sq_abs_error_full/sum_sq_prev_voltage_full) << "\t"
00573                                             << sqrt(sum_sq_abs_error/sum_sq_prev_voltage) << "\t"
00574                                             << max_abs_error << "\t"
00575                                             << Apd90FirstQn <<" "<< apd90_first_qn_error <<""<< "\t"
00576                                             << Apd90ThirdQn <<" "<< apd90_third_qn_error <<""<< "\t"
00577                                             << ConductionVelocity <<" "<< cond_velocity_error  <<""<< std::endl;
00578                     }
00579                     // convergence criterion
00580                     this->Converged = sum_sq_abs_error/sum_sq_prev_voltage<this->RelativeConvergenceCriterion;
00581                     this->LastDifference=sum_sq_abs_error/sum_sq_prev_voltage;
00582 #define COVERAGE_IGNORE
00583                     if (time_series.size() == 1u)
00584                     {
00585                         std::cout << "Failed after successful convergence - give up this convergence test\n";
00586                         break;
00587                     }
00588 #undef COVERAGE_IGNORE
00589 
00590                 }
00591 
00592                 if (!this->PopulatedResult)
00593                 {
00594                     this->PopulatedResult=true;
00595 
00596                 }
00597             }
00598 
00599             // Get ready for the next test by halving the time step
00600             if (!this->Converged)
00601             {
00602                 UpdateConvergenceParameters();
00603                 file_num++;
00604             }
00605             delete p_cell_factory;
00606         }
00607         while (!GiveUpConvergence() && !this->Converged);
00608 
00609 
00610         if (PetscTools::AmMaster())
00611         {
00612             p_conv_info_file->close();
00613 
00614             std::cout << "Results: " << std::endl;
00615             ABORT_IF_NON0(system, "cat " + conv_info_handler.GetOutputDirectoryFullPath() + nameOfTest + "_info.csv");
00616         }
00617 
00618     }
00619 
00620     void DisplayRun()
00621     {
00622         unsigned num_ele_across = (unsigned) SmallPow(2, this->MeshNum+2);// number of elements in each dimension
00623         double scaling = mMeshWidth/(double) num_ele_across;
00624 
00625         std::cout<<"================================================================================"<<std::endl;
00626         std::cout<<"Solving in "<<DIM<<"D\t";
00627         std::cout<<"Space step "<< scaling << " cm (mesh " << this->MeshNum << ")" << "\n";
00628         std::cout<<"PDE step "<<this->PdeTimeStep<<" ms"<<"\t";
00629         std::cout<<"ODE step "<<this->OdeTimeStep<<" ms"<<"\t";
00630         if (HeartConfig::Instance()->GetUseAbsoluteTolerance())
00631         {
00632             std::cout<<"KSP absolute "<<HeartConfig::Instance()->GetAbsoluteTolerance()<<"\t";
00633         }
00634         else
00635         {
00636             std::cout<<"KSP relative "<<HeartConfig::Instance()->GetRelativeTolerance()<<"\t";
00637         }
00638         switch (this->Stimulus)
00639         {
00640             case PLANE:
00641             std::cout<<"Stimulus = Plane\n";
00642             break;
00643 
00644             case QUARTER:
00645             std::cout<<"Stimulus = Ramped first quarter\n";
00646             break;
00647 
00648             case NEUMANN:
00649             std::cout<<"Stimulus = Neumann\n";
00650             break;
00651 
00652         }
00653         EXPECT0(system, "date");//To keep track of what Nightly things are doing
00656         if (this->UseAbsoluteStimulus)
00657         {
00658             #define COVERAGE_IGNORE
00659             std::cout<<"Using absolute stimulus of "<<this->AbsoluteStimulus<<std::endl;
00660             #undef COVERAGE_IGNORE
00661         }
00662         std::cout << std::flush;
00663         //HeartEventHandler::Headings();
00664         //HeartEventHandler::Report();
00665 
00666     }
00667 
00668 public:
00669     virtual ~AbstractConvergenceTester() {}
00670 
00672     virtual void SetInitialConvergenceParameters()=0;
00674     virtual void UpdateConvergenceParameters()=0;
00676     virtual bool GiveUpConvergence()=0;
00678     virtual double Abscissa()=0;
00685     virtual void PopulateStandardResult(std::vector<double> &result, std::vector<double> &times)
00686     {
00687         assert(this->PopulatedResult==false);
00688         assert(result.size()==0);
00689         assert(times.size()==0);
00690     }
00691 
00695     bool IsConverged()
00696     {
00697         return Converged;
00698     }
00699 
00703     void SetMeshWidth(double meshWidth)
00704     {
00705         mMeshWidth=meshWidth;
00706     }
00707 };
00708 
00709 #endif /*ABSTRACTCONVERGENCETESTER_HPP_*/