41#include <gsl/gsl_sys.h>
45#define SQR(x) ((x)*(x))
46#define PointID(triangle_id, vertex_id) Triangles_m[triangle_id][vertex_id]
47#define Point(triangle_id, vertex_id) Points_m[Triangles_m[triangle_id][vertex_id]]
61#define FUNC_EQ(x, y) inline bool eq(double x, double y) { \
62 return almost_eq(x, y); \
65#define FUNC_EQ_ZERO(x) inline bool eq_zero(double x) { \
66 return almost_eq_zero(x); \
69#define FUNC_LE(x, y) inline bool le(double x, double y) { \
70 if (almost_eq(x, y)) { \
76#define FUNC_LE_ZERO(x) inline bool le_zero(double x) { \
77 if (almost_eq_zero(x)) { \
83#define FUNC_LT(x, y) inline bool lt(double x, double y) { \
84 if (almost_eq(x, y)) { \
90#define FUNC_LT_ZERO(x) inline bool lt_zero(double x) { \
91 if (almost_eq_zero(x)) { \
97#define FUNC_GE(x, y) inline bool ge(double x, double y) { \
98 if (almost_eq(x, y)) { \
104#define FUNC_GE_ZERO(x) inline bool ge_zero(double x) { \
105 if (almost_eq_zero(x)) { \
111#define FUNC_GT(x, y) inline bool gt(double x, double y) { \
112 if (almost_eq(x, y)) { \
118#define FUNC_GT_ZERO(x) inline bool gt_zero(double x) { \
119 if (almost_eq_zero(x)) { \
131 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-15,
double maxRelDiff = DBL_EPSILON) {
134 const double diff = std::abs(A - B);
140 const double largest = (B > A) ? B : A;
142 if (diff <= largest * maxRelDiff)
148 const double diff = std::abs(A);
149 return (diff <= maxDiff);
169 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
176 if (std::isnan(A) || std::isnan(B)) {
180 if (std::abs (A - B) <= maxDiff) {
184#pragma GCC diagnostic push
185#pragma GCC diagnostic ignored "-Wstrict-aliasing"
186 auto aInt = *(int64_t*)&A;
187#pragma GCC diagnostic pop
190 aInt = 0x8000000000000000 - aInt;
193#pragma GCC diagnostic push
194#pragma GCC diagnostic ignored "-Wstrict-aliasing"
195 auto bInt = *(int64_t*)&B;
196#pragma GCC diagnostic pop
199 bInt = 0x8000000000000000 - bInt;
202 if (std::abs (aInt - bInt) <= maxUlps) {
210 return (std::abs(A) <= maxDiff);
231 inline bool almost_eq (
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
233 if (std::isnan (A) || std::isnan (B)) {
239 if (std::abs (A - B) <= maxDiff)
242#pragma GCC diagnostic push
243#pragma GCC diagnostic ignored "-Wstrict-aliasing"
244 auto aInt = *(int64_t*)&A;
245 auto bInt = *(int64_t*)&B;
246#pragma GCC diagnostic pop
250 if (std::signbit (aInt) != std::signbit (bInt))
254 return (std::abs (aInt - bInt) <= maxUlps);
258 return (std::abs (A) <= maxDiff);
307Vector_t get_max_extent (std::vector<Vector_t>& coords) {
309 coords.begin (), coords.end (), VectorLessX ());
311 coords.begin (), coords.end (), VectorLessY ());
313 coords.begin (), coords.end (), VectorLessZ ());
314 return Vector_t ({x(0), y(1), z(2)});
321Vector_t get_min_extent (std::vector<Vector_t>& coords) {
323 coords.begin (), coords.end (), VectorLessX ());
325 coords.begin (), coords.end (), VectorLessY ());
327 coords.begin (), coords.end (), VectorLessZ ());
328 return Vector_t ({x(0), y(1), z(2)});
334static void write_voxel_mesh (
336 const std::unordered_map<
int, std::unordered_set<int> >& ids,
342 const size_t numpoints = 8 * ids.size ();
345 *
gmsg <<
level2 <<
"* Writing VTK file of voxel mesh '" << fname <<
"'" <<
endl;
350 of <<
"# vtk DataFile Version 2.0" << std::endl;
351 of <<
"generated using BoundaryGeometry::computeMeshVoxelization"
353 of <<
"ASCII" << std::endl << std::endl;
354 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
355 of <<
"POINTS " << numpoints <<
" float" << std::endl;
357 const auto nr0_times_nr1 =
nr[0] *
nr[1];
358 for (
auto& elem: ids) {
359 auto id = elem.first;
360 int k = (
id - 1) / nr0_times_nr1;
361 int rest = (
id - 1) % nr0_times_nr1;
362 int j = rest /
nr[0];
363 int i = rest %
nr[0];
366 P[0] = i * hr_m[0] + origin[0];
367 P[1] = j * hr_m[1] + origin[1];
368 P[2] = k * hr_m[2] + origin[2];
370 of << P[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
371 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
372 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
373 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
374 of << P[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
375 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
376 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
377 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
380 const auto num_cells = ids.size ();
381 of <<
"CELLS " << num_cells <<
" " << 9 * num_cells << std::endl;
382 for (
size_t i = 0; i < num_cells; i++)
384 << 8 * i <<
" " << 8 * i + 1 <<
" " << 8 * i + 2 <<
" " << 8 * i + 3 <<
" "
385 << 8 * i + 4 <<
" " << 8 * i + 5 <<
" " << 8 * i + 6 <<
" " << 8 * i + 7 << std::endl;
386 of <<
"CELL_TYPES " << num_cells << std::endl;
387 for (
size_t i = 0; i < num_cells; i++)
388 of <<
"11" << std::endl;
389 of <<
"CELL_DATA " << num_cells << std::endl;
390 of <<
"SCALARS " <<
"cell_attribute_data" <<
" float " <<
"1" << std::endl;
391 of <<
"LOOKUP_TABLE " <<
"default" << std::endl;
392 for (
size_t i = 0; i < num_cells; i++)
393 of << (
float)(i) << std::endl;
395 of <<
"COLOR_SCALARS " <<
"BBoxColor " << 4 << std::endl;
396 for (
size_t i = 0; i < num_cells; i++) {
397 of <<
"1.0" <<
" 1.0 " <<
"0.0 " <<
"1.0" << std::endl;
428 inline double v1(
int i)
const {
434 inline double v2(
int i)
const {
440 inline double v3(
int i)
const {
449 pts[0][0] *= scaleby[0];
450 pts[0][1] *= scaleby[1];
451 pts[0][2] *= scaleby[2];
452 pts[1][0] *= scaleby[0];
453 pts[1][1] *= scaleby[1];
454 pts[1][2] *= scaleby[2];
455 pts[2][0] *= scaleby[0];
456 pts[2][1] *= scaleby[1];
457 pts[2][2] *= scaleby[2];
475 int outcode_fcmp = 0;
477 if (
cmp::gt(p[0], 0.5)) outcode_fcmp |= 0x01;
478 if (
cmp::lt(p[0], -0.5)) outcode_fcmp |= 0x02;
479 if (
cmp::gt(p[1], 0.5)) outcode_fcmp |= 0x04;
480 if (
cmp::lt(p[1], -0.5)) outcode_fcmp |= 0x08;
481 if (
cmp::gt(p[2], 0.5)) outcode_fcmp |= 0x10;
482 if (
cmp::lt(p[2], -0.5)) outcode_fcmp |= 0x20;
484 return(outcode_fcmp);
495 int outcode_fcmp = 0;
497 if (
cmp::gt( p[0] + p[1], 1.0)) outcode_fcmp |= 0x001;
498 if (
cmp::gt( p[0] - p[1], 1.0)) outcode_fcmp |= 0x002;
499 if (
cmp::gt(-p[0] + p[1], 1.0)) outcode_fcmp |= 0x004;
500 if (
cmp::gt(-p[0] - p[1], 1.0)) outcode_fcmp |= 0x008;
501 if (
cmp::gt( p[0] + p[2], 1.0)) outcode_fcmp |= 0x010;
502 if (
cmp::gt( p[0] - p[2], 1.0)) outcode_fcmp |= 0x020;
503 if (
cmp::gt(-p[0] + p[2], 1.0)) outcode_fcmp |= 0x040;
504 if (
cmp::gt(-p[0] - p[2], 1.0)) outcode_fcmp |= 0x080;
505 if (
cmp::gt( p[1] + p[2], 1.0)) outcode_fcmp |= 0x100;
506 if (
cmp::gt( p[1] - p[2], 1.0)) outcode_fcmp |= 0x200;
507 if (
cmp::gt(-p[1] + p[2], 1.0)) outcode_fcmp |= 0x400;
508 if (
cmp::gt(-p[1] - p[2], 1.0)) outcode_fcmp |= 0x800;
510 return(outcode_fcmp);
521 int outcode_fcmp = 0;
523 if (
cmp::gt( p[0] + p[1] + p[2], 1.5)) outcode_fcmp |= 0x01;
524 if (
cmp::gt( p[0] + p[1] - p[2], 1.5)) outcode_fcmp |= 0x02;
525 if (
cmp::gt( p[0] - p[1] + p[2], 1.5)) outcode_fcmp |= 0x04;
526 if (
cmp::gt( p[0] - p[1] - p[2], 1.5)) outcode_fcmp |= 0x08;
527 if (
cmp::gt(-p[0] + p[1] + p[2], 1.5)) outcode_fcmp |= 0x10;
528 if (
cmp::gt(-p[0] + p[1] - p[2], 1.5)) outcode_fcmp |= 0x20;
529 if (
cmp::gt(-p[0] - p[1] + p[2], 1.5)) outcode_fcmp |= 0x40;
530 if (
cmp::gt(-p[0] - p[1] - p[2], 1.5)) outcode_fcmp |= 0x80;
532 return(outcode_fcmp);
551#define LERP(a, b, t) (a + t * (b - a))
553 plane_point[0] =
LERP(p1[0], p2[0], alpha);
554 plane_point[1] =
LERP(p1[1], p2[1], alpha);
555 plane_point[2] =
LERP(p1[2], p2[2], alpha);
557 return(face_plane(plane_point) & mask);
571 const int outcode_diff
573 if ((0x01 & outcode_diff) != 0)
574 if (check_point(p1,p2,( .5-p1[0])/(p2[0]-p1[0]),0x3e) ==
INSIDE)
return(
INSIDE);
575 if ((0x02 & outcode_diff) != 0)
576 if (check_point(p1,p2,(-.5-p1[0])/(p2[0]-p1[0]),0x3d) ==
INSIDE)
return(
INSIDE);
577 if ((0x04 & outcode_diff) != 0)
578 if (check_point(p1,p2,( .5-p1[1])/(p2[1]-p1[1]),0x3b) ==
INSIDE)
return(
INSIDE);
579 if ((0x08 & outcode_diff) != 0)
580 if (check_point(p1,p2,(-.5-p1[1])/(p2[1]-p1[1]),0x37) ==
INSIDE)
return(
INSIDE);
581 if ((0x10 & outcode_diff) != 0)
582 if (check_point(p1,p2,( .5-p1[2])/(p2[2]-p1[2]),0x2f) ==
INSIDE)
return(
INSIDE);
583 if ((0x20 & outcode_diff) != 0)
584 if (check_point(p1,p2,(-.5-p1[2])/(p2[2]-p1[2]),0x1f) ==
INSIDE)
return(
INSIDE);
592constexpr double EPS = 10e-15;
597 return (((A[0] <
EPS) ? 4 : 0) | ((A[0] > -
EPS) ? 32 : 0) |
598 ((A[1] <
EPS) ? 2 : 0) | ((A[1] > -
EPS) ? 16 : 0) |
599 ((A[2] <
EPS) ? 1 : 0) | ((A[2] > -
EPS) ? 8 : 0));
603point_triangle_intersection (
628 const int sign12 = SIGN3(cross12_1p);
633 const int sign23 = SIGN3(cross23_2p);
638 const int sign31 = SIGN3(cross31_3p);
658triangle_intersects_cube (
677 if ((v1_test & v2_test & v3_test) != 0)
return(
OUTSIDE);
682 v1_test |= bevel_2d(t.
v1()) << 8;
683 v2_test |= bevel_2d(t.
v2()) << 8;
684 v3_test |= bevel_2d(t.
v3()) << 8;
685 if ((v1_test & v2_test & v3_test) != 0)
return(
OUTSIDE);
690 v1_test |= bevel_3d(t.
v1()) << 24;
691 v2_test |= bevel_3d(t.
v2()) << 24;
692 v3_test |= bevel_3d(t.
v3()) << 24;
693 if ((v1_test & v2_test & v3_test) != 0)
return(
OUTSIDE);
703 if ((v1_test & v2_test) == 0)
705 if ((v1_test & v3_test) == 0)
707 if ((v2_test & v3_test) == 0)
737 double d = norm[0] * t.
v1(0) + norm[1] * t.
v1(1) + norm[2] * t.
v1(2);
743 double denom = norm[0] + norm[1] + norm[2];
747 if (
cmp::le(std::abs(hitpp[0]), 0.5))
748 if (point_triangle_intersection(hitpp,t) ==
INSIDE)
751 denom = norm[0] + norm[1] - norm[2];
754 hitpn[2] = -(hitpn[0] = hitpn[1] = d / denom);
755 if (
cmp::le(std::abs(hitpn[0]), 0.5))
756 if (point_triangle_intersection(hitpn,t) ==
INSIDE)
759 denom = norm[0] - norm[1] + norm[2];
762 hitnp[1] = -(hitnp[0] = hitnp[2] = d / denom);
763 if (
cmp::le(std::abs(hitnp[0]), 0.5))
764 if (point_triangle_intersection(hitnp,t) ==
INSIDE)
767 denom = norm[0] - norm[1] - norm[2];
770 hitnn[1] = hitnn[2] = -(hitnn[0] = d / denom);
771 if (
cmp::le(std::abs(hitnn[0]), 0.5))
772 if (point_triangle_intersection(hitnn,t) ==
INSIDE)
891 t_.
scale (scaleby , v_.
pts[0] + 0.5);
892 return triangle_intersects_cube (t_);
914static inline Vector_t normalVector (
920 const double magnitude = std::sqrt (
SQR (N (0)) +
SQR (N (1)) +
SQR (N (2)));
922 return N / magnitude;
926static inline double computeArea (
933 return(0.5 * std::sqrt (
dot (AB, AB) *
dot (AC, AC) -
dot (AB, AC) *
dot (AB, AC)));
948 SIZE,
"GEOMETRY",
"The \"GEOMETRY\" statement defines the beam pipe geometry.") {
952 "Specifies the geometry file [H5hut]",
957 "If FGEOM is selected topo is over-written. ",
958 {
"RECTANGULAR",
"BOXCORNER",
"ELLIPTIC"},
963 "Specifies the length of a tube shaped elliptic beam pipe [m]",
968 "Specifies the start of a tube shaped elliptic beam pipe [m]",
973 "Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]",
978 "Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]",
983 "In case of BOXCORNER Specifies first part with height == B [m]",
988 "In case of BOXCORNER Specifies first second with height == B-C [m]",
993 "In case of BOXCORNER Specifies height of corner C [m]",
998 "Multiplicative scaling factor for coordinates ",
1003 "Multiplicative scaling factor for X coordinates ",
1008 "Multiplicative scaling factor for Y coordinates ",
1013 "Multiplicative scaling factor for Z coordinates ",
1018 "Shift in z direction",
1022 (
"INSIDEPOINT",
"A point inside the geometry");
1043 gsl_rng_env_setup();
1044 randGen_m = gsl_rng_alloc(gsl_rng_default);
1051 const std::string&
name,
1054 gsl_rng_env_setup();
1055 randGen_m = gsl_rng_alloc(gsl_rng_default);
1100 throw OpalException (
"BoundaryGeometry::find()",
"Geometry \""
1101 +
name +
"\" not found.");
1110 const int triangle_id,
1129 return v.intersect (t);
1176 const int triangle_id,
1192 const double a = -
dot(n,w0);
1193 const double b =
dot(n,dir);
1203 const double r =
a / b;
1221 const double uu =
dot(u,u);
1222 const double uv =
dot(u,v);
1223 const double vv =
dot(v,v);
1225 const double wu =
dot(w,u);
1226 const double wv =
dot(w,v);
1227 const double D = uv * uv - uu * vv;
1230 const double s = (uv * wv - vv * wu) / D;
1234 const double t = (uv * wu - uu * wv) / D;
1248static inline double magnitude (
1251 return std::sqrt (
dot (v,v));
1264 double distance = P[0] - x;
1269 if (
cmp::lt(x - P[0], distance)) {
1270 distance = x - P[0];
1271 ref_pt = {x, P[1], P[2]};
1276 if (
cmp::lt(P[1] - y, distance)) {
1278 ref_pt = {P[0], y, P[1]};
1283 if (
cmp::lt(y - P[1], distance)) {
1284 distance = y - P[1];
1285 ref_pt = {P[0], y, P[2]};
1289 if (
cmp::lt(P[2] - z, distance)) {
1290 distance = P[2] - z;
1291 ref_pt = {P[0], P[1], z};
1295 if (
cmp::lt(z - P[2], distance)) {
1296 ref_pt = {P[0], P[1], z};
1305 return (k % 2) == 1;
1364 *
gmsg <<
level2 <<
"* Searching for a point inside the geometry..." <<
endl;
1369 std::vector<Vector_t> P_outs {
1379 for (
const auto& P: P_outs) {
1404 }
else if (n == n_i) {
1430 if (!c.isInside (P))
return 1;
1435 *
gmsg <<
"* " << __func__ <<
": "
1436 <<
"reference_pt=" << reference_pt
1437 <<
", P=" << P <<
endl;
1441 const Vector_t v = reference_pt - P;
1442 const int N = std::ceil (magnitude (v) / std::min ({
voxelMesh_m.sizeOfVoxel [0],
1449 int triangle_id = -1;
1451 for (
int i = 0; i < N; i++) {
1458 *
gmsg <<
"* " << __func__ <<
": "
1459 <<
"result: " << result <<
endl;
1485 *
gmsg <<
"* " << __func__ <<
": "
1502 c.intersect (r, tmin, tmax);
1503 int triangle_id = -1;
1506 I, triangle_id) > 0) ? 1 : 0;
1509 *
gmsg <<
"* " << __func__ <<
": "
1510 <<
" result=" << result
1541#define mapPoint2VoxelIndices(pt, i, j, k) { \
1542 i = floor ((pt[0] - voxelMesh_m.minExtent [0]) / voxelMesh_m.sizeOfVoxel[0]); \
1543 j = floor ((pt[1] - voxelMesh_m.minExtent [1]) / voxelMesh_m.sizeOfVoxel[1]); \
1544 k = floor ((pt[2] - voxelMesh_m.minExtent [2]) / voxelMesh_m.sizeOfVoxel[2]); \
1545 if (!(0 <= i && i < voxelMesh_m.nr_m[0] && \
1546 0 <= j && j < voxelMesh_m.nr_m[1] && \
1547 0 <= k && k < voxelMesh_m.nr_m[2])) { \
1549 << "* " << __func__ << ":" \
1550 << " WARNING: pt=" << pt \
1551 << " is outside the bbox" \
1586 for (
unsigned int triangle_id = 0; triangle_id <
Triangles_m.size(); triangle_id++) {
1591 std::min({v1[0], v2[0], v3[0]}),
1592 std::min({v1[1], v2[1], v3[1]}),
1593 std::min({v1[2], v2[2], v3[2]}) };
1595 std::max({v1[0], v2[0], v3[0]}),
1596 std::max({v1[1], v2[1], v3[1]}),
1597 std::max({v1[2], v2[2], v3[2]}) };
1598 int i_min, j_min, k_min;
1599 int i_max, j_max, k_max;
1603 for (
int i = i_min; i <= i_max; i++) {
1604 for (
int j = j_min; j <= j_max; j++) {
1605 for (
int k = k_min; k <= k_max; k++) {
1623 bool writeVTK =
false;
1625 if (!std::filesystem::exists(vtkFileName)) {
1628 const auto t_geom = std::filesystem::last_write_time(
h5FileName_m);
1629 const auto t_vtk = std::filesystem::last_write_time(vtkFileName);
1630 if (t_geom > t_vtk) {
1636 write_voxel_mesh (vtkFileName,
1660 double longest_edge_max_m = 0.0;
1661 for (
unsigned int i = 0; i < bg->
Triangles_m.size(); i++) {
1666 const double length_edge1 = std::sqrt (
1667 SQR (x1[0] - x2[0]) +
SQR (x1[1] - x2[1]) +
SQR (x1[2] - x2[2]));
1668 const double length_edge2 = std::sqrt (
1669 SQR (x3[0] - x2[0]) +
SQR (x3[1] - x2[1]) +
SQR (x3[2] - x2[2]));
1670 const double length_edge3 = std::sqrt (
1671 SQR (x3[0] - x1[0]) +
SQR (x3[1] - x1[1]) +
SQR (x3[2] - x1[2]));
1673 double max = length_edge1;
1674 if (length_edge2 >
max)
max = length_edge2;
1675 if (length_edge3 >
max)
max = length_edge3;
1678 if (longest_edge_max_m <
max) longest_edge_max_m =
max;
1699 bg->
voxelMesh_m.
nr_m (0) = 16 * (int)std::floor (extent [0] / longest_edge_max_m);
1700 bg->
voxelMesh_m.
nr_m (1) = 16 * (int)std::floor (extent [1] / longest_edge_max_m);
1701 bg->
voxelMesh_m.
nr_m (2) = 16 * (int)std::floor (extent [2] / longest_edge_max_m);
1835 static void computeTriangleNeighbors (
1837 std::vector<std::set<unsigned int>>& neighbors
1839 std::vector<std::set<unsigned int>> adjacencies_to_pt (bg->
Points_m.size());
1842 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size(); triangle_id++) {
1843 for (
unsigned int j = 1; j <= 3; j++) {
1844 auto pt_id = bg->PointID (triangle_id, j);
1845 PAssert (pt_id < bg->Points_m.size ());
1846 adjacencies_to_pt [pt_id].insert (triangle_id);
1850 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size(); triangle_id++) {
1851 std::set<unsigned int> to_A = adjacencies_to_pt [bg->PointID (triangle_id, 1)];
1852 std::set<unsigned int> to_B = adjacencies_to_pt [bg->PointID (triangle_id, 2)];
1853 std::set<unsigned int> to_C = adjacencies_to_pt [bg->PointID (triangle_id, 3)];
1855 std::set<unsigned int> intersect;
1856 std::set_intersection (
1857 to_A.begin(), to_A.end(),
1858 to_B.begin(), to_B.end(),
1859 std::inserter(intersect,intersect.begin()));
1860 std::set_intersection(
1861 to_B.begin(), to_B.end(),
1862 to_C.begin(), to_C.end(),
1863 std::inserter(intersect,intersect.begin()));
1864 std::set_intersection(
1865 to_C.begin(), to_C.end(),
1866 to_A.begin(), to_A.end(),
1867 std::inserter(intersect, intersect.begin()));
1868 intersect.erase (triangle_id);
1870 neighbors [triangle_id] = intersect;
1872 *
gmsg <<
level2 <<
"* " << __func__ <<
": Computing neighbors done" <<
endl;
1902 std::vector<Vector_t> intersection_points;
1905 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size(); triangle_id++) {
1908 intersection_points.push_back (result);
1913 return ((intersection_points.size () % 2) == 1);
1917 static bool hasInwardPointingNormal (
1919 const int triangle_id
1924 const Vector_t triNormal = normalVector (A, B, C);
1933 const Vector_t P = (A+B+C)/3 + triNormal * minvoxelmesh;
1943 const bool is_inside = isInside (bg, P);
1944 const double dotPA_N =
dot (P - A, triNormal);
1945 return (is_inside && dotPA_N >= 0) || (!is_inside && dotPA_N < 0);
1949 static void orientTriangle (
BoundaryGeometry* bg,
int ref_id,
int triangle_id) {
1954 for (
int i = 1; i <= 3; i++) {
1955 for (
int j = 1; j <= 3; j++) {
1956 if (bg->PointID (triangle_id, j) == bg->PointID (ref_id, i)) {
1960 if (n == 2)
goto edge_found;
1966 int diff =
id[1] -
id[0];
1967 if ((((ic[1] - ic[0]) == 1) && ((diff == 1) || (diff == -2))) ||
1968 (((ic[1] - ic[0]) == 2) && ((diff == -1) || (diff == 2)))) {
1969 std::swap (bg->PointID (triangle_id,
id[0]), bg->PointID (triangle_id,
id[1]));
1974 std::vector<std::set<unsigned int>> neighbors (bg->
Triangles_m.size());
1976 computeTriangleNeighbors (bg, neighbors);
1979 int triangle_id = 0;
1981 std::vector<unsigned int> triangles (bg->
Triangles_m.size());
1982 std::vector<unsigned int>::size_type queue_cursor = 0;
1983 std::vector<unsigned int>::size_type queue_end = 0;
1984 std::vector <bool> isOriented (bg->
Triangles_m.size(),
false);
1991 while (isOriented[triangle_id])
1995 if (!hasInwardPointingNormal (bg, triangle_id)) {
1996 std::swap (bg->PointID (triangle_id, 2), bg->PointID (triangle_id, 3));
1998 isOriented[triangle_id] =
true;
2001 triangles[queue_end++] = triangle_id;
2003 for (
auto neighbor_id: neighbors[triangle_id]) {
2004 if (isOriented[neighbor_id])
continue;
2005 orientTriangle (bg, triangle_id, neighbor_id);
2006 isOriented[neighbor_id] =
true;
2007 triangles[queue_end++] = neighbor_id;
2010 }
while (queue_cursor < queue_end && (triangle_id = triangles[queue_cursor],
true));
2011 }
while (queue_end < bg->Triangles_m.size());
2014 *
gmsg <<
level2 <<
"* " << __func__ <<
": mesh is contiguous" <<
endl;
2016 *
gmsg <<
level2 <<
"* " << __func__ <<
": mesh is discontiguous (" << parts <<
") parts" <<
endl;
2024 *
gmsg <<
level2 <<
"* Initializing Boundary Geometry..." <<
endl;
2030 "', please check if it exists");
2043 rc = H5SetErrorHandler (H5AbortErrorhandler);
2045 H5SetVerbosityLevel (1);
2047 h5_prop_t props = H5CreateFileProp ();
2049 H5SetPropFileMPIOCollective (props, &comm);
2050 h5_file_t f = H5OpenFile (
h5FileName_m.c_str(), H5_O_RDONLY, props);
2051 H5CloseProp (props);
2053 h5t_mesh_t* m =
nullptr;
2054 H5FedOpenTriangleMesh (f,
"0", &m);
2055 H5FedSetLevel (m, 0);
2057 auto numTriangles = H5FedGetNumElementsTotal (m);
2061 h5_loc_id_t local_id;
2063 h5t_iterator_t* iter = H5FedBeginTraverseEntities (m, 0);
2064 while ((local_id = H5FedTraverseEntities (iter)) >= 0) {
2065 h5_loc_id_t local_vids[4];
2066 H5FedGetVertexIndicesOfEntity (m, local_id, local_vids);
2068 PointID (i, 1) = local_vids[0];
2069 PointID (i, 2) = local_vids[1];
2070 PointID (i, 3) = local_vids[2];
2073 H5FedEndTraverseEntities (iter);
2076 int num_points = H5FedGetNumVerticesTotal (m);
2078 for (i = 0; i < num_points; i++) {
2080 H5FedGetVertexCoordsByIndex (m, i, P);
2082 P[0] * xyzscale * xscale,
2083 P[1] * xyzscale * yscale,
2084 P[2] * xyzscale * zscale + zshift}));
2090 Local::computeGeometryInterval (
this);
2095 if (pt.size () != 3) {
2097 "BoundaryGeometry::initialize()",
2098 "Dimension of INSIDEPOINT must be 3");
2103 if (is_inside ==
false) {
2105 "BoundaryGeometry::initialize()",
2106 "INSIDEPOINT is not inside the geometry");
2113 *
gmsg <<
level2 <<
"* using as point inside the geometry: ("
2118 *
gmsg <<
level2 <<
"* no point inside the geometry found!" <<
endl;
2121 Local::makeTriangleNormalInwardPointing (
this);
2164 *
gmsg <<
"* " << __func__ <<
": "
2171 const Ray r =
Ray (P, v_);
2173 std::min(P[0], Q[0]),
2174 std::min(P[1], Q[1]),
2175 std::min(P[2], Q[2]) };
2177 std::max(P[0], Q[0]),
2178 std::max(P[1], Q[1]),
2179 std::max(P[2], Q[2]) };
2202 std::unordered_set<int> triangle_ids;
2203 for (
int i = i_min; i <= i_max; i++) {
2204 for (
int j = j_min; j <= j_max; j++) {
2205 for (
int k = k_min; k <= k_max; k++) {
2210 *
gmsg <<
"* " << __func__ <<
": "
2211 <<
" Test voxel: (" << i <<
", " << j <<
", " << k <<
"), "
2228 const auto triangles_intersecting_voxel =
2230 if (triangles_intersecting_voxel !=
voxelMesh_m.ids.end()) {
2231 triangle_ids.insert (
2232 triangles_intersecting_voxel->second.begin(),
2233 triangles_intersecting_voxel->second.end());
2242 int num_intersections = 0;
2243 int tmp_intersect_result = 0;
2245 for (
auto it = triangle_ids.begin ();
2246 it != triangle_ids.end ();
2256 *
gmsg <<
"* " << __func__ <<
": "
2257 <<
" Test triangle: " << *it
2258 <<
" intersect: " << tmp_intersect_result
2265 switch (tmp_intersect_result) {
2274 t = (tmp_intersect_pt[0] - P[0]) / (Q[0] - P[0]);
2276 t = (tmp_intersect_pt[1] - P[1]) / (Q[1] - P[1]);
2278 t = (tmp_intersect_pt[2] - P[2]) / (Q[2] - P[2]);
2280 num_intersections++;
2284 *
gmsg <<
"* " << __func__ <<
": "
2290 intersect_pt = tmp_intersect_pt;
2291 triangle_id = (*it);
2295 PAssert (tmp_intersect_result != -1);
2299 return num_intersections;
2317 *
gmsg <<
"* " << __func__ <<
": "
2327 int intersect_result = 0;
2329 int i_min, j_min, k_min;
2330 int i_max, j_max, k_max;
2335 std::min(P0[0], Q[0]),
2336 std::min(P0[1], Q[1]),
2337 std::min(P0[2], Q[2]) };
2339 std::max(P0[0], Q[0]),
2340 std::max(P0[1], Q[1]),
2341 std::max(P0[2], Q[2]) };
2344 }
while (( (i_max-i_min+1) * (j_max-j_min+1) * (k_max-k_min+1)) > 27);
2349 for (
int l = 1; l <= n; l++, P = Q) {
2352 P, Q, intersect_pt, triangle_id);
2353 if (triangle_id != -1) {
2359 *
gmsg <<
"* " << __func__ <<
": "
2360 <<
" result=" << intersect_result
2361 <<
" intersection pt: " << intersect_pt
2366 return intersect_result;
2388 *
gmsg <<
"* " << __func__ <<
": "
2409 int tmp_triangle_id = -1;
2411 if (tmp_triangle_id >= 0) {
2412 intersect_pt = tmp_intersect_pt;
2413 triangle_id = tmp_triangle_id;
2418 *
gmsg <<
"* " << __func__ <<
":"
2419 <<
" result=" << ret;
2421 *
gmsg <<
" intersetion=" << intersect_pt;
2434 of.open (fn.c_str ());
2437 of <<
"# vtk DataFile Version 2.0" << std::endl;
2438 of <<
"generated using DataSink::writeGeoToVtk" << std::endl;
2439 of <<
"ASCII" << std::endl << std::endl;
2440 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
2441 of <<
"POINTS " <<
Points_m.size () <<
" float" << std::endl;
2442 for (
unsigned int i = 0; i <
Points_m.size (); i++)
2455 <<
PointID (i, 3) << std::endl;
2456 of <<
"CELL_TYPES " <<
Triangles_m.size() << std::endl;
2458 of <<
"5" << std::endl;
2459 of <<
"CELL_DATA " <<
Triangles_m.size() << std::endl;
2460 of <<
"SCALARS " <<
"cell_attribute_data" <<
" float " <<
"1" << std::endl;
2461 of <<
"LOOKUP_TABLE " <<
"default" << std::endl;
2463 of << (
float)(i) << std::endl;
2470 os <<
"* ************* B O U N D A R Y G E O M E T R Y *********************************** " <<
endl;
2487 os <<
"* Total triangle num " <<
Triangles_m.size() <<
'\n'
2488 <<
"* Total points num " <<
Points_m.size () <<
'\n'
2489 <<
"* Geometry bounds(m) Max = " <<
maxExtent_m <<
'\n'
2492 <<
"* Resolution of voxel mesh " <<
voxelMesh_m.nr_m <<
'\n'
2493 <<
"* Size of voxel " <<
voxelMesh_m.sizeOfVoxel <<
'\n'
2495 os <<
"* ********************************************************************************** " <<
endl;
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
#define PointID(triangle_id, vertex_id)
#define mapPoint2VoxelIndices(pt, i, j, k)
Inform & level2(Inform &inf)
Inform & endl(Inform &inf)
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
double getReal(const Attribute &attr)
Return real value.
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Attribute makeRealArray(const std::string &name, const std::string &help)
Create real array attribute.
std::vector< double > getRealArray(const Attribute &attr)
Get array value.
std::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
constexpr double c
The velocity of light in m/s.
bool enableVTK
If true VTK files are written.
std::string combineFilePath(std::initializer_list< std::string > ilist)
bool almost_eq(double A, double B, double maxDiff=1e-15, double maxRelDiff=DBL_EPSILON)
bool almost_eq_zero(double A, double maxDiff=1e-15)
bool almost_eq(double A, double B, double maxDiff=1e-20, int maxUlps=1000)
bool almost_eq_zero(double A, double maxDiff=1e-15)
bool almost_eq(double A, double B, double maxDiff=1e-20, int maxUlps=1000)
bool ge(double x, double y)
bool gt(double x, double y)
bool almost_eq_zero(double A, double maxDiff=1e-15)
bool lt(double x, double y)
bool le(double x, double y)
The base class for all OPAL definitions.
The base class for all OPAL objects.
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
const std::string & getOpalName() const
Return object name.
void setOpalName(const std::string &name)
Set object name.
std::vector< Attribute > itsAttr
The object attributes.
bool builtin
Built-in flag.
Object * find(const std::string &name)
Find entry.
static OpalData * getInstance()
void define(Object *newObject)
Define a new object.
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Abstract base class for accelerator geometry classes.
Triangle(const Vector_t &v1, const Vector_t &v2, const Vector_t &v3)
const Vector_t & v3() const
const Vector_t & v2() const
const Vector_t & v1() const
void scale(const Vector_t &scaleby, const Vector_t &shiftby)
const Ray & operator=(const Ray &a)=delete
Ray(Vector_t o, Vector_t d)
bool isInside(const Vector_t &P) const
bool intersect(const Ray &r, double &tmin, double &tmax) const
Voxel(const Vector_t &min, const Vector_t &max)
int intersect(const Triangle &t) const
bool intersect(const Ray &r) const
void scale(const Vector_t &scale)
std::vector< std::array< unsigned int, 4 > > Triangles_m
IpplTimings::TimerRef TisInside_m
std::vector< Vector_t > TriNormals_m
int fastIsInside(const Vector_t &reference_pt, const Vector_t &P)
int intersectRayBoundary(const Vector_t &P, const Vector_t &v, Vector_t &I)
std::vector< double > TriAreas_m
virtual void execute()
Execute the command.
const Vector_t & getPoint(const int triangle_id, const int vertex_id)
virtual void update()
Update this object.
struct BoundaryGeometry::@69 voxelMesh_m
IpplTimings::TimerRef TRayTrace_m
virtual bool canReplaceBy(Object *object)
Test if replacement is allowed.
bool isInside(const Vector_t &P)
std::vector< Vector_t > Points_m
static BoundaryGeometry * find(const std::string &name)
int intersectLineSegmentBoundary(const Vector_t &P0, const Vector_t &P1, Vector_t &intersection_pt, int &triangle_id)
IpplTimings::TimerRef Tinitialize_m
int mapVoxelIndices2ID(const int i, const int j, const int k)
IpplTimings::TimerRef TPartInside_m
Vector_t mapPoint2Voxel(const Vector_t &)
IpplTimings::TimerRef TfastIsInside_m
int intersectTriangleVoxel(const int triangle_id, const int i, const int j, const int k)
void writeGeomToVtk(std::string fn)
@ debug_intersectRayBoundary
@ debug_intersectTinyLineSegmentBoundary
@ debug_intersectLineSegmentBoundary
bool findInsidePoint(void)
int partInside(const Vector_t &r, const Vector_t &v, const double dt, Vector_t &intecoords, int &triId)
int intersectTinyLineSegmentBoundary(const Vector_t &, const Vector_t &, Vector_t &, int &)
virtual BoundaryGeometry * clone(const std::string &name)
Return a clone.
Topology getTopology() const
virtual ~BoundaryGeometry()
Inform & printInfo(Inform &os) const
Vector_t mapIndices2Voxel(const int, const int, const int)
int intersectLineTriangle(const enum INTERSECTION_TESTS kind, const Vector_t &P0, const Vector_t &P1, const int triangle_id, Vector_t &I)
void computeMeshVoxelization(void)
void updateElement(ElementBase *element)
The base class for all OPAL exceptions.
static MPI_Comm getComm()
static Communicate * Comm
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static void startTimer(TimerRef t)
Vektor< double, 3 > Vector_t