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 **************************************************************************/
17 // This implementation AliTPCExB is using an "exact" calculation of the ExB
18 // effect. That is, it uses the drift ODE to calculate the distortion
19 // without any further assumption.
20 // Due to the numerical integration of the ODE, there are some numerical
21 // uncertencies involed.
25 #include "TTreeStream.h"
26 #include "AliFieldMap.h"
28 #include "AliTPCExBExact.h"
30 ClassImp(AliTPCExBExact)
32 const Double_t AliTPCExBExact::fgkEM=1.602176487e-19/9.10938215e-31;
33 const Double_t AliTPCExBExact::fgkDriftField=40.e3;
35 AliTPCExBExact::AliTPCExBExact()
37 fkMap(0),fkField(0),fkN(0),
38 fkNX(0),fkNY(0),fkNZ(0),
39 fkXMin(-250.),fkXMax(250.),fkYMin(-250.),fkYMax(250.),
40 fkZMin(-250.),fkZMax(250.),
41 fkNLook(0),fkLook(0) {
47 AliTPCExBExact::AliTPCExBExact(const AliMagF *bField,
48 Double_t driftVelocity,
49 Int_t nx,Int_t ny,Int_t nz,Int_t n)
50 : fDriftVelocity(driftVelocity),
51 fkMap(0),fkField(bField),fkN(n),
52 fkNX(nx),fkNY(ny),fkNZ(nz),
53 fkXMin(-250.),fkXMax(250.),fkYMin(-250.),fkYMax(250.),
54 fkZMin(-250.),fkZMax(250.),
55 fkNLook(0),fkLook(0) {
57 // The constructor. One has to supply a magnetic field and an (initial)
58 // drift velocity. Since some kind of lookuptable is created the
59 // number of its meshpoints can be supplied.
60 // n sets the number of integration steps to be used when integrating
61 // over the full drift length.
66 AliTPCExBExact::AliTPCExBExact(const AliFieldMap *bFieldMap,
67 Double_t driftVelocity,Int_t n)
68 : fDriftVelocity(driftVelocity),
69 fkMap(bFieldMap),fkField(0),fkN(n),
70 fkNX(0),fkNY(0),fkNZ(0),
71 fkXMin(-250.),fkXMax(250.),fkYMin(-250.),fkYMax(250.),
72 fkZMin(-250.),fkZMax(250.),
73 fkNLook(0),fkLook(0) {
75 // The constructor. One has to supply a field map and an (initial)
77 // n sets the number of integration steps to be used when integrating
78 // over the full drift length.
81 fkXMin=bFieldMap->Xmin()
82 -TMath::Ceil( (bFieldMap->Xmin()+250.0)/bFieldMap->DelX())
84 fkXMax=bFieldMap->Xmax()
85 -TMath::Floor((bFieldMap->Xmax()-250.0)/bFieldMap->DelX())
87 fkYMin=bFieldMap->Ymin()
88 -TMath::Ceil( (bFieldMap->Ymin()+250.0)/bFieldMap->DelY())
90 fkYMax=bFieldMap->Ymax()
91 -TMath::Floor((bFieldMap->Ymax()-250.0)/bFieldMap->DelY())
93 fkZMax=bFieldMap->Zmax()
94 -TMath::Floor((bFieldMap->Zmax()-250.0)/bFieldMap->DelZ())
96 fkZMax=TMath::Max(0.,fkZMax); // I really hope that this is unnecessary!
98 fkNX=static_cast<Int_t>((fkXMax-fkXMin)/bFieldMap->DelX()+1.1);
99 fkNY=static_cast<Int_t>((fkYMax-fkYMin)/bFieldMap->DelY()+1.1);
100 fkNZ=static_cast<Int_t>((fkZMax-fkZMin)/bFieldMap->DelZ()+1.1);
105 AliTPCExBExact::~AliTPCExBExact() {
107 // destruct the poor object.
112 void AliTPCExBExact::Correct(const Double_t *position, Double_t *corrected) {
114 // correct for the distortion
116 Double_t x=(position[0]-fkXMin)/(fkXMax-fkXMin)*(fkNX-1);
117 Int_t xi1=static_cast<Int_t>(x);
118 xi1=TMath::Max(TMath::Min(xi1,fkNX-2),0);
121 Double_t dx1=(xi2-x);
123 Double_t y=(position[1]-fkYMin)/(fkYMax-fkYMin)*(fkNY-1);
124 Int_t yi1=static_cast<Int_t>(y);
125 yi1=TMath::Max(TMath::Min(yi1,fkNY-2),0);
128 Double_t dy1=(yi2-y);
130 Double_t z=position[2]/fkZMax*(fkNZ-1);
139 Int_t zi1=static_cast<Int_t>(z);
140 zi1=TMath::Max(TMath::Min(zi1,fkNZ-2),0);
143 Double_t dz1=(zi2-z);
145 for (int i=0;i<3;++i)
147 =fkLook[(((xi1*fkNY+yi1)*fkNZ+zi1)*2+side)*3+i]*dx1*dy1*dz1
148 +fkLook[(((xi1*fkNY+yi1)*fkNZ+zi2)*2+side)*3+i]*dx1*dy1*dz
149 +fkLook[(((xi1*fkNY+yi2)*fkNZ+zi1)*2+side)*3+i]*dx1*dy *dz1
150 +fkLook[(((xi1*fkNY+yi2)*fkNZ+zi2)*2+side)*3+i]*dx1*dy *dz
151 +fkLook[(((xi2*fkNY+yi2)*fkNZ+zi1)*2+side)*3+i]*dx *dy *dz1
152 +fkLook[(((xi2*fkNY+yi2)*fkNZ+zi2)*2+side)*3+i]*dx *dy *dz
153 +fkLook[(((xi2*fkNY+yi1)*fkNZ+zi1)*2+side)*3+i]*dx *dy1*dz1
154 +fkLook[(((xi2*fkNY+yi1)*fkNZ+zi2)*2+side)*3+i]*dx *dy1*dz ;
155 // corrected[2]=position[2];
158 void AliTPCExBExact::TestThisBeautifulObject(const AliFieldMap *bFieldMap,
159 const char* fileName) {
161 // Have a look at the common part "TestThisBeautifulObjectGeneric".
165 TestThisBeautifulObjectGeneric(fileName);
168 void AliTPCExBExact::TestThisBeautifulObject(const AliMagF *bField,
169 const char* fileName) {
171 // Have a look at the common part "TestThisBeautifulObjectGeneric".
175 TestThisBeautifulObjectGeneric(fileName);
178 void AliTPCExBExact::TestThisBeautifulObjectGeneric(const char* fileName) {
180 // Well, as the name sais... it tests the object.
182 TTreeSRedirector ts(fileName);
184 for (x[0]=-250.;x[0]<=250.;x[0]+=10.)
185 for (x[1]=-250.;x[1]<=250.;x[1]+=10.)
186 for (x[2]=-250.;x[2]<=250.;x[2]+=10.) {
190 CalculateDistortion(x,dnl);
191 Double_t r=TMath::Sqrt(x[0]*x[0]+x[1]*x[1]);
192 Double_t rd=TMath::Sqrt(d[0]*d[0]+d[1]*d[1]);
194 Double_t phi=TMath::ATan2(x[0],x[1]);
195 Double_t phid=TMath::ATan2(d[0],d[1]);
196 Double_t dphi=phi-phid;
197 if (dphi<0.) dphi+=TMath::TwoPi();
198 if (dphi>TMath::Pi()) dphi=TMath::TwoPi()-dphi;
199 Double_t drphi=r*dphi;
200 Double_t dx=x[0]-d[0];
201 Double_t dy=x[1]-d[1];
202 Double_t dz=x[2]-d[2];
203 Double_t dnlx=x[0]-dnl[0];
204 Double_t dnly=x[1]-dnl[1];
205 Double_t dnlz=x[2]-dnl[2];
229 void AliTPCExBExact::CreateLookupTable() {
231 // Helper function to fill the lookup table.
233 fkNLook=fkNX*fkNY*fkNZ*2*3;
234 fkLook=new Double_t[fkNLook];
236 for (int i=0;i<fkNX;++i) {
237 x[0]=fkXMin+(fkXMax-fkXMin)/(fkNX-1)*i;
238 for (int j=0;j<fkNY;++j) {
239 x[1]=fkYMin+(fkYMax-fkYMin)/(fkNY-1)*j;
240 for (int k=0;k<fkNZ;++k) {
241 x[2]=1.*fkZMax/(fkNZ-1)*k;
242 x[2]=TMath::Max((Double_t)0.0001,x[2]); //ugly
243 CalculateDistortion(x,&fkLook[(((i*fkNY+j)*fkNZ+k)*2+1)*3]);
245 CalculateDistortion(x,&fkLook[(((i*fkNY+j)*fkNZ+k)*2+0)*3]);
251 void AliTPCExBExact::GetE(Double_t *e,const Double_t *x) const {
253 // Helper function returning the E field in SI units (V/m).
257 e[2]=(x[2]<0.?-1.:1.)*fgkDriftField; // in V/m
260 void AliTPCExBExact::GetB(Double_t *b,const Double_t *x) const {
262 // Helper function returning the B field in SI units (T).
265 // the beautiful m to cm (and the ugly "const_cast") and Double_t
266 // to Float_t read the NRs introduction!:
267 for (int i=0;i<3;++i) xm[i]=x[i]*100.;
272 fkField->Field(xm,bf);
273 for (int i=0;i<3;++i) b[i]=bf[i]/10.;
276 void AliTPCExBExact::Motion(const Double_t *x,Double_t,
277 Double_t *dxdt) const {
279 // The differential equation of motion of the electrons.
281 Double_t tau=fDriftVelocity/fgkDriftField/fgkEM;
282 Double_t tau2=tau*tau;
287 Double_t wx=fgkEM*b[0];
288 Double_t wy=fgkEM*b[1];
289 Double_t wz=fgkEM*b[2];
290 Double_t ex=fgkEM*e[0];
291 Double_t ey=fgkEM*e[1];
292 Double_t ez=fgkEM*e[2];
293 Double_t w2=(wx*wx+wy*wy+wz*wz);
294 dxdt[0]=(1.+wx*wx*tau2)*ex+(wz*tau+wx*wy*tau2)*ey+(-wy*tau+wx*wz*tau2)*ez;
295 dxdt[1]=(-wz*tau+wx*wy*tau2)*ex+(1.+wy*wy*tau2)*ey+(wx*tau+wy*wz*tau2)*ez;
296 dxdt[2]=(wy*tau+wx*wz*tau2)*ex+(-wx*tau+wy*wz*tau2)*ey+(1.+wz*wz*tau2)*ez;
297 Double_t fac=tau/(1.+w2*tau2);
303 void AliTPCExBExact::CalculateDistortion(const Double_t *x0,
304 Double_t *dist) const {
306 // Helper function that calculates one distortion by integration
307 // (only used to fill the lookup table).
309 Double_t h=0.01*250./fDriftVelocity/fkN;
313 for (int i=0;i<3;++i)
314 xo[i]=xt[i]=x0[i]*0.01;
315 while (TMath::Abs(xt[2])<250.*0.01) {
316 for (int i=0;i<3;++i)
322 Double_t p=((xt[2]<0.?-1.:1.)*250.*0.01-xo[2])/(xt[2]-xo[2]);
323 dist[0]=(xo[0]+p*(xt[0]-xo[0]))*100.;
324 dist[1]=(xo[1]+p*(xt[1]-xo[1]))*100.;
325 // dist[2]=(xo[2]+p*(xt[2]-xo[2]))*100.;
326 dist[2]=(x0[2]>0.?-1:1.)*(t-h+p*h)*fDriftVelocity*100.;
327 dist[2]+=(x0[2]<0.?-1:1.)*250.;
334 // reverse the distortion, i.e. get the correction
335 dist[0]=x0[0]-(dist[0]-x0[0]);
336 dist[1]=x0[1]-(dist[1]-x0[1]);
339 void AliTPCExBExact::DGLStep(Double_t *x,Double_t t,Double_t h) const {
341 // An elementary integration step.
342 // (simple Euler Method)
346 for (int i=0;i<3;++i)
349 /* suggestions about how to write it this way are welcome!
350 void DGLStep(void (*f)(const Double_t *x,Double_t t,Double_t *dxdt),
351 Double_t *x,Double_t t,Double_t h,Int_t n) const;