AbstractCardiacProblem.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 "TrianglesMeshReader.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       mUseMatrixBasedRhsAssembly(true),
00050       mAllocatedMemoryForMesh(false),
00051       mWriteInfo(false),
00052       mPrintOutput(true),
00053       mpCardiacPde(NULL),
00054       mpAssembler(NULL),
00055       mpCellFactory(pCellFactory),
00056       mpMesh(NULL),
00057       mSolution(NULL),
00058       mCurrentTime(0.0),
00059       mpWriter(NULL)
00060 {
00061     assert(mNodesToOutput.empty());
00062 
00063     HeartEventHandler::BeginEvent(HeartEventHandler::EVERYTHING);
00064 }
00065 
00066 
00067 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00068 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::AbstractCardiacProblem()
00069     // it doesn't really matter what we initialise these to, as they'll be overwritten by
00070     // the serialization methods
00071     : mMeshFilename(""),
00072       mUseMatrixBasedRhsAssembly(true),
00073       mAllocatedMemoryForMesh(false), // Handled by AbstractCardiacPde
00074       mWriteInfo(false),
00075       mPrintOutput(true),
00076       mVoltageColumnId(UINT_MAX),
00077       mTimeColumnId(UINT_MAX),
00078       mNodeColumnId(UINT_MAX),
00079       mpCardiacPde(NULL),
00080       mpAssembler(NULL),
00081       mpCellFactory(NULL),
00082       mpMesh(NULL),
00083       mSolution(NULL),
00084       mCurrentTime(0.0),
00085       mpWriter(NULL)
00086 {
00087 }
00088 
00089 
00090 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00091 AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::~AbstractCardiacProblem()
00092 {
00093     delete mpCardiacPde;
00094     if (mSolution)
00095     {
00096         VecDestroy(mSolution);
00097     }
00098 
00099     if (mAllocatedMemoryForMesh)
00100     {
00101         delete mpMesh;
00102     }
00103 };
00104 
00105 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00106 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::Initialise()
00107 {
00108     HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00109     if (mpMesh==NULL)
00110     {
00111         // If no mesh has been passed, we get it from the configuration file
00112         try
00113         {
00114             if(HeartConfig::Instance()->GetLoadMesh())
00115             {
00116                 mpMesh = new DistributedTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>();
00117                 TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM> mesh_reader(HeartConfig::Instance()->GetMeshName());
00118                 mpMesh->ConstructFromMeshReader(mesh_reader);
00119             }
00120             else if(HeartConfig::Instance()->GetCreateMesh())
00121             {
00122                 mpMesh = new DistributedTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>();
00123                 assert(HeartConfig::Instance()->GetSpaceDimension()==SPACE_DIM);
00124                 double inter_node_space = HeartConfig::Instance()->GetInterNodeSpace();
00125 
00126                 switch(HeartConfig::Instance()->GetSpaceDimension())
00127                 {
00128                     case 1:
00129                     {
00130                         c_vector<double, 1> fibre_length;
00131                         HeartConfig::Instance()->GetFibreLength(fibre_length);
00132                         unsigned slab_nodes_x = (unsigned)round(fibre_length[0]/inter_node_space);
00133                         mpMesh->ConstructLinearMesh(slab_nodes_x);
00134                         break;
00135                     }
00136                     case 2:
00137                     {
00138                         c_vector<double, 2> sheet_dimensions; //cm
00139                         HeartConfig::Instance()->GetSheetDimensions(sheet_dimensions);
00140                         unsigned slab_nodes_x = (unsigned)round(sheet_dimensions[0]/inter_node_space);
00141                         unsigned slab_nodes_y = (unsigned)round(sheet_dimensions[1]/inter_node_space);
00142                         mpMesh->ConstructRectangularMesh(slab_nodes_x, slab_nodes_y);
00143                         break;
00144                     }
00145                     case 3:
00146                     {
00147                         c_vector<double, 3> slab_dimensions; //cm
00148                         HeartConfig::Instance()->GetSlabDimensions(slab_dimensions);
00149                         unsigned slab_nodes_x = (unsigned)round(slab_dimensions[0]/inter_node_space);
00150                         unsigned slab_nodes_y = (unsigned)round(slab_dimensions[1]/inter_node_space);
00151                         unsigned slab_nodes_z = (unsigned)round(slab_dimensions[2]/inter_node_space);
00152                         mpMesh->ConstructCuboid(slab_nodes_x, slab_nodes_y, slab_nodes_z);
00153                         break;
00154                     }
00155                     default:
00156                         NEVER_REACHED;
00157                 }
00158                 // scale by mesh_scale_factor = inter_node_space;
00159                 mpMesh->Scale(inter_node_space, inter_node_space, inter_node_space);
00160 
00161             }
00162             else
00163             {
00164                 NEVER_REACHED;
00165             }
00166 
00167             mAllocatedMemoryForMesh = true;
00168         }
00169         catch (Exception& e)
00170         {
00171             EXCEPTION(std::string("No mesh given: define it in XML parameters file or call SetMesh()\n") + e.GetShortMessage());
00172         }
00173     }
00174     mpCellFactory->SetMesh( mpMesh );
00175     HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00176 
00177     HeartEventHandler::BeginEvent(HeartEventHandler::INITIALISE);
00178     // if the user requested transmural stuff, we fill in the mCellHeterogeneityAreas here.
00179     if (HeartConfig::Instance()->AreCellularTransmuralHeterogeneitiesRequested())
00180     {
00181         mpCellFactory->FillInCellularTransmuralAreas();
00182     }
00183 
00184     delete mpCardiacPde; // In case we're called twice
00185     mpCardiacPde = CreateCardiacPde();
00186 
00187     HeartEventHandler::EndEvent(HeartEventHandler::INITIALISE);
00188 
00189     // Delete any previous solution, so we get a fresh initial condition
00190     if (mSolution)
00191     {
00192         HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00193         VecDestroy(mSolution);
00194         mSolution = NULL;
00195         HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00196     }
00197 
00198     // Always start at time zero
00199     mCurrentTime = 0.0;
00200 }
00201 
00202 
00203 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00204 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetBoundaryConditionsContainer(boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> > pBcc)
00205 {
00206     this->mpBoundaryConditionsContainer = pBcc;
00207 }
00208 
00209 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00210 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::PreSolveChecks()
00211 {
00212     if ( mpCardiacPde == NULL ) // if pde is NULL, Initialise() probably hasn't been called
00213     {
00214         EXCEPTION("Pde is null, Initialise() probably hasn't been called");
00215     }
00216     if ( HeartConfig::Instance()->GetSimulationDuration() <= mCurrentTime)
00217     {
00218         EXCEPTION("End time should be in the future");
00219     }
00220     if (mPrintOutput==true)
00221     {
00222         if( (HeartConfig::Instance()->GetOutputDirectory()=="") || (HeartConfig::Instance()->GetOutputFilenamePrefix()==""))
00223         {
00224             EXCEPTION("Either explicitly specify not to print output (call PrintOutput(false)) or specify the output directory and filename prefix");
00225         }
00226     }
00227 
00228     double end_time = HeartConfig::Instance()->GetSimulationDuration();
00229     double pde_time = HeartConfig::Instance()->GetPdeTimeStep();
00230 
00231     // MatrixIsConstant stuff requires CONSTANT dt - do some checks to make sure the TimeStepper won't find
00232     // non-constant dt.
00233     // Note: printing_time does not have to divide end_time, but dt must divide printing_time and end_time.
00234     // HeartConfig checks pde_dt divides printing dt
00235     if( fabs( end_time - pde_time*round(end_time/pde_time)) > 1e-10 )
00236     {
00237         EXCEPTION("Pde timestep does not seem to divide end time - check parameters");
00238     }
00239 }
00240 
00241 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00242 Vec AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::CreateInitialCondition()
00243 {
00244     DistributedVectorFactory* p_factory = mpMesh->GetDistributedVectorFactory();
00245     Vec initial_condition = p_factory->CreateVec(PROBLEM_DIM);
00246     DistributedVector ic = p_factory->CreateDistributedVector(initial_condition);
00247     std::vector<DistributedVector::Stripe> stripe;
00248     stripe.reserve(PROBLEM_DIM);
00249 
00250     for (unsigned i=0; i<PROBLEM_DIM; i++)
00251     {
00252         stripe.push_back(DistributedVector::Stripe(ic, i));
00253     }
00254 
00255     for (DistributedVector::Iterator index = ic.Begin();
00256          index != ic.End();
00257          ++index)
00258     {
00259         stripe[0][index] = mpCardiacPde->GetCardiacCell(index.Global)->GetVoltage();
00260         if (PROBLEM_DIM==2)
00261         {
00262             stripe[1][index] = 0;
00263         }
00264     }
00265 
00266     ic.Restore();
00267 
00268     return initial_condition;
00269 }
00270 
00271 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00272 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00273 {
00274     // If this fails the mesh has already been set. We assert rather throw an exception
00275     // to avoid a memory leak when checking it throws correctly
00276     assert(mpMesh==NULL);
00277     assert(pMesh!=NULL);
00278     mAllocatedMemoryForMesh = false;
00279     mpMesh = pMesh;
00280 }
00281 
00282 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00283 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::PrintOutput(bool printOutput)
00284 {
00285     mPrintOutput = printOutput;
00286 }
00287 
00288 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00289 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetWriteInfo(bool writeInfo)
00290 {
00291     mWriteInfo = writeInfo;
00292 }
00293 
00294 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00295 Vec AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetSolution()
00296 {
00297     return mSolution;
00298 }
00299 
00300 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00301 DistributedVector AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetSolutionDistributedVector()
00302 {
00303     return mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00304 }
00305 
00306 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00307 double AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetCurrentTime()
00308 {
00309     return mCurrentTime;
00310 }
00311 
00312 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00313 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::rGetMesh()
00314 {
00315     assert (mpMesh);
00316     return *mpMesh;
00317 }
00318 
00319 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00320 AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>* AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetPde()
00321 {
00322     return mpCardiacPde;
00323 }
00324 
00325 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00326 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::Solve()
00327 {
00328     PreSolveChecks();
00329 
00330     if (!mpBoundaryConditionsContainer) // the user didn't supply a bcc
00331     {
00332         // Set up the default bcc
00333         mpDefaultBoundaryConditionsContainer.reset(new BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>);
00334         for (unsigned problem_index=0; problem_index<PROBLEM_DIM; problem_index++)
00335         {
00336             mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00337         }
00338         mpBoundaryConditionsContainer = mpDefaultBoundaryConditionsContainer;
00339     }
00340 
00341     assert(mpAssembler==NULL);
00342     mpAssembler = CreateAssembler(); // passes mpBoundaryConditionsContainer to assember
00343 
00344     // If we have already run a simulation, use the old solution as initial condition
00345     Vec initial_condition;
00346     if (mSolution)
00347     {
00348         initial_condition = mSolution;
00349     }
00350     else
00351     {
00352         initial_condition = CreateInitialCondition();
00353     }
00354 
00355     std::vector<double> additional_stopping_times;
00356     SetUpAdditionalStoppingTimes(additional_stopping_times);
00357 
00358     TimeStepper stepper(mCurrentTime,
00359                         HeartConfig::Instance()->GetSimulationDuration(),
00360                         HeartConfig::Instance()->GetPrintingTimeStep(),
00361                         false,
00362                         additional_stopping_times);
00363 
00364     std::string progress_reporter_dir;
00365 
00366     if (mPrintOutput)
00367     {
00368         HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00369         try
00370         {
00371             InitialiseWriter();
00372         }
00373         catch (Exception& e)
00374         {
00375             delete mpWriter;
00376             mpWriter = NULL;
00377             delete mpAssembler;
00378             if (mSolution != initial_condition)
00379             {
00380                 VecDestroy(initial_condition);
00381             }
00382             throw e;
00383         }
00384 
00385         // If we are resuming a simulation (i.e. mSolution already exists) there's no need
00386         // of writing the initial timestep,
00387         // since it was already written as the last timestep of the previous run
00388         if (!mSolution)
00389         {
00390             WriteOneStep(stepper.GetTime(), initial_condition);
00391             mpWriter->AdvanceAlongUnlimitedDimension();
00392         }
00393         HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00394 
00395         progress_reporter_dir = HeartConfig::Instance()->GetOutputDirectory();
00396     }
00397     else
00398     {
00399         progress_reporter_dir = ""; // progress printed to CHASTE_TEST_OUTPUT
00400     }
00401 
00402     // create a progress reporter so users can track how much has gone and
00403     // estimate how much time is left. (Note this has to be done after the
00404     // InitialiseWriter above (if mPrintOutput==true)
00405     ProgressReporter progress_reporter(progress_reporter_dir, mCurrentTime,
00406                                        HeartConfig::Instance()->GetSimulationDuration());
00407     progress_reporter.Update(mCurrentTime);
00408 
00409 
00410     while ( !stepper.IsTimeAtEnd() )
00411     {
00412         // solve from now up to the next printing time
00413         mpAssembler->SetTimes(stepper.GetTime(), stepper.GetNextTime(), HeartConfig::Instance()->GetPdeTimeStep());
00414         mpAssembler->SetInitialCondition( initial_condition );
00415 
00416         AtBeginningOfTimestep(stepper.GetTime());
00417 
00418         try
00419         {
00420             mSolution = mpAssembler->Solve();
00421         }
00422         catch (Exception &e)
00423         {
00424             // Free memory.
00425             delete mpAssembler;
00426             mpAssembler=NULL;
00427             //VecDestroy(initial_condition);
00428 #ifndef NDEBUG
00429             PetscTools::ReplicateException(true);
00430 #endif
00431             // Re-throw
00432             HeartEventHandler::Reset();//EndEvent(HeartEventHandler::EVERYTHING);
00434             CloseFilesAndPostProcess();
00435             throw e;
00436         }
00437 #ifndef NDEBUG
00438         PetscTools::ReplicateException(false);
00439 #endif
00440 
00441         // Free old initial condition
00442         HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00443         VecDestroy(initial_condition);
00444         HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00445 
00446         // Initial condition for next loop is current solution
00447         initial_condition = mSolution;
00448 
00449         // update the current time
00450         stepper.AdvanceOneTimeStep();
00451         mCurrentTime = stepper.GetTime();
00452 
00453         if (mPrintOutput)
00454         {
00455             // print out details at current time if asked for
00456             if (mWriteInfo)
00457             {
00458                 HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00459                 WriteInfo(stepper.GetTime());
00460                 HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00461             }
00462 
00463             // Writing data out to the file <FilenamePrefix>.dat
00464             HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00465             WriteOneStep(stepper.GetTime(), mSolution);
00466             // Just flags that we've finished a time-step; won't actually 'extend' unless new data is written.
00467             mpWriter->AdvanceAlongUnlimitedDimension();
00468 
00469             HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00470         }
00471 
00472         progress_reporter.Update(stepper.GetTime());
00473 
00474         OnEndOfTimestep(stepper.GetTime());
00475     }
00476 
00477     // Free assembler
00478     delete mpAssembler;
00479     mpAssembler=NULL;
00480 
00481     // close the file that stores voltage values
00482     progress_reporter.PrintFinalising();
00483     CloseFilesAndPostProcess();
00484     HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING);
00485 }
00486 
00487 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00488 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::CloseFilesAndPostProcess()
00489 {
00490     // Close files
00491     if (!mPrintOutput)
00492     {
00493         //Nothing to do
00494         return;
00495     }
00496     delete mpWriter;
00497     mpWriter = NULL;
00498 
00499     HeartEventHandler::BeginEvent(HeartEventHandler::POST_PROC);
00500     // Only if results files were written and we are outputting all nodes
00501     if (mNodesToOutput.empty())
00502     {
00503         if (HeartConfig::Instance()->GetVisualizeWithMeshalyzer())
00504         {
00505             //Convert simulation data to Meshalyzer format
00506             Hdf5ToMeshalyzerConverter<ELEMENT_DIM,SPACE_DIM> converter(HeartConfig::Instance()->GetOutputDirectory(), HeartConfig::Instance()->GetOutputFilenamePrefix(), mpMesh);
00507         }
00508 
00509         if (HeartConfig::Instance()->GetVisualizeWithCmgui())
00510         {
00511             //Convert simulation data to Cmgui format
00512             Hdf5ToCmguiConverter<ELEMENT_DIM,SPACE_DIM> converter(HeartConfig::Instance()->GetOutputDirectory(), HeartConfig::Instance()->GetOutputFilenamePrefix(), mpMesh);
00513         }
00514 
00515         if (HeartConfig::Instance()->GetVisualizeWithVtk())
00516         {
00517             //Convert simulation data to VTK format
00518             Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(HeartConfig::Instance()->GetOutputDirectory(), HeartConfig::Instance()->GetOutputFilenamePrefix(), mpMesh);
00519         }
00520     }
00521 
00522     if(HeartConfig::Instance()->IsPostProcessingRequested())
00523     {
00524         PostProcessingWriter<ELEMENT_DIM, SPACE_DIM> post_writer(*mpMesh, HeartConfig::Instance()->GetOutputDirectory(),
00525                         HeartConfig::Instance()->GetOutputFilenamePrefix(), true);
00526         post_writer.WritePostProcessingFiles();
00527     }
00528 
00529     HeartEventHandler::EndEvent(HeartEventHandler::POST_PROC);
00530 }
00531 
00532 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00533 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::DefineWriterColumns(bool extending)
00534 {
00535     if (!extending)
00536     {
00537         if ( mNodesToOutput.empty() )
00538         {
00539             //Set writer to output all nodes
00540             mpWriter->DefineFixedDimension( mpMesh->GetNumNodes() );
00541         }
00542         else
00543         {
00544             //Output only the nodes indicted
00545             mpWriter->DefineFixedDimension( mNodesToOutput, mpMesh->GetNumNodes() );
00546         }
00547         //mNodeColumnId = mpWriter->DefineVariable("Node", "dimensionless");
00548         mVoltageColumnId = mpWriter->DefineVariable("V","mV");
00549 
00550         mpWriter->DefineUnlimitedDimension("Time","msecs");
00551     }
00552     else
00553     {
00554         mVoltageColumnId = mpWriter->GetVariableByName("V");
00555     }
00556 }
00557 
00558 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00559 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::DefineExtraVariablesWriterColumns(bool extending)
00560 {
00561     // Check if any extra output variables have been requested
00562     if (HeartConfig::Instance()->GetOutputVariablesProvided())
00563     {
00564         // Get their names in a vector
00565         std::vector<std::string> output_variables;
00566         HeartConfig::Instance()->GetOutputVariables(output_variables);
00567 
00568         // Loop over them
00569         for (unsigned var_index=0; var_index<output_variables.size(); var_index++)
00570         {
00571             // Get variable name
00572             std::string var_name = output_variables[var_index];
00573 
00574             // Register it (or look it up) in the data writer
00575             unsigned column_id;
00576             if (extending)
00577             {
00578                 column_id = this->mpWriter->GetVariableByName(var_name);
00579             }
00580             else
00581             {
00582                 column_id = this->mpWriter->DefineVariable(var_name, "");
00583             }
00584 
00585             // Store column id
00586             mExtraVariablesId.push_back(column_id);
00587         }
00588     }
00589 }
00590 
00591 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00592 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::WriteExtraVariablesOneStep()
00593 {
00594     // Loop over the requested state variables
00595     for (unsigned var_index=0; var_index<mExtraVariablesId.size(); var_index++)
00596     {
00597         // Create vector for storing values over the local nodes
00598         Vec variable_data =  this->mpMesh->GetDistributedVectorFactory()->CreateVec();
00599         DistributedVector distributed_var_data = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(variable_data);
00600 
00601         // Loop over the local nodes and gather the data
00602         for (DistributedVector::Iterator index = distributed_var_data.Begin();
00603              index!= distributed_var_data.End();
00604              ++index)
00605         {
00606             // Store value for node "index"
00607             distributed_var_data[index] = this->mpCardiacPde->GetCardiacCell(index.Global)->GetStateVariableValueByNumber(mExtraVariablesId[var_index]);
00608         }
00609         distributed_var_data.Restore();
00610 
00611         // Write it to disc
00612         this->mpWriter->PutVector(mExtraVariablesId[var_index], variable_data);
00613 
00614         VecDestroy(variable_data);
00615     }
00616 }
00617 
00618 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00619 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::InitialiseWriter()
00620 {
00621     bool extend_file = (mSolution != NULL);
00622     
00623     // I think this is impossible to trip; certainly it's very difficult!
00624     assert(!mpWriter);
00625 
00626     try
00627     {
00628         mpWriter = new Hdf5DataWriter(*mpMesh->GetDistributedVectorFactory(),
00629                                       HeartConfig::Instance()->GetOutputDirectory(),
00630                                       HeartConfig::Instance()->GetOutputFilenamePrefix(),
00631                                       !extend_file, // don't clear directory if extension requested
00632                                       extend_file);
00633     }
00634     catch (Exception& e)
00635     {
00636         // The constructor only throws an Exception if we're extending
00637         assert(extend_file);
00638         // Tried to extend and failed, so just create from scratch
00639         extend_file = false;
00640         mpWriter = new Hdf5DataWriter(*mpMesh->GetDistributedVectorFactory(),
00641                                       HeartConfig::Instance()->GetOutputDirectory(),
00642                                       HeartConfig::Instance()->GetOutputFilenamePrefix(),
00643                                       !extend_file,
00644                                       extend_file);
00645     }
00646 
00647     // Define columns, or get the variable IDs from the writer
00648     DefineWriterColumns(extend_file);
00649     if (!extend_file)
00650     {
00651         mpWriter->EndDefineMode();
00652     }
00653 }
00654 
00655 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00656 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::SetOutputNodes(std::vector<unsigned> &nodesToOutput)
00657 {
00658     mNodesToOutput = nodesToOutput;
00659 }
00660 
00661 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00662 Hdf5DataReader AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::GetDataReader()
00663 {
00664     if( (HeartConfig::Instance()->GetOutputDirectory()=="") || (HeartConfig::Instance()->GetOutputFilenamePrefix()==""))
00665     {
00666         EXCEPTION("Data reader invalid as data writer cannot be initialised");
00667     }
00668     return Hdf5DataReader(HeartConfig::Instance()->GetOutputDirectory(), HeartConfig::Instance()->GetOutputFilenamePrefix());
00669 }
00670 
00671 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00672 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::UseMatrixBasedRhsAssembly(bool usematrix)
00673 {
00674     mUseMatrixBasedRhsAssembly = usematrix;
00675 }
00676 
00678 // Explicit instantiation
00680 
00681 // Monodomain
00682 template class AbstractCardiacProblem<1,1,1>;
00683 template class AbstractCardiacProblem<1,2,1>;
00684 template class AbstractCardiacProblem<1,3,1>;
00685 template class AbstractCardiacProblem<2,2,1>;
00686 template class AbstractCardiacProblem<3,3,1>;
00687 
00688 // Bidomain
00689 template class AbstractCardiacProblem<1,1,2>;
00690 template class AbstractCardiacProblem<2,2,2>;
00691 template class AbstractCardiacProblem<3,3,2>;

Generated by  doxygen 1.6.2