Skip to content

Commit 885e4ea

Browse files
sawenzelclaude
andcommitted
Field: keep polarity on MagneticField re-initialisation
This commit fixes MagneticField re-initialisation such that a field read back from a file keeps its polarity instead of being silently inverted. It: - applies the polarity convention once, in the constructors, instead of in CreateField() - leaves the stored factors untouched in CreateField(), which is the entry point for re-initialising a streamed object whose measured map is transient - adds a test comparing field vectors, not magnitudes, across a write/read round trip at solenoid, dipole and machine-compensator points This makes it possible to write a configured field to a ROOT file and read it back unchanged; until now the only correct way to recreate a field was to rebuild it from the GRP currents. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0178JHAQ2biaX5ac9ThppBXi
1 parent c76360f commit 885e4ea

3 files changed

Lines changed: 61 additions & 8 deletions

File tree

Common/Field/include/Field/MagneticField.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,8 @@ class MagneticField : public FairField
262262

263263
Int_t mDefaultIntegration; ///< Default integration method as indicated in Geant
264264
Int_t mPrecisionInteg; ///< Alternative integration method, e.g. for higher precision
265-
Double_t mMultipicativeFactorSolenoid; ///< Multiplicative factor for solenoid
266-
Double_t mMultipicativeFactorDipole; ///< Multiplicative factor for dipole
265+
Double_t mMultipicativeFactorSolenoid; ///< Multiplicative factor for solenoid, polarity convention applied
266+
Double_t mMultipicativeFactorDipole; ///< Multiplicative factor for dipole, polarity convention applied
267267
Double_t mMaxField; ///< Max Field as indicated in Geant
268268
Bool_t mDipoleOnOffFlag; ///< Dipole ON/OFF flag
269269

Common/Field/src/MagneticField.cxx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ MagneticField::MagneticField(const char* name, const char* title, Double_t facto
108108
mBeamEnergy(be),
109109
mDefaultIntegration(integ),
110110
mPrecisionInteg(1),
111-
mMultipicativeFactorSolenoid(factorSol),
112-
mMultipicativeFactorDipole(factorDip),
111+
mMultipicativeFactorSolenoid(1.),
112+
mMultipicativeFactorDipole(1.),
113113
mMaxField(fmax),
114114
mDipoleOnOffFlag(factorDip == 0.),
115115
mQuadrupoleGradient(0),
@@ -122,6 +122,8 @@ MagneticField::MagneticField(const char* name, const char* title, Double_t facto
122122
/*
123123
* Constructor for human readable params
124124
*/
125+
setFactorSolenoid(factorSol);
126+
setFactorDipole(factorDip);
125127
setDataFileName(path.c_str());
126128
if (!gOriginBias) {
127129
checkOriginBias();
@@ -139,8 +141,8 @@ MagneticField::MagneticField(const MagFieldParam& param)
139141
mBeamEnergy(param.GetBeamEnergy()),
140142
mDefaultIntegration(param.GetDefInt()),
141143
mPrecisionInteg(1),
142-
mMultipicativeFactorSolenoid(param.GetFactorSol()), // temporary
143-
mMultipicativeFactorDipole(param.GetFactorDip()), // temporary
144+
mMultipicativeFactorSolenoid(1.),
145+
mMultipicativeFactorDipole(1.),
144146
mMaxField(param.GetMaxField()),
145147
mDipoleOnOffFlag(param.GetFactorDip() == 0.),
146148
mQuadrupoleGradient(0),
@@ -153,6 +155,8 @@ MagneticField::MagneticField(const MagFieldParam& param)
153155
/*
154156
* Constructor for FairParam derived params
155157
*/
158+
setFactorSolenoid(param.GetFactorSol());
159+
setFactorDipole(param.GetFactorDip());
156160
setDataFileName(param.GetMapPath());
157161
if (!gOriginBias) {
158162
checkOriginBias();
@@ -235,8 +239,11 @@ void MagneticField::CreateField()
235239

236240
loadParameterization();
237241
initializeMachineField(mBeamType, mBeamEnergy);
238-
setFactorSolenoid(mMultipicativeFactorSolenoid);
239-
setFactorDipole(mMultipicativeFactorDipole);
242+
// The scaling factors are left alone: they already carry the polarity convention, and
243+
// re-applying it would invert a field re-initialized after being read back from a file.
244+
if (mFastField) {
245+
mFastField->setFactorSol(getFactorSolenoid());
246+
}
240247
double xyz[3] = {0., 0., 0.};
241248
mSolenoid = getBz(xyz);
242249
Print("a");

Common/Field/test/testMagneticField.cxx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "Field/MagFieldFast.h"
1919
#include <memory>
2020
#include <fairlogger/Logger.h> // for FairLogger
21+
#include <TFile.h>
2122
#include <TStopwatch.h>
2223
#include <TRandom.h>
2324

@@ -98,3 +99,48 @@ BOOST_AUTO_TEST_CASE(MagneticField_test)
9899
BOOST_CHECK(TMath::Abs(rms[i] / nomBz) < 1.e-3);
99100
}
100101
}
102+
103+
BOOST_AUTO_TEST_CASE(MagneticField_reinitialization_test)
104+
{
105+
// The measured map is transient, so a MagneticField read back from a file has to be
106+
// re-created before it can be used. That must reproduce the field vectors, not merely
107+
// their magnitude: a sign flip leaves |B| untouched.
108+
const double points[][3] = {
109+
{0., 0., 0.}, // solenoid, on axis
110+
{100., 50., 100.}, // solenoid, off axis
111+
{10., 10., -900.}, // muon dipole
112+
{0., 0., 1000.}, // compensator 1A, side A
113+
{0., 0., -2049.}, // compensator 2C, side C
114+
{0., 0., 2049.} // compensator 2A, side A
115+
};
116+
const int npoints = sizeof(points) / sizeof(points[0]);
117+
const double tolerance = 1.e-9; // kGauss
118+
119+
std::unique_ptr<MagneticField> fld = std::make_unique<MagneticField>("Maps", "Maps", 1., 1., MagFieldParam::k5kG);
120+
const double facSol = fld->getFactorSolenoid(), facDip = fld->getFactorDipole();
121+
double bref[npoints][3] = {};
122+
for (int ip = 0; ip < npoints; ip++) {
123+
fld->Field(points[ip], bref[ip]);
124+
// a point where the field vanishes would make the comparisons below vacuous
125+
BOOST_CHECK(TMath::Abs(bref[ip][0]) + TMath::Abs(bref[ip][1]) + TMath::Abs(bref[ip][2]) > tolerance);
126+
}
127+
128+
const char* fname = "testMagneticFieldReinitialization.root";
129+
{
130+
TFile fout(fname, "recreate");
131+
fout.WriteObject(fld.get(), "field");
132+
}
133+
TFile fin(fname);
134+
auto* fldRead = fin.Get<MagneticField>("field");
135+
BOOST_REQUIRE(fldRead != nullptr);
136+
fldRead->CreateField();
137+
BOOST_CHECK_EQUAL(fldRead->getFactorSolenoid(), facSol);
138+
BOOST_CHECK_EQUAL(fldRead->getFactorDipole(), facDip);
139+
for (int ip = 0; ip < npoints; ip++) {
140+
double b[3] = {};
141+
fldRead->Field(points[ip], b);
142+
for (int i = 0; i < 3; i++) {
143+
BOOST_CHECK_SMALL(b[i] - bref[ip][i], tolerance);
144+
}
145+
}
146+
}

0 commit comments

Comments
 (0)