Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/script_interface/integrators/IntegratorHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void IntegratorHandle::on_bind_system(::System::System &system) {
system.propagation->integ_switch == INTEG_METHOD_NVT and
system.get_time_step() == -1. and
is_type<double>(params.at(key)) and
get_value<double>(is_type<double>(params.at(key))) == -1.)) {
get_value<double>(params.at(key)) == -1.)) {
do_set_parameter(key, params.at(key));
}
}
Expand Down
1 change: 1 addition & 0 deletions testsuite/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ python_test(FILE propagation_stokesian.py MAX_NUM_PROC 2)
python_test(FILE integrator_symplectic_euler_langevin.py MAX_NUM_PROC 4)
python_test(FILE integrator_steepest_descent.py MAX_NUM_PROC 4)
python_test(FILE integrator_exceptions.py MAX_NUM_PROC 1)
python_test(FILE integrator_time_step_restore.py MAX_NUM_PROC 1)
python_test(FILE integrator_langevin_stats.py MAX_NUM_PROC 1 LABELS long)
python_test(FILE integrator_brownian_stats.py MAX_NUM_PROC 1 LABELS long)
python_test(FILE integrator_npt_stats.py MAX_NUM_PROC 4 LABELS long)
Expand Down
54 changes: 54 additions & 0 deletions testsuite/python/integrator_time_step_restore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# Copyright (C) 2026 The ESPResSo project
#
# This file is part of ESPResSo.
#
# ESPResSo is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ESPResSo is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

import unittest as ut
import pickle

import espressomd


class IntegratorTimeStepRestore(ut.TestCase):
"""
Regression test for the ``on_bind_system`` sentinel-skip guard in
``IntegratorHandle``. A :class:`System` whose ``time_step`` was never set
keeps the ``-1.`` sentinel and the default Velocity Verlet integrator
(``INTEG_METHOD_NVT``). Serializing and deserializing such a system must
succeed: the guard is supposed to *skip* re-applying ``time_step == -1.``
during ``on_bind_system`` so that ``System::set_time_step(-1.)`` is never
called (it throws ``std::domain_error`` for non-positive time steps).
"""

def test_restore_unset_time_step(self):
system = espressomd.System(box_l=[1., 1., 1.])
# time_step must still be the -1. sentinel (never set by the user)
self.assertEqual(system.integrator.time_step, -1.)

# round-trip via pickle: this triggers
# System._restore_object -> do_construct (else-branch) ->
# do_set_parameter("integrator", deserialized handle) ->
# IntegratorHandle::on_bind_system -> sentinel-skip guard
state = pickle.dumps(system)
restored = pickle.loads(state)

# restore must succeed and preserve the unset sentinel
self.assertEqual(restored.integrator.time_step, -1.)


if __name__ == "__main__":
ut.main()
Loading