Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-13 08:20:52

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 "ActsExamples/Io/Json/JsonDigitizationConfig.hpp"
0010 
0011 #include "Acts/Definitions/TrackParametrization.hpp"
0012 #include "Acts/Utilities/AxisDefinitions.hpp"
0013 #include "Acts/Utilities/BinUtility.hpp"
0014 #include "Acts/Utilities/BinningData.hpp"
0015 #include "Acts/Utilities/IAxis.hpp"
0016 #include "Acts/Utilities/IMultiAxis.hpp"
0017 #include "ActsExamples/Digitization/Smearers.hpp"
0018 #include "ActsExamples/Framework/RandomNumbers.hpp"
0019 #include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp"
0020 #include "ActsPlugins/Json/UtilitiesJsonConverter.hpp"
0021 
0022 #include <cstddef>
0023 #include <fstream>
0024 #include <memory>
0025 #include <stdexcept>
0026 #include <utility>
0027 #include <vector>
0028 
0029 namespace ActsExamples {
0030 namespace {
0031 void to_json(nlohmann::json& j,
0032              const ActsFatras::SingleParameterSmearFunction<RandomEngine>& f) {
0033   // Gauss:
0034   auto gauss = f.target<const Digitization::Gauss>();
0035   if (gauss != nullptr) {
0036     j["type"] = "Gauss";
0037     j["mean"] = 0;
0038     j["stddev"] = gauss->sigma;
0039     return;
0040   }
0041   // Truncated gauss:
0042   auto gaussT = f.target<const Digitization::GaussTrunc>();
0043   if (gaussT != nullptr) {
0044     j["type"] = "GaussTrunc";
0045     j["mean"] = 0;
0046     j["stddev"] = gaussT->sigma;
0047     j["range"] = gaussT->range;
0048     return;
0049   }
0050   // Clipped gauss:
0051   auto gaussC = f.target<const Digitization::GaussClipped>();
0052   if (gaussC != nullptr) {
0053     j["type"] = "GaussClipped";
0054     j["mean"] = 0;
0055     j["stddev"] = gaussC->sigma;
0056     j["range"] = gaussC->range;
0057     j["max_attempts"] = gaussC->maxAttemps;
0058     return;
0059   }
0060   // Uniform
0061   auto uniform = f.target<const Digitization::Uniform>();
0062   if (uniform != nullptr) {
0063     j["type"] = "Uniform";
0064     j["bindata"] = nlohmann::json(uniform->binningData);
0065     return;
0066   }
0067   // Digital
0068   auto digital = f.target<const Digitization::Digital>();
0069   if (digital != nullptr) {
0070     j["type"] = "Digital";
0071     j["bindata"] = nlohmann::json(digital->binningData);
0072     return;
0073   }
0074   // Exact
0075   auto exact = f.target<const Digitization::Exact>();
0076   if (exact != nullptr) {
0077     j["type"] = "Exact";
0078     j["stddev"] = exact->sigma;
0079     return;
0080   }
0081 
0082   throw std::runtime_error("Unable to serialize smearer");
0083 }
0084 
0085 void from_json(const nlohmann::json& j,
0086                ActsFatras::SingleParameterSmearFunction<RandomEngine>& f) {
0087   std::string sType = j["type"];
0088 
0089   if (sType == "Gauss") {
0090     f = Digitization::Gauss(j["stddev"]);
0091   } else if (sType == "GaussTrunc") {
0092     double sigma = j["stddev"];
0093     std::pair<double, double> range = j["range"];
0094     f = Digitization::GaussTrunc(sigma, range);
0095   } else if (sType == "GaussClipped") {
0096     double sigma = j["stddev"];
0097     std::pair<double, double> range = j["range"];
0098     f = Digitization::GaussClipped(sigma, range);
0099   } else if (sType == "Uniform") {
0100     Acts::BinningData bd;
0101     from_json(j["bindata"], bd);
0102     f = Digitization::Uniform(bd);
0103   } else if (sType == "Digital") {
0104     Acts::BinningData bd;
0105     from_json(j["bindata"], bd);
0106     f = Digitization::Digital(bd);
0107   } else if (sType == "Exact") {
0108     f = Digitization::Exact(j["stddev"]);
0109   } else {
0110     throw std::invalid_argument("Unknown smearer type '" + sType + "'");
0111   }
0112 }
0113 
0114 }  // namespace
0115 }  // namespace ActsExamples
0116 
0117 void ActsExamples::to_json(nlohmann::json& j,
0118                            const ParameterSmearingConfig& psc) {
0119   j["index"] = psc.index;
0120   j["forcePositiveValues"] = psc.forcePositiveValues;
0121   to_json(j, psc.smearFunction);
0122 }
0123 
0124 void ActsExamples::from_json(const nlohmann::json& j,
0125                              ParameterSmearingConfig& psc) {
0126   psc.index = static_cast<Acts::BoundIndices>(j["index"]);
0127   if (j.find("forcePositiveValues") != j.end()) {
0128     psc.forcePositiveValues = j["forcePositiveValues"];
0129   }
0130   from_json(j, psc.smearFunction);
0131 }
0132 
0133 void ActsExamples::to_json(nlohmann::json& j, const GeometricConfig& gdc) {
0134   std::vector<std::size_t> indices;
0135   for (const auto& idx : gdc.indices) {
0136     indices.push_back(static_cast<std::size_t>(idx));
0137   }
0138   j["indices"] = indices;
0139   Acts::BinUtility segmentation;
0140   if (gdc.segmentation != nullptr) {
0141     for (const Acts::IAxis& axis : *gdc.segmentation) {
0142       const Acts::AxisDirection axisDir = axis.getDirection().value();
0143       const Acts::BinningOption bOption =
0144           axis.getBoundaryType() == Acts::AxisBoundaryType::Closed
0145               ? Acts::closed
0146               : Acts::open;
0147       if (axis.isEquidistant()) {
0148         segmentation += Acts::BinUtility(axis.getNBins(), axis.getMin(),
0149                                          axis.getMax(), bOption, axisDir);
0150       } else {
0151         const std::vector<double> edges = axis.getBinEdges();
0152         std::vector<float> floatEdges(edges.begin(), edges.end());
0153         segmentation += Acts::BinUtility(floatEdges, bOption, axisDir);
0154       }
0155     }
0156   }
0157   j["segmentation"] = segmentation;
0158   j["thickness"] = gdc.thickness;
0159   j["threshold"] = gdc.threshold;
0160   j["digital"] = gdc.digital;
0161   if (j.find("charge-smearing") != j.end()) {
0162     to_json(j["charge-smearing"], gdc.chargeSmearer);
0163   }
0164 }
0165 
0166 void ActsExamples::from_json(const nlohmann::json& j, GeometricConfig& gdc) {
0167   for (const auto& jidx : j["indices"]) {
0168     gdc.indices.push_back(static_cast<Acts::BoundIndices>(jidx));
0169   }
0170   Acts::BinUtility segmentation;
0171   from_json(j["segmentation"], segmentation);
0172   std::vector<std::unique_ptr<Acts::IAxis>> axes;
0173   for (const Acts::BinningData& binData : segmentation.binningData()) {
0174     const Acts::AxisDirection axisDir = binData.binvalue;
0175     const Acts::AxisType axisType = binData.type == Acts::equidistant
0176                                         ? Acts::AxisType::Equidistant
0177                                         : Acts::AxisType::Variable;
0178     const Acts::AxisBoundaryType abType = binData.option == Acts::open
0179                                               ? Acts::AxisBoundaryType::Bound
0180                                               : Acts::AxisBoundaryType::Closed;
0181     if (axisType == Acts::AxisType::Equidistant) {
0182       axes.push_back(Acts::IAxis::createEquidistant(
0183           abType, binData.min, binData.max, binData.bins(), axisDir));
0184     } else {
0185       const std::vector<double> edges(binData.boundaries().begin(),
0186                                       binData.boundaries().end());
0187       axes.push_back(Acts::IAxis::createVariable(abType, edges, axisDir));
0188     }
0189   }
0190   if (axes.size() == 1) {
0191     gdc.segmentation = Acts::IMultiAxis::create(*axes[0]);
0192   } else if (axes.size() == 2) {
0193     gdc.segmentation = Acts::IMultiAxis::create(*axes[0], *axes[1]);
0194   } else if (!axes.empty()) {
0195     throw std::invalid_argument(
0196         "GeometricConfig: only 1D and 2D segmentations are supported");
0197   }
0198   gdc.thickness = j["thickness"];
0199   gdc.threshold = j["threshold"];
0200   gdc.digital = j["digital"];
0201   if (j.find("variances") != j.end()) {
0202     /// Read the variances from the json file
0203     auto jvariances = j["variances"];
0204     for (const auto& jvar : jvariances) {
0205       auto idx =
0206           static_cast<Acts::BoundIndices>(jvar["index"].get<std::size_t>());
0207       auto rms = jvar["rms"].get<std::vector<double>>();
0208       auto vars = rms;
0209       // Square the RMS values to get the variances
0210       std::transform(vars.begin(), vars.end(), vars.begin(),
0211                      [](double val) { return val * val; });
0212       gdc.varianceMap[idx] = vars;
0213     }
0214   }
0215   if (j.find("charge-smearing") != j.end()) {
0216     from_json(j["charge-smearing"], gdc.chargeSmearer);
0217   }
0218 }
0219 
0220 void ActsExamples::to_json(nlohmann::json& j, const SmearingConfig& sdc) {
0221   for (const auto& sc : sdc.params) {
0222     j.push_back(nlohmann::json(sc));
0223   }
0224 }
0225 
0226 void ActsExamples::from_json(const nlohmann::json& j, SmearingConfig& sdc) {
0227   for (const auto& jpsc : j) {
0228     ParameterSmearingConfig psc;
0229     from_json(jpsc, psc);
0230     sdc.params.push_back(psc);
0231   }
0232 }
0233 
0234 void ActsExamples::to_json(nlohmann::json& j, const DigiComponentsConfig& dc) {
0235   if (!dc.geometricDigiConfig.indices.empty()) {
0236     j["geometric"] = nlohmann::json(dc.geometricDigiConfig);
0237   }
0238   if (!dc.smearingDigiConfig.params.empty()) {
0239     j["smearing"] = nlohmann::json(dc.smearingDigiConfig);
0240   }
0241 }
0242 
0243 void ActsExamples::from_json(const nlohmann::json& j,
0244                              DigiComponentsConfig& dc) {
0245   if (j.find("geometric") != j.end()) {
0246     nlohmann::json jgdc = j["geometric"];
0247     from_json(jgdc, dc.geometricDigiConfig);
0248   }
0249   if (j.find("smearing") != j.end()) {
0250     nlohmann::json jsdc = j["smearing"];
0251     from_json(jsdc, dc.smearingDigiConfig);
0252   }
0253 }
0254 
0255 Acts::GeometryHierarchyMap<ActsExamples::DigiComponentsConfig>
0256 ActsExamples::readDigiConfigFromJson(const std::string& path) {
0257   nlohmann::json djson;
0258   if (path.empty()) {
0259     return Acts::GeometryHierarchyMap<DigiComponentsConfig>();
0260   }
0261   std::ifstream infile(path, std::ifstream::in | std::ifstream::binary);
0262   // rely on exception for error handling
0263   infile.exceptions(std::ofstream::failbit | std::ofstream::badbit);
0264   infile >> djson;
0265   return DigiConfigConverter("digitization-configuration").fromJson(djson);
0266 }
0267 
0268 void ActsExamples::writeDigiConfigToJson(
0269     const Acts::GeometryHierarchyMap<DigiComponentsConfig>& cfg,
0270     const std::string& path) {
0271   std::ofstream outfile(path, std::ofstream::out | std::ofstream::binary);
0272   // rely on exception for error handling
0273   outfile.exceptions(std::ofstream::failbit | std::ofstream::badbit);
0274   outfile << DigiConfigConverter("digitization-configuration")
0275                  .toJson(cfg, nullptr)
0276                  .dump(2);
0277 }