Some changes to make it possible to run the DA's
[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   UShort_t factor       = 0;
180   UInt_t   prevddl      = 0xFFFF;
181   UInt_t   prevaddr     = 0xFFF;
182   // UShort_t prevStrip    = 0;
183   
184   // Which channel number in the ALTRO channel we're at 
185   UShort_t nWords       = 0;
186   UShort_t preSamples   = 0;
187   UShort_t sampleRate   = 0;
188   
189   // A buffer to hold 1 ALTRO channel - Normally, one ALTRO channel
190   // holds 128 VA1_ALICE channels, sampled at a rate of `sampleRate' 
191   TArrayI data(pars->GetChannelsPerAltro() * 8);
192   TArrayF peds(pars->GetChannelsPerAltro() * 8);
193   TArrayF noise(pars->GetChannelsPerAltro() * 8);
194
195   // The Altro buffer 
196   AliAltroBufferV3* altro = 0;
197   
198   Int_t  totalWords = 0;
199   Int_t  nCounts    = 0;
200   Long_t nBits      = 0;
201
202   // Loop over the digits in the event.  Note, that we assume the
203   // the digits are in order in the branch.   If they were not, we'd
204   // have to cache all channels before we could write the data to
205   // the ALTRO buffer, or we'd have to set up a map of the digits. 
206   UShort_t oldDet = 1000;
207   for (Int_t i = 0; i < nDigits; i++) {
208     // Get the digit
209     AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
210     UShort_t det    = digit->Detector();
211     Char_t   ring   = digit->Ring();
212     UShort_t sector = digit->Sector();
213     UShort_t strip  = digit->Strip();
214     UShort_t ddl, addr, time;
215
216     AliFMDDebug(15, ("Processing digit # %5d FMD%d%c[%2d,%3d]", 
217                     i, det, ring, sector, strip));
218     threshold  = pars->GetZeroSuppression(det, ring, sector, strip);
219     sampleRate = pars->GetSampleRate(det, ring, sector, strip);
220     preSamples = pars->GetPreSamples(det, ring, sector, strip);
221     factor     = UShort_t(pars->GetPedestalFactor());
222
223     if (det != oldDet) {
224       AliFMDDebug(5, ("Got new detector: %d (was %d)", det, oldDet));
225       oldDet = det;      
226     }
227     AliFMDDebug(15, ("Sample rate is %d", sampleRate));
228     
229     for (UShort_t j = 0; j < sampleRate; j++) { 
230       if (!pars->Detector2Hardware(det,ring,sector,strip,j,ddl,addr,time)){
231         AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]-%d", 
232                       det, ring, sector, strip, j));
233         continue;
234       }
235     
236       AliFMDDebug(10, ("FMD%d%c[%2d,%3d]-%d-> 0x%x/0x%x/%04d", 
237                        det, ring, sector, strip, j, ddl, addr, time));
238       if (addr != prevaddr) {
239         // Flush a channel to output 
240         AliFMDDebug(5, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d]-%d"
241                          "(b: 0x%02x, a: 0x%01x, c: 0x%02x, t: %04d), "
242                          "flushing old channel at 0x%x with %d words", 
243                          addr, det, ring, sector, strip, j,
244                          (addr >> 7), (addr >> 4) & 0x7, addr & 0xf, 
245                          time, prevaddr, nWords));
246         totalWords += nWords;
247         ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
248         if (altro) 
249           /*nBits+=*/altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
250         data.Reset(-1);
251         peds.Reset(0);
252         noise.Reset(0);
253         nWords   = 0;
254         prevaddr = addr;
255       }
256       if (ddl != prevddl) {
257         AliFMDDebug(10, ("FMD: New DDL, was %d, now %d", prevddl, ddl));
258         // If an altro exists, delete the object, flushing the data to
259         // disk, and closing the file. 
260         if (altro) { 
261           // When the first argument is false, we write the real
262           // header. 
263           AliFMDDebug(15, ("Closing output"));
264           WriteRCUTrailer(altro, prevddl, threshold > 0, factor, sampleRate); 
265     
266           delete altro;
267           altro = 0;
268         }
269         prevddl = ddl;
270         // Need to open a new DDL! 
271         TString filename(AliDAQ::DdlFileName(fFMD ? fFMD->GetName() : "FMD",  ddl));
272         AliFMDDebug(5, ("New altro buffer with DDL file %s", filename.Data()));
273         // Create a new altro buffer - a `1' as the second argument
274         // means `write mode' 
275         altro = new AliAltroBufferV3(filename.Data());
276         altro->SetMapping(pars->GetAltroMap());      
277         // Write a dummy (first argument is true) header to the DDL
278         // file - later on, when we close the file, we write the real
279         // header
280         altro->WriteDataHeader(kTRUE, kFALSE);
281       }
282     
283       // Get the pedestal value 
284       peds[time]  = pars->GetPedestal(det, ring, sector, strip);
285       noise[time] = pars->GetPedestalWidth(det, ring, sector, strip);
286
287       // Store the counts of the ADC in the channel buffer 
288       AliFMDDebug(15, ("Storing FMD%d%c[%02d,%03d]-%d in timebin %d (%d)",
289                       det, ring, sector, strip, j, time, preSamples));
290       data[time] = digit->Count(j);
291       nWords++;
292       nCounts++;
293       if (time == preSamples) {
294         AliFMDDebug(15, ("Filling in %4d for %d presamples", 
295                         data[time], preSamples));
296         for (int k = 0; k < preSamples; k++) { 
297           peds[k]  = peds[time];
298           noise[k] = noise[time];
299           data[k]  = data[time];
300         }
301         nWords += preSamples;
302       }
303     }
304   }
305   // Finally, we need to close the final ALTRO buffer if it wasn't
306   // already 
307   if (altro) {
308     ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
309     if (nWords > 0) 
310       /* nBits += */ altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
311     WriteRCUTrailer(altro, prevddl, threshold > 0, factor, sampleRate); 
312     delete altro;
313   }
314   AliFMDDebug(5, ("Wrote a total of %d words in %ld bytes for %d counts", 
315                   nWords, nBits / 8, nCounts));
316   return nBits;
317 }
318 //____________________________________________________________________
319 void
320 AliFMDRawWriter::WriteRCUTrailer(AliAltroBufferV3* altro,
321                                  UInt_t ddl,
322                                  Bool_t zs,
323                                  UShort_t factor,
324                                  UShort_t rate) const
325 {
326   // Flush and write the data header
327   altro->Flush();
328   altro->WriteDataHeader(kFALSE, kFALSE);
329     
330   // Set parameters in RCU trailer. 
331   // Zero-suppression flag
332   altro->SetZeroSupp(zs); // bool
333   // WARNING: We store the noise factor in the 2nd baseline
334   // filters excluded post samples, since we'll never use that
335   // mode. 
336   altro->SetNPostsamples(factor); // 
337   // WARNING: We store the sample rate in the number of pre-trigger
338   // samples, since we'll never use that mode.
339   altro->SetNPretriggerSamples(rate); // fSampleRate[ddl]
340   // Active front-end cars 
341   altro->SetActiveFECsA((ddl == 0 ? 0x1 : 0x3));
342   altro->SetActiveFECsB((ddl == 0 ? 0x1 : 0x3));
343
344   // Calculate number of samples 
345   altro->SetNSamplesPerCh(rate * 128);
346   AliDebug(5,Form("Writing RCU trailer @ DDL %d w/zs=%d, factor=%d, rate=%d",
347                   ddl, zs > 0, factor, rate));
348   altro->WriteRCUTrailer(ddl);
349 }
350
351 //____________________________________________________________________
352 void
353 AliFMDRawWriter::ZeroSuppress(Int_t*& data, Int_t nWords, 
354                               const Float_t* peds, 
355                               const Float_t* noise, UShort_t threshold) const
356 {
357   // Simulate the ALTRO zero-suppression filter.  The data passed in
358   // the first array is modified, such that all suppressed channels
359   // are set to some value below threshold.  
360   // 
361   // If threshold == 0 zero suppression is considered disabled, and no
362   // action is taken. 
363   if (threshold <= 0) return;
364
365   // const Short_t width  = 3;
366   // If fPedSubtract is false, compare data-(ped+f*noise), if true
367   // always modify data by -(ped+f*noise), and force negative values
368   // to zero.
369   Bool_t   pedSubtract = AliFMDParameters::Instance()->IsZSPedSubtract();
370   UShort_t pre         = AliFMDParameters::Instance()->GetZSPreSamples();
371   UShort_t post        = AliFMDParameters::Instance()->GetZSPostSamples();
372   Float_t  factor      = AliFMDParameters::Instance()->GetPedestalFactor();
373   
374   TArrayC mask(nWords+1);
375   for (Short_t i = 0; i < nWords; i++) { 
376     Float_t            val     = data[i] - peds[i] - factor * noise[i];
377     if (val < 0.5)     val     = 0;
378     if (pedSubtract)   data[i] = Int_t(val) & 0x3FF;
379
380     mask[i] = (val > threshold ? 1 : 0);
381     AliFMDDebug(10, ("Comparing sample %d %d-%f-%f*%f=%f to %d -> %s", 
382                      i, data[i], peds[i], factor, noise[i], val, threshold, 
383                     (mask[i] ? "above" : "below")));
384   }
385   
386   for (Short_t i = 0; i < nWords; i++) { 
387     if (mask[i]) { // Signal above, so do nothing 
388       AliFMDDebug(10, ("Sample %d, above", i));
389       if (i < nWords-1 && !mask[i+1]) { 
390         // After a valid sample.  Increase the pointer to the next
391         // possible data, thereby skipping over the post-samples 
392         AliFMDDebug(10, ("At sample %d, next is below, skipping %d to %d", 
393                         i, post, i+post));
394         i += post;
395       }
396       continue;
397     }
398     
399     Short_t lookahead = TMath::Min(Short_t(nWords), Short_t(i+pre));
400     AliFMDDebug(10, ("Sample %d, below, look to %d", i, lookahead));
401     if (mask[lookahead] && pre > 0) { 
402       AliFMDDebug(10, ("Sample %d is a pre-sample to %d", i, lookahead));
403       // We're in a presample, so don't modify the data, and increase
404       // counter by the number of pre-samples 
405       i += pre-1;
406       continue;
407     }
408     
409     // This sample must be surpressed 
410     data[i] = threshold - 1;
411   }
412 }
413
414 #else
415 //____________________________________________________________________
416 void
417 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
418 {
419   // 
420   // Write digits to file 
421   //
422   Int_t nDigits = digits->GetEntries();
423   if (nDigits < 1) return;
424
425   AliFMDParameters*  pars    = AliFMDParameters::Instance();
426   AliFMDAltroWriter* writer  = 0;
427   Int_t          sampleRate  = -1;
428   UShort_t       hwaddr      = 0;
429   UShort_t       ddl         = 0;
430   std::ofstream* file        = 0;
431   Int_t          ret         = 0;
432   for (Int_t i = 0; i < nDigits; i++) {
433     // Get the digit
434     AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
435     UInt_t   thisDDL, thisHwaddr;
436     UShort_t det    = digit->Detector();
437     Char_t   ring   = digit->Ring();
438     UShort_t sector = digit->Sector();
439     UShort_t strip  = digit->Strip();
440     if (!pars->Detector2Hardware(det,ring,sector,strip,thisDDL,thisHwaddr)) {
441       AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]",
442                     det, ring, sector, strip));
443       continue;
444     }
445     AliFMDDebug(40, ("Got DDL=%d and address=%d from FMD%d%c[%2d,%3d]", 
446                      thisDDL, thisHwaddr, det, ring, sector, strip));
447     // Check if we're still in the same channel
448     if (thisHwaddr != hwaddr) {
449       AliFMDDebug(30, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d] "
450                        "(board 0x%x, chip 0x%x, channel 0x%x)",
451                        thisHwaddr, det, ring, sector, strip, 
452                        (thisHwaddr >> 7), (thisHwaddr >> 4) & 0x7, 
453                        thisHwaddr & 0xf));
454       if (writer) writer->AddChannelTrailer(hwaddr);
455       hwaddr = thisHwaddr;
456     }
457     // Check if we're still in the same detector (DDL)
458     if (ddl != thisDDL) {
459       if (writer) {
460         AliFMDDebug(1, ("Closing altro writer %p", writer));
461         if ((ret = writer->Close()) < 0) {
462           AliError(Form("Error: %s", writer->ErrorString(ret)));
463           return;
464         }
465         delete writer;
466         writer = 0;
467         file->close();
468         delete file;
469         file = 0;
470       }
471       ddl = thisDDL;
472     }
473     // If we haven't got a writer (either because none were made so
474     // far, or because we've switch DDL), make one. 
475     if (!writer) {
476       AliFMDDebug(1, ("Opening new ALTRO writer w/file %s", 
477                       AliDAQ::DdlFileName("FMD",ddl)));
478       file   = new std::ofstream(AliDAQ::DdlFileName("FMD",ddl));
479       if (!file || !*file) {
480         AliFatal(Form("Failed to open file %s", 
481                       AliDAQ::DdlFileName("FMD",ddl)));
482         return;
483       }
484       writer  = new AliFMDAltroWriter(*file);
485       writer->SetThreshold(pars->GetZeroSuppression(det, ring, sector, strip));
486     }
487     // Write out our signal
488     sampleRate =  pars->GetSampleRate(det,ring,sector,strip);
489     writer->AddSignal(digit->Count1());
490     if (sampleRate >= 2) writer->AddSignal(digit->Count2());
491     if (sampleRate >= 3) writer->AddSignal(digit->Count3());
492   }
493   if (writer) {
494     writer->AddChannelTrailer(hwaddr);
495     writer->Close();
496     delete writer;
497     file->close();
498     delete file;
499   }
500 }
501 #endif
502
503
504   
505
506 //____________________________________________________________________
507 // 
508 // EOF
509 //
510