46 inferenceBatchSize_(ps.getParameter<unsigned
int>(
"inferenceBatchSize")),
47 nnWorkingPoint_(ps.getParameter<double>(
"nnWorkingPoint")),
48 deltaEtaWindow_(ps.getParameter<double>(
"deltaEtaWindow")),
49 deltaPhiWindow_(ps.getParameter<double>(
"deltaPhiWindow")),
50 seedPtThreshold_(ps.getParameter<double>(
"seedPtThreshold")),
51 candidateEnergyThreshold_(ps.getParameter<double>(
"candidateEnergyThreshold")),
52 explVarRatioCut_energyBoundary_(ps.getParameter<double>(
"candidateEnergyThreshold")),
53 explVarRatioMinimum_lowEnergy_(ps.getParameter<double>(
"explVarRatioMinimum_lowEnergy")),
54 explVarRatioMinimum_highEnergy_(ps.getParameter<double>(
"explVarRatioMinimum_highEnergy")),
55 filterByTracksterPID_(ps.getParameter<
bool>(
"filterByTracksterPID")),
56 tracksterPIDCategoriesToFilter_(ps.getParameter<
std::
vector<
int>>(
"tracksterPIDCategoriesToFilter")),
57 PIDThreshold_(ps.getParameter<double>(
"PIDThreshold")) {
59 "TracksterLinkingbySuperClusteringDNN : ONNXRuntime was not provided, the model should have been set in " 60 "onnxModelPath in the plugin config");
73 float explVar_denominator =
75 if (explVar_denominator != 0.) {
76 float explVarRatio = ts.
eigenvalues()[0] / explVar_denominator;
87 float probTotal = 0.0f;
104 std::vector<Trackster>& resultTracksters,
105 std::vector<std::vector<unsigned int>>& outputSuperclusters,
106 std::vector<std::vector<unsigned int>>& linkedTracksterIdToInputTracksterId) {
108 auto const& inputTracksters =
input.tracksters;
109 const unsigned int tracksterCount = inputTracksters.size();
115 std::vector<unsigned int> trackstersIndicesPt(inputTracksters.size());
116 std::iota(trackstersIndicesPt.begin(), trackstersIndicesPt.end(), 0);
118 trackstersIndicesPt.begin(), trackstersIndicesPt.end(), [&inputTracksters](
unsigned int i1,
unsigned int i2) {
119 return inputTracksters[
i1].raw_pt() > inputTracksters[
i2].raw_pt();
126 const unsigned int miniBatchSize =
129 std::vector<std::vector<float>>
132 unsigned int candidateIndexInCurrentBatch = miniBatchSize;
135 std::vector<std::vector<std::pair<unsigned int, unsigned int>>> tracksterIndicesUsedInDNN;
138 std::array<TICLLayerTile, 2> tracksterTilesBothEndcaps_pt;
139 for (
unsigned int i_pt = 0; i_pt < trackstersIndicesPt.size(); ++i_pt) {
140 Trackster const& ts = inputTracksters[trackstersIndicesPt[i_pt]];
145 for (
unsigned int ts_cand_idx_pt = 1; ts_cand_idx_pt < tracksterCount; ts_cand_idx_pt++) {
146 Trackster const& ts_cand = inputTracksters[trackstersIndicesPt[ts_cand_idx_pt]];
152 auto& tracksterTiles = tracksterTilesBothEndcaps_pt[ts_cand.
barycenter().eta() > 0];
158 for (
int eta_i = search_box[0]; eta_i <= search_box[1]; ++eta_i) {
159 for (
int phi_i = search_box[2]; phi_i <= search_box[3]; ++phi_i) {
160 for (
unsigned int ts_seed_idx_pt :
162 if (ts_seed_idx_pt >= ts_cand_idx_pt)
165 Trackster const& ts_seed = inputTracksters[trackstersIndicesPt[ts_seed_idx_pt]];
176 if (candidateIndexInCurrentBatch >= miniBatchSize) {
178 assert(candidateIndexInCurrentBatch == miniBatchSize);
185 inputTensorBatches.emplace_back(
187 (tracksterCount * (tracksterCount - 1) - ts_cand_idx_pt * (ts_cand_idx_pt - 1)) / 2) *
190 candidateIndexInCurrentBatch = 0;
191 tracksterIndicesUsedInDNN.emplace_back();
196 assert((candidateIndexInCurrentBatch + 1) *
dnnInputs_->featureCount() <= inputTensorBatches.back().size());
200 inputTensorBatches.back().begin() + candidateIndexInCurrentBatch *
dnnInputs_->featureCount());
201 candidateIndexInCurrentBatch++;
202 tracksterIndicesUsedInDNN.back().emplace_back(trackstersIndicesPt[ts_seed_idx_pt],
203 trackstersIndicesPt[ts_cand_idx_pt]);
210 if (inputTensorBatches.empty()) {
211 LogDebug(
"HGCalTICLSuperclustering")
212 <<
"No superclustering candidate pairs passed preselection before DNN. There are " << tracksterCount
213 <<
" tracksters in this event.";
217 if (!inputTensorBatches.empty()) {
218 std::ostringstream
s;
220 for (
unsigned int i = 0;
221 i <
std::min(
dnnInputs_->featureCount() * 20,
static_cast<unsigned int>(inputTensorBatches[0].size()));
223 s << inputTensorBatches[0][
i] <<
" ";
227 LogDebug(
"HGCalTICLSuperclustering") << inputTensorBatches.size()
228 <<
" batches were created. First batch starts as follows : [" <<
s.str()
234 std::vector<std::vector<float>>
236 for (std::vector<float>& singleBatch : inputTensorBatches) {
238 std::vector<std::vector<float>> inputs_for_onnx{{
std::move(singleBatch)}};
240 {
"input"}, inputs_for_onnx, {}, {}, inputs_for_onnx[0].size() /
dnnInputs_->featureCount())[0];
246 std::vector<bool> tracksterMask(tracksterCount,
false);
256 auto onCandidateTransition = [&](
unsigned ts_cand_idx) {
257 if (bestSeedForCurrentCandidate_idx <
259 tracksterMask[ts_cand_idx] =
true;
262 std::vector<std::vector<unsigned int>>::iterator seed_supercluster_it =
263 std::find_if(outputSuperclusters.begin(),
264 outputSuperclusters.end(),
265 [bestSeedForCurrentCandidate_idx](std::vector<unsigned int>
const& sc) {
266 return sc[0] == bestSeedForCurrentCandidate_idx;
269 if (seed_supercluster_it == outputSuperclusters.end()) {
270 outputSuperclusters.emplace_back(std::initializer_list<unsigned int>{bestSeedForCurrentCandidate_idx});
271 resultTracksters.emplace_back(inputTracksters[bestSeedForCurrentCandidate_idx]);
272 linkedTracksterIdToInputTracksterId.emplace_back(
273 std::initializer_list<unsigned int>{bestSeedForCurrentCandidate_idx});
274 seed_supercluster_it = outputSuperclusters.end() - 1;
275 tracksterMask[bestSeedForCurrentCandidate_idx] =
279 unsigned int indexIntoOutputTracksters = seed_supercluster_it - outputSuperclusters.begin();
280 seed_supercluster_it->push_back(ts_cand_idx);
281 resultTracksters[indexIntoOutputTracksters].mergeTracksters(inputTracksters[ts_cand_idx]);
282 linkedTracksterIdToInputTracksterId[indexIntoOutputTracksters].push_back(ts_cand_idx);
284 assert(outputSuperclusters.size() == resultTracksters.size() &&
285 outputSuperclusters.size() == linkedTracksterIdToInputTracksterId.size());
286 assert(seed_supercluster_it->size() == linkedTracksterIdToInputTracksterId[indexIntoOutputTracksters].size());
294 for (
unsigned int batchIndex = 0; batchIndex < batchOutputs.size(); batchIndex++) {
295 std::vector<float>
const& currentBatchOutputs = batchOutputs[batchIndex];
297 for (
unsigned int indexInBatch = 0; indexInBatch < tracksterIndicesUsedInDNN[batchIndex].size(); indexInBatch++) {
298 assert(indexInBatch < static_cast<unsigned int>(batchOutputs[batchIndex].size()));
300 const unsigned int ts_seed_idx = tracksterIndicesUsedInDNN[batchIndex][indexInBatch].first;
301 const unsigned int ts_cand_idx = tracksterIndicesUsedInDNN[batchIndex][indexInBatch].second;
302 const float currentDnnScore = currentBatchOutputs[indexInBatch];
305 ts_cand_idx != previousCandTrackster_idx) {
307 onCandidateTransition(previousCandTrackster_idx);
310 if (currentDnnScore > bestSeedForCurrentCandidate_dnnScore && !tracksterMask[ts_seed_idx]) {
312 bestSeedForCurrentCandidate_idx = ts_seed_idx;
313 bestSeedForCurrentCandidate_dnnScore = currentDnnScore;
315 previousCandTrackster_idx = ts_cand_idx;
318 onCandidateTransition(previousCandTrackster_idx);
321 for (
unsigned int ts_id = 0; ts_id < tracksterCount; ts_id++) {
322 if (!tracksterMask[ts_id] && inputTracksters[ts_id].raw_pt() >=
seedPtThreshold_) {
323 outputSuperclusters.emplace_back(std::initializer_list<unsigned int>{ts_id});
324 resultTracksters.emplace_back(inputTracksters[ts_id]);
325 linkedTracksterIdToInputTracksterId.emplace_back(std::initializer_list<unsigned int>{ts_id});
330 for (std::vector<unsigned int>
const& sc : outputSuperclusters) {
331 std::ostringstream
s;
332 for (
unsigned int trackster_id : sc)
333 s << trackster_id <<
" ";
334 LogDebug(
"HGCalTICLSuperclustering") <<
"Created supercluster of size " << sc.size()
335 <<
" holding tracksters (first one is seed) " <<
s.str();
344 edm::allowedValues<std::string>(
"v1",
"v2"))
346 "DNN inputs version tag. Defines which set of features is fed to the DNN. Must match with the actual DNN.");
347 desc.add<
unsigned int>(
"inferenceBatchSize", 1
e5)
349 "Size of inference batches fed to DNN. Increasing it should produce faster inference but higher memory " 351 "Has no physics impact.");
352 desc.add<
double>(
"nnWorkingPoint")
353 ->setComment(
"Working point of DNN (in [0, 1]). DNN score above WP will attempt to supercluster.");
354 desc.add<
double>(
"deltaEtaWindow", 0.1)
356 "Size of delta eta window to consider for superclustering. Seed-candidate pairs outside this window " 357 "are not considered for DNN inference.");
358 desc.add<
double>(
"deltaPhiWindow", 0.5)
360 "Size of delta phi window to consider for superclustering. Seed-candidate pairs outside this window " 361 "are not considered for DNN inference.");
362 desc.add<
double>(
"seedPtThreshold", 4.)
363 ->setComment(
"Minimum transverse energy of trackster to be considered as seed of a supercluster");
364 desc.add<
double>(
"candidateEnergyThreshold", 2.)
365 ->setComment(
"Minimum energy of trackster to be considered as candidate for superclustering");
366 desc.add<
double>(
"explVarRatioCut_energyBoundary", 50.)
367 ->setComment(
"Boundary energy between low and high energy explVarRatio cut threshold");
368 desc.add<
double>(
"explVarRatioMinimum_lowEnergy", 0.92)
370 "Cut on explained variance ratio of tracksters to be considered as candidate, " 371 "for trackster raw_energy < explVarRatioCut_energyBoundary");
372 desc.add<
double>(
"explVarRatioMinimum_highEnergy", 0.95)
374 "Cut on explained variance ratio of tracksters to be considered as candidate, " 375 "for trackster raw_energy > explVarRatioCut_energyBoundary");
376 desc.add<
bool>(
"filterByTracksterPID",
true)->setComment(
"Filter tracksters before superclustering by PID score");
377 desc.add<std::vector<int>>(
378 "tracksterPIDCategoriesToFilter",
380 ->setComment(
"List of PID particle types (ticl::Trackster::ParticleType enum) to consider for PID filtering");
381 desc.add<
double>(
"PIDThreshold", 0.8)->setComment(
"PID score threshold");
void initialize(const HGCalDDDConstants *hgcons, const hgcal::RecHitTools rhtools, const edm::ESHandle< MagneticField > bfieldH, const edm::ESHandle< Propagator > propH) override
const float raw_pt() const
unsigned int inferenceBatchSize_
std::unique_ptr< AbstractSuperclusteringDNNInput > dnnInputs_
static void fillPSetDescription(edm::ParameterSetDescription &iDesc)
static constexpr int nPhiBins
const Vector & barycenter() const
TracksterLinkingbySuperClusteringDNN(const edm::ParameterSet &ps, edm::ConsumesCollector iC, cms::Ort::ONNXRuntime const *onnxRuntime=nullptr)
bool trackstersPassesPIDCut(const Trackster &ts) const
static std::string const input
void linkTracksters(const Inputs &input, std::vector< Trackster > &resultTracksters, std::vector< std::vector< unsigned int >> &linkedResultTracksters, std::vector< std::vector< unsigned int >> &linkedTracksterIdToInputTracksterId) override
bool filterByTracksterPID_
cms::Ort::ONNXRuntime const * onnxRuntime_
float explVarRatioMinimum_highEnergy_
std::vector< float > features(const reco::PreId &ecal, const reco::PreId &hcal, double rho, const reco::BeamSpot &spot, noZS::EcalClusterLazyTools &ecalTools)
const float raw_energy() const
Abs< T >::type abs(const T &t)
bool checkExplainedVarianceRatioCut(ticl::Trackster const &ts) const
float explVarRatioMinimum_lowEnergy_
static void fillPSetDescription(edm::ParameterSetDescription &desc)
std::vector< int > tracksterPIDCategoriesToFilter_
float explVarRatioCut_energyBoundary_
std::unique_ptr< AbstractSuperclusteringDNNInput > makeSuperclusteringDNNInputFromString(std::string dnnVersion)
float candidateEnergyThreshold_
const std::array< float, 8 > & id_probabilities() const
const std::array< float, 3 > & eigenvalues() const
FloatArrays run(const std::vector< std::string > &input_names, FloatArrays &input_values, const std::vector< std::vector< int64_t >> &input_shapes={}, const std::vector< std::string > &output_names={}, int64_t batch_size=1) const