GenXSecAnalyzer

LumiCache

RunCache

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "TMath.h"
#include <iostream>
#include <iomanip>

// analyzer of a summary information product on filter efficiency for a user specified path
// meant for the generator filter efficiency calculation

// system include files
#include <memory>
#include <vector>
#include <map>

// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/global/EDAnalyzer.h"

#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/Run.h"
#include "FWCore/Framework/interface/EventSetup.h"
#include "FWCore/Framework/interface/LuminosityBlock.h"
#include "FWCore/Utilities/interface/InputTag.h"
#include "FWCore/Utilities/interface/thread_safety_macros.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "SimDataFormats/GeneratorProducts/interface/GenLumiInfoProduct.h"
#include "SimDataFormats/GeneratorProducts/interface/GenFilterInfo.h"
#include "SimDataFormats/GeneratorProducts/interface/LHERunInfoProduct.h"

#include "FWCore/Framework/interface/MakerMacros.h"

//
// class declaration
//
namespace gxsec {
  struct LumiCache {};
  struct RunCache {
    RunCache()
        : product_(-9999),
          filterOnlyEffRun_(0, 0, 0, 0, 0., 0., 0., 0.),
          hepMCFilterEffRun_(0, 0, 0, 0, 0., 0., 0., 0.) {}
    // for weight before GenFilter and HepMCFilter and before matching
    CMS_THREAD_GUARD(GenXSecAnalyzer::mutex_) mutable double thisRunWeightPre_ = 0;

    // for weight after GenFilter and HepMCFilter and after matching
    CMS_THREAD_GUARD(GenXSecAnalyzer::mutex_) mutable double thisRunWeight_ = 0;

    // GenLumiInfo before HepMCFilter and GenFilter, this is used
    // for computation
    CMS_THREAD_GUARD(GenXSecAnalyzer::mutex_) mutable GenLumiInfoProduct product_;

    // statistics from additional generator filter, for computation
    // reset for each run
    CMS_THREAD_GUARD(GenXSecAnalyzer::mutex_) mutable GenFilterInfo filterOnlyEffRun_;

    // statistics from HepMC filter, for computation
    CMS_THREAD_GUARD(GenXSecAnalyzer::mutex_) mutable GenFilterInfo hepMCFilterEffRun_;

    // the following vectors all have the same size
    // LHE or Pythia/Herwig cross section of previous luminosity block
    // vector size = number of processes, used for computation
    CMS_THREAD_GUARD(GenXSecAnalyzer::mutex_) mutable std::map<int, GenLumiInfoProduct::XSec> previousLumiBlockLHEXSec_;

    // LHE or Pythia/Herwig combined cross section of current luminosity block
    // updated for each luminosity block, initialized in every run
    // used for computation
    CMS_THREAD_GUARD(GenXSecAnalyzer::mutex_) mutable std::map<int, GenLumiInfoProduct::XSec> currentLumiBlockLHEXSec_;
  };
}  // namespace gxsec

