modelon-community / PyFMI

PyFMI is a package for loading and interacting with Functional Mock-Up Units (FMUs) both for Model Exchange and Co-Simulation, which are compiled dynamic models compliant with the Functional Mock-Up Interface (FMI)
http://jmodelica.org/pyfmi
GNU Lesser General Public License v3.0
165 stars 37 forks source link

TypeError #259

Open YanceyYq opened 2 months ago

YanceyYq commented 2 months ago
model_sub_1 = FMUModelME2(os.path.join(me2_xml_path, "inc.fmu"))

model_sub_2 = FMUModelME2(os.path.join(me2_xml_path, "valuesreal.fmu"))

models = [("First", model_sub_1), ("Second", model_sub_2)]

connections = [(model_sub_1, "counter", model_sub_2, "real_in")]

coupled = CoupledFMUModelME2(models, connections=connections)

opts = {"CVode_options": {"rtol": 1e-6, "atol": 1e-6}, "ncp": 0}
results = coupled.simulate(options=opts)

When I execute the above code.It will display the following error.

Traceback (most recent call last):
  File "/home/yancey/Desktop/FMU/Fmu/Test/win1.0/maketest/test2/dist/fmu20/me/fmiMeincreal.py", line 63, in <module>
    results = coupled.simulate(options=opts)
  File "src/pyfmi/fmi_coupled.pyx", line 2416, in pyfmi.fmi_coupled.CoupledFMUModelME2.simulate
  File "src/pyfmi/fmi_coupled.pyx", line 139, in pyfmi.fmi_coupled.CoupledModelBase._exec_simulate_algorithm
  File "src/pyfmi/fmi_coupled.pyx", line 132, in pyfmi.fmi_coupled.CoupledModelBase._exec_simulate_algorithm
  File "/home/yancey/miniconda3/envs/Fmu/lib/python3.9/site-packages/pyfmi/fmi_algorithm_drivers.py", line 335, in __init__
    self.model.initialize()
  File "src/pyfmi/fmi_coupled.pyx", line 436, in pyfmi.fmi_coupled.CoupledFMUModelBase.initialize
  File "src/pyfmi/fmi_coupled.pyx", line 464, in pyfmi.fmi_coupled.CoupledFMUModelBase.enter_initialization_mode
  File "src/pyfmi/fmi_coupled.pyx", line 1962, in pyfmi.fmi_coupled.CoupledFMUModelME2._update_coupling_equations
  File "src/pyfmi/fmi.pyx", line 273, in pyfmi.fmi.ModelBase.set
  File "src/pyfmi/fmi.pyx", line 4520, in pyfmi.fmi.FMUModelBase2._set
  File "src/pyfmi/fmi.pyx", line 4484, in pyfmi.fmi.FMUModelBase2.set_string
TypeError: expected bytes, numpy.ndarray found

I'm sure there are no string and array types in my Fmu file, so what could be the problem?

PeterMeisrimelModelon commented 2 months ago

Can you share the modelDescription.xml for both models?

YanceyYq commented 2 months ago

inc.fmu

<?xml version="1.0" encoding="ISO-8859-1"?>
<fmiModelDescription
  fmiVersion="2.0"
  modelName="inc"
  guid="{8c4e810f-3df3-4a00-8276-176fa3c9f008}"
  numberOfEventIndicators="0">

<ModelExchange
  modelIdentifier="inc">
  <SourceFiles>
    <File name="inc.c"/>
  </SourceFiles>
</ModelExchange>

<LogCategories>
  <Category name="logAll"/>
  <Category name="logError"/>
  <Category name="logFmiCall"/>
  <Category name="logEvent"/>
</LogCategories>

<ModelVariables>
  <ScalarVariable name="counter" valueReference="0" description="counts the seconds"
                  causality="output" variability="discrete" initial="exact">
     <Integer start="1"/>
  </ScalarVariable>
</ModelVariables>

<ModelStructure>
  <Outputs>
    <Unknown index="1" />
  </Outputs>
</ModelStructure>

</fmiModelDescription>

valuesreal.fmu

<?xml version="1.0" encoding="ISO-8859-1"?>
<fmiModelDescription
  fmiVersion="2.0"
  modelName="valuesreal"
  guid="{8c4e810f-3df3-4a00-8276-176fa3c9f004}"
  numberOfEventIndicators="0">

