1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
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
21 //____________________________________________________________________
23 // Class to write ADC values to a raw data file
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.
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.
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
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
57 //____________________________________________________________________
58 ClassImp(AliFMDRawWriter)
60 ; // This is here to keep Emacs for indenting the next line
63 //____________________________________________________________________
64 AliFMDRawWriter::AliFMDRawWriter(AliFMD* fmd)
65 : TTask("FMDRawWriter", "Writer of Raw ADC values from the FMD"),
72 AliFMDDebug(5, ("Created AliFMDRawWriter object"));
77 //____________________________________________________________________
79 AliFMDRawWriter::Exec(Option_t*)
81 // Turn digits into raw data.
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,
87 // The raw data files consists of a header, followed by ALTRO
98 // An ALTRO formatted block, in the FMD context, consists of a
99 // number of counts followed by a trailer.
101 // +------------------+
104 // | possible fillers |
105 // +------------------+
107 // +------------------+
110 // The counts are listed backwards, that is, starting with the
111 // latest count, and ending in the first.
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
118 // +------------------------------------+
119 // | S(1) | S(2) | S(3) | S(4) |
120 // | ... | ... | ... | ... |
121 // | S(n) | T(n) | n+2 | 2AA |
122 // +------------------------------------+
123 // Counts + possible filler
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.
129 // +------------------------------------+
130 // | 2AAA | Len | A | Address |
131 // +------------------------------------+
134 // Note, that this method assumes that the digits are ordered.
136 AliLoader* loader = fFMD->GetLoader();
137 loader->LoadDigits("READ");
138 TTree* digitTree = loader->TreeD();
140 AliError("no digit tree");
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()));
152 // digitBranch->SetAddress(&digits);
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++) {
158 digitTree->GetEvent(event);
160 // Write out the digits
163 loader->UnloadDigits();
168 //____________________________________________________________________
170 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
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));
177 AliFMDParameters* pars = AliFMDParameters::Instance();
178 UShort_t threshold = 0;
179 UInt_t prevddl = 0xFFFF;
180 UInt_t prevaddr = 0xFFF;
181 // UShort_t prevStrip = 0;
183 // Which channel number in the ALTRO channel we're at
185 UShort_t preSamples = 0;
186 UShort_t sampleRate = 0;
188 // A buffer to hold 1 ALTRO channel - Normally, one ALTRO channel
189 // holds 128 VA1_ALICE channels, sampled at a rate of `sampleRate'
190 TArrayI data(pars->GetChannelsPerAltro() * 8);
191 TArrayF peds(pars->GetChannelsPerAltro() * 8);
192 TArrayF noise(pars->GetChannelsPerAltro() * 8);
195 AliAltroBufferV3* altro = 0;
197 Int_t totalWords = 0;
201 // Loop over the digits in the event. Note, that we assume the
202 // the digits are in order in the branch. If they were not, we'd
203 // have to cache all channels before we could write the data to
204 // the ALTRO buffer, or we'd have to set up a map of the digits.
205 UShort_t oldDet = 1000;
206 for (Int_t i = 0; i < nDigits; i++) {
208 AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
209 UShort_t det = digit->Detector();
210 Char_t ring = digit->Ring();
211 UShort_t sector = digit->Sector();
212 UShort_t strip = digit->Strip();
213 UShort_t ddl, addr, time;
215 AliFMDDebug(15, ("Processing digit # %5d FMD%d%c[%2d,%3d]",
216 i, det, ring, sector, strip));
217 threshold = pars->GetZeroSuppression(det, ring, sector, strip);
218 sampleRate = pars->GetSampleRate(det, ring, sector, strip);
219 preSamples = pars->GetPreSamples(det, ring, sector, strip);
222 AliFMDDebug(5, ("Got new detector: %d (was %d)", det, oldDet));
225 AliFMDDebug(15, ("Sample rate is %d", sampleRate));
227 for (UShort_t j = 0; j < sampleRate; j++) {
228 if (!pars->Detector2Hardware(det,ring,sector,strip,j,ddl,addr,time)){
229 AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]-%d",
230 det, ring, sector, strip, j));
234 AliFMDDebug(10, ("FMD%d%c[%2d,%3d]-%d-> 0x%x/0x%x/%04d",
235 det, ring, sector, strip, j, ddl, addr, time));
236 if (addr != prevaddr) {
237 // Flush a channel to output
238 AliFMDDebug(5, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d]-%d"
239 "(b: 0x%02x, a: 0x%01x, c: 0x%02x, t: %04d), "
240 "flushing old channel at 0x%x with %d words",
241 addr, det, ring, sector, strip, j,
242 (addr >> 7), (addr >> 4) & 0x7, addr & 0xf,
243 time, prevaddr, nWords));
244 totalWords += nWords;
245 ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
247 /*nBits+=*/altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
254 if (ddl != prevddl) {
255 AliFMDDebug(10, ("FMD: New DDL, was %d, now %d", prevddl, ddl));
256 // If an altro exists, delete the object, flushing the data to
257 // disk, and closing the file.
259 // When the first argument is false, we write the real
261 AliFMDDebug(15, ("Closing output"));
262 /* nBits += */ altro->Flush();
263 /* nBits += */ altro->WriteDataHeader(kFALSE, kFALSE);
268 // Need to open a new DDL!
269 TString filename(AliDAQ::DdlFileName(fFMD ? fFMD->GetName() : "FMD", ddl));
270 AliFMDDebug(5, ("New altro buffer with DDL file %s", filename.Data()));
271 // Create a new altro buffer - a `1' as the second argument
272 // means `write mode'
273 altro = new AliAltroBufferV3(filename.Data());
274 altro->SetMapping(pars->GetAltroMap());
275 // Write a dummy (first argument is true) header to the DDL
276 // file - later on, when we close the file, we write the real
278 altro->WriteDataHeader(kTRUE, kFALSE);
281 // Get the pedestal value
282 peds[time] = pars->GetPedestal(det, ring, sector, strip);
283 noise[time] = pars->GetPedestalWidth(det, ring, sector, strip);
285 // Store the counts of the ADC in the channel buffer
286 AliFMDDebug(15, ("Storing FMD%d%c[%02d,%03d]-%d in timebin %d (%d)",
287 det, ring, sector, strip, j, time, preSamples));
288 data[time] = digit->Count(j);
291 if (time == preSamples) {
292 AliFMDDebug(15, ("Filling in %4d for %d presamples",
293 data[time], preSamples));
294 for (int k = 0; k < preSamples; k++) {
295 peds[k] = peds[time];
296 noise[k] = noise[time];
297 data[k] = data[time];
299 nWords += preSamples;
303 // Finally, we need to close the final ALTRO buffer if it wasn't
306 ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
308 /* nBits += */ altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
309 /* nBits += */ altro->Flush();
310 /* nBits += */ altro->WriteDataHeader(kFALSE, kFALSE);
313 AliFMDDebug(5, ("Wrote a total of %d words in %ld bytes for %d counts",
314 nWords, nBits / 8, nCounts));
317 //____________________________________________________________________
319 AliFMDRawWriter::ZeroSuppress(Int_t*& data, Int_t nWords,
321 const Float_t* noise, UShort_t threshold) const
323 // Simulate the ALTRO zero-suppression filter. The data passed in
324 // the first array is modified, such that all suppressed channels
325 // are set to some value below threshold.
327 // If threshold == 0 zero suppression is considered disabled, and no
329 if (threshold <= 0) return;
331 // const Short_t width = 3;
332 // If fPedSubtract is false, compare data-(ped+f*noise), if true
333 // always modify data by -(ped+f*noise), and force negative values
335 Bool_t pedSubtract = AliFMDParameters::Instance()->IsZSPedSubtract();
336 UShort_t pre = AliFMDParameters::Instance()->GetZSPreSamples();
337 UShort_t post = AliFMDParameters::Instance()->GetZSPostSamples();
338 Float_t factor = AliFMDParameters::Instance()->GetPedestalFactor();
340 TArrayC mask(nWords+1);
341 for (Short_t i = 0; i < nWords; i++) {
342 Float_t val = data[i] - peds[i] - factor * noise[i];
343 if (val < 0.5) val = 0;
344 if (pedSubtract) data[i] = Int_t(val) & 0x3FF;
346 mask[i] = (val > threshold ? 1 : 0);
347 AliFMDDebug(10, ("Comparing sample %d %d-%f-%f*%f=%f to %d -> %s",
348 i, data[i], peds[i], factor, noise[i], val, threshold,
349 (mask[i] ? "above" : "below")));
352 for (Short_t i = 0; i < nWords; i++) {
353 if (mask[i]) { // Signal above, so do nothing
354 AliFMDDebug(10, ("Sample %d, above", i));
355 if (i < nWords-1 && !mask[i+1]) {
356 // After a valid sample. Increase the pointer to the next
357 // possible data, thereby skipping over the post-samples
358 AliFMDDebug(10, ("At sample %d, next is below, skipping %d to %d",
365 Short_t lookahead = TMath::Min(Short_t(nWords), Short_t(i+pre));
366 AliFMDDebug(10, ("Sample %d, below, look to %d", i, lookahead));
367 if (mask[lookahead] && pre > 0) {
368 AliFMDDebug(10, ("Sample %d is a pre-sample to %d", i, lookahead));
369 // We're in a presample, so don't modify the data, and increase
370 // counter by the number of pre-samples
375 // This sample must be surpressed
376 data[i] = threshold - 1;
381 //____________________________________________________________________
383 AliFMDRawWriter::WriteDigits(TClonesArray* digits)
386 // Write digits to file
388 Int_t nDigits = digits->GetEntries();
389 if (nDigits < 1) return;
391 AliFMDParameters* pars = AliFMDParameters::Instance();
392 AliFMDAltroWriter* writer = 0;
393 Int_t sampleRate = -1;
396 std::ofstream* file = 0;
398 for (Int_t i = 0; i < nDigits; i++) {
400 AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
401 UInt_t thisDDL, thisHwaddr;
402 UShort_t det = digit->Detector();
403 Char_t ring = digit->Ring();
404 UShort_t sector = digit->Sector();
405 UShort_t strip = digit->Strip();
406 if (!pars->Detector2Hardware(det,ring,sector,strip,thisDDL,thisHwaddr)) {
407 AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]",
408 det, ring, sector, strip));
411 AliFMDDebug(40, ("Got DDL=%d and address=%d from FMD%d%c[%2d,%3d]",
412 thisDDL, thisHwaddr, det, ring, sector, strip));
413 // Check if we're still in the same channel
414 if (thisHwaddr != hwaddr) {
415 AliFMDDebug(30, ("Now hardware address 0x%x from FMD%d%c[%2d,%3d] "
416 "(board 0x%x, chip 0x%x, channel 0x%x)",
417 thisHwaddr, det, ring, sector, strip,
418 (thisHwaddr >> 7), (thisHwaddr >> 4) & 0x7,
420 if (writer) writer->AddChannelTrailer(hwaddr);
423 // Check if we're still in the same detector (DDL)
424 if (ddl != thisDDL) {
426 AliFMDDebug(1, ("Closing altro writer %p", writer));
427 if ((ret = writer->Close()) < 0) {
428 AliError(Form("Error: %s", writer->ErrorString(ret)));
439 // If we haven't got a writer (either because none were made so
440 // far, or because we've switch DDL), make one.
442 AliFMDDebug(1, ("Opening new ALTRO writer w/file %s",
443 AliDAQ::DdlFileName("FMD",ddl)));
444 file = new std::ofstream(AliDAQ::DdlFileName("FMD",ddl));
445 if (!file || !*file) {
446 AliFatal(Form("Failed to open file %s",
447 AliDAQ::DdlFileName("FMD",ddl)));
450 writer = new AliFMDAltroWriter(*file);
451 writer->SetThreshold(pars->GetZeroSuppression(det, ring, sector, strip));
453 // Write out our signal
454 sampleRate = pars->GetSampleRate(det,ring,sector,strip);
455 writer->AddSignal(digit->Count1());
456 if (sampleRate >= 2) writer->AddSignal(digit->Count2());
457 if (sampleRate >= 3) writer->AddSignal(digit->Count3());
460 writer->AddChannelTrailer(hwaddr);
472 //____________________________________________________________________