aegir-genie
GENIE neutrino event generation for the SHiP experiment's aegir framework.
Loading...
Searching...
No Matches
ship_geom_analyzer.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 CERN for the benefit of the SHiP Collaboration
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
5// ship_geom_analyzer.hpp — GENIE geometry analyzer over the SHiP geometry
6// service
7//
8// Implements genie::GeomAnalyzerI directly on the GeoModel-built Geant4
9// geometry (ship::IGeometryService + ship::G4RayScanner), so GENIE sees the
10// exact same geometry the Geant4 simulation tracks through — no GDML/TGeo
11// conversion in between. The contract mirrors GENIE's ROOTGeomAnalyzer:
12// - path lengths are density-weighted (rho x length x element mass
13// fraction) in SI kg/m2, one entry per target nucleus;
14// - target nuclei are one averaged-A ion per element,
15// IonPdgCode(Nint(N), Z) — no isotope expansion, keeping the
16// genie-splines-ship target list valid;
17// - positions arrive and leave in SI meters (the GFluxI frame);
18// - max path lengths come from a flux-ray scan (SetScannerFlux) with a
19// safety factor, and the scan ends with flux->Clear("CycleHistory") so
20// scan rays do not count as delivered POT.
21//
22// All Geant4 work (GeoModel->G4 conversion, navigation, teardown) is
23// confined to the process-wide ship::geometry_thread(), shared by every
24// Geant4 geometry user in the process (all analyzers, and aegir's
25// geant4_module in the full chain — issue #11): the conda Geant4 is an MT
26// build, whose logical/physical volumes keep per-thread state usable only
27// on the creating thread — and only a single thread per process may create
28// geometry at all — while phlex may run even a serial source on changing
29// TBB threads.
30
31#pragma once
32
33#include <TLorentzVector.h>
34#include <TVector3.h>
35
36#include <memory>
37#include <string>
38
39#include "Framework/EventGen/GeomAnalyzerI.h"
40#include "Framework/EventGen/PathLengthList.h"
41#include "Framework/ParticleData/PDGCodeList.h"
42
43namespace genie {
44class GFluxI;
45}
46namespace ship {
47class IGeometryService;
48}
49
50namespace aegir {
51
52class ShipGeomAnalyzer final : public genie::GeomAnalyzerI {
53 public:
54 enum class G4Teardown {
55 // The process (e.g. aegir's geant4_module) owns Geant4 store cleanup.
57 // Clean the Geant4 stores on the geometry thread in the destructor —
58 // required when nothing else does it (gevgen_ship), because the store
59 // singletons otherwise delete thread-local volume state from the main
60 // thread at exit (aegir issue #68).
62 };
63
64 // `top_volume` empty: scan the full world. Otherwise the named logical
65 // volume becomes the scan world; it must exist and be placed exactly once,
66 // and flux-frame coordinates are mapped through its placement transform.
67 // Must be constructed after the GENIE tune (PDGLibrary) is initialized.
68 // Shares ownership of the service (SHiPGeometryService::sharedFromFile
69 // hands the same instance to every user of the same file) and holds its
70 // reference for the analyzer's lifetime — GeoModel2G4 caches conversions
71 // in static maps keyed by GeoModel pointers, so the tree must not be
72 // freed while a later conversion in the same process is possible.
73 ShipGeomAnalyzer(std::shared_ptr<ship::IGeometryService> geometry,
74 std::string const& top_volume, G4Teardown teardown);
75 ~ShipGeomAnalyzer() override;
76
81
82 // ROOTGeomAnalyzer-compatible knobs, used by make_genie_driver. The flux
83 // scanner is the only max-path-lengths strategy: a box scanner never
84 // samples beam-like axial paths and underestimates the maxima.
85 void SetScannerFlux(genie::GFluxI* flux) { scanner_flux_ = flux; }
86 void SetScannerNParticles(int n) { scanner_particles_ = n; }
87 void SetMaxPlSafetyFactor(double sf) { safety_factor_ = sf; }
88 genie::PathLengthList const& GetMaxPathLengths() const {
89 return max_path_lengths_;
90 }
91
92 // Bounding box of the scan volume in the master (flux) frame, SI meters —
93 // for the startup frame check against the first flux ray.
94 struct Extents {
95 TVector3 lo, hi;
96 };
97 Extents const& extents() const { return extents_; }
98
99 // GeomAnalyzerI
100 genie::PDGCodeList const& ListOfTargetNuclei() override { return targets_; }
101 genie::PathLengthList const& ComputeMaxPathLengths() override;
102 genie::PathLengthList const& ComputePathLengths(
103 TLorentzVector const& x, TLorentzVector const& p) override;
104 TVector3 const& GenerateVertex(TLorentzVector const& x,
105 TLorentzVector const& p, int tgtpdg) override;
106
107 private:
108 struct Impl; // all Geant4 state (used only on the geometry thread)
109 std::unique_ptr<Impl> impl_;
110
111 // Both run on the geometry thread.
112 void init(std::shared_ptr<ship::IGeometryService> geometry,
113 std::string const& top_volume);
114 static void teardown_geant4(Impl& impl);
115
116 genie::GFluxI* scanner_flux_ = nullptr;
117 int scanner_particles_ = 10000;
118 double safety_factor_ = 1.1; // as ROOTGeomAnalyzer's default
119
120 genie::PDGCodeList targets_;
121 genie::PathLengthList path_lengths_;
122 genie::PathLengthList max_path_lengths_;
123 TVector3 vertex_;
124 Extents extents_;
125};
126
127} // namespace aegir
Definition ship_geom_analyzer.hpp:52
ShipGeomAnalyzer(ShipGeomAnalyzer const &)=delete
genie::PDGCodeList const & ListOfTargetNuclei() override
Definition ship_geom_analyzer.hpp:100
void SetMaxPlSafetyFactor(double sf)
Definition ship_geom_analyzer.hpp:87
~ShipGeomAnalyzer() override
Definition ship_geom_analyzer.cpp:234
void SetScannerFlux(genie::GFluxI *flux)
Definition ship_geom_analyzer.hpp:85
Extents const & extents() const
Definition ship_geom_analyzer.hpp:97
void SetScannerNParticles(int n)
Definition ship_geom_analyzer.hpp:86
G4Teardown
Definition ship_geom_analyzer.hpp:54
genie::PathLengthList const & ComputeMaxPathLengths() override
Definition ship_geom_analyzer.cpp:264
TVector3 const & GenerateVertex(TLorentzVector const &x, TLorentzVector const &p, int tgtpdg) override
Definition ship_geom_analyzer.cpp:293
ShipGeomAnalyzer & operator=(ShipGeomAnalyzer const &)=delete
ShipGeomAnalyzer & operator=(ShipGeomAnalyzer &&)=delete
genie::PathLengthList const & ComputePathLengths(TLorentzVector const &x, TLorentzVector const &p) override
Definition ship_geom_analyzer.cpp:238
genie::PathLengthList const & GetMaxPathLengths() const
Definition ship_geom_analyzer.hpp:88
ShipGeomAnalyzer(ShipGeomAnalyzer &&)=delete
Definition genie_config.hpp:22
Definition genie_driver_setup.hpp:26
Definition ship_geom_analyzer.hpp:46
Definition ship_geom_analyzer.hpp:94
TVector3 hi
Definition ship_geom_analyzer.hpp:95
TVector3 lo
Definition ship_geom_analyzer.hpp:95