OffLatticeSimulation.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 #include "T2SwapCellKiller.hpp"
00040 #include "AbstractVertexBasedDivisionRule.hpp"
00041 #include "Cylindrical2dMesh.hpp"
00042 #include "Cylindrical2dVertexMesh.hpp"
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 {
00055     if (!dynamic_cast<AbstractOffLatticeCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation))
00056     {
00057         EXCEPTION("OffLatticeSimulations require a subclass of AbstractOffLatticeCellPopulation.");
00058     }
00059 
00060     // Different time steps are used for cell-centre and vertex-based simulations
00061     if (dynamic_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation))
00062     {
00063         this->mDt = 1.0/120.0; // 30 seconds
00064     }
00065     else
00066     {
00067         assert(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation));
00068         this->mDt = 0.002; // smaller time step required for convergence/stability
00069 
00070         // For VertexBasedCellPopulations we automatically add a T2SwapCellKiller. In order to inhibit T2 swaps
00071         // the user needs to set the threshold for T2 swaps in the mesh to 0.
00072         VertexBasedCellPopulation<SPACE_DIM>* p_vertex_based_cell_population = dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation);
00073         MAKE_PTR_ARGS(T2SwapCellKiller<SPACE_DIM>, T2_swap_cell_killer, (p_vertex_based_cell_population));
00074         this->AddCellKiller(T2_swap_cell_killer);
00075     }
00076 }
00077 
00078 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00079 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::AddForce(boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > pForce)
00080 {
00081     mForceCollection.push_back(pForce);
00082 }
00083 
00084 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00085 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::RemoveAllForces()
00086 {
00087     mForceCollection.clear();
00088 }
00089 
00090 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00091 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::AddCellPopulationBoundaryCondition(boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > pBoundaryCondition)
00092 {
00093     mBoundaryConditions.push_back(pBoundaryCondition);
00094 }
00095 
00096 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00097 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::RemoveAllCellPopulationBoundaryConditions()
00098 {
00099     mBoundaryConditions.clear();
00100 }
00101 
00102 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00103 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::UpdateCellLocationsAndTopology()
00104 {
00105     // Calculate forces
00106     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::FORCE);
00107 
00108     // Clear all forces
00109     for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrCellPopulation.rGetMesh().GetNodeIteratorBegin();
00110          node_iter != this->mrCellPopulation.rGetMesh().GetNodeIteratorEnd();
00111          ++node_iter)
00112     {
00113         node_iter->ClearAppliedForce();
00114     }
00115 
00116     // Now add force contributions from each AbstractForce
00117     for (typename std::vector<boost::shared_ptr<AbstractForce<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mForceCollection.begin();
00118          iter != mForceCollection.end();
00119          ++iter)
00120     {
00121         (*iter)->AddForceContribution(this->mrCellPopulation);
00122     }
00123     CellBasedEventHandler::EndEvent(CellBasedEventHandler::FORCE);
00124 
00125     // Update node positions
00126     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::POSITION);
00127     UpdateNodePositions();
00128     CellBasedEventHandler::EndEvent(CellBasedEventHandler::POSITION);
00129 }
00130 
00131 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00132 c_vector<double, SPACE_DIM> OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::CalculateCellDivisionVector(CellPtr pParentCell)
00133 {
00139     // If it is not vertex based...
00140     if (dynamic_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation)))
00141     {
00142         // Location of parent and daughter cells
00143         c_vector<double, SPACE_DIM> parent_coords = this->mrCellPopulation.GetLocationOfCellCentre(pParentCell);
00144         c_vector<double, SPACE_DIM> daughter_coords;
00145 
00146         // Get separation parameter
00147         double separation = static_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->GetMeinekeDivisionSeparation();
00148 
00149         // Make a random direction vector of the required length
00150         c_vector<double, SPACE_DIM> random_vector;
00151 
00152         /*
00153          * Pick a random direction and move the parent cell backwards by 0.5*separation
00154          * in that direction and return the position of the daughter cell 0.5*separation
00155          * forwards in that direction.
00156          */
00157         switch (SPACE_DIM)
00158         {
00159             case 1:
00160             {
00161                 double random_direction = -1.0 + 2.0*(RandomNumberGenerator::Instance()->ranf() < 0.5);
00162 
00163                 random_vector(0) = 0.5*separation*random_direction;
00164                 break;
00165             }
00166             case 2:
00167             {
00168                 double random_angle = 2.0*M_PI*RandomNumberGenerator::Instance()->ranf();
00169 
00170                 random_vector(0) = 0.5*separation*cos(random_angle);
00171                 random_vector(1) = 0.5*separation*sin(random_angle);
00172                 break;
00173             }
00174             case 3:
00175             {
00176                 /*
00177                  * Note that to pick a random point on the surface of a sphere, it is incorrect
00178                  * to select spherical coordinates from uniform distributions on [0, 2*pi) and
00179                  * [0, pi) respectively, since points picked in this way will be 'bunched' near
00180                  * the poles. See #2230.
00181                  */
00182                 double u = RandomNumberGenerator::Instance()->ranf();
00183                 double v = RandomNumberGenerator::Instance()->ranf();
00184 
00185                 double random_azimuth_angle = 2*M_PI*u;
00186                 double random_zenith_angle = std::acos(2*v - 1);
00187 
00188                 random_vector(0) = 0.5*separation*cos(random_azimuth_angle)*sin(random_zenith_angle);
00189                 random_vector(1) = 0.5*separation*sin(random_azimuth_angle)*sin(random_zenith_angle);
00190                 random_vector(2) = 0.5*separation*cos(random_zenith_angle);
00191                 break;
00192             }
00193             default:
00194                 // This can't happen
00195                 NEVER_REACHED;
00196         }
00197 
00198         parent_coords = parent_coords - random_vector;
00199         daughter_coords = parent_coords + random_vector;
00200 
00201         // Set the parent to use this location
00202         ChastePoint<SPACE_DIM> parent_coords_point(parent_coords);
00203         unsigned node_index = this->mrCellPopulation.GetLocationIndexUsingCell(pParentCell);
00204         this->mrCellPopulation.SetNode(node_index, parent_coords_point);
00205 
00206         return daughter_coords;
00207     }
00208     else
00209     {
00210         // Check this is a Vertex based cell population (in case new types are added later!).
00211         assert(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&(this->mrCellPopulation)));
00212 
00213         VertexBasedCellPopulation<SPACE_DIM>* p_vertex_population = dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&(this->mrCellPopulation));
00214         boost::shared_ptr<AbstractVertexBasedDivisionRule<SPACE_DIM> > p_division_rule = p_vertex_population->GetVertexBasedDivisionRule();
00215 
00216         return p_division_rule->CalculateCellDivisionVector(pParentCell, *p_vertex_population);
00217     }
00218 }
00219 
00220 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00221 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::WriteVisualizerSetupFile()
00222 {
00223     if (PetscTools::AmMaster())
00224     {
00225         for (unsigned i=0; i<this->mForceCollection.size(); i++)
00226         {
00227             // This may cause compilation problems, probably due to AbstractTwoBodyInteractionForce not having two template parameters
00229 
00230             boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > p_force = this->mForceCollection[i];
00231             if (boost::dynamic_pointer_cast<AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM> >(p_force))
00232             {
00233                 double cutoff = (boost::static_pointer_cast<AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM> >(p_force))->GetCutOffLength();
00234                 *(this->mpVizSetupFile) << "Cutoff\t" << cutoff << "\n";
00235             }
00236         }
00237 
00238         // This is a quick and dirty check to see if the mesh is periodic
00239         if (dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&this->mrCellPopulation))
00240         {
00241            if (dynamic_cast<Cylindrical2dMesh*>(&(dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->rGetMesh())))
00242            {
00243                *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n";
00244            }
00245         }
00246         else if (dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&this->mrCellPopulation))
00247         {
00248            if (dynamic_cast<Cylindrical2dVertexMesh*>(&(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&(this->mrCellPopulation))->rGetMesh())))
00249            {
00250                *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n";
00251            }
00252         }
00253     }
00254 }
00255 
00256 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00257 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::UpdateNodePositions()
00258 {
00259     /*
00260      * Get the previous node positions (these may be needed when applying boundary conditions,
00261      * e.g. in the case of immotile cells)
00262      */
00263     std::map<Node<SPACE_DIM>*, c_vector<double, SPACE_DIM> > old_node_locations;
00264     for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrCellPopulation.rGetMesh().GetNodeIteratorBegin();
00265          node_iter != this->mrCellPopulation.rGetMesh().GetNodeIteratorEnd();
00266          ++node_iter)
00267     {
00268         old_node_locations[&(*node_iter)] = (node_iter)->rGetLocation();
00269     }
00270 
00271     // Update node locations
00272     static_cast<AbstractOffLatticeCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->UpdateNodeLocations(this->mDt);
00273 
00274     // Apply any boundary conditions
00275     for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator bcs_iter = mBoundaryConditions.begin();
00276          bcs_iter != mBoundaryConditions.end();
00277          ++bcs_iter)
00278     {
00279         (*bcs_iter)->ImposeBoundaryCondition(old_node_locations);
00280     }
00281 
00282     // Verify that each boundary condition is now satisfied
00283     for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator bcs_iter = mBoundaryConditions.begin();
00284          bcs_iter != mBoundaryConditions.end();
00285          ++bcs_iter)
00286     {
00287         if (!((*bcs_iter)->VerifyBoundaryCondition()))
00288         {
00289             EXCEPTION("The cell population boundary conditions are incompatible.");
00290         }
00291     }
00292 }
00293 
00294 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00295 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::SetupSolve()
00296 {
00297     // Clear all forces
00298     for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrCellPopulation.rGetMesh().GetNodeIteratorBegin();
00299          node_iter != this->mrCellPopulation.rGetMesh().GetNodeIteratorEnd();
00300          ++node_iter)
00301     {
00302         node_iter->ClearAppliedForce();
00303     }
00304 }
00305 
00306 
00307 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00308 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::OutputAdditionalSimulationSetup(out_stream& rParamsFile)
00309 {
00310     // Loop over forces
00311     *rParamsFile << "\n\t<Forces>\n";
00312     for (typename std::vector<boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > >::iterator iter = mForceCollection.begin();
00313          iter != mForceCollection.end();
00314          ++iter)
00315     {
00316         // Output force details
00317         (*iter)->OutputForceInfo(rParamsFile);
00318     }
00319     *rParamsFile << "\t</Forces>\n";
00320 
00321     // Loop over cell population boundary conditions
00322     *rParamsFile << "\n\t<CellPopulationBoundaryConditions>\n";
00323     for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator iter = mBoundaryConditions.begin();
00324          iter != mBoundaryConditions.end();
00325          ++iter)
00326     {
00327         // Output cell Boundary condition details
00328         (*iter)->OutputCellPopulationBoundaryConditionInfo(rParamsFile);
00329     }
00330     *rParamsFile << "\t</CellPopulationBoundaryConditions>\n";
00331 }
00332 
00333 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00334 void OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::OutputSimulationParameters(out_stream& rParamsFile)
00335 {
00336     // Call method on direct parent class
00337     AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>::OutputSimulationParameters(rParamsFile);
00338 }
00339 
00341 // Explicit instantiation
00343 
00344 template class OffLatticeSimulation<1,1>;
00345 template class OffLatticeSimulation<1,2>;
00346 template class OffLatticeSimulation<2,2>;
00347 template class OffLatticeSimulation<1,3>;
00348 template class OffLatticeSimulation<2,3>;
00349 template class OffLatticeSimulation<3,3>;
00350 
00351 // Serialization for Boost >= 1.36
00352 #include "SerializationExportWrapperForCpp.hpp"
00353 EXPORT_TEMPLATE_CLASS_ALL_DIMS(OffLatticeSimulation)

Generated by  doxygen 1.6.2