diff --git a/src/underworld3/discretisation/discretisation_mesh.py b/src/underworld3/discretisation/discretisation_mesh.py index ce006b59..e37848d4 100644 --- a/src/underworld3/discretisation/discretisation_mesh.py +++ b/src/underworld3/discretisation/discretisation_mesh.py @@ -3456,6 +3456,15 @@ def _do_move(): result = remesh_with_field_transfer( self, _do_move, dt=dt, extra_zero=zero, verbose=verbose) + # Notify registered swarms: solve-entry sync compares this version + # and marks them for deferred migration (#379 item 1 retired the + # read-trigger that consumed this channel). The bump lives HERE, + # not in _deform_mesh: the internal primitive also runs on + # snapshot restore, whose integrity check treats a moved version + # as invalidation and would refuse its own recovery. + if result: + self._mesh_version += 1 + # Refresh deformation-tracking per-boundary normals so Nitsche/penalty # BCs that captured ``boundary_normal(...).sym`` at setup read the new # geometry (the JIT reads the variable's .data, which would otherwise @@ -3560,13 +3569,6 @@ def _deform_mesh(self, new_coords: numpy.ndarray, verbose=False, if solver is not None and hasattr(solver, "is_setup"): solver.is_setup = False - # Notify registered swarms: solve-entry sync compares this - # version and marks them for deferred migration (#379 item 1 - # retired the read-trigger that used to consume this channel). - # The mesh.X.coords callback path bumps again after this - # returns — harmless, the consumer checks inequality. - self._mesh_version += 1 - # Invalidate caches whose contents become stale when mesh # coordinates change. Matches the cache hygiene already # performed by mesh.adapt() and _legacy_access. Without