Chaste  Release::3.4
OffLatticeSimulation.cpp
1 /*
2 
3 Copyright (c) 2005-2016, 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 "OffLatticeSimulation.hpp"
37 #include "AbstractCentreBasedCellPopulation.hpp"
38 #include "VertexBasedCellPopulation.hpp"
39 #include "T2SwapCellKiller.hpp"
40 #include "AbstractVertexBasedDivisionRule.hpp"
41 #include "Cylindrical2dMesh.hpp"
42 #include "Cylindrical2dVertexMesh.hpp"
43 #include "AbstractTwoBodyInteractionForce.hpp"
44 #include "CellBasedEventHandler.hpp"
45 #include "LogFile.hpp"
46 #include "Version.hpp"
47 #include "ExecutableSupport.hpp"
48 
49 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
51  bool deleteCellPopulationInDestructor,
52  bool initialiseCells)
53  : AbstractCellBasedSimulation<ELEMENT_DIM,SPACE_DIM>(rCellPopulation, deleteCellPopulationInDestructor, initialiseCells)
54 {
55  if (!dynamic_cast<AbstractOffLatticeCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation))
56  {
57  EXCEPTION("OffLatticeSimulations require a subclass of AbstractOffLatticeCellPopulation.");
58  }
59 
60  // Different time steps are used for cell-centre and vertex-based simulations
61  if (bool(dynamic_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)))
62  {
63  this->mDt = 1.0/120.0; // 30 seconds
64  }
65  else if (bool(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)))
66  {
67  this->mDt = 0.002; // smaller time step required for convergence/stability
68 
69  // For VertexBasedCellPopulations we automatically add a T2SwapCellKiller. In order to inhibit T2 swaps
70  // the user needs to set the threshold for T2 swaps in the mesh to 0.
71  VertexBasedCellPopulation<SPACE_DIM>* p_vertex_based_cell_population = dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation);
72  MAKE_PTR_ARGS(T2SwapCellKiller<SPACE_DIM>, T2_swap_cell_killer, (p_vertex_based_cell_population));
73  this->AddCellKiller(T2_swap_cell_killer);
74  }
75  else
76  {
77  // All classes derived from AbstractOffLatticeCellPopulation are covered by the above (except user-derived classes),
78  // i.e. if you want to use this method with your own subclass of AbstractOffLatticeCellPopulation, then simply
79  // comment out the line below
81  }
82 }
83 
84 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
86 {
87  mForceCollection.push_back(pForce);
88 }
89 
90 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
92 {
93  mForceCollection.clear();
94 }
95 
96 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
98 {
99  mBoundaryConditions.push_back(pBoundaryCondition);
100 }
101 
102 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
104 {
105  mBoundaryConditions.clear();
106 }
107 
108 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
110 {
111  // Calculate forces
112  CellBasedEventHandler::BeginEvent(CellBasedEventHandler::FORCE);
113 
114  // Clear all forces
115  for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrCellPopulation.rGetMesh().GetNodeIteratorBegin();
116  node_iter != this->mrCellPopulation.rGetMesh().GetNodeIteratorEnd();
117  ++node_iter)
118  {
119  node_iter->ClearAppliedForce();
120  }
121 
122  // Now add force contributions from each AbstractForce
123  for (typename std::vector<boost::shared_ptr<AbstractForce<ELEMENT_DIM, SPACE_DIM> > >::iterator iter = mForceCollection.begin();
124  iter != mForceCollection.end();
125  ++iter)
126  {
127  (*iter)->AddForceContribution(this->mrCellPopulation);
128  }
129  CellBasedEventHandler::EndEvent(CellBasedEventHandler::FORCE);
130 
131  // Update node positions
132  CellBasedEventHandler::BeginEvent(CellBasedEventHandler::POSITION);
133  UpdateNodePositions();
134  CellBasedEventHandler::EndEvent(CellBasedEventHandler::POSITION);
135 }
136 
137 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
138 c_vector<double, SPACE_DIM> OffLatticeSimulation<ELEMENT_DIM,SPACE_DIM>::CalculateCellDivisionVector(CellPtr pParentCell)
139 {
145  // If it is not vertex based...
146  if (bool(dynamic_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))))
147  {
148  // Location of parent and daughter cells
149  c_vector<double, SPACE_DIM> parent_coords = this->mrCellPopulation.GetLocationOfCellCentre(pParentCell);
150  c_vector<double, SPACE_DIM> daughter_coords;
151 
152  // Get separation parameter
153  double separation = static_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->GetMeinekeDivisionSeparation();
154 
155  // Make a random direction vector of the required length
156  c_vector<double, SPACE_DIM> random_vector;
157 
158  /*
159  * Pick a random direction and move the parent cell backwards by 0.5*separation
160  * in that direction and return the position of the daughter cell 0.5*separation
161  * forwards in that direction.
162  */
163  switch (SPACE_DIM)
164  {
165  case 1:
166  {
167  double random_direction = -1.0 + 2.0*(RandomNumberGenerator::Instance()->ranf() < 0.5);
168 
169  random_vector(0) = 0.5*separation*random_direction;
170  break;
171  }
172  case 2:
173  {
174  double random_angle = 2.0*M_PI*RandomNumberGenerator::Instance()->ranf();
175 
176  random_vector(0) = 0.5*separation*cos(random_angle);
177  random_vector(1) = 0.5*separation*sin(random_angle);
178  break;
179  }
180  case 3:
181  {
182  /*
183  * Note that to pick a random point on the surface of a sphere, it is incorrect
184  * to select spherical coordinates from uniform distributions on [0, 2*pi) and
185  * [0, pi) respectively, since points picked in this way will be 'bunched' near
186  * the poles. See #2230.
187  */
188  double u = RandomNumberGenerator::Instance()->ranf();
189  double v = RandomNumberGenerator::Instance()->ranf();
190 
191  double random_azimuth_angle = 2*M_PI*u;
192  double random_zenith_angle = std::acos(2*v - 1);
193 
194  random_vector(0) = 0.5*separation*cos(random_azimuth_angle)*sin(random_zenith_angle);
195  random_vector(1) = 0.5*separation*sin(random_azimuth_angle)*sin(random_zenith_angle);
196  random_vector(2) = 0.5*separation*cos(random_zenith_angle);
197  break;
198  }
199  default:
200  // This can't happen
202  }
203 
204  parent_coords = parent_coords - random_vector;
205  daughter_coords = parent_coords + random_vector;
206 
207  // Set the parent to use this location
208  ChastePoint<SPACE_DIM> parent_coords_point(parent_coords);
209  unsigned node_index = this->mrCellPopulation.GetLocationIndexUsingCell(pParentCell);
210  this->mrCellPopulation.SetNode(node_index, parent_coords_point);
211 
212  return daughter_coords;
213  }
214  else if (bool(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&(this->mrCellPopulation))))
215  {
216  VertexBasedCellPopulation<SPACE_DIM>* p_vertex_population = dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&(this->mrCellPopulation));
217  boost::shared_ptr<AbstractVertexBasedDivisionRule<SPACE_DIM> > p_division_rule = p_vertex_population->GetVertexBasedDivisionRule();
218 
219  return p_division_rule->CalculateCellDivisionVector(pParentCell, *p_vertex_population);
220  }
221  else
222  {
223  // All classes derived from AbstractOffLatticeCellPopulation are covered by the above (except user-derived classes),
224  // i.e. if you want to use this class with your own subclass of AbstractOffLatticeCellPopulation, then simply
225  // comment out the line below
227  }
228 }
229 
230 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
232 {
233  if (PetscTools::AmMaster())
234  {
235  for (unsigned i=0; i<this->mForceCollection.size(); i++)
236  {
237  // This may cause compilation problems, probably due to AbstractTwoBodyInteractionForce not having two template parameters
239 
240  boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > p_force = this->mForceCollection[i];
241  if (boost::dynamic_pointer_cast<AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM> >(p_force))
242  {
243  double cutoff = (boost::static_pointer_cast<AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM> >(p_force))->GetCutOffLength();
244  *(this->mpVizSetupFile) << "Cutoff\t" << cutoff << "\n";
245  }
246  }
247 
248  // This is a quick and dirty check to see if the mesh is periodic
249  if (bool(dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&this->mrCellPopulation)))
250  {
251  if (bool(dynamic_cast<Cylindrical2dMesh*>(&(dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->rGetMesh()))))
252  {
253  *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n";
254  }
255  }
256  else if (bool(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&this->mrCellPopulation)))
257  {
258  if (bool(dynamic_cast<Cylindrical2dVertexMesh*>(&(dynamic_cast<VertexBasedCellPopulation<SPACE_DIM>*>(&(this->mrCellPopulation))->rGetMesh()))))
259  {
260  *this->mpVizSetupFile << "MeshWidth\t" << this->mrCellPopulation.GetWidth(0) << "\n";
261  }
262  }
263  }
264 }
265 
266 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
268 {
269  /*
270  * Get the previous node positions (these may be needed when applying boundary conditions,
271  * e.g. in the case of immotile cells)
272  */
273  std::map<Node<SPACE_DIM>*, c_vector<double, SPACE_DIM> > old_node_locations;
274  for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrCellPopulation.rGetMesh().GetNodeIteratorBegin();
275  node_iter != this->mrCellPopulation.rGetMesh().GetNodeIteratorEnd();
276  ++node_iter)
277  {
278  old_node_locations[&(*node_iter)] = (node_iter)->rGetLocation();
279  }
280 
281  // Update node locations
282  static_cast<AbstractOffLatticeCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation))->UpdateNodeLocations(this->mDt);
283 
284  // Apply any boundary conditions
285  for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator bcs_iter = mBoundaryConditions.begin();
286  bcs_iter != mBoundaryConditions.end();
287  ++bcs_iter)
288  {
289  (*bcs_iter)->ImposeBoundaryCondition(old_node_locations);
290  }
291 
292  // Verify that each boundary condition is now satisfied
293  for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator bcs_iter = mBoundaryConditions.begin();
294  bcs_iter != mBoundaryConditions.end();
295  ++bcs_iter)
296  {
297  if (!((*bcs_iter)->VerifyBoundaryCondition()))
298  {
299  EXCEPTION("The cell population boundary conditions are incompatible.");
300  }
301  }
302 }
303 
304 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
306 {
307  // Clear all forces
308  for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrCellPopulation.rGetMesh().GetNodeIteratorBegin();
309  node_iter != this->mrCellPopulation.rGetMesh().GetNodeIteratorEnd();
310  ++node_iter)
311  {
312  node_iter->ClearAppliedForce();
313  }
314 }
315 
316 
317 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
319 {
320  // Loop over forces
321  *rParamsFile << "\n\t<Forces>\n";
322  for (typename std::vector<boost::shared_ptr<AbstractForce<ELEMENT_DIM,SPACE_DIM> > >::iterator iter = mForceCollection.begin();
323  iter != mForceCollection.end();
324  ++iter)
325  {
326  // Output force details
327  (*iter)->OutputForceInfo(rParamsFile);
328  }
329  *rParamsFile << "\t</Forces>\n";
330 
331  // Loop over cell population boundary conditions
332  *rParamsFile << "\n\t<CellPopulationBoundaryConditions>\n";
333  for (typename std::vector<boost::shared_ptr<AbstractCellPopulationBoundaryCondition<ELEMENT_DIM,SPACE_DIM> > >::iterator iter = mBoundaryConditions.begin();
334  iter != mBoundaryConditions.end();
335  ++iter)
336  {
337  // Output cell Boundary condition details
338  (*iter)->OutputCellPopulationBoundaryConditionInfo(rParamsFile);
339  }
340  *rParamsFile << "\t</CellPopulationBoundaryConditions>\n";
341 }
342 
343 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
345 {
346  // Call method on direct parent class
348 }
349 
351 template class OffLatticeSimulation<1,1>;
352 template class OffLatticeSimulation<1,2>;
353 template class OffLatticeSimulation<2,2>;
354 template class OffLatticeSimulation<1,3>;
355 template class OffLatticeSimulation<2,3>;
356 template class OffLatticeSimulation<3,3>;
357 
358 // Serialization for Boost >= 1.36
void AddCellKiller(boost::shared_ptr< AbstractCellKiller< SPACE_DIM > > pCellKiller)
void OutputAdditionalSimulationSetup(out_stream &rParamsFile)
virtual void WriteVisualizerSetupFile()
#define EXCEPTION(message)
Definition: Exception.hpp:143
static bool AmMaster()
Definition: PetscTools.cpp:120
virtual void UpdateNodeLocations(double dt)=0
#define NEVER_REACHED
Definition: Exception.hpp:206
boost::shared_ptr< AbstractVertexBasedDivisionRule< DIM > > GetVertexBasedDivisionRule()
void AddForce(boost::shared_ptr< AbstractForce< ELEMENT_DIM, SPACE_DIM > > pForce)
virtual void OutputSimulationParameters(out_stream &rParamsFile)=0
virtual void UpdateNodePositions()
static RandomNumberGenerator * Instance()
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
virtual c_vector< double, SPACE_DIM > CalculateCellDivisionVector(CellPtr pParentCell)
OffLatticeSimulation(AbstractCellPopulation< ELEMENT_DIM, SPACE_DIM > &rCellPopulation, bool deleteCellPopulationInDestructor=false, bool initialiseCells=true)
#define MAKE_PTR_ARGS(TYPE, NAME, ARGS)
virtual void OutputSimulationParameters(out_stream &rParamsFile)
virtual void UpdateCellLocationsAndTopology()
void AddCellPopulationBoundaryCondition(boost::shared_ptr< AbstractCellPopulationBoundaryCondition< ELEMENT_DIM, SPACE_DIM > > pBoundaryCondition)