Skip to content

Choose a tag to compare

@maureeungaro maureeungaro released this 17 Jun 15:52
· 9 commits to main since this release

GEMC Release 0.3

This version includes:

  • New python module: pygemc
  • Generators in GUI
  • Photon detection
  • Binary gemc tarballs for Linux CI platforms
  • Namespaced module includes (<gemc/module/header.h>)
  • Theme-aware SVG toggle icons for display options
  • Volume inspection from the geometry tree
  • Geometry-tree right panel redesign: sticky style buttons, expanding parameters box, system-aware visibility
  • Unified value*unit notation for gparticle kinematic fields
  • digitization_variation option to override the gsystem variation for digitization constants/tables
  • GEMC_PLUGIN_PATH and -plugin_path for external plugin discovery
  • Pre-parse plugin options hook for dynamic plugin option registration
  • Clearer command-line help: reviewed every module's option/switch help, added usage examples, and
    implemented the previously-advertised search <value> command
  • ROOT gstreamer and event-action bug fixes
  • Fixed TOOLSSG_OFFSCREEN batch crash (race condition between screenshot rendering and vis subthread)
  • Optical photon trajectories rendered in cyan in both GUI and offscreen screenshots
  • Fixed geometry-tree opacity slider resetting volume color to original
  • Plotting tests for digitizing-SD examples and Cherenkov photon hit maps

Release notes

  • Added Linux binary gemc tarballs to the development deployment workflow. The archives contain the
    installed executable, support files, selected smoke tests, gemc.env, and a generated Geant4 data
    installer, and are attached to the dev release.
  • Isolated ROOT linkage to the ROOT gstreamer plugin so the main gemc executable can run without ROOT
    shared libraries.
  • Reorganized all source modules under a gemc/ subdirectory and adopted <gemc/module/header.h>
    namespaced #include directives throughout.
  • Moved the API and analyzer into the pygemc Python module; examples and tests now run through it, and
    Python workflows no longer need GEMC-specific environment variables — only the gemc executable in
    PATH.
  • Replaced the separate punit, aunit, and vunit fields in gparticle with direct value*unit
    notation on each kinematic field (e.g. p: 4*GeV, theta: 23*deg, vz: -10*cm). A plain number without
    a unit still falls back to MeV / deg / cm with a logged warning. See the compatibility notes below.
  • Added a digitization_variation option to override the per-system gsystem variation used when
    digitization routines load their calibration constants and translation tables.
  • Added GEMC_PLUGIN_PATH and -plugin_path for external plugin discovery, plus a pre-parse hook that
    registers plugin-specific options so they appear in gemc <config>.yaml -h and can be set from the
    command line or YAML.
  • Reviewed every module's command-line option/switch help, added usage examples, and implemented the
    previously-advertised search <value> command.
  • Made the GUI follow the active Qt palette consistently (setup tables, log/search widgets, geometry-tree
    color controls, navigation buttons, splash screen) and replaced the four display-option toggle buttons
    with theme-aware SVG icons.
  • Improved the geometry tree: volume inspection in a dedicated viewer window, a redesigned right panel
    (sticky style buttons, expanding parameters box, system-aware visibility), a per-volume description
    field shown in the properties panel, and "Centre"/"Twinkle" navigation buttons.
  • Added optical-photon detection support: optical photon trajectories are now drawn in cyan in both the GUI
    and offscreen screenshots, distinguishing them from other neutral particles.
  • Added y-vs-x analyzer plotting in pygemc and used it for the Cherenkov homepage photon hit-position
    maps.
  • Fixed an intermittent SIGSEGV in batch mode with TOOLSSG_OFFSCREEN, caused by a race between
    screenshot rendering and the Geant4 vis subthread freeing the same scene-graph nodes.
  • Fixed several GUI geometry-reload issues: crashes when reloading geometry after running events, and hits
    not being recorded after a setup-tab reload or on repeated BeamOn calls.
  • Fixed a SIGSEGV in the ROOT gstreamer plugin and an event-mode null-pointer crash when a plugin
    returned no digitized data.
  • Fixed the geometry-tree opacity slider silently resetting a volume's color to its original value.
  • The related pygemc release notes are maintained separately in the
    gemc/pygemc repository.

