17 #include "CLHEP/Units/SystemOfUnits.h" 
   27   m_plottedVariablesInitialized(false)
 
   37   const std::string this_name = this->
name();
 
   39   const std::string algorithm_name_prefix = this_name.substr(0, this_name.rfind(
'.'));
 
   43   auto final_string = [& algorithm_name_prefix](
const std::string & unpref_str) -> std::string
 
   45     return algorithm_name_prefix + 
"." + unpref_str;
 
   57       const std::string tool_name = final_string(
tool.tool);
 
   62   auto add_tool_from_pair = [
this](
const std::string & 
name) -> 
int 
   87       const int first_index = add_tool_from_pair(final_string(pair.tool_ref));
 
   88       const int second_index = add_tool_from_pair(final_string(pair.tool_test));
 
   91                                                    pair.match_without_shared,
 
   92                                                    pair.match_perfectly});
 
   97   return StatusCode::SUCCESS;
 
  108       auto mon_num_clust = 
Monitored::Scalar(k_v.second + 
"_num_total_clusters", m_numClustersPerTool.at(k_v.first).load());
 
  111   return StatusCode::SUCCESS;
 
  120       std::lock_guard<std::mutex> lock_guard(
m_mutex);
 
  126           ATH_CHECK( dhis->initialize_plotted_variables() );
 
  136   return StatusCode::SUCCESS;
 
  147       if (combination.index_ref < 0 || combination.index_test < 0)
 
  149           ATH_MSG_WARNING(
"Invalid tool combination, please check your configuration! " << combination.prefix);
 
  153                                  combination.match_in_energy, combination.match_without_shared, combination.match_perfectly) );
 
  160       m_storageHolder.release_one();
 
  164   return StatusCode::SUCCESS;
 
  180                                                 cell_info, cell_state, 
clusters, moments        )  );
 
  186       return StatusCode::SUCCESS;
 
  203       return StatusCode::SUCCESS;
 
  226       return StatusCode::SUCCESS;
 
  244                                                 cell_info, cell_state, 
clusters, moments          )  );
 
  250       return StatusCode::SUCCESS;
 
  273   if ( !cell_collection.
isValid() )
 
  275       ATH_MSG_ERROR( 
" Cannot retrieve CaloCellContainer: " << cell_collection.
name()  );
 
  276       return StatusCode::FAILURE;
 
  281   if (cluster_collection != 
nullptr)
 
  283       ret_state.allocate();
 
  284       ret_clusts.allocate();
 
  285       ret_moments.allocate();
 
  290       ret_info->energy[
i] = 0;
 
  291       ret_info->gain[
i] = GainConversion::invalid_gain();
 
  292       ret_info->time[
i] = 0;
 
  293       ret_info->qualityProvenance[
i] = 0;
 
  295       if (cluster_collection != 
nullptr)
 
  297           ret_state->clusterTag[
i] = ClusterTag::make_invalid_tag();
 
  309       const unsigned int gain = GainConversion::from_standard_gain(
cell->gain());
 
  318   if (cluster_collection != 
nullptr)
 
  320       const auto cluster_end = cluster_collection->
end();
 
  321       auto cluster_iter = cluster_collection->
begin();
 
  323       for (
int cluster_number = 0; cluster_iter != cluster_end; ++cluster_iter, ++cluster_number )
 
  329               ATH_MSG_ERROR(
"Can't get valid links to CaloCells (CaloClusterCellLink)!");
 
  330               return StatusCode::FAILURE;
 
  333           ret_clusts->clusterEnergy[cluster_number] = cluster->
e();
 
  334           ret_clusts->clusterEt[cluster_number] = cluster->
et();
 
  335           ret_clusts->clusterEta[cluster_number] = cluster->
eta();
 
  336           ret_clusts->clusterPhi[cluster_number] = cluster->
phi();
 
  348           ret_moments->time[cluster_number] = cluster->
time();
 
  391           ret_moments->numCells[cluster_number] = cluster->
numberCells();
 
  422           for (
auto it = cell_links->
begin(); 
it != cell_links->
end(); ++
it)
 
  424               const int cell_ID = 
m_calo_id->calo_cell_hash(
it->ID());
 
  428               std::memcpy(&weight_as_int, &
weight, 
sizeof(
float));
 
  433               if (weight_as_int == 0)
 
  441               const ClusterTag other_tag = ret_state->clusterTag[cell_ID];
 
  449                       ret_state->clusterTag[cell_ID] = ClusterTag::make_tag(cluster_number, weight_as_int, 0);
 
  453                       ret_state->clusterTag[cell_ID] = ClusterTag::make_tag(cluster_number);
 
  458                   ret_state->clusterTag[cell_ID] = ClusterTag::make_tag(cluster_number, other_tag.
secondary_cluster_weight(), other_index);
 
  463                   const int max_cluster = cluster_number > other_index ? cluster_number : other_index;
 
  464                   const int min_cluster = cluster_number > other_index ? other_index : cluster_number;
 
  465                   ret_state->clusterTag[cell_ID] = ClusterTag::make_tag(max_cluster, weight_as_int, min_cluster);
 
  469                   ret_state->clusterTag[cell_ID] = ClusterTag::make_tag(other_index, weight_as_int, cluster_number);
 
  474       ret_clusts->number = cluster_collection->
