@@ -234,7 +234,7 @@ void MatLayerCylSet::finalizeStructures()
234234 o2::gpu::FlatObject::resizeArray (get ()->mR2Intervals , 0 , nR2Int);
235235 o2::gpu::FlatObject::resizeArray (get ()->mInterval2LrID , 0 , nR2Int);
236236 get ()->mR2Intervals [0 ] = get ()->mRMin2 ;
237- get ()->mR2Intervals [1 ] = get ()-> mRMax2 ;
237+ get ()->mR2Intervals [1 ] = getLayer ( 0 ). getRMax2 () ;
238238 get ()->mInterval2LrID [0 ] = 0 ;
239239 auto & nRIntervals = get ()->mNRIntervals ;
240240 nRIntervals = 1 ;
@@ -319,14 +319,17 @@ void MatLayerCylSet::initLayerVoxelLU()
319319 if (LayerRMax < get ()->mRMax ) {
320320 LOG (fatal) << " Cannot initialized layer voxel lookup due to dimension problem (fix constants in MatLayerCylSet.h)" ;
321321 }
322+ // the top bit of an entry carries the ambiguity flag, so the interval index has one bit less
323+ if (get ()->mNRIntervals > VoxelSegmentMask) {
324+ LOG (fatal) << " Too many R intervals (" << get ()->mNRIntervals << " ) to pack into a layer voxel lookup entry" ;
325+ }
322326 for (int voxel = 0 ; voxel < NumVoxels; ++voxel) {
323327 // check the 2 extremes of this voxel "covering"
324- const auto lowerR = voxel * VoxelRDelta ;
325- const auto upperR = lowerR + VoxelRDelta ;
328+ const auto lowerR = voxelRMin ( voxel) ;
329+ const auto upperR = voxelRMax (voxel) ;
326330 const auto lowerSegment = searchSegment (lowerR * lowerR);
327331 const auto upperSegment = searchSegment (upperR * upperR);
328- mLayerVoxelLU [2 * voxel] = lowerSegment;
329- mLayerVoxelLU [2 * voxel + 1 ] = upperSegment;
332+ mLayerVoxelLU [voxel] = uint16_t (lowerSegment) | (lowerSegment != upperSegment ? VoxelAmbiguousBit : uint16_t {0 });
330333 }
331334 mInitializedLayerVoxelLU = true ;
332335}
@@ -477,7 +480,10 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
477480 tEndPhi = cross2;
478481 checkMorePhi = false ;
479482 } else { // last phi slice still not reached
480- tEndPhi = ray.crossRadial (lr, (stepPhiID > 0 ? phiID + 1 : phiID) % nphiSlices);
483+ const int boundaryPhiID = stepPhiID > 0 ? phiID + 1 : phiID;
484+ // phiID may be offset by one revolution to handle wrapping, but never by more.
485+ const int wrappedBoundaryPhiID = boundaryPhiID < nphiSlices ? boundaryPhiID : boundaryPhiID - nphiSlices;
486+ tEndPhi = ray.crossRadial (lr, wrappedBoundaryPhiID);
481487 if (tEndPhi == Ray::InvalidT) {
482488 break ; // ray parallel to radial line, abandon check for phi bin change
483489 }
@@ -490,6 +496,8 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
490496 }
491497 auto zID = lr.getZBinID (ray.getZ (tStartPhi));
492498 auto zIDLast = lr.getZBinID (ray.getZ (tEndPhi));
499+ const int wrappedPhiID = phiID < nphiSlices ? phiID : phiID - nphiSlices;
500+ const auto * cellRow = lr.getCellRow (wrappedPhiID);
493501 // check if Zbins are crossed
494502
495503#ifdef _DBG_LOC_
@@ -512,7 +520,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
512520 }
513521 // account materials of this step
514522 float step = tEndZ > tStartZ ? tEndZ - tStartZ : tStartZ - tEndZ; // the real step is ray.getDist(tEnd-tStart), will rescale all later
515- const auto & cell = lr. getCell (phiID % nphiSlices, zID) ;
523+ const auto & cell = cellRow[ zID] ;
516524 rval.meanRho += cell.meanRho * step;
517525 rval.meanX2X0 += cell.meanX2X0 * step;
518526 rval.length += step;
@@ -523,7 +531,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
523531 printf (
524532 " Lr#%3d / cross#%d : account %f<t<%f at phiSlice %d | Zbin: %3d (%3d) |[%+e %+e +%e]:[%+e %+e %+e] "
525533 " Step: %.3e StrpCor: %.3e\n " ,
526- lrID, ic, tEndZ, tStartZ, phiID % nphiSlices , zID, zIDLast,
534+ lrID, ic, tEndZ, tStartZ, wrappedPhiID , zID, zIDLast,
527535 pos0[0 ], pos0[1 ], pos0[2 ], pos1[0 ], pos1[1 ], pos1[2 ], step, ray.getDist (step));
528536#endif
529537
@@ -532,7 +540,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
532540 } while (checkMoreZ);
533541 } else {
534542 float step = tEndPhi > tStartPhi ? tEndPhi - tStartPhi : tStartPhi - tEndPhi; // the real step is |ray.getDist(tEnd-tStart)|, will rescale all later
535- const auto & cell = lr. getCell (phiID % nphiSlices, zID) ;
543+ const auto & cell = cellRow[ zID] ;
536544 rval.meanRho += cell.meanRho * step;
537545 rval.meanX2X0 += cell.meanX2X0 * step;
538546 rval.length += step;
@@ -543,7 +551,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
543551 printf (
544552 " Lr#%3d / cross#%d : account %f<t<%f at phiSlice %d | Zbin: %3d ----- |[%+e %+e +%e]:[%+e %+e %+e]"
545553 " Step: %.3e StrpCor: %.3e\n " ,
546- lrID, ic, tEndPhi, tStartPhi, phiID % nphiSlices , zID,
554+ lrID, ic, tEndPhi, tStartPhi, wrappedPhiID , zID,
547555 pos0[0 ], pos0[1 ], pos0[2 ], pos1[0 ], pos1[1 ], pos1[2 ], step, ray.getDist (step));
548556#endif
549557 }
@@ -585,8 +593,15 @@ GPUd() bool MatLayerCylSet::getLayersRange(const Ray& ray, short& lmin, short& l
585593 lmxInt = rmax2 < getRMax2 () ? searchSegment (rmax2, 0 ) : get ()->mNRIntervals - 2 ;
586594 lmnInt = rmin2 >= getRMin2 () ? searchSegment (rmin2, 0 , lmxInt + 1 ) : 0 ;
587595 } else {
588- lmxInt = rmax2 < getRMax2 () ? searchLayerFast (rmax2, 0 ) : get ()->mNRIntervals - 2 ;
589- lmnInt = rmin2 >= getRMin2 () ? searchLayerFast (rmin2, 0 , lmxInt + 1 ) : 0 ;
596+ // The two lookups are independent so overlapping the pair is worth the clumsier shape.
597+ const bool useMax = rmax2 < getRMax2 ();
598+ const bool useMin = rmin2 >= getRMin2 ();
599+ const int ixMax = useMax ? voxelIndex (rmax2) : NumVoxels - 1 ;
600+ const int ixMin = useMin ? voxelIndex (rmin2) : 0 ;
601+ const uint16_t eMax = mLayerVoxelLU [ixMax];
602+ const uint16_t eMin = mLayerVoxelLU [ixMin];
603+ lmxInt = useMax ? resolveLayerRange (rmax2, ixMax, eMax) : get ()->mNRIntervals - 2 ;
604+ lmnInt = useMin ? resolveLayerRange (rmin2, ixMin, eMin) : 0 ;
590605 }
591606
592607 const auto * interval2LrID = get ()->mInterval2LrID ;
@@ -605,11 +620,17 @@ GPUd() bool MatLayerCylSet::getLayersRange(const Ray& ray, short& lmin, short& l
605620GPUd () int MatLayerCylSet::searchLayerFast(float r2, int low, int high) const
606621{
607622 // we can avoid the sqrt .. at the cost of more memory in the lookup
608- const auto index = 2 * int (o2::gpu::CAMath::Sqrt (r2) * InvVoxelRDelta);
609- const auto layersfirst = mLayerVoxelLU [index];
610- const auto layerslast = mLayerVoxelLU [index + 1 ];
611- if (layersfirst != layerslast) {
612- // this means the voxel is undecided and we revert to search
623+ const auto index = voxelIndex (r2);
624+ return resolveLayerRange (r2, index, mLayerVoxelLU [index]);
625+ }
626+
627+ GPUd () int MatLayerCylSet::resolveLayerRange(float r2, int voxel, uint16_t entry) const
628+ {
629+ const int layersfirst = entry & VoxelSegmentMask;
630+ if (entry & VoxelAmbiguousBit) {
631+ // Recreate the upper candidate only for the small fraction of undecided voxels
632+ const auto upperR = voxelRMax (voxel);
633+ const auto layerslast = searchSegment (upperR * upperR);
613634 return searchSegment (r2, layersfirst, layerslast + 1 );
614635 }
615636 return layersfirst;
@@ -663,12 +684,13 @@ void MatLayerCylSet::flatten()
663684 offs = alignSize (offs + nLr * sizeof (MatLayerCyl), MatLayerCyl::getClassAlignmentBytes ()); // account for the alignment
664685
665686 // move array of R2 boundaries to the flat array
666- delete[] o2::gpu::FlatObject::resizeArray (get ()->mR2Intervals , nLr + 1 , nLr + 1 , (float *)(mFlatBufferPtr + offs));
667- offs = alignSize (offs + (nLr + 1 ) * sizeof (float ), getBufferAlignmentBytes ()); // account for the alignment
687+ const int nRBound = get ()->mNRIntervals ;
688+ delete[] o2::gpu::FlatObject::resizeArray (get ()->mR2Intervals , nRBound, nRBound, (float *)(mFlatBufferPtr + offs));
689+ offs = alignSize (offs + nRBound * sizeof (float ), getBufferAlignmentBytes ()); // account for the alignment
668690
669- // move array of R2 boundaries to the flat array
670- delete[] o2::gpu::FlatObject::resizeArray (get ()->mInterval2LrID , nLr, nLr , (int *)(mFlatBufferPtr + offs));
671- offs = alignSize (offs + nLr * sizeof (int ), getBufferAlignmentBytes ()); // account for the alignment
691+ // move array of interval -> layer ID to the flat array
692+ delete[] o2::gpu::FlatObject::resizeArray (get ()->mInterval2LrID , nRBound - 1 , nRBound - 1 , (int *)(mFlatBufferPtr + offs));
693+ offs = alignSize (offs + (nRBound - 1 ) * sizeof (int ), getBufferAlignmentBytes ()); // account for the alignment
672694
673695 for (int il = 0 ; il < nLr; il++) {
674696 MatLayerCyl& lr = get ()->mLayers [il];
@@ -710,6 +732,11 @@ void MatLayerCylSet::cloneFromObject(const MatLayerCylSet& obj, char* newFlatBuf
710732 // / Initializes from another object, copies data to newBufferPtr
711733 flatObject::cloneFromObject (obj, newFlatBufferPtr);
712734 fixPointers (mFlatBufferPtr );
735+ // the voxel lookup lives outside the flat buffer
736+ if (obj.mInitializedLayerVoxelLU ) {
737+ std::copy (obj.mLayerVoxelLU , obj.mLayerVoxelLU + NumVoxels, mLayerVoxelLU );
738+ mInitializedLayerVoxelLU = true ;
739+ }
713740}
714741
715742// ______________________________________________
0 commit comments