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