StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
St_l3_Coordinate_Transformer.cxx
1 //:>-----------------------------------------------------------------
2 //: FILE: St_l3_Coordinate_Transformer.cxx
3 //: HISTORY:
4 //: may2000 version 1.00
5 //: 29jun2000 ppy SectorSin and SectorCos values changed
6 //: 29jun2000 ppy local_to_global changed
7 //: 29jun2000 ppy global_to_raw(int sector, int row, ... ) added
8 //: 29jun2000 ppy local_to_raw (int row, ... ) added
9 //:<------------------------------------------------------------------
10 //:>------------------------------------------------------------------
11 //: CLASS: St_l3_Coordinate_Transformer
12 //: DESCRIPTION: Transforms coordinates from/to: global, local and raw
13 //: AUTHOR: dfl - Dominik Flierl, flierl@bnl.gov
14 //:>------------------------------------------------------------------
15 
16 #include "Stl3Util/base/St_l3_Coordinate_Transformer.h"
17 
18 #include "Stl3Util/ftf/FtfGeneral.h"
19 #include "Stl3Util/base/FtfLog.h"
20 #include "StMultiArray.h"
21 
22 
23 #include <stdio.h>
24 #include <Stiostream.h>
25 #include <iomanip>
26 #include "Stl3Util/base/FtfLog.h"
27 #include <stdlib.h>
28 #include <cstring>
29 
30 #include <unistd.h>
31 #include <sys/mman.h>
32 #include <errno.h>
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 
38 
39 
40 St_l3_Coordinate_Transformer::St_l3_Coordinate_Transformer()
41 {
42 
43  // initialize transformations
44  // reset start values
45  //max_tb_inner =0;
46  //max_tb_outer =0;
47  transformation_errors =0;
48 
49  //Use_transformation_provided_by_db() ;
50  Set_parameters_by_hand() ;
51  //Get_parameters_from_db() ;
52  //Use_transformation_provided_by_db() ;
53  //Print_parameters() ;
54 
55 
56  TPCmap = NULL;
57  //LoadTPCLookupTable();
58 }
59 
60 
61 St_l3_Coordinate_Transformer::~St_l3_Coordinate_Transformer()
62 {
63  // if (transformation_errors>1000)
64  // {
65  // cout << transformation_errors
66  // << " transformation errors occured.\n";
67  // }
68 
69  if(TPCmap) free(TPCmap);
70  TPCmap = NULL;
71 }
72 
73 
74 
75 int St_l3_Coordinate_Transformer::LoadTPCLookupTable(const char * mapfilename)
76 {
77 
78 #ifdef Solaris
79  ftfLog("Transformation tables not available under Solaris\n");
80 
81  return -1;
82 #else
83 
84 
85  if (TPCmap) free(TPCmap);
86  TPCmap = NULL;
87 
88  // open and map file
89  int fd = open(mapfilename, O_RDONLY);
90 
91  if (fd == -1)
92  {
93  ftfLog("Unable to open transformation map '%s'.Aborting.\n",
94  mapfilename);
95 
96  return -1;
97  }
98 
99  int filesize = lseek(fd, 0, SEEK_END);
100  void *file = mmap(0, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
101  if ( file == MAP_FAILED ) {
102  ftfLog("Unable to mmap transformation map '%s'.Aborting.\n",
103  mapfilename);
104  return -1;
105  }
106 
107 
108  int type = ((int *)file)[0];
109  if ((type != 3) && (type != 100)) { //only support conversion map types
110  // 3 and 100 (local coordinates)
111  ftfLog("No valid map found in %s.\n", mapfilename);
112  return -1;
113  }
114 
115  int headerSize = ((int *)file)[1];
116 
117  dpad = ((float *)file)[3];
118  dtb = ((float *)file)[4];
119  maxtb = ((float *)file)[5];
120 
121  npad = (int) ceil( 182. / dpad);
122  ntb = (int) ceil( maxtb / dtb);
123 
124 
125  TPCmap = (float *)malloc(filesize - headerSize*4);
126  if (TPCmap == NULL) {
127  ftfLog("Cannot allocate memory for lookup table.\n", mapfilename);
128  return -1;
129  }
130 
131  memcpy(TPCmap, (float *)file+headerSize, filesize - headerSize*4);
132 
133 
134  if (munmap((char*)file, filesize))
135  ftfLog("St_l3_Coordinate_Transformer: error munmapping %s\n",
136  mapfilename);
137  if (close(fd))
138  ftfLog("St_l3_Coordinate_Transformer: error closing %s\n",
139  mapfilename);
140 
141 
142  ftfLog("St_l3_Coordinate_Transformer: loaded conversion map \"%s\"\n",
143  mapfilename);
144 
145  return 0;
146 
147 #endif
148 }
149 
150 //______________________________
151 void St_l3_Coordinate_Transformer::raw_to_global(const St_l3_ptrs_Coordinate &raw ,St_l3_xyz_Coordinate &global)
152 {
153 
154 #ifdef Solaris
155  St_l3_xyz_Coordinate local;
156 
157  raw_to_local(raw, local);
158  local_to_global(raw, local, global);
159 
160  return;
161 
162 #else
163 
164  if(!TPCmap) {
165  // no lookup table loaded -> using pure geometrical conversion
166  St_l3_xyz_Coordinate local;
167 
168  raw_to_local(raw, local);
169  local_to_global(raw, local, global);
170 
171  return;
172  }
173 // float (*binmap)[45][NPAD+1][NTB+1][3];
174 // binmap = (float (*)[45][NPAD+1][NTB+1][3])TPCmap;
175  StMultiArray<float> binmap(45,npad+1,ntb+1,3);
176  binmap = TPCmap;
177  // grid coordinates
178  int ipad = (int)floor(raw.Getp()/dpad);
179  int itb = (int)floor(raw.Gett()/dtb);
180 
181  // position in grid square
182  float wpad = raw.Getp()/dpad - (float)ipad;
183  float wtb = raw.Gett()/dtb - (float)itb;
184 
185  int sec = (int)raw.Gets() - 1;
186  int row = (int)raw.Getr() - 1;
187 
188  float x1 = binmap[sec][row][ipad ][itb ][0];
189  float y1 = binmap[sec][row][ipad ][itb ][1];
190  float z1 = binmap[sec][row][ipad ][itb ][2];
191  float x2 = binmap[sec][row][ipad+1][itb ][0];
192  float y2 = binmap[sec][row][ipad+1][itb ][1];
193  float z2 = binmap[sec][row][ipad+1][itb ][2];
194  float x3 = binmap[sec][row][ipad+1][itb+1][0];
195  float y3 = binmap[sec][row][ipad+1][itb+1][1];
196  float z3 = binmap[sec][row][ipad+1][itb+1][2];
197  float x4 = binmap[sec][row][ipad ][itb+1][0];
198  float y4 = binmap[sec][row][ipad ][itb+1][1];
199  float z4 = binmap[sec][row][ipad ][itb+1][2];
200 
201 
202 
203  float x = (1-wpad)*(1-wtb)*x1 + wpad*(1-wtb)*x2
204  + wpad*wtb*x3 + (1-wpad)*wtb*x4;
205  float y = (1-wpad)*(1-wtb)*y1 + wpad*(1-wtb)*y2
206  + wpad*wtb*y3 + (1-wpad)*wtb*y4;
207  float z = (1-wpad)*(1-wtb)*z1 + wpad*(1-wtb)*z2
208  + wpad*wtb*z3 + (1-wpad)*wtb*z4;
209 
210  global.Setxyz(x,y,z);
211 
212 #endif
213 
214 }
215 //______________________________
216 void St_l3_Coordinate_Transformer::raw_to_local(const St_l3_ptrs_Coordinate &raw ,St_l3_xyz_Coordinate &local )
217 {
218  double pitch = (raw.Getr()<14) ? innerSectorPadPitch : outerSectorPadPitch;
219  double pads2move = raw.Getp() - numberOfPadsAtRow[(int)raw.Getr()-1]/2;
220  local.Setx( pitch * (pads2move - 0.5) ) ;
221  local.Sety( radialDistanceAtRow[(int)(raw.Getr())-1] ) ;
222 
223  // Timebucket_to_z different for inner and outer sector
224  if( raw.Getr() <= 13 )
225  {
226  local.Setz(drift_length_inner - raw.Gett() * lengthPerTb) ;
227  if (raw.Gett()>max_tb_inner) {
228  transformation_errors++;
229  }
230  }
231  else
232  {
233  local.Setz(drift_length_outer - raw.Gett() * lengthPerTb) ;
234  if (raw.Gett()>max_tb_outer) {
235  transformation_errors++;
236  }
237  }
238 }
239 //______________________________
240 void St_l3_Coordinate_Transformer::local_to_global(const St_l3_ptrs_Coordinate &raw , const St_l3_xyz_Coordinate &local ,St_l3_xyz_Coordinate &global )
241 {
242  int sector = (int) raw.Gets();
243 
244  // rotate local x,y coordinates
245  // 2x2 rotation matrix:
246  // ( cos b sin b )
247  // (-sin b cos b )
248  //
249  // caution: sector>12 needs x->-x and y->y (east side!)
250  double x = SectorCos[sector-1] * local.Getx() + SectorSin[sector-1] * local.Gety();
251  if (sector>12) x = -x;
252  double y = -1.* SectorSin[sector-1] * local.Getx() + SectorCos[sector-1] * local.Gety();
253  double z = (sector<13) ? local.Getz() : -local.Getz() ;
254 
255  global.Setxyz(x,y,z);
256 
257 }
258 //______________________________
259 void St_l3_Coordinate_Transformer::global_to_raw(const St_l3_xyz_Coordinate &global , St_l3_ptrs_Coordinate &raw )
260 {
261  St_l3_xyz_Coordinate local(0,0,0) ;
262  global_to_local( global, local, raw ) ;
263 
264 
265  local_to_raw( global ,local ,raw ) ;
266 }
267 //______________________________
268 void St_l3_Coordinate_Transformer::global_to_raw(int sector, int row,
269  const St_l3_xyz_Coordinate &global ,
270  St_l3_ptrs_Coordinate &raw )
271 {
272  St_l3_xyz_Coordinate local(0,0,0) ;
273  global_to_local( sector, row, global, local ) ;
274  local_to_raw( row ,local ,raw ) ;
275 }
276 //______________________________
277 void St_l3_Coordinate_Transformer::global_to_local(const St_l3_xyz_Coordinate &global, St_l3_xyz_Coordinate &local ,St_l3_ptrs_Coordinate &raw)
278 {
279 
280  // Get xyz right
281 
282  double y = global.Gety() ;
283  if (y== 0) y= 0.000000001;
284 
285  double x = 0;
286  if(global.Getz()>=0)
287  {
288  x = global.Getx() ;
289  local.Setz(global.Getz());
290  }
291  else
292  {
293  x = -(global.Getx()) ; // ATTENTION must be mirrowed for sectors 13 - 24 !!!
294  local.Setz(-(global.Getz()));
295  }
296 
297  // Prepare turn operation
298  double pi = 3.14159265358979323846;
299  double sec_border = tan(pi/12) ; // 15 degree
300  double turn_angle = -pi/6 ; // 30 degree
301  double sin_turn_angle = sin(turn_angle);
302  double cos_turn_angle = cos(turn_angle);
303  double sector = 0 ;
304 
305  if (y>=0 && fabs(x/y)<=sec_border)
306  {
307  // We are already in sector 12
308  sector = 12 ;
309  }
310  else
311  {
312  // We have to turn system until we are in first sector
313  while( y<0 || (fabs(x/y)>sec_border))
314  {
315  double xn = x*cos_turn_angle + y*sin_turn_angle ;
316  double yn = -x*sin_turn_angle + y*cos_turn_angle ;
317  x = xn ;
318  y = yn ;
319  sector++;
320  }
321  }
322 
323  // Set it
324  local.Setx(x);
325  local.Sety(y);
326 
327  if (global.Getz()<0)
328  {
329  raw.Sets(sector+12);
330  }
331  else
332  {
333  raw.Sets(sector);
334  }
335 
336 }
337 //______________________________
338 void St_l3_Coordinate_Transformer::global_to_local(
339  int sector, int row,
340  const St_l3_xyz_Coordinate &global, St_l3_xyz_Coordinate &local )
341 {
342 
343  // rotate global x,y coordinates back to local
344  // 2x2 rotation matrix:
345  // ( cos b -sin b )
346  // ( sin b cos b )
347  //
348  // caution: sector>12 needs x->-x and y->y (east side!)
349  double xGlobal = global.Getx();
350  if (sector>12) xGlobal = -xGlobal;
351 
352  double x = SectorCos[sector-1] * xGlobal - SectorSin[sector-1] * global.Gety() ;
353  double y = SectorSin[sector-1] * xGlobal + SectorCos[sector-1] * global.Gety() ;
354  double z = fabs(global.Getz());
355 
356  local.Setxyz(x,y,z);
357 
358  return ;
359 }
360 //______________________________
361 void St_l3_Coordinate_Transformer::local_to_raw(const St_l3_xyz_Coordinate &global ,const St_l3_xyz_Coordinate &local , St_l3_ptrs_Coordinate &raw )
362 {
363  // first lets find the row
364  double y = local.Gety() ;
365  int row = 0;
366  int row_index = 0 ;
367  while( (fabs(radialDistanceAtRow[row_index]-y) > 0.5) && (row_index < 46) )
368  {
369  row_index++;
370  }
371  if (row_index==45 || y<59)
372  {
373  // no matching row found
374  //cerr << "Alert row not found !" << endl;
375  return ;
376  }
377  else
378  {
379  // yes row found !
380  row = row_index+1;
381  }
382 
383  // then lets go for the pad
384  double x = local.Getx();
385  double pitch = (row<=13) ? innerSectorPadPitch : outerSectorPadPitch ;
386  int half_num_pads_this_row = numberOfPadsAtRow[row-1]/2 ;
387  double pad = half_num_pads_this_row + x/pitch + 0.5 ;
388 
389  // finally lets get the bucket
390  double bucket = 0;
391  double z = local.Getz();
392  if (row<=13)
393  {
394  bucket = ( drift_length_inner - z )/lengthPerTb ;
395  if (z>drift_length_inner) {
396  transformation_errors++;
397  }
398  }
399  else
400  {
401  bucket = ( drift_length_outer - z )/lengthPerTb ;
402  if (z>drift_length_outer) {
403  transformation_errors++;
404  }
405  }
406 
407  // fill it
408  raw.Setp(pad);
409  raw.Sett(bucket);
410  raw.Setr(row);
411 }
412 //______________________________
413 void St_l3_Coordinate_Transformer::local_to_raw( int row ,const St_l3_xyz_Coordinate &local , St_l3_ptrs_Coordinate &raw )
414 {
415  // then lets go for the pad
416  double x = local.Getx();
417  double pitch = (row<=13) ? innerSectorPadPitch : outerSectorPadPitch ;
418  int half_num_pads_this_row = numberOfPadsAtRow[row-1]/2 ;
419  double pad = half_num_pads_this_row + x/pitch + 0.5 ;
420 
421  // finally lets get the bucket
422  double bucket = 0;
423  double z = local.Getz();
424  if (row<=13)
425  {
426  bucket = ( drift_length_inner - z )/lengthPerTb ;
427  if (z>drift_length_inner) {
428  transformation_errors++;
429  }
430  }
431  else
432  {
433  bucket = ( drift_length_outer - z )/lengthPerTb ;
434  if (z>drift_length_outer) {
435  transformation_errors++;
436  }
437  }
438 
439  // fill it
440  raw.Setp(pad);
441  raw.Sett(bucket);
442  raw.Setr(row);
443 }
444 //______________________________
445 void St_l3_Coordinate_Transformer::Set_parameters_by_hand(const double mlengthPerTb,
446  const double mdrift_length_inner,
447  const double mdrift_length_outer)
448 {
449  lengthPerTb = mlengthPerTb ;
450  drift_length_inner = mdrift_length_inner ;
451  drift_length_outer = mdrift_length_outer ;
452 
453  // set max timebucket
454  max_tb_inner = drift_length_inner/lengthPerTb;
455  max_tb_outer = drift_length_outer/lengthPerTb;
456 }
457 
458 
459 //______________________________
460 void St_l3_Coordinate_Transformer::Use_transformation_provided_by_db()
461 {
462 #ifdef L3OFFLINE
463  // perform official transform and recalulate parameters
464  // the official transform doesn't take doubles for pad and time
465  // that's why we must extract the parameters ...
466  StTpcPadCoordinate padco;
467  StGlobalCoordinate glo;
468  StTpcCoordinateTransform tra(gStTpcDb);
469 
470  // shaping time
471  double tau3 = 3 * (gStTpcDb->Electronics()->tau() * 1e-09) * (gStTpcDb->DriftVelocity()) ;
472 
473  // inner row (5) in sector 1
474  padco.setSector(1);
475  padco.setRow(5);
476  padco.setPad(1);
477  padco.setTimeBucket(100);
478 
479  tra(padco,glo);
480  double z_100 = glo.position().z();
481  padco.setTimeBucket(0);
482  tra(padco,glo);
483  double z_0 = glo.position().z();
484  double lengthPerTb_inner = fabs((z_0-z_100)/100) ;
485  drift_length_inner = fabs(glo.position().z()+tau3);
486 
487  //cout << "sector : " << padco.sector() << "\t";
488  //cout << "length per tb inner = " << lengthPerTb_inner << "\t";
489  //cout << "innerdrift : " <<drift_length_inner << endl;
490 
491  // outer row (30) in sector 1
492  padco.setSector(1);
493  padco.setRow(30);
494  padco.setPad(1);
495  padco.setTimeBucket(100);
496  tra(padco,glo);
497  z_100 = glo.position().z();
498  padco.setTimeBucket(0);
499  tra(padco,glo);
500  z_0 = glo.position().z();
501  double lengthPerTb_outer = fabs((z_0-z_100)/100) ;
502  drift_length_outer = fabs(glo.position().z()+tau3) ;
503 
504  //cout << "sector : " << padco.sector() << "\t";
505  //cout << "length per tb outer = " << lengthPerTb_outer << "\t";
506  //cout << "outerdrift : " << drift_length_outer << endl;
507 
508 
509  if (lengthPerTb_outer == lengthPerTb_inner )
510  {
511  lengthPerTb = lengthPerTb_outer ;
512  }
513  else
514  {
515  cerr << "Different driftvelocities in TPC observed -> Set to 0. " << endl;
516  lengthPerTb = 0;
517  }
518  //cout << "Constants set by using official transformation." << endl;
519 
520  // set max timebucket
521  max_tb_inner = drift_length_inner/lengthPerTb;
522  max_tb_outer = drift_length_outer/lengthPerTb;
523 
524 #else
525  cout << "This is not functional online.\n" ;
526 #endif
527 
528 };
529 
530 
531 //______________________________
532 void St_l3_Coordinate_Transformer::Get_parameters_from_db()
533 {
534 #ifdef L3OFFLINE
535  // connect to database
536  double driftvelocity = gStTpcDb->DriftVelocity();
537  double inner_effective_driftlength = gStTpcDb->Dimensions()->innerEffectiveDriftDistance();
538  double outer_effective_driftlength = gStTpcDb->Dimensions()->outerEffectiveDriftDistance();
539  double gatingrid = gStTpcDb->Dimensions()->gatingGridZ();
540  double t0pad = gStTpcDb->T0(1)->getT0(1,1);
541  double zinneroffset = gStTpcDb->Dimensions()->zInnerOffset();
542  double zouteroffset = gStTpcDb->Dimensions()->zOuterOffset();
543  double frequency = gStTpcDb->Electronics()->samplingFrequency();
544  double tzero = gStTpcDb->Electronics()->tZero();
545  double tau = gStTpcDb->Electronics()->tau();
546  double shapingtime = gStTpcDb->Electronics()->shapingTime();
547 
548  if (0)
549  {
550  cout << "Fresh from the db we got : \n" ;
551  cout << "The driftvelocity : " << driftvelocity << endl;
552  cout << "The effective innerdrift (not used) : " << inner_effective_driftlength << endl ;
553  cout << "The effective outerdrift (not used) : " << outer_effective_driftlength << endl ;
554  cout << "Innerzoffset : " << zinneroffset << endl ;
555  cout << "Outerzoffset : " << zouteroffset << endl ;
556  cout << "Gatinggrid : " << gatingrid << endl ;
557  cout << "t0pad : " << t0pad << endl ;
558  cout << "The tzero : " << tzero << endl;
559  cout << "Frequency ist set to : " << frequency << endl;
560  cout << "tau : " << tau << endl ;
561  cout << "shapingtime (not used) : " << shapingtime << endl ;
562  }
563 
564  // length per timebucket = 1 / frequency * driftvelocity
565  lengthPerTb = 1 / frequency / (1E6) * driftvelocity ; // cm per timebucket
566 
567  // driftlength = gatingrid - dv * t0 (this is a general t0) + dv/frequency * 0.5 (half a timebucket to get in the middle of a tb)
568  // + zoffset (differnt offset of inner and outer padrows) + t0 (per individual pad = 0 at 05/05/2000)
569  // + 3*tau*driftvelocity ( = shaping time (this depends on the used algorithm used ) this holds for weigthed mean see STARNOT
570  //
571  drift_length_inner = gatingrid-driftvelocity*1e-6*(-tzero+0.5/frequency)+zinneroffset+t0pad+3*tau*1e-09*driftvelocity;
572  drift_length_outer = gatingrid-driftvelocity*1e-6*(-tzero+0.5/frequency)+zouteroffset+t0pad+3*tau*1e-09*driftvelocity;
573 
574 
575  if (0)
576  {
577  cout << "inner drift length : " << drift_length_inner << endl;
578  cout << "outer drift length : " << drift_length_outer << endl;
579  cout << "lengthPerTb : " << lengthPerTb << endl;
580  }
581 
582  // set max timebucket
583  max_tb_inner = drift_length_inner/lengthPerTb;
584  max_tb_outer = drift_length_outer/lengthPerTb;
585 
586 #else
587  cout << "This is not functional online.\n" ;
588 #endif
589 
590 };
591 
592 
593 //______________________________
594 void St_l3_Coordinate_Transformer::Print_parameters()
595 {
596  cout << "St_l3_Coordinate_Transformer: Parameters used <== " << endl ;
597  cout << " Used parameters : " << endl ;
598  cout << " Length per tb : " << lengthPerTb << endl ;
599  cout << " drift_length_inner: " << drift_length_inner << endl ;
600  cout << " drift_length_outer: " << drift_length_outer << endl ;
601  cout << " max_tb_inner : " << max_tb_inner << endl ;
602  cout << " max_tb_outer : " << max_tb_outer << endl ;
603 
604 };
605 
607 // init our statics
609 double St_l3_Coordinate_Transformer::outerSectorPadPitch = 0.67; // cm
610 double St_l3_Coordinate_Transformer::innerSectorPadPitch = 0.335; // cm
611 
612 // number of pads in padrow
613 int St_l3_Coordinate_Transformer::numberOfPadsAtRow[] = {
614  88,96,104,112,118,126,134,142,150,158,166,174,182,
615  98,100,102,104,106,106,108,110,112,112,114,116,
616  118,120,122,122,124,126,128,128,130,132,134,136,
617  138,138,140,142,144,144,144,144
618 };
619 // radial distance (center pad) from detector center in cm
620 double St_l3_Coordinate_Transformer::radialDistanceAtRow[] = {
621  60.0, 64.8, 69.6, 74.4, 79.2, 84.0, 88.8, 93.60, // 7 * 4.80 cm spacing
622  98.8, 104., 109.20, 114.4, 119.6, // 5 * 5.20 cm spacing
623  127.195, 129.195, 131.195, 133.195, 135.195, // 32 * 2.00 cm spacing
624  137.195, 139.195, 141.195, 143.195, 145.195,
625  147.195, 149.195, 151.195, 153.195, 155.195,
626  157.195, 159.195, 161.195, 163.195, 165.195,
627  167.195, 169.195, 171.195, 173.195, 175.195,
628  177.195, 179.195, 181.195, 183.195, 185.195,
629  187.195, 189.195
630 };
631 // sector-rotation factors: 30 degree steps
632 double St_l3_Coordinate_Transformer::SectorSin[] = {
633  0.5, 0.866025404, // 1-2
634  1.0, 0.866025404, // 3-4
635  0.5, 0., // 5-6
636  -0.5, -0.866025404, // 7-8
637  -1.0, -0.866025404, // 9-10
638  -0.5, 0., // 11-12
639  0.5, 0.866025404, // 13-14
640  1.0, 0.866025404, // 15-16
641  0.5, 0., // 17-18
642  -0.5, -0.866025404, // 19-20
643  -1.0, -0.866025404, // 21-22
644  -0.5, 0. // 23-24
645 };
646 // sector-rotation factors: 30 degree steps
647 double St_l3_Coordinate_Transformer::SectorCos[] = {
648  0.866025404, 0.5, // 1-2
649  0., -0.5, // 3-4
650  -0.866025404, -1.0, // 5-6
651  -0.866025404, -0.5, // 7-8
652  0., 0.5, // 9-10
653  0.866025404, 1.0, // 11-12
654  0.866025404, 0.5, // 13-14
655  0., -0.5, // 15-16
656  -0.866025404, -1.0, // 17-18
657  -0.866025404, -0.5, // 19-20
658  0., 0.5, // 21-22
659  0.866025404, 1.0 // 23-24
660 };
661