File indexing completed on 2025-08-06 08:17:21
0001
0002
0003
0004
0005
0006
0007
0008 #include "MicromegasBcoMatchingInformation_v1.h"
0009
0010 #include <Event/packet.h>
0011
0012 #include <algorithm>
0013 #include <vector>
0014
0015 namespace
0016 {
0017
0018
0019 template <class T>
0020 std::ostream& operator<<(std::ostream& o, const std::list<T>& list)
0021 {
0022 if (list.empty())
0023 {
0024 o << "{}";
0025 }
0026 else
0027 {
0028 const bool is_hex = (o.flags() & std::ios_base::hex);
0029 o << "{ ";
0030 bool first = true;
0031 for (const auto& value : list)
0032 {
0033 if (!first)
0034 {
0035 o << ", ";
0036 }
0037 if (is_hex)
0038 {
0039 o << "0x";
0040 }
0041 o << value;
0042 first = false;
0043 }
0044 o << " }";
0045 }
0046 return o;
0047 }
0048
0049 template <class T>
0050 std::ostream& operator<<(std::ostream& o, const std::vector<T>& list)
0051 {
0052 if (list.empty())
0053 {
0054 o << "{}";
0055 }
0056 else
0057 {
0058 const bool is_hex = (o.flags() & std::ios_base::hex);
0059 o << "{ ";
0060 bool first = true;
0061 for (const auto& value : list)
0062 {
0063 if (!first)
0064 {
0065 o << ", ";
0066 }
0067 if (is_hex)
0068 {
0069 o << "0x";
0070 }
0071 o << value;
0072 first = false;
0073 }
0074 o << " }";
0075 }
0076 return o;
0077 }
0078
0079
0080 template <class T>
0081 inline static constexpr T get_bco_diff(const T& first, const T& second)
0082 {
0083 return first < second ? (second - first) : (first - second);
0084 }
0085
0086
0087 static constexpr unsigned int m_max_multiplier_adjustment_count = 1000;
0088
0089
0090 static constexpr unsigned int m_max_fee_bco_diff = 10;
0091
0092
0093 static constexpr unsigned int m_max_gtm_bco_diff = 100;
0094
0095
0096 static constexpr unsigned int m_max_matching_data_size = 50;
0097
0098
0099 static constexpr int m_nchannels_fee = 256;
0100
0101
0102 enum SampaDataType
0103 {
0104 HEARTBEAT_T = 0b000,
0105 TRUNCATED_DATA_T = 0b001,
0106 TRUNCATED_TRIG_EARLY_DATA_T = 0b011,
0107 NORMAL_DATA_T = 0b100,
0108 LARGE_DATA_T = 0b101,
0109 TRIG_EARLY_DATA_T = 0b110,
0110 TRIG_EARLY_LARGE_DATA_T = 0b111,
0111 };
0112
0113
0114 enum ModeBitType
0115 {
0116 BX_COUNTER_SYNC_T = 0,
0117 ELINK_HEARTBEAT_T = 1,
0118 SAMPA_EVENT_TRIGGER_T = 2,
0119 CLEAR_LV1_LAST_T = 6,
0120 CLEAR_LV1_ENDAT_T = 7
0121 };
0122 }
0123
0124
0125
0126 double MicromegasBcoMatchingInformation_v1::m_multiplier = 4.262916255;
0127
0128
0129 std::optional<uint32_t> MicromegasBcoMatchingInformation_v1::get_predicted_fee_bco(uint64_t gtm_bco) const
0130 {
0131
0132 if (!is_verified())
0133 {
0134 return std::nullopt;
0135 }
0136
0137
0138 const uint64_t gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first);
0139
0140
0141 const uint64_t fee_bco_predicted = m_fee_bco_first + get_adjusted_multiplier() * gtm_bco_difference;
0142 return uint32_t(fee_bco_predicted & 0xFFFFFU);
0143 }
0144
0145
0146 void MicromegasBcoMatchingInformation_v1::print_gtm_bco_information() const
0147 {
0148 if (!m_gtm_bco_list.empty())
0149 {
0150 std::cout
0151 << "MicromegasBcoMatchingInformation_v1::print_gtm_bco_information -"
0152 << " gtm_bco: " << std::hex << m_gtm_bco_list << std::dec
0153 << std::endl;
0154
0155
0156 if (is_verified())
0157 {
0158 std::list<uint32_t> fee_bco_predicted_list;
0159 std::transform(
0160 m_gtm_bco_list.begin(),
0161 m_gtm_bco_list.end(),
0162 std::back_inserter(fee_bco_predicted_list),
0163 [this](const uint64_t& gtm_bco)
0164 { return get_predicted_fee_bco(gtm_bco).value(); });
0165
0166 std::cout
0167 << "MicromegasBcoMatchingInformation_v1::print_gtm_bco_information -"
0168 << " fee_bco_predicted: " << std::hex << fee_bco_predicted_list << std::dec
0169 << std::endl;
0170 }
0171 }
0172 }
0173
0174
0175 void MicromegasBcoMatchingInformation_v1::save_gtm_bco_information(Packet* packet)
0176 {
0177
0178 const int n_tagger = packet->lValue(0, "N_TAGGER");
0179 for (int t = 0; t < n_tagger; ++t)
0180 {
0181
0182 const bool is_lvl1 = static_cast<uint8_t>(packet->lValue(t, "IS_LEVEL1_TRIGGER"));
0183 if (is_lvl1)
0184 {
0185 const uint64_t gtm_bco = static_cast<uint64_t>(packet->lValue(t, "BCO"));
0186 m_gtm_bco_list.push_back(gtm_bco);
0187 continue;
0188 }
0189
0190
0191 const bool is_endat = static_cast<uint8_t>(packet->lValue(t, "IS_ENDAT"));
0192 if( is_endat )
0193 {
0194 const uint64_t gtm_bco = static_cast<uint64_t>(packet->lValue(t, "BCO"));
0195
0196
0197 if( m_gtm_bco_list.empty() || (gtm_bco-m_gtm_bco_list.back()) > 10 )
0198 { m_gtm_bco_list.push_back(gtm_bco); }
0199
0200 continue;
0201 }
0202
0203
0204 const bool is_modebit = static_cast<uint8_t>(packet->lValue(t, "IS_MODEBIT"));
0205 if (is_modebit)
0206 {
0207
0208 uint64_t modebits = static_cast<uint8_t>(packet->lValue(t, "MODEBITS"));
0209 if (modebits & (1U << ELINK_HEARTBEAT_T))
0210 {
0211 const uint64_t gtm_bco = static_cast<uint64_t>(packet->lValue(t, "BCO"));
0212 m_gtm_bco_list.push_back(gtm_bco);
0213 continue;
0214 }
0215 }
0216 }
0217 }
0218
0219
0220 bool MicromegasBcoMatchingInformation_v1::find_reference_from_modebits(Packet* packet)
0221 {
0222
0223 const int n_tagger = packet->lValue(0, "N_TAGGER");
0224 for (int t = 0; t < n_tagger; ++t)
0225 {
0226 const bool is_modebit = static_cast<uint8_t>(packet->lValue(t, "IS_MODEBIT"));
0227 if (is_modebit)
0228 {
0229
0230 uint64_t modebits = static_cast<uint8_t>(packet->lValue(t, "MODEBITS"));
0231 if (modebits & (1U << BX_COUNTER_SYNC_T))
0232 {
0233 std::cout << "MicromegasBcoMatchingInformation_v1::find_reference_from_modebits"
0234 << " - packet: " << packet->getIdentifier()
0235 << " found reference from modebits"
0236 << std::endl;
0237
0238
0239 const uint64_t gtm_bco = static_cast<uint64_t>(packet->lValue(t, "BCO"));
0240 m_gtm_bco_first = gtm_bco;
0241 m_fee_bco_first = 0;
0242 m_verified_from_modebits = true;
0243 return true;
0244 }
0245 }
0246 }
0247
0248 return false;
0249 }
0250
0251
0252 bool MicromegasBcoMatchingInformation_v1::find_reference_from_data(Packet* packet)
0253 {
0254
0255 std::vector<uint64_t> gtm_bco_list;
0256 std::vector<uint64_t> gtm_bco_diff_list;
0257 for (const auto& gtm_bco : m_gtm_bco_list)
0258 {
0259 if (!gtm_bco_list.empty())
0260 {
0261
0262
0263 const uint64_t gtm_bco_difference = (gtm_bco >= gtm_bco_list.back()) ? (gtm_bco - gtm_bco_list.back()) : (gtm_bco + (1ULL << 40U) - gtm_bco_list.back());
0264
0265 gtm_bco_diff_list.push_back(get_adjusted_multiplier() * gtm_bco_difference);
0266 }
0267
0268
0269 gtm_bco_list.push_back(gtm_bco);
0270 }
0271
0272
0273 if (verbosity())
0274 {
0275 std::cout << "MicromegasBcoMatchingInformation_v1::find_reference_from_data - gtm_bco_diff_list: " << gtm_bco_diff_list << std::endl;
0276 }
0277
0278 uint32_t fee_bco_prev = 0;
0279 bool has_fee_bco_prev = false;
0280
0281
0282 const int n_waveform = packet->iValue(0, "NR_WF");
0283 for (int iwf = 0; iwf < n_waveform; ++iwf)
0284 {
0285
0286 const unsigned short type = packet->iValue(iwf, "TYPE");
0287
0288
0289 if (type == HEARTBEAT_T)
0290 {
0291 continue;
0292 }
0293
0294
0295 const unsigned short channel = packet->iValue(iwf, "CHANNEL");
0296
0297
0298 if (channel >= m_nchannels_fee)
0299 {
0300 continue;
0301 }
0302
0303 const uint32_t fee_bco = static_cast<uint32_t>(packet->iValue(iwf, "BCO"));
0304 if (!has_fee_bco_prev)
0305 {
0306 fee_bco_prev = fee_bco;
0307 has_fee_bco_prev = true;
0308 }
0309
0310
0311 const uint64_t fee_bco_diff = get_bco_diff(fee_bco, fee_bco_prev);
0312
0313
0314 if (fee_bco_diff < m_max_fee_bco_diff)
0315 {
0316 continue;
0317 }
0318
0319 std::cout << "MicromegasBcoMatchingInformation_v1::find_reference_from_data - fee_bco_diff: " << fee_bco_diff << std::endl;
0320
0321
0322 for (size_t i = 0; i < gtm_bco_diff_list.size(); ++i)
0323 {
0324 uint64_t sum = 0;
0325 for (size_t j = i; j < gtm_bco_diff_list.size(); ++j)
0326 {
0327 sum += gtm_bco_diff_list[j];
0328 if (get_bco_diff(sum, fee_bco_diff) < m_max_fee_bco_diff)
0329 {
0330 m_verified_from_data = true;
0331 m_gtm_bco_first = gtm_bco_list[i];
0332 m_fee_bco_first = fee_bco_prev;
0333
0334 if (verbosity())
0335 {
0336 std::cout << "MicromegasBcoMatchingInformation_v1::find_reference_from_data - matching is verified" << std::endl;
0337 std::cout
0338 << "MicromegasBcoMatchingInformation_v1::find_reference_from_data -"
0339 << " m_gtm_bco_first: " << std::hex << m_gtm_bco_first << std::dec
0340 << std::endl;
0341 std::cout
0342 << "MicromegasBcoMatchingInformation_v1::find_reference_from_data -"
0343 << " m_fee_bco_first: " << std::hex << m_fee_bco_first << std::dec
0344 << std::endl;
0345 }
0346 return true;
0347 }
0348 }
0349 }
0350
0351
0352 fee_bco_prev = fee_bco;
0353 }
0354 return false;
0355 }
0356
0357
0358 std::optional<uint64_t> MicromegasBcoMatchingInformation_v1::find_gtm_bco(uint32_t fee_bco)
0359 {
0360
0361 if (!is_verified())
0362 {
0363 return std::nullopt;
0364 }
0365
0366 const auto bco_matching_iter = std::find_if(
0367 m_bco_matching_list.begin(),
0368 m_bco_matching_list.end(),
0369 [fee_bco](const m_bco_matching_pair_t& pair)
0370 { return get_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; });
0371
0372 if (bco_matching_iter != m_bco_matching_list.end())
0373 {
0374 return bco_matching_iter->second;
0375 }
0376 else
0377 {
0378
0379 const auto iter = std::find_if(
0380 m_gtm_bco_list.begin(),
0381 m_gtm_bco_list.end(),
0382 [this, fee_bco](const uint64_t& gtm_bco)
0383 { return get_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; });
0384
0385
0386 if (iter != m_gtm_bco_list.end())
0387 {
0388 const auto gtm_bco = *iter;
0389 if (verbosity())
0390 {
0391 const auto fee_bco_predicted = get_predicted_fee_bco(gtm_bco).value();
0392 const auto fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco);
0393
0394 std::cout << "MicromegasBcoMatchingInformation_v1::find_gtm_bco -"
0395 << std::hex
0396 << " fee_bco: 0x" << fee_bco
0397 << " predicted: 0x" << fee_bco_predicted
0398 << " gtm_bco: 0x" << gtm_bco
0399 << std::dec
0400 << " difference: " << fee_bco_diff
0401 << std::endl;
0402 }
0403
0404
0405 m_bco_matching_list.emplace_back(fee_bco, gtm_bco);
0406
0407
0408 m_gtm_bco_list.erase(iter);
0409
0410
0411 update_multiplier_adjustment(gtm_bco, fee_bco);
0412
0413 return gtm_bco;
0414 }
0415 else
0416 {
0417 if (m_orphans.insert(fee_bco).second)
0418 {
0419 if (verbosity())
0420 {
0421
0422 const auto iter2 = std::min_element(
0423 m_gtm_bco_list.begin(),
0424 m_gtm_bco_list.end(),
0425 [this, fee_bco](const uint64_t& first, const uint64_t& second)
0426 { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); });
0427
0428 const int fee_bco_diff = (iter2 != m_gtm_bco_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1;
0429
0430 std::cout << "MicromegasBcoMatchingInformation_v1::find_gtm_bco -"
0431 << std::hex
0432 << " fee_bco: 0x" << fee_bco
0433 << std::dec
0434 << " gtm_bco: none"
0435 << " difference: " << fee_bco_diff
0436 << std::endl;
0437 }
0438 }
0439 return std::nullopt;
0440 }
0441 }
0442
0443
0444 return std::nullopt;
0445 }
0446
0447
0448 void MicromegasBcoMatchingInformation_v1::cleanup()
0449 {
0450
0451 while (m_gtm_bco_list.size() > m_max_matching_data_size)
0452 {
0453 m_gtm_bco_list.pop_front();
0454 }
0455 while (m_bco_matching_list.size() > m_max_matching_data_size)
0456 {
0457 m_bco_matching_list.pop_front();
0458 }
0459
0460
0461 m_orphans.clear();
0462 }
0463
0464
0465 void MicromegasBcoMatchingInformation_v1::cleanup(uint64_t ref_bco)
0466 {
0467
0468 m_gtm_bco_list.erase( std::remove_if( m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [ref_bco](const uint64_t& bco) { return bco<=ref_bco; }), m_gtm_bco_list.end() );
0469
0470
0471 m_bco_matching_list.erase( std::remove_if( m_bco_matching_list.begin(), m_bco_matching_list.end(), [ref_bco](const m_bco_matching_pair_t& pair) { return pair.second<=ref_bco; }), m_bco_matching_list.end() );
0472
0473
0474 m_orphans.clear();
0475 }
0476
0477
0478 double MicromegasBcoMatchingInformation_v1::get_adjusted_multiplier() const
0479 {
0480 return m_multiplier + m_multiplier_adjustment;
0481 }
0482
0483
0484 void MicromegasBcoMatchingInformation_v1::update_multiplier_adjustment(uint64_t gtm_bco, uint32_t fee_bco)
0485 {
0486
0487 if (!is_verified())
0488 {
0489 return;
0490 }
0491
0492
0493 if (gtm_bco == m_gtm_bco_first)
0494 {
0495 return;
0496 }
0497
0498 const uint32_t fee_bco_predicted = get_predicted_fee_bco(gtm_bco).value();
0499 const double delta_fee_bco = double(fee_bco) - double(fee_bco_predicted);
0500 const double gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first);
0501
0502 m_multiplier_adjustment_numerator += gtm_bco_difference * delta_fee_bco;
0503 m_multiplier_adjustment_denominator += gtm_bco_difference * gtm_bco_difference;
0504 ++m_multiplier_adjustment_count;
0505
0506 if (verbosity())
0507 {
0508 const auto default_precision{std::cout.precision()};
0509 std::cout << "MicromegasBcoMatchingInformation_v1::update_multiplier_adjustment -"
0510 << " m_multiplier_adjustment_count: " << m_multiplier_adjustment_count
0511 << std::setprecision(10)
0512 << " m_multiplier: " << get_adjusted_multiplier()
0513 << " adjustment: " << m_multiplier_adjustment_numerator / m_multiplier_adjustment_denominator
0514 << " m_multiplier_adjusted: " << get_adjusted_multiplier() + m_multiplier_adjustment_numerator / m_multiplier_adjustment_denominator
0515 << std::setprecision(default_precision)
0516 << std::endl;
0517 }
0518
0519
0520 if (m_multiplier_adjustment_count > m_max_multiplier_adjustment_count)
0521 {
0522 m_multiplier_adjustment += m_multiplier_adjustment_numerator / m_multiplier_adjustment_denominator;
0523 m_multiplier_adjustment_numerator = 0;
0524 m_multiplier_adjustment_denominator = 0;
0525 m_multiplier_adjustment_count = 0;
0526 }
0527 }