.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/surrogate/plot_surrogate_scenario.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_surrogate_plot_surrogate_scenario.py: Plug a surrogate discipline in a Scenario ========================================= In this section we describe the usage of surrogate model in |g|, which is implemented in the :class:`.SurrogateDiscipline` class. A :class:`.SurrogateDiscipline` can be used to substitute a :class:`.Discipline` within a :class:`.Scenario`. This :class:`.SurrogateDiscipline` is an evaluation of the :class:`.Discipline` and is faster to compute than the original discipline. It relies on a :class:`.BaseRegressor`. This comes at the price of computing a :term:`DOE` on the original :class:`.Discipline`, and validating the approximation. The computations from which the approximation is built can be available, or can be built using |g|' :term:`DOE` capabilities. See :ref:`sobieski_doe` and :ref:`sellar_mdo`. In |g|'s, the data used to build the surrogate model is taken from a :class:`.Dataset` containing both inputs and outputs of the :term:`DOE`. This :class:`.Dataset` may have been generated by |g| from a cache, using the :meth:`.BaseFullCache.to_dataset` method, from a database, using the :meth:`.OptimizationProblem.to_dataset` method, or from a NumPy array or a text file using the :meth:`.Dataset.from_array` and :meth:`.Dataset.from_txt`. Then, the surrogate discipline can be used as any other discipline in a :class:`.MDOScenario`, a :class:`.DOEScenario`, or a :class:`.BaseMDA`. .. GENERATED FROM PYTHON SOURCE LINES 50-68 .. code-block:: Python from __future__ import annotations from numpy import array from numpy import hstack from numpy import vstack from gemseo import configure_logger from gemseo import create_discipline from gemseo import create_scenario from gemseo import create_surrogate from gemseo import sample_disciplines from gemseo.datasets.io_dataset import IODataset from gemseo.problems.mdo.sobieski.core.design_space import SobieskiDesignSpace configure_logger() .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 69-81 Create a surrogate discipline ----------------------------- Create the training dataset ~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you already have available data from a :term:`DOE` produced externally, it is possible to create a :class:`.Dataset` and Step 1 ends here. For example, let us consider a synthetic dataset, with :math:`x` as input and :math:`y` as output, described as a numpy array. Then, we store these data in a :class:`.Dataset`: .. GENERATED FROM PYTHON SOURCE LINES 81-90 .. code-block:: Python variables = ["x", "y"] sizes = {"x": 1, "y": 1} groups = {"x": "inputs", "y": "outputs"} data = vstack(( hstack((array([1.0]), array([1.0]))), hstack((array([2.0]), array([2.0]))), )) synthetic_dataset = IODataset.from_array(data, variables, sizes, groups) .. GENERATED FROM PYTHON SOURCE LINES 91-110 If you do not have available data,the following paragraphs of Step 1 concern you. Here, we illustrate the generation of the training data using a :class:`.DOEScenario`, similarly to :ref:`sobieski_doe`, where more details are given. In this basic example, an :class:`.Discipline` computing the mission performance (range) in the :ref:`SSBJ test case ` is sampled with a :class:`.DOEScenario`. Then, the generated database is used to build a :class:`.SurrogateDiscipline`. But more complex scenarios can be used in the same way: complete optimization processes or MDAs can be replaced by their surrogate counterparts. The right cache or database shall then be used to build the :class:`.SurrogateDiscipline`, but the main logic won't differ from this example. Firstly, we create the :class:`.Discipline` by means of the API function :func:`.create_discipline`: .. GENERATED FROM PYTHON SOURCE LINES 110-113 .. code-block:: Python discipline = create_discipline("SobieskiMission") .. GENERATED FROM PYTHON SOURCE LINES 114-121 .. _surrogates_design_space: Then, we read the :class:`.DesignSpace` of the :ref:`Sobieski problem ` and keep only the inputs of the Sobieski Mission "x_shared", "y_24", "y_34" as inputs of the DOE: .. GENERATED FROM PYTHON SOURCE LINES 122-125 .. code-block:: Python design_space = SobieskiDesignSpace() design_space = design_space.filter(["x_shared", "y_24", "y_34"]) .. GENERATED FROM PYTHON SOURCE LINES 126-129 From this :class:`.Discipline` and this :class:`.DesignSpace`, we can generate 30 samples by means of the :func:`.sample_disciplines` function with the :term:`LHS` algorithm: .. GENERATED FROM PYTHON SOURCE LINES 130-134 .. code-block:: Python mission_dataset = sample_disciplines( [discipline], design_space, "y_4", algo_name="PYDOE_LHS", n_samples=30 ) .. rst-class:: sphx-glr-script-out .. code-block:: none WARNING - 11:43:19: No coupling in MDA, switching chain_linearize to True. WARNING - 11:43:19: Unsupported feature 'minItems' in JSONGrammar 'SobieskiMission_discipline_output' for property 'y_4' in conversion to SimpleGrammar. WARNING - 11:43:19: Unsupported feature 'maxItems' in JSONGrammar 'SobieskiMission_discipline_output' for property 'y_4' in conversion to SimpleGrammar. INFO - 11:43:19: *** Start Sampling execution *** INFO - 11:43:19: Sampling INFO - 11:43:19: Disciplines: SobieskiMission INFO - 11:43:19: MDO formulation: MDF INFO - 11:43:19: Running the algorithm PYDOE_LHS: INFO - 11:43:19: 3%|▎ | 1/30 [00:00<00:00, 342.56 it/sec] INFO - 11:43:19: 7%|▋ | 2/30 [00:00<00:00, 549.71 it/sec] INFO - 11:43:19: 10%|█ | 3/30 [00:00<00:00, 727.46 it/sec] INFO - 11:43:19: 13%|█▎ | 4/30 [00:00<00:00, 883.15 it/sec] INFO - 11:43:19: 17%|█▋ | 5/30 [00:00<00:00, 1014.05 it/sec] INFO - 11:43:19: 20%|██ | 6/30 [00:00<00:00, 1133.70 it/sec] INFO - 11:43:19: 23%|██▎ | 7/30 [00:00<00:00, 1239.87 it/sec] INFO - 11:43:19: 27%|██▋ | 8/30 [00:00<00:00, 1326.37 it/sec] INFO - 11:43:19: 30%|███ | 9/30 [00:00<00:00, 1405.81 it/sec] INFO - 11:43:19: 33%|███▎ | 10/30 [00:00<00:00, 1481.09 it/sec] INFO - 11:43:19: 37%|███▋ | 11/30 [00:00<00:00, 1544.66 it/sec] INFO - 11:43:19: 40%|████ | 12/30 [00:00<00:00, 1609.43 it/sec] INFO - 11:43:19: 43%|████▎ | 13/30 [00:00<00:00, 1657.27 it/sec] INFO - 11:43:19: 47%|████▋ | 14/30 [00:00<00:00, 1705.20 it/sec] INFO - 11:43:19: 50%|█████ | 15/30 [00:00<00:00, 1754.06 it/sec] INFO - 11:43:19: 53%|█████▎ | 16/30 [00:00<00:00, 1792.15 it/sec] INFO - 11:43:19: 57%|█████▋ | 17/30 [00:00<00:00, 1832.89 it/sec] INFO - 11:43:19: 60%|██████ | 18/30 [00:00<00:00, 1872.74 it/sec] INFO - 11:43:19: 63%|██████▎ | 19/30 [00:00<00:00, 1905.77 it/sec] INFO - 11:43:19: 67%|██████▋ | 20/30 [00:00<00:00, 1938.44 it/sec] INFO - 11:43:19: 70%|███████ | 21/30 [00:00<00:00, 1971.32 it/sec] INFO - 11:43:19: 73%|███████▎ | 22/30 [00:00<00:00, 1998.24 it/sec] INFO - 11:43:19: 77%|███████▋ | 23/30 [00:00<00:00, 1994.85 it/sec] INFO - 11:43:19: 80%|████████ | 24/30 [00:00<00:00, 2011.86 it/sec] INFO - 11:43:19: 83%|████████▎ | 25/30 [00:00<00:00, 2034.85 it/sec] INFO - 11:43:19: 87%|████████▋ | 26/30 [00:00<00:00, 2058.44 it/sec] INFO - 11:43:19: 90%|█████████ | 27/30 [00:00<00:00, 2075.06 it/sec] INFO - 11:43:19: 93%|█████████▎| 28/30 [00:00<00:00, 2095.02 it/sec] INFO - 11:43:19: 97%|█████████▋| 29/30 [00:00<00:00, 2115.90 it/sec] INFO - 11:43:19: 100%|██████████| 30/30 [00:00<00:00, 2132.19 it/sec] INFO - 11:43:19: *** End Sampling execution (time: 0:00:00.015754) *** .. GENERATED FROM PYTHON SOURCE LINES 135-144 .. seealso:: In this tutorial, the :term:`DOE` is based on `pyDOE `_, however, several other designs are available, based on the package or `OpenTURNS `_. Some examples of these designs are plotted in :ref:`doe_algos`. To list the available :term:`DOE` algorithms in the current |g| configuration, use :meth:`gemseo.get_available_doe_algorithms`. .. GENERATED FROM PYTHON SOURCE LINES 146-160 Create the :class:`.SurrogateDiscipline` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From this :class:`.Dataset`, we can build a :class:`.SurrogateDiscipline` of the :class:`.Discipline`. Indeed, by means of the API function :class:`~gemseo.create_surrogate`, we create the :class:`.SurrogateDiscipline` from the dataset, which can be executed as any other :term:`discipline`. Precisely, by means of the API function :func:`.create_surrogate`, we create a :class:`.SurrogateDiscipline` relying on a :class:`.LinearRegressor` and inheriting from :class:`.Discipline`: .. GENERATED FROM PYTHON SOURCE LINES 160-163 .. code-block:: Python synthetic_surrogate = create_surrogate("LinearRegressor", synthetic_dataset) .. GENERATED FROM PYTHON SOURCE LINES 164-171 .. seealso:: Note that a subset of the inputs and outputs to be used to build the :class:`.SurrogateDiscipline` may be specified by the user if needed, mainly to avoid unnecessary computations. Then, we execute it as any :class:`.Discipline`: .. GENERATED FROM PYTHON SOURCE LINES 171-175 .. code-block:: Python input_data = {"x": array([2.0])} out = synthetic_surrogate.execute(input_data) out["y"] .. rst-class:: sphx-glr-script-out .. code-block:: none array([2.]) .. GENERATED FROM PYTHON SOURCE LINES 176-179 In our study case, from the :term:`DOE` built at Step 1, we build a :class:`.RBFRegressor` of :math:`y_4` representing the range in function of L/D: .. GENERATED FROM PYTHON SOURCE LINES 179-181 .. code-block:: Python range_surrogate = create_surrogate("RBFRegressor", mission_dataset) .. GENERATED FROM PYTHON SOURCE LINES 182-189 Use the :class:`.SurrogateDiscipline` in MDO -------------------------------------------- The obtained :class:`.SurrogateDiscipline` can be used in any :class:`.Scenario`, such as a :class:`.DOEScenario` or :class:`.MDOScenario`. We see here that the :meth:`.Discipline.execute` method can be used as in any other discipline to compute the outputs for given inputs: .. GENERATED FROM PYTHON SOURCE LINES 189-195 .. code-block:: Python for i in range(5): lod = i * 2.0 y_4_pred = range_surrogate.execute({"y_24": array([lod])})["y_4"] print(f"Surrogate range (L/D = {lod}) = {y_4_pred}") .. rst-class:: sphx-glr-script-out .. code-block:: none Surrogate range (L/D = 0.0) = [-97.86844673] Surrogate range (L/D = 2.0) = [184.60105962] Surrogate range (L/D = 4.0) = [505.37518268] Surrogate range (L/D = 6.0) = [840.33241658] Surrogate range (L/D = 8.0) = [1161.49215263] .. GENERATED FROM PYTHON SOURCE LINES 196-201 And we can build and execute an optimization scenario from it. The design variables are "y_24". The Jacobian matrix is computed by finite differences by default for surrogates, except for the :class:`.SurrogateDiscipline` relying on :class:`.LinearRegressor` which has an analytical (and constant) Jacobian. .. GENERATED FROM PYTHON SOURCE LINES 201-211 .. code-block:: Python design_space = design_space.filter(["y_24"]) scenario = create_scenario( range_surrogate, "y_4", design_space, formulation_name="DisciplinaryOpt", maximize_objective=True, ) scenario.execute(algo_name="L-BFGS-B", max_iter=30) .. rst-class:: sphx-glr-script-out .. code-block:: none INFO - 11:43:19: *** Start MDOScenario execution *** INFO - 11:43:19: MDOScenario INFO - 11:43:19: Disciplines: RBF_Sampling INFO - 11:43:19: MDO formulation: DisciplinaryOpt INFO - 11:43:19: Optimization problem: INFO - 11:43:19: minimize -y_4(y_24) INFO - 11:43:19: with respect to y_24 INFO - 11:43:19: over the design space: INFO - 11:43:19: +------+-------------+--------------------+-------------+-------+ INFO - 11:43:19: | Name | Lower bound | Value | Upper bound | Type | INFO - 11:43:19: +------+-------------+--------------------+-------------+-------+ INFO - 11:43:19: | y_24 | 0.44 | 0.8060924457095278 | 11.13 | float | INFO - 11:43:19: +------+-------------+--------------------+-------------+-------+ INFO - 11:43:19: Solving optimization problem with algorithm L-BFGS-B: INFO - 11:43:19: 3%|▎ | 1/30 [00:00<00:00, 575.19 it/sec, obj=-10.3] INFO - 11:43:19: 7%|▋ | 2/30 [00:00<00:00, 356.51 it/sec, obj=-1.59e+3] INFO - 11:43:19: Optimization result: INFO - 11:43:19: Optimizer info: INFO - 11:43:19: Status: 0 INFO - 11:43:19: Message: CONVERGENCE: NORM OF PROJECTED GRADIENT <= PGTOL INFO - 11:43:19: Number of calls to the objective function by the optimizer: 3 INFO - 11:43:19: Solution: INFO - 11:43:19: Objective: -1589.7138353791013 INFO - 11:43:19: Design space: INFO - 11:43:19: +------+-------------+-------+-------------+-------+ INFO - 11:43:19: | Name | Lower bound | Value | Upper bound | Type | INFO - 11:43:19: +------+-------------+-------+-------------+-------+ INFO - 11:43:19: | y_24 | 0.44 | 11.13 | 11.13 | float | INFO - 11:43:19: +------+-------------+-------+-------------+-------+ INFO - 11:43:19: *** End MDOScenario execution (time: 0:00:00.009271) *** .. GENERATED FROM PYTHON SOURCE LINES 212-255 Available surrogate models -------------------------- Currently, the following surrogate models are available: - Linear regression, based on the `Scikit-learn `_ library, for that use the :class:`.LinearRegressor` class. - Polynomial regression, based on the `Scikit-learn `_ library, for that use the :class:`.PolynomialRegressor` class, - Gaussian processes (also known as Kriging), based on the `Scikit-learn `_ library, for that use the :class:`.GaussianProcessRegressor` class, - Mixture of experts, for that use the :class:`.MOERegressor` class, - Random forest models, based on the `Scikit-learn # `_ library, for that use the :class:`.RandomForestRegressor` class. - RBF models (Radial Basis Functions), using the `SciPy `_ library, for that use the :class:`.RBFRegressor` class. - PCE models (Polynomial Chaos Expansion), based on the `OpenTURNS `_ library, for that use the :class:`.PCERegressor` class. To understand the detailed behavior of the models, please go to the documentation of the used packages. Extending surrogate models -------------------------- All surrogate models work the same way: the :class:`.BaseRegressor` base class shall be extended. See :ref:`extending-gemseo` to learn how to run |g| with external Python modules. Then, the :class:`.RegressorFactory` can build the new :class:`.BaseRegressor` automatically from its regression algorithm name and options. This factory is called by the constructor of :class:`.SurrogateDiscipline`. .. seealso:: More generally, |g| provides extension mechanisms to integrate external :DOE and optimization algorithms, disciplines, MDAs and surrogate models. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.078 seconds) .. _sphx_glr_download_examples_surrogate_plot_surrogate_scenario.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_surrogate_scenario.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_surrogate_scenario.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_surrogate_scenario.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_