<ModelExchange
  modelIdentifier="valuesreal">
  <SourceFiles>
    <File name="valuesreal.c"/>
  </SourceFiles>
</ModelExchange>

<LogCategories>
  <Category name="logAll"/>
  <Category name="logError"/>
  <Category name="logFmiCall"/>
  <Category name="logEvent"/>
</LogCategories>

<ModelVariables>
  <ScalarVariable name="x" valueReference="0" description="used as continuous state"
                  causality="local" variability="continuous" initial="exact">
    <Real start="1"/>
  </ScalarVariable>
  <ScalarVariable name="der(x)" valueReference="1" description="time derivative of x"
                  causality="local" variability="continuous" initial="calculated">
    <Real derivative="1"/>
  </ScalarVariable>
  <ScalarVariable name="int_in" valueReference="0" description="integer input"
                  causality="input" variability="discrete">
    <Integer start="2"/>
  </ScalarVariable>
  <ScalarVariable name="int_out" valueReference="1" description="index in string array 'month'"
                  causality="output" variability="discrete" initial="exact">
    <Integer start="0"/>
  </ScalarVariable>
  <ScalarVariable name="bool_in" valueReference="0" description="boolean input"
                  causality="input" variability="discrete">
    <Boolean start="true"/>
  </ScalarVariable>
  <ScalarVariable name="bool_out" valueReference="1" description="boolean output"
                  causality="output" variability="discrete" initial="exact">
    <Boolean start="false"/>
  </ScalarVariable>
  <ScalarVariable name="real_in" valueReference="0" description="real input"
                  causality="input" variability="discrete">
    <String start="0"/>
  </ScalarVariable>
  <ScalarVariable name="real_out" valueReference="1" description="real output"
                  causality="output" variability="continuous" initial="exact">
    <String start="0"/>
  </ScalarVariable>
</ModelVariables>

<ModelStructure>
  <Outputs>
    <Unknown index="4" />
    <Unknown index="6" />
    <Unknown index="8" />
  </Outputs>
  <Derivatives>
    <Unknown index="2" />
  </Derivatives>
  <InitialUnknowns>
    <Unknown index="2"/>
  </InitialUnknowns>
</ModelStructure>

</fmiModelDescription>
PeterMeisrimelModelon commented 2 months ago

real_in in valuesreal.fmu is a String variable.

While it maybe shouldn't fail exactly in the part of the code where is does fail, this is still the same problem as in https://github.com/modelon-community/PyFMI/issues/256.

/Peter

YanceyYq commented 2 months ago

I have already changed the relevant types to real in the .c file.Do I need to modify all the related content in modelDescription.xml as well?

PeterMeisrimelModelon commented 2 months ago

Yes, if not for the modelDescription.xml, how else would an FMU Import tool like PyFMI know the type of a given variable?

YanceyYq commented 2 months ago

The revised modelDescription.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<fmiModelDescription
  fmiVersion="2.0"
  modelName="valuesreal"
  guid="{8c4e810f-3df3-4a00-8276-176fa3c9f004}"
  numberOfEventIndicators="0">

<ModelExchange
  modelIdentifier="valuesreal">
  <SourceFiles>
    <File name="valuesreal.c"/>
  </SourceFiles>
</ModelExchange>

<LogCategories>
  <Category name="logAll"/>
  <Category name="logError"/>
  <Category name="logFmiCall"/>
  <Category name="logEvent"/>
</LogCategories>

<ModelVariables>
  <ScalarVariable name="x" valueReference="0" description="used as continuous state"
                  causality="local" variability="continuous" initial="exact">
    <Real start="1"/>
  </ScalarVariable>
  <ScalarVariable name="der(x)" valueReference="1" description="time derivative of x"
                  causality="local" variability="continuous" initial="calculated">
    <Real derivative="1"/>
  </ScalarVariable>
  <ScalarVariable name="real_in" valueReference="0" description="real input"
                  causality="input" variability="continuous">
    <Real start="0"/>
  </ScalarVariable>
  <ScalarVariable name="real_out" valueReference="1" description="real output"
                  causality="output" variability="continuous" initial="exact">
    <Real start="0"/>
  </ScalarVariable>
  <ScalarVariable name="bool_in" valueReference="0" description="boolean input"
                  causality="input" variability="discrete">
    <Boolean start="true"/>
  </ScalarVariable>
  <ScalarVariable name="bool_out" valueReference="1" description="boolean output"
                  causality="output" variability="discrete" initial="exact">
    <Boolean start="false"/>
  </ScalarVariable>
  <ScalarVariable name="string_in" valueReference="0" description="string input"
                  causality="input" variability="discrete">
    <String start="QTronic"/>
  </ScalarVariable>
  <ScalarVariable name="string_out" valueReference="1" description="the string month[int_out]"
                  causality="output" variability="discrete" initial="exact">
    <String start="jan"/>
  </ScalarVariable>
