All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UnfoldTikhonov.cxx
Go to the documentation of this file.
2 
3 //#include "sbnana/CAFAna/Core/Utilities.h"
5 
6 #include "TH2.h"
7 
8 #include <Eigen/Dense>
9 
10 #include <cassert>
11 #include <iostream>
12 
13 namespace ana
14 {
15  //----------------------------------------------------------------------
17  const ReweightableSpectrum& recoVsTrue,
18  double regStrength)
19  {
20  assert(regStrength >= 0);
21 
22  if(recoVsTrue.NDimensions() != 1){
23  std::cout << "UnfoldTikhonov: must use 1D reco axis. This is not a fundamental limitation. The code could be improved relatively easily." << std::endl;
24  abort();
25  }
26 
27  DontAddDirectory guard;
28 
29  // This is where that requirement comes in
30  const unsigned int Nreco = recoVsTrue.GetBinnings()[0].NBins();
31  const unsigned int Ntrue = recoVsTrue.GetBinnings()[1].NBins();
32 
33  // Smearing matrix from true to reco
34  Eigen::MatrixXd M(Nreco, Ntrue);
35 
36  TH2D* m = recoVsTrue.ToTH2(1);
37  for(unsigned int j = 0; j < Ntrue; ++j){
38  double tot = 0;
39  for(unsigned int i = 0; i < Nreco; ++i){
40  const double mij = m->GetBinContent(i+1, j+1);
41  M(i, j) = mij;
42  tot += mij;
43  }
44  // Normalize each column of true energy. One true event smears to one
45  // reco event total.
46  if(tot != 0) for(unsigned int i = 0; i < Nreco; ++i) M(i, j) /= tot;
47  } // end for j
48  delete m;
49 
50  // Data vector
51  TH1D* hy = reco.ToTH1(reco.POT());
52  Eigen::VectorXd y(Nreco);
53  for(unsigned int i = 0; i < Nreco; ++i) y[i] = hy->GetBinContent(i+1);
55 
56  // Matrix penalizing true distributions with large second derivative. Would
57  // also need an update here for multi-dimensional distribution. I think you
58  // would add an extra P term to the equations for each dimension.
59  Eigen::MatrixXd P = Eigen::MatrixXd::Zero(Ntrue, Ntrue);
60  for(unsigned int i = 1; i+1 < Ntrue; ++i){
61  P(i, i) = -2;
62  P(i, i-1) = P(i, i+1) = 1;
63  }
64 
65  // We are trying to minimize a chisq
66  //
67  // chisq = (M*x-y)^2 + lambda*(P*x)^2
68  //
69  // to solve for the best true distribution x.
70  //
71  // This results in needing to solve
72  //
73  // (M^T*M + lambda*P^T*P)*x = M^T*y
74 
75  const Eigen::MatrixXd lhs = M.transpose()*M + regStrength*P.transpose()*P;
76  const Eigen::VectorXd rhs = M.transpose()*y;
77 
78  // https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html
79  Eigen::ColPivHouseholderQR<Eigen::MatrixXd> dec(lhs);
80  const Eigen::VectorXd ret = dec.solve(rhs);
81 
82 
83  // To get the correct binning
84  std::unique_ptr<TH1D> hret(recoVsTrue.WeightingVariable().ToTH1(reco.POT()));
85  hret->Reset();
86  for(unsigned int i = 0; i < Ntrue; ++i) hret->SetBinContent(i+1, ret[i]);
87 
88  // TODO in principle these should be the true labels and bins. Will be
89  // easier with cafanacore
90  return Spectrum(std::move(hret), {""}, {recoVsTrue.GetBinnings()[1]},
91  reco.POT(), reco.Livetime());
92  }
93 }
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.
Spectrum with the value of a second variable, allowing for reweighting
process_name opflashCryoW ana
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
Spectrum UnfoldTikhonov(const Spectrum &reco, const ReweightableSpectrum &recoVsTrue, double regStrength)
Unfolding using Tikhonov regularization (penalizing true spectra with large second derivatives) ...
process_name standard_reco_uboone reco
process_name opflash particleana ie ie y
std::vector< Binning > GetBinnings() const
static void Delete(TH1D *&h)
Definition: HistCache.cxx:92
double POT() const
Definition: Spectrum.h:289
Prevent histograms being added to the current directory.
double Livetime() const
Seconds. For informational purposes only. No calculations use this.
Definition: Spectrum.h:292
BEGIN_PROLOG could also be cout
unsigned int NDimensions() const
TH2D * ToTH2(double pot) const