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