No reachable path leaves a stale latch (Grok review): initialize and _recompile recompute it, and post-init removal of a translating circle cannot commit. simulation.py is back to b448bc3f; the latch-only test is dropped. The recompile, close-retry and tightened after-close tests stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
71c12aedce
commit
e1ed27b438
2 files changed
+4
-23
No files matched your search
@@ -148,6 +148,7 @@ class Simulation:
|
|||||||
from .body.motion import MovingCircle
|
from .body.motion import MovingCircle
|
||||||
obj.motion = MovingCircle((cx, cy), radius, translation,
|
obj.motion = MovingCircle((cx, cy), radius, translation,
|
||||||
on_failure=self._fail_moving)
|
on_failure=self._fail_moving)
|
||||||
|
self.stepper.blocked = MOVING_BLOCKED
|
||||||
elif type_lower == "sensor":
|
elif type_lower == "sensor":
|
||||||
from .body.geometry.circle import CircleGeometry
|
from .body.geometry.circle import CircleGeometry
|
||||||
cx, cy = float(center[0]), float(center[1])
|
cx, cy = float(center[0]), float(center[1])
|
||||||
@@ -171,10 +172,7 @@ class Simulation:
|
|||||||
if self._initialized:
|
if self._initialized:
|
||||||
self.bodies.stage_add(obj)
|
self.bodies.stage_add(obj)
|
||||||
return -1
|
return -1
|
||||||
body_id = self.bodies.add(obj)
|
return self.bodies.add(obj)
|
||||||
if translation is not None:
|
|
||||||
self._refresh_stepper_block()
|
|
||||||
return body_id
|
|
||||||
|
|
||||||
def add_jet(self, jet) -> int:
|
def add_jet(self, jet) -> int:
|
||||||
"""Register a body-independent Jet before ``initialize()``; returns its index.
|
"""Register a body-independent Jet before ``initialize()``; returns its index.
|
||||||
@@ -214,10 +212,6 @@ class Simulation:
|
|||||||
# Device geometry is unknown after a failed moving step: same lifecycle as Jets.
|
# Device geometry is unknown after a failed moving step: same lifecycle as Jets.
|
||||||
self._failed = f"moving circle step failed: {exc!r}"
|
self._failed = f"moving circle step failed: {exc!r}"
|
||||||
|
|
||||||
def _refresh_stepper_block(self) -> None:
|
|
||||||
# Derived latch: direct stepper calls must not step after static-link exclusion.
|
|
||||||
self.stepper.blocked = MOVING_BLOCKED if self._moving_bodies() else None
|
|
||||||
|
|
||||||
def _moving_bodies(self):
|
def _moving_bodies(self):
|
||||||
return [obj for obj in self.bodies.objects if obj.motion is not None]
|
return [obj for obj in self.bodies.objects if obj.motion is not None]
|
||||||
|
|
||||||
@@ -274,10 +268,7 @@ class Simulation:
|
|||||||
if self._initialized:
|
if self._initialized:
|
||||||
self.bodies.stage_remove(id)
|
self.bodies.stage_remove(id)
|
||||||
else:
|
else:
|
||||||
moving = self.bodies.get(id).motion is not None
|
|
||||||
self.bodies.remove(id)
|
self.bodies.remove(id)
|
||||||
if moving:
|
|
||||||
self._refresh_stepper_block()
|
|
||||||
|
|
||||||
# -- Legacy convenience (keep for backward compat) -----------------------
|
# -- Legacy convenience (keep for backward compat) -----------------------
|
||||||
def add_cylinder(self, center: Tuple[float, ...],
|
def add_cylinder(self, center: Tuple[float, ...],
|
||||||
@@ -525,7 +516,7 @@ class Simulation:
|
|||||||
self.field, self._module, self.lbm_cfg,
|
self.field, self._module, self.lbm_cfg,
|
||||||
)
|
)
|
||||||
self.stepper._step_count = _prev_step_count
|
self.stepper._step_count = _prev_step_count
|
||||||
self._refresh_stepper_block()
|
self.stepper.blocked = MOVING_BLOCKED if self._moving_bodies() else None
|
||||||
|
|
||||||
self._assert_object_count_contract(expected_count=expected_n_objects)
|
self._assert_object_count_contract(expected_count=expected_n_objects)
|
||||||
|
|
||||||
@@ -552,7 +543,7 @@ class Simulation:
|
|||||||
# change. Compact-list construction publishes no outputs on failure.
|
# change. Compact-list construction publishes no outputs on failure.
|
||||||
next_flags = self.bodies.build_flags(self.field.build_channel_flags())
|
next_flags = self.bodies.build_flags(self.field.build_channel_flags())
|
||||||
self._validate_moving_bodies()
|
self._validate_moving_bodies()
|
||||||
self._refresh_stepper_block()
|
self.stepper.blocked = MOVING_BLOCKED if self._moving_bodies() else None
|
||||||
if self.bodies.jets and self.bodies.count == 0:
|
if self.bodies.jets and self.bodies.count == 0:
|
||||||
raise ValueError("Jets need bodies with cut links")
|
raise ValueError("Jets need bodies with cut links")
|
||||||
self.bodies.build_compact_lists_for(self.bodies.objects, next_flags)
|
self.bodies.build_compact_lists_for(self.bodies.objects, next_flags)
|
||||||
|
|||||||
@@ -258,16 +258,6 @@ def test_recompile_installs_a_guarded_stepper(monkeypatch):
|
|||||||
assert sim.stepper.step_count == 7
|
assert sim.stepper.step_count == 7
|
||||||
|
|
||||||
|
|
||||||
def test_stepper_latch_follows_moving_bodies(monkeypatch):
|
|
||||||
sim = routed_simulation(monkeypatch)
|
|
||||||
still = sim.add_body("circle", (100., 40.), 5.)
|
|
||||||
assert sim.stepper.blocked is None
|
|
||||||
moving = sim.add_body("circle", (50., 40.), 10., translation=Translation((0., 0., -1., 1.), .1))
|
|
||||||
assert sim.stepper.blocked is not None
|
|
||||||
sim.remove_body(moving) # removing the last translating circle clears the latch
|
|
||||||
assert sim.stepper.blocked is None and sim.bodies.get(still).motion is None
|
|
||||||
|
|
||||||
|
|
||||||
def validate(monkeypatch, objects, flags=None, **cfg):
|
def validate(monkeypatch, objects, flags=None, **cfg):
|
||||||
sim = routed_simulation(monkeypatch)
|
sim = routed_simulation(monkeypatch)
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
|
|||||||
Reference in new issue
Block a user