Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:39

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2019-2020 CERN for the benefit of the Acts project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Material/VolumeMaterialMapper.hpp"
0010 
0011 #include "Acts/Definitions/Direction.hpp"
0012 #include "Acts/Definitions/Tolerance.hpp"
0013 #include "Acts/EventData/ParticleHypothesis.hpp"
0014 #include "Acts/EventData/TrackParameters.hpp"
0015 #include "Acts/Geometry/ApproachDescriptor.hpp"
0016 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0017 #include "Acts/Geometry/Layer.hpp"
0018 #include "Acts/Geometry/TrackingGeometry.hpp"
0019 #include "Acts/Material/AccumulatedVolumeMaterial.hpp"
0020 #include "Acts/Material/HomogeneousVolumeMaterial.hpp"
0021 #include "Acts/Material/IVolumeMaterial.hpp"
0022 #include "Acts/Material/InterpolatedMaterialMap.hpp"
0023 #include "Acts/Material/Material.hpp"
0024 #include "Acts/Material/MaterialGridHelper.hpp"
0025 #include "Acts/Material/MaterialInteraction.hpp"
0026 #include "Acts/Material/ProtoVolumeMaterial.hpp"
0027 #include "Acts/Propagator/AbortList.hpp"
0028 #include "Acts/Propagator/ActionList.hpp"
0029 #include "Acts/Propagator/SurfaceCollector.hpp"
0030 #include "Acts/Propagator/VolumeCollector.hpp"
0031 #include "Acts/Surfaces/SurfaceArray.hpp"
0032 #include "Acts/Utilities/BinAdjustmentVolume.hpp"
0033 #include "Acts/Utilities/BinnedArray.hpp"
0034 #include "Acts/Utilities/Grid.hpp"
0035 #include "Acts/Utilities/Result.hpp"
0036 
0037 #include <cmath>
0038 #include <cstddef>
0039 #include <iosfwd>
0040 #include <ostream>
0041 #include <stdexcept>
0042 #include <string>
0043 #include <tuple>
0044 #include <type_traits>
0045 #include <vector>
0046 
0047 namespace Acts {
0048 struct EndOfWorldReached;
0049 }  // namespace Acts
0050 
0051 Acts::VolumeMaterialMapper::VolumeMaterialMapper(
0052     const Config& cfg, StraightLinePropagator propagator,
0053     std::unique_ptr<const Logger> slogger)
0054     : m_cfg(cfg),
0055       m_propagator(std::move(propagator)),
0056       m_logger(std::move(slogger)) {}
0057 
0058 Acts::VolumeMaterialMapper::State Acts::VolumeMaterialMapper::createState(
0059     const GeometryContext& gctx, const MagneticFieldContext& mctx,
0060     const TrackingGeometry& tGeometry) const {
0061   // Parse the geometry and find all surfaces with material proxies
0062   auto world = tGeometry.highestTrackingVolume();
0063 
0064   // The Surface material mapping state
0065   State mState(gctx, mctx);
0066   resolveMaterialVolume(mState, *world);
0067   collectMaterialSurfaces(mState, *world);
0068   return mState;
0069 }
0070 
0071 void Acts::VolumeMaterialMapper::resolveMaterialVolume(
0072     State& mState, const TrackingVolume& tVolume) const {
0073   ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
0074                                    << "' for material surfaces.")
0075 
0076   ACTS_VERBOSE("- Insert Volume ...");
0077   checkAndInsert(mState, tVolume);
0078 
0079   // Step down into the sub volume
0080   if (tVolume.confinedVolumes()) {
0081     ACTS_VERBOSE("- Check children volume ...");
0082     for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
0083       // Recursive call
0084       resolveMaterialVolume(mState, *sVolume);
0085     }
0086   }
0087   if (!tVolume.denseVolumes().empty()) {
0088     for (auto& sVolume : tVolume.denseVolumes()) {
0089       // Recursive call
0090       resolveMaterialVolume(mState, *sVolume);
0091     }
0092   }
0093 }
0094 
0095 void Acts::VolumeMaterialMapper::checkAndInsert(
0096     State& mState, const TrackingVolume& volume) const {
0097   auto volumeMaterial = volume.volumeMaterial();
0098   // Check if the volume has a proxy
0099   if (volumeMaterial != nullptr) {
0100     auto geoID = volume.geometryId();
0101     std::size_t volumeID = geoID.volume();
0102     ACTS_DEBUG("Material volume found with volumeID " << volumeID);
0103     ACTS_DEBUG("       - ID is " << geoID);
0104 
0105     // We need a dynamic_cast to either a volume material proxy or
0106     // proper surface material
0107     auto psm = dynamic_cast<const ProtoVolumeMaterial*>(volumeMaterial);
0108     // Get the bin utility: try proxy material first
0109     const BinUtility* bu = (psm != nullptr) ? (&psm->binUtility()) : nullptr;
0110     if (bu != nullptr) {
0111       // Screen output for Binned Surface material
0112       ACTS_DEBUG("       - (proto) binning is " << *bu);
0113       // Now update
0114       BinUtility buAdjusted = adjustBinUtility(*bu, volume);
0115       // Screen output for Binned Surface material
0116       ACTS_DEBUG("       - adjusted binning is " << buAdjusted);
0117       mState.materialBin[geoID] = buAdjusted;
0118       if (bu->dimensions() == 0) {
0119         ACTS_DEBUG("Binning of dimension 0 create AccumulatedVolumeMaterial");
0120         Acts::AccumulatedVolumeMaterial homogeneousAccumulation;
0121         mState.homogeneousGrid[geoID] = homogeneousAccumulation;
0122       } else if (bu->dimensions() == 2) {
0123         ACTS_DEBUG("Binning of dimension 2 create 2D Grid");
0124         std::function<Acts::Vector2(Acts::Vector3)> transfoGlobalToLocal;
0125         Acts::Grid2D Grid = createGrid2D(buAdjusted, transfoGlobalToLocal);
0126         mState.grid2D.insert(std::make_pair(geoID, Grid));
0127         mState.transform2D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0128       } else if (bu->dimensions() == 3) {
0129         ACTS_DEBUG("Binning of dimension 3 create 3D Grid");
0130         std::function<Acts::Vector3(Acts::Vector3)> transfoGlobalToLocal;
0131         Acts::Grid3D Grid = createGrid3D(buAdjusted, transfoGlobalToLocal);
0132         mState.grid3D.insert(std::make_pair(geoID, Grid));
0133         mState.transform3D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0134       } else {
0135         throw std::invalid_argument(
0136             "Incorrect bin dimension, only 0, 2 and 3 are accepted");
0137       }
0138       return;
0139     }
0140     // Second attempt: 2D binned material
0141     auto bmp2 = dynamic_cast<
0142         const InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid2D>>*>(
0143         volumeMaterial);
0144     bu = (bmp2 != nullptr) ? (&bmp2->binUtility()) : nullptr;
0145     if (bu != nullptr) {
0146       // Screen output for Binned Surface material
0147       ACTS_DEBUG("       - (2D grid) binning is " << *bu);
0148       mState.materialBin[geoID] = *bu;
0149       std::function<Acts::Vector2(Acts::Vector3)> transfoGlobalToLocal;
0150       Acts::Grid2D Grid = createGrid2D(*bu, transfoGlobalToLocal);
0151       mState.grid2D.insert(std::make_pair(geoID, Grid));
0152       mState.transform2D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0153       return;
0154     }
0155     // Third attempt: 3D binned material
0156     auto bmp3 = dynamic_cast<
0157         const InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid3D>>*>(
0158         volumeMaterial);
0159     bu = (bmp3 != nullptr) ? (&bmp3->binUtility()) : nullptr;
0160     if (bu != nullptr) {
0161       // Screen output for Binned Surface material
0162       ACTS_DEBUG("       - (3D grid) binning is " << *bu);
0163       mState.materialBin[geoID] = *bu;
0164       std::function<Acts::Vector3(Acts::Vector3)> transfoGlobalToLocal;
0165       Acts::Grid3D Grid = createGrid3D(*bu, transfoGlobalToLocal);
0166       mState.grid3D.insert(std::make_pair(geoID, Grid));
0167       mState.transform3D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0168       return;
0169     } else {
0170       // Create a homogeneous type of material
0171       ACTS_DEBUG("       - this is homogeneous material.");
0172       BinUtility buHomogeneous;
0173       mState.materialBin[geoID] = buHomogeneous;
0174       Acts::AccumulatedVolumeMaterial homogeneousAccumulation;
0175       mState.homogeneousGrid[geoID] = homogeneousAccumulation;
0176       return;
0177     }
0178   }
0179 }
0180 
0181 void Acts::VolumeMaterialMapper::collectMaterialSurfaces(
0182     State& mState, const TrackingVolume& tVolume) const {
0183   ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
0184                                    << "' for material surfaces.")
0185 
0186   ACTS_VERBOSE("- boundary surfaces ...");
0187   // Check the boundary surfaces
0188   for (auto& bSurface : tVolume.boundarySurfaces()) {
0189     if (bSurface->surfaceRepresentation().surfaceMaterial() != nullptr) {
0190       mState.surfaceMaterial[bSurface->surfaceRepresentation().geometryId()] =
0191           bSurface->surfaceRepresentation().surfaceMaterialSharedPtr();
0192     }
0193   }
0194 
0195   ACTS_VERBOSE("- confined layers ...");
0196   // Check the confined layers
0197   if (tVolume.confinedLayers() != nullptr) {
0198     for (auto& cLayer : tVolume.confinedLayers()->arrayObjects()) {
0199       // Take only layers that are not navigation layers
0200       if (cLayer->layerType() != navigation) {
0201         // Check the representing surface
0202         if (cLayer->surfaceRepresentation().surfaceMaterial() != nullptr) {
0203           mState.surfaceMaterial[cLayer->surfaceRepresentation().geometryId()] =
0204               cLayer->surfaceRepresentation().surfaceMaterialSharedPtr();
0205         }
0206         // Get the approach surfaces if present
0207         if (cLayer->approachDescriptor() != nullptr) {
0208           for (auto& aSurface :
0209                cLayer->approachDescriptor()->containedSurfaces()) {
0210             if (aSurface != nullptr) {
0211               if (aSurface->surfaceMaterial() != nullptr) {
0212                 mState.surfaceMaterial[aSurface->geometryId()] =
0213                     aSurface->surfaceMaterialSharedPtr();
0214               }
0215             }
0216           }
0217         }
0218         // Get the sensitive surface is present
0219         if (cLayer->surfaceArray() != nullptr) {
0220           // Sensitive surface loop
0221           for (auto& sSurface : cLayer->surfaceArray()->surfaces()) {
0222             if (sSurface != nullptr) {
0223               if (sSurface->surfaceMaterial() != nullptr) {
0224                 mState.surfaceMaterial[sSurface->geometryId()] =
0225                     sSurface->surfaceMaterialSharedPtr();
0226               }
0227             }
0228           }
0229         }
0230       }
0231     }
0232   }
0233   // Step down into the sub volume
0234   if (tVolume.confinedVolumes()) {
0235     for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
0236       // Recursive call
0237       collectMaterialSurfaces(mState, *sVolume);
0238     }
0239   }
0240 }
0241 
0242 void Acts::VolumeMaterialMapper::createExtraHits(
0243     State& mState,
0244     std::pair<const GeometryIdentifier, BinUtility>& currentBinning,
0245     Acts::MaterialSlab properties, const Vector3& position,
0246     Vector3 direction) const {
0247   if (currentBinning.second.dimensions() == 0) {
0248     // Writing homogeneous material for the current volumes no need to create
0249     // extra hits. We directly accumulate the material
0250     mState.homogeneousGrid[currentBinning.first].accumulate(properties);
0251     return;
0252   }
0253 
0254   // Computing the extra hits properties based on the mappingStep length
0255   int volumeStep =
0256       static_cast<int>(std::floor(properties.thickness() / m_cfg.mappingStep));
0257   float remainder = properties.thickness() - m_cfg.mappingStep * volumeStep;
0258   properties.scaleThickness(m_cfg.mappingStep / properties.thickness());
0259   direction = direction * (m_cfg.mappingStep / direction.norm());
0260 
0261   for (int extraStep = 0; extraStep < volumeStep; extraStep++) {
0262     Vector3 extraPosition = position + extraStep * direction;
0263     // Create additional extrapolated points for the grid mapping
0264 
0265     if (currentBinning.second.dimensions() == 2) {
0266       auto grid = mState.grid2D.find(currentBinning.first);
0267       if (grid != mState.grid2D.end()) {
0268         // Find which grid bin the material fall into then accumulate
0269         Acts::Grid2D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0270             mState.transform2D[currentBinning.first](extraPosition));
0271         grid->second.atLocalBins(index).accumulate(properties);
0272       } else {
0273         throw std::domain_error("No grid 2D was found");
0274       }
0275     } else if (currentBinning.second.dimensions() == 3) {
0276       auto grid = mState.grid3D.find(currentBinning.first);
0277       if (grid != mState.grid3D.end()) {
0278         // Find which grid bin the material fall into then accumulate
0279         Acts::Grid3D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0280             mState.transform3D[currentBinning.first](extraPosition));
0281         grid->second.atLocalBins(index).accumulate(properties);
0282       } else {
0283         throw std::domain_error("No grid 3D was found");
0284       }
0285     }
0286   }
0287 
0288   if (remainder > 0) {
0289     // We need to have an additional extra hit with the remainder length. Adjust
0290     // the thickness of the last extrapolated step
0291     properties.scaleThickness(remainder / properties.thickness());
0292     Vector3 extraPosition = position + volumeStep * direction;
0293     if (currentBinning.second.dimensions() == 2) {
0294       auto grid = mState.grid2D.find(currentBinning.first);
0295       if (grid != mState.grid2D.end()) {
0296         // Find which grid bin the material fall into then accumulate
0297         Acts::Grid2D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0298             mState.transform2D[currentBinning.first](extraPosition));
0299         grid->second.atLocalBins(index).accumulate(properties);
0300       } else {
0301         throw std::domain_error("No grid 2D was found");
0302       }
0303     } else if (currentBinning.second.dimensions() == 3) {
0304       auto grid = mState.grid3D.find(currentBinning.first);
0305       if (grid != mState.grid3D.end()) {
0306         // Find which grid bin the material fall into then accumulate
0307         Acts::Grid3D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0308             mState.transform3D[currentBinning.first](extraPosition));
0309         grid->second.atLocalBins(index).accumulate(properties);
0310       } else {
0311         throw std::domain_error("No grid 3D was found");
0312       }
0313     }
0314   }
0315 }
0316 
0317 void Acts::VolumeMaterialMapper::finalizeMaps(State& mState) const {
0318   // iterate over the volumes
0319   for (auto& matBin : mState.materialBin) {
0320     ACTS_DEBUG("Create the material for volume  " << matBin.first);
0321     if (matBin.second.dimensions() == 0) {
0322       // Average the homogeneous volume material then store it
0323       ACTS_DEBUG("Homogeneous material volume");
0324       Acts::Material mat = mState.homogeneousGrid[matBin.first].average();
0325       mState.volumeMaterial[matBin.first] =
0326           std::make_unique<HomogeneousVolumeMaterial>(mat);
0327     } else if (matBin.second.dimensions() == 2) {
0328       // Average the material in the 2D grid then create an
0329       // InterpolatedMaterialMap
0330       ACTS_DEBUG("Grid material volume");
0331       auto grid = mState.grid2D.find(matBin.first);
0332       if (grid != mState.grid2D.end()) {
0333         Acts::MaterialGrid2D matGrid = mapMaterialPoints(grid->second);
0334         MaterialMapper<Acts::MaterialGrid2D> matMap(
0335             mState.transform2D[matBin.first], matGrid);
0336         mState.volumeMaterial[matBin.first] = std::make_unique<
0337             InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid2D>>>(
0338             std::move(matMap), matBin.second);
0339       } else {
0340         throw std::domain_error("No grid 2D was found");
0341       }
0342     } else if (matBin.second.dimensions() == 3) {
0343       // Average the material in the 3D grid then create an
0344       // InterpolatedMaterialMap
0345       ACTS_DEBUG("Grid material volume");
0346       auto grid = mState.grid3D.find(matBin.first);
0347       if (grid != mState.grid3D.end()) {
0348         Acts::MaterialGrid3D matGrid = mapMaterialPoints(grid->second);
0349         MaterialMapper<Acts::MaterialGrid3D> matMap(
0350             mState.transform3D[matBin.first], matGrid);
0351         mState.volumeMaterial[matBin.first] = std::make_unique<
0352             InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid3D>>>(
0353             std::move(matMap), matBin.second);
0354       } else {
0355         throw std::domain_error("No grid 3D was found");
0356       }
0357     } else {
0358       throw std::invalid_argument(
0359           "Incorrect bin dimension, only 0, 2 and 3 are accepted");
0360     }
0361   }
0362 }
0363 
0364 void Acts::VolumeMaterialMapper::mapMaterialTrack(
0365     State& mState, RecordedMaterialTrack& mTrack) const {
0366   using VectorHelpers::makeVector4;
0367 
0368   // Neutral curvilinear parameters
0369   NeutralCurvilinearTrackParameters start(
0370       makeVector4(mTrack.first.first, 0), mTrack.first.second,
0371       1 / mTrack.first.second.norm(), std::nullopt,
0372       NeutralParticleHypothesis::geantino());
0373 
0374   // Prepare Action list and abort list
0375   using BoundSurfaceCollector = SurfaceCollector<BoundSurfaceSelector>;
0376   using MaterialVolumeCollector = VolumeCollector<MaterialVolumeSelector>;
0377   using ActionList = ActionList<BoundSurfaceCollector, MaterialVolumeCollector>;
0378   using AbortList = AbortList<EndOfWorldReached>;
0379 
0380   PropagatorOptions<ActionList, AbortList> options(mState.geoContext,
0381                                                    mState.magFieldContext);
0382 
0383   // Now collect the material volume by using the straight line propagator
0384   const auto& result = m_propagator.propagate(start, options).value();
0385   auto mcResult = result.get<BoundSurfaceCollector::result_type>();
0386   auto mvcResult = result.get<MaterialVolumeCollector::result_type>();
0387 
0388   auto mappingSurfaces = mcResult.collected;
0389   auto mappingVolumes = mvcResult.collected;
0390 
0391   // Retrieve the recorded material from the recorded material track
0392   auto& rMaterial = mTrack.second.materialInteractions;
0393   ACTS_VERBOSE("Retrieved " << rMaterial.size()
0394                             << " recorded material steps to map.")
0395 
0396   // These should be mapped onto the mapping surfaces found
0397   ACTS_VERBOSE("Found     " << mappingVolumes.size()
0398                             << " mapping volumes for this track.");
0399   ACTS_VERBOSE("Mapping volumes are :")
0400   for (auto& mVolumes : mappingVolumes) {
0401     ACTS_VERBOSE(" - Volume : " << mVolumes.volume->geometryId()
0402                                 << " at position = (" << mVolumes.position.x()
0403                                 << ", " << mVolumes.position.y() << ", "
0404                                 << mVolumes.position.z() << ")");
0405 
0406     mappingVolumes.push_back(mVolumes);
0407   }
0408   // Run the mapping process, i.e. take the recorded material and map it
0409   // onto the mapping volume:
0410   auto rmIter = rMaterial.begin();
0411   auto sfIter = mappingSurfaces.begin();
0412   auto volIter = mappingVolumes.begin();
0413 
0414   // Use those to minimize the lookup
0415   GeometryIdentifier lastID = GeometryIdentifier();
0416   GeometryIdentifier currentID = GeometryIdentifier();
0417   auto currentBinning = mState.materialBin.end();
0418 
0419   // store end position of the last material slab
0420   Acts::Vector3 lastPositionEnd = {0, 0, 0};
0421   Acts::Vector3 direction = {0, 0, 0};
0422 
0423   if (volIter != mappingVolumes.end()) {
0424     lastPositionEnd = volIter->position;
0425   }
0426 
0427   // loop over all the material hit in the track or until there no more volume
0428   // to map onto
0429   while (rmIter != rMaterial.end() && volIter != mappingVolumes.end()) {
0430     if (volIter != mappingVolumes.end() &&
0431         !volIter->volume->inside(rmIter->position)) {
0432       // Check if the material point is past the entry point to the current
0433       // volume (this prevents switching volume before the first volume has been
0434       // reached)
0435       double distVol = (volIter->position - mTrack.first.first).norm();
0436       double distMat = (rmIter->position - mTrack.first.first).norm();
0437       if (distMat - distVol > s_epsilon) {
0438         // Switch to next material volume
0439         ++volIter;
0440         continue;
0441       }
0442     }
0443     if (volIter != mappingVolumes.end() &&
0444         volIter->volume->inside(rmIter->position, s_epsilon)) {
0445       currentID = volIter->volume->geometryId();
0446       direction = rmIter->direction;
0447       if (!(currentID == lastID)) {
0448         // Let's (re-)assess the information
0449         lastID = currentID;
0450         lastPositionEnd = volIter->position;
0451         currentBinning = mState.materialBin.find(currentID);
0452       }
0453       // If the current volume has a ProtoVolumeMaterial
0454       // and the material hit has a non 0 thickness
0455       if (currentBinning != mState.materialBin.end() &&
0456           rmIter->materialSlab.thickness() > 0) {
0457         // check if there is vacuum between this material point and the last one
0458         float vacuumThickness = (rmIter->position - lastPositionEnd).norm();
0459         if (vacuumThickness > s_epsilon) {
0460           auto properties = Acts::MaterialSlab(vacuumThickness);
0461           // creat vacuum hits
0462           createExtraHits(mState, *currentBinning, properties, lastPositionEnd,
0463                           direction);
0464         }
0465         // determine the position of the last material slab using the track
0466         // direction
0467         direction =
0468             direction * (rmIter->materialSlab.thickness() / direction.norm());
0469         lastPositionEnd = rmIter->position + direction;
0470         // create additional material point
0471         createExtraHits(mState, *currentBinning, rmIter->materialSlab,
0472                         rmIter->position, direction);
0473       }
0474 
0475       // check if we have reached the end of the volume or the last hit of the
0476       // track.
0477       if ((rmIter + 1) == rMaterial.end() ||
0478           !volIter->volume->inside((rmIter + 1)->position, s_epsilon)) {
0479         // find the boundary surface corresponding to the end of the volume
0480         while (sfIter != mappingSurfaces.end()) {
0481           if (sfIter->surface->geometryId().volume() == lastID.volume() ||
0482               ((volIter + 1) != mappingVolumes.end() &&
0483                sfIter->surface->geometryId().volume() ==
0484                    (volIter + 1)->volume->geometryId().volume())) {
0485             double distVol = (volIter->position - mTrack.first.first).norm();
0486             double distSur = (sfIter->position - mTrack.first.first).norm();
0487             if (distSur - distVol > s_epsilon) {
0488               float vacuumThickness =
0489                   (sfIter->position - lastPositionEnd).norm();
0490               // if the last material slab stop before the boundary surface
0491               // create vacuum hits
0492               if (vacuumThickness > s_epsilon) {
0493                 auto properties = Acts::MaterialSlab(vacuumThickness);
0494                 createExtraHits(mState, *currentBinning, properties,
0495                                 lastPositionEnd, direction);
0496                 lastPositionEnd = sfIter->position;
0497               }
0498               break;
0499             }
0500           }
0501           sfIter++;
0502         }
0503       }
0504       rmIter->volume = volIter->volume;
0505       rmIter->intersectionID = currentID;
0506       rmIter->intersection = rmIter->position;
0507     }
0508     ++rmIter;
0509   }
0510 }