Skip to content

feat(dd4hep): add experimental DDG4 integration plugins and examples#266

Merged
plexoos merged 46 commits intomainfrom
dd4hep_integration
Apr 12, 2026
Merged

feat(dd4hep): add experimental DDG4 integration plugins and examples#266
plexoos merged 46 commits intomainfrom
dd4hep_integration

Conversation

@ggalgoczi
Copy link
Copy Markdown
Contributor

Adds DD4hep plugin layer (dd4hepplugins/) and a raindrop example geometry to
run optical photon simulation through the DD4hep framework, both on CPU
(Geant4) and GPU (simphony).

ggalgoczi added 25 commits March 5, 2026 13:49
Removed license header from OpticsEvent.cc
Removed license header and brief description from OpticsEvent.hh
Removed license header and comments related to SEvt initialization.
Removed license header and brief description from OpticsSteppingAction.hh
Implement raindrop detector geometry for DD4hep with nested volumes and optical surfaces.
Add CMake configuration for DD4hep example
…rectory

When DD4hep is found, dd4hepplugins is built in-tree alongside the rest of
eic-opticks. The plugins CMakeLists.txt now detects whether it is being built
standalone (find_package(eic-opticks)) or in-tree (uses local target names)
so it works in both modes.
U4SensorIdentifierDefault::getInstanceIdentity required the physical
volume name to contain "PMT" to be recognized as a sensor. This is a
JUNO-specific assumption that breaks any detector using non-PMT sensors
(e.g. dRICH SiPMs). A volume with a G4VSensitiveDetector attached is a
sensor regardless of its name.
Replace hardcoded spack hashes and absolute paths with portable
alternatives: compact file resolved relative to the script location,
ROOT/DD4hep python paths expected on PYTHONPATH from the activated
spack environment, DD4hepINSTALL read from the environment.
Add examples/dd4hep as a subdirectory in the DD4hep conditional block
so libRaindropGeo.so builds and installs alongside libddeicopticks.so.
Fix examples/dd4hep/CMakeLists.txt which contained prose mixed with
cmake commands and was not valid.
- Move sensitive volume from water drop to lead container (CtPMT)
- Move border surface from water/air to air/lead with EFFICIENCY=1.0
- Remove all scintillation properties from OpWater
- Add ABSLENGTH to OpLead (1mm)
- CPU test: use Geant4OpticalTrackerAction + BoundaryInvokeSD=true
- GPU test: add OpticsSteppingAction, fix gun isotrop
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Cpp-linter Review

Used clang-format v20.1.2

Only 73 out of 74 clang-format concerns fit within this pull request's diff.

