Line data Source code
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 12 : 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 4 : : TTask("FMDRawWriter", "Writer of Raw ADC values from the FMD"),
66 4 : fFMD(fmd),
67 4 : fSampleRate(0),
68 4 : fChannelsPerAltro(0),
69 4 : fThreshold(0)
70 20 : {
71 : // CTOR
72 16 : AliFMDDebug(5, ("Created AliFMDRawWriter object"));
73 8 : }
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 8 : AliLoader* loader = fFMD->GetLoader();
137 4 : loader->LoadDigits("READ");
138 4 : TTree* digitTree = loader->TreeD();
139 4 : if (!digitTree) {
140 0 : AliError("no digit tree");
141 0 : return;
142 : }
143 :
144 4 : fFMD->SetTreeAddress();
145 4 : 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 4 : Int_t nEvents = Int_t(digitTree->GetEntries());
155 8 : AliFMDDebug(5, ("Got a total of %5d events from tree", nEvents));
156 16 : for (Int_t event = 0; event < nEvents; event++) {
157 4 : fFMD->ResetDigits();
158 4 : digitTree->GetEvent(event);
159 :
160 : // Write out the digits
161 4 : WriteDigits(digits);
162 : }
163 4 : loader->UnloadDigits();
164 : //delete digits;
165 8 : }
166 :
167 : #if 1
168 : //____________________________________________________________________
169 : Long_t
170 : AliFMDRawWriter::WriteDigits(TClonesArray* digits)
171 : {
172 : // WRite an array of digits to disk file
173 8 : Int_t nDigits = digits->GetEntries();
174 4 : if (nDigits < 1) return 0;
175 8 : AliFMDDebug(5, ("Got a total of %5d digits from tree", nDigits));
176 :
177 4 : 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 4 : TArrayI data(pars->GetChannelsPerAltro() * 8);
192 4 : TArrayF peds(pars->GetChannelsPerAltro() * 8);
193 4 : 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 409608 : for (Int_t i = 0; i < nDigits; i++) {
208 : // Get the digit
209 409600 : AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
210 204800 : UShort_t det = digit->Detector();
211 204800 : Char_t ring = digit->Ring();
212 204800 : UShort_t sector = digit->Sector();
213 204800 : UShort_t strip = digit->Strip();
214 204800 : UShort_t ddl, addr, time;
215 :
216 819200 : AliFMDDebug(15, ("Processing digit # %5d FMD%d%c[%2d,%3d]",
217 : i, det, ring, sector, strip));
218 204800 : threshold = pars->GetZeroSuppression(det, ring, sector, strip);
219 204800 : sampleRate = pars->GetSampleRate(det, ring, sector, strip);
220 204800 : preSamples = pars->GetPreSamples(det, ring, sector, strip);
221 204800 : factor = UShort_t(pars->GetPedestalFactor());
222 :
223 204800 : if (det != oldDet) {
224 48 : AliFMDDebug(5, ("Got new detector: %d (was %d)", det, oldDet));
225 : oldDet = det;
226 12 : }
227 819200 : AliFMDDebug(15, ("Sample rate is %d", sampleRate));
228 :
229 2048000 : for (UShort_t j = 0; j < sampleRate; j++) {
230 1638400 : if (!pars->Detector2Hardware(det,ring,sector,strip,j,ddl,addr,time)){
231 0 : 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 3276800 : AliFMDDebug(10, ("FMD%d%c[%2d,%3d]-%d-> 0x%x/0x%x/%04d",
237 : det, ring, sector, strip, j, ddl, addr, time));
238 819200 : if (addr != prevaddr) {
239 : // Flush a channel to output
240 6400 : 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 1600 : totalWords += nWords;
247 1600 : ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
248 1600 : if (altro)
249 1596 : /*nBits+=*/altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
250 1600 : data.Reset(-1);
251 1600 : peds.Reset(0);
252 1600 : noise.Reset(0);
253 : nWords = 0;
254 1600 : prevaddr = addr;
255 1600 : }
256 819200 : if (ddl != prevddl) {
257 48 : 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 12 : if (altro) {
261 : // When the first argument is false, we write the real
262 : // header.
263 32 : AliFMDDebug(15, ("Closing output"));
264 8 : WriteRCUTrailer(altro, prevddl, threshold > 0, factor, sampleRate);
265 :
266 16 : delete altro;
267 : altro = 0;
268 8 : }
269 12 : prevddl = ddl;
270 : // Need to open a new DDL!
271 48 : TString filename(AliDAQ::DdlFileName(fFMD ? fFMD->GetName() : "FMD", ddl));
272 48 : 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 36 : altro = new AliAltroBufferV3(filename.Data());
276 24 : 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 12 : altro->WriteDataHeader(kTRUE, kFALSE);
281 12 : }
282 :
283 : // Get the pedestal value
284 2457600 : peds[time] = pars->GetPedestal(det, ring, sector, strip);
285 2457600 : noise[time] = pars->GetPedestalWidth(det, ring, sector, strip);
286 :
287 : // Store the counts of the ADC in the channel buffer
288 3276800 : AliFMDDebug(15, ("Storing FMD%d%c[%02d,%03d]-%d in timebin %d (%d)",
289 : det, ring, sector, strip, j, time, preSamples));
290 1638400 : data[time] = digit->Count(j);
291 819200 : nWords++;
292 819200 : nCounts++;
293 819200 : if (time == preSamples) {
294 6400 : AliFMDDebug(15, ("Filling in %4d for %d presamples",
295 : data[time], preSamples));
296 64000 : for (int k = 0; k < preSamples; k++) {
297 91200 : peds[k] = peds[time];
298 91200 : noise[k] = noise[time];
299 91200 : data[k] = data[time];
300 : }
301 1600 : nWords += preSamples;
302 1600 : }
303 : }
304 204800 : }
305 : // Finally, we need to close the final ALTRO buffer if it wasn't
306 : // already
307 4 : if (altro) {
308 4 : ZeroSuppress(data.fArray, nWords, peds.fArray, noise.fArray, threshold);
309 4 : if (nWords > 0)
310 4 : /* nBits += */ altro->WriteChannel(prevaddr,nWords,data.fArray,threshold);
311 4 : WriteRCUTrailer(altro, prevddl, threshold > 0, factor, sampleRate);
312 8 : delete altro;
313 : }
314 16 : AliFMDDebug(5, ("Wrote a total of %d words in %ld bytes for %d counts",
315 : nWords, nBits / 8, nCounts));
316 : return nBits;
317 8 : }
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 12 : altro->Flush();
328 12 : altro->WriteDataHeader(kFALSE, kFALSE);
329 :
330 : // Set parameters in RCU trailer.
331 : // Zero-suppression flag
332 12 : 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 12 : 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 12 : altro->SetNPretriggerSamples(rate); // fSampleRate[ddl]
341 : // Active front-end cars
342 12 : altro->SetActiveFECsA((ddl == 0 ? 0x1 : 0x3));
343 12 : altro->SetActiveFECsB((ddl == 0 ? 0x1 : 0x3));
344 :
345 : // Calculate number of samples
346 12 : altro->SetNSamplesPerCh(rate * 128);
347 36 : AliDebug(5,Form("Writing RCU trailer @ DDL %d w/zs=%d, factor=%d, rate=%d",
348 : ddl, zs > 0, factor, rate));
349 12 : altro->WriteRCUTrailer(ddl);
350 12 : }
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 3208 : 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 0 : Bool_t pedSubtract = AliFMDParameters::Instance()->IsZSPedSubtract();
371 0 : UShort_t pre = AliFMDParameters::Instance()->GetZSPreSamples();
372 0 : UShort_t post = AliFMDParameters::Instance()->GetZSPostSamples();
373 0 : Float_t factor = AliFMDParameters::Instance()->GetPedestalFactor();
374 :
375 0 : TArrayC mask(nWords+1);
376 0 : for (Short_t i = 0; i < nWords; i++) {
377 0 : Float_t val = data[i] - peds[i] - factor * noise[i];
378 0 : if (val < 0.5) val = 0;
379 0 : if (pedSubtract) data[i] = Int_t(val) & 0x3FF;
380 :
381 0 : mask[i] = (val > threshold ? 1 : 0);
382 0 : 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 0 : for (Short_t i = 0; i < nWords; i++) {
388 0 : if (mask[i]) { // Signal above, so do nothing
389 0 : AliFMDDebug(10, ("Sample %d, above", i));
390 0 : 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 0 : AliFMDDebug(10, ("At sample %d, next is below, skipping %d to %d",
394 : i, post, i+post));
395 0 : i += post;
396 0 : }
397 : continue;
398 : }
399 :
400 0 : Short_t lookahead = TMath::Min(Short_t(nWords), Short_t(i+pre));
401 0 : AliFMDDebug(10, ("Sample %d, below, look to %d", i, lookahead));
402 0 : if (mask[lookahead] && pre > 0) {
403 0 : 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 0 : i += pre-1;
407 0 : continue;
408 : }
409 :
410 : // This sample must be surpressed
411 0 : data[i] = threshold - 1;
412 0 : }
413 1604 : }
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 :
|