Skip to content

Choose a tag to compare

@maureeungaro maureeungaro released this 04 Aug 14:39
· 2 commits to main since this release

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 CopyOf meshes, 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, and G4Paraboloid.
  • 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, prepared ganalysis options, variable validation, and the Simple Flux avgy-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 emfield vs. the global global_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_digitized and no_true_info controls in the sensitivity
    workflow.
  • Added a Mirrors page to the Geometry documentation category covering the GMirror fields, 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 asciimap examples under the gfields module: asciimap_dipole.yaml (dipole-z), and the
    clas12 solenoid.yaml (cylindrical-z) and torus.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_lines and show_auxiliary_edges entries 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 -fieldAt and -fieldMapPoints query workflows.
  • Added asciimap load and -fieldAt tests for the dipole, solenoid, and phi-segmented torus
    example maps.
  • Updated the gemc_gfield_verbose integration 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 across beamOn calls, 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/mirrors example 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 gemc and 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.
  • GMagneto now loads only the fields that are actually used (those referenced by a volume emfield
    or by -global_field), instead of every configured gmultipoles/gfields entry. A field that no
    volume references — including any reset via -no_field — has its plugin and map skipped. The
    -fieldAt / -fieldMapPoints query 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 explicit global_field is 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 GUI beamOn completes. 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 mirrors sqlite table and the ascii mirrors file are optional: systems created before mirror
    support load unchanged. Mirror tables created before the transmittance property read it as unset.
  • Volumes ported from GEMC2 should carry the mirror name in the geometry mirror column instead of
    the legacy sensitivity: "mirror: <name>" string, and mirror definitions move from the GEMC2
    mirrors format to GMirror rows (pygemc GMirror publishes 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.txt reads one x y z triplet 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's G4FieldManager is
    installed on the ROOT world volume with propagation to all daughters; per-volume emfield labels
    still override it locally. The field options are now also aggregated into gdetector::defineOptions
    so the option resolves in every context that builds a detector.
  • Added the -no_field option (defined in the gfields module, consumed in
    GDetectorConstruction::ConstructSDandField). The value is a gvolume name, a whitespace/comma-
    separated list of names, or all. A first pass over the geometry collects the field names actually
    required — each volume's emfield minus the reset volumes, plus -global_field unless all was
    given — and GMagneto is 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, and all additionally
    suppresses the global field. GMagneto's constructor gained an optional required_fields set
    (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 default 0*mm leaves Geant4's
    propagation limit unchanged. Per-field minimum_step still controls the field integration driver.
  • The GUI field-line toggle now parses the configured ROOT G4Box dimensions and sends
    /vis/set/extentForField -dx dx -dy dy -dz dz mm before adding or refreshing the magnetic-field
    model. Non-G4Box roots keep Geant4's default scene-extent behavior.
  • Added periodic event logging in GEventAction driven by the log_every option (defined in the
    geventaction module). The option string is parsed once per worker into a log module N and an
    optional target thread NTH; malformed values (non-positive N, or NTH outside
    [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) for gemc search.
  • Added the -print_summary switch (defined in gemc_options.cc, consumed in gemc.cc).
    GSwitch and GOptions::defineSwitch gained an optional default_status parameter so a switch can
    be on by default, and switch value parsing (CLI -name=value and YAML) now accepts
    true/false/yes/no/y/n/on/off/1/0 case-insensitively, with YAML able to turn a default-on switch
    off. EventDispenser records the time of the first /run/beamOn and exposes beamOnIssued() /
    beamOnStartTime(); main captures 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
    prepend getIdentityMap(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 GTrackingAction and event-scoped GTrackProvenance registry. 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_ancestors is enabled, avoiding the legacy
    trajectory-container scans and repeated parent-chain searches.
  • -save_original_track replaces the placeholder otid/opid/opx/opy/opz=0 in
    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_ancestors implies original-track collection and publishes pid, tid, mtid, initial
    kinetic trackE, 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 an ancestors tree, and CSV lazily creates a
    per-thread _ancestors.csv file only when ancestor output is requested.
  • Added no_digitized and no_true_info scalar options to the event-action module. Both parse none,
    all, or whitespace- and comma-separated detector names. The event action skips digitizeHit() for
    detectors selected by no_digitized and skips collectTrueInformation() for detectors selected by
    no_true_info; digitized-only events remain eligible for streamer publication.
  • Added applyThresholds and applyInefficiencies options for whitespace- or comma-separated
    digitization-system names, or all. Enrolled systems delegate post-digitization acceptance to
    apply_thresholds_impl() and apply_efficiency_impl(); rejected hits also lose their true-info row
    when also_reject_true_info is 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.pc now lists GEMC's installed static archives by absolute ${libdir} paths in
    Libs: and moves Geant4, CLHEP, expat, zlib, sqlite3, yaml-cpp, and assimp to Libs.private.
    The file also publishes a plugin_link_args variable, set to
    -Wl,-undefined,dynamic_lookup on 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 asciimap field plugin (gfieldFactories/asciimap, built as gfieldasciimapFactory).
    GField_AsciiMapFactory decodes 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
    hot GetFieldValue path 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 the min/max expression of each coordinate<n> entry.
    Supported configurations include dipole-{x,y,z}, cylindrical-{x,y,z}, phi-segmented, and
    cartesian_3D[_quadrant] symmetries; linear or none interpolation; 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), and GetFieldValue is const with no mutable or static state.
  • GFieldDefinition gained a config_dir field, set in gfields::get_GFieldDefinition from 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 hardcoded dipole, 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_field is 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 ROOT G4Box; 0 keeps 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 1 and
    /vis/viewer/set/hiddenEdge 1, preserving the same paired behavior as the GUI auxiliary-edges
    toggle.
  • Added the ganalysis module. GAnalysisShard records all numeric GTrueInfoData variables and all
    integer and floating-point GDigitizedData observables under a run, detector, source, and variable key.
    Each detector record receives a sample identifier so matchAnalysisSeries() can reconstruct valid X/Y
    pairs after worker data is merged. GAnalysisAccumulator serializes shard merges and snapshots, tracks
    beamOn intervals and the current run, and clears or preserves the store at the next beamOn according
    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 GHistogram and GHistogram2D builders with independent optional minima and maxima, finite-entry
    accounting, underflow/overflow or out-of-range counts, constant-range expansion, and matched-sample 2D
    binning. GHistogramChart renders 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 cumulative ganalysis schema 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 .stl and .ply files by filename stem and load only meshes
    with matching SQLite geometry rows 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 with gemc-sqlite -cad. Meshes without matching database rows are ignored,
    replacing the legacy clas12Tags cad_<variation>.gxml path.
  • Added CopyOf support 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 GMirror gsystem 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's none/notDefined markers and a -1
    sigmaAlpha are accepted as unset. GSystem gains a system-scoped mirror map with
    addGMirror/getGMirror (error codes 213–215), deep-copied with the system.
  • GSystemFactory::loadSystem() calls a new loadMirrors() 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 a mirrors table, and substitutes
    NULL for a missing transmittance column; the ascii implementation reads the optional
    <system>__mirrors_<variation>.txt through the existing text-file search path. The CAD factory now
    overrides loadMirrors() too (gsystemFactories/cad/loadMirrors.cc), reading the same mirrors
    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. One G4OpticalSurface is 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 the matOptProps material
    (error if that material has no table) or built from the mirror vectors as RINDEX, REFLECTIVITY,
    EFFICIENCY, SPECULARLOBECONSTANT, SPECULARSPIKECONSTANT, BACKSCATTERCONSTANT, and TRANSMITTANCE.
    SkinSurface borders attach a G4LogicalSkinSurface to the volume logical; named borders attach a
    G4LogicalBorderSurface from 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 its G4Volume wrapper at solid-creation time, and the boolean applies the second
    operand's placement as translate ∘ rotation⁻¹, matching clas12Tags detector.cc. Operand
    dependencies resolve through the same retry loop as mothers, so components may appear in any order.
    Volumes using the Component material 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, alongside G4EllipticalTube and
    G4Paraboloid.
  • The sqlite mirrors loader tolerates databases whose mirrors table 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 GSteppingAction on 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 after MAX_TRACK_STEPS (10000), and tracks touching the Kryptonite
    material are killed immediately.
  • Added the predefined G4_AIR_Optical and Kryptonite materials. G4_AIR_Optical is air at
    1.29 mg/cm3 with RINDEX 1.00 at 2.034–4.136 eV, allowing optical photons to propagate. Kryptonite is
    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
    exact GTouchable::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-scene visman0106 warnings
    without triggering OGLSQt scene-tree initialization crashes.