StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StTpcDb.cxx
1 /***************************************************************************
2  *
3  * $Id: StTpcDb.cxx,v 1.69 2021/03/26 20:26:48 fisyak Exp $
4  *
5  * Author: David Hardtke
6  ***************************************************************************
7  *
8  * Description: This is the interface between the database and the offline
9  * TPC software. This classes takes care of the annoying
10  * calls to the root infrastucture, packages and manipulates
11  * the data, and returns the data to the user via simple
12  * interface classes.
13  *
14  ***************************************************************************
15  *
16  * $Log: StTpcDb.cxx,v $
17  * Revision 1.69 2021/03/26 20:26:48 fisyak
18  * Synchronize with TFG version, new schema for Inner Sector alignment (thank to Hongwei)
19  *
20  * Revision 1.65 2018/06/21 01:47:14 perev
21  * iTPCheckIn
22  *
23  * Revision 1.63.6.1 2018/02/16 22:14:59 perev
24  * iTPC
25  *
26  * Revision 1.63 2015/05/17 22:53:52 fisyak
27  * Remove duplicted line
28  *
29  * Revision 1.62 2014/07/01 20:28:32 fisyak
30  * Add alternative (B) table for new TPC alignment
31  *
32  * Revision 1.61 2014/06/27 14:04:25 fisyak
33  * Add env. NewTpcAlignment to switch between new and old scheme
34  *
35  * Revision 1.60 2014/06/26 21:32:57 fisyak
36  * New Tpc Alignment, v632
37  *
38  * Revision 1.59 2012/09/17 19:39:44 fisyak
39  * Add rotation for Half Tpc's
40  *
41  * Revision 1.58 2012/05/03 23:56:48 fisyak
42  * Set interpolation for one week only, fix sign of interpolation (thanks Gene), add TriggerId
43  *
44  * Revision 1.57 2011/07/21 16:48:53 fisyak
45  * New schema for Sub Sector Alginement: SuperSectror position (defined by inner sub sector) and Outer sector position wrt SuperSectror position
46  *
47  * Revision 1.56 2011/01/18 14:39:43 fisyak
48  * Clean up TpcDb interfaces and Tpc coordinate transformation
49  *
50  * Revision 1.55 2010/05/27 19:14:26 fisyak
51  * Take out flavoring by 'sim' for tpcGlobalPosition,tpcSectorPosition and starClockOnl tables. remove usage tpcISTimeOffsets and tpcOSTimeOffsets tables
52  *
53  * Revision 1.54 2010/01/27 21:30:39 perev
54  * GetValidity now is static
55  *
56  * Revision 1.53 2010/01/26 21:04:42 fisyak
57  * Add new dE/dx calibration tables: TpcRowQ, tpcMethaneIn, tpcWaterOut, TpcZDC
58  *
59  * Revision 1.52 2009/12/07 23:44:58 fisyak
60  * Drop coordinate transformation for fortran, remove TpcHitErr
61  *
62  * Revision 1.51 2009/11/02 17:31:41 fisyak
63  * use directly field from StarMagField, replace St_tpcGainC and St_tpcT0C by St_tpcPadGainT0C, add remove defaults in coordinate transformations
64  *
65  * Revision 1.50 2009/03/16 14:13:30 fisyak
66  * Use StDetectorDb chairs for TpcGlobalPosition and TpcSectorPosition
67  *
68  * Revision 1.49 2008/09/10 15:46:36 fisyak
69  * Recalculate Tpc drift velocity once per event, avoid expensive conversion to unix time
70  *
71  * Revision 1.48 2008/08/01 14:28:22 fisyak
72  * Add new getT0, clean up
73  *
74  * Revision 1.47 2007/10/29 21:37:27 fisyak
75  * add protection from laserDriftVelocity and cathodeDriftVelocity mixing
76  *
77  * Revision 1.46 2007/08/12 15:06:30 fisyak
78  * Use separated East/West drift velocities only >= 2007, for back compartibility
79  *
80  * Revision 1.45 2007/07/19 22:19:23 perev
81  * Bug in drift velocity fixed
82  *
83  * Revision 1.44 2007/07/12 20:21:09 fisyak
84  * Drift velocity depends on TPC half, use online RHIC clock
85  *
86  * Revision 1.43 2007/04/16 22:51:03 fisyak
87  * Add protection from infinit endTime
88  *
89  * Revision 1.42 2007/04/15 20:57:01 fisyak
90  * Add drift velocity interpolation between two measurement in time
91  *
92  * Revision 1.41 2007/03/21 17:27:01 fisyak
93  * use TGeoHMatrix, change mode for switching drift velocities
94  *
95  * Revision 1.40 2005/07/06 22:26:53 fisyak
96  * dEdx_t=>dEdxY2_t
97  *
98  * Revision 1.39 2005/03/30 17:56:59 fisyak
99  * Fix a bug with flavor handling, StTpcDb has to be instantiated after setting flavor
100  *
101  * Revision 1.38 2004/11/19 10:21:54 jecc
102  * Initialize pointers
103  *
104  * Revision 1.37 2004/10/27 21:44:28 fisyak
105  * Add debug print for tables Validities, add access to ExB correction
106  *
107  * Revision 1.36 2004/03/16 22:17:46 jecc
108  * Update triggerTimeOffset() due to a change in L0 TriggerActionWd
109  *
110  * Revision 1.35 2004/02/23 00:35:00 fisyak
111  * Add access to tpcPadResponse
112  *
113  * Revision 1.34 2004/01/14 22:54:30 fisyak
114  * Add hooks for Pedestal and tpcGain
115  *
116  * Revision 1.33 2002/04/02 00:16:30 hardtke
117  * New class that gets hit errors from database
118  *
119  * Revision 1.32 2002/02/06 18:39:13 hardtke
120  * Add tpc Field Cage structure
121  *
122  * Revision 1.31 2001/08/14 18:18:03 hardtke
123  * Add sector position structures
124  *
125  * Revision 1.30 2001/06/20 22:25:26 hardtke
126  * Get TRS gain parameters from tsspar table
127  *
128  * Revision 1.29 2001/05/21 23:25:34 hardtke
129  * Add tpcGlobalPosition to StTpcDb. This includes the global position offset and the rotation w.r.t. the magnet
130  *
131  * Revision 1.28 2000/08/18 17:19:21 hardtke
132  * use laser velocity, if available
133  *
134  * Revision 1.27 2000/08/10 18:41:34 hardtke
135  * only look for L0_trigger table once per event -- improves timing
136  *
137  * Revision 1.26 2000/08/09 14:54:54 hardtke
138  * Add Clear option, set trigger table pointer to 0 after each event
139  *
140  * Revision 1.25 2000/08/09 13:00:03 hardtke
141  * Add protections to make sure trigger table is filled before using
142  *
143  * Revision 1.24 2000/08/08 19:15:22 hardtke
144  * use correct trigger time offset in case of laser
145  *
146  * Revision 1.23 2000/08/04 21:03:55 perev
147  * Leaks + Clear() cleanup
148  *
149  * Revision 1.22 2000/05/12 20:31:38 fisyak
150  * Add ClassImp for abstract classes, new rootcint requires them
151  *
152  * Revision 1.21 2000/05/11 17:17:27 hardtke
153  * make trigger time offset available -- currently NOT different for beam and laser events
154  *
155  * Revision 1.20 2000/04/05 15:44:56 hardtke
156  * fix solaris bug -- char* was too short for table name
157  *
158  * Revision 1.19 2000/03/30 17:02:36 hardtke
159  * limit warning message in StRTpcPadPlane
160  *
161  * Revision 1.18 2000/02/23 21:03:17 hardtke
162  * fix tpc_row_par -- causing tpt problems
163  *
164  * Revision 1.17 2000/02/15 22:21:47 hardtke
165  * Add effective drift distances
166  *
167  * Revision 1.16 2000/02/10 00:29:08 hardtke
168  * Add tpg functions to StTpcDbMaker, fix a few bugs
169  *
170  * Revision 1.15 2000/01/24 15:31:31 hardtke
171  * change to use new gain and t0 tables
172  *
173  * Revision 1.14 2000/01/11 15:49:52 hardtke
174  * get Electronics table from Calibrations database, Fix error messages
175  *
176  * Revision 1.13 1999/12/16 22:00:53 hardtke
177  * add CVS tags
178  *
179  **************************************************************************/
181 // //
182 // StTpcDb //
183 // //
184 // //
185 #include "StChain.h"
186 #include "StTpcDb.h"
187 #include "tables/St_trgTimeOffset_Table.h"
188 #include "tables/St_dst_L0_Trigger_Table.h"
189 #include "TUnixTime.h"
190 #include "StMessMgr.h"
191 #include "St_db_Maker/St_db_Maker.h"
192 #include "TVector3.h"
193 #include "TGeoManager.h"
194 #include "StDetectorDbMaker/StTpcSurveyC.h"
195 #include "StDetectorDbMaker/St_tpcDriftVelocityC.h"
196 #include "StDetectorDbMaker/St_TpcDriftVelRowCorC.h"
197 #include "StarMagField.h"
198 #include "TEnv.h"
199 StTpcDb* gStTpcDb = 0;
200 Bool_t StTpcDb::mOldScheme = kTRUE;
201 // C++ routines:
202 //_____________________________________________________________________________
203 ClassImp(StTpcDb);
204 //_____________________________________________________________________________
205 StTpcDb::StTpcDb() {
206  assert(gStTpcDb==0);
207  memset(mBeg,0,mEnd-mBeg+1);
208  mTpc2GlobMatrix = new TGeoHMatrix("Default Tpc2Glob");
209  for (Int_t i = 1; i <= 24; i++) {
210  for (Int_t k = 0; k < kTotalTpcSectorRotaions; k++) {
211  mTpcSectorRotations[i-1][k] = new TGeoHMatrix(Form("Default %02i %i",i,k));
212  }
213  }
214  mFlip = new TGeoHMatrix;
215  mzGG = Dimensions()->gatingGridZ(); // zGG
216  Double_t Rotation[9] = {0, 1, 0,
217  1, 0, 0,
218  0, 0,-1};
219  // Double_t Translation[3] = {0, 0, mzGG};
220  mFlip->SetName("Flip"); mFlip->SetRotation(Rotation);// mFlip->SetTranslation(Translation);
221  mShift[0] = new TGeoTranslation("Signed Drift distance to z for East", 0, 0, -mzGG);
222  mShift[1] = new TGeoTranslation("Signed Drift distance to z for West", 0, 0, mzGG);
223  mHalf[0] = new TGeoHMatrix("Default for east part of TPC");
224  mHalf[1] = new TGeoHMatrix("Default for west part of TPC");
225  gStTpcDb = this;
226 }
227 //_____________________________________________________________________________
228 //_____________________________________________________________________________
229 StTpcDb::~StTpcDb() {
230  for (Int_t i = 0;i<24;i++) {
231  for (Int_t k = 0; k < kTotalTpcSectorRotaions; k++)
232  SafeDelete(mTpcSectorRotations[i][k]);
233  }
234  SafeDelete(mHalf[0]);
235  SafeDelete(mHalf[1]);
236  SafeDelete(mShift[0]);
237  SafeDelete(mShift[1]);
238  SafeDelete(mTpc2GlobMatrix);
239  SafeDelete(mFlip);
240  gStTpcDb = 0;
241 }
242 //-----------------------------------------------------------------------------
243 float StTpcDb::DriftVelocity(Int_t sector, Int_t row) {
244  static UInt_t u2007 = TUnixTime(20070101,0,1).GetUTime(); //
245  assert(mUc > 0);
246  if (mUc < u2007) sector = 24;
247  UInt_t kase = 1;
248  if (sector <= 12) kase = 0;
249  Float_t DV =1e6*mDriftVel[kase];
250  if (row > 0) {
251  // Extra row correction
252  if (St_TpcDriftVelRowCorC::instance()->idx()) {
253  DV *= (1. - St_TpcDriftVelRowCorC::instance()->CalcCorrection(0,row));
254  }
255  }
256  return DV;
257 }
258 //-----------------------------------------------------------------------------
259 void StTpcDb::SetDriftVelocity() {
260  static UInt_t u0 = 0; // beginTime of current Table
261  static UInt_t u1 = 0; // beginTime for next Table
262  static UInt_t umax = TUnixTime(20250101,0,1).GetUTime(); // maximum time allowed for next table
263  // for back compartiblity switch to separated West and East drift velocities after 2007
264  static St_tpcDriftVelocity *dvel0 = 0;
265  static St_tpcDriftVelocity *dvel1 = 0;
266  static TDatime t[2];
267  UInt_t uc = TUnixTime(StMaker::GetChain()->GetDateTime(),1).GetUTime();
268  if (uc != mUc) {
269  if (! dvel0 || (uc < umax && ((uc < u0) || (uc > u1)))) {//First time only
270  dvel0 = (St_tpcDriftVelocity *) St_tpcDriftVelocityC::instance()->Table();
271  if (! dvel0) {
272  gMessMgr->Message("StTpcDb::Error Finding Tpc DriftVelocity","E");
273  mUc = 0;
274  return;
275  }
276  if (St_db_Maker::GetValidity(dvel0,t) < 0) {
277  gMessMgr->Message("StTpcDb::Error Wrong Validity Tpc DriftVelocity","E");
278  mUc = 0;
279  return;
280  }
281  u0 = TUnixTime(t[0],1).GetUTime();
282  u1 = TUnixTime(t[1],1).GetUTime();
283  SafeDelete(dvel1);
284  if (u1 < umax && u1 - u0 < 7*24*3600) // do not extrapolate for more than 1 week
285  dvel1 = (St_tpcDriftVelocity *) StMaker::GetChain()->GetDataBase("Calibrations/tpc/tpcDriftVelocity",&t[1]);
286  }//End First time only
287 
288  if (!(u0<=uc && uc<u1)) {//current time out of validity
289 
290  SafeDelete(dvel1);
291  if (u1 < umax && u1 - u0 < 7*24*3600 && uc - u0 < 7*24*3600) {// next drift velocity should within a week from current
292  dvel1 = (St_tpcDriftVelocity *) StMaker::GetChain()->GetDataBase("Calibrations/tpc/tpcDriftVelocity",&t[1]);
293  if (! dvel1) {
294  gMessMgr->Message("StTpcDb::Error Finding next Tpc DriftVelocity","W");
295  }
296  }
297  }
298 
299  mDriftVel[0] = mDriftVel[1] = 0;
300  tpcDriftVelocity_st *d0 = dvel0->GetTable();
301  if (dvel1) {
302  tpcDriftVelocity_st *d1 = dvel1->GetTable();
303  if (d0->laserDriftVelocityWest > 0 && d1->laserDriftVelocityWest > 0)
304  mDriftVel[0] = (d1->laserDriftVelocityWest *(uc-u0) + d0->laserDriftVelocityWest *(u1-uc))/(u1 - u0);
305  if (d0->laserDriftVelocityEast > 0 && d1->laserDriftVelocityEast > 0)
306  mDriftVel[1] = (d1->laserDriftVelocityEast *(uc-u0) + d0->laserDriftVelocityEast *(u1-uc))/(u1 - u0);
307  if (mDriftVel[0] <= 0.0 || mDriftVel[1] <= 0.0) {
308  if (d0->cathodeDriftVelocityWest > 0 && d1->cathodeDriftVelocityWest > 0)
309  mDriftVel[0] = (d1->cathodeDriftVelocityWest*(uc-u0) + d0->cathodeDriftVelocityWest*(u1-uc))/(u1 - u0);
310  if (d0->cathodeDriftVelocityEast > 0 && d1->cathodeDriftVelocityEast > 0)
311  mDriftVel[1] = (d1->cathodeDriftVelocityEast*(uc-u0) + d0->cathodeDriftVelocityEast*(u1-uc))/(u1 - u0);
312  }
313  }
314  if (mDriftVel[0] <= 0.0 || mDriftVel[1] <= 0.0) {
315  mDriftVel[0] = d0->laserDriftVelocityWest;
316  mDriftVel[1] = d0->laserDriftVelocityEast;
317  if (mDriftVel[0] <= 0.0) mDriftVel[0] = d0->cathodeDriftVelocityWest;
318  if (mDriftVel[1] <= 0.0) mDriftVel[1] = d0->cathodeDriftVelocityEast;
319  }
320 #if 0
321  LOG_INFO << "Set Tpc Drift Velocity =" << mDriftVel[0] << " (West) " << mDriftVel[0] << " (East) for "
322  << StMaker::GetChain()->GetDateTime().AsString() << endm;
323 #endif
324  mUc = uc;
325  }
326 }
327 //_____________________________________________________________________________
328 void StTpcDb::SetTpcRotations() {
329  // Pad [== sector12 == localsector (SecL, ideal)] => subsector (SubS,local sector aligned) => flip => sector (SupS) => tpc => global
330  // ------
331  //old: global = Tpc2GlobalMatrix() * SupS2Tpc(sector) * Flip() * {SubSInner2SupS(sector) | SubSOuter2SupS(sector)}
332  //new: global = Tpc2GlobalMatrix() * SupS2Tpc(sector) * StTpcSuperSectorPosition(sector) * Flip() * {StTpcInnerSectorPosition(sector)} | StTpcOuterSectorPosition(sector)}
333  // StTpcSuperSectorPosition(sector) * Flip() = Flip() * SubSInner2SupS(sector)
334  // => StTpcSuperSectorPosition(sector) = Flip() * SubSInner2SupS(sector) * Flip()^-1
335  // StTpcSuperSectorPosition(sector) * Flip() * StTpcOuterSectorPosition(sector) = Flip() * SubSOuter2SupS(sector)
336  // => StTpcOuterSectorPosition(sector) = Flip()^-1 * StTpcSuperSectorPosition(sector)^-1 * Flip() * SubSOuter2SupS(sector)
337  /*
338  . <-- the system of coordinate where Outer to Inner Alignment done -->
339  global = Tpc2GlobalMatrix() * SupS2Tpc(sector) * StTpcSuperSectorPosition(sector) * Flip() * { StTpcInnerSectorPosition(sector) | StTpcOuterSectorPosition(sector)} * local
340  . result of super sector alignment result of Outer to Inner sub sector alignment
341  */
342  /* 03/07/14
343  StTpcPadCoordinate P(sector,row,pad,timebacket);
344  x = xFromPad()
345  z = zFromTB() - drift distance
346  StTpcLocalSectorCoordinate LS(position(x,y,z),sector,row);
347 
348  StTpcLocalCoordinate Tpc(position(x,y,z),sector,row);
349  Pad2Tpc(sector,row).LocalToMaster(LS.position().xyz(), Tpc.postion().xyz())
350  Flip transformation from Pad Coordinate system (xFromPad(pad), yFromRow(row), DriftDistance(timebacket)) => (y, x, -z): local sector CS => super sectoe CS
351 
352 
353 
354  (0 1 0 0 ) ( x ) ( y )
355  Flip ; (1 0 0 0 ) ( y ) = ( x )
356  (0 0 -1 zGG) ( z ) ( zGG - z)
357  (0 0 0 1 ) ( 1 ) ( 1 )
358  Z_tpc is not changed during any sector transformation !!!
359  ================================================================================
360  10/17/18 Just checking new schema
361  TPCE ( TPGV ) * ( TPSS )
362  StTpcPosition * ((Shift(half) * StTpcHalfPosition(half)) * (rotmS(sector,iPhi) * StTpcSuperSectorPosition) * Flip) * (StTpcInnerSectorPosition || StTpcOuterSectorPosition)
363  kTpcRefSys * kTpcHalf * kTpcPad
364  kTpcRefSys * kSupS2Tpc
365 
366  kTpc2GlobalMatrix := StTpcPosition
367  kSupS2Tpc := (Shift(half) * StTpcHalfPosition(half)) * (rotmS(sector,iPhi) * StTpcSuperSectorPosition)
368  kSupS2Glob := StTpcPosition * kSupS2Tpc
369  kSubSInner2SupS := Flip * StTpcInnerSectorPosition
370  kSubSOuter2SupS := Flip * StTpcOuterSectorPosition
371  kSubSInner2Tpc := kSupS2Tpc * kSubSInner2SupS
372  kSubSOuter2Tpc := kSupS2Tpc * kSubSOuter2SupS
373  kPadInner2SupS := kSubSInner2SupS
374  kPadOuter2SupS := kSubSOuter2SupS
375  kPadInner2Tpc := kSupS2Tpc * kPadInner2SupS == kSubSInner2Tpc
376  kPadOuter2Tpc := kSupS2Tpc * PadOuter2SupS = kSupS2Tpc * kSubSOuter2SupS = kSubSOuter2Tpc
377  kPadInner2Glob := kTpc2GlobalMatrix * kPadInner2Tpc = kTpc2GlobalMatrix * kSubSInner2Tpc
378  kPadOuter2Glob := kTpc2GlobalMatrix * kPadOuter2Tpc = kTpc2GlobalMatrix * kSubSOuter2Tpc
379  */
380  assert(Dimensions()->numberOfSectors() == 24);
381  Float_t gFactor = StarMagField::Instance()->GetFactor();
382  Double_t phi, theta, psi;
383  Int_t iphi;
384  TGeoRotation *rotm = 0;
385  TObjArray *listOfMatrices = 0;
386  TString Rot;
387  if (gEnv->GetValue("NewTpcAlignment",0) != 0) mOldScheme = kFALSE;
388  if (! mOldScheme) {
389  LOG_INFO << "StTpcDb::SetTpcRotations use new schema for Rotation matrices" << endm;
390  } else {
391  LOG_INFO << "StTpcDb::SetTpcRotations use old schema for Rotation matrices" << endm;
392  }
393  St_SurveyC *chair = 0;
394  for (Int_t sector = 0; sector <= 24; sector++) {// loop over Tpc as whole, sectors, inner and outer subsectors
395  Int_t k;
396  Int_t k1 = kSupS2Tpc;
397  Int_t k2 = kTotalTpcSectorRotaions;
398  if (sector == 0) {k2 = k1; k1 = kUndefSector;}
399  for (k = k1; k < k2; k++) {
400  Int_t Id = 0;
401  TGeoHMatrix rotA; // After alignment
402  chair = 0;
403  if (!sector ) { // TPC Reference System
404  if (mOldScheme) { // old scheme
405  St_tpcGlobalPositionC *tpcGlobalPosition = St_tpcGlobalPositionC::instance();
406  assert(tpcGlobalPosition);
407  Id = 1;
408  phi = 0.0; // -gamma large uncertainty, so set to 0
409  theta = tpcGlobalPosition->PhiXZ_geom()*TMath::RadToDeg(); // -beta
410  psi = tpcGlobalPosition->PhiYZ_geom()*TMath::RadToDeg(); // -alpha
411  rotA.RotateX(-psi);
412  rotA.RotateY(-theta);
413  rotA.RotateZ(-phi);
414  Double_t transTpcRefSys[3] = {tpcGlobalPosition->LocalxShift(),
415  tpcGlobalPosition->LocalyShift(),
416  tpcGlobalPosition->LocalzShift()};
417  rotA.SetTranslation(transTpcRefSys);
418  } else {
419  rotA = StTpcPosition::instance()->GetMatrix();
420  *mHalf[east] = StTpcHalfPosition::instance()->GetEastMatrix();
421  *mHalf[west] = StTpcHalfPosition::instance()->GetWestMatrix();
422  }
423  } else {
424  Id = 10*sector + k;
425  StBeamDirection part = east;
426  if (sector <= 12) part = west;
427  switch (k) {
428  case kSupS2Tpc: // SupS => Tpc
429  if (sector <= 12) {iphi = (360 + 90 - 30* sector )%360; Rot = Form("R%03i",iphi);}
430  else {iphi = ( 90 + 30*(sector - 12))%360; Rot = Form("Y%03i",iphi);}
431  rotm = 0;
432  if (gGeoManager) {
433  listOfMatrices = gGeoManager->GetListOfMatrices();
434  rotm = (TGeoRotation *) listOfMatrices->FindObject(Rot);
435  }
436  if (! rotm) {
437  if (sector <= 12) rotm = new TGeoRotation(Rot);
438  else rotm = new TGeoRotation(Rot, 90.0, 0.0, 90.0, -90.0, 180.0, 0.00); // Flip (x,y,z) => ( x,-y,-z)
439  rotm->RotateZ(iphi);
440  }
441  rotA = (*mShift[part]) * (*mHalf[part]) * (*rotm);
442  rotA *= StTpcSuperSectorPosition::instance()->GetMatrix(sector-1);
443  if (gGeoManager) rotm->RegisterYourself();
444  else SafeDelete(rotm);
445  break;
446  case kSupS2Glob: // SupS => Tpc => Glob
447  rotA = Tpc2GlobalMatrix() * SupS2Tpc(sector);
448  break;
449  case kSubSInner2SupS:
450  if (mOldScheme) {rotA = Flip(); break;}
451  chair = StTpcInnerSectorPosition::instance();
452  case kSubSOuter2SupS:
453  if (mOldScheme) {rotA = Flip() * StTpcOuterSectorPosition::instance()->GetMatrix(sector-1); break;}
454  if (! chair) chair = StTpcOuterSectorPosition::instance();
455  rotA = Flip() * chair->GetMatrix(sector-1);
456  if (chair->GetNRows() > 24) {
457  if (gFactor > 0.2) {
458  rotA *= chair->GetMatrix(sector-1+24);
459  } else if (gFactor < -0.2) {
460  rotA *= chair->GetMatrix(sector-1+24).Inverse();
461  }
462  }
463  break;
464  case kSubSInner2Tpc: rotA = SupS2Tpc(sector) * SubSInner2SupS(sector); break; // (Subs[io] => SupS) => Tpc
465  case kSubSOuter2Tpc: rotA = SupS2Tpc(sector) * SubSOuter2SupS(sector); break; // -"-
466 
467  case kSubSInner2Glob: rotA = Tpc2GlobalMatrix() * SubSInner2Tpc(sector); break; // Subs[io] => SupS => Tpc) => Glob
468  case kSubSOuter2Glob: rotA = Tpc2GlobalMatrix() * SubSOuter2Tpc(sector); break; // -"-
469 
470  case kPadInner2SupS: rotA = SubSInner2SupS(sector); break; // (Pad == SecL) => (SubS[io] => SupS)
471  case kPadOuter2SupS: rotA = SubSOuter2SupS(sector); break; // -"-
472  case kPadInner2Tpc: rotA = SupS2Tpc(sector) * PadInner2SupS(sector); break; // (Pad == SecL) => (SubS[io] => SupS => Tpc)
473  case kPadOuter2Tpc: rotA = SupS2Tpc(sector) * PadOuter2SupS(sector); break; // -"-
474 
475  case kPadInner2Glob: rotA = Tpc2GlobalMatrix() * PadInner2Tpc(sector); break; // (Pad == SecL) => (SubS[io] => SupS => Tpc => Glob)
476  case kPadOuter2Glob: rotA = Tpc2GlobalMatrix() * PadOuter2Tpc(sector); break; // -"-
477  default:
478  assert(0);
479  }
480  }
481  // Normalize
482  Double_t *r = rotA.GetRotationMatrix();
483  Double_t norm;
484  TVector3 d(r[0],r[3],r[6]); norm = 1/d.Mag(); d *= norm;
485  TVector3 t(r[2],r[5],r[8]); norm = 1/t.Mag(); t *= norm;
486  TVector3 n(r[1],r[4],r[7]);
487  TVector3 c = d.Cross(t);
488  if (c.Dot(n) < 0) c *= -1;
489  Double_t rot[9] = {
490  d[0], c[0], t[0],
491  d[1], c[1], t[1],
492  d[2], c[2], t[2]};
493  rotA.SetRotation(rot);
494  const Char_t *names[kTotalTpcSectorRotaions] = {
495  "SupS_%02itoTpc",
496  "SupS_%02itoGlob",
497  "SubS_%02iInner2SupS",
498  "SubS_%02iOuter2SupS",
499  "SubS_%02iInner2Tpc",
500  "SubS_%02iOuter2Tpc",
501  "SubS_%02iInner2Glob",
502  "SubS_%02iOuter2Glob",
503  "PadInner2SupS_%02i",
504  "PadOuter2SupS_%02i",
505  "SupS_%02i12Inner2Tpc",
506  "SupS_%02i12Outer2Tpc",
507  "SupS_%02i12Inner2Glob",
508  "SupS_%02i12Outer2Glob"
509  };
510  if (sector == 0) rotA.SetName("Tpc2Glob");
511  else rotA.SetName(Form(names[k],sector));
512  if (Debug() > 1) {
513  cout << "Id : " << Id << " "; rotA.Print();
514  }
515  SetTpcRotationMatrix(&rotA,sector,k);
516  }
517  }
518 }