Skip to content

Commit 2e67262

Browse files
authored
Allow detection in non-optical materials through an optical surface (#2308)
* Remove rindex and vestigial reflectivity * Allow detector executor to detect hits on non-optical materials * Apply feedback and add comments * Delete old CI names * Add build_sd_names virtual method to GeantTestBase Prompt: "Add a virtual method to GeantTestBase that returns SetDetectors, then passed to GeantSetup. Update the GeantTestBase::ImportSetup to include that list. Then add the x/y/z detectors to the GDML file (auxtype="SensDet") assuming the exising VolumeId is the order of the volume in that file." Assisted-by: GitHub Copilot (claude-sonnet-4-5) * Add note to GGParams * Delete now-unnnecessary block and silence disabled physics * Fix squirrel
1 parent 299eee2 commit 2e67262

13 files changed

Lines changed: 94 additions & 94 deletions

File tree

src/celeritas/optical/CoreTrackView.hh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,6 @@ CoreTrackView::operator=(TrackInitializer const& init)
163163
// Initialize the surface state
164164
this->surface_physics().reset();
165165

166-
// Clear detector state data
167-
states_.detectors.detector_hits[track_slot_id_].detector = {};
168-
169166
return *this;
170167
}
171168

src/celeritas/optical/action/detail/DetectorExecutor.hh

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//---------------------------------------------------------------------------//
77
#pragma once
88

9+
#include "celeritas/Types.hh"
910
#include "celeritas/optical/CoreTrackView.hh"
1011
#include "celeritas/optical/DetectorData.hh"
1112

@@ -23,7 +24,14 @@ namespace detail
2324
* or is not in a detector region, an invalid hit is set in the corresponding
2425
* buffer track slot.
2526
*
27+
* Detection can occur after a surface crossing \em or (for coupled EM
28+
* problems) if an optical photon is emitted inside a detector region.
29+
*
2630
* When a track generates a valid hit, it is killed (absorbed by the detector).
31+
*
32+
* \note This is called by \em all track slots, which is necessary to clear the
33+
* outgoing detector hits. We could break this into a "reset" kernel that
34+
* applies to all slots, and a "fill" kernel that applies only to valid slots.
2735
*/
2836
struct DetectorExecutor
2937
{
@@ -43,41 +51,49 @@ CELER_FUNCTION void
4351
DetectorExecutor::operator()(CoreTrackView const& track) const
4452
{
4553
auto& hit = detector_state_.detector_hits[track.track_slot_id()];
54+
// Clear the hit if inactive, errored, or not detected
55+
hit.detector = {};
56+
4657
auto sim = track.sim();
4758

48-
if (sim.status() == TrackStatus::alive)
59+
if (!is_track_valid(sim.status()))
4960
{
50-
auto const detectors = track.detectors();
51-
52-
auto geometry = track.geometry();
61+
// Inactive or errored
62+
return;
63+
}
64+
if (track.surface_physics().is_crossing_boundary())
65+
{
66+
// Boundary crossing not yet completed, so not yet detected!
67+
return;
68+
}
5369

54-
auto const volume_id = geometry.volume_id();
55-
auto const detector_id = detectors.detector_id(volume_id);
70+
auto geometry = track.geometry();
71+
if (geometry.is_outside())
72+
{
73+
// Killed by leaving geometry; no detection
74+
return;
75+
}
5676

57-
if (detector_id)
58-
{
59-
// Score a valid hit
60-
hit = DetectorHit{detector_id,
61-
track.sim().primary_id(),
62-
track.particle().energy(),
63-
sim.time(),
64-
geometry.pos(),
65-
geometry.volume_instance_id()};
77+
auto const detectors = track.detectors();
78+
auto const volume_id = geometry.volume_id();
79+
auto const detector_id = detectors.detector_id(volume_id);
6680

67-
// Kill the track
68-
sim.status(TrackStatus::killed);
69-
}
70-
else
71-
{
72-
// Mark that the track is not in a detector
73-
hit.detector = {};
74-
}
75-
}
76-
else
81+
if (!detector_id)
7782
{
78-
// Ensure killed, inactive, and errored tracks don't contribute to hits
79-
hit.detector = {};
83+
// Not in a detector
84+
return;
8085
}
86+
87+
// Score a valid hit
88+
hit.detector = detector_id;
89+
hit.primary = sim.primary_id();
90+
hit.energy = track.particle().energy();
91+
hit.time = sim.time();
92+
hit.position = geometry.pos();
93+
hit.volume_instance = geometry.volume_instance_id();
94+
95+
// Kill the track
96+
sim.status(TrackStatus::killed);
8197
}
8298

8399
//---------------------------------------------------------------------------//

