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.mdo.aerostructure.aerostructure_design_space import (
AerostructureDesignSpace,
)
from gemseo.problems.mdo.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 BaseFullCache
datasets
based on a DiagonalDOE
.
disciplines = create_discipline(["Aerodynamics", "Structure", "Mission"])
datasets = []
for discipline in disciplines:
design_space = AerostructureDesignSpace()
design_space.filter(discipline.io.input_grammar.names)
output_names = iter(discipline.io.output_grammar.names)
scenario = create_scenario(
discipline,
next(output_names),
design_space,
formulation_name="DisciplinaryOpt",
scenario_type="DOE",
)
for output_name in output_names:
scenario.add_observable(output_name)
scenario.execute(algo_name="DiagonalDOE", n_samples=10)
datasets.append(scenario.to_dataset(name=discipline.name, opt_naming=False))
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/stable/lib/python3.9/site-packages/gemseo/algos/design_space.py:424: ComplexWarning: Casting complex values to real discards the imaginary part
self.__current_value[name] = array_value.astype(
INFO - 08:36:54:
INFO - 08:36:54: *** Start DOEScenario execution ***
INFO - 08:36:54: DOEScenario
INFO - 08:36:54: Disciplines: Aerodynamics
INFO - 08:36:54: MDO formulation: DisciplinaryOpt
INFO - 08:36:54: Optimization problem:
INFO - 08:36:54: minimize drag(thick_airfoils, sweep, displ)
INFO - 08:36:54: with respect to displ, sweep, thick_airfoils
INFO - 08:36:54: over the design space:
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | thick_airfoils | 5 | 15 | 25 | float |
INFO - 08:36:54: | sweep | 10 | 25 | 35 | float |
INFO - 08:36:54: | displ | -1000 | -700 | 1000 | float |
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: Solving optimization problem with algorithm DiagonalDOE:
INFO - 08:36:54: 10%|█ | 1/10 [00:00<00:00, 268.45 it/sec, obj=422]
INFO - 08:36:54: 20%|██ | 2/10 [00:00<00:00, 436.95 it/sec, obj=336]
INFO - 08:36:54: 30%|███ | 3/10 [00:00<00:00, 557.41 it/sec, obj=250]
INFO - 08:36:54: 40%|████ | 4/10 [00:00<00:00, 641.72 it/sec, obj=166]
INFO - 08:36:54: 50%|█████ | 5/10 [00:00<00:00, 710.39 it/sec, obj=82.3]
INFO - 08:36:54: 60%|██████ | 6/10 [00:00<00:00, 766.74 it/sec, obj=-0.0983]
INFO - 08:36:54: 70%|███████ | 7/10 [00:00<00:00, 814.16 it/sec, obj=-81.6]
INFO - 08:36:54: 80%|████████ | 8/10 [00:00<00:00, 854.13 it/sec, obj=-162]
INFO - 08:36:54: 90%|█████████ | 9/10 [00:00<00:00, 877.20 it/sec, obj=-242]
INFO - 08:36:54: 100%|██████████| 10/10 [00:00<00:00, 903.24 it/sec, obj=-320]
INFO - 08:36:54: Optimization result:
INFO - 08:36:54: Optimizer info:
INFO - 08:36:54: Status: None
INFO - 08:36:54: Message: None
INFO - 08:36:54: Number of calls to the objective function by the optimizer: 10
INFO - 08:36:54: Solution:
INFO - 08:36:54: Objective: -319.99905478395067
INFO - 08:36:54: Design space:
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | thick_airfoils | 5 | 25 | 25 | float |
INFO - 08:36:54: | sweep | 10 | 35 | 35 | float |
INFO - 08:36:54: | displ | -1000 | 1000 | 1000 | float |
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: *** End DOEScenario execution (time: 0:00:00.016423) ***
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/stable/lib/python3.9/site-packages/gemseo/algos/design_space.py:424: ComplexWarning: Casting complex values to real discards the imaginary part
self.__current_value[name] = array_value.astype(
INFO - 08:36:54:
INFO - 08:36:54: *** Start DOEScenario execution ***
INFO - 08:36:54: DOEScenario
INFO - 08:36:54: Disciplines: Structure
INFO - 08:36:54: MDO formulation: DisciplinaryOpt
INFO - 08:36:54: Optimization problem:
INFO - 08:36:54: minimize mass(thick_panels, sweep, forces)
INFO - 08:36:54: with respect to forces, sweep, thick_panels
INFO - 08:36:54: over the design space:
INFO - 08:36:54: +--------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:54: +--------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | thick_panels | 1 | 3 | 20 | float |
INFO - 08:36:54: | sweep | 10 | 25 | 35 | float |
INFO - 08:36:54: | forces | -1000 | 400 | 1000 | float |
INFO - 08:36:54: +--------------+-------------+-------+-------------+-------+
INFO - 08:36:54: Solving optimization problem with algorithm DiagonalDOE:
INFO - 08:36:54: 10%|█ | 1/10 [00:00<00:00, 284.51 it/sec, obj=100]
INFO - 08:36:54: 20%|██ | 2/10 [00:00<00:00, 455.78 it/sec, obj=4.48e+4]
INFO - 08:36:54: 30%|███ | 3/10 [00:00<00:00, 577.36 it/sec, obj=8.94e+4]
INFO - 08:36:54: 40%|████ | 4/10 [00:00<00:00, 668.36 it/sec, obj=1.34e+5]
INFO - 08:36:54: 50%|█████ | 5/10 [00:00<00:00, 738.15 it/sec, obj=1.79e+5]
INFO - 08:36:54: 60%|██████ | 6/10 [00:00<00:00, 791.60 it/sec, obj=2.23e+5]
INFO - 08:36:54: 70%|███████ | 7/10 [00:00<00:00, 832.37 it/sec, obj=2.68e+5]
INFO - 08:36:54: 80%|████████ | 8/10 [00:00<00:00, 869.22 it/sec, obj=3.13e+5]
INFO - 08:36:54: 90%|█████████ | 9/10 [00:00<00:00, 900.47 it/sec, obj=3.57e+5]
INFO - 08:36:54: 100%|██████████| 10/10 [00:00<00:00, 928.99 it/sec, obj=4.02e+5]
INFO - 08:36:54: Optimization result:
INFO - 08:36:54: Optimizer info:
INFO - 08:36:54: Status: None
INFO - 08:36:54: Message: None
INFO - 08:36:54: Number of calls to the objective function by the optimizer: 10
INFO - 08:36:54: Solution:
INFO - 08:36:54: Objective: 100.08573388203513
INFO - 08:36:54: Design space:
INFO - 08:36:54: +--------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:54: +--------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | thick_panels | 1 | 1 | 20 | float |
INFO - 08:36:54: | sweep | 10 | 10 | 35 | float |
INFO - 08:36:54: | forces | -1000 | -1000 | 1000 | float |
INFO - 08:36:54: +--------------+-------------+-------+-------------+-------+
INFO - 08:36:54: *** End DOEScenario execution (time: 0:00:00.015943) ***
/home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/stable/lib/python3.9/site-packages/gemseo/algos/design_space.py:424: ComplexWarning: Casting complex values to real discards the imaginary part
self.__current_value[name] = array_value.astype(
INFO - 08:36:54:
INFO - 08:36:54: *** Start DOEScenario execution ***
INFO - 08:36:54: DOEScenario
INFO - 08:36:54: Disciplines: Mission
INFO - 08:36:54: MDO formulation: DisciplinaryOpt
INFO - 08:36:54: Optimization problem:
INFO - 08:36:54: minimize range(drag, lift, mass, reserve_fact)
INFO - 08:36:54: with respect to drag, lift, mass, reserve_fact
INFO - 08:36:54: over the design space:
INFO - 08:36:54: +--------------+-------------+--------+-------------+-------+
INFO - 08:36:54: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:54: +--------------+-------------+--------+-------------+-------+
INFO - 08:36:54: | drag | 100 | 340 | 1000 | float |
INFO - 08:36:54: | lift | 0.1 | 0.5 | 1 | float |
INFO - 08:36:54: | mass | 100000 | 100000 | 500000 | float |
INFO - 08:36:54: | reserve_fact | -1000 | 0 | 1000 | float |
INFO - 08:36:54: +--------------+-------------+--------+-------------+-------+
INFO - 08:36:54: Solving optimization problem with algorithm DiagonalDOE:
INFO - 08:36:54: 10%|█ | 1/10 [00:00<00:00, 290.12 it/sec, obj=8e+3+0j]
INFO - 08:36:54: 20%|██ | 2/10 [00:00<00:00, 466.37 it/sec, obj=5.54e+3+0j]
INFO - 08:36:54: 30%|███ | 3/10 [00:00<00:00, 586.78 it/sec, obj=4.24e+3+0j]
INFO - 08:36:54: 40%|████ | 4/10 [00:00<00:00, 672.60 it/sec, obj=3.43e+3+0j]
INFO - 08:36:54: 50%|█████ | 5/10 [00:00<00:00, 720.32 it/sec, obj=2.88e+3+0j]
INFO - 08:36:54: 60%|██████ | 6/10 [00:00<00:00, 771.67 it/sec, obj=2.48e+3+0j]
INFO - 08:36:54: 70%|███████ | 7/10 [00:00<00:00, 814.07 it/sec, obj=2.18e+3+0j]
INFO - 08:36:54: 80%|████████ | 8/10 [00:00<00:00, 849.59 it/sec, obj=1.95e+3+0j]
INFO - 08:36:54: 90%|█████████ | 9/10 [00:00<00:00, 879.99 it/sec, obj=1.76e+3+0j]
INFO - 08:36:54: 100%|██████████| 10/10 [00:00<00:00, 906.01 it/sec, obj=(1600+0j)]
INFO - 08:36:54: Optimization result:
INFO - 08:36:54: Optimizer info:
INFO - 08:36:54: Status: None
INFO - 08:36:54: Message: None
INFO - 08:36:54: Number of calls to the objective function by the optimizer: 10
INFO - 08:36:54: Solution:
INFO - 08:36:54: Objective: (1600+0j)
INFO - 08:36:54: Design space:
INFO - 08:36:54: +--------------+-------------+--------+-------------+-------+
INFO - 08:36:54: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:54: +--------------+-------------+--------+-------------+-------+
INFO - 08:36:54: | drag | 100 | 1000 | 1000 | float |
INFO - 08:36:54: | lift | 0.1 | 1 | 1 | float |
INFO - 08:36:54: | mass | 100000 | 500000 | 500000 | float |
INFO - 08:36:54: | reserve_fact | -1000 | 1000 | 1000 | float |
INFO - 08:36:54: +--------------+-------------+--------+-------------+-------+
INFO - 08:36:54: *** End DOEScenario execution (time: 0:00:00.016727) ***
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 - 08:36:54: 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_name="NLOPT_SLSQP", max_iter=100)
INFO - 08:36:54:
INFO - 08:36:54: *** Start MDOScenario execution ***
INFO - 08:36:54: MDOScenario
INFO - 08:36:54: Disciplines: sdm_Aerodynamics sdm_Mission sdm_Structure
INFO - 08:36:54: MDO formulation: MDF
INFO - 08:36:54: Optimization problem:
INFO - 08:36:54: minimize -range(thick_airfoils, thick_panels, sweep)
INFO - 08:36:54: with respect to sweep, thick_airfoils, thick_panels
INFO - 08:36:54: subject to constraints:
INFO - 08:36:54: c_lift(thick_airfoils, thick_panels, sweep) <= [0.74554856]
INFO - 08:36:54: c_rf(thick_airfoils, thick_panels, sweep) == 0.49642016361892943
INFO - 08:36:54: over the design space:
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: | thick_airfoils | 0 | 0.5 | 1 | float |
INFO - 08:36:54: | thick_panels | 0 | 0.5 | 1 | float |
INFO - 08:36:54: | sweep[0] | 0 | 0.5 | 1 | float |
INFO - 08:36:54: | sweep[1] | 0 | 0.5 | 1 | float |
INFO - 08:36:54: +----------------+-------------+-------+-------------+-------+
INFO - 08:36:54: Solving optimization problem with algorithm NLOPT_SLSQP:
INFO - 08:36:54: 1%| | 1/100 [00:00<00:00, 103.15 it/sec, obj=-0.168]
INFO - 08:36:55: 2%|▏ | 2/100 [00:00<00:08, 11.62 it/sec, obj=-0.172]
INFO - 08:36:55: 3%|▎ | 3/100 [00:00<00:07, 13.54 it/sec, obj=-0.2]
INFO - 08:36:55: 4%|▍ | 4/100 [00:00<00:06, 14.55 it/sec, obj=-0.302]
INFO - 08:36:55: 5%|▌ | 5/100 [00:00<00:06, 14.95 it/sec, obj=-0.302]
INFO - 08:36:55: 6%|▌ | 6/100 [00:00<00:06, 15.59 it/sec, obj=-0.303]
INFO - 08:36:55: 7%|▋ | 7/100 [00:00<00:05, 16.08 it/sec, obj=-0.304]
INFO - 08:36:55: 8%|▊ | 8/100 [00:00<00:05, 16.47 it/sec, obj=-0.309]
INFO - 08:36:55: 9%|▉ | 9/100 [00:00<00:05, 16.84 it/sec, obj=-0.309]
INFO - 08:36:55: 10%|█ | 10/100 [00:00<00:05, 17.14 it/sec, obj=-0.309]
INFO - 08:36:55: 11%|█ | 11/100 [00:00<00:04, 18.82 it/sec, obj=Not evaluated]
INFO - 08:36:55: Optimization result:
INFO - 08:36:55: Optimizer info:
INFO - 08:36:55: Status: None
INFO - 08:36:55: Message: Successive iterates of the design variables are closer than xtol_rel or xtol_abs. GEMSEO stopped the driver.
INFO - 08:36:55: Number of calls to the objective function by the optimizer: 11
INFO - 08:36:55: Solution:
INFO - 08:36:55: The solution is feasible.
INFO - 08:36:55: Objective: -0.3093760989443488
INFO - 08:36:55: Standardized constraints:
INFO - 08:36:55: [c_lift+offset] = [-0.42031165]
INFO - 08:36:55: [c_rf-0.49642016361892943] = 0.0
INFO - 08:36:55: Design space:
INFO - 08:36:55: +----------------+-------------+--------------------+-------------+-------+
INFO - 08:36:55: | Name | Lower bound | Value | Upper bound | Type |
INFO - 08:36:55: +----------------+-------------+--------------------+-------------+-------+
INFO - 08:36:55: | thick_airfoils | 0 | 0.3004770228426635 | 1 | float |
INFO - 08:36:55: | thick_panels | 0 | 0.9999999999999978 | 1 | float |
INFO - 08:36:55: | sweep[0] | 0 | 0.9999999999999998 | 1 | float |
INFO - 08:36:55: | sweep[1] | 0 | 1 | 1 | float |
INFO - 08:36:55: +----------------+-------------+--------------------+-------------+-------+
INFO - 08:36:55: *** End MDOScenario execution (time: 0:00:00.590342) ***
We can post-process the results.
Here, we use the standard OptHistoryView
.
scenario.post_process(post_name="OptHistoryView", save=False, show=True)
<gemseo.post.opt_history_view.OptHistoryView object at 0x7f24f451f040>
Total running time of the script: (0 minutes 2.382 seconds)