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