Chaste Release::3.1
GeneralisedLinearSpringForce.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 "GeneralisedLinearSpringForce.hpp"
00037 
00038 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00039 GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::GeneralisedLinearSpringForce()
00040    : AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM>(),
00041      mMeinekeSpringStiffness(15.0),        // denoted by mu in Meineke et al, 2001 (doi:10.1046/j.0960-7722.2001.00216.x)
00042      mMeinekeDivisionRestingSpringLength(0.5),
00043      mMeinekeSpringGrowthDuration(1.0)
00044 {
00045     if (SPACE_DIM == 1)
00046     {
00047         mMeinekeSpringStiffness = 30.0;
00048     }
00049 }
00050 
00051 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00052 double GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::VariableSpringConstantMultiplicationFactor(unsigned nodeAGlobalIndex,
00053                                                                                      unsigned nodeBGlobalIndex,
00054                                                                                      AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation,
00055                                                                                      bool isCloserThanRestLength)
00056 {
00057     return 1.0;
00058 }
00059 
00060 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00061 GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::~GeneralisedLinearSpringForce()
00062 {
00063 }
00064 
00065 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00066 c_vector<double, SPACE_DIM> GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::CalculateForceBetweenNodes(unsigned nodeAGlobalIndex,
00067                                                                                     unsigned nodeBGlobalIndex,
00068                                                                                     AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation)
00069 {
00070     // We should only ever calculate the force between two distinct nodes
00071     assert(nodeAGlobalIndex != nodeBGlobalIndex);
00072 
00073     // Get the node locations
00074     c_vector<double, SPACE_DIM> node_a_location = rCellPopulation.GetNode(nodeAGlobalIndex)->rGetLocation();
00075     c_vector<double, SPACE_DIM> node_b_location = rCellPopulation.GetNode(nodeBGlobalIndex)->rGetLocation();
00076 
00077     // Get the node radii for a NodeBasedCellPopulation
00078     double node_a_radius=0.0;
00079     double node_b_radius=0.0;
00080 
00081     if (dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation))
00082     {
00083         node_a_radius = dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)->rGetMesh().GetCellRadius(nodeAGlobalIndex);
00084         node_b_radius = dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)->rGetMesh().GetCellRadius(nodeBGlobalIndex);
00085     }
00086 
00087     // Get the unit vector parallel to the line joining the two nodes
00088     c_vector<double, SPACE_DIM> unit_difference;
00089     if (dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation))
00090     {
00091         /*
00092          * We use the mesh method GetVectorFromAtoB() to compute the direction of the
00093          * unit vector along the line joining the two nodes, rather than simply subtract
00094          * their positions, because this method can be overloaded (e.g. to enforce a
00095          * periodic boundary in Cylindrical2dMesh).
00096          */
00097         unit_difference = (static_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation))->rGetMesh().GetVectorFromAtoB(node_a_location, node_b_location);
00098     }
00099     else
00100     {
00101         unit_difference = node_b_location - node_a_location;
00102     }
00103 
00104     // Calculate the distance between the two nodes
00105     double distance_between_nodes = norm_2(unit_difference);
00106     assert(distance_between_nodes > 0);
00107     assert(!std::isnan(distance_between_nodes));
00108 
00109     unit_difference /= distance_between_nodes;
00110 
00111     /*
00112      * If mUseCutOffLength has been set, then there is zero force between
00113      * two nodes located a distance apart greater than mMechanicsCutOffLength in AbstractTwoBodyInteractionForce.
00114      */
00115     if (this->mUseCutOffLength)
00116     {
00117         if (distance_between_nodes >= this->GetCutOffLength())
00118         {
00119             return zero_vector<double>(SPACE_DIM); // c_vector<double,SPACE_DIM>() is not guaranteed to be fresh memory
00120         }
00121     }
00122 
00123     /*
00124      * Calculate the rest length of the spring connecting the two nodes with a default
00125      * value of 1.0.
00126      */
00127     double rest_length_final = 1.0;
00128 
00129     if (dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation))
00130     {
00131         rest_length_final = static_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)->GetRestLength(nodeAGlobalIndex, nodeBGlobalIndex);
00132     }
00133     else if (dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation))
00134     {
00135         assert(node_a_radius > 0 && node_b_radius > 0);
00136         rest_length_final = node_a_radius+node_b_radius;
00137     }
00138 
00139     double rest_length = rest_length_final;
00140 
00141     CellPtr p_cell_A = rCellPopulation.GetCellUsingLocationIndex(nodeAGlobalIndex);
00142     CellPtr p_cell_B = rCellPopulation.GetCellUsingLocationIndex(nodeBGlobalIndex);
00143 
00144     double ageA = p_cell_A->GetAge();
00145     double ageB = p_cell_B->GetAge();
00146 
00147     assert(!std::isnan(ageA));
00148     assert(!std::isnan(ageB));
00149 
00150     /*
00151      * If the cells are both newly divided, then the rest length of the spring
00152      * connecting them grows linearly with time, until 1 hour after division.
00153      */
00154     if (ageA < mMeinekeSpringGrowthDuration && ageB < mMeinekeSpringGrowthDuration)
00155     {
00156         AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>* p_static_cast_cell_population = static_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation);
00157 
00158         std::pair<CellPtr,CellPtr> cell_pair = p_static_cast_cell_population->CreateCellPair(p_cell_A, p_cell_B);
00159 
00160         if (p_static_cast_cell_population->IsMarkedSpring(cell_pair))
00161         {
00162             // Spring rest length increases from a small value to the normal rest length over 1 hour
00163             double lambda = mMeinekeDivisionRestingSpringLength;
00164             rest_length = lambda + (rest_length_final - lambda) * ageA/mMeinekeSpringGrowthDuration;
00165         }
00166         if (ageA + SimulationTime::Instance()->GetTimeStep() >= mMeinekeSpringGrowthDuration)
00167         {
00168             // This spring is about to go out of scope
00169             p_static_cast_cell_population->UnmarkSpring(cell_pair);
00170         }
00171     }
00172 
00173     /*
00174      * For apoptosis, progressively reduce the radius of the cell
00175      */
00176     double a_rest_length = rest_length*0.5;
00177     double b_rest_length = a_rest_length;
00178 
00179     if (dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation))
00180     {
00181         assert(node_a_radius > 0 && node_b_radius > 0);
00182         a_rest_length = (node_a_radius/(node_a_radius+node_b_radius))*rest_length;
00183         b_rest_length = (node_b_radius/(node_a_radius+node_b_radius))*rest_length;
00184     }
00185 
00186     /*
00187      * If either of the cells has begun apoptosis, then the length of the spring
00188      * connecting them decreases linearly with time.
00189      */
00190     if (p_cell_A->HasApoptosisBegun())
00191     {
00192         double time_until_death_a = p_cell_A->GetTimeUntilDeath();
00193         a_rest_length = a_rest_length * time_until_death_a / p_cell_A->GetApoptosisTime();
00194     }
00195     if (p_cell_B->HasApoptosisBegun())
00196     {
00197         double time_until_death_b = p_cell_B->GetTimeUntilDeath();
00198         b_rest_length = b_rest_length * time_until_death_b / p_cell_B->GetApoptosisTime();
00199     }
00200 
00201     rest_length = a_rest_length + b_rest_length;
00202     //assert(rest_length <= 1.0+1e-12); ///\todo #1884 Magic number: would "<= 1.0" do?
00203 
00204 
00205     // Although in this class the 'spring constant' is a constant parameter, in
00206     // subclasses it can depend on properties of each of the cells
00207     double overlap = distance_between_nodes - rest_length;
00208     bool is_closer_than_rest_length = (overlap <= 0);
00209     double multiplication_factor = VariableSpringConstantMultiplicationFactor(nodeAGlobalIndex, nodeBGlobalIndex, rCellPopulation, is_closer_than_rest_length);
00210     double spring_stiffness = mMeinekeSpringStiffness;
00211 
00212     if (dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation))
00213     {
00214         return multiplication_factor * spring_stiffness * unit_difference * overlap;
00215     }
00216     else
00217     {
00218         // A reasonably stable simple force law
00219         if (is_closer_than_rest_length) //overlap is negative
00220         {
00221             //log(x+1) is undefined for x<=-1
00222             assert(overlap > -rest_length_final);
00223             c_vector<double, SPACE_DIM> temp = spring_stiffness * unit_difference * rest_length_final* log(1.0 + overlap/rest_length_final);
00224             return temp;
00225         }
00226         else
00227         {
00228             double alpha = 5.0;
00229             c_vector<double, SPACE_DIM> temp = spring_stiffness * unit_difference * overlap * exp(-alpha * overlap/rest_length_final);
00230             return temp;
00231         }
00232     }
00233 }
00234 
00235 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00236 double GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::GetMeinekeSpringStiffness()
00237 {
00238     return mMeinekeSpringStiffness;
00239 }
00240 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00241 double GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::GetMeinekeDivisionRestingSpringLength()
00242 {
00243     return mMeinekeDivisionRestingSpringLength;
00244 }
00245 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00246 double GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::GetMeinekeSpringGrowthDuration()
00247 {
00248     return mMeinekeSpringGrowthDuration;
00249 }
00250 
00251 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00252 void GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::SetMeinekeSpringStiffness(double springStiffness)
00253 {
00254     assert(springStiffness > 0.0);
00255     mMeinekeSpringStiffness = springStiffness;
00256 }
00257 
00258 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00259 void GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::SetMeinekeDivisionRestingSpringLength(double divisionRestingSpringLength)
00260 {
00261     assert(divisionRestingSpringLength <= 1.0);
00262     assert(divisionRestingSpringLength >= 0.0);
00263 
00264     mMeinekeDivisionRestingSpringLength = divisionRestingSpringLength;
00265 }
00266 
00267 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00268 void GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::SetMeinekeSpringGrowthDuration(double springGrowthDuration)
00269 {
00270     assert(springGrowthDuration >= 0.0);
00271 
00272     mMeinekeSpringGrowthDuration = springGrowthDuration;
00273 }
00274 
00275 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00276 void GeneralisedLinearSpringForce<ELEMENT_DIM,SPACE_DIM>::OutputForceParameters(out_stream& rParamsFile)
00277 {
00278     *rParamsFile << "\t\t\t<MeinekeSpringStiffness>" << mMeinekeSpringStiffness << "</MeinekeSpringStiffness>\n";
00279     *rParamsFile << "\t\t\t<MeinekeDivisionRestingSpringLength>" << mMeinekeDivisionRestingSpringLength << "</MeinekeDivisionRestingSpringLength>\n";
00280     *rParamsFile << "\t\t\t<MeinekeSpringGrowthDuration>" << mMeinekeSpringGrowthDuration << "</MeinekeSpringGrowthDuration>\n";
00281 
00282     // Call method on direct parent class
00283     AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM>::OutputForceParameters(rParamsFile);
00284 }
00285 
00287 // Explicit instantiation
00289 
00290 template class GeneralisedLinearSpringForce<1,1>;
00291 template class GeneralisedLinearSpringForce<1,2>;
00292 template class GeneralisedLinearSpringForce<2,2>;
00293 template class GeneralisedLinearSpringForce<1,3>;
00294 template class GeneralisedLinearSpringForce<2,3>;
00295 template class GeneralisedLinearSpringForce<3,3>;
00296 
00297 // Serialization for Boost >= 1.36
00298 #include "SerializationExportWrapperForCpp.hpp"
00299 EXPORT_TEMPLATE_CLASS_ALL_DIMS(GeneralisedLinearSpringForce)