Chaste Commit::baa90ac2819b962188b7562f2326be23c47859a7
Cylindrical2dMesh.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("Cylindrical2dMeshDebug", "mesh", false);
41mesh_writer.WriteFilesUsingMesh(*this);
42*/
43#include "Cylindrical2dMesh.hpp"
44#include "Exception.hpp"
45#include "VtkMeshWriter.hpp"
46
48 : MutableMesh<2,2>(),
49 mWidth(width),
50 mHaloScalingFactor(2.0), // Default value
51 mHaloOffset(1.0) // Default value
52{
53 assert(width > 0.0);
54}
55
59
60Cylindrical2dMesh::Cylindrical2dMesh(double width, std::vector<Node<2>* > nodes)
61 : MutableMesh<2,2>(),
62 mWidth(width),
63 mHaloScalingFactor(2.0), // Default value
64 mHaloOffset(1.0) // Default value
65{
66 assert(width > 0.0);
67// mMismatchedBoundaryElements = false;
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 mNodes.push_back(p_temp_node);
75 }
76 NodeMap node_map(nodes.size());
77 ReMesh(node_map);
78}
79
80//bool Cylindrical2dMesh::GetInstanceOfMismatchedBoundaryNodes()
81//{
82// return mMismatchedBoundaryElements;
83//}
84
86{
88 mBottom = bounding_box.rGetLowerCorner()[1];
89 mTop = bounding_box.rGetUpperCorner()[1];
90}
91
93{
94 double half_way = 0.5*mWidth;
95
96 mLeftOriginals.clear();
97 mLeftImages.clear();
99 mRightOriginals.clear();
100 mRightImages.clear();
104
106 node_iter != GetNodeIteratorEnd();
107 ++node_iter)
108 {
109 c_vector<double, 2> location;
110 location = node_iter->rGetLocation();
111 unsigned this_node_index = node_iter->GetIndex();
112 double this_node_x_location = location[0];
113
114 // Check the mesh currently conforms to the dimensions given
115 assert(0.0 <= location[0]);
116 assert(location[0] <= mWidth);
117
118 // Put the nodes which are to be mirrored in the relevant vectors
119 if (this_node_x_location < half_way)
120 {
121 mLeftOriginals.push_back(this_node_index);
122 }
123 else
124 {
125 mRightOriginals.push_back(this_node_index);
126 }
127 }
128
129 // For each left original node, create an image node and record its new index
130 for (unsigned i=0; i<mLeftOriginals.size(); i++)
131 {
132 c_vector<double, 2> location {};
133 location = mNodes[mLeftOriginals[i]]->rGetLocation();
134 location[0] = location[0] + mWidth;
135
136 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
137 mLeftImages.push_back(new_node_index);
138 mImageToLeftOriginalNodeMap[new_node_index] = mLeftOriginals[i];
139 }
140
141 // For each right original node, create an image node and record its new index
142 for (unsigned i=0; i<mRightOriginals.size(); i++)
143 {
144 c_vector<double, 2> location {};
145 location = mNodes[mRightOriginals[i]]->rGetLocation();
146 location[0] = location[0] - mWidth;
147
148 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
149 mRightImages.push_back(new_node_index);
151 }
152
153 assert(mRightOriginals.size() == mRightImages.size());
154 assert(mLeftOriginals.size() == mLeftImages.size());
155 assert(mImageToLeftOriginalNodeMap.size() == mLeftOriginals.size());
156 assert(mImageToRightOriginalNodeMap.size() == mRightOriginals.size());
157}
158
160{
162
163 mTopHaloNodes.clear();
164 mBottomHaloNodes.clear();
165
166 unsigned num_halo_nodes = static_cast<unsigned>(floor(mWidth * mHaloScalingFactor));
167 double halo_node_separation = mWidth / (static_cast<double>(num_halo_nodes));
168 double y_top_coordinate = mTop + mHaloOffset * halo_node_separation;
169 double y_bottom_coordinate = mBottom - mHaloOffset * halo_node_separation;
170
171 c_vector<double, 2> location;
172 for (unsigned i=0; i<num_halo_nodes; i++)
173 {
174 double x_coordinate = 0.5 * halo_node_separation + static_cast<double>(i) * halo_node_separation;
175
176 // Inserting top halo node in mesh
177 location[0] = x_coordinate;
178 location[1] = y_top_coordinate;
179 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
180 mTopHaloNodes.push_back(new_node_index);
181
182 location[1] = y_bottom_coordinate;
183 new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
184 mBottomHaloNodes.push_back(new_node_index);
185 }
186}
187
189{
190 unsigned old_num_all_nodes = GetNumAllNodes();
191
192 rMap.Resize(old_num_all_nodes);
193 rMap.ResetToIdentity();
194
195 // Flag the deleted nodes as deleted in the map
196 for (unsigned i=0; i<old_num_all_nodes; i++)
197 {
198 if (mNodes[i]->IsDeleted())
199 {
200 rMap.SetDeleted(i);
201 }
202 }
203
205
206 // Create mirrored nodes for the normal remesher to work with
208
209 /*
210 * The mesh now has messed up boundary elements, but this
211 * doesn't matter as the ReMesh() below doesn't read them in
212 * and reconstructs the boundary elements.
213 *
214 * Call ReMesh() on the parent class. Note that the mesh now has lots
215 * of extra nodes which will be deleted, hence the name 'big_map'.
216 */
217 NodeMap big_map(GetNumAllNodes());
219
220 /*
221 * If the big_map isn't the identity map, the little map ('map') needs to be
222 * altered accordingly before being passed to the user. Not sure how this all
223 * works, so deal with this bridge when we get to it.
224 */
225 assert(big_map.IsIdentityMap());
226
227 // Re-index the vectors according to the big nodemap, and set up the maps.
230
231 assert(mLeftOriginals.size() == mLeftImages.size());
232 assert(mRightOriginals.size() == mRightImages.size());
233
234 for (unsigned i=0; i<mLeftOriginals.size(); i++)
235 {
237 mLeftImages[i] = big_map.GetNewIndex(mLeftImages[i]);
239 }
240
241 for (unsigned i=0; i<mRightOriginals.size(); i++)
242 {
244 mRightImages[i] = big_map.GetNewIndex(mRightImages[i]);
246 }
247
248 for (unsigned i=0; i<mTopHaloNodes.size(); i++)
249 {
250 mTopHaloNodes[i] = big_map.GetNewIndex(mTopHaloNodes[i]);
252 }
253
254 /*
255 * Check that elements crossing the periodic boundary have been meshed
256 * in the same way at each side.
257 */
259
260 /*
261 * Take the double-sized mesh, with its new boundary elements, and
262 * remove the relevant nodes, elements and boundary elements to leave
263 * a proper periodic mesh.
264 */
266
268
269 /*
270 * Create a random boundary element between two nodes of the first
271 * element if it is not deleted. This is a temporary measure to get
272 * around re-index crashing when there are no boundary elements.
273 */
274 unsigned num_elements = GetNumAllElements();
275 bool boundary_element_made = false;
276 unsigned elem_index = 0;
277
278 while (elem_index<num_elements && !boundary_element_made)
279 {
280 Element<2,2>* p_element = GetElement(elem_index);
281 if (!p_element->IsDeleted())
282 {
283 boundary_element_made = true;
284 std::vector<Node<2>*> nodes;
285 nodes.push_back(p_element->GetNode(0));
286 nodes.push_back(p_element->GetNode(1));
287 BoundaryElement<1,2>* p_boundary_element = new BoundaryElement<1,2>(0, nodes);
288 p_boundary_element->RegisterWithNodes();
289 mBoundaryElements.push_back(p_boundary_element);
290 this->mBoundaryElementWeightedDirections.push_back(zero_vector<double>(2));
291 this->mBoundaryElementJacobianDeterminants.push_back(0.0);
292 }
293 elem_index++;
294 }
295
296 // Now call ReIndex() to remove the temporary nodes which are marked as deleted
297 NodeMap reindex_map(GetNumAllNodes());
298 ReIndex(reindex_map);
299 assert(!reindex_map.IsIdentityMap()); // maybe don't need this
300
301 /*
302 * Go through the reindex map and use it to populate the original NodeMap
303 * (the one that is returned to the user).
304 */
305 for (unsigned i=0; i<rMap.GetSize(); i++) // only going up to be size of map, not size of reindex_map
306 {
307 if (reindex_map.IsDeleted(i))
308 {
309 /*
310 * i < num_original_nodes and node is deleted, this should correspond to
311 * a node that was labelled as before the remeshing, so should have already
312 * been set as deleted in the map above.
313 */
314 assert(rMap.IsDeleted(i));
315 }
316 else
317 {
318 rMap.SetNewIndex(i, reindex_map.GetNewIndex(i));
319 }
320 }
321
322 // We can now clear the index vectors and maps; they are only used for remeshing
323 mLeftOriginals.clear();
324 mLeftImages.clear();
326 mRightOriginals.clear();
327 mRightImages.clear();
331}
332
334{
335 /*
336 * Figure out which elements have real nodes and image nodes in them
337 * and replace image nodes with corresponding real ones.
338 */
340 elem_iter != GetElementIteratorEnd();
341 ++elem_iter)
342 {
343 // Left images are on the right of the mesh
344 unsigned number_of_left_image_nodes = 0;
345 unsigned number_of_right_image_nodes = 0;
346
347 for (unsigned i=0; i<3; i++)
348 {
349 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
350
351 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
352 {
353 number_of_left_image_nodes++;
354 }
355 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
356 {
357 number_of_right_image_nodes++;
358 }
359 }
360
361 // Delete all the elements on the left hand side (images of right)...
362 if (number_of_right_image_nodes >= 1)
363 {
364 elem_iter->MarkAsDeleted();
365 mDeletedElementIndices.push_back(elem_iter->GetIndex());
366 }
367
368 // Delete only purely imaginary elements on the right (images of left nodes)
369 if (number_of_left_image_nodes == 3)
370 {
371 elem_iter->MarkAsDeleted();
372 mDeletedElementIndices.push_back(elem_iter->GetIndex());
373 }
374
375 /*
376 * If some are images then replace them with the real nodes. There
377 * can be elements with either two image nodes on the right (and one
378 * real) or one image node on the right (and two real).
379 */
380 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
381 {
382 for (unsigned i=0; i<3; i++)
383 {
384 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
385 std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
386 if (it != mImageToLeftOriginalNodeMap.end())
387 {
388 elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
389 }
390 }
391 }
392 }
393
394 /*
395 * Figure out which boundary elements have real nodes and image nodes in them
396 * and replace image nodes with corresponding real ones.
397 */
398 for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
399 {
400 BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
401 if (!p_boundary_element->IsDeleted())
402 {
403 unsigned number_of_image_nodes = 0;
404 for (unsigned i=0; i<2; i++)
405 {
406 unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
407
408 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
409 {
410 number_of_image_nodes++;
411 }
412 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
413 {
414 number_of_image_nodes++;
415 }
416 }
417
418 if (number_of_image_nodes == 2)
419 {
420 p_boundary_element->MarkAsDeleted();
421 mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
422 }
423
424 /*
425 * To avoid having two copies of the boundary elements on the periodic
426 * boundaries we only deal with the elements on the left image and
427 * delete the ones on the right image.
428 */
429 if (number_of_image_nodes == 1)
430 {
431 for (unsigned i=0; i<2; i++)
432 {
433 unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
434 std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
435 if (it != mImageToLeftOriginalNodeMap.end())
436 {
437 p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
438 }
439 else
440 {
441 it = mImageToRightOriginalNodeMap.find(this_node_index);
442 if (it != mImageToRightOriginalNodeMap.end())
443 {
444 p_boundary_element->MarkAsDeleted();
445 mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
446 }
447 }
448 }
449 }
450 }
451 }
452
453 // Delete all image nodes unless they have already gone (halo nodes)
454 for (unsigned i=0; i<mLeftImages.size(); i++)
455 {
456 mNodes[mLeftImages[i]]->MarkAsDeleted();
457 mDeletedNodeIndices.push_back(mLeftImages[i]);
458 }
459
460 for (unsigned i=0; i<mRightImages.size(); i++)
461 {
462 mNodes[mRightImages[i]]->MarkAsDeleted();
463 mDeletedNodeIndices.push_back(mRightImages[i]);
464 }
465}
466
468{
469 assert(mTopHaloNodes.size() == mBottomHaloNodes.size());
470 for (unsigned i=0; i<mTopHaloNodes.size(); i++)
471 {
474 }
475}
476
477c_vector<double, 2> Cylindrical2dMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
478{
479 assert(mWidth > 0.0);
480
481 c_vector<double, 2> vector = rLocation2 - rLocation1;
482 vector[0] = fmod(vector[0], mWidth);
483
484 /*
485 * Handle the cylindrical condition here: if the points are more
486 * than halfway around the cylinder apart, measure the other way.
487 */
488 if (vector[0] > 0.5*mWidth)
489 {
490 vector[0] -= mWidth;
491 }
492 else if (vector[0] < -0.5*mWidth)
493 {
494 vector[0] += mWidth;
495 }
496 return vector;
497}
498
499void Cylindrical2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove)
500{
501 // Perform a periodic movement if necessary
502 if (point.rGetLocation()[0] >= mWidth)
503 {
504 // Move point to the left
505 point.SetCoordinate(0, point.rGetLocation()[0] - mWidth);
506 }
507 else if (point.rGetLocation()[0] < 0.0)
508 {
509 // Move point to the right
510 point.SetCoordinate(0, point.rGetLocation()[0] + mWidth);
511 }
512
513 // Update the node's location
514 MutableMesh<2,2>::SetNode(index, point, concreteMove);
515}
516
517double Cylindrical2dMesh::GetWidth(const unsigned& rDimension) const
518{
519 double width = 0.0;
520 assert(rDimension==0 || rDimension==1);
521 if (rDimension==0)
522 {
523 width = mWidth;
524 }
525 else
526 {
527 width = MutableMesh<2,2>::GetWidth(rDimension);
528 }
529 return width;
530}
531
533{
534 unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode);
535
536 // If necessary move it to be back on the cylinder
537 ChastePoint<2> new_node_point = pNewNode->GetPoint();
538 SetNode(node_index, new_node_point, false);
539
540 return node_index;
541}
542
544{
546
547 /*
548 * Copy the member variables into new vectors, which we modify
549 * by knocking out elements which pair up on each side.
550 */
551 std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices;
552 std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices;
553
554// if ((mLeftPeriodicBoundaryElementIndices.size()!=mRightPeriodicBoundaryElementIndices.size())
555// || (temp_left_hand_side_elements.size() <= 2)
556// || (temp_right_hand_side_elements.size() <= 2) )
557// {
558// mMismatchedBoundaryElements = true;
559// }
561
562 // Go through all of the elements on the left periodic boundary
563 for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin();
564 left_iter != mLeftPeriodicBoundaryElementIndices.end();
565 ++left_iter)
566 {
567 unsigned elem_index = *left_iter;
568
569 Element<2,2>* p_element = GetElement(elem_index);
570
571 /*
572 * Make lists of the nodes which the elements on the left contain and
573 * the nodes which should be in a corresponding element on the right.
574 */
575 c_vector<unsigned,3> original_element_node_indices;
576 c_vector<unsigned,3> corresponding_element_node_indices;
577 for (unsigned i=0; i<3; i++)
578 {
579 original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
580 corresponding_element_node_indices[i] = GetCorrespondingNodeIndex(original_element_node_indices[i]);
581 }
582
583 // Search the right hand side elements for the corresponding element
584 for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin();
585 right_iter != mRightPeriodicBoundaryElementIndices.end();
586 ++right_iter)
587 {
588 unsigned corresponding_elem_index = *right_iter;
589
590 Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
591
592 bool is_corresponding_node = true;
593
594 for (unsigned i=0; i<3; i++)
595 {
596 if ((corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
597 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
598 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
599 {
600 is_corresponding_node = false;
601 break;
602 }
603 }
604
605 if (is_corresponding_node)
606 {
607 // Remove original and corresponding element from sets
608 temp_left_hand_side_elements.erase(elem_index);
609 temp_right_hand_side_elements.erase(corresponding_elem_index);
610 }
611 }
612 }
613
614 /*
615 * If either of these ever throw you have more than one situation where the mesher has an option
616 * of how to mesh. If it does ever throw you need to be cleverer and match up the
617 * elements into as many pairs as possible on the left hand and right hand sides.
618 */
619 // assert(temp_left_hand_side_elements.size() <= 2);
620 // assert(temp_right_hand_side_elements.size() <= 2);
621
622 /*
623 * Now we just have to use the first pair of elements and copy their info over to the other side.
624 * First we need to get hold of both elements on either side.
625 */
626 if (temp_left_hand_side_elements.empty() || temp_right_hand_side_elements.empty())
627 {
628 assert(temp_right_hand_side_elements.empty());
629 assert(temp_left_hand_side_elements.empty());
630 }
631 else
632 {
633 if (temp_right_hand_side_elements.size() == 2 && temp_left_hand_side_elements.size() == 2)
634 {
635 if (temp_right_hand_side_elements.size() == 2)
636 {
637 // Use the right hand side meshing and map to left
638 UseTheseElementsToDecideMeshing(temp_right_hand_side_elements);
639 }
640 else
641 {
642 /*
643 * If you get here there are more than two mixed up elements on the periodic edge.
644 * We need to knock the pair out and then rerun this function. This shouldn't be
645 * too hard to do but is as yet unnecessary.
646 */
648 }
649 }
650 }
651}
652
653void Cylindrical2dMesh::UseTheseElementsToDecideMeshing(std::set<unsigned>& rMainSideElements)
654{
655 assert(rMainSideElements.size() == 2);
656
657 // We find the four nodes surrounding the dodgy meshing, on each side.
658 std::set<unsigned> main_four_nodes;
659 for (std::set<unsigned>::iterator left_iter = rMainSideElements.begin();
660 left_iter != rMainSideElements.end();
661 ++left_iter)
662 {
663 unsigned elem_index = *left_iter;
664 Element<2,2>* p_element = GetElement(elem_index);
665 for (unsigned i=0; i<3; i++)
666 {
667 unsigned index = p_element->GetNodeGlobalIndex(i);
668 main_four_nodes.insert(index);
669 }
670 }
671 assert(main_four_nodes.size() == 4);
672
673 std::set<unsigned> other_four_nodes;
674 for (std::set<unsigned>::iterator iter = main_four_nodes.begin();
675 iter != main_four_nodes.end();
676 ++iter)
677 {
678 other_four_nodes.insert(GetCorrespondingNodeIndex(*iter));
679 }
680 assert(other_four_nodes.size() == 4);
681
682 /*
683 * Find the elements surrounded by the nodes on the right
684 * and change them to match the elements on the left.
685 */
686 std::vector<unsigned> corresponding_elements;
687
688 // Loop over all elements
690 elem_iter != GetElementIteratorEnd();
691 ++elem_iter)
692 {
693 // Loop over the nodes of the element
694 if (!(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(0))==other_four_nodes.end()) &&
695 !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(1))==other_four_nodes.end()) &&
696 !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(2))==other_four_nodes.end()) )
697 {
698 corresponding_elements.push_back(elem_iter->GetIndex());
699 elem_iter->MarkAsDeleted();
700 mDeletedElementIndices.push_back(elem_iter->GetIndex());
701 }
702 }
703 assert(corresponding_elements.size() == 2);
704
705 // Now corresponding_elements contains the two elements which are going to be replaced by rMainSideElements
706 unsigned num_elements = GetNumAllElements();
707 for (std::set<unsigned>::iterator iter = rMainSideElements.begin();
708 iter != rMainSideElements.end();
709 ++iter)
710 {
711 Element<2,2>* p_main_element = GetElement(*iter);
712 std::vector<Node<2>*> nodes;
713
714 // Put corresponding nodes into a std::vector
715 for (unsigned i=0; i<3; i++)
716 {
717 unsigned main_node = p_main_element->GetNodeGlobalIndex(i);
718 nodes.push_back(this->GetNode(GetCorrespondingNodeIndex(main_node)));
719 }
720
721 // Make a new element
722 Element<2,2>* p_new_element = new Element<2,2>(num_elements, nodes);
723 this->mElements.push_back(p_new_element);
724 this->mElementJacobians.push_back(zero_matrix<double>(2,2));
725 this->mElementInverseJacobians.push_back(zero_matrix<double>(2,2));
726 this->mElementJacobianDeterminants.push_back(0.0);
727 num_elements++;
728 }
729
730 // Reindex to get rid of extra elements indices
731 NodeMap map(GetNumAllNodes());
732 this->ReIndex(map);
733}
734
736{
739
741 elem_iter != GetElementIteratorEnd();
742 ++elem_iter)
743 {
744 // Left images are on the right of the mesh
745 unsigned number_of_left_image_nodes = 0;
746 unsigned number_of_right_image_nodes = 0;
747
748 for (unsigned i=0; i<3; i++)
749 {
750 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
751
752 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
753 {
754 number_of_left_image_nodes++;
755 }
756 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
757 {
758 number_of_right_image_nodes++;
759 }
760 }
761
762 /* SJ - Have checked the following:
763 * - It is never the case that number_of_left_image_nodes + number_of_right_image_nodes > 3
764 * - There are 1264 incidences of zero left image nodes, and 1252 incidences of zero right image nodes
765 * - 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
766 * image nodes
767 * - 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
768 * 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
769 * image node with 1/2 right image nodes that is responsible for the extra element.
770 */
771
772 // Elements on the left hand side (images of right nodes)
773 if (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2)
774 {
775 mLeftPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
776 }
777
778 // Elements on the right (images of left nodes)
779 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
780 {
781 mRightPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
782 }
783 }
784
785// if (mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
786// {
787// mMismatchedBoundaryElements = true;
788// // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
789// }
790
791 // Every boundary element on the left must have a corresponding element on the right
793}
794
796{
797 unsigned corresponding_node_index = UINT_MAX;
798
799 // If nodeIndex is a member of mRightOriginals, then find the corresponding node index in mRightImages
800 std::vector<unsigned>::iterator right_orig_iter = std::find(mRightOriginals.begin(), mRightOriginals.end(), nodeIndex);
801 if (right_orig_iter != mRightOriginals.end())
802 {
803 corresponding_node_index = mRightImages[right_orig_iter - mRightOriginals.begin()];
804 }
805 else
806 {
807 // If nodeIndex is a member of mRightImages, then find the corresponding node index in mRightOriginals
808 std::vector<unsigned>::iterator right_im_iter = std::find(mRightImages.begin(), mRightImages.end(), nodeIndex);
809 if (right_im_iter != mRightImages.end())
810 {
811 corresponding_node_index = mRightOriginals[right_im_iter - mRightImages.begin()];
812 }
813 else
814 {
815 // If nodeIndex is a member of mLeftOriginals, then find the corresponding node index in mLeftImages
816 std::vector<unsigned>::iterator left_orig_iter = std::find(mLeftOriginals.begin(), mLeftOriginals.end(), nodeIndex);
817 if (left_orig_iter != mLeftOriginals.end())
818 {
819 corresponding_node_index = mLeftImages[left_orig_iter - mLeftOriginals.begin()];
820 }
821 else
822 {
823 // If nodeIndex is a member of mLeftImages, then find the corresponding node index in mLeftOriginals
824 std::vector<unsigned>::iterator left_im_iter = std::find(mLeftImages.begin(), mLeftImages.end(), nodeIndex);
825 if (left_im_iter != mLeftImages.end())
826 {
827 corresponding_node_index = mLeftOriginals[left_im_iter - mLeftImages.begin()];
828 }
829 }
830 }
831 }
832
833 // We must have found the corresponding node index
834 assert(corresponding_node_index != UINT_MAX);
835 return corresponding_node_index;
836}
837
842
843void Cylindrical2dMesh::SetHaloScalingFactor(double haloScalingFactor)
844{
845 assert(haloScalingFactor >= 0.0);
846 mHaloScalingFactor = haloScalingFactor;
847}
848
850{
851 return mHaloOffset;
852}
853
854void Cylindrical2dMesh::SetHaloOffset(double haloOffset)
855{
856 assert(haloOffset >= 0.0);
857 mHaloOffset = haloOffset;
858}
859
860// Serialization for Boost >= 1.36
#define UNUSED_OPT(var)
#define NEVER_REACHED
#define CHASTE_CLASS_EXPORT(T)
void ReplaceNode(Node< SPACE_DIM > *pOldNode, Node< SPACE_DIM > *pNewNode)
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
bool IsDeleted() const
unsigned GetNodeGlobalIndex(unsigned localIndex) const
unsigned GetIndex() const
virtual unsigned GetNumAllNodes() const
virtual ChasteCuboid< SPACE_DIM > CalculateBoundingBox() const
NodeIterator GetNodeIteratorEnd()
virtual double GetWidth(const unsigned &rDimension) const
Node< SPACE_DIM > * GetNode(unsigned index) const
std::vector< Node< SPACE_DIM > * > mNodes
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
std::vector< Element< ELEMENT_DIM, SPACE_DIM > * > mElements
BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * GetBoundaryElement(unsigned index) const
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * > mBoundaryElements
const ChastePoint< SPACE_DIM > & rGetUpperCorner() const
const ChastePoint< SPACE_DIM > & rGetLowerCorner() const
c_vector< double, DIM > & rGetLocation()
void SetCoordinate(unsigned i, double value)
std::vector< unsigned > mLeftImages
unsigned AddNode(Node< 2 > *pNewNode)
unsigned GetCorrespondingNodeIndex(unsigned nodeIndex)
std::vector< unsigned > mRightImages
std::map< unsigned, unsigned > mImageToLeftOriginalNodeMap
double GetWidth(const unsigned &rDimension) const
void GenerateVectorsOfElementsStraddlingPeriodicBoundaries()
double GetHaloOffset() const
c_vector< double, 2 > GetVectorFromAtoB(const c_vector< double, 2 > &rLocation1, const c_vector< double, 2 > &rLocation2)
std::map< unsigned, unsigned > mImageToRightOriginalNodeMap
void SetHaloOffset(double haloOffset)
void SetHaloScalingFactor(double haloScalingFactor)
Cylindrical2dMesh(double width)
std::vector< unsigned > mTopHaloNodes
double GetHaloScalingFactor() const
void SetNode(unsigned index, ChastePoint< 2 > point, bool concreteMove)
std::vector< unsigned > mRightOriginals
std::vector< unsigned > mLeftOriginals
std::vector< unsigned > mBottomHaloNodes
std::set< unsigned > mRightPeriodicBoundaryElementIndices
std::set< unsigned > mLeftPeriodicBoundaryElementIndices
void UseTheseElementsToDecideMeshing(std::set< unsigned > &rMainSideElements)
void ReIndex(NodeMap &map)
virtual void SetNode(unsigned index, ChastePoint< SPACE_DIM > point, bool concreteMove=true)
std::vector< unsigned > mDeletedBoundaryElementIndices
void DeleteBoundaryNodeAt(unsigned index)
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< c_matrix< double, ELEMENT_DIM, SPACE_DIM > > mElementInverseJacobians
std::vector< double > mBoundaryElementJacobianDeterminants
std::vector< c_vector< double, SPACE_DIM > > mBoundaryElementWeightedDirections
std::vector< c_matrix< double, SPACE_DIM, ELEMENT_DIM > > mElementJacobians
std::vector< double > mElementJacobianDeterminants