Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ target_sources(
TYPE HEADERS
BASE_DIRS include
FILES
include/SHiP/EventHeader.hpp
include/SHiP/MCParticle.hpp
include/SHiP/SimHit.hpp
include/SHiP/SimParticle.hpp
Expand Down Expand Up @@ -43,6 +44,7 @@ target_link_libraries(SHiPUnits INTERFACE mp-units::mp-units)

root_generate_dictionary(
G__SHiPDataModel
SHiP/EventHeader.hpp
SHiP/MCParticle.hpp
SHiP/SimHit.hpp
SHiP/SimParticle.hpp
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ An [automatic class reference](https://shipsoft.github.io/data-model/) is built

| Header | Class | Category |
|--------|-------|----------|
| `SHiP/EventHeader.hpp` | `SHiP::EventHeader` | Event metadata |
| `SHiP/MCParticle.hpp` | `SHiP::MCParticle` | MC / generation |
| `SHiP/SimHit.hpp` | `SHiP::SimHit` | Simulation |
| `SHiP/SimParticle.hpp` | `SHiP::SimParticle` | Simulation |
Expand Down
25 changes: 25 additions & 0 deletions include/SHiP/EventHeader.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <cstdint>
#include <limits>

namespace SHiP {

// The event weight must be a 64-bit IEEE-754 binary64 value for portable
// I/O. std::float64_t would state this in the type system, but cling does
// not implement __STDCPP_FLOAT64_T__, so it cannot appear in a class that
// needs a ROOT dictionary; this assertion gives the same guarantee.
static_assert(std::numeric_limits<double>::is_iec559 && sizeof(double) == 8,
"EventHeader::weight requires IEEE-754 binary64 double");

/// Per-event metadata — one record per event
struct EventHeader {
double weight{1.0}; ///< Event weight (e.g. P_DIS / nReplicas)
std::int64_t originalEventId{-1}; ///< Originating event id, e.g. the muon
///< event that seeded this replica
///< (-1 = none). Event-level provenance,
///< distinct from MCParticle::motherId,
///< which links particles within an event.
Comment on lines +15 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use the contracted parentEventId member name.

The PR contract specifies parentEventId, but this public record exposes originalEventId. Rename the member and update all producers, consumers, helpers, and round-trip expectations consistently; otherwise downstream code and serialized schemas will observe a different API.

Proposed fix
-  std::int64_t originalEventId{-1};
+  std::int64_t parentEventId{-1};
🤖 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/EventHeader.hpp` around lines 15 - 22, Rename
EventHeader::originalEventId to the contracted parentEventId and update every
producer, consumer, helper, and serialization round-trip expectation to use the
new member consistently. Preserve the existing default value and provenance
semantics while ensuring no references to originalEventId remain in the public
API or related schema handling.

};

} // namespace SHiP
3 changes: 3 additions & 0 deletions include/SHiP/LinkDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#pragma link off all classes;
#pragma link off all functions;

// Event metadata
#pragma link C++ class SHiP::EventHeader+;

// MC / generation
#pragma link C++ class SHiP::MCParticle+;
#pragma link C++ class std::vector<SHiP::MCParticle>+;
Expand Down
6 changes: 6 additions & 0 deletions tests/test_rntuple_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "ROOT/RNTupleModel.hxx"
#include "ROOT/RNTupleReader.hxx"
#include "ROOT/RNTupleWriter.hxx"
#include "SHiP/EventHeader.hpp"
#include "SHiP/MCParticle.hpp"
#include "SHiP/RecParticle.hpp"
#include "SHiP/SimHit.hpp"
Expand All @@ -25,6 +26,7 @@ constexpr char const* kFileName = "test_rntuple_io_tmp.root";

bool writeFile() {
auto model = ROOT::RNTupleModel::Create();
auto eventHeader = model->MakeField<SHiP::EventHeader>("eventHeader");
auto mcParticles =
model->MakeField<std::vector<SHiP::MCParticle>>("mcParticles");
auto simHits = model->MakeField<std::vector<SHiP::SimHit>>("simHits");
Expand All @@ -41,6 +43,7 @@ bool writeFile() {
return false;
}
for (int entry = 0; entry < kEntries; ++entry) {
*eventHeader = SHiP::test::makeEventHeader(entry);
*mcParticles = SHiP::test::makeMCParticles(entry);
*simHits = SHiP::test::makeSimHits(entry);
*simParticles = SHiP::test::makeSimParticles(entry);
Expand All @@ -64,6 +67,7 @@ bool readAndCompare() {
}

auto const& entry = reader->GetModel().GetDefaultEntry();
auto eventHeader = entry.GetPtr<SHiP::EventHeader>("eventHeader");
auto mcParticles = entry.GetPtr<std::vector<SHiP::MCParticle>>("mcParticles");
auto simHits = entry.GetPtr<std::vector<SHiP::SimHit>>("simHits");
auto simParticles =
Expand All @@ -76,6 +80,8 @@ bool readAndCompare() {
for (int i = 0; i < kEntries; ++i) {
reader->LoadEntry(i);
std::string const suffix = " (entry " + std::to_string(i) + ")";
ok &= SHiP::test::check("EventHeader round-trip" + suffix,
SHiP::test::makeEventHeader(i), *eventHeader);
ok &= SHiP::test::check("MCParticle round-trip" + suffix,
SHiP::test::makeMCParticles(i), *mcParticles);
ok &= SHiP::test::check("SimHit round-trip" + suffix,
Expand Down
17 changes: 13 additions & 4 deletions tests/test_ttree_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <string>
#include <vector>

#include "SHiP/EventHeader.hpp"
#include "SHiP/MCParticle.hpp"
#include "SHiP/RecParticle.hpp"
#include "SHiP/SimHit.hpp"
Expand All @@ -26,10 +27,10 @@ constexpr char const* kFileName = "test_ttree_io_tmp.root";
bool checkDictionaries() {
bool ok = true;
for (auto const* name :
{"SHiP::MCParticle", "SHiP::SimHit", "SHiP::SimParticle",
"SHiP::SimResult", "SHiP::RecParticle", "std::vector<SHiP::MCParticle>",
"std::vector<SHiP::SimHit>", "std::vector<SHiP::SimParticle>",
"std::vector<SHiP::RecParticle>"}) {
{"SHiP::EventHeader", "SHiP::MCParticle", "SHiP::SimHit",
"SHiP::SimParticle", "SHiP::SimResult", "SHiP::RecParticle",
"std::vector<SHiP::MCParticle>", "std::vector<SHiP::SimHit>",
"std::vector<SHiP::SimParticle>", "std::vector<SHiP::RecParticle>"}) {
if (TClass::GetClass(name) == nullptr) {
std::cout << "dictionary for " << name
<< ": FAIL (TClass::GetClass is null)\n";
Expand All @@ -49,19 +50,22 @@ bool writeFile() {
}
TTree tree("events", "SHiP data model I/O test");

SHiP::EventHeader eventHeader;
std::vector<SHiP::MCParticle> mcParticles;
std::vector<SHiP::SimHit> simHits;
std::vector<SHiP::SimParticle> simParticles;
std::vector<SHiP::RecParticle> recParticles;
SHiP::SimResult simResult;

tree.Branch("eventHeader", &eventHeader);
tree.Branch("mcParticles", &mcParticles);
tree.Branch("simHits", &simHits);
tree.Branch("simParticles", &simParticles);
tree.Branch("recParticles", &recParticles);
tree.Branch("simResult", &simResult);

for (int entry = 0; entry < kEntries; ++entry) {
eventHeader = SHiP::test::makeEventHeader(entry);
mcParticles = SHiP::test::makeMCParticles(entry);
simHits = SHiP::test::makeSimHits(entry);
simParticles = SHiP::test::makeSimParticles(entry);
Expand Down Expand Up @@ -90,12 +94,14 @@ bool readAndCompare() {
return false;
}

auto* eventHeader = new SHiP::EventHeader();
auto* mcParticles = new std::vector<SHiP::MCParticle>();
auto* simHits = new std::vector<SHiP::SimHit>();
auto* simParticles = new std::vector<SHiP::SimParticle>();
auto* recParticles = new std::vector<SHiP::RecParticle>();
auto* simResult = new SHiP::SimResult();

tree->SetBranchAddress("eventHeader", &eventHeader);
tree->SetBranchAddress("mcParticles", &mcParticles);
tree->SetBranchAddress("simHits", &simHits);
tree->SetBranchAddress("simParticles", &simParticles);
Expand All @@ -106,6 +112,8 @@ bool readAndCompare() {
for (int entry = 0; entry < kEntries; ++entry) {
tree->GetEntry(entry);
std::string const suffix = " (entry " + std::to_string(entry) + ")";
ok &= SHiP::test::check("EventHeader round-trip" + suffix,
SHiP::test::makeEventHeader(entry), *eventHeader);
ok &= SHiP::test::check("MCParticle round-trip" + suffix,
SHiP::test::makeMCParticles(entry), *mcParticles);
ok &= SHiP::test::check("SimHit round-trip" + suffix,
Expand All @@ -119,6 +127,7 @@ bool readAndCompare() {
}

tree->ResetBranchAddresses();
delete eventHeader;
delete mcParticles;
delete simHits;
delete simParticles;
Expand Down
13 changes: 13 additions & 0 deletions tests/test_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <vector>

#include "SHiP/EventHeader.hpp"
#include "SHiP/MCParticle.hpp"
#include "SHiP/RecParticle.hpp"
#include "SHiP/SimHit.hpp"
Expand All @@ -13,6 +14,14 @@

namespace SHiP::test {

/// Build an EventHeader with distinctive non-default values in every member.
inline EventHeader makeEventHeader(int offset) {
EventHeader h;
h.weight = 0.125 + offset;
h.originalEventId = 7000 + offset;
return h;
}

/// Build MCParticles with distinctive non-default values in every member.
inline std::vector<MCParticle> makeMCParticles(int offset) {
std::vector<MCParticle> v;
Expand Down Expand Up @@ -84,6 +93,10 @@ inline SimResult makeSimResult(int offset) {
.particles = makeSimParticles(offset + 5)};
}

inline bool equal(EventHeader const& a, EventHeader const& b) {
return a.weight == b.weight && a.originalEventId == b.originalEventId;
}

inline bool equal(MCParticle const& a, MCParticle const& b) {
return a.pdgCode == b.pdgCode && a.vertex == b.vertex &&
a.momentum == b.momentum && a.energy == b.energy && a.time == b.time &&
Expand Down
Loading