Updated ZDC geometry
[u/mrichter/AliRoot.git] / ZDC / AliZDC.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
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  **************************************************************************/
15
16 /* $Id$ */
17
18 ///////////////////////////////////////////////////////////////////////////////
19 //                                                                           //
20 //                      Zero Degree Calorimeter                              //
21 //           This class contains the basic functions for the ZDCs;           //
22 //            functions specific to one particular geometry are              //
23 //                      contained in the derived classes                     //
24 //                                                                           //
25 ///////////////////////////////////////////////////////////////////////////////
26
27 // --- ROOT system
28 #include <TBRIK.h>
29 #include <TGeometry.h>
30 #include <TNode.h>
31 #include <TTree.h>
32
33 // --- AliRoot header files
34 #include "AliDetector.h"
35 #include "AliZDC.h"
36 #include "AliZDCHit.h"
37 #include "AliZDCSDigit.h"
38 #include "AliZDCDigit.h"
39 #include "AliZDCDigitizer.h"
40 #include "AliZDCRawStream.h"
41
42 #include "AliRawDataHeader.h"
43 #include "AliLoader.h"
44 #include "AliRun.h"
45 #include "AliMC.h"
46
47  
48 ClassImp(AliZDC)
49  
50 //_____________________________________________________________________________
51 AliZDC::AliZDC()
52 {
53   //
54   // Default constructor for the Zero Degree Calorimeter base class
55   //
56   
57   fIshunt     = 1;
58   fNoShower   = 0;
59
60   fHits       = 0;
61   fNhits      = 0;
62
63   fDigits     = 0;
64   fNdigits    = 0;
65
66 }
67  
68 //_____________________________________________________________________________
69 AliZDC::AliZDC(const char *name, const char *title)
70   : AliDetector(name,title)
71 {
72   //
73   // Standard constructor for the Zero Degree Calorimeter base class
74   //
75
76   fIshunt   = 1;
77   fNoShower = 0;
78
79   // Allocate the hits array  
80   fHits   = new TClonesArray("AliZDCHit",1000);
81   gAlice->GetMCApp()->AddHitList(fHits);
82
83   fDigits     = 0;
84   fNdigits    = 0;
85
86 }
87 //____________________________________________________________________________ 
88 AliZDC::~AliZDC()
89 {
90   //
91   // ZDC destructor
92   //
93
94   fIshunt   = 0;
95
96 }
97 //_____________________________________________________________________________
98 void AliZDC::AddHit(Int_t track, Int_t *vol, Float_t *hits)
99 {
100   //
101   //            Add a ZDC hit to the hit list.
102   // -> We make use of 2 array of hits:
103   // [1]  fHits (the usual one) that contains hits for each PRIMARY
104   // [2]  fStHits that contains hits for each EVENT and is used to
105   //      obtain digits at the end of each event
106   //
107   
108   static Float_t primKinEn, xImpact, yImpact, sFlag;
109
110   AliZDCHit *newquad, *curprimquad;
111   newquad = new AliZDCHit(fIshunt, track, vol, hits);
112   TClonesArray &lhits = *fHits;
113   
114   if(fNhits==0){
115       // First hit -> setting flag for primary or secondary particle
116       Int_t primary = gAlice->GetMCApp()->GetPrimary(track);     
117       if(track != primary){
118         newquad->SetSFlag(1);  // SECONDARY particle entering the ZDC
119       }
120       else if(track == primary){
121         newquad->SetSFlag(0);  // PRIMARY particle entering the ZDC
122       }  
123       sFlag     = newquad->GetSFlag();
124       primKinEn = newquad->GetPrimKinEn();
125       xImpact   = newquad->GetXImpact();
126       yImpact   = newquad->GetYImpact();
127    }
128    else{       
129       newquad->SetPrimKinEn(primKinEn);
130       newquad->SetXImpact(xImpact);
131       newquad->SetYImpact(yImpact);
132       newquad->SetSFlag(sFlag);
133    }
134  
135   Int_t j;
136   for(j=0; j<fNhits; j++){
137     // If hits are equal (same track, same volume), sum them.
138      curprimquad = (AliZDCHit*) lhits[j];
139      if(*curprimquad == *newquad){
140         *curprimquad = *curprimquad+*newquad;
141         delete newquad;
142         return;
143      } 
144   }
145
146     //Otherwise create a new hit
147     new(lhits[fNhits]) AliZDCHit(newquad);
148     fNhits++;
149     
150     delete newquad;
151 }
152
153 //_____________________________________________________________________________
154 void AliZDC::BuildGeometry()
155 {
156   //
157   // Build the ROOT TNode geometry for event display 
158   // in the Zero Degree Calorimeter
159   // This routine is dummy for the moment
160   //
161
162   TNode *node, *top;
163   TBRIK *brik;
164   const int kColorZDC  = kBlue;
165   
166   //
167   top=gAlice->GetGeometry()->GetNode("alice");
168   
169   // ZDC
170     brik = new TBRIK("S_ZDC","ZDC box","void",300,300,5);
171     top->cd();
172     node = new TNode("ZDC","ZDC","S_ZDC",0,0,600,"");
173     node->SetLineColor(kColorZDC);
174     fNodes->Add(node);
175 }
176
177 //_____________________________________________________________________________
178 Int_t AliZDC::DistancetoPrimitive(Int_t , Int_t )
179 {
180   //
181   // Distance from the mouse to the Zero Degree Calorimeter
182   // Dummy routine
183   //
184   return 9999;
185 }
186
187 //____________________________________________________________________________
188 Float_t AliZDC::ZMin(void) const
189 {
190   // Minimum dimension of the ZDC module in z
191   return -11600.;
192 }
193
194 //____________________________________________________________________________
195 Float_t AliZDC::ZMax(void) const
196 {
197   // Maximum dimension of the ZDC module in z
198   return -11750.;
199 }
200   
201
202 //_____________________________________________________________________________
203 void AliZDC::MakeBranch(Option_t *opt, const char * /*file*/)
204 {
205   //
206   // Create Tree branches for the ZDC
207   //
208
209   char branchname[10];
210   sprintf(branchname,"%s",GetName());
211
212   const char *cH = strstr(opt,"H");
213   
214   if (cH && fLoader->TreeH())
215    fHits   = new TClonesArray("AliZDCHit",1000); 
216   
217   AliDetector::MakeBranch(opt);
218 }
219
220 //_____________________________________________________________________________
221 void AliZDC::Hits2SDigits()
222 {
223   // Create summable digits from hits
224   
225   if (GetDebug()) printf("\n    Entering AliZDC::Hits2Digits() ");
226   
227   fLoader->LoadHits("read");
228   fLoader->LoadSDigits("recreate");
229   AliRunLoader* runLoader = fLoader->GetRunLoader();
230   AliZDCSDigit sdigit;
231   AliZDCSDigit* psdigit = &sdigit;
232
233   // Event loop
234   for (Int_t iEvent = 0; iEvent < runLoader->GetNumberOfEvents(); iEvent++) {
235     Float_t pmCZN = 0, pmCZP = 0, pmQZN[4], pmQZP[4], pmZEM1 = 0, pmZEM2 = 0;
236     for (Int_t i = 0; i < 4; i++) pmQZN[i] = pmQZP[i] = 0;
237
238     runLoader->GetEvent(iEvent);
239     TTree* treeH = fLoader->TreeH();
240     Int_t ntracks = (Int_t) treeH->GetEntries();
241     ResetHits();
242
243     // Tracks loop
244     Int_t sector[2];
245     for (Int_t itrack = 0; itrack < ntracks; itrack++) {
246       treeH->GetEntry(itrack);
247       for (AliZDCHit* zdcHit = (AliZDCHit*)FirstHit(-1); zdcHit;
248                       zdcHit = (AliZDCHit*)NextHit()) { 
249                       
250         sector[0] = zdcHit->GetVolume(0);
251         sector[1] = zdcHit->GetVolume(1);
252         if ((sector[1] < 1) || (sector[1] > 4)) {
253           Error("Hits2SDigits", "sector[0] = %d, sector[1] = %d", 
254                 sector[0], sector[1]);
255           continue;
256         }
257         Float_t lightQ = zdcHit->GetLightPMQ();
258         Float_t lightC = zdcHit->GetLightPMC();
259      
260         if (sector[0] == 1) {          //ZN 
261           pmCZN += lightC;
262           pmQZN[sector[1]-1] += lightQ;
263         } else if (sector[0] == 2) {   //ZP 
264           pmCZP += lightC;
265           pmQZP[sector[1]-1] += lightQ;
266         } else if (sector[0] == 3) {   //ZEM 
267           if (sector[1] == 1) pmZEM1 += lightC;
268           else                pmZEM2 += lightQ;
269         }
270       }//Hits loop
271     }
272
273     // create the output tree
274     fLoader->MakeTree("S");
275     TTree* treeS = fLoader->TreeS();
276     const Int_t kBufferSize = 4000;
277     treeS->Branch(GetName(), "AliZDCSDigit", &psdigit, kBufferSize);
278
279     // Create sdigits for ZN
280     sector[0] = 1; // Detector = ZN
281     sector[1] = 0; // Common PM ADC
282     new(psdigit) AliZDCSDigit(sector, pmCZN);
283     if (pmCZN > 0) treeS->Fill();
284     for (Int_t j = 0; j < 4; j++) {
285       sector[1] = j+1; // Towers PM ADCs
286       new(psdigit) AliZDCSDigit(sector, pmQZN[j]);
287       if (pmQZN[j] > 0) treeS->Fill();
288     }
289   
290     // Create sdigits for ZP
291     sector[0] = 2; // Detector = ZP
292     sector[1] = 0; // Common PM ADC
293     new(psdigit) AliZDCSDigit(sector, pmCZP);
294     if (pmCZP > 0) treeS->Fill();
295     for (Int_t j = 0; j < 4; j++) {
296       sector[1] = j+1; // Towers PM ADCs
297       new(psdigit) AliZDCSDigit(sector, pmQZP[j]);
298       if (pmQZP[j] > 0) treeS->Fill();
299     }
300
301     // Create sdigits for ZEM
302     sector[0] = 3; 
303     sector[1] = 1; // Detector = ZEM1
304     new(psdigit) AliZDCSDigit(sector, pmZEM1);
305     if (pmZEM1 > 0) treeS->Fill();
306     sector[1] = 2; // Detector = ZEM2
307     new(psdigit) AliZDCSDigit(sector, pmZEM2);
308     if (pmZEM2 > 0) treeS->Fill();
309
310     // write the output tree
311     fLoader->WriteSDigits("OVERWRITE");
312   }
313
314   fLoader->UnloadHits();
315   fLoader->UnloadSDigits();
316 }
317
318 //_____________________________________________________________________________
319 AliDigitizer* AliZDC::CreateDigitizer(AliRunDigitizer* manager) const
320 {
321   // Create the digitizer for ZDC
322
323   return new AliZDCDigitizer(manager);
324 }
325
326 //_____________________________________________________________________________
327 void AliZDC::Digits2Raw()
328 {
329   // Convert ZDC digits to raw data
330
331   // preliminary format: 12 interger values (ZNC, ZNQ1-4, ZPC, ZPQ1-4, ZEM1,2)
332   // For the CAEN module V965 we have an header, the Data Words and an End Of Block
333   UInt_t ADCHeader; 
334   UInt_t ADCData[24];
335   UInt_t ADCEndBlock;
336
337   // load the digits
338   fLoader->LoadDigits("read");
339   AliZDCDigit digit;
340   AliZDCDigit* pdigit = &digit;
341   TTree* treeD = fLoader->TreeD();
342   if (!treeD) return;
343   treeD->SetBranchAddress("ZDC", &pdigit);
344
345   // Fill data array
346   // ADC header
347   UInt_t ADCHeaderGEO = 0;
348   UInt_t ADCHeaderCRATE = 0;
349   UInt_t ADCHeaderCNT = (UInt_t) treeD->GetEntries();
350     
351   ADCHeader = ADCHeaderGEO << 27 | 0x1 << 25 | ADCHeaderCRATE << 16 |
352               ADCHeaderCNT << 8 ;
353
354   //printf("ADCHeader = %d\n",ADCHeader);
355       
356   // ADC data word
357   UInt_t ADCDataGEO = ADCHeaderGEO;
358   UInt_t ADCDataValue[24];
359   UInt_t ADCDataOvFlw[24];
360   for(Int_t i = 0; i < 24; i++){
361     ADCDataValue[i] = 0;
362     ADCDataOvFlw[i] = 0;
363   }
364   UInt_t ADCDataChannel = 0;
365   
366   // loop over digits
367   for (Int_t iDigit = 0; iDigit < treeD->GetEntries(); iDigit++) {
368     treeD->GetEntry(iDigit);
369     if (!pdigit) continue;
370
371     //ADC data
372     Int_t index = 0;
373     if(digit.GetSector(0)!=3){
374       index = (digit.GetSector(0)-1) + digit.GetSector(1)*4;
375       ADCDataChannel = (digit.GetSector(0)-1)*8 + digit.GetSector(1);
376     }
377     else {
378       index = 19 + digit.GetSector(1);
379       ADCDataChannel = 5 + digit.GetSector(1)*8;
380     }
381      
382     if ((index < 0) || (index >= 22)) {
383       Error("Digits2Raw", "sector[0] = %d, sector[1] = %d", 
384             digit.GetSector(0), digit.GetSector(1));
385       continue;
386     }
387     
388     ADCDataValue[index] = digit.GetADCValue(0);
389     if (ADCDataValue[index] > 2047) ADCDataOvFlw[index] = 1; 
390     ADCDataValue[index+2] = digit.GetADCValue(1);
391     if (ADCDataValue[index+2] > 2047) ADCDataOvFlw[index+2] = 1; 
392     
393     ADCData[index] =   ADCDataGEO << 27 | ADCDataChannel << 17 | 
394                        ADCDataOvFlw[index] << 12 | (ADCDataValue[index] & 0xfff); 
395     ADCData[index+2] = ADCDataGEO << 27 | ADCDataChannel << 17 | 0x1 << 16 |
396                        ADCDataOvFlw[index+2] << 12 | (ADCDataValue[index+2] & 0xfff);                    
397   }
398   //for (Int_t i=0;i<24;i++)printf("ADCData[%d] = %d\n",i,ADCData[i]);
399   
400   // End of Block
401   UInt_t ADCEndBlockGEO = ADCHeaderGEO;
402   UInt_t ADCEndBlockEvCount = gAlice->GetEventNrInRun();
403   
404   ADCEndBlock = ADCEndBlockGEO << 27 | 0x1 << 26 | ADCEndBlockEvCount;
405   
406   //printf("ADCEndBlock = %d\n",ADCEndBlock);
407
408
409   // open the output file
410   char fileName[30];
411   sprintf(fileName, "ZDC_%d.ddl", AliZDCRawStream::kDDLOffset);
412 #ifndef __DECCXX
413   ofstream file(fileName, ios::binary);
414 #else
415   ofstream file(fileName);
416 #endif
417
418   // write the DDL data header
419   AliRawDataHeader header;
420   header.fSize = sizeof(header) + sizeof(ADCHeader) + 
421                  sizeof(ADCData) + sizeof(ADCEndBlock);
422   //printf("sizeof header = %d, ADCHeader = %d, ADCData = %d, ADCEndBlock = %d\n",
423   //        sizeof(header),sizeof(ADCHeader),sizeof(ADCData),sizeof(ADCEndBlock));
424   header.SetAttribute(0);  // valid data
425   file.write((char*)(&header), sizeof(header));
426
427   // write the raw data and close the file
428   file.write((char*) &ADCHeader, sizeof (ADCHeader));
429   file.write((char*)(ADCData), sizeof(ADCData));
430   file.write((char*) &ADCEndBlock, sizeof(ADCEndBlock));
431   file.close();
432
433   // unload the digits
434   fLoader->UnloadDigits();
435 }
436
437 //______________________________________________________________________
438 void AliZDC::SetTreeAddress(){
439   // Set branch address for the Trees.
440   // Inputs:
441   //      none.
442   // Outputs:
443   //      none.
444   // Return:
445   //      none.
446   if (fLoader->TreeH() && (fHits == 0x0))
447     fHits   = new TClonesArray("AliZDCHit",1000);
448       
449   AliDetector::SetTreeAddress();
450 }
451