Project
Loading...
Searching...
No Matches
MagneticField.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15
16#include "Field/MagneticField.h"
18#include <TFile.h> // for TFile
19#include <TPRegexp.h> // for TPRegexp
20#include <TString.h> // for TString
21#include <TSystem.h> // for TSystem, gSystem
22#include <fairlogger/Logger.h> // for FairLogger
23#include "FairParamList.h"
24#include "FairRun.h"
25#include "FairRuntimeDb.h"
26
27using namespace o2::field;
28
30
31const FieldOriginBiasParam* MagneticField::gOriginBias = nullptr;
32
33const Double_t MagneticField::sSolenoidToDipoleZ = -700.;
34
67const UShort_t MagneticField::sPolarityConvention = MagneticField::kConvLHC;
68
70 : FairField(),
71 mMeasuredMap(nullptr),
72 mFastField(nullptr),
73 mMapType(MagFieldParam::k5kG),
74 mSolenoid(0),
75 mBeamType(MagFieldParam::kNoBeamField),
76 mBeamEnergy(0),
77 mDefaultIntegration(0),
78 mPrecisionInteg(0),
79 mMultipicativeFactorSolenoid(1.),
80 mMultipicativeFactorDipole(1.),
81 mMaxField(15),
82 mDipoleOnOffFlag(kFALSE),
83 mQuadrupoleGradient(0),
84 mDipoleField(0),
85 mCompensatorField2C(0),
86 mCompensatorField1A(0),
87 mCompensatorField2A(0),
88 mParameterNames("", "")
89{
90 /*
91 * Default constructor
92 */
93 fType = 2; // flag non-constant field
94 if (!gOriginBias) {
96 }
97}
98
99MagneticField::MagneticField(const char* name, const char* title, Double_t factorSol, Double_t factorDip,
100 MagFieldParam::BMap_t maptype, MagFieldParam::BeamType_t bt, Double_t be, Int_t integ,
101 Double_t fmax, const std::string path)
102 : FairField(name, title),
103 mMeasuredMap(nullptr),
104 mFastField(nullptr),
105 mMapType(maptype),
106 mSolenoid(0),
107 mBeamType(bt),
108 mBeamEnergy(be),
109 mDefaultIntegration(integ),
110 mPrecisionInteg(1),
111 mMultipicativeFactorSolenoid(1.),
112 mMultipicativeFactorDipole(1.),
113 mMaxField(fmax),
114 mDipoleOnOffFlag(factorDip == 0.),
115 mQuadrupoleGradient(0),
116 mDipoleField(0),
117 mCompensatorField2C(0),
118 mCompensatorField1A(0),
119 mCompensatorField2A(0),
120 mParameterNames("", "")
121{
122 /*
123 * Constructor for human readable params
124 */
125 setFactorSolenoid(factorSol);
126 setFactorDipole(factorDip);
127 setDataFileName(path.c_str());
128 if (!gOriginBias) {
130 }
131 CreateField();
132}
133
135 : FairField(param.GetName(), param.GetTitle()),
136 mMeasuredMap(nullptr),
137 mFastField(nullptr),
138 mMapType(param.GetMapType()),
139 mSolenoid(0),
140 mBeamType(param.GetBeamType()),
141 mBeamEnergy(param.GetBeamEnergy()),
142 mDefaultIntegration(param.GetDefInt()),
143 mPrecisionInteg(1),
144 mMultipicativeFactorSolenoid(1.),
145 mMultipicativeFactorDipole(1.),
146 mMaxField(param.GetMaxField()),
147 mDipoleOnOffFlag(param.GetFactorDip() == 0.),
148 mQuadrupoleGradient(0),
149 mDipoleField(0),
150 mCompensatorField2C(0),
151 mCompensatorField1A(0),
152 mCompensatorField2A(0),
153 mParameterNames("", "")
154{
155 /*
156 * Constructor for FairParam derived params
157 */
158 setFactorSolenoid(param.GetFactorSol());
159 setFactorDipole(param.GetFactorDip());
160 setDataFileName(param.GetMapPath());
161 if (!gOriginBias) {
163 }
164 CreateField();
165}
166
168{
169 float fldCoeffL3, fldCoeffDip;
171 if (uniform) {
172 fldCoeffL3 = float(fld) / 5.;
173 fldCoeffDip = fld > 0 ? 1. : -1;
175 } else {
176 switch (std::abs(fld)) {
177 case 5:
179 fldCoeffL3 = fldCoeffDip = fld > 0 ? 1. : -1;
180 break;
181 case 0:
183 fldCoeffL3 = fldCoeffDip = 0;
184 break;
185 case 2:
187 fldCoeffL3 = fldCoeffDip = fld > 0 ? 1. : -1;
188 break;
189 default:
190 LOG(fatal) << "Field option " << fld << " is not supported, use +-2, +-5 or 0 or <int_kilogauss>U";
191 };
192 }
193 return new o2::field::MagneticField("Maps", "Maps", fldCoeffL3, fldCoeffDip, fldType);
194}
195
197{
198 /*
199 * field initialization
200 */
201
202 fType = 2; // flag non-constant field
203
204 // does real creation of the field
205 if (mDefaultIntegration < 0 || mDefaultIntegration > 2) {
206 LOG(warning) << "MagneticField::CreateField: Invalid magnetic field flag: " << mDefaultIntegration
207 << "; Helix tracking chosen instead";
208 mDefaultIntegration = 2;
209 }
210 if (mDefaultIntegration == 0) {
211 mPrecisionInteg = 0;
212 }
213
214 if (mBeamEnergy <= 0 && mBeamType != MagFieldParam::kNoBeamField) {
215 if (mBeamType == MagFieldParam::kBeamTypepp) {
216 mBeamEnergy = 7000.; // max proton energy
217 } else if (mBeamType == MagFieldParam::kBeamTypeAA) {
218 mBeamEnergy = 2760; // max PbPb energy
219 } else if (mBeamType == MagFieldParam::kBeamTypepA || mBeamType == MagFieldParam::kBeamTypeAp) {
220 mBeamEnergy = 2760; // same rigitiy max PbPb energy
221 }
222 //
223 LOG(info) << "MagneticField::CreateField: Maximim possible beam energy for requested beam is assumed";
224 }
225
226 const char* parname = nullptr;
227
228 if (mMapType == MagFieldParam::k2kG) {
229 parname = mDipoleOnOffFlag ? "Sol12_Dip0_Hole" : "Sol12_Dip6_Hole";
230 } else if (mMapType == MagFieldParam::k5kG) {
231 parname = mDipoleOnOffFlag ? "Sol30_Dip0_Hole" : "Sol30_Dip6_Hole";
232 } else if (mMapType == MagFieldParam::k5kGUniform) {
233 parname = "Sol30_Dip6_Uniform";
234 } else {
235 LOG(fatal) << "MagneticField::CreateField: Unknown field identifier " << mMapType << " is requested\n";
236 }
237
238 setParameterName(parname);
239
241 initializeMachineField(mBeamType, mBeamEnergy);
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 }
247 double xyz[3] = {0., 0., 0.};
248 mSolenoid = getBz(xyz);
249 Print("a");
250 //
251}
252
254{
255 /*
256 * load parametrization for measured field
257 */
258
259 if (mMeasuredMap) {
260 LOG(fatal) << "MagneticField::loadParameterization: Field data " << getParameterName()
261 << " are already loaded from " << getDataFileName() << "\n";
262 }
263 TString fname = getDataFileName();
264 gSystem->ExpandPathName(fname);
265 TFile* file = TFile::Open(fname);
266 if (!file) {
267 LOG(fatal) << "MagneticField::loadParameterization: Failed to open magnetic field data file " << fname << "\n";
268 }
269
270 mMeasuredMap =
271 std::unique_ptr<MagneticWrapperChebyshev>(dynamic_cast<MagneticWrapperChebyshev*>(file->Get(getParameterName())));
272 if (!mMeasuredMap) {
273 LOG(fatal) << "MagneticField::loadParameterization: Did not find field " << getParameterName() << " in " << fname
274 << "%s\n";
275 }
276 file->Close();
277 delete file;
278 return kTRUE;
279}
280
281void MagneticField::Field(const Double_t* __restrict__ xyzExt, Double_t* __restrict__ b)
282{
283 /*
284 * query field value at point
285 */
286 double xyz[3] = {xyzExt[0] - gOriginBias->x, xyzExt[1] - gOriginBias->y, xyzExt[2] - gOriginBias->z};
287 // b[0]=b[1]=b[2]=0.0;
288 if (mFastField && mFastField->Field(xyz, b)) {
289 return;
290 }
291
292 if (mMeasuredMap && xyz[2] > mMeasuredMap->getMinZ() && xyz[2] < mMeasuredMap->getMaxZ()) {
293 mMeasuredMap->Field(xyz, b);
294 if (xyz[2] > sSolenoidToDipoleZ || mDipoleOnOffFlag) {
295 for (int i = 3; i--;) {
296 b[i] *= mMultipicativeFactorSolenoid;
297 }
298 } else {
299 for (int i = 3; i--;) {
300 b[i] *= mMultipicativeFactorDipole;
301 }
302 }
303 } else {
304 MachineField(xyz, b);
305 }
306}
307
308Double_t MagneticField::getBz(const Double_t* xyzExt) const
309{
310 /*
311 * query field Bz component at point
312 */
313 double xyz[3] = {xyzExt[0] - gOriginBias->x, xyzExt[1] - gOriginBias->y, xyzExt[2] - gOriginBias->z};
314 if (mFastField) {
315 double bz = 0;
316 if (mFastField->GetBz(xyz, bz)) {
317 return bz;
318 }
319 }
320 if (mMeasuredMap && xyz[2] > mMeasuredMap->getMinZ() && xyz[2] < mMeasuredMap->getMaxZ()) {
321 double bz = mMeasuredMap->getBz(xyz);
322 return (xyz[2] > sSolenoidToDipoleZ || mDipoleOnOffFlag) ? bz * mMultipicativeFactorSolenoid
323 : bz * mMultipicativeFactorDipole;
324 } else {
325 return 0.;
326 }
327}
328
330{
331 /*
332 * assignment operator
333 */
334
335 if (this != &src) {
336 if (src.mMeasuredMap) {
337 mMeasuredMap.reset(new MagneticWrapperChebyshev(*src.getMeasuredMap()));
338 }
339 SetName(src.GetName());
340 mSolenoid = src.mSolenoid;
341 mBeamType = src.mBeamType;
342 mBeamEnergy = src.mBeamEnergy;
343 mDefaultIntegration = src.mDefaultIntegration;
344 mPrecisionInteg = src.mPrecisionInteg;
345 mMultipicativeFactorSolenoid = src.mMultipicativeFactorSolenoid;
346 mMultipicativeFactorDipole = src.mMultipicativeFactorDipole;
347 mMaxField = src.mMaxField;
348 mDipoleOnOffFlag = src.mDipoleOnOffFlag;
349 mParameterNames = src.mParameterNames;
350 mFastField.reset(src.mFastField ? new MagFieldFast(*src.getFastField()) : nullptr);
351 }
352 return *this;
353}
354
356{
357 if (btype == MagFieldParam::kNoBeamField) {
358 mQuadrupoleGradient = mDipoleField = mCompensatorField2C = mCompensatorField1A = mCompensatorField2A = 0.;
359 return;
360 }
361
362 double rigScale = benergy / 7000.; // scale according to ratio of E/Enominal
363 // for ions assume PbPb (with energy provided per nucleon) and account for A/Z
364 if (btype == MagFieldParam::kBeamTypeAA /* || btype==kBeamTypepA || btype==kBeamTypeAp */) {
365 rigScale *= 208. / 82.;
366 }
367 // Attention: in p-Pb the energy recorded in the GRP is the PROTON energy, no rigidity
368 // rescaling is needed
369
370 mQuadrupoleGradient = 22.0002 * rigScale;
371 mDipoleField = 37.8781 * rigScale;
372
373 // SIDE C
374 mCompensatorField2C = -9.6980;
375 // SIDE A
376 mCompensatorField1A = -13.2247;
377 mCompensatorField2A = 11.7905;
378}
379
380void MagneticField::MachineField(const Double_t* __restrict__ x, Double_t* __restrict__ b) const
381{
382 // ---- This is the ZDC part
383 // Compansators for Alice Muon Arm Dipole
384 const Double_t kBComp1CZ = 1075., kBComp1hDZ = 260. / 2., kBComp1SqR = 4.0 * 4.0;
385 const Double_t kBComp2CZ = 2049., kBComp2hDZ = 153. / 2., kBComp2SqR = 4.5 * 4.5;
386
387 const Double_t kTripQ1CZ = 2615., kTripQ1hDZ = 637. / 2., kTripQ1SqR = 3.5 * 3.5;
388 const Double_t kTripQ2CZ = 3480., kTripQ2hDZ = 550. / 2., kTripQ2SqR = 3.5 * 3.5;
389 const Double_t kTripQ3CZ = 4130., kTripQ3hDZ = 550. / 2., kTripQ3SqR = 3.5 * 3.5;
390 const Double_t kTripQ4CZ = 5015., kTripQ4hDZ = 637. / 2., kTripQ4SqR = 3.5 * 3.5;
391
392 const Double_t kDip1CZ = 6310.8, kDip1hDZ = 945. / 2., kDip1SqRC = 4.5 * 4.5, kDip1SqRA = 3.375 * 3.375;
393 const Double_t kDip2CZ = 12640.3, kDip2hDZ = 945. / 2., kDip2SqRC = 4.5 * 4.5, kDip2SqRA = 3.75 * 3.75;
394 const Double_t kDip2DXC = 9.7, kDip2DXA = 9.4;
395
396 double rad2 = x[0] * x[0] + x[1] * x[1];
397
398 b[0] = b[1] = b[2] = 0;
399
400 // SIDE C
401 if (x[2] < 0.) {
402 if (TMath::Abs(x[2] + kBComp2CZ) < kBComp2hDZ && rad2 < kBComp2SqR) {
403 b[0] = mCompensatorField2C * mMultipicativeFactorDipole;
404 } else if (TMath::Abs(x[2] + kTripQ1CZ) < kTripQ1hDZ && rad2 < kTripQ1SqR) {
405 b[0] = mQuadrupoleGradient * x[1];
406 b[1] = mQuadrupoleGradient * x[0];
407 } else if (TMath::Abs(x[2] + kTripQ2CZ) < kTripQ2hDZ && rad2 < kTripQ2SqR) {
408 b[0] = -mQuadrupoleGradient * x[1];
409 b[1] = -mQuadrupoleGradient * x[0];
410 } else if (TMath::Abs(x[2] + kTripQ3CZ) < kTripQ3hDZ && rad2 < kTripQ3SqR) {
411 b[0] = -mQuadrupoleGradient * x[1];
412 b[1] = -mQuadrupoleGradient * x[0];
413 } else if (TMath::Abs(x[2] + kTripQ4CZ) < kTripQ4hDZ && rad2 < kTripQ4SqR) {
414 b[0] = mQuadrupoleGradient * x[1];
415 b[1] = mQuadrupoleGradient * x[0];
416 } else if (TMath::Abs(x[2] + kDip1CZ) < kDip1hDZ && rad2 < kDip1SqRC) {
417 b[1] = mDipoleField;
418 } else if (TMath::Abs(x[2] + kDip2CZ) < kDip2hDZ && rad2 < kDip2SqRC) {
419 double dxabs = TMath::Abs(x[0]) - kDip2DXC;
420 if ((dxabs * dxabs + x[1] * x[1]) < kDip2SqRC) {
421 b[1] = -mDipoleField;
422 }
423 }
424 }
425
426 // SIDE A
427 else {
428 if (TMath::Abs(x[2] - kBComp1CZ) < kBComp1hDZ && rad2 < kBComp1SqR) {
429 // Compensator magnet at z = 1075 m
430 b[0] = mCompensatorField1A * mMultipicativeFactorDipole;
431 }
432
433 if (TMath::Abs(x[2] - kBComp2CZ) < kBComp2hDZ && rad2 < kBComp2SqR) {
434 b[0] = mCompensatorField2A * mMultipicativeFactorDipole;
435 } else if (TMath::Abs(x[2] - kTripQ1CZ) < kTripQ1hDZ && rad2 < kTripQ1SqR) {
436 b[0] = -mQuadrupoleGradient * x[1];
437 b[1] = -mQuadrupoleGradient * x[0];
438 } else if (TMath::Abs(x[2] - kTripQ2CZ) < kTripQ2hDZ && rad2 < kTripQ2SqR) {
439 b[0] = mQuadrupoleGradient * x[1];
440 b[1] = mQuadrupoleGradient * x[0];
441 } else if (TMath::Abs(x[2] - kTripQ3CZ) < kTripQ3hDZ && rad2 < kTripQ3SqR) {
442 b[0] = mQuadrupoleGradient * x[1];
443 b[1] = mQuadrupoleGradient * x[0];
444 } else if (TMath::Abs(x[2] - kTripQ4CZ) < kTripQ4hDZ && rad2 < kTripQ4SqR) {
445 b[0] = -mQuadrupoleGradient * x[1];
446 b[1] = -mQuadrupoleGradient * x[0];
447 } else if (TMath::Abs(x[2] - kDip1CZ) < kDip1hDZ && rad2 < kDip1SqRA) {
448 b[1] = -mDipoleField;
449 } else if (TMath::Abs(x[2] - kDip2CZ) < kDip2hDZ && rad2 < kDip2SqRA) {
450 double dxabs = TMath::Abs(x[0]) - kDip2DXA;
451 if ((dxabs * dxabs + x[1] * x[1]) < kDip2SqRA) {
452 b[1] = mDipoleField;
453 }
454 }
455 }
456}
457
458void MagneticField::getTPCIntegral(const Double_t* xyz, Double_t* b) const
459{
460 b[0] = b[1] = b[2] = 0.0;
461 if (mMeasuredMap) {
462 mMeasuredMap->getTPCIntegral(xyz, b);
463 for (int i = 3; i--;) {
464 b[i] *= mMultipicativeFactorSolenoid;
465 }
466 }
467}
468
469void MagneticField::getTPCRatIntegral(const Double_t* xyz, Double_t* b) const
470{
471 b[0] = b[1] = b[2] = 0.0;
472 if (mMeasuredMap) {
473 mMeasuredMap->getTPCRatIntegral(xyz, b);
474 b[2] /= 100;
475 }
476}
477
478void MagneticField::getTPCIntegralCylindrical(const Double_t* rphiz, Double_t* b) const
479{
480 b[0] = b[1] = b[2] = 0.0;
481 if (mMeasuredMap) {
482 mMeasuredMap->getTPCIntegralCylindrical(rphiz, b);
483 for (int i = 3; i--;) {
484 b[i] *= mMultipicativeFactorSolenoid;
485 }
486 }
487}
488
489void MagneticField::getTPCRatIntegralCylindrical(const Double_t* rphiz, Double_t* b) const
490{
491 b[0] = b[1] = b[2] = 0.0;
492 if (mMeasuredMap) {
493 mMeasuredMap->getTPCRatIntegralCylindrical(rphiz, b);
494 b[2] /= 100;
495 }
496}
497
499{
500 switch (sPolarityConvention) {
501 case kConvDCS2008:
502 mMultipicativeFactorSolenoid = -fc;
503 break;
504 case kConvLHC:
505 mMultipicativeFactorSolenoid = -fc;
506 break;
507 default:
508 mMultipicativeFactorSolenoid = fc;
509 break; // case kConvMap2005: mMultipicativeFactorSolenoid = fc; break;
510 }
511 if (mFastField) {
512 mFastField->setFactorSol(getFactorSolenoid());
513 }
514}
515
517{
518 switch (sPolarityConvention) {
519 case kConvDCS2008:
520 mMultipicativeFactorDipole = fc;
521 break;
522 case kConvLHC:
523 mMultipicativeFactorDipole = -fc;
524 break;
525 default:
526 mMultipicativeFactorDipole = fc;
527 break; // case kConvMap2005: mMultipicativeFactorDipole = fc; break;
528 }
529}
530
532{
533 switch (sPolarityConvention) {
534 case kConvDCS2008:
535 return -mMultipicativeFactorSolenoid;
536 case kConvLHC:
537 return -mMultipicativeFactorSolenoid;
538 default:
539 return mMultipicativeFactorSolenoid; // case kConvMap2005: return mMultipicativeFactorSolenoid;
540 }
541}
542
544{
545 switch (sPolarityConvention) {
546 case kConvDCS2008:
547 return mMultipicativeFactorDipole;
548 case kConvLHC:
549 return -mMultipicativeFactorDipole;
550 default:
551 return mMultipicativeFactorDipole; // case kConvMap2005: return mMultipicativeFactorDipole;
552 }
553}
554
555void MagneticField::rescaleField(float l3Cur, float diCur, bool uniform, int convention)
556{
557 // this function taks as input magnet currents and rescales existing field if the map is compatible
558 float sclL3 = l3Cur, sclDip = diCur;
559 MagFieldParam::BMap_t map = getFieldMapScale(sclL3, sclDip, uniform);
560 if (map != mMapType) {
561 LOGP(fatal, "Provided L3current={} DipCurrent={} uniform={} leads to map type {}, incompatible with loaded {}", l3Cur, diCur, uniform, (int)map, (int)mMapType);
562 }
563 setFactorSolenoid(sclL3);
564 setFactorDipole(sclDip);
565 LOGP(info, "Updating magnetic field: L3current={} DipCurrent={} uniform={}", l3Cur, diCur, uniform);
566}
567
568MagFieldParam::BMap_t MagneticField::getFieldMapScale(float& l3, float& dip, bool uniform, int convention)
569{
570 // this function taks as input magnet currents and returns the field type and scalings for L3 and dipole
571 const float l3NominalCurrent1 = 30000.f; // (A)
572 const float l3NominalCurrent2 = 12000.f; // (A)
573 const float diNominalCurrent = 6000.f; // (A)
574
575 const float tolerance = 0.03; // relative current tolerance
576 const float zero = 77.f; // "zero" current (A)
577
579 float sclL3, sclDip;
580 float l3sav = l3, dipsav = dip;
581
582 float l3Pol = l3 > 0 ? 1 : -1;
583 float diPol = dip > 0 ? 1 : -1;
584
585 l3 = TMath::Abs(l3);
586 dip = TMath::Abs(dip);
587 static bool overrideL3 = std::getenv("O2_OVERRIDE_L3_CURRENT") != nullptr;
588 static bool overrideDIP = std::getenv("O2_OVERRIDE_DIPOLE_CURRENT") != nullptr;
589 static bool warnL3Done = false, warnDipDone = false, warnPolarityDone = false;
590
591 if (TMath::Abs((sclDip = dip / diNominalCurrent) - 1.) > tolerance && !uniform) {
592 if (dip <= zero) {
593 sclDip = 0.; // some small current.. -> Dipole OFF
594 } else {
595 if (!overrideDIP) {
596 LOG(fatal) << "MagneticField::createFieldMap: Wrong dipole current (" << dipsav << " A)!";
597 } else {
598 if (!warnDipDone) {
599 LOGP(error, "Dipole current was overridden to unsupported value {}", dipsav);
600 warnDipDone = true;
601 }
602 }
603 }
604 }
605 if (uniform) {
606 // special treatment of special MC with uniform mag field (normalized to 0.5 T)
607 // no check for scaling/polarities are done
609 sclL3 = l3 / l3NominalCurrent1;
610 } else {
611 if (TMath::Abs((sclL3 = l3 / l3NominalCurrent1) - 1.) < tolerance) {
613 } else if (TMath::Abs((sclL3 = l3 / l3NominalCurrent2) - 1.) < tolerance) {
615 } else if (l3 <= zero && dip <= zero) {
616 sclL3 = 0;
617 sclDip = 0;
619 } else {
620 if (!overrideL3) {
621 LOG(fatal) << "MagneticField::createFieldMap: Wrong L3 current (" << l3sav << " A)!";
622 } else {
623 if (!warnL3Done) {
624 LOGP(error, "L3 current was overridden to unsupported value {}", l3sav);
625 warnL3Done = true;
626 }
628 sclL3 = l3 / l3NominalCurrent1;
629 }
630 }
631 }
632 if (sclDip != 0 && map != MagFieldParam::k5kGUniform) {
633 if ((l3 <= zero) ||
634 ((convention == kConvLHC && l3Pol != diPol) || (convention == kConvDCS2008 && l3Pol == diPol))) {
635 if (overrideL3 || overrideDIP) {
636 if (!warnPolarityDone) {
637 LOG(error) << "Overriden currents have wrong combination for L3/Dipole polarities ("
638 << (l3Pol > 0 ? '+' : '-') << "/" << (diPol > 0 ? '+' : '-') << ") for convention "
640 warnPolarityDone = true;
641 }
642 } else {
643 LOG(fatal) << "MagneticField::createFieldMap: Wrong combination for L3/Dipole polarities ("
644 << (l3Pol > 0 ? '+' : '-') << "/" << (diPol > 0 ? '+' : '-') << ") for convention "
646 }
647 }
648 }
649 l3 = (l3Pol < 0) ? -sclL3 : sclL3;
650 dip = (diPol < 0) ? -sclDip : sclDip;
651 return map;
652}
653
654MagneticField* MagneticField::createFieldMap(float l3Cur, float diCur, Int_t convention, Bool_t uniform,
655 float beamenergy, const Char_t* beamtype, const std::string path)
656{
657 float sclL3 = l3Cur, sclDip = diCur;
658 MagFieldParam::BMap_t map = getFieldMapScale(sclL3, sclDip, uniform);
660 TString btypestr = beamtype;
661 btypestr.ToLower();
662 TPRegexp protonBeam(R"((proton|p)\s*-?\s*\1)");
663 TPRegexp ionBeam(R"((lead|pb|ion|a|A)\s*-?\s*\1)");
664 TPRegexp protonionBeam(R"((proton|p)\s*-?\s*(lead|pb|ion|a|A))");
665 TPRegexp ionprotonBeam(R"((lead|pb|ion|a|A)\s*-?\s*(proton|p))");
666 if (btypestr.Contains(ionBeam)) {
668 } else if (btypestr.Contains(protonBeam)) {
670 } else if (btypestr.Contains(protonionBeam)) {
672 } else if (btypestr.Contains(ionprotonBeam)) {
674 } else {
675 LOG(info) << "Assume no LHC magnet field for the beam type " << beamtype;
676 }
677 char ttl[80];
678 snprintf(ttl, 79, "L3: %+5d Dip: %+4d kA; %s | Polarities in %s convention", (int)TMath::Sign(l3Cur, float(sclL3)),
679 (int)TMath::Sign(diCur, float(sclDip)), uniform ? " Constant" : "",
680 convention == kConvLHC ? "LHC" : "DCS2008");
681 // LHC and DCS08 conventions have opposite dipole polarities
682 if (getPolarityConvention() != convention) {
683 sclDip = -sclDip;
684 }
685
686 return new MagneticField("MagneticFieldMap", ttl, sclL3, sclDip, map, btype, beamenergy, 2, 10., path);
687}
688
690{
691 const char* beamNA = "No Beam";
692 const char* beamPP = "p-p";
693 const char* beamPbPb = "A-A";
694 const char* beamPPb = "p-A";
695 const char* beamPbP = "A-p";
696 switch (mBeamType) {
698 return beamPP;
700 return beamPbPb;
702 return beamPPb;
704 return beamPbP;
706 default:
707 return beamNA;
708 }
709}
710
711void MagneticField::Print(Option_t* opt) const
712{
713 TString opts = opt;
714 opts.ToLower();
715 LOG(info) << "MagneticField::Print: " << GetName() << ":" << GetTitle();
716 LOG(info) << "MagneticField::Print: Solenoid (" << getFactorSolenoid() << "*)"
717 << ((mMapType == MagFieldParam::k5kG || mMapType == MagFieldParam::k5kGUniform) ? 5. : 2) << " kG, Dipole "
718 << (mDipoleOnOffFlag ? "OFF" : "ON") << " (" << getFactorDipole() << ") "
719 << (mMapType == MagFieldParam::k5kGUniform ? " |Constant Field!" : "");
720 if (opts.Contains("a")) {
721 LOG(info) << "MagneticField::Print: Machine B fields for " << getBeamTypeText() << " beam (" << mBeamEnergy
722 << " GeV): QGrad: " << mQuadrupoleGradient << " Dipole: " << mDipoleField;
723 LOG(info) << "MagneticField::Print: Uses " << getParameterName() << " of " << getDataFileName();
724 }
725}
726
728{
729 // fill field parameters
730 FairRun* fRun = FairRun::Instance();
731 FairRuntimeDb* rtdb = fRun->GetRuntimeDb();
732 MagFieldParam* par = static_cast<MagFieldParam*>(rtdb->getContainer("MagFieldParam"));
733 par->SetParam(this);
734 par->setChanged();
735}
736
737//_____________________________________________________________________________
739{
740 if (v) {
741 if (!mFastField) {
742 mFastField = std::make_unique<MagFieldFast>(getFactorSolenoid(), mMapType == MagFieldParam::k2kG ? 2 : 5);
743 }
744 } else {
745 mFastField.reset(nullptr);
746 }
747}
748
749//_____________________________________________________________________________
751{
752 // posibility to globally bias all data members with the proper env.var
753 if (const auto* biasString = std::getenv("O2_DPL_FIELDORIGINBIAS"); biasString && *biasString) {
755 }
756 gOriginBias = &FieldOriginBiasParam::Instance();
757 LOGP(info, "Field origin is set to: XYZ: {:.4f},{:.4f},{:.4f}", gOriginBias->x, gOriginBias->y, gOriginBias->z);
758}
int32_t i
ClassImp(MagneticField)
Definition of the MagF class.
static void updateFromString(std::string const &)
static MagFieldParam::BMap_t getFieldMapScale(float &l3, float &dip, bool uniform, int convention=0)
Double_t getBz(const Double_t *xyz) const
Method to calculate the field at point xyz.
Double_t getFactorDipole() const
Return the sign*scale of the current in the Dipole according to sPolarityConventionthe.
void getTPCRatIntegralCylindrical(const Double_t *rphiz, Double_t *b) const
void MachineField(const Double_t *__restrict__ x, Double_t *__restrict__ b) const
const char * getBeamTypeText() const
Returns beam type in text form.
void getTPCRatIntegral(const Double_t *xyz, Double_t *b) const
Method to calculate the integral_0^z of br,bt,bz.
void rescaleField(float l3Cur, float diCur, bool uniform, int convention=0)
void getTPCIntegralCylindrical(const Double_t *rphiz, Double_t *b) const
Method to calculate the integral_0^z of br,bt,bz in cylindrical coordinates ( -pi<phi<pi convention )
Char_t * getDataFileName() const
void setDataFileName(const Char_t *nm)
static MagneticField * createFieldMap(float l3Current=-30000., float diCurrent=-6000., Int_t convention=0, Bool_t uniform=kFALSE, float beamenergy=7000, const Char_t *btype="pp", const std::string path=std::string(gSystem->Getenv("VMCWORKDIR"))+std::string("/Common/maps/mfchebKGI_sym.root"))
void setFactorDipole(float fc=1.)
Sets the sign*scale of the current in the Dipole according to sPolarityConvention.
MagneticField & operator=(const MagneticField &src)
void AllowFastField(bool v=true)
allow fast field param
void FillParContainer() override
Fill Paramater.
Double_t getFactorSolenoid() const
Returns the sign*scale of the current in the Dipole according to sPolarityConventionthe.
static Int_t getPolarityConvention()
void Field(const Double_t *__restrict__ point, Double_t *__restrict__ bField) override
void getTPCIntegral(const Double_t *xyz, Double_t *b) const
Method to calculate the integral_0^z of br,bt,bz.
void setParameterName(const Char_t *nm)
void Print(Option_t *opt) const override
Prints short or long info.
Char_t * getParameterName() const
MagneticField()
Default constructor.
void setFactorSolenoid(float fc=1.)
Sets the sign/scale of the current in the L3 according to sPolarityConvention.
void CreateField()
real field creation is here
static MagneticField * createNominalField(int fld, bool uniform=false)
create field from rounded value, i.e. +-5 or +-2 kGauss
void initializeMachineField(MagFieldParam::BeamType_t btype, Double_t benergy)
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum src
Definition glcorearb.h:1767
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLenum GLfloat param
Definition glcorearb.h:271
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"