KaliVeda
Toolkit for HIC analysis
KVEventFiltering.cpp
1 //Created by KVClassFactory on Thu Jun 21 17:01:26 2012
2 //Author: John Frankland,,,
3 
4 #include "KVEventFiltering.h"
5 #include "KVMultiDetArray.h"
6 #include "KV2Body.h"
7 #include "KVDBSystem.h"
8 #include "KVDBRun.h"
9 #include "KVDataSet.h"
10 #include "KVDataSetManager.h"
11 #include "KVGeoNavigator.h"
12 #include "TRandom.h"
13 
15 
16 
17 
18 
19 
23 {
24  // Default constructor
25  fTransformKinematics = kTRUE;
26  fNewFrame = "";
27  fRotate = kTRUE;
28 #ifdef WITH_GEMINI
29  fGemini = kFALSE;
30  fGemDecayPerEvent = 1;
31  fGemAddRotEner = kFALSE;
32 #endif
33 #ifdef DEBUG_FILTER
34  memory_check = KVClassMonitor::GetInstance();
35  SetEventsReadInterval(100);
36 #endif
37 }
38 
39 
40 
41 
48 
50 {
51  // Copy constructor
52  // This ctor is used to make a copy of an existing object (for example
53  // when a method returns an object), and it is always a good idea to
54  // implement it.
55  // If your class allocates memory in its constructor(s) then it is ESSENTIAL :-)
56 
58  fNewFrame = "";
59  obj.Copy(*this);
60 }
61 
62 
63 
66 
68 {
69  // Destructor
70 #ifdef DEBUG_FILTER
71  delete memory_check;
72 #endif
73 }
74 
75 
76 
77 
85 
87 {
88  // This method copies the current state of 'this' object into 'obj'
89  // You should add here any member variables, for example:
90  // (supposing a member variable KVEventFiltering::fToto)
91  // CastedObj.fToto = fToto;
92  // or
93  // CastedObj.SetToto( GetToto() );
94 
96  KVEventFiltering& CastedObj = (KVEventFiltering&)obj;
97  CastedObj.fRotate = fRotate;
98 #ifdef WITH_GEMINI
99  CastedObj.fGemini = fGemini;
101 #endif
102 }
103 
104 
105 
111 
112 void KVEventFiltering::RandomRotation(KVEvent* to_rotate, const TString& frame_name) const
113 {
114  // do random phi rotation around z-axis
115  // if frame_name is given, apply rotation to that frame
116  //
117  // store phi rotation angle [radians] in event parameter "RANDOM_PHI"
118  TRotation r;
120  r.RotateZ(phi);
121  if (frame_name != "") to_rotate->SetFrame("rotated_frame", frame_name, r);
122  else to_rotate->SetFrame("rotated_frame", r);
123  to_rotate->SetParameter("RANDOM_PHI", phi);
124 }
125 
126 
127 
137 
139 {
140  // Event-by-event filtering of simulated data.
141  // If needed (fTransformKinematics = kTRUE), kinematics of event are transformed
142  // to laboratory frame using C.M. velocity calculated in InitAnalysis().
143  // Detection of particles in event is simulated with KVMultiDetArray::DetectEvent,
144  // then the reconstructed detected event is treated by the same identification and calibration
145  // procedures as for experimental data.
146 
147  // few event counter print at the beginning to be sure the process started properly
148  // because in case GEMINI decay is used, it sometimes stops (randomly) after few events
149  if ((fEVN <= 10)) Info("Analysis", "%d events processed", (int)fEVN);
150  else if ((fEVN <= 1000) && !(fEVN % 100)) Info("Analysis", "%d events processed", (int)fEVN);
151 
152 #ifdef DEBUG_FILTER
153  if (fEVN == 2500) memory_check->SetInitStatistics();
154  else if (fEVN > 4995) memory_check->CompareToInit();
155 #endif
156  KVEvent* to_be_detected = GetEvent();
157 #ifdef WITH_GEMINI
158  Int_t iterations = 1;
159  if (fGemini) iterations = fGemDecayPerEvent;
160 #endif
161  if (to_be_detected->GetNumber()) to_be_detected->SetParameter("SIMEVENT_NUMBER", (int)to_be_detected->GetNumber());
162  to_be_detected->SetParameter("SIMEVENT_TREE_ENTRY", (int)fTreeEntry);
163 #ifdef WITH_GEMINI
164  do {
165  if (fGemini) {
166  try {
168  }
169  catch (...) {
170  continue;
171  }
172  //Copy any parameters associated with simulated event into the Gemini-decayed event
174  to_be_detected = &fGemEvent;
175  }
176 #endif
177  if (fTransformKinematics) {
178  if (fNewFrame == "proj") to_be_detected->SetFrame("lab", fProjVelocity);
179  else to_be_detected->SetFrame("lab", fCMVelocity);
180  }
181  else {
182  // default kinematics is lab frame. make sure name is set.
183  to_be_detected->SetFrameName("lab");
184  }
185  if (fRotate) {
186  RandomRotation(to_be_detected, "lab");
187  fDetSimulator.DetectEvent(to_be_detected, "rotated_frame");
188  }
189  else {
190  fDetSimulator.DetectEvent(to_be_detected, "lab");
191  }
192 
194  fEventReconstructor->SetSimEvent(to_be_detected);
195  fEventReconstructor->ReconstructEvent();
196 
198  fReconEvent->SetFrameName("lab");
199 
200  FillTree();
201 #ifdef WITH_GEMINI
202  }
203  while (fGemini && --iterations);
204 #endif
205 
206 
207  return kTRUE;
208 }
209 
210 
211 
213 
215 {
216  gEnv->SetValue(Form("%s.HasCalibIdentInfos", GetOpt("Dataset").Data()), fIdCalMode.Data());
217 }
218 
219 
220 
222 
224 {
225 }
226 
227 
228 
242 
244 {
245  // Select required dataset for filtering (option "Dataset")
246  // Build the associated multidetector geometry.
247  // Calculate C.M. velocity associated with required experimental collision
248  // kinematics (option "System").
249  //
250  // Set the parameters of the detectors according to the required run
251  // if given (option "Run"), or the first run of the given system otherwise.
252  //
253  // Open file for filtered data (see KVEventFiltering::OpenOutputFile), which will
254  // be stored in a TTree with name 'ReconstructedEvents', in a branch with name
255  // 'ReconEvent'. The class used for reconstructed events depends on the dataset,
256  // it is given by KVDataSet::GetReconstructedEventClassName().
257 
258  if (fDisableCreateTreeFile) return; //when running with PROOF, only execute on workers
259 
260  TString dataset = GetOpt("Dataset").Data();
261  if (!gDataSetManager) {
262  gDataSetManager = new KVDataSetManager;
263  gDataSetManager->Init();
264  }
265  gDataSetManager->GetDataSet(dataset)->cd();
266 
267  TString system;
268  if (IsOptGiven("System")) system = GetOpt("System").Data();
269  KVDBSystem* sys = (gExpDB && system != "" ? gExpDB->GetSystem(system) : nullptr);
270 
271  KV2Body* tb = nullptr;
272 
273  Bool_t justcreated = kFALSE;
274  if (sys) tb = sys->GetKinematics();
275  else if (system != "") {
276  tb = new KV2Body(system);
277  tb->CalculateKinematics();
278  justcreated = kTRUE;
279  }
280 
281  fCMVelocity = (tb ? tb->GetCMVelocity() : TVector3(0, 0, 0));
282  fCMVelocity *= -1.0;
283 
284  fProjVelocity = (tb ? tb->GetNucleus(1)->GetVelocity() : TVector3(0, 0, 0));
285  fProjVelocity *= -1.0;
286 
287  if (justcreated)
288  delete tb;
289 
290  Int_t run = 0;
291  if (IsOptGiven("Run")) {
292  run = GetOpt("Run").Atoi();
293  Info("InitAnalysis", "Run given in options = %d", run);
294  }
295  if (!run) {
296  if (sys) {
297  run = ((KVDBRun*)sys->GetRuns().First())->GetNumber();
298  Info("InitAnalysis", "Using first run for system = %d", run);
299  }
300  else {
301  Info("InitAnalysis", "No run information");
302  run = -1;
303  }
304  }
305 
306  fIdCalMode = gEnv->GetValue(Form("%s.HasCalibIdentInfos", dataset.Data()), "no");
307 
308  TString filt = GetOpt("Filter").Data();
309  if (filt == "GeoThresh") {
310  // in geo+thresholds mode, we ignore any calibration/identification parameters for the dataset,
311  // i.e. all detectors and all identification ntelescopes are supposed to work
312  gEnv->SetValue(Form("%s.HasCalibIdentInfos", dataset.Data()), "no");
313  }
314 
316  if (run == -1) gMultiDetArray->InitializeIDTelescopes();
317 
318  fDetSimulator.SetArray(gMultiDetArray);
319 
320  if (filt == "Geo") {
322  Info("InitAnalysis", "Geometric filter");
323  }
324  else if (filt == "GeoThresh") {
326  Info("InitAnalysis", "Geometry + thresholds filter");
327  }
328  else if (filt == "Full") {
330  Info("InitAnalysis", "Geometry + thresholds filter + implemented identifications and calibrations.");
331  }
332  TString kine = GetOpt("Kinematics").Data();
333  if (kine == "lab") {
335  Info("InitAnalysis", "Simulation is in laboratory/detector frame");
336  }
337  else {
338  fNewFrame = kine;
339  Info("InitAnalysis", "Simulation will be transformed to laboratory/detector frame");
340  }
341 
342  if (IsOptGiven("PhiRot")) {
343  if (GetOpt("PhiRot") == "no") fRotate = kFALSE;
344  }
345  if (fRotate) Info("InitAnalysis", "Random phi rotation around beam axis performed for each event");
346 #ifdef WITH_GEMINI
347  if (IsOptGiven("Gemini")) {
348  if (GetOpt("Gemini") == "yes") fGemini = kTRUE;
350  if (IsOptGiven("GemDecayPerEvent")) fGemDecayPerEvent = GetOpt("GemDecayPerEvent").Atoi();
351  else fGemDecayPerEvent = 1;
352  if (IsOptGiven("GemAddRotEner")) {
353  if (GetOpt("GemAddRotEner") == "yes") fGemAddRotEner = kTRUE;
354  }
355  }
356  if (fGemini) {
357  Info("InitAnalysis", "Statistical decay with Gemini++ for each event before detection");
358  if (fGemDecayPerEvent > 1) Info("InitAnalysis", " -- %d decays per primary event", fGemDecayPerEvent);
359  if (fGemAddRotEner) Info("InitAnalysis", " -- Rotational energy will be added to excitation energy");
360  }
361 #endif
362  if (filt == "Full" && !gDataSet->HasCalibIdentInfos()) {
363  // for old data without implementation of calibration/identification
364  // we set status of identifications according to experimental informations in IdentificationBilan.dat
365  // this "turns off" any telescopes which were not working during the experimental run
366 
367  // beforehand we have to "turn on" all identification telescopes by initializing them
368  // as this will not have been done yet
369  gMultiDetArray->InitializeIDTelescopes();
370  // this will also set informations on (simulated) mass identification capabilities for
371  // certain telescopes
372 
373  TString fullpath;
374  if (sys && KVBase::SearchKVFile("IdentificationBilan.dat", fullpath, gDataSet->GetName())) {
375  Info("InitAnalysis", "Setting identification bilan...");
376  TString sysname = sys->GetBatchName();
378  TIter next(gMultiDetArray->GetListOfIDTelescopes());
379  KVIDTelescope* idt;
380  while ((idt = (KVIDTelescope*)next())) {
381  idt->CheckIdentificationBilan(sysname);
382  }
383  }
384  }
385  gMultiDetArray->PrintStatusOfIDTelescopes();
386 
387  OpenOutputFile(sys, run);
388  TTree* t{nullptr};
389  if (sys) t = AddTree("ReconstructedEvents", Form("%s filtered with %s (%s)", GetOpt("SimTitle").Data(), gMultiDetArray->GetTitle(), sys->GetName()));
390  else t = AddTree("ReconstructedEvents", Form("%s filtered with %s", GetOpt("SimTitle").Data(), gMultiDetArray->GetTitle()));
391 
392  TString reconevclass = gDataSet->GetReconstructedEventClassName();
394  KVEvent::MakeEventBranch(t, "ReconEvent", fReconEvent);
395 
396  auto fer = new KVFilterEventReconstructor(gMultiDetArray, fReconEvent);
397 
398  // look for required data quality audit given as
399  // [dataset][/[system]]
400  // [dataset] is not necessarily the same as the one used for detector geometry
401  if (IsOptGiven("DataQualityAudit"))
402  {
403  KVString audit = GetOpt("DataQualityAudit");
404  audit.Begin("/");
405  KVString dataset,system;
406  dataset = audit.Next();
407  if(!audit.End())
408  system = audit.Next();
409  auto dqaf = TFile::Open(KVDataSet::GetFullPathToDataSetFile(dataset,"DataQualityAudit.root"));
410  auto dqa = system.IsNull() ? dqaf->Get<KVDataQualityAudit>(dataset) : dqaf->Get<KVDataQualityAudit>(system);
411  fer->SetDataQualityAudit(dqa);
412 
413  if(IsOptGiven("ExtensibleID"))
414  {
415  // the ID telescopes in the ExtensibleID list can go beyond the largest identified Z in the audit
416  // using theoretical (calculated) identification thresholds
417  KVString idlabs = GetOpt("ExtensibleID");
418  idlabs.Begin("|");
419  while(!idlabs.End())
420  {
422  }
423  }
424  }
425 
426  fEventReconstructor.reset(fer);
427 }
428 
429 
430 
432 
434 {
435  fEVN = 0;
436 #ifdef DEBUG_FILTER
438 #endif
439 }
440 
441 
442 
464 
466 {
467  // Open ROOT file for new filtered events TTree.
468  //
469  // The filename is built up from the original simulation filename and the values
470  // of various options:
471  //
472  // [simfile]_[Gemini]_filt=[filter-type]_[dataset]_[system]_run=[run-number].root
473  //
474  // In addition, informations on the filtered data are stored in the file as
475  // TNamed objects. These can be read by KVSimDir::AnalyseFile:
476  //
477  // KEY: TNamed System;1 title=[full system name]
478  // KEY: TNamed Dataset;1 title=[dataset name]
479  // KEY: TNamed Run;1 title=[run-number]
480  // KEY: TNamed Filter;1 title=[filter-type]
481  // KEY: TNamed Origin;1 title=[name of simulation file]
482  // KEY: TNamed RandomPhi;1 title=[yes/no, random rotation about beam axis]
483  // KEY: TNamed Gemini++;1 title=[yes/no, Gemini++ decay before detection]
484  // KEY: TNamed GemDecayPerEvent;1 title=[number of Gemini++ decays per primary event]
485  // KEY: TNamed GemAddRotEner;1 title=[Enable or not the addition of the rotational energy to the excitation energy]
486  //
487  TString basefile = GetOpt("SimFileName");
488  basefile.Remove(basefile.Index(".root"), 5);
489  TString outfile = basefile;
490 #ifdef WITH_GEMINI
491  if (fGemini) {
492  outfile += "_Gemini";
493  if (fGemDecayPerEvent > 1) outfile += fGemDecayPerEvent;
494  if (fGemAddRotEner) outfile += "AddedRotEner";
495  }
496 #endif
497  outfile += "_filt=";
498  outfile += GetOpt("Filter");
499  outfile += "_";
500  outfile += gDataSet->GetName();
501 
502  if (S) {
503  outfile += "_";
504  outfile += S->GetBatchName();
505  }
506  else if (IsOptGiven("System")) {
507  TString tmp = GetOpt("System");
508  tmp.ReplaceAll(" ", "");
509  tmp.ReplaceAll("@", "");
510  tmp.ReplaceAll("MeV/A", "");
511  tmp.ReplaceAll("+", "");
512  outfile += "_";
513  outfile += tmp.Data();
514  }
515  if (run > 0) {
516  outfile += "_run=";
517  outfile += Form("%d", run);
518  }
519  if (IsOptGiven("DataQualityAudit"))
520  {
521  KVString tmp(GetOpt("DataQualityAudit"));
522  tmp.ReplaceAll("/",":");
523  outfile += "_DQA=" + tmp;
524  }
525  outfile += ".root";
526 
527  TString fullpath;
528  AssignAndDelete(fullpath, gSystem->ConcatFileName(GetOpt("OutputDir").Data(), outfile.Data()));
529 
530  SetJobOutputFileName(fullpath);
531 
532  TDirectory* curdir = gDirectory;
533  writeFile->cd();
534  if (S) {
535  TNamed* system = new TNamed("System", S->GetName());
536  system->Write();
537  }
538  else if (GetOpt("System"))(new TNamed("System", GetOpt("System").Data()))->Write();
539 
540  (new TNamed("Dataset", gDataSet->GetName()))->Write();
541  if (run > 0)(new TNamed("Run", Form("%d", run)))->Write();
542  (new TNamed("Filter", GetOpt("Filter").Data()))->Write();
543  if (IsOptGiven("DataQualityAudit"))(new TNamed("DataQualityAudit", GetOpt("DataQualityAudit").Data()))->Write();
544  (new TNamed("Origin", (basefile + ".root").Data()))->Write();
545  (new TNamed("RandomPhi", (fRotate ? "yes" : "no")))->Write();
546 #ifdef WITH_GEMINI
547  (new TNamed("Gemini++", (fGemini ? "yes" : "no")))->Write();
548  (new TNamed("GemDecayPerEvent", Form("%d", fGemDecayPerEvent)))->Write();
549  (new TNamed("GemAddRotEner", (fGemAddRotEner ? "yes" : "no")))->Write();
550 #endif
551  curdir->cd();
552 }
553 
554 
int Int_t
ROOT::R::TRInterface & r
bool Bool_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
#define gDirectory
R__EXTERN TEnv * gEnv
R__EXTERN TRandom * gRandom
char * Form(const char *fmt,...)
void AssignAndDelete(TString &target, char *tobedeleted)
R__EXTERN TSystem * gSystem
Relativistic binary kinematics calculator.
Definition: KV2Body.h:168
TVector3 GetCMVelocity() const
Return vector velocity of centre of mass of reaction (units: cm/ns)
Definition: KV2Body.cpp:572
void CalculateKinematics()
Definition: KV2Body.cpp:677
KVNucleus * GetNucleus(Int_t i) const
Definition: KV2Body.cpp:456
virtual void SetNumber(UInt_t num)
Definition: KVBase.h:215
static Bool_t SearchKVFile(const Char_t *name, TString &fullpath, const Char_t *kvsubdir="")
Definition: KVBase.cpp:541
UInt_t GetNumber() const
Definition: KVBase.h:219
static KVClassMonitor * GetInstance()
Return pointer to unique instance of class monitor class.
Description of an experimental run in database ,,.
Definition: KVDBRun.h:41
Database class used to store information on different colliding systems studied during an experiment....
Definition: KVDBSystem.h:51
TString GetBatchName()
Definition: KVDBSystem.cpp:657
KV2Body * GetKinematics()
Definition: KVDBSystem.cpp:103
KVUnownedList GetRuns() const
Returns a sorted list of all the runs associated with this system.
Definition: KVDBSystem.cpp:139
Audit of experimental data identification and calibrations.
Manage all datasets contained in a given data repository.
virtual Bool_t Init(KVDataRepository *=0)
KVDataSet * GetDataSet(Int_t) const
Return pointer to DataSet using index in list of all datasets, index>=0.
TString GetFullPathToDataSetFile(const Char_t *filename) const
Definition: KVDataSet.cpp:2053
virtual KVString GetReconstructedEventClassName() const
Definition: KVDataSet.h:377
Bool_t HasCalibIdentInfos() const
Definition: KVDataSet.h:396
void cd() const
Definition: KVDataSet.cpp:770
void SetArray(KVMultiDetArray *a, Double_t e_cut_off=1.e-3)
void DetectEvent(KVEvent *event, const Char_t *detection_frame="")
TString GetDetectionFrame() const
Filter simulated events with multidetector response.
void InitRun() override
TString fNewFrame
allow the definition of a specific frame
std::unique_ptr< KVFilterEventReconstructor > fEventReconstructor
void EndRun() override
void OpenOutputFile(KVDBSystem *, Int_t)
Bool_t fTransformKinematics
=kTRUE if simulation not in lab frame
void RandomRotation(KVEvent *to_rotate, const TString &frame_name="") const
void EndAnalysis() override
TString fIdCalMode
original exp setup hasIDandCalib to be reset in case of modifications
KVReconstructedEvent * fReconEvent
KVEventFiltering()
Default constructor.
void Copy(TObject &) const override
void InitAnalysis() override
KVDetectionSimulator fDetSimulator
Bool_t Analysis() override
virtual ~KVEventFiltering()
Destructor.
Long64_t fEVN
event number counter
Bool_t fRotate
true if random phi rotation should be applied [default: yes]
General purpose analysis base class for TTree containing KVEvent objects.
Bool_t fDisableCreateTreeFile
used with PROOF
Long64_t fTreeEntry
current tree entry number
void AddTree(TTree *tree)
void SetEventsReadInterval(Long64_t N)
void SetJobOutputFileName(const TString &filename)
Bool_t IsOptGiven(const Char_t *option)
KVEvent * GetEvent() const
TString GetOpt(const Char_t *option) const
void FillTree(const Char_t *tree_name="")
Abstract base class container for multi-particle events.
Definition: KVEvent.h:67
KVNameValueList * GetParameters() const
Definition: KVEvent.h:180
virtual void SetFrameName(const KVString &name)=0
static void MakeEventBranch(TTree *tree, const TString &branchname, T &event, Int_t bufsize=10000000)
Definition: KVEvent.h:211
virtual void SetFrame(const Char_t *, const KVFrameTransform &)=0
void SetParameter(const Char_t *name, ValType value) const
Definition: KVEvent.h:198
virtual KVDBSystem * GetSystem(const Char_t *system) const
Definition: KVExpDB.h:155
Reconstruct events after filtering a simulation.
static void EnableIDExtensionBeyondAudit(const TString &idlab)
void DecayEvent(const KVSimEvent *, KVSimEvent *, bool=true)
Definition: KVGemini.cpp:173
Base class for all detectors or associations of detectors in array which can identify charged particl...
Definition: KVIDTelescope.h:85
void CheckIdentificationBilan(const TString &system)
Set status of ID Telescope for given system.
static void OpenIdentificationBilan(const TString &path)
Open IdentificationBilan.dat file with given path.
KVSeqCollection * GetListOfIDTelescopes() const
static KVMultiDetArray * MakeMultiDetector(const Char_t *dataset_name, Int_t run=-1, TString classname="KVMultiDetArray", KVExpDB *db=nullptr)
void SetFilterType(Int_t t)
virtual void InitializeIDTelescopes()
void PrintStatusOfIDTelescopes()
void Copy(TObject &nvl) const override
TVector3 GetVelocity() const
returns velocity vector in cm/ns units
Event containing KVReconstructedNucleus nuclei reconstructed from hits in detectors.
TObject * First() const override
Container class for simulated nuclei, KVSimNucleus.
Definition: KVSimEvent.h:22
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
void Begin(TString delim) const
Definition: KVString.cpp:565
Bool_t End() const
Definition: KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
void SetFrameName(const KVString &name)
const char * GetName() const override
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
static TClass * GetClass(Bool_t load=kTRUE, Bool_t silent=kFALSE)
Bool_t cd() override
virtual Bool_t cd()
virtual const char * GetValue(const char *name, const char *dflt) const
virtual void SetValue(const char *name, const char *value, EEnvLevel level=kEnvChange, const char *type=nullptr)
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
const char * GetName() const override
const char * GetTitle() const override
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
virtual void Copy(TObject &object) const
virtual void Info(const char *method, const char *msgfmt,...) const
virtual Double_t Uniform(Double_t x1, Double_t x2)
Int_t Atoi() const
const char * Data() const
Bool_t IsNull() const
TString & Remove(EStripType s, char c)
TString & ReplaceAll(const char *s1, const char *s2)
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
virtual char * ConcatFileName(const char *dir, const char *name)
RooArgSet S(Args_t &&... args)
constexpr Double_t TwoPi()
ClassImp(TPyArg)