Click here for the full clang-format patch
diff --git a/dd4hepplugins/OpticsEvent.cc b/dd4hepplugins/OpticsEvent.cc
index 6325aec..63cea33 100644
--- a/dd4hepplugins/OpticsEvent.cc
+++ b/dd4hepplugins/OpticsEvent.cc
@@ -4,0 +5 @@
+#include <DDG4/Geant4Context.h>
@@ -8 +8,0 @@
-#include <DDG4/Geant4Context.h>
@@ -13,3 +12,0 @@
-#include <SEvt.hh>
-#include <SComp.h>
-#include <sphoton.h>
@@ -17,0 +15,3 @@
+#include <SComp.h>
+#include <SEvt.hh>
+#include <sphoton.h>
@@ -22,2 +22 @@ namespace ddeicopticks
-OpticsEvent::OpticsEvent(dd4hep::sim::Geant4Context* ctxt,
-                         std::string const& name)
+OpticsEvent::OpticsEvent(dd4hep::sim::Geant4Context *ctxt, std::string const &name)
@@ -37 +36 @@ OpticsEvent::~OpticsEvent()
-void OpticsEvent::begin(G4Event const* event)
+void OpticsEvent::begin(G4Event const *event)
@@ -47 +46 @@ void OpticsEvent::begin(G4Event const* event)
-    SEvt* sev = SEvt::Get_EGPU();
+    SEvt *sev = SEvt::Get_EGPU();
@@ -55 +54 @@ void OpticsEvent::begin(G4Event const* event)
-void OpticsEvent::end(G4Event const* event)
+void OpticsEvent::end(G4Event const *event)
@@ -59 +58 @@ void OpticsEvent::end(G4Event const* event)
-    G4CXOpticks* gx = G4CXOpticks::Get();
+    G4CXOpticks *gx = G4CXOpticks::Get();
@@ -66 +65 @@ void OpticsEvent::end(G4Event const* event)
-    SEvt* sev = SEvt::Get_EGPU();
+    SEvt *sev = SEvt::Get_EGPU();
@@ -78,3 +77 @@ void OpticsEvent::end(G4Event const* event)
-        info("Event #%d: %lld gensteps, %lld photons to simulate",
-             eventID,
-             static_cast<long long>(num_genstep),
+        info("Event #%d: %lld gensteps, %lld photons to simulate", eventID, static_cast<long long>(num_genstep),
@@ -109,3 +106 @@ void OpticsEvent::end(G4Event const* event)
-void OpticsEvent::injectHits(G4Event const* event,
-                             SEvt* sev,
-                             unsigned num_hit)
+void OpticsEvent::injectHits(G4Event const *event, SEvt *sev, unsigned num_hit)
@@ -113 +107,0 @@ void OpticsEvent::injectHits(G4Event const* event,
-    using dd4hep::sim::Geant4SensDetSequences;
@@ -114,0 +109 @@ void OpticsEvent::injectHits(G4Event const* event,
+    using dd4hep::sim::Geant4SensDetSequences;
@@ -119,2 +114,2 @@ void OpticsEvent::injectHits(G4Event const* event,
-    Geant4SensDetSequences& sens = context()->sensitiveActions();
-    auto const& seqs = sens.sequences();
+    Geant4SensDetSequences &sens = context()->sensitiveActions();
+    auto const &seqs = sens.sequences();
@@ -125 +120,2 @@ void OpticsEvent::injectHits(G4Event const* event,
-                "call setupTracker() in steering script", eventID);
+                "call setupTracker() in steering script",
+                eventID);
@@ -129 +125 @@ void OpticsEvent::injectHits(G4Event const* event,
-    for (auto const& [det_name, seq] : seqs)
+    for (auto const &[det_name, seq] : seqs)
@@ -131 +127 @@ void OpticsEvent::injectHits(G4Event const* event,
-        Geant4HitCollection* coll = seq->collection(0);
+        Geant4HitCollection *coll = seq->collection(0);
@@ -142,2 +138 @@ void OpticsEvent::injectHits(G4Event const* event,
-        info("Event #%d: injected %u hits into '%s' collection",
-             eventID, num_hit, det_name.c_str());
+        info("Event #%d: injected %u hits into '%s' collection", eventID, num_hit, det_name.c_str());
@@ -148,2 +143 @@ void OpticsEvent::injectHits(G4Event const* event,
-dd4hep::sim::Geant4Tracker::Hit*
-OpticsEvent::createTrackerHit(sphoton const& ph)
+dd4hep::sim::Geant4Tracker::Hit *OpticsEvent::createTrackerHit(sphoton const &ph)
@@ -153 +147 @@ OpticsEvent::createTrackerHit(sphoton const& ph)
-    auto* hit = new Geant4Tracker::Hit();
+    auto *hit = new Geant4Tracker::Hit();
@@ -177 +171 @@ OpticsEvent::createTrackerHit(sphoton const& ph)
-}  // namespace ddeicopticks
+} // namespace ddeicopticks
diff --git a/dd4hepplugins/OpticsEvent.hh b/dd4hepplugins/OpticsEvent.hh
index 38c30df..770cf8f 100644
--- a/dd4hepplugins/OpticsEvent.hh
+++ b/dd4hepplugins/OpticsEvent.hh
@@ -3 +2,0 @@
-#include <string>
@@ -5 +3,0 @@
-#include <DDG4/Geant4EventAction.h>
@@ -6,0 +5,2 @@
+#include <DDG4/Geant4EventAction.h>
+#include <string>
@@ -31 +31 @@ class OpticsEvent final : public dd4hep::sim::Geant4EventAction
-    OpticsEvent(dd4hep::sim::Geant4Context* ctxt, std::string const& name);
+    OpticsEvent(dd4hep::sim::Geant4Context *ctxt, std::string const &name);
@@ -33,2 +33,2 @@ class OpticsEvent final : public dd4hep::sim::Geant4EventAction
-    void begin(G4Event const* event) final;
-    void end(G4Event const* event) final;
+    void begin(G4Event const *event) final;
+    void end(G4Event const *event) final;
@@ -41,2 +41,2 @@ class OpticsEvent final : public dd4hep::sim::Geant4EventAction
-    void injectHits(G4Event const* event, SEvt* sev, unsigned num_hit);
-    static dd4hep::sim::Geant4Tracker::Hit* createTrackerHit(sphoton const& ph);
+    void injectHits(G4Event const *event, SEvt *sev, unsigned num_hit);
+    static dd4hep::sim::Geant4Tracker::Hit *createTrackerHit(sphoton const &ph);
@@ -48 +48 @@ class OpticsEvent final : public dd4hep::sim::Geant4EventAction
-}  // namespace ddeicopticks
+} // namespace ddeicopticks
diff --git a/dd4hepplugins/OpticsPhysics.cc b/dd4hepplugins/OpticsPhysics.cc
index 2b7e68f..037c10e 100644
--- a/dd4hepplugins/OpticsPhysics.cc
+++ b/dd4hepplugins/OpticsPhysics.cc
@@ -6,3 +5,0 @@
-#include <G4ParticleTable.hh>
-#include <G4ProcessManager.hh>
-#include <G4OpticalPhoton.hh>
@@ -10 +6,0 @@
-#include <G4OpRayleigh.hh>
@@ -11,0 +8,4 @@
+#include <G4OpRayleigh.hh>
+#include <G4OpticalPhoton.hh>
+#include <G4ParticleTable.hh>
+#include <G4ProcessManager.hh>
@@ -13 +12,0 @@
-#include <Local_G4Cerenkov_modified.hh>
@@ -14,0 +14 @@
+#include <Local_G4Cerenkov_modified.hh>
@@ -19,2 +19 @@ namespace ddeicopticks
-OpticsPhysics::OpticsPhysics(dd4hep::sim::Geant4Context* ctxt,
-                             std::string const& name)
+OpticsPhysics::OpticsPhysics(dd4hep::sim::Geant4Context *ctxt, std::string const &name)
@@ -37 +36 @@ OpticsPhysics::~OpticsPhysics()
-void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
+void OpticsPhysics::constructProcesses(G4VUserPhysicsList * /* physics */)
@@ -42 +41 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-    auto* cerenkov = new Local_G4Cerenkov_modified;
+    auto *cerenkov = new Local_G4Cerenkov_modified;
@@ -48 +47 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-    auto* scintillation = new Local_DsG4Scintillation(opticks_mode_);
+    auto *scintillation = new Local_DsG4Scintillation(opticks_mode_);
@@ -52,3 +51,3 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-    auto* absorption = new G4OpAbsorption;
-    auto* rayleigh = new G4OpRayleigh;
-    auto* boundary = new G4OpBoundaryProcess;
+    auto *absorption = new G4OpAbsorption;
+    auto *rayleigh = new G4OpRayleigh;
+    auto *boundary = new G4OpBoundaryProcess;
@@ -56,3 +55 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-    info("  Cerenkov: MaxPhotons=%d MaxBeta=%.1f TrackFirst=�����-��� ;�"�~���U� ��������������������
-         max_beta_change_per_step_,
+    info("  Cerenkov: MaxPhotons=%d MaxBeta=%.1f TrackFirst=%s", max_num_photons_per_step_, max_beta_change_per_step_,
@@ -66,2 +63,2 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-    auto* particleTable = G4ParticleTable::GetParticleTable();
-    auto* particleIterator = particleTable->GetIterator();
+    auto *particleTable = G4ParticleTable::GetParticleTable();
+    auto *particleIterator = particleTable->GetIterator();
@@ -72,2 +69,2 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-        G4ParticleDefinition* particle = particleIterator->value();
-        G4ProcessManager* pmanager = particle->GetProcessManager();
+        G4ParticleDefinition *particle = particleIterator->value();
+        G4ProcessManager *pmanager = particle->GetProcessManager();
@@ -84,2 +81 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-        if (scintillation->IsApplicable(*particle)a-
�������U� ���� ;�"�~������������������photon")
+        if (scintillation->IsApplicable(*particle) && particleName != "opticalphoton")
@@ -110 +106 @@ void OpticsPhysics::constructProcesses(G4VUserPhysicsList* /* physics */)
-}  // namespace ddeicopticks
+} // namespace ddeicopticks
diff --git a/dd4hepplugins/OpticsPhysics.hh b/dd4hepplugins/OpticsPhysics.hh
index 47e243d..6aeae9c 100644
--- a/dd4hepplugins/OpticsPhysics.hh
+++ b/dd4hepplugins/OpticsPhysics.hh
@@ -3 +2,0 @@
-#include <string>
@@ -5,0 +5 @@
+#include <string>
@@ -33 +33 @@ class OpticsPhysics final : public dd4hep::sim::Geant4PhysicsList
-    OpticsPhysics(dd4hep::sim::Geant4Context* ctxt, std::string const& name);
+    OpticsPhysics(dd4hep::sim::Geant4Context *ctxt, std::string const &name);
@@ -35 +35 @@ class OpticsPhysics final : public dd4hep::sim::Geant4PhysicsList
-    void constructProcesses(G4VUserPhysicsList* physics) final;
+    void constructProcesses(G4VUserPhysicsList *physics) final;
@@ -49 +49 @@ class OpticsPhysics final : public dd4hep::sim::Geant4PhysicsList
-}  // namespace ddeicopticks
+} // namespace ddeicopticks
diff --git a/dd4hepplugins/OpticsRun.cc b/dd4hepplugins/OpticsRun.cc
index 6e249a4..bdd312f 100644
--- a/dd4hepplugins/OpticsRun.cc
+++ b/dd4hepplugins/OpticsRun.cc
@@ -10 +9,0 @@
-#include <SEvt.hh>
@@ -11,0 +11 @@
+#include <SEvt.hh>
@@ -16,2 +16 @@ namespace ddeicopticks
-OpticsRun::OpticsRun(dd4hep::sim::Geant4Context* ctxt,
-                     std::string const& name)
+OpticsRun::OpticsRun(dd4hep::sim::Geant4Context *ctxt, std::string const &name)
@@ -31 +30 @@ OpticsRun::~OpticsRun()
-void OpticsRun::begin(G4Run const* run)
+void OpticsRun::begin(G4Run const *run)
@@ -33 +32 @@ void OpticsRun::begin(G4Run const* run)
-    G4VPhysicalVolume* world = context()->world();
+    G4VPhysicalVolume *world = context()->world();
@@ -44,2 +43 @@ void OpticsRun::begin(G4Run const* run)
-    info("HasDevice=%s, IntegrationMode=%d", hasDevice ? "YES" : "NO",
-         SEventConfig::IntegrationMode());
+    info("HasDevice=%s, IntegrationMode=%d", hasDevice ? "YES" : "NO", SEventConfig::IntegrationMode());
@@ -58 +56 @@ void OpticsRun::begin(G4Run const* run)
-void OpticsRun::end(G4Run const* run)
+void OpticsRun::end(G4Run const *run)
@@ -65 +63 @@ void OpticsRun::end(G4Run const* run)
-}  // namespace ddeicopticks
+} // namespace ddeicopticks
diff --git a/dd4hepplugins/OpticsRun.hh b/dd4hepplugins/OpticsRun.hh
index b657d9c..a9fec1e 100644
--- a/dd4hepplugins/OpticsRun.hh
+++ b/dd4hepplugins/OpticsRun.hh
@@ -3 +2,0 @@
-#include <string>
@@ -5,0 +5 @@
+#include <string>
@@ -24 +24 @@ class OpticsRun final : public dd4hep::sim::Geant4RunAction
-    OpticsRun(dd4hep::sim::Geant4Context* ctxt, std::string const& name);
+    OpticsRun(dd4hep::sim::Geant4Context *ctxt, std::string const &name);
@@ -26,2 +26,2 @@ class OpticsRun final : public dd4hep::sim::Geant4RunAction
-    void begin(G4Run const* run) final;
-    void end(G4Run const* run) final;
+    void begin(G4Run const *run) final;
+    void end(G4Run const *run) final;
@@ -38 +38 @@ class OpticsRun final : public dd4hep::sim::Geant4RunAction
-}  // namespace ddeicopticks
+} // namespace ddeicopticks
diff --git a/examples/dd4hep/geometry/Raindrop_geo.cpp b/examples/dd4hep/geometry/Raindrop_geo.cpp
index 191115c..5ba79aa 100644
--- a/examples/dd4hep/geometry/Raindrop_geo.cpp
+++ b/examples/dd4hep/geometry/Raindrop_geo.cpp
@@ -7,0 +8 @@
+#include <DD4hep/Detector.h>
@@ -10 +10,0 @@
-#include <DD4hep/Detector.h>
@@ -14 +14 @@ using namespace dd4hep;
-static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector sens)
+static Ref_t create_raindrop(Detector &description, xml_h e, SensitiveDetector sens)
@@ -16,3 +16,3 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    xml_det_t   x_det = e;
-    std::string name  = x_det.nameStr();
-    DetElement  sdet(name, x_det.id());
+    xml_det_t x_det = e;
+    std::string name = x_det.nameStr();
+    DetElement sdet(name, x_det.id());
@@ -22,2 +22,2 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    xml_det_t x_medium    = x_det.child(_Unicode(medium));
-    xml_det_t x_drop      = x_det.child(_Unicode(drop));
+    xml_det_t x_medium = x_det.child(_Unicode(medium));
+    xml_det_t x_drop = x_det.child(_Unicode(drop));
@@ -26,3 +26,2 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    Box    container_box(x_container.x(), x_container.y(), x_container.z());
-    Volume container_vol("CtPMT", container_box,
-                         description.material(x_container.attr<std::string>(_U(material))));
+    Box container_box(x_container.x(), x_container.y(), x_container.z());
+    Volume container_vol("CtPMT", container_box, description.material(x_container.attr<std::string>(_U(material))));
@@ -30,3 +29,2 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    Box    medium_box(x_medium.x(), x_medium.y(), x_medium.z());
-    Volume medium_vol("Md", medium_box,
-                      description.material(x_medium.attr<std::string>(_U(material))));
+    Box medium_box(x_medium.x(), x_medium.y(), x_medium.z());
+    Volume medium_vol("Md", medium_box, description.material(x_medium.attr<std::string>(_U(material))));
@@ -34,3 +32,2 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    Box    drop_box(x_drop.x(), x_drop.y(), x_drop.z());
-    Volume drop_vol("Dr", drop_box,
-                    description.material(x_drop.attr<std::string>(_U(material))));
+    Box drop_box(x_drop.x(), x_drop.y(), x_drop.z());
+    Volume drop_vol("Dr", drop_box, description.material(x_drop.attr<std::string>(_U(material))));
@@ -50 +47 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    PlacedVolume drop_pv   = medium_vol.placeVolume(drop_vol);
+    PlacedVolume drop_pv = medium_vol.placeVolume(drop_vol);
@@ -64,3 +61,3 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    if (surf.isValid()) {
-        BorderSurface bsurf = BorderSurface(description, sdet, "MediumContainer",
-                                            surf, medium_pv, container_pv);
+    if (surf.isValid())
+    {
+        BorderSurface bsurf = BorderSurface(description, sdet, "MediumContainer", surf, medium_pv, container_pv);
@@ -73 +70,2 @@ static Ref_t create_raindrop(Detector& description, xml_h e, SensitiveDetector s
-    if (skinSurf.isValid()) {
+    if (skinSurf.isValid())
+    {
diff --git a/u4/U4SensorIdentifierDefault.h b/u4/U4SensorIdentifierDefault.h
index ae58003..2d451f2 100644
--- a/u4/U4SensorIdentifierDefault.h
+++ b/u4/U4SensorIdentifierDefault.h
@@ -120 +120 @@ inline int U4SensorIdentifierDefault::getInstanceIdentity( const G4VPhysicalVolu
-    bool is_sensor = num_sd > 0 ;
+    bool is_sensor = num_sd > 0;

Have any feedback or feature suggestions? Share it here.

Use standard G4OpticalPhysics (via DDG4 addPhysicsConstructor) instead
of the broken OpticsPhysics plugin whose constructProcesses ran too
late for Geant4 to register Cerenkov/Scintillation on charged particles.

Add OpticsSteppingAction that intercepts standard G4Cerenkov to collect
gensteps for GPU simulation. Add DD4hepSensorIdentifier for SD-based
sensor lookup (replaces env-var GLOBAL_SENSOR_BOUNDARY_LIST approach).
Add Geant4 10.x scintillation property aliases in OpticsRun for Opticks
GPU compatibility.

Remove OpticsPhysics plugin (broken, now unused).

Verified: raindrop DD4hep GPU test produces ~9800-10400 hits/event.
@github-actions github-actions bot dismissed their stale review April 3, 2026 02:53

outdated suggestion

Add benchmark_gpu_speedup.py that quantifies GPU speedup by running
three configurations: CPU with photon tracking, baseline without photon
tracking (SetStackPhotons=false), and GPU via eic-opticks. Measures
wall-clock time per mode and precise GPU simulate() time via chrono
timing added to OpticsEvent::end().
@plexoos
Copy link
Copy Markdown
Member

plexoos commented Apr 3, 2026

I see you added new directories: calibrations/ and fieldmaps/ . Please check.

These symlinks to the EPIC spack install were accidentally committed
during the examples/dd4hep -> dd4hepplugins/examples move.
They are runtime dependencies resolved by DETECTOR_PATH, not source files.

Added calibrations/ and fieldmaps/ to .gitignore.
@plexoos
Copy link
Copy Markdown
Member

plexoos commented Apr 6, 2026

Thanks for moving the new code into dd4hepplugins/. I also noticed that the change in u4/U4SensorIdentifierDefault.h is still part of this PR. Would you mind splitting that into a separate PR as we discussed?

@ggalgoczi
Copy link
Copy Markdown
Contributor Author

Thanks for moving the new code into dd4hepplugins/. I also noticed that the change in u4/U4SensorIdentifierDefault.h is still part of this PR. Would you mind splitting that into a separate PR as we discussed?

Yes, opened it in #275

@plexoos
Copy link
Copy Markdown
Member

plexoos commented Apr 7, 2026

These are all new files, so they need to follow the formatting style policy. I’ve asked Copilot to handle that in PR #277.

@plexoos
Copy link
Copy Markdown
Member

plexoos commented Apr 7, 2026

@ggalgoczi Can you please check if the following are valid findings?

Findings

  • High: PhotonThreshold batching is internally inconsistent and will fail as soon as a batch spans more than one event. begin() only calls SEvt::beginOfEvent once per batch (OpticsEvent.cc#L51, OpticsEvent.cc#L56), but end() and the run flush finalize with the current or last event ID (OpticsEvent.cc#L92, OpticsEvent.cc#L137, OpticsRun.cc#L132, OpticsRun.cc#L149). SEvt::endOfEvent asserts that the end ID matches the ID captured in beginOfEvent (SEvt.cc#L1911, SEvt.cc#L1963, SEvt.cc#L2256). The documented --photon-threshold path is therefore not actually usable.

  • High: GPU-injected DD4hep hits store the wrong sensor identifier. createTrackerHit() writes ph.identity into cellID (OpticsEvent.cc#L213), but Opticks defines that field as sensor_identifier + 1 and provides pmtid() to recover the real sensor id (sphoton.h#L57, sphoton.h#L236, sphoton.h#L238). Every injected hit is therefore off by one, which breaks downstream mapping that relies on DD4hep cellID.

  • Medium: multi-detector and multi-collection routing is not implemented, but the code silently produces wrong output instead of failing. When more than one sensitive sequence exists it only logs a warning (OpticsEvent.cc#L172) and then injects every GPU hit into the first available collection(0) before breaking (OpticsEvent.cc#L182, OpticsEvent.cc#L184, OpticsEvent.cc#L197). Any detector with multiple sensitive actions or multiple output collections will get mis-assigned hits.

Reviewed origin/dd4hep_integration against origin/main. The new Python examples pass python -m py_compile; I did not run the DD4hep/Geant4 integration end-to-end in this environment.

…erge (#277)

New files introduced by the DD4hep integration (PR #266) were not
compliant with the repo's `.clang-format` policy, blocking a clean merge
into `dd4hep_integration` under the `cpp-linter` CI check.

## Changes

- Ran `clang-format --style=file -i` against all 8 new files in
`dd4hepplugins/`:
  - `DD4hepSensorIdentifier.hh`
  - `OpticsEvent.{cc,hh}`
  - `OpticsRun.{cc,hh}`
  - `OpticsSteppingAction.{cc,hh}`
  - `examples/geometry/Raindrop_geo.cpp`

Formatting only — no behavioral or logic changes. Applies the
Microsoft-based style with `ColumnLimit: 0`, `SpaceBeforeParens: Never`,
`SpacesInParentheses: true`, `AlignConsecutiveDeclarations/Assignments:
Consecutive`, and related settings from root `.clang-format`.


Co-authored-by: plexoos <5005079+plexoos@users.noreply.github.com>
@plexoos plexoos changed the title Dd4hep integration feat(dd4hep): add experimental DDG4 integration plugins and examples Apr 7, 2026
@plexoos plexoos force-pushed the dd4hep_integration branch from 05ea17c to 8f76af5 Compare April 7, 2026 21:20
OPTICKS_GPU_TIME was measuring only the kernel launch overhead, not
actual GPU computation time.  Adding cudaDeviceSynchronize() ensures
the timer waits for the GPU kernel to complete before taking the end
timestamp.
Runs the dRICH 1-sector geometry in GPU or CPU mode and reports hit
counts.  Supports configurable geometry via DRICH_SIMPLE_XML env var,
event/multiplicity control via NUM_EVENTS/MULTIPLICITY env vars.

GPU mode registers OpticsSteppingAction, OpticsRun, OpticsEvent plugins,
disables CPU photon stacking, and injects GPU hits into the DD4hep
collection before ROOT output.

Usage:
  python validate_drich.py gpu
  python validate_drich.py cpu
@plexoos
Copy link
Copy Markdown
Member

plexoos commented Apr 9, 2026

@ggalgoczi Do you plan to address the concerns raised above? Please let me know what you think and whether you consider this ready to merge. It would be great if we could tag another release by the end of this week.

@ggalgoczi
Copy link
Copy Markdown
Contributor Author

@plexoos yes, will be done by tomorrow.

sphoton::identity is sensor_identifier+1 (0 means not-a-sensor).
The DD4hep cellID should be the actual sensor identifier, which
is returned by sphoton::pmtid() (identity - 1).
@ggalgoczi
Copy link
Copy Markdown
Contributor Author

ggalgoczi commented Apr 11, 2026

Tested codex first claim. Tested with Debug and Release flags too. Eventbatching works. Wrong conclusion from codex — simulate() internally calls beginOfEvent which updates the index.

Second claim is correct. We do not use IDs though but fixed it. Pushed.

Third claim is correct but is by design now. All the detectors I know have one type of detector. Can be added as a git issue for a future feature.

@plexoos
Copy link
Copy Markdown
Member

plexoos commented Apr 12, 2026

Great! Thanks for checking on this and clearing up the concerns.

@plexoos plexoos merged commit 6ffdc8e into main Apr 12, 2026
13 checks passed
@plexoos plexoos deleted the dd4hep_integration branch April 12, 2026 01:04
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.

4 participants