]> git.uio.no Git - u/mrichter/AliRoot.git/blob - FMD/AliFMDParameters.cxx
7142e26eeb13727c37e4f7754a68298140d35c2e
[u/mrichter/AliRoot.git] / FMD / AliFMDParameters.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  * $Id$ */
16 /**
17  * @file    AliFMDParameters.cxx
18  * @author  Christian Holm Christensen <cholm@nbi.dk>
19  * @date    Mon Mar 27 12:44:26 2006
20  * @brief   Manager of FMD parameters     
21  */
22 //____________________________________________________________________
23 //                                                                          
24 // Forward Multiplicity Detector based on Silicon wafers. 
25 //
26 // This class is a singleton that handles various parameters of
27 // the FMD detectors.  
28 // The manager normally serves the parameters from the Conditions
29 // Database (CDB).  These are retrivied by the member function
30 // `Init'.  Optionally, the class can serve hard-coded constants, if
31 // no CDB is available. 
32 //                                                       
33 #include "AliFMDDebug.h"                   // ALILOG_H
34 #include "AliFMDParameters.h"      // ALIFMDPARAMETERS_H
35 #include "AliFMDGeometry.h"        // ALIFMDGEOMETRY_H
36 #include "AliFMDRing.h"            // ALIFMDRING_H
37 #include "AliFMDCalibGain.h"       // ALIFMDCALIBGAIN_H
38 #include "AliFMDCalibPedestal.h"   // ALIFMDCALIBPEDESTAL_H
39 #include "AliFMDCalibSampleRate.h" // ALIFMDCALIBSAMPLERATE_H
40 #include "AliFMDCalibStripRange.h" // ALIFMDCALIBSTRIPRANGE_H
41 #include "AliFMDAltroMapping.h"    // ALIFMDALTROMAPPING_H
42 #include <AliCDBManager.h>         // ALICDBMANAGER_H
43 #include <AliCDBEntry.h>           // ALICDBMANAGER_H
44 #include <AliFMDPreprocessor.h>
45 #include <AliLog.h>
46 #include <Riostream.h>
47 #include <sstream>
48 #include <TSystem.h>
49 #include <TArrayF.h>
50 #include <TH2D.h>
51
52 //====================================================================
53 ClassImp(AliFMDParameters)
54 #if 0
55   ; // This is here to keep Emacs for indenting the next line
56 #endif
57
58 //____________________________________________________________________
59 AliFMDParameters* AliFMDParameters::fgInstance = 0;
60
61 //____________________________________________________________________
62 const char* AliFMDParameters::fgkPulseGain          = "FMD/Calib/PulseGain";
63 const char* AliFMDParameters::fgkPedestal           = "FMD/Calib/Pedestal";
64 const char* AliFMDParameters::fgkDead               = "FMD/Calib/Dead";
65 const char* AliFMDParameters::fgkSampleRate         = "FMD/Calib/SampleRate";
66 const char* AliFMDParameters::fgkAltroMap           = "FMD/Calib/AltroMap";
67 const char* AliFMDParameters::fgkZeroSuppression    = "FMD/Calib/ZeroSuppression";
68 const char* AliFMDParameters::fgkStripRange         = "FMD/Calib/StripRange";
69 const char* AliFMDParameters::fkPedestalShuttleID   = "pedestals";
70 const char* AliFMDParameters::fkGainShuttleID       = "gains";
71 const char* AliFMDParameters::fkConditionsShuttleID = "conditions";
72
73 //____________________________________________________________________
74 AliFMDParameters* 
75 AliFMDParameters::Instance() 
76 {
77   // 
78   // Get static instance 
79   //
80   if (!fgInstance) fgInstance = new AliFMDParameters;
81   return fgInstance;
82 }
83
84 //____________________________________________________________________
85 AliFMDParameters::AliFMDParameters() 
86   : fIsInit(kFALSE),
87     fkSiDeDxMip(1.664), 
88     fVA1MipRange(0),
89     fAltroChannelSize(0),
90     fChannelsPerAltro(0),
91     fPedestalFactor(0),
92     fZSPre(1),
93     fZSPost(1),
94     fZSPedSubtract(kTRUE),
95     fFixedPedestal(100),
96     fFixedPedestalWidth(2),
97     fFixedZeroSuppression(1),
98     fFixedSampleRate(2),
99     fFixedThreshold(0),
100     fFixedMinStrip(0),
101     fFixedMaxStrip(127),
102     fFixedPulseGain(2), 
103     fEdepMip(0),
104     fHasCompleteHeader(kTRUE),
105     fZeroSuppression(0), 
106     fSampleRate(0), 
107     fPedestal(0), 
108     fPulseGain(0), 
109     fDeadMap(0), 
110     fAltroMap(0), 
111     fStripRange(0)
112 {
113   //
114   // Default constructor 
115   //
116   SetVA1MipRange();
117   SetAltroChannelSize();
118   SetChannelsPerAltro();
119   SetZeroSuppression();
120   SetSampleRate();
121   SetPedestal();
122   SetPedestalWidth();
123   SetPedestalFactor();
124   SetThreshold();
125   SetStripRange();
126   SetGain();
127   fAltroMap = new AliFMDAltroMapping;
128 }
129
130 //__________________________________________________________________
131 void
132 AliFMDParameters::Init(Bool_t forceReInit, UInt_t what)
133 {
134   // 
135   // Initialize the manager.  This tries to read the parameters from
136   // CDB.  If that fails, the class uses the hard-coded parameters.
137   // 
138   // Parameters:
139   //    forceReInit Force (re-)initalize flag
140   //    what        What to initialize 
141   //
142   if (forceReInit) fIsInit = kFALSE;
143   if (fIsInit) return;
144   if (what & kPulseGain)       InitPulseGain();
145   if (what & kPedestal)        InitPedestal();
146   if (what & kDeadMap)         InitDeadMap();
147   if (what & kSampleRate)      InitSampleRate();
148   if (what & kZeroSuppression) InitZeroSuppression();
149   if (what & kAltroMap)        InitAltroMap();
150   if (what & kStripRange)      InitStripRange();
151   fIsInit = kTRUE;
152 }
153 //__________________________________________________________________
154 void
155 AliFMDParameters::Init(AliFMDPreprocessor* pp, Bool_t forceReInit, UInt_t what)
156 {
157   // 
158   // Initialize the manager.  This tries to read the parameters from
159   // CDB.  If that fails, the class uses the hard-coded parameters.
160   // 
161   // Parameters:
162   //    pp          Preprocessor 
163   //    forceReInit Force (re-)initalize flag
164   //    what        What to initialize 
165   //
166   if (forceReInit) fIsInit = kFALSE;
167   if (fIsInit) return;
168   if (what & kPulseGain)       InitPulseGain(pp);
169   if (what & kPedestal)        InitPedestal(pp);
170   if (what & kDeadMap)         InitDeadMap(pp);
171   if (what & kSampleRate)      InitSampleRate(pp);
172   if (what & kZeroSuppression) InitZeroSuppression(pp);
173   if (what & kAltroMap)        InitAltroMap(pp);
174   if (what & kStripRange)      InitStripRange(pp);
175   fIsInit = kTRUE;
176 }
177
178 //__________________________________________________________________
179 Bool_t
180 AliFMDParameters::CheckFile(const char* prefix, 
181                             const char* path, 
182                             int         number, 
183                             TString&    f) const
184 {
185   // 
186   // Check if the file <i>prefix</i><i>number</i> exists in @a path, 
187   // and write the full path to @a f.  
188   // 
189   // Parameters:
190   //    prefix  File prefix (cond, peds, gains, ...)
191   //    path    Path to files
192   //    number  Detector number (1, 2, or 3)
193   //    f       On return full path to file (if found)
194   // 
195   // Return:
196   //    @c true if file exists and is readable, @c false otherwise
197   //
198   f = (Form("%s%d.csv", prefix, number));
199   AliFMDDebug(5, ("Checking if %s exists in %s ...", f.Data(), path));
200   f = gSystem->Which(path, f.Data());
201   AliFMDDebug(5, ("Got back '%s'", f.Data()));
202   return !f.IsNull();
203 }
204
205 //__________________________________________________________________
206 void
207 AliFMDParameters::Init(const char* path, Bool_t forceReInit, UInt_t what)
208 {
209   // 
210   // Initialize the manager.  This will try to read some calibrations
211   // (sample rate, strip range, gains, pedestals) from local comma
212   // separated value (CSV) files in the directory pointed at by @a
213   // path.  If they are not found, then they will be retrieved from
214   // OCDB as appropriately.   Other calibrations are always read from
215   // OCDB.  
216   // 
217   // The CSV files should be named as 
218   // 
219   // - Pedestals: <tt>peds</tt><i>det_number</i><tt>.csv</tt>
220   // - Gains: <tt>gains</tt><i>det_number</i><tt>.csv</tt>
221   // - Sample Rate: <tt>conditions</tt><i>det_number</i><tt>.csv</tt>
222   // - Strip Range: <tt>conditions</tt><i>det_number</i><tt>.csv</tt>
223   //
224   // where <i>det_number</i> is the detector number (1, 2, or 3). 
225   // 
226   // Parameters:
227   //    path        Where to look for the CSV files
228   //    forceReInit Always reinitialise 
229   //    what        What calibrations to load. 
230   //  
231   if (forceReInit) fIsInit = kFALSE;
232   if (fIsInit) return;
233
234   AliFMDCalibStripRange*  range = 0;
235   AliFMDCalibSampleRate*  rate  = 0;
236   AliFMDCalibPedestal*    peds  = 0;
237   AliFMDCalibGain*        gains = 0;
238
239   for (Int_t i = 1; i <= 3; i++) { 
240     TString f;
241     if (((what & kSampleRate) || (what & kStripRange)) && 
242         CheckFile("conditions", path, i, f)) {
243       if (!rate  && (what & kSampleRate)) rate  = new AliFMDCalibSampleRate;
244       if (!range && (what & kStripRange)) range = new AliFMDCalibStripRange;
245       std::ifstream in(f.Data());
246       if (range) range->ReadFromFile(in);
247       if (rate)  rate->ReadFromFile(in);
248       in.close();
249     }
250     if ((what & kPedestal) && CheckFile("peds", path, i, f)) {
251       if (!peds) peds  = new AliFMDCalibPedestal;
252       std::ifstream in(f.Data());
253       peds->ReadFromFile(in);
254       in.close();
255     }
256     if ((what & kPulseGain) && CheckFile("gains", path, i, f)) { 
257       if (!gains) gains = new AliFMDCalibGain;
258       std::ifstream in(f.Data());
259       gains->ReadFromFile(in);
260       in.close();
261     }
262   }
263
264   if (range) what &= ~kStripRange;
265   if (rate)  what &= ~kSampleRate;
266   if (peds)  what &= ~kPedestal;
267   if (gains) what &= ~kPulseGain;
268
269   Init(kFALSE, what);
270   
271   if (range) SetStripRange(range);
272   if (rate)  SetSampleRate(rate);
273   if (peds)  SetPedestal(peds);
274   if (gains) SetGain(gains);
275
276   fIsInit = kTRUE;
277 }
278
279 //__________________________________________________________________
280 void
281 AliFMDParameters::MakeDeadMap(Float_t maxNoise, 
282                               Float_t minGain, 
283                               Float_t maxGain)
284 {
285   // 
286   // Automatically generate a dead map from the pedestals and gains.
287   // A channel is marked as dead of the noise is too high (currently
288   // more than 10 ADC counts), or the gain is unreasonable (currently
289   // larger than 10, or smaller than 0.1). 
290   // 
291   // The procedure does not overwrite channels previously marked as
292   // dead - e.g., channels marked as dead in the calibration loaded
293   // from OCDB will continue to be marked as dead.  That is, this
294   // procedure will never make a channel un-dead. 
295   // 
296   // Parameters:
297   //    maxNoise  Maximum noise value before a channel is marked
298   // as dead. 
299   //    minGain   Minimum value of the calibrated gain before a
300   // channel is considered dead. 
301   //    maxGain   Maximum value of the calibrated gain before a
302   // channel is considered dead. 
303   //
304   if (fPedestal)  
305     fDeadMap = fPedestal->MakeDeadMap(maxNoise, fDeadMap);
306   if (fPulseGain) 
307     fDeadMap = fPulseGain->MakeDeadMap(minGain, maxGain, fDeadMap);
308 }
309 //__________________________________________________________________
310 #define DET2IDX(det,ring,sec,str) \
311   (det * 1000 + (ring == 'I' ? 0 : 512) + str)  
312   
313 //__________________________________________________________________
314 void
315 AliFMDParameters::Draw(Option_t* option)
316 {
317   // 
318   // Draw parameters. 
319   // 
320   // Parameters:
321   //    option What to draw. Should be one of 
322   // - dead       Dead channels
323   // - threshold Threshold
324   // - gain       Gain
325   // - pedestal  Pedestal
326   // - noise      Noise (or pedestal width)
327   // - zero       Zero suppression
328   // - rate       Sampling rate (VA1 clock / ALTRO clock)
329   // - min        Minimum strip read out
330   // - max        Maximum strip read out
331   // - map        hardware address
332   //
333   TString opt(option);
334   enum {
335     kLocalPulseGain,       // Path to PulseGain calib object
336     kLocalThreshold,       // Path to PulseGain calib object
337     kLocalPedestal,        // Path to Pedestal calib object
338     kLocalPedestalWidth,   // Path to Pedestal calib object
339     kLocalDead,            // Path to Dead calib object
340     kLocalSampleRate,      // Path to SampleRate calib object
341     kLocalAltroMap,        // Path to AltroMap calib object
342     kLocalZeroSuppression, // Path to ZeroSuppression cal object
343     kLocalMinStripRange,   // Path to strip range cal object
344     kLocalMaxStripRange    // Path to strip range cal object
345   } what;
346     
347   if      (opt.Contains("dead", TString::kIgnoreCase)) 
348     what = kLocalDead;
349   else if (opt.Contains("threshold",TString::kIgnoreCase)) 
350     what = kLocalThreshold;
351   else if (opt.Contains("gain",TString::kIgnoreCase)) 
352     what = kLocalPulseGain;
353   else if (opt.Contains("pedestal",TString::kIgnoreCase)) 
354     what = kLocalPedestal;
355   else if (opt.Contains("noise",TString::kIgnoreCase)) 
356     what = kLocalPedestalWidth;
357   else if (opt.Contains("zero",TString::kIgnoreCase)) 
358     what = kLocalZeroSuppression;
359   else if (opt.Contains("rate",TString::kIgnoreCase)) 
360     what = kLocalSampleRate;
361   else if (opt.Contains("min",TString::kIgnoreCase)) 
362     what = kLocalMinStripRange;
363   else if (opt.Contains("max",TString::kIgnoreCase)) 
364     what = kLocalMaxStripRange;
365   else if (opt.Contains("map",TString::kIgnoreCase)) 
366     what = kLocalAltroMap;
367   else {
368     Warning("Draw", "unknown parameter: %s\n\tShould be one of\n\t"
369             "dead, threshold, gain, pedestal, noise, zero, rate, "
370             "min, max, map",  
371             option); 
372     return;
373   }
374
375   TArrayD xbins(3 * 512 + 2 * 256 + 5);
376   Int_t i = 1;
377   Bool_t skip = kTRUE;
378   for (UShort_t det = 1; det <= 3; det++) {
379     UShort_t nRings = (det == 1 ? 1 : 2);
380     for (UShort_t iring = 0; iring < nRings; iring++) {
381       UShort_t nStrip  = (iring == 0 ? 512 : 256);
382       Char_t   ring    = (iring == 0 ? 'I' : 'O');
383       for (UShort_t str = 0; str < nStrip; str++) {
384         // UShort_t nSec    = (iring == 0 ? 20  : 40);
385         // Char_t   ring    = (iring == 0 ? 'I' : 'O');
386         // for (UShort_t sec = 0; sec < nSec; sec++) {
387         Int_t idx = DET2IDX(det, ring, 0, str);
388         // Int_t idx = DET2IDX(det, ring, sec, 0);
389         if (skip) {
390           xbins[i-1] = idx - .5;
391           skip  = kFALSE;
392         }
393         xbins[i] = idx + .5;
394         i++;
395       }
396       skip = kTRUE;
397       i++;
398     }
399   }
400   TArrayD ybins(41);
401   for (/*Int_t*/ i = 0; i < ybins.fN; i++) ybins[i] = Float_t(i - .5);
402   TH2D* hist = new TH2D("calib", Form("Calibration %s", option), 
403                         xbins.fN-1, xbins.fArray,  
404                         ybins.fN-1, ybins.fArray);
405   hist->GetXaxis()->SetTitle("1000 #times detector + 512 #times ring + strip");
406   hist->GetYaxis()->SetTitle("sector");
407   
408   // hist->Draw("Lego");
409   // return;
410   
411   for (UShort_t det = 1; det <= 3; det++) {
412     UShort_t nRings = (det == 1 ? 1 : 2);
413     for (UShort_t iring = 0; iring < nRings; iring++) {
414       UShort_t nSector = (iring == 0 ?  20 : 40);
415       UShort_t nStrip  = (iring == 0 ? 512 : 256);
416       Char_t   ring    = (iring == 0 ? 'I' : 'O');
417       for (UShort_t sec = 0; sec < nSector; sec++) {
418         for (UShort_t str = 0; str < nStrip; str++) {
419           Int_t idx = DET2IDX(det, ring, sec, str);
420           UShort_t ddl, addr, time, sam=0;
421           Double_t val = 0;
422           switch (what) {
423           case kLocalPulseGain:       // Path to PulseGain calib object
424             val = GetPulseGain(det,ring,sec,str); break;
425           case kLocalThreshold:       // Path to PulseGain calib object
426             val = GetThreshold(); break;
427           case kLocalPedestal:        // Path to Pedestal calib object
428             val = GetPedestal(det,ring,sec,str); break;
429           case kLocalPedestalWidth:   // Path to Pedestal calib object
430             val = GetPedestalWidth(det,ring,sec,str); break;
431           case kLocalDead:            // Path to Dead calib object
432             val = IsDead(det,ring,sec,str); break;
433           case kLocalSampleRate:      // Path to SampleRate calib object
434             val = GetSampleRate(det,ring,sec,str); break;
435           case kLocalAltroMap:        // Path to AltroMap calib object
436             Detector2Hardware(det,ring,sec,str,sam,ddl,addr,time); 
437             val = addr; break;
438           case kLocalZeroSuppression: // Path to ZeroSuppression cal object
439             val = GetZeroSuppression(det,ring,sec,str); break;
440           case kLocalMinStripRange:   // Path to strip range cal object
441             val = GetMinStrip(det,ring,sec,str); break;
442           case kLocalMaxStripRange:    // Path to strip range cal object
443             val = GetMaxStrip(det,ring,sec,str); break;
444           }
445           hist->Fill(idx,sec,val);
446           // hist->Fill(idx,str,val);
447         }
448       }
449     }
450   }
451   hist->Draw("lego");
452 }
453
454 //__________________________________________________________________
455 void
456 AliFMDParameters::Print(Option_t* option) const
457 {
458   // Print information. 
459   // If option contains an 'A' then everything is printed. 
460   // If the option contains the string "FMD" the function will search 
461   // for detector, ring, sector, and strip numbers to print, in the
462   // format 
463   // 
464   //    FMD<detector><ring>[<sector>,<string>] 
465   // 
466   // The wild card '*' means all of <detector>, <ring>, <sector>, or 
467   // <strip>. 
468   TString opt(option);
469   Bool_t showStrips  = opt.Contains("a", TString::kIgnoreCase);
470   UShort_t ds[]      = { 1, 2, 3, 0 };
471   Char_t   rs[]      = { 'I', 'O', '\0' };
472   UShort_t minStrip  = 0;
473   UShort_t maxStrip  = 512;
474   UShort_t minSector = 0;
475   UShort_t maxSector = 40;
476   
477   
478   if (opt.Contains("fmd",TString::kIgnoreCase)) {
479     Int_t   i    = opt.Index("fmd",TString::kIgnoreCase);
480     Int_t   j    = opt.Index("]",TString::kIgnoreCase);
481     if (j != kNPOS)
482       showStrips    = kTRUE;
483     else 
484       j = opt.Length();
485     enum {
486       kReadDet, 
487       kReadRing, 
488       kReadLbrack,
489       kReadSector,
490       kReadComma,
491       kReadStrip,
492       kReadRbrack, 
493       kEnd
494     } state = kReadDet;
495     std::stringstream s(opt(i+4, j-i-3).Data());
496     while (state != kEnd) {
497       Char_t tmp = s.peek();
498       if (tmp == ' ' || tmp == '\t') {
499         s.get();
500         continue;
501       }
502       switch (state) {
503       case kReadDet: { // First, try to kRead the detector 
504         if (tmp == '*') s.get();
505         else { 
506           UShort_t det;
507           s >> det;
508           if (!s.bad()) {
509             ds[0] = det;
510             ds[1] = 0;
511           }
512         }
513         state = (s.bad() ? kEnd : kReadRing);
514       } break;
515       case kReadRing: { // Then try to read the ring;
516         Char_t ring;
517         s >> ring;
518         if (ring != '*' && !s.bad()) {
519           rs[0] = ring;
520           rs[1] = '\0';
521         }
522         state = (s.bad() ? kEnd : kReadLbrack);
523       } break;
524       case kReadLbrack: { // Try to read a left bracket 
525         Char_t lbrack;
526         s >> lbrack;
527         state = (s.bad() ? kEnd : kReadSector);
528       } break;
529       case kReadSector: { // Try to read a sector 
530         if (tmp == '*') s.get();
531         else {
532           UShort_t sec;
533           s >> sec;
534           if (!s.bad()) {
535             minSector = sec;
536             maxSector = sec + 1;
537           }
538         }
539         state = (s.bad() ? kEnd : kReadComma);
540       } break;
541       case kReadComma: { // Try to read a left bracket 
542         Char_t comma;
543         s >> comma;
544         state = (s.bad() ? kEnd : kReadStrip);
545       } break;
546       case kReadStrip: { // Try to read a strip 
547         if (tmp == '*') s.get();
548         else {
549           UShort_t str;
550           s >> str;
551           if (!s.bad()) {
552             minStrip = str;
553             maxStrip = str + 1;
554           }
555         }
556         state = (s.bad() ? kEnd : kReadRbrack);
557       } break;
558       case kReadRbrack: { // Try to read a left bracket 
559         Char_t rbrack;
560         s >> rbrack;
561         state = kEnd;
562       } break;
563       case kEnd: 
564         break;
565       }
566     }
567   }
568   UShort_t* dp = ds;
569   UShort_t  det;
570   while ((det = *(dp++))) {
571
572     Char_t* rp = rs;
573     Char_t  ring;
574     while ((ring = *(rp++))) {
575       if (det == 1 && ring == 'O') continue;
576       UShort_t min  = GetMinStrip(det, ring, 0, 0);
577       UShort_t max  = GetMaxStrip(det, ring, 0, 0);
578       std::cout << "FMD" << det << ring 
579                 << "  Strip range: " 
580                 << std::setw(3) << min << "," 
581                 << std::setw(3) << max << std::endl;
582
583       UShort_t nSec = ( ring == 'I' ? 20  :  40 );
584       UShort_t nStr = ( ring == 'I' ? 512 : 256 );
585       for (UShort_t sec = minSector; sec < maxSector && sec < nSec; sec++) {
586
587         UShort_t rate = GetSampleRate(det, ring, sec, 0);
588         std::cout << "FMD" << det << ring << "[" << std::setw(2) << sec 
589                   << "] sample rate: " << rate << std::endl;
590
591         if (!showStrips) continue;
592         std::cout 
593           << "  Strip |     Pedestal      |    Gain    | ZS thr. | Address\n" 
594           << "--------+-------------------+------------+---------+---------" 
595           << std::endl;
596         for (UShort_t str = minStrip; str < nStr && str < maxStrip; str++) {
597           if (str == minStrip) std::cout << std::setw(3) << sec << ",";
598           else std::cout << "    ";
599           std::cout << std::setw(3) << str << " | ";
600           if (IsDead(det, ring, sec, str)) {
601             std::cout << "dead" << std::endl;
602             continue;
603           }
604           UShort_t ddl, addr, time, sam=0;
605           Detector2Hardware(det, ring, sec, str, sam, ddl, addr, time);
606           std::cout << std::setw(7) << GetPedestal(det, ring, sec, str) 
607                     << "+/-" << std::setw(7) 
608                     << GetPedestalWidth(det, ring, sec, str) 
609                     << " | " << std::setw(10) 
610                     << GetPulseGain(det, ring, sec, str) 
611                     << " | " << std::setw(7) 
612                     << GetZeroSuppression(det, ring, sec, str) 
613                     << " | 0x" << std::hex << std::setw(4) 
614                     << std::setfill('0') << ddl << ",0x" << std::setw(3) 
615                     << addr << std::dec << std::setfill(' ') << std::endl;
616         } // for (strip)
617       } // for (sector)
618       std::cout
619         << "=============================================================" 
620         << std::endl;
621     } // while (ring)
622   } // while (det)
623   
624 }
625
626 //__________________________________________________________________
627 AliCDBEntry*
628 AliFMDParameters::GetEntry(const char* path, AliFMDPreprocessor* pp, 
629                            Bool_t fatal) const
630 {
631   // 
632   // Get an entry from either global AliCDBManager or passed
633   // AliFMDPreprocessor. 
634   // 
635   // Parameters:
636   //    path  Path to CDB object. 
637   //    pp    AliFMDPreprocessor 
638   //    fatal If true, raise a fatal flag if we didn't get the entry.
639   // Return:
640   //    AliCDBEntry if found 
641   // 
642   AliCDBEntry* entry = 0;
643   if (!pp) {
644     AliCDBManager* cdb = AliCDBManager::Instance();
645     entry              = cdb->Get(path);
646   }
647   else {
648     const char* third  = gSystem->BaseName(path);
649     const char* second = gSystem->BaseName(gSystem->DirName(path));
650     entry              = pp->GetFromCDB(second, third);
651   }
652   if (!entry) { 
653     TString msg(Form("No %s found in CDB, perhaps you need to "
654                      "use AliFMDCalibFaker?", path));
655     if (fatal) { AliFatal(msg.Data()); }
656     else       AliLog::Message(AliLog::kWarning, msg.Data(), "FMD", 
657                                "AliFMDParameters", "GetEntry", __FILE__, 
658                                __LINE__);
659     return 0;
660   }
661   if (entry && AliLog::GetDebugLevel("FMD", "") > 0) { 
662     AliInfoF("Got entry %p for %s", entry, path);
663     entry->PrintId();
664     entry->PrintMetaData();                     
665     entry->Print();
666   }
667   return entry;
668 }
669
670     
671 //__________________________________________________________________
672 void
673 AliFMDParameters::InitPulseGain(AliFMDPreprocessor* pp)
674 {
675   // 
676   // Initialize gains.  Try to get them from CDB 
677   // 
678   // Parameters:
679   //    pp Pre-processor if called from shuttle
680   //
681   AliCDBEntry*   gain     = GetEntry(fgkPulseGain, pp);
682   if (!gain) return;
683   
684   AliFMDDebug(5, ("Got gain from CDB"));
685   fPulseGain = dynamic_cast<AliFMDCalibGain*>(gain->GetObject());
686   if (!fPulseGain) AliFatal("Invalid pulser gain object from CDB");
687   if (!fPulseGain->Values().Ptr()) 
688     AliFatal("Empty pulser gain object from CDB");
689 }
690 //__________________________________________________________________
691 void
692 AliFMDParameters::InitPedestal(AliFMDPreprocessor* pp)
693 {
694   //
695   // Initialize pedestals.  Try to get them from CDB
696   // 
697   // Parameters:
698   //    pp Pre-processor if called from shuttle
699   //
700   AliCDBEntry*   pedestal = GetEntry(fgkPedestal, pp);
701   if (!pedestal) return;
702
703   AliFMDDebug(5, ("Got pedestal from CDB"));
704   fPedestal = dynamic_cast<AliFMDCalibPedestal*>(pedestal->GetObject());
705   if (!fPedestal) AliFatal("Invalid pedestal object from CDB");
706   if (!fPedestal->Values().Ptr()) AliFatal("Empty pedestal object from CDB");
707 }
708
709 //__________________________________________________________________
710 void
711 AliFMDParameters::InitDeadMap(AliFMDPreprocessor* pp)
712 {
713   //
714   // Initialize dead map.  Try to get it from CDB
715   // 
716   // Parameters:
717   //    pp Pre-processor if called from shuttle
718   //
719   AliCDBEntry*   deadMap  = GetEntry(fgkDead, pp);
720   if (!deadMap) return;
721   
722   AliFMDDebug(5, ("Got dead map from CDB"));
723   fDeadMap = dynamic_cast<AliFMDCalibDeadMap*>(deadMap->GetObject());
724   if (!fDeadMap) AliFatal("Invalid dead map object from CDB");
725   if (!fDeadMap->Ptr()) AliFatal("Empty dead map object from CDB");
726 }
727
728 //__________________________________________________________________
729 void
730 AliFMDParameters::InitZeroSuppression(AliFMDPreprocessor* pp)
731 {
732   //
733   // Initialize zero suppression thresholds.  Try to get them from CDB
734   // 
735   // Parameters:
736   //    pp Pre-processor if called from shuttle
737   //
738   AliCDBEntry*   zeroSup  = GetEntry(fgkZeroSuppression, pp);
739   if (!zeroSup) return;
740   AliFMDDebug(5, ("Got zero suppression from CDB"));
741   fZeroSuppression = 
742     dynamic_cast<AliFMDCalibZeroSuppression*>(zeroSup->GetObject());
743   if (!fZeroSuppression)AliFatal("Invalid zero suppression object from CDB");
744   if (!fZeroSuppression->Ptr()) {
745     AliWarningF("Empty zero suppression object from CDB, assuming %d",
746                 fFixedZeroSuppression);
747     AliCDBManager* cdbMan = AliCDBManager::Instance();
748     if(!cdbMan || !cdbMan->GetCacheFlag())
749       delete fZeroSuppression;
750     fZeroSuppression = 0;
751   }
752 }
753
754 //__________________________________________________________________
755 void
756 AliFMDParameters::InitSampleRate(AliFMDPreprocessor* pp)
757 {
758   //
759   // Initialize sample rates.  Try to get them from CDB
760   // 
761   // Parameters:
762   //    pp Pre-processor if called from shuttle
763   //
764   AliCDBEntry*   sampRat  = GetEntry(fgkSampleRate, pp);
765   if (!sampRat) return;
766   AliFMDDebug(5, ("Got zero suppression from CDB"));
767   fSampleRate = dynamic_cast<AliFMDCalibSampleRate*>(sampRat->GetObject());
768   if (!fSampleRate) AliFatal("Invalid sample rate object from CDB");
769   if (!fSampleRate->Rates().Ptr()) 
770     AliFatal("empty sample rate object from CDB");
771 }
772
773 //__________________________________________________________________
774 void
775 AliFMDParameters::InitAltroMap(AliFMDPreprocessor* pp)
776 {
777   //
778   // Initialize hardware map.  Try to get it from CDB
779   // 
780   // Parameters:
781   //    pp Pre-processor if called from shuttle
782   //
783   if (fAltroMap) { 
784     delete fAltroMap;
785     fAltroMap = 0;
786   }
787   AliCDBEntry*   hwMap    = GetEntry(fgkAltroMap, pp, kFALSE);       
788   if (!hwMap) return;
789
790   AliFMDDebug(5, ("Got ALTRO map from CDB"));
791   fAltroMap = dynamic_cast<AliFMDAltroMapping*>(hwMap->GetObject());
792   if (!fAltroMap) {
793     AliFatal("Invalid ALTRO map object from CDB");
794     fAltroMap = new AliFMDAltroMapping;
795   }
796 }
797
798 //__________________________________________________________________
799 void
800 AliFMDParameters::InitStripRange(AliFMDPreprocessor* pp)
801 {
802   //
803   // Initialize strip range.  Try to get it from CDB
804   // 
805   // Parameters:
806   //    pp Pre-processor if called from shuttle
807   //
808   AliCDBEntry*   range    = GetEntry(fgkStripRange, pp);
809   if (!range) return;
810   AliFMDDebug(5, ("Got strip range from CDB"));
811   fStripRange = dynamic_cast<AliFMDCalibStripRange*>(range->GetObject());
812   if (!fStripRange) AliFatal("Invalid strip range object from CDB");
813   if (!fStripRange->Ranges().Ptr()) 
814     AliFatal("Empty strip range object from CDB");
815 }
816
817
818 //__________________________________________________________________
819 Float_t
820 AliFMDParameters::GetThreshold() const
821 {
822   // 
823   // Get the threshold in the pulser gain 
824   // 
825   // 
826   // Return:
827   //    Threshold from pulser 
828   //
829   if (!fPulseGain) return fFixedThreshold;
830   return fPulseGain->Threshold();
831 }
832
833 //__________________________________________________________________
834 Float_t
835 AliFMDParameters::GetPulseGain(UShort_t detector, Char_t ring, 
836                                UShort_t sector, UShort_t strip) const
837 {
838   // 
839   // Gain of pre-amp. for strip, sector, ring, detector 
840   //
841   // For simulations this is normally set to 
842   //
843   // @f[ 
844   //  \frac{\mbox{VA1_MIP_Range}{\mbox{ALTRO_channel_size}}\mbox{MIP_Energy_Loss}
845   // @f]
846   // 
847   // 
848   // Parameters:
849   //    detector Detector # (1-3)
850   //    ring     Ring ID ('I' or 'O')
851   //    sector   Sector number (0-39)
852   //    strip    Strip number (0-511)
853   //
854   // Return:
855   //    Gain of pre-amp.  
856   //
857   if (!fPulseGain) { 
858     if (fFixedPulseGain <= 0)
859       fFixedPulseGain = fVA1MipRange * GetEdepMip() / fAltroChannelSize;
860     return fFixedPulseGain;
861   }  
862   AliFMDDebug(50, ("pulse gain for FMD%d%c[%2d,%3d]=%f",
863                     detector, ring, sector, strip,
864                     fPulseGain->Value(detector, ring, sector, strip)));
865   return fPulseGain->Value(detector, ring, sector, strip);
866 }
867
868 //__________________________________________________________________
869 Bool_t
870 AliFMDParameters::IsDead(UShort_t detector, Char_t ring, 
871                          UShort_t sector, UShort_t strip) const
872 {
873   // 
874   // Whether the strip is considered dead
875   // 
876   // Parameters:
877   //    detector Detector # (1-3)
878   //    ring     Ring ID ('I' or 'O')
879   //    sector   Sector number (0-39)
880   //    strip    Strip number (0-511)
881   //
882   // Return:
883   //    @c true if the strip is considered dead, @c false if it's
884   // OK.
885   //
886   if (!fDeadMap) return kFALSE;
887   AliFMDDebug(50, ("Dead for FMD%d%c[%2d,%3d]=%s",
888                     detector, ring, sector, strip,
889                     fDeadMap->operator()(detector, ring, sector, strip) ? 
890                     "no" : "yes"));
891   return fDeadMap->operator()(detector, ring, sector, strip);
892 }
893
894 //__________________________________________________________________
895 UShort_t
896 AliFMDParameters::GetZeroSuppression(UShort_t detector, Char_t ring, 
897                                      UShort_t sector, UShort_t strip) const
898 {
899   // 
900   // zero suppression threshold (in ADC counts)
901   // 
902   // Parameters:
903   //    detector Detector # (1-3)
904   //    ring     Ring ID ('I' or 'O')
905   //    sector   Sector number (0-39)
906   //    strip    Strip number (0-511)
907   //
908   // Return:
909   //    zero suppression threshold (in ADC counts) 
910   //
911   if (!fZeroSuppression) return fFixedZeroSuppression;
912
913   // In case of empty zero suppression objects. 
914   if (!fZeroSuppression->Ptr() || 
915       fZeroSuppression->MaxIndex() <= 0) return fFixedZeroSuppression;
916
917   // Need to map strip to ALTRO chip. 
918   AliFMDDebug(50, ("zero sup. for FMD%d%c[%2d,%3d]=%d",
919                     detector, ring, sector, strip,
920                     fZeroSuppression->operator()(detector, ring, 
921                                                  sector, strip)));
922   return fZeroSuppression->operator()(detector, ring, sector, strip/128);
923 }
924
925 //__________________________________________________________________
926 UShort_t
927 AliFMDParameters::GetSampleRate(UShort_t det, Char_t ring, UShort_t sector, 
928                                 UShort_t str) const
929 {
930   // 
931   // Get the sampling rate
932   // 
933   // Parameters:
934   //    detector Detector # (1-3)
935   //    ring     Ring ID ('I' or 'O')
936   //    sector   Sector number (0-39)
937   //    strip    Strip number (0-511)
938   //
939   // Return:
940   //    The sampling rate 
941   //
942   if (!fSampleRate) return fFixedSampleRate;
943   // Need to map sector to digitizier card. 
944   UInt_t ret = fSampleRate->Rate(det, ring, sector, str);
945   AliFMDDebug(50, ("Sample rate for FMD%d%c[%2d,%3d]=%d", 
946                     det, ring, sector, str, ret));
947   return ret;
948 }
949
950 //__________________________________________________________________
951 UShort_t
952 AliFMDParameters::GetMinStrip(UShort_t det, Char_t ring, UShort_t sector, 
953                               UShort_t str) const
954 {
955   // 
956   // Get the minimum strip in the read-out range
957   // 
958   // Parameters:
959   //    detector Detector # (1-3)
960   //    ring     Ring ID ('I' or 'O')
961   //    sector   Sector number (0-39)
962   //    strip    Strip number (0-511)
963   //
964   // Return:
965   //    Minimum strip 
966   //
967   if (!fStripRange) return fFixedMinStrip;
968   // Need to map sector to digitizier card. 
969   UInt_t ret = fStripRange->Min(det, ring, sector, str);
970   AliFMDDebug(50, ("Min strip # for FMD%d%c[%2d,%3d]=%d", 
971                     det, ring, sector, str, ret));
972   return ret;
973 }
974
975 //__________________________________________________________________
976 UShort_t
977 AliFMDParameters::GetMaxStrip(UShort_t det, Char_t ring, UShort_t sector, 
978                               UShort_t str) const
979 {
980   // 
981   // Get the maximum strip in the read-out range
982   // 
983   // Parameters:
984   //    detector Detector # (1-3)
985   //    ring     Ring ID ('I' or 'O')
986   //    sector   Sector number (0-39)
987   //    strip    Strip number (0-511)
988   //
989   // Return:
990   //    Maximum strip 
991   //
992   if (!fStripRange) return fFixedMaxStrip;
993   // Need to map sector to digitizier card. 
994   UInt_t ret = fStripRange->Max(det, ring, sector, str);
995   AliFMDDebug(50, ("Max strip # for FMD%d%c[%2d,%3d]=%d", 
996                     det, ring, sector, str, ret));
997   return ret;
998 }
999
1000 //__________________________________________________________________
1001 Float_t
1002 AliFMDParameters::GetPedestal(UShort_t detector, Char_t ring, 
1003                               UShort_t sector, UShort_t strip) const
1004 {
1005   // 
1006   // Get mean of pedestal
1007   // 
1008   // Parameters:
1009   //    detector Detector # (1-3)
1010   //    ring     Ring ID ('I' or 'O')
1011   //    sector   Sector number (0-39)
1012   //    strip    Strip number (0-511)
1013   //
1014   // Return:
1015   //    Mean of pedestal 
1016   //
1017   if (!fPedestal) return fFixedPedestal;
1018   AliFMDDebug(50, ("pedestal for FMD%d%c[%2d,%3d]=%f",
1019                     detector, ring, sector, strip,
1020                     fPedestal->Value(detector, ring, sector, strip)));
1021   return fPedestal->Value(detector, ring, sector, strip);
1022 }
1023
1024 //__________________________________________________________________
1025 Float_t
1026 AliFMDParameters::GetPedestalWidth(UShort_t detector, Char_t ring, 
1027                                    UShort_t sector, UShort_t strip) const
1028 {
1029   // 
1030   // Width of pedestal
1031   // 
1032   // Parameters:
1033   //    detector Detector # (1-3)
1034   //    ring     Ring ID ('I' or 'O')
1035   //    sector   Sector number (0-39)
1036   //    strip    Strip number (0-511)
1037   //
1038   // Return:
1039   //    Width of pedestal 
1040   //
1041   if (!fPedestal) return fFixedPedestalWidth;
1042   AliFMDDebug(50, ("pedetal width for FMD%d%c[%2d,%3d]=%f",
1043                     detector, ring, sector, strip,
1044                     fPedestal->Width(detector, ring, sector, strip)));
1045   return fPedestal->Width(detector, ring, sector, strip);
1046 }
1047   
1048 //__________________________________________________________________
1049 AliFMDAltroMapping*
1050 AliFMDParameters::GetAltroMap() const
1051 {
1052   // 
1053   // Get the map that translates hardware to detector coordinates 
1054   //
1055   // Return:
1056   //    Get the map that translates hardware to detector
1057   // coordinates 
1058   // 
1059   return fAltroMap;
1060 }
1061
1062
1063 //____________________________________________________________________
1064 Bool_t 
1065 AliFMDParameters::Hardware2Detector(UShort_t  ddl,       UShort_t addr,
1066                                     UShort_t  timebin,   
1067                                     UShort_t& det,       Char_t&  ring, 
1068                                     UShort_t& sec,       Short_t& str,
1069                                     UShort_t& sam) const
1070 {
1071   // 
1072   // Map a hardware address into a detector index. 
1073   // 
1074   // Parameters:
1075   //    ddl        Hardware DDL number 
1076   //    addr       Hardware address.  
1077   //    timebin    Timebin 
1078   //    det        On return, the detector #
1079   //    ring       On return, the ring ID
1080   //    sec        On return, the sector #
1081   //    str        On return, the base of strip #
1082   //    sam        On return, the sample number for this strip
1083   //
1084   // Return:
1085   //    @c true on success, false otherwise 
1086   //
1087   if (!fAltroMap) return kFALSE;
1088   UShort_t board, chip, chan;
1089   fAltroMap->ChannelAddress(addr, board, chip, chan);
1090   return Hardware2Detector(ddl,board,chip,chan,timebin,det,ring,sec,str,sam);
1091 }
1092 //____________________________________________________________________
1093 Bool_t 
1094 AliFMDParameters::Hardware2Detector(UShort_t  ddl,       UShort_t   board,
1095                                     UShort_t  chip,      UShort_t   chan,
1096                                     UShort_t  timebin,   
1097                                     UShort_t& det,       Char_t&   ring, 
1098                                     UShort_t& sec,       Short_t& str,
1099                                     UShort_t& sam) const
1100 {
1101   // 
1102   // Map a hardware address into a detector index. 
1103   // 
1104   // Parameters:
1105   //    ddl        Hardware DDL number 
1106   //    board      FEC number
1107   //    altro      ALTRO number 
1108   //    channel    Channel number 
1109   //    timebin    Timebin 
1110   //    det        On return, the detector #
1111   //    ring       On return, the ring ID
1112   //    sec        On return, the sector #
1113   //    str        On return, the base of strip #
1114   //    sam        On return, the sample number for this strip
1115   //
1116   // Return:
1117   //    @c true on success, false otherwise 
1118   //
1119   if (!fAltroMap) {
1120     AliFMDDebug(1, ("No ALTRO map available"));
1121     return kFALSE;
1122   }
1123   if (fAltroMap->DDL2Detector(ddl) < 0) { 
1124     AliFMDDebug(1, ("Invalid DDL number %d", ddl));
1125     return kFALSE;
1126   }
1127   det = fAltroMap->DDL2Detector(ddl);
1128   Short_t stripBase = 0;
1129   if (!fAltroMap->Channel2StripBase(board,chip,chan, ring, sec, stripBase)) {
1130     AliFMDDebug(1, ("Failed to translate  "
1131                     "%d/0x%02x/0x%x/0x%x/%04d -> "
1132                     "FMD%d%c[%2d,%3d] to detector", 
1133                     ddl, board, chip, chan, timebin, 
1134                     det, ring, sec, stripBase));
1135     return kFALSE;
1136   }
1137   UShort_t preSamples = GetPreSamples(det, ring, sec, stripBase);
1138   UShort_t sampleRate = GetSampleRate(det, ring, sec, stripBase);
1139   Short_t stripOff = 0;
1140   fAltroMap->Timebin2Strip(sec, timebin, preSamples, sampleRate, stripOff, sam);
1141   str = stripBase + stripOff;
1142   AliFMDDebug(50, ("%d/0x%02x/0x%x/0x%x/%04d -> FMD%d%c[%02d,%03d]-%d"
1143                   " (pre=%2d, rate=%d)", 
1144                    ddl, board, chip, chan, timebin, 
1145                    det, ring, sec, str, sam, preSamples, sampleRate));
1146   return kTRUE;
1147 }
1148
1149
1150 //____________________________________________________________________
1151 Bool_t 
1152 AliFMDParameters::Detector2Hardware(UShort_t  det,        Char_t    ring, 
1153                                     UShort_t  sec,        UShort_t  str,
1154                                     UShort_t  sam, 
1155                                     UShort_t& ddl,        UShort_t& board, 
1156                                     UShort_t& altro,      UShort_t& channel, 
1157                                     UShort_t& timebin) const
1158 {
1159   // 
1160   // Map a detector index into a hardware address. 
1161   // 
1162   // Parameters:
1163   //    det         The detector #
1164   //    ring        The ring ID
1165   //    sec         The sector #
1166   //    str         The strip #
1167   //    sam         The sample number 
1168   //    ddl         On return, hardware DDL number 
1169   //    board       On return, the FEC board address (local to DDL)
1170   //    altro       On return, the ALTRO number (local to FEC)
1171   //    channel     On return, the channel number (local to ALTRO)
1172   //    timebin     On return, the timebin number (local to ALTRO)
1173   //
1174   // Return:
1175   //    @c true on success, false otherwise 
1176   //
1177   if (!fAltroMap) { 
1178     AliFMDDebug(1, ("No ALTRO map available"));
1179     return kFALSE;
1180   }
1181   UShort_t preSamples = GetPreSamples(det, ring, sec, str);
1182   UShort_t sampleRate = GetSampleRate(det, ring, sec, str);
1183   UShort_t strip      = str - GetMinStrip(det,ring,sec,str);
1184   return fAltroMap->Detector2Hardware(det, ring, sec, strip, sam,
1185                                       preSamples, sampleRate,
1186                                       ddl, board, altro, channel, timebin);
1187 }
1188
1189   
1190
1191 //____________________________________________________________________
1192 Bool_t 
1193 AliFMDParameters::Detector2Hardware(UShort_t  det,        Char_t    ring, 
1194                                     UShort_t  sec,        UShort_t  str,
1195                                     UShort_t  sam, 
1196                                     UShort_t&   ddl,        UShort_t&   addr,
1197                                     UShort_t& timebin) const
1198 {
1199   // 
1200   // Map a detector index into a hardware address. 
1201   // 
1202   // Parameters:
1203   //    det         The detector #
1204   //    ring        The ring ID
1205   //    sec         The sector #
1206   //    str         The strip #
1207   //    sam         The sample number 
1208   //    ddl         On return, hardware DDL number 
1209   //    addr      On return, hardware address.  
1210   //    timebin     On return, the timebin number (local to ALTRO)
1211   //
1212   // Return:
1213   //    @c true on success, false otherwise 
1214   //
1215   if (!fAltroMap) return kFALSE;
1216   UShort_t preSamples = GetPreSamples(det, ring, sec, str);
1217   UShort_t sampleRate = GetSampleRate(det, ring, sec, str);
1218   UShort_t strip      = str - GetMinStrip(det,ring,sec,str);
1219   return fAltroMap->Detector2Hardware(det, ring, sec, strip, sam,
1220                                       preSamples, sampleRate,
1221                                       ddl, addr, timebin);
1222 }
1223
1224
1225 //__________________________________________________________________
1226 Float_t
1227 AliFMDParameters::GetEdepMip() const 
1228
1229   // 
1230   // Return:
1231   //    The average energy deposited by one MIP 
1232   //
1233   if (fEdepMip <= 0){
1234     AliFMDGeometry* fmd = AliFMDGeometry::Instance();
1235     fEdepMip = (fkSiDeDxMip 
1236                 * fmd->GetRing('I')->GetSiThickness() 
1237                 * fmd->GetSiDensity());
1238   }
1239   return fEdepMip;
1240 }
1241 //____________________________________________________________________
1242 Float_t  
1243 AliFMDParameters::GetDACPerMIP() const
1244 {
1245   // 
1246   // This is the conversion from Digital-to-Analog-Converter setting
1247   // to the number of MIPs. The number was measured in the NBI lab during
1248   // August 2008.
1249   //
1250   // Return:
1251   //    The conversion factor from DAC to ADC 
1252   //
1253   return 29.67;
1254   
1255 }
1256  
1257 //____________________________________________________________________
1258 //
1259 // EOF
1260 //