Skip to content

Choose a tag to compare

@maureeungaro maureeungaro released this 08 Oct 14:07
· 2 commits to main since this release

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.mac to 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 sro factory 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
    CAD gsystem entry.
  • Optional scalar settings now use typed std::optional values, 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::nullopt once, so downstream field,
    digitization, copy, boolean-solid, mirror, annotation, and imported-parameter code no longer interprets
    serialized sentinel strings.
  • GHit now 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 increasing nthreads.
  • 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 exported PKG_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 pygemc geometry 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 gparticle eventTimeWidth option 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-systems deployment 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.sh to 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
    loadTTImpl and 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 the sro and threading suites.

  • 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 Test run originating from a push to main
    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, the threading suite 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


Compatibility notes

  • Building GEMC now requires a C++20-capable compiler. The project compiles at cpp_std=c++20 to 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.ini from setup commands;
    existing build directories configured with that file need a fresh setup after its removal.
  • Replace format: jlabsro with format: sro and an implementation plugin library basename. The old
    fixed binary backend is removed; its required DAQ definitions are ported into clas12-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
    overriding GDynamicDigitization::stream_hit. Existing digitizers default to producing no SRO payloads.
  • The C++ GOptions::getScalarString(), getScalarInt(), and getScalarDouble() APIs have been removed.
    Callers must use the corresponding getRequiredScalar*() or getOptionalScalar*() accessor.
  • Optional GVolume metadata getters now return const std::optional<std::string>&. This affects
    getEMField(), getDigitization(), getGIdentity(), getCopyOf(), getSolidsOpr(), getMirror(), and
    getImportedFile(). The ASCII NULL token and SQLite NULL representation remain unchanged.
  • GHit::calculateInfos(), GHit::getProcID(), and the misspelled GHit::getAvgGlobaPosition() have been
    removed. Derived getters calculate the complete state lazily; use getAvgGlobalPosition() for the corrected
    spelling. getProcessName() now returns const std::optional<std::string>&. The parallel mother-track
    getters have been replaced by getMotherInfos() and getMotherInfo(), whose PID and vertex members are
    optional.
  • GTouchable::getStepTimeAtElectronicsIndex() now returns const std::optional<int>&, and
    GDigitizedData::getTimeAtElectronics() returns std::optional<int>.
  • GSystem::getAnnotations() and GVolume::getParameters() now return optional strings. Missing native-solid
    parameters are rejected when the solid is built; CAD volumes retain the legacy description fallback.
  • GModifier shift and tilt values and the useBackupMaterial option are optional. GVolume::getShift() and
    getTilt() now return optional strings, and configured tilt modifiers are applied during rotation building.
  • GElectronic is no longer default-constructible, and its constructor now takes
    GElectronic::ComparisonMode instead of an integer. For a full-address comparison, replace mode 2 with
    GElectronic::ComparisonMode::crate_slot_channel; modes 0 and 1 become crate and crate_slot.
    GTranslationTable::getElectronics() now returns const GElectronic& rather than a copy. Constructors and
    setters reject negative crate, slot, or channel values.
  • GVariable schemas use typed YAML defaults. Use goptions::REQUIRED for required entries and
    std::nullopt for optional entries; optional numeric values are available through
    getOptionalScalarInt() and getOptionalScalarDouble().
  • Particle momentum is required. A particle entry without p is 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() returns std::optional<std::filesystem::path>; absence is no longer encoded as
    a string path.
  • GAnalysisAccumulator::currentRunNumber() returns std::optional<int>. Premature access to resolved
    GVolume names, 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_FOUND and gtranslationTable::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 removed Gparticle::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 gparticle in 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 as Invalid verbosity or debug requested: hipo without 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 global applyThresholds / applyInefficiencies options on a
    non-intrinsic plugin is unchanged and still writes the true-information row unless also_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, with 0 cuts 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 in solidsOpr places 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 = CAD row 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/stls without changing the stored parameters = "stls/<mesh>, <scale>". The description
    column remains available for descriptive text. Existing rows with the path in description remain
    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-constructible GElectronic mapped type.

  • Removed the unused GOptions::option_verbosity_name member 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 with std::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 constexpr constants 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
    Qt SVG image-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
    ganalysis view sources and examples are dropped from the build.

  • The Geant4 geant4.pc / geant4_core.pc pkg-config files are generated into the build tree and resolved by
    invoking pkg-config with an augmented PKG_CONFIG_PATH, so configuring GEMC no longer requires exporting
    PKG_CONFIG_PATH or passing -Dpkg_config_path. Each Geant4 library is resolved through find_library so
    Meson deduplicates the archives on the link line: a heavy target no longer repeats the same -lG4* once per
    static module, which previously left GNU ld reprocessing every Geant4 archive many times and could stall
    the link. The generated files are still installed into <prefix>/lib/pkgconfig for downstream projects such
    as clas12-systems.

  • Raised the project C++ standard to C++20. Geant4's generated geant4_core.pc hardcodes -std=c++17 in its
    cflags, which Meson appended after the project -std=c++20; because the last -std wins, 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 project cpp_std governs 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::stod warnings 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_with replace the rfind(x, 0) == 0 prefix idiom and the manual compare() suffix checks (including a
    hand-rolled ends_with lambda), associative-container membership tests use contains() in place of
    find(key) != end() across 11 files, and std::numbers::pi replaces the non-standard M_PI macro. These are
    clearer and more robust (no length-guard or iterator-misuse foot-guns) with no behavior change.

  • Widened the boolean_solids example 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 cm world
    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.