Chaste Commit::1fd4e48e3990e67db148bc1bc4cf6991a0049d0c
CryptProjectionForce.cpp
1/*
2
3Copyright (c) 2005-2024, 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 "CryptProjectionForce.hpp"
37#include "MeshBasedCellPopulation.hpp"
38#include "WntConcentration.hpp"
39#include "StemCellProliferativeType.hpp"
40
41#include <cmath>
42
51
55
57{
58 mNode3dLocationMap.clear();
59
60 c_vector<double, 2> node_location_2d;
61 c_vector<double, 3> node_location_3d;
62
63 // Only consider nodes corresponding to real cells
64 for (AbstractCellPopulation<2>::Iterator cell_iter = rCellPopulation.Begin();
65 cell_iter != rCellPopulation.End();
66 ++cell_iter)
67 {
68 // Get node index
69 unsigned node_index = rCellPopulation.GetLocationIndexUsingCell(*cell_iter);
70
71 // Get 3D location
72 node_location_2d = rCellPopulation.GetLocationOfCellCentre(*cell_iter);
73
74 node_location_3d[0] = node_location_2d[0];
75 node_location_3d[1] = node_location_2d[1];
76 node_location_3d[2] = CalculateCryptSurfaceHeightAtPoint(node_location_2d);
77
78 // Add to map
79 mNode3dLocationMap[node_index] = node_location_3d;
80 }
81}
82
84{
85 return mA;
86}
87
89{
90 return mB;
91}
92
93void CryptProjectionForce::SetWntChemotaxisStrength(double wntChemotaxisStrength)
94{
95 assert(wntChemotaxisStrength >= 0.0);
96 mWntChemotaxisStrength = wntChemotaxisStrength;
97}
102
103void CryptProjectionForce::SetWntChemotaxis(bool includeWntChemotaxis)
104{
105 mIncludeWntChemotaxis = includeWntChemotaxis;
106}
107
108double CryptProjectionForce::CalculateCryptSurfaceHeightAtPoint(const c_vector<double,2>& rNodeLocation)
109{
110 return mA*pow(norm_2(rNodeLocation), mB); // =z_coord;
111}
112
113double CryptProjectionForce::CalculateCryptSurfaceDerivativeAtPoint(const c_vector<double,2>& rNodeLocation)
114{
115 return mA*mB*pow(norm_2(rNodeLocation), (mB - 1.0));
116}
117
118c_vector<double,2> CryptProjectionForce::CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation<2>& rCellPopulation)
119{
120 MeshBasedCellPopulation<2>* p_static_cast_cell_population = static_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation);
121
122 // We should only ever calculate the force between two distinct nodes
123 assert(nodeAGlobalIndex != nodeBGlobalIndex);
124
125 // Get the node locations in 2D
126 c_vector<double,2> node_a_location_2d = rCellPopulation.GetNode(nodeAGlobalIndex)->rGetLocation();
127 c_vector<double,2> node_b_location_2d = rCellPopulation.GetNode(nodeBGlobalIndex)->rGetLocation();
128
129 // "Get the unit vector parallel to the line joining the two nodes" [GeneralisedLinearSpringForce]
130
131 // Create a unit vector in the direction of the 3D spring
132 c_vector<double,3> unit_difference = mNode3dLocationMap[nodeBGlobalIndex] - mNode3dLocationMap[nodeAGlobalIndex];
133
134 // Calculate the distance between the two nodes
135 double distance_between_nodes = norm_2(unit_difference);
136 assert(distance_between_nodes > 0);
137 assert(!std::isnan(distance_between_nodes));
138
139 unit_difference /= distance_between_nodes;
140
141 // If mUseCutOffLength has been set, then there is zero force between
142 // two nodes located a distance apart greater than mUseCutOffLength
143 if (this->mUseCutOffLength)
144 {
145 if (distance_between_nodes >= mMechanicsCutOffLength)
146 {
147 // Return zero (2D projected) force
148 return zero_vector<double>(2);
149 }
150 }
151
152 // Calculate the rest length of the spring connecting the two nodes
153
154 double rest_length = 1.0;
155
156 CellPtr p_cell_A = rCellPopulation.GetCellUsingLocationIndex(nodeAGlobalIndex);
157 CellPtr p_cell_B = rCellPopulation.GetCellUsingLocationIndex(nodeBGlobalIndex);
158
159 double ageA = p_cell_A->GetAge();
160 double ageB = p_cell_B->GetAge();
161
162 assert(!std::isnan(ageA));
163 assert(!std::isnan(ageB));
164
165 /*
166 * If the cells are both newly divided, then the rest length of the spring
167 * connecting them grows linearly with time, until mMeinekeSpringGrowthDuration hour after division.
168 */
170 {
171 /*
172 * The spring rest length increases from a predefined small parameter
173 * to a normal rest length of 1.0, over a period of one hour.
174 */
175 std::pair<CellPtr,CellPtr> cell_pair = p_static_cast_cell_population->CreateCellPair(p_cell_A, p_cell_B);
176 if (p_static_cast_cell_population->IsMarkedSpring(cell_pair))
177 {
179 rest_length = lambda + (1.0 - lambda) * ageA/mMeinekeSpringGrowthDuration;
180 }
182 {
183 // This spring is about to go out of scope
184 p_static_cast_cell_population->UnmarkSpring(cell_pair);
185 }
186 }
187
188 double a_rest_length = rest_length*0.5;
189 double b_rest_length = a_rest_length;
190
191 /*
192 * If either of the cells has begun apoptosis, then the length of the spring
193 * connecting them decreases linearly with time.
194 */
195 if (p_cell_A->HasApoptosisBegun())
196 {
197 double time_until_death_a = p_cell_A->GetTimeUntilDeath();
198 a_rest_length = a_rest_length * time_until_death_a / p_cell_A->GetApoptosisTime();
199 }
200 if (p_cell_B->HasApoptosisBegun())
201 {
202 double time_until_death_b = p_cell_B->GetTimeUntilDeath();
203 b_rest_length = b_rest_length * time_until_death_b / p_cell_B->GetApoptosisTime();
204 }
205
206 rest_length = a_rest_length + b_rest_length;
207
208 // Assert that the rest length does not exceed 1
209 assert(rest_length <= 1.0+1e-12);
210
211 bool is_closer_than_rest_length = true;
212
213 if (distance_between_nodes - rest_length > 0)
214 {
215 is_closer_than_rest_length = false;
216 }
217
218 /*
219 * Although in this class the 'spring constant' is a constant parameter, in
220 * subclasses it can depend on properties of each of the cells.
221 */
222 double multiplication_factor = 1.0;
223 multiplication_factor *= VariableSpringConstantMultiplicationFactor(nodeAGlobalIndex, nodeBGlobalIndex, rCellPopulation, is_closer_than_rest_length);
224
225 // Calculate the 3D force between the two points
226 c_vector<double,3> force_between_nodes = multiplication_factor * this->GetMeinekeSpringStiffness() * unit_difference * (distance_between_nodes - rest_length);
227
228 // Calculate an outward normal unit vector to the tangent plane of the crypt surface at the 3D point corresponding to node B
229 c_vector<double,3> outward_normal_unit_vector;
230
231 double dfdr = CalculateCryptSurfaceDerivativeAtPoint(node_b_location_2d);
232 double theta_B = atan2(node_b_location_2d[1], node_b_location_2d[0]); // use atan2 to determine the quadrant
233 double normalization_factor = sqrt(1 + dfdr*dfdr);
234
235 outward_normal_unit_vector[0] = dfdr*cos(theta_B)/normalization_factor;
236 outward_normal_unit_vector[1] = dfdr*sin(theta_B)/normalization_factor;
237 outward_normal_unit_vector[2] = -1.0/normalization_factor;
238
239 // Calculate the projection of the force onto the plane z=0
240 c_vector<double,2> projected_force_between_nodes_2d;
241 double force_dot_normal = inner_prod(force_between_nodes, outward_normal_unit_vector);
242
243 for (unsigned i=0; i<2; i++)
244 {
245 projected_force_between_nodes_2d[i] = force_between_nodes[i]
246 - force_dot_normal*outward_normal_unit_vector[i]
247 + force_dot_normal*outward_normal_unit_vector[2];
248 }
249
250 return projected_force_between_nodes_2d;
251}
252
254{
255 // First work out the 3D location of each cell
256 UpdateNode3dLocationMap(rCellPopulation);
257
258 // Throw an exception message if not using a MeshBasedCellPopulation
259 if (dynamic_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation) == nullptr)
260 {
261 EXCEPTION("CryptProjectionForce is to be used with a subclass of MeshBasedCellPopulation only");
262 }
263
264 MeshBasedCellPopulation<2>* p_static_cast_cell_population = static_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation);
265
266 for (MeshBasedCellPopulation<2>::SpringIterator spring_iterator = p_static_cast_cell_population->SpringsBegin();
267 spring_iterator != p_static_cast_cell_population->SpringsEnd();
268 ++spring_iterator)
269 {
270 unsigned nodeA_global_index = spring_iterator.GetNodeA()->GetIndex();
271 unsigned nodeB_global_index = spring_iterator.GetNodeB()->GetIndex();
272
273 c_vector<double, 2> force = CalculateForceBetweenNodes(nodeA_global_index, nodeB_global_index, rCellPopulation);
274 c_vector<double, 2> negative_force = -1.0 * force;
275 spring_iterator.GetNodeB()->AddAppliedForceContribution(negative_force);
276 spring_iterator.GetNodeA()->AddAppliedForceContribution(force);
277 }
278
280 {
281 assert(WntConcentration<2>::Instance()->IsWntSetUp());
282
283 for (AbstractCellPopulation<2>::Iterator cell_iter = rCellPopulation.Begin();
284 cell_iter != rCellPopulation.End();
285 ++cell_iter)
286 {
287 if (cell_iter->GetCellProliferativeType()->IsType<StemCellProliferativeType>())
288 {
289 c_vector<double, 2> wnt_chemotactic_force = mWntChemotaxisStrength*WntConcentration<2>::Instance()->GetWntGradient(*cell_iter);
290 unsigned index = rCellPopulation.GetLocationIndexUsingCell(*cell_iter);
291
292 rCellPopulation.GetNode(index)->AddAppliedForceContribution(wnt_chemotactic_force);
293 }
294 }
295 }
296}
297
299{
300 *rParamsFile << "\t\t\t<A>" << mA << "</A>\n";
301 *rParamsFile << "\t\t\t<B>" << mB << "</B>\n";
302 *rParamsFile << "\t\t\t<IncludeWntChemotaxis>" << mIncludeWntChemotaxis << "</IncludeWntChemotaxis>\n";
303 *rParamsFile << "\t\t\t<WntChemotaxisStrength>" << mWntChemotaxisStrength << "</WntChemotaxisStrength>\n";
304
305 // Call method on direct parent class
307}
308
309// Serialization for Boost >= 1.36
#define EXCEPTION(message)
#define CHASTE_CLASS_EXPORT(T)
virtual Node< SPACE_DIM > * GetNode(unsigned index)=0
virtual c_vector< double, SPACE_DIM > GetLocationOfCellCentre(CellPtr pCell)=0
unsigned GetLocationIndexUsingCell(CellPtr pCell)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
void UnmarkSpring(std::pair< CellPtr, CellPtr > &rCellPair)
std::pair< CellPtr, CellPtr > CreateCellPair(CellPtr pCell1, CellPtr pCell2)
bool IsMarkedSpring(const std::pair< CellPtr, CellPtr > &rCellPair)
void UpdateNode3dLocationMap(AbstractCellPopulation< 2 > &rCellPopulation)
void SetWntChemotaxisStrength(double wntChemotaxisStrength)
std::map< unsigned, c_vector< double, 3 > > mNode3dLocationMap
c_vector< double, 2 > CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation< 2 > &rCellPopulation)
double CalculateCryptSurfaceDerivativeAtPoint(const c_vector< double, 2 > &rNodeLocation)
void AddForceContribution(AbstractCellPopulation< 2 > &rCellPopulation)
void SetWntChemotaxis(bool includeWntChemotaxis)
void OutputForceParameters(out_stream &rParamsFile)
double CalculateCryptSurfaceHeightAtPoint(const c_vector< double, 2 > &rNodeLocation)
virtual double VariableSpringConstantMultiplicationFactor(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation< ELEMENT_DIM, ELEMENT_DIM > &rCellPopulation, bool isCloserThanRestLength)
virtual void OutputForceParameters(out_stream &rParamsFile)
double GetTimeStep() const
static SimulationTime * Instance()
static WntConcentration * Instance()
double GetCryptProjectionParameterB()
c_vector< double, DIM > GetWntGradient(c_vector< double, DIM > &rLocation)
double GetCryptProjectionParameterA()