Documentation

  • Added binary tarball installation instructions with per-platform download,
    unpack, Geant4 data install, environment setup, and smoke-test commands.
  • Added ROOT-free binary installation prerequisite tabs and retitled the full
    source-build prerequisite section to distinguish it from binary installation.
  • Updated the Cherenkov homepage documentation for the neutral radiator
    variations and one-electron quick workflow.
  • Updated the Cherenkov example documentation to use a one-electron quick
    workflow and to note that optical constants may be unphysical in the demo.

Examples

  • Added a scintillator_barrel example: a 48-paddle barrel array of G4Trap scintillator paddles
    distributed on a circle (distribute_on_circle) with flux digitization, with each paddle's wider
    face oriented radially outward.
  • Added annotations.yaml files to the b1 and material examples demonstrating g4decoration
    (scale, axes, event ID, date, logo, frame) and g4text 2D/3D overlays.
  • Reworked the Cherenkov optical example to use neutral demonstration radiator variation names
    (lowIndexRadiator, mediumIndexRadiator, highIndexRadiator) instead of real gas names, and a
    one-electron quick workflow.
  • Migrated all examples to the pygemc API and the unified value*unit gparticle notation, and made
    the YAML steering cards more consistent across examples.

Tests

  • Added a Binary Tarballs workflow that uploads deploy-produced tarballs to
    the dev release and then tests those release assets. It can also run the
    same install checks on a nightly schedule or by manual dispatch.
  • Removed redundant dev prefixes from deploy and sanitizer matrix job names.
  • Updated CodeQL to use build-mode: none for all analyzed languages and
    removed the manual Geant4 container build from the analysis workflow.
  • Made installed examples database generation skip cleanly when sanitizer
    builds intentionally skip installing the Python environment.
  • Made the Test and Sanitize workflows use the same runner/container execution
    model and shared matrix source; Sanitize differs only by passing the sanitizer
    option to ci/build.sh and by naming sanitizer log artifacts.
  • Switched sanitizer builds to shared GEMC project libraries so plugin-loading
    tests avoid Linux/aarch64 static TLS exhaustion from sanitizer-instrumented
    static archives.
  • Added analyzer coverage in pygemc for y-vs-x plotting and CLI image output.
  • Added gemc-analyzer plot tests to the examples test suite: examples with a digitizing SD
    (simple_flux, b1, b2) get a dedicated CSV gemc run at priority -15 feeding into a
    gemc-analyzer histogram test at priority -20; b1 overrides n to 50 events so the
    dosimeter fires reliably (a 6 MeV gamma has only ~27% interaction probability per event in
    bone). The Cherenkov example gets a y-vs-x photon hit-position map from its true-info stream.

