Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:10:59

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
0008 
0009 #include <concepts>
0010 #include <numbers>
0011 
0012 template <typename external_spacepoint_t>
0013 Acts::CylindricalSpacePointGrid<external_spacepoint_t>
0014 Acts::CylindricalSpacePointGridCreator::createGrid(
0015     const Acts::CylindricalSpacePointGridConfig& config,
0016     const Acts::CylindricalSpacePointGridOptions& options,
0017     const Acts::Logger& logger) {
0018   if (!config.isInInternalUnits) {
0019     throw std::runtime_error(
0020         "CylindricalSpacePointGridConfig not in ACTS internal units in "
0021         "CylindricalSpacePointGridCreator::createGrid");
0022   }
0023   if (!options.isInInternalUnits) {
0024     throw std::runtime_error(
0025         "CylindricalSpacePointGridOptions not in ACTS internal units in "
0026         "CylindricalSpacePointGridCreator::createGrid");
0027   }
0028   using AxisScalar = Acts::Vector3::Scalar;
0029   using namespace Acts::UnitLiterals;
0030 
0031   int phiBins = 0;
0032   // for no magnetic field, create 100 phi-bins
0033   if (options.bFieldInZ == 0) {
0034     phiBins = 100;
0035     ACTS_VERBOSE(
0036         "B-Field is 0 (z-coordinate), setting the number of bins in phi to "
0037         << phiBins);
0038   } else {
0039     // calculate circle intersections of helix and max detector radius
0040     float minHelixRadius =
0041         config.minPt /
0042         (1_T * 1e6 *
0043          options.bFieldInZ);  // in mm -> R[mm] =pT[GeV] / (3·10−4×B[T])
0044                               // = pT[MeV] / (300 *Bz[kT])
0045 
0046     // sanity check: if yOuter takes the square root of a negative number
0047     if (minHelixRadius < config.rMax * 0.5) {
0048       throw std::domain_error(
0049           "The value of minHelixRadius cannot be smaller than rMax / 2. Please "
0050           "check the configuration of bFieldInZ and minPt");
0051     }
0052 
0053     float maxR2 = config.rMax * config.rMax;
0054     float xOuter = maxR2 / (2 * minHelixRadius);
0055     float yOuter = std::sqrt(maxR2 - xOuter * xOuter);
0056     float outerAngle = std::atan(xOuter / yOuter);
0057     // intersection of helix and max detector radius minus maximum R distance
0058     // from middle SP to top SP
0059     float innerAngle = 0;
0060     float rMin = config.rMax;
0061     if (config.rMax > config.deltaRMax) {
0062       rMin = config.rMax - config.deltaRMax;
0063       float innerCircleR2 =
0064           (config.rMax - config.deltaRMax) * (config.rMax - config.deltaRMax);
0065       float xInner = innerCircleR2 / (2 * minHelixRadius);
0066       float yInner = std::sqrt(innerCircleR2 - xInner * xInner);
0067       innerAngle = std::atan(xInner / yInner);
0068     }
0069 
0070     // evaluating the azimutal deflection including the maximum impact parameter
0071     float deltaAngleWithMaxD0 =
0072         std::abs(std::asin(config.impactMax / (rMin)) -
0073                  std::asin(config.impactMax / config.rMax));
0074 
0075     // evaluating delta Phi based on the inner and outer angle, and the azimutal
0076     // deflection including the maximum impact parameter
0077     // Divide by config.phiBinDeflectionCoverage since we combine
0078     // config.phiBinDeflectionCoverage number of consecutive phi bins in the
0079     // seed making step. So each individual bin should cover
0080     // 1/config.phiBinDeflectionCoverage of the maximum expected azimutal
0081     // deflection
0082     float deltaPhi = (outerAngle - innerAngle + deltaAngleWithMaxD0) /
0083                      config.phiBinDeflectionCoverage;
0084 
0085     // sanity check: if the delta phi is equal to or less than zero, we'll be
0086     // creating an infinite or a negative number of bins, which would be bad!
0087     if (deltaPhi <= 0.f) {
0088       throw std::domain_error(
0089           "Delta phi value is equal to or less than zero, leading to an "
0090           "impossible number of bins (negative or infinite)");
0091     }
0092 
0093     // divide 2pi by angle delta to get number of phi-bins
0094     // size is always 2pi even for regions of interest
0095     phiBins = static_cast<int>(std::ceil(2 * std::numbers::pi / deltaPhi));
0096     // need to scale the number of phi bins accordingly to the number of
0097     // consecutive phi bins in the seed making step.
0098     // Each individual bin should be approximately a fraction (depending on this
0099     // number) of the maximum expected azimutal deflection.
0100 
0101     // set protection for large number of bins, by default it is large
0102     phiBins = std::min(phiBins, config.maxPhiBins);
0103   }
0104 
0105   Acts::Axis<AxisType::Equidistant, AxisBoundaryType::Closed> phiAxis(
0106       config.phiMin, config.phiMax, phiBins);
0107 
0108   // vector that will store the edges of the bins of z
0109   std::vector<AxisScalar> zValues{};
0110 
0111   // If zBinEdges is not defined, calculate the edges as zMin + bin * zBinSize
0112   if (config.zBinEdges.empty()) {
0113     // TODO: can probably be optimized using smaller z bins
0114     // and returning (multiple) neighbors only in one z-direction for forward
0115     // seeds
0116     // FIXME: zBinSize must include scattering
0117     float zBinSize = config.cotThetaMax * config.deltaRMax;
0118     float zBins =
0119         std::max(1.f, std::floor((config.zMax - config.zMin) / zBinSize));
0120 
0121     zValues.reserve(static_cast<int>(zBins));
0122     for (int bin = 0; bin <= static_cast<int>(zBins); bin++) {
0123       AxisScalar edge =
0124           config.zMin + bin * ((config.zMax - config.zMin) / zBins);
0125       zValues.push_back(edge);
0126     }
0127 
0128   } else {
0129     // Use the zBinEdges defined in the config
0130     zValues.reserve(config.zBinEdges.size());
0131     for (float bin : config.zBinEdges) {
0132       zValues.push_back(bin);
0133     }
0134   }
0135 
0136   std::vector<AxisScalar> rValues{};
0137   rValues.reserve(std::max(2ul, config.rBinEdges.size()));
0138   if (config.rBinEdges.empty()) {
0139     rValues = {config.rMin, config.rMax};
0140   } else {
0141     rValues.insert(rValues.end(), config.rBinEdges.begin(),
0142                    config.rBinEdges.end());
0143   }
0144 
0145   Axis<AxisType::Variable, AxisBoundaryType::Open> zAxis(std::move(zValues));
0146   Axis<AxisType::Variable, AxisBoundaryType::Open> rAxis(std::move(rValues));
0147 
0148   ACTS_VERBOSE("Defining Grid:");
0149   ACTS_VERBOSE("- Phi Axis: " << phiAxis);
0150   ACTS_VERBOSE("- Z axis  : " << zAxis);
0151   ACTS_VERBOSE("- R axis  : " << rAxis);
0152 
0153   return Acts::CylindricalSpacePointGrid<external_spacepoint_t>(
0154       std::make_tuple(std::move(phiAxis), std::move(zAxis), std::move(rAxis)));
0155 }
0156 
0157 template <typename external_spacepoint_t,
0158           typename external_spacepoint_iterator_t>
0159 void Acts::CylindricalSpacePointGridCreator::fillGrid(
0160     const Acts::SeedFinderConfig<external_spacepoint_t>& config,
0161     const Acts::SeedFinderOptions& options,
0162     Acts::CylindricalSpacePointGrid<external_spacepoint_t>& grid,
0163     external_spacepoint_iterator_t spBegin,
0164     external_spacepoint_iterator_t spEnd, const Acts::Logger& logger) {
0165   if (!config.isInInternalUnits) {
0166     throw std::runtime_error(
0167         "SeedFinderConfig not in ACTS internal units in BinnedSPGroup");
0168   }
0169   if (config.seedFilter == nullptr) {
0170     throw std::runtime_error("SeedFinderConfig has a null SeedFilter object");
0171   }
0172   if (!options.isInInternalUnits) {
0173     throw std::runtime_error(
0174         "SeedFinderOptions not in ACTS internal units in BinnedSPGroup");
0175   }
0176 
0177   // Space points are assumed to be ALREADY CORRECTED for beamspot position
0178   // phi, z and r space point selection comes naturally from the
0179   // grid axis definition. Calling `isInside` will let us know if we are
0180   // inside the grid range.
0181   // If a space point is outside the validity range of these quantities
0182   // it goes in an over- or under-flow bin. We want to avoid to consider those
0183   // and skip some computations.
0184   // Additional cuts can be applied by customizing the space point selector
0185   // in the config object.
0186 
0187   // keep track of changed bins while sorting
0188   std::vector<bool> usedBinIndex(grid.size(), false);
0189   std::vector<std::size_t> rBinsIndex;
0190   rBinsIndex.reserve(grid.size());
0191 
0192   ACTS_VERBOSE("Fetching " << std::distance(spBegin, spEnd)
0193                            << " space points to the grid");
0194   std::size_t counter = 0ul;
0195   for (external_spacepoint_iterator_t it = spBegin; it != spEnd; ++it) {
0196     const external_spacepoint_t& sp = *it;
0197 
0198     // remove SPs according to experiment specific cuts
0199     if (!config.spacePointSelector(sp)) {
0200       continue;
0201     }
0202 
0203     // fill rbins into grid
0204     Acts::Vector3 position(sp.phi(), sp.z(), sp.radius());
0205     if (!grid.isInside(position)) {
0206       continue;
0207     }
0208 
0209     std::size_t globIndex = grid.globalBinFromPosition(position);
0210     auto& rbin = grid.at(globIndex);
0211     rbin.push_back(&sp);
0212     ++counter;
0213 
0214     // keep track of the bins we modify so that we can later sort the SPs in
0215     // those bins only
0216     if (rbin.size() > 1 && !usedBinIndex[globIndex]) {
0217       usedBinIndex[globIndex] = true;
0218       rBinsIndex.push_back(globIndex);
0219     }
0220   }
0221 
0222   /// sort SPs in R for each filled bin
0223   for (std::size_t binIndex : rBinsIndex) {
0224     auto& rbin = grid.atPosition(binIndex);
0225     std::ranges::sort(rbin, {}, [](const auto& rb) { return rb->radius(); });
0226   }
0227 
0228   ACTS_VERBOSE(
0229       "Number of space points inserted (within grid range): " << counter);
0230 }
0231 
0232 template <typename external_spacepoint_t, typename external_collection_t>
0233   requires std::ranges::range<external_collection_t> &&
0234            std::same_as<typename external_collection_t::value_type,
0235                         external_spacepoint_t>
0236 void Acts::CylindricalSpacePointGridCreator::fillGrid(
0237     const Acts::SeedFinderConfig<external_spacepoint_t>& config,
0238     const Acts::SeedFinderOptions& options,
0239     Acts::CylindricalSpacePointGrid<external_spacepoint_t>& grid,
0240     const external_collection_t& collection, const Acts::Logger& logger) {
0241   Acts::CylindricalSpacePointGridCreator::fillGrid<external_spacepoint_t>(
0242       config, options, grid, std::ranges::begin(collection),
0243       std::ranges::end(collection), logger);
0244 }