File indexing completed on 2026-11-13 11:00:07
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef VECGEOM_MANAGEMENT_TOUCHABLEPATH_H_
0010 #define VECGEOM_MANAGEMENT_TOUCHABLEPATH_H_
0011
0012 #include "VecGeom/base/Global.h"
0013 #include "VecGeom/base/Transformation3D.h"
0014 #include "VecGeom/volumes/PlacedVolume.h"
0015
0016 namespace vecgeom {
0017 inline namespace VECGEOM_IMPL_NAMESPACE {
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 enum class ReferenceNavValidationError : int {
0028 kNone = 0,
0029 kIncompatibleDaughter = 1,
0030 kIncompatibleScene = 2,
0031 kTopVolumeMismatch = 3,
0032 kChildIdMismatch = 4,
0033 kLogicalIdMismatch = 5,
0034 kLevelMismatch = 6,
0035 kPushPopMismatch = 7,
0036 kDaughterCountMismatch = 8,
0037 kTransformationMismatch = 9
0038 };
0039
0040
0041
0042
0043
0044
0045 inline char const *ToString(ReferenceNavValidationError error)
0046 {
0047 switch (error) {
0048 case ReferenceNavValidationError::kNone:
0049 return "success";
0050 case ReferenceNavValidationError::kIncompatibleDaughter:
0051 return "incompatible daughter pointer";
0052 case ReferenceNavValidationError::kIncompatibleScene:
0053 return "incompatible scene index";
0054 case ReferenceNavValidationError::kTopVolumeMismatch:
0055 return "top placed volume pointer mismatch";
0056 case ReferenceNavValidationError::kChildIdMismatch:
0057 return "top placed volume child id mismatch";
0058 case ReferenceNavValidationError::kLogicalIdMismatch:
0059 return "logical volume id mismatch";
0060 case ReferenceNavValidationError::kLevelMismatch:
0061 return "level mismatch";
0062 case ReferenceNavValidationError::kPushPopMismatch:
0063 return "navigation index inconsistency for Push/Pop";
0064 case ReferenceNavValidationError::kDaughterCountMismatch:
0065 return "number of daughters mismatch";
0066 case ReferenceNavValidationError::kTransformationMismatch:
0067 return "transformation matrix mismatch";
0068 }
0069 return "unknown validation error";
0070 }
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 class TouchablePath {
0093 private:
0094 static constexpr unsigned int kMaxPathEntries = 256;
0095
0096 VPlacedVolume const *fPath[kMaxPathEntries] = {};
0097 unsigned short fCurrentLevel = 0;
0098
0099 public:
0100
0101 VECCORE_ATT_HOST_DEVICE
0102 TouchablePath() = default;
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117 VECCORE_ATT_HOST_DEVICE
0118 static TouchablePath MakeWorld(VPlacedVolume const *world)
0119 {
0120 TouchablePath state;
0121 if (world) {
0122 state.fPath[0] = world;
0123 state.fCurrentLevel = 1;
0124 }
0125 return state;
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 VECCORE_ATT_HOST_DEVICE
0138 VECGEOM_FORCE_INLINE
0139 void Push(VPlacedVolume const *volume)
0140 {
0141 VECGEOM_VALIDATE(volume != nullptr, << "TouchablePath cannot push a null placed volume");
0142 VECGEOM_VALIDATE(fCurrentLevel < kMaxPathEntries, << "TouchablePath does not support geometry depths beyond 255");
0143 fPath[fCurrentLevel++] = volume;
0144 }
0145
0146
0147
0148
0149
0150
0151
0152 VECCORE_ATT_HOST_DEVICE
0153 VECGEOM_FORCE_INLINE
0154 void Pop()
0155 {
0156 VECGEOM_VALIDATE(fCurrentLevel > 0, << "TouchablePath cannot pop an empty path");
0157 fPath[--fCurrentLevel] = nullptr;
0158 }
0159
0160
0161 VECCORE_ATT_HOST_DEVICE
0162 VECGEOM_FORCE_INLINE
0163 VPlacedVolume const *Top() const { return (fCurrentLevel > 0) ? fPath[fCurrentLevel - 1] : nullptr; }
0164
0165
0166
0167
0168
0169
0170 VECCORE_ATT_HOST_DEVICE
0171 VECGEOM_FORCE_INLINE
0172 VPlacedVolume const *At(unsigned char level) const { return (level < fCurrentLevel) ? fPath[level] : nullptr; }
0173
0174
0175
0176
0177
0178 VECCORE_ATT_HOST_DEVICE
0179 VECGEOM_FORCE_INLINE
0180 unsigned char GetLevel() const { return (fCurrentLevel > 0) ? static_cast<unsigned char>(fCurrentLevel - 1) : 0; }
0181
0182
0183 VECCORE_ATT_HOST_DEVICE
0184 VECGEOM_FORCE_INLINE
0185 bool IsOutside() const { return fCurrentLevel == 0; }
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 VECCORE_ATT_HOST_DEVICE
0207 VECGEOM_FORCE_INLINE
0208 void TopMatrix(Transformation3D &matrix) const
0209 {
0210 matrix.Clear();
0211 for (int i = fCurrentLevel - 1; i > 0; --i)
0212 matrix *= *(fPath[i]->GetTransformation());
0213 }
0214
0215
0216 void Print() const
0217 {
0218 printf("TouchablePath: level=%u, path=<", unsigned(GetLevel()));
0219 for (unsigned int i = 0; i < fCurrentLevel; ++i)
0220 printf("/%s", fPath[i] ? fPath[i]->GetLabel().c_str() : "NULL");
0221 printf(">\n");
0222 }
0223 };
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235 template <typename EncodedNavState, typename EncodedState>
0236 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE ReferenceNavValidationError
0237 ValidateEncodedState(TouchablePath const &reference, EncodedState encoded_state)
0238 {
0239 if (reference.IsOutside()) return ReferenceNavValidationError::kNone;
0240
0241 if (EncodedNavState::TopImpl(encoded_state) != reference.Top())
0242 return ReferenceNavValidationError::kTopVolumeMismatch;
0243
0244 if (EncodedNavState::GetChildIdImpl(encoded_state) != reference.Top()->GetChildId())
0245 return ReferenceNavValidationError::kChildIdMismatch;
0246
0247 if (EncodedNavState::GetLogicalIdImpl(encoded_state) != reference.Top()->GetLogicalVolume()->id())
0248 return ReferenceNavValidationError::kLogicalIdMismatch;
0249
0250 if (EncodedNavState::GetLevelImpl(encoded_state) != reference.GetLevel())
0251 return ReferenceNavValidationError::kLevelMismatch;
0252
0253 auto roundtrip_state = encoded_state;
0254 if (reference.GetLevel() > 0) {
0255 EncodedNavState::PopImpl(roundtrip_state);
0256 EncodedNavState::PushImpl(roundtrip_state, reference.Top());
0257 if (roundtrip_state != encoded_state) return ReferenceNavValidationError::kPushPopMismatch;
0258 }
0259
0260 if (EncodedNavState::GetNdaughtersImpl(encoded_state) != reference.Top()->GetDaughters().size())
0261 return ReferenceNavValidationError::kDaughterCountMismatch;
0262
0263 Transformation3D reference_matrix;
0264 Transformation3D encoded_matrix;
0265 reference.TopMatrix(reference_matrix);
0266 EncodedNavState::TopMatrixImpl(encoded_state, encoded_matrix);
0267 if (!reference_matrix.ApproxEqual(encoded_matrix)) return ReferenceNavValidationError::kTransformationMismatch;
0268
0269 return ReferenceNavValidationError::kNone;
0270 }
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287 template <typename EncodedNavState, typename EncodedState>
0288 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE ReferenceNavValidationError
0289 ValidateSceneTransition(EncodedState parent_state, EncodedState child_state)
0290 {
0291 unsigned short parent_scene = 0, parent_new_scene = 0;
0292 bool inside_scene = EncodedNavState::GetSceneIdImpl(parent_state, parent_scene, parent_new_scene);
0293 unsigned short child_scene = 0, child_new_scene = 0;
0294 EncodedNavState::GetSceneIdImpl(child_state, child_scene, child_new_scene);
0295 if (inside_scene && child_scene == parent_scene) return ReferenceNavValidationError::kIncompatibleScene;
0296 return ReferenceNavValidationError::kNone;
0297 }
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313 template <typename EncodedNavState, typename EncodedState>
0314 void PrintValidationFailure(ReferenceNavValidationError error, TouchablePath const &reference,
0315 EncodedState encoded_state)
0316 {
0317 printf("=== EEE === Validation detail: error code %d\n", static_cast<int>(error));
0318 switch (error) {
0319 case ReferenceNavValidationError::kTopVolumeMismatch: {
0320 auto const expected_top_id = reference.Top() ? static_cast<long long>(reference.Top()->id()) : -1LL;
0321 printf(" expected top placed volume id %lld, got %d\n", expected_top_id,
0322 EncodedNavState::TopIdImpl(encoded_state));
0323 break;
0324 }
0325 case ReferenceNavValidationError::kChildIdMismatch:
0326 printf(" expected child id %d, got %d\n", reference.Top()->GetChildId(),
0327 EncodedNavState::GetChildIdImpl(encoded_state));
0328 break;
0329 case ReferenceNavValidationError::kLogicalIdMismatch:
0330 printf(" expected logical volume id %d, got %u\n", reference.Top()->GetLogicalVolume()->id(),
0331 EncodedNavState::GetLogicalIdImpl(encoded_state));
0332 break;
0333 case ReferenceNavValidationError::kLevelMismatch:
0334 printf(" expected level %u, got %u\n", unsigned(reference.GetLevel()),
0335 unsigned(EncodedNavState::GetLevelImpl(encoded_state)));
0336 break;
0337 case ReferenceNavValidationError::kPushPopMismatch: {
0338 auto roundtrip_state = encoded_state;
0339 EncodedNavState::PopImpl(roundtrip_state);
0340 EncodedNavState::PushImpl(roundtrip_state, reference.Top());
0341 auto const expected_top_id = reference.Top() ? static_cast<long long>(reference.Top()->id()) : -1LL;
0342 printf(" expected Pop/Push to reconstruct the same encoded state for top id %lld\n", expected_top_id);
0343 printf(" original top id %d, roundtrip top id %d\n", EncodedNavState::TopIdImpl(encoded_state),
0344 EncodedNavState::TopIdImpl(roundtrip_state));
0345 break;
0346 }
0347 case ReferenceNavValidationError::kDaughterCountMismatch:
0348 printf(" expected daughter count %zu, got %u\n", reference.Top()->GetDaughters().size(),
0349 EncodedNavState::GetNdaughtersImpl(encoded_state));
0350 break;
0351 case ReferenceNavValidationError::kTransformationMismatch: {
0352 Transformation3D reference_matrix;
0353 Transformation3D encoded_matrix;
0354 reference.TopMatrix(reference_matrix);
0355 EncodedNavState::TopMatrixImpl(encoded_state, encoded_matrix);
0356 printf(" expected translation (%.8g, %.8g, %.8g), got (%.8g, %.8g, %.8g)\n", reference_matrix.Translation(0),
0357 reference_matrix.Translation(1), reference_matrix.Translation(2), encoded_matrix.Translation(0),
0358 encoded_matrix.Translation(1), encoded_matrix.Translation(2));
0359 break;
0360 }
0361 default:
0362 break;
0363 }
0364 }
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377 template <typename EncodedNavState, typename EncodedState>
0378 void PrintSceneTransitionFailure(EncodedState parent_state, EncodedState child_state,
0379 VPlacedVolume const *parent_volume, VPlacedVolume const *child_volume)
0380 {
0381 unsigned short parent_scene = 0, parent_new_scene = 0;
0382 unsigned short child_scene = 0, child_new_scene = 0;
0383 EncodedNavState::GetSceneIdImpl(parent_state, parent_scene, parent_new_scene);
0384 EncodedNavState::GetSceneIdImpl(child_state, child_scene, child_new_scene);
0385 auto const parent_id = parent_volume ? static_cast<long long>(parent_volume->id()) : -1LL;
0386 auto const child_id = child_volume ? static_cast<long long>(child_volume->id()) : -1LL;
0387 printf("=== EEE === Validation detail: error code %d\n",
0388 static_cast<int>(ReferenceNavValidationError::kIncompatibleScene));
0389 printf(" expected child scene different from parent scene %u, got %u for %lld/%lld\n", parent_scene, child_scene,
0390 parent_id, child_id);
0391 }
0392
0393 }
0394 }
0395
0396 #endif