From 0e2f038fe6b7196833c74ccb43fa453bc9afa915 Mon Sep 17 00:00:00 2001 From: Milan Rother Date: Thu, 19 Feb 2026 15:42:22 +0100 Subject: [PATCH 1/2] Zero target inputs on remove_connection to avoid stale values --- src/pathsim/simulation.py | 5 +++++ src/pathsim/subsystem.py | 5 +++++ tests/pathsim/test_simulation.py | 15 +++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/pathsim/simulation.py b/src/pathsim/simulation.py index f2814cc8..7f9307db 100644 --- a/src/pathsim/simulation.py +++ b/src/pathsim/simulation.py @@ -446,6 +446,11 @@ def remove_connection(self, connection): self.logger.error(_msg) raise ValueError(_msg) + #zero out target input ports to avoid stale values + for target in connection.targets: + for port in target.ports: + target.block.inputs[port] = 0.0 + #remove from global connection list self.connections.discard(connection) diff --git a/src/pathsim/subsystem.py b/src/pathsim/subsystem.py index 3f0cabc4..a46415ff 100644 --- a/src/pathsim/subsystem.py +++ b/src/pathsim/subsystem.py @@ -337,6 +337,11 @@ def remove_connection(self, connection): if connection not in self.connections: raise ValueError(f"{connection} not part of subsystem") + #zero out target input ports to avoid stale values + for target in connection.targets: + for port in target.ports: + target.block.inputs[port] = 0.0 + self.connections.discard(connection) if self.graph: diff --git a/tests/pathsim/test_simulation.py b/tests/pathsim/test_simulation.py index c1ae6b8a..e17e3fb9 100644 --- a/tests/pathsim/test_simulation.py +++ b/tests/pathsim/test_simulation.py @@ -884,6 +884,21 @@ def test_remove_connection_error(self): with self.assertRaises(ValueError): self.Sim.remove_connection(C) + def test_remove_connection_zeroes_inputs(self): + """Removing a connection zeroes the target block's input ports""" + # Run a step so the connection pushes data + self.Src.function = lambda t: 5.0 + self.Sim.step(0.01) + + # Int should have received input from Src + self.assertNotEqual(self.Int.inputs[0], 0.0) + + # Remove the connection + self.Sim.remove_connection(self.C1) + + # Target input should now be zero + self.assertEqual(self.Int.inputs[0], 0.0) + def test_remove_event(self): """Adding and removing events works""" evt = Event(func_evt=lambda t: t - 1.0, func_act=lambda t: None) From 655ed3a36066adc5ca1ba033cbc581404e7aaad3 Mon Sep 17 00:00:00 2001 From: Milan Rother Date: Thu, 19 Feb 2026 15:53:09 +0100 Subject: [PATCH 2/2] Reset block inputs in _assemble_graph instead of remove_connection --- src/pathsim/simulation.py | 11 +++++------ src/pathsim/subsystem.py | 10 +++++----- tests/pathsim/test_simulation.py | 8 +++++--- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/pathsim/simulation.py b/src/pathsim/simulation.py index 7f9307db..306c7e4c 100644 --- a/src/pathsim/simulation.py +++ b/src/pathsim/simulation.py @@ -446,11 +446,6 @@ def remove_connection(self, connection): self.logger.error(_msg) raise ValueError(_msg) - #zero out target input ports to avoid stale values - for target in connection.targets: - for port in target.ports: - target.block.inputs[port] = 0.0 - #remove from global connection list self.connections.discard(connection) @@ -504,10 +499,14 @@ def remove_event(self, event): # system assembly ------------------------------------------------------------- def _assemble_graph(self): - """Build the internal graph representation for fast system function + """Build the internal graph representation for fast system function evaluation and algebraic loop resolution. """ + #reset all block inputs to clear stale values from removed connections + for block in self.blocks: + block.inputs.reset() + #time the graph construction with Timer(verbose=False) as T: self.graph = Graph(self.blocks, self.connections) diff --git a/src/pathsim/subsystem.py b/src/pathsim/subsystem.py index a46415ff..2dd3640c 100644 --- a/src/pathsim/subsystem.py +++ b/src/pathsim/subsystem.py @@ -337,11 +337,6 @@ def remove_connection(self, connection): if connection not in self.connections: raise ValueError(f"{connection} not part of subsystem") - #zero out target input ports to avoid stale values - for target in connection.targets: - for port in target.ports: - target.block.inputs[port] = 0.0 - self.connections.discard(connection) if self.graph: @@ -386,6 +381,11 @@ def _assemble_graph(self): """Assemble internal graph of subsystem for fast algebraic evaluation during simulation. """ + + #reset all block inputs to clear stale values from removed connections + for block in self.blocks: + block.inputs.reset() + self.graph = Graph({*self.blocks, self.interface}, self.connections) self._graph_dirty = False diff --git a/tests/pathsim/test_simulation.py b/tests/pathsim/test_simulation.py index e17e3fb9..beda6aae 100644 --- a/tests/pathsim/test_simulation.py +++ b/tests/pathsim/test_simulation.py @@ -885,7 +885,7 @@ def test_remove_connection_error(self): self.Sim.remove_connection(C) def test_remove_connection_zeroes_inputs(self): - """Removing a connection zeroes the target block's input ports""" + """Removing a connection zeroes target inputs on next graph rebuild""" # Run a step so the connection pushes data self.Src.function = lambda t: 5.0 self.Sim.step(0.01) @@ -893,10 +893,12 @@ def test_remove_connection_zeroes_inputs(self): # Int should have received input from Src self.assertNotEqual(self.Int.inputs[0], 0.0) - # Remove the connection + # Remove the connection — graph is dirty but not rebuilt yet self.Sim.remove_connection(self.C1) + self.assertTrue(self.Sim._graph_dirty) - # Target input should now be zero + # Next step triggers graph rebuild which resets inputs + self.Sim.step(0.01) self.assertEqual(self.Int.inputs[0], 0.0) def test_remove_event(self):