</ModelVariables>

<ModelStructure>
  <Outputs>
    <Unknown index="4" />
    <Unknown index="6" />
    <Unknown index="8" />
  </Outputs>
  <Derivatives>
    <Unknown index="2" />
  </Derivatives>
  <InitialUnknowns>
    <Unknown index="2"/>
  </InitialUnknowns>
</ModelStructure>

</fmiModelDescription>

error:

Traceback (most recent call last):
  File "/home/yancey/Desktop/FMU/Fmu/Test/win1.0/maketest/test3/dist/fmu20/me/fmiMeincreal.py", line 46, in <module>
    model_sub_2 = FMUModelME2(os.path.join(me2_xml_path, "valuesreal.fmu"))
  File "src/pyfmi/fmi.pyx", line 7613, in pyfmi.fmi.FMUModelME2.__init__
  File "src/pyfmi/fmi.pyx", line 4106, in pyfmi.fmi.FMUModelBase2.__init__
pyfmi.fmi.InvalidXMLException: The FMU could not be loaded. The model data from 'modelDescription.xml' within the FMU could not be read. Parse error at line 69:
parsing aborted

I checked that the syntax of modelDescription.xml is correct.

PeterMeisrimelModelon commented 2 months ago

Did you check the log? There is quite a number of issues here:

[ERROR][FMI2XML] Only one variable among non constant aliases is allowed to have start attribute (variables: real_in and x) 4, 4, const enum value: 0
[ERROR][FMI2XML] Removing incorrect alias variable 'real_in'
[ERROR][FMI2XML] Removing incorrect alias variable 'x'
[INFO][FMI2XML] [Line:61] Detected during parsing:
[ERROR][FMI2XML] The index attribute must have a value between 1 and the number of model variables.
[INFO][FMI2XML] [Line:64] Detected during parsing:
[ERROR][FMI2XML] The state derivative 'real_out' does not specify the state variable that it is a derivative of.
[FATAL][FMI2XML] Model structure is not valid due to detected errors. Cannot continue.
[FATAL][FMI2XML] Parse error at line 69:

(from parsing with fmi-library directly)

These will need to be addressed.

YanceyYq commented 2 months ago

How was this log obtained?

PeterMeisrimelModelon commented 2 months ago

This is from parsing the modelDescription.xml directly using fmi-library (via the import API in C).

Normally, PyFMI does create .txt logs with the log output from loading the model via fmi-library, however this does not happen if parsing the modelDescription.xml fails. In that case you only get the latest error.

This could be improved in PyFMI.

YanceyYq commented 2 months ago

Can you provide an example of parsing?

PeterMeisrimelModelon commented 2 months ago
#include <stdio.h>
#include "fmilib.h"

int main(int argc, char **argv) {
    fmi_import_context_t *ctx = fmi_import_allocate_context(jm_get_default_callbacks());
    fmi2_import_t* xml = fmi2_import_parse_xml(ctx, ".", NULL);
    fmi2_import_free(xml);
}

(assuming you modelDescription.xml is in the same folder)

See also tests in fmi-library.

YanceyYq commented 2 months ago
fmi2_import_t * importedModel = fmi2_import_parse_xml(ctx, xmlPath.toStdString().c_str(), NULL);

How to get the error message?

PeterMeisrimelModelon commented 2 months ago

They should print to stdout.

YanceyYq commented 2 months ago

when importedModel = 0x0,The console has no information at all.

PeterMeisrimelModelon commented 2 months ago

Are you sure you are passing in the path to the modelDescription.xml correctly? Try to use some simple but valid modelDescription.xml.

With parsing errors it is expected that importedModel result is NULL. There will still be output.

YanceyYq commented 2 months ago

I'm sure the file path is correct. Is there a way to print the logs of parsing the xml to a file?

PeterMeisrimelModelon commented 2 months ago

Have you tried with a known valid modelDescription.xml?