size();
 
  477   return StatusCode::SUCCESS;
 
  487   std::map<int, int> tag_map;
 
  489   std::vector<int> cluster_order(
clusters->number);
 
  491   std::iota(cluster_order.begin(), cluster_order.end(), 0);
 
  493   std::sort(cluster_order.begin(), cluster_order.end(), [&](
const int a, 
const int b)
 
  495     if (clusters->seedCellID[a] < 0)
 
  509   int real_cluster_numbers = 
clusters->number;
 
  511   for (
size_t i = 0; 
i < cluster_order.size(); ++
i)
 
  513       const int this_id = cluster_order[
i];
 
  514       if (
clusters->seedCellID[this_id] < 0)
 
  516           tag_map[this_id] = -1;
 
  517           --real_cluster_numbers;
 
  521           tag_map[this_id] = 
i;
 
  528   clusters->number = real_cluster_numbers;
 
  530   for (
int i = 0; 
i < temp_clusters->number; ++
i)
 
  532       clusters->clusterEnergy[
i]      =   temp_clusters->clusterEnergy[cluster_order[
i]];
 
  533       clusters->clusterEt[
i]          =   temp_clusters->clusterEt[cluster_order[
i]];
 
  534       clusters->clusterEta[
i]         =   temp_clusters->clusterEta[cluster_order[
i]];
 
  535       clusters->clusterPhi[
i]         =   temp_clusters->clusterPhi[cluster_order[
i]];
 
  536       clusters->seedCellID[
i]         =   temp_clusters->seedCellID[cluster_order[
i]];
 
  539           moments->energyPerSample[j][
i]     =   temp_moments->energyPerSample[j][cluster_order[
i]];
 
  540           moments->maxEPerSample[j][
i]       =   temp_moments->maxEPerSample[j][cluster_order[
i]];
 
  541           moments->maxPhiPerSample[j][
i]     =   temp_moments->maxPhiPerSample[j][cluster_order[
i]];
 
  542           moments->maxEtaPerSample[j][
i]     =   temp_moments->maxEtaPerSample[j][cluster_order[
i]];
 
  543           moments->etaPerSample[j][
i]        =   temp_moments->etaPerSample[j][cluster_order[
i]];
 
  544           moments->phiPerSample[j][
i]        =   temp_moments->phiPerSample[j][cluster_order[
i]];
 
  546       moments->time[
i]                =   temp_moments->time[cluster_order[
i]];
 
  547       moments->firstPhi[
i]            =   temp_moments->firstPhi[cluster_order[
i]];
 
  548       moments->firstEta[
i]            =   temp_moments->firstEta[cluster_order[
i]];
 
  549       moments->secondR[
i]             =   temp_moments->secondR[cluster_order[
i]];
 
  550       moments->secondLambda[
i]        =   temp_moments->secondLambda[cluster_order[
i]];
 
  551       moments->deltaPhi[
i]            =   temp_moments->deltaPhi[cluster_order[
i]];
 
  552       moments->deltaTheta[
i]          =   temp_moments->deltaTheta[cluster_order[
i]];
 
  553       moments->deltaAlpha[
i]          =   temp_moments->deltaAlpha[cluster_order[
i]];
 
  554       moments->centerX[
i]             =   temp_moments->centerX[cluster_order[
i]];
 
  555       moments->centerY[
i]             =   temp_moments->centerY[cluster_order[
i]];
 
  556       moments->centerZ[
i]             =   temp_moments->centerZ[cluster_order[
i]];
 
  557       moments->centerMag[
i]           =   temp_moments->centerMag[cluster_order[
i]];
 
  558       moments->centerLambda[
i]        =   temp_moments->centerLambda[cluster_order[
i]];
 
  559       moments->lateral[
i]             =   temp_moments->lateral[cluster_order[
i]];
 
  560       moments->longitudinal[
i]        =   temp_moments->longitudinal[cluster_order[
i]];
 
  561       moments->engFracEM[
i]           =   temp_moments->engFracEM[cluster_order[
i]];
 
  562       moments->engFracMax[
i]          =   temp_moments->engFracMax[cluster_order[
i]];
 
  563       moments->engFracCore[
i]         =   temp_moments->engFracCore[cluster_order[
i]];
 
  564       moments->firstEngDens[
i]        =   temp_moments->firstEngDens[cluster_order[
i]];
 
  565       moments->secondEngDens[
i]       =   temp_moments->secondEngDens[cluster_order[
i]];
 
  566       moments->isolation[
i]           =   temp_moments->isolation[cluster_order[
i]];
 
  567       moments->engBadCells[
i]         =   temp_moments->engBadCells[cluster_order[
i]];
 
  568       moments->nBadCells[
i]           =   temp_moments->nBadCells[cluster_order[
i]];
 
  569       moments->nBadCellsCorr[
i]       =   temp_moments->nBadCellsCorr[cluster_order[
i]];
 
  570       moments->badCellsCorrE[
i]       =   temp_moments->badCellsCorrE[cluster_order[
i]];
 
  571       moments->badLArQFrac[
i]         =   temp_moments->badLArQFrac[cluster_order[
i]];
 
  572       moments->engPos[
i]              =   temp_moments->engPos[cluster_order[
i]];
 
  573       moments->significance[
i]        =   temp_moments->significance[cluster_order[
i]];
 
  574       moments->cellSignificance[
i]    =   temp_moments->cellSignificance[cluster_order[
i]];
 
  575       moments->cellSigSampling[
i]     =   temp_moments->cellSigSampling[cluster_order[
i]];
 
  576       moments->avgLArQ[
i]             =   temp_moments->avgLArQ[cluster_order[
i]];
 
  577       moments->avgTileQ[
i]            =   temp_moments->avgTileQ[cluster_order[
i]];
 
  578       moments->engBadHVCells[
i]       =   temp_moments->engBadHVCells[cluster_order[
i]];
 
  579       moments->nBadHVCells[
i]         =   temp_moments->nBadHVCells[cluster_order[
i]];
 
  580       moments->PTD[
i]                 =   temp_moments->PTD[cluster_order[
i]];
 
  581       moments->mass[
i]                =   temp_moments->mass[cluster_order[
i]];
 
  582       moments->EMProbability[
i]       =   temp_moments->EMProbability[cluster_order[
i]];
 
  583       moments->hadWeight[
i]           =   temp_moments->hadWeight[cluster_order[
i]];
 
  584       moments->OOCweight[
i]           =   temp_moments->OOCweight[cluster_order[
i]];
 
  585       moments->DMweight[
i]            =   temp_moments->DMweight[cluster_order[
i]];
 
  586       moments->tileConfidenceLevel[
i] =   temp_moments->tileConfidenceLevel[cluster_order[
i]];
 
  587       moments->secondTime[
i]          =   temp_moments->secondTime[cluster_order[
i]];
 
  590           moments->nCellSampling[j][
i]       =   temp_moments->nCellSampling[j][cluster_order[
i]];
 
  592       moments->nExtraCellSampling[
i]  =   temp_moments->nExtraCellSampling[cluster_order[
i]];
 
  593       moments->numCells[
i]            =   temp_moments->numCells[cluster_order[
i]];
 
  594       moments->vertexFraction[
i]      =   temp_moments->vertexFraction[cluster_order[
i]];
 
  595       moments->nVertexFraction[
i]     =   temp_moments->nVertexFraction[cluster_order[
i]];
 
  596       moments->etaCaloFrame[
i]        =   temp_moments->etaCaloFrame[cluster_order[
i]];
 
  597       moments->phiCaloFrame[
i]        =   temp_moments->phiCaloFrame[cluster_order[
i]];
 
  598       moments->eta1CaloFrame[
i]       =   temp_moments->eta1CaloFrame[cluster_order[
i]];
 
  599       moments->phi1CaloFrame[
i]       =   temp_moments->phi1CaloFrame[cluster_order[
i]];
 
  600       moments->eta2CaloFrame[
i]       =   temp_moments->eta2CaloFrame[cluster_order[
i]];
 
  601       moments->phi2CaloFrame[
i]       =   temp_moments->phi2CaloFrame[cluster_order[
i]];
 
  602       moments->engCalibTot[
i]         =   temp_moments->engCalibTot[cluster_order[
i]];
 
  603       moments->engCalibOutL[
i]        =   temp_moments->engCalibOutL[cluster_order[
i]];
 
  604       moments->engCalibOutM[
i]        =   temp_moments->engCalibOutM[cluster_order[
i]];
 
  605       moments->engCalibOutT[
i]        =   temp_moments->engCalibOutT[cluster_order[
i]];
 
  606       moments->engCalibDeadL[
i]       =   temp_moments->engCalibDeadL[cluster_order[
i]];
 
  607       moments->engCalibDeadM[
i]       =   temp_moments->engCalibDeadM[cluster_order[
i]];
 
  608       moments->engCalibDeadT[
i]       =   temp_moments->engCalibDeadT[cluster_order[
i]];
 
  609       moments->engCalibEMB0[
i]        =   temp_moments->engCalibEMB0[cluster_order[
i]];
 
  610       moments->engCalibEME0[
i]        =   temp_moments->engCalibEME0[cluster_order[
i]];
 
  611       moments->engCalibTileG3[
i]      =   temp_moments->engCalibTileG3[cluster_order[
i]];
 
  612       moments->engCalibDeadTot[
i]     =   temp_moments->engCalibDeadTot[cluster_order[
i]];
 
  613       moments->engCalibDeadEMB0[
i]    =   temp_moments->engCalibDeadEMB0[cluster_order[
i]];
 
  614       moments->engCalibDeadTile0[
i]   =   temp_moments->engCalibDeadTile0[cluster_order[
i]];
 
  615       moments->engCalibDeadTileG3[
i]  =   temp_moments->engCalibDeadTileG3[cluster_order[
i]];
 
  616       moments->engCalibDeadEME0[
i]    =   temp_moments->engCalibDeadEME0[cluster_order[
i]];
 
  617       moments->engCalibDeadHEC0[
i]    =   temp_moments->engCalibDeadHEC0[cluster_order[
i]];
 
  618       moments->engCalibDeadFCAL[
i]    =   temp_moments->engCalibDeadFCAL[cluster_order[
i]];
 
  619       moments->engCalibDeadLeakage[
i] =   temp_moments->engCalibDeadLeakage[cluster_order[
i]];
 
  620       moments->engCalibDeadUnclass[
i] =   temp_moments->engCalibDeadUnclass[cluster_order[
i]];
 
  621       moments->engCalibFracEM[
i]      =   temp_moments->engCalibFracEM[cluster_order[
i]];
 
  622       moments->engCalibFracHad[
i]     =   temp_moments->engCalibFracHad[cluster_order[
i]];
 
  623       moments->engCalibFracRest[
i]    =   temp_moments->engCalibFracRest[cluster_order[
i]];
 
  628       if (!cell_info->is_valid(
i))
 
  632       const ClusterTag this_tag = cell_state->clusterTag[
i];
 
  635           cell_state->clusterTag[
i] = ClusterTag::make_invalid_tag();
 
  640           const int new_idx = tag_map[old_idx];
 
  642           const int new_idx2 = old_idx2 >= 0 ? tag_map[old_idx2] : -1;
 
  643           if (new_idx < 0 && new_idx2 < 0)
 
  645               cell_state->clusterTag[
i] = ClusterTag::make_invalid_tag();
 
  647           else if (new_idx < 0)
 
  649               cell_state->clusterTag[
i] = ClusterTag::make_tag(new_idx2);
 
  651           else if (new_idx2 < 0)
 
  653               cell_state->clusterTag[
i] = ClusterTag::make_tag(new_idx);
 
  662   return StatusCode::SUCCESS;
 
  667   template <
class ... 
Args>
 
  668   struct multi_class_holder
 
  670     static constexpr 
size_t size()
 
  672       return sizeof...(Args);
 
  678   static constexpr decltype(
auto) suppress_warning(Arg && 
a)
 
  680     return std::forward<Arg>(
a);
 
  683   template <
class F, 
class ... 
Types, 
class ... 
Args>
 
  684   void apply_to_multi_class(
F && 
f, 
const multi_class_holder<Types...> &, 
Args && ... 
args)
 
  687     if constexpr (std::is_same_v < decltype(
f((
Types{}, ...), 
i, std::forward<Args>(
args)...)), 
void > )
 
  689         (
f(
Types{}, 
i++, std::forward<Args>(
args)...), ...);
 
  693         (suppress_warning(
f(
Types{}, 
i++, std::forward<Args>(
args)...)), ...);
 
  697   static float float_unhack(
const unsigned int bits)
 
  700     std::memcpy(&
res, &bits, 
sizeof(
float));
 
  705   static double protect_from_zero(
const double x)
 
  707     return x == 0 ? 1
e-15 : 
x;
 
  710   static float protect_from_zero(
const float x)
 
  712     return x == 0 ? 1
e-7 : 
x;
 
  725                                                             const bool match_in_energy,
 
  726                                                             const bool match_without_shared)
 const 
  734   std::vector<double> similarity_map(cluster_info_1.
number * cluster_info_2.
number, 0.);
 
  736   std::vector<double> ref_normalization(cluster_info_1.
number, 0.);
 
  737   std::vector<double> test_normalization(cluster_info_2.
number, 0.);
 
  749       double SNR = 0.00001;
 
  756           if (std::isfinite(cellNoise) && cellNoise > 0.0
f)
 
  758               SNR = std::abs(cell_info.
energy[
i] / cellNoise);
 
  762       const double quantity = ( match_in_energy ? std::abs(cell_info.
energy[
i]) : SNR );
 
  763       const double weight = (quantity + 1
e-8) *
 
  772       int ref_c1 = -1, ref_c2 = -1, test_c1 = -1, test_c2 = -1;
 
  797       float ref_cw = 1.0f - ref_rev_cw;
 
  798       float test_cw = 1.0f - test_rev_cw;
 
  800       if (ref_c1 >= 
int(cluster_info_1.
number) || ref_c2 >= 
int(cluster_info_1.
number) ||
 
  801           test_c1 >= 
int(cluster_info_2.
number) || test_c2 >= 
int(cluster_info_2.
number) )
 
  803           ATH_MSG_DEBUG(  
"Error in matches: " << 
i << 
" " << ref_c1 << 
" " << ref_c2 << 
" " 
  804                           << test_c1 << 
" " << test_c2 << 
" (" 
  805                           << cluster_info_1.
number << 
" | " << cluster_info_2.
number << 
")"   );
 
  809       if (ref_c1 >= 0 && test_c1 >= 0)
 
  811           similarity_map[test_c1 * cluster_info_1.
number + ref_c1] += 
weight * ref_cw * test_cw;
 
  812           similarity_map[test_c1 * cluster_info_1.
number + ref_c2] += 
weight * ref_rev_cw * test_cw;
 
  813           similarity_map[test_c2 * cluster_info_1.
number + ref_c1] += 
weight * ref_cw * test_rev_cw;
 
  814           similarity_map[test_c2 * cluster_info_1.
number + ref_c2] += 
weight * ref_rev_cw * test_rev_cw;
 
  818           ref_normalization[ref_c1] += 
