All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SpectrumLoader.cxx
Go to the documentation of this file.
2 
8 
10 
11 #include "sbnanaobj/StandardRecord/Proxy/SRProxy.h"
12 
13 #include <cassert>
14 #include <iostream>
15 #include <cmath>
16 
17 #include "TFile.h"
18 #include "TH2.h"
19 #include "TTree.h"
20 
21 namespace ana
22 {
23  //----------------------------------------------------------------------
24  SpectrumLoader::SpectrumLoader(const std::string& wildcard, DataSource src, int max)
25  : SpectrumLoaderBase(wildcard, src), max_entries(max)
26  {
27  }
28 
29  //----------------------------------------------------------------------
30  SpectrumLoader::SpectrumLoader(const std::vector<std::string>& fnames,
31  DataSource src, int max)
32  : SpectrumLoaderBase(fnames, src), max_entries(max)
33  {
34  }
35 
36  //----------------------------------------------------------------------
38  : SpectrumLoaderBase(src)
39  {
40  }
41 
42  //----------------------------------------------------------------------
44  DataSource src,
45  int fileLimit)
46  {
47  SpectrumLoader ret;
48  ret.fSource = src;
49  ret.fWildcard = "project "+proj;
50  ret.fFileSource = std::unique_ptr<IFileSource>(new SAMProjectSource(proj, fileLimit));
51  return ret;
52  }
53 
54  //----------------------------------------------------------------------
56  {
57  }
58 
59  struct CompareByID
60  {
61  bool operator()(const Cut& a, const Cut& b) const
62  {
63  return a.ID() < b.ID();
64  }
65  };
66 
67  //----------------------------------------------------------------------
69  {
70  if(fGone){
71  std::cerr << "Error: can only call Go() once on a SpectrumLoader" << std::endl;
72  abort();
73  }
74  fGone = true;
75 
76  // Find all the unique cuts
77  // std::set<Cut, CompareByID> cuts;
78  // for(auto& shiftdef: fHistDefs)
79  // for(auto& cutdef: shiftdef.second)
80  // cuts.insert(cutdef.first);
81  // for(const Cut& cut: cuts) fAllCuts.push_back(cut);
82 
83  // fLivetimeByCut.resize(fAllCuts.size());
84  // fPOTByCut.resize(fAllCuts.size());
85 
86 
87  const int Nfiles = NFiles();
88 
89  Progress* prog = 0;
90 
91  caf::SRBranchRegistry::clear();
92 
93  int fileIdx = -1;
94  while(TFile* f = GetNextFile()){
95  ++fileIdx;
96 
97  if(Nfiles >= 0 && !prog) prog = new Progress(TString::Format("Filling %lu spectra from %d files matching '%s'", fHistDefs.TotalSize(), Nfiles, fWildcard.c_str()).Data());
98 
99  HandleFile(f, Nfiles == 1 ? prog : 0);
100 
101  if(Nfiles > 1 && prog) prog->SetProgress((fileIdx+1.)/Nfiles);
102  } // end for fileIdx
103 
104  if(prog){
105  prog->Done();
106  delete prog;
107  }
108 
109  StoreExposures(); // also triggers the POT printout
110 
111  fHistDefs.RemoveLoader(this);
112  fHistDefs.Clear();
113  }
114 
115  //----------------------------------------------------------------------
117  {
118  assert(!f->IsZombie());
119 
120  TTree* tr = (TTree*)f->Get("recTree");
121  assert(tr);
122 
123  // We try to access this field for every record. It was only added to the
124  // files in late 2021, and we don't want to render all earlier files
125  // unusable at a stroke. This logic can safely be removed once all extant
126  // files have such a field (estimate mid-2022?)
127  const bool has_husk = tr->GetLeaf("rec.hdr.husk");
128 
129  caf::SRSpillProxy sr(tr, "rec");
130 
131  // FloatingExceptionOnNaN fpnan;
132 
133  long Nentries = tr->GetEntries();
134  if (max_entries != 0 && max_entries < Nentries) Nentries = max_entries;
135 
136  for(long n = 0; n < Nentries; ++n){
137  tr->LoadTree(n);
138 
139  // If there is no husk field there is no concept of husk events
140  if(!has_husk) sr.hdr.husk = false;
141 
142  HandleRecord(&sr);
143 
144  if(prog) prog->SetProgress(double(n)/Nentries);
145  } // end for n
146  }
147 
148  //----------------------------------------------------------------------
149  /// Helper for \ref HandleRecord
150  template<class T, class U, class V> class CutVarCache
151  {
152  public:
153  CutVarCache() : fVals(U::MaxID()+1), fValsSet(U::MaxID()+1, false) {}
154 
155  inline T Get(const U& var, const V* sr)
156  {
157  const unsigned int id = var.ID();
158 
159  if(fValsSet[id]){
160  return fVals[id];
161  }
162  else{
163  const T val = var(sr);
164  fVals[id] = val;
165  fValsSet[id] = true;
166  return val;
167  }
168  }
169 
170  protected:
171  // Seems to be faster to do this than [unordered_]map
172  std::vector<T> fVals;
173  std::vector<bool> fValsSet;
174  };
175 
176  //----------------------------------------------------------------------
178  {
179  if(sr->hdr.first_in_subrun){
180  fPOT += sr->hdr.pot;
181  // TODO think about if this should be gated behind first_in_file. At the
182  // moment I think these will be synonymous. And despite the comment on
183  // hdr.pot, I think it may be file-based in practice too.
184  if(sr->hdr.ismc) fNReadouts += sr->hdr.ngenevt;
185  }
186 
187  if(!sr->hdr.ismc){
188  const int nbnb = sr->hdr.bnbinfo.size();
189  const int nnumi = sr->hdr.numiinfo.size();
190  if(nbnb > 0 && nnumi > 0){
191  std::cout << "SpectrumLoader: nonzero number of both BNB (" << nbnb
192  << ") and NuMI (" << nnumi << ") triggers. I'm confused"
193  << std::endl;
194  abort();
195  }
196 
197  fNReadouts += nbnb + nnumi;
198  }
199 
200  // This record was only kept as a receptacle for exposure information. It
201  // shouldn't be included in any selected spectra.
202  if(sr->hdr.husk) return;
203 
204  // Do the spill-level spectra first. Keep this very simple because we
205  // intend to change it.
206  for(auto& spillcutdef: fSpillHistDefs){
207  if(!spillcutdef.first(sr)) continue;
208  for(auto& spillweidef: spillcutdef.second){
209  const double wei = spillweidef.first(sr);
210  if(wei == 0) continue;
211  for(auto spillvardef: spillweidef.second){
212  if(spillvardef.first.IsMulti()){
213  for(double val: spillvardef.first.GetMultiVar()(sr)){
214  for(Spectrum* s: spillvardef.second.spects) s->Fill(val, wei);
215  }
216  }
217  else{
218  const double val = spillvardef.first.GetVar()(sr);
219  for(Spectrum* s: spillvardef.second.spects) s->Fill(val, wei);
220  }
221  }
222  }
223  }
224 
225 
226  for(auto& spillcutdef: fHistDefs){
227  const SpillCut& spillcut = spillcutdef.first;
228 
229  const bool spillpass = spillcut(sr); // nomSpillCutCache.Get(spillcut, sr);
230  // Cut failed, skip all the histograms that depended on it
231  if(!spillpass) continue;
232 
233  for(caf::SRSliceProxy& slc: sr->slc){
234 
235  // Some shifts only adjust the weight, so they're effectively nominal,
236  // but aren't grouped with the other nominal histograms. Keep track of
237  // the results for nominals in these caches to speed those systs up.
241 
242  for(auto& shiftdef: spillcutdef.second){
243  const SystShifts& shift = shiftdef.first;
244 
245  // Need to provide a clean slate for each new set of systematic
246  // shifts to work from. Copying the whole StandardRecord is pretty
247  // expensive, so modify it in place and revert it afterwards.
248 
249  caf::SRProxySystController::BeginTransaction();
250 
251  bool shifted = false;
252 
253  double systWeight = 1;
254  // Can special-case nominal to not pay cost of Shift()
255  if(!shift.IsNominal()){
256  shift.Shift(&slc, systWeight);
257  // If there were only weighting systs applied then the cached
258  // nominal values are still valid.
259  shifted = caf::SRProxySystController::AnyShifted();
260  }
261 
262  for(auto& cutdef: shiftdef.second){
263  const Cut& cut = cutdef.first;
264 
265  const bool pass = shifted ? cut(&slc) : nomCutCache.Get(cut, &slc);
266  // Cut failed, skip all the histograms that depended on it
267  if(!pass) continue;
268 
269  for(auto& weidef: cutdef.second){
270  const Var& weivar = weidef.first;
271 
272  double wei = shifted ? weivar(&slc) : nomWeiCache.Get(weivar, &slc);
273 
274  wei *= systWeight;
275  if(wei == 0) continue;
276 
277  for(auto& vardef: weidef.second){
278  if(vardef.first.IsMulti()){
279  for(double val: vardef.first.GetMultiVar()(&slc)){
280  for(Spectrum* s: vardef.second.spects)
281  s->Fill(val, wei);
282  }
283  continue;
284  }
285 
286  const Var& var = vardef.first.GetVar();
287 
288  const double val = shifted ? var(&slc) : nomVarCache.Get(var, &slc);
289 
290  if(std::isnan(val) || std::isinf(val)){
291  std::cerr << "Warning: Bad value: " << val
292  << " returned from a Var. The input variable(s) could "
293  << "be NaN in the CAF, or perhaps your "
294  << "Var code computed 0/0?";
295  std::cout << " Not filling into this histogram for this slice." << std::endl;
296  continue;
297  }
298 
299  for(Spectrum* s: vardef.second.spects) s->Fill(val, wei);
300 
301  for(ReweightableSpectrum* rw: vardef.second.rwSpects){
302  const double yval = rw->ReweightVar()(&slc);
303 
304  if(std::isnan(yval) || std::isinf(yval)){
305  std::cerr << "Warning: Bad value: " << yval
306  << " for reweighting Var";
307  std::cout << ". Not filling into histogram." << std::endl;
308  continue;
309  }
310 
311  rw->fHist->Fill(val, yval, wei);
312  } // end for rw
313  } // end for vardef
314  } // end for weidef
315  } // end for cutdef
316 
317  // Return StandardRecord to its unshifted form ready for the next
318  // histogram.
319  caf::SRProxySystController::Rollback();
320  } // end for shiftdef
321  } // end for slc
322  } // end for spillcutdef
323  }
324 
325  //----------------------------------------------------------------------
327  {
328  if(fabs(fPOT - fPOTFromHist)/std::min(fPOT, fPOTFromHist) > 0.001){
329  std::cout << fPOT << " POT from hdr differs from " << fPOTFromHist << " POT from the TotalPOT histogram!" << std::endl;
330  abort();
331  }
332 
333  std::cout << fPOT << " POT over " << fNReadouts << " readouts" << std::endl;
334 
335  for(auto& shiftdef: fHistDefs){
336  for(auto& spillcutdef: shiftdef.second){
337  for(auto& cutdef: spillcutdef.second){
338  for(auto& weidef: cutdef.second){
339  for(auto& vardef: weidef.second){
340  for(Spectrum* s: vardef.second.spects){
341  s->fPOT += fPOT;
342  s->fLivetime += fNReadouts;
343  }
344  for(ReweightableSpectrum* rw: vardef.second.rwSpects){
345  rw->fPOT += fPOT;
346  rw->fLivetime += fNReadouts;
347  }
348  }
349  }
350  }
351  }
352  }
353 
354 
355  for(auto& spillcutdef: fSpillHistDefs){
356  for(auto& spillweidef: spillcutdef.second){
357  for(auto spillvardef: spillweidef.second){
358  for(Spectrum* s: spillvardef.second.spects){
359  s->fPOT += fPOT;
360  s->fLivetime += fNReadouts;
361  }
362  }
363  }
364  }
365 
366  }
367 } // namespace
const Var & ReweightVar() const
The variable that will be used to fill the y-axis.
virtual void StoreExposures()
Save accumulated exposures into the individual spectra.
int max_entries
All unique cuts contained in fHistDefs.
BEGIN_PROLOG could also be cerr
bool IsNominal() const
Definition: SystShifts.h:26
bool fGone
Has Go() been called? Can&#39;t add more histograms after that.
Simple record of shifts applied to systematic parameters.
Definition: SystShifts.h:16
Spectrum with the value of a second variable, allowing for reweighting
SpectrumLoader(const std::string &wildcard, DataSource src=kBeam, int max=0)
Helper for HandleRecord.
double fPOT
Definition: Spectrum.h:342
void Fill(double x, double w=1)
process_name opflashCryoW ana
shift
Definition: fcl_checks.sh:26
caf::Proxy< caf::SRSlice > SRSliceProxy
Definition: EpilogFwd.h:2
Representation of a spectrum in any variable, with associated POT.
Definition: Spectrum.h:30
void Shift(caf::SRSliceProxy *slc, double &weight) const
Definition: SystShifts.cxx:86
process_name gaushit a
BEGIN_PROLOG V
double fPOTFromHist
Accumulated by calls to GetNextFile.
IDMap< SpillCut, IDMap< SpillVar, IDMap< SpillVarOrMultiVar, SpectList > > > fSpillHistDefs
[spillcut][spillwei][spillvar]
IDMap< SpillCut, IDMap< SystShifts, IDMap< Cut, IDMap< Var, IDMap< VarOrMultiVar, SpectList > > > > > fHistDefs
All the spectra that need to be filled.
DataSource
Is this data-file representing beam spills or cosmic spills?
caf::Proxy< caf::StandardRecord > SRSpillProxy
Definition: EpilogFwd.h:3
bool operator()(const Cut &a, const Cut &b) const
virtual void HandleRecord(caf::SRSpillProxy *sr)
int ID() const
Cuts with the same definition will have the same ID.
Definition: Cut.h:57
double fLivetime
Definition: Spectrum.h:343
virtual void Go() override
Load all the registered spectra.
static SpectrumLoader FromSAMProject(const std::string &proj, DataSource src=kBeam, int fileLimit=-1)
Named constructor for SAM projects.
T Get(const U &var, const V *sr)
Base class for the various types of spectrum loader.
std::unique_ptr< IFileSource > fFileSource
void SetProgress(double frac)
Update the progress fraction between zero and one.
Definition: Progress.cxx:44
Collaborates with Spectrum and OscillatableSpectrum to fill spectra from CAF files.
then echo File list $list not found else cat $list while read file do echo $file sed s
Definition: file_to_url.sh:60
std::vector< T > fVals
A simple ascii-art progress bar.
Definition: Progress.h:9
Fetch files from a pre-existing SAM project.
virtual void HandleFile(TFile *f, Progress *prog=0)
int NFiles() const
Forwards to fFileSource.
std::vector< bool > fValsSet
prog
Definition: just_cmake.sh:3
void Done()
Call this when action is completed.
Definition: Progress.cxx:91
BEGIN_PROLOG could also be cout