Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RootBFieldWriter.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file RootBFieldWriter.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2021 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
16 
17 #include <cassert>
18 #include <ios>
19 #include <sstream>
20 #include <stdexcept>
21 #include <utility>
22 #include <vector>
23 
24 #include <TFile.h>
25 #include <TTree.h>
26 
27 namespace ActsExamples {
28 
31  std::unique_ptr<const Acts::Logger> p_logger) {
32  // Set up (local) logging
33  // @todo Remove dangerous using declaration once the logger macro
34  // tolerates it
35  using namespace Acts;
36  ACTS_LOCAL_LOGGER(std::move(p_logger))
37 
38  Acts::MagneticFieldContext bFieldContext;
39 
40  // Check basic configuration
41  if (config.treeName.empty()) {
42  throw std::invalid_argument("Missing tree name");
43  } else if (config.fileName.empty()) {
44  throw std::invalid_argument("Missing file name");
45  } else if (config.bField == nullptr) {
46  throw std::invalid_argument("Missing interpolated magnetic field");
47  }
48 
49  // Setup ROOT I/O
50  ACTS_INFO("Registering new ROOT output File : " << config.fileName);
51  TFile* outputFile =
52  TFile::Open(config.fileName.c_str(), config.fileMode.c_str());
53  if (outputFile == nullptr) {
54  throw std::ios_base::failure("Could not open '" + config.fileName + "'");
55  }
56  TTree* outputTree = new TTree(config.treeName.c_str(),
57  config.treeName.c_str(), 99, outputFile);
58  if (outputTree == nullptr) {
59  throw std::bad_alloc();
60  }
61 
62  // Access the minima and maxima of all axes
63  auto minima = config.bField->getMin();
64  auto maxima = config.bField->getMax();
65  auto nBins = config.bField->getNBins();
66 
67  if (logger().doPrint(Acts::Logging::VERBOSE)) {
68  std::stringstream ss;
69  ss << "Minimum:";
70  for (auto m : minima) {
71  ss << " " << m;
72  }
73  ACTS_VERBOSE(ss.str());
74  ss.str("");
75  ss << "Maximum:";
76  for (auto m : maxima) {
77  ss << " " << m;
78  }
79  ACTS_VERBOSE(ss.str());
80  ss.str("");
81  ss << "nBins:";
82  for (auto m : nBins) {
83  ss << " " << m;
84  }
85  ACTS_VERBOSE(ss.str());
86  }
87 
88  if (config.gridType == GridType::xyz) {
89  ACTS_INFO("Map will be written out in cartesian coordinates (x,y,z).");
90 
91  // Write out the interpolated magnetic field map
92  double minX = 0., minY = 0., minZ = 0.;
93  double maxX = 0., maxY = 0., maxZ = 0.;
94  size_t nBinsX = 0, nBinsY = 0, nBinsZ = 0;
95 
96  // The position values in xyz
97  double x = 0;
98  outputTree->Branch("x", &x);
99  double y = 0;
100  outputTree->Branch("y", &y);
101  double z = 0;
102  outputTree->Branch("z", &z);
103 
104  // The BField values in xyz
105  double Bx = 0;
106  outputTree->Branch("Bx", &Bx);
107  double By = 0;
108  outputTree->Branch("By", &By);
109  double Bz = 0;
110  outputTree->Branch("Bz", &Bz);
111 
112  // check if range is user defined
113  if (config.rBounds && config.zBounds) {
114  ACTS_INFO("User defined ranges handed over.");
115 
116  // print out map in user defined range
117  minX = config.rBounds->at(0);
118  minY = config.rBounds->at(0);
119  minZ = config.zBounds->at(0);
120 
121  maxX = config.rBounds->at(1);
122  maxY = config.rBounds->at(1);
123  maxZ = config.zBounds->at(1);
124 
125  nBinsX = config.rBins;
126  nBinsY = config.rBins;
127  nBinsZ = config.zBins;
128 
129  } else {
130  ACTS_INFO("No user defined ranges handed over - write out whole map.");
131  // write out whole map
132 
133  // check dimension of Bfieldmap
134  if (minima.size() == 3 && maxima.size() == 3) {
135  minX = minima.at(0);
136  minY = minima.at(1);
137  minZ = minima.at(2);
138 
139  maxX = maxima.at(0);
140  maxY = maxima.at(1);
141  maxZ = maxima.at(2);
142 
143  nBinsX = nBins.at(0);
144  nBinsY = nBins.at(1);
145  nBinsZ = nBins.at(2);
146 
147  } else if (minima.size() == 2 && maxima.size() == 2) {
148  minX = -maxima.at(0);
149  minY = -maxima.at(0);
150  minZ = minima.at(1);
151 
152  maxX = maxima.at(0);
153  maxY = maxima.at(0);
154  maxZ = maxima.at(1);
155 
156  nBinsX = nBins.at(0);
157  nBinsY = nBins.at(0);
158  nBinsZ = nBins.at(1);
159  } else {
160  throw std::invalid_argument(
161  "BField has wrong dimension. The dimension needs to be "
162  "either 2 (r,z,Br,Bz) or 3(x,y,z,Bx,By,Bz) in order to be "
163  "written out by this writer.");
164  }
165  }
166 
167  assert(maxX > minX);
168  assert(maxY > minY);
169  assert(maxZ > minZ);
170 
171  double stepX = (maxX - minX) / (nBinsX - 1);
172  double stepY = (maxY - minY) / (nBinsY - 1);
173  double stepZ = (maxZ - minZ) / (nBinsZ - 1);
174 
175  for (size_t i = 0; i < nBinsX; i++) {
176  double raw_x = minX + i * stepX;
177  for (size_t j = 0; j < nBinsY; j++) {
178  double raw_y = minY + j * stepY;
179  for (size_t k = 0; k < nBinsZ; k++) {
180  double raw_z = minZ + k * stepZ;
181  Acts::Vector3 position(raw_x, raw_y, raw_z);
182  Vector3 bField = config.bField->getFieldUnchecked(position);
183 
184  x = raw_x / Acts::UnitConstants::mm;
185  y = raw_y / Acts::UnitConstants::mm;
186  z = raw_z / Acts::UnitConstants::mm;
187  Bx = bField.x() / Acts::UnitConstants::T;
188  By = bField.y() / Acts::UnitConstants::T;
189  Bz = bField.z() / Acts::UnitConstants::T;
190  outputTree->Fill();
191  } // for z
192  } // for y
193  } // for x
194 
195  } else {
196  ACTS_INFO("Map will be written out in cylinder coordinates (r,z).");
197 
198  // The position value in rz
199  double r = 0;
200  outputTree->Branch("r", &r);
201  double z = 0;
202  outputTree->Branch("z", &z);
203  // The BField value in rz
204  double Br = 0;
205  outputTree->Branch("Br", &Br);
206  double Bz = 0;
207  outputTree->Branch("Bz", &Bz);
208 
209  double minR = 0, maxR = 0;
210  double minZ = 0, maxZ = 0;
211  size_t nBinsR = 0, nBinsZ = 0;
212 
213  if (config.rBounds && config.zBounds) {
214  ACTS_INFO("User defined ranges handed over.");
215 
216  minR = config.rBounds->at(0);
217  minZ = config.zBounds->at(0);
218 
219  maxR = config.rBounds->at(1);
220  maxZ = config.zBounds->at(1);
221 
222  nBinsR = config.rBins;
223  nBinsZ = config.zBins;
224  } else {
225  ACTS_INFO("No user defined ranges handed over - printing out whole map.");
226 
227  if (minima.size() == 3 && maxima.size() == 3) {
228  minR = 0.;
229  minZ = minima.at(2);
230 
231  maxR = maxima.at(0);
232  maxZ = maxima.at(2);
233 
234  nBinsR = nBins.at(0);
235  nBinsZ = nBins.at(2);
236 
237  } else if (minima.size() == 2 || maxima.size() == 2) {
238  minR = minima.at(0);
239  minZ = minima.at(1);
240 
241  maxR = maxima.at(0);
242  maxZ = maxima.at(1);
243 
244  nBinsR = nBins.at(0);
245  nBinsZ = nBins.at(1);
246 
247  } else {
248  throw std::invalid_argument(
249  "BField has wrong dimension. The dimension needs to be "
250  "either 2 (r,z,Br,Bz) or 3(x,y,z,Bx,By,Bz) in order to be "
251  "written out by this writer.");
252  }
253  }
254 
255  assert(maxR > minR);
256  assert(maxZ > minZ);
257 
258  double stepR = (maxR - minR) / (nBinsR - 1);
259  double stepZ = (maxZ - minZ) / (nBinsZ - 1);
260 
261  for (size_t k = 0; k < nBinsZ; k++) {
262  double raw_z = minZ + k * stepZ;
263  for (size_t j = 0; j < nBinsR; j++) {
264  double raw_r = minR + j * stepR;
265  Acts::Vector3 position(raw_r, 0.0, raw_z); // position at phi=0
266  ACTS_VERBOSE("Requesting position: " << position.transpose());
267  auto bField = config.bField->getFieldUnchecked(position);
268  z = raw_z / Acts::UnitConstants::mm;
269  r = raw_r / Acts::UnitConstants::mm;
270  Bz = bField.z() / Acts::UnitConstants::T;
272  outputTree->Fill();
273  } // for R
274  } // for z
275  }
276 
277  // Tear down ROOT I/O
278  ACTS_INFO("Closing and Writing ROOT output File : " << config.fileName);
279  outputTree->Write();
280  delete outputFile;
281 }
282 } // namespace ActsExamples