Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
38123c8
Add CMakeLists.txt for ddeicopticks plugin
ggalgoczi Mar 5, 2026
7ad57c3
Add OpticsEvent.cc
ggalgoczi Mar 5, 2026
10c7a1f
Remove license header from OpticsEvent.hh
ggalgoczi Mar 5, 2026
2c54e77
Clean up OpticsRun.cc by removing comments and header
ggalgoczi Mar 5, 2026
2bca8fb
Add OpticsRun class for eic-opticks run lifecycle
ggalgoczi Mar 5, 2026
e8e95f2
Add OpticsSteppingAction implementation
ggalgoczi Mar 5, 2026
620924b
Remove license header from OpticsSteppingAction.hh
ggalgoczi Mar 5, 2026
732496e
Move to physics genstep collection from stepping in CMakeLists.txt
ggalgoczi Mar 6, 2026
ca9dd60
Create OpticsPhysics.cc
ggalgoczi Mar 6, 2026
38d2764
Create OpticsPhysics.hh
ggalgoczi Mar 6, 2026
d78307e
Delete dd4hepplugins/OpticsSteppingAction.cc
ggalgoczi Mar 6, 2026
cfc869b
Delete dd4hepplugins/OpticsSteppingAction.hh
ggalgoczi Mar 6, 2026
d4fde26
hit injection into DD4hep collections
ggalgoczi Mar 8, 2026
c4a6751
hit injection OpticsEvent.hh
ggalgoczi Mar 8, 2026
5d36375
Create test_raindrop_dd4hep.py
ggalgoczi Mar 8, 2026
c084196
Create raindrop_dd4hep.xml
ggalgoczi Mar 8, 2026
cfb55ef
Create test_raindrop_cpu.py
ggalgoczi Mar 8, 2026
1350cd2
Merge branch 'main' (early part) into dd4hep_integration
ggalgoczi Apr 2, 2026
fba67e0
Add raindrop detector geometry implementation
ggalgoczi Apr 2, 2026
7717636
Create CMakeLists.txt for DD4hep example
ggalgoczi Apr 2, 2026
09f0701
build: integrate dd4hepplugins into top-level cmake as optional subdi…
ggalgoczi Apr 2, 2026
df563cc
fix(u4): remove PMT name requirement from sensor identification
ggalgoczi Apr 2, 2026
da2d0b4
fix(examples): remove hardcoded spack paths from dd4hep test scripts
ggalgoczi Apr 2, 2026
72fb922
build(examples): wire dd4hep raindrop plugin into top-level cmake
ggalgoczi Apr 2, 2026
4ee7da3
raindrop: move sensitive detector to lead, remove scintillation
ggalgoczi Apr 3, 2026
288a570
fix(dd4hep): enable GPU optical photon simulation via DDG4 plugins
ggalgoczi Apr 3, 2026
180f748
add GPU vs CPU optical photon benchmark script
ggalgoczi Apr 3, 2026
7b27080
rename test scripts to test_raindrop_dd4hep_{cpu,gpu}.py
ggalgoczi Apr 3, 2026
65bfcee
add photon batching to OpticsEvent for improved GPU throughput
ggalgoczi Apr 3, 2026
664b313
add thread safety and enable scintillation in OpticsSteppingAction
ggalgoczi Apr 3, 2026
8da8410
Merge branch 'main' into dd4hep_integration
plexoos Apr 3, 2026
0b7595e
move examples/dd4hep to dd4hepplugins/examples
ggalgoczi Apr 3, 2026
71d7f41
fix CMakeLists.txt path after examples move to dd4hepplugins
ggalgoczi Apr 3, 2026
8c53d91
address Copilot and Codex PR review feedback
ggalgoczi Apr 3, 2026
399228b
Remove EPIC calibrations/fieldmaps symlinks from repo
ggalgoczi Apr 5, 2026
6af15f6
Remove stray run.npy and run_meta.txt from repo
ggalgoczi Apr 5, 2026
277765c
revert sensor ID fix, moved to separate PR (fix-sensor-id branch)
ggalgoczi Apr 6, 2026
585d0da
Merge branch 'main' into dd4hep_integration
plexoos Apr 7, 2026
afff87a
chore(gitignore): stop ignoring ALL .npy files
plexoos Apr 7, 2026
d88a4b5
style: clang-format DD4hep integration files for dd4hep_integration m…
Copilot Apr 7, 2026
a81f9fe
Merge remote-tracking branch 'origin/main' into dd4hep_integration
plexoos Apr 7, 2026
8f76af5
style: apply clang-format Microsoft style to dd4hepplugins files
plexoos Apr 7, 2026
d5b8b6e
fix: add cudaDeviceSynchronize after GPU simulate for accurate timing
ggalgoczi Apr 7, 2026
656e529
add dRICH GPU vs CPU validation steering script
ggalgoczi Apr 9, 2026
3ec3797
Merge branch 'main' into dd4hep_integration
plexoos Apr 11, 2026
c5a3bc7
fix: use pmtid() instead of identity for hit cellID
ggalgoczi Apr 11, 2026
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
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ add_subdirectory(g4cx)
add_subdirectory(g4cx/tests)
add_subdirectory(src)