weight * ref_cw * ref_cw;
 
  819           ref_normalization[ref_c2] += 
weight * ref_rev_cw * ref_rev_cw;
 
  823           test_normalization[test_c1] += 
weight * test_cw * test_cw;
 
  824           test_normalization[test_c2] += 
weight * test_rev_cw * test_rev_cw;
 
  828   for (
int testc = 0; testc < cluster_info_2.
number; ++testc)
 
  830       const double test_norm = test_normalization[testc] + 
double(test_normalization[testc] == 0.);
 
  831       for (
int refc = 0; refc < cluster_info_1.
number; ++refc)
 
  833           const double ref_norm = ref_normalization[refc] + 
double(ref_normalization[refc] == 0.);
 
  834           similarity_map[testc * cluster_info_1.
number + refc] /= std::sqrt(ref_norm * test_norm);
 
  840   std::vector<std::vector<int>> sorted_GPU_matches;
 
  842   sorted_GPU_matches.reserve(cluster_info_2.
number);
 
  844   for (
int testc = 0; testc < cluster_info_2.
number; ++testc)
 
  850                 [&](
const int a, 
const int b)
 
  852         const double a_weight = similarity_map[testc * cluster_info_1.number + a];
 
  853         const double b_weight = similarity_map[testc * cluster_info_1.number + b];
 
  854         return a_weight > b_weight;
 
  858       size_t wanted_size = 0;
 
  860       for (; wanted_size < 
sorter.size(); ++wanted_size)
 
  862           const double match_weight = similarity_map[testc * cluster_info_1.
number + 
sorter[wanted_size]];
 
  875       sorter.resize(wanted_size);
 
  877       sorted_GPU_matches.push_back(
sorter);
 
  882   constexpr 
int max_iter = 32;
 
  884   std::vector<double> matched_weights(cluster_info_1.
number, -1.);
 
  886   std::vector<size_t> skipped_matching(cluster_info_2.
number, 0);
 
  888   for (
int stop_counter = 0; stop_counter < cluster_info_2.
number && num_iter < max_iter; ++num_iter)
 
  891       for (
int testc = 0; testc < 
int(sorted_GPU_matches.size()); ++testc)
 
  893           if (skipped_matching[testc] < sorted_GPU_matches[testc].
size())
 
  895               const int match_c = sorted_GPU_matches[testc][skipped_matching[testc]];
 
  896               const double match_weight = similarity_map[testc * cluster_info_1.
number + match_c];
 
  897               if (match_weight >= 
m_min_similarity && match_weight > matched_weights[match_c])
 
  899                   const int prev_match = sch.
