Skip to content

Xinyue/testapp p2#38

Open
xinyue-uoft wants to merge 31 commits intodevelopfrom
xinyue/testapp_p2
Open

Xinyue/testapp p2#38
xinyue-uoft wants to merge 31 commits intodevelopfrom
xinyue/testapp_p2

Conversation

@xinyue-uoft
Copy link
Contributor

Description

See issue #21 for motivation and overview.

This PR adds a standalone TPGenerator test application and the supporting test infrastructure needed to validate TPGenerator algorithms offline, independently of the full DAQ system. The new test app follows the same pattern as the existing test_tpg_processor_app.cxx (single processor test application), but is focused on end‑to‑end verification of TPGenerator using frame format data and binary validation files.

Main changes:
• New TPGenerator test application (test_tpg_generator_app.cxx)
• Implements a CLI test app (installed as tpglibs_generator_test) that:
• Reads binary input frames from a .bin file using FrameReader.
• Adapts them to DUMMY_FRAME_STRUCT via DummyFrameAdapter so they are compatible with TPGenerator.
• Configures TPGenerator from a JSON config (processor_configs, channel_plane_mappings, test_config)(same format as actual config)
• Runs frames through TPGenerator and collects output TriggerPrimitives.
• (Can also turn off optionally) validates the output against a .val validation file using TPReader + TPComparator.
• BinaryFormatSpecification.md and example README are updated to describe the TP binary format, header, sort order, and concrete usage of the new test app and datasets.

Type of change

  • Documentation (non-breaking change that adds or improves the documentation)
  • New feature or enhancement (non-breaking change which adds functionality)
  • Optimization (non-breaking change that improves code/performance)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (whatever its nature)

Testing checklist

  • Unit tests pass (e.g. dbt-build --unittest)
  • Minimal system quicktest passes (pytest -s minimal_system_quick_test.py)
  • Full set of integration tests pass (daqsystemtest_integtest_bundle.sh)
  • Python tests pass if applicable (e.g. python -m pytest)
  • Pre-commit hooks run successfully if applicable (e.g. pre-commit run --all-files)

This is a completely standalone test application that does not interfere with DAQ software. Test is mainly done by unit tests directed to the test application infrastructure. Two simple test cases are developed and tested, where the test application behaves as expected: 1. an all zero input sanity check, no tp 2. a square wave in a single adc channel, with tp also localized to single channel.

