Skip to content

Stop searching complex cells for a boundary beyond the collision site - #4162

Open
GuySten wants to merge 2 commits into
openmc-dev:developfrom
GuySten:claude/collision-distance-cutoff
Open

GuySten wants to merge 2 commits into
openmc-dev:developfrom
GuySten:claude/collision-distance-cutoff

Conversation

@GuySten

@GuySten GuySten commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Description

Since #3934, the distance to the boundary of a complex cell is found by moving from one surface crossing to the next until a crossing changes whether the ray is in the cell. Each step recomputes the distance to every surface of the cell and evaluates its region expression. Cells written as unions of many pieces have many such virtual crossings: for example, CAD-to-CSG conversions that split non-convex solids into convex pieces. On those cells the search is expensive, and it was the source of the 10–30% slowdowns reported for the JET and ITER models.

Most of that search is wasted. In an optically thick material, a particle usually collides long before reaching the boundary, and a boundary beyond the collision site is never used.

This PR samples the distance to collision before the distance to the boundary and passes it to the boundary search as a maximum distance. The search through a complex cell stops as soon as it passes the collision site. It returns INFTY, which the caller already handles as "collision first". Simple cells, lattices and DAGMC cells are unaffected.

The boundary search uses no random numbers, so sampling the collision distance first doesn't change the random number sequence. A boundary at or beyond the collision site was never selected before either (collision_distance > boundary.distance is false in both cases), so results are bitwise identical.

Particles that collide in place, such as electrons and positrons deposited locally with TTB, now skip the boundary search entirely, since its result was never used. This is for consistency; it has no measurable effect on run time.

Changes:

  • Cell::distance, Region::distance and distance_to_boundary take an optional max_distance (default INFTY). Other callers (plotting, ray tracing, volume calculations, mesh material volumes) are unchanged.
  • Particle::event_advance samples the collision distance first and passes it as max_distance.
  • New C++ unit test sections check that a boundary within the maximum distance is still found, and that the search stops when the maximum distance falls before or after the virtual crossings.

Performance

Single thread, transport time, mean of 3 runs (2 for the scan). Tallies are bitwise identical to develop in every case.

Shield written as a union of convex blocks. A 2 m concrete cube around a 40 cm void room with a Watt fission source at its center. The concrete is one cell written as the union of the blocks of a grid, as a CAD-to-CSG converter would emit it. The physical geometry is the same for every decomposition, and the shield flux is identical across all of them.

Blocks in union develop this PR speedup
26 0.89 s 0.40 s 2.2×
56 1.95 s 0.73 s 2.7×
124 4.52 s 1.24 s 3.6×
208 8.05 s 2.03 s 4.0×
504 22.98 s 4.32 s 5.3×
992 49.13 s 8.08 s 6.1×

Other models.

Model develop this PR speedup
Shield (124 blocks), neutron source 22.36 s 6.52 s 3.43×
Shield (124 blocks), Co-60 photon source 2.42 s 0.92 s 2.63×
Shield (124 blocks), coupled neutron–photon 28.06 s 8.41 s 3.34×
Water tank with 400 finite rods (water = tank minus rods) 7.54 s 6.22 s 1.21×
Nested box shells (cask-like) 22.76 s 21.39 s 1.06×
PWR assembly (simple cells only) 16.90 s 16.56 s 1.02×
D2O with S(a,b) (simple cells only) 15.97 s 15.89 s 1.01×
PWR assembly, photon source 3.64 s 3.65 s 1.00×

It would be great if someone with access to the JET or ITER E-lite models from #3934 could check how much of that slowdown this recovers.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

claude added 2 commits October 3, 2026 01:00
The distance to collision is now sampled before the distance to the
nearest boundary and passed to the boundary search as a maximum
distance. The search through a complex cell, which moves from one
surface crossing to the next until one changes whether the ray is in
the cell, stops once it passes the collision site, since a farther
boundary is not used. The boundary search uses no random numbers, so
results are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RN7JroEkrbkLKVHbMDap9
Electrons and positrons whose energy is deposited locally have a
distance to collision of zero, so the distance to the nearest boundary
is never used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RN7JroEkrbkLKVHbMDap9
@GuySten
GuySten marked this pull request as ready for review October 3, 2026 01:46
@GuySten
GuySten requested a review from pshriwise as a code owner October 3, 2026 01:46

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants