2. Compilation

Compiling a model is done with just a few steps; importing a compiler function from the JModelica.org Python package pymodelica, specifying a model class and file location and performing the actual compilation. This will be demonstrated in Section 2.1 for the JMU, in Section 2.2 for the FMU and in Section 2.3 for the FMUX.

For more advanced usage of the compiler functions, there are compiler options and parameters which can be modified. These will be explained in Section 2.5.

Section 2.6, will go through some parts of the compilation process and how to perform these steps one by one.

2.1. Simple JMU compilation example

The following steps compiles a model to a JMU in the JModelica.org Python interface:

  1. Import the JModelica.org compiler function compile_jmu from the package pymodelica.

  2. Specify the model and model file.

  3. Perform the compilation.

This is demonstrated in the following code example.

# Import the compiler function
from pymodelica import compile_jmu

# Specify Modelica model and model file
model_name = 'myPackage.myModel'
mo_file = 'myPackage.mo'

# Compile the model, return argument is the file name of the JMU
compile_jmu(model_name, mo_file)
>> '.\\myPackage_myModel.jmu'

Once compilation has completed successfully a JMU file will have been created on the file system. The JMU file is essentially a compressed file archive containing files created during compilation that are needed when instantiating a model object. Return argument for compile_jmu is the full file path of the JMU that has just been created, this will be useful later when we want to create model objects. More about the JMU file and loading models can be found in Section 3.

In the above example, compilation has been performed with default parameters and options. The only parameters specified are the model class name and file. compile_jmu has several other parameters which can be modified. The different parameters, their default values and interpretation will be explained in Section 2.5.

2.2. Simple FMU compilation example

The steps required to compile a model to an FMU is very similar to compiling a model to a JMU:

  1. Import the JModelica.org compiler function compile_fmu from the package pymodelica.

  2. Specify the model and model file.

  3. Perform the compilation.

The only difference is really the requirement on the model, it must be a pure Modelica model. The following code example demonstrates how to compile an FMU.

# Import the compiler function
from pymodelica import compile_fmu

# Specify Modelica model and model file
model_name = 'myPackage.myModel'
mo_file = 'myPackage.mo'

# Compile the model, return argument is the file name of the FMU
compile_fmu(model_name, mo_file)
>> '.\\myPackage_myModel.fmu'

As in the JMU case, when the compilation has completed successfully an FMU file will have been created on the file system. The return argument is also the full file path of the FMU that has just been created, which will be useful later when we want to create model objects. More about the FMU file and loading models can be found in Section 3.

2.3. Simple FMUX compilation example

Compiling an FMUX follows the same principle as compiling a JMU and an FMU.

  1. Import the JModelica.org compiler function compile_fmux from the package pymodelica.

  2. Specify the model and model file.

  3. Perform the compilation.

The Python code example below will perform these steps.

# Import the compiler function
from pymodelica import compile_fmux

# Specify Modelica model and model file
model_name = 'myPackage.myModel'
mo_file = 'myPackage.mo'

# Compile the model, return argument is the file name of the FMUX
compile_fmux(model_name, mo_file)
>> '.\\myPackage_myModel.fmux'

2.4. Compiling from libraries

The model to be compiled might not be in a loose .mo file, but rather part of a library consisting of a directory structure containing several Modelica files. In this case, the file within the library that contains the model should not be given on the command line. Instead, the entire library should to added to the list of libraries the compiler searches for classes in. This can be done in several ways (here library directory refers to the top directory of the library, that should have the same name as the top package in the library):

  • Adding the directory containing the library directory to the environment variable MODELICAPATH. The compiler will search for classes in all libraries found in any on the directories in MODELICAPATH. In this case the file_name argument of the compilation function can be omitted, assuming no additional Modelica files are needed.

  • Setting the 'extra_lib_dirs' compiler option to the path to the directory containing the library directory. This is equivalent to adding it to the MODELICAPATH, but only for that compilation.

  • Giving the path to the library directory in the file_name argument of the compilation function. This allows adding a specific library to the search list (as opposed to adding all libraries in a specific directory).

By default, the script starting a JModelica.org Python shell sets the MODELICAPATH to the directory containing the version of the Modelica Standard Library (MSL) that is included in the installation. Thus, all classes in the MSL are available without any need to specify its location.

The Python code example below demonstrates these methods:

# Import the compiler function
from pymodelica import compile_fmu

# Compile an example model from the MSL
fmu1 = compile_fmu('Modelica.Mechanics.Rotational.Examples.First')

# Compile a model from the library MyLibrary, located in C:\MyLibs
fmu2 = compile_fmu('MyLibrary.MyModel', compiler_options = {'extra_lib_dirs':'C:\MyLibs'})

