Skip to content

Conversation

@rruusu
Copy link

@rruusu rruusu commented Oct 21, 2025

These changes are cherry picked from the branch "work", which includes changes originally made to the master branch in October 2024. I hadn't had the time earlier to rebase my code on the major refactoring done to SystemSC.cpp on 19.11.2024 (6d7a397).

Note: This request is based on the maintenance/v2.1 branch, on which I have been working on.

Related Issues

Purpose

This pull request changes SystemSC so that:

  • doStep() always advances a single step of CVODE.
  • stepUntil(double) steps to exactly the given time value.
  • Results are emitted for the nearest CVODE step according to the defined output interval.
    • This allows emitting results at a faster rate than the maximum step size.

Approach

doStepCVODE() and doStepEuler() are changed to get the end time from stepUntil(), instead of just using the stopping time for the whole model.

doStepCVODE() is changed to:

  • Return after each CVODE time step
    • Single call from doStep(), calls in a loop from stepUntil().
    • This allows the progress bar to be updated during simulation.
  • CVODE is called with mode CV_ONE_STEP instead of CV_NORMAL.
    • If the single step goes beyond the end time, a second call with CV_NORMAL is made.
    • The second call only interpolates the values, instead of advancing the solver.

Also eliminates unnecessary calls to getContinuousStates() after the event loop but before updating inputs.

Note, that this change makes a logging interval of zero emit all solver time steps instead using the maximum step size. This may drastically increase the output file size, if the actual time step is much smaller than the maximum step size. The remedy is to set the logging interval to the maximum step size.

Note: The indentation of the while loop in doStepCVODE is unchanged to create simpler view of the changes.

@CLAassistant
Copy link

CLAassistant commented Oct 21, 2025

CLA assistant check
All committers have signed the CLA.

@rruusu
Copy link
Author

rruusu commented Oct 23, 2025

Running the tests locally, it seems that:

  • reference-fmus/BouncingBall.lua fails
  • reference-fmus/Stair.lua gets into an endless loop

I will look into it.

@rruusu
Copy link
Author

rruusu commented Oct 23, 2025

I had somehow managed to lose a condition for checking the stopping time in SystemSC::stepUntil(), when rebasing the code to the current HEAD of maintenance/v2.1, which caused that busy loop in Stairs.lua.

I updated the BouncingBall reference data to reflect the variable step size output.

image

Detail of first bounce shown with stepped lines:
image

@rruusu
Copy link
Author

rruusu commented Oct 23, 2025

What does this mean in the Jenkins failure above?

image

@rruusu
Copy link
Author

rruusu commented Oct 27, 2025

It seems that CVODE doesn't properly take into account the given stopping time, when the stopping time is before a previously found root.

It can be seen in this test output from EventTest.lua that should stop at 2.0, but instead step to 2.1 (the next root):

info:    maximum step size for 'EventTest.root': 1.000000
info:    Result file: EventTest_lua.csv (bufferSize=1)
info:    Final Statistics for 'EventTest.root':
         NumSteps = 0 NumRhsEvals  = 0 NumLinSolvSetups = 0
         NumNonlinSolvIters = 0 NumNonlinSolvConvFails = 0 NumErrTestFails = 0
time,EventTest.root.model.height,EventTest.root.model.der(height)
0, 0.3, -1
0.30000001, -1.00000002723e-08, -1
0.30000001, 0.3, -1
0.60000002, -1.00000004943e-08, -1
0.60000002, 0.3, -1
0.90000003, -1.00000004943e-08, -1
0.90000003, 0.3, -1
1.20000004, -1.00000006054e-08, -1
1.20000004, 0.3, -1
1.50000005, -1.00000006054e-08, -1
1.50000005, 0.3, -1
1.80000006, -1.00000006054e-08, -1
1.80000006, 0.3, -1
2.10000007, -9.99995886097e-09, -1
2.10000007, -9.99995886097e-09, -1
2, -9.99995886097e-09, -1

Looking at CVODE source code, it really seems that the search for additional roots really overrides the test for the stopping time. I need to figure out a new way to handle the outputting of all steps.

refs OpenModelica#1330

It seems that simply calling CVode with mode CV_NORMAL does not work correctly to return at the given stopping time, if the previous call stopped due to a root.
@rruusu
Copy link
Author

rruusu commented Oct 28, 2025

The approach in dd04f81 is clumsy, but I couldn't figure out any other way to force CVODE to always stop at or before tnext in the presence of roots, while keeping an internal state that is consistent with the state of the system.

The issue was that using a second call with CV_NORMAL does not correctly return the state at tnext, when the previous call with CV_ONE_STEP has found a root at a time after tnext.

This approach results in skipping the output of possible intermediate time steps, when the stopping time is at most maximum step size away from the current time.

It is interesting that CVODE returns slightly different state values depending on whether the root is found in a call made using CV_NORMAL or CV_ONE_STEP. CV_ONE_STEP apparently produces a smaller numerical error, at least in the case of EventTest.lua. (See decimal changes in baseline.)

@rruusu
Copy link
Author

rruusu commented Oct 30, 2025

The approach in dd04f81 is clumsy, but I couldn't figure out any other way to force CVODE to always stop at or before tnext in the presence of roots, while keeping an internal state that is consistent with the state of the system.

I found a solution for this using CVodeSetStopTime(). If forces the solver to restrict its actual integration step size so that it will not overstep the given stopping time.

This also fixes issue #1530 that occurs when an input is changed while stopped between two calls to stepUntil(), which happens constantly when SystemSC is used as a component in a co-simulation.

It can also happen when using the solution in #1524 to issue #1516 that omits some solver resets on events in which nothing significant happens to the states or their derivatives at an event.

I will push the fix and a new test case to this branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants