Skip to content
This repository was archived by the owner on May 18, 2019. It is now read-only.

Commit aaeec2c

Browse files
vrugeOpenModelica-Hudson
authored andcommitted
added explicit rungekutta with step size control of order 4
based on: 2016 9th EUROSIM Congress on Modelling and Simulation, Solving Stiff Systems of ODEs by Explicit Methods with Conformed Stability Domains, A. E. Novikov, A. E. Novikov, A. E. Novikov, A. E. Novikov ToDo: - terms for stability error missing in the ste size control - added internal event handling (??)
1 parent 6759fed commit aaeec2c

3 files changed

Lines changed: 138 additions & 1 deletion

File tree

SimulationRuntime/c/simulation/solver/solver_main.c

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ typedef struct RK4_DATA
7777
int work_states_ndims;
7878
double *b;
7979
double *c;
80+
double h;
8081
}RK4_DATA;
8182

8283

8384
static int euler_ex_step(DATA* data, SOLVER_INFO* solverInfo);
85+
static int rungekutta_step_ssc(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo);
8486
static int rungekutta_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo);
8587
static int sym_euler_im_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo);
8688

@@ -154,6 +156,12 @@ int solver_main_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverIn
154156
TRACE_POP
155157
return retVal;
156158
#endif
159+
case S_ERKSSC:
160+
retVal = rungekutta_step_ssc(data, threadData, solverInfo);
161+
if(omc_flag[FLAG_SOLVER_STEPS])
162+
data->simulationInfo->solverSteps = solverInfo->solverStats[0] + solverInfo->solverStatsTmp[0];
163+
TRACE_POP
164+
return retVal;
157165
case S_SYM_EULER:
158166
retVal = sym_euler_im_step(data, threadData, solverInfo);
159167
if(omc_flag[FLAG_SOLVER_STEPS])
@@ -214,6 +222,7 @@ int initializeSolverData(DATA* data, threadData_t *threadData, SOLVER_INFO* solv
214222
allocateSymEulerImp(solverInfo, data->modelData->nStates);
215223
break;
216224
}
225+
case S_ERKSSC:
217226
case S_RUNGEKUTTA:
218227
case S_HEUN:
219228
{
@@ -237,6 +246,9 @@ int initializeSolverData(DATA* data, threadData_t *threadData, SOLVER_INFO* solv
237246
rungeData->work_states_ndims = heun_s;
238247
rungeData->b = heun_b;
239248
rungeData->c = heun_c;
249+
} else if (solverInfo->solverMethod==S_ERKSSC) {
250+
rungeData->h = (omc_flag[FLAG_INITIAL_STEP_SIZE]) ? atof(omc_flagValue[FLAG_INITIAL_STEP_SIZE]) : solverInfo->currentStepSize;
251+
rungeData->work_states_ndims = 5;
240252
} else {
241253
throwStreamPrint(threadData, "Unknown RK solver");
242254
}
@@ -357,7 +369,8 @@ int freeSolverData(DATA* data, SOLVER_INFO* solverInfo)
357369
{
358370
freeSymEulerImp(solverInfo);
359371
}
360-
else if(solverInfo->solverMethod == S_RUNGEKUTTA || solverInfo->solverMethod == S_HEUN)
372+
else if(solverInfo->solverMethod == S_RUNGEKUTTA || solverInfo->solverMethod == S_HEUN
373+
|| solverInfo->solverMethod == S_ERKSSC)
361374
{
362375
/* free RK work arrays */
363376
for(i = 0; i < ((RK4_DATA*)(solverInfo->solverData))->work_states_ndims + 1; i++)
@@ -802,6 +815,127 @@ static int euler_ex_step(DATA* data, SOLVER_INFO* solverInfo)
802815
return 0;
803816
}
804817

818+
/*************************************** EXP_RK_SSC *********************************/
819+
static int rungekutta_step_ssc(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo)
820+
{
821+
// see.
822+
// Solving Stiff Systems of ODEs by Explicit Methods with Conformed Stability
823+
// Domains
824+
// 2016 9th EUROSIM Congress on Modelling and Simulation
825+
// A. E. Novikov...
826+
827+
RK4_DATA *rk = ((RK4_DATA*)(solverInfo->solverData));
828+
const double Atol = data->simulationInfo->tolerance;
829+
const double Rtol = data->simulationInfo->tolerance;
830+
const int nx = data->modelData->nStates;
831+
modelica_real h = rk->h;
832+
double** k = rk->work_states;
833+
int j, i;
834+
double sum;
835+
SIMULATION_DATA *sData = (SIMULATION_DATA*)data->localData[0];
836+
SIMULATION_DATA *sDataOld = (SIMULATION_DATA*)data->localData[1];
837+
modelica_real* stateDer = sData->realVars + nx;
838+
modelica_real* stateDerOld = sDataOld->realVars + nx;
839+
double t = sDataOld->timeValue;
840+
const double targetTime = t + solverInfo->currentStepSize;
841+
const short isMaxStepSizeSet = (short) omc_flagValue[FLAG_MAX_STEP_SIZE];
842+
const double maxStepSize = isMaxStepSizeSet ? atof(omc_flagValue[FLAG_MAX_STEP_SIZE]) : -1;
843+
double x0[nx];
844+
845+
if(t + h > targetTime)
846+
h = solverInfo->currentStepSize;
847+
848+
memcpy(k[0], stateDerOld, nx*sizeof(double));
849+
memcpy(x0, sDataOld->realVars, nx*sizeof(double));
850+
while(t < targetTime && h > 0){
851+
//printf("\nfrom %g to %g by %g\n", t, targetTime, h);
852+
for(j = 0; j < 5; ++j){
853+
854+
if(j > 0)
855+
memcpy(k[j], stateDer, nx*sizeof(double));
856+
857+
switch(j){
858+
case 0:
859+
//yn + k1/3
860+
for(i = 0; i < nx; ++i)
861+
sData->realVars[i] = x0[i] + h * k[0][i]/3.0;
862+
sData->timeValue = t + h/3.0;
863+
break;
864+
865+
case 1:
866+
//yn + 1/6(k1 + k2)
867+
for(i = 0; i < nx; ++i)
868+
sData->realVars[i] = x0[i] + h/6.0 * (k[0][i] + k[1][i]);
869+
sData->timeValue = t + h/3.0;
870+
break;
871+
872+
case 2:
873+
//yn + 1/8*(k1 + 3*k3)
874+
for(i = 0; i < nx; ++i)
875+
sData->realVars[i] = x0[i] + h/8.0 * (k[0][i] + 3*k[2][i]);
876+
sData->timeValue = t + h/2.0;
877+
break;
878+
879+
case 3:
880+
//yn + 1/2*(k1 - 3*k3 + 4*k4)
881+
for(i = 0; i < nx; ++i)
882+
sData->realVars[i] = x0[i] + h/2.0 * (k[0][i] - 3*k[2][i] + 4*k[3][i]);
883+
sData->timeValue = t + h;
884+
break;
885+
886+
case 4:
887+
//yn + 1/6*(k1 + 4*k3 + k5)
888+
for(i = 0; i < nx; ++i){
889+
sData->realVars[i] = x0[i] + h/6.0 * (k[0][i] + 4*k[3][i] + k[4][i]);
890+
}
891+
sData->timeValue = t + h;
892+
break;
893+
894+
}
895+
//f(yn + ...)
896+
/* read input vars */
897+
externalInputUpdate(data);
898+
data->callback->input_function(data, threadData);
899+
/* eval ode equations */
900+
data->callback->functionODE(data, threadData);
901+
}
902+
t += h;
903+
sData->timeValue = t;
904+
solverInfo->currentTime = t;
905+
906+
/* save stats */
907+
/* steps */
908+
solverInfo->solverStatsTmp[0] += 1;
909+
/* function ODE evaluation is done directly after this */
910+
solverInfo->solverStatsTmp[1] += 4;
911+
912+
913+
//stepsize
914+
for(i = 0, sum = 0.0; i < nx; ++i)
915+
sum = fmax(fabs(k[0][i] + 4*k[3][i] -(4.5*k[2][i] + k[4][i]))/(fabs(k[4][i]) + fabs(k[2][i]) + fabs(k[3][i])+ + fabs(k[0][i]) + Atol), sum);
916+
sum *= 2.0/30.0;
917+
918+
919+
h = fmin(0.9*fmax(pow(sum,1/4.0)/(Atol ), 1e-12)*h + 1e-12, (targetTime - h));
920+
if(isMaxStepSizeSet && h > maxStepSize) h = maxStepSize;
921+
if (h > 0) rk->h = h;
922+
923+
if(t < targetTime){
924+
memcpy(x0, sData->realVars, nx*sizeof(double));
925+
memcpy(k[0], k[4], nx*sizeof(double));
926+
sim_result.emit(&sim_result, data, threadData);
927+
}
928+
}
929+
930+
//assert(sData->timeValue == targetTime);
931+
//assert(solverInfo->currentTime == targetTime);
932+
933+
return 0;
934+
}
935+
936+
937+
938+
805939
/*************************************** SYM_EULER_IMP *********************************/
806940
static int sym_euler_im_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo){
807941
int retVal,i,j;

SimulationRuntime/c/util/simulation_options.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ const char *SOLVER_METHOD_NAME[S_MAX] = {
482482
"symEulerSsc",
483483
"heun",
484484
"ida",
485+
"rungekutta_ssc",
485486
"qss"
486487
};
487488

@@ -501,6 +502,7 @@ const char *SOLVER_METHOD_DESC[S_MAX] = {
501502
"symEulerSsc - symbolic implicit euler with step-size control, [compiler flag +symEuler needed]",
502503
"heun - Heun's method (Runge-Kutta fixed step, order 2)",
503504
"ida - Sundials ida solver",
505+
"rungekutta_ssc - Runge-Kutta (with step size control, see. Novikov (2016), Solving Stiff Systems of ODEs...)",
504506
"qss - A QSS solver [experimental]"
505507
};
506508

SimulationRuntime/c/util/simulation_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ enum SOLVER_METHOD
149149
S_SYM_IMP_EULER, /* 12 */
150150
S_HEUN, /* 13 */
151151
S_IDA, /* 14 */
152+
S_ERKSSC, /* 15 */
152153
S_QSS,
153154

154155
S_MAX

0 commit comments

Comments
 (0)