AbstractCardiacProblem.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
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 "TetrahedralMesh.hpp"
00033 #include "ParallelTetrahedralMesh.hpp"
00034 #include "MeshalyzerMeshWriter.hpp"
00035 #include "Hdf5ToMeshalyzerConverter.hpp"
00036 #include "Exception.hpp"
00037 #include "HeartConfig.hpp"
00038 #include "HeartEventHandler.hpp"
00039 #include "TimeStepper.hpp"
00040 #include "PetscTools.hpp"
00041 #include "DistributedVector.hpp"
00042 #include "ProgressReporter.hpp"
00043 
00044 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00045 AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::AbstractCardiacProblem(
00046             AbstractCardiacCellFactory<SPACE_DIM>* pCellFactory)
00047     : mMeshFilename(""),               // i.e. undefined
00048       mNodesPerProcessorFilename(""),  // i.e. undefined
00049       mOutputDirectory(""),            // i.e. undefined
00050       mOutputFilenamePrefix(""),       // i.e. undefined
00051       mUseMatrixBasedRhsAssembly(true),
00052       mpBoundaryConditionsContainer(NULL),
00053       mpDefaultBoundaryConditionsContainer(NULL),
00054       mpCellFactory(pCellFactory),
00055       mpMesh(NULL),
00056       mpWriter(NULL)
00057 {
00058     mWriteInfo = false;
00059     mPrintOutput = true;
00060     mCallChaste2Meshalyzer = false;
00061     mpCardiacPde = NULL;
00062     mpAssembler = NULL;
00063     mSolution = NULL;
00064     mAllocatedMemoryForMesh = false;
00065     assert(mNodesToOutput.empty());
00066 
00067     HeartEventHandler::BeginEvent(HeartEventHandler::EVERYTHING);
00068 }
00069 
00070 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00071 AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::~AbstractCardiacProblem()
00072 {
00073     if(mpDefaultBoundaryConditionsContainer!=NULL)
00074     {
00075         delete mpDefaultBoundaryConditionsContainer;
00076     }
00077     
00078     delete mpCardiacPde;
00079     if (mSolution)
00080     {
00081         VecDestroy(mSolution);
00082     }
00083 
00084     if (mAllocatedMemoryForMesh)
00085     {
00086         delete mpMesh;
00087     }
00088 };
00089 
00090 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00091 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::Initialise()
00092 {
00093     mOutputDirectory = HeartConfig::Instance()->GetOutputDirectory();
00094     mOutputFilenamePrefix = HeartConfig::Instance()->GetOutputFilenamePrefix();
00095     
00096     if (mpMesh==NULL)
00097     {
00098         // If no mesh has been passed, we get it from the configuration file
00099         try
00100         {
00102             if(HeartConfig::Instance()->GetLoadMesh())
00103             {
00104                 TrianglesMeshReader<SPACE_DIM, SPACE_DIM> mesh_reader(HeartConfig::Instance()->GetMeshName());
00105                 if (SPACE_DIM == 1)
00106                 {
00108                     mpMesh = new TetrahedralMesh<SPACE_DIM, SPACE_DIM>();
00109                 }
00110                 else
00111                 {
00112                     mpMesh = new ParallelTetrahedralMesh<SPACE_DIM, SPACE_DIM>();
00113                 }
00114         
00115                 HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00116                 mpMesh->ConstructFromMeshReader(mesh_reader);
00117                 HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00118             }
00119             else
00120             {
00121                 if(HeartConfig::Instance()->GetCreateMesh())
00122                 {
00123                     switch(HeartConfig::Instance()->GetSpaceDimension())
00124                     {
00125                         case 1:
00126                         {
00127                             c_vector<double, 1> fibre_length;
00128                             HeartConfig::Instance()->GetFibreLength(fibre_length);
00129                             double inter_node_space = HeartConfig::Instance()->GetInterNodeSpace();
00130 
00131                             mpMesh = new TetrahedralMesh<SPACE_DIM, SPACE_DIM>();
00132                             
00133                             unsigned slab_nodes_x = (unsigned)round(fibre_length[0]/inter_node_space);
00134                         
00135                             static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->ConstructLinearMesh(slab_nodes_x);
00136                             // place at origin
00137 //                            static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->Translate(-(double)slab_nodes_x/2.0,
00138 //                                             -(double)slab_nodes_y/2.0,
00139 //                                             -(double)slab_nodes_z/2.0);
00140                                              
00141                             // scale
00142                             double mesh_scale_factor = inter_node_space;
00143                             static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->Scale(mesh_scale_factor, 1, 1);
00144                             break;
00145                         }
00146                         case 2:
00147                         {
00148                             c_vector<double, 2> sheet_dimensions; //cm                    
00149                             HeartConfig::Instance()->GetSheetDimensions(sheet_dimensions);
00150                             double inter_node_space = HeartConfig::Instance()->GetInterNodeSpace();
00151                             
00152                             mpMesh = new TetrahedralMesh<SPACE_DIM, SPACE_DIM>();
00153                             
00154                             unsigned slab_nodes_x = (unsigned)round(sheet_dimensions[0]/inter_node_space);
00155                             unsigned slab_nodes_y = (unsigned)round(sheet_dimensions[1]/inter_node_space);
00156                         
00157                             static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->ConstructRectangularMesh(slab_nodes_x, slab_nodes_y);
00158                             
00159                             // place at origin
00160 //                            static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->Translate(-(double)slab_nodes_x/2.0,
00161 //                                             -(double)slab_nodes_y/2.0,
00162 //                                             -(double)slab_nodes_z/2.0);
00163                                              
00164                             // scale
00165                             double mesh_scale_factor = inter_node_space;
00166                             static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->Scale(mesh_scale_factor, mesh_scale_factor, mesh_scale_factor);
00167                             break;
00168                         }
00169                         case 3:
00170                         {
00171                             c_vector<double, 3> slab_dimensions; //cm                    
00172                             HeartConfig::Instance()->GetSlabDimensions(slab_dimensions);
00173                             double inter_node_space = HeartConfig::Instance()->GetInterNodeSpace();
00174                             
00175                             mpMesh = new TetrahedralMesh<SPACE_DIM, SPACE_DIM>();
00176                             
00177                             unsigned slab_nodes_x = (unsigned)round(slab_dimensions[0]/inter_node_space);
00178                             unsigned slab_nodes_y = (unsigned)round(slab_dimensions[1]/inter_node_space);
00179                             unsigned slab_nodes_z = (unsigned)round(slab_dimensions[2]/inter_node_space);
00180                         
00181                             static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->ConstructCuboid(slab_nodes_x,
00182                                                    slab_nodes_y,
00183                                                    slab_nodes_z,
00184                                                    true);
00185                             // place at origin
00186 //                            static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->Translate(-(double)slab_nodes_x/2.0,
00187 //                                             -(double)slab_nodes_y/2.0,
00188 //                                             -(double)slab_nodes_z/2.0);
00189                                              
00190                             // scale
00191                             double mesh_scale_factor = inter_node_space;
00192                             static_cast<TetrahedralMesh<SPACE_DIM, SPACE_DIM>*>(mpMesh)->Scale(mesh_scale_factor, mesh_scale_factor, mesh_scale_factor);
00193                             break;
00194                         }
00195                         default:
00196                             NEVER_REACHED;
00197                     }
00198                 }
00199                 else
00200                 {
00201                     NEVER_REACHED;
00202                 }   
00203             } 
00204             
00205             mAllocatedMemoryForMesh = true;                      
00206         }
00207         catch (Exception& e)
00208         {               
00209             EXCEPTION(std::string("No mesh given: define it in XML parameters file or call SetMesh()\n") + e.GetMessage());
00210         }
00211     }
00212     mpCellFactory->SetMesh( mpMesh );
00213 
00214     if (mNodesPerProcessorFilename != "")
00215     {
00216         mpMesh->ReadNodesPerProcessorFile(mNodesPerProcessorFilename);
00217     }
00219     delete mpCardiacPde; // In case we're called twice
00220     mpCardiacPde = CreateCardiacPde();
00221 }
00222 
00223 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00224 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::SetNodesPerProcessorFilename(const std::string& filename)
00225 {
00226     mNodesPerProcessorFilename = filename;
00227 }
00228 
00229 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00230 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::SetBoundaryConditionsContainer(BoundaryConditionsContainer<SPACE_DIM, SPACE_DIM, PROBLEM_DIM> *bcc)
00231 {
00232     this->mpBoundaryConditionsContainer = bcc;
00233 }
00234 
00235 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00236 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::PreSolveChecks()
00237 {
00238     if ( mpCardiacPde == NULL ) // if pde is NULL, Initialise() probably hasn't been called
00239     {
00240         EXCEPTION("Pde is null, Initialise() probably hasn't been called");
00241     }
00242     if ( HeartConfig::Instance()->GetSimulationDuration() <= 0.0)
00243     {
00244         EXCEPTION("End time should be greater than 0");
00245     }
00246     if (mPrintOutput==true)
00247     {
00248         if( (mOutputDirectory=="") || (mOutputFilenamePrefix==""))
00249         {
00250             EXCEPTION("Either explicitly specify not to print output (call PrintOutput(false)) or specify the output directory and filename prefix");
00251         }
00252     }
00253 }
00254 
00255 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00256 Vec AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::CreateInitialCondition()
00257 {
00258     //if (DistributedVector::GetProblemSize()==0)
00259     //{
00260     //    DistributedVector::SetProblemSize(mpMesh->GetNumNodes());
00261     //}
00262     Vec initial_condition = DistributedVector::CreateVec(PROBLEM_DIM);
00263     DistributedVector ic(initial_condition);
00264     std::vector<DistributedVector::Stripe> stripe;
00265     stripe.reserve(PROBLEM_DIM);
00266 
00267     for (unsigned i=0; i<PROBLEM_DIM; i++)
00268     {
00269         stripe.push_back(DistributedVector::Stripe(ic, i));
00270     }
00271 
00272     for (DistributedVector::Iterator index = DistributedVector::Begin();
00273          index != DistributedVector::End();
00274          ++index)
00275     {
00276         stripe[0][index] = mpCardiacPde->GetCardiacCell(index.Global)->GetVoltage();
00277         if (PROBLEM_DIM==2)
00278         {
00279             stripe[1][index] = 0;
00280         }
00281     }
00282 
00283     ic.Restore();
00284 
00285     return initial_condition;
00286 }
00287 
00288 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00289 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::ConvertOutputToMeshalyzerFormat(bool call)
00290 {
00291     mCallChaste2Meshalyzer=call;
00292 }
00293 
00294 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00295 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::SetMesh(AbstractMesh<SPACE_DIM,SPACE_DIM>* pMesh)
00296 {
00297     // If this fails the mesh has already been set. We assert rather throw an exception
00298     // to avoid a memory leak when checking it throws correctly
00299     assert(mpMesh==NULL);
00300     assert(pMesh!=NULL);
00301     mAllocatedMemoryForMesh = false;
00302     mpMesh = pMesh;
00303 }
00304 
00305 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00306 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::PrintOutput(bool printOutput)
00307 {
00308     mPrintOutput = printOutput;
00309 }
00310 
00311 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00312 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::SetWriteInfo(bool writeInfo)
00313 {
00314     mWriteInfo = writeInfo;
00315 }
00316 
00317 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00318 Vec AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::GetSolution()
00319 {
00320     return mSolution;
00321 }
00322 
00323 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00324 AbstractMesh<SPACE_DIM,SPACE_DIM> & AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::rGetMesh()
00325 {
00326     assert (mpMesh);        
00327     return *mpMesh;
00328 }
00329 
00330 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00331 AbstractCardiacPde<SPACE_DIM>* AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::GetPde()
00332 {
00333     return mpCardiacPde;
00334 }
00335 
00336 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00337 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::Solve()
00338 {
00339     PreSolveChecks();
00340 
00341     if(mpBoundaryConditionsContainer == NULL) // the user didnt supply a bcc
00342     {
00343         // set up the default bcc
00344         mpDefaultBoundaryConditionsContainer = new BoundaryConditionsContainer<SPACE_DIM, SPACE_DIM, PROBLEM_DIM>;
00345         for (unsigned problem_index=0; problem_index<PROBLEM_DIM; problem_index++)
00346         {
00347             mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(mpMesh, problem_index);
00348         }
00349         mpBoundaryConditionsContainer = mpDefaultBoundaryConditionsContainer;
00350     }
00351 
00352     mpAssembler = CreateAssembler(); // passes mpBoundaryConditionsContainer to assember
00353     Vec initial_condition = CreateInitialCondition();
00354 
00355     TimeStepper stepper(0.0, HeartConfig::Instance()->GetSimulationDuration(), 
00356                         HeartConfig::Instance()->GetPrintingTimeStep());
00357 
00358     std::string progress_reporter_dir;
00359 
00360     if (mPrintOutput)
00361     {
00362         HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00363         InitialiseWriter();
00364         WriteOneStep(stepper.GetTime(), initial_condition);
00365         HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00366         
00367         progress_reporter_dir = mOutputDirectory;
00368     }
00369     else
00370     {
00371         progress_reporter_dir = ""; // progress printed to CHASTE_TEST_OUTPUT
00372     }
00373 
00374     // create a progress reporter so users can track how much has gone and 
00375     // estimate how much time is left. (Note this has to be done after the
00376     // InitialiseWriter above (if mPrintOutput==true)
00377     ProgressReporter progress_reporter(progress_reporter_dir, 0.0, HeartConfig::Instance()->GetSimulationDuration());
00378     progress_reporter.Update(0);
00379 
00380     // If we have already run a simulation, free the old solution vec
00381     if (mSolution)
00382     {
00383         VecDestroy(mSolution);
00384     }
00385 
00386     while ( !stepper.IsTimeAtEnd() )
00387     {
00388         // solve from now up to the next printing time
00389         mpAssembler->SetTimes(stepper.GetTime(), stepper.GetNextTime(), HeartConfig::Instance()->GetPdeTimeStep());
00390         mpAssembler->SetInitialCondition( initial_condition );
00391 
00392         try
00393         {
00394             mSolution = mpAssembler->Solve();
00395         }
00396         catch (Exception &e)
00397         {
00398             // Free memory.
00399             delete mpAssembler;
00400             //VecDestroy(initial_condition);
00401             
00402             PetscTools::ReplicateException(true);
00403             // Re-throw
00404             HeartEventHandler::Reset();//EndEvent(HeartEventHandler::EVERYTHING);
00405             
00406             CloseFilesAndPostProcess();
00407             throw e;
00408         }
00409         PetscTools::ReplicateException(false);
00410 
00411         // Free old initial condition
00412         VecDestroy(initial_condition);
00413 
00414         // Initial condition for next loop is current solution
00415         initial_condition = mSolution;
00416 
00417         // update the current time
00418         stepper.AdvanceOneTimeStep();
00419 
00420         if (mPrintOutput)
00421         {
00422             // print out details at current time if asked for
00423             if (mWriteInfo)
00424             {
00425                 WriteInfo(stepper.GetTime());
00426             }
00427 
00428             // Writing data out to the file <mOutputFilenamePrefix>.dat
00429             HeartEventHandler::BeginEvent(HeartEventHandler::WRITE_OUTPUT);
00430             mpWriter->AdvanceAlongUnlimitedDimension(); //creates a new file
00431             WriteOneStep(stepper.GetTime(), mSolution);
00432             HeartEventHandler::EndEvent(HeartEventHandler::WRITE_OUTPUT);
00433         }
00434         
00435         progress_reporter.Update(stepper.GetTime());
00436         
00437         OnEndOfTimestep(stepper.GetTime());
00438     }
00439 
00440     // Free assembler
00441     delete mpAssembler;
00442 
00443     // close the file that stores voltage values
00444     progress_reporter.PrintFinalising();
00445     CloseFilesAndPostProcess();
00446     HeartEventHandler::EndEvent(HeartEventHandler::EVERYTHING);
00447 }
00448 
00449 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00450 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::CloseFilesAndPostProcess()
00451 {
00452     // Close files
00453     if (!mPrintOutput)
00454     { 
00455         //Nothing to do
00456         return;
00457     }
00458     mpWriter->Close();
00459     delete mpWriter;
00460 
00461     HeartEventHandler::BeginEvent(HeartEventHandler::USER2); //Temporarily using USER2 to instrument post-processing
00462     // Only if results files were written and we are outputting all nodes
00463     if (mCallChaste2Meshalyzer && mNodesToOutput.empty()) 
00464     {
00465         //Convert simulation data to Meshalyzer format
00466         std::string output_directory =  mOutputDirectory + "/output";
00467         Hdf5ToMeshalyzerConverter converter(mOutputDirectory, output_directory, mOutputFilenamePrefix);
00468         
00469         //Write mesh in a suitable form for meshalyzer
00470         if (PetscTools::AmMaster())
00471         {
00472             //Write the mesh
00473             MeshalyzerMeshWriter<SPACE_DIM,SPACE_DIM> mesh_writer(output_directory, mOutputFilenamePrefix+"_mesh", false);
00474 
00475             try
00476             {
00477                 // If this mesh object has been constructed from a mesh reader we can get reference to it            
00478                 TrianglesMeshReader<SPACE_DIM,SPACE_DIM> mesh_reader(mpMesh->GetMeshFileBaseName());
00479                 mesh_writer.WriteFilesUsingMeshReader(mesh_reader, mpMesh->rGetNodePermutation());
00480             }
00481             catch(Exception& e)
00482             {
00483                 //If there isn't a MeshReader available we will use the data contained in the actual mesh object.                
00485                 mesh_writer.WriteFilesUsingMesh(*mpMesh);
00486             }
00487             
00488             //Write the parameters out
00489             HeartConfig::Instance()->Write(output_directory, mOutputFilenamePrefix+"_parameters.xml");
00490         }
00491     }
00492     HeartEventHandler::EndEvent(HeartEventHandler::USER2); //Temporarily using USER2 to instrument post-processing
00493 }
00494 
00495 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00496 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::DefineWriterColumns()
00497 {
00498     if ( mNodesToOutput.empty() )
00499     {
00500         //Set writer to output all nodes
00501         mpWriter->DefineFixedDimension( mpMesh->GetNumNodes() );
00502     }
00503     else
00504     {
00505         //Output only the nodes indicted
00506         mpWriter->DefineFixedDimension( mNodesToOutput, mpMesh->GetNumNodes() );
00507     }
00508     //mNodeColumnId = mpWriter->DefineVariable("Node", "dimensionless");
00509     mVoltageColumnId = mpWriter->DefineVariable("V","mV");
00510 
00511     mpWriter->DefineUnlimitedDimension("Time","msecs");
00512 
00513 }
00514 
00515 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00516 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::WriteOneStep(double time, Vec voltageVec)
00517 {
00518     mpWriter->PutUnlimitedVariable(time);
00519 
00520     //DistributedVector::Stripe transmembrane(voltageVec, 0);
00521     mpWriter->PutVector(mVoltageColumnId, voltageVec);
00522 }
00523 
00524 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00525 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::InitialiseWriter()
00526 {
00527     mpWriter = new Hdf5DataWriter(mOutputDirectory,mOutputFilenamePrefix);
00528     DefineWriterColumns();
00529     mpWriter->EndDefineMode();
00530 }
00531 
00532 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00533 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::SetOutputNodes(std::vector<unsigned> &nodesToOutput)
00534 {
00535     mNodesToOutput = nodesToOutput;
00536 }
00537 
00538 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00539 Hdf5DataReader AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::GetDataReader()
00540 {
00541     if( (mOutputDirectory=="") || (mOutputFilenamePrefix==""))
00542     {
00543         EXCEPTION("Data reader invalid as data writer cannot be initialised");
00544     }
00545     return Hdf5DataReader(mOutputDirectory, mOutputFilenamePrefix);
00546 }
00547 
00548 template<unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00549 void AbstractCardiacProblem<SPACE_DIM,PROBLEM_DIM>::UseMatrixBasedRhsAssembly(bool usematrix)
00550 {
00551     mUseMatrixBasedRhsAssembly = usematrix;
00552 }
00553 
00554 
00556 // Explicit instantiation
00558 
00559 // Monodomain
00560 template class AbstractCardiacProblem<1,1>;
00561 template class AbstractCardiacProblem<2,1>;
00562 template class AbstractCardiacProblem<3,1>;
00563 
00564 // Bidomain
00565 template class AbstractCardiacProblem<1,2>;
00566 template class AbstractCardiacProblem<2,2>;
00567 template class AbstractCardiacProblem<3,2>;

Generated on Wed Mar 18 12:51:51 2009 for Chaste by  doxygen 1.5.5