Scalable problem

We want to solve the Aerostructure MDO problem by means of the MDF formulation with a higher dimension for the sweep parameter. For that, we use the ScalableProblem class.

from __future__ import annotations

from gemseo import configure_logger
from gemseo import create_discipline
from gemseo import create_scenario
from gemseo.problems.aerostructure.aerostructure_design_space import (
    AerostructureDesignSpace,
)
from gemseo.problems.scalable.data_driven.problem import ScalableProblem

configure_logger()
<RootLogger root (INFO)>

Define the design problem

In a first step, we define the design problem in terms of objective function (to maximize or minimize), design variables (local and global) and constraints (equality and inequality).

design_variables = ["thick_airfoils", "thick_panels", "sweep"]
objective_function = "range"
eq_constraints = ["c_rf"]
ineq_constraints = ["c_lift"]
maximize_objective = True

Create the disciplinary datasets

Then, we create the disciplinary AbstractFullCache datasets based on a DiagonalDOE.

disciplines = create_discipline(["Aerodynamics", "Structure", "Mission"])
datasets = []
for discipline in disciplines:
    design_space = AerostructureDesignSpace()
    design_space.filter(discipline.get_input_data_names())
    output_names = iter(discipline.get_output_data_names())
    scenario = create_scenario(
        discipline,
        "DisciplinaryOpt",
        next(output_names),
        design_space,
        scenario_type="DOE",
    )
    for output_name in output_names:
        scenario.add_observable(output_name)
    scenario.execute({"algo": "DiagonalDOE", "n_samples": 10})
    datasets.append(scenario.to_dataset(name=discipline.name, opt_naming=False))
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.0.0/lib/python3.9/site-packages/gemseo/algos/design_space.py:426: ComplexWarning: Casting complex values to real discards the imaginary part
  self.__current_value[name] = array_value.astype(
    INFO - 16:25:43:
    INFO - 16:25:43: *** Start DOEScenario execution ***
    INFO - 16:25:43: DOEScenario
    INFO - 16:25:43:    Disciplines: Aerodynamics
    INFO - 16:25:43:    MDO formulation: DisciplinaryOpt
    INFO - 16:25:43: Optimization problem:
    INFO - 16:25:43:    minimize drag(thick_airfoils, sweep, displ)
    INFO - 16:25:43:    with respect to displ, sweep, thick_airfoils
    INFO - 16:25:43:    over the design space:
    INFO - 16:25:43:    +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:    | name           | lower_bound | value | upper_bound | type  |
    INFO - 16:25:43:    +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:    | thick_airfoils |      5      |   15  |      25     | float |
    INFO - 16:25:43:    | sweep          |      10     |   25  |      35     | float |
    INFO - 16:25:43:    | displ          |    -1000    |  -700 |     1000    | float |
    INFO - 16:25:43:    +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43: Solving optimization problem with algorithm DiagonalDOE:
    INFO - 16:25:43: ...   0%|          | 0/10 [00:00<?, ?it]
    INFO - 16:25:43: ...  10%|█         | 1/10 [00:00<00:00, 216.82 it/sec, obj=422]
    INFO - 16:25:43: ...  20%|██        | 2/10 [00:00<00:00, 345.67 it/sec, obj=336]
    INFO - 16:25:43: ...  30%|███       | 3/10 [00:00<00:00, 431.68 it/sec, obj=250]
    INFO - 16:25:43: ...  40%|████      | 4/10 [00:00<00:00, 494.73 it/sec, obj=166]
    INFO - 16:25:43: ...  50%|█████     | 5/10 [00:00<00:00, 542.01 it/sec, obj=82.3]
    INFO - 16:25:43: ...  60%|██████    | 6/10 [00:00<00:00, 580.43 it/sec, obj=-.0983]
    INFO - 16:25:43: ...  70%|███████   | 7/10 [00:00<00:00, 608.50 it/sec, obj=-81.6]
    INFO - 16:25:43: ...  80%|████████  | 8/10 [00:00<00:00, 632.42 it/sec, obj=-162]
    INFO - 16:25:43: ...  90%|█████████ | 9/10 [00:00<00:00, 653.10 it/sec, obj=-242]
    INFO - 16:25:43: ... 100%|██████████| 10/10 [00:00<00:00, 670.98 it/sec, obj=-320]
    INFO - 16:25:43: Optimization result:
    INFO - 16:25:43:    Optimizer info:
    INFO - 16:25:43:       Status: None
    INFO - 16:25:43:       Message: None
    INFO - 16:25:43:       Number of calls to the objective function by the optimizer: 10
    INFO - 16:25:43:    Solution:
    INFO - 16:25:43:       Objective: -319.99905478395067
    INFO - 16:25:43:       Design space:
    INFO - 16:25:43:       +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:       | name           | lower_bound | value | upper_bound | type  |
    INFO - 16:25:43:       +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:       | thick_airfoils |      5      |   25  |      25     | float |
    INFO - 16:25:43:       | sweep          |      10     |   35  |      35     | float |
    INFO - 16:25:43:       | displ          |    -1000    |  1000 |     1000    | float |
    INFO - 16:25:43:       +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43: *** End DOEScenario execution (time: 0:00:00.026901) ***
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.0.0/lib/python3.9/site-packages/gemseo/algos/design_space.py:426: ComplexWarning: Casting complex values to real discards the imaginary part
  self.__current_value[name] = array_value.astype(
    INFO - 16:25:43:
    INFO - 16:25:43: *** Start DOEScenario execution ***
    INFO - 16:25:43: DOEScenario
    INFO - 16:25:43:    Disciplines: Structure
    INFO - 16:25:43:    MDO formulation: DisciplinaryOpt
    INFO - 16:25:43: Optimization problem:
    INFO - 16:25:43:    minimize mass(thick_panels, sweep, forces)
    INFO - 16:25:43:    with respect to forces, sweep, thick_panels
    INFO - 16:25:43:    over the design space:
    INFO - 16:25:43:    +--------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:    | name         | lower_bound | value | upper_bound | type  |
    INFO - 16:25:43:    +--------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:    | thick_panels |      1      |   3   |      20     | float |
    INFO - 16:25:43:    | sweep        |      10     |   25  |      35     | float |
    INFO - 16:25:43:    | forces       |    -1000    |  400  |     1000    | float |
    INFO - 16:25:43:    +--------------+-------------+-------+-------------+-------+
    INFO - 16:25:43: Solving optimization problem with algorithm DiagonalDOE:
    INFO - 16:25:43: ...   0%|          | 0/10 [00:00<?, ?it]
    INFO - 16:25:43: ...  10%|█         | 1/10 [00:00<00:00, 222.34 it/sec, obj=100]
    INFO - 16:25:43: ...  20%|██        | 2/10 [00:00<00:00, 351.86 it/sec, obj=4.48e+4]
    INFO - 16:25:43: ...  30%|███       | 3/10 [00:00<00:00, 438.99 it/sec, obj=8.94e+4]
    INFO - 16:25:43: ...  40%|████      | 4/10 [00:00<00:00, 502.55 it/sec, obj=1.34e+5]
    INFO - 16:25:43: ...  50%|█████     | 5/10 [00:00<00:00, 547.40 it/sec, obj=1.79e+5]
    INFO - 16:25:43: ...  60%|██████    | 6/10 [00:00<00:00, 584.98 it/sec, obj=2.23e+5]
    INFO - 16:25:43: ...  70%|███████   | 7/10 [00:00<00:00, 613.95 it/sec, obj=2.68e+5]
    INFO - 16:25:43: ...  80%|████████  | 8/10 [00:00<00:00, 638.75 it/sec, obj=3.13e+5]
    INFO - 16:25:43: ...  90%|█████████ | 9/10 [00:00<00:00, 657.91 it/sec, obj=3.57e+5]
    INFO - 16:25:43: ... 100%|██████████| 10/10 [00:00<00:00, 674.98 it/sec, obj=4.02e+5]
    INFO - 16:25:43: Optimization result:
    INFO - 16:25:43:    Optimizer info:
    INFO - 16:25:43:       Status: None
    INFO - 16:25:43:       Message: None
    INFO - 16:25:43:       Number of calls to the objective function by the optimizer: 10
    INFO - 16:25:43:    Solution:
    INFO - 16:25:43:       Objective: 100.08573388203513
    INFO - 16:25:43:       Design space:
    INFO - 16:25:43:       +--------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:       | name         | lower_bound | value | upper_bound | type  |
    INFO - 16:25:43:       +--------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:       | thick_panels |      1      |   1   |      20     | float |
    INFO - 16:25:43:       | sweep        |      10     |   10  |      35     | float |
    INFO - 16:25:43:       | forces       |    -1000    | -1000 |     1000    | float |
    INFO - 16:25:43:       +--------------+-------------+-------+-------------+-------+
    INFO - 16:25:43: *** End DOEScenario execution (time: 0:00:00.026405) ***
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.0.0/lib/python3.9/site-packages/gemseo/algos/design_space.py:426: ComplexWarning: Casting complex values to real discards the imaginary part
  self.__current_value[name] = array_value.astype(
    INFO - 16:25:43:
    INFO - 16:25:43: *** Start DOEScenario execution ***
    INFO - 16:25:43: DOEScenario
    INFO - 16:25:43:    Disciplines: Mission
    INFO - 16:25:43:    MDO formulation: DisciplinaryOpt
    INFO - 16:25:43: Optimization problem:
    INFO - 16:25:43:    minimize range(drag, lift, mass, reserve_fact)
    INFO - 16:25:43:    with respect to drag, lift, mass, reserve_fact
    INFO - 16:25:43:    over the design space:
    INFO - 16:25:43:    +--------------+-------------+--------+-------------+-------+
    INFO - 16:25:43:    | name         | lower_bound | value  | upper_bound | type  |
    INFO - 16:25:43:    +--------------+-------------+--------+-------------+-------+
    INFO - 16:25:43:    | drag         |     100     |  340   |     1000    | float |
    INFO - 16:25:43:    | lift         |     0.1     |  0.5   |      1      | float |
    INFO - 16:25:43:    | mass         |    100000   | 100000 |    500000   | float |
    INFO - 16:25:43:    | reserve_fact |    -1000    |   0    |     1000    | float |
    INFO - 16:25:43:    +--------------+-------------+--------+-------------+-------+
    INFO - 16:25:43: Solving optimization problem with algorithm DiagonalDOE:
    INFO - 16:25:43: ...   0%|          | 0/10 [00:00<?, ?it]
    INFO - 16:25:43: ...  10%|█         | 1/10 [00:00<00:00, 230.04 it/sec, obj=8e+3+j]
    INFO - 16:25:43: ...  20%|██        | 2/10 [00:00<00:00, 359.38 it/sec, obj=5.54e+3+j]
    INFO - 16:25:43: ...  30%|███       | 3/10 [00:00<00:00, 445.00 it/sec, obj=4.24e+3+j]
    INFO - 16:25:43: ...  40%|████      | 4/10 [00:00<00:00, 504.06 it/sec, obj=3.43e+3+j]
    INFO - 16:25:43: ...  50%|█████     | 5/10 [00:00<00:00, 548.55 it/sec, obj=2.88e+3+j]
    INFO - 16:25:43: ...  60%|██████    | 6/10 [00:00<00:00, 582.49 it/sec, obj=2.48e+3+j]
    INFO - 16:25:43: ...  70%|███████   | 7/10 [00:00<00:00, 610.06 it/sec, obj=2.18e+3+j]
    INFO - 16:25:43: ...  80%|████████  | 8/10 [00:00<00:00, 630.40 it/sec, obj=1.95e+3+j]
    INFO - 16:25:43: ...  90%|█████████ | 9/10 [00:00<00:00, 648.84 it/sec, obj=1.76e+3+j]
    INFO - 16:25:43: ... 100%|██████████| 10/10 [00:00<00:00, 664.99 it/sec, obj=1.6e+3+j]
    INFO - 16:25:43: Optimization result:
    INFO - 16:25:43:    Optimizer info:
    INFO - 16:25:43:       Status: None
    INFO - 16:25:43:       Message: None
    INFO - 16:25:43:       Number of calls to the objective function by the optimizer: 10
    INFO - 16:25:43:    Solution:
    INFO - 16:25:43:       Objective: (1600+0j)
    INFO - 16:25:43:       Design space:
    INFO - 16:25:43:       +--------------+-------------+--------+-------------+-------+
    INFO - 16:25:43:       | name         | lower_bound | value  | upper_bound | type  |
    INFO - 16:25:43:       +--------------+-------------+--------+-------------+-------+
    INFO - 16:25:43:       | drag         |     100     |  1000  |     1000    | float |
    INFO - 16:25:43:       | lift         |     0.1     |   1    |      1      | float |
    INFO - 16:25:43:       | mass         |    100000   | 500000 |    500000   | float |
    INFO - 16:25:43:       | reserve_fact |    -1000    |  1000  |     1000    | float |
    INFO - 16:25:43:       +--------------+-------------+--------+-------------+-------+
    INFO - 16:25:43: *** End DOEScenario execution (time: 0:00:00.027244) ***

Instantiate a scalable problem

In a third stage, we instantiate a ScalableProblem from these disciplinary datasets and from the definition of the MDO problem. We also increase the dimension of the sweep parameter.

problem = ScalableProblem(
    datasets,
    design_variables,
    objective_function,
    eq_constraints,
    ineq_constraints,
    maximize_objective,
    sizes={"sweep": 2},
)
print(problem)
MDO problem
   Disciplines: Aerodynamics, Structure, Mission
   Design variables: thick_airfoils, thick_panels, sweep
   Objective function: range (to maximize)
   Inequality constraints: c_lift
   Equality constraints: c_rf
   Sizes: displ (1), sweep (2), thick_airfoils (1), drag (1), forces (1), lift (1), thick_panels (1), mass (1), reserve_fact (1), c_lift (1), c_rf (1), range (1)

Note

We could also provide options to the ScalableModel objects by means of the constructor of ScalableProblem, e.g. fill_factor in the frame of the ScalableDiagonalModel. In this example, we use the standard ones.

Visualize the N2 chart

We can see the coupling between disciplines through this N2 chart:

problem.plot_n2_chart(save=False, show=True)
plot problem

Create an MDO scenario

Lastly, we create a MDOScenario with the MDF formulation and start the optimization at equilibrium, thus ensuring the feasibility of the first iterate.

scenario = problem.create_scenario("MDF", start_at_equilibrium=True)
INFO - 16:25:43: Build a preliminary MDA to start at equilibrium

Note

We could also provide options for the scalable models to the constructor of ScalableProblem, e.g. fill_factor in the frame of the ScalableDiagonalModel. In this example, we use the standard ones.

Once the scenario is created, we can execute it as any scenario. Here, we use the NLOPT_SLSQP optimization algorithm with no more than 100 iterations.

scenario.execute({"algo": "NLOPT_SLSQP", "max_iter": 100})
    INFO - 16:25:43:
    INFO - 16:25:43: *** Start MDOScenario execution ***
    INFO - 16:25:43: MDOScenario
    INFO - 16:25:43:    Disciplines: sdm_Aerodynamics sdm_Mission sdm_Structure
    INFO - 16:25:43:    MDO formulation: MDF
    INFO - 16:25:43: Optimization problem:
    INFO - 16:25:43:    minimize -range(thick_airfoils, thick_panels, sweep)
    INFO - 16:25:43:    with respect to sweep, thick_airfoils, thick_panels
    INFO - 16:25:43:    subject to constraints:
    INFO - 16:25:43:       c_lift(thick_airfoils, thick_panels, sweep) <= [0.74804822]
    INFO - 16:25:43:       c_rf(thick_airfoils, thick_panels, sweep) == 0.4974338463722027
    INFO - 16:25:43:    over the design space:
    INFO - 16:25:43:    +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:    | name           | lower_bound | value | upper_bound | type  |
    INFO - 16:25:43:    +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43:    | thick_airfoils |      0      |  0.5  |      1      | float |
    INFO - 16:25:43:    | thick_panels   |      0      |  0.5  |      1      | float |
    INFO - 16:25:43:    | sweep[0]       |      0      |  0.5  |      1      | float |
    INFO - 16:25:43:    | sweep[1]       |      0      |  0.5  |      1      | float |
    INFO - 16:25:43:    +----------------+-------------+-------+-------------+-------+
    INFO - 16:25:43: Solving optimization problem with algorithm NLOPT_SLSQP:
    INFO - 16:25:43: ...   0%|          | 0/100 [00:00<?, ?it]
    INFO - 16:25:43: ...   1%|          | 1/100 [00:00<00:03, 30.43 it/sec, obj=-.168]
    INFO - 16:25:43: ...   2%|▏         | 2/100 [00:00<00:11,  8.73 it/sec, obj=-.171]
 WARNING - 16:25:43: MDAJacobi has reached its maximum number of iterations but the normed residual 0.5 is still above the tolerance 1e-06.
    INFO - 16:25:43: ...   3%|▎         | 3/100 [00:00<00:10,  8.84 it/sec, obj=-.197]
    INFO - 16:25:44: ...   4%|▍         | 4/100 [00:00<00:09,  9.61 it/sec, obj=-.286]
    INFO - 16:25:44: ...   5%|▌         | 5/100 [00:00<00:09,  9.83 it/sec, obj=-.299]
    INFO - 16:25:44: ...   6%|▌         | 6/100 [00:00<00:09, 10.14 it/sec, obj=-.299]
   ERROR - 16:25:44: NLopt run failed: NLopt roundoff-limited, RoundoffLimited
    INFO - 16:25:44: ...   7%|▋         | 7/100 [00:00<00:07, 11.76 it/sec, obj=-.299]
    INFO - 16:25:44: Optimization result:
    INFO - 16:25:44:    Optimizer info:
    INFO - 16:25:44:       Status: None
    INFO - 16:25:44:       Message:  GEMSEO Stopped the driver
    INFO - 16:25:44:       Number of calls to the objective function by the optimizer: 8
    INFO - 16:25:44:    Solution:
    INFO - 16:25:44:       The solution is feasible.
    INFO - 16:25:44:       Objective: -0.298527662515633
    INFO - 16:25:44:       Standardized constraints:
    INFO - 16:25:44:          c_lift + offset = [-0.49234168]
    INFO - 16:25:44:          c_rf - 0.4974338463722027 = -4.3298697960381105e-15
    INFO - 16:25:44:       Design space:
    INFO - 16:25:44:       +----------------+-------------+--------------------+-------------+-------+
    INFO - 16:25:44:       | name           | lower_bound |       value        | upper_bound | type  |
    INFO - 16:25:44:       +----------------+-------------+--------------------+-------------+-------+
    INFO - 16:25:44:       | thick_airfoils |      0      |         1          |      1      | float |
    INFO - 16:25:44:       | thick_panels   |      0      | 0.5155052311584976 |      1      | float |
    INFO - 16:25:44:       | sweep[0]       |      0      |         1          |      1      | float |
    INFO - 16:25:44:       | sweep[1]       |      0      |         1          |      1      | float |
    INFO - 16:25:44:       +----------------+-------------+--------------------+-------------+-------+
    INFO - 16:25:44: *** End MDOScenario execution (time: 0:00:00.610651) ***

{'max_iter': 100, 'algo': 'NLOPT_SLSQP'}

We can post-process the results. Here, we use the standard OptHistoryView.

scenario.post_process("OptHistoryView", save=False, show=True)
  • Evolution of the optimization variables
  • Evolution of the objective value
  • Distance to the optimum
  • Hessian diagonal approximation
  • Evolution of the inequality constraints
  • Evolution of the equality constraints
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.0.0/lib/python3.9/site-packages/genson/schema/strategies/base.py:42: UserWarning: Schema incompatible. Keyword 'description' has conflicting values ('The width and height of the figure in inches, e.g. ``(w, h)``.\nIf ``None``, use the :attr:`.OptPostProcessor.DEFAULT_FIG_SIZE`\nof the post-processor.' vs. 'The width and height of the figure in inches, e.g. `(w, h)`.\nIf ``None``, use the :attr:`.OptPostProcessor.DEFAULT_FIG_SIZE`\nof the post-processor.'). Using 'The width and height of the figure in inches, e.g. ``(w, h)``.\nIf ``None``, use the :attr:`.OptPostProcessor.DEFAULT_FIG_SIZE`\nof the post-processor.'
  warn(('Schema incompatible. Keyword {0!r} has conflicting '
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.0.0/lib/python3.9/site-packages/gemseo/post/opt_history_view.py:599: UserWarning: All values for SymLogScale are below linthresh, making it effectively linear. You likely should lower the value of linthresh.
  col_bar = fig.colorbar(

<gemseo.post.opt_history_view.OptHistoryView object at 0x7fea479d74f0>

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

Gallery generated by Sphinx-Gallery