]> git.uio.no Git - u/mrichter/AliRoot.git/blob - FMD/AliFMDRawWriter.cxx
Merge branch 'master' of https://git.cern.ch/reps/AliRoot
[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   altro->SetNNonZSPostsamples(factor);
338   // WARNING: We store the sample rate in the number of pre-trigger
339   // samples, since we'll never use that mode.
340   altro->SetNPretriggerSamples(rate); // fSampleRate[ddl]
341   // Active front-end cars 
342   altro->SetActiveFECsA((ddl == 0 ? 0x1 : 0x3));
343   altro->SetActiveFECsB((ddl == 0 ? 0x1 : 0x3));
344
345   // Calculate number of samples 
346   altro->SetNSamplesPerCh(rate * 128);
347   AliDebug(5,Form("Writing RCU trailer @ DDL %d w/zs=%d, factor=%d, rate=%d",
348                   ddl, zs > 0, factor, rate));
349   altro->WriteRCUTrailer(ddl);
350 }
351
352 //____________________________________________________________________
353 void
354 AliFMDRawWriter::ZeroSuppress(Int_t*& data, Int_t nWords, 
355                               const Float_t* peds, 
356                               const Float_t* noise, UShort_t threshold) const
357 {
358   // Simulate the ALTRO zero-suppression filter.  The data passed in
359   // the first array is modified, such that all suppressed channels
360   // are set to some value below threshold.  
361   // 
362   // If threshold == 0 zero suppression is considered disabled, and no
363   // action is taken. 
364   if (threshold <= 0) return;
365
366   // const Short_t width  = 3;
367   // If fPedSubtract is false, compare data-(ped+f*noise), if true
368   // always modify data by -(ped+f*noise), and force negative values
369   // to zero.
370   Bool_t   pedSubtract = AliFMDParameters::Instance()->IsZSPedSubtract();
371   UShort_t pre         = AliFMDParameters::Instance()->GetZSPreSamples();
372   UShort_t post        = AliFMDParameters::Instance()->GetZSPostSamples();
373   Float_t  factor      = AliFMDParameters::Instance()->GetPedestalFactor();
374   
375   TArrayC mask(nWords+1);
376   for (Short_t i = 0; i < nWords; i++) { 
377     Float_t            val     = data[i] - peds[i] - factor * noise[i];
378     if (val < 0.5)     val     = 0;
379     if (pedSubtract)   data[i] = Int_t(val) & 0x3FF;
380
381     mask[i] = (val > threshold ? 1 : 0);
382     AliFMDDebug(10, ("Comparing sample %d %d-%f-%f*%f=%f to %d -> %s", 
383                      i, data[i], peds[i], factor, noise[i], val, threshold, 
384                     (mask[i] ? "above" : "below")));
385   }
386   
387   for (Short_t i = 0; i < nWords; i++) { 
388     if (mask[i]) { // Signal above, so do nothing 
389       AliFMDDebug(10, ("Sample %d, above", i));
390       if (i < nWords-1 && !mask[i+1]) { 
391         // After a valid sample.  Increase the pointer to the next
392         // possible data, thereby skipping over the post-samples 
393         AliFMDDebug(10, ("At sample %d, next is below, skipping %d to %d", 
394                         i, post, i+post));
395         i += post;
396       }
397       continue;
398     }
399     
400     Short_t lookahead = TMath::Min(Short_t(nWords), Short_t(i+pre));
401     AliFMDDebug(10, ("Sample %d, below, look to %d", i, lookahead));
402     if (mask[lookahead] && pre > 0) { 
403       AliFMDDebug(10, ("Sample %d is a pre-sample to %d", i, lookahead));
404       // We're in a presample, so don't modify the data, and increase
405       // counter by the number of pre-samples 
406       i += pre-1;
407       continue;
408     }
409     
410     // This sample must be surpressed 
411     data[i] = threshold - 1;
412   }
413 }
414
415 #else
416 //____________________________________________________________________
417 void
418 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
419 {
420   // 
421   // Write digits to file 
422   //
423   Int_t nDigits = digits->GetEntries();
424   if (nDigits < 1) return;
425
426   AliFMDParameters*  pars    = AliFMDParameters::Instance();
427   AliFMDAltroWriter* writer  = 0;
428   Int_t          sampleRate  = -1;
429   UShort_t       hwaddr      = 0;
430   UShort_t       ddl         = 0;
431   std::ofstream* file        = 0;
432   Int_t          ret         = 0;
433   for (Int_t i = 0; i < nDigits; i++) {
434     // Get the digit
435     AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
436     UInt_t   thisDDL, thisHwaddr;
437     UShort_t det    = digit->Detector();
438     Char_t   ring   = digit->Ring();
439     UShort_t sector = digit->Sector();
440     UShort_t strip  = digit->Strip();
441     if (!pars->Detector2Hardware(det,ring,sector,strip,thisDDL,thisHwaddr)) {
442       AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]",
443                     det, ring, sector, strip));
444       continue;
445     }
446     AliFMDDebug(40, ("Got DDL=%d and address=%d from FMD%d%c[%2d,%3d]", 
447                      thisDDL, thisHwaddr, det, ring, sector, strip));
448     // Check if we're still in the same channel
449     if (thisHwaddr != hwaddr) {
450       AliFMDDebug(30, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d] "
451                        "(board 0x%x, chip 0x%x, channel 0x%x)",
452                        thisHwaddr, det, ring, sector, strip, 
453                        (thisHwaddr >> 7), (thisHwaddr >> 4) & 0x7, 
454                        thisHwaddr & 0xf));
455       if (writer) writer->AddChannelTrailer(hwaddr);
456       hwaddr = thisHwaddr;
457     }
458     // Check if we're still in the same detector (DDL)
459     if (ddl != thisDDL) {
460       if (writer) {
461         AliFMDDebug(1, ("Closing altro writer %p", writer));
462         if ((ret = writer->Close()) < 0) {
463           AliError(Form("Error: %s", writer->ErrorString(ret)));
464           return;
465         }
466         delete writer;
467         writer = 0;
468         file->close();
469         delete file;
470         file = 0;
471       }
472       ddl = thisDDL;
473     }
474     // If we haven't got a writer (either because none were made so
475     // far, or because we've switch DDL), make one. 
476     if (!writer) {
477       AliFMDDebug(1, ("Opening new ALTRO writer w/file %s", 
478                       AliDAQ::DdlFileName("FMD",ddl)));
479       file   = new std::ofstream(AliDAQ::DdlFileName("FMD",ddl));
480       if (!file || !*file) {
481         AliFatal(Form("Failed to open file %s", 
482                       AliDAQ::DdlFileName("FMD",ddl)));
483         return;
484       }
485       writer  = new AliFMDAltroWriter(*file);
486       writer->SetThreshold(pars->GetZeroSuppression(det, ring, sector, strip));
487     }
488     // Write out our signal
489     sampleRate =  pars->GetSampleRate(det,ring,sector,strip);
490     writer->AddSignal(digit->Count1());
491     if (sampleRate >= 2) writer->AddSignal(digit->Count2());
492     if (sampleRate >= 3) writer->AddSignal(digit->Count3());
493   }
494   if (writer) {
495     writer->AddChannelTrailer(hwaddr);
496     writer->Close();
497     delete writer;
498     file->close();
499     delete file;
500   }
501 }
502 #endif
503
504
505   
506
507 //____________________________________________________________________
508 // 
509 // EOF
510 //
511