BiLevel-based DOE on the Sobieski SSBJ test case

from __future__ import annotations

from copy import deepcopy
from os import name as os_name

from gemseo import configure_logger
from gemseo import create_discipline
from gemseo import create_scenario
from gemseo.problems.sobieski.core.design_space import SobieskiDesignSpace

configure_logger()
<RootLogger root (INFO)>

Instantiate the disciplines

First, we instantiate the four disciplines of the use case: SobieskiPropulsion, SobieskiAerodynamics, SobieskiMission and SobieskiStructure.

propu, aero, mission, struct = create_discipline([
    "SobieskiPropulsion",
    "SobieskiAerodynamics",
    "SobieskiMission",
    "SobieskiStructure",
])

Build, execute and post-process the scenario

Then, we build the scenario which links the disciplines with the formulation and the optimization algorithm. Here, we use the BiLevel formulation. We tell the scenario to minimize -y_4 instead of minimizing y_4 (range), which is the default option.

We need to define the design space.

design_space = SobieskiDesignSpace()

Then, we build a sub-scenario for each strongly coupled disciplines, using the following algorithm, maximum number of iterations and algorithm options:

algo_options = {
    "xtol_rel": 1e-7,
    "xtol_abs": 1e-7,
    "ftol_rel": 1e-7,
    "ftol_abs": 1e-7,
    "ineq_tolerance": 1e-4,
}
sub_sc_opts = {"max_iter": 30, "algo": "SLSQP", "algo_options": algo_options}

Build a sub-scenario for Propulsion

This sub-scenario will minimize SFC.

sc_prop = create_scenario(
    propu,
    "DisciplinaryOpt",
    "y_34",
    design_space=deepcopy(design_space).filter("x_3"),
    name="PropulsionScenario",
)

Build a sub-scenario for Aerodynamics

This sub-scenario will minimize L/D.

sc_aero = create_scenario(
    aero,
    "DisciplinaryOpt",
    "y_24",
    deepcopy(design_space).filter("x_2"),
    name="AerodynamicsScenario",
    maximize_objective=True,
)

Build a sub-scenario for Structure

This sub-scenario will maximize log(aircraft total weight / (aircraft total weight - fuel weight)).

sc_str = create_scenario(
    struct,
    "DisciplinaryOpt",
    "y_11",
    deepcopy(design_space).filter("x_1"),
    name="StructureScenario",
    maximize_objective=True,
)

Build a scenario for Mission

This scenario is based on the three previous sub-scenarios and on the Mission and aims to maximize the range (Breguet).

sub_disciplines = [sc_prop, sc_aero, sc_str, mission]
design_space = deepcopy(design_space).filter("x_shared")
system_scenario = create_scenario(
    sub_disciplines,
    "BiLevel",
    "y_4",
    design_space,
    parallel_scenarios=False,
    reset_x0_before_opt=True,
    scenario_type="DOE",
)

Note

Setting reset_x0_before_opt=True is mandatory when doing a DOE in parallel. If we want reproducible results, don’t reuse previous xopt.

system_scenario.formulation.mda1.warm_start = False
system_scenario.formulation.mda2.warm_start = False

Note

This is mandatory when doing a DOE in parallel if we want always exactly the same results, don’t warm start mda1 to have exactly the same process whatever the execution order and process dispatch.

for sub_sc in sub_disciplines[0:3]:
    sub_sc.default_inputs = {"max_iter": 20, "algo": "L-BFGS-B"}

Visualize the XDSM

Generate the XDSM on the fly:

  • log_workflow_status=True will log the status of the workflow in the console,

  • save_html (default True) will generate a self-contained HTML file, that can be automatically opened using show_html=True.

system_scenario.xdsmize(save_html=False)


Multiprocessing

It is possible to run a DOE in parallel using multiprocessing, in order to do this, we specify the number of processes to be used for the computation of the samples.

Warning

The multiprocessing option has some limitations on Windows. Due to problems with sphinx, we disable it in this example. The features MemoryFullCache and HDF5Cache are not available for multiprocessing on Windows. As an alternative, we recommend the method DOEScenario.set_optimization_history_backup().

system_scenario.execute({
    "n_samples": 30,
    "algo": "lhs",
    "algo_options": {"n_processes": 1 if os_name == "nt" else 4},
})

