ShowerCalibrationGaloreFromPID.h
Go to the documentation of this file.
1 /**
2  * @file ShowerCalibrationGaloreFromPID.h
3  * @brief Shower energy calibration according to particle type
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date April 28, 2016
6  * @see ShowerCalibrationGalore.h
7  * @ingroup ShowerCalibrationGalore
8  *
9  *
10  */
11 
12 
13 #ifndef LAREXAMPLES_SERVICES_SHOWERCALIBRATIONGALORE_PROVIDERS_SHOWERCALIBRATIONGALOREFROMPID_H
14 #define LAREXAMPLES_SERVICES_SHOWERCALIBRATIONGALORE_PROVIDERS_SHOWERCALIBRATIONGALOREFROMPID_H
15 
16 
17 // LArSoft libraries
19 
20 /// framework and utility libraries
21 #include "fhiclcpp/types/Atom.h"
22 #include "fhiclcpp/types/Table.h"
23 #include "cetlib_except/exception.h"
24 
25 // ROOT libraries
26 #include "Math/Interpolator.h"
27 #include "TDirectory.h"
28 #include "TClass.h"
29 #include "TH1.h"
30 #include "TObject.h"
31 
32 // C/C++ standard libraries
33 #include <string>
34 #include <vector>
35 #include <memory> // std::unique_ptr()
36 #include <type_traits> // std::is_base_of<>
37 #include <initializer_list>
38 
39 
40 // forward declarations
41 class TGraph; // from ROOT
42 
43 
44 namespace lar {
45  namespace example {
46 
47  // BEGIN ShowerCalibrationGalore -----------------------------------------
48  /// @ingroup ShowerCalibrationGalore
49  /// @{
50 
51  namespace details {
52 
53  /// Reads an object from a ROOT directory, checking its type
54  /// @throw cet::exception if no object or wrong type
55  template <typename ROOTobj>
56  std::unique_ptr<ROOTobj> readROOTobject
57  (TDirectory* sourceDir, std::string name);
58 
59  } // namespace details
60 
61 
62  /// Splits path into ROOT file name and directory path
63  std::pair<std::string, std::string> splitROOTpath(std::string path);
64 
65 
66  /**
67  * @brief Shower calibration service provider correcting according to PID.
68  *
69  * The service provider computes a calibration factor for a reconstructed
70  * shower. The calibration factor depends on an hypothesis on the type of
71  * particle.
72  * The calibration factors are extracted from the specified ROOT file.
73  *
74  * Calibration file format
75  * ------------------------
76  *
77  * Calibration is represented by a list of objects with specific names:
78  *
79  * * `"Pi0"` (`TGraphErrors`):
80  * neutral pion calibration vs. reconstructed energy
81  * * `"Photon"` (`TGraphErrors`):
82  * photon calibration vs. reconstructed energy
83  * * `"Electron"` (`TGraphErrors`):
84  * electron/positron calibration vs. reconstructed energy
85  * * `"Muon"` (`TGraphErrors`):
86  * muon/antimuon calibration vs. reconstructed energy
87  * * `"Default"` (`TGraphErrors`):
88  * other particle calibration vs. reconstructed energy
89  *
90  * Each graph is required to hold at least one point, and its points must
91  * be already sorted by energy.
92  * Energy is measured in GeV.
93  *
94  *
95  * Calibration factors from the input
96  * -----------------------------------
97  *
98  * The input calibration objects are graphs with symmetric errors.
99  * The independent variable is the best estimation of the reconstructed
100  * energy of the shower. The correction factor is interpolated (by a cubic
101  * spline) between the points in the graph; errors are likewise
102  * interpolated. If the requested energy is outside the range of the graph
103  * the correction is the same as the closest available energy point, with
104  * its uncertainty doubled every half full range of the graph.
105  * As a special case, if the graph has only one point, the correction is
106  * uniform in the full energy spectrum (including its uncertainty).
107  *
108  *
109  * Configuration parameters
110  * -------------------------
111  *
112  * * *CalibrationFile* (string, _mandatory_): path to the file containing
113  * the full shower calibration information; it is made of a file system
114  * path to the ROOT file, and an optional ROOT directory path; for
115  * example: `path/to/file.root:Calibrations/Shower` expects a nested
116  * ROOT directory structure `Calibrations/Shower` in the ROOT file
117  * `path/to/file.root`, where `path` is accessible from the usual search
118  * path in `FW_SEARCH_PATH`
119  *
120  */
122  public:
123 
124  //---------------------------------------------------------------------
125  /// Collection of configuration parameters for the service
126  struct Config {
127  using Name = fhicl::Name;
129 
130  fhicl::Atom<std::string> CalibrationFile {
131  Name("CalibrationFile"),
132  Comment(
133  "path to calibration file and ROOT directory"
134  " (e.g. path/to/file.root:Dir/Dir)"
135  )
136  };
137 
138  }; // struct Config
139 
140  /// Type describing all the parameters
142 
143 
144  //---------------------------------------------------------------------
145  /// Constructor from the complete configuration object
147  { readCalibration(config.CalibrationFile()); }
148 
149  //---------------------------------------------------------------------
150  /// Constructor from a parameter set
153  (parameters_type(pset, { "service_type", "service_provider" })())
154  {}
155 
156 
157  /// @{
158  /// @name Correction query
159 
160  //---------------------------------------------------------------------
161  /**
162  * @brief Returns a correction factor for a given reconstructed shower
163  * @return the uniform energy correction factor
164  * @see correction()
165  *
166  * The returned value includes a correction factor to be applied to
167  * the shower energy to calibrate it, but no uncertainty.
168  *
169  */
170  virtual float correctionFactor
171  (recob::Shower const&, PDGID_t = unknownID) const override;
172 
173  /**
174  * @brief Returns the correction for a given reconstructed shower
175  * @return the correction with its uncertainty
176  * @see correctionFactor()
177  *
178  * The returned value includes a correction factor to be applied to
179  * any shower energy to calibrate it, with its global uncertainty.
180  *
181  */
182  virtual Correction_t correction
183  (recob::Shower const&, PDGID_t = unknownID) const override;
184 
185  /// @}
186 
187  /// Returns a string with a short report of the current corrections
188  virtual std::string report() const override
189  { std::ostringstream sstr; reportTo(sstr); return sstr.str(); }
190 
191 
192  /// Reads the calibration information from the specified file
193  void readCalibration(std::string path);
194 
195 
196  /// Prints a short report of the current corrections
197  template <typename Stream>
198  void reportTo(Stream&& out) const;
199 
200 
201  /// Verifies that points in specified graph have increasing abscissa
202  /// @throw cet::exception if points are not sorted by growing x
203  static void verifyOrder(TGraph const* graph);
204 
205 
206  //---------------------------------------------------------------------
207  private:
208  /// Internal structure containing the calibration information
210  std::vector<PDGID_t> appliesTo; ///< PID it applies to; unused
211  double minE = -1.; ///< lower end of the energy range covered [GeV]
212  double maxE = -1.; ///< upper end of the energy range covered [GeV]
213 
214  /// parametrisation of the correction factor
215  std::unique_ptr<ROOT::Math::Interpolator> factor;
216 
217  /// parametrisation of the correction uncertainty
218  std::unique_ptr<ROOT::Math::Interpolator> error;
219 
220  double evalFactor(double E) const;
221  double evalError(double E) const;
222 
223  bool present() const { return maxE >= 0.; }
224  bool uniform() const { return minE == maxE; }
225 
226  CalibrationInfo_t& applyTo(PDGID_t id);
227  CalibrationInfo_t& applyTo(std::initializer_list<PDGID_t> ids);
228 
229  /// Prints a short report of this correction
230  template <typename Stream>
231  void reportTo(Stream&& out) const;
232  }; // CalibrationInfo_t
233 
234 
235  CalibrationInfo_t Calibration_pi0; ///< neutral pion calibration
236  CalibrationInfo_t Calibration_photon; ///< photon calibration
237  CalibrationInfo_t Calibration_electron; ///< electron/positron calibration
238  CalibrationInfo_t Calibration_muon; ///< muon/antimuon calibration
239  CalibrationInfo_t Calibration_other; ///< default calibration
240 
241 
242  /// Returns the correct CalibrationInfo_t for specified id
243  CalibrationInfo_t const& selectCorrection(PDGID_t id) const;
244 
245  /// Reads and returns calibration information from the specified graph
246  CalibrationInfo_t readParticleCalibration
247  (TDirectory* SourceDir, std::string GraphName) const;
248 
249  /// Reads and returns calibration information from the specified graph
250  /// and register a particle ID in it
251  CalibrationInfo_t readParticleCalibration
252  (TDirectory* SourceDir, std::string GraphName, PDGID_t id) const;
253 
254  /// Reads and returns calibration information from the specified graph
255  /// and register a list of particle IDs to it
256  CalibrationInfo_t readParticleCalibration(
257  TDirectory* SourceDir, std::string GraphName,
258  std::initializer_list<PDGID_t> ids
259  ) const;
260 
261  /// Opens the specified ROOT directory, as in path/to/file.root:dir/dir
262  static TDirectory* OpenROOTdirectory(std::string path);
263 
264  /// Creates a ROOT interpolator from a set of N points
265  static std::unique_ptr<ROOT::Math::Interpolator>
266  createInterpolator(unsigned int N, double const* x, double const* y);
267 
268  }; // class ShowerCalibrationGaloreFromPID
269 
270  /// @}
271  // END ShowerCalibrationGalore -----------------------------------------------
272 
273 
274  } // namespace example
275 } // namespace lar
276 
277 
278 
279 //------------------------------------------------------------------------------
280 //--- template implementation
281 //---
282 template <typename ROOTobj>
283 std::unique_ptr<ROOTobj> lar::example::details::readROOTobject
284  (TDirectory* sourceDir, std::string name)
285 {
286  if (!sourceDir) {
287  throw cet::exception("readROOTobject")
288  << "Invalid source ROOT directory\n";
289  }
290 
291  // read the object and immediately claim its ownership
292  TObject* pObj = sourceDir->Get(name.c_str());
293  if (!pObj) {
294  throw cet::exception("readROOTobject")
295  << "No object '" << name << "' in ROOT directory '"
296  << sourceDir->GetPath() << "'\n";
297  }
298 
299  if (std::is_base_of<TH1, std::decay_t<ROOTobj>>::value)
300  static_cast<TH1*>(pObj)->SetDirectory(nullptr);
301 // if (std::is_base_of<TTree, std::decay_t<ROOTobj>>::value)
302 // static_cast<TTree*>(pObj)->SetDirectory(nullptr);
303  std::unique_ptr<TObject> obj(pObj);
304 
305  // use ROOT to investigate whether this is the right type
306  if (!obj->InheritsFrom(ROOTobj::Class())) {
307  throw cet::exception("readROOTobject")
308  << "Object '" << name << "' in ROOT directory '"
309  << sourceDir->GetPath() << "' is a " << obj->IsA()->GetName()
310  << ", not derived from " << ROOTobj::Class()->GetName() << "\n";
311  }
312 
313  // now that we are sure obj is of the right type, we transfer ownership
314  // from obj to the return value (that here is implicitly constructed)
315  return std::unique_ptr<ROOTobj>(static_cast<ROOTobj*>(obj.release()));
316 } // lar::example::details::readROOTobject()
317 
318 //------------------------------------------------------------------------------
319 //--- lar::example::ShowerCalibrationGaloreFromPID
320 //---
321 template <typename Stream>
323 {
324  out << "Corrections for:";
325  out << "\n - neutral pion: ";
326  Calibration_pi0.reportTo(std::forward<Stream>(out));
327  out << "\n - photon: ";
328  Calibration_photon.reportTo(std::forward<Stream>(out));
329  out << "\n - electron/positron: ";
330  Calibration_electron.reportTo(std::forward<Stream>(out));
331  out << "\n - muon/antimuon: ";
332  Calibration_muon.reportTo(std::forward<Stream>(out));
333  out << "\n - other (default): ";
334  Calibration_other.reportTo(std::forward<Stream>(out));
335  out << "\n";
336 } // lar::example::ShowerCalibrationGaloreFromPID::report()
337 
338 
339 //------------------------------------------------------------------------------
340 template <typename Stream>
342  (Stream&& out) const
343 {
344  if (!present()) {
345  out << "not present";
346  return;
347  }
348  if (uniform()) {
349  out << "uniform correction " << factor->Eval(minE) << " +/- "
350  << error->Eval(minE) << " for all energies";
351  }
352  else {
353  out << "correction valid from E=" << minE
354  << " GeV (" << factor->Eval(minE) << " +/- " << error->Eval(minE)
355  << ") to E=" << maxE
356  << " GeV (" << factor->Eval(maxE) << " +/- " << error->Eval(maxE)
357  << ")";
358  }
359  if (!appliesTo.empty()) {
360  out << "; covers particles ID={";
361  for (auto id: appliesTo) out << " " << id;
362  out << " }";
363  }
364 
365 } // lar::example::ShowerCalibrationGaloreFromPID::CalibrationInfo_t::report()
366 
367 
368 //------------------------------------------------------------------------------
369 
370 
371 #endif // LAREXAMPLES_SERVICES_SHOWERCALIBRATIONGALORE_PROVIDERS_SHOWERCALIBRATIONGALOREFROMPID_H
372 
CalibrationInfo_t Calibration_pi0
neutral pion calibration
static QCString name
Definition: declinfo.cpp:673
CalibrationInfo_t Calibration_electron
electron/positron calibration
Internal structure containing the calibration information.
std::string string
Definition: nybbler.cc:12
std::unique_ptr< ROOT::Math::Interpolator > error
parametrisation of the correction uncertainty
ChannelGroupService::Name Name
def graph(desc, maker=maker)
Definition: apa.py:294
error
Definition: include.cc:26
Collection of configuration parameters for the service.
A correction factor with global uncertainty.
Shower calibration service provider correcting according to PID.
CalibrationInfo_t Calibration_photon
photon calibration
ShowerCalibrationGaloreFromPID(fhicl::ParameterSet const &pset)
Constructor from a parameter set.
CalibrationInfo_t Calibration_other
default calibration
static Config * config
Definition: config.cpp:1054
CalibrationInfo_t Calibration_muon
muon/antimuon calibration
std::unique_ptr< ROOT::Math::Interpolator > factor
parametrisation of the correction factor
#define Comment
int PDGID_t
A type representing a particle ID in Particle Data Group convention.
Interface for a shower calibration service provider.
LArSoft-specific namespace.
virtual std::string report() const override
Returns a string with a short report of the current corrections.
list x
Definition: train.py:276
std::unique_ptr< ROOTobj > readROOTobject(TDirectory *sourceDir, std::string name)
std::pair< std::string, std::string > splitROOTpath(std::string path)
Splits path into ROOT file name and directory path.
void reportTo(Stream &&out) const
Prints a short report of this correction.
ShowerCalibrationGaloreFromPID(Config const &config)
Constructor from the complete configuration object.
void reportTo(Stream &&out) const
Prints a short report of the current corrections.
constexpr ProductStatus present() noexcept
Definition: ProductStatus.h:10
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Interface for a shower calibration service provider.