Conversation
Regions were stored as infix token streams including parenthesis and operator tokens. Evaluating a complex region scanned the tokens while tracking parenthesis depth, precedence was enforced by inserting parentheses, and bounding boxes required converting the expression to postfix on every call. Region specifications are now parsed with a recursive descent parser into an expression tree of intersections and unions with half-spaces as leaves. Nested operators of the same type are merged, so the depth of the tree is the number of alternations between intersection and union. The tree is stored in pre-order with the index of the end of each subtree and of the parent of each node, so contains_complex evaluates it in a single loop without recursion, skipping the rest of a subtree as soon as its value is known. The half-spaces of a region are also stored as a contiguous list, which is all a simple region needs and is used for distance calculations. Complements are removed while parsing by applying De Morgan's laws to the tree. Previously complement operators were removed by flipping the operators in the token stream before precedence was enforced, so the complement of an expression mixing intersection and union without inner parentheses, such as ~(1 2 | 3), was interpreted as -1 | (-2 -3) instead of (-1 | -2) -3. Expressions written by the Python API are fully parenthesized and were not affected. A test comparing cell lookup against the Python region parser for random expressions is added. Region strings written to the summary file are generated from the tree. They are equivalent to the previous strings, but redundant parentheses are no longer kept. n_surfaces now returns the number of half-spaces rather than the number of tokens including operators. Results are identical for the tested models. Transport time is unchanged for lattice and simple geometries, and reduced by 16% for a water tank containing 400 rods, where the water region is the tank minus the rods. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RN7JroEkrbkLKVHbMDap9
CSGCell::find_left_parenthesis searched token streams and had no callers, the cell ID argument of Region::bounding_box was only used for error messages when converting the expression to postfix, and the <set> and <sstream> includes are no longer used in cell.cpp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RN7JroEkrbkLKVHbMDap9
Region::str() is now generated from the expression tree, in which nested operators of the same type are merged and redundant parentheses are not kept, so the expected string for the issue openmc-dev#3685 case changes from " ( ( -1 2 ( -3 4 ) ) | ( -5 6 ) )" to the equivalent " ( -1 2 -3 4 ) | ( -5 6 )". Add cases checking that complements of mixed expressions are applied after grouping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RN7JroEkrbkLKVHbMDap9
A simple region needs only its half-spaces, so the expression tree of a complex region is moved behind a pointer. This keeps Region, and the cells holding it, small for the common case of simple cells. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RN7JroEkrbkLKVHbMDap9
This branch has not been deployed
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
Cell regions were stored as infix token streams, including parenthesis and operator tokens. Evaluating a complex region scanned the tokens while tracking parenthesis depth. Operator precedence was enforced by inserting parentheses into the token stream, and computing a bounding box converted the expression to postfix on every call.
This PR parses region specifications with a recursive descent parser (intersection binds tighter than union; complement applies to the following half-space or parenthesized group) into an expression tree of intersections and unions with half-spaces as leaves:
contains_complexevaluates it in one loop without recursion, skipping the rest of a subtree as soon as its value is known.Region, and the cells holding it, stay small in the common case of simple cells.str()andbounding_box()work directly on the tree.enforce_precedence,add_parentheses,remove_complement_ops,apply_demorgan,generate_postfix, the two bounding box helpers, the unusedCSGCell::find_left_parenthesis, and the no longer neededcell_idargument ofRegion::bounding_boxare removed (about −190 lines incell.cpp/cell.h).Bug fix: complements of unparenthesized expressions
Complements were previously removed by flipping the operators in the token stream before precedence was enforced. The complement of an expression mixing intersection and union without inner parentheses was therefore wrong. For example,
~(1 2 | 3)was interpreted as-1 | (-2 -3)instead of(-1 | -2) -3, which produces overlapping cells (reproduced withopenmc -g). Complements are now applied to the tree with De Morgan's laws after grouping. Expressions written by the Python API are fully parenthesized and were not affected; hand-written XML was.A new test,
tests/unit_tests/test_region_parsing.py, builds a cell from a random expression with minimal parentheses and complements, and its complement as a second cell. It then checksopenmc.lib.find_cellagainst Python's independentRegion.from_expressionat random points. Ondevelop, 7 of the 20 cases fail; with this PR all pass.Other behavior changes
summary.h5are generated from the tree. They are equivalent to the previous strings but no longer keep redundant parentheses (simple regions print exactly as before).openmc.Summaryreads them back unchanged.Region::n_surfaces()now returns the number of half-spaces, where it previously counted operator and parenthesis tokens too. It is used as a ray-tracing cost estimate for random ray domain-decomposition load balancing, where the half-space count is the better proxy. Random ray maintainers may want to confirm.Performance
Single thread, transport time, median of 3 runs in shuffled order,
develop/ this PR. Results (k-eff and all tallies) are bit-for-bit identical in every case. Run-to-run spread is about ±2.5–4%.The full unit and regression test suite gives the same results as
develop.Checklist
I have made corresponding changes to the documentation (if applicable)