r2t_table[match_c];
 
  902                       ++skipped_matching[prev_match];
 
  906                   matched_weights[match_c] = match_weight;
 
  911                   ++skipped_matching[testc];
 
  946     char message_buffer[256];
 
  947     snprintf(message_buffer, 256,
 
  948              "%2d: %5d / %5d || %5d / %5d || %3d || %5d | %5d || %5d",
 
  960   return StatusCode::SUCCESS;
 
  973                                                                       const bool match_without_shared)
 const 
  981   std::vector<char> match_possibilities(cluster_info_1.
number * cluster_info_2.
number, 1);
 
  993       int ref_c1 = -1, ref_c2 = -1, test_c1 = -1, test_c2 = -1;
 
 1015       for (
int refc = 0; refc < cluster_info_1.
number; ++refc)
 
 1017           if (refc == ref_c1 || refc == ref_c2)
 
 1024               match_possibilities[test_c1 * cluster_info_1.
number + refc] = 0;
 
 1028               match_possibilities[test_c2 * cluster_info_1.
number + refc] = 0;
 
 1032       for (
int testc = 0; testc < cluster_info_2.
number; ++testc)
 
 1034           if (testc == test_c1 || testc == test_c2)
 
 1041               match_possibilities[testc * cluster_info_1.
number + ref_c1] = 0;
 
 1045               match_possibilities[testc * cluster_info_1.
number + ref_c2] = 0;
 
 1051   for (
int testc = 0; testc < cluster_info_2.
number; ++testc)
 
 1053       for (
int refc = 0; refc < cluster_info_1.
number; ++refc)
 
 1055           if (match_possibilities[testc * cluster_info_1.
number + refc] > 0)
 
 1063   for (
int refc = 0; refc < cluster_info_1.
number; ++refc)
 
 1071   for (
int testc = 0; testc < cluster_info_2.
number; ++testc)
 
 1080     char message_buffer[256];
 
 1081     snprintf(message_buffer, 256,
 
 1082              "%2d: %5d / %5d || %5d / %5d || %3d || %5d | %5d || %5d",
 
 1094   return StatusCode::SUCCESS;
 
 1103 #define CALORECGPU_BASIC_CLUSTER_PROPERTY(NAME, ...)                                                                              \ 
 1104   struct clusters_ ## NAME                                                                                                        \ 
 1106     static std::string name()                                                                                                     \ 
 1110     static double get_property([[maybe_unused]] const ConstantDataHolder & constant_data,                                         \ 
 1111                                [[maybe_unused]] const CaloRecGPU::CellInfoArr & cell_info,                                        \ 
 1112                                [[maybe_unused]] const CaloRecGPU::CellStateArr & cell_state,                                      \ 
 1113                                [[maybe_unused]] const CaloRecGPU::ClusterInfoArr & cluster_info,                                  \ 
 1114                                [[maybe_unused]] const CaloRecGPU::ClusterMomentsArr & cluster_moments,                            \ 
 1115                                [[maybe_unused]] const int cluster_index                                   )                       \ 
 1133 #define CALORECGPU_CLUSTER_MOMENT(...) CALORECGPU_CLUSTER_MOMENT_INNER(__VA_ARGS__, 1, 1) 
 1134 #define CALORECGPU_CLUSTER_MOMENT_INNER(NAME, PROPERTY, UNIT, ...) CALORECGPU_BASIC_CLUSTER_PROPERTY(moments_ ## NAME, return cluster_moments . PROPERTY [cluster_index] / UNIT;) 
 1210     using BasicClusterProperties = multi_class_holder <
 
 1217                                    clusters_moments_time,
 
 1218                                    clusters_moments_FIRST_PHI,
 
 1219                                    clusters_moments_FIRST_ETA,
 
 1220                                    clusters_moments_SECOND_R,
 
 1221                                    clusters_moments_SECOND_LAMBDA,
 
 1222                                    clusters_moments_DELTA_PHI,
 
 1223                                    clusters_moments_DELTA_THETA,
 
 1224                                    clusters_moments_DELTA_ALPHA,
 
 1225                                    clusters_moments_CENTER_X,
 
 1226                                    clusters_moments_CENTER_Y,
 
 1227                                    clusters_moments_CENTER_Z,
 
 1228                                    clusters_moments_CENTER_MAG,
 
 1229                                    clusters_moments_CENTER_LAMBDA,
 
 1230                                    clusters_moments_LATERAL,
 
 1231                                    clusters_moments_LONGITUDINAL,
 
 1232                                    clusters_moments_ENG_FRAC_EM,
 
 1233                                    clusters_moments_ENG_FRAC_MAX,
 
 1234                                    clusters_moments_ENG_FRAC_CORE,
 
 1235                                    clusters_moments_FIRST_ENG_DENS,
 
 1236                                    clusters_moments_SECOND_ENG_DENS,
 
 1237                                    clusters_moments_ISOLATION,
 
 1238                                    clusters_moments_ENG_BAD_CELLS,
 
 1239                                    clusters_moments_N_BAD_CELLS,
 
 1240                                    clusters_moments_N_BAD_CELLS_CORR,
 
 1241                                    clusters_moments_BAD_CELLS_CORR_E,
 
 1242                                    clusters_moments_BADLARQ_FRAC,
 
 1243                                    clusters_moments_ENG_POS,
 
 1244                                    clusters_moments_SIGNIFICANCE,
 
 1245                                    clusters_moments_CELL_SIGNIFICANCE,
 
 1246                                    clusters_moments_CELL_SIG_SAMPLING,
 
 1247                                    clusters_moments_AVG_LAR_Q,
 
 1248                                    clusters_moments_AVG_TILE_Q,
 
 1249                                    clusters_moments_ENG_BAD_HV_CELLS,
 
 1250                                    clusters_moments_N_BAD_HV_CELLS,
 
 1251                                    clusters_moments_PTD,
 
 1252                                    clusters_moments_MASS,
 
 1253                                    clusters_moments_EM_PROBABILITY,
 
 1254                                    clusters_moments_HAD_WEIGHT,
 
 1255                                    clusters_moments_OOC_WEIGHT,
 
 1256                                    clusters_moments_DM_WEIGHT,
 
 1257                                    clusters_moments_TILE_CONFIDENCE_LEVEL,
 
 1258                                    clusters_moments_SECOND_TIME,
 
 1259                                    clusters_moments_number_of_cells,
 
 1260                                    clusters_moments_VERTEX_FRACTION,
 
 1261                                    clusters_moments_NVERTEX_FRACTION,
 
 1262                                    clusters_moments_ETACALOFRAME,
 
 1263                                    clusters_moments_PHICALOFRAME,
 
 1264                                    clusters_moments_ETA1CALOFRAME,
 
 1265                                    clusters_moments_PHI1CALOFRAME,
 
 1266                                    clusters_moments_ETA2CALOFRAME,
 
 1267                                    clusters_moments_PHI2CALOFRAME,
 
 1268                                    clusters_moments_ENG_CALIB_TOT,
 
 1269                                    clusters_moments_ENG_CALIB_OUT_L,
 
 1270                                    clusters_moments_ENG_CALIB_OUT_M,
 
 1271                                    clusters_moments_ENG_CALIB_OUT_T,
 
 1272                                    clusters_moments_ENG_CALIB_DEAD_L,
 
 1273                                    clusters_moments_ENG_CALIB_DEAD_M,
 
 1274                                    clusters_moments_ENG_CALIB_DEAD_T,
 
 1275                                    clusters_moments_ENG_CALIB_EMB0,
 
 1276                                    clusters_moments_ENG_CALIB_EME0,
 
 1277                                    clusters_moments_ENG_CALIB_TILEG3,
 
 1278                                    clusters_moments_ENG_CALIB_DEAD_TOT,
 
 1279                                    clusters_moments_ENG_CALIB_DEAD_EMB0,
 
 1280                                    clusters_moments_ENG_CALIB_DEAD_TILE0,
 
 1281                                    clusters_moments_ENG_CALIB_DEAD_TILEG3,
 
 1282                                    clusters_moments_ENG_CALIB_DEAD_EME0,
 
 1283                                    clusters_moments_ENG_CALIB_DEAD_HEC0,
 
 1284                                    clusters_moments_ENG_CALIB_DEAD_FCAL,
 
 1285                                    clusters_moments_ENG_CALIB_DEAD_LEAKAGE,
 
 1286                                    clusters_moments_ENG_CALIB_DEAD_UNCLASS,
 
 1287                                    clusters_moments_ENG_CALIB_FRAC_EM,
 
 1288                                    clusters_moments_ENG_CALIB_FRAC_HAD,
 
 1289                                    clusters_moments_ENG_CALIB_FRAC_REST
 
 1295   using ClusterProperties::BasicClusterProperties;
 
 1299 #define CALORECGPU_COMPARED_CLUSTER_PROPERTY(NAME, ...)                                                                           \ 
 1300   struct clusters_ ## NAME                                                                                                        \ 
 1302     static std::string name()                                                                                                     \ 
 1306     static double get_property([[maybe_unused]] const ConstantDataHolder & constant_data,                                         \ 
 1307                                [[maybe_unused]] const CaloRecGPU::CellInfoArr & cell_info_1,                                      \ 
 1308                                [[maybe_unused]] const CaloRecGPU::CellStateArr & cell_state_1,                                    \ 
 1309                                [[maybe_unused]] const CaloRecGPU::ClusterInfoArr & cluster_info_1,                                \ 
 1310                                [[maybe_unused]] const CaloRecGPU::ClusterMomentsArr & cluster_moments_1,                          \ 
 1311                                [[maybe_unused]] const int cluster_index_1,                                                        \ 
 1312                                [[maybe_unused]] const CaloRecGPU::CellInfoArr & cell_info_2,                                      \ 
 1313                                [[maybe_unused]] const CaloRecGPU::CellStateArr & cell_state_2,                                    \ 
 1314                                [[maybe_unused]] const CaloRecGPU::ClusterInfoArr & cluster_info_2,                                \ 
 1315                                [[maybe_unused]] const CaloRecGPU::ClusterMomentsArr & cluster_moments_2,                          \ 
 1316                                [[maybe_unused]] const int cluster_index_2)                                                        \ 
 1323                                          return Helpers::regularize_angle( Helpers::regularize_angle(cluster_info_2.clusterPhi[cluster_index_2]) -
 
 1324                                                                            Helpers::regularize_angle(cluster_info_1.clusterPhi[cluster_index_1])    );
 
 1328                                          const double delta_eta = cluster_info_2.clusterEta[cluster_index_2] - cluster_info_1.clusterEta[cluster_index_1];
 
 1329                                          const double delta_phi = Helpers::regularize_angle( Helpers::regularize_angle(cluster_info_2.clusterPhi[cluster_index_2]) -
 
 1330                                                                                              Helpers::regularize_angle(cluster_info_1.clusterPhi[cluster_index_1])    );
 
 1336     using ComparedClusterProperties = multi_class_holder <
 
 1338                                       clusters_delta_phi_in_range,
 
 1345   using ExtraClusterComparisons::ComparedClusterProperties;
 
 1349 #define CALORECGPU_BASIC_CELL_PROPERTY(NAME, ...)                                                                                 \ 
 1350   struct cells_ ## NAME                                                                                                           \ 
 1352     static std::string name()                                                                                                     \ 
 1356     static double get_property([[maybe_unused]] const ConstantDataHolder & constant_data,                                         \ 
 1357                                [[maybe_unused]] const CaloRecGPU::CellInfoArr & cell_info,                                        \ 
 1358                                [[maybe_unused]] const CaloRecGPU::CellStateArr & cell_state,                                      \ 
 1359                                [[maybe_unused]] const CaloRecGPU::ClusterInfoArr & cluster_info,                                  \ 
 1360                                [[maybe_unused]] const CaloRecGPU::ClusterMomentsArr & cluster_moments,                            \ 
 1361                                [[maybe_unused]] const int cell                                          )                         \ 
 1375                                                protect_from_zero(constant_data.m_cell_noise->get_noise(
cell, cell_info.gain[
cell]));
 
 1379                                                              protect_from_zero(constant_data.m_cell_noise->get_noise(
cell, cell_info.gain[
cell])));)
 
 1404       if (
tag.is_part_of_cluster())
 
 1406           float rev_weight = float_unhack(tag.secondary_cluster_weight());
 
 1407           return 1.0f - rev_weight;
 
 1419       if (
tag.is_part_of_cluster())
 
 1421           float rev_weight = float_unhack(tag.secondary_cluster_weight());
 
 1431     using BasicCellProperties = multi_class_holder <
 
 1447                                 cells_primary_cluster_index,
 
 1448                                 cells_secondary_cluster_index,
 
 1449                                 cells_primary_weight,
 
 1450                                 cells_secondary_weight
 
 1456   using CellProperties::BasicCellProperties;
 
 1460 #define CALORECGPU_BASIC_CELL_TYPE(NAME, ...)                                                                                     \ 
 1461   struct cell_type_ ## NAME                                                                                                       \ 
 1463     static std::string name()                                                                                                     \ 
 1467     static bool is_type([[maybe_unused]] const ConstantDataHolder & constant_data,                                                \ 
 1468                         [[maybe_unused]] const CaloRecGPU::CellInfoArr & cell_info,                                               \ 
 1469                         [[maybe_unused]] const CaloRecGPU::CellStateArr & cell_state,                                             \ 
 1470                         [[maybe_unused]] const CaloRecGPU::ClusterInfoArr & cluster_info,                                         \ 
 1471                         [[maybe_unused]] const CaloRecGPU::ClusterMomentsArr & cluster_moments,                                   \ 
 1472                         [[maybe_unused]] const int cell                                          )                                \ 
 1484                                return tag.is_part_of_cluster() && 
