Chaste  Release::3.4
HeterotypicBoundaryLengthWriter.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 "HeterotypicBoundaryLengthWriter.hpp"
37 #include "AbstractCellPopulation.hpp"
38 #include "MeshBasedCellPopulation.hpp"
39 #include "CaBasedCellPopulation.hpp"
40 #include "NodeBasedCellPopulation.hpp"
41 #include "PottsBasedCellPopulation.hpp"
42 #include "VertexBasedCellPopulation.hpp"
43 
44 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
46  : AbstractCellPopulationWriter<ELEMENT_DIM, SPACE_DIM>("heterotypicboundary.dat")
47 {
48 }
49 
50 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
52 {
53  // Initialise helper variables
54  double heterotypic_boundary_length = 0.0;
55  double total_shared_edges_length = 0.0;
56  double num_heterotypic_pairs = 0.0;
57  double total_num_pairs = 0.0;
58 
59  // Make sure the Voronoi tessellation has been created
61  pCellPopulation->CreateVoronoiTessellation();
62 
63  // Iterate over cells
64  for (typename AbstractCellPopulation<ELEMENT_DIM, SPACE_DIM>::Iterator cell_iter = pCellPopulation->Begin();
65  cell_iter != pCellPopulation->End();
66  ++cell_iter)
67  {
68  // Get the location index corresponding to this cell
69  unsigned index = pCellPopulation->GetLocationIndexUsingCell(*cell_iter);
70 
71  // Store whether this cell is labelled
72  bool cell_is_labelled = cell_iter->template HasCellProperty<CellLabel>();
73 
74  // Get the set of neighbouring location indices
75  std::set<unsigned> neighbour_indices = pCellPopulation->GetNeighbouringNodeIndices(index);
76 
77  // Iterate over these neighbours
78  for (std::set<unsigned>::iterator neighbour_iter = neighbour_indices.begin();
79  neighbour_iter != neighbour_indices.end();
80  ++neighbour_iter)
81  {
82  // Get the length of the edge shared with this neighbour
83  unsigned neighbour_index = *neighbour_iter;
84  double edge_length = pCellPopulation->GetVoronoiEdgeLength(index,neighbour_index);
85 
86  // Ignore ghost nodes (in the case of a MeshBasedCellPopulationWithGhostNodes)
88  if (!pCellPopulation->IsGhostNode(neighbour_index))
89  {
90  total_shared_edges_length += edge_length;
91  total_num_pairs += 1.0;
92 
93  // Store whether this neighbour is labelled
94  CellPtr p_neighbour_cell = pCellPopulation->GetCellUsingLocationIndex(neighbour_index);
95  bool neighbour_is_labelled = p_neighbour_cell->template HasCellProperty<CellLabel>();
96 
97  // If this cell is labelled and its neighbour is not, or vice versa...
98  if (cell_is_labelled != neighbour_is_labelled)
99  {
100  // ... then increment the fractional boundary length
101  heterotypic_boundary_length += edge_length;
102  num_heterotypic_pairs += 1.0;
103  }
104  }
105  }
106  }
107 
108  // We have counted each cell-cell edge twice
109  heterotypic_boundary_length *= 0.5;
110  total_shared_edges_length *= 0.5;
111 
112  // We have counted each pair of neighbouring cells twice
113  num_heterotypic_pairs *= 0.5;
114  total_num_pairs *= 0.5;
115 
116  *this->mpOutStream << heterotypic_boundary_length << "\t" << total_shared_edges_length << "\t" << num_heterotypic_pairs << "\t" << total_num_pairs;
117 }
118 
119 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
121 {
122  // Initialise helper variables
123  double heterotypic_boundary_length = 0.0;
124  double total_shared_edges_length = 0.0;
125  double num_heterotypic_pairs = 0.0;
126  double total_num_pairs = 0.0;
127 
128  // Iterate over cells
129  for (typename AbstractCellPopulation<SPACE_DIM>::Iterator cell_iter = pCellPopulation->Begin();
130  cell_iter != pCellPopulation->End();
131  ++cell_iter)
132  {
133  // Get the location index corresponding to this cell
134  unsigned index = pCellPopulation->GetLocationIndexUsingCell(*cell_iter);
135 
136  // Store whether this cell is labelled
137  bool cell_is_labelled = cell_iter->template HasCellProperty<CellLabel>();
138 
139 
140  // Get this node's von Neumann neighbours (not Moore neighbours, since they must share an edge)
141  std::set<unsigned> neighbour_node_indices = pCellPopulation->rGetMesh().GetVonNeumannNeighbouringNodeIndices(index);
142 
143  // Iterate over these neighbours
144  for (std::set<unsigned>::iterator neighbour_iter = neighbour_node_indices.begin();
145  neighbour_iter != neighbour_node_indices.end();
146  ++neighbour_iter)
147  {
148  // Assume the lattice is comprised of uniform unit lattice sites
149  double edge_length = 1.0;
150 
151  unsigned neighbour_index = *neighbour_iter;
152 
153  if (pCellPopulation->IsCellAttachedToLocationIndex(neighbour_index))
154  {
155  CellPtr p_neighbour_cell = pCellPopulation->GetCellUsingLocationIndex(neighbour_index);
156 
157  total_shared_edges_length += edge_length;
158  total_num_pairs += 1.0;
159 
160  // Store whether this neighbour is labelled
161  bool neighbour_is_labelled = p_neighbour_cell->template HasCellProperty<CellLabel>();
162 
163  // If this cell is labelled and its neighbour is not, or vice versa...
164  if (cell_is_labelled != neighbour_is_labelled)
165  {
166  // ... then increment the fractional boundary length
167  heterotypic_boundary_length += edge_length;
168  num_heterotypic_pairs += 1.0;
169  }
170  }
171  }
172  }
173 
174  // We have counted each cell-cell edge twice
175  heterotypic_boundary_length *= 0.5;
176  total_shared_edges_length *= 0.5;
177 
178  // We have counted each pair of neighbouring cells twice
179  num_heterotypic_pairs *= 0.5;
180  total_num_pairs *= 0.5;
181 
182  *this->mpOutStream << heterotypic_boundary_length << "\t" << total_shared_edges_length << "\t" << num_heterotypic_pairs << "\t" << total_num_pairs;
183 }
184 
185 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
187 {
188  // Make sure the cell population is updated so that mNodeNeighbours is set up
190  pCellPopulation->Update();
191 
192  // Initialise helper variables
193  double heterotypic_boundary_length = 0.0;
194  double total_shared_edges_length = 0.0;
195  double num_heterotypic_pairs = 0.0;
196  double total_num_pairs = 0.0;
197 
198  // Loop over cells
199  for (typename AbstractCellPopulation<SPACE_DIM>::Iterator cell_iter = pCellPopulation->Begin();
200  cell_iter != pCellPopulation->End();
201  ++cell_iter)
202  {
203  // Store whether this cell is labelled
204  bool cell_is_labelled = cell_iter->template HasCellProperty<CellLabel>();
205 
206  // Store the radius of the node corresponding to this cell
207  unsigned node_index = pCellPopulation->GetLocationIndexUsingCell(*cell_iter);
208  double node_radius = pCellPopulation->GetNode(node_index)->GetRadius();
209 
210  // Get the set of neighbouring node indices
211  std::set<unsigned> neighbour_indices = pCellPopulation->GetNeighbouringNodeIndices(node_index);
212 
213  if (!neighbour_indices.empty())
214  {
215  // Iterate over these neighbours
216  for (std::set<unsigned>::iterator neighbour_iter = neighbour_indices.begin();
217  neighbour_iter != neighbour_indices.end();
218  ++neighbour_iter)
219  {
220  // Store the radius of the node corresponding to this neighbour
221  double neighbour_radius = pCellPopulation->GetNode(*neighbour_iter)->GetRadius();
222 
223  // Get the (approximate) length of the edge shared with this neighbour
224  double separation = pCellPopulation->rGetMesh().GetDistanceBetweenNodes(node_index, *neighbour_iter);
225  double sum_of_radii = node_radius + neighbour_radius;
226 
227  // If the neighbours are close enough, then approximate their 'edge length'
228  if (separation < sum_of_radii)
229  {
230  // Use Heron's formula to compute the edge length
231  double a = node_radius;
232  double b = neighbour_radius;
233  double c = separation;
234  double s = 0.5*(a + b + c);
235  double A = sqrt(s*(s-a)*(s-b)*(s-c));
236  double edge_length = 4.0*A/c;
237 
238  total_shared_edges_length += edge_length;
239  total_num_pairs += 1.0;
240 
241  // Store whether this neighbour is labelled
242  CellPtr p_neighbour_cell = pCellPopulation->GetCellUsingLocationIndex(*neighbour_iter);
243  bool neighbour_is_labelled = p_neighbour_cell->template HasCellProperty<CellLabel>();
244 
245  // If this cell is labelled and its neighbour is not, or vice versa...
246  if (cell_is_labelled != neighbour_is_labelled)
247  {
248  // ... then increment the fractional boundary length
249  heterotypic_boundary_length += edge_length;
250  num_heterotypic_pairs += 1.0;
251  }
252  }
253  }
254  }
255  }
256 
257  // We have counted each cell-cell edge twice
258  heterotypic_boundary_length *= 0.5;
259  total_shared_edges_length *= 0.5;
260 
261  // We have counted each pair of neighbouring cells twice
262  num_heterotypic_pairs *= 0.5;
263  total_num_pairs *= 0.5;
264 
265  *this->mpOutStream << heterotypic_boundary_length << "\t" << total_shared_edges_length << "\t" << num_heterotypic_pairs << "\t" << total_num_pairs;
266 }
267 
268 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
270 {
272 
273  // Initialise helper variables
274  double heterotypic_boundary_length = 0.0;
275  double total_shared_edges_length = 0.0;
276  double num_heterotypic_pairs = 0.0;
277  double total_num_pairs = 0.0;
278 
279  // Iterate over cells
280  for (typename AbstractCellPopulation<SPACE_DIM>::Iterator cell_iter = pCellPopulation->Begin();
281  cell_iter != pCellPopulation->End();
282  ++cell_iter)
283  {
284  // Store whether this cell is labelled
285  bool cell_is_labelled = cell_iter->template HasCellProperty<CellLabel>();
286 
287  unsigned elem_index = pCellPopulation->GetLocationIndexUsingCell(*cell_iter);
288  unsigned num_nodes_in_elem = pCellPopulation->rGetMesh().GetElement(elem_index)->GetNumNodes();
289 
290  // Iterate over nodes contained in the element corresponding to this cell
291  for (unsigned local_index=0; local_index<num_nodes_in_elem; local_index++)
292  {
293  // Get this node's von Neumann neighbours (not Moore neighbours, since they must share an edge)
294  unsigned global_index = pCellPopulation->rGetMesh().GetElement(elem_index)->GetNodeGlobalIndex(local_index);
295  std::set<unsigned> neighbour_node_indices = pCellPopulation->rGetMesh().GetVonNeumannNeighbouringNodeIndices(global_index);
296 
297  // Iterate over these neighbours
298  for (std::set<unsigned>::iterator neighbour_iter = neighbour_node_indices.begin();
299  neighbour_iter != neighbour_node_indices.end();
300  ++neighbour_iter)
301  {
302  // Get the elements containing this neighbour
303  std::set<unsigned> neighbour_elem_indices = pCellPopulation->GetNode(*neighbour_iter)->rGetContainingElementIndices();
304 
305  if (neighbour_elem_indices.size() == 1)
306  {
307  unsigned neigbour_elem_index = *(neighbour_elem_indices.begin());
308 
309  if (neigbour_elem_index != elem_index)
310  {
311  // Edge is between two different elements
312  total_shared_edges_length += 1.0;
313 
314  // Store whether the cell corresponding to this element index is labelled
315  CellPtr p_neighbour_cell = pCellPopulation->GetCellUsingLocationIndex(neigbour_elem_index);
316  bool neighbour_is_labelled = p_neighbour_cell->template HasCellProperty<CellLabel>();
317 
318  // If this cell is labelled and its neighbour is not, or vice versa...
319  if (cell_is_labelled != neighbour_is_labelled)
320  {
321  // ... then increment the fractional boundary length
322  heterotypic_boundary_length += 1.0;
323  }
324  }
325  }
326  else
327  {
328  // Original node is on boundary of mesh so don't include in the edge calculation.
329  }
330  }
331  }
332 
333  std::set<unsigned> neighbour_node_indices = pCellPopulation->GetNeighbouringLocationIndices(*cell_iter);
334 
335  // Iterate over these neighbours
336  for (std::set<unsigned>::iterator neighbour_iter = neighbour_node_indices.begin();
337  neighbour_iter != neighbour_node_indices.end();
338  ++neighbour_iter)
339  {
340  total_num_pairs += 1.0;
341 
342  CellPtr p_neighbour_cell = pCellPopulation->GetCellUsingLocationIndex(*neighbour_iter);
343  bool neighbour_is_labelled = p_neighbour_cell->template HasCellProperty<CellLabel>();
344 
345  // If this cell is labelled and its neighbour is not, or vice versa...
346  if (cell_is_labelled != neighbour_is_labelled)
347  {
348  // ... then increment the fractional boundary length
349  num_heterotypic_pairs += 1.0;
350  }
351  }
352  }
353 
354  // We have counted each cell-cell edge twice
355  heterotypic_boundary_length *= 0.5;
356  total_shared_edges_length *= 0.5;
357 
358  // We have counted each pair of neighbouring cells twice
359  num_heterotypic_pairs *= 0.5;
360  total_num_pairs *= 0.5;
361 
362  *this->mpOutStream << heterotypic_boundary_length << "\t" << total_shared_edges_length << "\t" << num_heterotypic_pairs << "\t" << total_num_pairs;
363 }
364 
365 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
367 {
368  // Make sure the cell population is updated
370  pCellPopulation->Update();
371 
372  // Initialise helper variables
373  double heterotypic_boundary_length = 0.0;
374  double total_shared_edges_length = 0.0;
375  double num_heterotypic_pairs = 0.0;
376  double total_num_pairs = 0.0;
377 
378  // Iterate over cells
379  for (typename AbstractCellPopulation<SPACE_DIM>::Iterator cell_iter = pCellPopulation->Begin();
380  cell_iter != pCellPopulation->End();
381  ++cell_iter)
382  {
383  // Store whether this cell is labelled
384  bool cell_is_labelled = cell_iter->template HasCellProperty<CellLabel>();
385 
386  // Get the set of neighbouring element indices
387  unsigned elem_index = pCellPopulation->GetLocationIndexUsingCell(*cell_iter);
388  std::set<unsigned> neighbour_elem_indices = pCellPopulation->rGetMesh().GetNeighbouringElementIndices(elem_index);
389 
390  // Iterate over these neighbours
391  for (std::set<unsigned>::iterator neighbour_iter = neighbour_elem_indices.begin();
392  neighbour_iter != neighbour_elem_indices.end();
393  ++neighbour_iter)
394  {
395  // Get the length of the edge shared with this neighbour
396  unsigned neighbour_index = *neighbour_iter;
397  double edge_length = pCellPopulation->rGetMesh().GetEdgeLength(elem_index, neighbour_index);
398 
399  total_shared_edges_length += edge_length;
400  total_num_pairs += 1.0;
401 
402  // Store whether this neighbour is labelled
403  CellPtr p_neighbour_cell = pCellPopulation->GetCellUsingLocationIndex(*neighbour_iter);
404  bool neighbour_is_labelled = p_neighbour_cell->template HasCellProperty<CellLabel>();
405 
406  // If this cell is labelled and its neighbour is not, or vice versa...
407  if (cell_is_labelled != neighbour_is_labelled)
408  {
409  // ... then increment the fractional boundary length
410  heterotypic_boundary_length += edge_length;
411  num_heterotypic_pairs += 1.0;
412  }
413  }
414  }
415 
416  // We have counted each cell-cell edge twice
417  heterotypic_boundary_length *= 0.5;
418  total_shared_edges_length *= 0.5;
419 
420  // We have counted each pair of neighbouring cells twice
421  num_heterotypic_pairs *= 0.5;
422  total_num_pairs *= 0.5;
423 
424  *this->mpOutStream << heterotypic_boundary_length << "\t" << total_shared_edges_length << "\t" << num_heterotypic_pairs << "\t" << total_num_pairs;
425 }
426 
427 // Explicit instantiation
434 
436 // Declare identifier for the serializer
double GetVoronoiEdgeLength(unsigned index1, unsigned index2)
NodesOnlyMesh< DIM > & rGetMesh()
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
PottsMesh< DIM > & rGetMesh()
unsigned GetLocationIndexUsingCell(CellPtr pCell)
Node< DIM > * GetNode(unsigned index)
Node< DIM > * GetNode(unsigned index)
std::set< unsigned > GetNeighbouringLocationIndices(CellPtr pCell)
bool IsCellAttachedToLocationIndex(unsigned index)
double GetDistanceBetweenNodes(unsigned indexA, unsigned indexB)
MutableVertexMesh< DIM, DIM > & rGetMesh()
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
void Update(bool hasHadBirthsOrDeaths=true)
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
virtual void Visit(MeshBasedCellPopulation< ELEMENT_DIM, SPACE_DIM > *pCellPopulation)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
std::set< unsigned > GetNeighbouringElementIndices(unsigned elementIndex)
Definition: VertexMesh.cpp:799
void Update(bool hasHadBirthsOrDeaths=true)
double GetEdgeLength(unsigned elementIndex1, unsigned elementIndex2)
Definition: VertexMesh.cpp:412