ATLAS Offline Software
Loading...
Searching...
No Matches
CalibrationDataContainer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5
7
8#include <iostream>
9#include <cassert>
10#include <limits>
11#include <algorithm>
12#include <cmath>
13
14#include "TH1.h"
15#include "TAxis.h"
16#include "TF1.h"
17#include "TVectorT.h"
18#include "TMatrixT.h"
19#include "TMatrixDSym.h"
20#include "TMath.h"
21#include "TString.h"
22#include "TObjString.h"
23
30
31// Things that are best hidden from the outside world...
32namespace {
33
34 // The value below is added to (subtracted from) the lower (upper) bound of validity
35 // when a variable is restricted to be within its validity range.
36 const double rangeEpsilon = 1.e-5;
37
38 // array size for boundary specifications
39 const int maxParameters = 10;
40
41}
42
43
44
45
47// //
48// CalibrationDataContainer //
49// //
50// These container classes represent the basic b-tagging calibration information //
51// stored in ROOT files. The abstract base class is the CalibrationDataContainer, //
52// and this "container" is meant to be used for basic jet-by-jet usage. The idea //
53// is that the container object itself contains sufficient information to determine //
54// how b-tagging information (mostly efficiencies for given working points, but in //
55// the case of so-called "continuous tagging" it can be the fractions of jets in //
56// tag weight bins) is parametrised. The retrieval of the requested information is //
57// then done by passing a (reference to a) CalibrationDataVariables struct, which is //
58// a very simple object containing information that can potentially be used for the //
59// parametrisation. It is then up to the container object to figure out what subset //
60// of the information then to use in reality. The user may request a fairly wide //
61// range of information, ranging from mere central values (typically, //
62// CalibrationDataContainer::getResult() will be used for this) to individual //
63// contributions to the total systematic uncertainty (using //
64// CalibrationDataContainer::getUncertainty()). The container class derives from a //
65// TMap, with keys being strings (TObjString, for technical reasons) ensuring significant //
66// flexibility as to the specification of uncertainty information. //
67// //
68// The underlying information can be presented in two forms: in histogram form (this //
69// corresponds to the CalibrationDataHistogramContainer derived class), and as a //
70// functional parametrisation (the CalibrationDataFunctionContainer derived class). //
71// So far, the CalibrationDataHistogramContainer has been used for the storage of //
72// data/MC calibration scale factor information, while up to recently the //
73// CalibrationDataFunctionContainer was used to store MC information. Recently, the //
74// storage of MC information also moved to the use of histograms, because of biases //
75// in the functional parametrisations (in addition to the fact that in order to //
76// derive these parametrisations in the first place, a non-negligible amount of //
77// manual intervention is required). //
78// //
79// CalibrationDataContainer.cxx, (c) ATLAS Detector software //
81
82#ifndef __CINT__
84#endif
85
86//________________________________________________________________________________
88 TMap(), m_objResult(0), m_objSystematics(0), m_vars(), m_restrict(false)
89{
90 // default constructor
91 SetName(name);
92}
93
94//________________________________________________________________________________
98
99//________________________________________________________________________________
102 UncertaintyResult& result, TObject* obj)
103{
104 // short-hand for the total systematic uncertainty retrieval.
105 // For "normal" usage (retrieval of central values and total uncertainties), the total systematic
106 // uncertainty object needs to be accessed frequently. In order to avoid nee
107
108 // cache the pointer to the "systematics" object (to avoid string comparisons)
109 if (!obj) {
110 if (! m_objSystematics) {
111 m_objSystematics = GetValue("systematics");
112 }
113 obj = m_objSystematics;
114 }
115 return getUncertainty("systematics", x, result, obj);
116}
117
118//________________________________________________________________________________
119std::vector<std::string>
121{
122 // Retrieve the list of uncertainties for this calibration.
123 // Note that this is an un-pruned list: it contains also entries that
124 // are not proper uncertainties (e.g. "result", "comment")
125
126 std::vector<std::string> uncertainties;
127 TIter it(GetTable());
128 while (TPair* pair = (TPair*) it()) {
129
130 uncertainties.emplace_back(pair->Key()->GetName());
131 }
132 return uncertainties;
133}
134
135//________________________________________________________________________________
138 std::map<std::string, UncertaintyResult>& all)
139{
140 // Retrieve all uncertainties for this calibration.
141
144
145 // first treat the "result" entry separately
146 double single_result;
147 CalibrationStatus code = getResult(x, single_result);
148 if (code == Analysis::kError) {
149 std::cerr << "in CalibrationDataContainer::getUncertainties(): error retrieving result!" << std::endl;
150 return code;
151 }
152 else if (code != Analysis::kSuccess) mycode = code;
153 result.first = single_result;
154 result.second = 0;
155 all[std::string("result")] = result;
156
157 // similar for the "statistics" entry
158 code = getStatUncertainty(x, single_result);
159 if (code == Analysis::kError) {
160 std::cerr << "in CalibrationDataContainer::getUncertainties(): error retrieving stat. uncertainty!" << std::endl;
161 return code;
162 }
163 else if (code != Analysis::kSuccess) mycode = code;
164 result.first = single_result;
165 result.second = -single_result;
166 all[std::string("statistics")] = result;
167
168 // then cycle through the other (systematic) uncertainties
169 TIter it(GetTable());
170 while (TPair* pair = (TPair*) it()) {
171 std::string spec(pair->Key()->GetName());
172 // ignore these specific entries
173 if (spec == "comment" || spec == "result" || spec == "statistics" || spec == "MChadronisation" || spec == "excluded_set") continue;
174 code = getUncertainty(spec, x, result, pair->Value());
175 // we should never be finding any errors
176 if (code == Analysis::kError) {
177 std::cerr << "in CalibrationDataContainer::getUncertainties(): error retrieving named uncertainty "
178 << spec << "!" << std::endl;
179 return code;
180 }
181 // this assumes that non-success codes are likely to be correlated between uncertainty sources
182 else if (code != Analysis::kSuccess) mycode = code;
183 all[spec] = result;
184 }
185 return mycode;
186}
187
188//________________________________________________________________________________
189std::string
191{
192 // Retrieve the comments for this calibration (if any)
193
194 TObject* obj = GetValue("comment");
195 if (! obj) return std::string("");
196 TObjString* s = dynamic_cast<TObjString*>(obj);
197 if (! s ) return std::string("");
198 return std::string(s->GetName());
199}
200
201//________________________________________________________________________________
202std::string
204{
205 // Retrieve the hadronisation reference for this calibration (if any)
206 const static std::string null("");
207
208 TObject* obj = GetValue("MChadronisation");
209 if (! obj) return null;
210 TObjString* s = dynamic_cast<TObjString*>(obj);
211 if (! s ) return null;
212 return std::string(s->GetName());
213}
214
215//________________________________________________________________________________
216std::string
218{
219 // Retrieve the (semicolon-separated) set of uncertainties that are recommended for removal from the eigenvector decomposition (if any)
220 const static std::string null("");
221
222 TObject* obj = GetValue("excluded_set");
223 if (! obj) return null;
224 TObjString* s = dynamic_cast<TObjString*>(obj);
225 if (! s ) return null;
226 return std::string(s->GetName());
227}
228
229//________________________________________________________________________________
230void
231CalibrationDataContainer::setUncertainty(const std::string& unc, TObject* obj)
232{
233 // Insert (or replace) the given object at the position indicated by the given index.
234 //
235 // unc: uncertainty index
236 // obj: object to be entered (needs to inherit from TObject)
237
238 if (TPair* p = (TPair*) FindObject(unc.c_str())) DeleteEntry(p->Key());
239 Add(new TObjString(unc.c_str()), obj);
240}
241
242//________________________________________________________________________________
243void
245{
246 // Specialization of the setUncertainty() method: insert the calibration result
247 //
248 // obj: object to be entered (needs to inherit from TObject)
249
250 setUncertainty(std::string("result"), obj);
251}
252
253//________________________________________________________________________________
254void
256{
257 // Insert (or replace) the comment field. This needs to be handled somewhat
258 // specially as TString itself doesn't inherit from TObject.
259 //
260 // text: comment field (will be converted to TObjString)
261
262 if (TPair* p = (TPair*) FindObject("comment")) DeleteEntry(p->Key());
263 Add(new TObjString("comment"), new TObjString(text.c_str()));
264}
265
266//________________________________________________________________________________
267void
269{
270 // Insert (or replace) the hadronisation reference.
271 //
272 // text: hadronisation reference in string form (will be converted to TObjString)
273
274 if (TPair* p = (TPair*) FindObject("MChadronisation")) DeleteEntry(p->Key());
275 Add(new TObjString("MChadronisation"), new TObjString(text.c_str()));
276}
277
278//________________________________________________________________________________
279void
281{
282 // Insert (or replace) the (semicolon-separated) list of uncertainties that are recommended to be excluded from the eigenvector decomposition
283 //
284 // text: the (semicolon-separated) list of uncertainties in string form (will be converted to TObjString)
285
286 if (TPair* p = (TPair*) FindObject("excluded_set")) DeleteEntry(p->Key());
287 Add(new TObjString("excluded_set"), new TObjString(text.c_str()));
288}
289
290//________________________________________________________________________________
291int
292CalibrationDataContainer::typeFromString(const std::string& key) const
293{
294 // Small utility function collecting the correspondence between axis labels and (integer) variable indices.
295 // In case of an unknown label, a negative number will be returned to flag the issue.
296
297 if (key == "eta") return kEta;
298 else if (key == "abseta") return kAbsEta;
299 else if (key == "pt") return kPt;
300 else if (key == "tagweight") return kTagWeight;
301 // return value for unknown keywords
302 else return -1;
303}
304
305//________________________________________________________________________________
308{
309 // Determine which variables are to be used, and insert them in a separate array (which is only used internally).
310 // The return value is used to indicate whether any input co-ordinate was out of bounds; where a distinction
311 // is made between being outside the extrapolation region (kExtrapolatedRange) or merely the calibration region
312 // (kRange).
313 // The "extrapolate" variable is used to flag whether an extrapolation uncertainty applies
314 // (this should anyway occur only for histogram containers).
315 // This is also the place where any computations are being done (e.g. jet pt values are divided by 1000
316 // to convert them from MeV to GeV).
317
318 // ensure that the variable types have been computed properly
319 if (m_variables.size() == 0) computeVariableTypes();
320
321 // also keep track of whether the variables are within bounds
323
324 // std::cout << "computeVariables(): input jet pt: " << x.jetPt << ", eta " << x.jetEta << ", tag weight " << x.jetTagWeight << std::endl;
325
326 for (unsigned int var = 0; var < m_variables.size(); ++var) {
327 switch (m_variables[var]) {
328 case kPt:
329 // assume that the input values are given in MeV but the performance calibration in GeV!
330 m_vars[var] = x.jetPt * 0.001;
331 break;
332 case kEta:
333 m_vars[var] = x.jetEta;
334 break;
335 case kAbsEta:
336 m_vars[var] = x.jetEta;
337 if (m_vars[var] < 0) m_vars[var] *= -1.0;
338 break;
339 case kTagWeight:
340 m_vars[var] = x.jetTagWeight;
341 }
342 if (m_vars[var] < getLowerBound(m_variables[var], extrapolate)) {
343 if (status != kExtrapolatedRange) {
344 status = (extrapolate || (m_vars[var] < getLowerBound(m_variables[var], true))) ? kExtrapolatedRange : kRange;
345 // std::cout << "computeVariables(): variable " << var << ", value: " << m_vars[var] << ", setting status to " << status << std::endl;
346 }
347 if (m_restrict) m_vars[var] = getLowerBound(m_variables[var], extrapolate) + rangeEpsilon;
348 } else if (m_vars[var] >= getUpperBound(m_variables[var], extrapolate)) {
349 if (status != kExtrapolatedRange) {
350 status = (extrapolate || (m_vars[var] >= getUpperBound(m_variables[var], true))) ? kExtrapolatedRange : kRange;
351 // std::cout << "computeVariables(): variable " << var << ", value: " << m_vars[var] << ", extrapolate? " << extrapolate
352 // << ", upper bound: " << getUpperBound(m_variables[var],extrapolate)
353 // << " (extrapolation bound: " << getUpperBound(m_variables[var],true) << "), setting status to " << status << std::endl;
354 }
355 if (m_restrict) m_vars[var] = getUpperBound(m_variables[var], extrapolate) - rangeEpsilon;
356 }
357 }
358
359 // std::cout << "computeVariables(): output variables: " << m_vars[0] << ", " << m_vars[1] << ", " << m_vars[2] << std::endl;
360
361 return status;
362}
363
364//________________________________________________________________________________
365double
366CalibrationDataContainer::getLowerBound(unsigned int vartype, bool extrapolate) const
367{
368 // Utility function returning the lower validity bound for the given variable type.
369 // The "extrapolate" variable flags whether normal validity bounds are to be used,
370 // or instead those relevant for the extrapolation uncertainty.
371
372 double minDefault = (vartype == kAbsEta || vartype == kPt) ? 0 : -std::numeric_limits<double>::max();
373 if (! (vartype < m_lowerBounds.size())) return minDefault;
374 return extrapolate ? m_lowerBoundsExtrapolated[vartype] : m_lowerBounds[vartype];
375}
376
377//________________________________________________________________________________
378double
379CalibrationDataContainer::getUpperBound(unsigned int vartype, bool extrapolate) const
380{
381 // Utility function returning the upper validity bound for the given variable type.
382 // The "extrapolate" variable flags whether normal validity bounds are to be used,
383 // or instead those relevant for the extrapolation uncertainty.
384
385 if (! (vartype < m_lowerBounds.size())) return std::numeric_limits<double>::max();
386 return extrapolate ? m_upperBoundsExtrapolated[vartype] : m_upperBounds[vartype];
387}
388
389//________________________________________________________________________________
390std::vector<std::pair<double, double> >
392{
393 // List the validity bounds relevant to this container.
394
395 // ensure that the variable types have been computed properly
396 if (m_variables.size() == 0) computeVariableTypes();
397
398 std::vector<std::pair<double, double> > bounds;
399 for (unsigned int t = 0; t < m_lowerBounds.size() && t <= kAbsEta; ++t) {
400 bounds.push_back(std::make_pair(m_lowerBounds[t], m_upperBounds[t]));
401 }
402 return bounds;
403}
404
405
406//________________________________________________________________________________
407std::vector<unsigned int>
409{
410 // List the variable types used for this calibration object.
411 // The meaning of the types is encapsulated by the CalibrationParametrization enum.
412
413 // ensure that the variable types have been computed properly
414 if (m_variables.size() == 0) computeVariableTypes();
415
416 return m_variables;
417}
418
420// //
421// CalibrationDataHistogramContainer //
422// //
423/* Begin_Html
424<p> The CalibrationDataHistogramContainer class inherits from the CalibrationDataContainer
425 abstract class. It covers the cases where the relevant information is presented in
426 binned form.
427</p>
428<p> This class allows for the following features:
429<ul>
430 <li>Access to individual uncertainty contributions, in addition to total (or separate
431 statistical and systematic) uncertainties.</li>
432 <li>Access to correlations between calibration bins. Note that exploiting this
433 requires using the CalibrationDataEigenVariations class.</li>
434 <li>Histogram interpolation (note that this implementation is not complete; however it
435 should work at least for the most common implementation of 2D MC efficiencies. For
436 this case, interpolation has been demonstrated to be more accurate than
437 parametrisations).</li>
438 <li>Use with "continuous tagging" (in which the -binned- tag weight distribution is
439 considered in different kinematic bins) in addition to the more straightforward
440 consideration of the efficiency to pass a given tag weight cut.</li>
441</ul>
442</p>
443End_Html */
444// //
446
447#ifndef __CINT__
449#endif
450
451//________________________________________________________________________________
453 CalibrationDataContainer(name), m_interpolate(false)
454{
455 // default constructor.
456
457 // // Reset 'regular' bin ranges to a nonsensical value
458 // for (unsigned int t = 0; t < 3; ++t) {
459 // m_binmin[t] = m_binmax[t] = 0;
460 // m_noExtrapolation[t] = false;
461 // }
462
463 // Reset the validity bounds (including those for extrapolation uncertainties) to reflect 'no bounds'.
464 // They will be re-determined upon the first computation.
465
466 m_lowerBounds.clear();
467 m_lowerBounds.resize(maxParameters, -std::numeric_limits<double>::max());
468 m_lowerBounds[kPt] = m_lowerBounds[kAbsEta] = 0;
469 m_upperBounds.clear();
470 m_upperBounds.resize(maxParameters, std::numeric_limits<double>::max());
471
472 m_lowerBoundsExtrapolated.clear();
473 m_lowerBoundsExtrapolated.resize(maxParameters, -std::numeric_limits<double>::max());
474 m_lowerBoundsExtrapolated[kPt] = m_lowerBounds[kAbsEta] = 0;
475 m_upperBoundsExtrapolated.clear();
476 m_upperBoundsExtrapolated.resize(maxParameters, std::numeric_limits<double>::max());
477
478 // But by default, switch on the range checking
479 restrictToRange(true);
480}
481
482//________________________________________________________________________________
486
487
488//________________________________________________________________________________
489void
491{
492 // Compute the variable types for this container object, using the histogram axis labels.
493 // Valid axis labels can be found in the CalibrationDataContainer::typeFromString() method.
494 // Note that only the "result" histogram is inspected; it is assumed that all
495 // histograms provided use the same binning (a small exception is the "extrapolation"
496 // uncertainty histogram, which may have additional bins beyond the usual validity bounds).
497 //
498 // This function will be called upon first usage, and its results cached internally.
499 // It also calls checkBounds() to determine the validity bounds.
500
501 // cache pointer to central values histogram
502 if (! m_objResult) m_objResult = GetValue("result");
503
504 // histograms need a special treatment, as the coordinate titles are not actually stored
505 // with the title itself, but instead moved off to the axis titles...
506 const TH1* hobj = dynamic_cast<const TH1*>(m_objResult);
507 if (not hobj){
508 std::cerr << "in CalibrationDataHistogramContainer::computeVariableTypes(): dynamic_cast failed\n";
509 return;
510 }
511
512 int dims = hobj->GetDimension();
513 for (int dim = 0; dim < dims; ++dim) {
514 const TAxis* axis = 0;
515 switch (dim) {
516 case 0: axis = hobj->GetXaxis(); break;
517 case 1: axis = hobj->GetYaxis(); break;
518 default: axis = hobj->GetZaxis();
519 }
520 int vartype = typeFromString(axis->GetTitle());
521 if (vartype < 0) {
522 // Only flag the issue but otherwise take no action (assume non-argument use of a semicolon)
523 std::cerr << "in CalibrationDataHistogramContainer::computeVariableTypes(): cannot construct variable type from name "
524 << axis->GetTitle() << std::endl;
525 } else {
526 m_variables.push_back((unsigned int) vartype);
527 }
528 }
529
530 // After doing this, we should always have a non-null vector!
531 assert(m_variables.size() > 0);
532
533 // also compute the validity bounds for this calibration object
535}
536
537//________________________________________________________________________________
540 double& result, TObject* obj, bool extrapolate)
541{
542 // Retrieve the central value for the given input variables. There are cases where
543 // it may be useful to provide an alternative histogram rather than the original
544 // one; in such cases (notably used with eigenvector variations) it is possible to
545 // provide a pointer to this alternative histogram.
546 //
547 // x: input variables
548 // result: result
549 // obj: pointer to alternative results histogram
550 // extrapolate: set to true if bounds checking is to be carried out to looser
551 // validity bounds as relevant for extrapolation uncertainties
552 if (!obj) {
553 if (! m_objResult) {
554 m_objResult = GetValue("result");
555 }
556 obj = m_objResult;
557 }
558 TH1* hist = dynamic_cast<TH1*>(obj);
559 if (! hist) return Analysis::kError;
560
561 // select the relevant kinematic variables
562 CalibrationStatus status = computeVariables(x, extrapolate);
563 // find the relevant "global" bin.
564 // Note the limitation: at most three dimensions are supported.
565 // TH1::FindFixBin() will ignore the variables not needed.
566 // Note: FindFixBin() is only available in "recent" ROOT versions (FindBin() is appropriate for older versions)
567 // (otherwise we need to rely on the ResetBit(TH1::kCanRebin) method having been used)
568 if (m_interpolate) {
570 } else {
571 Int_t bin = hist->FindFixBin(m_vars[0], m_vars[1], m_vars[2]);
572 result = hist->GetBinContent(bin);
573 }
574
575 return status;
576}
577
578// statistical uncertainty retrieval (special since it is stored with the result itself)
579
580//________________________________________________________________________________
583 double& result)
584{
585 // Retrieve the statistical uncertainty for the given input variables.
586 //
587 // x: input variables
588 // result: result
589
590 if (! m_objResult) {
591 m_objResult = GetValue("result");
592 }
593 TH1* hist = dynamic_cast<TH1*>(m_objResult);
594 if (! hist) {
595 std::cout << " getStatUncertainty error: no (valid) central values object!" << std::endl;
596 return Analysis::kError;
597 }
598
599 // select the relevant kinematic variables
601 // find the relevant "global" bin.
602 // Note the limitation: at most three dimensions are supported.
603 // TH1::FindFixBin() will ignore the variables not needed.
604 // Note: FindFixBin() is only available in "recent" ROOT versions (FindBin() is appropriate for older versions)
605 // (otherwise we need to rely on the ResetBit(TH1::kCanRebin) method having been used)
606 if (m_interpolate) {
607 // interpolating the uncertainties doesn't seem very sensible..
609 } else {
610 Int_t bin = hist->FindFixBin(m_vars[0], m_vars[1], m_vars[2]);
611 // Int_t bin = findBin(hist, false);
612 result = hist->GetBinError(bin);
613 }
614
615 return status;
616}
617
618// general uncertainty retrieval
619
620//________________________________________________________________________________
624 UncertaintyResult& result, TObject* obj)
625{
626 // Retrieve the uncertainty for the given input variables.
627 //
628 // unc: keyword indicating requested source of uncertainty. This should
629 // correspond to one of the histograms added explicitly as a systematic
630 // uncertainty or the keyword "statistics" (statistical uncertainties are
631 // accessed differently, see method getStatUncertainty()).
632 // x: input variables
633 // result: result
634 // obj: pointer to alternative or cached histogram
635
636 if (unc == "statistics") {
637 // treat statistical uncertainties separately (they are stored with the actual result)
638 double res;
640 if (code == Analysis::kError) return code;
641 result.first = res;
642 result.second = -res;
643 return code;
644 }
645
646 if (!obj) obj = GetValue(unc.c_str());
647 TH1* hist = dynamic_cast<TH1*>(obj);
648 if (! hist) return Analysis::kError;
649
650 // select the relevant kinematic variables
651 CalibrationStatus status = computeVariables(x, (unc == "extrapolation") );
652
653 if (m_interpolate) {
654 result.first = getInterpolatedResult(hist);
655 // symmetrise the uncertainty (as there is no code to interpolate the bin errors)
656 result.second = -result.first;
657 } else {
658 // TH1::FindFixBin() will ignore the variables not needed.
659 // Note: FindFixBin() is only available in "recent" ROOT versions (FindBin() is appropriate for older versions)
660 // (otherwise we need to rely on the ResetBit(TH1::kCanRebin) method having been used)
661 Int_t bin = hist->FindFixBin(m_vars[0], m_vars[1], m_vars[2]);
662 // the "first" and "second" entries are filled with the
663 // "positive" and "negative" uncertainties, respectively.
664 result.first = hist->GetBinContent(bin);
665 result.second = hist->GetBinError(bin);
666 }
667
668 return status;
669}
670
671//________________________________________________________________________________
672void
674{
675 // Determine the bounds of validity for this calibration object. If an "extrapolation"
676 // uncertainty histogram exists, it is used to determine the (typically) looser bounds
677 // of validity appropriate for extrapolation uncertainties.
678
679 const TH1* hist = dynamic_cast<const TH1*>(m_objResult);
680 if (!hist) {
681 std::cerr << "in CalibrationDataHistogramContainer::checkBounds(): object type does not derive from TH1" << std::endl;
682 return;
683 } else if (hist->GetDimension() != int(m_variables.size())) {
684 std::cerr << "in CalibrationDataHistogramContainer::checkBounds(): given number of variable types ("
685 << m_variables.size() << ") doesn't match histogram dimension ("
686 << hist->GetDimension() << ")!" << std::endl;
687 return;
688 }
689 // if an extrapolation uncertainty histogram was provided, use this to determine a second set of validity bounds
690 const TH1* hExtrapolate = dynamic_cast<const TH1*>(GetValue("extrapolation"));
691 for (unsigned int t = 0; int(t) < hist->GetDimension(); ++t) {
692 const TAxis* axis; const TAxis* axis2 = 0;
693 switch (t) {
694 case 0: axis = hist->GetXaxis(); if (hExtrapolate) axis2 = hExtrapolate->GetXaxis(); break;
695 case 1: axis = hist->GetYaxis(); if (hExtrapolate) axis2 = hExtrapolate->GetYaxis(); break;
696 default: axis = hist->GetZaxis(); if (hExtrapolate) axis2 = hExtrapolate->GetZaxis();
697 }
698
699 // for (unsigned int t = 0; t < m_variables.size(); ++t) {
700 // if (m_variables[t] > m_upperBounds.size()) {
701 // std::cerr << "in CalibrationDataHistogramContainer::checkBounds(): variable " << t << "type ("
702 // << m_variables[t] << "exceeds maximum type number (" << m_upperBounds.size() << ")!"
703 // << std::endl;
704 // return;
705 // }
706 // }
707 m_upperBounds[m_variables[t]] = axis->GetXmax();
708 m_lowerBounds[m_variables[t]] = axis->GetXmin();
709 m_upperBoundsExtrapolated[m_variables[t]] = (axis2) ? axis2->GetXmax() : m_upperBounds[m_variables[t]];
710 m_lowerBoundsExtrapolated[m_variables[t]] = (axis2) ? axis2->GetXmin() : m_lowerBounds[m_variables[t]];
711 // std::cout << "debug: min = " << m_lowerBounds[m_variables[t]] << ", max = " << m_upperBounds[m_variables[t]]
712 // << ", extrap min = " << m_lowerBoundsExtrapolated[m_variables[t]] << ", extrap max = "
713 // << m_upperBoundsExtrapolated[m_variables[t]] << std::endl;
714 }
715}
716
717//________________________________________________________________________________
718bool
720{
721 // Indicate whether the given uncertainty is correlated from bin to bin or not
722 // (note that this function is to be used only for _systematic_ uncertainties)
723 return (m_uncorrelatedSyst.FindObject(unc.c_str()) == 0);
724}
725
726//________________________________________________________________________________
727void
729{
730 // Indicate that the given uncertainty is to be treated uncorrelated from bin to bin
731 // (the default is for all systematic uncertainties to be treated as correlated).
732 // This method is not normall intended to be used during physics analysis; this
733 // information is written to and read back from the calibration file.
734
735 m_uncorrelatedSyst.Add(new TObjString(unc.c_str()));
736}
737
738//________________________________________________________________________________
739void
741{
742 // Indicate whether results are to be interpolated between bins or not
743 // (this feature is thought to be useful mostly for MC efficiencies).
744 // The default is not to use any interpolation.
745
746 m_interpolate = doInterpolate;
747}
748
749//________________________________________________________________________________
750bool
752{
753 // Indicate whether histogram interpolation is used or not.
754
755 return m_interpolate;
756}
757
758//________________________________________________________________________________
759double
761{
762 // Small utility function (intended for internal use only) for the retrieval of interpolated results
763
764 switch (hist->GetDimension()) {
765 case 3:
766 return hist->Interpolate(m_vars[0], m_vars[1], m_vars[2]);
767 case 2:
768 return hist->Interpolate(m_vars[0], m_vars[1]);
769 case 1:
770 default:
771 return hist->Interpolate(m_vars[0]);
772 }
773}
774
775//________________________________________________________________________________
776double
778{
779 TAxis* xAxis = hist->GetXaxis();
780 TAxis* yAxis = 0; TAxis* zAxis = 0;
781 Double_t x0,x1,y0,y1;
782
783 Int_t ndim = hist->GetDimension();
784 if (ndim == 1) {
785 // Code copied from TH1::Interpolate()
786
787 Int_t xbin = hist->FindBin(m_vars[0]);
788
789 if(m_vars[0] <= hist->GetBinCenter(1)) {
790 return hist->GetBinError(1);
791 } else if(m_vars[0] >= hist->GetBinCenter(hist->GetNbinsX())) {
792 return hist->GetBinError(hist->GetNbinsX());
793 }
794
795 if(m_vars[0] <= hist->GetBinCenter(xbin)) {
796 y0 = hist->GetBinError(xbin-1);
797 x0 = hist->GetBinCenter(xbin-1);
798 y1 = hist->GetBinError(xbin);
799 x1 = hist->GetBinCenter(xbin);
800 } else {
801 y0 = hist->GetBinError(xbin);
802 x0 = hist->GetBinCenter(xbin);
803 y1 = hist->GetBinError(xbin+1);
804 x1 = hist->GetBinCenter(xbin+1);
805 }
806 return y0 + (m_vars[0]-x0)*((y1-y0)/(x1-x0));
807
808 } else if (ndim == 2) {
809
810 // Code copied from TH2::Interpolate()
811
812 Double_t f=0;
813 x1 = y1 = 0;
814 Double_t x2=0,y2=0;
815 Double_t dx,dy;
816 yAxis = hist->GetYaxis();
817 Int_t bin_x = xAxis->FindBin(m_vars[0]);
818 Int_t bin_y = yAxis->FindBin(m_vars[1]);
819 if (bin_x<1 || bin_x>hist->GetNbinsX() || bin_y<1 || bin_y>hist->GetNbinsY()) {
820 Error("Interpolate","Cannot interpolate outside histogram domain.");
821 return 0;
822 }
823 // Int_t quadrant = 0; // CCW from UR 1,2,3,4
824 // which quadrant of the bin (bin_P) are we in?
825 dx = xAxis->GetBinUpEdge(bin_x)-m_vars[0];
826 dy = yAxis->GetBinUpEdge(bin_y)-m_vars[1];
827 if (dx<=xAxis->GetBinWidth(bin_x)/2 && dy<=yAxis->GetBinWidth(bin_y)/2) {
828 // quadrant = 1; // upper right
829 x1 = xAxis->GetBinCenter(bin_x);
830 y1 = yAxis->GetBinCenter(bin_y);
831 x2 = xAxis->GetBinCenter(bin_x+1);
832 y2 = yAxis->GetBinCenter(bin_y+1);
833 } else if (dx>xAxis->GetBinWidth(bin_x)/2 && dy<=yAxis->GetBinWidth(bin_y)/2) {
834 // quadrant = 2; // upper left
835 x1 = xAxis->GetBinCenter(bin_x-1);
836 y1 = yAxis->GetBinCenter(bin_y);
837 x2 = xAxis->GetBinCenter(bin_x);
838 y2 = yAxis->GetBinCenter(bin_y+1);
839 } else if (dx>xAxis->GetBinWidth(bin_x)/2 && dy>yAxis->GetBinWidth(bin_y)/2) {
840 // quadrant = 3; // lower left
841 x1 = xAxis->GetBinCenter(bin_x-1);
842 y1 = yAxis->GetBinCenter(bin_y-1);
843 x2 = xAxis->GetBinCenter(bin_x);
844 y2 = yAxis->GetBinCenter(bin_y);
845 } else {
846 // quadrant = 4; // lower right
847 x1 = xAxis->GetBinCenter(bin_x);
848 y1 = yAxis->GetBinCenter(bin_y-1);
849 x2 = xAxis->GetBinCenter(bin_x+1);
850 y2 = yAxis->GetBinCenter(bin_y);
851 }
852 Int_t bin_x1 = xAxis->FindBin(x1);
853 if(bin_x1<1) bin_x1=1;
854 Int_t bin_x2 = xAxis->FindBin(x2);
855 if(bin_x2>hist->GetNbinsX()) bin_x2=hist->GetNbinsX();
856 Int_t bin_y1 = yAxis->FindBin(y1);
857 if(bin_y1<1) bin_y1=1;
858 Int_t bin_y2 = yAxis->FindBin(y2);
859 if(bin_y2>hist->GetNbinsY()) bin_y2=hist->GetNbinsY();
860 Int_t bin_q22 = hist->GetBin(bin_x2,bin_y2);
861 Int_t bin_q12 = hist->GetBin(bin_x1,bin_y2);
862 Int_t bin_q11 = hist->GetBin(bin_x1,bin_y1);
863 Int_t bin_q21 = hist->GetBin(bin_x2,bin_y1);
864 Double_t q11 = hist->GetBinError(bin_q11);
865 Double_t q12 = hist->GetBinError(bin_q12);
866 Double_t q21 = hist->GetBinError(bin_q21);
867 Double_t q22 = hist->GetBinError(bin_q22);
868 Double_t d = 1.0*(x2-x1)*(y2-y1);
869 f = 1.0*q11/d*(x2-m_vars[0])*(y2-m_vars[1])
870 + 1.0*q21/d*(m_vars[0]-x1)*(y2-m_vars[1])
871 + 1.0*q12/d*(x2-m_vars[0])*(m_vars[1]-y1)
872 + 1.0*q22/d*(m_vars[0]-x1)*(m_vars[1]-y1);
873 return f;
874
875 } else {
876
877 // Copied from TH3::Interpolate()
878
879 yAxis = hist->GetYaxis();
880 zAxis = hist->GetZaxis();
881
882 Int_t ubx = xAxis->FindBin(m_vars[0]);
883 if ( m_vars[0] < xAxis->GetBinCenter(ubx) ) ubx -= 1;
884 Int_t obx = ubx + 1;
885
886 Int_t uby = yAxis->FindBin(m_vars[1]);
887 if ( m_vars[1] < yAxis->GetBinCenter(uby) ) uby -= 1;
888 Int_t oby = uby + 1;
889
890 Int_t ubz = zAxis->FindBin(m_vars[2]);
891 if ( m_vars[2] < zAxis->GetBinCenter(ubz) ) ubz -= 1;
892 Int_t obz = ubz + 1;
893
894
895 // if ( IsBinUnderflow(GetBin(ubx, uby, ubz)) ||
896 // IsBinOverflow (GetBin(obx, oby, obz)) ) {
897 if (ubx <=0 || uby <=0 || ubz <= 0 ||
898 obx > xAxis->GetNbins() || oby > yAxis->GetNbins() || obz > zAxis->GetNbins() ) {
899 }
900
901 Double_t xw = xAxis->GetBinCenter(obx) - xAxis->GetBinCenter(ubx);
902 Double_t yw = yAxis->GetBinCenter(oby) - yAxis->GetBinCenter(uby);
903 Double_t zw = zAxis->GetBinCenter(obz) - zAxis->GetBinCenter(ubz);
904
905 Double_t xd = (m_vars[0] - xAxis->GetBinCenter(ubx)) / xw;
906 Double_t yd = (m_vars[1] - yAxis->GetBinCenter(uby)) / yw;
907 Double_t zd = (m_vars[2] - zAxis->GetBinCenter(ubz)) / zw;
908
909
910 Double_t v[] = { hist->GetBinError( ubx, uby, ubz ), hist->GetBinError( ubx, uby, obz ),
911 hist->GetBinError( ubx, oby, ubz ), hist->GetBinError( ubx, oby, obz ),
912 hist->GetBinError( obx, uby, ubz ), hist->GetBinError( obx, uby, obz ),
913 hist->GetBinError( obx, oby, ubz ), hist->GetBinError( obx, oby, obz ) };
914
915
916 Double_t i1 = v[0] * (1 - zd) + v[1] * zd;
917 Double_t i2 = v[2] * (1 - zd) + v[3] * zd;
918 Double_t j1 = v[4] * (1 - zd) + v[5] * zd;
919 Double_t j2 = v[6] * (1 - zd) + v[7] * zd;
920
921
922 Double_t w1 = i1 * (1 - yd) + i2 * yd;
923 Double_t w2 = j1 * (1 - yd) + j2 * yd;
924
925
926 Double_t result = w1 * (1 - xd) + w2 * xd;
927
928 return result;
929 };
930}
931
932
933//________________________________________________________________________________
934int
936{
937 // Test whether this calibration object is one for "continuous" calibration
938 // (this has some subtle consequences for the treatment of bin-to-bin correlations).
939 // The return value will be -1 in case this is not a "continuous" calibration object,
940 // and the axis number (0 for X, 1 for Y, 2 for Z) otherwise.
941
942 // Ensure that the variable types have been computed at this point
943 if (m_variables.size() == 0) computeVariableTypes();
944
945 for (unsigned int type = 0; type < m_variables.size(); ++type)
946 if (m_variables[type] == kTagWeight) return int(type);
947 return -1;
948}
949
950//________________________________________________________________________________
951std::vector<double>
953{
954 // Retrieve the bin boundaries for the specified variable type (which should be a CalibrationParametrization enum).
955 // An empty vector will be returned if the specified variable is not actually used.
956
957 // Ensure that the variable types have been computed at this point
958 if (m_variables.size() == 0) computeVariableTypes();
959
960 // Check whether the variable type is actually being used
961 std::vector<double> boundaries;
962 if (std::find(m_variables.begin(), m_variables.end(), vartype) == m_variables.end()) return boundaries;
963
964 // use cached information if available
965 std::map<unsigned int, std::vector<double> >::iterator it = m_binBoundaries.find(vartype);
966 if (it != m_binBoundaries.end()) return it->second;
967
968 // Retrieve the appropriate histogram axis
969 if (! m_objResult) m_objResult = GetValue("result");
970 const TH1* hobj = dynamic_cast<const TH1*>(m_objResult);
971 if (!hobj) return boundaries;
972 const TAxis* axis = 0;
973 if (m_variables[0] == vartype) axis = hobj->GetXaxis();
974 else if (m_variables[1] == vartype) axis = hobj->GetYaxis();
975 else axis = hobj->GetZaxis();
976
977 // Retrieve the actual bin boundaries
978 const TArrayD* bins = axis->GetXbins(); int nb = bins->GetSize();
979 for (int b = 0; b < nb; ++b) boundaries.push_back(bins->At(b));
980
981 m_binBoundaries[vartype] = boundaries;
982 return boundaries;
983}
984
985//________________________________________________________________________________
986int
988{
989 TObject* obj = GetValue("ReducedSets");
990 if (! obj) return -1;
991 TVectorT<double>* v = dynamic_cast<TVectorT<double>* >(obj);
992 if (! (v && v->GetNoElements() > int(choice)) ) return -1;
993 return int((*v)[choice]);
994}
995
997// //
998// CalibrationDataMappedHistogramContainer //
999// //
1000// The CalibrationDataMappedHistogramContainer class inherits from the //
1001// CalibrationDataHistogramContainer class. It covers the special case (for at least two //
1002// dimensions) where the calibration is not done in a rectangular grid as would be implied //
1003// by the use of a TH2 or TH3. Instead, the class implements a mapping from a set of //
1004// general bins to bins on a given TH2 or TH3 axis. This generality implies that this class //
1005// in principle could be used also for the storage of higher-dimensional results. The only //
1006// assumptions made are that //
1007// - all bins have the same dimensions //
1008// - and the bins cover the 'mapped' dimensions completely, without any overlaps //
1009// Necessarily, the added flexibility makes access slower (even if caching of the mapped //
1010// bin is used). //
1011// //
1013
1014#ifndef __CINT__
1016#endif
1017
1018//________________________________________________________________________________
1020 CalibrationDataHistogramContainer(name), m_beginMapped(0),m_lastBin(0)
1021{
1022}
1023
1024//________________________________________________________________________________
1028
1029//________________________________________________________________________________
1030void
1032{
1033 // Compute the variable types for this container object.
1034 // The computation differs from that used for the parent CalibrationDataHistogramContainer
1035 // class, as also the 'mapped' variables (the variables that are mapped onto a single histogram
1036 // axis) need to be accounted for properly. This is handled as a special case.
1037
1038 // cache pointer to central values histogram
1039 if (! m_objResult) m_objResult = GetValue("result");
1040
1041 // histograms need a special treatment, as the coordinate titles are not actually stored
1042 // with the title itself, but instead moved off to the axis titles...
1043 const TH1* hobj = dynamic_cast<const TH1*>(m_objResult);
1044 if (not hobj){
1045 std::cerr << "in CalibrationDataMappedHistogramContainer::computeVariableTypes(): dynamic cast failed\n";
1046 return;
1047 }
1048
1049 int dims = hobj->GetDimension();
1050 for (int dim = 0; dim < dims; ++dim) {
1051 const TAxis* axis = 0;
1052 switch (dim) {
1053 case 0: axis = hobj->GetXaxis(); break;
1054 case 1: axis = hobj->GetYaxis(); break;
1055 default: axis = hobj->GetZaxis();
1056 }
1057 std::string var(axis->GetTitle());
1058 if (var == "mapped") {
1059 // Special case: mapped variables, so make sure to specify the original variables (not the mapped ones).
1060 // Note that the code here assumes that the mapping is identical for all objects..
1061 for (unsigned int m = 0; m < m_mapped.size(); ++m) {
1062 int vartype = typeFromString(m_mapped[m]);
1063 // this check should never fail; therefore, bail out if this does happen
1064 assert (! (vartype < 0));
1065 m_variables.push_back((unsigned int)vartype);
1066 }
1067 // In this case, also flag _where_ in the resulting list of variables the mapping starts
1068 m_beginMapped = dim;
1069 } else {
1070 int vartype = typeFromString(var);
1071 if (vartype < 0) {
1072 // Only flag the issue but otherwise take no action (assume non-argument use of a semicolon)
1073 std::cerr << "in CalibrationDataMappedHistogramContainer::computeVariableTypes(): cannot construct variable type from name "
1074 << var << std::endl;
1075 } else {
1076 m_variables.push_back((unsigned int)vartype);
1077 }
1078 }
1079 }
1080
1081 // After doing this, we should always have a non-null vector!
1082 assert(m_variables.size() > 0);
1083
1084 // Also compute the validity bounds for this calibration object
1086}
1087
1088
1089//________________________________________________________________________________
1090void
1092{
1093 // Check the bounds of validity for this calibration object.
1094 // See the CalibrationDataHistogramContainer::checkBounds() method. The difference is
1095 // that the 'mapped' dimensions need to be handled separately (this is carried out by
1096 // looping over the mapped bins and inspecting each bin's validity bounds individually).
1097 // Note that extrapolation uncertainties are not covered at this point.
1098
1099 const TH1* hist = dynamic_cast<const TH1*>(m_objResult);
1100 if (!hist) {
1101 std::cerr << "in CalibrationDataHistogramContainer::checkBounds(): object type does not derive from TH1" << std::endl;
1102 return;
1103 } else if (hist->GetDimension() + int(m_mapped.size()) - 1 != int(m_variables.size())) {
1104 std::cerr << "in CalibrationDataMappedHistogramContainer::checkBounds(): given number of variable types ("
1105 << m_variables.size() << ") doesn't match (mapped) histogram dimension ("
1106 << hist->GetDimension() + m_mapped.size() - 1 << ")!" << std::endl;
1107 return;
1108 }
1109
1110 // Carry out the only cross-check that's possible for the binning: check that the dimensionality
1111 // for all bins matches the number of variables specified for the mapping
1112 for (unsigned int bin = 0; bin < m_bins.size(); ++bin)
1113 assert(m_bins[bin].getDimension() == m_mapped.size());
1114
1115 for (unsigned int t = 0, t2 = 0; int(t) < hist->GetDimension(); ++t) {
1116 const TAxis* axis = 0;
1117 switch (t) {
1118 case 0: axis = hist->GetXaxis(); break;
1119 case 1: axis = hist->GetYaxis(); break;
1120 default: axis = hist->GetZaxis();
1121 }
1122
1123 // Special case for the mapped dimension: here the only thing that can be done is to
1124 // cycle through all Bins and inspect the boundaries of each bin manually.
1125 if (t == m_beginMapped) {
1126 for (unsigned int mapped = 0; mapped < m_mapped.size(); ++mapped) {
1127 for (unsigned int bin = 0; bin < m_bins.size(); ++bin) {
1128 double amax = m_bins[bin].getUpperBound(mapped), amin = m_bins[bin].getLowerBound(mapped);
1129 if (bin == 0 || amax > m_upperBounds[m_variables[t2]]) m_upperBounds[m_variables[t2]] = amax;
1130 if (bin == 0 || amin < m_lowerBounds[m_variables[t2]]) m_lowerBounds[m_variables[t2]] = amin;
1131 }
1132 ++t2;
1133 }
1134 } else {
1135 // for (unsigned int t = 0; t < m_variables.size(); ++t) {
1136 // if (m_variables[t] > m_upperBounds.size()) {
1137 // std::cerr << "in CalibrationDataHistogramContainer::checkBounds(): variable " << t << "type ("
1138 // << m_variables[t] << "exceeds maximum type number (" << m_upperBounds.size() << ")!"
1139 // << std::endl;
1140 // return;
1141 // }
1142 // }
1143 double amax = axis->GetXmax(), amin = axis->GetXmin();
1144 if (amax < m_upperBounds[m_variables[t2]]) m_upperBounds[m_variables[t2]] = amax;
1145 if (amin > m_lowerBounds[m_variables[t2]]) m_lowerBounds[m_variables[t2]] = amin;
1146 ++t2;
1147 }
1148 }
1149}
1150
1151//________________________________________________________________________________
1154 double& result, TObject* obj, bool /* extrapolate */)
1155{
1156 // Retrieve the central value for the given input variables. There are cases where
1157 // it may be useful to provide an alternative histogram rather than the original
1158 // one; in such cases (notably used with eigenvector variations) it is possible to
1159 // provide a pointer to this alternative histogram.
1160 // The method here differs from CalibrationDataHistogramContainer::getResult()
1161 // since histogram interpolation does not make sense for mapped bins.
1162 //
1163 // x: input variables
1164 // result: result
1165 // obj: pointer to alternative results histogram
1166
1167 if (!obj) {
1168 if (! m_objResult) {
1169 m_objResult = GetValue("result");
1170 }
1171 obj = m_objResult;
1172 }
1173 TH1* hist = dynamic_cast<TH1*>(obj);
1174 if (! hist) return Analysis::kError;
1175
1176 // select the relevant kinematic variables
1178 // find the relevant "global" bin and retrieve its contents
1179 result = hist->GetBinContent(findBin());
1180
1181 return status;
1182}
1183
1184//________________________________________________________________________________
1187 double& result)
1188{
1189 // Retrieve the statistical uncertainty for the given input variables.
1190 //
1191 // x: input variables
1192 // result: result
1193
1194 if (! m_objResult) {
1195 m_objResult = GetValue("result");
1196 }
1197 TH1* hist = dynamic_cast<TH1*>(m_objResult);
1198 if (! hist) return Analysis::kError;
1199
1200 // select the relevant kinematic variables
1202 // find the relevant "global" bin and retrieve its contents
1203 result = hist->GetBinError(findBin());
1204
1205 return status;
1206}
1207
1208//________________________________________________________________________________
1212 UncertaintyResult& result, TObject* obj)
1213{
1214 // Retrieve the uncertainty for the given input variables.
1215 //
1216 // unc: keyword indicating requested source of uncertainty. This should
1217 // correspond to one of the histograms added explicitly as a systematic
1218 // uncertainty or the keyword "statistics" (statistical uncertainties are
1219 // accessed differently, see method getStatUncertainty()).
1220 // x: input variables
1221 // result: result
1222 // obj: pointer to alternative or cached histogram
1223
1224 // treat statistical uncertainties separately (they are stored with the actual result)
1225 if (unc == "statistics") {
1226 double res;
1228 if (code == Analysis::kError) return code;
1229 result.first = res;
1230 result.second = -res;
1231 return code;
1232 }
1233
1234 if (!obj) obj = GetValue(unc.c_str());
1235 TH1* hist = dynamic_cast<TH1*>(obj);
1236 if (! hist) return Analysis::kError;
1237
1238 // select the relevant kinematic variables
1240 // find the relevant "global" bin and retrieve its contents
1241 Int_t bin = findBin();
1242 result.first = hist->GetBinError(bin);
1243 result.second = hist->GetBinError(bin);
1244
1245 return status;
1246}
1247
1248//________________________________________________________________________________
1249int
1251{
1252 // Test whether this calibration object is one for "continuous" calibration
1253 // (this has some subtle consequences for the treatment of bin-to-bin correlations).
1254 // The return value will be -1 in case this is not a "continuous" calibration object,
1255 // and the axis number (0 for X, 1 for Y, 2 for Z) otherwise.
1256
1257 for (unsigned int type = 0; type < m_variables.size(); ++type)
1258 if (m_variables[type] == kTagWeight) {
1259 int hist_type = int(type);
1260 return (hist_type > int(m_beginMapped)) ? hist_type - m_mapped.size() + 1 : hist_type;
1261 }
1262 return -1;
1263}
1264
1265//________________________________________________________________________________
1266void
1267CalibrationDataMappedHistogramContainer::setMappedVariables(const std::vector<std::string>& variables)
1268{
1269 // Set (by hand) the variables that will be mapped onto a single histogram axis
1270
1271 m_mapped = variables;
1272}
1273
1274//________________________________________________________________________________
1275const std::vector<std::string>&
1277{
1278 // List which variables get mapped onto a single histogram axis
1279
1280 return m_mapped;
1281}
1282
1283//________________________________________________________________________________
1284unsigned int
1286{
1287 // Add a bin to the present list
1288 // Note the absence of a -1 in the return value: this is because ROOT's histogram axes start counting from 1
1289
1290 m_bins.push_back(bin);
1291 return m_bins.size();
1292}
1293
1294//________________________________________________________________________________
1295unsigned int
1297{
1298 // Return the number of mapped bins
1299 // Note the absence of a -1 in the return value: this is because ROOT's histogram axes start counting from 1
1300
1301 return m_bins.size();
1302}
1303
1304//________________________________________________________________________________
1305Int_t
1307{
1308 // Find the mapped bin corresponding to the variables used for the mapping
1309
1310 if (m_bins[m_lastBin].contains(x)) return m_lastBin + 1; // First check quickly whether the last bin (cached) matches
1311
1312 // Search the whole array for a match
1313 for (unsigned int bin = 0; bin < m_bins.size(); ++bin)
1314 if (m_bins[bin].contains(x)) {
1315 m_lastBin = bin;
1316 return m_lastBin + 1;
1317 }
1318 std::cerr << "CalibrationDataMappedHistogramContainer::findMappedBin(): unable to find bin for mapping variables:";
1319 for (unsigned int d = 0; d < m_mapped.size(); ++d) std::cerr << "\t" << x[d];
1320 std::cerr << std::endl;
1321 // -1 means invalid..
1322 return -1;
1323}
1324
1325//________________________________________________________________________________
1326Int_t
1328{
1329 // Find the bin corresponding to the computed variables (the computation is assumed to have just
1330 // taken place and resulted in the m_vars array having been filled appropriately)
1331
1332 Int_t mapped[3] = {0};
1333 const TH1* hist = dynamic_cast<const TH1*>(m_objResult);
1334 if (not hist){
1335 std::cerr << "CalibrationDataMappedHistogramContainer::findBin(): dynamic cast failed\n";
1336 return 0;
1337 }
1338 Int_t ndim = hist->GetDimension();
1339 // Push the mapped variables onto an array.
1340 // Since we derive from TH1 this need never be more than 3 elements long.
1341 for (unsigned int dim = 0; dim < (unsigned int) ndim; ++dim) {
1342 if (dim == m_beginMapped) {
1343 if ((mapped[dim] = findMappedBin(&(m_vars[dim]))) < 0) return -1;
1344 } else {
1345 const TAxis* axis = 0;
1346 switch (dim) {
1347 case 0: axis = hist->GetXaxis(); break;
1348 case 1: axis = hist->GetYaxis(); break;
1349 default: axis = hist->GetZaxis();
1350 }
1351 mapped[dim] = axis->FindFixBin((dim < m_beginMapped) ? m_vars[dim] : m_vars[dim+m_mapped.size()-1]);
1352 }
1353 }
1354 return hist->GetBin(mapped[0], mapped[1], mapped[2]);
1355}
1356
1357//________________________________________________________________________________
1358std::vector<double>
1360{
1361 // Retrieve the bin boundaries for the specified variable type (which should be a CalibrationParametrization enum).
1362 // An empty vector will be returned if the specified variable is not actually used.
1363
1364 // Ensure that the variable types have been computed at this point
1365 if (m_variables.size() == 0) computeVariableTypes();
1366
1367 // use cached information if available
1368 std::map<unsigned int, std::vector<double> >::iterator it = m_binBoundaries.find(vartype);
1369 if (it != m_binBoundaries.end()) return it->second;
1370
1371 // Check whether the variable type is actually being used
1372 std::vector<double> boundaries;
1373 int var = -1;
1374 for (unsigned int v = 0; v < m_variables.size(); ++v)
1375 if (m_variables[v] == vartype) var = (int) v;
1376 if (var == -1) return boundaries;
1377
1378 // Retrieve the appropriate histogram axis
1379 if (! m_objResult) m_objResult = GetValue("result");
1380 const TH1* hobj = dynamic_cast<const TH1*>(m_objResult);
1381
1382 if (var >= int(m_beginMapped) && var < int(m_beginMapped + m_mapped.size())) {
1383 // Special case of a mapped variable. In this case, test all Bins for their boundaries
1384 unsigned int mapped = var - m_beginMapped;
1385 for (unsigned int bin = 0; bin < m_bins.size(); ++bin) {
1386 double binBoundaries[2];
1387 binBoundaries[0] = m_bins[bin].getLowerBound(mapped);
1388 binBoundaries[1] = m_bins[bin].getUpperBound(mapped);
1389 // Insert the bin boundaries, if not already present (the test is whether the relative difference
1390 // is smaller than 1e-8)
1391 if (boundaries.size() == 0) {
1392 boundaries.push_back(binBoundaries[0]); boundaries.push_back(binBoundaries[1]);
1393 } else {
1394 for (unsigned int ib = 0; ib < 2; ++ib) {
1395 double newvalue = binBoundaries[ib];
1396 bool done = false;
1397 for (std::vector<double>::iterator it = boundaries.begin(); it != boundaries.end(); ++it) {
1398 if (isNearlyEqual(newvalue, *it)) {
1399 // consider this value to have been inserted already
1400 done = true; break;
1401 } else if (newvalue < *it) {
1402 // the interesting case: insert the new value
1403 boundaries.insert(it, newvalue);
1404 done = true; break;
1405 }
1406 }
1407 // last case: new value is larger than any of the values in the array so far
1408 if (! done) boundaries.push_back(newvalue);
1409 }
1410 }
1411 }
1412 } else {
1413 // Normal case:
1414 unsigned int dim = (var < int(m_beginMapped)) ? var : var + 1 - m_mapped.size();
1415 const TAxis* axis = 0;
1416 switch (dim) {
1417 case 0: axis = hobj->GetXaxis(); break;
1418 case 1: axis = hobj->GetYaxis(); break;
1419 default: axis = hobj->GetZaxis();
1420 }
1421 // Retrieve the actual bin boundaries
1422 const TArrayD* bins = axis->GetXbins();
1423 if (!bins){
1424 return boundaries;
1425 }
1426 int nb = bins->GetSize();
1427 for (int b = 0; b < nb; ++b) boundaries.push_back(bins->At(b));
1428 }
1429
1430 m_binBoundaries[vartype] = boundaries;
1431 return boundaries;
1432}
1433
1434// Bin helper class methods
1435
1437// //
1438// CalibrationDataMappedHistogramContainer::Bin //
1439// //
1440// This is a small nested class collecting 'mapped' bin information. Its purpose is mostly //
1441// to store binning information in a structured way. The only relevant event-level method //
1442// is the contains() method. //
1443// //
1445
1446#ifndef __CINT__
1448#endif
1449
1450//________________________________________________________________________________
1452 m_dimension(0), m_low(0), m_up(0)
1453{
1454 // Default constructor (for persistency)
1455}
1456
1457//________________________________________________________________________________
1458CalibrationDataMappedHistogramContainer::Bin::Bin(unsigned int dimension, const double* low, const double* up):
1459 m_dimension(dimension)
1460{
1461 // Normal constructor, containing a full specification of the bin boundaries
1462
1463 m_up = new double[dimension];
1464 m_low = new double[dimension];
1465 for (unsigned int dim = 0; dim < dimension; ++dim) {
1466 m_up[dim] = up[dim];
1467 m_low[dim] = low[dim];
1468 }
1469}
1470
1471//________________________________________________________________________________
1473 m_dimension(other.m_dimension)
1474{
1475 m_up = new double[m_dimension];
1476 m_low = new double[m_dimension];
1477 for (unsigned int dim = 0; dim < m_dimension; ++dim) {
1478 m_up[dim] = other.m_up[dim];
1479 m_low[dim] = other.m_low[dim];
1480 }
1481}
1482
1483//________________________________________________________________________________
1486{
1487 if (this != &other) {
1488 m_dimension = other.m_dimension;
1489 delete[] m_up;
1490 delete[] m_low;
1491 m_up = new double[m_dimension];
1492 m_low = new double[m_dimension];
1493 for (unsigned int dim = 0; dim < m_dimension; ++dim) {
1494 m_up[dim] = other.m_up[dim];
1495 m_low[dim] = other.m_low[dim];
1496 }
1497 }
1498 return *this;
1499}
1500
1501//________________________________________________________________________________
1503{
1504 delete[] m_up;
1505 delete[] m_low;
1506}
1507
1508//________________________________________________________________________________
1509bool
1511{
1512 // Determine whether the given set of variables is within the bin boundaries.
1513
1514 for (unsigned int dim = 0; dim < m_dimension; ++dim)
1515 if (x[dim] < m_low[dim] || x[dim] > m_up[dim]) return false;
1516 return true;
1517}
1518
1519//________________________________________________________________________________
1520double
1522{
1523 // Return the upper bound for the specified dimension
1524 return m_up[dim];
1525}
1526
1527//________________________________________________________________________________
1528double
1530{
1531 // Return the lower bound for the specified dimension
1532 return m_low[dim];
1533}
1534
1536// //
1537// CalibrationDataFunctionContainer //
1538// //
1539// The CalibrationDataFunctionContainer class inherits from the CalibrationDataContainer //
1540// abstract class. It covers the cases where the relevant information is presented in //
1541// parametrised form. //
1542// //
1544
1545#ifndef __CINT__
1547#endif
1548
1549//________________________________________________________________________________
1551 CalibrationDataContainer(name), m_objStatistics(0)
1552{
1553 // Default constructor
1554
1555 // Reset the validity bounds to reflect 'no bounds'.
1556 m_lowerBounds.clear();
1557 m_lowerBounds.resize(maxParameters, -std::numeric_limits<double>::max());
1558 m_lowerBounds[kPt] = m_lowerBounds[kAbsEta] = 0;
1559 m_upperBounds.clear();
1560 m_upperBounds.resize(maxParameters, std::numeric_limits<double>::max());
1561 // and do the same for the validity bounds associated with extrapolation uncertainties
1562 // (this should anyway not be relevant for function containers)
1563 m_lowerBoundsExtrapolated.clear();
1564 m_lowerBoundsExtrapolated.resize(maxParameters, -std::numeric_limits<double>::max());
1565 m_lowerBoundsExtrapolated[kPt] = m_lowerBoundsExtrapolated[kAbsEta] = 0;
1566 m_upperBoundsExtrapolated.clear();
1567 m_upperBoundsExtrapolated.resize(maxParameters, std::numeric_limits<double>::max());
1568}
1569
1570//________________________________________________________________________________
1574
1575//________________________________________________________________________________
1576void
1578{
1579 // Determine which variable types are to be used.
1580 // This needs to be done only once per calibration object, as the results will be
1581 // cached (even if not persistified).
1582 // This method should normally only be used internally.
1583
1584 if (! m_objResult) m_objResult = GetValue("result");
1585
1586 std::string title(m_objResult->GetTitle());
1587 std::string::size_type pos = title.find(";");
1588 while (pos != std::string::npos && pos != title.size()) {
1589 title = title.substr(pos+1);
1590 pos = title.find(";");
1591 std::string var = title.substr(0, pos);
1592 int vartype = typeFromString(var);
1593 if (vartype < 0) {
1594 // Only flag the issue but otherwise take no action (assume non-argument use of a semicolon)
1595 std::cerr << "in CalibrationDataFunctionContainer::computeVariableTypes(): cannot construct variable type from name "
1596 << var << std::endl;
1597 } else {
1598 m_variables.push_back((unsigned int)vartype);
1599 }
1600 }
1601
1602 // After doing this, we should always have a non-null vector!
1603 assert(m_variables.size() > 0);
1604}
1605
1606// result retrieval
1607
1608//________________________________________________________________________________
1611 double& result, TObject* obj, bool /* extrapolate */)
1612{
1613 // Retrieve the central value for the given input variables. There are cases where
1614 // it may be useful to provide an alternative parametrisation rather than the original
1615 // one; in such cases it is possible to provide a pointer to this alternative parametrisation.
1616 //
1617 // x: input variables
1618 // result: result
1619 // obj: pointer to alternative results histogram
1620 if (!obj) {
1621 if (! m_objResult) m_objResult = GetValue("result");
1622 obj = m_objResult;
1623 }
1624 TF1* func = dynamic_cast<TF1*>(obj);
1625 if (! func) return Analysis::kError;
1626
1627 // select the relevant kinematic variables
1629 result = func->EvalPar(m_vars);
1630
1631 return status;
1632}
1633
1634// general uncertainty retrieval
1635
1636//________________________________________________________________________________
1640 UncertaintyResult& result, TObject* obj)
1641{
1642 // Retrieve the uncertainty for the given input variables.
1643 // Note that the uncertainties returned will be symmetrised.
1644 //
1645 // unc: keyword indicating requested source of uncertainty. This should
1646 // correspond to one of the parametrisations added explicitly as a systematic
1647 // uncertainty or the keyword "statistics" (statistical uncertainties are
1648 // accessed differently, see method getStatUncertainty()).
1649 // x: input variables
1650 // result: result
1651 // obj: pointer to alternative or cached parametrisation
1652 if (unc == "statistics") {
1653 // treat statistical uncertainties separately (they are stored with the actual result)
1654 double res;
1656 if (code == Analysis::kError) return code;
1657 result.first = res;
1658 result.second = -res;
1659 return code;
1660 }
1661
1662 if (!obj) obj = GetValue(unc.c_str());
1663 TF1* func = dynamic_cast<TF1*>(obj);
1664 if (! func) return Analysis::kError;
1665
1666 // select the relevant kinematic variables
1668
1669 // the "first" and "second" entries are filled with the
1670 // "positive" and "negative" uncertainties, respectively.
1671 // Note: no "negative" uncertainties implemented as yet!
1672 result.first = func->EvalPar(m_vars);
1673 result.second = -result.first;
1674
1675 return status;
1676}
1677
1678//________________________________________________________________________________
1681 double& result)
1682{
1683 // Retrieve the statistical uncertainty for the given input variables.
1684 // The model that is assumed here is that statistical uncertainties follow from
1685 // a fit of the function to other information, and that the parameter covariance matrix
1686 // resulting from the fit are stored in a TMatrixDSym object identified by the
1687 // keyword "statistics". The effect of a change of fit parameters is then used to
1688 // evaluate the change in function value at the given co-ordinates.
1689 //
1690 // x: input variables
1691 // result: result
1692
1693 if (! m_objResult) m_objResult = GetValue("result"); // ensure that the requested objects exist
1694 TF1* func = dynamic_cast<TF1*>(m_objResult);
1695 if (! func) {
1696 // std::cerr << "... unable to retrieve the result" << std::endl;
1697 return Analysis::kError;
1698 }
1699
1700 if (! m_objStatistics) m_objStatistics = GetValue("statistics");
1701 // m_objStatistics->Dump();
1702 TMatrixTSym<double>* cov = dynamic_cast<TMatrixTSym<double>*>(m_objStatistics);
1703 if (! cov) {
1704 // std::cerr << "... unable to retrieve the covariance matrix" << std::endl;
1705 return Analysis::kError;
1706 }
1707
1708 // select the relevant kinematic variables
1710
1711 // use a large value for "eps": this multiplies the uncertainties that
1712 // are expected to be associated with the parameters. Choosing a large
1713 // value expresses the fact that we are not primarily interested in the
1714 // parabolic behaviour at the minimum
1715 // const Double_t eps = 1.0;
1716 // test: set to 0.5
1717 const Double_t eps = 0.5;
1718
1719 int npar = func->GetNpar();
1720 if (npar == 0) {
1721 result = 0.;
1722 return status;
1723 }
1724
1725 TMatrixT<double> gradients(npar,1);
1726 for (int ipar = 0; ipar < npar; ++ipar) {
1727 gradients(ipar,0) = func->GradientPar(ipar, m_vars, eps);
1728 }
1729
1730 // carry out the matrix multiplication
1731 TMatrixT<double> gradientsTransposed(TMatrixT<double>::kTransposed, gradients);
1732 // std::cout << "parametricVariance: transposed gradients:";
1733 // for (int ipar = 0; ipar < npar; ++ipar)
1734 // std::cout << " " << gradients(0,ipar);
1735 // std::cout << std::endl;
1736 TMatrixT<double> tmp1(*cov, TMatrixT<double>::kMult, gradients);
1737 // std::cout << "parametricVariance: cov * gradients:";
1738 // for (int ipar = 0; ipar < npar; ++ipar)
1739 // std::cout << " " << tmp1(ipar,0);
1740 TMatrixT<double> tmp2(gradientsTransposed, TMatrixT<double>::kMult, tmp1);
1741
1742 result = TMath::Sqrt(tmp2(0,0));
1743
1744 return status;
1745}
1746
1747//________________________________________________________________________________
1748bool
1750 // Simple utility function testing whether two double values are sufficiently similar.
1751 // The test carried out is on their relative difference, which should be within a given tolerance.
1752
1753 static const double tolerance = 1.e-8;
1754
1755 double diff = a - b;
1756 double ref = std::fabs(a) + std::fabs(b);
1757 return (ref == 0 || std::fabs(diff) < tolerance*ref);
1758}
const boost::regex ref(r_ef)
ClassImp(CalibrationDataContainer) CalibrationDataContainer
std::pair< std::vector< unsigned int >, bool > res
static Double_t a
static const std::vector< std::string > bins
ClassImp(xAOD::Experimental::RFileChecker) namespace xAOD
void diff(const Jet &rJet1, const Jet &rJet2, std::map< std::string, double > varDiff)
Difference between jets - Non-Class function required by trigger.
Definition Jet.cxx:631
#define x
This is the interface for the objects to be stored in the calibration ROOT file.
void setResult(TObject *obj)
insert the main object for this calibration
double getLowerBound(unsigned int vartype, bool extrapolate=false) const
retrieve the lower bound of validity for the requested variable type
std::vector< double > m_upperBoundsExtrapolated
(possibly looser) lower validity bounds for extrapolation
virtual CalibrationStatus getUncertainty(const std::string &unc, const CalibrationDataVariables &x, UncertaintyResult &result, TObject *obj=0)=0
retrieve the calibration uncertainty due to the given source.
void setExcludedUncertainties(const std::string &text)
insert the set of uncertainties that are recommended for removal from the eigenvector decomposition.
virtual CalibrationStatus getStatUncertainty(const CalibrationDataVariables &x, double &result)=0
retrieve the calibration statistical uncertainty.
double getUpperBound(unsigned int vartype, bool extrapolate=false) const
retrieve the upper bound of validity for the requested variable type
int typeFromString(const std::string &key) const
Connection between variable names (on histogram axes etc.) and variable 'types' as used in actual eva...
CalibrationStatus getUncertainties(const CalibrationDataVariables &x, std::map< std::string, Analysis::UncertaintyResult > &all)
retrieve the list of "uncertainties" accessible to this object.
void setUncertainty(const std::string &unc, TObject *obj)
insert the relevant object for the requested source of 'uncertainty'
virtual void computeVariableTypes()=0
decode the 'uncertainty' objects' names to determine the relevant variable types
std::vector< std::pair< double, double > > getBounds()
allow the user to inspect the bounds of validity
CalibrationStatus getSystUncertainty(const CalibrationDataVariables &x, UncertaintyResult &result, TObject *obj=0)
retrieve the calibration total systematic uncertainty
CalibrationStatus computeVariables(const CalibrationDataVariables &x, bool extrapolate=false)
compute the variables to be used for the given 'uncertainty'
void setHadronisation(const std::string &text)
insert the given text as the 'hadronisation reference' for this calibration
std::string getHadronisation() const
retrieve the 'hadronisation reference' entered for this calibration, if any
std::string getExcludedUncertainties() const
retrieve the (semicolon-separated) set of uncertainties that are recommended for removal from the eig...
static bool isNearlyEqual(double a, double b)
utility for comparison of doubles
void setComment(const std::string &text)
insert the given text as comment for this calibration
double m_vars[MaxCalibrationVars]
don't persistify
bool m_restrict
persistency not needed for this variable
std::vector< unsigned int > getVariableTypes()
utility to retrieve variable types
std::vector< std::string > listUncertainties() const
retrieve the list of "uncertainties" accessible to this object.
virtual CalibrationStatus getResult(const CalibrationDataVariables &x, double &result, TObject *obj=0, bool extrapolate=false)=0
retrieve the calibration result.
TObject * m_objResult
(possibly looser) upper validity bounds for extrapolation
std::string getComment() const
retrieve the comments entered for this calibration, if any
std::vector< unsigned int > m_variables
don't persistify
This is the class holding information for function-based calibration results.
virtual CalibrationStatus getUncertainty(const std::string &unc, const CalibrationDataVariables &x, UncertaintyResult &result, TObject *obj=0)
retrieve the calibration uncertainty due to the given source.
CalibrationDataFunctionContainer(const char *name="default")
virtual CalibrationStatus getStatUncertainty(const CalibrationDataVariables &x, double &result)
retrieve the calibration statistical uncertainty.
virtual CalibrationStatus getResult(const CalibrationDataVariables &x, double &result, TObject *obj=0, bool=false)
retrieve the calibration result.
This is the class holding information for histogram-based calibration results.
virtual int getEigenvectorReduction(unsigned int choice) const
Retrieve the number of eigenvectors to be retained for the purpose of eigenvector variation reduction...
std::map< unsigned int, std::vector< double > > m_binBoundaries
Cache for bin boundary information.
double getInterpolatedUncertainty(TH1 *hist) const
Retrieve interpolated result (utility function)
virtual CalibrationStatus getUncertainty(const std::string &unc, const CalibrationDataVariables &x, UncertaintyResult &result, TObject *obj=0)
retrieve the calibration uncertainty due to the given source.
void setUncorrelated(const std::string &unc)
Indicate that the given uncertainty is to be treated uncorrelated from bin to bin (note that the defa...
void setInterpolated(bool doInterpolate)
Indicate whether results are to be interpolated between bins or not (this feature is thought to be us...
virtual std::vector< double > getBinBoundaries(unsigned int vartype)
Retrieve the bin boundaries for the specified variable type (which should be a CalibrationParametriza...
virtual int getTagWeightAxis()
Test whether this calibration object is one for "continuous" calibration (this has some subtle conseq...
bool m_interpolate
If true, interpolate between bins rather than doing a straight bin-wise evaluation.
void checkBounds()
check the bounds of validity for this calibration object
double getInterpolatedResult(TH1 *hist) const
Retrieve interpolated result (utility function)
virtual CalibrationStatus getStatUncertainty(const CalibrationDataVariables &x, double &result)
retrieve the calibration statistical uncertainty.
virtual CalibrationStatus getResult(const CalibrationDataVariables &x, double &result, TObject *obj=0, bool extrapolate=false)
retrieve the calibration result.
virtual void computeVariableTypes()
utility for determining global bin number, subject to extrapolation constraints.
CalibrationDataHistogramContainer(const char *name="default")
bool isBinCorrelated(const std::string &unc) const
Indicate whether the given uncertainty is correlated from bin to bin or not (note that this function ...
virtual bool isInterpolated() const
Indicate whether histogram interpolation is used or not.
Helper class for the specification of custom binning.
This is the class holding information for histogram-based calibration results, in cases where 'irregu...
virtual int getTagWeightAxis()
Test whether this calibration object is one for "continuous" calibration (this has some subtle conseq...
unsigned int getNMappedBins() const
return the number of mapped bins
virtual void computeVariableTypes()
decode the 'uncertainty' objects' names to determine the relevant variable types
unsigned int m_beginMapped
starting position of mapped variables
std::vector< std::string > m_mapped
mapped variables.
virtual CalibrationStatus getResult(const CalibrationDataVariables &x, double &result, TObject *obj=0, bool extrapolate=false)
retrieve the calibration result.
void setMappedVariables(const std::vector< std::string > &variables)
Set (by hand) the variables that will be mapped onto a single histogram axis.
virtual CalibrationStatus getUncertainty(const std::string &unc, const CalibrationDataVariables &x, UncertaintyResult &result, TObject *obj=0)
retrieve the calibration uncertainty due to the given source.
virtual CalibrationStatus getStatUncertainty(const CalibrationDataVariables &x, double &result)
retrieve the calibration statistical uncertainty.
CalibrationDataMappedHistogramContainer(const char *name="default")
const std::vector< std::string > & getMappedVariables() const
List which variables get mapped onto a single histogram axis.
virtual std::vector< double > getBinBoundaries(unsigned int vartype)
Retrieve the bin boundaries for the specified variable type (which should be a CalibrationParametriza...
unsigned int addBin(const Bin &bin)
Add mapping bin.
void checkBounds()
check the bounds of validity for this calibration object
This class (struct, actually) is nothing but a light-weight container of (kinematic or other) variabl...
CalibrationDataContainer(const char *name="default")
Helper class for the specification of custom binning.
STL class.
std::vector< std::string > mapped
Definition hcg.cxx:54
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
std::pair< double, double > UncertaintyResult
The following typedef is for convenience: most uncertainties can be asymmetric.