ATLAS Offline Software
Loading...
Searching...
No Matches
CalibrationDataContainer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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 const TAxis* axis = 0;
972 if (m_variables[0] == vartype) axis = hobj->GetXaxis();
973 else if (m_variables[1] == vartype) axis = hobj->GetYaxis();
974 else axis = hobj->GetZaxis();
975
976 // Retrieve the actual bin boundaries
977 const TArrayD* bins = axis->GetXbins(); int nb = bins->GetSize();
978 for (int b = 0; b < nb; ++b) boundaries.push_back(bins->At(b));
979
980 m_binBoundaries[vartype] = boundaries;
981 return boundaries;
982}
983
984//________________________________________________________________________________
985int
987{
988 TObject* obj = GetValue("ReducedSets");
989 if (! obj) return -1;
990 TVectorT<double>* v = dynamic_cast<TVectorT<double>* >(obj);
991 if (! (v && v->GetNoElements() > int(choice)) ) return -1;
992 return int((*v)[choice]);
993}
994
996// //
997// CalibrationDataMappedHistogramContainer //
998// //
999// The CalibrationDataMappedHistogramContainer class inherits from the //
1000// CalibrationDataHistogramContainer class. It covers the special case (for at least two //
1001// dimensions) where the calibration is not done in a rectangular grid as would be implied //
1002// by the use of a TH2 or TH3. Instead, the class implements a mapping from a set of //
1003// general bins to bins on a given TH2 or TH3 axis. This generality implies that this class //
1004// in principle could be used also for the storage of higher-dimensional results. The only //
1005// assumptions made are that //
1006// - all bins have the same dimensions //
1007// - and the bins cover the 'mapped' dimensions completely, without any overlaps //
1008// Necessarily, the added flexibility makes access slower (even if caching of the mapped //
1009// bin is used). //
1010// //
1012
1013#ifndef __CINT__
1015#endif
1016
1017//________________________________________________________________________________
1019 CalibrationDataHistogramContainer(name), m_beginMapped(0),m_lastBin(0)
1020{
1021}
1022
1023//________________________________________________________________________________
1027
1028//________________________________________________________________________________
1029void
1031{
1032 // Compute the variable types for this container object.
1033 // The computation differs from that used for the parent CalibrationDataHistogramContainer
1034 // class, as also the 'mapped' variables (the variables that are mapped onto a single histogram
1035 // axis) need to be accounted for properly. This is handled as a special case.
1036
1037 // cache pointer to central values histogram
1038 if (! m_objResult) m_objResult = GetValue("result");
1039
1040 // histograms need a special treatment, as the coordinate titles are not actually stored
1041 // with the title itself, but instead moved off to the axis titles...
1042 const TH1* hobj = dynamic_cast<const TH1*>(m_objResult);
1043 if (not hobj){
1044 std::cerr << "in CalibrationDataMappedHistogramContainer::computeVariableTypes(): dynamic cast failed\n";
1045 return;
1046 }
1047
1048 int dims = hobj->GetDimension();
1049 for (int dim = 0; dim < dims; ++dim) {
1050 const TAxis* axis = 0;
1051 switch (dim) {
1052 case 0: axis = hobj->GetXaxis(); break;
1053 case 1: axis = hobj->GetYaxis(); break;
1054 default: axis = hobj->GetZaxis();
1055 }
1056 std::string var(axis->GetTitle());
1057 if (var == "mapped") {
1058 // Special case: mapped variables, so make sure to specify the original variables (not the mapped ones).
1059 // Note that the code here assumes that the mapping is identical for all objects..
1060 for (unsigned int m = 0; m < m_mapped.size(); ++m) {
1061 int vartype = typeFromString(m_mapped[m]);
1062 // this check should never fail; therefore, bail out if this does happen
1063 assert (! (vartype < 0));
1064 m_variables.push_back((unsigned int)vartype);
1065 }
1066 // In this case, also flag _where_ in the resulting list of variables the mapping starts
1067 m_beginMapped = dim;
1068 } else {
1069 int vartype = typeFromString(var);
1070 if (vartype < 0) {
1071 // Only flag the issue but otherwise take no action (assume non-argument use of a semicolon)
1072 std::cerr << "in CalibrationDataMappedHistogramContainer::computeVariableTypes(): cannot construct variable type from name "
1073 << var << std::endl;
1074 } else {
1075 m_variables.push_back((unsigned int)vartype);
1076 }
1077 }
1078 }
1079
1080 // After doing this, we should always have a non-null vector!
1081 assert(m_variables.size() > 0);
1082
1083 // Also compute the validity bounds for this calibration object
1085}
1086
1087
1088//________________________________________________________________________________
1089void
1091{
1092 // Check the bounds of validity for this calibration object.
1093 // See the CalibrationDataHistogramContainer::checkBounds() method. The difference is
1094 // that the 'mapped' dimensions need to be handled separately (this is carried out by
1095 // looping over the mapped bins and inspecting each bin's validity bounds individually).
1096 // Note that extrapolation uncertainties are not covered at this point.
1097
1098 const TH1* hist = dynamic_cast<const TH1*>(m_objResult);
1099 if (!hist) {
1100 std::cerr << "in CalibrationDataHistogramContainer::checkBounds(): object type does not derive from TH1" << std::endl;
1101 return;
1102 } else if (hist->GetDimension() + int(m_mapped.size()) - 1 != int(m_variables.size())) {
1103 std::cerr << "in CalibrationDataMappedHistogramContainer::checkBounds(): given number of variable types ("
1104 << m_variables.size() << ") doesn't match (mapped) histogram dimension ("
1105 << hist->GetDimension() + m_mapped.size() - 1 << ")!" << std::endl;
1106 return;
1107 }
1108
1109 // Carry out the only cross-check that's possible for the binning: check that the dimensionality
1110 // for all bins matches the number of variables specified for the mapping
1111 for (unsigned int bin = 0; bin < m_bins.size(); ++bin)
1112 assert(m_bins[bin].getDimension() == m_mapped.size());
1113
1114 for (unsigned int t = 0, t2 = 0; int(t) < hist->GetDimension(); ++t) {
1115 const TAxis* axis = 0;
1116 switch (t) {
1117 case 0: axis = hist->GetXaxis(); break;
1118 case 1: axis = hist->GetYaxis(); break;
1119 default: axis = hist->GetZaxis();
1120 }
1121
1122 // Special case for the mapped dimension: here the only thing that can be done is to
1123 // cycle through all Bins and inspect the boundaries of each bin manually.
1124 if (t == m_beginMapped) {
1125 for (unsigned int mapped = 0; mapped < m_mapped.size(); ++mapped) {
1126 for (unsigned int bin = 0; bin < m_bins.size(); ++bin) {
1127 double amax = m_bins[bin].getUpperBound(mapped), amin = m_bins[bin].getLowerBound(mapped);
1128 if (bin == 0 || amax > m_upperBounds[m_variables[t2]]) m_upperBounds[m_variables[t2]] = amax;
1129 if (bin == 0 || amin < m_lowerBounds[m_variables[t2]]) m_lowerBounds[m_variables[t2]] = amin;
1130 }
1131 ++t2;
1132 }
1133 } else {
1134 // for (unsigned int t = 0; t < m_variables.size(); ++t) {
1135 // if (m_variables[t] > m_upperBounds.size()) {
1136 // std::cerr << "in CalibrationDataHistogramContainer::checkBounds(): variable " << t << "type ("
1137 // << m_variables[t] << "exceeds maximum type number (" << m_upperBounds.size() << ")!"
1138 // << std::endl;
1139 // return;
1140 // }
1141 // }
1142 double amax = axis->GetXmax(), amin = axis->GetXmin();
1143 if (amax < m_upperBounds[m_variables[t2]]) m_upperBounds[m_variables[t2]] = amax;
1144 if (amin > m_lowerBounds[m_variables[t2]]) m_lowerBounds[m_variables[t2]] = amin;
1145 ++t2;
1146 }
1147 }
1148}
1149
1150//________________________________________________________________________________
1153 double& result, TObject* obj, bool /* extrapolate */)
1154{
1155 // Retrieve the central value for the given input variables. There are cases where
1156 // it may be useful to provide an alternative histogram rather than the original
1157 // one; in such cases (notably used with eigenvector variations) it is possible to
1158 // provide a pointer to this alternative histogram.
1159 // The method here differs from CalibrationDataHistogramContainer::getResult()
1160 // since histogram interpolation does not make sense for mapped bins.
1161 //
1162 // x: input variables
1163 // result: result
1164 // obj: pointer to alternative results histogram
1165
1166 if (!obj) {
1167 if (! m_objResult) {
1168 m_objResult = GetValue("result");
1169 }
1170 obj = m_objResult;
1171 }
1172 TH1* hist = dynamic_cast<TH1*>(obj);
1173 if (! hist) return Analysis::kError;
1174
1175 // select the relevant kinematic variables
1177 // find the relevant "global" bin and retrieve its contents
1178 result = hist->GetBinContent(findBin());
1179
1180 return status;
1181}
1182
1183//________________________________________________________________________________
1186 double& result)
1187{
1188 // Retrieve the statistical uncertainty for the given input variables.
1189 //
1190 // x: input variables
1191 // result: result
1192
1193 if (! m_objResult) {
1194 m_objResult = GetValue("result");
1195 }
1196 TH1* hist = dynamic_cast<TH1*>(m_objResult);
1197 if (! hist) return Analysis::kError;
1198
1199 // select the relevant kinematic variables
1201 // find the relevant "global" bin and retrieve its contents
1202 result = hist->GetBinError(findBin());
1203
1204 return status;
1205}
1206
1207//________________________________________________________________________________
1211 UncertaintyResult& result, TObject* obj)
1212{
1213 // Retrieve the uncertainty for the given input variables.
1214 //
1215 // unc: keyword indicating requested source of uncertainty. This should
1216 // correspond to one of the histograms added explicitly as a systematic
1217 // uncertainty or the keyword "statistics" (statistical uncertainties are
1218 // accessed differently, see method getStatUncertainty()).
1219 // x: input variables
1220 // result: result
1221 // obj: pointer to alternative or cached histogram
1222
1223 // treat statistical uncertainties separately (they are stored with the actual result)
1224 if (unc == "statistics") {
1225 double res;
1227 if (code == Analysis::kError) return code;
1228 result.first = res;
1229 result.second = -res;
1230 return code;
1231 }
1232
1233 if (!obj) obj = GetValue(unc.c_str());
1234 TH1* hist = dynamic_cast<TH1*>(obj);
1235 if (! hist) return Analysis::kError;
1236
1237 // select the relevant kinematic variables
1239 // find the relevant "global" bin and retrieve its contents
1240 Int_t bin = findBin();
1241 result.first = hist->GetBinError(bin);
1242 result.second = hist->GetBinError(bin);
1243
1244 return status;
1245}
1246
1247//________________________________________________________________________________
1248int
1250{
1251 // Test whether this calibration object is one for "continuous" calibration
1252 // (this has some subtle consequences for the treatment of bin-to-bin correlations).
1253 // The return value will be -1 in case this is not a "continuous" calibration object,
1254 // and the axis number (0 for X, 1 for Y, 2 for Z) otherwise.
1255
1256 for (unsigned int type = 0; type < m_variables.size(); ++type)
1257 if (m_variables[type] == kTagWeight) {
1258 int hist_type = int(type);
1259 return (hist_type > int(m_beginMapped)) ? hist_type - m_mapped.size() + 1 : hist_type;
1260 }
1261 return -1;
1262}
1263
1264//________________________________________________________________________________
1265void
1266CalibrationDataMappedHistogramContainer::setMappedVariables(const std::vector<std::string>& variables)
1267{
1268 // Set (by hand) the variables that will be mapped onto a single histogram axis
1269
1270 m_mapped = variables;
1271}
1272
1273//________________________________________________________________________________
1274const std::vector<std::string>&
1276{
1277 // List which variables get mapped onto a single histogram axis
1278
1279 return m_mapped;
1280}
1281
1282//________________________________________________________________________________
1283unsigned int
1285{
1286 // Add a bin to the present list
1287 // Note the absence of a -1 in the return value: this is because ROOT's histogram axes start counting from 1
1288
1289 m_bins.push_back(bin);
1290 return m_bins.size();
1291}
1292
1293//________________________________________________________________________________
1294unsigned int
1296{
1297 // Return the number of mapped bins
1298 // Note the absence of a -1 in the return value: this is because ROOT's histogram axes start counting from 1
1299
1300 return m_bins.size();
1301}
1302
1303//________________________________________________________________________________
1304Int_t
1306{
1307 // Find the mapped bin corresponding to the variables used for the mapping
1308
1309 if (m_bins[m_lastBin].contains(x)) return m_lastBin + 1; // First check quickly whether the last bin (cached) matches
1310
1311 // Search the whole array for a match
1312 for (unsigned int bin = 0; bin < m_bins.size(); ++bin)
1313 if (m_bins[bin].contains(x)) {
1314 m_lastBin = bin;
1315 return m_lastBin + 1;
1316 }
1317 std::cerr << "CalibrationDataMappedHistogramContainer::findMappedBin(): unable to find bin for mapping variables:";
1318 for (unsigned int d = 0; d < m_mapped.size(); ++d) std::cerr << "\t" << x[d];
1319 std::cerr << std::endl;
1320 // -1 means invalid..
1321 return -1;
1322}
1323
1324//________________________________________________________________________________
1325Int_t
1327{
1328 // Find the bin corresponding to the computed variables (the computation is assumed to have just
1329 // taken place and resulted in the m_vars array having been filled appropriately)
1330
1331 Int_t mapped[3] = {0};
1332 const TH1* hist = dynamic_cast<const TH1*>(m_objResult);
1333 if (not hist){
1334 std::cerr << "CalibrationDataMappedHistogramContainer::findBin(): dynamic cast failed\n";
1335 return 0;
1336 }
1337 Int_t ndim = hist->GetDimension();
1338 // Push the mapped variables onto an array.
1339 // Since we derive from TH1 this need never be more than 3 elements long.
1340 for (unsigned int dim = 0; dim < (unsigned int) ndim; ++dim) {
1341 if (dim == m_beginMapped) {
1342 if ((mapped[dim] = findMappedBin(&(m_vars[dim]))) < 0) return -1;
1343 } else {
1344 const TAxis* axis = 0;
1345 switch (dim) {
1346 case 0: axis = hist->GetXaxis(); break;
1347 case 1: axis = hist->GetYaxis(); break;
1348 default: axis = hist->GetZaxis();
1349 }
1350 mapped[dim] = axis->FindFixBin((dim < m_beginMapped) ? m_vars[dim] : m_vars[dim+m_mapped.size()-1]);
1351 }
1352 }
1353 return hist->GetBin(mapped[0], mapped[1], mapped[2]);
1354}
1355
1356//________________________________________________________________________________
1357std::vector<double>
1359{
1360 // Retrieve the bin boundaries for the specified variable type (which should be a CalibrationParametrization enum).
1361 // An empty vector will be returned if the specified variable is not actually used.
1362
1363 // Ensure that the variable types have been computed at this point
1364 if (m_variables.size() == 0) computeVariableTypes();
1365
1366 // use cached information if available
1367 std::map<unsigned int, std::vector<double> >::iterator it = m_binBoundaries.find(vartype);
1368 if (it != m_binBoundaries.end()) return it->second;
1369
1370 // Check whether the variable type is actually being used
1371 std::vector<double> boundaries;
1372 int var = -1;
1373 for (unsigned int v = 0; v < m_variables.size(); ++v)
1374 if (m_variables[v] == vartype) var = (int) v;
1375 if (var == -1) return boundaries;
1376
1377 // Retrieve the appropriate histogram axis
1378 if (! m_objResult) m_objResult = GetValue("result");
1379 const TH1* hobj = dynamic_cast<const TH1*>(m_objResult);
1380
1381 if (var >= int(m_beginMapped) && var < int(m_beginMapped + m_mapped.size())) {
1382 // Special case of a mapped variable. In this case, test all Bins for their boundaries
1383 unsigned int mapped = var - m_beginMapped;
1384 for (unsigned int bin = 0; bin < m_bins.size(); ++bin) {
1385 double binBoundaries[2];
1386 binBoundaries[0] = m_bins[bin].getLowerBound(mapped);
1387 binBoundaries[1] = m_bins[bin].getUpperBound(mapped);
1388 // Insert the bin boundaries, if not already present (the test is whether the relative difference
1389 // is smaller than 1e-8)
1390 if (boundaries.size() == 0) {
1391 boundaries.push_back(binBoundaries[0]); boundaries.push_back(binBoundaries[1]);
1392 } else {
1393 for (unsigned int ib = 0; ib < 2; ++ib) {
1394 double newvalue = binBoundaries[ib];
1395 bool done = false;
1396 for (std::vector<double>::iterator it = boundaries.begin(); it != boundaries.end(); ++it) {
1397 if (isNearlyEqual(newvalue, *it)) {
1398 // consider this value to have been inserted already
1399 done = true; break;
1400 } else if (newvalue < *it) {
1401 // the interesting case: insert the new value
1402 boundaries.insert(it, newvalue);
1403 done = true; break;
1404 }
1405 }
1406 // last case: new value is larger than any of the values in the array so far
1407 if (! done) boundaries.push_back(newvalue);
1408 }
1409 }
1410 }
1411 } else {
1412 // Normal case:
1413 unsigned int dim = (var < int(m_beginMapped)) ? var : var + 1 - m_mapped.size();
1414 const TAxis* axis = 0;
1415 switch (dim) {
1416 case 0: axis = hobj->GetXaxis(); break;
1417 case 1: axis = hobj->GetYaxis(); break;
1418 default: axis = hobj->GetZaxis();
1419 }
1420 // Retrieve the actual bin boundaries
1421 const TArrayD* bins = axis->GetXbins(); int nb = bins->GetSize();
1422 for (int b = 0; b < nb; ++b) boundaries.push_back(bins->At(b));
1423 }
1424
1425 m_binBoundaries[vartype] = boundaries;
1426 return boundaries;
1427}
1428
1429// Bin helper class methods
1430
1432// //
1433// CalibrationDataMappedHistogramContainer::Bin //
1434// //
1435// This is a small nested class collecting 'mapped' bin information. Its purpose is mostly //
1436// to store binning information in a structured way. The only relevant event-level method //
1437// is the contains() method. //
1438// //
1440
1441#ifndef __CINT__
1443#endif
1444
1445//________________________________________________________________________________
1447 m_dimension(0), m_low(0), m_up(0)
1448{
1449 // Default constructor (for persistency)
1450}
1451
1452//________________________________________________________________________________
1453CalibrationDataMappedHistogramContainer::Bin::Bin(unsigned int dimension, const double* low, const double* up):
1454 m_dimension(dimension)
1455{
1456 // Normal constructor, containing a full specification of the bin boundaries
1457
1458 m_up = new double[dimension];
1459 m_low = new double[dimension];
1460 for (unsigned int dim = 0; dim < dimension; ++dim) {
1461 m_up[dim] = up[dim];
1462 m_low[dim] = low[dim];
1463 }
1464}
1465
1466//________________________________________________________________________________
1468 m_dimension(other.m_dimension)
1469{
1470 m_up = new double[m_dimension];
1471 m_low = new double[m_dimension];
1472 for (unsigned int dim = 0; dim < m_dimension; ++dim) {
1473 m_up[dim] = other.m_up[dim];
1474 m_low[dim] = other.m_low[dim];
1475 }
1476}
1477
1478//________________________________________________________________________________
1481{
1482 if (this != &other) {
1483 m_dimension = other.m_dimension;
1484 delete[] m_up;
1485 delete[] m_low;
1486 m_up = new double[m_dimension];
1487 m_low = new double[m_dimension];
1488 for (unsigned int dim = 0; dim < m_dimension; ++dim) {
1489 m_up[dim] = other.m_up[dim];
1490 m_low[dim] = other.m_low[dim];
1491 }
1492 }
1493 return *this;
1494}
1495
1496//________________________________________________________________________________
1498{
1499 delete[] m_up;
1500 delete[] m_low;
1501}
1502
1503//________________________________________________________________________________
1504bool
1506{
1507 // Determine whether the given set of variables is within the bin boundaries.
1508
1509 for (unsigned int dim = 0; dim < m_dimension; ++dim)
1510 if (x[dim] < m_low[dim] || x[dim] > m_up[dim]) return false;
1511 return true;
1512}
1513
1514//________________________________________________________________________________
1515double
1517{
1518 // Return the upper bound for the specified dimension
1519 return m_up[dim];
1520}
1521
1522//________________________________________________________________________________
1523double
1525{
1526 // Return the lower bound for the specified dimension
1527 return m_low[dim];
1528}
1529
1531// //
1532// CalibrationDataFunctionContainer //
1533// //
1534// The CalibrationDataFunctionContainer class inherits from the CalibrationDataContainer //
1535// abstract class. It covers the cases where the relevant information is presented in //
1536// parametrised form. //
1537// //
1539
1540#ifndef __CINT__
1542#endif
1543
1544//________________________________________________________________________________
1546 CalibrationDataContainer(name), m_objStatistics(0)
1547{
1548 // Default constructor
1549
1550 // Reset the validity bounds to reflect 'no bounds'.
1551 m_lowerBounds.clear();
1552 m_lowerBounds.resize(maxParameters, -std::numeric_limits<double>::max());
1553 m_lowerBounds[kPt] = m_lowerBounds[kAbsEta] = 0;
1554 m_upperBounds.clear();
1555 m_upperBounds.resize(maxParameters, std::numeric_limits<double>::max());
1556 // and do the same for the validity bounds associated with extrapolation uncertainties
1557 // (this should anyway not be relevant for function containers)
1558 m_lowerBoundsExtrapolated.clear();
1559 m_lowerBoundsExtrapolated.resize(maxParameters, -std::numeric_limits<double>::max());
1560 m_lowerBoundsExtrapolated[kPt] = m_lowerBoundsExtrapolated[kAbsEta] = 0;
1561 m_upperBoundsExtrapolated.clear();
1562 m_upperBoundsExtrapolated.resize(maxParameters, std::numeric_limits<double>::max());
1563}
1564
1565//________________________________________________________________________________
1569
1570//________________________________________________________________________________
1571void
1573{
1574 // Determine which variable types are to be used.
1575 // This needs to be done only once per calibration object, as the results will be
1576 // cached (even if not persistified).
1577 // This method should normally only be used internally.
1578
1579 if (! m_objResult) m_objResult = GetValue("result");
1580
1581 std::string title(m_objResult->GetTitle());
1582 std::string::size_type pos = title.find(";");
1583 while (pos != std::string::npos && pos != title.size()) {
1584 title = title.substr(pos+1);
1585 pos = title.find(";");
1586 std::string var = title.substr(0, pos);
1587 int vartype = typeFromString(var);
1588 if (vartype < 0) {
1589 // Only flag the issue but otherwise take no action (assume non-argument use of a semicolon)
1590 std::cerr << "in CalibrationDataFunctionContainer::computeVariableTypes(): cannot construct variable type from name "
1591 << var << std::endl;
1592 } else {
1593 m_variables.push_back((unsigned int)vartype);
1594 }
1595 }
1596
1597 // After doing this, we should always have a non-null vector!
1598 assert(m_variables.size() > 0);
1599}
1600
1601// result retrieval
1602
1603//________________________________________________________________________________
1606 double& result, TObject* obj, bool /* extrapolate */)
1607{
1608 // Retrieve the central value for the given input variables. There are cases where
1609 // it may be useful to provide an alternative parametrisation rather than the original
1610 // one; in such cases it is possible to provide a pointer to this alternative parametrisation.
1611 //
1612 // x: input variables
1613 // result: result
1614 // obj: pointer to alternative results histogram
1615 if (!obj) {
1616 if (! m_objResult) m_objResult = GetValue("result");
1617 obj = m_objResult;
1618 }
1619 TF1* func = dynamic_cast<TF1*>(obj);
1620 if (! func) return Analysis::kError;
1621
1622 // select the relevant kinematic variables
1624 result = func->EvalPar(m_vars);
1625
1626 return status;
1627}
1628
1629// general uncertainty retrieval
1630
1631//________________________________________________________________________________
1635 UncertaintyResult& result, TObject* obj)
1636{
1637 // Retrieve the uncertainty for the given input variables.
1638 // Note that the uncertainties returned will be symmetrised.
1639 //
1640 // unc: keyword indicating requested source of uncertainty. This should
1641 // correspond to one of the parametrisations added explicitly as a systematic
1642 // uncertainty or the keyword "statistics" (statistical uncertainties are
1643 // accessed differently, see method getStatUncertainty()).
1644 // x: input variables
1645 // result: result
1646 // obj: pointer to alternative or cached parametrisation
1647 if (unc == "statistics") {
1648 // treat statistical uncertainties separately (they are stored with the actual result)
1649 double res;
1651 if (code == Analysis::kError) return code;
1652 result.first = res;
1653 result.second = -res;
1654 return code;
1655 }
1656
1657 if (!obj) obj = GetValue(unc.c_str());
1658 TF1* func = dynamic_cast<TF1*>(obj);
1659 if (! func) return Analysis::kError;
1660
1661 // select the relevant kinematic variables
1663
1664 // the "first" and "second" entries are filled with the
1665 // "positive" and "negative" uncertainties, respectively.
1666 // Note: no "negative" uncertainties implemented as yet!
1667 result.first = func->EvalPar(m_vars);
1668 result.second = -result.first;
1669
1670 return status;
1671}
1672
1673//________________________________________________________________________________
1676 double& result)
1677{
1678 // Retrieve the statistical uncertainty for the given input variables.
1679 // The model that is assumed here is that statistical uncertainties follow from
1680 // a fit of the function to other information, and that the parameter covariance matrix
1681 // resulting from the fit are stored in a TMatrixDSym object identified by the
1682 // keyword "statistics". The effect of a change of fit parameters is then used to
1683 // evaluate the change in function value at the given co-ordinates.
1684 //
1685 // x: input variables
1686 // result: result
1687
1688 if (! m_objResult) m_objResult = GetValue("result"); // ensure that the requested objects exist
1689 TF1* func = dynamic_cast<TF1*>(m_objResult);
1690 if (! func) {
1691 // std::cerr << "... unable to retrieve the result" << std::endl;
1692 return Analysis::kError;
1693 }
1694
1695 if (! m_objStatistics) m_objStatistics = GetValue("statistics");
1696 // m_objStatistics->Dump();
1697 TMatrixTSym<double>* cov = dynamic_cast<TMatrixTSym<double>*>(m_objStatistics);
1698 if (! cov) {
1699 // std::cerr << "... unable to retrieve the covariance matrix" << std::endl;
1700 return Analysis::kError;
1701 }
1702
1703 // select the relevant kinematic variables
1705
1706 // use a large value for "eps": this multiplies the uncertainties that
1707 // are expected to be associated with the parameters. Choosing a large
1708 // value expresses the fact that we are not primarily interested in the
1709 // parabolic behaviour at the minimum
1710 // const Double_t eps = 1.0;
1711 // test: set to 0.5
1712 const Double_t eps = 0.5;
1713
1714 int npar = func->GetNpar();
1715 if (npar == 0) {
1716 result = 0.;
1717 return status;
1718 }
1719
1720 TMatrixT<double> gradients(npar,1);
1721 for (int ipar = 0; ipar < npar; ++ipar) {
1722 gradients(ipar,0) = func->GradientPar(ipar, m_vars, eps);
1723 }
1724
1725 // carry out the matrix multiplication
1726 TMatrixT<double> gradientsTransposed(TMatrixT<double>::kTransposed, gradients);
1727 // std::cout << "parametricVariance: transposed gradients:";
1728 // for (int ipar = 0; ipar < npar; ++ipar)
1729 // std::cout << " " << gradients(0,ipar);
1730 // std::cout << std::endl;
1731 TMatrixT<double> tmp1(*cov, TMatrixT<double>::kMult, gradients);
1732 // std::cout << "parametricVariance: cov * gradients:";
1733 // for (int ipar = 0; ipar < npar; ++ipar)
1734 // std::cout << " " << tmp1(ipar,0);
1735 TMatrixT<double> tmp2(gradientsTransposed, TMatrixT<double>::kMult, tmp1);
1736
1737 result = TMath::Sqrt(tmp2(0,0));
1738
1739 return status;
1740}
1741
1742//________________________________________________________________________________
1743bool
1745 // Simple utility function testing whether two double values are sufficiently similar.
1746 // The test carried out is on their relative difference, which should be within a given tolerance.
1747
1748 static const double tolerance = 1.e-8;
1749
1750 double diff = a - b;
1751 double ref = std::fabs(a) + std::fabs(b);
1752 return (ref == 0 || std::fabs(diff) < tolerance*ref);
1753}
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.