Note
Go to the end to download the full example code.
Create a discipline from a Python function#
There is a simplified and straightforward way of integrating a discipline from a Python function that:
returns variables, e.g.
return xorreturn x, y, but no expression likereturn a+borreturn a+b, y,must have a default value per argument if the
AutoPyDisciplineis used by anMDA(deriving fromBaseMDA), as in the case ofMDFandBiLevelformulations.
from __future__ import annotations
from numpy import array
from gemseo import create_discipline
In this example, we will illustrate this feature using the Python function:
def f(x, y=0.0):
"""A simple Python function taking float numbers and returning a float number."""
z = x + 2 * y
return z
Warning
Note that the Python function must return one or more variables. The following Python function would not be suitable as it returns an expression instead of a variable:
def g(x, y=0.):
"""A simple Python function returning an expression."""
return x + 2*y
Note
Note also that by default,
the arguments and the returned variables of the Python function
are supposed to be either float numbers
or NumPy arrays with dimensions greater than 1.
At the end of the example, we will see how to use other types.
Then, we can consider the
AutoPyDiscipline class
to wrap this Python function into a Discipline.
For that,
we can use the create_discipline() high-level function
with the string "AutoPyDiscipline" as first argument:
discipline = create_discipline("AutoPyDiscipline", py_func=f)
WARNING - 16:15:06: The Args section is missing.
The input variables of the discipline are the arguments of the Python function f:
discipline.io.input_grammar.names
KeysView(Grammar name: f_discipline_input
Required elements:
x:
Type: array
Items:
Type: number
y:
Type: array
Items:
Type: number
Optional elements:)
the output variables of the discipline are the variables returned by f:
discipline.io.output_grammar.names
KeysView(Grammar name: f_discipline_output
Required elements:
z:
Type: array
Items:
Type: number
Optional elements:)
and the default input values of the discipline
are the default values of the arguments of f:
discipline.io.input_grammar.defaults
{'y': array([0.])}
Note
The argument x of the Python function f shall have a default value
when the discipline is used by an MDA (deriving from BaseMDA),
as in the case of MDF and BiLevel formulations,
in presence of strong couplings.
This is not the case in this example.
Execute the discipline#
Then, we can execute this discipline easily, either considering default input values:
discipline.execute({"x": array([1.0])})
{'x': array([1.]), 'y': array([0.]), 'z': array([1.])}
or custom ones:
discipline.execute({"x": array([1.0]), "y": array([-3.2])})
{'x': array([1.]), 'y': array([-3.2]), 'z': array([-5.4])}
Warning
You may have noticed that
the input data are passed to the AutoPyDiscipline as NumPy arrays
even if the Python function f is expecting float numbers.
Define the Jacobian function#
Here is an example of a Python function returning the Jacobian matrix as a 2D NumPy array:
def df(x, y):
"""Function returning the Jacobian of z=f(x,y)"""
return array([[1.0, 2.0]])
We can create a new AutoPyDiscipline from f and df:
discipline = create_discipline("AutoPyDiscipline", py_func=f, py_jac=df)
WARNING - 16:15:06: The Args section is missing.
and compute its Jacobian at {"x": array([1.0]), "y": array([0.0])}:
discipline.linearize(input_data={"x": array([1.0])}, compute_all_jacobians=True)
discipline.jac
{'z': {'x': array([[1.]]), 'y': array([[2.]])}}
Use custom types#
By default,
the AutoPyDiscipline assumes that
the arguments and the returned variables of the Python function are
either float numbers or NumPy arrays with dimensions greater than 1.
This behaviour can be changed in two different ways.
NumPy arrays#
We can force AutoPyDiscipline
to consider all arguments and variables as NumPy arrays
by setting the option use_arrays to True,
as illustrated here:
def copy_array(a):
a_copy = a.copy()
return a_copy
discipline = create_discipline("AutoPyDiscipline", py_func=copy_array, use_arrays=True)
discipline.execute({"a": array([1.0])})
{'a': array([1.]), 'a_copy': array([1.])}
User types#
We can also define specific types for each argument and return variable.
Warning
If you forget to annotate an argument or a return variable, all the types you have specified will be ignored.
As a very simple example, we can consider a Python function which replicates a string n times:
def replicate_string(string: str = "a", n: int = 3) -> str:
final_string = string * n
return final_string
Then, we create the discipline:
discipline = create_discipline("AutoPyDiscipline", py_func=replicate_string)
execute it with its default input values:
discipline.execute()
{'string': 'a', 'n': 3, 'final_string': 'aaa'}
and with custom ones:
discipline.execute({"string": "ab", "n": 5})
{'string': 'ab', 'n': 5, 'final_string': 'ababababab'}
Total running time of the script: (0 minutes 0.013 seconds)