From 12c448a98e51ea52ccafaa5e7840b307b1194fcd Mon Sep 17 00:00:00 2001 From: Will Hasecke Date: Thu, 25 Jun 2026 11:53:39 -0400 Subject: [PATCH 01/14] Updated toa_vref_scan for multiple rocs --- app/tool/algorithm/get_toa_efficiencies.cxx | 42 ++++++- app/tool/algorithm/get_toa_efficiencies.h | 2 + app/tool/algorithm/toa_vref_scan.cxx | 132 ++++++++++++++------ app/tool/algorithm/toa_vref_scan.h | 3 +- app/tool/algorithm/trim_toa_scan.cxx | 6 +- app/tool/algorithm/trim_toa_scan.h | 2 +- app/tool/tasks/toa_vref_scan.cxx | 26 ++-- app/tool/tasks/trim_toa_scan.cxx | 2 +- 8 files changed, 161 insertions(+), 54 deletions(-) diff --git a/app/tool/algorithm/get_toa_efficiencies.cxx b/app/tool/algorithm/get_toa_efficiencies.cxx index d472a52b7..bb231af91 100644 --- a/app/tool/algorithm/get_toa_efficiencies.cxx +++ b/app/tool/algorithm/get_toa_efficiencies.cxx @@ -1,25 +1,61 @@ #include "get_toa_efficiencies.h" #include "pflib/utility/efficiency.h" +#include "pflib/logging/Logging.h" namespace pflib::algorithm { std::array get_toa_efficiencies( + int i_roc, + const pflib::packing::SingleECONDRocErxMapping& mapping, const std::vector& data) { + + static auto the_log_{::pflib::logging::get("get_toa_efficiencies")}; + std::array efficiencies; + /// reserve a vector of the appropriate size to avoid repeating allocation /// time for all 72 channels + + if (data.empty()) { + pflib_log(warn) << "[DEBUG TOA] data packet vector is EMPTY for ROC " << i_roc; + efficiencies.fill(0.0); + return efficiencies; + } + std::vector toas(data.size()); for (int ch{0}; ch < 72; ch++) { // TODO: 348 - int i_link = (ch / 36); - int i_ch = ch % 36; + + auto [i_erx, i_ch] = mapping.toErxChannel(i_roc, ch); + + if (i_erx < 0 || i_ch < 0) { + pflib_log(error) << "[DEBUG MAP] Sanity Failure: Negative mapping values detected " + << "ROC " << i_roc << " Ch " << ch + << " resolved to eRx = " << (int)i_erx << ", eCh = " << (int) i_ch; + } + for (std::size_t i{0}; i < toas.size(); i++) { - toas[i] = data[i].samples[data[i].i_soi].channel(i_link, i_ch).toa(); + toas[i] = data[i].soi().channel(i_erx, i_ch).toa(); } + /// we assume that the data provided is not empty otherwise the efficiency /// calculation is meaningless + + if (ch == 0 || ch == 36) { + pflib_log(trace) << "[DEBUG TOA] ROC " << i_roc << " Ch " << ch + << " (eRx: " << (int)i_erx << ", eCh: " << (int)i_ch << ")" + << " first 3 raw TOAs: [" << toas[0] << ", " + << (toas.size() > 1 ? std::to_string(toas[1]) : "N/A") << ", " + << (toas.size() > 2 ? std::to_string(toas[2]) : "N/A") << "]"; + } + efficiencies[ch] = pflib::utility::efficiency(toas); + + if (efficiencies[ch] > 0.0) { + pflib_log(debug) << "[DEBUG TOA] Found non-zero efficiency on ROC " << i_roc + << " Ch " << ch << " = " << efficiencies[ch]; + } } return efficiencies; } diff --git a/app/tool/algorithm/get_toa_efficiencies.h b/app/tool/algorithm/get_toa_efficiencies.h index 1b7b21a0a..4fdd2401a 100644 --- a/app/tool/algorithm/get_toa_efficiencies.h +++ b/app/tool/algorithm/get_toa_efficiencies.h @@ -15,6 +15,8 @@ namespace pflib::algorithm { // templated to match any event packet type std::array get_toa_efficiencies( + int i_roc, + const pflib::packing::SingleECONDRocErxMapping& mapping, const std::vector& data); } // namespace pflib::algorithm diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index 5fff9c53c..da426e1d4 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -8,8 +8,8 @@ namespace pflib::algorithm { -std::map> toa_vref_scan( - Target* tgt, ROC roc) { +std::map>> toa_vref_scan( + Target* tgt) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; /// do a run of 100 samples per toa_vref to measure the TOA @@ -19,59 +19,119 @@ std::map> toa_vref_scan( tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); - std::array target; - std::array, 2> final_effs; + std::map> target; // i_roc int for each variable + std::map, 2>> final_effs; + std::map>> settings; + // TODO 348 - DecodeAndBuffer buffer{n_events, 2}; + DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; // loop over runs, from toa_vref = 0 to = 255 for (int toa_vref{0}; toa_vref < 256; toa_vref++) { pflib_log(info) << "testing toa_vref = " << toa_vref; - auto test_handle = roc.testParameters() - .add("REFERENCEVOLTAGE_0", "TOA_VREF", toa_vref) - .add("REFERENCEVOLTAGE_1", "TOA_VREF", toa_vref) - .apply(); + std::map> parameters; + parameters["REFERENCEVOLTAGE_0"]["TOA_VREF"] = toa_vref; + parameters["REFERENCEVOLTAGE_1"]["TOA_VREF"] = toa_vref; + auto test_params = tgt->tempApplyAllROCs(parameters); + + usleep(10); + daq_run(tgt, "PEDESTAL", buffer, n_events, 100); + pflib_log(trace) << "finished toa_vref = " << toa_vref << ", getting efficiencies"; - auto efficiencies = get_toa_efficiencies(buffer.get_buffer()); - pflib_log(trace) - << "got channel efficiencies, getting max efficiency per link"; - for (int i_link{0}; i_link < 2; i_link++) { - auto start = efficiencies.begin() + - 36 * i_link; // start at 0 for link 0, 36 for link 1 - auto end = start + 36; - final_effs[i_link][toa_vref] = *std::max_element(start, end); + + for (int i_roc : tgt->roc_ids()) { + // Debug callout for mapping + const auto& mapping = tgt->getRocErxMapping(); + + try { + auto [first_erx, first_ch] = mapping.toErxChannel(i_roc, 0); + auto [last_erx, last_ch] = mapping.toErxChannel(i_roc, 71); + + if (toa_vref == 0) { + pflib_log(info) << "[DEBUG MAP] Mapping Check for ROC " << i_roc << ":" + << " Ch 0 -> eRx " << (int)first_erx << ", eCh " << (int)first_ch + << " | Ch 71 -> eRx " << (int)last_erx << ", eCh " << (int)last_ch; + } + } + + catch (const std::exception& e) { + pflib_log(error) << "[DEBUG MAP] Critical: Mapping lookup threw an exception for ROC " + << i_roc << ". Message: " << e.what(); + } + // + + auto efficiencies = get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); + pflib_log(trace) << "got channel efficiencies for ROC " << i_roc + << ", getting max efficiency per link"; + for (int i_link{0}; i_link < 2; i_link++){ + auto start = efficiencies.begin() + 36 * i_link; + auto end = start + 36; + + double max_eff = *std::max_element(start, end); + + final_effs[i_roc][i_link][toa_vref] = max_eff; + + if (toa_vref % 32 == 0 || max_eff > 0.0) { + pflib_log(trace) << "[DEBUG SCAN] VREF " << toa_vref + << " | ROC " << i_roc << " Link " << i_link + << " | Max Efficiency: " << max_eff; + } + } + pflib_log(trace) << "got link efficiencies"; } - pflib_log(trace) << "got link efficiencies"; } - pflib_log(info) << "sample collections done, deducing settings"; // get the max toa_vref with non-zero efficiency? Iterate through the array // from bottom up. - for (int i_link{0}; i_link < 2; i_link++) { - int highest_non_zero_eff = -1; // just a placeholder in case it's not found - for (int toa_vref = final_effs[0].size() - 1; toa_vref >= 0; toa_vref--) { - if (final_effs[i_link][toa_vref] > 0.0) { - highest_non_zero_eff = - toa_vref + 10; // need to add 10 since we don't want to overlap - // with highest pedestals! - break; // should break from link 0 into link 1 + for (int i_roc : tgt->roc_ids()) { + for (int i_link{0}; i_link < 2; i_link++) { + int highest_non_zero_eff = -1; // just a placeholder in case it's not found + for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; toa_vref--) { + if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { + pflib_log(trace) << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc + << " Link " << i_link << ". Initial val at max VREF: " + << final_effs[i_roc][i_link][toa_vref]; + } + + if (final_effs[i_roc][i_link][toa_vref] > 0.0) { + highest_non_zero_eff = + toa_vref + 10; // need to add 10 since we don't want to overlap + // with highest pedestals! + pflib_log(info) << "[DEBUG SEARCH] Success. Found threshold edge at VREF " << toa_vref + << " (Setting target to " << highest_non_zero_eff << ")"; + break; // should break from link 0 into link 1 + } + } + + if (highest_non_zero_eff < 0) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": no non-zero TOA efficiency found, skipping"; + continue; + } + + if (highest_non_zero_eff > 255) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": deduced TOA_VREF " << highest_non_zero_eff + << " out of range, clamping to 255"; + highest_non_zero_eff = 255; } + + target[i_roc][i_link] = highest_non_zero_eff; // store value + } - target[i_link] = highest_non_zero_eff; // store value - } - // toa_vref is a global parameter (1 value per link) + // toa_vref is a global parameter (1 value per link) - std::map> settings; - for (int i_link{0}; i_link < 2; i_link++) { - std::string page{ - pflib::utility::string_format("REFERENCEVOLTAGE_%d", i_link)}; - settings[page]["TOA_VREF"] = target[i_link]; + for (int i_link{0}; i_link < 2; i_link++) { + std::string page{ + pflib::utility::string_format("REFERENCEVOLTAGE_%d", i_link)}; + settings[i_roc][page]["TOA_VREF"] = target[i_roc][i_link]; + } } - return settings; } + } // namespace pflib::algorithm diff --git a/app/tool/algorithm/toa_vref_scan.h b/app/tool/algorithm/toa_vref_scan.h index 633af3a56..90ca0412a 100644 --- a/app/tool/algorithm/toa_vref_scan.h +++ b/app/tool/algorithm/toa_vref_scan.h @@ -15,7 +15,6 @@ namespace pflib::algorithm { * * @note Only functional for single-ROC targets */ -std::map> toa_vref_scan( - Target* tgt, ROC roc); +std::map>> toa_vref_scan(Target* tgt); } // namespace pflib::algorithm diff --git a/app/tool/algorithm/trim_toa_scan.cxx b/app/tool/algorithm/trim_toa_scan.cxx index 84cc4fa01..efc44bc59 100644 --- a/app/tool/algorithm/trim_toa_scan.cxx +++ b/app/tool/algorithm/trim_toa_scan.cxx @@ -65,7 +65,7 @@ std::tuple siegel_regression( namespace pflib::algorithm { std::map> trim_toa_scan( - Target* tgt, ROC roc) { + Target* tgt, ROC roc, int i_roc) { // added int i_roc index for efficiencies static auto the_log_{::pflib::logging::get("trim_toa_scan")}; /** @@ -95,6 +95,8 @@ std::map> trim_toa_scan( // loop over trim_toa, from trim_toa = 0 to 32 by skipping 4 // loop over calib, from calib = 0 to 800 by skipping over 4 + auto mapping = tgt->getRocErxMapping(); + for (int trim_toa{0}; trim_toa < 32; trim_toa += 4) { pflib_log(info) << "testing trim_toa = " << trim_toa; auto trim_toa_test_builder = roc.testParameters(); @@ -117,7 +119,7 @@ std::map> trim_toa_scan( pflib_log(trace) << "finished trim_toa = " << trim_toa << ", and calib = " << calib << ", getting efficiencies"; - auto efficiencies = get_toa_efficiencies(buffer.get_buffer()); + auto efficiencies = get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); // added i_roc index for efficiencies pflib_log(trace) << "got channel efficiencies, storing now"; for (int ch{0}; ch < 72; ch++) { // need to divide by 4 because index is value/4 from final_data diff --git a/app/tool/algorithm/trim_toa_scan.h b/app/tool/algorithm/trim_toa_scan.h index b5cc75700..7ab2f68f3 100644 --- a/app/tool/algorithm/trim_toa_scan.h +++ b/app/tool/algorithm/trim_toa_scan.h @@ -16,6 +16,6 @@ namespace pflib::algorithm { * @note Only functional for single-ROC targets */ std::map> trim_toa_scan( - Target* tgt, ROC roc); + Target* tgt, ROC roc, int i_roc); } // namespace pflib::algorithm diff --git a/app/tool/tasks/toa_vref_scan.cxx b/app/tool/tasks/toa_vref_scan.cxx index 86667b0bc..f8b7b6e45 100644 --- a/app/tool/tasks/toa_vref_scan.cxx +++ b/app/tool/tasks/toa_vref_scan.cxx @@ -7,15 +7,21 @@ #include "../algorithm/toa_vref_scan.h" void toa_vref_scan(Target* tgt) { - auto roc{tgt->roc(pftool::state.iroc)}; - auto settings = pflib::algorithm::toa_vref_scan(tgt, roc); + auto settings = pflib::algorithm::toa_vref_scan(tgt); + YAML::Emitter out; out << YAML::BeginMap; - for (const auto& page : settings) { - out << YAML::Key << page.first; + + for (const auto& [i_roc, page_map] : settings) { + out << YAML::Key << i_roc; out << YAML::Value << YAML::BeginMap; - for (const auto& param : page.second) { - out << YAML::Key << param.first << YAML::Value << param.second; + for (const auto& page: page_map) { + out << YAML::Key << page.first; + out << YAML::Value << YAML::BeginMap; + for (const auto& param : page.second) { + out << YAML::Key << param.first << YAML::Value << param.second; + } + out << YAML::EndMap; } out << YAML::EndMap; } @@ -25,13 +31,15 @@ void toa_vref_scan(Target* tgt) { std::cout << out.c_str() << std::endl; } - if (pftool::readline_bool("Apply settings to the chip? ", true)) { - roc.applyParameters(settings); + if (pftool::readline_bool("Apply settings to the chips? ", true)) { + for (const auto& [i_roc, page_map] : settings) { + tgt->roc(i_roc).applyParameters(page_map); + } } if (pftool::readline_bool("Save settings to a file? ", false)) { std::string fname = pftool::readline_path( - "toa-vref-scan-" + std::to_string(pftool::state.iroc) + "-settings", + "toa-vref-scan-settings", ".yaml"); std::ofstream f{fname}; diff --git a/app/tool/tasks/trim_toa_scan.cxx b/app/tool/tasks/trim_toa_scan.cxx index e78bc849d..45be07b21 100644 --- a/app/tool/tasks/trim_toa_scan.cxx +++ b/app/tool/tasks/trim_toa_scan.cxx @@ -8,7 +8,7 @@ void trim_toa_scan(Target* tgt) { auto roc{tgt->roc(pftool::state.iroc)}; - auto settings = pflib::algorithm::trim_toa_scan(tgt, roc); + auto settings = pflib::algorithm::trim_toa_scan(tgt, roc, pftool::state.iroc); YAML::Emitter out; out << YAML::BeginMap; for (const auto& page : settings) { From c29101239029a0ccbf37d93958d8738edc0f75c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 26 Jun 2026 16:05:41 +0000 Subject: [PATCH 02/14] Apply clang-format --style=Google --- app/tool/algorithm/get_toa_efficiencies.cxx | 29 +++++----- app/tool/algorithm/get_toa_efficiencies.h | 3 +- app/tool/algorithm/toa_vref_scan.cxx | 59 ++++++++++++--------- app/tool/algorithm/toa_vref_scan.h | 3 +- app/tool/algorithm/trim_toa_scan.cxx | 7 ++- app/tool/tasks/toa_vref_scan.cxx | 7 ++- include/pflib/Exception.h | 14 ++--- src/pflib/packing/ECONDEventPacket.cxx | 6 +-- 8 files changed, 70 insertions(+), 58 deletions(-) diff --git a/app/tool/algorithm/get_toa_efficiencies.cxx b/app/tool/algorithm/get_toa_efficiencies.cxx index bb231af91..d84d7aa52 100644 --- a/app/tool/algorithm/get_toa_efficiencies.cxx +++ b/app/tool/algorithm/get_toa_efficiencies.cxx @@ -1,15 +1,13 @@ #include "get_toa_efficiencies.h" -#include "pflib/utility/efficiency.h" #include "pflib/logging/Logging.h" +#include "pflib/utility/efficiency.h" namespace pflib::algorithm { std::array get_toa_efficiencies( - int i_roc, - const pflib::packing::SingleECONDRocErxMapping& mapping, + int i_roc, const pflib::packing::SingleECONDRocErxMapping& mapping, const std::vector& data) { - static auto the_log_{::pflib::logging::get("get_toa_efficiencies")}; std::array efficiencies; @@ -18,7 +16,8 @@ std::array get_toa_efficiencies( /// time for all 72 channels if (data.empty()) { - pflib_log(warn) << "[DEBUG TOA] data packet vector is EMPTY for ROC " << i_roc; + pflib_log(warn) << "[DEBUG TOA] data packet vector is EMPTY for ROC " + << i_roc; efficiencies.fill(0.0); return efficiencies; } @@ -30,9 +29,10 @@ std::array get_toa_efficiencies( auto [i_erx, i_ch] = mapping.toErxChannel(i_roc, ch); if (i_erx < 0 || i_ch < 0) { - pflib_log(error) << "[DEBUG MAP] Sanity Failure: Negative mapping values detected " - << "ROC " << i_roc << " Ch " << ch - << " resolved to eRx = " << (int)i_erx << ", eCh = " << (int) i_ch; + pflib_log(error) + << "[DEBUG MAP] Sanity Failure: Negative mapping values detected " + << "ROC " << i_roc << " Ch " << ch + << " resolved to eRx = " << (int)i_erx << ", eCh = " << (int)i_ch; } for (std::size_t i{0}; i < toas.size(); i++) { @@ -44,17 +44,20 @@ std::array get_toa_efficiencies( if (ch == 0 || ch == 36) { pflib_log(trace) << "[DEBUG TOA] ROC " << i_roc << " Ch " << ch - << " (eRx: " << (int)i_erx << ", eCh: " << (int)i_ch << ")" + << " (eRx: " << (int)i_erx << ", eCh: " << (int)i_ch + << ")" << " first 3 raw TOAs: [" << toas[0] << ", " - << (toas.size() > 1 ? std::to_string(toas[1]) : "N/A") << ", " - << (toas.size() > 2 ? std::to_string(toas[2]) : "N/A") << "]"; + << (toas.size() > 1 ? std::to_string(toas[1]) : "N/A") + << ", " + << (toas.size() > 2 ? std::to_string(toas[2]) : "N/A") + << "]"; } efficiencies[ch] = pflib::utility::efficiency(toas); if (efficiencies[ch] > 0.0) { - pflib_log(debug) << "[DEBUG TOA] Found non-zero efficiency on ROC " << i_roc - << " Ch " << ch << " = " << efficiencies[ch]; + pflib_log(debug) << "[DEBUG TOA] Found non-zero efficiency on ROC " + << i_roc << " Ch " << ch << " = " << efficiencies[ch]; } } return efficiencies; diff --git a/app/tool/algorithm/get_toa_efficiencies.h b/app/tool/algorithm/get_toa_efficiencies.h index 4fdd2401a..02933494d 100644 --- a/app/tool/algorithm/get_toa_efficiencies.h +++ b/app/tool/algorithm/get_toa_efficiencies.h @@ -15,8 +15,7 @@ namespace pflib::algorithm { // templated to match any event packet type std::array get_toa_efficiencies( - int i_roc, - const pflib::packing::SingleECONDRocErxMapping& mapping, + int i_roc, const pflib::packing::SingleECONDRocErxMapping& mapping, const std::vector& data); } // namespace pflib::algorithm diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index da426e1d4..1a8b0f365 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -8,8 +8,8 @@ namespace pflib::algorithm { -std::map>> toa_vref_scan( - Target* tgt) { +std::map>> +toa_vref_scan(Target* tgt) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; /// do a run of 100 samples per toa_vref to measure the TOA @@ -21,7 +21,8 @@ std::map>> toa_vref_s std::map> target; // i_roc int for each variable std::map, 2>> final_effs; - std::map>> settings; + std::map>> + settings; // TODO 348 DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; @@ -34,7 +35,6 @@ std::map>> toa_vref_s parameters["REFERENCEVOLTAGE_1"]["TOA_VREF"] = toa_vref; auto test_params = tgt->tempApplyAllROCs(parameters); - usleep(10); daq_run(tgt, "PEDESTAL", buffer, n_events, 100); @@ -51,22 +51,26 @@ std::map>> toa_vref_s auto [last_erx, last_ch] = mapping.toErxChannel(i_roc, 71); if (toa_vref == 0) { - pflib_log(info) << "[DEBUG MAP] Mapping Check for ROC " << i_roc << ":" - << " Ch 0 -> eRx " << (int)first_erx << ", eCh " << (int)first_ch - << " | Ch 71 -> eRx " << (int)last_erx << ", eCh " << (int)last_ch; + pflib_log(info) << "[DEBUG MAP] Mapping Check for ROC " << i_roc + << ":" + << " Ch 0 -> eRx " << (int)first_erx << ", eCh " + << (int)first_ch << " | Ch 71 -> eRx " + << (int)last_erx << ", eCh " << (int)last_ch; } } catch (const std::exception& e) { - pflib_log(error) << "[DEBUG MAP] Critical: Mapping lookup threw an exception for ROC " + pflib_log(error) << "[DEBUG MAP] Critical: Mapping lookup threw an " + "exception for ROC " << i_roc << ". Message: " << e.what(); } // - auto efficiencies = get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); + auto efficiencies = + get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); pflib_log(trace) << "got channel efficiencies for ROC " << i_roc << ", getting max efficiency per link"; - for (int i_link{0}; i_link < 2; i_link++){ + for (int i_link{0}; i_link < 2; i_link++) { auto start = efficiencies.begin() + 36 * i_link; auto end = start + 36; @@ -75,12 +79,12 @@ std::map>> toa_vref_s final_effs[i_roc][i_link][toa_vref] = max_eff; if (toa_vref % 32 == 0 || max_eff > 0.0) { - pflib_log(trace) << "[DEBUG SCAN] VREF " << toa_vref - << " | ROC " << i_roc << " Link " << i_link + pflib_log(trace) << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " + << i_roc << " Link " << i_link << " | Max Efficiency: " << max_eff; } } - pflib_log(trace) << "got link efficiencies"; + pflib_log(trace) << "got link efficiencies"; } } pflib_log(info) << "sample collections done, deducing settings"; @@ -88,39 +92,43 @@ std::map>> toa_vref_s // from bottom up. for (int i_roc : tgt->roc_ids()) { for (int i_link{0}; i_link < 2; i_link++) { - int highest_non_zero_eff = -1; // just a placeholder in case it's not found - for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; toa_vref--) { + int highest_non_zero_eff = + -1; // just a placeholder in case it's not found + for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; + toa_vref--) { if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { - pflib_log(trace) << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc - << " Link " << i_link << ". Initial val at max VREF: " - << final_effs[i_roc][i_link][toa_vref]; + pflib_log(trace) + << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc + << " Link " << i_link << ". Initial val at max VREF: " + << final_effs[i_roc][i_link][toa_vref]; } if (final_effs[i_roc][i_link][toa_vref] > 0.0) { highest_non_zero_eff = toa_vref + 10; // need to add 10 since we don't want to overlap // with highest pedestals! - pflib_log(info) << "[DEBUG SEARCH] Success. Found threshold edge at VREF " << toa_vref - << " (Setting target to " << highest_non_zero_eff << ")"; - break; // should break from link 0 into link 1 + pflib_log(info) + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << highest_non_zero_eff + << ")"; + break; // should break from link 0 into link 1 } } if (highest_non_zero_eff < 0) { pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": no non-zero TOA efficiency found, skipping"; + << ": no non-zero TOA efficiency found, skipping"; continue; } if (highest_non_zero_eff > 255) { pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": deduced TOA_VREF " << highest_non_zero_eff - << " out of range, clamping to 255"; + << ": deduced TOA_VREF " << highest_non_zero_eff + << " out of range, clamping to 255"; highest_non_zero_eff = 255; } target[i_roc][i_link] = highest_non_zero_eff; // store value - } // toa_vref is a global parameter (1 value per link) @@ -133,5 +141,4 @@ std::map>> toa_vref_s return settings; } - } // namespace pflib::algorithm diff --git a/app/tool/algorithm/toa_vref_scan.h b/app/tool/algorithm/toa_vref_scan.h index 90ca0412a..2ccc6322d 100644 --- a/app/tool/algorithm/toa_vref_scan.h +++ b/app/tool/algorithm/toa_vref_scan.h @@ -15,6 +15,7 @@ namespace pflib::algorithm { * * @note Only functional for single-ROC targets */ -std::map>> toa_vref_scan(Target* tgt); +std::map>> +toa_vref_scan(Target* tgt); } // namespace pflib::algorithm diff --git a/app/tool/algorithm/trim_toa_scan.cxx b/app/tool/algorithm/trim_toa_scan.cxx index efc44bc59..548e4ecf0 100644 --- a/app/tool/algorithm/trim_toa_scan.cxx +++ b/app/tool/algorithm/trim_toa_scan.cxx @@ -65,7 +65,8 @@ std::tuple siegel_regression( namespace pflib::algorithm { std::map> trim_toa_scan( - Target* tgt, ROC roc, int i_roc) { // added int i_roc index for efficiencies + Target* tgt, ROC roc, + int i_roc) { // added int i_roc index for efficiencies static auto the_log_{::pflib::logging::get("trim_toa_scan")}; /** @@ -119,7 +120,9 @@ std::map> trim_toa_scan( pflib_log(trace) << "finished trim_toa = " << trim_toa << ", and calib = " << calib << ", getting efficiencies"; - auto efficiencies = get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); // added i_roc index for efficiencies + auto efficiencies = get_toa_efficiencies( + i_roc, mapping, + buffer.get_buffer()); // added i_roc index for efficiencies pflib_log(trace) << "got channel efficiencies, storing now"; for (int ch{0}; ch < 72; ch++) { // need to divide by 4 because index is value/4 from final_data diff --git a/app/tool/tasks/toa_vref_scan.cxx b/app/tool/tasks/toa_vref_scan.cxx index f8b7b6e45..1fe460d27 100644 --- a/app/tool/tasks/toa_vref_scan.cxx +++ b/app/tool/tasks/toa_vref_scan.cxx @@ -15,7 +15,7 @@ void toa_vref_scan(Target* tgt) { for (const auto& [i_roc, page_map] : settings) { out << YAML::Key << i_roc; out << YAML::Value << YAML::BeginMap; - for (const auto& page: page_map) { + for (const auto& page : page_map) { out << YAML::Key << page.first; out << YAML::Value << YAML::BeginMap; for (const auto& param : page.second) { @@ -38,9 +38,8 @@ void toa_vref_scan(Target* tgt) { } if (pftool::readline_bool("Save settings to a file? ", false)) { - std::string fname = pftool::readline_path( - "toa-vref-scan-settings", - ".yaml"); + std::string fname = + pftool::readline_path("toa-vref-scan-settings", ".yaml"); std::ofstream f{fname}; if (not f.is_open()) { diff --git a/include/pflib/Exception.h b/include/pflib/Exception.h index ab5d94375..6cf430ac3 100644 --- a/include/pflib/Exception.h +++ b/include/pflib/Exception.h @@ -26,8 +26,8 @@ class Exception : public std::exception { * @param line Line in the source code where the exception occurred. * @param function Function in which the exception occurred. */ - Exception(const std::string &name, const std::string &message, - const std::string &module, int line, const std::string &function) + Exception(const std::string& name, const std::string& message, + const std::string& module, int line, const std::string& function) : name_{name}, message_{message}, module_{module}, @@ -43,25 +43,25 @@ class Exception : public std::exception { * Get the name of the exception. * @return The name of the exception. */ - const std::string &name() const throw() { return name_; } + const std::string& name() const throw() { return name_; } /** * Get the message of the exception. * @return The message of the exception. */ - const std::string &message() const throw() { return message_; } + const std::string& message() const throw() { return message_; } /** * Get the source filename where the exception occurred. * @return The source filename where the exception occurred. */ - const std::string &module() const throw() { return module_; } + const std::string& module() const throw() { return module_; } /** * Get the function name where the exception occurred. * @return The function name where the exception occurred. */ - const std::string &function() const throw() { return function_; } + const std::string& function() const throw() { return function_; } /** * Get the source line number where the exception occurred. @@ -73,7 +73,7 @@ class Exception : public std::exception { * The error message. * @return The error message. */ - virtual const char *what() const throw() { return message_.c_str(); } + virtual const char* what() const throw() { return message_.c_str(); } private: /** Exception name. */ diff --git a/src/pflib/packing/ECONDEventPacket.cxx b/src/pflib/packing/ECONDEventPacket.cxx index 04f91f3e3..a5f00d8f3 100644 --- a/src/pflib/packing/ECONDEventPacket.cxx +++ b/src/pflib/packing/ECONDEventPacket.cxx @@ -11,7 +11,7 @@ namespace pflib::packing { std::size_t ECONDEventPacket::unpack_link_subpacket(std::span data, - DAQLinkFrame &link, + DAQLinkFrame& link, bool passthrough) { pflib_log(trace) << "link header " << hex(data[0]); // sub-packet start @@ -56,7 +56,7 @@ std::size_t ECONDEventPacket::unpack_link_subpacket(std::span data, << " i_ch=" << i_chan; // deduce a reference to the channel that we are unpacking - Sample *ch = &(link.calib); + Sample* ch = &(link.calib); if (i_chan < 18) { ch = &(link.channels[i_chan]); } else if (i_chan > 18) { @@ -327,7 +327,7 @@ void ECONDEventPacket::from(std::span data) { } std::size_t offset{2}; - for (auto &link : links) { + for (auto& link : links) { offset += unpack_link_subpacket(data.subspan(offset), link, passthrough); link.bx = bx; link.event = l1a; From 6dabfa431ccd7f6fc93cf6772505b6f0ded85169 Mon Sep 17 00:00:00 2001 From: haseckew Date: Thu, 2 Jul 2026 11:11:10 -0400 Subject: [PATCH 03/14] updated toa_vref_scan and toa_efficiency to successfully plot toa_vref vs efficiency --- ana/toa/toa_efficiency.py | 16 ++----- app/tool/algorithm/toa_vref_scan.cxx | 67 ++++++++++++++++++---------- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/ana/toa/toa_efficiency.py b/ana/toa/toa_efficiency.py index 7984f8d63..0ec180b3e 100644 --- a/ana/toa/toa_efficiency.py +++ b/ana/toa/toa_efficiency.py @@ -50,19 +50,11 @@ the signal-to-noise ratio. Select the point 'o' on the graph. """ +vref_axis = data['TOA_VREF'].values + channel_lists = [] for chan in range(72): - channel_lists.append([]) - -unique_toa_vrefs = data['TOA_VREF'].unique() - -for toa_vref in unique_toa_vrefs: - filtered_data = data[data['TOA_VREF'] == toa_vref] - for chan in range(72): - non_zero = filtered_data[filtered_data[str(chan)] != 0] - chan_triggers = len(non_zero) - chan_toa_efficiency = chan_triggers / len(filtered_data) - channel_lists[chan].append(chan_toa_efficiency) + channel_lists.append(data[str(chan)].values) # Plotting the results plt.figure(figsize=(10, 6)) @@ -115,4 +107,4 @@ with open("output.yaml", "w") as f: yaml.dump(yaml_data, f, sort_keys=False) -print("Output saved to 'output.yaml'") \ No newline at end of file +print("Output saved to 'output.yaml'") diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index 1a8b0f365..1241395f0 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -1,10 +1,13 @@ #include "toa_vref_scan.h" +#include "trim_toa_scan.h" #include "../daq_run.h" #include "../tasks/toa_vref_scan.h" #include "get_toa_efficiencies.h" #include "pflib/utility/efficiency.h" #include "pflib/utility/string_format.h" +#include + namespace pflib::algorithm { @@ -12,6 +15,29 @@ std::map>> toa_vref_scan(Target* tgt) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; + if (!tgt->roc_ids().empty()) { + int first_roc = *(tgt->roc_ids().begin()); + pflib::ROC& my_roc = tgt->roc(first_roc); + + // Run the scan and program the trim values + trim_toa_scan(tgt, my_roc, first_roc); + + // Log the first 5 channels + for (int i = 0; i < 5; i++) { + std::string ch_str = "CH_" + std::to_string(i); + auto channel_params = my_roc.getParameters(ch_str); + + auto it = channel_params.find("TRIM_TOA"); + if (it != channel_params.end()) { + pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; + } else { + pflib_log(info) << "TRIM_TOA not set for channel " << i; + } + } + } else { + pflib_log(error) << "No ROC IDs found."; + } + /// do a run of 100 samples per toa_vref to measure the TOA /// efficiency when looking at pedestal data @@ -27,6 +53,14 @@ toa_vref_scan(Target* tgt) { // TODO 348 DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; + // create a .csv file to save efficiency and vref data for analysis + std::ofstream csv_file("toa_vref_scan_data.csv"); + csv_file << "TOA_VREF"; + for (int chan = 0; chan < 72; ++chan) { + csv_file << "," << chan; + } + csv_file<< "\n"; + // loop over runs, from toa_vref = 0 to = 255 for (int toa_vref{0}; toa_vref < 256; toa_vref++) { pflib_log(info) << "testing toa_vref = " << toa_vref; @@ -43,34 +77,21 @@ toa_vref_scan(Target* tgt) { << ", getting efficiencies"; for (int i_roc : tgt->roc_ids()) { - // Debug callout for mapping - const auto& mapping = tgt->getRocErxMapping(); - try { - auto [first_erx, first_ch] = mapping.toErxChannel(i_roc, 0); - auto [last_erx, last_ch] = mapping.toErxChannel(i_roc, 71); + const auto& mapping = tgt->getRocErxMapping(); - if (toa_vref == 0) { - pflib_log(info) << "[DEBUG MAP] Mapping Check for ROC " << i_roc - << ":" - << " Ch 0 -> eRx " << (int)first_erx << ", eCh " - << (int)first_ch << " | Ch 71 -> eRx " - << (int)last_erx << ", eCh " << (int)last_ch; - } - } + auto efficiencies = get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); + pflib_log(trace) << "got channel efficiencies for ROC " << i_roc + << ", getting max efficiency per link"; - catch (const std::exception& e) { - pflib_log(error) << "[DEBUG MAP] Critical: Mapping lookup threw an " - "exception for ROC " - << i_roc << ". Message: " << e.what(); + // Save raw channel efficiencies to .csv file + csv_file << toa_vref; + for (double eff : efficiencies) { + csv_file << "," << eff; } - // + csv_file << "\n"; - auto efficiencies = - get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); - pflib_log(trace) << "got channel efficiencies for ROC " << i_roc - << ", getting max efficiency per link"; - for (int i_link{0}; i_link < 2; i_link++) { + for (int i_link{0}; i_link < 2; i_link++){ auto start = efficiencies.begin() + 36 * i_link; auto end = start + 36; From 8adaf9367c24080bab189c5664b4329fccd5b445 Mon Sep 17 00:00:00 2001 From: haseckew Date: Thu, 2 Jul 2026 10:29:55 -0400 Subject: [PATCH 04/14] updated toa_vref_scan with efficiency plots --- ana/toa/output.yaml | 4 +++ ana/toa/toa_efficiency_plot.png | Bin 0 -> 44580 bytes app/tool/algorithm/toa_vref_scan.cxx | 40 +++++++++++++-------------- 3 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 ana/toa/output.yaml create mode 100644 ana/toa/toa_efficiency_plot.png diff --git a/ana/toa/output.yaml b/ana/toa/output.yaml new file mode 100644 index 000000000..d98d92a10 --- /dev/null +++ b/ana/toa/output.yaml @@ -0,0 +1,4 @@ +REFERENCEVOLTAGE_0: + TOA_VREF: 180 +REFERENCEVOLTAGE_1: + TOA_VREF: 157 diff --git a/ana/toa/toa_efficiency_plot.png b/ana/toa/toa_efficiency_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..a8b49147a4fd9ea0f94d301c40fc2987ac560e4e GIT binary patch literal 44580 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 Y8~ZS@ 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 toa_vref_scan(Target* tgt) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; +// Reading out the trim_toa values for the first 5 channels to test, Cristina's suggestion if (!tgt->roc_ids().empty()) { - int first_roc = *(tgt->roc_ids().begin()); - pflib::ROC& my_roc = tgt->roc(first_roc); - - // Run the scan and program the trim values - trim_toa_scan(tgt, my_roc, first_roc); - - // Log the first 5 channels - for (int i = 0; i < 5; i++) { - std::string ch_str = "CH_" + std::to_string(i); - auto channel_params = my_roc.getParameters(ch_str); - - auto it = channel_params.find("TRIM_TOA"); - if (it != channel_params.end()) { - pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; - } else { - pflib_log(info) << "TRIM_TOA not set for channel " << i; - } - } + int first_roc = *(tgt->roc_ids().begin()); + pflib::ROC& my_roc = tgt->roc(first_roc); + + // Run the scan and program the trim values + trim_toa_scan(tgt, my_roc, first_roc); + + // Log the first 5 channels + for (int i = 0; i < 5; i++) { + std::string ch_str = "CH_" + std::to_string(i); + auto channel_params = my_roc.getParameters(ch_str); + + auto it = channel_params.find("TRIM_TOA"); + if (it != channel_params.end()) { + pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; + } else { + pflib_log(info) << "TRIM_TOA not set for channel " << i; + } + } } else { - pflib_log(error) << "No ROC IDs found."; + pflib_log(error) << "No ROC IDs found."; } - /// do a run of 100 samples per toa_vref to measure the TOA /// efficiency when looking at pedestal data From eca8815caa8d9804535d903cbe2b71f116279516 Mon Sep 17 00:00:00 2001 From: haseckew Date: Thu, 2 Jul 2026 11:01:44 -0400 Subject: [PATCH 05/14] updated toa_vref_scan --- app/tool/algorithm/toa_vref_scan.cxx | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index b074653c5..813a618ac 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -20,24 +20,23 @@ toa_vref_scan(Target* tgt) { int first_roc = *(tgt->roc_ids().begin()); pflib::ROC& my_roc = tgt->roc(first_roc); - // Run the scan and program the trim values trim_toa_scan(tgt, my_roc, first_roc); - // Log the first 5 channels for (int i = 0; i < 5; i++) { - std::string ch_str = "CH_" + std::to_string(i); - auto channel_params = my_roc.getParameters(ch_str); - - auto it = channel_params.find("TRIM_TOA"); - if (it != channel_params.end()) { - pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; - } else { - pflib_log(info) << "TRIM_TOA not set for channel " << i; - } + std::string ch_str = "CH_" + std::to_string(i); + auto channel_params = my_roc.getParameters(ch_str); + + auto it = channel_params.find("TRIM_TOA"); + if (it != channel_params.end()) { + pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; + } else { + pflib_log(info) << "TRIM_TOA not set for channel " << i; + } } } else { - pflib_log(error) << "No ROC IDs found."; - } + pflib_log(error) << "No ROC IDs found."; + } + /// do a run of 100 samples per toa_vref to measure the TOA /// efficiency when looking at pedestal data From 68c1fb39f72e52eead4750f43499af3b6170f179 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 2 Jul 2026 15:21:22 +0000 Subject: [PATCH 06/14] Apply clang-format --style=Google --- app/tool/algorithm/toa_vref_scan.cxx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index 813a618ac..ebbedc72c 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -1,13 +1,13 @@ #include "toa_vref_scan.h" -#include "trim_toa_scan.h" +#include + #include "../daq_run.h" #include "../tasks/toa_vref_scan.h" #include "get_toa_efficiencies.h" #include "pflib/utility/efficiency.h" #include "pflib/utility/string_format.h" -#include - +#include "trim_toa_scan.h" namespace pflib::algorithm { @@ -15,7 +15,8 @@ std::map>> toa_vref_scan(Target* tgt) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; -// Reading out the trim_toa values for the first 5 channels to test, Cristina's suggestion + // Reading out the trim_toa values for the first 5 channels to test, + // Cristina's suggestion if (!tgt->roc_ids().empty()) { int first_roc = *(tgt->roc_ids().begin()); pflib::ROC& my_roc = tgt->roc(first_roc); @@ -28,14 +29,14 @@ toa_vref_scan(Target* tgt) { auto it = channel_params.find("TRIM_TOA"); if (it != channel_params.end()) { - pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; + pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; } else { - pflib_log(info) << "TRIM_TOA not set for channel " << i; + pflib_log(info) << "TRIM_TOA not set for channel " << i; } } } else { - pflib_log(error) << "No ROC IDs found."; - } + pflib_log(error) << "No ROC IDs found."; + } /// do a run of 100 samples per toa_vref to measure the TOA /// efficiency when looking at pedestal data @@ -58,7 +59,7 @@ toa_vref_scan(Target* tgt) { for (int chan = 0; chan < 72; ++chan) { csv_file << "," << chan; } - csv_file<< "\n"; + csv_file << "\n"; // loop over runs, from toa_vref = 0 to = 255 for (int toa_vref{0}; toa_vref < 256; toa_vref++) { @@ -76,10 +77,10 @@ toa_vref_scan(Target* tgt) { << ", getting efficiencies"; for (int i_roc : tgt->roc_ids()) { - const auto& mapping = tgt->getRocErxMapping(); - auto efficiencies = get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); + auto efficiencies = + get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); pflib_log(trace) << "got channel efficiencies for ROC " << i_roc << ", getting max efficiency per link"; @@ -90,7 +91,7 @@ toa_vref_scan(Target* tgt) { } csv_file << "\n"; - for (int i_link{0}; i_link < 2; i_link++){ + for (int i_link{0}; i_link < 2; i_link++) { auto start = efficiencies.begin() + 36 * i_link; auto end = start + 36; From 3a54d2528d7ea3c8565445b0c7b17ad471d40920 Mon Sep 17 00:00:00 2001 From: haseckew Date: Tue, 7 Jul 2026 11:23:39 -0400 Subject: [PATCH 07/14] updated scanning method for toa_vref_scan --- ana/toa/output.yaml | 4 - ana/toa/toa_efficiency.py | 33 ++++-- ana/toa/toa_efficiency_plot.png | Bin 44580 -> 0 bytes app/tool/algorithm/toa_vref_scan.cxx | 165 +++++++++++++++++---------- app/tool/algorithm/toa_vref_scan.h | 2 +- app/tool/tasks/toa_vref_scan.cxx | 4 +- 6 files changed, 133 insertions(+), 75 deletions(-) delete mode 100644 ana/toa/output.yaml delete mode 100644 ana/toa/toa_efficiency_plot.png diff --git a/ana/toa/output.yaml b/ana/toa/output.yaml deleted file mode 100644 index d98d92a10..000000000 --- a/ana/toa/output.yaml +++ /dev/null @@ -1,4 +0,0 @@ -REFERENCEVOLTAGE_0: - TOA_VREF: 180 -REFERENCEVOLTAGE_1: - TOA_VREF: 157 diff --git a/ana/toa/toa_efficiency.py b/ana/toa/toa_efficiency.py index 0ec180b3e..ea38e4f81 100644 --- a/ana/toa/toa_efficiency.py +++ b/ana/toa/toa_efficiency.py @@ -20,6 +20,7 @@ description='takes a csv from tasks.toa_vref_scan and outputs a plot of TOA efficiency per channel against TOA VREF values' ) parser.add_argument('-f', required = True, help='csv file containing scan from tasks.toa_vref_scan') +parser.add_argument('-r', '--roc', type = int, choices = [0, 1, 2, 3], required = True, help = 'ROC index to filter data (e.g., 0, 1, 2, 3)') args = parser.parse_args() if not os.path.isfile(args.f): @@ -30,6 +31,11 @@ sys.exit() data, head = read_pflib_csv(args.f) +data = data.iloc[args.roc::4].copy() + +data = data.sort_values(by='TOA_VREF').reset_index(drop = True) +print(f"Extracted {len(data)} voltage points for ROC {args.roc}") + """ Example plot of how TOA_VREF plot should look. I credit the toa_vref_analysis.py script from the TileboardQC Repository for HGCAL Tileboard Quality Control for this @@ -67,9 +73,9 @@ plt.xlabel('TOA VREF') plt.ylabel('TOA Efficiency') plt.tight_layout() -plt.savefig('toa_efficiency_plot.png') +plt.savefig(f"toa_efficiency_plot_roc{args.roc}.png") plt.show() -print("Plot saved as 'toa_efficiency_plot.png'") +print(f"Plot saved as 'toa_efficiency_plot_roc{args.roc}.png'") # Printing the values of highest non-zero TOA_VREF per link link0 = np.array(channel_lists[:36]).T @@ -83,16 +89,24 @@ if not all(x == 0 for x in link1[i]): link1_count.append(i) -print("for link 0, the highest non-zero toa_vref is " + str(link0_count[-1]) + ", " \ -"so set TOA_VREF to ", link0_count[-1] + 10) -print("for link 1, the highest non-zero toa_vref is " + str(link1_count[-1]) + ", " \ -"so set TOA_VREF to ", link1_count[-1] + 10) +if not link0_count or not link1_count: + print("Error: Efficiency data contains only zeros for one or both links.") + sys.exit() + +max_vref_l0 = vref_axis[link0_count[-1]] +max_vref_l1 = vref_axis[link1_count[-1]] + +optimal_vref_l0 = max_vref_l0 + 10 +optimal_vref_l1 = max_vref_l1 + 10 + +print(f"for link 0, the highest non-zero toa_vref is {max_vref_l0} so set TOA_VREF to {optimal_vref_l0}") +print(f"for link 1, the highest non-zero toa_vref is {max_vref_l1} so set TOA_VREF to {optimal_vref_l1}") #Outputting the values to a yaml file df_max = pd.DataFrame({ 'link': [0, 1], - 'max_toa': [link0_count[-1] + 10, link1_count[-1] + 10] + 'max_toa': [optimal_vref_l0, optimal_vref_l1] } ) @@ -104,7 +118,8 @@ 'TOA_VREF': int(row['max_toa']) } -with open("output.yaml", "w") as f: +yaml_filename = f"output_roc{args.roc}.yaml" +with open(yaml_filename, "w") as f: yaml.dump(yaml_data, f, sort_keys=False) -print("Output saved to 'output.yaml'") +print(f"Output saved to '{yaml_filename}'") diff --git a/ana/toa/toa_efficiency_plot.png b/ana/toa/toa_efficiency_plot.png deleted file mode 100644 index a8b49147a4fd9ea0f94d301c40fc2987ac560e4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44580 zcmbrm2T)Ym_chuMBaBKgBUuELD3X(aiV`F#2uL0zXUP&8R1^#Z0VU@sS#oSp5s=tO zYRO8@2y_#=3E#dr^ZSRYSM|R4sG6c3x^JI*&OUpuwe~vq)K$J30tm z7PxX*g7>_YtLsA-Nq&C&|GeX}qq8OdMfo0GxXO`-in=Z+6pab;-=X)iS=K02{u`y6 z*Y7=wUmWrDxkte4uWrU1i8)@Zaz2Lrro*+M8(*{sM!uz{>*d+=^&0(IrfqAV8&$6J zE9Z3CQ$xSkOzx7*K&B>B|OkOX+!ivNUxp-{xP`GuzrUZGCI-NR4%pGRE}UTB~W zOCG%7di)0y^5XI7Yfq?=7uSv^U!y=?oIiXgnGAXH<`2%UL&yuoL;qd|_5boR_#7$* z(b*uO&aUL^{$}R_MC}LJm2&d(db6_=>k|oo6~p-Yc(1IX;wC*187(Z;9r6% zo@5GXT$-6y?a>101o_V@F@m==Ggammgi+^BU^M3&&jp<5NzyU$dP*70#(XYQ%<3v^cNJC?(qYD-FyZMw2UFk{@)$bX8w^Hh+VDU-j_xX9u#?G!+OUE!{ zb)va#V%2J(*gRGSUG0lcW0{+g-S_9Z}wWWtCz+1S`PMI#UHc=(&}0wqe(m44D(&=rgNlj@ebc6( zB0(XceE29i)57fR2aC>lYo+2uulejZF0#Z~Hsx@_VhL97@ZrP#>b`3c(Jqpk!!G#| z>N49eoc1^U_ATMfzQnoY)n;bz_HZ-%?;lvFy)QUvEP2nryp;HXUDuD;lk}On{@3SY z`NP8ox%v4W#k_6A29~|!8>E@(ILC5!-L@!x8v0NINu=9N^Eq~=WMgHF1t;=gmzVh3 z1uKn1zL6wJg;G41$$&~`A+0Cv=fUk+jn;ayD!*ECuVME2bzLGsZFlmL>=6kMSe@3k zww^{>-PwSZmnEdFn4lr&pGekcf~o@(Y-jbNm<=I@l921B;BMTpylVoSyCNF& z!gBko%`9zKD0jzc>$~J=q|?LL6k2~iwEFz)$lwPPxv$<{`@5SW5W;6ppSJq(@rmSI zdIVl}e_b{_J<8ZuH^5|;-)~#_tEb=21dI8(fYC=2!5@_$kOZwMGGS(uaLY-r0dAp8W zia#INkOFr(SHDlHpCWkqkHdc5tlN}EqWn^lPcb8PAU6+B+VtxF-q?Om)l6dU;-cNu zSQr?)#p*=?=m5)UlQ^XJd2 zm#Y^_EwPF3S6EO)smMyQYqI4wecVdjivuMM%&_13qUv|dr8mBtvbF_B@#$wmO3A&g zu8y0EGA#>! z?%(HBI#@SY;KPw8Lm4Fm$I*3!e8)LtztPrj-7<9P5SgEy?aD2z%Yn^gv$M5of*q)E zOhTfrudffeY>(egv)?QMXN=p~Ue_`SZuUa8z)$h}=^}4+Um4B+T;Lk&)5YA~tkAb3t}C7rUse?EZ_*u@cMB%hj_NI-&*SV8N@j z^X{iC6xJKf&COL4=W{u>k71QBSKTbcY{V8|HuQp-rS;;(91n_s{ZP58-|m93f5CRQ zGQV}>t24yW&AP0eot^h_oHE4OG~@zESlI6EY&%OPc#)PWv~+c|9evm1u6t_VyEmI_ zyqjau9-U&D=qWEY=2N03F?AZf`r7y{yNHZq}zkbL0JI8WZ99Z0d0GG`!83gu}O{+ zjMPy5{%jg{sDPSl!FT_|`AKO;2blT($A`$CuKn`DME1;;7Ss{vKi+q6C~#|_61$1% z4@)24>|MvoIw}=IqW+Y;+7fX|pM!%V5<7D&$jx`Zc5D2#wy9|vVJ<644+$`>J9qwu z?^@_lm!+zf&l@XDz)@|^C`zuZwi)jUUYRC%P?XnT9tnCtFM?TE&8coF(^ z{5$=AJfVPjK+^cfX!bUX65SQd=IDu)mDNXikfdz8)0J4;e$ebQFSV~j+NNnOdH?<^ zaS&H`_8e0EYKOOBRxpBYP$aGAazo+q_j$u?V^mEayL;xJtKaY4rz z-4|{K36YnxptxAjES_T-6(Y*(MDf@+FC*g?%-da4$xtydF^Z;0$UdJx-#}7g_>Qu* zWoJA@mKV2KwlzBf8D#fXL*K}Xjks!JM^(=G?X4$45je|x|G0Dem7o_h(y)h-&HpYc zDl0+CgM3dVK~f9ZbvrY%{^M{lI^l)Es(Zw=P?>Oc5mC|kr2U;NSOS~fX1^VUFIO$F ziF}2)TnPV*SIT|1o!wkrZ;oWt3I&o;P|rdNrV7e8!ss!FDhOG2QU*a4g`KaKgx=8Y zT_D^uMyne>`uUujlk+dV5JOGPGz4L+wei!`9Qo0ktqBX2jMNDzGChzXN}Z=}GkFX< zu@;SN`(jq=NH@kGgaH6sD5$yoOHx|e5NGI-0KqfrwZNyex6<(~O~JPJ{oU(haWhGN zb?nc1S!JQpYZ)2&e(~N10C@+J;&ewGZSi#@oS#l{aq-hSmY$v-5vTDlA2(|z{o+~S zn&E!^eh|7y>fKtMXpm8JO7{z--h{k%X_f%@$8>rV-=oe0HHX&V;q@*{VTWOHs4mZa zCQ(bw1sNF}$9cA+qLJMxxl+4+PgC>Mi#TEHaNq4VW1Egxk!k=j zp^sLeNE}}JILd(J;1sz)az4+HTW)S;qv%aTDDlsvm)&dpjXe0OrH%!6&KOF)4rE)J zl(y;RRE@rJ9neTmMI8a||FhfLWQ)RZ#}2@mTKQo5jH$LLicZ5ipQ^R>b+X1dcBlig zJ@FDQ!gk-U1T%=K(Hgpj!D{ADgv!dy6HNPb#xw!(#!9$k`U0}fDJW2bP4(n~bobf@ z6b$uCiH}laV`K58v3(;XSlDE;MiW+WFHc>P_wl(93j+_}jgkeB&9NOdrk;3J7mCzi zwVQ4GSe&6pL}>bY73scvoa}Pt#En-QP%n@wblo&mdLtT{j``iqF&sel)M;0kZ%Mah zwr?UEzbfbFZ6NivOgTUAs9&)B6Qytph{&YIeeqU;FwKFw4V#I-l!BSVdVny0}!wyM_ z#LfDBB(9Nw9Q9rao*Rx4vYbb%q5JZ1HtcjrsTxSJ>F%c9UGZuPqC++j0YJg6T%E#x ztlyr?2w+REjR8wCEKPG7e|?rkM{I`o3PuM3tbpuy6_FSBjEtDqYF)A#j?F3aWA0fd zxJA}&cR0@b)5zS>*4E~A6q{4&>E+6bPvuaKd?qbp_x(dM4z`xcBkCfbdfDyCi0ZXg z9yiF&^S~>L3@%44y4RfL(>v{cs_y0+ff;~`YeM1L|Yw~K*`E!V8nz1gx%LTmfMqToN0(co{J zbQ!WKg!CTcuRUJubf0&oti1f9T|m8yyB7qXLeOrLSY1k$%gnsGA29-ucHtp1@;~|R zhFVOw$LLi)Oxc52$^G!*PDe)v5#D;@q>h0>9@NDe;<86Q55USI(`IC%t#2H~*X<<6 z!v2sCVa!I-SoM#m$MCQk2r98w@$@(wI+Ng$xQy8}>WCBL&s;w_2Pm{>6yxo0@vXvs z=%Uh-juGUukQo(>w?5OR%4B{sOkm)17$}~4kt_0GwOt51yEPGtgO4%1wXAGbJ!ucH z#%r~a)@?e*GV_aHAnJU~BXTAbu?T_sQ&UrVwU3DO@*8%gW=R4a7iinIn3sF+cKdSbk5WQqu%&UBi_A;f!S$lVHh!?MkU@`pXWBkt; z*B@Pl^fIf>41_>(Cf?;>OC|ZNDfM23tx9O*_q_{rC>_c3uU@^1c1K0+l;E=BonIkH z3wCvGW#xVNnA(p@?2IP-bV*!}QkDy(rn3Ilr-|N`CL{rbLXb<@-=F>fYEnwt3PT9? zsY_}I>IKetmK3M{gJy)c4k914)ptq_P`tx6Z=e`mKkcc%2nQjuK_T!evwGnS z3Wa`7hwRtxo*n`+_s5L4o_0zu@EW@HY0=C2)?Q@}-P>xGwV7xNCjO-HI~V=ju*x|@ zPfyRag(K=2W^}S80vQ#+PbR1SitKD9m>09}rV4|{`LvNxD5xAix;rgae;3jvH#fIg zY^D*KpoLUM1lG}R)UxbvHS578>+l);bFDmuy_HTAr5-Cr_M^22*i!}wdi3jQwR+ft zuKl`})__r~HwJAH7K7edZT8yRo+-2L$xQw}P-3}&ke~Dqx8#MPw)GykL1sAFVz>(x%^51B>v(AJ>9e zWQ}-q3VQK#J!D0YJ2d6x11?woc=`cXJYZK1sIAOyKyYcWOj#~~^5vs3zkSkJ_4q5E z&&-7B%B{SNx1=WOqIsJ$B3u0OdUL zj`K|xC37&9x$sfrgFJ1#w?=CY_l2aaV6oA2#j-a%d?4P!LBSbseC-BvZ1eH)A$k#; zw|fiqd$~h6q&W0-btQw)bO)l~DXbv@koi2aN}#)SPcWJiAgNmoS2`hE-mQ(Vf|HL= z6~T>px+O?NZV-15B^RF4R_~WSgnIl!Qc_abb@q;Gl8hlT??g!^_D>+PmAcGyMsIL| zh1{#+ zU&9p`6Y`F0vSzxGkUEgz4%m$((PUkV!UJHl{{F!Poq))~s2`laU?S!#CqfoBJWtPt z7nhW9Y|DO$kB^t>Ja|JF3y?Tl_`nnTk{ZsgjE}_|5JJDT&}#->#986EF9%BL{}0I& z#_`{7=KquOs<^O#2*Ae^to3pVH>?~>bo`wexi7o4S_ly(`B2xM-bH3F{lk)D4Pk!G zW{L2K%+x=gIzhTbg-zXsU}AxKeA5)5D(c#+!M$?*cQg)1xH~zl3!8IWDJrZ;L(4L) zl&CI-gRyD6vDWi)^K|Qt#%bSc6V7Kh{}VN9f1nd{y{{WQCFnA$wZL3BpDW#>^cSjY z;rEBSMyF>RJv}B+sO(Tge?EVhs?~{Im>Ttl`1=iaoMJTnSJ(UaAWd zs=$^GYVKTpRXv8pnNyXhtmcyi7@#r7N=49PP$9lIF&?IxR}FQ&TU@SDiU?MqpD8 zq+1{!gSDO|Ha0fj4X9CGF($f^eK@6OE@S9TM5V8yr>DnnWBrUk)ZEVn8Wa$W#(z@) zWTSI97~}?+kVe1m6p>FJ#8?70{9ZjfWL`3zX_Dc8|m$~%povP=F(RT)OdbhNVT z=DM&Fja77dS1<-=OkZ(uWYS1tdJiR&#`F0!i?102jYGH^1@oh85f@dv0mc!4hAseY zc+)m@^rav2%>XbF9`RQYsD7V6e^2B|gYf?`J6^(@Pbh628D-UpO=;;^X&s&4kaaQg zlCMvYC>+)(Tu2&zUm#n{WN<2(WEo6#dJZC>yj(j!KOYfLffBY0%_LxY*$~kL(=;@>qMw)g`fyMmu|j72@}a7qzdh&)Wv`l zq4i=KDoTm0m2jowN!Hdsb8_B{8?1S_i?Q<=Xk{F0eQj1j2PlAE;K9v`l~cC-gu7|- zjRwESP!A%U_qFUn?bUb0WMpe*kvG|i#$~D{l0@pY_aZhcpXLxI0a;TSKwAm!gVsc7=`=8Vh%-8i zGdj&c_wx-fewn?tsPxoPWVq$t6TCDtlEa>GN@4)wkeA)MCkyn zB44-U;uVY7%>F#xG!Vq3Gi|qgWDq#q*w~19cM)=}#(;gmS(VL|cn4RB{%x;Mc;^9o z!%%niRPSt9j;Qc`bI^?nn0>cQ5IGzuer`eip4ZYyjo61=63FEuetSFDc0jmE>C4qw z08HE66wCm<174(A6>D2Cms^&jOuk-|h>VJ|1%}1S z_Y~5ARS`J~!#NdMsodQjBh>f(`}-lsdP7)UNe~7=%cc7+zKrMw#Qdd1X>a_Jqn|$f z5$W&%H^37Y3fE<6ptV}HtMA@gVpHRzy7WZA+o3wXN5SSt^vG-OuE} z<}BScy_zd?)M(j(xFa-UQgKI0Tw7x0z3wve!)KfJE!|6GiEmUbqS$<4gtrWrsZol| zNLGI1Tq~k_y=|~zRm5{D-&#`m4$14++Vb(pUW1uXsaVFJ=plA05qIm$_SFa(IEfLbVZc?hIsf?iAb5fQfsgEE&kM{h6{WYXlK;~pW zLfg25md1;k2($uqEEVx5LaT~}E-;g!*lCc`uP706qN;dCp1*skidsT`l9`@Ux}o0I zQ!(n7TEJV)@!z9~3zsPgu);`iPe!xuJ1oPVSnfN02vu}Y^0=Bm&^fEI(1|oj>^`C^ zZ+N844t`&&=sSytu*7GQsM%}?na6H8Fk}_56BZhVvGO|{vzLZtagtrmMf*HJ3HO6RBj8ssH zxVmn^@?P`nuk|XMcc@jGC$a_qqEl-8r|uHm#XXc1^5NU%&VZ z04BVCBsPo5ga0UBXU50xaH}nA+u`xLXiNTVGUokm-(q~r10=wF}4#@p#pT}((YB#+Ho*{N6= zaN7=hOm6<|X4dSQ?-hC}vl8Pi`2=C(gdUehFO1IvFYVD#PI?dta z>vE>AAiT+u@Sd#@Y!21byL)%mzc+zW&idA^Rz}&&RWAuoiwcUk+j%MN{=&UumE+hZ zX}z6zas1~PXMwnwoUt_N0xZu_(rn$NpHDqTTKQ4}KI7RWHR=V`!KSg!w9a1kmmVxn zx$efY7-mh(y$w}&shJt$M(FVJ_`14AXXu+Jalf=?8jG`J5e1+^Y5*?}*it)C#}%8yOu&%lsECA~SWg_hDCI!ShxbjAb>_qwpwn z*D1u|^0>ET*S>ec`s6`G78*x*Pk8tNLqO;v-QJqux3*TTq5^i znmH^w4TN#KGG2Nqr2_@@IRdZK<1rmSUoT+f?bN5y<=(~y zn}<-z{D`sV@mnFz<`cfduk0m=U7uo{Mkr8^>kd3X8fs24J@xwDw9Rhc-Fe0oZ+@iYOA%A+)?;yw*=a?0 z%UQQ=oD-AL`4qyO&Gp2`#t%`~t`L(i9e9?q+l2Y{3zj=ZlRsbSml+G|RB-Lc)v;|J zdENW1>%7O_j28McZmQ$!F-De2*V)CGom4UuwZfCc-xjDq;XViVzZVzgd@hAEPrXnD|g%Sc@)%qI>*}_MPKfgWpCOdnEjwQ#a!&P+tOmeEHZjP(* zaNe2TauQtJc<;3F^pg#XbvDK{i=2}4j;7|5jpY&W0`WpqwbjBjBsJoHl@IP(^ExDX z2e7_FZp z2&by9{223r#5nr81~OOJQOB6V_+$J*^fNAcHbk$$LA8=ef`tt!@KmWS&X4obB?Vvt zi0*hlakp=ePijiH%&;zV<72e6m|^D}o7<0);Jc(`%P9%h{vbgunqNQ;xckJ)4u_nX zv9N;7qZP!ZHcvYAxK5r0|0hC4&%0yAyj(jXL;DC6FFLoo6`Cm36~lZV@h|^i*j~A} zwvf?U_3QHsr~Xfrn?5yiBz1xxrfl9|X^_AYo=zuZ!Ps+)2;(SQXvsejN)scZN0+w# zNA5{GxwXE@tJg_-G**a$K$_1XH{73WdNFnkDwc8>^^fQqNHu;VEYsGV-{;19I41q$ zcl$oKwZ?7IeuKADATvI6snR>FePiQ=Q`09wfteU#Itm&VS!aKC&G37=x?DZN6Rjon z#VX2)T0?0~kF?S3bfQ$T!gs5TtM3nFsdqc21-Z*!Azw3>OA{`y+ zZQMfSWYX08{QO`Z>|U#W&uJ)vjK&cLfjF%TG*Yn)N=uCwhEQHBgjSS$&LUtGZ02&X^sqW1);6zZxm-p*%TWd&voP z;2P|rD!_lI{|J=m;G;?`qP&^n#>*+@{Yy(^WX6`}=5G8&Y0vniq?g5Y+~rkpFGK)Q zAfU0@q*zF~G33yz-fL}dgnI?9MI@}Ase@pr_G3G!jHKzQyA!;+^IuDPeV=l)g%1u2 z_VrGNvx8OWeQBw1!BrAZ^9zFkmo(bB4TC^NHfJ{GB=H9yUbzUtOrD-0>K6b$l|#Pj zfrS|5h?e#RCD!M-{%WN*Oeov5SHgNLI3=+SVQ|>Vxfr%m&Q<*%DL`6WT zEIlIJ6}>$aOepG98m~W)b?ibzxaz6rf(qlDk!4*h#Iqc;{*X6`zw5PBe)2U)LM`; z%J-h_eq_QRVY2^4b6`6?lO%&dnTDQ#{?WN{^oRHHtB-DiVZuNVYMD7lwbkl+{~y2qmq6L^6@D!Q!g~+N}5741U6# zadfTCVzWYH-8g08%&wmn@AA6utZ1AeERB6{^!l{HP@3;7#?u~k4SOK2eN{=ix1LkF zO}9UW{*YT?z6~BYJrUu&-b86zFv5WIM`MJ-8$Y*4Jy&Z|JoP6weTYIyu5*JEedpa? zSzB8D;`cPaCF?M3@eW_F#nsDGrzysGN)$(5?&pd&OMH^5-#nBw7m?-qc Y8~ZS@ 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 +#include namespace pflib::algorithm { std::map>> -toa_vref_scan(Target* tgt) { +toa_vref_scan(Target* tgt, bool scan_all) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; - // Reading out the trim_toa values for the first 5 channels to test, - // Cristina's suggestion - if (!tgt->roc_ids().empty()) { - int first_roc = *(tgt->roc_ids().begin()); - pflib::ROC& my_roc = tgt->roc(first_roc); - - trim_toa_scan(tgt, my_roc, first_roc); +// Reading out the trim_toa values for the first 5 channels to test, Cristina's suggestion, bug fix this later +// if (!tgt->roc_ids().empty()) { +// int first_roc = *(tgt->roc_ids().begin()); +// pflib::ROC& my_roc = tgt->roc(first_roc); + +// bool needs_trim_scan = false; +// for (int i = 0; i < 5; i++) { +// std::string ch_str = "CH_" + std::to_string(i); +// auto channel_params = my_roc.getParameters(ch_str); + +// if (channel_params.find("TRIM_TOA") == channel_params.end()) { +// needs_trim_scan = true; +// break; +// } +// } + +// if (needs_trim_scan) { +// pflib_log(info) << "TRIM_TOA values missing. Running trim_toa_scan..."; +// trim_toa_scan(tgt, my_roc, first_roc); + +// for (int i = 0; i < 5; i++) { +// std::string ch_str = "CH_" + std::to_string(i); +// auto channel_params = my_roc.getParameters(ch_str); + +// auto it = channel_params.find("TRIM_TOA"); +// if (it != channel_params.end()) { +// pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; +// } else { +// pflib_log(info) << "TRIM_TOA not set for channel " << i; +// } +// } +// } else { +// pflib_log(error) << "No ROC IDs found."; +// } - for (int i = 0; i < 5; i++) { - std::string ch_str = "CH_" + std::to_string(i); - auto channel_params = my_roc.getParameters(ch_str); - - auto it = channel_params.find("TRIM_TOA"); - if (it != channel_params.end()) { - pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; - } else { - pflib_log(info) << "TRIM_TOA not set for channel " << i; - } - } - } else { - pflib_log(error) << "No ROC IDs found."; - } /// do a run of 100 samples per toa_vref to measure the TOA /// efficiency when looking at pedestal data @@ -50,7 +65,14 @@ toa_vref_scan(Target* tgt) { std::map>> settings; - // TODO 348 + for (int i_roc : tgt->roc_ids()) { + target[i_roc][0] = -1; + target[i_roc][1] = -1; + } + + size_t total_links_to_find = tgt->roc_ids().size() * 2; + size_t links_found_count = 0; + DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; // create a .csv file to save efficiency and vref data for analysis @@ -61,8 +83,8 @@ toa_vref_scan(Target* tgt) { } csv_file << "\n"; - // loop over runs, from toa_vref = 0 to = 255 - for (int toa_vref{0}; toa_vref < 256; toa_vref++) { + // loop down from 255 to 0 + for (int toa_vref = 255; toa_vref >= 0; toa_vref--) { pflib_log(info) << "testing toa_vref = " << toa_vref; std::map> parameters; parameters["REFERENCEVOLTAGE_0"]["TOA_VREF"] = toa_vref; @@ -104,61 +126,84 @@ toa_vref_scan(Target* tgt) { << i_roc << " Link " << i_link << " | Max Efficiency: " << max_eff; } + + if (!scan_all) { + if (target[i_roc][i_link] == -1 && max_eff > 0.0) { + int calculated_vref = toa_vref + 10; + target[i_roc][i_link] = (calculated_vref > 255) ? 255 : calculated_vref; + links_found_count++; + pflib_log(info) + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << target[i_roc][i_link] + << ")"; + } + } } - pflib_log(trace) << "got link efficiencies"; + } + + if (!scan_all && links_found_count == total_links_to_find) { + pflib_log(info) << "All links found their threshold early. Breaking VREF loop at " << toa_vref; + break; } } + pflib_log(info) << "sample collections done, deducing settings"; + // get the max toa_vref with non-zero efficiency? Iterate through the array // from bottom up. - for (int i_roc : tgt->roc_ids()) { - for (int i_link{0}; i_link < 2; i_link++) { - int highest_non_zero_eff = - -1; // just a placeholder in case it's not found - for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; - toa_vref--) { - if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { - pflib_log(trace) - << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc - << " Link " << i_link << ". Initial val at max VREF: " - << final_effs[i_roc][i_link][toa_vref]; + + if (scan_all) { + for (int i_roc : tgt->roc_ids()) { + for (int i_link{0}; i_link < 2; i_link++) { + int highest_non_zero_eff = -1; // just a placeholder in case it's not found + for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; + toa_vref--) { + if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { + pflib_log(trace) + << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc + << " Link " << i_link << ". Initial val at max VREF: " + << final_effs[i_roc][i_link][toa_vref]; + } + + if (final_effs[i_roc][i_link][toa_vref] > 0.0) { + highest_non_zero_eff = + toa_vref + 10; // need to add 10 since we don't want to overlap + // with highest pedestals! + pflib_log(info) + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << highest_non_zero_eff + << ")"; + break; // should break from link 0 into link 1 + } } - if (final_effs[i_roc][i_link][toa_vref] > 0.0) { - highest_non_zero_eff = - toa_vref + 10; // need to add 10 since we don't want to overlap - // with highest pedestals! - pflib_log(info) - << "[DEBUG SEARCH] Success. Found threshold edge at VREF " - << toa_vref << " (Setting target to " << highest_non_zero_eff - << ")"; - break; // should break from link 0 into link 1 + if (highest_non_zero_eff < 0) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": no non-zero TOA efficiency found, skipping"; + continue; } - } - if (highest_non_zero_eff < 0) { - pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": no non-zero TOA efficiency found, skipping"; - continue; - } + if (highest_non_zero_eff > 255) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": deduced TOA_VREF " << highest_non_zero_eff + << " out of range, clamping to 255"; + highest_non_zero_eff = 255; + } - if (highest_non_zero_eff > 255) { - pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": deduced TOA_VREF " << highest_non_zero_eff - << " out of range, clamping to 255"; - highest_non_zero_eff = 255; + target[i_roc][i_link] = highest_non_zero_eff; // store value } - - target[i_roc][i_link] = highest_non_zero_eff; // store value + // toa_vref is a global parameter (1 value per link) } - // toa_vref is a global parameter (1 value per link) + } + for (int i_roc : tgt->roc_ids()) { for (int i_link{0}; i_link < 2; i_link++) { std::string page{ pflib::utility::string_format("REFERENCEVOLTAGE_%d", i_link)}; settings[i_roc][page]["TOA_VREF"] = target[i_roc][i_link]; } } + return settings; } diff --git a/app/tool/algorithm/toa_vref_scan.h b/app/tool/algorithm/toa_vref_scan.h index 2ccc6322d..bc4835715 100644 --- a/app/tool/algorithm/toa_vref_scan.h +++ b/app/tool/algorithm/toa_vref_scan.h @@ -16,6 +16,6 @@ namespace pflib::algorithm { * @note Only functional for single-ROC targets */ std::map>> -toa_vref_scan(Target* tgt); +toa_vref_scan(Target* tgt, bool scan_all = false); } // namespace pflib::algorithm diff --git a/app/tool/tasks/toa_vref_scan.cxx b/app/tool/tasks/toa_vref_scan.cxx index 1fe460d27..834767cbe 100644 --- a/app/tool/tasks/toa_vref_scan.cxx +++ b/app/tool/tasks/toa_vref_scan.cxx @@ -7,7 +7,9 @@ #include "../algorithm/toa_vref_scan.h" void toa_vref_scan(Target* tgt) { - auto settings = pflib::algorithm::toa_vref_scan(tgt); + + bool scan_all = pftool::readline_bool("Scan all VREF values?", false); + auto settings = pflib::algorithm::toa_vref_scan(tgt, scan_all); YAML::Emitter out; out << YAML::BeginMap; From 8b5db12757bf0ae5102fc0454313e124c679eed8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 7 Jul 2026 15:24:53 +0000 Subject: [PATCH 08/14] Apply clang-format --style=Google --- app/tool/algorithm/toa_vref_scan.cxx | 93 +++++++++++++++------------- app/tool/tasks/toa_vref_scan.cxx | 1 - 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index ab393789a..d6f5e5827 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -1,5 +1,6 @@ #include "toa_vref_scan.h" +#include #include #include "../daq_run.h" @@ -8,8 +9,6 @@ #include "pflib/utility/efficiency.h" #include "pflib/utility/string_format.h" #include "trim_toa_scan.h" -#include -#include namespace pflib::algorithm { @@ -17,41 +16,43 @@ std::map>> toa_vref_scan(Target* tgt, bool scan_all) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; -// Reading out the trim_toa values for the first 5 channels to test, Cristina's suggestion, bug fix this later -// if (!tgt->roc_ids().empty()) { -// int first_roc = *(tgt->roc_ids().begin()); -// pflib::ROC& my_roc = tgt->roc(first_roc); - -// bool needs_trim_scan = false; -// for (int i = 0; i < 5; i++) { -// std::string ch_str = "CH_" + std::to_string(i); -// auto channel_params = my_roc.getParameters(ch_str); - -// if (channel_params.find("TRIM_TOA") == channel_params.end()) { -// needs_trim_scan = true; -// break; -// } -// } - -// if (needs_trim_scan) { -// pflib_log(info) << "TRIM_TOA values missing. Running trim_toa_scan..."; -// trim_toa_scan(tgt, my_roc, first_roc); - -// for (int i = 0; i < 5; i++) { -// std::string ch_str = "CH_" + std::to_string(i); -// auto channel_params = my_roc.getParameters(ch_str); - -// auto it = channel_params.find("TRIM_TOA"); -// if (it != channel_params.end()) { -// pflib_log(info) << "TRIM_TOA for channel " << i << ": " << it->second; -// } else { -// pflib_log(info) << "TRIM_TOA not set for channel " << i; -// } -// } -// } else { -// pflib_log(error) << "No ROC IDs found."; -// } - + // Reading out the trim_toa values for the first 5 channels to test, + // Cristina's suggestion, bug fix this later + // if (!tgt->roc_ids().empty()) { + // int first_roc = *(tgt->roc_ids().begin()); + // pflib::ROC& my_roc = tgt->roc(first_roc); + + // bool needs_trim_scan = false; + // for (int i = 0; i < 5; i++) { + // std::string ch_str = "CH_" + std::to_string(i); + // auto channel_params = my_roc.getParameters(ch_str); + + // if (channel_params.find("TRIM_TOA") == channel_params.end()) { + // needs_trim_scan = true; + // break; + // } + // } + + // if (needs_trim_scan) { + // pflib_log(info) << "TRIM_TOA values missing. Running + // trim_toa_scan..."; + // trim_toa_scan(tgt, my_roc, first_roc); + + // for (int i = 0; i < 5; i++) { + // std::string ch_str = "CH_" + std::to_string(i); + // auto channel_params = my_roc.getParameters(ch_str); + + // auto it = channel_params.find("TRIM_TOA"); + // if (it != channel_params.end()) { + // pflib_log(info) << "TRIM_TOA for channel " << i << ": " << + // it->second; + // } else { + // pflib_log(info) << "TRIM_TOA not set for channel " << i; + // } + // } + // } else { + // pflib_log(error) << "No ROC IDs found."; + // } /// do a run of 100 samples per toa_vref to measure the TOA /// efficiency when looking at pedestal data @@ -83,7 +84,7 @@ toa_vref_scan(Target* tgt, bool scan_all) { } csv_file << "\n"; - // loop down from 255 to 0 + // loop down from 255 to 0 for (int toa_vref = 255; toa_vref >= 0; toa_vref--) { pflib_log(info) << "testing toa_vref = " << toa_vref; std::map> parameters; @@ -130,19 +131,22 @@ toa_vref_scan(Target* tgt, bool scan_all) { if (!scan_all) { if (target[i_roc][i_link] == -1 && max_eff > 0.0) { int calculated_vref = toa_vref + 10; - target[i_roc][i_link] = (calculated_vref > 255) ? 255 : calculated_vref; + target[i_roc][i_link] = + (calculated_vref > 255) ? 255 : calculated_vref; links_found_count++; pflib_log(info) - << "[DEBUG SEARCH] Success. Found threshold edge at VREF " - << toa_vref << " (Setting target to " << target[i_roc][i_link] - << ")"; + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << target[i_roc][i_link] + << ")"; } } } } if (!scan_all && links_found_count == total_links_to_find) { - pflib_log(info) << "All links found their threshold early. Breaking VREF loop at " << toa_vref; + pflib_log(info) + << "All links found their threshold early. Breaking VREF loop at " + << toa_vref; break; } } @@ -155,7 +159,8 @@ toa_vref_scan(Target* tgt, bool scan_all) { if (scan_all) { for (int i_roc : tgt->roc_ids()) { for (int i_link{0}; i_link < 2; i_link++) { - int highest_non_zero_eff = -1; // just a placeholder in case it's not found + int highest_non_zero_eff = + -1; // just a placeholder in case it's not found for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; toa_vref--) { if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { diff --git a/app/tool/tasks/toa_vref_scan.cxx b/app/tool/tasks/toa_vref_scan.cxx index 834767cbe..1a60e8fc9 100644 --- a/app/tool/tasks/toa_vref_scan.cxx +++ b/app/tool/tasks/toa_vref_scan.cxx @@ -7,7 +7,6 @@ #include "../algorithm/toa_vref_scan.h" void toa_vref_scan(Target* tgt) { - bool scan_all = pftool::readline_bool("Scan all VREF values?", false); auto settings = pflib::algorithm::toa_vref_scan(tgt, scan_all); From b9377a692b77789b850db9b3065c1f7fad1defdf Mon Sep 17 00:00:00 2001 From: haseckew Date: Wed, 15 Jul 2026 11:16:59 -0400 Subject: [PATCH 09/14] updated toa_efficiency.py and toa_vref_scan.cxx to support 6 rocs, cleaned up commented code, and fixed non-4 roc bug with toa_efficiency.py --- ana/toa/toa_efficiency.py | 16 +++++++++------- app/tool/algorithm/toa_vref_scan.cxx | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/ana/toa/toa_efficiency.py b/ana/toa/toa_efficiency.py index ea38e4f81..bb8a2535d 100644 --- a/ana/toa/toa_efficiency.py +++ b/ana/toa/toa_efficiency.py @@ -63,9 +63,10 @@ channel_lists.append(data[str(chan)].values) # Plotting the results +input_stem = Path(args.f).stem plt.figure(figsize=(10, 6)) for chan in range(72): - plt.plot(channel_lists[chan], + plt.plot(vref_axis, channel_lists[chan], marker = 'o', label=f'Ch. {chan}', linestyle='none') @@ -73,9 +74,10 @@ plt.xlabel('TOA VREF') plt.ylabel('TOA Efficiency') plt.tight_layout() -plt.savefig(f"toa_efficiency_plot_roc{args.roc}.png") -plt.show() -print(f"Plot saved as 'toa_efficiency_plot_roc{args.roc}.png'") +plot_filename = f"toa_efficiency_plot_{input_stem}_roc{args.roc}.png" +plt.savefig(plot_filename) +plt.close() +print(f"Plot saved as '{plot_filename}'") # Printing the values of highest non-zero TOA_VREF per link link0 = np.array(channel_lists[:36]).T @@ -93,8 +95,8 @@ print("Error: Efficiency data contains only zeros for one or both links.") sys.exit() -max_vref_l0 = vref_axis[link0_count[-1]] -max_vref_l1 = vref_axis[link1_count[-1]] +max_vref_l0 = data.loc[link0_count[-1], "TOA_VREF"] +max_vref_l1 = data.loc[link1_count[-1], "TOA_VREF"] optimal_vref_l0 = max_vref_l0 + 10 optimal_vref_l1 = max_vref_l1 + 10 @@ -118,7 +120,7 @@ 'TOA_VREF': int(row['max_toa']) } -yaml_filename = f"output_roc{args.roc}.yaml" +yaml_filename = f"output_{input_stem}_roc{args.roc}.yaml" with open(yaml_filename, "w") as f: yaml.dump(yaml_data, f, sort_keys=False) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index d6f5e5827..39866fb5f 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -9,6 +9,13 @@ #include "pflib/utility/efficiency.h" #include "pflib/utility/string_format.h" #include "trim_toa_scan.h" +<<<<<<< Updated upstream +======= +#include +#include +#include +#include +>>>>>>> Stashed changes namespace pflib::algorithm { @@ -77,8 +84,21 @@ toa_vref_scan(Target* tgt, bool scan_all) { DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; // create a .csv file to save efficiency and vref data for analysis +<<<<<<< Updated upstream std::ofstream csv_file("toa_vref_scan_data.csv"); csv_file << "TOA_VREF"; +======= + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + + std::stringstream ss; + ss << "toa_vref_scan_data_" << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; + std::string filename = ss.str(); + + std::ofstream csv_file(filename); + pflib_log(info) << "Saving scan data to file: " << filename; + csv_file << "TOA_VREF,ROC"; +>>>>>>> Stashed changes for (int chan = 0; chan < 72; ++chan) { csv_file << "," << chan; } From e4b77af8f1ba36a8e21b43c50533b3b0c28db994 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 Jul 2026 15:18:27 +0000 Subject: [PATCH 10/14] Apply clang-format --style=Google --- app/tool/algorithm/toa_vref_scan.cxx | 354 ++++++++++++++------------- 1 file changed, 178 insertions(+), 176 deletions(-) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index 39866fb5f..b97268a75 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -15,221 +15,223 @@ #include #include #include ->>>>>>> Stashed changes + >>>>>>> Stashed changes + + namespace pflib::algorithm { -namespace pflib::algorithm { - -std::map>> -toa_vref_scan(Target* tgt, bool scan_all) { - static auto the_log_{::pflib::logging::get("toa_vref_scan")}; - - // Reading out the trim_toa values for the first 5 channels to test, - // Cristina's suggestion, bug fix this later - // if (!tgt->roc_ids().empty()) { - // int first_roc = *(tgt->roc_ids().begin()); - // pflib::ROC& my_roc = tgt->roc(first_roc); - - // bool needs_trim_scan = false; - // for (int i = 0; i < 5; i++) { - // std::string ch_str = "CH_" + std::to_string(i); - // auto channel_params = my_roc.getParameters(ch_str); - - // if (channel_params.find("TRIM_TOA") == channel_params.end()) { - // needs_trim_scan = true; - // break; - // } - // } - - // if (needs_trim_scan) { - // pflib_log(info) << "TRIM_TOA values missing. Running - // trim_toa_scan..."; - // trim_toa_scan(tgt, my_roc, first_roc); - - // for (int i = 0; i < 5; i++) { - // std::string ch_str = "CH_" + std::to_string(i); - // auto channel_params = my_roc.getParameters(ch_str); - - // auto it = channel_params.find("TRIM_TOA"); - // if (it != channel_params.end()) { - // pflib_log(info) << "TRIM_TOA for channel " << i << ": " << - // it->second; - // } else { - // pflib_log(info) << "TRIM_TOA not set for channel " << i; - // } - // } - // } else { - // pflib_log(error) << "No ROC IDs found."; - // } - - /// do a run of 100 samples per toa_vref to measure the TOA - /// efficiency when looking at pedestal data - - static const std::size_t n_events = 100; - - tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); - - std::map> target; // i_roc int for each variable - std::map, 2>> final_effs; std::map>> - settings; + toa_vref_scan(Target * tgt, bool scan_all) { + static auto the_log_{::pflib::logging::get("toa_vref_scan")}; + + // Reading out the trim_toa values for the first 5 channels to test, + // Cristina's suggestion, bug fix this later + // if (!tgt->roc_ids().empty()) { + // int first_roc = *(tgt->roc_ids().begin()); + // pflib::ROC& my_roc = tgt->roc(first_roc); + + // bool needs_trim_scan = false; + // for (int i = 0; i < 5; i++) { + // std::string ch_str = "CH_" + std::to_string(i); + // auto channel_params = my_roc.getParameters(ch_str); + + // if (channel_params.find("TRIM_TOA") == channel_params.end()) { + // needs_trim_scan = true; + // break; + // } + // } + + // if (needs_trim_scan) { + // pflib_log(info) << "TRIM_TOA values missing. Running + // trim_toa_scan..."; + // trim_toa_scan(tgt, my_roc, first_roc); + + // for (int i = 0; i < 5; i++) { + // std::string ch_str = "CH_" + std::to_string(i); + // auto channel_params = my_roc.getParameters(ch_str); + + // auto it = channel_params.find("TRIM_TOA"); + // if (it != channel_params.end()) { + // pflib_log(info) << "TRIM_TOA for channel " << i << ": " << + // it->second; + // } else { + // pflib_log(info) << "TRIM_TOA not set for channel " << i; + // } + // } + // } else { + // pflib_log(error) << "No ROC IDs found."; + // } + + /// do a run of 100 samples per toa_vref to measure the TOA + /// efficiency when looking at pedestal data + + static const std::size_t n_events = 100; + + tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); + + std::map> target; // i_roc int for each variable + std::map, 2>> final_effs; + std::map>> + settings; - for (int i_roc : tgt->roc_ids()) { - target[i_roc][0] = -1; - target[i_roc][1] = -1; - } + for (int i_roc : tgt->roc_ids()) { + target[i_roc][0] = -1; + target[i_roc][1] = -1; + } - size_t total_links_to_find = tgt->roc_ids().size() * 2; - size_t links_found_count = 0; + size_t total_links_to_find = tgt->roc_ids().size() * 2; + size_t links_found_count = 0; - DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; + DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; - // create a .csv file to save efficiency and vref data for analysis + // create a .csv file to save efficiency and vref data for analysis <<<<<<< Updated upstream - std::ofstream csv_file("toa_vref_scan_data.csv"); - csv_file << "TOA_VREF"; + std::ofstream csv_file("toa_vref_scan_data.csv"); + csv_file << "TOA_VREF"; ======= - auto now = std::chrono::system_clock::now(); - auto in_time_t = std::chrono::system_clock::to_time_t(now); + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); - std::stringstream ss; - ss << "toa_vref_scan_data_" << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; - std::string filename = ss.str(); + std::stringstream ss; + ss << "toa_vref_scan_data_" + << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; + std::string filename = ss.str(); - std::ofstream csv_file(filename); - pflib_log(info) << "Saving scan data to file: " << filename; - csv_file << "TOA_VREF,ROC"; + std::ofstream csv_file(filename); + pflib_log(info) << "Saving scan data to file: " << filename; + csv_file << "TOA_VREF,ROC"; >>>>>>> Stashed changes - for (int chan = 0; chan < 72; ++chan) { - csv_file << "," << chan; - } - csv_file << "\n"; + for (int chan = 0; chan < 72; ++chan) { + csv_file << "," << chan; + } + csv_file << "\n"; - // loop down from 255 to 0 - for (int toa_vref = 255; toa_vref >= 0; toa_vref--) { - pflib_log(info) << "testing toa_vref = " << toa_vref; - std::map> parameters; - parameters["REFERENCEVOLTAGE_0"]["TOA_VREF"] = toa_vref; - parameters["REFERENCEVOLTAGE_1"]["TOA_VREF"] = toa_vref; - auto test_params = tgt->tempApplyAllROCs(parameters); + // loop down from 255 to 0 + for (int toa_vref = 255; toa_vref >= 0; toa_vref--) { + pflib_log(info) << "testing toa_vref = " << toa_vref; + std::map> parameters; + parameters["REFERENCEVOLTAGE_0"]["TOA_VREF"] = toa_vref; + parameters["REFERENCEVOLTAGE_1"]["TOA_VREF"] = toa_vref; + auto test_params = tgt->tempApplyAllROCs(parameters); - usleep(10); + usleep(10); - daq_run(tgt, "PEDESTAL", buffer, n_events, 100); + daq_run(tgt, "PEDESTAL", buffer, n_events, 100); - pflib_log(trace) << "finished toa_vref = " << toa_vref - << ", getting efficiencies"; + pflib_log(trace) << "finished toa_vref = " << toa_vref + << ", getting efficiencies"; - for (int i_roc : tgt->roc_ids()) { - const auto& mapping = tgt->getRocErxMapping(); + for (int i_roc : tgt->roc_ids()) { + const auto& mapping = tgt->getRocErxMapping(); - auto efficiencies = - get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); - pflib_log(trace) << "got channel efficiencies for ROC " << i_roc - << ", getting max efficiency per link"; + auto efficiencies = + get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); + pflib_log(trace) << "got channel efficiencies for ROC " << i_roc + << ", getting max efficiency per link"; - // Save raw channel efficiencies to .csv file - csv_file << toa_vref; - for (double eff : efficiencies) { - csv_file << "," << eff; - } - csv_file << "\n"; + // Save raw channel efficiencies to .csv file + csv_file << toa_vref; + for (double eff : efficiencies) { + csv_file << "," << eff; + } + csv_file << "\n"; - for (int i_link{0}; i_link < 2; i_link++) { - auto start = efficiencies.begin() + 36 * i_link; - auto end = start + 36; + for (int i_link{0}; i_link < 2; i_link++) { + auto start = efficiencies.begin() + 36 * i_link; + auto end = start + 36; - double max_eff = *std::max_element(start, end); + double max_eff = *std::max_element(start, end); - final_effs[i_roc][i_link][toa_vref] = max_eff; + final_effs[i_roc][i_link][toa_vref] = max_eff; - if (toa_vref % 32 == 0 || max_eff > 0.0) { - pflib_log(trace) << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " - << i_roc << " Link " << i_link - << " | Max Efficiency: " << max_eff; - } + if (toa_vref % 32 == 0 || max_eff > 0.0) { + pflib_log(trace) + << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " << i_roc + << " Link " << i_link << " | Max Efficiency: " << max_eff; + } - if (!scan_all) { - if (target[i_roc][i_link] == -1 && max_eff > 0.0) { - int calculated_vref = toa_vref + 10; - target[i_roc][i_link] = - (calculated_vref > 255) ? 255 : calculated_vref; - links_found_count++; - pflib_log(info) - << "[DEBUG SEARCH] Success. Found threshold edge at VREF " - << toa_vref << " (Setting target to " << target[i_roc][i_link] - << ")"; + if (!scan_all) { + if (target[i_roc][i_link] == -1 && max_eff > 0.0) { + int calculated_vref = toa_vref + 10; + target[i_roc][i_link] = + (calculated_vref > 255) ? 255 : calculated_vref; + links_found_count++; + pflib_log(info) + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << target[i_roc][i_link] + << ")"; + } } } } - } - if (!scan_all && links_found_count == total_links_to_find) { - pflib_log(info) - << "All links found their threshold early. Breaking VREF loop at " - << toa_vref; - break; + if (!scan_all && links_found_count == total_links_to_find) { + pflib_log(info) + << "All links found their threshold early. Breaking VREF loop at " + << toa_vref; + break; + } } - } - - pflib_log(info) << "sample collections done, deducing settings"; - // get the max toa_vref with non-zero efficiency? Iterate through the array - // from bottom up. - - if (scan_all) { - for (int i_roc : tgt->roc_ids()) { - for (int i_link{0}; i_link < 2; i_link++) { - int highest_non_zero_eff = - -1; // just a placeholder in case it's not found - for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; - toa_vref--) { - if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { - pflib_log(trace) - << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc - << " Link " << i_link << ". Initial val at max VREF: " - << final_effs[i_roc][i_link][toa_vref]; + pflib_log(info) << "sample collections done, deducing settings"; + + // get the max toa_vref with non-zero efficiency? Iterate through the array + // from bottom up. + + if (scan_all) { + for (int i_roc : tgt->roc_ids()) { + for (int i_link{0}; i_link < 2; i_link++) { + int highest_non_zero_eff = + -1; // just a placeholder in case it's not found + for (int toa_vref = final_effs[i_roc][i_link].size() - 1; + toa_vref >= 0; toa_vref--) { + if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { + pflib_log(trace) + << "[DEBUG SEARCH] Starting backwards search for ROC " + << i_roc << " Link " << i_link + << ". Initial val at max VREF: " + << final_effs[i_roc][i_link][toa_vref]; + } + + if (final_effs[i_roc][i_link][toa_vref] > 0.0) { + highest_non_zero_eff = + toa_vref + 10; // need to add 10 since we don't want to + // overlap with highest pedestals! + pflib_log(info) + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << highest_non_zero_eff + << ")"; + break; // should break from link 0 into link 1 + } } - if (final_effs[i_roc][i_link][toa_vref] > 0.0) { - highest_non_zero_eff = - toa_vref + 10; // need to add 10 since we don't want to overlap - // with highest pedestals! - pflib_log(info) - << "[DEBUG SEARCH] Success. Found threshold edge at VREF " - << toa_vref << " (Setting target to " << highest_non_zero_eff - << ")"; - break; // should break from link 0 into link 1 + if (highest_non_zero_eff < 0) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": no non-zero TOA efficiency found, skipping"; + continue; } - } - if (highest_non_zero_eff < 0) { - pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": no non-zero TOA efficiency found, skipping"; - continue; - } + if (highest_non_zero_eff > 255) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": deduced TOA_VREF " << highest_non_zero_eff + << " out of range, clamping to 255"; + highest_non_zero_eff = 255; + } - if (highest_non_zero_eff > 255) { - pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": deduced TOA_VREF " << highest_non_zero_eff - << " out of range, clamping to 255"; - highest_non_zero_eff = 255; + target[i_roc][i_link] = highest_non_zero_eff; // store value } - - target[i_roc][i_link] = highest_non_zero_eff; // store value + // toa_vref is a global parameter (1 value per link) } - // toa_vref is a global parameter (1 value per link) } - } - for (int i_roc : tgt->roc_ids()) { - for (int i_link{0}; i_link < 2; i_link++) { - std::string page{ - pflib::utility::string_format("REFERENCEVOLTAGE_%d", i_link)}; - settings[i_roc][page]["TOA_VREF"] = target[i_roc][i_link]; + for (int i_roc : tgt->roc_ids()) { + for (int i_link{0}; i_link < 2; i_link++) { + std::string page{ + pflib::utility::string_format("REFERENCEVOLTAGE_%d", i_link)}; + settings[i_roc][page]["TOA_VREF"] = target[i_roc][i_link]; + } } - } - return settings; -} + return settings; + } } // namespace pflib::algorithm From 1a08d7aa12e93fb3c55c339c8b2b808bae3cac8b Mon Sep 17 00:00:00 2001 From: haseckew Date: Wed, 15 Jul 2026 11:59:19 -0400 Subject: [PATCH 11/14] fixed merge conflicts from previous merge --- app/tool/algorithm/toa_vref_scan.cxx | 53 ++-------------------------- 1 file changed, 2 insertions(+), 51 deletions(-) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index b97268a75..9bf9d1649 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -9,61 +9,17 @@ #include "pflib/utility/efficiency.h" #include "pflib/utility/string_format.h" #include "trim_toa_scan.h" -<<<<<<< Updated upstream -======= -#include #include #include #include - >>>>>>> Stashed changes - namespace pflib::algorithm { + + namespace pflib::algorithm { std::map>> toa_vref_scan(Target * tgt, bool scan_all) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; - // Reading out the trim_toa values for the first 5 channels to test, - // Cristina's suggestion, bug fix this later - // if (!tgt->roc_ids().empty()) { - // int first_roc = *(tgt->roc_ids().begin()); - // pflib::ROC& my_roc = tgt->roc(first_roc); - - // bool needs_trim_scan = false; - // for (int i = 0; i < 5; i++) { - // std::string ch_str = "CH_" + std::to_string(i); - // auto channel_params = my_roc.getParameters(ch_str); - - // if (channel_params.find("TRIM_TOA") == channel_params.end()) { - // needs_trim_scan = true; - // break; - // } - // } - - // if (needs_trim_scan) { - // pflib_log(info) << "TRIM_TOA values missing. Running - // trim_toa_scan..."; - // trim_toa_scan(tgt, my_roc, first_roc); - - // for (int i = 0; i < 5; i++) { - // std::string ch_str = "CH_" + std::to_string(i); - // auto channel_params = my_roc.getParameters(ch_str); - - // auto it = channel_params.find("TRIM_TOA"); - // if (it != channel_params.end()) { - // pflib_log(info) << "TRIM_TOA for channel " << i << ": " << - // it->second; - // } else { - // pflib_log(info) << "TRIM_TOA not set for channel " << i; - // } - // } - // } else { - // pflib_log(error) << "No ROC IDs found."; - // } - - /// do a run of 100 samples per toa_vref to measure the TOA - /// efficiency when looking at pedestal data - static const std::size_t n_events = 100; tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); @@ -84,10 +40,6 @@ DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; // create a .csv file to save efficiency and vref data for analysis -<<<<<<< Updated upstream - std::ofstream csv_file("toa_vref_scan_data.csv"); - csv_file << "TOA_VREF"; -======= auto now = std::chrono::system_clock::now(); auto in_time_t = std::chrono::system_clock::to_time_t(now); @@ -99,7 +51,6 @@ std::ofstream csv_file(filename); pflib_log(info) << "Saving scan data to file: " << filename; csv_file << "TOA_VREF,ROC"; ->>>>>>> Stashed changes for (int chan = 0; chan < 72; ++chan) { csv_file << "," << chan; } From 20a2be946f58d939cba805c4c474fb7c72e5e8f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 Jul 2026 16:00:52 +0000 Subject: [PATCH 12/14] Apply clang-format --style=Google --- app/tool/algorithm/toa_vref_scan.cxx | 268 +++++++++++++-------------- 1 file changed, 133 insertions(+), 135 deletions(-) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index 9bf9d1649..389884d9b 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -1,7 +1,10 @@ #include "toa_vref_scan.h" #include +#include #include +#include +#include #include "../daq_run.h" #include "../tasks/toa_vref_scan.h" @@ -9,180 +12,175 @@ #include "pflib/utility/efficiency.h" #include "pflib/utility/string_format.h" #include "trim_toa_scan.h" -#include -#include -#include - - namespace pflib::algorithm { +namespace pflib::algorithm { - std::map>> - toa_vref_scan(Target * tgt, bool scan_all) { - static auto the_log_{::pflib::logging::get("toa_vref_scan")}; +std::map>> +toa_vref_scan(Target* tgt, bool scan_all) { + static auto the_log_{::pflib::logging::get("toa_vref_scan")}; - static const std::size_t n_events = 100; + static const std::size_t n_events = 100; - tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); + tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); - std::map> target; // i_roc int for each variable - std::map, 2>> final_effs; - std::map>> - settings; + std::map> target; // i_roc int for each variable + std::map, 2>> final_effs; + std::map>> + settings; - for (int i_roc : tgt->roc_ids()) { - target[i_roc][0] = -1; - target[i_roc][1] = -1; - } + for (int i_roc : tgt->roc_ids()) { + target[i_roc][0] = -1; + target[i_roc][1] = -1; + } - size_t total_links_to_find = tgt->roc_ids().size() * 2; - size_t links_found_count = 0; + size_t total_links_to_find = tgt->roc_ids().size() * 2; + size_t links_found_count = 0; - DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; + DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; - // create a .csv file to save efficiency and vref data for analysis - auto now = std::chrono::system_clock::now(); - auto in_time_t = std::chrono::system_clock::to_time_t(now); + // create a .csv file to save efficiency and vref data for analysis + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); - std::stringstream ss; - ss << "toa_vref_scan_data_" - << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; - std::string filename = ss.str(); + std::stringstream ss; + ss << "toa_vref_scan_data_" + << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; + std::string filename = ss.str(); - std::ofstream csv_file(filename); - pflib_log(info) << "Saving scan data to file: " << filename; - csv_file << "TOA_VREF,ROC"; - for (int chan = 0; chan < 72; ++chan) { - csv_file << "," << chan; - } - csv_file << "\n"; + std::ofstream csv_file(filename); + pflib_log(info) << "Saving scan data to file: " << filename; + csv_file << "TOA_VREF,ROC"; + for (int chan = 0; chan < 72; ++chan) { + csv_file << "," << chan; + } + csv_file << "\n"; - // loop down from 255 to 0 - for (int toa_vref = 255; toa_vref >= 0; toa_vref--) { - pflib_log(info) << "testing toa_vref = " << toa_vref; - std::map> parameters; - parameters["REFERENCEVOLTAGE_0"]["TOA_VREF"] = toa_vref; - parameters["REFERENCEVOLTAGE_1"]["TOA_VREF"] = toa_vref; - auto test_params = tgt->tempApplyAllROCs(parameters); + // loop down from 255 to 0 + for (int toa_vref = 255; toa_vref >= 0; toa_vref--) { + pflib_log(info) << "testing toa_vref = " << toa_vref; + std::map> parameters; + parameters["REFERENCEVOLTAGE_0"]["TOA_VREF"] = toa_vref; + parameters["REFERENCEVOLTAGE_1"]["TOA_VREF"] = toa_vref; + auto test_params = tgt->tempApplyAllROCs(parameters); - usleep(10); + usleep(10); - daq_run(tgt, "PEDESTAL", buffer, n_events, 100); + daq_run(tgt, "PEDESTAL", buffer, n_events, 100); - pflib_log(trace) << "finished toa_vref = " << toa_vref - << ", getting efficiencies"; + pflib_log(trace) << "finished toa_vref = " << toa_vref + << ", getting efficiencies"; - for (int i_roc : tgt->roc_ids()) { - const auto& mapping = tgt->getRocErxMapping(); + for (int i_roc : tgt->roc_ids()) { + const auto& mapping = tgt->getRocErxMapping(); - auto efficiencies = - get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); - pflib_log(trace) << "got channel efficiencies for ROC " << i_roc - << ", getting max efficiency per link"; + auto efficiencies = + get_toa_efficiencies(i_roc, mapping, buffer.get_buffer()); + pflib_log(trace) << "got channel efficiencies for ROC " << i_roc + << ", getting max efficiency per link"; - // Save raw channel efficiencies to .csv file - csv_file << toa_vref; - for (double eff : efficiencies) { - csv_file << "," << eff; - } - csv_file << "\n"; + // Save raw channel efficiencies to .csv file + csv_file << toa_vref; + for (double eff : efficiencies) { + csv_file << "," << eff; + } + csv_file << "\n"; - for (int i_link{0}; i_link < 2; i_link++) { - auto start = efficiencies.begin() + 36 * i_link; - auto end = start + 36; + for (int i_link{0}; i_link < 2; i_link++) { + auto start = efficiencies.begin() + 36 * i_link; + auto end = start + 36; - double max_eff = *std::max_element(start, end); + double max_eff = *std::max_element(start, end); - final_effs[i_roc][i_link][toa_vref] = max_eff; + final_effs[i_roc][i_link][toa_vref] = max_eff; - if (toa_vref % 32 == 0 || max_eff > 0.0) { - pflib_log(trace) - << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " << i_roc - << " Link " << i_link << " | Max Efficiency: " << max_eff; - } + if (toa_vref % 32 == 0 || max_eff > 0.0) { + pflib_log(trace) << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " + << i_roc << " Link " << i_link + << " | Max Efficiency: " << max_eff; + } - if (!scan_all) { - if (target[i_roc][i_link] == -1 && max_eff > 0.0) { - int calculated_vref = toa_vref + 10; - target[i_roc][i_link] = - (calculated_vref > 255) ? 255 : calculated_vref; - links_found_count++; - pflib_log(info) - << "[DEBUG SEARCH] Success. Found threshold edge at VREF " - << toa_vref << " (Setting target to " << target[i_roc][i_link] - << ")"; - } + if (!scan_all) { + if (target[i_roc][i_link] == -1 && max_eff > 0.0) { + int calculated_vref = toa_vref + 10; + target[i_roc][i_link] = + (calculated_vref > 255) ? 255 : calculated_vref; + links_found_count++; + pflib_log(info) + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << target[i_roc][i_link] + << ")"; } } } + } - if (!scan_all && links_found_count == total_links_to_find) { - pflib_log(info) - << "All links found their threshold early. Breaking VREF loop at " - << toa_vref; - break; - } + if (!scan_all && links_found_count == total_links_to_find) { + pflib_log(info) + << "All links found their threshold early. Breaking VREF loop at " + << toa_vref; + break; } + } - pflib_log(info) << "sample collections done, deducing settings"; - - // get the max toa_vref with non-zero efficiency? Iterate through the array - // from bottom up. - - if (scan_all) { - for (int i_roc : tgt->roc_ids()) { - for (int i_link{0}; i_link < 2; i_link++) { - int highest_non_zero_eff = - -1; // just a placeholder in case it's not found - for (int toa_vref = final_effs[i_roc][i_link].size() - 1; - toa_vref >= 0; toa_vref--) { - if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { - pflib_log(trace) - << "[DEBUG SEARCH] Starting backwards search for ROC " - << i_roc << " Link " << i_link - << ". Initial val at max VREF: " - << final_effs[i_roc][i_link][toa_vref]; - } - - if (final_effs[i_roc][i_link][toa_vref] > 0.0) { - highest_non_zero_eff = - toa_vref + 10; // need to add 10 since we don't want to - // overlap with highest pedestals! - pflib_log(info) - << "[DEBUG SEARCH] Success. Found threshold edge at VREF " - << toa_vref << " (Setting target to " << highest_non_zero_eff - << ")"; - break; // should break from link 0 into link 1 - } - } + pflib_log(info) << "sample collections done, deducing settings"; - if (highest_non_zero_eff < 0) { - pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": no non-zero TOA efficiency found, skipping"; - continue; + // get the max toa_vref with non-zero efficiency? Iterate through the array + // from bottom up. + + if (scan_all) { + for (int i_roc : tgt->roc_ids()) { + for (int i_link{0}; i_link < 2; i_link++) { + int highest_non_zero_eff = + -1; // just a placeholder in case it's not found + for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; + toa_vref--) { + if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { + pflib_log(trace) + << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc + << " Link " << i_link << ". Initial val at max VREF: " + << final_effs[i_roc][i_link][toa_vref]; } - if (highest_non_zero_eff > 255) { - pflib_log(warn) << "ROC " << i_roc << " link " << i_link - << ": deduced TOA_VREF " << highest_non_zero_eff - << " out of range, clamping to 255"; - highest_non_zero_eff = 255; + if (final_effs[i_roc][i_link][toa_vref] > 0.0) { + highest_non_zero_eff = + toa_vref + 10; // need to add 10 since we don't want to + // overlap with highest pedestals! + pflib_log(info) + << "[DEBUG SEARCH] Success. Found threshold edge at VREF " + << toa_vref << " (Setting target to " << highest_non_zero_eff + << ")"; + break; // should break from link 0 into link 1 } + } - target[i_roc][i_link] = highest_non_zero_eff; // store value + if (highest_non_zero_eff < 0) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": no non-zero TOA efficiency found, skipping"; + continue; } - // toa_vref is a global parameter (1 value per link) - } - } - for (int i_roc : tgt->roc_ids()) { - for (int i_link{0}; i_link < 2; i_link++) { - std::string page{ - pflib::utility::string_format("REFERENCEVOLTAGE_%d", i_link)}; - settings[i_roc][page]["TOA_VREF"] = target[i_roc][i_link]; + if (highest_non_zero_eff > 255) { + pflib_log(warn) << "ROC " << i_roc << " link " << i_link + << ": deduced TOA_VREF " << highest_non_zero_eff + << " out of range, clamping to 255"; + highest_non_zero_eff = 255; + } + + target[i_roc][i_link] = highest_non_zero_eff; // store value } + // toa_vref is a global parameter (1 value per link) } + } - return settings; + for (int i_roc : tgt->roc_ids()) { + for (int i_link{0}; i_link < 2; i_link++) { + std::string page{ + pflib::utility::string_format("REFERENCEVOLTAGE_%d", i_link)}; + settings[i_roc][page]["TOA_VREF"] = target[i_roc][i_link]; + } } + return settings; +} + } // namespace pflib::algorithm From 3ce251d168eb7e7539149a40346c54996e9c5c9c Mon Sep 17 00:00:00 2001 From: haseckew Date: Thu, 16 Jul 2026 11:57:32 -0400 Subject: [PATCH 13/14] more flexibility in file creation and general improvements --- ana/toa/toa_efficiency.py | 17 +++++-- app/tool/algorithm/toa_vref_scan.cxx | 70 +++++++++++++++++----------- app/tool/algorithm/toa_vref_scan.h | 2 +- app/tool/tasks/toa_vref_scan.cxx | 9 +++- 4 files changed, 65 insertions(+), 33 deletions(-) diff --git a/ana/toa/toa_efficiency.py b/ana/toa/toa_efficiency.py index bb8a2535d..f644e5c27 100644 --- a/ana/toa/toa_efficiency.py +++ b/ana/toa/toa_efficiency.py @@ -20,7 +20,7 @@ description='takes a csv from tasks.toa_vref_scan and outputs a plot of TOA efficiency per channel against TOA VREF values' ) parser.add_argument('-f', required = True, help='csv file containing scan from tasks.toa_vref_scan') -parser.add_argument('-r', '--roc', type = int, choices = [0, 1, 2, 3], required = True, help = 'ROC index to filter data (e.g., 0, 1, 2, 3)') +parser.add_argument('-r', '--roc', type = int, choices = [0, 1, 2, 3, 4, 5], required = True, help = 'ROC index to filter data (e.g., 0, 1, 2, 3, 4, 5)') args = parser.parse_args() if not os.path.isfile(args.f): @@ -29,9 +29,20 @@ if not args.f.lower().endswith('csv'): print(args.f + ' is not a csv file') sys.exit() + data, head = read_pflib_csv(args.f) -data = data.iloc[args.roc::4].copy() +data.columns = data.columns.str.strip() + +if 'ROC' not in data.columns: + print("Error: 'ROC' column missing from CSV header. Please make sure you are using the updated C++ code.") + sys.exit() + +data = data[data['ROC'] == args.roc].copy() + +if data.empty: + print(f"Error: No scan data found for ROC {args.roc} in '{args.f}'. Was this ROC active during the run?") + sys.exit() data = data.sort_values(by='TOA_VREF').reset_index(drop = True) print(f"Extracted {len(data)} voltage points for ROC {args.roc}") @@ -70,7 +81,7 @@ marker = 'o', label=f'Ch. {chan}', linestyle='none') -plt.title('TOA Efficiency vs TOA VREF per channel') +plt.title(f'TOA Efficiency vs TOA VREF per channel for ROC: {args.roc}') plt.xlabel('TOA VREF') plt.ylabel('TOA Efficiency') plt.tight_layout() diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index 389884d9b..e72c3f145 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -16,7 +16,7 @@ namespace pflib::algorithm { std::map>> -toa_vref_scan(Target* tgt, bool scan_all) { +toa_vref_scan(Target * tgt, bool scan_all, bool write_csv, const std::string& csv_filepath) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; static const std::size_t n_events = 100; @@ -39,21 +39,32 @@ toa_vref_scan(Target* tgt, bool scan_all) { DecodeAndBuffer buffer{n_events, tgt->nrocs() * 2}; // create a .csv file to save efficiency and vref data for analysis - auto now = std::chrono::system_clock::now(); - auto in_time_t = std::chrono::system_clock::to_time_t(now); - - std::stringstream ss; - ss << "toa_vref_scan_data_" - << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; - std::string filename = ss.str(); - - std::ofstream csv_file(filename); - pflib_log(info) << "Saving scan data to file: " << filename; - csv_file << "TOA_VREF,ROC"; - for (int chan = 0; chan < 72; ++chan) { - csv_file << "," << chan; + std::ofstream csv_file; + + if (write_csv) { + std::string final_path = csv_filepath; + + if (final_path.empty()) { + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + std::stringstream ss; + ss << "toa_vref_scan_data_" << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; + final_path = ss.str(); + } + + csv_file.open(final_path); + if (!csv_file) { + pflib_log(error) << "Failed to open CSV file for writing: " << final_path; + write_csv = false; + } else { + pflib_log(info) << "Saving scan data to file: " << final_path; + csv_file << "TOA_VREF, ROC"; + for (int chan = 0; chan < 72; ++chan) { + csv_file << "," << chan; + } + csv_file << "\n"; + } } - csv_file << "\n"; // loop down from 255 to 0 for (int toa_vref = 255; toa_vref >= 0; toa_vref--) { @@ -79,11 +90,13 @@ toa_vref_scan(Target* tgt, bool scan_all) { << ", getting max efficiency per link"; // Save raw channel efficiencies to .csv file - csv_file << toa_vref; - for (double eff : efficiencies) { - csv_file << "," << eff; + if (write_csv) { + csv_file << toa_vref << "," << i_roc; + for (double eff : efficiencies) { + csv_file << "," << eff; + } + csv_file << "\n"; } - csv_file << "\n"; for (int i_link{0}; i_link < 2; i_link++) { auto start = efficiencies.begin() + 36 * i_link; @@ -94,11 +107,12 @@ toa_vref_scan(Target* tgt, bool scan_all) { final_effs[i_roc][i_link][toa_vref] = max_eff; if (toa_vref % 32 == 0 || max_eff > 0.0) { - pflib_log(trace) << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " - << i_roc << " Link " << i_link - << " | Max Efficiency: " << max_eff; + pflib_log(trace) + << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " << i_roc + << " Link " << i_link << " | Max Efficiency: " << max_eff; } + // iterating from 255 down, find the first non-zero efficiency for each link in each roc if (!scan_all) { if (target[i_roc][i_link] == -1 && max_eff > 0.0) { int calculated_vref = toa_vref + 10; @@ -124,20 +138,20 @@ toa_vref_scan(Target* tgt, bool scan_all) { pflib_log(info) << "sample collections done, deducing settings"; - // get the max toa_vref with non-zero efficiency? Iterate through the array - // from bottom up. + // get the max toa_vref with non-zero efficiency? Iterate through the array from top down. if (scan_all) { for (int i_roc : tgt->roc_ids()) { for (int i_link{0}; i_link < 2; i_link++) { int highest_non_zero_eff = -1; // just a placeholder in case it's not found - for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; - toa_vref--) { + for (int toa_vref = final_effs[i_roc][i_link].size() - 1; + toa_vref >= 0; toa_vref--) { if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { pflib_log(trace) - << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc - << " Link " << i_link << ". Initial val at max VREF: " + << "[DEBUG SEARCH] Starting backwards search for ROC " + << i_roc << " Link " << i_link + << ". Initial val at max VREF: " << final_effs[i_roc][i_link][toa_vref]; } diff --git a/app/tool/algorithm/toa_vref_scan.h b/app/tool/algorithm/toa_vref_scan.h index bc4835715..dee7c59c6 100644 --- a/app/tool/algorithm/toa_vref_scan.h +++ b/app/tool/algorithm/toa_vref_scan.h @@ -16,6 +16,6 @@ namespace pflib::algorithm { * @note Only functional for single-ROC targets */ std::map>> -toa_vref_scan(Target* tgt, bool scan_all = false); +toa_vref_scan(Target* tgt, bool scan_all = false, bool write_csv = false, const std::string& csv_filepath = ""); } // namespace pflib::algorithm diff --git a/app/tool/tasks/toa_vref_scan.cxx b/app/tool/tasks/toa_vref_scan.cxx index 1a60e8fc9..9f783c39d 100644 --- a/app/tool/tasks/toa_vref_scan.cxx +++ b/app/tool/tasks/toa_vref_scan.cxx @@ -8,7 +8,14 @@ void toa_vref_scan(Target* tgt) { bool scan_all = pftool::readline_bool("Scan all VREF values?", false); - auto settings = pflib::algorithm::toa_vref_scan(tgt, scan_all); + + bool write_csv = pftool::readline_bool("Save raw scan data to a CSV file?", true); + std::string csv_path = ""; + if (write_csv) { + csv_path = pftool::readline_path("toa-vref-scan-data", ".csv"); + } + + auto settings = pflib::algorithm::toa_vref_scan(tgt, scan_all, write_csv, csv_path); YAML::Emitter out; out << YAML::BeginMap; From b8aaef824cc1dbae6f842eebfd6d792bfbeb5073 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 Jul 2026 16:13:19 +0000 Subject: [PATCH 14/14] Apply clang-format --style=Google --- app/tool/algorithm/toa_vref_scan.cxx | 28 ++++++++++++++++------------ app/tool/algorithm/toa_vref_scan.h | 3 ++- app/tool/tasks/toa_vref_scan.cxx | 6 ++++-- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/app/tool/algorithm/toa_vref_scan.cxx b/app/tool/algorithm/toa_vref_scan.cxx index e72c3f145..fb5627955 100644 --- a/app/tool/algorithm/toa_vref_scan.cxx +++ b/app/tool/algorithm/toa_vref_scan.cxx @@ -16,7 +16,8 @@ namespace pflib::algorithm { std::map>> -toa_vref_scan(Target * tgt, bool scan_all, bool write_csv, const std::string& csv_filepath) { +toa_vref_scan(Target* tgt, bool scan_all, bool write_csv, + const std::string& csv_filepath) { static auto the_log_{::pflib::logging::get("toa_vref_scan")}; static const std::size_t n_events = 100; @@ -48,7 +49,9 @@ toa_vref_scan(Target * tgt, bool scan_all, bool write_csv, const std::string& cs auto now = std::chrono::system_clock::now(); auto in_time_t = std::chrono::system_clock::to_time_t(now); std::stringstream ss; - ss << "toa_vref_scan_data_" << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << ".csv"; + ss << "toa_vref_scan_data_" + << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") + << ".csv"; final_path = ss.str(); } @@ -107,12 +110,13 @@ toa_vref_scan(Target * tgt, bool scan_all, bool write_csv, const std::string& cs final_effs[i_roc][i_link][toa_vref] = max_eff; if (toa_vref % 32 == 0 || max_eff > 0.0) { - pflib_log(trace) - << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " << i_roc - << " Link " << i_link << " | Max Efficiency: " << max_eff; + pflib_log(trace) << "[DEBUG SCAN] VREF " << toa_vref << " | ROC " + << i_roc << " Link " << i_link + << " | Max Efficiency: " << max_eff; } - // iterating from 255 down, find the first non-zero efficiency for each link in each roc + // iterating from 255 down, find the first non-zero efficiency for each + // link in each roc if (!scan_all) { if (target[i_roc][i_link] == -1 && max_eff > 0.0) { int calculated_vref = toa_vref + 10; @@ -138,20 +142,20 @@ toa_vref_scan(Target * tgt, bool scan_all, bool write_csv, const std::string& cs pflib_log(info) << "sample collections done, deducing settings"; - // get the max toa_vref with non-zero efficiency? Iterate through the array from top down. + // get the max toa_vref with non-zero efficiency? Iterate through the array + // from top down. if (scan_all) { for (int i_roc : tgt->roc_ids()) { for (int i_link{0}; i_link < 2; i_link++) { int highest_non_zero_eff = -1; // just a placeholder in case it's not found - for (int toa_vref = final_effs[i_roc][i_link].size() - 1; - toa_vref >= 0; toa_vref--) { + for (int toa_vref = final_effs[i_roc][i_link].size() - 1; toa_vref >= 0; + toa_vref--) { if (toa_vref == (int)final_effs[i_roc][i_link].size() - 1) { pflib_log(trace) - << "[DEBUG SEARCH] Starting backwards search for ROC " - << i_roc << " Link " << i_link - << ". Initial val at max VREF: " + << "[DEBUG SEARCH] Starting backwards search for ROC " << i_roc + << " Link " << i_link << ". Initial val at max VREF: " << final_effs[i_roc][i_link][toa_vref]; } diff --git a/app/tool/algorithm/toa_vref_scan.h b/app/tool/algorithm/toa_vref_scan.h index dee7c59c6..1c98c34df 100644 --- a/app/tool/algorithm/toa_vref_scan.h +++ b/app/tool/algorithm/toa_vref_scan.h @@ -16,6 +16,7 @@ namespace pflib::algorithm { * @note Only functional for single-ROC targets */ std::map>> -toa_vref_scan(Target* tgt, bool scan_all = false, bool write_csv = false, const std::string& csv_filepath = ""); +toa_vref_scan(Target* tgt, bool scan_all = false, bool write_csv = false, + const std::string& csv_filepath = ""); } // namespace pflib::algorithm diff --git a/app/tool/tasks/toa_vref_scan.cxx b/app/tool/tasks/toa_vref_scan.cxx index 9f783c39d..8240d6019 100644 --- a/app/tool/tasks/toa_vref_scan.cxx +++ b/app/tool/tasks/toa_vref_scan.cxx @@ -9,13 +9,15 @@ void toa_vref_scan(Target* tgt) { bool scan_all = pftool::readline_bool("Scan all VREF values?", false); - bool write_csv = pftool::readline_bool("Save raw scan data to a CSV file?", true); + bool write_csv = + pftool::readline_bool("Save raw scan data to a CSV file?", true); std::string csv_path = ""; if (write_csv) { csv_path = pftool::readline_path("toa-vref-scan-data", ".csv"); } - auto settings = pflib::algorithm::toa_vref_scan(tgt, scan_all, write_csv, csv_path); + auto settings = + pflib::algorithm::toa_vref_scan(tgt, scan_all, write_csv, csv_path); YAML::Emitter out; out << YAML::BeginMap;