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 "MatrixBasedBidomainSolver.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 MatrixBasedBidomainSolver<3,3>* p_new_solver;
00248 p_new_solver = new MatrixBasedBidomainSolver<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];
00323 if ( (x-mNeumannStimulusLowerValue)*(x-mNeumannStimulusLowerValue) <= 1e-10 )
00324 {
00325 p_new_bcc->AddNeumannBoundaryCondition(*iter, mpNeumannStimulusBoundaryCondition);
00326 }
00327 iter++;
00328 }
00329
00330
00331 for (AbstractTetrahedralMesh<3,3>::NodeIterator node_iter=mpMesh->GetNodeIteratorBegin();
00332 node_iter != mpMesh->GetNodeIteratorEnd();
00333 ++node_iter)
00334 {
00335 if (fabs((*node_iter).rGetLocation()[mNeumannStimulusIndex] - mNeumannStimulusUpperValue) < 1e-6)
00336 {
00337 p_new_bcc->AddDirichletBoundaryCondition(&(*node_iter), p_zero_bc, 1);
00338 }
00339 }
00340
00341 mpBoundaryConditionsContainer = p_new_bcc;
00342 }
00343
00344 void AdaptiveBidomainProblem::LoadSimulationFromVtuFile()
00345 {
00346 mInitializeFromVtu = true;
00347 AbstractCardiacProblem<3,3,2>::Initialise();
00348 }
00349
00350 void AdaptiveBidomainProblem::Solve()
00351 {
00352 OutputFileHandler file_handler(HeartConfig::Instance()->GetOutputDirectory(), false);
00353
00354 mOutputDirectory = file_handler.GetOutputDirectoryFullPath();
00355 mOutputFilenamePrefix = HeartConfig::Instance()->GetOutputFilenamePrefix();
00356
00357 PreSolveChecks();
00358
00359 mpNeumannStimulus = new RegularStimulus(mNeumannStimulusMagnitude, mNeumannStimulusDuration, mNeumannStimulusPeriod, 0.0);
00360
00361 if (mUseNeumannBoundaryConditions)
00362 {
00363
00364 double local_min = DBL_MAX;
00365 double local_max = -DBL_MAX;
00366
00367 for (AbstractTetrahedralMesh<3,3>::NodeIterator iter=mpMesh->GetNodeIteratorBegin();
00368 iter != mpMesh->GetNodeIteratorEnd();
00369 ++iter)
00370 {
00371 double value = (*iter).rGetLocation()[mNeumannStimulusIndex];
00372 if(value < local_min)
00373 {
00374 local_min = value;
00375 }
00376 if(value > local_max)
00377 {
00378 local_max = value;
00379 }
00380 }
00381
00382 int mpi_ret = MPI_Allreduce(&local_min, &mNeumannStimulusLowerValue, 1, MPI_DOUBLE, MPI_MIN, PETSC_COMM_WORLD);
00383 assert(mpi_ret == MPI_SUCCESS);
00384 mpi_ret = MPI_Allreduce(&local_max, &mNeumannStimulusUpperValue, 1, MPI_DOUBLE, MPI_MAX, PETSC_COMM_WORLD);
00385 assert(mpi_ret == MPI_SUCCESS);
00386
00387 SetupNeumannBoundaryConditionOnMesh();
00388 }
00389 else
00390 {
00391 if(mpBoundaryConditionsContainer == NULL)
00392 {
00393
00394 boost::shared_ptr<BoundaryConditionsContainer<3, 3, 2> > p_allocated_memory(new BoundaryConditionsContainer<3, 3, 2>);
00395 mpDefaultBoundaryConditionsContainer = p_allocated_memory;
00396 for (unsigned problem_index=0; problem_index<2; problem_index++)
00397 {
00398 mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00399 }
00400 mpBoundaryConditionsContainer = mpDefaultBoundaryConditionsContainer;
00401 }
00402 }
00403
00404 mpSolver = new MatrixBasedBidomainSolver<3,3>(false, mpMesh, mpBidomainTissue,
00405 mpBoundaryConditionsContainer.get(), 2);
00406 mSolution = CreateInitialCondition();
00407
00408 TimeStepper stepper(0.0, HeartConfig::Instance()->GetSimulationDuration(),
00409 HeartConfig::Instance()->GetPrintingTimeStep());
00410
00411 std::string progress_reporter_dir;
00412
00413 assert( !mPrintOutput );
00414
00415 progress_reporter_dir = "";
00416
00417
00418
00419
00420 ProgressReporter progress_reporter(progress_reporter_dir, 0.0, HeartConfig::Instance()->GetSimulationDuration());
00421 progress_reporter.Update(0);
00422
00423
00424
00425
00426
00427
00428 if ( mInitializeFromVtu )
00429 {
00430 mpAdaptiveMesh->ConstructFromVtuFile( HeartConfig::Instance()->GetMeshName() );
00431 mpAdaptiveMesh->CalculateSENListAndSids();
00432
00433 VtkMeshReader<3,3> mesh_reader( HeartConfig::Instance()->GetMeshName() );
00434
00435 InitializeSolutionOnAdaptedMesh( &mesh_reader );
00436 }
00437 else
00438 {
00439 mpAdaptiveMesh->ConstructFromMesh( mpMesh );
00440 mpAdaptiveMesh->CalculateSENListAndSids();
00441 AddCurrentSolutionToAdaptiveMesh( mSolution );
00442 }
00443
00444
00445
00446 unsigned count = 0;
00447
00448
00449 std::ostringstream adapt_file_name, solution_file_name;
00450
00451
00452
00453
00454
00455
00456
00457 mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00458
00459 while ( !stepper.IsTimeAtEnd() )
00460 {
00461 {
00462 solution_file_name.str("");
00463 solution_file_name << mOutputFilenamePrefix << std::setw(4) << std::setfill('0') << count << ".vtu";
00464 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00465 mpAdaptiveMesh->WriteMeshToFile( mOutputDirectory, solution_file_name.str() );
00466 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00467 }
00468
00469
00470
00471 if ( mIsMeshAdapting && ( count > 0 || mInitializeFromVtu ) )
00472 {
00473 AdaptMesh();
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 mpSolver->SetTimes(stepper.GetTime(), stepper.GetNextTime());
00485 mpSolver->SetInitialCondition( mSolution );
00486
00487 try
00488 {
00489 Vec new_solution = mpSolver->Solve();
00490 VecDestroy(mSolution);
00491 mSolution = new_solution;
00492
00493
00494 }
00495 catch (Exception &e)
00496 {
00497
00498
00499 delete mpSolver;
00500 mpSolver=NULL;
00501 if (!mUseNeumannBoundaryConditions)
00502 {
00503 mpDefaultBoundaryConditionsContainer = mpBoundaryConditionsContainer;
00504 }
00505 delete mpNeumannStimulus;
00506
00507 PetscTools::ReplicateException(true);
00508
00509 HeartEventHandler::Reset();
00510
00511 CloseFilesAndPostProcess();
00512 throw e;
00513 }
00514 PetscTools::ReplicateException(false);
00515
00516
00517 AddCurrentSolutionToAdaptiveMesh( mSolution );
00518
00519
00520 stepper.AdvanceOneTimeStep();
00521
00522 if (mWriteInfo)
00523 {
00524 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00525 WriteInfo(stepper.GetTime());
00526 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00527 }
00528
00529 progress_reporter.Update(stepper.GetTime());
00530
00531 OnEndOfTimestep(stepper.GetTime());
00532
00533 count++;
00534 }
00535
00536 {
00537 solution_file_name.str("");
00538 solution_file_name << mOutputFilenamePrefix << std::setw(4) << std::setfill('0') << count << ".vtu";
00539 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00540 mpAdaptiveMesh->WriteMeshToFile( mOutputDirectory, solution_file_name.str() );
00541 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00542 }
00543
00544
00545 delete mpSolver;
00546
00547 if (!mUseNeumannBoundaryConditions)
00548 {
00549 mpDefaultBoundaryConditionsContainer = mpBoundaryConditionsContainer;
00550 }
00551 delete mpNeumannStimulus;
00552
00553
00554 progress_reporter.PrintFinalising();
00555 CloseFilesAndPostProcess();
00556 HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING);
00557 }
00558
00559 #endif //CHASTE_ADAPTIVITY