Chaste Release::3.1
|
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 "OffLatticeSimulation.hpp" 00037 #include "AbstractCentreBasedCellPopulation.hpp" 00038 #include "VertexBasedCellPopulation.hpp" 00039 00040 #include "Cylindrical2dMesh.hpp" 00041 #include "Cylindrical2dVertexMesh.hpp" 00042 00043 #include "AbstractTwoBodyInteractionForce.hpp" 00044 #include "CellBasedEventHandler.hpp" 00045 #include "LogFile.hpp" 00046 #include "Version.hpp" 00047 #include "ExecutableSupport.hpp" 00048 00049 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00050 OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::OffLatticeSimulation(AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation, 00051 bool deleteCellPopulationInDestructor, 00052 bool initialiseCells) 00053 : AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>(rCellPopulation, deleteCellPopulationInDestructor, initialiseCells), 00054 mOutputNodeVelocities(false) 00055 { 00056 if (!dynamic_cast<AbstractOffLatticeCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)) 00057 { 00058 EXCEPTION("OffLatticeSimulations require a subclass of AbstractOffLatticeCellPopulation."); 00059 } 00060 00061 // Different time steps are used for cell-centre and vertex-based simulations 00062 if (dynamic_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)) 00063 { 00064 this->mDt = 1.0/120.0; // 30 seconds 00065 } 00066 else 00067 { 00068 assert (dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)); 00069 this->mDt = 0.002; // smaller time step required for convergence/stability 00070 } 00071 } 00072 00073 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00074 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::AddForce(boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > pForce) 00075 { 00076 mForceCollection.push_back(pForce); 00077 } 00078 00079 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00080 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::RemoveAllForces() 00081 { 00082 mForceCollection.clear(); 00083 } 00084 00085 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00086 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::AddCellPopulationBoundaryCondition(boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > pBoundaryCondition) 00087 { 00088 mBoundaryConditions.push_back(pBoundaryCondition); 00089 } 00090 00091 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00092 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::RemoveAllCellPopulationBoundaryConditions() 00093 { 00094 mBoundaryConditions.clear(); 00095 } 00096 00097 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00098 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::UpdateCellLocationsAndTopology() 00099 { 00100 // Calculate forces 00101 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::FORCE); 00102 00103 // Initialise a vector of forces on node 00104 std::vector<c_vector<double, SPACE_DIM> > forces(this->mrCellPopulation.GetNumNodes(), zero_vector<double>(SPACE_DIM)); 00105 00107 // // First set all the forces to zero 00108 // for (unsigned i=0; i<forces.size(); i++) 00109 // { 00110 // forces[i].clear(); 00111 // } 00112 // 00113 // // Then resize the std::vector if the number of cells has increased or decreased 00114 // // (note this should be done after the above zeroing) 00115 // unsigned num_nodes = mrCellPopulation.GetNumNodes(); 00116 // if (num_nodes != forces.size()) 00117 // { 00118 // forces.resize(num_nodes, zero_vector<double>(DIM)); 00119 // } 00120 00121 // Now add force contributions from each AbstractForce 00122 for (typename std::vector<boost::shared_ptr<AbstractForce<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mForceCollection.begin(); 00123 iter != mForceCollection.end(); 00124 ++iter) 00125 { 00126 (*iter)->AddForceContribution(forces, this->mrCellPopulation); 00127 } 00128 CellBasedEventHandler::EndEvent(CellBasedEventHandler::FORCE); 00129 00130 // Update node positions 00131 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::POSITION); 00132 UpdateNodePositions(forces); 00133 CellBasedEventHandler::EndEvent(CellBasedEventHandler::POSITION); 00134 } 00135 00136 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00137 c_vector<double, SPACE_DIM> OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::CalculateCellDivisionVector(CellPtr pParentCell) 00138 { 00144 if (dynamic_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))) 00145 { 00146 // Location of parent and daughter cells 00147 c_vector<double, SPACE_DIM> parent_coords = this->mrCellPopulation.GetLocationOfCellCentre(pParentCell); 00148 c_vector<double, SPACE_DIM> daughter_coords; 00149 00150 // Get separation parameter 00151 double separation = static_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->GetMeinekeDivisionSeparation(); 00152 00153 // Make a random direction vector of the required length 00154 c_vector<double, SPACE_DIM> random_vector; 00155 00156 /* 00157 * Pick a random direction and move the parent cell backwards by 0.5*separation 00158 * in that direction and return the position of the daughter cell 0.5*separation 00159 * forwards in that direction. 00160 */ 00161 switch (SPACE_DIM) 00162 { 00163 case 1: 00164 { 00165 double random_direction = -1.0 + 2.0*(RandomNumberGenerator::Instance()->ranf() < 0.5); 00166 00167 random_vector(0) = 0.5*separation*random_direction; 00168 break; 00169 } 00170 case 2: 00171 { 00172 double random_angle = 2.0*M_PI*RandomNumberGenerator::Instance()->ranf(); 00173 00174 random_vector(0) = 0.5*separation*cos(random_angle); 00175 random_vector(1) = 0.5*separation*sin(random_angle); 00176 break; 00177 } 00178 case 3: 00179 { 00180 double random_zenith_angle = M_PI*RandomNumberGenerator::Instance()->ranf(); // phi 00181 double random_azimuth_angle = 2*M_PI*RandomNumberGenerator::Instance()->ranf(); // theta 00182 00183 random_vector(0) = 0.5*separation*cos(random_azimuth_angle)*sin(random_zenith_angle); 00184 random_vector(1) = 0.5*separation*sin(random_azimuth_angle)*sin(random_zenith_angle); 00185 random_vector(2) = 0.5*separation*cos(random_zenith_angle); 00186 break; 00187 } 00188 default: 00189 // This can't happen 00190 NEVER_REACHED; 00191 } 00192 00193 parent_coords = parent_coords - random_vector; 00194 daughter_coords = parent_coords + random_vector; 00195 00196 // Set the parent to use this location 00197 ChastePoint<SPACE_DIM> parent_coords_point(parent_coords); 00198 unsigned node_index = this->mrCellPopulation.GetLocationIndexUsingCell(pParentCell); 00199 this->mrCellPopulation.SetNode(node_index, parent_coords_point); 00200 00201 return daughter_coords; 00202 } 00203 else 00204 { 00206 return zero_vector<double>(SPACE_DIM); 00207 } 00208 } 00209 00210 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00211 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::WriteVisualizerSetupFile() 00212 { 00213 if (PetscTools::AmMaster()) 00214 { 00215 for (unsigned i=0; i<this->mForceCollection.size(); i++) 00216 { 00217 // This may cause compilation problems, probably due to AbstractTwoBodyInteractionForce not having two template parameters 00219 00220 boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > p_force = this->mForceCollection[i]; 00221 if (boost::dynamic_pointer_cast<AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM> >(p_force)) 00222 { 00223 double cutoff = (boost::static_pointer_cast<AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM> >(p_force))->GetCutOffLength(); 00224 *(this->mpVizSetupFile) << "Cutoff\t" << cutoff << "\n"; 00225 } 00226 } 00227 00228 // This is a quick and dirty check to see if the mesh is periodic 00229 if (dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&this->mrCellPopulation)) 00230 { 00231 if (dynamic_cast<Cylindrical2dMesh*>(&(dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->rGetMesh()))) 00232 { 00233 *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n"; 00234 } 00235 } 00236 else if (dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&this->mrCellPopulation)) 00237 { 00238 if (dynamic_cast<Cylindrical2dVertexMesh*>(&(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&(this->mrCellPopulation))->rGetMesh()))) 00239 { 00240 *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n"; 00241 } 00242 } 00243 } 00244 } 00245 00246 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00247 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::UpdateNodePositions(const std::vector< c_vector<double, SPACE_DIM> >& rNodeForces) 00248 { 00249 unsigned num_nodes = this->mrCellPopulation.GetNumNodes(); 00250 00251 /* 00252 * Get the previous node positions (these may be needed when applying boundary conditions, 00253 * e.g. in the case of immotile cells) 00254 */ 00255 std::vector<c_vector<double, SPACE_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] = this->mrCellPopulation.GetNode(node_index)->rGetLocation(); 00260 } 00261 00262 // Update node locations 00263 static_cast<AbstractOffLatticeCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->UpdateNodeLocations(rNodeForces, this->mDt); 00264 00265 // Apply any boundary conditions 00266 for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator bcs_iter = mBoundaryConditions.begin(); 00267 bcs_iter != mBoundaryConditions.end(); 00268 ++bcs_iter) 00269 { 00270 (*bcs_iter)->ImposeBoundaryCondition(old_node_locations); 00271 } 00272 00273 // Verify that each boundary condition is now satisfied 00274 for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator bcs_iter = mBoundaryConditions.begin(); 00275 bcs_iter != mBoundaryConditions.end(); 00276 ++bcs_iter) 00277 { 00278 if (!((*bcs_iter)->VerifyBoundaryCondition())) 00279 { 00280 EXCEPTION("The cell population boundary conditions are incompatible."); 00281 } 00282 } 00283 00284 // Write node velocities to file if required 00285 if (mOutputNodeVelocities) 00286 { 00287 OutputFileHandler output_file_handler2(this->mSimulationOutputDirectory+"/", false); 00288 PetscTools::BeginRoundRobin(); 00289 { 00290 if (!PetscTools::AmMaster() || SimulationTime::Instance()->GetTimeStepsElapsed()!=0) 00291 { 00292 mpNodeVelocitiesFile = output_file_handler2.OpenOutputFile("nodevelocities.dat", std::ios::app); 00293 } 00294 00295 if (SimulationTime::Instance()->GetTimeStepsElapsed()%this->mSamplingTimestepMultiple == 0) 00296 { 00297 *mpNodeVelocitiesFile << SimulationTime::Instance()->GetTime() << "\t"; 00298 00299 for (unsigned node_index=0; node_index<num_nodes; node_index++) 00300 { 00301 // We should never encounter deleted nodes due to where this method is called by Solve() 00302 assert(!this->mrCellPopulation.GetNode(node_index)->IsDeleted()); 00303 00304 // Check that results should be written for this node 00305 bool is_real_node = true; 00306 00307 if (dynamic_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&this->mrCellPopulation)) 00308 { 00309 if (static_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->IsGhostNode(node_index)) 00310 { 00311 // If this node is a ghost node then don't record its velocity 00312 is_real_node = false; 00313 } 00314 else 00315 { 00316 // We should never encounter nodes associated with dead cells due to where this method is called by Solve() 00317 assert(!this->mrCellPopulation.GetCellUsingLocationIndex(node_index)->IsDead()); 00318 } 00319 } 00320 00321 // Write node data to file 00322 if (is_real_node) 00323 { 00324 const c_vector<double,SPACE_DIM>& position = this->mrCellPopulation.GetNode(node_index)->rGetLocation(); 00325 double damping_constant = static_cast<AbstractOffLatticeCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->GetDampingConstant(node_index); 00326 c_vector<double, SPACE_DIM> velocity = this->mDt * rNodeForces[node_index] / damping_constant; 00327 00328 *mpNodeVelocitiesFile << node_index << " "; 00329 for (unsigned i=0; i<SPACE_DIM; i++) 00330 { 00331 *mpNodeVelocitiesFile << position[i] << " "; 00332 } 00333 for (unsigned i=0; i<SPACE_DIM; i++) 00334 { 00335 *mpNodeVelocitiesFile << velocity[i] << " "; 00336 } 00337 } 00338 } 00339 *mpNodeVelocitiesFile << "\n"; 00340 } 00341 mpNodeVelocitiesFile->close(); 00342 } 00343 } 00344 } 00345 00346 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00347 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::SetupSolve() 00348 { 00349 if (mOutputNodeVelocities && PetscTools::AmMaster()) 00350 { 00351 OutputFileHandler output_file_handler2(this->mSimulationOutputDirectory+"/", false); 00352 mpNodeVelocitiesFile = output_file_handler2.OpenOutputFile("nodevelocities.dat"); 00353 } 00354 } 00355 00356 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00357 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::UpdateAtEndOfSolve() 00358 { 00359 if (mOutputNodeVelocities) 00360 { 00361 mpNodeVelocitiesFile->close(); 00362 } 00363 } 00364 00365 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00366 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::OutputAdditionalSimulationSetup(out_stream& rParamsFile) 00367 { 00368 // Loop over forces 00369 *rParamsFile << "\n\t<Forces>\n"; 00370 for (typename std::vector<boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > >::iterator iter = mForceCollection.begin(); 00371 iter != mForceCollection.end(); 00372 ++iter) 00373 { 00374 // Output force details 00375 (*iter)->OutputForceInfo(rParamsFile); 00376 } 00377 *rParamsFile << "\t</Forces>\n"; 00378 00379 // Loop over cell population boundary conditions 00380 *rParamsFile << "\n\t<CellPopulationBoundaryConditions>\n"; 00381 for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator iter = mBoundaryConditions.begin(); 00382 iter != mBoundaryConditions.end(); 00383 ++iter) 00384 { 00385 // Output cell Boundary condition details 00386 (*iter)->OutputCellPopulationBoundaryConditionInfo(rParamsFile); 00387 } 00388 *rParamsFile << "\t</CellPopulationBoundaryConditions>\n"; 00389 } 00390 00391 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00392 bool OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::GetOutputNodeVelocities() 00393 { 00394 return mOutputNodeVelocities; 00395 } 00396 00397 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00398 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::SetOutputNodeVelocities(bool outputNodeVelocities) 00399 { 00400 mOutputNodeVelocities = outputNodeVelocities; 00401 } 00402 00403 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00404 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::OutputSimulationParameters(out_stream& rParamsFile) 00405 { 00406 *rParamsFile << "\t\t<OutputNodeVelocities>" << mOutputNodeVelocities << "</OutputNodeVelocities>\n"; 00407 00408 // Call method on direct parent class 00409 AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::OutputSimulationParameters(rParamsFile); 00410 } 00411 00413 // Explicit instantiation 00415 00416 template class OffLatticeSimulation<1,1>; 00417 template class OffLatticeSimulation<1,2>; 00418 template class OffLatticeSimulation<2,2>; 00419 template class OffLatticeSimulation<1,3>; 00420 template class OffLatticeSimulation<2,3>; 00421 template class OffLatticeSimulation<3,3>; 00422 00423 // Serialization for Boost >= 1.36 00424 #include "SerializationExportWrapperForCpp.hpp" 00425 EXPORT_TEMPLATE_CLASS_ALL_DIMS(OffLatticeSimulation)