AbstractConvergenceTester.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
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 "TetrahedralMesh.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 "OutputFileHandler.hpp"
00052 #include "ZeroStimulusCellFactory.hpp"
00053 #include "SimpleStimulus.hpp"
00054 #include "ConstBoundaryCondition.hpp"
00055 #include "StimulusBoundaryCondition.hpp"
00056 
00057 
00058 typedef enum StimulusType_
00059 {
00060     PLANE=0,
00061     REGION,
00062     NEUMANN
00063 } StimulusType;
00064 
00069 template <class CELL, unsigned DIM>
00070 class QuarterStimulusCellFactory : public AbstractCardiacCellFactory<DIM>
00071 {
00072 private:
00074     boost::shared_ptr<SimpleStimulus> mpStimulus;
00076     double mMeshWidth;
00077 public:
00078 
00083     QuarterStimulusCellFactory(double meshWidth)
00084         : AbstractCardiacCellFactory<DIM>(),
00085           mpStimulus(new SimpleStimulus(-1000000, 0.5)),
00086           mMeshWidth(meshWidth)
00087     {
00088     }
00089 
00100     AbstractCardiacCell* CreateCardiacCellForTissueNode(unsigned node)
00101     {
00102         double x = this->GetMesh()->GetNode(node)->GetPoint()[0];
00103         if (x<=mMeshWidth*0.25+1e-10)
00104         {
00105             return new CELL(this->mpSolver, this->mpStimulus);
00106         }
00107         else
00108         {
00109             return new CELL(this->mpSolver, this->mpZeroStimulus);
00110         }
00111     }
00112 };
00113 
00114 
00119 class AbstractUntemplatedConvergenceTester
00120 {
00121 protected:
00123     double mMeshWidth;
00124 public:
00126     double OdeTimeStep;
00128     double PdeTimeStep;
00133     unsigned MeshNum;
00134     double RelativeConvergenceCriterion; 
00135     double LastDifference; 
00136     double Apd90FirstQn; 
00137     double Apd90ThirdQn; 
00138     double ConductionVelocity;  
00142     bool PopulatedResult;
00146     bool FixedResult;
00150     bool UseAbsoluteStimulus; 
00155     double AbsoluteStimulus;
00156     bool SimulateFullActionPotential; 
00157     bool Converged; 
00158     StimulusType Stimulus; 
00159     double NeumannStimulus; 
00161     AbstractUntemplatedConvergenceTester();
00162     
00168     virtual void Converge(std::string nameOfTest)=0;
00169 
00170     virtual ~AbstractUntemplatedConvergenceTester();
00171 };
00172 
00176 template<class CARDIAC_PROBLEM, unsigned DIM>
00177 void SetConductivities(CARDIAC_PROBLEM& rCardiacProblem);
00178 
00179 template<unsigned DIM>
00180 void SetConductivities(BidomainProblem<DIM>& rProblem)
00181 {
00182     c_vector<double, DIM> conductivities;
00183     for (unsigned i=0; i<DIM; i++)
00184     {
00185         conductivities[i] = 1.75;
00186     }
00187     HeartConfig::Instance()->SetIntracellularConductivities(conductivities);
00188 
00189     for (unsigned i=0; i<DIM; i++)
00190     {
00191         conductivities[i] = 7.0;
00192     }
00193     HeartConfig::Instance()->SetExtracellularConductivities(conductivities);
00194 }
00195 
00196 template<unsigned DIM>
00197 void SetConductivities(MonodomainProblem<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 
00211 template<class CELL, class CARDIAC_PROBLEM, unsigned DIM, unsigned PROBLEM_DIM>
00212 class AbstractConvergenceTester : public AbstractUntemplatedConvergenceTester
00213 {
00214 public:
00219     void Converge(std::string nameOfTest)
00220     {
00221         std::cout << "=========================== Beginning Test...==================================\n";
00222         // Create the meshes on which the test will be based
00223         const std::string mesh_dir = "ConvergenceMesh";
00224         OutputFileHandler output_file_handler(mesh_dir);
00225         ReplicatableVector voltage_replicated;
00226 
00227         unsigned file_num=0;
00228 
00229         // Create a file for storing conduction velocity and AP data and write the header
00230         OutputFileHandler conv_info_handler("ConvergencePlots", false);
00231         out_stream p_conv_info_file;
00232         if (conv_info_handler.IsMaster())
00233         {
00234             p_conv_info_file = conv_info_handler.OpenOutputFile(nameOfTest+"_info.csv");
00235             (*p_conv_info_file) << "#Abcisa\t"
00236                                 << "l2-norm-full\t"
00237                                 << "l2-norm-onset\t"
00238                                 << "Max absolute err\t"
00239                                 << "APD90_1st_quad\t"
00240                                 << "APD90_3rd_quad\t"
00241                                 << "Conduction velocity (relative diffs)" << std::endl;
00242         }
00243         SetInitialConvergenceParameters();
00244 
00245         double prev_apd90_first_qn=0.0;
00246         double prev_apd90_third_qn=0.0;
00247         double prev_cond_velocity=0.0;
00248         std::vector<double> prev_voltage;
00249         std::vector<double> prev_times;
00250         PopulateStandardResult(prev_voltage, prev_times);
00251 
00252         do
00253         {
00254             CuboidMeshConstructor<DIM> constructor;
00255             
00256             //If the printing time step is too fine, then simulations become I/O bound without much improvement in accuracy
00257             double printing_step = this->PdeTimeStep;
00258 #define COVERAGE_IGNORE
00259             while (printing_step < 1.0e-4)
00260             {
00261                 printing_step *= 2.0;
00262                 std::cout<<"Warning: PrintingTimeStep increased\n";
00263             }
00264 #undef COVERAGE_IGNORE
00265             HeartConfig::Instance()->SetOdePdeAndPrintingTimeSteps(this->OdeTimeStep, this->PdeTimeStep, printing_step);
00266 #define COVERAGE_IGNORE
00267             if (SimulateFullActionPotential)
00268             {
00269                 HeartConfig::Instance()->SetSimulationDuration(400.0);
00270             }
00271             else
00272             {
00273                 HeartConfig::Instance()->SetSimulationDuration(8.0);
00274             }
00275 #undef COVERAGE_IGNORE
00276             HeartConfig::Instance()->SetOutputDirectory ("Convergence");
00277             HeartConfig::Instance()->SetOutputFilenamePrefix ("Results");
00278 
00279             //Don't use parallel mesh for now
00280             //HeartConfig::Instance()->SetMeshFileName( constructor.Construct(this->MeshNum, mMeshWidth) );
00281 
00282             TetrahedralMesh<DIM, DIM> mesh;
00283             TrianglesMeshReader<DIM, DIM> mesh_reader(constructor.Construct(this->MeshNum, mMeshWidth) );
00284             mesh.ConstructFromMeshReader(mesh_reader);
00285 
00286             unsigned num_ele_across = (unsigned) pow(2, this->MeshNum+2); // number of elements in each dimension
00287 
00288             AbstractCardiacCellFactory<DIM>* p_cell_factory=NULL;
00289 
00290             switch (this->Stimulus)
00291             {
00292                 case NEUMANN:
00293                 {
00294                     p_cell_factory = new ZeroStimulusCellFactory<CELL, DIM>();
00295                     break;
00296                 }
00297                 case PLANE:
00298                 {
00299                     if (this->UseAbsoluteStimulus)
00300                     {
00301                         #define COVERAGE_IGNORE
00302                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(0, this->AbsoluteStimulus, true);
00303                         #undef COVERAGE_IGNORE
00304                     }
00305                     else
00306                     {
00307                         p_cell_factory = new GeneralPlaneStimulusCellFactory<CELL, DIM>(num_ele_across, constructor.GetWidth());
00308                     }
00309                     break;
00310                 }
00311                 case REGION:
00312                 {
00313                     p_cell_factory = new QuarterStimulusCellFactory<CELL, DIM>(constructor.GetWidth());
00314                     break;
00315                 }
00316             }
00317 
00318 
00319             CARDIAC_PROBLEM cardiac_problem(p_cell_factory);
00321             cardiac_problem.SetMesh(&mesh);
00322 
00323             // Calculate positions of nodes 1/4 and 3/4 through the mesh
00324             unsigned third_quadrant_node;
00325             unsigned first_quadrant_node;
00326             switch(DIM)
00327             {
00328                 case 1:
00329                 {
00330                     first_quadrant_node = (unsigned) (0.25*constructor.NumElements);
00331                     third_quadrant_node = (unsigned) (0.75*constructor.NumElements);
00332                     break;
00333                 }
00334                 case 2:
00335                 {
00336                     unsigned n= (unsigned) pow (2, this->MeshNum+2);
00337                     first_quadrant_node =   (n+1)*(n/2)+  n/4 ;
00338                     third_quadrant_node =   (n+1)*(n/2)+3*n/4 ;
00339                     break;
00340                 }
00341                 case 3:
00342                 {
00343                     const unsigned first_quadrant_nodes_3d[5]={61, 362, 2452, 17960, 137296};
00344                     const unsigned third_quadrant_nodes_3d[5]={63, 366, 2460, 17976, 137328};
00345                     assert(this->PdeTimeStep<5);
00346                     first_quadrant_node = first_quadrant_nodes_3d[this->MeshNum];
00347                     third_quadrant_node = third_quadrant_nodes_3d[this->MeshNum];
00348                     break;
00349                 }
00350 
00351                 default:
00352                     NEVER_REACHED;
00353             }
00354 
00355             double mesh_width=constructor.GetWidth();
00356 
00357             // We only need the output of these two nodes
00358             std::vector<unsigned> nodes_to_be_output;
00359             nodes_to_be_output.push_back(first_quadrant_node);
00360             nodes_to_be_output.push_back(third_quadrant_node);
00361             cardiac_problem.SetOutputNodes(nodes_to_be_output);
00362   
00363             // The results of the tests were originally obtained with the following conductivity
00364             // values. After implementing fibre orientation the defaults changed. Here we set
00365             // the former ones to be used.
00366             SetConductivities(cardiac_problem);
00367 
00368             cardiac_problem.Initialise();
00369 
00370             #ifndef NDEBUG
00371             Node<DIM>* fqn = cardiac_problem.rGetMesh().GetNode(first_quadrant_node);
00372             Node<DIM>* tqn = cardiac_problem.rGetMesh().GetNode(third_quadrant_node);
00373             assert(fqn->rGetLocation()[0]==0.25*mesh_width);
00374             assert(fabs(tqn->rGetLocation()[0] - 0.75*mesh_width) < 1e-10);
00375             for (unsigned coord=1; coord<DIM; coord++)
00376             {
00377                 assert(fqn->rGetLocation()[coord]==0.5*mesh_width);
00378                 assert(tqn->rGetLocation()[coord]==0.5*mesh_width);
00379             }
00380             #endif
00381 
00382             BoundaryConditionsContainer<DIM,DIM,PROBLEM_DIM> bcc;
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                         bcc.AddNeumannBoundaryCondition(*iter, p_bc_stim);
00400                     }
00401                     iter++;
00402                 }
00403                 // pass the bcc to the problem
00404                 cardiac_problem.SetBoundaryConditionsContainer(&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                 // Write out the time series for the node at third quadrant
00435                 if (results_handler.IsMaster())
00436                 {
00437                     OutputFileHandler plot_file_handler("ConvergencePlots", false);
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 
00448                 // Write time series for first quadrant node
00449                 if (results_handler.IsMaster())
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                     OutputFileHandler plot_file_handler("ConvergencePlots", false);
00454                     std::stringstream plot_file_name_stream;
00455                     plot_file_name_stream<< nameOfTest << "_First_quadrant_node_run_"<< file_num << ".csv";
00456                     out_stream p_plot_file = plot_file_handler.OpenOutputFile(plot_file_name_stream.str());
00457                     for (unsigned data_point = 0; data_point<time_series.size(); data_point++)
00458                     {
00459                         (*p_plot_file) << time_series_1qd[data_point] << "\t" << transmembrane_potential_1qd[data_point] << "\n";
00460                     }
00461                     p_plot_file->close();
00462                 }
00463 
00464                 // calculate conduction velocity and APD90 error
00465                 PropagationPropertiesCalculator ppc(&results_reader);
00466 
00467 
00468                 try
00469                 {
00470                     #define COVERAGE_IGNORE
00471                     if (SimulateFullActionPotential)
00472                     {
00473                         Apd90FirstQn = ppc.CalculateActionPotentialDuration(90.0, first_quadrant_node);
00474                         Apd90ThirdQn = ppc.CalculateActionPotentialDuration(90.0, third_quadrant_node);
00475                     }
00476                     #undef COVERAGE_IGNORE
00477                     ConductionVelocity  = ppc.CalculateConductionVelocity(first_quadrant_node,third_quadrant_node,0.5*mesh_width);
00478                 }
00479                 catch (Exception e)
00480                 {
00481                     #define COVERAGE_IGNORE
00482                     std::cout<<"Warning - this run threw an exception in calculating propagation.  Check convergence results\n";
00483                     std::cout<<e.GetMessage() << std::endl;
00484                     #undef COVERAGE_IGNORE
00485                 }
00486                 double cond_velocity_error = 1e10;
00487                 double apd90_first_qn_error = 1e10;
00488                 double apd90_third_qn_error = 1e10;
00489                 
00490                 if (this->PopulatedResult)
00491                 {
00492                     if (prev_cond_velocity != 0.0)
00493                     {
00494                         cond_velocity_error = fabs(ConductionVelocity - prev_cond_velocity) / prev_cond_velocity;
00495                     }
00496 #define COVERAGE_IGNORE                    
00497                     if (prev_apd90_first_qn != 0.0)
00498                     {
00499                         apd90_first_qn_error = fabs(Apd90FirstQn - prev_apd90_first_qn) / prev_apd90_first_qn;
00500                     }
00501                     if (prev_apd90_third_qn != 0.0)
00502                     {
00503                         apd90_third_qn_error = fabs(Apd90ThirdQn - prev_apd90_third_qn) / prev_apd90_third_qn;
00504                     }
00505                     if (apd90_first_qn_error == 0.0)
00506                     {
00507                         apd90_first_qn_error = DBL_EPSILON; //Avoid log zero on plot
00508                     }
00509                     if (apd90_third_qn_error == 0.0)
00510                     {
00511                         apd90_third_qn_error = DBL_EPSILON; //Avoid log zero on plot
00512                     }
00513 #undef COVERAGE_IGNORE                    
00514                     if (cond_velocity_error == 0.0)
00515                     {
00516                         cond_velocity_error = DBL_EPSILON; //Avoid log zero on plot
00517                     }
00518                 }
00519 
00520                 prev_cond_velocity = ConductionVelocity;
00521                 prev_apd90_first_qn = Apd90FirstQn;
00522                 prev_apd90_third_qn = Apd90ThirdQn;
00523 
00524                 // calculate l2norm
00525                 double max_abs_error = 0;
00526                 double sum_sq_abs_error =0;
00527                 double sum_sq_prev_voltage = 0;
00528                 double sum_sq_abs_error_full =0;
00529                 double sum_sq_prev_voltage_full = 0;
00530                 if (this->PopulatedResult)
00531                 {
00532                     //If the PDE step is varying then we'll have twice as much data now as we use to have
00533                     
00534                     unsigned time_factor=(time_series.size()-1) / (prev_times.size()-1);               
00535                     assert (time_factor == 1 || time_factor == 2 || time_factor == 8);
00536                     //Iterate over the shorter time series data
00537                     for (unsigned data_point = 0; data_point<prev_times.size(); data_point++)
00538                     {
00539                         unsigned this_data_point=time_factor*data_point;
00540                        
00541                         assert(time_series[this_data_point] == prev_times[data_point]);
00542                         double abs_error = fabs(transmembrane_potential[this_data_point]-prev_voltage[data_point]);
00543                         max_abs_error = (abs_error > max_abs_error) ? abs_error : max_abs_error;
00544                         //Only do resolve the upstroke...
00545                         sum_sq_abs_error_full += abs_error*abs_error;
00546                         sum_sq_prev_voltage_full += prev_voltage[data_point] * prev_voltage[data_point];
00547                         if (time_series[this_data_point] <= 8.0)
00548                         {   
00549                             //In most regular cases we always do this, since the simulation stops at ms
00550                             sum_sq_abs_error += abs_error*abs_error;
00551                             sum_sq_prev_voltage += prev_voltage[data_point] * prev_voltage[data_point];
00552                         }
00553                     }
00554 
00555                 }
00556                 if (!this->PopulatedResult || !FixedResult)
00557                 {
00558                     prev_voltage = transmembrane_potential;
00559                     prev_times = time_series;
00560                 }
00561 
00562                 if (this->PopulatedResult)
00563                 {
00564 
00565                     if (conv_info_handler.IsMaster())
00566                     {
00567                         (*p_conv_info_file) << std::setprecision(8)
00568                                             << Abscissa() << "\t"
00569                                             << sqrt(sum_sq_abs_error_full/sum_sq_prev_voltage_full) << "\t"
00570                                             << sqrt(sum_sq_abs_error/sum_sq_prev_voltage) << "\t"
00571                                             << max_abs_error << "\t"
00572                                             << Apd90FirstQn <<" "<< apd90_first_qn_error <<""<< "\t"
00573                                             << Apd90ThirdQn <<" "<< apd90_third_qn_error <<""<< "\t"
00574                                             << ConductionVelocity <<" "<< cond_velocity_error  <<""<< std::endl;
00575                     }
00576                     // convergence criterion
00577                     this->Converged = sum_sq_abs_error/sum_sq_prev_voltage<this->RelativeConvergenceCriterion;
00578                     this->LastDifference=sum_sq_abs_error/sum_sq_prev_voltage;
00579 #define COVERAGE_IGNORE
00580                     if (time_series.size() == 1u)
00581                     {
00582                         std::cout<<"Failed after successful convergence - give up this convergence test\n";
00583                         break;
00584                     }
00585 #undef COVERAGE_IGNORE
00586 
00587                 }
00588 
00589                 if (!this->PopulatedResult)
00590                 {
00591                     this->PopulatedResult=true;
00592 
00593                 }
00594             }
00595 
00596             // Get ready for the next test by halving the time step
00597             if (!this->Converged)
00598             {
00599                 UpdateConvergenceParameters();
00600                 file_num++;
00601             }
00602             delete p_cell_factory;
00603         }
00604         while (!GiveUpConvergence() && !this->Converged);
00605 
00606 
00607         if (conv_info_handler.IsMaster())
00608         {
00609             p_conv_info_file->close();
00610 
00611             std::cout << "Results: " << std::endl;
00612             EXPECT0(system, "cat " + conv_info_handler.GetOutputDirectoryFullPath() + nameOfTest + "_info.csv");
00613         }
00614 
00615     }
00616 
00617     void DisplayRun()
00618     {
00619         unsigned num_ele_across = (unsigned) pow(2, this->MeshNum+2);// number of elements in each dimension
00620         double scaling = mMeshWidth/(double) num_ele_across;
00621 
00622         std::cout<<"================================================================================"<<std::endl;
00623         std::cout<<"Solving in "<<DIM<<"D\t";
00624         std::cout<<"Space step "<< scaling << " cm (mesh " << this->MeshNum << ")" << "\n";
00625         std::cout<<"PDE step "<<this->PdeTimeStep<<" ms"<<"\t";
00626         std::cout<<"ODE step "<<this->OdeTimeStep<<" ms"<<"\t";
00627         if (HeartConfig::Instance()->GetUseAbsoluteTolerance())
00628         {
00629             std::cout<<"KSP absolute "<<HeartConfig::Instance()->GetAbsoluteTolerance()<<"\t";
00630         }
00631         else
00632         {
00633             std::cout<<"KSP relative "<<HeartConfig::Instance()->GetRelativeTolerance()<<"\t";
00634         }
00635         switch (this->Stimulus)
00636         {
00637             case PLANE:
00638             std::cout<<"Stimulus = Plane\n";
00639             break;
00640 
00641             case REGION:
00642             std::cout<<"Stimulus = Region\n";
00643             break;
00644 
00645             case NEUMANN:
00646             std::cout<<"Stimulus = Neumann\n";
00647             break;
00648 
00649         }
00650         EXPECT0(system, "date");//To keep track of what Nightly things are doing
00653         if (this->UseAbsoluteStimulus)
00654         {
00655             #define COVERAGE_IGNORE
00656             std::cout<<"Using absolute stimulus of "<<this->AbsoluteStimulus<<std::endl;
00657             #undef COVERAGE_IGNORE
00658         }
00659         std::cout << std::flush;
00660         //HeartEventHandler::Headings();
00661         //HeartEventHandler::Report();
00662 
00663     }
00664 
00665 public:
00666     virtual ~AbstractConvergenceTester() {}
00667 
00669     virtual void SetInitialConvergenceParameters()=0;
00671     virtual void UpdateConvergenceParameters()=0;
00673     virtual bool GiveUpConvergence()=0;
00675     virtual double Abscissa()=0;
00682     virtual void PopulateStandardResult(std::vector<double> &result, std::vector<double> &times)
00683     {
00684         assert(this->PopulatedResult==false);
00685         assert(result.size()==0);
00686         assert(times.size()==0);
00687     }
00688 
00692     bool IsConverged()
00693     {
00694         return Converged;
00695     }
00696 
00700     void SetMeshWidth(double meshWidth)
00701     {
00702         mMeshWidth=meshWidth;
00703     }
00704 };
00705 
00706 #endif /*ABSTRACTCONVERGENCETESTER_HPP_*/

Generated on Tue Aug 4 16:10:21 2009 for Chaste by  doxygen 1.5.5