@@ -534,23 +534,23 @@ oms_status_enu_t oms::SystemSC::doStep()
534534 switch (solverMethod)
535535 {
536536 case oms_solver_sc_explicit_euler:
537- return doStepEuler ();
537+ return doStepEuler (time + maximumStepSize );
538538
539539 case oms_solver_sc_cvode:
540- return doStepCVODE ();
540+ return doStepCVODE (time + maximumStepSize );
541541
542542 default :
543543 return logError_InternalError;
544544 }
545545}
546546
547- oms_status_enu_t oms::SystemSC::doStepEuler ()
547+ oms_status_enu_t oms::SystemSC::doStepEuler (double stopTime )
548548{
549549 fmi2Status fmistatus;
550550 oms_status_enu_t status;
551551
552552 // Step 1: Initialize state variables and time
553- const fmi2Real end_time = std::min (time + maximumStepSize, getModel (). getStopTime () );
553+ const fmi2Real end_time = std::min (time + maximumStepSize, stopTime );
554554 const fmi2Real event_time_tolerance = 1e-4 ;
555555
556556 logDebug (" doStepEuler: " + std::to_string (time) + " -> " + std::to_string (end_time));
@@ -766,13 +766,14 @@ oms_status_enu_t oms::SystemSC::doStepEuler()
766766 return oms_status_ok;
767767}
768768
769- oms_status_enu_t oms::SystemSC::doStepCVODE ()
769+ oms_status_enu_t oms::SystemSC::doStepCVODE (double stopTime )
770770{
771771 fmi2Status fmistatus;
772772 oms_status_enu_t status;
773- int flag;
773+ int flag = 0 ;
774+ bool tnext_is_event = false ;
774775
775- const fmi2Real end_time = std::min (time + maximumStepSize, getModel (). getStopTime ()) ;
776+ const fmi2Real end_time = stopTime ;
776777
777778 // find next time event
778779 fmi2Real tnext = end_time+1.0 ;
@@ -788,16 +789,35 @@ oms_status_enu_t oms::SystemSC::doStepCVODE()
788789 time = end_time;
789790 }
790791 }
792+
793+ tnext_is_event = tnext <= end_time;
794+ tnext = std::min (tnext, end_time);
795+
791796 logDebug (" tnext: " + std::to_string (tnext));
792797
793- while (time < end_time)
794- {
798+ // while (time < end_time)
799+ // {
795800 logDebug (" CVode: " + std::to_string (time) + " -> " + std::to_string (end_time));
796801 for (size_t j=0 , k=0 ; j < fmus.size (); ++j)
797802 for (size_t i=0 ; i < nStates[j]; ++i, ++k)
798803 NV_Ith_S (solverData.cvode .y , k) = states[j][i];
799804
800- flag = CVode (solverData.cvode .mem , std::min (tnext, end_time), solverData.cvode .y , &time, CV_NORMAL);
805+ double cvode_time = tnext;
806+ CVodeGetCurrentTime (solverData.cvode .mem , &cvode_time);
807+ if (cvode_time < tnext) {
808+ flag = CVode (solverData.cvode .mem , tnext, solverData.cvode .y , &cvode_time, CV_ONE_STEP);
809+ if (flag < 0 )
810+ return logError (" SUNDIALS_ERROR: CVode() failed with flag = " + std::to_string (flag));
811+ }
812+
813+ if (cvode_time > tnext) {
814+ // interpolate result to tnext (this shouldn't take any further steps)
815+ flag = CVode (solverData.cvode .mem , tnext, solverData.cvode .y , &cvode_time, CV_NORMAL);
816+ if (flag < 0 )
817+ return logError (" SUNDIALS_ERROR: CVode() failed with flag = " + std::to_string (flag));
818+ }
819+
820+ time = cvode_time;
801821
802822 for (size_t i = 0 , j=0 ; i < fmus.size (); ++i)
803823 {
@@ -809,7 +829,7 @@ oms_status_enu_t oms::SystemSC::doStepCVODE()
809829 if (oms_status_ok != status) return status;
810830 }
811831
812- if (flag == CV_ROOT_RETURN || time == tnext)
832+ if (flag == CV_ROOT_RETURN || tnext_is_event && time == tnext)
813833 {
814834 logDebug (" event found!!! " + std::to_string (time));
815835
@@ -839,15 +859,6 @@ oms_status_enu_t oms::SystemSC::doStepCVODE()
839859 if (fmi2OK != fmistatus) logError_FMUCall (" fmi2_enterContinuousTimeMode" , fmus[i]);
840860 }
841861
842- for (size_t i = 0 ; i < fmus.size (); ++i)
843- {
844- if (0 == nStates[i])
845- continue ;
846-
847- status = fmus[i]->getContinuousStates (states[i]);
848- if (oms_status_ok != status) return status;
849- }
850-
851862 // find next time event
852863 tnext = end_time+1.0 ;
853864 for (size_t i = 0 ; i < fmus.size (); ++i)
@@ -862,6 +873,10 @@ oms_status_enu_t oms::SystemSC::doStepCVODE()
862873 time = end_time;
863874 }
864875 }
876+
877+ tnext_is_event = tnext <= end_time;
878+ tnext = std::min (tnext, end_time);
879+
865880 logDebug (" tnext: " + std::to_string (tnext));
866881
867882 // emit the right limit of the event
@@ -885,10 +900,10 @@ oms_status_enu_t oms::SystemSC::doStepCVODE()
885900 flag = CVodeReInit (solverData.cvode .mem , time, solverData.cvode .y );
886901 if (flag < 0 ) return logError (" SUNDIALS_ERROR: CVodeReInit() failed with flag = " + std::to_string (flag));
887902
888- continue ;
903+ return oms_status_ok ;
889904 }
890905
891- if (flag == CV_SUCCESS)
906+ if (flag >= 0 ) // Some kind of success
892907 {
893908 logDebug (" CVode completed successfully at t = " + std::to_string (time));
894909
@@ -914,7 +929,7 @@ oms_status_enu_t oms::SystemSC::doStepCVODE()
914929 }
915930 else
916931 return logError (" CVode failed with flag = " + std::to_string (flag));
917- }
932+ // }
918933
919934 return oms_status_ok;
920935
@@ -930,14 +945,25 @@ oms_status_enu_t oms::SystemSC::stepUntil(double stopTime)
930945
931946 // main simulation loop
932947 oms_status_enu_t status = oms_status_ok;
933- while (time < std::min (stopTime, getModel ().getStopTime ()) && oms_status_ok == status)
948+ double endTime = std::min (stopTime, getModel ().getStopTime ());
949+ double lastTime = time;
950+ while (time < endTime && oms_status_ok == status)
934951 {
935- status = doStep ();
952+ if (solverMethod == oms_solver_sc_explicit_euler)
953+ status = doStepEuler (endTime);
954+ else if (solverMethod == oms_solver_sc_cvode)
955+ status = doStepCVODE (endTime);
956+ else
957+ return logError_InternalError;
958+
936959 if (status != oms_status_ok)
937960 logWarning (" Bad return code at time " + std::to_string (time));
938961
939- if (isTopLevelSystem () && Flags::ProgressBar ())
962+ if (isTopLevelSystem () && Flags::ProgressBar () && time > lastTime + maximumStepSize)
963+ {
940964 Log::ProgressBar (startTime, stopTime, time);
965+ lastTime = time;
966+ }
941967 }
942968
943969 if (isTopLevelSystem () && Flags::ProgressBar ())
0 commit comments