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