# The same as the last command, if no other libraries in C:\MyLibs are needed
fmu3 = compile_fmu('MyLibrary.MyModel', 'C:\MyLibs\MyLibrary')

2.5. Compiler settings

The compiler function parameters can be listed with the interactive help in Python. The parameters are explained in the corresponding Python docstring which is visualized with the interactive help. This is demonstrated in the code examples below.

The parameter target, is further explained in Section 2.5.5, Section 2.5.6 and Section 2.5.7.

2.5.1. compile_jmu parameters

The compile_jmu parameters can be listed with the interactive help.

# Display the docstring for compile_jmu with the Python command 'help'
from pymodelica import compile_jmu
help(compile_jmu)
Help on function compile_jmu in module pymodelica.compiler:

compile_jmu(class_name, file_name=[], compiler='auto', target='ipopt', compiler_options={}, 
            compile_to='.', compiler_log_level='warning')
    Compile a Modelica or Optimica model to a JMU.

    A model class name must be passed, all other arguments have default values.
    The different scenarios are:

    * Only class_name is passed:
        - Class is assumed to be in MODELICAPATH.
        - Default compiler is ModelicaCompiler.
    
    * class_name and file_name is passed:
        - file_name can be a single path as a string or a list of paths 
          (strings). The paths can be for files or libraries
        - Default compiler setting is 'auto' which means that the appropriate
          compiler will be selected based on model file ending, i.e.
          ModelicaCompiler if .mo file and OptimicaCompiler if a .mop file is
          found in file_name list.

    Library directories can be added to MODELICAPATH by listing them in a
    special compiler option 'extra_lib_dirs', for example:

        compiler_options =
            {'extra_lib_dirs':['c:\MyLibs1','c:\MyLibs2']}

    Other options for the compiler should also be listed in the compiler_options
    dict.

    The compiler target is 'ipopt' by default which means that libraries for AD
    and optimization/initialization algortihms will be available as well as the
    JMI. The other targets are:

        'model' --
            AD and JMI is included.
        'algorithm' --
            AD and algorithm but no Ipopt linking.
        'model_noad' --
            Only JMI, that is no AD interface. (Must currently be used when
            model includes external functions.)

    Parameters::

        class_name --
            The name of the model class.

        file_name --
            A path (string) or paths (list of strings) to model files and/or 
            libraries. Supports both be .mo and .mop files.
            Default: Empty list.

        compiler --
            'auto' if a compiler should be selected automatically depending on
            file ending, 'modelica' if a ModelicaCompiler should be used or
            'optimica' if a OptimicaCompiler should be used.
            Default: 'auto' (i.e. depends on argument file_name)

        target --
            Compiler target. 'model', 'algorithm', 'ipopt' or 'model_noad'.
            Default: 'ipopt'

        compiler_options --
            Options for the compiler.
            Default: Empty dict.

        compile_to --
            Specify location of the compiled JMU. Directory will be created if
            it does not exist.
            Default: Current directory.

        compiler_log_level --
            Set the log level for the compiler. Valid options are 'warning'/'w',
            'error'/'e' or 'info'/'i'.
            Default: 'warning'

    Returns::

        Name of the JMU which has been created.

2.5.2. compile_fmu parameters

The compile_fmu parameters can be listed with the interactive help.

# Display the docstring for compile_fmu with the Python command 'help'
from pymodelica import compile_fmu
help(compile_fmu)
Help on function compile_fmu in module pymodelica.compiler:

compile_fmu(class_name, file_name=[], compiler='modelica', target='model_fmume', 
            compiler_options={}, compile_to='.', compiler_log_level='warning')
    Compile a Modelica model to an FMU.

    A model class name must be passed, all other arguments have default values.
    The different scenarios are:

    * Only class_name is passed:
        - Class is assumed to be in MODELICAPATH.

    * class_name and file_name is passed:
        - file_name can be a single path as a string or a list of paths 
          (strings). The paths can be to files or libraries
    
    Library directories can be added to MODELICAPATH by listing them in a 
    special compiler option 'extra_lib_dirs', for example:
    
        compiler_options = 
            {'extra_lib_dirs':['c:\MyLibs1','c:\MyLibs2']}
        
    Other options for the compiler should also be listed in the compiler_options 
    dict.
    
    The compiler target is 'model_fmume' by default which means that the shared 
    file contains the FMI for Model Exchange API. This is currently the only 
    target that is possible to use.
    
    Parameters::
    
        class_name -- 
            The name of the model class.
            
        file_name -- 
            A path (string) or paths (list of strings) to model files and/or 
            libraries. Supports only be .mo files.
            Default: Empty list.
            
        compiler -- 
            The compiler used to compile the model. Currently, only ModelicaCompiler 
            can be used.
            Default: 'modelica'

        target --
            Compiler target.
            Default: 'model_fmume'

        compiler_options --
            Options for the compiler.
            Default: Empty dict.

        compile_to --
            Specify location of the compiled FMU. Directory will be created if
            it does not exist.
            Default: Current directory.

        compiler_log_level --
            Set the log level for the compiler. Valid options are 'warning'/'w',
            'error'/'e' or 'info'/'i'.
            Default: 'warning'

    Returns::

        Name of the FMU which has been created.