system_scenario.print_execution_metrics()
 INFO - 10:52:00:
 INFO - 10:52:00: *** Start DOEScenario execution ***
 INFO - 10:52:00: DOEScenario
 INFO - 10:52:00:    Disciplines: AerodynamicsScenario PropulsionScenario SobieskiMission StructureScenario
 INFO - 10:52:00:    MDO formulation: BiLevel
 INFO - 10:52:00: Optimization problem:
 INFO - 10:52:00:    minimize y_4(x_shared)
 INFO - 10:52:00:    with respect to x_shared
 INFO - 10:52:00:    over the design space:
 INFO - 10:52:00:       +-------------+-------------+-------+-------------+-------+
 INFO - 10:52:00:       | Name        | Lower bound | Value | Upper bound | Type  |
 INFO - 10:52:00:       +-------------+-------------+-------+-------------+-------+
 INFO - 10:52:00:       | x_shared[0] |     0.01    |  0.05 |     0.09    | float |
 INFO - 10:52:00:       | x_shared[1] |    30000    | 45000 |    60000    | float |
 INFO - 10:52:00:       | x_shared[2] |     1.4     |  1.6  |     1.8     | float |
 INFO - 10:52:00:       | x_shared[3] |     2.5     |  5.5  |     8.5     | float |
 INFO - 10:52:00:       | x_shared[4] |      40     |   55  |      70     | float |
 INFO - 10:52:00:       | x_shared[5] |     500     |  1000 |     1500    | float |
 INFO - 10:52:00:       +-------------+-------------+-------+-------------+-------+
 INFO - 10:52:00: Solving optimization problem with algorithm lhs:
 INFO - 10:52:00: Running DOE in parallel on n_processes = 4
ERROR - 10:52:01: Failed to execute task indexed 0
ERROR - 10:52:01: math domain error
 INFO - 10:52:01:      3%|▎         | 1/30 [00:01<00:37, 46.11 it/min, obj=388]
 INFO - 10:52:01:      7%|▋         | 2/30 [00:01<00:18,  1.49 it/sec, obj=350]
 INFO - 10:52:01:     10%|█         | 3/30 [00:01<00:12,  2.16 it/sec, obj=485]
 INFO - 10:52:02:     13%|█▎        | 4/30 [00:02<00:13,  1.97 it/sec, obj=621]
 INFO - 10:52:02:     17%|█▋        | 5/30 [00:02<00:10,  2.37 it/sec, obj=458]
 INFO - 10:52:02:     20%|██        | 6/30 [00:02<00:08,  2.75 it/sec, obj=549]
 INFO - 10:52:02:     23%|██▎       | 7/30 [00:02<00:07,  3.19 it/sec, obj=495]
 INFO - 10:52:03:     27%|██▋       | 8/30 [00:02<00:07,  2.88 it/sec, obj=367]
 INFO - 10:52:03:     30%|███       | 9/30 [00:02<00:06,  3.18 it/sec, obj=892]
 INFO - 10:52:03:     33%|███▎      | 10/30 [00:02<00:05,  3.43 it/sec, obj=918]
 INFO - 10:52:03:     37%|███▋      | 11/30 [00:02<00:05,  3.69 it/sec, obj=1.27e+3]
 INFO - 10:52:04:     40%|████      | 12/30 [00:03<00:05,  3.38 it/sec, obj=337]
 INFO - 10:52:04:     43%|████▎     | 13/30 [00:03<00:04,  3.65 it/sec, obj=415]
 INFO - 10:52:04:     47%|████▋     | 14/30 [00:03<00:04,  3.79 it/sec, obj=354]
 INFO - 10:52:04:     50%|█████     | 15/30 [00:03<00:03,  3.99 it/sec, obj=1.2e+3]
 INFO - 10:52:04:     53%|█████▎    | 16/30 [00:04<00:03,  3.80 it/sec, obj=2.27e+3]
 INFO - 10:52:04:     57%|█████▋    | 17/30 [00:04<00:03,  3.94 it/sec, obj=394]
 INFO - 10:52:04:     60%|██████    | 18/30 [00:04<00:02,  4.06 it/sec, obj=380]
 INFO - 10:52:05:     63%|██████▎   | 19/30 [00:04<00:02,  3.93 it/sec, obj=829]
 INFO - 10:52:05:     67%|██████▋   | 20/30 [00:04<00:02,  4.07 it/sec, obj=1.21e+3]
 INFO - 10:52:05:     70%|███████   | 21/30 [00:04<00:02,  4.23 it/sec, obj=832]
 INFO - 10:52:05:     73%|███████▎  | 22/30 [00:05<00:01,  4.39 it/sec, obj=1.04e+3]
 INFO - 10:52:06:     77%|███████▋  | 23/30 [00:05<00:01,  4.05 it/sec, obj=640]
 INFO - 10:52:06:     80%|████████  | 24/30 [00:05<00:01,  4.22 it/sec, obj=1.19e+3]
 INFO - 10:52:06:     83%|████████▎ | 25/30 [00:05<00:01,  4.37 it/sec, obj=484]
 INFO - 10:52:06:     87%|████████▋ | 26/30 [00:05<00:00,  4.54 it/sec, obj=470]
 INFO - 10:52:06:     90%|█████████ | 27/30 [00:06<00:00,  4.37 it/sec, obj=647]
 INFO - 10:52:06:     93%|█████████▎| 28/30 [00:06<00:00,  4.48 it/sec, obj=952]
 INFO - 10:52:06:     97%|█████████▋| 29/30 [00:06<00:00,  4.64 it/sec, obj=293]
 INFO - 10:52:06: Optimization result:
 INFO - 10:52:06:    Optimizer info:
 INFO - 10:52:06:       Status: None
 INFO - 10:52:06:       Message: None
 INFO - 10:52:06:       Number of calls to the objective function by the optimizer: 30
 INFO - 10:52:06:    Solution:
 INFO - 10:52:06:       Objective: 292.9117883370658
 INFO - 10:52:06:       Design space:
 INFO - 10:52:06:          +-------------+-------------+---------------------+-------------+-------+
 INFO - 10:52:06:          | Name        | Lower bound |        Value        | Upper bound | Type  |
 INFO - 10:52:06:          +-------------+-------------+---------------------+-------------+-------+
 INFO - 10:52:06:          | x_shared[0] |     0.01    | 0.04666883227502976 |     0.09    | float |
 INFO - 10:52:06:          | x_shared[1] |    30000    |  37789.27932845149  |    60000    | float |
 INFO - 10:52:06:          | x_shared[2] |     1.4     |  1.667044086506944  |     1.8     | float |
 INFO - 10:52:06:          | x_shared[3] |     2.5     |   8.29772323088249  |     8.5     | float |
 INFO - 10:52:06:          | x_shared[4] |      40     |  42.41730480236713  |      70     | float |
 INFO - 10:52:06:          | x_shared[5] |     500     |  724.9388551459947  |     1500    | float |
 INFO - 10:52:06:          +-------------+-------------+---------------------+-------------+-------+
 INFO - 10:52:06: *** End DOEScenario execution (time: 0:00:06.314241) ***
 INFO - 10:52:06: Scenario Execution Statistics
 INFO - 10:52:06:    Discipline: PropulsionScenario
 INFO - 10:52:06:       Executions number: 30
 INFO - 10:52:06:       Execution time: 1.7752986019877426 s
 INFO - 10:52:06:       Linearizations number: 0
 INFO - 10:52:06:    Discipline: AerodynamicsScenario
 INFO - 10:52:06:       Executions number: 30
 INFO - 10:52:06:       Execution time: 2.122430796000117 s
 INFO - 10:52:06:       Linearizations number: 0
 INFO - 10:52:06:    Discipline: StructureScenario
 INFO - 10:52:06:       Executions number: 30
 INFO - 10:52:06:       Execution time: 8.274247871006082 s
 INFO - 10:52:06:       Linearizations number: 0
 INFO - 10:52:06:    Discipline: SobieskiMission
 INFO - 10:52:06:       Executions number: 29
 INFO - 10:52:06:       Execution time: 0.0019757509871851653 s
 INFO - 10:52:06:       Linearizations number: 0
 INFO - 10:52:06:    Total number of executions calls: 119
 INFO - 10:52:06:    Total number of linearizations: 0

