Chaste Commit::f841a6fa79bd6f7a205054452b95ddf6d10aae23
AbstractVariableSizeTwoBodyInteractionForce.cpp
1/*
2
3Copyright (c) 2005-2026, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#include "AbstractVariableSizeTwoBodyInteractionForce.hpp"
37
38#include "AbstractCentreBasedCellPopulation.hpp"
39#include "MeshBasedCellPopulation.hpp"
40#include "NodeBasedCellPopulation.hpp"
41
42template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
44 : AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM>(),
45 mSpringStiffness(15.0),
46 mDivisionRestingSpringLength(0.5),
47 mSpringGrowthDuration(1.0)
48{
49 if constexpr (SPACE_DIM == 1)
50 {
51 mSpringStiffness = 30.0;
52 }
53}
54
55template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
59
60template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
62 unsigned nodeAGlobalIndex,
63 unsigned nodeBGlobalIndex,
65 bool isCloserThanRestLength)
66{
67 return 1.0;
68}
69
70template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
72 unsigned nodeAGlobalIndex,
73 unsigned nodeBGlobalIndex,
75{
76 // We should only ever calculate the force between two distinct nodes
77 assert(nodeAGlobalIndex != nodeBGlobalIndex);
78
79 Node<SPACE_DIM>* p_node_a = rCellPopulation.GetNode(nodeAGlobalIndex);
80 Node<SPACE_DIM>* p_node_b = rCellPopulation.GetNode(nodeBGlobalIndex);
81
82 // Get the node locations
83 const c_vector<double, SPACE_DIM>& r_node_a_location = p_node_a->rGetLocation();
84 const c_vector<double, SPACE_DIM>& r_node_b_location = p_node_b->rGetLocation();
85
86 // Get the node radii for a NodeBasedCellPopulation
87 double node_a_radius = 0.0;
88 double node_b_radius = 0.0;
89
90 if (bool(dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)))
91 {
92 node_a_radius = p_node_a->GetRadius();
93 node_b_radius = p_node_b->GetRadius();
94 }
95
96 // Get the unit vector parallel to the line joining the two nodes
97 c_vector<double, SPACE_DIM> unit_difference;
98 /*
99 * We use the mesh method GetVectorFromAtoB() to compute the direction of the
100 * unit vector along the line joining the two nodes, rather than simply subtract
101 * their positions, because this method can be overloaded (e.g. to enforce a
102 * periodic boundary in Cylindrical2dMesh).
103 */
104 unit_difference = rCellPopulation.rGetMesh().GetVectorFromAtoB(r_node_a_location, r_node_b_location);
105
106 // Calculate the distance between the two nodes
107 double distance_between_nodes = norm_2(unit_difference);
108 assert(distance_between_nodes > 0);
109 assert(!std::isnan(distance_between_nodes));
110
111 unit_difference /= distance_between_nodes;
112
113 /*
114 * If mUseCutOffLength has been set, then there is zero force between
115 * two nodes located a distance apart greater than mMechanicsCutOffLength in AbstractTwoBodyInteractionForce.
116 */
117 if (this->mUseCutOffLength)
118 {
119 if (distance_between_nodes >= this->GetCutOffLength())
120 {
121 return zero_vector<double>(SPACE_DIM); // c_vector<double,SPACE_DIM>() is not guaranteed to be fresh memory
122 }
123 }
124
125 /*
126 * Calculate the rest length of the spring connecting the two nodes with a default
127 * value of 1.0.
128 */
129 double rest_length_final = 1.0;
131 if (bool(dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)))
132 {
133 rest_length_final = static_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)->GetRestLength(nodeAGlobalIndex, nodeBGlobalIndex);
134 }
135 else if (bool(dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)))
136 {
137 assert(node_a_radius > 0 && node_b_radius > 0);
138 rest_length_final = node_a_radius + node_b_radius;
139 }
140
141 double rest_length = rest_length_final;
142
143 CellPtr p_cell_A = rCellPopulation.GetCellUsingLocationIndex(nodeAGlobalIndex);
144 CellPtr p_cell_B = rCellPopulation.GetCellUsingLocationIndex(nodeBGlobalIndex);
145
146 double ageA = p_cell_A->GetAge();
147 double ageB = p_cell_B->GetAge();
148
149 assert(!std::isnan(ageA));
150 assert(!std::isnan(ageB));
151
152 /*
153 * If the cells are both newly divided, then the rest length of the spring
154 * connecting them grows linearly with time, until 1 hour after division.
155 */
156 if (ageA < mSpringGrowthDuration && ageB < mSpringGrowthDuration)
157 {
160 std::pair<CellPtr,CellPtr> cell_pair = p_static_cast_cell_population->CreateCellPair(p_cell_A, p_cell_B);
161
162 if (p_static_cast_cell_population->IsMarkedSpring(cell_pair))
163 {
164 // Spring rest length increases from a small value to the normal rest length over 1 hour
165 double lambda = mDivisionRestingSpringLength;
166 rest_length = lambda + (rest_length_final - lambda) * ageA/mSpringGrowthDuration;
167 }
168 if (ageA + SimulationTime::Instance()->GetTimeStep() >= mSpringGrowthDuration)
169 {
170 // This spring is about to go out of scope
171 p_static_cast_cell_population->UnmarkSpring(cell_pair);
172 }
173 }
174
175 /*
176 * For apoptosis, progressively reduce the radius of the cell.
177 */
178 double a_rest_length = rest_length*0.5;
179 double b_rest_length = a_rest_length;
180
181 if (bool(dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)))
182 {
183 assert(node_a_radius > 0 && node_b_radius > 0);
184 a_rest_length = (node_a_radius/(node_a_radius+node_b_radius))*rest_length;
185 b_rest_length = (node_b_radius/(node_a_radius+node_b_radius))*rest_length;
186 }
187
188 /*
189 * If either of the cells has begun apoptosis, then the length of the spring
190 * connecting them decreases linearly with time.
191 */
192 if (p_cell_A->HasApoptosisBegun())
193 {
194 double time_until_death_a = p_cell_A->GetTimeUntilDeath();
195 a_rest_length = a_rest_length * time_until_death_a / p_cell_A->GetApoptosisTime();
196 }
197 if (p_cell_B->HasApoptosisBegun())
198 {
199 double time_until_death_b = p_cell_B->GetTimeUntilDeath();
200 b_rest_length = b_rest_length * time_until_death_b / p_cell_B->GetApoptosisTime();
201 }
202
203 rest_length = a_rest_length + b_rest_length;
204
205 double overlap = distance_between_nodes - rest_length;
206 bool is_closer_than_rest_length = (overlap <= 0);
207 double multiplication_factor = VariableSpringConstantMultiplicationFactor(nodeAGlobalIndex,
208 nodeBGlobalIndex,
209 rCellPopulation,
210 is_closer_than_rest_length);
211
212 // TODO issue 1017 This should be rest_length not rest_length_final, keeping it the same for now to maintain backwards compatibility with existing force laws, but we should eventually change it and update the force laws accordingly.
213 return CalculateLinkInteraction(overlap, rest_length_final, unit_difference, multiplication_factor);
214}
215
216template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
221
222template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
227
228template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
233
234template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
236{
237 assert(springStiffness > 0.0);
238 mSpringStiffness = springStiffness;
239}
240
241template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
243{
244 assert(divisionRestingSpringLength <= 1.0);
245 assert(divisionRestingSpringLength >= 0.0);
246
247 mDivisionRestingSpringLength = divisionRestingSpringLength;
248}
249
250template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
252{
253 assert(springGrowthDuration >= 0.0);
254
255 mSpringGrowthDuration = springGrowthDuration;
256}
257
258template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
263
264// Explicit instantiation
virtual Node< SPACE_DIM > * GetNode(unsigned index)=0
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
AbstractMesh< ELEMENT_DIM, SPACE_DIM > & rGetMesh()
void UnmarkSpring(std::pair< CellPtr, CellPtr > &rCellPair)
std::pair< CellPtr, CellPtr > CreateCellPair(CellPtr pCell1, CellPtr pCell2)
bool IsMarkedSpring(const std::pair< CellPtr, CellPtr > &rCellPair)
virtual void OutputForceParameters(out_stream &rParamsFile)
c_vector< double, SPACE_DIM > CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation< ELEMENT_DIM, SPACE_DIM > &rCellPopulation)
virtual double VariableSpringConstantMultiplicationFactor(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation< ELEMENT_DIM, SPACE_DIM > &rCellPopulation, bool isCloserThanRestLength)
Definition Node.hpp:59
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition Node.cpp:139
double GetRadius()
Definition Node.cpp:248
double GetTimeStep() const
static SimulationTime * Instance()