AbstractCardiacProblem.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "AbstractCardiacProblem.hpp"
00030 
00031 #include "GenericMeshReader.hpp"
00032 #include "Exception.hpp"
00033 #include "HeartConfig.hpp"
00034 #include "HeartEventHandler.hpp"
00035 #include "TimeStepper.hpp"
00036 #include "PetscTools.hpp"
00037 #include "DistributedVector.hpp"
00038 #include "ProgressReporter.hpp"
00039 #include "LinearSystem.hpp"
00040 #include "PostProcessingWriter.hpp"
00041 #include "Hdf5ToMeshalyzerConverter.hpp"
00042 #include "Hdf5ToCmguiConverter.hpp"
00043 #include "Hdf5ToVtkConverter.hpp"
00044 
00045 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00046 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::AbstractCardiacProblem(
00047             AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory)
00048     : mMeshFilename(""), // i.e. undefined
00049       mAllocatedMemoryForMesh(false),
00050       mWriteInfo(false),
00051       mPrintOutput(true),
00052       mpCardiacTissue(NULL),
00053       mpSolver(NULL),
00054       mpCellFactory(pCellFactory),
00055       mpMesh(NULL),
00056       mSolution(NULL),
00057       mCurrentTime(0.0),
00058       mpTimeAdaptivityController(NULL),
00059       mpWriter(NULL)
00060 {
00061     assert(mNodesToOutput.empty());
00062     if (!mpCellFactory)
00063     {
00064         EXCEPTION("AbstractCardiacProblem: Please supply a cell factory pointer to your cardiac problem constructor.");
00065     }
00066     HeartEventHandler::BeginEvent(HeartEventHandler::EVERYTHING);
00067 }
00068 
00069 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00070 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::AbstractCardiacProblem()
00071     // It doesn't really matter what we initialise these to, as they'll be overwritten by
00072     // the serialization methods
00073     : mMeshFilename(""),
00074       mAllocatedMemoryForMesh(false), // Handled by AbstractCardiacTissue
00075       mWriteInfo(false),
00076       mPrintOutput(true),
00077       mVoltageColumnId(UINT_MAX),
00078       mTimeColumnId(UINT_MAX),
00079       mNodeColumnId(UINT_MAX),
00080       mpCardiacTissue(NULL),
00081       mpSolver(NULL),
00082       mpCellFactory(NULL),
00083       mpMesh(NULL),
00084       mSolution(NULL),
00085       mCurrentTime(0.0),
00086       mpTimeAdaptivityController(NULL),
00087       mpWriter(NULL)
00088 {
00089 }
00090 
00091 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00092 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::~AbstractCardiacProblem()
00093 {
00094     delete mpCardiacTissue;
00095     if (mSolution)
00096     {
00097         VecDestroy(mSolution);
00098     }
00099 
00100     if (mAllocatedMemoryForMesh)
00101     {
00102         delete mpMesh;
00103     }
00104 }
00105 
00106 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00107 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::Initialise()
00108 {
00109     HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00110     if (mpMesh==NULL)
00111     {
00112         // If no mesh has been passed, we get it from the configuration file
00113         try
00114         {
00115             if (HeartConfig::Instance()->GetLoadMesh())
00116             {
00117                 mpMesh = new DistributedTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>(HeartConfig::Instance()->GetMeshPartitioning());
00118                 std::auto_ptr<AbstractMeshReader<ELEMENT_DIM, SPACE_DIM> > p_mesh_reader
00119                     = GenericMeshReader<ELEMENT_DIM, SPACE_DIM>(HeartConfig::Instance()->GetMeshName());
00120                 mpMesh->ConstructFromMeshReader(*p_mesh_reader);
00121             }
00122             else if (HeartConfig::Instance()->GetCreateMesh())
00123             {
00124                 mpMesh = new DistributedTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>(HeartConfig::Instance()->GetMeshPartitioning());
00125                 assert(HeartConfig::Instance()->GetSpaceDimension()==SPACE_DIM);
00126                 double inter_node_space = HeartConfig::Instance()->GetInterNodeSpace();
00127 
00128                 switch(HeartConfig::Instance()->GetSpaceDimension())
00129                 {
00130                     case 1:
00131                     {
00132                         c_vector<double, 1> fibre_length;
00133                         HeartConfig::Instance()->GetFibreLength(fibre_length);
00134                         mpMesh->ConstructRegularSlabMesh(inter_node_space, fibre_length[0]);
00135                         break;
00136                     }
00137                     case 2:
00138                     {
00139                         c_vector<double, 2> sheet_dimensions; //cm
00140                         HeartConfig::Instance()->GetSheetDimensions(sheet_dimensions);
00141                         mpMesh->ConstructRegularSlabMesh(inter_node_space, sheet_dimensions[0], sheet_dimensions[1]);
00142                         break;
00143                     }
00144                     case 3:
00145                     {
00146                         c_vector<double, 3> slab_dimensions; //cm
00147                         HeartConfig::Instance()->GetSlabDimensions(slab_dimensions);
00148                         mpMesh->ConstructRegularSlabMesh(inter_node_space, slab_dimensions[0], slab_dimensions[1], slab_dimensions[2]);
00149                         break;
00150                     }
00151                     default:
00152                         NEVER_REACHED;
00153                 }
00154             }
00155             else
00156             {
00157                 NEVER_REACHED;
00158             }
00159 
00160             mAllocatedMemoryForMesh = true;
00161         }
00162         catch (Exception& e)
00163         {
00164             EXCEPTION(std::string("No mesh given: define it in XML parameters file or call SetMesh()\n") + e.GetShortMessage());
00165         }
00166     }
00167     mpCellFactory->SetMesh( mpMesh );
00168     HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00169 
00170     HeartEventHandler::BeginEvent(HeartEventHandler::INITIALISE);
00171 
00172     // If the user requested transmural stuff, we fill in the mCellHeterogeneityAreas here
00173     if (HeartConfig::Instance()->AreCellularTransmuralHeterogeneitiesRequested())
00174     {
00175         mpCellFactory->FillInCellularTransmuralAreas();
00176     }
00177 
00178     delete mpCardiacTissue; // In case we're called twice
00179     mpCardiacTissue = CreateCardiacTissue();
00180 
00181     HeartEventHandler::EndEvent(HeartEventHandler::INITIALISE);
00182 
00183     // Delete any previous solution, so we get a fresh initial condition
00184     if (mSolution)
00185     {
00186         HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00187         VecDestroy(mSolution);
00188         mSolution = NULL;
00189         HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00190     }
00191 
00192     // Always start at time zero
00193     mCurrentTime = 0.0;
00194 
00195     // For Bidomain with bath, this is where we set up the electrodes
00196 
00197     SetElectrodes();
00198 }
00199 
00200 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00201 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetBoundaryConditionsContainer(boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> > pBcc)
00202 {
00203     this->mpBoundaryConditionsContainer = pBcc;
00204 }
00205 
00206 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00207 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::PreSolveChecks()
00208 {
00209     if ( mpCardiacTissue == NULL ) // if tissue is NULL, Initialise() probably hasn't been called
00210     {
00211         EXCEPTION("Cardiac tissue is null, Initialise() probably hasn't been called");
00212     }
00213     if ( HeartConfig::Instance()->GetSimulationDuration() <= mCurrentTime)
00214     {
00215         EXCEPTION("End time should be in the future");
00216     }
00217     if (mPrintOutput)
00218     {
00219         if( (HeartConfig::Instance()->GetOutputDirectory()=="") || (HeartConfig::Instance()->GetOutputFilenamePrefix()==""))
00220         {
00221             EXCEPTION("Either explicitly specify not to print output (call PrintOutput(false)) or specify the output directory and filename prefix");
00222         }
00223     }
00224 
00225     double end_time = HeartConfig::Instance()->GetSimulationDuration();
00226     double pde_time = HeartConfig::Instance()->GetPdeTimeStep();
00227 
00228     /*
00229      * MatrixIsConstant stuff requires CONSTANT dt - do some checks to make sure
00230      * the TimeStepper won't find non-constant dt.
00231      * Note: printing_time does not have to divide end_time, but dt must divide
00232      * printing_time and end_time.
00233      * HeartConfig checks pde_dt divides printing dt.
00234      */
00236     if( fabs(end_time - pde_time*round(end_time/pde_time)) > 1e-10 )
00237     {
00238         EXCEPTION("PDE timestep does not seem to divide end time - check parameters");
00239     }
00240 }
00241 
00242 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00243 Vec AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::CreateInitialCondition()
00244 {
00245     DistributedVectorFactory* p_factory = mpMesh->GetDistributedVectorFactory();
00246     Vec initial_condition = p_factory->CreateVec(PROBLEM_DIM);
00247     DistributedVector ic = p_factory->CreateDistributedVector(initial_condition);
00248     std::vector<DistributedVector::Stripe> stripe;
00249     stripe.reserve(PROBLEM_DIM);
00250 
00251     for (unsigned i=0; i<PROBLEM_DIM; i++)
00252     {
00253         stripe.push_back(DistributedVector::Stripe(ic, i));
00254     }
00255 
00256     for (DistributedVector::Iterator index = ic.Begin();
00257          index != ic.End();
00258          ++index)
00259     {
00260         stripe[0][index] = mpCardiacTissue->GetCardiacCell(index.Global)->GetVoltage();
00261         if (PROBLEM_DIM==2)
00262         {
00263             stripe[1][index] = 0;
00264         }
00265     }
00266 
00267     ic.Restore();
00268 
00269     return initial_condition;
00270 }
00271 
00272 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00273 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00274 {
00275     /*
00276      * If this fails the mesh has already been set. We assert rather throw
00277      * an exception to avoid a memory leak when checking it throws correctly.
00278      */
00279     assert(mpMesh == NULL);
00280     assert(pMesh != NULL);
00281     mAllocatedMemoryForMesh = false;
00282     mpMesh = pMesh;
00283 }
00284 
00285 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00286 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::PrintOutput(bool printOutput)
00287 {
00288     mPrintOutput = printOutput;
00289 }
00290 
00291 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00292 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetWriteInfo(bool writeInfo)
00293 {
00294     mWriteInfo = writeInfo;
00295 }
00296 
00297 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00298 Vec AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetSolution()
00299 {
00300     return mSolution;
00301 }
00302 
00303 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00304 DistributedVector AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetSolutionDistributedVector()
00305 {
00306     return mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00307 }
00308 
00309 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00310 double AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetCurrentTime()
00311 {
00312     return mCurrentTime;
00313 }
00314 
00315 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00316 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::rGetMesh()
00317 {
00318     assert (mpMesh);
00319     return *mpMesh;
00320 }
00321 
00322 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00323 AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetTissue()
00324 {
00325     return mpCardiacTissue;
00326 }
00327 
00328 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00329 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetUseTimeAdaptivityController(
00330         bool useAdaptivity,
00331         AbstractTimeAdaptivityController* pController)
00332 {
00333     if (useAdaptivity)
00334     {
00335         assert(pController);
00336         mpTimeAdaptivityController = pController;
00337     }
00338     else
00339     {
00340         mpTimeAdaptivityController = NULL;
00341     }
00342 }
00343 
00344 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00345 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::Solve()
00346 {
00347     PreSolveChecks();
00348 
00349     if (!mpBoundaryConditionsContainer) // the user didn't supply a bcc
00350     {
00351         // Set up the default bcc
00352         mpDefaultBoundaryConditionsContainer.reset(new BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>);
00353         for (unsigned problem_index=0; problem_index<PROBLEM_DIM; problem_index++)
00354         {
00355             mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00356         }
00357         mpBoundaryConditionsContainer = mpDefaultBoundaryConditionsContainer;
00358     }
00359 
00360     assert(mpSolver==NULL);
00361     mpSolver = CreateSolver(); // passes mpBoundaryConditionsContainer to solver
00362 
00363     // If we have already run a simulation, use the old solution as initial condition
00364     Vec initial_condition;
00365     if (mSolution)
00366     {
00367         initial_condition = mSolution;
00368     }
00369     else
00370     {
00371         initial_condition = CreateInitialCondition();
00372     }
00373 
00374     std::vector<double> additional_stopping_times;
00375     SetUpAdditionalStoppingTimes(additional_stopping_times);
00376 
00377     TimeStepper stepper(mCurrentTime,
00378                         HeartConfig::Instance()->GetSimulationDuration(),
00379                         HeartConfig::Instance()->GetPrintingTimeStep(),
00380                         false,
00381                         additional_stopping_times);
00382 
00383     std::string progress_reporter_dir;
00384 
00385     if (mPrintOutput)
00386     {
00387         HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00388         try
00389         {
00390             InitialiseWriter();
00391         }
00392         catch (Exception& e)
00393         {
00394             delete mpWriter;
00395             mpWriter = NULL;
00396             delete mpSolver;
00397             if (mSolution != initial_condition)
00398             {
00399                 /*
00400                  * A PETSc Vec is a pointer, so we *don't* need to free the memory if it is
00401                  * freed somewhere else (e.g. in the destructor). If this is a resumed solution
00402                  * we set initial_condition = mSolution earlier. mSolution is going to be
00403                  * cleaned up in the constructor. So, only VecDestroy initial_condition when
00404                  * it is not equal to mSolution (see #1695).
00405                  */
00406                 VecDestroy(initial_condition);
00407             }
00408             throw e;
00409         }
00410 
00411         /*
00412          * If we are resuming a simulation (i.e. mSolution already exists) there's no need
00413          * to write the initial timestep, since it was already written as the last timestep
00414          * of the previous run.
00415          */
00416         if (!mSolution)
00417         {
00418             WriteOneStep(stepper.GetTime(), initial_condition);
00419             mpWriter->AdvanceAlongUnlimitedDimension();
00420         }
00421         HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00422 
00423         progress_reporter_dir = HeartConfig::Instance()->GetOutputDirectory();
00424     }
00425     else
00426     {
00427         progress_reporter_dir = ""; // progress printed to CHASTE_TEST_OUTPUT
00428     }
00429 
00430     /*
00431      * Create a progress reporter so users can track how much has gone and
00432      * estimate how much time is left. Note this has to be done after the
00433      * InitialiseWriter above (if mPrintOutput==true).
00434      */
00435     ProgressReporter progress_reporter(progress_reporter_dir,
00436                                        mCurrentTime,
00437                                        HeartConfig::Instance()->GetSimulationDuration());
00438     progress_reporter.Update(mCurrentTime);
00439 
00440     mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00441     if (mpTimeAdaptivityController)
00442     {
00443         mpSolver->SetTimeAdaptivityController(mpTimeAdaptivityController);
00444     }
00445 
00446     while (!stepper.IsTimeAtEnd())
00447     {
00448         // Solve from now up to the next printing time
00449         mpSolver->SetTimes(stepper.GetTime(), stepper.GetNextTime());
00450         mpSolver->SetInitialCondition( initial_condition );
00451 
00452         AtBeginningOfTimestep(stepper.GetTime());
00453 
00454         try
00455         {
00456             mSolution = mpSolver->Solve();
00457         }
00458         catch (Exception &e)
00459         {
00460             // Free memory
00461             delete mpSolver;
00462             mpSolver=NULL;
00463             if (initial_condition != mSolution)
00464             {
00465                 /*
00466                  * A PETSc Vec is a pointer, so we *don't* need to free the memory if it is
00467                  * freed somewhere else (e.g. in the destructor). Later, in this while loop
00468                  * we will set initial_condition = mSolution (or, if this is a resumed solution
00469                  * it may also have been done when initial_condition was created). mSolution
00470                  * is going to be cleaned up in the constructor. So, only VecDestroy
00471                  * initial_condition when it is not equal to mSolution (see #1695).
00472                  */
00473                 VecDestroy(initial_condition);
00474             }
00475 
00476 #ifndef NDEBUG
00477             PetscTools::ReplicateException(true);
00478 #endif
00479             // Re-throw
00480             HeartEventHandler::Reset();//EndEvent(HeartEventHandler::EVERYTHING);
00482             CloseFilesAndPostProcess();
00483             throw e;
00484         }
00485 #ifndef NDEBUG
00486         PetscTools::ReplicateException(false);
00487 #endif
00488 
00489         // Free old initial condition
00490         HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00491         VecDestroy(initial_condition);
00492         HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00493 
00494         // Initial condition for next loop is current solution
00495         initial_condition = mSolution;
00496 
00497         // Update the current time
00498         stepper.AdvanceOneTimeStep();
00499         mCurrentTime = stepper.GetTime();
00500 
00501         // Print out details at current time if asked for
00502         if (mWriteInfo)
00503         {
00504             HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00505             WriteInfo(stepper.GetTime());
00506             HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00507         }
00508 
00509         if (mPrintOutput)
00510         {
00511             // Writing data out to the file <FilenamePrefix>.dat
00512             HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00513             WriteOneStep(stepper.GetTime(), mSolution);
00514             // Just flags that we've finished a time-step; won't actually 'extend' unless new data is written.
00515             mpWriter->AdvanceAlongUnlimitedDimension();
00516 
00517             HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00518         }
00519 
00520         progress_reporter.Update(stepper.GetTime());
00521 
00522         OnEndOfTimestep(stepper.GetTime());
00523     }
00524 
00525     // Free solver
00526     delete mpSolver;
00527     mpSolver = NULL;
00528 
00529     // Close the file that stores voltage values
00530     progress_reporter.PrintFinalising();
00531     CloseFilesAndPostProcess();
00532     HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING);
00533 }
00534 
00535 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00536 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::CloseFilesAndPostProcess()
00537 {
00538     // Close files
00539     if (!mPrintOutput)
00540     {
00541         // Nothing to do
00542         return;
00543     }
00544     delete mpWriter;
00545     mpWriter = NULL;
00546 
00547     HeartEventHandler::BeginEvent(HeartEventHandler::DATA_CONVERSION);
00548     // Only if results files were written and we are outputting all nodes
00549     if (mNodesToOutput.empty())
00550     {
00551         if (HeartConfig::Instance()->GetVisualizeWithMeshalyzer())
00552         {
00553             // Convert simulation data to Meshalyzer format
00554             Hdf5ToMeshalyzerConverter<ELEMENT_DIM,SPACE_DIM> converter(HeartConfig::Instance()->GetOutputDirectory(),
00555                     HeartConfig::Instance()->GetOutputFilenamePrefix(), mpMesh, HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering());
00556             std::string subdirectory_name = converter.GetSubdirectory();
00557             HeartConfig::Instance()->Write(false, subdirectory_name);
00558         }
00559 
00560         if (HeartConfig::Instance()->GetVisualizeWithCmgui())
00561         {
00562             // Convert simulation data to Cmgui format
00563             Hdf5ToCmguiConverter<ELEMENT_DIM,SPACE_DIM> converter(HeartConfig::Instance()->GetOutputDirectory(),
00564                     HeartConfig::Instance()->GetOutputFilenamePrefix(), mpMesh, GetHasBath());
00565             std::string subdirectory_name = converter.GetSubdirectory();
00566             HeartConfig::Instance()->Write(false, subdirectory_name);
00567         }
00568 
00569         if (HeartConfig::Instance()->GetVisualizeWithVtk())
00570         {
00571             // Convert simulation data to VTK format
00572             Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(HeartConfig::Instance()->GetOutputDirectory(),
00573                     HeartConfig::Instance()->GetOutputFilenamePrefix(), mpMesh, false, HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering());
00574             std::string subdirectory_name = converter.GetSubdirectory();
00575             HeartConfig::Instance()->Write(false, subdirectory_name);
00576         }
00577 
00578         if (HeartConfig::Instance()->GetVisualizeWithParallelVtk())
00579         {
00580             // Convert simulation data to parallel VTK (pvtu) format
00581             Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(HeartConfig::Instance()->GetOutputDirectory(),
00582                     HeartConfig::Instance()->GetOutputFilenamePrefix(), mpMesh, true, HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering());
00583             std::string subdirectory_name = converter.GetSubdirectory();
00584             HeartConfig::Instance()->Write(false, subdirectory_name);
00585         }
00586     }
00587     HeartEventHandler::EndEvent(HeartEventHandler::DATA_CONVERSION);
00588 
00589     HeartEventHandler::BeginEvent(HeartEventHandler::POST_PROC);
00590     if(HeartConfig::Instance()->IsPostProcessingRequested())
00591     {
00592         PostProcessingWriter<ELEMENT_DIM, SPACE_DIM> post_writer(*mpMesh, HeartConfig::Instance()->GetOutputDirectory(),
00593                         HeartConfig::Instance()->GetOutputFilenamePrefix(), true);
00594         post_writer.WritePostProcessingFiles();
00595     }
00596 
00597     HeartEventHandler::EndEvent(HeartEventHandler::POST_PROC);
00598 }
00599 
00600 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00601 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::DefineWriterColumns(bool extending)
00602 {
00603     if (!extending)
00604     {
00605         if ( mNodesToOutput.empty() )
00606         {
00607             //Set writer to output all nodes
00608             mpWriter->DefineFixedDimension( mpMesh->GetNumNodes() );
00609         }
00610         else
00611         {
00612             //Output only the nodes indicted
00613             mpWriter->DefineFixedDimension( mNodesToOutput, mpMesh->GetNumNodes() );
00614         }
00615         //mNodeColumnId = mpWriter->DefineVariable("Node", "dimensionless");
00616         mVoltageColumnId = mpWriter->DefineVariable("V","mV");
00617 
00618         // Only used to get an estimate of the # of timesteps below
00619         TimeStepper stepper(mCurrentTime,
00620                             HeartConfig::Instance()->GetSimulationDuration(),
00621                             HeartConfig::Instance()->GetPrintingTimeStep());
00622 
00623         mpWriter->DefineUnlimitedDimension("Time","msecs", stepper.EstimateTimeSteps()+1); // plus one for start and end points
00624     }
00625     else
00626     {
00627         mVoltageColumnId = mpWriter->GetVariableByName("V");
00628     }
00629 }
00630 
00631 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00632 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::DefineExtraVariablesWriterColumns(bool extending)
00633 {
00634     mExtraVariablesId.clear();
00635     // Check if any extra output variables have been requested
00636     if (HeartConfig::Instance()->GetOutputVariablesProvided())
00637     {
00638         // Get their names in a vector
00639         std::vector<std::string> output_variables;
00640         HeartConfig::Instance()->GetOutputVariables(output_variables);
00641         const unsigned num_vars = output_variables.size();
00642         mExtraVariablesId.reserve(num_vars);
00643 
00644         // Loop over them
00645         for (unsigned var_index=0; var_index<num_vars; var_index++)
00646         {
00647             // Get variable name
00648             std::string var_name = output_variables[var_index];
00649 
00650             // Register it (or look it up) in the data writer
00651             unsigned column_id;
00652             if (extending)
00653             {
00654                 column_id = this->mpWriter->GetVariableByName(var_name);
00655             }
00656             else
00657             {
00658                 column_id = this->mpWriter->DefineVariable(var_name, "");
00659             }
00660 
00661             // Store column id
00662             mExtraVariablesId.push_back(column_id);
00663         }
00664     }
00665 }
00666 
00667 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00668 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::WriteExtraVariablesOneStep()
00669 {
00670     // Get the variable names in a vector
00671     std::vector<std::string> output_variables;
00672     unsigned num_vars = mExtraVariablesId.size();
00673     if (num_vars > 0)
00674     {
00675         HeartConfig::Instance()->GetOutputVariables(output_variables);
00676     }
00677     assert(output_variables.size() == num_vars);
00678 
00679     // Loop over the requested variables
00680     for (unsigned var_index=0; var_index<num_vars; var_index++)
00681     {
00682         // Create vector for storing values over the local nodes
00683         Vec variable_data =  this->mpMesh->GetDistributedVectorFactory()->CreateVec();
00684         DistributedVector distributed_var_data = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(variable_data);
00685 
00686         // Loop over the local nodes and gather the data
00687         for (DistributedVector::Iterator index = distributed_var_data.Begin();
00688              index!= distributed_var_data.End();
00689              ++index)
00690         {
00691             // Find the variable in the cell model
00692             AbstractCardiacCell* p_cell = this->mpCardiacTissue->GetCardiacCell(index.Global);
00693             unsigned cell_id = p_cell->GetAnyVariableIndex(output_variables[var_index]);
00694             // Store its value
00695             distributed_var_data[index] = p_cell->GetAnyVariable(cell_id, mCurrentTime);
00696         }
00697         distributed_var_data.Restore();
00698 
00699         // Write it to disc
00700         this->mpWriter->PutVector(mExtraVariablesId[var_index], variable_data);
00701 
00702         VecDestroy(variable_data);
00703     }
00704 }
00705 
00706 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00707 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::InitialiseWriter()
00708 {
00709     bool extend_file = (mSolution != NULL);
00710 
00711     // I think this is impossible to trip; certainly it's very difficult!
00712     assert(!mpWriter);
00713 
00714     try
00715     {
00716         mpWriter = new Hdf5DataWriter(*mpMesh->GetDistributedVectorFactory(),
00717                                       HeartConfig::Instance()->GetOutputDirectory(),
00718                                       HeartConfig::Instance()->GetOutputFilenamePrefix(),
00719                                       !extend_file, // don't clear directory if extension requested
00720                                       extend_file);
00721     }
00722     catch (Exception& e)
00723     {
00724         // The constructor only throws an Exception if we're extending
00725         assert(extend_file);
00726         // Tried to extend and failed, so just create from scratch
00727         extend_file = false;
00728         mpWriter = new Hdf5DataWriter(*mpMesh->GetDistributedVectorFactory(),
00729                                       HeartConfig::Instance()->GetOutputDirectory(),
00730                                       HeartConfig::Instance()->GetOutputFilenamePrefix(),
00731                                       !extend_file,
00732                                       extend_file);
00733     }
00734 
00735     // Define columns, or get the variable IDs from the writer
00736     DefineWriterColumns(extend_file);
00737 
00738     //Possibility of applying a permutation
00739     if (HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering())
00740     {
00741         bool success = mpWriter->ApplyPermutation(mpMesh->rGetNodePermutation());
00742         if (success == false)
00743         {
00744             //It's not really a permutation, so reset
00745             HeartConfig::Instance()->SetOutputUsingOriginalNodeOrdering(false);
00746         }
00747     }
00748 
00749 
00750     if (!extend_file)
00751     {
00752         mpWriter->EndDefineMode();
00753     }
00754 }
00755 
00756 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00757 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetOutputNodes(std::vector<unsigned> &nodesToOutput)
00758 {
00759     mNodesToOutput = nodesToOutput;
00760 }
00761 
00762 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00763 Hdf5DataReader AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetDataReader()
00764 {
00765     if( (HeartConfig::Instance()->GetOutputDirectory()=="") || (HeartConfig::Instance()->GetOutputFilenamePrefix()==""))
00766     {
00767         EXCEPTION("Data reader invalid as data writer cannot be initialised");
00768     }
00769     return Hdf5DataReader(HeartConfig::Instance()->GetOutputDirectory(), HeartConfig::Instance()->GetOutputFilenamePrefix());
00770 }
00771 
00772 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00773 bool AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetHasBath()
00774 {
00775     return false;
00776 }
00777 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00778 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetElectrodes()
00779 {
00780 }
00781 
00782 
00784 // Explicit instantiation
00786 
00787 // Monodomain
00788 template class AbstractCardiacProblem<1,1,1>;
00789 template class AbstractCardiacProblem<1,2,1>;
00790 template class AbstractCardiacProblem<1,3,1>;
00791 template class AbstractCardiacProblem<2,2,1>;
00792 template class AbstractCardiacProblem<3,3,1>;
00793 
00794 // Bidomain
00795 template class AbstractCardiacProblem<1,1,2>;
00796 template class AbstractCardiacProblem<2,2,2>;
00797 template class AbstractCardiacProblem<3,3,2>;
00798 
00799 // Extended Bidomain
00800 template class AbstractCardiacProblem<1,1,3>;
00801 template class AbstractCardiacProblem<2,2,3>;
00802 template class AbstractCardiacProblem<3,3,3>;
Generated on Thu Dec 22 13:00:06 2011 for Chaste by  doxygen 1.6.3