Skip to content

Tallies - #1005

Draft
MicahGale wants to merge 36 commits into
beta_rel_devfrom
tallies
Draft

Tallies#1005
MicahGale wants to merge 36 commits into
beta_rel_devfrom
tallies

Conversation

@MicahGale

@MicahGale MicahGale commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

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

  • I have performed a self-review of my own code.
  • The code follows the standards outlined in the development documentation.
  • I have formatted my code with black version 25 or 26.
  • I have added tests that prove my fix is effective or that my feature works (if applicable).

LLM Disclosure

  1. Are you?

    • A human user
    • A large language model (LLM), including ones acting on behalf of a human
  2. Were any large language models (LLM or "AI") used in to generate any of this code?

  • Yes
    • Model(s) used:
  • No

Documentation Checklist

  • I have documented all added classes and methods.
  • I have added type hints to all functions as needed.
  • I have marked all changes with the .. versionchanged:: or .. versionadded:: directives.

Infrastructure Changes

  • For infrastructure updates, I have updated the developer's guide.

Significant features or Behavior changes

  • For significant new features, I have added a section to the getting started guide.

First-Time Contributor Checklist

  • If this is your first contribution, add yourself to pyproject.toml if you wish to do so.

Additional Notes for Reviewers

Ensure that:

  • This PR fully addresses and resolves the referenced issue(s).
  • The submitted code is consistent with the merge checklist outlined here.
  • The PR covers all relevant aspects according to the development guidelines.
  • 100% coverage of the patch is achieved, or justification for a variance is given.

📚 Documentation preview 📚: https://montepy--1005.org.readthedocs.build/en/1005/

MicahGale and others added 30 commits January 13, 2024 22:08
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>
MicahGale and others added 5 commits July 30, 2026 21:06
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>
@MicahGale MicahGale added feature request An issue that improves the user interface. good first prompt 🤖 A good task for AI assistant automation labels Aug 5, 2026
@MicahGale
MicahGale changed the base branch from beta-test to beta_rel_dev August 5, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request An issue that improves the user interface. good first prompt 🤖 A good task for AI assistant automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant