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