Skip to content

WIP: Refactor and extend IndexSplit to work with non-cell centered index spaces - #1388

Open
lroberts36 wants to merge 11 commits into
developfrom
lrobert36/update-index-split-manual
Open

WIP: Refactor and extend IndexSplit to work with non-cell centered index spaces#1388
lroberts36 wants to merge 11 commits into
developfrom
lrobert36/update-index-split-manual

Conversation

@lroberts36

@lroberts36 lroberts36 commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator

PR Summary

TODO:

  • Decide on removing RawMemoryIndexer interface
  • Remove gold files once convinced we aren't changing behavior

PR Checklist

  • Code passes cpplint
  • New features are documented.
  • Adds a test for any bugs fixed. Adds tests for new features.
  • Code is formatted
  • Changes are summarized in CHANGELOG.md
  • Change is breaking (API, behavior, ...)
    • Change is additionally added to CHANGELOG.md in the breaking section
    • PR is marked as breaking
    • Short summary API changes at the top of the PR (plus optionally with an automated update/fix script)
  • CI has been triggered on Darwin for performance regression tests.
  • Docs build
  • Any contribution that was created or modified with the assistance of generative AI must have a comment disclosing this such as // This file was made in part with generative AI.
  • (@lanl.gov employees) Update copyright on changed files

lroberts36 and others added 6 commits April 13, 2026 18:34
This test suite captures the current IndexSplit behavior across
multiple configurations (ndim, block sizes, ghost zones, chunking
parameters). It will serve as regression tests during the refactoring
to add topology awareness.

Test coverage includes:
- 1D, 2D, and 3D configurations
- Multiple block sizes (4, 6, 16)
- Asymmetric blocks (4x8x16)
- Ghost zone counts (0, 2)
- Various nkp/njp combinations (all_outer, no_outer, 0, specific values)
- Both IndexDomain and explicit IndexRange constructors

All public methods are tested:
- outer_size(), GetBoundsK/J/I(), GetInnerBounds()
- get_i(), get_deltaj()
- get_max_ni/nj/nk/nij()
- is_i_ghost(), is_j_ghost(), is_k_ghost(), is_ghost()

Invariant checks verify:
- Complete (k,j) domain coverage with no gaps or overlaps
- Total work across chunks equals domain volume
- Both constructors produce identical results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enhance test_index_split.cpp with:

1. Coverage tests using proper loop structure:
   - Triple-nested loop: outer (team) → k (serial) → inner (fused j-i)
   - Track every logical (k,j,i) point visited
   - Verify each interior point visited exactly once
   - Account for ghost cells in fused j-i loop for memory contiguity
   - Verify: total_iterations = interior_iterations + ghost_iterations

2. Gold file regression tests:
   - Record exact IndexSplit structure for representative configurations
   - Captures outer_size, bounds, and inner loop sizes
   - Generated with GENERATE_GOLD=1 environment variable
   - Locks down current behavior before refactoring

3. Expanded test matrix:
   - Focus on nghost>0 cases (where j-fusion matters)
   - Cover various nkp/njp combinations
   - Test j-fusion patterns (full, partial, none)
   - Asymmetric block sizes

This completes Phase 1a (comprehensive testing) and Phase 1b (baseline)
of the IndexSplit refactor plan.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename fields for clarity
- Switch to indexers where possible
- add Indexer::Extent and Indexer::IdxInRange
- remove unused members
- integrate topological element support
- start on compatibility with raw memory indexer

All IndexSplit tests still passing
- Add middle loop abstraction
- Add RawMemoryIndexer interface support
@lroberts36
lroberts36 requested a review from swjones April 15, 2026 20:31

@Yurlungur Yurlungur left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't read super carefully but looks good enough for government work. Thanks for filling this in!

Comment thread src/utils/index_split.hpp
Comment on lines +45 to +48
static IndexSplit RawMemIJ(IndexDomain domain, int halo, MeshData<Real> *md,
TE logical_te, TE memory_te = TE::CC);
static IndexSplit RawMemIJ(IndexDomain domain, MeshData<Real> *md, TE logical_te,
TE memory_te = TE::CC) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the distinction between logical and memory topological element.

Comment thread src/utils/index_split.cpp
Comment on lines +48 to +49
ib.s -= halo;
ib.e += halo;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice feature

Comment thread src/utils/index_split.cpp
auto mjb = md->GetBoundsJ(IndexDomain::entire, te_mem);
auto mkb = md->GetBoundsK(IndexDomain::entire, te_mem);

memory_ = Indexer3D(mkb, mjb, mib);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol nice reuse

Comment thread src/utils/index_split.cpp
Comment on lines -115 to -125
target_k_ = (1.0 * total_k) / nkp_ + 1.e-6;
target_j_ = (1.0 * total_j) / njp_ + 1.e-6;

// save the "entire" ranges
// don't bother save ".s" since it's always zero
auto ib = md->GetBoundsI(IndexDomain::entire);
auto jb = md->GetBoundsJ(IndexDomain::entire);
auto kb = md->GetBoundsK(IndexDomain::entire);
kbe_entire_ = kb.e;
jbe_entire_ = jb.e;
ibe_entire_ = ib.e;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this not needed anymore?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, everything should be available from the two 3D indexers (e.g. kbe_entire_ == memory_.Extent<KDIM>() and a lot of the logic for moving between the index spaces is already taken care of in the Indexer class. I don't exactly like how calling those sorts of functions all over the place looks, but it does mean there is one source of truth and everything is consistent. I switched to that model mostly because that was how I wrote the RawMemoryIndexer and it made it basically a one line change to switch between topological types. It also makes it pretty easy to move to spans in logical space that aren't multiples of ni (although I doubt that is too important to have).

I switched to purely integer based arithmetic for splitting up the tiled space (hence the removal of target_k_ and target_j_). It should give exactly the same results as the floating point based choices.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants