Clean-up of include files
[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 <AliAltroBufferV3.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 <TArrayF.h>            // ROOT_TArrayI
51 #include <TArrayC.h>            // ROOT_TArrayI
52 #include <TClonesArray.h>       // ROOT_TClonesArray
53 #include <TTree.h>
54 // #include <fstream>
55 #include "AliDAQ.h"
56
57 //____________________________________________________________________
58 ClassImp(AliFMDRawWriter)
59 #if 0
60   ; // This is here to keep Emacs for indenting the next line
61 #endif
62
63 //____________________________________________________________________
64 AliFMDRawWriter::AliFMDRawWriter(AliFMD* fmd) 
65   : TTask("FMDRawWriter", "Writer of Raw ADC values from the FMD"),
66     fFMD(fmd),
67     fSampleRate(0), 
68     fChannelsPerAltro(0), 
69     fThreshold(0)
70 {
71   // CTOR 
72   AliFMDDebug(5, ("Created AliFMDRawWriter object"));
73 }
74
75
76
77 //____________________________________________________________________
78 void
79 AliFMDRawWriter::Exec(Option_t*) 
80 {
81   // Turn digits into raw data. 
82   // 
83   // Digits are read from the Digit branch, and processed to make
84   // three DDL files, one for each of the sub-detectors FMD1, FMD2,
85   // and FMD3. 
86   //
87   // The raw data files consists of a header, followed by ALTRO
88   // formatted blocks.  
89   // 
90   //          +-------------+
91   //          | Header      |
92   //          +-------------+
93   //          | ALTRO Block |
94   //          | ...         |
95   //          +-------------+
96   //          DDL file 
97   // 
98   // An ALTRO formatted block, in the FMD context, consists of a
99   // number of counts followed by a trailer. 
100   // 
101   //          +------------------+
102   //          | Count            |
103   //          | ...              |
104   //          | possible fillers |
105   //          +------------------+
106   //          | Trailer          |
107   //          +------------------+
108   //          ALTRO block 
109   // 
110   // The counts are listed backwards, that is, starting with the
111   // latest count, and ending in the first. 
112   // 
113   // Each count consist of 1 or more ADC samples of the VA1_ALICE
114   // pre-amp. signal.  Just how many samples are used depends on
115   // whether the ALTRO over samples the pre-amp.  Each sample is a
116   // 10-bit word, and the samples are grouped into 40-bit blocks 
117   //
118   //          +------------------------------------+
119   //          |  S(1)   | S(2)   | S(3)   | S(4)   |
120   //          |  ...    | ...    | ...    | ...    |
121   //          |  S(n)   | T(n)   | n+2    | 2AA    |
122   //          +------------------------------------+
123   //          Counts + possible filler 
124   //
125   // The trailer of the number of words of signales, the starting
126   // strip number, the sector number, and the ring ID; each 10-bit
127   // words,  packed into 40-bits. 
128   // 
129   //          +------------------------------------+
130   //          |   2AAA   |  Len   |  A |  Address  |
131   //          +------------------------------------+
132   //          Trailer
133   // 
134   // Note, that this method assumes that the digits are ordered. 
135   // 
136   AliLoader* loader = fFMD->GetLoader();
137   loader->LoadDigits("READ");
138   TTree* digitTree = loader->TreeD();
139   if (!digitTree) {
140     AliError("no digit tree");
141     return;
142   }
143   
144   fFMD->SetTreeAddress();
145   TClonesArray* digits = fFMD->Digits(); 
146   // new TClonesArray("AliFMDDigit", 1000);
147   // TBranch* digitBranch = digitTree->GetBranch(fFMD->GetName());
148   // if (!digitBranch) {
149   //   AliError(Form("no branch for %s", fFMD->GetName()));
150   //   return;
151   // }
152   // digitBranch->SetAddress(&digits);
153   
154   Int_t nEvents = Int_t(digitTree->GetEntries());
155   AliFMDDebug(5, ("Got a total of %5d events from tree", nEvents));
156   for (Int_t event = 0; event < nEvents; event++) {
157     fFMD->ResetDigits();
158     digitTree->GetEvent(event);
159     
160     // Write out the digits
161     WriteDigits(digits);
162   }
163   loader->UnloadDigits();
164   //delete digits;
165 }
166
167 #if 1
168 //____________________________________________________________________
169 Long_t
170 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
171 {
172   // WRite an array of digits to disk file 
173   Int_t nDigits = digits->GetEntries();
174   if (nDigits < 1) return 0;
175   AliFMDDebug(5, ("Got a total of %5d digits from tree", nDigits));
176
177   AliFMDParameters* pars = AliFMDParameters::Instance();
178   UShort_t threshold    = 0;
179   UInt_t   prevddl      = 0xFFFF;
180   UInt_t   prevaddr     = 0xFFF;
181   // UShort_t prevStrip    = 0;
182   
183   // Which channel number in the ALTRO channel we're at 
184   UShort_t nWords       = 0;
185   UShort_t preSamples   = 0;
186   UShort_t sampleRate   = 0;
187   
188   // A buffer to hold 1 ALTRO channel - Normally, one ALTRO channel
189   // holds 128 VA1_ALICE channels, sampled at a rate of `sampleRate' 
190   TArrayI data(pars->GetChannelsPerAltro() * 8);
191   TArrayF peds(pars->GetChannelsPerAltro() * 8);
192   TArrayF noise(pars->GetChannelsPerAltro() * 8);
193
194   // The Altro buffer 
195   AliAltroBufferV3* altro = 0;
196   
197   Int_t  totalWords = 0;
198   Int_t  nCounts    = 0;
199   Long_t nBits      = 0;
200
201   // Loop over the digits in the event.  Note, that we assume the
202   // the digits are in order in the branch.   If they were not, we'd
203   // have to cache all channels before we could write the data to
204   // the ALTRO buffer, or we'd have to set up a map of the digits. 
205   UShort_t oldDet = 1000;
206   for (Int_t i = 0; i < nDigits; i++) {
207     // Get the digit
208     AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
209     UShort_t det    = digit->Detector();
210     Char_t   ring   = digit->Ring();
211     UShort_t sector = digit->Sector();
212     UShort_t strip  = digit->Strip();
213     UShort_t ddl, addr, time;
214
215     AliFMDDebug(15, ("Processing digit # %5d FMD%d%c[%2d,%3d]", 
216                     i, det, ring, sector, strip));
217     threshold  = pars->GetZeroSuppression(det, ring, sector, strip);
218     sampleRate = pars->GetSampleRate(det, ring, sector, strip);
219     preSamples = pars->GetPreSamples(det, ring, sector, strip);
220
221     if (det != oldDet) {
222       AliFMDDebug(5, ("Got new detector: %d (was %d)", det, oldDet));
223       oldDet = det;
224     }
225     AliFMDDebug(15, ("Sample rate is %d", sampleRate));
226     
227     for (UShort_t j = 0; j < sampleRate; j++) { 
228       if (!pars->Detector2Hardware(det,ring,sector,strip,j,ddl,addr,time)){
229         AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]-%d", 
230                       det, ring, sector, strip, j));
231         continue;
232       }
233     
234       AliFMDDebug(10, ("FMD%d%c[%2d,%3d]-%d-> 0x%x/0x%x/%04d", 
235                        det, ring, sector, strip, j, ddl, addr, time));
236       if (addr != prevaddr) {
237         // Flush a channel to output 
238         AliFMDDebug(5, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d]-%d"
239                          "(b: 0x%02x, a: 0x%01x, c: 0x%02x, t: %04d), "
240                          "flushing old channel at 0x%x with %d words", 
241                          addr, det, ring, sector, strip, j,
242                          (addr >> 7), (addr >> 4) & 0x7, addr & 0xf, 
243                          time, prevaddr, nWords));
244         totalWords += nWords;
245         ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
246         if (altro) 
247           /*nBits+=*/altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
248         data.Reset(-1);
249         peds.Reset(0);
250         noise.Reset(0);
251         nWords   = 0;
252         prevaddr = addr;
253       }
254       if (ddl != prevddl) {
255         AliFMDDebug(10, ("FMD: New DDL, was %d, now %d", prevddl, ddl));
256         // If an altro exists, delete the object, flushing the data to
257         // disk, and closing the file. 
258         if (altro) { 
259           // When the first argument is false, we write the real
260           // header. 
261           AliFMDDebug(15, ("Closing output"));
262           /* nBits += */ altro->Flush();
263           /* nBits += */ altro->WriteDataHeader(kFALSE, kFALSE);
264           delete altro;
265           altro = 0;
266         }
267         prevddl = ddl;
268         // Need to open a new DDL! 
269         TString filename(AliDAQ::DdlFileName(fFMD ? fFMD->GetName() : "FMD",  ddl));
270         AliFMDDebug(5, ("New altro buffer with DDL file %s", filename.Data()));
271         // Create a new altro buffer - a `1' as the second argument
272         // means `write mode' 
273         altro = new AliAltroBufferV3(filename.Data());
274         altro->SetMapping(pars->GetAltroMap());      
275         // Write a dummy (first argument is true) header to the DDL
276         // file - later on, when we close the file, we write the real
277         // header
278         altro->WriteDataHeader(kTRUE, kFALSE);
279       }
280     
281       // Get the pedestal value 
282       peds[time]  = pars->GetPedestal(det, ring, sector, strip);
283       noise[time] = pars->GetPedestalWidth(det, ring, sector, strip);
284
285       // Store the counts of the ADC in the channel buffer 
286       AliFMDDebug(15, ("Storing FMD%d%c[%02d,%03d]-%d in timebin %d (%d)",
287                       det, ring, sector, strip, j, time, preSamples));
288       data[time] = digit->Count(j);
289       nWords++;
290       nCounts++;
291       if (time == preSamples) {
292         AliFMDDebug(15, ("Filling in %4d for %d presamples", 
293                         data[time], preSamples));
294         for (int k = 0; k < preSamples; k++) { 
295           peds[k]  = peds[time];
296           noise[k] = noise[time];
297           data[k]  = data[time];
298         }
299         nWords += preSamples;
300       }
301     }
302   }
303   // Finally, we need to close the final ALTRO buffer if it wasn't
304   // already 
305   if (altro) {
306     ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
307     if (nWords > 0) 
308       /* nBits += */ altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
309     /* nBits += */ altro->Flush();
310     /* nBits += */ altro->WriteDataHeader(kFALSE, kFALSE);
311     delete altro;
312   }
313   AliFMDDebug(5, ("Wrote a total of %d words in %ld bytes for %d counts", 
314                   nWords, nBits / 8, nCounts));
315   return nBits;
316 }
317 //____________________________________________________________________
318 void
319 AliFMDRawWriter::ZeroSuppress(Int_t*& data, Int_t nWords, 
320                               const Float_t* peds, 
321                               const Float_t* noise, UShort_t threshold) const
322 {
323   // Simulate the ALTRO zero-suppression filter.  The data passed in
324   // the first array is modified, such that all suppressed channels
325   // are set to some value below threshold.  
326   // 
327   // If threshold == 0 zero suppression is considered disabled, and no
328   // action is taken. 
329   if (threshold <= 0) return;
330
331   // const Short_t width  = 3;
332   // If fPedSubtract is false, compare data-(ped+f*noise), if true
333   // always modify data by -(ped+f*noise), and force negative values
334   // to zero.
335   Bool_t   pedSubtract = AliFMDParameters::Instance()->IsZSPedSubtract();
336   UShort_t pre         = AliFMDParameters::Instance()->GetZSPreSamples();
337   UShort_t post        = AliFMDParameters::Instance()->GetZSPostSamples();
338   Float_t  factor      = AliFMDParameters::Instance()->GetPedestalFactor();
339   
340   TArrayC mask(nWords+1);
341   for (Short_t i = 0; i < nWords; i++) { 
342     Float_t            val     = data[i] - peds[i] - factor * noise[i];
343     if (val < 0.5)     val     = 0;
344     if (pedSubtract)   data[i] = Int_t(val) & 0x3FF;
345
346     mask[i] = (val > threshold ? 1 : 0);
347     AliFMDDebug(10, ("Comparing sample %d %d-%f-%f*%f=%f to %d -> %s", 
348                      i, data[i], peds[i], factor, noise[i], val, threshold, 
349                     (mask[i] ? "above" : "below")));
350   }
351   
352   for (Short_t i = 0; i < nWords; i++) { 
353     if (mask[i]) { // Signal above, so do nothing 
354       AliFMDDebug(10, ("Sample %d, above", i));
355       if (i < nWords-1 && !mask[i+1]) { 
356         // After a valid sample.  Increase the pointer to the next
357         // possible data, thereby skipping over the post-samples 
358         AliFMDDebug(10, ("At sample %d, next is below, skipping %d to %d", 
359                         i, post, i+post));
360         i += post;
361       }
362       continue;
363     }
364     
365     Short_t lookahead = TMath::Min(Short_t(nWords), Short_t(i+pre));
366     AliFMDDebug(10, ("Sample %d, below, look to %d", i, lookahead));
367     if (mask[lookahead] && pre > 0) { 
368       AliFMDDebug(10, ("Sample %d is a pre-sample to %d", i, lookahead));
369       // We're in a presample, so don't modify the data, and increase
370       // counter by the number of pre-samples 
371       i += pre-1;
372       continue;
373     }
374     
375     // This sample must be surpressed 
376     data[i] = threshold - 1;
377   }
378 }
379
380 #else
381 //____________________________________________________________________
382 void
383 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
384 {
385   // 
386   // Write digits to file 
387   //
388   Int_t nDigits = digits->GetEntries();
389   if (nDigits < 1) return;
390
391   AliFMDParameters*  pars    = AliFMDParameters::Instance();
392   AliFMDAltroWriter* writer  = 0;
393   Int_t          sampleRate  = -1;
394   UShort_t       hwaddr      = 0;
395   UShort_t       ddl         = 0;
396   std::ofstream* file        = 0;
397   Int_t          ret         = 0;
398   for (Int_t i = 0; i < nDigits; i++) {
399     // Get the digit
400     AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
401     UInt_t   thisDDL, thisHwaddr;
402     UShort_t det    = digit->Detector();
403     Char_t   ring   = digit->Ring();
404     UShort_t sector = digit->Sector();
405     UShort_t strip  = digit->Strip();
406     if (!pars->Detector2Hardware(det,ring,sector,strip,thisDDL,thisHwaddr)) {
407       AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]",
408                     det, ring, sector, strip));
409       continue;
410     }
411     AliFMDDebug(40, ("Got DDL=%d and address=%d from FMD%d%c[%2d,%3d]", 
412                      thisDDL, thisHwaddr, det, ring, sector, strip));
413     // Check if we're still in the same channel
414     if (thisHwaddr != hwaddr) {
415       AliFMDDebug(30, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d] "
416                        "(board 0x%x, chip 0x%x, channel 0x%x)",
417                        thisHwaddr, det, ring, sector, strip, 
418                        (thisHwaddr >> 7), (thisHwaddr >> 4) & 0x7, 
419                        thisHwaddr & 0xf));
420       if (writer) writer->AddChannelTrailer(hwaddr);
421       hwaddr = thisHwaddr;
422     }
423     // Check if we're still in the same detector (DDL)
424     if (ddl != thisDDL) {
425       if (writer) {
426         AliFMDDebug(1, ("Closing altro writer %p", writer));
427         if ((ret = writer->Close()) < 0) {
428           AliError(Form("Error: %s", writer->ErrorString(ret)));
429           return;
430         }
431         delete writer;
432         writer = 0;
433         file->close();
434         delete file;
435         file = 0;
436       }
437       ddl = thisDDL;
438     }
439     // If we haven't got a writer (either because none were made so
440     // far, or because we've switch DDL), make one. 
441     if (!writer) {
442       AliFMDDebug(1, ("Opening new ALTRO writer w/file %s", 
443                       AliDAQ::DdlFileName("FMD",ddl)));
444       file   = new std::ofstream(AliDAQ::DdlFileName("FMD",ddl));
445       if (!file || !*file) {
446         AliFatal(Form("Failed to open file %s", 
447                       AliDAQ::DdlFileName("FMD",ddl)));
448         return;
449       }
450       writer  = new AliFMDAltroWriter(*file);
451       writer->SetThreshold(pars->GetZeroSuppression(det, ring, sector, strip));
452     }
453     // Write out our signal
454     sampleRate =  pars->GetSampleRate(det,ring,sector,strip);
455     writer->AddSignal(digit->Count1());
456     if (sampleRate >= 2) writer->AddSignal(digit->Count2());
457     if (sampleRate >= 3) writer->AddSignal(digit->Count3());
458   }
459   if (writer) {
460     writer->AddChannelTrailer(hwaddr);
461     writer->Close();
462     delete writer;
463     file->close();
464     delete file;
465   }
466 }
467 #endif
468
469
470   
471
472 //____________________________________________________________________
473 // 
474 // EOF
475 //
476