OffLatticeSimulation.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "OffLatticeSimulation.hpp"
00030 #include "AbstractCentreBasedCellPopulation.hpp"
00031 #include "VertexBasedCellPopulation.hpp"
00032 
00033 #include "Cylindrical2dMesh.hpp"
00034 #include "Cylindrical2dVertexMesh.hpp"
00035 
00036 #include "AbstractTwoBodyInteractionForce.hpp"
00037 #include "CellBasedEventHandler.hpp"
00038 #include "LogFile.hpp"
00039 #include "Version.hpp"
00040 #include "ExecutableSupport.hpp"
00041 
00042 template<unsigned DIM>
00043 OffLatticeSimulation<DIM>::OffLatticeSimulation(AbstractCellPopulation<DIM>& rCellPopulation,
00044                                                 bool deleteCellPopulationInDestructor,
00045                                                 bool initialiseCells)
00046     : AbstractCellBasedSimulation<DIM>(rCellPopulation, deleteCellPopulationInDestructor, initialiseCells),
00047       mOutputNodeVelocities(false)
00048 {
00049     if (!dynamic_cast<AbstractOffLatticeCellPopulation<DIM>*>(&rCellPopulation))
00050     {
00051         EXCEPTION("OffLatticeSimulations require a subclass of AbstractOffLatticeCellPopulation.");
00052     }
00053 
00054     // Different time steps are used for cell-centre and vertex-based simulations
00055     if (dynamic_cast<AbstractCentreBasedCellPopulation<DIM>*>(&rCellPopulation))
00056     {
00057         this->mDt = 1.0/120.0; // 30 seconds
00058     }
00059     else
00060     {
00061         assert (dynamic_cast<VertexBasedCellPopulation<DIM>*>(&rCellPopulation));
00062         this->mDt = 0.002; // smaller time step required for convergence/stability
00063     }
00064 }
00065 
00066 template<unsigned DIM>
00067 void OffLatticeSimulation<DIM>::AddForce(boost::shared_ptr<AbstractForce<DIM> > pForce)
00068 {
00069     mForceCollection.push_back(pForce);
00070 }
00071 
00072 template<unsigned DIM>
00073 void OffLatticeSimulation<DIM>::AddCellPopulationBoundaryCondition(boost::shared_ptr<AbstractCellPopulationBoundaryCondition<DIM> > pBoundaryCondition)
00074 {
00075     mBoundaryConditions.push_back(pBoundaryCondition);
00076 }
00077 
00078 template<unsigned DIM>
00079 void OffLatticeSimulation<DIM>::UpdateCellLocationsAndTopology()
00080 {
00081     // Calculate forces
00082     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::FORCE);
00083 
00084     // Initialise a vector of forces on node
00085     std::vector<c_vector<double, DIM> > forces(this->mrCellPopulation.GetNumNodes(), zero_vector<double>(DIM));
00086 
00088 //    // First set all the forces to zero
00089 //    for (unsigned i=0; i<forces.size(); i++)
00090 //    {
00091 //         forces[i].clear();
00092 //    }
00093 //
00094 //    // Then resize the std::vector if the number of cells has increased or decreased
00095 //    // (note this should be done after the above zeroing)
00096 //    unsigned num_nodes = mrCellPopulation.GetNumNodes();
00097 //    if (num_nodes != forces.size())
00098 //    {
00099 //        forces.resize(num_nodes, zero_vector<double>(DIM));
00100 //    }
00101 
00102     // Now add force contributions from each AbstractForce
00103     for (typename std::vector<boost::shared_ptr<AbstractForce<DIM> > >::iterator iter = mForceCollection.begin();
00104          iter != mForceCollection.end();
00105          ++iter)
00106     {
00107         (*iter)->AddForceContribution(forces, this->mrCellPopulation);
00108     }
00109     CellBasedEventHandler::EndEvent(CellBasedEventHandler::FORCE);
00110 
00111     // Update node positions
00112     CellBasedEventHandler::BeginEvent(CellBasedEventHandler::POSITION);
00113     UpdateNodePositions(forces);
00114     CellBasedEventHandler::EndEvent(CellBasedEventHandler::POSITION);
00115 }
00116 
00117 template<unsigned DIM>
00118 c_vector<double, DIM> OffLatticeSimulation<DIM>::CalculateCellDivisionVector(CellPtr pParentCell)
00119 {
00125     if (dynamic_cast<AbstractCentreBasedCellPopulation<DIM>*>(&(this->mrCellPopulation)))
00126     {
00127         // Location of parent and daughter cells
00128         c_vector<double, DIM> parent_coords = this->mrCellPopulation.GetLocationOfCellCentre(pParentCell);
00129         c_vector<double, DIM> daughter_coords;
00130 
00131         // Get separation parameter
00132         double separation = static_cast<AbstractCentreBasedCellPopulation<DIM>*>(&(this->mrCellPopulation))->GetMeinekeDivisionSeparation();
00133 
00134         // Make a random direction vector of the required length
00135         c_vector<double, DIM> random_vector;
00136 
00137         /*
00138          * Pick a random direction and move the parent cell backwards by 0.5*separation
00139          * in that direction and return the position of the daughter cell 0.5*separation
00140          * forwards in that direction.
00141          */
00142         switch (DIM)
00143         {
00144             case 1:
00145             {
00146                 double random_direction = -1.0 + 2.0*(RandomNumberGenerator::Instance()->ranf() < 0.5);
00147 
00148                 random_vector(0) = 0.5*separation*random_direction;
00149                 break;
00150             }
00151             case 2:
00152             {
00153                 double random_angle = 2.0*M_PI*RandomNumberGenerator::Instance()->ranf();
00154 
00155                 random_vector(0) = 0.5*separation*cos(random_angle);
00156                 random_vector(1) = 0.5*separation*sin(random_angle);
00157                 break;
00158             }
00159             case 3:
00160             {
00161                 double random_zenith_angle = M_PI*RandomNumberGenerator::Instance()->ranf(); // phi
00162                 double random_azimuth_angle = 2*M_PI*RandomNumberGenerator::Instance()->ranf(); // theta
00163 
00164                 random_vector(0) = 0.5*separation*cos(random_azimuth_angle)*sin(random_zenith_angle);
00165                 random_vector(1) = 0.5*separation*sin(random_azimuth_angle)*sin(random_zenith_angle);
00166                 random_vector(2) = 0.5*separation*cos(random_zenith_angle);
00167                 break;
00168             }
00169             default:
00170                 // This can't happen
00171                 NEVER_REACHED;
00172         }
00173 
00174         parent_coords = parent_coords - random_vector;
00175         daughter_coords = parent_coords + random_vector;
00176 
00177         // Set the parent to use this location
00178         ChastePoint<DIM> parent_coords_point(parent_coords);
00179         unsigned node_index = this->mrCellPopulation.GetLocationIndexUsingCell(pParentCell);
00180         this->mrCellPopulation.SetNode(node_index, parent_coords_point);
00181 
00182         return daughter_coords;
00183     }
00184     else
00185     {
00187         return zero_vector<double>(DIM);
00188     }
00189 }
00190 
00191 template<unsigned DIM>
00192 void OffLatticeSimulation<DIM>::WriteVisualizerSetupFile()
00193 {
00194     for (unsigned i=0; i<this->mForceCollection.size(); i++)
00195     {
00196         boost::shared_ptr<AbstractForce<DIM> > p_force = this->mForceCollection[i];
00197         if (boost::dynamic_pointer_cast<AbstractTwoBodyInteractionForce<DIM> >(p_force))
00198         {
00199             double cutoff = (boost::static_pointer_cast<AbstractTwoBodyInteractionForce<DIM> >(p_force))->GetCutOffLength();
00200             *(this->mpVizSetupFile) << "Cutoff\t" << cutoff << "\n";
00201         }
00202     }
00203 
00204     // This is a quick and dirty check to see if the mesh is periodic
00205     if (dynamic_cast<MeshBasedCellPopulation<DIM>*>(&this->mrCellPopulation))
00206     {
00207        if (dynamic_cast<Cylindrical2dMesh*>(&(dynamic_cast<MeshBasedCellPopulation<DIM>*>(&(this->mrCellPopulation))->rGetMesh())))
00208        {
00209            *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n";
00210        }
00211     }
00212     else if (dynamic_cast<VertexBasedCellPopulation<DIM>*>(&this->mrCellPopulation))
00213     {
00214        if (dynamic_cast<Cylindrical2dVertexMesh*>(&(dynamic_cast<VertexBasedCellPopulation<DIM>*>(&(this->mrCellPopulation))->rGetMesh())))
00215        {
00216            *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n";
00217        }
00218     }
00219 
00220 }
00221 
00222 template<unsigned DIM>
00223 void OffLatticeSimulation<DIM>::UpdateNodePositions(const std::vector< c_vector<double, DIM> >& rNodeForces)
00224 {
00225     unsigned num_nodes = this->mrCellPopulation.GetNumNodes();
00226 
00227     /*
00228      * Get the previous node positions (these may be needed when applying boundary conditions,
00229      * e.g. in the case of immotile cells)
00230      */
00231     std::vector<c_vector<double, DIM> > old_node_locations;
00232     old_node_locations.reserve(num_nodes);
00233     for (unsigned node_index=0; node_index<num_nodes; node_index++)
00234     {
00235         old_node_locations[node_index] = this->mrCellPopulation.GetNode(node_index)->rGetLocation();
00236     }
00237 
00238     // Update node locations
00239     static_cast<AbstractOffLatticeCellPopulation<DIM>*>(&(this->mrCellPopulation))->UpdateNodeLocations(rNodeForces, this->mDt);
00240 
00241     // Apply any boundary conditions
00242     for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<DIM> > >::iterator bcs_iter = mBoundaryConditions.begin();
00243          bcs_iter != mBoundaryConditions.end();
00244          ++bcs_iter)
00245     {
00246         (*bcs_iter)->ImposeBoundaryCondition(old_node_locations);
00247     }
00248 
00249     // Verify that each boundary condition is now satisfied
00250     for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<DIM> > >::iterator bcs_iter = mBoundaryConditions.begin();
00251          bcs_iter != mBoundaryConditions.end();
00252          ++bcs_iter)
00253     {
00254         if (!((*bcs_iter)->VerifyBoundaryCondition()))
00255         {
00256             EXCEPTION("The cell population boundary conditions are incompatible.");
00257         }
00258     }
00259 
00260     // Write node velocities to file if required
00261     if (mOutputNodeVelocities)
00262     {
00263         if (SimulationTime::Instance()->GetTimeStepsElapsed()%this->mSamplingTimestepMultiple == 0)
00264         {
00265             *mpNodeVelocitiesFile << SimulationTime::Instance()->GetTime() << "\t";
00266             for (unsigned node_index=0; node_index<num_nodes; node_index++)
00267             {
00268                 // We should never encounter deleted nodes due to where this method is called by Solve()
00269                 assert(!this->mrCellPopulation.GetNode(node_index)->IsDeleted());
00270 
00271                 // Check that results should be written for this node
00272                 bool is_real_node = true;
00273 
00274                 if (dynamic_cast<AbstractCentreBasedCellPopulation<DIM>*>(&this->mrCellPopulation))
00275                 {
00276                     if (static_cast<AbstractCentreBasedCellPopulation<DIM>*>(&(this->mrCellPopulation))->IsGhostNode(node_index))
00277                     {
00278                         // If this node is a ghost node then don't record its velocity
00279                         is_real_node = false;
00280                     }
00281                     else
00282                     {
00283                         // We should never encounter nodes associated with dead cells due to where this method is called by Solve()
00284                         assert(!this->mrCellPopulation.GetCellUsingLocationIndex(node_index)->IsDead());
00285                     }
00286                 }
00287 
00288                 // Write node data to file
00289                 if (is_real_node)
00290                 {
00291                     const c_vector<double,DIM>& position = this->mrCellPopulation.GetNode(node_index)->rGetLocation();
00292                     double damping_constant = static_cast<AbstractOffLatticeCellPopulation<DIM>*>(&(this->mrCellPopulation))->GetDampingConstant(node_index);
00293                     c_vector<double, DIM> velocity = this->mDt * rNodeForces[node_index] / damping_constant;
00294 
00295                     *mpNodeVelocitiesFile << node_index  << " ";
00296                     for (unsigned i=0; i<DIM; i++)
00297                     {
00298                         *mpNodeVelocitiesFile << position[i] << " ";
00299                     }
00300                     for (unsigned i=0; i<DIM; i++)
00301                     {
00302                         *mpNodeVelocitiesFile << velocity[i] << " ";
00303                     }
00304                 }
00305             }
00306             *mpNodeVelocitiesFile << "\n";
00307         }
00308     }
00309 }
00310 
00311 template<unsigned DIM>
00312 void OffLatticeSimulation<DIM>::SetupSolve()
00313 {
00314     // First call method on base class
00315     AbstractCellBasedSimulation<DIM>::SetupSolve();
00316 
00317     if (mOutputNodeVelocities)
00318     {
00319         OutputFileHandler output_file_handler2(this->mSimulationOutputDirectory+"/", false);
00320         mpNodeVelocitiesFile = output_file_handler2.OpenOutputFile("nodevelocities.dat");
00321     }
00322 }
00323 
00324 template<unsigned DIM>
00325 void OffLatticeSimulation<DIM>::AfterSolve()
00326 {
00327     // First call method on base class
00328     AbstractCellBasedSimulation<DIM>::AfterSolve();
00329 
00330     if (mOutputNodeVelocities)
00331     {
00332         mpNodeVelocitiesFile->close();
00333     }
00334 }
00335 
00336 template<unsigned DIM>
00337 void OffLatticeSimulation<DIM>::OutputAdditionalSimulationSetup(out_stream& rParamsFile)
00338 {
00339     // Loop over forces
00340     *rParamsFile << "\n\t<Forces>\n";
00341     for (typename std::vector<boost::shared_ptr<AbstractForce<DIM> > >::iterator iter = mForceCollection.begin();
00342          iter != mForceCollection.end();
00343          ++iter)
00344     {
00345         // Output force details
00346         (*iter)->OutputForceInfo(rParamsFile);
00347     }
00348     *rParamsFile << "\t</Forces>\n";
00349 
00350     // Loop over cell population boundary conditions
00351     *rParamsFile << "\n\t<CellPopulationBoundaryConditions>\n";
00352     for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<DIM> > >::iterator iter = mBoundaryConditions.begin();
00353          iter != mBoundaryConditions.end();
00354          ++iter)
00355     {
00356         // Output cell Boundary condition details
00357         (*iter)->OutputCellPopulationBoundaryConditionInfo(rParamsFile);
00358     }
00359     *rParamsFile << "\t</CellPopulationBoundaryConditions>\n";
00360 }
00361 
00362 template<unsigned DIM>
00363 bool OffLatticeSimulation<DIM>::GetOutputNodeVelocities()
00364 {
00365     return mOutputNodeVelocities;
00366 }
00367 
00368 template<unsigned DIM>
00369 void OffLatticeSimulation<DIM>::SetOutputNodeVelocities(bool outputNodeVelocities)
00370 {
00371     mOutputNodeVelocities = outputNodeVelocities;
00372 }
00373 
00374 template<unsigned DIM>
00375 void OffLatticeSimulation<DIM>::OutputSimulationParameters(out_stream& rParamsFile)
00376 {
00377     *rParamsFile << "\t\t<OutputNodeVelocities>" << mOutputNodeVelocities << "</OutputNodeVelocities>\n";
00378 
00379     // Call method on direct parent class
00380     AbstractCellBasedSimulation<DIM>::OutputSimulationParameters(rParamsFile);
00381 }
00382 
00384 // Explicit instantiation
00386 
00387 template class OffLatticeSimulation<1>;
00388 template class OffLatticeSimulation<2>;
00389 template class OffLatticeSimulation<3>;
00390 
00391 // Serialization for Boost >= 1.36
00392 #include "SerializationExportWrapperForCpp.hpp"
00393 EXPORT_TEMPLATE_CLASS_SAME_DIMS(OffLatticeSimulation)
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3