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 #include <petscvec.h>
00036 #include <vector>
00037 #include <iostream>
00038 #include <fstream>
00039 #include <cmath>
00040 
00041 #include "AbstractTetrahedralMesh.hpp"
00042 #include "TrianglesMeshReader.hpp"
00043 #include "AbstractCardiacCellFactory.hpp"
00044 #include "OutputFileHandler.hpp"
00045 #include "TrianglesMeshWriter.hpp"
00046 #include "PropagationPropertiesCalculator.hpp"
00047 #include "Hdf5DataReader.hpp"
00048 #include "GeneralPlaneStimulusCellFactory.hpp"
00049 #include "CuboidMeshConstructor.hpp"
00050 #include "ZeroStimulusCellFactory.hpp"
00051 #include "SimpleStimulus.hpp"
00052 #include "ConstBoundaryCondition.hpp"
00053 #include "StimulusBoundaryCondition.hpp"
00054 
00055 
00056 typedef enum StimulusType_
00057 {
00058     PLANE=0,
00059     QUARTER,
00060     NEUMANN
00061 } StimulusType;
00062 
00067 template <class CELL, unsigned DIM>
00068 class RampedQuarterStimulusCellFactory : public AbstractCardiacCellFactory<DIM>
00069 {
00070 private:
00072     std::vector< boost::shared_ptr<SimpleStimulus> > mpStimuli;
00074     double mMeshWidth;
00076     double mStepSize;
00080     unsigned mLevels;
00081 public:
00082 
00088     RampedQuarterStimulusCellFactory(double meshWidth, unsigned numElemAcross)
00089         : AbstractCardiacCellFactory<DIM>(),
00090           mMeshWidth(meshWidth),
00091           mStepSize(meshWidth/numElemAcross),
00092           mLevels(numElemAcross/4)
00093     {
00094         assert(numElemAcross%4 == 0); //numElemAcross is supposed to be a multiple of 4
00095         double full_stim=-1000000;
00096 
00097         for (unsigned level=0; level<mLevels; level++)
00098         {
00099             double this_stim=full_stim - (level*full_stim)/mLevels;
00100             //this_stim is full_stim at the zero level and would be zero at level=mLevels
00101             mpStimuli.push_back((boost::shared_ptr<SimpleStimulus>)new SimpleStimulus(this_stim, 0.5));
00102         }
00103     }
00104 
00105 
00111     AbstractCardiacCell* CreateCardiacCellForTissueNode(unsigned node)
00112     {
00113         double x = this->GetMesh()->GetNode(node)->GetPoint()[0];
00114         double d_level=x/mStepSize;
00115         unsigned level=(unsigned) d_level;
00116         assert(fabs(level-d_level) < DBL_MAX); //x ought to really be a multiple of the step size
00117 
00118         if (level < mLevels)
00119         {
00120             return new CELL(this->mpSolver, this->mpStimuli[level]);
00121         }
00122         else
00123         {
00124             return new CELL(this->mpSolver, this->mpZeroStimulus);
00125         }
00126     }
00127 };
00128 
00129 
00134 class AbstractUntemplatedConvergenceTester
00135 {
00136 protected:
00138     double mMeshWidth;
00139 public:
00141     double OdeTimeStep;
00143     double PdeTimeStep;
00148     unsigned MeshNum;
00149     double RelativeConvergenceCriterion; 
00150     double LastDifference; 
00151     double Apd90FirstQn; 
00152     double Apd90ThirdQn; 
00153     double ConductionVelocity;  
00157     bool PopulatedResult;
00161     bool FixedResult;
00165     bool UseAbsoluteStimulus;
00170     double AbsoluteStimulus;
00171     bool SimulateFullActionPotential; 
00172     bool Converged; 
00173     StimulusType Stimulus; 
00174     double NeumannStimulus; 
00176     AbstractUntemplatedConvergenceTester();
00177 
00183     virtual void Converge(std::string nameOfTest)=0;
00184 
00185     virtual ~AbstractUntemplatedConvergenceTester();
00186 };
00187 
00191 template<class CARDIAC_PROBLEM, unsigned DIM>
00192 void SetConductivities(CARDIAC_PROBLEM& rCardiacProblem);
00193 
00194 template<unsigned DIM>
00195 void SetConductivities(BidomainProblem<DIM>& rProblem)
00196 {
00197     c_vector<double, DIM> conductivities;
00198     for (unsigned i=0; i<DIM; i++)
00199     {
00200         conductivities[i] = 1.75;
00201     }
00202     HeartConfig::Instance()->SetIntracellularConductivities(conductivities);
00203 
00204     for (unsigned i=0; i<DIM; i++)
00205     {
00206         conductivities[i] = 7.0;
00207     }
00208     HeartConfig::Instance()->SetExtracellularConductivities(conductivities);
00209 }
00210 
00211 template<unsigned DIM>
00212 void SetConductivities(MonodomainProblem<DIM>& rProblem)
00213 {
00214     c_vector<double, DIM> conductivities;
00215     for (unsigned i=0; i<DIM; i++)
00216     {
00217         conductivities[i] = 1.75;
00218     }
00219     HeartConfig::Instance()->SetIntracellularConductivities(conductivities);
00220 }
00221 
00226 template<class CELL, class CARDIAC_PROBLEM, unsigned DIM, unsigned PROBLEM_DIM>
00227 class AbstractConvergenceTester : public AbstractUntemplatedConvergenceTester
00228 {
00229 public:
00234     void Converge(std::string nameOfTest)
00235     {
00236         std::cout << "=========================== Beginning Test...==================================\n";
00237         // Create the meshes on which the test will be based
00238         const std::string mesh_dir = "ConvergenceMesh";
00239         OutputFileHandler output_file_handler(mesh_dir);
00240         ReplicatableVector voltage_replicated;
00241 
00242         unsigned file_num=0;
00243 
00244         // Create a file for storing conduction velocity and AP data and write the header
00245         OutputFileHandler conv_info_handler("ConvergencePlots", false);
00246         out_stream p_conv_info_file;
00247         if (PetscTools::AmMaster())
00248         {
00249             p_conv_info_file = conv_info_handler.OpenOutputFile(nameOfTest+"_info.csv");
00250             (*p_conv_info_file) << "#Abcisa\t"
00251                                 << "l2-norm-full\t"
00252                                 << "l2-norm-onset\t"
00253                                 << "Max absolute err\t"
00254                                 << "APD90_1st_quad\t"
00255                                 << "APD90_3rd_quad\t"
00256                                 << "Conduction velocity (relative diffs)" << std::endl;
00257         }
00258         SetInitialConvergenceParameters();
00259 
00260         double prev_apd90_first_qn=0.0;
00261         double prev_apd90_third_qn=0.0;
00262         double prev_cond_velocity=0.0;
00263         std::vector<double> prev_voltage;
00264         std::vector<double> prev_times;
00265         PopulateStandardResult(prev_voltage, prev_times);
00266 
00267         do
00268         {
00269             CuboidMeshConstructor<DIM> constructor;
00270 
00271             //If the printing time step is too fine, then simulations become I/O bound without much improvement in accuracy
00272             double printing_step = this->PdeTimeStep;
00273 #define COVERAGE_IGNORE
00274             while (printing_step < 1.0e-4)
00275             {
00276                 printing_step *= 2.0;
00277                 std::cout<<"Warning: PrintingTimeStep increased\n";
00278             }
00279 #undef COVERAGE_IGNORE
00280             HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(this->OdeTimeStep, this->PdeTimeStep, printing_step);
00281 #define COVERAGE_IGNORE
00282             if (SimulateFullActionPotential)
00283             {
00284                 HeartConfig::Instance()->SetSimulationDuration(400.0);
00285             }
00286             else
00287             {
00288                 HeartConfig::Instance()->SetSimulationDuration(8.0);
00289             }
00290 #undef COVERAGE_IGNORE
00291             HeartConfig::Instance()->SetOutputDirectory("Convergence");
00292             HeartConfig::Instance()->SetOutputFilenamePrefix("Results");
00293 
00294             //Don't use parallel mesh for now
00295             //HeartConfig::Instance()->SetMeshFileName( constructor.Construct(this->MeshNum, mMeshWidth) );
00296 
00297             DistributedTetrahedralMesh<DIM, DIM> mesh;
00298             constructor.Construct(mesh, this->MeshNum, mMeshWidth);
00299 
00300             unsigned num_ele_across = (unsigned) SmallPow(2, this->MeshNum+2); // number of elements in each dimension
00301 
00302             AbstractCardiacCellFactory<DIM>* p_cell_factory=NULL;
00303 
00304             switch (this->Stimulus)
00305             {
00306                 case NEUMANN:
00307                 {
00308                     p_cell_factory = new ZeroStimulusCellFactory<CELL, DIM>();
00309                     break;
00310                 }
00311                 case PLANE:
00312                 {
00313                     if (this->UseAbsoluteStimulus)
00314                     {
00315                         #define COVERAGE_IGNORE
00316                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(0, this->AbsoluteStimulus, true);
00317                         #undef COVERAGE_IGNORE
00318                     }
00319                     else
00320                     {
00321                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(num_ele_across, constructor.GetWidth());
00322                     }
00323                     break;
00324                 }
00325                 case QUARTER:
00326                 {
00327                     p_cell_factory = new RampedQuarterStimulusCellFactory<CELL, DIM>(constructor.GetWidth(), num_ele_across);
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];
00398                     if (x*x<=1e-10)
00399                     {
00400                         p_bcc->AddNeumannBoundaryCondition(*iter, p_bc_stim);
00401                     }
00402                     iter++;
00403                 }
00404                 // pass the bcc to the problem
00405                 cardiac_problem.SetBoundaryConditionsContainer(p_bcc);
00406             }
00407 
00408             DisplayRun();
00409             double time_before=MPI_Wtime();
00411             //cardiac_problem.SetWriteInfo();
00412 
00413             try
00414             {
00415                 cardiac_problem.Solve();
00416             }
00417             catch (Exception e)
00418             {
00419                 #define COVERAGE_IGNORE
00421                 std::cout<<"Warning - this run threw an exception.  Check convergence results\n";
00422                 std::cout<<e.GetMessage() << std::endl;
00423                 #undef COVERAGE_IGNORE
00424             }
00425 
00426             std::cout << "Time to solve = "<<MPI_Wtime()-time_before<<" seconds\n";
00427 
00428             OutputFileHandler results_handler("Convergence", false);
00429             Hdf5DataReader results_reader = cardiac_problem.GetDataReader();
00430 
00431             {
00432                 std::vector<double> transmembrane_potential=results_reader.GetVariableOverTime("V", third_quadrant_node);
00433                 std::vector<double> time_series = results_reader.GetUnlimitedDimensionValues();
00434 
00435                 OutputFileHandler plot_file_handler("ConvergencePlots", false);
00436                 if (PetscTools::AmMaster())
00437                 {
00438                     // Write out the time series for the node at third quadrant
00439                     {
00440                         std::stringstream plot_file_name_stream;
00441                         plot_file_name_stream<< nameOfTest << "_Third_quadrant_node_run_"<< file_num << ".csv";
00442                         out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
00443                         for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
00444                         {
00445                             (*p_plot_file) << time_series[data_point] << "\t" << transmembrane_potential[data_point] << "\n";
00446                         }
00447                         p_plot_file->close();
00448                     }
00449                     // Write time series for first quadrant node
00450                     {
00451                         std::vector<double> transmembrane_potential_1qd=results_reader.GetVariableOverTime("V", first_quadrant_node);
00452                         std::vector<double> time_series_1qd = results_reader.GetUnlimitedDimensionValues();
00453                         std::stringstream plot_file_name_stream;
00454                         plot_file_name_stream<< nameOfTest << "_First_quadrant_node_run_"<< file_num << ".csv";
00455                         out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
00456                         for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
00457                         {
00458                             (*p_plot_file) << time_series_1qd[data_point] << "\t" << transmembrane_potential_1qd[data_point] << "\n";
00459                         }
00460                         p_plot_file->close();
00461                     }
00462                 }
00463                 // calculate conduction velocity and APD90 error
00464                 PropagationPropertiesCalculator ppc(&results_reader);
00465 
00466                 try
00467                 {
00468                     #define COVERAGE_IGNORE
00469                     if (SimulateFullActionPotential)
00470                     {
00471                         Apd90FirstQn = ppc.CalculateActionPotentialDuration(90.0, first_quadrant_node);
00472                         Apd90ThirdQn = ppc.CalculateActionPotentialDuration(90.0, third_quadrant_node);
00473                     }
00474                     #undef COVERAGE_IGNORE
00475                     ConductionVelocity  = ppc.CalculateConductionVelocity(first_quadrant_node,third_quadrant_node,0.5*mesh_width);
00476                 }
00477                 catch (Exception e)
00478                 {
00479                     #define COVERAGE_IGNORE
00480                     std::cout<<"Warning - this run threw an exception in calculating propagation.  Check convergence results\n";
00481                     std::cout<<e.GetMessage() << std::endl;
00482                     #undef COVERAGE_IGNORE
00483                 }
00484                 double cond_velocity_error = 1e10;
00485                 double apd90_first_qn_error = 1e10;
00486                 double apd90_third_qn_error = 1e10;
00487 
00488                 if (this->PopulatedResult)
00489                 {
00490                     if (prev_cond_velocity != 0.0)
00491                     {
00492                         cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity;
00493                     }
00494 #define COVERAGE_IGNORE
00495                     if (prev_apd90_first_qn != 0.0)
00496                     {
00497                         apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn;
00498                     }
00499                     if (prev_apd90_third_qn != 0.0)
00500                     {
00501                         apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn;
00502                     }
00503                     if (apd90_first_qn_error == 0.0)
00504                     {
00505                         apd90_first_qn_error = DBL_EPSILON; //Avoid log zero on plot
00506                     }
00507                     if (apd90_third_qn_error == 0.0)
00508                     {
00509                         apd90_third_qn_error = DBL_EPSILON; //Avoid log zero on plot
00510                     }
00511 #undef COVERAGE_IGNORE
00512                     if (cond_velocity_error == 0.0)
00513                     {
00514                         cond_velocity_error = DBL_EPSILON; //Avoid log zero on plot
00515                     }
00516                 }
00517 
00518                 prev_cond_velocity = ConductionVelocity;
00519                 prev_apd90_first_qn = Apd90FirstQn;
00520                 prev_apd90_third_qn = Apd90ThirdQn;
00521 
00522                 // calculate l2norm
00523                 double max_abs_error = 0;
00524                 double sum_sq_abs_error =0;
00525                 double sum_sq_prev_voltage = 0;
00526                 double sum_sq_abs_error_full =0;
00527                 double sum_sq_prev_voltage_full = 0;
00528                 if (this->PopulatedResult)
00529                 {
00530                     //If the PDE step is varying then we'll have twice as much data now as we use to have
00531 
00532                     unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1);
00533                     assert (time_factor == 1 || time_factor == 2 || time_factor == 8);
00534                     //Iterate over the shorter time series data
00535                     for (unsigned data_point = 0; data_point<prev_times.size(); data_point++)
00536                     {
00537                         unsigned this_data_point=time_factor*data_point;
00538 
00539                         assert(time_series[this_data_point] == prev_times[data_point]);
00540                         double abs_error = fabs(transmembrane_potential[this_data_point]-prev_voltage[data_point]);
00541                         max_abs_error = (abs_error > max_abs_error) ? abs_error : max_abs_error;
00542                         //Only do resolve the upstroke...
00543                         sum_sq_abs_error_full += abs_error*abs_error;
00544                         sum_sq_prev_voltage_full += prev_voltage[data_point] * prev_voltage[data_point];
00545                         if (time_series[this_data_point] <= 8.0)
00546                         {
00547                             //In most regular cases we always do this, since the simulation stops at ms
00548                             sum_sq_abs_error += abs_error*abs_error;
00549                             sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point];
00550                         }
00551                     }
00552 
00553                 }
00554                 if (!this->PopulatedResult || !FixedResult)
00555                 {
00556                     prev_voltage = transmembrane_potential;
00557                     prev_times = time_series;
00558                 }
00559 
00560                 if (this->PopulatedResult)
00561                 {
00562 
00563                     if (PetscTools::AmMaster())
00564                     {
00565                         (*p_conv_info_file) << std::setprecision(8)
00566                                             << Abscissa() << "\t"
00567                                             << sqrt(sum_sq_abs_error_full/sum_sq_prev_voltage_full) << "\t"
00568                                             << sqrt(sum_sq_abs_error/sum_sq_prev_voltage) << "\t"
00569                                             << max_abs_error << "\t"
00570                                             << Apd90FirstQn <<" "<< apd90_first_qn_error <<""<< "\t"
00571                                             << Apd90ThirdQn <<" "<< apd90_third_qn_error <<""<< "\t"
00572                                             << ConductionVelocity <<" "<< cond_velocity_error  <<""<< std::endl;
00573                     }
00574                     // convergence criterion
00575                     this->Converged = sum_sq_abs_error/sum_sq_prev_voltage<this->RelativeConvergenceCriterion;
00576                     this->LastDifference=sum_sq_abs_error/sum_sq_prev_voltage;
00577 #define COVERAGE_IGNORE
00578                     if (time_series.size() == 1u)
00579                     {
00580                         std::cout<<"Failed after successful convergence - give up this convergence test\n";
00581                         break;
00582                     }
00583 #undef COVERAGE_IGNORE
00584 
00585                 }
00586 
00587                 if (!this->PopulatedResult)
00588                 {
00589                     this->PopulatedResult=true;
00590 
00591                 }
00592             }
00593 
00594             // Get ready for the next test by halving the time step
00595             if (!this->Converged)
00596             {
00597                 UpdateConvergenceParameters();
00598                 file_num++;
00599             }
00600             delete p_cell_factory;
00601         }
00602         while (!GiveUpConvergence() && !this->Converged);
00603 
00604 
00605         if (PetscTools::AmMaster())
00606         {
00607             p_conv_info_file->close();
00608 
00609             std::cout << "Results: " << std::endl;
00610             EXPECT0(system, "cat " + conv_info_handler.GetOutputDirectoryFullPath() + nameOfTest + "_info.csv");
00611         }
00612 
00613     }
00614 
00615     void DisplayRun()
00616     {
00617         unsigned num_ele_across = (unsigned) SmallPow(2, this->MeshNum+2);// number of elements in each dimension
00618         double scaling = mMeshWidth/(double) num_ele_across;
00619 
00620         std::cout<<"================================================================================"<<std::endl;
00621         std::cout<<"Solving in "<<DIM<<"D\t";
00622         std::cout<<"Space step "<< scaling << " cm (mesh " << this->MeshNum << ")" << "\n";
00623         std::cout<<"PDE step "<<this->PdeTimeStep<<" ms"<<"\t";
00624         std::cout<<"ODE step "<<this->OdeTimeStep<<" ms"<<"\t";
00625         if (HeartConfig::Instance()->GetUseAbsoluteTolerance())
00626         {
00627             std::cout<<"KSP absolute "<<HeartConfig::Instance()->GetAbsoluteTolerance()<<"\t";
00628         }
00629         else
00630         {
00631             std::cout<<"KSP relative "<<HeartConfig::Instance()->GetRelativeTolerance()<<"\t";
00632         }
00633         switch (this->Stimulus)
00634         {
00635             case PLANE:
00636             std::cout<<"Stimulus = Plane\n";
00637             break;
00638 
00639             case QUARTER:
00640             std::cout<<"Stimulus = Ramped first quarter\n";
00641             break;
00642 
00643             case NEUMANN:
00644             std::cout<<"Stimulus = Neumann\n";
00645             break;
00646 
00647         }
00648         EXPECT0(system, "date");//To keep track of what Nightly things are doing
00651         if (this->UseAbsoluteStimulus)
00652         {
00653             #define COVERAGE_IGNORE
00654             std::cout<<"Using absolute stimulus of "<<this->AbsoluteStimulus<<std::endl;
00655             #undef COVERAGE_IGNORE
00656         }
00657         std::cout << std::flush;
00658         //HeartEventHandler::Headings();
00659         //HeartEventHandler::Report();
00660 
00661     }
00662 
00663 public:
00664     virtual ~AbstractConvergenceTester() {}
00665 
00667     virtual void SetInitialConvergenceParameters()=0;
00669     virtual void UpdateConvergenceParameters()=0;
00671     virtual bool GiveUpConvergence()=0;
00673     virtual double Abscissa()=0;
00680     virtual void PopulateStandardResult(std::vector<double> &result, std::vector<double> &times)
00681     {
00682         assert(this->PopulatedResult==false);
00683         assert(result.size()==0);
00684         assert(times.size()==0);
00685     }
00686 
00690     bool IsConverged()
00691     {
00692         return Converged;
00693     }
00694 
00698     void SetMeshWidth(double meshWidth)
00699     {
00700         mMeshWidth=meshWidth;
00701     }
00702 };
00703 
00704 #endif /*ABSTRACTCONVERGENCETESTER_HPP_*/

Generated by  doxygen 1.6.2