Access to the headers from 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 **************************************************************************/
15
16/* $Id$ */
17
18//____________________________________________________________________
19//
20// Class to write ADC values to a raw data file
21//
7684b53c 22// This class writes FMD Raw data to a file. The sample rate (number
23// of times the ALTRO ADC samples each pre-amp. channel - that is,
24// data from a single strip), can be set via SetSampleRate.
25//
26// Zero-suppression can be enabled by calling SetThreshold with a
27// non-zero argument. ADC values less than the value set will not be
28// written to output. Note, that if you use zero-suppression, you
29// need to explicitly set the sample rate when reading back the data
30// with AliFMDRawReader.
31//
32// This class uses the AliAltroBuffer class to write the data in the
33// ALTRO format. See the Exec member function for more information on
34// that format.
35//
56b1929b 36#include <AliLog.h> // ALILOG_H
37#include <AliLoader.h> // ALILOADER_H
38#include <AliAltroBuffer.h> // ALIALTROBUFFER_H
e802be3e 39#include "AliFMD.h" // ALIFMD_H
1a1fdef7 40#include "AliFMDParameters.h" // ALIFMDPARAMETERS_H
e802be3e 41#include "AliFMDDigit.h" // ALIFMDDIGIT_H
42#include "AliFMDRawWriter.h" // ALIFMDRAWREADER_H
1e8f773e 43#include "AliFMDAltroMapping.h" // ALIFMDALTROMAPPING_H
44#include "AliFMDAltroIO.h" // ALIFMDALTROWRITER_H
56b1929b 45#include <TArrayI.h> // ROOT_TArrayI
e802be3e 46#include <TClonesArray.h> // ROOT_TClonesArray
1e8f773e 47#include <fstream>
e802be3e 48
49//____________________________________________________________________
925e6570 50ClassImp(AliFMDRawWriter)
1a1fdef7 51#if 0
52 ; // This is here to keep Emacs for indenting the next line
53#endif
e802be3e 54
55//____________________________________________________________________
56AliFMDRawWriter::AliFMDRawWriter(AliFMD* fmd)
57 : TTask("FMDRawWriter", "Writer of Raw ADC values from the FMD"),
58 fFMD(fmd)
59{
1a1fdef7 60 AliFMDParameters* pars = AliFMDParameters::Instance();
8f6ee336 61 fSampleRate = pars->GetSampleRate(AliFMDParameters::kBaseDDL);
1a1fdef7 62 fChannelsPerAltro = pars->GetChannelsPerAltro();
e802be3e 63}
64
65
66//____________________________________________________________________
67void
68AliFMDRawWriter::Exec(Option_t*)
69{
70 // Turn digits into raw data.
71 //
72 // Digits are read from the Digit branch, and processed to make
73 // three DDL files, one for each of the sub-detectors FMD1, FMD2,
74 // and FMD3.
75 //
76 // The raw data files consists of a header, followed by ALTRO
77 // formatted blocks.
78 //
79 // +-------------+
80 // | Header |
81 // +-------------+
82 // | ALTRO Block |
83 // | ... |
84 // +-------------+
85 // DDL file
86 //
87 // An ALTRO formatted block, in the FMD context, consists of a
88 // number of counts followed by a trailer.
89 //
90 // +------------------+
91 // | Count |
92 // | ... |
93 // | possible fillers |
94 // +------------------+
95 // | Trailer |
96 // +------------------+
97 // ALTRO block
98 //
99 // The counts are listed backwards, that is, starting with the
100 // latest count, and ending in the first.
101 //
102 // Each count consist of 1 or more ADC samples of the VA1_ALICE
103 // pre-amp. signal. Just how many samples are used depends on
104 // whether the ALTRO over samples the pre-amp. Each sample is a
105 // 10-bit word, and the samples are grouped into 40-bit blocks
106 //
107 // +------------------------------------+
108 // | S(n) | S(n-1) | S(n-2) | S(n-3) |
109 // | ... | ... | ... | ... |
110 // | S(2) | S(1) | AA | AA |
111 // +------------------------------------+
112 // Counts + possible filler
113 //
114 // The trailer of the number of words of signales, the starting
115 // strip number, the sector number, and the ring ID; each 10-bit
116 // words, packed into 40-bits.
117 //
118 // +------------------------------------+
119 // | # words | start | sector | ring |
120 // +------------------------------------+
121 // Trailer
122 //
123 // Note, that this method assumes that the digits are ordered.
124 //
125 AliLoader* loader = fFMD->GetLoader();
126 loader->LoadDigits();
127 TTree* digitTree = loader->TreeD();
128 if (!digitTree) {
129 Error("Digits2Raw", "no digit tree");
130 return;
131 }
132
133 TClonesArray* digits = new TClonesArray("AliFMDDigit", 1000);
134 fFMD->SetTreeAddress();
135 TBranch* digitBranch = digitTree->GetBranch(fFMD->GetName());
136 if (!digitBranch) {
137 Error("Digits2Raw", "no branch for %s", fFMD->GetName());
138 return;
139 }
140 digitBranch->SetAddress(&digits);
141
142 Int_t nEvents = Int_t(digitTree->GetEntries());
143 for (Int_t event = 0; event < nEvents; event++) {
144 fFMD->ResetDigits();
145 digitTree->GetEvent(event);
146
1e8f773e 147 // Write out the digits
148 WriteDigits(digits);
149 }
150 loader->UnloadDigits();
151}
e802be3e 152
1e8f773e 153//____________________________________________________________________
154void
155AliFMDRawWriter::WriteDigits(TClonesArray* digits)
156{
157 Int_t nDigits = digits->GetEntries();
158 if (nDigits < 1) return;
e802be3e 159
1e8f773e 160 AliFMDParameters* pars = AliFMDParameters::Instance();
161 AliFMDAltroWriter* writer = 0;
162 Int_t sampleRate = -1;
163 UShort_t hwaddr = 0;
164 UShort_t ddl = 0;
165 std::ofstream* file = 0;
166 Int_t ret = 0;
167 for (Int_t i = 0; i < nDigits; i++) {
168 // Get the digit
169 AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
170 UInt_t thisDDL, thisHwaddr;
171 UShort_t det = digit->Detector();
172 Char_t ring = digit->Ring();
173 UShort_t sector = digit->Sector();
174 UShort_t strip = digit->Strip();
175 if (!pars->Detector2Hardware(det,ring,sector,strip,thisDDL,thisHwaddr)) {
176 AliError(Form("Failed to get hardware address for FMD%d%c[%2d,%3d]",
177 det, ring, sector, strip));
178 continue;
179 }
180 AliDebug(40, Form("Got DDL=%d and address=%d from FMD%d%c[%2d,%3d]",
181 thisDDL, thisHwaddr, det, ring, sector, strip));
182 // Check if we're still in the same channel
183 if (thisHwaddr != hwaddr) {
184 AliDebug(30, Form("Now hardware address 0x%x from FMD%d%c[%2d,%3d] "
185 "(board 0x%x, chip 0x%x, channel 0x%x)",
186 thisHwaddr, det, ring, sector, strip,
187 (thisHwaddr >> 7), (thisHwaddr >> 4) & 0x7,
188 thisHwaddr & 0xf));
189 if (writer) writer->AddChannelTrailer(hwaddr);
190 hwaddr = thisHwaddr;
191 }
192 // Check if we're still in the same detector (DDL)
193 if (ddl != thisDDL) {
194 if (writer) {
195 AliDebug(1, Form("Closing altro writer %p", writer));
196 if ((ret = writer->Close()) < 0) {
197 AliError(Form("Error: %s", writer->ErrorString(ret)));
198 return;
199 }
200 delete writer;
201 writer = 0;
202 file->close();
203 delete file;
204 file = 0;
205 }
206 ddl = thisDDL;
207 }
208 // If we haven't got a writer (either because none were made so
209 // far, or because we've switch DDL), make one.
210 if (!writer) {
211 AliDebug(1, Form("Opening new ALTRO writer w/file FMD_%d.ddl", ddl));
212 file = new std::ofstream(Form("FMD_%d.ddl", ddl));
213 if (!file || !*file) {
214 AliFatal(Form("Failed to open file FMD_%d.ddl", ddl));
215 return;
216 }
217 writer = new AliFMDAltroWriter(*file);
218 writer->SetThreshold(pars->GetZeroSuppression(det, ring, sector, strip));
219 sampleRate = pars->GetSampleRate(ddl);
220 }
221 // Write out our signal
222 writer->AddSignal(digit->Count1());
223 if (sampleRate >= 2) writer->AddSignal(digit->Count2());
224 if (sampleRate >= 3) writer->AddSignal(digit->Count3());
225 }
226 if (writer) {
227 writer->AddChannelTrailer(hwaddr);
228 writer->Close();
229 delete writer;
230 file->close();
231 delete file;
232 }
233}
e802be3e 234
1e8f773e 235
e802be3e 236
1e8f773e 237#if 0
238//____________________________________________________________________
239void
240AliFMDRawWriter::WriteDigits(TClonesArray* digits)
241{
242 Int_t nDigits = digits->GetEntries();
243 if (nDigits < 1) return;
e802be3e 244
1e8f773e 245 AliFMDParameters* pars = AliFMDParameters::Instance();
246 UShort_t prevDetector = 0;
247 Char_t prevRing = '\0';
248 UShort_t prevSector = 0;
249 // UShort_t prevStrip = 0;
250
251 // The first seen strip number for a channel
252 UShort_t startStrip = 0;
253
254 // Which channel number in the ALTRO channel we're at
255 UShort_t offset = 0;
256
257 // How many times the ALTRO Samples one VA1_ALICE channel
258 Int_t sampleRate = 1;
259
260 // A buffer to hold 1 ALTRO channel - Normally, one ALTRO channel
261 // holds 128 VA1_ALICE channels, sampled at a rate of `sampleRate'
262 TArrayI channel(fChannelsPerAltro * sampleRate);
e802be3e 263
1e8f773e 264 // The Altro buffer
265 AliAltroBuffer* altro = 0;
e802be3e 266
1e8f773e 267 // Loop over the digits in the event. Note, that we assume the
268 // the digits are in order in the branch. If they were not, we'd
269 // have to cache all channels before we could write the data to
270 // the ALTRO buffer, or we'd have to set up a map of the digits.
271 for (Int_t i = 0; i < nDigits; i++) {
272 // Get the digit
273 AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
e802be3e 274
1e8f773e 275 UShort_t det = digit->Detector();
276 Char_t ring = digit->Ring();
277 UShort_t sector = digit->Sector();
278 UShort_t strip = digit->Strip();
279 fThreshold = pars->GetZeroSuppression(det, ring, sector, strip);
280 if (det != prevDetector) {
281 AliDebug(15, Form("FMD: New DDL, was %d, now %d",
282 AliFMDParameters::kBaseDDL + prevDetector - 1,
283 AliFMDParameters::kBaseDDL + det - 1));
284 // If an altro exists, delete the object, flushing the data to
285 // disk, and closing the file.
286 if (altro) {
287 // When the first argument is false, we write the real
288 // header.
289 AliDebug(15, Form("New altro: Write channel at %d Strip: %d "
e802be3e 290 "Sector: %d Ring: %d",
291 i, startStrip, prevSector, prevRing));
1e8f773e 292 // TPC to FMD translations
293 //
294 // TPC FMD
295 // ----------+-----------
296 // pad | strip
297 // row | sector
298 // sector | ring
299 //
7684b53c 300 WriteChannel(altro, startStrip, prevSector, prevRing, channel);
1e8f773e 301 altro->Flush();
302 altro->WriteDataHeader(kFALSE, kFALSE);
303 delete altro;
304 altro = 0;
305 }
306 prevDetector = det;
307 // Need to open a new DDL!
308 Int_t ddlId = AliFMDParameters::kBaseDDL + det - 1;
309 TString filename(Form("%s_%d.ddl", fFMD->GetName(), ddlId));
310
311 AliDebug(15, Form("New altro buffer with DDL file %s",
312 filename.Data()));
313 AliDebug(15, Form("New altro at %d", i));
314 // Create a new altro buffer - a `1' as the second argument
315 // means `write mode'
316 altro = new AliAltroBuffer(filename.Data(), 1);
317 altro->SetMapping(pars->GetAltroMap());
318
319 // Write a dummy (first argument is true) header to the DDL
320 // file - later on, when we close the file, we write the real
321 // header
322 altro->WriteDataHeader(kTRUE, kFALSE);
323
324 // Figure out the sample rate
325 if (fSampleRate > 0) sampleRate = fSampleRate;
326 else {
327 if (digit->Count2() >= 0) sampleRate = 2;
328 if (digit->Count3() >= 0) sampleRate = 3;
e802be3e 329 }
330
1e8f773e 331 channel.Set(fChannelsPerAltro * sampleRate);
332 offset = 0;
333 prevRing = ring;
334 prevSector = sector;
335 startStrip = strip;
e802be3e 336 }
1e8f773e 337 else if (offset == fChannelsPerAltro
338 || digit->Ring() != prevRing
339 || digit->Sector() != prevSector) {
340 // Force a new Altro channel
341 AliDebug(15, Form("Flushing channel to disk because %s",
342 (offset == fChannelsPerAltro ? "channel is full" :
343 (ring != prevRing ? "new ring up" :
344 "new sector up"))));
345 AliDebug(15, Form("New Channel: Write channel at %d Strip: %d "
346 "Sector: %d Ring: %d",
347 i, startStrip, prevSector, prevRing));
348 WriteChannel(altro, startStrip, prevSector, prevRing, channel);
349 // Reset and update channel variables
350 channel.Reset(0);
351 offset = 0;
352 startStrip = strip;
353 prevRing = ring;
354 prevSector = sector;
e802be3e 355 }
1e8f773e 356
357 // Store the counts of the ADC in the channel buffer
358 channel[offset * sampleRate] = digit->Count1();
359 if (sampleRate > 1)
360 channel[offset * sampleRate + 1] = digit->Count2();
361 if (sampleRate > 2)
362 channel[offset * sampleRate + 2] = digit->Count3();
363 offset++;
364 }
365 // Finally, we need to close the final ALTRO buffer if it wasn't
366 // already
367 if (altro) {
368 altro->Flush();
369 altro->WriteDataHeader(kFALSE, kFALSE);
370 delete altro;
e802be3e 371 }
e802be3e 372}
1e8f773e 373#endif
e802be3e 374
375//____________________________________________________________________
7684b53c 376void
377AliFMDRawWriter::WriteChannel(AliAltroBuffer* altro,
378 UShort_t strip, UShort_t sector, Char_t ring,
379 const TArrayI& data)
380{
381 // Write out one ALTRO channel to the data file.
382 // Derived classes can overload this method to use a per-ALTRO
383 // threshold. This implementation uses the common threshold set by
384 // SetThreshold.
385 altro->WriteChannel(Int_t(strip),
386 Int_t(sector),
387 Int_t((ring == 'I' ? 0 : 1)),
388 data.fN, data.fArray, fThreshold);
389}
390
391
392
393//____________________________________________________________________
e802be3e 394//
395// EOF
396//