OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
BoundaryGeometry.cpp
Go to the documentation of this file.
1//
2// Declaration of the BoundaryGeometry class
3//
4// Copyright (c) 200x - 2020, Achim Gsell,
5// Paul Scherrer Institut, Villigen PSI, Switzerland
6// All rights reserved.
7//
8// This file is part of OPAL.
9//
10// OPAL is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// You should have received a copy of the GNU General Public License
16// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17//
18
19//#define ENABLE_DEBUG
20
22
23#include <algorithm>
24#include <chrono>
25#include <cmath>
26#include <filesystem>
27#include <fstream>
28#include <string>
29
30#include "H5hut.h"
31#include <cfloat>
32
37#include "Physics/Physics.h"
39#include "Utilities/Options.h"
40
41#include <gsl/gsl_sys.h>
42
43extern Inform* gmsg;
44
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]]
48
49/*
50 In the following namespaces various approximately floating point
51 comparisons are implemented. The used implementation is selected
52 via
53
54 namespaces cmp = IMPLEMENTATION;
55
56*/
57
58/*
59 First we define some macros for function common in all namespaces.
60*/
61#define FUNC_EQ(x, y) inline bool eq(double x, double y) { \
62 return almost_eq(x, y); \
63 }
64
65#define FUNC_EQ_ZERO(x) inline bool eq_zero(double x) { \
66 return almost_eq_zero(x); \
67 }
68
69#define FUNC_LE(x, y) inline bool le(double x, double y) { \
70 if (almost_eq(x, y)) { \
71 return true; \
72 } \
73 return x < y; \
74 }
75
76#define FUNC_LE_ZERO(x) inline bool le_zero(double x) { \
77 if (almost_eq_zero(x)) { \
78 return true; \
79 } \
80 return x < 0.0; \
81 }
82
83#define FUNC_LT(x, y) inline bool lt(double x, double y) { \
84 if (almost_eq(x, y)) { \
85 return false; \
86 } \
87 return x < y; \
88 }
89
90#define FUNC_LT_ZERO(x) inline bool lt_zero(double x) { \
91 if (almost_eq_zero(x)) { \
92 return false; \
93 } \
94 return x < 0.0; \
95 }
96
97#define FUNC_GE(x, y) inline bool ge(double x, double y) { \
98 if (almost_eq(x, y)) { \
99 return true; \
100 } \
101 return x > y; \
102 }
103
104#define FUNC_GE_ZERO(x) inline bool ge_zero(double x) { \
105 if (almost_eq_zero(x)) { \
106 return true; \
107 } \
108 return x > 0.0; \
109 }
110
111#define FUNC_GT(x, y) inline bool gt(double x, double y) { \
112 if (almost_eq(x, y)) { \
113 return false; \
114 } \
115 return x > y; \
116 }
117
118#define FUNC_GT_ZERO(x) inline bool gt_zero(double x) { \
119 if (almost_eq_zero(x)) { \
120 return false; \
121 } \
122 return x > 0.0; \
123 }
124
125namespace cmp_diff {
126
127 /*
128 Link:
129 https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
130 */
131 inline bool almost_eq(double A, double B, double maxDiff = 1e-15, double maxRelDiff = DBL_EPSILON) {
132 // Check if the numbers are really close -- needed
133 // when comparing numbers near zero.
134 const double diff = std::abs(A - B);
135 if (diff <= maxDiff)
136 return true;
137
138 A = std::abs(A);
139 B = std::abs(B);
140 const double largest = (B > A) ? B : A;
141
142 if (diff <= largest * maxRelDiff)
143 return true;
144 return false;
145 }
146
147 inline bool almost_eq_zero(double A, double maxDiff = 1e-15) {
148 const double diff = std::abs(A);
149 return (diff <= maxDiff);
150 }
151
152 FUNC_EQ(x, y);
154 FUNC_LE(x, y);
156 FUNC_LT(x, y);
158 FUNC_GE(x, y);
160 FUNC_GT(x, y);
162}
163
165 /*
166 See:
167 https://www.cygnus-software.com/papers/comparingfloats/comparing_floating_point_numbers_obsolete.htm
168 */
169 inline bool almost_eq(double A, double B, double maxDiff = 1e-20, int maxUlps = 1000) {
170 // Make sure maxUlps is non-negative and small enough that the
171 // default NAN won't compare as equal to anything.
172 // assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
173
174 // handle NaN's
175 // Note: comparing something with a NaN is always false!
176 if (std::isnan(A) || std::isnan(B)) {
177 return false;
178 }
179
180 if (std::abs (A - B) <= maxDiff) {
181 return true;
182 }
183
184#pragma GCC diagnostic push
185#pragma GCC diagnostic ignored "-Wstrict-aliasing"
186 auto aInt = *(int64_t*)&A;
187#pragma GCC diagnostic pop
188 // Make aInt lexicographically ordered as a twos-complement int
189 if (aInt < 0) {
190 aInt = 0x8000000000000000 - aInt;
191 }
192
193#pragma GCC diagnostic push
194#pragma GCC diagnostic ignored "-Wstrict-aliasing"
195 auto bInt = *(int64_t*)&B;
196#pragma GCC diagnostic pop
197 // Make bInt lexicographically ordered as a twos-complement int
198 if (bInt < 0) {
199 bInt = 0x8000000000000000 - bInt;
200 }
201
202 if (std::abs (aInt - bInt) <= maxUlps) {
203 return true;
204 }
205 return false;
206 }
207
208 inline bool almost_eq_zero(double A, double maxDiff = 1e-15) {
209 // no need to handle NaN's!
210 return (std::abs(A) <= maxDiff);
211 }
212 FUNC_EQ(x, y);
214 FUNC_LE(x, y);
216 FUNC_LT(x, y);
218 FUNC_GE(x, y);
220 FUNC_GT(x, y);
222}
223
224namespace cmp_ulp {
225 /*
226 See:
227 https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
228 */
229
230
231 inline bool almost_eq (double A, double B, double maxDiff = 1e-20, int maxUlps = 1000) {
232 // handle NaN's
233 if (std::isnan (A) || std::isnan (B)) {
234 return false;
235 }
236
237 // Check if the numbers are really close -- needed
238 // when comparing numbers near zero.
239 if (std::abs (A - B) <= maxDiff)
240 return true;
241
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
247
248 // Different signs means they do not match.
249 // Note: a negative floating point number is also negative as integer.
250 if (std::signbit (aInt) != std::signbit (bInt))
251 return false;
252
253 // Find the difference in ULPs.
254 return (std::abs (aInt - bInt) <= maxUlps);
255 }
256
257 inline bool almost_eq_zero(double A, double maxDiff = 1e-15) {
258 return (std::abs (A) <= maxDiff);
259 }
260 FUNC_EQ(x, y);
262 FUNC_LE(x, y);
264 FUNC_LT(x, y);
266 FUNC_GE(x, y);
268 FUNC_GT(x, y);
270}
271
272namespace cmp = cmp_ulp;
273/*
274
275 Some
276 _ _ _
277 | | | | ___| |_ __ ___ _ __
278 | |_| |/ _ \ | '_ \ / _ \ '__|
279 | _ | __/ | |_) | __/ |
280 |_| |_|\___|_| .__/ \___|_|
281 |_|
282
283 functions
284 */
285namespace {
286struct VectorLessX {
287 bool operator() (Vector_t x1, Vector_t x2) {
288 return cmp::lt (x1(0), x2(0));
289 }
290};
291
292struct VectorLessY {
293 bool operator() (Vector_t x1, Vector_t x2) {
294 return cmp::lt(x1(1), x2 (1));
295 }
296};
297
298struct VectorLessZ {
299 bool operator() (Vector_t x1, Vector_t x2) {
300 return cmp::lt(x1(2), x2(2));
301 }
302};
303
307Vector_t get_max_extent (std::vector<Vector_t>& coords) {
308 const Vector_t x = *max_element (
309 coords.begin (), coords.end (), VectorLessX ());
310 const Vector_t y = *max_element (
311 coords.begin (), coords.end (), VectorLessY ());
312 const Vector_t z = *max_element (
313 coords.begin (), coords.end (), VectorLessZ ());
314 return Vector_t ({x(0), y(1), z(2)});
315}
316
317
318/*
319 Compute the minimum of coordinates of geometry, i.e the minimum of X,Y,Z
320 */
321Vector_t get_min_extent (std::vector<Vector_t>& coords) {
322 const Vector_t x = *min_element (
323 coords.begin (), coords.end (), VectorLessX ());
324 const Vector_t y = *min_element (
325 coords.begin (), coords.end (), VectorLessY ());
326 const Vector_t z = *min_element (
327 coords.begin (), coords.end (), VectorLessZ ());
328 return Vector_t ({x(0), y(1), z(2)});
329}
330
331/*
332 write legacy VTK file of voxel mesh
333*/
334static void write_voxel_mesh (
335 std::string fname,
336 const std::unordered_map< int, std::unordered_set<int> >& ids,
337 const Vector_t& hr_m,
338 const Vektor<int,3>& nr,
339 const Vector_t& origin
340 ) {
341 /*----------------------------------------------------------------------*/
342 const size_t numpoints = 8 * ids.size ();
343 std::ofstream of;
344
345 *gmsg << level2 << "* Writing VTK file of voxel mesh '" << fname << "'" << endl;
346 of.open (fname);
347 PAssert (of.is_open ());
348 of.precision (6);
349
350 of << "# vtk DataFile Version 2.0" << std::endl;
351 of << "generated using BoundaryGeometry::computeMeshVoxelization"
352 << std::endl;
353 of << "ASCII" << std::endl << std::endl;
354 of << "DATASET UNSTRUCTURED_GRID" << std::endl;
355 of << "POINTS " << numpoints << " float" << std::endl;
356
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];
364
365 Vector_t P;
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];
369
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;
378 }
379 of << 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++)
383 of << "8 "
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;
394 of << 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;
398 }
399 of << std::endl;
400}
401}
402
403/*___________________________________________________________________________
404
405 Triangle-cube intersection test.
406
407 See:
408 http://tog.acm.org/resources/GraphicsGems/gemsiii/triangleCube.c
409
410 */
411
412
413#define INSIDE 0
414#define OUTSIDE 1
415
416class Triangle {
417public:
418 Triangle () { }
419 Triangle (const Vector_t& v1, const Vector_t& v2, const Vector_t& v3) {
420 pts[0] = v1;
421 pts[1] = v2;
422 pts[2] = v3;
423 }
424
425 inline const Vector_t& v1() const {
426 return pts[0];
427 }
428 inline double v1(int i) const {
429 return pts[0][i];
430 }
431 inline const Vector_t& v2() const {
432 return pts[1];
433 }
434 inline double v2(int i) const {
435 return pts[1][i];
436 }
437 inline const Vector_t& v3() const {
438 return pts[2];
439 }
440 inline double v3(int i) const {
441 return pts[2][i];
442 }
443
444
445 inline void scale (
446 const Vector_t& scaleby,
447 const Vector_t& shiftby
448 ) {
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];
458 pts[0] -= shiftby;
459 pts[1] -= shiftby;
460 pts[2] -= shiftby;
461 }
462
463
465};
466
467/*___________________________________________________________________________*/
468
469/* Which of the six face-plane(s) is point P outside of? */
470
471static inline int
472face_plane (
473 const Vector_t& p
474 ) {
475 int outcode_fcmp = 0;
476
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;
483
484 return(outcode_fcmp);
485}
486
487/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
488
489/* Which of the twelve edge plane(s) is point P outside of? */
490
491static inline int
492bevel_2d (
493 const Vector_t& p
494 ) {
495 int outcode_fcmp = 0;
496
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;
509
510 return(outcode_fcmp);
511}
512
513/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
514
515 Which of the eight corner plane(s) is point P outside of?
516*/
517static inline int
518bevel_3d (
519 const Vector_t& p
520 ) {
521 int outcode_fcmp = 0;
522
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;
531
532 return(outcode_fcmp);
533}
534
535/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
536
537 Test the point "alpha" of the way from P1 to P2
538 See if it is on a face of the cube
539 Consider only faces in "mask"
540*/
541
542static inline int
543check_point (
544 const Vector_t& p1,
545 const Vector_t& p2,
546 const double alpha,
547 const int mask
548 ) {
549 Vector_t plane_point;
550
551#define LERP(a, b, t) (a + t * (b - a))
552 // with C++20 we can use: std::lerp(a, b, t)
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);
556#undef LERP
557 return(face_plane(plane_point) & mask);
558}
559
560/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
561
562 Compute intersection of P1 --> P2 line segment with face planes
563 Then test intersection point to see if it is on cube face
564 Consider only face planes in "outcode_diff"
565 Note: Zero bits in "outcode_diff" means face line is outside of
566*/
567static inline int
568check_line (
569 const Vector_t& p1,
570 const Vector_t& p2,
571 const int outcode_diff
572 ) {
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);
585 return(OUTSIDE);
586}
587
588/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
589
590 Test if 3D point is inside 3D triangle
591*/
592constexpr double EPS = 10e-15;
593static inline int
594SIGN3 (
595 Vector_t A
596 ) {
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));
600}
601
602static int
603point_triangle_intersection (
604 const Vector_t& p,
605 const Triangle& t
606 ) {
607 /*
608 First, a quick bounding-box test:
609 If P is outside triangle bbox, there cannot be an intersection.
610 */
611 if (cmp::gt(p[0], std::max({t.v1(0), t.v2(0), t.v3(0)}))) return(OUTSIDE);
612 if (cmp::gt(p[1], std::max({t.v1(1), t.v2(1), t.v3(1)}))) return(OUTSIDE);
613 if (cmp::gt(p[2], std::max({t.v1(2), t.v2(2), t.v3(2)}))) return(OUTSIDE);
614 if (cmp::lt(p[0], std::min({t.v1(0), t.v2(0), t.v3(0)}))) return(OUTSIDE);
615 if (cmp::lt(p[1], std::min({t.v1(1), t.v2(1), t.v3(1)}))) return(OUTSIDE);
616 if (cmp::lt(p[2], std::min({t.v1(2), t.v2(2), t.v3(2)}))) return(OUTSIDE);
617
618 /*
619 For each triangle side, make a vector out of it by subtracting vertexes;
620 make another vector from one vertex to point P.
621 The crossproduct of these two vectors is orthogonal to both and the
622 signs of its X,Y,Z components indicate whether P was to the inside or
623 to the outside of this triangle side.
624 */
625 const Vector_t vect12 = t.v1() - t.v2();
626 const Vector_t vect1h = t.v1() - p;
627 const Vector_t cross12_1p = cross (vect12, vect1h);
628 const int sign12 = SIGN3(cross12_1p); /* Extract X,Y,Z signs as 0..7 or 0...63 integer */
629
630 const Vector_t vect23 = t.v2() - t.v3();
631 const Vector_t vect2h = t.v2() - p;
632 const Vector_t cross23_2p = cross (vect23, vect2h);
633 const int sign23 = SIGN3(cross23_2p);
634
635 const Vector_t vect31 = t.v3() - t.v1();
636 const Vector_t vect3h = t.v3() - p;
637 const Vector_t cross31_3p = cross (vect31, vect3h);
638 const int sign31 = SIGN3(cross31_3p);
639
640 /*
641 If all three crossproduct vectors agree in their component signs,
642 then the point must be inside all three.
643 P cannot be OUTSIDE all three sides simultaneously.
644 */
645 return ((sign12 & sign23 & sign31) == 0) ? OUTSIDE : INSIDE;
646}
647
648
649/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
650
651 This is the main algorithm procedure.
652 Triangle t is compared with a unit cube,
653 centered on the origin.
654 It returns INSIDE (0) or OUTSIDE(1) if t
655 intersects or does not intersect the cube.
656*/
657static int
658triangle_intersects_cube (
659 const Triangle& t
660 ) {
661 int v1_test;
662 int v2_test;
663 int v3_test;
664
665 /*
666 First compare all three vertexes with all six face-planes
667 If any vertex is inside the cube, return immediately!
668 */
669 if ((v1_test = face_plane(t.v1())) == INSIDE) return(INSIDE);
670 if ((v2_test = face_plane(t.v2())) == INSIDE) return(INSIDE);
671 if ((v3_test = face_plane(t.v3())) == INSIDE) return(INSIDE);
672
673 /*
674 If all three vertexes were outside of one or more face-planes,
675 return immediately with a trivial rejection!
676 */
677 if ((v1_test & v2_test & v3_test) != 0) return(OUTSIDE);
678
679 /*
680 Now do the same trivial rejection test for the 12 edge planes
681 */
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);
686
687 /*
688 Now do the same trivial rejection test for the 8 corner planes
689 */
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);
694
695 /*
696 If vertex 1 and 2, as a pair, cannot be trivially rejected
697 by the above tests, then see if the v1-->v2 triangle edge
698 intersects the cube. Do the same for v1-->v3 and v2-->v3./
699 Pass to the intersection algorithm the "OR" of the outcode
700 bits, so that only those cube faces which are spanned by
701 each triangle edge need be tested.
702 */
703 if ((v1_test & v2_test) == 0)
704 if (check_line (t.v1(), t.v2(), v1_test|v2_test) == INSIDE) return(INSIDE);
705 if ((v1_test & v3_test) == 0)
706 if (check_line (t.v1(), t.v3(), v1_test|v3_test) == INSIDE) return(INSIDE);
707 if ((v2_test & v3_test) == 0)
708 if (check_line (t.v2(), t.v3(), v2_test|v3_test) == INSIDE) return(INSIDE);
709
710 /*
711 By now, we know that the triangle is not off to any side,
712 and that its sides do not penetrate the cube. We must now
713 test for the cube intersecting the interior of the triangle.
714 We do this by looking for intersections between the cube
715 diagonals and the triangle...first finding the intersection
716 of the four diagonals with the plane of the triangle, and
717 then if that intersection is inside the cube, pursuing
718 whether the intersection point is inside the triangle itself.
719
720 To find plane of the triangle, first perform crossproduct on
721 two triangle side vectors to compute the normal vector.
722 */
723 Vector_t vect12 = t.v1() - t.v2();
724 Vector_t vect13 = t.v1() - t.v3();
725 Vector_t norm = cross (vect12, vect13);
726
727 /*
728 The normal vector "norm" X,Y,Z components are the coefficients
729 of the triangles AX + BY + CZ + D = 0 plane equation. If we
730 solve the plane equation for X=Y=Z (a diagonal), we get
731 -D/(A+B+C) as a metric of the distance from cube center to the
732 diagonal/plane intersection. If this is between -0.5 and 0.5,
733 the intersection is inside the cube. If so, we continue by
734 doing a point/triangle intersection.
735 Do this for all four diagonals.
736 */
737 double d = norm[0] * t.v1(0) + norm[1] * t.v1(1) + norm[2] * t.v1(2);
738
739 /*
740 if one of the diagonals is parallel to the plane, the other will
741 intersect the plane
742 */
743 double denom = norm[0] + norm[1] + norm[2];
744 if (cmp::eq_zero(std::abs(denom)) == false) {
745 /* skip parallel diagonals to the plane; division by 0 can occure */
746 Vector_t hitpp = d / denom;
747 if (cmp::le(std::abs(hitpp[0]), 0.5))
748 if (point_triangle_intersection(hitpp,t) == INSIDE)
749 return(INSIDE);
750 }
751 denom = norm[0] + norm[1] - norm[2];
752 if (cmp::eq_zero(std::abs(denom)) == false) {
753 Vector_t hitpn;
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)
757 return(INSIDE);
758 }
759 denom = norm[0] - norm[1] + norm[2];
760 if (cmp::eq_zero(std::abs(denom)) == false) {
761 Vector_t hitnp;
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)
765 return(INSIDE);
766 }
767 denom = norm[0] - norm[1] - norm[2];
768 if (cmp::eq_zero(std::abs(denom)) == false) {
769 Vector_t hitnn;
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)
773 return(INSIDE);
774 }
775
776 /*
777 No edge touched the cube; no cube diagonal touched the triangle.
778 We're done...there was no intersection.
779 */
780 return(OUTSIDE);
781}
782
783/*
784 * Ray class, for use with the optimized ray-box intersection test
785 * described in:
786 *
787 * Amy Williams, Steve Barrus, R. Keith Morley, and Peter Shirley
788 * "An Efficient and Robust Ray-Box Intersection Algorithm"
789 * Journal of graphics tools, 10(1):49-54, 2005
790 *
791 */
792
793class Ray {
794public:
795 Ray () { }
797 origin = o;
798 direction = d;
799 inv_direction = Vector_t ({1/d[0], 1/d[1], 1/d[2]});
800 sign[0] = (inv_direction[0] < 0);
801 sign[1] = (inv_direction[1] < 0);
802 sign[2] = (inv_direction[2] < 0);
803 }
804 Ray(const Ray &r) {
805 origin = r.origin;
808 sign[0] = r.sign[0]; sign[1] = r.sign[1]; sign[2] = r.sign[2];
809 }
810 const Ray &operator=(const Ray& a) = delete;
811
815 int sign[3];
816};
817
818
819/*
820 * Axis-aligned bounding box class, for use with the optimized ray-box
821 * intersection test described in:
822 *
823 * Amy Williams, Steve Barrus, R. Keith Morley, and Peter Shirley
824 * "An Efficient and Robust Ray-Box Intersection Algorithm"
825 * Journal of graphics tools, 10(1):49-54, 2005
826 *
827 */
828
829class Voxel {
830public:
831 Voxel () { }
832 Voxel (const Vector_t &min, const Vector_t &max) {
833 pts[0] = min;
834 pts[1] = max;
835 }
836 inline void scale (
837 const Vector_t& scale
838 ) {
839 pts[0][0] *= scale[0];
840 pts[0][1] *= scale[1];
841 pts[0][2] *= scale[2];
842 pts[1][0] *= scale[0];
843 pts[1][1] *= scale[1];
844 pts[1][2] *= scale[2];
845 }
846
847 // (t0, t1) is the interval for valid hits
849 const Ray& r,
850 double& tmin, // tmin and tmax are unchanged, if there is
851 double& tmax // no intersection
852 ) const {
853 double tmin_ = (pts[r.sign[0]][0] - r.origin[0]) * r.inv_direction[0];
854 double tmax_ = (pts[1-r.sign[0]][0] - r.origin[0]) * r.inv_direction[0];
855 const double tymin = (pts[r.sign[1]][1] - r.origin[1]) * r.inv_direction[1];
856 const double tymax = (pts[1-r.sign[1]][1] - r.origin[1]) * r.inv_direction[1];
857 if ( cmp::gt(tmin_, tymax) || cmp::gt(tymin, tmax_) )
858 return 0; // no intersection
859 if (cmp::gt(tymin, tmin_))
860 tmin_ = tymin;
861 if (cmp::lt(tymax, tmax_))
862 tmax_ = tymax;
863 const double tzmin = (pts[r.sign[2]][2] - r.origin[2]) * r.inv_direction[2];
864 const double tzmax = (pts[1-r.sign[2]][2] - r.origin[2]) * r.inv_direction[2];
865 if ( cmp::gt(tmin_, tzmax) || cmp::gt(tzmin, tmax_) )
866 return 0; // no intersection
867 if (cmp::gt(tzmin, tmin_))
868 tmin_ = tzmin;
869 tmin = tmin_;
870 if (cmp::lt(tzmax, tmax_))
871 tmax_ = tzmax;
872 tmax = tmax_;
873 return cmp::ge_zero(tmax);
874 }
875
876 inline bool intersect (
877 const Ray& r
878 ) const {
879 double tmin = 0.0;
880 double tmax = 0.0;
881 return intersect(r, tmin, tmax);
882 }
883
884 inline int intersect (
885 const Triangle& t
886 ) const {
887 Voxel v_ = *this;
888 Triangle t_ = t;
889 const Vector_t scaleby = 1.0 / v_.extent();
890 v_.scale (scaleby);
891 t_.scale (scaleby , v_.pts[0] + 0.5);
892 return triangle_intersects_cube (t_);
893 }
894
895 inline Vector_t extent () const {
896 return (pts[1] - pts[0]);
897 }
898
899 inline bool isInside (
900 const Vector_t& P
901 ) const {
902 return (
903 cmp::ge(P[0], pts[0][0])
904 && cmp::ge(P[1], pts[0][1])
905 && cmp::ge(P[2], pts[0][2])
906 && cmp::le(P[0], pts[1][0])
907 && cmp::le(P[1], pts[1][1])
908 && cmp::le(P[2], pts[1][2]));
909 }
910
912};
913
914static inline Vector_t normalVector (
915 const Vector_t& A,
916 const Vector_t& B,
917 const Vector_t& C
918 ) {
919 const Vector_t N = cross (B - A, C - A);
920 const double magnitude = std::sqrt (SQR (N (0)) + SQR (N (1)) + SQR (N (2)));
921 PAssert (cmp::gt_zero(magnitude)); // in case we have degenerated triangles
922 return N / magnitude;
923}
924
925// Calculate the area of triangle given by id.
926static inline double computeArea (
927 const Vector_t& A,
928 const Vector_t& B,
929 const Vector_t& C
930 ) {
931 const Vector_t AB = A - B;
932 const Vector_t AC = C - A;
933 return(0.5 * std::sqrt (dot (AB, AB) * dot (AC, AC) - dot (AB, AC) * dot (AB, AC)));
934}
935
936
937/*
938 ____ _
939 / ___| ___ ___ _ __ ___ ___| |_ _ __ _ _
940| | _ / _ \/ _ \| '_ ` _ \ / _ \ __| '__| | | |
941| |_| | __/ (_) | | | | | | __/ |_| | | |_| |
942 \____|\___|\___/|_| |_| |_|\___|\__|_| \__, |
943 |___/
944*/
945
947 Definition (
948 SIZE, "GEOMETRY", "The \"GEOMETRY\" statement defines the beam pipe geometry.") {
949
951 ("FGEOM",
952 "Specifies the geometry file [H5hut]",
953 "");
954
956 ("TOPO",
957 "If FGEOM is selected topo is over-written. ",
958 {"RECTANGULAR", "BOXCORNER", "ELLIPTIC"},
959 "ELLIPTIC");
960
962 ("LENGTH",
963 "Specifies the length of a tube shaped elliptic beam pipe [m]",
964 1.0);
965
967 ("S",
968 "Specifies the start of a tube shaped elliptic beam pipe [m]",
969 0.0);
970
972 ("A",
973 "Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]",
974 0.025);
975
977 ("B",
978 "Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]",
979 0.025);
980
982 ("L1",
983 "In case of BOXCORNER Specifies first part with height == B [m]",
984 0.5);
985
987 ("L2",
988 "In case of BOXCORNER Specifies first second with height == B-C [m]",
989 0.2);
990
992 ("C",
993 "In case of BOXCORNER Specifies height of corner C [m]",
994 0.01);
995
997 ("XYZSCALE",
998 "Multiplicative scaling factor for coordinates ",
999 1.0);
1000
1002 ("XSCALE",
1003 "Multiplicative scaling factor for X coordinates ",
1004 1.0);
1005
1007 ("YSCALE",
1008 "Multiplicative scaling factor for Y coordinates ",
1009 1.0);
1010
1012 ("ZSCALE",
1013 "Multiplicative scaling factor for Z coordinates ",
1014 1.0);
1015
1017 ("ZSHIFT",
1018 "Shift in z direction",
1019 0.0);
1020
1022 ("INSIDEPOINT", "A point inside the geometry");
1023
1025
1026 BoundaryGeometry* defGeometry = clone ("UNNAMED_GEOMETRY");
1027 defGeometry->builtin = true;
1028
1029 Tinitialize_m = IpplTimings::getTimer ("Initialize geometry");
1030 TisInside_m = IpplTimings::getTimer ("Inside test");
1031 TfastIsInside_m = IpplTimings::getTimer ("Fast inside test");
1032 TRayTrace_m = IpplTimings::getTimer ("Ray tracing");
1033 TPartInside_m = IpplTimings::getTimer ("Particle Inside");
1034
1036
1037 try {
1038 defGeometry->update ();
1039 OpalData::getInstance ()->define (defGeometry);
1040 } catch (...) {
1041 delete defGeometry;
1042 }
1043 gsl_rng_env_setup();
1044 randGen_m = gsl_rng_alloc(gsl_rng_default);
1045
1046 if (!h5FileName_m.empty ())
1047 initialize ();
1048}
1049
1051 const std::string& name,
1052 BoundaryGeometry* parent
1053 ) : Definition (name, parent) {
1054 gsl_rng_env_setup();
1055 randGen_m = gsl_rng_alloc(gsl_rng_default);
1056
1057 Tinitialize_m = IpplTimings::getTimer ("Initialize geometry");
1058 TisInside_m = IpplTimings::getTimer ("Inside test");
1059 TfastIsInside_m = IpplTimings::getTimer ("Fast inside test");
1060 TRayTrace_m = IpplTimings::getTimer ("Ray tracing");
1061 TPartInside_m = IpplTimings::getTimer ("Particle Inside");
1062
1064 if (!h5FileName_m.empty ())
1065 initialize ();
1066 }
1067
1071
1073 // Can replace only by another GEOMETRY.
1074 return dynamic_cast<BGeometryBase*>(object) != 0;
1075}
1076
1078 return new BoundaryGeometry (name, this);
1079}
1080
1082 if (getOpalName ().empty ()) setOpalName ("UNNAMED_GEOMETRY");
1083}
1084
1085
1087 update ();
1088 Tinitialize_m = IpplTimings::getTimer ("Initialize geometry");
1089 TisInside_m = IpplTimings::getTimer ("Inside test");
1090 TfastIsInside_m = IpplTimings::getTimer ("Fast inside test");
1091 TRayTrace_m = IpplTimings::getTimer ("Ray tracing");
1092 TPartInside_m = IpplTimings::getTimer ("Particle Inside");
1093}
1094
1096 BoundaryGeometry* geom = dynamic_cast<BoundaryGeometry*>(
1098
1099 if (geom == 0)
1100 throw OpalException ("BoundaryGeometry::find()", "Geometry \""
1101 + name + "\" not found.");
1102 return geom;
1103}
1104
1107
1108int
1110 const int triangle_id,
1111 const int i,
1112 const int j,
1113 const int k
1114 ) {
1115 const Triangle t(
1116 getPoint (triangle_id, 1),
1117 getPoint (triangle_id, 2),
1118 getPoint (triangle_id, 3)
1119 );
1120
1121 const Vector_t P({
1122 i * voxelMesh_m.sizeOfVoxel [0] + voxelMesh_m.minExtent[0],
1123 j * voxelMesh_m.sizeOfVoxel [1] + voxelMesh_m.minExtent[1],
1124 k * voxelMesh_m.sizeOfVoxel [2] + voxelMesh_m.minExtent[2]
1125 });
1126
1127 Voxel v(P, P+voxelMesh_m.sizeOfVoxel);
1128
1129 return v.intersect (t);
1130}
1131
1132/*
1133 Find the 3D intersection of a line segment, ray or line with a triangle.
1134
1135 Input:
1136 kind: type of test: SEGMENT, RAY or LINE
1137 P0, P0: defining
1138 a line segment from P0 to P1 or
1139 a ray starting at P0 with directional vector P1-P0 or
1140 a line through P0 and P1
1141 V0, V1, V2: the triangle vertices
1142
1143 Output:
1144 I: intersection point (when it exists)
1145
1146 Return values for line segment and ray test :
1147 -1 = triangle is degenerated (a segment or point)
1148 0 = disjoint (no intersect)
1149 1 = are in the same plane
1150 2 = intersect in unique point I1
1151
1152 Return values for line intersection test :
1153 -1: triangle is degenerated (a segment or point)
1154 0: disjoint (no intersect)
1155 1: are in the same plane
1156 2: intersect in unique point I1, with r < 0.0
1157 3: intersect in unique point I1, with 0.0 <= r <= 1.0
1158 4: intersect in unique point I1, with 1.0 < r
1159
1160 For algorithm and implementation see:
1161 http://geomalgorithms.com/a06-_intersect-2.html
1162
1163 Copyright 2001 softSurfer, 2012 Dan Sunday
1164 This code may be freely used and modified for any purpose
1165 providing that this copyright notice is included with it.
1166 SoftSurfer makes no warranty for this code, and cannot be held
1167 liable for any real or imagined damage resulting from its use.
1168 Users of this code must verify correctness for their application.
1169 */
1170
1171int
1173 const enum INTERSECTION_TESTS kind,
1174 const Vector_t& P0,
1175 const Vector_t& P1,
1176 const int triangle_id,
1177 Vector_t& I
1178 ) {
1179 const Vector_t V0 = getPoint (triangle_id, 1);
1180 const Vector_t V1 = getPoint (triangle_id, 2);
1181 const Vector_t V2 = getPoint (triangle_id, 3);
1182
1183 // get triangle edge vectors and plane normal
1184 const Vector_t u = V1 - V0; // triangle vectors
1185 const Vector_t v = V2 - V0;
1186 const Vector_t n = cross (u, v);
1187 if (n == (Vector_t)0) // triangle is degenerate
1188 return -1; // do not deal with this case
1189
1190 const Vector_t dir = P1 - P0; // ray direction vector
1191 const Vector_t w0 = P0 - V0;
1192 const double a = -dot(n,w0);
1193 const double b = dot(n,dir);
1194 if (cmp::eq_zero(b)) { // ray is parallel to triangle plane
1195 if (cmp::eq_zero(a)) { // ray lies in triangle plane
1196 return 1;
1197 } else { // ray disjoint from plane
1198 return 0;
1199 }
1200 }
1201
1202 // get intersect point of ray with triangle plane
1203 const double r = a / b;
1204 switch (kind) {
1205 case RAY:
1206 if (cmp::lt_zero(r)) { // ray goes away from triangle
1207 return 0; // => no intersect
1208 }
1209 break;
1210 case SEGMENT:
1211 if (cmp::lt_zero(r) || cmp::lt(1.0, r)) { // intersection on extended
1212 return 0; // segment
1213 }
1214 break;
1215 case LINE:
1216 break;
1217 };
1218 I = P0 + r * dir; // intersect point of ray and plane
1219
1220 // is I inside T?
1221 const double uu = dot(u,u);
1222 const double uv = dot(u,v);
1223 const double vv = dot(v,v);
1224 const Vector_t w = I - V0;
1225 const double wu = dot(w,u);
1226 const double wv = dot(w,v);
1227 const double D = uv * uv - uu * vv;
1228
1229 // get and test parametric coords
1230 const double s = (uv * wv - vv * wu) / D;
1231 if (cmp::lt_zero(s) || cmp::gt(s, 1.0)) { // I is outside T
1232 return 0;
1233 }
1234 const double t = (uv * wu - uu * wv) / D;
1235 if (cmp::lt_zero(t) || cmp::gt((s + t), 1.0)) { // I is outside T
1236 return 0;
1237 }
1238 // intersection point is in triangle
1239 if (cmp::lt_zero(r)) { // in extended segment in opposite
1240 return 2; // direction of ray
1241 } else if (cmp::ge_zero(r) && cmp::le(r, 1.0)) { // in segment
1242 return 3;
1243 } else { // in extended segment in
1244 return 4; // direction of ray
1245 }
1246}
1247
1248static inline double magnitude (
1249 const Vector_t& v
1250 ) {
1251 return std::sqrt (dot (v,v));
1252}
1253
1254bool
1256 const Vector_t& P // [in] pt to test
1257 ) {
1258
1259 /*
1260 select a "close" reference pt outside the bounding box
1261 */
1262 // right boundary of bounding box (x direction)
1263 double x = minExtent_m[0] - 0.01;
1264 double distance = P[0] - x;
1265 Vector_t ref_pt {x, P[1], P[2]};
1266
1267 // left boundary of bounding box (x direction)
1268 x = maxExtent_m[0] + 0.01;
1269 if (cmp::lt(x - P[0], distance)) {
1270 distance = x - P[0];
1271 ref_pt = {x, P[1], P[2]};
1272 }
1273
1274 // lower boundary of bounding box (y direction)
1275 double y = minExtent_m[1] - 0.01;
1276 if (cmp::lt(P[1] - y, distance)) {
1277 distance = P[1] -y;
1278 ref_pt = {P[0], y, P[1]};
1279 }
1280
1281 // upper boundary of bounding box (y direction)
1282 y = maxExtent_m[1] + 0.01;
1283 if (cmp::lt(y - P[1], distance)) {
1284 distance = y - P[1];
1285 ref_pt = {P[0], y, P[2]};
1286 }
1287 // front boundary of bounding box (z direction)
1288 double z = minExtent_m[2] - 0.01;
1289 if (cmp::lt(P[2] - z, distance)) {
1290 distance = P[2] - z;
1291 ref_pt = {P[0], P[1], z};
1292 }
1293 // back boundary of bounding box (z direction)
1294 z = maxExtent_m[2] + 0.01;
1295 if (cmp::lt(z - P[2], distance)) {
1296 ref_pt = {P[0], P[1], z};
1297 }
1298
1299 /*
1300 the test returns the number of intersections =>
1301 since the reference point is outside, P is inside
1302 if the result is odd.
1303 */
1304 int k = fastIsInside (ref_pt, P);
1305 return (k % 2) == 1;
1306}
1307
1308/*
1309 searching a point inside the geometry.
1310
1311 sketch of the algorithm:
1312 In a first step, we try to find a line segment defined by one
1313 point outside the bounding box and a point somewhere inside the
1314 bounding box which has intersects with the geometry.
1315
1316 If the number of intersections is odd, the center point is inside
1317 the geometry and we are already done.
1318
1319 If the number of intersections is even, there must be points on
1320 this line segment which are inside the geometry. In the next step
1321 we have to find one if these points.
1322
1323
1324 A bit more in detail:
1325
1326 1. Finding a line segment intersecting the geometry
1327 For the fast isInside test it is of advantage to choose line segments
1328 parallel to the X, Y or Z axis. In this implementation we choose as
1329 point outside the bounding box a point on an axis but close to the
1330 bounding box and the center of the bounding box. This gives us six
1331 line segments to test. This covers not all possible geometries but
1332 most likely almost all. If not, it's easy to extend.
1333
1334 2. Searching for a point inside the geometry
1335 In the first step we get a line segment from which we know, that one
1336 point is ouside the geometry (P_out) and the other inside the bounding
1337 box (Q). We also know the number of intersections n_i of this line
1338 segment with the geometry.
1339
1340 If n_i is odd, Q is inside the boundary!
1341
1342 while (true); do
1343 bisect the line segment [P_out, Q], let B the bisecting point.
1344
1345 compute number of intersections of the line segment [P_out, B]
1346 and the geometry.
1347
1348 If the number of intersections is odd, then B is inside the geometry
1349 and we are done. Set P_in = B and exit loop.
1350
1351 Otherwise we have either no or an even number of intersections.
1352 In both cases this implies that B is a point outside the geometry.
1353
1354 If the number of intersection of [P_out, B] is even but not equal zero,
1355 it might be that *all* intersections are in this line segment and none in
1356 [B, Q].
1357 In this case we continue with the line segment [P_out, Q] = [P_out, B],
1358 otherwise with the line segment [P_out, Q] = [B, Q].
1359*/
1360bool
1362 void
1363 ) {
1364 *gmsg << level2 << "* Searching for a point inside the geometry..." << endl;
1365 /*
1366 find line segment
1367 */
1368 Vector_t Q {(maxExtent_m + minExtent_m) / 2};
1369 std::vector<Vector_t> P_outs {
1370 {minExtent_m[0]-0.01, Q[1], Q[2]},
1371 {maxExtent_m[0]+0.01, Q[1], Q[2]},
1372 {Q[0], minExtent_m[1]-0.01, Q[2]},
1373 {Q[0], maxExtent_m[1]+0.01, Q[2]},
1374 {Q[0], Q[1], minExtent_m[2]-0.01},
1375 {Q[0], Q[1], maxExtent_m[2]+0.01}
1376 };
1377 int n_i = 0;
1378 Vector_t P_out;
1379 for (const auto& P: P_outs) {
1380 n_i = fastIsInside (P, Q);
1381 if (n_i != 0) {
1382 P_out = P;
1383 break;
1384 }
1385 }
1386 if (n_i == 0) {
1387 // this is possible with some obscure geometries.
1388 return false;
1389 }
1390
1391 /*
1392 if the number of intersections is odd, Q is inside the geometry
1393 */
1394 if (n_i % 2 == 1) {
1395 insidePoint_m = Q;
1396 return true;
1397 }
1398 while (true) {
1399 Vector_t B {(P_out + Q) / 2};
1400 int n = fastIsInside (P_out, B);
1401 if (n % 2 == 1) {
1402 insidePoint_m = B;
1403 return true;
1404 } else if (n == n_i) {
1405 Q = B;
1406 } else {
1407 P_out = B;
1408 }
1409 n_i = n;
1410 }
1411 // never reached
1412 return false;
1413}
1414
1415/*
1416 Game plan:
1417 Count number of intersection of the line segment defined by P and a reference
1418 pt with the boundary. If the reference pt is inside the boundary and the number
1419 of intersections is even, then P is inside the geometry. Otherwise P is outside.
1420 To count the number of intersection, we divide the line segment in N segments
1421 and run the line-segment boundary intersection test for all these segments.
1422 N must be choosen carefully. It shouldn't be to large to avoid needless test.
1423 */
1424int
1426 const Vector_t& reference_pt, // [in] reference pt inside the boundary
1427 const Vector_t& P // [in] pt to test
1428 ) {
1429 const Voxel c (minExtent_m, maxExtent_m);
1430 if (!c.isInside (P)) return 1;
1432#ifdef ENABLE_DEBUG
1433 int saved_flags = debugFlags_m;
1435 *gmsg << "* " << __func__ << ": "
1436 << "reference_pt=" << reference_pt
1437 << ", P=" << P << endl;
1439 }
1440#endif
1441 const Vector_t v = reference_pt - P;
1442 const int N = std::ceil (magnitude (v) / std::min ({voxelMesh_m.sizeOfVoxel [0],
1443 voxelMesh_m.sizeOfVoxel [1],
1444 voxelMesh_m.sizeOfVoxel [2]}));
1445 const Vector_t v_ = v / N;
1446 Vector_t P0 = P;
1447 Vector_t P1 = P + v_;
1448 Vector_t I;
1449 int triangle_id = -1;
1450 int result = 0;
1451 for (int i = 0; i < N; i++) {
1452 result += intersectTinyLineSegmentBoundary (P0, P1, I, triangle_id);
1453 P0 = P1;
1454 P1 += v_;
1455 }
1456#ifdef ENABLE_DEBUG
1458 *gmsg << "* " << __func__ << ": "
1459 << "result: " << result << endl;
1460 debugFlags_m = saved_flags;
1461 }
1462#endif
1464 return result;
1465}
1466
1467/*
1468 P must be *inside* the boundary geometry!
1469
1470 return value:
1471 0 no intersection
1472 1 intersection found, I is set to the first intersection coordinates in
1473 ray direction
1474 */
1475int
1477 const Vector_t& P,
1478 const Vector_t& v,
1479 Vector_t& I
1480 ) {
1482#ifdef ENABLE_DEBUG
1483 int saved_flags = debugFlags_m;
1485 *gmsg << "* " << __func__ << ": "
1486 << " ray: "
1487 << " origin=" << P
1488 << " dir=" << v
1489 << endl;
1491 }
1492#endif
1493 /*
1494 set P1 to intersection of ray with bbox of voxel mesh
1495 run line segment boundary intersection test with P and P1
1496 */
1497 Ray r = Ray (P, v);
1498 Voxel c = Voxel (voxelMesh_m.minExtent+0.25*voxelMesh_m.sizeOfVoxel,
1499 voxelMesh_m.maxExtent-0.25*voxelMesh_m.sizeOfVoxel);
1500 double tmin = 0.0;
1501 double tmax = 0.0;
1502 c.intersect (r, tmin, tmax);
1503 int triangle_id = -1;
1504 int result = (intersectLineSegmentBoundary (
1505 P, P + (tmax*v),
1506 I, triangle_id) > 0) ? 1 : 0;
1507#ifdef ENABLE_DEBUG
1509 *gmsg << "* " << __func__ << ": "
1510 << " result=" << result
1511 << " I=" << I
1512 << endl;
1513 debugFlags_m = saved_flags;
1514 }
1515#endif
1517 return result;
1518}
1519
1520/*
1521 Map point to unique voxel ID.
1522
1523 Remember:
1524 * hr_m: is the mesh size
1525 * nr_m: number of mesh points
1526 */
1527inline int
1529 const int i,
1530 const int j,
1531 const int k
1532 ) {
1533 if (i < 0 || i >= voxelMesh_m.nr_m[0] ||
1534 j < 0 || j >= voxelMesh_m.nr_m[1] ||
1535 k < 0 || k >= voxelMesh_m.nr_m[2]) {
1536 return 0;
1537 }
1538 return 1 + k * voxelMesh_m.nr_m[0] * voxelMesh_m.nr_m[1] + j * voxelMesh_m.nr_m[0] + i;
1539}
1540
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])) { \
1548 *gmsg << level2 \
1549 << "* " << __func__ << ":" \
1550 << " WARNING: pt=" << pt \
1551 << " is outside the bbox" \
1552 << " i=" << i \
1553 << " j=" << j \
1554 << " k=" << k \
1555 << endl; \
1556 } \
1557 }
1558
1559inline Vector_t
1561 const int i,
1562 const int j,
1563 const int k
1564 ) {
1565 return Vector_t ({
1566 i * voxelMesh_m.sizeOfVoxel [0] + voxelMesh_m.minExtent[0],
1567 j * voxelMesh_m.sizeOfVoxel [1] + voxelMesh_m.minExtent[1],
1568 k * voxelMesh_m.sizeOfVoxel [2] + voxelMesh_m.minExtent[2]});
1569}
1570
1571inline Vector_t
1573 const Vector_t& pt
1574 ) {
1575 const int i = std::floor ((pt[0] - voxelMesh_m.minExtent [0]) / voxelMesh_m.sizeOfVoxel [0]);
1576 const int j = std::floor ((pt[1] - voxelMesh_m.minExtent [1]) / voxelMesh_m.sizeOfVoxel [1]);
1577 const int k = std::floor ((pt[2] - voxelMesh_m.minExtent [2]) / voxelMesh_m.sizeOfVoxel [2]);
1578
1579 return mapIndices2Voxel (i, j, k);
1580}
1581
1582
1583inline void
1585
1586 for (unsigned int triangle_id = 0; triangle_id < Triangles_m.size(); triangle_id++) {
1587 Vector_t v1 = getPoint (triangle_id, 1);
1588 Vector_t v2 = getPoint (triangle_id, 2);
1589 Vector_t v3 = getPoint (triangle_id, 3);
1590 Vector_t bbox_min = {
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]}) };
1594 Vector_t bbox_max = {
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;
1600 mapPoint2VoxelIndices (bbox_min, i_min, j_min, k_min);
1601 mapPoint2VoxelIndices (bbox_max, i_max, j_max, k_max);
1602
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++) {
1606 // test if voxel (i,j,k) has an intersection with triangle
1607 if (intersectTriangleVoxel (triangle_id, i, j, k) == INSIDE) {
1608 auto id = mapVoxelIndices2ID (i, j, k);
1609 voxelMesh_m.ids [id].insert (triangle_id);
1610 }
1611 }
1612 }
1613 }
1614 } // for_each triangle
1615 *gmsg << level2 << "* Mesh voxelization done" << endl;
1616
1617 // write voxel mesh into VTK file
1618 if (Ippl::myNode() == 0 && Options::enableVTK) {
1619 std::string vtkFileName = Util::combineFilePath({
1621 "testBBox.vtk"
1622 });
1623 bool writeVTK = false;
1624
1625 if (!std::filesystem::exists(vtkFileName)) {
1626 writeVTK = true;
1627 } else {
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) {
1631 writeVTK = true;
1632 }
1633 }
1634
1635 if (writeVTK) {
1636 write_voxel_mesh (vtkFileName,
1637 voxelMesh_m.ids,
1638 voxelMesh_m.sizeOfVoxel,
1639 voxelMesh_m.nr_m,
1640 voxelMesh_m.minExtent);
1641 }
1642 }
1643}
1644
1646
1647 class Local {
1648
1649 public:
1650
1651 static void computeGeometryInterval (BoundaryGeometry* bg) {
1652
1653 bg->minExtent_m = get_min_extent (bg->Points_m);
1654 bg->maxExtent_m = get_max_extent (bg->Points_m);
1655
1656 /*
1657 Calculate the maximum size of triangles. This value will be used to
1658 define the voxel size
1659 */
1660 double longest_edge_max_m = 0.0;
1661 for (unsigned int i = 0; i < bg->Triangles_m.size(); i++) {
1662 // compute length of longest edge
1663 const Vector_t x1 = bg->getPoint (i, 1);
1664 const Vector_t x2 = bg->getPoint (i, 2);
1665 const Vector_t x3 = bg->getPoint (i, 3);
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]));
1672
1673 double max = length_edge1;
1674 if (length_edge2 > max) max = length_edge2;
1675 if (length_edge3 > max) max = length_edge3;
1676
1677 // save min and max of length of longest edge
1678 if (longest_edge_max_m < max) longest_edge_max_m = max;
1679 }
1680
1681 /*
1682 In principal the number of discretization nr_m is the extent of
1683 the geometry divided by the extent of the largest triangle. Whereby
1684 the extent of a triangle is defined as the lenght of its longest
1685 edge. Thus the largest triangle is the triangle with the longest edge.
1686
1687 But if the hot spot, i.e., the multipacting/field emission zone is
1688 too small that the normal bounding box covers the whole hot spot, the
1689 expensive triangle-line intersection tests will be frequently called.
1690 In these cases, we have to use smaller bounding box size to speed up
1691 simulation.
1692
1693 Todo:
1694 The relation between bounding box size and simulation time step &
1695 geometry shape maybe need to be summarized and modeled in a more
1696 flexible manner and could be adjusted in input file.
1697 */
1698 Vector_t extent = bg->maxExtent_m - bg->minExtent_m;
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);
1702
1703 bg->voxelMesh_m.sizeOfVoxel = extent / bg->voxelMesh_m.nr_m;
1706 bg->voxelMesh_m.nr_m += 1;
1707 }
1708
1709 /*
1710 To speed up ray-triangle intersection tests, the normal vector of
1711 all triangles are pointing inward. Since this is clearly not
1712 guaranteed for the triangles in the H5hut file, this must be checked
1713 for each triangle and - if necessary changed - after reading the mesh.
1714
1715 To test whether the normal of a triangle is pointing inward or outward,
1716 we choose a random point P close to the center of the triangle and test
1717 whether this point is inside or outside the geometry. The way we choose
1718 P guarantees that the vector spanned by P and a vertex of the triangle
1719 points into the same direction as the normal vector. From this it
1720 follows that if P is inside the geometry the normal vector is pointing
1721 to the inside and vise versa.
1722
1723 Since the inside-test is computational expensive we perform this test
1724 for one reference triangle T (per sub-mesh) only. Knowing the adjacent
1725 triangles for all three edges of a triangle for all triangles of the
1726 mesh facilitates another approach using the orientation of the
1727 reference triangle T. Assuming that the normal vector of T points to
1728 the inside of the geometry an adjacent triangle of T has an inward
1729 pointing normal vector if and only if it has the same orientation as
1730 T.
1731
1732 Starting with the reference triangle T we can change the orientation
1733 of the adjancent triangle of T and so on.
1734
1735 NOTE: For the time being we do not make use of the inward pointing
1736 normals.
1737
1738 FIXME: Describe the basic ideas behind the following comment! Without
1739 it is completely unclear.
1740
1741 Following combinations are possible:
1742 1,1 && 2,2 1,2 && 2,1 1,3 && 2,1
1743 1,1 && 2,3 1,2 && 2,3 1,3 && 2,2
1744 1,1 && 3,2 1,2 && 3,1 1,3 && 3,1
1745 1,1 && 3,3 1,2 && 3,3 1,3 && 3,2
1746
1747 (2,1 && 1,2) (2,2 && 1,1) (2,3 && 1,1)
1748 (2,1 && 1,3) (2,2 && 1,3) (2,3 && 1,2)
1749 2,1 && 3,2 2,2 && 3,1 2,3 && 3,1
1750 2,1 && 3,3 2,2 && 3,3 2,3 && 3,2
1751
1752 (3,1 && 1,2) (3,2 && 1,1) (3,3 && 1,1)
1753 (3,1 && 1,3) (3,2 && 1,3) (3,3 && 1,2)
1754 (3,1 && 2,2) (3,2 && 2,1) (3,3 && 2,1)
1755 (3,1 && 2,3) (3,2 && 2,3) (3,3 && 2,2)
1756
1757 Note:
1758 Since we find vertices with lower enumeration first, we
1759 can ignore combinations in ()
1760
1761 2 2 2 3 3 2 3 3
1762 * * * *
1763 /|\ /|\ /|\ /|\
1764 / | \ / | \ / | \ / | \
1765 / | \ / | \ / | \ / | \
1766 / | \ / | \ / | \ / | \
1767 *----*----* *----*----* *----*----* *----*----*
1768 3 1 1 3 3 1 1 2 2 1 1 3 2 1 1 2
1769diff: (1,1) (1,2) (2,1) (2,2)
1770change orient.: yes no no yes
1771
1772
1773 2 1 2 3 3 1 3 3
1774 * * * *
1775 /|\ /|\ /|\ /|\
1776 / | \ / | \ / | \ / | \
1777 / | \ / | \ / | \ / | \
1778 / | \ / | \ / | \ / | \
1779 *----*----* *----*----* *----*----* *----*----*
1780 3 1 2 3 3 1 2 1 2 1 2 3 2 1 2 1
1781diff: (1,-1) (1,1) (2,-1) (2,1)
1782change orient.: no yes yes no
1783
1784
1785 2 1 2 2 3 1 3 2
1786 * * * *
1787 /|\ /|\ /|\ /|\
1788 / | \ / | \ / | \ / | \
1789 / | \ / | \ / | \ / | \
1790 / | \ / | \ / | \ / | \
1791 *----*----* *----*----* *----*----* *----*----*
1792 3 1 3 2 3 1 3 1 2 1 3 2 2 1 3 1
1793diff: (1,-2) (1,-1) (2,-2) (2,-1)
1794change orient.: yes no no yes
1795
1796 3 2 3 3
1797 * *
1798 /|\ /|\
1799 / | \ / | \
1800 / | \ / | \
1801 / | \ / | \
1802 *----*----* *----*----*
1803 1 2 1 3 1 2 1 2
1804diff: (1,1) (1,2)
1805change orient.: yes no
1806
1807 3 1 3 3
1808 * *
1809 /|\ /|\
1810 / | \ / | \
1811 / | \ / | \
1812 / | \ / | \
1813 *----*----* *----*----*
1814 1 2 2 3 1 2 2 1
1815diff: (1,-1) (1,1)
1816change orient.: no yes
1817
1818 3 1 3 2
1819 * *
1820 /|\ /|\
1821 / | \ / | \
1822 / | \ / | \
1823 / | \ / | \
1824 *----*----* *----*----*
1825 1 2 3 2 1 2 3 1
1826diff: (1,-2) (1,-1)
1827change orient.: yes no
1828
1829
1830Change orientation if diff is:
1831(1,1) || (1,-2) || (2,2) || (2,-1) || (2,-1)
1832
1833 */
1834
1835 static void computeTriangleNeighbors (
1836 BoundaryGeometry* bg,
1837 std::vector<std::set<unsigned int>>& neighbors
1838 ) {
1839 std::vector<std::set<unsigned int>> adjacencies_to_pt (bg->Points_m.size());
1840
1841 // for each triangles find adjacent triangles for each vertex
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);
1847 }
1848 }
1849
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)];
1854
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);
1869
1870 neighbors [triangle_id] = intersect;
1871 }
1872 *gmsg << level2 << "* " << __func__ << ": Computing neighbors done" << endl;
1873 }
1874
1875 /*
1876 Helper function for hasInwardPointingNormal()
1877
1878 Determine if a point x is outside or inside the geometry or just on
1879 the boundary. Return true if point is inside geometry or on the
1880 boundary, false otherwise
1881
1882 The basic idea here is:
1883 If a line segment from the point to test to a random point outside
1884 the geometry has has an even number of intersections with the
1885 boundary, the point is outside the geometry.
1886
1887 Note:
1888 If the point is on the boundary, the number of intersections is 1.
1889 Points on the boundary are handled as inside.
1890
1891 A random selection of the reference point outside the boundary avoids
1892 some specific issues, like line parallel to boundary.
1893 */
1894 static inline bool isInside (BoundaryGeometry* bg, const Vector_t x) {
1896
1897 Vector_t y = Vector_t ({
1898 bg->maxExtent_m[0] * (1.1 + gsl_rng_uniform(bg->randGen_m)),
1899 bg->maxExtent_m[1] * (1.1 + gsl_rng_uniform(bg->randGen_m)),
1900 bg->maxExtent_m[2] * (1.1 + gsl_rng_uniform(bg->randGen_m))});
1901
1902 std::vector<Vector_t> intersection_points;
1903 //int num_intersections = 0;
1904
1905 for (unsigned int triangle_id = 0; triangle_id < bg->Triangles_m.size(); triangle_id++) {
1906 Vector_t result;
1907 if (bg->intersectLineTriangle (SEGMENT, x, y, triangle_id, result)) {
1908 intersection_points.push_back (result);
1909 //num_intersections++;
1910 }
1911 }
1913 return ((intersection_points.size () % 2) == 1);
1914 }
1915
1916 // helper for function makeTriangleNormalInwardPointing()
1917 static bool hasInwardPointingNormal (
1918 BoundaryGeometry* const bg,
1919 const int triangle_id
1920 ) {
1921 const Vector_t& A = bg->getPoint (triangle_id, 1);
1922 const Vector_t& B = bg->getPoint (triangle_id, 2);
1923 const Vector_t& C = bg->getPoint (triangle_id, 3);
1924 const Vector_t triNormal = normalVector (A, B, C);
1925
1926 // choose a point P close to the center of the triangle
1927 //const Vector_t P = (A+B+C)/3 + triNormal * 0.1;
1928 double minvoxelmesh = bg->voxelMesh_m.sizeOfVoxel[0];
1929 if (minvoxelmesh > bg->voxelMesh_m.sizeOfVoxel[1])
1930 minvoxelmesh = bg->voxelMesh_m.sizeOfVoxel[1];
1931 if (minvoxelmesh > bg->voxelMesh_m.sizeOfVoxel[2])
1932 minvoxelmesh = bg->voxelMesh_m.sizeOfVoxel[2];
1933 const Vector_t P = (A+B+C)/3 + triNormal * minvoxelmesh;
1934 /*
1935 The triangle normal points inward, if P is
1936 - outside the geometry and the dot product is negativ
1937 - or inside the geometry and the dot product is positiv
1938
1939 Remember:
1940 The dot product is positiv only if both vectors are
1941 pointing in the same direction.
1942 */
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);
1946 }
1947
1948 // helper for function makeTriangleNormalInwardPointing()
1949 static void orientTriangle (BoundaryGeometry* bg, int ref_id, int triangle_id) {
1950 // find pts of common edge
1951 int ic[2] = {0, 0};
1952 int id[2] = {0, 0};
1953 int n = 0;
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)) {
1957 id[n] = j;
1958 ic[n] = i;
1959 n++;
1960 if (n == 2) goto edge_found;
1961 }
1962 }
1963 }
1964 PAssert (n == 2);
1965 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]));
1970 }
1971 }
1972
1973 static void makeTriangleNormalInwardPointing (BoundaryGeometry* bg) {
1974 std::vector<std::set<unsigned int>> neighbors (bg->Triangles_m.size());
1975
1976 computeTriangleNeighbors (bg, neighbors);
1977
1978 // loop over all sub-meshes
1979 int triangle_id = 0;
1980 int parts = 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);
1985 do {
1986 parts++;
1987 /*
1988 Find next untested triangle, trivial for the first sub-mesh.
1989 There is a least one not yet tested triangle!
1990 */
1991 while (isOriented[triangle_id])
1992 triangle_id++;
1993
1994 // ensure that normal of this triangle is inward pointing
1995 if (!hasInwardPointingNormal (bg, triangle_id)) {
1996 std::swap (bg->PointID (triangle_id, 2), bg->PointID (triangle_id, 3));
1997 }
1998 isOriented[triangle_id] = true;
1999
2000 // loop over all triangles in sub-mesh
2001 triangles[queue_end++] = triangle_id;
2002 do {
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;
2008 }
2009 queue_cursor++;
2010 } while (queue_cursor < queue_end && (triangle_id = triangles[queue_cursor],true));
2011 } while (queue_end < bg->Triangles_m.size());
2012
2013 if (parts == 1) {
2014 *gmsg << level2 << "* " << __func__ << ": mesh is contiguous" << endl;
2015 } else {
2016 *gmsg << level2 << "* " << __func__ << ": mesh is discontiguous (" << parts << ") parts" << endl;
2017 }
2018 *gmsg << level2 <<"* Triangle Normal built done" << endl;
2019 }
2020
2021 };
2022
2023 debugFlags_m = 0;
2024 *gmsg << level2 << "* Initializing Boundary Geometry..." << endl;
2026
2027 if (!std::filesystem::exists(h5FileName_m)) {
2028 throw OpalException("BoundaryGeometry::initialize",
2029 "Failed to open file '" + h5FileName_m +
2030 "', please check if it exists");
2031 }
2032
2033 double xscale = Attributes::getReal(itsAttr[XSCALE]);
2034 double yscale = Attributes::getReal(itsAttr[YSCALE]);
2035 double zscale = Attributes::getReal(itsAttr[ZSCALE]);
2036 double xyzscale = Attributes::getReal(itsAttr[XYZSCALE]);
2037 double zshift = (double)(Attributes::getReal (itsAttr[ZSHIFT]));
2038
2039 h5_int64_t rc;
2040#if defined (NDEBUG)
2041 (void)rc;
2042#endif
2043 rc = H5SetErrorHandler (H5AbortErrorhandler);
2044 PAssert (rc != H5_ERR);
2045 H5SetVerbosityLevel (1);
2046
2047 h5_prop_t props = H5CreateFileProp ();
2048 MPI_Comm comm = Ippl::getComm();
2049 H5SetPropFileMPIOCollective (props, &comm);
2050 h5_file_t f = H5OpenFile (h5FileName_m.c_str(), H5_O_RDONLY, props);
2051 H5CloseProp (props);
2052
2053 h5t_mesh_t* m = nullptr;
2054 H5FedOpenTriangleMesh (f, "0", &m);
2055 H5FedSetLevel (m, 0);
2056
2057 auto numTriangles = H5FedGetNumElementsTotal (m);
2058 Triangles_m.resize (numTriangles);
2059
2060 // iterate over all co-dim 0 entities, i.e. elements
2061 h5_loc_id_t local_id;
2062 int i = 0;
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);
2067 PointID (i, 0) = 0;
2068 PointID (i, 1) = local_vids[0];
2069 PointID (i, 2) = local_vids[1];
2070 PointID (i, 3) = local_vids[2];
2071 i++;
2072 }
2073 H5FedEndTraverseEntities (iter);
2074
2075 // loop over all vertices
2076 int num_points = H5FedGetNumVerticesTotal (m);
2077 Points_m.reserve (num_points);
2078 for (i = 0; i < num_points; i++) {
2079 h5_float64_t P[3];
2080 H5FedGetVertexCoordsByIndex (m, i, P);
2081 Points_m.push_back (Vector_t ({
2082 P[0] * xyzscale * xscale,
2083 P[1] * xyzscale * yscale,
2084 P[2] * xyzscale * zscale + zshift}));
2085 }
2086 H5FedCloseMesh (m);
2087 H5CloseFile (f);
2088 *gmsg << level2 << "* Reading mesh done" << endl;
2089
2090 Local::computeGeometryInterval (this);
2092 haveInsidePoint_m = false;
2093 std::vector<double> pt = Attributes::getRealArray (itsAttr[INSIDEPOINT]);
2094 if (!pt.empty()) {
2095 if (pt.size () != 3) {
2096 throw OpalException (
2097 "BoundaryGeometry::initialize()",
2098 "Dimension of INSIDEPOINT must be 3");
2099 }
2100 /* test whether this point is inside */
2101 insidePoint_m = {pt[0], pt[1], pt[2]};
2102 bool is_inside = isInside (insidePoint_m);
2103 if (is_inside == false) {
2104 throw OpalException (
2105 "BoundaryGeometry::initialize()",
2106 "INSIDEPOINT is not inside the geometry");
2107 }
2108 haveInsidePoint_m = true;
2109 } else {
2111 }
2112 if (haveInsidePoint_m == true) {
2113 *gmsg << level2 << "* using as point inside the geometry: ("
2114 << insidePoint_m[0] << ", "
2115 << insidePoint_m[1] << ", "
2116 << insidePoint_m[2] << ")" << endl;
2117 } else {
2118 *gmsg << level2 << "* no point inside the geometry found!" << endl;
2119 }
2120
2121 Local::makeTriangleNormalInwardPointing (this);
2122
2123 TriNormals_m.resize (Triangles_m.size());
2124 TriAreas_m.resize (Triangles_m.size());
2125
2126 for (size_t i = 0; i < Triangles_m.size(); i++) {
2127 const Vector_t& A = getPoint (i, 1);
2128 const Vector_t& B = getPoint (i, 2);
2129 const Vector_t& C = getPoint (i, 3);
2130
2131 TriAreas_m[i] = computeArea (A, B, C);
2132 TriNormals_m[i] = normalVector (A, B, C);
2133
2134 }
2135 *gmsg << level2 << "* Triangle barycent built done" << endl;
2136
2137 *gmsg << *this << endl;
2140}
2141
2142/*
2143 Line segment triangle intersection test. This method should be used only
2144 for "tiny" line segments or, to be more exact, if the number of
2145 voxels covering the bounding box of the line segment is small (<<100).
2146
2147 Actually the method can be used for any line segment, but may not perform
2148 well. Performace depends on the size of the bounding box of the line
2149 segment.
2150
2151 The method returns the number of intersections of the line segment defined
2152 by the points P and Q with the boundary. If there are multiple intersections,
2153 the nearest intersection point with respect to P wil be returned.
2154 */
2155int
2157 const Vector_t& P, // [i] starting point of ray
2158 const Vector_t& Q, // [i] end point of ray
2159 Vector_t& intersect_pt, // [o] intersection with boundary
2160 int& triangle_id // [o] intersected triangle
2161 ) {
2162#ifdef ENABLE_DEBUG
2164 *gmsg << "* " << __func__ << ": "
2165 << " P = " << P
2166 << ", Q = " << Q
2167 << endl;
2168 }
2169#endif
2170 const Vector_t v_ = Q - P;
2171 const Ray r = Ray (P, v_);
2172 const Vector_t bbox_min = {
2173 std::min(P[0], Q[0]),
2174 std::min(P[1], Q[1]),
2175 std::min(P[2], Q[2]) };
2176 const Vector_t bbox_max = {
2177 std::max(P[0], Q[0]),
2178 std::max(P[1], Q[1]),
2179 std::max(P[2], Q[2]) };
2180 int i_min, i_max;
2181 int j_min, j_max;
2182 int k_min, k_max;
2183 mapPoint2VoxelIndices (bbox_min, i_min, j_min, k_min);
2184 mapPoint2VoxelIndices (bbox_max, i_max, j_max, k_max);
2185
2186 Vector_t tmp_intersect_pt = Q;
2187 double tmin = 1.1;
2188
2189 /*
2190 Triangles can - and in many cases do - intersect with more than one
2191 voxel. If we loop over all voxels intersecting with the line segment
2192 spaned by the points P and Q, we might perform the same line-triangle
2193 intersection test more than once. We must this into account when
2194 counting the intersections with the boundary.
2195
2196 To avoid multiple counting we can either
2197 - build a set of all relevant triangles and loop over this set
2198 - or we loop over all voxels and remember the intersecting triangles.
2199
2200 The first solution is implemented here.
2201 */
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++) {
2206 const Vector_t bmin = mapIndices2Voxel(i, j, k);
2207 const Voxel v(bmin, bmin + voxelMesh_m.sizeOfVoxel);
2208#ifdef ENABLE_DEBUG
2210 *gmsg << "* " << __func__ << ": "
2211 << " Test voxel: (" << i << ", " << j << ", " << k << "), "
2212 << v.pts[0] << v.pts[1]
2213 << endl;
2214 }
2215#endif
2216 /*
2217 do line segment and voxel intersect? continue if not
2218 */
2219 if (!v.intersect (r)) {
2220 continue;
2221 }
2222
2223 /*
2224 get triangles intersecting with this voxel and add them to
2225 the to be tested triangles.
2226 */
2227 const int voxel_id = mapVoxelIndices2ID (i, j, k);
2228 const auto triangles_intersecting_voxel =
2229 voxelMesh_m.ids.find (voxel_id);
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());
2234 }
2235 }
2236 }
2237 }
2238 /*
2239 test all triangles intersecting with one of the above voxels
2240 if there is more than one intersection, return closest
2241 */
2242 int num_intersections = 0;
2243 int tmp_intersect_result = 0;
2244
2245 for (auto it = triangle_ids.begin ();
2246 it != triangle_ids.end ();
2247 it++) {
2248
2249 tmp_intersect_result = intersectLineTriangle (
2250 LINE,
2251 P, Q,
2252 *it,
2253 tmp_intersect_pt);
2254#ifdef ENABLE_DEBUG
2256 *gmsg << "* " << __func__ << ": "
2257 << " Test triangle: " << *it
2258 << " intersect: " << tmp_intersect_result
2259 << getPoint(*it,1)
2260 << getPoint(*it,2)
2261 << getPoint(*it,3)
2262 << endl;
2263 }
2264#endif
2265 switch (tmp_intersect_result) {
2266 case 0: // no intersection
2267 case 2: // both points are outside
2268 case 4: // both points are inside
2269 break;
2270 case 1: // line and triangle are in same plane
2271 case 3: // unique intersection in segment
2272 double t;
2273 if (cmp::eq_zero(Q[0] - P[0]) == false) {
2274 t = (tmp_intersect_pt[0] - P[0]) / (Q[0] - P[0]);
2275 } else if (cmp::eq_zero(Q[1] - P[1]) == false) {
2276 t = (tmp_intersect_pt[1] - P[1]) / (Q[1] - P[1]);
2277 } else {
2278 t = (tmp_intersect_pt[2] - P[2]) / (Q[2] - P[2]);
2279 }
2280 num_intersections++;
2281 if (t < tmin) {
2282#ifdef ENABLE_DEBUG
2284 *gmsg << "* " << __func__ << ": "
2285 << " set triangle"
2286 << endl;
2287 }
2288#endif
2289 tmin = t;
2290 intersect_pt = tmp_intersect_pt;
2291 triangle_id = (*it);
2292 }
2293 break;
2294 case -1: // triangle is degenerated
2295 PAssert (tmp_intersect_result != -1);
2296 exit (42); // terminate even if NDEBUG is set
2297 }
2298 } // end for all triangles
2299 return num_intersections;
2300}
2301
2302/*
2303 General purpose line segment boundary intersection test.
2304
2305 The method returns with a value > 0 if an intersection was found.
2306 */
2307int
2309 const Vector_t& P0, // [in] starting point of ray
2310 const Vector_t& P1, // [in] end point of ray
2311 Vector_t& intersect_pt, // [out] intersection with boundary
2312 int& triangle_id // [out] triangle the line segment intersects with
2313 ) {
2314#ifdef ENABLE_DEBUG
2315 int saved_flags = debugFlags_m;
2317 *gmsg << "* " << __func__ << ": "
2318 << " P0 = " << P0
2319 << " P1 = " << P1
2320 << endl;
2322 }
2323#endif
2324 triangle_id = -1;
2325
2326 const Vector_t v = P1 - P0;
2327 int intersect_result = 0;
2328 int n = 0;
2329 int i_min, j_min, k_min;
2330 int i_max, j_max, k_max;
2331 do {
2332 n++;
2333 Vector_t Q = P0 + v / n;
2334 Vector_t bbox_min = {
2335 std::min(P0[0], Q[0]),
2336 std::min(P0[1], Q[1]),
2337 std::min(P0[2], Q[2]) };
2338 Vector_t bbox_max = {
2339 std::max(P0[0], Q[0]),
2340 std::max(P0[1], Q[1]),
2341 std::max(P0[2], Q[2]) };
2342 mapPoint2VoxelIndices (bbox_min, i_min, j_min, k_min);
2343 mapPoint2VoxelIndices (bbox_max, i_max, j_max, k_max);
2344 } while (( (i_max-i_min+1) * (j_max-j_min+1) * (k_max-k_min+1)) > 27);
2345 Vector_t P = P0;
2346 Vector_t Q;
2347 const Vector_t v_ = v / n;
2348
2349 for (int l = 1; l <= n; l++, P = Q) {
2350 Q = P0 + l*v_;
2351 intersect_result = intersectTinyLineSegmentBoundary (
2352 P, Q, intersect_pt, triangle_id);
2353 if (triangle_id != -1) {
2354 break;
2355 }
2356 }
2357#ifdef ENABLE_DEBUG
2359 *gmsg << "* " << __func__ << ": "
2360 << " result=" << intersect_result
2361 << " intersection pt: " << intersect_pt
2362 << endl;
2363 debugFlags_m = saved_flags;
2364 }
2365#endif
2366 return intersect_result;
2367}
2368
2377int
2379 const Vector_t& r, // [in] particle position
2380 const Vector_t& v, // [in] momentum
2381 const double dt, // [in]
2382 Vector_t& intersect_pt, // [out] intersection with boundary
2383 int& triangle_id // [out] intersected triangle
2384 ) {
2385#ifdef ENABLE_DEBUG
2386 int saved_flags = debugFlags_m;
2388 *gmsg << "* " << __func__ << ": "
2389 << " r=" << r
2390 << " v=" << v
2391 << " dt=" << dt
2392 << endl;
2394 }
2395#endif
2396 int ret = -1; // result defaults to no collision
2397
2398 // nothing to do if momenta == 0
2399 if (v == (Vector_t)0)
2400 return ret;
2401
2403
2404 // P0, P1: particle position in time steps n and n+1
2405 const Vector_t P0 = r;
2406 const Vector_t P1 = r + (Physics::c * v * dt / std::sqrt (1.0 + dot(v,v)));
2407
2408 Vector_t tmp_intersect_pt = 0.0;
2409 int tmp_triangle_id = -1;
2410 intersectTinyLineSegmentBoundary (P0, P1, tmp_intersect_pt, tmp_triangle_id);
2411 if (tmp_triangle_id >= 0) {
2412 intersect_pt = tmp_intersect_pt;
2413 triangle_id = tmp_triangle_id;
2414 ret = 0;
2415 }
2416#ifdef ENABLE_DEBUG
2418 *gmsg << "* " << __func__ << ":"
2419 << " result=" << ret;
2420 if (ret == 0) {
2421 *gmsg << " intersetion=" << intersect_pt;
2422 }
2423 *gmsg << endl;
2424 debugFlags_m = saved_flags;
2425 }
2426#endif
2428 return ret;
2429}
2430
2431void
2433 std::ofstream of;
2434 of.open (fn.c_str ());
2435 PAssert (of.is_open ());
2436 of.precision (6);
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++)
2443 of << Points_m[i](0) << " "
2444 << Points_m[i](1) << " "
2445 << Points_m[i](2) << std::endl;
2446 of << std::endl;
2447
2448 of << "CELLS "
2449 << Triangles_m.size() << " "
2450 << 4 * Triangles_m.size() << std::endl;
2451 for (size_t i = 0; i < Triangles_m.size(); i++)
2452 of << "3 "
2453 << PointID (i, 1) << " "
2454 << PointID (i, 2) << " "
2455 << PointID (i, 3) << std::endl;
2456 of << "CELL_TYPES " << Triangles_m.size() << std::endl;
2457 for (size_t i = 0; i < Triangles_m.size(); i++)
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;
2462 for (size_t i = 0; i < Triangles_m.size(); i++)
2463 of << (float)(i) << std::endl;
2464 of << std::endl;
2465}
2466
2467Inform&
2469 os << endl;
2470 os << "* ************* B O U N D A R Y G E O M E T R Y *********************************** " << endl;
2471 os << "* GEOMETRY " << getOpalName () << '\n'
2472 << "* FGEOM '" << Attributes::getString (itsAttr[FGEOM]) << "'\n"
2473 << "* TOPO " << Attributes::getString (itsAttr[TOPO]) << '\n'
2474 << "* XSCALE " << Attributes::getReal (itsAttr[XSCALE]) << '\n'
2475 << "* YSCALE " << Attributes::getReal (itsAttr[YSCALE]) << '\n'
2476 << "* ZSCALE " << Attributes::getReal (itsAttr[ZSCALE]) << '\n'
2477 << "* XYZSCALE " << Attributes::getReal (itsAttr[XYZSCALE]) << '\n'
2478 << "* LENGTH " << Attributes::getReal (itsAttr[LENGTH]) << '\n'
2479 << "* S " << Attributes::getReal (itsAttr[S]) << '\n'
2480 << "* A " << Attributes::getReal (itsAttr[A]) << '\n'
2481 << "* B " << Attributes::getReal (itsAttr[B]) << '\n';
2482 if (getTopology () == Topology::BOXCORNER) {
2483 os << "* C " << Attributes::getReal (itsAttr[C]) << '\n'
2484 << "* L1 " << Attributes::getReal (itsAttr[L1]) << '\n'
2485 << "* L2 " << Attributes::getReal (itsAttr[L2]) << '\n';
2486 }
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'
2490 << "* Min = " << minExtent_m << '\n'
2491 << "* Geometry length(m) " << maxExtent_m - minExtent_m << '\n'
2492 << "* Resolution of voxel mesh " << voxelMesh_m.nr_m << '\n'
2493 << "* Size of voxel " << voxelMesh_m.sizeOfVoxel << '\n'
2494 << "* Number of voxels in mesh " << voxelMesh_m.ids.size () << endl;
2495 os << "* ********************************************************************************** " << endl;
2496 return os;
2497}
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
Definition Vector3D.cpp:111
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition Vector3D.cpp:118
const int nr
#define INSIDE
constexpr double EPS
#define PointID(triangle_id, vertex_id)
#define LERP(a, b, t)
#define FUNC_LE(x, y)
#define FUNC_GE(x, y)
#define FUNC_LT_ZERO(x)
#define FUNC_EQ(x, y)
#define OUTSIDE
#define FUNC_GT(x, y)
#define FUNC_EQ_ZERO(x)
#define SQR(x)
#define mapPoint2VoxelIndices(pt, i, j, k)
#define FUNC_LE_ZERO(x)
#define FUNC_GT_ZERO(x)
Inform * gmsg
Definition Main.cpp:69
#define FUNC_GE_ZERO(x)
#define FUNC_LT(x, y)
Inform * gmsg
Definition Main.cpp:69
@ SIZE
Definition IndexMap.cpp:178
#define PAssert(c)
Definition PAssert.h:102
Inform & level2(Inform &inf)
Definition Inform.cpp:46
Inform & endl(Inform &inf)
Definition Inform.cpp:42
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)
std::complex< double > a
const std::string name
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.
Definition Physics.h:45
bool enableVTK
If true VTK files are written.
Definition Options.cpp:81
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:204
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_zero(double x)
bool ge(double x, double y)
bool gt(double x, double y)
bool gt_zero(double x)
bool lt_zero(double x)
bool eq_zero(double x)
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.
Definition Definition.h:30
The base class for all OPAL objects.
Definition Object.h:48
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition Object.cpp:191
const std::string & getOpalName() const
Return object name.
Definition Object.cpp:310
void setOpalName(const std::string &name)
Set object name.
Definition Object.cpp:331
std::vector< Attribute > itsAttr
The object attributes.
Definition Object.h:216
bool builtin
Built-in flag.
Definition Object.h:233
Object * find(const std::string &name)
Find entry.
Definition OpalData.cpp:571
static OpalData * getInstance()
Definition OpalData.cpp:196
void define(Object *newObject)
Define a new object.
Definition OpalData.cpp:489
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:666
Abstract base class for accelerator geometry classes.
Definition Geometry.h:43
Vector_t pts[3]
double v1(int i) const
Triangle(const Vector_t &v1, const Vector_t &v2, const Vector_t &v3)
double v2(int i) const
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)
double v3(int i) const
Vector_t direction
Ray(const Ray &r)
const Ray & operator=(const Ray &a)=delete
Ray(Vector_t o, Vector_t d)
int sign[3]
Vector_t inv_direction
Vector_t origin
bool isInside(const Vector_t &P) const
Vector_t extent() const
bool intersect(const Ray &r, double &tmin, double &tmax) const
Voxel(const Vector_t &min, const Vector_t &max)
Vector_t pts[2]
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)
Vektor< int, 3 > nr_m
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::string h5FileName_m
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)
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
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.
void barrier(void)
static MPI_Comm getComm()
Definition IpplInfo.h:152
static int myNode()
Definition IpplInfo.cpp:691
static Communicate * Comm
Definition IpplInfo.h:84
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static void startTimer(TimerRef t)
Vektor< double, 3 > Vector_t
Definition Vektor.h:6