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
gmsh_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
27
#ifndef OOMPH_GMSH_TET_MESH_TEMPLATE_HEADER
28
#define OOMPH_GMSH_TET_MESH_TEMPLATE_HEADER
29
30
#ifndef OOMPH_GMSH_TET_MESH_HEADER
31
#error __FILE__ should only be included from gmsh_tet_mesh.h.
32
#endif
// OOMPH_GMSH_TET_MESH_HEADER
33
34
namespace
oomph
35
{
36
//======================================================================
37
/// Adapt problem based on specified elemental error estimates
38
//======================================================================
39
template
<
class
ELEMENT>
40
void
RefineableGmshTetMesh<ELEMENT>::adapt
(
const
Vector<double>
&
elem_error
)
41
{
42
double
t_start
= 0.0;
43
44
// ###################################
45
t_start
= TimingHelpers::timer();
46
// ###################################
47
48
// Get refinement targets
49
Vector<double>
target_size
(
elem_error
.size());
50
double
max_edge_ratio
=
51
this->
compute_volume_target
(
elem_error
,
target_size
);
52
// Get maximum target volume
53
unsigned
n
=
target_size
.size();
54
double
max_size
= 0.0;
55
double
min_size
=
DBL_MAX
;
56
for
(
unsigned
e
= 0;
e
<
n
;
e
++)
57
{
58
if
(
target_size
[
e
] >
max_size
)
max_size
=
target_size
[
e
];
59
if
(
target_size
[
e
] <
min_size
)
min_size
=
target_size
[
e
];
60
}
61
62
oomph_info
<<
"Maximum target size: "
<<
max_size
<< std::endl;
63
oomph_info
<<
"Minimum target size: "
<<
min_size
<< std::endl;
64
oomph_info
<<
"Number of elements to be refined "
<< this->
Nrefined
65
<< std::endl;
66
oomph_info
<<
"Number of elements to be unrefined "
<< this->
Nunrefined
67
<< std::endl;
68
oomph_info
<<
"Max edge ratio "
<<
max_edge_ratio
<< std::endl;
69
70
double
orig_max_size
,
orig_min_size
;
71
this->
max_and_min_element_size
(
orig_max_size
,
orig_min_size
);
72
oomph_info
<<
"Max/min element size in original mesh: "
<<
orig_max_size
73
<<
" "
<<
orig_min_size
<< std::endl;
74
75
// ##################################################################
76
oomph_info
77
<<
"adapt: Time for getting volume targets : "
78
<< TimingHelpers::timer() -
t_start
<<
" sec "
<< std::endl;
79
// ##################################################################
80
81
// Should we bother to adapt?
82
if
((
Nrefined
> 0) || (
Nunrefined
> this->
max_keep_unrefined
()) ||
83
(
max_edge_ratio
> this->max_permitted_edge_ratio()))
84
{
85
if
(!((
Nrefined
> 0) || (
Nunrefined
>
max_keep_unrefined
())))
86
{
87
oomph_info
<<
"Mesh regeneration triggered by edge ratio criterion\n"
;
88
}
89
90
// Are we dealing with a solid mesh?
91
SolidMesh*
solid_mesh_pt
=
dynamic_cast<
SolidMesh*
>
(
this
);
92
93
// If the mesh is a solid mesh then do the mapping based on the
94
// Eulerian coordinates
95
bool
use_eulerian_coords
=
false
;
96
if
(
solid_mesh_pt
!= 0)
97
{
98
use_eulerian_coords
=
true
;
99
}
100
101
MeshAsGeomObject
*
mesh_geom_obj_pt
= 0;
102
103
#ifdef OOMPH_HAS_CGAL
104
105
// Make cgal-based bin
106
CGALSamplePointContainerParameters
cgal_params
(
this
);
107
if
(
use_eulerian_coords
)
108
{
109
cgal_params
.enable_use_eulerian_coordinates_during_setup();
110
}
111
mesh_geom_obj_pt
=
new
MeshAsGeomObject
(&
cgal_params
);
112
113
#else
114
115
std::ostringstream
error_message
;
116
error_message
<<
"Non-CGAL-based target size transfer not implemented.\n"
;
117
throw
OomphLibError
(
118
error_message
.str(),
OOMPH_CURRENT_FUNCTION
,
OOMPH_EXCEPTION_LOCATION
);
119
120
// Do something here...
121
122
#endif
123
124
// Set up a map from pointer to element to its number
125
// in the mesh
126
std::map<GeneralisedElement*, unsigned>
element_number
;
127
unsigned
nelem
= this->
nelement
();
128
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
129
{
130
element_number
[this->
element_pt
(
e
)] =
e
;
131
}
132
133
// Get min/max coordinates
134
Vector<std::pair<double, double>
>
min_and_max_coordinates
=
135
mesh_geom_obj_pt
->sample_point_container_pt()
136
->min_and_max_coordinates();
137
138
// Setup grid dimensions for size transfer
139
double
dx
=
140
(
min_and_max_coordinates
[0].second -
min_and_max_coordinates
[0].first);
141
double
dy
=
142
(
min_and_max_coordinates
[1].second -
min_and_max_coordinates
[1].first);
143
double
dz
=
144
(
min_and_max_coordinates
[2].second -
min_and_max_coordinates
[2].first);
145
146
double
dx_target
=
147
this->Gmsh_parameters_pt->dx_for_target_size_transfer();
148
unsigned
nx =
unsigned
(
dx
/
dx_target
);
149
unsigned
ny =
unsigned
(
dy
/
dx_target
);
150
unsigned
nz =
unsigned
(
dz
/
dx_target
);
151
152
dx
/=
double
(nx);
153
dy
/=
double
(ny);
154
dz
/=
double
(nz);
155
156
// Size transfer via hard disk -- yikes...
157
std::string target_size_file_name =
158
this->Gmsh_parameters_pt->target_size_file_name();
159
160
std::ofstream
target_size_file
;
161
target_size_file
.open(target_size_file_name.c_str());
162
target_size_file
<<
min_and_max_coordinates
[0].first <<
" "
163
<<
min_and_max_coordinates
[1].first <<
" "
164
<<
min_and_max_coordinates
[2].first <<
" "
<< std::endl;
165
target_size_file
<<
dx
<<
" "
<<
dy
<<
" "
<<
dz
<< std::endl;
166
target_size_file
<< nx + 1 <<
" "
<< ny + 1 <<
" "
<< nz + 1 << std::endl;
167
168
// Doc target areas
169
int
counter
=
170
this->Gmsh_parameters_pt->counter_for_filename_gmsh_size_transfer();
171
std::string
stem
=
172
this->Gmsh_parameters_pt->stem_for_filename_gmsh_size_transfer();
173
std::ofstream
latest_sizes_file
;
174
bool
doc_target_areas
=
false
;
175
if
((
stem
!=
""
) && (
counter
>= 0))
176
{
177
doc_target_areas
=
true
;
178
std::string
filename
=
179
stem
+ oomph::StringConversion::to_string(
counter
) +
".dat"
;
180
latest_sizes_file
.open(
filename
.c_str());
181
latest_sizes_file
<<
"ZONE I="
<< nx + 1 <<
", J="
<< ny + 1
182
<<
", K="
<< nz + 1 << std::endl;
183
this->Gmsh_parameters_pt->counter_for_filename_gmsh_size_transfer()++;
184
}
185
186
Vector<double>
x(3);
187
for
(
unsigned
i
= 0;
i
<= nx;
i
++)
188
{
189
x[0] =
min_and_max_coordinates
[0].first +
double
(
i
) *
dx
;
190
for
(
unsigned
j
= 0;
j
<= ny;
j
++)
191
{
192
x[1] =
min_and_max_coordinates
[1].first +
double
(
j
) *
dy
;
193
for
(
unsigned
k
= 0;
k
<= nz;
k
++)
194
{
195
x[2] =
min_and_max_coordinates
[2].first +
double
(
k
) *
dz
;
196
197
// Try the specified number of nearest sample points for Newton
198
// search then just settle on the nearest one
199
Vector<double>
s
(3);
200
GeomObject
*
geom_obj_pt
= 0;
201
unsigned
max_sample_points
=
202
this->Gmsh_parameters_pt
203
->max_sample_points_for_limited_locate_zeta_during_target_size_transfer();
204
205
#ifdef OOMPH_HAS_CGAL
206
207
dynamic_cast<
CGALSamplePointContainer
*
>
(
208
mesh_geom_obj_pt
->sample_point_container_pt())
209
->
limited_locate_zeta
(x,
max_sample_points
,
geom_obj_pt
,
s
);
210
211
#else
212
213
std::ostringstream
error_message
;
214
error_message
215
<<
"Non-CGAL-based target size transfer not implemented.\n"
;
216
throw
OomphLibError
(
error_message
.str(),
217
OOMPH_CURRENT_FUNCTION
,
218
OOMPH_EXCEPTION_LOCATION
);
219
220
// Do something here...
221
222
#endif
223
224
#ifdef PARANOID
225
if
(
geom_obj_pt
== 0)
226
{
227
std::stringstream
error_message
;
228
error_message
<<
"Limited locate zeta failed for zeta = [ "
229
<< x[0] <<
" "
<< x[1] <<
" "
<< x[2]
230
<<
" ]. Makes no sense!\n"
;
231
throw
OomphLibError
(
error_message
.str(),
232
OOMPH_CURRENT_FUNCTION
,
233
OOMPH_EXCEPTION_LOCATION
);
234
}
235
else
236
{
237
#endif
238
239
FiniteElement
*
fe_pt
=
dynamic_cast<
FiniteElement
*
>
(
geom_obj_pt
);
240
241
#ifdef PARANOID
242
if
(
fe_pt
== 0)
243
{
244
std::stringstream
error_message
;
245
error_message
246
<<
"Cast to FE for GeomObject returned by limited "
247
<<
"locate zeta failed for zeta = [ "
<< x[0] <<
" "
<< x[1]
248
<<
" "
<< x[2] <<
" ]. Makes no sense!\n"
;
249
throw
OomphLibError
(
error_message
.str(),
250
OOMPH_CURRENT_FUNCTION
,
251
OOMPH_EXCEPTION_LOCATION
);
252
}
253
else
254
{
255
#endif
256
257
// What's the target size of the element that contains this
258
// point
259
double
tg_size
=
260
pow
(
target_size
[
element_number
[
fe_pt
]], 1.0 / 3.0);
261
target_size_file
<<
tg_size
<<
" "
;
262
263
// Doc?
264
if
(
doc_target_areas
)
265
{
266
latest_sizes_file
<< x[0] <<
" "
<< x[1] <<
" "
<< x[2] <<
" "
267
<<
tg_size
<< std::endl;
268
}
269
270
#ifdef PARANOID
271
}
272
}
273
#endif
274
}
275
target_size_file
<< std::endl;
276
}
277
}
278
target_size_file
.close();
279
280
if
(
doc_target_areas
)
281
{
282
latest_sizes_file
.close();
283
}
284
285
// Build new mesh, reading area information from file
286
bool
use_mesh_grading_from_file
=
true
;
287
RefineableGmshTetMesh<ELEMENT>
*
new_mesh_pt
=
288
new
RefineableGmshTetMesh<ELEMENT>
(this->Gmsh_parameters_pt,
289
use_mesh_grading_from_file
,
290
this->
Time_stepper_pt
);
291
292
/* // keep around for debugging */
293
/* unsigned nplot=5; */
294
/* ofstream vtu_file; */
295
/* vtu_file.open("new_mesh.vtu"); */
296
/* new_mesh_pt->output_paraview(vtu_file,nplot); */
297
/* vtu_file.close(); */
298
299
// ###################################
300
t_start = TimingHelpers::timer();
301
// ###################################
302
303
ProjectionProblem<ELEMENT>
*
project_problem_pt
= 0;
304
305
// Check that the projection step is not disabled
306
if
(!this->Gmsh_parameters_pt->projection_is_disabled())
307
{
308
// Project current solution onto new mesh
309
//---------------------------------------
310
project_problem_pt
=
new
ProjectionProblem<ELEMENT>
;
311
project_problem_pt
->mesh_pt() =
new_mesh_pt
;
312
project_problem_pt
->project(
this
);
313
314
oomph_info
315
<<
"adapt: Time for project soln onto new mesh : "
316
<< TimingHelpers::timer() -
t_start
<<
" sec "
<< std::endl;
317
}
318
// ###################################
319
t_start
= TimingHelpers::timer();
320
// ###################################
321
322
// Flush the old mesh
323
unsigned
nnod
=
nnode
();
324
for
(
unsigned
j
=
nnod
;
j
> 0;
j
--)
325
{
326
delete
Node_pt
[
j
- 1];
327
Node_pt
[
j
- 1] = 0;
328
}
329
unsigned
nel
=
nelement
();
330
for
(
unsigned
e
=
nel
;
e
> 0;
e
--)
331
{
332
delete
Element_pt
[
e
- 1];
333
Element_pt
[
e
- 1] = 0;
334
}
335
336
// Now copy back to current mesh
337
//------------------------------
338
nnod
=
new_mesh_pt
->nnode();
339
Node_pt
.resize(
nnod
);
340
nel
=
new_mesh_pt
->nelement();
341
Element_pt
.resize(
nel
);
342
for
(
unsigned
j
= 0;
j
<
nnod
;
j
++)
343
{
344
Node_pt
[
j
] =
new_mesh_pt
->node_pt(
j
);
345
}
346
for
(
unsigned
e
= 0;
e
<
nel
;
e
++)
347
{
348
Element_pt
[
e
] =
new_mesh_pt
->element_pt(
e
);
349
}
350
351
// Copy the boundary schemes
352
unsigned
nbound
=
new_mesh_pt
->nboundary();
353
Boundary_element_pt
.resize(
nbound
);
354
Face_index_at_boundary
.resize(
nbound
);
355
Boundary_node_pt
.resize(
nbound
);
356
for
(
unsigned
b
= 0;
b
<
nbound
;
b
++)
357
{
358
unsigned
nel
=
new_mesh_pt
->nboundary_element(
b
);
359
Boundary_element_pt
[
b
].resize(
nel
);
360
Face_index_at_boundary
[
b
].resize(
nel
);
361
for
(
unsigned
e
= 0;
e
<
nel
;
e
++)
362
{
363
Boundary_element_pt
[
b
][
e
] =
new_mesh_pt
->boundary_element_pt(
b
,
e
);
364
Face_index_at_boundary
[
b
][
e
] =
365
new_mesh_pt
->face_index_at_boundary(
b
,
e
);
366
}
367
unsigned
nnod
=
new_mesh_pt
->nboundary_node(
b
);
368
Boundary_node_pt
[
b
].resize(
nnod
);
369
for
(
unsigned
j
= 0;
j
<
nnod
;
j
++)
370
{
371
Boundary_node_pt
[
b
][
j
] =
new_mesh_pt
->boundary_node_pt(
b
,
j
);
372
}
373
}
374
375
// Also copy over the new boundary and region information
376
unsigned
n_region
=
new_mesh_pt
->nregion();
377
378
// Only bother if we have regions
379
if
(
n_region
> 1)
380
{
381
// Deal with the region information first
382
this->
Region_element_pt
.resize(
n_region
);
383
this->
Region_attribute
.resize(
n_region
);
384
for
(
unsigned
i
= 0;
i
<
n_region
;
i
++)
385
{
386
// Copy across region attributes (region ids!)
387
this->
Region_attribute
[
i
] =
new_mesh_pt
->region_attribute(
i
);
388
389
// Find the number of elements in the region
390
unsigned
r
= this->
Region_attribute
[
i
];
391
unsigned
n_region_element
=
new_mesh_pt
->nregion_element(
r
);
392
this->
Region_element_pt
[
i
].resize(
n_region_element
);
393
for
(
unsigned
e
= 0;
e
<
n_region_element
;
e
++)
394
{
395
this->
Region_element_pt
[
i
][
e
] =
396
new_mesh_pt
->region_element_pt(
r
,
e
);
397
}
398
}
399
400
// Now the boundary region information
401
this->
Boundary_region_element_pt
.resize(
nbound
);
402
this->
Face_index_region_at_boundary
.resize(
nbound
);
403
404
// Now loop over the boundaries
405
for
(
unsigned
b
= 0;
b
<
nbound
; ++
b
)
406
{
407
// Loop over the regions
408
for
(
unsigned
i
= 0;
i
<
n_region
; ++
i
)
409
{
410
unsigned
r
= this->
Region_attribute
[
i
];
411
412
unsigned
n_boundary_el_in_region
=
413
new_mesh_pt
->nboundary_element_in_region(
b
,
r
);
414
if
(
n_boundary_el_in_region
> 0)
415
{
416
// Allocate storage in the map
417
this->
Boundary_region_element_pt
[
b
][
r
].resize(
418
n_boundary_el_in_region
);
419
this->
Face_index_region_at_boundary
[
b
][
r
].resize(
420
n_boundary_el_in_region
);
421
422
// Copy over the information
423
for
(
unsigned
e
= 0;
e
<
n_boundary_el_in_region
; ++
e
)
424
{
425
this->
Boundary_region_element_pt
[
b
][
r
][
e
] =
426
new_mesh_pt
->boundary_element_in_region_pt(
b
,
r
,
e
);
427
this->
Face_index_region_at_boundary
[
b
][
r
][
e
] =
428
new_mesh_pt
->face_index_at_boundary_in_region(
b
,
r
,
e
);
429
}
430
}
431
}
432
}
// End of loop over boundaries
433
434
}
// End of case when more than one region
435
436
// Flush the mesh
437
new_mesh_pt
->flush_element_and_node_storage();
438
439
// Delete the mesh and the problem
440
delete
new_mesh_pt
;
441
delete
project_problem_pt
;
442
443
// ##################################################################
444
oomph_info
445
<<
"adapt: Time for moving nodes etc. to actual mesh : "
446
<< TimingHelpers::timer() -
t_start
<<
" sec "
<< std::endl;
447
// ##################################################################
448
449
// Solid mesh?
450
if
(
solid_mesh_pt
!= 0)
451
{
452
// Warning
453
std::stringstream
error_message
;
454
error_message
455
<<
"Lagrangian coordinates are currently not projected but are\n"
456
<<
"are re-set during adaptation. This is not appropriate for\n"
457
<<
"real solid mechanics problems!\n"
;
458
OomphLibWarning
(
error_message
.str(),
459
OOMPH_CURRENT_FUNCTION
,
460
OOMPH_EXCEPTION_LOCATION
);
461
462
// Reset Lagrangian coordinates
463
dynamic_cast<
SolidMesh*
>
(
this
)->
set_lagrangian_nodal_coordinates
();
464
}
465
466
double
max_area
;
467
double
min_area
;
468
this->
max_and_min_element_size
(
max_area
,
min_area
);
469
oomph_info
<<
"Max/min element size in adapted mesh: "
<<
max_area
<<
" "
470
<<
min_area
<< std::endl;
471
}
472
else
473
{
474
oomph_info
<<
"Not enough benefit in adaptation.\n"
;
475
Nrefined
= 0;
476
Nunrefined
= 0;
477
}
478
}
479
}
// namespace oomph
480
481
#endif
oomph::RefineableGmshTetMesh::adapt
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
Definition
gmsh_tet_mesh.template.cc:40
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition
triangle_mesh.h:2225
oomph::TriangleMesh::Time_stepper_pt
TimeStepper * Time_stepper_pt
Timestepper used to build elements.
Definition
triangle_mesh.h:1162
oomph
Definition
annular_domain.h:35