Chaste Release::3.1
|
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)