AbstractConvergenceTester.hpp

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

Generated by  doxygen 1.6.2