Added docs and fixed a bug
[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
16 /* $Id$ */
17
18 //____________________________________________________________________
19 //
20 // Class to write ADC values to a raw data file
21 //
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 //
36 #include <AliLog.h>             // ALILOG_H
37 #include <AliLoader.h>          // ALILOADER_H
38 #include <AliAltroBuffer.h>     // ALIALTROBUFFER_H
39 #include "AliFMD.h"             // ALIFMD_H
40 #include "AliFMDDigit.h"        // ALIFMDDIGIT_H
41 #include "AliFMDRawWriter.h"    // ALIFMDRAWREADER_H 
42 #include <TArrayI.h>            // ROOT_TArrayI
43 #include <TClonesArray.h>       // ROOT_TClonesArray
44
45 //____________________________________________________________________
46 ClassImp(AliFMDRawWriter);
47
48 //____________________________________________________________________
49 AliFMDRawWriter::AliFMDRawWriter(AliFMD* fmd) 
50   : TTask("FMDRawWriter", "Writer of Raw ADC values from the FMD"),
51     fFMD(fmd)
52 {
53   SetSampleRate();
54   SetThreshold();
55   SetChannelsPerAltro();
56 }
57
58
59 //____________________________________________________________________
60 void
61 AliFMDRawWriter::Exec(Option_t*) 
62 {
63   // Turn digits into raw data. 
64   // 
65   // Digits are read from the Digit branch, and processed to make
66   // three DDL files, one for each of the sub-detectors FMD1, FMD2,
67   // and FMD3. 
68   //
69   // The raw data files consists of a header, followed by ALTRO
70   // formatted blocks.  
71   // 
72   //          +-------------+
73   //          | Header      |
74   //          +-------------+
75   //          | ALTRO Block |
76   //          | ...         |
77   //          +-------------+
78   //          DDL file 
79   // 
80   // An ALTRO formatted block, in the FMD context, consists of a
81   // number of counts followed by a trailer. 
82   // 
83   //          +------------------+
84   //          | Count            |
85   //          | ...              |
86   //          | possible fillers |
87   //          +------------------+
88   //          | Trailer          |
89   //          +------------------+
90   //          ALTRO block 
91   // 
92   // The counts are listed backwards, that is, starting with the
93   // latest count, and ending in the first. 
94   // 
95   // Each count consist of 1 or more ADC samples of the VA1_ALICE
96   // pre-amp. signal.  Just how many samples are used depends on
97   // whether the ALTRO over samples the pre-amp.  Each sample is a
98   // 10-bit word, and the samples are grouped into 40-bit blocks 
99   //
100   //          +------------------------------------+
101   //          |  S(n)   | S(n-1) | S(n-2) | S(n-3) |
102   //          |  ...    | ...    | ...    | ...    |
103   //          |  S(2)   | S(1)   | AA     | AA     |
104   //          +------------------------------------+
105   //          Counts + possible filler 
106   //
107   // The trailer of the number of words of signales, the starting
108   // strip number, the sector number, and the ring ID; each 10-bit
109   // words,  packed into 40-bits. 
110   // 
111   //          +------------------------------------+
112   //          | # words | start  | sector | ring   |
113   //          +------------------------------------+
114   //          Trailer
115   // 
116   // Note, that this method assumes that the digits are ordered. 
117   // 
118   AliLoader* loader = fFMD->GetLoader();
119   loader->LoadDigits();
120   TTree* digitTree = loader->TreeD();
121   if (!digitTree) {
122     Error("Digits2Raw", "no digit tree");
123     return;
124   }
125   
126   TClonesArray* digits = new TClonesArray("AliFMDDigit", 1000);
127   fFMD->SetTreeAddress();
128   TBranch* digitBranch = digitTree->GetBranch(fFMD->GetName());
129   if (!digitBranch) {
130     Error("Digits2Raw", "no branch for %s", fFMD->GetName());
131     return;
132   }
133   digitBranch->SetAddress(&digits);
134   
135   Int_t nEvents = Int_t(digitTree->GetEntries());
136   for (Int_t event = 0; event < nEvents; event++) {
137     fFMD->ResetDigits();
138     digitTree->GetEvent(event);
139     
140     Int_t nDigits = digits->GetEntries();
141     if (nDigits < 1) continue;
142
143
144     UShort_t prevDetector = 0;
145     Char_t   prevRing     = '\0';
146     UShort_t prevSector   = 0;
147     // UShort_t prevStrip    = 0;
148
149     // The first seen strip number for a channel 
150     UShort_t startStrip   = 0;
151     
152     // Which channel number in the ALTRO channel we're at 
153     UShort_t offset       = 0;
154
155     // How many times the ALTRO Samples one VA1_ALICE channel 
156     Int_t sampleRate = 1;
157
158     // A buffer to hold 1 ALTRO channel - Normally, one ALTRO channel
159     // holds 128 VA1_ALICE channels, sampled at a rate of `sampleRate' 
160     TArrayI channel(fChannelsPerAltro * sampleRate);
161     
162     // The Altro buffer 
163     AliAltroBuffer* altro = 0;
164     
165     // Loop over the digits in the event.  Note, that we assume the
166     // the digits are in order in the branch.   If they were not, we'd
167     // have to cache all channels before we could write the data to
168     // the ALTRO buffer, or we'd have to set up a map of the digits. 
169     for (Int_t i = 0; i < nDigits; i++) {
170       // Get the digit
171       AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
172
173       UShort_t det    = digit->Detector();
174       Char_t   ring   = digit->Ring();
175       UShort_t sector = digit->Sector();
176       UShort_t strip  = digit->Strip();
177       if (det != prevDetector) {
178         AliDebug(10, Form("FMD: New DDL, was %d, now %d",
179                           AliFMD::kBaseDDL + prevDetector - 1,
180                           AliFMD::kBaseDDL + det - 1));
181         // If an altro exists, delete the object, flushing the data to
182         // disk, and closing the file. 
183         if (altro) { 
184           // When the first argument is false, we write the real
185           // header. 
186           AliDebug(10, Form("New altro: Write channel at %d Strip: %d "
187                             "Sector: %d  Ring: %d", 
188                             i, startStrip, prevSector, prevRing));
189           // TPC to FMD translations 
190           // 
191           //    TPC                FMD
192           //    ----------+-----------
193           //    pad       |      strip
194           //    row       |     sector
195           //    sector    |       ring
196           // 
197           WriteChannel(altro, startStrip, prevSector, prevRing, channel);
198           altro->Flush();
199           altro->WriteDataHeader(kFALSE, kFALSE);
200           delete altro;
201           altro = 0;
202         }
203
204         prevDetector = det;
205         // Need to open a new DDL! 
206         Int_t ddlId = AliFMD::kBaseDDL + det - 1;
207         TString filename(Form("%s_%d.ddl", fFMD->GetName(),  ddlId));
208
209         AliDebug(10, Form("New altro buffer with DDL file %s", 
210                           filename.Data()));
211         AliDebug(10, Form("New altro at %d", i));
212         // Create a new altro buffer - a `1' as the second argument
213         // means `write mode' 
214         altro = new AliAltroBuffer(filename.Data(), 1);
215         
216         // Write a dummy (first argument is true) header to the DDL
217         // file - later on, when we close the file, we write the real
218         // header
219         altro->WriteDataHeader(kTRUE, kFALSE);
220
221         // Figure out the sample rate 
222         if (fSampleRate > 0) sampleRate = fSampleRate;
223         else {
224           if (digit->Count2() >= 0) sampleRate = 2;
225           if (digit->Count3() >= 0) sampleRate = 3;
226         }
227
228         channel.Set(fChannelsPerAltro * sampleRate);
229         offset     = 0;
230         prevRing   = ring;
231         prevSector = sector;
232         startStrip = strip;
233       }
234       else if (offset == fChannelsPerAltro
235                || digit->Ring() != prevRing 
236                || digit->Sector() != prevSector) {
237         // Force a new Altro channel
238         AliDebug(10, Form("Flushing channel to disk because %s",
239                           (offset == fChannelsPerAltro ? "channel is full" :
240                            (ring != prevRing ? "new ring up" :
241                             "new sector up"))));
242         AliDebug(10, Form("New Channel: Write channel at %d Strip: %d "
243                           "Sector: %d  Ring: %d", 
244                           i, startStrip, prevSector, prevRing));
245         WriteChannel(altro, startStrip, prevSector, prevRing, channel);
246         // Reset and update channel variables 
247         channel.Reset(0);
248         offset     = 0; 
249         startStrip = strip;
250         prevRing   = ring;
251         prevSector = sector;
252       }
253
254       // Store the counts of the ADC in the channel buffer 
255       channel[offset * sampleRate] = digit->Count1();
256       if (sampleRate > 1) 
257         channel[offset * sampleRate + 1] = digit->Count2();
258       if (sampleRate > 2) 
259         channel[offset * sampleRate + 2] = digit->Count3();
260       offset++;
261     }
262     // Finally, we need to close the final ALTRO buffer if it wasn't
263     // already 
264     if (altro) {
265       altro->Flush();
266       altro->WriteDataHeader(kFALSE, kFALSE);
267       delete altro;
268     }
269   }
270   loader->UnloadDigits();
271 }
272
273 //____________________________________________________________________
274 void
275 AliFMDRawWriter::WriteChannel(AliAltroBuffer* altro, 
276                               UShort_t strip, UShort_t sector, Char_t ring, 
277                               const TArrayI& data) 
278 {
279   // Write out one ALTRO channel to the data file. 
280   // Derived classes can overload this method to use a per-ALTRO
281   // threshold.   This implementation uses the common threshold set by
282   // SetThreshold. 
283   altro->WriteChannel(Int_t(strip), 
284                       Int_t(sector), 
285                       Int_t((ring == 'I' ? 0 : 1)), 
286                       data.fN, data.fArray, fThreshold);
287 }
288
289   
290
291 //____________________________________________________________________
292 // 
293 // EOF
294 //