.. 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:`sellar_mdo`. .. _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-72 .. code-block:: Python from __future__ import annotations from gemseo import configure_logger 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.utils.discipline import get_all_inputs from gemseo.utils.discipline import get_all_outputs configure_logger() .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 73-79 Step 1: Creation of :class:`.Discipline` ------------------------------------------- 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 79-87 .. code-block:: Python disciplines = create_discipline([ "SobieskiPropulsion", "SobieskiAerodynamics", "SobieskiMission", "SobieskiStructure", ]) .. GENERATED FROM PYTHON SOURCE LINES 88-95 .. tip:: For the disciplines that are not interfaced with |g|, the |g|'s :mod:`~gemseo` eases the creation of disciplines without having to import them. See :ref:`api`. .. GENERATED FROM PYTHON SOURCE LINES 97-113 Step 2: Creation of :class:`.Scenario` -------------------------------------- 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:`~gemseo.algos.design_space.DesignSpace.add_variable`. In this case, we will create it directly from the API. .. GENERATED FROM PYTHON SOURCE LINES 113-114 .. code-block:: Python design_space = SobieskiDesignSpace() .. GENERATED FROM PYTHON SOURCE LINES 115-148 .. 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`` classname (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 148-149 .. 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 150-154 - :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.disciplines.utils.get_all_outputs`: .. GENERATED FROM PYTHON SOURCE LINES 154-156 .. 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 157-160 From these :class:`~gemseo.core.discipline.Discipline`, design space filename, :ref:`MDO formulation ` name and objective function name, we build the scenario: .. GENERATED FROM PYTHON SOURCE LINES 160-167 .. code-block:: Python scenario = create_scenario( disciplines, "y_4", design_space, formulation_name="MDF", maximize_objective=True, ) .. rst-class:: sphx-glr-script-out .. code-block:: none WARNING - 11:43:21: Unsupported feature 'minItems' in JSONGrammar 'SobieskiMission_discipline_output' for property 'y_4' in conversion to SimpleGrammar. WARNING - 11:43:21: Unsupported feature 'maxItems' in JSONGrammar 'SobieskiMission_discipline_output' for property 'y_4' in conversion to SimpleGrammar. .. GENERATED FROM PYTHON SOURCE LINES 168-182 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 vailable 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 a method is to let the optimizer determine it: .. GENERATED FROM PYTHON SOURCE LINES 182-183 .. code-block:: Python scenario.set_differentiation_method() .. GENERATED FROM PYTHON SOURCE LINES 184-209 The default behavior of the optimizer triggers :term:`finite differences`. It corresponds to: .. code:: scenario.set_differentiation_method("finite_differences",1e-7) It it 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.disciplines.utils.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:`~gemseo.scenarios.scenario.Scenario.add_constraint`: .. GENERATED FROM PYTHON SOURCE LINES 210-212 .. code-block:: Python for constraint in ["g_1", "g_2", "g_3"]: scenario.add_constraint(constraint, constraint_type="ineq") .. GENERATED FROM PYTHON SOURCE LINES 213-227 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="SLSQP", max_iter=10, ftol_rel=1e-6)`` or as a Pydantic model of settings, e.g. ``scenario.execute(NLOPTSLSQPSettings(max_iter=10, ftol_rel=1e-6))`` where the Pydantic model ``NLOPTSLSQPSettings`` is imported from ``gemseo.settings.opt``. In this example, we do not use any option: .. GENERATED FROM PYTHON SOURCE LINES 227-228 .. code-block:: Python scenario.execute(algo_name="SLSQP", max_iter=10) .. rst-class:: sphx-glr-script-out .. code-block:: none INFO - 11:43:21: *** Start MDOScenario execution *** INFO - 11:43:21: MDOScenario INFO - 11:43:21: Disciplines: SobieskiAerodynamics SobieskiMission SobieskiPropulsion SobieskiStructure INFO - 11:43:21: MDO formulation: MDF INFO - 11:43:21: Optimization problem: INFO - 11:43:21: minimize -y_4(x_shared, x_1, x_2, x_3) INFO - 11:43:21: with respect to x_1, x_2, x_3, x_shared INFO - 11:43:21: subject to constraints: INFO - 11:43:21: g_1(x_shared, x_1, x_2, x_3) <= 0 INFO - 11:43:21: g_2(x_shared, x_1, x_2, x_3) <= 0 INFO - 11:43:21: g_3(x_shared, x_1, x_2, x_3) <= 0 INFO - 11:43:21: over the design space: INFO - 11:43:21: +-------------+-------------+-------+-------------+-------+ INFO - 11:43:21: | Name | Lower bound | Value | Upper bound | Type | INFO - 11:43:21: +-------------+-------------+-------+-------------+-------+ INFO - 11:43:21: | x_shared[0] | 0.01 | 0.05 | 0.09 | float | INFO - 11:43:21: | x_shared[1] | 30000 | 45000 | 60000 | float | INFO - 11:43:21: | x_shared[2] | 1.4 | 1.6 | 1.8 | float | INFO - 11:43:21: | x_shared[3] | 2.5 | 5.5 | 8.5 | float | INFO - 11:43:21: | x_shared[4] | 40 | 55 | 70 | float | INFO - 11:43:21: | x_shared[5] | 500 | 1000 | 1500 | float | INFO - 11:43:21: | x_1[0] | 0.1 | 0.25 | 0.4 | float | INFO - 11:43:21: | x_1[1] | 0.75 | 1 | 1.25 | float | INFO - 11:43:21: | x_2 | 0.75 | 1 | 1.25 | float | INFO - 11:43:21: | x_3 | 0.1 | 0.5 | 1 | float | INFO - 11:43:21: +-------------+-------------+-------+-------------+-------+ INFO - 11:43:21: Solving optimization problem with algorithm SLSQP: INFO - 11:43:21: 10%|█ | 1/10 [00:00<00:00, 23.11 it/sec, obj=-536] INFO - 11:43:21: 20%|██ | 2/10 [00:00<00:00, 17.89 it/sec, obj=-2.12e+3] WARNING - 11:43:21: MDAJacobi has reached its maximum number of iterations, but the normalized residual norm 5.741449586530469e-06 is still above the tolerance 1e-06. INFO - 11:43:21: 30%|███ | 3/10 [00:00<00:00, 14.68 it/sec, obj=-3.46e+3] INFO - 11:43:21: 40%|████ | 4/10 [00:00<00:00, 14.08 it/sec, obj=-3.96e+3] INFO - 11:43:21: 50%|█████ | 5/10 [00:00<00:00, 14.34 it/sec, obj=-4.61e+3] INFO - 11:43:21: 60%|██████ | 6/10 [00:00<00:00, 15.30 it/sec, obj=-4.5e+3] INFO - 11:43:21: 70%|███████ | 7/10 [00:00<00:00, 15.84 it/sec, obj=-4.26e+3] INFO - 11:43:21: 80%|████████ | 8/10 [00:00<00:00, 16.25 it/sec, obj=-4.11e+3] INFO - 11:43:22: 90%|█████████ | 9/10 [00:00<00:00, 16.61 it/sec, obj=-4.02e+3] INFO - 11:43:22: 100%|██████████| 10/10 [00:00<00:00, 16.89 it/sec, obj=-3.99e+3] INFO - 11:43:22: Optimization result: INFO - 11:43:22: Optimizer info: INFO - 11:43:22: Status: None INFO - 11:43:22: Message: Maximum number of iterations reached. GEMSEO stopped the driver. INFO - 11:43:22: Number of calls to the objective function by the optimizer: 12 INFO - 11:43:22: Solution: INFO - 11:43:22: The solution is feasible. INFO - 11:43:22: Objective: -3463.120411437138 INFO - 11:43:22: Standardized constraints: INFO - 11:43:22: g_1 = [-0.01112145 -0.02847064 -0.04049911 -0.04878943 -0.05476349 -0.14014207 INFO - 11:43:22: -0.09985793] INFO - 11:43:22: g_2 = -0.0020925663903177405 INFO - 11:43:22: g_3 = [-0.71359843 -0.28640157 -0.05926796 -0.183255 ] INFO - 11:43:22: Design space: INFO - 11:43:22: +-------------+-------------+---------------------+-------------+-------+ INFO - 11:43:22: | Name | Lower bound | Value | Upper bound | Type | INFO - 11:43:22: +-------------+-------------+---------------------+-------------+-------+ INFO - 11:43:22: | x_shared[0] | 0.01 | 0.05947685840242058 | 0.09 | float | INFO - 11:43:22: | x_shared[1] | 30000 | 59246.692998739 | 60000 | float | INFO - 11:43:22: | x_shared[2] | 1.4 | 1.4 | 1.8 | float | INFO - 11:43:22: | x_shared[3] | 2.5 | 2.64097355362077 | 8.5 | float | INFO - 11:43:22: | x_shared[4] | 40 | 69.32144380869019 | 70 | float | INFO - 11:43:22: | x_shared[5] | 500 | 1478.031626737187 | 1500 | float | INFO - 11:43:22: | x_1[0] | 0.1 | 0.4 | 0.4 | float | INFO - 11:43:22: | x_1[1] | 0.75 | 0.7608797907508461 | 1.25 | float | INFO - 11:43:22: | x_2 | 0.75 | 0.7607584987262048 | 1.25 | float | INFO - 11:43:22: | x_3 | 0.1 | 0.1514057659459843 | 1 | float | INFO - 11:43:22: +-------------+-------------+---------------------+-------------+-------+ INFO - 11:43:22: *** End MDOScenario execution (time: 0:00:00.597614) *** .. GENERATED FROM PYTHON SOURCE LINES 229-236 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 236-238 .. 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 239-247 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 247-249 .. 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 250-255 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 255-257 .. code-block:: Python scenario.formulation.mda.matrix_type = JacobianAssembly.JacobianType.MATRIX scenario.formulation.mda.use_lu_fact = True .. GENERATED FROM PYTHON SOURCE LINES 258-262 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 262-263 .. code-block:: Python scenario.formulation.mda.matrix_type = JacobianAssembly.JacobianType.LINEAR_OPERATOR .. GENERATED FROM PYTHON SOURCE LINES 264-285 The next table shows the performance of each method for solving the Sobieski use case with :ref:`MDF ` and :ref:`IDF ` formulations. Efficiency of linearization is clearly visible has 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 1.348 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 `_