class GenXSecAnalyzer
    : public edm::global::EDAnalyzer<edm::RunCache<gxsec::RunCache>, edm::LuminosityBlockCache<gxsec::LumiCache>> {
public:
  explicit GenXSecAnalyzer(const edm::ParameterSet &);
  ~GenXSecAnalyzer() override;

private:
  void beginJob() final;
  std::shared_ptr<gxsec::RunCache> globalBeginRun(edm::Run const &, edm::EventSetup const &) const final;
  std::shared_ptr<gxsec::LumiCache> globalBeginLuminosityBlock(edm::LuminosityBlock const &,
                                                               edm::EventSetup const &) const final;
  void analyze(edm::StreamID, const edm::Event &, const edm::EventSetup &) const final;
  void globalEndLuminosityBlock(edm::LuminosityBlock const &, edm::EventSetup const &) const final;
  void globalEndRun(edm::Run const &, edm::EventSetup const &) const final;
  void endJob() final;
  // computation of cross section after matching and before HepcFilter and GenFilter
  GenLumiInfoProduct::XSec compute(const GenLumiInfoProduct &) const;
  // combination of cross section from different MCs after matching (could be either before or after HepcFilter and GenFilter)
  void combine(GenLumiInfoProduct::XSec &, double &, const GenLumiInfoProduct::XSec &, const double &) const;
  void combine(double &, double &, double &, const double &, const double &, const double &) const;

  edm::EDGetTokenT<GenFilterInfo> genFilterInfoToken_;
  edm::EDGetTokenT<GenFilterInfo> hepMCFilterInfoToken_;
  edm::EDGetTokenT<GenLumiInfoProduct> genLumiInfoToken_;
  edm::EDGetTokenT<LHERunInfoProduct> lheRunInfoToken_;

  // ----------member data --------------------------

  mutable std::atomic<int> nMCs_;

  mutable std::atomic<int> hepidwtup_;

  mutable std::mutex mutex_;

  // for weight before GenFilter and HepMCFilter and before matching
  CMS_THREAD_GUARD(mutex_) mutable double totalWeightPre_;

  // for weight after GenFilter and HepMCFilter and after matching
  CMS_THREAD_GUARD(mutex_) mutable double totalWeight_;

  // combined cross sections before HepMCFilter and GenFilter
  CMS_THREAD_GUARD(mutex_) mutable GenLumiInfoProduct::XSec xsecPreFilter_;

  // final combined cross sections
  CMS_THREAD_GUARD(mutex_) mutable GenLumiInfoProduct::XSec xsec_;

  // statistics from additional generator filter, for print-out only
  CMS_THREAD_GUARD(mutex_) mutable GenFilterInfo filterOnlyEffStat_;

  // statistics from HepMC filter, for print-out only
  CMS_THREAD_GUARD(mutex_) mutable GenFilterInfo hepMCFilterEffStat_;

  // the vector/map size is the number of LHE processes + 1
  // needed only for printouts, not used for computation
  // only printed out when combining the same physics process
  // uncertainty-averaged cross sections before matching
  CMS_THREAD_GUARD(mutex_) mutable std::vector<GenLumiInfoProduct::XSec> xsecBeforeMatching_;
  // uncertainty-averaged cross sections after matching
  CMS_THREAD_GUARD(mutex_) mutable std::vector<GenLumiInfoProduct::XSec> xsecAfterMatching_;
  // statistics from jet matching
  CMS_THREAD_GUARD(mutex_) mutable std::map<int, GenFilterInfo> jetMatchEffStat_;
};

GenXSecAnalyzer::GenXSecAnalyzer(const edm::ParameterSet &iConfig)
    : nMCs_(0),
      hepidwtup_(-9999),
      totalWeightPre_(0),
      totalWeight_(0),
      xsecPreFilter_(-1, -1),
      xsec_(-1, -1),
      filterOnlyEffStat_(0, 0, 0, 0, 0., 0., 0., 0.),
      hepMCFilterEffStat_(0, 0, 0, 0, 0., 0., 0., 0.) {
  genFilterInfoToken_ = consumes<GenFilterInfo, edm::InLumi>(edm::InputTag("genFilterEfficiencyProducer", ""));
  hepMCFilterInfoToken_ = consumes<GenFilterInfo, edm::InLumi>(edm::InputTag("generator", ""));
  genLumiInfoToken_ = consumes<GenLumiInfoProduct, edm::InLumi>(edm::InputTag("generator", ""));
  lheRunInfoToken_ = consumes<LHERunInfoProduct, edm::InRun>(edm::InputTag("externalLHEProducer", ""));
}

GenXSecAnalyzer::~GenXSecAnalyzer() {}

void GenXSecAnalyzer::beginJob() {}

std::shared_ptr<gxsec::RunCache> GenXSecAnalyzer::globalBeginRun(edm::Run const &iRun, edm::EventSetup const &) const {
  // initialization for every different physics MC

  nMCs_++;

  {
    std::lock_guard l{mutex_};
    xsecBeforeMatching_.clear();
    xsecAfterMatching_.clear();
    jetMatchEffStat_.clear();
  }
  return std::make_shared<gxsec::RunCache>();
}

std::shared_ptr<gxsec::LumiCache> GenXSecAnalyzer::globalBeginLuminosityBlock(edm::LuminosityBlock const &iLumi,
                                                                              edm::EventSetup const &) const {
  return std::shared_ptr<gxsec::LumiCache>();
}

void GenXSecAnalyzer::analyze(edm::StreamID, const edm::Event &, const edm::EventSetup &) const {}

