Fixes for reading zero-suppressed data. Also fixes to simulated raw
[u/mrichter/AliRoot.git] / FMD / AliFMDRawWriter.cxx
CommitLineData
e802be3e 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 **************************************************************************/
e802be3e 15/* $Id$ */
c2fc1258 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*/
e802be3e 21//____________________________________________________________________
22//
23// Class to write ADC values to a raw data file
24//
7684b53c 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//
f95a63c4 39// #include <AliLog.h> // ALILOG_H
40#include "AliFMDDebug.h" // Better debug macros
56b1929b 41#include <AliLoader.h> // ALILOADER_H
42#include <AliAltroBuffer.h> // ALIALTROBUFFER_H
e802be3e 43#include "AliFMD.h" // ALIFMD_H
1a1fdef7 44#include "AliFMDParameters.h" // ALIFMDPARAMETERS_H
e802be3e 45#include "AliFMDDigit.h" // ALIFMDDIGIT_H
46#include "AliFMDRawWriter.h" // ALIFMDRAWREADER_H
1e8f773e 47#include "AliFMDAltroMapping.h" // ALIFMDALTROMAPPING_H
c2fc1258 48// #include "AliFMDAltroIO.h" // ALIFMDALTROWRITER_H
56b1929b 49#include <TArrayI.h> // ROOT_TArrayI
cce354f6 50#include <TArrayF.h> // ROOT_TArrayI
51#include <TArrayC.h> // ROOT_TArrayI
e802be3e 52#include <TClonesArray.h> // ROOT_TClonesArray
02a27b50 53// #include <fstream>
362c9d61 54#include "AliDAQ.h"
e802be3e 55
56//____________________________________________________________________
925e6570 57ClassImp(AliFMDRawWriter)
1a1fdef7 58#if 0
59 ; // This is here to keep Emacs for indenting the next line
60#endif
e802be3e 61
62//____________________________________________________________________
63AliFMDRawWriter::AliFMDRawWriter(AliFMD* fmd)
64 : TTask("FMDRawWriter", "Writer of Raw ADC values from the FMD"),
b5ee4425 65 fFMD(fmd),
66 fSampleRate(0),
67 fChannelsPerAltro(0),
68 fThreshold(0)
02a27b50 69{
70 // CTOR
ef8e8623 71 AliFMDDebug(5, ("Created AliFMDRawWriter object"));
02a27b50 72}
73
e802be3e 74
75
76//____________________________________________________________________
77void
78AliFMDRawWriter::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 // +------------------------------------+
c2fc1258 118 // | S(1) | S(2) | S(3) | S(4) |
e802be3e 119 // | ... | ... | ... | ... |
c2fc1258 120 // | S(n) | T(n) | n+2 | 2AA |
e802be3e 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 // +------------------------------------+
c2fc1258 129 // | 2AAA | Len | A | Address |
e802be3e 130 // +------------------------------------+
131 // Trailer
132 //
133 // Note, that this method assumes that the digits are ordered.
134 //
135 AliLoader* loader = fFMD->GetLoader();
ef8e8623 136 loader->LoadDigits("READ");
e802be3e 137 TTree* digitTree = loader->TreeD();
138 if (!digitTree) {
ef8e8623 139 AliError("no digit tree");
e802be3e 140 return;
141 }
142
143 TClonesArray* digits = new TClonesArray("AliFMDDigit", 1000);
144 fFMD->SetTreeAddress();
145 TBranch* digitBranch = digitTree->GetBranch(fFMD->GetName());
146 if (!digitBranch) {
ef8e8623 147 AliError(Form("no branch for %s", fFMD->GetName()));
e802be3e 148 return;
149 }
150 digitBranch->SetAddress(&digits);
151
152 Int_t nEvents = Int_t(digitTree->GetEntries());
f95a63c4 153 AliFMDDebug(5, ("Got a total of %5d events from tree", nEvents));
e802be3e 154 for (Int_t event = 0; event < nEvents; event++) {
155 fFMD->ResetDigits();
156 digitTree->GetEvent(event);
157
1e8f773e 158 // Write out the digits
159 WriteDigits(digits);
160 }
161 loader->UnloadDigits();
162}
e802be3e 163
c2fc1258 164#if 1
165//____________________________________________________________________
166void
167AliFMDRawWriter::WriteDigits(TClonesArray* digits)
168{
02a27b50 169 // WRite an array of digits to disk file
c2fc1258 170 Int_t nDigits = digits->GetEntries();
171 if (nDigits < 1) return;
f95a63c4 172 AliFMDDebug(5, ("Got a total of %5d digits from tree", nDigits));
c2fc1258 173
174 AliFMDParameters* pars = AliFMDParameters::Instance();
175 UShort_t threshold = 0;
f95a63c4 176 UInt_t prevddl = 0xFFFF;
c2fc1258 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;
f38b1653 183 UShort_t sampleRate = 0;
c2fc1258 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);
cce354f6 188 TArrayF peds(pars->GetChannelsPerAltro() * 8);
189 TArrayF noise(pars->GetChannelsPerAltro() * 8);
c2fc1258 190
191 // The Altro buffer
192 AliAltroBuffer* altro = 0;
f38b1653 193
194 Int_t totalWords = 0;
195 Int_t nCounts = 0;
196
c2fc1258 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.
f95a63c4 201 UShort_t oldDet = 1000;
c2fc1258 202 for (Int_t i = 0; i < nDigits; i++) {
203 // Get the digit
204 AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
c2fc1258 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 UInt_t ddl;
210 UInt_t addr;
f38b1653 211 UShort_t time;
212
cce354f6 213 AliFMDDebug(15, ("Processing digit # %5d FMD%d%c[%2d,%3d]",
f38b1653 214 i, det, ring, sector, strip));
215 threshold = pars->GetZeroSuppression(det, ring, sector, strip);
216 sampleRate = pars->GetSampleRate(det, ring, sector, strip);
217 preSamples = pars->GetPreSamples(det, ring, sector, strip);
218
f95a63c4 219 if (det != oldDet) {
220 AliFMDDebug(5, ("Got new detector: %d (was %d)", det, oldDet));
221 oldDet = det;
222 }
cce354f6 223 AliFMDDebug(15, ("Sample rate is %d", sampleRate));
625d7886 224
f38b1653 225 for (UShort_t j = 0; j < sampleRate; j++) {
226 if (!pars->Detector2Hardware(det,ring,sector,strip,j,ddl,addr,time)){
227 AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]-%d",
228 det, ring, sector, strip, j));
229 continue;
c2fc1258 230 }
c2fc1258 231
f38b1653 232 AliFMDDebug(10, ("FMD%d%c[%2d,%3d]-%d-> 0x%x/0x%x/%04d",
233 det, ring, sector, strip, j, ddl, addr, time));
234 if (addr != prevaddr) {
235 // Flush a channel to output
236 AliFMDDebug(5, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d]-%d"
237 "(b: 0x%02x, a: 0x%01x, c: 0x%02x, t: %04d), "
238 "flushing old channel at 0x%x with %d words",
239 addr, det, ring, sector, strip, j,
240 (addr >> 7), (addr >> 4) & 0x7, addr & 0xf,
241 time, prevaddr, nWords));
242 totalWords += nWords;
cce354f6 243 ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
f38b1653 244 if (altro) altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
cce354f6 245 data.Reset(-1);
246 peds.Reset(0);
247 noise.Reset(0);
f38b1653 248 nWords = 0;
249 prevaddr = addr;
250 }
251 if (ddl != prevddl) {
252 AliFMDDebug(10, ("FMD: New DDL, was %d, now %d", prevddl, ddl));
253 // If an altro exists, delete the object, flushing the data to
254 // disk, and closing the file.
255 if (altro) {
256 // When the first argument is false, we write the real
257 // header.
258 AliFMDDebug(15, ("Closing output"));
259 altro->Flush();
260 altro->WriteDataHeader(kFALSE, kFALSE);
261 delete altro;
262 altro = 0;
263 }
264 prevddl = ddl;
265 // Need to open a new DDL!
266 TString filename(AliDAQ::DdlFileName(fFMD->GetName(), ddl));
267 AliFMDDebug(5, ("New altro buffer with DDL file %s", filename.Data()));
268 // Create a new altro buffer - a `1' as the second argument
269 // means `write mode'
270 altro = new AliAltroBuffer(filename.Data());
271 altro->SetMapping(pars->GetAltroMap());
272 // Write a dummy (first argument is true) header to the DDL
273 // file - later on, when we close the file, we write the real
274 // header
275 altro->WriteDataHeader(kTRUE, kFALSE);
276 }
277
cce354f6 278 // Get the pedestal value
279 peds[time] = pars->GetPedestal(det, ring, sector, strip);
280 noise[time] = pars->GetPedestalWidth(det, ring, sector, strip);
281
f38b1653 282 // Store the counts of the ADC in the channel buffer
cce354f6 283 AliFMDDebug(15, ("Storing FMD%d%c[%02d,%03d]-%d in timebin %d (%d)",
f38b1653 284 det, ring, sector, strip, j, time, preSamples));
cce354f6 285 data[time] = digit->Count(j);
c2fc1258 286 nWords++;
f38b1653 287 nCounts++;
288 if (time == preSamples) {
cce354f6 289 AliFMDDebug(15, ("Filling in %4d for %d presamples",
290 data[time], preSamples));
291 for (int k = 0; k < preSamples; k++) {
292 peds[k] = peds[time];
293 noise[k] = noise[time];
294 data[k] = data[time];
295 }
f38b1653 296 nWords += preSamples;
297 }
c2fc1258 298 }
299 }
300 // Finally, we need to close the final ALTRO buffer if it wasn't
301 // already
302 if (altro) {
cce354f6 303 ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
c2fc1258 304 if (nWords > 0) altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
305 altro->Flush();
306 altro->WriteDataHeader(kFALSE, kFALSE);
307 delete altro;
308 }
f38b1653 309 AliFMDDebug(5, ("Wrote a total of %d words for %d counts",
310 nWords, nCounts));
c2fc1258 311}
cce354f6 312//____________________________________________________________________
313void
314AliFMDRawWriter::ZeroSuppress(Int_t*& data, Int_t nWords,
315 const Float_t* peds,
316 const Float_t* noise, UShort_t threshold) const
317{
318 // Simulate the ALTRO zero-suppression filter. The data passed in
319 // the first array is modified, such that all suppressed channels
320 // are set to some value below threshold.
321 //
322 // If threshold == 0 zero suppression is considered disabled, and no
323 // action is taken.
324 if (threshold <= 0) return;
325
326 // const Short_t width = 3;
327 // If fPedSubtract is false, compare data-(ped+f*noise), if true
328 // always modify data by -(ped+f*noise), and force negative values
329 // to zero.
330 Bool_t pedSubtract = AliFMDParameters::Instance()->IsZSPedSubtract();
331 UShort_t pre = AliFMDParameters::Instance()->GetZSPreSamples();
332 UShort_t post = AliFMDParameters::Instance()->GetZSPostSamples();
333 Float_t factor = AliFMDParameters::Instance()->GetPedestalFactor();
334
335 TArrayC mask(nWords+1);
336 for (Short_t i = 0; i < nWords; i++) {
337 Float_t val = data[i] - peds[i] - factor * noise[i];
338 if (val < 0.5) val = 0;
339 if (pedSubtract) data[i] = Int_t(val) & 0x3FF;
340
341 mask[i] = (val > threshold ? 1 : 0);
342 AliFMDDebug(10, ("Comparing sample %d %d-%f-%f*%f=%f to %d -> %s",
343 i, data[i], peds[i], factor, noise[i], val, threshold,
344 (mask[i] ? "above" : "below")));
345 }
346
347 for (Short_t i = 0; i < nWords; i++) {
348 if (mask[i]) { // Signal above, so do nothing
349 AliFMDDebug(10, ("Sample %d, above", i));
350 if (i < nWords-1 && !mask[i+1]) {
351 // After a valid sample. Increase the pointer to the next
352 // possible data, thereby skipping over the post-samples
353 AliFMDDebug(10, ("At sample %d, next is below, skipping %d to %d",
354 i, post, i+post));
355 i += post;
356 }
357 continue;
358 }
359
360 Short_t lookahead = TMath::Min(Short_t(nWords), Short_t(i+pre));
361 AliFMDDebug(10, ("Sample %d, below, look to %d", i, lookahead));
362 if (mask[lookahead] && pre > 0) {
363 AliFMDDebug(10, ("Sample %d is a pre-sample to %d", i, lookahead));
364 // We're in a presample, so don't modify the data, and increase
365 // counter by the number of pre-samples
366 i += pre-1;
367 continue;
368 }
369
370 // This sample must be surpressed
371 data[i] = threshold - 1;
372 }
373}
374
c2fc1258 375#else
1e8f773e 376//____________________________________________________________________
377void
378AliFMDRawWriter::WriteDigits(TClonesArray* digits)
379{
380 Int_t nDigits = digits->GetEntries();
381 if (nDigits < 1) return;
e802be3e 382
1e8f773e 383 AliFMDParameters* pars = AliFMDParameters::Instance();
384 AliFMDAltroWriter* writer = 0;
385 Int_t sampleRate = -1;
386 UShort_t hwaddr = 0;
387 UShort_t ddl = 0;
388 std::ofstream* file = 0;
389 Int_t ret = 0;
390 for (Int_t i = 0; i < nDigits; i++) {
391 // Get the digit
392 AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
393 UInt_t thisDDL, thisHwaddr;
394 UShort_t det = digit->Detector();
395 Char_t ring = digit->Ring();
396 UShort_t sector = digit->Sector();
397 UShort_t strip = digit->Strip();
398 if (!pars->Detector2Hardware(det,ring,sector,strip,thisDDL,thisHwaddr)) {
399 AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]",
400 det, ring, sector, strip));
401 continue;
402 }
f95a63c4 403 AliFMDDebug(40, ("Got DDL=%d and address=%d from FMD%d%c[%2d,%3d]",
1e8f773e 404 thisDDL, thisHwaddr, det, ring, sector, strip));
405 // Check if we're still in the same channel
406 if (thisHwaddr != hwaddr) {
f95a63c4 407 AliFMDDebug(30, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d] "
1e8f773e 408 "(board 0x%x, chip 0x%x, channel 0x%x)",
409 thisHwaddr, det, ring, sector, strip,
410 (thisHwaddr >> 7), (thisHwaddr >> 4) & 0x7,
411 thisHwaddr & 0xf));
412 if (writer) writer->AddChannelTrailer(hwaddr);
413 hwaddr = thisHwaddr;
414 }
415 // Check if we're still in the same detector (DDL)
416 if (ddl != thisDDL) {
417 if (writer) {
f95a63c4 418 AliFMDDebug(1, ("Closing altro writer %p", writer));
1e8f773e 419 if ((ret = writer->Close()) < 0) {
420 AliError(Form("Error: %s", writer->ErrorString(ret)));
421 return;
422 }
423 delete writer;
424 writer = 0;
425 file->close();
426 delete file;
427 file = 0;
428 }
429 ddl = thisDDL;
430 }
431 // If we haven't got a writer (either because none were made so
432 // far, or because we've switch DDL), make one.
433 if (!writer) {
f95a63c4 434 AliFMDDebug(1, ("Opening new ALTRO writer w/file %s",
435 AliDAQ::DdlFileName("FMD",ddl)));
362c9d61 436 file = new std::ofstream(AliDAQ::DdlFileName("FMD",ddl));
1e8f773e 437 if (!file || !*file) {
f95a63c4 438 AliFatal(Form("Failed to open file %s",
439 AliDAQ::DdlFileName("FMD",ddl)));
1e8f773e 440 return;
441 }
442 writer = new AliFMDAltroWriter(*file);
443 writer->SetThreshold(pars->GetZeroSuppression(det, ring, sector, strip));
1e8f773e 444 }
445 // Write out our signal
c2fc1258 446 sampleRate = pars->GetSampleRate(det,ring,sector,strip);
1e8f773e 447 writer->AddSignal(digit->Count1());
448 if (sampleRate >= 2) writer->AddSignal(digit->Count2());
449 if (sampleRate >= 3) writer->AddSignal(digit->Count3());
450 }
451 if (writer) {
452 writer->AddChannelTrailer(hwaddr);
453 writer->Close();
454 delete writer;
455 file->close();
456 delete file;
457 }
458}
9f662337 459#endif
7684b53c 460
c2fc1258 461
7684b53c 462
463
e802be3e 464//____________________________________________________________________
465//
466// EOF
467//