Chaste Release::3.1
AdaptiveBidomainProblem.cpp
00001 /*
00002 
00003 Copyright (C) Fujitsu Laboratories of Europe, 2009-2010
00004 
00005 */
00006 
00007 /*
00008 
00009 Copyright (c) 2005-2012, University of Oxford.
00010 All rights reserved.
00011 
00012 University of Oxford means the Chancellor, Masters and Scholars of the
00013 University of Oxford, having an administrative office at Wellington
00014 Square, Oxford OX1 2JD, UK.
00015 
00016 This file is part of Chaste.
00017 
00018 Redistribution and use in source and binary forms, with or without
00019 modification, are permitted provided that the following conditions are met:
00020  * Redistributions of source code must retain the above copyright notice,
00021    this list of conditions and the following disclaimer.
00022  * Redistributions in binary form must reproduce the above copyright notice,
00023    this list of conditions and the following disclaimer in the documentation
00024    and/or other materials provided with the distribution.
00025  * Neither the name of the University of Oxford nor the names of its
00026    contributors may be used to endorse or promote products derived from this
00027    software without specific prior written permission.
00028 
00029 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00030 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00031 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00032 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00033 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00034 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00035 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00036 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00037 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00038 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039 
00040 */
00041 
00042 
00043 
00044 #ifdef CHASTE_ADAPTIVITY
00045 
00046 #include "AdaptiveBidomainProblem.hpp"
00047 #include "BidomainSolver.hpp"
00048 
00049 #include "VtkMeshWriter.hpp"
00050 #include "TetrahedralMesh.hpp"
00051 #include "BidomainTissue.hpp"
00052 #include "HeartRegionCodes.hpp"
00053 #include "HeartConfig.hpp"
00054 #include "Exception.hpp"
00055 #include "DistributedVector.hpp"
00056 #include "ReplicatableVector.hpp"
00057 #include "ProgressReporter.hpp"
00058 #include "PetscTools.hpp"
00059 #include "RegularStimulus.hpp"
00060 
00061 AdaptiveBidomainProblem::AdaptiveBidomainProblem(
00062             AbstractCardiacCellFactory<3>* pCellFactory, bool hasBath)
00063     : BidomainProblem<3>(pCellFactory, hasBath),
00064       mIsMeshAdapting(true),
00065       mInitializeFromVtu(false),
00066       mUseNeumannBoundaryConditions(false),
00067       mNeumannStimulusIndex(0),
00068       mNeumannStimulusLowerValue(DBL_MAX),
00069       mNeumannStimulusUpperValue(-DBL_MAX),
00070       mNeumannStimulusMagnitude(0.0),
00071       mNeumannStimulusDuration(0.0),
00072       mNeumannStimulusPeriod(DBL_MAX)
00073 //      mGoodEdgeRange(0.0),
00074 //      mBadEdgeCriterion(0.0)
00075 {
00076     mFixedExtracellularPotentialNodes.resize(0);
00077     mpAdaptiveMesh = new AdaptiveTetrahedralMesh;
00078 }
00079 
00080 AdaptiveBidomainProblem::~AdaptiveBidomainProblem()
00081 {
00082     delete mpAdaptiveMesh;
00083 }
00084 
00085 void AdaptiveBidomainProblem::DoNotAdaptMesh()
00086 {
00087     mIsMeshAdapting = false;
00088 }
00089 
00090 //void AdaptiveBidomainProblem::SetAdaptCriterion(double range, double criterion)
00091 //{
00092 //    mGoodEdgeRange = range;
00093 //    mBadEdgeCriterion = criterion;
00094 //}
00095 
00096 void AdaptiveBidomainProblem::AddCurrentSolutionToAdaptiveMesh( Vec solution )
00097 {
00098     HeartEventHandler::BeginEvent(HeartEventHandler::USER1);
00099 
00100     ReplicatableVector replicatable_solution( solution );
00101     std::vector<double> vm_for_vtk, phi_for_vtk;
00102     vm_for_vtk.resize(mpMesh->GetNumNodes());
00103     phi_for_vtk.resize(mpMesh->GetNumNodes());
00104 
00105     for (AbstractTetrahedralMesh<3,3>::NodeIterator it=mpMesh->GetNodeIteratorBegin();
00106          it != mpMesh->GetNodeIteratorEnd();
00107          ++it)
00108     {
00109         vm_for_vtk[it->GetIndex()]  = replicatable_solution[2*it->GetIndex()];
00110         phi_for_vtk[it->GetIndex()] = replicatable_solution[2*it->GetIndex()+1];
00111     }
00112     mpAdaptiveMesh->AddPointData("Vm", vm_for_vtk);
00113     mpAdaptiveMesh->AddPointData("Phi", phi_for_vtk);
00114 
00115     std::vector<std::string> state_variable_names = mpBidomainTissue->GetCardiacCell(0)->rGetStateVariableNames();
00116     unsigned number_of_state_variables = state_variable_names.size();
00117     std::vector< std::vector<double> > state_variable_values;
00118     state_variable_values.resize( mpMesh->GetNumNodes() );
00119 
00120     // add state variable to vtu file as point data
00121     for (unsigned variable=0; variable<number_of_state_variables; variable++)
00122     {
00123         if (variable != mpBidomainTissue->GetCardiacCell(0)->GetVoltageIndex())
00124         {
00125             std::vector<double> variable_for_vtk;
00126             variable_for_vtk.resize(mpMesh->GetNumNodes());
00127             for (AbstractTetrahedralMesh<3,3>::NodeIterator it=mpMesh->GetNodeIteratorBegin();
00128                  it != mpMesh->GetNodeIteratorEnd();
00129                  ++it)
00130             {
00131                 variable_for_vtk[it->GetIndex()] = mpBidomainTissue->GetCardiacCell(it->GetIndex())->GetStdVecStateVariables()[variable];
00132             }
00133             mpAdaptiveMesh->AddPointData(state_variable_names[variable], variable_for_vtk);
00134         }
00135     }
00136 
00137     HeartEventHandler::EndEvent(HeartEventHandler::USER1);
00138 }
00139 
00140 void AdaptiveBidomainProblem::InitializeSolutionOnAdaptedMesh( VtkMeshReader<3,3>* reader )
00141 {
00142     HeartEventHandler::BeginEvent(HeartEventHandler::USER1);
00143 
00144     std::vector<double> adapted_vm, adapted_phi;
00145 
00146     reader->GetPointData("Vm", adapted_vm);
00147     reader->GetPointData("Phi", adapted_phi);
00148 
00149     Vec solution = mpMesh->GetDistributedVectorFactory()->CreateVec(2);
00150     DistributedVector nic = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(solution);
00151     std::vector<DistributedVector::Stripe> stripe;
00152     stripe.reserve(2);
00153 
00154     for (unsigned i=0; i<2; i++)
00155     {
00156         stripe.push_back(DistributedVector::Stripe(nic, i));
00157     }
00158 
00159     for (DistributedVector::Iterator it = nic.Begin();
00160              it != nic.End();
00161              ++it)
00162     {
00163         stripe[0][it] = adapted_vm[it.Global];
00164         stripe[1][it] = adapted_phi[it.Global];
00165     }
00166 
00167     nic.Restore();
00168 
00169     std::vector<std::string> state_variable_names = mpBidomainTissue->GetCardiacCell(0)->rGetStateVariableNames();
00170     unsigned number_of_state_variables = state_variable_names.size();
00171 
00172     for (unsigned variable=0; variable<number_of_state_variables; variable++)
00173     {
00174         if (variable != mpBidomainTissue->GetCardiacCell(0)->GetVoltageIndex())
00175         {
00176             std::vector<double> adapted_state_variable;
00177             reader->GetPointData( state_variable_names[variable], adapted_state_variable);
00178 
00179             for (DistributedVector::Iterator it = nic.Begin();
00180                      it != nic.End();
00181                      ++it)
00182             {
00183                 mpBidomainTissue->GetCardiacCell(it.Global)->SetStateVariable(variable, adapted_state_variable[it.Global]);
00184             }
00185         }
00186         else
00187         {
00188             for (DistributedVector::Iterator it = nic.Begin();
00189                      it != nic.End();
00190                      ++it)
00191             {
00192                 mpBidomainTissue->GetCardiacCell(it.Global)->SetStateVariable(variable, adapted_vm[it.Global]);
00193             }
00194 
00195         }
00196     }
00197 
00198     if (mSolution)
00199     {
00200         PetscTools::Destroy(mSolution);
00201     }
00202 
00203     mSolution = solution;
00204 
00205     HeartEventHandler::EndEvent(HeartEventHandler::USER1);
00206 }
00207 
00208 void AdaptiveBidomainProblem::AdaptMesh()
00209 {
00210     HeartEventHandler::BeginEvent(HeartEventHandler::USER1);
00211     mpAdaptiveMesh->AdaptMesh();
00212     HeartEventHandler::EndEvent(HeartEventHandler::USER1);
00213 
00214     if ( mpAdaptiveMesh->GetAdaptSuccess() )
00215     {
00216         if (mWriteInfo)
00217         {
00218             HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00219             std::cout << "Adapt completed. New mesh has " << mpAdaptiveMesh->GetNumNodes() << " nodes" << std::endl;
00220             HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00221         }
00222         // Adapt succeeded, need new mesh, boundary conditions, solver
00223         delete mpMesh;
00224         DistributedTetrahedralMesh<3,3>* p_new_mesh = new DistributedTetrahedralMesh<3,3>;
00225         VtkMeshReader<3,3> mesh_reader( mpAdaptiveMesh->GetVtkUnstructuredGrid() );
00226         HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00227         p_new_mesh->ConstructFromMeshReader(mesh_reader);
00228         HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00229         mpMesh = p_new_mesh;
00230 
00231         mpCellFactory->SetMesh( mpMesh );
00232 
00233         if (mUseNeumannBoundaryConditions)
00234         {
00235             SetupNeumannBoundaryConditionOnMesh();
00236         }
00237         else
00238         {
00239             boost::shared_ptr<BoundaryConditionsContainer<3, 3, 2> > p_new_bcc(new BoundaryConditionsContainer<3, 3, 2>);
00240             for (unsigned problem_index=0; problem_index<2; problem_index++)
00241             {
00242                 p_new_bcc->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00243             }
00244             mpBoundaryConditionsContainer = p_new_bcc;
00245         }
00246 
00247         delete mpBidomainTissue;
00248         BidomainTissue<3>* new_bidomain_tissue;
00249         new_bidomain_tissue = new BidomainTissue<3>(mpCellFactory);
00250         mpBidomainTissue = new_bidomain_tissue;
00251         mpCardiacTissue = mpBidomainTissue;
00252 
00253         delete mpSolver;
00254         BidomainSolver<3,3>* p_new_solver;
00255         p_new_solver = new BidomainSolver<3,3>(false, mpMesh, mpBidomainTissue,
00256                                                mpBoundaryConditionsContainer.get(), 2);
00257         mpSolver = p_new_solver;
00258         mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00259 
00260         InitializeSolutionOnAdaptedMesh( &mesh_reader );
00261     }
00262     else
00263     {
00264         NEVER_REACHED;
00265     }
00266 }
00267 
00268 void AdaptiveBidomainProblem::SetNeumannStimulusMagnitudeAndDuration(double magnitude, double duration, double period)
00269 {
00270     mNeumannStimulusMagnitude = magnitude;
00271     mNeumannStimulusDuration  = duration;
00272     mNeumannStimulusPeriod = std::min( period, HeartConfig::Instance()->GetSimulationDuration() );
00273 }
00274 
00275 void AdaptiveBidomainProblem::UseNeumannBoundaryCondition(unsigned index)
00276 {
00277     mUseNeumannBoundaryConditions = true;
00278     mNeumannStimulusIndex = index;
00279 }
00280 
00281 double AdaptiveBidomainProblem::GetTargetError()
00282 {
00283     return HeartConfig::Instance()->GetTargetErrorForAdaptivity();
00284 }
00285 
00286 double AdaptiveBidomainProblem::GetSigma()
00287 {
00288     return HeartConfig::Instance()->GetSigmaForAdaptivity();
00289 }
00290 
00291 double AdaptiveBidomainProblem::GetMaxEdgeLength()
00292 {
00293     return HeartConfig::Instance()->GetMaxEdgeLengthForAdaptivity();
00294 }
00295 
00296 double AdaptiveBidomainProblem::GetMinEdgeLength()
00297 {
00298     return HeartConfig::Instance()->GetMinEdgeLengthForAdaptivity();
00299 }
00300 
00301 double AdaptiveBidomainProblem::GetGradation()
00302 {
00303     return HeartConfig::Instance()->GetGradationForAdaptivity();
00304 }
00305 
00306 unsigned AdaptiveBidomainProblem::GetMaxMeshNodes()
00307 {
00308     return HeartConfig::Instance()->GetMaxNodesForAdaptivity();
00309 }
00310 
00311 unsigned AdaptiveBidomainProblem::GetNumAdaptSweeps()
00312 {
00313     return HeartConfig::Instance()->GetNumberOfAdaptiveSweeps();
00314 }
00315 
00316 void AdaptiveBidomainProblem::SetupNeumannBoundaryConditionOnMesh()
00317 {
00318     boost::shared_ptr<BoundaryConditionsContainer<3, 3, 2> > p_new_bcc(new BoundaryConditionsContainer<3, 3, 2>);
00319 
00320     mpNeumannStimulusBoundaryCondition = new StimulusBoundaryCondition<3>(mpNeumannStimulus);
00321     ConstBoundaryCondition<3>* p_zero_bc = new ConstBoundaryCondition<3>(0.0);
00322 
00323     // loop over boundary elements
00324     AbstractTetrahedralMesh<3,3>::BoundaryElementIterator iter;
00325     iter = mpMesh->GetBoundaryElementIteratorBegin();
00326 
00327     while (iter != mpMesh->GetBoundaryElementIteratorEnd())
00328     {
00329         double x = ((*iter)->CalculateCentroid())[mNeumannStimulusIndex];
00331         if ( (x-mNeumannStimulusLowerValue)*(x-mNeumannStimulusLowerValue) <= 1e-10 )
00332         {
00333             p_new_bcc->AddNeumannBoundaryCondition(*iter, mpNeumannStimulusBoundaryCondition);
00334         }
00335         iter++;
00336     }
00337 
00338     // Ground other end of domain
00339     for (AbstractTetrahedralMesh<3,3>::NodeIterator node_iter=mpMesh->GetNodeIteratorBegin();
00340          node_iter != mpMesh->GetNodeIteratorEnd();
00341          ++node_iter)
00342     {
00343         if (fabs((*node_iter).rGetLocation()[mNeumannStimulusIndex] - mNeumannStimulusUpperValue) < 1e-6)
00344         {
00345             p_new_bcc->AddDirichletBoundaryCondition(&(*node_iter), p_zero_bc, 1);
00346         }
00347     }
00348 
00349     mpBoundaryConditionsContainer = p_new_bcc;
00350 }
00351 
00352 void AdaptiveBidomainProblem::LoadSimulationFromVtuFile()
00353 {
00354     mInitializeFromVtu = true;
00355     AbstractCardiacProblem<3,3,2>::Initialise();
00356 }
00357 
00358 void AdaptiveBidomainProblem::Solve()
00359 {
00360     OutputFileHandler file_handler(HeartConfig::Instance()->GetOutputDirectory(), false);
00361 
00362     mOutputDirectory = file_handler.GetOutputDirectoryFullPath();
00363     mOutputFilenamePrefix = HeartConfig::Instance()->GetOutputFilenamePrefix();
00364 
00365     PreSolveChecks();
00366 
00367     mpNeumannStimulus = new RegularStimulus(mNeumannStimulusMagnitude, mNeumannStimulusDuration, mNeumannStimulusPeriod, 0.0);
00368 
00369     if (mUseNeumannBoundaryConditions)
00370     {
00371         // Determine the values a and b to apply Neumann bcs at x_i=a (stimulus), x_i=b (ground)
00372         double local_min = DBL_MAX;
00373         double local_max = -DBL_MAX;
00374 
00375         for (AbstractTetrahedralMesh<3,3>::NodeIterator iter=mpMesh->GetNodeIteratorBegin();
00376              iter != mpMesh->GetNodeIteratorEnd();
00377              ++iter)
00378         {
00379             double value = (*iter).rGetLocation()[mNeumannStimulusIndex];
00380             if(value < local_min)
00381             {
00382                 local_min = value;
00383             }
00384             if(value > local_max)
00385             {
00386                local_max = value;
00387             }
00388         }
00389 
00390         int mpi_ret = MPI_Allreduce(&local_min, &mNeumannStimulusLowerValue, 1, MPI_DOUBLE, MPI_MIN, PETSC_COMM_WORLD);
00391         assert(mpi_ret == MPI_SUCCESS);
00392         mpi_ret = MPI_Allreduce(&local_max, &mNeumannStimulusUpperValue, 1, MPI_DOUBLE, MPI_MAX, PETSC_COMM_WORLD);
00393         assert(mpi_ret == MPI_SUCCESS);
00394 
00395         SetupNeumannBoundaryConditionOnMesh();
00396     }
00397     else
00398     {
00399         if(mpBoundaryConditionsContainer == NULL) // the user didnt supply a bcc
00400         {
00401             // set up the default bcc
00402             boost::shared_ptr<BoundaryConditionsContainer<3, 3, 2> > p_allocated_memory(new BoundaryConditionsContainer<3, 3, 2>);
00403             mpDefaultBoundaryConditionsContainer = p_allocated_memory;
00404             for (unsigned problem_index=0; problem_index<2; problem_index++)
00405             {
00406                 mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00407             }
00408             mpBoundaryConditionsContainer = mpDefaultBoundaryConditionsContainer;
00409         }
00410     }
00411 
00412     mpSolver = new BidomainSolver<3,3>(false, mpMesh, mpBidomainTissue,
00413                                        mpBoundaryConditionsContainer.get(), 2);
00414     mSolution = CreateInitialCondition();
00415 
00416     TimeStepper stepper(0.0, HeartConfig::Instance()->GetSimulationDuration(),
00417                         HeartConfig::Instance()->GetPrintingTimeStep());
00418 
00419     std::string progress_reporter_dir;
00420 
00421     assert( !mPrintOutput );
00422 
00423     progress_reporter_dir = ""; // progress printed to CHASTE_TEST_OUTPUT
00424 
00425     // create a progress reporter so users can track how much has gone and
00426     // estimate how much time is left. (Note this has to be done after the
00427     // InitialiseWriter above (if mPrintOutput==true)
00428     ProgressReporter progress_reporter(progress_reporter_dir, 0.0, HeartConfig::Instance()->GetSimulationDuration());
00429     progress_reporter.Update(0);
00430 
00431     // Initialize adaptive mesh using Chaste mesh
00432 //    mpAdaptiveMesh->ConstructFromMesh( mpMesh );
00433 //    mpAdaptiveMesh->CalculateSENListAndSids();
00434 
00435     // Get initial condition from file, or add Chaste initial condition to adaptive mesh
00436     if ( mInitializeFromVtu )
00437     {
00438         mpAdaptiveMesh->ConstructFromVtuFile( HeartConfig::Instance()->GetMeshName() );
00439         mpAdaptiveMesh->CalculateSENListAndSids();
00440 
00441         VtkMeshReader<3,3> mesh_reader( HeartConfig::Instance()->GetMeshName() );
00442 
00443         InitializeSolutionOnAdaptedMesh( &mesh_reader );
00444     }
00445     else
00446     {
00447         mpAdaptiveMesh->ConstructFromMesh( mpMesh );
00448         mpAdaptiveMesh->CalculateSENListAndSids();
00449         AddCurrentSolutionToAdaptiveMesh( mSolution );
00450     }
00451 
00452     // Use printing time step as adaptive time step...
00453 
00454     unsigned count = 0;
00455 
00456     // Set up filenames for convenient ParaView visualization
00457     std::ostringstream adapt_file_name, solution_file_name;
00458 
00459 //    {
00460 //        std::cout << "Values of Vm at node 2,000,000" << std::endl;
00461 //        ReplicatableVector replicatable_solution( mSolution );
00462 //        std::cout << replicatable_solution[2*2e6] << std::endl;        // Vm at node x is mSolution[2*x] (phi is mSolution[2*x+1])
00463 //    }
00464 
00465     mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00466 
00467     while ( !stepper.IsTimeAtEnd() )
00468     {
00469         {
00470             solution_file_name.str("");
00471             solution_file_name << mOutputFilenamePrefix << std::setw(4) << std::setfill('0') << count << ".vtu";
00472             HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00473             mpAdaptiveMesh->WriteMeshToFile( mOutputDirectory, solution_file_name.str() );
00474             HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00475         }
00476 
00477 
00478         // Adapt the mesh
00479         if ( mIsMeshAdapting && ( count > 0 || mInitializeFromVtu ) )
00480         {
00481             AdaptMesh();
00482         }
00483 
00484 //        // For non-adapting heart simulation, we may want to refine the mesh *ONCE* after the end of the stimulus
00485         // (in order to change the resolution).
00486 //        if ( (! mIsMeshAdapting) && (count == 1) )
00487 //        {
00488 //            AdaptMesh();
00489 //        }
00490 
00491         // Solve from now up to the next printing time step
00492         mpSolver->SetTimes(stepper.GetTime(), stepper.GetNextTime());
00493         mpSolver->SetInitialCondition( mSolution );
00494 
00495         try
00496         {
00497             Vec new_solution = mpSolver->Solve();
00498             PetscTools::Destroy(mSolution);
00499             mSolution = new_solution;
00500 //            ReplicatableVector replicatable_solution( mSolution );
00501 //            std::cout << replicatable_solution[2*2e6] << std::endl;        // Vm at node x is mSolution[2*x]
00502         }
00503         catch (Exception &e)
00504         {
00505             // Free memory.
00506 
00507             delete mpSolver;
00508             mpSolver=NULL;
00509             if (!mUseNeumannBoundaryConditions)
00510             {
00511                 mpDefaultBoundaryConditionsContainer = mpBoundaryConditionsContainer;
00512             }
00513             delete mpNeumannStimulus;
00514 
00515             PetscTools::ReplicateException(true);
00516             // Re-throw
00517             HeartEventHandler::Reset();//EndEvent(HeartEventHandler::EVERYTHING);
00518 
00519             CloseFilesAndPostProcess();
00520             throw e;
00521         }
00522         PetscTools::ReplicateException(false);
00523 
00524         // Add current solution into the node "point" data
00525         AddCurrentSolutionToAdaptiveMesh( mSolution );
00526 
00527         // update the current time
00528         stepper.AdvanceOneTimeStep();
00529 
00530         if (mWriteInfo)
00531         {
00532             HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00533             WriteInfo(stepper.GetTime());
00534             HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00535         }
00536 
00537         progress_reporter.Update(stepper.GetTime());
00538 
00539         OnEndOfTimestep(stepper.GetTime());
00540 
00541         count++;
00542     }
00543 
00544     {
00545         solution_file_name.str("");
00546         solution_file_name << mOutputFilenamePrefix << std::setw(4) << std::setfill('0') << count << ".vtu";
00547         HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00548         mpAdaptiveMesh->WriteMeshToFile( mOutputDirectory, solution_file_name.str() );
00549         HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00550     }
00551 
00552     // Free solver
00553     delete mpSolver;
00554 
00555     if (!mUseNeumannBoundaryConditions)
00556     {
00557         mpDefaultBoundaryConditionsContainer = mpBoundaryConditionsContainer;
00558     }
00559     delete mpNeumannStimulus;
00560 
00561     // close the file that stores voltage values
00562     progress_reporter.PrintFinalising();
00563     CloseFilesAndPostProcess();
00564     HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING);
00565 }
00566 
00567 #endif //CHASTE_ADAPTIVITY