Repository navigation
GEMC Release 0.5
This version includes:
- Mixed native and CAD geometry in one database-backed system.
- Typed absence and required values throughout the configuration schema.
- Typed optional metadata inside loaded geometry volumes.
- Coherent, sentinel-free calculated state for detector hits.
- Typed translation-table entries and scoped compile-time constants without placeholder macro state.
Release notes
- Added
-geant4_macro=run.macto execute a Geant4 macro after startup in batch, terminal, or GUI mode.
Macros control batch event generation through/run/beamOn; missing files and command errors fail the run. - Streaming readout now supports a shared
srofactory with one collector thread per crate. Experiment
implementations supply payloads, timing, frame processing, and output encoding. - SQLite and ASCII systems can contain native and CAD volumes together, removing the need for a separate
CADgsystementry. - Optional scalar settings now use typed
std::optionalvalues, while required schema entries are represented
explicitly instead of by string or numeric sentinels. - Geometry loading now converts empty and legacy unset spellings to
std::nulloptonce, so downstream field,
digitization, copy, boolean-solid, mirror, annotation, and imported-parameter code no longer interprets
serialized sentinel strings. GHitnow calculates and invalidates all derived values as one state, preventing partially calculated or
stale energy, time, position, process, and mother-track metadata.- Translation-table lookup remains fail-fast, but successful lookup now exposes the stored electronics entry
directly and insertion no longer depends on a sentinel-filled default object. - First-party defaults, labels, error codes, and serialized sentinels now use typed
inline constexpr
constants in their owning module namespaces instead of unscoped preprocessor definitions. - Multithreaded primary generation no longer shares mutable event state or rewrites shared logical-volume step
limits from workers, preventing example-dependent crashes when increasingnthreads. - GEMC now configures on stock systems without extra setup: Qt Svg and Qt Charts are optional, and the Geant4
pkg-config files are generated inside the build tree and resolved internally, so building no longer needs the
Qt Svg/Charts development packages nor a manually exportedPKG_CONFIG_PATH. A missing Qt Svg module only
drops the GUI toolbar icons; a missing Qt Charts module replaces the GUI analysis page with a short notice. - The matching
pygemcgeometry serialization and CAD authoring changes are documented in the
pygemc release notes.
Documentation
- Added a website guide for the 11 generator manipulation cards, with 100-event GEMC views,
verified Analyzer plots with compact layouts, transparent tube geometry, particles originating inside the
target, and reproducible asset-generation instructions. - Documented SRO configuration, the worker payload hook, implementation factories, and crate ownership.
Explained how one event can contribute to several frames and how timing guarantees let crates close frames. - Documented the generic
gparticleeventTimeWidthoption for assigning consecutive simulation events
positions on a continuous timeline, with an accessor for timing-aware consumers. - Ported the required JLAB SRO definitions and header setup to
clas12-systems/geometry_src/sro, removed
obsolete sources, and documented their provenance. GEMC retains only the generic SRO infrastructure. - Added an authoritative CI workflow guide covering the
pygemc -> src -> clas12-systemsdeployment chain,
workflow triggers, publication permissions, retry behavior, cross-repository contracts, and safe rollout. - Documented the local Meson threading suite and its repeat option alongside the CI scaling benchmarks.
- Organized README badges into Quality, Deploy, and Docs columns and documented machine-specific thread-scaling
reports without embedding changing benchmark results in the README. - Added
bin/scaling.shto clone ThreadScale, run a configurable local scintillator scaling sweep, retain its
report artifacts, and name its Markdown summary from the CPU, OS, architecture, and core count. It accepts
workload and thread-cap options and defaults to a shared rate plot comparing sequential no-output and
ROOT-output sweeps. Explicit output-disabled, YAML-configured, ROOT-only, and comparison modes are available,
additional GEMC arguments can be appended to every invocation, workloads can scale by requested thread
count for throughput measurements, and measurement options are forwarded to ThreadScale.
Examples
-
Added a tube-target generator manipulation example with combined XY and separate Z smearing,
sphere sampling, fixed theta/phi, angular models, prepared Analyzer plots, and checks against
generated records. -
Added a documented streaming readout example with crate, slot, channel, and random ADC payloads,
collecting complete time frames into one CSV file per crate. The plugin loads a translation table in
loadTTImpland resolves sensitive IDs to electronics addresses in the worker.
Tests
-
Standardized build and benchmark environment logs with CPU availability, model, topology, affinity, Docker
image, Geant4 configuration, and the Geant4 data-directory contents before GEMC runs. -
Thread-scaling compilation and benchmark jobs now use the Ubuntu 26.04 Geant4 base image and a freshly built
GEMC installation, with their dependencies installed explicitly. -
Macro startup checks verify that all usual starter commands finish before the user macro executes.
-
Added a full GEMC SRO example check covering geometry generation, plugin loading, identical output with
one and four workers, frame boundaries, and discard of unfinished frames. -
Added SRO crate tests for concurrent producers, time ordering, buffer limits, shutdown, resource lifetime,
and propagation of plugin/output failures; registered them in thesroandthreadingsuites. -
Added SRO service tests for concurrent crate creation, routing, inherited time boundaries, repeated runs,
cancellation across crates, automatic event progress, empty and missing events, and timing failures. -
Added Geant4 SRO integration tests for serial and multithreaded runs, empty collections, aborted events,
deterministic crate output, and repeated invocations using a dynamically loaded test implementation. -
Simplified the Deploy workflow gate so every successful
Testrun originating from a push tomain
publishes the GEMC images instead of being skipped by redundant workflow metadata checks. -
Added pull-request, weekly, and release thread-scaling benchmarks for the scintillator-barrel and Cherenkov
examples. Each example/output combination runs in a separate matrix job with its own report artifact and
hosted runner, sharing one benchmark installation build. The workflow uses ThreadScale's standalone command;
statistical runs repeat complete CPU sweeps and publish machine-named Markdown summaries with the complete
report artifacts. Matrix jobs continue independently if another scenario fails. -
Added a four-worker shared-generator record-integrity stress test and sequential, 1,000-event
scintillator-barrel integration tests across a bounded set of worker counts. Instead of one test per
core, thethreadingsuite now exercises at most 10 worker counts sampled evenly from 1 to the
machine's usable core count (always including serial and the full-core run), so the suite no longer
grows to hundreds of tests on many-core hosts. -
Increased the statistical scintillator-barrel scaling workload to 50,000 events so fixed initialization costs
do not dominate the measured throughput. -
Split push-triggered tests from compatibility tests dispatched by pygemc while sharing the same test
implementation. Successful trusted compatibility runs now rebuild and publish GEMC images, so
pygemc-only updates propagate without creating skipped Deploy and Binary Tarballs workflows. -
Added option-manager tests for required scalar accessors and absent, empty, and explicitly configured
optional scalar values. -
Added geometry-boundary tests for unset aliases, configured optional metadata, resolved-name lifecycle
errors, modifier shift and tilt transforms, and CAD detector-dimension handling. -
Added lifecycle tests for absent run state and premature EventDispenser beam-on timestamp access.
-
Added a hit-calculation test covering empty state, weighted values, process metadata, and cache invalidation.
-
Expanded the translation-table example test to cover scoped comparison modes, direct lookup references, and
preservation of the original entry after duplicate insertion. -
Rebuilt the complete target graph after migrating module constants and retained focused coverage across
options, geometry, fields, digitization, streaming, and translation-table consumers.
Addressed issues
- Issue #40: metrics
- Issue #41: uninitialized vars and #defines
- Issue #58: add test checking n threads.
- Issue #100: add vertex manipulation checks
- Issue #101: add ability to run geant4 macro
Compatibility notes
- Building GEMC now requires a C++20-capable compiler. The project compiles at
cpp_std=c++20to match the
ROOT build (also C++20) and remove ROOT's "C++ standard does not match configuration" warning. All supported
platforms already ship a sufficient compiler (GCC >= 11, Clang >= 13, Apple Clang >= 14); no action is needed
on the documented toolchains. - Build settings now live in the Meson project defaults. Remove
--native-file=core.inifrom setup commands;
existing build directories configured with that file need a fresh setup after its removal. - Replace
format: jlabsrowithformat: sroand animplementationplugin library basename. The old
fixed binary backend is removed; its required DAQ definitions are ported intoclas12-systems.
The implementation controls the file format and crate/run filenames.
Rebuild native digitizer and streamer plugins against the updated interfaces; detectors opt into SRO by
overridingGDynamicDigitization::stream_hit. Existing digitizers default to producing no SRO payloads. - The C++
GOptions::getScalarString(),getScalarInt(), andgetScalarDouble()APIs have been removed.
Callers must use the correspondinggetRequiredScalar*()orgetOptionalScalar*()accessor. - Optional
GVolumemetadata getters now returnconst std::optional<std::string>&. This affects
getEMField(),getDigitization(),getGIdentity(),getCopyOf(),getSolidsOpr(),getMirror(), and
getImportedFile(). The ASCIINULLtoken and SQLiteNULLrepresentation remain unchanged. GHit::calculateInfos(),GHit::getProcID(), and the misspelledGHit::getAvgGlobaPosition()have been
removed. Derived getters calculate the complete state lazily; usegetAvgGlobalPosition()for the corrected
spelling.getProcessName()now returnsconst std::optional<std::string>&. The parallel mother-track
getters have been replaced bygetMotherInfos()andgetMotherInfo(), whose PID and vertex members are
optional.GTouchable::getStepTimeAtElectronicsIndex()now returnsconst std::optional<int>&, and
GDigitizedData::getTimeAtElectronics()returnsstd::optional<int>.GSystem::getAnnotations()andGVolume::getParameters()now return optional strings. Missing native-solid
parameters are rejected when the solid is built; CAD volumes retain the legacy description fallback.GModifiershift and tilt values and theuseBackupMaterialoption are optional.GVolume::getShift()and
getTilt()now return optional strings, and configured tilt modifiers are applied during rotation building.GElectronicis no longer default-constructible, and its constructor now takes
GElectronic::ComparisonModeinstead of an integer. For a full-address comparison, replace mode2with
GElectronic::ComparisonMode::crate_slot_channel; modes0and1becomecrateandcrate_slot.
GTranslationTable::getElectronics()now returnsconst GElectronic&rather than a copy. Constructors and
setters reject negative crate, slot, or channel values.GVariableschemas use typed YAML defaults. Usegoptions::REQUIREDfor required entries and
std::nulloptfor optional entries; optional numeric values are available through
getOptionalScalarInt()andgetOptionalScalarDouble().- Particle momentum is required. A particle entry without
pis now a configuration error rather than a
particle with a sentinel momentum. An omitted random seed still selects an automatically generated seed,
while every explicitly supplied integer is treated as the requested seed. searchForDirInLocations()returnsstd::optional<std::filesystem::path>; absence is no longer encoded as
a string path.GAnalysisAccumulator::currentRunNumber()returnsstd::optional<int>. Premature access to resolved
GVolumenames, Analyzer run numbers, or the EventDispenser beam-on timestamp now reports a contextual
lifecycle error.- C++ convention constants now require their owning namespace, such as
gfields::ERR_WRONG_FIELD_NOT_FOUNDandgtranslationTable::EC__TTNOTFOUNDINTT. The remaining serialized
null marker is internal to format-boundary code. Unscoped macro aliases are not provided. Gparticle::shootParticle()now returns the generated runtime records. Callers that need those records should
consume the return value instead of calling the removedGparticle::getRuntimeRecords()method afterward.
Detailed list of changes and fixes
-
Install the Python environment from the resolved pygemc source directory when GEMC is built as a
subproject, fixing installation when the parent project shares its pygemc checkout. -
Filtered ROOT's
-std=compiler flags so dependency flags cannot override Meson's C++20 setting. -
The SRO example module now resolves framework symbols from GEMC in static builds, avoiding duplicate
framework/Geant4 archives and their static TLS requirements during plugin loading on Linux ARM64. -
Isolated Assimp's bundled pugixml namespace, fixing duplicate symbols when GEMC links static Assimp and
Geant4 libraries together while preserving static Geant4 linking for binary tarballs. -
Moved the active native-file settings into Meson project defaults and removed the CI native-file argument,
making direct setup and CI use the same C++ standard and library/linker preferences. -
Linked the SRO example module directly to
gparticlein shared builds, resolving its event-time accessor
through the corresponding framework library. -
Linked actions and their SRO runtime tests directly to
ghit, resolving missing allocator and RTTI symbols
in shared-library sanitizer builds. -
Added SRO C++ interfaces for owned implementation-defined payloads, timing bounds, crate processing,
and frame sinks. -
Added the standalone SRO crate thread with bounded input and ordering buffers, deterministic delivery,
implementation-owned finalization, and propagation of background failures to blocked producers. -
Added the shared SRO service with lazy crate creation, direct payload dispatch, and coordinated shutdown
and failure handling. -
Added automatic SRO safe-time tracking from closed events and crate delivery acknowledgments, with bounded
event bookkeeping and a separate progress thread. Timing and incomplete-frame policy remain in the
implementation. -
Connected SRO to worker digitizers and master/sequential run actions, including empty-event completion,
worker failure cancellation, aborted-event handling, and checked finalization after all workers return. -
The GEMC startup banner now reports the running executable directory. It no longer searches PATH for
geant4-config, which does not identify the Geant4 libraries linked into the running binary. -
Plugin option discovery now searches the GEMC installation and build directories used by the runtime loader,
fixing startup failures such asInvalid verbosity or debug requested: hipowithout an explicit plugin path. -
True-information records now include
nphotons, the number of unique optical-photon tracks in each hit,
so the GUI Analyzer can display photon counts for detectors such as LTCC. Optical-photon hits are drawn as
small green markers even when Geant4 assigns a terminal energy deposit to the photon. -
Automatic Analyzer Y-axis limits now round the highest bin count up to a clean decimal boundary, such as
2 for one entry or 110 for 105 entries, instead of applying a fractional 15 percent margin. -
Digitization plugins can request post-hit track termination. The sensitive detector applies
fStopAndKill
only after all touchables have stored the current step, allowing terminal optical detectors to prevent
trapped photons without adding geometry that can obscure the sensitive volume. -
A hit rejected by a digitization routine's intrinsic threshold or efficiency policy is now dropped from the
true-information bank as well as the digitized bank, matching GEMC2, where a below-threshold hit produced no
output at all. Rejection driven by the globalapplyThresholds/applyInefficienciesoptions on a
non-intrinsic plugin is unchanged and still writes the true-information row unlessalso_reject_true_info
is set. This removes the excess of low-energy true hits that calorimeter detectors such as the CLAS12 ECAL
recorded below their intrinsic FADC threshold. -
The Volumes tab now shows a mirror button for volumes with an optical surface. The button opens a closable
window containing the complete mirror definition. -
The native solid factory now builds
G4Ellipsoid(five parameters: the three semi-axes and the lower and
upper z cuts, with0cuts meaning a full ellipsoid), completing the primitive already accepted by the
parameter validator. The CLAS12 HTCC mirror surfaces rely on it. -
Boolean solids now support GEMC2's
Operation:@absolute-coordinate convention in addition to the default
Operation:one. A leading@token insolidsOprplaces both operands in their common mother frame, so
the second solid's transform accounts for the first solid's own rotation and position; without it the first
solid is taken at identity (the previous, only, behaviour). This reduces to the default when the first
operand is unrotated at the origin, and fixes booleans that subtract from a rotated solid, such as the
CLAS12 HTCC mirrors (subtracted from a rotated polycone barrel). The dependency resolver ignores the@
token when checking operand prerequisites. -
Geant4 object-factory selection now happens per volume: a
solid = CADrow uses the CAD mesh builder
while native rows in the same system keep the native builder. Relative SQLite mesh paths resolve from
both an asset root and its<system>/subdirectory, supporting combined experiment layouts such as
ltcc/stlswithout changing the storedparameters = "stls/<mesh>, <scale>". Thedescription
column remains available for descriptive text. Existing rows with the path indescriptionremain
supported. SQLite database filenames also resolve relative to the steering-card directory. -
Sensitive CAD volumes now omit native-solid dimension metadata, avoiding numeric parsing of the encoded
mesh path and scale when their digitization touchables are registered. -
Translation-table insertion now uses
try_emplace(), so duplicate keys preserve their existing entries
without requiring a default-constructibleGElectronicmapped type. -
Removed the unused
GOptions::option_verbosity_namemember and the obsolete post-lookup hardware-address
sentinel check. -
Scene-text depth, display angles, random seeds, geometry annotations and parameters, hit mother metadata,
touchable electronics indices, and digitized electronics times now model absence withstd::optional. -
Geometry modifiers, backup materials, run-context state, Analyzer run state, and ASCII field-map axis lookup
now use typed optional values instead of module-specific strings or-1. -
Added 225 typed
inline constexprconstants in place of first-party value and formatting macros. Feature
switches, call-site function-name expansion, Doxygen guards, and CADMesh lexer macros remain macros because
their behavior depends on preprocessing. -
Documented converted progress-bar and translation-table constants as C++ variables so Doxygen no longer
interprets them as removed preprocessor definitions, and corrected the SQLite factory's lifecycle reference. -
Updated the generated-documentation link checker for Doxygen 1.18's obfuscated external email links.
-
Primary generation now returns event records directly to each worker's thread-local output buffers, leaving
the particle definitions shared with the GUI free of mutable per-event state. -
Sensitive logical-volume step limits are installed once during master geometry construction instead of being
replaced concurrently by every worker during sensitive-detector setup. -
Qt Svg is no longer a build dependency. The GUI toolbar-button icons are rasterized at run time through the
QtSVGimage-format plugin, so a missing Qt Svg module only leaves the buttons without icons and no longer
fails configuration. -
Qt Charts is now optional. When present, the GUI analysis (histogram) page builds as before; when absent,
GEMC still builds and runs, the analysis page shows a "Qt6 Charts required" placeholder, and the Charts-only
ganalysisview sources and examples are dropped from the build. -
The Geant4
geant4.pc/geant4_core.pcpkg-config files are generated into the build tree and resolved by
invoking pkg-config with an augmentedPKG_CONFIG_PATH, so configuring GEMC no longer requires exporting
PKG_CONFIG_PATHor passing-Dpkg_config_path. Each Geant4 library is resolved throughfind_libraryso
Meson deduplicates the archives on the link line: a heavy target no longer repeats the same-lG4*once per
static module, which previously left GNUldreprocessing every Geant4 archive many times and could stall
the link. The generated files are still installed into<prefix>/lib/pkgconfigfor downstream projects such
as clas12-systems. -
Raised the project C++ standard to C++20. Geant4's generated
geant4_core.pchardcodes-std=c++17in its
cflags, which Meson appended after the project-std=c++20; because the last-stdwins, every
Geant4-consuming translation unit was silently pinned back to C++17, which also re-triggered ROOT's
"C++ standard does not match configuration (202002L)" warning. The Geant4 cflag ingestion now drops any
-std=token, so the projectcpp_stdgoverns the whole build and matching ROOT's C++20 removes the
mismatch warning. Geant4 11.4 headers compile cleanly at the newer standard. -
Silenced the
[[nodiscard]]std::stodwarnings in the CAD and SQLite geometry loaders by explicitly
discarding the return value; only the parsed-length out-parameter is used, to test whether the whole string
is numeric. -
Adopted C++20 standard-library features now that the project builds at C++20:
std::string::starts_with/
ends_withreplace therfind(x, 0) == 0prefix idiom and the manualcompare()suffix checks (including a
hand-rolledends_withlambda), associative-container membership tests usecontains()in place of
find(key) != end()across 11 files, andstd::numbers::pireplaces the non-standardM_PImacro. These are
clearer and more robust (no length-guard or iterator-misuse foot-guns) with no behavior change. -
Widened the
boolean_solidsexample world so the generator's uniform vertex spread (vx = -40 cm,
delta_vx = 12 cm, reaching-52 cm) stays inside it. A vertex sampled beyond the former+-45 cmworld
made Geant4 navigation dereference a null start volume and crash the run on roughly a third of seeds, which
surfaced as an intermittently failing example test.