181 ATH_MSG_WARNING(
"Model not loaded or Egamma pointer is null, returning cluster energy");
184 ATH_MSG_FATAL(
"Model not loaded or Egamma pointer is null, and useClusterIf0 is false, cannot proceed");
191 bool recoverySucceeded =
true;
194 if (maxECell.
sc == StatusCode::FAILURE) {
196 recoverySucceeded =
false;
201 ATH_MSG_WARNING(
"Cell Recovery Tool failed. Proceeding without recovered cells.");
202 recoverySucceeded =
false;
211 auto array_layer_scales = std::array<double, 4>{1.0, 1.0, 1.0, 1.0};
214 ATH_MSG_DEBUG(
"Applying layer recalibration for GNN on data.");
218 ATH_MSG_ERROR(
"EventInfo is required to apply data layer corrections; using configured fallback");
224 << array_layer_scales[0] <<
" " << array_layer_scales[1] <<
" "
225 << array_layer_scales[2] <<
" " << array_layer_scales[3]);
228 ATH_MSG_DEBUG(
"Applying extra layer scales for systematic studies, normally this is for MC events.");
230 ATH_MSG_WARNING(
"You are applying extra layer scales but the input is not MC! Are you sure this is intended?");
233 for (std::size_t i = 0; i < 4; ++i)
234 array_layer_scales[i] *= gei.
scaleEs[i];
244 ATH_MSG_DEBUG(
"raw Es " << raw_Es1 <<
" " << raw_Es2 <<
" " << raw_Es3);
247 std::vector<float> cells_E, cells_eta, cells_phi, cells_x, cells_y, cells_z;
248 std::vector<int> cells_layer;
249 std::vector<Identifier> included_cells;
252 double sum_cell_E_L0 = 0.0, sum_cell_E_L1 = 0.0, sum_cell_E_L2 = 0.0, sum_cell_E_L3 = 0.0, sum_cell_E_Gap = 0.0;
257 for (
const CaloCell* cell : *cellLinks) {
258 if (!cell || !cell->caloDDE()) {
263 int sampling = cell->caloDDE()->getSampling();
264 double scale_factor = 1.0;
268 case CaloCell_ID::PreSamplerB:
case CaloCell_ID::PreSamplerE:
269 scale_factor = array_layer_scales[0]; layer_idx = 0;
break;
270 case CaloCell_ID::EMB1:
case CaloCell_ID::EME1:
271 scale_factor = array_layer_scales[1]; layer_idx = 1;
break;
272 case CaloCell_ID::EMB2:
case CaloCell_ID::EME2:
273 scale_factor = array_layer_scales[2]; layer_idx = 2;
275 if (std::abs(cell->time()) >
m_timeCut) {
276 included_cells.push_back(cell->ID());
279 case CaloCell_ID::EMB3:
case CaloCell_ID::EME3:
280 scale_factor = array_layer_scales[3]; layer_idx = 3;
281 if (std::abs(cell->time()) >
m_timeCut) {
282 included_cells.push_back(cell->ID());
285 case CaloCell_ID::TileGap3:
286 scale_factor = 1.0; layer_idx = 4;
break;
290 double final_E = cell->e() * scale_factor;
292 cells_E.push_back(final_E);
293 cells_eta.push_back(cell->eta());
294 cells_phi.push_back(cell->phi());
295 cells_x.push_back(cell->x());
296 cells_y.push_back(cell->y());
297 cells_z.push_back(cell->z());
298 cells_layer.push_back(layer_idx);
302 case 0: sum_cell_E_L0 += final_E;
break;
303 case 1: sum_cell_E_L1 += final_E;
break;
304 case 2: sum_cell_E_L2 += final_E;
break;
305 case 3: sum_cell_E_L3 += final_E;
break;
306 case 4: sum_cell_E_Gap += final_E;
break;
313 if (recoverySucceeded) {
315 if (!cell || !cell->caloDDE())
continue;
318 if (std::find(included_cells.begin(), included_cells.end(), cell->ID()) != included_cells.end()) {
319 ATH_MSG_WARNING(
"Recovered cell " << cell->ID() <<
" already included in cluster. Skipping to avoid double counting.");
323 ATH_MSG_DEBUG(
"Adding recovered cell " << cell->ID() <<
" to cluster inputs.");
326 int sampling = cell->caloDDE()->getSampling();
327 double scale_factor = 1.0;
330 if (sampling == CaloCell_ID::EMB2 || sampling == CaloCell_ID::EME2) {
331 scale_factor = array_layer_scales[2]; layer_idx = 2;
332 }
else if (sampling == CaloCell_ID::EMB3 || sampling == CaloCell_ID::EME3) {
333 scale_factor = array_layer_scales[3]; layer_idx = 3;
336 if (sampling == CaloCell_ID::PreSamplerB || sampling == CaloCell_ID::PreSamplerE) {
337 scale_factor = array_layer_scales[0]; layer_idx = 0;
338 }
else if (sampling == CaloCell_ID::EMB1 || sampling == CaloCell_ID::EME1) {
339 scale_factor = array_layer_scales[1]; layer_idx = 1;
345 double final_E = cell->e() * scale_factor;
347 cells_E.push_back(final_E);
348 cells_eta.push_back(cell->eta());
349 cells_phi.push_back(cell->phi());
350 cells_x.push_back(cell->x());
351 cells_y.push_back(cell->y());
352 cells_z.push_back(cell->z());
353 cells_layer.push_back(layer_idx);
356 case 0: sum_cell_E_L0 += final_E;
break;
357 case 1: sum_cell_E_L1 += final_E;
break;
358 case 2: sum_cell_E_L2 += final_E;
break;
359 case 3: sum_cell_E_L3 += final_E;
break;
368 const size_t nCells = cells_E.size();
371 ATH_MSG_WARNING(
"No supported calorimeter cells; using configured fallback");
375 double sum_cell_E_total = sum_cell_E_L0 + sum_cell_E_L1 + sum_cell_E_L2 + sum_cell_E_L3;
376 const double cluster_eta = clus.
eta();
377 const double cluster_phi = clus.
phi();
379 std::vector<float> cells_deta, cells_dphi, cells_eFrac;
380 cells_deta.reserve(nCells);
381 cells_dphi.reserve(nCells);
382 cells_eFrac.reserve(nCells);
384 for (
size_t i = 0; i < nCells; ++i) {
385 float deta = cells_eta[i] - cluster_eta;
386 float dphi = cells_phi[i] - cluster_phi;
387 dphi = std::fmod(dphi + 3.0f *
M_PI, 2.0f *
M_PI) -
M_PI;
389 cells_deta.push_back(deta);
390 cells_dphi.push_back(dphi);
392 float eFrac_layer = 0.0f;
393 switch (cells_layer[i]) {
394 case 0: eFrac_layer = (sum_cell_E_L0 != 0) ? (cells_E[i] / sum_cell_E_L0) : 0.0f;
break;
395 case 1: eFrac_layer = (sum_cell_E_L1 != 0) ? (cells_E[i] / sum_cell_E_L1) : 0.0f;
break;
396 case 2: eFrac_layer = (sum_cell_E_L2 != 0) ? (cells_E[i] / sum_cell_E_L2) : 0.0f;
break;
397 case 3: eFrac_layer = (sum_cell_E_L3 != 0) ? (cells_E[i] / sum_cell_E_L3) : 0.0f;
break;
398 case 4: eFrac_layer = (sum_cell_E_Gap != 0) ? (cells_E[i] / sum_cell_E_Gap) : 0.0f;
break;
400 cells_eFrac.push_back(eFrac_layer);
404 double ratio_L1_L2 = (sum_cell_E_L2 != 0) ? (sum_cell_E_L1 / sum_cell_E_L2) : 0.0;
405 double main_layers_sum = sum_cell_E_L1 + sum_cell_E_L2 + sum_cell_E_L3;
406 double ratio_L0_total = (main_layers_sum != 0) ? (sum_cell_E_L0 / main_layers_sum) : 0.0;
407 double ratio_Tile_total = (main_layers_sum != 0) ? (sum_cell_E_Gap / main_layers_sum) : 0.0;
411 static const std::vector<std::string> featN = {
412 "Etot",
"E0",
"E1",
"E2",
"E3",
"Egap",
"cleta",
"clphi",
"E1/E2",
"E0/E123",
"Egap/E123",
413 "convR",
"convEoP",
"convPt1OPt2",
"convT" };
416 std::vector<float> cluster_feats = {
417 static_cast<float>(sum_cell_E_total),
418 static_cast<float>(sum_cell_E_L0),
419 static_cast<float>(sum_cell_E_L1),
420 static_cast<float>(sum_cell_E_L2),
421 static_cast<float>(sum_cell_E_L3),
422 static_cast<float>(sum_cell_E_Gap),
423 static_cast<float>(cluster_eta),
424 static_cast<float>(cluster_phi),
425 static_cast<float>(ratio_L1_L2),
426 static_cast<float>(ratio_L0_total),
427 static_cast<float>(ratio_Tile_total)
435 float convR = 799.0f;
441 float convEtOverPt = 0.0f;
445 (raw_Es1 * array_layer_scales[1] + raw_Es2 * array_layer_scales[2] + raw_Es3 * array_layer_scales[3]) :
446 (raw_Es1 + raw_Es2 + raw_Es3));
448 convEtOverPt = std::max(0.0f, eacc / (std::cosh(cl_eta) * ptconv));
450 convEtOverPt = std::min(convEtOverPt, 2.0f);
453 float convPtRatio = 1.0f;
457 if ((pt1 + pt2) > 0.0f) {
458 convPtRatio = std::max(pt1, pt2) / (pt1 + pt2);
463 float conversionType =
static_cast<float>(photon->conversionType());
465 cluster_feats.push_back(convR);
466 cluster_feats.push_back(convEtOverPt);
467 cluster_feats.push_back(convPtRatio);
468 cluster_feats.push_back(conversionType);
470 cluster_feats.push_back(0.0f);
471 cluster_feats.push_back(0.0f);
472 cluster_feats.push_back(0.0f);
473 cluster_feats.push_back(0.0f);
477 for (
int ifeat = 0;
auto f : cluster_feats) {
478 ATH_MSG_DEBUG(
"Cluster feature " << ifeat <<
" " << featN[ifeat] <<
" = " << f);
482 gnn_input[
"cluster_features"] = FlavorTagInference::Inputs(cluster_feats, {1, (int64_t)cluster_feats.size()});
485 std::vector<float> cell_feats_flat;
487 for (
size_t i = 0; i < nCells; ++i) {
488 cell_feats_flat.push_back(cells_eFrac[i]);
489 cell_feats_flat.push_back(cells_deta[i]);
490 cell_feats_flat.push_back(cells_dphi[i]);
491 cell_feats_flat.push_back(cells_x[i]);
492 cell_feats_flat.push_back(cells_y[i]);
493 cell_feats_flat.push_back(cells_z[i]);
494 cell_feats_flat.push_back(
static_cast<float>(cells_layer[i]));
496 <<
"Layer " << cells_layer[i] <<
" deta = " << cells_deta[i] <<
" dphi = " << cells_dphi[i]
497 <<
" x, y, z = " << cells_x[i] <<
" " << cells_y[i] <<
" " << cells_z[i]
498 <<
" eFrac = " << cells_eFrac[i]);
500 gnn_input[
"cell_features"] = FlavorTagInference::Inputs(cell_feats_flat, {(int64_t)nCells,
m_num_cell_features});
503 auto [out_f, out_vc, out_vf] =
m_saltModel->runInference(gnn_input);
505 float el_gnn_score = 0.0f;
507 if (output == out_vf.end() || output->second.empty()) {
510 el_gnn_score = output->second.front();
514 if (el_gnn_score == 0.0f) {
518 return el_gnn_score *
static_cast<float>(sum_cell_E_total);