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.;
29 //_______________________________________________________________________
35 fBeamType(kNoBeamField),
52 // Default constructor
56 //_______________________________________________________________________
57 AliMagF::AliMagF(const char *name, const char* title, Int_t integ,
58 Double_t factorSol, Double_t factorDip,
59 Double_t fmax, BMap_t maptype, const char* path,
60 BeamType_t bt, Double_t be):
61 TVirtualMagField(name),
73 fDipoleOFF(factorDip==0.),
82 // Initialize the field with Geant integration option "integ" and max field "fmax,
83 // Impose scaling of parameterized L3 field by factorSol and of dipole by factorDip.
84 // The "be" is the energy of the beam in GeV/nucleon
87 if(integ<0 || integ > 2) {
88 AliWarning(Form("Invalid magnetic field flag: %5d; Helix tracking chosen instead",integ));
91 if (fInteg == 0) fPrecInteg = 0;
93 const char* parname = 0;
95 if (fMapType == k2kG) parname = fDipoleOFF ? "Sol12_Dip0_Hole":"Sol12_Dip6_Hole";
96 else if (fMapType == k5kG) parname = fDipoleOFF ? "Sol30_Dip0_Hole":"Sol30_Dip6_Hole";
97 else if (fMapType == k5kGUniform) parname = "Sol30_Dip6_Uniform";
98 else AliFatal(Form("Unknown field identifier %d is requested\n",fMapType));
100 SetDataFileName(path);
101 SetParamName(parname);
103 LoadParameterization();
104 InitMachineField(fBeamType,fBeamEnergy);
105 double xyz[3]={0.,0.,0.};
106 fSolenoid = GetBz(xyz);
107 SetFactorSol(factorSol);
108 SetFactorDip(factorDip);
111 //_______________________________________________________________________
112 AliMagF::AliMagF(const AliMagF &src):
113 TVirtualMagField(src),
115 fMapType(src.fMapType),
116 fSolenoid(src.fSolenoid),
117 fBeamType(src.fBeamType),
118 fBeamEnergy(src.fBeamEnergy),
120 fPrecInteg(src.fPrecInteg),
121 fFactorSol(src.fFactorSol),
122 fFactorDip(src.fFactorDip),
124 fDipoleOFF(src.fDipoleOFF),
125 fQuadGradient(src.fQuadGradient),
126 fDipoleField(src.fDipoleField),
127 fCCorrField(src.fCCorrField),
128 fACorr1Field(src.fACorr1Field),
129 fACorr2Field(src.fACorr2Field),
130 fParNames(src.fParNames)
132 if (src.fMeasuredMap) fMeasuredMap = new AliMagWrapCheb(*src.fMeasuredMap);
135 //_______________________________________________________________________
141 //_______________________________________________________________________
142 Bool_t AliMagF::LoadParameterization()
145 AliError(Form("Field data %s are already loaded from %s\n",GetParamName(),GetDataFileName()));
149 char* fname = gSystem->ExpandPathName(GetDataFileName());
150 TFile* file = TFile::Open(fname);
152 AliError(Form("Failed to open magnetic field data file %s\n",fname));
156 fMeasuredMap = dynamic_cast<AliMagWrapCheb*>(file->Get(GetParamName()));
158 AliError(Form("Did not find field %s in %s\n",GetParamName(),fname));
167 //_______________________________________________________________________
168 void AliMagF::Field(const Double_t *xyz, Double_t *b)
170 // Method to calculate the field at point xyz
172 // b[0]=b[1]=b[2]=0.0;
173 if (fMeasuredMap && xyz[2]>fMeasuredMap->GetMinZ() && xyz[2]<fMeasuredMap->GetMaxZ()) {
174 fMeasuredMap->Field(xyz,b);
175 if (xyz[2]>fgkSol2DipZ || fDipoleOFF) for (int i=3;i--;) b[i] *= fFactorSol;
176 else for (int i=3;i--;) b[i] *= fFactorDip;
178 else MachineField(xyz, b);
182 //_______________________________________________________________________
183 Double_t AliMagF::GetBz(const Double_t *xyz) const
185 // Method to calculate the field at point xyz
187 if (fMeasuredMap && xyz[2]>fMeasuredMap->GetMinZ() && xyz[2]<fMeasuredMap->GetMaxZ()) {
188 double bz = fMeasuredMap->GetBz(xyz);
189 return (xyz[2]>fgkSol2DipZ || fDipoleOFF) ? bz*fFactorSol : bz*fFactorDip;
194 //_______________________________________________________________________
195 AliMagF& AliMagF::operator=(const AliMagF& src)
197 if (this != &src && src.fMeasuredMap) {
198 if (fMeasuredMap) delete fMeasuredMap;
199 fMeasuredMap = new AliMagWrapCheb(*src.fMeasuredMap);
200 SetName(src.GetName());
201 fSolenoid = src.fSolenoid;
202 fBeamType = src.fBeamType;
203 fBeamEnergy = src.fBeamEnergy;
205 fPrecInteg = src.fPrecInteg;
206 fFactorSol = src.fFactorSol;
207 fFactorDip = src.fFactorDip;
209 fDipoleOFF = src.fDipoleOFF;
210 fParNames = src.fParNames;
215 //_______________________________________________________________________
216 void AliMagF::InitMachineField(BeamType_t btype, Double_t benergy)
218 if (btype==kNoBeamField || benergy<1.) {
219 fQuadGradient = fDipoleField = fCCorrField = fACorr1Field = fACorr2Field = 0.;
223 double rigScale = benergy/7000.; // scale according to ratio of E/Enominal
224 // for ions assume PbPb (with energy provided per nucleon) and account for A/Z
225 if (btype == kBeamTypeAA) rigScale *= 208./82.;
227 fQuadGradient = 22.0002*rigScale;
228 fDipoleField = 37.8781*rigScale;
231 fCCorrField = -9.6980;
233 fACorr1Field = -13.2247;
234 fACorr2Field = 11.7905;
238 //_______________________________________________________________________
239 void AliMagF::MachineField(const Double_t *x, Double_t *b) const
241 // ---- This is the ZDC part
242 // Compansators for Alice Muon Arm Dipole
243 const Double_t kBComp1CZ = 1075., kBComp1hDZ = 260./2., kBComp1SqR = 4.0*4.0;
244 const Double_t kBComp2CZ = 2049., kBComp2hDZ = 153./2., kBComp2SqR = 4.5*4.5;
246 const Double_t kTripQ1CZ = 2615., kTripQ1hDZ = 637./2., kTripQ1SqR = 3.5*3.5;
247 const Double_t kTripQ2CZ = 3480., kTripQ2hDZ = 550./2., kTripQ2SqR = 3.5*3.5;
248 const Double_t kTripQ3CZ = 4130., kTripQ3hDZ = 550./2., kTripQ3SqR = 3.5*3.5;
249 const Double_t kTripQ4CZ = 5015., kTripQ4hDZ = 637./2., kTripQ4SqR = 3.5*3.5;
251 const Double_t kDip1CZ = 6310.8, kDip1hDZ = 945./2., kDip1SqRC = 4.5*4.5, kDip1SqRA = 3.375*3.375;
252 const Double_t kDip2CZ = 12640.3, kDip2hDZ = 945./2., kDip2SqRC = 4.5*4.5, kDip2SqRA = 3.75*3.75;
253 const Double_t kDip2DXC = 9.7, kDip2DXA = 9.4;
255 double rad2 = x[0] * x[0] + x[1] * x[1];
257 b[0] = b[1] = b[2] = 0;
259 // SIDE C **************************************************
261 if(TMath::Abs(x[2]+kBComp2CZ)<kBComp2hDZ && rad2 < kBComp2SqR){
262 b[0] = fCCorrField*fFactorDip;
264 else if(TMath::Abs(x[2]+kTripQ1CZ)<kTripQ1hDZ && rad2 < kTripQ1SqR){
265 b[0] = fQuadGradient*x[1];
266 b[1] = fQuadGradient*x[0];
268 else if(TMath::Abs(x[2]+kTripQ2CZ)<kTripQ2hDZ && rad2 < kTripQ2SqR){
269 b[0] = -fQuadGradient*x[1];
270 b[1] = -fQuadGradient*x[0];
272 else if(TMath::Abs(x[2]+kTripQ3CZ)<kTripQ3hDZ && rad2 < kTripQ3SqR){
273 b[0] = -fQuadGradient*x[1];
274 b[1] = -fQuadGradient*x[0];
276 else if(TMath::Abs(x[2]+kTripQ4CZ)<kTripQ4hDZ && rad2 < kTripQ4SqR){
277 b[0] = fQuadGradient*x[1];
278 b[1] = fQuadGradient*x[0];
280 else if(TMath::Abs(x[2]+kDip1CZ)<kDip1hDZ && rad2 < kDip1SqRC){
283 else if(TMath::Abs(x[2]+kDip2CZ)<kDip2hDZ && rad2 < kDip2SqRC) {
284 double dxabs = TMath::Abs(x[0])-kDip2DXC;
285 if ( (dxabs*dxabs + x[1]*x[1])<kDip2SqRC) {
286 b[1] = -fDipoleField;
291 // SIDE A **************************************************
293 if(TMath::Abs(x[2]-kBComp1CZ)<kBComp1hDZ && rad2 < kBComp1SqR) {
294 // Compensator magnet at z = 1075 m
295 b[0] = fACorr1Field*fFactorDip;
298 if(TMath::Abs(x[2]-kBComp2CZ)<kBComp2hDZ && rad2 < kBComp2SqR){
299 b[0] = fACorr2Field*fFactorDip;
301 else if(TMath::Abs(x[2]-kTripQ1CZ)<kTripQ1hDZ && rad2 < kTripQ1SqR){
302 b[0] = -fQuadGradient*x[1];
303 b[1] = -fQuadGradient*x[0];
305 else if(TMath::Abs(x[2]-kTripQ2CZ)<kTripQ2hDZ && rad2 < kTripQ2SqR){
306 b[0] = fQuadGradient*x[1];
307 b[1] = fQuadGradient*x[0];
309 else if(TMath::Abs(x[2]-kTripQ3CZ)<kTripQ3hDZ && rad2 < kTripQ3SqR){
310 b[0] = fQuadGradient*x[1];
311 b[1] = fQuadGradient*x[0];
313 else if(TMath::Abs(x[2]-kTripQ4CZ)<kTripQ4hDZ && rad2 < kTripQ4SqR){
314 b[0] = -fQuadGradient*x[1];
315 b[1] = -fQuadGradient*x[0];
317 else if(TMath::Abs(x[2]-kDip1CZ)<kDip1hDZ && rad2 < kDip1SqRA){
318 b[1] = -fDipoleField;
320 else if(TMath::Abs(x[2]-kDip2CZ)<kDip2hDZ && rad2 < kDip2SqRA) {
321 double dxabs = TMath::Abs(x[0])-kDip2DXA;
322 if ( (dxabs*dxabs + x[1]*x[1])<kDip2SqRA) {
330 //_______________________________________________________________________
331 void AliMagF::GetTPCInt(const Double_t *xyz, Double_t *b) const
333 // Method to calculate the integral of magnetic integral from xyz to nearest cathode plane
336 fMeasuredMap->GetTPCInt(xyz,b);
337 for (int i=3;i--;) b[i] *= fFactorSol;
341 //_______________________________________________________________________
342 void AliMagF::GetTPCIntCyl(const Double_t *rphiz, Double_t *b) const
344 // Method to calculate the integral of magnetic integral from point to nearest cathode plane
345 // in cylindrical coordiates ( -pi<phi<pi convention )
348 fMeasuredMap->GetTPCIntCyl(rphiz,b);
349 for (int i=3;i--;) b[i] *= fFactorSol;