Architecture#
Architecture documentation explains how MC/DC translates flexible Python model definitions into particle-transport execution:
The architecture flow follows a Monte Carlo transport model from definition through one common preparation path, then branches into the Python, Numba-CPU, or Numba-GPU execution modes. The figure above emphasizes three major model-to-execution stages:
Simulation compilation discovers the Python objects owned by a
mcdc.Simulation, deduplicates them, and assigns simulation-local identifiers. Simulation Compilation explains model ownership, discovery, and finalization.Runtime preparation converts the compiled model into the structured
simulationstate and flatdataarray consumed by transport. Runtime Data Layout explains this numerical representation and its generated access helpers,mcdc_getandmcdc_set.Transport execution runs the common, adaptable transport implementation in the selected execution mode. Transport Execution explains how Python, Numba-CPU, and Numba-GPU execute it, including GPU code generation, memory placement, and Harmonize scheduling.
After transport, main.run_simulation passes the completed runtime state to mcdc.output for result aggregation and HDF5 serialization.
This final results-and-output stage completes the calculation lifecycle but remains outside the shared transport implementation shown in the figure.
Visit Python-First, Numba-Accelerated Design for the rationale, boundaries, and tradeoffs that shape MC/DC’s architecture. It explains why method development begins in unrestricted Python mode and may progress through Numba-CPU to Numba-GPU.
Component Responsibility#
The source tree follows the same separation of responsibilities shown in the architecture flow.
Model-facing components define, collect, and finalize the simulation.
Code-factory components coordinate object discovery and generate its runtime representation.
Transport components implement the numerical algorithms shared by all execution modes.
Output components aggregate and serialize completed results.
For methods development, object_/ and transport/ form the primary extension surface.
The code_factory/ package implements the framework-level compilation and generation bridge between them.
The table maps each component to its corresponding architecture role.
Paths in the component column are relative to the top-level mcdc/ package.
Component |
Architecture role |
Responsibility |
|---|---|---|
|
Model definition and compilation |
Defines Python-side model classes and their object-local finalization hooks. |
|
Model definition and control |
Owns model roots and configuration, resolves model-wide finalization, and controls compilation, visualization, and execution. |
|
Calculation configuration |
Parses command-line controls, configures process-wide execution behavior, and applies supported simulation-setting overrides before compilation. |
|
Shared static definitions |
Defines named numerical codes, event flags, numerical limits, and tolerances used across model, transport, and output components. |
|
Simulation compilation |
Coordinates recursive discovery, registration, and model-wide finalization. |
|
Calculation orchestration |
Coordinates runtime preparation, transport execution, result generation, runtime reporting, and backend finalization. |
|
Diagnostics and reporting |
Centralizes fatal errors, master-rank messages, calculation progress, and runtime summaries used across the model, transport, and output stages. |
|
Runtime preparation |
Coordinates framework-level packing, execution-resource allocation, backend configuration, and external runtime state. |
|
Runtime preparation |
Derive and expose simulation-specific values that compiled transport requires as literals. |
|
Support generation and runtime preparation |
Generates the shared Numba support and derives problem-dependent dtypes and prepared runtime state. |
|
Generated Numba support |
Define dtypes for the shared runtime schema, pure factories for problem-dependent dtypes, and accessors for variable-length fields in |
|
Development-time generation |
Runs the support generator after changes to the object model or generation logic. |
Runtime |
Prepared runtime state |
Store fixed-layout state and variable-length numerical data generated by |
|
Shared transport |
Implements the particle-transport algorithms used by every execution mode. |
|
Results and output |
Aggregates completed tally results and writes settings, tallies, eigenvalue data, saved particles, and runtime measurements to HDF5. |
The mcdc/object_ modules, mcdc.Simulation, and python_objects_compiler.py implement the model-definition and simulation-compilation stages.
Simulation Compilation explains their relationships, while Extending the Object Model explains how contributors can extend them.
main.prepare and numba_layers_generator.py use the generated Numba
support to create the runtime simulation and data objects that form the
data boundary between model compilation and transport.
Runtime Data Layout explains the complete representation,
Generated Numba Support and Problem-Dependent Dtypes distinguishes its three lifetimes, and
Rebuilding Numba Support gives the object model development workflow.
The mcdc/transport package implements the shared-transport stage.
Transport Execution explains how the execution modes run it.
Writing Numba-Compatible Transport Code provides practical rules for extending its algorithms.
Results and Output#
After the selected transport driver returns, main.run_simulation calls output.generate_output with the prepared simulation record, flat data array, and Python mcdc.Simulation.
output.py reads fixed fields directly, uses mcdc_get for variable-length runtime data, and retains Python-side settings and names where they form part of the output schema.
The module writes the primary HDF5 file, serializes tally and eigenvalue results, optionally saves particles, recombines census-based tally files, and appends runtime measurements.
It may reshape or aggregate finalized results for storage, but particle tracking and tally scoring remain responsibilities of transport/.
When a new result must persist after a run, define and prepare its runtime storage first, populate it during the appropriate transport or closeout stage, and add only the serialization step to output.py.
Changes to the user-visible HDF5 structure should also update the corresponding user documentation, regression coverage, and CHANGELOG.md entry.
Utility Module Scope#
util denotes helpers shared within the package that contains the module.
The complete import path therefore defines the helper’s architectural scope.
Module |
Scope |
|---|---|
|
Contains framework-neutral helpers shared across top-level MC/DC packages, currently the nested-list |
|
Supports Python model construction and finalization, including distribution conversion, validation, motion processing, and model-side reference data. |
|
Provides Numba-compatible helpers shared across transport domains, including binning, interpolation, atomic updates, local arrays, and backend-neutral simulation access. |
|
Contains numerical helpers shared specifically by neutron and electron physics implementations. |
|
Implements GPU-compatible replacements and compiler lowering for the adaptable operations exposed by |
Place a new helper in the narrowest package that contains all of its consumers.
Model-construction helpers may use ordinary Python and NumPy behavior, while helpers reachable from transport/ must follow the compiled-execution constraints described in Writing Numba-Compatible Transport Code.
Hardware-specific replacements belong in the corresponding backend adaptation.
Promote a helper to a broader util.py only when multiple sibling components genuinely share it, and avoid treating any utility module as a collection for otherwise unrelated code.