9#include <geometry/modules/CreateFieldMapModule.h>
10#include <framework/geometry/BFieldManager.h>
11#include <framework/utilities/Utils.h>
12#include <framework/gearbox/Unit.h>
14#include <Math/Vector3D.h>
15#include <Math/VectorUtil.h>
20#include <boost/algorithm/string.hpp>
21#include <boost/format.hpp>
36 setDescription(
"Create Field maps of the Belle II magnetic field used in the simulation");
39 addParam(
"filename",
m_filename,
"ROOT filename for the map", std::string(
"FieldMap.root"));
40 addParam(
"type",
m_type,
"type of the fieldmap (xy, zx, zy, zr)", std::string(
"zx"));
41 addParam(
"nU",
m_nU,
"number of steps along first coordinate", 1800);
42 addParam(
"minU",
m_minU,
"minimum value for the first coordinate", -400.);
43 addParam(
"maxU",
m_maxU,
"maximum value for the first coordinate", 500.);
44 addParam(
"nV",
m_nV,
"number of steps along second coordinate", 1600);
45 addParam(
"minV",
m_minV,
"minimum value for the second coordinate", -400.);
46 addParam(
"maxV",
m_maxV,
"maximum value for the second coordinate", 400.);
47 addParam(
"phi",
m_phi,
"phi angle for the scan in radians", 0.);
51 "WARNING: output can be huge",
false);
57 B2WARNING(
"CreateFieldMap: No Filename given, just sampling for fun");
62 B2ERROR(
"CreateFieldMap type '" <<
m_type <<
"' not valid, use one of 'xy', 'zx', 'zy' or 'zr'");
65 B2ERROR(
"Number of steps has to be positive");
68 B2ERROR(
"Range for first coordinate is zero");
73 B2ERROR(
"Range for second coordinate is zero");
79 B2ERROR(
"R values (minV, maxV) must be positive");
82 B2ERROR(
"Number of steps in phi must be positive");
90 TFile* outfile{
nullptr};
93 outfile =
new TFile(
m_filename.c_str(),
"RECREATE");
111 auto showProgress = [&]() {
113 const int64_t donePercent = 100 * ++curStep / nSteps;
114 if (donePercent > lastPercent) {
116 const double perStep = totalTime / curStep;
117 if (donePercent == 100) {
118 B2INFO(boost::format(
"BField %s Scan: %d samples, %.3f us per sample, total: %.2f seconds")
122 B2INFO(boost::format(
"BField %s Scan: %3d%%, %.3f us per sample")
126 lastPercent = donePercent;
130 struct {
float x{0}, y{0}, z{0}, bx{0}, by{0}, bz{0}; } field_point;
131 TTree* all_values{
nullptr};
133 all_values =
new TTree(
"bfield_values",
"All B field values");
134 all_values->Branch(
"x", &field_point.x,
"x/F");
135 all_values->Branch(
"y", &field_point.y,
"y/F");
136 all_values->Branch(
"z", &field_point.z,
"z/F");
137 all_values->Branch(
"bx", &field_point.bx,
"bx/F");
138 all_values->Branch(
"by", &field_point.by,
"by/F");
139 all_values->Branch(
"bz", &field_point.bz,
"bz/F");
141 auto fillTree = [&](
const ROOT::Math::XYZVector & p,
const ROOT::Math::XYZVector & b) {
142 if (!all_values)
return;
143 field_point.x = p.X();
144 field_point.y = p.Y();
145 field_point.z = p.Z();
146 field_point.bx = b.X();
147 field_point.by = b.Y();
148 field_point.bz = b.Z();
157 for (
int iU = 0; iU <
m_nU; ++iU) {
158 for (
int iV = 0; iV <
m_nV; ++iV) {
160 const double u = h_b->GetXaxis()->GetBinCenter(iU + 1);
161 const double v = h_b->GetYaxis()->GetBinCenter(iV + 1);
163 for (
int iPhi = 0; iPhi <
m_nPhi; ++iPhi) {
164 ROOT::Math::XYZVector pos(v, 0, u);
165 pos = ROOT::Math::VectorUtil::RotateZ(pos, 2 * M_PI * iPhi /
m_nPhi);
170 h_br->Fill(u, v, bfield.Rho());
171 h_bz->Fill(u, v, bfield.Z());
172 h_b->Fill(u, v, bfield.R());
173 fillTree(pos, bfield);
181 for (TH2D* h : {h_br, h_bz, h_b}) {
187 const std::string nu =
m_type.substr(0, 1);
188 const std::string nv =
m_type.substr(1, 1);
195 for (
int iU = 0; iU <
m_nU; ++iU) {
196 for (
int iV = 0; iV <
m_nV; ++iV) {
197 ROOT::Math::XYZVector pos(0, 0, 0);
199 const double u = h_bx->GetXaxis()->GetBinCenter(iU + 1);
200 const double v = h_bx->GetYaxis()->GetBinCenter(iV + 1);
215 pos = ROOT::Math::VectorUtil::RotateZ(pos,
m_phi);
220 h_bx->Fill(u, v, bfield.X());
221 h_by->Fill(u, v, bfield.Y());
222 h_bz->Fill(u, v, bfield.Z());
223 h_b->Fill(u, v, bfield.R());
224 fillTree(pos, bfield);
231 for (TH2D* h : {h_bx, h_by, h_bz, h_b}) {
237 if (all_values) all_values->Write();
static ROOT::Math::XYZVector getFieldInTesla(const ROOT::Math::XYZVector &pos)
return the magnetic field at a given position in Tesla.
int m_nPhi
number of steps in phi
virtual void initialize() override
Check input parameters.
double m_minV
start value for the first coordinate
double m_wOffset
offset on the third coordinate
double m_minU
start value for the first coordinate
double m_phi
phi rotation when sampling magnetic field (value of pi will convert ZX to ZY scan)
int m_nV
number of steps along the second coordinate
int m_nU
number of steps along the first coordinate
std::string m_type
type of the fieldmap (zx, zy, zr)
double m_maxV
end value for the first coordinate
virtual void beginRun() override
Create the fieldmap.
std::string m_filename
output filename for the fieldmap
EFieldTypes
Types of Fieldmap to be created.
@ c_ZX
scan along ZX plane
@ c_ZY
scan along ZY plane
@ c_ZR
scan along Z and R, averaging over phi
@ c_XY
scan along XY plane
double m_maxU
end value for the first coordinate
bool m_createTree
if true create a TTree with all sampled points
CreateFieldMapModule()
Constructor: Sets the description, the properties and the parameters of the module.
void setDescription(const std::string &description)
Sets the description of the module.
static const double us
[microsecond]
static const double s
[second]
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
double getClock()
Return current value of the real-time clock.
Abstract base class for different kinds of events.