Tallies - #1005
Draft
MicahGale wants to merge 36 commits into
Draft
Conversation
DataLexer's FILE_PATH pattern consumes `[` and `]`, preventing them from being matched as literals. TallyLexer narrows FILE_PATH to exclude those characters and adds them as literals so `[0 0 0]` tokenizes correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds grammar rules for: - Path separators: (1<2<5) - Lattice element indices: (1[0 0 0]<2) - Lattice ranges: (1<2[0:1 0:1 0:0]<5) - Comma-separated lattice sets: (1<2[0 0 0, 0 1 0]<5) - Nested sub-paths: (1<(2[0 0 0] 2[0 1 0])<5) - Universe references: (u=1<2<5), ((u=1)<2<5) tally_numbers uses fresh rules (no inherited number_sequence) so the LALR(1) conflict between lparen_phrase and the parenthetical number_sequence production is eliminated — those states are unreachable from the `tally` start symbol. All new rule names are distinct from inherited DataParser rules to avoid MetaBuilder merge side-effects. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Six bugs prevented TallyParser (and TallySegmentParser) from ever being used; all tally inputs silently fell back to DataParser: 1. _load_correct_parser stored a parser instance instead of the class, so _parse_input's self._parser() call double-instantiated it. 2. DataInput.__init__ did not propagate _prefix when full_parse() called it without a prefix argument, so _load_correct_parser was skipped. 3. parse_data did not pass prefix= to the final DataInput() call. 4. Input.tokenize() had no lexer_class parameter, so parser-specific lexers (e.g. TallyLexer) could not be selected. 5. _parse_input did not forward parser._lexer_class to tokenize(). 6. DataInput._KEYS_TO_PRESERVE did not include _prefix, so the prefix was not guaranteed to survive the JIT-to-full-parse transition. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TestTallyPathSyntax directly invokes TallyParser + TallyLexer against all 11 complex tally forms from test_tally.imcnp. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a full Tally class hierarchy (SurfaceCurrentTally, SurfaceFluxTally, CellFluxTally, DetectorTally, EnergyDepositionTally, FissionEnergyDepositionTally, EnergyDetectorPulseTally) with JIT parsing, subclass dispatch via Tally.from_input(), and correct handling of path/ lattice syntax in tally groups. Key changes: - tally.py: full rewrite with TallyGroup, FlatGroup, PathGroup, LatticeIndex helpers; lattice phrase and universe phrase parsing; link_to_problem uses problem._surfaces/_cells to avoid __relink_objs recursion - tally_parser.py: fix tally_group_body to preserve lattice_phrase and universe_phrase ListNodes intact (only flatten ShortcutNode) - tallies.py: inherit from NumberedDataObjectCollection (not NumberedObjectCollection) so insert_in_data kwarg is supported - data_parser.py: register Tally and dispatch via Tally.from_input() - mcnp_problem.py: add tallies property and load tallies during parse - cell.py: add tallies generator property (scanning pattern) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Tally.clone_as(new_type) to duplicate a tally as a different type (e.g. F4 -> F6) while keeping the same scoring cells/surfaces, restricted to same-category conversions (surface/cell/detector). Also fixes a bug in the inherited clone() where its numbering had no awareness that a tally number's last digit encodes its type. Adds a shallow scores/filters API (Score enum, scores property, Filter/ParticleFilter/SpatialFilter, filters property) as a lightweight analog of OpenMC's tally attributes, backed by data Tally already parses (tally type, particle_classifiers, groups). Also fixes SurfaceTally/CellTally.link_to_problem, which wasn't idempotent: re-linking (needed by clone/clone_as) duplicated stale deep-copied cells/surfaces into the live collection and raised NumberConflictError. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rewrites Tally.from_input to dispatch via _peek_light_parse (matching parse_surface's own idiom) instead of building a throwaway full Tally instance just to read the type digit. Adds @needs_full_cst to add_surface/add_cell/add_group/add_path_group. This was a real bug, not just style: calling one of these on a tally that had only been JIT-parsed mutated _groups starting from its blank state, and the next @needs_full_ast getter access would then silently overwrite that mutation with a fresh full parse. Adds @args_checked plus type annotations to LatticeIndex, FlatGroup, PathGroup, PathGroup.inside, ParticleFilter, SpatialFilter, and the add_group/add_path_group pairs, using this codebase's existing list[X] | set[X] idiom (see syntax_node.py's particles setter) rather than a plain list[X] that would reject the set particle_classifiers actually returns. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ve flag. The barebone TallyParser rejected `:`/`#` reaction-list operators outside of lattice-index brackets (e.g. `fm4 (1.0 26 16:103)` raised ParsingError on full_parse(), even though the grammar already accepted the identical `:` token inside `[...]` lattice ranges). Adds a flat reaction_operator alternative to tally_group_item, with no precedence/tree-building in the grammar itself -- that's left to the semantic layer, same as the rest of this file's CST-then-interpret split. Also fixes the FM `C` (cumulative) end flag: `T` (total) happens to lex as PARTICLE (the triton letter), but `C` isn't a particle letter and lexes as TEXT instead, so end_phrase silently only ever supported `T`. Verified no new SLY shift/reduce conflicts from either change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a real object model for FM tally-multiplier cards, mirroring the F
tally hierarchy built earlier this session and resolving the TODO left in
Tally.scores's docstring ("not something derived from FM tally-multiplier
cards, which aren't modeled yet").
montepy/data_inputs/tally_multiplier.py / tally_multiplier_type.py:
- ReactionExpression/Reaction: a binary expression tree for one reaction
list, modeled on montepy.surfaces.half_space.HalfSpace (left/operator/
right, &/|/~ there -> */+/- here). Python's own operator precedence
gives MCNP's "multiply binds tighter than add/subtract" rule for free.
- ReactionNumber: common reaction numbers as named Reaction instances
rather than an Enum, since Enum members can't be composed with */+/-
without unwrapping .value.
- AttenuatorLayer/AttenuatorSet (layers chain via &), MultiplierSet/
SpecialMultiplierSet, MultiplierBin, and the flattened MultiplierScore
leaf -- one MultiplierScore per actual FM output bin.
- TallyMultiplier(DataInputAbstract, Numbered_MCNP_Object): the FMn card,
linked to its parent Tally by number, the same companion-card pattern
ThermalScatteringLaw uses for MTn/Mn (montepy/tallies.py's
Tallies.append()/finalize_init(), mirroring Materials._tsl_queue).
Tally changes:
- New `multiplier` property; `scores` now returns the linked multiplier's
per-bin MultiplierScore list instead of the default Score list once one
is attached.
- `clone()`/`clone_as()` now explicitly drop `_multiplier` on the copy --
a multiplier is tied to this exact tally number, not something that
should transfer to a renumbered/retyped clone.
- Fixed a real, previously-latent bug found while wiring the FM<->Tally
link: Tally never populated `_old_number` during JIT parsing (only
ThermalScatteringLaw did this, via its own _jit_light_init override),
so anything keying off `_old_number` during the JIT window -- as the
new Tallies.append() linking does -- silently saw the blank sentinel.
Added the matching _jit_light_init override.
tests/inputs/test_tally.imcnp: added companion F-tally cards for FM
fixtures that had none, and renumbered a few reaction-precedence fixtures
whose numbers collided with invalid or wrong-family TallyType digits
(109/110 aren't valid types at all; 105/111 landed on detector/current
instead of cell-flux).
tests/test_tally_multiplier.py: grammar round-trip, operator-overload and
precedence checks against hand-built expressions, attenuator chaining,
companion-card linking (including the orphaned-FM error path), and
scores integration -- including a regression test that calls `.scores`
as the very first touch on a freshly-read (still-JIT) tally, which is
what would have caught the _old_number bug above.
Full suite: 1543 passed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Pull Request Checklist for MontePy
Description
Please provide a summary of the change, referencing the issue it fixes, if applicable. Include relevant context and motivation.
Fixes #11
General Checklist
blackversion 25 or 26.LLM Disclosure
Are you?
Were any large language models (LLM or "AI") used in to generate any of this code?
Documentation Checklist
.. versionchanged::or.. versionadded::directives.Infrastructure Changes
Significant features or Behavior changes
First-Time Contributor Checklist
pyproject.tomlif you wish to do so.Additional Notes for Reviewers
Ensure that:
📚 Documentation preview 📚: https://montepy--1005.org.readthedocs.build/en/1005/