Chaste  Release::2017.1
CryptProjectionForce.cpp
1 /*
2 
3 Copyright (c) 2005-2017, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, 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 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF 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 "IsNan.hpp"
40 #include "StemCellProliferativeType.hpp"
41 
44  mIncludeWntChemotaxis(false),
45  mWntChemotaxisStrength(100.0)
46 {
49 }
50 
52 {
53 }
54 
56 {
57  mNode3dLocationMap.clear();
58 
59  c_vector<double, 2> node_location_2d;
60  c_vector<double, 3> node_location_3d;
61 
62  // Only consider nodes corresponding to real cells
63  for (AbstractCellPopulation<2>::Iterator cell_iter = rCellPopulation.Begin();
64  cell_iter != rCellPopulation.End();
65  ++cell_iter)
66  {
67  // Get node index
68  unsigned node_index = rCellPopulation.GetLocationIndexUsingCell(*cell_iter);
69 
70  // Get 3D location
71  node_location_2d = rCellPopulation.GetLocationOfCellCentre(*cell_iter);
72 
73  node_location_3d[0] = node_location_2d[0];
74  node_location_3d[1] = node_location_2d[1];
75  node_location_3d[2] = CalculateCryptSurfaceHeightAtPoint(node_location_2d);
76 
77  // Add to map
78  mNode3dLocationMap[node_index] = node_location_3d;
79  }
80 }
81 
83 {
84  return mA;
85 }
86 
88 {
89  return mB;
90 }
91 
92 void CryptProjectionForce::SetWntChemotaxisStrength(double wntChemotaxisStrength)
93 {
94  assert(wntChemotaxisStrength >= 0.0);
95  mWntChemotaxisStrength = wntChemotaxisStrength;
96 }
98 {
100 }
101 
102 void CryptProjectionForce::SetWntChemotaxis(bool includeWntChemotaxis)
103 {
104  mIncludeWntChemotaxis = includeWntChemotaxis;
105 }
106 
107 double CryptProjectionForce::CalculateCryptSurfaceHeightAtPoint(const c_vector<double,2>& rNodeLocation)
108 {
109  return mA*pow(norm_2(rNodeLocation), mB); // =z_coord;
110 }
111 
112 double CryptProjectionForce::CalculateCryptSurfaceDerivativeAtPoint(const c_vector<double,2>& rNodeLocation)
113 {
114  return mA*mB*pow(norm_2(rNodeLocation), (mB - 1.0));
115 }
116 
117 c_vector<double,2> CryptProjectionForce::CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation<2>& rCellPopulation)
118 {
119  MeshBasedCellPopulation<2>* p_static_cast_cell_population = static_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation);
120 
121  // We should only ever calculate the force between two distinct nodes
122  assert(nodeAGlobalIndex != nodeBGlobalIndex);
123 
124  // Get the node locations in 2D
125  c_vector<double,2> node_a_location_2d = rCellPopulation.GetNode(nodeAGlobalIndex)->rGetLocation();
126  c_vector<double,2> node_b_location_2d = rCellPopulation.GetNode(nodeBGlobalIndex)->rGetLocation();
127 
128  // "Get the unit vector parallel to the line joining the two nodes" [GeneralisedLinearSpringForce]
129 
130  // Create a unit vector in the direction of the 3D spring
131  c_vector<double,3> unit_difference = mNode3dLocationMap[nodeBGlobalIndex] - mNode3dLocationMap[nodeAGlobalIndex];
132 
133  // Calculate the distance between the two nodes
134  double distance_between_nodes = norm_2(unit_difference);
135  assert(distance_between_nodes > 0);
136  assert(!std::isnan(distance_between_nodes));
137 
138  unit_difference /= distance_between_nodes;
139 
140  // If mUseCutOffLength has been set, then there is zero force between
141  // two nodes located a distance apart greater than mUseCutOffLength
142  if (this->mUseCutOffLength)
143  {
144  if (distance_between_nodes >= mMechanicsCutOffLength)
145  {
146  // Return zero (2D projected) force
147  return zero_vector<double>(2);
148  }
149  }
150 
151  // Calculate the rest length of the spring connecting the two nodes
152 
153  double rest_length = 1.0;
154 
155  CellPtr p_cell_A = rCellPopulation.GetCellUsingLocationIndex(nodeAGlobalIndex);
156  CellPtr p_cell_B = rCellPopulation.GetCellUsingLocationIndex(nodeBGlobalIndex);
157 
158  double ageA = p_cell_A->GetAge();
159  double ageB = p_cell_B->GetAge();
160 
161  assert(!std::isnan(ageA));
162  assert(!std::isnan(ageB));
163 
164  /*
165  * If the cells are both newly divided, then the rest length of the spring
166  * connecting them grows linearly with time, until mMeinekeSpringGrowthDuration hour after division.
167  */
169  {
170  /*
171  * The spring rest length increases from a predefined small parameter
172  * to a normal rest length of 1.0, over a period of one hour.
173  */
174  std::pair<CellPtr,CellPtr> cell_pair = p_static_cast_cell_population->CreateCellPair(p_cell_A, p_cell_B);
175  if (p_static_cast_cell_population->IsMarkedSpring(cell_pair))
176  {
177  double lambda = mMeinekeDivisionRestingSpringLength;
178  rest_length = lambda + (1.0 - lambda) * ageA/mMeinekeSpringGrowthDuration;
179  }
181  {
182  // This spring is about to go out of scope
183  p_static_cast_cell_population->UnmarkSpring(cell_pair);
184  }
185  }
186 
187  double a_rest_length = rest_length*0.5;
188  double b_rest_length = a_rest_length;
189 
190  /*
191  * If either of the cells has begun apoptosis, then the length of the spring
192  * connecting them decreases linearly with time.
193  */
194  if (p_cell_A->HasApoptosisBegun())
195  {
196  double time_until_death_a = p_cell_A->GetTimeUntilDeath();
197  a_rest_length = a_rest_length * time_until_death_a / p_cell_A->GetApoptosisTime();
198  }
199  if (p_cell_B->HasApoptosisBegun())
200  {
201  double time_until_death_b = p_cell_B->GetTimeUntilDeath();
202  b_rest_length = b_rest_length * time_until_death_b / p_cell_B->GetApoptosisTime();
203  }
204 
205  rest_length = a_rest_length + b_rest_length;
206 
207  // Assert that the rest length does not exceed 1
208  assert(rest_length <= 1.0+1e-12);
209 
210  bool is_closer_than_rest_length = true;
211 
212  if (distance_between_nodes - rest_length > 0)
213  {
214  is_closer_than_rest_length = false;
215  }
216 
217  /*
218  * Although in this class the 'spring constant' is a constant parameter, in
219  * subclasses it can depend on properties of each of the cells.
220  */
221  double multiplication_factor = 1.0;
222  multiplication_factor *= VariableSpringConstantMultiplicationFactor(nodeAGlobalIndex, nodeBGlobalIndex, rCellPopulation, is_closer_than_rest_length);
223 
224  // Calculate the 3D force between the two points
225  c_vector<double,3> force_between_nodes = multiplication_factor * this->GetMeinekeSpringStiffness() * unit_difference * (distance_between_nodes - rest_length);
226 
227  // Calculate an outward normal unit vector to the tangent plane of the crypt surface at the 3D point corresponding to node B
228  c_vector<double,3> outward_normal_unit_vector;
229 
230  double dfdr = CalculateCryptSurfaceDerivativeAtPoint(node_b_location_2d);
231  double theta_B = atan2(node_b_location_2d[1], node_b_location_2d[0]); // use atan2 to determine the quadrant
232  double normalization_factor = sqrt(1 + dfdr*dfdr);
233 
234  outward_normal_unit_vector[0] = dfdr*cos(theta_B)/normalization_factor;
235  outward_normal_unit_vector[1] = dfdr*sin(theta_B)/normalization_factor;
236  outward_normal_unit_vector[2] = -1.0/normalization_factor;
237 
238  // Calculate the projection of the force onto the plane z=0
239  c_vector<double,2> projected_force_between_nodes_2d;
240  double force_dot_normal = inner_prod(force_between_nodes, outward_normal_unit_vector);
241 
242  for (unsigned i=0; i<2; i++)
243  {
244  projected_force_between_nodes_2d[i] = force_between_nodes[i]
245  - force_dot_normal*outward_normal_unit_vector[i]
246  + force_dot_normal*outward_normal_unit_vector[2];
247  }
248 
249  return projected_force_between_nodes_2d;
250 }
251 
253 {
254  // First work out the 3D location of each cell
255  UpdateNode3dLocationMap(rCellPopulation);
256 
257  // Throw an exception message if not using a MeshBasedCellPopulation
258  if (dynamic_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation) == nullptr)
259  {
260  EXCEPTION("CryptProjectionForce is to be used with a subclass of MeshBasedCellPopulation only");
261  }
262 
263  MeshBasedCellPopulation<2>* p_static_cast_cell_population = static_cast<MeshBasedCellPopulation<2>*>(&rCellPopulation);
264 
265  for (MeshBasedCellPopulation<2>::SpringIterator spring_iterator = p_static_cast_cell_population->SpringsBegin();
266  spring_iterator != p_static_cast_cell_population->SpringsEnd();
267  ++spring_iterator)
268  {
269  unsigned nodeA_global_index = spring_iterator.GetNodeA()->GetIndex();
270  unsigned nodeB_global_index = spring_iterator.GetNodeB()->GetIndex();
271 
272  c_vector<double, 2> force = CalculateForceBetweenNodes(nodeA_global_index, nodeB_global_index, rCellPopulation);
273  c_vector<double, 2> negative_force = -1.0 * force;
274  spring_iterator.GetNodeB()->AddAppliedForceContribution(negative_force);
275  spring_iterator.GetNodeA()->AddAppliedForceContribution(force);
276  }
277 
279  {
280  assert(WntConcentration<2>::Instance()->IsWntSetUp());
281 
282  for (AbstractCellPopulation<2>::Iterator cell_iter = rCellPopulation.Begin();
283  cell_iter != rCellPopulation.End();
284  ++cell_iter)
285  {
286  if (cell_iter->GetCellProliferativeType()->IsType<StemCellProliferativeType>())
287  {
288  c_vector<double, 2> wnt_chemotactic_force = mWntChemotaxisStrength*WntConcentration<2>::Instance()->GetWntGradient(*cell_iter);
289  unsigned index = rCellPopulation.GetLocationIndexUsingCell(*cell_iter);
290 
291  rCellPopulation.GetNode(index)->AddAppliedForceContribution(wnt_chemotactic_force);
292  }
293  }
294  }
295 }
296 
297 void CryptProjectionForce::OutputForceParameters(out_stream& rParamsFile)
298 {
299  *rParamsFile << "\t\t\t<A>" << mA << "</A>\n";
300  *rParamsFile << "\t\t\t<B>" << mB << "</B>\n";
301  *rParamsFile << "\t\t\t<IncludeWntChemotaxis>" << mIncludeWntChemotaxis << "</IncludeWntChemotaxis>\n";
302  *rParamsFile << "\t\t\t<WntChemotaxisStrength>" << mWntChemotaxisStrength << "</WntChemotaxisStrength>\n";
303 
304  // Call method on direct parent class
306 }
307 
308 // Serialization for Boost >= 1.36
virtual Node< SPACE_DIM > * GetNode(unsigned index)=0
void UnmarkSpring(std::pair< CellPtr, CellPtr > &rCellPair)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
void SetWntChemotaxis(bool includeWntChemotaxis)
unsigned GetLocationIndexUsingCell(CellPtr pCell)
#define EXCEPTION(message)
Definition: Exception.hpp:143
static SimulationTime * Instance()
double CalculateCryptSurfaceDerivativeAtPoint(const c_vector< double, 2 > &rNodeLocation)
double GetCryptProjectionParameterB()
double GetTimeStep() const
std::pair< CellPtr, CellPtr > CreateCellPair(CellPtr pCell1, CellPtr pCell2)
double CalculateCryptSurfaceHeightAtPoint(const c_vector< double, 2 > &rNodeLocation)
void UpdateNode3dLocationMap(AbstractCellPopulation< 2 > &rCellPopulation)
static WntConcentration * Instance()
c_vector< double, 2 > CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation< 2 > &rCellPopulation)
c_vector< double, DIM > GetWntGradient(c_vector< double, DIM > &rLocation)
bool IsMarkedSpring(const std::pair< CellPtr, CellPtr > &rCellPair)
virtual c_vector< double, SPACE_DIM > GetLocationOfCellCentre(CellPtr pCell)=0
std::map< unsigned, c_vector< double, 3 > > mNode3dLocationMap
void OutputForceParameters(out_stream &rParamsFile)
virtual double VariableSpringConstantMultiplicationFactor(unsigned nodeAGlobalIndex, unsigned nodeBGlobalIndex, AbstractCellPopulation< ELEMENT_DIM, ELEMENT_DIM > &rCellPopulation, bool isCloserThanRestLength)
virtual void OutputForceParameters(out_stream &rParamsFile)
void AddForceContribution(AbstractCellPopulation< 2 > &rCellPopulation)
void SetWntChemotaxisStrength(double wntChemotaxisStrength)
#define CHASTE_CLASS_EXPORT(T)
double GetCryptProjectionParameterA()