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