Skip to content

feat: add canonical unit vocabulary via mp-units#15

Merged
olantwin merged 2 commits into
mainfrom
feat/units
Jul 14, 2026
Merged

feat: add canonical unit vocabulary via mp-units#15
olantwin merged 2 commits into
mainfrom
feat/units

Conversation

@olantwin

@olantwin olantwin commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Adds SHiP/Units.hpp (canonical quantity types — mm/ns/GeV/GeV-per-c/tesla, with momentum and time-of-flight units derived from the exact speed of light) and SHiP/QuantityView.hpp (free-function views over the data classes), exported as a headers-only SHiP::SHiPUnits target. Persisted structs and dictionary are untouched: ROOT cannot stream quantity members (verified: TStreamerInfo::Build fails, member silently zeroed on readback), so quantities stop at the I/O boundary and conversions are bitwise.

First step of the framework-wide mp-units adoption; aegir bridge headers and the field_service alias re-point follow.

Summary by CodeRabbit

  • New Features
    • Added a canonical, type-safe units system (length/time/energy/momentum and more) with helpers to convert between raw numeric storage and typed quantities.
    • Introduced ship::view accessors providing unit-typed getters/setters for particle and hit fields while preserving the underlying POD layout.
    • Updated the package to require and export the new header-only units interface (based on mp-units v2.5).
  • Tests
    • Added a dedicated CTest (units) validating conversions, round-trips, and ship::view accessor behavior.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc037b78-0121-499d-96fb-98fc86e4de32

📥 Commits

Reviewing files that changed from the base of the PR and between 803dd92 and 516ef88.

📒 Files selected for processing (1)
  • tests/test_units.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_units.cpp

📝 Walkthrough

Walkthrough

Adds an mp-units-based physics unit system with canonical quantity aliases and vector conversions, plus typed accessors over persisted SHiP PODs. It adds the SHiPUnits CMake interface library, propagates the dependency, and introduces unit and quantity-view tests.

Changes

SHiP Units and Quantity Views

Layer / File(s) Summary
Canonical units and conversion helpers
include/SHiP/Units.hpp
Defines SHiP unit constants, canonical quantity aliases, scalar conversion helpers, and Vec3/vecOf/raw conversions.
Quantity views over persisted PODs
include/SHiP/QuantityView.hpp
Adds ship::view getters and setters for unit-typed access to numeric fields of MCParticle, SimHit, SimParticle, and RecParticle.
Build and package integration
CMakeLists.txt, cmake/SHiPDataModelConfig.cmake.in, pixi.toml
Requires mp-units 2.5, defines and installs the SHiPUnits interface target, updates package dependency resolution, and adds the workspace dependency.
Unit and quantity-view validation
tests/CMakeLists.txt, tests/test_units.cpp
Registers a test_units CTest target and checks conversions, dimensional constraints, storage round-trips, and POD-backed quantity views.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: introducing a canonical unit vocabulary based on mp-units.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/units

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

✅ prek hooks passed

@olantwin

olantwin commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
include/SHiP/QuantityView.hpp (1)

17-149: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a template-based approach to reduce repetitive getter/setter boilerplate.

Each of the four types follows the same pattern: scalar getters return p.field * units::U, scalar setters do p.field = v.numerical_value_in(units::U), vector getters use vecOf<T>(p.field), vector setters use raw(v). A template macro or CRTP-based approach could eliminate ~40 lines of near-identical code. However, the current explicit form is readable and debuggable, so this is purely optional.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@include/SHiP/QuantityView.hpp` around lines 17 - 149, The getter/setter
blocks for MCParticle, SimHit, SimParticle, and RecParticle are repeated
boilerplate. Refactor the repeated patterns in ship::view into a template or
CRTP-based helper so scalar fields use the same unit conversion logic and vector
fields reuse the same vecOf/raw handling, while preserving the existing explicit
API names like vertex, momentum, energy, time, and the corresponding set*
functions. Keep the behavior unchanged and only centralize the shared conversion
code to reduce duplication.
tests/test_units.cpp (1)

42-96: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a SimHit setter round-trip test.

MCParticle gets a full getter→setter→equality round-trip (lines 65–78), but SimHit only tests the pathLength getter (lines 80–85). The set* functions in QuantityView.hpp for SimHit (setPosition, setMomentum, setEnergyDeposit, setTime, setPathLength) are untested. A round-trip test mirroring the MCParticle one would catch bitwise-conversion bugs in those code paths.

✨ Suggested addition
   SHiP::SimHit hit;
   hit.position = {-0.5, 0.0, 12000.0};
+  hit.momentum = {0.3, -0.1, 50.0};
+  hit.energyDeposit = 0.025;
+  hit.time = 12.3;
   hit.pathLength = 0.3;
   expect(
       ship::view::pathLength(hit).numerical_value_in(su::mm) == hit.pathLength,
       "SimHit pathLength view is bitwise");
+
+  SHiP::SimHit hitCopy;
+  ship::view::setPosition(hitCopy, ship::view::position(hit));
+  ship::view::setMomentum(hitCopy, ship::view::momentum(hit));
+  ship::view::setEnergyDeposit(hitCopy, ship::view::energyDeposit(hit));
+  ship::view::setTime(hitCopy, ship::view::time(hit));
+  ship::view::setPathLength(hitCopy, ship::view::pathLength(hit));
+  expect(hitCopy.position == hit.position && hitCopy.momentum == hit.momentum &&
+             hitCopy.energyDeposit == hit.energyDeposit &&
+             hitCopy.time == hit.time && hitCopy.pathLength == hit.pathLength,
+         "SimHit view round-trip is bitwise");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_units.cpp` around lines 42 - 96, The SimHit quantity-view setters
are not covered, so add a getter-to-setter round-trip test for SimHit in main
that mirrors the MCParticle check. Use ship::view::position, momentum,
energyDeposit, time, and pathLength together with the corresponding
ship::view::setPosition, setMomentum, setEnergyDeposit, setTime, and
setPathLength helpers, then assert the copied SimHit matches the original
bitwise. This will locate the missing coverage in the existing SimHit test block
and exercise the setter paths in QuantityView.hpp.
cmake/SHiPDataModelConfig.cmake.in (1)

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider specifying version and mode in find_dependency(mp-units).

