Skip to content

Commit 5d3bc29

Browse files
author
skywalker_cn
committed
Merge branch 'develop' into virtual_lattice_0.15.2
2 parents 03f6b5b + d118356 commit 5d3bc29

527 files changed

Lines changed: 22842 additions & 12795 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ jobs:
7575
LIBMESH: ${{ matrix.libmesh }}
7676
NPY_DISABLE_CPU_FEATURES: "AVX512F AVX512_SKX"
7777
OPENBLAS_NUM_THREADS: 1
78+
PYTEST_ADDOPTS: --cov=openmc --cov-report=lcov:coverage-python.lcov
7879
# libfabric complains about fork() as a result of using Python multiprocessing.
7980
# We can work around it with RDMAV_FORK_SAFE=1 in libfabric < 1.13 and with
8081
# FI_EFA_FORK_SAFE=1 in more recent versions.
@@ -171,11 +172,37 @@ jobs:
171172
uses: mxschmitt/action-tmate@v3
172173
timeout-minutes: 10
173174

174-
- name: after_success
175+
- name: Generate C++ coverage (gcovr)
175176
shell: bash
176177
run: |
177-
cpp-coveralls -i src -i include -e src/external --exclude-pattern "/usr/*" --dump cpp_cov.json
178-
coveralls --merge=cpp_cov.json --service=github
178+
# Produce LCOV directly from gcov data in the build tree
179+
gcovr \
180+
--root "$GITHUB_WORKSPACE" \
181+
--object-directory "$GITHUB_WORKSPACE/build" \
182+
--filter "$GITHUB_WORKSPACE/src" \
183+
--filter "$GITHUB_WORKSPACE/include" \
184+
--exclude "$GITHUB_WORKSPACE/src/external/.*" \
185+
--exclude "$GITHUB_WORKSPACE/src/include/openmc/external/.*" \
186+
--gcov-ignore-errors source_not_found \
187+
--gcov-ignore-errors output_error \
188+
--gcov-ignore-parse-errors suspicious_hits.warn \
189+
--print-summary \
190+
--lcov -o coverage-cpp.lcov || true
191+
192+
- name: Merge C++ and Python coverage
193+
shell: bash
194+
run: |
195+
# Merge C++ and Python LCOV into a single file for upload
196+
cat coverage-cpp.lcov coverage-python.lcov > coverage.lcov
197+
198+
- name: Upload coverage to Coveralls
199+
if: ${{ hashFiles('coverage.lcov') != '' }}
200+
uses: coverallsapp/github-action@v2
201+
with:
202+
github-token: ${{ secrets.GITHUB_TOKEN }}
203+
parallel: true
204+
flag-name: C++ and Python
205+
path-to-lcov: coverage.lcov
179206

180207
finish:
181208
needs: main
@@ -184,5 +211,5 @@ jobs:
184211
- name: Coveralls Finished
185212
uses: coverallsapp/github-action@v2
186213
with:
187-
github-token: ${{ secrets.github_token }}
214+
github-token: ${{ secrets.GITHUB_TOKEN }}
188215
parallel-finished: true

