af05dd4ea1eca5054e255545525948e95eff5294
[u/mrichter/AliRoot.git] / FMD / AliFMDRawWriter.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 /* $Id$ */
16 /** @file    AliFMDRawWriter.cxx
17     @author  Christian Holm Christensen <cholm@nbi.dk>
18     @date    Mon Mar 27 12:45:56 2006
19     @brief   Class to write raw data 
20 */
21 //____________________________________________________________________
22 //
23 // Class to write ADC values to a raw data file
24 //
25 // This class writes FMD Raw data to a file.   The sample rate (number
26 // of times the ALTRO ADC samples each pre-amp. channel - that is,
27 // data from a single strip), can be set via SetSampleRate. 
28 //
29 // Zero-suppression can be enabled by calling SetThreshold with a
30 // non-zero argument.   ADC values less than the value set will not be
31 // written to output.   Note, that if you use zero-suppression, you
32 // need to explicitly set the sample rate when reading back the data
33 // with AliFMDRawReader. 
34 // 
35 // This class uses the AliAltroBuffer class to write the data in the
36 // ALTRO format.  See the Exec member function for more information on
37 // that format.  
38 //
39 // #include <AliLog.h>          // ALILOG_H
40 #include "AliFMDDebug.h" // Better debug macros
41 #include <AliLoader.h>          // ALILOADER_H
42 #include <AliAltroBuffer.h>     // ALIALTROBUFFER_H
43 #include "AliFMD.h"             // ALIFMD_H
44 #include "AliFMDParameters.h"   // ALIFMDPARAMETERS_H
45 #include "AliFMDDigit.h"        // ALIFMDDIGIT_H
46 #include "AliFMDRawWriter.h"    // ALIFMDRAWREADER_H 
47 #include "AliFMDAltroMapping.h" // ALIFMDALTROMAPPING_H
48 // #include "AliFMDAltroIO.h"   // ALIFMDALTROWRITER_H
49 #include <TArrayI.h>            // ROOT_TArrayI
50 #include <TClonesArray.h>       // ROOT_TClonesArray
51 // #include <fstream>
52 #include "AliDAQ.h"
53
54 //____________________________________________________________________
55 ClassImp(AliFMDRawWriter)
56 #if 0
57   ; // This is here to keep Emacs for indenting the next line
58 #endif
59
60 //____________________________________________________________________
61 AliFMDRawWriter::AliFMDRawWriter(AliFMD* fmd) 
62   : TTask("FMDRawWriter", "Writer of Raw ADC values from the FMD"),
63     fFMD(fmd),
64     fSampleRate(0), 
65     fChannelsPerAltro(0), 
66     fThreshold(0)
67 {
68   // CTOR 
69   AliFMDDebug(5, ("Created AliFMDRawWriter object"));
70 }
71
72
73
74 //____________________________________________________________________
75 void
76 AliFMDRawWriter::Exec(Option_t*) 
77 {
78   // Turn digits into raw data. 
79   // 
80   // Digits are read from the Digit branch, and processed to make
81   // three DDL files, one for each of the sub-detectors FMD1, FMD2,
82   // and FMD3. 
83   //
84   // The raw data files consists of a header, followed by ALTRO
85   // formatted blocks.  
86   // 
87   //          +-------------+
88   //          | Header      |
89   //          +-------------+
90   //          | ALTRO Block |
91   //          | ...         |
92   //          +-------------+
93   //          DDL file 
94   // 
95   // An ALTRO formatted block, in the FMD context, consists of a
96   // number of counts followed by a trailer. 
97   // 
98   //          +------------------+
99   //          | Count            |
100   //          | ...              |
101   //          | possible fillers |
102   //          +------------------+
103   //          | Trailer          |
104   //          +------------------+
105   //          ALTRO block 
106   // 
107   // The counts are listed backwards, that is, starting with the
108   // latest count, and ending in the first. 
109   // 
110   // Each count consist of 1 or more ADC samples of the VA1_ALICE
111   // pre-amp. signal.  Just how many samples are used depends on
112   // whether the ALTRO over samples the pre-amp.  Each sample is a
113   // 10-bit word, and the samples are grouped into 40-bit blocks 
114   //
115   //          +------------------------------------+
116   //          |  S(1)   | S(2)   | S(3)   | S(4)   |
117   //          |  ...    | ...    | ...    | ...    |
118   //          |  S(n)   | T(n)   | n+2    | 2AA    |
119   //          +------------------------------------+
120   //          Counts + possible filler 
121   //
122   // The trailer of the number of words of signales, the starting
123   // strip number, the sector number, and the ring ID; each 10-bit
124   // words,  packed into 40-bits. 
125   // 
126   //          +------------------------------------+
127   //          |   2AAA   |  Len   |  A |  Address  |
128   //          +------------------------------------+
129   //          Trailer
130   // 
131   // Note, that this method assumes that the digits are ordered. 
132   // 
133   AliLoader* loader = fFMD->GetLoader();
134   loader->LoadDigits("READ");
135   TTree* digitTree = loader->TreeD();
136   if (!digitTree) {
137     AliError("no digit tree");
138     return;
139   }
140   
141   TClonesArray* digits = new TClonesArray("AliFMDDigit", 1000);
142   fFMD->SetTreeAddress();
143   TBranch* digitBranch = digitTree->GetBranch(fFMD->GetName());
144   if (!digitBranch) {
145     AliError(Form("no branch for %s", fFMD->GetName()));
146     return;
147   }
148   digitBranch->SetAddress(&digits);
149   
150   Int_t nEvents = Int_t(digitTree->GetEntries());
151   AliFMDDebug(5, ("Got a total of %5d events from tree", nEvents));
152   for (Int_t event = 0; event < nEvents; event++) {
153     fFMD->ResetDigits();
154     digitTree->GetEvent(event);
155     
156     // Write out the digits
157     WriteDigits(digits);
158   }
159   loader->UnloadDigits();
160 }
161
162 #if 1
163 //____________________________________________________________________
164 void
165 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
166 {
167   // WRite an array of digits to disk file 
168   Int_t nDigits = digits->GetEntries();
169   if (nDigits < 1) return;
170   AliFMDDebug(5, ("Got a total of %5d digits from tree", nDigits));
171
172   AliFMDParameters* pars = AliFMDParameters::Instance();
173   UShort_t threshold    = 0;
174   UInt_t   prevddl      = 0xFFFF;
175   UInt_t   prevaddr     = 0xFFF;
176   // UShort_t prevStrip    = 0;
177   
178   // Which channel number in the ALTRO channel we're at 
179   UShort_t nWords       = 0;
180   UShort_t preSamples   = 0;
181   UShort_t sampleRate   = 0;
182   
183   // A buffer to hold 1 ALTRO channel - Normally, one ALTRO channel
184   // holds 128 VA1_ALICE channels, sampled at a rate of `sampleRate' 
185   TArrayI data(pars->GetChannelsPerAltro() * 8);
186
187   // The Altro buffer 
188   AliAltroBuffer* altro = 0;
189   
190   Int_t totalWords = 0;
191   Int_t nCounts    = 0;
192   
193   // Loop over the digits in the event.  Note, that we assume the
194   // the digits are in order in the branch.   If they were not, we'd
195   // have to cache all channels before we could write the data to
196   // the ALTRO buffer, or we'd have to set up a map of the digits. 
197   UShort_t oldDet = 1000;
198   for (Int_t i = 0; i < nDigits; i++) {
199     // Get the digit
200     AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
201     UShort_t det    = digit->Detector();
202     Char_t   ring   = digit->Ring();
203     UShort_t sector = digit->Sector();
204     UShort_t strip  = digit->Strip();
205     UInt_t   ddl;
206     UInt_t   addr;  
207     UShort_t time;
208
209     AliFMDDebug(10, ("Processing digit # %5d FMD%d%c[%2d,%3d]", 
210                     i, det, ring, sector, strip));
211     threshold  = pars->GetZeroSuppression(det, ring, sector, strip);
212     sampleRate = pars->GetSampleRate(det, ring, sector, strip);
213     preSamples = pars->GetPreSamples(det, ring, sector, strip);
214
215     if (det != oldDet) {
216       AliFMDDebug(5, ("Got new detector: %d (was %d)", det, oldDet));
217       oldDet = det;
218     }
219     AliFMDDebug(10, ("Sample rate is %d", sampleRate));
220     
221     for (UShort_t j = 0; j < sampleRate; j++) { 
222       if (!pars->Detector2Hardware(det,ring,sector,strip,j,ddl,addr,time)){
223         AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]-%d", 
224                       det, ring, sector, strip, j));
225         continue;
226       }
227     
228       AliFMDDebug(10, ("FMD%d%c[%2d,%3d]-%d-> 0x%x/0x%x/%04d", 
229                        det, ring, sector, strip, j, ddl, addr, time));
230       if (addr != prevaddr) {
231         // Flush a channel to output 
232         AliFMDDebug(5, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d]-%d"
233                          "(b: 0x%02x, a: 0x%01x, c: 0x%02x, t: %04d), "
234                          "flushing old channel at 0x%x with %d words", 
235                          addr, det, ring, sector, strip, j,
236                          (addr >> 7), (addr >> 4) & 0x7, addr & 0xf, 
237                          time, prevaddr, nWords));
238         totalWords += nWords;
239         if (altro) altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
240         nWords   = 0;
241         prevaddr = addr;
242       }
243       if (ddl != prevddl) {
244         AliFMDDebug(10, ("FMD: New DDL, was %d, now %d", prevddl, ddl));
245         // If an altro exists, delete the object, flushing the data to
246         // disk, and closing the file. 
247         if (altro) { 
248           // When the first argument is false, we write the real
249           // header. 
250           AliFMDDebug(15, ("Closing output"));
251           altro->Flush();
252           altro->WriteDataHeader(kFALSE, kFALSE);
253           delete altro;
254           altro = 0;
255         }
256         prevddl = ddl;
257         // Need to open a new DDL! 
258         TString filename(AliDAQ::DdlFileName(fFMD->GetName(),  ddl));
259         AliFMDDebug(5, ("New altro buffer with DDL file %s", filename.Data()));
260         // Create a new altro buffer - a `1' as the second argument
261         // means `write mode' 
262         altro = new AliAltroBuffer(filename.Data());
263         altro->SetMapping(pars->GetAltroMap());      
264         // Write a dummy (first argument is true) header to the DDL
265         // file - later on, when we close the file, we write the real
266         // header
267         altro->WriteDataHeader(kTRUE, kFALSE);
268       }
269     
270       // Store the counts of the ADC in the channel buffer 
271       AliFMDDebug(6, ("Storing FMD%d%c[%02d,%03d]-%d in timebin %d (%d)",
272                       det, ring, sector, strip, j, time, preSamples));
273       UShort_t count = digit->Count(j);
274       data[time] = count;
275       nWords++;
276       nCounts++;
277       if (time == preSamples) {
278         AliFMDDebug(5, ("Filling in %4d for %d presamples", count, preSamples));
279         for (int k = 0; k < preSamples; k++) data[k] = count;
280         nWords += preSamples;
281       }
282     }
283   }
284   // Finally, we need to close the final ALTRO buffer if it wasn't
285   // already 
286   if (altro) {
287     if (nWords > 0) altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
288     altro->Flush();
289     altro->WriteDataHeader(kFALSE, kFALSE);
290     delete altro;
291   }
292   AliFMDDebug(5, ("Wrote a total of %d words for %d counts", 
293                   nWords, nCounts));
294 }
295 #else
296 //____________________________________________________________________
297 void
298 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
299 {
300   Int_t nDigits = digits->GetEntries();
301   if (nDigits < 1) return;
302
303   AliFMDParameters*  pars    = AliFMDParameters::Instance();
304   AliFMDAltroWriter* writer  = 0;
305   Int_t          sampleRate  = -1;
306   UShort_t       hwaddr      = 0;
307   UShort_t       ddl         = 0;
308   std::ofstream* file        = 0;
309   Int_t          ret         = 0;
310   for (Int_t i = 0; i < nDigits; i++) {
311     // Get the digit
312     AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
313     UInt_t   thisDDL, thisHwaddr;
314     UShort_t det    = digit->Detector();
315     Char_t   ring   = digit->Ring();
316     UShort_t sector = digit->Sector();
317     UShort_t strip  = digit->Strip();
318     if (!pars->Detector2Hardware(det,ring,sector,strip,thisDDL,thisHwaddr)) {
319       AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]",
320                     det, ring, sector, strip));
321       continue;
322     }
323     AliFMDDebug(40, ("Got DDL=%d and address=%d from FMD%d%c[%2d,%3d]", 
324                      thisDDL, thisHwaddr, det, ring, sector, strip));
325     // Check if we're still in the same channel
326     if (thisHwaddr != hwaddr) {
327       AliFMDDebug(30, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d] "
328                        "(board 0x%x, chip 0x%x, channel 0x%x)",
329                        thisHwaddr, det, ring, sector, strip, 
330                        (thisHwaddr >> 7), (thisHwaddr >> 4) & 0x7, 
331                        thisHwaddr & 0xf));
332       if (writer) writer->AddChannelTrailer(hwaddr);
333       hwaddr = thisHwaddr;
334     }
335     // Check if we're still in the same detector (DDL)
336     if (ddl != thisDDL) {
337       if (writer) {
338         AliFMDDebug(1, ("Closing altro writer %p", writer));
339         if ((ret = writer->Close()) < 0) {
340           AliError(Form("Error: %s", writer->ErrorString(ret)));
341           return;
342         }
343         delete writer;
344         writer = 0;
345         file->close();
346         delete file;
347         file = 0;
348       }
349       ddl = thisDDL;
350     }
351     // If we haven't got a writer (either because none were made so
352     // far, or because we've switch DDL), make one. 
353     if (!writer) {
354       AliFMDDebug(1, ("Opening new ALTRO writer w/file %s", 
355                       AliDAQ::DdlFileName("FMD",ddl)));
356       file   = new std::ofstream(AliDAQ::DdlFileName("FMD",ddl));
357       if (!file || !*file) {
358         AliFatal(Form("Failed to open file %s", 
359                       AliDAQ::DdlFileName("FMD",ddl)));
360         return;
361       }
362       writer  = new AliFMDAltroWriter(*file);
363       writer->SetThreshold(pars->GetZeroSuppression(det, ring, sector, strip));
364     }
365     // Write out our signal
366     sampleRate =  pars->GetSampleRate(det,ring,sector,strip);
367     writer->AddSignal(digit->Count1());
368     if (sampleRate >= 2) writer->AddSignal(digit->Count2());
369     if (sampleRate >= 3) writer->AddSignal(digit->Count3());
370   }
371   if (writer) {
372     writer->AddChannelTrailer(hwaddr);
373     writer->Close();
374     delete writer;
375     file->close();
376     delete file;
377   }
378 }
379 #endif
380
381
382   
383
384 //____________________________________________________________________
385 // 
386 // EOF
387 //