The context input ctx contains the callbacks to used for e.g., the logger. The standard logger if using printf, but you could set it to something else, e.g., writing to file.

YanceyYq commented 2 months ago

Yes, I have tried with a known valid modelDescription.xml。The console still has no log information.

PeterMeisrimelModelon commented 2 months ago

Can you share your code for that? Also what fmi-library version?

YanceyYq commented 2 months ago
    QString xmlPath = QFileDialog::getOpenFileName(this, tr("Open XML File"), "", tr("XML Files (*.xml)"));

    fmi_import_context_t * ctx = fmi_import_allocate_context(jm_get_default_callbacks());

    const char * xmlPathCStr = xmlPath.toStdString().c_str();

    fmi2_import_t * importedModel = fmi2_import_parse_xml(ctx, xmlPathCStr, NULL);

fmi-library version = 3.0a3

PeterMeisrimelModelon commented 2 months ago

Can you try a minimal pure C code with a hardcoded path? The default logger is simply printf, can you verify that in whatever environment you are using here, that you see printfoutput?

/Peter

YanceyYq commented 2 months ago
<?xml version="1.0" encoding="UTF-8"?>
<fmiModelDescription
  fmiVersion="2.0"
  modelName="valuesreal"
  guid="{8c4e810f-3df3-4a00-8276-176fa3c9f004}"
  numberOfEventIndicators="0">

  <!-- Model Exchange details -->
  <ModelExchange
    modelIdentifier="valuesreal">
    <SourceFiles>
      <File name="valuesreal.c"/>
    </SourceFiles>
  </ModelExchange>

  <LogCategories>
    <Category name="logAll"/>
    <Category name="logError"/>
    <Category name="logFmiCall"/>
    <Category name="logEvent"/>
  </LogCategories>

  <ModelVariables>
    <!-- State variable 'x' -->
    <ScalarVariable name="x" valueReference="0" description="used as continuous state"
                    causality="local" variability="continuous" initial="exact">
      <Real start="1"/>
    </ScalarVariable>
    <!-- Derivative variable for 'x' -->
    <ScalarVariable name="der(x)" valueReference="1" description="time derivative of x"
                    causality="local" variability="continuous" initial="calculated">
      <Real derivative="1"/> <!-- Corrected to reference the valueReference of 'x' -->
    </ScalarVariable>
    <!-- Input variable 'real_in' -->
    <ScalarVariable name="real_in" valueReference="2" description="real input"
                    causality="input" variability="continuous">
      <Real start="0"/>
    </ScalarVariable>
    <!-- Output variable 'real_out' -->
    <ScalarVariable name="real_out" valueReference="3" description="real output"
                    causality="output" variability="continuous" initial="calculated">
      <Real/>
    </ScalarVariable>
    <!-- Boolean input variable 'bool_in' -->
    <ScalarVariable name="bool_in" valueReference="4" description="boolean input"
                    causality="input" variability="discrete">
      <Boolean start="true"/>
    </ScalarVariable>
    <!-- Boolean output variable 'bool_out' -->
    <ScalarVariable name="bool_out" valueReference="5" description="boolean output"
                    causality="output" variability="discrete" initial="exact">
      <Boolean start="false"/>
    </ScalarVariable>
    <!-- String input variable 'string_in' -->
    <ScalarVariable name="string_in" valueReference="6" description="string input"
                    causality="input" variability="discrete">
      <String start="QTronic"/>
    </ScalarVariable>
    <!-- String output variable 'string_out' -->
    <ScalarVariable name="string_out" valueReference="7" description="the string output"
                    causality="output" variability="discrete" initial="exact">
      <String start="January"/> <!-- Corrected the start value for clarity -->
    </ScalarVariable>
  </ModelVariables>

  <ModelStructure>
    <Outputs>
      <Unknown index="3"/>
      <Unknown index="5"/>
      <Unknown index="7"/>
    </Outputs>
    <Derivatives>
      <Unknown index="1"/>
    </Derivatives>
    <InitialUnknowns>
      <Unknown index="0"/>
    </InitialUnknowns>
  </ModelStructure>

</fmiModelDescription>

How should I modify this modelDescription.xml to fix these two errors?I don't quite understand the causes of these two errors.

[ERROR][FMI2XML] The state derivative 'x' does not specify the state variable that it is a derivative of.
[ERROR][FMI2XML] The index attribute must have a value between 1 and the number of model variables.
PeterMeisrimelModelon commented 2 months ago

