40#include <boost/filesystem.hpp>
42#include <gsl/gsl_sys.h>
46#define SQR(x) ((x) * (x))
47#define PointID(triangle_id, vertex_id) Triangles_m[triangle_id][vertex_id]
48#define Point(triangle_id, vertex_id) Points_m[Triangles_m[triangle_id][vertex_id]]
62#define FUNC_EQ(x, y) \
63 inline bool eq(double x, double y) { return almost_eq(x, y); }
65#define FUNC_EQ_ZERO(x) \
66 inline bool eq_zero(double x) { return almost_eq_zero(x); }
68#define FUNC_LE(x, y) \
69 inline bool le(double x, double y) { \
70 if (almost_eq(x, y)) { \
76#define FUNC_LE_ZERO(x) \
77 inline bool le_zero(double x) { \
78 if (almost_eq_zero(x)) { \
84#define FUNC_LT(x, y) \
85 inline bool lt(double x, double y) { \
86 if (almost_eq(x, y)) { \
92#define FUNC_LT_ZERO(x) \
93 inline bool lt_zero(double x) { \
94 if (almost_eq_zero(x)) { \
100#define FUNC_GE(x, y) \
101 inline bool ge(double x, double y) { \
102 if (almost_eq(x, y)) { \
108#define FUNC_GE_ZERO(x) \
109 inline bool ge_zero(double x) { \
110 if (almost_eq_zero(x)) { \
116#define FUNC_GT(x, y) \
117 inline bool gt(double x, double y) { \
118 if (almost_eq(x, y)) { \
124#define FUNC_GT_ZERO(x) \
125 inline bool gt_zero(double x) { \
126 if (almost_eq_zero(x)) { \
139 double A,
double B,
double maxDiff = 1e-15,
double maxRelDiff = DBL_EPSILON) {
142 const double diff = std::abs(A - B);
148 const double largest = (B > A) ? B : A;
150 if (diff <= largest * maxRelDiff)
156 const double diff = std::abs(A);
157 return (diff <= maxDiff);
177 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
184 if (std::isnan(A) || std::isnan(B)) {
188 if (std::abs(A - B) <= maxDiff) {
192#pragma GCC diagnostic push
193#pragma GCC diagnostic ignored "-Wstrict-aliasing"
194 auto aInt = *(int64_t*)&A;
195#pragma GCC diagnostic pop
198 aInt = 0x8000000000000000 - aInt;
201#pragma GCC diagnostic push
202#pragma GCC diagnostic ignored "-Wstrict-aliasing"
203 auto bInt = *(int64_t*)&B;
204#pragma GCC diagnostic pop
207 bInt = 0x8000000000000000 - bInt;
210 if (std::abs(aInt - bInt) <= maxUlps) {
218 return (std::abs(A) <= maxDiff);
238 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
240 if (std::isnan(A) || std::isnan(B)) {
246 if (std::abs(A - B) <= maxDiff)
249#pragma GCC diagnostic push
250#pragma GCC diagnostic ignored "-Wstrict-aliasing"
251 auto aInt = *(int64_t*)&A;
252 auto bInt = *(int64_t*)&B;
253#pragma GCC diagnostic pop
257 if (std::signbit(aInt) != std::signbit(bInt))
261 return (std::abs(aInt - bInt) <= maxUlps);
265 return (std::abs(A) <= maxDiff);
334 static void write_voxel_mesh(
335 std::string fname,
const std::unordered_map<
int, std::unordered_set<int>>& ids,
339 const size_t numpoints = 8 * ids.size();
342 *
gmsg << level2 <<
"* Writing VTK file of voxel mesh '" << fname <<
"'" << endl;
344 PAssert(of.is_open());
347 of <<
"# vtk DataFile Version 2.0" << std::endl;
348 of <<
"generated using BoundaryGeometry::computeMeshVoxelization" << std::endl;
349 of <<
"ASCII" << std::endl << std::endl;
350 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
351 of <<
"POINTS " << numpoints <<
" float" << std::endl;
353 const auto nr0_times_nr1 =
nr[0] *
nr[1];
354 for (
auto& elem : ids) {
355 auto id = elem.first;
356 int k = (
id - 1) / nr0_times_nr1;
357 int rest = (
id - 1) % nr0_times_nr1;
358 int j = rest /
nr[0];
359 int i = rest %
nr[0];
362 P[0] = i * hr_m[0] + origin[0];
363 P[1] = j * hr_m[1] + origin[1];
364 P[2] = k * hr_m[2] + origin[2];
366 of << P[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
367 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
368 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
369 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
370 of << P[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
371 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
372 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
373 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
376 const auto num_cells = ids.size();
377 of <<
"CELLS " << num_cells <<
" " << 9 * num_cells << std::endl;
378 for (
size_t i = 0; i < num_cells; i++)
379 of <<
"8 " << 8 * i <<
" " << 8 * i + 1 <<
" " << 8 * i + 2 <<
" " << 8 * i + 3 <<
" "
380 << 8 * i + 4 <<
" " << 8 * i + 5 <<
" " << 8 * i + 6 <<
" " << 8 * i + 7
382 of <<
"CELL_TYPES " << num_cells << std::endl;
383 for (
size_t i = 0; i < num_cells; i++)
384 of <<
"11" << std::endl;
385 of <<
"CELL_DATA " << num_cells << std::endl;
387 <<
"cell_attribute_data"
390 of <<
"LOOKUP_TABLE "
391 <<
"default" << std::endl;
392 for (
size_t i = 0; i < num_cells; i++)
393 of << (
float)(i) << std::endl;
395 of <<
"COLOR_SCALARS "
396 <<
"BBoxColor " << 4 << std::endl;
397 for (
size_t i = 0; i < num_cells; i++) {
401 <<
"1.0" << std::endl;
434 inline double v1(
int i)
const {
440 inline double v2(
int i)
const {
446 inline double v3(
int i)
const {
451 pts[0][0] *= scaleby[0];
452 pts[0][1] *= scaleby[1];
453 pts[0][2] *= scaleby[2];
454 pts[1][0] *= scaleby[0];
455 pts[1][1] *= scaleby[1];
456 pts[1][2] *= scaleby[2];
457 pts[2][0] *= scaleby[0];
458 pts[2][1] *= scaleby[1];
459 pts[2][2] *= scaleby[2];
473 int outcode_fcmp = 0;
476 outcode_fcmp |= 0x01;
478 outcode_fcmp |= 0x02;
480 outcode_fcmp |= 0x04;
482 outcode_fcmp |= 0x08;
484 outcode_fcmp |= 0x10;
486 outcode_fcmp |= 0x20;
488 return (outcode_fcmp);
496 int outcode_fcmp = 0;
499 outcode_fcmp |= 0x001;
501 outcode_fcmp |= 0x002;
502 if (
cmp::gt(-p[0] + p[1], 1.0))
503 outcode_fcmp |= 0x004;
504 if (
cmp::gt(-p[0] - p[1], 1.0))
505 outcode_fcmp |= 0x008;
507 outcode_fcmp |= 0x010;
509 outcode_fcmp |= 0x020;
510 if (
cmp::gt(-p[0] + p[2], 1.0))
511 outcode_fcmp |= 0x040;
512 if (
cmp::gt(-p[0] - p[2], 1.0))
513 outcode_fcmp |= 0x080;
515 outcode_fcmp |= 0x100;
517 outcode_fcmp |= 0x200;
518 if (
cmp::gt(-p[1] + p[2], 1.0))
519 outcode_fcmp |= 0x400;
520 if (
cmp::gt(-p[1] - p[2], 1.0))
521 outcode_fcmp |= 0x800;
523 return (outcode_fcmp);
531 int outcode_fcmp = 0;
533 if (
cmp::gt(p[0] + p[1] + p[2], 1.5))
534 outcode_fcmp |= 0x01;
535 if (
cmp::gt(p[0] + p[1] - p[2], 1.5))
536 outcode_fcmp |= 0x02;
537 if (
cmp::gt(p[0] - p[1] + p[2], 1.5))
538 outcode_fcmp |= 0x04;
539 if (
cmp::gt(p[0] - p[1] - p[2], 1.5))
540 outcode_fcmp |= 0x08;
541 if (
cmp::gt(-p[0] + p[1] + p[2], 1.5))
542 outcode_fcmp |= 0x10;
543 if (
cmp::gt(-p[0] + p[1] - p[2], 1.5))
544 outcode_fcmp |= 0x20;
545 if (
cmp::gt(-p[0] - p[1] + p[2], 1.5))
546 outcode_fcmp |= 0x40;
547 if (
cmp::gt(-p[0] - p[1] - p[2], 1.5))
548 outcode_fcmp |= 0x80;
550 return (outcode_fcmp);
560static inline int check_point(
565#define LERP(a, b, t) (a + t * (b - a))
567 plane_point[0] =
LERP(p1[0], p2[0], alpha);
568 plane_point[1] =
LERP(p1[1], p2[1], alpha);
569 plane_point[2] =
LERP(p1[2], p2[2], alpha);
571 return (face_plane(plane_point) & mask);
581static inline int check_line(
583 if ((0x01 & outcode_diff) != 0)
584 if (check_point(p1, p2, (.5 - p1[0]) / (p2[0] - p1[0]), 0x3e) ==
INSIDE)
586 if ((0x02 & outcode_diff) != 0)
587 if (check_point(p1, p2, (-.5 - p1[0]) / (p2[0] - p1[0]), 0x3d) ==
INSIDE)
589 if ((0x04 & outcode_diff) != 0)
590 if (check_point(p1, p2, (.5 - p1[1]) / (p2[1] - p1[1]), 0x3b) ==
INSIDE)
592 if ((0x08 & outcode_diff) != 0)
593 if (check_point(p1, p2, (-.5 - p1[1]) / (p2[1] - p1[1]), 0x37) ==
INSIDE)
595 if ((0x10 & outcode_diff) != 0)
596 if (check_point(p1, p2, (.5 - p1[2]) / (p2[2] - p1[2]), 0x2f) ==
INSIDE)
598 if ((0x20 & outcode_diff) != 0)
599 if (check_point(p1, p2, (-.5 - p1[2]) / (p2[2] - p1[2]), 0x1f) ==
INSIDE)
608constexpr double EPS = 10e-15;
611 ((A[0] <
EPS) ? 4 : 0) | ((A[0] > -
EPS) ? 32 : 0) | ((A[1] <
EPS) ? 2 : 0)
612 | ((A[1] > -
EPS) ? 16 : 0) | ((A[2] <
EPS) ? 1 : 0) | ((A[2] > -
EPS) ? 8 : 0));
643 const int sign12 = SIGN3(cross12_1p);
648 const int sign23 = SIGN3(cross23_2p);
653 const int sign31 = SIGN3(cross31_3p);
671static int triangle_intersects_cube(
const Triangle& t) {
680 if ((v1_test = face_plane(t.
v1())) ==
INSIDE)
682 if ((v2_test = face_plane(t.
v2())) ==
INSIDE)
684 if ((v3_test = face_plane(t.
v3())) ==
INSIDE)
691 if ((v1_test & v2_test & v3_test) != 0)
697 v1_test |= bevel_2d(t.
v1()) << 8;
698 v2_test |= bevel_2d(t.
v2()) << 8;
699 v3_test |= bevel_2d(t.
v3()) << 8;
700 if ((v1_test & v2_test & v3_test) != 0)
706 v1_test |= bevel_3d(t.
v1()) << 24;
707 v2_test |= bevel_3d(t.
v2()) << 24;
708 v3_test |= bevel_3d(t.
v3()) << 24;
709 if ((v1_test & v2_test & v3_test) != 0)
720 if ((v1_test & v2_test) == 0)
721 if (check_line(t.
v1(), t.
v2(), v1_test | v2_test) ==
INSIDE)
723 if ((v1_test & v3_test) == 0)
724 if (check_line(t.
v1(), t.
v3(), v1_test | v3_test) ==
INSIDE)
726 if ((v2_test & v3_test) == 0)
727 if (check_line(t.
v2(), t.
v3(), v2_test | v3_test) ==
INSIDE)
757 double d = norm[0] * t.
v1(0) + norm[1] * t.
v1(1) + norm[2] * t.
v1(2);
763 double denom = norm[0] + norm[1] + norm[2];
767 if (
cmp::le(std::abs(hitpp[0]), 0.5))
768 if (point_triangle_intersection(hitpp, t) ==
INSIDE)
771 denom = norm[0] + norm[1] - norm[2];
774 hitpn[2] = -(hitpn[0] = hitpn[1] = d / denom);
775 if (
cmp::le(std::abs(hitpn[0]), 0.5))
776 if (point_triangle_intersection(hitpn, t) ==
INSIDE)
779 denom = norm[0] - norm[1] + norm[2];
782 hitnp[1] = -(hitnp[0] = hitnp[2] = d / denom);
783 if (
cmp::le(std::abs(hitnp[0]), 0.5))
784 if (point_triangle_intersection(hitnp, t) ==
INSIDE)
787 denom = norm[0] - norm[1] - norm[2];
790 hitnn[1] = hitnn[2] = -(hitnn[0] = d / denom);
791 if (
cmp::le(std::abs(hitnn[0]), 0.5))
792 if (point_triangle_intersection(hitnn, t) ==
INSIDE)
909 return triangle_intersects_cube(t_);
928 const double magnitude = std::sqrt(
SQR(N(0)) +
SQR(N(1)) +
SQR(N(2)));
930 return N / magnitude;
934static inline double computeArea(
938 return (0.5 * std::sqrt(
dot(AB, AB) *
dot(AC, AC) -
dot(AB, AC) *
dot(AB, AC)));
951 :
Definition(
SIZE,
"GEOMETRY",
"The \"GEOMETRY\" statement defines the beam pipe geometry.") {
955 "TOPO",
"If FGEOM is selected topo is over-written. ",
956 {
"RECTANGULAR",
"BOXCORNER",
"ELLIPTIC"},
"ELLIPTIC");
959 "LENGTH",
"Specifies the length of a tube shaped elliptic beam pipe [m]", 1.0);
962 "S",
"Specifies the start of a tube shaped elliptic beam pipe [m]", 0.0);
965 "A",
"Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]", 0.025);
968 "B",
"Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]", 0.025);
971 "L1",
"In case of BOXCORNER Specifies first part with height == B [m]", 0.5);
974 "L2",
"In case of BOXCORNER Specifies first second with height == B-C [m]", 0.2);
1000 Tinitialize_m = IpplTimings::getTimer(
"Initialize geometry");
1001 TisInside_m = IpplTimings::getTimer(
"Inside test");
1003 TRayTrace_m = IpplTimings::getTimer(
"Ray tracing");
1014 gsl_rng_env_setup();
1015 randGen_m = gsl_rng_alloc(gsl_rng_default);
1023 gsl_rng_env_setup();
1024 randGen_m = gsl_rng_alloc(gsl_rng_default);
1026 Tinitialize_m = IpplTimings::getTimer(
"Initialize geometry");
1027 TisInside_m = IpplTimings::getTimer(
"Inside test");
1029 TRayTrace_m = IpplTimings::getTimer(
"Ray tracing");
1057 Tinitialize_m = IpplTimings::getTimer(
"Initialize geometry");
1058 TisInside_m = IpplTimings::getTimer(
"Inside test");
1060 TRayTrace_m = IpplTimings::getTimer(
"Ray tracing");
1068 throw OpalException(
"BoundaryGeometry::find()",
"Geometry \"" + name +
"\" not found.");
1076 const int triangle_id,
const int i,
const int j,
const int k) {
1145 const double a = -
dot(n, w0);
1146 const double b =
dot(n, dir);
1156 const double r = a / b;
1174 const double uu =
dot(u, u);
1175 const double uv =
dot(u, v);
1176 const double vv =
dot(v, v);
1178 const double wu =
dot(w, u);
1179 const double wv =
dot(w, v);
1180 const double D = uv * uv - uu * vv;
1183 const double s = (uv * wv - vv * wu) / D;
1187 const double t = (uv * wu - uu * wv) / D;
1202 return std::sqrt(
dot(v, v));
1212 double distance = P[0] - x;
1217 if (
cmp::lt(x - P[0], distance)) {
1218 distance = x - P[0];
1219 ref_pt = {x, P[1], P[2]};
1224 if (
cmp::lt(P[1] - y, distance)) {
1225 distance = P[1] - y;
1226 ref_pt = {P[0], y, P[1]};
1231 if (
cmp::lt(y - P[1], distance)) {
1232 distance = y - P[1];
1233 ref_pt = {P[0], y, P[2]};
1237 if (
cmp::lt(P[2] - z, distance)) {
1238 distance = P[2] - z;
1239 ref_pt = {P[0], P[1], z};
1243 if (
cmp::lt(z - P[2], distance)) {
1244 ref_pt = {P[0], P[1], z};
1253 return (k % 2) == 1;
1309 *
gmsg << level2 <<
"* Searching for a point inside the geometry..." << endl;
1314 std::vector<Vector_t<double, 3>> P_outs{
1320 for (
const auto& P : P_outs) {
1345 }
else if (n == n_i) {
1376 *
gmsg <<
"* " << __func__ <<
": "
1377 <<
"reference_pt=" << reference_pt <<
", P=" << P << endl;
1382 const int N = std::ceil(
1390 int triangle_id = -1;
1392 for (
int i = 0; i < N; i++) {
1399 *
gmsg <<
"* " << __func__ <<
": "
1400 <<
"result: " << result << endl;
1422 *
gmsg <<
"* " << __func__ <<
": "
1424 <<
" origin=" << P <<
" dir=" << v << endl;
1438 c.intersect(r, tmin, tmax);
1439 int triangle_id = -1;
1443 *
gmsg <<
"* " << __func__ <<
": "
1444 <<
" result=" << result <<
" I=" << I << endl;
1467#define mapPoint2VoxelIndices(pt, i, j, k) \
1469 i = floor((pt[0] - voxelMesh_m.minExtent[0]) / voxelMesh_m.sizeOfVoxel[0]); \
1470 j = floor((pt[1] - voxelMesh_m.minExtent[1]) / voxelMesh_m.sizeOfVoxel[1]); \
1471 k = floor((pt[2] - voxelMesh_m.minExtent[2]) / voxelMesh_m.sizeOfVoxel[2]); \
1472 if (!(0 <= i && i < voxelMesh_m.nr_m[0] && 0 <= j && j < voxelMesh_m.nr_m[1] && 0 <= k \
1473 && k < voxelMesh_m.nr_m[2])) { \
1474 *gmsg << level2 << "* " << __func__ << ":" \
1475 << " WARNING: pt=" << pt << " is outside the bbox" \
1476 << " i=" << i << " j=" << j << " k=" << k << endl; \
1481 const int i,
const int j,
const int k) {
1497 for (
unsigned int triangle_id = 0; triangle_id <
Triangles_m.size(); triangle_id++) {
1502 std::min({v1[0], v2[0], v3[0]}), std::min({v1[1], v2[1], v3[1]}),
1503 std::min({v1[2], v2[2], v3[2]})};
1505 std::max({v1[0], v2[0], v3[0]}), std::max({v1[1], v2[1], v3[1]}),
1506 std::max({v1[2], v2[2], v3[2]})};
1507 int i_min, j_min, k_min;
1508 int i_max, j_max, k_max;
1512 for (
int i = i_min; i <= i_max; i++) {
1513 for (
int j = j_min; j <= j_max; j++) {
1514 for (
int k = k_min; k <= k_max; k++) {
1524 *
gmsg << level2 <<
"* Mesh voxelization done" << endl;
1530 bool writeVTK =
false;
1532 if (!boost::filesystem::exists(vtkFileName)) {
1535 std::time_t t_geom = boost::filesystem::last_write_time(
h5FileName_m);
1536 std::time_t t_vtk = boost::filesystem::last_write_time(vtkFileName);
1537 if (std::difftime(t_geom, t_vtk) > 0)
1560 double longest_edge_max_m = 0.0;
1561 for (
unsigned int i = 0; i < bg->
Triangles_m.size(); i++) {
1566 const double length_edge1 =
1567 std::sqrt(
SQR(x1[0] - x2[0]) +
SQR(x1[1] - x2[1]) +
SQR(x1[2] - x2[2]));
1568 const double length_edge2 =
1569 std::sqrt(
SQR(x3[0] - x2[0]) +
SQR(x3[1] - x2[1]) +
SQR(x3[2] - x2[2]));
1570 const double length_edge3 =
1571 std::sqrt(
SQR(x3[0] - x1[0]) +
SQR(x3[1] - x1[1]) +
SQR(x3[2] - x1[2]));
1573 double max = length_edge1;
1574 if (length_edge2 > max)
1576 if (length_edge3 > max)
1580 if (longest_edge_max_m < max)
1581 longest_edge_max_m = max;
1602 bg->
voxelMesh_m.nr_m(0) = 16 * (int)std::floor(extent[0] / longest_edge_max_m);
1603 bg->
voxelMesh_m.nr_m(1) = 16 * (int)std::floor(extent[1] / longest_edge_max_m);
1604 bg->
voxelMesh_m.nr_m(2) = 16 * (int)std::floor(extent[2] / longest_edge_max_m);
1738 static void computeTriangleNeighbors(
1740 std::vector<std::set<unsigned int>> adjacencies_to_pt(bg->
Points_m.size());
1743 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size();
1745 for (
unsigned int j = 1; j <= 3; j++) {
1746 auto pt_id = bg->PointID(triangle_id, j);
1747 PAssert(pt_id < bg->
Points_m.size());
1748 adjacencies_to_pt[pt_id].insert(triangle_id);
1752 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size();
1754 std::set<unsigned int> to_A = adjacencies_to_pt[bg->PointID(triangle_id, 1)];
1755 std::set<unsigned int> to_B = adjacencies_to_pt[bg->PointID(triangle_id, 2)];
1756 std::set<unsigned int> to_C = adjacencies_to_pt[bg->PointID(triangle_id, 3)];
1758 std::set<unsigned int> intersect;
1759 std::set_intersection(
1760 to_A.begin(), to_A.end(), to_B.begin(), to_B.end(),
1761 std::inserter(intersect, intersect.begin()));
1762 std::set_intersection(
1763 to_B.begin(), to_B.end(), to_C.begin(), to_C.end(),
1764 std::inserter(intersect, intersect.begin()));
1765 std::set_intersection(
1766 to_C.begin(), to_C.end(), to_A.begin(), to_A.end(),
1767 std::inserter(intersect, intersect.begin()));
1768 intersect.erase(triangle_id);
1770 neighbors[triangle_id] = intersect;
1772 *
gmsg << level2 <<
"* " << __func__ <<
": Computing neighbors done" << endl;
1802 std::vector<Vector_t<double, 3>> intersection_points;
1805 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size();
1809 intersection_points.push_back(result);
1814 return ((intersection_points.size() % 2) == 1);
1818 static bool hasInwardPointingNormal(
BoundaryGeometry*
const bg,
const int triangle_id) {
1826 double minvoxelmesh = bg->
voxelMesh_m.sizeOfVoxel[0];
1827 if (minvoxelmesh > bg->
voxelMesh_m.sizeOfVoxel[1])
1829 if (minvoxelmesh > bg->
voxelMesh_m.sizeOfVoxel[2])
1841 const bool is_inside =
isInside(bg, P);
1843 const double dotPA_N =
dot(d, triNormal);
1844 return (is_inside && dotPA_N >= 0) || (!is_inside && dotPA_N < 0);
1848 static void orientTriangle(
BoundaryGeometry* bg,
int ref_id,
int triangle_id) {
1853 for (
int i = 1; i <= 3; i++) {
1854 for (
int j = 1; j <= 3; j++) {
1855 if (bg->PointID(triangle_id, j) == bg->PointID(ref_id, i)) {
1866 int diff =
id[1] -
id[0];
1867 if ((((ic[1] - ic[0]) == 1) && ((diff == 1) || (diff == -2)))
1868 || (((ic[1] - ic[0]) == 2) && ((diff == -1) || (diff == 2)))) {
1869 std::swap(bg->PointID(triangle_id,
id[0]), bg->PointID(triangle_id,
id[1]));
1874 std::vector<std::set<unsigned int>> neighbors(bg->
Triangles_m.size());
1876 computeTriangleNeighbors(bg, neighbors);
1879 int triangle_id = 0;
1881 std::vector<unsigned int> triangles(bg->
Triangles_m.size());
1882 std::vector<unsigned int>::size_type queue_cursor = 0;
1883 std::vector<unsigned int>::size_type queue_end = 0;
1884 std::vector<bool> isOriented(bg->
Triangles_m.size(),
false);
1891 while (isOriented[triangle_id])
1895 if (!hasInwardPointingNormal(bg, triangle_id)) {
1896 std::swap(bg->PointID(triangle_id, 2), bg->PointID(triangle_id, 3));
1898 isOriented[triangle_id] =
true;
1901 triangles[queue_end++] = triangle_id;
1903 for (
auto neighbor_id : neighbors[triangle_id]) {
1904 if (isOriented[neighbor_id])
1906 orientTriangle(bg, triangle_id, neighbor_id);
1907 isOriented[neighbor_id] =
true;
1908 triangles[queue_end++] = neighbor_id;
1911 }
while (queue_cursor < queue_end && (triangle_id = triangles[queue_cursor],
true));
1915 *
gmsg << level2 <<
"* " << __func__ <<
": mesh is contiguous" << endl;
1917 *
gmsg << level2 <<
"* " << __func__ <<
": mesh is discontiguous (" << parts
1918 <<
") parts" << endl;
1920 *
gmsg << level2 <<
"* Triangle Normal built done" << endl;
1925 *
gmsg << level2 <<
"* Initializing Boundary Geometry..." << endl;
1930 "BoundaryGeometry::initialize",
1931 "Failed to open file '" +
h5FileName_m +
"', please check if it exists");
1944 rc = H5SetErrorHandler(H5AbortErrorhandler);
1945 PAssert(rc != H5_ERR);
1946 H5SetVerbosityLevel(1);
1948 h5_prop_t props = H5CreateFileProp();
1949 MPI_Comm comm = ippl::Comm->getCommunicator();
1950 H5SetPropFileMPIOCollective(props, &comm);
1951 h5_file_t f = H5OpenFile(
h5FileName_m.c_str(), H5_O_RDONLY, props);
1954 h5t_mesh_t* m =
nullptr;
1955 H5FedOpenTriangleMesh(f,
"0", &m);
1956 H5FedSetLevel(m, 0);
1958 auto numTriangles = H5FedGetNumElementsTotal(m);
1962 h5_loc_id_t local_id;
1964 h5t_iterator_t* iter = H5FedBeginTraverseEntities(m, 0);
1965 while ((local_id = H5FedTraverseEntities(iter)) >= 0) {
1966 h5_loc_id_t local_vids[4];
1967 H5FedGetVertexIndicesOfEntity(m, local_id, local_vids);
1969 PointID(i, 1) = local_vids[0];
1970 PointID(i, 2) = local_vids[1];
1971 PointID(i, 3) = local_vids[2];
1974 H5FedEndTraverseEntities(iter);
1977 int num_points = H5FedGetNumVerticesTotal(m);
1979 for (i = 0; i < num_points; i++) {
1981 H5FedGetVertexCoordsByIndex(m, i, P);
1983 P[0] * xyzscale * xscale, P[1] * xyzscale * yscale, P[2] * xyzscale * zscale + zshift));
1987 *
gmsg << level2 <<
"* Reading mesh done" << endl;
1989 Local::computeGeometryInterval(
this);
1994 if (pt.size() != 3) {
1996 "BoundaryGeometry::initialize()",
"Dimension of INSIDEPOINT must be 3");
2001 if (is_inside ==
false) {
2003 "BoundaryGeometry::initialize()",
"INSIDEPOINT is not inside the geometry");
2010 *
gmsg << level2 <<
"* using as point inside the geometry: (" <<
insidePoint_m[0] <<
", "
2013 *
gmsg << level2 <<
"* no point inside the geometry found!" << endl;
2016 Local::makeTriangleNormalInwardPointing(
this);
2029 *
gmsg << level2 <<
"* Triangle barycent built done" << endl;
2031 *
gmsg << *
this << endl;
2032 ippl::Comm->barrier();
2057 *
gmsg <<
"* " << __func__ <<
": "
2058 <<
" P = " << P <<
", Q = " << Q << endl;
2062 const Ray r =
Ray(P, v_);
2064 std::min(P[0], Q[0]), std::min(P[1], Q[1]), std::min(P[2], Q[2])};
2066 std::max(P[0], Q[0]), std::max(P[1], Q[1]), std::max(P[2], Q[2])};
2089 std::unordered_set<int> triangle_ids;
2090 for (
int i = i_min; i <= i_max; i++) {
2091 for (
int j = j_min; j <= j_max; j++) {
2092 for (
int k = k_min; k <= k_max; k++) {
2097 *
gmsg <<
"* " << __func__ <<
": "
2098 <<
" Test voxel: (" << i <<
", " << j <<
", " << k <<
"), " << v.
pts[0]
2099 << v.
pts[1] << endl;
2114 const auto triangles_intersecting_voxel =
voxelMesh_m.ids.find(voxel_id);
2115 if (triangles_intersecting_voxel !=
voxelMesh_m.ids.end()) {
2116 triangle_ids.insert(
2117 triangles_intersecting_voxel->second.begin(),
2118 triangles_intersecting_voxel->second.end());
2127 int num_intersections = 0;
2128 int tmp_intersect_result = 0;
2130 for (
auto it = triangle_ids.begin(); it != triangle_ids.end(); it++) {
2134 *
gmsg <<
"* " << __func__ <<
": "
2135 <<
" Test triangle: " << *it <<
" intersect: " << tmp_intersect_result
2139 switch (tmp_intersect_result) {
2148 t = (tmp_intersect_pt[0] - P[0]) / (Q[0] - P[0]);
2150 t = (tmp_intersect_pt[1] - P[1]) / (Q[1] - P[1]);
2152 t = (tmp_intersect_pt[2] - P[2]) / (Q[2] - P[2]);
2154 num_intersections++;
2158 *
gmsg <<
"* " << __func__ <<
": "
2159 <<
" set triangle" << endl;
2163 intersect_pt = tmp_intersect_pt;
2164 triangle_id = (*it);
2168 PAssert(tmp_intersect_result != -1);
2172 return num_intersections;
2189 *
gmsg <<
"* " << __func__ <<
": "
2190 <<
" P0 = " << P0 <<
" P1 = " << P1 << endl;
2197 int intersect_result = 0;
2199 int i_min, j_min, k_min;
2200 int i_max, j_max, k_max;
2205 std::min(P0[0], Q[0]), std::min(P0[1], Q[1]), std::min(P0[2], Q[2])};
2207 std::max(P0[0], Q[0]), std::max(P0[1], Q[1]), std::max(P0[2], Q[2])};
2210 }
while (((i_max - i_min + 1) * (j_max - j_min + 1) * (k_max - k_min + 1)) > 27);
2215 for (
int l = 1; l <= n; l++, P = Q) {
2218 if (triangle_id != -1) {
2224 *
gmsg <<
"* " << __func__ <<
": "
2225 <<
" result=" << intersect_result <<
" intersection pt: " << intersect_pt << endl;
2229 return intersect_result;
2250 *
gmsg <<
"* " << __func__ <<
": "
2251 <<
" r=" << r <<
" v=" << v <<
" dt=" << dt << endl;
2270 int tmp_triangle_id = -1;
2272 if (tmp_triangle_id >= 0) {
2273 intersect_pt = tmp_intersect_pt;
2274 triangle_id = tmp_triangle_id;
2279 *
gmsg <<
"* " << __func__ <<
":"
2280 <<
" result=" << ret;
2282 *
gmsg <<
" intersetion=" << intersect_pt;
2294 of.open(fn.c_str());
2295 PAssert(of.is_open());
2297 of <<
"# vtk DataFile Version 2.0" << std::endl;
2298 of <<
"generated using DataSink::writeGeoToVtk" << std::endl;
2299 of <<
"ASCII" << std::endl << std::endl;
2300 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
2301 of <<
"POINTS " <<
Points_m.size() <<
" float" << std::endl;
2302 for (
unsigned int i = 0; i <
Points_m.size(); i++)
2309 of <<
"CELL_TYPES " <<
Triangles_m.size() << std::endl;
2311 of <<
"5" << std::endl;
2312 of <<
"CELL_DATA " <<
Triangles_m.size() << std::endl;
2314 <<
"cell_attribute_data"
2316 <<
"1" << std::endl;
2317 of <<
"LOOKUP_TABLE "
2318 <<
"default" << std::endl;
2320 of << (
float)(i) << std::endl;
2326 os <<
"* ************* B O U N D A R Y G E O M E T R Y *********************************** "
2353 os <<
"* ********************************************************************************** "
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
ippl::Vector< T, Dim > Vector_t
#define PointID(triangle_id, vertex_id)
#define mapPoint2VoxelIndices(pt, i, j, k)
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 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)
bool enableVTK
If true VTK files are written.
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition(int size, const char *name, const char *help)
Constructor for exemplars.
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
const std::string & getOpalName() const
Return object name.
Object(int size, const char *name, const char *help)
Constructor for exemplars.
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.
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)
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
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
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
struct BoundaryGeometry::@117056140100230112133004050263065356254101277345 voxelMesh_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 exceptions.