Addressed issues

  • Issue #62: fix reload geometry : run/beamOn does not work after a reload
  • Issue #74: add generator in the GUI with tabs fore each particle.
  • Issue #84: add photon_detector
  • Issue #86: add options for background colors and num cloud points
  • Issue #89: Pyvista installed on the container
  • Issue #93: add pygemc repo for api and analyzer
  • Issue #94: add barrel scintillator array example
  • Issue #95: add text and arrow options to g4display
  • Issue #96: fix detector not showing in the gui if running with just gemc -gui
  • Issue #97: geometry reload crash
  • Issue #103: [High] EventDispenser: run weights are not normalized before stochastic sampling
  • Issue #104: [High] Run header stores the Geant4 internal run ID instead of the GEMC run number
  • Issue #105: [High] Run-level normalization applied once per streamer causes double-normalization
  • Issue #106: [High] Multiple same-format gstreamer outputs collapse into a single streamer
  • Issue #107: [High] Multipole field parameters bypass unit parsing (stod/stoi ignore unit expressions)
  • Issue #108: [High] Inverted dependency-stall check aborts geometry/material build when progress is made
  • Issue #109: [High] Sphere vertex sampling compares squared radius against un-squared bound
  • Issue #110: [High] Fix CAD loader mutating dirLocation in-place inside the per-file loop
  • Issue #111: [High] Add missing opacity field in addVolumeFromFile so GVolume gets all 21 parameters
  • Issue #112: [High] Run optical-property size validation once after parsing, not on every rayleigh token
  • Issue #113: [High] ProcessHits mutates the persistent map GTouchable, leaking state across events
  • Issue #115: [High] JSON streamer emits invalid JSON for multi-detector digitized output
  • Issue #116: [High] JSON streamer never closes the event "header" object, nesting siblings inside it
  • Issue #117: [High] add_rotation() emits a multi-token rotation string the C++ parser silently drops
  • Issue #118: [High] set_rotation() then add_rotation() raises AttributeError due to inconsistent rotations type
  • Issue #119: [High] make_polycone() length check uses and instead of or, missing single-array mismatches
  • Issue #120: [High] make_trap() passes an extra self to already-bound methods, raising TypeError
  • Issue #121: [Medium] gemc help with no topic crashes with std::logic_error (null argv read)
  • Issue #122: [Medium] GConfiguration ignores constructor args; argparse defaults clobber factory/variation/runno
  • Issue #123: [Medium] Tarball is not self-contained: docs claim static Geant4 linking but gemc is dynamically linked
  • Issue #124: [Medium] EventDispenser::variation is never initialized, always passing empty string to digitization
  • Issue #125: [Medium] YAML file detection uses substring match and misses YAML::BadFile, causing misparse and crashes
  • Issue #126: [Medium] Worker run-data stashed every run but drained only when run streamers exist
  • Issue #127: [Medium] GHit::nsteps() returns Es.size(), which is empty unless HitBit 0 is set
  • Issue #128: [Medium] CSV run-mode rows print uninitialized event_number and thread_id
  • Issue #129: [Medium] CSV row newline only written inside the double-observables loop, dropped when a hit has no doubles
  • Issue #130: [Medium] GPhysics dereferences possibly-null physics list before the null check
  • Issue #131: [Medium] Switches cannot be turned off from the CLI, breaking documented YAML-override precedence
  • Issue #132: [Medium] Stop leaking heap ifstream on every ASCII system/material load
  • Issue #133: [Medium] parseFileAndRemoveComments throws std::out_of_range on a comment before the first newline
  • Issue #134: [Medium] gemc-sqlite CLI builds queries via raw f-strings (breakage + SQL injection)
  • Issue #135: [Low] Make G4World own its G4Volume wrappers to stop a leak per volume on geometry reload
  • Issue #136: [Low] Add rule-of-five to GFrameDataCollection to prevent double-free if copied
  • Issue #137: [Low] Guard against null GetVisAttributes() in G4Ttree_item constructor
  • Issue #139: [Low] convert_angle(out='gon') returns radians instead of gradians
  • Issue #169: Checkout of untrusted code in a privileged context

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

Compatibility notes

  • gparticle unit fields removed: the punit, aunit, and vunit fields are
    no longer recognized. Replace them by attaching the unit directly to each value:

    # before
    gparticle:
      - name: e-
        p: 2300
        punit: MeV
        theta: 23.0
        aunit: deg
        vz: -10.0
        vunit: cm
    
    # after
    gparticle:
      - name: e-
        p: 2300*MeV
        theta: 23*deg
        vz: -10*cm

    A plain number without a unit is still accepted and defaults to MeV / deg / cm
    (with a logged warning), so existing steering cards that omit the unit fields
    continue to work.


