ToolDAQFramework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
DataOut.cpp
Go to the documentation of this file.
1 #include "DataOut.h"
2 
3 DataOut::DataOut():Tool(){}
4 
6 bool DataOut::Initialise(std::string configfile, DataModel &data){
7 
8  if(configfile!="") m_variables.Initialise(configfile);
9  //m_variables.Print();
10 
11  m_verbose = 0;
12  m_variables.Get("verbose", m_verbose);
13 
14  //Setup and start the stopwatch
15  bool use_stopwatch = false;
16  m_variables.Get("use_stopwatch", use_stopwatch);
17  m_stopwatch = use_stopwatch ? new util::Stopwatch("DataOut") : 0;
18 
19  m_stopwatch_file = "";
20  m_variables.Get("stopwatch_file", m_stopwatch_file);
21 
23 
24  m_data= &data;
25 
26  //open the output file
27  Log("DEBUG: DataOut::Initialise opening output file...", DEBUG2, m_verbose);
28  if(! m_variables.Get("outfilename", m_output_filename)) {
29  Log("ERROR: outfilename configuration not found. Cancelling initialisation", ERROR, m_verbose);
30  return false;
31  }
32  m_output_file = new TFile(m_output_filename.c_str(), "RECREATE");
33 
34  //other options
36  m_variables.Get("save_multiple_hits_per_trigger", m_save_multiple_hits_per_trigger);
37  Log("WARN: TODO save_multiple_hits_per_trigger is not currently implemented", WARN, m_verbose);
38  double trigger_offset_temp = 0;
39  m_variables.Get("trigger_offset", trigger_offset_temp);
40  m_trigger_offset = TimeDelta(trigger_offset_temp);
42  m_variables.Get("save_only_failed_hits", m_save_only_failed_hits);
43  Log("WARN: TODO save_only_failed_hits is not currently implemented", WARN, m_verbose);
44 
45  //setup the out event tree
46  Log("DEBUG: DataOut::Initialise setting up output event tree...", DEBUG2, m_verbose);
47  // Nevents unique event objects
48  Int_t bufsize = 64000;
49  m_event_tree = new TTree("wcsimT","WCSim Tree");
50  m_id_wcsimevent_triggered = new WCSimRootEvent();
51  m_id_wcsimevent_triggered->Initialize();
52  m_event_tree->Branch("wcsimrootevent", "WCSimRootEvent", &m_id_wcsimevent_triggered, bufsize,2);
53  if(m_data->HasOD) {
54  m_od_wcsimevent_triggered = new WCSimRootEvent();
55  m_od_wcsimevent_triggered->Initialize();
56  m_event_tree->Branch("wcsimrootevent_OD", "WCSimRootEvent", &m_od_wcsimevent_triggered, bufsize,2);
57  }
58  else {
60  }
61  m_event_tree->Branch("wcsimfilename", &(m_data->CurrentWCSimFile));
62  m_event_tree->Branch("wcsimeventnum", &(m_data->CurrentWCSimEventNum));
63 
64  //fill the output event-independent trees
65  Log("DEBUG: DataOut::Initialise filling event-independent trees...", DEBUG2, m_verbose);
66 
67  //There are 1 unique geom objects, so this is a simple clone of 1 entry
68  if(m_data->IsMC) {
69  Log("DEBUG: Geometry...", DEBUG2, m_verbose);
70  TTree * geom_tree = m_data->WCSimGeomTree->CloneTree(1);
71  geom_tree->Write();
72  delete geom_tree;
73  }
74  else {
75  Log("WARN: TODO Geometry tree filling is not yet implemented for data");
76  }
77 
78  //There are Nfiles unique options objects, so this is a clone of all entries
79  // plus a new branch with the wcsim filename
80  if(m_data->IsMC) {
81  Log("DEBUG: Options & file names...", DEBUG2, m_verbose);
82  TTree * options_tree = m_data->WCSimOptionsTree->CloneTree();
83  m_ss << "DEBUG: entries: " << options_tree->GetEntries();
85  TObjString * wcsimfilename = new TObjString();
86  TBranch * branch = options_tree->Branch("wcsimfilename", &wcsimfilename);
87  for(int i = 0; i < options_tree->GetEntries(); i++) {
88  m_data->WCSimOptionsTree->GetEntry(i);
89  options_tree->GetEntry(i);
90  wcsimfilename->SetString(m_data->WCSimOptionsTree->GetFile()->GetName());
91  branch->Fill();
92  }//i
93  options_tree->Write();
94  delete wcsimfilename;
95  delete options_tree;
96  }
97 
98  Log("DEBUG: DataOut::Initialise creating trigger info...", DEBUG2, m_verbose);
100  m_event_num = 0;
101 
102  if(m_stopwatch) Log(m_stopwatch->Result("Initialise"), INFO, m_verbose);
103 
104  return true;
105 }
106 
110 
113 
114  //Gather together all the trigger windows
116  m_all_triggers->AddTriggers(&(m_data->IDTriggers));
117  if(m_data->HasOD)
118  m_all_triggers->AddTriggers(&(m_data->ODTriggers));
119  m_ss << "INFO: Have " << m_all_triggers->m_num_triggers << " triggers to save times:";
120  StreamToLog(INFO);
121  for(int i = 0; i < m_all_triggers->m_num_triggers; i++) {
122  m_ss << "INFO: \t[" << m_all_triggers->m_readout_start_time.at(i)
123  << ", " << m_all_triggers->m_readout_end_time.at(i) << "] "
124  << m_all_triggers->m_trigger_time.at(i) << " ns with type "
125  << WCSimEnumerations::EnumAsString(m_all_triggers->m_type.at(i)) << " extra info";
126  for(unsigned int ii = 0; ii < m_all_triggers->m_info.at(i).size(); ii++)
127  m_ss << " " << m_all_triggers->m_info.at(i).at(ii);
128  StreamToLog(INFO);
129  }//i
130 
131  //Note: the trigger ranges vector can contain overlapping ranges
132  //we want to make sure the triggers output aren't overlapping
133  // This is actually handled in DataOut::FillHits()
134  // It puts hits into the output event in the earliest trigger they belong to
135 
136  //Fill the WCSimRootEvent with hit/trigger information, and truth information (if available)
137  if(m_all_triggers->m_num_triggers || m_data->IsMC) {
138  ExecuteSubDet(m_id_wcsimevent_triggered, m_data->IDSamples, m_data->IDWCSimEvent_Raw);
139  if(m_data->HasOD) {
140  ExecuteSubDet(m_od_wcsimevent_triggered, m_data->ODSamples, m_data->ODWCSimEvent_Raw);
141  }
142 
143  //Fill the tree with what we've just created
144  m_event_tree->Fill();
145  }//>=1 trigger found or IsMC
146 
147  //increment event number
148  m_event_num++;
149 
151 
152  return true;
153 }
155 void DataOut::ExecuteSubDet(WCSimRootEvent * wcsim_event, std::vector<SubSample> & samples, WCSimRootEvent * original_wcsim_event) {
156  //ReInitialise the WCSimRootEvent
157  // This clears the TObjArray of WCSimRootTrigger's,
158  // and creates a WCSimRootTrigger in the first slot
159  wcsim_event->ReInitialize();
160 
161  //If there are multiple triggers in the event,
162  // create subevents (i.e. new WCSimRootTrigger's) in the WCSimRootEvent
163  //Also sets the time correctly
164  CreateSubEvents(wcsim_event);
165 
166  //Get the WCSim "date", used later to give the hits the correct absolute time.
167  // Also add the trigger offset from the config file
168  TimeDelta time_shift = GetOffset(original_wcsim_event);
169 
170  //For every hit, if it's in a trigger window,
171  //add it to the appropriate WCSimRootTrigger in the WCSimRootEvent
172  FillHits(wcsim_event, samples);
173 
174  //If this is an MC file, we also need to add
175  // - true tracks
176  // - true hits
177  if(m_data->IsMC)
178  AddTruthInfo(wcsim_event, original_wcsim_event, time_shift);
179 
180  //Set some trigger header infromation that requires all the hits to be
181  // present to calculate e.g. sumq
182  FinaliseSubEvents(wcsim_event);
183 }
185 void DataOut::CreateSubEvents(WCSimRootEvent * wcsim_event) {
186  const int n = m_all_triggers->m_num_triggers;
187  WCSimRootTrigger * trig;
188  if (n==0) {
189  trig = wcsim_event->GetTrigger(0);
190  trig->SetHeader(m_event_num, 0, 0, 0);
191  return;
192  }
193 
194  // Change trigger times and create new SubEvents where necessary
195  for(int i = 0; i < n; i++) {
196  if(i)
197  wcsim_event->AddSubEvent();
198  trig = wcsim_event->GetTrigger(i);
199  trig->SetHeader(m_event_num, 0, (m_all_triggers->m_trigger_time.at(i) / TimeDelta::ns), i+1);
200  trig->SetTriggerInfo(m_all_triggers->m_type.at(i), m_all_triggers->m_info.at(i));
201  trig->SetMode(0);
202  }//i
203 }
205 TimeDelta DataOut::GetOffset(WCSimRootEvent * original_wcsim_event) {
206 
207  TimeDelta time_shift(0);
208 
209  if(m_data->IsMC) {
210  // Get the original event trigger time ("date"). Subtraction of this is used
211  // when we want to store the hits with their new trigger offsets
212  WCSimRootTrigger * trig0 = original_wcsim_event->GetTrigger(0);
213  // The old time (stored in ns)
214  TimeDelta old_trigger_time = trig0->GetHeader()->GetDate() * TimeDelta::ns;
215  time_shift += old_trigger_time;
216  m_ss << "DEBUG: Trigger date shift from input WCSim file is " << old_trigger_time;
218  }
219 
220  m_ss << "DEBUG: Adding additional user-defined time shift of "
221  << m_trigger_offset;
223 
224  time_shift += m_trigger_offset;
225  m_ss << "DEBUG: Total time shift is " << time_shift;
227 
228  return time_shift;
229 }
231 void DataOut::FillHits(WCSimRootEvent * wcsim_event, std::vector<SubSample> & samples) {
232  unsigned int trigger_window;
233  TimeDelta time;
234  std::vector<int> photon_id_temp;
235  WCSimRootTrigger * wcsim_trigger;
236  //Loop over all SubSamples
237  for(std::vector<SubSample>::iterator is=samples.begin(); is!=samples.end(); ++is){
238  const size_t nhits = is->m_time.size();
239  unsigned int counter = 0;
240  for(size_t ihit = 0; ihit < nhits; ihit++) {
241  //skip if hit is not in a readout window
242  if(!is->m_trigger_readout_windows[ihit].size())
243  continue;
244 
245  //Find out which window it's in.
246  // We're taking the first one it's associated with
247  trigger_window = is->m_trigger_readout_windows[ihit][0];
248  wcsim_trigger = wcsim_event->GetTrigger(trigger_window);
249 
250  //Get the time
251  time = is->AbsoluteDigitTime(ihit);
252  m_ss << "Hit " << ihit << " is at time " << time << std::endl;
254 
255  //Apply the time offsets
256  // + m_trigger_offset adds the user-defined "offset"
257  // - trigger time ("Date") because hits are defined relative to their trigger time
258  time += m_trigger_offset -
259  (wcsim_trigger->GetHeader()->GetDate() * TimeDelta::ns);
260 
261  //hit is in this window. Let's save it
262  wcsim_trigger->AddCherenkovDigiHit(is->m_charge[ihit],
263  time / TimeDelta::ns,
264  is->m_PMTid[ihit],
265  photon_id_temp);
266  m_ss << "Saved hit " << counter++;
268  }//ihit
269  }//loop over SubSamples
270 }
272 void DataOut::AddTruthInfo(WCSimRootEvent * wcsim_event, WCSimRootEvent * original_wcsim_event, const TimeDelta & time_shift) {
273  //get the "triggers", where everything is stored
274  WCSimRootTrigger * new_trig = wcsim_event->GetTrigger(0);
275  WCSimRootTrigger * old_trig = original_wcsim_event->GetTrigger(0);
276 
277  //set vertex info
278  const int nvtx = old_trig->GetNvtxs();
279  new_trig->SetNvtxs(nvtx);
280  for(int ivtx = 0; ivtx < nvtx; ivtx++) {
281  new_trig->SetVtxsvol(ivtx, old_trig->GetVtxsvol(ivtx));
282  for(int idim = 0; idim < 3; idim++) {
283  new_trig->SetVtxs(ivtx, idim, old_trig->GetVtxs(ivtx, idim));
284  }//idim
285  }//ivtx
286 
287  //set generic event info
288  new_trig->SetMode(old_trig->GetMode());
289  new_trig->SetVecRecNumber(old_trig->GetVecRecNumber());
290  new_trig->SetJmu(old_trig->GetJmu());
291  new_trig->SetJp(old_trig->GetJp());
292  new_trig->SetNpar(old_trig->GetNpar());
293 
294  //set pi0 info
295  const WCSimRootPi0 * pi0 = old_trig->GetPi0Info();
296  Double_t pi0_vtx[3];
297  Int_t pi0_gamma_id[2];
298  Double_t pi0_gamma_e[2];
299  Double_t pi0_gamma_vtx[2][3];
300  for(int i = 0; i < 3; i++)
301  pi0_vtx[i] = pi0->GetPi0Vtx(i);
302  for(int i = 0; i < 2; i++) {
303  pi0_gamma_id[i] = pi0->GetGammaID(i);
304  pi0_gamma_e [i] = pi0->GetGammaE (i);
305  for(int j = 0; j < 3; j++)
306  pi0_gamma_vtx[i][j] = pi0->GetGammaVtx(i, j);
307  }//i
308  new_trig->SetPi0Info(pi0_vtx, pi0_gamma_id, pi0_gamma_e, pi0_gamma_vtx);
309 
310  //set true hit info
311  new_trig->SetNumTubesHit(old_trig->GetNumTubesHit());
312  WCSimRootCherenkovHit * hit;
313  WCSimRootCherenkovHitTime * hit_time;
314  for(int ihit = 0; ihit < old_trig->GetNcherenkovhits(); ihit++) {
315  TObject * obj = old_trig->GetCherenkovHits()->At(ihit);
316  if(!obj) continue;
317  hit = dynamic_cast<WCSimRootCherenkovHit*>(obj);
318  int tube_id = hit->GetTubeID();
319  std::vector<double> true_times;
320  std::vector<int> primary_parent_id;
321  for(int itime = hit->GetTotalPe(0); itime < hit->GetTotalPe(0) + hit->GetTotalPe(1); itime++) {
322  TObject * obj = old_trig->GetCherenkovHitTimes()->At(itime);
323  if(!obj) continue;
324  hit_time = dynamic_cast<WCSimRootCherenkovHitTime*>(obj);
325  true_times .push_back(hit_time->GetTruetime());
326  primary_parent_id.push_back(hit_time->GetParentID());
327  }//itime
328  new_trig->AddCherenkovHit(tube_id, true_times, primary_parent_id);
329  }//ihit
330 
331  //set true track info
332  WCSimRootTrack * track;
333  for(int itrack = 0; itrack < old_trig->GetNtrack_slots(); itrack++) {
334  TObject * obj = old_trig->GetTracks()->At(itrack);
335  if(!obj) continue;
336  track = dynamic_cast<WCSimRootTrack*>(obj);
337  new_trig->AddTrack(track);
338  }//itrack
339 
340  //set true digit parent info
341  // This is messy, since the WCSim digit order
342  // is different to the TriggerApplication digit order
343  //we're looping over triggers here
344  for(int itrigger = 0; itrigger < m_all_triggers->m_num_triggers; itrigger++) {
345  if(itrigger)
346  new_trig = wcsim_event->GetTrigger(itrigger);
347  double this_trigger_time = new_trig->GetHeader()->GetDate();
348  WCSimRootCherenkovDigiHit * new_digit;
349  WCSimRootCherenkovDigiHit * old_digit;
350  //not looping over "slots", because we just wrote this file, so we know there are no gaps
351  for(int idigit = 0; idigit < new_trig->GetNcherenkovdigihits(); idigit++) {
352  TObject * obj = new_trig->GetCherenkovDigiHits()->At(idigit);
353  if(!obj) continue;
354  new_digit = dynamic_cast<WCSimRootCherenkovDigiHit*>(obj);
355  int tube_id = new_digit->GetTubeId();
356  //get the time
357  double time = new_digit->GetT();
358  //and convert it back to the original (i.e. relative to WCSim's Date(), rather than
359  // TriggerApp's individual triggers' Date()s)
360  // - time_shift subtracts the WCSim Date, and subtracts the user-defined "offset"
361  // + this_trigger_time because hits are defined relative to their trigger time
362  time += - (time_shift / TimeDelta::ns) + this_trigger_time;
363 
364  //Now we find the new digit
365  bool found = false;
366  for(int idigit_old = 0; idigit_old < old_trig->GetNcherenkovdigihits_slots(); idigit_old++) {
367  TObject * obj = old_trig->GetCherenkovDigiHits()->At(idigit_old);
368  if(!obj) continue;
369  old_digit = dynamic_cast<WCSimRootCherenkovDigiHit*>(obj);
370  // First check tube id
371  if(tube_id != old_digit->GetTubeId()) continue;
372  // Then the time. Assume if we're within 0.5 ns it's the same hit
373  if(abs(time - old_digit->GetT()) > 0.5) continue;
374  found = true;
375  break;
376  }//idigit_old
377  if(found) {
378  new_digit->SetPhotonIds(old_digit->GetPhotonIds());
379  }
380  }//idigit
381  }//itrigger
382 }
384 void DataOut::FinaliseSubEvents(WCSimRootEvent * wcsim_event) {
385  const int n = m_all_triggers->m_num_triggers;
386  for(int i = 0; i < n; i++) {
387  WCSimRootTrigger * trig = wcsim_event->GetTrigger(i);
388  TClonesArray * hits = trig->GetCherenkovDigiHits();
389  double sumq = 0;
390  int nhits = 0;
391  for(int j = 0; j < trig->GetNcherenkovdigihits_slots(); j++) {
392  WCSimRootCherenkovDigiHit * digi = (WCSimRootCherenkovDigiHit *)hits->At(j);
393  if(digi) {
394  sumq += digi->GetQ();
395  nhits++;
396  }
397  }//j
398  trig->SetSumQ(sumq);
399  //this is actually number of hits, not number of unique PMTs with hits
400  trig->SetNumDigitizedTubes(nhits);
401  m_ss << "DEBUG: Trigger " << i << " has " << nhits << " hits";
403  }//i
404 }
408 
410  if(m_stopwatch) {
412  m_stopwatch->Start();
413  }
414 
415  //multiple TFiles may be open. Ensure we save to the correct one
416  m_output_file->cd(TString::Format("%s:/", m_output_filename.c_str()));
417  m_event_tree->Write();
418 
419  delete m_event_tree;
423 
424  delete m_all_triggers;
425 
426  m_output_file->Close();
427  delete m_output_file;
428 
429  if(m_stopwatch) {
430  Log(m_stopwatch->Result("Finalise"), INFO, m_verbose);
431  delete m_stopwatch;
432  }
433 
434  return true;
435 }
std::string Result(std::string method_name, std::string output_file="")
Definition: Stopwatch.cpp:38
bool Finalise()
Definition: DataOut.cpp:409
std::string m_stopwatch_file
Image filename to save the histogram to, if required.
Definition: DataOut.h:78
void Start()
Start the stopwatch.
Definition: Stopwatch.cpp:18
void CreateSubEvents(WCSimRootEvent *wcsim_event)
Definition: DataOut.cpp:185
std::stringstream m_ss
For easy formatting of Log messages.
Definition: DataOut.h:84
StopwatchTimes Stop()
Stop the stopwatch, returning the CPU time.
Definition: Stopwatch.cpp:24
void Clear()
Clear all triggers.
Definition: TriggerInfo.cpp:34
void FillHits(WCSimRootEvent *wcsim_event, std::vector< SubSample > &samples)
Definition: DataOut.cpp:231
std::vector< TimeDelta > m_readout_end_time
The ending time of the trigger window.
Definition: TriggerInfo.h:36
std::vector< std::vector< float > > m_info
Additional information, specific to the trigger.
Definition: TriggerInfo.h:44
WCSimRootEvent * m_od_wcsimevent_triggered
Output ROOT event structure for OD.
Definition: DataOut.h:60
int m_event_num
Current event number.
Definition: DataOut.h:68
TTree * m_event_tree
Tree contain WCSimRootEvent(s), and the original WCSim filename / event number.
Definition: DataOut.h:56
bool Execute()
Definition: DataOut.cpp:111
TimeDelta m_trigger_offset
A time used to offset all hit times. Set by config file.
Definition: DataOut.h:65
TFile * m_output_file
Output ROOT file.
Definition: DataOut.h:54
bool Initialise(std::string configfile, DataModel &data)
Definition: DataOut.cpp:6
TriggerInfo * m_all_triggers
Combined list of triggers from all sources (ID+OD)
Definition: DataOut.h:63
std::vector< TimeDelta > m_trigger_time
The actual time of the trigger.
Definition: TriggerInfo.h:42
void AddTriggers(TriggerInfo *in)
Add all triggers from another TriggerInfo object.
Definition: TriggerInfo.cpp:25
static std::string EnumAsString(Distribution_t dist)
bool m_save_multiple_hits_per_trigger
If false, only 1 hit is allowed to be saved per trigger, rather than all hits from that trigger...
Definition: DataOut.h:73
void FinaliseSubEvents(WCSimRootEvent *wcsim_event)
Definition: DataOut.cpp:384
static const TimeDelta ns
TimeDelta of 1 ns.
Definition: TimeDelta.h:57
void AddTruthInfo(WCSimRootEvent *wcsim_event, WCSimRootEvent *original_wcsim_event, const TimeDelta &time_shift)
Definition: DataOut.cpp:272
void ExecuteSubDet(WCSimRootEvent *wcsim_event, std::vector< SubSample > &samples, WCSimRootEvent *original_wcsim_event=0)
Runs other methods to take information from the DataModel and create/populate the WCSimRootEvent...
Definition: DataOut.cpp:155
std::vector< TimeDelta > m_readout_start_time
The starting time of the trigger window.
Definition: TriggerInfo.h:34
TimeDelta GetOffset(WCSimRootEvent *original_wcsim_event=0)
Definition: DataOut.cpp:205
int m_verbose
Verbosity level, as defined in tool parameter file.
Definition: DataOut.h:81
void Log(const std::string &message, const int message_level)
Format messages in the same way as for tools.
Definition: Utilities.cpp:276
WCSimRootEvent * m_id_wcsimevent_triggered
Output ROOT event structure for ID.
Definition: DataOut.h:58
DataOut()
Definition: DataOut.cpp:3
void StreamToLog(int level)
Definition: DataOut.h:88
util::Stopwatch * m_stopwatch
The stopwatch, if we&#39;re using one.
Definition: DataOut.h:76
bool m_save_only_failed_hits
If true, saves hits that failed the trigger, rather those that passed.
Definition: DataOut.h:71
std::string m_output_filename
Output ROOT filename that this tool RECREATE&#39;s.
Definition: DataOut.h:52
unsigned int m_num_triggers
The number of triggers.
Definition: TriggerInfo.h:30
std::vector< TriggerType_t > m_type
The type of Trigger.
Definition: TriggerInfo.h:32