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 **************************************************************************/
16 ////////////////////////////////////////////////////////////////////////////
18 // AliTPCGGVoltError class //
19 // The class calculates the electric field and space point distortions //
20 // due a Gating Grid (GG) Error voltage. It uses the exact calculation //
21 // technique based on bessel functions. (original code from STAR) //
22 // The class allows "effective Omega Tau" corrections. //
24 // date: 27/04/2010 //
25 // Authors: Jim Thomas, Stefan Rossegger, Magnus Mager //
28 // AliTPCGGVoltError GGerror; //
29 // GGerror.SetOmegaTauT1T2(0.32,1.,1.); // values ideally from OCDB //
30 // GGerror.SetDeltaVGGA(50.); // voltage offset A-side //
31 // GGerror.SetDeltaVGGC(50.); // voltage offset C-side //
32 // GGerror.InitGGVoltErrorDistortion(); // initialization of the look up //
33 // // plot dRPhi distortions ... //
34 // GGerror.CreateHistoDRPhiinZR(1.,100,100)->Draw("surf2"); //
35 ////////////////////////////////////////////////////////////////////////////
39 #include "TGeoGlobalMagField.h"
40 #include "AliTPCcalibDB.h"
41 #include "AliTPCParam.h"
44 #include "AliTPCGGVoltError.h"
47 AliTPCGGVoltError::AliTPCGGVoltError()
48 : AliTPCCorrection("GGVoltError","GatingGrid (GG) Voltage Error"),
50 fDeltaVGGA(0.),fDeltaVGGC(0.)
53 // default constructor
57 AliTPCGGVoltError::~AliTPCGGVoltError() {
63 void AliTPCGGVoltError::Init() {
67 AliMagF* magF= (AliMagF*)TGeoGlobalMagField::Instance()->GetField();
68 if (!magF) AliError("Magneticd field - not initialized");
69 Double_t bzField = magF->SolenoidField()/10.; //field in T
70 AliTPCParam *param= AliTPCcalibDB::Instance()->GetParameters();
71 if (!param) AliError("Parameters - not initialized");
72 Double_t vdrift = param->GetDriftV()/1000000.; // [cm/us] // From dataBase: to be updated: per second (ideally)
73 Double_t ezField = 400; // [V/cm] // to be updated: never (hopefully)
74 Double_t wt = -10.0 * (bzField*10) * vdrift / ezField ;
76 SetOmegaTauT1T2(wt,fT1,fT2);
77 InitGGVoltErrorDistortion();
78 //SetDeltaVGGA(0.0);// ideally from the database
79 //SetDeltaVGGC(0.0);// ideally from the database
82 void AliTPCGGVoltError::Update(const TTimeStamp &/*timeStamp*/) {
86 AliMagF* magF= (AliMagF*)TGeoGlobalMagField::Instance()->GetField();
87 if (!magF) AliError("Magneticd field - not initialized");
88 Double_t bzField = magF->SolenoidField()/10.; //field in T
89 AliTPCParam *param= AliTPCcalibDB::Instance()->GetParameters();
90 if (!param) AliError("Parameters - not initialized");
91 Double_t vdrift = param->GetDriftV()/1000000.; // [cm/us] // From dataBase: to be updated: per second (ideally)
92 Double_t ezField = 400; // [V/cm] // to be updated: never (hopefully)
93 Double_t wt = -10.0 * (bzField*10) * vdrift / ezField ;
95 SetOmegaTauT1T2(wt,fT1,fT2);
96 InitGGVoltErrorDistortion();
101 void AliTPCGGVoltError::GetCorrection(const Float_t x[],const Short_t roc,Float_t dx[]) {
104 // Gated Grid Voltage Error
106 // Calculates the effect of having an incorrect voltage on the A or C end plate Gated Grids.
108 // Electrostatic Equations from StarNote SN0253 by Howard Wieman.
111 Int_t order = 1 ; // FIXME: hardcoded? Linear interpolation = 1, Quadratic = 2
113 Double_t intEr, intEphi ;
119 r = TMath::Sqrt( x[0]*x[0] + x[1]*x[1] );
120 phi = TMath::ATan2(x[1],x[0]);
121 if ( phi < 0 ) phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi
124 if ( (roc%36) < 18 ) {
126 deltaVGG = fDeltaVGGA; // (TPC End A)
128 sign = -1; // (TPC End C)
129 deltaVGG = fDeltaVGGC;
132 if ( sign==1 && z < fgkZOffSet ) z = fgkZOffSet; // Protect against discontinuity at CE
133 if ( sign==-1 && z > -fgkZOffSet ) z = -fgkZOffSet; // Protect against discontinuity at CE
135 Interpolate2DEdistortion( order, r, z, fGGVoltErrorER, intEr );
136 intEphi = 0.0; // Efield is symmetric in phi
138 // Calculate distorted position
140 phi = phi + deltaVGG*( fC0*intEphi - fC1*intEr ) / r;
141 r = r + deltaVGG*( fC0*intEr + fC1*intEphi );
144 // Calculate correction in cartesian coordinates
145 dx[0] = r * TMath::Cos(phi) - x[0];
146 dx[1] = r * TMath::Sin(phi) - x[1];
147 dx[2] = 0.; // z distortion not implemented (1st order distortions)
152 Float_t AliTPCGGVoltError::GetIntErOverEz(const Float_t x[],const Short_t roc) {
154 // This function is purely for calibration purposes
155 // Calculates the integral (int Er/Ez dz) for the setted GG voltage offset
158 Int_t order = 1 ; // FIXME: so far hardcoded? Linear interpolation = 1, Quadratic = 2
166 r = TMath::Sqrt( x[0]*x[0] + x[1]*x[1] );
167 phi = TMath::ATan2(x[1],x[0]);
168 if ( phi < 0 ) phi += TMath::TwoPi(); // Table uses phi from 0 to 2*Pi
171 if ( (roc%36) < 18 ) {
173 deltaVGG = fDeltaVGGA; // (TPC End A)
175 sign = -1; // (TPC End C)
176 deltaVGG = fDeltaVGGC;
179 if ( sign==1 && z < fgkZOffSet ) z = fgkZOffSet; // Protect against discontinuity at CE
180 if ( sign==-1 && z > -fgkZOffSet ) z = -fgkZOffSet; // Protect against discontinuity at CE
182 Interpolate2DEdistortion(order, r, z, fGGVoltErrorER, intEr );
184 return (intEr*deltaVGG);
188 void AliTPCGGVoltError::InitGGVoltErrorDistortion() {
190 // Initialization of the Lookup table which contains the solutions of the GG Error problem
195 for ( Int_t i = 0 ; i < kNZ ; ++i ) {
197 for ( Int_t j = 0 ; j < kNR ; ++j ) {
199 fGGVoltErrorER[i][j] = 0.0 ;
200 Double_t intz = 0.0 ;
201 for ( Int_t n = 1 ; n < nterms ; ++n ) {
202 Double_t k = n * TMath::Pi() / fgkTPCZ0 ;
203 Double_t ein = 0 ; // Error potential on the IFC
204 Double_t eout = 0 ; // Error potential on the OFC
206 ein = -2.0 / ( k * (fgkCathodeV - fgkGG) ) ;
207 eout = -2.0 / ( k * (fgkCathodeV - fgkGG) ) ;
209 if ( z == 0 ) continue ;
211 ein = -2.0 / ( k * (fgkCathodeV - fgkGG) ) ;
212 eout = -2.0 / ( k * (fgkCathodeV - fgkGG) ) ;
214 Double_t an = ein * TMath::BesselK0( k*fgkOFCRadius ) - eout * TMath::BesselK0( k*fgkIFCRadius ) ;
215 Double_t bn = eout * TMath::BesselI0( k*fgkIFCRadius ) - ein * TMath::BesselI0( k*fgkOFCRadius ) ;
217 an * TMath::BesselI1( k*r ) - bn * TMath::BesselK1( k*r ) ;
218 Double_t denominator =
219 TMath::BesselK0( k*fgkOFCRadius ) * TMath::BesselI0( k*fgkIFCRadius ) -
220 TMath::BesselK0( k*fgkIFCRadius ) * TMath::BesselI0( k*fgkOFCRadius ) ;
221 Double_t zterm = TMath::Cos( k*(fgkTPCZ0-TMath::Abs(z)) ) - 1 ;
222 intz += zterm * numerator / denominator ;
223 // Assume series converges, break if small terms
224 if ( n>10 && TMath::Abs(intz)*1.e-10 > TMath::Abs(numerator/denominator) ) break;
226 fGGVoltErrorER[i][j] = (Double_t) intz ;
234 void AliTPCGGVoltError::Print(const Option_t* option) const {
236 // Print function to check the settings (e.g. voltage offsets)
237 // option=="a" prints the C0 and C1 coefficents for calibration purposes
240 TString opt = option; opt.ToLower();
241 printf("%s\n",GetTitle());
242 printf(" - GG Voltage offset: A-side: %3.1f V, C-side: %3.1f V \n",fDeltaVGGA,fDeltaVGGC);
243 if (opt.Contains("a")) { // Print all details
244 printf(" - T1: %1.4f, T2: %1.4f \n",fT1,fT2);
245 printf(" - C1: %1.4f, C0: %1.4f \n",fC1,fC0);