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