Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-14 09:26:14

0001 /*
0002  * VNavigator.h
0003  *
0004  *  Created on: 17.09.2015
0005  *      Author: swenzel
0006  */
0007 
0008 #ifndef NAVIGATION_VNAVIGATOR_H_
0009 #define NAVIGATION_VNAVIGATOR_H_
0010 
0011 #include "VecGeom/base/Global.h"
0012 #include "VecGeom/base/Vector3D.h"
0013 #include "VecGeom/base/SOA3D.h"
0014 #include "VecGeom/base/Transformation3D.h"
0015 #include "VecGeom/navigation/NavigationState.h"
0016 #include "VecGeom/navigation/GlobalLocator.h"
0017 #include "VecGeom/volumes/PlacedVolume.h"
0018 #include "VecGeom/volumes/LogicalVolume.h"
0019 #include "VecGeom/navigation/VSafetyEstimator.h"
0020 #include "VecGeom/navigation/NavStateFwd.h"
0021 
0022 namespace vecgeom {
0023 inline namespace VECGEOM_IMPL_NAMESPACE {
0024 
0025 // some forward declarations
0026 template <typename T>
0027 class Vector3D;
0028 // class NavigationState;
0029 class LogicalVolume;
0030 class Transformation3D;
0031 class VPlacedVolume;
0032 
0033 //! base class defining basic interface for navigation ( hit-detection )
0034 //! sub classes implement optimized algorithms for logical volumes
0035 class VNavigator {
0036 
0037 public:
0038   VNavigator() : fSafetyEstimator(nullptr) {}
0039 
0040   VECCORE_ATT_HOST_DEVICE
0041   VSafetyEstimator const *GetSafetyEstimator() const { return fSafetyEstimator; }
0042 
0043   //! computes the step (distance) to the next object in the geometry hierarchy obtained
0044   //! by propagating with step along the ray
0045   //! the next object could be after a boundary and does not necessarily coincide with the object
0046   //! hit by the ray
0047 
0048   //! this methods transforms the global coordinates into local ones usually calls more specialized methods
0049   //! like the hit detection on local coordinates
0050   VECCORE_ATT_HOST_DEVICE
0051   virtual Precision ComputeStepAndPropagatedState(Vector3D<Precision> const & /*globalpoint*/,
0052                                                   Vector3D<Precision> const & /*globaldir*/,
0053                                                   Precision /*(physics) step limit */,
0054                                                   NavigationState const & /*in_state*/,
0055                                                   NavigationState & /*out_state*/) const = 0;
0056 
0057   //! computes the step (distance) to the next object in the geometry hierarchy obtained
0058   //! by propagating with step along the ray
0059   //! updates out_state to contain information about the next hitting boundary:
0060   //!   - if a daugher is hit: out_state.Top() will be daughter
0061   //!   - if ray leaves volume: out_state.Top() will point to current volume
0062   //!   - if step limit > step: out_state == in_state
0063   //!
0064   //! This function is essentialy equal to ComputeStepAndPropagatedState without
0065   //! the relocation part
0066   virtual Precision ComputeStep(Vector3D<Precision> const & /*globalpoint*/, Vector3D<Precision> const & /*globaldir*/,
0067                                 Precision /*(physics) step limit */, NavigationState const & /*in_state*/,
0068                                 NavigationState & /*out_state*/) const = 0;
0069 
0070   //! as above ... also returns the safety ... does not give_back an out_state
0071   //! but the in_state might be modified to contain the next daughter when
0072   //! user specifies indicateDaughterHit = true
0073   VECCORE_ATT_HOST_DEVICE
0074   virtual Precision ComputeStepAndSafety(Vector3D<Precision> const & /*globalpoint*/,
0075                                          Vector3D<Precision> const & /*globaldir*/, Precision /*(physics) step limit */,
0076                                          NavigationState & /*in_state*/, bool /*calcsafety*/, Precision & /*safety*/,
0077                                          bool indicateDaughterHit = false) const = 0;
0078 
0079   // an alias interface ( using TGeo name )
0080   VECCORE_ATT_HOST_DEVICE
0081   void FindNextBoundaryAndStep(Vector3D<Precision> const &globalpoint, Vector3D<Precision> const &globaldir,
0082                                NavigationState const &in_state, NavigationState &out_state, Precision step_limit,
0083                                Precision &step) const
0084   {
0085     step = ComputeStepAndPropagatedState(globalpoint, globaldir, step_limit, in_state, out_state);
0086   }
0087 
0088   // an alias interface ( using TGeo name )
0089   void FindNextBoundaryAndStepAndSafety(Vector3D<Precision> const &globalpoint, Vector3D<Precision> const &globaldir,
0090                                         NavigationState const &in_state, NavigationState &out_state,
0091                                         Precision step_limit, Precision &step, bool calcsafety, Precision &safety) const
0092   {
0093     step = ComputeStepAndSafetyAndPropagatedState(globalpoint, globaldir, step_limit, in_state, out_state, calcsafety,
0094                                                   safety);
0095   }
0096 
0097   // a similar interface, in addition also returning the safety as a result
0098   VECCORE_ATT_HOST_DEVICE
0099   virtual Precision ComputeStepAndSafetyAndPropagatedState(Vector3D<Precision> const & /*globalpoint*/,
0100                                                            Vector3D<Precision> const & /*globaldir*/,
0101                                                            Precision /*(physics) step limit */,
0102                                                            NavigationState const & /*in_state*/,
0103                                                            NavigationState & /*out_state*/, bool /*calcsafefty*/,
0104                                                            Precision & /*safety_out*/) const = 0;
0105 
0106   // the bool return type indicates if out_state was already modified; this may happen in assemblies;
0107   // in this case we don't need to copy the in_state to the out state later on
0108   // NavigationState a pointer since we might want to pass nullptr
0109   VECCORE_ATT_HOST_DEVICE
0110   virtual bool CheckDaughterIntersections(LogicalVolume const * /*lvol*/, Vector3D<Precision> const & /*localpoint*/,
0111                                           Vector3D<Precision> const & /*localdir*/,
0112                                           NavigationState const * /*in_state*/, NavigationState * /*out_state*/,
0113                                           Precision & /*step*/, VPlacedVolume const *& /*hitcandidate*/) const = 0;
0114 
0115   /// check if a ray given by localpoint, localdir intersects with any daughter. Possibility
0116   /// to pass a volume which is blocked/should be ignored in the query. Updates the step as well as the hitcandidate
0117   /// volume. (This version is useful for G4; assemblies not supported)
0118   VECCORE_ATT_HOST_DEVICE
0119   virtual bool CheckDaughterIntersections(LogicalVolume const * /*lvol*/, Vector3D<Precision> const & /*localpoint*/,
0120                                           Vector3D<Precision> const & /*localdir*/, VPlacedVolume const * /*blocked*/,
0121                                           Precision & /*step*/, VPlacedVolume const *& /*hitcandidate*/) const
0122   {
0123     VECGEOM_ASSERT(false); // Not implemented --- notify of failure !!
0124     return false;
0125   }
0126 
0127 protected:
0128   // a common relocate method ( to calculate propagated states after the boundary )
0129   VECCORE_ATT_HOST_DEVICE
0130   virtual void Relocate(Vector3D<Precision> const & /*localpoint*/, NavigationState const &__restrict__ /*in_state*/,
0131                         NavigationState &__restrict__ /*out_state*/) const = 0;
0132 
0133   // a common function to be used by all navigators to ensure consistency in transporting points
0134   // after a boundary
0135   VECGEOM_FORCE_INLINE
0136   VECCORE_ATT_HOST_DEVICE
0137   static Vector3D<Precision> MovePointAfterBoundary(Vector3D<Precision> const &localpoint,
0138                                                     Vector3D<Precision> const &dir, Precision step)
0139   {
0140     const Precision extra = 1E-6; // TODO: to be revisited (potentially going for a more relative approach)
0141     return localpoint + (step + extra) * dir;
0142   }
0143 
0144 public:
0145   VECCORE_ATT_DEVICE
0146   virtual ~VNavigator(){};
0147 
0148   // get name of implementing class
0149   virtual const char *GetName() const = 0;
0150 
0151   typedef VSafetyEstimator SafetyEstimator_t;
0152 
0153 protected:
0154   VECCORE_ATT_HOST_DEVICE
0155   VNavigator(VSafetyEstimator *s) : fSafetyEstimator(s) {}
0156   VSafetyEstimator *fSafetyEstimator; // a pointer to the safetyEstimator which can be used by the Navigator
0157 
0158   // some common code to prepare the outstate
0159   VECGEOM_FORCE_INLINE
0160   VECCORE_ATT_HOST_DEVICE
0161   static Precision PrepareOutState(NavigationState const &__restrict__ in_state,
0162                                    NavigationState &__restrict__ out_state, Precision geom_step, Precision step_limit,
0163                                    VPlacedVolume const *hitcandidate, bool &doneafterthisstep)
0164   {
0165     // now we have the candidates and we prepare the out_state
0166     in_state.CopyTo(&out_state);
0167     doneafterthisstep = false;
0168 
0169     // if the following is the case we are in the wrong volume;
0170     // assuming that DistanceToIn returns negative number when point is inside
0171     // do nothing (step=0) and retry one level higher
0172 
0173     // TODO: put diagnostic code here ( like in original SimpleNavigator )
0174     if (geom_step == kInfLength && step_limit > 0.) {
0175       geom_step = vecgeom::kTolerance;
0176       out_state.SetBoundaryState(true);
0177       do {
0178         out_state.Pop();
0179       } while (out_state.Top()->GetLogicalVolume()->GetUnplacedVolume()->IsAssembly());
0180       doneafterthisstep = true;
0181       return geom_step;
0182     }
0183 
0184     // is geometry further away than physics step?
0185     // this is a physics step
0186     if (geom_step > step_limit) {
0187       // don't need to do anything
0188       geom_step = step_limit;
0189       out_state.SetBoundaryState(false);
0190       return geom_step;
0191     }
0192 
0193     // otherwise it is a geometry step
0194     out_state.SetBoundaryState(true);
0195     out_state.SetLastExited();
0196     if (hitcandidate) out_state.Push(hitcandidate);
0197 
0198     if (geom_step < 0.) {
0199       // std::cerr << "WARNING: STEP NEGATIVE; NEXTVOLUME " << nexthitvolume << std::endl;
0200       // InspectEnvironmentForPointAndDirection( globalpoint, globaldir, currentstate );
0201       geom_step = 0.;
0202     }
0203     return geom_step;
0204   }
0205 
0206   // kernel to be used with both scalar and vector types
0207   template <typename T>
0208   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static T TreatDistanceToMother(VPlacedVolume const *pvol,
0209                                                                               Vector3D<T> const &localpoint,
0210                                                                               Vector3D<T> const &localdir, T step_limit)
0211   {
0212     T step;
0213     VECGEOM_VALIDATE(pvol != nullptr, << "currentvolume is null in navigation");
0214     step = pvol->DistanceToOut(localpoint, localdir, step_limit);
0215     vecCore::MaskedAssign(step, step < T(0.), T(0.));
0216     return step;
0217   }
0218 
0219   // default static function doing the global to local transformation
0220   // may be redefined in concrete implementations ( for instance in cases where we know the form of the global matrix
0221   // a-priori )
0222   // input
0223   // TODO: think about how we can have scalar + SIMD version
0224   // note: the last argument is a trick to pass information across function calls ( only exploited in specialized
0225   // navigators )
0226   template <typename T>
0227   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DoGlobalToLocalTransformation(
0228       NavigationState const &in_state, Vector3D<T> const &globalpoint, Vector3D<T> const &globaldir,
0229       Vector3D<T> &localpoint, Vector3D<T> &localdir)
0230   {
0231     // calculate local point/dir from global point/dir
0232     Transformation3D m;
0233     in_state.TopMatrix(m);
0234     localpoint = m.Transform(globalpoint);
0235     localdir   = m.TransformDirection(globaldir);
0236   }
0237 };
0238 
0239 //! template class providing a standard implementation for
0240 //! some interfaces in VNavigator (using the CRT pattern)
0241 template <typename Impl, bool MotherIsConvex = false>
0242 class VNavigatorHelper : public VNavigator {
0243 protected:
0244   using VNavigator::VNavigator;
0245 
0246 public:
0247   VECCORE_ATT_HOST_DEVICE
0248   virtual Precision ComputeStepAndPropagatedState(Vector3D<Precision> const &globalpoint,
0249                                                   Vector3D<Precision> const &globaldir, Precision step_limit,
0250                                                   NavigationState const &in_state,
0251                                                   NavigationState &out_state) const override
0252   {
0253 #ifdef DEBUGNAV
0254     static size_t counter = 0;
0255     counter++;
0256 #endif
0257     // calculate local point/dir from global point/dir
0258     // call the static function for this provided/specialized by the Impl
0259     Vector3D<Precision> localpoint;
0260     Vector3D<Precision> localdir;
0261     Impl::DoGlobalToLocalTransformation(in_state, globalpoint, globaldir, localpoint, localdir);
0262 
0263     VPlacedVolume const *hitcandidate = nullptr;
0264     auto pvol                         = in_state.Top();
0265     auto lvol                         = pvol->GetLogicalVolume();
0266     Precision step                    = Impl::TreatDistanceToMother(pvol, localpoint, localdir, step_limit);
0267     // "suck in" algorithm from Impl and treat hit detection in local coordinates for daughters
0268     if (lvol->GetDaughters().size() > 0)
0269       ((Impl *)this)
0270           ->Impl::CheckDaughterIntersections(lvol, localpoint, localdir, &in_state, &out_state, step, hitcandidate);
0271 
0272     // fix state
0273     bool done;
0274     step = Impl::PrepareOutState(in_state, out_state, step, step_limit, hitcandidate, done);
0275     if (done) {
0276       if (out_state.Top() != nullptr) {
0277         VECGEOM_ASSERT(!out_state.Top()->GetLogicalVolume()->GetUnplacedVolume()->IsAssembly());
0278       }
0279       return step;
0280     }
0281     // step was physics limited
0282     if (!out_state.IsOnBoundary()) return step;
0283 
0284     // otherwise if necessary do a relocation
0285     // try relocation to refine out_state to correct location after the boundary
0286     ((Impl *)this)->Impl::Relocate(MovePointAfterBoundary(localpoint, localdir, step), in_state, out_state);
0287     if (out_state.Top() != nullptr) {
0288       while (out_state.Top()->IsAssembly()) {
0289         out_state.Pop();
0290       }
0291       VECGEOM_ASSERT(!out_state.Top()->GetLogicalVolume()->GetUnplacedVolume()->IsAssembly());
0292     }
0293     return step;
0294   }
0295 
0296   virtual Precision ComputeStep(Vector3D<Precision> const &globalpoint, Vector3D<Precision> const &globaldir,
0297                                 Precision step_limit, NavigationState const &in_state,
0298                                 NavigationState &out_state) const override
0299   {
0300 #ifdef DEBUGNAV
0301     static size_t counter = 0;
0302     counter++;
0303 #endif
0304     // calculate local point/dir from global point/dir
0305     // call the static function for this provided/specialized by the Impl
0306     Vector3D<Precision> localpoint;
0307     Vector3D<Precision> localdir;
0308     Impl::DoGlobalToLocalTransformation(in_state, globalpoint, globaldir, localpoint, localdir);
0309 
0310     VPlacedVolume const *hitcandidate = nullptr;
0311     auto pvol                         = in_state.Top();
0312     auto lvol                         = pvol->GetLogicalVolume();
0313     Precision step                    = Impl::TreatDistanceToMother(pvol, localpoint, localdir, step_limit);
0314     // "suck in" algorithm from Impl and treat hit detection in local coordinates for daughters
0315     if (lvol->GetDaughters().size() > 0)
0316       ((Impl *)this)
0317           ->Impl::CheckDaughterIntersections(lvol, localpoint, localdir, &in_state, &out_state, step, hitcandidate);
0318 
0319     // fix state
0320     bool done;
0321     step = Impl::PrepareOutState(in_state, out_state, step, step_limit, hitcandidate, done);
0322     if (done) {
0323       if (out_state.Top() != nullptr) {
0324         VECGEOM_ASSERT(!out_state.Top()->GetLogicalVolume()->GetUnplacedVolume()->IsAssembly());
0325       }
0326       return step;
0327     }
0328     // step was physics limited
0329     if (!out_state.IsOnBoundary()) return step;
0330 
0331     return step;
0332   }
0333 
0334   VECCORE_ATT_HOST_DEVICE
0335   virtual Precision ComputeStepAndSafety(Vector3D<Precision> const &globalpoint, Vector3D<Precision> const &globaldir,
0336                                          Precision step_limit, NavigationState &in_state, bool calcsafety,
0337                                          Precision &safety, bool indicateDaughterHit = false) const override
0338   {
0339 // FIXME: combine this kernel and the one for ComputeStep() into one generic function
0340 #ifdef DEBUGNAV
0341     static size_t counter = 0;
0342     counter++;
0343 #endif
0344     // calculate local point/dir from global point/dir
0345     // call the static function for this provided/specialized by the Impl
0346     Vector3D<Precision> localpoint;
0347     Vector3D<Precision> localdir;
0348     NavigationState *out_state = nullptr;
0349 
0350     Impl::DoGlobalToLocalTransformation(in_state, globalpoint, globaldir, localpoint, localdir);
0351 
0352     // get safety first ( the benefit here is that we reuse the local points )
0353     using SafetyE_t = typename Impl::SafetyEstimator_t;
0354     if (calcsafety) {
0355       // call the appropriate safety Estimator
0356       safety = ((SafetyE_t *)fSafetyEstimator)->SafetyE_t::ComputeSafetyForLocalPoint(localpoint, in_state.Top());
0357     }
0358 
0359     VPlacedVolume const *hitcandidate = nullptr;
0360     auto pvol                         = in_state.Top();
0361     auto lvol                         = pvol->GetLogicalVolume();
0362     Precision step                    = step_limit;
0363 
0364     // is the next object certainly further away than the safety
0365     bool safetydone = calcsafety && safety >= step;
0366 
0367     if (!safetydone) {
0368       step = Impl::TreatDistanceToMother(pvol, localpoint, localdir, step_limit);
0369       // "suck in" algorithm from Impl and treat hit detection in local coordinates for daughters
0370       if (lvol->GetDaughters().size() > 0)
0371         ((Impl *)this)
0372             ->Impl::CheckDaughterIntersections(lvol, localpoint, localdir, &in_state, out_state, step, hitcandidate);
0373     }
0374     if (indicateDaughterHit && hitcandidate) in_state.Push(hitcandidate);
0375     return Min(step, step_limit);
0376   }
0377 
0378   // a similar interface also returning the safety
0379   // TODO: reduce this evident code duplication with ComputeStepAndPropagatedState
0380   VECCORE_ATT_HOST_DEVICE
0381   virtual Precision ComputeStepAndSafetyAndPropagatedState(Vector3D<Precision> const &globalpoint,
0382                                                            Vector3D<Precision> const &globaldir, Precision step_limit,
0383                                                            NavigationState const &__restrict__ in_state,
0384                                                            NavigationState &__restrict__ out_state, bool calcsafety,
0385                                                            Precision &safety_out) const override
0386   {
0387     // calculate local point/dir from global point/dir
0388     Vector3D<Precision> localpoint;
0389     Vector3D<Precision> localdir;
0390     Impl::DoGlobalToLocalTransformation(in_state, globalpoint, globaldir, localpoint, localdir);
0391 
0392     // get safety first ( the benefit here is that we reuse the local points )
0393     using SafetyE_t = typename Impl::SafetyEstimator_t;
0394     safety_out      = 0.;
0395     if (calcsafety) {
0396       // call the appropriate safety Estimator
0397       safety_out = ((SafetyE_t *)fSafetyEstimator)->SafetyE_t::ComputeSafetyForLocalPoint(localpoint, in_state.Top());
0398     }
0399 
0400     VPlacedVolume const *hitcandidate = nullptr;
0401     auto pvol                         = in_state.Top();
0402     auto lvol                         = pvol->GetLogicalVolume();
0403     Precision step                    = Impl::TreatDistanceToMother(pvol, localpoint, localdir, step_limit);
0404     ;
0405     if (lvol->GetDaughters().size() > 0)
0406       // "suck in" algorithm from Impl and treat hit detection in local coordinates for daughters
0407       ((Impl *)this)
0408           ->Impl::CheckDaughterIntersections(lvol, localpoint, localdir, &in_state, &out_state, step, hitcandidate);
0409 
0410     // fix state
0411     bool done;
0412     step = Impl::PrepareOutState(in_state, out_state, step, step_limit, hitcandidate, done);
0413     if (done) return step;
0414 
0415     // step was physics limited
0416     if (!out_state.IsOnBoundary()) return step;
0417 
0418     // otherwise if necessary do a relocation
0419     // try relocation to refine out_state to correct location after the boundary
0420     ((Impl *)this)->Impl::Relocate(MovePointAfterBoundary(localpoint, localdir, step), in_state, out_state);
0421     return step;
0422   }
0423 
0424 protected:
0425   // a common relocate method ( to calculate propagated states after the boundary )
0426   VECGEOM_FORCE_INLINE
0427   VECCORE_ATT_HOST_DEVICE
0428   virtual void Relocate(Vector3D<Precision> const &pointafterboundary, NavigationState const &__restrict__ in_state,
0429                         NavigationState &__restrict__ out_state) const override
0430   {
0431     // this means that we are leaving the mother
0432     // alternatively we could use nextvolumeindex like before
0433     if (out_state.Top() == in_state.Top()) {
0434       GlobalLocator::RelocatePointFromPathForceDifferent(pointafterboundary, out_state);
0435 #ifdef CHECK_RELOCATION_ERRORS
0436       VECGEOM_VALIDATE(in_state.Distance(out_state) != 0, << " error relocating when leaving ");
0437 #endif
0438     } else {
0439       // continue directly further down ( next volume should have been stored in out_state already )
0440       VPlacedVolume const *nextvol = out_state.Top();
0441       out_state.Pop();
0442       GlobalLocator::LocateGlobalPoint(nextvol, nextvol->GetTransformation()->Transform(pointafterboundary), out_state,
0443                                        false);
0444 #ifdef CHECK_RELOCATION_ERRORS
0445       VECGEOM_VALIDATE(in_state.Distance(out_state) != 0, << " error relocating when entering ");
0446 #endif
0447       return;
0448     }
0449   }
0450 
0451 public:
0452   static const char *GetClassName() { return Impl::gClassNameString; }
0453 
0454   virtual const char *GetName() const override { return GetClassName(); }
0455 }; // end class VNavigatorHelper
0456 } // namespace VECGEOM_IMPL_NAMESPACE
0457 } // namespace vecgeom
0458 
0459 #endif /* NAVIGATION_VNAVIGATOR_H_ */