tag.is_shared_between_clusters(); )
 
 1486     using BasicCellTypes = multi_class_holder <
 
 1488                            cell_type_intracluster,
 
 1489                            cell_type_extracluster,
 
 1499   enum ExtraThingsToCalculate
 
 1502     ClusterComparedSize,
 
 1507     SameSNRCellsCombined,
 
 1514   const std::vector<std::string> histo_strings = 
m_moniTool->histogramService()->getHists();
 
 1527   auto string_contains = [](
const std::string & container, 
const std::string & contained) -> 
bool 
 1529     return container.find(contained) != std::string::npos;
 
 1532   auto search_lambda = [&](
const auto & prop, 
const size_t count, 
bool & 
check,
 
 1533                            const std::string & 
str, std::vector<bool> & to_do,
 
 1534                            const std::string & 
prefix = 
"", 
const std::string & 
suffix = 
"")
 
 1538         to_do[
count] = 
true;
 
 1543   for (
const auto & 
str : histo_strings)
 
 1590       if ( string_contains(
str, 
"cluster_size_ref")            ||
 
 1591            string_contains(
str, 
"cluster_size_test")           ||
 
 1592            string_contains(
str, 
"cluster_delta_size")          ||
 
 1593            string_contains(
str, 
"cluster_weighted_size_ref")   ||
 
 1594            string_contains(
str, 
"cluster_weighted_size_test")  ||
 
 1595            string_contains(
str, 
"cluster_delta_weighted_size")    )
 
 1601       else if ( string_contains(
str, 
"cluster_size")          ||
 
 1602                 string_contains(
str, 
"cluster_weighted_size")    )
 
 1609       if (string_contains(
str, 
"cluster_diff_cells"))
 
 1616       if ( string_contains(
str, 
"_num_same_E_cells_ref")      ||
 
 1617            string_contains(
str, 
"_num_same_E_cells_test")     ||
 
 1618            string_contains(
str, 
"delta_num_same_E_cells")     ||
 
 1619            string_contains(
str, 
"_num_same_abs_E_cells_ref")  ||
 
 1620            string_contains(
str, 
"_num_same_abs_E_cells_test") ||
 
 1621            string_contains(
str, 
"delta_num_same_abs_E_cells")    )
 
 1626       else if ( string_contains(
str, 
"_num_same_E_cells")     ||
 
 1627                 string_contains(
str, 
"_num_same_abs_E_cells")    )
 
 1633       if ( string_contains(
str, 
"_num_same_SNR_cells_ref")      ||
 
 1634            string_contains(
str, 
"_num_same_SNR_cells_test")     ||
 
 1635            string_contains(
str, 
"delta_num_same_SNR_cells")     ||
 
 1636            string_contains(
str, 
"_num_same_abs_SNR_cells_ref")  ||
 
 1637            string_contains(
str, 
"_num_same_abs_SNR_cells_test") ||
 
 1638            string_contains(
str, 
"delta_num_same_abs_SNR_cells")    )
 
 1643       else if ( string_contains(
str, 
"_num_same_SNR_cells")     ||
 
 1644                 string_contains(
str, 
"_num_same_abs_SNR_cells")    )
 
 1651   return StatusCode::SUCCESS;
 
 1662                                                       const std::string & tool_name)
 const 
 1664   m_numClustersPerTool[tool_name].fetch_add(
clusters->number);
 
 1672       std::vector<per_tool_storage> & store_vec = m_storageHolder.get_for_thread();
 
 1673       store_vec[
index].cell_info = *cell_info;
 
 1674       store_vec[
index].cell_state = *cell_state;
 
 1676       store_vec[
index].moments = *moments;
 
 1683       std::unordered_map<std::string, std::vector<double>> cluster_properties, cell_properties;
 
 1685       std::unordered_map<std::string, long long int> cell_counts;
 
 1687       cluster_properties[
"size"].resize(
clusters->number, 0.);
 
 1688       cluster_properties[
"weighted_size"].resize(
clusters->number, 0.);
 
 1690       long long int same_energy = 0, same_abs_energy = 0, same_snr = 0, same_abs_snr = 0;
 
 1692       std::set<double> energies, snrs;
 
 1699               if (!cell_info->is_valid(
cell))
 
 1704               apply_to_multi_class([&](
const auto & prop, 
const size_t i)
 
 1708                     cell_properties[prop.name()].push_back(prop.get_property(constant_data, *cell_info, *cell_state, *
clusters, *moments, 
cell));
 
 1710               }, BasicCellProperties{});
 
 1712               apply_to_multi_class([&](
const auto & prop, 
const size_t i)
 
 1716                     cell_counts[prop.name()] += prop.is_type(constant_data, *cell_info, *cell_state, *
clusters, *moments, 
cell);
 
 1718               }, BasicCellTypes{});
 
 1720               const float this_energy = cell_info->energy[
cell];
 
 1725                   if (energies.count(this_energy))
 
 1730                   else if (energies.count(-this_energy))
 
 1734                   energies.insert(this_energy);
 
 1740                   const float this_snr = this_energy / protect_from_zero(constant_data.
m_cell_noise->get_noise(
cell, cell_info->gain[
cell]));
 
 1742                   if (snrs.count(this_snr))
 
 1747                   else if (snrs.count(-this_snr))
 
 1751                   snrs.insert(this_snr);
 
 1757                   const float weight = float_unhack(
tag.secondary_cluster_weight());
 
 1758                   if (
tag.is_part_of_cluster())
 
 1760                       cluster_properties[
"size"][
tag.cluster_index()] += 1;
 
 1761                       cluster_properties[
"weighted_size"][
tag.cluster_index()] += 1.0f - 
weight;
 
 1762                       if (
tag.is_shared_between_clusters())
 
 1764                           cluster_properties[
"size"][
tag.secondary_cluster_index()] += 1;
 
 1765                           cluster_properties[
"weighted_size"][
tag.secondary_cluster_index()] += 
weight;
 
 1774           for (
int cluster = 0; cluster < 
clusters->number; ++cluster)
 
 1776               apply_to_multi_class([&](
const auto & prop, 
const size_t i)
 
 1780                     cluster_properties[prop.name()].push_back(prop.get_property(constant_data, *cell_info, *cell_state, *
clusters, *moments, cluster));
 
 1782               }, BasicClusterProperties{});
 
 1787       using scalar_type = decltype(
Monitored::Scalar(
"", std::declval<long long int>()));
 
 1789       std::vector<coll_type> collections;
 
 1790       std::vector<scalar_type> count_scalars;
 
 1791       std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> cluster_group, cell_group, counts_group;
 
 1793       collections.reserve(cluster_properties.size() + cell_properties.size());
 
 1794       count_scalars.reserve(cell_counts.size());
 
 1795       cluster_group.reserve(cluster_properties.size());
 
 1796       cell_group.reserve(cell_properties.size());
 
 1797       counts_group.reserve(cell_counts.size() + 5);
 
 1805       counts_group.push_back(
std::ref(mon_clus_num));
 
 1806       counts_group.push_back(
std::ref(mon_same_energy));
 
 1807       counts_group.push_back(
std::ref(mon_same_abs_energy));
 
 1808       counts_group.push_back(
std::ref(mon_same_snr));
 
 1809       counts_group.push_back(
std::ref(mon_same_abs_snr));
 
 1815       for (
const auto & k_v : cluster_properties)
 
 1818           cluster_group.push_back(
std::ref(collections.back()));
 
 1821       for (
const auto & k_v : cell_properties)
 
 1824           cell_group.push_back(
std::ref(collections.back()));
 
 1827       for (
const auto & k_v : cell_counts)
 
 1830           counts_group.push_back(
std::ref(count_scalars.back()));
 
 1841   return StatusCode::SUCCESS;
 
 1849                                                              const std::string & 