2.5.3. compile_fmux parameters

The compile_fmux parameters can be listed with the interactive help.

# Display the docstring for compile_fmux with the Python command 'help'
from pymodelica import compile_fmux
help(compile_fmux)
Help on function compile_fmux in module pymodelica.compiler:

compile_fmux(class_name, file_name=[], compiler='auto', compiler_options={}, compile_to='.', 
             compiler_log_level='warning')
    Compile a Modelica model to an FMUX.

    A model class name must be passed, all other arguments have default values.
    The different scenarios are:

    * Only class_name is passed:
        - Class is assumed to be in MODELICAPATH.

    * class_name and file_name is passed:
        - file_name can be a single path as a string or a list of paths 
          (strings). The paths can be to files or libraries
    
    Library directories can be added to MODELICAPATH by listing them in a 
    special compiler option 'extra_lib_dirs', for example:
    
        compiler_options = 
            {'extra_lib_dirs':['c:\MyLibs1','c:\MyLibs2']}
        
    Other options for the compiler should also be listed in the compiler_options 
    dict.
    
    
    Parameters::
    
        class_name -- 
            The name of the model class.
            
        file_name -- 
            A path (string) or paths (list of strings) to model files and/or 
            libraries. Supports both be .mo and .mop files.
            Default: Empty list.

        compiler --
            The compiler used to compile the model.
            Default: 'auto'

        compiler_options --
            Options for the compiler.
            Default: Empty dict.

        compile_to --
            Specify location of the compiled FMUX. Directory will be created if
            it does not exist.
            Default: Current directory.

        compiler_log_level --
            Set the log level for the compiler. Valid options are 'warning'/'w',
            'error'/'e' or 'info'/'i'.
            Default: 'warning'

    Returns::

        Name of the FMUX which has been created.

2.5.4. Compiler options

Compiler options are read from an XML file, options.xml, which can be found in the JModelica.org installation folder under the folder Options. The options are loaded from the file when a compiler is created, that is when compile_jmu, compile_fmu or compile_fmux is run. Options for a compiler instance can be modified interactively when compiling using the parameter compiler_options. This is shown in an example compiling an Optimica model below.

# Compile with the compiler option 'enable_variable_scaling' set to True

# Specify Optimica model and model file
model_name = 'myPackage.myModel'
mo_file = 'myPackage.mop'

compile_jmu(model_name, mo_file, compiler_options={"enable_variable_scaling":True})

There are four type categories: string, real, integer and boolean. The available options, default values and description are listed in Table 4.1.

Table 4.1. Compiler options

