WCSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
WCSimWCAddDarkNoise.cc
Go to the documentation of this file.
1 #include "WCSimWCAddDarkNoise.hh"
2 #include "WCSimWCPMT.hh"
3 #include "WCSimWCDigi.hh"
4 #include "WCSimWCHit.hh"
5 #include "WCSimWCTrigger.hh"
6 
7 #include "G4EventManager.hh"
8 #include "G4Event.hh"
9 #include "G4SDManager.hh"
10 #include "G4DigiManager.hh"
11 #include "G4ios.hh"
12 #include "G4RotationMatrix.hh"
13 #include "G4ThreeVector.hh"
14 #include "G4LogicalVolumeStore.hh"
15 
17 #include "WCSimPmtInfo.hh"
19 
20 #include <vector>
21 #include <utility>
22 // for memset
23 #include <cstring>
24 
25 #ifndef WCSIMWCADDDARKNOISE_VERBOSE
26 //#define WCSIMWCADDDARKNOISE_VERBOSE
27 #endif
28 
29 #ifndef NPMTS_VERBOSE
30 #define NPMTS_VERBOSE 10
31 #endif
32 
33 #ifndef HYPER_VERBOSITY
34 // #define HYPER_VERBOSITY
35 #endif
36 
38  WCSimDetectorConstruction* inDetector,
39  G4String detectorElement)
40  :G4VDigitizerModule(name), fCalledAddDarkNoise(false), myDetector(inDetector), detectorElement(detectorElement)
41 {
42  //Set defaults to be unphysical, so that we know if they have been overwritten by the user
43  PMTDarkRate = -99;
44  ConvRate = -99;
45 
46  //Get the user options
47  // DarkRateMessenger = new WCSimDarkRateMessenger(this);
49  DarkRateMessenger->AddDarkRateInstance(this, detectorElement);
51  ReInitialize();
52 }
53 
55  // delete DarkRateMessenger;
56  DarkRateMessenger->RemoveDarkRateInstance(detectorElement); // DarkRateMessenger singleton calls it's destructor when map is empty
58 }
59 
61 {
62  //Grab Dark Rate and Conversion from PMT itself
63  // G4String WCIDCollectionName = myDetector->GetIDCollectionName();
64  // WCSimPMTObject * PMT = myDetector->GetPMTPointer(WCIDCollectionName);
65  G4String WCCollectionName;
66  if(detectorElement == "tank") WCCollectionName = myDetector->GetIDCollectionName();
67  else if(detectorElement == "OD") WCCollectionName = myDetector->GetODCollectionName();
68  else G4cout << "### detectorElement undefined ..." << G4endl;
69  WCSimPMTObject * PMT = myDetector->GetPMTPointer(WCCollectionName);
70 
71  double const conversion_to_kHz = 1000000; //ToDo: remove this and treat DarkRate in CLHEP units throughout the class.
72 
73  double defaultPMTDarkRate = PMT->GetDarkRate() * conversion_to_kHz;
74  double defaultConvRate = PMT->GetDarkRateConversionFactor();
75 
76  //Only set the defaults if the user hasn't overwritten the unphysical defaults
77  if(PMTDarkRate < -98)
78  PMTDarkRate = defaultPMTDarkRate;
79  if(ConvRate < -98)
80  ConvRate = defaultConvRate;
81 }
82 
84  //Grab the PMT-specific defaults
85  if(!fCalledAddDarkNoise) {
87  fCalledAddDarkNoise = true;
88  }
89 
90  //clear the result and range vectors
91  ReInitialize();
92 
93  G4DigiManager* DigiMan = G4DigiManager::GetDMpointer();
94  // Get the PMT collection ID
95  // G4int WCHCID = DigiMan->GetDigiCollectionID("WCRawPMTSignalCollection");
96 
97  // Get the PMT collection ID
98  G4String thecollectionName;
99  if(detectorElement=="tank") thecollectionName="WCRawPMTSignalCollection";
100  else if(detectorElement=="OD") thecollectionName="WCRawPMTSignalCollection_OD";
101  else G4cout << "### detectorElement undefined ..." << G4endl;
102  G4int WCHCID = DigiMan->GetDigiCollectionID(thecollectionName);
103 
104  // Get the PMT Digits collection
105  WCSimWCDigitsCollection* WCHCPMT =
106  (WCSimWCDigitsCollection*)(DigiMan->GetDigiCollection(WCHCID));
107 
108  #ifdef HYPER_VERBOSITY
109  if(detectorElement=="OD"){G4cout<<"WCSimWCAddDarkNoise::AddDarkNoise ☆ retrieved hit collection (WCSimWCDigitsCollection*)"<<thecollectionName<<" which has "<<WCHCPMT->entries()<<" entries"<<G4endl;}
110  #endif
111 
112  G4String thetriggertype="";
113  if(detectorElement=="OD") { // check to see if this detector element uses the tank for triggering
114  WCSimWCTriggerBase *WCTM = (WCSimWCTriggerBase *) DigiMan->FindDigitizerModule("WCReadout_OD");
115  thetriggertype = WCTM->GetTriggerClassName();
116  }
117 
118  WCSimWCDigitsCollection* WCHCPMT_tank=NULL;
119  if(thetriggertype=="TankDigits"){
120  //if triggertype is TankDigits, then we should add noise in the windows around the *tank* digits, not this
121  //collection's digits, because those are the windows that will be relevant when reading out triggers.
122  int WCHCID_tank = DigiMan->GetDigiCollectionID("WCRawPMTSignalCollection");
123  WCHCPMT_tank = (WCSimWCDigitsCollection*)(DigiMan->GetDigiCollection(WCHCID_tank));
124  (WCSimWCDigitsCollection*)(DigiMan->GetDigiCollection(WCHCID));
125  #ifdef HYPER_VERBOSITY
126  if(detectorElement=="OD"){ G4cout<<"WCSimWCAddDarkNoise::AddDarkNoise ☆ retrieved hit collection (WCSimWCDigitsCollection*)WCRawPMTSignalCollection for finding dark noise windows, which has "<<WCHCPMT_tank->entries()<<" entries"<<G4endl;}
127  #endif
128  }
129 
130  // if ((WCHCPMT != NULL) && (this->PMTDarkRate > 1E-307)) {
131  if (((WCHCPMT != NULL)||(thetriggertype=="TankDigits"&&WCHCPMT_tank!=NULL)) && (this->PMTDarkRate > 1E-307)) {
132  //Determine ranges for adding noise
133  // if(DarkMode == 1)
134  // FindDarkNoiseRanges(WCHCPMT,this->DarkWindow);
135  if(DarkMode == 1){
136  if(thetriggertype=="TankDigits"){
137  WCSimWCAddDarkNoise* WCDNM_tank = (WCSimWCAddDarkNoise*)DigiMan->FindDigitizerModule("WCDarkNoise");
138  int DarkWindow_tank = WCDNM_tank->GetDarkWindow();
139  #ifdef HYPER_VERBOSITY
140  if(detectorElement=="OD") G4cout<<"WCSimWCAddDarkNoise::AddDarkNoise ☆ calling FindDarkNoiseRanges() with tank raw collection and darkwindow size"<<G4endl;
141  #endif
142  FindDarkNoiseRanges(WCHCPMT_tank,DarkWindow_tank);
143  } else {
144  FindDarkNoiseRanges(WCHCPMT,this->DarkWindow);
145  }
146  }
147  else if(DarkMode == 0) {
148  result.push_back(std::pair<double,double>(DarkLow,DarkHigh));
149  }
150  //Call routine to add dark noise here.
151  //loop over pairs which represent ranges.
152  //Add noise to those ranges
153  #ifdef HYPER_VERBOSITY
154  if(detectorElement=="OD") G4cout<<"WCSimWCAddDarkNoise::AddDarkNoise ☆ adding dark noise hits in "<<result.size()<<" window(s) around found digits."<<G4endl;
155  #endif
156  int windowfordarknoise=0;
157 
158  for(std::vector<std::pair<double, double> >::iterator it2 = result.begin(); it2 != result.end(); it2++) {
159  #ifdef HYPER_VERBOSITY
160  if(detectorElement=="OD") G4cout<<"WCSimWCAddDarkNoise::AddDarkNoise ☆ adding dark noise in window "<<windowfordarknoise<<G4endl; windowfordarknoise++;
161  #endif
162  AddDarkNoiseBeforeDigi(WCHCPMT,it2->first,it2->second);
163  }
164  }
165 }
166 
168  // Introduces dark noise into each PMT during an event window
169  // This won't introduce noise only events, and isn't written
170  // to handle different rates for each PMT (although this shouldn't
171  // be too difficult to add at a later time)
172  //
173  // Added by: Morgan Askins (maskins@ucdavis.edu)
174 
175  G4int number_entries = WCHCPMT->entries();
176  // const G4int number_pmts = myDetector->GetTotalNumPmts();
177  #ifdef HYPER_VERBOSITY
178  if(detectorElement=="OD")G4cout<<"WCSimWCAddDarkNoise::AddDarkNoiseBeforeDigi ☆ adding dark noise to collection of "<<number_entries<<" entries"<<G4endl;
179  #endif
180  G4int thenum_pmts;
181  if(detectorElement=="tank") thenum_pmts = myDetector->GetTotalNumPmts();
182  else if(detectorElement=="OD") thenum_pmts = myDetector->GetTotalNumODPmts();
183  else G4cout << "### detectorElement undefined ..." << G4endl;
184  const G4int number_pmts=thenum_pmts;
185  int *PMTindex = new int [number_pmts+1];
186 
187  //initialize PMTindex
188  for (int l=0; l<number_pmts+1; l++){
189  PMTindex[l] =0;
190  }
191 
192  // G4cout<<"entries before "<<WCHCPMT->entries()<<"\n";
193  //Set up proper indices for tubes which have already been hit
194  int num_hit_b4=0;
195  for (int g=0; g<number_entries; g++){
196  G4int tube = (*WCHCPMT)[g]->GetTubeID();
197  //G4cout<<"totalpe "<<tube<<" "<<(*WCHCPMT)[g]->GetTotalPe()<<"\n";
198  //should this be tube-1?
199  PMTindex[tube] += (*WCHCPMT)[g]->GetTotalPe();
200  num_hit_b4 += (*WCHCPMT)[g]->GetTotalPe();
201  //G4cout<<"TotalPe "<<(*WCHCPMT)[g]->GetTotalPe()<<" "<<PMTindex[tube]<<"\n";
202  }
203 
204  // Get the info for pmt positions
205  // std::vector<WCSimPmtInfo*> *pmts = myDetector->Get_Pmts();
206 
207  std::vector<WCSimPmtInfo*> *pmts;
208  if(detectorElement=="tank") pmts = myDetector->Get_Pmts();
209  else if(detectorElement=="OD")pmts = myDetector->Get_ODPmts();
210  else G4cout << "### detectorElement undefined ..." << G4endl;
211 
212  // It works out that the pmts here are ordered !
213  // pmts->at(i) has tubeid i+1
214 
215  std::vector<int> list;
216  list.assign( number_pmts+1, 0 );
217 
218  for( int h = 0; h < number_entries; h++ ) {
219  list[(*WCHCPMT)[h]->GetTubeID()] = h+1;
220  }
221 
222  // Add noise to PMT's here, do so in the range num1 to num2
223  double current_time = 0;
224  double pe = 0.0;
225  //Calculate the time window size
226  double windowsize = num2 - num1;
227 
228  G4DigiManager* DMman = G4DigiManager::GetDMpointer();
229  // WCSimWCPMT* WCPMT = (WCSimWCPMT*)DMman->FindDigitizerModule("WCReadoutPMT");
230 
231  G4String thewcpmtname;
232  if(detectorElement=="tank") thewcpmtname="WCReadoutPMT";
233  else if(detectorElement=="OD") thewcpmtname="WCReadoutPMT_OD";
234  else G4cout << "### detectorElement undefined ..." << G4endl;
235 
236  WCSimWCPMT* WCPMT = (WCSimWCPMT*)DMman->FindDigitizerModule(thewcpmtname);
237  #ifdef HYPER_VERBOSITY
238  if(detectorElement=="OD"){G4cout<<"WCSimWCAddDarkNoise::AddDarkNoiseBeforeDigi ☆ getting (WCSimWCPMT*)"<<thewcpmtname<<G4endl;}
239  #endif
240 
241 
242  //average number of PMTs with noise
243  double ave=number_pmts * this->PMTDarkRate * this->ConvRate * windowsize * 1E-6;
244 
245  //poisson distributed noise, number of noise hits to add
246  int nnoispmt = CLHEP::RandPoisson::shoot(ave);
247  G4String thecollectionName;
248  if(detectorElement=="tank") thecollectionName="WCRawPMTSignalCollection";
249  else if(detectorElement=="OD") thecollectionName="WCRawPMTSignalCollection_OD";
250  else G4cout << "### detectorElement undefined ..." << G4endl;
251  #ifdef HYPER_VERBOSITY
252  if(detectorElement=="OD"){G4cout<<"WCSimWCAddDarkNoise::AddDarkNoiseBeforeDigi ☆ adding "<<nnoispmt<<" dark hits to "<<thecollectionName<<G4endl;}
253  #endif
254 
255 #ifdef WCSIMWCADDDARKNOISE_VERBOSE
256  G4cout << "WCSimWCAddDarkNoise::AddDarkNoiseBeforeDigi Going to add " << nnoispmt << " dark noise hits in time window [" << num1 << "," << num2 << "] duration " << num2 - num1 << G4endl;
257 #endif
258  for( int i = 0; i < nnoispmt; i++ )
259  {
260  //time of noise hit to be generated
261  //A time from t=num1 to num2
262  current_time = num1 + G4UniformRand()*windowsize;
263 
264  //now a random PMT. Assuming noise levels are the same for
265  //each PMT.
266  int noise_pmt = static_cast<int>( G4UniformRand() * number_pmts ) + 1; //so that pmt numbers runs from 1 to Npmt
267 
268  if( list[ noise_pmt ] == 0 )
269  {
270  //PMT has no hits yet. Create a new WCSimWCDigi
271  WCSimWCDigi* ahit = new WCSimWCDigi();
272  ahit->SetTubeID( noise_pmt);
273  //G4cout<<"setting new noise pmt "<<noise_pmt<<" "<<ahit->GetTubeID()<<"\n";
274  // This Logical volume is GlassFaceWCPMT
275 
276  // ahit->SetLogicalVolume(G4LogicalVolumeStore::GetInstance()->GetVolume(myDetector->GetDetectorName()+"-glassFaceWCPMT"));
277 
278  if(detectorElement=="tank") ahit->SetLogicalVolume(G4LogicalVolumeStore::GetInstance()->GetVolume(myDetector->GetDetectorName()+"-glassFaceWCPMT"));
279  else if(detectorElement=="OD")ahit->SetLogicalVolume(G4LogicalVolumeStore::GetInstance()->GetVolume(myDetector->GetDetectorName()+"-glassFaceWCPMT_OD"));
280  else G4cout << "### detectorElement undefined ..." << G4endl;
281 
282  //G4cout<<"1 "<<(G4LogicalVolumeStore::GetInstance()->GetVolume("glassFaceWCPMT"))->GetName()<<"\n";
283  //G4cout<<"2 "<<(*WCHCPMT)[0]->GetLogicalVolume()->GetName()<<"\n";
284  ahit->SetTrackID(-1);
285  ahit->SetParentID(PMTindex[noise_pmt], -1);
286  // Set the position and rotation of the pmt
287  Double_t hit_pos[3];
288  Double_t hit_rot[3];
289  // TODO: need to change the format of hit_pos to G4ThreeVector
290  // and change hit_rot to G4RotationMatrix
291 
292  WCSimPmtInfo* pmtinfo = (WCSimPmtInfo*)pmts->at( noise_pmt -1 );
293  hit_pos[0] = 10*pmtinfo->Get_transx();
294  hit_pos[1] = 10*pmtinfo->Get_transy();
295  hit_pos[2] = 10*pmtinfo->Get_transz();
296  hit_rot[0] = pmtinfo->Get_orienx();
297  hit_rot[1] = pmtinfo->Get_orieny();
298  hit_rot[2] = pmtinfo->Get_orienz();
299  G4RotationMatrix pmt_rotation(hit_rot[0], hit_rot[1], hit_rot[2]);
300  G4ThreeVector pmt_position(hit_pos[0], hit_pos[1], hit_pos[2]);
301  ahit->SetRot(pmt_rotation);
302  ahit->SetPos(pmt_position);
303  ahit->SetTime(PMTindex[noise_pmt],current_time);
304  ahit->SetPreSmearTime(PMTindex[noise_pmt],current_time); //presmear==postsmear for dark noise
305  pe = WCPMT->rn1pe();
306  ahit->SetPe(PMTindex[noise_pmt],pe);
307  //Added this line to increase the totalPe by 1
308  ahit->AddPe(current_time);
309  WCHCPMT->insert(ahit);
310  PMTindex[noise_pmt]++;
311  number_entries ++;
312  list[ noise_pmt ] = number_entries; // Add this PMT to the end of the list
313 #ifdef WCSIMWCADDDARKNOISE_VERBOSE
314  if(noise_pmt < NPMTS_VERBOSE)
315  G4cout << "WCSimWCAddDarkNoise::AddDarkNoiseBeforeDigi Added NEW DIGI with dark noise hit at time " << current_time << " to PMT " << noise_pmt << G4endl;
316 #endif
317  }
318  else {
319  (*WCHCPMT)[ list[noise_pmt]-1 ]->AddPe(current_time);
320  pe = WCPMT->rn1pe();
321  (*WCHCPMT)[ list[noise_pmt]-1 ]->SetPe(PMTindex[noise_pmt],pe);
322  (*WCHCPMT)[ list[noise_pmt]-1 ]->SetTime(PMTindex[noise_pmt],current_time);
323  (*WCHCPMT)[ list[noise_pmt]-1 ]->SetPreSmearTime(PMTindex[noise_pmt],current_time); //presmear==postsmear for dark noise
324  (*WCHCPMT)[ list[noise_pmt]-1 ]->SetParentID(PMTindex[noise_pmt],-1);
325  PMTindex[noise_pmt]++;
326 #ifdef WCSIMWCADDDARKNOISE_VERBOSE
327  if(noise_pmt < NPMTS_VERBOSE)
328  G4cout << "WCSimWCAddDarkNoise::AddDarkNoiseBeforeDigi Added to exisiting digi a dark noise hit at time " << current_time << " to PMT " << noise_pmt << G4endl;
329 #endif
330  }
331 
332  }//i (number of noise hits to add)
333 
334  delete [] PMTindex;
335  return;
336 }
337 
338 
339 
341  //Loop over all Hits and assign a time window around each hit
342  //store these in the ranges vector as pairs
343  for (int g=0; g<WCHCPMT->entries(); g++){
344  for (int gp=0; gp<(*WCHCPMT)[g]->GetTotalPe(); gp++){
345  double time = (*WCHCPMT)[g]->GetTime(gp);
346  //lets assume a 5us window. So we centre this on the hit time.
347  //t1 is the lower limit of the window.
348  double t1=time - width/2.;
349  double t2=time + width/2.;
350  ranges.push_back(std::pair<double, double>(t1, t2));
351  }
352  }
353 
354  #ifdef HYPER_VERBOSITY
355  if(detectorElement=="mrd") G4cout<<"WCSimWCAddDarkNoise::FindDarkNoiseRanges ☆ "<<ranges.size()<<" windows around digits found before pruning."<<G4endl;
356  #endif
357  //we need to ensure that the ranges found above are sorted first
358  //for the algorithm below to work
359  sort(ranges.begin(),ranges.end());
360 
361  //check if the vector range has any entries
362  //If no entries this indicates that no digits were
363  //found in the WCSimWCDigitsCollection, which can cause
364  //segmentation faults in the next part of the code in this method
365  //which searches for overlapping ranges.
366  //Set range vector to have one element from 0 to 0 (so no noise digits will be added)
367  if(ranges.size() == 0)
368  {
369  //push back a range of 0 and 0 and return
370  result.push_back(std::make_pair(0.,0.));
371  return;
372  }
373 
374  //the ranges vector contains overlapping ranges
375  //this loop removes overlaps
376  //output are pairs stored in the result vector
377  std::vector<std::pair<double, double> >::iterator it = ranges.begin();
378  std::pair<double, double> current = *(it)++;
379  for( ; it != ranges.end(); it++) {
380  if (current.second >= it->first){
381  current.second = std::max(current.second, it->second);
382  }
383  else {
384  result.push_back(current);
385  current = *(it);
386  }
387  }
388  result.push_back(current);
389 
390  //now we should have a vector of non-overlapping range pairs to pass to the
391  //dark noise routine
392 }
393 
395 {
396  wcopt->SetPMTDarkRate(tag, PMTDarkRate);
397  wcopt->SetConvRate(tag, ConvRate);
398  wcopt->SetDarkHigh(tag, DarkHigh);
399  wcopt->SetDarkLow(tag, DarkLow);
400  wcopt->SetDarkWindow(tag, DarkWindow);
401  wcopt->SetDarkMode(tag, DarkMode);
402 }
void SetPreSmearTime(G4int gate, G4double T)
Definition: WCSimWCDigi.hh:89
void SetLogicalVolume(G4LogicalVolume *logV)
Definition: WCSimWCDigi.hh:121
void SetDarkHigh(string tag, double iDarkHigh)
std::vector< std::pair< double, double > > ranges
Double_t Get_orienx()
Definition: WCSimPmtInfo.hh:36
void SetRot(G4RotationMatrix rotMatrix)
Definition: WCSimWCDigi.hh:123
Double_t Get_transy()
Definition: WCSimPmtInfo.hh:34
Double_t Get_orieny()
Definition: WCSimPmtInfo.hh:37
void AddDarkNoiseBeforeDigi(WCSimWCDigitsCollection *WCHCPMT, double num1, double num2)
void SetTrackID(G4int track)
Definition: WCSimWCDigi.hh:122
void SetTubeID(G4int tube)
Definition: WCSimWCDigi.hh:85
void SetDarkLow(string tag, double iDarkLow)
WCSimPMTObject * GetPMTPointer(G4String CollectionName)
WCSimDarkRateMessenger * DarkRateMessenger
void SetPe(G4int gate, G4double Q)
Definition: WCSimWCDigi.hh:87
G4TDigiCollection< WCSimWCDigi > WCSimWCDigitsCollection
Definition: WCSimWCDigi.hh:214
Double_t Get_transz()
Definition: WCSimPmtInfo.hh:35
The base class for WCSim triggering algorithms.
Double_t Get_transx()
Definition: WCSimPmtInfo.hh:33
void SetPMTDarkRate(string tag, double iPMTDarkRate)
G4String GetTriggerClassName()
Get the trigger class name.
static WCSimDarkRateMessenger * GetInstance()
WCSimDetectorConstruction * myDetector
void SetDarkWindow(string tag, double iDarkWindow)
std::vector< std::pair< double, double > > result
virtual G4double GetDarkRateConversionFactor()=0
WCSimWCAddDarkNoise(G4String name, WCSimDetectorConstruction *, G4String)
void AddPe(G4double hitTime)
Definition: WCSimWCDigi.hh:128
std::vector< WCSimPmtInfo * > * Get_Pmts()
std::vector< WCSimPmtInfo * > * Get_ODPmts()
void SetPos(G4ThreeVector xyz)
Definition: WCSimWCDigi.hh:120
void SetTime(G4int gate, G4double T)
Definition: WCSimWCDigi.hh:88
void FindDarkNoiseRanges(WCSimWCDigitsCollection *WCHCPMT, double width)
Double_t Get_orienz()
Definition: WCSimPmtInfo.hh:38
virtual G4double GetDarkRate()=0
#define NPMTS_VERBOSE
void SetConvRate(string tag, double iConvRate)
void SetParentID(G4int gate, G4int parent)
Definition: WCSimWCDigi.hh:90
void SaveOptionsToOutput(WCSimRootOptions *wcopt, string tag)
void RemoveDarkRateInstance(G4String detectorElement)
double E[MAX_N_PRIMARIES]
Definition: jhfNtuple.h:24
void SetDarkMode(string tag, int iDarkMode)
void AddDarkRateInstance(WCSimWCAddDarkNoise *darkratepoint, G4String detectorElement)
G4double rn1pe()
Definition: WCSimWCPMT.cc:55