Chaste Release::3.1
|
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