Warning

On Windows, the progress bar may show duplicated instances during the initialization of each subprocess. In some cases it may also print the conclusion of an iteration ahead of another one that was concluded first. This is a consequence of the pickling process and does not affect the computations of the scenario.

Exporting the problem data.

After the execution of the scenario, you may want to export your data to use it elsewhere. The method Scenario.to_dataset() will allow you to export your results to a Dataset, the basic GEMSEO class to store data.

dataset = system_scenario.to_dataset("a_name_for_my_dataset")

Plot the optimization history view

system_scenario.post_process("OptHistoryView", save=False, show=True)
  • Evolution of the optimization variables
  • Evolution of the objective value
  • Distance to the optimum
<gemseo.post.opt_history_view.OptHistoryView object at 0x7f1de089b2e0>

Plot the scatter matrix

system_scenario.post_process(
    "ScatterPlotMatrix",
    variable_names=["y_4", "x_shared"],
    save=False,
    show=True,
)
plot doe sobieski bilevel example
<gemseo.post.scatter_mat.ScatterPlotMatrix object at 0x7f1de0d8e220>

Plot parallel coordinates

system_scenario.post_process("ParallelCoordinates", save=False, show=True)
  • Design variables history colored by 'y_4' value
  • Objective function and constraints history colored by 'y_4' value.
<gemseo.post.para_coord.ParallelCoordinates object at 0x7f1de0bbc9d0>

Plot correlations

system_scenario.post_process("Correlations", save=False, show=True)
    INFO - 10:52:10: Detected 0 correlations > 0.95

<gemseo.post.correlations.Correlations object at 0x7f1ddfa1b520>

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

Gallery generated by Sphinx-Gallery