Add domain decomposition for random ray solver#4026
Open
Suark94 wants to merge 51 commits into
Open
Conversation
added 30 commits
September 18, 2025 17:25
added 19 commits
December 15, 2025 10:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR adds a domain decomposition capability to the random ray solver, allowing users to run random ray calculations in parallel across multiple MPI ranks. This lets random ray problems that are too large to fit in the memory of a single computational node be spread across multiple nodes and enables greater scalability on HPC clusters.
This feature is enabled automatically when the random ray solver is run with more than one MPI rank. No additional input settings are required. The geometry is decomposed with a capacity-constrained Voronoi tessellation, where each Voronoi region corresponds to one MPI rank's subdomain. A source region is assigned to a Voronoi region/ MPI rank based on the squared distance between the source region centroid and the Voronoi region centroid, adjusted with an additive weight. Using the weighted squared distance rather than the simple Euclidean distance yields compact, centroidal subdomains and prevents elongated or scattered subdomains. During the first 5 iterations, the weights are adjusted according to the measured rank load to balance the work across subdomains.
Both CSG and CAD geometries are supported. CAD models require MOAB version 5.2.0 or later.
The full method documentation is included in this PR under
docs/source/methods/random_ray.rst(see the new "Domain Decomposition" section).Fixes #3009
Verification
The implemented domain decomposition scheme preserves the original source region mesh and ray sampling routines regardless of the number of parallel MPI processes. Simulation results are therefore fully reproducible.
For verification, the random ray solver with and without domain decomposition was tested on the 2D C5G7 benchmark problem. This is a multi-group benchmark problem with 7 energy groups, which describes four simplified 2D reactor assemblies surrounded by a reflector region.
For the verification, a simulation mesh with 142,964 flat source regions was used. The simulation was run twice with the same random number seed: once with the original version of OpenMC with a single MPI rank and 128 OpenMP threads (no domain decomposition), and once with the implemented domain decomposition scheme on 128 MPI ranks with 1 thread per rank. Both runs produced an identical eigenvalue of 1.18626 ± 0.00038. Pin powers were also compared against the reference multi-group Monte Carlo benchmark solution, with average absolute pin power errors of 0.5534%, and a maximum pin power error of 2.0456% in both cases.
Performance
The performance of the domain decomposition scheme was tested with a strong scaling study on the UKAEA “Simple Tokamak” benchmark, a large fixed source fusion neutronics simulation problem.
This problem is a nearly “worst case” challenge problem for domain decomposition as it features extreme spatial mesh resolution differences, with fine detail and small cells in areas like the divertor, and coarse mesh resolution in void areas of the problem, giving 1,626,536 source regions in total. Furthermore, the high complexity of the wall of the fusion device results in some cells being bounded by hundreds of CSG surfaces (resulting in extremely high ray tracing costs), while other areas (like the shield wall) are constrained with just a few planar surfaces. All results were obtained from simulations on the Improv cluster at Argonne National Laboratory. It was found that OpenMC performed best on the Improv architecture when 8 MPI ranks (each with 16 OpenMP threads) were used on each node.
Simulations were scaled from one node out to 40 nodes (5120 cores) while the mesh size was kept fixed. The simulations were run with 4 million rays per batch.
The domain decomposition feature enables a continuous reduction in runtime all the way out to 40 nodes. As the problem is scaled to higher node counts, an increasing deviation from ideal scaling behavior can be observed due to the progressive loss of parallel efficiency. At the maximum of 40 nodes, only 38 % parallel efficiency was achieved compared to single node operation. At this scale, the cost of the domain decomposition operations begin to dominate the runtime of the code.
Summary of changes
New classes / files
DecompositionMap(decomposition_map): Contains thesubdomain_map_, which maps source regions to MPI ranks. Provides methods for initializing the Voronoi volumes, estimating and balancing load, exchanging source regions and determining the owner rank of newly discovered source regions.RayBank(ray_bank): Contains the list of rays to be sent to their new owner ranks and the methods for exchanging ray data between MPI ranks.Random ray transport (
random_ray)RayBufferContainer, which holds the scalar members and vector fields of a ray while it is stored in the buffer, andRayExchangeData, which collects the scalar members for communication between MPI ranks.RayBufferContainer.restart_ray()reinitializes a ray that has been received by its new owner rank. Additional methods check whether a ray has left its subdomain and pack it into the buffer.Random ray simulation (
random_ray_simulation)transport_sweep_decomp()that buffers rays as they leave a subdomainSource regions (
source_region)ScalarSourceRegionFields, which holds all scalar fields of a source region.SourceRegion::merge(), which merges two source regions that were discovered and contested by separate ranks in the same transport sweep.Flat source domain (
flat_source_domain)is_geometry_3D()to probe the geometry typeoutput_to_vtk_decomp()to compose the VTK output data from the separate MPI processes.Supporting changes
parallel_map: addedsize()anderase().operator[]now raises an error when the requested key is not present to help with debugging.cell:Cellcan now return its number of surfaces.constants: addedMAX_N_HANDLES(max DAGMC entity handles sent when exchanging rays, set to 5) andITER_LOAD_BALANCE(max batches over which load balancing is performed, set to 5).source:satisfies_spatial_constraintsmoved fromprotectedtopublicso it can be used to confine Voronoi regions to the real geometry at the start of a simulation.Testing
No new regression tests were added, as the existing test suite already covers this feature. Domain decomposition activates automatically whenever the random ray solver runs on more than one MPI rank, so every existing
random_ray_*regression test doubles as a domain decomposition test when the test suite is run with the--mpiflag. Since the reference results for these tests are generated from serial runs, the MPI runs directly verify that the decomposed solver reproduces the single-rank solution for the eigenvalue, fixed source, linear source, adjoint and mesh-tally variants.Checklist