How to add custom OpenMDAO modules to FAST-OAD

With FAST-OAD, you can register any OpenMDAO system of your own so it can be used through the configuration file.

It is therefore strongly advised to have at least a basic knowledge of OpenMDAO to develop a module for FAST-OAD.

To have your OpenMDAO system available as a FAST-OAD module, you should follow these steps:

Create your OpenMDAO system

It can be a Group or a Component-like class (generally an ExplicitComponent).

You can create the Python file at the location of your choice. You will just have to provide later the folder path in FAST-OAD configuration file (see Modify the configuration file).

Variable naming

You have to pay attention to the naming of your input and output variables. As FAST-OAD uses the promotion system of OpenMDAO, which means that variables you want to link to the rest of the process must have the name that is given in the global process.

Nevertheless, you can create new variables for your system:

  • Outputs of your system will be available in output file and will be usable as any other variable.

  • Unconnected inputs will simply have to be in the input file of the process. They will be automatically included in the input file generated by FAST-OAD (see How to generate an input file).

  • And if you add more than one system to the FAST-OAD process, outputs created by one of your system can of course be used as inputs by other systems.

Also keep in mind that the naming of your variable will decide of its location in the input and output files. Therefore, the way you name your new variables should be consistent with FAST-OAD convention, as explained in Problem variables.

Defining options

You may use the OpenMDAO way for adding options to your system. The options you add will be accessible from the FAST-OAD configuration file (see Problem definition).

When declaring an option, the usage of the desc field if strongly advised, as any description you provide will be printed along with module information with the list_modules sub-command (see How to get list of registered modules).

Definition of partial derivatives

Your OpenMDAO system is expected to provide partial derivatives for all its outputs in analytic or approximate way.

At the very least, for most Component classes, the setup() method of your class should contain:

self.declare_partials("*", "*", method='fd')

or for a Group class:

self.approx_totals()

The two lines above are the most generic and the least CPU-efficient ways of declaring partial derivatives. For better efficiency, see how to work with derivatives in OpenMDAO.

About ImplicitComponent classes

In some cases, you may have to use ImplicitComponent classes.

Just remember, as told in this tutorial, that the loop that will allow to solve it needs usage of the NewtonSolver.

A good way to ensure it is to build a Group class that will solve the ImplicitComponent with NewtonSolver. This Group should be the system you will register in FAST-OAD.

Checking validity domains

Generally, models are valid only when variable values are in given ranges.

OpenMDAO provides a way to specify lower and upper bounds of an output variable and to enforce them when using a Newton solver by using backtracking line searches.

FAST-OAD proposes a way to set lower and upper bounds for input and output variables, but only for checking and giving feedback of variables that would be out of bounds.

If you want your OpenMDAO class to do this checking, simply use the decorator ValidityDomainChecker:

@ValidityDomainChecker
class MyComponent(om.ExplicitComponent):
    def setup(self):
        self.add_input("length", 1., units="km" )
        self.add_input("time", 1., units="h" )
        self.add_output("speed", 1., units="km/h", lower=0., upper=130.)

The above code make that FAST-OAD will issue a warning if at the end of the computation, “speed” variable is not between lower and upper bound.

But it is possible to set your own bounds outside of OpenMDAO by following this example:

@ValidityDomainChecker(
    {
        "length": (0.1, None),  # Defines only a lower bound
        "time": (0., 1.),  # Defines lower and upper bounds
        "speed": (None, 150.0),  # Ignores original bounds and sets only upper bound
    }
)
class MyComponent(om.ExplicitComponent):
    def setup(self):
        self.add_input("length", 1., units="km" )
        self.add_input("time", 1., units="h" )
        # Bounds that are set here will still apply if backtracking line search is used, but
        # will not be used for validity domain checking because it has been replaced above
        self.add_output("speed", 1., units="km/h", lower=0., upper=130.)

Register your system(s)

Once your OpenMDAO system is ready, you have to register it to make it known as a FAST-OAD module.

To do that, you just have to add the RegisterOpenMDAOSystem decorator to your OpenMDAO class like this:

import fastoad.api as oad
import openmdao.api as om

@oad.RegisterOpenMDAOSystem("my.custom.name")
class MyOMClass(om.ExplicitComponent):
    [ ... ]

Note

If you work with Jupyter notebook, remember that any change in your Python files will require the kernel to be restarted.

Modify the configuration file

The folders that contain your Python files must be listed in module_folders in the FAST-OAD configuration file:

title: OAD Process with custom component

# List of folder paths where user added custom registered OpenMDAO components
module_folders:
  - /path/to/my/custom/module/folder
  - /another/path/

[ ... ]

Once this is done, (assuming your configuration file is named my_custom_conf.yml) your custom, registered, module should appear in the list provided by the command line:

$ fastoad list_modules my_custom_conf.yml

Then your component can be used like any other using the id you have given.

# Definition of OpenMDAO model
model:
  [ ... ]

  my_custom_model:
    id: "my.custom.name"

  [ ... ]

Note

FAST-OAD will inspect all sub-folders in a specified module folder, as long as they are Python packages, i.e. if they contain a __init__.py file.