Option Default Description
normalize_minimum_time_problems true When this option is set to true then minimum time optimal control problems encoded in Optimica are converted to fixed interval problems by scaling of the derivative variables. (Boolean option.)
enable_variable_scaling false If this option is true, then the "nominal" attribute will be used to scale variables in the model. (Boolean option.)
halt_on_warning false If this option is set to false one or more compiler warnings will not stop compilation of the model. (Boolean option.)
automatic_add_initial_equations true When this option is set to true, then additional initial equations are added to the model based on a the result of a matching algorithm. Initial equations are added for states that are not matched to an equation. (Boolean option.)
generate_ode_jacobian false If this option is set to true, code for computing ODE Jacobians are generated. (Boolean option.)
eliminate_alias_variables true If this option is true, then alias variables are eliminated from the model. (Boolean option.)
extra_lib_dirs "" The value of this option is appended to the value of the MODELICAPATH environment variable for determining in what directories to search for libraries. (String option.)
generate_xml_equations false If this option is true, then model equations are generated in XML format. (Boolean option.)
state_start_values_fixed false This option enables the user to specify if initial equations should be generated automatically for differentiated variables even though the fixed attribute is equal to fixed. Setting this option to true is, however, often practical in optimization problems. (Boolean option.)
equation_sorting false If this option is true, equations are sorted using the BLT algorithm. (Boolean option.)
index_reduction true If this option is true, index reduction is performed. (Boolean option.)
enable_structural_diagnosis true Enable this option to invoke the structural error diagnosis based on the matching algorithm. (Boolean option.)
compliance_as_warning false When this option is set to true, then compliance errors are treated as warnings instead. This can lead to the compiler or solver crashing. Use with caution! (Boolean option.)
generate_html_diagnostics false When this option is set to true model diagnostics is generated in HTML format. This includes the flattened model, connection sets, alias sets and BLT form. (Boolean option.)
generate_ode false If this option is set to true, code for solving ODEs is generated. (Boolean option.)
convert_free_dependent_ parameters_to_algebraics true If this option is true, free dependent parameters are converted to algebraic variables. (Boolean option.)
generate_dae true If this option is true, code for solving DAEs is generated. (Boolean option.)
generate_dae_jacobian false If this option is true, code for computing DAE Jacobians is generated. (Boolean option.)
export_functions false Export used Modelica functions to generated C code in a manner that is compatible with the external C interface in the Modelica Language Specification. (Boolean option.)
export_functions_vba false If this option is true, then VBA-compatible wrappers for exported functions are created. Requires export_functions = true. (Boolean option.)
generate_fmi_cs_xml false If this option is true the model description part of the XML variables file will be FMI for co simulation compliant. To generate an XML which will validate with FMI schema the option generate_xml_equations must also be false.
divide_by_vars_in_tearing false If this option is set to true, a less restrictive strategy is used for solving equations in the tearing algorithm. Specifically, division by parameters and variables is permitted, by default no such divisions are made during tearing.
enable_tearing false If this option is set to true, tearing of equation systems is enabled.
generate_fmi_me_xml false If this option is true the model description part of the XML variables file will be FMI for model exchange compliant. To generate an XML which will validate with FMI schema the option generate_xml_equations must also be false.
inline_functions false Perform function inlining on model after flattening.
fmi_version 1.0 FMI version to use in compilation.


2.5.5. Compiler targets for compile_jmu

There are four compiler targets available for compile_jmu:

  • ipopt: Compiled model will include JMI interface, AD and linking to Ipopt libraries. There is support for optimization and initialization algorithm.

  • model: Compiled model will include support for JMI interface and AD.

  • algorithm: Compiled model will include support for JMI interface. AD and algorithm but not link with the Ipopt libraries.

  • model_noad: Compiled model will only include the JMI interface.

The compiler target is 'ipopt' by default which will work for most cases. However, if JModelica.org has been built without Ipopt libraries the target would have to be changed to any other suitable target that does not include the Ipopt libraries.

The target model_noad must be used if the model contains external equations since external equations do not work with the AD interface at the moment.

2.5.6. Compiler targets for compile_fmu

Currently, the only possible target available for compile_fmu is 'model_fmume'. With this target the compiled model will include the FMI for Model Exchange API.

2.5.7. Compiler targets for compile_fmux

Compiler targets are not relevant for compile_fmux since no binary file is compiled.

2.6. Compilation in more detail

Compiling with compile_jmu, compile_fmu or compile_fmux bundles quite a few steps required for the compilation from model file to JMU, FMU or FMUX. Some of these steps will be described briefly here, for a more detailed review on the compilation steps see Section 4 in Chapter 1.

2.6.1. Create a compiler

A compiler, can be either a Modelica or Optimica compiler, is created by importing the Python classes from the compiler module. The compiler constructors only has optional arguments. These are the paths to the template XML and C files which in most cases can be left to the default values. (Note that in the compile_fmux case the only template needed is to the Model description XML template file since no C code is produced.) This example code will create a Modelica compiler.

# import the class ModelicaCompiler from the compiler module
from pymodelica.compiler import ModelicaCompiler

# create a compiler instance
mc = ModelicaCompiler()

2.6.2. Source tree generation and flattening

In the first step of the compilation, the model is parsed and instantiated. Then the model is transformed into a flat representation which can be used to generate C and XML code. If there are errors in the model, for example syntax or type errors, Python exceptions will be thrown during these steps.

# Parse the model and get a reference to the source root
source_root = mc.parse_model('myPackage.mo')

# Generate an instance tree representation and get a reference to the model instance
model_instance = mc.instantiate_model(source_root, 'myPackage.myModel')

# Perform flattening and get a flat representation
flat_rep = mc.flatten_model(model_instance)

2.6.3. Code generation

The next step is the code generation which produces C code containing the model equations and a couple of XML files containing model meta data such as variable names and types and parameter values. Note that in the compile_fmux case, only XML code is generated in this step.

# Generate code
mc.generate_code(flat_rep)