Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:23:31

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2024 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 <boost/container/flat_set.hpp>
0010 
0011 template <typename SpacePoint>
0012 Acts::CylindricalSpacePointGrid<SpacePoint>
0013 Acts::CylindricalSpacePointGridCreator::createGrid(
0014     const Acts::CylindricalSpacePointGridConfig& config,
0015     const Acts::CylindricalSpacePointGridOptions& options) {
0016   if (!config.isInInternalUnits) {
0017     throw std::runtime_error(
0018         "CylindricalSpacePointGridConfig not in ACTS internal units in "
0019         "CylindricalSpacePointGridCreator::createGrid");
0020   }
0021   if (!options.isInInternalUnits) {
0022     throw std::runtime_error(
0023         "CylindricalSpacePointGridOptions not in ACTS internal units in "
0024         "CylindricalSpacePointGridCreator::createGrid");
0025   }
0026   using AxisScalar = Acts::Vector3::Scalar;
0027   using namespace Acts::UnitLiterals;
0028 
0029   int phiBins = 0;
0030   // for no magnetic field, create 100 phi-bins
0031   if (options.bFieldInZ == 0) {
0032     phiBins = 100;
0033   } else {
0034     // calculate circle intersections of helix and max detector radius
0035     float minHelixRadius =
0036         config.minPt /
0037         (1_T * 1e6 *
0038          options.bFieldInZ);  // in mm -> R[mm] =pT[GeV] / (3·10−4×B[T])
0039                               // = pT[MeV] / (300 *Bz[kT])
0040 
0041     // sanity check: if yOuter takes the square root of a negative number
0042     if (minHelixRadius < config.rMax / 2) {
0043       throw std::domain_error(
0044           "The value of minHelixRadius cannot be smaller than rMax / 2. Please "
0045           "check the configuration of bFieldInZ and minPt");
0046     }
0047 
0048     float maxR2 = config.rMax * config.rMax;
0049     float xOuter = maxR2 / (2 * minHelixRadius);
0050     float yOuter = std::sqrt(maxR2 - xOuter * xOuter);
0051     float outerAngle = std::atan(xOuter / yOuter);
0052     // intersection of helix and max detector radius minus maximum R distance
0053     // from middle SP to top SP
0054     float innerAngle = 0;
0055     float rMin = config.rMax;
0056     if (config.rMax > config.deltaRMax) {
0057       rMin = config.rMax - config.deltaRMax;
0058       float innerCircleR2 =
0059           (config.rMax - config.deltaRMax) * (config.rMax - config.deltaRMax);
0060       float xInner = innerCircleR2 / (2 * minHelixRadius);
0061       float yInner = std::sqrt(innerCircleR2 - xInner * xInner);
0062       innerAngle = std::atan(xInner / yInner);
0063     }
0064 
0065     // evaluating the azimutal deflection including the maximum impact parameter
0066     float deltaAngleWithMaxD0 =
0067         std::abs(std::asin(config.impactMax / (rMin)) -
0068                  std::asin(config.impactMax / config.rMax));
0069 
0070     // evaluating delta Phi based on the inner and outer angle, and the azimutal
0071     // deflection including the maximum impact parameter
0072     // Divide by config.phiBinDeflectionCoverage since we combine
0073     // config.phiBinDeflectionCoverage number of consecutive phi bins in the
0074     // seed making step. So each individual bin should cover
0075     // 1/config.phiBinDeflectionCoverage of the maximum expected azimutal
0076     // deflection
0077     float deltaPhi = (outerAngle - innerAngle + deltaAngleWithMaxD0) /
0078                      config.phiBinDeflectionCoverage;
0079 
0080     // sanity check: if the delta phi is equal to or less than zero, we'll be
0081     // creating an infinite or a negative number of bins, which would be bad!
0082     if (deltaPhi <= 0.f) {
0083       throw std::domain_error(
0084           "Delta phi value is equal to or less than zero, leading to an "
0085           "impossible number of bins (negative or infinite)");
0086     }
0087 
0088     // divide 2pi by angle delta to get number of phi-bins
0089     // size is always 2pi even for regions of interest
0090     phiBins = static_cast<int>(std::ceil(2 * M_PI / deltaPhi));
0091     // need to scale the number of phi bins accordingly to the number of
0092     // consecutive phi bins in the seed making step.
0093     // Each individual bin should be approximately a fraction (depending on this
0094     // number) of the maximum expected azimutal deflection.
0095 
0096     // set protection for large number of bins, by default it is large
0097     if (phiBins > config.maxPhiBins) {
0098       phiBins = config.maxPhiBins;
0099     }
0100   }
0101 
0102   Acts::detail::Axis<detail::AxisType::Equidistant,
0103                      detail::AxisBoundaryType::Closed>
0104       phiAxis(config.phiMin, config.phiMax, phiBins);
0105 
0106   // vector that will store the edges of the bins of z
0107   std::vector<AxisScalar> zValues;
0108 
0109   // If zBinEdges is not defined, calculate the edges as zMin + bin * zBinSize
0110   if (config.zBinEdges.empty()) {
0111     // TODO: can probably be optimized using smaller z bins
0112     // and returning (multiple) neighbors only in one z-direction for forward
0113     // seeds
0114     // FIXME: zBinSize must include scattering
0115     float zBinSize = config.cotThetaMax * config.deltaRMax;
0116     float zBins =
0117         std::max(1.f, std::floor((config.zMax - config.zMin) / zBinSize));
0118 
0119     zValues.reserve(static_cast<int>(zBins));
0120     for (int bin = 0; bin <= static_cast<int>(zBins); bin++) {
0121       AxisScalar edge =
0122           config.zMin + bin * ((config.zMax - config.zMin) / zBins);
0123       zValues.push_back(edge);
0124     }
0125 
0126   } else {
0127     // Use the zBinEdges defined in the config
0128     zValues.reserve(config.zBinEdges.size());
0129     for (float bin : config.zBinEdges) {
0130       zValues.push_back(bin);
0131     }
0132   }
0133 
0134   detail::Axis<detail::AxisType::Variable, detail::AxisBoundaryType::Bound>
0135       zAxis(std::move(zValues));
0136   return Acts::CylindricalSpacePointGrid<SpacePoint>(
0137       std::make_tuple(std::move(phiAxis), std::move(zAxis)));
0138 }
0139 
0140 template <typename external_spacepoint_t,
0141           typename external_spacepoint_iterator_t, typename callable_t>
0142 void Acts::CylindricalSpacePointGridCreator::fillGrid(
0143     const Acts::SeedFinderConfig<external_spacepoint_t>& config,
0144     const Acts::SeedFinderOptions& options,
0145     Acts::CylindricalSpacePointGrid<external_spacepoint_t>& grid,
0146     external_spacepoint_iterator_t spBegin,
0147     external_spacepoint_iterator_t spEnd, callable_t&& toGlobal,
0148     Acts::Extent& rRangeSPExtent) {
0149   using iterated_value_t =
0150       typename std::iterator_traits<external_spacepoint_iterator_t>::value_type;
0151   using iterated_t = typename std::remove_const<
0152       typename std::remove_pointer<iterated_value_t>::type>::type;
0153   static_assert(std::is_pointer<iterated_value_t>::value,
0154                 "Iterator must contain pointers to space points");
0155   static_assert(std::is_same<iterated_t, external_spacepoint_t>::value,
0156                 "Iterator does not contain type this class was templated with");
0157 
0158   if (!config.isInInternalUnits) {
0159     throw std::runtime_error(
0160         "SeedFinderConfig not in ACTS internal units in BinnedSPGroup");
0161   }
0162   if (config.seedFilter == nullptr) {
0163     throw std::runtime_error("SeedFinderConfig has a null SeedFilter object");
0164   }
0165   if (!options.isInInternalUnits) {
0166     throw std::runtime_error(
0167         "SeedFinderOptions not in ACTS internal units in BinnedSPGroup");
0168   }
0169 
0170   // get region of interest (or full detector if configured accordingly)
0171   float phiMin = config.phiMin;
0172   float phiMax = config.phiMax;
0173   float zMin = config.zMin;
0174   float zMax = config.zMax;
0175 
0176   // sort by radius
0177   // add magnitude of beamPos to rMax to avoid excluding measurements
0178   // create number of bins equal to number of millimeters rMax
0179   // (worst case minR: configured minR + 1mm)
0180   // binSizeR allows to increase or reduce numRBins if needed
0181   std::size_t numRBins = static_cast<std::size_t>(
0182       (config.rMax + options.beamPos.norm()) / config.binSizeR);
0183 
0184   // keep track of changed bins while sorting
0185   boost::container::flat_set<std::size_t> rBinsIndex;
0186 
0187   std::size_t counter = 0ul;
0188   for (external_spacepoint_iterator_t it = spBegin; it != spEnd;
0189        it++, ++counter) {
0190     if (*it == nullptr) {
0191       continue;
0192     }
0193     const external_spacepoint_t& sp = **it;
0194     const auto& [spPosition, variance, spTime] =
0195         toGlobal(sp, config.zAlign, config.rAlign, config.sigmaError);
0196 
0197     float spX = spPosition[0];
0198     float spY = spPosition[1];
0199     float spZ = spPosition[2];
0200 
0201     // store x,y,z values in extent
0202     rRangeSPExtent.extend({spX, spY, spZ});
0203 
0204     // remove SPs outside z and phi region
0205     if (spZ > zMax || spZ < zMin) {
0206       continue;
0207     }
0208     float spPhi = std::atan2(spY, spX);
0209     if (spPhi > phiMax || spPhi < phiMin) {
0210       continue;
0211     }
0212 
0213     auto isp = std::make_unique<InternalSpacePoint<external_spacepoint_t>>(
0214         counter, sp, spPosition, options.beamPos, variance, spTime);
0215     // calculate r-Bin index and protect against overflow (underflow not
0216     // possible)
0217     std::size_t rIndex =
0218         static_cast<std::size_t>(isp->radius() / config.binSizeR);
0219     // if index out of bounds, the SP is outside the region of interest
0220     if (rIndex >= numRBins) {
0221       continue;
0222     }
0223 
0224     // fill rbins into grid
0225     Acts::Vector2 spLocation(isp->phi(), isp->z());
0226     std::vector<std::unique_ptr<InternalSpacePoint<external_spacepoint_t>>>&
0227         rbin = grid.atPosition(spLocation);
0228     rbin.push_back(std::move(isp));
0229 
0230     // keep track of the bins we modify so that we can later sort the SPs in
0231     // those bins only
0232     if (rbin.size() > 1) {
0233       rBinsIndex.insert(grid.globalBinFromPosition(spLocation));
0234     }
0235   }
0236 
0237   /// sort SPs in R for each filled bin
0238   for (auto& binIndex : rBinsIndex) {
0239     auto& rbin = grid.atPosition(binIndex);
0240     std::sort(rbin.begin(), rbin.end(), [](const auto& a, const auto& b) {
0241       return a->radius() < b->radius();
0242     });
0243   }
0244 }