47#define SQR(x) ((x) * (x))
48#define PointID(triangle_id, vertex_id) Triangles_m[triangle_id][vertex_id]
49#define Point(triangle_id, vertex_id) Points_m[Triangles_m[triangle_id][vertex_id]]
63#define FUNC_EQ(x, y) \
64 inline bool eq(double x, double y) { return almost_eq(x, y); }
66#define FUNC_EQ_ZERO(x) \
67 inline bool eq_zero(double x) { return almost_eq_zero(x); }
69#define FUNC_LE(x, y) \
70 inline bool le(double x, double y) { \
71 if (almost_eq(x, y)) { \
77#define FUNC_LE_ZERO(x) \
78 inline bool le_zero(double x) { \
79 if (almost_eq_zero(x)) { \
85#define FUNC_LT(x, y) \
86 inline bool lt(double x, double y) { \
87 if (almost_eq(x, y)) { \
93#define FUNC_LT_ZERO(x) \
94 inline bool lt_zero(double x) { \
95 if (almost_eq_zero(x)) { \
101#define FUNC_GE(x, y) \
102 inline bool ge(double x, double y) { \
103 if (almost_eq(x, y)) { \
109#define FUNC_GE_ZERO(x) \
110 inline bool ge_zero(double x) { \
111 if (almost_eq_zero(x)) { \
117#define FUNC_GT(x, y) \
118 inline bool gt(double x, double y) { \
119 if (almost_eq(x, y)) { \
125#define FUNC_GT_ZERO(x) \
126 inline bool gt_zero(double x) { \
127 if (almost_eq_zero(x)) { \
140 double A,
double B,
double maxDiff = 1e-15,
double maxRelDiff = DBL_EPSILON) {
143 const double diff = std::abs(A - B);
144 if (diff <= maxDiff)
return true;
148 const double largest = (B > A) ? B : A;
150 if (diff <= largest * maxRelDiff)
return true;
155 const double diff = std::abs(A);
156 return (diff <= maxDiff);
176 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
183 if (std::isnan(A) || std::isnan(B)) {
187 if (std::abs(A - B) <= maxDiff) {
191#pragma GCC diagnostic push
192#pragma GCC diagnostic ignored "-Wstrict-aliasing"
193 auto aInt = *(int64_t*)&A;
194#pragma GCC diagnostic pop
197 aInt = 0x8000000000000000 - aInt;
200#pragma GCC diagnostic push
201#pragma GCC diagnostic ignored "-Wstrict-aliasing"
202 auto bInt = *(int64_t*)&B;
203#pragma GCC diagnostic pop
206 bInt = 0x8000000000000000 - bInt;
209 if (std::abs(aInt - bInt) <= maxUlps) {
217 return (std::abs(A) <= maxDiff);
237 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
239 if (std::isnan(A) || std::isnan(B)) {
245 if (std::abs(A - B) <= maxDiff)
return true;
247#pragma GCC diagnostic push
248#pragma GCC diagnostic ignored "-Wstrict-aliasing"
249 auto aInt = *(int64_t*)&A;
250 auto bInt = *(int64_t*)&B;
251#pragma GCC diagnostic pop
255 if (std::signbit(aInt) != std::signbit(bInt))
return false;
258 return (std::abs(aInt - bInt) <= maxUlps);
262 return (std::abs(A) <= maxDiff);
331 static void write_voxel_mesh(
332 std::string fname,
const std::unordered_map<
int, std::unordered_set<int>>& ids,
336 const size_t numpoints = 8 * ids.size();
339 *
gmsg << level2 <<
"* Writing VTK file of voxel mesh '" << fname <<
"'" << endl;
341 PAssert(of.is_open());
344 of <<
"# vtk DataFile Version 2.0" << std::endl;
345 of <<
"generated using BoundaryGeometry::computeMeshVoxelization" << std::endl;
346 of <<
"ASCII" << std::endl << std::endl;
347 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
348 of <<
"POINTS " << numpoints <<
" float" << std::endl;
350 const auto nr0_times_nr1 =
nr[0] *
nr[1];
351 for (
auto& elem : ids) {
352 auto id = elem.first;
353 int k = (
id - 1) / nr0_times_nr1;
354 int rest = (
id - 1) % nr0_times_nr1;
355 int j = rest /
nr[0];
356 int i = rest %
nr[0];
359 P[0] = i * hr_m[0] + origin[0];
360 P[1] = j * hr_m[1] + origin[1];
361 P[2] = k * hr_m[2] + origin[2];
363 of << P[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
364 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
365 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
366 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
367 of << P[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
368 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
369 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
370 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
373 const auto num_cells = ids.size();
374 of <<
"CELLS " << num_cells <<
" " << 9 * num_cells << std::endl;
375 for (
size_t i = 0; i < num_cells; i++)
376 of <<
"8 " << 8 * i <<
" " << 8 * i + 1 <<
" " << 8 * i + 2 <<
" " << 8 * i + 3 <<
" "
377 << 8 * i + 4 <<
" " << 8 * i + 5 <<
" " << 8 * i + 6 <<
" " << 8 * i + 7
379 of <<
"CELL_TYPES " << num_cells << std::endl;
380 for (
size_t i = 0; i < num_cells; i++)
381 of <<
"11" << std::endl;
382 of <<
"CELL_DATA " << num_cells << std::endl;
384 <<
"cell_attribute_data"
387 of <<
"LOOKUP_TABLE "
388 <<
"default" << std::endl;
389 for (
size_t i = 0; i < num_cells; i++)
390 of << (
float)(i) << std::endl;
392 of <<
"COLOR_SCALARS "
393 <<
"BBoxColor " << 4 << std::endl;
394 for (
size_t i = 0; i < num_cells; i++) {
398 <<
"1.0" << std::endl;
428 inline double v1(
int i)
const {
return pts[0][i]; }
430 inline double v2(
int i)
const {
return pts[1][i]; }
432 inline double v3(
int i)
const {
return pts[2][i]; }
435 pts[0][0] *= scaleby[0];
436 pts[0][1] *= scaleby[1];
437 pts[0][2] *= scaleby[2];
438 pts[1][0] *= scaleby[0];
439 pts[1][1] *= scaleby[1];
440 pts[1][2] *= scaleby[2];
441 pts[2][0] *= scaleby[0];
442 pts[2][1] *= scaleby[1];
443 pts[2][2] *= scaleby[2];
457 int outcode_fcmp = 0;
459 if (
cmp::gt(p[0], 0.5)) outcode_fcmp |= 0x01;
460 if (
cmp::lt(p[0], -0.5)) outcode_fcmp |= 0x02;
461 if (
cmp::gt(p[1], 0.5)) outcode_fcmp |= 0x04;
462 if (
cmp::lt(p[1], -0.5)) outcode_fcmp |= 0x08;
463 if (
cmp::gt(p[2], 0.5)) outcode_fcmp |= 0x10;
464 if (
cmp::lt(p[2], -0.5)) outcode_fcmp |= 0x20;
466 return (outcode_fcmp);
474 int outcode_fcmp = 0;
476 if (
cmp::gt(p[0] + p[1], 1.0)) outcode_fcmp |= 0x001;
477 if (
cmp::gt(p[0] - p[1], 1.0)) outcode_fcmp |= 0x002;
478 if (
cmp::gt(-p[0] + p[1], 1.0)) outcode_fcmp |= 0x004;
479 if (
cmp::gt(-p[0] - p[1], 1.0)) outcode_fcmp |= 0x008;
480 if (
cmp::gt(p[0] + p[2], 1.0)) outcode_fcmp |= 0x010;
481 if (
cmp::gt(p[0] - p[2], 1.0)) outcode_fcmp |= 0x020;
482 if (
cmp::gt(-p[0] + p[2], 1.0)) outcode_fcmp |= 0x040;
483 if (
cmp::gt(-p[0] - p[2], 1.0)) outcode_fcmp |= 0x080;
484 if (
cmp::gt(p[1] + p[2], 1.0)) outcode_fcmp |= 0x100;
485 if (
cmp::gt(p[1] - p[2], 1.0)) outcode_fcmp |= 0x200;
486 if (
cmp::gt(-p[1] + p[2], 1.0)) outcode_fcmp |= 0x400;
487 if (
cmp::gt(-p[1] - p[2], 1.0)) outcode_fcmp |= 0x800;
489 return (outcode_fcmp);
497 int outcode_fcmp = 0;
499 if (
cmp::gt(p[0] + p[1] + p[2], 1.5)) outcode_fcmp |= 0x01;
500 if (
cmp::gt(p[0] + p[1] - p[2], 1.5)) outcode_fcmp |= 0x02;
501 if (
cmp::gt(p[0] - p[1] + p[2], 1.5)) outcode_fcmp |= 0x04;
502 if (
cmp::gt(p[0] - p[1] - p[2], 1.5)) outcode_fcmp |= 0x08;
503 if (
cmp::gt(-p[0] + p[1] + p[2], 1.5)) outcode_fcmp |= 0x10;
504 if (
cmp::gt(-p[0] + p[1] - p[2], 1.5)) outcode_fcmp |= 0x20;
505 if (
cmp::gt(-p[0] - p[1] + p[2], 1.5)) outcode_fcmp |= 0x40;
506 if (
cmp::gt(-p[0] - p[1] - p[2], 1.5)) outcode_fcmp |= 0x80;
508 return (outcode_fcmp);
518static inline int check_point(
523#define LERP(a, b, t) (a + t * (b - a))
525 plane_point[0] =
LERP(p1[0], p2[0], alpha);
526 plane_point[1] =
LERP(p1[1], p2[1], alpha);
527 plane_point[2] =
LERP(p1[2], p2[2], alpha);
529 return (face_plane(plane_point) & mask);
539static inline int check_line(
541 if ((0x01 & outcode_diff) != 0)
542 if (check_point(p1, p2, (.5 - p1[0]) / (p2[0] - p1[0]), 0x3e) ==
INSIDE)
return (
INSIDE);
543 if ((0x02 & outcode_diff) != 0)
544 if (check_point(p1, p2, (-.5 - p1[0]) / (p2[0] - p1[0]), 0x3d) ==
INSIDE)
return (
INSIDE);
545 if ((0x04 & outcode_diff) != 0)
546 if (check_point(p1, p2, (.5 - p1[1]) / (p2[1] - p1[1]), 0x3b) ==
INSIDE)
return (
INSIDE);
547 if ((0x08 & outcode_diff) != 0)
548 if (check_point(p1, p2, (-.5 - p1[1]) / (p2[1] - p1[1]), 0x37) ==
INSIDE)
return (
INSIDE);
549 if ((0x10 & outcode_diff) != 0)
550 if (check_point(p1, p2, (.5 - p1[2]) / (p2[2] - p1[2]), 0x2f) ==
INSIDE)
return (
INSIDE);
551 if ((0x20 & outcode_diff) != 0)
552 if (check_point(p1, p2, (-.5 - p1[2]) / (p2[2] - p1[2]), 0x1f) ==
INSIDE)
return (
INSIDE);
560constexpr double EPS = 10e-15;
562 return (((A[0] <
EPS) ? 4 : 0) | ((A[0] > -
EPS) ? 32 : 0) | ((A[1] <
EPS) ? 2 : 0)
563 | ((A[1] > -
EPS) ? 16 : 0) | ((A[2] <
EPS) ? 1 : 0) | ((A[2] > -
EPS) ? 8 : 0));
588 const int sign12 = SIGN3(cross12_1p);
593 const int sign23 = SIGN3(cross23_2p);
598 const int sign31 = SIGN3(cross31_3p);
616static int triangle_intersects_cube(
const Triangle& t) {
633 if ((v1_test & v2_test & v3_test) != 0)
return (
OUTSIDE);
638 v1_test |= bevel_2d(t.
v1()) << 8;
639 v2_test |= bevel_2d(t.
v2()) << 8;
640 v3_test |= bevel_2d(t.
v3()) << 8;
641 if ((v1_test & v2_test & v3_test) != 0)
return (
OUTSIDE);
646 v1_test |= bevel_3d(t.
v1()) << 24;
647 v2_test |= bevel_3d(t.
v2()) << 24;
648 v3_test |= bevel_3d(t.
v3()) << 24;
649 if ((v1_test & v2_test & v3_test) != 0)
return (
OUTSIDE);
659 if ((v1_test & v2_test) == 0)
660 if (check_line(t.
v1(), t.
v2(), v1_test | v2_test) ==
INSIDE)
return (
INSIDE);
661 if ((v1_test & v3_test) == 0)
662 if (check_line(t.
v1(), t.
v3(), v1_test | v3_test) ==
INSIDE)
return (
INSIDE);
663 if ((v2_test & v3_test) == 0)
664 if (check_line(t.
v2(), t.
v3(), v2_test | v3_test) ==
INSIDE)
return (
INSIDE);
693 double d = norm[0] * t.
v1(0) + norm[1] * t.
v1(1) + norm[2] * t.
v1(2);
699 double denom = norm[0] + norm[1] + norm[2];
703 if (
cmp::le(std::abs(hitpp[0]), 0.5))
704 if (point_triangle_intersection(hitpp, t) ==
INSIDE)
return (
INSIDE);
706 denom = norm[0] + norm[1] - norm[2];
709 hitpn[2] = -(hitpn[0] = hitpn[1] = d / denom);
710 if (
cmp::le(std::abs(hitpn[0]), 0.5))
711 if (point_triangle_intersection(hitpn, t) ==
INSIDE)
return (
INSIDE);
713 denom = norm[0] - norm[1] + norm[2];
716 hitnp[1] = -(hitnp[0] = hitnp[2] = d / denom);
717 if (
cmp::le(std::abs(hitnp[0]), 0.5))
718 if (point_triangle_intersection(hitnp, t) ==
INSIDE)
return (
INSIDE);
720 denom = norm[0] - norm[1] - norm[2];
723 hitnn[1] = hitnn[2] = -(hitnn[0] = d / denom);
724 if (
cmp::le(std::abs(hitnn[0]), 0.5))
725 if (point_triangle_intersection(hitnn, t) ==
INSIDE)
return (
INSIDE);
809 if (
cmp::gt(tymin, tmin_)) tmin_ = tymin;
810 if (
cmp::lt(tymax, tmax_)) tmax_ = tymax;
814 if (
cmp::gt(tzmin, tmin_)) tmin_ = tzmin;
816 if (
cmp::lt(tzmax, tmax_)) tmax_ = tzmax;
833 return triangle_intersects_cube(t_);
850 const double magnitude = std::sqrt(
SQR(N(0)) +
SQR(N(1)) +
SQR(N(2)));
852 return N / magnitude;
856static inline double computeArea(
860 return (0.5 * std::sqrt(
dot(AB, AB) *
dot(AC, AC) -
dot(AB, AC) *
dot(AB, AC)));
873 :
Definition(
SIZE,
"GEOMETRY",
"The \"GEOMETRY\" statement defines the beam pipe geometry.") {
877 "TOPO",
"If FGEOM is selected topo is over-written. ",
878 {
"RECTANGULAR",
"BOXCORNER",
"ELLIPTIC"},
"ELLIPTIC");
881 "LENGTH",
"Specifies the length of a tube shaped elliptic beam pipe [m]", 1.0);
884 "S",
"Specifies the start of a tube shaped elliptic beam pipe [m]", 0.0);
887 "A",
"Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]", 0.025);
890 "B",
"Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]", 0.025);
893 "L1",
"In case of BOXCORNER Specifies first part with height == B [m]", 0.5);
896 "L2",
"In case of BOXCORNER Specifies first second with height == B-C [m]", 0.2);
899 "C",
"In case of BOXCORNER Specifies height of corner C [m]", 0.01);
922 Tinitialize_m = IpplTimings::getTimer(
"Initialize geometry");
923 TisInside_m = IpplTimings::getTimer(
"Inside test");
925 TRayTrace_m = IpplTimings::getTimer(
"Ray tracing");
947 Tinitialize_m = IpplTimings::getTimer(
"Initialize geometry");
948 TisInside_m = IpplTimings::getTimer(
"Inside test");
950 TRayTrace_m = IpplTimings::getTimer(
"Ray tracing");
974 Tinitialize_m = IpplTimings::getTimer(
"Initialize geometry");
975 TisInside_m = IpplTimings::getTimer(
"Inside test");
977 TRayTrace_m = IpplTimings::getTimer(
"Ray tracing");
985 throw OpalException(
"BoundaryGeometry::find()",
"Geometry \"" + name +
"\" not found.");
992 const int triangle_id,
const int i,
const int j,
const int k) {
1061 const double a = -
dot(n, w0);
1062 const double b =
dot(n, dir);
1072 const double r = a / b;
1090 const double uu =
dot(u, u);
1091 const double uv =
dot(u, v);
1092 const double vv =
dot(v, v);
1094 const double wu =
dot(w, u);
1095 const double wv =
dot(w, v);
1096 const double D = uv * uv - uu * vv;
1099 const double s = (uv * wv - vv * wu) / D;
1103 const double t = (uv * wu - uu * wv) / D;
1127 double distance = P[0] - x;
1132 if (
cmp::lt(x - P[0], distance)) {
1133 distance = x - P[0];
1134 ref_pt = {x, P[1], P[2]};
1139 if (
cmp::lt(P[1] - y, distance)) {
1140 distance = P[1] - y;
1141 ref_pt = {P[0], y, P[1]};
1146 if (
cmp::lt(y - P[1], distance)) {
1147 distance = y - P[1];
1148 ref_pt = {P[0], y, P[2]};
1152 if (
cmp::lt(P[2] - z, distance)) {
1153 distance = P[2] - z;
1154 ref_pt = {P[0], P[1], z};
1158 if (
cmp::lt(z - P[2], distance)) {
1159 ref_pt = {P[0], P[1], z};
1168 return (k % 2) == 1;
1224 *
gmsg << level2 <<
"* Searching for a point inside the geometry..." << endl;
1229 std::vector<Vector_t<double, 3>> P_outs{
1235 for (
const auto& P : P_outs) {
1260 }
else if (n == n_i) {
1285 if (!c.isInside(P))
return 1;
1290 *
gmsg <<
"* " << __func__ <<
": "
1291 <<
"reference_pt=" << reference_pt <<
", P=" << P << endl;
1296 const int N = std::ceil(
1305 int triangle_id = -1;
1307 for (
int i = 0; i < N; i++) {
1314 *
gmsg <<
"* " << __func__ <<
": "
1315 <<
"result: " << result << endl;
1337 *
gmsg <<
"* " << __func__ <<
": "
1339 <<
" origin=" << P <<
" dir=" << v << endl;
1353 c.intersect(r, tmin, tmax);
1354 int triangle_id = -1;
1358 *
gmsg <<
"* " << __func__ <<
": "
1359 <<
" result=" << result <<
" I=" << I << endl;
1382#define mapPoint2VoxelIndices(pt, i, j, k) \
1384 i = floor((pt[0] - voxelMesh_m.minExtent[0]) / voxelMesh_m.sizeOfVoxel[0]); \
1385 j = floor((pt[1] - voxelMesh_m.minExtent[1]) / voxelMesh_m.sizeOfVoxel[1]); \
1386 k = floor((pt[2] - voxelMesh_m.minExtent[2]) / voxelMesh_m.sizeOfVoxel[2]); \
1387 if (!(0 <= i && i < voxelMesh_m.nr_m[0] && 0 <= j && j < voxelMesh_m.nr_m[1] && 0 <= k \
1388 && k < voxelMesh_m.nr_m[2])) { \
1389 *gmsg << level2 << "* " << __func__ << ":" \
1390 << " WARNING: pt=" << pt << " is outside the bbox" \
1391 << " i=" << i << " j=" << j << " k=" << k << endl; \
1396 const int i,
const int j,
const int k) {
1412 for (
unsigned int triangle_id = 0; triangle_id <
Triangles_m.size(); triangle_id++) {
1417 std::min({v1[0], v2[0], v3[0]}), std::min({v1[1], v2[1], v3[1]}),
1418 std::min({v1[2], v2[2], v3[2]})};
1420 std::max({v1[0], v2[0], v3[0]}), std::max({v1[1], v2[1], v3[1]}),
1421 std::max({v1[2], v2[2], v3[2]})};
1422 int i_min, j_min, k_min;
1423 int i_max, j_max, k_max;
1427 for (
int i = i_min; i <= i_max; i++) {
1428 for (
int j = j_min; j <= j_max; j++) {
1429 for (
int k = k_min; k <= k_max; k++) {
1439 *
gmsg << level2 <<
"* Mesh voxelization done" << endl;
1445 bool writeVTK =
false;
1447 if (!std::filesystem::exists(vtkFileName)) {
1450 auto ft_geom = std::filesystem::last_write_time(
h5FileName_m);
1451 auto ft_vtk = std::filesystem::last_write_time(vtkFileName);
1453 if (ft_geom > ft_vtk) writeVTK =
true;
1475 double longest_edge_max_m = 0.0;
1476 for (
unsigned int i = 0; i < bg->
Triangles_m.size(); i++) {
1481 const double length_edge1 =
1482 std::sqrt(
SQR(x1[0] - x2[0]) +
SQR(x1[1] - x2[1]) +
SQR(x1[2] - x2[2]));
1483 const double length_edge2 =
1484 std::sqrt(
SQR(x3[0] - x2[0]) +
SQR(x3[1] - x2[1]) +
SQR(x3[2] - x2[2]));
1485 const double length_edge3 =
1486 std::sqrt(
SQR(x3[0] - x1[0]) +
SQR(x3[1] - x1[1]) +
SQR(x3[2] - x1[2]));
1488 double max = length_edge1;
1489 if (length_edge2 > max) max = length_edge2;
1490 if (length_edge3 > max) max = length_edge3;
1493 if (longest_edge_max_m < max) longest_edge_max_m = max;
1514 bg->
voxelMesh_m.nr_m(0) = 16 * (int)std::floor(extent[0] / longest_edge_max_m);
1515 bg->
voxelMesh_m.nr_m(1) = 16 * (int)std::floor(extent[1] / longest_edge_max_m);
1516 bg->
voxelMesh_m.nr_m(2) = 16 * (int)std::floor(extent[2] / longest_edge_max_m);
1650 static void computeTriangleNeighbors(
1652 std::vector<std::set<unsigned int>> adjacencies_to_pt(bg->
Points_m.size());
1655 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size();
1657 for (
unsigned int j = 1; j <= 3; j++) {
1658 auto pt_id = bg->PointID(triangle_id, j);
1659 PAssert(pt_id < bg->Points_m.size());
1660 adjacencies_to_pt[pt_id].insert(triangle_id);
1664 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size();
1666 std::set<unsigned int> to_A = adjacencies_to_pt[bg->PointID(triangle_id, 1)];
1667 std::set<unsigned int> to_B = adjacencies_to_pt[bg->PointID(triangle_id, 2)];
1668 std::set<unsigned int> to_C = adjacencies_to_pt[bg->PointID(triangle_id, 3)];
1670 std::set<unsigned int> intersect;
1671 std::set_intersection(
1672 to_A.begin(), to_A.end(), to_B.begin(), to_B.end(),
1673 std::inserter(intersect, intersect.begin()));
1674 std::set_intersection(
1675 to_B.begin(), to_B.end(), to_C.begin(), to_C.end(),
1676 std::inserter(intersect, intersect.begin()));
1677 std::set_intersection(
1678 to_C.begin(), to_C.end(), to_A.begin(), to_A.end(),
1679 std::inserter(intersect, intersect.begin()));
1680 intersect.erase(triangle_id);
1682 neighbors[triangle_id] = intersect;
1684 *
gmsg << level2 <<
"* " << __func__ <<
": Computing neighbors done" << endl;
1714 std::vector<Vector_t<double, 3>> intersection_points;
1717 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size();
1721 intersection_points.push_back(result);
1726 return ((intersection_points.size() % 2) == 1);
1730 static bool hasInwardPointingNormal(
BoundaryGeometry*
const bg,
const int triangle_id) {
1738 double minvoxelmesh = bg->
voxelMesh_m.sizeOfVoxel[0];
1739 if (minvoxelmesh > bg->
voxelMesh_m.sizeOfVoxel[1])
1741 if (minvoxelmesh > bg->
voxelMesh_m.sizeOfVoxel[2])
1753 const bool is_inside = isInside(bg, P);
1755 const double dotPA_N =
dot(d, triNormal);
1756 return (is_inside && dotPA_N >= 0) || (!is_inside && dotPA_N < 0);
1760 static void orientTriangle(
BoundaryGeometry* bg,
int ref_id,
int triangle_id) {
1765 for (
int i = 1; i <= 3; i++) {
1766 for (
int j = 1; j <= 3; j++) {
1767 if (bg->PointID(triangle_id, j) == bg->PointID(ref_id, i)) {
1771 if (n == 2)
goto edge_found;
1777 int diff =
id[1] -
id[0];
1778 if ((((ic[1] - ic[0]) == 1) && ((diff == 1) || (diff == -2)))
1779 || (((ic[1] - ic[0]) == 2) && ((diff == -1) || (diff == 2)))) {
1780 std::swap(bg->PointID(triangle_id,
id[0]), bg->PointID(triangle_id,
id[1]));
1785 std::vector<std::set<unsigned int>> neighbors(bg->
Triangles_m.size());
1787 computeTriangleNeighbors(bg, neighbors);
1790 int triangle_id = 0;
1792 std::vector<unsigned int> triangles(bg->
Triangles_m.size());
1793 std::vector<unsigned int>::size_type queue_cursor = 0;
1794 std::vector<unsigned int>::size_type queue_end = 0;
1795 std::vector<bool> isOriented(bg->
Triangles_m.size(),
false);
1802 while (isOriented[triangle_id])
1806 if (!hasInwardPointingNormal(bg, triangle_id)) {
1807 std::swap(bg->PointID(triangle_id, 2), bg->PointID(triangle_id, 3));
1809 isOriented[triangle_id] =
true;
1812 triangles[queue_end++] = triangle_id;
1814 for (
auto neighbor_id : neighbors[triangle_id]) {
1815 if (isOriented[neighbor_id])
continue;
1816 orientTriangle(bg, triangle_id, neighbor_id);
1817 isOriented[neighbor_id] =
true;
1818 triangles[queue_end++] = neighbor_id;
1821 }
while (queue_cursor < queue_end && (triangle_id = triangles[queue_cursor],
true));
1822 }
while (queue_end < bg->Triangles_m.size());
1825 *
gmsg << level2 <<
"* " << __func__ <<
": mesh is contiguous" << endl;
1827 *
gmsg << level2 <<
"* " << __func__ <<
": mesh is discontiguous (" << parts
1828 <<
") parts" << endl;
1830 *
gmsg << level2 <<
"* Triangle Normal built done" << endl;
1835 *
gmsg << level2 <<
"* Initializing Boundary Geometry..." << endl;
1840 "BoundaryGeometry::initialize",
1841 "Failed to open file '" +
h5FileName_m +
"', please check if it exists");
1850 h5_int64_t rc [[maybe_unused]];
1851 rc = H5SetErrorHandler(H5AbortErrorhandler);
1852 PAssert(rc != H5_ERR);
1853 H5SetVerbosityLevel(1);
1855 h5_prop_t props = H5CreateFileProp();
1856 MPI_Comm comm = ippl::Comm->getCommunicator();
1857 H5SetPropFileMPIOCollective(props, &comm);
1858 h5_file_t f = H5OpenFile(
h5FileName_m.c_str(), H5_O_RDONLY, props);
1861 h5t_mesh_t* m =
nullptr;
1862 H5FedOpenTriangleMesh(f,
"0", &m);
1863 H5FedSetLevel(m, 0);
1865 auto numTriangles = H5FedGetNumElementsTotal(m);
1869 h5_loc_id_t local_id;
1871 h5t_iterator_t* iter = H5FedBeginTraverseEntities(m, 0);
1872 while ((local_id = H5FedTraverseEntities(iter)) >= 0) {
1873 h5_loc_id_t local_vids[4];
1874 H5FedGetVertexIndicesOfEntity(m, local_id, local_vids);
1876 PointID(i, 1) = local_vids[0];
1877 PointID(i, 2) = local_vids[1];
1878 PointID(i, 3) = local_vids[2];
1881 H5FedEndTraverseEntities(iter);
1884 int num_points = H5FedGetNumVerticesTotal(m);
1886 for (i = 0; i < num_points; i++) {
1888 H5FedGetVertexCoordsByIndex(m, i, P);
1891 P[0] * xyzscale * xscale, P[1] * xyzscale * yscale,
1892 P[2] * xyzscale * zscale + zshift));
1896 *
gmsg << level2 <<
"* Reading mesh done" << endl;
1898 Local::computeGeometryInterval(
this);
1903 if (pt.size() != 3) {
1905 "BoundaryGeometry::initialize()",
"Dimension of INSIDEPOINT must be 3");
1910 if (is_inside ==
false) {
1912 "BoundaryGeometry::initialize()",
"INSIDEPOINT is not inside the geometry");
1919 *
gmsg << level2 <<
"* using as point inside the geometry: (" <<
insidePoint_m[0] <<
", "
1922 *
gmsg << level2 <<
"* no point inside the geometry found!" << endl;
1925 Local::makeTriangleNormalInwardPointing(
this);
1938 *
gmsg << level2 <<
"* Triangle barycent built done" << endl;
1940 *
gmsg << *
this << endl;
1941 ippl::Comm->barrier();
1966 *
gmsg <<
"* " << __func__ <<
": "
1967 <<
" P = " << P <<
", Q = " << Q << endl;
1971 const Ray r =
Ray(P, v_);
1973 std::min(P[0], Q[0]), std::min(P[1], Q[1]), std::min(P[2], Q[2])};
1975 std::max(P[0], Q[0]), std::max(P[1], Q[1]), std::max(P[2], Q[2])};
1998 std::unordered_set<int> triangle_ids;
1999 for (
int i = i_min; i <= i_max; i++) {
2000 for (
int j = j_min; j <= j_max; j++) {
2001 for (
int k = k_min; k <= k_max; k++) {
2006 *
gmsg <<
"* " << __func__ <<
": "
2007 <<
" Test voxel: (" << i <<
", " << j <<
", " << k <<
"), " << v.
pts[0]
2008 << v.
pts[1] << endl;
2023 const auto triangles_intersecting_voxel =
voxelMesh_m.ids.find(voxel_id);
2024 if (triangles_intersecting_voxel !=
voxelMesh_m.ids.end()) {
2025 triangle_ids.insert(
2026 triangles_intersecting_voxel->second.begin(),
2027 triangles_intersecting_voxel->second.end());
2036 int num_intersections = 0;
2037 int tmp_intersect_result = 0;
2039 for (
auto it = triangle_ids.begin(); it != triangle_ids.end(); it++) {
2043 *
gmsg <<
"* " << __func__ <<
": "
2044 <<
" Test triangle: " << *it <<
" intersect: " << tmp_intersect_result
2048 switch (tmp_intersect_result) {
2057 t = (tmp_intersect_pt[0] - P[0]) / (Q[0] - P[0]);
2059 t = (tmp_intersect_pt[1] - P[1]) / (Q[1] - P[1]);
2061 t = (tmp_intersect_pt[2] - P[2]) / (Q[2] - P[2]);
2063 num_intersections++;
2067 *
gmsg <<
"* " << __func__ <<
": "
2068 <<
" set triangle" << endl;
2072 intersect_pt = tmp_intersect_pt;
2073 triangle_id = (*it);
2077 PAssert(tmp_intersect_result != -1);
2081 return num_intersections;
2098 *
gmsg <<
"* " << __func__ <<
": "
2099 <<
" P0 = " << P0 <<
" P1 = " << P1 << endl;
2106 int intersect_result = 0;
2108 int i_min, j_min, k_min;
2109 int i_max, j_max, k_max;
2114 std::min(P0[0], Q[0]), std::min(P0[1], Q[1]), std::min(P0[2], Q[2])};
2116 std::max(P0[0], Q[0]), std::max(P0[1], Q[1]), std::max(P0[2], Q[2])};
2119 }
while (((i_max - i_min + 1) * (j_max - j_min + 1) * (k_max - k_min + 1)) > 27);
2124 for (
int l = 1; l <= n; l++, P = Q) {
2127 if (triangle_id != -1) {
2133 *
gmsg <<
"* " << __func__ <<
": "
2134 <<
" result=" << intersect_result <<
" intersection pt: " << intersect_pt << endl;
2138 return intersect_result;
2159 *
gmsg <<
"* " << __func__ <<
": "
2160 <<
" r=" << r <<
" v=" << v <<
" dt=" << dt << endl;
2179 int tmp_triangle_id = -1;
2181 if (tmp_triangle_id >= 0) {
2182 intersect_pt = tmp_intersect_pt;
2183 triangle_id = tmp_triangle_id;
2188 *
gmsg <<
"* " << __func__ <<
":"
2189 <<
" result=" << ret;
2191 *
gmsg <<
" intersetion=" << intersect_pt;
2203 of.open(fn.c_str());
2204 PAssert(of.is_open());
2206 of <<
"# vtk DataFile Version 2.0" << std::endl;
2207 of <<
"generated using DataSink::writeGeoToVtk" << std::endl;
2208 of <<
"ASCII" << std::endl << std::endl;
2209 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
2210 of <<
"POINTS " <<
Points_m.size() <<
" float" << std::endl;
2211 for (
unsigned int i = 0; i <
Points_m.size(); i++)
2218 of <<
"CELL_TYPES " <<
Triangles_m.size() << std::endl;
2220 of <<
"5" << std::endl;
2221 of <<
"CELL_DATA " <<
Triangles_m.size() << std::endl;
2223 <<
"cell_attribute_data"
2225 <<
"1" << std::endl;
2226 of <<
"LOOKUP_TABLE "
2227 <<
"default" << std::endl;
2229 of << (
float)(i) << std::endl;
2235 os <<
"* ************* B O U N D A R Y G E O M E T R Y *********************************** "
2262 os <<
"* ********************************************************************************** "
#define PointID(triangle_id, vertex_id)
#define mapPoint2VoxelIndices(pt, i, j, k)
ippl::Vector< T, Dim > Vector_t
Template PIC bunch: IPPL PicManager, shared field mesh/solver, and multiple particle containers.
double gsl_rng_uniform(gsl_rng *rng)
void gsl_rng_free(gsl_rng *rng)
gsl_rng * gsl_rng_alloc(const gsl_rng_type *)
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Abstract base class for accelerator geometry classes.
struct BoundaryGeometry::@33 voxelMesh_m
IpplTimings::TimerRef TisInside_m
int fastIsInside(const Vector_t< double, 3 > &reference_pt, const Vector_t< double, 3 > &P)
Vector_t< double, 3 > mapIndices2Voxel(const int, const int, const int)
std::vector< double > TriAreas_m
virtual void execute()
Execute the command.
virtual void update()
Update this object.
IpplTimings::TimerRef TRayTrace_m
virtual bool canReplaceBy(Object *object)
Test if replacement is allowed.
Vector_t< double, 3 > maxExtent_m
const Vector_t< double, 3 > & getPoint(const int triangle_id, const int vertex_id)
std::vector< std::array< unsigned int, 4 > > Triangles_m
int intersectLineTriangle(const enum INTERSECTION_TESTS kind, const Vector_t< double, 3 > &P0, const Vector_t< double, 3 > &P1, const int triangle_id, Vector_t< double, 3 > &I)
static BoundaryGeometry * find(const std::string &name)
IpplTimings::TimerRef Tinitialize_m
int mapVoxelIndices2ID(const int i, const int j, const int k)
int intersectRayBoundary(const Vector_t< double, 3 > &P, const Vector_t< double, 3 > &v, Vector_t< double, 3 > &I)
IpplTimings::TimerRef TPartInside_m
IpplTimings::TimerRef TfastIsInside_m
int intersectTriangleVoxel(const int triangle_id, const int i, const int j, const int k)
int intersectLineSegmentBoundary(const Vector_t< double, 3 > &P0, const Vector_t< double, 3 > &P1, Vector_t< double, 3 > &intersection_pt, int &triangle_id)
Vector_t< double, 3 > insidePoint_m
int partInside(const Vector_t< double, 3 > &r, const Vector_t< double, 3 > &v, const double dt, Vector_t< double, 3 > &intecoords, int &triId)
int intersectTinyLineSegmentBoundary(const Vector_t< double, 3 > &, const Vector_t< double, 3 > &, Vector_t< double, 3 > &, int &)
void writeGeomToVtk(std::string fn)
@ debug_intersectRayBoundary
@ debug_intersectTinyLineSegmentBoundary
@ debug_intersectLineSegmentBoundary
bool findInsidePoint(void)
virtual BoundaryGeometry * clone(const std::string &name)
Return a clone.
bool isInside(const Vector_t< double, 3 > &P)
Topology getTopology() const
virtual ~BoundaryGeometry()
Inform & printInfo(Inform &os) const
Vector_t< double, 3 > mapPoint2Voxel(const Vector_t< double, 3 > &)
void computeMeshVoxelization(void)
std::vector< Vector_t< double, 3 > > TriNormals_m
std::vector< Vector_t< double, 3 > > Points_m
Vector_t< double, 3 > minExtent_m
void updateElement(ElementBase *element)
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
Vector_t< double, 3 > inv_direction
Vector_t< double, 3 > direction
Ray(Vector_t< double, 3 > o, Vector_t< double, 3 > d)
const Ray & operator=(const Ray &a)=delete
Vector_t< double, 3 > origin
const Vector_t< double, 3 > & v1() const
Vector_t< double, 3 > pts[3]
Triangle(const Vector_t< double, 3 > &v1, const Vector_t< double, 3 > &v2, const Vector_t< double, 3 > &v3)
const Vector_t< double, 3 > & v2() const
const Vector_t< double, 3 > & v3() const
void scale(const Vector_t< double, 3 > &scaleby, const Vector_t< double, 3 > &shiftby)
bool intersect(const Ray &r, double &tmin, double &tmax) const
bool isInside(const Vector_t< double, 3 > &P) const
Vector_t< double, 3 > extent() const
Voxel(const Vector_t< double, 3 > &min, const Vector_t< double, 3 > &max)
void scale(const Vector_t< double, 3 > &scale)
int intersect(const Triangle &t) const
Vector_t< double, 3 > pts[2]
bool intersect(const Ray &r) const
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.
bool enableVTK
If true VTK files are written.
constexpr double c
The velocity of light in m/s.
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)