27#ifndef ALICEO2_BASE_XRAYTRANSPORT_H_
28#define ALICEO2_BASE_XRAYTRANSPORT_H_
128template <
typename ContainsFn,
typename DistOutFn,
typename DistInFn>
132 DistOutFn distFromOutside, DistInFn distFromInside)
134 std::vector<Crossing> crossings;
136 bool inside = contains(point);
138 ++stats.originInside;
142 for (; iter < cfg.
maxIter; ++iter) {
143 const double step = inside ? distFromInside(point, dir.data()) : distFromOutside(point, dir.data());
145 if (!(step < TGeoShape::Big())) {
148 const double tCross = t + step;
153 ++stats.zeroLengthSteps;
155 crossings.push_back({tCross, inside ? -1 : +1});
157 double advance = step + cfg.
push;
158 if (!(advance > 0.)) {
159 ++stats.nonAdvancingSteps;
161 ++stats.unstickPushes;
164 ++stats.unstickPushes;
170 for (
int k = 0; k < 3; ++k) {
171 point[k] =
origin[k] + t * dir[k];
175 ++stats.iterationCapHits;
178 ++stats.unterminated;
185 const Point3D& dir,
double tMax,
189 origin, dir, tMax, cfg, stats, [shape](
const double* p) {
return shape->Contains(p); },
190 [shape](
const double* p,
const double* d) {
191 return shape->DistFromOutside(p, d, 3, TGeoShape::Big(),
nullptr);
193 [shape](
const double* p,
const double* d) {
194 return shape->DistFromInside(p, d, 3, TGeoShape::Big(),
nullptr);
202 const Point3D&
origin,
const Point3D& dir,
double tMax,
206 stats.crossings +=
static_cast<long long>(crossings.size());
207 if (!crossings.empty()) {
208 ++stats.raysWithCrossings;
210 if (crossings.size() % 2 != 0) {
211 ++stats.oddCrossingLists;
213 for (
size_t i = 1;
i < crossings.size(); ++
i) {
214 if (crossings[
i].
kind == crossings[
i - 1].
kind) {
215 ++stats.nonAlternating;
218 ++stats.duplicateCrossings;
222 for (
size_t i = 0;
i + 1 < crossings.size();
i += 2) {
223 if (crossings[
i].
kind == +1 && crossings[
i + 1].
kind == -1) {
224 stats.insideLength += crossings[
i + 1].t - crossings[
i].t;
230 if (shape !=
nullptr) {
231 std::vector<double>
edges;
233 for (
const auto&
c : crossings) {
236 edges.push_back(tMax);
237 bool expectInside =
false;
238 for (
size_t i = 0;
i + 1 <
edges.size(); ++
i) {
242 for (
int k = 0; k < 3; ++k) {
243 p[k] =
origin[k] + mid * dir[k];
245 const bool actuallyInside = shape->Contains(p);
246 if (actuallyInside != expectInside) {
256 if (shape->Safety(p, actuallyInside ? kTRUE : kFALSE) <= cfg.
matchTolerance) {
257 ++stats.parityMismatchNearBoundary;
259 ++stats.parityMismatchIntervals;
263 expectInside = !expectInside;
293 bool sameShape = candidate.size() ==
reference.size();
294 for (
size_t i = 0; sameShape &&
i < candidate.size(); ++
i) {
295 sameShape = candidate[
i].kind ==
reference[
i].kind;
301 bool identical =
true;
302 for (
size_t i = 0;
i < candidate.size(); ++
i) {
303 const double delta = std::fabs(candidate[
i].t -
reference[
i].t);
305 if (delta > tolerance) {
313 out.
worstReason = delta > tolerance ?
"displaced crossing" :
"deltaT";
325 while (
i < candidate.size() &&
j <
reference.size()) {
326 const double delta = candidate[
i].t -
reference[
j].t;
327 if (std::fabs(delta) <= tolerance) {
337 }
else if (delta < 0.) {
345 out.
extra +=
static_cast<long long>(candidate.size() -
i);
388inline double dot3(
const Point3D&
a,
const Point3D&
b)
390 return a[0] *
b[0] +
a[1] *
b[1] +
a[2] *
b[2];
395 const double norm = std::sqrt(
dot3(
a,
a));
396 return {
a[0] / norm,
a[1] / norm,
a[2] / norm};
399inline Point3D
cross3(
const Point3D&
a,
const Point3D&
b)
401 return {
a[1] *
b[2] -
a[2] *
b[1],
a[2] *
b[0] -
a[0] *
b[2],
a[0] *
b[1] -
a[1] *
b[0]};
421 std::vector<Beam> beams;
422 const double golden = 3.14159265358979323846 * (3. - std::sqrt(5.));
425 const double z = (
count == 1) ? 1. : 1. -
static_cast<double>(
i) /
static_cast<double>(
count);
426 const double radius = std::sqrt(std::max(0., 1. -
z *
z));
427 const double theta = golden *
i;
429 beam.
dir =
normalize3({radius * std::cos(theta), radius * std::sin(theta),
z});
432 for (
int k = 1; k < 3; ++k) {
433 if (std::fabs(beam.
dir[k]) < std::fabs(beam.
dir[least])) {
439 const double projection =
dot3(seed, beam.
dir);
440 beam.
u =
normalize3({seed[0] - projection * beam.
dir[0], seed[1] - projection * beam.
dir[1],
441 seed[2] - projection * beam.
dir[2]});
444 beams.push_back(std::move(beam));
449inline std::vector<Beam>
buildBeams(
const std::string& axesSpec,
double tiltDegrees)
451 std::vector<Beam> beams;
452 const double t = std::tan(tiltDegrees * 3.14159265358979323846 / 180.);
453 for (
const char c : axesSpec) {
455 if (
c ==
'x' ||
c ==
'X') {
457 }
else if (
c ==
'y' ||
c ==
'Y') {
459 }
else if (
c ==
'z' ||
c ==
'Z') {
464 const int iu = (axis + 1) % 3;
465 const int iv = (axis + 2) % 3;
477 beam.
label = std::string(1,
"xyz"[axis]);
479 Point3D dir{
w[0] + t * u[0] + 0.618 * t *
v[0],
w[1] + t * u[1] + 0.618 * t *
v[1],
480 w[2] + t * u[2] + 0.618 * t *
v[2]};
487 beam.
label = std::string(1,
"xyz"[axis]) +
"+t";
489 beams.push_back(std::move(beam));
504 const std::vector<Beam>& beams,
double transverseMargin)
508 raster.
beams = beams;
510 for (
int k = 0; k < 3; ++k) {
511 raster.
windowMin[k] = bboxMin[k] - transverseMargin;
512 raster.
windowMax[k] = bboxMax[k] + transverseMargin;
514 for (
const auto& beam : beams) {
516 double lo[3] = {1.e300, 1.e300, 1.e300};
517 double hi[3] = {-1.e300, -1.e300, -1.e300};
518 for (
int corner = 0; corner < 8; ++corner) {
519 const Point3D p{(corner & 1) ? bboxMax[0] : bboxMin[0], (corner & 2) ? bboxMax[1] : bboxMin[1],
520 (corner & 4) ? bboxMax[2] : bboxMin[2]};
521 const double coordinate[3] = {
dot3(p, beam.u),
dot3(p, beam.v),
dot3(p, beam.dir)};
522 for (
int k = 0; k < 3; ++k) {
523 lo[k] = std::min(lo[k], coordinate[k]);
524 hi[k] = std::max(hi[k], coordinate[k]);
527 const double uLo = lo[0] - transverseMargin;
528 const double vLo = lo[1] - transverseMargin;
529 const double du = (hi[0] - lo[0] + 2. * transverseMargin) /
n;
530 const double dv = (hi[1] - lo[1] + 2. * transverseMargin) /
n;
532 const double bboxArea = (hi[0] - lo[0]) * (hi[1] - lo[1]);
533 raster.
windowExcess.push_back(bboxArea > 0. ? (du * dv *
n *
n) / bboxArea - 1. : 0.);
534 const double extent = hi[2] - lo[2];
535 const double lead = 0.05 * extent + 1.e-3;
536 const double wStart = lo[2] - lead;
537 const int index =
static_cast<int>(raster.
cellArea.size()) - 1;
538 for (
int i = 0;
i <
n; ++
i) {
539 for (
int j = 0;
j <
n; ++
j) {
540 const double uu = uLo + (
i + 0.5) * du;
541 const double vv = vLo + (
j + 0.5) * dv;
544 for (
int k = 0; k < 3; ++k) {
545 ray.origin[k] = uu * beam.u[k] + vv * beam.v[k] + wStart * beam.dir[k];
546 ray.dir[k] = beam.dir[k];
548 ray.tMax = extent + 2. * lead;
549 raster.
rays.push_back(ray);
562 for (
size_t i = 0;
i < raster.
beams.size() &&
i < insideLengthPerBeam.size(); ++
i) {
566 return used > 0 ?
sum /
static_cast<double>(used) : 0.;
header::DataOrigin origin
Validation and timing harness for TGeoShape navigation, typed on plain TGeoShape*.
std::vector< SidecarEdge > edges
float sum(float s, o2::dcs::DataPointValue v)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLdouble GLdouble GLdouble z
std::array< double, 3 > Point3D
std::vector< Crossing > stepWithShapeApi(const TGeoShape *shape, const Point3D &origin, const Point3D &dir, double tMax, const StepConfig &cfg, Robustness &stats)
Mode (a): the same loop driven by the ordinary TGeoShape virtuals.
void compareLists(const std::vector< Crossing > &candidate, const std::vector< Crossing > &reference, const Point3D &origin, const Point3D &dir, double tolerance, ListComparison &out)
double chordVolume(const Raster &raster, const std::vector< double > &insideLengthPerBeam)
std::vector< Crossing > stepCrossingsWithKernels(const Point3D &origin, const Point3D &dir, double tMax, const StepConfig &cfg, Robustness &stats, ContainsFn contains, DistOutFn distFromOutside, DistInFn distFromInside)
void auditCrossingList(const std::vector< Crossing > &crossings, const TGeoShape *shape, const Point3D &origin, const Point3D &dir, double tMax, const StepConfig &cfg, Robustness &stats)
double dot3(const Point3D &a, const Point3D &b)
Point3D cross3(const Point3D &a, const Point3D &b)
std::vector< Beam > buildFanBeams(int count)
Raster buildRaster(const Point3D &bboxMin, const Point3D &bboxMax, int n, const std::vector< Beam > &beams, double transverseMargin)
std::vector< Beam > buildBeams(const std::string &axesSpec, double tiltDegrees)
Point3D normalize3(const Point3D &a)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
long long displaced
same position in both lists, more than tolerance apart
long long raysStructural
the lists have different lengths or senses
long long raysIdentical
the whole ordered list matched, position and sense
double worstDeltaT
max |dt| over positionally matched crossings, cm
long long missing
in the reference, absent from the candidate
long long extra
in the candidate, absent from the reference
Point3D windowMin
the part bbox plus the margin, in world coordinates (the world box)
std::vector< RayDef > rays
std::vector< double > windowExcess
std::vector< Beam > beams
std::vector< double > cellArea
int beam
index into Raster::beams
long long raysWithCrossings
long long zeroLengthSteps
a step at or below zeroStep (default 1e-9 cm)
long long unterminated
the ray ended INSIDE the solid: entered and never left
long long duplicateCrossings
long long originOutsideWorld
long long iterationCapHits
the loop hit maxIter without leaving the window
long long unstickPushes
a stalled step that had to be nudged to continue
long long parityMismatchNearBoundary
long long oddCrossingLists
long long originInside
a raster ray whose origin was not outside the solid
long long parityMismatchIntervals
double insideLength
summed inside-segment length, cm (the chord integral)
long long nonAlternating
two consecutive crossings of the same kind
long long nonAdvancingSteps
the accumulated distance did not increase
long long boundaryWithoutTransition
double zeroStep
A step at or below this is a stall, not progress.