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
tetgen_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
#ifndef OOMPH_TETGEN_MESH_TEMPLATE_HEADER
27
#define OOMPH_TETGEN_MESH_TEMPLATE_HEADER
28
29
#ifndef OOMPH_TETGEN_MESH_HEADER
30
#error __FILE__ should only be included from tetgen_mesh.h.
31
#endif
// OOMPH_TETGEN_MESH_HEADER
32
33
#include <algorithm>
34
35
#include "generic/Telements.h"
36
#include "generic/map_matrix.h"
37
38
namespace
oomph
39
{
40
///////////////////////////////////////////////////////////////////////
41
///////////////////////////////////////////////////////////////////////
42
///////////////////////////////////////////////////////////////////////
43
44
//========================================================================
45
/// Build unstructured tet mesh based on output from scaffold
46
//========================================================================
47
template
<
class
ELEMENT>
48
void
TetgenMesh<ELEMENT>::build_from_scaffold
(
TimeStepper
*
time_stepper_pt
,
49
const
bool
&
use_attributes
)
50
{
51
// Mesh can only be built with 3D Telements.
52
MeshChecker::assert_geometric_element<TElementGeometricBase, ELEMENT>(3);
53
54
// Create space for elements
55
unsigned
nelem
=
Tmp_mesh_pt
->nelement();
56
Element_pt
.resize(
nelem
);
57
58
// Create space for nodes
59
unsigned
nnode_scaffold
=
Tmp_mesh_pt
->nnode();
60
Node_pt
.resize(
nnode_scaffold
);
61
62
// Set number of boundaries
63
unsigned
nbound
=
Tmp_mesh_pt
->nboundary();
64
set_nboundary
(
nbound
);
65
Boundary_element_pt
.resize(
nbound
);
66
Face_index_at_boundary
.resize(
nbound
);
67
68
// If we have different regions, then resize the region
69
// information
70
if
(
use_attributes
)
71
{
72
Boundary_region_element_pt
.resize(
nbound
);
73
Face_index_region_at_boundary
.resize(
nbound
);
74
}
75
76
// Build elements
77
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
78
{
79
Element_pt
[
e
] =
new
ELEMENT
;
80
}
81
82
// Number of nodes per element
83
unsigned
nnod_el
=
Tmp_mesh_pt
->finite_element_pt(0)->nnode();
84
85
// Setup map to check the (pseudo-)global node number
86
// Nodes whose number is zero haven't been copied across
87
// into the mesh yet.
88
std::map<Node*, unsigned>
global_number
;
89
unsigned
global_count
= 0;
90
91
// Map of element attribute pairs
92
std::map<double, Vector<FiniteElement*>>
element_attribute_map
;
93
94
// Loop over elements in scaffold mesh, visit their nodes
95
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
96
{
97
// Loop over all nodes in element
98
for
(
unsigned
j
= 0;
j
<
nnod_el
;
j
++)
99
{
100
// Pointer to node in the scaffold mesh
101
Node
*
scaffold_node_pt
=
Tmp_mesh_pt
->finite_element_pt(
e
)->node_pt(
j
);
102
103
// Get the (pseudo-)global node number in scaffold mesh
104
// (It's zero [=default] if not visited this one yet)
105
unsigned
j_global
=
global_number
[
scaffold_node_pt
];
106
107
// Haven't done this one yet
108
if
(
j_global
== 0)
109
{
110
// Get pointer to set of mesh boundaries that this
111
// scaffold node occupies; NULL if the node is not on any boundary
112
std::set<unsigned>*
boundaries_pt
;
113
scaffold_node_pt
->get_boundaries_pt(
boundaries_pt
);
114
115
// Is it on boundaries?
116
if
(
boundaries_pt
!= 0)
117
{
118
// Create new boundary node
119
Node
*
new_node_pt
=
120
finite_element_pt
(
e
)->construct_boundary_node(
j
,
time_stepper_pt
);
121
122
// Give it a number (not necessarily the global node
123
// number in the scaffold mesh -- we just need something
124
// to keep track...)
125
global_count
++;
126
global_number
[
scaffold_node_pt
] =
global_count
;
127
128
// Add to boundaries
129
for
(std::set<unsigned>::iterator
it
=
boundaries_pt
->begin();
130
it
!=
boundaries_pt
->end();
131
++
it
)
132
{
133
add_boundary_node
(*
it
,
new_node_pt
);
134
}
135
}
136
// Build normal node
137
else
138
{
139
// Create new normal node
140
finite_element_pt
(
e
)->construct_node(
j
,
time_stepper_pt
);
141
142
// Give it a number (not necessarily the global node
143
// number in the scaffold mesh -- we just need something
144
// to keep track...)
145
global_count
++;
146
global_number
[
scaffold_node_pt
] =
global_count
;
147
}
148
149
// Copy new node, created using the NEW element's construct_node
150
// function into global storage, using the same global
151
// node number that we've just associated with the
152
// corresponding node in the scaffold mesh
153
Node_pt
[
global_count
- 1] =
finite_element_pt
(
e
)->node_pt(
j
);
154
155
// Assign coordinates
156
Node_pt
[
global_count
- 1]->x(0) =
scaffold_node_pt
->x(0);
157
Node_pt
[
global_count
- 1]->x(1) =
scaffold_node_pt
->x(1);
158
Node_pt
[
global_count
- 1]->x(2) =
scaffold_node_pt
->x(2);
159
}
160
// This one has already been done: Copy across
161
else
162
{
163
finite_element_pt
(
e
)->node_pt(
j
) =
Node_pt
[
j_global
- 1];
164
}
165
}
166
167
// Store the attributes in the map
168
if
(
use_attributes
)
169
{
170
element_attribute_map
[
Tmp_mesh_pt
->element_attribute(
e
)].push_back(
171
finite_element_pt
(
e
));
172
}
173
}
174
175
// Now let's construct lists
176
// Find the number of attributes
177
if
(
use_attributes
)
178
{
179
unsigned
n_attribute
=
element_attribute_map
.size();
180
// There are n_attribute different regions
181
Region_element_pt
.resize(
n_attribute
);
182
Region_attribute
.resize(
n_attribute
);
183
// Copy the vectors in the map over to our internal storage
184
unsigned
count
= 0;
185
for
(std::map<
double
,
Vector<FiniteElement*>
>::iterator
it
=
186
element_attribute_map
.begin();
187
it
!=
element_attribute_map
.end();
188
++
it
)
189
{
190
Region_attribute
[
count
] =
it
->first;
191
Region_element_pt
[
count
] =
it
->second;
192
++
count
;
193
}
194
}
195
196
// At this point we've created all the elements and
197
// created their vertex nodes. Now we need to create
198
// the additional (midside and internal) nodes!
199
unsigned
boundary_id
;
200
201
// Get number of nodes along element edge and dimension of element (3)
202
// from first element
203
unsigned
n_node_1d
=
finite_element_pt
(0)->nnode_1d();
204
205
// At the moment we're only able to deal with nnode_1d=2 or 3.
206
if
((
n_node_1d
!= 2) && (
n_node_1d
!= 3))
207
{
208
std::ostringstream
error_message
;
209
error_message
<<
"Mesh generation from tetgen currently only works\n"
;
210
error_message
<<
"for nnode_1d = 2 or 3. You're trying to use it\n"
;
211
error_message
<<
"for nnode_1d="
<<
n_node_1d
<< std::endl;
212
213
throw
OomphLibError
(
214
error_message
.str(),
OOMPH_CURRENT_FUNCTION
,
OOMPH_EXCEPTION_LOCATION
);
215
}
216
217
// Spatial dimension of element = number of local coordinates
218
unsigned
dim
=
finite_element_pt
(0)->dim();
219
220
// Storage for the local coordinate of the new node
221
Vector<double>
s
(
dim
);
222
223
// Get number of nodes in the element from first element
224
unsigned
n_node
=
finite_element_pt
(0)->nnode();
225
226
// Storage for each global edge of the mesh
227
unsigned
n_global_edge
=
Tmp_mesh_pt
->nglobal_edge();
228
Vector<Vector<Node*>
>
nodes_on_global_edge
(
n_global_edge
);
229
230
// Storage for each global face of the mesh
231
unsigned
n_global_face
=
Tmp_mesh_pt
->nglobal_face();
232
Vector<Vector<Node*>
>
nodes_on_global_face
(
n_global_face
);
233
234
// Map storing the mid-side of an edge; edge identified by
235
// pointers to vertex nodes in scaffold mesh
236
// MapMatrix<Node*,Node*> central_edge_node_pt;
237
// Node* edge_node1_pt=0;
238
// Node* edge_node2_pt=0;
239
240
// Map storing the mid point of a face; face identified by
241
// set of pointers to vertex nodes in scaffold mesh
242
// std::map<std::set<Node*>,Node*> central_face_node_pt;
243
// std::set<Node*> face_nodes_pt;
244
245
// Mapping of Tetgen faces to face nodes in the enriched element
246
unsigned
face_map
[4] = {1, 0, 2, 3};
247
248
// Storage for the faces shared by the edges
249
const
unsigned
faces_on_edge
[6][2] = {
250
{0, 1}, {0, 2}, {1, 2}, {0, 3}, {2, 3}, {1, 3}};
251
252
// Loop over all elements
253
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
254
{
255
// Cache pointers to the elements
256
FiniteElement
*
const
elem_pt
= this->
finite_element_pt
(
e
);
257
FiniteElement
*
const
tmp_elem_pt
=
Tmp_mesh_pt
->finite_element_pt(
e
);
258
259
// The number of edge nodes is 4 + 6*(n_node1d-2)
260
unsigned
n_edge_node
= 4 + 6 * (
n_node_1d
- 2);
261
262
// Now loop over the edge nodes
263
// assuming that the numbering scheme is the same as the triangles
264
// which puts edge nodes in ascending order.
265
// We don't have any higher than quadratic at the moment, so it's
266
// a bit academic really.
267
268
// Only bother if we actually have some edge nodes
269
if
(
n_edge_node
> 4)
270
{
271
// Start from node number 4
272
unsigned
n
= 4;
273
274
// Loop over the edges
275
for
(
unsigned
j
= 0;
j
< 6; ++
j
)
276
{
277
// Find the global edge index
278
unsigned
edge_index
=
Tmp_mesh_pt
->edge_index(
e
,
j
);
279
280
// Use the intersection of the appropriate faces to determine
281
// whether the boundaries on which an edge lies
282
std::set<unsigned>
edge_boundaries
;
283
for
(
unsigned
i
= 0;
i
< 2; ++
i
)
284
{
285
unsigned
face_boundary_id
=
286
Tmp_mesh_pt
->face_boundary(
e
,
faces_on_edge
[
j
][
i
]);
287
if
(
face_boundary_id
> 0)
288
{
289
edge_boundaries
.insert(
face_boundary_id
);
290
}
291
}
292
293
// If the nodes on the edge have not been allocated, construct them
294
if
(
nodes_on_global_edge
[
edge_index
].
size
() == 0)
295
{
296
// Now loop over the nodes on the edge
297
for
(
unsigned
j2
= 0;
j2
<
n_node_1d
- 2; ++
j2
)
298
{
299
// Storage for the new node
300
Node
*
new_node_pt
= 0;
301
302
// If the edge is on a boundary, determined from the
303
// scaffold mesh, construct a boundary node
304
// The use of the scaffold mesh's edge_boundary data structure
305
// ensures that a boundary node is created, even if the faces of
306
// the current element do not lie on boundaries
307
if
(
Tmp_mesh_pt
->edge_boundary(
edge_index
) ==
true
)
308
{
309
new_node_pt
=
310
elem_pt
->construct_boundary_node(
n
,
time_stepper_pt
);
311
// Add it to the boundaries in the set,
312
// remembering to subtract one to get to the oomph-lib numbering
313
// scheme
314
for
(std::set<unsigned>::iterator
it
=
edge_boundaries
.begin();
315
it
!=
edge_boundaries
.end();
316
++
it
)
317
{
318
this->
add_boundary_node
((*
it
) - 1,
new_node_pt
);
319
}
320
}
321
// Otherwise construct a normal node
322
else
323
{
324
new_node_pt
=
elem_pt
->construct_node(
n
,
time_stepper_pt
);
325
}
326
327
// Find the local coordinates of the node
328
elem_pt
->local_coordinate_of_node(
n
,
s
);
329
330
// Find the coordinates of the new node from the exiting and
331
// fully-functional element in the scaffold mesh
332
for
(
unsigned
i
= 0;
i
<
dim
; ++
i
)
333
{
334
new_node_pt
->x(
i
) =
tmp_elem_pt
->interpolated_x(
s
,
i
);
335
}
336
337
// Add the newly created node to the global node list
338
Node_pt
.push_back(
new_node_pt
);
339
// Add to the edge index
340
nodes_on_global_edge
[
edge_index
].push_back(
new_node_pt
);
341
// Increment the local node number
342
++
n
;
343
}
// end of loop over edge nodes
344
}
345
// Otherwise just set the pointers (orientation assumed the same)
346
else
347
{
348
for
(
unsigned
j2
= 0;
j2
<
n_node_1d
- 2; ++
j2
)
349
{
350
elem_pt
->node_pt(
n
) =
nodes_on_global_edge
[
edge_index
][
j2
];
351
// It is possible that the edge may be on additional boundaries
352
// through another element
353
// So add again (note that this function will not add to
354
// boundaries twice)
355
for
(std::set<unsigned>::iterator
it
=
edge_boundaries
.begin();
356
it
!=
edge_boundaries
.end();
357
++
it
)
358
{
359
this->
add_boundary_node
((*
it
) - 1,
elem_pt
->node_pt(
n
));
360
}
361
++
n
;
362
}
363
}
364
}
// End of loop over edges
365
366
// Deal with enriched elements
367
if
(
n_node
== 15)
368
{
369
// Now loop over the faces
370
for
(
unsigned
j
= 0;
j
< 4; ++
j
)
371
{
372
// Find the boundary id of the face (need to map between node
373
// numbers and the face)
374
boundary_id
=
Tmp_mesh_pt
->face_boundary(
e
,
face_map
[
j
]);
375
376
// Find the global face index (need to map between node numbers and
377
// the face)
378
unsigned
face_index
=
Tmp_mesh_pt
->face_index(
e
,
face_map
[
j
]);
379
380
// If the nodes on the face have not been allocated
381
if
(
nodes_on_global_face
[
face_index
].
size
() == 0)
382
{
383
// Storage for the new node
384
Node
*
new_node_pt
= 0;
385
386
// If the face is on a boundary, construct a boundary node
387
if
(
boundary_id
> 0)
388
{
389
new_node_pt
=
390
elem_pt
->construct_boundary_node(
n
,
time_stepper_pt
);
391
// Add it to the boundary
392
this->
add_boundary_node
(
boundary_id
- 1,
new_node_pt
);
393
}
394
// Otherwise construct a normal node
395
else
396
{
397
new_node_pt
=
elem_pt
->construct_node(
n
,
time_stepper_pt
);
398
}
399
400
// Find the local coordinates of the node
401
elem_pt
->local_coordinate_of_node(
n
,
s
);
402
403
// Find the coordinates of the new node from the exiting and
404
// fully-functional element in the scaffold mesh
405
for
(
unsigned
i
= 0;
i
<
dim
; ++
i
)
406
{
407
new_node_pt
->x(
i
) =
tmp_elem_pt
->interpolated_x(
s
,
i
);
408
}
409
410
// Add the newly created node to the global node list
411
Node_pt
.push_back(
new_node_pt
);
412
// Add to the face index
413
nodes_on_global_face
[
face_index
].push_back(
new_node_pt
);
414
// Increment the local node number
415
++
n
;
416
}
417
// Otherwise just set the single node from the face element
418
else
419
{
420
elem_pt
->node_pt(
n
) =
nodes_on_global_face
[
face_index
][0];
421
++
n
;
422
}
423
}
// end of loop over faces
424
425
// Construct the element's central node, which is not on a boundary
426
{
427
Node
*
new_node_pt
=
428
finite_element_pt
(
e
)->construct_node(
n
,
time_stepper_pt
);
429
Node_pt
.push_back(
new_node_pt
);
430
431
// Find the local coordinates of the node
432
elem_pt
->local_coordinate_of_node(
n
,
s
);
433
434
// Find the coordinates of the new node from the existing
435
// and fully-functional element in the scaffold mesh
436
for
(
unsigned
i
= 0;
i
<
dim
;
i
++)
437
{
438
new_node_pt
->x(
i
) =
tmp_elem_pt
->interpolated_x(
s
,
i
);
439
}
440
}
441
}
// End of enriched case
442
443
}
// End of case for edge nodes
444
445
// Now loop over the faces to setup the information about elements
446
// adjacent to the boundary
447
for
(
unsigned
j
= 0;
j
< 4; ++
j
)
448
{
449
// Find the boundary id of the face
450
boundary_id
=
Tmp_mesh_pt
->face_boundary(
e
,
j
);
451
452
if
(
boundary_id
> 0)
453
{
454
Boundary_element_pt
[
boundary_id
- 1].push_back(
elem_pt
);
455
// Need to put a shift in here because of an inconsistent naming
456
// convention between tetgen and our faces
457
// Tetgen Face 0 is our Face 3
458
// Tetgen Face 1 is our Face 2
459
// Tetgen Face 2 is our Face 1
460
// Tetgen Face 3 is our Face 0
461
Face_index_at_boundary
[
boundary_id
- 1].push_back(3 -
j
);
462
463
// If using regions set up the boundary information
464
if
(
use_attributes
)
465
{
466
// Element adjacent to boundary
467
Boundary_region_element_pt
[
boundary_id
- 1]
468
[
static_cast<
unsigned
>
(
469
Tmp_mesh_pt
->element_attribute(
e
))]
470
.
push_back
(
elem_pt
);
471
// Need to put a shift in here because of an inconsistent naming
472
// convention between triangle and face elements
473
Face_index_region_at_boundary
[
boundary_id
- 1]
474
[
static_cast<
unsigned
>
(
475
Tmp_mesh_pt
->element_attribute(
e
))]
476
.
push_back
(3 -
j
);
477
}
478
}
479
}
// End of loop over faces
480
481
// Lookup scheme has now been setup
482
Lookup_for_elements_next_boundary_is_setup
=
true
;
483
484
// /*
485
486
// //For standard quadratic elements all nodes are edge nodes
487
// unsigned n_vertex_and_edge_node = n_node;
488
// //If we have enriched elements, there are only 10 vertex and edge
489
// nodes if(n_node==15)
490
// {
491
// //There are only 10 vertex and edge nodes
492
// n_vertex_and_edge_node = 10;
493
// }
494
495
// // Loop over the new (edge) nodes in the element and create them.
496
// for(unsigned j=4;j<n_vertex_and_edge_node;j++)
497
// {
498
499
// // Figure out edge nodes
500
// switch(j)
501
// {
502
503
// // Node 4 is between nodes 0 and 1
504
// case 4:
505
506
// edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(0);
507
// edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(1);
508
// break;
509
510
// // Node 5 is between nodes 0 and 2
511
// case 5:
512
513
// edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(0);
514
// edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(2);
515
// break;
516
517
// // Node 6 is between nodes 0 and 3
518
// case 6:
519
520
// edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(0);
521
// edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(3);
522
// break;
523
524
// // Node 7 is between nodes 1 and 2
525
// case 7:
526
527
// edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(1);
528
// edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(2);
529
// break;
530
531
// // Node 8 is between nodes 2 and 3
532
// case 8:
533
534
// edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(2);
535
// edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(3);
536
// break;
537
538
// // Node 9 is between nodes 1 and 3
539
// case 9:
540
541
// edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(1);
542
// edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(3);
543
// break;
544
545
// break;
546
547
// //Error
548
// default:
549
550
// throw OomphLibError("More than ten edge nodes in Tet Element",
551
// OOMPH_CURRENT_FUNCTION,
552
// OOMPH_EXCEPTION_LOCATION);
553
// }
554
555
// // Do we need a boundary node?
556
// bool need_boundary_node=false;
557
558
// // hierher At some point fine tune via intersection of boundary
559
// sets if
560
// (edge_node1_pt->is_on_boundary()&&edge_node2_pt->is_on_boundary())
561
// {
562
// need_boundary_node=true;
563
// }
564
565
// // Do we need a new node?
566
// if (central_edge_node_pt(edge_node1_pt,edge_node2_pt)==0)
567
// {
568
// Node* new_node_pt=0;
569
570
// // Create new boundary node
571
// if (need_boundary_node)
572
// {
573
// new_node_pt=finite_element_pt(e)->
574
// construct_boundary_node(j,time_stepper_pt);
575
// }
576
// // Create new normal node
577
// else
578
// {
579
// new_node_pt=finite_element_pt(e)->
580
// construct_node(j,time_stepper_pt);
581
// }
582
// Node_pt.push_back(new_node_pt);
583
584
// // Now indicate existence of newly created mideside node in map
585
// central_edge_node_pt(edge_node1_pt,edge_node2_pt)=new_node_pt;
586
// central_edge_node_pt(edge_node2_pt,edge_node1_pt)=new_node_pt;
587
588
// // What are the node's local coordinates?
589
// finite_element_pt(e)->local_coordinate_of_node(j,s);
590
591
// // Find the coordinates of the new node from the existing
592
// // and fully-functional element in the scaffold mesh
593
// for(unsigned i=0;i<dim;i++)
594
// {
595
// new_node_pt->x(i)=
596
// Tmp_mesh_pt->finite_element_pt(e)->interpolated_x(s,i);
597
// }
598
// }
599
// else
600
// {
601
// // Set pointer to the existing node
602
// finite_element_pt(e)->node_pt(j)=
603
// central_edge_node_pt(edge_node1_pt,edge_node2_pt);
604
// }
605
606
// } // end of loop over new nodes
607
608
// //Need to sort out the face nodes
609
// if(n_node==15)
610
// {
611
// // Loop over the new (face) nodes in the element and create them.
612
// for(unsigned j=10;j<14;j++)
613
// {
614
// //Empty the set of face nodes
615
// face_nodes_pt.clear();
616
// // Figure out face nodes
617
// switch(j)
618
// {
619
620
// // Node 10 is between nodes 0 and 1 and 3
621
// case 10:
622
623
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(0));
624
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(1));
625
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(3));
626
// break;
627
628
// // Node 11 is between nodes 0 and 1 and 2
629
// case 11:
630
631
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(0));
632
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(1));
633
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(2));
634
// break;
635
636
// // Node 12 is between nodes 0 and 2 and 3
637
// case 12:
638
639
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(0));
640
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(2));
641
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(3));
642
// break;
643
644
// // Node 13 is between nodes 1 and 2 and 3
645
// case 13:
646
647
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(1));
648
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(2));
649
// face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(3));
650
// break;
651
652
// //Error
653
// default:
654
655
// throw OomphLibError("More than four face nodes in Tet Element",
656
// OOMPH_CURRENT_FUNCTION,
657
// OOMPH_EXCEPTION_LOCATION);
658
// }
659
660
// // Do we need a boundary node?
661
// bool need_boundary_node=false;
662
663
// //Work it out from the face boundary
664
// boundary_id = Tmp_mesh_pt->face_boundary(e,face_map[j-10]);
665
// //If it's non-zero then we do need to create a boundary node
666
// if(boundary_id!=0) {need_boundary_node=true;}
667
668
// // Do we need a new node?
669
// if (central_face_node_pt[face_nodes_pt]==0)
670
// {
671
// Node* new_node_pt=0;
672
673
// // Create a new boundary node
674
// if (need_boundary_node)
675
// {
676
// new_node_pt=finite_element_pt(e)->
677
// construct_boundary_node(j,time_stepper_pt);
678
// //Add it to the boundary
679
// add_boundary_node(boundary_id-1,new_node_pt);
680
// }
681
// // Create new normal node
682
// else
683
// {
684
// new_node_pt=finite_element_pt(e)->
685
// construct_node(j,time_stepper_pt);
686
// }
687
// Node_pt.push_back(new_node_pt);
688
689
// // Now indicate existence of newly created mideside node in map
690
// central_face_node_pt[face_nodes_pt]=new_node_pt;
691
692
// // What are the node's local coordinates?
693
// finite_element_pt(e)->local_coordinate_of_node(j,s);
694
695
// // Find the coordinates of the new node from the existing
696
// // and fully-functional element in the scaffold mesh
697
// for(unsigned i=0;i<dim;i++)
698
// {
699
// new_node_pt->x(i)=
700
// Tmp_mesh_pt->finite_element_pt(e)->interpolated_x(s,i);
701
// }
702
// }
703
// else
704
// {
705
// // Set pointer to the existing node
706
// finite_element_pt(e)->node_pt(j)=
707
// central_face_node_pt[face_nodes_pt];
708
// }
709
// } //End of loop over face nodes
710
711
// //Construct the element's central node, which is not on a boundary
712
// {
713
// Node* new_node_pt=
714
// finite_element_pt(e)->construct_node(14,time_stepper_pt);
715
// Node_pt.push_back(new_node_pt);
716
717
// // What are the node's local coordinates?
718
// finite_element_pt(e)->local_coordinate_of_node(14,s);
719
// // Find the coordinates of the new node from the existing
720
// // and fully-functional element in the scaffold mesh
721
// for(unsigned i=0;i<dim;i++)
722
// {
723
// new_node_pt->x(i)=
724
// Tmp_mesh_pt->finite_element_pt(e)->interpolated_x(s,i);
725
// }
726
// }
727
// } //End of enriched case
728
729
// } //end of loop over elements
730
731
// //Boundary conditions
732
733
// // Matrix map to check if a node has already been added to
734
// // the boundary number b
735
// MapMatrixMixed<Node*,unsigned,bool> bound_node_done;
736
737
// // Loop over elements
738
// for (unsigned e=0;e<nelem;e++)
739
// {
740
// // Loop over new local nodes
741
// for(unsigned j=4;j<n_node;j++)
742
// {
743
// // Pointer to the element's local node
744
// Node* loc_node_pt=finite_element_pt(e)->node_pt(j);
745
746
// // This will have to be changed for higher-order elements
747
// //=======================================================
748
749
// // These are the face nodes on the element's face 0:
750
// if ( (j==4) || (j==5) || (j==7) )
751
// {
752
// boundary_id=Tmp_mesh_pt->face_boundary(e,0);
753
// if (boundary_id!=0)
754
// {
755
// if (!bound_node_done(loc_node_pt,boundary_id-1))
756
// {
757
// add_boundary_node(boundary_id-1,loc_node_pt);
758
// bound_node_done(loc_node_pt,boundary_id-1)=true;
759
// }
760
// }
761
// }
762
763
// // These are the face nodes on the element's face 1:
764
// if ( (j==4) || (j==6) || (j==9) )
765
// {
766
// boundary_id=Tmp_mesh_pt->face_boundary(e,1);
767
// if (boundary_id!=0)
768
// {
769
// if (!bound_node_done(loc_node_pt,boundary_id-1))
770
// {
771
// add_boundary_node(boundary_id-1,loc_node_pt);
772
// bound_node_done(loc_node_pt,boundary_id-1)=true;
773
// }
774
// }
775
// }
776
777
// // These are the face nodes on the element's face 2:
778
// if ( (j==5) || (j==6) || (j==8) )
779
// {
780
// boundary_id=Tmp_mesh_pt->face_boundary(e,2);
781
// if (boundary_id!=0)
782
// {
783
// if (!bound_node_done(loc_node_pt,boundary_id-1))
784
// {
785
// add_boundary_node(boundary_id-1,loc_node_pt);
786
// bound_node_done(loc_node_pt,boundary_id-1)=true;
787
// }
788
// }
789
// }
790
791
// // These are the face nodes on the element's face 3:
792
// if ( (j==7) || (j==8) || (j==9) )
793
// {
794
// boundary_id=Tmp_mesh_pt->face_boundary(e,3);
795
// if (boundary_id!=0)
796
// {
797
// if (!bound_node_done(loc_node_pt,boundary_id-1))
798
// {
799
// add_boundary_node(boundary_id-1,loc_node_pt);
800
// bound_node_done(loc_node_pt,boundary_id-1)=true;
801
// }
802
// }
803
// }
804
805
// } //end for j
806
807
// */
808
809
}
// end for e
810
811
}
// end function
812
813
//=====================================================================
814
/// Helper function to set up the reverse look up scheme for facets.
815
/// This is used to set up boundary coordinates.
816
//=====================================================================
817
template
<
class
ELEMENT>
818
void
TetgenMesh<ELEMENT>::setup_reverse_lookup_schemes_for_faceted_surface
(
819
TetMeshFacetedSurface
*
const
&
faceted_surface_pt
)
820
{
821
// Set up reverse lookup scheme for a given faceted surface
822
// Assumption is that there there is one boundary ID per facet.
823
unsigned
n_facet
=
faceted_surface_pt
->nfacet();
824
for
(
unsigned
f
= 0;
f
<
n_facet
;
f
++)
825
{
826
unsigned
b
=
faceted_surface_pt
->one_based_facet_boundary_id(
f
);
827
if
(
b
!= 0)
828
{
829
this->
Tet_mesh_faceted_surface_pt
[
b
- 1] =
faceted_surface_pt
;
830
this->
Tet_mesh_facet_pt
[
b
- 1] =
faceted_surface_pt
->facet_pt(
f
);
831
}
832
else
833
{
834
std::ostringstream
error_message
;
835
error_message
<<
"Boundary IDs have to be one-based. Yours is "
<<
b
836
<<
"\n"
;
837
throw
OomphLibError
(
error_message
.str(),
838
OOMPH_CURRENT_FUNCTION
,
839
OOMPH_EXCEPTION_LOCATION
);
840
}
841
}
842
}
843
844
845
///////////////////////////////////////////////////////////////////////
846
///////////////////////////////////////////////////////////////////////
847
///////////////////////////////////////////////////////////////////////
848
849
//=========================================================================
850
/// Transfer tetgenio data from the input to the output
851
/// The output is assumed to have been constructed and "empty"
852
//=========================================================================
853
template
<
class
ELEMENT>
854
void
TetgenMesh<ELEMENT>::deep_copy_of_tetgenio
(
tetgenio
*
const
&
input_pt
,
855
tetgenio
*&
output_pt
)
856
{
857
// Copy data values
858
output_pt
->firstnumber =
input_pt
->firstnumber;
859
output_pt
->mesh_dim =
input_pt
->mesh_dim;
860
output_pt
->useindex =
input_pt
->useindex;
861
862
// Copy the number of points
863
output_pt
->numberofpoints =
input_pt
->numberofpoints;
864
output_pt
->numberofpointattributes =
input_pt
->numberofpointattributes;
865
output_pt
->numberofpointmtrs =
input_pt
->numberofpointmtrs;
866
867
const
int
n_point
=
output_pt
->numberofpoints;
868
if
(
n_point
> 0)
869
{
870
output_pt
->pointlist =
new
double
[
n_point
* 3];
871
// Copy the values
872
for
(
int
n
= 0;
n
< (
n_point
* 3); ++
n
)
873
{
874
output_pt
->pointlist[
n
] =
input_pt
->pointlist[
n
];
875
}
876
877
// If there are point markers copy as well
878
if
(
input_pt
->pointmarkerlist != (
int
*)
NULL
)
879
{
880
output_pt
->pointmarkerlist =
new
int
[
n_point
];
881
for
(
int
n
= 0;
n
<
n_point
; ++
n
)
882
{
883
output_pt
->pointmarkerlist[
n
] =
input_pt
->pointmarkerlist[
n
];
884
}
885
}
886
887
const
int
n_attr
=
output_pt
->numberofpointattributes;
888
if
(
n_attr
> 0)
889
{
890
output_pt
->pointattributelist =
new
double
[
n_point
*
n_attr
];
891
for
(
int
n
= 0;
n
< (
n_point
*
n_attr
); ++
n
)
892
{
893
output_pt
->pointattributelist[
n
] =
input_pt
->pointattributelist[
n
];
894
}
895
}
896
}
// End of point case
897
898
// Now add in metric tensors (if there are any)
899
const
int
n_point_mtr
=
output_pt
->numberofpointmtrs;
900
if
(
n_point_mtr
> 0)
901
{
902
output_pt
->pointmtrlist =
new
double
[
n_point
*
n_point_mtr
];
903
for
(
int
n
= 0;
n
< (
n_point
*
n_point_mtr
); ++
n
)
904
{
905
output_pt
->pointmtrlist[
n
] =
input_pt
->pointmtrlist[
n
];
906
}
907
}
908
909
// Next tetrahedrons
910
output_pt
->numberoftetrahedra =
input_pt
->numberoftetrahedra;
911
output_pt
->numberofcorners =
input_pt
->numberofcorners;
912
output_pt
->numberoftetrahedronattributes =
913
input_pt
->numberoftetrahedronattributes;
914
915
const
int
n_tetra
=
output_pt
->numberoftetrahedra;
916
const
int
n_corner
=
output_pt
->numberofcorners;
917
if
(
n_tetra
> 0)
918
{
919
output_pt
->tetrahedronlist =
new
int
[
n_tetra
*
n_corner
];
920
for
(
int
n
= 0;
n
< (
n_tetra
*
n_corner
); ++
n
)
921
{
922
output_pt
->tetrahedronlist[
n
] =
input_pt
->tetrahedronlist[
n
];
923
}
924
925
// Add in the volume constriants
926
if
(
input_pt
->tetrahedronvolumelist != (
double
*)
NULL
)
927
{
928
output_pt
->tetrahedronvolumelist =
new
double
[
n_tetra
];
929
for
(
int
n
= 0;
n
<
n_tetra
; ++
n
)
930
{
931
output_pt
->tetrahedronvolumelist[
n
] =
932
input_pt
->tetrahedronvolumelist[
n
];
933
}
934
}
935
936
// Add in the attributes
937
const
int
n_tetra_attr
=
output_pt
->numberoftetrahedronattributes;
938
if
(
n_tetra_attr
> 0)
939
{
940
output_pt
->tetrahedronattributelist =
941
new
double
[
n_tetra
*
n_tetra_attr
];
942
for
(
int
n
= 0;
n
< (
n_tetra
*
n_tetra_attr
); ++
n
)
943
{
944
output_pt
->tetrahedronattributelist[
n
] =
945
input_pt
->tetrahedronattributelist[
n
];
946
}
947
}
948
949
// Add in the neighbour list
950
if
(
input_pt
->neighborlist != (
int
*)
NULL
)
951
{
952
output_pt
->neighborlist =
new
int
[
n_tetra
* 4];
953
for
(
int
n
= 0;
n
< (
n_tetra
* 4); ++
n
)
954
{
955
output_pt
->neighborlist =
input_pt
->neighborlist;
956
}
957
}
958
}
// End of tetrahedron section
959
960
// Now arrange the facet list
961
output_pt
->numberoffacets =
input_pt
->numberoffacets;
962
const
int
n_facet
=
output_pt
->numberoffacets;
963
if
(
n_facet
> 0)
964
{
965
output_pt
->facetlist =
new
tetgenio::facet[
n_facet
];
966
for
(
int
n
= 0;
n
<
n_facet
; ++
n
)
967
{
968
tetgenio::facet*
input_f_pt
= &
input_pt
->facetlist[
n
];
969
tetgenio::facet*
output_f_pt
= &
output_pt
->facetlist[
n
];
970
971
// Copy polygons and holes from the facets
972
output_f_pt
->numberofpolygons =
input_f_pt
->numberofpolygons;
973
974
// Loop over polygons
975
const
int
n_poly
=
output_f_pt
->numberofpolygons;
976
if
(
n_poly
> 0)
977
{
978
output_f_pt
->polygonlist =
new
tetgenio::polygon[
n_poly
];
979
for
(
int
p
= 0;
p
<
n_poly
; ++
p
)
980
{
981
tetgenio::polygon*
output_p_pt
= &
output_f_pt
->polygonlist[
p
];
982
tetgenio::polygon*
input_p_pt
= &
input_f_pt
->polygonlist[
p
];
983
// Find out how many vertices each polygon has
984
output_p_pt
->numberofvertices =
input_p_pt
->numberofvertices;
985
// Now copy of the vertices
986
const
int
n_vertex
=
output_p_pt
->numberofvertices;
987
if
(
n_vertex
> 0)
988
{
989
output_p_pt
->vertexlist =
new
int
[
n_vertex
];
990
for
(
int
v
= 0;
v
<
n_vertex
; ++
v
)
991
{
992
output_p_pt
->vertexlist[
v
] =
input_p_pt
->vertexlist[
v
];
993
}
994
}
995
}
996
}
997
998
// Hole information
999
output_f_pt
->numberofholes =
input_f_pt
->numberofholes;
1000
const
int
n_hole
=
output_f_pt
->numberofholes;
1001
if
(
n_hole
> 0)
1002
{
1003
throw
OomphLibError
(
"Don't know how to handle holes yet\n"
,
1004
OOMPH_CURRENT_FUNCTION
,
1005
OOMPH_EXCEPTION_LOCATION
);
1006
}
1007
}
// end of loop over facets
1008
1009
// Add the facetmarkers if there are any
1010
if
(
input_pt
->facetmarkerlist != (
int
*)
NULL
)
1011
{
1012
output_pt
->facetmarkerlist =
new
int
[
n_facet
];
1013
for
(
int
n
= 0;
n
<
n_facet
; ++
n
)
1014
{
1015
output_pt
->facetmarkerlist[
n
] =
input_pt
->facetmarkerlist[
n
];
1016
}
1017
}
1018
}
1019
1020
// Now the holes
1021
output_pt
->numberofholes =
input_pt
->numberofholes;
1022
const
int
n_hole
=
output_pt
->numberofholes;
1023
if
(
n_hole
> 0)
1024
{
1025
output_pt
->holelist =
new
double
[
n_hole
* 3];
1026
for
(
int
n
= 0;
n
< (
n_hole
* 3); ++
n
)
1027
{
1028
output_pt
->holelist[
n
] =
input_pt
->holelist[
n
];
1029
}
1030
}
1031
1032
// Now the regions
1033
output_pt
->numberofregions =
input_pt
->numberofregions;
1034
const
int
n_region
=
output_pt
->numberofregions;
1035
if
(
n_region
> 0)
1036
{
1037
output_pt
->regionlist =
new
double
[
n_region
* 5];
1038
for
(
int
n
= 0;
n
< (
n_region
* 5); ++
n
)
1039
{
1040
output_pt
->regionlist[
n
] =
input_pt
->regionlist[
n
];
1041
}
1042
}
1043
1044
// Now the facet constraints
1045
output_pt
->numberoffacetconstraints =
input_pt
->numberoffacetconstraints;
1046
const
int
n_facet_const
=
output_pt
->numberoffacetconstraints;
1047
if
(
n_facet_const
> 0)
1048
{
1049
output_pt
->facetconstraintlist =
new
double
[
n_facet_const
* 2];
1050
for
(
int
n
= 0;
n
< (
n_facet_const
* 2); ++
n
)
1051
{
1052
output_pt
->facetconstraintlist[
n
] =
input_pt
->facetconstraintlist[
n
];
1053
}
1054
}
1055
1056
// Now the segment constraints
1057
output_pt
->numberofsegmentconstraints =
1058
input_pt
->numberofsegmentconstraints;
1059
const
int
n_seg_const
=
output_pt
->numberofsegmentconstraints;
1060
if
(
n_seg_const
> 0)
1061
{
1062
output_pt
->segmentconstraintlist =
new
double
[
n_seg_const
* 2];
1063
for
(
int
n
= 0;
n
< (
n_seg_const
* 2); ++
n
)
1064
{
1065
output_pt
->segmentconstraintlist[
n
] =
1066
input_pt
->segmentconstraintlist[
n
];
1067
}
1068
}
1069
1070
// Now the face list
1071
output_pt
->numberoftrifaces =
input_pt
->numberoftrifaces;
1072
const
int
n_tri_face
=
output_pt
->numberoftrifaces;
1073
if
(
n_tri_face
> 0)
1074
{
1075
output_pt
->trifacelist =
new
int
[
n_tri_face
* 3];
1076
for
(
int
n
= 0;
n
< (
n_tri_face
* 3); ++
n
)
1077
{
1078
output_pt
->trifacelist[
n
] =
input_pt
->trifacelist[
n
];
1079
}
1080
1081
output_pt
->trifacemarkerlist =
new
int
[
n_tri_face
];
1082
for
(
int
n
= 0;
n
<
n_tri_face
; ++
n
)
1083
{
1084
output_pt
->trifacemarkerlist[
n
] =
input_pt
->trifacemarkerlist[
n
];
1085
}
1086
}
1087
1088
// Now the edge list
1089
output_pt
->numberofedges =
input_pt
->numberofedges;
1090
const
int
n_edge
=
output_pt
->numberofedges;
1091
if
(
n_edge
> 0)
1092
{
1093
output_pt
->edgelist =
new
int
[
n_edge
* 2];
1094
for
(
int
n
= 0;
n
< (
n_edge
* 2); ++
n
)
1095
{
1096
output_pt
->edgelist[
n
] =
input_pt
->edgelist[
n
];
1097
}
1098
1099
output_pt
->edgemarkerlist =
new
int
[
n_edge
];
1100
for
(
int
n
= 0;
n
<
n_edge
; ++
n
)
1101
{
1102
output_pt
->edgemarkerlist[
n
] =
input_pt
->edgemarkerlist[
n
];
1103
}
1104
}
1105
}
1106
1107
}
// namespace oomph
1108
#endif
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition
triangle_mesh.h:2225
oomph::TetgenMesh::build_from_scaffold
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
Definition
tetgen_mesh.template.cc:48
oomph::TetgenMesh::setup_reverse_lookup_schemes_for_faceted_surface
void setup_reverse_lookup_schemes_for_faceted_surface(TetMeshFacetedSurface *const &faceted_surface_pt)
Function to setup the reverse look-up schemes.
Definition
tetgen_mesh.template.cc:818
oomph::TetgenMesh::deep_copy_of_tetgenio
void deep_copy_of_tetgenio(tetgenio *const &input_pt, tetgenio *&output_pt)
Transfer tetgenio data from the input to the output The output is assumed to have been constructed an...
Definition
tetgen_mesh.template.cc:854
oomph::TriangleMesh::Tmp_mesh_pt
TriangleScaffoldMesh * Tmp_mesh_pt
Temporary scaffold mesh.
Definition
triangle_mesh.h:1334
oomph
Definition
annular_domain.h:35