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(factorSol),
112 mMultipicativeFactorDipole(factorDip),
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 setDataFileName(path.c_str());
126 if (!gOriginBias) {
128 }
129 CreateField();
130}
131
133 : FairField(param.GetName(), param.GetTitle()),
134 mMeasuredMap(nullptr),
135 mFastField(nullptr),
136 mMapType(param.GetMapType()),
137 mSolenoid(0),
138 mBeamType(param.GetBeamType()),
139 mBeamEnergy(param.GetBeamEnergy()),
140 mDefaultIntegration(param.GetDefInt()),
141 mPrecisionInteg(1),
142 mMultipicativeFactorSolenoid(param.GetFactorSol()), // temporary
143 mMultipicativeFactorDipole(param.GetFactorDip()), // temporary
144 mMaxField(param.GetMaxField()),
145 mDipoleOnOffFlag(param.GetFactorDip() == 0.),
146 mQuadrupoleGradient(0),
147 mDipoleField(0),
148 mCompensatorField2C(0),
149 mCompensatorField1A(0),
150 mCompensatorField2A(0),
151 mParameterNames("", "")
152{
153 /*
154 * Constructor for FairParam derived params
155 */
156 setDataFileName(param.GetMapPath());
157 if (!gOriginBias) {
159 }
160 CreateField();
161}
162
164{
165 float fldCoeffL3, fldCoeffDip;
167 if (uniform) {
168 fldCoeffL3 = float(fld) / 5.;
169 fldCoeffDip = fld > 0 ? 1. : -1;
171 } else {
172 switch (std::abs(fld)) {
173 case 5:
175 fldCoeffL3 = fldCoeffDip = fld > 0 ? 1. : -1;
176 break;
177 case 0:
179 fldCoeffL3 = fldCoeffDip = 0;
180 break;
181 case 2:
183 fldCoeffL3 = fldCoeffDip = fld > 0 ? 1. : -1;
184 break;
185 default:
186 LOG(fatal) << "Field option " << fld << " is not supported, use +-2, +-5 or 0 or <int_kilogauss>U";
187 };
188 }
189 return new o2::field::MagneticField("Maps", "Maps", fldCoeffL3, fldCoeffDip, fldType);
190}
191
193{
194 /*
195 * field initialization
196 */
197
198 fType = 2; // flag non-constant field
199
200 // does real creation of the field
201 if (mDefaultIntegration < 0 || mDefaultIntegration > 2) {
202 LOG(warning) << "MagneticField::CreateField: Invalid magnetic field flag: " << mDefaultIntegration
203 << "; Helix tracking chosen instead";
204 mDefaultIntegration = 2;
205 }
206 if (mDefaultIntegration == 0) {
207 mPrecisionInteg = 0;
208 }
209
210 if (mBeamEnergy <= 0 && mBeamType != MagFieldParam::kNoBeamField) {
211 if (mBeamType == MagFieldParam::kBeamTypepp) {
212 mBeamEnergy = 7000.; // max proton energy
213 } else if (mBeamType == MagFieldParam::kBeamTypeAA) {
214 mBeamEnergy = 2760; // max PbPb energy
215 } else if (mBeamType == MagFieldParam::kBeamTypepA || mBeamType == MagFieldParam::kBeamTypeAp) {
216 mBeamEnergy = 2760; // same rigitiy max PbPb energy
217 }
218 //
219 LOG(info) << "MagneticField::CreateField: Maximim possible beam energy for requested beam is assumed";
220 }
221
222 const char* parname = nullptr;
223
224 if (mMapType == MagFieldParam::k2kG) {
225 parname = mDipoleOnOffFlag ? "Sol12_Dip0_Hole" : "Sol12_Dip6_Hole";
226 } else if (mMapType == MagFieldParam::k5kG) {
227 parname = mDipoleOnOffFlag ? "Sol30_Dip0_Hole" : "Sol30_Dip6_Hole";
228 } else if (mMapType == MagFieldParam::k5kGUniform) {
229 parname = "Sol30_Dip6_Uniform";
230 } else {
231 LOG(fatal) << "MagneticField::CreateField: Unknown field identifier " << mMapType << " is requested\n";
232 }
233
234 setParameterName(parname);
235
237 initializeMachineField(mBeamType, mBeamEnergy);
238 setFactorSolenoid(mMultipicativeFactorSolenoid);
239 setFactorDipole(mMultipicativeFactorDipole);
240 double xyz[3] = {0., 0., 0.};
241 mSolenoid = getBz(xyz);
242 Print("a");
243 //
244}
245
247{
248 /*
249 * load parametrization for measured field
250 */
251
252 if (mMeasuredMap) {
253 LOG(fatal) << "MagneticField::loadParameterization: Field data " << getParameterName()
254 << " are already loaded from " << getDataFileName() << "\n";
255 }
256 TString fname = getDataFileName();
257 gSystem->ExpandPathName(fname);
258 TFile* file = TFile::Open(fname);
259 if (!file) {
260 LOG(fatal) << "MagneticField::loadParameterization: Failed to open magnetic field data file " << fname << "\n";
261 }
262
263 mMeasuredMap =
264 std::unique_ptr<MagneticWrapperChebyshev>(dynamic_cast<MagneticWrapperChebyshev*>(file->Get(getParameterName())));
265 if (!mMeasuredMap) {
266 LOG(fatal) << "MagneticField::loadParameterization: Did not find field " << getParameterName() << " in " << fname
267 << "%s\n";
268 }
269 file->Close();
270 delete file;
271 return kTRUE;
272}
273
274void MagneticField::Field(const Double_t* __restrict__ xyzExt, Double_t* __restrict__ b)
275{
276 /*
277 * query field value at point
278 */
279 double xyz[3] = {xyzExt[0] - gOriginBias->x, xyzExt[1] - gOriginBias->y, xyzExt[2] - gOriginBias->z};
280 // b[0]=b[1]=b[2]=0.0;
281 if (mFastField && mFastField->Field(xyz, b)) {
282 return;
283 }
284
285 if (mMeasuredMap && xyz[2] > mMeasuredMap->getMinZ() && xyz[2] < mMeasuredMap->getMaxZ()) {
286 mMeasuredMap->Field(xyz, b);
287 if (xyz[2] > sSolenoidToDipoleZ || mDipoleOnOffFlag) {
288 for (int i = 3; i--;) {
289 b[i] *= mMultipicativeFactorSolenoid;
290 }
291 } else {
292 for (int i = 3; i--;) {
293 b[i] *= mMultipicativeFactorDipole;
294 }
295 }
296 } else {
297 MachineField(xyz, b);
298 }
299}
300
301Double_t MagneticField::getBz(const Double_t* xyzExt) const
302{
303 /*
304 * query field Bz component at point
305 */
306 double xyz[3] = {xyzExt[0] - gOriginBias->x, xyzExt[1] - gOriginBias->y, xyzExt[2] - gOriginBias->z};
307 if (mFastField) {
308 double bz = 0;
309 if (mFastField->GetBz(xyz, bz)) {
310 return bz;
311 }
312 }
313 if (mMeasuredMap && xyz[2] > mMeasuredMap->getMinZ() && xyz[2] < mMeasuredMap->getMaxZ()) {
314 double bz = mMeasuredMap->getBz(xyz);
315 return (xyz[2] > sSolenoidToDipoleZ || mDipoleOnOffFlag) ? bz * mMultipicativeFactorSolenoid
316 : bz * mMultipicativeFactorDipole;
317 } else {
318 return 0.;
319 }
320}
321
323{
324 /*
325 * assignment operator
326 */
327
328 if (this != &src) {
329 if (src.mMeasuredMap) {
330 mMeasuredMap.reset(new MagneticWrapperChebyshev(*src.getMeasuredMap()));
331 }
332 SetName(src.GetName());
333 mSolenoid = src.mSolenoid;
334 mBeamType = src.mBeamType;
335 mBeamEnergy = src.mBeamEnergy;
336 mDefaultIntegration = src.mDefaultIntegration;
337 mPrecisionInteg = src.mPrecisionInteg;
338 mMultipicativeFactorSolenoid = src.mMultipicativeFactorSolenoid;
339 mMultipicativeFactorDipole = src.mMultipicativeFactorDipole;
340 mMaxField = src.mMaxField;
341 mDipoleOnOffFlag = src.mDipoleOnOffFlag;
342 mParameterNames = src.mParameterNames;
343 mFastField.reset(src.mFastField ? new MagFieldFast(*src.getFastField()) : nullptr);
344 }
345 return *this;
346}
347
349{
350 if (btype == MagFieldParam::kNoBeamField) {
351 mQuadrupoleGradient = mDipoleField = mCompensatorField2C = mCompensatorField1A = mCompensatorField2A = 0.;
352 return;
353 }
354
355 double rigScale = benergy / 7000.; // scale according to ratio of E/Enominal
356 // for ions assume PbPb (with energy provided per nucleon) and account for A/Z
357 if (btype == MagFieldParam::kBeamTypeAA /* || btype==kBeamTypepA || btype==kBeamTypeAp */) {
358 rigScale *= 208. / 82.;
359 }
360 // Attention: in p-Pb the energy recorded in the GRP is the PROTON energy, no rigidity
361 // rescaling is needed
362
363 mQuadrupoleGradient = 22.0002 * rigScale;
364 mDipoleField = 37.8781 * rigScale;
365
366 // SIDE C
367 mCompensatorField2C = -9.6980;
368 // SIDE A
369 mCompensatorField1A = -13.2247;
370 mCompensatorField2A = 11.7905;
371}
372
373void MagneticField::MachineField(const Double_t* __restrict__ x, Double_t* __restrict__ b) const
374{
375 // ---- This is the ZDC part
376 // Compansators for Alice Muon Arm Dipole
377 const Double_t kBComp1CZ = 1075., kBComp1hDZ = 260. / 2., kBComp1SqR = 4.0 * 4.0;
378 const Double_t kBComp2CZ = 2049., kBComp2hDZ = 153. / 2., kBComp2SqR = 4.5 * 4.5;
379
380 const Double_t kTripQ1CZ = 2615., kTripQ1hDZ = 637. / 2., kTripQ1SqR = 3.5 * 3.5;
381 const Double_t kTripQ2CZ = 3480., kTripQ2hDZ = 550. / 2., kTripQ2SqR = 3.5 * 3.5;
382 const Double_t kTripQ3CZ = 4130., kTripQ3hDZ = 550. / 2., kTripQ3SqR = 3.5 * 3.5;
383 const Double_t kTripQ4CZ = 5015., kTripQ4hDZ = 637. / 2., kTripQ4SqR = 3.5 * 3.5;
384
385 const Double_t kDip1CZ = 6310.8, kDip1hDZ = 945. / 2., kDip1SqRC = 4.5 * 4.5, kDip1SqRA = 3.375 * 3.375;
386 const Double_t kDip2CZ = 12640.3, kDip2hDZ = 945. / 2., kDip2SqRC = 4.5 * 4.5, kDip2SqRA = 3.75 * 3.75;
387 const Double_t kDip2DXC = 9.7, kDip2DXA = 9.4;
388
389 double rad2 = x[0] * x[0] + x[1] * x[1];
390
391 b[0] = b[1] = b[2] = 0;
392
393 // SIDE C
394 if (x[2] < 0.) {
395 if (TMath::Abs(x[2] + kBComp2CZ) < kBComp2hDZ && rad2 < kBComp2SqR) {
396 b[0] = mCompensatorField2C * mMultipicativeFactorDipole;
397 } else if (TMath::Abs(x[2] + kTripQ1CZ) < kTripQ1hDZ && rad2 < kTripQ1SqR) {
398 b[0] = mQuadrupoleGradient * x[1];
399 b[1] = mQuadrupoleGradient * x[0];
400 } else if (TMath::Abs(x[2] + kTripQ2CZ) < kTripQ2hDZ && rad2 < kTripQ2SqR) {
401 b[0] = -mQuadrupoleGradient * x[1];
402 b[1] = -mQuadrupoleGradient * x[0];
403 } else if (TMath::Abs(x[2] + kTripQ3CZ) < kTripQ3hDZ && rad2 < kTripQ3SqR) {
404 b[0] = -mQuadrupoleGradient * x[1];
405 b[1] = -mQuadrupoleGradient * x[0];
406 } else if (TMath::Abs(x[2] + kTripQ4CZ) < kTripQ4hDZ && rad2 < kTripQ4SqR) {
407 b[0] = mQuadrupoleGradient * x[1];
408 b[1] = mQuadrupoleGradient * x[0];
409 } else if (TMath::Abs(x[2] + kDip1CZ) < kDip1hDZ && rad2 < kDip1SqRC) {
410 b[1] = mDipoleField;
411 } else if (TMath::Abs(x[2] + kDip2CZ) < kDip2hDZ && rad2 < kDip2SqRC) {
412 double dxabs = TMath::Abs(x[0]) - kDip2DXC;
413 if ((dxabs * dxabs + x[1] * x[1]) < kDip2SqRC) {
414 b[1] = -mDipoleField;
415 }
416 }
417 }
418
419 // SIDE A
420 else {
421 if (TMath::Abs(x[2] - kBComp1CZ) < kBComp1hDZ && rad2 < kBComp1SqR) {
422 // Compensator magnet at z = 1075 m
423 b[0] = mCompensatorField1A * mMultipicativeFactorDipole;
424 }
425
426 if (TMath::Abs(x[2] - kBComp2CZ) < kBComp2hDZ && rad2 < kBComp2SqR) {
427 b[0] = mCompensatorField2A * mMultipicativeFactorDipole;
428 } else if (TMath::Abs(x[2] - kTripQ1CZ) < kTripQ1hDZ && rad2 < kTripQ1SqR) {
429 b[0] = -mQuadrupoleGradient * x[1];
430 b[1] = -mQuadrupoleGradient * x[0];
431 } else if (TMath::Abs(x[2] - kTripQ2CZ) < kTripQ2hDZ && rad2 < kTripQ2SqR) {
432 b[0] = mQuadrupoleGradient * x[1];
433 b[1] = mQuadrupoleGradient * x[0];
434 } else if (TMath::Abs(x[2] - kTripQ3CZ) < kTripQ3hDZ && rad2 < kTripQ3SqR) {
435 b[0] = mQuadrupoleGradient * x[1];
436 b[1] = mQuadrupoleGradient * x[0];
437 } else if (TMath::Abs(x[2] - kTripQ4CZ) < kTripQ4hDZ && rad2 < kTripQ4SqR) {
438 b[0] = -mQuadrupoleGradient * x[1];
439 b[1] = -mQuadrupoleGradient * x[0];
440 } else if (TMath::Abs(x[2] - kDip1CZ) < kDip1hDZ && rad2 < kDip1SqRA) {
441 b[1] = -mDipoleField;
442 } else if (TMath::Abs(x[2] - kDip2CZ) < kDip2hDZ && rad2 < kDip2SqRA) {
443 double dxabs = TMath::Abs(x[0]) - kDip2DXA;
444 if ((dxabs * dxabs + x[1] * x[1]) < kDip2SqRA) {
445 b[1] = mDipoleField;
446 }
447 }
448 }
449}
450
451void MagneticField::getTPCIntegral(const Double_t* xyz, Double_t* b) const
452{
453 b[0] = b[1] = b[2] = 0.0;
454 if (mMeasuredMap) {
455 mMeasuredMap->getTPCIntegral(xyz, b);
456 for (int i = 3; i--;) {
457 b[i] *= mMultipicativeFactorSolenoid;
458 }
459 }
460}
461
462void MagneticField::getTPCRatIntegral(const Double_t* xyz, Double_t* b) const
463{
464 b[0] = b[1] = b[2] = 0.0;
465 if (mMeasuredMap) {
466 mMeasuredMap->getTPCRatIntegral(xyz, b);
467 b[2] /= 100;
468 }
469}
470
471void MagneticField::getTPCIntegralCylindrical(const Double_t* rphiz, Double_t* b) const
472{
473 b[0] = b[1] = b[2] = 0.0;
474 if (mMeasuredMap) {
475 mMeasuredMap->getTPCIntegralCylindrical(rphiz, b);
476 for (int i = 3; i--;) {
477 b[i] *= mMultipicativeFactorSolenoid;
478 }
479 }
480}
481
482void MagneticField::getTPCRatIntegralCylindrical(const Double_t* rphiz, Double_t* b) const
483{
484 b[0] = b[1] = b[2] = 0.0;
485 if (mMeasuredMap) {
486 mMeasuredMap->getTPCRatIntegralCylindrical(rphiz, b);
487 b[2] /= 100;
488 }
489}
490
492{
493 switch (sPolarityConvention) {
494 case kConvDCS2008:
495 mMultipicativeFactorSolenoid = -fc;
496 break;
497 case kConvLHC:
498 mMultipicativeFactorSolenoid = -fc;
499 break;
500 default:
501 mMultipicativeFactorSolenoid = fc;
502 break; // case kConvMap2005: mMultipicativeFactorSolenoid = fc; break;
503 }
504 if (mFastField) {
505 mFastField->setFactorSol(getFactorSolenoid());
506 }
507}
508
510{
511 switch (sPolarityConvention) {
512 case kConvDCS2008:
513 mMultipicativeFactorDipole = fc;
514 break;
515 case kConvLHC:
516 mMultipicativeFactorDipole = -fc;
517 break;
518 default:
519 mMultipicativeFactorDipole = fc;
520 break; // case kConvMap2005: mMultipicativeFactorDipole = fc; break;
521 }
522}
523
525{
526 switch (sPolarityConvention) {
527 case kConvDCS2008:
528 return -mMultipicativeFactorSolenoid;
529 case kConvLHC:
530 return -mMultipicativeFactorSolenoid;
531 default:
532 return mMultipicativeFactorSolenoid; // case kConvMap2005: return mMultipicativeFactorSolenoid;
533 }
534}
535
537{
538 switch (sPolarityConvention) {
539 case kConvDCS2008:
540 return mMultipicativeFactorDipole;
541 case kConvLHC:
542 return -mMultipicativeFactorDipole;
543 default:
544 return mMultipicativeFactorDipole; // case kConvMap2005: return mMultipicativeFactorDipole;
545 }
546}
547
548void MagneticField::rescaleField(float l3Cur, float diCur, bool uniform, int convention)
549{
550 // this function taks as input magnet currents and rescales existing field if the map is compatible
551 float sclL3 = l3Cur, sclDip = diCur;
552 MagFieldParam::BMap_t map = getFieldMapScale(sclL3, sclDip, uniform);
553 if (map != mMapType) {
554 LOGP(fatal, "Provided L3current={} DipCurrent={} uniform={} leads to map type {}, incompatible with loaded {}", l3Cur, diCur, uniform, (int)map, (int)mMapType);
555 }
556 setFactorSolenoid(sclL3);
557 setFactorDipole(sclDip);
558 LOGP(info, "Updating magnetic field: L3current={} DipCurrent={} uniform={}", l3Cur, diCur, uniform);
559}
560
561MagFieldParam::BMap_t MagneticField::getFieldMapScale(float& l3, float& dip, bool uniform, int convention)
562{
563 // this function taks as input magnet currents and returns the field type and scalings for L3 and dipole
564 const float l3NominalCurrent1 = 30000.f; // (A)
565 const float l3NominalCurrent2 = 12000.f; // (A)
566 const float diNominalCurrent = 6000.f; // (A)
567
568 const float tolerance = 0.03; // relative current tolerance
569 const float zero = 77.f; // "zero" current (A)
570
572 float sclL3, sclDip;
573 float l3sav = l3, dipsav = dip;
574
575 float l3Pol = l3 > 0 ? 1 : -1;
576 float diPol = dip > 0 ? 1 : -1;
577
578 l3 = TMath::Abs(l3);
579 dip = TMath::Abs(dip);
580 static bool overrideL3 = std::getenv("O2_OVERRIDE_L3_CURRENT") != nullptr;
581 static bool overrideDIP = std::getenv("O2_OVERRIDE_DIPOLE_CURRENT") != nullptr;
582 static bool warnL3Done = false, warnDipDone = false, warnPolarityDone = false;
583
584 if (TMath::Abs((sclDip = dip / diNominalCurrent) - 1.) > tolerance && !uniform) {
585 if (dip <= zero) {
586 sclDip = 0.; // some small current.. -> Dipole OFF
587 } else {
588 if (!overrideDIP) {
589 LOG(fatal) << "MagneticField::createFieldMap: Wrong dipole current (" << dipsav << " A)!";
590 } else {
591 if (!warnDipDone) {
592 LOGP(error, "Dipole current was overridden to unsupported value {}", dipsav);
593 warnDipDone = true;
594 }
595 }
596 }
597 }
598 if (uniform) {
599 // special treatment of special MC with uniform mag field (normalized to 0.5 T)
600 // no check for scaling/polarities are done
602 sclL3 = l3 / l3NominalCurrent1;
603 } else {
604 if (TMath::Abs((sclL3 = l3 / l3NominalCurrent1) - 1.) < tolerance) {
606 } else if (TMath::Abs((sclL3 = l3 / l3NominalCurrent2) - 1.) < tolerance) {
608 } else if (l3 <= zero && dip <= zero) {
609 sclL3 = 0;
610 sclDip = 0;
612 } else {
613 if (!overrideL3) {
614 LOG(fatal) << "MagneticField::createFieldMap: Wrong L3 current (" << l3sav << " A)!";
615 } else {
616 if (!warnL3Done) {
617 LOGP(error, "L3 current was overridden to unsupported value {}", l3sav);
618 warnL3Done = true;
619 }
621 sclL3 = l3 / l3NominalCurrent1;
622 }
623 }
624 }
625 if (sclDip != 0 && map != MagFieldParam::k5kGUniform) {
626 if ((l3 <= zero) ||
627 ((convention == kConvLHC && l3Pol != diPol) || (convention == kConvDCS2008 && l3Pol == diPol))) {
628 if (overrideL3 || overrideDIP) {
629 if (!warnPolarityDone) {
630 LOG(error) << "Overriden currents have wrong combination for L3/Dipole polarities ("
631 << (l3Pol > 0 ? '+' : '-') << "/" << (diPol > 0 ? '+' : '-') << ") for convention "
633 warnPolarityDone = true;
634 }
635 } else {
636 LOG(fatal) << "MagneticField::createFieldMap: Wrong combination for L3/Dipole polarities ("
637 << (l3Pol > 0 ? '+' : '-') << "/" << (diPol > 0 ? '+' : '-') << ") for convention "
639 }
640 }
641 }
642 l3 = (l3Pol < 0) ? -sclL3 : sclL3;
643 dip = (diPol < 0) ? -sclDip : sclDip;
644 return map;
645}
646
647MagneticField* MagneticField::createFieldMap(float l3Cur, float diCur, Int_t convention, Bool_t uniform,
648 float beamenergy, const Char_t* beamtype, const std::string path)
649{
650 float sclL3 = l3Cur, sclDip = diCur;
651 MagFieldParam::BMap_t map = getFieldMapScale(sclL3, sclDip, uniform);
653 TString btypestr = beamtype;
654 btypestr.ToLower();
655 TPRegexp protonBeam(R"((proton|p)\s*-?\s*\1)");
656 TPRegexp ionBeam(R"((lead|pb|ion|a|A)\s*-?\s*\1)");
657 TPRegexp protonionBeam(R"((proton|p)\s*-?\s*(lead|pb|ion|a|A))");
658 TPRegexp ionprotonBeam(R"((lead|pb|ion|a|A)\s*-?\s*(proton|p))");
659 if (btypestr.Contains(ionBeam)) {
661 } else if (btypestr.Contains(protonBeam)) {
663 } else if (btypestr.Contains(protonionBeam)) {
665 } else if (btypestr.Contains(ionprotonBeam)) {
667 } else {
668 LOG(info) << "Assume no LHC magnet field for the beam type " << beamtype;
669 }
670 char ttl[80];
671 snprintf(ttl, 79, "L3: %+5d Dip: %+4d kA; %s | Polarities in %s convention", (int)TMath::Sign(l3Cur, float(sclL3)),
672 (int)TMath::Sign(diCur, float(sclDip)), uniform ? " Constant" : "",
673 convention == kConvLHC ? "LHC" : "DCS2008");
674 // LHC and DCS08 conventions have opposite dipole polarities
675 if (getPolarityConvention() != convention) {
676 sclDip = -sclDip;
677 }
678
679 return new MagneticField("MagneticFieldMap", ttl, sclL3, sclDip, map, btype, beamenergy, 2, 10., path);
680}
681
683{
684 const char* beamNA = "No Beam";
685 const char* beamPP = "p-p";
686 const char* beamPbPb = "A-A";
687 const char* beamPPb = "p-A";
688 const char* beamPbP = "A-p";
689 switch (mBeamType) {
691 return beamPP;
693 return beamPbPb;
695 return beamPPb;
697 return beamPbP;
699 default:
700 return beamNA;
701 }
702}
703
704void MagneticField::Print(Option_t* opt) const
705{
706 TString opts = opt;
707 opts.ToLower();
708 LOG(info) << "MagneticField::Print: " << GetName() << ":" << GetTitle();
709 LOG(info) << "MagneticField::Print: Solenoid (" << getFactorSolenoid() << "*)"
710 << ((mMapType == MagFieldParam::k5kG || mMapType == MagFieldParam::k5kGUniform) ? 5. : 2) << " kG, Dipole "
711 << (mDipoleOnOffFlag ? "OFF" : "ON") << " (" << getFactorDipole() << ") "
712 << (mMapType == MagFieldParam::k5kGUniform ? " |Constant Field!" : "");
713 if (opts.Contains("a")) {
714 LOG(info) << "MagneticField::Print: Machine B fields for " << getBeamTypeText() << " beam (" << mBeamEnergy
715 << " GeV): QGrad: " << mQuadrupoleGradient << " Dipole: " << mDipoleField;
716 LOG(info) << "MagneticField::Print: Uses " << getParameterName() << " of " << getDataFileName();
717 }
718}
719
721{
722 // fill field parameters
723 FairRun* fRun = FairRun::Instance();
724 FairRuntimeDb* rtdb = fRun->GetRuntimeDb();
725 MagFieldParam* par = static_cast<MagFieldParam*>(rtdb->getContainer("MagFieldParam"));
726 par->SetParam(this);
727 par->setChanged();
728}
729
730//_____________________________________________________________________________
732{
733 if (v) {
734 if (!mFastField) {
735 mFastField = std::make_unique<MagFieldFast>(getFactorSolenoid(), mMapType == MagFieldParam::k2kG ? 2 : 5);
736 }
737 } else {
738 mFastField.reset(nullptr);
739 }
740}
741
742//_____________________________________________________________________________
744{
745 // posibility to globally bias all data members with the proper env.var
746 if (const auto* biasString = std::getenv("O2_DPL_FIELDORIGINBIAS"); biasString && *biasString) {
748 }
749 gOriginBias = &FieldOriginBiasParam::Instance();
750 LOGP(info, "Field origin is set to: XYZ: {:.4f},{:.4f},{:.4f}", gOriginBias->x, gOriginBias->y, gOriginBias->z);
751}
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"