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

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5