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
34namespace oomph
35{
36 //======================================================================
37 /// Adapt problem based on specified elemental error estimates
38 //======================================================================
39 template<class ELEMENT>
41 {
42 double t_start = 0.0;
43
44 // ###################################
46 // ###################################
47
48 // Get refinement targets
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 {
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
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 // ##################################################################
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 {
99 }
100
102
103#ifdef OOMPH_HAS_CGAL
104
105 // Make cgal-based bin
108 {
109 cgal_params.enable_use_eulerian_coordinates_during_setup();
110 }
112
113#else
114
115 std::ostringstream error_message;
116 error_message << "Non-CGAL-based target size transfer not implemented.\n";
117 throw OomphLibError(
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 =
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);
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(),
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(),
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(),
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?
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
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;
288 new RefineableGmshTetMesh<ELEMENT>(this->Gmsh_parameters_pt,
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 // ###################################
301 // ###################################
302
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 //---------------------------------------
311 project_problem_pt->mesh_pt() = new_mesh_pt;
312 project_problem_pt->project(this);
313
315 << "adapt: Time for project soln onto new mesh : "
316 << TimingHelpers::timer() - t_start << " sec " << std::endl;
317 }
318 // ###################################
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 //------------------------------
340 nel = new_mesh_pt->nelement();
341 Element_pt.resize(nel);
342 for (unsigned j = 0; j < nnod; j++)
343 {
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);
415 {
416 // Allocate storage in the map
417 this->Boundary_region_element_pt[b][r].resize(
419 this->Face_index_region_at_boundary[b][r].resize(
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 // ##################################################################
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(),
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
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
CGAL-based SamplePointContainer.
Helper object for dealing with the parameters used for the CGALSamplePointContainer objects.
A general Finite Element class.
Definition elements.h:1317
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
Node ** Node_pt
Storage for pointers to the nodes in the element.
Definition elements.h:1323
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
A geometric object is an object that provides a parametrised description of its shape via the functio...
This class provides a GeomObject representation of a given finite element mesh. The Lagrangian coordi...
void resize(const unsigned &n_value)
Resize the number of equations.
Definition nodes.cc:2167
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
General SolidMesh class.
Definition mesh.h:2570
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
TAdvectionDiffusionReactionElement()
Constructor: Call constructors for TElement and AdvectionDiffusionReaction equations.
std::string to_string(T object, unsigned float_precision=8)
Conversion function that should work for anything with operator<< defined (at least all basic types).
double timer()
returns the time in seconds after some point in past
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...