# Optional DD4hep integration plugins
find_package(DD4hep QUIET COMPONENTS DDG4 DDCore)
if(DD4hep_FOUND)
message(STATUS "DD4hep found -- building dd4hepplugins")
add_subdirectory(dd4hepplugins)
add_subdirectory(examples/dd4hep)
else()
message(STATUS "DD4hep not found -- skipping dd4hepplugins")
endif()

# Export configs
include(CMakePackageConfigHelpers)

Expand Down
59 changes: 59 additions & 0 deletions dd4hepplugins/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#------------------------------- -*- cmake -*- -------------------------------#
# eic-opticks DD4hep integration plugins
#
# Builds DD4hep action plugins that integrate eic-opticks GPU-accelerated
# optical photon simulation into DD4hep/Geant4.
#
# Works both as part of the top-level eic-opticks build (in-tree) and as a
# standalone project against an installed eic-opticks.
#
# Usage from a DD4hep steering file:
# OpticsRun -- initializes/finalizes G4CXOpticks per run
# OpticsEvent -- triggers GPU simulation per event
#----------------------------------------------------------------------------#

# Detect standalone vs in-tree build
if(NOT TARGET G4CX)
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
project(ddeicopticks VERSION 0.1.0 LANGUAGES CXX)
find_package(DD4hep REQUIRED COMPONENTS DDG4 DDCore)
find_package(eic-opticks REQUIRED)
find_package(Geant4 REQUIRED)
set(_g4cx eic-opticks::G4CX)
set(_u4 eic-opticks::U4)
set(_sysrap eic-opticks::SysRap)
else()
# In-tree: DD4hep already found by parent, targets use local names
find_package(Geant4 REQUIRED)
set(_g4cx G4CX)
set(_u4 U4)
set(_sysrap SysRap)
endif()

dd4hep_set_compiler_flags()

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
set(LIBRARY_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}")

dd4hep_add_plugin(ddeicopticks
SOURCES
OpticsPhysics.cc
OpticsRun.cc
OpticsEvent.cc
USES
DD4hep::DDG4
DD4hep::DDCore
${_g4cx}
${_u4}
${_sysrap}
)
target_compile_definitions(ddeicopticks PRIVATE STANDALONE)

install(TARGETS ddeicopticks
LIBRARY DESTINATION lib
)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_MODULE_PREFIX}ddeicopticks.components
DESTINATION lib
)
179 changes: 179 additions & 0 deletions dd4hepplugins/OpticsEvent.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include "OpticsEvent.hh"

#include <DD4hep/InstanceCount.h>
#include <DDG4/Factories.h>
#include <DDG4/Geant4Data.h>
#include <DDG4/Geant4HitCollection.h>
#include <DDG4/Geant4SensDetAction.h>
#include <DDG4/Geant4Context.h>

#include <G4Event.hh>

#include <G4CXOpticks.hh>
#include <SEvt.hh>
#include <SComp.h>
#include <sphoton.h>
#include <NP.hh>
#include <NPFold.h>