src/celeritas/optical/surface/detail/InitBoundaryExecutor.hh

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,7 @@ CELER_FUNCTION void InitBoundaryExecutor::operator()(CoreTrackView& track) const
8181
= select_surface(track.surface(), geo.volume_instance_id());
8282
if (!oriented_surface)
8383
{
84-
// Kill the track if the post-volume doesn't have a valid optical
85-
// material and there's no surface
86-
if (!post_volume_material)
87-
{
88-
track.sim().status(TrackStatus::killed);
89-
return;
90-
}
91-
92-
// Use default surface data
84+
// Use default surface properties: typically dielectric-dielectric
9385
oriented_surface.surface = surface_physics.scalars().default_surface;
9486
oriented_surface.orientation = SubsurfaceDirection::forward;
9587
}
@@ -102,12 +94,16 @@ CELER_FUNCTION void InitBoundaryExecutor::operator()(CoreTrackView& track) const
10294
global_normal = -global_normal;
10395
}
10496

105-
surface_physics
106-
= SurfacePhysicsTrackView::Initializer{oriented_surface.surface,
107-
oriented_surface.orientation,
108-
global_normal,
109-
pre_volume_material,
110-
post_volume_material};
97+
surface_physics = [&] {
98+
SurfacePhysicsTrackView::Initializer init;
99+
init.surface = oriented_surface.surface;
100+
init.orientation = oriented_surface.orientation;
101+
init.global_normal = global_normal;
102+
init.pre_volume_material = pre_volume_material;
103+
// Note that post-volume material may be null
104+
init.post_volume_material = post_volume_material;
105+
return init;
106+
}();
111107

112108
CELER_ASSERT(
113109
is_entering_surface(geo.dir(), surface_physics.global_normal()));

src/celeritas/optical/surface/detail/PostBoundaryExecutor.hh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ CELER_FUNCTION void PostBoundaryExecutor::operator()(CoreTrackView& track) const
6262

6363
if (!track.material_record().material_id())
6464
{
65-
// Kill track if it enters an invalid optical material
65+
// Kill track if it enters an invalid optical material after crossing
66+
// through a custom physics surface
6667
track.sim().status(TrackStatus::killed);
6768
}
6869

src/geocel/GeantGeoParams.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,8 @@ GeantGeoParams::from_gdml(std::string const& filename)
720720
// Create geo params
721721
auto result
722722
= std::make_shared<GeantGeoParams>(loaded.world, Ownership::value);
723-
// Set detectors (hack)
723+
// We own constructed detectors (note that these live only on the main
724+
// thread and are not suitable for G4 MT: use DetectorConstruction instead)
724725
result->built_detectors_ = std::move(built_detectors);
725726

726727
// Save for use outside in Celeritas

test/celeritas/GeantTestBase.cc

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct GeantTestBase::ImportSetup
4242
std::shared_ptr<GeantGeoParams> geo;
4343
GeantPhysicsOptions options{};
4444
GeantImportDataSelection selection{};
45+
GeantSetup::SetString sd_names{};
4546
ImportData imported;
4647
ScopedGeantExceptionHandler scoped_exceptions;
4748
};
@@ -64,21 +65,6 @@ bool GeantTestBase::is_ci_build()
6465
return clhep >= Version{2, 4, 6} && clhep < Version{2, 5}
6566
&& g4 >= Version{11, 3} && g4 < Version{11, 4};
6667
}
67-
68-
//---------------------------------------------------------------------------//
69-
//! Whether Geant4 dependencies match those on Wildstyle
70-
bool GeantTestBase::is_wildstyle_build()
71-
{
72-
return GeantTestBase::is_ci_build();
73-
}
74-
75-
//---------------------------------------------------------------------------//
76-
//! Whether Geant4 dependencies match those on Summit
77-
bool GeantTestBase::is_summit_build()
78-
{
79-
return GeantTestBase::is_ci_build();
80-
}
81-
8268
//---------------------------------------------------------------------------//
8369
// PROTECTED MEMBER FUNCTIONS
8470
//---------------------------------------------------------------------------//
@@ -146,6 +132,7 @@ auto GeantTestBase::load(std::string const& filename) const
146132
{
147133
GeantPhysicsOptions opts = this->build_geant_options();
148134
GeantImportDataSelection sel = this->build_import_data_selection();
135+
GeantSetup::SetString sd_names = this->build_sd_names();
149136

150137
using PersistentImportSetup = PersistentSP<GeantTestBase::ImportSetup>;
151138

@@ -158,7 +145,9 @@ auto GeantTestBase::load(std::string const& filename) const
158145
<< "load was called before build_geant_geo");
159146
i = std::make_shared<ImportSetup>();
160147
i->options = opts;
161-
i->import = std::make_unique<GeantImporter>(GeantSetup{filename, opts});
148+
i->sd_names = sd_names;
149+
i->import = std::make_unique<GeantImporter>(
150+
GeantSetup{filename, opts, std::move(sd_names)});
162151
i->geo = i->import->geo_params();
163152
CELER_ASSERT(i->geo);
164153
CELER_ASSERT(!celeritas::global_geant_geo().expired());
@@ -181,6 +170,9 @@ auto GeantTestBase::load(std::string const& filename) const
181170
CELER_VALIDATE(opts == i->options,
182171
<< "cannot change physics options after setup "
183172
<< explanation);
173+
CELER_VALIDATE(sd_names == i->sd_names,
174+
<< "cannot change sensitive detector names after setup "
175+
<< explanation);
184176

