From da8e50f92eafa37928fdf9b18e26eb4566d5aba0 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Fri, 31 Jul 2026 21:42:51 +0000 Subject: [PATCH 01/15] command to watch the self-trigger and collect events one at a time --- app/tool/trig/trig.cxx | 2 + app/tool/trig/watch_run.cxx | 105 ++++++++++++++++++++++++++++++++++++ app/tool/trig/watch_run.h | 2 + 3 files changed, 109 insertions(+) create mode 100644 app/tool/trig/watch_run.cxx create mode 100644 app/tool/trig/watch_run.h diff --git a/app/tool/trig/trig.cxx b/app/tool/trig/trig.cxx index 50432d2c..559cef22 100644 --- a/app/tool/trig/trig.cxx +++ b/app/tool/trig/trig.cxx @@ -8,6 +8,7 @@ #include "align.h" #include "decode_multi_sample.h" #include "histo.h" +#include "watch_run.h" #include "pflib/packing/SingleECONTCaptureFrame.h" #include "self_trig.h" #include "timein.h" @@ -156,6 +157,7 @@ auto menu_trig = "SETUP", "apply time offset parameters deduced from TIMEIN and/or SELF_TRIG", setup) + ->line("WATCH_RUN", "collect data following self-trigger", watch_run) ->line("ELINK_SPY", "spy on the six TRIG elinks", trig) ->line("EVENT_SPY", "attempt to read the last captured event", trig); diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx new file mode 100644 index 00000000..468e9b23 --- /dev/null +++ b/app/tool/trig/watch_run.cxx @@ -0,0 +1,105 @@ +#include "watch_run.h" + +#include "pflib/TRIG.h" + +#include "decode_multi_sample.h" +#include "pflib/TRIG.h" +#include "pflib/packing/Hex.h" +#include "pflib/packing/MultiSampleECONDEventPacket.h" +#include "pflib/packing/SingleECONTCaptureFrame.h" +#include "pflib/packing/TrigAlgoOutput.h" +#include "pflib/utility/string_format.h" +using pflib::packing::SingleECONTCaptureFrame; +using pflib::packing::MultiSampleECONDEventPacket; + +ENABLE_LOGGING(); + +void watch_run(pflib::Target* tgt) { + auto trig = tgt->trig(); + if (!trig) return; + /** + * TRIG.WATCH_RUN + * + * watch the self trigger and write out the + * data that it collects + */ + + int n_events = 100; + auto path{pftool::readline_path("watch-run", ".csv")}; + std::ofstream file{path}; + if (not file.is_open()) { + pflib_log(fatal) << "unabel to open " << path; + } + + file << "i_event,i_sample"; + for (int i_ch{0}; i_ch < 8; i_ch++) { + file + << ",ch_" << i_ch << ".Tp" + << ",ch_" << i_ch << ".Tc" + << ",ch_" << i_ch << ".adc_tm1" + << ",ch_" << i_ch << ".adc" + << ",ch_" << i_ch << ".toa" + << ",ch_" << i_ch << ".tot"; + } + file << ",stc6\n"; + + bool l1aen, extl1a; + tgt->fc().fc_enables_read(l1aen, extl1a); + bool og_single_shot = trig->get_enable_single_shot(); + trig->enable_single_shot(true); + tgt->fc().fc_enables(true, true); + + tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); + + for (int i_event{0}; i_event < n_events; i_event++) { + trig->reset_single_shot(); + int i100us{0}; + do { + usleep(100); + i100us++; + } while(not trig->single_shot_fired() and i100us < 10000); + + if (not trig->single_shot_fired()) { + pflib_log(warn) << "waiting for 1s and did not see a self-trigger"; + continue; + } + + // capture data output, using daq last to advance readout pointer + std::vector trg_charge_event = trig->read_event(); + std::vector charge_algo_output_raw = trig->read_algo_output(); + std::vector daq_charge_event = tgt->read_event(); + + // decode after capturing all data so decoding errors don't cause + // readout pointer misalignment + std::vector trg_charge = + decode_multi_sample(trig->get_l1a_per_ror(), + trg_charge_event); + + /* + std::vector charge_algo_output = + decode_multi_sample(trig->get_l1a_per_ror(), + charge_algo_output_raw); + */ + + pflib::packing::MultiSampleECONDEventPacket daq_charge(2); + daq_charge.from(daq_charge_event); + + // serialize + for (int i_sample{0}; i_sample < trig->get_l1a_per_ror(); i_sample++) { + file << i_event << ',' << i_sample; + for (int ch{0}; ch < 8; ch++) { + auto sample{daq_charge.samples.at(i_sample).channel(1 /* should use mapping! */, ch)}; + file << ',' << sample.Tp() + << ',' << sample.Tc() + << ',' << sample.adc_tm1() + << ',' << sample.adc() + << ',' << sample.toa() + << ',' << sample.tot(); + } + file << ',' << trg_charge[i_sample].stc_sum(6, 0) << '\n'; + } + } + + tgt->fc().fc_enables(l1aen, extl1a); + trig->enable_single_shot(og_single_shot); +} diff --git a/app/tool/trig/watch_run.h b/app/tool/trig/watch_run.h new file mode 100644 index 00000000..05f9200b --- /dev/null +++ b/app/tool/trig/watch_run.h @@ -0,0 +1,2 @@ +#include "../pftool.h" +void watch_run(pflib::Target* tgt); From ab473fb209d65e24fcb4305e0ec4581bb245884f Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Mon, 3 Aug 2026 17:43:20 +0000 Subject: [PATCH 02/15] example hgcroc config for wiki page --- config/hgcroc/umn-cosmic-init.yaml | 157 +++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 config/hgcroc/umn-cosmic-init.yaml diff --git a/config/hgcroc/umn-cosmic-init.yaml b/config/hgcroc/umn-cosmic-init.yaml new file mode 100644 index 00000000..ac876b9b --- /dev/null +++ b/config/hgcroc/umn-cosmic-init.yaml @@ -0,0 +1,157 @@ +digitalhalf_0: + adc_th: 31 +digitalhalf_1: + adc_th: 31 +ch_0: + adc_pedestal: 225 + trim_inv: 14 +ch_1: + adc_pedestal: 225 + trim_inv: 61 +ch_2: + adc_pedestal: 225 + trim_inv: 59 +ch_3: + adc_pedestal: 225 + trim_inv: 37 +ch_4: + adc_pedestal: 225 + # was not leveled? +ch_5: + adc_pedestal: 225 + trim_inv: 1 +ch_6: + adc_pedestal: 225 + trim_inv: 27 +ch_7: + adc_pedestal: 225 + dacb: 1 + sign_dac: 1 +ch_8: + channel_off: 1 +ch_9: + channel_off: 1 +ch_10: + channel_off: 1 +ch_11: + channel_off: 1 +ch_12: + channel_off: 1 +ch_13: + channel_off: 1 +ch_14: + channel_off: 1 +ch_15: + channel_off: 1 +ch_16: + channel_off: 1 +ch_17: + channel_off: 1 +ch_18: + channel_off: 1 +ch_19: + channel_off: 1 +ch_20: + channel_off: 1 +ch_21: + channel_off: 1 +ch_22: + channel_off: 1 +ch_23: + channel_off: 1 +ch_24: + channel_off: 1 +ch_25: + channel_off: 1 +ch_26: + channel_off: 1 +ch_27: + channel_off: 1 +ch_28: + channel_off: 1 +ch_29: + channel_off: 1 +ch_30: + channel_off: 1 +ch_31: + channel_off: 1 +ch_32: + channel_off: 1 +ch_33: + channel_off: 1 +ch_34: + channel_off: 1 +ch_35: + channel_off: 1 +ch_36: + channel_off: 1 +ch_37: + channel_off: 1 +ch_38: + channel_off: 1 +ch_39: + channel_off: 1 +ch_40: + channel_off: 1 +ch_41: + channel_off: 1 +ch_42: + channel_off: 1 +ch_43: + channel_off: 1 +ch_44: + channel_off: 1 +ch_45: + channel_off: 1 +ch_46: + channel_off: 1 +ch_47: + channel_off: 1 +ch_48: + channel_off: 1 +ch_49: + channel_off: 1 +ch_50: + channel_off: 1 +ch_51: + channel_off: 1 +ch_52: + channel_off: 1 +ch_53: + channel_off: 1 +ch_54: + channel_off: 1 +ch_55: + channel_off: 1 +ch_56: + channel_off: 1 +ch_57: + channel_off: 1 +ch_58: + channel_off: 1 +ch_59: + channel_off: 1 +ch_60: + channel_off: 1 +ch_61: + channel_off: 1 +ch_62: + channel_off: 1 +ch_63: + channel_off: 1 +ch_64: + channel_off: 1 +ch_65: + channel_off: 1 +ch_66: + channel_off: 1 +ch_67: + channel_off: 1 +ch_68: + channel_off: 1 +ch_69: + channel_off: 1 +ch_70: + channel_off: 1 +ch_71: + channel_off: 1 From 23c4750e327a9a4373baa7800f538928234cb691 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 3 Aug 2026 17:45:52 +0000 Subject: [PATCH 03/15] Apply clang-format --style=Google --- app/tool/trig/trig.cxx | 2 +- app/tool/trig/watch_run.cxx | 37 ++++++++++++++++--------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/app/tool/trig/trig.cxx b/app/tool/trig/trig.cxx index 559cef22..9492b86f 100644 --- a/app/tool/trig/trig.cxx +++ b/app/tool/trig/trig.cxx @@ -8,10 +8,10 @@ #include "align.h" #include "decode_multi_sample.h" #include "histo.h" -#include "watch_run.h" #include "pflib/packing/SingleECONTCaptureFrame.h" #include "self_trig.h" #include "timein.h" +#include "watch_run.h" using pflib::packing::SingleECONTCaptureFrame; #include diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx index 468e9b23..b6bc3c8f 100644 --- a/app/tool/trig/watch_run.cxx +++ b/app/tool/trig/watch_run.cxx @@ -1,7 +1,5 @@ #include "watch_run.h" -#include "pflib/TRIG.h" - #include "decode_multi_sample.h" #include "pflib/TRIG.h" #include "pflib/packing/Hex.h" @@ -9,8 +7,8 @@ #include "pflib/packing/SingleECONTCaptureFrame.h" #include "pflib/packing/TrigAlgoOutput.h" #include "pflib/utility/string_format.h" -using pflib::packing::SingleECONTCaptureFrame; using pflib::packing::MultiSampleECONDEventPacket; +using pflib::packing::SingleECONTCaptureFrame; ENABLE_LOGGING(); @@ -23,7 +21,7 @@ void watch_run(pflib::Target* tgt) { * watch the self trigger and write out the * data that it collects */ - + int n_events = 100; auto path{pftool::readline_path("watch-run", ".csv")}; std::ofstream file{path}; @@ -33,13 +31,12 @@ void watch_run(pflib::Target* tgt) { file << "i_event,i_sample"; for (int i_ch{0}; i_ch < 8; i_ch++) { - file - << ",ch_" << i_ch << ".Tp" - << ",ch_" << i_ch << ".Tc" - << ",ch_" << i_ch << ".adc_tm1" - << ",ch_" << i_ch << ".adc" - << ",ch_" << i_ch << ".toa" - << ",ch_" << i_ch << ".tot"; + file << ",ch_" << i_ch << ".Tp" + << ",ch_" << i_ch << ".Tc" + << ",ch_" << i_ch << ".adc_tm1" + << ",ch_" << i_ch << ".adc" + << ",ch_" << i_ch << ".toa" + << ",ch_" << i_ch << ".tot"; } file << ",stc6\n"; @@ -57,13 +54,13 @@ void watch_run(pflib::Target* tgt) { do { usleep(100); i100us++; - } while(not trig->single_shot_fired() and i100us < 10000); + } while (not trig->single_shot_fired() and i100us < 10000); if (not trig->single_shot_fired()) { pflib_log(warn) << "waiting for 1s and did not see a self-trigger"; continue; } - + // capture data output, using daq last to advance readout pointer std::vector trg_charge_event = trig->read_event(); std::vector charge_algo_output_raw = trig->read_algo_output(); @@ -73,7 +70,7 @@ void watch_run(pflib::Target* tgt) { // readout pointer misalignment std::vector trg_charge = decode_multi_sample(trig->get_l1a_per_ror(), - trg_charge_event); + trg_charge_event); /* std::vector charge_algo_output = @@ -83,17 +80,15 @@ void watch_run(pflib::Target* tgt) { pflib::packing::MultiSampleECONDEventPacket daq_charge(2); daq_charge.from(daq_charge_event); - + // serialize for (int i_sample{0}; i_sample < trig->get_l1a_per_ror(); i_sample++) { file << i_event << ',' << i_sample; for (int ch{0}; ch < 8; ch++) { - auto sample{daq_charge.samples.at(i_sample).channel(1 /* should use mapping! */, ch)}; - file << ',' << sample.Tp() - << ',' << sample.Tc() - << ',' << sample.adc_tm1() - << ',' << sample.adc() - << ',' << sample.toa() + auto sample{daq_charge.samples.at(i_sample).channel( + 1 /* should use mapping! */, ch)}; + file << ',' << sample.Tp() << ',' << sample.Tc() << ',' + << sample.adc_tm1() << ',' << sample.adc() << ',' << sample.toa() << ',' << sample.tot(); } file << ',' << trg_charge[i_sample].stc_sum(6, 0) << '\n'; From 08e05f826d271a459cd0822bbea81d0b4289f4c0 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Mon, 3 Aug 2026 18:52:25 +0000 Subject: [PATCH 04/15] save time since last clear for scaling histograms --- app/tool/trig/FWHistoPool.cxx | 11 ++++++---- app/tool/trig/FWHistoPool.h | 11 ++++++++-- app/tool/trig/histo.cxx | 41 +++++++++++++++++++++++++---------- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/app/tool/trig/FWHistoPool.cxx b/app/tool/trig/FWHistoPool.cxx index 96c15f52..72949a01 100644 --- a/app/tool/trig/FWHistoPool.cxx +++ b/app/tool/trig/FWHistoPool.cxx @@ -62,13 +62,14 @@ std::array FWHistoPool::read(int ihist) { } nlohmann::json FWHistoPool::to_json(const std::array& data, - int ihist) { + int ihist, double collection_time) { nlohmann::json hist; hist["uhi_schema"] = 1; hist["writer_info"]["pftool.FWHistoPool"]["version"] = pflib::version::debug(); hist["writer_info"]["trigpath-firmware"]["version"] = FW_VERSION; hist["metadata"]["_variance_known"] = true; + hist["metadata"]["collection_time"] = collection_time; nlohmann::json axis; axis["type"] = "regular"; @@ -88,19 +89,21 @@ nlohmann::json FWHistoPool::to_json(const std::array& data, axis["metadata"]["label"] = name + " Encoded Sum"; hist["axes"] = {axis}; - hist["storage"]["type"] = "int"; + hist["storage"]["type"] = "double"; hist["storage"]["values"] = data; return hist; } nlohmann::json FWHistoPool::to_json( - const std::array, 8>& data) { + const std::array, 8>& data, + double collection_time) { nlohmann::json hist; hist["uhi_schema"] = 1; hist["writer_info"]["pftool.FWHistoPool"]["version"] = pflib::version::debug(); hist["writer_info"]["trigpath-firmware"]["version"] = FW_VERSION; hist["metadata"]["_variance_known"] = true; + hist["metadata"]["collection_time"] = collection_time; nlohmann::json cat; cat["type"] = "category_str"; @@ -122,7 +125,7 @@ nlohmann::json FWHistoPool::to_json( reg["metadata"]["label"] = "Encoded Sum"; hist["axes"] = {cat, reg}; - hist["storage"]["type"] = "int"; + hist["storage"]["type"] = "double"; hist["storage"]["values"] = data; return hist; } diff --git a/app/tool/trig/FWHistoPool.h b/app/tool/trig/FWHistoPool.h index 07413aca..308ba6e5 100644 --- a/app/tool/trig/FWHistoPool.h +++ b/app/tool/trig/FWHistoPool.h @@ -79,10 +79,13 @@ class FWHistoPool { * * @param[in] hist histogram to serialize into UHI JSON * @param[in] ihist histogram index to include in labeling + * @param[in] collection_time time in s that data was collected, + * included in the histograms 'metadata' in the JSON for scaling + * the plot later if desired * @return JSON representation of histogram */ static nlohmann::json to_json(const std::array& hist, - int ihist); + int ihist, double collection_time); /** * convert the input set of many histograms into a JSON @@ -105,10 +108,14 @@ class FWHistoPool { * ``` * * @param[in] data set of histograms to serialize into JSON + * @param[in] collection_time time in s that data was collected, + * included in the histograms 'metadata' in the JSON for scaling + * the plot later if desired * @return JSON representation of list of histograms */ static nlohmann::json to_json( - const std::array, 8>& data); + const std::array, 8>& data, + double collection_time); }; #endif diff --git a/app/tool/trig/histo.cxx b/app/tool/trig/histo.cxx index b607061f..6f3e8d09 100644 --- a/app/tool/trig/histo.cxx +++ b/app/tool/trig/histo.cxx @@ -4,17 +4,24 @@ #include "histo.h" #include +#include #include "FWHistoPool.h" #include "pflib/TRIG.h" #include "pflib/utility/string_format.h" using pflib::utility::string_format; +using the_clock = std::chrono::high_resolution_clock; +using a_time_point = std::chrono::time_point; + void histo(const std::string& cmd, Target* tgt) { + using namespace std::literals; static FWHistoPool hist_pool{0}; + static a_time_point time_of_last_clear{}; if (cmd == "CLEAR") { hist_pool.clear(); + time_of_last_clear = the_clock::now(); } if (cmd == "DEBUG") { @@ -26,9 +33,18 @@ void histo(const std::string& cmd, Target* tgt) { if (cmd == "READ") { static int ihist = 0; ihist = pftool::readline_int("Which histogram?", ihist); + auto now = the_clock::now(); std::array hist = hist_pool.read(ihist); + double collection_time = (now - time_of_last_clear) / 1.0s; + bool raw_counts = pftool::readline_bool("Show raw counts (y) or rate (n)?", true); for (std::size_t i{0}; i < hist.size(); i++) { - printf("%3d %u\n", i, hist[i]); + printf("%3d ", i); + if (raw_counts) { + printf("%u", hist[i]); + } else { + printf("%0.4e", hist[i] / collection_time); + } + printf("\n"); } if (pftool::readline_bool("Store histogram in JSON file for plotting?", false)) { @@ -38,7 +54,7 @@ void histo(const std::string& cmd, Target* tgt) { if (not file.is_open()) { PFEXCEPTION_RAISE("FileOpen", "Unable to open " + path); } - file << FWHistoPool::to_json(hist, ihist); + file << FWHistoPool::to_json(hist, ihist, collection_time); } } @@ -47,28 +63,29 @@ void histo(const std::string& cmd, Target* tgt) { // we read BEFORE asking what to write to enable a RESET->DUMP to // be able to happen quickly std::array, 8> hists; - std::array total; - total.fill(0); + auto now = the_clock::now(); for (int ihist{0}; ihist < hists.size(); ihist++) { hists[ihist] = hist_pool.read(ihist); } + double collection_time = (now - time_of_last_clear) / 1.0s; + std::cout << collection_time << std::endl; + if (pftool::readline_bool("Show histograms in terminal?", true)) { + bool raw_counts = pftool::readline_bool("Show raw counts (y) or rate (n)?", true); printf("bin : %10u %10u %10u %10u %10u %10u %10u %10u\n", 0, 1, 2, 3, 4, 5, 6, 7); for (std::size_t i{0}; i < hists[0].size(); i++) { printf("%3d :", i); for (int ihist{0}; ihist < hists.size(); ihist++) { - printf(" %10u", hists[ihist][i]); - total[ihist] += hists[ihist][i]; + if (raw_counts) { + printf(" %10u", hists[ihist][i]); + } else { + printf(" %10.4e", hists[ihist][i] / collection_time); + } } printf("\n"); } - printf("tot :"); - for (int ihist{0}; ihist < total.size(); ihist++) { - printf(" %10u", total[ihist]); - } - printf("\n"); } if (pftool::readline_bool("Store histograms in JSON file for plotting?", @@ -78,7 +95,7 @@ void histo(const std::string& cmd, Target* tgt) { if (not file.is_open()) { PFEXCEPTION_RAISE("FileOpen", "Unable to open " + path); } - file << FWHistoPool::to_json(hists); + file << FWHistoPool::to_json(hists, collection_time); } } } From e9751d609ccceb7120398280a69adc69f3ba24b6 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Mon, 3 Aug 2026 13:53:07 -0500 Subject: [PATCH 05/15] scale trig histograms to rate --- ana/plot-fw-histograms.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ana/plot-fw-histograms.py b/ana/plot-fw-histograms.py index 8c4d39c0..59286295 100644 --- a/ana/plot-fw-histograms.py +++ b/ana/plot-fw-histograms.py @@ -19,6 +19,7 @@ parser.add_argument('--stc', type=int, help='only plot input STC if given') parser.add_argument('--roc-adc-th', type=int, help='digitalhalf_#.adc_th setting on the ROCs being used') parser.add_argument('--trigger-th', type=int, help='trigger threshold being used') +parser.add_argument('--raw-counts', action='store_true', help='plot raw counts instead of scaling by collection time to estimate the rate') args = parser.parse_args() if args.output is None: @@ -28,6 +29,8 @@ data = json.load(file, object_hook=uhi.io.json.object_hook) h = hist.Hist(data) +if not args.raw_counts: + h /= data['metadata']['collection_time'] if args.stc is not None and len(h.axes) > 1: h[f'STC{args.stc}',:].plot(yerr = args.error_bars) plt.annotate( @@ -54,5 +57,8 @@ rotation = 90, ) plt.yscale('log') -plt.ylabel('Events / bin') +if args.raw_counts: + plt.ylabel('Events / bin') +else: + plt.ylabel('Rate / Hz') plt.savefig(args.output, bbox_inches='tight') From 772418c79eb6653f9a178b0579d3c666b9a19d32 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 3 Aug 2026 18:54:17 +0000 Subject: [PATCH 06/15] Apply clang-format --style=Google --- app/tool/trig/histo.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/tool/trig/histo.cxx b/app/tool/trig/histo.cxx index 6f3e8d09..1ee95fb7 100644 --- a/app/tool/trig/histo.cxx +++ b/app/tool/trig/histo.cxx @@ -3,8 +3,8 @@ */ #include "histo.h" -#include #include +#include #include "FWHistoPool.h" #include "pflib/TRIG.h" @@ -36,7 +36,8 @@ void histo(const std::string& cmd, Target* tgt) { auto now = the_clock::now(); std::array hist = hist_pool.read(ihist); double collection_time = (now - time_of_last_clear) / 1.0s; - bool raw_counts = pftool::readline_bool("Show raw counts (y) or rate (n)?", true); + bool raw_counts = + pftool::readline_bool("Show raw counts (y) or rate (n)?", true); for (std::size_t i{0}; i < hist.size(); i++) { printf("%3d ", i); if (raw_counts) { @@ -72,7 +73,8 @@ void histo(const std::string& cmd, Target* tgt) { std::cout << collection_time << std::endl; if (pftool::readline_bool("Show histograms in terminal?", true)) { - bool raw_counts = pftool::readline_bool("Show raw counts (y) or rate (n)?", true); + bool raw_counts = + pftool::readline_bool("Show raw counts (y) or rate (n)?", true); printf("bin : %10u %10u %10u %10u %10u %10u %10u %10u\n", 0, 1, 2, 3, 4, 5, 6, 7); for (std::size_t i{0}; i < hists[0].size(); i++) { From 2213fece017e7fe16464f23cb1cb964df954c293 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Mon, 3 Aug 2026 19:41:12 +0000 Subject: [PATCH 07/15] option to increase events, add status printouts --- app/tool/trig/watch_run.cxx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx index b6bc3c8f..6620c5c1 100644 --- a/app/tool/trig/watch_run.cxx +++ b/app/tool/trig/watch_run.cxx @@ -22,14 +22,16 @@ void watch_run(pflib::Target* tgt) { * data that it collects */ - int n_events = 100; + int n_events = pftool::readline_int("Number of events to wait for?", 100); auto path{pftool::readline_path("watch-run", ".csv")}; std::ofstream file{path}; if (not file.is_open()) { pflib_log(fatal) << "unabel to open " << path; + return; } file << "i_event,i_sample"; + // TODO: choose channels to write out for (int i_ch{0}; i_ch < 8; i_ch++) { file << ",ch_" << i_ch << ".Tp" << ",ch_" << i_ch << ".Tc" @@ -49,6 +51,11 @@ void watch_run(pflib::Target* tgt) { tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); for (int i_event{0}; i_event < n_events; i_event++) { + if (i_event % 100 == 0 and i_event > 99) { + // status on every 100 events after the first 100 + pflib_log(info) << i_event << " events collected"; + } + trig->reset_single_shot(); int i100us{0}; do { @@ -57,7 +64,7 @@ void watch_run(pflib::Target* tgt) { } while (not trig->single_shot_fired() and i100us < 10000); if (not trig->single_shot_fired()) { - pflib_log(warn) << "waiting for 1s and did not see a self-trigger"; + pflib_log(warn) << "waiting for 1s and did not see a self-trigger, skipping event " << i_event; continue; } From 8af4b3b42d1259c292c9c1433cf97d56a2f9680b Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Mon, 3 Aug 2026 14:42:00 -0500 Subject: [PATCH 08/15] easier viewing of pedestal results --- ana/pedestal/text-summary.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ana/pedestal/text-summary.py b/ana/pedestal/text-summary.py index 11c1c54a..4291005c 100644 --- a/ana/pedestal/text-summary.py +++ b/ana/pedestal/text-summary.py @@ -7,7 +7,7 @@ parser.add_argument('pedestals', help='decoded pedestal CSV file to summarize') args = parser.parse_args() -samples = pd.read_csv(args.pedestals).groupby(['link','channel']) +samples = pd.read_csv(args.pedestals).groupby(['i_link','channel']) summary = pd.DataFrame({ 'mean': samples.adc.mean(), @@ -17,4 +17,6 @@ # could sort index so the channels appear in non dictionary order # but can't figure out the correct key function right now -print(summary.to_string()) +# ignore channels where the standard deviation is exactly zero +# these are broken or turned off +print(summary[summary['std'] > 0].to_string()) From 0175d5491ce433d47d88b50fad248c83c17d401c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 3 Aug 2026 19:42:58 +0000 Subject: [PATCH 09/15] Apply clang-format --style=Google --- app/tool/trig/watch_run.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx index 6620c5c1..92774348 100644 --- a/app/tool/trig/watch_run.cxx +++ b/app/tool/trig/watch_run.cxx @@ -64,7 +64,9 @@ void watch_run(pflib::Target* tgt) { } while (not trig->single_shot_fired() and i100us < 10000); if (not trig->single_shot_fired()) { - pflib_log(warn) << "waiting for 1s and did not see a self-trigger, skipping event " << i_event; + pflib_log(warn) + << "waiting for 1s and did not see a self-trigger, skipping event " + << i_event; continue; } From b7f234449f10bf52e442548a8d6668a816be7d54 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Tue, 4 Aug 2026 10:50:34 -0500 Subject: [PATCH 10/15] more safely acquire collection time --- app/tool/trig/histo.cxx | 50 ++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/app/tool/trig/histo.cxx b/app/tool/trig/histo.cxx index 1ee95fb7..9f5de5f5 100644 --- a/app/tool/trig/histo.cxx +++ b/app/tool/trig/histo.cxx @@ -13,11 +13,24 @@ using pflib::utility::string_format; using the_clock = std::chrono::high_resolution_clock; using a_time_point = std::chrono::time_point; +static std::optional time_of_last_clear{}; -void histo(const std::string& cmd, Target* tgt) { +ENABLE_LOGGING(); + +std::optional get_collection_time(a_time_point now) { using namespace std::literals; + if (time_of_last_clear) { + return (now - time_of_last_clear.value()) / 1.0s; + } else { + pflib_log(warn) << "There hasn't be a CLEAR recently," + " so we don't know the collection time and" + " the histograms are probably saturated!"; + return {}; + } +} + +void histo(const std::string& cmd, Target* tgt) { static FWHistoPool hist_pool{0}; - static a_time_point time_of_last_clear{}; if (cmd == "CLEAR") { hist_pool.clear(); @@ -35,15 +48,19 @@ void histo(const std::string& cmd, Target* tgt) { ihist = pftool::readline_int("Which histogram?", ihist); auto now = the_clock::now(); std::array hist = hist_pool.read(ihist); - double collection_time = (now - time_of_last_clear) / 1.0s; - bool raw_counts = - pftool::readline_bool("Show raw counts (y) or rate (n)?", true); + std::optional collection_time = get_collection_time(now); + pflib_log(info) << "accumulated histogram for " << collection_time.value_or(0) << "s"; + bool raw_counts = true; + if (collection_time) { + raw_counts = + pftool::readline_bool("Show raw counts (y) or rate (n)?", raw_counts); + } for (std::size_t i{0}; i < hist.size(); i++) { - printf("%3d ", i); + printf("%3ld ", i); if (raw_counts) { printf("%u", hist[i]); } else { - printf("%0.4e", hist[i] / collection_time); + printf("%0.4e", hist[i] / collection_time.value()); } printf("\n"); } @@ -55,7 +72,7 @@ void histo(const std::string& cmd, Target* tgt) { if (not file.is_open()) { PFEXCEPTION_RAISE("FileOpen", "Unable to open " + path); } - file << FWHistoPool::to_json(hist, ihist, collection_time); + file << FWHistoPool::to_json(hist, ihist, collection_time.value_or(0)); } } @@ -69,21 +86,24 @@ void histo(const std::string& cmd, Target* tgt) { hists[ihist] = hist_pool.read(ihist); } - double collection_time = (now - time_of_last_clear) / 1.0s; - std::cout << collection_time << std::endl; + std::optional collection_time = get_collection_time(now); + pflib_log(info) << "accumulated histogram for " << collection_time.value_or(0) << "s"; if (pftool::readline_bool("Show histograms in terminal?", true)) { - bool raw_counts = - pftool::readline_bool("Show raw counts (y) or rate (n)?", true); + bool raw_counts = true; + if (collection_time) { + raw_counts = + pftool::readline_bool("Show raw counts (y) or rate (n)?", raw_counts); + } printf("bin : %10u %10u %10u %10u %10u %10u %10u %10u\n", 0, 1, 2, 3, 4, 5, 6, 7); for (std::size_t i{0}; i < hists[0].size(); i++) { - printf("%3d :", i); + printf("%3ld :", i); for (int ihist{0}; ihist < hists.size(); ihist++) { if (raw_counts) { printf(" %10u", hists[ihist][i]); } else { - printf(" %10.4e", hists[ihist][i] / collection_time); + printf(" %10.4e", hists[ihist][i] / collection_time.value()); } } printf("\n"); @@ -97,7 +117,7 @@ void histo(const std::string& cmd, Target* tgt) { if (not file.is_open()) { PFEXCEPTION_RAISE("FileOpen", "Unable to open " + path); } - file << FWHistoPool::to_json(hists, collection_time); + file << FWHistoPool::to_json(hists, collection_time.value_or(0)); } } } From 6a991f3fccb82dbbac6dc38062b6ca2d20a95c3f Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Tue, 4 Aug 2026 11:13:48 -0500 Subject: [PATCH 11/15] draft status message to share how many self-triggers were ignored --- app/tool/trig/watch_run.cxx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx index 92774348..a2ffb4ad 100644 --- a/app/tool/trig/watch_run.cxx +++ b/app/tool/trig/watch_run.cxx @@ -50,6 +50,7 @@ void watch_run(pflib::Target* tgt) { tgt->setup_run(1, Target::DaqFormat::ECOND_SW_HEADERS, 1); + int self_trigger_count = trig->get_self_trigger_count(); for (int i_event{0}; i_event < n_events; i_event++) { if (i_event % 100 == 0 and i_event > 99) { // status on every 100 events after the first 100 @@ -102,6 +103,25 @@ void watch_run(pflib::Target* tgt) { } file << ',' << trg_charge[i_sample].stc_sum(6, 0) << '\n'; } + + int new_self_trigger_count = trig->get_self_trigger_count(); + if (new_self_trigger_count != self_trigger_count+1) { + // self trigger counter is 16bits and so we may have wrapped around + // if its getting spammed + int diff{0}; + if (new_self_trigger_count < self_trigger_count) { + // wrap around happend + diff = (0xffff - self_trigger_count) + new_self_trigger_count; + } else { + // no wrap around + diff = new_self_trigger_count - self_trigger_count - 1; + } + pflib_log(info) << "single-shot gate ignored " + << diff + << " self-triggers while acquiring, decoding, and serializing data" + << " for event " << i_event; + } + self_trigger_count = new_self_trigger_count; } tgt->fc().fc_enables(l1aen, extl1a); From b60d10c807ecd111fbb2fa62878fa57e5fa8b258 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Tue, 4 Aug 2026 11:33:53 -0500 Subject: [PATCH 12/15] ask for roc/channels to readout, deduce STCs to readout as well --- app/tool/trig/watch_run.cxx | 56 ++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx index a2ffb4ad..ed2eb598 100644 --- a/app/tool/trig/watch_run.cxx +++ b/app/tool/trig/watch_run.cxx @@ -30,17 +30,44 @@ void watch_run(pflib::Target* tgt) { return; } + int i_roc = pftool::readline_int("ROC to readout: ", pftool::state.iroc); + + std::string channel_str = "0,1,2,3,4,5,6,7"; + channel_str = pftool::readline("Comma-separated list of channels in that ROC to readout:", channel_str); + std::stringstream channel_stream{channel_str}; + std::string channel; + std::vector channels; + while (getline(channel_stream, channel, ',')) { + channels.push_back(std::stoi(channel)); + } + const auto& mapping{tgt->getRocErxMapping()}; + file << "i_event,i_sample"; - // TODO: choose channels to write out - for (int i_ch{0}; i_ch < 8; i_ch++) { - file << ",ch_" << i_ch << ".Tp" - << ",ch_" << i_ch << ".Tc" - << ",ch_" << i_ch << ".adc_tm1" - << ",ch_" << i_ch << ".adc" - << ",ch_" << i_ch << ".toa" - << ",ch_" << i_ch << ".tot"; + for (int ch : channels) { + file << ",ch_" << ch << "_Tp" + << ",ch_" << ch << "_Tc" + << ",ch_" << ch << "_adc_tm1" + << ",ch_" << ch << "_adc" + << ",ch_" << ch << "_toa" + << ",ch_" << ch << "_tot"; } - file << ",stc6\n"; + + // TODO: expand deduction to ECON-T2 EcalSMM + static const std::vector> i_roc_to_stcs = { + {6, 7, 4, 5}, + {3, 2, 1, 0}, + }; + + if (i_roc > 1) { + pflib_log(warn) << "untested using ECON-T2, will not run without further software dev"; + return; + } + + auto stc_indices = i_roc_to_stcs.at(i_roc); + for (int i_stc : stc_indices) { + file << ",stc" << i_stc; + } + file << '\n'; bool l1aen, extl1a; tgt->fc().fc_enables_read(l1aen, extl1a); @@ -94,14 +121,17 @@ void watch_run(pflib::Target* tgt) { // serialize for (int i_sample{0}; i_sample < trig->get_l1a_per_ror(); i_sample++) { file << i_event << ',' << i_sample; - for (int ch{0}; ch < 8; ch++) { - auto sample{daq_charge.samples.at(i_sample).channel( - 1 /* should use mapping! */, ch)}; + for (int ch : channels) { + auto [i_erx, i_ch] = mapping.toErxChannel(i_roc, ch); + auto sample{daq_charge.samples.at(i_sample).channel(i_erx, i_ch)}; file << ',' << sample.Tp() << ',' << sample.Tc() << ',' << sample.adc_tm1() << ',' << sample.adc() << ',' << sample.toa() << ',' << sample.tot(); } - file << ',' << trg_charge[i_sample].stc_sum(6, 0) << '\n'; + for (int i_stc : stc_indices) { + file << ',' << trg_charge[i_sample].stc_sum(i_stc, 0); + } + file << '\n'; } int new_self_trigger_count = trig->get_self_trigger_count(); From b78f099fc9353ea0054106406e8cd917aa932b87 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 4 Aug 2026 16:34:53 +0000 Subject: [PATCH 13/15] Apply clang-format --style=Google --- app/tool/trig/histo.cxx | 10 ++++++---- app/tool/trig/watch_run.cxx | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/tool/trig/histo.cxx b/app/tool/trig/histo.cxx index 9f5de5f5..10622b98 100644 --- a/app/tool/trig/histo.cxx +++ b/app/tool/trig/histo.cxx @@ -49,7 +49,8 @@ void histo(const std::string& cmd, Target* tgt) { auto now = the_clock::now(); std::array hist = hist_pool.read(ihist); std::optional collection_time = get_collection_time(now); - pflib_log(info) << "accumulated histogram for " << collection_time.value_or(0) << "s"; + pflib_log(info) << "accumulated histogram for " + << collection_time.value_or(0) << "s"; bool raw_counts = true; if (collection_time) { raw_counts = @@ -87,13 +88,14 @@ void histo(const std::string& cmd, Target* tgt) { } std::optional collection_time = get_collection_time(now); - pflib_log(info) << "accumulated histogram for " << collection_time.value_or(0) << "s"; + pflib_log(info) << "accumulated histogram for " + << collection_time.value_or(0) << "s"; if (pftool::readline_bool("Show histograms in terminal?", true)) { bool raw_counts = true; if (collection_time) { - raw_counts = - pftool::readline_bool("Show raw counts (y) or rate (n)?", raw_counts); + raw_counts = pftool::readline_bool("Show raw counts (y) or rate (n)?", + raw_counts); } printf("bin : %10u %10u %10u %10u %10u %10u %10u %10u\n", 0, 1, 2, 3, 4, 5, 6, 7); diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx index ed2eb598..17676dc7 100644 --- a/app/tool/trig/watch_run.cxx +++ b/app/tool/trig/watch_run.cxx @@ -33,7 +33,8 @@ void watch_run(pflib::Target* tgt) { int i_roc = pftool::readline_int("ROC to readout: ", pftool::state.iroc); std::string channel_str = "0,1,2,3,4,5,6,7"; - channel_str = pftool::readline("Comma-separated list of channels in that ROC to readout:", channel_str); + channel_str = pftool::readline( + "Comma-separated list of channels in that ROC to readout:", channel_str); std::stringstream channel_stream{channel_str}; std::string channel; std::vector channels; @@ -53,13 +54,14 @@ void watch_run(pflib::Target* tgt) { } // TODO: expand deduction to ECON-T2 EcalSMM - static const std::vector> i_roc_to_stcs = { - {6, 7, 4, 5}, - {3, 2, 1, 0}, + static const std::vector> i_roc_to_stcs = { + {6, 7, 4, 5}, + {3, 2, 1, 0}, }; if (i_roc > 1) { - pflib_log(warn) << "untested using ECON-T2, will not run without further software dev"; + pflib_log(warn) + << "untested using ECON-T2, will not run without further software dev"; return; } @@ -135,7 +137,7 @@ void watch_run(pflib::Target* tgt) { } int new_self_trigger_count = trig->get_self_trigger_count(); - if (new_self_trigger_count != self_trigger_count+1) { + if (new_self_trigger_count != self_trigger_count + 1) { // self trigger counter is 16bits and so we may have wrapped around // if its getting spammed int diff{0}; @@ -146,10 +148,10 @@ void watch_run(pflib::Target* tgt) { // no wrap around diff = new_self_trigger_count - self_trigger_count - 1; } - pflib_log(info) << "single-shot gate ignored " - << diff - << " self-triggers while acquiring, decoding, and serializing data" - << " for event " << i_event; + pflib_log(info) + << "single-shot gate ignored " << diff + << " self-triggers while acquiring, decoding, and serializing data" + << " for event " << i_event; } self_trigger_count = new_self_trigger_count; } From b53b165d8e05249461446a1aa7d58aa9ccc253a1 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Tue, 4 Aug 2026 11:34:44 -0500 Subject: [PATCH 14/15] slightly more accurate but still rough trg path roc calib --- config/hgcroc/umn-cosmic-init.yaml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/config/hgcroc/umn-cosmic-init.yaml b/config/hgcroc/umn-cosmic-init.yaml index ac876b9b..e06114c7 100644 --- a/config/hgcroc/umn-cosmic-init.yaml +++ b/config/hgcroc/umn-cosmic-init.yaml @@ -1,30 +1,28 @@ digitalhalf_0: - adc_th: 31 -digitalhalf_1: - adc_th: 31 + adc_th: 16 ch_0: - adc_pedestal: 225 + adc_pedestal: 210 trim_inv: 14 ch_1: - adc_pedestal: 225 + adc_pedestal: 210 trim_inv: 61 ch_2: - adc_pedestal: 225 + adc_pedestal: 210 trim_inv: 59 ch_3: - adc_pedestal: 225 + adc_pedestal: 210 trim_inv: 37 ch_4: - adc_pedestal: 225 + adc_pedestal: 210 # was not leveled? ch_5: - adc_pedestal: 225 + adc_pedestal: 210 trim_inv: 1 ch_6: - adc_pedestal: 225 + adc_pedestal: 210 trim_inv: 27 ch_7: - adc_pedestal: 225 + adc_pedestal: 210 dacb: 1 sign_dac: 1 ch_8: From 97e78600d51b3d766d7ba39c9d0e09409a7c49a7 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Tue, 4 Aug 2026 16:47:39 +0000 Subject: [PATCH 15/15] make roc/channel selectors static so multiple runs share choice --- app/tool/trig/watch_run.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/tool/trig/watch_run.cxx b/app/tool/trig/watch_run.cxx index 17676dc7..41fe9a01 100644 --- a/app/tool/trig/watch_run.cxx +++ b/app/tool/trig/watch_run.cxx @@ -30,9 +30,10 @@ void watch_run(pflib::Target* tgt) { return; } - int i_roc = pftool::readline_int("ROC to readout: ", pftool::state.iroc); + static int i_roc = pftool::state.iroc; + i_roc = pftool::readline_int("ROC to readout: ", pftool::state.iroc); - std::string channel_str = "0,1,2,3,4,5,6,7"; + static std::string channel_str = "0,1,2,3,4,5,6,7"; channel_str = pftool::readline( "Comma-separated list of channels in that ROC to readout:", channel_str); std::stringstream channel_stream{channel_str};