namespace ddeicopticks
{
//---------------------------------------------------------------------------//
OpticsEvent::OpticsEvent(dd4hep::sim::Geant4Context* ctxt,
std::string const& name)
: dd4hep::sim::Geant4EventAction(ctxt, name)
{
dd4hep::InstanceCount::increment(this);
declareProperty("Verbose", verbose_);
}

//---------------------------------------------------------------------------//
OpticsEvent::~OpticsEvent()
{
dd4hep::InstanceCount::decrement(this);
}

//---------------------------------------------------------------------------//
void OpticsEvent::begin(G4Event const* event)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
void OpticsEvent::begin(G4Event const* event)
void OpticsEvent::begin(G4Event const *event)

{
int eventID = event->GetEventID();

if (verbose_ > 0)
{
info("OpticsEvent::begin -- event #%d", eventID);
}

SEvt::CreateOrReuse_EGPU();
SEvt* sev = SEvt::Get_EGPU();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
SEvt* sev = SEvt::Get_EGPU();
SEvt *sev = SEvt::Get_EGPU();

if (sev)
{
sev->beginOfEvent(eventID);
}
Comment on lines +48 to +58
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

batch_begun_ mode calls SEvt::beginOfEvent(eventID) only once per batch. However SEvt::beginOfEvent sets the internal event index and clears output buffers (but preserves gensteps). Skipping it for subsequent events while later calling simulate/endOfEvent/reset with a different eventID risks inconsistent SEvt indexing/metadata and overwriting output state. Consider always updating the SEvt index for the current eventID (without clearing accumulated gensteps), or implement an explicit batching API in SEvt to support this safely.

Suggested change
// In batch mode, only start a new SEvt at the beginning of each batch.
// Skipping beginOfEvent between events lets gensteps accumulate
// (SEvt::clear_output preserves gensteps by design).
if (!batch_begun_)
{
SEvt::CreateOrReuse_EGPU();
SEvt* sev = SEvt::Get_EGPU();
if (sev)
sev->beginOfEvent(eventID);
batch_begun_ = true;
}
// In batch mode, create or reuse the SEvt once per batch, but still
// begin each event so the internal event index/metadata is updated and
// per-event output buffers are cleared. beginOfEvent preserves gensteps.
if (!batch_begun_)
{
SEvt::CreateOrReuse_EGPU();
batch_begun_ = true;
}
SEvt* sev = SEvt::Get_EGPU();
if (sev)
sev->beginOfEvent(eventID);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is intentional. In batch mode, gensteps accumulate across events; calling beginOfEvent for each event would clear them. The bot doesn't understand the batching design.

}

//---------------------------------------------------------------------------//
void OpticsEvent::end(G4Event const* event)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
void OpticsEvent::end(G4Event const* event)
void OpticsEvent::end(G4Event const *event)

{
int eventID = event->GetEventID();

G4CXOpticks* gx = G4CXOpticks::Get();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
G4CXOpticks* gx = G4CXOpticks::Get();
G4CXOpticks *gx = G4CXOpticks::Get();

if (!gx)
{
error("OpticsEvent::end -- G4CXOpticks not initialized");
return;
}

SEvt* sev = SEvt::Get_EGPU();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
SEvt* sev = SEvt::Get_EGPU();
SEvt *sev = SEvt::Get_EGPU();

if (!sev)
{
error("OpticsEvent::end -- no EGPU SEvt instance");
return;
}

int64_t num_genstep = sev->getNumGenstepFromGenstep();
int64_t num_photon = sev->getNumPhotonFromGenstep();

if (verbose_ > 0 || num_genstep > 0)
{
info("Event #%d: %lld gensteps, %lld photons to simulate",
eventID,
static_cast<long long>(num_genstep),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
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),

static_cast<long long>(num_photon));
}

if (num_genstep > 0)
{
gx->simulate(eventID, /*reset=*/false);

unsigned num_hit = sev->getNumHit();
info("Event #%d: %u hits from GPU", eventID, num_hit);

// Inject GPU hits into DD4hep sensitive detector hit collections
if (num_hit > 0)
{
injectHits(event, sev, num_hit);
}

sev->endOfEvent(eventID);
gx->reset(eventID);
}
else
{
if (verbose_ > 0)
info("Event #%d: no gensteps, skipping GPU simulation", eventID);
sev->endOfEvent(eventID);
}
}

//---------------------------------------------------------------------------//
void OpticsEvent::injectHits(G4Event const* event,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
void OpticsEvent::injectHits(G4Event const* event,
using dd4hep::sim::Geant4SensDetSequences;

SEvt* sev,
unsigned num_hit)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
void OpticsEvent::injectHits(G4Event const* event,
SEvt* sev,
unsigned num_hit)
void OpticsEvent::injectHits(G4Event const *event, SEvt *sev, unsigned num_hit)

{
using dd4hep::sim::Geant4SensDetSequences;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Please remove the line(s)

  • 113

using dd4hep::sim::Geant4HitCollection;
using dd4hep::sim::Geant4Tracker;

int eventID = event->GetEventID();

Geant4SensDetSequences& sens = context()->sensitiveActions();
auto const& seqs = sens.sequences();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
Geant4SensDetSequences& sens = context()->sensitiveActions();
auto const& seqs = sens.sequences();
Geant4SensDetSequences &sens = context()->sensitiveActions();
auto const &seqs = sens.sequences();


if (seqs.empty())
{
warning("Event #%d: no sensitive detectors registered -- "
"call setupTracker() in steering script", eventID);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
"call setupTracker() in steering script", eventID);
"call setupTracker() in steering script",
eventID);

return;
}

