File indexing completed on 2026-09-26 09:15:36
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef ABBOX_MANAGER_H
0009 #define ABBOX_MANAGER_H
0010
0011 #pragma once
0012
0013 #include "VecGeom/base/Global.h"
0014
0015 #include "VecGeom/volumes/PlacedVolume.h"
0016 #include "VecGeom/volumes/UnplacedBox.h"
0017 #include "VecGeom/base/Vector3D.h"
0018 #include "VecGeom/management/GeoManager.h"
0019 #include "VecGeom/navigation/NavigationState.h"
0020 #include "VecGeom/base/Transformation3D.h"
0021 #include "VecGeom/volumes/kernel/BoxImplementation.h"
0022
0023 #ifdef VECGEOM_USE_SURF
0024 #include "VecGeom/surfaces/SurfData.h" // still need this for the init bvh function, then we can cut this
0025 #include "VecGeom/surfaces/base/CpuTypes.h"
0026 #endif
0027
0028 #include <map>
0029 #include <vector>
0030
0031 namespace vecgeom {
0032
0033
0034
0035
0036 template <typename Real_b>
0037 class ABBoxManager {
0038 public:
0039 typedef float Real_s;
0040 using Float_v = vecgeom::VectorBackend::Float_v;
0041
0042 typedef Vector3D<Float_v> ABBox_v;
0043
0044 typedef Vector3D<Real_b> ABBox_s;
0045
0046
0047
0048 typedef ABBox_s *ABBoxContainer_t;
0049 typedef ABBox_v *ABBoxContainer_v;
0050
0051 typedef std::pair<unsigned int, double> BoxIdDistancePair_t;
0052
0053
0054 template <typename C, typename Compare>
0055 static void sort(C &v, Compare cmp)
0056 {
0057 std::sort(v.begin(), v.end(), cmp);
0058 }
0059
0060 struct HitBoxComparatorFunctor {
0061 bool operator()(BoxIdDistancePair_t const &left, BoxIdDistancePair_t const &right)
0062 {
0063 return left.second < right.second;
0064 }
0065 };
0066
0067 using FP_t = HitBoxComparatorFunctor;
0068
0069 std::vector<ABBoxContainer_t> fVolToSurfaceABBoxesMap;
0070
0071 private:
0072 std::vector<ABBoxContainer_t> fVolToABBoxesMap;
0073 std::vector<ABBoxContainer_v> fVolToABBoxesMap_v;
0074
0075 public:
0076
0077 static void ComputeABBox(VPlacedVolume const *pvol, ABBox_s *lowerc, ABBox_s *upperc)
0078 {
0079
0080
0081
0082 Vector3D<Precision> lower, upper;
0083 pvol->GetUnplacedVolume()->Extent(lower, upper);
0084
0085 auto transformation = pvol->GetTransformation();
0086 TransformBoundingBox<Transformation3D>(lower, upper, *transformation);
0087 *lowerc = Vector3D<Precision>(lower.x() - 1E-3, lower.y() - 1E-3, lower.z() - 1E-3);
0088 *upperc = Vector3D<Precision>(upper.x() + 1E-3, upper.y() + 1E-3, upper.z() + 1E-3);
0089 }
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 static void ComputeSplittedABBox(VPlacedVolume const *pvol, std::vector<ABBox_s> &lowerc,
0107 std::vector<ABBox_s> &upperc, int numOfSlices)
0108 {
0109
0110
0111
0112
0113
0114
0115
0116 Vector3D<Precision> tmpLower, tmpUpper;
0117 pvol->GetUnplacedVolume()->Extent(tmpLower, tmpUpper);
0118 Vector3D<Precision> delta = tmpUpper - tmpLower;
0119
0120 int dim = 0;
0121 if (delta.y() > delta.x() && delta.y() > delta.z())
0122 dim = 1;
0123 if (delta.z() > delta.x() && delta.z() > delta.y())
0124 dim = 2;
0125
0126 Precision splitDx = 0., splitDy = 0., splitDz = 0.;
0127 splitDx = delta.x();
0128 splitDy = delta.y();
0129 splitDz = delta.z();
0130
0131
0132 Precision val = 0.;
0133
0134 if (dim == 0) {
0135 splitDx = delta.x() / numOfSlices;
0136 val = -delta.x() / 2 + splitDx / 2;
0137 }
0138 if (dim == 1) {
0139 splitDy = delta.y() / numOfSlices;
0140 val = -delta.y() / 2 + splitDy / 2;
0141 }
0142 if (dim == 2) {
0143 splitDz = delta.z() / numOfSlices;
0144 val = -delta.z() / 2 + splitDz / 2;
0145 }
0146
0147
0148 Transformation3D const *transf = pvol->GetTransformation();
0149
0150
0151 for (int i = 0; i < numOfSlices; i++) {
0152
0153
0154
0155
0156 Transformation3D transf2;
0157 Vector3D<Precision> transVec(0., 0., 0.);
0158 if (dim == 0) {
0159 transVec = transf->InverseTransform(Vector3D<Precision>(val, 0., 0.));
0160 val += splitDx;
0161 }
0162 if (dim == 1) {
0163 transVec = transf->InverseTransform(Vector3D<Precision>(0., val, 0.));
0164 val += splitDy;
0165 }
0166 if (dim == 2) {
0167 transVec = transf->InverseTransform(Vector3D<Precision>(0., 0., val));
0168 val += splitDz;
0169 }
0170
0171 transf2.SetTranslation(transVec);
0172 transf2.SetRotation(transf->Rotation()[0], transf->Rotation()[1], transf->Rotation()[2], transf->Rotation()[3],
0173 transf->Rotation()[4], transf->Rotation()[5], transf->Rotation()[6], transf->Rotation()[7],
0174 transf->Rotation()[8]);
0175 transf2.SetProperties();
0176
0177 Vector3D<Precision> lower1(0., 0., 0.), upper1(0., 0., 0.);
0178 UnplacedBox newBox2(splitDx / 2., splitDy / 2., splitDz / 2.);
0179 VPlacedVolume const *newBoxPlaced2 = LogicalVolume("", &newBox2).Place(&transf2);
0180 ABBoxManager<Precision>::Instance().ComputeABBox(newBoxPlaced2, &lower1, &upper1);
0181 lowerc.push_back(lower1);
0182 upperc.push_back(upper1);
0183 }
0184 }
0185
0186 template <typename Transformation>
0187 static void TransformBoundingBox(Vector3D<Precision> &lower, Vector3D<Precision> &upper, Transformation const &transf)
0188 {
0189 auto delta = upper - lower;
0190 Precision minx, miny, minz, maxx, maxy, maxz;
0191 minx = kInfLength;
0192 miny = kInfLength;
0193 minz = kInfLength;
0194 maxx = -kInfLength;
0195 maxy = -kInfLength;
0196 maxz = -kInfLength;
0197 for (int x = 0; x <= 1; ++x)
0198 for (int y = 0; y <= 1; ++y)
0199 for (int z = 0; z <= 1; ++z) {
0200 Vector3D<Precision> corner;
0201 corner.x() = lower.x() + x * delta.x();
0202 corner.y() = lower.y() + y * delta.y();
0203 corner.z() = lower.z() + z * delta.z();
0204 Vector3D<Precision> transformedcorner = transf.InverseTransform(corner);
0205 minx = std::min(minx, transformedcorner.x());
0206 miny = std::min(miny, transformedcorner.y());
0207 minz = std::min(minz, transformedcorner.z());
0208 maxx = std::max(maxx, transformedcorner.x());
0209 maxy = std::max(maxy, transformedcorner.y());
0210 maxz = std::max(maxz, transformedcorner.z());
0211 }
0212 lower.Set(minx, miny, minz);
0213 upper.Set(maxx, maxy, maxz);
0214 }
0215
0216 static ABBoxManager<Real_b> &Instance()
0217 {
0218 static ABBoxManager<Real_b> instance;
0219 return instance;
0220 }
0221
0222
0223
0224
0225 void InitABBoxes(LogicalVolume const *lvol)
0226 {
0227 if (fVolToABBoxesMap[lvol->id()] != nullptr) {
0228
0229 RemoveABBoxes(lvol);
0230 }
0231 uint ndaughters = lvol->GetDaughtersp()->size();
0232 ABBox_s *boxes = new ABBox_s[2 * ndaughters];
0233 fVolToABBoxesMap[lvol->id()] = boxes;
0234
0235
0236 int extra = (ndaughters % vecCore::VectorSize<Float_v>() > 0) ? 1 : 0;
0237 int size = 2 * (ndaughters / vecCore::VectorSize<Float_v>() + extra);
0238 ABBox_v *vectorboxes = new ABBox_v[size];
0239 fVolToABBoxesMap_v[lvol->id()] = vectorboxes;
0240
0241
0242 for (uint d = 0; d < ndaughters; ++d) {
0243 auto pvol = lvol->GetDaughtersp()->operator[](d);
0244 ComputeABBox(pvol, &boxes[2 * d], &boxes[2 * d + 1]);
0245 }
0246
0247
0248 int index = 0;
0249 unsigned int assignedscalarvectors = 0;
0250 for (uint i = 0; i < ndaughters; i += vecCore::VectorSize<Float_v>()) {
0251 Vector3D<Float_v> lower;
0252 Vector3D<Float_v> upper;
0253
0254 for (uint k = 0; k < vecCore::VectorSize<Float_v>(); ++k) {
0255 if (2 * (i + k) < 2 * ndaughters) {
0256 vecCore::Set(lower.x(), k, boxes[2 * (i + k)].x());
0257 vecCore::Set(lower.y(), k, boxes[2 * (i + k)].y());
0258 vecCore::Set(lower.z(), k, boxes[2 * (i + k)].z());
0259 vecCore::Set(upper.x(), k, boxes[2 * (i + k) + 1].x());
0260 vecCore::Set(upper.y(), k, boxes[2 * (i + k) + 1].y());
0261 vecCore::Set(upper.z(), k, boxes[2 * (i + k) + 1].z());
0262 assignedscalarvectors += 2;
0263 } else {
0264
0265
0266 vecCore::Scalar<Float_v> neginf = -InfinityLength<vecCore::Scalar<Float_v>>();
0267 vecCore::Set(lower.x(), k, neginf);
0268 vecCore::Set(lower.y(), k, neginf);
0269 vecCore::Set(lower.z(), k, neginf);
0270 vecCore::Set(upper.x(), k, neginf);
0271 vecCore::Set(upper.y(), k, neginf);
0272 vecCore::Set(upper.z(), k, neginf);
0273 }
0274 }
0275 vectorboxes[index++] = lower;
0276 vectorboxes[index++] = upper;
0277 }
0278 VECGEOM_ASSERT(index == size);
0279 VECGEOM_ASSERT(assignedscalarvectors == 2 * ndaughters);
0280 (void)assignedscalarvectors;
0281 }
0282
0283
0284 template <typename Container>
0285 void InitABBoxes(Container const &lvolumes)
0286 {
0287 for (auto lvol : lvolumes) {
0288 InitABBoxes(lvol);
0289 }
0290 }
0291
0292 #ifdef VECGEOM_USE_SURF
0293 static void ComputeSurfaceABBox(vgbrep::FramedSurface<Precision, Transformation3DMP<Precision>> const &framedSurface,
0294 Transformation3D const &volumeTransform, ABBox_s &lowerc, ABBox_s &upperc,
0295 vgbrep::CPUsurfData<Precision> const &cpudata, LogicalVolume const *lvol,
0296 const bool crop)
0297 {
0298 Vector3D<Precision> lowert, uppert;
0299
0300
0301 Vector3D<Precision> lower_vol, upper_vol;
0302 if (crop) lvol->GetUnplacedVolume()->Extent(lower_vol, upper_vol);
0303
0304
0305 framedSurface.Extent3D(lowert, uppert, cpudata);
0306 Vector3D<Precision> lower(lowert[0], lowert[1], lowert[2]);
0307 Vector3D<Precision> upper(uppert[0], uppert[1], uppert[2]);
0308
0309
0310 TransformBoundingBox<Transformation3DMP<Precision>>(lower, upper, framedSurface.fTrans);
0311
0312
0313 TransformBoundingBox<Transformation3D>(lower, upper, volumeTransform);
0314 if (crop) TransformBoundingBox<Transformation3D>(lower_vol, upper_vol, volumeTransform);
0315
0316 if (!crop) {
0317 lowerc.Set(lower.x(), lower.y(), lower.z());
0318 upperc.Set(upper.x(), upper.y(), upper.z());
0319 } else {
0320 lowerc.Set(std::max(lower_vol.x() - 1e-3, lower.x()), std::max(lower_vol.y() - 1e-3, lower.y()),
0321 std::max(lower_vol.z() - 1e-3, lower.z()));
0322 upperc.Set(std::min(upper_vol.x() + 1e-3, upper.x()), std::min(upper_vol.y() + 1e-3, upper.y()),
0323 std::min(upper_vol.z() + 1e-3, upper.z()));
0324
0325
0326 if (lower.x() > upper_vol.x() + vecgeom::kTolerance || upper.x() < lower_vol.x() - vecgeom::kTolerance ||
0327 lower.y() > upper_vol.y() + vecgeom::kTolerance || upper.y() < lower_vol.y() - vecgeom::kTolerance ||
0328 lower.z() > upper_vol.z() + vecgeom::kTolerance || upper.z() < lower_vol.z() - vecgeom::kTolerance) {
0329 lowerc.Set(0., 0., 0.);
0330 upperc.Set(0., 0., 0.);
0331 }
0332 }
0333 }
0334
0335
0336 void InitSurfaceABBoxesVol(LogicalVolume const *lvol, vgbrep::CPUsurfData<Precision> &cpudata, bool crop = false)
0337 {
0338 if (fVolToSurfaceABBoxesMap[lvol->id()] != nullptr && !crop) {
0339
0340 RemoveSurfaceABBoxes(lvol);
0341 }
0342
0343
0344 auto &rootShell = cpudata.fShells[lvol->id()];
0345 if (rootShell.fSurfaces.size() == 0) return;
0346
0347 ABBox_s *boxes;
0348 if (!crop) {
0349
0350 boxes = new ABBox_s[2 * rootShell.fExitingSurfaces.size() + 2 * rootShell.fEnteringSurfaces.size()];
0351 fVolToSurfaceABBoxesMap[lvol->id()] = boxes;
0352 } else {
0353 boxes = fVolToSurfaceABBoxesMap[lvol->id()];
0354 }
0355
0356 auto const identityTransform = new Transformation3D();
0357
0358
0359 for (auto motherSurfIndex = 0u; motherSurfIndex < rootShell.fExitingSurfaces.size(); motherSurfIndex++) {
0360
0361 auto exiting_ind = rootShell.fExitingSurfaces[motherSurfIndex];
0362 auto const localSurface = cpudata.fLocalSurfaces[rootShell.fSurfaces[exiting_ind]];
0363
0364 ComputeSurfaceABBox(localSurface, *identityTransform, boxes[2 * motherSurfIndex], boxes[2 * motherSurfIndex + 1],
0365 cpudata, lvol, crop);
0366 }
0367
0368
0369
0370
0371 int localSurfIndex = 0;
0372 for (auto pvol : lvol->GetDaughters()) {
0373
0374 auto shell = cpudata.fShells[pvol->GetLogicalVolume()->id()];
0375
0376 for (auto i = 0u; i < shell.fExitingSurfaces.size(); i++) {
0377 auto exiting_ind = shell.fExitingSurfaces[i];
0378 auto const &localSurface = cpudata.fLocalSurfaces[shell.fSurfaces[exiting_ind]];
0379
0380 auto daughterTransform = pvol->GetTransformation();
0381 ComputeSurfaceABBox(localSurface, *daughterTransform,
0382 boxes[2 * (localSurfIndex + rootShell.fExitingSurfaces.size())],
0383 boxes[2 * (localSurfIndex + rootShell.fExitingSurfaces.size()) + 1], cpudata,
0384 pvol->GetLogicalVolume(), crop);
0385 localSurfIndex++;
0386 }
0387 }
0388 }
0389
0390
0391 template <typename Container>
0392 void InitSurfaceABBoxes(Container const &lvolumes, vgbrep::CPUsurfData<Precision> &cpudata, bool crop = false)
0393 {
0394 for (auto lvol : lvolumes) {
0395 InitSurfaceABBoxesVol(lvol, cpudata, crop);
0396 }
0397 }
0398
0399
0400 void InitABBoxesForSurfaces(vgbrep::CPUsurfData<Precision> &cpudata, bool crop = false)
0401 {
0402 auto &container = GeoManager::Instance().GetLogicalVolumesMap();
0403 std::vector<LogicalVolume const *> logicalvolumes;
0404 if (!crop) {
0405 fVolToSurfaceABBoxesMap.resize(container.size(), nullptr);
0406 logicalvolumes.reserve(container.size());
0407 for (const auto &p : container) {
0408 logicalvolumes.push_back(p.second);
0409 }
0410 } else {
0411 GeoManager::Instance().GetAllLogicalVolumes(logicalvolumes);
0412 }
0413 InitSurfaceABBoxes(logicalvolumes, cpudata, crop);
0414 }
0415
0416 void RemoveSurfaceABBoxes(LogicalVolume const *lvol)
0417 {
0418 if (fVolToSurfaceABBoxesMap[lvol->id()] != nullptr) delete[] fVolToSurfaceABBoxesMap[lvol->id()];
0419 }
0420
0421
0422 ABBoxContainer_t GetSurfaceABBoxes(int ivol, int &size, vgbrep::CPUsurfData<Precision> const &cpudata)
0423 {
0424 size = cpudata.fShells[ivol].fExitingSurfaces.size() + cpudata.fShells[ivol].fEnteringSurfaces.size();
0425 return fVolToSurfaceABBoxesMap[ivol];
0426 }
0427 #endif
0428
0429 void InitABBoxesForCompleteGeometry()
0430 {
0431 auto &container = GeoManager::Instance().GetLogicalVolumesMap();
0432 fVolToABBoxesMap.resize(container.size(), nullptr);
0433 fVolToABBoxesMap_v.resize(container.size(), nullptr);
0434 std::vector<LogicalVolume const *> logicalvolumes(container.size());
0435 logicalvolumes.resize(0);
0436 for (auto p : container) {
0437 logicalvolumes.push_back(p.second);
0438 }
0439 InitABBoxes(logicalvolumes);
0440 }
0441
0442
0443 void RemoveABBoxes(LogicalVolume const *lvol)
0444 {
0445 if (fVolToABBoxesMap[lvol->id()] != nullptr) delete[] fVolToABBoxesMap[lvol->id()];
0446 }
0447
0448
0449
0450 ABBoxContainer_t GetABBoxes(LogicalVolume const *lvol, int &size)
0451 {
0452 size = lvol->GetDaughtersp()->size();
0453 return fVolToABBoxesMap[lvol->id()];
0454 }
0455
0456
0457
0458 ABBoxContainer_v GetABBoxes_v(LogicalVolume const *lvol, int &size)
0459 {
0460 int ndaughters = lvol->GetDaughtersp()->size();
0461 int extra = (ndaughters % vecCore::VectorSize<Float_v>() > 0) ? 1 : 0;
0462 size = ndaughters / vecCore::VectorSize<Float_v>() + extra;
0463 return fVolToABBoxesMap_v[lvol->id()];
0464 }
0465 };
0466
0467
0468 using ABBoxManager_t = ABBoxManager<vecgeom::Precision>;
0469
0470
0471 template <typename stream, typename Real_b>
0472 stream &operator<<(stream &s, std::vector<std::pair<unsigned int, double>> const &list)
0473 {
0474 for (auto i : list) {
0475 s << "(" << i.first << "," << i.second << ")" << " ";
0476 }
0477 return s;
0478 }
0479 }
0480
0481 #endif