Chaste Commit::f2ff7ee04e70ac9d06c57344df8d017dbb12b97b
Toroidal2dMesh.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 <map>
37
38/* These lines are very useful for debugging (visualize with 'showme').
39#include "TrianglesMeshWriter.hpp"
40TrianglesMeshWriter<2,2> mesh_writer("Toroidal2dMeshDebug", "mesh", false);
41mesh_writer.WriteFilesUsingMesh(*this);
42*/
43#include "Toroidal2dMesh.hpp"
44#include "Exception.hpp"
45#include "VtkMeshWriter.hpp"
46
47Toroidal2dMesh::Toroidal2dMesh(double width, double depth)
48 : MutableMesh<2,2>(),
49 mWidth(width),
50 mHeight(depth)
51{
52 assert(width > 0.0);
53 assert(depth > 0.0);
54}
55
59
60Toroidal2dMesh::Toroidal2dMesh(double width, double depth, std::vector<Node<2>* > nodes)
61 : MutableMesh<2,2>(),
62 mWidth(width),
63 mHeight(depth)
64{
65 assert(width > 0.0);
66 assert(depth > 0.0);
67
68 for (unsigned index=0; index<nodes.size(); index++)
69 {
70 Node<2>* p_temp_node = nodes[index];
71 double x = p_temp_node->rGetLocation()[0];
72 UNUSED_OPT(x); // Fix optimised build
73 assert( 0 <= x && x < width);
74 double y = p_temp_node->rGetLocation()[1];
75 UNUSED_OPT(y); // Fix optimised build
76 assert( 0 <= y && y < depth);
77 mNodes.push_back(p_temp_node);
78 }
79
80 NodeMap node_map(nodes.size());
81 ReMesh(node_map);
82}
83
85{
86 mLeftOriginals.clear();
87 mLeftImages.clear();
90
91 mRightOriginals.clear();
92 mRightImages.clear();
95
96 mTopOriginals.clear();
97 mTopImages.clear();
100
101 mBottomOriginals.clear();
102 mBottomImages.clear();
105
106
108 node_iter != GetNodeIteratorEnd();
109 ++node_iter)
110 {
111 c_vector<double, 2> location;
112 unsigned this_node_index = node_iter->GetIndex();
113
114 // Check the mesh currently conforms to the dimensions given
115 assert(0.0 <= node_iter->rGetLocation()[1]);
116 assert(node_iter->rGetLocation()[1] <= mHeight);
117
118 // Put the nodes which are to be mirrored in the relevant vectors
119 mBottomOriginals.push_back(this_node_index);
120 mTopOriginals.push_back(this_node_index);
121 }
122
123 // For each Bottom original node, create an image node and record its new index
124 for (unsigned i=0; i<mBottomOriginals.size(); i++)
125 {
126 c_vector<double, 2> location;
127 location = mNodes[mBottomOriginals[i]]->rGetLocation();
128 location[1] = location[1] + mHeight;
129
130 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
131 mBottomImages.push_back(new_node_index);
133 }
134
135 // For each Top original node, create an image node and record its new index
136 for (unsigned i=0; i<mTopOriginals.size(); i++)
137 {
138 c_vector<double, 2> location;
139 location = mNodes[mTopOriginals[i]]->rGetLocation();
140 location[1] = location[1] - mHeight;
141
142 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
143 mTopImages.push_back(new_node_index);
144 mImageToTopOriginalNodeMap[new_node_index] = mTopOriginals[i];
145 }
146
147 assert(mTopOriginals.size() == mTopImages.size());
148 assert(mBottomOriginals.size() == mBottomImages.size());
149 assert(mImageToBottomOriginalNodeMap.size() == mBottomOriginals.size());
150 assert(mImageToTopOriginalNodeMap.size() == mTopOriginals.size());
151
152
154 node_iter != GetNodeIteratorEnd();
155 ++node_iter)
156 {
157 c_vector<double, 2> location;
158 unsigned this_node_index = node_iter->GetIndex();
159
160 // Check the mesh currently conforms to the dimensions given
161 assert(0.0 <= node_iter->rGetLocation()[0]);
162 assert(node_iter->rGetLocation()[0] <= mWidth);
163
164 mLeftOriginals.push_back(this_node_index);
165 mRightOriginals.push_back(this_node_index);
166 }
167
168 // For each left original node, create an image node and record its new index
169 for (unsigned i=0; i<mLeftOriginals.size(); i++)
170 {
171 c_vector<double, 2> location;
172 location = mNodes[mLeftOriginals[i]]->rGetLocation();
173 location[0] = location[0] + mWidth;
174
175 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
176 mLeftImages.push_back(new_node_index);
177 mImageToLeftOriginalNodeMap[new_node_index] = mLeftOriginals[i];
178 }
179
180 // For each right original node, create an image node and record its new index
181 for (unsigned i=0; i<mRightOriginals.size(); i++)
182 {
183 c_vector<double, 2> location;
184 location = mNodes[mRightOriginals[i]]->rGetLocation();
185 location[0] = location[0] - mWidth;
186
187 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
188 mRightImages.push_back(new_node_index);
190 }
191
192 assert(mRightOriginals.size() == mRightImages.size());
193 assert(mLeftOriginals.size() == mLeftImages.size());
194 assert(mImageToLeftOriginalNodeMap.size() == mLeftOriginals.size());
195 assert(mImageToRightOriginalNodeMap.size() == mRightOriginals.size());
196
197}
198
200{
201 unsigned old_num_all_nodes = GetNumAllNodes();
202
203 rMap.Resize(old_num_all_nodes);
204 rMap.ResetToIdentity();
205
206 // Flag the deleted nodes as deleted in the map
207 for (unsigned i=0; i<old_num_all_nodes; i++)
208 {
209 if (mNodes[i]->IsDeleted())
210 {
211 rMap.SetDeleted(i);
212 }
213 }
214
215 // Create mirrored nodes for the normal remesher to work with
217
218 /*
219 * The mesh now has messed up boundary elements, but this
220 * doesn't matter as the ReMesh() below doesn't read them in
221 * and reconstructs the boundary elements.
222 *
223 * Call ReMesh() on the parent class. Note that the mesh now has lots
224 * of extra nodes which will be deleted, hence the name 'big_map'.
225 */
226 NodeMap big_map(GetNumAllNodes());
228
229 /*
230 * If the big_map isn't the identity map, the little map ('map') needs to be
231 * altered accordingly before being passed to the user. Not sure how this all
232 * works, so deal with this bridge when we get to it.
233 */
234 assert(big_map.IsIdentityMap());
235
236 /*
237 * Now remove any long edges to help stop extra edges on the boundary
238 *
239 * We need to do this extra step in the toroidal mesh as otherwise there can be extra edges
240 * on the left or right boundary due to remeshing the convex hull. See #3043
241 */
242 double left_boundary = -0.5*mWidth;
243 double right_boundary = 1.5*mWidth;
244 double bottom_boundary = -0.5*mHeight;
245 double top_boundary = 1.5*mHeight;
246
248 elem_iter != this->GetElementIteratorEnd();
249 ++elem_iter)
250 {
251 unsigned num_nodes_outside = 0;
252 for (unsigned j=0; j<3; j++)
253 {
254 Node<2>* p_node = this->GetNode(elem_iter->GetNodeGlobalIndex(j));
255
256 c_vector<double, 2> location;
257 location = p_node->rGetLocation();
258 double this_node_x_location = location[0];
259 double this_node_y_location = location[1];
260
261 if ((this_node_x_location < left_boundary) ||
262 (this_node_x_location > right_boundary) ||
263 (this_node_y_location < bottom_boundary) ||
264 (this_node_y_location > top_boundary))
265 {
266 num_nodes_outside++;
267 }
268
269 if (num_nodes_outside==3)
270 {
271 elem_iter->MarkAsDeleted();
272 mDeletedElementIndices.push_back(elem_iter->GetIndex());
273 }
274 }
275 }
277 elem_iter != this->GetBoundaryElementIteratorEnd();
278 ++elem_iter)
279 {
280 unsigned num_nodes_outside = 0;
281 for (unsigned j=0; j<2; j++)
282 {
283 Node<2>* p_node = this->GetNode((*elem_iter)->GetNodeGlobalIndex(j));
284
285 c_vector<double, 2> location;
286 location = p_node->rGetLocation();
287 double this_node_x_location = location[0];
288 double this_node_y_location = location[1];
289
290 if ((this_node_x_location < left_boundary) ||
291 (this_node_x_location > right_boundary) ||
292 (this_node_y_location < bottom_boundary) ||
293 (this_node_y_location > top_boundary))
294 {
295 num_nodes_outside++;
296 }
297
298 if (num_nodes_outside==2)
299 {
300 (*elem_iter)->MarkAsDeleted();
301 mDeletedBoundaryElementIndices.push_back((*elem_iter)->GetIndex());
302 }
303 }
304 }
305
306 // Re-index the vectors according to the big nodemap, and set up the maps.
309
310 assert(mLeftOriginals.size() == mLeftImages.size());
311 assert(mRightOriginals.size() == mRightImages.size());
312
313 for (unsigned i=0; i<mLeftOriginals.size(); i++)
314 {
316 mLeftImages[i] = big_map.GetNewIndex(mLeftImages[i]);
318 }
319
320 for (unsigned i=0; i<mRightOriginals.size(); i++)
321 {
323 mRightImages[i] = big_map.GetNewIndex(mRightImages[i]);
325 }
326
327 /*
328 * Check that elements crossing the periodic boundary have been meshed
329 * in the same way at each side.
330 */
332
333 /*
334 * Take the double-sized mesh, with its new boundary elements, and
335 * remove the relevant nodes, elements and boundary elements to leave
336 * a proper periodic mesh.
337 */
339
340 // We can now clear the index vectors and maps; they are only used for remeshing
341 mLeftOriginals.clear();
342 mLeftImages.clear();
344 mRightOriginals.clear();
345 mRightImages.clear();
349
350 // At this point we have an extended cylindrical mesh now we need to stitch the top and bottom together
351
352 // Re-index the vectors according to the big nodemap, and set up the maps.
355
356 assert(mBottomOriginals.size() == mBottomImages.size());
357 assert(mTopOriginals.size() == mTopImages.size());
358
359 for (unsigned i=0; i<mBottomOriginals.size(); i++)
360 {
362 mBottomImages[i] = big_map.GetNewIndex(mBottomImages[i]);
364 }
365
366 for (unsigned i=0; i<mTopOriginals.size(); i++)
367 {
368 mTopOriginals[i] = big_map.GetNewIndex(mTopOriginals[i]);
369 mTopImages[i] = big_map.GetNewIndex(mTopImages[i]);
371 }
372
373 /*
374 * Check that elements crossing the periodic boundary have been meshed
375 * in the same way at each side.
376 */
378
379 /*
380 * Take the double-sized mesh, with its new boundary elements, and
381 * remove the relevant nodes, elements and boundary elements to leave
382 * a proper periodic mesh.
383 */
385
386 /*
387 * Create a random boundary element between two nodes of the first
388 * element if it is not deleted. This is a temporary measure to get
389 * around re-index crashing when there are no boundary elements.
390 */
391 unsigned num_elements = GetNumAllElements();
392 bool boundary_element_made = false;
393 unsigned elem_index = 0;
394
395 while (elem_index<num_elements && !boundary_element_made)
396 {
397 Element<2,2>* p_element = GetElement(elem_index);
398 if (!p_element->IsDeleted())
399 {
400 boundary_element_made = true;
401 std::vector<Node<2>*> nodes;
402 nodes.push_back(p_element->GetNode(0));
403 nodes.push_back(p_element->GetNode(1));
404 BoundaryElement<1,2>* p_boundary_element = new BoundaryElement<1,2>(0, nodes);
405 p_boundary_element->RegisterWithNodes();
406 mBoundaryElements.push_back(p_boundary_element);
407 this->mBoundaryElementWeightedDirections.push_back(zero_vector<double>(2));
408 this->mBoundaryElementJacobianDeterminants.push_back(0.0);
409 }
410 elem_index++;
411 }
412
413 // Now call ReIndex() to remove the temporary nodes which are marked as deleted
414 NodeMap reindex_map(GetNumAllNodes());
415 ReIndex(reindex_map);
416 assert(!reindex_map.IsIdentityMap()); // maybe don't need this
417
418 /*
419 * Go through the reindex map and use it to populate the original NodeMap
420 * (the one that is returned to the user).
421 */
422 for (unsigned i=0; i<rMap.GetSize(); i++) // only going up to be size of map, not size of reindex_map
423 {
424 if (reindex_map.IsDeleted(i))
425 {
426 /*
427 * i < num_original_nodes and node is deleted, this should correspond to
428 * a node that was labelled as before the remeshing, so should have already
429 * been set as deleted in the map above.
430 */
431 assert(rMap.IsDeleted(i));
432 }
433 else
434 {
435 rMap.SetNewIndex(i, reindex_map.GetNewIndex(i));
436 }
437 }
438
439 // We can now clear the index vectors and maps; they are only used for remeshing
440 mBottomOriginals.clear();
441 mBottomImages.clear();
443 mTopOriginals.clear();
444 mTopImages.clear();
448
449}
450
452{
453 /*
454 * Figure out which elements have real nodes and image nodes in them
455 * and replace image nodes with corresponding real ones.
456 */
458 elem_iter != GetElementIteratorEnd();
459 ++elem_iter)
460 {
461 // Left images are on the right of the mesh
462 unsigned number_of_left_image_nodes = 0;
463 unsigned number_of_right_image_nodes = 0;
464
465 for (unsigned i=0; i<3; i++)
466 {
467 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
468
469 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
470 {
471 number_of_left_image_nodes++;
472 }
473 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
474 {
475 number_of_right_image_nodes++;
476 }
477 }
478
479 // Delete all the elements on the left hand side (images of right)...
480 if (number_of_right_image_nodes >= 1)
481 {
482 elem_iter->MarkAsDeleted();
483 mDeletedElementIndices.push_back(elem_iter->GetIndex());
484 }
485
486 // Delete only purely imaginary elements on the right (images of left nodes)
487 if (number_of_left_image_nodes == 3)
488 {
489 elem_iter->MarkAsDeleted();
490 mDeletedElementIndices.push_back(elem_iter->GetIndex());
491 }
492
493 /*
494 * If some are images then replace them with the real nodes. There
495 * can be elements with either two image nodes on the right (and one
496 * real) or one image node on the right (and two real).
497 */
498 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
499 {
500 for (unsigned i=0; i<3; i++)
501 {
502 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
503 std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
504 if (it != mImageToLeftOriginalNodeMap.end())
505 {
506 elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
507 }
508 }
509 }
510 }
511
512
513
514 // TODO #3043 include Boundary elements if needed
515 // /*
516 // * Figure out which boundary elements have real nodes and image nodes in them
517 // * and replace image nodes with corresponding real ones.
518 // */
519 // for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
520 // {
521 // BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
522 // if (!p_boundary_element->IsDeleted())
523 // {
524 // unsigned number_of_image_nodes = 0;
525 // for (unsigned i=0; i<2; i++)
526 // {
527 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
528
529 // if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
530 // {
531 // number_of_image_nodes++;
532 // }
533 // else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
534 // {
535 // number_of_image_nodes++;
536 // }
537 // }
538
539 // if (number_of_image_nodes == 2)
540 // {
541 // p_boundary_element->MarkAsDeleted();
542 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
543 // }
544
545 // /*
546 // * To avoid having two copies of the boundary elements on the periodic
547 // * boundaries we only deal with the elements on the left image and
548 // * delete the ones on the right image.
549 // */
550 // if (number_of_image_nodes == 1)
551 // {
552 // for (unsigned i=0; i<2; i++)
553 // {
554 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
555 // std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
556 // if (it != mImageToLeftOriginalNodeMap.end())
557 // {
558 // p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
559 // }
560 // else
561 // {
562 // it = mImageToRightOriginalNodeMap.find(this_node_index);
563 // if (it != mImageToRightOriginalNodeMap.end())
564 // {
565 // p_boundary_element->MarkAsDeleted();
566 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
567 // }
568 // }
569 // }
570 // }
571 // }
572 // }
573
574 // Delete all image nodes unless they have already gone
575 for (unsigned i=0; i<mLeftImages.size(); i++)
576 {
577 mNodes[mLeftImages[i]]->MarkAsDeleted();
578 mDeletedNodeIndices.push_back(mLeftImages[i]);
579 }
580
581 for (unsigned i=0; i<mRightImages.size(); i++)
582 {
583 mNodes[mRightImages[i]]->MarkAsDeleted();
584 mDeletedNodeIndices.push_back(mRightImages[i]);
585 }
586}
587
589{
590 /*
591 * Figure out which elements have real nodes and image nodes in them
592 * and replace image nodes with corresponding real ones.
593 */
595 elem_iter != GetElementIteratorEnd();
596 ++elem_iter)
597 {
598 // Bottom images are on the top of the mesh
599 unsigned number_of_bottom_image_nodes = 0;
600 unsigned number_of_top_image_nodes = 0;
601
602 for (unsigned i=0; i<3; i++)
603 {
604 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
605
606 if (mImageToBottomOriginalNodeMap.find(this_node_index) != mImageToBottomOriginalNodeMap.end())
607 {
608 number_of_bottom_image_nodes++;
609 }
610 else if (mImageToTopOriginalNodeMap.find(this_node_index) != mImageToTopOriginalNodeMap.end())
611 {
612 number_of_top_image_nodes++;
613 }
614 }
615
616 // Delete all the elements on the bottom hand side (images of top)...
617 if (number_of_top_image_nodes >= 1)
618 {
619 elem_iter->MarkAsDeleted();
620 mDeletedElementIndices.push_back(elem_iter->GetIndex());
621 }
622
623 // Delete only purely imaginary elements on the top (images of bottom nodes)
624 if (number_of_bottom_image_nodes == 3)
625 {
626 elem_iter->MarkAsDeleted();
627 mDeletedElementIndices.push_back(elem_iter->GetIndex());
628 }
629
630 /*
631 * If some are images then replace them with the real nodes. There
632 * can be elements with either two image nodes on the top (and one
633 * real) or one image node on the top (and two real).
634 */
635 if (number_of_bottom_image_nodes == 1 || number_of_bottom_image_nodes == 2)
636 {
637 for (unsigned i=0; i<3; i++)
638 {
639 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
640 std::map<unsigned, unsigned>::iterator it = mImageToBottomOriginalNodeMap.find(this_node_index);
641 if (it != mImageToBottomOriginalNodeMap.end())
642 {
643 elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
644 }
645 }
646 }
647 }
648
649 // TODO #3043 Deal with boundary nodes if wanted
650 // /*
651 // * Figure out which boundary elements have real nodes and image nodes in them
652 // * and replace image nodes with corresponding real ones.
653 // */
654 // for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
655 // {
656 // BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
657 // if (!p_boundary_element->IsDeleted())
658 // {
659 // unsigned number_of_image_nodes = 0;
660 // for (unsigned i=0; i<2; i++)
661 // {
662 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
663 // if (mImageToBottomOriginalNodeMap.find(this_node_index) != mImageToBottomOriginalNodeMap.end())
664 // {
665 // number_of_image_nodes++;
666 // }
667 // else if (mImageToTopOriginalNodeMap.find(this_node_index) != mImageToTopOriginalNodeMap.end())
668 // {
669 // number_of_image_nodes++;
670 // }
671 // }
672
673 // if (number_of_image_nodes == 2)
674 // {
675 // p_boundary_element->MarkAsDeleted();
676 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
677 // }
678
679 // /*
680 // * To avoid having two copies of the boundary elements on the periodic
681 // * boundaries we only deal with the elements on the bottom image and
682 // * delete the ones on the top image.
683 // */
684 // if (number_of_image_nodes == 1)
685 // {
686 // for (unsigned i=0; i<2; i++)
687 // {
688 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
689 // std::map<unsigned, unsigned>::iterator it = mImageToBottomOriginalNodeMap.find(this_node_index);
690 // if (it != mImageToBottomOriginalNodeMap.end())
691 // {
692 // p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
693 // }
694 // else
695 // {
696 // it = mImageToTopOriginalNodeMap.find(this_node_index);
697 // if (it != mImageToTopOriginalNodeMap.end())
698 // {
699 // p_boundary_element->MarkAsDeleted();
700 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
701 // }
702 // }
703 // }
704 // }
705 // }
706 // }
707
708 // Delete all image nodes unless they have already gone
709 for (unsigned i=0; i<mBottomImages.size(); i++)
710 {
711 mNodes[mBottomImages[i]]->MarkAsDeleted();
713 }
714
715 for (unsigned i=0; i<mTopImages.size(); i++)
716 {
717 mNodes[mTopImages[i]]->MarkAsDeleted();
718 mDeletedNodeIndices.push_back(mTopImages[i]);
719 }
720}
721
722c_vector<double, 2> Toroidal2dMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
723{
724 assert(mWidth > 0.0);
725 assert(mHeight > 0.0);
726
727 c_vector<double, 2> vector = rLocation2 - rLocation1;
728 vector[0] = fmod(vector[0], mWidth);
729 vector[1] = fmod(vector[1], mHeight);
730
731 /*
732 * Handle the Toroidal condition here: if the points are more
733 * than halfway around the domain apart, measure the other way.
734 */
735 if (vector[0] > 0.5*mWidth)
736 {
737 vector[0] -= mWidth;
738 }
739 else if (vector[0] < -0.5*mWidth)
740 {
741 vector[0] += mWidth;
742 }
743 if (vector[1] > 0.5*mHeight)
744 {
745 vector[1] -= mHeight;
746 }
747 else if (vector[1] < -0.5*mHeight)
748 {
749 vector[1] += mHeight;
750 }
751 return vector;
752}
753
754void Toroidal2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove)
755{
756
757 // Perform a width periodic movement if necessary
758 if (point.rGetLocation()[0] >= mWidth)
759 {
760 // Move point to the left
761 point.SetCoordinate(0, point.rGetLocation()[0] - mWidth);
762 }
763 else if (point.rGetLocation()[0] < 0.0)
764 {
765 // Move point to the right
766 point.SetCoordinate(0, point.rGetLocation()[0] + mWidth);
767 }
768
769 // Perform a depth periodic movement if necessary
770 if (point.rGetLocation()[1] >= mHeight)
771 {
772 // Move point down
773 point.SetCoordinate(1, point.rGetLocation()[1] - mHeight);
774 }
775 else if (point.rGetLocation()[1] < 0.0)
776 {
777 // Move point up
778 point.SetCoordinate(1, point.rGetLocation()[1] + mHeight);
779 }
780
781 // Update the node's location
782 MutableMesh<2,2>::SetNode(index, point, concreteMove);
783}
784
785double Toroidal2dMesh::GetWidth(const unsigned& rDimension) const
786{
787 double width = 0.0;
788 assert(rDimension==0 || rDimension==1);
789 if (rDimension==0)
790 {
791 width = mWidth;
792 }
793 else
794 {
795 width = mHeight;
796 }
797 return width;
798}
799
801{
802 unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode);
803
804 // If necessary move it to be back on the cylinder
805 ChastePoint<2> new_node_point = pNewNode->GetPoint();
806 SetNode(node_index, new_node_point, false);
807
808 return node_index;
809}
810
812{
814
815 /*
816 * Copy the member variables into new vectors, which we modify
817 * by knocking out elements which pair up on each side.
818 */
819 std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices;
820 std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices;
821
822// if ((mLeftPeriodicBoundaryElementIndices.size()!=mRightPeriodicBoundaryElementIndices.size())
823// || (temp_left_hand_side_elements.size() <= 2)
824// || (temp_right_hand_side_elements.size() <= 2) )
825// {
826// mMismatchedBoundaryElements = true;
827// }
829
830 // Go through all of the elements on the left periodic boundary
831 for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin();
832 left_iter != mLeftPeriodicBoundaryElementIndices.end();
833 ++left_iter)
834 {
835 unsigned elem_index = *left_iter;
836
837 Element<2,2>* p_element = GetElement(elem_index);
838
839 /*
840 * Make lists of the nodes which the elements on the left contain and
841 * the nodes which should be in a corresponding element on the right.
842 */
843 c_vector<unsigned,3> original_element_node_indices;
844 c_vector<unsigned,3> corresponding_element_node_indices;
845 for (unsigned i=0; i<3; i++)
846 {
847 original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
848 corresponding_element_node_indices[i] = GetCorrespondingCylindricalNodeIndex(original_element_node_indices[i]);
849 }
850
851 // Search the right hand side elements for the corresponding element
852 for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin();
853 right_iter != mRightPeriodicBoundaryElementIndices.end();
854 ++right_iter)
855 {
856 unsigned corresponding_elem_index = *right_iter;
857
858 Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
859
860 bool is_corresponding_node = true;
861
862 for (unsigned i=0; i<3; i++)
863 {
864 if ((corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
865 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
866 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
867 {
868 is_corresponding_node = false;
869 break;
870 }
871 }
872
873 if (is_corresponding_node)
874 {
875 // If this trips then you need to deal with remeshing where the left and right are different
876 // See #3043 and Cylindrical2dMesh
878 // Remove original and corresponding element from sets
879 // temp_left_hand_side_elements.erase(elem_index);
880 // temp_right_hand_side_elements.erase(corresponding_elem_index);
881 }
882 }
883 }
884
885 /*
886 * If either of these ever throw you have more than one situation where the mesher has an option
887 * of how to mesh. If it does ever throw you need to be cleverer and match up the
888 * elements into as many pairs as possible on the left hand and right hand sides.
889 */
890 //assert(temp_left_hand_side_elements.size() <= 2);
891 //assert(temp_right_hand_side_elements.size() <= 2);
892
893 /*
894 * Now we just have to use the first pair of elements and copy their info over to the other side.
895 * First we need to get hold of both elements on either side.
896 */
897 if (temp_left_hand_side_elements.empty() || temp_right_hand_side_elements.empty())
898 {
900 //assert(temp_right_hand_side_elements.empty());
901 //assert(temp_left_hand_side_elements.empty());
902 }
903 else
904 {
905 if (temp_right_hand_side_elements.size() == 2 && temp_left_hand_side_elements.size() == 2)
906 {
907 /*
908 * If you get here there are mixed up elements on the periodic edge.
909 * We need to knock the pair out and then rerun this function. This shouldn't be
910 * too hard to do but is as yet unnecessary.
911 */
913 }
914 }
915}
916
918{
920
921 /*
922 * Copy the member variables into new vectors, which we modify
923 * by knocking out elements which pair up on each side.
924 */
925 std::set<unsigned> temp_bottom_hand_side_elements = mBottomPeriodicBoundaryElementIndices;
926 std::set<unsigned> temp_top_hand_side_elements = mTopPeriodicBoundaryElementIndices;
927
928// if ((mBottomPeriodicBoundaryElementIndices.size()!=mTopPeriodicBoundaryElementIndices.size())
929// || (temp_bottom_hand_side_elements.size() <= 2)
930// || (temp_top_hand_side_elements.size() <= 2) )
931// {
932// mMismatchedBoundaryElements = true;
933// }
935
936 // Go through all of the elements on the bottom periodic boundary
937 for (std::set<unsigned>::iterator bottom_iter = mBottomPeriodicBoundaryElementIndices.begin();
938 bottom_iter != mBottomPeriodicBoundaryElementIndices.end();
939 ++bottom_iter)
940 {
941 unsigned elem_index = *bottom_iter;
942
943 Element<2,2>* p_element = GetElement(elem_index);
944
945 /*
946 * Make lists of the nodes which the elements on the bottom contain and
947 * the nodes which should be in a corresponding element on the top.
948 */
949 c_vector<unsigned,3> original_element_node_indices;
950 c_vector<unsigned,3> corresponding_element_node_indices;
951 for (unsigned i=0; i<3; i++)
952 {
953 original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
954 corresponding_element_node_indices[i] = GetCorrespondingToroidalNodeIndex(original_element_node_indices[i]);
955 }
956
957 // Search the top hand side elements for the corresponding element
958 for (std::set<unsigned>::iterator top_iter = mTopPeriodicBoundaryElementIndices.begin();
959 top_iter != mTopPeriodicBoundaryElementIndices.end();
960 ++top_iter)
961 {
962 unsigned corresponding_elem_index = *top_iter;
963
964 Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
965
966 bool is_corresponding_node = true;
967
968 for (unsigned i=0; i<3; i++)
969 {
970 if ((corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
971 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
972 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
973 {
974 is_corresponding_node = false;
975 break;
976 }
977 }
978
979 if (is_corresponding_node)
980 {
981 // If this trips then you need to deal with remeshing where the left and right are different
982 // See #3043 and Cylindrical2dMesh
984
985 // Remove original and corresponding element from sets
986 //temp_bottom_hand_side_elements.erase(elem_index);
987 temp_top_hand_side_elements.erase(corresponding_elem_index);
988 }
989 }
990 }
991
992 /*
993 * If either of these ever throw you have more than one situation where the mesher has an option
994 * of how to mesh. If it does ever throw you need to be cleverer and match up the
995 * elements into as many pairs as possible on the left hand and right hand sides.
996 */
997 //assert(temp_bottom_hand_side_elements.size() <= 2);
998 //assert(temp_top_hand_side_elements.size() <= 2);
999
1000 /*
1001 * Now we just have to use the first pair of elements and copy their info over to the other side.
1002 * First we need to get hold of both elements on either side.
1003 */
1004 if (temp_bottom_hand_side_elements.empty() || temp_top_hand_side_elements.empty())
1005 {
1007 //assert(temp_top_hand_side_elements.empty());
1008 //assert(temp_bottom_hand_side_elements.empty());
1009 }
1010 else
1011 {
1012 if (temp_top_hand_side_elements.size() == 2 && temp_bottom_hand_side_elements.size() == 2)
1013 {
1014 /*
1015 * If you get here there are mixed up elements on the periodic edge.
1016 * We need to knock the pair out and then rerun this function. This shouldn't be
1017 * too hard to do but is as yet unnecessary.
1018 */
1020 }
1021 }
1022}
1023
1025{
1028
1029 unsigned incidences_of_zero_left_image_nodes = 0;
1030 unsigned incidences_of_zero_right_image_nodes = 0;
1031
1033 elem_iter != GetElementIteratorEnd();
1034 ++elem_iter)
1035 {
1036 // Left images are on the right of the mesh
1037 unsigned number_of_left_image_nodes = 0;
1038 unsigned number_of_right_image_nodes = 0;
1039
1040 for (unsigned i=0; i<3; i++)
1041 {
1042 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
1043
1044 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
1045 {
1046 number_of_left_image_nodes++;
1047 }
1048 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
1049 {
1050 number_of_right_image_nodes++;
1051 }
1052 }
1053
1054 if ((number_of_left_image_nodes == 0) && (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2) )
1055 {
1056 incidences_of_zero_left_image_nodes++;
1057 }
1058 if ((number_of_right_image_nodes == 0) && (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2) )
1059 {
1060 incidences_of_zero_right_image_nodes++;
1061 }
1062
1063 /* SJ - Have checked the following:
1064 * - It is never the case that number_of_left_image_nodes + number_of_right_image_nodes > 3
1065 * - There are 1264 incidences of zero left image nodes, and 1252 incidences of zero right image nodes
1066 * - There are 450 incidences of zero left image nodes and non-zero right image nodes; 438 incidences of zero right image nodes and non-zero left
1067 * image nodes
1068 * - There are 40 incidences of 0 left image nodes, and 1/2 right image nodes; 39 incidences of 0 right image nodes and 1/2 left image nodes
1069 * As this corresponds to 40 left-hand boundary elements and 39 right-hand boundary elements, then it is this extra occurrence of a 0 left
1070 * image node with 1/2 right image nodes that is responsible for the extra element.
1071 */
1072
1073 // Elements on the left hand side (images of right nodes)
1074 if (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2)
1075 {
1076 mLeftPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1077 }
1078
1079 // Elements on the right (images of left nodes)
1080 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
1081 {
1082 mRightPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1083 }
1084 }
1085
1086// if (mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
1087// {
1088// mMismatchedBoundaryElements = true;
1089// // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
1090//
1091// }
1092
1093 // Every boundary element on the left must have a corresponding element on the right
1095 // if(mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
1096 // {
1097 // TRACE("Left");
1098 // PRINT_VARIABLE(mLeftPeriodicBoundaryElementIndices.size());
1099 // for (std::set<unsigned>::iterator iter = mLeftPeriodicBoundaryElementIndices.begin();
1100 // iter != mLeftPeriodicBoundaryElementIndices.end();
1101 // iter++)
1102 // {
1103 // PRINT_VARIABLE(*iter);
1104 // }
1105 // TRACE("Right");
1106 // PRINT_VARIABLE(mRightPeriodicBoundaryElementIndices.size());
1107 // for (std::set<unsigned>::iterator iter = mRightPeriodicBoundaryElementIndices.begin();
1108 // iter != mRightPeriodicBoundaryElementIndices.end();
1109 // iter++)
1110 // {
1111 // PRINT_VARIABLE(*iter);
1112 // }
1113
1114 // }
1115}
1116
1118{
1121
1122 unsigned incidences_of_zero_bottom_image_nodes = 0;
1123 unsigned incidences_of_zero_top_image_nodes = 0;
1124
1126 elem_iter != GetElementIteratorEnd();
1127 ++elem_iter)
1128 {
1129 // Left images are on the right of the mesh
1130 unsigned number_of_bottom_image_nodes = 0;
1131 unsigned number_of_top_image_nodes = 0;
1132
1133 for (unsigned i=0; i<3; i++)
1134 {
1135 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
1136
1137 if (mImageToBottomOriginalNodeMap.find(this_node_index) != mImageToBottomOriginalNodeMap.end())
1138 {
1139 number_of_bottom_image_nodes++;
1140 }
1141 else if (mImageToTopOriginalNodeMap.find(this_node_index) != mImageToTopOriginalNodeMap.end())
1142 {
1143 number_of_top_image_nodes++;
1144 }
1145 }
1146
1147 if ((number_of_bottom_image_nodes == 0) && (number_of_top_image_nodes == 1 || number_of_top_image_nodes == 2) )
1148 {
1149 incidences_of_zero_bottom_image_nodes++;
1150 }
1151 if ((number_of_top_image_nodes == 0) && (number_of_bottom_image_nodes == 1 || number_of_bottom_image_nodes == 2) )
1152 {
1153 incidences_of_zero_top_image_nodes++;
1154 }
1155
1156 // Elements on the bottom hand side (images of top nodes)
1157 if (number_of_top_image_nodes == 1 || number_of_top_image_nodes == 2)
1158 {
1159 mBottomPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1160 }
1161
1162 // Elements on the right (images of bottom nodes)
1163 if (number_of_bottom_image_nodes == 1 || number_of_bottom_image_nodes == 2)
1164 {
1165 mTopPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1166 }
1167 }
1168
1169// if (mBottomPeriodicBoundaryElementIndices.size() != mTopPeriodicBoundaryElementIndices.size())
1170// {
1171// mMismatchedBoundaryElements = true;
1172// // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
1173//
1174// }
1175
1176 // Every boundary element on the bottom must have a corresponding element on the top
1178}
1179
1181{
1182 unsigned corresponding_node_index = UINT_MAX;
1183
1184 // If nodeIndex is a member of mRightOriginals, then find the corresponding node index in mRightImages
1185 std::vector<unsigned>::iterator right_orig_iter = std::find(mRightOriginals.begin(), mRightOriginals.end(), nodeIndex);
1186 if (right_orig_iter != mRightOriginals.end())
1187 {
1188 corresponding_node_index = mRightImages[right_orig_iter - mRightOriginals.begin()];
1189 }
1190 else
1191 {
1192 // If nodeIndex is a member of mRightImages, then find the corresponding node index in mRightOriginals
1193 std::vector<unsigned>::iterator right_im_iter = std::find(mRightImages.begin(), mRightImages.end(), nodeIndex);
1194 if (right_im_iter != mRightImages.end())
1195 {
1196 corresponding_node_index = mRightOriginals[right_im_iter - mRightImages.begin()];
1197 }
1198 else
1199 {
1200 // This isn't needed as now we copy all nodes to the left and right.
1201 // If you reach here then you have probably
1202 // Changed it back to half the nodes or similar
1204
1205 // // If nodeIndex is a member of mLeftOriginals, then find the corresponding node index in mLeftImages
1206 // std::vector<unsigned>::iterator left_orig_iter = std::find(mLeftOriginals.begin(), mLeftOriginals.end(), nodeIndex);
1207 // if (left_orig_iter != mLeftOriginals.end())
1208 // {
1209 // corresponding_node_index = mLeftImages[left_orig_iter - mLeftOriginals.begin()];
1210 // }
1211 // else
1212 // {
1213 // // If nodeIndex is a member of mLeftImages, then find the corresponding node index in mLeftOriginals
1214 // std::vector<unsigned>::iterator left_im_iter = std::find(mLeftImages.begin(), mLeftImages.end(), nodeIndex);
1215 // if (left_im_iter != mLeftImages.end())
1216 // {
1217 // corresponding_node_index = mLeftOriginals[left_im_iter - mLeftImages.begin()];
1218 // }
1219 // }
1220 }
1221 }
1222
1223 // We must have found the corresponding node index
1224 assert(corresponding_node_index != UINT_MAX);
1225 return corresponding_node_index;
1226}
1227
1228
1230{
1231 unsigned corresponding_node_index = UINT_MAX;
1232
1233 // If nodeIndex is a member of mTopOriginals, then find the corresponding node index in mTopImages
1234 std::vector<unsigned>::iterator top_orig_iter = std::find(mTopOriginals.begin(), mTopOriginals.end(), nodeIndex);
1235 if (top_orig_iter != mTopOriginals.end())
1236 {
1237 corresponding_node_index = mTopImages[top_orig_iter - mTopOriginals.begin()];
1238 }
1239 else
1240 {
1241 // If nodeIndex is a member of mTopImages, then find the corresponding node index in mTopOriginals
1242 std::vector<unsigned>::iterator top_im_iter = std::find(mTopImages.begin(), mTopImages.end(), nodeIndex);
1243 if (top_im_iter != mTopImages.end())
1244 {
1245 corresponding_node_index = mTopOriginals[top_im_iter - mTopImages.begin()];
1246 }
1247 else
1248 {
1249 // This isn't needed as now we copy all nodes to the top and bottom.
1250 // If you reach here then you have probably
1251 // Changed it back to half the nodes or similar
1253
1254 // // If nodeIndex is a member of mBottomOriginals, then find the corresponding node index in mBottomImages
1255 // std::vector<unsigned>::iterator bottom_orig_iter = std::find(mBottomOriginals.begin(), mBottomOriginals.end(), nodeIndex);
1256 // if (bottom_orig_iter != mBottomOriginals.end())
1257 // {
1258 // corresponding_node_index = mBottomImages[bottom_orig_iter - mBottomOriginals.begin()];
1259 // }
1260 // else
1261 // {
1262 // // If nodeIndex is a member of mBottomImages, then find the corresponding node index in mBottomOriginals
1263 // std::vector<unsigned>::iterator bottom_im_iter = std::find(mBottomImages.begin(), mBottomImages.end(), nodeIndex);
1264 // if (bottom_im_iter != mBottomImages.end())
1265 // {
1266 // corresponding_node_index = mBottomOriginals[bottom_im_iter - mBottomImages.begin()];
1267 // }
1268 // }
1269 }
1270 }
1271
1272 // We must have found the corresponding node index
1273 assert(corresponding_node_index != UINT_MAX);
1274 return corresponding_node_index;
1275}
1276
1277
1279{
1280 // Check if the (x,y) coordinates are in the domain, if not, get the fmod and relocate.
1281 unsigned num_nodes = mNodes.size();
1282 for (unsigned i=0; i<num_nodes; i++)
1283 {
1284 double& x_location = (mNodes[i]->rGetModifiableLocation())[0];
1285 if (x_location < 0.0)
1286 {
1287 x_location = fmod(x_location, mWidth) + mWidth;
1288 }
1289 else if (x_location >= mWidth)
1290 {
1291 x_location = fmod(x_location, mWidth);
1292 }
1293 double& y_location = (mNodes[i]->rGetModifiableLocation())[1];
1294 if (y_location < 0.0)
1295 {
1296 y_location = fmod(y_location, mHeight) + mHeight;
1297 }
1298 else if (y_location >= mHeight)
1299 {
1300 y_location = fmod(y_location, mHeight);
1301 }
1302 }
1303
1304 // Now run the base class method
1305 //TetrahedralMesh<2,2>::RefreshMesh();
1306}
1307
1308// Serialization for Boost >= 1.36
#define UNUSED_OPT(var)
#define NEVER_REACHED
#define CHASTE_CLASS_EXPORT(T)
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
bool IsDeleted() const
unsigned GetNodeGlobalIndex(unsigned localIndex) const
virtual unsigned GetNumAllNodes() const
NodeIterator GetNodeIteratorEnd()
Node< SPACE_DIM > * GetNode(unsigned index) const
std::vector< Node< SPACE_DIM > * > mNodes
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * >::const_iterator BoundaryElementIterator
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
BoundaryElementIterator GetBoundaryElementIteratorBegin() const
BoundaryElementIterator GetBoundaryElementIteratorEnd() const
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * > mBoundaryElements
c_vector< double, DIM > & rGetLocation()
void SetCoordinate(unsigned i, double value)
void ReIndex(NodeMap &map)
virtual void SetNode(unsigned index, ChastePoint< SPACE_DIM > point, bool concreteMove=true)
std::vector< unsigned > mDeletedBoundaryElementIndices
std::vector< unsigned > mDeletedElementIndices
std::vector< unsigned > mDeletedNodeIndices
virtual unsigned AddNode(Node< SPACE_DIM > *pNewNode)
void SetDeleted(unsigned index)
Definition NodeMap.cpp:76
unsigned GetNewIndex(unsigned oldIndex) const
Definition NodeMap.cpp:87
bool IsIdentityMap()
Definition NodeMap.cpp:100
void ResetToIdentity()
Definition NodeMap.cpp:57
unsigned GetSize()
Definition NodeMap.cpp:105
void SetNewIndex(unsigned oldIndex, unsigned newIndex)
Definition NodeMap.cpp:66
void Resize(unsigned size)
Definition NodeMap.cpp:52
bool IsDeleted(unsigned index)
Definition NodeMap.cpp:82
Definition Node.hpp:59
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition Node.cpp:139
ChastePoint< SPACE_DIM > GetPoint() const
Definition Node.cpp:133
std::vector< double > mBoundaryElementJacobianDeterminants
std::vector< c_vector< double, SPACE_DIM > > mBoundaryElementWeightedDirections
std::vector< unsigned > mBottomOriginals
std::map< unsigned, unsigned > mImageToRightOriginalNodeMap
void GenerateVectorsOfElementsStraddlingToroidalPeriodicBoundaries()
std::vector< unsigned > mLeftImages
std::vector< unsigned > mRightOriginals
Toroidal2dMesh(double width, double depth)
std::set< unsigned > mBottomPeriodicBoundaryElementIndices
void ReconstructToroidalMesh()
std::map< unsigned, unsigned > mImageToTopOriginalNodeMap
std::set< unsigned > mTopPeriodicBoundaryElementIndices
std::vector< unsigned > mLeftOriginals
unsigned GetCorrespondingToroidalNodeIndex(unsigned nodeIndex)
void SetNode(unsigned index, ChastePoint< 2 > point, bool concreteMove)
void CorrectToroidalNonPeriodicMesh()
std::set< unsigned > mLeftPeriodicBoundaryElementIndices
std::map< unsigned, unsigned > mImageToBottomOriginalNodeMap
c_vector< double, 2 > GetVectorFromAtoB(const c_vector< double, 2 > &rLocation1, const c_vector< double, 2 > &rLocation2)
std::vector< unsigned > mRightImages
std::set< unsigned > mRightPeriodicBoundaryElementIndices
std::vector< unsigned > mTopOriginals
unsigned GetCorrespondingCylindricalNodeIndex(unsigned nodeIndex)
void ReconstructCylindricalMesh()
double GetWidth(const unsigned &rDimension) const
std::vector< unsigned > mBottomImages
std::map< unsigned, unsigned > mImageToLeftOriginalNodeMap
unsigned AddNode(Node< 2 > *pNewNode)
void CorrectCylindricalNonPeriodicMesh()
std::vector< unsigned > mTopImages
void GenerateVectorsOfElementsStraddlingCylindricalPeriodicBoundaries()