Chaste Release::3.1
OffLatticeSimulation.cpp
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)