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 #include "AbstractCardiacProblem.hpp"
00037
00038 #include "GenericMeshReader.hpp"
00039 #include "Exception.hpp"
00040 #include "HeartConfig.hpp"
00041 #include "HeartEventHandler.hpp"
00042 #include "TimeStepper.hpp"
00043 #include "PetscTools.hpp"
00044 #include "DistributedVector.hpp"
00045 #include "ProgressReporter.hpp"
00046 #include "LinearSystem.hpp"
00047 #include "PostProcessingWriter.hpp"
00048 #include "Hdf5ToMeshalyzerConverter.hpp"
00049 #include "Hdf5ToCmguiConverter.hpp"
00050 #include "Hdf5ToVtkConverter.hpp"
00051
00052 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00053 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::AbstractCardiacProblem(
00054 AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory)
00055 : mMeshFilename(""),
00056 mAllocatedMemoryForMesh(false),
00057 mWriteInfo(false),
00058 mPrintOutput(true),
00059 mpCardiacTissue(NULL),
00060 mpSolver(NULL),
00061 mpCellFactory(pCellFactory),
00062 mpMesh(NULL),
00063 mSolution(NULL),
00064 mCurrentTime(0.0),
00065 mpTimeAdaptivityController(NULL),
00066 mpWriter(NULL)
00067 {
00068 assert(mNodesToOutput.empty());
00069 if (!mpCellFactory)
00070 {
00071 EXCEPTION("AbstractCardiacProblem: Please supply a cell factory pointer to your cardiac problem constructor.");
00072 }
00073 HeartEventHandler::BeginEvent(HeartEventHandler::EVERYTHING);
00074 }
00075
00076 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00077 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::AbstractCardiacProblem()
00078
00079
00080 : mMeshFilename(""),
00081 mAllocatedMemoryForMesh(false),
00082 mWriteInfo(false),
00083 mPrintOutput(true),
00084 mVoltageColumnId(UINT_MAX),
00085 mTimeColumnId(UINT_MAX),
00086 mNodeColumnId(UINT_MAX),
00087 mpCardiacTissue(NULL),
00088 mpSolver(NULL),
00089 mpCellFactory(NULL),
00090 mpMesh(NULL),
00091 mSolution(NULL),
00092 mCurrentTime(0.0),
00093 mpTimeAdaptivityController(NULL),
00094 mpWriter(NULL)
00095 {
00096 }
00097
00098 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00099 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::~AbstractCardiacProblem()
00100 {
00101 delete mpCardiacTissue;
00102 if (mSolution)
00103 {
00104 PetscTools::Destroy(mSolution);
00105 }
00106
00107 if (mAllocatedMemoryForMesh)
00108 {
00109 delete mpMesh;
00110 }
00111 }
00112
00113 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00114 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::Initialise()
00115 {
00116 HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00117 if (mpMesh)
00118 {
00119 if (PetscTools::IsParallel() && !dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh))
00120 {
00121 WARNING("Using a non-distributed mesh in a parallel simulation is not a good idea.");
00122 }
00123 }
00124 else
00125 {
00126
00127 try
00128 {
00129 if (HeartConfig::Instance()->GetLoadMesh())
00130 {
00131 CreateMeshFromHeartConfig();
00132 std::auto_ptr<AbstractMeshReader<ELEMENT_DIM, SPACE_DIM> > p_mesh_reader
00133 = GenericMeshReader<ELEMENT_DIM, SPACE_DIM>(HeartConfig::Instance()->GetMeshName());
00134 mpMesh->ConstructFromMeshReader(*p_mesh_reader);
00135 }
00136 else if (HeartConfig::Instance()->GetCreateMesh())
00137 {
00138 CreateMeshFromHeartConfig();
00139 assert(HeartConfig::Instance()->GetSpaceDimension()==SPACE_DIM);
00140 double inter_node_space = HeartConfig::Instance()->GetInterNodeSpace();
00141
00142 switch(HeartConfig::Instance()->GetSpaceDimension())
00143 {
00144 case 1:
00145 {
00146 c_vector<double, 1> fibre_length;
00147 HeartConfig::Instance()->GetFibreLength(fibre_length);
00148 mpMesh->ConstructRegularSlabMesh(inter_node_space, fibre_length[0]);
00149 break;
00150 }
00151 case 2:
00152 {
00153 c_vector<double, 2> sheet_dimensions;
00154 HeartConfig::Instance()->GetSheetDimensions(sheet_dimensions);
00155 mpMesh->ConstructRegularSlabMesh(inter_node_space, sheet_dimensions[0], sheet_dimensions[1]);
00156 break;
00157 }
00158 case 3:
00159 {
00160 c_vector<double, 3> slab_dimensions;
00161 HeartConfig::Instance()->GetSlabDimensions(slab_dimensions);
00162 mpMesh->ConstructRegularSlabMesh(inter_node_space, slab_dimensions[0], slab_dimensions[1], slab_dimensions[2]);
00163 break;
00164 }
00165 default:
00166 NEVER_REACHED;
00167 }
00168 }
00169 else
00170 {
00171 NEVER_REACHED;
00172 }
00173
00174 mAllocatedMemoryForMesh = true;
00175 }
00176 catch (Exception& e)
00177 {
00178 EXCEPTION(std::string("No mesh given: define it in XML parameters file or call SetMesh()\n") + e.GetShortMessage());
00179 }
00180 }
00181 mpCellFactory->SetMesh( mpMesh );
00182 HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00183
00184 HeartEventHandler::BeginEvent(HeartEventHandler::INITIALISE);
00185
00186
00187 if (HeartConfig::Instance()->AreCellularTransmuralHeterogeneitiesRequested())
00188 {
00189 mpCellFactory->FillInCellularTransmuralAreas();
00190 }
00191
00192 delete mpCardiacTissue;
00193 mpCardiacTissue = CreateCardiacTissue();
00194
00195 HeartEventHandler::EndEvent(HeartEventHandler::INITIALISE);
00196
00197
00198 if (mSolution)
00199 {
00200 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00201 PetscTools::Destroy(mSolution);
00202 mSolution = NULL;
00203 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00204 }
00205
00206
00207 mCurrentTime = 0.0;
00208
00209
00210 SetElectrodes();
00211 }
00212
00213 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00214 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::CreateMeshFromHeartConfig()
00215 {
00216 mpMesh = new DistributedTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>(HeartConfig::Instance()->GetMeshPartitioning());
00217 }
00218
00219 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00220 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetBoundaryConditionsContainer(boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> > pBcc)
00221 {
00222 this->mpBoundaryConditionsContainer = pBcc;
00223 }
00224
00225 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00226 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::PreSolveChecks()
00227 {
00228 if ( mpCardiacTissue == NULL )
00229 {
00230 EXCEPTION("Cardiac tissue is null, Initialise() probably hasn't been called");
00231 }
00232 if ( HeartConfig::Instance()->GetSimulationDuration() <= mCurrentTime)
00233 {
00234 EXCEPTION("End time should be in the future");
00235 }
00236 if (mPrintOutput)
00237 {
00238 if( (HeartConfig::Instance()->GetOutputDirectory()=="") || (HeartConfig::Instance()->GetOutputFilenamePrefix()==""))
00239 {
00240 EXCEPTION("Either explicitly specify not to print output (call PrintOutput(false)) or specify the output directory and filename prefix");
00241 }
00242 }
00243
00244 double end_time = HeartConfig::Instance()->GetSimulationDuration();
00245 double pde_time = HeartConfig::Instance()->GetPdeTimeStep();
00246
00247
00248
00249
00250
00251
00252
00253
00255 if( fabs(end_time - pde_time*round(end_time/pde_time)) > 1e-10 )
00256 {
00257 EXCEPTION("PDE timestep does not seem to divide end time - check parameters");
00258 }
00259 }
00260
00261 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00262 Vec AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::CreateInitialCondition()
00263 {
00264 DistributedVectorFactory* p_factory = mpMesh->GetDistributedVectorFactory();
00265 Vec initial_condition = p_factory->CreateVec(PROBLEM_DIM);
00266 DistributedVector ic = p_factory->CreateDistributedVector(initial_condition);
00267 std::vector<DistributedVector::Stripe> stripe;
00268 stripe.reserve(PROBLEM_DIM);
00269
00270 for (unsigned i=0; i<PROBLEM_DIM; i++)
00271 {
00272 stripe.push_back(DistributedVector::Stripe(ic, i));
00273 }
00274
00275 for (DistributedVector::Iterator index = ic.Begin();
00276 index != ic.End();
00277 ++index)
00278 {
00279 stripe[0][index] = mpCardiacTissue->GetCardiacCell(index.Global)->GetVoltage();
00280 if (PROBLEM_DIM==2)
00281 {
00282 stripe[1][index] = 0;
00283 }
00284 }
00285
00286 ic.Restore();
00287
00288 return initial_condition;
00289 }
00290
00291 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00292 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00293 {
00294
00295
00296
00297
00298 assert(mpMesh == NULL);
00299 assert(pMesh != NULL);
00300 mAllocatedMemoryForMesh = false;
00301 mpMesh = pMesh;
00302 }
00303
00304 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00305 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::PrintOutput(bool printOutput)
00306 {
00307 mPrintOutput = printOutput;
00308 }
00309
00310 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00311 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetWriteInfo(bool writeInfo)
00312 {
00313 mWriteInfo = writeInfo;
00314 }
00315
00316 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00317 Vec AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetSolution()
00318 {
00319 return mSolution;
00320 }
00321
00322 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00323 DistributedVector AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetSolutionDistributedVector()
00324 {
00325 return mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00326 }
00327
00328 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00329 double AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetCurrentTime()
00330 {
00331 return mCurrentTime;
00332 }
00333
00334 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00335 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::rGetMesh()
00336 {
00337 assert (mpMesh);
00338 return *mpMesh;
00339 }
00340
00341 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00342 AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetTissue()
00343 {
00344 if (mpCardiacTissue == NULL)
00345 {
00346 EXCEPTION("Tissue not yet set up, you may need to call Initialise() before GetTissue().");
00347 }
00348 return mpCardiacTissue;
00349 }
00350
00351 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00352 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetUseTimeAdaptivityController(
00353 bool useAdaptivity,
00354 AbstractTimeAdaptivityController* pController)
00355 {
00356 if (useAdaptivity)
00357 {
00358 assert(pController);
00359 mpTimeAdaptivityController = pController;
00360 }
00361 else
00362 {
00363 mpTimeAdaptivityController = NULL;
00364 }
00365 }
00366
00367
00368 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00369 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::Solve()
00370 {
00371 PreSolveChecks();
00372
00373 std::vector<double> additional_stopping_times;
00374 SetUpAdditionalStoppingTimes(additional_stopping_times);
00375
00376 TimeStepper stepper(mCurrentTime,
00377 HeartConfig::Instance()->GetSimulationDuration(),
00378 HeartConfig::Instance()->GetPrintingTimeStep(),
00379 false,
00380 additional_stopping_times);
00381
00382
00383
00384
00385 if (!mpBoundaryConditionsContainer)
00386 {
00387
00388 mpDefaultBoundaryConditionsContainer.reset(new BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>);
00389 for (unsigned problem_index=0; problem_index<PROBLEM_DIM; problem_index++)
00390 {
00391 mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00392 }
00393 mpBoundaryConditionsContainer = mpDefaultBoundaryConditionsContainer;
00394 }
00395
00396 assert(mpSolver==NULL);
00397 mpSolver = CreateSolver();
00398
00399
00400 Vec initial_condition;
00401 if (mSolution)
00402 {
00403 initial_condition = mSolution;
00404 }
00405 else
00406 {
00407 initial_condition = CreateInitialCondition();
00408 }
00409
00410 std::string progress_reporter_dir;
00411
00412 if (mPrintOutput)
00413 {
00414 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00415 bool extending_file = false;
00416 try
00417 {
00418 extending_file = InitialiseWriter();
00419 }
00420 catch (Exception& e)
00421 {
00422 delete mpWriter;
00423 mpWriter = NULL;
00424 delete mpSolver;
00425 if (mSolution != initial_condition)
00426 {
00427
00428
00429
00430
00431
00432
00433
00434 PetscTools::Destroy(initial_condition);
00435 }
00436 throw e;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445 if (!(mSolution && extending_file))
00446 {
00447 WriteOneStep(stepper.GetTime(), initial_condition);
00448 mpWriter->AdvanceAlongUnlimitedDimension();
00449 }
00450 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00451
00452 progress_reporter_dir = HeartConfig::Instance()->GetOutputDirectory();
00453 }
00454 else
00455 {
00456 progress_reporter_dir = "";
00457 }
00458
00459
00460
00461
00462
00463
00464 ProgressReporter progress_reporter(progress_reporter_dir,
00465 mCurrentTime,
00466 HeartConfig::Instance()->GetSimulationDuration());
00467 progress_reporter.Update(mCurrentTime);
00468
00469 mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00470 if (mpTimeAdaptivityController)
00471 {
00472 mpSolver->SetTimeAdaptivityController(mpTimeAdaptivityController);
00473 }
00474
00475 while (!stepper.IsTimeAtEnd())
00476 {
00477
00478 mpSolver->SetTimes(stepper.GetTime(), stepper.GetNextTime());
00479 mpSolver->SetInitialCondition( initial_condition );
00480
00481 AtBeginningOfTimestep(stepper.GetTime());
00482
00483 try
00484 {
00485 try
00486 {
00487 mSolution = mpSolver->Solve();
00488 }
00489 catch (const Exception &e)
00490 {
00491 #ifndef NDEBUG
00492 PetscTools::ReplicateException(true);
00493 #endif
00494 throw e;
00495 }
00496 #ifndef NDEBUG
00497 PetscTools::ReplicateException(false);
00498 #endif
00499 }
00500 catch (const Exception& e)
00501 {
00502
00503 delete mpSolver;
00504 mpSolver = NULL;
00505 if (initial_condition != mSolution)
00506 {
00507
00508
00509
00510
00511
00512
00513
00514
00515 PetscTools::Destroy(initial_condition);
00516 }
00517
00518
00519 HeartEventHandler::Reset();
00520 CloseFilesAndPostProcess();
00521
00522 throw e;
00523 }
00524
00525
00526 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00527 PetscTools::Destroy(initial_condition);
00528 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00529
00530
00531 initial_condition = mSolution;
00532
00533
00534 stepper.AdvanceOneTimeStep();
00535 mCurrentTime = stepper.GetTime();
00536
00537
00538 if (mWriteInfo)
00539 {
00540 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00541 WriteInfo(stepper.GetTime());
00542 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00543 }
00544
00545 if (mPrintOutput)
00546 {
00547
00548 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00549 WriteOneStep(stepper.GetTime(), mSolution);
00550
00551 mpWriter->AdvanceAlongUnlimitedDimension();
00552
00553 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00554 }
00555
00556 progress_reporter.Update(stepper.GetTime());
00557
00558 OnEndOfTimestep(stepper.GetTime());
00559 }
00560
00561
00562 delete mpSolver;
00563 mpSolver = NULL;
00564
00565
00566 progress_reporter.PrintFinalising();
00567 CloseFilesAndPostProcess();
00568 HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING);
00569 }
00570
00571 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00572 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::CloseFilesAndPostProcess()
00573 {
00574
00575 if (!mPrintOutput)
00576 {
00577
00578 return;
00579 }
00580 delete mpWriter;
00581 mpWriter = NULL;
00582
00583 FileFinder test_output(HeartConfig::Instance()->GetOutputDirectory(), RelativeTo::ChasteTestOutput);
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594 HeartEventHandler::BeginEvent(HeartEventHandler::POST_PROC);
00595 if(HeartConfig::Instance()->IsPostProcessingRequested())
00596 {
00597 PostProcessingWriter<ELEMENT_DIM, SPACE_DIM> post_writer(*mpMesh,
00598 test_output,
00599 HeartConfig::Instance()->GetOutputFilenamePrefix());
00600 post_writer.WritePostProcessingFiles();
00601 }
00602 HeartEventHandler::EndEvent(HeartEventHandler::POST_PROC);
00603
00604
00605
00606
00607
00608 HeartEventHandler::BeginEvent(HeartEventHandler::DATA_CONVERSION);
00609
00610 if (mNodesToOutput.empty())
00611 {
00612 if (HeartConfig::Instance()->GetVisualizeWithMeshalyzer())
00613 {
00614
00615 Hdf5ToMeshalyzerConverter<ELEMENT_DIM,SPACE_DIM> converter(test_output,
00616 HeartConfig::Instance()->GetOutputFilenamePrefix(),
00617 mpMesh,
00618 HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering(),
00619 HeartConfig::Instance()->GetVisualizerOutputPrecision() );
00620 std::string subdirectory_name = converter.GetSubdirectory();
00621 HeartConfig::Instance()->Write(false, subdirectory_name);
00622 }
00623
00624 if (HeartConfig::Instance()->GetVisualizeWithCmgui())
00625 {
00626
00627 Hdf5ToCmguiConverter<ELEMENT_DIM,SPACE_DIM> converter(test_output,
00628 HeartConfig::Instance()->GetOutputFilenamePrefix(),
00629 mpMesh,
00630 GetHasBath(),
00631 HeartConfig::Instance()->GetVisualizerOutputPrecision() );
00632 std::string subdirectory_name = converter.GetSubdirectory();
00633 HeartConfig::Instance()->Write(false, subdirectory_name);
00634 }
00635
00636 if (HeartConfig::Instance()->GetVisualizeWithVtk())
00637 {
00638
00639 Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(test_output,
00640 HeartConfig::Instance()->GetOutputFilenamePrefix(),
00641 mpMesh,
00642 false,
00643 HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering());
00644 std::string subdirectory_name = converter.GetSubdirectory();
00645 HeartConfig::Instance()->Write(false, subdirectory_name);
00646 }
00647
00648 if (HeartConfig::Instance()->GetVisualizeWithParallelVtk())
00649 {
00650
00651 Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(test_output,
00652 HeartConfig::Instance()->GetOutputFilenamePrefix(),
00653 mpMesh,
00654 true,
00655 HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering());
00656 std::string subdirectory_name = converter.GetSubdirectory();
00657 HeartConfig::Instance()->Write(false, subdirectory_name);
00658 }
00659 }
00660 HeartEventHandler::EndEvent(HeartEventHandler::DATA_CONVERSION);
00661 }
00662
00663 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00664 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::DefineWriterColumns(bool extending)
00665 {
00666 if (!extending)
00667 {
00668 if ( mNodesToOutput.empty() )
00669 {
00670
00671 mpWriter->DefineFixedDimension( mpMesh->GetNumNodes() );
00672 }
00673 else
00674 {
00675
00676 mpWriter->DefineFixedDimension( mNodesToOutput, mpMesh->GetNumNodes() );
00677 }
00678
00679 mVoltageColumnId = mpWriter->DefineVariable("V","mV");
00680
00681
00682 TimeStepper stepper(mCurrentTime,
00683 HeartConfig::Instance()->GetSimulationDuration(),
00684 HeartConfig::Instance()->GetPrintingTimeStep());
00685
00686 mpWriter->DefineUnlimitedDimension("Time","msecs", stepper.EstimateTimeSteps()+1);
00687 }
00688 else
00689 {
00690 mVoltageColumnId = mpWriter->GetVariableByName("V");
00691 }
00692 }
00693
00694 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00695 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::DefineExtraVariablesWriterColumns(bool extending)
00696 {
00697 mExtraVariablesId.clear();
00698
00699 if (HeartConfig::Instance()->GetOutputVariablesProvided())
00700 {
00701
00702 std::vector<std::string> output_variables;
00703 HeartConfig::Instance()->GetOutputVariables(output_variables);
00704 const unsigned num_vars = output_variables.size();
00705 mExtraVariablesId.reserve(num_vars);
00706
00707
00708 for (unsigned var_index=0; var_index<num_vars; var_index++)
00709 {
00710
00711 std::string var_name = output_variables[var_index];
00712
00713
00714 unsigned column_id;
00715 if (extending)
00716 {
00717 column_id = this->mpWriter->GetVariableByName(var_name);
00718 }
00719 else
00720 {
00721
00722
00723 column_id = this->mpWriter->DefineVariable(var_name, "unknown_units");
00724 }
00725
00726
00727 mExtraVariablesId.push_back(column_id);
00728 }
00729 }
00730 }
00731
00732 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00733 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::WriteExtraVariablesOneStep()
00734 {
00735
00736 std::vector<std::string> output_variables;
00737 unsigned num_vars = mExtraVariablesId.size();
00738 if (num_vars > 0)
00739 {
00740 HeartConfig::Instance()->GetOutputVariables(output_variables);
00741 }
00742 assert(output_variables.size() == num_vars);
00743
00744
00745 for (unsigned var_index=0; var_index<num_vars; var_index++)
00746 {
00747
00748 Vec variable_data = this->mpMesh->GetDistributedVectorFactory()->CreateVec();
00749 DistributedVector distributed_var_data = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(variable_data);
00750
00751
00752 for (DistributedVector::Iterator index = distributed_var_data.Begin();
00753 index!= distributed_var_data.End();
00754 ++index)
00755 {
00756
00757 if (HeartRegionCode::IsRegionBath( this->mpMesh->GetNode( index.Global )->GetRegion() ))
00758 {
00759
00760
00761 distributed_var_data[index] = 0.0;
00762 }
00763 else
00764 {
00765
00766 distributed_var_data[index] = this->mpCardiacTissue->GetCardiacCell(index.Global)->
00767 GetAnyVariable(output_variables[var_index], mCurrentTime);
00768 }
00769 }
00770 distributed_var_data.Restore();
00771
00772
00773 this->mpWriter->PutVector(mExtraVariablesId[var_index], variable_data);
00774
00775 PetscTools::Destroy(variable_data);
00776 }
00777 }
00778
00779 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00780 bool AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::InitialiseWriter()
00781 {
00782 bool extend_file = (mSolution != NULL);
00783
00784
00785 assert(!mpWriter);
00786
00787 if (extend_file)
00788 {
00789 FileFinder h5_file(OutputFileHandler::GetChasteTestOutputDirectory() + HeartConfig::Instance()->GetOutputDirectory()
00790 + "/" + HeartConfig::Instance()->GetOutputFilenamePrefix() + ".h5",
00791 RelativeTo::Absolute);
00792
00793
00794
00795
00796 PetscTools::Barrier("InitialiseWriter::Extension check");
00797 if (!h5_file.Exists())
00798 {
00799 extend_file = false;
00800 }
00801 else
00802 {
00803 Hdf5DataReader reader(HeartConfig::Instance()->GetOutputDirectory(),
00804 HeartConfig::Instance()->GetOutputFilenamePrefix(),
00805 true);
00806 std::vector<double> times = reader.GetUnlimitedDimensionValues();
00807 if (times.back() > mCurrentTime)
00808 {
00809 EXCEPTION("Attempting to extend " << h5_file.GetAbsolutePath() <<
00810 " with results from time = " << mCurrentTime <<
00811 ", but it already contains results up to time = " << times.back() << "."
00812 " Calling HeartConfig::Instance()->SetOutputDirectory() before Solve() will direct results elsewhere.");
00813 }
00814 }
00815 PetscTools::Barrier("InitialiseWriter::Extension check");
00816 }
00817 mpWriter = new Hdf5DataWriter(*mpMesh->GetDistributedVectorFactory(),
00818 HeartConfig::Instance()->GetOutputDirectory(),
00819 HeartConfig::Instance()->GetOutputFilenamePrefix(),
00820 !extend_file,
00821 extend_file);
00822
00823
00824
00825 DefineWriterColumns(extend_file);
00826
00827
00828 if (HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering())
00829 {
00830 bool success = mpWriter->ApplyPermutation(mpMesh->rGetNodePermutation(), true);
00831 if (success == false)
00832 {
00833
00834 HeartConfig::Instance()->SetOutputUsingOriginalNodeOrdering(false);
00835 }
00836 }
00837
00838 if (!extend_file)
00839 {
00840 mpWriter->EndDefineMode();
00841 }
00842
00843 return extend_file;
00844 }
00845
00846 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00847 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetOutputNodes(std::vector<unsigned> &nodesToOutput)
00848 {
00849 mNodesToOutput = nodesToOutput;
00850 }
00851
00852 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00853 Hdf5DataReader AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetDataReader()
00854 {
00855 if( (HeartConfig::Instance()->GetOutputDirectory()=="") || (HeartConfig::Instance()->GetOutputFilenamePrefix()==""))
00856 {
00857 EXCEPTION("Data reader invalid as data writer cannot be initialised");
00858 }
00859 return Hdf5DataReader(HeartConfig::Instance()->GetOutputDirectory(), HeartConfig::Instance()->GetOutputFilenamePrefix());
00860 }
00861
00862 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00863 bool AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetHasBath()
00864 {
00865 return false;
00866 }
00867
00868 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00869 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetElectrodes()
00870 {
00871 }
00872
00873
00875
00877
00878
00879 template class AbstractCardiacProblem<1,1,1>;
00880 template class AbstractCardiacProblem<1,2,1>;
00881 template class AbstractCardiacProblem<1,3,1>;
00882 template class AbstractCardiacProblem<2,2,1>;
00883 template class AbstractCardiacProblem<3,3,1>;
00884
00885
00886 template class AbstractCardiacProblem<1,1,2>;
00887 template class AbstractCardiacProblem<2,2,2>;
00888 template class AbstractCardiacProblem<3,3,2>;
00889
00890
00891 template class AbstractCardiacProblem<1,1,3>;
00892 template class AbstractCardiacProblem<2,2,3>;
00893 template class AbstractCardiacProblem<3,3,3>;