prefix,
 
 1850                                                              const bool match_in_energy,
 
 1851                                                              const bool match_without_shared,
 
 1852                                                              const bool match_perfectly)
 const 
 1860   std::vector<per_tool_storage> & store_vec = m_storageHolder.get_for_thread();
 
 1874   if (match_perfectly)
 
 1877                                           clusters_1, clusters_2, moments_1, moments_2, match_without_shared) );
 
 1882                                 clusters_1, clusters_2, moments_1, moments_2, match_in_energy, match_without_shared) );
 
 1885   std::unordered_map<std::string, std::vector<double>> cluster_properties, cell_properties;
 
 1887   std::unordered_map<std::string, long long int> cell_counts;
 
 1889   std::vector<double> ref_size_vec(clusters_1.
number, 0.), test_size_vec(clusters_2.
number, 0.),
 
 1890       ref_weighted_size_vec(clusters_1.
number, 0.), test_weighted_size_vec(clusters_2.
number, 0.),
 
 1891       ref_diff_cells(clusters_1.
number, 0.), test_diff_cells(clusters_2.
number, 0.),
 
 1892       ref_diff_cells_weight(clusters_1.
number, 0.), test_diff_cells_weight(clusters_2.
number, 0.);
 
 1895   long long int same_energy_1 = 0, same_energy_2 = 0,
 
 1896                 same_abs_energy_1 = 0, same_abs_energy_2 = 0,
 
 1897                 same_snr_1 = 0, same_snr_2 = 0,
 
 1898                 same_abs_snr_1 = 0, same_abs_snr_2 = 0,
 
 1899                 same_cluster_cells_count = 0, diff_cluster_cells_count = 0;
 
 1901   std::set<double> energies_1, energies_2, snrs_1, snrs_2;
 
 1912           apply_to_multi_class([&](
const auto & prop, 
const size_t i)
 
 1916                 const auto prop_1 = prop.get_property(constant_data, cell_info_1, cell_state_1, clusters_1, moments_1, 
cell);
 
 1917                 const auto prop_2 = prop.get_property(constant_data, cell_info_2, cell_state_2, clusters_2, moments_2, 
cell);
 
 1919                 cell_properties[prop.name() + 
"_ref"].push_back(prop_1);
 
 1920                 cell_properties[prop.name() + 
"_test"].push_back(prop_2);
 
 1922                 cell_properties[
"delta_" + prop.name()].push_back(prop_2 - prop_1);
 
 1923                 cell_properties[
"delta_" + prop.name() + 
"_rel_ref"].push_back((prop_2 - prop_1) / protect_from_zero(std::abs(prop_1)));
 
 1924                 cell_properties[
"delta_" + prop.name() + 
"_rel_test"].push_back((prop_2 - prop_1) / protect_from_zero(std::abs(prop_2)));
 
 1926           }, BasicCellProperties{});
 
 1928           apply_to_multi_class([&](
const auto & prop, 
const size_t i)
 
 1932                 const auto is_1 = prop.is_type(constant_data, cell_info_1, cell_state_1, clusters_1, moments_1, 
cell);
 
 1933                 const auto is_2 = prop.is_type(constant_data, cell_info_2, cell_state_2, clusters_2, moments_2, 
cell);
 
 1935                 cell_counts[
"num_" + prop.name() + 
"_cells_ref"] += is_1;
 
 1936                 cell_counts[
"num_" + prop.name() + 
"_cells_test"] += is_2;
 
 1937                 cell_counts[
"delta_num_" + prop.name() + 
"_cells"] += is_2 - is_1;
 
 1939           }, BasicCellTypes{});
 
 1941           const float this_energy_1 = cell_info_1.