for (auto const& [det_name, seq] : seqs)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
for (auto const& [det_name, seq] : seqs)
for (auto const &[det_name, seq] : seqs)

{
Geant4HitCollection* coll = seq->collection(0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
Geant4HitCollection* coll = seq->collection(0);
Geant4HitCollection *coll = seq->collection(0);

if (!coll)
continue;

for (unsigned i = 0; i < num_hit; i++)
{
sphoton ph;
sev->getHit(ph, i);
coll->add(createTrackerHit(ph));
}

info("Event #%d: injected %u hits into '%s' collection",
eventID, num_hit, det_name.c_str());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
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());

}
}

//---------------------------------------------------------------------------//
dd4hep::sim::Geant4Tracker::Hit*
OpticsEvent::createTrackerHit(sphoton const& ph)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
dd4hep::sim::Geant4Tracker::Hit*
OpticsEvent::createTrackerHit(sphoton const& ph)
dd4hep::sim::Geant4Tracker::Hit *OpticsEvent::createTrackerHit(sphoton const &ph)

{
using dd4hep::sim::Geant4Tracker;

auto* hit = new Geant4Tracker::Hit();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
auto* hit = new Geant4Tracker::Hit();
auto *hit = new Geant4Tracker::Hit();


hit->position = {ph.pos.x, ph.pos.y, ph.pos.z};
hit->momentum = {ph.mom.x, ph.mom.y, ph.mom.z};
hit->length = ph.wavelength;
hit->energyDeposit = 0;
hit->cellID = ph.identity;

hit->truth.trackID = ph.index;
hit->truth.pdgID = 0;
hit->truth.deposit = 0;
hit->truth.time = ph.time;
hit->truth.length = ph.wavelength;
hit->truth.x = ph.pos.x;
hit->truth.y = ph.pos.y;
hit->truth.z = ph.pos.z;
hit->truth.px = ph.mom.x;
hit->truth.py = ph.mom.y;
hit->truth.pz = ph.mom.z;

return hit;
}

//---------------------------------------------------------------------------//
} // namespace ddeicopticks
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
} // namespace ddeicopticks
} // namespace ddeicopticks


DECLARE_GEANT4ACTION_NS(ddeicopticks, OpticsEvent)
48 changes: 48 additions & 0 deletions dd4hepplugins/OpticsEvent.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include <string>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Please remove the line(s)

  • 3

#include <DDG4/Geant4Action.h>
#include <DDG4/Geant4EventAction.h>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Please remove the line(s)

  • 5

clang-format suggestion

Suggested change
#include <DDG4/Geant4EventAction.h>
#include <DDG4/Geant4EventAction.h>
#include <string>

#include <DDG4/Geant4Data.h>

class SEvt;
struct sphoton;

namespace ddeicopticks
{
//---------------------------------------------------------------------------//
/*!
* DDG4 action plugin for eic-opticks event-level GPU simulation.
*
* At begin-of-event: prepares GPU event buffer (SEvt).
* At end-of-event: triggers GPU optical photon simulation via
* G4CXOpticks::simulate(), retrieves hits, injects them into DD4hep
* hit collections, and resets for next event.
*
* Requires setupTracker() to be called in the steering script so that
* DD4hep creates hit collections for the sensitive detectors.
*
* Properties:
* - Verbose (default: 0) -- verbosity level
*/
class OpticsEvent final : public dd4hep::sim::Geant4EventAction
{
public:
OpticsEvent(dd4hep::sim::Geant4Context* ctxt, std::string const& name);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
OpticsEvent(dd4hep::sim::Geant4Context* ctxt, std::string const& name);
OpticsEvent(dd4hep::sim::Geant4Context *ctxt, std::string const &name);


void begin(G4Event const* event) final;
void end(G4Event const* event) final;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
void begin(G4Event const* event) final;
void end(G4Event const* event) final;
void begin(G4Event const *event) final;
void end(G4Event const *event) final;


protected:
DDG4_DEFINE_ACTION_CONSTRUCTORS(OpticsEvent);
~OpticsEvent() final;

private:
void injectHits(G4Event const* event, SEvt* sev, unsigned num_hit);
static dd4hep::sim::Geant4Tracker::Hit* createTrackerHit(sphoton const& ph);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
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);


int verbose_{0};
};

//---------------------------------------------------------------------------//
} // namespace ddeicopticks
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-format suggestion

Suggested change
} // namespace ddeicopticks
} // namespace ddeicopticks

Loading
Loading