File indexing completed on 2025-08-05 08:10:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootBFieldWriter.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/MagneticField/InterpolatedBFieldMap.hpp"
0014 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0015 #include "Acts/Utilities/VectorHelpers.hpp"
0016
0017 #include <cassert>
0018 #include <ios>
0019 #include <sstream>
0020 #include <stdexcept>
0021 #include <utility>
0022 #include <vector>
0023
0024 #include <TFile.h>
0025 #include <TTree.h>
0026
0027 namespace ActsExamples {
0028
0029
0030 void RootBFieldWriter::run(const Config& config,
0031 std::unique_ptr<const Acts::Logger> p_logger) {
0032
0033
0034
0035 using namespace Acts;
0036 ACTS_LOCAL_LOGGER(std::move(p_logger))
0037
0038 Acts::MagneticFieldContext bFieldContext;
0039
0040
0041 if (config.treeName.empty()) {
0042 throw std::invalid_argument("Missing tree name");
0043 } else if (config.fileName.empty()) {
0044 throw std::invalid_argument("Missing file name");
0045 } else if (config.bField == nullptr) {
0046 throw std::invalid_argument("Missing interpolated magnetic field");
0047 }
0048
0049
0050 ACTS_INFO("Registering new ROOT output File : " << config.fileName);
0051 TFile* outputFile =
0052 TFile::Open(config.fileName.c_str(), config.fileMode.c_str());
0053 if (outputFile == nullptr) {
0054 throw std::ios_base::failure("Could not open '" + config.fileName + "'");
0055 }
0056 TTree* outputTree = new TTree(config.treeName.c_str(),
0057 config.treeName.c_str(), 99, outputFile);
0058 if (outputTree == nullptr) {
0059 throw std::bad_alloc();
0060 }
0061
0062
0063 auto minima = config.bField->getMin();
0064 auto maxima = config.bField->getMax();
0065 auto nBins = config.bField->getNBins();
0066
0067 if (logger().doPrint(Acts::Logging::VERBOSE)) {
0068 std::stringstream ss;
0069 ss << "Minimum:";
0070 for (auto m : minima) {
0071 ss << " " << m;
0072 }
0073 ACTS_VERBOSE(ss.str());
0074 ss.str("");
0075 ss << "Maximum:";
0076 for (auto m : maxima) {
0077 ss << " " << m;
0078 }
0079 ACTS_VERBOSE(ss.str());
0080 ss.str("");
0081 ss << "nBins:";
0082 for (auto m : nBins) {
0083 ss << " " << m;
0084 }
0085 ACTS_VERBOSE(ss.str());
0086 }
0087
0088 if (config.gridType == GridType::xyz) {
0089 ACTS_INFO("Map will be written out in cartesian coordinates (x,y,z).");
0090
0091
0092 double minX = 0., minY = 0., minZ = 0.;
0093 double maxX = 0., maxY = 0., maxZ = 0.;
0094 std::size_t nBinsX = 0, nBinsY = 0, nBinsZ = 0;
0095
0096
0097 double x = 0;
0098 outputTree->Branch("x", &x);
0099 double y = 0;
0100 outputTree->Branch("y", &y);
0101 double z = 0;
0102 outputTree->Branch("z", &z);
0103
0104
0105 double Bx = 0;
0106 outputTree->Branch("Bx", &Bx);
0107 double By = 0;
0108 outputTree->Branch("By", &By);
0109 double Bz = 0;
0110 outputTree->Branch("Bz", &Bz);
0111
0112
0113 if (config.rBounds && config.zBounds) {
0114 ACTS_INFO("User defined ranges handed over.");
0115
0116
0117 minX = config.rBounds->at(0);
0118 minY = config.rBounds->at(0);
0119 minZ = config.zBounds->at(0);
0120
0121 maxX = config.rBounds->at(1);
0122 maxY = config.rBounds->at(1);
0123 maxZ = config.zBounds->at(1);
0124
0125 nBinsX = config.rBins;
0126 nBinsY = config.rBins;
0127 nBinsZ = config.zBins;
0128
0129 } else {
0130 ACTS_INFO("No user defined ranges handed over - write out whole map.");
0131
0132
0133
0134 if (minima.size() == 3 && maxima.size() == 3) {
0135 minX = minima.at(0);
0136 minY = minima.at(1);
0137 minZ = minima.at(2);
0138
0139 maxX = maxima.at(0);
0140 maxY = maxima.at(1);
0141 maxZ = maxima.at(2);
0142
0143 nBinsX = nBins.at(0);
0144 nBinsY = nBins.at(1);
0145 nBinsZ = nBins.at(2);
0146
0147 } else if (minima.size() == 2 && maxima.size() == 2) {
0148 minX = -maxima.at(0);
0149 minY = -maxima.at(0);
0150 minZ = minima.at(1);
0151
0152 maxX = maxima.at(0);
0153 maxY = maxima.at(0);
0154 maxZ = maxima.at(1);
0155
0156 nBinsX = nBins.at(0);
0157 nBinsY = nBins.at(0);
0158 nBinsZ = nBins.at(1);
0159 } else {
0160 throw std::invalid_argument(
0161 "BField has wrong dimension. The dimension needs to be "
0162 "either 2 (r,z,Br,Bz) or 3(x,y,z,Bx,By,Bz) in order to be "
0163 "written out by this writer.");
0164 }
0165 }
0166
0167 assert(maxX > minX);
0168 assert(maxY > minY);
0169 assert(maxZ > minZ);
0170
0171 double stepX = (maxX - minX) / (nBinsX - 1);
0172 double stepY = (maxY - minY) / (nBinsY - 1);
0173 double stepZ = (maxZ - minZ) / (nBinsZ - 1);
0174
0175 for (std::size_t i = 0; i < nBinsX; i++) {
0176 double raw_x = minX + i * stepX;
0177 for (std::size_t j = 0; j < nBinsY; j++) {
0178 double raw_y = minY + j * stepY;
0179 for (std::size_t k = 0; k < nBinsZ; k++) {
0180 double raw_z = minZ + k * stepZ;
0181 Acts::Vector3 position(raw_x, raw_y, raw_z);
0182 Vector3 bField = config.bField->getFieldUnchecked(position);
0183
0184 x = raw_x / Acts::UnitConstants::mm;
0185 y = raw_y / Acts::UnitConstants::mm;
0186 z = raw_z / Acts::UnitConstants::mm;
0187 Bx = bField.x() / Acts::UnitConstants::T;
0188 By = bField.y() / Acts::UnitConstants::T;
0189 Bz = bField.z() / Acts::UnitConstants::T;
0190 outputTree->Fill();
0191 }
0192 }
0193 }
0194
0195 } else {
0196 ACTS_INFO("Map will be written out in cylinder coordinates (r,z).");
0197
0198
0199 double r = 0;
0200 outputTree->Branch("r", &r);
0201 double z = 0;
0202 outputTree->Branch("z", &z);
0203
0204 double Br = 0;
0205 outputTree->Branch("Br", &Br);
0206 double Bz = 0;
0207 outputTree->Branch("Bz", &Bz);
0208
0209 double minR = 0, maxR = 0;
0210 double minZ = 0, maxZ = 0;
0211 std::size_t nBinsR = 0, nBinsZ = 0;
0212
0213 if (config.rBounds && config.zBounds) {
0214 ACTS_INFO("User defined ranges handed over.");
0215
0216 minR = config.rBounds->at(0);
0217 minZ = config.zBounds->at(0);
0218
0219 maxR = config.rBounds->at(1);
0220 maxZ = config.zBounds->at(1);
0221
0222 nBinsR = config.rBins;
0223 nBinsZ = config.zBins;
0224 } else {
0225 ACTS_INFO("No user defined ranges handed over - printing out whole map.");
0226
0227 if (minima.size() == 3 && maxima.size() == 3) {
0228 minR = 0.;
0229 minZ = minima.at(2);
0230
0231 maxR = maxima.at(0);
0232 maxZ = maxima.at(2);
0233
0234 nBinsR = nBins.at(0);
0235 nBinsZ = nBins.at(2);
0236
0237 } else if (minima.size() == 2 || maxima.size() == 2) {
0238 minR = minima.at(0);
0239 minZ = minima.at(1);
0240
0241 maxR = maxima.at(0);
0242 maxZ = maxima.at(1);
0243
0244 nBinsR = nBins.at(0);
0245 nBinsZ = nBins.at(1);
0246
0247 } else {
0248 throw std::invalid_argument(
0249 "BField has wrong dimension. The dimension needs to be "
0250 "either 2 (r,z,Br,Bz) or 3(x,y,z,Bx,By,Bz) in order to be "
0251 "written out by this writer.");
0252 }
0253 }
0254
0255 assert(maxR > minR);
0256 assert(maxZ > minZ);
0257
0258 double stepR = (maxR - minR) / (nBinsR - 1);
0259 double stepZ = (maxZ - minZ) / (nBinsZ - 1);
0260
0261 for (std::size_t k = 0; k < nBinsZ; k++) {
0262 double raw_z = minZ + k * stepZ;
0263 for (std::size_t j = 0; j < nBinsR; j++) {
0264 double raw_r = minR + j * stepR;
0265 Acts::Vector3 position(raw_r, 0.0, raw_z);
0266 ACTS_VERBOSE("Requesting position: " << position.transpose());
0267 auto bField = config.bField->getFieldUnchecked(position);
0268 z = raw_z / Acts::UnitConstants::mm;
0269 r = raw_r / Acts::UnitConstants::mm;
0270 Bz = bField.z() / Acts::UnitConstants::T;
0271 Br = VectorHelpers::perp(bField) / Acts::UnitConstants::T;
0272 outputTree->Fill();
0273 }
0274 }
0275 }
0276
0277
0278 ACTS_INFO("Closing and Writing ROOT output File : " << config.fileName);
0279 outputTree->Write();
0280 delete outputFile;
0281 }
0282 }