.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/mdo/plot_sobieski_use_case.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_mdo_plot_sobieski_use_case.py: Application: Sobieski's Super-Sonic Business Jet (MDO) ====================================================== .. GENERATED FROM PYTHON SOURCE LINES 26-59 This section describes how to setup and solve the MDO problem relative to the :ref:`Sobieski test case ` with |g|. .. seealso:: To begin with a more simple MDO problem, and have a detailed description of how to plug a test case to |g|, see :ref:`sphx_glr_examples_mdo_plot_sellar.py`. .. _sobieski_use_case: Solving with an :ref:`MDF formulation ` -------------------------------------------------------- In this example, we solve the range optimization using the following :ref:`MDF formulation `: - The :ref:`MDF formulation ` couples all the disciplines during the :ref:`mda` at each optimization iteration. - All the :term:`design variables` are equally treated, concatenated in a single vector and given to a single :term:`optimization algorithm` as the unknowns of the problem. - There is no specific :term:`constraint` due to the :ref:`MDF formulation `. - Only the design :term:`constraints` :math:`g\_1`, :math:`g\_2` and :math:`g\_3` are added to the problem. - The :term:`objective function` is the range (the :math:`y\_4` variable in the model), computed after the :ref:`mda`. Imports ------- All the imports needed for the tutorials are performed here. Note that some of the imports are related to the Python 2/3 compatibility. .. GENERATED FROM PYTHON SOURCE LINES 59-71 .. code-block:: Python from __future__ import annotations from gemseo import create_discipline from gemseo import create_scenario from gemseo import get_available_formulations from gemseo.core.derivatives.jacobian_assembly import JacobianAssembly from gemseo.problems.mdo.sobieski.core.design_space import SobieskiDesignSpace from gemseo.settings.mda import MDAGaussSeidel_Settings from gemseo.settings.opt import NLOPT_SLSQP_Settings from gemseo.utils.discipline import get_all_inputs from gemseo.utils.discipline import get_all_outputs .. GENERATED FROM PYTHON SOURCE LINES 72-78 Step 1: :class:`.Discipline` creation. -------------------------------------- To build the scenario, we first instantiate the disciplines. Here, the disciplines themselves have already been developed and interfaced with |g| (see :ref:`benchmark_problems`). .. GENERATED FROM PYTHON SOURCE LINES 78-86 .. code-block:: Python disciplines = create_discipline([ "SobieskiPropulsion", "SobieskiAerodynamics", "SobieskiMission", "SobieskiStructure", ]) .. GENERATED FROM PYTHON SOURCE LINES 87-94 .. tip:: For the disciplines that are not interfaced with |g|, the |g|'s :mod:`~gemseo` module eases the creation of disciplines without having to import them. See :ref:`api`. .. GENERATED FROM PYTHON SOURCE LINES 96-112 Step 2: :class:`.Scenario` creation. ------------------------------------ The scenario delegates the creation of the optimization problem to the :ref:`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, as ``design_space.txt``) defines the unknowns of the optimization problem, and their bounds. It contains all the design variables needed by the :ref:`MDF formulation `. It can be imported from a text file, or created from scratch with the methods :func:`.create_design_space` and :meth:`.DesignSpace.add_variable`. In this case, we will create it directly from the API. .. GENERATED FROM PYTHON SOURCE LINES 112-113 .. code-block:: Python design_space = SobieskiDesignSpace() .. GENERATED FROM PYTHON SOURCE LINES 114-147 .. code:: vi design_space.csv 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 :ref:`MDO formulations ` are located in the **gemseo.formulations** package, see :ref:`extending-gemseo` for extending GEMSEO with other formulations. - The ``formulation`` class name (here, ``"MDF"``) shall be passed to the scenario to select them. - The list of available formulations can be obtained by using :func:`.get_available_formulations`. .. GENERATED FROM PYTHON SOURCE LINES 147-148 .. code-block:: Python get_available_formulations() .. rst-class:: sphx-glr-script-out .. code-block:: none ['BiLevel', 'BiLevelBCD', 'DisciplinaryOpt', 'IDF', 'MDF'] .. GENERATED FROM PYTHON SOURCE LINES 149-153 - :math:`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 :meth:`~gemseo.utils.discipline.get_all_outputs`: .. GENERATED FROM PYTHON SOURCE LINES 153-155 .. code-block:: Python get_all_outputs(disciplines) get_all_inputs(disciplines) .. rst-class:: sphx-glr-script-out .. code-block:: none ['c_0', 'c_1', 'c_2', 'c_3', 'c_4', 'x_1', 'x_2', 'x_3', 'x_shared', 'y_12', 'y_14', 'y_21', 'y_23', 'y_24', 'y_31', 'y_32', 'y_34'] .. GENERATED FROM PYTHON SOURCE LINES 156-163 From these :class:`.Discipline`, design space filename, :ref:`MDO formulation ` name and objective function name, we build the scenario. During the instantiation of the scenario, we provide some options for the MDF formulations. The MDF formulation includes an MDA, and thus one of the settings of the formulation is ``main_mda_settings``, which configures the solver for the strong couplings. .. GENERATED FROM PYTHON SOURCE LINES 163-178 .. code-block:: Python main_mda_settings = MDAGaussSeidel_Settings( tolerance=1e-14, max_mda_iter=50, warm_start=True, use_lu_fact=False, linear_solver_tolerance=1e-14, ) scenario = create_scenario( disciplines, "y_4", design_space, formulation_name="MDF", maximize_objective=True, main_mda_settings=main_mda_settings, ) .. GENERATED FROM PYTHON SOURCE LINES 179-194 The range function (:math:`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``. Scenario options ~~~~~~~~~~~~~~~~ We may provide additional options to the scenario: **Function derivatives.** As analytical disciplinary derivatives are available for 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 it is the method :meth:`.BaseScenario.set_differentiation_method`: .. GENERATED FROM PYTHON SOURCE LINES 194-195 .. code-block:: Python scenario.set_differentiation_method() .. GENERATED FROM PYTHON SOURCE LINES 196-222 The default behavior uses the analytical derivatives defined in :meth:`.Discipline._compute_jacobian`. Otherwise, the finite differences method can be set as follows: .. code:: scenario.set_differentiation_method("finite_differences",1e-7) It is also possible to differentiate functions by means of the :term:`complex step` method: .. code:: 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 :meth:`~gemseo.utils.discipline.get_all_outputs`. The formulation has a powerful feature to automatically dispatch the constraints (:math:`g\_1, g\_2, g\_3`) and plug them to the optimizers depending on the formulation. To do that, we use the method :meth:`.BaseScenario.add_constraint`: .. GENERATED FROM PYTHON SOURCE LINES 223-225 .. code-block:: Python for constraint in ["g_1", "g_2", "g_3"]: scenario.add_constraint(constraint, constraint_type="ineq") .. GENERATED FROM PYTHON SOURCE LINES 226-241 Step 3: Execution and visualization of the results -------------------------------------------------- The scenario is executed from an optimization algorithm name (see :ref:`gen_opt_algos`), a maximum number of iterations and possibly a few options. The maximum number of iterations and the options can be passed either as keyword arguments e.g. ``scenario.execute(algo_name="NLOPT_SLSQP", max_iter=10, ftol_rel=1e-6)`` or as a Pydantic model of settings, e.g. ``scenario.execute(NLOPT_SLSQP_Settings(max_iter=10, ftol_rel=1e-6))`` where the Pydantic model ``NLOPT_SLSQP_Settings`` is imported from ``gemseo.settings.opt``. In this example, we use the Pydantic model: .. GENERATED FROM PYTHON SOURCE LINES 241-248 .. code-block:: Python slsqp_settings = NLOPT_SLSQP_Settings( max_iter=10, ftol_rel=1e-10, ineq_tolerance=2e-3, normalize_design_space=True, ) scenario.execute(slsqp_settings) .. rst-class:: sphx-glr-script-out .. code-block:: none INFO - 16:25:04: *** Start MDOScenario execution *** INFO - 16:25:04: MDOScenario INFO - 16:25:04: Disciplines: SobieskiAerodynamics SobieskiMission SobieskiPropulsion SobieskiStructure INFO - 16:25:04: MDO formulation: MDF INFO - 16:25:04: Optimization problem: INFO - 16:25:04: minimize -y_4(x_shared, x_1, x_2, x_3) INFO - 16:25:04: with respect to x_1, x_2, x_3, x_shared INFO - 16:25:04: under the inequality constraints INFO - 16:25:04: g_1(x_shared, x_1, x_2, x_3) <= 0 INFO - 16:25:04: g_2(x_shared, x_1, x_2, x_3) <= 0 INFO - 16:25:04: g_3(x_shared, x_1, x_2, x_3) <= 0 INFO - 16:25:04: over the design space: INFO - 16:25:04: +-------------+-------------+-------+-------------+-------+ INFO - 16:25:04: | Name | Lower bound | Value | Upper bound | Type | INFO - 16:25:04: +-------------+-------------+-------+-------------+-------+ INFO - 16:25:04: | x_shared[0] | 0.01 | 0.05 | 0.09 | float | INFO - 16:25:04: | x_shared[1] | 30000 | 45000 | 60000 | float | INFO - 16:25:04: | x_shared[2] | 1.4 | 1.6 | 1.8 | float | INFO - 16:25:04: | x_shared[3] | 2.5 | 5.5 | 8.5 | float | INFO - 16:25:04: | x_shared[4] | 40 | 55 | 70 | float | INFO - 16:25:04: | x_shared[5] | 500 | 1000 | 1500 | float | INFO - 16:25:04: | x_1[0] | 0.1 | 0.25 | 0.4 | float | INFO - 16:25:04: | x_1[1] | 0.75 | 1 | 1.25 | float | INFO - 16:25:04: | x_2 | 0.75 | 1 | 1.25 | float | INFO - 16:25:04: | x_3 | 0.1 | 0.5 | 1 | float | INFO - 16:25:04: +-------------+-------------+-------+-------------+-------+ INFO - 16:25:04: Solving optimization problem with algorithm NLOPT_SLSQP: INFO - 16:25:04: 10%|█ | 1/10 [00:00<00:00, 26.22 it/sec, feas=False, obj=-536] INFO - 16:25:04: 20%|██ | 2/10 [00:00<00:00, 30.76 it/sec, feas=False, obj=-2.12e+3] INFO - 16:25:04: 30%|███ | 3/10 [00:00<00:00, 32.35 it/sec, feas=True, obj=-3.46e+3] INFO - 16:25:04: 40%|████ | 4/10 [00:00<00:00, 33.63 it/sec, feas=False, obj=-4.45e+3] INFO - 16:25:04: 50%|█████ | 5/10 [00:00<00:00, 38.47 it/sec, feas=False, obj=-4.18e+3] INFO - 16:25:04: 60%|██████ | 6/10 [00:00<00:00, 42.68 it/sec, feas=False, obj=-3.86e+3] INFO - 16:25:04: 70%|███████ | 7/10 [00:00<00:00, 42.01 it/sec, feas=False, obj=-3.69e+3] INFO - 16:25:04: 80%|████████ | 8/10 [00:00<00:00, 41.01 it/sec, feas=True, obj=-3.96e+3] INFO - 16:25:04: 90%|█████████ | 9/10 [00:00<00:00, 40.76 it/sec, feas=True, obj=-3.96e+3] INFO - 16:25:04: 100%|██████████| 10/10 [00:00<00:00, 40.62 it/sec, feas=True, obj=-3.96e+3] INFO - 16:25:04: Optimization result: INFO - 16:25:04: Optimizer info: INFO - 16:25:04: Status: None INFO - 16:25:04: Message: Maximum number of iterations reached. GEMSEO stopped the driver. INFO - 16:25:04: Solution: INFO - 16:25:04: The solution is feasible. INFO - 16:25:04: Objective: -3964.170448501361 INFO - 16:25:04: Standardized constraints: INFO - 16:25:04: g_1 = [-0.01816104 -0.03341834 -0.04430538 -0.05188028 -0.05736466 -0.13720865 INFO - 16:25:04: -0.10279135] INFO - 16:25:04: g_2 = 3.630903829798804e-05 INFO - 16:25:04: g_3 = [-0.76773712 -0.23226288 0.00083037 -0.183255 ] INFO - 16:25:04: Design space: INFO - 16:25:04: +-------------+-------------+---------------------+-------------+-------+ INFO - 16:25:04: | Name | Lower bound | Value | Upper bound | Type | INFO - 16:25:04: +-------------+-------------+---------------------+-------------+-------+ INFO - 16:25:04: | x_shared[0] | 0.01 | 0.06000907725957451 | 0.09 | float | INFO - 16:25:04: | x_shared[1] | 30000 | 60000 | 60000 | float | INFO - 16:25:04: | x_shared[2] | 1.4 | 1.4 | 1.8 | float | INFO - 16:25:04: | x_shared[3] | 2.5 | 2.5 | 8.5 | float | INFO - 16:25:04: | x_shared[4] | 40 | 70 | 70 | float | INFO - 16:25:04: | x_shared[5] | 500 | 1500 | 1500 | float | INFO - 16:25:04: | x_1[0] | 0.1 | 0.4 | 0.4 | float | INFO - 16:25:04: | x_1[1] | 0.75 | 0.75 | 1.25 | float | INFO - 16:25:04: | x_2 | 0.75 | 0.75 | 1.25 | float | INFO - 16:25:04: | x_3 | 0.1 | 0.1563744859357456 | 1 | float | INFO - 16:25:04: +-------------+-------------+---------------------+-------------+-------+ INFO - 16:25:04: *** End MDOScenario execution *** .. GENERATED FROM PYTHON SOURCE LINES 249-256 Post-processing options ~~~~~~~~~~~~~~~~~~~~~~~ A whole variety of visualizations may be displayed for both MDO and DOE scenarios. These features are illustrated on the SSBJ use case in :ref:`post_processing`. To visualize the optimization history: .. GENERATED FROM PYTHON SOURCE LINES 256-258 .. code-block:: Python scenario.post_process(post_name="OptHistoryView", save=False, show=True) .. rst-class:: sphx-glr-horizontal * .. image-sg:: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_001.png :alt: Evolution of the optimization variables :srcset: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_001.png :class: sphx-glr-multi-img * .. image-sg:: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_002.png :alt: Evolution of the objective value :srcset: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_002.png :class: sphx-glr-multi-img * .. image-sg:: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_003.png :alt: Evolution of the distance to the optimum :srcset: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_003.png :class: sphx-glr-multi-img * .. image-sg:: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_004.png :alt: Evolution of the inequality constraints :srcset: /examples/mdo/images/sphx_glr_plot_sobieski_use_case_004.png :class: sphx-glr-multi-img .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 259-267 Influence of gradient computation method on performance ------------------------------------------------------- As mentioned in :ref:`jacobian_assembly`, several methods are available in order to perform the gradient computations: classical finite differences, complex step and :ref:`mda` linearization in direct or adjoint mode. These modes are automatically selected by |g| to minimize the CPU time. Yet, they can be forced on demand in each :ref:`mda`: .. GENERATED FROM PYTHON SOURCE LINES 267-269 .. code-block:: Python scenario.formulation.mda.linearization_mode = JacobianAssembly.DerivationMode.DIRECT scenario.formulation.mda.matrix_type = JacobianAssembly.JacobianType.LINEAR_OPERATOR .. GENERATED FROM PYTHON SOURCE LINES 270-275 The method used to solve the adjoint or direct linear problem may also be selected. |g| can either assemble a sparse residual Jacobian matrix of the :ref:`mda` from the disciplines matrices. This has the advantage that LU factorizations may be stored to solve multiple right hand sides problems in a cheap way. But this requires extra memory. .. GENERATED FROM PYTHON SOURCE LINES 275-277 .. code-block:: Python scenario.formulation.mda.matrix_type = JacobianAssembly.JacobianType.MATRIX scenario.formulation.mda.use_lu_fact = True .. GENERATED FROM PYTHON SOURCE LINES 278-282 Alternatively, |g| can implicitly create a matrix-vector product operator, which is sufficient for GMRES-like solvers. It avoids to create an additional data structure. This can also be mandatory if the disciplines do not provide full Jacobian matrices but only matrix-vector product operators. .. GENERATED FROM PYTHON SOURCE LINES 282-283 .. code-block:: Python scenario.formulation.mda.matrix_type = JacobianAssembly.JacobianType.LINEAR_OPERATOR .. GENERATED FROM PYTHON SOURCE LINES 284-305 The next table shows the performance of each method for solving the Sobieski use case with :ref:`MDF ` and :ref:`IDF ` formulations. The efficiency of linearization is clearly visible as it takes from 10 to 20 times less CPU time to compute analytic derivatives of an :ref:`mda` compared to finite difference and complex step. For :ref:`IDF `, improvements are less consequent, but direct linearization is more than 2.5 times faster than other methods. .. tabularcolumns:: |l|c|c| +-----------------------+------------------------------+------------------------------+ | | Execution time (s) | + Derivation Method +------------------------------+------------------------------+ | | :ref:`MDF ` | :ref:`IDF ` | +=======================+==============================+==============================+ | Finite differences | 8.22 | 1.93 | +-----------------------+------------------------------+------------------------------+ | Complex step | 18.11 | 2.07 | +-----------------------+------------------------------+------------------------------+ | Linearized (direct) | 0.90 | 0.68 | +-----------------------+------------------------------+------------------------------+ .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.697 seconds) .. _sphx_glr_download_examples_mdo_plot_sobieski_use_case.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_sobieski_use_case.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_sobieski_use_case.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_sobieski_use_case.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_