CMS 3D CMS Logo

MLPFProducer.cc
Go to the documentation of this file.
5 
9 
11 
12 using namespace cms::Ort;
13 
14 //use this to switch on detailed print statements in MLPF
15 //#define MLPF_DEBUG
16 
17 class MLPFProducer : public edm::stream::EDProducer<edm::GlobalCache<ONNXRuntime>> {
18 public:
19  explicit MLPFProducer(const edm::ParameterSet&, const ONNXRuntime*);
20 
21  void produce(edm::Event& event, const edm::EventSetup& setup) override;
22  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
23 
24  // static methods for handling the global cache
25  static std::unique_ptr<ONNXRuntime> initializeGlobalCache(const edm::ParameterSet&);
26  static void globalEndJob(const ONNXRuntime*);
27 
28 private:
31 };
32 
34  : pfCandidatesPutToken_{produces<reco::PFCandidateCollection>()},
35  inputTagBlocks_(consumes<reco::PFBlockCollection>(cfg.getParameter<edm::InputTag>("src"))) {}
36 
38  using namespace reco::mlpf;
39 
40  const auto& blocks = event.get(inputTagBlocks_);
41  const auto& all_elements = getPFElements(blocks);
42 
43  std::vector<const reco::PFBlockElement*> selected_elements;
44  unsigned int num_elements_total = 0;
45  for (const auto* pelem : all_elements) {
46  if (pelem->type() == reco::PFBlockElement::PS1 || pelem->type() == reco::PFBlockElement::PS2) {
47  continue;
48  }
49  num_elements_total += 1;
50  selected_elements.push_back(pelem);
51  }
52  const auto tensor_size = LSH_BIN_SIZE * std::max(2u, (num_elements_total / LSH_BIN_SIZE + 1));
53 
54 #ifdef MLPF_DEBUG
55  assert(num_elements_total < NUM_MAX_ELEMENTS_BATCH);
56  //tensor size must be a multiple of the bin size and larger than the number of elements
57  assert(tensor_size <= NUM_MAX_ELEMENTS_BATCH);
58  assert(tensor_size % LSH_BIN_SIZE == 0);
59 #endif
60 
61 #ifdef MLPF_DEBUG
62  std::cout << "tensor_size=" << tensor_size << std::endl;
63 #endif
64 
65  //Fill the input tensor (batch, elems, features) = (1, tensor_size, NUM_ELEMENT_FEATURES)
66  std::vector<std::vector<float>> inputs(1, std::vector<float>(NUM_ELEMENT_FEATURES * tensor_size, 0.0));
67  unsigned int ielem = 0;
68  for (const auto* pelem : selected_elements) {
69  if (ielem > tensor_size) {
70  continue;
71  }
72 
73  const auto& elem = *pelem;
74 
75  //prepare the input array from the PFElement
76  const auto& props = getElementProperties(elem);
77 
78  //copy features to the input array
79  for (unsigned int iprop = 0; iprop < NUM_ELEMENT_FEATURES; iprop++) {
80  inputs[0][ielem * NUM_ELEMENT_FEATURES + iprop] = normalize(props[iprop]);
81  }
82  ielem += 1;
83  }
84 
85  //run the GNN inference, given the inputs and the output.
86  const auto& outputs = globalCache()->run({"x:0"}, inputs, {{1, tensor_size, NUM_ELEMENT_FEATURES}});
87  const auto& output = outputs[0];
88 #ifdef MLPF_DEBUG
89  assert(output.size() == tensor_size * NUM_OUTPUT_FEATURES);
90 #endif
91 
92  std::vector<reco::PFCandidate> pOutputCandidateCollection;
93  for (size_t ielem = 0; ielem < num_elements_total; ielem++) {
94  std::vector<float> pred_id_probas(IDX_CLASS + 1, 0.0);
95  const reco::PFBlockElement* elem = selected_elements[ielem];
96 
97  for (unsigned int idx_id = 0; idx_id <= IDX_CLASS; idx_id++) {
98  auto pred_proba = output[ielem * NUM_OUTPUT_FEATURES + idx_id];
99 #ifdef MLPF_DEBUG
100  assert(!std::isnan(pred_proba));
101 #endif
102  pred_id_probas[idx_id] = pred_proba;
103  }
104 
105  auto imax = argMax(pred_id_probas);
106 
107  //get the most probable class PDGID
108  int pred_pid = pdgid_encoding[imax];
109 
110 #ifdef MLPF_DEBUG
111  std::cout << "ielem=" << ielem << " inputs:";
112  for (unsigned int iprop = 0; iprop < NUM_ELEMENT_FEATURES; iprop++) {
113  std::cout << iprop << "=" << inputs[0][ielem * NUM_ELEMENT_FEATURES + iprop] << " ";
114  }
115  std::cout << std::endl;
116  std::cout << "ielem=" << ielem << " pred: pid=" << pred_pid << std::endl;
117 #endif
118 
119  //a particle was predicted for this PFElement, otherwise it was a spectator
120  if (pred_pid != 0) {
121  //muons and charged hadrons should only come from tracks, otherwise we won't have track references to pass downstream
122  if (((pred_pid == 13) || (pred_pid == 211)) && elem->type() != reco::PFBlockElement::TRACK) {
123  pred_pid = 130;
124  }
125 
126  if (elem->type() == reco::PFBlockElement::TRACK) {
127  const auto* eltTrack = dynamic_cast<const reco::PFBlockElementTrack*>(elem);
128 
129  //a track with no muon ref should not produce a muon candidate, instead we interpret it as a charged hadron
130  if (pred_pid == 13 && eltTrack->muonRef().isNull()) {
131  pred_pid = 211;
132  }
133 
134  //tracks from displaced vertices need reference debugging downstream as well, so we just treat them as neutrals for the moment
135  if ((pred_pid == 211) && (eltTrack->isLinkedToDisplacedVertex())) {
136  pred_pid = 130;
137  }
138  }
139 
140  //get the predicted momentum components
141  float pred_pt = output[ielem * NUM_OUTPUT_FEATURES + IDX_PT];
142  float pred_eta = output[ielem * NUM_OUTPUT_FEATURES + IDX_ETA];
143  float pred_sin_phi = output[ielem * NUM_OUTPUT_FEATURES + IDX_SIN_PHI];
144  float pred_cos_phi = output[ielem * NUM_OUTPUT_FEATURES + IDX_COS_PHI];
145  float pred_e = output[ielem * NUM_OUTPUT_FEATURES + IDX_ENERGY];
146  float pred_charge = output[ielem * NUM_OUTPUT_FEATURES + IDX_CHARGE];
147 
148  auto cand = makeCandidate(pred_pid, pred_charge, pred_pt, pred_eta, pred_sin_phi, pred_cos_phi, pred_e);
149  setCandidateRefs(cand, selected_elements, ielem);
150  pOutputCandidateCollection.push_back(cand);
151 
152 #ifdef MLPF_DEBUG
153  std::cout << "ielem=" << ielem << " cand: pid=" << cand.pdgId() << " E=" << cand.energy() << " pt=" << cand.pt()
154  << " eta=" << cand.eta() << " phi=" << cand.phi() << " charge=" << cand.charge() << std::endl;
155 #endif
156  }
157  } //loop over PFElements
158 
159  event.emplace(pfCandidatesPutToken_, pOutputCandidateCollection);
160 }
161 
162 std::unique_ptr<ONNXRuntime> MLPFProducer::initializeGlobalCache(const edm::ParameterSet& params) {
163  return std::make_unique<ONNXRuntime>(params.getParameter<edm::FileInPath>("model_path").fullPath());
164 }
165 
167 
170  desc.add<edm::InputTag>("src", edm::InputTag("particleFlowBlock"));
171  desc.add<edm::FileInPath>(
172  "model_path",
174  "RecoParticleFlow/PFProducer/data/mlpf/"
175  "mlpf_2021_11_16__no_einsum__all_data_cms-best-of-asha-scikit_20211026_042043_178263.workergpu010.onnx"));
176  descriptions.addWithDefaultLabel(desc);
177 }
178 
Abstract base class for a PFBlock element (track, cluster...)
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
def isnan(num)
static constexpr unsigned int IDX_ETA
Definition: MLPFModel.h:33
std::array< float, NUM_ELEMENT_FEATURES > getElementProperties(const reco::PFBlockElement &orig)
Definition: MLPFModel.cc:17
int argMax(std::vector< float > const &vec)
Definition: MLPFModel.cc:216
static std::unique_ptr< ONNXRuntime > initializeGlobalCache(const edm::ParameterSet &)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
static constexpr unsigned int NUM_ELEMENT_FEATURES
Definition: MLPFModel.h:10
static constexpr unsigned int IDX_PT
Definition: MLPFModel.h:32
static constexpr unsigned int IDX_ENERGY
Definition: MLPFModel.h:36
assert(be >=bs)
void produce(edm::Event &event, const edm::EventSetup &setup) override
Definition: MLPFProducer.cc:37
const std::vector< const reco::PFBlockElement * > getPFElements(const reco::PFBlockCollection &blocks)
Definition: MLPFModel.cc:263
static constexpr unsigned int NUM_OUTPUT_FEATURES
Definition: MLPFModel.h:11
const edm::EDPutTokenT< reco::PFCandidateCollection > pfCandidatesPutToken_
Definition: MLPFProducer.cc:29
static void globalEndJob(const ONNXRuntime *)
MLPFProducer(const edm::ParameterSet &, const ONNXRuntime *)
Definition: MLPFProducer.cc:33
static constexpr unsigned int IDX_CHARGE
Definition: MLPFModel.h:30
reco::PFCandidate makeCandidate(int pred_pid, int pred_charge, float pred_pt, float pred_eta, float pred_sin_phi, float pred_cos_phi, float pred_e)
Definition: MLPFModel.cc:220
static constexpr unsigned int IDX_CLASS
Definition: MLPFModel.h:28
static constexpr unsigned int IDX_SIN_PHI
Definition: MLPFModel.h:34
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
float normalize(float in)
Definition: MLPFModel.cc:207
const edm::EDGetTokenT< reco::PFBlockCollection > inputTagBlocks_
Definition: MLPFProducer.cc:30
static constexpr unsigned int IDX_COS_PHI
Definition: MLPFModel.h:35
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
def cache(function)
Definition: utilities.py:3
static const std::vector< int > pdgid_encoding
Definition: MLPFModel.h:43
void setCandidateRefs(reco::PFCandidate &cand, const std::vector< const reco::PFBlockElement *> elems, size_t ielem_originator)
Definition: MLPFModel.cc:284
static constexpr int LSH_BIN_SIZE
Definition: MLPFModel.h:14
Definition: event.py:1
static constexpr int NUM_MAX_ELEMENTS_BATCH
Definition: MLPFModel.h:15