KaliVeda
Toolkit for HIC analysis
KVINDRAReconDataAnalyser.cpp
1 /*
2 $Id: KVINDRAReconDataAnalyser.cpp,v 1.4 2007/11/15 14:59:45 franklan Exp $
3 $Revision: 1.4 $
4 $Date: 2007/11/15 14:59:45 $
5 */
6 
7 //Created by KVClassFactory on Wed Apr 5 23:50:04 2006
8 //Author: John Frankland
9 
10 #include "KVBase.h"
11 #include "KVINDRAReconDataAnalyser.h"
12 #include "KVINDRADBRun.h"
13 #include "KVINDRADB.h"
14 #include "KVDataAnalysisTask.h"
15 #include "KVDataSet.h"
16 #include "TChain.h"
17 #include "TObjString.h"
18 #include "TChain.h"
19 #include "KVAvailableRunsFile.h"
20 #include "KVINDRA.h"
21 #include "TProof.h"
22 #include "KVINDRATriggerConditions.h"
23 #include "KVINDRAEventSelector.h"
24 
25 #include <KVReconEventSelector.h>
26 
27 using namespace std;
28 
30 
31 
32 
35  : fSelector(nullptr), fOldSelector(nullptr), theChain(nullptr),
36  theRawData(nullptr), theGeneData(nullptr),
37  ParVal(nullptr), ParNum(nullptr), parList(nullptr)
38 {
39 }
40 
41 
42 
45 
47 {
48  //Reset task variables
50  theChain = nullptr;
51  theRawData = nullptr;
52  theGeneData = nullptr;
53  ParVal = nullptr;
54  ParNum = nullptr;
55  fSelector = nullptr;
56  fOldSelector = nullptr;
57  TotalEntriesToRead = 0;
58 }
59 
60 
61 
62 
63 
64 
67 
69 {
70  // Checks the task variables
71 
73 
74  cout << "============> Analysis summary <=============" << endl;
75  cout << "Analysis of runs " << GetRunList().
76  GetList() << " with the class ";
77  cout << "\"" << GetUserClass() << "\"." << endl;
78  if (GetNbEventToRead()) {
79  cout << GetNbEventToRead() << " events will be processed." << endl;
80  }
81  else {
82  cout << "All events will be processed." << endl;
83  }
84  cout << "=============================================" << endl;
85 
86  return kTRUE;
87 }
88 
89 
90 
91 
96 
98 {
99  //Run the interactive analysis
100 
101  //make the chosen dataset the active dataset ( = gDataSet; note this also opens database
102  //and positions gDataBase & gIndraDB).
103  GetDataSet()->cd();
104  fSelector = nullptr;
105  fOldSelector = nullptr;
106 
107  theChain = new TChain("ReconstructedEvents");
108  theChain->SetDirectory(0); // we handle delete
109 
110  GetRunList().Begin();
111  Int_t run;
112 
113  // open and add to TChain all required files
114  // we force the opening of the files to avoid problems with xrootd which sometimes
115  // seems to have a little difficulty
116  while (!GetRunList().End()) {
117  run = GetRunList().Next();
118  TString fullPathToRunfile = gDataSet->GetFullPathToRunfile(GetDataType(), run);
119  cout << "Opening file " << fullPathToRunfile << endl;
120  TFile* f = gDataSet->OpenRunfile<TFile>(GetDataType(), run);
121  cout << "Adding file " << fullPathToRunfile;
122  cout << " to the TChain." << endl;
123  dynamic_cast<TChain*>(theChain)->Add(fullPathToRunfile);
124  if (f && !f->IsZombie()) {
125  // update run infos in available runs file if necessary
127  if (ARF->InfosNeedUpdate(run, gSystem->BaseName(fullPathToRunfile))) {
128  if (!((TTree*)f->Get("ReconstructedEvents"))) {
129  Error("SubmitTask", "No tree named ReconstructedEvents is present in the current file");
130  delete theChain;
131  return;
132  }
133  TEnv* treeInfos = (TEnv*)((TTree*)f->Get("ReconstructedEvents"))->GetUserInfo()->FindObject("TEnv");
134  if (treeInfos) {
135  TString kvversion = treeInfos->GetValue("KVBase::GetKVVersion()", "");
136  TString username = treeInfos->GetValue("gSystem->GetUserInfo()->fUser", "");
137  if (kvversion != "") ARF->UpdateInfos(run, gSystem->BaseName(fullPathToRunfile), kvversion, username);
138  }
139  else {
140  Info("SubmitTask", "No TEnv object associated to the tree");
141  }
142  }
143  }
144  }
145  TotalEntriesToRead = theChain->GetEntries();
146  TString option("");
147 
148  // Add the total run list in option
149  if (!(option.IsNull())) option += ",";
150  option += Form("FullRunList=%s", GetFullRunList().GetList());
151 
152  // Add any user-defined options
153  if (GetUserClassOptions() != "") {
154  option += ",";
155  option += GetUserClassOptions();
156  }
157 
158  set_up_analyser_for_task(this);
159 
160  // for backwards compatibility, we allow user class to inherit from
161  // KVOldINDRASelector instead of KVINDRAEventSelector
162  // for forwards compatibility, we allow it to inherit from KVReconEventSelector too!
163  TObject* new_selector = GetInstanceOfUserClass("KVOldINDRASelector,KVReconEventSelector");
164 
165  if (!new_selector || !new_selector->InheritsFrom("TSelector")) {
166  cout << "The selector \"" << GetUserClass() << "\" is not valid." << endl;
167  cout << "Process aborted." << endl;
168  SafeDelete(new_selector);
169  }
170  else {
171  SafeDelete(new_selector);
172  Info("SubmitTask", "Beginning TChain::Process...");
173 #ifdef WITH_CPP11
174  if (GetProofMode() != KVDataAnalyser::EProofMode::None) dynamic_cast<TChain*>(theChain)->SetProof(kTRUE);
175 #else
176  if (GetProofMode() != KVDataAnalyser::None) dynamic_cast<TChain*>(theChain)->SetProof(kTRUE);
177 #endif
178  TString analysis_class;
179  if (GetAnalysisTask()->WithUserClass()) analysis_class.Form("%s%s", GetUserClassImp().Data(), GetACliCMode());
180  else analysis_class = GetUserClass();
181 
182  if (GetNbEventToRead()) {
183  theChain->Process(analysis_class, option.Data(), GetNbEventToRead());
184  }
185  else {
186  theChain->Process(analysis_class, option.Data());
187  }
188  }
189  delete theChain;
190  fSelector = nullptr; //deleted by TChain/TTreePlayer
191  fOldSelector = nullptr; //deleted by TChain/TTreePlayer
192 }
193 
194 
195 
196 
202 
204 {
205  //Save (in the TEnv fBatchEnv) all necessary information on analysis task which can be used to execute it later
206  //(i.e. when batch processing system executes the job).
207  //If save=kTRUE (default), write the information in a file whose name is given by ".jobname"
208  //where 'jobname' is the name of the job as given to the batch system.
209 
211  // backwards-compatible fix for old KVSelector analysis classes
212  // for forwards compatibility, we allow it to inherit from KVReconEventSelector too!
213  GetBatchInfoFile()->SetValue("UserClassAlternativeBaseClass", "KVOldINDRASelector,KVReconEventSelector");
214  if (save) GetBatchInfoFile()->SaveLevel(kEnvUser);
215 }
216 
217 
218 
223 
225 {
226  //Prints list of available runs, sorted according to multiplicity
227  //trigger, for selected dataset, data type/analysis task, and system
228  //Returns list containing all run numbers
229 
230  KVNumberList all_runs =
231  GetDataSet()->GetRunList(datatype.Data(), GetSystem());
232  KVINDRADBRun* dbrun;
233 
234  //first read list and find what triggers are available
235  vector<int> triggers;
236  all_runs.Begin();
237  while (!all_runs.End()) {
238  dbrun = (KVINDRADBRun*)GetDataSet()->GetDataBase()->GetDBRun(all_runs.Next());
239  if (triggers.size() == 0
240  || std::find(triggers.begin(), triggers.end(), dbrun->GetTrigger()) != triggers.end()) {
241  triggers.push_back(dbrun->GetTrigger());
242  }
243  }
244  //sort triggers in ascending order
245  std::sort(triggers.begin(), triggers.end());
246 
247  for (std::vector<int>::iterator it = triggers.begin(); it != triggers.end(); ++it) {
248  cout << " ---> Trigger M>" << *it << endl;
249  all_runs.Begin();
250  while (!all_runs.End()) {
251  dbrun = (KVINDRADBRun*)GetDataSet()->GetDataBase()->GetDBRun(all_runs.Next());
252  if (dbrun->GetTrigger() == *it) {
253  cout << " " << Form("%4d", dbrun->GetNumber());
254  cout << Form("\t(%9llu events)", dbrun->GetEvents());
255  cout << "\t[File written: " << dbrun->GetDatime().
256  AsString() << "]";
257  if (dbrun->GetComments())
258  cout << "\t" << dbrun->GetComments();
259  cout << endl;
260  }
261  }
262  cout << endl;
263  }
264  return all_runs;
265 }
266 
267 
268 
278 
280 {
281  // Called by currently-processed KVEventSelector before user's InitAnalysis() method.
282  // We build the multidetector for the current dataset in case informations on
283  // detector are needed e.g. to define histograms in InitAnalysis().
284  // Note that at this stage we are not analysing a given run, so the parameters
285  // of the array are not set (they will be set in preInitRun()).
286  //
287  // Note for PROOF: as this will be called both on master and on slave workers,
288  // in order to reduce memory footprint we only build INDRA on the slaves
289 
290  if (!gProof || !gProof->IsMaster()) {
291  if (!gIndra) KVMultiDetArray::MakeMultiDetector(GetDataSet()->GetName());
292  }
293  // in case data is being analysed with a "vanilla" KVReconEventSelector, we need
294  // to set the correct branch name for reconstructed INDRA data which is "INDRAReconEvent"
295  // instead of the default "ReconEvent"
296  if (fSelector) fSelector->SetBranchName("INDRAReconEvent");
297  else Warning("preInitAnalysis", "could not set branch name correctly");
298 }
299 
300 
301 
303 
305 {
306  if (fSelector) {
307  if (fSelector->InheritsFrom("KVINDRAEventSelector"))
308  dynamic_cast<KVINDRAEventSelector*>(fSelector)->SetCurrentRun(CurrentRun);
309  // WARNING - horrible kludge...
310  else if (fSelector->InheritsFrom("KVReconEventSelector"))
311  dynamic_cast<KVReconEventSelector*>(fSelector)->SetCurrentRun(CurrentRun);
312  }
313  else {
314  fOldSelector->SetCurrentRun(CurrentRun);
315  }
316 }
317 
318 
319 
335 
337 {
338  // Called by currently-processed TSelector when a new file in the TChain is opened.
339  // We call gIndra->SetParameters for the current run: whether only physics parameters will be set,
340  // or the full set of identification/calibration parameters depends on the value of the
341  // environment variable
342  //~~~
343  // [dataset].ReconAnalysis.WithCalibInfos: [yes/no]
344  //~~~
345  //This can be overridden for any individual analysis by setting the analysis class option
346  //~~~~
347  // WithCalibInfos=yes
348  //~~~~
349  // We connect the acquisition parameter objects to the branches of the raw data tree.
350  // Infos on currently read file/tree are printed.
351  // Any required data patches ("rustines") are initialized.
352 
353  Bool_t physics_parameters_only = !gDataSet->GetDataSetEnv("ReconAnalysis.WithCalibInfos", kTRUE);
354  if (fSelector->IsOptGiven("WithCalibInfos"))
355  physics_parameters_only = (fSelector->GetOpt("WithCalibInfos") != "yes");
356 
357  Int_t run = GetRunNumberFromFileName(theChain->GetCurrentFile()->GetName());
358  gIndra->SetParameters(run, physics_parameters_only);
359  KVINDRADBRun* CurrentRun = gIndraDB->GetRun(run);
360  SetCurrentRun(CurrentRun);
361  SetSelectorCurrentRun(CurrentRun);
362  cout << endl << " =================== New Run =================== " <<
363  endl << endl;
364 
365  CurrentRun->Print();
366  if (CurrentRun->GetSystem()) {
367  SetSystem(CurrentRun->GetSystem());
368  if (CurrentRun->GetSystem()->GetKinematics())
369  CurrentRun->GetSystem()->GetKinematics()->Print();
370  }
371 
372  cout << endl << " ================================================= " <<
373  endl << endl;
374 
375  ConnectRawDataTree();
376  ConnectGeneDataTree();
377  PrintTreeInfos();
378  Info("preInitRun", "Data written with series %s, release %d", GetDataSeries().Data(),
379  GetDataReleaseNumber());
380  fRustines.InitializePatchList(GetDataSet()->GetName(), GetDataType(), run, GetDataSeries(),
381  GetDataReleaseNumber(), theChain->GetCurrentFile()->GetStreamerInfoCache());
382  fRustines.Print();
383 }
384 
385 
386 
388 
390 {
391  Long64_t rawEntry = (fSelector ? fSelector->GetEventNumber() - 1
392  : fOldSelector->GetEventNumber() - 1);
393 
394  return rawEntry;
395 }
396 
397 
398 
400 
402 {
403  return (fSelector ? dynamic_cast<KVReconstructedEvent*>(fSelector->GetEvent()) : fOldSelector->GetEvent());
404 }
405 
406 
407 #ifdef USING_ROOT6
408 
410 
412 {
414  trig.SetTriggerConditionsForRun(fSelector, run);
415 }
416 
417 #endif
418 
419 
423 
425 {
426  // Read and set raw data for the current reconstructed event
427  // Any required data patches ("rustines") are applied.
428 
429  if (!theRawData) return;
430  // all recon events are numbered 1, 2, ... : therefore entry number is N-1
431  Long64_t rawEntry = GetRawEntryNumber();
432  theRawData->GetEntry(rawEntry);
434  for (int i = 0; i < NbParFired; i++)
435  gIndra->handle_ebyedat_raw_data_parameter((*parList)[ParNum[i]]->GetName(), ParVal[i]);
436 
437  // as rustines often depend on a knowledge of the original raw data,
438  // we apply them after it has been read in
439  KVINDRAReconEvent* event = (KVINDRAReconEvent*)GetReconstructedEvent();
440  if (fRustines.HasActivePatches()) fRustines.Apply(event);
441 }
442 
443 
444 
451 
453 {
454  // Called by preInitRun().
455  // When starting to read a new run (=new file), we look for the TTree "RawData" in the
456  // current file (it should have been created by KVINDRARawDataReconstructor).
457  // If found, it will be used by ReadRawData() to set the values of all acquisition parameters
458  // for each event.
459 
460  theRawData = (TTree*)theChain->GetCurrentFile()->Get("RawData");
461  if (!theRawData) {
462  Warning("ConnectRawDataTree", "RawData tree not found in file; raw data parameters of detectors will not be available in analysis");
463  return;
464  }
465  else
466  Info("ConnectRawDataTree", "Found RawData tree in file");
467  Int_t maxNopar = theRawData->GetMaximum("NbParFired");
468  if (ParVal) delete [] ParVal;
469  if (ParNum) delete [] ParNum;
470  ParVal = new UShort_t[maxNopar];
471  ParNum = new UInt_t[maxNopar];
472  parList = (TObjArray*)theRawData->GetUserInfo()->FindObject("ParameterList");
473  theRawData->SetBranchAddress("NbParFired", &NbParFired);
474  theRawData->SetBranchAddress("ParNum", ParNum);
475  theRawData->SetBranchAddress("ParVal", ParVal);
476  Info("ConnectRawDataTree", "Connected raw data parameters");
477  Entry = 0;
478 }
479 
480 
481 
486 
488 {
489  // Called by preInitRun().
490  // When starting to read a new run (=new file), we look for the TTree "GeneData" in the
491  // current file (it should have been created by KVINDRARawDataReconstructor).
492 
493  theGeneData = (TTree*)theChain->GetCurrentFile()->Get("GeneData");
494  if (!theGeneData) {
495  cout << " --> No pulser & laser data for this run !!!" << endl << endl;
496  }
497  else {
498  cout << " --> Pulser & laser data tree contains " << theGeneData->GetEntries()
499  << " events" << endl << endl;
500  }
501 }
502 
503 
504 
506 
508 {
509  return (TEnv*)theChain->GetTree()->GetUserInfo()->FindObject("TEnv");
510 }
511 
512 
513 
516 
518 {
519  // Print informations on currently analysed TTree
520  TEnv* treeInfos = GetReconDataTreeInfos();
521  if (!treeInfos) return;
522  cout << endl << "----------------------------------------------------------------------------------------------------" << endl;
523  cout << "INFORMATIONS ON VERSION OF KALIVEDA USED TO GENERATE FILE:" << endl << endl;
524  fDataVersion = treeInfos->GetValue("KVBase::GetKVVersion()", "(unknown)");
525  cout << "version = " << fDataVersion << endl ;
526  cout << "build date = " << treeInfos->GetValue("KVBase::GetKVBuildDate()", "(unknown)") << endl ;
527  cout << "source directory = " << treeInfos->GetValue("KVBase::GetKVSourceDir()", "(unknown)") << endl ;
528  cout << "KVROOT = " << treeInfos->GetValue("KVBase::GetKVRoot()", "(unknown)") << endl ;
529  cout << "BZR branch name = " << treeInfos->GetValue("KVBase::bzrBranchNick()", "(unknown)") << endl ;
530  cout << "BZR revision #" << treeInfos->GetValue("KVBase::bzrRevisionNumber()", "(unknown)") << endl ;
531  cout << "BZR revision ID = " << treeInfos->GetValue("KVBase::bzrRevisionId()", "(unknown)") << endl ;
532  cout << "BZR revision date = " << treeInfos->GetValue("KVBase::bzrRevisionDate()", "(unknown)") << endl ;
533  cout << endl << "INFORMATIONS ON GENERATION OF FILE:" << endl << endl;
534  cout << "Generated by : " << treeInfos->GetValue("gSystem->GetUserInfo()->fUser", "(unknown)") << endl ;
535  cout << "Analysis task : " << treeInfos->GetValue("AnalysisTask", "(unknown)") << endl ;
536  cout << "Job name : " << treeInfos->GetValue("BatchSystem.JobName", "(unknown)") << endl ;
537  cout << "Job submitted from : " << treeInfos->GetValue("LaunchDirectory", "(unknown)") << endl ;
538  cout << "Runs : " << treeInfos->GetValue("Runs", "(unknown)") << endl ;
539  cout << "Number of events requested : " << treeInfos->GetValue("NbToRead", "(unknown)") << endl ;
540  cout << endl << "----------------------------------------------------------------------------------------------------" << endl;
541 
542  // if possible, parse fDataVersion into series and release number
543  // e.g. if fDataVersion = "1.8.10":
544  // => fDataSeries = "1.8" fDataReleaseNum = 10
545  Int_t a, b, c;
546  if (fDataVersion != "(unknown)") {
547  if (sscanf(fDataVersion.Data(), "%d.%d.%d", &a, &b, &c) == 3) {
548  fDataSeries.Form("%d.%d", a, b);
549  fDataReleaseNum = c;
550  }
551  }
552  else {
553  fDataSeries = "";
554  fDataReleaseNum = -1;
555  }
556 }
557 
558 
559 
561 
563 {
564  if (theRawData) theRawData->CloneTree(-1, "fast"); //copy raw data tree to file
565  if (theGeneData) theGeneData->CloneTree(-1, "fast"); //copy pulser & laser (gene) tree to file
566 }
567 
568 
569 
576 
578 {
579  // Overrides KVDataAnalyser method, for backwards & forwards compatibility.
580  //
581  // Old user analysis classes may derive from KVOldINDRASelector (aka KVSelector) instead of KVINDRAEventSelector.
582  //
583  // It is also possible to analyse data with a "vanilla" KVReconEventSelector analysis class.
584  return KVDataAnalyser::CheckIfUserClassIsValid("KVOldINDRASelector,KVReconEventSelector");
585 }
586 
587 
int Int_t
unsigned int UInt_t
#define SafeDelete(p)
#define f(i)
#define c(i)
bool Bool_t
unsigned short UShort_t
constexpr Bool_t kFALSE
constexpr Bool_t kTRUE
kEnvUser
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t b
R__EXTERN TProof * gProof
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
void Print(Option_t *opt="") const
Definition: KV2Body.cpp:813
Handles lists of available runs for different datasets and types of data.
virtual void UpdateInfos(Int_t run, const Char_t *filename, const Char_t *kvversion, const Char_t *username)
virtual Bool_t InfosNeedUpdate(Int_t run, const Char_t *filename)
virtual Int_t GetNumber() const
Definition: KVDBRecord.h:73
ULong64_t GetEvents() const
Definition: KVDBRun.h:134
KVDBSystem * GetSystem() const
Definition: KVDBRun.cpp:242
const TDatime & GetDatime() const
Definition: KVDBRun.h:114
virtual void Print(Option_t *option="") const
Definition: KVDBRun.cpp:69
Int_t GetTrigger() const
Definition: KVDBRun.h:104
const Char_t * GetComments() const
Definition: KVDBRun.h:147
KV2Body * GetKinematics()
Definition: KVDBSystem.cpp:80
virtual void Reset()
virtual Bool_t CheckIfUserClassIsValid(const KVString &alternative_base_class="")
virtual Bool_t CheckTaskVariables()
void WriteBatchEnvFile(const TString &jobname, Bool_t save=kTRUE)
KVAvailableRunsFile * GetAvailableRunsFile(const Char_t *type) const
Definition: KVDataSet.cpp:50
FileType * OpenRunfile(const Char_t *type, Int_t run)
Definition: KVDataSet.h:167
const Char_t * GetDataSetEnv(const Char_t *type, const Char_t *defval="") const
Definition: KVDataSet.cpp:767
TString GetFullPathToRunfile(const Char_t *type, Int_t run) const
Definition: KVDataSet.cpp:897
Database entry for each run of an INDRA experiment.
Definition: KVINDRADBRun.h:30
KVINDRADBRun * GetRun(Int_t run) const
Definition: KVINDRADB.h:133
Base class for analysis of reconstructed INDRA events.
Manage analysis of reconstructed INDRA data.
void SetTriggerConditionsForRun(int) override
void SetSelectorCurrentRun(KVINDRADBRun *CurrentRun)
void WriteBatchEnvFile(const TString &, Bool_t sav=kTRUE) override
void PrintTreeInfos()
Print informations on currently analysed TTree.
KVReconstructedEvent * GetReconstructedEvent()
Bool_t CheckIfUserClassIsValid(const KVString &="") override
Bool_t CheckTaskVariables(void) override
Checks the task variables.
void Reset() override
Reset task variables.
virtual KVNumberList PrintAvailableRuns(KVString &datatype) override
Event reconstructed from energy losses in INDRA multidetector.
Set trigger conditions for analysis of reconstructed INDRA data.
void SetTriggerConditionsForRun(KVEventSelector *, Int_t, Bool_t=kFALSE)
void handle_ebyedat_raw_data_parameter(const char *param_name, uint16_t val)
Definition: KVINDRA.cpp:801
void prepare_to_handle_new_raw_data()
reset acquisition parameters etc. before reading new raw data event
virtual void SetParameters(UInt_t n, Bool_t physics_parameters_only=kFALSE)
static KVMultiDetArray * MakeMultiDetector(const Char_t *dataset_name, Int_t run=-1, TString classname="KVMultiDetArray")
Strings used to represent a set of ranges of values.
Definition: KVNumberList.h:85
Bool_t End(void) const
Definition: KVNumberList.h:199
void Begin(void) const
Int_t Next(void) const
Base class for user analysis of reconstructed data.
void SetCurrentRun(KVDBRun *r)
Event containing KVReconstructedNucleus nuclei reconstructed from hits in detectors.
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
virtual void SetProof(Bool_t on=kTRUE, Bool_t refresh=kFALSE, Bool_t gettreeheader=kFALSE)
virtual const char * GetValue(const char *name, const char *dflt) const
virtual TObject * FindObject(const char *name) const
virtual Bool_t InheritsFrom(const char *classname) const
Bool_t IsMaster() const
const char * Data() const
void Form(const char *fmt,...)
virtual const char * BaseName(const char *pathname)
long long Long64_t
BinData::ErrorType GetDataType(const TGraph *gr, DataOptions &fitOpt)
void Error(const char *location, const char *fmt,...)
void Info(const char *location, const char *fmt,...)
void Warning(const char *location, const char *fmt,...)
void End()
Add
TArc a
ClassImp(TPyArg)