Specification:

The “ModelVariables” element consists of an ordered set of “ScalarVariable” elements (see figure above). The first element has index = 1, the second index=2, etc.

<Unknown index="1"/>, index 1 points to<!-- State variable 'x' -->, which does not have a derivative attribute.

<Unknown index="0"/>: Indexing is 1 based, 0 is not valid.

YanceyYq commented 2 months ago

When the modelDescription.xml is parsed successfully. Execute the code:

results = coupled.simulate(options=opts)

An error occurs:

FMIL: module = Model, log level = 2: [logError][FMU status:Error] fmi2SetReal: Illegal value reference 2.

What is this error related to?

PeterMeisrimelModelon commented 2 months ago

Since you appear to be hand-crafting your FMUs, did you change your C code in accordance with the value reference changes in the modelDescription?

YanceyYq commented 2 months ago
/* ---------------------------------------------------------------------------*
 * Sample implementation of an FMU.
 * This demonstrates the use of all FMU variable types.
 * Copyright QTronic GmbH. All rights reserved.
 * ---------------------------------------------------------------------------*/

// define class name and unique id
#define MODEL_IDENTIFIER values
#define MODEL_GUID "{8c4e810f-3df3-4a00-8276-176fa3c9f004}"

// define model size
#define NUMBER_OF_REALS 2
#define NUMBER_OF_INTEGERS 2
#define NUMBER_OF_BOOLEANS 2
#define NUMBER_OF_STRINGS 2
#define NUMBER_OF_STATES 1
#define NUMBER_OF_EVENT_INDICATORS 0

// include fmu header files, typedefs and macros
#include "fmuTemplate.h"

// define all model variables and their value references
// conventions used here:
// - if x is a variable, then macro x_ is its variable reference
// - the vr of a variable is its index in array  r, i, b or s
// - if k is the vr of a real state, then k+1 is the vr of its derivative
#define x_          0
#define der_x_      1
#define real_in_    0
#define real_out_   0
#define bool_in_    0
#define bool_out_   1
// define state vector as vector of value references
#define STATES { x_ }

// called by fmi2Instantiate
// Set values for all variables that define a start value
// Settings used unless changed by fmi2SetX before fmi2EnterInitializationMode
void setStartValues(ModelInstance *comp) {
    r(x_) = 1;
    r(real_in_) =  0;
    r(real_out_) = 0;
    b(bool_in_) = fmi2True;
    b(bool_out_) = fmi2False;
}

// called by fmi2GetReal, fmi2GetInteger, fmi2GetBoolean, fmi2GetString, fmi2ExitInitialization
// if setStartValues or environment set new values through fmi2SetXXX.
// Lazy set values for all variable that are computed from other variables.
void calculateValues(ModelInstance *comp) {
    if (comp->state == modelInitializationMode) {
        // set first time event
        comp->eventInfo.nextEventTimeDefined = fmi2True;
        comp->eventInfo.nextEventTime        = 1 + comp->time;
    }
}

// called by fmi2GetReal, fmi2GetContinuousStates and fmi2GetDerivatives
fmi2Real getReal(ModelInstance *comp, fmi2ValueReference vr){
    switch (vr) {
        case x_     : return   r(x_);
        case der_x_ : return - r(x_);
        default: return 0;
    }
}

// used to set the next time event, if any.
void eventUpdate(ModelInstance *comp, fmi2EventInfo *eventInfo, int isTimeEvent, int isNewEventIteration) {
    if (isTimeEvent) {
        eventInfo->nextEventTimeDefined = fmi2True;
        eventInfo->nextEventTime        = 1 + comp->time;
        r(real_out_) = r(real_in_);
        b(bool_out_) = !b(bool_out_);
        if (r(real_out_) >= 12)
    {   
          eventInfo->terminateSimulation = fmi2True;
    }
    }
}

// include code that implements the FMI based on the above definitions
#include "fmuTemplate.c"

real_out and real_in have been changed from int type.

PeterMeisrimelModelon commented 2 months ago

I am sorry, but I am not going to debug your FMU code for you.

This is issue has gone way beyond the scope of PyFMI support already.

YanceyYq commented 2 months ago

I'm providing the code to illustrate that:i changed my C code in accordance with the value reference changes in the modelDescription。

PeterMeisrimelModelon commented 2 months ago

The error message is generated from the FMU though, which is your code, respectively whatever template/library/example you are using/modifying.