Beispiel #1
0
// 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
}
Beispiel #2
0
// 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
}