00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifdef CHASTE_ADAPTIVITY
00038
00039 #include "AdaptiveBidomainProblem.hpp"
00040 #include "BidomainSolver.hpp"
00041
00042 #include "VtkMeshWriter.hpp"
00043 #include "TetrahedralMesh.hpp"
00044 #include "BidomainTissue.hpp"
00045 #include "HeartRegionCodes.hpp"
00046 #include "HeartConfig.hpp"
00047 #include "Exception.hpp"
00048 #include "DistributedVector.hpp"
00049 #include "ReplicatableVector.hpp"
00050 #include "ProgressReporter.hpp"
00051 #include "PetscTools.hpp"
00052 #include "RegularStimulus.hpp"
00053
00054 AdaptiveBidomainProblem::AdaptiveBidomainProblem(
00055 AbstractCardiacCellFactory<3>* pCellFactory, bool hasBath)
00056 : BidomainProblem<3>(pCellFactory, hasBath),
00057 mIsMeshAdapting(true),
00058 mInitializeFromVtu(false),
00059 mUseNeumannBoundaryConditions(false),
00060 mNeumannStimulusIndex(0),
00061 mNeumannStimulusLowerValue(DBL_MAX),
00062 mNeumannStimulusUpperValue(-DBL_MAX),
00063 mNeumannStimulusMagnitude(0.0),
00064 mNeumannStimulusDuration(0.0),
00065 mNeumannStimulusPeriod(DBL_MAX)
00066
00067
00068 {
00069 mFixedExtracellularPotentialNodes.resize(0);
00070 mpAdaptiveMesh = new AdaptiveTetrahedralMesh;
00071 }
00072
00073 AdaptiveBidomainProblem::~AdaptiveBidomainProblem()
00074 {
00075 delete mpAdaptiveMesh;
00076 }
00077
00078 void AdaptiveBidomainProblem::DoNotAdaptMesh()
00079 {
00080 mIsMeshAdapting = false;
00081 }
00082
00083
00084
00085
00086
00087
00088
00089 void AdaptiveBidomainProblem::AddCurrentSolutionToAdaptiveMesh( Vec solution )
00090 {
00091 HeartEventHandler::BeginEvent(HeartEventHandler::USER1);
00092
00093 ReplicatableVector replicatable_solution( solution );
00094 std::vector<double> vm_for_vtk, phi_for_vtk;
00095 vm_for_vtk.resize(mpMesh->GetNumNodes());
00096 phi_for_vtk.resize(mpMesh->GetNumNodes());
00097
00098 for (AbstractTetrahedralMesh<3,3>::NodeIterator it=mpMesh->GetNodeIteratorBegin();
00099 it != mpMesh->GetNodeIteratorEnd();
00100 ++it)
00101 {
00102 vm_for_vtk[it->GetIndex()] = replicatable_solution[2*it->GetIndex()];
00103 phi_for_vtk[it->GetIndex()] = replicatable_solution[2*it->GetIndex()+1];
00104 }
00105 mpAdaptiveMesh->AddPointData("Vm", vm_for_vtk);
00106 mpAdaptiveMesh->AddPointData("Phi", phi_for_vtk);
00107
00108 std::vector<std::string> state_variable_names = mpBidomainTissue->GetCardiacCell(0)->rGetStateVariableNames();
00109 unsigned number_of_state_variables = state_variable_names.size();
00110 std::vector< std::vector<double> > state_variable_values;
00111 state_variable_values.resize( mpMesh->GetNumNodes() );
00112
00113
00114 for (unsigned variable=0; variable<number_of_state_variables; variable++)
00115 {
00116 if (variable != mpBidomainTissue->GetCardiacCell(0)->GetVoltageIndex())
00117 {
00118 std::vector<double> variable_for_vtk;
00119 variable_for_vtk.resize(mpMesh->GetNumNodes());
00120 for (AbstractTetrahedralMesh<3,3>::NodeIterator it=mpMesh->GetNodeIteratorBegin();
00121 it != mpMesh->GetNodeIteratorEnd();
00122 ++it)
00123 {
00124 variable_for_vtk[it->GetIndex()] = mpBidomainTissue->GetCardiacCell(it->GetIndex())->rGetStateVariables()[variable];
00125 }
00126 mpAdaptiveMesh->AddPointData(state_variable_names[variable], variable_for_vtk);
00127 }
00128 }
00129
00130 HeartEventHandler::EndEvent(HeartEventHandler::USER1);
00131 }
00132
00133 void AdaptiveBidomainProblem::InitializeSolutionOnAdaptedMesh( VtkMeshReader<3,3>* reader )
00134 {
00135 HeartEventHandler::BeginEvent(HeartEventHandler::USER1);
00136
00137 std::vector<double> adapted_vm, adapted_phi;
00138
00139 reader->GetPointData("Vm", adapted_vm);
00140 reader->GetPointData("Phi", adapted_phi);
00141
00142 Vec solution = mpMesh->GetDistributedVectorFactory()->CreateVec(2);
00143 DistributedVector nic = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(solution);
00144 std::vector<DistributedVector::Stripe> stripe;
00145 stripe.reserve(2);
00146
00147 for (unsigned i=0; i<2; i++)
00148 {
00149 stripe.push_back(DistributedVector::Stripe(nic, i));
00150 }
00151
00152 for (DistributedVector::Iterator it = nic.Begin();
00153 it != nic.End();
00154 ++it)
00155 {
00156 stripe[0][it] = adapted_vm[it.Global];
00157 stripe[1][it] = adapted_phi[it.Global];
00158 }
00159
00160 nic.Restore();
00161
00162 std::vector<std::string> state_variable_names = mpBidomainTissue->GetCardiacCell(0)->rGetStateVariableNames();
00163 unsigned number_of_state_variables = state_variable_names.size();
00164
00165 for (unsigned variable=0; variable<number_of_state_variables; variable++)
00166 {
00167 if (variable != mpBidomainTissue->GetCardiacCell(0)->GetVoltageIndex())
00168 {
00169 std::vector<double> adapted_state_variable;
00170 reader->GetPointData( state_variable_names[variable], adapted_state_variable);
00171
00172 for (DistributedVector::Iterator it = nic.Begin();
00173 it != nic.End();
00174 ++it)
00175 {
00176 mpBidomainTissue->GetCardiacCell(it.Global)->SetStateVariable(variable, adapted_state_variable[it.Global]);
00177 }
00178 }
00179 else
00180 {
00181 for (DistributedVector::Iterator it = nic.Begin();
00182 it != nic.End();
00183 ++it)
00184 {
00185 mpBidomainTissue->GetCardiacCell(it.Global)->SetStateVariable(variable, adapted_vm[it.Global]);
00186 }
00187
00188 }
00189 }
00190
00191 if (mSolution)
00192 {
00193 VecDestroy(mSolution);
00194 }
00195
00196 mSolution = solution;
00197
00198 HeartEventHandler::EndEvent(HeartEventHandler::USER1);
00199 }
00200
00201 void AdaptiveBidomainProblem::AdaptMesh()
00202 {
00203 HeartEventHandler::BeginEvent(HeartEventHandler::USER1);
00204 mpAdaptiveMesh->AdaptMesh();
00205 HeartEventHandler::EndEvent(HeartEventHandler::USER1);
00206
00207 if ( mpAdaptiveMesh->GetAdaptSuccess() )
00208 {
00209 if (mWriteInfo)
00210 {
00211 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00212 std::cout << "Adapt completed. New mesh has " << mpAdaptiveMesh->GetNumNodes() << " nodes" << std::endl;
00213 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00214 }
00215
00216 delete mpMesh;
00217 DistributedTetrahedralMesh<3,3>* p_new_mesh = new DistributedTetrahedralMesh<3,3>;
00218 VtkMeshReader<3,3> mesh_reader( mpAdaptiveMesh->GetVtkUnstructuredGrid() );
00219 HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00220 p_new_mesh->ConstructFromMeshReader(mesh_reader);
00221 HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00222 mpMesh = p_new_mesh;
00223
00224 mpCellFactory->SetMesh( mpMesh );
00225
00226 if (mUseNeumannBoundaryConditions)
00227 {
00228 SetupNeumannBoundaryConditionOnMesh();
00229 }
00230 else
00231 {
00232 boost::shared_ptr<BoundaryConditionsContainer<3, 3, 2> > p_new_bcc(new BoundaryConditionsContainer<3, 3, 2>);
00233 for (unsigned problem_index=0; problem_index<2; problem_index++)
00234 {
00235 p_new_bcc->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00236 }
00237 mpBoundaryConditionsContainer = p_new_bcc;
00238 }
00239
00240 delete mpBidomainTissue;
00241 BidomainTissue<3>* new_bidomain_tissue;
00242 new_bidomain_tissue = new BidomainTissue<3>(mpCellFactory);
00243 mpBidomainTissue = new_bidomain_tissue;
00244 mpCardiacTissue = mpBidomainTissue;
00245
00246 delete mpSolver;
00247 BidomainSolver<3,3>* p_new_solver;
00248 p_new_solver = new BidomainSolver<3,3>(false, mpMesh, mpBidomainTissue,
00249 mpBoundaryConditionsContainer.get(), 2);
00250 mpSolver = p_new_solver;
00251 mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00252
00253 InitializeSolutionOnAdaptedMesh( &mesh_reader );
00254 }
00255 else
00256 {
00257 NEVER_REACHED;
00258 }
00259 }
00260
00261 void AdaptiveBidomainProblem::SetNeumannStimulusMagnitudeAndDuration(double magnitude, double duration, double period)
00262 {
00263 mNeumannStimulusMagnitude = magnitude;
00264 mNeumannStimulusDuration = duration;
00265 mNeumannStimulusPeriod = std::min( period, HeartConfig::Instance()->GetSimulationDuration() );
00266 }
00267
00268 void AdaptiveBidomainProblem::UseNeumannBoundaryCondition(unsigned index)
00269 {
00270 mUseNeumannBoundaryConditions = true;
00271 mNeumannStimulusIndex = index;
00272 }
00273
00274 double AdaptiveBidomainProblem::GetTargetError()
00275 {
00276 return HeartConfig::Instance()->GetTargetErrorForAdaptivity();
00277 }
00278
00279 double AdaptiveBidomainProblem::GetSigma()
00280 {
00281 return HeartConfig::Instance()->GetSigmaForAdaptivity();
00282 }
00283
00284 double AdaptiveBidomainProblem::GetMaxEdgeLength()
00285 {
00286 return HeartConfig::Instance()->GetMaxEdgeLengthForAdaptivity();
00287 }
00288
00289 double AdaptiveBidomainProblem::GetMinEdgeLength()
00290 {
00291 return HeartConfig::Instance()->GetMinEdgeLengthForAdaptivity();
00292 }
00293
00294 double AdaptiveBidomainProblem::GetGradation()
00295 {
00296 return HeartConfig::Instance()->GetGradationForAdaptivity();
00297 }
00298
00299 unsigned AdaptiveBidomainProblem::GetMaxMeshNodes()
00300 {
00301 return HeartConfig::Instance()->GetMaxNodesForAdaptivity();
00302 }
00303
00304 unsigned AdaptiveBidomainProblem::GetNumAdaptSweeps()
00305 {
00306 return HeartConfig::Instance()->GetNumberOfAdaptiveSweeps();
00307 }
00308
00309 void AdaptiveBidomainProblem::SetupNeumannBoundaryConditionOnMesh()
00310 {
00311 boost::shared_ptr<BoundaryConditionsContainer<3, 3, 2> > p_new_bcc(new BoundaryConditionsContainer<3, 3, 2>);
00312
00313 mpNeumannStimulusBoundaryCondition = new StimulusBoundaryCondition<3>(mpNeumannStimulus);
00314 ConstBoundaryCondition<3>* p_zero_bc = new ConstBoundaryCondition<3>(0.0);
00315
00316
00317 AbstractTetrahedralMesh<3,3>::BoundaryElementIterator iter;
00318 iter = mpMesh->GetBoundaryElementIteratorBegin();
00319
00320 while (iter != mpMesh->GetBoundaryElementIteratorEnd())
00321 {
00322 double x = ((*iter)->CalculateCentroid())[mNeumannStimulusIndex];
00324 if ( (x-mNeumannStimulusLowerValue)*(x-mNeumannStimulusLowerValue) <= 1e-10 )
00325 {
00326 p_new_bcc->AddNeumannBoundaryCondition(*iter, mpNeumannStimulusBoundaryCondition);
00327 }
00328 iter++;
00329 }
00330
00331
00332 for (AbstractTetrahedralMesh<3,3>::NodeIterator node_iter=mpMesh->GetNodeIteratorBegin();
00333 node_iter != mpMesh->GetNodeIteratorEnd();
00334 ++node_iter)
00335 {
00336 if (fabs((*node_iter).rGetLocation()[mNeumannStimulusIndex] - mNeumannStimulusUpperValue) < 1e-6)
00337 {
00338 p_new_bcc->AddDirichletBoundaryCondition(&(*node_iter), p_zero_bc, 1);
00339 }
00340 }
00341
00342 mpBoundaryConditionsContainer = p_new_bcc;
00343 }
00344
00345 void AdaptiveBidomainProblem::LoadSimulationFromVtuFile()
00346 {
00347 mInitializeFromVtu = true;
00348 AbstractCardiacProblem<3,3,2>::Initialise();
00349 }
00350
00351 void AdaptiveBidomainProblem::Solve()
00352 {
00353 OutputFileHandler file_handler(HeartConfig::Instance()->GetOutputDirectory(), false);
00354
00355 mOutputDirectory = file_handler.GetOutputDirectoryFullPath();
00356 mOutputFilenamePrefix = HeartConfig::Instance()->GetOutputFilenamePrefix();
00357
00358 PreSolveChecks();
00359
00360 mpNeumannStimulus = new RegularStimulus(mNeumannStimulusMagnitude, mNeumannStimulusDuration, mNeumannStimulusPeriod, 0.0);
00361
00362 if (mUseNeumannBoundaryConditions)
00363 {
00364
00365 double local_min = DBL_MAX;
00366 double local_max = -DBL_MAX;
00367
00368 for (AbstractTetrahedralMesh<3,3>::NodeIterator iter=mpMesh->GetNodeIteratorBegin();
00369 iter != mpMesh->GetNodeIteratorEnd();
00370 ++iter)
00371 {
00372 double value = (*iter).rGetLocation()[mNeumannStimulusIndex];
00373 if(value < local_min)
00374 {
00375 local_min = value;
00376 }
00377 if(value > local_max)
00378 {
00379 local_max = value;
00380 }
00381 }
00382
00383 int mpi_ret = MPI_Allreduce(&local_min, &mNeumannStimulusLowerValue, 1, MPI_DOUBLE, MPI_MIN, PETSC_COMM_WORLD);
00384 assert(mpi_ret == MPI_SUCCESS);
00385 mpi_ret = MPI_Allreduce(&local_max, &mNeumannStimulusUpperValue, 1, MPI_DOUBLE, MPI_MAX, PETSC_COMM_WORLD);
00386 assert(mpi_ret == MPI_SUCCESS);
00387
00388 SetupNeumannBoundaryConditionOnMesh();
00389 }
00390 else
00391 {
00392 if(mpBoundaryConditionsContainer == NULL)
00393 {
00394
00395 boost::shared_ptr<BoundaryConditionsContainer<3, 3, 2> > p_allocated_memory(new BoundaryConditionsContainer<3, 3, 2>);
00396 mpDefaultBoundaryConditionsContainer = p_allocated_memory;
00397 for (unsigned problem_index=0; problem_index<2; problem_index++)
00398 {
00399 mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00400 }
00401 mpBoundaryConditionsContainer = mpDefaultBoundaryConditionsContainer;
00402 }
00403 }
00404
00405 mpSolver = new BidomainSolver<3,3>(false, mpMesh, mpBidomainTissue,
00406 mpBoundaryConditionsContainer.get(), 2);
00407 mSolution = CreateInitialCondition();
00408
00409 TimeStepper stepper(0.0, HeartConfig::Instance()->GetSimulationDuration(),
00410 HeartConfig::Instance()->GetPrintingTimeStep());
00411
00412 std::string progress_reporter_dir;
00413
00414 assert( !mPrintOutput );
00415
00416 progress_reporter_dir = "";
00417
00418
00419
00420
00421 ProgressReporter progress_reporter(progress_reporter_dir, 0.0, HeartConfig::Instance()->GetSimulationDuration());
00422 progress_reporter.Update(0);
00423
00424
00425
00426
00427
00428
00429 if ( mInitializeFromVtu )
00430 {
00431 mpAdaptiveMesh->ConstructFromVtuFile( HeartConfig::Instance()->GetMeshName() );
00432 mpAdaptiveMesh->CalculateSENListAndSids();
00433
00434 VtkMeshReader<3,3> mesh_reader( HeartConfig::Instance()->GetMeshName() );
00435
00436 InitializeSolutionOnAdaptedMesh( &mesh_reader );
00437 }
00438 else
00439 {
00440 mpAdaptiveMesh->ConstructFromMesh( mpMesh );
00441 mpAdaptiveMesh->CalculateSENListAndSids();
00442 AddCurrentSolutionToAdaptiveMesh( mSolution );
00443 }
00444
00445
00446
00447 unsigned count = 0;
00448
00449
00450 std::ostringstream adapt_file_name, solution_file_name;
00451
00452
00453
00454
00455
00456
00457
00458 mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00459
00460 while ( !stepper.IsTimeAtEnd() )
00461 {
00462 {
00463 solution_file_name.str("");
00464 solution_file_name << mOutputFilenamePrefix << std::setw(4) << std::setfill('0') << count << ".vtu";
00465 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00466 mpAdaptiveMesh->WriteMeshToFile( mOutputDirectory, solution_file_name.str() );
00467 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00468 }
00469
00470
00471
00472 if ( mIsMeshAdapting && ( count > 0 || mInitializeFromVtu ) )
00473 {
00474 AdaptMesh();
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 mpSolver->SetTimes(stepper.GetTime(), stepper.GetNextTime());
00486 mpSolver->SetInitialCondition( mSolution );
00487
00488 try
00489 {
00490 Vec new_solution = mpSolver->Solve();
00491 VecDestroy(mSolution);
00492 mSolution = new_solution;
00493
00494
00495 }
00496 catch (Exception &e)
00497 {
00498
00499
00500 delete mpSolver;
00501 mpSolver=NULL;
00502 if (!mUseNeumannBoundaryConditions)
00503 {
00504 mpDefaultBoundaryConditionsContainer = mpBoundaryConditionsContainer;
00505 }
00506 delete mpNeumannStimulus;
00507
00508 PetscTools::ReplicateException(true);
00509
00510 HeartEventHandler::Reset();
00511
00512 CloseFilesAndPostProcess();
00513 throw e;
00514 }
00515 PetscTools::ReplicateException(false);
00516
00517
00518 AddCurrentSolutionToAdaptiveMesh( mSolution );
00519
00520
00521 stepper.AdvanceOneTimeStep();
00522
00523 if (mWriteInfo)
00524 {
00525 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00526 WriteInfo(stepper.GetTime());
00527 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00528 }
00529
00530 progress_reporter.Update(stepper.GetTime());
00531
00532 OnEndOfTimestep(stepper.GetTime());
00533
00534 count++;
00535 }
00536
00537 {
00538 solution_file_name.str("");
00539 solution_file_name << mOutputFilenamePrefix << std::setw(4) << std::setfill('0') << count << ".vtu";
00540 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00541 mpAdaptiveMesh->WriteMeshToFile( mOutputDirectory, solution_file_name.str() );
00542 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00543 }
00544
00545
00546 delete mpSolver;
00547
00548 if (!mUseNeumannBoundaryConditions)
00549 {
00550 mpDefaultBoundaryConditionsContainer = mpBoundaryConditionsContainer;
00551 }
00552 delete mpNeumannStimulus;
00553
00554
00555 progress_reporter.PrintFinalising();
00556 CloseFilesAndPostProcess();
00557 HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING);
00558 }
00559
00560 #endif //CHASTE_ADAPTIVITY