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