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