void GenXSecAnalyzer::globalEndLuminosityBlock(edm::LuminosityBlock const &iLumi, edm::EventSetup const &) const {
  edm::Handle<GenLumiInfoProduct> genLumiInfo;
  iLumi.getByToken(genLumiInfoToken_, genLumiInfo);
  if (!genLumiInfo.isValid())
    return;
  hepidwtup_ = genLumiInfo->getHEPIDWTUP();

  std::vector<GenLumiInfoProduct::ProcessInfo> const &theProcesses = genLumiInfo->getProcessInfos();

  unsigned int theProcesses_size = theProcesses.size();

  // if it's a pure parton-shower generator, check there should be only one element in thisProcessInfos
  // the error of lheXSec is -1
  if (hepidwtup_ == -1) {
    if (theProcesses_size != 1) {
      edm::LogError("GenXSecAnalyzer::endLuminosityBlock") << "Pure parton shower has thisProcessInfos size!=1";
      return;
    }
  }

  for (unsigned int ip = 0; ip < theProcesses_size; ip++) {
    if (theProcesses[ip].lheXSec().value() < 0) {
      edm::LogError("GenXSecAnalyzer::endLuminosityBlock")
          << "cross section of process " << ip << " value = " << theProcesses[ip].lheXSec().value();
      return;
    }
  }

  auto runC = runCache(iLumi.getRun().index());
  {
    std::lock_guard g{mutex_};
    runC->product_.mergeProduct(*genLumiInfo);
  }
  edm::Handle<GenFilterInfo> genFilter;
  iLumi.getByToken(genFilterInfoToken_, genFilter);

  if (genFilter.isValid()) {
    std::lock_guard g{mutex_};
    filterOnlyEffStat_.mergeProduct(*genFilter);
    runC->filterOnlyEffRun_.mergeProduct(*genFilter);
    runC->thisRunWeight_ += genFilter->sumPassWeights();
  }

  edm::Handle<GenFilterInfo> hepMCFilter;
  iLumi.getByToken(hepMCFilterInfoToken_, hepMCFilter);

  if (hepMCFilter.isValid()) {
    std::lock_guard g{mutex_};
    hepMCFilterEffStat_.mergeProduct(*hepMCFilter);
    runC->hepMCFilterEffRun_.mergeProduct(*hepMCFilter);
  }

  std::lock_guard g{mutex_};
  // doing generic summing for jet matching statistics
  // and computation of combined LHE information
  for (unsigned int ip = 0; ip < theProcesses_size; ip++) {
    int id = theProcesses[ip].process();
    GenFilterInfo &x = jetMatchEffStat_[id];
    GenLumiInfoProduct::XSec &y = runC->currentLumiBlockLHEXSec_[id];
    GenLumiInfoProduct::FinalStat temp_killed = theProcesses[ip].killed();
    GenLumiInfoProduct::FinalStat temp_selected = theProcesses[ip].selected();
    double passw = temp_killed.sum();
    double passw2 = temp_killed.sum2();
    double totalw = temp_selected.sum();
    double totalw2 = temp_selected.sum2();
    GenFilterInfo tempInfo(theProcesses[ip].nPassPos(),
                           theProcesses[ip].nPassNeg(),
                           theProcesses[ip].nTotalPos(),
                           theProcesses[ip].nTotalNeg(),
                           passw,
                           passw2,
                           totalw,
                           totalw2);

    // matching statistics for all processes
    jetMatchEffStat_[10000].mergeProduct(tempInfo);
    double currentValue = theProcesses[ip].lheXSec().value();
    double currentError = theProcesses[ip].lheXSec().error();

    // this process ID has occurred before
    auto &thisRunWeightPre = runC->thisRunWeightPre_;
    if (y.value() > 0) {
      x.mergeProduct(tempInfo);
      double previousValue = runC->previousLumiBlockLHEXSec_[id].value();

      if (currentValue != previousValue)  // transition of cross section
      {
        double xsec = y.value();
        double err = y.error();
        combine(xsec, err, thisRunWeightPre, currentValue, currentError, totalw);
        y = GenLumiInfoProduct::XSec(xsec, err);
      } else  // LHE cross section is the same as previous lumiblock
        thisRunWeightPre += totalw;

    }
    // this process ID has never occurred before
    else {
      x = tempInfo;
      y = theProcesses[ip].lheXSec();
      thisRunWeightPre += totalw;
    }

    runC->previousLumiBlockLHEXSec_[id] = theProcesses[ip].lheXSec();
  }  // end

  return;
}

