Chaste  Release::2017.1
CaBasedCellPopulation.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 <boost/scoped_array.hpp>
37 
38 #include "CaBasedCellPopulation.hpp"
39 #include "MutableMesh.hpp"
40 #include "AbstractCaUpdateRule.hpp"
41 #include "AbstractCaSwitchingUpdateRule.hpp"
42 #include "RandomNumberGenerator.hpp"
43 #include "CellLocationIndexWriter.hpp"
44 #include "ExclusionCaBasedDivisionRule.hpp"
45 #include "NodesOnlyMesh.hpp"
46 #include "ApoptoticCellProperty.hpp"
47 
48 // Needed to convert mesh in order to write nodes to VTK (visualize as glyphs)
49 #include "VtkMeshWriter.hpp"
50 
51 // LCOV_EXCL_START
52 template<unsigned DIM>
54 {
56 }
57 // LCOV_EXCL_STOP
58 
59 template<unsigned DIM>
61  std::vector<CellPtr>& rCells,
62  const std::vector<unsigned> locationIndices,
63  unsigned latticeCarryingCapacity,
64  bool deleteMesh,
65  bool validate)
66  : AbstractOnLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh),
67  mLatticeCarryingCapacity(latticeCarryingCapacity)
68 {
69  mAvailableSpaces = std::vector<unsigned>(this->GetNumNodes(), latticeCarryingCapacity);
71 
72  // This must always be true
73  assert(this->mCells.size() <= this->mrMesh.GetNumNodes()*latticeCarryingCapacity);
74 
75  if (locationIndices.empty())
76  {
77  EXCEPTION("No location indices being passed. Specify where cells lie before creating the cell population.");
78  }
79  else
80  {
81  // Create a set of node indices corresponding to empty sites.
82  // Note iterating over mCells is OK as it has the same order as location indices at this point (its just coppied from rCells)
83  std::list<CellPtr>::iterator it = this->mCells.begin();
84  for (unsigned i=0; it != this->mCells.end(); ++it, ++i)
85  {
86  assert(i < locationIndices.size());
87  if (!IsSiteAvailable(locationIndices[i],*it))
88  {
89  EXCEPTION("One of the lattice sites has more cells than the carrying capacity. Check the initial cell locations.");
90  }
91  mAvailableSpaces[locationIndices[i]]--;
92  }
93  }
94  if (validate)
95  {
96  EXCEPTION("There is no validation for CaBasedCellPopulation.");
97  }
98 }
99 
100 template<unsigned DIM>
102  : AbstractOnLatticeCellPopulation<DIM>(rMesh)
103 {
104 }
105 
106 template<unsigned DIM>
108 {
109  if (this->mDeleteMesh)
110  {
111  delete &this->mrMesh;
112  }
113 }
114 
115 template<unsigned DIM>
117 {
118  return mAvailableSpaces;
119 }
120 
121 template<unsigned DIM>
122 bool CaBasedCellPopulation<DIM>::IsSiteAvailable(unsigned index, CellPtr pCell)
123 {
125  return (mAvailableSpaces[index] != 0);
126 }
127 
128 template<unsigned DIM>
130 {
131  return static_cast<PottsMesh<DIM>& >((this->mrMesh));
132 }
133 
134 template<unsigned DIM>
136 {
137  return static_cast<PottsMesh<DIM>& >((this->mrMesh));
138 }
139 
140 template<unsigned DIM>
142 {
143  std::vector<Node<DIM>*> temp_nodes;
144 
145  // Create nodes at the centre of the cells
146  unsigned cell_index = 0;
147  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
148  cell_iter != this->End();
149  ++cell_iter)
150  {
151  temp_nodes.push_back(new Node<DIM>(cell_index, this->GetLocationOfCellCentre(*cell_iter)));
152  cell_index++;
153  }
154 
155  return new MutableMesh<DIM,DIM>(temp_nodes);
156 }
157 
158 template<unsigned DIM>
160 {
161  return this->mrMesh.GetNode(index);
162 }
163 
164 template<unsigned DIM>
166 {
167  return this->mrMesh.GetNumNodes();
168 }
169 
170 template<unsigned DIM>
172 {
173  unsigned index = this->GetLocationIndexUsingCell(pCell);
174  std::set<unsigned> candidates = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(index);
175 
176  std::set<unsigned> neighbour_indices;
177  for (std::set<unsigned>::iterator iter = candidates.begin();
178  iter != candidates.end();
179  ++iter)
180  {
181  if (!IsSiteAvailable(*iter, pCell))
182  {
183  neighbour_indices.insert(*iter);
184  }
185  }
186 
187  return neighbour_indices;
188 }
189 
190 template<unsigned DIM>
191 c_vector<double, DIM> CaBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
192 {
193  return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell))->rGetLocation();
194 }
195 
196 template<unsigned DIM>
198 {
199  return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell));
200 }
201 
202 template<unsigned DIM>
203 void CaBasedCellPopulation<DIM>::AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
204 {
205  if (!IsSiteAvailable(index, pCell))
206  {
207  EXCEPTION("No available spaces at location index " << index << ".");
208  }
209 
210  mAvailableSpaces[index]--;
212 }
213 
214 template<unsigned DIM>
216 {
218 
219  mAvailableSpaces[index]++;
220 
221  assert(mAvailableSpaces[index] <= mLatticeCarryingCapacity);
222 }
223 
224 template<unsigned DIM>
226 {
227  return mpCaBasedDivisionRule->IsRoomToDivide(pCell, *this);
228 }
229 
230 template<unsigned DIM>
231 CellPtr CaBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, CellPtr pParentCell)
232 {
233  unsigned daughter_node_index = mpCaBasedDivisionRule->CalculateDaughterNodeIndex(pNewCell,pParentCell,*this);
234 
235  // Associate the new cell with the neighbouring node
236  this->mCells.push_back(pNewCell);
237 
238  // Update location cell map
239  CellPtr p_created_cell = this->mCells.back();
240  AddCellUsingLocationIndex(daughter_node_index,p_created_cell);
241 
242  return p_created_cell;
243 }
244 
245 template<unsigned DIM>
247  unsigned targetNodeIndex,
248  CellPtr pCell)
249 {
250  return 1.0;
251 }
252 
253 template<unsigned DIM>
255 {
256  unsigned num_removed = 0;
257 
258  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
259  cell_iter != this->mCells.end();
260  )
261  {
262  if ((*cell_iter)->IsDead())
263  {
264  // Get the location index corresponding to this cell
265  unsigned location_index = this->GetLocationIndexUsingCell(*cell_iter);
266 
267  // Use this to remove the cell from the population
268  RemoveCellUsingLocationIndex(location_index, (*cell_iter));
269 
270  // Erase cell and update counter
271  cell_iter = this->mCells.erase(cell_iter);
272  num_removed++;
273  }
274  else
275  {
276  ++cell_iter;
277  }
278  }
279  return num_removed;
280 }
281 
282 template<unsigned DIM>
284 {
285  /*
286  * Here we loop over the nodes and calculate the probability of moving
287  * and then select the node to move to.
288  */
289  if (!(this->mUpdateRuleCollection.empty()))
290  {
291  // Iterate over cells
293  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
294  cell_iter != this->mCells.end();
295  ++cell_iter)
296  {
297  // Loop over neighbours and calculate probability of moving (make sure all probabilities are <1)
298  unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
299 
300  // Find a random available neighbouring node to overwrite current site
301  std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
302  std::vector<double> neighbouring_node_propensities;
303  std::vector<unsigned> neighbouring_node_indices_vector;
304 
305  if (!neighbouring_node_indices.empty())
306  {
307  unsigned num_neighbours = neighbouring_node_indices.size();
308  double probability_of_not_moving = 1.0;
309 
310  for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
311  iter != neighbouring_node_indices.end();
312  ++iter)
313  {
314  double probability_of_moving = 0.0;
315 
316  neighbouring_node_indices_vector.push_back(*iter);
317 
318  if (IsSiteAvailable(*iter, *cell_iter))
319  {
320  // Iterating over the update rule
321  for (typename std::vector<boost::shared_ptr<AbstractUpdateRule<DIM> > >::iterator iter_rule = this->mUpdateRuleCollection.begin();
322  iter_rule != this->mUpdateRuleCollection.end();
323  ++iter_rule)
324  {
325  // This static cast is fine, since we assert the update rule must be a CA update rule in AddUpdateRule()
326  double p = (boost::static_pointer_cast<AbstractCaUpdateRule<DIM> >(*iter_rule))->EvaluateProbability(node_index, *iter, *this, dt, 1, *cell_iter);
327  probability_of_moving += p;
328  if (probability_of_moving < 0)
329  {
330  EXCEPTION("The probability of cellular movement is smaller than zero. In order to prevent it from happening you should change your time step and parameters");
331  }
332 
333  if (probability_of_moving > 1)
334  {
335  EXCEPTION("The probability of the cellular movement is bigger than one. In order to prevent it from happening you should change your time step and parameters");
336  }
337  }
338 
339  probability_of_not_moving -= probability_of_moving;
340  neighbouring_node_propensities.push_back(probability_of_moving);
341  }
342  else
343  {
344  neighbouring_node_propensities.push_back(0.0);
345  }
346  }
347  if (probability_of_not_moving < 0)
348  {
349  EXCEPTION("The probability of the cell not moving is smaller than zero. In order to prevent it from happening you should change your time step and parameters");
350  }
351 
352  // Sample random number to specify which move to make
354  double random_number = p_gen->ranf();
355 
356  double total_probability = 0.0;
357  for (unsigned counter=0; counter<num_neighbours; counter++)
358  {
359  total_probability += neighbouring_node_propensities[counter];
360  if (total_probability >= random_number)
361  {
362  // Move the cell to this neighbour location
363  unsigned chosen_neighbour_location_index = neighbouring_node_indices_vector[counter];
364  this->MoveCellInLocationMap((*cell_iter), node_index, chosen_neighbour_location_index);
365  break;
366  }
367  }
368  // If loop completes with total_probability < random_number then stay in the same location
369  }
370  else
371  {
372  // Each node in the mesh must have at least one neighbour
374  }
375  }
376  }
377 
378  /*
379  * Here we loop over the nodes and select a neighbour to test if
380  * the cells (associated with the nodes) should swap locations
381  * or if a cell should move to an empty node
382  * Note this currently only works for latticeCarryingCapacity = 1
383  */
384  if (!(mSwitchingUpdateRuleCollection.empty()))
385  {
386  assert(mLatticeCarryingCapacity == 1);
387 
389  unsigned num_nodes = this->mrMesh.GetNumNodes();
390 
391  // Randomly permute mUpdateRuleCollection if specified
393  {
394  // Randomly permute mUpdateRuleCollection
396  }
397 
398  for (unsigned i=0; i<num_nodes; i++)
399  {
400  unsigned node_index;
401 
402  if (this->mUpdateNodesInRandomOrder)
403  {
404  node_index = p_gen->randMod(num_nodes);
405  }
406  else
407  {
408  // Loop over nodes in index order
409  node_index = i%num_nodes;
410  }
411 
412  // Find a random available neighbouring node to switch cells with the current site
413  std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
414 
415  unsigned neighbour_location_index;
416 
417  if (!neighbouring_node_indices.empty())
418  {
419  unsigned num_neighbours = neighbouring_node_indices.size();
420  unsigned chosen_neighbour = p_gen->randMod(num_neighbours);
421 
422  std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
423  for (unsigned j=0; j<chosen_neighbour; j++)
424  {
425  neighbour_iter++;
426  }
427  neighbour_location_index = *neighbour_iter;
428 
429  bool is_cell_on_node_index = mAvailableSpaces[node_index] == 0 ? true : false;
430  bool is_cell_on_neighbour_location_index = mAvailableSpaces[neighbour_location_index] == 0 ? true : false;
431 
432  if (is_cell_on_node_index || is_cell_on_neighbour_location_index)
433  {
434  double probability_of_switch = 0.0;
435 
436  // Now add contributions to the probability from each CA switching update rule
437  for (typename std::vector<boost::shared_ptr<AbstractUpdateRule<DIM> > >::iterator iter_rule = mSwitchingUpdateRuleCollection.begin();
438  iter_rule != mSwitchingUpdateRuleCollection.end();
439  ++iter_rule)
440  {
441  // This static cast is fine, since we assert the update rule must be a CA switching update rule in AddUpdateRule()
442  double p = (boost::static_pointer_cast<AbstractCaSwitchingUpdateRule<DIM> >(*iter_rule))->EvaluateSwitchingProbability(node_index, neighbour_location_index, *this, dt, 1);
443  probability_of_switch += p;
444  }
445 
446  assert(probability_of_switch >= 0);
447  assert(probability_of_switch <= 1);
448 
449  // Generate a uniform random number to do the random switch
450  double random_number = p_gen->ranf();
451 
452  if (random_number < probability_of_switch)
453  {
454  if (is_cell_on_node_index && is_cell_on_neighbour_location_index)
455  {
456  // Swap the cells associated with the node and the neighbour node
457  CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
458  CellPtr p_neighbour_cell = this->GetCellUsingLocationIndex(neighbour_location_index);
459 
460  // Remove the cells from their current location
461  RemoveCellUsingLocationIndex(node_index, p_cell);
462  RemoveCellUsingLocationIndex(neighbour_location_index, p_neighbour_cell);
463 
464  // Add cells to their new locations
465  AddCellUsingLocationIndex(node_index, p_neighbour_cell);
466  AddCellUsingLocationIndex(neighbour_location_index, p_cell);
467  }
468  else if (is_cell_on_node_index && !is_cell_on_neighbour_location_index)
469  {
470  // Move the cells associated with the node to the neighbour node
471  CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
472  RemoveCellUsingLocationIndex(node_index, p_cell);
473  AddCellUsingLocationIndex(neighbour_location_index, p_cell);
474  }
475  else if (!is_cell_on_node_index && is_cell_on_neighbour_location_index)
476  {
477  // Move the cell associated with the neighbour node onto the node
478  CellPtr p_neighbour_cell = this->GetCellUsingLocationIndex(neighbour_location_index);
479  RemoveCellUsingLocationIndex(neighbour_location_index, p_neighbour_cell);
480  AddCellUsingLocationIndex(node_index, p_neighbour_cell);
481  }
482  else
483  {
485  }
486  }
487  }
488  }
489  }
490  }
491 }
492 
493 template<unsigned DIM>
495 {
496  return false;
497 }
498 
499 template<unsigned DIM>
500 void CaBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
501 {
502 }
503 
504 template<unsigned DIM>
506 {
507  pPopulationWriter->Visit(this);
508 }
509 
510 template<unsigned DIM>
512 {
513  pPopulationCountWriter->Visit(this);
514 }
515 
516 template<unsigned DIM>
517 void CaBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
518 {
519  pCellWriter->VisitCell(pCell, this);
520 }
521 
522 template<unsigned DIM>
524 {
526  {
527  if (!this-> template HasWriter<CellLocationIndexWriter>())
528  {
529  this-> template AddCellWriter<CellLocationIndexWriter>();
530  }
531  }
532 
534 }
535 
536 template<unsigned DIM>
538 {
539  double cell_volume = 1.0;
540  return cell_volume;
541 }
542 
543 template<unsigned DIM>
544 double CaBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
545 {
546  double width = this->mrMesh.GetWidth(rDimension);
547  return width;
548 }
549 
550 template<unsigned DIM>
552 {
553  // The update rule must be derived from AbstractCaUpdateRule or AbstractCaSwitchingUpdateRule
554  assert(bool(dynamic_cast<AbstractCaUpdateRule<DIM>*>(pUpdateRule.get())) ||
555  bool(dynamic_cast<AbstractCaSwitchingUpdateRule<DIM>*>(pUpdateRule.get())));
556 
557  if (bool(dynamic_cast<AbstractCaUpdateRule<DIM>*>(pUpdateRule.get())))
558  {
559  this->mUpdateRuleCollection.push_back(pUpdateRule);
560  }
561  else
562  {
563  mSwitchingUpdateRuleCollection.push_back(pUpdateRule);
564  }
565 }
566 
567 template<unsigned DIM>
569 {
570  // Clear mSwitchingUpdateRuleCollection
572 
573  // Clear mUpdateRuleCollection
575 }
576 
577 template<unsigned DIM>
578 const std::vector<boost::shared_ptr<AbstractUpdateRule<DIM> > > CaBasedCellPopulation<DIM>::GetUpdateRuleCollection() const
579 {
580  std::vector<boost::shared_ptr<AbstractUpdateRule<DIM> > > update_rules;
581 
582  for (unsigned i=0; i<this->mUpdateRuleCollection.size(); i++)
583  {
584  update_rules.push_back(this->mUpdateRuleCollection[i]);
585  }
586  for (unsigned i=0; i<mSwitchingUpdateRuleCollection.size(); i++)
587  {
588  update_rules.push_back(mSwitchingUpdateRuleCollection[i]);
589  }
590 
591  return update_rules;
592 }
593 
594 template<unsigned DIM>
595 boost::shared_ptr<AbstractCaBasedDivisionRule<DIM> > CaBasedCellPopulation<DIM>::GetCaBasedDivisionRule()
596 {
597  return mpCaBasedDivisionRule;
598 }
599 
600 template<unsigned DIM>
602 {
603  mpCaBasedDivisionRule = pCaBasedDivisionRule;
604 }
605 
606 template<unsigned DIM>
608 {
609  // Add the division rule parameters
610  *rParamsFile << "\t\t<CaBasedDivisionRule>\n";
611  mpCaBasedDivisionRule->OutputCellCaBasedDivisionRuleInfo(rParamsFile);
612  *rParamsFile << "\t\t</CaBasedDivisionRule>\n";
613 
614  // Call method on direct parent class
616 }
617 
618 template<unsigned DIM>
619 void CaBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
620 {
621 #ifdef CHASTE_VTK
622  // Store the present time as a string
623  unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
624  std::stringstream time;
625  time << num_timesteps;
626 
627  // Store the number of cells for which to output data to VTK
628  unsigned num_cells = this->GetNumRealCells();
629 
630  // When outputting any CellData, we assume that the first cell is representative of all cells
631  unsigned num_cell_data_items = 0u;
632  std::vector<std::string> cell_data_names;
633  if (num_cells > 0u)
634  {
635  num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
636  cell_data_names = this->Begin()->GetCellData()->GetKeys();
637  }
638  std::vector<std::vector<double> > cell_data;
639  for (unsigned var=0; var<num_cell_data_items; var++)
640  {
641  std::vector<double> cell_data_var(num_cells);
642  cell_data.push_back(cell_data_var);
643  }
644 
645  // Create mesh writer for VTK output
646  VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
647 
648  // Create a counter to keep track of how many cells are at a lattice site
649  unsigned num_sites = this->mrMesh.GetNumNodes();
650  boost::scoped_array<unsigned> number_of_cells_at_site(new unsigned[num_sites]);
651  for (unsigned i=0; i<num_sites; i++)
652  {
653  number_of_cells_at_site[i] = 0;
654  }
655 
656  // Populate a vector of nodes associated with cell locations, by iterating through the list of cells
657  std::vector<Node<DIM>*> nodes;
658  unsigned node_index = 0;
659  for (typename AbstractCellPopulation<DIM,DIM>::Iterator cell_iter = this->Begin();
660  cell_iter != this->End();
661  ++cell_iter)
662  {
663  // Get the location index of this cell and update the counter number_of_cells_at_site
664  unsigned location_index = this->GetLocationIndexUsingCell(*cell_iter);
665  number_of_cells_at_site[location_index]++;
666  assert(number_of_cells_at_site[location_index] <= mLatticeCarryingCapacity);
667 
668  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
669  c_vector<double, DIM> coords;
670  coords = this->mrMesh.GetNode(location_index)->rGetLocation();
671 
672  // Move the coordinates slightly so that we can visualise all cells in a lattice site if there is more than one per site
673  if (mLatticeCarryingCapacity > 1)
674  {
675  c_vector<double, DIM> offset;
676 
677  if (DIM == 2)
678  {
679  double angle = (double)number_of_cells_at_site[location_index]*2.0*M_PI/(double)mLatticeCarryingCapacity;
680  offset[0] = 0.2*sin(angle);
681  offset[1] = 0.2*cos(angle);
682  }
683  else
684  {
686  for (unsigned i=0; i<DIM; i++)
687  {
688  offset[i] = p_gen->ranf(); // This assumes that all sites are 1 unit apart
689  }
690  }
691 
692  for (unsigned i=0; i<DIM; i++)
693  {
694  coords[i] += offset[i];
695  }
696  }
697 
698  nodes.push_back(new Node<DIM>(node_index, coords, false));
699  node_index++;
700  }
701 
702  // Iterate over any cell writers that are present
703  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
704  cell_writer_iter != this->mCellWriters.end();
705  ++cell_writer_iter)
706  {
707  // Create vector to store VTK cell data
708  // (using a default value of -1 to correspond to an empty lattice site)
709  std::vector<double> vtk_cell_data(num_cells, -1.0);
710 
711  // Loop over cells
712  unsigned cell_index = 0;
713  for (typename AbstractCellPopulation<DIM,DIM>::Iterator cell_iter = this->Begin();
714  cell_iter != this->End();
715  ++cell_iter)
716  {
717  // Populate the vector of VTK cell data
718  vtk_cell_data[cell_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter, this);
719  cell_index++;
720  }
721 
722  mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
723  }
724 
725  // Loop over cells to output the cell data
726  unsigned cell_index = 0;
727  for (typename AbstractCellPopulation<DIM,DIM>::Iterator cell_iter = this->Begin();
728  cell_iter != this->End();
729  ++cell_iter)
730  {
731  for (unsigned var=0; var<num_cell_data_items; var++)
732  {
733  cell_data[var][cell_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
734  }
735  cell_index++;
736  }
737  for (unsigned var=0; var<num_cell_data_items; var++)
738  {
739  mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
740  }
741 
742  /*
743  * At present, the VTK writer can only write things which inherit from AbstractTetrahedralMeshWriter.
744  * For now, we do an explicit conversion to NodesOnlyMesh. This can be written to VTK, then visualized
745  * as glyphs in Paraview.
746  */
747  NodesOnlyMesh<DIM> temp_mesh;
748 
749  // Use an approximation of the node spacing as the interaction distance for the nodes only mesh. This is to
750  // avoid rounding errors in distributed box collection.
751  double volume = this->mrMesh.GetWidth(0);
752  for (unsigned idx=1; idx<DIM; idx++)
753  {
754  volume *= this->mrMesh.GetWidth(idx);
755  }
756 
757  double spacing;
758  if (this->mrMesh.GetNumNodes() >0 && volume > 0.0)
759  {
760  spacing = std::pow(volume / double(this->mrMesh.GetNumNodes()), 1.0/double(DIM));
761  }
762  else
763  {
764  spacing = 1.0;
765  }
766 
767  temp_mesh.ConstructNodesWithoutMesh(nodes, spacing * 1.2);
768  mesh_writer.WriteFilesUsingMesh(temp_mesh);
769 
770  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
771  *(this->mpVtkMetaFile) << num_timesteps;
772  *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
773  *(this->mpVtkMetaFile) << num_timesteps;
774  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
775 
776  // Tidy up
777  for (unsigned i=0; i<nodes.size(); i++)
778  {
779  delete nodes[i];
780  }
781 #endif //CHASTE_VTK
782 }
783 
784 template<unsigned DIM>
786  unsigned pdeNodeIndex,
787  std::string& rVariableName,
788  bool dirichletBoundaryConditionApplies,
789  double dirichletBoundaryValue)
790 {
791  unsigned counter = 0;
792  typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
793  while (counter != pdeNodeIndex)
794  {
795  ++cell_iter;
796  counter++;
797  }
798 
799  double value = cell_iter->GetCellData()->GetItem(rVariableName);
800 
801  return value;
802 }
803 
804 template<unsigned DIM>
806 {
807  // pdeNodeIndex corresponds to the 'position' of the cell to interrogate in the vector of cells
808  typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
809 
810  assert(pdeNodeIndex < this->GetNumRealCells());
811  for (unsigned i=0; i<pdeNodeIndex; i++)
812  {
813  ++cell_iter;
814  }
815  bool is_cell_apoptotic = cell_iter->template HasCellProperty<ApoptoticCellProperty>();
816 
817  return !is_cell_apoptotic;
818 }
819 
820 // Explicit instantiation
821 template class CaBasedCellPopulation<1>;
822 template class CaBasedCellPopulation<2>;
823 template class CaBasedCellPopulation<3>;
824 
825 // Serialization for Boost >= 1.36
bool IsCellAssociatedWithADeletedLocation(CellPtr pCell)
boost::shared_ptr< AbstractCaBasedDivisionRule< DIM > > GetCaBasedDivisionRule()
std::vector< unsigned > mAvailableSpaces
unsigned randMod(unsigned base)
std::vector< unsigned > & rGetAvailableSpaces()
void AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
virtual double EvaluateDivisionPropensity(unsigned currentNodeIndex, unsigned targetNodeIndex, CellPtr pCell)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
Definition: Node.hpp:58
PottsMesh< DIM > & rGetMesh()
unsigned GetLocationIndexUsingCell(CellPtr pCell)
void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual bool IsPdeNodeAssociatedWithNonApoptoticCell(unsigned pdeNodeIndex)
std::vector< boost::shared_ptr< AbstractCellWriter< ELEMENT_DIM, ELEMENT_DIM > > > mCellWriters
virtual void RemoveCellUsingLocationIndex(unsigned index, CellPtr pCell)
Node< DIM > * GetNode(unsigned index)
Node< SPACE_DIM > * GetNode(unsigned index) const
#define EXCEPTION(message)
Definition: Exception.hpp:143
virtual void AcceptPopulationCountWriter(boost::shared_ptr< AbstractCellPopulationCountWriter< DIM, DIM > > pPopulationCountWriter)
static SimulationTime * Instance()
virtual bool IsSiteAvailable(unsigned index, CellPtr pCell)
boost::shared_ptr< AbstractCaBasedDivisionRule< DIM > > mpCaBasedDivisionRule
virtual unsigned GetNumNodes() const
unsigned GetTimeStepsElapsed() const
std::set< unsigned > GetMooreNeighbouringNodeIndices(unsigned nodeIndex)
Definition: PottsMesh.cpp:233
virtual void OutputCellPopulationParameters(out_stream &rParamsFile)
void RemoveCellUsingLocationIndex(unsigned index, CellPtr pCell)
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
#define NEVER_REACHED
Definition: Exception.hpp:206
CaBasedCellPopulation(PottsMesh< DIM > &rMesh, std::vector< CellPtr > &rCells, const std::vector< unsigned > locationIndices, unsigned latticeCarryingCapacity=1u, bool deleteMesh=false, bool validate=false)
void MoveCellInLocationMap(CellPtr pCell, unsigned old_index, unsigned new_index)
void Shuffle(std::vector< boost::shared_ptr< T > > &rValues)
bool IsRoomToDivide(CellPtr pCell)
virtual TetrahedralMesh< DIM, DIM > * GetTetrahedralMeshForPdeModifier()
void SetCaBasedDivisionRule(boost::shared_ptr< AbstractCaBasedDivisionRule< DIM > > pCaBasedDivisionRule)
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
std::set< unsigned > GetNeighbouringLocationIndices(CellPtr pCell)
std::vector< boost::shared_ptr< AbstractUpdateRule< DIM > > > mUpdateRuleCollection
void Update(bool hasHadBirthsOrDeaths=true)
static RandomNumberGenerator * Instance()
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
virtual double GetCellDataItemAtPdeNode(unsigned pdeNodeIndex, std::string &rVariableName, bool dirichletBoundaryConditionApplies=false, double dirichletBoundaryValue=0.0)
void ConstructNodesWithoutMesh(const std::vector< Node< SPACE_DIM > * > &rNodes, double maxInteractionDistance)
std::vector< boost::shared_ptr< AbstractUpdateRule< DIM > > > mSwitchingUpdateRuleCollection
virtual double GetWidth(const unsigned &rDimension) const
Node< DIM > * GetNodeCorrespondingToCell(CellPtr pCell)
c_vector< double, DIM > GetLocationOfCellCentre(CellPtr pCell)
double GetWidth(const unsigned &rDimension)
virtual void AcceptPopulationWriter(boost::shared_ptr< AbstractCellPopulationWriter< DIM, DIM > > pPopulationWriter)
double GetVolumeOfCell(CellPtr pCell)
virtual void AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
CellPtr AddCell(CellPtr pNewCell, CellPtr pParentCell=CellPtr())
AbstractMesh< ELEMENT_DIM, ELEMENT_DIM > & mrMesh
virtual void AddUpdateRule(boost::shared_ptr< AbstractUpdateRule< DIM > > pUpdateRule)
virtual void AcceptCellWriter(boost::shared_ptr< AbstractCellWriter< DIM, DIM > > pCellWriter, CellPtr pCell)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
virtual const std::vector< boost::shared_ptr< AbstractUpdateRule< DIM > > > GetUpdateRuleCollection() const