Project
Loading...
Searching...
No Matches
O2SolidHarness.h
Go to the documentation of this file.
1// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
13
16
17#ifndef ALICEO2_CADSUPPORT_O2SOLIDHARNESS_
18#define ALICEO2_CADSUPPORT_O2SOLIDHARNESS_
19
20#include "TGeoShape.h"
21
22class TGeoMatrix;
23class TGeoHMatrix;
24
25#include <array>
26#include <chrono>
27#include <cstdint>
28#include <string>
29#include <vector>
30
31namespace o2
32{
33namespace cad
34{
35namespace harness
36{
37
38using Point3D = std::array<double, 3>;
39
40struct Ray {
42 Point3D dir{}; // unit vector by convention (TGeo contract); not renormalized by the harness
43};
44
47 int nBulk = 2000;
48 int nBoundary = 2000;
49 int nInside = 1000;
50 int nOutsideRays = 4000;
51 int nInsideRays = 2000;
52 double bboxInflate = 0.15;
53 double boundaryBand = -1.;
54 double aimedRayFraction = 0.5;
58 uint64_t seed = 1;
59};
60
61struct SampleSet {
64 std::vector<Point3D> bulkPoints;
65 std::vector<Point3D> boundaryPoints;
66 std::vector<Point3D> insidePoints;
67 std::vector<Ray> outsideRays;
68 std::vector<Ray> insideRays;
69};
70
72SampleSet generateSamples(const TGeoShape* reference, const Point3D& bboxMin, const Point3D& bboxMax,
73 const SampleConfig& cfg = {});
74
75// ---- Validation ----------------------------------------------------------------------------------
76
79struct Offender {
81 Point3D dir{}; // zero for point-only queries (Contains, Safety)
82 double candidateValue = 0.;
83 double referenceValue = 0.;
84 double deviation = 0.;
85 double referenceSafety = 0.; // point queries: reference distance to its own surface
86 double incidenceCosine = 1.; // ray queries: |cos| between ray and surface normal at the hit,
87 // i.e. how much surface uncertainty this ray amplifies
88};
89
91 size_t nSamples = 0;
92 size_t nAgree = 0;
93 size_t nMismatchWithinBand = 0; // explainable by the reference's own imprecision (see below)
94 size_t nMismatchMissedSurface = 0; // one side found no crossing where the other did
96 size_t nNoVerdict = 0; // oracle mode only: the reference declined to answer
97 size_t nRelabelled = 0; // ray queries, oracle mode: origins whose category the oracle
98 // contradicted, so the other TGeo entry point was asked
99 double worstDeviation = 0.;
100 std::vector<Offender> worstOffenders; // bounded by opt.maxOffenders, worst-first
101};
102
106 double distanceTolerance = 1.e-6;
107 double meshBand = 1.e-2;
109 double minIncidenceCosine = 1.e-2;
110 double stepmax = TGeoShape::Big();
111 size_t maxOffenders = 10;
112};
113
114ValidationResult validateContains(const TGeoShape* candidate, const TGeoShape* reference,
115 const std::vector<Point3D>& points, const ValidationOptions& opt = {});
116
117ValidationResult validateDistFromOutside(const TGeoShape* candidate, const TGeoShape* reference,
118 const std::vector<Ray>& rays, const ValidationOptions& opt = {});
119
120ValidationResult validateDistFromInside(const TGeoShape* candidate, const TGeoShape* reference,
121 const std::vector<Ray>& rays, const ValidationOptions& opt = {});
122
124ValidationResult validateSafety(const TGeoShape* shape, const std::vector<Point3D>& points,
125 const ValidationOptions& opt = {});
126
127// ---- Validation against the OpenCascade oracle: a disagreement beyond the model tolerance is a defect ----
128
130ValidationResult validateContainsAgainstOracle(const TGeoShape* candidate,
131 const std::vector<Point3D>& points,
132 const std::vector<int>& oracleState,
133 const std::vector<double>& oracleBoundaryDistance,
134 const ValidationOptions& opt = {});
135
138ValidationResult validateDistanceAgainstOracle(const TGeoShape* candidate,
139 const std::vector<Ray>& rays,
140 const std::vector<double>& oracleDistance,
141 bool wantInside, const ValidationOptions& opt = {},
142 const std::vector<int>& oracleOriginState = {});
143
145ValidationResult validateSafetyAgainstOracle(const TGeoShape* candidate,
146 const std::vector<Point3D>& points,
147 const std::vector<double>& oracleBoundaryDistance,
148 const ValidationOptions& opt = {});
149
150// ---- Timing --------------------------------------------------------------------------------------
151
153 size_t nCalls = 0;
154 double nsPerCall = 0.;
155 uint64_t checksum = 0;
156};
157
158namespace detail
159{
162uint64_t mixDouble(uint64_t acc, double value);
163} // namespace detail
164
166template <typename RayKernel>
167TimingResult timeRayKernel(const std::vector<Ray>& rays, int warmupRepeats, int timedRepeats, RayKernel&& kernel)
168{
169 for (int warmup = 0; warmup < warmupRepeats; ++warmup) {
170 for (const auto& ray : rays) {
171 volatile double sink = kernel(ray.origin, ray.dir);
172 (void)sink;
173 }
174 }
175 uint64_t checksum = 0;
176 const auto start = std::chrono::steady_clock::now();
177 for (int repeat = 0; repeat < timedRepeats; ++repeat) {
178 for (const auto& ray : rays) {
179 checksum = detail::mixDouble(checksum, kernel(ray.origin, ray.dir));
180 }
181 }
182 const auto stop = std::chrono::steady_clock::now();
184 result.nCalls = rays.size() * static_cast<size_t>(timedRepeats);
185 const double nanoseconds = std::chrono::duration<double, std::nano>(stop - start).count();
186 result.nsPerCall = result.nCalls > 0 ? nanoseconds / static_cast<double>(result.nCalls) : 0.;
187 result.checksum = checksum;
188 return result;
189}
190
191TimingResult timeContains(const TGeoShape* shape, const std::vector<Point3D>& points, int warmupRepeats,
192 int timedRepeats);
193TimingResult timeDistFromOutside(const TGeoShape* shape, const std::vector<Ray>& rays, int warmupRepeats,
194 int timedRepeats, double stepmax = TGeoShape::Big());
195TimingResult timeDistFromInside(const TGeoShape* shape, const std::vector<Ray>& rays, int warmupRepeats,
196 int timedRepeats);
197TimingResult timeSafety(const TGeoShape* shape, const std::vector<Point3D>& points, int warmupRepeats,
198 int timedRepeats);
199
200// ---- The `shape_<part>.root` sidecar -------------------------------------------------------------
201//
202// * one file per part, `shape_<VOL>_<LID>.root`, next to the part's other sidecars;
203// * one TGeoShape-derived object under the key "shape" (the first such key is the fallback);
204// * lengths in centimetres;
205// * an optional TGeoHMatrix under "placement" takes the shape's frame to the part's (`local -> part`);
206// no key means the identity;
207// * a TGeoCompositeShape is written whole and needs no TGeoManager.
208
210TGeoShape* loadShapeFromRootFile(const std::string& path, std::string* error = nullptr);
211
213TGeoHMatrix* loadShapePlacementFromRootFile(const std::string& path);
214
216bool saveShapeToRootFile(const std::string& path, const TGeoShape& shape, std::string* error = nullptr);
217bool saveShapeToRootFile(const std::string& path, const TGeoShape& shape,
218 const TGeoMatrix* placement, std::string* error);
219
220} // namespace harness
221} // namespace cad
222} // namespace o2
223
224#endif
GLuint64EXT * result
Definition glcorearb.h:5662
GLsizei const GLfloat * value
Definition glcorearb.h:819
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLuint start
Definition glcorearb.h:469
uint64_t mixDouble(uint64_t acc, double value)
bool saveShapeToRootFile(const std::string &path, const TGeoShape &shape, std::string *error=nullptr)
Write a shape sidecar, with placement under "placement" unless it is null or the identity.
ValidationResult validateContainsAgainstOracle(const TGeoShape *candidate, const std::vector< Point3D > &points, const std::vector< int > &oracleState, const std::vector< double > &oracleBoundaryDistance, const ValidationOptions &opt={})
oracleState: 1 inside, 0 outside, -1 declined; oracleBoundaryDistance may cover only a prefix of poin...
SampleSet generateSamples(const TGeoShape *reference, const Point3D &bboxMin, const Point3D &bboxMax, const SampleConfig &cfg={})
A deterministic sample set from cfg.seed and the bbox; reference, the trusted mesh,...
ValidationResult validateSafetyAgainstOracle(const TGeoShape *candidate, const std::vector< Point3D > &points, const std::vector< double > &oracleBoundaryDistance, const ValidationOptions &opt={})
Safety's contract against the oracle's exact distance: 0 <= safety <= trueDistance.
TimingResult timeDistFromInside(const TGeoShape *shape, const std::vector< Ray > &rays, int warmupRepeats, int timedRepeats)
TimingResult timeDistFromOutside(const TGeoShape *shape, const std::vector< Ray > &rays, int warmupRepeats, int timedRepeats, double stepmax=TGeoShape::Big())
ValidationResult validateSafety(const TGeoShape *shape, const std::vector< Point3D > &points, const ValidationOptions &opt={})
Check one shape's Safety() lower-bound contract against its own DistFrom* along six probe directions;...
ValidationResult validateDistFromInside(const TGeoShape *candidate, const TGeoShape *reference, const std::vector< Ray > &rays, const ValidationOptions &opt={})
ValidationResult validateDistanceAgainstOracle(const TGeoShape *candidate, const std::vector< Ray > &rays, const std::vector< double > &oracleDistance, bool wantInside, const ValidationOptions &opt={}, const std::vector< int > &oracleOriginState={})
TimingResult timeContains(const TGeoShape *shape, const std::vector< Point3D > &points, int warmupRepeats, int timedRepeats)
TGeoHMatrix * loadShapePlacementFromRootFile(const std::string &path)
Read the shape's placement, or nullptr when there is none, meaning the identity. The caller owns it.
TGeoShape * loadShapeFromRootFile(const std::string &path, std::string *error=nullptr)
Read the single TGeoShape of a shape_<part>.root sidecar; nullptr on failure, with the reason in *err...
ValidationResult validateContains(const TGeoShape *candidate, const TGeoShape *reference, const std::vector< Point3D > &points, const ValidationOptions &opt={})
TimingResult timeRayKernel(const std::vector< Ray > &rays, int warmupRepeats, int timedRepeats, RayKernel &&kernel)
Time a per-ray kernel kernel(origin, dir) exactly like the timeDistFrom* functions,...
ValidationResult validateDistFromOutside(const TGeoShape *candidate, const TGeoShape *reference, const std::vector< Ray > &rays, const ValidationOptions &opt={})
TimingResult timeSafety(const TGeoShape *shape, const std::vector< Point3D > &points, int warmupRepeats, int timedRepeats)
std::array< double, 3 > Point3D
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Parameters of generateSamples; the counts are targets, and a category may come back short.
int nInsideRays
rays from inside origins, for DistFromInside
int nOutsideRays
rays from outside origins, for DistFromOutside
int nBulk
uniform points over the inflated bbox
double boundaryBand
absolute distance (cm); <0 auto-picks 1e-3 * bbox diagonal
int nBoundary
points within boundaryBand of the reference surface
int maxRejectionAttempts
attempts per accepted sample before giving up on that category
uint64_t seed
every SampleSet is fully determined by this and the bbox
int nInside
points accepted by the reference Contains()
double bboxInflate
fractional bbox half-extent padding for bulk/outside sampling
std::vector< Point3D > boundaryPoints
std::vector< Point3D > bulkPoints
std::vector< Ray > outsideRays
std::vector< Ray > insideRays
std::vector< Point3D > insidePoints
uint64_t checksum
accumulated from the results so the optimizer cannot elide the calls
double minIncidenceCosine
Floor of the incidence cosine that scales the distance allowance, so a tangent ray cannot excuse an u...
double distanceTolerance
absolute agreement tolerance for distances (cm)
std::vector< Offender > worstOffenders