void GenXSecAnalyzer::globalEndRun(edm::Run const &iRun, edm::EventSetup const &) const {
  //xsection before matching
  edm::Handle<LHERunInfoProduct> run;

  if (iRun.getByToken(lheRunInfoToken_, run)) {
    const lhef::HEPRUP thisHeprup = run->heprup();

    for (unsigned int iSize = 0; iSize < thisHeprup.XSECUP.size(); iSize++) {
      std::cout << std::setw(14) << std::fixed << thisHeprup.XSECUP[iSize] << std::setw(14) << std::fixed
                << thisHeprup.XERRUP[iSize] << std::setw(14) << std::fixed << thisHeprup.XMAXUP[iSize] << std::setw(14)
                << std::fixed << thisHeprup.LPRUP[iSize] << std::endl;
    }
    std::cout << " " << std::endl;
  }

  auto runC = runCache(iRun.index());
  if (nullptr == runC)
    return;

  std::lock_guard l{mutex_};

  // compute cross section for this run first
  // set the correct combined LHE+filter cross sections
  unsigned int i = 0;
  std::vector<GenLumiInfoProduct::ProcessInfo> newInfos;
  for (std::map<int, GenLumiInfoProduct::XSec>::const_iterator iter = runC->currentLumiBlockLHEXSec_.begin();
       iter != runC->currentLumiBlockLHEXSec_.end();
       ++iter, i++) {
    GenLumiInfoProduct::ProcessInfo temp = runC->product_.getProcessInfos()[i];
    temp.setLheXSec(iter->second.value(), iter->second.error());
    newInfos.push_back(temp);
  }
  runC->product_.setProcessInfo(newInfos);

  const GenLumiInfoProduct::XSec thisRunXSecPre = compute(runC->product_);
  // xsection after matching before filters
  combine(xsecPreFilter_, totalWeightPre_, thisRunXSecPre, runC->thisRunWeightPre_);

  double thisHepFilterEff = 1;
  double thisHepFilterErr = 0;

  if (runC->hepMCFilterEffRun_.sumWeights2() > 0) {
    thisHepFilterEff = runC->hepMCFilterEffRun_.filterEfficiency(hepidwtup_);
    thisHepFilterErr = runC->hepMCFilterEffRun_.filterEfficiencyError(hepidwtup_);
    if (thisHepFilterEff < 0) {
      thisHepFilterEff = 1;
      thisHepFilterErr = 0;
    }
  }

  double thisGenFilterEff = 1;
  double thisGenFilterErr = 0;

  if (runC->filterOnlyEffRun_.sumWeights2() > 0) {
    thisGenFilterEff = runC->filterOnlyEffRun_.filterEfficiency(hepidwtup_);
    thisGenFilterErr = runC->filterOnlyEffRun_.filterEfficiencyError(hepidwtup_);
    if (thisGenFilterEff < 0) {
      thisGenFilterEff = 1;
      thisGenFilterErr = 0;
    }
  }
  double thisXsec = thisRunXSecPre.value() > 0 ? thisHepFilterEff * thisGenFilterEff * thisRunXSecPre.value() : 0;
  double thisErr =
      thisRunXSecPre.value() > 0
          ? thisXsec * sqrt(pow(TMath::Max(thisRunXSecPre.error(), (double)0) / thisRunXSecPre.value(), 2) +
                            pow(thisHepFilterErr / thisHepFilterEff, 2) + pow(thisGenFilterErr / thisGenFilterEff, 2))
          : 0;
  const GenLumiInfoProduct::XSec thisRunXSec = GenLumiInfoProduct::XSec(thisXsec, thisErr);
  combine(xsec_, totalWeight_, thisRunXSec, runC->thisRunWeight_);
}

void GenXSecAnalyzer::combine(double &finalValue,
                              double &finalError,
                              double &finalWeight,
                              const double &currentValue,
                              const double &currentError,
                              const double &currentWeight) const {
  if (finalValue <= 0) {
    finalValue = currentValue;
    finalError = currentError;
    finalWeight += currentWeight;
  } else {
    double wgt1 = (finalError <= 0 || currentError <= 0) ? finalWeight : 1 / (finalError * finalError);
    double wgt2 = (finalError <= 0 || currentError <= 0) ? currentWeight : 1 / (currentError * currentError);
    double xsec = (wgt1 * finalValue + wgt2 * currentValue) / (wgt1 + wgt2);
    double err = (finalError <= 0 || currentError <= 0) ? 0 : 1.0 / std::sqrt(wgt1 + wgt2);
    finalValue = xsec;
    finalError = err;
    finalWeight += currentWeight;
  }
  return;
}

