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

Generated by  doxygen 1.6.2