CMakeLists.txt requires mp-units 2.5 CONFIG REQUIRED, but the config template uses a bare find_dependency(mp-units). A downstream consumer with an older mp-units that lacks the APIs used by Units.hpp would get a configure-time failure in the imported targets rather than a clear dependency-resolution error. Adding 2.5 CONFIG makes the contract explicit.

♻️ Proposed fix
-find_dependency(mp-units)
+find_dependency(mp-units 2.5 CONFIG)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmake/SHiPDataModelConfig.cmake.in` at line 5, The dependency declaration in
the config template is too loose: `find_dependency(mp-units)` should match the
explicit requirement used by the project. Update the `find_dependency` call in
the CMake package config template to request `mp-units` version 2.5 in CONFIG
mode, so downstream consumers fail during dependency resolution instead of later
in `Units.hpp`-related target usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@cmake/SHiPDataModelConfig.cmake.in`:
- Line 5: The dependency declaration in the config template is too loose:
`find_dependency(mp-units)` should match the explicit requirement used by the
project. Update the `find_dependency` call in the CMake package config template
to request `mp-units` version 2.5 in CONFIG mode, so downstream consumers fail
during dependency resolution instead of later in `Units.hpp`-related target
usage.

In `@include/SHiP/QuantityView.hpp`:
- Around line 17-149: The getter/setter blocks for MCParticle, SimHit,
SimParticle, and RecParticle are repeated boilerplate. Refactor the repeated
patterns in ship::view into a template or CRTP-based helper so scalar fields use
the same unit conversion logic and vector fields reuse the same vecOf/raw
handling, while preserving the existing explicit API names like vertex,
momentum, energy, time, and the corresponding set* functions. Keep the behavior
unchanged and only centralize the shared conversion code to reduce duplication.

In `@tests/test_units.cpp`:
- Around line 42-96: The SimHit quantity-view setters are not covered, so add a
getter-to-setter round-trip test for SimHit in main that mirrors the MCParticle
check. Use ship::view::position, momentum, energyDeposit, time, and pathLength
together with the corresponding ship::view::setPosition, setMomentum,
setEnergyDeposit, setTime, and setPathLength helpers, then assert the copied
SimHit matches the original bitwise. This will locate the missing coverage in
the existing SimHit test block and exercise the setter paths in
QuantityView.hpp.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9d1f163-b248-4bfd-b8fc-dcbc74ae7225

📥 Commits

Reviewing files that changed from the base of the PR and between 543f568 and 616b4c8.

⛔ Files ignored due to path filters (1)
  • pixi.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • CMakeLists.txt
  • cmake/SHiPDataModelConfig.cmake.in
  • include/SHiP/QuantityView.hpp
  • include/SHiP/Units.hpp
  • pixi.toml
  • tests/CMakeLists.txt
  • tests/test_units.cpp

Introduce SHiP/Units.hpp (canonical quantity types: mm, ns, GeV, GeV/c,
tesla, with momentum and time-of-flight units derived from the exact
speed of light) and SHiP/QuantityView.hpp (free-function views that
convert the plain-double data classes to and from quantities), exported
as the headers-only SHiP::SHiPUnits target.

The persisted structs are unchanged: ROOT cannot stream mp-units
quantity members (TStreamerInfo::Build fails and the member is silently
zeroed on readback), so quantities stop at the I/O boundary by design.
Computation code works in quantity types; conversions to and from
storage are bitwise because the storage unit is the quantity unit.
@olantwin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@olantwin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@include/SHiP/QuantityView.hpp`:
- Around line 68-129: Add round-trip coverage in tests/test_units.cpp for the
SimParticle and RecParticle quantity views, exercising each getter/setter pair
exposed by vertex, endpoint, momentum, energy, and time, plus ipPV and setIpPV
for RecParticle. Verify values written through setters are returned unchanged by
the corresponding accessors, including the unique endpoint and ipPV fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a5b8441-4f85-47d0-9280-6ab4dce34207

📥 Commits

Reviewing files that changed from the base of the PR and between 616b4c8 and 803dd92.

⛔ Files ignored due to path filters (1)
  • pixi.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • CMakeLists.txt
  • cmake/SHiPDataModelConfig.cmake.in
  • include/SHiP/QuantityView.hpp
  • include/SHiP/Units.hpp
  • pixi.toml
  • tests/CMakeLists.txt
  • tests/test_units.cpp
🚧 Files skipped from review as they are similar to previous changes (6)
  • cmake/SHiPDataModelConfig.cmake.in
  • pixi.toml
  • tests/CMakeLists.txt
  • tests/test_units.cpp
  • CMakeLists.txt
  • include/SHiP/Units.hpp

Comment thread include/SHiP/QuantityView.hpp
@olantwin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@olantwin
olantwin merged commit 090d3ac into main Jul 14, 2026
4 checks passed
@olantwin
olantwin deleted the feat/units branch July 14, 2026 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant