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-2022 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_CC
28#define OOMPH_GMSH_TET_MESH_TEMPLATE_CC
29
30
32
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 //###################################
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 //##################################################################
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
91 // Are we dealing with a solid mesh?
92 SolidMesh* solid_mesh_pt = dynamic_cast<SolidMesh*>(this);
93
94
95 // If the mesh is a solid mesh then do the mapping based on the
96 // Eulerian coordinates
97 bool use_eulerian_coords = false;
98 if (solid_mesh_pt != 0)
99 {
100 use_eulerian_coords = true;
101 }
102
103 MeshAsGeomObject* mesh_geom_obj_pt = 0;
104
105#ifdef OOMPH_HAS_CGAL
106
107 // Make cgal-based bin
108 CGALSamplePointContainerParameters cgal_params(this);
109 if (use_eulerian_coords)
110 {
112 }
113 mesh_geom_obj_pt = new MeshAsGeomObject(&cgal_params);
114
115#else
116
117 std::ostringstream error_message;
118 error_message << "Non-CGAL-based target size transfer not implemented.\n";
119 throw OomphLibError(
120 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
121
122 // Do something here...
123
124#endif
125
126 // Set up a map from pointer to element to its number
127 // in the mesh
128 std::map<GeneralisedElement*, unsigned> element_number;
129 unsigned nelem = this->nelement();
130 for (unsigned e = 0; e < nelem; e++)
131 {
132 element_number[this->element_pt(e)] = e;
133 }
134
135 // Get min/max coordinates
136 Vector<std::pair<double, double>> min_and_max_coordinates =
137 mesh_geom_obj_pt->sample_point_container_pt()
139
140 // Setup grid dimensions for size transfer
141 double dx =
142 (min_and_max_coordinates[0].second - min_and_max_coordinates[0].first);
143 double dy =
144 (min_and_max_coordinates[1].second - min_and_max_coordinates[1].first);
145 double dz =
146 (min_and_max_coordinates[2].second - min_and_max_coordinates[2].first);
147
148 double dx_target =
149 this->Gmsh_parameters_pt->dx_for_target_size_transfer();
150 unsigned nx = unsigned(dx / dx_target);
151 unsigned ny = unsigned(dy / dx_target);
152 unsigned nz = unsigned(dz / dx_target);
153
154 dx /= double(nx);
155 dy /= double(ny);
156 dz /= double(nz);
157
158
159 // Size transfer via hard disk -- yikes...
160 std::string target_size_file_name =
161 this->Gmsh_parameters_pt->target_size_file_name();
162
163 std::ofstream target_size_file;
164 target_size_file.open(target_size_file_name.c_str());
165 target_size_file << min_and_max_coordinates[0].first << " "
166 << min_and_max_coordinates[1].first << " "
167 << min_and_max_coordinates[2].first << " " << std::endl;
168 target_size_file << dx << " " << dy << " " << dz << std::endl;
169 target_size_file << nx + 1 << " " << ny + 1 << " " << nz + 1 << std::endl;
170
171
172 // Doc target areas
173 int counter =
174 this->Gmsh_parameters_pt->counter_for_filename_gmsh_size_transfer();
175 std::string stem =
176 this->Gmsh_parameters_pt->stem_for_filename_gmsh_size_transfer();
177 std::ofstream latest_sizes_file;
178 bool doc_target_areas = false;
179 if ((stem != "") && (counter >= 0))
180 {
181 doc_target_areas = true;
182 std::string filename =
183 stem + oomph::StringConversion::to_string(counter) + ".dat";
184 latest_sizes_file.open(filename.c_str());
185 latest_sizes_file << "ZONE I=" << nx + 1 << ", J=" << ny + 1
186 << ", K=" << nz + 1 << std::endl;
187 this->Gmsh_parameters_pt->counter_for_filename_gmsh_size_transfer()++;
188 }
189
190
191 Vector<double> x(3);
192 for (unsigned i = 0; i <= nx; i++)
193 {
194 x[0] = min_and_max_coordinates[0].first + double(i) * dx;
195 for (unsigned j = 0; j <= ny; j++)
196 {
197 x[1] = min_and_max_coordinates[1].first + double(j) * dy;
198 for (unsigned k = 0; k <= nz; k++)
199 {
200 x[2] = min_and_max_coordinates[2].first + double(k) * dz;
201
202 // Try the specified number of nearest sample points for Newton
203 // search then just settle on the nearest one
204 Vector<double> s(3);
205 GeomObject* geom_obj_pt = 0;
206 unsigned max_sample_points =
207 this->Gmsh_parameters_pt
208 ->max_sample_points_for_limited_locate_zeta_during_target_size_transfer();
209
210#ifdef OOMPH_HAS_CGAL
211
212 dynamic_cast<CGALSamplePointContainer*>(
213 mesh_geom_obj_pt->sample_point_container_pt())
214 ->limited_locate_zeta(x, max_sample_points, geom_obj_pt, s);
215
216#else
217
218 std::ostringstream error_message;
219 error_message
220 << "Non-CGAL-based target size transfer not implemented.\n";
221 throw OomphLibError(error_message.str(),
222 OOMPH_CURRENT_FUNCTION,
223 OOMPH_EXCEPTION_LOCATION);
224
225 // Do something here...
226
227#endif
228
229
230#ifdef PARANOID
231 if (geom_obj_pt == 0)
232 {
233 std::stringstream error_message;
234 error_message << "Limited locate zeta failed for zeta = [ "
235 << x[0] << " " << x[1] << " " << x[2]
236 << " ]. Makes no sense!\n";
237 throw OomphLibError(error_message.str(),
238 OOMPH_CURRENT_FUNCTION,
239 OOMPH_EXCEPTION_LOCATION);
240 }
241 else
242 {
243#endif
244
245 FiniteElement* fe_pt = dynamic_cast<FiniteElement*>(geom_obj_pt);
246
247#ifdef PARANOID
248 if (fe_pt == 0)
249 {
250 std::stringstream error_message;
251 error_message
252 << "Cast to FE for GeomObject returned by limited "
253 << "locate zeta failed for zeta = [ " << x[0] << " " << x[1]
254 << " " << x[2] << " ]. Makes no sense!\n";
255 throw OomphLibError(error_message.str(),
256 OOMPH_CURRENT_FUNCTION,
257 OOMPH_EXCEPTION_LOCATION);
258 }
259 else
260 {
261#endif
262
263 // What's the target size of the element that contains this
264 // point
265 double tg_size =
266 pow(target_size[element_number[fe_pt]], 1.0 / 3.0);
267 target_size_file << tg_size << " ";
268
269 // Doc?
270 if (doc_target_areas)
271 {
272 latest_sizes_file << x[0] << " " << x[1] << " " << x[2] << " "
273 << tg_size << std::endl;
274 }
275
276#ifdef PARANOID
277 }
278 }
279#endif
280 }
281 target_size_file << std::endl;
282 }
283 }
284 target_size_file.close();
285
286 if (doc_target_areas)
287 {
288 latest_sizes_file.close();
289 }
290
291 // Build new mesh, reading area information from file
292 bool use_mesh_grading_from_file = true;
293 RefineableGmshTetMesh<ELEMENT>* new_mesh_pt =
294 new RefineableGmshTetMesh<ELEMENT>(this->Gmsh_parameters_pt,
295 use_mesh_grading_from_file,
296 this->Time_stepper_pt);
297
298 /* // keep around for debugging */
299 /* unsigned nplot=5; */
300 /* ofstream vtu_file; */
301 /* vtu_file.open("new_mesh.vtu"); */
302 /* new_mesh_pt->output_paraview(vtu_file,nplot); */
303 /* vtu_file.close(); */
304
305 //###################################
306 t_start = TimingHelpers::timer();
307 //###################################
308
309 ProjectionProblem<ELEMENT>* project_problem_pt = 0;
310
311 // Check that the projection step is not disabled
312 if (!this->Gmsh_parameters_pt->projection_is_disabled())
313 {
314 // Project current solution onto new mesh
315 //---------------------------------------
316 project_problem_pt = new ProjectionProblem<ELEMENT>;
317 project_problem_pt->mesh_pt() = new_mesh_pt;
318 project_problem_pt->project(this);
319
321 << "adapt: Time for project soln onto new mesh : "
322 << TimingHelpers::timer() - t_start << " sec " << std::endl;
323 }
324 //###################################
325 t_start = TimingHelpers::timer();
326 //###################################
327
328 // Flush the old mesh
329 unsigned nnod = nnode();
330 for (unsigned j = nnod; j > 0; j--)
331 {
332 delete Node_pt[j - 1];
333 Node_pt[j - 1] = 0;
334 }
335 unsigned nel = nelement();
336 for (unsigned e = nel; e > 0; e--)
337 {
338 delete Element_pt[e - 1];
339 Element_pt[e - 1] = 0;
340 }
341
342 // Now copy back to current mesh
343 //------------------------------
344 nnod = new_mesh_pt->nnode();
345 Node_pt.resize(nnod);
346 nel = new_mesh_pt->nelement();
347 Element_pt.resize(nel);
348 for (unsigned j = 0; j < nnod; j++)
349 {
350 Node_pt[j] = new_mesh_pt->node_pt(j);
351 }
352 for (unsigned e = 0; e < nel; e++)
353 {
354 Element_pt[e] = new_mesh_pt->element_pt(e);
355 }
356
357 // Copy the boundary schemes
358 unsigned nbound = new_mesh_pt->nboundary();
359 Boundary_element_pt.resize(nbound);
360 Face_index_at_boundary.resize(nbound);
361 Boundary_node_pt.resize(nbound);
362 for (unsigned b = 0; b < nbound; b++)
363 {
364 unsigned nel = new_mesh_pt->nboundary_element(b);
365 Boundary_element_pt[b].resize(nel);
366 Face_index_at_boundary[b].resize(nel);
367 for (unsigned e = 0; e < nel; e++)
368 {
369 Boundary_element_pt[b][e] = new_mesh_pt->boundary_element_pt(b, e);
370 Face_index_at_boundary[b][e] =
371 new_mesh_pt->face_index_at_boundary(b, e);
372 }
373 unsigned nnod = new_mesh_pt->nboundary_node(b);
374 Boundary_node_pt[b].resize(nnod);
375 for (unsigned j = 0; j < nnod; j++)
376 {
377 Boundary_node_pt[b][j] = new_mesh_pt->boundary_node_pt(b, j);
378 }
379 }
380
381 // Also copy over the new boundary and region information
382 unsigned n_region = new_mesh_pt->nregion();
383
384 // Only bother if we have regions
385 if (n_region > 1)
386 {
387 // Deal with the region information first
388 this->Region_element_pt.resize(n_region);
389 this->Region_attribute.resize(n_region);
390 for (unsigned i = 0; i < n_region; i++)
391 {
392 // Copy across region attributes (region ids!)
393 this->Region_attribute[i] = new_mesh_pt->region_attribute(i);
394
395 // Find the number of elements in the region
396 unsigned r = this->Region_attribute[i];
397 unsigned n_region_element = new_mesh_pt->nregion_element(r);
398 this->Region_element_pt[i].resize(n_region_element);
399 for (unsigned e = 0; e < n_region_element; e++)
400 {
401 this->Region_element_pt[i][e] =
402 new_mesh_pt->region_element_pt(r, e);
403 }
404 }
405
406 // Now the boundary region information
407 this->Boundary_region_element_pt.resize(nbound);
408 this->Face_index_region_at_boundary.resize(nbound);
409
410 // Now loop over the boundaries
411 for (unsigned b = 0; b < nbound; ++b)
412 {
413 // Loop over the regions
414 for (unsigned i = 0; i < n_region; ++i)
415 {
416 unsigned r = this->Region_attribute[i];
417
418 unsigned n_boundary_el_in_region =
419 new_mesh_pt->nboundary_element_in_region(b, r);
420 if (n_boundary_el_in_region > 0)
421 {
422 // Allocate storage in the map
423 this->Boundary_region_element_pt[b][r].resize(
424 n_boundary_el_in_region);
425 this->Face_index_region_at_boundary[b][r].resize(
426 n_boundary_el_in_region);
427
428 // Copy over the information
429 for (unsigned e = 0; e < n_boundary_el_in_region; ++e)
430 {
431 this->Boundary_region_element_pt[b][r][e] =
432 new_mesh_pt->boundary_element_in_region_pt(b, r, e);
433 this->Face_index_region_at_boundary[b][r][e] =
434 new_mesh_pt->face_index_at_boundary_in_region(b, r, e);
435 }
436 }
437 }
438 } // End of loop over boundaries
439
440 } // End of case when more than one region
441
442
443 // Flush the mesh
444 new_mesh_pt->flush_element_and_node_storage();
445
446 // Delete the mesh and the problem
447 delete new_mesh_pt;
448 delete project_problem_pt;
449
450 //##################################################################
452 << "adapt: Time for moving nodes etc. to actual mesh : "
453 << TimingHelpers::timer() - t_start << " sec " << std::endl;
454 //##################################################################
455
456
457 // Solid mesh?
458 if (solid_mesh_pt != 0)
459 {
460 // Warning
461 std::stringstream error_message;
462 error_message
463 << "Lagrangian coordinates are currently not projected but are\n"
464 << "are re-set during adaptation. This is not appropriate for\n"
465 << "real solid mechanics problems!\n";
466 OomphLibWarning(error_message.str(),
467 OOMPH_CURRENT_FUNCTION,
468 OOMPH_EXCEPTION_LOCATION);
469
470 // Reset Lagrangian coordinates
471 dynamic_cast<SolidMesh*>(this)->set_lagrangian_nodal_coordinates();
472 }
473
474 double max_area;
475 double min_area;
476 this->max_and_min_element_size(max_area, min_area);
477 oomph_info << "Max/min element size in adapted mesh: " << max_area << " "
478 << min_area << std::endl;
479 }
480 else
481 {
482 oomph_info << "Not enough benefit in adaptation.\n";
483 Nrefined = 0;
484 Nunrefined = 0;
485 }
486 }
487} // namespace oomph
488
489
490#endif
e
Definition: cfortran.h:571
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
const std::pair< double, double > & min_and_max_coordinates(const unsigned &i) const
Pair of doubles for min and maximum coordinates in i-th direction: min (first) and max....
/////////////////////////////////////////////////////////////////////////// /////////////////////////...
A general Finite Element class.
Definition: elements.h:1313
/////////////////////////////////////////////////////////////////////
Definition: geom_objects.h:101
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
SamplePointContainer * sample_point_container_pt() const
Pointer to the sample point container.
unsigned long nboundary_node(const unsigned &ibound) const
Return number of nodes on a particular boundary.
Definition: mesh.h:833
void flush_element_and_node_storage()
Flush storage for elements and nodes by emptying the vectors that store the pointers to them....
Definition: mesh.h:407
int face_index_at_boundary(const unsigned &b, const unsigned &e) const
For the e-th finite element on boundary b, return int to indicate the face_index of the face adjacent...
Definition: mesh.h:896
unsigned nboundary_element(const unsigned &b) const
Return number of finite elements that are adjacent to boundary b.
Definition: mesh.h:878
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition: mesh.h:436
FiniteElement * boundary_element_pt(const unsigned &b, const unsigned &e) const
Return pointer to e-th finite element on boundary b.
Definition: mesh.h:840
unsigned nboundary() const
Return number of boundaries.
Definition: mesh.h:827
unsigned long nnode() const
Return number of nodes in the mesh.
Definition: mesh.h:596
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:448
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition: mesh.h:493
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....
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition: problem.h:1280
Projection problem. This is created during the adaptation of unstructured meshes and it is assumed th...
Definition: projection.h:695
void project(Mesh *base_mesh_pt, const bool &dont_project_positions=false)
Project from base into the problem's own mesh.
Definition: projection.h:748
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
void enable_use_eulerian_coordinates_during_setup()
Enable use of eulerian coordinates (via interpolated_x) during setup (otherwise use interpolated_zeta...
General SolidMesh class.
Definition: mesh.h:2562
int face_index_at_boundary_in_region(const unsigned &b, const unsigned &r, const unsigned &e) const
Return face index of the e-th element adjacent to boundary b in region r.
Definition: tet_mesh.h:834
double region_attribute(const unsigned &i)
Return the i-th region attribute (here only used as the (assumed to be unsigned) region id.
Definition: tet_mesh.h:906
unsigned nregion()
Return the number of regions specified by attributes.
Definition: tet_mesh.h:860
FiniteElement * boundary_element_in_region_pt(const unsigned &b, const unsigned &r, const unsigned &e) const
Return pointer to the e-th element adjacent to boundary b in region r.
Definition: tet_mesh.h:816
FiniteElement * region_element_pt(const unsigned &r, const unsigned &e)
Return the e-th element in the r-th region.
Definition: tet_mesh.h:912
unsigned nboundary_element_in_region(const unsigned &b, const unsigned &r) const
Return the number of elements adjacent to boundary b in region r.
Definition: tet_mesh.h:797
unsigned nregion_element(const unsigned &r)
Return the number of elements in region r.
Definition: tet_mesh.h:866
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
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
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...