Three levels: nested body-free child patch on a single chain
FixedPatchStepper(..., child=(x0,y0,x1,y1), child_block=(by,bx)) adds an L2 patch in L1 window cells (requires fine_block/base_block, one L1 patch, no bodies/jets). nest_patch() builds the L1->L2 FixedPatch2D (2*nu on L1) and the composed L1 kind (inherited INNER/OUTER kept, child-covered ACTIVE made OUTER), rejecting from the actual tables: coverage outside ACTIVE, donors or receivers not uncovered ACTIVE, surviving ACTIVE pulls of covered/OUTER cells without a child-supplied arrival, and overlap with L1's restriction footprint. Step order per L1 hop: explode L1(src)->L2, two L2 hops (halo, step), L1 halo, receiver-local L2->L1 staging into src, L1 step. The second hop thus feeds L2 from the new L1 G; L2 is never refilled from L0; L0 stays once per step (1:2:4). Existing kernels only; a small _Pair holds the child transfer bindings (explode from the child module, parent window stride). Two-level API unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6301887093
commit
76555de4b8
4 files changed
+264
-21
No files matched your search
@@ -233,5 +233,32 @@ class FixedPatchSetTests(unittest.TestCase):
|
||||
self.build(self.FACE).fine_layout(block)
|
||||
|
||||
|
||||
class NestPatchTests(unittest.TestCase):
|
||||
"""Three-level single chain: L2 bounds in L1 window cells (probe fixture)."""
|
||||
def setUp(self):
|
||||
self.cfg = config()
|
||||
self.l1 = FixedPatch2D.from_config(self.cfg, (4, 4, 12, 12)) # 24x24 window
|
||||
|
||||
def test_probe_fixture_composes_kinds(self):
|
||||
child, kind = refinement.nest_patch(self.cfg, self.l1, (8, 8, 16, 16))
|
||||
self.assertEqual(child.fine_shape, (24, 24))
|
||||
self.assertAlmostEqual(child.tau_coarse, self.l1.tau_fine)
|
||||
base = self.l1.fine_kind
|
||||
for role in (INNER_GHOST, OUTER_GHOST):
|
||||
np.testing.assert_array_equal(kind[base == role], role)
|
||||
self.assertTrue((kind[child.covered] == OUTER_GHOST).all())
|
||||
self.assertEqual(int((kind == ACTIVE).sum()), 192)
|
||||
self.assertEqual(int((kind == INNER_GHOST).sum()), 144)
|
||||
self.assertEqual(int(child.covered.sum()), 64)
|
||||
|
||||
def test_invalid_nesting_rejected(self):
|
||||
for bounds in ((2, 8, 16, 16), # covers inherited INNER
|
||||
(4, 8, 16, 16), # explosion donors in INNER
|
||||
(8, 8, 20, 16), # donors reach OUTER/INNER at the far side
|
||||
(5, 8, 16, 16)): # one-cell outward: restriction footprint/donors
|
||||
with self.subTest(bounds=bounds), self.assertRaises(ValueError):
|
||||
refinement.nest_patch(self.cfg, self.l1, bounds)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in new issue
Block a user