void AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::Solve() { CellBasedEventHandler::BeginEvent(CellBasedEventHandler::EVERYTHING); CellBasedEventHandler::BeginEvent(CellBasedEventHandler::SETUP); // Set up the simulation time SimulationTime* p_simulation_time = SimulationTime::Instance(); double current_time = p_simulation_time->GetTime(); assert(mDt != DOUBLE_UNSET); //Subclass constructors take care of this if (mEndTime == DOUBLE_UNSET) { EXCEPTION("SetEndTime has not yet been called."); } /* * Note that mDt is used here for "ideal time step". If this step doesn't divide the time remaining * then a *different* time step will be taken by the time-stepper. The real time-step (used in the * SimulationTime singleton) is currently not available to this class. * * \todo Should we over-write the value of mDt, or change this behaviour? (see #2159) */ unsigned num_time_steps = (unsigned) ((mEndTime-current_time)/mDt+0.5); if (current_time > 0) // use the reset function if necessary { p_simulation_time->ResetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps); } else { if (p_simulation_time->IsEndTimeAndNumberOfTimeStepsSetUp()) { EXCEPTION("End time and number of timesteps already setup. You should not use SimulationTime::SetEndTimeAndNumberOfTimeSteps in cell-based tests."); } else { p_simulation_time->SetEndTimeAndNumberOfTimeSteps(mEndTime, num_time_steps); } } if (mOutputDirectory == "") { EXCEPTION("OutputDirectory not set"); } double time_now = p_simulation_time->GetTime(); std::ostringstream time_string; time_string << time_now; std::string results_directory = mOutputDirectory +"/results_from_time_" + time_string.str(); mSimulationOutputDirectory = results_directory; // Set up simulation // Create output files for the visualizer OutputFileHandler output_file_handler(results_directory+"/", true); mrCellPopulation.OpenWritersFiles(results_directory+"/"); if (mOutputDivisionLocations) { mpDivisionLocationFile = output_file_handler.OpenOutputFile("divisions.dat"); } if (PetscTools::AmMaster()) { mpVizSetupFile = output_file_handler.OpenOutputFile("results.vizsetup"); } // If any PDEs have been defined, set up results files to store their solution if (mpCellBasedPdeHandler != NULL) { mpCellBasedPdeHandler->OpenResultsFiles(this->mSimulationOutputDirectory); if (PetscTools::AmMaster()) { *this->mpVizSetupFile << "PDE \n"; } /* * If any PDEs have been defined, solve them here before updating cells and store * their solution in results files. This also initializes the relevant CellData. * NOTE that this works as the PDEs are elliptic. */ CellBasedEventHandler::BeginEvent(CellBasedEventHandler::PDE); mpCellBasedPdeHandler->SolvePdeAndWriteResultsToFile(this->mSamplingTimestepMultiple); CellBasedEventHandler::EndEvent(CellBasedEventHandler::PDE); } SetupSolve(); // Call SetupSolve() on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->SetupSolve(this->mrCellPopulation,this->mSimulationOutputDirectory); } /* * Age the cells to the correct time. Note that cells are created with * negative birth times so that some are initially almost ready to divide. */ LOG(1, "Setting up cells..."); for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = mrCellPopulation.Begin(); cell_iter != mrCellPopulation.End(); ++cell_iter) { /* * We don't use the result; this call is just to force the cells to age * to the current time running their cell-cycle models to get there. */ cell_iter->ReadyToDivide(); } LOG(1, "\tdone\n"); // Write initial conditions to file for the visualizer WriteVisualizerSetupFile(); if (PetscTools::AmMaster()) { *mpVizSetupFile << std::flush; } mrCellPopulation.WriteResultsToFiles(results_directory+"/"); OutputSimulationSetup(); CellBasedEventHandler::EndEvent(CellBasedEventHandler::SETUP); // Enter main time loop while (!( p_simulation_time->IsFinished() || StoppingEventHasOccurred() ) ) { LOG(1, "--TIME = " << p_simulation_time->GetTime() << "\n"); // This function calls DoCellRemoval(), DoCellBirth() and CellPopulation::Update() UpdateCellPopulation(); // Update cell locations and topology UpdateCellLocationsAndTopology(); // Update the assignment of cells to processes. mrCellPopulation.UpdateCellProcessLocation(); // Increment simulation time here, so results files look sensible p_simulation_time->IncrementTimeOneStep(); // If any PDEs have been defined, solve them and store their solution in results files if (mpCellBasedPdeHandler != NULL) { CellBasedEventHandler::BeginEvent(CellBasedEventHandler::PDE); mpCellBasedPdeHandler->SolvePdeAndWriteResultsToFile(this->mSamplingTimestepMultiple); CellBasedEventHandler::EndEvent(CellBasedEventHandler::PDE); } // Call UpdateAtEndOfTimeStep(), which may be implemented by child classes CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATESIMULATION); UpdateAtEndOfTimeStep(); // Call UpdateAtEndOfTimeStep() on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->UpdateAtEndOfTimeStep(this->mrCellPopulation); } CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATESIMULATION); // Output current results to file CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT); if (p_simulation_time->GetTimeStepsElapsed()%mSamplingTimestepMultiple == 0) { mrCellPopulation.WriteResultsToFiles(results_directory+"/"); // Call UpdateAtEndOfOutputTimeStep() on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->UpdateAtEndOfOutputTimeStep(this->mrCellPopulation); } } CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT); } LOG(1, "--END TIME = " << p_simulation_time->GetTime() << "\n"); /* * Carry out a final update so that cell population is coherent with new cell positions. * Note that cell birth and death still need to be checked because they may be spatially * dependent. */ UpdateCellPopulation(); // If any PDEs have been defined, close the results files storing their solution if (mpCellBasedPdeHandler != NULL) { mpCellBasedPdeHandler->CloseResultsFiles(); } CellBasedEventHandler::BeginEvent(CellBasedEventHandler::UPDATESIMULATION); UpdateAtEndOfSolve(); // Call UpdateAtEndOfSolve(), on each modifier for (typename std::vector<boost::shared_ptr<AbstractCellBasedSimulationModifier<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mSimulationModifiers.begin(); iter != mSimulationModifiers.end(); ++iter) { (*iter)->UpdateAtEndOfSolve(this->mrCellPopulation); } CellBasedEventHandler::EndEvent(CellBasedEventHandler::UPDATESIMULATION); CellBasedEventHandler::BeginEvent(CellBasedEventHandler::OUTPUT); mrCellPopulation.CloseOutputFiles(); if (mOutputDivisionLocations) { mpDivisionLocationFile->close(); } if (PetscTools::AmMaster()) { *mpVizSetupFile << "Complete\n"; mpVizSetupFile->close(); } CellBasedEventHandler::EndEvent(CellBasedEventHandler::OUTPUT); CellBasedEventHandler::EndEvent(CellBasedEventHandler::EVERYTHING); }
unsigned AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::DoCellBirth() { if (mNoBirth) { return 0; } unsigned num_births_this_step = 0; // Iterate over all cells, seeing if each one can be divided for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = mrCellPopulation.Begin(); cell_iter != mrCellPopulation.End(); ++cell_iter) { // Check if this cell is ready to divide double cell_age = cell_iter->GetAge(); if (cell_age > 0.0) { if (cell_iter->ReadyToDivide()) { // Check if there is room into which the cell may divide if (mrCellPopulation.IsRoomToDivide(*cell_iter)) { // Create a new cell CellPtr p_new_cell = cell_iter->Divide(); // Call method that determines how cell division occurs and returns a vector c_vector<double, SPACE_DIM> new_location = CalculateCellDivisionVector(*cell_iter); // If required, output this location to file /** * \todo (#2441) * * For consistency with the rest of the output code, consider removing the * AbstractCellBasedSimulation member mOutputDivisionLocations, adding a new * member mAgesAndLocationsOfDividingCells to AbstractCellPopulation, adding * a new class CellDivisionLocationsWriter to the CellPopulationWriter hierarchy * to output the content of mAgesAndLocationsOfDividingCells to file (remembering * to clear mAgesAndLocationsOfDividingCells at each timestep), and replacing the * following conditional statement with something like * * if (mrCellPopulation.HasWriter<CellDivisionLocationsWriter>()) * { * mCellDivisionLocations.push_back(new_location); * } */ if (mOutputDivisionLocations) { *mpDivisionLocationFile << SimulationTime::Instance()->GetTime() << "\t"; for (unsigned i=0; i<SPACE_DIM; i++) { *mpDivisionLocationFile << new_location[i] << "\t"; } *mpDivisionLocationFile << "\t" << cell_age << "\n"; } // Add new cell to the cell population mrCellPopulation.AddCell(p_new_cell, new_location, *cell_iter); // Update counter num_births_this_step++; } } } } return num_births_this_step; }