1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
22 #include "AliMagWrapCheb.h"
27 const Double_t AliMagF::fgkSol2DipZ = -700.;
28 const UShort_t AliMagF::fgkPolarityConvention = kConvLHC;
31 Explanation for polarity conventions: these are the mapping between the
32 current signs and main field components in L3 (Bz) and Dipole (Bx) (in Alice frame)
33 1) kConvMap2005: used for the field mapping in 2005
34 positive L3 current -> negative Bz
35 positive Dip current -> positive Bx
36 2) kConvMapDCS2008: defined by the microswitches/cabling of power converters as of 2008 - 1st half 2009
37 positive L3 current -> positive Bz
38 positive Dip current -> positive Bx
39 3) kConvLHC : defined by LHC
40 positive L3 current -> negative Bz
41 positive Dip current -> negative Bx
43 Note: only "negative Bz(L3) with postive Bx(Dipole)" and its inverse was mapped in 2005. Hence
44 the GRP Manager will reject the runs with the current combinations (in the convention defined by the
45 static Int_t AliMagF::GetPolarityConvention()) which do not lead to such field polarities.
47 //_______________________________________________________________________
53 fBeamType(kNoBeamField),
70 // Default constructor
74 //_______________________________________________________________________
75 AliMagF::AliMagF(const char *name, const char* title, Int_t integ,
76 Double_t factorSol, Double_t factorDip,
77 Double_t fmax, BMap_t maptype, const char* path,
78 BeamType_t bt, Double_t be):
79 TVirtualMagField(name),
91 fDipoleOFF(factorDip==0.),
100 // Initialize the field with Geant integration option "integ" and max field "fmax,
101 // Impose scaling of parameterized L3 field by factorSol and of dipole by factorDip.
102 // The "be" is the energy of the beam in GeV/nucleon
105 if(integ<0 || integ > 2) {
106 AliWarning(Form("Invalid magnetic field flag: %5d; Helix tracking chosen instead",integ));
109 if (fInteg == 0) fPrecInteg = 0;
111 const char* parname = 0;
113 if (fMapType == k2kG) parname = fDipoleOFF ? "Sol12_Dip0_Hole":"Sol12_Dip6_Hole";
114 else if (fMapType == k5kG) parname = fDipoleOFF ? "Sol30_Dip0_Hole":"Sol30_Dip6_Hole";
115 else if (fMapType == k5kGUniform) parname = "Sol30_Dip6_Uniform";
116 else AliFatal(Form("Unknown field identifier %d is requested\n",fMapType));
118 SetDataFileName(path);
119 SetParamName(parname);
121 LoadParameterization();
122 InitMachineField(fBeamType,fBeamEnergy);
123 double xyz[3]={0.,0.,0.};
124 fSolenoid = GetBz(xyz);
125 SetFactorSol(factorSol);
126 SetFactorDip(factorDip);
129 //_______________________________________________________________________
130 AliMagF::AliMagF(const AliMagF &src):
131 TVirtualMagField(src),
133 fMapType(src.fMapType),
134 fSolenoid(src.fSolenoid),
135 fBeamType(src.fBeamType),
136 fBeamEnergy(src.fBeamEnergy),
138 fPrecInteg(src.fPrecInteg),
139 fFactorSol(src.fFactorSol),
140 fFactorDip(src.fFactorDip),
142 fDipoleOFF(src.fDipoleOFF),
143 fQuadGradient(src.fQuadGradient),
144 fDipoleField(src.fDipoleField),
145 fCCorrField(src.fCCorrField),
146 fACorr1Field(src.fACorr1Field),
147 fACorr2Field(src.fACorr2Field),
148 fParNames(src.fParNames)
150 if (src.fMeasuredMap) fMeasuredMap = new AliMagWrapCheb(*src.fMeasuredMap);
153 //_______________________________________________________________________
159 //_______________________________________________________________________
160 Bool_t AliMagF::LoadParameterization()
163 AliError(Form("Field data %s are already loaded from %s\n",GetParamName(),GetDataFileName()));
167 char* fname = gSystem->ExpandPathName(GetDataFileName());
168 TFile* file = TFile::Open(fname);
170 AliError(Form("Failed to open magnetic field data file %s\n",fname));
174 fMeasuredMap = dynamic_cast<AliMagWrapCheb*>(file->Get(GetParamName()));
176 AliError(Form("Did not find field %s in %s\n",GetParamName(),fname));
185 //_______________________________________________________________________
186 void AliMagF::Field(const Double_t *xyz, Double_t *b)
188 // Method to calculate the field at point xyz
190 // b[0]=b[1]=b[2]=0.0;
191 if (fMeasuredMap && xyz[2]>fMeasuredMap->GetMinZ() && xyz[2]<fMeasuredMap->GetMaxZ()) {
192 fMeasuredMap->Field(xyz,b);
193 if (xyz[2]>fgkSol2DipZ || fDipoleOFF) for (int i=3;i--;) b[i] *= fFactorSol;
194 else for (int i=3;i--;) b[i] *= fFactorDip;
196 else MachineField(xyz, b);
200 //_______________________________________________________________________
201 Double_t AliMagF::GetBz(const Double_t *xyz) const
203 // Method to calculate the field at point xyz
205 if (fMeasuredMap && xyz[2]>fMeasuredMap->GetMinZ() && xyz[2]<fMeasuredMap->GetMaxZ()) {
206 double bz = fMeasuredMap->GetBz(xyz);
207 return (xyz[2]>fgkSol2DipZ || fDipoleOFF) ? bz*fFactorSol : bz*fFactorDip;
212 //_______________________________________________________________________
213 AliMagF& AliMagF::operator=(const AliMagF& src)
215 if (this != &src && src.fMeasuredMap) {
216 if (fMeasuredMap) delete fMeasuredMap;
217 fMeasuredMap = new AliMagWrapCheb(*src.fMeasuredMap);
218 SetName(src.GetName());
219 fSolenoid = src.fSolenoid;
220 fBeamType = src.fBeamType;
221 fBeamEnergy = src.fBeamEnergy;
223 fPrecInteg = src.fPrecInteg;
224 fFactorSol = src.fFactorSol;
225 fFactorDip = src.fFactorDip;
227 fDipoleOFF = src.fDipoleOFF;
228 fParNames = src.fParNames;
233 //_______________________________________________________________________
234 void AliMagF::InitMachineField(BeamType_t btype, Double_t benergy)
236 if (btype==kNoBeamField || benergy<1.) {
237 fQuadGradient = fDipoleField = fCCorrField = fACorr1Field = fACorr2Field = 0.;
241 double rigScale = benergy/7000.; // scale according to ratio of E/Enominal
242 // for ions assume PbPb (with energy provided per nucleon) and account for A/Z
243 if (btype == kBeamTypeAA) rigScale *= 208./82.;
245 fQuadGradient = 22.0002*rigScale;
246 fDipoleField = 37.8781*rigScale;
249 fCCorrField = -9.6980;
251 fACorr1Field = -13.2247;
252 fACorr2Field = 11.7905;
256 //_______________________________________________________________________
257 void AliMagF::MachineField(const Double_t *x, Double_t *b) const
259 // ---- This is the ZDC part
260 // Compansators for Alice Muon Arm Dipole
261 const Double_t kBComp1CZ = 1075., kBComp1hDZ = 260./2., kBComp1SqR = 4.0*4.0;
262 const Double_t kBComp2CZ = 2049., kBComp2hDZ = 153./2., kBComp2SqR = 4.5*4.5;
264 const Double_t kTripQ1CZ = 2615., kTripQ1hDZ = 637./2., kTripQ1SqR = 3.5*3.5;
265 const Double_t kTripQ2CZ = 3480., kTripQ2hDZ = 550./2., kTripQ2SqR = 3.5*3.5;
266 const Double_t kTripQ3CZ = 4130., kTripQ3hDZ = 550./2., kTripQ3SqR = 3.5*3.5;
267 const Double_t kTripQ4CZ = 5015., kTripQ4hDZ = 637./2., kTripQ4SqR = 3.5*3.5;
269 const Double_t kDip1CZ = 6310.8, kDip1hDZ = 945./2., kDip1SqRC = 4.5*4.5, kDip1SqRA = 3.375*3.375;
270 const Double_t kDip2CZ = 12640.3, kDip2hDZ = 945./2., kDip2SqRC = 4.5*4.5, kDip2SqRA = 3.75*3.75;
271 const Double_t kDip2DXC = 9.7, kDip2DXA = 9.4;
273 double rad2 = x[0] * x[0] + x[1] * x[1];
275 b[0] = b[1] = b[2] = 0;
277 // SIDE C **************************************************
279 if(TMath::Abs(x[2]+kBComp2CZ)<kBComp2hDZ && rad2 < kBComp2SqR){
280 b[0] = fCCorrField*fFactorDip;
282 else if(TMath::Abs(x[2]+kTripQ1CZ)<kTripQ1hDZ && rad2 < kTripQ1SqR){
283 b[0] = fQuadGradient*x[1];
284 b[1] = fQuadGradient*x[0];
286 else if(TMath::Abs(x[2]+kTripQ2CZ)<kTripQ2hDZ && rad2 < kTripQ2SqR){
287 b[0] = -fQuadGradient*x[1];
288 b[1] = -fQuadGradient*x[0];
290 else if(TMath::Abs(x[2]+kTripQ3CZ)<kTripQ3hDZ && rad2 < kTripQ3SqR){
291 b[0] = -fQuadGradient*x[1];
292 b[1] = -fQuadGradient*x[0];
294 else if(TMath::Abs(x[2]+kTripQ4CZ)<kTripQ4hDZ && rad2 < kTripQ4SqR){
295 b[0] = fQuadGradient*x[1];
296 b[1] = fQuadGradient*x[0];
298 else if(TMath::Abs(x[2]+kDip1CZ)<kDip1hDZ && rad2 < kDip1SqRC){
301 else if(TMath::Abs(x[2]+kDip2CZ)<kDip2hDZ && rad2 < kDip2SqRC) {
302 double dxabs = TMath::Abs(x[0])-kDip2DXC;
303 if ( (dxabs*dxabs + x[1]*x[1])<kDip2SqRC) {
304 b[1] = -fDipoleField;
309 // SIDE A **************************************************
311 if(TMath::Abs(x[2]-kBComp1CZ)<kBComp1hDZ && rad2 < kBComp1SqR) {
312 // Compensator magnet at z = 1075 m
313 b[0] = fACorr1Field*fFactorDip;
316 if(TMath::Abs(x[2]-kBComp2CZ)<kBComp2hDZ && rad2 < kBComp2SqR){
317 b[0] = fACorr2Field*fFactorDip;
319 else if(TMath::Abs(x[2]-kTripQ1CZ)<kTripQ1hDZ && rad2 < kTripQ1SqR){
320 b[0] = -fQuadGradient*x[1];
321 b[1] = -fQuadGradient*x[0];
323 else if(TMath::Abs(x[2]-kTripQ2CZ)<kTripQ2hDZ && rad2 < kTripQ2SqR){
324 b[0] = fQuadGradient*x[1];
325 b[1] = fQuadGradient*x[0];
327 else if(TMath::Abs(x[2]-kTripQ3CZ)<kTripQ3hDZ && rad2 < kTripQ3SqR){
328 b[0] = fQuadGradient*x[1];
329 b[1] = fQuadGradient*x[0];
331 else if(TMath::Abs(x[2]-kTripQ4CZ)<kTripQ4hDZ && rad2 < kTripQ4SqR){
332 b[0] = -fQuadGradient*x[1];
333 b[1] = -fQuadGradient*x[0];
335 else if(TMath::Abs(x[2]-kDip1CZ)<kDip1hDZ && rad2 < kDip1SqRA){
336 b[1] = -fDipoleField;
338 else if(TMath::Abs(x[2]-kDip2CZ)<kDip2hDZ && rad2 < kDip2SqRA) {
339 double dxabs = TMath::Abs(x[0])-kDip2DXA;
340 if ( (dxabs*dxabs + x[1]*x[1])<kDip2SqRA) {
348 //_______________________________________________________________________
349 void AliMagF::GetTPCInt(const Double_t *xyz, Double_t *b) const
351 // Method to calculate the integral of magnetic integral from xyz to nearest cathode plane
354 fMeasuredMap->GetTPCInt(xyz,b);
355 for (int i=3;i--;) b[i] *= fFactorSol;
359 //_______________________________________________________________________
360 void AliMagF::GetTPCIntCyl(const Double_t *rphiz, Double_t *b) const
362 // Method to calculate the integral of magnetic integral from point to nearest cathode plane
363 // in cylindrical coordiates ( -pi<phi<pi convention )
366 fMeasuredMap->GetTPCIntCyl(rphiz,b);
367 for (int i=3;i--;) b[i] *= fFactorSol;
371 //_______________________________________________________________________
372 void AliMagF::SetFactorSol(Float_t fc)
374 // set the sign/scale of the current in the L3 according to fgkPolarityConvention
375 switch (fgkPolarityConvention) {
376 case kConvDCS2008: fFactorSol = -fc; break;
377 case kConvLHC : fFactorSol = -fc; break;
378 default : fFactorSol = fc; break; // case kConvMap2005: fFactorSol = fc; break;
382 //_______________________________________________________________________
383 void AliMagF::SetFactorDip(Float_t fc)
385 // set the sign*scale of the current in the Dipole according to fgkPolarityConvention
386 switch (fgkPolarityConvention) {
387 case kConvDCS2008: fFactorDip = fc; break;
388 case kConvLHC : fFactorDip = -fc; break;
389 default : fFactorDip = fc; break; // case kConvMap2005: fFactorDip = fc; break;
393 //_______________________________________________________________________
394 Double_t AliMagF::GetFactorSol() const
396 // return the sign*scale of the current in the Dipole according to fgkPolarityConventionthe
397 switch (fgkPolarityConvention) {
398 case kConvDCS2008: return -fFactorSol;
399 case kConvLHC : return -fFactorSol;
400 default : return fFactorSol; // case kConvMap2005: return fFactorSol;
404 //_______________________________________________________________________
405 Double_t AliMagF::GetFactorDip() const
407 // return the sign*scale of the current in the Dipole according to fgkPolarityConventionthe
408 switch (fgkPolarityConvention) {
409 case kConvDCS2008: return fFactorDip;
410 case kConvLHC : return -fFactorDip;
411 default : return fFactorDip; // case kConvMap2005: return fFactorDip;