File indexing completed on 2026-09-13 08:20:52
0001
0002
0003
0004
0005
0006
0007
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
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
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
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
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
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
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 }
0115 }
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
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
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
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
0273 outfile.exceptions(std::ofstream::failbit | std::ofstream::badbit);
0274 outfile << DigiConfigConverter("digitization-configuration")
0275 .toJson(cfg, nullptr)
0276 .dump(2);
0277 }