void GenXSecAnalyzer::combine(GenLumiInfoProduct::XSec &finalXSec,
                              double &totalw,
                              const GenLumiInfoProduct::XSec &thisRunXSec,
                              const double &thisw) const {
  double value = finalXSec.value();
  double error = finalXSec.error();
  double thisValue = thisRunXSec.value();
  double thisError = thisRunXSec.error();
  combine(value, error, totalw, thisValue, thisError, thisw);
  finalXSec = GenLumiInfoProduct::XSec(value, error);
  return;
}

GenLumiInfoProduct::XSec GenXSecAnalyzer::compute(const GenLumiInfoProduct &iLumiInfo) const {
  // sum of cross sections and errors over different processes
  double sigSelSum = 0.0;
  double err2SelSum = 0.0;

  std::vector<GenLumiInfoProduct::XSec> tempVector_before;
  std::vector<GenLumiInfoProduct::XSec> tempVector_after;

  // loop over different processes for each sample
  unsigned int vectorSize = iLumiInfo.getProcessInfos().size();
  for (unsigned int ip = 0; ip < vectorSize; ip++) {
    GenLumiInfoProduct::ProcessInfo proc = iLumiInfo.getProcessInfos()[ip];
    double hepxsec_value = proc.lheXSec().value();
    double hepxsec_error = proc.lheXSec().error() <= 0 ? 0 : proc.lheXSec().error();
    tempVector_before.push_back(GenLumiInfoProduct::XSec(hepxsec_value, hepxsec_error));

    sigSelSum += hepxsec_value;
    err2SelSum += hepxsec_error * hepxsec_error;

    // skips computation if jet matching efficiency=0
    if (proc.killed().n() < 1) {
      tempVector_after.push_back(GenLumiInfoProduct::XSec(0.0, 0.0));
      continue;
    }

    // computing jet matching efficiency for this process
    double fracAcc = 0;
    double ntotal = proc.nTotalPos() - proc.nTotalNeg();
    double npass = proc.nPassPos() - proc.nPassNeg();
    switch (hepidwtup_) {
      case 3:
      case -3:
        fracAcc = ntotal > 0 ? npass / ntotal : -1;
        break;
      default:
        fracAcc = proc.selected().sum() > 0 ? proc.killed().sum() / proc.selected().sum() : -1;
        break;
    }

    if (fracAcc <= 0) {
      tempVector_after.push_back(GenLumiInfoProduct::XSec(0.0, 0.0));
      continue;
    }

    // cross section after matching for this particular process
    double sigmaFin = hepxsec_value * fracAcc;

    // computing error on jet matching efficiency
    double relErr = 1.0;
    double efferr2 = 0;
    switch (hepidwtup_) {
      case 3:
      case -3: {
        double ntotal_pos = proc.nTotalPos();
        double effp = ntotal_pos > 0 ? (double)proc.nPassPos() / ntotal_pos : 0;
        double effp_err2 = ntotal_pos > 0 ? (1 - effp) * effp / ntotal_pos : 0;

        double ntotal_neg = proc.nTotalNeg();
        double effn = ntotal_neg > 0 ? (double)proc.nPassNeg() / ntotal_neg : 0;
        double effn_err2 = ntotal_neg > 0 ? (1 - effn) * effn / ntotal_neg : 0;

        efferr2 = ntotal > 0
                      ? (ntotal_pos * ntotal_pos * effp_err2 + ntotal_neg * ntotal_neg * effn_err2) / ntotal / ntotal
                      : 0;
        break;
      }
      default: {
        double denominator = pow(proc.selected().sum(), 4);
        double passw = proc.killed().sum();
        double passw2 = proc.killed().sum2();
        double failw = proc.selected().sum() - passw;
        double failw2 = proc.selected().sum2() - passw2;
        double numerator = (passw2 * failw * failw + failw2 * passw * passw);

        efferr2 = denominator > 0 ? numerator / denominator : 0;
        break;
      }
    }
    double delta2Veto = efferr2 / fracAcc / fracAcc;

    // computing total error on cross section after matching efficiency

    double sigma2Sum, sigma2Err;
    sigma2Sum = hepxsec_value * hepxsec_value;
    sigma2Err = hepxsec_error * hepxsec_error;

    double delta2Sum = delta2Veto + sigma2Err / sigma2Sum;
    relErr = (delta2Sum > 0.0 ? std::sqrt(delta2Sum) : 0.0);
    double deltaFin = sigmaFin * relErr;

    tempVector_after.push_back(GenLumiInfoProduct::XSec(sigmaFin, deltaFin));

  }  // end of loop over different processes
  tempVector_before.push_back(GenLumiInfoProduct::XSec(sigSelSum, sqrt(err2SelSum)));

  double total_matcheff = jetMatchEffStat_[10000].filterEfficiency(hepidwtup_);
  double total_matcherr = jetMatchEffStat_[10000].filterEfficiencyError(hepidwtup_);

  double xsec_after = sigSelSum * total_matcheff;
  double xsecerr_after = (total_matcheff > 0 && sigSelSum > 0)
                             ? xsec_after * sqrt(err2SelSum / sigSelSum / sigSelSum +
                                                 total_matcherr * total_matcherr / total_matcheff / total_matcheff)
                             : 0;

  GenLumiInfoProduct::XSec result(xsec_after, xsecerr_after);
  tempVector_after.push_back(result);

  xsecBeforeMatching_ = tempVector_before;
  xsecAfterMatching_ = tempVector_after;

  return result;
}

