TissueSimulation.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 #include <cmath>
00029 #include <ctime>
00030 #include <iostream>
00031 #include <fstream>
00032 #include <set>
00033 
00034 #include "TissueSimulation.hpp"
00035 #include "AbstractCellCentreBasedTissue.hpp"
00036 #include "CancerEventHandler.hpp"
00037 #include "LogFile.hpp"
00038 
00039 
00040 template<unsigned DIM>
00041 TissueSimulation<DIM>::TissueSimulation(AbstractTissue<DIM>& rTissue,
00042                                         std::vector<AbstractForce<DIM>*> forceCollection,
00043                                         bool deleteTissueAndForceCollection,
00044                                         bool initialiseCells)
00045   :  mrTissue(rTissue)
00046 {
00047     #define COVERAGE_IGNORE
00048     assert(DIM==2 || DIM==3); // there are no instances of TissueSimulation<1>
00049     #undef COVERAGE_IGNORE
00050 
00051     mDeleteTissue = deleteTissueAndForceCollection;
00052 
00053     mInitialiseCells = initialiseCells;
00054 
00055     mpParams = CancerParameters::Instance();
00056 
00057     // This line sets a random seed of 0 if it wasn't specified earlier.
00058     mpRandomGenerator = RandomNumberGenerator::Instance();
00059 
00060     mDt = 1.0/120.0; // Timestep of 30 seconds (as per Meineke)
00061     mEndTime = 0.0; // hours - this is set later on.
00062 
00063     // Defaults
00064     mOutputDirectory = "";
00065     mSimulationOutputDirectory = mOutputDirectory;
00066 
00067     if (mrTissue.HasMesh())
00068     {
00069         mUpdateTissue = true;
00070     }
00071     else
00072     {
00073         mUpdateTissue = false;
00074     }
00075 
00076     mOutputCellMutationStates = false;
00077     mOutputCellAncestors = false;
00078     mOutputCellTypes = false;
00079     mOutputCellVariables = false;
00080     mOutputCellCyclePhases = false;
00081     mNoBirth = false;
00082     mNumBirths = 0;
00083     mNumDeaths = 0;
00084     mSamplingTimestepMultiple = 1;
00085 
00086     mAllocatedMemoryForForceCollection = deleteTissueAndForceCollection;
00087 
00088     mForceCollection = forceCollection;
00089     if (mInitialiseCells)
00090     {
00091         mrTissue.InitialiseCells();
00092     }
00093 }
00094 
00095 
00096 template<unsigned DIM>
00097 TissueSimulation<DIM>::~TissueSimulation()
00098 {
00099     if (mAllocatedMemoryForForceCollection)
00100     {
00101         for (typename std::vector<AbstractForce<DIM>*>::iterator force_iter = mForceCollection.begin();
00102              force_iter != mForceCollection.end();
00103              ++force_iter)
00104         {
00105             delete *force_iter;
00106         }
00107     }
00108 
00109     if (mDeleteTissue)
00110     {
00111         for (typename std::vector<AbstractCellKiller<DIM>*>::iterator it=mCellKillers.begin();
00112              it != mCellKillers.end();
00113              ++it)
00114         {
00115             delete *it;
00116         }
00117         delete &mrTissue;
00118     }
00119 }
00120 
00121 
00122 template<unsigned DIM>
00123 unsigned TissueSimulation<DIM>::DoCellBirth()
00124 {
00125     if (mNoBirth)
00126     {
00127         return 0;
00128     }
00129 
00130     unsigned num_births_this_step = 0;
00131 
00132     // Iterate over all cells, seeing if each one can be divided
00133     for (typename AbstractTissue<DIM>::Iterator cell_iter = mrTissue.Begin();
00134          cell_iter != mrTissue.End();
00135          ++cell_iter)
00136     {
00137         // Check if this cell is ready to divide - if so create a new cell etc.
00138         if (cell_iter->GetAge() > 0.0)
00139         {
00140             if (cell_iter->ReadyToDivide())
00141             {
00142                 // Create a new cell
00143                 TissueCell new_cell = cell_iter->Divide();
00144 
00145                 c_vector<double, DIM> new_location = zero_vector<double>(DIM);
00146                 if (dynamic_cast<AbstractCellCentreBasedTissue<DIM>*>(&mrTissue))
00147                 {
00148                     new_location = CalculateDividingCellCentreLocations(&(*cell_iter));
00149                 }
00150 
00151                 // Add new cell to the tissue
00152                 mrTissue.AddCell(new_cell, new_location, &(*cell_iter));
00153 
00154                 // Update counter
00155                 num_births_this_step++;
00156             }
00157         }
00158     }
00159     return num_births_this_step;
00160 }
00161 
00162 
00163 template<unsigned DIM>
00164 unsigned TissueSimulation<DIM>::DoCellRemoval()
00165 {
00166     unsigned num_deaths_this_step = 0;
00167 
00168     // This labels cells as dead or apoptosing. It does not actually remove the cells,
00169     // tissue.RemoveDeadCells() needs to be called for this.
00170     for (typename std::vector<AbstractCellKiller<DIM>*>::iterator killer_iter = mCellKillers.begin();
00171          killer_iter != mCellKillers.end();
00172          ++killer_iter)
00173     {
00174         (*killer_iter)->TestAndLabelCellsForApoptosisOrDeath();
00175     }
00176 
00177     num_deaths_this_step += mrTissue.RemoveDeadCells();
00178 
00179     return num_deaths_this_step;
00180 }
00181 
00182 
00183 template<unsigned DIM>
00184 const std::vector<AbstractForce<DIM>*> TissueSimulation<DIM>::rGetForceCollection() const
00185 {
00186     return mForceCollection;
00187 }
00188 
00189 
00190 template<unsigned DIM>
00191 c_vector<double, DIM> TissueSimulation<DIM>::CalculateDividingCellCentreLocations(TissueCell* pParentCell)
00192 {
00193     double separation = CancerParameters::Instance()->GetDivisionSeparation();
00194     c_vector<double, DIM> parent_coords = mrTissue.GetLocationOfCellCentre(pParentCell);
00195     c_vector<double, DIM> daughter_coords;
00196 
00197     // Pick a random direction and move the parent cell backwards by 0.5*sep in that
00198     // direction and return the position of the daughter cell (0.5*sep forwards in the
00199     // random vector direction
00200 
00201     // Make a random direction vector of the required length
00202     c_vector<double, DIM> random_vector;
00203 
00204     if (DIM==2)
00205     {
00206         double random_angle = RandomNumberGenerator::Instance()->ranf();
00207         random_angle *= 2.0*M_PI;
00208 
00209         random_vector(0) = 0.5*separation*cos(random_angle);
00210         random_vector(1) = 0.5*separation*sin(random_angle);
00211 
00212         parent_coords = parent_coords - random_vector;
00213         daughter_coords = parent_coords + random_vector;
00214     }
00215     else if (DIM==3)
00216     {
00217         double random_zenith_angle = RandomNumberGenerator::Instance()->ranf(); // phi
00218         random_zenith_angle *= M_PI;
00219         double random_azimuth_angle = RandomNumberGenerator::Instance()->ranf(); // theta
00220         random_azimuth_angle *= 2*M_PI;
00221 
00222         random_vector(0) = 0.5*separation*cos(random_azimuth_angle)*sin(random_zenith_angle);
00223         random_vector(1) = 0.5*separation*sin(random_azimuth_angle)*sin(random_zenith_angle);
00224         random_vector(2) = 0.5*separation*cos(random_zenith_angle);
00225 
00226         daughter_coords = parent_coords + random_vector;
00227         parent_coords = parent_coords - random_vector;
00228     }
00229 
00230     // Set the parent to use this location
00231     ChastePoint<DIM> parent_coords_point(parent_coords);
00232     unsigned node_index = mrTissue.GetLocationIndexUsingCell(pParentCell);
00233     mrTissue.SetNode(node_index, parent_coords_point);
00234 
00235     return daughter_coords;
00236 }
00237 
00238 
00239 template<unsigned DIM>
00240 void TissueSimulation<DIM>::UpdateNodePositions(const std::vector< c_vector<double, DIM> >& rNodeForces)
00241 {
00242     // Get the previous node positions (these may be needed
00243     // when applying boundary conditions, e.g. in the case
00244     // of immotile cells)
00245     std::vector<c_vector<double, DIM> > old_node_locations;
00246     old_node_locations.reserve(mrTissue.GetNumNodes());
00247     for (unsigned node_index=0; node_index<mrTissue.GetNumNodes(); node_index++)
00248     {
00249         old_node_locations[node_index] = mrTissue.GetNode(node_index)->rGetLocation();
00250     }
00251 
00252     // Update node locations
00253     mrTissue.UpdateNodeLocations(rNodeForces, mDt);
00254 
00255     // Apply any boundary conditions
00256     ApplyTissueBoundaryConditions(old_node_locations);
00257 }
00258 
00259 
00260 template<unsigned DIM>
00261 void TissueSimulation<DIM>::SetDt(double dt)
00262 {
00263     assert(dt > 0);
00264     mDt = dt;
00265 }
00266 
00267 
00268 template<unsigned DIM>
00269 double TissueSimulation<DIM>::GetDt()
00270 {
00271     return mDt;
00272 }
00273 
00274 
00275 template<unsigned DIM>
00276 unsigned TissueSimulation<DIM>::GetNumBirths()
00277 {
00278     return mNumBirths;
00279 }
00280 
00281 
00282 template<unsigned DIM>
00283 unsigned TissueSimulation<DIM>::GetNumDeaths()
00284 {
00285     return mNumDeaths;
00286 }
00287 
00288 
00289 template<unsigned DIM>
00290 void TissueSimulation<DIM>::SetEndTime(double endTime)
00291 {
00292     assert(endTime > 0);
00293     mEndTime = endTime;
00294 }
00295 
00296 
00297 template<unsigned DIM>
00298 void TissueSimulation<DIM>::SetOutputDirectory(std::string outputDirectory)
00299 {
00300     mOutputDirectory = outputDirectory;
00301     mSimulationOutputDirectory = mOutputDirectory;
00302 }
00303 
00304 
00305 template<unsigned DIM>
00306 std::string TissueSimulation<DIM>::GetOutputDirectory()
00307 {
00308     return mOutputDirectory;
00309 }
00310 
00311 
00312 template<unsigned DIM>
00313 void TissueSimulation<DIM>::SetSamplingTimestepMultiple(unsigned samplingTimestepMultiple)
00314 {
00315     assert(samplingTimestepMultiple > 0);
00316     mSamplingTimestepMultiple = samplingTimestepMultiple;
00317 }
00318 
00319 
00320 template<unsigned DIM>
00321 AbstractTissue<DIM>& TissueSimulation<DIM>::rGetTissue()
00322 {
00323     return mrTissue;
00324 }
00325 
00326 
00327 template<unsigned DIM>
00328 const AbstractTissue<DIM>& TissueSimulation<DIM>::rGetTissue() const
00329 {
00330     return mrTissue;
00331 }
00332 
00333 
00334 template<unsigned DIM>
00335 void TissueSimulation<DIM>::SetUpdateTissueRule(bool updateTissue)
00336 {
00337     mUpdateTissue = updateTissue;
00338 }
00339 
00340 
00341 template<unsigned DIM>
00342 void TissueSimulation<DIM>::SetNoBirth(bool noBirth)
00343 {
00344     mNoBirth = noBirth;
00345 }
00346 
00347 
00348 template<unsigned DIM>
00349 void TissueSimulation<DIM>::SetOutputCellMutationStates(bool outputCellMutationStates)
00350 {
00351     mOutputCellMutationStates = outputCellMutationStates;
00352 }
00353 
00354 
00355 template<unsigned DIM>
00356 void TissueSimulation<DIM>::SetOutputCellTypes(bool outputCellTypes)
00357 {
00358     mOutputCellTypes = outputCellTypes;
00359 }
00360 
00361 
00362 template<unsigned DIM>
00363 void TissueSimulation<DIM>::SetOutputCellAncestors(bool outputCellAncestors)
00364 {
00365     mOutputCellAncestors = outputCellAncestors;
00366 }
00367 
00368 
00369 template<unsigned DIM>
00370 void TissueSimulation<DIM>::SetOutputCellVariables(bool outputCellVariables)
00371 {
00372     mOutputCellVariables = outputCellVariables;
00373 }
00374 
00375 
00376 template<unsigned DIM>
00377 void TissueSimulation<DIM>::SetOutputCellCyclePhases(bool outputCellCyclePhases)
00378 {
00379     mOutputCellCyclePhases = outputCellCyclePhases;
00380 }
00381 
00382 
00383 template<unsigned DIM>
00384 void TissueSimulation<DIM>::AddCellKiller(AbstractCellKiller<DIM>* pCellKiller)
00385 {
00386     mCellKillers.push_back(pCellKiller);
00387 }
00388 
00389 
00390 template<unsigned DIM>
00391 std::vector<double> TissueSimulation<DIM>::GetNodeLocation(const unsigned& rNodeIndex)
00392 {
00393     std::vector<double> location;
00394     for (unsigned i=0; i<DIM; i++)
00395     {
00396         location.push_back( mrTissue.GetNode(rNodeIndex)->rGetLocation()[i] );
00397     }
00398     return location;
00399 }
00400 
00401 
00402 template<unsigned DIM>
00403 void TissueSimulation<DIM>::Solve()
00404 {
00405     CancerEventHandler::BeginEvent(CancerEventHandler::EVERYTHING);
00406     CancerEventHandler::BeginEvent(CancerEventHandler::SETUP);
00407 
00408     // Set up the simulation time
00409     SimulationTime* p_simulation_time = SimulationTime::Instance();
00410     double current_time = p_simulation_time->GetTime();
00411 
00412     unsigned num_time_steps = (unsigned) ((mEndTime-current_time)/mDt+0.5);
00413 
00414     if (current_time > 0) // use the reset function if necessary
00415     {
00416         p_simulation_time->ResetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00417     }
00418     else
00419     {
00420         p_simulation_time->SetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00421     }
00422 
00423     if (mOutputDirectory=="")
00424     {
00425         EXCEPTION("OutputDirectory not set");
00426     }
00427 
00428     double time_now = p_simulation_time->GetTime();
00429     std::ostringstream time_string;
00430     time_string << time_now;
00431 
00432     std::string results_directory = mOutputDirectory +"/results_from_time_" + time_string.str();
00433     mSimulationOutputDirectory = results_directory;
00434 
00436     // Set up Simulation
00438 
00439     // Create output files for the visualizer
00440     OutputFileHandler output_file_handler(results_directory+"/", true);
00441 
00442     mrTissue.CreateOutputFiles(results_directory+"/",
00443                                false,
00444                                mOutputCellMutationStates,
00445                                mOutputCellTypes,
00446                                mOutputCellVariables,
00447                                mOutputCellCyclePhases,
00448                                mOutputCellAncestors);
00449 
00450     mpSetupFile = output_file_handler.OpenOutputFile("results.vizsetup");
00451 
00452     SetupSolve();
00453 
00454     // Age the cells to the correct time. Note that cells are created with
00455     // negative birth times so that some are initially almost ready to divide.
00456     LOG(1, "Setting up cells...");
00457     for (typename AbstractTissue<DIM>::Iterator cell_iter = mrTissue.Begin();
00458          cell_iter != mrTissue.End();
00459          ++cell_iter)
00460     {
00461         // We don't use the result; this call is just to force the cells to age
00462         // to the current time running their cell cycle models to get there
00463         cell_iter->ReadyToDivide();
00464     }
00465     LOG(1, "\tdone\n");
00466 
00467     // Write initial conditions to file for the visualizer
00468     if (DIM==2)
00469     {
00470         WriteVisualizerSetupFile();
00471     }
00472     *mpSetupFile << std::flush;
00473 
00474     mrTissue.WriteResultsToFiles(mOutputCellMutationStates,
00475                                  mOutputCellTypes,
00476                                  mOutputCellVariables,
00477                                  mOutputCellCyclePhases,
00478                                  mOutputCellAncestors);
00479 
00480     CancerEventHandler::EndEvent(CancerEventHandler::SETUP);
00481 
00482     // Initialise a vector of forces on node
00483     std::vector<c_vector<double, DIM> > forces(mrTissue.GetNumNodes(),zero_vector<double>(DIM));
00484 
00486     // Main time loop
00488 
00489     while ((p_simulation_time->GetTimeStepsElapsed() < num_time_steps) && !(StoppingEventHasOccurred()) )
00490     {
00491         LOG(1, "--TIME = " << p_simulation_time->GetTime() << "\n");
00492 
00494         // Remove dead cells
00496         CancerEventHandler::BeginEvent(CancerEventHandler::DEATH);
00497         unsigned deaths_this_step = DoCellRemoval();
00498         mNumDeaths += deaths_this_step;
00499         LOG(1, "\tNum deaths = " << mNumDeaths << "\n");
00500         CancerEventHandler::EndEvent(CancerEventHandler::DEATH);
00501 
00503         // Divide cells
00505         CancerEventHandler::BeginEvent(CancerEventHandler::BIRTH);
00506         unsigned births_this_step = DoCellBirth();
00507         mNumBirths += births_this_step;
00508         LOG(1, "\tNum births = " << mNumBirths << "\n");
00509         CancerEventHandler::EndEvent(CancerEventHandler::BIRTH);
00510 
00512         // Update topology of tissue
00514 
00520         if (mrTissue.HasMesh())
00521         {
00522             //This assertion is not necessarily true
00523             //assert(mUpdateTissue);
00524             //See TestCryptSimulation2dNightly::Test2DSpringSystem where the
00525             //default value is over-written
00526         }
00527         else
00528         {
00529             mUpdateTissue = false;
00530             if ( (births_this_step>0) || (deaths_this_step>0) )
00531             {
00532                 mUpdateTissue = true;
00533             }
00534         }
00535 
00536         // Update the topology of the tissue (and tessellate if needed)
00537         CancerEventHandler::BeginEvent(CancerEventHandler::UPDATE);
00538         if (mUpdateTissue)
00539         {
00540             LOG(1, "\tUpdating tissue...");
00541             mrTissue.Update();
00542             LOG(1, "\tdone.\n");
00543         }
00544         CancerEventHandler::EndEvent(CancerEventHandler::UPDATE);
00545 
00547         // Calculate Forces
00549         CancerEventHandler::BeginEvent(CancerEventHandler::FORCE);
00550 
00551         // First set all the forces to zero
00552         for (unsigned i=0; i<forces.size(); i++)
00553         {
00554              forces[i].clear();
00555         }
00556 
00557         // Then resize the std::vector if the number of cells has increased or decreased
00558         // (note this should be done after the above zeroing)
00559         if (mrTissue.GetNumNodes()!=forces.size())
00560         {
00561             forces.resize(mrTissue.GetNumNodes(), zero_vector<double>(DIM));
00562         }
00563 
00564         // Now add force contributions from each AbstractForce
00565         for (typename std::vector<AbstractForce<DIM>*>::iterator iter = mForceCollection.begin();
00566              iter !=mForceCollection.end();
00567              iter++)
00568         {
00569             (*iter)->AddForceContribution(forces, mrTissue);
00570         }
00571         CancerEventHandler::EndEvent(CancerEventHandler::FORCE);
00572 
00574         // Update node positions
00576         CancerEventHandler::BeginEvent(CancerEventHandler::POSITION);
00577         UpdateNodePositions(forces);
00578         CancerEventHandler::EndEvent(CancerEventHandler::POSITION);
00579 
00581         // PostSolve, which may be implemented by
00582         // child classes (eg to solve nutrient pdes)
00584         PostSolve();
00585 
00586         // Increment simulation time here, so results files look sensible
00587         p_simulation_time->IncrementTimeOneStep();
00588 
00589 
00591         // Output current results
00593         CancerEventHandler::BeginEvent(CancerEventHandler::OUTPUT);
00594 
00595         // Write results to file
00596         if (p_simulation_time->GetTimeStepsElapsed()%mSamplingTimestepMultiple==0)
00597         {
00598             mrTissue.WriteResultsToFiles(mOutputCellMutationStates,
00599                                          mOutputCellTypes,
00600                                          mOutputCellVariables,
00601                                          mOutputCellCyclePhases,
00602                                          mOutputCellAncestors);
00603         }
00604 
00605         CancerEventHandler::EndEvent(CancerEventHandler::OUTPUT);
00606 
00607     }
00608 
00609     AfterSolve();
00610 
00611     CancerEventHandler::BeginEvent(CancerEventHandler::OUTPUT);
00612     mrTissue.CloseOutputFiles(mOutputCellMutationStates,
00613                               mOutputCellTypes,
00614                               mOutputCellVariables,
00615                               mOutputCellCyclePhases,
00616                               mOutputCellAncestors);
00617 
00618     *mpSetupFile << "Complete\n";
00619     mpSetupFile->close();
00620 
00621     CancerEventHandler::EndEvent(CancerEventHandler::OUTPUT);
00622 
00623     CancerEventHandler::EndEvent(CancerEventHandler::EVERYTHING);
00624 }
00625 
00626 
00627 template<unsigned DIM>
00628 void TissueSimulation<DIM>::AfterSolve()
00629 {
00630     LOG(1, "--TIME = " << SimulationTime::Instance()->GetTime() << "\n");
00631 
00632     // Remove dead cells then implement cell birth
00633     CancerEventHandler::BeginEvent(CancerEventHandler::DEATH);
00634     mNumDeaths += DoCellRemoval();
00635     LOG(1, "\tNum deaths = " << mNumDeaths << "\n");
00636     CancerEventHandler::EndEvent(CancerEventHandler::DEATH);
00637 
00638     CancerEventHandler::BeginEvent(CancerEventHandler::BIRTH);
00639     mNumBirths += DoCellBirth();
00640     LOG(1, "\tNum births = " << mNumBirths << "\n");
00641     CancerEventHandler::EndEvent(CancerEventHandler::BIRTH);
00642 
00643     // Carry out a final tissue update if necessary
00644     if (mrTissue.HasMesh())
00645     {
00646         //This assertion is not necessarily true
00647         //assert(mUpdateTissue);
00648         //See TestCryptSimulation2dNightly::Test2DSpringSystem where the
00649         //default value is over-written
00650     }
00651     else
00652     {
00653         mUpdateTissue = false;
00654         if ( (mNumBirths>0) || (mNumDeaths>0) )
00655         {
00656             mUpdateTissue = true;
00657         }
00658     }
00659 
00660     if (mUpdateTissue)
00661     {
00662         LOG(1, "\tUpdating tissue...");
00663         mrTissue.Update();
00664         LOG(1, "\tdone.\n");
00665     }
00666 }
00667 
00668 
00669 template<unsigned DIM>
00670 bool TissueSimulation<DIM>::StoppingEventHasOccurred()
00671 {
00672     return false;
00673 }
00674 
00675 
00676 template<unsigned DIM>
00677 c_vector<unsigned, NUM_CELL_MUTATION_STATES> TissueSimulation<DIM>::GetCellMutationStateCount()
00678 {
00679     if (!mOutputCellMutationStates)
00680     {
00681         EXCEPTION("Call simulator.SetOutputCellMutationStates before using this function");
00682     }
00683     return mrTissue.GetCellMutationStateCount();
00684 }
00685 
00686 
00687 template<unsigned DIM>
00688 c_vector<unsigned, NUM_CELL_TYPES> TissueSimulation<DIM>::GetCellTypeCount()
00689 {
00690     if (!mOutputCellTypes)
00691     {
00692         EXCEPTION("Call simulator.SetOutputCellTypes() before using this function");
00693     }
00694     return mrTissue.GetCellTypeCount();
00695 }
00696 
00697 
00698 template<unsigned DIM>
00699 c_vector<unsigned, 5> TissueSimulation<DIM>::GetCellCyclePhaseCount()
00700 {
00701     if (!mOutputCellCyclePhases)
00702     {
00703         EXCEPTION("Call simulator.SetOutputCellCyclePhases() before using this function");
00704     }
00705     return mrTissue.GetCellCyclePhaseCount();
00706 }
00707 
00708 
00710 // Explicit instantiation
00712 
00713 
00714 template class TissueSimulation<1>;
00715 template class TissueSimulation<2>;
00716 template class TissueSimulation<3>;

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