2 ROOT Macro to generate all numbering believed to be relevant for EMCAL
3 - at least as far as electronics is concerned.
4 Includes FEE, TRU and LED information. Sorry if this macro does not quite
5 adher to ALICE coding conventions (but on the other hand it is not used in AliRoot)
7 Some further documentation is available at:
8 http://cern.ch/dsilverm/mapping/emcal_mapping.html
10 Author: David Silvermyr, ORNL; silvermy@mail.phy.ornl.gov
14 First we define a number of constants; the main method EMCALNumbering starts below
17 const int kDDLEqIdOffsetEMCAL = 0x1200; /* From AliDAQ; first equipment Id # for EMCAL*/
19 // global arrays for chip, channel and CSP numbering
20 // - in the area covered by a single FEC (32 CSPs covering a 4x8 tower area)
25 // the way CSPs are populated, as seen from the back where we
26 // plug in the T-cards
27 const int kCspMap[kNROWS][kNCOLS] = {
38 // i.e. the highest row comes first, and this map should thus be indexed as [NROWS-1-irow][icol]
39 // - Csp help array is constructed below.
42 The rest of the global Chan/Chip arrays are either fixed
43 from the Altro mapping, or a function of the CspMap above
46 // Altro mapping for chips and channels, high and low gain
47 const int kChip[kNCSP] = {
48 2, 2, 2, 2, 3, 3, 3, 3,
49 0, 0, 0, 0, 4, 4, 4, 4,
50 2, 2, 2, 2, 3, 3, 3, 3,
51 0, 0, 0, 0, 4, 4, 4, 4
54 const int kChanHigh[kNCSP] = {
55 10, 14, 5, 1, 1, 5, 14, 10,
56 10, 14, 5, 1, 1, 5, 14, 10,
57 8, 12, 7, 3, 3, 7, 12, 8,
58 8, 12, 7, 3, 3, 7, 12, 8
61 const int kChanLow[kNCSP] = {
62 11, 15, 4, 0, 0, 4, 15, 11,
63 11, 15, 4, 0, 0, 4, 15, 11,
64 9, 13, 6, 2, 2, 6, 13, 9,
65 9, 13, 6, 2, 2, 6, 13, 9
68 // Order that CSPs appear in the data
69 const int kCspOrder[kNCSP] = { // just from ALTRO mapping of chips/channels to CSP
70 11, 27, 10, 26, 24, 8, 25, 9,
71 3, 19, 2, 18, 16, 0, 17, 1,
72 4, 20, 5, 21, 23, 7, 22, 6,
73 12, 28, 13, 29, 31, 15, 30, 14
76 // LED reference info:
77 const int kNLED = 24; // per SuperModule; equals number of StripModules per SuperModule
78 const int kNLEDPerTCard = kNLED / 2;
79 // CSPs and LED are connected on a special T-card with only 12 connectors
80 // Half of the StripModules in a SuperModule will be connected to the Top
81 // (and half to the Bottom) T-card
83 const int kCspMapLEDTop[kNLEDPerTCard] = {
91 const int kStripModuleMapLEDTop[kNLEDPerTCard] = {
101 const int kCspMapLEDBottom[kNLEDPerTCard] = {
102 9, 25, // Strips 12,13
103 10, 26, // Strips 14,15
104 11, 27, // Strips 16,17
105 12, 28, // Strips 18,19
106 13, 29, // Strips 20,21
107 14, 30 // Strips 22,23
109 const int kStripModuleMapLEDBottom[kNLEDPerTCard] = {
118 // let's make some simpler/normal help index arrays too, that we'll use later on
121 int Csp[kNROWS][kNCOLS];
123 // Order that Towers, appear in the data
124 int towerOrder[kNCSP];
128 for(int icol=0; icol<kNCOLS; icol++){
129 for(int irow=0; irow<kNROWS; irow++){
130 int csp = kCspMap[kNROWS-1-irow][icol];
133 Csp[irow][icol] = csp;
135 cout << " icol " << icol
137 << " csp " << csp << endl;
141 // let's also give the order that Towers appear in the data
142 for (int ic=0; ic<kNCSP; ic++) {
143 int towerid = ROW[kCspOrder[ic]]*kNCOLS + COL[kCspOrder[ic]];
144 towerOrder[ic] = towerid;
149 // help functions for TRU mapping:
150 int getTRUADC(int iFEC) { // iFEC is a number 0-35, within a SM
151 // ADC channel 1-12 on TRU as a function of connected iFEC
152 return (iFEC%12 + 1);
155 int getTRUADCChan(int iCSP) { // iCSP is from 0 to 31
156 int bottom = (iCSP%16)/8; // 0 for top, 1 for bottom T-card
157 int iADCChan = (iCSP%8)/2 + 1; // within a T-card; 1-4
158 return (iADCChan + bottom*4);
160 // ok, done with TRU help methods also; let's do what needs to be done
162 // HERE STARTS THE MAIN METHOD..
163 void EMCalNumbering()
166 General coord. info: ALICE-INT-2003-038 EDMS doc.
168 z goes in the beam direction from RB26 (side C,where the muon arm is,Gex),
169 to RB24 (side A, Bellegarde), i.e. away from muon arm.
171 x is horizontal, perpendicular to the beam direction and points to the
172 accelerator (LHC ring) centre.
173 [visual aid.: pos. x = Saleve; Inside/I, negative = Jura; Outside/O]
175 y is vertical, perpendicular to z and x. Positive y points upward.
176 [pos. y = Up/U. neg. y = Down/D]
178 The usual relation to r, phi(-pi, pi), theta (0,pi) applies:
179 x = r * sin(theta) * cos(phi);
180 y = r * sin(theta) * sin(phi);
183 r = sqrt(x*x + y*y +z*z);
184 theta = TMath::ACos(z/r);
185 phi = TMath::ATan2(y, x);
188 /* Numbering rules: ALICE-INT-2003-038 EDMS doc.
190 All numbering starts from 0.
192 Rotational Numbering: follows phi direction
193 [looks counter-clockwise from A, and clockwise from C]
195 Linear numbering: follows _reverse_ z-direction from A to C,
196 without interruption at z=0
197 [presumably to have a reasonable numbering in the muon system]
199 Radial numbering increases outwards, but EMCAL only has one layer.
200 so doesn't matter for us.
205 initTowers(); // prepare setup
207 // global info on sectors
208 const int kNFullSect = 5;
209 const int kNThirdSect = 1;
210 const int kNSides = 2; // supermodules for both positive and negative Z
211 // let's call side A '0', and side C '1'
213 // Number of SuperModules and DDLs total
214 const int kNSM = (kNFullSect + kNThirdSect)*kNSides; // 12
215 // const int NDDL = NSides*(NFullSect * 2 + NThirdSect*1); // 22
217 // per supermodule info
218 const int kNTowersZ = 48;
219 const int kNTowersPhi = 24;
220 const int kNTowersPerFEC = 32;
221 const int kNFEC = 36;
226 const int kNTowersSM = kNTowersZ*kNTowersPhi; // 1152
228 const int kNModulesZ = kNTowersZ/2; // 24
229 const int kNModulesPhi = kNTowersPhi/2; // 12
230 const int kNModulesSM = kNTowersSM/4; // 288
233 const int kNFECPerGTL = kNFEC/kNGTL; // 9
235 const int kNFECPerRCU = kNFEC/kNRCU; // 18
237 const int kNFECPerTRU = kNFEC/kNTRU; // 12
239 // and per FrontEndCard:
240 // 2 T-cards, each with 16 towers, per FEC
241 const int kNTCards = 2;
242 // each T-card covers a 2x8 tower area
243 const int kNTowersPhiTC = 8;
244 const int kNTowersZTC = 2;
246 // OK, that was all the setup and definitions of constants..
248 /* Now, how do we populate the Supermodule and it's GTL space?
249 Simplest seems to be to have 3 rows of 12 FECs each,
250 where each FEC's 2 T-cards cover a 4(z)*8(phi) tower area.
251 Do the coverage in order..
253 const int kNFECPerRow = kNFEC/3; // 12
255 TFile *f = new TFile("map.root","RECREATE");
258 int iside = 0; // A=0, C=1
259 int isect = 0; // 0-5
260 int iSM = 0; // 0-11, offline SuperModule index
261 int iDDLEqId = 0; // kDDLEqIdOffsetEMCAL = 0x1200 upwards (NDDL)
265 int iTRU = 0; // 0-2, within SM
266 int iTRUADC = 0; // 1-8, within TRU
267 int iRCU = 0; // 0-1, within SM
268 int iBranch = 0; // A=0, B=1
269 int iGTL = 0; // address 1-9; TRU is in address slot 0
271 int nTow = kNCSP; // # of towers, per FEC
272 int CSP[kNCSP] = {0};
273 int chip[kNCSP] = {0};
274 int lowGainChan[kNCSP] = {0};
275 int highGainChan[kNCSP] = {0};
276 int towerCol[kNCSP] = {0};
277 int towerRow[kNCSP] = {0};
278 int iTRUADCChan[kNCSP] = {0};
280 TTree *t = new TTree("tree","ALICE EMCal tower map");
281 t->Branch("iside",&iside,"iside/I");
282 t->Branch("isect",&isect,"isect/I");
283 t->Branch("iSM",&iSM,"iSM/I");
284 t->Branch("iDDLEqId",&iDDLEqId,"iDDLEqId/I");
285 t->Branch("iFEC",&iFEC,"iFEC/I");
286 t->Branch("iTRU",&iTRU,"iTRU/I");
287 t->Branch("iTRUADC",&iTRUADC,"iTRUADC/I");
288 t->Branch("iRCU",&iRCU,"iRCU/I");
289 t->Branch("iBranch",&iBranch,"iBranch/I");
290 t->Branch("iGTL",&iGTL,"iGTL/I");
291 t->Branch("nTow",&nTow,"nTow/I");
292 t->Branch("CSP",CSP,"CSP[nTow]/I");
293 t->Branch("chip",chip,"chip[nTow]/I");
294 t->Branch("lowGainChan",lowGainChan,"lowGainChan[nTow]/I");
295 t->Branch("highGainChan",highGainChan,"highGainChan[nTow]/I");
296 t->Branch("towerCol",towerCol,"towerCol[nTow]/I");
297 t->Branch("towerRow",towerRow,"towerRow[nTow]/I");
298 t->Branch("towerOrder",towerOrder,"towerOrder[nTow]/I");
299 t->Branch("iTRUADCChan",iTRUADCChan,"iTRUADCChan[nTow]/I");
302 TTree *tLED = new TTree("tLED","ALICE EMCal LED reference map");
303 tLED->Branch("iside",&iside,"iside/I");
304 tLED->Branch("isect",&isect,"isect/I");
305 tLED->Branch("iSM",&iSM,"iSM/I");
306 tLED->Branch("iDDLEqId",&iDDLEqId,"iDDLEqId/I");
307 tLED->Branch("iRCU",&iRCU,"iRCU/I");
308 tLED->Branch("iBranch",&iBranch,"iBranch/I");
309 tLED->Branch("iGTL",&iGTL,"iGTL/I");
311 tLED->Branch("nLED",&nLED,"nLED/I");
312 int iLEDCSP[kNLED] = {0};
313 int iLEDchip[kNLED] = {0};
314 int iLEDhighGainChan[kNLED] = {0};
315 int iLEDlowGainChan[kNLED] = {0};
316 int iLEDStrip[kNLED] = {0};
317 tLED->Branch("iLEDCSP",iLEDCSP,"iLEDCSP[nLED]/I");
318 tLED->Branch("iLEDchip",iLEDchip,"iLEDchip[nLED]/I");
319 tLED->Branch("iLEDlowGainChan",iLEDlowGainChan,"iLEDlowGainChan[nLED]/I");
320 tLED->Branch("iLEDhighGainChan",iLEDhighGainChan,"iLEDhighGainChan[nLED]/I");
321 tLED->Branch("iLEDStrip",iLEDStrip,"iLEDStrip[nLED]/I");
324 TTree *tTRU = new TTree("tTRU","ALICE EMCal TRU fake-altro map");
325 tTRU->Branch("iside",&iside,"iside/I");
326 tTRU->Branch("isect",&isect,"isect/I");
327 tTRU->Branch("iSM",&iSM,"iSM/I");
328 tTRU->Branch("iDDLEqId",&iDDLEqId,"iDDLEqId/I");
329 tTRU->Branch("iRCU",&iRCU,"iRCU/I");
330 tTRU->Branch("iBranch",&iBranch,"iBranch/I");
331 tTRU->Branch("iGTL",&iGTL,"iGTL/I");
332 // TRU is identified by (GTL==0 && !(Branch==0 && RCU==0))
333 int iTRUFirstChan = 0;
334 int iTRULastChan = 127; // maximum allowed number of fake ALTRO channels=128 from TRU
335 tTRU->Branch("iTRUFirstChan",&iTRUFirstChan,"iTRUFirstChan/I");
336 tTRU->Branch("iTRULastChan",&iTRULastChan,"iTRULastChan/I");
338 for (isect = 0; isect<(kNFullSect+kNThirdSect); isect++) {
339 for (iside=0; iside<kNSides; iside++) { // A or C sides
340 // half sector only has one third of the FECs
345 if (isect==kNFullSect) { // meaning last third-size-sector
346 if (iside==0) { // A side
350 else if (iside==1) { // C side
351 MINFEC = 2 * kNFEC / 3;
356 iSM = isect*2 + iside;
357 for (iFEC=MINFEC; iFEC<MAXFEC; iFEC++) {
359 // ok, where does this FEC belong? Use the local iFEC index which starts with 0
360 // closest to the crate and revert to global z and phi index at the end..
362 iTRU = iFEC / (kNFECPerTRU);
363 iTRUADC = getTRUADC(iFEC);
364 iRCU = iFEC / (kNFECPerRCU);
365 iBranch = (iFEC%kNFECPerRCU) / kNFECPerGTL; // local index inside RCU
366 iGTL = iFEC % kNFECPerGTL + 1;
368 iDDLEqId = kDDLEqIdOffsetEMCAL + iSM*kNRCU + iRCU;
370 // tower limits/indices
371 int tcolLow = (iFEC%kNFECPerRow)*kNCOLS;
372 int trowLow = (iFEC/kNFECPerRow)*kNROWS;
374 printf("iside %d iSM %d: FEC %02d RCU %d Branch %d iGTL\n",
375 iside, iSM, iFEC, iRCU, iBranch, iGTL);
377 for (int col=0; col<kNCOLS; col++) {
378 for (int row=0; row<kNROWS; row++) {
379 int tcol = col + tcolLow;
380 int trow = row + trowLow;
382 int itow = row*kNCOLS + col;
384 CSP[itow] = Csp[row][col];
385 chip[itow] = kChip[CSP[itow]];
386 lowGainChan[itow] = kChanLow[CSP[itow]];
387 highGainChan[itow] = kChanHigh[CSP[itow]];
389 iTRUADCChan[itow] = getTRUADCChan(CSP[itow]);
391 // we need to switch to global indices if we are on side C
393 tcol = kNTowersZ-1 - tcol; // flip axis
394 trow = kNTowersPhi-1 - trow; // just flip axis
397 towerCol[itow] = tcol;
398 towerRow[itow] = trow;
405 // also handle special LED and TRU mapping
406 iGTL = 0; // they are all in GTL/FEC slot 0
409 iRCU = 0; iBranch = 0;
410 iDDLEqId = kDDLEqIdOffsetEMCAL + iSM*kNRCU + iRCU;
412 /* for the special 'half'/third sector, side C, there is
413 no RCU=0.. So we put the LED in RCU=1 instead then.
414 There is only 1 TRU in this sector (RCU=1, branch=1), so no problem..
416 if (MINTRU == 2) { // key for this special sector
421 // loop over attached CSPs
423 for (int iled = 0; iled<kNLEDPerTCard; iled++) {
425 iLEDCSP[il] = kCspMapLEDTop[iled];
426 iLEDStrip[il] = kStripModuleMapLEDTop[iled];
428 cout << " LED CSP " << iLEDCSP[il]
429 << " Strip " << iLEDStrip[il] << endl;
431 iLEDchip[il] = kChip[iLEDCSP[il]];
432 iLEDlowGainChan[il] = kChanLow[iLEDCSP[il]];
433 iLEDhighGainChan[il] = kChanHigh[iLEDCSP[il]];
436 for (int iled = 0; iled<kNLEDPerTCard; iled++) {
437 int il = iled + kNLEDPerTCard; // just a convenient index
438 iLEDCSP[il] = kCspMapLEDBottom[iled];
439 iLEDStrip[il] = kStripModuleMapLEDBottom[iled];
441 cout << " LED CSP " << iLEDCSP[il]
442 << " Strip " << iLEDStrip[il] << endl;
444 iLEDchip[il] = kChip[iLEDCSP[il]];
445 iLEDlowGainChan[il] = kChanLow[iLEDCSP[il]];
446 iLEDhighGainChan[il] = kChanHigh[iLEDCSP[il]];
450 // then we also have the TRUs (fake ALTRO)
451 for (iTRU=MINTRU; iTRU<MAXTRU; iTRU++) {
453 if (iTRU == 0) { iRCU = 0; iBranch = 1; }
454 else if (iTRU == 1) { iRCU = 1; iBranch = 0; }
455 else if (iTRU == 2) { iRCU = 1; iBranch = 1; }
457 cout << " TRU " << iTRU
459 << " Branch " << iBranch << endl;
461 iDDLEqId = kDDLEqIdOffsetEMCAL + iSM*kNRCU + iRCU;
463 last sector only has 1 TRU, but it's probably called TRU 0 on A
464 and TRU 2 on C side..
465 This is handled via MINFEC/MAXFEC and MINTRU/MAXTRU at the start