Chaste Release::3.1
AbstractCellBasedSimulation.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #include <cmath>
00037 #include <ctime>
00038 #include <iostream>
00039 #include <fstream>
00040 #include <set>
00041 
00042 #include "AbstractCellBasedSimulation.hpp"
00043 #include "CellBasedEventHandler.hpp"
00044 #include "LogFile.hpp"
00045 #include "Version.hpp"
00046 #include "ExecutableSupport.hpp"
00047 #include "Exception.hpp"
00048 #include <typeinfo>
00049 
00050 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00051 AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::AbstractCellBasedSimulation(AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation,
00052                                               bool deleteCellPopulationInDestructor,
00053                                               bool initialiseCells)
00054     : mDt(DOUBLE_UNSET),
00055       mEndTime(DOUBLE_UNSET),  // hours - this is set later on
00056       mrCellPopulation(rCellPopulation),
00057       mDeleteCellPopulationInDestructor(deleteCellPopulationInDestructor),
00058       mInitialiseCells(initialiseCells),
00059       mNoBirth(false),
00060       mUpdateCellPopulation(true),
00061       mOutputDirectory(""),
00062       mSimulationOutputDirectory(mOutputDirectory),
00063       mNumBirths(0),
00064       mNumDeaths(0),
00065       mOutputDivisionLocations(false),
00066       mSamplingTimestepMultiple(1),
00067       mpCellBasedPdeHandler(NULL)
00068 {
00069     // Set a random seed of 0 if it wasn't specified earlier
00070     RandomNumberGenerator::Instance();
00071 
00072     if (mInitialiseCells)
00073     {
00074         mrCellPopulation.InitialiseCells();
00075     }
00076 }
00077 
00078 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00079 AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::~AbstractCellBasedSimulation()
00080 {
00081     if (mDeleteCellPopulationInDestructor)
00082     {
00083         delete &mrCellPopulation;
00084         delete mpCellBasedPdeHandler;
00085     }
00086 }
00087 
00088 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00089 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetCellBasedPdeHandler(CellBasedPdeHandler<SPACE_DIM>* pCellBasedPdeHandler)
00090 {
00091     mpCellBasedPdeHandler = pCellBasedPdeHandler;
00092 }
00093 
00094 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00095 CellBasedPdeHandler<SPACE_DIM>* AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::GetCellBasedPdeHandler()
00096 {
00097     return mpCellBasedPdeHandler;
00098 }
00099 
00100 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00101 unsigned AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::DoCellBirth()
00102 {
00103     if (mNoBirth)
00104     {
00105         return 0;
00106     }
00107 
00108     unsigned num_births_this_step = 0;
00109 
00110     // Iterate over all cells, seeing if each one can be divided
00111     for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = mrCellPopulation.Begin();
00112          cell_iter != mrCellPopulation.End();
00113          ++cell_iter)
00114     {
00115         // Check if this cell is ready to divide - if so create a new cell etc.
00116         if (cell_iter->GetAge() > 0.0)
00117         {
00118             if (cell_iter->ReadyToDivide())
00119             {
00120                 try
00121                 {
00122                     // Store age before division
00123                     double cell_age =cell_iter->GetAge();
00124 
00125                     // Create a new cell
00126                     CellPtr p_new_cell = cell_iter->Divide();
00127 
00128                     // Call method that determines how cell division occurs and returns a vector
00129                     c_vector<double, SPACE_DIM> new_location = CalculateCellDivisionVector(*cell_iter);
00130 
00131                     // If required, output this location to file
00132                     if (mOutputDivisionLocations)
00133                     {
00134                         *mpDivisionLocationFile << SimulationTime::Instance()->GetTime() << "\t";
00135                         for (unsigned i=0; i<SPACE_DIM; i++)
00136                         {
00137                             *mpDivisionLocationFile << new_location[i] << "\t";
00138                         }
00139                         *mpDivisionLocationFile << "\t" << cell_age << "\n";
00140                     }
00141 
00142                     // Add new cell to the cell population
00143                     mrCellPopulation.AddCell(p_new_cell, new_location, *cell_iter);
00144 
00145                     // Update counter
00146                     num_births_this_step++;
00147                 }
00148                 catch (Exception& e)
00149                 {
00150                     if (!(e.GetShortMessage()=="No free space to divide."))
00151                     {
00152                         NEVER_REACHED;
00153                         // If you do reach here, then uncomment the following line to see why.
00154                         //throw e;
00155                     }
00156                 }
00157             }
00158         }
00159     }
00160     return num_births_this_step;
00161 }
00162 
00163 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00164 unsigned AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::DoCellRemoval()
00165 {
00166     unsigned num_deaths_this_step = 0;
00167 
00168     /*
00169      * This labels cells as dead or apoptosing. It does not actually remove the cells,
00170      * mrCellPopulation.RemoveDeadCells() needs to be called for this.
00171      */
00172     for (typename std::vector<boost::shared_ptr<AbstractCellKiller<SPACE_DIM> > >::iterator killer_iter = mCellKillers.begin();
00173          killer_iter != mCellKillers.end();
00174          ++killer_iter)
00175     {
00176         (*killer_iter)->CheckAndLabelCellsForApoptosisOrDeath();
00177     }
00178 
00179     num_deaths_this_step += mrCellPopulation.RemoveDeadCells();
00180 
00181     return num_deaths_this_step;
00182 }
00183 
00184 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00185 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetDt(double dt)
00186 {
00187     assert(dt > 0);
00188     mDt = dt;
00189 }
00190 
00191 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00192 double AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::GetDt()
00193 {
00194     return mDt;
00195 }
00196 
00197 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00198 unsigned AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::GetNumBirths()
00199 {
00200     return mNumBirths;
00201 }
00202 
00203 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00204 unsigned AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::GetNumDeaths()
00205 {
00206     return mNumDeaths;
00207 }
00208 
00209 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00210 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetEndTime(double endTime)
00211 {
00212     assert(endTime > 0);
00213     mEndTime = endTime;
00214 }
00215 
00216 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00217 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetOutputDirectory(std::string outputDirectory)
00218 {
00219     mOutputDirectory = outputDirectory;
00220     mSimulationOutputDirectory = mOutputDirectory;
00221 }
00222 
00223 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00224 std::string AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::GetOutputDirectory()
00225 {
00226     return mOutputDirectory;
00227 }
00228 
00229 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00230 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetSamplingTimestepMultiple(unsigned samplingTimestepMultiple)
00231 {
00232     assert(samplingTimestepMultiple > 0);
00233     mSamplingTimestepMultiple = samplingTimestepMultiple;
00234 }
00235 
00236 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00237 AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::rGetCellPopulation()
00238 {
00239     return mrCellPopulation;
00240 }
00241 
00242 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00243 const AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::rGetCellPopulation() const
00244 {
00245     return mrCellPopulation;
00246 }
00247 
00248 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00249 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetUpdateCellPopulationRule(bool updateCellPopulation)
00250 {
00251     mUpdateCellPopulation = updateCellPopulation;
00252 }
00253 
00254 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00255 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetNoBirth(bool noBirth)
00256 {
00257     mNoBirth = noBirth;
00258 }
00259 
00260 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00261 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::AddCellKiller(boost::shared_ptr<AbstractCellKiller<SPACE_DIM> > pCellKiller)
00262 {
00263     mCellKillers.push_back(pCellKiller);
00264 }
00265 
00266 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00267 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::RemoveAllCellKillers()
00268 {
00269     mCellKillers.clear();
00270 }
00271 
00272 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00273 std::vector<double> AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::GetNodeLocation(const unsigned& rNodeIndex)
00274 {
00275     std::vector<double> location;
00276     for (unsigned i=0; i<SPACE_DIM; i++)
00277     {
00278         location.push_back(mrCellPopulation.GetNode(rNodeIndex)->rGetLocation()[i]);
00279     }
00280     return location;
00281 }
00282 
00283 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00284 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::Solve()
00285 {
00286     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::EVERYTHING);
00287     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::SETUP);
00288 
00289     // Set up the simulation time
00290     SimulationTime* p_simulation_time = SimulationTime::Instance();
00291     double current_time = p_simulation_time->GetTime();
00292 
00293     assert(mDt != DOUBLE_UNSET);  //Subclass constructors take care of this
00294 
00295     if (mEndTime == DOUBLE_UNSET)
00296     {
00297         EXCEPTION("SetEndTime has not yet been called.");
00298     }
00299 
00300     /*Note that mDt is used here for "ideal time step".  If this step doesn't divide the time remaining then
00301      * a *different* time step will be taken by the time-stepper.  The real time-step (used in the SimulationTime
00302      * singleton is currently not available to this class!
00303      * Should we over-write the value of mDt, or should we change this behaviour? \todo #2159
00304      */
00305     unsigned num_time_steps = (unsigned) ((mEndTime-current_time)/mDt+0.5);
00306     if (current_time > 0) // use the reset function if necessary
00307     {
00308         p_simulation_time->ResetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00309     }
00310     else
00311     {
00312         if (p_simulation_time->IsEndTimeAndNumberOfTimeStepsSetUp())
00313         {
00314             EXCEPTION("End time and number of timesteps already setup. You should not use SimulationTime::SetEndTimeAndNumberOfTimeSteps in cell-based tests.");
00315         }
00316         else
00317         {
00318             p_simulation_time->SetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00319         }
00320     }
00321 
00322     if (mOutputDirectory == "")
00323     {
00324         EXCEPTION("OutputDirectory not set");
00325     }
00326 
00327     double time_now = p_simulation_time->GetTime();
00328     std::ostringstream time_string;
00329     time_string << time_now;
00330 
00331     std::string results_directory = mOutputDirectory +"/results_from_time_" + time_string.str();
00332     mSimulationOutputDirectory = results_directory;
00333 
00334     // Set up simulation
00335 
00336     // Create output files for the visualizer
00337     OutputFileHandler output_file_handler(results_directory+"/", true);
00338 
00339     mrCellPopulation.CreateOutputFiles(results_directory+"/", false);
00340 
00341     if (mOutputDivisionLocations)
00342     {
00343         mpDivisionLocationFile = output_file_handler.OpenOutputFile("divisions.dat");
00344     }
00345 
00346     if (PetscTools::AmMaster())
00347     {
00348         mpVizSetupFile = output_file_handler.OpenOutputFile("results.vizsetup");
00349     }
00350 
00351     // If any PDEs have been defined, set up results files to store their solution
00352     if (mpCellBasedPdeHandler != NULL)
00353     {
00354         mpCellBasedPdeHandler->OpenResultsFiles(this->mSimulationOutputDirectory);
00355         if (PetscTools::AmMaster())
00356         {
00357             *this->mpVizSetupFile << "PDE \n";
00358         }
00359     }
00360 
00361     SetupSolve();
00362 
00363     // Age the cells to the correct time. Note that cells are created with
00364     // negative birth times so that some are initially almost ready to divide.
00365     LOG(1, "Setting up cells...");
00366     for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = mrCellPopulation.Begin();
00367          cell_iter != mrCellPopulation.End();
00368          ++cell_iter)
00369     {
00370         // We don't use the result; this call is just to force the cells to age
00371         // to the current time running their cell-cycle models to get there
00372         cell_iter->ReadyToDivide();
00373     }
00374     LOG(1, "\tdone\n");
00375 
00376     // Write initial conditions to file for the visualizer
00377     WriteVisualizerSetupFile();
00378 
00379     if (PetscTools::AmMaster())
00380     {
00381         *mpVizSetupFile << std::flush;
00382     }
00383 
00384     mrCellPopulation.WriteResultsToFiles();
00385 
00386     OutputSimulationSetup();
00387 
00388     CellBasedEventHandler::EndEvent(CellBasedEventHandler::SETUP);
00389 
00390 
00391     // Enter main time loop
00392     while (!( p_simulation_time->IsFinished() || StoppingEventHasOccurred() ) )
00393     {
00394         LOG(1, "--TIME = " << p_simulation_time->GetTime() << "\n");
00395 
00396         // This function calls DoCellRemoval(), DoCellBirth() and CellPopulation::Update()
00397         UpdateCellPopulation();
00398 
00399         // Update cell locations and topology
00400         UpdateCellLocationsAndTopology();
00401 
00402         // If any PDEs have been defined, solve them and store their solution in results files
00403         if (mpCellBasedPdeHandler != NULL)
00404         {
00405             CellBasedEventHandler::BeginEvent(CellBasedEventHandler::PDE);
00406             mpCellBasedPdeHandler->SolvePdeAndWriteResultsToFile(this->mSamplingTimestepMultiple);
00407             CellBasedEventHandler::EndEvent(CellBasedEventHandler::PDE);
00408         }
00409 
00410         // Call UpdateAtEndOfTimeStep(), which may be implemented by child classes
00411         CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATESIMULATION);
00412         UpdateAtEndOfTimeStep();
00413         CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATESIMULATION);
00414 
00415         // Increment simulation time here, so results files look sensible
00416         p_simulation_time->IncrementTimeOneStep();
00417 
00418         // Output current results to file
00419         CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT);
00420         if (p_simulation_time->GetTimeStepsElapsed()%mSamplingTimestepMultiple == 0)
00421         {
00422             mrCellPopulation.WriteResultsToFiles();
00423         }
00424         CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT);
00425     }
00426 
00427     LOG(1, "--END TIME = " << p_simulation_time->GetTime() << "\n");
00428 
00429     // Carry out a final update so that cell population is coherent with new cell positions.
00430     // NB cell birth/death still need to be checked because they may be spatially-dependent.
00431     UpdateCellPopulation();
00432 
00433     // If any PDEs have been defined, close the results files storing their solution
00434     if (mpCellBasedPdeHandler != NULL)
00435     {
00436         mpCellBasedPdeHandler->CloseResultsFiles();
00437     }
00438 
00439     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATESIMULATION);
00440     UpdateAtEndOfSolve();
00441     CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATESIMULATION);
00442 
00443     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT);
00444 
00445     mrCellPopulation.CloseOutputFiles();
00446 
00447     if (mOutputDivisionLocations)
00448     {
00449         mpDivisionLocationFile->close();
00450     }
00451 
00452     if (PetscTools::AmMaster())
00453     {
00454         *mpVizSetupFile << "Complete\n";
00455         mpVizSetupFile->close();
00456     }
00457 
00458     CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT);
00459     CellBasedEventHandler::EndEvent(CellBasedEventHandler::EVERYTHING);
00460 }
00461 
00462 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00463 bool AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::StoppingEventHasOccurred()
00464 {
00465     return false;
00466 }
00467 
00468 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00469 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::UpdateCellPopulation()
00470 {
00471     // Remove dead cells
00472     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::DEATH);
00473     unsigned deaths_this_step = DoCellRemoval();
00474     mNumDeaths += deaths_this_step;
00475     LOG(1, "\tNum deaths = " << mNumDeaths << "\n");
00476     CellBasedEventHandler::EndEvent(CellBasedEventHandler::DEATH);
00477 
00478     // Divide cells
00479     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::BIRTH);
00480     unsigned births_this_step = DoCellBirth();
00481     mNumBirths += births_this_step;
00482     LOG(1, "\tNum births = " << mNumBirths << "\n");
00483     CellBasedEventHandler::EndEvent(CellBasedEventHandler::BIRTH);
00484 
00485     // This allows NodeBasedCellPopulation::Update() to do the minimum amount of work
00486     bool births_or_death_occurred = ((births_this_step>0) || (deaths_this_step>0));
00487 
00488     // Update topology of cell population
00489     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATECELLPOPULATION);
00490     if (mUpdateCellPopulation)
00491     {
00492         LOG(1, "\tUpdating cell population...");
00493         mrCellPopulation.Update(births_or_death_occurred);
00494         LOG(1, "\tdone.\n");
00495     }
00496     else if (births_or_death_occurred)
00497     {
00498         EXCEPTION("CellPopulation has had births or deaths but mUpdateCellPopulation is set to false, please set it to true.");
00499     }
00500     CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATECELLPOPULATION);
00501 }
00502 
00503 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00504 bool AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::GetOutputDivisionLocations()
00505 {
00506     return mOutputDivisionLocations;
00507 }
00508 
00509 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00510 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::SetOutputDivisionLocations(bool outputDivisionLocations)
00511 {
00512     mOutputDivisionLocations = outputDivisionLocations;
00513 }
00514 
00515 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00516 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::OutputSimulationSetup()
00517 {
00518     OutputFileHandler output_file_handler(this->mSimulationOutputDirectory + "/", false);
00519 
00520     // Output machine information
00521     ExecutableSupport::WriteMachineInfoFile(this->mSimulationOutputDirectory + "/system_info");
00522 
00523     // Output Chaste provenance information
00524     out_stream build_info_file = output_file_handler.OpenOutputFile("build.info");
00525     ExecutableSupport::WriteLibraryInfo(build_info_file);
00526     build_info_file->close();
00527 
00528     // Output simulation parameter and setup details
00529     out_stream parameter_file = output_file_handler.OpenOutputFile("results.parameters");
00530 
00531     // Output simulation details
00532     std::string simulation_type = GetIdentifier();
00533 
00534     *parameter_file << "<Chaste>\n";
00535     *parameter_file << "\n\t<" << simulation_type << ">\n";
00536     OutputSimulationParameters(parameter_file);
00537     *parameter_file << "\t</" << simulation_type << ">\n";
00538     *parameter_file << "\n";
00539 
00540     // Output cell population details (includes cell-cycle model details)
00541     mrCellPopulation.OutputCellPopulationInfo(parameter_file);
00542 
00543     // Loop over cell killers
00544     *parameter_file << "\n\t<CellKillers>\n";
00545     for (typename std::vector<boost::shared_ptr<AbstractCellKiller<SPACE_DIM> > >::iterator iter = mCellKillers.begin();
00546          iter != mCellKillers.end();
00547          ++iter)
00548     {
00549         // Output cell killer details
00550         (*iter)->OutputCellKillerInfo(parameter_file);
00551     }
00552     *parameter_file << "\t</CellKillers>\n";
00553 
00554     // This is used to output information about subclasses
00555     OutputAdditionalSimulationSetup(parameter_file);
00556 
00557     *parameter_file << "\n</Chaste>\n";
00558     parameter_file->close();
00559 }
00560 
00561 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00562 void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::OutputSimulationParameters(out_stream& rParamsFile)
00563 {
00564     if (mpCellBasedPdeHandler != NULL)
00565     {
00566         mpCellBasedPdeHandler->OutputParameters(rParamsFile);
00567     }
00568 
00569     *rParamsFile << "\t\t<Dt>" << mDt << "</Dt>\n";
00570     *rParamsFile << "\t\t<EndTime>" << mEndTime << "</EndTime>\n";
00571     *rParamsFile << "\t\t<SamplingTimestepMultiple>" << mSamplingTimestepMultiple << "</SamplingTimestepMultiple>\n";
00572     *rParamsFile << "\t\t<OutputDivisionLocations>" << mOutputDivisionLocations << "</OutputDivisionLocations>\n";
00573 }
00574 
00576 // Explicit instantiation
00578 
00579 template class AbstractCellBasedSimulation<1,1>;
00580 template class AbstractCellBasedSimulation<1,2>;
00581 template class AbstractCellBasedSimulation<2,2>;
00582 template class AbstractCellBasedSimulation<1,3>;
00583 template class AbstractCellBasedSimulation<2,3>;
00584 template class AbstractCellBasedSimulation<3,3>;