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 template<unsigned DIM>
00040 TissueSimulation<DIM>::TissueSimulation(AbstractTissue<DIM>& rTissue,
00041                                         std::vector<AbstractForce<DIM>*> forceCollection,
00042                                         bool deleteTissueAndForceCollection,
00043                                         bool initialiseCells)
00044     : mDt(1.0/120.0), // Timestep of 30 seconds (as per Meineke)
00045       mEndTime(0.0),  // hours - this is set later on
00046       mrTissue(rTissue),
00047       mDeleteTissue(deleteTissueAndForceCollection),
00048       mAllocatedMemoryForForceCollection(deleteTissueAndForceCollection),
00049       mInitialiseCells(initialiseCells),
00050       mNoBirth(false),
00051       mUpdateTissue(true),
00052       mOutputDirectory(""),
00053       mSimulationOutputDirectory(mOutputDirectory),
00054       mNumBirths(0),
00055       mNumDeaths(0),
00056       mSamplingTimestepMultiple(1),
00057       mForceCollection(forceCollection)
00058 {
00059     mpConfig = TissueConfig::Instance();
00060 
00061     // This line sets a random seed of 0 if it wasn't specified earlier.
00062     mpRandomGenerator = RandomNumberGenerator::Instance();
00063 
00064     if (mInitialiseCells)
00065     {
00066         mrTissue.InitialiseCells();
00067     }
00068 }
00069 
00070 
00071 template<unsigned DIM>
00072 TissueSimulation<DIM>::~TissueSimulation()
00073 {
00074     if (mAllocatedMemoryForForceCollection)
00075     {
00076         for (typename std::vector<AbstractForce<DIM>*>::iterator force_iter = mForceCollection.begin();
00077              force_iter != mForceCollection.end();
00078              ++force_iter)
00079         {
00080             delete *force_iter;
00081         }
00082     }
00083 
00084     if (mDeleteTissue)
00085     {
00086         for (typename std::vector<AbstractCellKiller<DIM>*>::iterator it=mCellKillers.begin();
00087              it != mCellKillers.end();
00088              ++it)
00089         {
00090             delete *it;
00091         }
00092         delete &mrTissue;
00093     }
00094 }
00095 
00096 
00097 template<unsigned DIM>
00098 unsigned TissueSimulation<DIM>::DoCellBirth()
00099 {
00100     if (mNoBirth)
00101     {
00102         return 0;
00103     }
00104 
00105     unsigned num_births_this_step = 0;
00106 
00107     // Iterate over all cells, seeing if each one can be divided
00108     for (typename AbstractTissue<DIM>::Iterator cell_iter = mrTissue.Begin();
00109          cell_iter != mrTissue.End();
00110          ++cell_iter)
00111     {
00112         // Check if this cell is ready to divide - if so create a new cell etc.
00113         if (cell_iter->GetAge() > 0.0)
00114         {
00115             if (cell_iter->ReadyToDivide())
00116             {
00117                 // Create a new cell
00118                 TissueCell new_cell = cell_iter->Divide();
00119 
00121                 c_vector<double, DIM> new_location = zero_vector<double>(DIM);
00122                 if (dynamic_cast<AbstractCellCentreBasedTissue<DIM>*>(&mrTissue))
00123                 {
00124                     new_location = CalculateDividingCellCentreLocations(&(*cell_iter));
00125                 }
00126 
00127                 // Add new cell to the tissue
00128                 mrTissue.AddCell(new_cell, new_location, &(*cell_iter));
00129 
00130                 // Update counter
00131                 num_births_this_step++;
00132             }
00133         }
00134     }
00135     return num_births_this_step;
00136 }
00137 
00138 
00139 template<unsigned DIM>
00140 unsigned TissueSimulation<DIM>::DoCellRemoval()
00141 {
00142     unsigned num_deaths_this_step = 0;
00143 
00144     // This labels cells as dead or apoptosing. It does not actually remove the cells,
00145     // tissue.RemoveDeadCells() needs to be called for this.
00146     for (typename std::vector<AbstractCellKiller<DIM>*>::iterator killer_iter = mCellKillers.begin();
00147          killer_iter != mCellKillers.end();
00148          ++killer_iter)
00149     {
00150         (*killer_iter)->TestAndLabelCellsForApoptosisOrDeath();
00151     }
00152 
00153     num_deaths_this_step += mrTissue.RemoveDeadCells();
00154 
00155     return num_deaths_this_step;
00156 }
00157 
00158 
00159 template<unsigned DIM>
00160 const std::vector<AbstractForce<DIM>*> TissueSimulation<DIM>::rGetForceCollection() const
00161 {
00162     return mForceCollection;
00163 }
00164 
00165 
00166 template<unsigned DIM>
00167 c_vector<double, DIM> TissueSimulation<DIM>::CalculateDividingCellCentreLocations(TissueCell* pParentCell)
00168 {
00169     // Location of parent and daughter cells
00170     c_vector<double, DIM> parent_coords = mrTissue.GetLocationOfCellCentre(pParentCell);
00171     c_vector<double, DIM> daughter_coords;
00172 
00173     // Get separation parameter
00174     double separation = TissueConfig::Instance()->GetDivisionSeparation();
00175 
00176     // Make a random direction vector of the required length
00177     c_vector<double, DIM> random_vector;
00178 
00179     /*
00180      * Pick a random direction and move the parent cell backwards by 0.5*separation
00181      * in that direction and return the position of the daughter cell 0.5*separation
00182      * forwards in that direction.
00183      */
00184     switch (DIM)
00185     {
00186         case 1:
00187         {
00188             double random_direction = -1.0 + 2.0*(RandomNumberGenerator::Instance()->ranf() < 0.5);
00189             
00190             random_vector(0) = 0.5*separation*random_direction;
00191             break;
00192         }
00193         case 2:
00194         {
00195             double random_angle = 2.0*M_PI*RandomNumberGenerator::Instance()->ranf();
00196             
00197             random_vector(0) = 0.5*separation*cos(random_angle);
00198             random_vector(1) = 0.5*separation*sin(random_angle);
00199             break;
00200         }
00201         case 3:
00202         {
00203             double random_zenith_angle = M_PI*RandomNumberGenerator::Instance()->ranf(); // phi
00204             double random_azimuth_angle = 2*M_PI*RandomNumberGenerator::Instance()->ranf(); // theta
00205 
00206             random_vector(0) = 0.5*separation*cos(random_azimuth_angle)*sin(random_zenith_angle);
00207             random_vector(1) = 0.5*separation*sin(random_azimuth_angle)*sin(random_zenith_angle);
00208             random_vector(2) = 0.5*separation*cos(random_zenith_angle);
00209             break;
00210         }
00211         default:
00212             // This can't happen
00213             NEVER_REACHED;
00214     }
00215     
00216     parent_coords = parent_coords - random_vector;
00217     daughter_coords = parent_coords + random_vector;
00218 
00219     // Set the parent to use this location
00220     ChastePoint<DIM> parent_coords_point(parent_coords);
00221     unsigned node_index = mrTissue.GetLocationIndexUsingCell(pParentCell);
00222     mrTissue.SetNode(node_index, parent_coords_point);
00223 
00224     return daughter_coords;
00225 }
00226 
00227 
00228 template<unsigned DIM>
00229 void TissueSimulation<DIM>::UpdateNodePositions(const std::vector< c_vector<double, DIM> >& rNodeForces)
00230 {
00231     // Get the previous node positions (these may be needed
00232     // when applying boundary conditions, e.g. in the case
00233     // of immotile cells)
00234     std::vector<c_vector<double, DIM> > old_node_locations;
00235     old_node_locations.reserve(mrTissue.GetNumNodes());
00236     for (unsigned node_index=0; node_index<mrTissue.GetNumNodes(); node_index++)
00237     {
00238         old_node_locations[node_index] = mrTissue.GetNode(node_index)->rGetLocation();
00239     }
00240 
00241     // Update node locations
00242     mrTissue.UpdateNodeLocations(rNodeForces, mDt);
00243 
00244     // Apply any boundary conditions
00245     ApplyTissueBoundaryConditions(old_node_locations);
00246 }
00247 
00248 
00249 template<unsigned DIM>
00250 void TissueSimulation<DIM>::SetDt(double dt)
00251 {
00252     assert(dt > 0);
00253     mDt = dt;
00254 }
00255 
00256 
00257 template<unsigned DIM>
00258 double TissueSimulation<DIM>::GetDt()
00259 {
00260     return mDt;
00261 }
00262 
00263 
00264 template<unsigned DIM>
00265 unsigned TissueSimulation<DIM>::GetNumBirths()
00266 {
00267     return mNumBirths;
00268 }
00269 
00270 
00271 template<unsigned DIM>
00272 unsigned TissueSimulation<DIM>::GetNumDeaths()
00273 {
00274     return mNumDeaths;
00275 }
00276 
00277 
00278 template<unsigned DIM>
00279 void TissueSimulation<DIM>::SetEndTime(double endTime)
00280 {
00281     assert(endTime > 0);
00282     mEndTime = endTime;
00283 }
00284 
00285 
00286 template<unsigned DIM>
00287 void TissueSimulation<DIM>::SetOutputDirectory(std::string outputDirectory)
00288 {
00289     mOutputDirectory = outputDirectory;
00290     mSimulationOutputDirectory = mOutputDirectory;
00291 }
00292 
00293 
00294 template<unsigned DIM>
00295 std::string TissueSimulation<DIM>::GetOutputDirectory()
00296 {
00297     return mOutputDirectory;
00298 }
00299 
00300 
00301 template<unsigned DIM>
00302 void TissueSimulation<DIM>::SetSamplingTimestepMultiple(unsigned samplingTimestepMultiple)
00303 {
00304     assert(samplingTimestepMultiple > 0);
00305     mSamplingTimestepMultiple = samplingTimestepMultiple;
00306 }
00307 
00308 
00309 template<unsigned DIM>
00310 AbstractTissue<DIM>& TissueSimulation<DIM>::rGetTissue()
00311 {
00312     return mrTissue;
00313 }
00314 
00315 
00316 template<unsigned DIM>
00317 const AbstractTissue<DIM>& TissueSimulation<DIM>::rGetTissue() const
00318 {
00319     return mrTissue;
00320 }
00321 
00322 
00323 template<unsigned DIM>
00324 void TissueSimulation<DIM>::SetUpdateTissueRule(bool updateTissue)
00325 {
00326     mUpdateTissue = updateTissue;
00327 }
00328 
00329 
00330 template<unsigned DIM>
00331 void TissueSimulation<DIM>::SetNoBirth(bool noBirth)
00332 {
00333     mNoBirth = noBirth;
00334 }
00335 
00336 
00337 template<unsigned DIM>
00338 void TissueSimulation<DIM>::AddCellKiller(AbstractCellKiller<DIM>* pCellKiller)
00339 {
00340     mCellKillers.push_back(pCellKiller);
00341 }
00342 
00343 
00344 template<unsigned DIM>
00345 std::vector<double> TissueSimulation<DIM>::GetNodeLocation(const unsigned& rNodeIndex)
00346 {
00347     std::vector<double> location;
00348     for (unsigned i=0; i<DIM; i++)
00349     {
00350         location.push_back( mrTissue.GetNode(rNodeIndex)->rGetLocation()[i] );
00351     }
00352     return location;
00353 }
00354 
00355 
00356 template<unsigned DIM>
00357 void TissueSimulation<DIM>::Solve()
00358 {
00359     CancerEventHandler::BeginEvent(CancerEventHandler::EVERYTHING);
00360     CancerEventHandler::BeginEvent(CancerEventHandler::SETUP);
00361 
00362     // Set up the simulation time
00363     SimulationTime *p_simulation_time = SimulationTime::Instance();
00364     double current_time = p_simulation_time->GetTime();
00365 
00366     unsigned num_time_steps = (unsigned) ((mEndTime-current_time)/mDt+0.5);
00367 
00368     if (current_time > 0) // use the reset function if necessary
00369     {
00370         p_simulation_time->ResetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00371     }
00372     else
00373     {
00374         p_simulation_time->SetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00375     }
00376 
00377     if (mOutputDirectory=="")
00378     {
00379         EXCEPTION("OutputDirectory not set");
00380     }
00381 
00382     double time_now = p_simulation_time->GetTime();
00383     std::ostringstream time_string;
00384     time_string << time_now;
00385 
00386     std::string results_directory = mOutputDirectory +"/results_from_time_" + time_string.str();
00387     mSimulationOutputDirectory = results_directory;
00388 
00390     // Set up Simulation
00392 
00393     // Create output files for the visualizer
00394     OutputFileHandler output_file_handler(results_directory+"/", true);
00395 
00396     mrTissue.CreateOutputFiles(results_directory+"/", false);
00397 
00398     mpSetupFile = output_file_handler.OpenOutputFile("results.vizsetup");
00399 
00400     SetupSolve();
00401 
00402     // Age the cells to the correct time. Note that cells are created with
00403     // negative birth times so that some are initially almost ready to divide.
00404     LOG(1, "Setting up cells...");
00405     for (typename AbstractTissue<DIM>::Iterator cell_iter = mrTissue.Begin();
00406          cell_iter != mrTissue.End();
00407          ++cell_iter)
00408     {
00409         // We don't use the result; this call is just to force the cells to age
00410         // to the current time running their cell cycle models to get there
00411         cell_iter->ReadyToDivide();
00412     }
00413     LOG(1, "\tdone\n");
00414 
00415     // Write initial conditions to file for the visualizer
00416     if (DIM==2)
00417     {
00418         WriteVisualizerSetupFile();
00419     }
00420     *mpSetupFile << std::flush;
00421 
00422     mrTissue.WriteResultsToFiles();
00423 
00424     CancerEventHandler::EndEvent(CancerEventHandler::SETUP);
00425 
00426     // Initialise a vector of forces on node
00427     std::vector<c_vector<double, DIM> > forces(mrTissue.GetNumNodes(),zero_vector<double>(DIM));
00428 
00430     // Main time loop
00432 
00433     while ((p_simulation_time->GetTimeStepsElapsed() < num_time_steps) && !(StoppingEventHasOccurred()) )
00434     {
00435         LOG(1, "--TIME = " << p_simulation_time->GetTime() << "\n");
00436 
00443         UpdateTissue();
00444 
00446         // Calculate Forces
00448         CancerEventHandler::BeginEvent(CancerEventHandler::FORCE);
00449 
00450         // First set all the forces to zero
00451         for (unsigned i=0; i<forces.size(); i++)
00452         {
00453              forces[i].clear();
00454         }
00455 
00456         // Then resize the std::vector if the number of cells has increased or decreased
00457         // (note this should be done after the above zeroing)
00458         if (mrTissue.GetNumNodes()!=forces.size())
00459         {
00460             forces.resize(mrTissue.GetNumNodes(), zero_vector<double>(DIM));
00461         }
00462 
00463         // Now add force contributions from each AbstractForce
00464         for (typename std::vector<AbstractForce<DIM>*>::iterator iter = mForceCollection.begin();
00465              iter !=mForceCollection.end();
00466              iter++)
00467         {
00468             (*iter)->AddForceContribution(forces, mrTissue);
00469         }
00470         CancerEventHandler::EndEvent(CancerEventHandler::FORCE);
00471 
00473         // Update node positions
00475         CancerEventHandler::BeginEvent(CancerEventHandler::POSITION);
00476         UpdateNodePositions(forces);
00477         CancerEventHandler::EndEvent(CancerEventHandler::POSITION);
00478 
00480         // PostSolve, which may be implemented by
00481         // child classes (eg to solve nutrient pdes)
00483         PostSolve();
00484 
00485         // Increment simulation time here, so results files look sensible
00486         p_simulation_time->IncrementTimeOneStep();
00487 
00489         // Output current results
00491         CancerEventHandler::BeginEvent(CancerEventHandler::OUTPUT);
00492 
00493         // Write results to file
00494         if (p_simulation_time->GetTimeStepsElapsed()%mSamplingTimestepMultiple==0)
00495         {
00496             mrTissue.WriteResultsToFiles();
00497         }
00498 
00499         CancerEventHandler::EndEvent(CancerEventHandler::OUTPUT);
00500     }
00501 
00502     LOG(1, "--END TIME = " << SimulationTime::Instance()->GetTime() << "\n");
00503     /* Carry out a final update so that tissue is coherent with new cell positions.
00504      * NB cell birth/death still need to be checked because they may be spatially-dependent.*/
00505     UpdateTissue();
00506 
00507     AfterSolve();
00508 
00509     CancerEventHandler::BeginEvent(CancerEventHandler::OUTPUT);
00510     mrTissue.CloseOutputFiles();
00511 
00512     *mpSetupFile << "Complete\n";
00513     mpSetupFile->close();
00514 
00515     CancerEventHandler::EndEvent(CancerEventHandler::OUTPUT);
00516 
00517     CancerEventHandler::EndEvent(CancerEventHandler::EVERYTHING);
00518 }
00519 
00520 
00521 template<unsigned DIM>
00522 bool TissueSimulation<DIM>::StoppingEventHasOccurred()
00523 {
00524     return false;
00525 }
00526 
00527 
00528 template<unsigned DIM>
00529 void TissueSimulation<DIM>::UpdateTissue()
00530 {
00532     // Remove dead cells
00534     CancerEventHandler::BeginEvent(CancerEventHandler::DEATH);
00535     unsigned deaths_this_step = DoCellRemoval();
00536     mNumDeaths += deaths_this_step;
00537     LOG(1, "\tNum deaths = " << mNumDeaths << "\n");
00538     CancerEventHandler::EndEvent(CancerEventHandler::DEATH);
00539 
00541     // Divide cells
00543     CancerEventHandler::BeginEvent(CancerEventHandler::BIRTH);
00544     unsigned births_this_step = DoCellBirth();
00545     mNumBirths += births_this_step;
00546     LOG(1, "\tNum births = " << mNumBirths << "\n");
00547     CancerEventHandler::EndEvent(CancerEventHandler::BIRTH);
00548 
00549     // This allows NodeBasedTissue::Update() to do the minimum amount of work
00550     bool births_or_death_occurred = ((births_this_step>0) || (deaths_this_step>0));
00551 
00553     // Update topology of tissue
00555     CancerEventHandler::BeginEvent(CancerEventHandler::UPDATETISSUE);
00556     if (mUpdateTissue)
00557     {
00558         LOG(1, "\tUpdating tissue...");
00559         mrTissue.Update(births_or_death_occurred);
00560         LOG(1, "\tdone.\n");
00561     }
00562     else if (births_or_death_occurred)
00563     {
00564         EXCEPTION("Tissue has had births or deaths but mUpdateTissue is set to false, please set it to true.");
00565     }
00566     CancerEventHandler::EndEvent(CancerEventHandler::UPDATETISSUE);
00567 }
00568 
00570 // Explicit instantiation
00572 
00573 
00574 template class TissueSimulation<1>;
00575 template class TissueSimulation<2>;
00576 template class TissueSimulation<3>;

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