Detailed list of changes and fixes

  • Added ci/package_install.sh to build installable tarballs from CI install
    prefixes while excluding python_env and keeping only gemc plus selected
    smoke-test executables in bin.
  • Generated gemc.env and install_geant4_data.sh during tarball packaging
    from the Geant4 data environment exported by geant4-config --sh.
  • Added package-export stages to the deploy/test Dockerfile generation and moved
    dev release asset upload into the dedicated Binary Tarballs workflow.
  • Added ci/binary_packages.py as the dedicated source of truth for ROOT-free
    binary runtime packages used by tarball tests.
  • Added per-plugin dependency handling in Meson and moved root_dep from the
    core gstreamer static library to gstreamer_root_plugin.
  • Added the splash_time option for GUI splash-screen timing and passed a
    0.2-second startup splash duration from gemc.cc.
  • Added a configurable splash-screen display duration and set the GEMC GUI
    startup splash to remain visible briefly before closing.
  • Emitted a setup-view geometry reload signal and used it to recreate the GUI
    volume tree page from GDetectorConstruction::get_g4volumes_map().
  • Fixed setup-tab geometry reloads so the Volumes tab is rebuilt from the
    reloaded detector geometry.
  • Reopened the Geant4 GUI scene during setup-tab reloads so reloaded geometry is
    displayed before running events.
  • Split setup-tab reload handling into an immediate GUI preview rebuild and a
    one-time non-propagating G4RunManager::ReinitializeGeometry(true, false)
    before BeamOn, avoiding stale world pointers during MT worker startup.
  • Synchronized setup-tab system selection back into runtime options so pressing
    Run after Reload uses the same geometry shown in the display.
  • Removed stale Geant4 visualization models before pre-run geometry
    reinitialization.
  • Temporarily detached the concrete Geant4 visualization manager during pre-run
    geometry reinitialization so stale preview-world models are not dereferenced.
  • Updated the gdetector example to register detector construction with the
    Geant4 run manager before reload, matching the main executable setup.
  • Added a runtime option update helper and used it to keep the gsystem and
    runno options aligned with setup-tab reload selections.
  • Deferred visualization scene setup until startup or reloaded geometry contains
    displayable volumes.
  • Deferred Geant4 initialization when starting gemc -gui without a selected
    system, preventing synthetic ROOT-world visualization state before setup-tab
    reloads.
  • Skipped the initial /run/initialize in GUI sessions that start without a
    gsystem, so setup-tab reloads install the first initialized geometry.
  • Replaced the GUI board newline regular expression with explicit line-ending
    normalization to avoid invalid QRegularExpression warnings.
  • Allowed gemc -gui to open with an empty setup tab when the default gemc.db
    is not present, instead of exiting with SQLite error code 209.
  • Made setup-tab database discovery non-fatal at GUI construction time, leaving
    the setup view empty when the configured SQLite file is unavailable.
  • Allowed the Volumes tab to start empty when no Geant4 world has been built,
    avoiding a fatal pre-window geometry-map lookup.
  • Added a detector-construction geometry-state check and used it to avoid
    querying Geant4 volumes before startup or setup reload has built a world.
  • Generated the installed examples SQLite database during meson install so the
    GUI setup tab is populated after a normal install.
  • Added an install script that rebuilds examples/gemc.db from the installed
    example geometry scripts using the installed python_env.
  • Initialized the Geant4 run manager during the GUI pre-run geometry handoff so
    BeamOn is not ignored after setup-tab reloads.
  • Made the GUI pre-run handoff remove stale visualization models, rebuild
    geometry, and call G4RunManager::Initialize() before event processing.
  • Rebuilt setup-tab run geometry from fresh system descriptors so preview
    reloads do not leave factory-populated systems that duplicate ROOT volumes at
    BeamOn.
  • Kept GUI reload system selections descriptor-only and cloned fresh systems for
    each Geant4 construction, avoiding duplicate root volumes when running after
    a setup-tab reload.
  • Fixed a GUI crash (SIGABRT in G4ToolsSGSceneHandler::GetOrCreateNode) when reloading geometry after
    running events: refreshGeometryTree now tracks whether a viewer already exists and skips /vis/open on
    subsequent reloads, avoiding a second viewer creation that triggers a synchronous ToolsSG refresh before
    the Qt widget is ready.
  • Fixed hits not being recorded after a GUI setup-tab reload or on the second and subsequent BeamOn calls:
    introduced a digiplugins_need_reload flag in GDetectorConstruction so loadDigitizationPlugins()
    (which clears the shared digitization-routines map) runs only when geometry actually changed, not on every
    ConstructSDandField() invocation. The flag is reset by reload_geometry() and
    prepare_geometry_for_run() so the next master-thread ConstructSDandField() refreshes the map exactly
    once per geometry change, avoiding a fatal "no digitization routine registered" error when task-parallel
    MT workers clear the shared map mid event loop.
  • Fixed a crash ("no digitization routine registered for collection X") when running events after switching
    geometries in the GUI setup tab: G4SDManager accumulates sensitive detectors across reloads and fires
    empty hit collections for stale detectors, so EndOfEventAction now skips any collection whose SD name is
    not in the current digitization-routines map with a non-fatal warning instead of terminating the process.
  • Cleared the digitization-routines map at the start of loadDigitizationPlugins() so that emplace()
    cannot silently reuse stale plugin objects from a prior load.
  • Reset Geant4 visualization accumulation before setup-tab geometry reloads and
    before the pre-run geometry handoff; after reload the GUI redraws geometry
    only, then re-adds hit and trajectory models immediately before BeamOn.
  • Cleared accumulated GUI visualization event drawings on setup-tab geometry
    reloads so hits and trajectories from a previous run are not redrawn with the
    newly loaded system.
  • Added a deferred setup-tab column resize after the initial Qt event-loop pass
    so startup column widths match post-selection widths.
  • Made the setup-tab experiment/system column resize after initial population,
    matching the readable sizing already applied after user selections.
  • Updated GUI widgets that previously used fixed light colors or static SVG
    rendering so they resolve colors from the current Qt palette.
  • Added light and dark PNG variants for the GEMC architecture splash and select
    the resource from the current application palette to avoid Qt SVG CSS
    rendering differences.
  • Added theme-specific rasterized splash images for the built-in GEMC
    architecture splash and a configurable scale plus palette-aware border.
  • Cleaned up CI job labels, opted JavaScript-based workflow actions into Node.js 24, and adjusted CodeQL to
    avoid the Actions overlay-base fallback warning.
  • Skipped installed examples database generation when
    GEMC_SKIP_PYTHON_ENV_INSTALL=1 or the installed python_env interpreter is
    absent, fixing sanitizer installs that intentionally omit the Python
    environment.
  • Replaced the sanitizer-specific matrix generator with matrix_sanitize
    output from ci/distros_tags.sh, keeping the sanitizer matrix on the same OS,
    architecture, Geant4, runner, and container definitions as the Test and Deploy
    matrices.
  • Consolidated Test, Sanitize, and Deploy matrix generation in
    ci/distros_tags.sh; the shared matrix source now emits normal build,
    sanitizer, and manifest matrices with consistent image, Geant4, runner, and
    container fields.
  • Changed the Test workflow to source the g4install container entrypoint, load
    the selected Geant4 module, and run ci/build.sh directly in the job
    container; logs are packaged from /root/src/logs without a BuildKit
    logs-export stage.
  • Simplified the Test workflow so it runs directly inside the matching
    ghcr.io/gemc/g4install:<geant4>-<os>-<tag> job container instead of
    generating and building a temporary Dockerfile.
  • Changed the GEMC Meson module loop from static_library() to library() so
    sanitizer CI can request shared project libraries with
    -Ddefault_library=shared -Ddefault_both_libraries=shared while normal builds
    keep the default static-library behavior.
  • Reduced sanitizer-build static linkage by allowing GEMC internal libraries to
    follow Meson's default_library option and selecting shared GEMC libraries
    for sanitizer builds, avoiding static-TLS pressure when tests load plugins
    with dlopen.
  • Better generator statistics for some examples
  • Api and analyzer moved to pygemc module
  • Examples and tests adapted to use pygemc
  • Removed the need for GEMC-specific environment variables in Python example
    workflows: the API runs through the pygemc module, and users only need the
    executable in PATH.
  • Fixed typos for various goptions help
  • Fixed meson tests checking dir
  • Added gemc-analyzer --plot yvsx support through the pygemc subproject,
    including configurable x/y limits for position plots.
  • Added y-vs-x analyzer plotting support in pygemc and used it for the
    Cherenkov homepage plots.
  • Reworked the Cherenkov example variations to use neutral radiator names
    instead of real gas names.
  • Updated the Cherenkov optical example with neutral demonstration radiator names:
    lowIndexRadiator, mediumIndexRadiator, and highIndexRadiator.
  • Replaced the old Cherenkov homepage image names with radiator-based names and
    updated the plots from one-event runs.
  • Moved all source modules from the repository root into a gemc/ subdirectory;
    updated every cross-module #include to the <gemc/module/header.h> namespaced
    form; added corresponding symlinks under src/gemc/; updated CI scripts and
    Doxygen configuration to match the new layout.
  • Changed the default g4display background color to a dark navy (r=0, g=18, b=43 in 8-bit, stored
    as the normalized Geant4 triplet 0 0.07059 0.16863).
  • Moved the Geant4 dialog panel to the bottom of the right content area in the
    main GUI layout for a cleaner vertical flow.
  • Added a description member to GVolume and wired it into the geometry-tree
    properties panel (descriptionLabel).
  • Added "Centre" (centre_1.svg / centre_2.svg) and "Twinkle" SVG icon buttons
    to the GQTButtonsWidget in gtree; connected to the appropriate Geant4
    visualization UI commands for the selected volume.
  • Added color-picker buttons (QColorDialog) for scale and frame annotation
    colors in g4displayutilities; connected to G4SceneProperties color update
    methods.
  • Added four SVG icon files (anti_aliasing.svg, auxiliary_edges.svg,
    field_lines.svg, hidden_lines.svg) for the GQTToggleButtonWidget display
    toggles; removed legacy PNG/XCF assets; updated both the module-level and root
    qtresources.qrc files; extended GQTToggleButtonWidget with a state-aware
    refresh_svg_icons() that replaces the #aaddff background placeholder and
    currentColor tokens with the correct QPalette values on construction, on
    every toggled signal, and on changeEvent.
  • Added inspectVolume() slot to GTree: reads the active G4VGraphicsSystem
    nickname at runtime (falls back to TOOLSSG_QT_GLES), saves the current
    viewer name, calls /vis/open, /vis/scene/create, /vis/sceneHandler/attach,
    /vis/scene/add/volume <name> -1, sets white background and a text2D label,
    flushes, then restores focus with /vis/viewer/select; button text is set to
    "Inspect <volumename>" when a volume node is selected in the tree.
  • Added plugin_path option and GEMC_PLUGIN_PATH environment variable support to GManager::registerDL
    so plugins installed to a separate prefix are found without touching LD_LIBRARY_PATH.
  • Extended DynamicLib constructor to search GEMC_PLUGIN_PATH directories before the existing
    <gemc_root>/lib/ and <gemc_root>/build/ fallbacks; diagnostic output on failure shows the current
    env-var value and a usage hint for both GEMC_PLUGIN_PATH and -plugin_path.
  • Fixed a segmentation fault in the ROOT gstreamer plugin: getOrInstantiateDigitizedDataTree,
    getOrInstantiateTrueInfoDataTree, and getOrInstantiateGeneratedParticleTree now call rootfile->cd()
    before creating TTree objects, matching the existing pattern in getOrInstantiateHeaderTree; without
    this, ROOT's thread-local gDirectory on a Geant4 worker thread does not point at the output file.
  • Fixed event-mode null-pointer crash in gEventAction.cc: GDigitizedData pointers returned as nullptr
    by digitizeHitImpl (the base-class default for plugins that have not yet implemented digitization) are now
    skipped instead of being inserted into the collection, matching the existing run-mode null guard and
    preventing the ROOT streamer from dereferencing a null pointer when building the tree schema.
  • Removed punit, aunit, and vunit from the gparticle option schema.
    Added parseG4Value() in gparticle_options.cc: reads each kinematic YAML
    field as a string, calls gutilities::getG4Number() directly when a *unit
    suffix is present, and falls back to the documented default unit (MeV / deg / cm)
    with a logger warning when only a plain number is given. The Gparticle
    constructor now receives G4-unit-converted doubles and no longer performs
    internal unit conversion. Schema defaults for numeric fields updated to
    "0*MeV", "0*deg", "0*cm" so unspecified optional fields do not trigger
    the fallback warning. The Lund file reader pre-converts its computed doubles
    via gutilities::getG4Number(value, unit) before passing them to the
    constructor.
  • Added gemc-analyzer plot tests to examples/meson.build: the examples_map gains optional
    plot_var, plot_yvsx, and n_events keys. For each example that carries one of these keys,
    a dedicated examples_run_csv_<branch>_<example> test (priority -15) runs gemc with
    factory: ascii and a CSV streamer, then examples_plot_<branch>_<example> (priority -20)
    invokes gemc-analyzer to save a PNG. simple_flux and b2 plot totEdep; b1 plots
    dose with n_events: 50 so enough gammas traverse the bone dosimeter. The Cherenkov example
    uses plot_yvsx: true to generate a 2D avgx-vs-avgy photon hit-position map from
    its true-info stream with ±55 cm axis limits.
  • Added gemc::collectPluginOptions(int argc, char* argv[]) declared in gemc_options.h and
    implemented in gemc_options.cc. Before the main GOptions parsing constructor is called in
    main(), GEMC scans every YAML file listed in argv for gsystem entries, resolves each
    <name>.gplugin using the plugin search path, and probes for an optional
    extern "C" GOptions* definePluginOptions() symbol. Options declared there are merged into
    the schema so plugin-specific options appear in gemc <config>.yaml -h, are saved to the
    configuration snapshot, and can be set from the command line or YAML alongside core options.
    The pre-parse search path honours -plugin_path= CLI arguments, plugin_path: YAML keys,
    and the GEMC_PLUGIN_PATH environment variable in that priority order. On Linux,
    RTLD_NODELETE keeps the probed library resident so the later GManager::dlopen during
    detector construction gets the same OS handle without re-executing static initialisers; on
    macOS, reference counting achieves the same effect. Plugin verbosity keys are registered by
    passing the channel name to the single-argument GOptions constructor inside
    definePluginOptions, adding verbosity.<plugin> to the schema independently of the global
    gdigitization verbosity.
  • Changed the g4view default background color from white to a dark navy (0 0.07059 0.16863,
    i.e. r=0 g=18 b=43 in 8-bit) for better contrast with typical detector geometry colors.
  • Redesigned GTree::right_widget(): moved GQTButtonsWidget (wireframe / surface / cloud /
    centre) to the top of the outer QVBoxLayout with QSizePolicy::Fixed so it is always visible
    regardless of selection state; gave bottomPanel a stretch factor of 1 so it fills all remaining
    space and the parameters QTextEdit (also stretch=1 inside blayout) expands with the window;
    added border: 1px solid black to the parameters box stylesheet; hidden the parameters box
    (setVisible(false)) when a system node is selected, showing it only for volume nodes that
    carry non-empty parameter data; added formatVal() in gtree.cc to format all numeric
    parameter tokens to at most three significant decimal places and to collapse values smaller
    than 10⁻⁷ to zero.
  • Fixed geometry-tree color/opacity desync: GTree::set_color was sending the
    /vis/geometry/set/colour command without updating the G4Ttree_item model cache and
    without including the alpha channel, so a subsequent opacity-slider change read stale RGB
    values from the model and reset the visible color. set_color now calls
    item->set_color(c), reads item->get_opacity() to preserve the current alpha, and
    appends it to the colour command. Changed G4Ttree_item::set_color to accept
    const QColor&. The twinkle restore branch in onTwinkleStep now also calls
    item->set_color(twinkleSavedColor) and item->set_opacity(twinkleSavedOpacity) before
    issuing the restore command, keeping the model consistent after animation.
  • Fixed intermittent SIGSEGV (bus error / pointer-authentication failure on ARM64) in batch mode
    when using TOOLSSG_OFFSCREEN. The crash was a data race between the main thread in
    GRunAction::EndOfRunActiontake_screenshot()G4ToolsSGOffscreenViewer::DrawView()
    tools::sg::separator::render() traversing scene-graph nodes, and G4VisManager::G4VisSubThread
    concurrently running G4ToolsSGSceneHandler::ClearTransientStore()_xzm_free() on the same
    nodes. Disassembly of G4VisManager::EndOfRun() confirmed that the vis subthread thread::join()
    happens inside EndOfRun(), which Geant4 11.4 calls after GRunAction::EndOfRunAction(), leaving
    a window where the render and the free overlap. The fix removes take_screenshot() from
    GRunAction entirely and moves the three screenshot UImanager commands into
    EventDispenser::processEvents(), after each g4uim->ApplyCommand("/run/beamOn ...") returns.
    By that point G4VisManager::EndOfRun() has already been called and the vis subthread is joined,
    so the scene graph is stable. The TOOLSSG_OFFSCREEN check is resolved once at construction from
    the g4view.driver option node so EventDispenser acquires no dependency on the g4display
    library.
  • Added a drawByParticleID trajectory model alongside the existing drawByCharge model in
    gemcUtilities::initial_commands(). Optical photon trajectories are assigned the color cyan via
    /vis/modeling/trajectories/create/drawByParticleID and
    /vis/modeling/trajectories/drawByParticleID-0/set opticalphoton cyan. Without this model, optical
    photons inherit the drawByCharge neutral-particle default color, making them indistinguishable
    from neutrons and other neutral tracks — particularly against the light-colored default background
    used in screenshots and the GUI.
  • Reviewed and clarified command-line option/switch help across the whole gemc/ tree, adding usage
    examples where they were missing. In the core goptions module: reworded the built-in -gui, -i,
    conf_yaml, and tt help; corrected the conf_yaml help, which described the saved-configuration
    filename incorrectly; expanded the verbosity and debug examples; and implemented the
    search <value> command, which printHelp() advertised but was never wired up (it now lists
    options and switches whose name or description contains the search term).
  • Fixed stale or copy-pasted option help in several modules:
    • gphysics: the phys_list help lost the literal + that joins extra constructors (it rendered
      as "using the sign"); fixed a "Livermode" → "Livermore" typo; added concrete -phys_list examples.
    • gstreamer: the ebuffer option reused the large gstreamer help block; it now has its own help
      and example, and the structured option registers under the literal name "gstreamer".
    • gsystem: corrected the ascii_db description (copied from sql) and added examples for sql,
      ascii_db, experiment, and runno.
    • gfields: added a gmultipoles usage example.
    • g4display: polished the dawn help wording and made its default phi/theta use the same
      value*unit notation as g4camera/g4light.
  • Clarified the two distinct run-number options that coexist in the full application: runno
    (gsystem, selects the geometry/conditions variation) versus run (eventDispenser, the run number
    assigned to generated events and the key used with -run_weights); both descriptions and help now
    cross-reference each other and the automatic Geant4 g4runno.
  • Added a digitization_variation option (defined by the gdynamicdigitization module) that overrides the
    per-system gsystem variation used when digitization routines load their calibration constants and
    translation tables. When unset (the default), each routine follows the variation of the gsystem it
    belongs to, resolved per digitization name at geometry load in loadDigitizationPlugins(); when set, the
    override applies to every routine. The resolved variation is stored on each GDynamicDigitization routine
    and passed to loadConstants()/loadTT(). This also fixes the variation reaching those calls, which
    previously defaulted to an empty string because EventDispenser's variation member was never assigned.
  • Removed the unused checkOverlaps switch from g4system: it was registered and shown in help but
    never read. Overlap checking is controlled solely by the integer check_overlaps option, whose
    value 1 already enables the G4PVPlacement surface overlap check (pSurfChk) at volume placement;
    the help now documents this and the doxygen page was updated to match.