EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicDetector.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicDetector.cxx
1 //
2 // AYK (ayk@bnl.gov), 2013/06/12
3 //
4 // Basic EIC detector class; several small size methods are
5 // here just to interface with basic FairRoot & PandaRoot classes;
6 //
7 
8 #include <assert.h>
9 // FIXME: is it really Mac-OS-specific?;
10 #ifndef __APPLE__
11 #include <asm/types.h>
12 #endif
13 #include <iostream>
14 using namespace std;
15 
16 #include "TGeoManager.h"
17 #include "TClonesArray.h"
18 #include "TVirtualMC.h"
19 #include "TLorentzVector.h"
20 #include "TList.h"
21 #include <TParticle.h>
22 #include "TObjArray.h"
23 #include <TSystem.h>
24 #include <TGeoArb8.h>
25 
26 #include "FairRun.h"
27 #include "FairRuntimeDb.h"
28 #include "FairGeoLoader.h"
29 #include "FairGeoInterface.h"
30 #include "FairGeoNode.h"
31 #include "FairGeoVolume.h"
32 #include "FairVolume.h"
33 #include "FairRootManager.h"
34 
35 #include "PndStack.h"
36 #include <PndGeoHandling.h>
37 
38 #include "EicGeo.h"
39 #include "EicGeoPar.h"
40 #include "EicDetector.h"
41 #include <EicRunSim.h>
42 
43 // ---------------------------------------------------------------------------------------
44 
45 EicDetector::EicDetector(const char *Name, const char *geometryName, EicDetectorId dType,
46  SteppingType stType, Bool_t Active): FairDetector(Name, Active)
47 {
48  ResetVars();
49 
50  // This would basically mean EicFieldMapDetector->DummyDetector chain was invoked
51  // with sort of default constructor;
52  if (!Name) return;
53 
54  fVerboseLevel = 1;
55 
56  // Do this check better later; will it work this way at all?;
57  assert(DetectorId(dType) <= kHYP);
58  fDetType = dType;
59 
60  fStType = stType;
61 
62  dname = new EicDetName(Name);
63 
64  fEicMoCaPointCollection = new TClonesArray("EicMoCaPoint");
65  // Yes, prefer to create this information flow anyway, no matter it is needed or not;
66  //fEicFakeMoCaPointCollection = new TClonesArray("EicFakeMoCaPoint");
67 
68  eicContFact = new EicContFact(this, (dname->Name() + "ContFact").Data(),
69  ("Factory for parameter containers in lib" + dname->Name()).Data(),
70  (dname->Name() + "GeoPar").Data(),
71  (dname->Name() + " Geometry Parameters").Data(),
72  (dname->Name() + "DefaultContext").Data());
73 
74  SetGeometryFileName(geometryName);
75 } // EicDetector::EicDetector()
76 
77 // ---------------------------------------------------------------------------------------
78 #if _LATER_
79 int EicDetector::SetEnergyCutOff(Int_t PDG, const Double_t cutMin, const Double_t cutMax)
80 {
81  if (cutMin <= 0.0 || cutMin >= cutMax) return -1;
82 
83  if (!_fCutOffMap) _fCutOffMap = new std::map<Int_t, std::pair<Double_t,Double_t> >();
84 
85  // No PDG code checks?; Ok; eventually should arrange something like a wildcard
86  // (say, all hadrons); also, prefer to store positive value, assuming that eg
87  // cutoff for electrons and positrons should be the same; change later if this
88  // proves to be misleading;
89  (*_fCutOffMap)[abs(PDG)] = std::pair<Double_t, Double_t>(cutMin, cutMax);
90 
91  return 0;
92 } // EicDetector::SetEnergyCutOff()
93 #endif
94 
95 // ---------------------------------------------------------------------------------------
96 
97 void EicDetector::SetGeometryFileName(TString fname, TString geoVer)
98 {
99  // Allow two exceptions;
100  if (fname.BeginsWith("/") || fname.BeginsWith("./") || fname.BeginsWith(".."))
101  fgeoName = fname;
102  else
103  // Otherwise append $VMCWORKDIR or such in a standard FairRoot call;
104  FairModule::SetGeometryFileName(fname, geoVer);
105 } // EicDetector::SetGeometryFileName()
106 
107 // ---------------------------------------------------------------------------------------
108 
110 {
111  return new EicGeoPar(c->getConcatName().Data(),c->GetTitle(),c->getContext());
112 } // EicDetector::EicGeoParAllocator()
113 
114 // ---------------------------------------------------------------------------------------
115 
116 //
117 // FIXME: well, there should be a plenty of stuff here, or?;
118 //
119 
121 {
122 } // EicDetector::~EicDetector()
123 
124 // ---------------------------------------------------------------------------------------
125 
127 {
129 
130  // I guess no double-counting check is really needed here?; if non-trivial stepping
131  // type is given, use it; otherwise pick up the stepping type given at detector initialization;
133 
134  return 0;
135 } // EicDetector::DeclareGeantSensitiveVolume()
136 
137 // ---------------------------------------------------------------------------------------
138 
140 {
142 
143  // Same logic as in DeclareGeantSensitiveVolume();
145 
146  return 0;
147 } // EicDetector::DeclareGeantSensitiveVolumePrefix()
148 
149 // ---------------------------------------------------------------------------------------
150 
152 {
153  if (mAllVolumesSensitiveFlag) return true;
154 
155  //return (fListOfGeantSensitives ? fListOfGeantSensitives->AnyMatch(name.c_str()) : false);
156  return (fListOfGeantSensitives && fListOfGeantSensitives->AnyMatch(name.c_str()));
157 } // EicDetector::CheckIfSensitive()
158 
159 // ---------------------------------------------------------------------------------------
160 
162 {
163  //return (mKillerVolumes ? mKillerVolumes->AnyMatch(name) : false);
164  return (mKillerVolumes && mKillerVolumes->AnyMatch(name));
165 } // EicDetector::IsKillerVolume()
166 
167 // ---------------------------------------------------------------------------------------
168 
170 {
171  if(fVerboseLevel) Print();
172 
173  // FIXME: figure out how to use point->GetPrimaryMotherID() here;
174 #if _LATER_
175  // If database creation is requested, fill out;
176  if (dbFile)
177  {
178  // Assume ID=0 (see comment below); can this call fail?; fix later;
179  TParticle *primary = ((PndStack*)gMC->GetStack())->GetParticle(0);
180 
181  dbEntry->setPrimaryVtx (TVector3(primary->Vx(), primary->Vy(), primary->Vz()));
182  dbEntry->setPrimaryParticleMomentum(TVector3(primary->Px(), primary->Py(), primary->Pz()));
183 
184  Int_t PDG = primary->GetPdgCode();
185  // Well, prefer yet another sanity check;
186  if (_fCutOffMap->find(abs(PDG)) == _fCutOffMap->end())
187  {
188  printf("\n *** Primary mother PDG is not present in original MC file map; "
189  "(must be the wrong input MC file)! ***\n\n");
190  exit(0);
191  } //if
192  dbEntry->setPrimaryParticlePDG(PDG);
193 
194  TClonesArray *arr = fThreadVar->GetArrayPtr();
195 
196  //unsigned int hNum = _fEicMoCaPointCollection[th]->GetEntriesFast();
197  unsigned int hNum = arr->GetEntriesFast();
198  // Loop through all the hits and put them into array;
199  printf("--> %4d hits ...\n", hNum);
200 
201  for(unsigned iq=0; iq<hNum; iq++)
202  {
203  //EicMoCaPoint *point = (EicMoCaPoint*)_fEicMoCaPointCollection[th]->At(iq);
204  EicMoCaPoint *point = (EicMoCaPoint*)arr->At(iq);
205 
206  // Well, if input MC file was properly cooked and no mess happened
207  // to generator setup (so - and better a single - EicFakeMoCaPointGenerator()
208  // call was used), primary mother should have been a single - and most likely
209  // one of the {e+,e-,gamma} PDG - track;
210  if (point->_GetPrimaryMotherID())
211  {
212  // Check whether I need a primary or a secondary mother ID here;
213  assert(0);
214  printf("\n *** Primary mother ID is != 0; "
215  "(must be the wrong input MC file and/or generator)! ***\n\n");
216  exit(0);
217  } //if
218 
219  EicFakeMoCaPointDbHit hit(point->GetPosIn(), point->GetEnergyLoss());
220 
221  new((*dbEntry->fHits)[dbEntry->fHits->GetEntriesFast()]) EicFakeMoCaPointDbHit(hit);
222  } //for iq
223 
224  dbTree->Fill();
225  dbEntry->fHits->Delete();
226  } //if
227 #endif
228 
229  // Eventually delete MC point clone arrays;
230  fEicMoCaPointCollection->Delete();
231  // fEicFakeMoCaPointCollection->Delete();
232 
233  // Clear registered track lists in energy monitors (to avoid double-counting);
234  for(unsigned mn=0; mn<mEnergyMonitorVolumes.size(); mn++) {
236 
237  monitor->mRegisteredTracks.clear();
238  } //for mn
239 } // EicDetector::EndOfEvent()
240 
241 // ---------------------------------------------------------------------------------------
242 
244 {
245  // This call creates a branch with a given name in the output tree; setting the last
246  // parameter to kFALSE means: this collection will not be written to the file (AYK ?),
247  // it will exist only during the simulation;
248  FairRootManager::Instance()->Register(dname->Name() + "MoCaPoint", dname->Name(),
249  fEicMoCaPointCollection, kTRUE);
250 
251  //FairRootManager::Instance()->Register(dname->Name() + "FakeMoCaPoint", dname->Name(),
252  // fEicFakeMoCaPointCollection, kTRUE);
253 } // EicDetector::Register()
254 
255 // ---------------------------------------------------------------------------------------
256 
257 #define _64BIT_VALUE_INVALID_ (~ULong64_t(0))
258 
260 {
261  ULong64_t ret = _64BIT_VALUE_INVALID_;
262 
263  // In particular HADES-style geometries have no chance to share their mapping; so
264  // just return back nonsense index; NB: also new-style geometry files may be missing
265  // this info;
266  if (!gptr) return ret;
267 
268  //
269  // Later may want to create a look-up table (STL map) based on node ID;
270  // really needed?;
271  //
272 
273  UInt_t lvVolumeIds[gptr->GetMaxVolumeLevelNum()], lvNodeIds[gptr->GetMaxVolumeLevelNum()];
274 
275  // If current path is not the same as it was upon sensitive volume entry,
276  // have to fool the geometry manager; check later, what's wrong with GEANT4 here;
277  TString returnBackPath;
278  if (strcmp(gGeoManager->GetPath(), fPathUponEntry.Data()))
279  {
280  returnBackPath = gGeoManager->GetPath();
281  gGeoManager->cd(fPathUponEntry);
282  } //if
283 
284  for(int lv=0; lv<gptr->GetMaxVolumeLevelNum(); lv++)
285  {
286  // May also use gGeoManager->GetMother() for lv=0; who cares;
287  TGeoNode *node = lv ? gGeoManager->GetMother(lv) : gGeoManager->GetCurrentNode();
288 
289  // Could this crash if node=0 (for instance levels exhausted in this branch)?;
290  // well, check on that; setting values to 0 do not hurt (may also leave them
291  // uninitialized, but Ok);
292  lvVolumeIds [lv] = node ? node->GetVolume()->GetNumber() : 0;
293  lvNodeIds [lv] = node ? node-> GetNumber() : 0;
294  } // for lv
295 
296  // Loop through all maps and find matching one;
297  for(int iq=0; iq<gptr->GetMapNum(); iq++)
298  {
299  EicGeoMap *fmap = gptr->GetMapPtrViaMapID(iq);
300 
301  if (fmap->IsMySignature(lvVolumeIds))
302  {
303  ret = (ULong64_t(iq) & _SERVICE_BIT_MASK_) << _GEANT_INDEX_BIT_NUM_;
304 
305  // Tune shifts to this particular map;
306  for(int lv=0; lv<fmap->GetGeantVolumeLevelNum(); lv++)
307  {
308  const GeantVolumeLevel *lptr = fmap->GetGeantVolumeLevelPtr(lv);
309  const EicBitMask<UGeantIndex_t> *mask = lptr->GetBitMaskPtr();
310 
311  // Skip "dummy" levels (for instance individual fibers);
312  if (!lptr->GetMaxEntryNum()) continue;
313 
314  // Check range;
315  if (lvNodeIds[lv] >= lptr->GetMaxEntryNum())
316  {
317  // Just a warning; want to see this situation first;
318  cout<<"-E- Eic"<< dname->Name() <<": " <<
319  "Sensitive volume multi-index too large!" << endl;
320 
321  // Restore GEANT4 geo manager state if had to switch it;
322  if (!returnBackPath.IsNull()) gGeoManager->cd(returnBackPath);
323  return _64BIT_VALUE_INVALID_;
324  } //if
325 
326  // Well, in fact there is no need to mask out bits here (see check above);
327  ret |= (lvNodeIds[lv] & mask->GetBitMask()) << mask->GetShift();
328  } //for lv
329 
330  // Well, consider to fill out base name if not done so yet; obviously,
331  // if no hits were registered at this map, string will not be filled
332  // out at all, which is Ok;
333  if (fmap->GetBaseVolumePath()->IsNull())
334  {
335  // Record current path;
336  TString path = gGeoManager->GetPath();
337 
338  // Go few levels up;
339  for(int lv=0; lv<fmap->GetGeantVolumeLevelNum(); lv++)
340  gGeoManager->CdUp();
341 
342  fmap->AssignBaseVolumePath(gGeoManager->GetPath());
343 
344  // Return back in the node tree;
345  gGeoManager->cd(path);
346  } //if
347 
348  break;
349  } /*if*/
350  } //for iq
351 
352  // Return back to the insensitive neighboring volume where GEANT4 probably
353  // ended up exiting from the "true" sensitive volume;
354  if (!returnBackPath.IsNull()) gGeoManager->cd(returnBackPath);
355 
356  // Do it better later; at least don't care about this warning for all-sensitive
357  // (basically dummy) detectors in a special-purpose mode (say neutron flux calculation);
359  printf("%s vs %s\n", gGeoManager->GetPath(), fPathUponEntry.Data());
360 
361  return ret;
362 } // EicDetector::GetNodeMultiIndex()
363 
364 // ---------------------------------------------------------------------------------------
365 
366 void EicDetector::CheckEnergyMonitors(const char *name, Int_t trackID,
367  Int_t PDG, bool isPrimary,
368  bool isEntering, bool isExiting,
369  double energy)
370 {
371  // Should either be entering or exiting -> check on that;
372  if (!isEntering && !isExiting) return;
373 
374  // Carelessly loop through all declared monitor volumes; no optimization,
375  // since this is a debugging stuff anyway;
376  for(unsigned mn=0; mn<mEnergyMonitorVolumes.size(); mn++) {
378 
379  // Check volume name match;
380  if (!monitor->mName.EqualTo(name)) continue;
381 
382  // Check entrance/exit condition match;
383  if (isEntering && !monitor->mAtEntrance) continue;
384  if (isExiting && monitor->mAtEntrance) continue;
385 
386  // Check PDG and primary/any particle type match;
387  if (PDG != monitor->mPDG) continue;
388  if (!isPrimary && monitor->mPrimaryOnly) continue;
389 
390  // Double-entry protection;
391  if (monitor->mRegisteredTracks.find(trackID) != monitor->mRegisteredTracks.end()) continue;
392  monitor->mRegisteredTracks.insert(trackID);
393 
394 #if 0
395  {
396  static unsigned counter = 0;
397 
398  printf("%4d (%d .. %d) %d -> %f\n", counter++, isPrimary, monitor->mPrimaryOnly, isEntering, energy);
399  }
400 #endif
401 
402  // Full match, fine; fill out hiftogram entry; FIXME: there is no control over
403  // 2-d entry of a given particle into the same volume, so use with care;
404  {
405  TAxis *xaxis = monitor->mHistogram->GetXaxis();
406 
407  // Do not bother to fill out-of-range values;
408  if (energy >= xaxis->GetXmin() && energy <= xaxis->GetXmax())
409  monitor->mHistogram->Fill(energy);
410  }
411  } //for mn
412 } // EicDetector::CheckEnergyMonitors()
413 
414 // ---------------------------------------------------------------------------------------
415 
417 {
418  // Set parameters at entrance of volume. Reset ELoss.
419  fELoss = fStep = 0.0;
420  fTime = gMC->TrackTime() * 1.0e09;
421  fLength = gMC->TrackLength();
422  gMC->TrackPosition(fPosIn);
423  gMC->TrackMomentum(fMomIn);
424 
425  fPathUponEntry = gGeoManager->GetPath();
426 } // EicDetector::ResetSteppingVariables()
427 
428 // ---------------------------------------------------------------------------------------
429 
431 {
432  //printf("Here! -> %s %d %d\n", v->GetName(), gMC->IsTrackEntering(), gMC->IsTrackExiting());
433 
434  // Well, even if SuppressHitProduction flag is set I still may want to record
435  // track trajectories in FairMCApplication::Stepping(); however return here
436  // immediately since no hits are wanted;
437  EicRunSim *fRun = EicRunSim::Instance();
438  if (fRun && fRun->SuppressHitProductionFlag()) return kTRUE;
439 
440  Int_t trackID = gMC->GetStack()->GetCurrentTrackNumber();
441  Int_t volumeID = v->getMCid();
442  TParticle *particle = ((PndStack*)gMC->GetStack())->GetParticle(trackID);
443  //printf("%d\n", particle->GetPdgCode());
444 
445  // For now consider the following logic of which particles will make it
446  // into the AddMoCaPoint() call:
447  // - any changed particle with fELoss>0;
448  // - neutral particles with PDG codes strictly bound to specific volumes;
449  // consider to let detector geometry know, which ones are those (so the
450  // respective call should happen in geometry creation script like rich.C
451  // in order to enable optical photons to produce hits; in fact this
452  // scheme also allows to have charged particle hits with fELoss=0; fine;
453  //
454  // No threshold is applied on either fELoss or fStep; digitizer may want to
455  // reject some of the hits later (especially since merged energy deposit from
456  // two tracks can go above threshold; makes sense?;
457  bool wanted = gptr ? gptr->IsWantedParticle(v->GetName(), particle->GetPdgCode()) : false;
458 
459  // May reconsider this return call once frozen shower code (see below) is
460  // back to life; in this case may want photons to be included in the database;
461  if (!wanted && !gMC->TrackCharge()) return kTRUE;
462 
463  // In Geant4 mode upon volume entry check whether max step should be set explicitely;
464  if ((gMC->IsTrackEntering() || gMC->IsNewTrack()) && gptr) {
465  double step = gptr->GetEnforcedStep(v->getMCid());
466 
467  // step=0.0 simply means "don't bother for this volume";
468  if (step) gMC->SetMaxStep(step);
469  //gMC->SetMaxStep(0.1);//step);
470  } //if
471 
472  // Track either just crossed volume boundary or is new born -> record time, length,
473  // entry point and momentum; reset energy loss counter and return;
474  if (gMC->IsTrackEntering() || gMC->IsNewTrack()) {
476 
477 #if _LATER_
478  // If energy cutoff is defined for this type of particle, check current
479  // energy against it and if below the limit, stop this track and fill out
480  // respective entry in fake MC point array;
481  {
482  // Unify these cheap calls later (see below);
483  //Int_t trackID = gMC->GetStack()->GetCurrentTrackNumber();
484  //TParticle *particle = ((PndStack*)gMC->GetStack())->GetParticle(trackID);
485  Int_t PDG = particle->GetPdgCode();
486 
487  // Check that such an entry exists in fCutOffMap table;
488  if ((_fCutOffMap && !dbFile) && _fCutOffMap->find(abs(PDG)) != _fCutOffMap->end()) {
489  TLorentzVector fMom;
490  gMC->TrackMomentum(fMom);
491 
492  // Well, I guess kinetic energy should be considered here, right?;
493  //printf("%2d: %f %f\n", particle->GetPdgCode(), fMom.E(), particle->GetMass());
494  double eKin = fMom.E() - particle->GetMass();
495 
496  if (eKin >= (*_fCutOffMap)[abs(PDG)].first && eKin <= (*_fCutOffMap)[abs(PDG)].second) {
497  // Also unify with the below call later?;
498  Int_t volumeID = v->getMCid();
499 #if _LATER_
500  AddFakeMoCaPoint(trackID, GetPrimaryMotherId(), PDG, volumeID, gGeoManager->GetPath(),
502  fPosIn.Vect(), fMomIn.Vect(), fTime, fLength/*, eKin*/);
503 #endif
504 
505  //printf(" -> will stop this track!\n");
506  gMC->StopTrack();
507  return kTRUE;
508  } //if
509  } //if
510  }
511 #endif
512 
513  return kTRUE;
514  } /*if*/
515 
516  fELoss += gMC->Edep();
517  fStep += gMC->TrackStep();
518 
519  // Figure out stepping type for this volume;
520  SteppingType effectiveSteppingType = qSteppingTypeUndefined;
521  // Try sensitive volume list first;
523  const std::pair<TString, SteppingType> *steppingType =
524  fListOfGeantSensitives->AnyMatch(v->GetName());
525 
526  if (steppingType) effectiveSteppingType = steppingType->second;
527  } //if
528  // Then check if all volumes should be sensitive;
529  if (effectiveSteppingType == qSteppingTypeUndefined && mAllVolumesSensitiveFlag)
530  effectiveSteppingType = fStType;
531  // Eventually check, that assignment resulted in a meaningful value;
532  if (effectiveSteppingType == qSteppingTypeUndefined ||
533  // This can hardly happen; just for completeness;
534  effectiveSteppingType == qSteppingTypeDefault)
535  fLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Sensitive volume with undefined stepping type found (%s)! \033[0m",
536  v->GetName());
537 
538  {
539  //TLorentzVector fPosOut;
540  //gMC->TrackPosition(fPosOut);
541  //printf("%7.3f %7.3f %d %d %d %d\n", fPosIn.Vect().Perp(), fPosOut.Vect().Perp(), effectiveSteppingType == qOneStepOneHit,
542  // gMC->IsTrackExiting(), gMC->IsTrackStop(), gMC->IsTrackDisappeared());
543  //printf("%7.3f %8.5f\n", fStep, fELoss);
544  }
545  if (effectiveSteppingType == qOneStepOneHit || gMC->IsTrackExiting() || gMC->IsTrackStop() ||
546  gMC->IsTrackDisappeared() ) {
547  TLorentzVector fPosOut, fMomOut;
548  gMC->TrackPosition(fPosOut);
549  gMC->TrackMomentum(fMomOut);
550 
551  // In fact neutrals can not reach this point unless they were booked
552  // for this sensitive volum explicitely; keep charge check here though;
553  if (wanted || (gMC->TrackCharge() && fELoss)) {
554  std::pair<int, int> parents = EicBlackHole::GetParentIDs();
555 
556  //printf("track: %3d; pdg: %d; parents: %4d %4d\n", trackID, particle->GetPdgCode(), parents.first, parents.second);
557 
558  // printf("%7.3f %7.3f %d %d %d %d\n", fPosIn.Vect().Perp(), fPosOut.Vect().Perp(), effectiveSteppingType == qOneStepOneHit,
559  // gMC->IsTrackExiting(), gMC->IsTrackStop(), gMC->IsTrackDisappeared());
560  // For now be dumb and record full path; figure out how to deal with sensor IDs later;
561  AddMoCaPoint(trackID, parents.first, parents.second, volumeID,
562  GetNodeMultiIndex(), fPosIn.Vect(), fPosOut.Vect(),
563  // NB: fStep is not necessarily calculabe from fPosIn and fPosOut
564  // for a curved track -> keep as extra variable;
565  fMomIn.Vect(), fMomOut.Vect(), fTime, fLength, fELoss, fStep);
566  } //if
567 
568  ((PndStack*)gMC->GetStack())->AddPoint(DetectorId(fDetType));
569 
570  // Reset working stepping variables;
571  if (effectiveSteppingType == qOneStepOneHit) ResetSteppingVariables();
572  } //if
573 
574  return kTRUE;
575 } // EicDetector::ProcessHits()
576 
577 // ---------------------------------------------------------------------------------------
578 
579 TClonesArray* EicDetector::GetCollection(Int_t iColl) const
580 {
581  if (iColl == 0)
583  else
584  return NULL;
585 } // EicDetector::GetCollection()
586 
587 // ---------------------------------------------------------------------------------------
588 
590 {
591  // Once the geometry is defined (so volume names are associated with
592  // unique IDs), calculate binary signatures for all maps;
594 
596 } // EicDetector::Initialize()
597 
598 // ---------------------------------------------------------------------------------------
599 #if _LATER_
601 {
602  // Open ROOT file;
603  fFakeMoCaDatabaseFile = TString(outFileName);
604  dbFile = new TFile(fFakeMoCaDatabaseFile, "RECREATE");
605 
606  // Declare ROOT tree which will hold entries;
607  dbTree = new TTree(dname->Name() + "EicFakeMoCaPointDatabase",
608  dname->Name() + "fake MC hit database");
609 
610  // Alocate buffer variable; think on split, etc; later;
611  dbEntry = new EicFakeMoCaPointDbEntry();
612  TBranch *branch = dbTree->Branch("EicFakeMoCaPointDbEntry",
613  "EicFakeMoCaPointDbEntry", &dbEntry, 16000, 1);
614  branch->SetFile(outFileName);
615 
616  TFile fgeo(GetGeometryFileName());
617 
618  // Yes, expect object with a predefined name; do a better check later;
619  fgeo.GetObject(dname->Name() + "EnergyCutOffTable", _fCutOffMap);
620  assert(_fCutOffMap);
621 
622  fgeo.Close();
623 
624  // And allocate the DB array right away;
625  //fakeDB->allocateDbMap();
626 
627  return 0;
628 } // EicDetector::createFakeMoCaDatabase()
629 #endif
630 // ---------------------------------------------------------------------------------------
631 
633 {
634  // Write out energy monitor histogram(s);
635  for(unsigned mn=0; mn<mEnergyMonitorVolumes.size(); mn++) {
637 
638  monitor->mHistogram->Write();
639  } //for mn
640 
641  if (gptr || vptr /*|| (_fCutOffMap && !dbFile)*/)
642  {
643  FairRun *fRun = FairRun::Instance();
644 
645  // I guess there is no need to save/restore current directory here?;
646  fRun->GetOutputFile()->cd();
647 
648  if (gptr) gptr->Write(dname->Name() + "GeoParData");
649 
650  // As of 2013/09/29 just dump detector geometry ROOT record into the MC output
651  // file; disk space overhead is indeed small; MC files can now be used to import
652  // detector geometry in calls like EicEmc() which comes handy for instance for
653  // safe shower database creation;
654  if (vptr) vptr->Write(dname->Name() + "GeantGeoWrapper");
655 
656  // And also save fast simulation cutoff parameters if specified; but only if fake
657  // database creation is NOT requested (since otherwise cutoff table is in fact
658  // imported rather than created);
659  //if (_fCutOffMap && !dbFile)
660  //fRun->GetOutputFile()->WriteObject(_fCutOffMap, dname->Name() + "EnergyCutOffTable");
661  } //if
662 
663 #if _LATER_
664  // Yes, goes to a separate file;
665  if (dbFile)
666  {
667  dbFile->Write();
668  dbFile->WriteObject(_fCutOffMap, dname->Name() + "EnergyCutOffTable");
669  // Crashes paramater database dump; WHY?; fix later;
670  //dbFile->Close();
671 
672  // Do this better later, please!;
673  //FairRun *fRun = FairRun::Instance();
674  //fRun->GetOutputFile()->cd();
675  } //if
676 #endif
677 } // EicDetector::FinishRun()
678 
679 // ---------------------------------------------------------------------------------------
680 
682  fEicMoCaPointCollection->Delete();
683  //fEicFakeMoCaPointCollection->Delete();
684 
685  //ResetParameters();
686 } // EicDetector::Reset()
687 
688 // ---------------------------------------------------------------------------------------
689 
690 void EicDetector::Print() const
691 {
692  Int_t nHits = fEicMoCaPointCollection->GetEntriesFast();
693  cout<<"-I- Eic"<< dname->Name() <<": " << nHits << " points registered in this event." << endl;
694 
695  if(fVerboseLevel > 1)
696  for(Int_t i=0; i<nHits; i++) (*fEicMoCaPointCollection)[i]->Print();
697 } // EicDetector::Print()
698 
699 // ---------------------------------------------------------------------------------------
700 
702 {
703  std::cout<<" --- Building " << dname->NAME() << " Geometry ---"<<std::endl;
704  std::cout << GetGeometryFileName() << std::endl;
705 
706  if(GetGeometryFileName().EndsWith(".root")) {
707  // For now assume it is quite natural to pack basic geometric parameter
708  // information into the same ROOT file used to describe the GEANT geometry;
709  // ideally this should go into GeoPar stuff, but I fail to make it working;
710  // so for now just infect the output MC file with this class information;
711  // if this ever becomes problematic (say, because of compatibility issues),
712  // consider to look once again into the GeoPar mechanism available in FairRoot;
713  {
714  TFile fgeo(GetGeometryFileName());
715 
716  // Yes, expect object with a predefined name;
717  fgeo.GetObject(dname->Name() + "GeoParData", gptr);
718 
719  // May want to print out some service info (and then perhaps exit);
720  if (gptr && mPrintGeometryInfoFlag) {
721  gptr->Print();
722 
723  if (mPrintGeometryInfoOption.EqualTo("and exit")) exit(0);
724  } //if
725  if (gptr && !mAttachedFilePrintoutRequestName.IsNull()) {
727 
728  if (mAttachedFilePrintoutOption.EqualTo("and exit")) exit(0);
729  } //if
730 
731  // Loop through all maps and declare sensitive volumes (top-level
732  // volume names of all maps); do this only if no sensitive volumes were
733  // declared by hand already (then assume user is able to define him/herself
734  // which ones does he want; perhaps activate only fiber cores and not absorber
735  // volumes to save CPU time);
737  for(int iq=0; iq<gptr->GetMapNum(); iq++)
738  {
739  const EicGeoMap *fmap = gptr->GetMapPtrViaMapID(iq);
740 
741  //printf("@SV@ %s\n", fmap->GetInnermostVolumeName()->Data());
742  // No 2-d argument -> will use stepping type defined at detector initialization;
744  } //if..for iq
745 
746  fgeo.GetObject(dname->Name() + "GeantGeoWrapper", vptr);
747 
748  fgeo.Close();
749  }
750 
751  // And make a standard FairRoot call to parse GEANT geometry information;
753 
754  // Once all the volumes are added to the geometry (so their IDs are known), create
755  // step enforced volume lookup table;
756  if (gptr && !strcmp(FairRun::Instance()->GetName(), "TGeant4")) {
757  // Could not have this all been arranged in a bit more straighforward way?;
759  FairGeoInterface *fgInterface = fgLoader->getGeoInterface();
760  FairGeoMedia *fgMedia = fgInterface->getMedia();
761 
762  for (std::set<TString>::iterator it=gptr->GetStepEnforcedVolumes().begin();
763  it!=gptr->GetStepEnforcedVolumes().end(); ++it) {
764  TGeoVolume *volume = gGeoManager->GetVolume(it->Data());
765 
766  // Well, volume with such name should exist, otherwise something went wrong;
767  if (!volume)
768  fLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Step enforcement for unknown "
769  "volume attempted (%s)! \033[0m", it->Data());
770 
771  FairGeoMedium *fgMedium = fgMedia->getMedium(volume->GetMedium()->GetName());
772 
773  // Assume medium at this point exists for sure; extract max step value;
774  // FIXME: well, hardcode for now both 10 and 4?;
775  double params[10];
776  fgMedium->getMediumPar(params);
777 
778  gptr->AddStepEnforcedVolumeLookupEntry(volume->GetNumber(), params[4]);
779  } //for it
780  } //if
781 
782  //
783  // If ever return back to FairRoot GeoPar interface, need to call the same
784  // "par"-stuff as in the ASCII section below;
785  //
786  }
787  else {
789  FairGeoInterface* geoFace = geoLoad->getGeoInterface();
790  EicGeo* Geo = new EicGeo(dname->name());
792  geoFace->addGeoModule(Geo);
793 
794  Bool_t rc = geoFace->readSet(Geo);
795  if (rc)
796  Geo->create(geoLoad->getGeoBuilder());
797  else
798  std::cerr<< dname->Name() <<"Det:: geometry could not be read!"<<std::endl;
799 
800  TList* volList = Geo->getListOfVolumes();
801 
802  // store geo parameter
803  FairRun *fRun = FairRun::Instance();
805  {
806  EicGeoPar* par=(EicGeoPar*)(rtdb->getContainer(dname->Name() + "GeoPar"));
807 #if _LATER_
808  TObjArray *fSensNodes = par->GetGeoSensitiveNodes();
809  TObjArray *fPassNodes = par->GetGeoPassiveNodes();
810 
811  TListIter iter(volList);
812  FairGeoNode* node = NULL;
813  FairGeoVolume *aVol=NULL;
814 
815  while( (node = (FairGeoNode*)iter.Next()) ) {
816  aVol = dynamic_cast<FairGeoVolume*> ( node );
817  if ( node->isSensitive() ) {
818  fSensNodes->AddLast( aVol );
819  }else{
820  fPassNodes->AddLast( aVol );
821  }
822  }
823 #endif
824 
825  par->setChanged();
826  par->setInputVersion(fRun->GetRunId(),1);
827 
828  ProcessNodes ( volList );
829  }
830  } // if
831 } // EicDetector::ConstructGeometry()
832 
833 // ---------------------------------------------------------------------------------------
834