Chaste Commit::baa90ac2819b962188b7562f2326be23c47859a7
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 = p_node->rGetLocation();
257 double this_node_x_location = location[0];
258 double this_node_y_location = location[1];
259
260 if ((this_node_x_location < left_boundary) ||
261 (this_node_x_location > right_boundary) ||
262 (this_node_y_location < bottom_boundary) ||
263 (this_node_y_location > top_boundary))
264 {
265 num_nodes_outside++;
266 }
267
268 if (num_nodes_outside==3)
269 {
270 elem_iter->MarkAsDeleted();
271 mDeletedElementIndices.push_back(elem_iter->GetIndex());
272 }
273 }
274 }
276 elem_iter != this->GetBoundaryElementIteratorEnd();
277 ++elem_iter)
278 {
279 unsigned num_nodes_outside = 0;
280 for (unsigned j=0; j<2; j++)
281 {
282 Node<2>* p_node = this->GetNode((*elem_iter)->GetNodeGlobalIndex(j));
283
284 c_vector<double, 2> location = p_node->rGetLocation();
285 double this_node_x_location = location[0];
286 double this_node_y_location = location[1];
287
288 if ((this_node_x_location < left_boundary) ||
289 (this_node_x_location > right_boundary) ||
290 (this_node_y_location < bottom_boundary) ||
291 (this_node_y_location > top_boundary))
292 {
293 num_nodes_outside++;
294 }
295
296 if (num_nodes_outside==2)
297 {
298 (*elem_iter)->MarkAsDeleted();
299 mDeletedBoundaryElementIndices.push_back((*elem_iter)->GetIndex());
300 }
301 }
302 }
303
304 // Re-index the vectors according to the big nodemap, and set up the maps.
307
308 assert(mLeftOriginals.size() == mLeftImages.size());
309 assert(mRightOriginals.size() == mRightImages.size());
310
311 for (unsigned i=0; i<mLeftOriginals.size(); i++)
312 {
314 mLeftImages[i] = big_map.GetNewIndex(mLeftImages[i]);
316 }
317
318 for (unsigned i=0; i<mRightOriginals.size(); i++)
319 {
321 mRightImages[i] = big_map.GetNewIndex(mRightImages[i]);
323 }
324
325 /*
326 * Check that elements crossing the periodic boundary have been meshed
327 * in the same way at each side.
328 */
330
331 /*
332 * Take the double-sized mesh, with its new boundary elements, and
333 * remove the relevant nodes, elements and boundary elements to leave
334 * a proper periodic mesh.
335 */
337
338 // We can now clear the index vectors and maps; they are only used for remeshing
339 mLeftOriginals.clear();
340 mLeftImages.clear();
342 mRightOriginals.clear();
343 mRightImages.clear();
347
348 // At this point we have an extended cylindrical mesh now we need to stitch the top and bottom together
349
350 // Re-index the vectors according to the big nodemap, and set up the maps.
353
354 assert(mBottomOriginals.size() == mBottomImages.size());
355 assert(mTopOriginals.size() == mTopImages.size());
356
357 for (unsigned i=0; i<mBottomOriginals.size(); i++)
358 {
360 mBottomImages[i] = big_map.GetNewIndex(mBottomImages[i]);
362 }
363
364 for (unsigned i=0; i<mTopOriginals.size(); i++)
365 {
366 mTopOriginals[i] = big_map.GetNewIndex(mTopOriginals[i]);
367 mTopImages[i] = big_map.GetNewIndex(mTopImages[i]);
369 }
370
371 /*
372 * Check that elements crossing the periodic boundary have been meshed
373 * in the same way at each side.
374 */
376
377 /*
378 * Take the double-sized mesh, with its new boundary elements, and
379 * remove the relevant nodes, elements and boundary elements to leave
380 * a proper periodic mesh.
381 */
383
384 /*
385 * Create a random boundary element between two nodes of the first
386 * element if it is not deleted. This is a temporary measure to get
387 * around re-index crashing when there are no boundary elements.
388 */
389 unsigned num_elements = GetNumAllElements();
390 bool boundary_element_made = false;
391 unsigned elem_index = 0;
392
393 while (elem_index<num_elements && !boundary_element_made)
394 {
395 Element<2,2>* p_element = GetElement(elem_index);
396 if (!p_element->IsDeleted())
397 {
398 boundary_element_made = true;
399 std::vector<Node<2>*> nodes;
400 nodes.push_back(p_element->GetNode(0));
401 nodes.push_back(p_element->GetNode(1));
402 BoundaryElement<1,2>* p_boundary_element = new BoundaryElement<1,2>(0, nodes);
403 p_boundary_element->RegisterWithNodes();
404 mBoundaryElements.push_back(p_boundary_element);
405 this->mBoundaryElementWeightedDirections.push_back(zero_vector<double>(2));
406 this->mBoundaryElementJacobianDeterminants.push_back(0.0);
407 }
408 elem_index++;
409 }
410
411 // Now call ReIndex() to remove the temporary nodes which are marked as deleted
412 NodeMap reindex_map(GetNumAllNodes());
413 ReIndex(reindex_map);
414 assert(!reindex_map.IsIdentityMap()); // maybe don't need this
415
416 /*
417 * Go through the reindex map and use it to populate the original NodeMap
418 * (the one that is returned to the user).
419 */
420 for (unsigned i=0; i<rMap.GetSize(); i++) // only going up to be size of map, not size of reindex_map
421 {
422 if (reindex_map.IsDeleted(i))
423 {
424 /*
425 * i < num_original_nodes and node is deleted, this should correspond to
426 * a node that was labelled as before the remeshing, so should have already
427 * been set as deleted in the map above.
428 */
429 assert(rMap.IsDeleted(i));
430 }
431 else
432 {
433 rMap.SetNewIndex(i, reindex_map.GetNewIndex(i));
434 }
435 }
436
437 // We can now clear the index vectors and maps; they are only used for remeshing
438 mBottomOriginals.clear();
439 mBottomImages.clear();
441 mTopOriginals.clear();
442 mTopImages.clear();
446
447}
448
450{
451 /*
452 * Figure out which elements have real nodes and image nodes in them
453 * and replace image nodes with corresponding real ones.
454 */
456 elem_iter != GetElementIteratorEnd();
457 ++elem_iter)
458 {
459 // Left images are on the right of the mesh
460 unsigned number_of_left_image_nodes = 0;
461 unsigned number_of_right_image_nodes = 0;
462
463 for (unsigned i=0; i<3; i++)
464 {
465 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
466
467 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
468 {
469 number_of_left_image_nodes++;
470 }
471 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
472 {
473 number_of_right_image_nodes++;
474 }
475 }
476
477 // Delete all the elements on the left hand side (images of right)...
478 if (number_of_right_image_nodes >= 1)
479 {
480 elem_iter->MarkAsDeleted();
481 mDeletedElementIndices.push_back(elem_iter->GetIndex());
482 }
483
484 // Delete only purely imaginary elements on the right (images of left nodes)
485 if (number_of_left_image_nodes == 3)
486 {
487 elem_iter->MarkAsDeleted();
488 mDeletedElementIndices.push_back(elem_iter->GetIndex());
489 }
490
491 /*
492 * If some are images then replace them with the real nodes. There
493 * can be elements with either two image nodes on the right (and one
494 * real) or one image node on the right (and two real).
495 */
496 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
497 {
498 for (unsigned i=0; i<3; i++)
499 {
500 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
501 std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
502 if (it != mImageToLeftOriginalNodeMap.end())
503 {
504 elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
505 }
506 }
507 }
508 }
509
510
511
512 // TODO #3043 include Boundary elements if needed
513 // /*
514 // * Figure out which boundary elements have real nodes and image nodes in them
515 // * and replace image nodes with corresponding real ones.
516 // */
517 // for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
518 // {
519 // BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
520 // if (!p_boundary_element->IsDeleted())
521 // {
522 // unsigned number_of_image_nodes = 0;
523 // for (unsigned i=0; i<2; i++)
524 // {
525 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
526
527 // if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
528 // {
529 // number_of_image_nodes++;
530 // }
531 // else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
532 // {
533 // number_of_image_nodes++;
534 // }
535 // }
536
537 // if (number_of_image_nodes == 2)
538 // {
539 // p_boundary_element->MarkAsDeleted();
540 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
541 // }
542
543 // /*
544 // * To avoid having two copies of the boundary elements on the periodic
545 // * boundaries we only deal with the elements on the left image and
546 // * delete the ones on the right image.
547 // */
548 // if (number_of_image_nodes == 1)
549 // {
550 // for (unsigned i=0; i<2; i++)
551 // {
552 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
553 // std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
554 // if (it != mImageToLeftOriginalNodeMap.end())
555 // {
556 // p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
557 // }
558 // else
559 // {
560 // it = mImageToRightOriginalNodeMap.find(this_node_index);
561 // if (it != mImageToRightOriginalNodeMap.end())
562 // {
563 // p_boundary_element->MarkAsDeleted();
564 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
565 // }
566 // }
567 // }
568 // }
569 // }
570 // }
571
572 // Delete all image nodes unless they have already gone
573 for (unsigned i=0; i<mLeftImages.size(); i++)
574 {
575 mNodes[mLeftImages[i]]->MarkAsDeleted();
576 mDeletedNodeIndices.push_back(mLeftImages[i]);
577 }
578
579 for (unsigned i=0; i<mRightImages.size(); i++)
580 {
581 mNodes[mRightImages[i]]->MarkAsDeleted();
582 mDeletedNodeIndices.push_back(mRightImages[i]);
583 }
584}
585
587{
588 /*
589 * Figure out which elements have real nodes and image nodes in them
590 * and replace image nodes with corresponding real ones.
591 */
593 elem_iter != GetElementIteratorEnd();
594 ++elem_iter)
595 {
596 // Bottom images are on the top of the mesh
597 unsigned number_of_bottom_image_nodes = 0;
598 unsigned number_of_top_image_nodes = 0;
599
600 for (unsigned i=0; i<3; i++)
601 {
602 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
603
604 if (mImageToBottomOriginalNodeMap.find(this_node_index) != mImageToBottomOriginalNodeMap.end())
605 {
606 number_of_bottom_image_nodes++;
607 }
608 else if (mImageToTopOriginalNodeMap.find(this_node_index) != mImageToTopOriginalNodeMap.end())
609 {
610 number_of_top_image_nodes++;
611 }
612 }
613
614 // Delete all the elements on the bottom hand side (images of top)...
615 if (number_of_top_image_nodes >= 1)
616 {
617 elem_iter->MarkAsDeleted();
618 mDeletedElementIndices.push_back(elem_iter->GetIndex());
619 }
620
621 // Delete only purely imaginary elements on the top (images of bottom nodes)
622 if (number_of_bottom_image_nodes == 3)
623 {
624 elem_iter->MarkAsDeleted();
625 mDeletedElementIndices.push_back(elem_iter->GetIndex());
626 }
627
628 /*
629 * If some are images then replace them with the real nodes. There
630 * can be elements with either two image nodes on the top (and one
631 * real) or one image node on the top (and two real).
632 */
633 if (number_of_bottom_image_nodes == 1 || number_of_bottom_image_nodes == 2)
634 {
635 for (unsigned i=0; i<3; i++)
636 {
637 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
638 std::map<unsigned, unsigned>::iterator it = mImageToBottomOriginalNodeMap.find(this_node_index);
639 if (it != mImageToBottomOriginalNodeMap.end())
640 {
641 elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
642 }
643 }
644 }
645 }
646
647 // TODO #3043 Deal with boundary nodes if wanted
648 // /*
649 // * Figure out which boundary elements have real nodes and image nodes in them
650 // * and replace image nodes with corresponding real ones.
651 // */
652 // for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
653 // {
654 // BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
655 // if (!p_boundary_element->IsDeleted())
656 // {
657 // unsigned number_of_image_nodes = 0;
658 // for (unsigned i=0; i<2; i++)
659 // {
660 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
661 // if (mImageToBottomOriginalNodeMap.find(this_node_index) != mImageToBottomOriginalNodeMap.end())
662 // {
663 // number_of_image_nodes++;
664 // }
665 // else if (mImageToTopOriginalNodeMap.find(this_node_index) != mImageToTopOriginalNodeMap.end())
666 // {
667 // number_of_image_nodes++;
668 // }
669 // }
670
671 // if (number_of_image_nodes == 2)
672 // {
673 // p_boundary_element->MarkAsDeleted();
674 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
675 // }
676
677 // /*
678 // * To avoid having two copies of the boundary elements on the periodic
679 // * boundaries we only deal with the elements on the bottom image and
680 // * delete the ones on the top image.
681 // */
682 // if (number_of_image_nodes == 1)
683 // {
684 // for (unsigned i=0; i<2; i++)
685 // {
686 // unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
687 // std::map<unsigned, unsigned>::iterator it = mImageToBottomOriginalNodeMap.find(this_node_index);
688 // if (it != mImageToBottomOriginalNodeMap.end())
689 // {
690 // p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
691 // }
692 // else
693 // {
694 // it = mImageToTopOriginalNodeMap.find(this_node_index);
695 // if (it != mImageToTopOriginalNodeMap.end())
696 // {
697 // p_boundary_element->MarkAsDeleted();
698 // mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
699 // }
700 // }
701 // }
702 // }
703 // }
704 // }
705
706 // Delete all image nodes unless they have already gone
707 for (unsigned i=0; i<mBottomImages.size(); i++)
708 {
709 mNodes[mBottomImages[i]]->MarkAsDeleted();
711 }
712
713 for (unsigned i=0; i<mTopImages.size(); i++)
714 {
715 mNodes[mTopImages[i]]->MarkAsDeleted();
716 mDeletedNodeIndices.push_back(mTopImages[i]);
717 }
718}
719
720c_vector<double, 2> Toroidal2dMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
721{
722 assert(mWidth > 0.0);
723 assert(mHeight > 0.0);
724
725 c_vector<double, 2> vector = rLocation2 - rLocation1;
726 vector[0] = fmod(vector[0], mWidth);
727 vector[1] = fmod(vector[1], mHeight);
728
729 /*
730 * Handle the Toroidal condition here: if the points are more
731 * than halfway around the domain apart, measure the other way.
732 */
733 if (vector[0] > 0.5*mWidth)
734 {
735 vector[0] -= mWidth;
736 }
737 else if (vector[0] < -0.5*mWidth)
738 {
739 vector[0] += mWidth;
740 }
741 if (vector[1] > 0.5*mHeight)
742 {
743 vector[1] -= mHeight;
744 }
745 else if (vector[1] < -0.5*mHeight)
746 {
747 vector[1] += mHeight;
748 }
749 return vector;
750}
751
752void Toroidal2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove)
753{
754
755 // Perform a width periodic movement if necessary
756 if (point.rGetLocation()[0] >= mWidth)
757 {
758 // Move point to the left
759 point.SetCoordinate(0, point.rGetLocation()[0] - mWidth);
760 }
761 else if (point.rGetLocation()[0] < 0.0)
762 {
763 // Move point to the right
764 point.SetCoordinate(0, point.rGetLocation()[0] + mWidth);
765 }
766
767 // Perform a depth periodic movement if necessary
768 if (point.rGetLocation()[1] >= mHeight)
769 {
770 // Move point down
771 point.SetCoordinate(1, point.rGetLocation()[1] - mHeight);
772 }
773 else if (point.rGetLocation()[1] < 0.0)
774 {
775 // Move point up
776 point.SetCoordinate(1, point.rGetLocation()[1] + mHeight);
777 }
778
779 // Update the node's location
780 MutableMesh<2,2>::SetNode(index, point, concreteMove);
781}
782
783double Toroidal2dMesh::GetWidth(const unsigned& rDimension) const
784{
785 double width = 0.0;
786 assert(rDimension==0 || rDimension==1);
787 if (rDimension==0)
788 {
789 width = mWidth;
790 }
791 else
792 {
793 width = mHeight;
794 }
795 return width;
796}
797
799{
800 unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode);
801
802 // If necessary move it to be back on the cylinder
803 ChastePoint<2> new_node_point = pNewNode->GetPoint();
804 SetNode(node_index, new_node_point, false);
805
806 return node_index;
807}
808
810{
812
813 /*
814 * Copy the member variables into new vectors, which we modify
815 * by knocking out elements which pair up on each side.
816 */
817 std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices;
818 std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices;
819
820// if ((mLeftPeriodicBoundaryElementIndices.size()!=mRightPeriodicBoundaryElementIndices.size())
821// || (temp_left_hand_side_elements.size() <= 2)
822// || (temp_right_hand_side_elements.size() <= 2) )
823// {
824// mMismatchedBoundaryElements = true;
825// }
827
828 // Go through all of the elements on the left periodic boundary
829 for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin();
830 left_iter != mLeftPeriodicBoundaryElementIndices.end();
831 ++left_iter)
832 {
833 unsigned elem_index = *left_iter;
834
835 Element<2,2>* p_element = GetElement(elem_index);
836
837 /*
838 * Make lists of the nodes which the elements on the left contain and
839 * the nodes which should be in a corresponding element on the right.
840 */
841 c_vector<unsigned,3> original_element_node_indices;
842 c_vector<unsigned,3> corresponding_element_node_indices;
843 for (unsigned i=0; i<3; i++)
844 {
845 original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
846 corresponding_element_node_indices[i] = GetCorrespondingCylindricalNodeIndex(original_element_node_indices[i]);
847 }
848
849 // Search the right hand side elements for the corresponding element
850 for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin();
851 right_iter != mRightPeriodicBoundaryElementIndices.end();
852 ++right_iter)
853 {
854 unsigned corresponding_elem_index = *right_iter;
855
856 Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
857
858 bool is_corresponding_node = true;
859
860 for (unsigned i=0; i<3; i++)
861 {
862 if ((corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
863 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
864 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
865 {
866 is_corresponding_node = false;
867 break;
868 }
869 }
870
871 if (is_corresponding_node)
872 {
873 // If this trips then you need to deal with remeshing where the left and right are different
874 // See #3043 and Cylindrical2dMesh
876 // Remove original and corresponding element from sets
877 // temp_left_hand_side_elements.erase(elem_index);
878 // temp_right_hand_side_elements.erase(corresponding_elem_index);
879 }
880 }
881 }
882
883 /*
884 * If either of these ever throw you have more than one situation where the mesher has an option
885 * of how to mesh. If it does ever throw you need to be cleverer and match up the
886 * elements into as many pairs as possible on the left hand and right hand sides.
887 */
888 //assert(temp_left_hand_side_elements.size() <= 2);
889 //assert(temp_right_hand_side_elements.size() <= 2);
890
891 /*
892 * Now we just have to use the first pair of elements and copy their info over to the other side.
893 * First we need to get hold of both elements on either side.
894 */
895 if (temp_left_hand_side_elements.empty() || temp_right_hand_side_elements.empty())
896 {
898 //assert(temp_right_hand_side_elements.empty());
899 //assert(temp_left_hand_side_elements.empty());
900 }
901 else
902 {
903 if (temp_right_hand_side_elements.size() == 2 && temp_left_hand_side_elements.size() == 2)
904 {
905 /*
906 * If you get here there are mixed up elements on the periodic edge.
907 * We need to knock the pair out and then rerun this function. This shouldn't be
908 * too hard to do but is as yet unnecessary.
909 */
911 }
912 }
913}
914
916{
918
919 /*
920 * Copy the member variables into new vectors, which we modify
921 * by knocking out elements which pair up on each side.
922 */
923 std::set<unsigned> temp_bottom_hand_side_elements = mBottomPeriodicBoundaryElementIndices;
924 std::set<unsigned> temp_top_hand_side_elements = mTopPeriodicBoundaryElementIndices;
925
926// if ((mBottomPeriodicBoundaryElementIndices.size()!=mTopPeriodicBoundaryElementIndices.size())
927// || (temp_bottom_hand_side_elements.size() <= 2)
928// || (temp_top_hand_side_elements.size() <= 2) )
929// {
930// mMismatchedBoundaryElements = true;
931// }
933
934 // Go through all of the elements on the bottom periodic boundary
935 for (std::set<unsigned>::iterator bottom_iter = mBottomPeriodicBoundaryElementIndices.begin();
936 bottom_iter != mBottomPeriodicBoundaryElementIndices.end();
937 ++bottom_iter)
938 {
939 unsigned elem_index = *bottom_iter;
940
941 Element<2,2>* p_element = GetElement(elem_index);
942
943 /*
944 * Make lists of the nodes which the elements on the bottom contain and
945 * the nodes which should be in a corresponding element on the top.
946 */
947 c_vector<unsigned,3> original_element_node_indices;
948 c_vector<unsigned,3> corresponding_element_node_indices;
949 for (unsigned i=0; i<3; i++)
950 {
951 original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
952 corresponding_element_node_indices[i] = GetCorrespondingToroidalNodeIndex(original_element_node_indices[i]);
953 }
954
955 // Search the top hand side elements for the corresponding element
956 for (std::set<unsigned>::iterator top_iter = mTopPeriodicBoundaryElementIndices.begin();
957 top_iter != mTopPeriodicBoundaryElementIndices.end();
958 ++top_iter)
959 {
960 unsigned corresponding_elem_index = *top_iter;
961
962 Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
963
964 bool is_corresponding_node = true;
965
966 for (unsigned i=0; i<3; i++)
967 {
968 if ((corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
969 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
970 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
971 {
972 is_corresponding_node = false;
973 break;
974 }
975 }
976
977 if (is_corresponding_node)
978 {
979 // If this trips then you need to deal with remeshing where the left and right are different
980 // See #3043 and Cylindrical2dMesh
982
983 // Remove original and corresponding element from sets
984 //temp_bottom_hand_side_elements.erase(elem_index);
985 temp_top_hand_side_elements.erase(corresponding_elem_index);
986 }
987 }
988 }
989
990 /*
991 * If either of these ever throw you have more than one situation where the mesher has an option
992 * of how to mesh. If it does ever throw you need to be cleverer and match up the
993 * elements into as many pairs as possible on the left hand and right hand sides.
994 */
995 //assert(temp_bottom_hand_side_elements.size() <= 2);
996 //assert(temp_top_hand_side_elements.size() <= 2);
997
998 /*
999 * Now we just have to use the first pair of elements and copy their info over to the other side.
1000 * First we need to get hold of both elements on either side.
1001 */
1002 if (temp_bottom_hand_side_elements.empty() || temp_top_hand_side_elements.empty())
1003 {
1005 //assert(temp_top_hand_side_elements.empty());
1006 //assert(temp_bottom_hand_side_elements.empty());
1007 }
1008 else
1009 {
1010 if (temp_top_hand_side_elements.size() == 2 && temp_bottom_hand_side_elements.size() == 2)
1011 {
1012 /*
1013 * If you get here there are mixed up elements on the periodic edge.
1014 * We need to knock the pair out and then rerun this function. This shouldn't be
1015 * too hard to do but is as yet unnecessary.
1016 */
1018 }
1019 }
1020}
1021
1023{
1026
1028 elem_iter != GetElementIteratorEnd();
1029 ++elem_iter)
1030 {
1031 // Left images are on the right of the mesh
1032 unsigned number_of_left_image_nodes = 0;
1033 unsigned number_of_right_image_nodes = 0;
1034
1035 for (unsigned i=0; i<3; i++)
1036 {
1037 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
1038
1039 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
1040 {
1041 number_of_left_image_nodes++;
1042 }
1043 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
1044 {
1045 number_of_right_image_nodes++;
1046 }
1047 }
1048
1049 /* SJ - Have checked the following:
1050 * - It is never the case that number_of_left_image_nodes + number_of_right_image_nodes > 3
1051 * - There are 1264 incidences of zero left image nodes, and 1252 incidences of zero right image nodes
1052 * - 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
1053 * image nodes
1054 * - 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
1055 * 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
1056 * image node with 1/2 right image nodes that is responsible for the extra element.
1057 */
1058
1059 // Elements on the left hand side (images of right nodes)
1060 if (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2)
1061 {
1062 mLeftPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1063 }
1064
1065 // Elements on the right (images of left nodes)
1066 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
1067 {
1068 mRightPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1069 }
1070 }
1071
1072// if (mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
1073// {
1074// mMismatchedBoundaryElements = true;
1075// // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
1076//
1077// }
1078
1079 // Every boundary element on the left must have a corresponding element on the right
1081 // if(mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
1082 // {
1083 // TRACE("Left");
1084 // PRINT_VARIABLE(mLeftPeriodicBoundaryElementIndices.size());
1085 // for (std::set<unsigned>::iterator iter = mLeftPeriodicBoundaryElementIndices.begin();
1086 // iter != mLeftPeriodicBoundaryElementIndices.end();
1087 // iter++)
1088 // {
1089 // PRINT_VARIABLE(*iter);
1090 // }
1091 // TRACE("Right");
1092 // PRINT_VARIABLE(mRightPeriodicBoundaryElementIndices.size());
1093 // for (std::set<unsigned>::iterator iter = mRightPeriodicBoundaryElementIndices.begin();
1094 // iter != mRightPeriodicBoundaryElementIndices.end();
1095 // iter++)
1096 // {
1097 // PRINT_VARIABLE(*iter);
1098 // }
1099
1100 // }
1101}
1102
1104{
1107
1109 elem_iter != GetElementIteratorEnd();
1110 ++elem_iter)
1111 {
1112 // Left images are on the right of the mesh
1113 unsigned number_of_bottom_image_nodes = 0;
1114 unsigned number_of_top_image_nodes = 0;
1115
1116 for (unsigned i=0; i<3; i++)
1117 {
1118 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
1119
1120 if (mImageToBottomOriginalNodeMap.find(this_node_index) != mImageToBottomOriginalNodeMap.end())
1121 {
1122 number_of_bottom_image_nodes++;
1123 }
1124 else if (mImageToTopOriginalNodeMap.find(this_node_index) != mImageToTopOriginalNodeMap.end())
1125 {
1126 number_of_top_image_nodes++;
1127 }
1128 }
1129
1130 // Elements on the bottom hand side (images of top nodes)
1131 if (number_of_top_image_nodes == 1 || number_of_top_image_nodes == 2)
1132 {
1133 mBottomPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1134 }
1135
1136 // Elements on the right (images of bottom nodes)
1137 if (number_of_bottom_image_nodes == 1 || number_of_bottom_image_nodes == 2)
1138 {
1139 mTopPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
1140 }
1141 }
1142
1143// if (mBottomPeriodicBoundaryElementIndices.size() != mTopPeriodicBoundaryElementIndices.size())
1144// {
1145// mMismatchedBoundaryElements = true;
1146// // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
1147//
1148// }
1149
1150 // Every boundary element on the bottom must have a corresponding element on the top
1152}
1153
1155{
1156 unsigned corresponding_node_index = UINT_MAX;
1157
1158 // If nodeIndex is a member of mRightOriginals, then find the corresponding node index in mRightImages
1159 std::vector<unsigned>::iterator right_orig_iter = std::find(mRightOriginals.begin(), mRightOriginals.end(), nodeIndex);
1160 if (right_orig_iter != mRightOriginals.end())
1161 {
1162 corresponding_node_index = mRightImages[right_orig_iter - mRightOriginals.begin()];
1163 }
1164 else
1165 {
1166 // If nodeIndex is a member of mRightImages, then find the corresponding node index in mRightOriginals
1167 std::vector<unsigned>::iterator right_im_iter = std::find(mRightImages.begin(), mRightImages.end(), nodeIndex);
1168 if (right_im_iter != mRightImages.end())
1169 {
1170 corresponding_node_index = mRightOriginals[right_im_iter - mRightImages.begin()];
1171 }
1172 else
1173 {
1174 // This isn't needed as now we copy all nodes to the left and right.
1175 // If you reach here then you have probably
1176 // Changed it back to half the nodes or similar
1178
1179 // // If nodeIndex is a member of mLeftOriginals, then find the corresponding node index in mLeftImages
1180 // std::vector<unsigned>::iterator left_orig_iter = std::find(mLeftOriginals.begin(), mLeftOriginals.end(), nodeIndex);
1181 // if (left_orig_iter != mLeftOriginals.end())
1182 // {
1183 // corresponding_node_index = mLeftImages[left_orig_iter - mLeftOriginals.begin()];
1184 // }
1185 // else
1186 // {
1187 // // If nodeIndex is a member of mLeftImages, then find the corresponding node index in mLeftOriginals
1188 // std::vector<unsigned>::iterator left_im_iter = std::find(mLeftImages.begin(), mLeftImages.end(), nodeIndex);
1189 // if (left_im_iter != mLeftImages.end())
1190 // {
1191 // corresponding_node_index = mLeftOriginals[left_im_iter - mLeftImages.begin()];
1192 // }
1193 // }
1194 }
1195 }
1196
1197 // We must have found the corresponding node index
1198 assert(corresponding_node_index != UINT_MAX);
1199 return corresponding_node_index;
1200}
1201
1202
1204{
1205 unsigned corresponding_node_index = UINT_MAX;
1206
1207 // If nodeIndex is a member of mTopOriginals, then find the corresponding node index in mTopImages
1208 std::vector<unsigned>::iterator top_orig_iter = std::find(mTopOriginals.begin(), mTopOriginals.end(), nodeIndex);
1209 if (top_orig_iter != mTopOriginals.end())
1210 {
1211 corresponding_node_index = mTopImages[top_orig_iter - mTopOriginals.begin()];
1212 }
1213 else
1214 {
1215 // If nodeIndex is a member of mTopImages, then find the corresponding node index in mTopOriginals
1216 std::vector<unsigned>::iterator top_im_iter = std::find(mTopImages.begin(), mTopImages.end(), nodeIndex);
1217 if (top_im_iter != mTopImages.end())
1218 {
1219 corresponding_node_index = mTopOriginals[top_im_iter - mTopImages.begin()];
1220 }
1221 else
1222 {
1223 // This isn't needed as now we copy all nodes to the top and bottom.
1224 // If you reach here then you have probably
1225 // Changed it back to half the nodes or similar
1227
1228 // // If nodeIndex is a member of mBottomOriginals, then find the corresponding node index in mBottomImages
1229 // std::vector<unsigned>::iterator bottom_orig_iter = std::find(mBottomOriginals.begin(), mBottomOriginals.end(), nodeIndex);
1230 // if (bottom_orig_iter != mBottomOriginals.end())
1231 // {
1232 // corresponding_node_index = mBottomImages[bottom_orig_iter - mBottomOriginals.begin()];
1233 // }
1234 // else
1235 // {
1236 // // If nodeIndex is a member of mBottomImages, then find the corresponding node index in mBottomOriginals
1237 // std::vector<unsigned>::iterator bottom_im_iter = std::find(mBottomImages.begin(), mBottomImages.end(), nodeIndex);
1238 // if (bottom_im_iter != mBottomImages.end())
1239 // {
1240 // corresponding_node_index = mBottomOriginals[bottom_im_iter - mBottomImages.begin()];
1241 // }
1242 // }
1243 }
1244 }
1245
1246 // We must have found the corresponding node index
1247 assert(corresponding_node_index != UINT_MAX);
1248 return corresponding_node_index;
1249}
1250
1251
1253{
1254 // Check if the (x,y) coordinates are in the domain, if not, get the fmod and relocate.
1255 unsigned num_nodes = mNodes.size();
1256 for (unsigned i=0; i<num_nodes; i++)
1257 {
1258 double& x_location = (mNodes[i]->rGetModifiableLocation())[0];
1259 if (x_location < 0.0)
1260 {
1261 x_location = fmod(x_location, mWidth) + mWidth;
1262 }
1263 else if (x_location >= mWidth)
1264 {
1265 x_location = fmod(x_location, mWidth);
1266 }
1267 double& y_location = (mNodes[i]->rGetModifiableLocation())[1];
1268 if (y_location < 0.0)
1269 {
1270 y_location = fmod(y_location, mHeight) + mHeight;
1271 }
1272 else if (y_location >= mHeight)
1273 {
1274 y_location = fmod(y_location, mHeight);
1275 }
1276 }
1277
1278 // Now run the base class method
1279 //TetrahedralMesh<2,2>::RefreshMesh();
1280}
1281
1282// 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()