]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWG2/FORWARD/analysis2/AliFMDEventInspector.cxx
Various upgrades. NSD true trigger for MC, pileup selection for analysis, fixes for...
[u/mrichter/AliRoot.git] / PWG2 / FORWARD / analysis2 / AliFMDEventInspector.cxx
1 // 
2 // This class inspects the event 
3 //
4 // Input:
5 //   - AliESDFMD object possibly corrected for sharing
6 //
7 // Output:
8 //   - A histogram of v_z of events with triggers. 
9 //   - A histogram of v_z of events with vertex and triggers 
10 //   - A histogram of trigger counters 
11 // 
12 // Note, that these are added to the master output list 
13 //
14 // Corrections used: 
15 //   - None
16 //
17 #include "AliFMDEventInspector.h"
18 #include "AliLog.h"
19 #include "AliESDEvent.h"
20 #include "AliMultiplicity.h"
21 #include "AliAnalysisManager.h"
22 #include "AliInputEventHandler.h"
23 #include "AliTriggerAnalysis.h"
24 #include "AliPhysicsSelection.h"
25 #include "AliAODForwardMult.h"
26 #include "AliForwardUtil.h"
27 #include "AliCentrality.h"
28 #include <TH1.h>
29 #include <TList.h>
30 #include <TDirectory.h>
31 #include <TROOT.h>
32 #include <iostream>
33 #include <iomanip>
34 #include "AliMCEvent.h"
35 #include "AliGenPythiaEventHeader.h"
36 #include "AliGenDPMjetEventHeader.h"
37 #include "AliHeader.h"
38 #include "AliMCEventHandler.h"
39 //====================================================================
40 AliFMDEventInspector::AliFMDEventInspector()
41   : TNamed(),
42     fHEventsTr(0), 
43     fHEventsTrVtx(0),
44     fHTriggers(0),
45     fHType(0),
46     fHWords(0),
47     fHCent(0),
48     fLowFluxCut(1000),
49     fMaxVzErr(0.1),
50     fList(0),
51     fEnergy(0),
52     fField(999), 
53     fCollisionSystem(kUnknown),
54     fDebug(0)
55 {
56   // 
57   // Constructor 
58   //
59 }
60
61 //____________________________________________________________________
62 AliFMDEventInspector::AliFMDEventInspector(const char* name)
63   : TNamed("fmdEventInspector", name),
64     fHEventsTr(0), 
65     fHEventsTrVtx(0), 
66     fHTriggers(0),
67     fHType(0),
68     fHWords(0),
69     fHCent(0),
70     fLowFluxCut(1000),
71     fMaxVzErr(0.1),
72     fList(0),
73     fEnergy(0),
74     fField(999), 
75     fCollisionSystem(kUnknown),
76     fDebug(0)
77 {
78   // 
79   // Constructor 
80   // 
81   // Parameters:
82   //   name Name of object
83   //
84 }
85
86 //____________________________________________________________________
87 AliFMDEventInspector::AliFMDEventInspector(const AliFMDEventInspector& o)
88   : TNamed(o), 
89     fHEventsTr(o.fHEventsTr), 
90     fHEventsTrVtx(o.fHEventsTrVtx), 
91     fHTriggers(o.fHTriggers),
92     fHType(o.fHType),
93     fHWords(o.fHWords),
94     fHCent(o.fHCent),
95     fLowFluxCut(o.fLowFluxCut),
96     fMaxVzErr(o.fMaxVzErr),
97     fList(o.fList),
98     fEnergy(o.fEnergy),
99     fField(o.fField), 
100     fCollisionSystem(o.fCollisionSystem),
101     fDebug(0)
102 {
103   // 
104   // Copy constructor 
105   // 
106   // Parameters:
107   //   o Object to copy from 
108   //
109 }
110
111 //____________________________________________________________________
112 AliFMDEventInspector::~AliFMDEventInspector()
113 {
114   // 
115   // Destructor 
116   //
117   if (fHEventsTr)    delete fHEventsTr;
118   if (fHEventsTrVtx) delete fHEventsTrVtx;
119   if (fHTriggers)    delete fHTriggers;  
120   if (fHType)        delete fHType;
121   if (fHWords)       delete fHWords;
122   if (fHCent)        delete fHCent;
123   if (fList)         delete fList;
124 }
125 //____________________________________________________________________
126 AliFMDEventInspector&
127 AliFMDEventInspector::operator=(const AliFMDEventInspector& o)
128 {
129   // 
130   // Assignement operator
131   // 
132   // Parameters:
133   //   o Object to assign from 
134   // 
135   // Return:
136   //    Reference to this object
137   //
138   TNamed::operator=(o);
139   fHEventsTr         = o.fHEventsTr;
140   fHEventsTrVtx      = o.fHEventsTrVtx;
141   fHTriggers         = o.fHTriggers;
142   fHType             = o.fHType;
143   fHWords            = o.fHWords;
144   fHCent             = o.fHCent;
145   fLowFluxCut        = o.fLowFluxCut;
146   fMaxVzErr          = o.fMaxVzErr;
147   fDebug             = o.fDebug;
148   fList              = (o.fList ? new TList : 0);
149   fEnergy            = o.fEnergy;
150   fField             = o.fField;
151   fCollisionSystem   = o.fCollisionSystem;
152   if (fList) { 
153     fList->SetName(GetName());
154     if (fHEventsTr)    fList->Add(fHEventsTr);
155     if (fHEventsTrVtx) fList->Add(fHEventsTrVtx);
156     if (fHTriggers)    fList->Add(fHTriggers);
157     if (fHType)        fList->Add(fHType);
158     if (fHWords)       fList->Add(fHWords);
159     if (fHCent)        fList->Add(fHCent);
160   }
161   return *this;
162 }
163
164 //____________________________________________________________________
165 Bool_t
166 AliFMDEventInspector::FetchHistograms(TList* d, 
167                                       TH1I*& hEventsTr, 
168                                       TH1I*& hEventsTrVtx, 
169                                       TH1I*& hTriggers) const
170 {
171   // 
172   // Fetch our histograms from the passed list 
173   // 
174   // Parameters:
175   //   d             Input
176   //   hEventsTr     On return, pointer to histogram, or null
177   //   hEventsTrVtx  On return, pointer to histogram, or null
178   //   hTriggers     On return, pointer to histogram, or null
179   // 
180   // Return:
181   //    true on success, false otherwise 
182   //
183   hEventsTr    = 0;
184   hEventsTrVtx = 0;
185   hTriggers    = 0;
186   TList* dd    = dynamic_cast<TList*>(d->FindObject(GetName()));
187   if (!dd) return kFALSE;
188   
189   hEventsTr    = dynamic_cast<TH1I*>(dd->FindObject("nEventsTr"));
190   hEventsTrVtx = dynamic_cast<TH1I*>(dd->FindObject("nEventsTrVtx"));
191   hTriggers    = dynamic_cast<TH1I*>(dd->FindObject("triggers"));
192
193   if (!hEventsTr || !hEventsTrVtx || !hTriggers) return kFALSE;
194   return kTRUE;
195 }
196 //____________________________________________________________________
197 void
198 AliFMDEventInspector::Init(const TAxis& vtxAxis)
199 {
200   // 
201   // Initialize the object 
202   // 
203   // Parameters:
204   //   vtxAxis Vertex axis in use 
205   //
206   fHEventsTr = new TH1I("nEventsTr", "Number of events w/trigger", 
207                         vtxAxis.GetNbins(), 
208                         vtxAxis.GetXmin(), 
209                         vtxAxis.GetXmax());
210   fHEventsTr->SetXTitle("v_{z} [cm]");
211   fHEventsTr->SetYTitle("# of events");
212   fHEventsTr->SetFillColor(kRed+1);
213   fHEventsTr->SetFillStyle(3001);
214   fHEventsTr->SetDirectory(0);
215   // fHEventsTr->Sumw2();
216   fList->Add(fHEventsTr);
217
218   fHEventsTrVtx = new TH1I("nEventsTrVtx", 
219                            "Number of events w/trigger and vertex", 
220                            vtxAxis.GetNbins(), 
221                            vtxAxis.GetXmin(), 
222                            vtxAxis.GetXmax());
223   fHEventsTrVtx->SetXTitle("v_{z} [cm]");
224   fHEventsTrVtx->SetYTitle("# of events");
225   fHEventsTrVtx->SetFillColor(kBlue+1);
226   fHEventsTrVtx->SetFillStyle(3001);
227   fHEventsTrVtx->SetDirectory(0);
228   // fHEventsTrVtx->Sumw2();
229   fList->Add(fHEventsTrVtx);
230
231       
232   fHTriggers = new TH1I("triggers", "Triggers", 10, 0, 10);
233   fHTriggers->SetFillColor(kRed+1);
234   fHTriggers->SetFillStyle(3001);
235   fHTriggers->SetStats(0);
236   fHTriggers->SetDirectory(0);
237   fHTriggers->GetXaxis()->SetBinLabel(kInel   +1,"INEL");
238   fHTriggers->GetXaxis()->SetBinLabel(kInelGt0+1,"INEL>0");
239   fHTriggers->GetXaxis()->SetBinLabel(kNSD    +1,"NSD");
240   fHTriggers->GetXaxis()->SetBinLabel(kEmpty  +1,"Empty");
241   fHTriggers->GetXaxis()->SetBinLabel(kA      +1,"A");
242   fHTriggers->GetXaxis()->SetBinLabel(kB      +1,"B");
243   fHTriggers->GetXaxis()->SetBinLabel(kC      +1,"C");
244   fHTriggers->GetXaxis()->SetBinLabel(kE      +1,"E");
245   fHTriggers->GetXaxis()->SetBinLabel(kPileUp +1,"Pileup");
246   fHTriggers->GetXaxis()->SetBinLabel(kMCNSD  +1,"nsd");
247   fList->Add(fHTriggers);
248
249   fHType = new TH1I("type", Form("Event type (cut: SPD mult>%d)", 
250                                  fLowFluxCut), 2, -.5, 1.5);
251   fHType->SetFillColor(kRed+1);
252   fHType->SetFillStyle(3001);
253   fHType->SetStats(0);
254   fHType->SetDirectory(0);
255   fHType->GetXaxis()->SetBinLabel(1,"Low-flux");
256   fHType->GetXaxis()->SetBinLabel(2,"High-flux");
257   fList->Add(fHType);
258
259
260   fHWords = new TH1I("words", "Trigger words seen", 1, 0, 0); 
261   fHWords->SetFillColor(kBlue+1);
262   fHWords->SetFillStyle(3001);
263   fHWords->SetStats(0);
264   fHWords->SetDirectory(0);
265   fHWords->SetBit(TH1::kCanRebin);
266   fList->Add(fHWords);
267
268   fHCent = new TH1F("cent", "Centrality", 101, -1.5, 100.5);
269   fHCent->SetFillColor(kBlue+1);
270   fHCent->SetFillStyle(3001);
271   fHCent->SetStats(0);
272   fHCent->SetDirectory(0);
273   fHCent->SetXTitle("Centrality [%]");
274   fHCent->SetYTitle("Events");
275   fList->Add(fHCent);
276 }
277
278 //____________________________________________________________________
279 void
280 AliFMDEventInspector::DefineOutput(TList* dir)
281 {
282   // 
283   // Define the output histograms.  These are put in a sub list of the
284   // passed list.   The histograms are merged before the parent task calls 
285   // AliAnalysisTaskSE::Terminate 
286   // 
287   //   dir Directory to add to 
288   //
289   fList = new TList;
290   fList->SetName(GetName());
291   dir->Add(fList);
292 }
293
294 //____________________________________________________________________
295 UInt_t
296 AliFMDEventInspector::Process(const AliESDEvent* event, 
297                               UInt_t&            triggers,
298                               Bool_t&            lowFlux,
299                               UShort_t&          ivz, 
300                               Double_t&          vz,
301                               Double_t&          cent)
302 {
303   // 
304   // Process the event 
305   // 
306   // Parameters:
307   //   event     Input event 
308   //   triggers  On return, the triggers fired 
309   //   lowFlux   On return, true if the event is considered a low-flux 
310   //                  event (according to the setting of fLowFluxCut) 
311   //   ivz       On return, the found vertex bin (1-based).  A zero
312   //                  means outside of the defined vertex range
313   //   vz        On return, the z position of the interaction
314   //   cent      On return, the centrality - if not available < 0
315   // 
316   // Return:
317   //    0 (or kOk) on success, otherwise a bit mask of error codes 
318   //
319
320   // Check that we have an event 
321   if (!event) { 
322     AliWarning("No ESD event found for input event");
323     return kNoEvent;
324   }
325
326   // Read trigger information from the ESD and store in AOD object
327   if (!ReadTriggers(event, triggers)) { 
328     if (fDebug > 2) {
329       AliWarning("Failed to read triggers from ESD"); }
330     return kNoTriggers;
331   }
332
333   // Check if this is a high-flux event 
334   const AliMultiplicity* testmult = event->GetMultiplicity();
335   if (!testmult) {
336     if (fDebug > 3) {
337       AliWarning("No central multiplicity object found"); }
338     return kNoSPD;
339   }
340   lowFlux = testmult->GetNumberOfTracklets() < fLowFluxCut;
341
342   fHType->Fill(lowFlux ? 0 : 1);
343   
344   cent = -10;
345   AliCentrality* centObj = const_cast<AliESDEvent*>(event)->GetCentrality();
346   if (centObj) {
347     AliInfo(Form("Got centrality object %p with quality %d", centObj, centObj->GetQuality()));
348     centObj->Print();
349     cent = centObj->GetCentralityPercentileUnchecked("V0M");  
350   }
351   AliInfo(Form("Centrality is %f", cent));
352   fHCent->Fill(cent);
353
354   // Check the FMD ESD data 
355   if (!event->GetFMDData()) { 
356     if (fDebug > 3) {
357       AliWarning("No FMD data found in ESD"); }
358     return kNoFMD;
359   }
360
361   // Get the vertex information 
362   vz          = 0;
363   Bool_t vzOk = ReadVertex(event, vz);
364
365   fHEventsTr->Fill(vz);
366   if (!vzOk) { 
367     if (fDebug > 3) {
368       AliWarning("Failed to read vertex from ESD"); }
369     return kNoVertex;
370   }
371   fHEventsTrVtx->Fill(vz);
372
373   // Get the vertex bin 
374   ivz = fHEventsTr->GetXaxis()->FindBin(vz);
375   if (ivz <= 0 || ivz > fHEventsTr->GetXaxis()->GetNbins()) { 
376     if (fDebug > 3) {
377       AliWarning(Form("Vertex @ %f outside of range [%f,%f]", 
378                       vz, fHEventsTr->GetXaxis()->GetXmin(), 
379                       fHEventsTr->GetXaxis()->GetXmax())); }
380     ivz = 0;
381     return kBadVertex;
382   }
383   
384   
385   return kOk;
386 }
387
388 //____________________________________________________________________
389 Bool_t
390 AliFMDEventInspector::ReadTriggers(const AliESDEvent* esd, UInt_t& triggers)
391 {
392   // 
393   // Read the trigger information from the ESD event 
394   // 
395   // Parameters:
396   //   esd        ESD event 
397   //   triggers   On return, contains the trigger bits 
398   // 
399   // Return:
400   //    @c true on success, @c false otherwise 
401   //
402   triggers = 0;
403
404   // Get the analysis manager - should always be there 
405   AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
406   if (!am) { 
407     AliWarning("No analysis manager defined!");
408     return kFALSE;
409   }
410
411   // Get the input handler - should always be there 
412   AliInputEventHandler* ih = 
413     static_cast<AliInputEventHandler*>(am->GetInputEventHandler());
414   if (!ih) { 
415     AliWarning("No input handler");
416     return kFALSE;
417   }
418   
419   AliMCEventHandler* mcHandler = dynamic_cast<AliMCEventHandler*> (AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler());
420   AliMCEvent* mcEvent = 0;
421   if(mcHandler)
422     mcEvent = mcHandler->MCEvent();
423   
424   if(mcEvent) {
425     //Assign MC only triggers : True NSD etc.
426     AliHeader* header            = mcEvent->Header();
427     AliGenEventHeader* genHeader = header->GenEventHeader();
428     
429     AliGenPythiaEventHeader* pythiaGenHeader = dynamic_cast<AliGenPythiaEventHeader*>(genHeader);
430     AliGenDPMjetEventHeader* dpmHeader = dynamic_cast<AliGenDPMjetEventHeader*>(header->GenEventHeader());
431     Bool_t sd = kFALSE;
432     if(pythiaGenHeader) {
433       Int_t pythiaType = pythiaGenHeader->ProcessType();
434       if(pythiaType==92 || pythiaType==93)
435         sd = kTRUE;
436     }
437     if(dpmHeader) {
438       Int_t processType = dpmHeader->ProcessType();
439       if(processType == 5 || processType == 6)  
440         sd = kTRUE;
441       
442     }
443     if(!sd) {
444       triggers |= AliAODForwardMult::kMCNSD;
445       fHTriggers->Fill(kMCNSD+0.5);
446     }
447     
448   }
449     
450   // Check if this is a collision candidate (INEL)
451   // Note, that we should use the value cached in the input 
452   // handler rather than calling IsCollisionCandiate directly 
453   // on the AliPhysicsSelection obejct.  If we called the latter
454   // then the AliPhysicsSelection object would overcount by a 
455   // factor of 2! :-(
456   Bool_t inel = ih->IsEventSelected();
457   if (inel) { 
458     triggers |= AliAODForwardMult::kInel;
459     fHTriggers->Fill(kInel+0.5);
460   }
461
462   // If this is inel, see if we have a tracklet 
463   if (inel) { 
464     const AliMultiplicity* spdmult = esd->GetMultiplicity();
465     if (!spdmult) {
466       AliWarning("No SPD multiplicity");
467     }
468     else { 
469       // Check if we have one or more tracklets 
470       // in the range -1 < eta < 1 to set the INEL>0 
471       // trigger flag. 
472       Int_t n = spdmult->GetNumberOfTracklets();
473       for (Int_t j = 0; j < n; j++) { 
474         if(TMath::Abs(spdmult->GetEta(j)) < 1) { 
475           triggers |= AliAODForwardMult::kInelGt0;
476           fHTriggers->Fill(kInelGt0+.5);
477           break;
478         }
479       }
480     }
481   }
482
483   // Analyse some trigger stuff 
484   AliTriggerAnalysis ta;
485   if (ta.IsOfflineTriggerFired(esd, AliTriggerAnalysis::kNSD1)) {
486     triggers |= AliAODForwardMult::kNSD;
487     fHTriggers->Fill(kNSD+.5);
488   }
489   //Check pileup
490   Bool_t pileup =  esd->IsPileupFromSPD(3,0.8);
491   if (pileup) {
492     triggers |= AliAODForwardMult::kPileUp;
493     fHTriggers->Fill(kPileUp+.5);
494   }
495     
496   // Get trigger stuff 
497   TString trigStr = esd->GetFiredTriggerClasses();
498   // AliWarning(Form("Fired trigger classes: %s", trigStr.Data()));
499   fHWords->Fill(trigStr.Data(), 1);
500 #if 0
501   if (trigStr.Contains("MB1") || trigStr.Contains("MBBG3"))
502       triggers |= AliAOODForwardMult::kB;
503   if (trigStr.Contains("COTA")) 
504     triggers |= AliAODForwardMult::kA;
505   if (trigStr.Contains("COTC")) 
506     triggers |= AliAODForwardMult::kC;
507 #endif
508   if (trigStr.Contains("CBEAMB-ABCE-NOPF-ALL")) {
509     triggers |= AliAODForwardMult::kEmpty;
510     fHTriggers->Fill(kEmpty+.5);
511   }
512
513   if (trigStr.Contains("CINT1A-ABCE-NOPF-ALL")) {
514     triggers |= AliAODForwardMult::kA;
515     fHTriggers->Fill(kA+.5);
516   }
517
518   if (trigStr.Contains("CINT1B-ABCE-NOPF-ALL")) {
519     triggers |= AliAODForwardMult::kB;
520     fHTriggers->Fill(kB+.5);
521   }
522
523
524   if (trigStr.Contains("CINT1C-ABCE-NOPF-ALL")) {
525     triggers |= AliAODForwardMult::kC;
526     fHTriggers->Fill(kC+.5);
527   }
528
529   if (trigStr.Contains("CINT1-E-NOPF-ALL")) {
530     triggers |= AliAODForwardMult::kE;
531     fHTriggers->Fill(kE+.5);
532   }
533
534   return kTRUE;
535 }
536 //____________________________________________________________________
537 Bool_t
538 AliFMDEventInspector::ReadVertex(const AliESDEvent* esd, Double_t& vz)
539 {
540   // 
541   // Read the vertex information from the ESD event 
542   // 
543   // Parameters:
544   //   esd  ESD event 
545   //   vz   On return, the vertex Z position 
546   // 
547   // Return:
548   //    @c true on success, @c false otherwise 
549   //
550   vz = 0;
551   // Get the vertex 
552   const AliESDVertex* vertex = esd->GetPrimaryVertexSPD();
553   if (!vertex) { 
554     if (fDebug > 2) {
555       AliWarning("No SPD vertex found in ESD"); }
556     return kFALSE;
557   }
558   
559   // Check that enough tracklets contributed 
560   if(vertex->GetNContributors() <= 0) {
561     if (fDebug > 2) {
562       AliWarning(Form("Number of contributors to vertex is %d<=0",
563                       vertex->GetNContributors())); }
564     vz = 0;
565     return kFALSE;
566   }
567
568   // Check that the uncertainty isn't too large 
569   if (vertex->GetZRes() > fMaxVzErr) { 
570     if (fDebug > 2) {
571       AliWarning(Form("Uncertaintity in Z of vertex is too large %f > %f", 
572                       vertex->GetZRes(), fMaxVzErr)); }
573     return kFALSE;
574   }
575
576   // HHD test
577   /*
578   if (vertex->IsFromVertexerZ()) { 
579     return kFALSE;
580   }
581   if (TMath::Sqrt(TMath::Power(vertex->GetX(),2) + TMath::Power(vertex->GetY(),2)) > 3 ) { 
582       return kFALSE;
583   }
584   */
585   
586   // Get the z coordiante 
587   vz = vertex->GetZ();
588   return kTRUE;
589 }
590
591 //____________________________________________________________________
592 Bool_t
593 AliFMDEventInspector::ReadRunDetails(const AliESDEvent* esd)
594 {
595   // 
596   // Read the collision system, collision energy, and L3 field setting
597   // from the ESD
598   // 
599   // Parameters:
600   //   esd ESD to get information from 
601   // 
602   // Return:
603   //    true on success, false 
604   //
605   // AliInfo(Form("Parameters from 1st ESD event: cms=%s, sNN=%f, field=%f",
606   //           esd->GetBeamType(), 2*esd->GetBeamEnergy(), 
607   //           esd->GetMagneticField()));
608   fCollisionSystem = 
609     AliForwardUtil::ParseCollisionSystem(esd->GetBeamType());
610   fEnergy          = 
611     AliForwardUtil::ParseCenterOfMassEnergy(fCollisionSystem,   
612                                               2 * esd->GetBeamEnergy());
613   fField           = 
614     AliForwardUtil::ParseMagneticField(esd->GetMagneticField());
615   
616   if (fCollisionSystem   == AliForwardUtil::kUnknown || 
617       fEnergy            <= 0                        || 
618       TMath::Abs(fField) >  10) 
619     return kFALSE;
620
621   return kTRUE;
622 }
623
624 //____________________________________________________________________
625 void
626 AliFMDEventInspector::Print(Option_t*) const
627 {
628   // 
629   // Print information
630   // 
631   //   option Not used 
632   //
633   char ind[gROOT->GetDirLevel()+1];
634   for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
635   ind[gROOT->GetDirLevel()] = '\0';
636   TString sNN(AliForwardUtil::CenterOfMassEnergyString(fEnergy));
637   sNN.Strip(TString::kBoth, '0');
638   sNN.ReplaceAll("GeV", " GeV");
639   TString field(AliForwardUtil::MagneticFieldString(fField));
640   field.ReplaceAll("p",  "+");
641   field.ReplaceAll("m",  "-");
642   field.ReplaceAll("kG", " kG");
643   
644   std::cout << ind << "AliFMDEventInspector: " << GetName() << '\n'
645             << ind << " Low flux cut:           " << fLowFluxCut << '\n'
646             << ind << " Max(delta v_z):         " << fMaxVzErr << " cm\n"
647             << ind << " System:                 " 
648             << AliForwardUtil::CollisionSystemString(fCollisionSystem) << '\n'
649             << ind << " CMS energy per nucleon: " << sNN << '\n'
650             << ind << " Field:                  " <<  field << std::endl;
651 }
652
653   
654 //
655 // EOF
656 //
657