Further checks

  • Code is commented where needed, particularly in hard-to-understand areas
  • Code style is correct (dbt-build --lint, and/or see https://dune-daq-sw.readthedocs.io/en/latest/packages/styleguide/)
  • If applicable, new tests have been added or an issue has been opened to tackle that in the future.
    (Indicate issue here: # (issue))

@xinyue-uoft
Copy link
Contributor Author

Eventually plan is to add the binary files and config for the two sanity type tests to DUNE asset system. To allow reviewers to perform independent tests for this PR, I will post them here together with their generation script soon.

@xinyue-uoft xinyue-uoft self-assigned this Dec 2, 2025
@xinyue-uoft xinyue-uoft added the enhancement New feature or request label Dec 2, 2025
@xinyue-uoft xinyue-uoft linked an issue Dec 2, 2025 that may be closed by this pull request
@xinyue-uoft
Copy link
Contributor Author

I have temporarily included the two test binary + config + validation file generation script for the following three test cases. We can remove them after review if they shouldn't go into tpglibs.

Test Patterns and Expected TP Presence

This summarizes which frames/channels are expected to have TPs for the sanity, multiframe, and golden test.


1. Sanity test (tpg_generator_sanity_*)

Input: All ADC values are below threshold.

Frame Channels with TP Notes
0 none No threshold crossings

2. Multi-frame test (tpg_generator_multiframe_*)

Frame Channels with TP Notes
0 ch 0 Single spike region in channel 0
1 none All zeros
2 ch 16 Single spike region in channel 16
3 none All zeros
4 ch 0, ch 16, ch 32, ch 48 Four independent spike regions

Each spike region is contiguous within one channel, so each listed channel generates exactly one TP.


3. Golden test (tpg_generator_golden_*)

Frame Channels with TP Notes
0 ch 0 Single spike region in channel 0
1 none All zeros

@xinyue-uoft xinyue-uoft requested a review from aeoranday December 5, 2025 09:30
Copy link
Member

@aeoranday aeoranday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not tested the functionality of this PR yet. This is only a result of reading with various style and design comments, questions, and suggestions.

One major comment is the header-only design of the test application files. Since none of the classes are general and require header-only, I would suggest that these get separated into the include­–source structure.

I'll test after these changes. One aspect I'm concerned about is the 16 b dynamic range in the dummy frame which does not match the expected 14 b signal. Since most of the applied data is composed of 0s, I would believe these "passed", but I believe high-valued testing would start to break.


## 3. Test File Examples
**Key Fields in TriggerPrimitive** (for reference):
- `time_start` (int64_t): Timestamp when TP starts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `time_start` (int64_t): Timestamp when TP starts
- `time_start` (uint64_t): Timestamp when TP starts

class BinaryFileValidator {
public:
static constexpr uint32_t MAGIC_NUMBER = 0x54504754; ///< "TPGT"
static constexpr uint32_t VERSION = 0x010004; ///< 1.0.4 in hex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this version derived from? Is this the tpglibs version at the time of this creation? We cannot keep this number up-to-date with the tpglibs version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed the version at creation. The hope is to create a marker for backward compatibility. The original goal is that in the future if there is a breaking change to the format of the binary files, then we update this value here to mark the end of compatibility with previously generated files.

Maybe we can just keep this independent of tpglibs version?

// Amplitude: threshold + 100
constexpr int16_t SPIKE_ADC_DELTA_ABOVE_THRESHOLD = 100;

// TPGenerator detects the TP when processing t = 106 in this setup
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TPGenerator generates the TP at t = 106. It detects it starting at t = 100 in this case.

Comment on lines +75 to +76
* @brief Calculate absolute timestamp for TP time_start
* Formula matches TPGenerator: (t - samples_over_threshold) * sample_tick_difference + timestamp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on this description, this test verifies that the TP generated is equivalent to an expected TP.

However, the objective for creating these tests seems to want to validate that the generated TP is expected for the known signal. The TP's time_start should be SPIKE_START_SAMPLE * SAMPLE_TICK_DIFFERENCE + frame_timestamp since we want to know that we are accurately representing the injected signal that we control.

Since the TPGenerator (in the current state) is consistent between verification and validation, the comparison appears the same (at the moment), but we should really be aiming for the second case.

┌─────────────────────┐
│ Frame Header │ (16 bytes)
│ - timestamp (8) │ uint64_t: Frame timestamp
│ - another_key (8) │ uint64_t: Additional header field
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have this? I see later that you set it to an arbitrary value, so it seems like this is not necessary for our purposes. I'm aware the reference has it, but the value is relevant for them.

Copy link
Contributor Author

@xinyue-uoft xinyue-uoft Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it is not really used here. It is purely carried over from the reference. Will be removed.

Copy link
Member

@aeoranday aeoranday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Missed this on previous review submission.)

Copy link
Contributor

@alessandrothea alessandrothea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work.
I did not have the time to look into the code.
The comments about naming conventions: in general I would trade the use of dummy and test words for something more specific to the purpose of the application, which is the validation of the tpg chain by regression tests involving generation and comparison to reference patterns.

static constexpr int16_t s_adc_min_value = 0; // 0 - 14-bit min

uint64_t timestamp; ///< Frame timestamp (8 bytes)
uint64_t another_key; ///< Additional header field (8 bytes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another_key seems a bit random. Something likeheader is more to the point

Copy link
Contributor Author

@xinyue-uoft xinyue-uoft Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was mentioned by Alejandro above. It is a carry over artifact from the original dummy frame definition https://github.com/DUNE-DAQ/datahandlinglibs/blob/develop/include/datahandlinglibs/ReadoutTypes.hpp that was referenced. Will be removed soon.

daq_add_application(tpglibs_generator_test test_tpg_generator_app.cxx TEST LINK_LIBRARIES tpglibs)

# Add golden test data generator utility
daq_add_application(generate_golden_test_data generate_golden_test_data.cxx TEST LINK_LIBRARIES tpglibs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Golden test data" is a little, how to say, mysterious.
What is golden? What test?
I would rather talk about reference + data + patterns

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I am planning to remove these generate test scripts before merging this PR. It is better to include the tests in asset system directly.

daq_add_application(generate_golden_test_data generate_golden_test_data.cxx TEST LINK_LIBRARIES tpglibs)

# Add example test files generator utility
daq_add_application(generate_example_tests generate_example_tests.cxx TEST LINK_LIBRARIES tpglibs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this app generate? tests or test data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As explained above, these are temporary.

namespace testapp {

/**
* @brief Dummy frame structure for test applications
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that this is more than a "dummy" frame: this is a reference/minimal 14b dataframe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The naming is more or less carried on from datahandlinglibs calling theirs DUMMY_FRAME_STRUCT.

@alessandrothea
Copy link
Contributor

This is a summary of my comment at yesterday's Readout WG Meeting:

  • inspection of the generated TPs and their analysis (potentially) is an important aspect for preparation of input patterns and debugging issues when detected by the tool
  • my suggestion is to add, if not available already, a way to write output products (TPs) in a format easily consumable by analysis tools (e.g. python, pandas). Being able to inspect input waveforms would be a bonus.
  • Depending on the typical output size, the "analysis" format options could include CSV or HDF5 or...

This enforces DUNE DAQ style guide naming convention for static class data members.
…s matches the actual physical constraint based on frame dimensions (64 channels × 256 time samples).
…mt library was included but never used in active code.
@xinyue-uoft
Copy link
Contributor Author

Addressed the all the review comments left over.

Regarding the comments related to generate_*_data.cxx: Sorry for the confusion, but these files are not really part of this commit. I am including them here for context about the full data flow. The original plan is to directly have the generated configuration and binary files added to the asset management system.

@xinyue-uoft xinyue-uoft requested a review from aeoranday January 20, 2026 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write A Basic Test Application

3 participants