AGENTS.md

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# OpenMC AI Coding Agent Instructions
2+
3+
## Project Overview
4+
5+
OpenMC is a Monte Carlo particle transport code for simulating nuclear reactors,
6+
fusion devices, or other systems with neutron/photon radiation. It's a hybrid
7+
C++17/Python codebase where:
8+
- **C++ core** (`src/`, `include/openmc/`) handles the computationally intensive transport simulation
9+
- **Python API** (`openmc/`) provides user-facing model building, post-processing, and depletion capabilities
10+
- **C API bindings** (`openmc/lib/`) wrap the C++ library via ctypes for runtime control
11+
12+
## Architecture & Key Components
13+
14+
### C++ Component Structure
15+
- **Global vectors of unique_ptrs**: Core objects like `model::cells`, `model::universes`, `nuclides` are stored as `vector<unique_ptr<T>>` in nested namespaces (`openmc::model`, `openmc::simulation`, `openmc::settings`, `openmc::data`)
16+
- **Custom container types**: OpenMC provides its own `vector`, `array`, `unique_ptr`, and `make_unique` in the `openmc::` namespace (defined in `vector.h`, `array.h`, `memory.h`). These are currently typedefs to `std::` equivalents but may become custom implementations for accelerator support. Always use `openmc::vector`, not `std::vector`.
17+
- **Geometry systems**:
18+
- **CSG (default)**: Arbitrarily complex Constructive Solid Geometry using `Surface`, `Region`, `Cell`, `Universe`, `Lattice`
19+
- **DAGMC**: CAD-based geometry via Direct Accelerated Geometry Monte Carlo (optional, requires `OPENMC_USE_DAGMC`)
20+
- **Unstructured mesh**: libMesh-based geometry (optional, requires `OPENMC_USE_LIBMESH`)
21+
- **Particle tracking**: `Particle` class with `GeometryState` manages particle transport through geometry
22+
- **Tallies**: Score quantities during simulation via `Filter` and `Tally` objects
23+
- **Random ray solver**: Alternative deterministic method in `src/random_ray/`
24+
- **Optional features**: DAGMC (CAD geometry), libMesh (unstructured mesh), MPI, all controlled by `#ifdef OPENMC_MPI`, etc.
25+
26+
### Python Component Structure
27+
- **ID management**: All geometry objects (Cell, Surface, Material, etc.) inherit from `IDManagerMixin` which auto-assigns unique integer IDs and tracks them via class-level `used_ids` and `next_id`
28+
- **Input validation**: Extensive use of `openmc.checkvalue` module functions (`check_type`, `check_value`, `check_length`) for all setters
29+
- **XML I/O**: Most classes implement `to_xml_element()` and `from_xml_element()` for serialization to OpenMC's XML input format
30+
- **HDF5 output**: Post-simulation data in statepoint files read via `openmc.StatePoint`
31+
- **Depletion**: `openmc.deplete` implements burnup via operator-splitting with various integrators (Predictor, CECM, etc.)
32+
- **Nuclear Data**: `openmc.data` provides programmatic access to nuclear data files (ENDF, ACE, HDF5)
33+
34+
## Critical Build & Test Workflows
35+
36+
### Build Dependencies
37+
- **C++17 compiler**: GCC, Clang, or Intel
38+
- **CMake** (3.16+): Required for configuring and building the C++ library
39+
- **HDF5**: Required for cross section data and output file formats
40+
- **libpng**: Used for generating visualization when OpenMC is run in plotting mode
41+
42+
Without CMake and HDF5, OpenMC cannot be compiled.
43+
44+
### Building the C++ Library
45+
```bash
46+
# Configure with CMake (from build/ directory)
47+
cmake .. -DOPENMC_USE_MPI=ON -DOPENMC_USE_OPENMP=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
48+
49+
# Available CMake options (all default OFF except OPENMC_USE_OPENMP and OPENMC_BUILD_TESTS):
50+
# -DOPENMC_USE_OPENMP=ON/OFF # OpenMP parallelism
51+
# -DOPENMC_USE_MPI=ON/OFF # MPI support
52+
# -DOPENMC_USE_DAGMC=ON/OFF # CAD geometry support
53+
# -DOPENMC_USE_LIBMESH=ON/OFF # Unstructured mesh
54+
# -DOPENMC_ENABLE_PROFILE=ON/OFF # Profiling flags
55+
# -DOPENMC_ENABLE_COVERAGE=ON/OFF # Coverage analysis
56+
57+
# Build
58+
make -j
59+
60+
# C++ unit tests (uses Catch2)
61+
ctest
62+
```
63+
64+
### Python Development
65+
```bash
66+
# Install in development mode (requires building C++ library first)
67+
pip install -e .
68+
69+
# Python tests (uses pytest)
70+
pytest tests/unit_tests/ # Fast unit tests
71+
pytest tests/regression_tests/ # Full regression suite (requires nuclear data)
72+
```
73+
74+
### Nuclear Data Setup (CRITICAL for Running OpenMC)
75+
Most tests require the NNDC HDF5 nuclear cross-section library.
76+
77+
**Important**: Check if `OPENMC_CROSS_SECTIONS` is already set in the user's
78+
environment before downloading, as many users already have nuclear data
79+
installed. Though do note that if this variable is present that it may point to
80+
different cross section data and that the NNDC data is required for tests to
81+
pass.
82+
83+
**If not already configured, download and setup:**
84+
```bash
85+
# Download NNDC HDF5 cross section library (~800 MB compressed)
86+
wget -q -O - https://anl.box.com/shared/static/teaup95cqv8s9nn56hfn7ku8mmelr95p.xz | tar -C $HOME -xJ
87+
88+
# Set environment variable (add to ~/.bashrc or ~/.zshrc for persistence)
89+
export OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml
90+
```
91+
92+
**Alternative**: Use the provided download script (checks if data exists before downloading):
93+
```bash
94+
bash tools/ci/download-xs.sh # Downloads both NNDC HDF5 and ENDF/B-VII.1 data
95+
```
96+
97+
Without this data, regression tests will fail with "No cross_sections.xml file
98+
found" errors, or, in the case that alternative cross section data is configured
99+
the tests will execute but will not pass. The `cross_sections.xml` file is an
100+
index listing paths to individual HDF5 nuclear data files for each nuclide.
101+
102+
## Testing Expectations
103+
104+
### Environment Requirements
105+
106+
- **Data**: As described above, OpenMC's test suite requires OpenMC to be configured with NNDC data.
107+
- **OpenMP Settings**: OpenMC's tests may fail is more than two OpenMP threads are used. The environment variable `OMP_NUM_THREADS=2` should be set to avoid sporadic test failures.
108+
- **Executable configuration**: The OpenMC executable should compiled with debug symbols enabled.
109+
110+
### C++ Tests
111+
Located in `tests/cpp_unit_tests/`, use Catch2 framework. Run via `ctest` after building with `-DOPENMC_BUILD_TESTS=ON`.
112+
113+
### Python Unit Tests
114+
Located in `tests/unit_tests/`, these are fast, standalone tests that verify Python API functionality without running full simulations. Use standard pytest patterns:
115+
116+
**Categories**:
117+
- **API validation**: Test object creation, property setters/getters, XML serialization (e.g., `test_material.py`, `test_cell.py`, `test_source.py`)
118+
- **Data processing**: Test nuclear data handling, cross sections, depletion chains (e.g., `test_data_neutron.py`, `test_deplete_chain.py`)
119+
- **Library bindings**: Test `openmc.lib` ctypes interface with `model.init_lib()`/`model.finalize_lib()` (e.g., `test_lib.py`)
120+
- **Geometry operations**: Test bounding boxes, containment, lattice generation (e.g., `test_bounding_box.py`, `test_lattice.py`)
121+
122+
**Common patterns**:
123+
- Use fixtures from `tests/unit_tests/conftest.py` (e.g., `uo2`, `water`, `sphere_model`)
124+
- Test invalid inputs with `pytest.raises(ValueError)` or `pytest.raises(TypeError)`
125+
- Use `run_in_tmpdir` fixture for tests that create files
126+
- Tests with `openmc.lib` require calling `model.init_lib()` in try/finally with `model.finalize_lib()`
127+
128+
**Example**:
129+
```python
130+
def test_material_properties():
131+
m = openmc.Material()
132+
m.add_nuclide('U235', 1.0)
133+
assert 'U235' in m.nuclides
134+
135+
with pytest.raises(TypeError):
136+
m.add_nuclide('H1', '1.0') # Invalid type
137+
```
138+
139+
Unit tests should be fast. For tests requiring simulation output, use regression tests instead.
140+
141+
### Python Regression Tests
142+
Regression tests compare OpenMC output against reference data. **Prefer using existing models from `openmc.examples` or those found in tests/unit_tests/conftest.py** (like `pwr_pin_cell()`, `pwr_assembly()`, `slab_mg()`) rather than building from scratch.
143+
144+
**Test Harness Types** (in `tests/testing_harness.py`):
145+
- **PyAPITestHarness**: Standard harness for Python API tests. Compares `inputs_true.dat` (XML hash) and `results_true.dat` (statepoint k-eff and tally values). Requires `model.xml` generation.
146+
- **HashedPyAPITestHarness**: Like PyAPITestHarness but hashes the results for compact comparison
147+
- **TolerantPyAPITestHarness**: For tests with floating-point non-associativity (e.g., random ray solver with single precision). Uses relative tolerance comparisons.
148+
- **WeightWindowPyAPITestHarness**: Compares weight window bounds from `weight_windows.h5`
149+
- **CollisionTrackTestHarness**: Compares collision track data from `collision_track.h5` against `collision_track_true.h5`
150+
- **TestHarness**: Base harness for XML-based tests (no Python model building)
151+
- **PlotTestHarness**: Compares plot output files (PNG or voxel HDF5)
152+
- **CMFDTestHarness**: Specialized for CMFD acceleration tests
153+
- **ParticleRestartTestHarness**: Tests particle restart functionality
154+
155+
Almost all cases use either `PyAPITestHarness` or `HashedPyAPITestHarness`
156+
157+
**Example Test**:
158+
```python
159+
from openmc.examples import pwr_pin_cell
160+
from tests.testing_harness import PyAPITestHarness
161+
162+
def test_my_feature():
163+
model = pwr_pin_cell()
164+
model.settings.particles = 1000 # Modify to exercise feature
165+
harness = PyAPITestHarness('statepoint.10.h5', model)
166+
harness.main()
167+
```
168+
169+
**Workflow**: Create `test.py` and `__init__.py` in `tests/regression_tests/my_test/`, run `pytest --update` to generate reference files (`inputs_true.dat`, `results_true.dat`, etc.), then verify with `pytest` without `--update`. Test results should be generated with a debug build (`-DCMAKE_BUILD_TYPE=Debug`)
170+
171+
**Critical**: When modifying OpenMC code, regenerate affected test references with `pytest --update` and commit updated reference files.
172+
173+
### Test Configuration
174+
175+
`pytest.ini` sets: `python_files = test*.py`, `python_classes = NoThanks` (disables class-based test collection).
176+
177+
### Testing Options
178+
179+
For builds of OpenMC with MPI enabled, the `--mpi` flag should be passed to the test suite to ensure that appropriate tests are executed using two MPI processes.
180+
181+
The entire test suite can be executed with OpenMC running in event-based mode (instead of the default history-based mode) by providing the `--event` flag to the `pytest` command.
182+
183+
## Cross-Language Boundaries
184+
185+
The C API (defined in `include/openmc/capi.h`) exposes C++ functionality to Python via ctypes bindings in `openmc/lib/`. Example:
186+
```cpp
187+
// C++ API in capi.h
188+
extern "C" int openmc_run();
189+
190+
// Python binding in openmc/lib/core.py
191+
_dll.openmc_run.restype = c_int
192+
def run():
193+
_dll.openmc_run()
194+
```
195+
196+
When modifying C++ public APIs, update corresponding ctypes signatures in `openmc/lib/*.py`.
197+
198+
## Code Style & Conventions
199+
200+
### C++ Style (enforced by .clang-format)
201+
OpenMC generally tries to follow C++ core guidelines where possible
202+
(https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) and follow
203+
modern C++ practices (e.g. RAII) whenever possible.
204+
205+
- **Naming**:
206+
- Classes: `CamelCase` (e.g., `HexLattice`)
207+
- Functions/methods: `snake_case` (e.g., `get_indices`)
208+
- Variables: `snake_case` with trailing underscore for class members (e.g., `n_particles_`, `energy_`)
209+
- Constants: `UPPER_SNAKE_CASE` (e.g., `SQRT_PI`)
210+
- **Namespaces**: All code in `openmc::` namespace, global state in sub-namespaces
211+
- **Include order**: Related header first, then C/C++ stdlib, third-party libs, local headers
212+
- **Comments**: C++-style (`//`) only, never C-style (`/* */`)
213+
- **Standard**: C++17 features allowed
214+
- **Formatting**: Run `clang-format` (version 15) before committing; install via `tools/dev/install-commit-hooks.sh`
215+
216+
### Python Style
217+
- **PEP8** compliant
218+
- **Docstrings**: numpydoc format for all public functions/methods
219+
- **Type hints**: Use sparingly, primarily for complex signatures
220+
- **Path handling**: Use `pathlib.Path` for filesystem operations, accept `str | os.PathLike` in function arguments
221+
- **Dependencies**: Core dependencies only (numpy, scipy, h5py, pandas, matplotlib, lxml, ipython, uncertainties, setuptools, endf). Other packages must be optional
222+
- **Python version**: Minimum 3.11 (as of Nov 2025)
223+
224+
### ID Management Pattern (Python)
225+
When creating geometry objects, IDs can be auto-assigned or explicit:
226+
```python
227+
# Auto-assigned ID
228+
cell = openmc.Cell() # Gets next available ID
229+
230+
# Explicit ID
231+
cell = openmc.Cell(id=10) # Warning if ID already used
232+
233+
# Reset all IDs (useful in test fixtures)
234+
openmc.reset_auto_ids()
235+
```
236+
237+
### Input Validation Pattern (Python)
238+
All setters use checkvalue functions:
239+
```python
240+
import openmc.checkvalue as cv
241+
242+
@property
243+
def temperature(self):
244+
return self._temperature
245+
246+
@temperature.setter
247+
def temperature(self, temp):
248+
cv.check_type('temperature', temp, Real)
249+
cv.check_greater_than('temperature', temp, 0.0)
250+
self._temperature = temp
251+
```
252+
253+
### Working with HDF5 Files
254+
C++ uses custom HDF5 wrappers in `src/hdf5_interface.cpp`. Python uses h5py directly. Statepoint format version is `VERSION_STATEPOINT` in `include/openmc/constants.h`.
255+
256+
### Conditional Compilation
257+
Check for optional features:
258+
```cpp
259+
#ifdef OPENMC_MPI
260+
// MPI-specific code
261+
#endif
262+
263+
#ifdef OPENMC_DAGMC
264+
// DAGMC-specific code
265+
#endif
266+
```
267+
268+
## Documentation
269+
270+
- **User docs**: Sphinx documentation in `docs/source/` hosted at https://docs.openmc.org
271+
- **C++ docs**: Doxygen-style comments with `\brief`, `\param` tags
272+
- **Python docs**: numpydoc format docstrings
273+
274+
## Common Pitfalls
275+
276+
1. **Forgetting nuclear data**: Tests fail without `OPENMC_CROSS_SECTIONS` environment variable
277+
2. **ID conflicts**: Python objects with duplicate IDs trigger `IDWarning`, use `reset_auto_ids()` between tests
278+
3. **MPI builds**: Code must work with and without MPI; use `#ifdef OPENMC_MPI` guards
279+
4. **Path handling**: Use `pathlib.Path` in new Python code, not `os.path`
280+
5. **Clang-format version**: CI uses version 15; other versions may produce different formatting

