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
xda_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_XDA_TET_MESH_TEMPLATE_HEADER
27
#define OOMPH_XDA_TET_MESH_TEMPLATE_HEADER
28
29
#ifndef OOMPH_XDA_TET_MESH_HEADER
30
#error __FILE__ should only be included from xda_tet_mesh.h.
31
#endif
// OOMPH_XDA_TET_MESH_HEADER
32
33
#include "
generic/Telements.h
"
34
35
namespace
oomph
36
{
37
//======================================================================
38
/// Constructor: Pass name of xda file. Note that all
39
/// boundary elements get their own ID -- this is required for
40
/// FSI problems. The vector containing the oomph-lib
41
/// boundary IDs of all oomph-lib boundaries that collectively form
42
/// a given boundary as specified in the xda input file can be
43
/// obtained from the access function oomph_lib_boundary_ids(...).
44
/// Timestepper defaults to steady pseudo-timestepper.
45
//======================================================================
46
template
<
class
ELEMENT>
47
XdaTetMesh<ELEMENT>::XdaTetMesh
(
const
std::string
xda_file_name
,
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
// Open and process xda input file
54
std::ifstream
infile
(
xda_file_name
.c_str(), std::ios_base::in);
55
unsigned
n_node
;
56
unsigned
n_element
;
57
unsigned
n_bound_face
;
58
59
if
(!
infile
.is_open())
60
{
61
std::ostringstream
error_stream
;
62
error_stream
<<
"Failed to open "
<<
xda_file_name
<<
"\n"
;
63
throw
OomphLibError
(
64
error_stream
.str(),
OOMPH_CURRENT_FUNCTION
,
OOMPH_EXCEPTION_LOCATION
);
65
}
66
67
// Dummy storage to jump lines
68
char
dummy
[101];
69
70
// Ignore file format
71
infile
.getline(
dummy
, 100);
72
73
// Get number of elements
74
infile
>>
n_element
;
75
76
// Ignore rest of line
77
infile
.getline(
dummy
, 100);
78
79
// Get number of nodes
80
infile
>>
n_node
;
81
82
// Ignore rest of line
83
infile
.getline(
dummy
, 100);
84
85
// Ignore sum of element weights (whatever that is...)
86
infile
.getline(
dummy
, 100);
87
88
// Get number of enumerated boundary faces on which boundary conditions
89
// are applied.
90
infile
>>
n_bound_face
;
91
92
// Keep reading until "Title String"
93
while
(
dummy
[0] !=
'T'
)
94
{
95
infile
.getline(
dummy
, 100);
96
}
97
98
// Make space for nodes and elements
99
Node_pt
.
resize
(
n_node
);
100
Element_pt.resize(
n_element
);
101
102
// Read first line with node labels and count them
103
std::string
line
;
104
std::getline(
infile
,
line
);
105
std::istringstream
ostr
(
line
);
106
std::istream_iterator<std::string>
it
(
ostr
);
107
std::istream_iterator<std::string>
end
;
108
unsigned
nnod_el
= 0;
109
Vector<unsigned>
first_node
;
110
while
(
it
!=
end
)
111
{
112
first_node
.push_back(
atoi
((*it).c_str()));
113
it
++;
114
nnod_el
++;
115
}
116
117
// Check
118
if
(
nnod_el
!= 10)
119
{
120
std::ostringstream
error_stream
;
121
error_stream
122
<<
"XdaTetMesh can currently only be built with quadratic tets "
123
<<
"with 10 nodes. The specified mesh file has "
<<
nnod_el
124
<<
"nodes per element.\n"
;
125
throw
OomphLibError
(
126
error_stream
.str(),
OOMPH_CURRENT_FUNCTION
,
OOMPH_EXCEPTION_LOCATION
);
127
}
128
129
// Storage for the global node numbers listed element-by-element
130
Vector<unsigned>
global_node
(
n_element
*
nnod_el
);
131
132
// Read in nodes
133
unsigned
k
= 0;
134
135
// Copy across first nodes
136
for
(
unsigned
j
= 0;
j
<
nnod_el
;
j
++)
137
{
138
global_node
[
k
] =
first_node
[
k
];
139
k
++;
140
}
141
142
// Read the other ones
143
for
(
unsigned
i
= 1;
i
<
n_element
;
i
++)
144
{
145
for
(
unsigned
j
= 0;
j
<
nnod_el
;
j
++)
146
{
147
infile
>>
global_node
[
k
];
148
k
++;
149
}
150
infile
.getline(
dummy
, 100);
151
}
152
153
// Create storage for coordinates
154
Vector<double>
x_node
(
n_node
);
155
Vector<double>
y_node
(
n_node
);
156
Vector<double>
z_node
(
n_node
);
157
158
// Get nodal coordinates
159
for
(
unsigned
i
= 0;
i
<
n_node
;
i
++)
160
{
161
infile
>>
x_node
[
i
];
162
infile
>>
y_node
[
i
];
163
infile
>>
z_node
[
i
];
164
}
165
166
// Read in boundaries for faces
167
unsigned
element_nmbr
;
168
unsigned
bound_id
;
169
unsigned
side_nmbr
;
170
unsigned
max_bound
= 0;
171
172
// Make space for enumeration of sub-boundaries
173
Boundary_id.resize(
n_bound_face
+ 1);
174
175
// Counter for number of separate boundary faces
176
unsigned
count
= 0;
177
Vector<std::set<unsigned>
> boundary_id(
n_node
);
178
for
(
unsigned
i
= 0;
i
<
n_bound_face
;
i
++)
179
{
180
// Number of the element
181
infile
>>
element_nmbr
;
182
183
// Which side/face on the tet are we dealing with (xda enumeratation)?
184
infile
>>
side_nmbr
;
185
186
// What's the boundary ID?
187
infile
>>
bound_id
;
188
189
// Turn into zero-based oomph-lib mesh boundary id
190
unsigned
oomph_lib_bound_id
=
bound_id
- 1;
191
oomph_lib_bound_id
=
count
;
192
Boundary_id[
bound_id
].push_back(
count
);
193
194
// Increment number of separate boundary faces
195
count
++;
196
197
// Get ready for allocation of total number of boundaries
198
if
(
oomph_lib_bound_id
>
max_bound
)
max_bound
=
oomph_lib_bound_id
;
199
200
// Identify the "side nodes" (i.e. the nodes on the faces of
201
// the bulk tet) according to the
202
// conventions in '.xda' mesh files so that orientation of the
203
// faces is always the same (required for computation of
204
// outer unit normals
205
Vector<unsigned>
side_node
(6);
206
switch
(
side_nmbr
)
207
{
208
case
0:
209
side_node
[0] =
global_node
[
nnod_el
*
element_nmbr
+ 1];
210
side_node
[1] =
global_node
[
nnod_el
*
element_nmbr
];
211
side_node
[2] =
global_node
[
nnod_el
*
element_nmbr
+ 2];
212
side_node
[3] =
global_node
[
nnod_el
*
element_nmbr
+ 4];
213
side_node
[4] =
global_node
[
nnod_el
*
element_nmbr
+ 6];
214
side_node
[5] =
global_node
[
nnod_el
*
element_nmbr
+ 5];
215
break
;
216
217
case
1:
218
side_node
[0] =
global_node
[
nnod_el
*
element_nmbr
];
219
side_node
[1] =
global_node
[
nnod_el
*
element_nmbr
+ 1];
220
side_node
[2] =
global_node
[
nnod_el
*
element_nmbr
+ 3];
221
side_node
[3] =
global_node
[
nnod_el
*
element_nmbr
+ 4];
222
side_node
[4] =
global_node
[
nnod_el
*
element_nmbr
+ 8];
223
side_node
[5] =
global_node
[
nnod_el
*
element_nmbr
+ 7];
224
break
;
225
226
case
2:
227
side_node
[0] =
global_node
[
nnod_el
*
element_nmbr
+ 1];
228
side_node
[1] =
global_node
[
nnod_el
*
element_nmbr
+ 2];
229
side_node
[2] =
global_node
[
nnod_el
*
element_nmbr
+ 3];
230
side_node
[3] =
global_node
[
nnod_el
*
element_nmbr
+ 5];
231
side_node
[4] =
global_node
[
nnod_el
*
element_nmbr
+ 9];
232
side_node
[5] =
global_node
[
nnod_el
*
element_nmbr
+ 8];
233
break
;
234
235
case
3:
236
side_node
[0] =
global_node
[
nnod_el
*
element_nmbr
+ 2];
237
side_node
[1] =
global_node
[
nnod_el
*
element_nmbr
];
238
side_node
[2] =
global_node
[
nnod_el
*
element_nmbr
+ 3];
239
side_node
[3] =
global_node
[
nnod_el
*
element_nmbr
+ 6];
240
side_node
[4] =
global_node
[
nnod_el
*
element_nmbr
+ 7];
241
side_node
[5] =
global_node
[
nnod_el
*
element_nmbr
+ 9];
242
break
;
243
244
default
:
245
throw
OomphLibError
(
246
"Unexcpected side number in your '.xda' input file\n"
,
247
OOMPH_CURRENT_FUNCTION
,
248
OOMPH_EXCEPTION_LOCATION
);
249
}
250
251
// Associate boundaries with nodes
252
for
(
unsigned
j
= 0;
j
< 6;
j
++)
253
{
254
boundary_id[
side_node
[
j
]].insert(
oomph_lib_bound_id
);
255
}
256
}
257
258
// Set number of boundaries
259
set_nboundary(
max_bound
+ 1);
260
261
// Vector of bools, will tell us if we already visited a node
262
std::vector<bool>
done
(
n_node
,
false
);
263
264
Vector<unsigned>
translate
(
n_node
);
265
translate
[0] = 0;
266
translate
[1] = 2;
267
translate
[2] = 1;
268
translate
[3] = 3;
269
translate
[4] = 5;
270
translate
[5] = 7;
271
translate
[6] = 4;
272
translate
[7] = 6;
273
translate
[8] = 8;
274
translate
[9] = 9;
275
276
// Create the elements
277
unsigned
node_count
= 0;
278
for
(
unsigned
e
= 0;
e
<
n_element
;
e
++)
279
{
280
Element_pt[
e
] =
new
ELEMENT;
281
282
// Loop over all nodes
283
for
(
unsigned
j
= 0;
j
<
nnod_el
;
j
++)
284
{
285
unsigned
j_global
=
global_node
[
node_count
];
286
if
(
done
[
j_global
] ==
false
)
287
{
288
if
(boundary_id[
j_global
].
size
() == 0)
289
{
290
Node_pt
[
j_global
] = finite_element_pt(
e
)->construct_node(
291
translate
[
j
],
time_stepper_pt
);
292
}
293
else
294
{
295
Node_pt
[
j_global
] = finite_element_pt(
e
)->construct_boundary_node(
296
translate
[
j
],
time_stepper_pt
);
297
for
(std::set<unsigned>::iterator
it
=
298
boundary_id[
j_global
].
begin
();
299
it
!= boundary_id[
j_global
].end();
300
it
++)
301
{
302
add_boundary_node(*
it
,
Node_pt
[
j_global
]);
303
}
304
}
305
done
[
j_global
] =
true
;
306
Node_pt
[
j_global
]->
x
(0) =
x_node
[
j_global
];
307
Node_pt
[
j_global
]->
x
(1) =
y_node
[
j_global
];
308
Node_pt
[
j_global
]->
x
(2) =
z_node
[
j_global
];
309
}
310
else
311
{
312
finite_element_pt(
e
)->
node_pt
(
translate
[
j
]) =
Node_pt
[
j_global
];
313
}
314
node_count
++;
315
}
316
}
317
318
// Figure out which elements are next to the boundaries.
319
setup_boundary_element_info();
320
321
// Setup boundary coordinates
322
unsigned
nb
= nboundary();
323
for
(
unsigned
b = 0; b <
nb
; b++)
324
{
325
bool
switch_normal
=
false
;
326
setup_boundary_coordinates(b,
switch_normal
);
327
}
328
}
329
330
//======================================================================
331
/// Setup boundary coordinate on boundary b while is
332
/// temporarily flattened to simplex faces. Boundary coordinates are the
333
/// x-y coordinates in the plane of that boundary with the
334
/// x-axis along the line from the (lexicographically)
335
/// "lower left" to the "upper right" node. The y axis
336
/// is obtained by taking the cross-product of the positive
337
/// x direction with the outer unit normal computed by
338
/// the face elements (or its negative if switch_normal is set
339
/// to true). Doc faces in output file.
340
//======================================================================
341
template
<
class
ELEMENT>
342
void
XdaTetMesh<ELEMENT>::setup_boundary_coordinates
(
343
const
unsigned
& b,
const
bool
&
switch_normal
, std::ofstream&
outfile
)
344
{
345
// Temporary storage for face elements
346
Vector<FiniteElement*>
face_el_pt
;
347
348
// Backup for nodal positions
349
std::map<Node*, Vector<double>>
backup_position
;
350
351
// Loop over all elements on boundaries
352
unsigned
nel
= this->nboundary_element(b);
353
if
(
nel
> 0)
354
{
355
// Loop over the bulk elements adjacent to boundary b
356
for
(
unsigned
e
= 0;
e
<
nel
;
e
++)
357
{
358
// Get pointer to the bulk element that is adjacent to boundary b
359
FiniteElement
*
bulk_elem_pt
= this->boundary_element_pt(b,
e
);
360
361
// Find the index of the face of element e along boundary b
362
int
face_index = this->face_index_at_boundary(b,
e
);
363
364
// Create new face element
365
DummyFaceElement<ELEMENT>
*
el_pt
=
366
new
DummyFaceElement<ELEMENT>
(
bulk_elem_pt
, face_index);
367
face_el_pt
.push_back(
el_pt
);
368
369
// Backup nodal position
370
Vector<double>
pos
(3);
371
for
(
unsigned
j
= 3;
j
< 6;
j
++)
372
{
373
if
(
backup_position
[
el_pt
->
node_pt
(
j
)].
size
() == 0)
374
{
375
el_pt
->
node_pt
(
j
)->
position
(
pos
);
376
backup_position
[
el_pt
->
node_pt
(
j
)] =
pos
;
377
}
378
}
379
380
// Temporarily flatten the element to a simplex
381
for
(
unsigned
i
= 0;
i
< 3;
i
++)
382
{
383
// Node 3 is between vertex nodes 0 and 1
384
el_pt
->
node_pt
(3)->
x
(
i
) =
385
0.5 * (
el_pt
->
node_pt
(0)->
x
(
i
) +
el_pt
->
node_pt
(1)->
x
(
i
));
386
387
// Node 4 is between vertex nodes 1 and 2
388
el_pt
->
node_pt
(4)->
x
(
i
) =
389
0.5 * (
el_pt
->
node_pt
(1)->
x
(
i
) +
el_pt
->
node_pt
(2)->
x
(
i
));
390
391
// Node 5 is between vertex nodes 2 and 0
392
el_pt
->
node_pt
(5)->
x
(
i
) =
393
0.5 * (
el_pt
->
node_pt
(2)->
x
(
i
) +
el_pt
->
node_pt
(0)->
x
(
i
));
394
}
395
396
// Output faces?
397
if
(
outfile
.is_open())
398
{
399
face_el_pt
[
face_el_pt
.
size
() - 1]->
output
(
outfile
);
400
}
401
}
402
403
// Loop over all nodes to find the lower left and upper right ones
404
Node
*
lower_left_node_pt
= this->boundary_node_pt(b, 0);
405
Node
*
upper_right_node_pt
= this->boundary_node_pt(b, 0);
406
407
// Loop over all nodes on the boundary
408
unsigned
nnod
= this->nboundary_node(b);
409
for
(
unsigned
j
= 0;
j
<
nnod
;
j
++)
410
{
411
// Get node
412
Node
*
nod_pt
= this->boundary_node_pt(b,
j
);
413
414
// Primary criterion for lower left: Does it have a lower z-coordinate?
415
if
(
nod_pt
->x(2) <
lower_left_node_pt
->x(2))
416
{
417
lower_left_node_pt
=
nod_pt
;
418
}
419
// ...or is it a draw?
420
else
if
(
nod_pt
->x(2) ==
lower_left_node_pt
->x(2))
421
{
422
// If it's a draw: Does it have a lower y-coordinate?
423
if
(
nod_pt
->x(1) <
lower_left_node_pt
->x(1))
424
{
425
lower_left_node_pt
=
nod_pt
;
426
}
427
// ...or is it a draw?
428
else
if
(
nod_pt
->x(1) ==
lower_left_node_pt
->x(1))
429
{
430
// If it's a draw: Does it have a lower x-coordinate?
431
if
(
nod_pt
->x(0) <
lower_left_node_pt
->x(0))
432
{
433
lower_left_node_pt
=
nod_pt
;
434
}
435
}
436
}
437
438
// Primary criterion for upper right: Does it have a higher
439
// z-coordinate?
440
if
(
nod_pt
->x(2) >
upper_right_node_pt
->x(2))
441
{
442
upper_right_node_pt
=
nod_pt
;
443
}
444
// ...or is it a draw?
445
else
if
(
nod_pt
->x(2) ==
upper_right_node_pt
->x(2))
446
{
447
// If it's a draw: Does it have a higher y-coordinate?
448
if
(
nod_pt
->x(1) >
upper_right_node_pt
->x(1))
449
{
450
upper_right_node_pt
=
nod_pt
;
451
}
452
// ...or is it a draw?
453
else
if
(
nod_pt
->x(1) ==
upper_right_node_pt
->x(1))
454
{
455
// If it's a draw: Does it have a higher x-coordinate?
456
if
(
nod_pt
->x(0) >
upper_right_node_pt
->x(0))
457
{
458
upper_right_node_pt
=
nod_pt
;
459
}
460
}
461
}
462
}
463
464
// Prepare storage for boundary coordinates
465
Vector<double>
zeta
(2);
466
467
// Unit vector connecting lower left and upper right nodes
468
Vector<double>
b0
(3);
469
b0
[0] =
upper_right_node_pt
->x(0) -
lower_left_node_pt
->x(0);
470
b0
[1] =
upper_right_node_pt
->x(1) -
lower_left_node_pt
->x(1);
471
b0
[2] =
upper_right_node_pt
->x(2) -
lower_left_node_pt
->x(2);
472
473
// Normalise
474
double
inv_length
=
475
1.0 /
sqrt
(
b0
[0] *
b0
[0] +
b0
[1] *
b0
[1] +
b0
[2] *
b0
[2]);
476
b0
[0] *=
inv_length
;
477
b0
[1] *=
inv_length
;
478
b0
[2] *=
inv_length
;
479
480
// Get (outer) unit normal to first face element
481
Vector<double>
normal
(3);
482
Vector<double>
s
(2, 0.0);
483
dynamic_cast<
DummyFaceElement<ELEMENT>
*
>
(
face_el_pt
[0])
484
->outer_unit_normal(
s
,
normal
);
485
486
if
(
switch_normal
)
487
{
488
normal
[0] = -
normal
[0];
489
normal
[1] = -
normal
[1];
490
normal
[2] = -
normal
[2];
491
}
492
493
#ifdef PARANOID
494
495
// Check that all elements have the same normal
496
for
(
unsigned
e
= 0;
e
<
nel
;
e
++)
497
{
498
// Get (outer) unit normal to face element
499
Vector<double>
my_normal
(3);
500
dynamic_cast<
DummyFaceElement<ELEMENT>
*
>
(
face_el_pt
[0])
501
->outer_unit_normal(
s
,
my_normal
);
502
503
// Dot product should be one!
504
double
error
=
normal
[0] *
my_normal
[0] +
normal
[1] *
my_normal
[1] +
505
normal
[2] *
my_normal
[2];
506
507
error
-= 1.0;
508
if
(
switch_normal
)
error
+= 1.0;
509
510
if
(
error
> Tolerance_for_boundary_finding)
511
{
512
std::ostringstream error_message;
513
error_message
514
<<
"Error in alingment of normals (dot product-1) "
<<
error
515
<<
" for element "
<<
e
<< std::endl
516
<<
"exceeds tolerance specified by the static member data\n"
517
<<
"TetMeshBase::Tolerance_for_boundary_finding = "
518
<< Tolerance_for_boundary_finding << std::endl
519
<<
"This usually means that the boundary is not planar.\n\n"
520
<<
"You can suppress this error message by recompiling \n"
521
<<
"recompiling without PARANOID or by changing the tolerance.\n"
;
522
throw
OomphLibError
(error_message.str(),
523
OOMPH_CURRENT_FUNCTION
,
524
OOMPH_EXCEPTION_LOCATION
);
525
}
526
}
527
#endif
528
529
// Cross-product to get second in-plane vector, normal to b0
530
Vector<double>
b1
(3);
531
b1
[0] =
b0
[1] *
normal
[2] -
b0
[2] *
normal
[1];
532
b1
[1] =
b0
[2] *
normal
[0] -
b0
[0] *
normal
[2];
533
b1
[2] =
b0
[0] *
normal
[1] -
b0
[1] *
normal
[0];
534
535
// Assign boundary coordinates: projection onto the axes
536
for
(
unsigned
j
= 0;
j
<
nnod
;
j
++)
537
{
538
// Get node
539
Node
*
nod_pt
= this->boundary_node_pt(b,
j
);
540
541
// Difference vector to lower left corner
542
Vector<double>
delta
(3);
543
delta
[0] =
nod_pt
->x(0) -
lower_left_node_pt
->x(0);
544
delta
[1] =
nod_pt
->x(1) -
lower_left_node_pt
->x(1);
545
delta
[2] =
nod_pt
->x(2) -
lower_left_node_pt
->x(2);
546
547
// Project
548
zeta
[0] =
delta
[0] *
b0
[0] +
delta
[1] *
b0
[1] +
delta
[2] *
b0
[2];
549
zeta
[1] =
delta
[0] *
b1
[0] +
delta
[1] *
b1
[1] +
delta
[2] *
b1
[2];
550
551
#ifdef PARANOID
552
553
// Check:
554
double
error
=
pow
(
lower_left_node_pt
->x(0) +
zeta
[0] *
b0
[0] +
555
zeta
[1] *
b1
[0] -
nod_pt
->x(0),
556
2) +
557
pow
(
lower_left_node_pt
->x(1) +
zeta
[0] *
b0
[1] +
558
zeta
[1] *
b1
[1] -
nod_pt
->x(1),
559
2) +
560
pow
(
lower_left_node_pt
->x(2) +
zeta
[0] *
b0
[2] +
561
zeta
[1] *
b1
[2] -
nod_pt
->x(2),
562
2);
563
564
if
(
sqrt
(
error
) > Tolerance_for_boundary_finding)
565
{
566
std::ostringstream error_message;
567
error_message
568
<<
"Error in setup of boundary coordinate "
<<
sqrt
(
error
)
569
<< std::endl
570
<<
"exceeds tolerance specified by the static member data\n"
571
<<
"TetMeshBase::Tolerance_for_boundary_finding = "
572
<< Tolerance_for_boundary_finding << std::endl
573
<<
"This usually means that the boundary is not planar.\n\n"
574
<<
"You can suppress this error message by recompiling \n"
575
<<
"recompiling without PARANOID or by changing the tolerance.\n"
;
576
throw
OomphLibError
(error_message.str(),
577
OOMPH_CURRENT_FUNCTION
,
578
OOMPH_EXCEPTION_LOCATION
);
579
}
580
#endif
581
582
// Set boundary coordinate
583
nod_pt
->set_coordinates_on_boundary(b,
zeta
);
584
}
585
}
586
587
// Indicate that boundary coordinate has been set up
588
set_boundary_coordinate_exists(b);
589
590
// Cleanup
591
unsigned
n
=
face_el_pt
.
size
();
592
for
(
unsigned
e
= 0;
e
<
n
;
e
++)
593
{
594
delete
face_el_pt
[
e
];
595
}
596
597
// Reset nodal position
598
for
(std::map<
Node
*,
Vector<double>
>
::iterator
it
=
backup_position
.begin();
599
it
!=
backup_position
.end();
600
it
++)
601
{
602
Node
*
nod_pt
= (*it).first;
603
Vector<double>
pos
((*it).second);
604
for
(
unsigned
i
= 0;
i
< 3;
i
++)
605
{
606
nod_pt
->x(
i
) =
pos
[
i
];
607
}
608
}
609
}
610
611
}
// namespace oomph
612
613
#endif
Telements.h
e
e
Definition
cfortran.h:571
s
static char t char * s
Definition
cfortran.h:568
i
cstr elem_len * i
Definition
cfortran.h:603
oomph::FiniteElement
A general Finite Element class.
Definition
elements.h:1317
oomph::FiniteElement::size
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition
elements.cc:4320
oomph::FiniteElement::Node_pt
Node ** Node_pt
Storage for pointers to the nodes in the element.
Definition
elements.h:1323
oomph::FiniteElement::node_pt
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition
elements.h:2179
oomph::GeomObject::time_stepper_pt
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
Definition
geom_objects.h:192
oomph::Node
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition
nodes.h:906
oomph::Node::position
void position(Vector< double > &pos) const
Compute Vector of nodal positions either directly or via hanging node representation.
Definition
nodes.cc:2499
oomph::Node::x
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition
nodes.h:1060
oomph::Node::resize
void resize(const unsigned &n_value)
Resize the number of equations.
Definition
nodes.cc:2167
oomph::OomphLibError
An OomphLibError object which should be thrown when an run-time error is encountered....
Definition
oomph_definitions.h:229
oomph::TAdvectionDiffusionReactionElement
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Definition
Tadvection_diffusion_reaction_elements.h:66
oomph::TAdvectionDiffusionReactionElement::output
void output(std::ostream &outfile)
Output function: x,y,u or x,y,z,u.
Definition
Tadvection_diffusion_reaction_elements.h:96
oomph::TAdvectionDiffusionReactionElement::TAdvectionDiffusionReactionElement
TAdvectionDiffusionReactionElement()
Constructor: Call constructors for TElement and AdvectionDiffusionReaction equations.
Definition
Tadvection_diffusion_reaction_elements.h:70
oomph::TimeStepper
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Definition
timesteppers.h:231
oomph::XdaTetMesh::setup_boundary_coordinates
void setup_boundary_coordinates(const unsigned &b, const bool &switch_normal)
Setup boundary coordinate on boundary b while is temporarily flattened to simplex faces....
Definition
xda_tet_mesh.h:74
oomph::XdaTetMesh::XdaTetMesh
XdaTetMesh(const std::string xda_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass name of xda file. Note that all boundary elements get their own ID – this is requir...
Definition
xda_tet_mesh.template.cc:47
oomph
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition
advection_diffusion_elements.cc:30