GEARS
Geant4 Example Application with Rich features and Small footprints
gears.cc
Go to the documentation of this file.
1 
5 #include <vector>
6 using namespace std;
7 #include <G4SteppingManager.hh>
8 #include <G4SteppingVerbose.hh>
12 class Output : public G4SteppingVerbose {
13 protected:
14  void Record();
15 public:
16  Output();
17  void TrackingStarted() {
18  G4SteppingVerbose::TrackingStarted();
19  Record();
20  }
21  void StepInfo() {
22  G4SteppingVerbose::StepInfo();
23  Record();
24  }
25  void Reset() {
26  trk.clear();
27  stp.clear();
28  vlm.clear();
29  pro.clear();
30  pdg.clear();
31  pid.clear();
32  xx.clear();
33  yy.clear();
34  zz.clear();
35  dt.clear();
36  de.clear();
37  dl.clear();
38  l.clear();
39  x.clear();
40  y.clear();
41  z.clear();
42  t.clear();
43  k.clear();
44  p.clear();
45  px.clear();
46  py.clear();
47  pz.clear();
48  q.clear();
49  et.clear();
50  }
51  void SetSteppingVerbose(int level) { fManager->SetVerboseLevel(level); }
52  int GetSteppingVerbose() { return fManager->GetverboseLevel(); }
53 
54  vector<int> trk;
55  vector<int> stp;
56  vector<int> vlm;
57  vector<int> pro;
58  vector<int> pdg;
59  vector<int> pid;
60  vector<double> xx;
61  vector<double> yy;
62  vector<double> zz;
63  vector<double> dt;
64  vector<double> de;
65  vector<double> dl;
66  vector<double> l;
67  vector<double> x;
68  vector<double> y;
69  vector<double> z;
70  vector<double> t;
71  vector<double> k;
72  vector<double> p;
73  vector<double> px;
74  vector<double> py;
75  vector<double> pz;
76  vector<double> q;
77  vector<double> et;
78 };
79 //______________________________________________________________________________
80 //
81 #include <G4AnalysisManager.hh>
82 Output::Output() : G4SteppingVerbose() {
83  auto manager = G4AnalysisManager::Instance();
84  manager->CreateNtuple("t", "Geant4 step points");
85  manager->CreateNtupleIColumn("n"); // total number of recorded hits
86  manager->CreateNtupleIColumn("m"); // max copy number of sensitive volume
87  manager->CreateNtupleIColumn("trk", trk);
88  manager->CreateNtupleIColumn("stp", stp);
89  manager->CreateNtupleIColumn("vlm", vlm);
90  manager->CreateNtupleIColumn("pro", pro);
91  manager->CreateNtupleIColumn("pdg", pdg);
92  manager->CreateNtupleIColumn("pid", pid);
93  manager->CreateNtupleDColumn("xx", xx);
94  manager->CreateNtupleDColumn("yy", yy);
95  manager->CreateNtupleDColumn("zz", zz);
96  manager->CreateNtupleDColumn("dt", dt);
97  manager->CreateNtupleDColumn("de", de);
98  manager->CreateNtupleDColumn("dl", dl);
99  manager->CreateNtupleDColumn("l", l);
100  manager->CreateNtupleDColumn("x", x);
101  manager->CreateNtupleDColumn("y", y);
102  manager->CreateNtupleDColumn("z", z);
103  manager->CreateNtupleDColumn("t", t);
104  manager->CreateNtupleDColumn("k", k);
105  manager->CreateNtupleDColumn("p", p);
106  manager->CreateNtupleDColumn("px", px);
107  manager->CreateNtupleDColumn("py", py);
108  manager->CreateNtupleDColumn("pz", pz);
109  manager->CreateNtupleDColumn("q", q);
110  manager->CreateNtupleDColumn("et", et);
111  manager->FinishNtuple();
112 }
113 //______________________________________________________________________________
114 //
115 #include <G4NavigationHistory.hh>
117  if (GetSilent() == 1) // CopyState() won't be called in G4SteppingVerbose
118  CopyState(); // point fTrack, fStep, etc. to right places
119 
120  G4TouchableHandle handle = fStep->GetPreStepPoint()->GetTouchableHandle();
121  int copyNo = handle->GetReplicaNumber();
122  if (copyNo <= 0)
123  return; // skip uninteresting volumes (copy No. of world == 0)
124  if (trk.size() >= 10000) {
125  G4cout << "GEARS: # of step points >=10000. Recording stopped." << G4endl;
126  fTrack->SetTrackStatus(fKillTrackAndSecondaries);
127  return;
128  }
129 
130  trk.push_back(fTrack->GetTrackID());
131  stp.push_back(fTrack->GetCurrentStepNumber());
132  vlm.push_back(copyNo);
133  pdg.push_back(fTrack->GetDefinition()->GetPDGEncoding());
134  pid.push_back(fTrack->GetParentID());
135  if (stp.back() == 0) { // step zero
136  if (pid.back() != 0) // not primary particle
137  pro.push_back(fTrack->GetCreatorProcess()->GetProcessType() * 1000 +
138  fTrack->GetCreatorProcess()->GetProcessSubType());
139  else
140  pro.push_back(1000); // primary particle
141  } else {
142  const G4VProcess *pr = fStep->GetPostStepPoint()->GetProcessDefinedStep();
143  if (pr)
144  pro.push_back(pr->GetProcessType() * 1000 + pr->GetProcessSubType());
145  else
146  pro.push_back(900); // not sure why pr can be zero
147  }
148 
149  k.push_back(fTrack->GetKineticEnergy() / CLHEP::keV);
150  p.push_back(fTrack->GetMomentum().mag() / CLHEP::keV);
151  q.push_back(fStep->GetPostStepPoint()->GetCharge());
152  l.push_back(fTrack->GetTrackLength() / CLHEP::mm);
153 
154  px.push_back(fTrack->GetMomentumDirection().x());
155  py.push_back(fTrack->GetMomentumDirection().y());
156  pz.push_back(fTrack->GetMomentumDirection().z());
157  de.push_back(fStep->GetTotalEnergyDeposit() / CLHEP::keV);
158  dl.push_back(fTrack->GetStepLength() / CLHEP::mm);
159 
160  t.push_back(fTrack->GetGlobalTime() / CLHEP::ns);
161  x.push_back(fTrack->GetPosition().x() / CLHEP::mm);
162  y.push_back(fTrack->GetPosition().y() / CLHEP::mm);
163  z.push_back(fTrack->GetPosition().z() / CLHEP::mm);
164 
165  G4ThreeVector pos = handle->GetHistory()->GetTopTransform().TransformPoint(
166  fStep->GetPostStepPoint()->GetPosition());
167  xx.push_back(pos.x() / CLHEP::mm);
168  yy.push_back(pos.y() / CLHEP::mm);
169  zz.push_back(pos.z() / CLHEP::mm);
170  dt.push_back(fTrack->GetLocalTime() / CLHEP::ns);
171 
172  if (de.back() > 0 &&
173  G4StrUtil::contains(handle->GetVolume()->GetName(), "(S)")) {
174  if (et.size() < (unsigned int)copyNo + 1)
175  et.resize((unsigned int)copyNo + 1);
176  et[copyNo] += de.back();
177  et[0] += de.back();
178  }
179 }
180 //______________________________________________________________________________
181 //
182 #include <G4OpticalSurface.hh>
189  G4String name;
190  G4String v1;
191  G4String v2;
192  G4OpticalSurface *optic;
194 };
195 //______________________________________________________________________________
196 //
197 #include <G4tgrLineProcessor.hh>
201 class LineProcessor : public G4tgrLineProcessor {
202 private:
203  G4MaterialPropertiesTable *
204  CreateMaterialPropertiesTable(const vector<G4String> &words,
205  size_t idxOfWords);
206 
207 public:
208  LineProcessor() : G4tgrLineProcessor(), Border(0) {};
210  while (Border) { // deleting G4OpticalSurface is done in Geant4
211  BorderSurface *next = Border->next;
212  delete Border;
213  Border = next;
214  }
215  }
227  G4bool ProcessLine(const vector<G4String> &words);
229 };
230 //______________________________________________________________________________
231 //
232 #include <G4NistManager.hh>
233 #include <G4UImessenger.hh>
234 #include <G4tgbMaterialMgr.hh>
235 G4bool LineProcessor::ProcessLine(const vector<G4String> &words) {
236  // process default text geometry tags
237  G4bool processed = G4tgrLineProcessor::ProcessLine(words);
238  if (processed)
239  return true; // no new tags involved
240 
241  // process added tags: prop & surf
242  G4String tag = words[0];
243  G4StrUtil::to_lower(tag); // to lower cases
244  if (tag.substr(0, 5) == ":prop") { // set optical properties of a material
245  G4NistManager *mgr = G4NistManager::Instance();
246  mgr->SetVerbose(2);
247  G4Material *m = mgr->FindOrBuildMaterial(words[1]);
248  if (m == NULL) // if not in NIST, then build in tgb
249  m = G4tgbMaterialMgr::GetInstance()->FindOrBuildG4Material(words[1]);
250  G4cout << "GEARS: Set optical properties of " << words[1] << ":" << G4endl;
251  m->SetMaterialPropertiesTable(CreateMaterialPropertiesTable(words, 2));
252  return true;
253  } else if (tag.substr(0, 5) == ":surf") { // define an optical surface
254  auto bdr = new BorderSurface;
255  bdr->next = Border; // save current border pointer
256  Border = bdr; // overwrite current border pointer
257  bdr->name = words[1];
258  bdr->v1 = words[2];
259  bdr->v2 = words[3];
260  bdr->optic = new G4OpticalSurface(words[1]);
261 
262  G4cout << "GEARS: Set optical properties of " << bdr->name << ":"<< G4endl;
263  size_t i = 4;
264  while (i < words.size()) { // loop over optical surface setup lines
265  G4String setting = words[i], value = words[i + 1];
266  G4StrUtil::to_lower(setting); G4StrUtil::to_lower(value);
267  if (setting == "property") {
268  i++;
269  break;
270  } else if (setting == "type") {
271  if (value == "dielectric_metal")
272  bdr->optic->SetType(dielectric_metal);
273  else if (value == "dielectric_dielectric")
274  bdr->optic->SetType(dielectric_dielectric);
275  else if (value == "dielectric_lut")
276  bdr->optic->SetType(dielectric_LUT);
277  else if (value == "dielectric_lutdavis")
278  bdr->optic->SetType(dielectric_LUTDAVIS);
279  else if (value == "dielectric_dichroic")
280  bdr->optic->SetType(dielectric_dichroic);
281  else if (value == "firsov")
282  bdr->optic->SetType(firsov);
283  else if (value == "x_ray")
284  bdr->optic->SetType(x_ray);
285  else if (value == "coated")
286  bdr->optic->SetType(coated);
287  else
288  G4cout << "GEARS: Ignore unknown surface type " << value << G4endl;
289  G4cout << "GEARS: type = " << value << G4endl;
290  } else if (setting == "model") {
291  if (value == "glisur")
292  bdr->optic->SetModel(glisur);
293  else if (value == "unified")
294  bdr->optic->SetModel(unified);
295  else if (value == "lut")
296  bdr->optic->SetModel(LUT);
297  else if (value == "davis")
298  bdr->optic->SetModel(DAVIS);
299  else if (value == "dichroic")
300  bdr->optic->SetModel(dichroic);
301  else
302  G4cout << "GEARS: Ignore unknown surface model " << value << G4endl;
303  G4cout << "GEARS: model = " << value << G4endl;
304  } else if (setting == "finish") {
305  if (value == "polished") bdr->optic->SetFinish(polished);
306  else if (value == "polishedfrontpainted") bdr->optic->SetFinish(polishedfrontpainted);
307  else if (value == "polishedbackpainted") bdr->optic->SetFinish(polishedbackpainted);
308  else if (value == "ground") bdr->optic->SetFinish(ground);
309  else if (value == "groundfrontpainted") bdr->optic->SetFinish(groundfrontpainted);
310  else if (value == "groundbackpainted") bdr->optic->SetFinish(groundbackpainted);
311  // --- LBNL LUT Model Finishes ---
312  else if (value == "polishedlumirrorair") bdr->optic->SetFinish(polishedlumirrorair);
313  else if (value == "polishedlumirrorglue") bdr->optic->SetFinish(polishedlumirrorglue);
314  else if (value == "polishedair") bdr->optic->SetFinish(polishedair);
315  else if (value == "polishedteflonair") bdr->optic->SetFinish(polishedteflonair);
316  else if (value == "polishedtioair") bdr->optic->SetFinish(polishedtioair);
317  else if (value == "polishedtyvekair") bdr->optic->SetFinish(polishedtyvekair);
318  else if (value == "polishedvm2000air") bdr->optic->SetFinish(polishedvm2000air);
319  else if (value == "polishedvm2000glue") bdr->optic->SetFinish(polishedvm2000glue);
320 
321  else if (value == "etchedlumirrorair") bdr->optic->SetFinish(etchedlumirrorair);
322  else if (value == "etchedlumirrorglue") bdr->optic->SetFinish(etchedlumirrorglue);
323  else if (value == "etchedair") bdr->optic->SetFinish(etchedair);
324  else if (value == "etchedteflonair") bdr->optic->SetFinish(etchedteflonair);
325  else if (value == "etchedtioair") bdr->optic->SetFinish(etchedtioair);
326  else if (value == "etchedtyvekair") bdr->optic->SetFinish(etchedtyvekair);
327  else if (value == "etchedvm2000air") bdr->optic->SetFinish(etchedvm2000air);
328  else if (value == "etchedvm2000glue") bdr->optic->SetFinish(etchedvm2000glue);
329 
330  else if (value == "groundlumirrorair") bdr->optic->SetFinish(groundlumirrorair);
331  else if (value == "groundlumirrorglue") bdr->optic->SetFinish(groundlumirrorglue);
332  else if (value == "groundair") bdr->optic->SetFinish(groundair);
333  else if (value == "groundteflonair") bdr->optic->SetFinish(groundteflonair);
334  else if (value == "groundtioair") bdr->optic->SetFinish(groundtioair);
335  else if (value == "groundtyvekair") bdr->optic->SetFinish(groundtyvekair);
336  else if (value == "groundvm2000air") bdr->optic->SetFinish(groundvm2000air);
337  else if (value == "groundvm2000glue") bdr->optic->SetFinish(groundvm2000glue);
338  // --- DAVIS Model Finishes (Lowercase Conversion) ---
339  else if (value == "rough_lut") bdr->optic->SetFinish(Rough_LUT);
340  else if (value == "roughteflon_lut") bdr->optic->SetFinish(RoughTeflon_LUT);
341  else if (value == "roughesr_lut") bdr->optic->SetFinish(RoughESR_LUT);
342  else if (value == "roughesrgrease_lut") bdr->optic->SetFinish(RoughESRGrease_LUT);
343  else if (value == "polished_lut") bdr->optic->SetFinish(Polished_LUT);
344  else if (value == "polishedteflon_lut") bdr->optic->SetFinish(PolishedTeflon_LUT);
345  else if (value == "polishedesr_lut") bdr->optic->SetFinish(PolishedESR_LUT);
346  else if (value == "polishedesrgrease_lut") bdr->optic->SetFinish(PolishedESRGrease_LUT);
347  else if (value == "detector_lut") bdr->optic->SetFinish(Detector_LUT);
348 
349  else {
350  G4cout << "GEARS: Unknown surface finish: " << value << "!" << G4endl;
351  abort();
352  }
353  G4cout << "GEARS: finish = " << value << G4endl;
354  } else if (setting == "sigma_alpha") {
355  bdr->optic->SetSigmaAlpha(G4UIcommand::ConvertToDouble(value));
356  G4cout<<"GEARS: sigma_alpha = "<<bdr->optic->GetSigmaAlpha()<<G4endl;
357  } else
358  G4cout << "GEARS: Ignore unknown surface setting " << value << G4endl;
359  i += 2;
360  }
361  if (i < words.size()) // break while loop because of "property"
362  bdr->optic->SetMaterialPropertiesTable(
363  CreateMaterialPropertiesTable(words, i));
364  return true;
365  } else
366  return false;
367 }
368 //______________________________________________________________________________
369 //
370 #include <G4tgrUtils.hh>
371 G4MaterialPropertiesTable *
372 LineProcessor::CreateMaterialPropertiesTable(const vector<G4String> &words,
373  size_t idxOfWords) {
374  bool photonEnergyUnDefined = true;
375  int cnt = 0; // number of photon energy values
376  double *energies = NULL; // photon energy values
377  auto table = new G4MaterialPropertiesTable();
378  for (size_t i = idxOfWords; i < words.size(); i++) {
379  G4String property = words[i];
380  G4StrUtil::to_upper(property);
381  if (G4StrUtil::contains(property, "TIMECONSTANT") ||
382  G4StrUtil::contains(property, "SCINTILLATIONYIELD") ||
383  property == "RESOLUTIONSCALE" || property == "YIELDRATIO") {
384  table->AddConstProperty(property, G4tgrUtils::GetDouble(words[i + 1]));
385  G4cout << "GEARS: " << property << " = " << words[i + 1] << G4endl;
386  i++; // property value has been used
387  } else if (property.substr(0, 12) == "PHOTON_ENERG") {
388  photonEnergyUnDefined = false;
389  cnt = G4UIcommand::ConvertToInt(words[i + 1]); // get array size
390  energies = new double[cnt]; // create energy array
391  for (int j = 0; j < cnt; j++)
392  energies[j] = G4tgrUtils::GetDouble(words[i + 2 + j]);
393  i = i + 1 + cnt; // array has been used
394  } else { // wavelength-dependent properties
395  if (photonEnergyUnDefined) {
396  G4cout << "GEARS: photon energies undefined, "
397  << "ignore all wavelength-dependent properties!" << G4endl;
398  break;
399  }
400  double *values = new double[cnt];
401  for (int j = 0; j < cnt; j++)
402  values[j] = G4tgrUtils::GetDouble(words[i + 1 + j]);
403  G4cout << "GEARS: " << property << " = " << values[0] << ", " << values[1]
404  << ", ..." << G4endl;
405  table->AddProperty(property, energies, values, cnt);
406  delete[] values;
407  i = i + cnt;
408  }
409  }
410  delete[] energies;
411  return table;
412 }
413 //______________________________________________________________________________
414 //
415 #include <G4tgbDetectorBuilder.hh>
419 class TextDetectorBuilder : public G4tgbDetectorBuilder {
420 public:
421  TextDetectorBuilder() : G4tgbDetectorBuilder() {
422  fLineProcessor = new LineProcessor();
423  }
424  ~TextDetectorBuilder() { delete fLineProcessor; }
425  const G4tgrVolume *ReadDetector();
426 
429  G4VPhysicalVolume *ConstructDetector(const G4tgrVolume *topVol);
430 
431 private:
432  LineProcessor *fLineProcessor;
433 };
434 //______________________________________________________________________________
435 //
436 #include <G4tgbVolumeMgr.hh>
437 #include <G4tgrFileReader.hh>
438 #include <G4tgrVolumeMgr.hh>
439 const G4tgrVolume *TextDetectorBuilder::ReadDetector() {
440  G4tgrFileReader *reader = G4tgrFileReader::GetInstance();
441  reader->SetLineProcessor(fLineProcessor);
442  reader->ReadFiles();
443  G4tgrVolumeMgr *mgr = G4tgrVolumeMgr::GetInstance();
444  const G4tgrVolume *world = mgr->GetTopVolume();
445  return world;
446 }
447 //______________________________________________________________________________
448 //
449 #include <G4LogicalBorderSurface.hh>
450 G4VPhysicalVolume *
451 TextDetectorBuilder::ConstructDetector(const G4tgrVolume *topVol) {
452  G4VPhysicalVolume *world = G4tgbDetectorBuilder::ConstructDetector(topVol);
453 
454  G4tgbVolumeMgr *tgbVolmgr = G4tgbVolumeMgr::GetInstance();
455  BorderSurface *border = fLineProcessor->Border;
456  while (border) {
457  G4String physV1 = border->v1.substr(0, border->v1.find(":"));
458  G4String physV2 = border->v2.substr(0, border->v2.find(":"));
459  int copyNo1 = atoi(border->v1.substr(border->v1.find(":") + 1).data());
460  int copyNo2 = atoi(border->v2.substr(border->v2.find(":") + 1).data());
461  G4LogicalVolume *m1 = tgbVolmgr->FindG4PhysVol(physV1)->GetMotherLogical();
462  G4LogicalVolume *m2 = tgbVolmgr->FindG4PhysVol(physV2)->GetMotherLogical();
463  // search for physics volumes on the sides of the border
464  G4VPhysicalVolume *v1 = 0, *v2 = 0;
465  for (int i = 0; i < (int)m1->GetNoDaughters(); i++) {
466  v1 = m1->GetDaughter(i);
467  if (v1->GetCopyNo() == copyNo1)
468  break;
469  }
470  for (int i = 0; i < (int)m2->GetNoDaughters(); i++) {
471  v2 = m2->GetDaughter(i);
472  if (v2->GetCopyNo() == copyNo2)
473  break;
474  }
475  if (v1 && v2) {
476  new G4LogicalBorderSurface(border->name, v1, v2, border->optic);
477  G4cout << "Border surface " << border->name << " in between " << physV1
478  << ":" << copyNo1 << " and " << physV2 << ":" << copyNo2
479  << " added" << G4endl;
480  }
481  border = border->next;
482  }
483  return world;
484 }
485 //______________________________________________________________________________
486 //
487 #include <G4UIcmdWith3VectorAndUnit.hh>
488 #include <G4UIcmdWithAString.hh>
489 #include <G4UIdirectory.hh>
490 #include <G4UImessenger.hh>
491 #include <G4VUserDetectorConstruction.hh>
506 class Detector : public G4VUserDetectorConstruction, public G4UImessenger {
507 public:
508  Detector();
510  delete fCmdSetB;
511  delete fCmdSrc;
512  delete fCmdOut;
513  }
514  G4VPhysicalVolume *Construct();
515  void SetNewValue(G4UIcommand *cmd, G4String value);
516 
517 private:
518  G4UIcmdWith3VectorAndUnit *fCmdSetB;
519  G4UIcmdWithAString *fCmdSrc;
520  G4UIcmdWithAString *fCmdOut;
521  G4UIcommand *fCmdLmt;
522  G4VPhysicalVolume *fWorld;
523 };
524 //______________________________________________________________________________
525 //
527  : G4VUserDetectorConstruction(), G4UImessenger(), fWorld(0) {
528 #ifdef hasGDML
529  fCmdOut = new G4UIcmdWithAString("/geometry/export", this);
530  fCmdOut->SetGuidance("Export geometry gdml file name");
531  fCmdOut->SetParameterName("gdml geometry output", false);
532  fCmdOut->AvailableForStates(G4State_Idle);
533 #else
534  fCmdOut = 0;
535 #endif
536 
537  fCmdSrc = new G4UIcmdWithAString("/geometry/source", this);
538  fCmdSrc->SetGuidance("Set geometry source file name");
539  fCmdSrc->SetParameterName("text geometry input", false);
540  fCmdSrc->AvailableForStates(G4State_PreInit);
541 
542  fCmdLmt = new G4UIcommand("/tracking/setStepLimit", this);
543  fCmdLmt->SetGuidance("set max step length for a logical volume");
544  fCmdLmt->AvailableForStates(G4State_Idle);
545  G4UIparameter *p0 = new G4UIparameter("logical volume name", 's', false);
546  G4UIparameter *p1 = new G4UIparameter("step length in mm", 'd', false);
547  fCmdLmt->SetParameter(p0);
548  fCmdLmt->SetParameter(p1);
549 
550  fCmdSetB = new G4UIcmdWith3VectorAndUnit("/geometry/SetB", this);
551  fCmdSetB->SetGuidance("Set uniform magnetic field value.");
552  fCmdSetB->SetParameterName("Bx", "By", "Bz", false);
553  fCmdSetB->SetUnitCategory("Magnetic flux density");
554 }
555 //______________________________________________________________________________
556 //
557 #include <G4FieldManager.hh>
558 #include <G4LogicalVolumeStore.hh>
559 #include <G4TransportationManager.hh>
560 #include <G4UniformMagField.hh>
561 #include <G4UserLimits.hh>
562 #ifdef hasGDML
563 #include "G4GDMLParser.hh"
564 #endif
565 void Detector::SetNewValue(G4UIcommand *cmd, G4String value) {
566  if (cmd == fCmdSetB) {
567  auto field = new G4UniformMagField(0, 0, 0);
568  field->SetFieldValue(fCmdSetB->GetNew3VectorValue(value));
569  G4FieldManager *mgr =
570  G4TransportationManager::GetTransportationManager()->GetFieldManager();
571  mgr->SetDetectorField(field);
572  mgr->CreateChordFinder(field);
573  G4cout << "GEARS: Magnetic field is set to " << value << G4endl;
574 #ifdef hasGDML
575  } else if (cmd == fCmdOut) {
576  G4GDMLParser paser;
577  paser.Write(value, fWorld);
578 #endif
579  } else if (cmd == fCmdLmt) {
580  istringstream iss(value);
581  G4String vlm, limit;
582  iss >> vlm >> limit;
583  auto v = G4LogicalVolumeStore::GetInstance()->GetVolume(vlm);
584  if (v) {
585  v->SetUserLimits(new G4UserLimits(stof(limit)));
586  G4cout << "GEARS: max step length in " << vlm << ": " << limit << " mm"
587  << G4endl;
588  }
589  } else { // cmd==fCmdSrc
590  if (value.substr(value.length() - 4) != "gdml") { // text geometry input
591  G4tgbVolumeMgr *mgr = G4tgbVolumeMgr::GetInstance();
592  mgr->AddTextFile(value);
593  auto tgb = new TextDetectorBuilder;
594  mgr->SetDetectorBuilder(tgb);
595  fWorld = mgr->ReadAndConstructDetector();
596 #ifdef hasGDML
597  } else { // GDML input
598  G4GDMLParser parser;
599  parser.Read(value);
600  fWorld = parser.GetWorldVolume();
601 #endif
602  }
603  }
604 }
605 //______________________________________________________________________________
606 //
607 #include "G4Box.hh"
608 #include "G4PVPlacement.hh"
609 G4VPhysicalVolume *Detector::Construct() {
610  if (fWorld == NULL) {
611  G4cout << "GEARS: no detector specified, set to a 10x10x10 m^3 box."
612  << G4endl;
613  auto box = new G4Box("hall", 5 * CLHEP::m, 5 * CLHEP::m, 5 * CLHEP::m);
614  G4NistManager *nist = G4NistManager::Instance();
615  G4Material *vacuum = nist->FindOrBuildMaterial("G4_Galactic");
616  auto v = new G4LogicalVolume(box, vacuum, "hall");
617  fWorld = new G4PVPlacement(0, G4ThreeVector(), v, "hall", 0, 0, 0);
618  }
619  return fWorld;
620 }
621 //______________________________________________________________________________
622 //
623 #include <G4GeneralParticleSource.hh>
624 #include <G4VUserPrimaryGeneratorAction.hh>
628 class Generator : public G4VUserPrimaryGeneratorAction {
629 private:
630  G4GeneralParticleSource *fSource;
631 
632 public:
633  Generator() : G4VUserPrimaryGeneratorAction(), fSource(0) {
634  fSource = new G4GeneralParticleSource;
635  }
636  virtual ~Generator() { delete fSource; }
637  virtual void GeneratePrimaries(G4Event *evt) {
638  fSource->GeneratePrimaryVertex(evt);
639  }
640 };
641 //______________________________________________________________________________
642 //
643 #include <G4Run.hh>
644 #include <G4RunManagerFactory.hh>
645 #include <G4UserRunAction.hh>
649 class RunAction : public G4UserRunAction {
650 public:
651  void BeginOfRunAction(const G4Run *) {
652  auto a = G4AnalysisManager::Instance();
653  if (a->GetFileName() == "")
654  return;
655  a->OpenFile();
656  Output *o = ((Output *)G4VSteppingVerbose::GetInstance());
657  if (o->GetSteppingVerbose() == 0) { // in case of /tracking/verbose 0
658  o->SetSilent(1); // avoid screen dump
659  o->SetSteppingVerbose(1); // enable calling StepInfo() in
660  // G4SteppingManager
661  }
662  }
663  void EndOfRunAction(const G4Run *) {
664  auto a = G4AnalysisManager::Instance();
665  if (a->GetFileName() != "") {
666  a->Write();
667  a->CloseFile();
668  }
669  }
670 };
671 //______________________________________________________________________________
672 //
674  auto a = G4AnalysisManager::Instance();
675  Output *o = ((Output *)G4VSteppingVerbose::GetInstance());
676  if (a->GetFileName() != "" && o->stp.size() != 0) {
677  a->FillNtupleIColumn(0, o->stp.size());
678  a->FillNtupleIColumn(1, o->et.size() - 1);
679  a->AddNtupleRow();
680  } // save n-tuple if it is not empty and output file name is specified
681  o->Reset(); // reset Output member variables for new record
682 }
683 //______________________________________________________________________________
684 //
685 #include <G4UserEventAction.hh>
689 class EventAction : public G4UserEventAction {
690 public:
691  void EndOfEventAction(const G4Event *) { SaveAndResetEvent(); }
692 };
693 //______________________________________________________________________________
694 //
695 #include <G4UIcmdWithADoubleAndUnit.hh>
696 #include <G4UserStackingAction.hh>
700 class StackingAction : public G4UserStackingAction, public G4UImessenger {
701 private:
702  double fT0;
703  double fTimeWindow;
704  G4UIcmdWithADoubleAndUnit *fCmdT;
705 public:
707  : G4UserStackingAction(), G4UImessenger(), fT0(0), fTimeWindow(0),
708  fCmdT(0) {
709  fCmdT = new G4UIcmdWithADoubleAndUnit("/grdm/setTimeWindow", this);
710  fCmdT->SetGuidance("Time window to split a radioactive decay chain.");
711  fCmdT->SetGuidance("If a daughter nucleus appears after the window,");
712  fCmdT->SetGuidance("it is saved in a new entry in the output ntuple.");
713  fCmdT->SetGuidance("---Set it to <=0 to disable the splitting---");
714  fCmdT->SetParameterName("time window", false, true);
715  fCmdT->SetDefaultUnit("s");
716  fCmdT->AvailableForStates(G4State_PreInit, G4State_Idle);
717  }
718  ~StackingAction() { delete fCmdT; }
719  G4ClassificationOfNewTrack ClassifyNewTrack(const G4Track *trk) {
720  if (fTimeWindow <= 0)
721  return fUrgent; // no need to split
722  if (trk->GetGlobalTime() > fT0 + fTimeWindow)
723  return fWaiting; // split
724  else
725  return fUrgent; // too fast to be split
726  }
727  void NewStage() { // called after processing urgent trk, before waiting trk
728  if (fTimeWindow <= 0)
729  return; // do nothing if no time window is specified
730  Output *o = ((Output *)G4VSteppingVerbose::GetInstance());
731  fT0 = o->t.back(); // update the reference time to the latest decay time
732  SaveAndResetEvent(); // end an event manually
733  }
734  void SetNewValue(G4UIcommand *cmd, G4String value) {
735  if (cmd != fCmdT)
736  return;
737  fTimeWindow = fCmdT->GetNewDoubleValue(value);
738  }
739 };
740 //______________________________________________________________________________
741 //
742 #include <G4VUserActionInitialization.hh>
743 class Action : public G4VUserActionInitialization {
744  void Build() const {
745  SetUserAction(new RunAction);
746  SetUserAction(new Generator);
747  SetUserAction(new EventAction);
748  SetUserAction(new StackingAction);
749  }
750 };
751 //______________________________________________________________________________
752 //
753 #include <G4PhysListFactory.hh>
754 #include <G4ScoringManager.hh>
755 #include <G4StepLimiterPhysics.hh>
756 #include <G4UIExecutive.hh>
757 #include <G4UImanager.hh> // needed for g4.10 and above
758 #include <G4VisExecutive.hh>
762 int main(int argc, char **argv) {
763  // inherit G4SteppingVerbose instead of G4UserSteppingAction to record data
764  G4VSteppingVerbose::SetInstance(new Output); // must be before run manager
765  auto run =
766  G4RunManagerFactory::CreateRunManager(G4RunManagerType::SerialOnly);
767  G4PhysListFactory factory;
768  auto physics = factory.ReferencePhysList();
769  physics->RegisterPhysics(new G4StepLimiterPhysics());
770  run->SetUserInitialization(physics); // initialize physics
771  run->SetUserInitialization(new Detector); // initialize detector
772  run->SetUserInitialization(new Action); // initialize user actions
773  G4ScoringManager::GetScoringManager(); // enable built-in scoring cmds
774  G4UIExecutive *ui = nullptr; // assume batch mode
775  if (argc == 1) {
776  ui = new G4UIExecutive(argc, argv);
777  } // interactive mode
778  auto vis = new G4VisExecutive("quiet"); // visualization
779  vis->Initialize(); // do this after ui mode is decided
780  if (ui) { // interactive mode
781  ui->SessionStart(); // do this after vis
782  delete ui;
783  } else { // batch mode
784  G4String cmd = "/control/execute ";
785  G4UImanager::GetUIpointer()->ApplyCommand(cmd + argv[1]);
786  }
787  delete vis;
788  delete run;
789  return 0;
790 }
791 // -*- C++; indent-tabs-mode:nil; tab-width:2 -*-
792 // vim: ft=cpp:ts=2:sts=2:sw=2:et
vector< double > l
length of track till this point [mm]
Definition: gears.cc:66
virtual ~Generator()
Definition: gears.cc:636
void EndOfEventAction(const G4Event *)
Definition: gears.cc:691
vector< double > p
momentum [keV]
Definition: gears.cc:72
vector< double > zz
z [mm] (origin: center of local volume)
Definition: gears.cc:62
void EndOfRunAction(const G4Run *)
Close output file.
Definition: gears.cc:663
vector< int > pid
parent particle&#39;s PDG encoding
Definition: gears.cc:59
BorderSurface * Border
pointer to a BorderSurface object
Definition: gears.cc:228
~LineProcessor()
Definition: gears.cc:209
G4String v1
name of volume 1
Definition: gears.cc:190
vector< double > yy
y [mm] (origin: center of local volume)
Definition: gears.cc:61
Generator()
Definition: gears.cc:633
G4bool ProcessLine(const vector< G4String > &words)
Overwrite G4tgrLineProcessor::ProcessLine to add new tags.
Definition: gears.cc:235
vector< int > pdg
PDG encoding.
Definition: gears.cc:58
LineProcessor()
Definition: gears.cc:208
vector< double > q
charge [elementary charge]
Definition: gears.cc:76
vector< double > px
x component of momentum direction
Definition: gears.cc:73
void Record()
Record simulated data.
Definition: gears.cc:116
G4OpticalSurface * optic
point to G4OpticalSurface object
Definition: gears.cc:192
vector< double > k
kinetic energy [keV]
Definition: gears.cc:71
vector< double > dt
time elapsed from previous step point [ns]
Definition: gears.cc:63
void BeginOfRunAction(const G4Run *)
enable output if output file name is not empty
Definition: gears.cc:651
Definition: gears.cc:743
~StackingAction()
Definition: gears.cc:718
vector< double > z
z [mm] (origin: center of the world)
Definition: gears.cc:69
Book keeping before and after a run.
Definition: gears.cc:649
void SetSteppingVerbose(int level)
Definition: gears.cc:51
vector< double > py
y component of momentum direction
Definition: gears.cc:74
Construct detector geometry.
Definition: gears.cc:506
vector< double > dl
step length [mm]
Definition: gears.cc:65
Dump simulation results to screen or a file.
Definition: gears.cc:12
vector< double > x
x [mm] (origin: center of the world)
Definition: gears.cc:67
vector< double > et
Total energy deposited in a volume [keV].
Definition: gears.cc:77
G4String v2
name of volume 2
Definition: gears.cc:191
void Reset()
Definition: gears.cc:25
G4VPhysicalVolume * ConstructDetector(const G4tgrVolume *topVol)
Construct detector based on text geometry description.
Definition: gears.cc:451
A link list of G4LogicalBorderSurface.
Definition: gears.cc:188
vector< double > y
y [mm] (origin: center of the world)
Definition: gears.cc:68
Book keeping before and after an event.
Definition: gears.cc:689
vector< double > de
energy deposited [keV]
Definition: gears.cc:64
const G4tgrVolume * ReadDetector()
Read text geometry input.
Definition: gears.cc:439
int GetSteppingVerbose()
Definition: gears.cc:52
vector< double > xx
x [mm] (origin: center of local volume)
Definition: gears.cc:60
G4String name
name of the surface
Definition: gears.cc:189
Output()
use analysis manager to handle output
Definition: gears.cc:82
BorderSurface * next
link to next border surface
Definition: gears.cc:193
Split a radioactive decay chain to different events based on a time window.
Definition: gears.cc:700
vector< double > t
time elapsed from the beginning of an event [ns]
Definition: gears.cc:70
vector< int > vlm
volume copy number
Definition: gears.cc:56
Call Geant4 General Particle Source to generate particles.
Definition: gears.cc:628
void StepInfo()
Information of steps>0.
Definition: gears.cc:21
~Detector()
Definition: gears.cc:509
G4ClassificationOfNewTrack ClassifyNewTrack(const G4Track *trk)
send a daughter particle to waiting stack if it appears too late
Definition: gears.cc:719
vector< int > stp
step number
Definition: gears.cc:55
vector< int > trk
track ID
Definition: gears.cc:54
int main(int argc, char **argv)
The main function that calls individual components.
Definition: gears.cc:762
StackingAction()
created macro /grdm/setTimeWindow
Definition: gears.cc:706
vector< int > pro
process ID * 100 + sub-process ID
Definition: gears.cc:57
void NewStage()
save and reset output before processing waiting tracks
Definition: gears.cc:727
vector< double > pz
z component of momentum direction
Definition: gears.cc:75
void SetNewValue(G4UIcommand *cmd, G4String value)
Definition: gears.cc:734
virtual void GeneratePrimaries(G4Event *evt)
add sources to an event
Definition: gears.cc:637
Detector()
Definition: gears.cc:526
void TrackingStarted()
Information of step 0 (initStep)
Definition: gears.cc:17
Extension to default text geometry file line processor.
Definition: gears.cc:201
Construct detector based on text geometry description.
Definition: gears.cc:419
G4VPhysicalVolume * Construct()
called at /run/initialize
Definition: gears.cc:609
void SetNewValue(G4UIcommand *cmd, G4String value)
for G4UI
Definition: gears.cc:565
void SaveAndResetEvent()
save and then reset an event
Definition: gears.cc:673