energy[
cell];
 
 1942           const float this_energy_2 = cell_info_2.
energy[
cell];
 
 1947               if (energies_1.count(this_energy_1))
 
 1950                   ++same_abs_energy_1;
 
 1952               else if (energies_1.count(-this_energy_1))
 
 1954                   ++same_abs_energy_1;
 
 1956               energies_1.insert(this_energy_1);
 
 1958               if (energies_2.count(this_energy_2))
 
 1961                   ++same_abs_energy_2;
 
 1963               else if (energies_2.count(-this_energy_2))
 
 1965                   ++same_abs_energy_2;
 
 1967               energies_2.insert(this_energy_2);
 
 1972               const float this_snr_1 = this_energy_1 / protect_from_zero(constant_data.
m_cell_noise->get_noise(
cell, cell_info_1.
gain[
cell]));
 
 1974               if (snrs_1.count(this_snr_1))
 
 1979               else if (snrs_1.count(-this_snr_1))
 
 1983               snrs_1.insert(this_snr_1);
 
 1986               const float this_snr_2 = this_energy_2 / protect_from_zero(constant_data.
m_cell_noise->get_noise(
cell, cell_info_2.
gain[
cell]));
 
 1988               if (snrs_2.count(this_snr_2))
 
 1993               else if (snrs_2.count(-this_snr_2))
 
 1997               snrs_2.insert(this_snr_2);
 
 2005               int ref_c1 = -3, ref_c2 = -3, test_c1 = -3, test_c2 = -3;
 
 2018               const int match_1 = test_c1 < 0 ? -1 : sch.
t2r(test_c1);
 
 2019               const int match_2 = test_c2 < 0 ? -1 : sch.
t2r(test_c2);
 
 2024               const float ref_weight = 1.0f - ref_rev_weight;
 
 2025               const float test_weight = 1.0f - test_rev_weight;
 
 2027               bool cell_is_diff = 
false;
 
 2031                   ref_size_vec[ref_c1] += 1;
 
 2032                   ref_weighted_size_vec[ref_c1] += ref_weight;
 
 2033 #if CALORECGPU_DISABLE_STRICT_MATCHING 
 2034                   if (!(ref_c1 == match_1 || ref_c1 == match_2 || (match_1 < 0 || match_2 < 0)))
 
 2036                   if (!(ref_c1 == match_1 || ref_c1 == match_2))
 
 2039                       cell_is_diff = 
true;
 
 2040                       ref_diff_cells[ref_c1] += 1;
 
 2041                       ref_diff_cells_weight[ref_c1] += ref_weight;
 
 2047                   ref_size_vec[ref_c2] += 1;
 
 2048                   ref_weighted_size_vec[ref_c2] += ref_rev_weight;
 
 2049 #if CALORECGPU_DISABLE_STRICT_MATCHING 
 2050                   if (!(ref_c2 == match_1 || ref_c2 == match_2 || (match_1 < 0 || match_2 < 0)))
 
 2052                   if (!(ref_c2 == match_1 || ref_c2 == match_2))
 
 2055                       cell_is_diff = 
true;
 
 2056                       ref_diff_cells[ref_c2] += 1;
 
 2057                       ref_diff_cells_weight[ref_c2] += ref_rev_weight;
 
 2063                   test_size_vec[test_c1] += 1;
 
 2064                   test_weighted_size_vec[test_c1] += test_weight;
 
 2065 #if CALORECGPU_DISABLE_STRICT_MATCHING 
 2066                   if (match_1 >= 0 && !(match_1 == ref_c1 || match_1 == ref_c2 || (ref_c1 < 0 || ref_c2 < 0)))
 
 2068                   if (match_1 < 0 || !(match_1 == ref_c1 || match_1 == ref_c2))
 
 2071                       cell_is_diff = 
true;
 
 2072                       test_diff_cells[test_c1] += 1;
 
 2073                       test_diff_cells_weight[test_c1] += test_weight;
 
 2079                   test_size_vec[test_c2] += 1;
 
 2080                   test_weighted_size_vec[test_c2] += test_rev_weight;
 
 2081 #if CALORECGPU_DISABLE_STRICT_MATCHING 
 2082                   if (match_2 >= 0 && !(match_2 == ref_c1 || match_2 == ref_c2 || (ref_c1 < 0 || ref_c2 < 0)))
 
 2084                   if (match_2 < 0 || !(match_2 == ref_c1 || match_2 == ref_c2))
 
 2087                       cell_is_diff = 
