Skip to content

Integrator state not updated after setValue when using oneStep with reset=False #1300

@matthiaskoenig

Description

@matthiaskoenig

Hi all,

I did some additional digging into the following issue:
#1232
This turns out to be a major problem for us.

We can partially work around it by calling oneStep with reset=False, which continues the integration while preserving the integrator state. This flag is exactly what we need. However, there is a bug: values set via setValue are not propagated into the integrator state between oneStep calls.

Example:

import roadrunner
r: roadrunner.RoadRunner = roadrunner.RoadRunner("spt_liver.xml")
r.setValue("[S_ext]", 1.0)
print({key: r.getValue(key) for key in r.selections})

print("--- [S_ext] change lost ---")
_new_time = r.oneStep(currentTime=0, stepSize=10, reset=False)
print({key: r.getValue(key) for key in r.selections})

This produces:

/home/mkoenig/git/pkdb_models/.venv/bin/python /home/mkoenig/git/pkdb_models/pkdb_models/models/tpm_spt/models/results/models/bug_onestep_reset.py 
{'time': 0.0, '[S_ext]': 1.0, '[P_ext]': 0.0, '[S]': 0.0, '[P]': 0.0, '[T]': 0.0, '[protein]': 0.3333333333333333, 'tsim': 0.0}
--- [S_ext] change lost ---
{'time': 10.0, '[S_ext]': 0.0, '[P_ext]': 0.0, '[S]': 0.0, '[P]': 0.0, '[T]': 0.0, '[protein]': 0.3333333333333333, 'tsim': 10.0}

As shown, the model modification to [S_ext] is lost during integration.
Values changed via setValue are simply not pushed into the integrator state.

A minimal example project is attached here:
[spt_liver.zip](https://github.com/user-attachments/files/23794143/spt_liver.zip)

Source of the issue

The problematic behavior is visible in the implementation of oneStep.
When reset == False, the integration continues without ensuring that any updated model values (set by setValue) are transferred to the integrator:

double RoadRunner::oneStep(const double currentTime, const double stepSize, const bool reset) {
    get_self();
    check_model();
    applySimulateOptions();

    try {
        if (reset) {
            self.integrator->restart(currentTime);
        }
        return self.integrator->integrate(currentTime, stepSize);
    }
    catch (EventListenerException &e) {
        rrLog(Logger::LOG_NOTICE) << e.what();
        return self.model->getTime();
    }
}

A missing branch should ensure that changed model values are synchronized when reset == false, e.g.:

if (!reset) {
    self.integrator->updateChangedValuesFromModel;
}

Alternatively, setValue should directly update the integrator state.

Documentation issue

The reset argument in oneStep is also poorly documented and misleadingly named.
The option does not "reset" the model; instead, it controls whether the integrator is restarted.

The Python docstring currently shows only two arguments and does not describe reset at all:

def oneStep(self, currentTime: "double", stepSize: "double", reset: "bool"=True) -> "double":
    r"""

    RoadRunner.oneStep(startTime, stepSize)

    Carry out a one step integration of the model. The method takes two arguments,
    the current time and the step size to us in the integration. The method returns
    the new time which will be currentTime + StepSize::

        newTime = rr.oneStep (10, 0.5)

    """

This should be updated to correctly document all three parameters and clarify the meaning of the reset/restart flag.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions