quad_from_triangle_mesh.template.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26// Driver for 2D moving block
27#ifndef OOMPH_QUAD_FROM_TRIANGLE_MESH_TEMPLATE_HEADER
28#define OOMPH_QUAD_FROM_TRIANGLE_MESH_TEMPLATE_HEADER
29
30#ifndef OOMPH_QUAD_FROM_TRIANGLE_MESH_HEADER
31#error __FILE__ should only be included from quad_from_triangle_mesh.h.
32#endif // OOMPH_QUAD_FROM_TRIANGLE_MESH_HEADER
33
34// The mesh
35
36using namespace std;
37using namespace oomph;
38
39////////////////////////////////////////////////////////////////////
40////////////////////////////////////////////////////////////////////
41////////////////////////////////////////////////////////////////////
42
43namespace oomph
44{
45 //======================================================================
46 /// Build the full mesh with the help of the scaffold mesh coming
47 /// from the triangle mesh generator, Triangle. To build this quad
48 /// element based mesh we make use of the fact that a triangle element
49 /// can be split as shown in the diagram below:
50 ///
51 /// N2
52 /// | | N0 : 1st scaffold element node
53 /// | | N1 : 2nd scaffold element node
54 /// | | N2 : 3rd scaffold element node
55 /// | |
56 /// C | Q_2 | B Edge 0 : N0 --> N1
57 /// | | | | Edge 1 : N1 --> N2
58 /// | | | | Edge 2 : N2 --> N0
59 /// | | | |
60 /// | | | | A : Midpoint of edge 0
61 /// | Q_0 | Q_1 | B : Midpoint of edge 1
62 /// | | | C : Midpoint of edge 2
63 /// | | |
64 /// N0 __________|__________ N1
65 /// A
66 ///
67 /// The intersection of all three quad elements is the centroid. Using
68 /// this splitting, the subsequent mesh will consist of quadrilaterals
69 /// whose shape which depend on the structure of the underlying mesh.
70 //======================================================================
71 template<class ELEMENT>
74 TimeStepper* time_stepper_pt,
75 const bool& use_attributes)
76 {
77 // Create space for elements
78 unsigned nelem = tmp_mesh_pt->nelement();
79
80 // We will have 3 quad elements per scaffold element
81 Element_pt.resize(3 * nelem);
82
83 // Set number of boundaries
84 unsigned nbound = tmp_mesh_pt->nboundary();
85
86 // Resize the boundary information (the number of boundaries doesn't
87 // change)
88 set_nboundary(nbound);
89
90 // Stores each element attached to a boundary and the index of the
91 // face of the given element attached to the boundary
92 Boundary_element_pt.resize(nbound);
93 Face_index_at_boundary.resize(nbound);
94
95 // Create a quad element for nodal data
96 ELEMENT* temp_el_pt = new ELEMENT;
97
98 // Get the number of nodes in a quad element
99 unsigned nnode_el = temp_el_pt->nnode();
100
101 // Find the number of nodes along one edge of a quad element
102 unsigned nnode_1d = temp_el_pt->nnode_1d();
103
104 // Calculate the number of nodes that will lie along an edge of a
105 // triangle element in the scaffold mesh
106 unsigned nnode_edge = 2 * nnode_1d - 1;
107
108 // Delete the element pointer
109 delete temp_el_pt;
110
111 // Make it a null pointer
112 temp_el_pt = 0;
113
114 // Create dummy linear quad for geometry
116
117 // The dimension of the element
118 unsigned n_dim = 2;
119
120 // The position type
121 unsigned n_position_type = 1;
122
123 // Don't assign memory for any values
124 unsigned initial_n_value = 0;
125
126 // Loop over the nodes of the element and make them
127 for (unsigned j = 0; j < 4; j++)
128 {
131 }
132
133 // Local node number of each quad element corner
134 unsigned corner_0 = 0;
135 unsigned corner_1 = nnode_1d - 1;
136 unsigned corner_2 = nnode_el - nnode_1d;
137 unsigned corner_3 = nnode_el - 1;
138
139 // Create a map to return a vector of pointers to nnode_1d nodes where
140 // the input is an edge. If the edge hasn't been set up then this will
141 // return a null pointer. Note: all node pointers on an edge will be
142 // stored in clockwise ordering. Therefore, to copy the data of an
143 // edge into the adjoining element we must proceed through the vector
144 // backwards (as progressing through an edge of an element in a clockwise
145 // manner is equivalent to proceeding through the edge of the neighbouring
146 // element in an anti-clockwise manner)
147 std::map<Edge, Vector<Node*>> edge_nodes_map;
148
149 // Set up a map to check if the scaffold mesh node has been set up in the
150 // quad mesh. If the node has been set up this map will return a pointer
151 // to it otherwise it will return a null pointer
152 std::map<Node*, Node*> scaffold_to_quad_mesh_node;
153
154 // Loop over elements in scaffold mesh
155 unsigned new_el_count = 0;
156
157 // Create storage for the coordinates of the centroid
159
160 // Create storage for the coordinates of the vertices of the triangle
162
163 // Loop over all of the elements in the scaffold mesh
164 for (unsigned e = 0; e < nelem; e++)
165 {
166 // Initialise centroid values for the e-th triangle element
167 centroid[0] = 0.0;
168 centroid[1] = 0.0;
169
170 // Loop over the scaffold element nodes
171 for (unsigned j = 0; j < 3; j++)
172 {
173 // Resize the j-th triangle_vertex entry to contain the x and
174 // y-coordinate
175 triangle_vertex[j].resize(2);
176
177 // Get the coordinates
178 double x = tmp_mesh_pt->finite_element_pt(e)->node_pt(j)->x(0);
179 double y = tmp_mesh_pt->finite_element_pt(e)->node_pt(j)->x(1);
180
181 // Increment the centroid coordinates
182 centroid[0] += x;
183 centroid[1] += y;
184
185 // Assign the triangle_vertex coordinates
186 triangle_vertex[j][0] = x;
187 triangle_vertex[j][1] = y;
188 }
189
190 // Divide the centroid entries by 3 to get the centroid coordinates
191 centroid[0] /= 3.0;
192 centroid[1] /= 3.0;
193
194 // Create element pointers and assign them to a vector
195 //----------------------------------------------------
196 // Make new quad elements of the type specified by the template parameter
197 ELEMENT* el0_pt = new ELEMENT;
198 ELEMENT* el1_pt = new ELEMENT;
199 ELEMENT* el2_pt = new ELEMENT;
200
201 // Create a vector of ELEMENTs to store el0_pt, el1_pt and el2_pt
203
204 // Assign the entries to el_vector_pt
205 el_vector_pt[0] = el0_pt;
206 el_vector_pt[1] = el1_pt;
207 el_vector_pt[2] = el2_pt;
208
209 // Create the first node in each quad element and store in Node_pt.
210 // These correspond to the nodes of the simplex triangle stored in
211 // Tmp_mesh_pt. If they have already been set up then we do nothing:
212 //------------------------------------------------------------------
213 // Loop over the scaffold element nodes and check to see if they have
214 // been set up
215 for (unsigned j = 0; j < 3; j++)
216 {
217 // Pointer to node in the scaffold mesh
218 Node* scaffold_node_pt = tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
219
220 // Check if the node has been set up yet
222
223 // Haven't done this one yet
224 if (qmesh_node_pt == 0)
225 {
226 // Get pointer to set of mesh boundaries that this
227 // scaffold node occupies; NULL if the node is not on any boundary
228 std::set<unsigned>* boundaries_pt;
229 scaffold_node_pt->get_boundaries_pt(boundaries_pt);
230
231 // Check to see if it's on any boundaries
232 if (boundaries_pt != 0)
233 {
234 // Create new boundary node. The scaffold element nodes are the
235 // corners of a simplex triangle and thus always correspond to the
236 // first node in each quad element
239
240 // Add to boundaries
241 for (std::set<unsigned>::iterator it = boundaries_pt->begin();
242 it != boundaries_pt->end();
243 ++it)
244 {
245 add_boundary_node(*it, qmesh_node_pt);
246 }
247 }
248 // Build normal node
249 else
250 {
251 // Create new normal node
254 }
255
256 // Add the mapping from the scaffold mesh node to the quad mesh node
258
259 // Copy new node, created using the NEW element's construct_node
260 // function into global storage, using the same global
261 // node number that we've just associated with the
262 // corresponding node in the scaffold mesh
263 Node_pt.push_back(qmesh_node_pt);
264 }
265 // If this node has already been done we need to copy the data across
266 else
267 {
269 }
270
271 // Set global coordinate
274 }
275
276 // Create the edges of the scaffold element and check to see if
277 // they've been set up yet or not. If they haven't:
278 //--------------------------------------------------------------
279 // Make the three edges of the triangle
280 Edge edge0(tmp_mesh_pt->finite_element_pt(e)->node_pt(0),
281 tmp_mesh_pt->finite_element_pt(e)->node_pt(1));
282 Edge edge1(tmp_mesh_pt->finite_element_pt(e)->node_pt(1),
283 tmp_mesh_pt->finite_element_pt(e)->node_pt(2));
284 Edge edge2(tmp_mesh_pt->finite_element_pt(e)->node_pt(2),
285 tmp_mesh_pt->finite_element_pt(e)->node_pt(0));
286
287 // Check if the edges have been set up (each will have size nnode_1d).
288 // If they have not been set up yet, this will
292
293 // Bools to indicate whether or not the edges have been set up
294 bool edge0_setup = (edge0_vector_pt.size() != 0);
295 bool edge1_setup = (edge1_vector_pt.size() != 0);
296 bool edge2_setup = (edge2_vector_pt.size() != 0);
297
298 // If edge 0 hasn't been set up (node 0 to node 1)
299 if (!edge0_setup)
300 {
301 // Resize the vector to have length nnode_1d
302 edge0_vector_pt.resize(nnode_edge, 0);
303
304 // First node along edge 0 is the first node of element 0
306
307 // Last node along edge 0 is the first node of element 1
309 }
310
311 // If edge 1 hasn't been set up (node 1 to node 2)
312 if (!edge1_setup)
313 {
314 // Resize the vector to have length nnode_1d
315 edge1_vector_pt.resize(nnode_edge, 0);
316
317 // First node along edge 1 is the first node of element 1
319
320 // Last node along edge 1 is the first node of element 2
322 }
323
324 // If edge 2 hasn't been set up (node 2 to node 0)
325 if (!edge2_setup)
326 {
327 // Resize the vector to have length nnode_1d
328 edge2_vector_pt.resize(nnode_edge, 0);
329
330 // First node along edge 2 is the first node of element 2
332
333 // Last node along edge 2 is the first node of element 0
335 }
336
337#ifdef PARANOID
338 // If any of the edges have been set up, make sure that that the endpoints
339 // in the returned vectors have the same address as those on the vertices
340
341 // Come back and finish this off.
342 // To check:
343 // - If two edges which have been set up have the same node in the
344 // middle
345 // - If an edge has already been set up then the map will return the
346 // same node as in the vector
347#endif
348
349 // Boundary IDs for bottom and left edge of quad
350 // from scaffold mesh (if these remain zero the edges
351 // are not on a boundary)
352 unsigned q0_lower_boundary_id = 0;
353 unsigned q0_left_boundary_id = 0;
354 unsigned q1_lower_boundary_id = 0;
355 unsigned q1_left_boundary_id = 0;
356 unsigned q2_lower_boundary_id = 0;
357 unsigned q2_left_boundary_id = 0;
358
359 // Lower/left boundary IDs for quad 0; the lower edge in quad 0 is on
360 // edge 0 of the scaffold triangle and the left edge in quad is on edge
361 // 2 in scaffold triangle
362 q0_lower_boundary_id = tmp_mesh_pt->edge_boundary(e, 0);
363 q0_left_boundary_id = tmp_mesh_pt->edge_boundary(e, 2);
364
365 // Lower/left boundary IDs for quad 1; the lower edge in quad 1 is on
366 // edge 1 of the scaffold triangle and the left edge in quad is on edge
367 // 0 of the scaffold triangle
368 q1_lower_boundary_id = tmp_mesh_pt->edge_boundary(e, 1);
369 q1_left_boundary_id = tmp_mesh_pt->edge_boundary(e, 0);
370
371 // Lower/left boundary IDs for quad 2; the lower edge in quad 2 is on
372 // edge 2 of the scaffold triangle and the left edge in quad is on edge
373 // 1 of the scaffold triangle
374 q2_lower_boundary_id = tmp_mesh_pt->edge_boundary(e, 2);
375 q2_left_boundary_id = tmp_mesh_pt->edge_boundary(e, 1);
376
377 // Store the boundary IDs as a vector; allows us to loop over them easily
385
386 // Loop over the quad elements and store the boundary elements in the
387 // vector Boundary_element_pt
388 for (unsigned j = 0; j < 3; j++)
389 {
390 // Loop over the lower and the left boundary ID in the j'th element
391 for (unsigned k = 0; k < 2; k++)
392 {
393 // The quad element lies on a boundary of the mesh
394 if (boundary_id_vector[2 * j + k] > 0)
395 {
396 // Since the j'th quad element lies on a boundary of the mesh we add
397 // a pointer to the element to the appropriate entry of
398 // Boundary_element_pt
399 Boundary_element_pt[boundary_id_vector[2 * j + k] - 1].push_back(
400 el_vector_pt[j]);
401
402 // If k=0 then the lower boundary of the quad element lies on
403 // the boundary of the mesh and if k=1 then the left boundary
404 // of the quad element lies on the mesh boundary. For quad elements
405 // the indices are as follows:
406 // North face: 2
407 // East face: 1
408 // South face: -2
409 // West face: -1
410 if (k == 0)
411 {
412 Face_index_at_boundary[boundary_id_vector[2 * j + k] - 1]
413 .push_back(-2);
414 }
415 else
416 {
417 Face_index_at_boundary[boundary_id_vector[2 * j + k] - 1]
418 .push_back(-1);
419 } // if (k==0)
420 } // if (boundary_id_vector[2*j+k]>0)
421 } // for (unsigned k=0;k<2;k++)
422 } // for (unsigned j=0;j<3;j++)
423
424 // The upper right node is always the centroid. Note: The 'corner_3' node
425 // lies within each of the three quad elements so we simply share the
426 // pointer to it with each element:
427 //---------------------------------------------------------------------------
428 // Construct the centroid node
430
431 // Add the pointer to the vector of nodal pointers
432 Node_pt.push_back(nod_pt);
433
434 // Quad 0
435 el0_pt->node_pt(corner_3)->x(0) = centroid[0];
436 el0_pt->node_pt(corner_3)->x(1) = centroid[1];
437
438 // Quad 1
440
441 // Quad 2
443
444 // Set the nodal positions of the dummy element to emulate the FIRST
445 // quad element (this allows for simple linear interpolation later):
446 //------------------------------------------------------------------
447 // Bottom-left corner
448 dummy_element.node_pt(0)->x(0) = triangle_vertex[0][0];
449 dummy_element.node_pt(0)->x(1) = triangle_vertex[0][1];
450
451 // Bottom-right corner
452 dummy_element.node_pt(1)->x(0) =
453 0.5 * (triangle_vertex[0][0] + triangle_vertex[1][0]);
454 dummy_element.node_pt(1)->x(1) =
455 0.5 * (triangle_vertex[0][1] + triangle_vertex[1][1]);
456
457 // Top-left corner
458 dummy_element.node_pt(2)->x(0) =
459 0.5 * (triangle_vertex[0][0] + triangle_vertex[2][0]);
460 dummy_element.node_pt(2)->x(1) =
461 0.5 * (triangle_vertex[0][1] + triangle_vertex[2][1]);
462
463 // Top-right corner
464 dummy_element.node_pt(3)->x(0) = centroid[0];
465 dummy_element.node_pt(3)->x(1) = centroid[1];
466
467 // Set up all of the nodes in the first quad element (Q0):
468 //--------------------------------------------------------
469 // Local and global coordinate vectors for the nodes
470 Vector<double> s(2);
471 Vector<double> x(2);
472
473 // Loop over all of nodes in Q0 noting that the lower left corner node
474 // (node 0) and the upper right corner node (centroid) have already
475 // been set up
476 for (unsigned j = 1; j < corner_3; j++)
477 {
478 // Indicates whether or not the node has been set up yet
479 bool done = false;
480
481 // On the lower edge
482 if (j < nnode_1d)
483 {
484 // If the lower edge has already been set up then we already know the
485 // nodes along this edge
486 if (edge0_setup)
487 {
488 // The j'th node along this edge is the (nnode_1d-j)'th node in the
489 // vector (remembering that the ordering is backwards since it has
490 // already been set up)
492
493 // Since the node has already been set up we do not need to sort
494 // out its global coordinate data so skip to the next node
495 continue;
496 }
497 // If the edge hasn't been set up yet
498 else
499 {
500 // If the node lies on a boundary too then we need to construct a
501 // boundary node
502 if (q0_lower_boundary_id > 0)
503 {
504 // Construct a boundary node
505 Node* nod_pt =
507
508 // Add it to the list of boundary nodes
509 add_boundary_node(q0_lower_boundary_id - 1, nod_pt);
510
511 // Add the node into the vector of nodes on edge 0
513
514 // Add it to the list of nodes in the mesh
515 Node_pt.push_back(nod_pt);
516
517 // Indicate the j'th node has been set up
518 done = true;
519 }
520 }
521
522 // Node is not on a mesh boundary but on the lower edge
523 if (!done)
524 {
525 // Construct a normal node
527
528 // Add the node into the vector of nodes on edge 0
530
531 // Add it to the list of nodes in the mesh
532 Node_pt.push_back(nod_pt);
533
534 // Indicate the j'th node has been set up
535 done = true;
536 }
537 }
538 // On the left edge
539 else if (j % nnode_1d == 0)
540 {
541 // If the left edge has already been set up then we already know the
542 // nodes along this edge
543 if (edge2_setup)
544 {
545 // The j'th node is the (j/nnode_1d)'th node along this edge and
546 // thus the (j/nnode_1d)'th entry in the edge vector
548
549 // Since the node has already been set up we do not need to sort
550 // out its global coordinate data
551 continue;
552 }
553 // If the edge hasn't been set up yet
554 else
555 {
556 if (q0_left_boundary_id > 0)
557 {
558 // Construct a boundary node
559 Node* nod_pt =
561
562 // Add it to the list of boundary nodes
563 add_boundary_node(q0_left_boundary_id - 1, nod_pt);
564
565 // Add the node into the vector of nodes on edge 2 in clockwise
566 // order
568
569 // Add it to the list of nodes in the mesh
570 Node_pt.push_back(nod_pt);
571
572 // Indicate that the j'th node has been set up
573 done = true;
574 }
575 }
576
577 // Node is not on a mesh boundary but on the left edge
578 if (!done)
579 {
580 // Construct a normal node
582
583 // Add the node into the vector of nodes on edge 2 in clockwise
584 // order
586
587 // Add it to the list of nodes in the mesh
588 Node_pt.push_back(nod_pt);
589
590 // Indicate the j'th node has been set up
591 done = true;
592 }
593 }
594
595 // Node is not on a mesh boundary or on the edge of the scaffold element
596 if (!done)
597 {
598 // Construct a normal node
600
601 // Add it to the list of nodes in the mesh
602 Node_pt.push_back(nod_pt);
603 }
604
605 // Get local coordinate
607
608 // Interpolate position linearly between vertex nodes
610 el0_pt->node_pt(j)->x(0) = x[0];
611 el0_pt->node_pt(j)->x(1) = x[1];
612 }
613
614 // Set the nodal positions of the dummy element to now emulate the
615 // SECOND quad element:
616 //------------------------------------------------------------------
617 // Note: we do not need to change the top-right corner since it always
618 // coincides with the centroid of the triangle element
619
620 // Bottom-left corner
621 dummy_element.node_pt(0)->x(0) = triangle_vertex[1][0];
622 dummy_element.node_pt(0)->x(1) = triangle_vertex[1][1];
623
624 // Bottom-right corner
625 dummy_element.node_pt(1)->x(0) =
626 0.5 * (triangle_vertex[1][0] + triangle_vertex[2][0]);
627 dummy_element.node_pt(1)->x(1) =
628 0.5 * (triangle_vertex[1][1] + triangle_vertex[2][1]);
629
630 // Top-left corner
631 dummy_element.node_pt(2)->x(0) =
632 0.5 * (triangle_vertex[0][0] + triangle_vertex[1][0]);
633 dummy_element.node_pt(2)->x(1) =
634 0.5 * (triangle_vertex[0][1] + triangle_vertex[1][1]);
635
636 // Set up all of the nodes in the second quad element (Q1):
637 //--------------------------------------------------------
638 // Here we need to notice that we have already set up the final nnode_1d
639 // nodes (the upper edge of Q1 coincides with the right edge of Q0)
640
641 // Loop over nodes 1 to (corner_2-1) in Q1 noting that the lower left
642 // corner node (node 0) and the upper edge of Q1 contains nodes
643 // corner_2 to corner_3
644 for (unsigned j = 1; j < corner_2; j++)
645 {
646 // Indicates whether or not the node has been set up yet
647 bool done = false;
648
649 // On the lower edge
650 if (j < nnode_1d)
651 {
652 // If the lower edge has already been set up then we already know the
653 // nodes along this edge
654 if (edge1_setup)
655 {
656 // The j'th node along this edge is the (nnode_1d-j)'th node in the
657 // vector (remembering that the ordering is backwards if it has
658 // already been set up)
660
661 // Since the node has already been set up we do not need to sort
662 // out its global coordinate data
663 continue;
664 }
665 // If the edge hasn't been set up yet
666 else
667 {
668 // If the node lies on a boundary too then we need to construct a
669 // boundary node
670 if (q1_lower_boundary_id > 0)
671 {
672 // Construct a boundary node
673 Node* nod_pt =
675
676 // Add it to the list of boundary nodes
677 add_boundary_node(q1_lower_boundary_id - 1, nod_pt);
678
679 // Add the node into the vector of nodes on edge 1
681
682 // Add it to the list of nodes in the mesh
683 Node_pt.push_back(nod_pt);
684
685 // Indicate the j'th node has been set up
686 done = true;
687 }
688 }
689
690 // Node is not on a mesh boundary but on the lower edge
691 if (!done)
692 {
693 // Construct a normal node
695
696 // Add the node into the vector of nodes on edge 1
698
699 // Add it to the list of nodes in the mesh
700 Node_pt.push_back(nod_pt);
701
702 // Indicate the j'th node has been set up
703 done = true;
704 }
705 }
706 // On the left edge
707 else if (j % nnode_1d == 0)
708 {
709 // If the left edge has already been set up then we already know the
710 // nodes along this edge
711 if (edge0_setup)
712 {
713 // The j'th node along this edge is the (j/nnode_1d)'th node in the
714 // vector
716
717 // Since the node has already been set up we do not need to sort
718 // out its global coordinate data
719 continue;
720 }
721 // If the edge hasn't been set up yet
722 else
723 {
724 if (q1_left_boundary_id > 0)
725 {
726 // Construct a boundary node
727 Node* nod_pt =
729
730 // Add it to the list of boundary nodes
731 add_boundary_node(q1_left_boundary_id - 1, nod_pt);
732
733 // Add the node into the vector of nodes on edge 0 in clockwise
734 // order
736
737 // Add it to the list of nodes in the mesh
738 Node_pt.push_back(nod_pt);
739
740 // Indicate that the j'th node has been set up
741 done = true;
742 }
743 }
744
745 // Node is not on a mesh boundary but on the left edge
746 if (!done)
747 {
748 // Construct a normal node
750
751 // Add the node into the vector of nodes on edge 0 in clockwise
752 // order
754
755 // Add it to the list of nodes in the mesh
756 Node_pt.push_back(nod_pt);
757
758 // Indicate the j'th node has been set up
759 done = true;
760 }
761 }
762
763 // Node is not on a mesh boundary or the scaffold element boundary
764 if (!done)
765 {
766 // Construct a normal node
768
769 // Add it to the list of nodes in the mesh
770 Node_pt.push_back(nod_pt);
771 }
772
773 // Get local coordinate
775
776 // Interpolate position linearly between vertex nodes
778 el1_pt->node_pt(j)->x(0) = x[0];
779 el1_pt->node_pt(j)->x(1) = x[1];
780 }
781
782 // We now need to loop over nodes corner_2 to (corner_3-1) and copy the
783 // given information from Q0. We do not need to set up the (corner_3)'th
784 // node since it coincides with the centroid which has already been set up
785 for (unsigned j = corner_2; j < corner_3; j++)
786 {
787 // The nodes along the upper edge of Q1 go from corner_2 to corner_3-1
788 // while the nodes along the right edge of Q0 go from corner_1 to
789 // (corner_3-nnode_1d) in increments of nnode_1d
790 el1_pt->node_pt(j) =
792 }
793
794 // Set the nodal positions of the dummy element to now emulate the
795 // THIRD quad element:
796 //------------------------------------------------------------------
797 // Note: we do not need to change the top-right corner since it always
798 // coincides with the centroid of the triangle element
799
800 // Bottom-left corner
801 dummy_element.node_pt(0)->x(0) = triangle_vertex[2][0];
802 dummy_element.node_pt(0)->x(1) = triangle_vertex[2][1];
803
804 // Bottom-right corner
805 dummy_element.node_pt(1)->x(0) =
806 0.5 * (triangle_vertex[0][0] + triangle_vertex[2][0]);
807 dummy_element.node_pt(1)->x(1) =
808 0.5 * (triangle_vertex[0][1] + triangle_vertex[2][1]);
809
810 // Top-left corner
811 dummy_element.node_pt(2)->x(0) =
812 0.5 * (triangle_vertex[1][0] + triangle_vertex[2][0]);
813 dummy_element.node_pt(2)->x(1) =
814 0.5 * (triangle_vertex[1][1] + triangle_vertex[2][1]);
815
816 // Set up all of the nodes in the third quad element (Q2):
817 //--------------------------------------------------------
818 // Here we need to notice that we have already set up the final nnode_1d
819 // nodes (the upper edge of Q2 coincides with the right edge of Q1).
820 // We have also already set up the nodes on the right edge of Q2 (the
821 // right edge of Q2 coincides with the upper edge of Q0)
822
823 // Loop over nodes 1 to (corner_2-1)
824 for (unsigned j = 1; j < corner_2; j++)
825 {
826 // Indicates whether or not the node has been set up yet
827 bool done = false;
828
829 // On the lower edge
830 if (j < nnode_1d - 1)
831 {
832 // If the lower edge has already been set up then we already know the
833 // nodes along this edge
834 if (edge2_setup)
835 {
836 // The j'th node along this edge is the (nnode_1d-j)'th node in the
837 // vector (remembering that the ordering is backwards if it has
838 // already been set up)
840
841 // Since the node has already been set up we do not need to sort
842 // out its global coordinate data
843 continue;
844 }
845 // If the edge hasn't been set up yet
846 else
847 {
848 // If the node lies on a boundary too then we need to construct a
849 // boundary node
850 if (q2_lower_boundary_id > 0)
851 {
852 // Construct a boundary node
853 Node* nod_pt =
855
856 // Add it to the list of boundary nodes
857 add_boundary_node(q2_lower_boundary_id - 1, nod_pt);
858
859 // Add the node into the vector of nodes on edge 2
861
862 // Add it to the list of nodes in the mesh
863 Node_pt.push_back(nod_pt);
864
865 // Indicate the j'th node has been set up
866 done = true;
867 }
868 }
869
870 // Node is not on a mesh boundary but on the lower edge
871 if (!done)
872 {
873 // Construct a normal node
875
876 // Add the node into the vector of nodes on edge 2
878
879 // Add it to the list of nodes in the mesh
880 Node_pt.push_back(nod_pt);
881
882 // Indicate the j'th node has been set up
883 done = true;
884 }
885 }
886 // On the right edge
887 else if ((j + 1) % nnode_1d == 0)
888 {
889 // Copy the data from the top edge of element 0 to element 2
890 el2_pt->node_pt(j) =
891 el0_pt->node_pt((corner_2 - 1) + (j + 1) / nnode_1d);
892
893 // We don't need to set up the global coordinate data so just
894 // skip to the next node in the element
895 continue;
896 }
897 // On the left edge
898 else if (j % nnode_1d == 0)
899 {
900 // If the left edge has already been set up then we already know the
901 // nodes along this edge
902 if (edge1_setup)
903 {
904 // The j'th node along this edge is the (j/nnode_1d)'th node in the
905 // vector
907
908 // Since the node has already been set up we do not need to sort
909 // out its global coordinate data
910 continue;
911 }
912 // If the edge hasn't been set up yet
913 else
914 {
915 if (q2_left_boundary_id > 0)
916 {
917 // Construct a boundary node
918 Node* nod_pt =
920
921 // Add it to the list of boundary nodes
922 add_boundary_node(q2_left_boundary_id - 1, nod_pt);
923
924 // Add the node into the vector of nodes on edge 1 in clockwise
925 // order
927
928 // Add it to the list of nodes in the mesh
929 Node_pt.push_back(nod_pt);
930
931 // Indicate that the j'th node has been set up
932 done = true;
933 }
934 }
935
936 // Node is not on a mesh boundary but on the left edge
937 if (!done)
938 {
939 // Construct a normal node
941
942 // Add the node into the vector of nodes on edge 1 in clockwise
943 // order
945
946 // Add it to the list of nodes in the mesh
947 Node_pt.push_back(nod_pt);
948
949 // Indicate the j'th node has been set up
950 done = true;
951 }
952 }
953
954 // Node is not on a mesh boundary
955 if (!done)
956 {
957 // Construct a normal node
959
960 // Add it to the list of nodes in the mesh
961 Node_pt.push_back(nod_pt);
962 }
963
964 // Get local coordinate
966
967 // Interpolate position linearly between vertex nodes
969 el2_pt->node_pt(j)->x(0) = x[0];
970 el2_pt->node_pt(j)->x(1) = x[1];
971 }
972
973 // We now need to loop over nodes corner_2 to (corner_3-1) and copy the
974 // given information from Q1. We do not need to set up the (corner_3)'th
975 // node since it coincides with the centroid which has already been set up
976 for (unsigned j = corner_2; j < corner_3; j++)
977 {
978 // The nodes along the upper edge of Q2 go from corner_2 to corner_3-1
979 // while the nodes along the right edge of Q1 go from corner_1 to
980 // (corner_3-nnode_1d) in increments of nnode_1d
981 el2_pt->node_pt(j) =
983 }
984
985 // Add the element pointers to Element_pt and then increment the counter
986 Element_pt[new_el_count] = el0_pt;
987 Element_pt[new_el_count + 1] = el1_pt;
988 Element_pt[new_el_count + 2] = el2_pt;
989 new_el_count += 3;
990
991 // Assign the edges to the edge map
995 }
996
997 // Indicate that the look up scheme has been set up
998 Lookup_for_elements_next_boundary_is_setup = true;
999
1000 // Clean the dummy element nodes
1001 for (unsigned j = 0; j < 4; j++)
1002 {
1003 // Delete the j-th dummy element node
1004 delete dummy_element.node_pt(j);
1005
1006 // Make it a null pointer
1007 dummy_element.node_pt(j) = 0;
1008 }
1009 }
1010
1011 ////////////////////////////////////////////////////////////////////
1012 ////////////////////////////////////////////////////////////////////
1013 ////////////////////////////////////////////////////////////////////
1014
1015 //======================================================================
1016 /// Adapt problem based on specified elemental error estimates
1017 //======================================================================
1018 template<class ELEMENT>
1021 {
1022 // Call the adapt function from the TreeBasedRefineableMeshBase base class
1024
1025#ifdef OOMPH_HAS_TRIANGLE_LIB
1026 // Move the nodes on the new boundary onto the old curvilinear
1027 // boundary. If the boundary is straight this will do precisely
1028 // nothing but will be somewhat inefficient
1029 this->snap_nodes_onto_geometric_objects();
1030#endif
1031 } // End of adapt
1032} // End of namespace oomph
1033
1034#endif // OOMPH_QUAD_FROM_TRIANGLE_MESH_TEMPLATE_HEADER
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
Edge class.
Definition mesh.h:2700
virtual void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size (broken virtual)
Definition elements.h:1846
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object.
Definition elements.h:2513
virtual double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s.
Definition elements.cc:3992
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
Node ** Node_pt
Storage for pointers to the nodes in the element.
Definition elements.h:1323
virtual Node * construct_boundary_node(const unsigned &n)
Construct the local node n as a boundary node; that is a node that MAY be placed on a mesh boundary a...
Definition elements.h:2542
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overload...
Definition elements.h:2222
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition nodes.h:1060
void build_from_scaffold(TriangleScaffoldMesh *tmp_mesh_pt, TimeStepper *time_stepper_pt, const bool &use_attributes)
Build the quad mesh from the given scaffold mesh.
void adapt(const Vector< double > &elem_error)
Overload the adapt function (to ensure nodes are snapped to the boundary)
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
TAdvectionDiffusionReactionElement()
Constructor: Call constructors for TElement and AdvectionDiffusionReaction equations.
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
void adapt(const Vector< double > &elemental_error)
Adapt mesh: Refine elements whose error is lager than err_max and (try to) unrefine those whose error...
Triangle Mesh that is based on input files generated by the triangle mesh generator Triangle.
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).