185177
if (sel == i->selection)
186178
{
@@ -206,6 +198,12 @@ auto GeantTestBase::load(std::string const& filename) const
206198
return *i;
207199
}
208200

201+
//---------------------------------------------------------------------------//
202+
auto GeantTestBase::build_sd_names() const -> GeantSetup::SetString
203+
{
204+
return {};
205+
}
206+
209207
//---------------------------------------------------------------------------//
210208
GeantImportDataSelection GeantTestBase::build_import_data_selection() const
211209
{

test/celeritas/GeantTestBase.hh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <iosfwd>
1010

1111
#include "celeritas/Types.hh"
12+
#include "celeritas/ext/GeantSetup.hh"
1213

1314
#include "ImportedDataTestBase.hh"
1415

@@ -17,7 +18,6 @@ class G4VPhysicalVolume;
1718
namespace celeritas
1819
{
1920
//---------------------------------------------------------------------------//
20-
struct GeantPhysicsOptions;
2121
struct GeantImportDataSelection;
2222

2323
namespace test
@@ -34,12 +34,11 @@ class GeantTestBase : public ImportedDataTestBase
3434
//!@{
3535
//! Whether the Geant4 configuration match a certain machine
3636
static bool is_ci_build();
37-
static bool is_wildstyle_build();
38-
static bool is_summit_build();
3937
//!@}
4038

4139
protected:
4240
virtual GeantPhysicsOptions build_geant_options() const;
41+
virtual GeantSetup::SetString build_sd_names() const;
4342

4443
SPConstTrackInit build_init() override;
4544
SPConstAction build_along_step() override;

test/celeritas/ext/GeantImporter.test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,8 +457,8 @@ TEST_F(DuneCryostat, optical_gen)
457457
ASSERT_TRUE(scint);
458458
EXPECT_EQ(1, scint->materials.size());
459459

460-
ASSERT_TRUE(scint->materials.count(OptMatId{1}));
461-
auto const& m = scint->materials.at(OptMatId{1});
460+
ASSERT_TRUE(scint->materials.count(OptMatId{0}));
461+
auto const& m = scint->materials.at(OptMatId{0});
462462
ASSERT_EQ(2, m.components.size());
463463
EXPECT_SOFT_EQ(50000 * 0.8, m.components[0].yield);
464464
EXPECT_SOFT_EQ(50000 * 0.2, m.components[1].yield);

test/celeritas/optical/Detector.test.cc

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ class DetectorTest : public ::celeritas::test::GeantTestBase
5656
{
5757
auto result = GeantTestBase::build_geant_options();
5858
result.optical.emplace();
59+
result.optical->scintillation = std::nullopt;
60+
result.optical->mie_scattering = false;
61+
result.optical->wavelength_shifting = std::nullopt;
62+
result.optical->wavelength_shifting2 = std::nullopt;
5963
return result;
6064
}
6165

@@ -66,6 +70,11 @@ class DetectorTest : public ::celeritas::test::GeantTestBase
6670
return result;
6771
}
6872

73+
GeantSetup::SetString build_sd_names() const override
74+
{
75+
return {"x-detectors", "y-detectors", "z-detectors"};
76+
}
77+
6978
std::vector<IMC> select_optical_models() const override
7079
{
7180
return {IMC::absorption};
@@ -87,23 +96,6 @@ class DetectorTest : public ::celeritas::test::GeantTestBase
8796
this->optical_action_reg().get(), input);
8897
}
8998

90-
SPConstDetectors detector() override
91-
{
92-
if (!detector_)
93-
{
94-
inp::Detectors input{{
95-
{"y-detectors", {VolumeId{1}, VolumeId{2}}},
96-
{"x-detectors", {VolumeId{3}, VolumeId{4}}},
97-
{"z-detectors", {VolumeId{5}, VolumeId{6}}},
98-
}};
99-
100-
detector_ = std::make_shared<DetectorParams>(std::move(input),
101-
*this->volume());
102-
}
103-
104-
return detector_;
105-
}
106-
10799
inp::OpticalDetector build_optical_detector_input() override
108100
{
109101
return detector_input_;

test/celeritas/optical/Generator.test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ TEST_F(DuneGeneratorTest, offload)
267267
gdd.primary = PrimaryId{123};
268268
gdd.step_length = 2.0 * units::centimeter;
269269
gdd.charge = units::ElementaryCharge{-1};
270-
gdd.material = OptMatId{1}; // Should be LAr
270+
gdd.material = OptMatId{0}; // Should be LAr
271271
gdd.continuous_edep_fraction = 1.0;
272272
gdd.points[StepPoint::pre] = {units::LightSpeed(0.7),
273273
1e-9 * units::nanosecond,

0 commit comments

Comments
 (0)