Chaste Commit::1fd4e48e3990e67db148bc1bc4cf6991a0049d0c
MutableElement.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#include "MutableElement.hpp"
36#include "RandomNumberGenerator.hpp"
37#include <cassert>
38
39
40template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
42 : AbstractElement<ELEMENT_DIM, SPACE_DIM>(index),
43 mEdgeHelper(nullptr)
44{
45}
46
47template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
49 const std::vector<Node<SPACE_DIM>*>& rNodes)
50 : AbstractElement<ELEMENT_DIM, SPACE_DIM>(index, rNodes),
51 mEdgeHelper(nullptr)
52{
53 if (SPACE_DIM == ELEMENT_DIM)
54 {
56 }
57}
58
59template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
63
64template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
66{
67 for (unsigned i=0; i<this->mNodes.size(); i++)
68 {
69 this->mNodes[i]->AddElement(this->mIndex);
70 }
71}
72
73template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
75{
76 // Mark element as deleted
77 this->mIsDeleted = true;
78
79 // Update nodes in the element so they know they are not contained by it
80 for (unsigned i=0; i<this->GetNumNodes(); i++)
81 {
82 this->mNodes[i]->RemoveElement(this->mIndex);
83 }
84 //Update edges in the element so they know they are not contained by it
85 for (unsigned i=0; i< GetNumEdges(); i++)
86 {
87 this->mEdges[i]->RemoveElement(this->mIndex);
88 }
89}
90
91template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
93{
94 for (unsigned i=0; i<this->GetNumNodes(); i++)
95 {
96 this->mNodes[i]->RemoveElement(this->mIndex);
97 }
98
99 for (unsigned i=0; i<this->GetNumEdges(); i++)
101 this->mEdges[i]->RemoveElement(this->mIndex);
102 }
103
104 this->mIndex = index;
105 RegisterWithNodes();
106 RegisterWithEdges();
108
109template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
111{
112 assert(rIndex < this->mNodes.size());
113
114 // Update surrounding edges
115 if (SPACE_DIM == 2 && this->mEdgeHelper != nullptr)
116 {
117 auto pOldNode = this->mNodes[rIndex];
118 unsigned rPrevIndex = (rIndex-1) % this->mEdges.size();
119 if (rIndex==0)
120 rPrevIndex = this->mEdges.size()-1;
121 this->mEdges[rPrevIndex]->ReplaceNode(pOldNode, pNode);
122 this->mEdges[rIndex]->ReplaceNode(pOldNode, pNode);
123 }
124
125 // Remove it from the node at this location
126 this->mNodes[rIndex]->RemoveElement(this->mIndex);
127
128 // Update the node at this location
129 this->mNodes[rIndex] = pNode;
130
131 // Add element to this node
132 this->mNodes[rIndex]->AddElement(this->mIndex);
133}
134
135template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
138 assert(rIndex < this->mNodes.size());
139
140 // Update surrounding edges
141 if (SPACE_DIM == 2 && this->mEdgeHelper != nullptr)
142 {
143 // Take the 3 node element as shown below (N# are nodes and E# are edges)
144 // N0 ==E0== N1 ==E1== N2 ==E2== N0
145 // If rIndex = 1, The edge E0 & E1 and Node N1 is removed [ ==E0== N1 ==E1== ]
146 // the section is replaced with edge --EN-- obtained from the EdgeHelper, this may be an existing edge
147 // N0 --EN-- N2 ==E2== N0
148
149 unsigned rPrevIndex = ((int)rIndex-1) % this->mEdges.size();
150 unsigned rNextIndex = (rIndex+1) % this->mEdges.size();
151 if (rIndex==0)
152 rPrevIndex = this->mEdges.size()-1;
153 auto prevNode = this->mNodes[rPrevIndex];
154 auto nextNode = this->mNodes[rNextIndex];
155
156 // Replace the edge
157 this->mEdges[rPrevIndex]->RemoveElement(this->GetIndex());
158 this->mEdges[rPrevIndex] = this->mEdgeHelper->GetEdgeFromNodes(this->GetIndex(), prevNode, nextNode);
159
160 // Delete the edge
161 this->mEdges[rIndex]->RemoveElement(this->GetIndex());
162 this->mEdges.erase(this->mEdges.begin() + rIndex);
163
164 }
165
166 // Remove element from the node at this location
167 this->mNodes[rIndex]->RemoveElement(this->mIndex);
168 // Remove the node at rIndex (removes node from element)
169 this->mNodes.erase(this->mNodes.begin() + rIndex);
170}
172template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
174{
181 if (SPACE_DIM == 2 && this->mEdgeHelper != nullptr && !this->mEdges.empty())
182 {
183 // Take the 3 node element as shown below (N# are nodes and E# are edges)
184 // N0 ==E0== N1 ==E1== N2 ==E2== N0
185 // If rIndex = 1, the new edge (NE) is added after the new node (NN)
186 // Edge ==E1== is marked for delete
187 // N0 ==E0== N1 --NE-- NN --NE-- N2 ==E2== N0
188
189
190 unsigned rNextIndex = (rIndex+1) % this->mEdges.size();
191
192 auto prevNode = this->mNodes[rIndex];
193 auto currentNode = pNode;
194 auto nextNode = this->mNodes[rNextIndex];
196 this->mEdges[rIndex]->RemoveElement(this->GetIndex());
197 this->mEdges[rIndex] = this->mEdgeHelper->GetEdgeFromNodes(this->mIndex, prevNode, currentNode);
198
199 auto edge = this->mEdgeHelper->GetEdgeFromNodes(this->mIndex, currentNode, nextNode);
200 this->mEdges.insert(this->mEdges.begin() + rIndex+1, edge);
201
203
204 if (this->mNodes.empty())
205 {
206 // Populate mNodes with pNode
207 this->mNodes.push_back(pNode);
208
209 // Add element to this node
210 this->mNodes[0]->AddElement(this->mIndex);
211 }
212 else
213 {
214 assert(rIndex < this->mNodes.size());
215
216 // Add pNode to rIndex+1 element of mNodes pushing the others up
217 this->mNodes.insert(this->mNodes.begin() + rIndex+1, pNode);
218
219 // Add element to this node
220 this->mNodes[rIndex+1]->AddElement(this->mIndex);
222}
223
224template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
226{
227 unsigned local_index = UINT_MAX;
228 for (unsigned i=0; i<this->mNodes.size(); i++)
229 {
230 if (this->GetNodeGlobalIndex(i) == globalIndex)
231 {
232 local_index = i;
233 }
234 }
235 return local_index;
236}
237
238template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
240{
241 for (auto edge : this->mEdges)
242 {
243 edge->AddElement(this->mIndex);
244 }
245}
246
247template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
249{
250 this->BuildEdges();
251 //TODO: handler
252}
253
254template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
256{
257 bool is_element_on_boundary = false;
258 for (unsigned i=0; i<this->mNodes.size(); i++)
259 {
260 if (this->GetNode(i)->IsBoundaryNode())
261 {
262 is_element_on_boundary = true;
263 break;
264 }
265 }
266 return is_element_on_boundary;
267}
268
269template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
271{
272 this->mEdgeHelper = pEdgeHelper;
273}
274
275template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
277{
278 for (auto edge: mEdges)
279 {
280 edge->RemoveElement(this->mIndex);
281 }
282 mEdges.clear();
283}
284
285template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
287{
288 assert(mEdgeHelper != nullptr);
289
290 // If SPACE_DIM == 2 then we can assume that the node layout
291 // in the array corresponds to its connections
292 // We can then infer the edge connection information
293 if (SPACE_DIM == 2)
294 {
295 this->ClearEdges();
296 for (unsigned i = 0; i < this->mNodes.size(); i++)
297 {
298 unsigned i_next = (i+1) % this->mNodes.size();
299 mEdges.push_back(mEdgeHelper->GetEdgeFromNodes(this->mIndex, this->mNodes[i], this->mNodes[i_next]));
300 }
301 }
302}
303
304template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
306{
307 assert(localIndex < mEdges.size());
308 return mEdges[localIndex]->GetIndex();
309}
310
311template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
313{
314 assert(localIndex < mEdges.size());
315 return mEdges[localIndex];
316}
317
318template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
320 return mEdges.size();
321}
322
323template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
325{
326 assert(localIndex < mEdges.size());
327 return mEdges[localIndex]->GetOtherElements(this->mIndex);
328}
329
330template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
332{
333 for (unsigned i=0; i<mEdges.size(); ++i)
334 {
335 if ((*mEdges[i]) == (*pEdge))
336 {
337 return true;
338 }
339 }
340 return false;
341}
342
343template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
345{
346 long result = -1;
347 for (unsigned i=0; i<mEdges.size(); ++i)
348 {
349 if ((*mEdges[i]) == (*pEdge))
350 {
351 result = i;
352 }
353 }
354 return result;
355}
356
358// Specialization for 1d elements //
359// //
360// 1d elements are just edges (lines) //
362
367template<unsigned SPACE_DIM>
368MutableElement<1, SPACE_DIM>::MutableElement(unsigned index, const std::vector<Node<SPACE_DIM>*>& rNodes)
369 : AbstractElement<1, SPACE_DIM>(index, rNodes),
370 mEdgeHelper(nullptr)
371{
372 // Sanity checking
373 assert(SPACE_DIM > 0);
374}
375
376template<unsigned SPACE_DIM>
380
381template<unsigned SPACE_DIM>
383{
384 for (unsigned i=0; i<this->mNodes.size(); i++)
385 {
386 this->mNodes[i]->AddElement(this->mIndex);
387 }
388}
389
390template<unsigned SPACE_DIM>
392{
393 // Mark element as deleted
394 this->mIsDeleted = true;
395
396 // Update nodes in the element so they know they are not contained by it
397 for (unsigned i=0; i<this->GetNumNodes(); i++)
398 {
399 this->mNodes[i]->RemoveElement(this->mIndex);
400 }
401}
402
403template <unsigned SPACE_DIM>
405{
406 for (unsigned i=0; i<this->GetNumNodes(); i++)
407 {
408 this->mNodes[i]->RemoveElement(this->mIndex);
409 }
410 this->mIndex = index;
411 RegisterWithNodes();
412 RegisterWithEdges();//does nothing in 1D
413 RebuildEdges();//does nothing in 1D
414}
415
416template<unsigned SPACE_DIM>
418 return mEdges.size();
419}
420
421template<unsigned SPACE_DIM>
423{
424 assert(localIndex < mEdges.size());
425 return mEdges[localIndex];
426}
427
428template <unsigned SPACE_DIM>
430{
431 for (unsigned i=0; i<mEdges.size(); ++i)
432 {
433 if ((*mEdges[i]) == (*pEdge))
434 {
435 return true;
436 }
437 }
438 return false;
439}
440
441template<unsigned SPACE_DIM>
443{
444 this->mEdgeHelper = pEdgeHelper;
445}
446
447template<unsigned SPACE_DIM>
449{
450 assert(mEdgeHelper != nullptr);
451
452 // If SPACE_DIM == 2 then we can assume that the node layout
453 // in the array corresponds to its connections
454 // We can then infer the edge connection information
455 if (SPACE_DIM == 2)
456 {
457 this->ClearEdges();
458 for (unsigned i = 0; i < this->mNodes.size(); i++)
459 {
460 unsigned i_next = (i+1) % this->mNodes.size();
461 mEdges.push_back(mEdgeHelper->GetEdgeFromNodes(this->mIndex, this->mNodes[i], this->mNodes[i_next]));
462 }
463 }
464}
465
466template<unsigned SPACE_DIM>
468{
469 for (auto p_edge : mEdges)
470 {
471 p_edge->RemoveElement(this->mIndex);
472 }
473 mEdges.clear();
474}
475
476template <unsigned SPACE_DIM>
478{
479 long result = -1;
480 for (unsigned i=0; i<mEdges.size(); ++i)
481 {
482 if ((*mEdges[i]) == (*pEdge))
483 {
484 result = i;
485 }
486 }
487 return result;
488}
489
490template<unsigned SPACE_DIM>
491unsigned MutableElement<1, SPACE_DIM>::GetEdgeGlobalIndex(unsigned localIndex) const
492{
493 assert(localIndex < mEdges.size());
494 return mEdges[localIndex]->GetIndex();
495}
496
497template<unsigned SPACE_DIM>
499{
500 assert(localIndex < mEdges.size());
501 return mEdges[localIndex]->GetOtherElements(this->mIndex);
502}
503
504template<unsigned SPACE_DIM>
506{
507 assert(rIndex < this->mNodes.size());
508
509 // Remove it from the node at this location
510 this->mNodes[rIndex]->RemoveElement(this->mIndex);
511
512 // Update the node at this location
513 this->mNodes[rIndex] = pNode;
514
515 // Add element to this node
516 this->mNodes[rIndex]->AddElement(this->mIndex);
517}
518
519template<unsigned SPACE_DIM>
521{
522 assert(rIndex < this->mNodes.size());
523
524 // Remove element from the node at this location
525 this->mNodes[rIndex]->RemoveElement(this->mIndex);
526
527 // Remove the node at rIndex (removes node from element)
528 this->mNodes.erase(this->mNodes.begin() + rIndex);
529}
530
531template<unsigned SPACE_DIM>
532void MutableElement<1, SPACE_DIM>::AddNode(Node<SPACE_DIM>* pNode, const unsigned& rIndex)
533{
534 assert(rIndex < this->mNodes.size());
535
536 // Add pNode to rIndex+1 element of mNodes pushing the others up
537 this->mNodes.insert(this->mNodes.begin() + rIndex+1, pNode);
538
539 // Add element to this node
540 this->mNodes[rIndex+1]->AddElement(this->mIndex);
541}
542
543template<unsigned SPACE_DIM>
544unsigned MutableElement<1, SPACE_DIM>::GetNodeLocalIndex(unsigned globalIndex) const
545{
546 unsigned local_index = UINT_MAX;
547 for (unsigned i=0; i<this->mNodes.size(); i++)
548 {
549 if (this->GetNodeGlobalIndex(i) == globalIndex)
550 {
551 local_index = i;
552 }
553 }
554 return local_index;
555}
556
557
558template<unsigned SPACE_DIM>
560 //Does nothing in 1D
561}
562
563template<unsigned SPACE_DIM>
565 //Does nothing in 1D
566}
567
568template<unsigned SPACE_DIM>
570{
571 bool is_element_on_boundary = false;
572 for (unsigned i=0; i<this->mNodes.size(); i++)
573 {
574 if (this->GetNode(i)->IsBoundaryNode())
575 {
576 is_element_on_boundary = true;
577 break;
578 }
579 }
580 return is_element_on_boundary;
581}
582
583// Explicit instantiation
584template class MutableElement<0,1>;
585template class MutableElement<1,1>;
586template class MutableElement<0,2>;
587template class MutableElement<1,2>;
588template class MutableElement<2,2>;
589template class MutableElement<0,3>;
590template class MutableElement<1,3>;
591template class MutableElement<2,3>;
592template class MutableElement<3,3>;
Definition Edge.hpp:52
MutableElement(unsigned index)
std::set< unsigned > GetNeighbouringElementAtEdgeIndex(unsigned localIndex)
unsigned GetEdgeGlobalIndex(unsigned localIndex) const
void ResetIndex(unsigned index)
virtual bool IsElementOnBoundary() const
long GetLocalEdgeIndex(const Edge< SPACE_DIM > *pEdge) const
void DeleteNode(const unsigned &rIndex)
virtual ~MutableElement()
bool ContainsEdge(const Edge< SPACE_DIM > *pEdge) const
void UpdateNode(const unsigned &rIndex, Node< SPACE_DIM > *pNode)
Edge< SPACE_DIM > * GetEdge(unsigned localIndex) const
void SetEdgeHelper(EdgeHelper< SPACE_DIM > *pEdgeHelper)
unsigned GetNodeLocalIndex(unsigned globalIndex) const
void AddNode(Node< SPACE_DIM > *pNode, const unsigned &rIndex)
unsigned GetNumEdges() const
Definition Node.hpp:59
void AddElement(unsigned index)
Definition Node.cpp:268
void RemoveElement(unsigned index)
Definition Node.cpp:274