true;
 
 2088                       test_diff_cells[test_c2] += 1;
 
 2089                       test_diff_cells_weight[test_c2] += test_rev_weight;
 
 2093               if (!cell_is_diff && (ref_c1 >= 0 || ref_c2 >= 0 || test_c1 >= 0 || test_c2 >= 0))
 
 2095                   ++same_cluster_cells_count;
 
 2097               else if (cell_is_diff)
 
 2099                   char message_buffer[256];
 
 2100                   snprintf(message_buffer, 256,
 
 2101                            "%7d | %18f || %6d | %6d | %6d | %6d || %6d | %6d || %016llX | %016llX",
 
 2103                            ref_c1, ref_c2, test_c1, test_c2,
 
 2107                   ++diff_cluster_cells_count;
 
 2117       for (
int cluster = 0; cluster < clusters_1.
number; ++cluster)
 
 2119           const int match = sch.
r2t(cluster);
 
 2126           apply_to_multi_class([&](
const auto & prop, 
const size_t i)
 
 2130                 const auto prop_1 = prop.get_property(constant_data, cell_info_1, cell_state_1, clusters_1, moments_1, cluster);
 
 2131                 const auto prop_2 = prop.get_property(constant_data, cell_info_2, cell_state_2, clusters_2, moments_2, 
match);
 
 2133                 cluster_properties[prop.name() + 
"_ref"].push_back(prop_1);
 
 2134                 cluster_properties[prop.name() + 
"_test"].push_back(prop_2);
 
 2136                 cluster_properties[
"delta_" + prop.name()].push_back(prop_2 - prop_1);
 
 2137                 cluster_properties[
"delta_" + prop.name() + 
"_rel_ref"].push_back((prop_2 - prop_1) / protect_from_zero(std::abs(prop_1)));
 
 2138                 cluster_properties[
"delta_" + prop.name() + 
"_rel_test"].push_back((prop_2 - prop_1) / protect_from_zero(std::abs(prop_2)));
 
 2140           }, BasicClusterProperties{});
 
 2142           apply_to_multi_class([&](
const auto & prop, 
const size_t i)
 
 2146                 cluster_properties[prop.name()].push_back(prop.get_property(constant_data, cell_info_1, cell_state_1, clusters_1, moments_1, cluster,
 
 2147                                                                             cell_info_2, cell_state_2, clusters_2, moments_2, 
match));
 
 2149           }, ComparedClusterProperties{});
 
 2153               cluster_properties[
"size_ref"].push_back(ref_size_vec[cluster]);
 
 2154               cluster_properties[
"size_test"].push_back(test_size_vec[
match]);
 
 2155               cluster_properties[
"delta_size"].push_back(ref_size_vec[cluster] - test_size_vec[
match]);
 
 2156               cluster_properties[
"delta_size_rel_ref"].push_back((ref_size_vec[cluster] - test_size_vec[
match]) / protect_from_zero(ref_size_vec[cluster]));
 
 2157               cluster_properties[
"delta_size_rel_test"].push_back((ref_size_vec[cluster] - test_size_vec[
match]) / protect_from_zero(test_size_vec[
match]));
 
 2159               cluster_properties[
"weighted_size_ref"].push_back(ref_weighted_size_vec[cluster]);
 
 2160               cluster_properties[
"weighted_size_test"].push_back(test_weighted_size_vec[
match]);
 
 2161               cluster_properties[
"delta_weighted_size"].push_back(ref_weighted_size_vec[cluster] - test_weighted_size_vec[
match]);
 
 2162               cluster_properties[
"delta_weighted_size_rel_ref"].push_back((ref_weighted_size_vec[cluster] - test_weighted_size_vec[
match]) / protect_from_zero(ref_weighted_size_vec[cluster]));
 
 2163               cluster_properties[
"delta_weighted_size_rel_test"].push_back((ref_weighted_size_vec[cluster] - test_weighted_size_vec[
match]) / protect_from_zero(test_weighted_size_vec[
match]));
 
 2168               cluster_properties[
"diff_cells_ref"].push_back(ref_diff_cells[cluster]);
 
 2169               cluster_properties[
"diff_cells_ref_rel_size"].push_back(ref_diff_cells[cluster] / protect_from_zero(ref_size_vec[cluster]));
 
 2170               cluster_properties[
"diff_cells_test"].push_back(test_diff_cells[
match]);
 
 2171               cluster_properties[
"diff_cells_test_rel_size"].push_back(test_diff_cells[
match] / protect_from_zero(test_size_vec[
match]));
 
 2172               cluster_properties[
"diff_cells"].push_back(ref_diff_cells[cluster] + test_diff_cells[
match]);
 
 2174               cluster_properties[
"weighted_diff_cells_ref"].push_back(ref_diff_cells_weight[cluster]);
 
 2175               cluster_properties[
"weighted_diff_cells_ref_rel_size"].push_back(ref_diff_cells_weight[cluster] / protect_from_zero(ref_weighted_size_vec[cluster]));
 
 2176               cluster_properties[
"weighted_diff_cells_test"].push_back(test_diff_cells_weight[
match]);
 
 2177               cluster_properties[
"weighted_diff_cells_test_rel_size"].push_back(test_diff_cells_weight[
match] / protect_from_zero(test_weighted_size_vec[
match]));
 
 2178               cluster_properties[
"weighted_diff_cells"].push_back(ref_diff_cells_weight[cluster] + test_diff_cells_weight[
match]);
 
 2184   using scalar_type = decltype(
Monitored::Scalar(
"", std::declval<long long int>()));
 
 2186   std::vector<coll_type> collections;
 
 2187   std::vector<scalar_type> count_scalars;
 
 2188   std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> cluster_group, cell_group, counts_group;
 
 2190   collections.reserve(cluster_properties.size() + cell_properties.size());
 
 2191   count_scalars.reserve(cell_counts.size() + 6 * 3);
 
 2192   cluster_group.reserve(cluster_properties.size());
 
 2193   cell_group.reserve(cell_properties.size());
 
 2194   counts_group.reserve(cell_counts.size() + 3 + 6 * 3);
 
 2196   auto add_count_vars = [&](
const std::string & 
name, 
const long long int ref_num, 
const long long int test_num)
 
 2199     counts_group.push_back(
std::ref(count_scalars.back()));
 
 2202     counts_group.push_back(
std::ref(count_scalars.back()));  
 
 2205     counts_group.push_back(
std::ref(count_scalars.back()));  
 
 2208   add_count_vars(
"num_clusters", clusters_1.
number, clusters_2.
number);
 
 2211   add_count_vars(
"num_same_E_cells", same_energy_1, same_energy_2);
 
 2212   add_count_vars(
"num_same_abs_E_cells", same_abs_energy_1, same_abs_energy_2);
 
 2213   add_count_vars(
"num_same_SNR_cells", same_snr_1, same_snr_2);
 
 2214   add_count_vars(
"num_same_abs_SNR_cells", same_abs_snr_1, same_abs_snr_2);
 
 2220   counts_group.push_back(
std::ref(mon_total_unmatched));
 
 2221   counts_group.push_back(
std::ref(mon_same_cluster_cell));
 
 2222   counts_group.push_back(
std::ref(mon_diff_cluster_cell));
 
 2224   for (
const auto & k_v : cluster_properties)
 
 2227       cluster_group.push_back(
std::ref(collections.back()));
 
 2230   for (
const auto & k_v : cell_properties)
 
 2233       cell_group.push_back(
std::ref(collections.back()));
 
 2236   for (
const auto & k_v : cell_counts)
 
 2239       counts_group.push_back(
std::ref(count_scalars.back()));
 
 2249   return StatusCode::SUCCESS;