27 #ifndef OOMPH_TET_MESH_HEADER
28 #define OOMPH_TET_MESH_HEADER
32 #include <oomph-lib-config.h>
61 std::ostringstream error_stream;
62 error_stream <<
"TetMeshVertex should only be used in 3D!\n"
63 <<
"Your Vector of coordinates, contains data for "
64 <<
x.size() <<
"-dimensional coordinates." << std::endl;
66 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
74 const unsigned n_dim = node_pt->
ndim();
78 std::ostringstream error_stream;
79 error_stream <<
"TetMeshVertex should only be used in 3D!\n"
80 <<
"Your Node contains data for " << n_dim
81 <<
"-dimensional coordinates." << std::endl;
83 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
89 for (
unsigned i = 0;
i < n_dim; ++
i)
100 if (zeta.size() != 2)
102 std::ostringstream error_stream;
104 <<
"TetMeshVertex should only be used in 3D!\n"
105 <<
"Your Vector of intrinisic coordinates, contains data for "
106 << zeta.size() <<
"-dimensional coordinates but should be 2!"
109 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
124 double x(
const unsigned&
i)
const
218 for (
unsigned j = 0; j < nv; j++)
250 const unsigned& one_based_region_id)
266 outfile <<
"ZONE I=" << n + 1 << std::endl;
267 for (
unsigned j = 0; j < n; j++)
333 return Facet_pt[j]->one_based_boundary_id();
339 return Vertex_pt[j]->one_based_boundary_id();
395 for (
unsigned j = 0; j < n; j++)
405 std::ofstream outfile;
406 outfile.open(filename.c_str());
418 const double& zeta_boundary,
422 zeta_vertex[0] =
Facet_pt[facet_id]->vertex_pt(0)->zeta_in_geom_object();
423 zeta_vertex[1] =
Facet_pt[facet_id]->vertex_pt(1)->zeta_in_geom_object();
424 zeta[0] = zeta_vertex[0][0] +
425 (zeta_vertex[1][0] - zeta_vertex[0][0]) * zeta_boundary;
426 zeta[1] = zeta_vertex[0][1] +
427 (zeta_vertex[1][1] - zeta_vertex[0][1]) * zeta_boundary;
437 const double& zeta_boundary,
441 zeta_vertex[0] =
Facet_pt[facet_id]->vertex_pt(1)->zeta_in_geom_object();
442 zeta_vertex[1] =
Facet_pt[facet_id]->vertex_pt(2)->zeta_in_geom_object();
443 zeta[0] = zeta_vertex[0][0] +
444 (zeta_vertex[1][0] - zeta_vertex[0][0]) * zeta_boundary;
445 zeta[1] = zeta_vertex[0][1] +
446 (zeta_vertex[1][1] - zeta_vertex[0][1]) * zeta_boundary;
456 const double& zeta_boundary,
460 zeta_vertex[0] =
Facet_pt[facet_id]->vertex_pt(2)->zeta_in_geom_object();
461 zeta_vertex[1] =
Facet_pt[facet_id]->vertex_pt(0)->zeta_in_geom_object();
462 zeta[0] = zeta_vertex[0][0] +
463 (zeta_vertex[1][0] - zeta_vertex[0][0]) * zeta_boundary;
464 zeta[1] = zeta_vertex[0][1] +
465 (zeta_vertex[1][1] - zeta_vertex[0][1]) * zeta_boundary;
507 for (
unsigned f = 0; f < nf; f++)
509 unsigned nv =
Facet_pt[f]->nvertex();
511 for (
unsigned v = 0; v < nv; v++)
514 for (
unsigned j = 0; j < nv_overall; j++)
569 const unsigned&
i)
const
586 std::make_pair(region_point, region_id));
701 template<
class ELEMENT>
705 std::ofstream some_file;
708 bool switch_normal =
false;
709 this->setup_boundary_coordinates<ELEMENT>(b, switch_normal, some_file);
732 template<
class ELEMENT>
734 const bool& switch_normal)
737 std::ofstream some_file;
739 this->setup_boundary_coordinates<ELEMENT>(b, switch_normal, some_file);
763 template<
class ELEMENT>
765 const bool& switch_normal,
766 std::ofstream& outfile);
787 template<
class ELEMENT>
791 bool switch_normal =
false;
792 this->setup_boundary_coordinates<ELEMENT>(b, switch_normal, outfile);
798 const unsigned& r)
const
802 std::map<unsigned, Vector<FiniteElement*>>::const_iterator it =
806 return (it->second).size();
818 const unsigned&
e)
const
821 std::map<unsigned, Vector<FiniteElement*>>::const_iterator it =
825 return (it->second)[
e];
836 const unsigned&
e)
const
839 std::map<unsigned, Vector<int>>::const_iterator it =
843 return (it->second)[
e];
847 std::ostringstream error_message;
848 error_message <<
"Face indices not set up for boundary " << b
849 <<
" in region " << r <<
"\n";
850 error_message <<
"This probably means that the boundary is not "
851 "adjacent to region\n";
853 OOMPH_CURRENT_FUNCTION,
854 OOMPH_EXCEPTION_LOCATION);
871 for (
unsigned i = 0;
i < n;
i++)
879 std::ostringstream error_message;
880 error_message <<
"Region attributes should be unsigneds because we \n"
881 <<
"only use them to set region ids\n";
883 OOMPH_CURRENT_FUNCTION,
884 OOMPH_EXCEPTION_LOCATION);
917 for (
unsigned i = 0;
i < n;
i++)
925 std::ostringstream error_message;
926 error_message <<
"Region attributes should be unsigneds because we \n"
927 <<
"only use the to set region ids\n";
929 OOMPH_CURRENT_FUNCTION,
930 OOMPH_EXCEPTION_LOCATION);
961 template<
class ELEMENT>
965 const bool& switch_normal,
978 template<
class ELEMENT>
982 const bool& switch_normal)
987 snap_to_quadratic_surface<ELEMENT>(
988 boundary_id, quadratic_surface_file_name, switch_normal, doc_info);
1000 template<
class ELEMENT>
1009 std::ofstream outfile;
1053 std::map<unsigned, Vector<Vector<double>>>
1091 template<
class ELEMENT>
1093 const bool& switch_normal,
1094 std::ofstream& outfile)
1096 Node* lower_left_node_pt = 0;
1097 Node* upper_right_node_pt = 0;
1111 f_pt = (*it).second;
1124 bool vertices_are_in_same_plane =
true;
1125 for (
unsigned do_for_real = 0; do_for_real < 2; do_for_real++)
1136 for (
unsigned e = 0;
e < nel;
e++)
1145 face_el_pt.push_back(
1149 if (outfile.is_open())
1151 face_el_pt[face_el_pt.size() - 1]->output(outfile);
1161 for (
unsigned j = 0; j < nnod; j++)
1168 if (nod_pt->
x(2) < lower_left_node_pt->
x(2))
1170 lower_left_node_pt = nod_pt;
1173 else if (nod_pt->
x(2) == lower_left_node_pt->
x(2))
1176 if (nod_pt->
x(1) < lower_left_node_pt->
x(1))
1178 lower_left_node_pt = nod_pt;
1181 else if (nod_pt->
x(1) == lower_left_node_pt->
x(1))
1184 if (nod_pt->
x(0) < lower_left_node_pt->
x(0))
1186 lower_left_node_pt = nod_pt;
1193 if (nod_pt->
x(2) > upper_right_node_pt->
x(2))
1195 upper_right_node_pt = nod_pt;
1198 else if (nod_pt->
x(2) == upper_right_node_pt->
x(2))
1201 if (nod_pt->
x(1) > upper_right_node_pt->
x(1))
1203 upper_right_node_pt = nod_pt;
1206 else if (nod_pt->
x(1) == upper_right_node_pt->
x(1))
1209 if (nod_pt->
x(0) > upper_right_node_pt->
x(0))
1211 upper_right_node_pt = nod_pt;
1228 b0[0] = upper_right_node_pt->
x(0) - lower_left_node_pt->
x(0);
1229 b0[1] = upper_right_node_pt->
x(1) - lower_left_node_pt->
x(1);
1230 b0[2] = upper_right_node_pt->
x(2) - lower_left_node_pt->
x(2);
1234 1.0 / sqrt(b0[0] * b0[0] + b0[1] * b0[1] + b0[2] * b0[2]);
1235 b0[0] *= inv_length;
1236 b0[1] *= inv_length;
1237 b0[2] *= inv_length;
1248 ->outer_unit_normal(
s, normal);
1264 normal[0] = t1y * t2z - t1z * t2y;
1265 normal[1] = t1z * t2x - t1x * t2z;
1266 normal[2] = t1x * t2y - t1y * t2x;
1268 1.0 / sqrt(normal[0] * normal[0] + normal[1] * normal[1] +
1269 normal[2] * normal[2]);
1270 normal[0] *= inv_length;
1271 normal[1] *= inv_length;
1272 normal[2] *= inv_length;
1277 normal[0] = -normal[0];
1278 normal[1] = -normal[1];
1279 normal[2] = -normal[2];
1288 for (
unsigned e = 0;
e < nel;
e++)
1293 ->outer_unit_normal(
s, my_normal);
1296 double dot_prod = normal[0] * my_normal[0] +
1297 normal[1] * my_normal[1] + normal[2] * my_normal[2];
1300 double error = abs(dot_prod) - 1.0;
1303 vertices_are_in_same_plane =
false;
1308 if (vertices_are_in_same_plane)
1311 b1[0] = b0[1] * normal[2] - b0[2] * normal[1];
1312 b1[1] = b0[2] * normal[0] - b0[0] * normal[2];
1313 b1[2] = b0[0] * normal[1] - b0[1] * normal[0];
1320 for (
unsigned j = 0; j < nnod; j++)
1327 delta[0] = nod_pt->
x(0) - lower_left_node_pt->
x(0);
1328 delta[1] = nod_pt->
x(1) - lower_left_node_pt->
x(1);
1329 delta[2] = nod_pt->
x(2) - lower_left_node_pt->
x(2);
1338 zeta[0] = delta[0] * b0[0] + delta[1] * b0[1] + delta[2] * b0[2];
1339 zeta[1] = delta[0] * b1[0] + delta[1] * b1[1] + delta[2] * b1[2];
1342 double error = pow(lower_left_node_pt->
x(0) + zeta[0] * b0[0] +
1343 zeta[1] * b1[0] - nod_pt->
x(0),
1345 pow(lower_left_node_pt->
x(1) + zeta[0] * b0[1] +
1346 zeta[1] * b1[1] - nod_pt->
x(1),
1348 pow(lower_left_node_pt->
x(2) + zeta[0] * b0[2] +
1349 zeta[1] * b1[2] - nod_pt->
x(2),
1354 std::ostringstream error_message;
1356 <<
"Error in projection of boundary coordinates = "
1357 << sqrt(error) <<
" > Tolerance_for_boundary_finding = "
1359 <<
"nv = " << nv << std::endl
1360 <<
"Lower left: " << lower_left_node_pt->
x(0) <<
" "
1361 << lower_left_node_pt->
x(1) <<
" " << lower_left_node_pt->
x(2)
1363 <<
"Upper right: " << upper_right_node_pt->
x(0) <<
" "
1364 << upper_right_node_pt->
x(1) <<
" " << upper_right_node_pt->
x(2)
1367 for (
unsigned j = 0; j < nnod; j++)
1371 error_message << nod_pt->
x(0) <<
" " << nod_pt->
x(1) <<
" "
1372 << nod_pt->
x(2) <<
" " << std::endl;
1375 OOMPH_CURRENT_FUNCTION,
1376 OOMPH_EXCEPTION_LOCATION);
1380 if (do_for_real == 1)
1390 if (do_for_real == 1)
1401 for (
unsigned j = 0; j < 3; j++)
1408 delta[0] = f_pt->
vertex_pt(j)->
x(0) - lower_left_node_pt->
x(0);
1409 delta[1] = f_pt->
vertex_pt(j)->
x(1) - lower_left_node_pt->
x(1);
1410 delta[2] = f_pt->
vertex_pt(j)->
x(2) - lower_left_node_pt->
x(2);
1414 zeta[0] = delta[0] * b0[0] + delta[1] * b0[1] + delta[2] * b0[2];
1415 zeta[1] = delta[0] * b1[0] + delta[1] * b1[1] + delta[2] * b1[2];
1417 for (
unsigned ii = 0; ii < 2; ii++)
1428 unsigned n = face_el_pt.size();
1429 for (
unsigned e = 0;
e < n;
e++)
1431 delete face_el_pt[
e];
1435 if (!vertices_are_in_same_plane)
1458 template<
class ELEMENT>
1462 const bool& switch_normal,
1469 std::ofstream the_file_non_snapped;
1471 "non_snapped_nodes_" + doc_info.
label() +
".dat";
1474 std::ifstream infile(quadratic_surface_file_name.c_str(),
1480 infile.getline(dummy, 100);
1487 infile.getline(dummy, 100);
1490 if (nel != boundary_id.size())
1492 std::ostringstream error_message;
1493 error_message <<
"Number of quadratic facets specified in "
1494 << quadratic_surface_file_name <<
"is: " << nel
1495 <<
"\nThis doesn't match the number of planar boundaries \n"
1496 <<
"specified in boundary_id which is "
1497 << boundary_id.size() << std::endl;
1499 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1506 for (
unsigned e = 0;
e < nel;
e++)
1514 unsigned n_position_type = 1;
1515 unsigned initial_n_value = 0;
1518 std::map<unsigned, unsigned> node_number;
1519 std::ofstream node_file;
1520 for (
unsigned j = 0; j < n_node; j++)
1524 infile >> nod_pt[j]->x(0);
1525 infile >> nod_pt[j]->x(1);
1526 infile >> nod_pt[j]->x(2);
1527 infile >> node_nmbr;
1528 node_number[node_nmbr] = j;
1535 for (
unsigned e = 0;
e < nel;
e++)
1537 unsigned nnod_el = face_el_pt[
e]->nnode();
1539 for (
unsigned j = 0; j < nnod_el; j++)
1542 face_el_pt[
e]->node_pt(j) = nod_pt[node_number[j_global]];
1543 face_el_pt[
e]->node_pt(j)->add_to_boundary(boundary_id[
e]);
1545 face_el_pt[
e]->set_boundary_number_in_bulk_mesh(boundary_id[
e]);
1546 face_el_pt[
e]->set_nodal_dimension(3);
1555 for (
unsigned e = 0;
e < nel;
e++)
1560 Node* lower_left_node_pt = face_el_pt[
e]->node_pt(0);
1561 Node* upper_right_node_pt = face_el_pt[
e]->node_pt(0);
1564 for (
unsigned j = 0; j < 3; j++)
1567 Node* nod_pt = face_el_pt[
e]->node_pt(j);
1570 if (nod_pt->
x(2) < lower_left_node_pt->
x(2))
1572 lower_left_node_pt = nod_pt;
1575 else if (nod_pt->
x(2) == lower_left_node_pt->
x(2))
1578 if (nod_pt->
x(1) < lower_left_node_pt->
x(1))
1580 lower_left_node_pt = nod_pt;
1583 else if (nod_pt->
x(1) == lower_left_node_pt->
x(1))
1586 if (nod_pt->
x(0) < lower_left_node_pt->
x(0))
1588 lower_left_node_pt = nod_pt;
1595 if (nod_pt->
x(2) > upper_right_node_pt->
x(2))
1597 upper_right_node_pt = nod_pt;
1600 else if (nod_pt->
x(2) == upper_right_node_pt->
x(2))
1603 if (nod_pt->
x(1) > upper_right_node_pt->
x(1))
1605 upper_right_node_pt = nod_pt;
1608 else if (nod_pt->
x(1) == upper_right_node_pt->
x(1))
1611 if (nod_pt->
x(0) > upper_right_node_pt->
x(0))
1613 upper_right_node_pt = nod_pt;
1624 b0[0] = upper_right_node_pt->
x(0) - lower_left_node_pt->
x(0);
1625 b0[1] = upper_right_node_pt->
x(1) - lower_left_node_pt->
x(1);
1626 b0[2] = upper_right_node_pt->
x(2) - lower_left_node_pt->
x(2);
1630 1.0 / sqrt(b0[0] * b0[0] + b0[1] * b0[1] + b0[2] * b0[2]);
1631 b0[0] *= inv_length;
1632 b0[1] *= inv_length;
1633 b0[2] *= inv_length;
1643 face_el_pt[
e]->node_pt(1)->x(0) - face_el_pt[
e]->node_pt(0)->x(0);
1645 face_el_pt[
e]->node_pt(1)->x(1) - face_el_pt[
e]->node_pt(0)->x(1);
1647 face_el_pt[
e]->node_pt(1)->x(2) - face_el_pt[
e]->node_pt(0)->x(2);
1649 face_el_pt[
e]->node_pt(2)->x(0) - face_el_pt[
e]->node_pt(0)->x(0);
1651 face_el_pt[
e]->node_pt(2)->x(1) - face_el_pt[
e]->node_pt(0)->x(1);
1653 face_el_pt[
e]->node_pt(2)->x(2) - face_el_pt[
e]->node_pt(0)->x(2);
1654 normal[0] = -(tang1[1] * tang2[2] - tang1[2] * tang2[1]);
1655 normal[1] = -(tang1[2] * tang2[0] - tang1[0] * tang2[2]);
1656 normal[2] = -(tang1[0] * tang2[1] - tang1[1] * tang2[0]);
1659 inv_length = 1.0 / sqrt(normal[0] * normal[0] + normal[1] * normal[1] +
1660 normal[2] * normal[2]);
1661 normal[0] *= inv_length;
1662 normal[1] *= inv_length;
1663 normal[2] *= inv_length;
1668 normal[0] = -normal[0];
1669 normal[1] = -normal[1];
1670 normal[2] = -normal[2];
1675 b1[0] = b0[1] * normal[2] - b0[2] * normal[1];
1676 b1[1] = b0[2] * normal[0] - b0[0] * normal[2];
1677 b1[2] = b0[0] * normal[1] - b0[1] * normal[0];
1680 for (
unsigned j = 0; j < 3; j++)
1683 Node* nod_pt = face_el_pt[
e]->node_pt(j);
1687 delta[0] = nod_pt->
x(0) - lower_left_node_pt->
x(0);
1688 delta[1] = nod_pt->
x(1) - lower_left_node_pt->
x(1);
1689 delta[2] = nod_pt->
x(2) - lower_left_node_pt->
x(2);
1692 zeta[0] = delta[0] * b0[0] + delta[1] * b0[1] + delta[2] * b0[2];
1693 zeta[1] = delta[0] * b1[0] + delta[1] * b1[1] + delta[2] * b1[2];
1695 vertex_boundary_coord[j].resize(2);
1696 vertex_boundary_coord[j][0] = zeta[0];
1697 vertex_boundary_coord[j][1] = zeta[1];
1702 double error = pow(lower_left_node_pt->
x(0) + zeta[0] * b0[0] +
1703 zeta[1] * b1[0] - nod_pt->
x(0),
1705 pow(lower_left_node_pt->
x(1) + zeta[0] * b0[1] +
1706 zeta[1] * b1[1] - nod_pt->
x(1),
1708 pow(lower_left_node_pt->
x(2) + zeta[0] * b0[2] +
1709 zeta[1] * b1[2] - nod_pt->
x(2),
1714 std::ostringstream error_message;
1716 <<
"Error in setup of boundary coordinate " << sqrt(error)
1718 <<
"exceeds tolerance specified by the static member data\n"
1719 <<
"TetMeshBase::Tolerance_for_boundary_finding = "
1721 <<
"This usually means that the boundary is not planar.\n\n"
1722 <<
"You can suppress this error message by recompiling \n"
1723 <<
"recompiling without PARANOID or by changing the tolerance.\n";
1725 OOMPH_CURRENT_FUNCTION,
1726 OOMPH_EXCEPTION_LOCATION);
1739 0.5 * (vertex_boundary_coord[0][0] + vertex_boundary_coord[1][0]);
1741 0.5 * (vertex_boundary_coord[0][1] + vertex_boundary_coord[1][1]);
1742 face_el_pt[
e]->node_pt(3)->set_coordinates_on_boundary(boundary_id[
e],
1747 0.5 * (vertex_boundary_coord[1][0] + vertex_boundary_coord[2][0]);
1749 0.5 * (vertex_boundary_coord[1][1] + vertex_boundary_coord[2][1]);
1750 face_el_pt[
e]->node_pt(4)->set_coordinates_on_boundary(boundary_id[
e],
1755 0.5 * (vertex_boundary_coord[2][0] + vertex_boundary_coord[0][0]);
1757 0.5 * (vertex_boundary_coord[2][1] + vertex_boundary_coord[0][1]);
1758 face_el_pt[
e]->node_pt(5)->set_coordinates_on_boundary(boundary_id[
e],
1764 bool success =
true;
1765 for (
unsigned b = 0; b < nel; b++)
1768 std::ofstream the_file;
1769 std::ofstream the_file_before;
1770 std::ofstream the_file_after;
1773 std::ostringstream filename;
1774 filename << doc_info.
directory() <<
"/quadratic_coordinates_"
1775 << doc_info.
label() << b <<
".dat";
1776 the_file.open(filename.str().c_str());
1778 std::ostringstream filename1;
1779 filename1 << doc_info.
directory() <<
"/quadratic_nodes_before_"
1780 << doc_info.
label() << b <<
".dat";
1781 the_file_before.open(filename1.str().c_str());
1783 std::ostringstream filename2;
1784 filename2 << doc_info.
directory() <<
"/quadratic_nodes_after_"
1785 << doc_info.
label() << b <<
".dat";
1786 the_file_after.open(filename2.str().c_str());
1798 unsigned n_plot = 3;
1799 the_file << el_pt->tecplot_zone_string(n_plot);
1802 unsigned num_plot_points = el_pt->nplot_points(n_plot);
1803 for (
unsigned iplot = 0; iplot < num_plot_points; iplot++)
1806 el_pt->get_s_plot(iplot, n_plot,
s);
1807 el_pt->interpolated_zeta(
s, zeta);
1808 el_pt->interpolated_x(
s, x);
1809 for (
unsigned i = 0;
i < 3;
i++)
1811 the_file << x[
i] <<
" ";
1813 for (
unsigned i = 0;
i < 2;
i++)
1815 the_file << zeta[
i] <<
" ";
1817 the_file << std::endl;
1819 el_pt->write_tecplot_zone_footer(the_file, n_plot);
1835 for (
unsigned e = 0;
e < nel;
e++)
1842 unsigned nnod = bulk_elem_pt->
nnode();
1843 for (
unsigned j = 0; j < nnod; j++)
1853 the_file_before << nod_pt->
x(0) <<
" " << nod_pt->
x(1) <<
" "
1854 << nod_pt->
x(2) <<
" " << boundary_zeta[0] <<
" "
1855 << boundary_zeta[1] <<
" " << std::endl;
1859 el_pt->locate_zeta(boundary_zeta, geom_obj_pt, s_geom_obj);
1860 if (geom_obj_pt != 0)
1862 geom_obj_pt->
position(s_geom_obj, quadratic_coordinates);
1863 nod_pt->
x(0) = quadratic_coordinates[0];
1864 nod_pt->
x(1) = quadratic_coordinates[1];
1865 nod_pt->
x(2) = quadratic_coordinates[2];
1872 std::ostringstream error_message;
1874 <<
"Warning: Couldn't find GeomObject during snapping to\n"
1875 <<
"quadratic surface for boundary " << boundary_id[b]
1876 <<
". I'm leaving the node where it was. Will bail out "
1879 "TetgenMesh::snap_to_quadratic_surface()",
1880 OOMPH_EXCEPTION_LOCATION);
1881 if (!the_file_non_snapped.is_open())
1883 the_file_non_snapped.open(non_snapped_filename.c_str());
1885 the_file_non_snapped << nod_pt->
x(0) <<
" " << nod_pt->
x(1) <<
" "
1886 << nod_pt->
x(2) <<
" " << boundary_zeta[0]
1887 <<
" " << boundary_zeta[1] <<
" "
1894 the_file_after << nod_pt->
x(0) <<
" " << nod_pt->
x(1) <<
" "
1895 << nod_pt->
x(2) <<
" " << boundary_zeta[0] <<
" "
1896 << boundary_zeta[1] <<
" " << std::endl;
1904 the_file_before.close();
1905 the_file_after.close();
1911 std::ostringstream error_message;
1913 <<
"Warning: Couldn't find GeomObject during snapping to\n"
1914 <<
"quadratic surface. Bailing out.\n"
1915 <<
"Nodes that couldn't be snapped are contained in \n"
1916 <<
"file: " << non_snapped_filename <<
".\n"
1917 <<
"This problem may arise because the switch_normal flag was \n"
1918 <<
"set wrongly.\n";
1920 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1924 if (!the_file_non_snapped.is_open())
1926 the_file_non_snapped.close();
1930 for (
unsigned e = 0;
e < nel;
e++)
1932 delete face_el_pt[
e];
1937 unsigned nn = nod_pt.size();
1938 for (
unsigned j = 0; j < nn; j++)
1949 template<
class ELEMENT>
1964 if ((nnode_1d != 2) && (nnode_1d != 3))
1966 std::ostringstream error_message;
1967 error_message <<
"Mesh generation from tetgen currently only works\n";
1968 error_message <<
"for nnode_1d = 2 or 3. You're trying to use it\n";
1969 error_message <<
"for nnode_1d=" << nnode_1d << std::endl;
1972 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1976 std::map<FiniteElement*, unsigned> count;
1980 for (
unsigned b = 0; b < nb; b++)
1984 for (
unsigned e = 0;
e < nel;
e++)
1997 std::set<FiniteElement*> elements_to_be_split;
1998 for (std::map<FiniteElement*, unsigned>::iterator it = count.begin();
2008 elements_to_be_split.insert(el_pt);
2015 new_or_retained_el_pt.reserve(nel);
2019 std::map<FiniteElement*, Vector<FiniteElement*>>
2020 old_to_new_corner_element_map;
2023 for (
unsigned e = 0;
e < nel;
e++)
2029 std::set<FiniteElement*>::iterator it = std::find(
2030 elements_to_be_split.begin(), elements_to_be_split.end(), el_pt);
2033 if (it == elements_to_be_split.end())
2036 new_or_retained_el_pt.push_back(el_pt);
2053 Node* node10_pt = 0;
2074 node0_pt = el_pt->
node_pt(14);
2075 el1_pt->
node_pt(2) = node0_pt;
2117 el2_pt->
node_pt(3) = node0_pt;
2120 el2_pt->
node_pt(6) = node1_pt;
2121 el2_pt->
node_pt(9) = node2_pt;
2127 el2_pt->
node_pt(10) = node5_pt;
2148 el3_pt->
node_pt(0) = node0_pt;
2151 el3_pt->
node_pt(4) = node2_pt;
2152 el3_pt->
node_pt(5) = node3_pt;
2153 el3_pt->
node_pt(6) = node4_pt;
2159 el3_pt->
node_pt(10) = node6_pt;
2160 el3_pt->
node_pt(11) = node10_pt;
2181 el4_pt->
node_pt(1) = node0_pt;
2184 el4_pt->
node_pt(4) = node1_pt;
2185 el4_pt->
node_pt(7) = node3_pt;
2186 el4_pt->
node_pt(9) = node4_pt;
2192 el4_pt->
node_pt(10) = node9_pt;
2193 el4_pt->
node_pt(11) = node8_pt;
2195 el4_pt->
node_pt(13) = node7_pt;
2201 new_or_retained_el_pt.push_back(el1_pt);
2202 new_or_retained_el_pt.push_back(el2_pt);
2203 new_or_retained_el_pt.push_back(el3_pt);
2204 new_or_retained_el_pt.push_back(el4_pt);
2208 temp_vec[0] = el1_pt;
2209 temp_vec[1] = el2_pt;
2210 temp_vec[2] = el3_pt;
2211 temp_vec[3] = el4_pt;
2214 old_to_new_corner_element_map.insert(
2235 for (
unsigned i = 0;
i < 3;
i++)
2247 node1_pt->
x(
i) = 0.5 * (el_pt->
node_pt(0)->
x(
i) + node0_pt->
x(
i));
2248 node2_pt->
x(
i) = 0.5 * (el_pt->
node_pt(1)->
x(
i) + node0_pt->
x(
i));
2249 node3_pt->
x(
i) = 0.5 * (el_pt->
node_pt(2)->
x(
i) + node0_pt->
x(
i));
2250 node4_pt->
x(
i) = 0.5 * (el_pt->
node_pt(3)->
x(
i) + node0_pt->
x(
i));
2261 for (
unsigned i = 0;
i < 3; ++
i)
2270 for (
unsigned i = 0;
i < 3; ++
i)
2279 for (
unsigned i = 0;
i < 3; ++
i)
2288 for (
unsigned i = 0;
i < 3; ++
i)
2297 for (
unsigned i = 0;
i < 3; ++
i)
2306 for (
unsigned i = 0;
i < 3; ++
i)
2318 for (
unsigned i = 0;
i < 3; ++
i)
2320 double av_pos = 0.0;
2321 for (
unsigned j = 0; j < 4; j++)
2326 temp_nod_pt->
x(
i) = 0.25 * av_pos;
2333 for (
unsigned i = 0;
i < 3; ++
i)
2335 double av_pos = 0.0;
2336 for (
unsigned j = 0; j < 4; j++)
2340 temp_nod_pt->
x(
i) = 0.25 * av_pos;
2346 for (
unsigned i = 0;
i < 3; ++
i)
2348 double av_pos = 0.0;
2349 for (
unsigned j = 0; j < 4; j++)
2353 temp_nod_pt->
x(
i) = 0.25 * av_pos;
2359 for (
unsigned i = 0;
i < 3; ++
i)
2361 double av_pos = 0.0;
2362 for (
unsigned j = 0; j < 4; j++)
2366 temp_nod_pt->
x(
i) = 0.25 * av_pos;
2380 nel = new_or_retained_el_pt.size();
2382 for (
unsigned e = 0;
e < nel;
e++)
2413 if (old_to_new_corner_element_map.size() == 0)
2415 oomph_info <<
"\nNo corner elements need splitting\n\n";
2424 old_to_new_corner_element_map.begin();
2425 map_it != old_to_new_corner_element_map.end();
2432 unsigned original_region_index = 0;
2458 original_region_index = region_index;
2473 std::ostringstream error_message;
2475 <<
"The corner element being split does not appear to be in any "
2476 <<
"region, so something has gone wrong with the region lookup "
2480 OOMPH_CURRENT_FUNCTION,
2481 OOMPH_EXCEPTION_LOCATION);
2488 for (
unsigned i = 0;
i < 4;
i++)
2502 for (
unsigned b = 0; b <
nboundary(); b++)
2506 for (
unsigned e = 0;
e < nel;
e++)
2533 oomph_info <<
"\nNumber of outer corner elements split: "
2534 << old_to_new_corner_element_map.size() <<
"\n\n";
A template Class for BoundaryNodes; that is Nodes that MAY live on the boundary of a Mesh....
Base class for upgraded disk-like GeomObject (i.e. 2D surface in 3D space) with specification of boun...
Information for documentation of results: Directory and file number to enable output in the form RESL...
bool is_doc_enabled() const
Are we documenting?
void disable_doc()
Disable documentation.
std::string & label()
String used (e.g.) for labeling output files.
std::string directory() const
Output directory.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
A general Finite Element class.
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
unsigned nnode() const
Return the number of nodes.
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overload...
virtual Node * construct_boundary_node(const unsigned &n)
Construct the local node n as a boundary node; that is a node that MAY be placed on a mesh boundary a...
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
/////////////////////////////////////////////////////////////////////
virtual void position(const Vector< double > &zeta, Vector< double > &r) const =0
Parametrised position on object at current time: r(zeta).
unsigned long nboundary_node(const unsigned &ibound) const
Return number of nodes on a particular boundary.
static Steady< 0 > Default_TimeStepper
Default Steady Timestepper, to be used in default arguments to Mesh constructors.
bool Lookup_for_elements_next_boundary_is_setup
Flag to indicate that the lookup schemes for elements that are adjacent to the boundaries has been se...
std::vector< bool > Boundary_coordinate_exists
Vector of boolean data that indicates whether the boundary coordinates have been set for the boundary...
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.
unsigned long nnode() const
Return number of nodes in the mesh.
void add_node_pt(Node *const &node_pt)
Add a (pointer to a) node to the mesh.
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Vector< GeneralisedElement * > Element_pt
Vector of pointers to generalised elements.
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 bool is_on_boundary() const
Test whether the Node lies on a boundary. The "bulk" Node cannot lie on a boundary,...
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
virtual void set_coordinates_on_boundary(const unsigned &b, const unsigned &k, const Vector< double > &boundary_zeta)
Set the vector of the k-th generalised boundary coordinates on mesh boundary b. Broken virtual interf...
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....
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
virtual ~TetMeshBase()
Destructor (empty)
void snap_nodes_onto_geometric_objects()
Move the nodes on boundaries with associated GeomObjects so that they exactly coincide with the geome...
void snap_to_quadratic_surface(const Vector< unsigned > &boundary_id, const std::string &quadratic_surface_file_name, const bool &switch_normal, DocInfo &doc_info)
Snap boundaries specified by the IDs listed in boundary_id to a quadratric surface,...
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.
Vector< double > Region_attribute
Vector of attributes associated with the elements in each region NOTE: double is enforced on us by te...
double region_attribute(const unsigned &i)
Return the i-th region attribute (here only used as the (assumed to be unsigned) region id.
void setup_boundary_coordinates(const unsigned &b, const bool &switch_normal)
Setup boundary coordinate on boundary b which is assumed to be planar. Boundary coordinates are the x...
unsigned nregion()
Return the number of regions specified by attributes.
TimeStepper * Time_stepper_pt
Timestepper used to build nodes.
unsigned nboundary_element_in_region(const unsigned &b, const unsigned &r) const
Return the number of elements adjacent to boundary b in region r.
std::map< unsigned, TetMeshFacetedSurface * > Tet_mesh_faceted_surface_pt
Reverse lookup scheme: Pointer to faceted surface (if any!) associated with boundary b.
Vector< TetMeshFacetedSurface * > Internal_surface_pt
Vector to faceted surfaces that define internal boundaries.
Vector< std::map< unsigned, Vector< FiniteElement * > > > Boundary_region_element_pt
Storage for elements adjacent to a boundary in a particular region.
void operator=(const TetMeshBase &)=delete
Broken assignment operator.
std::map< unsigned, TetMeshFacet * > Tet_mesh_facet_pt
Reverse lookup scheme: Pointer to facet (if any!) associated with boundary b.
void setup_boundary_coordinates(const unsigned &b)
Setup boundary coordinate on boundary b which is assumed to be planar. Boundary coordinates are the x...
TetMeshFacetedClosedSurface * Outer_boundary_pt
Faceted surface that defines outer boundaries.
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.
static double Tolerance_for_boundary_finding
Global static data that specifies the permitted error in the setup of the boundary coordinates.
void assess_mesh_quality(std::ofstream &some_file)
Assess mesh quality: Ratio of max. edge length to min. height, so if it's very large it's BAAAAAD.
FiniteElement * region_element_pt(const unsigned &r, const unsigned &e)
Return the e-th element in the r-th region.
TetMeshBase()
Constructor.
void snap_to_quadratic_surface(const Vector< unsigned > &boundary_id, const std::string &quadratic_surface_file_name, const bool &switch_normal)
Snap boundaries specified by the IDs listed in boundary_id to a quadratric surface,...
void setup_boundary_element_info()
Setup lookup schemes which establish which elements are located next to mesh's boundaries (wrapper to...
Vector< std::map< unsigned, Vector< int > > > Face_index_region_at_boundary
Storage for the face index adjacent to a boundary in a particular region.
std::map< unsigned, Vector< Vector< double > > > Triangular_facet_vertex_boundary_coordinate
Boundary coordinates of vertices in triangular facets associated with given boundary....
TetMeshBase(const TetMeshBase &node)=delete
Broken copy constructor.
Vector< Vector< FiniteElement * > > Region_element_pt
Vectors of vectors of elements in each region (note: this just stores them; the region IDs are contai...
void split_elements_in_corners(TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Non-Delaunay split elements that have three faces on a boundary into sons. Timestepper species timest...
void setup_boundary_coordinates(const unsigned &b, std::ofstream &outfile)
Setup boundary coordinate on boundary b which is assumed to be planar. Boundary coordinates are the x...
unsigned nregion_element(const unsigned &r)
Return the number of elements in region r.
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
Vector< TetMeshVertex * > Vertex_pt
Pointer to vertices.
void set_vertex_pt(const unsigned &j, TetMeshVertex *vertex_pt)
Set pointer to j-th vertex and pass one-based boundary id that may already have been set for this fac...
TetMeshVertex * vertex_pt(const unsigned &j) const
Pointer to j-th vertex (const)
void output(std::ostream &outfile) const
Output.
void set_one_based_region_that_facet_is_embedded_in(const unsigned &one_based_region_id)
Facet is to be embedded in specified one-based region.
std::set< unsigned > One_based_adjacent_region_id
Set of one-based adjacent region ids; no adjacent region if it's zero.
bool facet_is_embedded_in_a_specified_region()
Boolean indicating that facet is embedded in a specified region.
void set_one_based_boundary_id(const unsigned &one_based_id)
Set (one-based!) boundary IDs this facet lives on. Passed to any existing vertices and to any future ...
unsigned one_based_boundary_id() const
Constant access to (one-based!) boundary IDs this facet lives on.
unsigned nvertex() const
Number of vertices.
unsigned One_based_boundary_id
(One-based!) boundary IDs this facet lives on
unsigned One_based_region_id_that_facet_is_embedded_in
Facet is to be embedded in specified one-based region. Defaults to zero, indicating that its not embe...
void set_one_based_adjacent_region_id(const unsigned &one_based_id)
Set (one-based!) region ID this facet is adjacent to. Specification of zero argument is harmless as i...
unsigned one_based_region_that_facet_is_embedded_in()
Which (one-based) region is facet embedded in (if zero, it's not embedded in any region)
std::set< unsigned > one_based_adjacent_region_id() const
Return set of (one-based!) region IDs this facet is adjacent to.
TetMeshFacet(const unsigned &nvertex)
Constructor: Specify number of vertices.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
virtual ~TetMeshFacetedClosedSurfaceForRemesh()
Destructor. Delete allocated memory.
TetMeshFacetedClosedSurfaceForRemesh(Vector< Node * > const &vertex_node_pt, Vector< Vector< unsigned >> const &facet_connectivity, Vector< unsigned > const &facet_boundary_id)
Constructor for a FacetedSurface created from a list of nodes and connectivity information....
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
TetMeshFacetedClosedSurface()
Constructor:
bool Faceted_volume_represents_hole_for_gmsh
Does closed surface represent hole for gmsh?
void enable_faceted_volume_represents_hole_for_gmsh()
Declare closed surface to represent hole for gmsh.
const int & region_id_for_tetgen(const unsigned &j) const
Return the (zero-based) region ID of j-th internal point for tetgen. Negative if it's actually a hole...
bool faceted_volume_represents_hole_for_gmsh() const
Does closed surface represent hole for gmsh?
Vector< std::pair< Vector< double >, int > > Internal_point_for_tetgen
Storage for internal points for tetgen. Stores pair of: – Vector containing coordinates of internal p...
virtual ~TetMeshFacetedClosedSurface()
Empty destructor.
unsigned ninternal_point_for_tetgen()
Number of internal points (identifying either regions or holes) for tetgen.
bool internal_point_identifies_region_for_tetgen(const unsigned &j)
Is j-th internal point for tetgen associated with a region?
bool internal_point_identifies_hole_for_tetgen(const unsigned &j)
Is j-th internal point for tetgen associated with a hole?
const double & internal_point_for_tetgen(const unsigned &j, const unsigned &i) const
i=th coordinate of the j-th internal point for tetgen
void disable_faceted_volume_represents_hole_for_gmsh()
Declare closed surface NOT to represent hole for gmsh.
void set_region_for_tetgen(const unsigned ®ion_id, const Vector< double > ®ion_point)
Specify a region; pass (zero-based) region ID and coordinate of point in region for tetgen.
void set_hole_for_tetgen(const Vector< double > &hole_point)
Specify coordinate of hole for tetgen.
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
unsigned nvertex_on_facet(const unsigned &j) const
Number of vertices defining the j-th facet.
bool Boundaries_can_be_split_in_tetgen
Boolean to indicate whether extra vertices can be added on the boundary in tetgen.
void disable_boundaries_can_be_split_in_tetgen()
Test whether boundaries can be split in tetgen.
virtual void boundary_zeta01(const unsigned &facet_id, const double &zeta_boundary, Vector< double > &zeta)
Virtual function that specifies the variation of the zeta coordinates in the GeomObject along the bou...
Vector< TetMeshVertex * > Vertex_pt
Vector pointers to vertices.
unsigned nfacet() const
Number of facets.
Vector< Vector< unsigned > > Facet_vertex_index_in_tetgen
Facet connectivity: Facet_vertex_index[f][j] is the index of the j-th vertex (in the Vertex_pt vector...
DiskLikeGeomObjectWithBoundaries * Geom_object_with_boundaries_pt
GeomObject with boundaries associated with this surface.
virtual void boundary_zeta12(const unsigned &facet_id, const double &zeta_boundary, Vector< double > &zeta)
Virtual function that specifies the variation of the zeta coordinates in the GeomObject along the bou...
bool boundaries_can_be_split_in_tetgen()
Test whether boundary can be split in tetgen.
Vector< TetMeshFacet * > Facet_pt
Vector of pointers to facets.
unsigned one_based_facet_boundary_id(const unsigned &j) const
One-based boundary id of j-th facet.
TetMeshFacet * facet_pt(const unsigned &j) const
Pointer to j-th facet.
Vector< unsigned > vertex_index_in_tetgen(const unsigned &f)
Facet connectivity: vertex_index[j] is the index of the j-th vertex (in the Vertex_pt vector) in face...
void enable_boundaries_can_be_split_in_tetgen()
Test whether boundaries can be split in tetgen.
virtual void boundary_zeta20(const unsigned &facet_id, const double &zeta_boundary, Vector< double > &zeta)
Virtual function that specifies the variation of the zeta coordinates in the GeomObject along the bou...
void setup_facet_connectivity_for_tetgen()
Setup facet connectivity for tetgen.
double vertex_coordinate(const unsigned &j, const unsigned &i) const
i-th coordinate of j-th vertex
unsigned nvertex() const
Number of vertices.
TetMeshFacetedSurface()
Constructor:
void output(const std::string &filename) const
Output.
TetMeshVertex * vertex_pt(const unsigned &j) const
Pointer to j-th vertex.
void output(std::ostream &outfile) const
Output.
virtual ~TetMeshFacetedSurface()
Empty destructor.
DiskLikeGeomObjectWithBoundaries * geom_object_with_boundaries_pt()
Access to GeomObject with boundaries associated with this surface (Null if there isn't one!...
unsigned one_based_vertex_boundary_id(const unsigned &j) const
First (of possibly multiple) one-based boundary id of j-th vertex.
Vertex for Tet mesh generation. Can lie on multiple boundaries (identified via one-based enumeration!...
void set_zeta_in_geom_object(const Vector< double > &zeta)
Set intrinisic coordinates in GeomObject.
Vector< double > X
Coordinate vector.
TetMeshVertex(Node *const &node_pt)
Vector< double > zeta_in_geom_object() const
Get intrinisic coordinates in GeomObject (returns zero sized vector if no such coordinates have been ...
std::set< unsigned > One_based_boundary_id
Set of (one-based!) boundary IDs this vertex lives on.
unsigned one_based_boundary_id() const
First (of possibly multiple) one-based boundary id.
Vector< double > Zeta_in_geom_object
Intrinisic coordinates in GeomObject (zero sized if there isn't one.
void set_one_based_boundary_id(const unsigned &id)
Set of (one-based!) boundary IDs this vertex lives on.
double x(const unsigned &i) const
i-th coordinate
TetMeshVertex(const Vector< double > &x)
Constructor: Pass coordinates (length 3!)
////////////////////////////////////////////////////////////////////// //////////////////////////////...
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...