]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWG2/FORWARD/analysis/AliFMDAnaParameters.cxx
Adding new macro, loadFromOCDB.C, for loading magnetic field, mapping and
[u/mrichter/AliRoot.git] / PWG2 / FORWARD / analysis / AliFMDAnaParameters.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 //The design of this class is based on the AliFMDParameters class. Its purpose
17 //is to hold parameters for the analysis such as background correction and 
18 //fit functions.
19 //
20 //Author: Hans Hjersing Dalsgaard, NBI, hans.dalsgaard@cern.ch
21 //
22
23 #include "AliFMDDebug.h"                   // ALILOG_H
24 #include "AliFMDAnaParameters.h"           // ALIFMDPARAMETERS_H
25 //#include <AliCDBManager.h>         // ALICDBMANAGER_H
26 //#include <AliCDBEntry.h>           // ALICDBMANAGER_H
27 //#include "AliFMDRing.h"
28 #include <AliLog.h>
29 #include <Riostream.h>
30 #include <sstream>
31 #include <TSystem.h>
32 #include <TH2D.h>
33 #include <TF1.h>
34 #include <TMath.h>
35 #include "AliESDEvent.h"
36 #include "AliESDVertex.h"
37
38 //====================================================================
39 ClassImp(AliFMDAnaParameters)
40 #if 0
41   ; // This is here to keep Emacs for indenting the next line
42 #endif
43
44 //const char* AliFMDAnaParameters::fgkBackgroundCorrection  = "FMD/Correction/Background";
45 //const char* AliFMDAnaParameters::fgkEnergyDists = "FMD/Correction/EnergyDistribution";
46 const char* AliFMDAnaParameters::fgkBackgroundID         = "background";
47 const char* AliFMDAnaParameters::fgkEnergyDistributionID = "energydistributions";
48 const char* AliFMDAnaParameters::fgkEventSelectionEffID  = "eventselectionefficiency";
49 const char* AliFMDAnaParameters::fgkSharingEffID         = "sharingefficiency";
50 //____________________________________________________________________
51 AliFMDAnaParameters* AliFMDAnaParameters::fgInstance = 0;
52
53 //____________________________________________________________________
54
55 AliFMDAnaParameters* 
56 AliFMDAnaParameters::Instance() 
57 {
58   // Get static instance 
59   if (!fgInstance) fgInstance = new AliFMDAnaParameters;
60   return fgInstance;
61 }
62
63 //____________________________________________________________________
64 AliFMDAnaParameters::AliFMDAnaParameters() :
65   fIsInit(kFALSE),
66   fBackground(0),
67   fEnergyDistribution(0),
68   fEventSelectionEfficiency(0),
69   fCorner1(4.2231, 26.6638),
70   fCorner2(1.8357, 27.9500),
71   fEnergyPath("$ALICE_ROOT/FMD/Correction/EnergyDistribution"),
72   fBackgroundPath("$ALICE_ROOT/FMD/Correction/Background"),
73   fEventSelectionEffPath("$ALICE_ROOT/FMD/Correction/EventSelectionEfficiency"),
74   fSharingEffPath("$ALICE_ROOT/FMD/Correction/SharingEfficiency"),
75   fProcessPrimary(kFALSE),
76   fProcessHits(kFALSE),
77   fTrigger(kMB1),
78   fEnergy(k10000),
79   fMagField(k5G),
80   fSpecies(kPP)
81 {
82   
83   
84   //fVerticies.Add(new TVector2(4.2231, 26.6638));
85   // fVerticies.Add(new TVector2(1.8357, 27.9500));
86   // Default constructor 
87 }
88 //____________________________________________________________________
89 char* AliFMDAnaParameters::GetPath(const char* species) {
90   
91   char* path ;
92   
93   if(species == fgkBackgroundID)
94     path = Form("%s/%s_%d_%d_%d_%d_%d_%d.root",
95                 fBackgroundPath.Data(),
96                 fgkBackgroundID,
97                 fEnergy,
98                 fTrigger,
99                 fMagField,
100                 fSpecies,
101                 0,
102                 0);
103   if(species == fgkEnergyDistributionID)
104     path = Form("%s/%s_%d_%d_%d_%d_%d_%d.root",
105                 fEnergyPath.Data(),
106                 fgkEnergyDistributionID,
107                 fEnergy,
108                 fTrigger,
109                 fMagField,
110                 fSpecies,
111                 0,
112                 0);
113   if(species == fgkEventSelectionEffID)
114     path = Form("%s/%s_%d_%d_%d_%d_%d_%d.root",
115                 fEventSelectionEffPath.Data(),
116                 fgkEventSelectionEffID,
117                 fEnergy,
118                 fTrigger,
119                 fMagField,
120                 fSpecies,
121                 0,
122                 0);
123   if(species == fgkSharingEffID)
124     path = Form("%s/%s_%d_%d_%d_%d_%d_%d.root",
125                 fSharingEffPath.Data(),
126                 fgkSharingEffID,
127                 fEnergy,
128                 fTrigger,
129                 fMagField,
130                 fSpecies,
131                 0,
132                 0);
133
134   return path;
135 }
136 //____________________________________________________________________
137 void AliFMDAnaParameters::Init(Bool_t forceReInit, UInt_t what)
138 {
139   // Initialize the parameters manager.  We need to get stuff from the
140   // CDB here. 
141   if (forceReInit) fIsInit = kFALSE;
142   if (fIsInit) return;
143   if (what & kBackgroundCorrection)       InitBackground();
144   if (what & kEnergyDistributions)        InitEnergyDists();
145   if (what & kEventSelectionEfficiency)   InitEventSelectionEff();
146   if (what & kSharingEfficiency)          InitSharingEff();
147
148   fIsInit = kTRUE;
149 }
150 //____________________________________________________________________
151
152 void AliFMDAnaParameters::InitBackground() {
153   
154   //AliCDBEntry*   background = GetEntry(fgkBackgroundCorrection);
155   
156   TFile* fin = TFile::Open(GetPath(fgkBackgroundID));
157   
158   if (!fin) return;
159   
160   fBackground = dynamic_cast<AliFMDAnaCalibBackgroundCorrection*>(fin->Get(fgkBackgroundID));
161   if (!fBackground) AliFatal("Invalid background object from CDB");
162   
163 }
164
165 //____________________________________________________________________
166
167 void AliFMDAnaParameters::InitEnergyDists() {
168   
169   TFile* fin = TFile::Open(GetPath(fgkEnergyDistributionID));
170   //AliCDBEntry*   edist = GetEntry(fgkEnergyDists);
171   if (!fin) return;
172   
173   fEnergyDistribution = dynamic_cast<AliFMDAnaCalibEnergyDistribution*>(fin->Get(fgkEnergyDistributionID));
174   
175   if (!fEnergyDistribution) AliFatal("Invalid background object from CDB");
176   
177 }
178
179 //____________________________________________________________________
180
181 void AliFMDAnaParameters::InitEventSelectionEff() {
182   
183   //AliCDBEntry*   background = GetEntry(fgkBackgroundCorrection);
184   TFile* fin = TFile::Open(GetPath(fgkEventSelectionEffID));
185                             
186   if (!fin) return;
187   
188   fEventSelectionEfficiency = dynamic_cast<AliFMDAnaCalibEventSelectionEfficiency*>(fin->Get(fgkEventSelectionEffID));
189   if (!fEventSelectionEfficiency) AliFatal("Invalid background object from CDB");
190   
191 }
192 //____________________________________________________________________
193
194 void AliFMDAnaParameters::InitSharingEff() {
195   
196   //AliCDBEntry*   background = GetEntry(fgkBackgroundCorrection);
197   TFile* fin = TFile::Open(GetPath(fgkSharingEffID));
198                             
199   if (!fin) return;
200   
201   fSharingEfficiency = dynamic_cast<AliFMDAnaCalibSharingEfficiency*>(fin->Get(fgkSharingEffID));
202   if (!fSharingEfficiency) AliFatal("Invalid background object from CDB");
203   
204 }
205 //____________________________________________________________________
206 Float_t AliFMDAnaParameters::GetVtxCutZ() {
207   
208   if(!fIsInit) {
209     AliWarning("Not initialized yet. Call Init() to remedy");
210     return -1;
211   }
212   
213   return fBackground->GetVtxCutZ();
214 }
215
216 //____________________________________________________________________
217 Int_t AliFMDAnaParameters::GetNvtxBins() {
218   
219   if(!fIsInit) {
220     AliWarning("Not initialized yet. Call Init() to remedy");
221     return -1;
222   }
223   
224   return fBackground->GetNvtxBins();
225 }
226 //____________________________________________________________________
227 TH1F* AliFMDAnaParameters::GetEnergyDistribution(Int_t det, Char_t ring, Float_t eta) {
228   
229   return fEnergyDistribution->GetEnergyDistribution(det, ring, eta);
230 }
231 //____________________________________________________________________
232 Float_t AliFMDAnaParameters::GetSigma(Int_t det, Char_t ring, Float_t eta) {
233   
234   if(!fIsInit) {
235     AliWarning("Not initialized yet. Call Init() to remedy");
236     return 0;
237   }
238   
239   TH1F* hEnergyDist       = GetEnergyDistribution(det,ring, eta);
240   TF1*  fitFunc           = hEnergyDist->GetFunction("FMDfitFunc");
241   if(!fitFunc) {
242     AliWarning(Form("No function for FMD%d%c, eta %f",det,ring,eta));
243     return 1024;
244   }
245   Float_t sigma           = fitFunc->GetParameter(2);
246   return sigma;
247 }
248
249
250 //____________________________________________________________________
251 Float_t AliFMDAnaParameters::GetMPV(Int_t det, Char_t ring, Float_t eta) {
252   
253   if(!fIsInit) {
254     AliWarning("Not initialized yet. Call Init() to remedy");
255     return 0;
256   }
257   
258   TH1F* hEnergyDist     = GetEnergyDistribution(det,ring,eta);
259   TF1*  fitFunc         = hEnergyDist->GetFunction("FMDfitFunc");
260   if(!fitFunc) {
261     AliWarning(Form("No function for FMD%d%c, eta %f",det,ring,eta));
262     return 1024;
263   }
264     
265   Float_t mpv           = fitFunc->GetParameter(1);
266   return mpv;
267 }
268 //____________________________________________________________________
269 Float_t AliFMDAnaParameters::Get2MIPWeight(Int_t det, Char_t ring, Float_t eta) {
270   
271   if(!fIsInit) {
272     AliWarning("Not initialized yet. Call Init() to remedy");
273     return 0;
274   }
275   
276   TH1F* hEnergyDist     = GetEnergyDistribution(det,ring,eta);
277   TF1*  fitFunc         = hEnergyDist->GetFunction("FMDfitFunc");
278   if(!fitFunc) return 0;
279   Float_t twoMIPweight    = fitFunc->GetParameter(3);
280   
281   
282   
283   if(twoMIPweight < 1e-05)
284     twoMIPweight = 0;
285   
286   return twoMIPweight;
287 }
288 //____________________________________________________________________
289 Float_t AliFMDAnaParameters::Get3MIPWeight(Int_t det, Char_t ring, Float_t eta) {
290   
291   if(!fIsInit) {
292     AliWarning("Not initialized yet. Call Init() to remedy");
293     return 0;
294   }
295   
296   TH1F* hEnergyDist     = GetEnergyDistribution(det,ring,eta);
297   TF1*  fitFunc         = hEnergyDist->GetFunction("FMDfitFunc");
298   if(!fitFunc) return 0;
299   Float_t threeMIPweight    = fitFunc->GetParameter(4);
300   
301   if(threeMIPweight < 1e-05)
302     threeMIPweight = 0;
303   
304   Float_t twoMIPweight    = fitFunc->GetParameter(3);
305   
306   if(twoMIPweight < 1e-05)
307     threeMIPweight = 0;
308     
309   return threeMIPweight;
310 }
311 //____________________________________________________________________
312 Int_t AliFMDAnaParameters::GetNetaBins() {
313   return GetBackgroundCorrection(1,'I',0)->GetNbinsX();
314   
315 }
316 //____________________________________________________________________
317 Float_t AliFMDAnaParameters::GetEtaMin() {
318
319   return GetBackgroundCorrection(1,'I',0)->GetXaxis()->GetXmin();
320
321 //____________________________________________________________________
322 Float_t AliFMDAnaParameters::GetEtaMax() {
323
324 return GetBackgroundCorrection(1,'I',0)->GetXaxis()->GetXmax();
325
326 }
327 //____________________________________________________________________
328
329 TH2F* AliFMDAnaParameters::GetBackgroundCorrection(Int_t det, 
330                                                    Char_t ring, 
331                                                    Int_t vtxbin) {
332   
333   if(!fIsInit) {
334     AliWarning("Not initialized yet. Call Init() to remedy");
335     return 0;
336   }
337   
338   
339   
340   if(vtxbin > fBackground->GetNvtxBins()) {
341     AliWarning(Form("No background object for vertex bin %d", vtxbin));
342     return 0;
343   } 
344   
345   return fBackground->GetBgCorrection(det,ring,vtxbin);
346 }
347 //____________________________________________________________________
348
349 TH1F* AliFMDAnaParameters::GetDoubleHitCorrection(Int_t det, 
350                                                   Char_t ring) {
351   
352   if(!fIsInit) {
353     AliWarning("Not initialized yet. Call Init() to remedy");
354     return 0;
355   }
356   
357   return fBackground->GetDoubleHitCorrection(det,ring);
358 }
359 //_____________________________________________________________________
360 Float_t AliFMDAnaParameters::GetEventSelectionEfficiency(Int_t vtxbin) {
361   if(!fIsInit) {
362     AliWarning("Not initialized yet. Call Init() to remedy");
363     return 0;
364   }
365   return fEventSelectionEfficiency->GetCorrection(vtxbin);
366
367 }
368 //_____________________________________________________________________
369 TH1F* AliFMDAnaParameters::GetSharingEfficiency(Int_t det, Char_t ring, Int_t vtxbin) {
370   if(!fIsInit) {
371     AliWarning("Not initialized yet. Call Init() to remedy");
372     return 0;
373   }
374   
375   return fSharingEfficiency->GetSharingEff(det,ring,vtxbin);
376
377 }
378 //_____________________________________________________________________
379 TH1F* AliFMDAnaParameters::GetSharingEfficiencyTrVtx(Int_t det, Char_t ring, Int_t vtxbin) {
380   if(!fIsInit) {
381     AliWarning("Not initialized yet. Call Init() to remedy");
382     return 0;
383   }
384   
385   return fSharingEfficiency->GetSharingEffTrVtx(det,ring,vtxbin);
386
387 }
388 //_____________________________________________________________________
389 Float_t AliFMDAnaParameters::GetMaxR(Char_t ring) const{
390   Float_t radius = 0;
391   if(ring == 'I')
392     radius = 17.2;
393   else if(ring == 'O')
394     radius = 28.0;
395   else
396     AliWarning("Unknown ring - must be I or O!");
397   
398   return radius;
399 }
400 //_____________________________________________________________________
401 Float_t AliFMDAnaParameters::GetMinR(Char_t ring) const{
402   Float_t radius = 0;
403   if(ring == 'I')
404     radius = 4.5213;
405   else if(ring == 'O')
406     radius = 15.4;
407   else
408     AliWarning("Unknown ring - must be I or O!");
409   
410   return radius;
411
412 }
413 //_____________________________________________________________________
414 void AliFMDAnaParameters::SetCorners(Char_t ring) {
415   
416   if(ring == 'I') {
417     fCorner1.Set(4.9895, 15.3560);
418     fCorner2.Set(1.8007, 17.2000);
419   }
420   else {
421     fCorner1.Set(4.2231, 26.6638);
422     fCorner2.Set(1.8357, 27.9500);
423   }
424   
425 }
426 //_____________________________________________________________________
427 Float_t AliFMDAnaParameters::GetPhiFromSector(UShort_t det, Char_t ring, UShort_t sec) const
428 {
429   Int_t nsec = (ring == 'I' ? 20 : 40);
430   Float_t basephi = 0;
431   if(det == 1) 
432     basephi = 1.72787594; 
433   if(det == 2 && ring == 'I')
434     basephi = 0.15707963;
435   if(det == 2 && ring == 'O')
436     basephi = 0.078539818;
437   if(det == 3 && ring == 'I')
438     basephi = 2.984513044;
439   if(det == 3 && ring == 'O')
440     basephi = 3.06305289;
441   
442   Float_t step = 2*TMath::Pi() / nsec;
443   Float_t phi = 0;
444   if(det == 3)
445     phi = basephi - sec*step;
446   else
447     phi = basephi + sec*step;
448   
449   if(phi < 0) 
450     phi = phi +2*TMath::Pi();
451   if(phi > 2*TMath::Pi() )
452     phi = phi - 2*TMath::Pi();
453   
454   return phi;
455 }
456 //_____________________________________________________________________
457 Float_t AliFMDAnaParameters::GetEtaFromStrip(UShort_t det, Char_t ring, UShort_t sec, UShort_t strip, Float_t zvtx) const
458 {
459   // AliFMDRing fmdring(ring);
460   // fmdring.Init();
461   Float_t   rad       = GetMaxR(ring)-GetMinR(ring);
462   Float_t   nStrips   = (ring == 'I' ? 512 : 256);
463   Float_t   segment   = rad / nStrips;
464   Float_t   r         = GetMinR(ring) + segment*strip;
465   Float_t   z         = 0;
466   Int_t hybrid = sec / 2;
467   
468   if(det == 1) {
469     if(!(hybrid%2)) z = 320.266; else z = 319.766;
470   }
471   if(det == 2 && ring == 'I' ) {
472     if(!(hybrid%2)) z = 83.666; else z = 83.166;
473   }
474   if(det == 2 && ring == 'O' ) {
475     if(!(hybrid%2)) z = 74.966; else z = 75.466;
476   }
477   if(det == 3 && ring == 'I' ) {
478     if(!(hybrid%2)) z = -63.066; else z = -62.566;
479   }
480   if(det == 3 && ring == 'O' ) {
481     if(!(hybrid%2)) z = -74.966; else z = -75.466;
482   }
483   
484   //std::cout<<det<<"   "<<ring<<"   "<<sec<<"   "<<hybrid<<"    "<<z<<std::endl;
485   
486   // Float_t   r     = TMath::Sqrt(TMath::Power(x,2)+TMath::Power(y,2));
487   Float_t   theta = TMath::ATan2(r,z-zvtx);
488   Float_t   eta   = -1*TMath::Log(TMath::Tan(0.5*theta));
489   
490   return eta;
491 }
492
493 //_____________________________________________________________________
494
495 void AliFMDAnaParameters::GetVertex(AliESDEvent* esd, Double_t* vertexXYZ) 
496 {
497   const AliESDVertex* vertex = 0;
498   vertex = esd->GetPrimaryVertex();
499   if(!vertex || (vertexXYZ[0] == 0 && vertexXYZ[1] == 0 && vertexXYZ[2] == 0))        
500     vertex = esd->GetPrimaryVertexSPD();
501   if(!vertex || (vertexXYZ[0] == 0 && vertexXYZ[1] == 0 && vertexXYZ[2] == 0))        
502     vertex = esd->GetPrimaryVertexTPC();
503   if(!vertex || (vertexXYZ[0] == 0 && vertexXYZ[1] == 0 && vertexXYZ[2] == 0))    
504     vertex = esd->GetVertex();
505   if (vertex && (vertexXYZ[0] != 0 || vertexXYZ[1] != 0 || vertexXYZ[2] != 0)) {
506     vertex->GetXYZ(vertexXYZ);
507     //std::cout<<vertex->GetName()<<"   "<< vertex->GetTitle() <<"   "<< vertex->GetZv()<<std::endl;
508     return;
509   }
510   else if (esd->GetESDTZERO()) { 
511     vertexXYZ[0] = 0;
512     vertexXYZ[1] = 0;
513     vertexXYZ[2] = esd->GetT0zVertex();
514     
515     return;
516   }
517   
518   return;
519   
520 }
521
522 //____________________________________________________________________
523 Bool_t AliFMDAnaParameters::IsEventTriggered(AliESDEvent *esd) {
524   // check if the event was triggered
525   ULong64_t triggerMask = esd->GetTriggerMask();
526   
527   // definitions from p-p.cfg
528   ULong64_t spdFO = (1 << 14);
529   ULong64_t v0left = (1 << 11);
530   ULong64_t v0right = (1 << 12);
531   
532   switch (fTrigger) {
533   case kMB1: {
534     if (triggerMask & spdFO || ((triggerMask & v0left) || (triggerMask & v0right)))
535       return kTRUE;
536     break;
537   }
538   case kMB2: {
539     if (triggerMask & spdFO && ((triggerMask & v0left) || (triggerMask & v0right)))
540       return kTRUE;
541     break;
542   }
543   case kSPDFASTOR: {
544     if (triggerMask & spdFO)
545       return kTRUE;
546     break;
547   }
548   case kTEST_NOCTP: {
549     return kTRUE;
550     break;
551   }
552   }//switch
553
554   return kFALSE;
555 }
556
557 //____________________________________________________________________
558 Float_t 
559 AliFMDAnaParameters::GetStripLength(Char_t ring, UShort_t strip)  
560 {
561   //AliFMDRing fmdring(ring);
562   // fmdring.Init();
563   
564   Float_t rad        = GetMaxR(ring)-GetMinR(ring);
565   Float_t   nStrips   = (ring == 'I' ? 512 : 256);
566   Float_t segment    = rad / nStrips;
567   
568   //TVector2* corner1  = fmdring.GetVertex(2);  
569   // TVector2* corner2  = fmdring.GetVertex(3);
570   
571   SetCorners(ring);
572   /*
573   std::cout<<GetMaxR(ring)<<"   "<<fmdring.GetMaxR()<<std::endl;
574   std::cout<<GetMinR(ring)<<"   "<<fmdring.GetMinR()<<std::endl;
575   std::cout<<corner1->X()<<"   "<<fCorner1.X()<<std::endl;
576   std::cout<<corner2->X()<<"   "<<fCorner2.X()<<std::endl;
577   std::cout<<corner1->Y()<<"   "<<fCorner1.Y()<<std::endl;
578   std::cout<<corner2->Y()<<"   "<<fCorner2.Y()<<std::endl;*/
579   Float_t slope      = (fCorner1.Y() - fCorner2.Y()) / (fCorner1.X() - fCorner2.X());
580   Float_t constant   = (fCorner2.Y()*fCorner1.X()-(fCorner2.X()*fCorner1.Y())) / (fCorner1.X() - fCorner2.X());
581   Float_t radius     = GetMinR(ring) + strip*segment;
582   
583   Float_t d          = TMath::Power(TMath::Abs(radius*slope),2) + TMath::Power(radius,2) - TMath::Power(constant,2);
584   
585   Float_t arclength  = GetBaseStripLength(ring,strip);
586   if(d>0) {
587     
588     Float_t x        = (-1*TMath::Sqrt(d) -slope*constant) / (1+TMath::Power(slope,2));
589     Float_t y        = slope*x + constant;
590     Float_t theta    = TMath::ATan2(x,y);
591     
592     if(x < fCorner1.X() && y > fCorner1.Y()) {
593       arclength = radius*theta;                        //One sector since theta is by definition half-hybrid
594       
595     }
596     
597   }
598   
599   return arclength;
600   
601   
602 }
603 //____________________________________________________________________
604 Float_t 
605 AliFMDAnaParameters::GetBaseStripLength(Char_t ring, UShort_t strip)  
606 {  
607   // AliFMDRing fmdring(ring);
608   // fmdring.Init();
609   Float_t rad             = GetMaxR(ring)-GetMinR(ring);
610   Float_t nStrips         = (ring == 'I' ? 512 : 256);
611   Float_t nSec            = (ring == 'I' ? 20 : 40);
612   Float_t segment         = rad / nStrips;
613   Float_t basearc         = 2*TMath::Pi() / (0.5*nSec); // One hybrid: 36 degrees inner, 18 outer
614   Float_t radius          = GetMinR(ring) + strip*segment;
615   Float_t basearclength   = 0.5*basearc * radius;                // One sector   
616   
617   return basearclength;
618 }
619 //____________________________________________________________________
620 //
621 // EOF
622 //