All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sbnana/sbnana/CAFAna/Core/Utilities.cxx
Go to the documentation of this file.
2 
6 
7 #include "TArrayD.h"
8 #include "TClass.h"
9 #include "TDirectory.h"
10 #include "TH2.h"
11 #include "TH3.h"
12 #include "TF1.h"
13 #include "TMatrixD.h"
14 #include "TObjString.h"
15 #include "TString.h"
16 #include "TTree.h"
17 #include "TVector3.h"
18 #include "TVectorD.h"
19 
20 #include <vector>
21 #include <cassert>
22 #include <cmath>
23 #include <fstream>
24 #include "sys/stat.h"
25 #include "wordexp.h"
26 
27 namespace ana
28 {
29  double LLPerBinFracSystErr::fgErr = -1;
30 
31  //----------------------------------------------------------------------
32  std::string UniqueName()
33  {
34  static int N = 0;
35  return TString::Format("cafanauniq%d", N++).Data();
36  }
37 
38  //----------------------------------------------------------------------
40  {
41  fBackup = TH1::AddDirectoryStatus();
42  TH1::AddDirectory(false);
43  }
44 
45  //----------------------------------------------------------------------
47  {
48  TH1::AddDirectory(fBackup);
49  }
50 
51  //----------------------------------------------------------------------
53  {
54  const char* s = getenv("IFDH_SILENT");
55  fSet = (s && s == std::string("0"));
56  if(!fSet) setenv("IFDH_SILENT", "1", 1);
57  if(s) std::cout << "IFDH_SILENT=" << s << std::endl;
58  }
59 
60  //----------------------------------------------------------------------
62  {
63  if(!fSet) unsetenv("IFDH_SILENT");
64  }
65 
66  //----------------------------------------------------------------------
68  {
69  // Don't want any pending FPEs to trigger when we flip exceptions
70  // on. Whoever had them off previously had a reason.
71  feclearexcept(FE_INVALID);
72 
73  fegetexceptflag(&fBackup, FE_INVALID);
74 
75 #ifndef DARWINBUILD
76  if(enable)
77  feenableexcept(FE_INVALID);
78  else
79  fedisableexcept(FE_INVALID);
80 #else
81  std::cerr << "WARNING: CAFAna/Core/Utilities.cxx built on OS X, no feenableexcept available" << std::endl;
82 #endif
83  }
84 
85  //----------------------------------------------------------------------
87  {
88  fesetexceptflag(&fBackup, FE_INVALID);
89  }
90 
91  //----------------------------------------------------------------------
92  std::string Experiment()
93  {
94  const char* ret = getenv("EXPERIMENT");
95 
96  if(!ret){
97  std::cout << "\nERROR: Environment variable $EXPERIMENT not set." << std::endl;
98  exit(1);
99  }
100 
101  return ret;
102  }
103 
104  //----------------------------------------------------------------------
105  std::string SAMExperiment()
106  {
107  const char* ret = getenv("SAM_EXPERIMENT");
108 
109  if(!ret){
110  std::cout << "\nERROR: Environment variable $SAM_EXPERIMENT not set.\nThis is required for various ifdh/sam functionality.\nYou likely want it to be set to 'sbn', though it should have been set automatically by setup scripts." << std::endl;
111  exit(1);
112  }
113 
114  return ret;
115  }
116 
117  //----------------------------------------------------------------------
118  std::unique_ptr<TMatrixD> CalcCovMx(const std::vector<TArrayD*> & binSets, int firstBin, int lastBin)
119  {
120  if (binSets.size() < 2)
121  return std::unique_ptr<TMatrixD>(nullptr);
122 
123  if (lastBin < 0)
124  lastBin = binSets[0]->GetSize() - 1; // indexed from 0
125 
126  int nBins = lastBin - firstBin + 1; // firstBin and lastBin are inclusive
127 
128  std::vector<double> binMeans(nBins);
129  for( const auto & binSet : binSets )
130  {
131  for ( decltype(lastBin) binIdx = firstBin; binIdx <= lastBin; binIdx++ )
132  binMeans[binIdx] += (*binSet)[binIdx];
133  }
134  for (decltype(lastBin) binIdx = firstBin; binIdx <= lastBin; binIdx++)
135  binMeans[binIdx] /= binSets.size();
136 
137 
138  auto covmx = std::make_unique<TMatrixD>(nBins, nBins);
139 
140  for( unsigned int hist_idx = 0; hist_idx < binSets.size(); ++hist_idx )
141  {
142  // first calculate the weighted sum of squares of the deviations
143  for( decltype(nBins) i = 0; i < nBins; i++ )
144  {
145  double xi = (*(binSets[hist_idx]))[i];
146  for( decltype(nBins) k = i; k < nBins; k++ )
147  {
148  double xk = (*(binSets[hist_idx]))[k];
149  (*covmx)[i][k] += (xi - binMeans[i]) * (xk - binMeans[k]);
150  if (i != k)
151  (*covmx)[k][i] = (*covmx)[i][k]; // covariance matrices are always symmetric
152  }
153  }
154  } // for (hist_idx)
155 
156  // now divide by N-1 to get sample covariance
157  (*covmx) *= 1./(binSets.size()-1);
158 
159  return covmx;
160  }
161 
162  //----------------------------------------------------------------------
163  double LogLikelihood(double e, double o)
164  {
165  // http://www.wolframalpha.com/input/?i=d%2Fds+m*(1%2Bs)+-d+%2B+d*ln(d%2F(m*(1%2Bs)))%2Bs%5E2%2FS%5E2%3D0
166  // http://www.wolframalpha.com/input/?i=solve+-d%2F(s%2B1)%2Bm%2B2*s%2FS%5E2%3D0+for+s
167  const double S = LLPerBinFracSystErr::GetError();
168  if(S > 0){
169  const double S2 = util::sqr(S);
170  const double s = .25*(sqrt(8*o*S2+util::sqr(e*S2-2))-e*S2-2);
171  e *= 1+s;
172  }
173 
174  // With this value, negative expected events and one observed
175  // event gives a chisq from this one bin of 182.
176  const double minexp = 1e-40; // Don't let expectation go lower than this
177 
178  assert(o >= 0);
179  if(e < minexp){
180  if(!o) return 0;
181  e = minexp;
182  }
183 
184  if(o*1000 > e){
185  // This strange form is for numerical stability when e~o
186  return 2*o*((e-o)/o + log1p((o-e)/e));
187  }
188  else{
189  // But log1p doesn't like arguments near -1 (observation much smaller
190  // than expectation), and it's better to use the usual formula in that
191  // case.
192  if(o){
193  return 2*(e-o + o*log(o/e));
194  }
195  else{
196  return 2*e;
197  }
198  }
199  }
200 
201  //----------------------------------------------------------------------
202  double LogLikelihood(const TH1* eh, const TH1* oh, bool useOverflow)
203  {
204  assert(eh->GetNbinsX() == oh->GetNbinsX());
205 
206  double chi = 0;
207 
208  int bufferBins = useOverflow? 2 : 1;
209 
210  for(int i = 0; i < eh->GetNbinsX()+bufferBins; ++i){
211  const double e = eh->GetBinContent(i);
212  const double o = oh->GetBinContent(i);
213 
214  chi += LogLikelihood(e, o);
215  }
216 
217  return chi;
218  }
219 
220  //----------------------------------------------------------------------
221  double Chi2CovMx(const TVectorD* e, const TVectorD* o, const TMatrixD* covmxinv)
222  {
223  assert (e->GetNrows() == o->GetNrows());
224 
225  TVectorD diff = *o - *e;
226  return diff * ((*covmxinv) * diff); // operator* for two TVectorDs is the "dot product" (i.e., v1 * v2 = v1^{trans}v1)
227  }
228 
229  //----------------------------------------------------------------------
230  double Chi2CovMx(const TH1* e, const TH1* o, const TMatrixD* covmxinv)
231  {
232  TVectorD eVec(e->GetNbinsX());
233  TVectorD oVec(o->GetNbinsX());
234  for (int bin = 1; bin <= e->GetNbinsX(); bin++)
235  eVec[bin-1] = e->GetBinContent(bin);
236  for (int bin = 1; bin <= o->GetNbinsX(); bin++)
237  oVec[bin-1] = o->GetBinContent(bin);
238 
239  return Chi2CovMx(&eVec, &oVec, covmxinv);
240  }
241 
242  //----------------------------------------------------------------------
243  TH2F* ExpandedHistogram(const std::string& title,
244  int nbinsx, double xmin, double xmax, bool xlog,
245  int nbinsy, double ymin, double ymax, bool ylog)
246  {
247  DontAddDirectory guard;
248 
249  if(xlog){xmin = log(xmin); xmax = log(xmax);}
250  if(ylog){ymin = log(ymin); ymax = log(ymax);}
251 
252  // How wide the bins will be once we're done
253  const double xwidth = (xmax-xmin)/(nbinsx-1);
254  const double ywidth = (ymax-ymin)/(nbinsy-1);
255 
256  // Move the bin edges so that the limits occur at the centres
257  xmin -= xwidth/2; ymin -= ywidth/2;
258  xmax += xwidth/2; ymax += ywidth/2;
259 
260  std::vector<double> xedges(nbinsx+1);
261  std::vector<double> yedges(nbinsy+1);
262 
263  for(int i = 0; i <= nbinsx; ++i){
264  xedges[i] = xmin + (xmax-xmin)*i/double(nbinsx);
265  if(xlog) xedges[i] = exp(xedges[i]);
266  }
267  for(int i = 0; i <= nbinsy; ++i){
268  yedges[i] = ymin + (ymax-ymin)*i/double(nbinsy);
269  if(ylog) yedges[i] = exp(yedges[i]);
270  }
271 
272  return new TH2F(UniqueName().c_str(), title.c_str(),
273  nbinsx, &xedges.front(),
274  nbinsy, &yedges.front());
275  }
276 
277 
278  //----------------------------------------------------------------------
279  std::unique_ptr<TMatrixD> SymmMxInverse(const TMatrixD& mx)
280  {
281  // check if there are any null rows/columns.
282  // if there are, they make the matrix singular.
283  // we will remove them temporarily,
284  // invert the matrix, then put them back afterwards.
285  std::set<int> nullRows;
286  for (auto row = mx.GetRowLwb(); row <= mx.GetRowUpb(); row++)
287  {
288  bool rowIsNull = true;
289  for (auto col = mx.GetColLwb(); col <= mx.GetColUpb(); col++)
290  {
291  if (mx[row][col] != 0.)
292  {
293  rowIsNull = false;
294  break;
295  }
296  }
297 
298  if (rowIsNull)
299  nullRows.insert(row);
300  }
301 
302  std::cerr << " Notice: covariance matrix '" << mx.GetName() << "' has " << nullRows.size() << " null rows.\n"
303  << "They will be removed before inverting and added back afterwards." << std::endl;
304 
305  // create a new matrix for inverting, skipping the null rows
306  auto invMx = std::make_unique<TMatrixD>(mx.GetRowLwb(), mx.GetRowUpb() - nullRows.size(),
307  mx.GetColLwb(), mx.GetColUpb() - nullRows.size());
308  unsigned int skippedRows = 0;
309  for (auto row = mx.GetRowLwb(); row <= mx.GetRowUpb(); row++)
310  {
311  if (nullRows.find(row) != nullRows.end())
312  {
313  skippedRows++;
314  continue;
315  }
316  unsigned int skippedCols = 0;
317  for (auto col = mx.GetColLwb(); col <= mx.GetColUpb(); col++)
318  {
319  // since we assumed the matrix is symmetric,
320  // we can just use the null rows list here
321  if (nullRows.find(col) != nullRows.end())
322  {
323  skippedCols++;
324  continue;
325  }
326 
327  (*invMx)[col-skippedCols][row-skippedRows] = (*invMx)[row-skippedRows][col-skippedCols] = mx[row][col];
328  }
329  }
330 
331  invMx->Invert();
332 
333  // put back the empty rows if there were any
334  if (nullRows.size())
335  {
336  skippedRows = 0;
337  auto retMx = std::make_unique<TMatrixD>(mx.GetRowLwb(), mx.GetRowUpb(),
338  mx.GetColLwb(), mx.GetColUpb());
339  for (auto row = mx.GetRowLwb(); row <= mx.GetRowUpb(); row++)
340  {
341  if (nullRows.find(row) != nullRows.end())
342  {
343  skippedRows++;
344  continue;
345  }
346 
347  unsigned int skippedCols = skippedRows;
348  for (auto col = row; col <= mx.GetColUpb(); col++)
349  {
350  if (nullRows.find(col) != nullRows.end())
351  {
352  skippedCols++;
353  continue;
354  }
355 
356  (*retMx)[col][row] = (*retMx)[row][col] = (*invMx)[row-skippedRows][col-skippedCols];
357  }
358  }
359 
360  return retMx;
361  }
362 
363  return invMx;
364  }
365 
366  // Helper functions for MakeTHND().
367  namespace{
368  // Eventually the bin parameters will all be unpacked and we just pass them
369  // on to the regular constructor.
370  template<class T, class... A> T* MakeHist(A... a)
371  {
372  DontAddDirectory guard;
373  return new T(a...);
374  }
375 
376  // This function consumes bins from the start of the argument list and
377  // pushes their translations onto the list of arguments at the end.
378  template<class T, class... A> T* MakeHist(const Binning& firstBin,
379  A... args)
380  {
381  if(firstBin.IsSimple())
382  return MakeHist<T>(args...,
383  firstBin.NBins(), firstBin.Min(), firstBin.Max());
384  else
385  return MakeHist<T>(args...,
386  firstBin.NBins(), &firstBin.Edges().front());
387  }
388  }
389 
390  // Concrete instantiations. MakeHist() requires us to put the bin arguments
391  // first...
392  //----------------------------------------------------------------------
393  TH1D* MakeTH1D(const char* name, const char* title, const Binning& bins)
394  {
395  return MakeHist<TH1D>(bins, name, title);
396  }
397 
398  //----------------------------------------------------------------------
399  TH2D* MakeTH2D(const char* name, const char* title,
400  const Binning& binsx,
401  const Binning& binsy)
402  {
403  return MakeHist<TH2D>(binsx, binsy, name, title);
404  }
405 
406  //----------------------------------------------------------------------
407  TH2* ToTH2(const Spectrum& s, double exposure, ana::EExposureType expotype,
408  const Binning& binsx, const Binning& binsy, ana::EBinType bintype)
409  {
410  DontAddDirectory guard;
411 
412  std::unique_ptr<TH1> h1(s.ToTH1(exposure, expotype));
413  return ToTH2Helper(std::move(h1), binsx, binsy, bintype);
414  }
415 
416  //----------------------------------------------------------------------
417  TH2* ToTH2(const Ratio& r,
418  const Binning& binsx, const Binning& binsy)
419  {
420  DontAddDirectory guard;
421 
422  std::unique_ptr<TH1> h1(r.ToTH1());
423  return ToTH2Helper(std::move(h1), binsx, binsy);
424  }
425 
426  //----------------------------------------------------------------------
427  TH2* ToTH2Helper(std::unique_ptr<TH1> h1,
428  const Binning& binsx, const Binning& binsy,
429  ana::EBinType bintype)
430  {
431  // Make sure it's compatible with having been made with this binning
432  assert(h1->GetNbinsX() == binsx.NBins()*binsy.NBins());
433 
434  TH2* ret = MakeTH2D(UniqueName().c_str(), "", binsx, binsy);
435 
436  for(int i = 0; i < h1->GetNbinsX(); ++i){
437  const double val = h1->GetBinContent(i+1);
438  const double err = h1->GetBinError(i+1);
439 
440  const int ix = i / binsy.NBins();
441  const int iy = i % binsy.NBins();
442 
443  ret->SetBinContent(ix+1, iy+1, val);
444  ret->SetBinError (ix+1, iy+1, err);
445  }
446 
447  if(bintype == ana::EBinType::kBinDensity) ret->Scale(1, "width");
448 
449  return ret;
450  }
451 
452  //----------------------------------------------------------------------
453 
454  TH3* ToTH3(const Spectrum& s, double exposure, ana::EExposureType expotype,
455  const Binning& binsx, const Binning& binsy, const Binning& binsz,
456  ana::EBinType bintype)
457  {
458  DontAddDirectory guard;
459 
460  std::unique_ptr<TH1> h1(s.ToTH1(exposure, expotype));
461 
462  return ToTH3Helper(std::move(h1), binsx, binsy, binsz, bintype);
463  }
464 
465  //----------------------------------------------------------------------
466 
467  TH3* ToTH3(const Ratio& r,
468  const Binning& binsx, const Binning& binsy, const Binning& binsz)
469  {
470  DontAddDirectory guard;
471 
472  std::unique_ptr<TH1> h1(r.ToTH1());
473 
474  return ToTH3Helper(std::move(h1), binsx, binsy, binsz);
475  }
476 
477  //----------------------------------------------------------------------
478  TH3* ToTH3Helper(std::unique_ptr<TH1> h1,
479  const Binning& binsx,
480  const Binning& binsy,
481  const Binning& binsz,
482  ana::EBinType bintype)
483  {
484 
485  const int nx = binsx.NBins();
486  const int ny = binsy.NBins();
487  const int nz = binsz.NBins();
488 
489  // Make sure it's compatible with having been made with this binning
490  assert(h1->GetNbinsX() == nx*ny*nz);
491 
492  TH3* ret;
493 
494  // If all three axes are simple, we can call a simpler constructor
495  if(binsx.IsSimple() && binsy.IsSimple() && binsz.IsSimple()){
496  ret = new TH3F(UniqueName().c_str(), "",
497  nx, binsx.Min(), binsx.Max(),
498  ny, binsy.Min(), binsy.Max(),
499  nz, binsz.Min(), binsz.Max());
500 
501  if(!binsx.IsSimple() || !binsy.IsSimple() || !binsz.IsSimple()){
502  // TH3 doesn't have the constructors for mixed simple and custom
503  std::cerr << "ToTH3: one or more axes is custom, but not all three. Applying Simple binning to all three axes" << std::endl;
504  }
505  }
506  else{
507  ret = new TH3F(UniqueName().c_str(), "",
508  nx, &binsx.Edges().front(),
509  ny, &binsy.Edges().front(),
510  nz, &binsz.Edges().front());
511  }
512 
513  for(int i = 0; i < h1->GetNbinsX(); ++i){
514  const double val = h1->GetBinContent(i+1);
515  const double err = h1->GetBinError(i+1);
516 
517  const int nynz = ny*nz;
518  const int nmodnynz = i%nynz;
519  const int ix = i/nynz;
520  const int iy = nmodnynz/nz;
521  const int iz = i%nz;
522 
523  ret->SetBinContent(ix+1, iy+1, iz+1, val);
524  ret->SetBinError (ix+1, iy+1, iz+1, err);
525  }
526 
527  if(bintype == ana::EBinType::kBinDensity) ret->Scale(1, "width");
528 
529  return ret;
530 
531  }
532 
533  //----------------------------------------------------------------------
534  std::vector<std::string> Wildcard(const std::string& wildcardString)
535  {
536  // Expand environment variables and wildcards like the shell would
537  wordexp_t p;
538  const int status = wordexp(wildcardString.c_str(), &p, WRDE_SHOWERR);
539 
540  if(status != 0){
541  std::cerr << "Wildcard string '" << wildcardString
542  << "' returned error " << status << " from wordexp()."
543  << std::endl;
544  return {};
545  }
546 
547  std::vector<std::string> fileList;
548 
549  for(unsigned int i = 0; i < p.we_wordc; ++i){
550  // Check the file exists before adding it
551  struct stat sb;
552  if(stat(p.we_wordv[i], &sb) == 0)
553  fileList.push_back(p.we_wordv[i]);
554  }
555 
556  wordfree(&p);
557 
558  return fileList;
559  }
560 
561  //----------------------------------------------------------------------
562  std::string FindCAFAnaDir()
563  {
564  return std::string(getenv("MRB_SOURCE"))+"/sbnana/sbnana/CAFAna";
565  }
566 
567  //----------------------------------------------------------------------
568  std::vector<std::string> LoadFileList(const std::string& listfile)
569  {
570  std::vector<std::string> ret;
571 
572  std::ifstream is(listfile);
573  if(!is.good()){
574  std::cerr << "Can't open file list '" << listfile << "'. Aborting." << std::endl;
575  abort();
576  }
577 
578  while(!is.eof()){
579  std::string fname;
580  is >> fname;
581  if(!fname.empty()) ret.push_back(fname);
582  }
583  return ret;
584  }
585 
586  //----------------------------------------------------------------------
587  std::map<std::string, std::string> GetCAFMetadata(TDirectory* dir)
588  {
589  std::map<std::string, std::string> ret;
590 
591  TTree* tr = (TTree*)dir->Get("metatree");
592  if(!tr){
593  std::cout << "Failed to find metadata tree in input CAF. Metadata will be blank." << std::endl;
594  return ret;
595  }
596 
597  std::string key, value;
598  std::string* pkey = &key;
599  std::string* pvalue = &value;
600  tr->SetBranchAddress("key", &pkey);
601  tr->SetBranchAddress("value", &pvalue);
602 
603  for(int i = 0; i < tr->GetEntries(); ++i){
604  tr->GetEntry(i);
605  ret[key] = value;
606  }
607 
608  return ret;
609  }
610 
611  //----------------------------------------------------------------------
612  void CombineMetadata(std::map<std::string, std::string>& base,
613  const std::map<std::string, std::string>& add,
614  std::set<std::string>& mask)
615  {
616  for(auto it: add){
617  const std::string& key = it.first;
618 
619  // Needs special handling anyway, skip it
620  if(key == "parents") continue;
621 
622  // Accumulate the runs list
623  if(key == "runs"){
624  const std::string& r1 = base[key];
625  const std::string& r2 = it.second;
626 
627  assert(!r2.empty());
628 
629  // Strip the outermost enclosing []
630  const std::string& r2tmp = r2.substr(1, r2.length()-2);
631 
632  // Check that the run/subrun is not already present
633  if (r1.find(r2tmp) != std::string::npos){
634  std::cout << "Found files with duplicate run/subrun metadata: " << r2tmp << std::endl;
635 
636  abort();
637  }
638 
639  if(r1.empty()){
640  base[key] = r2;
641  continue;
642  }
643 
644  // "[foo]" + "[bar]"
645  std::string sum = r1+&r2[1]; // "[foo]bar]"
646  sum[r1.size()-1] = ','; // "[foo,bar]"
647  base[key] = sum;
648  continue;
649  }
650 
651  if(base.find(key) == base.end()){
652  // If it's new, add it
653  base[key] = it.second;
654  }
655  else{
656  if(key == "simulated.number_of_spills" ||
657  key == "event_count" ||
658  key == "online.totalevents"){
659  // These two fields should be accumulated
660  base[key] = TString::Format("%d",
661  atoi(base[key].c_str()) +
662  atoi(it.second.c_str())).Data();
663  }
664  else{
665  // If it's a clash, record it
666  if(base[key] != it.second) mask.insert(key);
667  }
668  }
669  }
670  }
671 
672 
673  //----------------------------------------------------------------------
674  void WriteCAFMetadata(TDirectory* dir,
675  const std::map<std::string, std::string>& meta)
676  {
677  TDirectory* tmp = gDirectory;
678  dir->cd();
679 
680  TTree* trmeta = new TTree("metatree", "metatree");
681  std::string key, value;
682  trmeta->Branch("key", &key);
683  trmeta->Branch("value", &value);
684  for(const auto& keyval: meta){
685  key = keyval.first;
686  value = keyval.second;
687  trmeta->Fill();
688  }
689  trmeta->Write();
690 
691  dir->Save();
692 
693  tmp->cd();
694  }
695 
696  //----------------------------------------------------------------------
698  {
699  static bool cache;
700  static bool cache_set = false;
701  if(!cache_set){
702  cache = (getenv("_CONDOR_SCRATCH_DIR") != 0);
703  cache_set = true;
704  }
705 
706  return cache;
707  }
708 
709  //----------------------------------------------------------------------
710  size_t Stride(bool allow_default)
711  {
712  static int cache = -1;
713 
714  if(cache < 0){
715  char* env = getenv("CAFANA_STRIDE");
716  if(env){
717  cache = std::atoi(env);
718  }
719  else{
720  if(allow_default){
721  cache = 1;
722  }
723  else{
724  std::cout << "Stride() called, but CAFANA_STRIDE is not set (--stride not passed?)" << std::endl;
725  abort();
726  }
727  }
728  }
729 
730  return cache;
731  }
732 
733  //----------------------------------------------------------------------
734  size_t Offset(bool allow_default)
735  {
736  static int cache = -1;
737 
738  if(cache < 0){
739  char* env = getenv("CAFANA_OFFSET");
740  if(env){
741  cache = std::atoi(env);
742  }
743  else{
744  if(allow_default){
745  cache = 0;
746  }
747  else{
748  std::cout << "Offset() called, but CAFANA_OFFSET is not set (--offset not passed?)" << std::endl;
749  abort();
750  }
751  }
752  }
753 
754  return cache;
755  }
756 
757  //----------------------------------------------------------------------
758  int Limit()
759  {
760  static int cache = 0;
761 
762  if(cache == 0){
763  char* env = getenv("CAFANA_LIMIT");
764  if(env){
765  cache = std::atoi(env);
766  }
767  else{
768  cache = -1;
769  }
770  }
771 
772  return cache;
773  }
774 
775  //----------------------------------------------------------------------
776  size_t JobNumber()
777  {
778  if(!RunningOnGrid()){
779  std::cout << "JobNumber() called, but we are not running on the grid" << std::endl;
780  abort();
781  }
782 
783  return Offset(false);
784  }
785 
786  //----------------------------------------------------------------------
787  size_t NumJobs()
788  {
789  if(!RunningOnGrid()){
790  std::cout << "NumJobs() called, but we are not running on the grid" << std::endl;
791  abort();
792  }
793 
794  return Stride(false);
795  }
796 
797 
798  //----------------------------------------------------------------------
799  bool AlmostEqual(double a, double b)
800  {
801  if(a == 0 && b == 0) return true;
802 
803  return fabs(a-b)/std::max(a, b) < .0001; // allow 0.01% error
804  }
805 
806 
807  //----------------------------------------------------------------------
808  std::string pnfs2xrootd(std::string loc, bool unauth)
809  {
810  static bool first = true;
811  static bool onsite = false;
812 
813  if (first && unauth) {
814  first = false;
815  char chostname[255];
816  gethostname(chostname, 255);
817  std::string hostname = chostname;
818 
819  if ( hostname.find("fnal.gov") != std::string::npos ){
820  onsite = true;
821  std::cout << "Using unauthenticated xrootd access (port 1095) while on-site, hostname: " << hostname << std::endl;
822  }
823  else {
824  onsite = false;
825  std::cout << "Using authenticated xrootd access (port 1094) access while off-site, hostname: " << hostname << std::endl;
826  }
827  }
828 
829  if(loc.rfind("/pnfs/", 0) == 0){ // ie begins with
830  if ( onsite && unauth )
831  loc = std::string("root://fndcagpvm01.fnal.gov:1095//pnfs/fnal.gov/usr/")+&loc.c_str()[6];
832  else
833  loc = std::string("root://fndcagpvm01.fnal.gov:1094//pnfs/fnal.gov/usr/")+&loc.c_str()[6];
834  }
835  return loc;
836  }
837 
838  //----------------------------------------------------------------------
839  FitToFourier::FitToFourier(TH1* h, double xlo, double xhi, int NOsc)
840  : fHist(h), fxlo(xlo), fxhi(xhi), fNOsc(NOsc)
841  {
842  }
843 
844  //----------------------------------------------------------------------
845  FitToFourier::~FitToFourier()
846  {
847  }
848 
849  //----------------------------------------------------------------------
850  double FitToFourier::operator()(double *x, double *par) const
851  {
852  double x0 = x[0];
853  double val = par[0];
854  for (int i = 1; i <= fNOsc; i++)
855  val += par[2*i-1]*sin(i*M_PI*x0) + par[2*i]*cos(i*M_PI*x0);
856  return val;
857  }
858 
859  //----------------------------------------------------------------------
860  TF1* FitToFourier::Fit() const
861  {
862  //double s[fNOsc] = {0};
863  //double c[fNOsc] = {0};
864 
865  std::vector<double> s(fNOsc, 0.0);
866  std::vector<double> c(fNOsc, 0.0);
867 
868  int nBins = 0;
869  for(int i = 1; i <= fHist->GetNbinsX(); ++i){
870  const double x = M_PI * fHist->GetXaxis()->GetBinCenter(i);
871  const double y = fHist->GetBinContent(i);
872 
873  if(y == 0) continue;
874  ++nBins;
875 
876  for(int n = 0; n <= fNOsc; ++n){
877  s[n] += y * sin(n*x);
878  c[n] += y * cos(n*x);
879  }
880  }
881 
882  for(int n = 0; n <= fNOsc; ++n){
883  s[n] *= 2./nBins;
884  c[n] *= 2./nBins;
885  }
886 
887  TF1* f = new TF1(UniqueName().c_str(), this, fxlo, fxhi, 2*fNOsc+1);
888 
889  f->SetParameter(0, c[0]/2);
890  for(int n = 1; n <= fNOsc; ++n){
891  f->SetParameter(n*2-1, s[n]);
892  f->SetParameter(n*2, c[n]);
893  }
894 
895  // Because ROOT is having problems drawing f if I don't
896  double min = fHist->GetMinimum();
897  double max = fHist->GetMaximum();
898  f->GetYaxis()->SetRangeUser(0.8*min, 1.2*max);
899  return f;
900  }
901 
902  //----------------------------------------------------------------------
903  void EnsurePositiveDefinite(TH2* mat)
904  {
905  // Convert histogram to a proper matrix
906  assert(mat->GetNbinsX() == mat->GetNbinsY());
907  const int N = mat->GetNbinsX();
908  TMatrixD m(N, N);
909  for(int i = 0; i < N; ++i)
910  for(int j = 0; j < N; ++j)
911  m(i, j) = mat->GetBinContent(i+1, j+1);
912 
913  // Decompose it
914  TVectorD evals;
915  TMatrixD evecs = m.EigenVectors(evals);
916  TMatrixD evalmat(N, N);
917  // Force any negative eigenvalues slightly positive (floating point errors)
918  for(int i = 0; i < N; ++i) evalmat(i, i) = std::max(1e-14, evals[i]);
919 
920  // Put the original matrix back together
921  const TMatrixD evecs_inv(TMatrixD::kTransposed, evecs);
922  m = evecs*evalmat*evecs_inv;
923 
924  // Decompose again to check for floating point problems
925  m.EigenVectors(evals);
926  for(int i = 0; i < N; ++i) assert(evals[i] > 0);
927 
928  // Copy the new matrix contents back into the histogram
929  for(int i = 0; i < N; ++i)
930  for(int j = 0; j < N; ++j)
931  mat->SetBinContent(i+1, j+1, m(i, j));
932  }
933 
934  //----------------------------------------------------------------------
935  // Note that this does not work for 3D!
936  TH1* GetMaskHist(const Spectrum& s, double xmin, double xmax, double ymin, double ymax)
937  {
938  if (s.GetBinnings().size() > 2){
939  std::cout << "Error: unable to apply a mask in " << s.GetBinnings().size() << " dimensions" << std::endl;
940  abort();
941  }
942 
943  // The exposure isn't important here
944  TH1* fMaskND = s.ToTHX(s.POT());
945  TH1D* fMask1D = s.ToTH1(s.POT());
946 
947  int ybins = fMaskND->GetNbinsY();
948 
949  for(int i = 0; i < fMask1D->GetNbinsX()+2; ++i){
950 
951  int ix = i / ybins;
952  int iy = i % ybins;
953 
954  bool isMask = false;
955 
956  if (xmin < xmax){
957  if (fMaskND->GetXaxis()->GetBinLowEdge(ix+1) < xmin) isMask=true;
958  if (fMaskND->GetXaxis()->GetBinUpEdge(ix+1) > xmax) isMask=true;
959  }
960 
961  if (ymin < ymax){
962  if (fMaskND->GetYaxis()->GetBinLowEdge(iy+1) < ymin) isMask=true;
963  if (fMaskND->GetYaxis()->GetBinUpEdge(iy+1) > ymax) isMask=true;
964  }
965 
966  if (isMask) fMask1D->SetBinContent(i+1, 0);
967  else fMask1D->SetBinContent(i+1, 1);
968 
969  }
970  return fMask1D;
971  }
972 
973  //----------------------------------------------------------------------
974  double FindQuantile(double frac, std::vector<double>& xs)
975  {
976  // This turns out to be a much more fraught issue than you would naively
977  // expect. This algorithm is equivalent to R-6 here:
978  // https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample
979 
980  // In principle we could use std::nth_element(). Probably doesn't matter
981  // much in practice since this is only for plotting.
982  std::sort(xs.begin(), xs.end());
983 
984  const int N = xs.size();
985  // The index we would ideally be sampling at
986  const double h = frac*(N+1);
987  // The indices on either side where we have to actually evaluate
988  const unsigned int h0 = std::floor(h);
989  const unsigned int h1 = std::ceil(h);
990  if(h0 == 0) return xs[0]; // Don't underflow indexing
991  if(h1 > xs.size()) return xs.back(); // Don't overflow indexing
992  // The values at those indices
993  const double x0 = xs[h0-1]; // wikipedia is using 1-based indexing
994  const double x1 = xs[h1-1];
995 
996  if(h0 == h1) return x0;
997 
998  // Linear interpolation
999  return (h1-h)*x0 + (h-h0)*x1;
1000  }
1001 }
TH2D * MakeTH2D(const char *name, const char *title, const Binning &binsx, const Binning &binsy)
see a below echo S(symbol in a section other than those above)
TH1D * ToTH1(double exposure, Color_t col=kBlack, Style_t style=kSolid, EExposureType expotype=kPOT, EBinType bintype=kBinContent) const
Histogram made from this Spectrum, scaled to some exposure.
Represent the binning of a Spectrum&#39;s x-axis.
Definition: Binning.h:18
TH1D * ToTH1(Color_t col=kBlack, Style_t style=kSolid) const
Definition: Ratio.cxx:116
string fname
Definition: demo.py:5
process_name opflash particleana ie x
BEGIN_PROLOG could also be cerr
size_t Offset(bool allow_default)
TH3 * ToTH3Helper(std::unique_ptr< TH1 > h1, const Binning &binsx, const Binning &binsy, const Binning &binsz, ana::EBinType bintype)
double LogLikelihood(double e, double o)
The log-likelihood formula for a single bin.
EResult err(const char *call)
TH2 * ToTH2Helper(std::unique_ptr< TH1 > h1, const Binning &binsx, const Binning &binsy, ana::EBinType bintype)
pdgs p
Definition: selectors.fcl:22
void CombineMetadata(std::map< std::string, std::string > &base, const std::map< std::string, std::string > &add, std::set< std::string > &mask)
Divide bin contents by bin widths.
std::vector< std::string > Wildcard(const std::string &wildcardString)
double FindQuantile(double frac, std::vector< double > &xs)
std::unique_ptr< TMatrixD > SymmMxInverse(const TMatrixD &mx)
process_name opflashCryoW ana
std::string pnfs2xrootd(std::string loc, bool unauth)
void EnsurePositiveDefinite(TH2 *mat)
T sqr(T x)
More efficient square function than pow(x,2)
Definition: MathUtil.h:23
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
Representation of a spectrum in any variable, with associated POT.
Definition: Spectrum.h:30
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
bool IsSimple() const
Definition: Binning.h:31
process_name gaushit a
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
while getopts h
std::map< std::string, std::string > GetCAFMetadata(TDirectory *dir)
TH2F * ExpandedHistogram(const std::string &title, int nbinsx, double xmin, double xmax, bool xlog, int nbinsy, double ymin, double ymax, bool ylog)
process_name opflash particleana ie ie y
double Min() const
Definition: Binning.h:28
constexpr mask_t< EnumType > mask(EnumType bit, OtherBits...otherBits)
Returns a mask with all specified bits set.
std::string Experiment()
$EXPERIMENT or a nice error message and abort
std::unique_ptr< TMatrixD > CalcCovMx(const std::vector< TArrayD * > &binSets, int firstBin, int lastBin)
Compute bin-to-bin covariance matrix from a collection of sets of bin contents.
EExposureType
For use as an argument to Spectrum::ToTH1.
TH1 * ToTHX(double exposure, bool force1D=false, EExposureType expotype=kPOT) const
Function decides what is the appropriate projection based on fBins, and does that.
void WriteCAFMetadata(TDirectory *dir, const std::map< std::string, std::string > &meta)
bool AlmostEqual(double a, double b)
double POT() const
Definition: Spectrum.h:289
TH2 * ToTH2(const Spectrum &s, double exposure, ana::EExposureType expotype, const Binning &binsx, const Binning &binsy, ana::EBinType bintype)
Represent the ratio between two spectra.
Definition: Ratio.h:8
const std::vector< double > & Edges() const
Definition: Binning.h:32
TH1D * MakeTH1D(const char *name, const char *title, const Binning &bins)
tuple dir
Definition: dropbox.py:28
double Max() const
Definition: Binning.h:29
size_t Stride(bool allow_default)
then echo File list $list not found else cat $list while read file do echo $file sed s
Definition: file_to_url.sh:60
int NBins() const
Definition: Binning.h:27
std::string SAMExperiment()
$SAM_EXPERIMENT or a nice error message and abort
process_name largeant stream1 can override from command line with o or output physics producers generator N
do i e
then echo fcl name
temporary value
std::vector< std::string > LoadFileList(const std::string &listfile)
pdgs k
Definition: selectors.fcl:22
Prevent histograms being added to the current directory.
float A
Definition: dedx.py:137
TH3 * ToTH3(const Spectrum &s, double exposure, ana::EExposureType expotype, const Binning &binsx, const Binning &binsy, const Binning &binsz, ana::EBinType bintype)
esac echo uname r
TH1 * GetMaskHist(const Spectrum &s, double xmin, double xmax, double ymin, double ymax)
std::string UniqueName()
Return a different string each time, for creating histograms.
BEGIN_PROLOG could also be cout
double Chi2CovMx(const TVectorD *e, const TVectorD *o, const TMatrixD *covmxinv)
std::vector< Binning > GetBinnings() const
Definition: Spectrum.h:325