WCSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
WCSimEventAction.cc
Go to the documentation of this file.
1 #include "WCSimEventAction.hh"
2 #include "WCSimTrajectory.hh"
3 #include "WCSimRunAction.hh"
5 #include "WCSimWCHit.hh"
6 #include "WCSimWCDigi.hh"
7 #include "WCSimWCDigitizer.hh"
8 #include "WCSimWCTrigger.hh"
9 #include "WCSimWCAddDarkNoise.hh"
10 #include "WCSimWCPMT.hh"
12 
13 #include "G4Event.hh"
14 #include "G4RunManager.hh"
15 #include "G4EventManager.hh"
16 #include "G4UImanager.hh"
17 #include "G4TrajectoryContainer.hh"
18 #include "G4VVisManager.hh"
19 #include "G4ios.hh"
20 #include "globals.hh"
21 #include "G4ThreeVector.hh"
22 #include "G4TransportationManager.hh"
23 #include "G4Navigator.hh"
24 #include "G4SDManager.hh"
25 #include "G4DigiManager.hh"
26 #include "G4UnitsTable.hh"
27 #include "G4UIcmdWith3VectorAndUnit.hh"
28 
29 #include "G4PhysicalConstants.hh"
30 #include "G4SystemOfUnits.hh"
31 
32 #include <set>
33 #include <iomanip>
34 #include <string>
35 #include <vector>
36 #include <climits>
37 
38 #include "jhfNtuple.h"
39 #include "TTree.h"
40 #include "TFile.h"
41 #include "WCSimRootEvent.hh"
42 #include "TStopwatch.h"
43 
44 #ifndef _SAVE_RAW_HITS
45 #define _SAVE_RAW_HITS
46 //Use this and one/two of below to debug hit information
47 //#define _SAVE_RAW_HITS_VERBOSE
48 #endif
49 
50 //Use this and one/two of below to debug digit information
51 //#define SAVE_DIGITS_VERBOSE
52 
53 //Print out hits with PMT IDs up to N
54 #define NPMTS_VERBOSE -1
55 //And/Or a specific PMT ID
56 #define VERBOSE_PMT -1
57 
58 #ifndef TIME_DAQ_STEPS
59 //#define TIME_DAQ_STEPS
60 #endif
61 
63  WCSimDetectorConstruction* myDetector,
64  WCSimPrimaryGeneratorAction* myGenerator)
65  :runAction(myRun), generatorAction(myGenerator),
66  detectorConstructor(myDetector),
67  ConstructedDAQClasses(false),
68  SavedOptions(false)
69 {
71 
72  G4DigiManager* DMman = G4DigiManager::GetDMpointer();
73 
74  //create PMT response module
75  WCSimWCPMT* WCDMPMT = new WCSimWCPMT( "WCReadoutPMT", myDetector, "tank");
76  DMman->AddNewModule(WCDMPMT);
77 
78  //create dark noise module
79  WCSimWCAddDarkNoise* WCDNM = new WCSimWCAddDarkNoise("WCDarkNoise", detectorConstructor, "tank");
80  DMman->AddNewModule(WCDNM);
81 
85  WCSimWCPMT* WCDMPMT_OD;
86  WCDMPMT_OD = new WCSimWCPMT( "WCReadoutPMT_OD", myDetector, "OD");
87  DMman->AddNewModule(WCDMPMT_OD);
88 
89  WCSimWCAddDarkNoise* WCDNM_OD;
90  WCDNM_OD = new WCSimWCAddDarkNoise("WCDarkNoise_OD", detectorConstructor, "OD");
91  DMman->AddNewModule(WCDNM_OD);
92 }
93 
95 {
96  delete DAQMessenger;
97 }
98 
100 {
102  G4cerr << "WCSimEventAction::CreateDAQInstances() has already been called. Exiting..." << G4endl;
103  return;
104  exit(-1);
105  }
106 
107  G4cout << "Creating digitizer and trigger class instances in WCSimEventAction::CreateDAQInstances()" << G4endl;
108 
109  G4DigiManager* DMman = G4DigiManager::GetDMpointer();
110 
111  //create your choice of digitizer module
112  if(DigitizerChoice == "SKI") {
113  WCSimWCDigitizerSKI* WCDM = new WCSimWCDigitizerSKI("WCReadoutDigits", detectorConstructor, DAQMessenger, "tank");
114  DMman->AddNewModule(WCDM);
115  }
116  else {
117  G4cerr << "Unknown DigitizerChoice " << DigitizerChoice << G4endl;
118  exit(-1);
119  }
120 
121  //create your choice of trigger module
122  if(TriggerChoice == "NDigits") {
124  DMman->AddNewModule(WCTM);
125  }
126  else if(TriggerChoice == "NDigits2") {
128  DMman->AddNewModule(WCTM);
129  }
130  else if(TriggerChoice == "NoTrigger") {
132  DMman->AddNewModule(WCTM);
133  }
134  else {
135  G4cerr << "Unknown TriggerChoice " << TriggerChoice << G4endl;
136  exit(-1);
137  }
138 
143  if (DigitizerChoice == "SKI") {
145  *WCDM_OD = new WCSimWCDigitizerSKI("WCReadoutDigits_OD", detectorConstructor, DAQMessenger, "OD");
146  DMman->AddNewModule(WCDM_OD);
147  }
148 
149  //create your choice of trigger module
150  if (TriggerChoice == "NDigits") {
152  *WCTM_OD = new WCSimWCTriggerNDigits("WCReadout_OD", detectorConstructor, DAQMessenger, "OD");
153  DMman->AddNewModule(WCTM_OD);
154  } else if (TriggerChoice == "NDigits2") {
156  *WCTM_OD = new WCSimWCTriggerNDigits2("WCReadout_OD", detectorConstructor, DAQMessenger, "OD");
157  DMman->AddNewModule(WCTM_OD);
158  } else if (TriggerChoice == "NoTrigger") {
160  *WCTM = new WCSimWCTriggerNoTrigger("WCReadout_OD", detectorConstructor, DAQMessenger, "OD");
161  DMman->AddNewModule(WCTM);
162  } else {
163  G4cerr << "Unknown TriggerChoice " << TriggerChoice << G4endl;
164  exit(-1);
165  }
166  }
167  ConstructedDAQClasses = true;
168 }
169 
170 
172 {
173  if(!ConstructedDAQClasses) {
175 
176  //and save options in output file
177  G4DigiManager* DMman = G4DigiManager::GetDMpointer();
178 
179  }
180 }
181 
182 void WCSimEventAction::EndOfEventAction(const G4Event* evt)
183 {
184 
185  // ----------------------------------------------------------------------
186  // Get Particle Table
187  // ----------------------------------------------------------------------
188 
189  G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
190 
191  // ----------------------------------------------------------------------
192  // Get Trajectory Container
193  // ----------------------------------------------------------------------
194 
195  G4TrajectoryContainer* trajectoryContainer = evt->GetTrajectoryContainer();
196 
197  G4int n_trajectories = 0;
198  if (trajectoryContainer) n_trajectories = trajectoryContainer->entries();
199 
200  // ----------------------------------------------------------------------
201  // Get Event Information
202  // ----------------------------------------------------------------------
203 
204  G4int event_id = evt->GetEventID();
205 // G4int mode = generatorAction->GetMode();
206 
207  unsigned int nvtxs = generatorAction->GetNvtxs();
208  G4ThreeVector vtxs[MAX_N_VERTICES];
209  G4int vtxsvol[MAX_N_VERTICES];
210  G4double vtxTimes[MAX_N_VERTICES];
211  for( Int_t u=0; u<nvtxs; u++ ){
212  vtxs[u] = generatorAction->GetVtx(u);
213  vtxsvol[u] = WCSimEventFindStartingVolume(vtxs[u]);
214  vtxTimes[u] = generatorAction->GetVertexTime(u);
215  }
216  G4int vecRecNumber = generatorAction->GetVecRecNumber();
217  G4double timeUnit=generatorAction->GetTimeUnit();
218 
219  // ----------------------------------------------------------------------
220  // Get WC Hit Collection
221  // ----------------------------------------------------------------------
222 
223  G4SDManager* SDman = G4SDManager::GetSDMpointer();
224 
225  // Get Hit collection of this event
226  G4HCofThisEvent* HCE = evt->GetHCofThisEvent();
227  WCSimWCHitsCollection* WCHC = 0;
228  G4String WCIDCollectionName = detectorConstructor->GetIDCollectionName();
229  if (HCE)
230  {
231  G4String name = WCIDCollectionName;
232  G4int collectionID = SDman->GetCollectionID(name);
233  if(collectionID>-1) WCHC = (WCSimWCHitsCollection*)HCE->GetHC(collectionID);
234  G4cout << G4endl;
235  G4cout << "WCSimEventAction::EndOfEventAction ☆ (WCSimWCHitsCollection*)" << WCIDCollectionName
236  << " has " << WCHC->entries() << " entries" << G4endl;
237  G4cout << G4endl;
238  }
239 
240  // To use Do like This:
241  // --------------------
242  // if (WCHC)
243  // for (G4int i=0; i< WCHC->entries() ;i++)
244  // G4cout << (*WCHC)[i]->GetTotalPe() << G4endl;
245 
246 
247  // ----------------------------------------------------------------------
248  // Get Digitized Hit Collection
249  // ----------------------------------------------------------------------
250 
251  // Get a pointer to the Digitizing Module Manager
252  G4DigiManager* DMman = G4DigiManager::GetDMpointer();
253 
254  // Get a pointer to the WC PMT module
255  WCSimWCPMT* WCDMPMT =
256  (WCSimWCPMT*)DMman->FindDigitizerModule("WCReadoutPMT");
257 
258 
259  // new MFechner, aug 2006
260  // need to clear up the old info inside PMT
261  WCDMPMT->ReInitialize();
262 
263 
264 #ifdef TIME_DAQ_STEPS
265  TStopwatch* ms = new TStopwatch();
266  ms->Start();
267 #endif
268 
269  //Convert the hits to PMT pulse
271  WCDMPMT->Digitize();
272 
273  //
274  // Do the Dark Noise, then Digitization, then Trigger
275  //
276 
277  //
278  // First, add Dark noise hits before digitizing
279 
280  //Get a pointer to the WC Dark Noise Module
281  WCSimWCAddDarkNoise* WCDNM =
282  (WCSimWCAddDarkNoise*)DMman->FindDigitizerModule("WCDarkNoise");
283 
284  //Add the dark noise
285  WCDNM->AddDarkNoise();
286 
287  //
288  // Next, do the digitization
289 
290  //Get a pointer to the WC Digitizer Module
291  WCSimWCDigitizerBase* WCDM =
292  (WCSimWCDigitizerBase*)DMman->FindDigitizerModule("WCReadoutDigits");
293 
294  //Digitize the hits
295  WCDM->Digitize();
296 
297  //
298  // Finally, apply the trigger
299 
300  //Get a pointer to the WC Trigger Module
301  WCSimWCTriggerBase* WCTM =
302  (WCSimWCTriggerBase*)DMman->FindDigitizerModule("WCReadout");
303 
304  //tell it the dark noise rate (for calculating the average dark occupancy -> can adjust the NDigits threshold)
305  WCTM->SetDarkRate(WCDNM->GetDarkRate());
306 
307  //Apply the trigger
308  // This takes the digits, and places them into trigger gates
309  // Also throws away digits not contained in an trigger gate
310  WCTM->Digitize();
311 
312 #ifdef TIME_DAQ_STEPS
313  ms->Stop();
314  G4cout << " Digtization : Real = " << ms->RealTime()
315  << " ; CPU = " << ms->CpuTime() << "\n";
316 #endif
317 
318  // Get the post-noise hit collection for the WC
319  G4int WCDChitsID = DMman->GetDigiCollectionID("WCRawPMTSignalCollection");
320  WCSimWCDigitsCollection * WCDC_hits = (WCSimWCDigitsCollection*) DMman->GetDigiCollection(WCDChitsID);
321 
322  // Get the digitized collection for the WC
323  G4int WCDCID = DMman->GetDigiCollectionID("WCDigitizedCollection");
324  WCSimWCTriggeredDigitsCollection * WCDC = (WCSimWCTriggeredDigitsCollection*) DMman->GetDigiCollection(WCDCID);
325  /*
326  // To use Do like This:
327  // --------------------
328  if(WCDC)
329  for (G4int i=0; i < WCDC->entries(); i++)
330  {
331  G4int tubeID = (*WCDC)[i]->GetTubeID();
332  G4double photoElectrons = (*WCDC)[i]->GetPe(i);
333  G4double time = (*WCDC)[i]->GetTime(i);
334  // G4cout << "time " << i << " " <<time << G4endl;
335  // G4cout << "tubeID " << i << " " <<tubeID << G4endl;
336  // G4cout << "Pe " << i << " " <<photoElectrons << G4endl;
337  // (*WCDC)[i]->Print();
338  }
339  */
340 
341  // ----------------------------------------------------------------------
342  // Repeat the steps for the OD
343  // ----------------------------------------------------------------------
344 
345  WCSimWCHitsCollection* WCHC_OD;
346  WCSimWCPMT* WCDMPMT_OD=NULL;
347  WCSimWCAddDarkNoise* WCDNM_OD=NULL;
348  WCSimWCDigitizerBase* WCDM_OD=NULL;
349  WCSimWCTriggerBase* WCTM_OD=NULL;
350  G4int WCDChitsID_OD;
351  WCSimWCDigitsCollection* WCDC_hits_OD=NULL;
354  WCHC_OD = 0;
355  G4String WCODCollectionName = detectorConstructor->GetODCollectionName();
356  if(HCE){
357  G4String name = WCODCollectionName;
358  G4int collectionID = SDman->GetCollectionID(name);
359  if(collectionID>-1) WCHC_OD = (WCSimWCHitsCollection*)HCE->GetHC(collectionID);
360  G4cout << G4endl;
361  G4cout<< "WCSimEventAction::EndOfEventAction() (WCSimWCHitsCollection*)" << WCODCollectionName
362  << " has " << WCHC_OD->entries() << " entries" << G4endl;
363  G4cout << G4endl;
364  }
365 
366  WCDMPMT_OD = (WCSimWCPMT*)DMman->FindDigitizerModule("WCReadoutPMT_OD");
367  if(WCDMPMT_OD == 0) G4cout << "WCReadoutPMT_OD digitzer module not found!" << G4endl;
368  WCDMPMT_OD->ReInitialize();
369  WCDMPMT_OD->Digitize();
370 
371  WCDNM_OD = (WCSimWCAddDarkNoise*)DMman->FindDigitizerModule("WCDarkNoise_OD");
372  if(WCDNM_OD == 0) G4cout << "WCDarkNoise_OD dark noise module not found!" << G4endl;
373  WCDNM_OD->AddDarkNoise();
374 
375  WCDM_OD = (WCSimWCDigitizerBase*)DMman->FindDigitizerModule("WCReadoutDigits_OD");
376  if(WCDM_OD == 0) G4cout << "WCReadoutDigits_OD digitizer module not found!" << G4endl;
377  WCDM_OD->Digitize();
378 
379  WCTM_OD = (WCSimWCTriggerBase*)DMman->FindDigitizerModule("WCReadout_OD");
380  if(WCTM_OD == 0) G4cout << "WCReadout_OD trigger module not found!" << G4endl;
381  WCTM_OD->SetDarkRate(WCDNM_OD->GetDarkRate());
382  WCTM_OD->Digitize();
383 
384  WCDChitsID_OD = DMman->GetDigiCollectionID("WCRawPMTSignalCollection_OD");
385  WCDC_hits_OD = (WCSimWCDigitsCollection*) DMman->GetDigiCollection(WCDChitsID_OD);
386  // printouts
387  G4cout << "WCSimEventAction::EndOfEventAction() retrieving raw hits" << G4endl
388  << " (WCSimWCDigitsCollection*)WCRawPMTSignalCollection_OD for FillRootEvent, which has ";
389  if(WCDC_hits_OD){
390  G4cout << WCDC_hits_OD->entries();
391  } else {
392  G4cout << "no";
393  }
394  G4cout << " entries" << G4endl;
395 
396  G4int WCDCID_OD = DMman->GetDigiCollectionID("WCDigitizedCollection_OD");
397  WCDC_OD = (WCSimWCTriggeredDigitsCollection*) DMman->GetDigiCollection(WCDCID_OD);
398  // printouts
399  G4cout << "WCSimEventAction::EndOfEventAction() retrieving readout hits"
400  << " (WCSimWCTriggeredDigitsCollection*)WCDigitizedCollection_OD for FillRootEvent, which has ";
401  if(WCDC_hits_OD){
402  G4cout << WCDC_OD->entries();
403  } else {
404  G4cout << "no";
405  }
406  G4cout << " entries" << G4endl;
407  }
408 
409  // ----------------------------------------------------------------------
410  // Fill Ntuple
411  // ----------------------------------------------------------------------
412  for(unsigned int ivx = 0;ivx<nvtxs;ivx++)
413  jhfNtuple.mode[ivx] = generatorAction->GetMode(ivx); // interaction mode
414  jhfNtuple.nvtxs = nvtxs; // number of vertices
415  for( Int_t u=0; u<nvtxs; u++ ){
416  jhfNtuple.vtxsvol[u] = vtxsvol[u]; // volume of vertex
417  // unit mismatch between geant4 and reconstruction, M Fechner
418  jhfNtuple.vtxs[u][0] = vtxs[u][0]/cm; // interaction vertex
419  jhfNtuple.vtxs[u][1] = vtxs[u][1]/cm; // interaction vertex
420  jhfNtuple.vtxs[u][2] = vtxs[u][2]/cm; // interaction vertex
421  jhfNtuple.vtxs[u][3] = vtxTimes[u]/timeUnit; // interaction vertex
422  }
423  jhfNtuple.vecRecNumber = vecRecNumber; //vectorfile record number
424 
425  // mustop, pstop, npar will be filled later
426 
427  // Next in the ntuple is an array of tracks.
428  // We will keep count with npar
429 
430  G4int npar = 0;
431 
432  // First two tracks are special: beam and target
433 
434  for( Int_t u=0; u<nvtxs; u++ ){
436  // npar = 0 NEUTRINO /////
438 
439  G4int beampdg;
440  G4double beamenergy;
441  G4ThreeVector beamdir;
442 
443  beampdg = generatorAction->GetBeamPDG(u);
444  beamenergy = generatorAction->GetBeamEnergy(u);
445  beamdir = generatorAction->GetBeamDir(u);
446 
447  jhfNtuple.ipnu[npar] = beampdg; // id
448  jhfNtuple.flag[npar] = -1; // incoming neutrino
449  jhfNtuple.m[npar] = 0.0; // mass (always a neutrino)
450  jhfNtuple.p[npar] = beamenergy; // momentum magnitude
451  jhfNtuple.E[npar] = beamenergy; // energy
452  jhfNtuple.startvol[npar]= vtxsvol[u]; // starting volume, vtxvol should be referred
453  jhfNtuple.stopvol[npar] = -1; // stopping volume
454  jhfNtuple.dir[npar][0] = beamdir[0]; // direction
455  jhfNtuple.dir[npar][1] = beamdir[1]; // direction
456  jhfNtuple.dir[npar][2] = beamdir[2]; // direction
457  jhfNtuple.pdir[npar][0] = beamenergy*beamdir[0]; // momentum-vector
458  jhfNtuple.pdir[npar][1] = beamenergy*beamdir[1]; // momentum-vector
459  jhfNtuple.pdir[npar][2] = beamenergy*beamdir[2]; // momentum-vector
460  // M Fechner, same as above
461  jhfNtuple.stop[npar][0] = vtxs[u][0]/cm; // stopping point (not meaningful)
462  jhfNtuple.stop[npar][1] = vtxs[u][1]/cm; // stopping point (not meaningful)
463  jhfNtuple.stop[npar][2] = vtxs[u][2]/cm; // stopping point (not meaningful)
464  /* Alex Finch
465  Create an imaginary start position for the incoming neutrino, to help event display
466  */
467  double distance=10000.0;
468  for(int idim=0;idim<3;idim++)
469  jhfNtuple.start[npar][idim]=jhfNtuple.stop[npar][idim] - (distance*jhfNtuple.dir[npar][idim]);
470 
471  jhfNtuple.parent[npar] = 0;
472 
473  npar++;
475  // npar = 1 TARGET ///////
477 
478  G4double targetpmag = 0.0, targetmass = 0.0;
479  G4int targetpdg = generatorAction->GetTargetPDG(u);
480  G4double targetenergy = generatorAction->GetTargetEnergy(u);
481  G4ThreeVector targetdir = generatorAction->GetTargetDir(u);
482 
483  if (targetpdg!=0) { // protects against seg-fault
484  if (targetpdg > 999) // 16O nucleus not in pdg table
485  targetmass = targetenergy; // 16O is at rest, so E = m
486  else
487  targetmass = particleTable->FindParticle(targetpdg)->GetPDGMass();
488  if (targetenergy > targetmass)
489  // targetpmag = sqrt(targetenergy*targetenergy - targetmass*targetenergy);
490  // MF : bug fix
491  targetpmag = sqrt(targetenergy*targetenergy - targetmass*targetmass);
492  else // protect against NaN
493  targetpmag = 0.0;
494  }
495 
496  jhfNtuple.ipnu[npar] = targetpdg; // id
497  jhfNtuple.flag[npar] = -2; // target
498  jhfNtuple.m[npar] = targetmass; // mass (always a neutrino)
499  jhfNtuple.p[npar] = targetpmag; // momentum magnitude
500  jhfNtuple.E[npar] = targetenergy; // energy (total!)
501  jhfNtuple.startvol[npar] = vtxsvol[u]; // starting volume
502  jhfNtuple.stopvol[npar] = -1; // stopping volume
503  jhfNtuple.dir[npar][0] = targetdir[0]; // direction
504  jhfNtuple.dir[npar][1] = targetdir[1]; // direction
505  jhfNtuple.dir[npar][2] = targetdir[2]; // direction
506  // MF feb9,2006 : we want the momentum, not the energy...
507  // jhfNtuple.pdir[npar][0] = targetenergy*targetdir[0]; // momentum-vector
508  // jhfNtuple.pdir[npar][1] = targetenergy*targetdir[1]; // momentum-vector
509  // jhfNtuple.pdir[npar][2] = targetenergy*targetdir[2]; // momentum-vector
510  jhfNtuple.pdir[npar][0] = targetpmag*targetdir[0]; // momentum-vector
511  jhfNtuple.pdir[npar][1] = targetpmag*targetdir[1]; // momentum-vector
512  jhfNtuple.pdir[npar][2] = targetpmag*targetdir[2]; // momentum-vector
513  // M Fechner, same as above
514  jhfNtuple.stop[npar][0] = vtxs[u][0]/cm; // stopping point (not meaningful)
515  jhfNtuple.stop[npar][1] = vtxs[u][1]/cm; // stopping point (not meaningful)
516  jhfNtuple.stop[npar][2] = vtxs[u][2]/cm; // stopping point (not meaningful)
517  jhfNtuple.parent[npar] = 0;
518 
519  npar++;
520  }
521 
523  // npar > nvertices ///
525 
526  // Draw Charged Tracks
527  G4int PDG_e=11,PDG_v_e=12,PDG_gam=22;
528  for( Int_t u=0; u<nvtxs; u++ ){
529  G4int trkid_e=INT_MAX,trkid_v_e=INT_MAX,trkid_gam=INT_MAX;
530  G4int idx_e=INT_MAX,idx_v_e=INT_MAX,idx_gam=INT_MAX;
531  for (G4int i=0; i < n_trajectories; i++)
532  {
533  WCSimTrajectory* trj =
534  (WCSimTrajectory*)((*(evt->GetTrajectoryContainer()))[i]);
535 
536  if (trj->GetCharge() != 0.)
537  trj->DrawTrajectory(50);
538  if(abs(trj->GetPDGEncoding()) == PDG_e && trj->GetParentID() == u+1 && trj->GetTrackID() < trkid_e) {
539  trkid_e = trj->GetTrackID();
540  idx_e = i;
541  }
542  if(abs(trj->GetPDGEncoding()) == PDG_v_e && trj->GetParentID() == u+1 && trj->GetTrackID() < trkid_v_e) {
543  trkid_v_e = trj->GetTrackID();
544  idx_v_e = i;
545  }
546  if(abs(trj->GetPDGEncoding()) == PDG_gam && trj->GetParentID() == u+1 && trj->GetTrackID() < trkid_gam) {
547  trkid_gam = trj->GetTrackID();
548  idx_gam = i;
549  }
550  }
551 
552  if(idx_e != INT_MAX) {
553  WCSimTrajectory* trj =
554  (WCSimTrajectory*)((*(evt->GetTrajectoryContainer()))[idx_e]);
555  jhfNtuple.ipnu[npar] = trj->GetPDGEncoding(); // id
556  jhfNtuple.flag[npar] = 0; // target
557  jhfNtuple.m[npar] = particleTable->FindParticle(trj->GetPDGEncoding())->GetPDGMass(); // mass (always a neutrino)
558  jhfNtuple.p[npar] = trj->GetInitialMomentum().mag(); // momentum magnitude
559  jhfNtuple.E[npar] = sqrt(jhfNtuple.m[npar]*jhfNtuple.m[npar]+jhfNtuple.p[npar]*jhfNtuple.p[npar]); // energy (total!)
560  jhfNtuple.startvol[npar] = -1; // starting volume
561  jhfNtuple.stopvol[npar] = -1; // stopping volume
562  jhfNtuple.dir[npar][0] = trj->GetInitialMomentum().unit().getX(); // direction
563  jhfNtuple.dir[npar][1] = trj->GetInitialMomentum().unit().getY(); // direction
564  jhfNtuple.dir[npar][2] = trj->GetInitialMomentum().unit().getZ(); // direction
565  // MF feb9,2006 : we want the momentum, not the energy...
566  // jhfNtuple.pdir[npar][0] = targetenergy*targetdir[0]; // momentum-vector
567  // jhfNtuple.pdir[npar][1] = targetenergy*targetdir[1]; // momentum-vector
568  // jhfNtuple.pdir[npar][2] = targetenergy*targetdir[2]; // momentum-vector
569  jhfNtuple.pdir[npar][0] = trj->GetInitialMomentum().getX(); // momentum-vector
570  jhfNtuple.pdir[npar][1] = trj->GetInitialMomentum().getY(); // momentum-vector
571  jhfNtuple.pdir[npar][2] = trj->GetInitialMomentum().getZ(); // momentum-vector
572  // M Fechner, same as above
573  jhfNtuple.stop[npar][0] = vtxs[u][0]/cm; // stopping point (not meaningful)
574  jhfNtuple.stop[npar][1] = vtxs[u][1]/cm; // stopping point (not meaningful)
575  jhfNtuple.stop[npar][2] = vtxs[u][2]/cm; // stopping point (not meaningful)
576  jhfNtuple.parent[npar] = 0;
577 
578  npar++;
579  }
580 
581  if(idx_v_e != INT_MAX) {
582  WCSimTrajectory* trj =
583  (WCSimTrajectory*)((*(evt->GetTrajectoryContainer()))[idx_v_e]);
584  jhfNtuple.ipnu[npar] = trj->GetPDGEncoding(); // id
585  jhfNtuple.flag[npar] = 0; // target
586  jhfNtuple.m[npar] = particleTable->FindParticle(trj->GetPDGEncoding())->GetPDGMass(); // mass (always a neutrino)
587  jhfNtuple.p[npar] = trj->GetInitialMomentum().mag(); // momentum magnitude
588  jhfNtuple.E[npar] = sqrt(jhfNtuple.m[npar]*jhfNtuple.m[npar]+jhfNtuple.p[npar]*jhfNtuple.p[npar]); // energy (total!)
589  jhfNtuple.startvol[npar] = -1; // starting volume
590  jhfNtuple.stopvol[npar] = -1; // stopping volume
591  jhfNtuple.dir[npar][0] = trj->GetInitialMomentum().unit().getX(); // direction
592  jhfNtuple.dir[npar][1] = trj->GetInitialMomentum().unit().getY(); // direction
593  jhfNtuple.dir[npar][2] = trj->GetInitialMomentum().unit().getZ(); // direction
594  // MF feb9,2006 : we want the momentum, not the energy...
595  // jhfNtuple.pdir[npar][0] = targetenergy*targetdir[0]; // momentum-vector
596  // jhfNtuple.pdir[npar][1] = targetenergy*targetdir[1]; // momentum-vector
597  // jhfNtuple.pdir[npar][2] = targetenergy*targetdir[2]; // momentum-vector
598  jhfNtuple.pdir[npar][0] = trj->GetInitialMomentum().getX(); // momentum-vector
599  jhfNtuple.pdir[npar][1] = trj->GetInitialMomentum().getY(); // momentum-vector
600  jhfNtuple.pdir[npar][2] = trj->GetInitialMomentum().getZ(); // momentum-vector
601  // M Fechner, same as above
602  jhfNtuple.stop[npar][0] = vtxs[u][0]/cm; // stopping point (not meaningful)
603  jhfNtuple.stop[npar][1] = vtxs[u][1]/cm; // stopping point (not meaningful)
604  jhfNtuple.stop[npar][2] = vtxs[u][2]/cm; // stopping point (not meaningful)
605  jhfNtuple.parent[npar] = 0;
606 
607  npar++;
608  }
609 
610 
611  if(idx_gam != INT_MAX) {
612  WCSimTrajectory* trj =
613  (WCSimTrajectory*)((*(evt->GetTrajectoryContainer()))[idx_gam]);
614  jhfNtuple.ipnu[npar] = trj->GetPDGEncoding(); // id
615  jhfNtuple.flag[npar] = 0; // target
616  jhfNtuple.m[npar] = particleTable->FindParticle(trj->GetPDGEncoding())->GetPDGMass(); // mass (always a neutrino)
617  jhfNtuple.p[npar] = trj->GetInitialMomentum().mag(); // momentum magnitude
618  jhfNtuple.E[npar] = sqrt(jhfNtuple.m[npar]*jhfNtuple.m[npar]+jhfNtuple.p[npar]*jhfNtuple.p[npar]); // energy (total!)
619  jhfNtuple.startvol[npar] = -1; // starting volume
620  jhfNtuple.stopvol[npar] = -1; // stopping volume
621  jhfNtuple.dir[npar][0] = trj->GetInitialMomentum().unit().getX(); // direction
622  jhfNtuple.dir[npar][1] = trj->GetInitialMomentum().unit().getY(); // direction
623  jhfNtuple.dir[npar][2] = trj->GetInitialMomentum().unit().getZ(); // direction
624  // MF feb9,2006 : we want the momentum, not the energy...
625  // jhfNtuple.pdir[npar][0] = targetenergy*targetdir[0]; // momentum-vector
626  // jhfNtuple.pdir[npar][1] = targetenergy*targetdir[1]; // momentum-vector
627  // jhfNtuple.pdir[npar][2] = targetenergy*targetdir[2]; // momentum-vector
628  jhfNtuple.pdir[npar][0] = trj->GetInitialMomentum().getX(); // momentum-vector
629  jhfNtuple.pdir[npar][1] = trj->GetInitialMomentum().getY(); // momentum-vector
630  jhfNtuple.pdir[npar][2] = trj->GetInitialMomentum().getZ(); // momentum-vector
631  // M Fechner, same as above
632  jhfNtuple.stop[npar][0] = vtxs[u][0]/cm; // stopping point (not meaningful)
633  jhfNtuple.stop[npar][1] = vtxs[u][1]/cm; // stopping point (not meaningful)
634  jhfNtuple.stop[npar][2] = vtxs[u][2]/cm; // stopping point (not meaningful)
635  jhfNtuple.parent[npar] = 0;
636 
637  npar++;
638  }
639  }
640 
641  //fill correct variables for track from decay
642 
643  // G4cout << "event_id: " << &event_id << G4endl;
644  // G4cout << "jhfNtuple: " << &jhfNtuple << G4endl;
645  // G4cout << "WCHC: " << &WCHC << G4endl;
646  // G4cout << "WCDC: " << &WCDC << G4endl;
647  // G4cout << "WCFVHC: " << &WCFVHC << G4endl;
648  // G4cout << "WCFVDC: " << &WCFVDC << G4endl;
649  // G4cout << "lArDHC: " << &lArDHC << G4endl;
650  // G4cout << "FGDxHC: " << &FGDxHC << G4endl;
651  // G4cout << "FGDyHC: " << &FGDyHC << G4endl;
652  // G4cout << "MRDxHC: " << &MRDxHC << G4endl;
653  // G4cout << "MRDyHC: " << &MRDyHC << G4endl;
654 
655  jhfNtuple.npar = npar;
656 
657 
658  FillRootEvent(event_id,
659  jhfNtuple,
660  trajectoryContainer,
661  WCDC_hits,
662  WCDC,
663  "tank");
664 
666  FillRootEvent(event_id,
667  jhfNtuple,
668  trajectoryContainer,
669  WCDC_hits_OD,
670  WCDC_OD,
671  "OD");
672  }
673 
674  TTree* tree = GetRunAction()->GetTree();
675  //TBranch* tankeventbranch = tree->GetBranch("wcsimrootevent");
676  //tree->SetEntries(tankeventbranch->GetEntries());
677  tree->SetEntries(GetRunAction()->GetNumberOfEventsGenerated());
678 
679  /*
680  -> G. Pronost (2019/12/17) Moved to RunAction (EndOfRun) in order to fasten the simulation
681  TFile* hfile = tree->GetCurrentFile();
682  // MF : overwrite the trees -- otherwise we have as many copies of the tree
683  // as we have events. All the intermediate copies are incomplete, only the
684  // last one is useful --> huge waste of disk space.
685  hfile->Write("",TObject::kOverwrite);
686  */
687  //save DAQ options here. This ensures that when the user selects a default option
688  // (e.g. with -99), the saved option value in the output reflects what was run
689  if(!SavedOptions) {
690  WCSimRootOptions * wcsimopt = runAction->GetRootOptions();
691  //Dark noise
692  WCDNM->SaveOptionsToOutput(wcsimopt, "tank");
693  //Digitizer
694  WCDM->SaveOptionsToOutput(wcsimopt);
695  //Trigger
696  WCTM->SaveOptionsToOutput(wcsimopt);
697  //Generator
699 
701  //Dark noise
702  WCDNM_OD->SaveOptionsToOutput(wcsimopt, "OD");
703  }
704 
705  SavedOptions = true;
706  }
707 }
708 
710 {
711  // Get volume of starting point (see GEANT4 FAQ)
712 
713  G4int vtxvol = -1;
714 
715  G4Navigator* tmpNavigator =
716  G4TransportationManager::GetTransportationManager()->
717  GetNavigatorForTracking();
718 
719  G4VPhysicalVolume* tmpVolume = tmpNavigator->LocateGlobalPointAndSetup(vtx);
720  G4String vtxVolumeName = tmpVolume->GetName();
721 
722 
723 
724  if ( vtxVolumeName == "outerTube" ||
725  vtxVolumeName == "innerTube" ||
726  vtxVolumeName == "rearEndCap"||
727  vtxVolumeName == "frontEndCap" )
728  vtxvol = 10;
729 
730  else if ( vtxVolumeName.contains("WC") && !vtxVolumeName.contains("FV") )
731  {
732 // aah original line ->if (vtxVolumeName.contains("WCBarrel"))
733  if ((vtxVolumeName.contains("WCBarrel"))|| (vtxVolumeName.contains("Tank"))) //aah I added "Tank" as MB equivalent of Barrel
734  vtxvol = 10;
735  else if (vtxVolumeName == "WCBox")
736  vtxvol = -2;
737  else if (vtxVolumeName.contains("PMT") ||
738  vtxVolumeName.contains("Cap") ||
739  vtxVolumeName.contains("Cell"))
740  vtxvol = 11;
741  else if (vtxVolumeName.contains("OD"))
742  vtxvol = 12;
743  else
744  {
745  G4cout << vtxVolumeName << " unkown vtxVolumeName " << G4endl;
746  vtxvol = -3;
747  }
748  }
749  else if ( vtxVolumeName == "expHall" )
750  vtxvol = 0;
751  else if ( vtxVolumeName == "catcher" )
752  vtxvol = 40;
753 
754 
755  return vtxvol;
756 }
757 
759 {
760  G4int stopvol = -1;
761 
762  if ( stopVolumeName.contains("WC") && !stopVolumeName.contains("FV") )
763  {
764 //aah Original line-> if (stopVolumeName.contains("WCBarrel"))
765  if ((stopVolumeName.contains("WCBarrel"))|| (stopVolumeName.contains("Tank"))) // aah I added "Tank" as MB equivalent of Barrel
766  stopvol = 10;
767  else if (stopVolumeName == "WCBox")
768  stopvol = -2;
769  else if (stopVolumeName.contains("PMT") ||
770  stopVolumeName.contains("Cap") ||
771  stopVolumeName.contains("Cell"))
772  stopvol = 11;
773  else if (stopVolumeName.contains("OD"))
774  stopvol = 12;
775  else
776  {
777  G4cout << stopVolumeName << " unkown stopVolumeName " << G4endl;
778  stopvol = -3;
779  }
780  }
781 
782  else if ( stopVolumeName.contains("FV") )
783  {
784  if (stopVolumeName == "WCFVBarrel" ||
785  stopVolumeName == "WCFVAnnulus" ||
786  stopVolumeName == "WCFVRing" )
787  stopvol = 10;
788  else if (stopVolumeName.contains("FVPMT"))
789  stopvol = 13;
790  else
791  {
792  G4cout << stopVolumeName << " unkown stopVolumeName " << G4endl;
793  stopvol = -3;
794  }
795  }
796  else if ( stopVolumeName == "expHall" )
797  stopvol = 0;
798  else if ( stopVolumeName == "catcher" )
799  stopvol = 40;
800 
801 
802  return stopvol;
803 }
804 
805 void WCSimEventAction::FillRootEvent(G4int event_id,
806  const struct ntupleStruct& jhfNtuple,
807  G4TrajectoryContainer* TC,
808  WCSimWCDigitsCollection* WCDC_hits,
810  G4String detectorElement)
811 {
812  // Fill up a Root event with stuff from the ntuple
813 
814  WCSimRootEvent* wcsimrootsuperevent = GetRunAction()->GetRootEvent(detectorElement);
815 
816  // start with the first "sub-event"
817  // if the WC digitization requires it, we will add another subevent
818  // for the WC.
819  // all the rest goes into the first "sub-event".
820  WCSimRootTrigger* wcsimrootevent = wcsimrootsuperevent->GetTrigger(0);
821  // get number of gates
822  G4DigiManager* DMman = G4DigiManager::GetDMpointer();
823  WCSimWCTriggerBase* WCTM;
824  if(detectorElement=="tank"){
825  WCTM = (WCSimWCTriggerBase*)DMman->FindDigitizerModule("WCReadout");
826  } else if(detectorElement=="OD"){
827  WCTM = (WCSimWCTriggerBase*)DMman->FindDigitizerModule("WCReadout_OD");
828  }
829  int ngates = WCTM->NumberOfGatesInThisEvent();
830  for (int index = 0 ; index < ngates ; index++)
831  {
832  if (index >=1 ) {
833  wcsimrootsuperevent->AddSubEvent();
834  wcsimrootevent = wcsimrootsuperevent->GetTrigger(index);
835  wcsimrootevent->SetHeader(event_id,0,
836  0,index+1); // date & # of subevent
837  wcsimrootevent->SetMode(jhfNtuple.mode[0]);
838  }
839  wcsimrootevent->SetTriggerInfo(WCTM->GetTriggerType(index),
840  WCTM->GetTriggerInfo(index));
841  }
842 
843 
844  // Fill the header
845  // Need to add run and date
846  wcsimrootevent = wcsimrootsuperevent->GetTrigger(0);
847  wcsimrootevent->SetHeader(event_id,0,0); // will be set later.
848 
849  // Fill other info for this event
850 
851  wcsimrootevent->SetMode(jhfNtuple.mode[0]);
852  wcsimrootevent->SetNvtxs(jhfNtuple.nvtxs);
853  for( Int_t u=0; u<jhfNtuple.nvtxs; u++ ){
854  wcsimrootevent->SetVtxsvol(u,jhfNtuple.vtxsvol[u]);
855  for (int j=0;j<4;j++)
856  {
857  wcsimrootevent->SetVtxs(u,j,jhfNtuple.vtxs[u][j]);
858  }
859  wcsimrootevent->SetMode(u,jhfNtuple.mode[u]);
860  }
861  wcsimrootevent->SetJmu(jhfNtuple.jmu);
862  wcsimrootevent->SetJp(jhfNtuple.jp);
863  wcsimrootevent->SetNpar(jhfNtuple.npar);
864  wcsimrootevent->SetVecRecNumber(jhfNtuple.vecRecNumber);
865 
866  // Add the tracks with the particle information
867  // First two tracks come from jhfNtuple, as they are special
868 
869  int k;
870  //Modify to add decay products
871  for (k=0;k<jhfNtuple.npar;k++) // should be just 2
872  {
873  double dir[3];
874  double pdir[3];
875  double stop[3];
876  double start[3];
877  for (int l=0;l<3;l++)
878  {
879  dir[l]=jhfNtuple.dir[k][l];
880  pdir[l]=jhfNtuple.pdir[k][l];
881  stop[l]=jhfNtuple.stop[k][l];
882  start[l]=jhfNtuple.start[k][l];
883  //G4cout<< "start[" << k << "][" << l <<"]: "<< jhfNtuple.start[k][l] <<G4endl;
884  }
885 
886  // Add the track to the TClonesArray
887  wcsimrootevent->AddTrack(jhfNtuple.ipnu[k],
888  jhfNtuple.flag[k],
889  jhfNtuple.m[k],
890  jhfNtuple.p[k],
891  jhfNtuple.E[k],
892  jhfNtuple.startvol[k],
893  jhfNtuple.stopvol[k],
894  dir,
895  pdir,
896  stop,
897  start,
898  jhfNtuple.parent[k],
899  jhfNtuple.time[k],0);
900  }
901 
902  // the rest of the tracks come from WCSimTrajectory
903 
904  std::set<int> pizeroList;
905  // added by M Fechner, dec 16th, 2004
906  std::set<int> muonList;
907  std::set<int> antimuonList;
908  // same, april 7th 2005
909  std::set<int> pionList;
910  std::set<int> antipionList;
911  std::set<int> primaryList;
912 
913  // Pi0 specific variables
914  Double_t pi0Vtx[3];
915  Int_t gammaID[2];
916  Double_t gammaE[2];
917  Double_t gammaVtx[2][3];
918  Int_t r = 0;
919 
920  G4int n_trajectories = 0;
921  if (TC)
922  n_trajectories = TC->entries();
923 
924  // M Fechner : removed this limit to get to the primaries...
925  //if (n_trajectories>50) // there is no need for this limit, but it has
926  //n_trajectories=50; // existed in previous versions of the code. It also
927  // makes the ROOT file smaller.
928 
929  for (int i=0; i <n_trajectories; i++)
930  {
931  WCSimTrajectory* trj = (WCSimTrajectory*)(*TC)[i];
932 
933  // If this track is a pizero remember it for later
934  if ( trj->GetPDGEncoding() == 111)
935  pizeroList.insert(trj->GetTrackID());
936  // If it is a mu+/mu- also remember it
937  if ( trj->GetPDGEncoding() == 13 ) muonList.insert(trj->GetTrackID());
938  if ( trj->GetPDGEncoding() == -13 ) antimuonList.insert(trj->GetTrackID());
939  if ( trj->GetPDGEncoding() == 211 ) pionList.insert(trj->GetTrackID());
940  if ( trj->GetPDGEncoding() == -211 ) antipionList.insert(trj->GetTrackID());
941 
942  if( trj->GetParentID() == 0 ) primaryList.insert(trj->GetTrackID());
943 
944  // Process primary tracks or the secondaries from pizero or muons...
945 
946  if ( trj->GetSaveFlag() )
947  {
948  // initial point of the trajectory
949  G4TrajectoryPoint* aa = (G4TrajectoryPoint*)trj->GetPoint(0) ;
950 
951  G4int ipnu = trj->GetPDGEncoding();
952  G4int id = trj->GetTrackID();
953  G4int flag = 0; // will be set later
954  G4double mass = trj->GetParticleDefinition()->GetPDGMass();
955  G4ThreeVector mom = trj->GetInitialMomentum();
956  G4double mommag = mom.mag();
957  G4double energy = sqrt(mom.mag2() + mass*mass);
958  G4ThreeVector Stop = trj->GetStoppingPoint();
959  G4ThreeVector Start = aa->GetPosition();
960 
961  G4String stopVolumeName = trj->GetStoppingVolume()->GetName();
962  G4int stopvol = WCSimEventFindStoppingVolume(stopVolumeName);
963  G4int startvol = WCSimEventFindStartingVolume(Start);
964 
965  G4double ttime = trj->GetGlobalTime();
966 
967  G4int parentType;
968 
969 
970  // Right now only secondaries whose parents are pi0's are stored
971  // This may change later
972  // M Fechner : dec 16, 2004 --> added decay e- from muons
973  if (trj->GetParentID() == 0){
974  parentType = 0;
975  } else if (pizeroList.count(trj->GetParentID()) ) {
976  parentType = 111;
977  } else if (muonList.count(trj->GetParentID()) ) {
978  parentType = 13;
979  } else if (antimuonList.count(trj->GetParentID()) ) {
980  parentType = -13;
981  } else if (antipionList.count(trj->GetParentID()) ) {
982  parentType = -211;
983  } else if (pionList.count(trj->GetParentID()) ) {
984  parentType = 211;
985  } else if (primaryList.count(trj->GetParentID()) ) {
986  parentType = 1;
987  } else { // no identified parent, but not a primary
988  parentType = 999;
989  }
990 
991  // G4cout << parentType << " " << ipnu << " "
992  // << id << " " << energy << "\n";
993 
994  // fill ntuple
995  double dir[3];
996  double pdir[3];
997  double stop[3];
998  double start[3];
999  for (int l=0;l<3;l++)
1000  {
1001  dir[l]= mom[l]/mommag; // direction
1002  pdir[l]=mom[l]; // momentum-vector
1003  stop[l]=Stop[l]/cm; // stopping point
1004  start[l]=Start[l]/cm; // starting point
1005  //G4cout<<"part 2 start["<<l<<"]: "<< start[l] <<G4endl;
1006  }
1007 
1008 
1009  // Add the track to the TClonesArray, watching out for times
1010  if ( ! ( (ipnu==22)&&(parentType==999)) ) {
1011  int choose_event=0;
1012 
1013  if (ngates)
1014  {
1015 
1016  if ( ttime > WCTM->GetTriggerTime(0)+950. && WCTM->GetTriggerTime(1)+950. > ttime ) choose_event=1;
1017  if ( ttime > WCTM->GetTriggerTime(1)+950. && WCTM->GetTriggerTime(2)+950. > ttime ) choose_event=2;
1018  if (choose_event >= ngates) choose_event = ngates-1; // do not overflow the number of events
1019 
1020  }
1021 
1022  wcsimrootevent= wcsimrootsuperevent->GetTrigger(choose_event);
1023  wcsimrootevent->AddTrack(ipnu,
1024  flag,
1025  mass,
1026  mommag,
1027  energy,
1028  startvol,
1029  stopvol,
1030  dir,
1031  pdir,
1032  stop,
1033  start,
1034  parentType,
1035  ttime,id);
1036  }
1037 
1038 
1039  if (detectorConstructor->SavePi0Info() == true)
1040  {
1041  G4cout<<"Pi0 parentType: " << parentType <<G4endl;
1042  if (parentType == 111)
1043  {
1044  if (r>1)
1045  G4cout<<"WARNING: more than 2 primary gammas found"<<G4endl;
1046  else
1047  {
1048 
1049  for (int y=0;y<3;y++)
1050  {
1051  pi0Vtx[y] = start[y];
1052  gammaVtx[r][y] = stop[y];
1053  }
1054 
1055  gammaID[r] = id;
1056  gammaE[r] = energy;
1057  r++;
1058 
1059  //amb79
1060  G4cout<<"Pi0 data: " << id <<G4endl;
1061  wcsimrootevent->SetPi0Info(pi0Vtx, gammaID, gammaE, gammaVtx);
1062  }
1063  }
1064  }
1065  }
1066  }
1067 
1068  // Add the Cherenkov hits
1069  wcsimrootevent = wcsimrootsuperevent->GetTrigger(0);
1070 
1071  wcsimrootevent->SetNumTubesHit(jhfNtuple.numTubesHit);
1072 
1073 #ifdef _SAVE_RAW_HITS
1074 
1075  if (WCDC_hits)
1076  {
1077  //add the truth raw hits
1078  // Both the pre- and post-PMT smearing hit times are accessible
1079  // Choose to save just the pre-smeared times for now
1080 #ifdef _SAVE_RAW_HITS_VERBOSE
1081  G4cout<<"RAW HITS"<<G4endl;
1082 #endif
1083  wcsimrootevent->SetNumTubesHit(WCDC_hits->entries());
1084  std::vector<double> truetime, smeartime;
1085  std::vector<int> primaryParentID;
1086  double hit_time_smear, hit_time_true;
1087  int hit_parentid;
1088  //loop over the DigitsCollection
1089  for(int idigi = 0; idigi < WCDC_hits->entries(); idigi++) {
1090  int digi_tubeid = (*WCDC_hits)[idigi]->GetTubeID();
1091  for(G4int id = 0; id < (*WCDC_hits)[idigi]->GetTotalPe(); id++){
1092  hit_time_true = (*WCDC_hits)[idigi]->GetPreSmearTime(id);
1093  hit_parentid = (*WCDC_hits)[idigi]->GetParentID(id);
1094  truetime.push_back(hit_time_true);
1095  primaryParentID.push_back(hit_parentid);
1096 #ifdef _SAVE_RAW_HITS_VERBOSE
1097  hit_time_smear = (*WCDC_hits)[idigi]->GetTime(id);
1098  smeartime.push_back(hit_time_smear);
1099 #endif
1100  }//id
1101 #ifdef _SAVE_RAW_HITS_VERBOSE
1102  if(digi_tubeid < NPMTS_VERBOSE || digi_tubeid == VERBOSE_PMT) {
1103  G4cout << "Adding " << truetime.size()
1104  << " Cherenkov hits in tube " << digi_tubeid
1105  << " with truetime:smeartime:primaryparentID";
1106  for(G4int id = 0; id < truetime.size(); id++) {
1107  G4cout << " " << truetime[id]
1108  << "\t" << smeartime[id]
1109  << "\t" << primaryParentID[id] << G4endl;
1110  }//id
1111  G4cout << G4endl;
1112  }
1113 #endif
1114  wcsimrootevent->AddCherenkovHit(digi_tubeid,
1115  truetime,
1116  primaryParentID);
1117  smeartime.clear();
1118  truetime.clear();
1119  primaryParentID.clear();
1120  }//idigi
1121  }//if(WCDC_hits)
1122 #endif //_SAVE_RAW_HITS
1123 
1124  // Add the digitized hits
1125 
1126  if (WCDC)
1127  {
1128 #ifdef SAVE_DIGITS_VERBOSE
1129  G4cout << "DIGI HITS" << G4endl;
1130 #endif
1131 
1132  G4double sumq_tmp = 0.;
1133 
1134  for ( int index = 0 ; index < ngates ; index++)
1135  {
1136  sumq_tmp = 0.0;
1137  G4double gatestart;
1138  int countdigihits = 0;
1139  wcsimrootevent = wcsimrootsuperevent->GetTrigger(index);
1140  for (k=0;k<WCDC->entries();k++)
1141  {
1142  if ( (*WCDC)[k]->HasHitsInGate(index)) {
1143  std::vector<double> vec_pe = (*WCDC)[k]->GetPe(index);
1144  std::vector<double> vec_time = (*WCDC)[k]->GetTime(index);
1145  std::vector<std::vector<int> > vec_digicomp = (*WCDC)[k]->GetDigiCompositionInfo(index);
1146  const int tubeID = (*WCDC)[k]->GetTubeID();
1147  assert(vec_pe.size() == vec_time.size());
1148  assert(vec_pe.size() == vec_digicomp.size());
1149  for(unsigned int iv = 0; iv < vec_pe.size(); iv++) {
1150 #ifdef SAVE_DIGITS_VERBOSE
1151  if(tubeID < NPMTS_VERBOSE || digi_tubeid == VERBOSE_PMT) {
1152  G4cout << "Adding digit " << iv
1153  << " for PMT " << tubeID
1154  << " pe " << vec_pe[iv]
1155  << " time " << vec_time[iv]
1156  << " digicomp";
1157  for(unsigned int ivv = 0; ivv < vec_digicomp[iv].size(); ivv++)
1158  G4cout << " " << vec_digicomp[iv][ivv];
1159  G4cout << G4endl;
1160  }
1161 #endif
1162  assert(vec_digicomp[iv].size() > 0);
1163  wcsimrootevent->AddCherenkovDigiHit(vec_pe[iv], vec_time[iv],
1164  tubeID, vec_digicomp[iv]);
1165  sumq_tmp += vec_pe[iv];
1166  countdigihits++;
1167  }//iv
1168  }//Digit exists in Gate
1169  }//k
1170  wcsimrootevent->SetNumDigitizedTubes(countdigihits);
1171  wcsimrootevent->SetSumQ(sumq_tmp);
1172 
1173 #ifdef SAVE_DIGITS_VERBOSE
1174  G4cout << "checking digi hits ...\n";
1175  G4cout << "hits collection size (number of PMTs hit) = " <<
1176  wcsimrootevent->GetCherenkovHits()->GetEntries() << "\n";
1177  G4cout << "hits collection size (number of true photon + dark noise hits) = " <<
1178  wcsimrootevent->GetCherenkovHitTimes()->GetEntries() << "\n";
1179  G4cout << "digihits collection size = " <<
1180  wcsimrootevent->GetCherenkovDigiHits()->GetEntries() << "\n";
1181  G4cout << "tracks collection size = " <<
1182  wcsimrootevent->GetTracks()->GetEntries()
1183  <<" get ntracks = " << wcsimrootevent->GetNtrack() << "\n";
1184 #endif
1185 
1186  gatestart = WCTM->GetTriggerTime(index);
1187  WCSimRootEventHeader*HH = wcsimrootevent->GetHeader();
1188  HH->SetDate(gatestart);
1189  }//index (loop over ngates)
1190 
1191  // end of loop over WC trigger gates --> back to the main sub-event
1192  wcsimrootevent = wcsimrootsuperevent->GetTrigger(0);
1193 
1194  }
1195 
1196 
1197  for (int i = 0 ; i < wcsimrootsuperevent->GetNumberOfEvents(); i++) {
1198  wcsimrootevent = wcsimrootsuperevent->GetTrigger(i);
1199  G4cout << ">>>Root event "
1200  <<std::setw(5)<<wcsimrootevent->GetHeader()->GetEvtNum()<<"\n";
1201  // if (WCDC){
1202  // G4cout <<"WC digi:"<<std::setw(4)<<wcsimrootevent->GetNcherenkovdigihits()<<" ";
1203  // G4cout <<"WC digi sumQ:"<<std::setw(4)<<wcsimrootevent->GetSumQ()<<" ";
1204  }
1205 
1206 #ifdef _SAVE_RAW_HITS
1207  //if (WCHC)
1208  // G4cout <<"WC:"<<std::setw(4)<<wcsimrootevent->GetNcherenkovhits()<<" ";
1209  // if (WCFVHC)
1210  //G4cout <<"WCFV:"<<std::setw(4)<<wcsimrootevent->GetINcherenkovhits()<<" ";
1211 #endif
1212 
1213  // if (WCFVDC){
1214  //G4cout <<"WCFV digi:"<<std::setw(4)<<wcsimrootevent->GetNcherenkovdigihits()<<" ";
1215  //G4cout <<"WCFV digi sumQ:"<<std::setw(4)<<wcsimrootevent->GetSumQ()<<" ";
1216  // }
1217 
1218  TTree* tree = GetRunAction()->GetTree();
1219  TBranch* branch = GetRunAction()->GetBranch(detectorElement);
1220  branch->Fill();
1221  //tree->Fill();
1222  // TFile* hfile = tree->GetCurrentFile();
1223  // // MF : overwrite the trees -- otherwise we have as many copies of the tree
1224  // // as we have events. All the intermediate copies are incomplete, only the
1225  // // last one is useful --> huge waste of disk space.
1226  // hfile->Write("",TObject::kOverwrite);
1227 
1228  if(detectorElement=="tank") runAction->incrementEventsGenerated();
1229 
1230  // M Fechner : reinitialize the super event after the writing is over
1231  wcsimrootsuperevent->ReInitialize();
1232 
1233 }
int vecRecNumber
Definition: jhfNtuple.h:13
double pdir[MAX_N_PRIMARIES][3]
Definition: jhfNtuple.h:28
WCSimPrimaryGeneratorAction * generatorAction
void SetRelativeDigitizedHitTime(bool val)
Definition: WCSimWCPMT.hh:25
Int_t GetEvtNum() const
A simple NDigits trigger class.
void SetNumDigitizedTubes(Int_t i)
void SaveOptionsToOutput(WCSimRootOptions *wcopt)
Save current values of options.
TBranch * GetBranch(G4String detectorElement="tank")
G4ThreeVector GetInitialMomentum() const
Double_t GetTriggerTime(int i)
Get the time of the ith trigger.
int stopvol[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:26
double stop[MAX_N_PRIMARIES][3]
Definition: jhfNtuple.h:29
void EndOfEventAction(const G4Event *)
virtual G4VTrajectoryPoint * GetPoint(G4int i) const
WCSimRootCherenkovHit * AddCherenkovHit(Int_t tubeID, std::vector< Double_t > truetime, std::vector< Int_t > primParID)
double time[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:32
WCSimRootEvent * GetRootEvent(G4String detectorElement="tank")
#define VERBOSE_PMT
TriggerType_t GetTriggerType(int i)
Get the trigger type of the ith trigger.
TClonesArray * GetCherenkovHitTimes() const
int vtxsvol[MAX_N_VERTICES]
Definition: jhfNtuple.h:11
WCSimRootEventHeader * GetHeader()
void SetVtxs(Int_t n, Int_t i, Double_t f)
void SetNumTubesHit(Int_t i)
WCSimWCDAQMessenger * DAQMessenger
TClonesArray * GetCherenkovHits() const
void SetDate(int64_t d)
G4int WCSimEventFindStartingVolume(G4ThreeVector vtx)
WCSimRunAction * GetRunAction()
G4THitsCollection< WCSimWCHit > WCSimWCHitsCollection
Definition: WCSimWCHit.hh:169
tuple energy
Definition: MakeKin.py:93
int NumberOfGatesInThisEvent()
Returns the number of trigger gates in the event (i.e. the number of triggers passed) ...
G4int GetTrackID() const
G4bool GetSaveFlag() const
int numTubesHit
Definition: jhfNtuple.h:34
virtual void DrawTrajectory(G4int i_mode=0) const
G4int GetPDGEncoding() const
TClonesArray * GetTracks() const
G4TDigiCollection< WCSimWCDigi > WCSimWCDigitsCollection
Definition: WCSimWCDigi.hh:214
WCSimRootCherenkovDigiHit * AddCherenkovDigiHit(Double_t q, Double_t t, Int_t tubeid, std::vector< int > photon_ids)
G4TDigiCollection< WCSimWCDigiTrigger > WCSimWCTriggeredDigitsCollection
int mode[MAX_N_VERTICES]
Definition: jhfNtuple.h:9
G4ThreeVector GetStoppingPoint() const
void SetJp(Int_t i)
double dir[MAX_N_PRIMARIES][3]
Definition: jhfNtuple.h:27
int parent[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:31
The base class for WCSim triggering algorithms.
void SetTriggerInfo(TriggerType_t trigger_type, std::vector< Float_t > trigger_info)
G4double GetGlobalTime() const
#define NPMTS_VERBOSE
void CreateDAQInstances()
Create instances of the user-chosen digitizer and trigger classes.
void SetPi0Info(Double_t pi0Vtx[3], Int_t gammaID[2], Double_t gammaE[2], Double_t gammaVtx[2][3])
WCSimRootTrigger * GetTrigger(int number)
Int_t GetNtrack() const
double start[MAX_N_PRIMARIES][3]
Definition: jhfNtuple.h:30
void Digitize()
Definition: WCSimWCPMT.cc:82
void ReInitialize()
Definition: WCSimWCPMT.hh:22
void SetNpar(Int_t i)
void SetJmu(Int_t i)
void SaveOptionsToOutput(WCSimRootOptions *wcopt)
Save current values of options.
G4ParticleDefinition * GetParticleDefinition()
G4int WCSimEventFindStoppingVolume(G4String stopVolumeName)
int startvol[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:25
Int_t GetNumberOfEvents() const
std::vector< Float_t > GetTriggerInfo(int i)
Get the additional trigger information associated with the ith trigger.
int flag[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:18
G4int GetParentID() const
void SetDarkRate(double idarkrate)
Knowledge of the dark rate (use for automatically adjusting for noise)
TTree * GetTree()
void SaveOptionsToOutput(WCSimRootOptions *wcopt)
WCSimRootTrack * AddTrack(Int_t ipnu, Int_t flag, Double_t m, Double_t p, Double_t E, Int_t startvol, Int_t stopvol, Double_t dir[3], Double_t pdir[3], Double_t stop[3], Double_t start[3], Int_t parenttype, Double_t time, Int_t id)
WCSimRunAction * runAction
TClonesArray * GetCherenkovDigiHits() const
void SetHeader(Int_t i, Int_t run, int64_t date, Int_t subevtn=1)
G4VPhysicalVolume * GetStoppingVolume() const
WCSimDetectorConstruction * detectorConstructor
void FillRootEvent(G4int, const struct ntupleStruct &, G4TrajectoryContainer *, WCSimWCDigitsCollection *, WCSimWCTriggeredDigitsCollection *, G4String detectorElement="tank")
struct ntupleStruct jhfNtuple
double vtxs[MAX_N_VERTICES][4]
Definition: jhfNtuple.h:12
double m[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:22
WCSimEventAction(WCSimRunAction *, WCSimDetectorConstruction *, WCSimPrimaryGeneratorAction *)
double p[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:23
static const int MAX_N_VERTICES
Definition: jhfNtuple.h:3
void SetVecRecNumber(Int_t i)
void SetMode(Int_t i)
G4double GetCharge() const
WCSimRootOptions * GetRootOptions()
void BeginOfEventAction(const G4Event *)
void SetVtxsvol(Int_t i, Int_t v)
void SaveOptionsToOutput(WCSimRootOptions *wcopt, string tag)
double E[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:24
void SetSumQ(Double_t x)
An (incomplete) example of running two trigger algorithms, one after the other.
void incrementEventsGenerated()
void Digitize()
The main user-callable routine of the class. Gets the input &amp; creates the output WCSimWCTriggeredDigi...
int ipnu[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:17
void SetNvtxs(Int_t i)