00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <cmath>
00029 #include <ctime>
00030 #include <iostream>
00031 #include <fstream>
00032 #include <set>
00033
00034 #include "CellBasedSimulation.hpp"
00035 #include "AbstractCentreBasedCellPopulation.hpp"
00036 #include "CellBasedEventHandler.hpp"
00037 #include "LogFile.hpp"
00038 #include "Version.hpp"
00039 #include "ExecutableSupport.hpp"
00040
00041 #include <typeinfo>
00042
00043 template<unsigned DIM>
00044 CellBasedSimulation<DIM>::CellBasedSimulation(AbstractCellPopulation<DIM>& rCellPopulation,
00045 bool deleteCellPopulationAndForcesAndBCsInDestructor,
00046 bool initialiseCells)
00047 : mEndTime(0.0),
00048 mrCellPopulation(rCellPopulation),
00049 mDeleteCellPopulationAndForcesAndBCsInDestructor(deleteCellPopulationAndForcesAndBCsInDestructor),
00050 mInitialiseCells(initialiseCells),
00051 mNoBirth(false),
00052 mUpdateCellPopulation(true),
00053 mOutputDirectory(""),
00054 mSimulationOutputDirectory(mOutputDirectory),
00055 mNumBirths(0),
00056 mNumDeaths(0),
00057 mSamplingTimestepMultiple(1),
00058 mOutputNodeVelocities(false)
00059 {
00060
00061 mpRandomGenerator = RandomNumberGenerator::Instance();
00062
00063
00064 if (dynamic_cast<AbstractCentreBasedCellPopulation<DIM>*>(&rCellPopulation))
00065 {
00066 mDt = 1.0/120.0;
00067 }
00068 else
00069 {
00070 mDt = 0.002;
00071 }
00072
00073 if (mInitialiseCells)
00074 {
00075 mrCellPopulation.InitialiseCells();
00076 }
00077 }
00078
00079
00080 template<unsigned DIM>
00081 CellBasedSimulation<DIM>::~CellBasedSimulation()
00082 {
00083 if (mDeleteCellPopulationAndForcesAndBCsInDestructor)
00084 {
00085 for (typename std::vector<AbstractForce<DIM>*>::iterator force_iter = mForceCollection.begin();
00086 force_iter != mForceCollection.end();
00087 ++force_iter)
00088 {
00089 delete *force_iter;
00090 }
00091
00092 for (typename std::vector<AbstractCellKiller<DIM>*>::iterator it=mCellKillers.begin();
00093 it != mCellKillers.end();
00094 ++it)
00095 {
00096 delete *it;
00097 }
00098
00099 for (typename std::vector<AbstractCellPopulationBoundaryCondition<DIM>*>::iterator it=mBoundaryConditions.begin();
00100 it != mBoundaryConditions.end();
00101 ++it)
00102 {
00103 delete *it;
00104 }
00105
00106 delete &mrCellPopulation;
00107 }
00108 }
00109
00110
00111 template<unsigned DIM>
00112 unsigned CellBasedSimulation<DIM>::DoCellBirth()
00113 {
00114 if (mNoBirth)
00115 {
00116 return 0;
00117 }
00118
00119 unsigned num_births_this_step = 0;
00120
00121
00122 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = mrCellPopulation.Begin();
00123 cell_iter != mrCellPopulation.End();
00124 ++cell_iter)
00125 {
00126
00127 if (cell_iter->GetAge() > 0.0)
00128 {
00129 if (cell_iter->ReadyToDivide())
00130 {
00131
00132 CellPtr p_new_cell = cell_iter->Divide();
00133
00134
00135 c_vector<double, DIM> new_location = CalculateCellDivisionVector(*cell_iter);
00136
00137
00138 mrCellPopulation.AddCell(p_new_cell, new_location, *cell_iter);
00139
00140
00141 num_births_this_step++;
00142 }
00143 }
00144 }
00145 return num_births_this_step;
00146 }
00147
00148
00149 template<unsigned DIM>
00150 unsigned CellBasedSimulation<DIM>::DoCellRemoval()
00151 {
00152 unsigned num_deaths_this_step = 0;
00153
00154
00155
00156 for (typename std::vector<AbstractCellKiller<DIM>*>::iterator killer_iter = mCellKillers.begin();
00157 killer_iter != mCellKillers.end();
00158 ++killer_iter)
00159 {
00160 (*killer_iter)->TestAndLabelCellsForApoptosisOrDeath();
00161 }
00162
00163 num_deaths_this_step += mrCellPopulation.RemoveDeadCells();
00164
00165 return num_deaths_this_step;
00166 }
00167
00168
00169 template<unsigned DIM>
00170 c_vector<double, DIM> CellBasedSimulation<DIM>::CalculateCellDivisionVector(CellPtr pParentCell)
00171 {
00177 if (dynamic_cast<AbstractCentreBasedCellPopulation<DIM>*>(&mrCellPopulation))
00178 {
00179
00180 c_vector<double, DIM> parent_coords = mrCellPopulation.GetLocationOfCellCentre(pParentCell);
00181 c_vector<double, DIM> daughter_coords;
00182
00183
00184 double separation = static_cast<AbstractCentreBasedCellPopulation<DIM>*>(&mrCellPopulation)->GetMeinekeDivisionSeparation();
00185
00186
00187 c_vector<double, DIM> random_vector;
00188
00189
00190
00191
00192
00193
00194 switch (DIM)
00195 {
00196 case 1:
00197 {
00198 double random_direction = -1.0 + 2.0*(RandomNumberGenerator::Instance()->ranf() < 0.5);
00199
00200 random_vector(0) = 0.5*separation*random_direction;
00201 break;
00202 }
00203 case 2:
00204 {
00205 double random_angle = 2.0*M_PI*RandomNumberGenerator::Instance()->ranf();
00206
00207 random_vector(0) = 0.5*separation*cos(random_angle);
00208 random_vector(1) = 0.5*separation*sin(random_angle);
00209 break;
00210 }
00211 case 3:
00212 {
00213 double random_zenith_angle = M_PI*RandomNumberGenerator::Instance()->ranf();
00214 double random_azimuth_angle = 2*M_PI*RandomNumberGenerator::Instance()->ranf();
00215
00216 random_vector(0) = 0.5*separation*cos(random_azimuth_angle)*sin(random_zenith_angle);
00217 random_vector(1) = 0.5*separation*sin(random_azimuth_angle)*sin(random_zenith_angle);
00218 random_vector(2) = 0.5*separation*cos(random_zenith_angle);
00219 break;
00220 }
00221 default:
00222
00223 NEVER_REACHED;
00224 }
00225
00226 parent_coords = parent_coords - random_vector;
00227 daughter_coords = parent_coords + random_vector;
00228
00229
00230 ChastePoint<DIM> parent_coords_point(parent_coords);
00231 unsigned node_index = mrCellPopulation.GetLocationIndexUsingCell(pParentCell);
00232 mrCellPopulation.SetNode(node_index, parent_coords_point);
00233
00234 return daughter_coords;
00235 }
00236 else
00237 {
00238
00239 return zero_vector<double>(DIM);
00240 }
00241 }
00242
00243
00244 template<unsigned DIM>
00245 void CellBasedSimulation<DIM>::UpdateNodePositions(const std::vector< c_vector<double, DIM> >& rNodeForces)
00246 {
00247 unsigned num_nodes = mrCellPopulation.GetNumNodes();
00248
00249
00250
00251
00252
00253 std::vector<c_vector<double, DIM> > old_node_locations;
00254 old_node_locations.reserve(num_nodes);
00255 for (unsigned node_index=0; node_index<num_nodes; node_index++)
00256 {
00257 old_node_locations[node_index] = mrCellPopulation.GetNode(node_index)->rGetLocation();
00258 }
00259
00260
00261 mrCellPopulation.UpdateNodeLocations(rNodeForces, mDt);
00262
00263
00264 for (typename std::vector<AbstractCellPopulationBoundaryCondition<DIM>*>::iterator bcs_iter = mBoundaryConditions.begin();
00265 bcs_iter != mBoundaryConditions.end();
00266 ++bcs_iter)
00267 {
00268 (*bcs_iter)->ImposeBoundaryCondition();
00269 }
00270
00271
00272 for (typename std::vector<AbstractCellPopulationBoundaryCondition<DIM>*>::iterator bcs_iter = mBoundaryConditions.begin();
00273 bcs_iter != mBoundaryConditions.end();
00274 ++bcs_iter)
00275 {
00276 if (!((*bcs_iter)->VerifyBoundaryCondition()))
00277 {
00278 EXCEPTION("The cell population boundary conditions are incompatible.");
00279 }
00280 }
00281
00283 ApplyCellPopulationBoundaryConditions(old_node_locations);
00284
00285
00286 if (mOutputNodeVelocities)
00287 {
00288 if (SimulationTime::Instance()->GetTimeStepsElapsed()%mSamplingTimestepMultiple == 0)
00289 {
00290 *mpNodeVelocitiesFile << SimulationTime::Instance()->GetTime() << "\t";
00291 for (unsigned node_index=0; node_index<num_nodes; node_index++)
00292 {
00293
00294 assert(!mrCellPopulation.GetNode(node_index)->IsDeleted());
00295
00296
00297 bool is_real_node = true;
00298 if (dynamic_cast<AbstractCentreBasedCellPopulation<DIM>*>(&mrCellPopulation))
00299 {
00300 if (static_cast<AbstractCentreBasedCellPopulation<DIM>*>(&mrCellPopulation)->IsGhostNode(node_index))
00301 {
00302
00303 is_real_node = false;
00304 }
00305 else
00306 {
00307
00308 assert(!mrCellPopulation.GetCellUsingLocationIndex(node_index)->IsDead());
00309 }
00310 }
00311
00312
00313 if (is_real_node)
00314 {
00315 const c_vector<double,DIM>& position = mrCellPopulation.GetNode(node_index)->rGetLocation();
00316 c_vector<double, 2> velocity = this->mDt * rNodeForces[node_index] / this->mrCellPopulation.GetDampingConstant(node_index);
00317
00318 *mpNodeVelocitiesFile << node_index << " ";
00319 for (unsigned i=0; i<DIM; i++)
00320 {
00321 *mpNodeVelocitiesFile << position[i] << " ";
00322 }
00323 for (unsigned i=0; i<DIM; i++)
00324 {
00325 *mpNodeVelocitiesFile << velocity[i] << " ";
00326 }
00327 }
00328 }
00329 *mpNodeVelocitiesFile << "\n";
00330 }
00331 }
00332 }
00333
00334
00335 template<unsigned DIM>
00336 void CellBasedSimulation<DIM>::SetDt(double dt)
00337 {
00338 assert(dt > 0);
00339 mDt = dt;
00340 }
00341
00342
00343 template<unsigned DIM>
00344 double CellBasedSimulation<DIM>::GetDt()
00345 {
00346 return mDt;
00347 }
00348
00349
00350 template<unsigned DIM>
00351 unsigned CellBasedSimulation<DIM>::GetNumBirths()
00352 {
00353 return mNumBirths;
00354 }
00355
00356
00357 template<unsigned DIM>
00358 unsigned CellBasedSimulation<DIM>::GetNumDeaths()
00359 {
00360 return mNumDeaths;
00361 }
00362
00363
00364 template<unsigned DIM>
00365 void CellBasedSimulation<DIM>::SetEndTime(double endTime)
00366 {
00367 assert(endTime > 0);
00368 mEndTime = endTime;
00369 }
00370
00371
00372 template<unsigned DIM>
00373 void CellBasedSimulation<DIM>::SetOutputDirectory(std::string outputDirectory)
00374 {
00375 mOutputDirectory = outputDirectory;
00376 mSimulationOutputDirectory = mOutputDirectory;
00377 }
00378
00379
00380 template<unsigned DIM>
00381 std::string CellBasedSimulation<DIM>::GetOutputDirectory()
00382 {
00383 return mOutputDirectory;
00384 }
00385
00386 template<unsigned DIM>
00387 void CellBasedSimulation<DIM>::SetSamplingTimestepMultiple(unsigned samplingTimestepMultiple)
00388 {
00389 assert(samplingTimestepMultiple > 0);
00390 mSamplingTimestepMultiple = samplingTimestepMultiple;
00391 }
00392
00393
00394 template<unsigned DIM>
00395 AbstractCellPopulation<DIM>& CellBasedSimulation<DIM>::rGetCellPopulation()
00396 {
00397 return mrCellPopulation;
00398 }
00399
00400
00401 template<unsigned DIM>
00402 const AbstractCellPopulation<DIM>& CellBasedSimulation<DIM>::rGetCellPopulation() const
00403 {
00404 return mrCellPopulation;
00405 }
00406
00407
00408 template<unsigned DIM>
00409 void CellBasedSimulation<DIM>::SetUpdateCellPopulationRule(bool updateCellPopulation)
00410 {
00411 mUpdateCellPopulation = updateCellPopulation;
00412 }
00413
00414
00415 template<unsigned DIM>
00416 void CellBasedSimulation<DIM>::SetNoBirth(bool noBirth)
00417 {
00418 mNoBirth = noBirth;
00419 }
00420
00421
00422 template<unsigned DIM>
00423 void CellBasedSimulation<DIM>::AddCellKiller(AbstractCellKiller<DIM>* pCellKiller)
00424 {
00425 mCellKillers.push_back(pCellKiller);
00426 }
00427
00428 template<unsigned DIM>
00429 void CellBasedSimulation<DIM>::AddForce(AbstractForce<DIM>* pForce)
00430 {
00431 mForceCollection.push_back(pForce);
00432 }
00433
00434 template<unsigned DIM>
00435 void CellBasedSimulation<DIM>::AddCellPopulationBoundaryCondition(AbstractCellPopulationBoundaryCondition<DIM>* pBoundaryCondition)
00436 {
00437 mBoundaryConditions.push_back(pBoundaryCondition);
00438 }
00439
00440
00441 template<unsigned DIM>
00442 std::vector<double> CellBasedSimulation<DIM>::GetNodeLocation(const unsigned& rNodeIndex)
00443 {
00444 std::vector<double> location;
00445 for (unsigned i=0; i<DIM; i++)
00446 {
00447 location.push_back(mrCellPopulation.GetNode(rNodeIndex)->rGetLocation()[i]);
00448 }
00449 return location;
00450 }
00451
00452
00453 template<unsigned DIM>
00454 void CellBasedSimulation<DIM>::Solve()
00455 {
00456 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::EVERYTHING);
00457 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::SETUP);
00458
00459
00460 SimulationTime* p_simulation_time = SimulationTime::Instance();
00461 double current_time = p_simulation_time->GetTime();
00462
00463 unsigned num_time_steps = (unsigned) ((mEndTime-current_time)/mDt+0.5);
00464
00465 if (current_time > 0)
00466 {
00467 p_simulation_time->ResetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00468 }
00469 else
00470 {
00471 p_simulation_time->SetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps);
00472 }
00473
00474 if (mOutputDirectory=="")
00475 {
00476 EXCEPTION("OutputDirectory not set");
00477 }
00478
00479 double time_now = p_simulation_time->GetTime();
00480 std::ostringstream time_string;
00481 time_string << time_now;
00482
00483 std::string results_directory = mOutputDirectory +"/results_from_time_" + time_string.str();
00484 mSimulationOutputDirectory = results_directory;
00485
00487
00489
00490
00491 OutputFileHandler output_file_handler(results_directory+"/", true);
00492
00493 mrCellPopulation.CreateOutputFiles(results_directory+"/", false);
00494
00495 mpVizSetupFile = output_file_handler.OpenOutputFile("results.vizsetup");
00496
00497 if (mOutputNodeVelocities)
00498 {
00499 OutputFileHandler output_file_handler2(results_directory+"/", false);
00500 mpNodeVelocitiesFile = output_file_handler2.OpenOutputFile("nodevelocities.dat");
00501 }
00502
00503 SetupSolve();
00504
00505
00506
00507 LOG(1, "Setting up cells...");
00508 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = mrCellPopulation.Begin();
00509 cell_iter != mrCellPopulation.End();
00510 ++cell_iter)
00511 {
00512
00513
00514 cell_iter->ReadyToDivide();
00515 }
00516 LOG(1, "\tdone\n");
00517
00518
00519 WriteVisualizerSetupFile();
00520
00521 *mpVizSetupFile << std::flush;
00522
00523 mrCellPopulation.WriteResultsToFiles();
00524
00525 OutputSimulationSetup();
00526
00527 CellBasedEventHandler::EndEvent(CellBasedEventHandler::SETUP);
00528
00529
00530 std::vector<c_vector<double, DIM> > forces(mrCellPopulation.GetNumNodes(), zero_vector<double>(DIM));
00531
00533
00535
00536 while ((p_simulation_time->GetTimeStepsElapsed() < num_time_steps) && !(StoppingEventHasOccurred()) )
00537 {
00538 LOG(1, "--TIME = " << p_simulation_time->GetTime() << "\n");
00539
00546 UpdateCellPopulation();
00547
00549
00551 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::FORCE);
00552
00553
00554 for (unsigned i=0; i<forces.size(); i++)
00555 {
00556 forces[i].clear();
00557 }
00558
00559
00560
00561 unsigned num_nodes = mrCellPopulation.GetNumNodes();
00562 if (num_nodes != forces.size())
00563 {
00564 forces.resize(num_nodes, zero_vector<double>(DIM));
00565 }
00566
00567
00568 for (typename std::vector<AbstractForce<DIM>*>::iterator iter = mForceCollection.begin();
00569 iter != mForceCollection.end();
00570 ++iter)
00571 {
00572 (*iter)->AddForceContribution(forces, mrCellPopulation);
00573 }
00574 CellBasedEventHandler::EndEvent(CellBasedEventHandler::FORCE);
00575
00577
00579 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::POSITION);
00580 UpdateNodePositions(forces);
00581 CellBasedEventHandler::EndEvent(CellBasedEventHandler::POSITION);
00582
00584
00585
00587 PostSolve();
00588
00589
00590 p_simulation_time->IncrementTimeOneStep();
00591
00593
00595 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT);
00596
00597
00598 if (p_simulation_time->GetTimeStepsElapsed()%mSamplingTimestepMultiple == 0)
00599 {
00600 mrCellPopulation.WriteResultsToFiles();
00601 }
00602
00603 CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT);
00604 }
00605
00606 LOG(1, "--END TIME = " << SimulationTime::Instance()->GetTime() << "\n");
00607
00608
00609 UpdateCellPopulation();
00610
00611 AfterSolve();
00612
00613 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT);
00614
00615 mrCellPopulation.CloseOutputFiles();
00616
00617 if (mOutputNodeVelocities)
00618 {
00619 mpNodeVelocitiesFile->close();
00620 }
00621
00622 *mpVizSetupFile << "Complete\n";
00623 mpVizSetupFile->close();
00624
00625 CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT);
00626
00627 CellBasedEventHandler::EndEvent(CellBasedEventHandler::EVERYTHING);
00628 }
00629
00630
00631 template<unsigned DIM>
00632 bool CellBasedSimulation<DIM>::StoppingEventHasOccurred()
00633 {
00634 return false;
00635 }
00636
00637
00638 template<unsigned DIM>
00639 void CellBasedSimulation<DIM>::UpdateCellPopulation()
00640 {
00642
00644 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::DEATH);
00645 unsigned deaths_this_step = DoCellRemoval();
00646 mNumDeaths += deaths_this_step;
00647 LOG(1, "\tNum deaths = " << mNumDeaths << "\n");
00648 CellBasedEventHandler::EndEvent(CellBasedEventHandler::DEATH);
00649
00651
00653 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::BIRTH);
00654 unsigned births_this_step = DoCellBirth();
00655 mNumBirths += births_this_step;
00656 LOG(1, "\tNum births = " << mNumBirths << "\n");
00657 CellBasedEventHandler::EndEvent(CellBasedEventHandler::BIRTH);
00658
00659
00660 bool births_or_death_occurred = ((births_this_step>0) || (deaths_this_step>0));
00661
00663
00665 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATECELLPOPULATION);
00666 if (mUpdateCellPopulation)
00667 {
00668 LOG(1, "\tUpdating cell population...");
00669 mrCellPopulation.Update(births_or_death_occurred);
00670 LOG(1, "\tdone.\n");
00671 }
00672 else if (births_or_death_occurred)
00673 {
00674 EXCEPTION("CellPopulation has had births or deaths but mUpdateCellPopulation is set to false, please set it to true.");
00675 }
00676 CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATECELLPOPULATION);
00677 }
00678
00679 template<unsigned DIM>
00680 void CellBasedSimulation<DIM>::OutputSimulationSetup()
00681 {
00682 OutputFileHandler output_file_handler(this->mSimulationOutputDirectory + "/", false);
00683
00684
00685 ExecutableSupport::WriteMachineInfoFile(this->mSimulationOutputDirectory + "/system_info");
00686
00687
00688 out_stream build_info_file = output_file_handler.OpenOutputFile("build.info");
00689 ExecutableSupport::WriteLibraryInfo(build_info_file);
00690 build_info_file->close();
00691
00692
00693 out_stream parameter_file = output_file_handler.OpenOutputFile("results.parameters");
00694
00695
00696 std::string simulation_type = GetIdentifier();
00697
00698 *parameter_file << "<Chaste>\n";
00699 *parameter_file << "\n\t<" << simulation_type << ">\n";
00700 OutputSimulationParameters(parameter_file);
00701 *parameter_file << "\t</" << simulation_type << ">\n";
00702 *parameter_file << "\n";
00703
00704
00705 mrCellPopulation.OutputCellPopulationInfo(parameter_file);
00706
00707
00708 *parameter_file << "\n\t<Forces>\n";
00709 for (typename std::vector<AbstractForce<DIM>*>::iterator iter = mForceCollection.begin();
00710 iter != mForceCollection.end();
00711 ++iter)
00712 {
00713
00714 (*iter)->OutputForceInfo(parameter_file);
00715 }
00716 *parameter_file << "\t</Forces>\n";
00717
00718
00719 *parameter_file << "\n\t<CellKillers>\n";
00720 for (typename std::vector<AbstractCellKiller<DIM>*>::iterator iter = mCellKillers.begin();
00721 iter != mCellKillers.end();
00722 ++iter)
00723 {
00724
00725 (*iter)->OutputCellKillerInfo(parameter_file);
00726 }
00727 *parameter_file << "\t</CellKillers>\n";
00728
00729
00730 *parameter_file << "\n\t<CellPopulationBoundaryConditions>\n";
00731 for (typename std::vector<AbstractCellPopulationBoundaryCondition<DIM>*>::iterator iter = mBoundaryConditions.begin();
00732 iter != mBoundaryConditions.end();
00733 ++iter)
00734 {
00735
00736 (*iter)->OutputCellPopulationBoundaryConditionInfo(parameter_file);
00737 }
00738 *parameter_file << "\t</CellPopulationBoundaryConditions>\n";
00739
00740 *parameter_file << "\n</Chaste>\n";
00741 parameter_file->close();
00742 }
00743
00744 template<unsigned DIM>
00745 bool CellBasedSimulation<DIM>::GetOutputNodeVelocities()
00746 {
00747 return mOutputNodeVelocities;
00748 }
00749
00750 template<unsigned DIM>
00751 void CellBasedSimulation<DIM>::SetOutputNodeVelocities(bool outputNodeVelocities)
00752 {
00753 mOutputNodeVelocities = outputNodeVelocities;
00754 }
00755
00756 template<unsigned DIM>
00757 void CellBasedSimulation<DIM>::OutputSimulationParameters(out_stream& rParamsFile)
00758 {
00759 *rParamsFile << "\t\t<Dt>" << mDt << "</Dt>\n";
00760 *rParamsFile << "\t\t<EndTime>" << mEndTime << "</EndTime>\n";
00761 *rParamsFile << "\t\t<SamplingTimestepMultiple>" << mSamplingTimestepMultiple << "</SamplingTimestepMultiple>\n";
00762 *rParamsFile << "\t\t<OutputNodeVelocities>" << mOutputNodeVelocities << "</OutputNodeVelocities>\n";
00763 }
00764
00765
00766
00767 #include "SerializationExportWrapperForCpp.hpp"
00768 EXPORT_TEMPLATE_CLASS_SAME_DIMS(CellBasedSimulation)
00769
00770
00771
00773
00774 template class CellBasedSimulation<1>;
00775 template class CellBasedSimulation<2>;
00776 template class CellBasedSimulation<3>;