27 #ifndef OOMPH_REFINEABLE_TETGEN_MESH_TEMPLATE_CC
28 #define OOMPH_REFINEABLE_TETGEN_MESH_TEMPLATE_CC
32 #include <oomph-lib-config.h>
37 #include "../generic/sample_point_parameters.h"
38 #include "../generic/mesh_as_geometric_object.h"
39 #include "../generic/projection.h"
40 #include "../generic/face_element_as_geometric_object.h"
48 template<
class ELEMENT>
57 std::list<Node*> new_vertex_nodes;
59 std::list<std::pair<Vector<unsigned>,
unsigned>> new_facet_list;
62 unsigned n_old_facet = faceted_surface_pt->
nfacet();
63 for (
unsigned f = 0; f < n_old_facet; f++)
74 this->
template build_face_mesh<ELEMENT, FaceElementAsGeomObject>(
80 unsigned n_face_element = face_mesh_pt->
nelement();
81 for (
unsigned e = 0;
e < n_face_element;
e++)
101 for (
unsigned e = 0;
e < n_face_element; ++
e)
107 unsigned n_vertex_node = 3;
108 for (
unsigned n = 0; n < n_vertex_node; n++)
113 unsigned counter = 0;
114 bool found_it =
false;
115 for (std::list<Node*>::iterator it = new_vertex_nodes.begin();
116 it != new_vertex_nodes.end();
122 new_local_facet[n] = counter;
132 new_vertex_nodes.push_back(nod_pt);
134 new_local_facet[n] = counter;
139 new_facet_list.push_back(std::make_pair(new_local_facet, bound + 1));
153 unsigned n_facet_vertex = new_vertex_nodes.size();
157 for (std::list<Node*>::iterator it = new_vertex_nodes.begin();
158 it != new_vertex_nodes.end();
161 facet_nodes_pt[count] = *it;
171 unsigned n_facet = new_facet_list.size();
176 new_facet_list.begin();
177 it != new_facet_list.end();
180 new_facet[count] = (*it).first;
181 new_facet_boundary_id[count] = (*it).second;
185 for (
unsigned f = 0; f < n_facet; f++)
187 for (
unsigned i = 0;
i < 3;
i++)
192 oomph_info << new_facet_boundary_id[f] <<
"\n";
196 delete faceted_surface_pt;
198 facet_nodes_pt, new_facet, new_facet_boundary_id);
201 this->setup_reverse_lookup_schemes_for_faceted_surface(faceted_surface_pt);
205 for (
unsigned n = 0; n < n_facet_vertex; n++)
207 for (
unsigned i = 0;
i < 3;
i++)
209 inner_point[
i] += facet_nodes_pt[n]->x(
i);
213 for (
unsigned i = 0;
i < 3;
i++)
215 inner_point[
i] /= n_facet_vertex;
220 ->set_hole_for_tetgen(inner_point);
226 template<
class ELEMENT>
230 unsigned n_hole = this->Internal_surface_pt.size();
231 for (
unsigned ihole = 0; ihole < n_hole; ihole++)
238 this->update_faceted_surface_using_face_mesh(
239 this->Internal_surface_pt[ihole]);
245 template<
class ELEMENT>
250 if (!Boundary_coordinate_exists[b])
252 oomph_info <<
"Not snapping nodes on boundary " << b
253 <<
" because no boundary coordinate has been set up.\n";
271 this->
template build_face_mesh<ELEMENT, FaceElementAsGeomObject>(
277 unsigned n_face_element = face_mesh_pt->
nelement();
278 for (
unsigned e = 0;
e < n_face_element;
e++)
293 new_mesh_pt->template build_face_mesh<ELEMENT, FaceElementAsGeomObject>(
294 b, new_face_mesh_pt);
296 std::ostringstream filestring;
297 filestring <<
"old_mesh_boundary" << b <<
".dat";
298 face_mesh_pt->
output(filestring.str().c_str());
300 filestring <<
"new_mesh_boundary" << b <<
".dat";
301 new_face_mesh_pt->
output(filestring.str().c_str());
304 std::cout <<
"OLD---\n";
306 unsigned n_tmp_node = this->nboundary_node(b);
307 for (
unsigned n = 0; n < n_tmp_node; ++n)
309 Node*
const nod_pt = this->boundary_node_pt(b, n);
311 std::cout << nod_pt->
x(0) <<
" " << nod_pt->
x(1) <<
" " << nod_pt->
x(2)
312 <<
" " << b_coo[0] <<
" " << b_coo[1] <<
"\n";
315 std::cout <<
"NEW-----------\n";
318 for (
unsigned n = 0; n < n_tmp_node; ++n)
322 std::cout << nod_pt->
x(0) <<
" " << nod_pt->
x(1) <<
" " << nod_pt->
x(2)
323 <<
" " << b_coo[0] <<
" " << b_coo[1] <<
"\n";
336 for (
unsigned n = 0; n < n_new_boundary_node; n++)
342 mesh_geom_obj_pt->
position(b_coord, new_x);
344 for (
unsigned i = 0;
i < 3;
i++)
346 nod_pt->
x(
i) = new_x[
i];
352 delete mesh_geom_obj_pt;
366 for (
unsigned n = 0; n < 4; n++)
368 dummy_four_node_element.construct_node(n);
370 for (
unsigned n = 0; n < 10; n++)
372 dummy_ten_node_element.construct_node(n);
374 for (
unsigned e = 0;
e < n_element;
e++)
381 const unsigned n_node = elem_pt->nnode();
386 for (
unsigned n = 0; n < 4; n++)
388 for (
unsigned i = 0;
i < 3;
i++)
390 dummy_four_node_element.node_pt(n)->x(
i) =
391 elem_pt->node_pt(n)->x(
i);
396 for (
unsigned n = 4; n < 10; n++)
400 if (!elem_pt->node_pt(n)->is_on_boundary())
402 elem_pt->local_coordinate_of_node(n,
s);
403 dummy_four_node_element.interpolated_x(
s, x_new);
404 for (
unsigned i = 0;
i < 3;
i++)
406 elem_pt->node_pt(n)->x(
i) = x_new[
i];
416 for (
unsigned n = 0; n < 10; n++)
418 for (
unsigned i = 0;
i < 3;
i++)
420 dummy_ten_node_element.node_pt(n)->x(
i) =
421 elem_pt->node_pt(n)->x(
i);
426 for (
unsigned n = 10; n < n_node; n++)
430 if (!elem_pt->node_pt(n)->is_on_boundary())
432 elem_pt->local_coordinate_of_node(n,
s);
433 dummy_ten_node_element.interpolated_x(
s, x_new);
434 for (
unsigned i = 0;
i < 3;
i++)
436 elem_pt->node_pt(n)->x(
i) = x_new[
i];
449 template<
class ELEMENT>
452 double t_start = 0.0;
459 double max_edge_ratio =
460 this->compute_volume_target(elem_error, target_size);
462 unsigned n = target_size.size();
463 double max_size = 0.0;
464 double min_size = DBL_MAX;
465 for (
unsigned e = 0;
e < n;
e++)
467 if (target_size[
e] > max_size) max_size = target_size[
e];
468 if (target_size[
e] < min_size) min_size = target_size[
e];
471 oomph_info <<
"Maximum target size: " << max_size << std::endl;
472 oomph_info <<
"Minimum target size: " << min_size << std::endl;
473 oomph_info <<
"Number of elements to be refined " << this->Nrefined
475 oomph_info <<
"Number of elements to be unrefined " << this->Nunrefined
477 oomph_info <<
"Max edge ratio " << max_edge_ratio << std::endl;
479 double orig_max_size, orig_min_size;
480 this->max_and_min_element_size(orig_max_size, orig_min_size);
481 oomph_info <<
"Max/min element size in original mesh: " << orig_max_size
482 <<
" " << orig_min_size << std::endl;
486 <<
"adapt: Time for getting volume targets : "
496 bool inner_boundary_update_necessary =
false;
499 if ((Nrefined > 0) || (Nunrefined > this->max_keep_unrefined()) ||
500 (max_edge_ratio > this->max_permitted_edge_ratio()))
502 if (!((Nrefined > 0) || (Nunrefined > max_keep_unrefined())))
504 oomph_info <<
"Mesh regeneration triggered by edge ratio criterion\n";
508 if (inner_boundary_update_necessary)
510 this->surface_remesh_for_inner_hole_boundaries();
516 const unsigned n_boundary = this->nboundary();
517 for (
unsigned b = 0; b < n_boundary; ++b)
521 this->
template setup_boundary_coordinates<ELEMENT>(b);
539 if (solid_mesh_pt != 0)
545 this->Outer_boundary_pt,
546 this->Internal_surface_pt,
548 this->Time_stepper_pt,
549 this->Use_attributes,
550 this->Corner_elements_must_be_split);
555 this->Outer_boundary_pt,
556 this->Internal_surface_pt,
558 this->Time_stepper_pt,
559 this->Use_attributes,
560 this->Corner_elements_must_be_split);
566 <<
"adapt: Time for building temp mesh : "
589 tetgenio* tmp_new_tetgenio_pt = tmp_new_mesh_pt->
tetgenio_pt();
594 bool use_eulerian_coords =
false;
595 if (solid_mesh_pt != 0)
597 use_eulerian_coords =
true;
600 #ifdef OOMPH_HAS_CGAL
604 if (use_eulerian_coords)
612 std::ostringstream error_message;
613 error_message <<
"Non-CGAL-based target size transfer not implemented.\n";
615 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
635 std::map<GeneralisedElement*, unsigned> element_number;
636 unsigned nelem = this->nelement();
637 for (
unsigned e = 0;
e < nelem;
e++)
639 element_number[this->element_pt(
e)] =
e;
655 unsigned nelem = tmp_new_mesh_pt->
nelement();
660 for (
unsigned e = 0;
e < nelem;
e++)
663 dynamic_cast<ELEMENT*
>(tmp_new_mesh_pt->
element_pt(
e));
664 unsigned nint = el_pt->integral_pt()->nweight();
665 for (
unsigned ipt = 0; ipt < nint; ipt++)
669 for (
unsigned i = 0;
i < 3;
i++)
671 s[
i] = el_pt->integral_pt()->knot(ipt,
i);
675 el_pt->interpolated_x(
s, x);
682 unsigned max_sample_points = 5;
685 ->limited_locate_zeta(x, max_sample_points, geom_obj_pt,
s);
687 if (geom_obj_pt == 0)
689 std::stringstream error_message;
690 error_message <<
"Limited locate zeta failed for zeta = [ "
691 << x[0] <<
" " << x[1] <<
" " << x[2]
692 <<
" ]. Makes no sense!\n";
694 OOMPH_CURRENT_FUNCTION,
695 OOMPH_EXCEPTION_LOCATION);
704 std::stringstream error_message;
705 error_message <<
"Cast to FE for GeomObject returned by "
706 "limited locate zeta failed for zeta = [ "
707 << x[0] <<
" " << x[1] <<
" " << x[2]
708 <<
" ]. Makes no sense!\n";
710 OOMPH_CURRENT_FUNCTION,
711 OOMPH_EXCEPTION_LOCATION);
718 double tg_size = target_size[element_number[fe_pt]];
725 if (new_transferred_target_size[
e] != 0.0)
727 new_transferred_target_size[
e] =
728 std::min(new_transferred_target_size[
e], tg_size);
732 new_transferred_target_size[
e] = tg_size;
742 std::ostringstream error_message;
744 <<
"Non-CGAL-based target size transfer not implemented.\n";
746 OOMPH_CURRENT_FUNCTION,
747 OOMPH_EXCEPTION_LOCATION);
796 const bool output_target_sizes =
false;
797 if (output_target_sizes)
799 unsigned length = new_transferred_target_size.size();
800 for (
unsigned u = 0; u < length; u++)
803 <<
",target size: " << new_transferred_target_size[u]
811 unsigned n_ele_need_refinement_iter = 0;
821 std::ofstream target_sizes_file;
823 sprintf(filename,
"target_sizes%i.dat", iter);
824 if (output_target_sizes)
826 target_sizes_file.open(filename);
829 const unsigned nel_new = tmp_new_mesh_pt->
nelement();
831 for (
unsigned e = 0;
e < nel_new;
e++)
837 const double new_size = new_transferred_target_size[
e];
840 std::ostringstream error_stream;
842 <<
"This shouldn't happen! Element whose centroid is at "
855 <<
" has no target size assigned\n";
857 OOMPH_CURRENT_FUNCTION,
858 OOMPH_EXCEPTION_LOCATION);
864 new_target_size[
e] = new_size;
865 if (new_target_size[
e] < f_ele_pt->
size() / 4.0)
867 new_target_size[
e] = f_ele_pt->
size() / 4.0;
880 if (output_target_sizes)
882 target_sizes_file <<
"ZONE N=4, E=1, F=FEPOINT, ET=TETRAHEDRON\n";
883 for (
unsigned j = 0; j < 4; j++)
885 target_sizes_file << f_ele_pt->
node_pt(j)->
x(0) <<
" "
886 << f_ele_pt->
node_pt(j)->
x(1) <<
" "
887 << f_ele_pt->
node_pt(j)->
x(2) <<
" "
888 << new_size <<
" " << new_target_size[
e]
891 target_sizes_file <<
"1 2 3 4\n";
913 n_ele_need_refinement_iter++;
921 if (output_target_sizes)
923 target_sizes_file.close();
929 <<
"All size adjustments accommodated by max. permitted size"
930 <<
" reduction during iter " << iter <<
"\n";
934 oomph_info <<
"NOT all size adjustments accommodated by max. "
935 <<
"permitted size reduction during iter " << iter
941 <<
"\n\n\n==================================================\n"
942 <<
"==================================================\n"
943 <<
"==================================================\n"
944 <<
"==================================================\n"
949 <<
"adapt: Time for new_target_size[.] : "
966 if (solid_mesh_pt != 0)
977 this->Outer_boundary_pt,
978 this->Internal_surface_pt,
979 this->Time_stepper_pt,
980 this->Use_attributes);
988 this->Outer_boundary_pt,
989 this->Internal_surface_pt,
990 this->Time_stepper_pt,
991 this->Use_attributes);
996 <<
"adapt: Time for new_mesh_pt : "
1009 unsigned nnod = tmp_new_mesh_pt->
nnode();
1010 if (nnod == new_mesh_pt->
nnode())
1012 unsigned nel = tmp_new_mesh_pt->
nelement();
1013 if (nel == new_mesh_pt->
nelement())
1015 bool nodes_identical =
true;
1016 for (
unsigned j = 0; j < nnod; j++)
1018 bool coords_identical =
true;
1019 for (
unsigned i = 0;
i < 3;
i++)
1024 coords_identical =
false;
1027 if (!coords_identical)
1029 nodes_identical =
false;
1033 if (nodes_identical)
1042 delete tmp_new_mesh_pt;
1047 tmp_new_mesh_pt = new_mesh_pt;
1067 if (!Projection_is_disabled)
1077 project_problem_pt->
mesh_pt() = new_mesh_pt;
1078 project_problem_pt->
project(
this);
1079 delete project_problem_pt;
1083 <<
"adapt: Time for project soln onto new mesh : "
1096 unsigned nnod = nnode();
1097 for (
unsigned j = nnod; j > 0; j--)
1099 delete Node_pt[j - 1];
1102 unsigned nel = nelement();
1103 for (
unsigned e = nel;
e > 0;
e--)
1105 delete Element_pt[
e - 1];
1106 Element_pt[
e - 1] = 0;
1111 nnod = new_mesh_pt->
nnode();
1112 Node_pt.resize(nnod);
1114 Element_pt.resize(nel);
1115 for (
unsigned j = 0; j < nnod; j++)
1117 Node_pt[j] = new_mesh_pt->
node_pt(j);
1119 for (
unsigned e = 0;
e < nel;
e++)
1125 unsigned nbound = new_mesh_pt->
nboundary();
1126 Boundary_element_pt.resize(nbound);
1127 Face_index_at_boundary.resize(nbound);
1128 Boundary_node_pt.resize(nbound);
1129 for (
unsigned b = 0; b < nbound; b++)
1132 Boundary_element_pt[b].resize(nel);
1133 Face_index_at_boundary[b].resize(nel);
1134 for (
unsigned e = 0;
e < nel;
e++)
1137 Face_index_at_boundary[b][
e] =
1141 Boundary_node_pt[b].resize(nnod);
1142 for (
unsigned j = 0; j < nnod; j++)
1149 unsigned n_region = new_mesh_pt->
nregion();
1155 this->Region_element_pt.resize(n_region);
1156 this->Region_attribute.resize(n_region);
1157 for (
unsigned i = 0;
i < n_region;
i++)
1163 unsigned r = this->Region_attribute[
i];
1165 this->Region_element_pt[
i].resize(n_region_element);
1166 for (
unsigned e = 0;
e < n_region_element;
e++)
1168 this->Region_element_pt[
i][
e] =
1174 this->Boundary_region_element_pt.resize(nbound);
1175 this->Face_index_region_at_boundary.resize(nbound);
1178 for (
unsigned b = 0; b < nbound; ++b)
1181 for (
unsigned i = 0;
i < n_region; ++
i)
1183 unsigned r = this->Region_attribute[
i];
1185 unsigned n_boundary_el_in_region =
1187 if (n_boundary_el_in_region > 0)
1190 this->Boundary_region_element_pt[b][r].resize(
1191 n_boundary_el_in_region);
1192 this->Face_index_region_at_boundary[b][r].resize(
1193 n_boundary_el_in_region);
1196 for (
unsigned e = 0;
e < n_boundary_el_in_region; ++
e)
1198 this->Boundary_region_element_pt[b][r][
e] =
1200 this->Face_index_region_at_boundary[b][r][
e] =
1210 this->set_deep_copy_tetgenio_pt(new_mesh_pt->
tetgenio_pt());
1221 <<
"adapt: Time for moving nodes etc. to actual mesh : "
1226 if (solid_mesh_pt != 0)
1229 std::stringstream error_message;
1231 <<
"Lagrangian coordinates are currently not projected but are\n"
1232 <<
"are re-set during adaptation. This is not appropriate for\n"
1233 <<
"real solid mechanics problems!\n";
1235 OOMPH_CURRENT_FUNCTION,
1236 OOMPH_EXCEPTION_LOCATION);
1239 dynamic_cast<SolidMesh*
>(
this)->set_lagrangian_nodal_coordinates();
1244 this->max_and_min_element_size(max_area, min_area);
1245 oomph_info <<
"Max/min element size in adapted mesh: " << max_area <<
" "
1246 << min_area << std::endl;
1250 oomph_info <<
"Not enough benefit in adaptation.\n";
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
/////////////////////////////////////////////////////////////////////////// /////////////////////////...
Class that is used to create FaceElement from bulk elements and to provide these FaceElement with a g...
void set_boundary_number_in_bulk_mesh(const unsigned &b)
Set function for the boundary number in bulk mesh.
A general Finite Element class.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
/////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
void position(const Vector< double > &zeta, Vector< double > &r) const
Return the position as a function of the intrinsic coordinate zeta. This provides an (expensive!...
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.
void flush_element_and_node_storage()
Flush storage for elements and nodes by emptying the vectors that store the pointers to them....
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
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...
unsigned nboundary_element(const unsigned &b) const
Return number of finite elements that are adjacent to boundary b.
unsigned nboundary() const
Return number of boundaries.
FiniteElement * boundary_element_pt(const unsigned &b, const unsigned &e) const
Return pointer to e-th finite element on boundary b.
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
unsigned long nnode() const
Return number of nodes in the mesh.
void output(std::ostream &outfile)
Output for all elements.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
unsigned long nelement() const
Return number of elements in the mesh.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
double & x(const unsigned &i)
Return the i-th nodal coordinate.
virtual void get_coordinates_on_boundary(const unsigned &b, const unsigned &k, Vector< double > &boundary_zeta)
Return the vector of the k-th generalised boundary coordinates on mesh boundary b....
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.
Projection problem. This is created during the adaptation of unstructured meshes and it is assumed th...
void project(Mesh *base_mesh_pt, const bool &dont_project_positions=false)
Project from base into the problem's own mesh.
////////////////////////////////////////////////////////////////////////// //////////////////////////...
void surface_remesh_for_inner_hole_boundaries()
Generate a new faceted representation of the inner hole boundaries.
void update_faceted_surface_using_face_mesh(TetMeshFacetedSurface *&faceted_surface_pt)
Helper function that updates the input faceted surface by using the flattened elements from FaceMesh(...
void snap_nodes_onto_boundary(RefineableTetgenMesh< ELEMENT > *&new_mesh_pt, const unsigned &b)
Snap the boundary nodes onto any curvilinear boundaries.
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...
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.
double region_attribute(const unsigned &i)
Return the i-th region attribute (here only used as the (assumed to be unsigned) region id.
unsigned nregion()
Return the number of regions specified by attributes.
unsigned nboundary_element_in_region(const unsigned &b, const unsigned &r) const
Return the number of elements adjacent to boundary b in region r.
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.
FiniteElement * region_element_pt(const unsigned &r, const unsigned &e)
Return the e-th element in the r-th region.
unsigned nregion_element(const unsigned &r)
Return the number of elements in region r.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
unsigned nfacet() const
Number of facets.
unsigned one_based_facet_boundary_id(const unsigned &j) const
One-based boundary id of j-th facet.
tetgenio *& tetgenio_pt()
Access to the triangulateio representation of the mesh.
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...