diff --git a/src/OMSimulatorLib/SystemSC.cpp b/src/OMSimulatorLib/SystemSC.cpp index 0c72d8f86..4376adf0d 100644 --- a/src/OMSimulatorLib/SystemSC.cpp +++ b/src/OMSimulatorLib/SystemSC.cpp @@ -881,6 +881,15 @@ oms_status_enu_t oms::SystemSC::doStepCVODE() { const fmi3Float64 tout = std::min(tnext, end_time); + // CVode rejects an interval it cannot tell apart from zero (CV_TOO_CLOSE) + // There is nothing left to integrate in it; assume end_time is reached. + if (tout - time < 2.0 * SUN_UNIT_ROUNDOFF * std::max(std::fabs(time), std::fabs(tout))) + { + logDebug("CVode: skipping degenerate interval " + std::to_string(time) + " -> " + std::to_string(tout)); + time = end_time; + break; + } + logDebug("CVode: " + std::to_string(time) + " -> " + std::to_string(tout)); for (size_t j=0, k=0; j < fmus.size(); ++j) for (size_t i=0; i < nStates[j]; ++i, ++k) diff --git a/testsuite/tests/resources/CMakeLists.txt b/testsuite/tests/resources/CMakeLists.txt index 11b735086..33b0927d1 100644 --- a/testsuite/tests/resources/CMakeLists.txt +++ b/testsuite/tests/resources/CMakeLists.txt @@ -12,6 +12,7 @@ set(OM_OMS_TESTSUITE_RESOURCES_FMUS ${CMAKE_CURRENT_SOURCE_DIR}/B ${CMAKE_CURRENT_SOURCE_DIR}/BouncingBall ${CMAKE_CURRENT_SOURCE_DIR}/BouncingBall3 + ${CMAKE_CURRENT_SOURCE_DIR}/ClockedStepBoundary ${CMAKE_CURRENT_SOURCE_DIR}/Dahlquist ${CMAKE_CURRENT_SOURCE_DIR}/Dahlquist3 ${CMAKE_CURRENT_SOURCE_DIR}/DualMassOscillator.System1 diff --git a/testsuite/tests/resources/ClockedStepBoundary.mos b/testsuite/tests/resources/ClockedStepBoundary.mos new file mode 100644 index 000000000..ea2d6384f --- /dev/null +++ b/testsuite/tests/resources/ClockedStepBoundary.mos @@ -0,0 +1,13 @@ +// Regenerates testsuite/resources/ClockedStepBoundary. +// +// A clocked model: Modelica.Clocked drives it from periodic clocks whose tick +// times are computed exactly (k * period), while a master stepping the FMU +// accumulates its own communication points. The two disagree by an ULP once the +// accumulated end of a communication step lands just past a tick, which is what +// the clockedStepBoundary test exercises. + +loadModel(Modelica, {"4.0.0"}); getErrorString(); + +buildModelFMU(Modelica.Clocked.Examples.CascadeControlledDrive.AbsoluteClocks, version="2.0", fmuType="me", fileNamePrefix="ClockedStepBoundary", platforms={"x86_64-linux-gnu docker run multiarch/crossbuild","x86_64-w64-mingw32 docker run multiarch/crossbuild"}); getErrorString(); + +system("zip -qd ClockedStepBoundary.fmu sources/* && unzip -o ClockedStepBoundary.fmu -d ClockedStepBoundary/"); diff --git a/testsuite/tests/resources/ClockedStepBoundary/binaries/linux64/ClockedStepBoundary.so b/testsuite/tests/resources/ClockedStepBoundary/binaries/linux64/ClockedStepBoundary.so new file mode 100755 index 000000000..b36b89020 Binary files /dev/null and b/testsuite/tests/resources/ClockedStepBoundary/binaries/linux64/ClockedStepBoundary.so differ diff --git a/testsuite/tests/resources/ClockedStepBoundary/documentation/index.html b/testsuite/tests/resources/ClockedStepBoundary/documentation/index.html new file mode 100644 index 000000000..2a1397266 --- /dev/null +++ b/testsuite/tests/resources/ClockedStepBoundary/documentation/index.html @@ -0,0 +1,14 @@ + +

Modelica.Clocked.Examples.CascadeControlledDrive.AbsoluteClocks

+

Drive with clocked cascade controller where all partitions are defined with exact (integer) clock that need to be compatible to each other

+

Information

+

+Cascade control drive with discrete-time controller where two +periodic clock with absolute periods are defined and +are associated to +the corresponding controller partitions. +The super-sampling factor of block "super" is derived by +clock inference. +

+ +

Revisions

diff --git a/testsuite/tests/resources/ClockedStepBoundary/modelDescription.xml b/testsuite/tests/resources/ClockedStepBoundary/modelDescription.xml new file mode 100644 index 000000000..f5e3aa1c9 --- /dev/null +++ b/testsuite/tests/resources/ClockedStepBoundary/modelDescription.xml @@ -0,0 +1,830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tests/resources/ClockedStepBoundary/resources/ClockedStepBoundary_JacA.bin b/testsuite/tests/resources/ClockedStepBoundary/resources/ClockedStepBoundary_JacA.bin new file mode 100644 index 000000000..035462ec2 Binary files /dev/null and b/testsuite/tests/resources/ClockedStepBoundary/resources/ClockedStepBoundary_JacA.bin differ diff --git a/testsuite/tests/simulation/CMakeLists.txt b/testsuite/tests/simulation/CMakeLists.txt index 0815cf3b4..2e7c51615 100644 --- a/testsuite/tests/simulation/CMakeLists.txt +++ b/testsuite/tests/simulation/CMakeLists.txt @@ -1,4 +1,5 @@ oms_add_test( + clockedStepBoundary.py DualMassOscillator1.py DualMassOscillator2.py exportJson1.py diff --git a/testsuite/tests/simulation/clockedStepBoundary.py b/testsuite/tests/simulation/clockedStepBoundary.py new file mode 100644 index 000000000..3c31829e4 --- /dev/null +++ b/testsuite/tests/simulation/clockedStepBoundary.py @@ -0,0 +1,44 @@ +## status: correct +## linux: yes +## ucrt64: no +## win: no +## mac: no +## the checked-in FMU carries linux64 binaries only; rebuild it with the +## cross-build platforms in resources/ClockedStepBoundary.mos to widen this + +from OMSimulator import FMU, Settings + +Settings.suppressPath = True + +# A clocked FMU integrated with CVode. Modelica.Clocked computes its tick times +# exactly (k * period), while doStepCVODE accumulates the end of each +# communication step. Once the accumulated end lands an ULP past a tick, the +# interval left over after the event at that tick is smaller than CVode can +# integrate, and CVode used to be called with it anyway - failing the whole +# simulation with CV_TOO_CLOSE (flag -27) at t = 0.08. + +model = FMU('../resources/ClockedStepBoundary.fmu') +model.mode = 'me' +model.startTime = 0.0 +model.stopTime = 0.2 +model.tolerance = 1e-8 +model.instantiate() +model.setSolver('cvode') +model.setResultFile('ClockedStepBoundary_res.mat') +model.initialize() +model.simulate() +model.terminate() +model.delete() + +print('simulation finished', flush=True) + +## Result: +## info: maximum step size for 'AbsoluteClocks.root': 0.008000 +## info: Result file: ClockedStepBoundary_res.mat (bufferSize=10) +## info: Parameter AbsoluteClocks.fastClock.solverMethod will not be stored in the result file, because the signal type is not supported +## info: Parameter AbsoluteClocks.slowClock.solverMethod will not be stored in the result file, because the signal type is not supported +## info: Final Statistics for 'AbsoluteClocks.root': +## NumSteps = 10 NumRhsEvals = 15 NumLinSolvSetups = 8 +## NumNonlinSolvIters = 14 NumNonlinSolvConvFails = 0 NumErrTestFails = 1 +## simulation finished +## endResult