All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OscillatableSpectrum.cxx
Go to the documentation of this file.
2 
8 
10 
11 #include "sbnanaobj/StandardRecord/Proxy/SRProxy.h"
12 
13 #include "OscLib/IOscCalc.h"
14 
15 #include "TDirectory.h"
16 #include "TH2.h"
17 #include "TMD5.h"
18 #include "TObjString.h"
19 
20 #include <cassert>
21 #include <memory>
22 
23 namespace ana
24 {
25  // Duplicate here because we can't include Vars.h
26  const Var kTrueE([](const caf::SRSliceProxy* slc) -> double {return slc->truth.E;});
27 
28  const Var kBaseline([](const caf::SRSliceProxy* slc) -> double {return slc->truth.baseline * 1e-3;}); // m -> km
29 
31 
32  //----------------------------------------------------------------------
34  OscillatableSpectrum(const std::string& label, const Binning& bins,
36  const Var& var,
37  const Cut& cut,
38  const SystShifts& shift,
39  const Var& wei)
40  : ReweightableSpectrum(label, bins, kTrueLOverE),
41  fCachedOsc(0, {}, {}, 0, 0),
43  {
44  fTrueLabel = "True baseline / True energy (km / GeV)";
45 
46  DontAddDirectory guard;
47 
48  fHist = HistCache::NewTH2D("", bins, kTrueLOverEBins);
49 
50  loader.AddReweightableSpectrum(*this, var, cut, shift, wei);
51  }
52 
53  //----------------------------------------------------------------------
55  const HistAxis& axis,
56  const Cut& cut,
57  const SystShifts& shift,
58  const Var& wei)
59  : OscillatableSpectrum(loader, axis, kNoSpillCut, cut, shift, wei)
60  {
61  }
62 
63  //----------------------------------------------------------------------
65  const HistAxis& axis,
66  const SpillCut& spillcut,
67  const SliceCut& slicecut,
68  const SystShifts& shift,
69  const Var& wei)
70  : ReweightableSpectrum(axis.GetLabels(), axis.GetBinnings(), kTrueLOverE),
71  fCachedOsc(0, {}, {}, 0, 0),
72  fCachedHash(0)
73  {
74  fTrueLabel = "True baseline / True energy (km / GeV)";
75 
76  Binning bins1D = fBins[0];
77  if(fBins.size() > 1){
78  int n = 1;
79  for(const Binning& b: fBins) n *= b.NBins();
80  bins1D = Binning::Simple(n, 0, n);
81  }
82 
83  std::string label;
84  for(const std::string& l: fLabels) label += l + " and ";
85  label.resize(label.size()-5); // drop the last "and"
86 
87  DontAddDirectory guard;
88 
90 
91  Var multiDVar = axis.GetVars()[0];
92  if(axis.NDimensions() == 2)
93  multiDVar = Var2D(axis.GetVars()[0], axis.GetBinnings()[0],
94  axis.GetVars()[1], axis.GetBinnings()[1]);
95  if(axis.NDimensions() == 3)
96  multiDVar = Var3D(axis.GetVars()[0], axis.GetBinnings()[0],
97  axis.GetVars()[1], axis.GetBinnings()[1],
98  axis.GetVars()[2], axis.GetBinnings()[2]);
99 
100  loader.AddReweightableSpectrum(*this, multiDVar, spillcut, slicecut, shift, wei);
101  }
102 
103  //----------------------------------------------------------------------
105  const Binning& bins)
106  : ReweightableSpectrum(label, bins, kTrueLOverE),
107  fCachedOsc(0, {}, {}, 0, 0),
108  fCachedHash(0)
109  {
110  fTrueLabel = "True baseline / True energy (km / GeV)";
111 
112  DontAddDirectory guard;
113 
114  fPOT = 0;
115  fLivetime = 0;
116 
118  }
119 
120  //----------------------------------------------------------------------
121  OscillatableSpectrum::OscillatableSpectrum(const std::string& label, double pot, double livetime,
122  const Binning& bins)
123  : ReweightableSpectrum(label, bins, kTrueLOverE),
124  fCachedOsc(0, {}, {}, 0, 0),
125  fCachedHash(0)
126  {
127  fTrueLabel = "True baseline / True energy (km / GeV)";
128 
129  DontAddDirectory guard;
130 
131  fPOT = pot;
132  fLivetime = livetime;
133 
135  }
136 
137  //----------------------------------------------------------------------
139  const std::vector<std::string>& labels,
140  const std::vector<Binning>& bins,
141  double pot, double livetime)
142  : ReweightableSpectrum(kTrueLOverE, h, labels, bins, pot, livetime),
143  fCachedOsc(0, {}, {}, 0, 0),
144  fCachedHash(0)
145  {
146  fTrueLabel = "True baseline / True energy (km / GeV)";
147  }
148 
149  //----------------------------------------------------------------------
151  const std::vector<std::string>& labels,
152  const std::vector<Binning>& bins,
153  double pot, double livetime)
154  : ReweightableSpectrum(kTrueLOverE, std::move(h), labels, bins, pot, livetime),
155  fCachedOsc(0, {}, {}, 0, 0),
156  fCachedHash(0)
157  {
158  fTrueLabel = "True baseline / True energy (km / GeV)";
159  }
160 
161  //----------------------------------------------------------------------
163  {
164  // Nulls fHist out, so it's safe that ~ReweightableSpectrum tries too
166 
168  { loader->RemoveReweightableSpectrum(this); }
169 
170  delete fCachedHash;
171  }
172 
173  //----------------------------------------------------------------------
175  : ReweightableSpectrum(rhs.fLabels, rhs.fBins, kTrueLOverE),
176  fCachedOsc(0, {}, {}, 0, 0),
177  fCachedHash(0)
178  {
179  DontAddDirectory guard;
180 
181  fHist = HistCache::Copy(rhs.fHist);
182 
183  fPOT = rhs.fPOT;
184  fLivetime = rhs.fLivetime;
185 
186  if(rhs.fCachedHash){
187  fCachedOsc = rhs.fCachedOsc;
188  fCachedHash = new TMD5(*rhs.fCachedHash);
189  }
190 
191  assert( rhs.fLoaderCount.empty() ); // Copying with pending loads is unexpected
192  }
193 
194  //----------------------------------------------------------------------
196  : ReweightableSpectrum(rhs.fLabels, rhs.fBins, kTrueLOverE),
197  fCachedOsc(0, {}, {}, 0, 0),
198  fCachedHash(0)
199  {
200  DontAddDirectory guard;
201 
202  fHist = rhs.fHist;
203  rhs.fHist = 0;
204 
205  fPOT = rhs.fPOT;
206  fLivetime = rhs.fLivetime;
207 
208  if(rhs.fCachedHash){
209  fCachedOsc = std::move(rhs.fCachedOsc);
210  fCachedHash = rhs.fCachedHash;
211  rhs.fCachedHash = 0;
212  }
213 
214  assert( rhs.fLoaderCount.empty() ); // Copying with pending loads is unexpected
215  }
216 
217  //----------------------------------------------------------------------
219  {
220  if(this == &rhs) return *this;
221 
222  DontAddDirectory guard;
223 
225  fHist = HistCache::Copy(rhs.fHist);
226  fPOT = rhs.fPOT;
227  fLivetime = rhs.fLivetime;
228  fLabels = rhs.fLabels;
229  fBins = rhs.fBins;
230 
231  if(rhs.fCachedHash){
232  fCachedOsc = rhs.fCachedOsc;
233  delete fCachedHash;
234  fCachedHash = new TMD5(*rhs.fCachedHash);
235  }
236 
237  assert( rhs.fLoaderCount.empty() ); // Copying with pending loads is unexpected
238  assert( fLoaderCount.empty() ); // Copying with pending loads is unexpected
239 
240  return *this;
241  }
242 
243  //----------------------------------------------------------------------
245  {
246  if(this == &rhs) return *this;
247 
248  DontAddDirectory guard;
249 
251  fHist = rhs.fHist;
252  rhs.fHist = 0;
253  fPOT = rhs.fPOT;
254  fLivetime = rhs.fLivetime;
255  fLabels = rhs.fLabels;
256  fBins = rhs.fBins;
257 
258  if(rhs.fCachedHash){
259  fCachedOsc = rhs.fCachedOsc;
260  delete fCachedHash;
261  fCachedHash = rhs.fCachedHash;
262  rhs.fCachedHash = 0;
263  }
264 
265  assert( rhs.fLoaderCount.empty() ); // Copying with pending loads is unexpected
266  assert( fLoaderCount.empty() ); // Copying with pending loads is unexpected
267 
268  return *this;
269  }
270 
271  //----------------------------------------------------------------------
273  int from, int to) const
274  {
275  // TODO remove this check in a little while, once no one is using old state
276  // files anymore (comment from Feb 2020).
277  const bool isLoverE = (fHist->GetYaxis()->GetXmax() == 2);
278  static bool once = true;
279  if(once && !isLoverE){
280  once = false;
281  std::cout << "\nWarning: OscillatableSpectrum with legacy non-L/E y-axis detected. Will oscillate correctly for now, but this code will eventually be removed\n" << std::endl;
282  }
283 
284  // POT = 0 implies empty spectrum and oscillated result will also always be
285  // empty
286  if(fCachedHash && fPOT == 0) return fCachedOsc;
287 
288  TMD5* hash = calc->GetParamsHash();
289  if(hash && fCachedHash && *hash == *fCachedHash){
290  delete hash;
291  return fCachedOsc;
292  }
293 
294  const OscCurve curve(calc, from, to, isLoverE);
295  TH1D* Ps = curve.ToTH1();
296 
297  const Spectrum ret = WeightedBy(Ps);
298  if(hash){
299  fCachedOsc = ret;
300  delete fCachedHash;
301  fCachedHash = hash;
302  }
303  HistCache::Delete(Ps);
304  return ret;
305  }
306 
307  //----------------------------------------------------------------------
309  {
310  // If someone actually needs this we can go in and fix the behaviour
311  assert(fPOT);
312 
313  if(rhs.fPOT){
314  fHist->Add(rhs.fHist, fPOT/rhs.fPOT);
315  }
316  else{
317  // How can it have events but no POT?
318  assert(rhs.fHist->Integral() == 0);
319  }
320 
321  delete fCachedHash;
322  fCachedHash = 0; // Invalidate
323 
324  return *this;
325  }
326 
327  //----------------------------------------------------------------------
329  {
330  OscillatableSpectrum ret = *this;
331  ret += rhs;
332  return ret;
333  }
334 
335  //----------------------------------------------------------------------
337  {
338  if(rhs.fPOT){
339  fHist->Add(rhs.fHist, -fPOT/rhs.fPOT);
340  }
341  else{
342  // How can it have events but no POT?
343  assert(rhs.fHist->Integral() == 0);
344  }
345 
346  delete fCachedHash;
347  fCachedHash = 0; // Invalidate
348 
349  return *this;
350  }
351 
352  //----------------------------------------------------------------------
354  {
355  OscillatableSpectrum ret = *this;
356  ret -= rhs;
357  return ret;
358  }
359 
360  //----------------------------------------------------------------------
361  void OscillatableSpectrum::SaveTo(TDirectory* dir) const
362  {
363  TDirectory* tmp = gDirectory;
364  dir->cd();
365 
366  TObjString("OscillatableSpectrum").Write("type");
367 
368  fHist->Write("hist");
369  TH1D hPot("", "", 1, 0, 1);
370  hPot.Fill(.5, fPOT);
371  hPot.Write("pot");
372  TH1D hLivetime("", "", 1, 0, 1);
373  hLivetime.Fill(.5, fLivetime);
374  hLivetime.Write("livetime");
375 
376  for(unsigned int i = 0; i < fBins.size(); ++i){
377  TObjString(fLabels[i].c_str()).Write(TString::Format("label%d", i).Data());
378  fBins[i].SaveTo(dir->mkdir(TString::Format("bins%d", i)));
379  }
380 
381  tmp->cd();
382  }
383 
384  //----------------------------------------------------------------------
385  std::unique_ptr<OscillatableSpectrum> OscillatableSpectrum::LoadFrom(TDirectory* dir)
386  {
387  DontAddDirectory guard;
388 
389  TObjString* tag = (TObjString*)dir->Get("type");
390  assert(tag);
391  assert(tag->GetString() == "OscillatableSpectrum");
392  delete tag;
393 
394  TH2D* spect = (TH2D*)dir->Get("hist");
395  assert(spect);
396  TH1* hPot = (TH1*)dir->Get("pot");
397  assert(hPot);
398  TH1* hLivetime = (TH1*)dir->Get("livetime");
399  assert(hLivetime);
400 
401  std::vector<std::string> labels;
402  std::vector<Binning> bins;
403 
404  for(int i = 0; ; ++i){
405  TDirectory* subdir = dir->GetDirectory(TString::Format("bins%d", i));
406  if(!subdir) break;
407  bins.push_back(*Binning::LoadFrom(subdir));
408  TObjString* label = (TObjString*)dir->Get(TString::Format("label%d", i));
409  labels.push_back(label ? label->GetString().Data() : "");
410  delete subdir;
411  delete label;
412  }
413 
414  if(bins.empty() && labels.empty()){
415  // Must be an old file. Make an attempt at backwards compatibility.
416  bins.push_back(Binning::FromTAxis(spect->GetXaxis()));
417  labels.push_back(spect->GetXaxis()->GetTitle());
418  }
419 
420  auto ret = std::make_unique<OscillatableSpectrum>(std::unique_ptr<TH2D>(spect),
421  labels, bins,
422  hPot->GetBinContent(1),
423  hLivetime->GetBinContent(1));
424 
425  delete hPot;
426  delete hLivetime;
427  return ret;
428  }
429 }
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
* labels
Represent the binning of a Spectrum&#39;s x-axis.
Definition: Binning.h:18
static TH1D * Copy(const TH1D *h)
Definition: HistCache.cxx:76
tuple loader
Definition: demo.py:7
Simple record of shifts applied to systematic parameters.
Definition: SystShifts.h:16
static Binning FromTAxis(const TAxis *ax)
Definition: Binning.cxx:122
_Var< T > Var2D(const _Var< T > &a, const Binning &binsa, const _Var< T > &b, const Binning &binsb)
Variable formed from two input variables.
Definition: Var.cxx:109
static std::unique_ptr< OscillatableSpectrum > LoadFrom(TDirectory *dir)
Spectrum with the value of a second variable, allowing for reweighting
const Binning kTrueLOverEBins
Definition: Binning.h:74
process_name opflashCryoW ana
OscillatableSpectrum & operator-=(const OscillatableSpectrum &rhs)
shift
Definition: fcl_checks.sh:26
caf::Proxy< caf::SRSlice > SRSliceProxy
Definition: EpilogFwd.h:2
_Var< caf::SRSliceProxy > Var
Representation of a variable to be retrieved from a caf::StandardRecord object.
Definition: Var.h:73
_Var< T > Var3D(const _Var< T > &a, const Binning &binsa, const _Var< T > &b, const Binning &binsb, const _Var< T > &c, const Binning &binsc)
This is just like a Var2D, but useful for 3D Spectra.
Definition: Var.cxx:133
Representation of a spectrum in any variable, with associated POT.
Definition: Spectrum.h:30
OscillatableSpectrum(const std::string &label, const Binning &bins, SpectrumLoaderBase &loader, const Var &var, const Cut &cut, const SystShifts &shift=kNoShift, const Var &wei=kUnweighted)
while getopts h
static TH2D * NewTH2D(const std::string &title, const Binning &xbins, const Binning &ybins)
Definition: HistCache.cxx:50
static void Delete(TH1D *&h)
Definition: HistCache.cxx:92
TH1D * ToTH1(bool title=false) const
Definition: OscCurve.cxx:129
std::set< SpectrumLoaderBase * > fLoaderCount
This count is maintained by SpectrumLoader, as a sanity check.
const SpillCut kNoSpillCut([](const caf::SRSpillProxy *){return true;})
The simplest possible cut: pass everything, used as a default.
std::vector< std::string > fLabels
const double kBaseline
Definition: CalcsNuFit.h:41
OscillatableSpectrum & operator+=(const OscillatableSpectrum &rhs)
OscillatableSpectrum operator+(const OscillatableSpectrum &rhs) const
tuple dir
Definition: dropbox.py:28
Base class for the various types of spectrum loader.
Transition probability for any one channel as a function of energy.
Definition: OscCurve.h:18
Spectrum Oscillated(osc::IOscCalc *calc, int from, int to) const
Spectrum WeightedBy(const TH1 *weights) const
do i e
std::vector< Binning > fBins
OscillatableSpectrum & operator=(const OscillatableSpectrum &rhs)
Assignment operator.
Prevent histograms being added to the current directory.
Spectrum with true energy information, allowing it to be oscillated
OscillatableSpectrum operator-(const OscillatableSpectrum &rhs) const
static Binning Simple(int n, double lo, double hi, const std::vector< std::string > &labels={})
Definition: Binning.cxx:38
static std::unique_ptr< Binning > LoadFrom(TDirectory *dir)
Definition: Binning.cxx:229
const Var kTrueLOverE
BEGIN_PROLOG could also be cout
const Var kTrueE([](const caf::SRSliceProxy *slc) -> double{return slc->truth.E;})
void SaveTo(TDirectory *dir) const