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

Generated on Mon Nov 1 12:35:16 2010 for Chaste by  doxygen 1.5.5