Toggle navigation
Documentation
Big picture
The finite element method
The data structure
Not-so-quick guide
Optimisation
Order of action functions
Example codes and tutorials
List of example codes and tutorials
Meshing
Solvers
MPI parallel processing
Post-processing/visualisation
Other
Change log
Creating documentation
Coding conventions
Index
FAQ
About
People
Contact/Get involved
Publications
Acknowledgements
Copyright
Picture show
Go
src
meshes
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
36
using namespace
std;
37
using namespace
oomph
;
38
39
////////////////////////////////////////////////////////////////////
40
////////////////////////////////////////////////////////////////////
41
////////////////////////////////////////////////////////////////////
42
43
namespace
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>
72
void
QuadFromTriangleMesh<ELEMENT>::build_from_scaffold
(
73
TriangleScaffoldMesh
*
tmp_mesh_pt
,
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
115
QElement<2, 2>
dummy_element
;
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
{
129
dummy_element
.node_pt(
j
) =
130
new
Node
(
n_dim
,
n_position_type
,
initial_n_value
);
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
158
Vector<double>
centroid
(2);
159
160
// Create storage for the coordinates of the vertices of the triangle
161
Vector<Vector<double>
>
triangle_vertex
(3);
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
202
Vector<ELEMENT*>
el_vector_pt
(3, 0);
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
221
Node
*
qmesh_node_pt
=
scaffold_to_quad_mesh_node
[
scaffold_node_pt
];
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
237
qmesh_node_pt
=
el_vector_pt
[
j
]->construct_boundary_node(
238
corner_0
,
time_stepper_pt
);
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
252
qmesh_node_pt
=
253
el_vector_pt
[
j
]->construct_node(
corner_0
,
time_stepper_pt
);
254
}
255
256
// Add the mapping from the scaffold mesh node to the quad mesh node
257
scaffold_to_quad_mesh_node
[
scaffold_node_pt
] =
qmesh_node_pt
;
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
{
268
el_vector_pt
[
j
]->node_pt(
corner_0
) =
qmesh_node_pt
;
269
}
270
271
// Set global coordinate
272
el_vector_pt
[
j
]->node_pt(
corner_0
)->x(0) =
triangle_vertex
[
j
][0];
273
el_vector_pt
[
j
]->node_pt(
corner_0
)->x(1) =
triangle_vertex
[
j
][1];
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
289
Vector<Node*>
edge0_vector_pt
=
edge_nodes_map
[
edge0
];
290
Vector<Node*>
edge1_vector_pt
=
edge_nodes_map
[
edge1
];
291
Vector<Node*>
edge2_vector_pt
=
edge_nodes_map
[
edge2
];
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
305
edge0_vector_pt
[0] =
el_vector_pt
[0]->node_pt(0);
306
307
// Last node along edge 0 is the first node of element 1
308
edge0_vector_pt
[
nnode_edge
- 1] =
el_vector_pt
[1]->node_pt(0);
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
318
edge1_vector_pt
[0] =
el_vector_pt
[1]->node_pt(0);
319
320
// Last node along edge 1 is the first node of element 2
321
edge1_vector_pt
[
nnode_edge
- 1] =
el_vector_pt
[2]->node_pt(0);
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
331
edge2_vector_pt
[0] =
el_vector_pt
[2]->node_pt(0);
332
333
// Last node along edge 2 is the first node of element 0
334
edge2_vector_pt
[
nnode_edge
- 1] =
el_vector_pt
[0]->node_pt(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
378
Vector<unsigned>
boundary_id_vector
(6, 0);
379
boundary_id_vector
[0] =
q0_lower_boundary_id
;
380
boundary_id_vector
[1] =
q0_left_boundary_id
;
381
boundary_id_vector
[2] =
q1_lower_boundary_id
;
382
boundary_id_vector
[3] =
q1_left_boundary_id
;
383
boundary_id_vector
[4] =
q2_lower_boundary_id
;
384
boundary_id_vector
[5] =
q2_left_boundary_id
;
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
429
Node
*
nod_pt
=
el0_pt
->construct_node(
corner_3
,
time_stepper_pt
);
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
439
el1_pt
->node_pt(
corner_3
) =
el0_pt
->node_pt(
corner_3
);
440
441
// Quad 2
442
el2_pt
->node_pt(
corner_3
) =
el0_pt
->node_pt(
corner_3
);
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)
491
el0_pt
->node_pt(
j
) =
edge0_vector_pt
[(
nnode_edge
- 1) -
j
];
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
=
506
el0_pt
->construct_boundary_node(
j
,
time_stepper_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
512
edge0_vector_pt
[
j
] =
nod_pt
;
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
526
Node
*
nod_pt
=
el0_pt
->construct_node(
j
,
time_stepper_pt
);
527
528
// Add the node into the vector of nodes on edge 0
529
edge0_vector_pt
[
j
] =
nod_pt
;
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
547
el0_pt
->node_pt(
j
) =
edge2_vector_pt
[
j
/
nnode_1d
];
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
=
560
el0_pt
->construct_boundary_node(
j
,
time_stepper_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
567
edge2_vector_pt
[(
nnode_edge
- 1) - (
j
/
nnode_1d
)] =
nod_pt
;
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
581
Node
*
nod_pt
=
el0_pt
->construct_node(
j
,
time_stepper_pt
);
582
583
// Add the node into the vector of nodes on edge 2 in clockwise
584
// order
585
edge2_vector_pt
[(
nnode_edge
- 1) - (
j
/
nnode_1d
)] =
nod_pt
;
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
599
Node
*
nod_pt
=
el0_pt
->construct_node(
j
,
time_stepper_pt
);
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
606
el0_pt
->local_coordinate_of_node(
j
,
s
);
607
608
// Interpolate position linearly between vertex nodes
609
dummy_element
.interpolated_x(
s
, x);
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)
659
el1_pt
->node_pt(
j
) =
edge1_vector_pt
[(
nnode_edge
- 1) -
j
];
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
=
674
el1_pt
->construct_boundary_node(
j
,
time_stepper_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
680
edge1_vector_pt
[
j
] =
nod_pt
;
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
694
Node
*
nod_pt
=
el1_pt
->construct_node(
j
,
time_stepper_pt
);
695
696
// Add the node into the vector of nodes on edge 1
697
edge1_vector_pt
[
j
] =
nod_pt
;
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
715
el1_pt
->node_pt(
j
) =
edge0_vector_pt
[
j
/
nnode_1d
];
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
=
728
el1_pt
->construct_boundary_node(
j
,
time_stepper_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
735
edge0_vector_pt
[(
nnode_edge
- 1) - (
j
/
nnode_1d
)] =
nod_pt
;
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
749
Node
*
nod_pt
=
el1_pt
->construct_node(
j
,
time_stepper_pt
);
750
751
// Add the node into the vector of nodes on edge 0 in clockwise
752
// order
753
edge0_vector_pt
[(
nnode_edge
- 1) - (
j
/
nnode_1d
)] =
nod_pt
;
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
767
Node
*
nod_pt
=
el1_pt
->construct_node(
j
,
time_stepper_pt
);
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
774
el1_pt
->local_coordinate_of_node(
j
,
s
);
775
776
// Interpolate position linearly between vertex nodes
777
dummy_element
.interpolated_x(
s
, x);
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
) =
791
el0_pt
->node_pt(
corner_1
+ (
j
-
corner_2
) *
nnode_1d
);
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)
839
el2_pt
->node_pt(
j
) =
edge2_vector_pt
[(
nnode_edge
- 1) -
j
];
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
=
854
el2_pt
->construct_boundary_node(
j
,
time_stepper_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
860
edge2_vector_pt
[
j
] =
nod_pt
;
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
874
Node
*
nod_pt
=
el2_pt
->construct_node(
j
,
time_stepper_pt
);
875
876
// Add the node into the vector of nodes on edge 2
877
edge2_vector_pt
[
j
] =
nod_pt
;
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
906
el2_pt
->node_pt(
j
) =
edge1_vector_pt
[
j
/
nnode_1d
];
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
=
919
el2_pt
->construct_boundary_node(
j
,
time_stepper_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
926
edge1_vector_pt
[(
nnode_edge
- 1) - (
j
/
nnode_1d
)] =
nod_pt
;
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
940
Node
*
nod_pt
=
el2_pt
->construct_node(
j
,
time_stepper_pt
);
941
942
// Add the node into the vector of nodes on edge 1 in clockwise
943
// order
944
edge1_vector_pt
[(
nnode_edge
- 1) - (
j
/
nnode_1d
)] =
nod_pt
;
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
958
Node
*
nod_pt
=
el2_pt
->construct_node(
j
,
time_stepper_pt
);
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
965
el2_pt
->local_coordinate_of_node(
j
,
s
);
966
967
// Interpolate position linearly between vertex nodes
968
dummy_element
.interpolated_x(
s
, x);
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
) =
982
el1_pt
->node_pt(
corner_1
+ (
j
-
corner_2
) *
nnode_1d
);
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
992
edge_nodes_map
[
edge0
] =
edge0_vector_pt
;
993
edge_nodes_map
[
edge1
] =
edge1_vector_pt
;
994
edge_nodes_map
[
edge2
] =
edge2_vector_pt
;
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>
1019
void
RefineableQuadFromTriangleMesh<ELEMENT>::adapt
(
1020
const
Vector<double>
&
elem_error
)
1021
{
1022
// Call the adapt function from the TreeBasedRefineableMeshBase base class
1023
TreeBasedRefineableMeshBase::adapt(
elem_error
);
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
oomph::GeompackQuadMesh
Quadrilateral mesh generator; Uses input from Geompack++. See: http://members.shaw....
Definition
geompack_mesh.h:42
oomph::QuadFromTriangleMesh::build_from_scaffold
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.
Definition
quad_from_triangle_mesh.template.cc:72
oomph::RefineableQuadFromTriangleMesh::adapt
void adapt(const Vector< double > &elem_error)
Overload the adapt function (to ensure nodes are snapped to the boundary)
Definition
quad_from_triangle_mesh.template.cc:1019
oomph
Definition
annular_domain.h:35