Skip to content

Commit 6ffdc8e

Browse files
authored
feat(dd4hep): add experimental DDG4 integration plugins and examples (#266)
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).
1 parent 2e02e3f commit 6ffdc8e

20 files changed

Lines changed: 2601 additions & 0 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
*~
2+
dd4hepplugins/examples/drich-dev/
3+
dd4hepplugins/examples/calibrations/
4+
dd4hepplugins/examples/fieldmaps/

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ add_subdirectory(g4cx)
3939
add_subdirectory(g4cx/tests)
4040
add_subdirectory(src)
4141

42+
# Optional DD4hep integration plugins
43+
find_package(DD4hep QUIET COMPONENTS DDG4 DDCore)
44+
if(DD4hep_FOUND)
45+
message(STATUS "DD4hep found -- building dd4hepplugins")
46+
add_subdirectory(dd4hepplugins)
47+
add_subdirectory(dd4hepplugins/examples)
48+
else()
49+
message(STATUS "DD4hep not found -- skipping dd4hepplugins")
50+
endif()
51+
4252
# Export configs
4353
include(CMakePackageConfigHelpers)
4454

dd4hepplugins/CMakeLists.txt

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#------------------------------- -*- cmake -*- -------------------------------#
2+
# eic-opticks DD4hep integration plugins
3+
#
4+
# Builds DD4hep action plugins that integrate eic-opticks GPU-accelerated
5+
# optical photon simulation into DD4hep/Geant4.
6+
#
7+
# Works both as part of the top-level eic-opticks build (in-tree) and as a
8+
# standalone project against an installed eic-opticks.
9+
#
10+
# Usage from a DD4hep steering file:
11+
# OpticsRun -- initializes/finalizes G4CXOpticks per run
12+
# OpticsEvent -- triggers GPU simulation per event
13+
#----------------------------------------------------------------------------#
14+
15+
# Detect standalone vs in-tree build
16+
if(NOT TARGET G4CX)
17+
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
18+
project(ddeicopticks VERSION 0.1.0 LANGUAGES CXX)
19+
find_package(DD4hep REQUIRED COMPONENTS DDG4 DDCore)
20+
find_package(eic-opticks REQUIRED)
21+
find_package(Geant4 REQUIRED)
22+
set(_g4cx eic-opticks::G4CX)
23+
set(_u4 eic-opticks::U4)
24+
set(_sysrap eic-opticks::SysRap)
25+
else()
26+
# In-tree: DD4hep already found by parent, targets use local names
27+
find_package(Geant4 REQUIRED)
28+
set(_g4cx G4CX)
29+
set(_u4 U4)
30+
set(_sysrap SysRap)
31+
endif()
32+
33+
dd4hep_set_compiler_flags()
34+
35+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
36+
set(LIBRARY_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}")
37+
38+
dd4hep_add_plugin(ddeicopticks
39+
SOURCES
40+
OpticsRun.cc
41+
OpticsEvent.cc
42+
OpticsSteppingAction.cc
43+
USES
44+
DD4hep::DDG4
45+
DD4hep::DDCore
46+
${_g4cx}
47+
${_u4}
48+
${_sysrap}
49+
)
50+
# STANDALONE changes class export macros in eic-opticks headers;
51+
# only needed when building outside the main eic-opticks tree.
52+
if(NOT TARGET G4CX)
53+
target_compile_definitions(ddeicopticks PRIVATE STANDALONE)
54+
endif()
55+
56+
install(TARGETS ddeicopticks
57+
LIBRARY DESTINATION lib
58+
)
59+
60+
install(FILES
61+
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_MODULE_PREFIX}ddeicopticks.components
62+
DESTINATION lib
63+
)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#pragma once
2+
/**
3+
DD4hepSensorIdentifier.hh
4+
===========================
5+
6+
Custom sensor identifier for DD4hep geometries.
7+
8+
Unlike the default U4SensorIdentifierDefault which relies on
9+
GLOBAL_SENSOR_BOUNDARY_LIST env var for non-instanced geometries,
10+
this implementation directly checks G4VSensitiveDetector on volumes.
11+
12+
This works for DD4hep geometries where sensitive detectors are
13+
explicitly set via DetElement::setSensitiveDetector().
14+
**/
15+
16+
#include <iostream>
17+
#include <vector>
18+
19+
#include "G4PVPlacement.hh"
20+
#include "G4VSensitiveDetector.hh"
21+
22+
#include "U4SensorIdentifier.h"
23+
24+
struct DD4hepSensorIdentifier : public U4SensorIdentifier
25+
{
26+
int level = 0;
27+
int counter = 0; // auto-increment sensor ID (1-based; 0 means "not a sensor" in opticks)
28+
29+
void setLevel(int _level) override
30+
{
31+
level = _level;
32+
}
33+
34+
/**
35+
getGlobalIdentity
36+
-------------------
37+
Checks if the physical volume has a G4VSensitiveDetector attached.
38+
Returns a unique 1-based sensor_id, or -1 if not sensitive.
39+
40+
Note: opticks treats sensor_id == 0 as "not a sensor", so IDs must be >= 1.
41+
PV copy numbers are not reliable (e.g. dRICH SiPMs all have copyNo=0).
42+
**/
43+
int getGlobalIdentity(const G4VPhysicalVolume *pv, const G4VPhysicalVolume * /*ppv*/) override
44+
{
45+
if (!pv)
46+
return -1;
47+
48+
const G4LogicalVolume *lv = pv->GetLogicalVolume();
49+
G4VSensitiveDetector *sd = lv->GetSensitiveDetector();
50+
51+
if (!sd)
52+
return -1;
53+
54+
int sensor_id = ++counter; // 1-based unique ID
55+
56+
if (level > 0)
57+
std::cout << "DD4hepSensorIdentifier::getGlobalIdentity" << " sensor_id " << sensor_id << " sd "
58+
<< sd->GetName() << " pv " << pv->GetName() << std::endl;
59+
60+
return sensor_id;
61+
}
62+
63+
/**
64+
getInstanceIdentity
65+
---------------------
66+
Same as default: recursively search for G4VSensitiveDetector
67+
within the instance subtree.
68+
**/
69+
int getInstanceIdentity(const G4VPhysicalVolume *instance_outer_pv) const override
70+
{
71+
if (!instance_outer_pv)
72+
return -1;
73+
74+
std::vector<const G4VPhysicalVolume *> sdpv;
75+
FindSD_r(sdpv, instance_outer_pv, 0);
76+
77+
if (sdpv.empty())
78+
return -1;
79+
80+
const G4PVPlacement *pvp = dynamic_cast<const G4PVPlacement *>(instance_outer_pv);
81+
return pvp ? pvp->GetCopyNo() : 0;
82+
}
83+
84+
static void FindSD_r(std::vector<const G4VPhysicalVolume *> &sdpv, const G4VPhysicalVolume *pv, int depth)
85+
{
86+
const G4LogicalVolume *lv = pv->GetLogicalVolume();
87+
G4VSensitiveDetector *sd = lv->GetSensitiveDetector();
88+
if (sd)
89+
sdpv.push_back(pv);
90+
for (size_t i = 0; i < size_t(lv->GetNoDaughters()); i++)
91+
FindSD_r(sdpv, lv->GetDaughter(i), depth + 1);
92+
}
93+
};

0 commit comments

Comments
 (0)