CITATION.cff

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,43 @@
1+
cff-version: 1.2.0
2+
message: "If you use this software, please cite it as below."
3+
title: OpenMC
4+
authors:
5+
- family-names: Romano
6+
given-names: Paul K.
7+
orcid: "https://orcid.org/0000-0002-1147-045X"
8+
- family-names: Shriwise
9+
given-names: Patrick C.
10+
orcid: "https://orcid.org/0000-0002-3979-7665"
11+
- family-names: Shimwell
12+
given-names: Jonathan
13+
orcid: "https://orcid.org/0000-0001-6909-0946"
14+
- family-names: Harper
15+
given-names: Sterling
16+
- family-names: Boyd
17+
given-names: Will
18+
- family-names: Nelson
19+
given-names: Adam G.
20+
orcid: "https://orcid.org/0000-0002-3614-0676"
21+
- family-names: Tramm
22+
given-names: John R.
23+
orcid: "https://orcid.org/0000-0002-5397-4402"
24+
- family-names: Ridley
25+
given-names: Gavin
26+
orcid: "https://orcid.org/0000-0003-1635-8042"
27+
- family-names: Johnson
28+
given-names: Andrew
29+
orcid: "https://orcid.org/0000-0003-2125-8775"
30+
- family-names: Peterson
31+
given-names: Ethan E.
32+
orcid: "https://orcid.org/0000-0002-5694-7194"
33+
- family-names: Herman
34+
given-names: Bryan R.
135
preferred-citation:
236
authors:
337
- family-names: Romano
438
given-names: Paul K.
539
orcid: "https://orcid.org/0000-0002-1147-045X"
6-
- final-names: Horelik
40+
- family-names: Horelik
741
given-names: Nicholas E.
842
- family-names: Herman
943
given-names: Bryan R.

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ list(APPEND libopenmc_SOURCES
338338
src/cell.cpp
339339
src/chain.cpp
340340
src/cmfd_solver.cpp
341+
src/collision_track.cpp
341342
src/cross_sections.cpp
342343
src/dagmc.cpp
343344
src/distribution.cpp

0 commit comments

Comments
 (0)