GEMC Release 0.4
This version includes:
- CAD geometry and first-class optical mirrors.
- SQLite-backed loading for CAD volumes and mirror definitions.
- GAnalyzers for interactive 1D and 2D analysis in the Qt GUI.
Release notes
- Reworked CAD geometry around SQLite definitions, added reusable
CopyOfmeshes, and introduced
first-class optical mirrors for native and CAD volumes. Mirrors may be loaded from SQLite or ASCII
and attached as Geant4 skin or border surfaces. - Added the Qt GUI Analyzer for runtime-discovered true-information and digitized variables, configurable
1D and 2D histograms, one- or four-plot layouts, cross-run accumulation, and vector PDF export. - Expanded magnetic-field support with data-only ASCII maps, direct field queries, global and suppressed
field assignments, propagation-step control, field-only runs, and improved visualization. - Added native boolean union, subtraction, and intersection solids, together with
G4Polyhedra,
G4EllipticalTube, andG4Paraboloid. - Added detector-output controls for thresholds, inefficiencies, digitized and true-information
suppression, and thread-safe primary-track and ancestor provenance. - Improved run diagnostics and output with periodic event-rate logging, end-of-run summaries,
self-describing CSV hit identities, and cleaner plugin link metadata. - Fixed boolean-solid build-order crashes and GUI freezes, made mirror loading compatible with empty and
older SQLite schemas, and replaced quadratic sensitive-detector hit lookup with an O(1) event map.
Documentation
- Added a dedicated GUI Analyzer guide covering runtime discovery, multithreaded accumulation, all plot
controls, preparedganalysisoptions, variable validation, and the Simple Fluxavgy-versus-avgx
example. The page includes a source-derived SVG interface diagram and a 10,000-event example plot; the
GUI quickstart and documentation navigation now include the sixth Analyzer page. - Documented how a field is attached to geometry (per-volume
emfieldvs. the globalglobal_field
option) in the Fields overview page. - Added an "ASCII field maps" page to the Fields documentation category describing the
asciimap
plugin, the data-only map format, the YAML grid definition, and migration from the legacy clas12
<mfield>XML headers. - Documented the upcoming track-provenance switches, output fields, and backend-specific ancestor
output in the main README. - Documented the upcoming per-detector
no_digitizedandno_true_infocontrols in the sensitivity
workflow. - Added a Mirrors page to the Geometry documentation category covering the
GMirrorfields, the two
boundary-property sources, skin vs. border surface semantics, semi-transparent mirrors, and the
specular-lobe/sigmaAlpha roughness controls, plus a Mirrors example page.
Examples
- Added gfield example coverage for direct coordinate queries and ASCII point-list input.
- Added
asciimapexamples under the gfields module:asciimap_dipole.yaml(dipole-z), and the
clas12solenoid.yaml(cylindrical-z) andtorus.yaml(phi-segmented) maps translated from their
legacy<mfield>headers, each with a small but complete data-only map file. - Added a top-level
examples/fields/category with runnable torus, dipole, solenoid, and constant
field display examples. The torus and solenoid examples use ASCII field maps, and each example has
a simple enclosing solid chosen to make the field region visible in the Geant4 viewer. - Added
show_field_linesandshow_auxiliary_edgesentries to the example YAML files. General
examples leave them disabled, while the field-display examples enable them by default. - Added
examples/basic/boolean_solids: one shape per boolean operator — a plate with an off-center
hole (subtraction), a cross from a bar plus the same bar rotated by 90 degrees (union), and a lens
from two overlapping spheres (intersection) — showing how component volumes and their positions and
rotations define each operation. - Added
examples/optical/mirrors: three identical electrons cross a low-index gas radiator, each
aimed at one reflector plate — polished, rough (specular lobe with sigmaAlpha blur), and
semi-transparent (60% reflected, 30% transmitted) — with a color-matched photon detector panel per
mirror, so the panel counts compare the reflections under identical conditions. A fourth panel
counts the transmitted photons after an optical-vacuum gap (refractive index 1) that keeps the
electron below Cherenkov threshold behind the semi-transparent plate.
Tests
- Added gfield tests for
-fieldAtand-fieldMapPointsquery workflows. - Added
asciimapload and-fieldAttests for the dipole, solenoid, and phi-segmented torus
example maps. - Updated the
gemc_gfield_verboseintegration test to install a global field and exercise
-max_field_step=5*mm. - Added focused provenance tests for original-track resolution, branching ancestry, deduplication,
deterministic ordering, event reset, and compact original-only storage. ASCII, CSV, JSON, and
ROOT streamer tests now exercise ancestor serialization. - Added Analyzer tests for concurrent shard merging, scalar type preservation, cross-thread 2D pairing,
accumulation and replacement acrossbeamOncalls, histogram binning and ranges, 1D/2D Qt rendering,
equal-size four-plot layout, independent settings, logarithmic scales, PDF export, prepared options,
pending and unavailable variables, schema-free dynamic-plugin discovery, geometry reloads, and the
absence of an Analyzer service in batch mode. - GEMC CI now installs the Qt Charts development package in each Linux build environment, keeping
Analyzer dependencies with GEMC rather than adding them to the Geant4 base images. - The
examples/optical/mirrorsexample runs through the full examples suite (ascii and sqlite
geometry generation, gemc runs with ascii/root/csv outputs, and the photon y-vs-x plot), exercising
mirror loading in both factories and skin/border optical-surface construction.
Addressed issues
- Issue #27: check Maui's Visualization presentation to add goodies
- Issue #31: improve field ASCII and add SQLITE factory and apply it to gemc3
- Issue #42: output options for digitized and true infos
- Issue #57: add max field steps definitions
- Issue #59: TSGQt plotter see B5 example from presentation
- Issue #75: add histo tab with g4histos
- Issue #76: refined CAD interface, add SQLITE like gemc2
- Issue #77: add mirror interfaces
- Issue #78: add TOOLSG visualization of dose
- Issue #91: analyzer tab in GUI
- Issue #92: add original track infos
- Issue #142: scale fields
- Issue #172: add boolean operations
Supported platforms
Both x86_64 and ARM64 platforms are supported.
- macOS: 26
- Ubuntu: 24.04, 26.04
- AlmaLinux: 10
- Fedora: 44
- Debian: 13
- Arch Linux: latest
Dependencies
- Geant4: 11.4.1 or higher
- CLHEP: 2.4.6.0 or higher
- Xerces-C: 3.2 or higher
- Qt: 6.4.2 or higher, including the Charts module
Compatibility notes
- Downstream plugin builds on macOS can read
pkg-config --variable=plugin_link_args gemcand append
the returned linker option so plugin symbols are resolved from the host GEMC process at load time.
This avoids recording Geant4 dynamic-library dependencies in plugins that only consume GEMC APIs. GMagnetonow loads only the fields that are actually used (those referenced by a volumeemfield
or by-global_field), instead of every configuredgmultipoles/gfieldsentry. A field that no
volume references — including any reset via-no_field— has its plugin and map skipped. The
-fieldAt/-fieldMapPointsquery path is unaffected and still loads all configured fields.- Field-only GUI runs no longer require selecting a detector system first. If exactly one configured
field is present and no explicitglobal_fieldis set, GEMC attaches that field to the default
ROOT world for visualization startup. - Sensitive-detector plugins require no Analyzer API changes. Their numeric true-information and digitized
variables appear after at least one GUIbeamOncompletes. Prepared variables that the run does not
produce are retained as Not available rather than treated as a configuration error. Non-GUI runs
keep the previous event-processing path and incur no Analyzer collection overhead. - The
mirrorssqlite table and the ascii mirrors file are optional: systems created before mirror
support load unchanged. Mirror tables created before thetransmittanceproperty read it as unset. - Volumes ported from GEMC2 should carry the mirror name in the geometry
mirrorcolumn instead of
the legacysensitivity: "mirror: <name>"string, and mirror definitions move from the GEMC2
mirrors format toGMirrorrows (pygemcGMirrorpublishes both sqlite and ascii forms).
Detailed list of changes and fixes
- Added gfield query mode:
-fieldAt="x y z"accepts one unit-bearing coordinate triplet, while
-fieldMapPoints=file.txtreads onex y ztriplet per non-comment ASCII line. Query mode loads
the configured field definitions, prints one result row per field and point, and exits before normal
simulation setup. - Added the
-global_field=<name>option (defined in the gfields module, consumed in
GDetectorConstruction::ConstructSDandField). When set, the named field'sG4FieldManageris
installed on the ROOT world volume with propagation to all daughters; per-volumeemfieldlabels
still override it locally. The field options are now also aggregated intogdetector::defineOptions
so the option resolves in every context that builds a detector. - Added the
-no_fieldoption (defined in the gfields module, consumed in
GDetectorConstruction::ConstructSDandField). The value is a gvolume name, a whitespace/comma-
separated list of names, orall. A first pass over the geometry collects the field names actually
required — each volume'semfieldminus the reset volumes, plus-global_fieldunlessallwas
given — andGMagnetois constructed only when that set is non-empty, receiving it as a filter so
only the needed plugins and maps are loaded. Per-volume names are matched against both the gvolume
name and the fully-qualified Geant4 name, an unmatched name emits a warning, andalladditionally
suppresses the global field.GMagneto's constructor gained an optionalrequired_fieldsset
(empty meaning "load everything", preserving the field-query path). - Added the
-max_field_step=<length>option (defined in the gfields module, consumed in
GMagneto). Positive values are parsed with GEMC's Geant4-unit parser and passed to
G4PropagatorInField::SetLargestAcceptableStep(), while the default0*mmleaves Geant4's
propagation limit unchanged. Per-fieldminimum_stepstill controls the field integration driver. - The GUI field-line toggle now parses the configured ROOT
G4Boxdimensions and sends
/vis/set/extentForField -dx dx -dy dy -dz dz mmbefore adding or refreshing the magnetic-field
model. Non-G4Boxroots keep Geant4's default scene-extent behavior. - Added periodic event logging in
GEventActiondriven by thelog_everyoption (defined in the
geventaction module). The option string is parsed once per worker into a log moduleNand an
optional target threadNTH; malformed values (non-positiveN, orNTHoutside
[0, nthreads-1]) are ignored with a single warning. Each worker keeps its own event count and
timing anchor, so both the trigger and the reported rate are per thread. The option description
carries searchable keywords (module, event, rate, thread) forgemc search. - Added the
-print_summaryswitch (defined ingemc_options.cc, consumed ingemc.cc).
GSwitchandGOptions::defineSwitchgained an optionaldefault_statusparameter so a switch can
be on by default, and switch value parsing (CLI-name=valueand YAML) now accepts
true/false/yes/no/y/n/on/off/1/0case-insensitively, with YAML able to turn a default-on switch
off.EventDispenserrecords the time of the first/run/beamOnand exposesbeamOnIssued()/
beamOnStartTime();maincaptures the program start time and, before teardown, prints the total
wall-clock time, the time since beamOn, and the average event rate computed as
getTotalNumberOfEvents()divided by the beamOn elapsed time. - CSV gstreamer event-mode digitized, run-mode digitized, and event-mode true-info publishers now
prependgetIdentityMap(hit->getIdentity())entries to each hit row and emit the same keys in the
header. This exposes identity metadata alongside the existing detector observables in the generated
CSV files. - Added a worker-local
GTrackingActionand event-scopedGTrackProvenanceregistry. Original track
IDs are calculated once as tracks begin, using compact vectors indexed by Geant4 track ID. Full
initial track records are retained only when-save_all_ancestorsis enabled, avoiding the legacy
trajectory-container scans and repeated parent-chain searches. -save_original_trackreplaces the placeholderotid/opid/opx/opy/opz=0in
true-information hits with the primary track's id, particle id, and momentum. The provenance
registry keeps these in compact per-track vectors, propagated from each track's original ancestor,
so they are available in the lightweight original-only mode without retaining full track records.
-save_all_ancestorsimplies original-track collection and publishespid,tid,mtid, initial
kinetictrackE, momentum, and vertex for each selected track and ancestor.- Ancestor records are copied into the event-owned data collection before streamer buffering. ASCII
and JSON include an event ancestor bank, ROOT writes anancestorstree, and CSV lazily creates a
per-thread_ancestors.csvfile only when ancestor output is requested. - Added
no_digitizedandno_true_infoscalar options to the event-action module. Both parsenone,
all, or whitespace- and comma-separated detector names. The event action skipsdigitizeHit()for
detectors selected byno_digitizedand skipscollectTrueInformation()for detectors selected by
no_true_info; digitized-only events remain eligible for streamer publication. - Added
applyThresholdsandapplyInefficienciesoptions for whitespace- or comma-separated
digitization-system names, orall. Enrolled systems delegate post-digitization acceptance to
apply_thresholds_impl()andapply_efficiency_impl(); rejected hits also lose their true-info row
whenalso_reject_true_infois set. Both options remain disabled by default for GEMC2 parity. - Extended the post-digitization policy API with mutable
GDigitizedData, non-streamed transient values,
and detector-intrinsic threshold and efficiency hooks. This lets plugins change or suppress individual
observables and keep efficiency random draws separate from deterministic detector response. - Generated
gemc.pcnow lists GEMC's installed static archives by absolute${libdir}paths in
Libs:and moves Geant4, CLHEP, expat, zlib, sqlite3, yaml-cpp, and assimp toLibs.private.
The file also publishes aplugin_link_argsvariable, set to
-Wl,-undefined,dynamic_lookupon Darwin and empty elsewhere, for downstream plugin modules that
should resolve GEMC/Geant4 symbols from the loading executable instead of linking those libraries
directly. - Added the
asciimapfield plugin (gfieldFactories/asciimap, built asgfieldasciimapFactory).
GField_AsciiMapFactorydecodes the symmetry once into an enum, stores the map in contiguous
std::vector<float>buffers addressed with precomputed strides (instead of the legacy
float**/float***pointer pyramids), and caches the rotation trigonometry at load time, so the
hotGetFieldValuepath does no string comparison and no pointer chasing. The map rows carry their
coordinates, so they may be listed in any order and are validated against the YAML grid on load.
The coordinate column unit is taken from themin/maxexpression of eachcoordinate<n>entry.
Supported configurations includedipole-{x,y,z},cylindrical-{x,y,z},phi-segmented, and
cartesian_3D[_quadrant]symmetries;linearornoneinterpolation; scaling; and translation and
rotation. The YAML contains the grid definition, and the companion map contains only data rows.
The reader is thread-safe: GEMC builds the field registry per worker thread (G4ThreadLocal
GMagneto), andGetFieldValueisconstwith no mutable or static state. GFieldDefinitiongained aconfig_dirfield, set ingfields::get_GFieldDefinitionfrom the
first parsed YAML file, so plugins can resolve companion data files (such as ASCII maps) relative to
the YAML that defined the field.- The gfields example driver now probes every configured field by name (
GMagneto::getFieldNames)
instead of a hardcodeddipole, so it works for the multipole, solenoid, and torus examples alike. - Startup now proceeds for field-only configurations even when no detector system is selected. The
detector construction can auto-attach a single configured field to ROOT when no explicit
global_fieldis set, and the default ROOT-only scene includes a visible viewer box so Geant4 has
an extent for camera setup. - Added
examples/fields/constant,examples/fields/dipole,examples/fields/solenoid, and
examples/fields/torus. The examples cover constant and multipole fields plus solenoid and torus
ASCII field maps, each with a simple visible enclosing solid suited to its field shape. - Added the scalar display option
show_field_lines, available as-show_field_lines=<n>and from
YAML. Positive values emit/vis/scene/add/magneticField <n>after setting the field extent from
the configured ROOTG4Box;0keeps field lines disabled. - Added the scalar display option
show_auxiliary_edges, available as-show_auxiliary_edges=<bool>
and from YAML. When enabled, startup emits/vis/viewer/set/auxiliaryEdge 1and
/vis/viewer/set/hiddenEdge 1, preserving the same paired behavior as the GUI auxiliary-edges
toggle. - Added the
ganalysismodule.GAnalysisShardrecords all numericGTrueInfoDatavariables and all
integer and floating-pointGDigitizedDataobservables under a run, detector, source, and variable key.
Each detector record receives a sample identifier somatchAnalysisSeries()can reconstruct valid X/Y
pairs after worker data is merged.GAnalysisAccumulatorserializes shard merges and snapshots, tracks
beamOnintervals and the current run, and clears or preserves the store at the nextbeamOnaccording
to the GUI Accumulate state.makeAnalysisAccumulator()returns null outside GUI mode. - Integrated Analyzer collection with the event and run actions. Each worker writes only to its own shard;
true-information and digitized values are recorded after the detector response is accepted, and the shard
is moved to the shared accumulator at the worker boundary. The GUI refreshes from a locked snapshot after
the run, and geometry reloads clear the accumulator before discovering the replacement plugins. - Added
GHistogramandGHistogram2Dbuilders with independent optional minima and maxima, finite-entry
accounting, underflow/overflow or out-of-range counts, constant-range expansion, and matched-sample 2D
binning.GHistogramChartrenders 1D counts with linear or logarithmic Y axes and 2D heatmap or boxes
styles with linear or logarithmic Z colors, and writes the current chart through Qt's PDF backend. - Added
GAnalysisView, selected by the sixth SVG button in the left GUI bar. One source radio selection
supplies both X and Y; 2D mode enables the Y selector and style list and relabels the scale as Z. Four
position tabs own independent settings above an exact equal-cell chart grid, and each axis endpoint has
its own automatic checkbox. Run, plugin, and variable menus are repopulated from runtime snapshots. - Added
ganalysis_plots(one or four),ganalysis_accumulate, and the cumulativeganalysisschema with
position, run, plugin, source, dimension, X/Y variables, bins, four automatic-limit flags, four fixed
limits, title, 2D style, and scale fields. Startup names remain red pending the first run, become normal
when discovered, or gain the Not available suffix when validation fails. - Reworked the CAD system factory to index
.stland.plyfiles by filename stem and load only meshes
with matching SQLitegeometryrows for the selected experiment, system, variation, and run. Database
metadata supplies material, placement, sensitivity, and other volume fields; definitions are uploaded
from one YAML or JSON file withgemc-sqlite -cad. Meshes without matching database rows are ignored,
replacing the legacy clas12Tagscad_<variation>.gxmlpath. - Added
CopyOfsupport to CAD systems. A copied CAD volume reuses its source mesh's solid and logical
volume, allowing one STL to be placed multiple times without loading duplicate meshes. - Added the
GMirrorgsystem object (gmirror.h/.cc), constructed from the canonical 16-field
serialized row (name, description, type, finish, model, border, matOptProps, photonEnergy,
indexOfRefraction, reflectivity, efficiency, specularlobe, specularspike, backscatter,
transmittance, sigmaAlpha). Mandatory fields and property-table lengths are validated at
construction; values parse with Geant4 units; GEMC2'snone/notDefinedmarkers and a-1
sigmaAlpha are accepted as unset.GSystemgains a system-scoped mirror map with
addGMirror/getGMirror(error codes 213–215), deep-copied with the system. GSystemFactory::loadSystem()calls a newloadMirrors()virtual with a no-op default, so the GDML
factory is unaffected. The sqlite implementation selects the mirror columns explicitly by name
(independent of table column order), skips databases without amirrorstable, and substitutes
NULLfor a missingtransmittancecolumn; the ascii implementation reads the optional
<system>__mirrors_<variation>.txtthrough the existing text-file search path. The CAD factory now
overridesloadMirrors()too (gsystemFactories/cad/loadMirrors.cc), reading the samemirrors
table from the geometry database so a CAD volume (e.g. an STL Winston cone) can carry an optical
surface.- Added
G4World::buildOpticalSurfaces()(g4system/g4mirrors.cc), phase 5 of the world
construction, running after all volumes are placed. OneG4OpticalSurfaceis created per
(system, mirror) and cached for reuse. The surface type/finish/model strings map to the Geant4
enums through lookup tables covering the full 11.x sets; unknown strings exit with
ERR_G4SURFACECONFIGINVALID. The properties table is borrowed from thematOptPropsmaterial
(error if that material has no table) or built from the mirror vectors as RINDEX, REFLECTIVITY,
EFFICIENCY, SPECULARLOBECONSTANT, SPECULARSPIKECONSTANT, BACKSCATTERCONSTANT, and TRANSMITTANCE.
SkinSurfaceborders attach aG4LogicalSkinSurfaceto the volume logical; named borders attach a
G4LogicalBorderSurfacefrom the volume physical to the same-system border volume physical. - The native factory builds boolean solids from
solidsOpr: each volume's frame rotation and position
are recorded on itsG4Volumewrapper at solid-creation time, and the boolean applies the second
operand's placement astranslate ∘ rotation⁻¹, matching clas12Tagsdetector.cc. Operand
dependencies resolve through the same retry loop as mothers, so components may appear in any order.
Volumes using theComponentmaterial contribute their solid to boolean operations without receiving a
material or placement of their own. - The logical volume of a geometry entry is no longer created before its solid is available: a boolean
volume can precede its operands in the build order, and a logical volume constructed on a null solid
would be placed and crash the Geant4 navigation voxelization at run initialization. - Added
G4Polyhedra(GEMC2 "Pgon" parameter order: phiStart, phiTotal, numSides, numZPlanes,
rInner[], rOuter[], zPlane[]) to the native solid factory, alongsideG4EllipticalTubeand
G4Paraboloid. - The sqlite mirrors loader tolerates databases whose
mirrorstable is bare (created when no system
defines mirrors) in addition to databases created before mirror support. - The GUI volume tree no longer computes every volume's mass at startup: Geant4 estimates a boolean
solid's cubic volume by Monte Carlo (1M points by default), which froze the GUI for boolean-heavy
systems. Mass, volume, and density are now computed when a volume is selected, boolean solids use a
bounded 100k-point estimate, and the mass is not propagated to daughters, so any selection stays
interactive. The properties panel labels change from "Total Mass"/"Average Density" to
"Mass"/"Density" accordingly. - Added
GSteppingActionon worker threads, restoring GEMC2 track guards. Optical photons are killed after
MAX_OPTICAL_PHOTON_STEPS(100), preventing photons trapped by total internal reflection from stalling
an event. All tracks are killed afterMAX_TRACK_STEPS(10000), and tracks touching theKryptonite
material are killed immediately. - Added the predefined
G4_AIR_OpticalandKryptonitematerials.G4_AIR_Opticalis air at
1.29 mg/cm3 with RINDEX 1.00 at 2.034–4.136 eV, allowing optical photons to propagate.Kryptoniteis
an ultra-low-density argon material whose tracks are removed by the stepping action. - Replaced sensitive-detector linear hit scans with a per-event
unordered_map<string, GHit*>keyed by
GTouchable::cellKey(). The key combines identity values and the type-specific discriminator with the
exactGTouchable::operator==semantics, reducing hit lookup from quadratic to constant time and
avoiding severe slowdowns in photon-rich events. - Using OGLSQt instead of TOOLSSG_QT_GLES as many feautres run on the GPU instead of the CPU.
- Visualization startup now initializes the Geant4 world, opens the viewer without an attached scene,
then creates a scene containing the ROOT volume. This prevents empty-scenevisman0106warnings
without triggering OGLSQt scene-tree initialization crashes.