Chaste  Release::3.4
PottsMesh.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 "PottsMesh.hpp"
37 #include "RandomNumberGenerator.hpp"
38 #include "UblasCustomFunctions.hpp"
39 #include <list>
40 
41 
42 template<unsigned DIM>
44  std::vector<PottsElement<DIM>*> pottsElements,
45  std::vector< std::set<unsigned> > vonNeumannNeighbouringNodeIndices,
46  std::vector< std::set<unsigned> > mooreNeighbouringNodeIndices)
47 {
48  // Reset member variables and clear mNodes, mElements.
49  Clear();
50 
51  // Verify the same size of nodes and neighbour information.
52  if ( (vonNeumannNeighbouringNodeIndices.size() != nodes.size()) || (mooreNeighbouringNodeIndices.size() != nodes.size()) )
53  {
54  EXCEPTION("Nodes and neighbour information for a Potts mesh need to be the same length.");
55  }
56  mVonNeumannNeighbouringNodeIndices = vonNeumannNeighbouringNodeIndices;
57  mMooreNeighbouringNodeIndices = mooreNeighbouringNodeIndices;
58 
59  // Populate mNodes and mElements
60  for (unsigned node_index=0; node_index<nodes.size(); node_index++)
61  {
62  Node<DIM>* p_temp_node = nodes[node_index];
63  this->mNodes.push_back(p_temp_node);
64  }
65  for (unsigned elem_index=0; elem_index<pottsElements.size(); elem_index++)
66  {
67  PottsElement<DIM>* p_temp_element = pottsElements[elem_index];
68  mElements.push_back(p_temp_element);
69  }
70 
71  // Register elements with nodes
72  for (unsigned index=0; index<mElements.size(); index++)
73  {
74  PottsElement<DIM>* p_element = mElements[index];
75 
76  unsigned element_index = p_element->GetIndex();
77  unsigned num_nodes_in_element = p_element->GetNumNodes();
78 
79  for (unsigned node_index=0; node_index<num_nodes_in_element; node_index++)
80  {
81  p_element->GetNode(node_index)->AddElement(element_index);
82  }
83  }
84 
85  this->mMeshChangesDuringSimulation = true;
86 }
87 
88 template<unsigned DIM>
90 {
91  this->mMeshChangesDuringSimulation = true;
92  Clear();
93 }
94 
95 template<unsigned DIM>
97 {
98  Clear();
99 }
100 
101 template<unsigned DIM>
102 unsigned PottsMesh<DIM>::SolveNodeMapping(unsigned index) const
103 {
104  assert(index < this->mNodes.size());
105  return index;
106 }
107 
108 template<unsigned DIM>
109 unsigned PottsMesh<DIM>::SolveElementMapping(unsigned index) const
110 {
111  assert(index < this->mElements.size());
112  return index;
113 }
114 
115 template<unsigned DIM>
116 unsigned PottsMesh<DIM>::SolveBoundaryElementMapping(unsigned index) const
117 {
118  return index;
119 }
120 
121 template<unsigned DIM>
123 {
124  // Delete elements
125  for (unsigned i=0; i<mElements.size(); i++)
126  {
127  delete mElements[i];
128  }
129  mElements.clear();
130 
131  // Delete nodes
132  for (unsigned i=0; i<this->mNodes.size(); i++)
133  {
134  delete this->mNodes[i];
135  }
136  this->mNodes.clear();
137 
138  mDeletedElementIndices.clear();
139 
140  // Delete neighbour info
141  //mVonNeumannNeighbouringNodeIndices.clear();
142  //mMooreNeighbouringNodeIndices.clear();
143 }
144 
145 template<unsigned DIM>
147 {
148  return this->mNodes.size();
149 }
150 
151 template<unsigned DIM>
153 {
154  return mElements.size() - mDeletedElementIndices.size();
155 }
156 
157 template<unsigned DIM>
159 {
160  return mElements.size();
161 }
162 
163 template<unsigned DIM>
165 {
166  assert(index < mElements.size());
167  return mElements[index];
168 }
169 
170 template<unsigned DIM>
171 c_vector<double, DIM> PottsMesh<DIM>::GetCentroidOfElement(unsigned index)
172 {
173  PottsElement<DIM>* p_element = GetElement(index);
174  unsigned num_nodes_in_element = p_element->GetNumNodes();
175 
177  c_vector<double, DIM> centroid = zero_vector<double>(DIM);
178 
179  for (unsigned local_index=0; local_index<num_nodes_in_element; local_index++)
180  {
181  // Find location of current node and add it to the centroid
182  centroid += p_element->GetNodeLocation(local_index);
183  }
184 
185  centroid /= num_nodes_in_element;
186 
187  return centroid;
188 }
189 
190 template<unsigned DIM>
192 {
193  PottsElement<DIM>* p_element = GetElement(index);
194  double element_volume = (double) p_element->GetNumNodes();
195 
196  return element_volume;
197 }
198 
199 template<unsigned DIM>
201 {
203  assert(DIM==2 || DIM==3);
204 
205  // Get pointer to this element
206  PottsElement<DIM>* p_element = GetElement(index);
207 
208  double surface_area = 0.0;
209  for (unsigned node_index=0; node_index< p_element->GetNumNodes(); node_index++)
210  {
211  std::set<unsigned> neighbouring_node_indices = GetVonNeumannNeighbouringNodeIndices(p_element->GetNode(node_index)->GetIndex());
212  unsigned local_edges = 2*DIM;
213  for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
214  iter != neighbouring_node_indices.end();
215  iter++)
216  {
217  std::set<unsigned> neighbouring_node_element_indices = this->mNodes[*iter]->rGetContainingElementIndices();
218 
219  if (!(neighbouring_node_element_indices.empty()) && (local_edges!=0))
220  {
221  unsigned neighbouring_node_element_index = *(neighbouring_node_element_indices.begin());
222  if (neighbouring_node_element_index == index)
223  {
224  local_edges--;
225  }
226  }
227  }
228  surface_area += local_edges;
229  }
230  return surface_area;
231 }
232 
233 template<unsigned DIM>
234 std::set<unsigned> PottsMesh<DIM>::GetMooreNeighbouringNodeIndices(unsigned nodeIndex)
235 {
236  return mMooreNeighbouringNodeIndices[nodeIndex];
237 }
238 
239 template<unsigned DIM>
240 std::set<unsigned> PottsMesh<DIM>::GetVonNeumannNeighbouringNodeIndices(unsigned nodeIndex)
241 {
242  return mVonNeumannNeighbouringNodeIndices[nodeIndex];
243 }
244 
245 template<unsigned DIM>
246 void PottsMesh<DIM>::DeleteElement(unsigned index)
247 {
248  // Mark this element as deleted; this also updates the nodes containing element indices
249  this->mElements[index]->MarkAsDeleted();
250  mDeletedElementIndices.push_back(index);
251 }
252 
253 template<unsigned DIM>
255 {
256  // Remove any elements that have been removed and re-order the remaining ones
257  unsigned num_deleted_elements = mDeletedElementIndices.size();
258 
259  for (unsigned index = num_deleted_elements; index>0; index--)
260  {
261  unsigned deleted_elem_index = mDeletedElementIndices[index-1];
262  delete mElements[deleted_elem_index];
263  mElements.erase(mElements.begin()+deleted_elem_index);
264  for (unsigned elem_index=deleted_elem_index; elem_index<mElements.size(); elem_index++)
265  {
266  mElements[elem_index]->ResetIndex(elem_index);
267  }
268  }
269  mDeletedElementIndices.clear();
270 }
271 
272 
273 template<unsigned DIM>
274 void PottsMesh<DIM>::DeleteNode(unsigned index)
275 {
276  //Mark node as deleted so we don't consider it when iterating over nodes
277  this->mNodes[index]->MarkAsDeleted();
278 
279  //Remove from Elements
280  std::set<unsigned> containing_element_indices = this->mNodes[index]->rGetContainingElementIndices();
281 
282  for (std::set<unsigned>::iterator iter = containing_element_indices.begin();
283  iter != containing_element_indices.end();
284  iter++)
285  {
286  assert(mElements[*iter]->GetNumNodes() > 0);
287  if (mElements[*iter]->GetNumNodes() == 1)
288  {
289  DeleteElement(*iter);
290  }
291  else
292  {
293  this->mElements[*iter]->DeleteNode(this->mElements[*iter]->GetNodeLocalIndex(index));
294  }
295  }
296 
297  // Remove from connectivity
298  mVonNeumannNeighbouringNodeIndices[index].clear();
299  mMooreNeighbouringNodeIndices[index].clear();
300 
301  assert(mVonNeumannNeighbouringNodeIndices.size()==mMooreNeighbouringNodeIndices.size());
302  for (unsigned node_index = 0;
303  node_index < mVonNeumannNeighbouringNodeIndices.size();
304  node_index++)
305  {
306  // Remove node "index" from the Von Neuman neighbourhood of node "node_index".
307  mVonNeumannNeighbouringNodeIndices[node_index].erase(index);
308  mMooreNeighbouringNodeIndices[node_index].erase(index);
309 
310  // Check there's still connectivity for the other non-deleted nodes
311  if (!this->mNodes[node_index]->IsDeleted())
312  {
313  assert(!mVonNeumannNeighbouringNodeIndices[node_index].empty());
314  assert(!mMooreNeighbouringNodeIndices[node_index].empty());
315  }
316  }
317 
318  // Remove node from mNodes and renumber all the elements and nodes
319  delete this->mNodes[index];
320  this->mNodes.erase(this->mNodes.begin()+index);
321  unsigned num_nodes = GetNumNodes();
322  mVonNeumannNeighbouringNodeIndices.erase(mVonNeumannNeighbouringNodeIndices.begin()+index);
323  mMooreNeighbouringNodeIndices.erase(mMooreNeighbouringNodeIndices.begin()+index);
324 
325  assert(mVonNeumannNeighbouringNodeIndices.size()==num_nodes);
326  assert(mMooreNeighbouringNodeIndices.size()==num_nodes);
327 
328  for (unsigned node_index = 0; node_index < num_nodes; node_index++)
329  {
330  // Reduce the index of all nodes greater than node "index"
331  if (node_index >= index)
332  {
333  assert(this->mNodes[node_index]->GetIndex() == node_index+1);
334  this->mNodes[node_index]->SetIndex(node_index);
335  }
336  assert(this->mNodes[node_index]->GetIndex() == node_index);
337 
338  // Reduce the index of all nodes greater than node "index"
339  // in the Moore and Von Neuman neighbourhoods.
340  std::set<unsigned> von_neuman = mVonNeumannNeighbouringNodeIndices[node_index];
341  mVonNeumannNeighbouringNodeIndices[node_index].clear();
342  for (std::set<unsigned>::iterator iter = von_neuman.begin();
343  iter != von_neuman.end();
344  iter++)
345  {
346  if (*iter >= index)
347  {
348  mVonNeumannNeighbouringNodeIndices[node_index].insert(*iter-1);
349  }
350  else
351  {
352  mVonNeumannNeighbouringNodeIndices[node_index].insert(*iter);
353  }
354  }
355  std::set<unsigned> moore = mMooreNeighbouringNodeIndices[node_index];
356  mMooreNeighbouringNodeIndices[node_index].clear();
357  for (std::set<unsigned>::iterator iter = moore.begin();
358  iter != moore.end();
359  iter++)
360  {
361  if (*iter >= index)
362  {
363  mMooreNeighbouringNodeIndices[node_index].insert(*iter-1);
364  }
365  else
366  {
367  mMooreNeighbouringNodeIndices[node_index].insert(*iter);
368  }
369  }
370  }
371  // Finally remove any elememts that have been removed
372  assert(mDeletedElementIndices.size() <= 1); // Should have at most one element to remove
373  if (mDeletedElementIndices.size() == 1)
374  {
375  unsigned deleted_elem_index = mDeletedElementIndices[0];
376  delete mElements[deleted_elem_index];
377  mElements.erase(mElements.begin()+deleted_elem_index);
378  mDeletedElementIndices.clear();
379 
380  for (unsigned elem_index=deleted_elem_index; elem_index<GetNumElements(); elem_index++)
381  {
382  mElements[elem_index]->ResetIndex(elem_index);
383  }
384  }
385 }
386 
387 template<unsigned DIM>
389  bool placeOriginalElementBelow)
390 {
392  assert(DIM==2 || DIM==3);
393 
394  // Store the number of nodes in the element (this changes when nodes are deleted from the element)
395  unsigned num_nodes = pElement->GetNumNodes();
396 
397  if (num_nodes < 2)
398  {
399  EXCEPTION("Tried to divide a Potts element with only one node. Cell dividing too often given dynamic parameters.");
400  }
401 
402  // Copy the nodes in this element
403  std::vector<Node<DIM>*> nodes_elem;
404  for (unsigned i=0; i<num_nodes; i++)
405  {
406  nodes_elem.push_back(pElement->GetNode(i));
407  }
408 
409  // Get the index of the new element
410  unsigned new_element_index;
411  if (mDeletedElementIndices.empty())
412  {
413  new_element_index = this->mElements.size();
414  }
415  else
416  {
417  new_element_index = mDeletedElementIndices.back();
418  mDeletedElementIndices.pop_back();
419  delete this->mElements[new_element_index];
420  }
421 
422  // Add the new element to the mesh
423  AddElement(new PottsElement<DIM>(new_element_index, nodes_elem));
424 
430  unsigned half_num_nodes = num_nodes/2; // This will round down
431  assert(half_num_nodes > 0);
432  assert(half_num_nodes < num_nodes);
433 
434  // Find lowest element
436  double height_midpoint_1 = 0.0;
437  double height_midpoint_2 = 0.0;
438  unsigned counter_1 = 0;
439  unsigned counter_2 = 0;
440 
441  for (unsigned i=0; i<num_nodes; i++)
442  {
443  if (i<half_num_nodes)
444  {
445  height_midpoint_1 += pElement->GetNode(i)->rGetLocation()[DIM - 1];
446  counter_1++;
447  }
448  else
449  {
450  height_midpoint_2 += pElement->GetNode(i)->rGetLocation()[DIM -1];
451  counter_2++;
452  }
453  }
454  height_midpoint_1 /= (double)counter_1;
455  height_midpoint_2 /= (double)counter_2;
456 
457  for (unsigned i=num_nodes; i>0; i--)
458  {
459  if (i-1 >= half_num_nodes)
460  {
461  if (height_midpoint_1 < height_midpoint_2)
462  {
463  if (placeOriginalElementBelow)
464  {
465  pElement->DeleteNode(i-1);
466  }
467  else
468  {
469  this->mElements[new_element_index]->DeleteNode(i-1);
470  }
471  }
472  else
473  {
474  if (placeOriginalElementBelow)
475  {
476  this->mElements[new_element_index]->DeleteNode(i-1);
477  }
478  else
479  {
480  pElement->DeleteNode(i-1);
481  }
482  }
483  }
484  else // i-1 < half_num_nodes
485  {
486  if (height_midpoint_1 < height_midpoint_2)
487  {
488  if (placeOriginalElementBelow)
489  {
490  this->mElements[new_element_index]->DeleteNode(i-1);
491  }
492  else
493  {
494  pElement->DeleteNode(i-1);
495  }
496  }
497  else
498  {
499  if (placeOriginalElementBelow)
500  {
501  pElement->DeleteNode(i-1);
502  }
503  else
504  {
505  this->mElements[new_element_index]->DeleteNode(i-1);
506  }
507  }
508  }
509  }
510 
511  return new_element_index;
512 }
513 
514 template<unsigned DIM>
516 {
517  unsigned new_element_index = pNewElement->GetIndex();
518 
519  if (new_element_index == this->mElements.size())
520  {
521  this->mElements.push_back(pNewElement);
522  }
523  else
524  {
525  this->mElements[new_element_index] = pNewElement;
526  }
527  pNewElement->RegisterWithNodes();
528  return pNewElement->GetIndex();
529 }
530 
531 template<unsigned DIM>
532 std::set<unsigned> PottsMesh<DIM>::GetNeighbouringElementIndices(unsigned elementIndex)
533 {
534  // Get a pointer to this element
535  PottsElement<DIM>* p_element = this->GetElement(elementIndex);
536 
537  // Create a set of neighbouring element indices
538  std::set<unsigned> neighbouring_element_indices;
539 
540  // Loop over nodes owned by this element
541  for (unsigned local_index=0; local_index<p_element->GetNumNodes(); local_index++)
542  {
543  // Get a pointer to this node
544  Node<DIM>* p_node = p_element->GetNode(local_index);
545 
546  // Find the indices of the elements owned by neighbours of this node
547 
548  // Loop over neighbouring nodes. Only want Von Neuman neighbours (i.e N,S,E,W) as need to share an edge
549  std::set<unsigned> neighbouring_node_indices = GetVonNeumannNeighbouringNodeIndices(p_node->GetIndex());
550 
551  // Iterate over these neighbouring nodes
552  for (std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
553  neighbour_iter != neighbouring_node_indices.end();
554  ++neighbour_iter)
555  {
556  std::set<unsigned> neighbouring_node_containing_elem_indices = this->GetNode(*neighbour_iter)->rGetContainingElementIndices();
557 
558  assert(neighbouring_node_containing_elem_indices.size()<2); // Either in element or in medium
559 
560  if (neighbouring_node_containing_elem_indices.size()==1) // Node is in an element
561  {
562  // Add this element to the neighbouring elements set
563  neighbouring_element_indices.insert(*(neighbouring_node_containing_elem_indices.begin()));
564  }
565  }
566  }
567 
568  // Lastly remove this element's index from the set of neighbouring element indices
569  neighbouring_element_indices.erase(elementIndex);
570 
571  return neighbouring_element_indices;
572 }
573 
574 template<unsigned DIM>
576 {
577  assert(rMeshReader.HasNodePermutation() == false);
578 
579  // Store numbers of nodes and elements
580  unsigned num_nodes = rMeshReader.GetNumNodes();
581  unsigned num_elements = rMeshReader.GetNumElements();
582 
583  // Reserve memory for nodes
584  this->mNodes.reserve(num_nodes);
585 
586  rMeshReader.Reset();
587 
588  // Add nodes
589  std::vector<double> node_data;
590  for (unsigned i=0; i<num_nodes; i++)
591  {
592  node_data = rMeshReader.GetNextNode();
593  unsigned is_boundary_node = (bool) node_data[DIM];
594  node_data.pop_back();
595  this->mNodes.push_back(new Node<DIM>(i, node_data, is_boundary_node));
596  }
597 
598  rMeshReader.Reset();
599 
600  // Reserve memory for nodes
601  mElements.reserve(rMeshReader.GetNumElements());
602 
603  // Add elements
604  for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
605  {
606  // Get the data for this element
607  ElementData element_data = rMeshReader.GetNextElementData();
608 
609  // Get the nodes owned by this element
610  std::vector<Node<DIM>*> nodes;
611  unsigned num_nodes_in_element = element_data.NodeIndices.size();
612  for (unsigned j=0; j<num_nodes_in_element; j++)
613  {
614  assert(element_data.NodeIndices[j] < this->mNodes.size());
615  nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
616  }
617 
618  // Use nodes and index to construct this element
619  PottsElement<DIM>* p_element = new PottsElement<DIM>(elem_index, nodes);
620  mElements.push_back(p_element);
621 
622  if (rMeshReader.GetNumElementAttributes() > 0)
623  {
624  assert(rMeshReader.GetNumElementAttributes() == 1);
625  double attribute_value = element_data.AttributeValue;
626  p_element->SetAttribute(attribute_value);
627  }
628  }
629 
630  // If we are just using a mesh reader, then there is no neighbour information (see #1932)
631  if (mVonNeumannNeighbouringNodeIndices.empty())
632  {
633  mVonNeumannNeighbouringNodeIndices.resize(num_nodes);
634  }
635  if (mMooreNeighbouringNodeIndices.empty())
636  {
637  mMooreNeighbouringNodeIndices.resize(num_nodes);
638  }
639 }
640 
641 // Explicit instantiation
642 template class PottsMesh<1>;
643 template class PottsMesh<2>;
644 template class PottsMesh<3>;
645 
646 // Serialization for Boost >= 1.36
unsigned AddElement(PottsElement< DIM > *pNewElement)
Definition: PottsMesh.cpp:515
unsigned SolveBoundaryElementMapping(unsigned index) const
Definition: PottsMesh.cpp:116
void SetAttribute(double attribute)
virtual ElementData GetNextElementData()=0
Definition: Node.hpp:58
void DeleteNode(unsigned index)
Definition: PottsMesh.cpp:274
void DeleteElement(unsigned index)
Definition: PottsMesh.cpp:246
virtual double GetVolumeOfElement(unsigned index)
Definition: PottsMesh.cpp:191
void ConstructFromMeshReader(AbstractMeshReader< DIM, DIM > &rMeshReader)
Definition: PottsMesh.cpp:575
#define EXCEPTION(message)
Definition: Exception.hpp:143
void RemoveDeletedElements()
Definition: PottsMesh.cpp:254
std::set< unsigned > GetVonNeumannNeighbouringNodeIndices(unsigned nodeIndex)
Definition: PottsMesh.cpp:240
unsigned GetNumAllElements() const
Definition: PottsMesh.cpp:158
virtual ~PottsMesh()
Definition: PottsMesh.cpp:96
std::set< unsigned > GetMooreNeighbouringNodeIndices(unsigned nodeIndex)
Definition: PottsMesh.cpp:234
unsigned SolveElementMapping(unsigned index) const
Definition: PottsMesh.cpp:109
unsigned DivideElement(PottsElement< DIM > *pElement, bool placeOriginalElementBelow=false)
Definition: PottsMesh.cpp:388
std::vector< unsigned > NodeIndices
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
virtual bool HasNodePermutation()
virtual c_vector< double, DIM > GetCentroidOfElement(unsigned index)
Definition: PottsMesh.cpp:171
virtual void Clear()
Definition: PottsMesh.cpp:122
virtual unsigned GetNumNodes() const
Definition: PottsMesh.cpp:146
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
virtual unsigned GetNumElements() const =0
virtual void Reset()=0
unsigned GetNumNodes() const
virtual double GetSurfaceAreaOfElement(unsigned index)
Definition: PottsMesh.cpp:200
std::set< unsigned > GetNeighbouringElementIndices(unsigned elementIndex)
Definition: PottsMesh.cpp:532
virtual unsigned GetNumElementAttributes() const
PottsElement< DIM > * GetElement(unsigned index) const
Definition: PottsMesh.cpp:164
virtual unsigned GetNumElements() const
Definition: PottsMesh.cpp:152
unsigned GetIndex() const
unsigned SolveNodeMapping(unsigned index) const
Definition: PottsMesh.cpp:102
void DeleteNode(const unsigned &rIndex)
double GetNodeLocation(unsigned localIndex, unsigned dimension) const
virtual std::vector< double > GetNextNode()=0
unsigned GetIndex() const
Definition: Node.cpp:159
virtual unsigned GetNumNodes() const =0