AbstractConvergenceTester.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 
00030 #ifndef ABSTRACTCONVERGENCETESTER_HPP_
00031 #define ABSTRACTCONVERGENCETESTER_HPP_
00032 
00033 #include "BidomainProblem.hpp"
00034 #include "MonodomainProblem.hpp"
00035 
00036 #include <petscvec.h>
00037 #include <vector>
00038 #include <iostream>
00039 #include <fstream>
00040 #include <cmath>
00041 
00042 #include "AbstractTetrahedralMesh.hpp"
00043 #include "TrianglesMeshReader.hpp"
00044 #include "AbstractCardiacCellFactory.hpp"
00045 #include "OutputFileHandler.hpp"
00046 #include "TrianglesMeshWriter.hpp"
00047 #include "PropagationPropertiesCalculator.hpp"
00048 #include "Hdf5DataReader.hpp"
00049 #include "GeneralPlaneStimulusCellFactory.hpp"
00050 #include "CuboidMeshConstructor.hpp"
00051 #include "ZeroStimulusCellFactory.hpp"
00052 #include "SimpleStimulus.hpp"
00053 #include "ConstBoundaryCondition.hpp"
00054 #include "StimulusBoundaryCondition.hpp"
00055 
00056 #include "Warnings.hpp"
00057 
00058 typedef enum StimulusType_
00059 {
00060     PLANE=0,
00061     QUARTER,
00062     NEUMANN
00063 } StimulusType;
00064 
00069 template <class CELL, unsigned DIM>
00070 class RampedQuarterStimulusCellFactory : public AbstractCardiacCellFactory<DIM>
00071 {
00072 private:
00074     std::vector< boost::shared_ptr<SimpleStimulus> > mpStimuli;
00076     double mMeshWidth;
00078     double mStepSize;
00082     unsigned mLevels;
00083 public:
00084 
00091     RampedQuarterStimulusCellFactory(double meshWidth, unsigned numElemAcross, double fullStim=-1e7)
00092         : AbstractCardiacCellFactory<DIM>(),
00093           mMeshWidth(meshWidth),
00094           mStepSize(meshWidth/numElemAcross),
00095           mLevels(numElemAcross/4)
00096     {
00097         assert(numElemAcross%4 == 0); //numElemAcross is supposed to be a multiple of 4
00098 
00099         for (unsigned level=0; level<mLevels; level++)
00100         {
00101             double this_stim = fullStim - (level*fullStim)/mLevels;
00102             //this_stim is full_stim at the zero level and would be zero at level=mLevels
00103             mpStimuli.push_back((boost::shared_ptr<SimpleStimulus>)new SimpleStimulus(this_stim, 0.5));
00104         }
00105     }
00106 
00107 
00113     AbstractCardiacCell* CreateCardiacCellForTissueNode(unsigned node)
00114     {
00115         double x = this->GetMesh()->GetNode(node)->GetPoint()[0];
00116         double d_level = x/mStepSize;
00117         unsigned level = (unsigned) d_level;
00118         assert(fabs(level-d_level) < DBL_MAX); //x ought to really be a multiple of the step size
00119 
00120         if (level < mLevels)
00121         {
00122             return new CELL(this->mpSolver, this->mpStimuli[level]);
00123         }
00124         else
00125         {
00126             return new CELL(this->mpSolver, this->mpZeroStimulus);
00127         }
00128     }
00129 };
00130 
00131 
00136 class AbstractUntemplatedConvergenceTester
00137 {
00138 protected:
00140     double mMeshWidth;
00141 public:
00143     double OdeTimeStep;
00145     double PdeTimeStep;
00150     unsigned MeshNum;
00151     double RelativeConvergenceCriterion; 
00152     double LastDifference; 
00153     double Apd90FirstQn; 
00154     double Apd90ThirdQn; 
00155     double ConductionVelocity;  
00159     bool PopulatedResult;
00163     bool FixedResult;
00167     bool UseAbsoluteStimulus;
00172     double AbsoluteStimulus;
00173     bool SimulateFullActionPotential; 
00174     bool Converged; 
00175     StimulusType Stimulus; 
00176     double NeumannStimulus; 
00178     AbstractUntemplatedConvergenceTester();
00179 
00185     virtual void Converge(std::string nameOfTest)=0;
00186 
00187     virtual ~AbstractUntemplatedConvergenceTester();
00188 };
00189 
00193 template<class CARDIAC_PROBLEM, unsigned DIM>
00194 void SetConductivities(CARDIAC_PROBLEM& rCardiacProblem);
00195 
00196 template<unsigned DIM>
00197 void SetConductivities(BidomainProblem<DIM>& rProblem)
00198 {
00199     c_vector<double, DIM> conductivities;
00200     for (unsigned i=0; i<DIM; i++)
00201     {
00202         conductivities[i] = 1.75;
00203     }
00204     HeartConfig::Instance()->SetIntracellularConductivities(conductivities);
00205 
00206     for (unsigned i=0; i<DIM; i++)
00207     {
00208         conductivities[i] = 7.0;
00209     }
00210     HeartConfig::Instance()->SetExtracellularConductivities(conductivities);
00211 }
00212 
00213 template<unsigned DIM>
00214 void SetConductivities(MonodomainProblem<DIM>& rProblem)
00215 {
00216     c_vector<double, DIM> conductivities;
00217     for (unsigned i=0; i<DIM; i++)
00218     {
00219         conductivities[i] = 1.75;
00220     }
00221     HeartConfig::Instance()->SetIntracellularConductivities(conductivities);
00222 }
00223 
00228 template<class CELL, class CARDIAC_PROBLEM, unsigned DIM, unsigned PROBLEM_DIM>
00229 class AbstractConvergenceTester : public AbstractUntemplatedConvergenceTester
00230 {
00231 public:
00236     void Converge(std::string nameOfTest)
00237     {
00238         std::cout << "=========================== Beginning Test...==================================\n";
00239         // Create the meshes on which the test will be based
00240         const std::string mesh_dir = "ConvergenceMesh";
00241         OutputFileHandler output_file_handler(mesh_dir);
00242         ReplicatableVector voltage_replicated;
00243 
00244         unsigned file_num=0;
00245 
00246         // Create a file for storing conduction velocity and AP data and write the header
00247         OutputFileHandler conv_info_handler("ConvergencePlots", false);
00248         out_stream p_conv_info_file;
00249         if (PetscTools::AmMaster())
00250         {
00251             p_conv_info_file = conv_info_handler.OpenOutputFile(nameOfTest+"_info.csv");
00252             (*p_conv_info_file) << "#Abcisa\t"
00253                                 << "l2-norm-full\t"
00254                                 << "l2-norm-onset\t"
00255                                 << "Max absolute err\t"
00256                                 << "APD90_1st_quad\t"
00257                                 << "APD90_3rd_quad\t"
00258                                 << "Conduction velocity (relative diffs)" << std::endl;
00259         }
00260         SetInitialConvergenceParameters();
00261 
00262         double prev_apd90_first_qn=0.0;
00263         double prev_apd90_third_qn=0.0;
00264         double prev_cond_velocity=0.0;
00265         std::vector<double> prev_voltage;
00266         std::vector<double> prev_times;
00267         PopulateStandardResult(prev_voltage, prev_times);
00268 
00269         do
00270         {
00271             CuboidMeshConstructor<DIM> constructor;
00272 
00273             //If the printing time step is too fine, then simulations become I/O bound without much improvement in accuracy
00274             double printing_step = this->PdeTimeStep;
00275 #define COVERAGE_IGNORE
00276             while (printing_step < 1.0e-4)
00277             {
00278                 printing_step *= 2.0;
00279                 std::cout<<"Warning: PrintingTimeStep increased\n";
00280             }
00281 #undef COVERAGE_IGNORE
00282             HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(this->OdeTimeStep, this->PdeTimeStep, printing_step);
00283 #define COVERAGE_IGNORE
00284             if (SimulateFullActionPotential)
00285             {
00286                 HeartConfig::Instance()->SetSimulationDuration(400.0);
00287             }
00288             else
00289             {
00290                 HeartConfig::Instance()->SetSimulationDuration(8.0);
00291             }
00292 #undef COVERAGE_IGNORE
00293             HeartConfig::Instance()->SetOutputDirectory("Convergence");
00294             HeartConfig::Instance()->SetOutputFilenamePrefix("Results");
00295 
00296             DistributedTetrahedralMesh<DIM, DIM> mesh;
00297             constructor.Construct(mesh, this->MeshNum, mMeshWidth);
00298 
00299             unsigned num_ele_across = (unsigned) SmallPow(2, this->MeshNum+2); // number of elements in each dimension
00300 
00301             AbstractCardiacCellFactory<DIM>* p_cell_factory=NULL;
00302 
00303             switch (this->Stimulus)
00304             {
00305                 case NEUMANN:
00306                 {
00307                     p_cell_factory = new ZeroStimulusCellFactory<CELL, DIM>();
00308                     break;
00309                 }
00310                 case PLANE:
00311                 {
00312                     if (this->UseAbsoluteStimulus)
00313                     {
00314                         #define COVERAGE_IGNORE
00315                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(0, this->AbsoluteStimulus, true);
00316                         #undef COVERAGE_IGNORE
00317                     }
00318                     else
00319                     {
00320                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(num_ele_across, constructor.GetWidth(), false, this->AbsoluteStimulus);
00321                     }
00322                     break;
00323                 }
00324                 case QUARTER:
00325                 {
00327                     p_cell_factory = new RampedQuarterStimulusCellFactory<CELL, DIM>(constructor.GetWidth(), num_ele_across, this->AbsoluteStimulus/10.0);
00328                     break;
00329                 }
00330             }
00331 
00332 
00333             CARDIAC_PROBLEM cardiac_problem(p_cell_factory);
00334             cardiac_problem.SetMesh(&mesh);
00335 
00336             // Calculate positions of nodes 1/4 and 3/4 through the mesh
00337             unsigned third_quadrant_node;
00338             unsigned first_quadrant_node;
00339             switch(DIM)
00340             {
00341                 case 1:
00342                 {
00343                     first_quadrant_node = (unsigned) (0.25*constructor.GetNumElements());
00344                     third_quadrant_node = (unsigned) (0.75*constructor.GetNumElements());
00345                     break;
00346                 }
00347                 case 2:
00348                 {
00349                     unsigned n= (unsigned) SmallPow (2, this->MeshNum+2);
00350                     first_quadrant_node =   (n+1)*(n/2)+  n/4 ;
00351                     third_quadrant_node =   (n+1)*(n/2)+3*n/4 ;
00352                     break;
00353                 }
00354                 case 3:
00355                 {
00356                     const unsigned first_quadrant_nodes_3d[5]={61, 362, 2452, 17960, 137296};
00357                     const unsigned third_quadrant_nodes_3d[5]={63, 366, 2460, 17976, 137328};
00358                     assert(this->PdeTimeStep<5);
00359                     first_quadrant_node = first_quadrant_nodes_3d[this->MeshNum];
00360                     third_quadrant_node = third_quadrant_nodes_3d[this->MeshNum];
00361                     break;
00362                 }
00363 
00364                 default:
00365                     NEVER_REACHED;
00366             }
00367 
00368             double mesh_width=constructor.GetWidth();
00369 
00370             // We only need the output of these two nodes
00371             std::vector<unsigned> nodes_to_be_output;
00372             nodes_to_be_output.push_back(first_quadrant_node);
00373             nodes_to_be_output.push_back(third_quadrant_node);
00374             cardiac_problem.SetOutputNodes(nodes_to_be_output);
00375 
00376             // The results of the tests were originally obtained with the following conductivity
00377             // values. After implementing fibre orientation the defaults changed. Here we set
00378             // the former ones to be used.
00379             SetConductivities(cardiac_problem);
00380 
00381             cardiac_problem.Initialise();
00382 
00383             boost::shared_ptr<BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM> > p_bcc(new BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM>);
00384             SimpleStimulus stim(NeumannStimulus, 0.5);
00385             if (Stimulus==NEUMANN)
00386             {
00387 
00388                 StimulusBoundaryCondition<DIM>* p_bc_stim = new StimulusBoundaryCondition<DIM>(&stim);
00389 
00390                 // get mesh
00391                 AbstractTetrahedralMesh<DIM, DIM> &r_mesh = cardiac_problem.rGetMesh();
00392                 // loop over boundary elements
00393                 typename AbstractTetrahedralMesh<DIM, DIM>::BoundaryElementIterator iter;
00394                 iter = r_mesh.GetBoundaryElementIteratorBegin();
00395                 while (iter != r_mesh.GetBoundaryElementIteratorEnd())
00396                 {
00397                     double x = ((*iter)->CalculateCentroid())[0];
00399                     if (x*x<=1e-10)
00400                     {
00401                         p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim);
00402                     }
00403                     iter++;
00404                 }
00405                 // pass the bcc to the problem
00406                 cardiac_problem.SetBoundaryConditionsContainer(p_bcc);
00407             }
00408 
00409             DisplayRun();
00410             double time_before=MPI_Wtime();
00412             //cardiac_problem.SetWriteInfo();
00413 
00414             try
00415             {
00416                 cardiac_problem.Solve();
00417             }
00418             catch (Exception e)
00419             {
00420                 WARNING("This run threw an exception.  Check convergence results\n");
00421                 std::cout << e.GetMessage() << std::endl;
00422             }
00423 
00424             std::cout << "Time to solve = " << MPI_Wtime()-time_before << " seconds\n";
00425 
00426             OutputFileHandler results_handler("Convergence", false);
00427             Hdf5DataReader results_reader = cardiac_problem.GetDataReader();
00428 
00429             {
00430                 std::vector<double> transmembrane_potential = results_reader.GetVariableOverTime("V", third_quadrant_node);
00431                 std::vector<double> time_series = results_reader.GetUnlimitedDimensionValues();
00432 
00433                 OutputFileHandler plot_file_handler("ConvergencePlots", false);
00434                 if (PetscTools::AmMaster())
00435                 {
00436                     // Write out the time series for the node at third quadrant
00437                     {
00438                         std::stringstream plot_file_name_stream;
00439                         plot_file_name_stream<< nameOfTest << "_Third_quadrant_node_run_"<< file_num << ".csv";
00440                         out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
00441                         for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
00442                         {
00443                             (*p_plot_file) << time_series[data_point] << "\t" << transmembrane_potential[data_point] << "\n";
00444                         }
00445                         p_plot_file->close();
00446                     }
00447                     // Write time series for first quadrant node
00448                     {
00449                         std::vector<double> transmembrane_potential_1qd=results_reader.GetVariableOverTime("V", first_quadrant_node);
00450                         std::vector<double> time_series_1qd = results_reader.GetUnlimitedDimensionValues();
00451                         std::stringstream plot_file_name_stream;
00452                         plot_file_name_stream<< nameOfTest << "_First_quadrant_node_run_"<< file_num << ".csv";
00453                         out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
00454                         for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
00455                         {
00456                             (*p_plot_file) << time_series_1qd[data_point] << "\t" << transmembrane_potential_1qd[data_point] << "\n";
00457                         }
00458                         p_plot_file->close();
00459                     }
00460                 }
00461                 // calculate conduction velocity and APD90 error
00462                 PropagationPropertiesCalculator ppc(&results_reader);
00463 
00464                 try
00465                 {
00466                     #define COVERAGE_IGNORE
00467                     if (SimulateFullActionPotential)
00468                     {
00469                         Apd90FirstQn = ppc.CalculateActionPotentialDuration(90.0, first_quadrant_node);
00470                         Apd90ThirdQn = ppc.CalculateActionPotentialDuration(90.0, third_quadrant_node);
00471                     }
00472                     #undef COVERAGE_IGNORE
00473                     ConductionVelocity  = ppc.CalculateConductionVelocity(first_quadrant_node,third_quadrant_node,0.5*mesh_width);
00474                 }
00475                 catch (Exception e)
00476                 {
00477                     #define COVERAGE_IGNORE
00478                     std::cout << "Warning - this run threw an exception in calculating propagation.  Check convergence results\n";
00479                     std::cout << e.GetMessage() << std::endl;
00480                     #undef COVERAGE_IGNORE
00481                 }
00482                 double cond_velocity_error = 1e10;
00483                 double apd90_first_qn_error = 1e10;
00484                 double apd90_third_qn_error = 1e10;
00485 
00486                 if (this->PopulatedResult)
00487                 {
00488                     if (prev_cond_velocity != 0.0)
00489                     {
00490                         cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity;
00491                     }
00492 #define COVERAGE_IGNORE
00493                     if (prev_apd90_first_qn != 0.0)
00494                     {
00495                         apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn;
00496                     }
00497                     if (prev_apd90_third_qn != 0.0)
00498                     {
00499                         apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn;
00500                     }
00501                     if (apd90_first_qn_error == 0.0)
00502                     {
00503                         apd90_first_qn_error = DBL_EPSILON; //Avoid log zero on plot
00504                     }
00505                     if (apd90_third_qn_error == 0.0)
00506                     {
00507                         apd90_third_qn_error = DBL_EPSILON; //Avoid log zero on plot
00508                     }
00509 #undef COVERAGE_IGNORE
00510                     if (cond_velocity_error == 0.0)
00511                     {
00512                         cond_velocity_error = DBL_EPSILON; //Avoid log zero on plot
00513                     }
00514                 }
00515 
00516                 prev_cond_velocity = ConductionVelocity;
00517                 prev_apd90_first_qn = Apd90FirstQn;
00518                 prev_apd90_third_qn = Apd90ThirdQn;
00519 
00520                 // calculate l2norm
00521                 double max_abs_error = 0;
00522                 double sum_sq_abs_error =0;
00523                 double sum_sq_prev_voltage = 0;
00524                 double sum_sq_abs_error_full =0;
00525                 double sum_sq_prev_voltage_full = 0;
00526                 if (this->PopulatedResult)
00527                 {
00528                     //If the PDE step is varying then we'll have twice as much data now as we use to have
00529 
00530                     unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1);
00531                     assert (time_factor == 1 || time_factor == 2 || time_factor == 8);
00532                     //Iterate over the shorter time series data
00533                     for (unsigned data_point = 0; data_point<prev_times.size(); data_point++)
00534                     {
00535                         unsigned this_data_point=time_factor*data_point;
00536 
00537                         assert(time_series[this_data_point] == prev_times[data_point]);
00538                         double abs_error = fabs(transmembrane_potential[this_data_point]-prev_voltage[data_point]);
00539                         max_abs_error = (abs_error > max_abs_error) ? abs_error : max_abs_error;
00540                         //Only do resolve the upstroke...
00541                         sum_sq_abs_error_full += abs_error*abs_error;
00542                         sum_sq_prev_voltage_full += prev_voltage[data_point] * prev_voltage[data_point];
00543                         if (time_series[this_data_point] <= 8.0)
00544                         {
00545                             //In most regular cases we always do this, since the simulation stops at ms
00546                             sum_sq_abs_error += abs_error*abs_error;
00547                             sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point];
00548                         }
00549                     }
00550 
00551                 }
00552                 if (!this->PopulatedResult || !FixedResult)
00553                 {
00554                     prev_voltage = transmembrane_potential;
00555                     prev_times = time_series;
00556                 }
00557 
00558                 if (this->PopulatedResult)
00559                 {
00560 
00561                     if (PetscTools::AmMaster())
00562                     {
00563                         (*p_conv_info_file) << std::setprecision(8)
00564                                             << Abscissa() << "\t"
00565                                             << sqrt(sum_sq_abs_error_full/sum_sq_prev_voltage_full) << "\t"
00566                                             << sqrt(sum_sq_abs_error/sum_sq_prev_voltage) << "\t"
00567                                             << max_abs_error << "\t"
00568                                             << Apd90FirstQn <<" "<< apd90_first_qn_error <<""<< "\t"
00569                                             << Apd90ThirdQn <<" "<< apd90_third_qn_error <<""<< "\t"
00570                                             << ConductionVelocity <<" "<< cond_velocity_error  <<""<< std::endl;
00571                     }
00572                     // convergence criterion
00573                     this->Converged = sum_sq_abs_error/sum_sq_prev_voltage<this->RelativeConvergenceCriterion;
00574                     this->LastDifference=sum_sq_abs_error/sum_sq_prev_voltage;
00575 #define COVERAGE_IGNORE
00576                     if (time_series.size() == 1u)
00577                     {
00578                         std::cout << "Failed after successful convergence - give up this convergence test\n";
00579                         break;
00580                     }
00581 #undef COVERAGE_IGNORE
00582 
00583                 }
00584 
00585                 if (!this->PopulatedResult)
00586                 {
00587                     this->PopulatedResult=true;
00588 
00589                 }
00590             }
00591 
00592             // Get ready for the next test by halving the time step
00593             if (!this->Converged)
00594             {
00595                 UpdateConvergenceParameters();
00596                 file_num++;
00597             }
00598             delete p_cell_factory;
00599         }
00600         while (!GiveUpConvergence() && !this->Converged);
00601 
00602 
00603         if (PetscTools::AmMaster())
00604         {
00605             p_conv_info_file->close();
00606 
00607             std::cout << "Results: " << std::endl;
00608             ABORT_IF_NON0(system, "cat " + conv_info_handler.GetOutputDirectoryFullPath() + nameOfTest + "_info.csv");
00609         }
00610 
00611     }
00612 
00613     void DisplayRun()
00614     {
00615         unsigned num_ele_across = (unsigned) SmallPow(2, this->MeshNum+2);// number of elements in each dimension
00616         double scaling = mMeshWidth/(double) num_ele_across;
00617 
00618         std::cout<<"================================================================================"<<std::endl;
00619         std::cout<<"Solving in "<<DIM<<"D\t";
00620         std::cout<<"Space step "<< scaling << " cm (mesh " << this->MeshNum << ")" << "\n";
00621         std::cout<<"PDE step "<<this->PdeTimeStep<<" ms"<<"\t";
00622         std::cout<<"ODE step "<<this->OdeTimeStep<<" ms"<<"\t";
00623         if (HeartConfig::Instance()->GetUseAbsoluteTolerance())
00624         {
00625             std::cout<<"KSP absolute "<<HeartConfig::Instance()->GetAbsoluteTolerance()<<"\t";
00626         }
00627         else
00628         {
00629             std::cout<<"KSP relative "<<HeartConfig::Instance()->GetRelativeTolerance()<<"\t";
00630         }
00631         switch (this->Stimulus)
00632         {
00633             case PLANE:
00634             std::cout<<"Stimulus = Plane\n";
00635             break;
00636 
00637             case QUARTER:
00638             std::cout<<"Stimulus = Ramped first quarter\n";
00639             break;
00640 
00641             case NEUMANN:
00642             std::cout<<"Stimulus = Neumann\n";
00643             break;
00644 
00645         }
00646         EXPECT0(system, "date");//To keep track of what Nightly things are doing
00649         if (this->UseAbsoluteStimulus)
00650         {
00651             #define COVERAGE_IGNORE
00652             std::cout<<"Using absolute stimulus of "<<this->AbsoluteStimulus<<std::endl;
00653             #undef COVERAGE_IGNORE
00654         }
00655         std::cout << std::flush;
00656         //HeartEventHandler::Headings();
00657         //HeartEventHandler::Report();
00658 
00659     }
00660 
00661 public:
00662     virtual ~AbstractConvergenceTester() {}
00663 
00665     virtual void SetInitialConvergenceParameters()=0;
00667     virtual void UpdateConvergenceParameters()=0;
00669     virtual bool GiveUpConvergence()=0;
00671     virtual double Abscissa()=0;
00678     virtual void PopulateStandardResult(std::vector<double> &result, std::vector<double> &times)
00679     {
00680         assert(this->PopulatedResult==false);
00681         assert(result.size()==0);
00682         assert(times.size()==0);
00683     }
00684 
00688     bool IsConverged()
00689     {
00690         return Converged;
00691     }
00692 
00696     void SetMeshWidth(double meshWidth)
00697     {
00698         mMeshWidth=meshWidth;
00699     }
00700 };
00701 
00702 #endif /*ABSTRACTCONVERGENCETESTER_HPP_*/
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3