void GenXSecAnalyzer::endJob() {
  edm::LogPrint("GenXSecAnalyzer") << "\n"
                                   << "------------------------------------"
                                   << "\n"
                                   << "GenXsecAnalyzer:"
                                   << "\n"
                                   << "------------------------------------";

  if (jetMatchEffStat_.empty()) {
    edm::LogPrint("GenXSecAnalyzer") << "------------------------------------"
                                     << "\n"
                                     << "Cross-section summary not available"
                                     << "\n"
                                     << "------------------------------------";
    return;
  }

  // fraction of negative weights
  double final_fract_neg_w = 0;
  double final_fract_neg_w_unc = 0;

  // below print out is only for combination of same physics MC samples and ME+Pythia MCs

  if (nMCs_ == 1 && hepidwtup_ != -1) {
    edm::LogPrint("GenXSecAnalyzer")
        << "-----------------------------------------------------------------------------------------------------------"
           "--------------------------------------------------------------- \n"
        << "Overall cross-section summary \n"
        << "-----------------------------------------------------------------------------------------------------------"
           "---------------------------------------------------------------";
    edm::LogPrint("GenXSecAnalyzer") << "Process\t\txsec_before [pb]\t\tpassed\tnposw\tnnegw\ttried\tnposw\tnnegw "
                                        "\txsec_match [pb]\t\t\taccepted [%]\t event_eff [%]";

    const unsigned sizeOfInfos = jetMatchEffStat_.size();
    const unsigned last = sizeOfInfos - 1;
    std::string *title = new std::string[sizeOfInfos];
    unsigned int i = 0;
    double jetmatch_eff = 0;
    double jetmatch_err = 0;
    double matching_eff = 1;
    double matching_efferr = 1;

    for (std::map<int, GenFilterInfo>::const_iterator iter = jetMatchEffStat_.begin(); iter != jetMatchEffStat_.end();
         ++iter, i++) {
      GenFilterInfo thisJetMatchStat = iter->second;
      GenFilterInfo thisEventEffStat =
          GenFilterInfo(thisJetMatchStat.numPassPositiveEvents() + thisJetMatchStat.numPassNegativeEvents(),
                        0,
                        thisJetMatchStat.numTotalPositiveEvents() + thisJetMatchStat.numTotalNegativeEvents(),
                        0,
                        thisJetMatchStat.numPassPositiveEvents() + thisJetMatchStat.numPassNegativeEvents(),
                        thisJetMatchStat.numPassPositiveEvents() + thisJetMatchStat.numPassNegativeEvents(),
                        thisJetMatchStat.numTotalPositiveEvents() + thisJetMatchStat.numTotalNegativeEvents(),
                        thisJetMatchStat.numTotalPositiveEvents() + thisJetMatchStat.numTotalNegativeEvents());

      jetmatch_eff = thisJetMatchStat.filterEfficiency(hepidwtup_);
      jetmatch_err = thisJetMatchStat.filterEfficiencyError(hepidwtup_);

      if (i == last) {
        title[i] = "Total";

        edm::LogPrint("GenXSecAnalyzer")
            << "-------------------------------------------------------------------------------------------------------"
               "------------------------------------------------------------------- ";

        // fill negative fraction of negative weights and uncertainty after matching
        final_fract_neg_w = thisEventEffStat.numEventsPassed() > 0
                                ? thisJetMatchStat.numPassNegativeEvents() / thisEventEffStat.numEventsPassed()
                                : 0;
        final_fract_neg_w_unc =
            thisJetMatchStat.numPassNegativeEvents() > 0
                ? final_fract_neg_w * final_fract_neg_w / thisEventEffStat.numEventsPassed() *
                      sqrt(thisJetMatchStat.numPassPositiveEvents() * thisJetMatchStat.numPassPositiveEvents() /
                               thisJetMatchStat.numPassNegativeEvents() +
                           thisJetMatchStat.numPassPositiveEvents())
                : 0;
      } else {
        title[i] = Form("%d", i);
      }

      edm::LogPrint("GenXSecAnalyzer") << title[i] << "\t\t" << std::scientific << std::setprecision(3)
                                       << xsecBeforeMatching_[i].value() << " +/- " << xsecBeforeMatching_[i].error()
                                       << "\t\t" << thisEventEffStat.numEventsPassed() << "\t"
                                       << thisJetMatchStat.numPassPositiveEvents() << "\t"
                                       << thisJetMatchStat.numPassNegativeEvents() << "\t"
                                       << thisEventEffStat.numEventsTotal() << "\t"
                                       << thisJetMatchStat.numTotalPositiveEvents() << "\t"
                                       << thisJetMatchStat.numTotalNegativeEvents() << "\t" << std::scientific
                                       << std::setprecision(3) << xsecAfterMatching_[i].value() << " +/- "
                                       << xsecAfterMatching_[i].error() << "\t\t" << std::fixed << std::setprecision(1)
                                       << (jetmatch_eff * 100) << " +/- " << (jetmatch_err * 100) << "\t" << std::fixed
                                       << std::setprecision(1) << (thisEventEffStat.filterEfficiency(+3) * 100)
                                       << " +/- " << (thisEventEffStat.filterEfficiencyError(+3) * 100);

      matching_eff = thisEventEffStat.filterEfficiency(+3);
      matching_efferr = thisEventEffStat.filterEfficiencyError(+3);
    }
    delete[] title;

    edm::LogPrint("GenXSecAnalyzer")
        << "-----------------------------------------------------------------------------------------------------------"
           "---------------------------------------------------------------";

    edm::LogPrint("GenXSecAnalyzer") << "Before matching: total cross section = " << std::scientific
                                     << std::setprecision(3) << xsecBeforeMatching_[last].value() << " +- "
                                     << xsecBeforeMatching_[last].error() << " pb";

    edm::LogPrint("GenXSecAnalyzer") << "After matching: total cross section = " << std::scientific
                                     << std::setprecision(3) << xsecAfterMatching_[last].value() << " +- "
                                     << xsecAfterMatching_[last].error() << " pb";

    edm::LogPrint("GenXSecAnalyzer") << "Matching efficiency = " << std::fixed << std::setprecision(1) << matching_eff
                                     << " +/- " << matching_efferr << "   [TO BE USED IN MCM]";

  } else if (hepidwtup_ == -1)
    edm::LogPrint("GenXSecAnalyzer") << "Before Filter: total cross section = " << std::scientific
                                     << std::setprecision(3) << xsecPreFilter_.value() << " +- "
                                     << xsecPreFilter_.error() << " pb";

  // hepMC filter efficiency
  double hepMCFilter_eff = 1.0;
  double hepMCFilter_err = 0.0;
  if (hepMCFilterEffStat_.sumWeights2() > 0) {
    hepMCFilter_eff = hepMCFilterEffStat_.filterEfficiency(-1);
    hepMCFilter_err = hepMCFilterEffStat_.filterEfficiencyError(-1);
    edm::LogPrint("GenXSecAnalyzer") << "HepMC filter efficiency (taking into account weights)= "
                                     << "(" << hepMCFilterEffStat_.sumPassWeights() << ")"
                                     << " / "
                                     << "(" << hepMCFilterEffStat_.sumWeights() << ")"
                                     << " = " << std::scientific << std::setprecision(3) << hepMCFilter_eff << " +- "
                                     << hepMCFilter_err;

    double hepMCFilter_event_total =
        hepMCFilterEffStat_.numTotalPositiveEvents() + hepMCFilterEffStat_.numTotalNegativeEvents();
    double hepMCFilter_event_pass =
        hepMCFilterEffStat_.numPassPositiveEvents() + hepMCFilterEffStat_.numPassNegativeEvents();
    double hepMCFilter_event_eff = hepMCFilter_event_total > 0 ? hepMCFilter_event_pass / hepMCFilter_event_total : 0;
    double hepMCFilter_event_err =
        hepMCFilter_event_total > 0
            ? sqrt((1 - hepMCFilter_event_eff) * hepMCFilter_event_eff / hepMCFilter_event_total)
            : -1;
    edm::LogPrint("GenXSecAnalyzer") << "HepMC filter efficiency (event-level)= "
                                     << "(" << hepMCFilter_event_pass << ")"
                                     << " / "
                                     << "(" << hepMCFilter_event_total << ")"
                                     << " = " << std::scientific << std::setprecision(3) << hepMCFilter_event_eff
                                     << " +- " << hepMCFilter_event_err;
  }

  // gen-particle filter efficiency
  if (filterOnlyEffStat_.sumWeights2() > 0) {
    double filterOnly_eff = filterOnlyEffStat_.filterEfficiency(-1);
    double filterOnly_err = filterOnlyEffStat_.filterEfficiencyError(-1);

    edm::LogPrint("GenXSecAnalyzer") << "Filter efficiency (taking into account weights)= "
                                     << "(" << filterOnlyEffStat_.sumPassWeights() << ")"
                                     << " / "
                                     << "(" << filterOnlyEffStat_.sumWeights() << ")"
                                     << " = " << std::scientific << std::setprecision(3) << filterOnly_eff << " +- "
                                     << filterOnly_err;

    double filterOnly_event_total =
        filterOnlyEffStat_.numTotalPositiveEvents() + filterOnlyEffStat_.numTotalNegativeEvents();
    double filterOnly_event_pass =
        filterOnlyEffStat_.numPassPositiveEvents() + filterOnlyEffStat_.numPassNegativeEvents();
    double filterOnly_event_eff = filterOnly_event_total > 0 ? filterOnly_event_pass / filterOnly_event_total : 0;
    double filterOnly_event_err = filterOnly_event_total > 0
                                      ? sqrt((1 - filterOnly_event_eff) * filterOnly_event_eff / filterOnly_event_total)
                                      : -1;
    edm::LogPrint("GenXSecAnalyzer") << "Filter efficiency (event-level)= "
                                     << "(" << filterOnly_event_pass << ")"
                                     << " / "
                                     << "(" << filterOnly_event_total << ")"
                                     << " = " << std::scientific << std::setprecision(3) << filterOnly_event_eff
                                     << " +- " << filterOnly_event_err << "    [TO BE USED IN MCM]";

    // fill negative fraction of negative weights and uncertainty after filter
    final_fract_neg_w =
        filterOnly_event_pass > 0 ? filterOnlyEffStat_.numPassNegativeEvents() / (filterOnly_event_pass) : 0;
    final_fract_neg_w_unc =
        filterOnlyEffStat_.numPassNegativeEvents() > 0
            ? final_fract_neg_w * final_fract_neg_w / filterOnly_event_pass *
                  sqrt(filterOnlyEffStat_.numPassPositiveEvents() * filterOnlyEffStat_.numPassPositiveEvents() /
                           filterOnlyEffStat_.numPassNegativeEvents() +
                       filterOnlyEffStat_.numPassPositiveEvents())
            : 0;
  }

  edm::LogPrint("GenXSecAnalyzer") << "\nAfter filter: final cross section = " << std::scientific
                                   << std::setprecision(3) << xsec_.value() << " +- " << xsec_.error() << " pb";

  edm::LogPrint("GenXSecAnalyzer") << "After filter: final fraction of events with negative weights = "
                                   << std::scientific << std::setprecision(3) << final_fract_neg_w << " +- "
                                   << final_fract_neg_w_unc;

  // L=[N*(1-2f)^2]/s
  double lumi_1M_evts =
      xsec_.value() > 0 ? 1e6 * (1 - 2 * final_fract_neg_w) * (1 - 2 * final_fract_neg_w) / xsec_.value() / 1e3 : 0;
  double lumi_1M_evts_unc =
      xsec_.value() > 0 ? (1 - 2 * final_fract_neg_w) * lumi_1M_evts *
                              sqrt(1e-6 + 16 * pow(final_fract_neg_w_unc, 2) / pow(1 - 2 * final_fract_neg_w, 2) +
                                   pow(xsec_.error() / xsec_.value(), 2))
                        : 0;
  edm::LogPrint("GenXSecAnalyzer") << "After filter: final equivalent lumi for 1M events (1/fb) = " << std::scientific
                                   << std::setprecision(3) << lumi_1M_evts << " +- " << lumi_1M_evts_unc;
}

DEFINE_FWK_MODULE(GenXSecAnalyzer);