GeneralisedLinearSpringForce.cpp

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

Generated on Mon Nov 1 12:35:16 2010 for Chaste by  doxygen 1.5.5