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
simple_cubic_tet_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_SIMPLE_CUBIC_TET_MESH_TEMPLATE_HEADER
27
#define OOMPH_SIMPLE_CUBIC_TET_MESH_TEMPLATE_HEADER
28
29
#ifndef OOMPH_SIMPLE_CUBIC_TET_MESH_HEADER
30
#error __FILE__ should only be included from simple_cubic_tet_mesh.h.
31
#endif
// OOMPH_SIMPLE_CUBIC_TET_MESH_HEADER
32
33
#include <algorithm>
34
35
// Simple 3D tetrahedral mesh class
36
37
#include "generic/map_matrix.h"
38
#include <algorithm>
39
40
namespace
oomph
41
{
42
//====================================================================
43
/// Simple tetrahedral mesh - with 24 tet elements constructed within a
44
/// "brick" form for each element block.
45
//====================================================================
46
template
<
class
ELEMENT>
47
void
SimpleCubicTetMesh<ELEMENT>::build_from_scaffold
(
48
TimeStepper
*
time_stepper_pt
)
49
{
50
// Mesh can only be built with 3D Telements.
51
MeshChecker::assert_geometric_element<TElementGeometricBase, ELEMENT>(3);
52
53
// Create space for elements
54
unsigned
nelem
=
Tmp_mesh_pt
->nelement();
55
Element_pt
.resize(
nelem
);
56
57
// Create space for nodes
58
unsigned
nnode_scaffold
=
Tmp_mesh_pt
->nnode();
59
Node_pt
.resize(
nnode_scaffold
);
60
61
// Set number of boundaries
62
unsigned
nbound
=
Tmp_mesh_pt
->nboundary();
63
set_nboundary
(
nbound
);
64
65
// Loop over elements in scaffold mesh, visit their nodes
66
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
67
{
68
Element_pt
[
e
] =
new
ELEMENT
;
69
}
70
71
// In the first instance build all nodes from within all the elements
72
unsigned
nnod_el
=
Tmp_mesh_pt
->finite_element_pt(0)->nnode();
73
// Loop over elements in scaffold mesh, visit their nodes
74
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
75
{
76
// Loop over all nodes in element
77
for
(
unsigned
j
= 0;
j
<
nnod_el
;
j
++)
78
{
79
// Create new node, using the NEW element's construct_node
80
// member function
81
finite_element_pt
(
e
)->construct_node(
j
,
time_stepper_pt
);
82
}
83
}
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
// Loop over elements in scaffold mesh, visit their nodes
91
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
92
{
93
// Loop over all nodes in element
94
for
(
unsigned
j
= 0;
j
<
nnod_el
;
j
++)
95
{
96
// Pointer to node in the scaffold mesh
97
Node
*
scaffold_node_pt
=
Tmp_mesh_pt
->finite_element_pt(
e
)->node_pt(
j
);
98
99
// Get the (pseudo-)global node number in scaffold mesh
100
// (It's zero [=default] if not visited this one yet)
101
unsigned
j_global
=
global_number
[
scaffold_node_pt
];
102
103
// Haven't done this one yet
104
if
(
j_global
== 0)
105
{
106
// Give it a number (not necessarily the global node
107
// number in the scaffold mesh -- we just need something
108
// to keep track...)
109
global_count
++;
110
global_number
[
scaffold_node_pt
] =
global_count
;
111
112
// Copy new node, created using the NEW element's construct_node
113
// function into global storage, using the same global
114
// node number that we've just associated with the
115
// corresponding node in the scaffold mesh
116
Node_pt
[
global_count
- 1] =
finite_element_pt
(
e
)->node_pt(
j
);
117
118
// Assign coordinates
119
Node_pt
[
global_count
- 1]->x(0) =
scaffold_node_pt
->x(0);
120
Node_pt
[
global_count
- 1]->x(1) =
scaffold_node_pt
->x(1);
121
Node_pt
[
global_count
- 1]->x(2) =
scaffold_node_pt
->x(2);
122
123
// Get pointer to set of mesh boundaries that this
124
// scaffold node occupies; NULL if the node is not on any boundary
125
std::set<unsigned>*
boundaries_pt
;
126
scaffold_node_pt
->get_boundaries_pt(
boundaries_pt
);
127
128
// Loop over the mesh boundaries that the node in the scaffold mesh
129
// occupies and assign new node to the same ones.
130
if
(
boundaries_pt
!= 0)
131
{
132
this->
convert_to_boundary_node
(
Node_pt
[
global_count
- 1]);
133
for
(std::set<unsigned>::iterator
it
=
boundaries_pt
->begin();
134
it
!=
boundaries_pt
->end();
135
++
it
)
136
{
137
add_boundary_node
(*
it
,
Node_pt
[
global_count
- 1]);
138
}
139
}
140
}
141
// This one has already been done: Kill it
142
else
143
{
144
// Kill it
145
delete
finite_element_pt
(
e
)->node_pt(
j
);
146
147
// Overwrite the element's pointer to local node by
148
// pointer to the already existing node -- identified by
149
// the number kept in the map
150
finite_element_pt
(
e
)->node_pt(
j
) =
Node_pt
[
j_global
- 1];
151
}
152
}
153
}
154
155
// At this point we've created all the elements and
156
// created their vertex nodes. Now we need to create
157
// the additional (midside and internal) nodes!
158
159
// We'll first create all local nodes for all elements
160
// and then delete the superfluous ones that have
161
// a matching node in an adjacent element.
162
163
// Get number of nodes along element edge and dimension of element (3)
164
// from first element
165
unsigned
nnode_1d
=
finite_element_pt
(0)->nnode_1d();
166
167
// At the moment we're only able to deal with nnode_1d=2 or 3.
168
if
((
nnode_1d
!= 2) && (
nnode_1d
!= 3))
169
{
170
std::ostringstream
error_message
;
171
error_message
<<
"Mesh generation currently only works\n"
;
172
error_message
<<
"for nnode_1d = 2 or 3. You're trying to use it\n"
;
173
error_message
<<
"for nnode_1d="
<<
nnode_1d
<< std::endl;
174
175
throw
OomphLibError
(
176
error_message
.str(),
OOMPH_CURRENT_FUNCTION
,
OOMPH_EXCEPTION_LOCATION
);
177
}
178
179
// Spatial dimension of element = number of local coordinates
180
unsigned
dim
=
finite_element_pt
(0)->dim();
181
182
// Storage for the local coordinate of the new node
183
Vector<double>
s
(
dim
);
184
185
// Get number of nodes in the element from first element
186
unsigned
nnode
=
finite_element_pt
(0)->nnode();
187
188
// Loop over all elements
189
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
190
{
191
// Loop over the new nodes in the element and create them.
192
for
(
unsigned
j
= 4;
j
<
nnode
;
j
++)
193
{
194
// Create new node
195
Node
*
new_node_pt
=
196
finite_element_pt
(
e
)->construct_node(
j
,
time_stepper_pt
);
197
198
// What are the node's local coordinates?
199
finite_element_pt
(
e
)->local_coordinate_of_node(
j
,
s
);
200
201
// Find the coordinates of the new node from the existing
202
// and fully-functional element in the scaffold mesh
203
for
(
unsigned
i
= 0;
i
<
dim
;
i
++)
204
{
205
new_node_pt
->x(
i
) =
206
Tmp_mesh_pt
->finite_element_pt(
e
)->interpolated_x(
s
,
i
);
207
}
208
}
// end of loop over new nodes
209
}
// end of loop over elements
210
211
// Bracket this away so the edge map goes out of scope
212
// when we're done
213
{
214
// Storage for pointer to mid-edge node
215
MapMatrix<Node*, Node*>
central_edge_node_pt
;
216
Node
*
edge_node1_pt
= 0;
217
Node
*
edge_node2_pt
= 0;
218
219
// Loop over elements
220
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
221
{
222
// Loop over new local nodes
223
for
(
unsigned
j
= 4;
j
<
nnode
;
j
++)
224
{
225
// Pointer to the element's local node
226
Node
*
node_pt
=
finite_element_pt
(
e
)->node_pt(
j
);
227
228
// By default, we assume the node is not new
229
bool
is_new
=
false
;
230
231
// This will have to be changed for higher-order elements
232
//=======================================================
233
234
// Switch on local node number (all located on edges)
235
switch
(
j
)
236
{
237
// Node 4 is located between nodes 0 and 1
238
case
4:
239
240
edge_node1_pt
=
finite_element_pt
(
e
)->node_pt(0);
241
edge_node2_pt
=
finite_element_pt
(
e
)->node_pt(1);
242
if
(
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) == 0)
243
{
244
is_new
=
true
;
245
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) =
node_pt
;
246
central_edge_node_pt
(
edge_node2_pt
,
edge_node1_pt
) =
node_pt
;
247
}
248
break
;
249
250
// Node 5 is located between nodes 0 and 2
251
case
5:
252
253
edge_node1_pt
=
finite_element_pt
(
e
)->node_pt(0);
254
edge_node2_pt
=
finite_element_pt
(
e
)->node_pt(2);
255
if
(
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) == 0)
256
{
257
is_new
=
true
;
258
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) =
node_pt
;
259
central_edge_node_pt
(
edge_node2_pt
,
edge_node1_pt
) =
node_pt
;
260
}
261
break
;
262
263
// Node 6 is located between nodes 0 and 3
264
case
6:
265
266
edge_node1_pt
=
finite_element_pt
(
e
)->node_pt(0);
267
edge_node2_pt
=
finite_element_pt
(
e
)->node_pt(3);
268
if
(
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) == 0)
269
{
270
is_new
=
true
;
271
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) =
node_pt
;
272
central_edge_node_pt
(
edge_node2_pt
,
edge_node1_pt
) =
node_pt
;
273
}
274
break
;
275
276
// Node 7 is located between nodes 1 and 2
277
case
7:
278
279
edge_node1_pt
=
finite_element_pt
(
e
)->node_pt(1);
280
edge_node2_pt
=
finite_element_pt
(
e
)->node_pt(2);
281
if
(
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) == 0)
282
{
283
is_new
=
true
;
284
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) =
node_pt
;
285
central_edge_node_pt
(
edge_node2_pt
,
edge_node1_pt
) =
node_pt
;
286
}
287
break
;
288
289
// Node 8 is located between nodes 2 and 3
290
case
8:
291
292
edge_node1_pt
=
finite_element_pt
(
e
)->node_pt(2);
293
edge_node2_pt
=
finite_element_pt
(
e
)->node_pt(3);
294
if
(
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) == 0)
295
{
296
is_new
=
true
;
297
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) =
node_pt
;
298
central_edge_node_pt
(
edge_node2_pt
,
edge_node1_pt
) =
node_pt
;
299
}
300
break
;
301
302
// Node 9 is located between nodes 1 and 3
303
case
9:
304
305
edge_node1_pt
=
finite_element_pt
(
e
)->node_pt(1);
306
edge_node2_pt
=
finite_element_pt
(
e
)->node_pt(3);
307
if
(
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) == 0)
308
{
309
is_new
=
true
;
310
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
) =
node_pt
;
311
central_edge_node_pt
(
edge_node2_pt
,
edge_node1_pt
) =
node_pt
;
312
}
313
break
;
314
315
default
:
316
throw
OomphLibError
(
"More than ten nodes in Tet Element"
,
317
OOMPH_CURRENT_FUNCTION
,
318
OOMPH_EXCEPTION_LOCATION
);
319
}
320
321
if
(
is_new
)
322
{
323
// New node: Add it to mesh
324
Node_pt
.push_back(
node_pt
);
325
}
326
else
327
{
328
// Delete local node in element...
329
delete
finite_element_pt
(
e
)->node_pt(
j
);
330
331
// ... and reset pointer to the existing node
332
finite_element_pt
(
e
)->node_pt(
j
) =
333
central_edge_node_pt
(
edge_node1_pt
,
edge_node2_pt
);
334
}
335
}
336
}
337
}
338
339
// Boundary conditions
340
341
// Matrix map to check if a node has already been added to
342
// the boundary number b (NOTE: Enumerated by pointer to ORIGINAL
343
// node before transfer to boundary node)
344
MapMatrixMixed<Node*, unsigned, bool>
bound_node_done
;
345
346
// Create lookup scheme for pointers to original local nodes
347
// in elements
348
Vector<Vector<Node*>
>
orig_node_pt
(
nelem
);
349
350
// Loop over elements
351
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
352
{
353
orig_node_pt
[
e
].resize(
nnode
, 0);
354
355
// Loop over new local nodes
356
for
(
unsigned
j
= 4;
j
<
nnode
;
j
++)
357
{
358
// Pointer to the element's local node
359
orig_node_pt
[
e
][
j
] =
finite_element_pt
(
e
)->node_pt(
j
);
360
}
361
}
362
363
// Loop over elements
364
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
365
{
366
// Loop over new local nodes
367
for
(
unsigned
j
= 4;
j
<
nnode
;
j
++)
368
{
369
// Loop over the boundaries
370
for
(
unsigned
bo
= 0;
bo
<
nbound
;
bo
++)
371
{
372
// Pointer to the element's local node
373
Node
*
loc_node_pt
=
finite_element_pt
(
e
)->node_pt(
j
);
374
375
// Pointer to original node
376
Node
*
orig_loc_node_pt
=
orig_node_pt
[
e
][
j
];
377
378
// value of the map for the node and boundary specified
379
bool
bound_test
=
bound_node_done
(
orig_loc_node_pt
,
bo
);
380
381
if
(
bound_test
==
false
)
382
{
383
bound_node_done
(
orig_loc_node_pt
,
bo
) =
true
;
384
385
// This will have to be changed for higher-order elements
386
//=======================================================
387
388
// Switch on local node number (all located on edges)
389
switch
(
j
)
390
{
391
// Node 4 is located between nodes 0 and 1
392
case
4:
393
394
if
(
finite_element_pt
(
e
)->
node_pt
(0)->
is_on_boundary
(
bo
) &&
395
finite_element_pt
(
e
)->
node_pt
(1)->
is_on_boundary
(
bo
))
396
{
397
this->
convert_to_boundary_node
(
loc_node_pt
);
398
add_boundary_node
(
bo
,
loc_node_pt
);
399
}
400
break
;
401
402
// Node 5 is located between nodes 0 and 2
403
case
5:
404
405
if
(
finite_element_pt
(
e
)->
node_pt
(0)->
is_on_boundary
(
bo
) &&
406
finite_element_pt
(
e
)->
node_pt
(2)->
is_on_boundary
(
bo
))
407
{
408
this->
convert_to_boundary_node
(
loc_node_pt
);
409
add_boundary_node
(
bo
,
loc_node_pt
);
410
}
411
break
;
412
413
// Node 6 is located between nodes 0 and 3
414
case
6:
415
416
if
(
finite_element_pt
(
e
)->
node_pt
(0)->
is_on_boundary
(
bo
) &&
417
finite_element_pt
(
e
)->
node_pt
(3)->
is_on_boundary
(
bo
))
418
{
419
this->
convert_to_boundary_node
(
loc_node_pt
);
420
add_boundary_node
(
bo
,
loc_node_pt
);
421
}
422
break
;
423
424
// Node 7 is located between nodes 1 and 2
425
case
7:
426
427
if
(
finite_element_pt
(
e
)->
node_pt
(1)->
is_on_boundary
(
bo
) &&
428
finite_element_pt
(
e
)->
node_pt
(2)->
is_on_boundary
(
bo
))
429
{
430
this->
convert_to_boundary_node
(
loc_node_pt
);
431
add_boundary_node
(
bo
,
loc_node_pt
);
432
}
433
break
;
434
435
// Node 8 is located between nodes 2 and 3
436
case
8:
437
438
if
(
finite_element_pt
(
e
)->
node_pt
(2)->
is_on_boundary
(
bo
) &&
439
finite_element_pt
(
e
)->
node_pt
(3)->
is_on_boundary
(
bo
))
440
{
441
this->
convert_to_boundary_node
(
loc_node_pt
);
442
add_boundary_node
(
bo
,
loc_node_pt
);
443
}
444
break
;
445
446
// Node 9 is located between nodes 1 and 3
447
case
9:
448
449
if
(
finite_element_pt
(
e
)->
node_pt
(1)->
is_on_boundary
(
bo
) &&
450
finite_element_pt
(
e
)->
node_pt
(3)->
is_on_boundary
(
bo
))
451
{
452
this->
convert_to_boundary_node
(
loc_node_pt
);
453
add_boundary_node
(
bo
,
loc_node_pt
);
454
}
455
break
;
456
457
default
:
458
throw
OomphLibError
(
"More than ten nodes in Tet Element"
,
459
OOMPH_CURRENT_FUNCTION
,
460
OOMPH_EXCEPTION_LOCATION
);
461
}
462
}
463
464
}
// end for bo
465
}
// end for j
466
}
// end for e
467
}
468
469
}
// namespace oomph
470
471
#endif
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition
triangle_mesh.h:2225
oomph::SimpleCubicTetMesh::build_from_scaffold
void build_from_scaffold(TimeStepper *time_stepper_pt)
Build mesh from scaffold mesh.
Definition
simple_cubic_tet_mesh.template.cc:47
oomph::TriangleMesh::Tmp_mesh_pt
TriangleScaffoldMesh * Tmp_mesh_pt
Temporary scaffold mesh.
Definition
triangle_mesh.h:1334
oomph
Definition
annular_domain.h:35