AbstractConvergenceTester.hpp

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

Generated by  doxygen 1.6.2