Note
Go to the end to download the full example code
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.2.0/lib/python3.9/site-packages/gemseo/algos/design_space.py:466: ComplexWarning: Casting complex values to real discards the imaginary part
self.__current_value[name] = array_value.astype(
INFO - 10:54:01:
INFO - 10:54:01: *** Start DOEScenario execution ***
INFO - 10:54:01: DOEScenario
INFO - 10:54:01: Disciplines: Aerodynamics
INFO - 10:54:01: MDO formulation: DisciplinaryOpt
INFO - 10:54:01: Optimization problem:
INFO - 10:54:01: minimize drag(thick_airfoils, sweep, displ)
INFO - 10:54:01: with respect to displ, sweep, thick_airfoils
INFO - 10:54:01: over the design space:
INFO - 10:54:01: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:01: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | thick_airfoils | 5 | 15 | 25 | float |
INFO - 10:54:01: | sweep | 10 | 25 | 35 | float |
INFO - 10:54:01: | displ | -1000 | -700 | 1000 | float |
INFO - 10:54:01: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:01: Solving optimization problem with algorithm DiagonalDOE:
INFO - 10:54:01: 10%|█ | 1/10 [00:00<00:00, 219.98 it/sec, obj=422]
INFO - 10:54:01: 20%|██ | 2/10 [00:00<00:00, 351.92 it/sec, obj=336]
INFO - 10:54:01: 30%|███ | 3/10 [00:00<00:00, 443.00 it/sec, obj=250]
INFO - 10:54:01: 40%|████ | 4/10 [00:00<00:00, 513.11 it/sec, obj=166]
INFO - 10:54:01: 50%|█████ | 5/10 [00:00<00:00, 567.75 it/sec, obj=82.3]
INFO - 10:54:01: 60%|██████ | 6/10 [00:00<00:00, 610.18 it/sec, obj=-.0983]
INFO - 10:54:01: 70%|███████ | 7/10 [00:00<00:00, 642.05 it/sec, obj=-81.6]
INFO - 10:54:01: 80%|████████ | 8/10 [00:00<00:00, 670.99 it/sec, obj=-162]
INFO - 10:54:01: 90%|█████████ | 9/10 [00:00<00:00, 696.96 it/sec, obj=-242]
INFO - 10:54:01: 100%|██████████| 10/10 [00:00<00:00, 718.60 it/sec, obj=-320]
INFO - 10:54:01: Optimization result:
INFO - 10:54:01: Optimizer info:
INFO - 10:54:01: Status: None
INFO - 10:54:01: Message: None
INFO - 10:54:01: Number of calls to the objective function by the optimizer: 10
INFO - 10:54:01: Solution:
INFO - 10:54:01: Objective: -319.99905478395067
INFO - 10:54:01: Design space:
INFO - 10:54:01: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:01: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | thick_airfoils | 5 | 25 | 25 | float |
INFO - 10:54:01: | sweep | 10 | 35 | 35 | float |
INFO - 10:54:01: | displ | -1000 | 1000 | 1000 | float |
INFO - 10:54:01: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:01: *** End DOEScenario execution (time: 0:00:00.026334) ***
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.2.0/lib/python3.9/site-packages/gemseo/algos/design_space.py:466: ComplexWarning: Casting complex values to real discards the imaginary part
self.__current_value[name] = array_value.astype(
INFO - 10:54:01:
INFO - 10:54:01: *** Start DOEScenario execution ***
INFO - 10:54:01: DOEScenario
INFO - 10:54:01: Disciplines: Structure
INFO - 10:54:01: MDO formulation: DisciplinaryOpt
INFO - 10:54:01: Optimization problem:
INFO - 10:54:01: minimize mass(thick_panels, sweep, forces)
INFO - 10:54:01: with respect to forces, sweep, thick_panels
INFO - 10:54:01: over the design space:
INFO - 10:54:01: +--------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:01: +--------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | thick_panels | 1 | 3 | 20 | float |
INFO - 10:54:01: | sweep | 10 | 25 | 35 | float |
INFO - 10:54:01: | forces | -1000 | 400 | 1000 | float |
INFO - 10:54:01: +--------------+-------------+-------+-------------+-------+
INFO - 10:54:01: Solving optimization problem with algorithm DiagonalDOE:
INFO - 10:54:01: 10%|█ | 1/10 [00:00<00:00, 228.75 it/sec, obj=100]
INFO - 10:54:01: 20%|██ | 2/10 [00:00<00:00, 366.70 it/sec, obj=4.48e+4]
INFO - 10:54:01: 30%|███ | 3/10 [00:00<00:00, 469.72 it/sec, obj=8.94e+4]
INFO - 10:54:01: 40%|████ | 4/10 [00:00<00:00, 547.93 it/sec, obj=1.34e+5]
INFO - 10:54:01: 50%|█████ | 5/10 [00:00<00:00, 604.65 it/sec, obj=1.79e+5]
INFO - 10:54:01: 60%|██████ | 6/10 [00:00<00:00, 644.98 it/sec, obj=2.23e+5]
INFO - 10:54:01: 70%|███████ | 7/10 [00:00<00:00, 679.32 it/sec, obj=2.68e+5]
INFO - 10:54:01: 80%|████████ | 8/10 [00:00<00:00, 706.28 it/sec, obj=3.13e+5]
INFO - 10:54:01: 90%|█████████ | 9/10 [00:00<00:00, 728.22 it/sec, obj=3.57e+5]
INFO - 10:54:01: 100%|██████████| 10/10 [00:00<00:00, 745.39 it/sec, obj=4.02e+5]
INFO - 10:54:01: Optimization result:
INFO - 10:54:01: Optimizer info:
INFO - 10:54:01: Status: None
INFO - 10:54:01: Message: None
INFO - 10:54:01: Number of calls to the objective function by the optimizer: 10
INFO - 10:54:01: Solution:
INFO - 10:54:01: Objective: 100.08573388203513
INFO - 10:54:01: Design space:
INFO - 10:54:01: +--------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:01: +--------------+-------------+-------+-------------+-------+
INFO - 10:54:01: | thick_panels | 1 | 1 | 20 | float |
INFO - 10:54:01: | sweep | 10 | 10 | 35 | float |
INFO - 10:54:01: | forces | -1000 | -1000 | 1000 | float |
INFO - 10:54:01: +--------------+-------------+-------+-------------+-------+
INFO - 10:54:01: *** End DOEScenario execution (time: 0:00:00.025709) ***
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.2.0/lib/python3.9/site-packages/gemseo/algos/design_space.py:466: ComplexWarning: Casting complex values to real discards the imaginary part
self.__current_value[name] = array_value.astype(
INFO - 10:54:01:
INFO - 10:54:01: *** Start DOEScenario execution ***
INFO - 10:54:01: DOEScenario
INFO - 10:54:01: Disciplines: Mission
INFO - 10:54:01: MDO formulation: DisciplinaryOpt
INFO - 10:54:01: Optimization problem:
INFO - 10:54:01: minimize range(drag, lift, mass, reserve_fact)
INFO - 10:54:01: with respect to drag, lift, mass, reserve_fact
INFO - 10:54:01: over the design space:
INFO - 10:54:01: +--------------+-------------+--------+-------------+-------+
INFO - 10:54:01: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:01: +--------------+-------------+--------+-------------+-------+
INFO - 10:54:01: | drag | 100 | 340 | 1000 | float |
INFO - 10:54:01: | lift | 0.1 | 0.5 | 1 | float |
INFO - 10:54:01: | mass | 100000 | 100000 | 500000 | float |
INFO - 10:54:01: | reserve_fact | -1000 | 0 | 1000 | float |
INFO - 10:54:01: +--------------+-------------+--------+-------------+-------+
INFO - 10:54:01: Solving optimization problem with algorithm DiagonalDOE:
INFO - 10:54:01: 10%|█ | 1/10 [00:00<00:00, 234.69 it/sec, obj=8e+3+j]
INFO - 10:54:01: 20%|██ | 2/10 [00:00<00:00, 371.28 it/sec, obj=5.54e+3+j]
INFO - 10:54:01: 30%|███ | 3/10 [00:00<00:00, 464.45 it/sec, obj=4.24e+3+j]
INFO - 10:54:01: 40%|████ | 4/10 [00:00<00:00, 528.53 it/sec, obj=3.43e+3+j]
INFO - 10:54:01: 50%|█████ | 5/10 [00:00<00:00, 579.80 it/sec, obj=2.88e+3+j]
INFO - 10:54:01: 60%|██████ | 6/10 [00:00<00:00, 620.93 it/sec, obj=2.48e+3+j]
INFO - 10:54:01: 70%|███████ | 7/10 [00:00<00:00, 653.19 it/sec, obj=2.18e+3+j]
INFO - 10:54:01: 80%|████████ | 8/10 [00:00<00:00, 677.25 it/sec, obj=1.95e+3+j]
INFO - 10:54:01: 90%|█████████ | 9/10 [00:00<00:00, 696.25 it/sec, obj=1.76e+3+j]
INFO - 10:54:01: 100%|██████████| 10/10 [00:00<00:00, 715.53 it/sec, obj=1.6e+3+j]
INFO - 10:54:01: Optimization result:
INFO - 10:54:01: Optimizer info:
INFO - 10:54:01: Status: None
INFO - 10:54:01: Message: None
INFO - 10:54:01: Number of calls to the objective function by the optimizer: 10
INFO - 10:54:01: Solution:
INFO - 10:54:01: Objective: (1600+0j)
INFO - 10:54:01: Design space:
INFO - 10:54:01: +--------------+-------------+--------+-------------+-------+
INFO - 10:54:01: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:01: +--------------+-------------+--------+-------------+-------+
INFO - 10:54:01: | drag | 100 | 1000 | 1000 | float |
INFO - 10:54:01: | lift | 0.1 | 1 | 1 | float |
INFO - 10:54:01: | mass | 100000 | 500000 | 500000 | float |
INFO - 10:54:01: | reserve_fact | -1000 | 1000 | 1000 | float |
INFO - 10:54:01: +--------------+-------------+--------+-------------+-------+
INFO - 10:54:01: *** End DOEScenario execution (time: 0:00:00.027015) ***
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)

Create an MDO scenario¶
Lastly, we create an 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 - 10:54:02: 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 - 10:54:02:
INFO - 10:54:02: *** Start MDOScenario execution ***
INFO - 10:54:02: MDOScenario
INFO - 10:54:02: Disciplines: sdm_Aerodynamics sdm_Mission sdm_Structure
INFO - 10:54:02: MDO formulation: MDF
INFO - 10:54:02: Optimization problem:
INFO - 10:54:02: minimize -range(thick_airfoils, thick_panels, sweep)
INFO - 10:54:02: with respect to sweep, thick_airfoils, thick_panels
INFO - 10:54:02: subject to constraints:
INFO - 10:54:02: c_lift(thick_airfoils, thick_panels, sweep) <= [0.74554856]
INFO - 10:54:02: c_rf(thick_airfoils, thick_panels, sweep) == 0.49642016361892943
INFO - 10:54:02: over the design space:
INFO - 10:54:02: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:02: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:02: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:02: | thick_airfoils | 0 | 0.5 | 1 | float |
INFO - 10:54:02: | thick_panels | 0 | 0.5 | 1 | float |
INFO - 10:54:02: | sweep[0] | 0 | 0.5 | 1 | float |
INFO - 10:54:02: | sweep[1] | 0 | 0.5 | 1 | float |
INFO - 10:54:02: +----------------+-------------+-------+-------------+-------+
INFO - 10:54:02: Solving optimization problem with algorithm NLOPT_SLSQP:
INFO - 10:54:02: 1%| | 1/100 [00:00<00:02, 34.06 it/sec, obj=-.168]
INFO - 10:54:02: 2%|▏ | 2/100 [00:00<00:12, 8.10 it/sec, obj=-.172]
INFO - 10:54:02: 3%|▎ | 3/100 [00:00<00:10, 9.13 it/sec, obj=-.2]
INFO - 10:54:02: 4%|▍ | 4/100 [00:00<00:09, 9.68 it/sec, obj=-.302]
INFO - 10:54:02: 5%|▌ | 5/100 [00:00<00:09, 10.14 it/sec, obj=-.302]
INFO - 10:54:02: 6%|▌ | 6/100 [00:00<00:09, 10.11 it/sec, obj=-.303]
INFO - 10:54:02: 7%|▋ | 7/100 [00:00<00:09, 10.23 it/sec, obj=-.304]
INFO - 10:54:02: 8%|▊ | 8/100 [00:00<00:08, 10.51 it/sec, obj=-.309]
INFO - 10:54:03: 9%|▉ | 9/100 [00:00<00:08, 10.69 it/sec, obj=-.309]
ERROR - 10:54:03: NLopt run failed: NLopt roundoff-limited, RoundoffLimited
Traceback (most recent call last):
File "/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.2.0/lib/python3.9/site-packages/gemseo/algos/opt/lib_nlopt.py", line 498, in _run
nlopt_problem.optimize(x_0.real)
File "/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.2.0/lib/python3.9/site-packages/nlopt/nlopt.py", line 335, in optimize
return _nlopt.opt_optimize(self, *args)
nlopt.RoundoffLimited: NLopt roundoff-limited
INFO - 10:54:03: 10%|█ | 10/100 [00:00<00:07, 11.83 it/sec, obj=-.309]
INFO - 10:54:03: Optimization result:
INFO - 10:54:03: Optimizer info:
INFO - 10:54:03: Status: None
INFO - 10:54:03: Message: GEMSEO Stopped the driver
INFO - 10:54:03: Number of calls to the objective function by the optimizer: 11
INFO - 10:54:03: Solution:
INFO - 10:54:03: The solution is feasible.
INFO - 10:54:03: Objective: -0.30937609894434914
INFO - 10:54:03: Standardized constraints:
INFO - 10:54:03: [c_lift+offset] = [-0.42031165]
INFO - 10:54:03: [c_rf-0.49642016361892943] = -2.7755575615628914e-16
INFO - 10:54:03: Design space:
INFO - 10:54:03: +----------------+-------------+--------------------+-------------+-------+
INFO - 10:54:03: | Name | Lower bound | Value | Upper bound | Type |
INFO - 10:54:03: +----------------+-------------+--------------------+-------------+-------+
INFO - 10:54:03: | thick_airfoils | 0 | 0.3004770228426673 | 1 | float |
INFO - 10:54:03: | thick_panels | 0 | 1 | 1 | float |
INFO - 10:54:03: | sweep[0] | 0 | 1 | 1 | float |
INFO - 10:54:03: | sweep[1] | 0 | 1 | 1 | float |
INFO - 10:54:03: +----------------+-------------+--------------------+-------------+-------+
INFO - 10:54:03: *** End MDOScenario execution (time: 0:00:00.861961) ***
{'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)
<gemseo.post.opt_history_view.OptHistoryView object at 0x7efd341c87c0>
Total running time of the script: (0 minutes 2.666 seconds)





