Chaste  Release::2017.1
PottsBasedCellPopulation.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 "PottsBasedCellPopulation.hpp"
37 #include "RandomNumberGenerator.hpp"
38 #include "AbstractPottsUpdateRule.hpp"
39 #include "NodesOnlyMesh.hpp"
40 #include "CellPopulationElementWriter.hpp"
41 #include "CellIdWriter.hpp"
42 
43 // Needed to convert mesh in order to write nodes to VTK (visualize as glyphs)
44 #include "VtkMeshWriter.hpp"
45 
46 template<unsigned DIM>
48 {
49  // Check each element has only one cell associated with it
50  std::vector<unsigned> validated_element = std::vector<unsigned>(this->GetNumElements(), 0);
51 
52  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
53  cell_iter != this->End();
54  ++cell_iter)
55  {
56  unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter);
57  validated_element[elem_index]++;
58  }
59 
60  for (unsigned i=0; i<validated_element.size(); i++)
61  {
62  if (validated_element[i] == 0)
63  {
64  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Element " << i << " does not appear to have a cell associated with it");
65  }
66 
67  if (validated_element[i] > 1)
68  {
69  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Element " << i << " appears to have " << validated_element[i] << " cells associated with it");
70  }
71  }
72 }
73 
74 template<unsigned DIM>
76  std::vector<CellPtr>& rCells,
77  bool deleteMesh,
78  bool validate,
79  const std::vector<unsigned> locationIndices)
80  : AbstractOnLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh),
81  mpElementTessellation(nullptr),
82  mpMutableMesh(nullptr),
83  mTemperature(0.1),
84  mNumSweepsPerTimestep(1)
85 {
86  mpPottsMesh = static_cast<PottsMesh<DIM>* >(&(this->mrMesh));
87  // Check each element has only one cell associated with it
88  if (validate)
89  {
90  Validate();
91  }
92 }
93 
94 template<unsigned DIM>
96  : AbstractOnLatticeCellPopulation<DIM>(rMesh),
97  mpElementTessellation(nullptr),
98  mpMutableMesh(nullptr),
99  mTemperature(0.1),
101 {
102  mpPottsMesh = static_cast<PottsMesh<DIM>* >(&(this->mrMesh));
103 }
104 
105 template<unsigned DIM>
107 {
108  delete mpElementTessellation;
109 
110  delete mpMutableMesh;
111 
112  if (this->mDeleteMesh)
113  {
114  delete &this->mrMesh;
115  }
116 }
117 
118 template<unsigned DIM>
120 {
121  return *mpPottsMesh;
122 }
123 
124 template<unsigned DIM>
126 {
127  return *mpPottsMesh;
128 }
129 
130 template<unsigned DIM>
132 {
133  std::vector<Node<DIM>*> temp_nodes;
134 
135  // Create nodes at the centre of the cells
136  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
137  cell_iter != this->End();
138  ++cell_iter)
139  {
140  unsigned index = this->GetLocationIndexUsingCell(*cell_iter);
141  c_vector<double, DIM> location = this->GetLocationOfCellCentre(*cell_iter);
142  temp_nodes.push_back(new Node<DIM>(index, location));
143  }
144 
145  return new MutableMesh<DIM, DIM>(temp_nodes);
146 }
147 
148 template<unsigned DIM>
150 {
151  return mpPottsMesh->GetElement(elementIndex);
152 }
153 
154 template<unsigned DIM>
156 {
157  return mpPottsMesh->GetNumElements();
158 }
159 
160 template<unsigned DIM>
162 {
163  return this->mrMesh.GetNode(index);
164 }
165 
166 template<unsigned DIM>
168 {
169  return this->mrMesh.GetNumNodes();
170 }
171 
172 template<unsigned DIM>
174 {
175  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
176  return mpPottsMesh->GetNeighbouringElementIndices(elem_index);
177 }
178 
179 template<unsigned DIM>
180 c_vector<double, DIM> PottsBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
181 {
182  return mpPottsMesh->GetCentroidOfElement(this->GetLocationIndexUsingCell(pCell));
183 }
184 
185 template<unsigned DIM>
187 {
188  return mpPottsMesh->GetElement(this->GetLocationIndexUsingCell(pCell));
189 }
190 
191 template<unsigned DIM>
192 CellPtr PottsBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, CellPtr pParentCell)
193 {
194  // Get the element associated with this cell
195  PottsElement<DIM>* p_element = GetElementCorrespondingToCell(pParentCell);
196 
197  // Divide the element
198  unsigned new_element_index = mpPottsMesh->DivideElement(p_element, true); // new element will be below the existing element
199 
200  // Associate the new cell with the element
201  this->mCells.push_back(pNewCell);
202 
203  // Update location cell map
204  CellPtr p_created_cell = this->mCells.back();
205  this->SetCellUsingLocationIndex(new_element_index,p_created_cell);
206  return p_created_cell;
207 }
208 
209 template<unsigned DIM>
211 {
212  unsigned num_removed = 0;
213 
214  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
215  cell_iter != this->mCells.end();
216  )
217  {
218  if ((*cell_iter)->IsDead())
219  {
220  // Get the location index corresponding to this cell
221  unsigned location_index = this->GetLocationIndexUsingCell(*cell_iter);
222 
223  // Use this to remove the cell from the population
224  mpPottsMesh->DeleteElement(location_index);
225 
226  // Erase cell and update counter
227  cell_iter = this->mCells.erase(cell_iter);
228  num_removed++;
229  }
230  else
231  {
232  ++cell_iter;
233  }
234  }
235  return num_removed;
236 }
237 
238 template<unsigned DIM>
240 {
241  /*
242  * This method implements a Monte Carlo method to update the cell population.
243  * We sample randomly from all nodes in the mesh. Once we have selected a target
244  * node we randomly select a neighbour. The Hamiltonian is evaluated in the
245  * current configuration (H_0) and with the target node added to the same
246  * element as the neighbour (H_1). Based on the vale of deltaH = H_1 - H_0,
247  * the switch is either made or not.
248  *
249  * For each time step (i.e. each time this method is called) we sample
250  * mrMesh.GetNumNodes() nodes. This is known as a Monte Carlo Step (MCS).
251  */
252 
254  unsigned num_nodes = this->mrMesh.GetNumNodes();
255 
256  // Randomly permute mUpdateRuleCollection if specified
258  {
259  // Randomly permute mUpdateRuleCollection
260  p_gen->Shuffle(this->mUpdateRuleCollection);
261  }
262 
263  for (unsigned i=0; i<num_nodes*mNumSweepsPerTimestep; i++)
264  {
265  unsigned node_index;
266 
267  if (this->mUpdateNodesInRandomOrder)
268  {
269  node_index = p_gen->randMod(num_nodes);
270  }
271  else
272  {
273  // Loop over nodes in index order.
274  node_index = i%num_nodes;
275  }
276 
277  Node<DIM>* p_node = this->mrMesh.GetNode(node_index);
278 
279  // Each node in the mesh must be in at most one element
280  assert(p_node->GetNumContainingElements() <= 1);
281 
282  // Find a random available neighbouring node to overwrite current site
283  std::set<unsigned> neighbouring_node_indices = mpPottsMesh->GetMooreNeighbouringNodeIndices(node_index);
284  unsigned neighbour_location_index;
285 
286  if (!neighbouring_node_indices.empty())
287  {
288  unsigned num_neighbours = neighbouring_node_indices.size();
289  unsigned chosen_neighbour = p_gen->randMod(num_neighbours);
290 
291  std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
292  for (unsigned j=0; j<chosen_neighbour; j++)
293  {
294  neighbour_iter++;
295  }
296 
297  neighbour_location_index = *neighbour_iter;
298 
299  std::set<unsigned> containing_elements = p_node->rGetContainingElementIndices();
300  std::set<unsigned> neighbour_containing_elements = GetNode(neighbour_location_index)->rGetContainingElementIndices();
301  // Only calculate Hamiltonian and update elements if the nodes are from different elements, or one is from the medium
302  if ((!containing_elements.empty() && neighbour_containing_elements.empty())
303  || (containing_elements.empty() && !neighbour_containing_elements.empty())
304  || (!containing_elements.empty() && !neighbour_containing_elements.empty() && *containing_elements.begin() != *neighbour_containing_elements.begin()))
305  {
306  double delta_H = 0.0; // This is H_1-H_0.
307 
308  // Now add contributions to the Hamiltonian from each AbstractPottsUpdateRule
309  for (typename std::vector<boost::shared_ptr<AbstractUpdateRule<DIM> > >::iterator iter = this->mUpdateRuleCollection.begin();
310  iter != this->mUpdateRuleCollection.end();
311  ++iter)
312  {
313  // This static cast is fine, since we assert the update rule must be a Potts update rule in AddUpdateRule()
314  double dH = (boost::static_pointer_cast<AbstractPottsUpdateRule<DIM> >(*iter))->EvaluateHamiltonianContribution(neighbour_location_index, p_node->GetIndex(), *this);
315  delta_H += dH;
316  }
317 
318  // Generate a uniform random number to do the random motion
319  double random_number = p_gen->ranf();
320 
321  double p = exp(-delta_H/mTemperature);
322  if (delta_H <= 0 || random_number < p)
323  {
324  // Do swap
325 
326  // Remove the current node from any elements containing it (there should be at most one such element)
327  for (std::set<unsigned>::iterator iter = containing_elements.begin();
328  iter != containing_elements.end();
329  ++iter)
330  {
331  GetElement(*iter)->DeleteNode(GetElement(*iter)->GetNodeLocalIndex(node_index));
332 
334  }
335 
336  // Next add the current node to any elements containing the neighbouring node (there should be at most one such element)
337  for (std::set<unsigned>::iterator iter = neighbour_containing_elements.begin();
338  iter != neighbour_containing_elements.end();
339  ++iter)
340  {
341  GetElement(*iter)->AddNode(this->mrMesh.GetNode(node_index));
342  }
343  }
344  }
345  }
346  }
347 }
348 
349 template<unsigned DIM>
351 {
352  return GetElementCorrespondingToCell(pCell)->IsDeleted();
353 }
354 
355 template<unsigned DIM>
356 void PottsBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
357 {
358 }
359 
360 template<unsigned DIM>
362 {
364  {
365  if (!this-> template HasWriter<CellPopulationElementWriter>())
366  {
367  this-> template AddPopulationWriter<CellPopulationElementWriter>();
368  }
369  }
370  // Add a CellID writer so that a VTK file will contain IDs for visualisation. (It will also dump a "loggedcell.dat" file as a side-effect.)
371  this-> template AddCellWriter<CellIdWriter>();
372 
374 }
375 
376 template<unsigned DIM>
377 void PottsBasedCellPopulation<DIM>::WriteResultsToFiles(const std::string& rDirectory)
378 {
379  CreateElementTessellation(); // To be used to output to the visualizer
380 
382 }
383 
384 template<unsigned DIM>
386 {
387  pPopulationWriter->Visit(this);
388 }
389 
390 template<unsigned DIM>
392 {
393  pPopulationCountWriter->Visit(this);
394 }
395 
396 template<unsigned DIM>
397 void PottsBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
398 {
399  pCellWriter->VisitCell(pCell, this);
400 }
401 
402 template<unsigned DIM>
404 {
405  // Get element index corresponding to this cell
406  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
407 
408  // Get volume of this element in the Potts mesh
409  double cell_volume = mpPottsMesh->GetVolumeOfElement(elem_index);
410 
411  return cell_volume;
412 }
413 
414 template<unsigned DIM>
415 double PottsBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
416 {
417  // Call GetWidth() on the mesh
418  double width = this->mrMesh.GetWidth(rDimension);
419 
420  return width;
421 }
422 
423 template<unsigned DIM>
425 {
426  assert(bool(dynamic_cast<AbstractPottsUpdateRule<DIM>*>(pUpdateRule.get())));
427  this->mUpdateRuleCollection.push_back(pUpdateRule);
428 }
429 
430 template<unsigned DIM>
432 {
434 // delete mpElementTessellation;
435 //
436 // ///\todo this code would need to be extended if the domain were required to be periodic
437 //
438 // std::vector<Node<2>*> nodes;
439 // for (unsigned node_index=0; node_index<mrMesh.GetNumNodes(); node_index++)
440 // {
441 // Node<2>* p_temp_node = mrMesh.GetNode(node_index);
442 // nodes.push_back(p_temp_node);
443 // }
444 // MutableMesh<2,2> mesh(nodes);
445 // mpElementTessellation = new VertexMesh<2,2>(mesh);
446 }
447 
448 template<unsigned DIM>
450 {
451 // assert(mpElementTessellation != NULL);
452  return mpElementTessellation;
453 }
454 
455 template<unsigned DIM>
457 {
458  delete mpMutableMesh;
459 
460  // Get the nodes of the PottsMesh
461  std::vector<Node<DIM>*> nodes;
462  for (unsigned node_index=0; node_index<this->mrMesh.GetNumNodes(); node_index++)
463  {
464  const c_vector<double, DIM>& r_location = this->mrMesh.GetNode(node_index)->rGetLocation();
465  nodes.push_back(new Node<DIM>(node_index, r_location));
466  }
467 
468  mpMutableMesh = new MutableMesh<DIM,DIM>(nodes);
469 }
470 
471 template<unsigned DIM>
473 {
474  assert(mpMutableMesh);
475  return mpMutableMesh;
476 }
477 
478 template<unsigned DIM>
480 {
481  *rParamsFile << "\t\t<Temperature>" << mTemperature << "</Temperature>\n";
482  *rParamsFile << "\t\t<NumSweepsPerTimestep>" << mNumSweepsPerTimestep << "</NumSweepsPerTimestep>\n";
483 
484  // Call method on direct parent class
486 }
487 
488 template<unsigned DIM>
490 {
491  mTemperature = temperature;
492 }
493 
494 template<unsigned DIM>
496 {
497  return mTemperature;
498 }
499 
500 template<unsigned DIM>
502 {
503  mNumSweepsPerTimestep = numSweepsPerTimestep;
504 }
505 
506 template<unsigned DIM>
508 {
509  return mNumSweepsPerTimestep;
510 }
511 
512 template<unsigned DIM>
513 void PottsBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
514 {
515 #ifdef CHASTE_VTK
516  unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
517  std::stringstream time;
518  time << num_timesteps;
519 
520  // Create mesh writer for VTK output
521  VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
522 
523  // Iterate over any cell writers that are present
524  unsigned num_nodes = GetNumNodes();
525  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
526  cell_writer_iter != this->mCellWriters.end();
527  ++cell_writer_iter)
528  {
529  // Create vector to store VTK cell data
530  std::vector<double> vtk_cell_data(num_nodes);
531 
532  // Iterate over nodes in the mesh
533  for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mpPottsMesh->GetNodeIteratorBegin();
534  iter != mpPottsMesh->GetNodeIteratorEnd();
535  ++iter)
536  {
537  // Get the index of this node in the mesh and those elements (i.e. cells) that contain this node
538  unsigned node_index = iter->GetIndex();
539  std::set<unsigned> element_indices = iter->rGetContainingElementIndices();
540 
541  // If there are no elements associated with this node, then we set the value of any VTK cell data to be -1 at this node...
542  if (element_indices.empty())
543  {
544  // Populate the vector of VTK cell data
545  vtk_cell_data[node_index] = -1.0;
546  }
547  else
548  {
549  // ... otherwise there should be exactly one element (i.e. cell) containing this node
550  assert(element_indices.size() == 1);
551  unsigned elem_index = *(element_indices.begin());
552  CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
553 
554  // Populate the vector of VTK cell data
555  vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
556  }
557  }
558 
559  mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
560  }
561 
562  // When outputting any CellData, we assume that the first cell is representative of all cells
563  unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
564  std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
565 
566  std::vector<std::vector<double> > cell_data;
567  for (unsigned var=0; var<num_cell_data_items; var++)
568  {
569  std::vector<double> cell_data_var(num_nodes);
570  cell_data.push_back(cell_data_var);
571  }
572 
573  for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mpPottsMesh->GetNodeIteratorBegin();
574  iter != mpPottsMesh->GetNodeIteratorEnd();
575  ++iter)
576  {
577  // Get the index of this node in the mesh and those elements (i.e. cells) that contain this node
578  unsigned node_index = iter->GetIndex();
579  std::set<unsigned> element_indices = iter->rGetContainingElementIndices();
580 
581  // If there are no elements associated with this node, then we set the value of any VTK cell data to be -1 at this node...
582  if (element_indices.empty())
583  {
584  for (unsigned var=0; var<num_cell_data_items; var++)
585  {
586  cell_data[var][node_index] = -1.0;
587  }
588  }
589  else
590  {
591  // ... otherwise there should be exactly one element (i.e. cell) containing this node
592  assert(element_indices.size() == 1);
593  unsigned elem_index = *(element_indices.begin());
594  CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
595 
596  for (unsigned var=0; var<num_cell_data_items; var++)
597  {
598  cell_data[var][node_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
599  }
600  }
601  }
602  for (unsigned var=0; var<cell_data.size(); var++)
603  {
604  mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
605  }
606 
607  /*
608  * At present, the VTK writer can only write things which inherit from AbstractTetrahedralMeshWriter.
609  * For now, we do an explicit conversion to NodesOnlyMesh. This can be written to VTK, then visualized
610  * as glyphs in Paraview.
611  */
612  NodesOnlyMesh<DIM> temp_mesh;
613  temp_mesh.ConstructNodesWithoutMesh(*mpPottsMesh, 1.5); // This cut-off is arbitrary, as node connectivity is not used here
614  mesh_writer.WriteFilesUsingMesh(temp_mesh);
615 
616  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
617  *(this->mpVtkMetaFile) << num_timesteps;
618  *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
619  *(this->mpVtkMetaFile) << num_timesteps;
620  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
621 
622  // Extra part to output the outlines of cells
623  if (DIM ==2)
624  {
625  std::vector<Node<2>*> outline_nodes;
626  std::vector<VertexElement<2,2>*> outline_elements;
627 
628  unsigned outline_node_index = 0;
629  unsigned outline_element_index = 0;
630  for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mpPottsMesh->GetNodeIteratorBegin();
631  iter != mpPottsMesh->GetNodeIteratorEnd();
632  ++iter)
633  {
634  // Get the index of this node in the mesh and those elements (i.e. cells) that contain this node
635  unsigned node_index = iter->GetIndex();
636  std::set<unsigned> element_indices = iter->rGetContainingElementIndices();
637 
638  std::set<unsigned> target_neighbouring_node_indices = this->rGetMesh().GetVonNeumannNeighbouringNodeIndices(node_index);
639 
640  for (std::set<unsigned>::iterator neighbour_iter = target_neighbouring_node_indices.begin();
641  neighbour_iter != target_neighbouring_node_indices.end();
642  ++neighbour_iter)
643  {
644  std::set<unsigned> neighbouring_element_indices = this->rGetMesh().GetNode(*neighbour_iter)->rGetContainingElementIndices();
645 
646  // If different cells add a line
647  if (element_indices != neighbouring_element_indices)
648  {
649  std::vector<Node<2>*> element_nodes;
650 
651  const c_vector<double, 2>& r_node_location = this->mrMesh.GetNode(node_index)->rGetLocation();
652  const c_vector<double, 2>& r_neighbour_node_location = this->mrMesh.GetNode(*neighbour_iter)->rGetLocation();
653 
654  c_vector<double, 2> unit_tangent = r_neighbour_node_location - r_node_location;
655 
656  if (norm_2(unit_tangent) > 1.0) // It's a periodic neighbour
657  {
658  c_vector<double, 2> mid_point = 0.5*(r_node_location + r_neighbour_node_location);
659  if (unit_tangent(0) == 0)
660  {
661  if (r_node_location(1) < r_neighbour_node_location(1))
662  {
663  mid_point(1) = r_node_location(1) - 0.5;
664  }
665  else
666  {
667  mid_point(1) = r_node_location(1) + 0.5;
668  }
669  }
670  else
671  {
672  assert(unit_tangent(1) == 0);
673 
674  if (r_node_location(0) < r_neighbour_node_location(0))
675  {
676  mid_point(0) = r_node_location(0) - 0.5;
677  }
678  else
679  {
680  mid_point(0) = r_node_location(0) + 0.5;
681  }
682  }
683  assert(norm_2(unit_tangent) > 0);
684  unit_tangent = unit_tangent/norm_2(unit_tangent);
685 
686  c_vector<double, DIM> unit_normal;
687  unit_normal(0) = -unit_tangent(1);
688  unit_normal(1) = unit_tangent(0);
689 
690  std::vector<Node<2>*> element_nodes;
691 
692  // Need at least three points to visualise in Paraview
693  Node<2>* p_node_1 = new Node<2>(outline_node_index, mid_point - 0.5*unit_normal);
694  outline_nodes.push_back(p_node_1);
695  element_nodes.push_back(outline_nodes[outline_node_index]);
696  outline_node_index++;
697 
698  Node<2>* p_node_2 = new Node<2>(outline_node_index, mid_point);
699  outline_nodes.push_back(p_node_2);
700  element_nodes.push_back(outline_nodes[outline_node_index]);
701  outline_node_index++;
702 
703  Node<2>* p_node_3 = new Node<2>(outline_node_index, mid_point + 0.5*unit_normal);
704  outline_nodes.push_back(p_node_3);
705  element_nodes.push_back(outline_nodes[outline_node_index]);
706  outline_node_index++;
707 
708  VertexElement<2,2>* p_element = new VertexElement<2,2>(outline_element_index, element_nodes);
709  outline_elements.push_back(p_element);
710  outline_element_index++;
711 
712  }
713  else // Standard Neighbour
714  {
715  c_vector<double, 2> mid_point = 0.5*(r_node_location + r_neighbour_node_location);
716 
717  assert(norm_2(unit_tangent) > 0);
718  unit_tangent = unit_tangent/norm_2(unit_tangent);
719 
720  c_vector<double, 2> unit_normal;
721  unit_normal(0) = -unit_tangent(1);
722  unit_normal(1) = unit_tangent(0);
723 
724  std::vector<Node<2>*> element_nodes;
725 
726  // Need at least three points to visualise in Paraview
727  Node<2>* p_node_1 = new Node<2>(outline_node_index, mid_point - 0.5*unit_normal);
728  outline_nodes.push_back(p_node_1);
729  element_nodes.push_back(outline_nodes[outline_node_index]);
730  outline_node_index++;
731 
732  Node<2>* p_node_2 = new Node<2>(outline_node_index, mid_point);
733  outline_nodes.push_back(p_node_2);
734  element_nodes.push_back(outline_nodes[outline_node_index]);
735  outline_node_index++;
736 
737  Node<2>* p_node_3 = new Node<2>(outline_node_index, mid_point + 0.5*unit_normal);
738  outline_nodes.push_back(p_node_3);
739  element_nodes.push_back(outline_nodes[outline_node_index]);
740  outline_node_index++;
741 
742  VertexElement<2,2>* p_element = new VertexElement<2,2>(outline_element_index, element_nodes);
743  outline_elements.push_back(p_element);
744  outline_element_index++;
745  }
746  }
747  }
748  }
749  VertexMesh<2,2> cell_outline_mesh(outline_nodes,outline_elements);
750 
751  VertexMeshWriter<2, 2> outline_mesh_writer(rDirectory, "outlines", false);
752  outline_mesh_writer.WriteVtkUsingMesh(cell_outline_mesh, time.str());
753  outline_mesh_writer.WriteFilesUsingMesh(cell_outline_mesh);
754  }
755 #endif //CHASTE_VTK
756 }
757 
758 template<unsigned DIM>
760  unsigned pdeNodeIndex,
761  std::string& rVariableName,
762  bool dirichletBoundaryConditionApplies,
763  double dirichletBoundaryValue)
764 {
765  CellPtr p_cell = this->GetCellUsingLocationIndex(pdeNodeIndex);
766  double value = p_cell->GetCellData()->GetItem(rVariableName);
767  return value;
768 }
769 
770 // Explicit instantiation
771 template class PottsBasedCellPopulation<1>;
772 template class PottsBasedCellPopulation<2>;
773 template class PottsBasedCellPopulation<3>;
774 
775 // Serialization for Boost >= 1.36
unsigned randMod(unsigned base)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
Definition: Node.hpp:58
unsigned GetLocationIndexUsingCell(CellPtr pCell)
Node< DIM > * GetNode(unsigned index)
std::vector< boost::shared_ptr< AbstractCellWriter< ELEMENT_DIM, ELEMENT_DIM > > > mCellWriters
void WriteFilesUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
Node< SPACE_DIM > * GetNode(unsigned index) const
MutableMesh< DIM, DIM > * mpMutableMesh
#define EXCEPTION(message)
Definition: Exception.hpp:143
VertexMesh< DIM, DIM > * GetElementTessellation()
static SimulationTime * Instance()
std::set< unsigned > GetNeighbouringLocationIndices(CellPtr pCell)
PottsElement< DIM > * GetElementCorrespondingToCell(CellPtr pCell)
std::set< unsigned > & rGetContainingElementIndices()
Definition: Node.cpp:300
virtual unsigned GetNumNodes() const
unsigned GetTimeStepsElapsed() const
virtual void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual void AcceptPopulationCountWriter(boost::shared_ptr< AbstractCellPopulationCountWriter< DIM, DIM > > pPopulationCountWriter)
virtual void WriteResultsToFiles(const std::string &rDirectory)
virtual double GetCellDataItemAtPdeNode(unsigned pdeNodeIndex, std::string &rVariableName, bool dirichletBoundaryConditionApplies=false, double dirichletBoundaryValue=0.0)
void Shuffle(std::vector< boost::shared_ptr< T > > &rValues)
c_vector< double, DIM > GetLocationOfCellCentre(CellPtr pCell)
virtual void AcceptCellWriter(boost::shared_ptr< AbstractCellWriter< DIM, DIM > > pCellWriter, CellPtr pCell)
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
void SetCellUsingLocationIndex(unsigned index, CellPtr pCell)
std::vector< boost::shared_ptr< AbstractUpdateRule< DIM > > > mUpdateRuleCollection
void OutputCellPopulationParameters(out_stream &rParamsFile)
void SetTemperature(double temperature)
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
virtual void AcceptPopulationWriter(boost::shared_ptr< AbstractCellPopulationWriter< DIM, DIM > > pPopulationWriter)
void Update(bool hasHadBirthsOrDeaths=true)
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::string stamp="")
virtual void AddUpdateRule(boost::shared_ptr< AbstractUpdateRule< DIM > > pUpdateRule)
static RandomNumberGenerator * Instance()
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
void ConstructNodesWithoutMesh(const std::vector< Node< SPACE_DIM > * > &rNodes, double maxInteractionDistance)
double GetVolumeOfCell(CellPtr pCell)
virtual void WriteResultsToFiles(const std::string &rDirectory)
virtual double GetWidth(const unsigned &rDimension) const
CellPtr AddCell(CellPtr pNewCell, CellPtr pParentCell=CellPtr())
virtual TetrahedralMesh< DIM, DIM > * GetTetrahedralMeshForPdeModifier()
MutableMesh< DIM, DIM > * GetMutableMesh()
unsigned GetNumContainingElements() const
Definition: Node.cpp:312
unsigned GetIndex() const
Definition: Node.cpp:158
PottsElement< DIM > * GetElement(unsigned elementIndex)
double GetWidth(const unsigned &rDimension)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
AbstractMesh< ELEMENT_DIM, ELEMENT_DIM > & mrMesh
void SetNumSweepsPerTimestep(unsigned numSweepsPerTimestep)
VertexMesh< DIM, DIM > * mpElementTessellation
PottsBasedCellPopulation(PottsMesh< DIM > &rMesh, std::vector< CellPtr > &rCells, bool deleteMesh=false, bool validate=true, const std::vector< unsigned > locationIndices=std::vector< unsigned >())
bool IsCellAssociatedWithADeletedLocation(CellPtr pCell)