Skip to content

Commit 9ec9cef

Browse files
committed
Introduce TauSpinner-table producer
1 parent 3914bc8 commit 9ec9cef

File tree

2 files changed

+247
-0
lines changed

2 files changed

+247
-0
lines changed

PhysicsTools/NanoAOD/plugins/BuildFile.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<use name="fastjet-contrib"/>
33
<use name="roothistmatrix"/>
44
<use name="tbb"/>
5+
<use name="tauolapp"/>
56
<use name="CommonTools/Egamma"/>
67
<use name="CondFormats/BTauObjects"/>
78
<use name="CondFormats/DataRecord"/>
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/**\class TauSpinnerTableProducer
2+
3+
Description: Produces FlatTable with TauSpinner weights for H->tau,tau events
4+
5+
Original Author: D. Winterbottom (IC)
6+
Update and adaptation to NanoAOD: M. Bluj (NCBJ)
7+
8+
*/
9+
10+
#include "FWCore/Framework/interface/one/EDProducer.h"
11+
#include "FWCore/Framework/interface/Event.h"
12+
#include "FWCore/Framework/interface/EventSetup.h"
13+
#include "FWCore/Concurrency/interface/SharedResourceNames.h"
14+
#include "FWCore/MessageLogger/interface/MessageLogger.h"
15+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
16+
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
17+
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
18+
#include "DataFormats/Common/interface/View.h"
19+
#include "DataFormats/HepMCCandidate/interface/GenParticle.h"
20+
#include "DataFormats/NanoAOD/interface/FlatTable.h"
21+
22+
#include "Tauola/Tauola.h"
23+
#include "TauSpinner/SimpleParticle.h"
24+
#include "TauSpinner/tau_reweight_lib.h"
25+
26+
class TauSpinnerTableProducer : public edm::one::EDProducer<edm::one::SharedResources> {
27+
public:
28+
explicit TauSpinnerTableProducer(const edm::ParameterSet &);
29+
30+
void produce(edm::Event &, const edm::EventSetup &) final;
31+
void beginJob() final;
32+
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
33+
edm::ParameterSetDescription desc;
34+
desc.add<edm::InputTag>("src")->setComment("input genParticle collection");
35+
desc.add<std::string>("name")->setComment("name of the TauSpinner weights table");
36+
desc.add<std::vector<double>>("theta")->setComment("values of CP-even and CP-odd tau Yukawa mixing angle");
37+
desc.add<std::string>("pdfSet", "NNPDF31_nnlo_hessian_pdfas")->setComment("PDF set for TauSpinner");
38+
desc.add<double>("cmsE", 13600)->setComment("cms energy for TauSpinner in GeV");
39+
desc.add<int>("bosonPdgId", 25)->setComment("boson pdgId");
40+
desc.add<double>("defaultWeight", 1)
41+
->setComment("default weight stored in case of presence of a tau decay unsupported by TauSpinner");
42+
descriptions.addWithDefaultLabel(desc);
43+
}
44+
45+
private:
46+
void getBosons(edm::RefVector<edm::View<reco::GenParticle>> &bosons, const edm::View<reco::GenParticle> &parts) const;
47+
static reco::GenParticleRef getLastCopy(const reco::GenParticleRef &part);
48+
static void getTaus(reco::GenParticleRefVector &taus, const reco::GenParticle &boson);
49+
static bool getTauDaughters(reco::GenParticleRefVector &tau_daughters, const reco::GenParticle &tau);
50+
TauSpinner::SimpleParticle convertToSimplePart(const reco::GenParticle &input_part) const {
51+
return TauSpinner::SimpleParticle(
52+
input_part.px(), input_part.py(), input_part.pz(), input_part.energy(), input_part.pdgId());
53+
}
54+
55+
static std::vector<std::pair<std::string, double>> nameAndValue(const std::vector<double> &val_vec) {
56+
std::vector<std::pair<std::string, double>> out;
57+
for (auto val : val_vec) {
58+
std::string name = std::to_string(val);
59+
name.erase(name.find_last_not_of('0') + 1, std::string::npos);
60+
name.erase(name.find_last_not_of('.') + 1, std::string::npos);
61+
size_t pos = name.find(".");
62+
if (pos != std::string::npos)
63+
name.replace(pos, 1, "p");
64+
pos = name.find("-");
65+
if (pos != std::string::npos)
66+
name.replace(pos, 1, "minus");
67+
out.push_back(std::make_pair(name, val));
68+
}
69+
return out;
70+
}
71+
72+
void printModuleInfo(edm::ParameterSet const &config) const {
73+
std::cout << std::string(78, '-') << "\n";
74+
std::cout << config.getParameter<std::string>("@module_type") << '/'
75+
<< config.getParameter<std::string>("@module_label") << "\n";
76+
std::cout << "Input collection: " << config.getParameter<edm::InputTag>("src").encode() << '\n';
77+
std::cout << "Table name: " << config.getParameter<std::string>("name") << '\n';
78+
std::string thetaStr;
79+
for (const auto &theta : theta_vec_)
80+
thetaStr += theta.first + ",";
81+
std::cout << "Theta: " << thetaStr << std::endl;
82+
}
83+
84+
const edm::EDGetTokenT<edm::View<reco::GenParticle>> genPartsToken_;
85+
const std::string name_;
86+
const std::vector<std::pair<std::string, double>> theta_vec_;
87+
const int bosonPdgId_;
88+
const std::string tauSpinnerPDF_;
89+
const bool ipp_;
90+
const int ipol_;
91+
const int nonSM2_;
92+
const int nonSMN_;
93+
const double cmsE_;
94+
const double default_weight_;
95+
};
96+
97+
TauSpinnerTableProducer::TauSpinnerTableProducer(const edm::ParameterSet &config)
98+
: genPartsToken_(consumes(config.getParameter<edm::InputTag>("src"))),
99+
name_(config.getParameter<std::string>("name")),
100+
theta_vec_(nameAndValue(config.getParameter<std::vector<double>>("theta"))),
101+
bosonPdgId_(config.getParameter<int>("bosonPdgId")),
102+
tauSpinnerPDF_(config.getParameter<std::string>("pdfSet")),
103+
ipp_(true), // pp collisions
104+
ipol_(0),
105+
nonSM2_(0),
106+
nonSMN_(0),
107+
cmsE_(config.getParameter<double>("cmsE")), // cms energy in GeV
108+
default_weight_(config.getParameter<double>(
109+
"defaultWeight")) // default weight stored in case of presence of a tau decay unsupported by TauSpinner
110+
{
111+
printModuleInfo(config);
112+
113+
// State that we use tauola/tauspinner resource
114+
usesResource(edm::SharedResourceNames::kTauola);
115+
116+
produces<nanoaod::FlatTable>();
117+
}
118+
119+
void TauSpinnerTableProducer::getBosons(edm::RefVector<edm::View<reco::GenParticle>> &bosons,
120+
const edm::View<reco::GenParticle> &parts) const {
121+
unsigned idx = 0;
122+
for (const auto &part : parts) {
123+
if (std::abs(part.pdgId()) == bosonPdgId_ && part.isLastCopy()) {
124+
edm::Ref<edm::View<reco::GenParticle>> partRef(&parts, idx);
125+
bosons.push_back(partRef);
126+
}
127+
++idx;
128+
}
129+
}
130+
131+
reco::GenParticleRef TauSpinnerTableProducer::getLastCopy(const reco::GenParticleRef &part) {
132+
if (part->statusFlags().isLastCopy())
133+
return part;
134+
for (const auto &daughter : part->daughterRefVector()) {
135+
if (daughter->pdgId() == part->pdgId() && daughter->statusFlags().fromHardProcess()) {
136+
return getLastCopy(daughter);
137+
}
138+
}
139+
throw std::runtime_error("getLastCopy: no last copy found");
140+
}
141+
142+
void TauSpinnerTableProducer::getTaus(reco::GenParticleRefVector &taus, const reco::GenParticle &boson) {
143+
for (const auto &daughterRef : boson.daughterRefVector()) {
144+
if (std::abs(daughterRef->pdgId()) == 15)
145+
taus.push_back(getLastCopy(daughterRef));
146+
}
147+
}
148+
149+
bool TauSpinnerTableProducer::getTauDaughters(reco::GenParticleRefVector &tau_daughters, const reco::GenParticle &tau) {
150+
static const std::set<int> directTauProducts = {11, 12, 13, 14, 16, 22};
151+
static const std::set<int> finalHadrons = {111, 130, 211, 310, 311, 321};
152+
static const std::set<int> intermediateHadrons = {221, 223, 323};
153+
for (auto daughterRef : tau.daughterRefVector()) {
154+
const int daughter_pdgId = std::abs(daughterRef->pdgId());
155+
if ((std::abs(tau.pdgId()) == 15 && directTauProducts.count(daughter_pdgId)) ||
156+
finalHadrons.count(daughter_pdgId)) {
157+
tau_daughters.push_back(daughterRef);
158+
} else if (intermediateHadrons.count(daughter_pdgId)) {
159+
if (!getTauDaughters(tau_daughters, *daughterRef))
160+
return false;
161+
} else {
162+
edm::LogWarning("TauSpinnerTableProducer::getTauDaughters")
163+
<< "Unsupported decay with " << daughter_pdgId << " being daughter of " << std::abs(tau.pdgId()) << "\n";
164+
return false;
165+
}
166+
}
167+
return true;
168+
}
169+
170+
void TauSpinnerTableProducer::beginJob() {
171+
// Initialize TauSpinner
172+
Tauolapp::Tauola::setNewCurrents(0);
173+
Tauolapp::Tauola::initialize();
174+
LHAPDF::initPDFSetByName(tauSpinnerPDF_);
175+
TauSpinner::initialize_spinner(ipp_, ipol_, nonSM2_, nonSMN_, cmsE_);
176+
}
177+
178+
void TauSpinnerTableProducer::produce(edm::Event &event, const edm::EventSetup &setup) {
179+
// Input gen-particles collection
180+
auto const &genParts = event.get(genPartsToken_);
181+
182+
// Output table
183+
auto wtTable = std::make_unique<nanoaod::FlatTable>(1, name_, true);
184+
wtTable->setDoc("TauSpinner weights");
185+
186+
// Search for boson
187+
edm::RefVector<edm::View<reco::GenParticle>> bosons;
188+
getBosons(bosons, genParts);
189+
if (bosons.size() !=
190+
1) { // no boson found or more than one found, produce empty table (expected for non HTT samples)
191+
event.put(std::move(wtTable));
192+
return;
193+
}
194+
195+
// Search for taus from boson decay
196+
reco::GenParticleRefVector taus;
197+
getTaus(taus, *bosons[0]);
198+
if (taus.size() != 2) { // boson does not decay to tau pair, produce empty table (expected for non HTT samples)
199+
event.put(std::move(wtTable));
200+
return;
201+
}
202+
203+
// Get tau daughters and convert all particles to TauSpinner format
204+
TauSpinner::SimpleParticle simple_boson = convertToSimplePart(*bosons[0]);
205+
std::array<TauSpinner::SimpleParticle, 2> simple_taus;
206+
std::array<std::vector<TauSpinner::SimpleParticle>, 2> simple_tau_daughters;
207+
bool supportedDecays = true;
208+
for (size_t tau_idx = 0; tau_idx < 2; ++tau_idx) {
209+
simple_taus[tau_idx] = convertToSimplePart(*taus[tau_idx]);
210+
reco::GenParticleRefVector tau_daughters;
211+
supportedDecays &= getTauDaughters(tau_daughters, *taus[tau_idx]);
212+
for (const auto &daughterRef : tau_daughters)
213+
simple_tau_daughters[tau_idx].push_back(convertToSimplePart(*daughterRef));
214+
}
215+
216+
// Compute TauSpinner weights and fill table
217+
std::array<double, 2> weights;
218+
for (const auto &theta : theta_vec_) {
219+
// Can make this more general by having boson pdgid as input or have option for set boson type
220+
TauSpinner::setHiggsParametersTR(-cos(2 * M_PI * theta.second),
221+
cos(2 * M_PI * theta.second),
222+
-sin(2 * M_PI * theta.second),
223+
-sin(2 * M_PI * theta.second));
224+
for (size_t i = 0; i < weights.size(); ++i) {
225+
Tauolapp::Tauola::setNewCurrents(i);
226+
weights[i] =
227+
supportedDecays
228+
? TauSpinner::calculateWeightFromParticlesH(
229+
simple_boson, simple_taus[0], simple_taus[1], simple_tau_daughters[0], simple_tau_daughters[1])
230+
: default_weight_;
231+
}
232+
// Nominal weights for setNewCurrents(0)
233+
wtTable->addColumnValue<double>(
234+
"weight_cp_" + theta.first, weights[0], "TauSpinner weight for theta_CP=" + theta.first);
235+
// Weights for alternative hadronic currents (can be used for uncertainty estimates)
236+
wtTable->addColumnValue<double>(
237+
"weight_cp_" + theta.first + "_alt",
238+
weights[1],
239+
"TauSpinner weight for theta_CP=" + theta.first + " (alternative hadronic currents)");
240+
}
241+
242+
event.put(std::move(wtTable));
243+
}
244+
245+
#include "FWCore/Framework/interface/MakerMacros.h"
246+
DEFINE_FWK_MODULE(TauSpinnerTableProducer);

0 commit comments

Comments
 (0)