Note

Go to the end to download the full example code

# Example for exterior penalty applied to the Sobieski test case.¶

This section describes how to set up and solve the MDO problem relative to the Sobieski test case with GEMSEO applying external penalty.

See also

To start with a simpler MDO problem, and for a detailed description of how to plug a test case into GEMSEO, see Tutorial: How to solve an MDO problem.

## Solving with an MDF formulation¶

In this example, we solve the range optimization using the following MDF formulation:

The MDF formulation couples all the disciplines during the Multi Disciplinary Analyses at each optimization iteration.

All the design variables are equally treated, concatenated in a single vector and given to a single optimization algorithm as the unknowns of the problem.

There is no specific constraint due to the MDF formulation.

Only the design constraints \(g\_1\), \(g\_2\) and \(g\_3\) are added to the problem.

The objective function is the range (the \(y\_4\) variable in the model), computed after the Multi Disciplinary Analyses.

## Imports¶

All the imports needed for the tutorials are performed here.

```
from __future__ import annotations
from gemseo import configure_logger
from gemseo import create_discipline
from gemseo import create_scenario
from gemseo import get_available_formulations
from gemseo.disciplines.utils import get_all_inputs
from gemseo.disciplines.utils import get_all_outputs
from gemseo.problems.sobieski.core.problem import SobieskiProblem
configure_logger()
```

## Step 1: Creation of `MDODiscipline`

¶

To build the scenario, we first instantiate the disciplines. Here, the disciplines themselves have already been developed and interfaced with GEMSEO (see Benchmark problems).

```
disciplines = create_discipline(
[
"SobieskiPropulsion",
"SobieskiAerodynamics",
"SobieskiMission",
"SobieskiStructure",
]
)
```

Tip

For the disciplines that are not interfaced with GEMSEO, the GEMSEO’s
`gemseo`

eases the creation of disciplines without having
to import them.

## Step 2: Creation of `Scenario`

¶

The scenario delegates the creation of the optimization problem to the MDO formulation.

Therefore, it needs the list of `disciplines`

, the names of the formulation,
the name of the objective function and the design space.

The

`design_space`

(shown below for reference) defines the unknowns of the optimization problem, and their bounds. It contains all the design variables needed by the MDF formulation. It can be imported from a text file, or created from scratch with the methods`create_design_space()`

and`add_variable()`

. In this case, we will retrieve it from the`SobieskiProblem`

already defined in GEMSEO.

```
design_space = SobieskiProblem().design_space
x_0 = design_space.get_current_value(as_dict=True)
```

```
name lower_bound value upper_bound type
x_shared 0.01 0.05 0.09 float
x_shared 30000.0 45000.0 60000.0 float
x_shared 1.4 1.6 1.8 float
x_shared 2.5 5.5 8.5 float
x_shared 40.0 55.0 70.0 float
x_shared 500.0 1000.0 1500.0 float
x_1 0.1 0.25 0.4 float
x_1 0.75 1.0 1.25 float
x_2 0.75 1.0 1.25 float
x_3 0.1 0.5 1.0 float
y_14 24850.0 50606.9741711 77100.0 float
y_14 -7700.0 7306.20262124 45000.0 float
y_32 0.235 0.50279625 0.795 float
y_31 2960.0 6354.32430691 10185.0 float
y_24 0.44 4.15006276 11.13 float
y_34 0.44 1.10754577 1.98 float
y_23 3365.0 12194.2671934 26400.0 float
y_21 24850.0 50606.9741711 77250.0 float
y_12 24850.0 50606.9742 77250.0 float
y_12 0.45 0.95 1.5 float
```

The available MDO formulations are located in the

**gemseo.formulations**package, see Extend GEMSEO features for extending GEMSEO with other formulations.The

`formulation`

classname (here,`"MDF"`

) shall be passed to the scenario to select them.The list of available formulations can be obtained by using

`get_available_formulations()`

.

```
get_available_formulations()
```

\(y\_4\) corresponds to the

`objective_name`

. This name must be one of the disciplines outputs, here the`SobieskiMission`

discipline. The list of all outputs of the disciplines can be obtained by using`get_all_outputs()`

:

```
get_all_outputs(disciplines)
get_all_inputs(disciplines)
```

From these `MDODiscipline`

, design space,
MDO formulation name and objective function name,
we build the scenario:

```
scenario = create_scenario(
disciplines,
formulation="MDF",
maximize_objective=True,
objective_name="y_4",
design_space=design_space,
)
```

The range function (\(y\_4\)) should be maximized. However, optimizers
minimize functions by default. Which is why, when creating the scenario, the argument
`maximize_objective`

shall be set to `True`

.

### Differentiation method¶

We may choose the way derivatives are computed:

**Function derivatives.** As analytical disciplinary derivatives are
available for the Sobieski test-case, they can be used instead of computing
the derivatives with finite-differences or with the complex-step method.
The easiest way to set a method is to let the optimizer determine it:

```
scenario.set_differentiation_method()
```

The default behavior of the optimizer triggers finite differences. It corresponds to:

```
scenario.set_differentiation_method("finite_differences",1e-7)
```

It it also possible to differentiate functions by means of the complex step method:

```
scenario.set_differentiation_method("complex_step",1e-30j)
```

### Constraints¶

Similarly to the objective function, the constraints names are a subset
of the disciplines’ outputs. They can be obtained by using
`get_all_outputs()`

.

The formulation has a powerful feature to automatically dispatch the constraints
(\(g\_1, g\_2, g\_3\)) and plug them to the optimizers depending on
the formulation. To do that, we use the method
`add_constraint()`

:

```
for constraint in ["g_1", "g_2", "g_3"]:
scenario.add_constraint(constraint, "ineq")
```

## Step 3: Apply the exterior penalty and execute the scenario¶

```
scenario.formulation.opt_problem.apply_exterior_penalty(
objective_scale=10.0, scale_inequality=10.0
)
```

In this way the L-BFGS-B algorithm can be used to solve the optimization problem. Note that this algorithm is not suited for constrained optimization problems.

```
algo_args = {"max_iter": 10, "algo": "L-BFGS-B"}
scenario.execute(algo_args)
```

### Post-processing options¶

To visualize the optimization history of the constraint violation one can use the
`BasicHistory`

:

```
scenario.post_process(
"BasicHistory", variable_names=["g_1", "g_2", "g_3"], save=False, show=True
)
```

This solution is almost feasible. The solution can better approximate the original problem solution increasing the value

of objective_scale and scale_inequality parameters.

## Step 4: Rerun the scenario with increased penalty and objective scaling.¶

```
design_space.set_current_value(x_0)
scenario_2 = create_scenario(
disciplines,
formulation="MDF",
maximize_objective=True,
objective_name="y_4",
design_space=design_space,
)
for constraint in ["g_1", "g_2", "g_3"]:
scenario_2.add_constraint(constraint, "ineq")
scenario_2.set_differentiation_method()
scenario_2.formulation.opt_problem.apply_exterior_penalty(
objective_scale=1000.0, scale_inequality=1000.0
)
algo_args_2 = {"max_iter": 1000, "algo": "L-BFGS-B"}
scenario_2.execute(algo_args_2)
scenario_2.post_process("BasicHistory", variable_names=["-y_4"], save=False, show=True)
scenario_2.post_process(
"BasicHistory", variable_names=["g_1", "g_2", "g_3"], save=False, show=True
)
```

The solution feasibility was improved but this comes with a much higher number of iterations.

**Total running time of the script:** ( 0 minutes 0.000 seconds)