// simulate the given FMU using the forward euler method. // time events are processed by reducing step size to exactly hit tNext. // state events are checked and fired only at the end of an Euler step. // the simulator may therefore miss state events and fires state events typically too late. static int simulate(FMU* fmu, double tEnd, double h, fmi2Boolean loggingOn, char separator, int nCategories, const fmi2String categories[]) { int i; double dt, tPre; fmi2Boolean timeEvent, stateEvent, stepEvent, terminateSimulation; double time; int nx; // number of state variables int nz; // number of state event indicators double *x = NULL; // continuous states double *xdot = NULL; // the corresponding derivatives in same order double *z = NULL; // state event indicators double *prez = NULL; // previous values of state event indicators fmi2EventInfo eventInfo; // updated by calls to initialize and eventUpdate ModelDescription* md; // handle to the parsed XML file const char* guid; // global unique id of the fmu fmi2CallbackFunctions callbacks = {fmuLogger, calloc, free, NULL, fmu}; // called by the model during simulation fmi2Component c; // instance of the fmu fmi2Status fmi2Flag; // return code of the fmu functions fmi2Real tStart = 0; // start time fmi2Boolean toleranceDefined = fmi2False; // true if model description define tolerance fmi2Real tolerance = 0; // used in setting up the experiment fmi2Boolean visible = fmi2False; // no simulator user interface const char *instanceName; // instance name char *fmuResourceLocation = getTempResourcesLocation(); // path to the fmu resources as URL, "file://C:\QTronic\sales" int nSteps = 0; int nTimeEvents = 0; int nStepEvents = 0; int nStateEvents = 0; FILE* file; ValueStatus vs; // instantiate the fmu md = fmu->modelDescription; guid = getAttributeValue((Element *)md, att_guid); instanceName = getAttributeValue((Element *)getModelExchange(md), att_modelIdentifier); c = fmu->instantiate(instanceName, fmi2ModelExchange, guid, fmuResourceLocation, &callbacks, visible, loggingOn); free(fmuResourceLocation); if (!c) return error("could not instantiate model"); if (nCategories > 0) { fmi2Flag = fmu->setDebugLogging(c, fmi2True, nCategories, categories); if (fmi2Flag > fmi2Warning) { return error("could not initialize model; failed FMI set debug logging"); } } // allocate memory nx = getDerivativesSize(getModelStructure(md)); // number of continuous states is number of derivatives // declared in model structure nz = getAttributeInt((Element *)md, att_numberOfEventIndicators, &vs); // number of event indicators x = (double *) calloc(nx, sizeof(double)); xdot = (double *) calloc(nx, sizeof(double)); if (nz>0) { z = (double *) calloc(nz, sizeof(double)); prez = (double *) calloc(nz, sizeof(double)); } if ((!x || !xdot) || (nz>0 && (!z || !prez))) return error("out of memory"); // open result file if (!(file = fopen(RESULT_FILE, "w"))) { printf("could not write %s because:\n", RESULT_FILE); printf(" %s\n", strerror(errno)); free (x); free(xdot); free(z); free(prez); return 0; // failure } // setup the experiment, set the start time time = tStart; fmi2Flag = fmu->setupExperiment(c, toleranceDefined, tolerance, tStart, fmi2True, tEnd); if (fmi2Flag > fmi2Warning) { return error("could not initialize model; failed FMI setup experiment"); } // initialize fmi2Flag = fmu->enterInitializationMode(c); if (fmi2Flag > fmi2Warning) { return error("could not initialize model; failed FMI enter initialization mode"); } fmi2Flag = fmu->exitInitializationMode(c); if (fmi2Flag > fmi2Warning) { return error("could not initialize model; failed FMI exit initialization mode"); } // event iteration eventInfo.newDiscreteStatesNeeded = fmi2True; eventInfo.terminateSimulation = fmi2False; while (eventInfo.newDiscreteStatesNeeded && !eventInfo.terminateSimulation) { // update discrete states fmi2Flag = fmu->newDiscreteStates(c, &eventInfo); if (fmi2Flag > fmi2Warning) return error("could not set a new discrete state"); } if (eventInfo.terminateSimulation) { printf("model requested termination at t=%.16g\n", time); } else { // enter Continuous-Time Mode fmu->enterContinuousTimeMode(c); // output solution for time tStart outputRow(fmu, c, tStart, file, separator, fmi2True); // output column names outputRow(fmu, c, tStart, file, separator, fmi2False); // output values // enter the simulation loop while (time < tEnd) { // get current state and derivatives fmi2Flag = fmu->getContinuousStates(c, x, nx); if (fmi2Flag > fmi2Warning) return error("could not retrieve states"); fmi2Flag = fmu->getDerivatives(c, xdot, nx); if (fmi2Flag > fmi2Warning) return error("could not retrieve derivatives"); // advance time tPre = time; time = min(time+h, tEnd); timeEvent = eventInfo.nextEventTimeDefined && eventInfo.nextEventTime <= time; if (timeEvent) time = eventInfo.nextEventTime; dt = time - tPre; fmi2Flag = fmu->setTime(c, time); if (fmi2Flag > fmi2Warning) error("could not set time"); // perform one step for (i = 0; i < nx; i++) x[i] += dt * xdot[i]; // forward Euler method fmi2Flag = fmu->setContinuousStates(c, x, nx); if (fmi2Flag > fmi2Warning) return error("could not set states"); if (loggingOn) printf("Step %d to t=%.16g\n", nSteps, time); // check for state event for (i = 0; i < nz; i++) prez[i] = z[i]; fmi2Flag = fmu->getEventIndicators(c, z, nz); if (fmi2Flag > fmi2Warning) return error("could not retrieve event indicators"); stateEvent = FALSE; for (i=0; i<nz; i++) stateEvent = stateEvent || (prez[i] * z[i] < 0); // check for step event, e.g. dynamic state selection fmi2Flag = fmu->completedIntegratorStep(c, fmi2True, &stepEvent, &terminateSimulation); if (fmi2Flag > fmi2Warning) return error("could not complete intgrator step"); if (terminateSimulation) { printf("model requested termination at t=%.16g\n", time); break; // success } // handle events if (timeEvent || stateEvent || stepEvent) { fmu->enterEventMode(c); if (timeEvent) { nTimeEvents++; if (loggingOn) printf("time event at t=%.16g\n", time); } if (stateEvent) { nStateEvents++; if (loggingOn) for (i=0; i<nz; i++) printf("state event %s z[%d] at t=%.16g\n", (prez[i]>0 && z[i]<0) ? "-\\-" : "-/-", i, time); } if (stepEvent) { nStepEvents++; if (loggingOn) printf("step event at t=%.16g\n", time); } // event iteration in one step, ignoring intermediate results eventInfo.newDiscreteStatesNeeded = fmi2True; eventInfo.terminateSimulation = fmi2False; while (eventInfo.newDiscreteStatesNeeded && !eventInfo.terminateSimulation) { // update discrete states fmi2Flag = fmu->newDiscreteStates(c, &eventInfo); if (fmi2Flag > fmi2Warning) return error("could not set a new discrete state"); } if (eventInfo.terminateSimulation) { printf("model requested termination at t=%.16g\n", time); break; // success } // enter Continuous-Time Mode fmu->enterContinuousTimeMode(c); // check for change of value of states if (eventInfo.valuesOfContinuousStatesChanged && loggingOn) { printf("continuous state values changed at t=%.16g\n", time); } if (eventInfo.nominalsOfContinuousStatesChanged && loggingOn){ printf("nominals of continuous state changed at t=%.16g\n", time); } } // if event outputRow(fmu, c, time, file, separator, fmi2False); // output values for this step nSteps++; } // while } // cleanup fmu->terminate(c); fmu->freeInstance(c); fclose(file); if (x != NULL) free(x); if (xdot != NULL) free(xdot); if (z != NULL) free(z); if (prez != NULL) free(prez); // print simulation summary printf("Simulation from %g to %g terminated successful\n", tStart, tEnd); printf(" steps ............ %d\n", nSteps); printf(" fixed step size .. %g\n", h); printf(" time events ...... %d\n", nTimeEvents); printf(" state events ..... %d\n", nStateEvents); printf(" step events ...... %d\n", nStepEvents); return 1; // success }
// simulate the given FMU using the forward euler method. // time events are processed by reducing step size to exactly hit tNext. // state events are checked and fired only at the end of an Euler step. // the simulator may therefore miss state events and fires state events typically too late. static int simulate(FMU* fmu, double tEnd, double h, fmiBoolean loggingOn, char separator) { int i, n; double dt, tPre; fmiBoolean timeEvent, stateEvent, stepEvent; double time; int nx; // number of state variables int nz; // number of state event indicators double *x; // continuous states double *xdot; // the crresponding derivatives in same order double *z = NULL; // state event indicators double *prez = NULL; // previous values of state event indicators fmiEventInfo eventInfo; // updated by calls to initialize and eventUpdate ModelDescription* md; // handle to the parsed XML file const char* guid; // global unique id of the fmu fmiCallbackFunctions callbacks; // called by the model during simulation fmiComponent c; // instance of the fmu fmiStatus fmiFlag; // return code of the fmu functions fmiReal t0 = 0; // start time fmiBoolean toleranceControlled = fmiFalse; int nSteps = 0; int nTimeEvents = 0; int nStepEvents = 0; int nStateEvents = 0; FILE* file; // instantiate the fmu md = fmu->modelDescription; guid = getString(md, att_guid); callbacks.logger = fmuLogger; callbacks.allocateMemory = calloc; callbacks.freeMemory = free; c = fmu->instantiateModel(getModelIdentifier(md), guid, callbacks, loggingOn); if (!c) return error("could not instantiate model"); // allocate memory nx = getNumberOfStates(md); nz = getNumberOfEventIndicators(md); x = (double *) calloc(nx, sizeof(double)); xdot = (double *) calloc(nx, sizeof(double)); if (nz>0) { z = (double *) calloc(nz, sizeof(double)); prez = (double *) calloc(nz, sizeof(double)); } if (!x || !xdot || nz>0 && (!z || !prez)) return error("out of memory"); // open result file if (!(file=fopen(RESULT_FILE, "w"))) { printf("could not write %s because:\n", RESULT_FILE); printf(" %s\n", strerror(errno)); return 0; // failure } // set the start time and initialize time = t0; fmiFlag = fmu->setTime(c, t0); if (fmiFlag > fmiWarning) return error("could not set time"); fmiFlag = fmu->initialize(c, toleranceControlled, t0, &eventInfo); if (fmiFlag > fmiWarning) error("could not initialize model"); if (eventInfo.terminateSimulation) { printf("model requested termination at init"); tEnd = time; } // output solution for time t0 outputRow(fmu, c, t0, file, separator, TRUE); // output column names outputRow(fmu, c, t0, file, separator, FALSE); // output values // enter the simulation loop while (time < tEnd) { // get current state and derivatives fmiFlag = fmu->getContinuousStates(c, x, nx); if (fmiFlag > fmiWarning) return error("could not retrieve states"); fmiFlag = fmu->getDerivatives(c, xdot, nx); if (fmiFlag > fmiWarning) return error("could not retrieve derivatives"); // advance time tPre = time; time = min(time+h, tEnd); timeEvent = eventInfo.upcomingTimeEvent && eventInfo.nextEventTime < time; if (timeEvent) time = eventInfo.nextEventTime; dt = time - tPre; fmiFlag = fmu->setTime(c, time); if (fmiFlag > fmiWarning) error("could not set time"); // perform one step for (i=0; i<nx; i++) x[i] += dt*xdot[i]; // forward Euler method fmiFlag = fmu->setContinuousStates(c, x, nx); if (fmiFlag > fmiWarning) return error("could not set states"); if (loggingOn) printf("Step %d to t=%.16g\n", nSteps, time); // Check for step event, e.g. dynamic state selection fmiFlag = fmu->completedIntegratorStep(c, &stepEvent); if (fmiFlag > fmiWarning) return error("could not complete intgrator step"); // Check for state event for (i=0; i<nz; i++) prez[i] = z[i]; fmiFlag = fmu->getEventIndicators(c, z, nz); if (fmiFlag > fmiWarning) return error("could not retrieve event indicators"); stateEvent = FALSE; for (i=0; i<nz; i++) stateEvent = stateEvent || (prez[i] * z[i] < 0); // handle events if (timeEvent || stateEvent || stepEvent) { if (timeEvent) { nTimeEvents++; if (loggingOn) printf("time event at t=%.16g\n", time); } if (stateEvent) { nStateEvents++; if (loggingOn) for (i=0; i<nz; i++) printf("state event %s z[%d] at t=%.16g\n", (prez[i]>0 && z[i]<0) ? "-\\-" : "-/-", i, time); } if (stepEvent) { nStepEvents++; if (loggingOn) printf("step event at t=%.16g\n", time); } // event iteration in one step, ignoring intermediate results fmiFlag = fmu->eventUpdate(c, fmiFalse, &eventInfo); if (fmiFlag > fmiWarning) return error("could not perform event update"); // terminate simulation, if requested by the model if (eventInfo.terminateSimulation) { printf("model requested termination at t=%.16g\n", time); break; // success } // check for change of value of states if (eventInfo.stateValuesChanged && loggingOn) { printf("state values changed at t=%.16g\n", time); } // check for selection of new state variables if (eventInfo.stateValueReferencesChanged && loggingOn) { printf("new state variables selected at t=%.16g\n", time); } } // if event outputRow(fmu, c, time, file, separator, FALSE); // output values for this step nSteps++; } // while // cleanup fclose(file); if (x!=NULL) free(x); if (xdot!= NULL) free(xdot); if (z!= NULL) free(z); if (prez!= NULL) free(prez); // print simulation summary printf("Simulation from %g to %g terminated successful\n", t0, tEnd); printf(" steps ............ %d\n", nSteps); printf(" fixed step size .. %g\n", h); printf(" time events ...... %d\n", nTimeEvents); printf(" state events ..... %d\n", nStateEvents); printf(" step events ...... %d\n", nStepEvents); return 1; // success }