AbstractConvergenceTester.hpp

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

Generated on Mon Nov 1 12:35:16 2010 for Chaste by  doxygen 1.5.5