void exec() { fmi2Flag = fmu.doStep(c, time.to_seconds(), h.to_seconds(), fmi2True); if (fmi2Flag == fmi2Discard) { fmi2Boolean b; // check if model requests to end simulation if (fmi2OK != fmu.getBooleanStatus(c, fmi2Terminated, &b)) { return SC_REPORT_ERROR(name(),"could not complete simulation of the model. getBooleanStatus return other than fmi2OK"); } if (b == fmi2True) { return SC_REPORT_ERROR(name(),"the model requested to end the simulation"); } return SC_REPORT_ERROR(name(),"could not complete simulation of the model"); } if (fmi2Flag != fmi2OK) return SC_REPORT_ERROR(name(),"could not complete simulation of the model"); // FIXME: res = outputRow(fmu, c, time, file, separator, fmi2False); // output values for this step auto res = getRealOutput(&fmu, c, output_index); oval = sub_signal(time, time+h, [this,res](const sc_time& t) { return res; } ); }
//Implementing the abstract semantics void init() { time = SC_ZERO_TIME; fmuResourceLocation = getTempResourcesLocation(); visible = fmi2False; //~ callbacks = {fmuLogger, calloc, free, NULL, fmu}; toleranceDefined = fmi2False; tolerance = 0; //~ vs = 0; // load the FMU loadFMU(fmuFileName.c_str(), &fmu); // run the simulation // instantiate the fmu md = fmu.modelDescription; guid = getAttributeValue((Element *)md, att_guid); instanceName = getAttributeValue((Element *)getCoSimulation(md), att_modelIdentifier); c = fmu.instantiate(instanceName, fmi2CoSimulation, guid, fmuResourceLocation, &callbacks, visible, fmi2False/*logging off*/); free(fmuResourceLocation); if (!c) return SC_REPORT_ERROR(name(),"could not instantiate model"); defaultExp = getDefaultExperiment(md); if (defaultExp) tolerance = getAttributeDouble(defaultExp, att_tolerance, &vs); if (vs == valueDefined) { toleranceDefined = fmi2True; } fmi2Flag = fmu.setupExperiment(c, toleranceDefined, tolerance, 0, fmi2True, 1000/* FIXME */); if (fmi2Flag > fmi2Warning) { return SC_REPORT_ERROR(name(),"could not initialize model; failed FMI setup experiment"); } fmi2Flag = fmu.enterInitializationMode(c); if (fmi2Flag > fmi2Warning) { return SC_REPORT_ERROR(name(),"could not initialize model; failed FMI enter initialization mode"); } fmi2Flag = fmu.exitInitializationMode(c); if (fmi2Flag > fmi2Warning) { return SC_REPORT_ERROR(name(),"could not initialize model; failed FMI exit initialization mode"); } // output solution for time t0 // FIXME: outputRow(fmu, c, tStart, file, separator, fmi2False); // output values //~ auto res = getRealOutput(fmu, c, 0); //~ oval = sub_signal(time, time+h, //~ [this,res](const sc_time& t) //~ { //~ return res; //~ } //~ ); //~ WRITE_MULTIPORT(oport1, oval) //~ time += h; //~ wait(time - sc_time_stamp()); ival1 = iport1.read(); }
void clean() { // end simulation fmu.terminate(c); fmu.freeInstance(c); #ifdef _MSC_VER FreeLibrary(fmu.dllHandle); #else dlclose(fmu.dllHandle); #endif freeModelDescription(fmu.modelDescription); deleteUnzippedFiles(); }
/////////////////////////////////////////////////////////////////////////////// /// 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. /// ///\param fmu FMU. ///\param tEnd Ending time of simulation. ///\param h Tiem step size. ///\param loggingOn Controller for logging. ///\param separator Separator character. ///\return 0 if there is no error occurred. /////////////////////////////////////////////////////////////////////////////// static int simulate(FMU* fmu, double tEnd, double h, fmiBoolean loggingOn, char separator) { int i, n; fmiBoolean timeEvent, stateEvent, stepEvent; double time; 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; FILE* file; fmiValueReference vr; // add it to get value reference for variables //Note: User defined references //Begin------------------------------------------------------------------ fmiValueReference vru[1], vry[1]; // value references for two input and two output variables //End-------------------------------------------------------------------- ScalarVariable** vars = fmu->modelDescription->modelVariables; // add it to get variables int k; // add a counter for variables fmiReal ru1, ru2, ry, ry1, ry2; // add real variables for input and output fmiInteger ix, iy; // add integer variables for input and output fmiBoolean bx, by; // add boolean variables for input and output fmiString sx, sy; // Zuo: add string variables for input and output fmiStatus status; // Zuo: add stauus for fmi printDebug("Instantiate the fmu.\n"); // instantiate the fmu md = fmu->modelDescription; guid = getString(md, att_guid); printfDebug("Got GUID = %s!\n", guid); callbacks.logger = fmuLogger; callbacks.allocateMemory = calloc; callbacks.freeMemory = free; printDebug("Got callbacks!\n"); printfDebug("Model Identifer is %s\n", getModelIdentifier(md)); c = fmu->instantiateSlave(getModelIdentifier(md), guid, "Model1", "", 10, fmiFalse, fmiFalse, callbacks, loggingOn); if (!c) { printError("could not instantiate slaves.\n"); return 1; } printDebug("Instantiated slaves!\n"); // Open result file if (!(file=fopen(RESULT_FILE, "w"))) { printfError("could not write %s because:\n", RESULT_FILE); printfError(" %s\n", strerror(errno)); return 1; } printDebug("Open results file!\n"); // Set the start time and initialize time = t0; printDebug("start to initialize fmu!\n"); fmiFlag = fmu->initializeSlave(c, t0, fmiTrue, tEnd); printDebug("Initialized fmu!\n"); if (fmiFlag > fmiWarning) { printError("could not initialize model"); return 1; } // Output solution for time t0 printDebug("start to outputRow"); //outputRow(fmu, c, t0, file, separator, TRUE); // output column names //outputRow(fmu, c, t0, file, separator, FALSE); // output initla value of fmu outputdata(t0, file, separator, 0, 0, TRUE); printDebug("start to getValueReference"); ///////////////////////////////////////////////////////////////////////////// // Get value references for input and output varibles // Note: User needs to specify the name of variables for their own fmus //Begin------------------------------------------------------------------ vru[0] = getValueReference(getVariableByName(md, "Toa")); //vru[1] = getValueReference(getVariableByName(md, "u2")); vry[0] = getValueReference(getVariableByName(md, "TrmSou")); //vry[1] = getValueReference(getVariableByName(md, "y2")); //End-------------------------------------------------------------------- printDebug("Enter in simulation loop.\n"); // enter the simulation loop while (time < tEnd) { if (loggingOn) printf("Step %d to t=%.4f\n", nSteps, time); /////////////////////////////////////////////////////////////////////////// // Step 1: get values of output variables from slaves for (k=0; vars[k]; k++) { ScalarVariable* sv = vars[k]; if (getAlias(sv)!=enu_noAlias) continue; if (getCausality(sv) != enu_output) continue; // only get output variable vr = getValueReference(sv); switch (sv->typeSpec->type){ case elm_Real: fmu->getReal(c, &vr, 1, &ry); break; case elm_Integer: fmu->getInteger(c, &vr, 1, &iy); break; case elm_Boolean: fmu->getBoolean(c, &vr, 1, &by); break; case elm_String: fmu->getString(c, &vr, 1, &sy); break; } // Allocate values to cooresponding varibles on master program // Note: User needs to specify the output variables for their own fmu //Begin------------------------------------------------------------------ if (vr == vry[0]) ry1 = ry; //else if(vr == vry[1]) ry2 = ry; //End-------------------------------------------------------------------- } /////////////////////////////////////////////////////////////////////////// // Step 2: compute on master side // Note: User can adjust the computing schemes of mater program //Begin------------------------------------------------------------------ printf("Dymola output = %f\n", ry1); //= ry2 + 3.0; ru1 = 293; //End-------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // Step 3: set input variables back to slaves for (k=0; vars[k]; k++) { ScalarVariable* sv = vars[k]; if (getAlias(sv)!=enu_noAlias) continue; if (getCausality(sv) != enu_input) continue; // only set input variable vr = getValueReference(sv); // Note: User can adjust the settings for input variables //Begin------------------------------------------------------------------ switch (sv->typeSpec->type){ case elm_Real: if(vr == vru[0]) { fmu->setReal(c, &vr, 1, &ru1); printDebug("Set u1.\n"); } //else if (vr == vru[1]) { // fmu->setReal(c, &vr, 1, &ru2); // printDebug("Set u2.\n"); //} else printf("Warning: no data given for input variable.\n"); break; case elm_Integer: fmu->setInteger(c, &vr, 1, &ix); break; case elm_Boolean: fmu->setBoolean(c, &vr, 1, &bx); break; case elm_String: printDebug("Get string in simulatio()"); fmu->setString(c, &vr, 1, &sx); break; } //End-------------------------------------------------------------------- } // Advance to next time step status = fmu->doStep(c, time, h, fmiTrue); // Terminate this row // fprintf(file, "\n"); (comment out this line to get rid of the blank line between the results in the csv file.) time = min(time+h, tEnd); //outputRow(fmu, c, time, file, separator, FALSE); // output values for this step outputdata(time, file, separator, ru1, ry1, FALSE); nSteps++; } // end of while // Cleanup fclose(file); // Print simulation summary if (loggingOn) printf("Step %d to t=%.4f\n", nSteps, time); printf("Simulation from %g to %g terminated successful\n", t0, tEnd); printf(" steps ............ %d\n", nSteps); printf(" fixed step size .. %g\n", h); return 0; // success }
/////////////////////////////////////////////////////////////////////////////// /// Output time and all non-alias variables in CSV format. /// If separator is ',', columns are separated by ',' and '.' is used for floating-point numbers. /// Otherwise, the given separator (e.g. ';' or '\t') is to separate columns, and ',' is used for /// floating-point numbers. /// ///\param fmu FMU. ///\param c FMI component. ///\param time Time when data is outputed. ///\param separator Separator in file. ///\param header Indicator of row head. /////////////////////////////////////////////////////////////////////////////// static void outputRow(FMU *fmu, fmiComponent c, double time, FILE* file, char separator, boolean header, double x, double y) { int k; fmiReal r; fmiInteger i; fmiBoolean b; fmiString s; fmiValueReference vr; ScalarVariable** vars = fmu->modelDescription->modelVariables; char buffer[32]; // Print first column if (header) fprintf(file, "time"); else { if (separator==',') fprintf(file, "%.4f", time); else { // Separator is e.g. ';' or '\t' doubleToCommaString(buffer, time); fprintf(file, "%s", buffer); } } // Print all other columns for (k=0; vars[k]; k++) { ScalarVariable* sv = vars[k]; if (getAlias(sv)!=enu_noAlias) continue; if (header) { // Output names only fprintf(file, "%c%s", separator, getName(sv)); } else { // Output values vr = getValueReference(sv); switch (sv->typeSpec->type){ case elm_Real: fmu->getReal(c, &vr, 1, &r); if (separator==',') fprintf(file, ",%.4f", r); else { // Separator is e.g. ';' or '\t' doubleToCommaString(buffer, r); fprintf(file, "%c%s", separator, buffer); } break; case elm_Integer: fmu->getInteger(c, &vr, 1, &i); fprintf(file, "%c%d", separator, i); break; case elm_Boolean: fmu->getBoolean(c, &vr, 1, &b); fprintf(file, "%c%d", separator, b); break; case elm_String: printDebug("get string in outputrow"); //fmu->getString(c, &vr, 1, &s); //fprintf(file, "%c%s", separator, s); break; } } } // for // Terminate this row fprintf(file, "\n"); }
// simulate the given FMU from tStart = 0 to tEnd. static int simulate(FMU* fmu, double tEnd, double h, fmi2Boolean loggingOn, char separator, int nCategories, const fmi2String categories[]) { double time; double tStart = 0; // start time const char *guid; // global unique id of the fmu const char *instanceName; // instance name fmi2Component c; // instance of the fmu fmi2Status fmi2Flag; // return code of the fmu functions char *fmuResourceLocation = getTempResourcesLocation(); // path to the fmu resources as URL, "file://C:\QTronic\sales" fmi2Boolean visible = fmi2False; // no simulator user interface fmi2CallbackFunctions callbacks = {fmuLogger, calloc, free, NULL, fmu}; // called by the model during simulation ModelDescription* md; // handle to the parsed XML file fmi2Boolean toleranceDefined = fmi2False; // true if model description define tolerance fmi2Real tolerance = 0; // used in setting up the experiment ValueStatus vs = 0; int nSteps = 0; Element *defaultExp; FILE* file; // instantiate the fmu md = fmu->modelDescription; guid = getAttributeValue((Element *)md, att_guid); instanceName = getAttributeValue((Element *)getCoSimulation(md), att_modelIdentifier); c = fmu->instantiate(instanceName, fmi2CoSimulation, 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"); } } defaultExp = getDefaultExperiment(md); if (defaultExp) tolerance = getAttributeDouble(defaultExp, att_tolerance, &vs); if (vs == valueDefined) { toleranceDefined = fmi2True; } fmi2Flag = fmu->setupExperiment(c, toleranceDefined, tolerance, tStart, fmi2True, tEnd); if (fmi2Flag > fmi2Warning) { return error("could not initialize model; failed FMI setup experiment"); } 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"); } // 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 } // output solution for time t0 outputRow(fmu, c, tStart, file, separator, fmi2True); // output column names outputRow(fmu, c, tStart, file, separator, fmi2False); // output values // enter the simulation loop time = tStart; while (time < tEnd) { fmi2Flag = fmu->doStep(c, time, h, fmi2True); if (fmi2Flag == fmi2Discard) { fmi2Boolean b; // check if model requests to end simulation if (fmi2OK != fmu->getBooleanStatus(c, fmi2Terminated, &b)) { return error("could not complete simulation of the model. getBooleanStatus return other than fmi2OK"); } if (b == fmi2True) { return error("the model requested to end the simulation"); } return error("could not complete simulation of the model"); } if (fmi2Flag != fmi2OK) return error("could not complete simulation of the model"); time += h; outputRow(fmu, c, time, file, separator, fmi2False); // output values for this step nSteps++; } // end simulation fmu->terminate(c); fmu->freeInstance(c); fclose(file); // 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); 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, 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 from tStart = 0 to tEnd. static int simulate(FMU* fmu, double tEnd, double h, fmiBoolean loggingOn, char separator) { double time; double tStart = 0; // start time const char* guid; // global unique id of the fmu fmiComponent c; // instance of the fmu fmiStatus fmiFlag; // return code of the fmu functions char* fmuLocation = getTempFmuLocation(); // path to the fmu as URL, "file://C:\QTronic\sales" const char* mimeType = "application/x-fmu-sharedlibrary"; // denotes tool in case of tool coupling fmiReal timeout = 1000; // wait period in milli seconds, 0 for unlimited wait period" fmiBoolean visible = fmiFalse; // no simulator user interface fmiBoolean interactive = fmiFalse; // simulation run without user interaction fmiCallbackFunctions callbacks; // called by the model during simulation ModelDescription* md; // handle to the parsed XML file int nSteps = 0; FILE* file; // instantiate the fmu md = fmu->modelDescription; guid = getString(md, att_guid); callbacks.logger = fmuLogger; callbacks.allocateMemory = calloc; callbacks.freeMemory = free; callbacks.stepFinished = NULL; // fmiDoStep has to be carried out synchronously c = fmu->instantiateSlave(getModelIdentifier(md), guid, fmuLocation, mimeType, timeout, visible, interactive, callbacks, loggingOn); free(fmuLocation); if (!c) return error("could not instantiate model"); // 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 } // StopTimeDefined=fmiFalse means: ignore value of tEnd fmiFlag = fmu->initializeSlave(c, tStart, fmiTrue, tEnd); if (fmiFlag > fmiWarning) return error("could not initialize model"); // output solution for time t0 outputRow(fmu, c, tStart, file, separator, fmiTrue); // output column names outputRow(fmu, c, tStart, file, separator, fmiFalse); // output values // enter the simulation loop time = tStart; while (time < tEnd) { fmiFlag = fmu->doStep(c, time, h, fmiTrue); if (fmiFlag != fmiOK) return error("could not complete simulation of the model"); time += h; outputRow(fmu, c, time, file, separator, fmiFalse); // output values for this step nSteps++; } // end simulation fmiFlag = fmu->terminateSlave(c); fmu->freeSlaveInstance(c); fclose(file); // 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); 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 }