File indexing completed on 2026-05-05 08:50:28
0001
0002 #ifndef RIVET_Analysis_HH
0003 #define RIVET_Analysis_HH
0004
0005 #include "Rivet/Config/RivetCommon.hh"
0006 #include "Rivet/AnalysisInfo.hh"
0007 #include "Rivet/Event.hh"
0008 #include "Rivet/Projection.hh"
0009 #include "Rivet/ProjectionApplier.hh"
0010 #include "Rivet/ProjectionHandler.hh"
0011 #include "Rivet/AnalysisLoader.hh"
0012 #include "Rivet/Tools/Cuts.hh"
0013 #include "Rivet/Tools/Logging.hh"
0014 #include "Rivet/Tools/ParticleUtils.hh"
0015 #ifdef HAVE_H5
0016 #include "Rivet/Tools/RivetHDF5.hh"
0017 #endif
0018 #include "Rivet/Tools/HistoGroup.hh"
0019 #include "Rivet/Tools/RivetMT2.hh"
0020 #include "Rivet/Tools/RivetPaths.hh"
0021 #include "Rivet/Tools/RivetYODA.hh"
0022 #include "Rivet/Tools/Percentile.hh"
0023 #include "Rivet/Tools/Cutflow.hh"
0024 #include "Rivet/Projections/CentralityProjection.hh"
0025 #include "Rivet/Projections/FastJets.hh"
0026 #include <tuple>
0027
0028
0029
0030
0031 #define vetoEvent \
0032 do { MSG_DEBUG("Vetoing event on line " << __LINE__ << " of " << __FILE__); return; } while(0)
0033
0034 namespace Rivet {
0035
0036
0037
0038 using std::cout;
0039 using std::cerr;
0040 using std::endl;
0041 using std::tuple;
0042 using std::stringstream;
0043 using std::swap;
0044 using std::numeric_limits;
0045
0046
0047
0048 class AnalysisHandler;
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 class Analysis : public ProjectionApplier {
0070 public:
0071
0072
0073 friend class AnalysisHandler;
0074
0075
0076
0077 Analysis(const std::string& name);
0078
0079
0080 virtual ~Analysis() {}
0081
0082
0083 Analysis& operator = (const Analysis&) = delete;
0084
0085
0086 public:
0087
0088
0089
0090
0091
0092
0093
0094 virtual void init() { }
0095
0096
0097
0098
0099
0100 virtual void analyze(const Event& event) = 0;
0101
0102
0103
0104
0105
0106
0107 virtual void finalize() { }
0108
0109
0110
0111
0112
0113
0114
0115
0116 virtual void preInit() { }
0117
0118 virtual void postInit() { }
0119
0120 virtual void preAnalyze(const Event&) { }
0121
0122 virtual void postAnalyze(const Event&) { }
0123
0124 virtual void preFinalize() { }
0125
0126 virtual void postFinalize() { }
0127
0128
0129
0130
0131 void syncDeclQueue() {
0132 this->_syncDeclQueue();
0133 this->markAsOwned();
0134 }
0135
0136
0137
0138
0139 public:
0140
0141
0142
0143
0144
0145
0146
0147
0148 void loadInfo() { info().parseInfoFile(); }
0149
0150
0151 const AnalysisInfo& info() const {
0152 if (!_info) throw Error("No AnalysisInfo object :-O");
0153 return *_info;
0154 }
0155
0156
0157
0158
0159
0160
0161
0162
0163 virtual std::string name() const {
0164 return ( (info().name().empty()) ? _defaultname : info().name() ) + _optstring;
0165 }
0166
0167
0168
0169
0170
0171 std::string analysisDataPath(const std::string& extn, const std::string& suffix="") {
0172 string filename = name() + (suffix.empty() ? "" : "-") + suffix + "." + extn;
0173 return findAnalysisDataFile(filename);
0174 }
0175
0176
0177 virtual std::string inspireID() const {
0178 return info().inspireID();
0179 }
0180
0181
0182 virtual std::string spiresID() const {
0183 return info().spiresID();
0184 }
0185
0186
0187
0188
0189
0190 virtual std::vector<std::string> authors() const {
0191 return info().authors();
0192 }
0193
0194
0195
0196
0197
0198
0199 virtual std::string summary() const {
0200 return info().summary();
0201 }
0202
0203
0204
0205
0206
0207
0208
0209 virtual std::string description() const {
0210 return info().description();
0211 }
0212
0213
0214
0215
0216
0217
0218 virtual std::string runInfo() const {
0219 return info().runInfo();
0220 }
0221
0222
0223 virtual std::string experiment() const {
0224 return info().experiment();
0225 }
0226
0227
0228 virtual std::string collider() const {
0229 return info().collider();
0230 }
0231
0232
0233 virtual std::string year() const {
0234 return info().year();
0235 }
0236
0237
0238 virtual double luminosityfb() const {
0239 return info().luminosityfb();
0240 }
0241
0242 virtual double luminosity() const {
0243 return info().luminosity();
0244 }
0245
0246 double luminositypb() const { return luminosity(); }
0247
0248
0249 virtual std::vector<std::string> references() const {
0250 return info().references();
0251 }
0252
0253
0254 virtual std::string bibKey() const {
0255 return info().bibKey();
0256 }
0257
0258
0259 virtual std::string bibTeX() const {
0260 return info().bibTeX();
0261 }
0262
0263
0264 virtual std::string status() const {
0265 return (info().status().empty()) ? "UNVALIDATED" : info().status();
0266 }
0267
0268
0269 virtual std::string warning() const {
0270 return info().warning();
0271 }
0272
0273
0274 virtual std::vector<std::string> todos() const {
0275 return info().todos();
0276 }
0277
0278
0279 virtual std::vector<std::string> validation() const {
0280 return info().validation();
0281 }
0282
0283
0284 virtual bool reentrant() const {
0285 return info().reentrant();
0286 }
0287
0288
0289 virtual const std::vector<std::string>& keywords() const {
0290 return info().keywords();
0291 }
0292
0293
0294 virtual std::string refMatch() const {
0295 return info().refMatch();
0296 }
0297
0298
0299 virtual std::string refUnmatch() const {
0300 return info().refUnmatch();
0301 }
0302
0303
0304 virtual std::string writerDoublePrecision() const {
0305 return info().writerDoublePrecision();
0306 }
0307
0308
0309 virtual const std::vector<PdgIdPair>& requiredBeamIDs() const {
0310 return info().beamIDs();
0311 }
0312
0313 virtual Analysis& setRequiredBeamIDs(const std::vector<PdgIdPair>& beamids) {
0314 info().setBeamIDs(beamids);
0315 return *this;
0316 }
0317
0318
0319 virtual const std::vector<std::pair<double, double> >& requiredBeamEnergies() const {
0320 return info().energies();
0321 }
0322
0323 virtual Analysis& setRequiredBeamEnergies(const std::vector<std::pair<double, double> >& energies) {
0324 info().setEnergies(energies);
0325 return *this;
0326 }
0327
0328
0329
0330 virtual std::string refFile() const {
0331 return info().refFile();
0332 }
0333
0334 virtual std::string refDataName() const {
0335 return (info().getRefDataName().empty()) ? _defaultname : info().getRefDataName();
0336 }
0337
0338 virtual void setRefDataName(const std::string& ref_data="") {
0339 info().setRefDataName(!ref_data.empty() ? ref_data : name());
0340 }
0341
0342
0343
0344
0345
0346 AnalysisInfo& info() {
0347 if (!_info) throw Error("No AnalysisInfo object :-O");
0348 return *_info;
0349 }
0350
0351
0352
0353
0354
0355
0356
0357
0358 bool merging() const {
0359 return sqrtS() <= 0.0;
0360 }
0361
0362
0363 bool compatibleWithRun() const;
0364
0365
0366 void raiseBeamErrorIf(const bool condition) const;
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376 const ParticlePair& beams() const;
0377
0378
0379 PdgIdPair beamIDs() const;
0380
0381
0382 pair<double,double> beamEnergies() const;
0383
0384
0385 vector<double> allowedEnergies() const;
0386
0387
0388 double sqrtS() const;
0389
0390
0391 bool beamsMatch(const ParticlePair& beams) const;
0392
0393
0394 bool beamsMatch(PdgId beam1, PdgId beam2, double e1, double e2) const;
0395
0396
0397 bool beamsMatch(const PdgIdPair& beams, const std::pair<double,double>& energies) const;
0398
0399
0400 bool beamIDsMatch(PdgId beam1, PdgId beam2) const;
0401
0402
0403 bool beamIDsMatch(const PdgIdPair& beamids) const;
0404
0405
0406 bool beamEnergiesMatch(double e1, double e2) const;
0407
0408
0409 bool beamEnergiesMatch(const std::pair<double,double>& energies) const;
0410
0411
0412 bool beamEnergyMatch(const std::pair<double,double>& energies) const;
0413
0414
0415 bool beamEnergyMatch(double sqrts) const;
0416
0417
0418 bool isCompatibleWithSqrtS(double energy, double tolerance=1e-5) const;
0419
0420
0421
0422
0423
0424 AnalysisHandler& handler() const { return *_analysishandler; }
0425
0426
0427 const Event& currentEvent() const {
0428 if (!_currentevent) throw Error("No current event set: did you try to access it in init() or finalize()?");
0429 return *_currentevent;
0430 }
0431
0432
0433 protected:
0434
0435
0436 Log& getLog() const;
0437
0438
0439 double crossSection() const;
0440
0441
0442
0443 double crossSectionPerEvent() const;
0444
0445
0446 double crossSectionError() const;
0447
0448
0449
0450 double crossSectionErrorPerEvent() const;
0451
0452
0453
0454
0455 size_t numEvents() const;
0456
0457
0458
0459
0460 double effNumEvents() const;
0461
0462
0463
0464
0465 double sumW() const;
0466
0467 double sumOfWeights() const { return sumW(); }
0468
0469
0470
0471
0472 double sumW2() const;
0473
0474
0475 protected:
0476
0477
0478
0479
0480
0481
0482
0483
0484 const std::string histoDir() const;
0485
0486
0487 const std::string histoPath(const std::string& hname) const;
0488
0489
0490 const std::string histoPath(unsigned int datasetID, unsigned int xAxisID, unsigned int yAxisID) const;
0491
0492
0493 const std::string mkAxisCode(unsigned int datasetID, unsigned int xAxisID, unsigned int yAxisID) const;
0494
0495
0496
0497
0498 #ifdef HAVE_H5
0499
0500
0501
0502
0503 H5::File auxFile() const {
0504 return H5::readFile(name()+".h5");
0505 }
0506
0507
0508 template <typename T>
0509 bool auxData(const string& dsname, T& rtndata) {
0510
0511 return H5::readData(name()+".h5", dsname, rtndata);
0512 }
0513
0514 template <typename T>
0515 T auxData(const string& dsname) {
0516
0517 return H5::readData<T>(name()+".h5", dsname);
0518 }
0519
0520
0521 #endif
0522
0523
0524
0525
0526
0527
0528 const std::map<std::string, YODA::AnalysisObjectPtr>& refData() const {
0529 _cacheRefData();
0530 return _refdata;
0531 }
0532
0533
0534
0535
0536 template <typename T=YODA::Estimate1D>
0537 const T& refData(const string& hname) const {
0538 _cacheRefData();
0539 MSG_TRACE("Using histo bin edges for " << name() << ":" << hname);
0540 if (!_refdata[hname]) {
0541 MSG_ERROR("Can't find reference histogram " << hname);
0542 throw Exception("Reference data " + hname + " not found.");
0543 }
0544 try {
0545 return dynamic_cast<T&>(*_refdata[hname]);
0546 } catch (...) {
0547 throw Exception("Expected type " + _refdata[hname]->type()+" for reference data \"" + hname + "\".\n");
0548 }
0549 }
0550
0551
0552
0553
0554 template <typename T=YODA::Estimate1D>
0555 const T& refData(unsigned int datasetId, unsigned int xAxisId, unsigned int yAxisId) const {
0556 const string hname = mkAxisCode(datasetId, xAxisId, yAxisId);
0557 return refData<T>(hname);
0558 }
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570 CounterPtr& book(CounterPtr&, const std::string& name);
0571
0572
0573
0574
0575 CounterPtr& book(CounterPtr&, unsigned int datasetID, unsigned int xAxisID, unsigned int yAxisID);
0576
0577
0578
0579
0580
0581
0582
0583
0584 Estimate0DPtr& book(Estimate0DPtr&, const std::string& name);
0585
0586
0587
0588
0589 Estimate0DPtr& book(Estimate0DPtr&, unsigned int datasetID, unsigned int xAxisID, unsigned int yAxisID);
0590
0591
0592
0593
0594
0595
0596
0597
0598 template<size_t DbnN, typename... AxisT, typename = YODA::enable_if_all_CAxisT<AxisT...>>
0599 BinnedDbnPtr<DbnN, AxisT...>& book(BinnedDbnPtr<DbnN, AxisT...>& ao,
0600 const std::string& name, const std::vector<size_t>& nbins,
0601 const std::vector<std::pair<double,double>>& loUpPairs) {
0602 if (nbins.size() != loUpPairs.size()) {
0603 throw RangeError("Vectors should have the same size!");
0604 }
0605 const string path = histoPath(name);
0606
0607 YODA::BinnedDbn<DbnN, AxisT...> yao(nbins, loUpPairs, path);
0608 _setWriterPrecision(path, yao);
0609
0610 return ao = registerAO(yao);
0611 }
0612
0613
0614 Histo1DPtr& book(Histo1DPtr& ao, const std::string& name,
0615 const size_t nbins, const double lower, const double upper) {
0616 return book(ao, name, vector<size_t>{nbins},
0617 vector<pair<double,double>>{{lower,upper}});
0618 }
0619
0620 Profile1DPtr& book(Profile1DPtr& ao, const std::string& name,
0621 const size_t nbins, const double lower, const double upper) {
0622 return book(ao, name, vector<size_t>{nbins},
0623 vector<pair<double,double>>{{lower,upper}});
0624 }
0625
0626
0627 Histo2DPtr& book(Histo2DPtr& ao, const std::string& name,
0628 const size_t nbinsX, const double lowerX, const double upperX,
0629 const size_t nbinsY, const double lowerY, const double upperY) {
0630 return book(ao, name, vector<size_t>{nbinsX,nbinsY},
0631 vector<pair<double,double>>{{lowerX,upperX}, {lowerY,upperY}});
0632 }
0633
0634 Profile2DPtr& book(Profile2DPtr& ao, const std::string& name,
0635 const size_t nbinsX, const double lowerX, const double upperX,
0636 const size_t nbinsY, const double lowerY, const double upperY) {
0637 return book(ao, name, vector<size_t>{nbinsX,nbinsY},
0638 vector<pair<double,double>>{{lowerX,upperX}, {lowerY,upperY}});
0639 }
0640
0641
0642 Histo3DPtr& book(Histo3DPtr& ao, const std::string& name,
0643 const size_t nbinsX, const double lowerX, const double upperX,
0644 const size_t nbinsY, const double lowerY, const double upperY,
0645 const size_t nbinsZ, const double lowerZ, const double upperZ) {
0646 return book(ao, name, vector<size_t>{nbinsX,nbinsY,nbinsZ},
0647 vector<pair<double,double>>{{lowerX,upperX}, {lowerY,upperY}, {lowerZ,upperZ}});
0648 }
0649
0650 Profile3DPtr& book(Profile3DPtr& ao, const std::string& name,
0651 const size_t nbinsX, const double lowerX, const double upperX,
0652 const size_t nbinsY, const double lowerY, const double upperY,
0653 const size_t nbinsZ, const double lowerZ, const double upperZ) {
0654 return book(ao, name, vector<size_t>{nbinsX,nbinsY,nbinsZ},
0655 vector<pair<double,double>>{{lowerX,upperX}, {lowerY,upperY}, {lowerZ,upperZ}});
0656 }
0657
0658
0659 template<size_t DbnN, typename... AxisT>
0660 BinnedDbnPtr<DbnN, AxisT...>& book(BinnedDbnPtr<DbnN, AxisT...>& ao, const std::string& name,
0661 const std::vector<AxisT>&... binedges) {
0662 const string path = histoPath(name);
0663 YODA::BinnedDbn<DbnN, AxisT...> yao(binedges..., path);
0664 _setWriterPrecision(path, yao);
0665
0666 return ao = registerAO(yao);
0667 }
0668
0669
0670 template<size_t DbnN, typename... AxisT>
0671 BinnedDbnPtr<DbnN, AxisT...>& book(BinnedDbnPtr<DbnN, AxisT...>& ao, const std::string& name,
0672 const std::initializer_list<AxisT>&... binedges) {
0673 return book(ao, name, vector<AxisT>{binedges} ...);
0674 }
0675
0676
0677 template<size_t DbnN, typename... AxisT>
0678 BinnedDbnPtr<DbnN, AxisT...>& book(BinnedDbnPtr<DbnN, AxisT...>& ao, const std::string& name,
0679 const YODA::BinnedEstimate<AxisT...>& refest) {
0680 const string path = histoPath(name);
0681
0682 YODA::BinnedDbn<DbnN, AxisT...> yao(refest.binning(), path);
0683 for (const string& a : yao.annotations()) {
0684 if (a != "Path") yao.rmAnnotation(a);
0685 }
0686 _setWriterPrecision(path, yao);
0687 return ao = registerAO(yao);
0688 }
0689
0690
0691 template<size_t DbnN, typename... AxisT>
0692 BinnedDbnPtr<DbnN, AxisT...>& book(BinnedDbnPtr<DbnN, AxisT...>& ao, const std::string& name) {
0693 return book(ao, name, refData<YODA::BinnedEstimate<AxisT...>>(name));
0694 }
0695
0696
0697
0698
0699 template<size_t DbnN, typename... AxisT>
0700 BinnedDbnPtr<DbnN, AxisT...>& book(BinnedDbnPtr<DbnN, AxisT...>& ao, const unsigned int datasetID,
0701 const unsigned int xAxisID, const unsigned int yAxisID) {
0702 const string name = mkAxisCode(datasetID, xAxisID, yAxisID);
0703 return book(ao, name);
0704 }
0705
0706
0707
0708
0709
0710
0711 template <typename GroupAxisT, typename... AxisT>
0712 HistoGroupPtr<GroupAxisT, AxisT...>& book(HistoGroupPtr<GroupAxisT, AxisT...>& ao,
0713 const std::vector<GroupAxisT>& edges,
0714 const std::vector<std::string>& names) {
0715 ao = make_shared<HistoGroup<GroupAxisT, AxisT...>>(edges);
0716 if (ao->numBins() != names.size()) {
0717 throw RangeError("Binning and reference-data names don't match!");
0718 }
0719 for (auto& b : ao->bins()) {
0720 const string& refname = names[b.index()-1];
0721 book(b, refname, refData<YODA::BinnedEstimate<AxisT...>>(refname));
0722 }
0723 return ao;
0724 }
0725
0726 template <typename GroupAxisT, typename... AxisT>
0727 HistoGroupPtr<GroupAxisT, AxisT...>& book(HistoGroupPtr<GroupAxisT, AxisT...>& ao,
0728 const std::vector<GroupAxisT>& edges) {
0729 return ao = make_shared<HistoGroup<GroupAxisT, AxisT...>>(edges);
0730 }
0731
0732 template <typename GroupAxisT, typename... AxisT>
0733 HistoGroupPtr<GroupAxisT, AxisT...>& book(HistoGroupPtr<GroupAxisT, AxisT...>& ao,
0734 std::initializer_list<GroupAxisT>&& edges) {
0735 return ao = make_shared<HistoGroup<GroupAxisT, AxisT...>>(std::move(edges));
0736 }
0737
0738
0739
0740
0741
0742
0743
0744 template<typename... AxisT, typename = YODA::enable_if_all_CAxisT<AxisT...>>
0745 BinnedEstimatePtr<AxisT...>& book(BinnedEstimatePtr<AxisT...>& ao,
0746 const std::string& name, const std::vector<size_t>& nbins,
0747 const std::vector<std::pair<double,double>>& loUpPairs) {
0748 if (nbins.size() != loUpPairs.size()) {
0749 throw RangeError("Vectors should have the same size!");
0750 }
0751 const string path = histoPath(name);
0752
0753 YODA::BinnedEstimate<AxisT...> yao(nbins, loUpPairs, path);
0754 _setWriterPrecision(path, yao);
0755
0756 return ao = registerAO(yao);
0757 }
0758
0759
0760
0761 Estimate1DPtr& book(Estimate1DPtr& ao, const std::string& name,
0762 const size_t nbins, const double lower, const double upper) {
0763 return book(ao, name, vector<size_t>{nbins},
0764 vector<pair<double,double>>{{lower,upper}});
0765 }
0766
0767
0768 Estimate2DPtr& book(Estimate2DPtr& ao, const std::string& name,
0769 const size_t nbinsX, const double lowerX, const double upperX,
0770 const size_t nbinsY, const double lowerY, const double upperY) {
0771 return book(ao, name, vector<size_t>{nbinsX,nbinsY},
0772 vector<pair<double,double>>{{lowerX,upperX}, {lowerY,upperY}});
0773 }
0774
0775
0776 Estimate3DPtr& book(Estimate3DPtr& ao, const std::string& name,
0777 const size_t nbinsX, const double lowerX, const double upperX,
0778 const size_t nbinsY, const double lowerY, const double upperY,
0779 const size_t nbinsZ, const double lowerZ, const double upperZ) {
0780 return book(ao, name, vector<size_t>{nbinsX,nbinsY,nbinsZ},
0781 vector<pair<double,double>>{{lowerX,upperX}, {lowerY,upperY}, {lowerZ,upperZ}});
0782 }
0783
0784
0785 template<typename... AxisT>
0786 BinnedEstimatePtr<AxisT...>& book(BinnedEstimatePtr<AxisT...>& ao, const std::string& name,
0787 const std::vector<AxisT>&... binedges) {
0788 const string path = histoPath(name);
0789 YODA::BinnedEstimate<AxisT...> yao(binedges..., path);
0790 _setWriterPrecision(path, yao);
0791
0792 return ao = registerAO(yao);
0793 }
0794
0795
0796 template<typename... AxisT>
0797 BinnedEstimatePtr<AxisT...>& book(BinnedEstimatePtr<AxisT...>& ao, const std::string& name,
0798 const std::initializer_list<AxisT>&... binedges) {
0799 return book(ao, name, vector<AxisT>{binedges} ...);
0800 }
0801
0802
0803 template<typename... AxisT>
0804 BinnedEstimatePtr<AxisT...>& book(BinnedEstimatePtr<AxisT...>& ao, const std::string& name) {
0805
0806 const string path = histoPath(name);
0807 YODA::BinnedEstimate<AxisT...> yao;
0808 try {
0809 yao = YODA::BinnedEstimate<AxisT...>(refData<YODA::BinnedEstimate<AxisT...>>(name).binning());
0810 } catch (...) {
0811 MSG_DEBUG("Couldn't retrieve reference binning, continue with nullary AO constructor.");
0812 }
0813 yao.setPath(path);
0814 _setWriterPrecision(path, yao);
0815 return ao = registerAO(yao);
0816 }
0817
0818
0819
0820
0821 template<typename... AxisT>
0822 BinnedEstimatePtr<AxisT...>& book(BinnedEstimatePtr<AxisT...>& ao, const unsigned int datasetID,
0823 const unsigned int xAxisID, const unsigned int yAxisID) {
0824 const string name = mkAxisCode(datasetID, xAxisID, yAxisID);
0825 return book(ao, name);
0826 }
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841
0842
0843
0844 template<size_t N>
0845 ScatterNDPtr<N>& book(ScatterNDPtr<N>& snd, const string& name, const bool copy_pts = false) {
0846 const string path = histoPath(name);
0847 YODA::ScatterND<N> scat(path);
0848 if (copy_pts) {
0849 const YODA::ScatterND<N> ref = refData<YODA::EstimateND<N-1>>(name).mkScatter();
0850 for (YODA::PointND<N> p : ref.points()) {
0851 p.setVal(N-1, 0.0);
0852 p.setErr(N-1, 0.0);
0853 scat.addPoint(std::move(p));
0854 }
0855 }
0856 _setWriterPrecision(path, scat);
0857 return snd = registerAO(scat);
0858 }
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870 template<size_t N>
0871 ScatterNDPtr<N>& book(ScatterNDPtr<N>& snd, const unsigned int datasetID, const unsigned int xAxisID,
0872 const unsigned int yAxisID, const bool copy_pts = false) {
0873 const string axisCode = mkAxisCode(datasetID, xAxisID, yAxisID);
0874 return book(snd, axisCode, copy_pts);
0875 }
0876
0877
0878
0879
0880
0881
0882 Scatter2DPtr& book(Scatter2DPtr& snd, const string& name,
0883 const size_t npts, const double lower, const double upper) {
0884 const string path = histoPath(name);
0885
0886 Scatter2D scat(path);
0887 const double binwidth = (upper-lower)/npts;
0888 for (size_t pt = 0; pt < npts; ++pt) {
0889 const double bincentre = lower + (pt + 0.5) * binwidth;
0890 scat.addPoint(bincentre, 0, binwidth/2.0, 0);
0891 }
0892 _setWriterPrecision(path, scat);
0893
0894 return snd = registerAO(scat);
0895 }
0896
0897 Scatter3DPtr& book(Scatter3DPtr& snd, const string& name,
0898 const size_t nptsX, const double lowerX, const double upperX,
0899 const size_t nptsY, const double lowerY, const double upperY) {
0900 const string path = histoPath(name);
0901
0902 Scatter3D scat(path);
0903 const double xbinwidth = (upperX-lowerX)/nptsX;
0904 const double ybinwidth = (upperY-lowerY)/nptsY;
0905 for (size_t xpt = 0; xpt < nptsX; ++xpt) {
0906 const double xbincentre = lowerX + (xpt + 0.5) * xbinwidth;
0907 for (size_t ypt = 0; ypt < nptsY; ++ypt) {
0908 const double ybincentre = lowerY + (ypt + 0.5) * ybinwidth;
0909 scat.addPoint(xbincentre, ybincentre, 0, 0.5*xbinwidth, 0.5*ybinwidth, 0);
0910 }
0911 }
0912 _setWriterPrecision(path, scat);
0913
0914 return snd = registerAO(scat);
0915 }
0916
0917
0918
0919
0920
0921
0922 Scatter2DPtr& book(Scatter2DPtr& snd, const string& name,
0923 const std::vector<double>& binedges) {
0924 const string path = histoPath(name);
0925
0926 Scatter2D scat(path);
0927 for (size_t pt = 0; pt < binedges.size()-1; ++pt) {
0928 const double bincentre = (binedges[pt] + binedges[pt+1]) / 2.0;
0929 const double binwidth = binedges[pt+1] - binedges[pt];
0930 scat.addPoint(bincentre, 0, binwidth/2.0, 0);
0931 }
0932 _setWriterPrecision(path, scat);
0933
0934 return snd = registerAO(scat);
0935 }
0936
0937 Scatter3DPtr& book(Scatter3DPtr& snd, const string& name,
0938 const std::vector<double>& binedgesX,
0939 const std::vector<double>& binedgesY) {
0940 const string path = histoPath(name);
0941
0942 Scatter3D scat(path);
0943 for (size_t xpt = 0; xpt < binedgesX.size()-1; ++xpt) {
0944 const double xbincentre = (binedgesX[xpt] + binedgesX[xpt+1]) / 2.0;
0945 const double xbinwidth = binedgesX[xpt+1] - binedgesX[xpt];
0946 for (size_t ypt = 0; ypt < binedgesY.size()-1; ++ypt) {
0947 const double ybincentre = (binedgesY[ypt] + binedgesY[ypt+1]) / 2.0;
0948 const double ybinwidth = binedgesY[ypt+1] - binedgesY[ypt];
0949 scat.addPoint(xbincentre, ybincentre, 0, 0.5*xbinwidth, 0.5*ybinwidth, 0);
0950 }
0951 }
0952 _setWriterPrecision(path, scat);
0953
0954 return snd = registerAO(scat);
0955 }
0956
0957
0958 template<size_t N>
0959 ScatterNDPtr<N>& book(ScatterNDPtr<N>& snd, const string& name, const YODA::ScatterND<N>& refscatter) {
0960 const string path = histoPath(name);
0961
0962 YODA::ScatterND<N> scat(refscatter, path);
0963 for (const string& a : scat.annotations()) {
0964 if (a != "Path") scat.rmAnnotation(a);
0965 }
0966 _setWriterPrecision(path, scat);
0967
0968 return snd = registerAO(scat);
0969 }
0970
0971
0972
0973
0974
0975
0976
0977 CutflowPtr& book(CutflowPtr& ao, const string& name, const std::vector<std::string>& edges) {
0978 const string path = histoPath(name);
0979 Cutflow yao(edges, path);
0980 _setWriterPrecision(path, yao);
0981 return ao = registerAO(yao);
0982 }
0983
0984
0985 CutflowPtr& book(CutflowPtr& ao, const string& name, const std::initializer_list<std::string>& edges) {
0986 return book(ao, name, vector<std::string>{edges});
0987 }
0988
0989
0990
0991
0992
0993
0994 CutflowsPtr& book(CutflowsPtr& ao, const std::vector<std::string>& edges,
0995 const std::vector<std::vector<std::string>>& innerEdges) {
0996 ao = make_shared<Cutflows>(edges);
0997 if (ao->numBins() !=innerEdges.size()) {
0998 throw RangeError("Outer and Inner edges don't match");
0999 }
1000 for (auto& b : ao->bins()) {
1001 book(b, b.xEdge(), innerEdges[b.index()-1]);
1002 }
1003 return ao;
1004 }
1005
1006 CutflowsPtr& book(CutflowsPtr& ao, const std::vector<std::string>& edges) {
1007 return ao = make_shared<Cutflows>(edges);
1008 }
1009
1010 CutflowsPtr& book(CutflowsPtr& ao, std::initializer_list<std::string>&& edges) {
1011 return ao = make_shared<Cutflows>(std::move(edges));
1012 }
1013
1014
1015
1016
1017
1018
1019
1020 virtual void rawHookIn(YODA::AnalysisObjectPtr yao) {
1021 (void) yao;
1022 }
1023
1024
1025
1026
1027 virtual void rawHookOut(const vector<MultiplexAOPtr>& raos, size_t iW) {
1028 (void) raos;
1029 (void) iW;
1030 }
1031
1032
1033 public:
1034
1035
1036
1037
1038
1039 const std::map<std::string,std::string>& options() const {
1040 return _options;
1041 }
1042
1043
1044 std::string getOption(std::string optname, string def="") const {
1045 if ( _options.find(optname) != _options.end() )
1046 return _options.find(optname)->second;
1047 return def;
1048 }
1049
1050
1051
1052
1053
1054 std::string getOption(std::string optname, const char* def) {
1055 return getOption<std::string>(optname, def);
1056 }
1057
1058
1059
1060
1061
1062
1063
1064
1065 template<typename T>
1066 T getOption(std::string optname, T def) const {
1067 if (_options.find(optname) == _options.end()) return def;
1068 std::stringstream ss;
1069 ss.exceptions(std::ios::failbit);
1070 T ret;
1071 ss << _options.find(optname)->second;
1072 try {
1073 ss >> ret;
1074 } catch (...) {
1075 throw ReadError("Could not read user-provided option into requested type");
1076 }
1077 return ret;
1078 }
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092 bool getOption(std::string optname, bool def) const {
1093 if (_options.find(optname) == _options.end()) return def;
1094 const std::string val = getOption(optname);
1095 const std::string lval = toLower(val);
1096 if (lval.empty()) return false;
1097 if (lval == "true" || lval == "yes" || lval == "on") return true;
1098 if (lval == "false" || lval == "no" || lval == "off") return false;
1099 return bool(getOption<int>(optname, 0));
1100 }
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124 const CentralityProjection&
1125 declareCentrality(const SingleValueProjection &proj,
1126 string calAnaName, string calHistName,
1127 const string projName,
1128 PercentileOrder pctorder=PercentileOrder::DECREASING);
1129
1130
1131
1132
1133
1134
1135
1136
1137 template<typename T>
1138 Percentile<T> book(const string& projName,
1139 const vector<pair<double, double>>& centralityBins,
1140 const vector<tuple<size_t, size_t, size_t>>& ref) {
1141
1142 using RefT = typename ReferenceTraits<T>::RefT;
1143 using WrapT = MultiplexPtr<Multiplexer<T>>;
1144
1145 Percentile<T> pctl(this, projName);
1146
1147 const size_t nCent = centralityBins.size();
1148 for (size_t iCent = 0; iCent < nCent; ++iCent) {
1149 const string axisCode = mkAxisCode(std::get<0>(ref[iCent]),
1150 std::get<1>(ref[iCent]),
1151 std::get<2>(ref[iCent]));
1152 const RefT& refscatter = refData<RefT>(axisCode);
1153
1154 WrapT wtf(_weightNames(), T(refscatter, histoPath(axisCode)));
1155 wtf = addAnalysisObject(wtf);
1156
1157 CounterPtr cnt(_weightNames(), Counter(histoPath("TMP/COUNTER/" + axisCode)));
1158 cnt = addAnalysisObject(cnt);
1159
1160 pctl.add(wtf, cnt, centralityBins[iCent]);
1161 }
1162 return pctl;
1163 }
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201 private:
1202
1203
1204
1205
1206 vector<string> _weightNames() const;
1207
1208
1209 YODA::AnalysisObjectPtr _getPreload (const string& name) const;
1210
1211
1212 MultiplexAOPtr _getOtherAnalysisObject(const std::string & ananame, const std::string& name);
1213
1214
1215 void _checkBookInit() const;
1216
1217
1218 bool _inInit() const;
1219
1220
1221 bool _inFinalize() const;
1222
1223
1224 template <typename YODAT>
1225 void _setWriterPrecision(const string& path, YODAT& yao) {
1226 const string re = _info->writerDoublePrecision();
1227 if (re != "") {
1228 std::smatch match;
1229 const bool needsDP = std::regex_search(path, match, std::regex(re));
1230 if (needsDP) yao.setAnnotation("WriterDoublePrecision", "1");
1231 }
1232 }
1233
1234
1235 private:
1236
1237
1238 class CounterAdapter {
1239 public:
1240
1241 CounterAdapter(double x) : x_(x) {}
1242
1243 CounterAdapter(const YODA::Counter& c) : x_(c.val()) {}
1244
1245 CounterAdapter(const YODA::Estimate& e) : x_(e.val()) {}
1246
1247 CounterAdapter(const YODA::Scatter1D& s) : x_(s.points()[0].x()) {
1248 if (s.numPoints() != 1) throw RangeError("Can only scale by a single value.");
1249 }
1250
1251 operator double() const { return x_; }
1252
1253 private:
1254 double x_;
1255
1256 };
1257
1258
1259 public:
1260
1261 double dbl(double x) { return x; }
1262 double dbl(const YODA::Counter& c) { return c.val(); }
1263 double dbl(const YODA::Estimate0D& e) { return e.val(); }
1264 double dbl(const YODA::Scatter1D& s) {
1265 if ( s.numPoints() != 1 ) throw RangeError("Only scatter with single value supported.");
1266 return s.points()[0].x();
1267 }
1268
1269
1270 protected:
1271
1272
1273
1274
1275
1276
1277 template<typename T>
1278 void scale(MultiplexPtr<Multiplexer<T>>& ao, CounterAdapter factor) {
1279 if (!ao) {
1280 MSG_WARNING("Failed to scale AnalysisObject=NULL in analysis "
1281 << name() << " (scale=" << double(factor) << ")");
1282 return;
1283 }
1284 if (std::isnan(double(factor)) || std::isinf(double(factor))) {
1285 MSG_WARNING("Failed to scale AnalysisObject=" << ao->path() << " in analysis: "
1286 << name() << " (invalid scale factor = " << double(factor) << ")");
1287 factor = 0;
1288 }
1289 MSG_TRACE("Scaling AnalysisObject " << ao->path() << " by factor " << double(factor));
1290 try {
1291 if constexpr( isFillable<T>::value ) {
1292 ao->scaleW(factor);
1293 }
1294 else {
1295 ao->scale(factor);
1296 }
1297 }
1298 catch (YODA::Exception& we) {
1299 MSG_WARNING("Could not scale AnalysisObject " << ao->path());
1300 return;
1301 }
1302 }
1303
1304
1305 template<typename GroupAxisT, typename... AxisT>
1306 void scale(HistoGroupPtr<GroupAxisT, AxisT...>& group, CounterAdapter factor) {
1307 if (!group) {
1308 MSG_WARNING("Failed to scale AnalysisObject=NULL in analysis "
1309 << name() << " (scale=" << double(factor) << ")");
1310 return;
1311 }
1312 if (std::isnan(double(factor)) || std::isinf(double(factor))) {
1313 MSG_WARNING("Failed to scale histo group in analysis: "
1314 << name() << " (invalid scale factor = " << double(factor) << ")");
1315 factor = 0;
1316 }
1317 MSG_TRACE("Scaling histo group by factor " << double(factor));
1318 try {
1319 group->scaleW(factor);
1320 }
1321 catch (YODA::Exception& we) {
1322 MSG_WARNING("Could not scale histo group.");
1323 return;
1324 }
1325 }
1326
1327
1328 template<typename GroupAxisT, typename... AxisT>
1329 void scale(HistoGroupPtr<GroupAxisT, AxisT...>& group, const vector<double>& factors) {
1330 if (!group) {
1331 MSG_WARNING("Failed to scale AnalysisObject=NULL in analysis " << name());
1332 return;
1333 }
1334 if (group->numBins(true) != factors.size()) {
1335 throw RangeError(name() + ": Number of scale factors does not match group binning");
1336 return;
1337 }
1338 for (auto& b : group->bins(true)) {
1339 if (!b.get()) continue;
1340 double factor = factors[b.index()];
1341 if (std::isnan(factor) || std::isinf(factor)) {
1342 MSG_WARNING("Failed to scale componment of histo group in analysis: "
1343 << name() << " (invalid scale factor = " << factor << ")");
1344 factor = 0;
1345 }
1346 MSG_TRACE("Scaling histo group element by factor " << factor);
1347 try {
1348 b->scaleW(factor);
1349 }
1350 catch (YODA::Exception& we) {
1351 MSG_WARNING("Could not scale component of histo group.");
1352 }
1353 }
1354 }
1355
1356
1357 void scale(CutflowsPtr& group, CounterAdapter factor) {
1358 if (!group) {
1359 MSG_WARNING("Failed to scale AnalysisObject=NULL in analysis "
1360 << name() << " (scale=" << double(factor) << ")");
1361 return;
1362 }
1363 if (std::isnan(double(factor)) || std::isinf(double(factor))) {
1364 MSG_WARNING("Failed to scale histo group in analysis: "
1365 << name() << " (invalid scale factor = " << double(factor) << ")");
1366 factor = 0;
1367 }
1368 MSG_TRACE("Scaling histo group by factor " << double(factor));
1369 try {
1370 group->scale(factor);
1371 }
1372 catch (YODA::Exception& we) {
1373 MSG_WARNING("Could not scale histo group.");
1374 return;
1375 }
1376 }
1377
1378
1379 template<typename T, typename U>
1380 void scale(std::map<T, U>& aos, CounterAdapter factor) {
1381 for (auto& item : aos) scale(item.second, factor);
1382 }
1383
1384
1385 template <typename AORange, typename = std::enable_if_t<YODA::isIterable<AORange>>>
1386 void scale(AORange& aos, CounterAdapter factor) {
1387 for (auto& ao : aos) scale(ao, factor);
1388 }
1389
1390
1391 template <typename T>
1392 void scale(std::initializer_list<T> aos, CounterAdapter factor) {
1393 for (auto& ao : std::vector<T>{aos}) scale(ao, factor);
1394 }
1395
1396
1397 template<typename T, typename U>
1398 void scale(std::map<T, U>& aos, const vector<double>& factors) {
1399 for (auto& item : aos) scale(item.second, factors);
1400 }
1401
1402
1403 template <typename AORange, typename = std::enable_if_t<YODA::isIterable<AORange>>>
1404 void scale(AORange& aos, const vector<double>& factors) {
1405 for (auto& ao : aos) scale(ao, factors);
1406 }
1407
1408
1409 template <typename T>
1410 void scale(std::initializer_list<T> aos, const vector<double>& factors) {
1411 for (auto& ao : std::vector<T>{aos}) scale(ao, factors);
1412 }
1413
1414
1415 template<typename GroupAxisT, typename... AxisT>
1416 void divByGroupWidth(HistoGroupPtr<GroupAxisT, AxisT...>& group) {
1417 if (!group) {
1418 MSG_WARNING("Failed to scale HistoGroup=NULL in analysis "
1419 << name() << " by group axis width");
1420 return;
1421 }
1422 group->divByGroupWidth();
1423 }
1424
1425
1426 template<typename T, typename U>
1427 void divByGroupWidth(std::map<T, U>& aos) {
1428 for (auto& item : aos) divByGroupWidth(item.second);
1429 }
1430
1431
1432 template <typename AORange, typename = std::enable_if_t<YODA::isIterable<AORange>>>
1433 void divByGroupWidth(AORange& aos) {
1434 for (auto& ao : aos) divByGroupWidth(ao);
1435 }
1436
1437
1438 template <typename T>
1439 void divByGroupWidth(std::initializer_list<T> aos) {
1440 for (auto& ao : std::vector<T>{aos}) divByGroupWidth(ao);
1441 }
1442
1443
1444
1445 template <size_t DbnN, typename... AxisT>
1446 void normalize(BinnedDbnPtr<DbnN, AxisT...> ao, const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1447 if (!ao) {
1448 MSG_WARNING("Failed to normalize histo=NULL in analysis " << name() << " (norm=" << double(norm) << ")");
1449 return;
1450 }
1451 MSG_TRACE("Normalizing histo " << ao->path() << " to " << double(norm));
1452 try {
1453 const double hint = ao->integral(includeoverflows);
1454 if (hint == 0) MSG_DEBUG("Skipping histo with null area " << ao->path());
1455 else ao->normalize(norm, includeoverflows);
1456 }
1457 catch (YODA::Exception& we) {
1458 MSG_WARNING("Could not normalize histo " << ao->path());
1459 return;
1460 }
1461 }
1462
1463
1464 template <typename GroupAxisT, typename... AxisT>
1465 void normalize(HistoGroupPtr<GroupAxisT, AxisT...> group, const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1466 if (!group) {
1467 MSG_WARNING("Failed to normalize histo=NULL in analysis " << name() << " (norm=" << double(norm) << ")");
1468 return;
1469 }
1470 MSG_TRACE("Normalizing histo group to " << double(norm));
1471 try {
1472 const double hint = group->integral(includeoverflows);
1473 if (hint == 0) MSG_DEBUG("Skipping histo group with null area.");
1474 else group->normalize(norm, includeoverflows);
1475 }
1476 catch (YODA::Exception& we) {
1477 MSG_WARNING("Could not normalize histo group.");
1478 return;
1479 }
1480 }
1481
1482
1483
1484 template <typename AORange, typename = std::enable_if_t<YODA::isIterable<AORange>>>
1485 void normalize(AORange& aos, const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1486 for (auto& ao : aos) normalize(ao, norm, includeoverflows);
1487 }
1488
1489
1490 template<typename T>
1491 void normalize(std::initializer_list<T>&& aos, const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1492 for (auto& ao : aos) normalize(ao, norm, includeoverflows);
1493 }
1494
1495
1496 template<typename T, typename U>
1497 void normalize(std::map<T, U>& aos,
1498 const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1499 for (auto& item : aos) normalize(item.second, norm, includeoverflows);
1500 }
1501
1502
1503 template <typename GroupAxisT, typename... AxisT>
1504 void normalizeGroup(HistoGroupPtr<GroupAxisT, AxisT...> group, const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1505 if (!group) {
1506 MSG_WARNING("Failed to normalize histo=NULL in analysis " << name() << " (norm=" << double(norm) << ")");
1507 return;
1508 }
1509 MSG_TRACE("Normalizing histo group to " << double(norm));
1510 try {
1511 const double hint = group->integral(includeoverflows);
1512 if (hint == 0) MSG_DEBUG("Skipping histo group with null area.");
1513 else group->normalizeGroup(norm, includeoverflows);
1514 }
1515 catch (YODA::Exception& we) {
1516 MSG_WARNING("Could not normalize histo group.");
1517 return;
1518 }
1519 }
1520
1521
1522 template <typename AORange, typename = std::enable_if_t<YODA::isIterable<AORange>>>
1523 void normalizeGroup(AORange& aos, const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1524 for (auto& ao : aos) normalizeGroup(ao, norm, includeoverflows);
1525 }
1526
1527
1528 template<typename T>
1529 void normalizeGroup(std::initializer_list<T>&& aos, const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1530 for (auto& ao : aos) normalizeGroup(ao, norm, includeoverflows);
1531 }
1532
1533
1534 template<typename T, typename U>
1535 void normalizeGroup(std::map<T, U>& aos,
1536 const CounterAdapter norm=1.0, const bool includeoverflows=true) {
1537 for (auto& item : aos) normalizeGroup(item.second, norm, includeoverflows);
1538 }
1539
1540
1541
1542
1543
1544
1545 template<size_t DbnN, typename... AxisT>
1546 void barchart(BinnedDbnPtr<DbnN, AxisT...> ao, BinnedEstimatePtr<AxisT...> est) const {
1547 const string path = est->path();
1548 *est = ao->mkEstimate(path, "stats", false);
1549 }
1550
1551
1552
1553
1554 void divide(CounterPtr c1, CounterPtr c2, Estimate0DPtr est) const;
1555
1556
1557
1558
1559 void divide(const YODA::Counter& c1, const YODA::Counter& c2, Estimate0DPtr est) const;
1560
1561
1562
1563
1564 void divide(Estimate0DPtr e1, Estimate0DPtr e2, Estimate0DPtr est) const;
1565
1566
1567
1568
1569 void divide(const YODA::Estimate0D& e1, const YODA::Estimate0D& e2, Estimate0DPtr est) const;
1570
1571
1572
1573
1574
1575 template<size_t DbnN, typename... AxisT>
1576 void divide(const YODA::BinnedDbn<DbnN, AxisT...>& h1, const YODA::BinnedDbn<DbnN, AxisT...>& h2,
1577 BinnedEstimatePtr<AxisT...> est) const {
1578 const string path = est->path();
1579 *est = h1 / h2;
1580 est->setPath(path);
1581 }
1582
1583 template<size_t DbnN, typename... AxisT>
1584 void divide(BinnedDbnPtr<DbnN, AxisT...> h1, BinnedDbnPtr<DbnN, AxisT...> h2,
1585 BinnedEstimatePtr<AxisT...> est) const {
1586 return divide(*h1, *h2, est);
1587 }
1588
1589
1590
1591
1592 template<typename... AxisT>
1593 void divide(const YODA::BinnedEstimate<AxisT...>& e1, const YODA::BinnedEstimate<AxisT...>& e2,
1594 BinnedEstimatePtr<AxisT...> est) const {
1595 const string path = est->path();
1596 *est = e1 / e2;
1597 est->setPath(path);
1598 }
1599
1600 template<typename... AxisT>
1601 void divide(BinnedEstimatePtr<AxisT...> e1, BinnedEstimatePtr<AxisT...> e2,
1602 BinnedEstimatePtr<AxisT...> est) const {
1603 return divide(*e1, *e2, est);
1604 }
1605
1606
1607
1608
1609
1610
1611 void efficiency(CounterPtr c1, CounterPtr c2, Estimate0DPtr est) const {
1612 efficiency(*c1, *c2, est);
1613 }
1614
1615
1616
1617
1618 void efficiency(const YODA::Counter& c1, const YODA::Counter& c2, Estimate0DPtr est) const {
1619 const string path = est->path();
1620 *est = YODA::efficiency(c1, c2);
1621 est->setPath(path);
1622 }
1623
1624
1625
1626
1627
1628
1629 template<size_t DbnN, typename... AxisT>
1630 void efficiency(const YODA::BinnedDbn<DbnN, AxisT...>& h1, const YODA::BinnedDbn<DbnN, AxisT...>& h2,
1631 BinnedEstimatePtr<AxisT...> est) const {
1632 const string path = est->path();
1633 *est = YODA::efficiency(h1, h2);
1634 est->setPath(path);
1635 }
1636
1637 template<size_t DbnN, typename... AxisT>
1638 void efficiency(BinnedDbnPtr<DbnN, AxisT...> h1, BinnedDbnPtr<DbnN, AxisT...> h2,
1639 BinnedEstimatePtr<AxisT...> est) const {
1640 efficiency(*h1, *h2, est);
1641 }
1642
1643
1644
1645
1646
1647 template<typename... AxisT>
1648 void efficiency(const YODA::BinnedEstimate<AxisT...>& e1, const YODA::BinnedEstimate<AxisT...>& e2,
1649 BinnedEstimatePtr<AxisT...> est) const {
1650 const string path = est->path();
1651 *est = YODA::efficiency(e1, e2);
1652 est->setPath(path);
1653 }
1654
1655 template<typename... AxisT>
1656 void efficiency(BinnedEstimatePtr<AxisT...> e1, BinnedEstimatePtr<AxisT...> e2,
1657 BinnedEstimatePtr<AxisT...> est) const {
1658 efficiency(*e1, *e2, est);
1659 }
1660
1661
1662
1663
1664
1665 template<size_t DbnN, typename... AxisT>
1666 void asymm(const YODA::BinnedDbn<DbnN, AxisT...>& h1, const YODA::BinnedDbn<DbnN, AxisT...>& h2,
1667 BinnedEstimatePtr<AxisT...> est) const {
1668 const string path = est->path();
1669 *est = YODA::asymm(h1, h2);
1670 est->setPath(path);
1671 }
1672
1673 template<size_t DbnN, typename... AxisT>
1674 void asymm(BinnedDbnPtr<DbnN, AxisT...> h1, BinnedDbnPtr<DbnN, AxisT...> h2,
1675 BinnedEstimatePtr<AxisT...> est) const {
1676 asymm(*h1, *h2, est);
1677 }
1678
1679
1680
1681
1682 template<typename... AxisT>
1683 void asymm(const YODA::BinnedEstimate<AxisT...>& e1, const YODA::BinnedEstimate<AxisT...>& e2,
1684 BinnedEstimatePtr<AxisT...> est) const {
1685 const string path = est->path();
1686 *est = YODA::asymm(e1, e2);
1687 est->setPath(path);
1688 }
1689
1690 template<typename... AxisT>
1691 void asymm(BinnedEstimatePtr<AxisT...> e1, BinnedEstimatePtr<AxisT...> e2,
1692 BinnedEstimatePtr<AxisT...> est) const {
1693 asymm(*e1, *e2, est);
1694 }
1695
1696
1697
1698
1699 template<size_t DbnN, typename... AxisT>
1700 void integrate(const YODA::BinnedDbn<DbnN, AxisT...>& h, BinnedEstimatePtr<AxisT...> est) const {
1701 const string path = est->path();
1702 *est = mkIntegral(h);
1703 est->setPath(path);
1704 }
1705
1706 template<size_t DbnN, typename... AxisT>
1707 void integrate(BinnedDbnPtr<DbnN, AxisT...>& h, BinnedEstimatePtr<AxisT...> est) const {
1708 integrate(*h, est);
1709 }
1710
1711
1712
1713
1714 public:
1715
1716
1717 const vector<MultiplexAOPtr>& analysisObjects() const {
1718 return _analysisobjects;
1719 }
1720
1721
1722 protected:
1723
1724
1725
1726
1727
1728 size_t defaultWeightIndex() const;
1729
1730
1731 template <typename YODAT>
1732 shared_ptr<YODAT> getPreload(const string& path) const {
1733 return dynamic_pointer_cast<YODAT>(_getPreload(path));
1734 }
1735
1736
1737
1738 template <typename YODAT>
1739 MultiplexPtr< Multiplexer<YODAT> > registerAO(const YODAT& yao) {
1740 using MultiplexerT = Multiplexer<YODAT>;
1741 using YODAPtrT = shared_ptr<YODAT>;
1742 using RAOT = MultiplexPtr<MultiplexerT>;
1743
1744 if ( !_inInit() && !_inFinalize() ) {
1745 MSG_ERROR("Can't book objects outside of init() or finalize()");
1746 throw UserError(name() + ": Can't book objects outside of init() or finalize().");
1747 }
1748
1749
1750
1751
1752 for (auto& waold : analysisObjects()) {
1753 if ( yao.path() == waold.get()->basePath() ) {
1754 const string msg = "Found double-booking of " + yao.path() + " in " + name();
1755 if ( _inInit() ) {
1756 MSG_ERROR(msg);
1757 throw LookupError(msg);
1758 } else {
1759 MSG_WARNING(msg + ". Keeping previous booking");
1760 }
1761 return RAOT(dynamic_pointer_cast<MultiplexerT>(waold.get()));
1762 }
1763 }
1764
1765 shared_ptr<MultiplexerT> wao = make_shared<MultiplexerT>();
1766 wao->_basePath = yao.path();
1767 YODAPtrT yaop = make_shared<YODAT>(yao);
1768
1769 for (const string& weightname : _weightNames()) {
1770
1771
1772 string finalpath = yao.path();
1773 if ( weightname != "" ) finalpath += "[" + weightname + "]";
1774 YODAPtrT preload = getPreload<YODAT>(finalpath);
1775 if ( preload ) {
1776 if ( !bookingCompatible(preload, yaop) ) {
1777
1778 MSG_WARNING("Found incompatible pre-existing data object with same base path "
1779 << finalpath << " for " << name());
1780 preload = nullptr;
1781 } else {
1782 MSG_TRACE("Using preloaded " << finalpath << " in " <<name());
1783 wao->_final.push_back(make_shared<YODAT>(*preload));
1784 }
1785 }
1786 else {
1787 wao->_final.push_back(make_shared<YODAT>(yao));
1788 wao->_final.back()->setPath(finalpath);
1789 }
1790
1791
1792 string rawpath = "/RAW" + finalpath;
1793 preload = getPreload<YODAT>(rawpath);
1794 if ( preload ) {
1795 if ( !bookingCompatible(preload, yaop) ) {
1796 MSG_WARNING("Found incompatible pre-existing data object with same base path "
1797 << rawpath << " for " << name());
1798 preload = nullptr;
1799 } else {
1800 MSG_TRACE("Using preloaded " << rawpath << " in " <<name());
1801 wao->_persistent.push_back(make_shared<YODAT>(*preload));
1802 }
1803 }
1804 else {
1805 wao->_persistent.push_back(make_shared<YODAT>(yao));
1806 wao->_persistent.back()->setPath(rawpath);
1807 }
1808 }
1809 MultiplexPtr<MultiplexerT> ret(wao);
1810
1811 ret.get()->unsetActiveWeight();
1812 if ( _inFinalize() ) {
1813
1814
1815 ret.get()->pushToFinal();
1816 ret.get()->setActiveFinalWeightIdx(0);
1817 }
1818 _analysisobjects.push_back(ret);
1819
1820 return ret;
1821 }
1822
1823
1824
1825 template <typename AO=MultiplexAOPtr>
1826 AO addAnalysisObject(const AO& aonew) {
1827 _checkBookInit();
1828
1829 for (const MultiplexAOPtr& ao : analysisObjects()) {
1830
1831
1832 ao.get()->setActiveWeightIdx(defaultWeightIndex());
1833 aonew.get()->setActiveWeightIdx(defaultWeightIndex());
1834 if (ao->path() != aonew->path()) continue;
1835
1836
1837
1838 AO aoold = AO(dynamic_pointer_cast<typename AO::value_type>(ao.get()));
1839 if ( !aoold || !bookingCompatible(aonew, aoold) ) {
1840 MSG_WARNING("Found incompatible pre-existing data object with same base path "
1841 << aonew->path() << " for " << name());
1842 throw LookupError("Found incompatible pre-existing data object with same base path during AO booking");
1843 }
1844
1845
1846 for (size_t weightIdx = 0; weightIdx < _weightNames().size(); ++weightIdx) {
1847 aoold.get()->setActiveWeightIdx(weightIdx);
1848 aonew.get()->setActiveWeightIdx(weightIdx);
1849 if (aoold->path() != aonew->path()) {
1850 MSG_WARNING("Found incompatible pre-existing data object with different weight-path "
1851 << aonew->path() << " for " << name());
1852 throw LookupError("Found incompatible pre-existing data object with same weight-path during AO booking");
1853 }
1854 }
1855
1856
1857 aoold.get()->unsetActiveWeight();
1858 MSG_TRACE("Bound pre-existing data object " << aoold->path() << " for " << name());
1859 return aoold;
1860 }
1861
1862
1863 MSG_TRACE("Registered " << aonew->annotation("Type") << " " << aonew->path() << " for " << name());
1864 aonew.get()->unsetActiveWeight();
1865
1866 _analysisobjects.push_back(aonew);
1867 return aonew;
1868 }
1869
1870
1871 void removeAnalysisObject(const std::string& path);
1872
1873
1874 void removeAnalysisObject(const MultiplexAOPtr& ao);
1875
1876
1877 template <typename AO=MultiplexAOPtr>
1878 const AO getAnalysisObject(const std::string& aoname) const {
1879 for (const MultiplexAOPtr& ao : analysisObjects()) {
1880 ao.get()->setActiveWeightIdx(defaultWeightIndex());
1881 if (ao->path() == histoPath(aoname)) {
1882
1883 return AO(dynamic_pointer_cast<typename AO::value_type>(ao.get()));
1884 }
1885 }
1886 throw LookupError("Data object " + histoPath(aoname) + " not found");
1887 }
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911 template <typename AO=MultiplexAOPtr>
1912 AO getAnalysisObject(const std::string& ananame,
1913 const std::string& aoname) {
1914 MultiplexAOPtr ao = _getOtherAnalysisObject(ananame, aoname);
1915
1916 return AO(dynamic_pointer_cast<typename AO::value_type>(ao.get()));
1917 }
1918
1919
1920
1921
1922
1923
1924
1925 template <
1926 typename... Args, typename CONTAINER,
1927 typename = std::enable_if_t<
1928 is_citerable_v<CONTAINER>,
1929 Jet
1930 >
1931 >
1932 static CONTAINER reclusterJets(const CONTAINER &jetsIn, Args&&... args){
1933 return FastJets::reclusterJets(jetsIn, std::forward<Args>(args)...);
1934 }
1935
1936 template <typename T, typename U, typename... Args>
1937 static std::map<T, U> reclusterJets(const std::map<T, U> &jetsMap, Args&&... args){
1938 return FastJets::reclusterJets(jetsMap, std::forward<Args>(args)...);
1939 }
1940
1941 template <
1942 JetAlg JETALG, typename... Args, typename CONTAINER,
1943 typename = std::enable_if_t<
1944 is_citerable_v<CONTAINER>,
1945 Jet
1946 >
1947 >
1948 static CONTAINER reclusterJets(const CONTAINER &jetsIn, Args&&... args){
1949 return FastJets::reclusterJets<JETALG>(jetsIn, std::forward<Args>(args)...);
1950 }
1951
1952 template <JetAlg JETALG, typename T, typename U, typename... Args>
1953 static std::map<T, U> reclusterJets(const std::map<T, U> &jetsMap, Args&&... args){
1954 return FastJets::reclusterJets<JETALG>(jetsMap, std::forward<Args>(args)...);
1955 }
1956
1957
1958
1959
1960 private:
1961
1962
1963 string _defaultname;
1964
1965
1966 unique_ptr<AnalysisInfo> _info;
1967
1968
1969
1970 vector<MultiplexAOPtr> _analysisobjects;
1971
1972
1973
1974 double _crossSection;
1975 bool _gotCrossSection;
1976
1977
1978
1979 AnalysisHandler* _analysishandler;
1980
1981
1982 const Event* _currentevent = nullptr;
1983
1984
1985
1986 mutable std::map<std::string, YODA::AnalysisObjectPtr> _refdata;
1987
1988
1989 map<string, string> _options;
1990
1991
1992 string _optstring;
1993
1994
1995 private:
1996
1997
1998
1999
2000
2001 void _cacheRefData() const;
2002
2003
2004
2005 };
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015 }
2016
2017
2018
2019 #include "Rivet/AnalysisBuilder.hh"
2020
2021
2022
2023
2024
2025
2026
2027 #define RIVET_DECLARE_PLUGIN(clsname) ::Rivet::AnalysisBuilder<clsname> plugin_ ## clsname
2028
2029
2030
2031 #define RIVET_DECLARE_ALIASED_PLUGIN(clsname, alias) RIVET_DECLARE_PLUGIN(clsname)( #alias )
2032
2033
2034
2035 #define RIVET_DEFAULT_ANALYSIS_CTOR(clsname) clsname() : Analysis(# clsname) {}
2036
2037
2038
2039 #define RIVET_REGISTER_TYPE(...) handler().registerType<__VA_ARGS__>()
2040
2041
2042
2043 #define RIVET_REGISTER_BINNED_SET(...) { \
2044 RIVET_REGISTER_TYPE(YODA::BinnedHisto<__VA_ARGS__>); \
2045 RIVET_REGISTER_TYPE(YODA::BinnedProfile<__VA_ARGS__>); \
2046 RIVET_REGISTER_TYPE(YODA::BinnedEstimate<__VA_ARGS__>); }
2047
2048
2049
2050
2051 #endif