.. 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 Click :ref:`here ` 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:`.MDODiscipline` within a :class:`.Scenario`. This :class:`.SurrogateDiscipline` is an evaluation of the :class:`.MDODiscipline` and is faster to compute than the original discipline. It relies on a :class:`.MLRegressionAlgo`. This comes at the price of computing a :term:`DOE` on the original :class:`.MDODiscipline`, 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:`.AbstractFullCache.export_to_dataset` method, from a database, using the :meth:`.OptimizationProblem.export_to_dataset` method, or from a NumPy array or a text file using the :meth:`.Dataset.set_from_array` and :meth:`.Dataset.set_from_file`. Then, the surrogate discipline can be used as any other discipline in a :class:`.MDOScenario`, a :class:`.DOEScenario`, or a :class:`.MDA`. .. GENERATED FROM PYTHON SOURCE LINES 50-63 .. code-block:: default from gemseo.api import configure_logger from gemseo.api import create_discipline from gemseo.api import create_scenario from gemseo.api import create_surrogate from gemseo.core.dataset import Dataset from gemseo.problems.sobieski.core.problem import SobieskiProblem from numpy import array from numpy import hstack from numpy import vstack configure_logger() .. rst-class:: sphx-glr-script-out Out: .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 64-76 Create a surrogate discipline ----------------------------- Create the learning 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 76-88 .. code-block:: default 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 = Dataset() synthetic_dataset.set_from_array(data, variables, sizes, groups) .. GENERATED FROM PYTHON SOURCE LINES 89-108 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:`.MDODiscipline` 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:`.MDODiscipline` by means of the API function :meth:`~gemseo.api.create_discipline`: .. GENERATED FROM PYTHON SOURCE LINES 108-111 .. code-block:: default discipline = create_discipline("SobieskiMission") .. GENERATED FROM PYTHON SOURCE LINES 112-119 .. _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 120-123 .. code-block:: default design_space = SobieskiProblem().design_space design_space = design_space.filter(["x_shared", "y_24", "y_34"]) .. GENERATED FROM PYTHON SOURCE LINES 124-128 From this :class:`.MDODiscipline` and this :class:`.DesignSpace`, we build a :class:`.DOEScenario` by means of the API function :meth:`~gemseo.api.create_scenario`: .. GENERATED FROM PYTHON SOURCE LINES 129-137 .. code-block:: default scenario = create_scenario( [discipline], "DisciplinaryOpt", objective_name="y_4", design_space=design_space, scenario_type="DOE", ) .. GENERATED FROM PYTHON SOURCE LINES 138-139 Lastly, we execute the process with the :term:`LHS` algorithm and 30 samples. .. GENERATED FROM PYTHON SOURCE LINES 139-142 .. code-block:: default scenario.execute({"n_samples": 30, "algo": "lhs"}) mission_dataset = scenario.export_to_dataset(opt_naming=False) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none INFO - 07:17:19: INFO - 07:17:19: *** Start DOEScenario execution *** INFO - 07:17:19: DOEScenario INFO - 07:17:19: Disciplines: SobieskiMission INFO - 07:17:19: MDO formulation: DisciplinaryOpt INFO - 07:17:19: Optimization problem: INFO - 07:17:19: minimize y_4(x_shared, y_24, y_34) INFO - 07:17:19: with respect to x_shared, y_24, y_34 INFO - 07:17:19: over the design space: INFO - 07:17:19: +----------+-------------+------------+-------------+-------+ INFO - 07:17:19: | name | lower_bound | value | upper_bound | type | INFO - 07:17:19: +----------+-------------+------------+-------------+-------+ INFO - 07:17:19: | x_shared | 0.01 | 0.05 | 0.09 | float | INFO - 07:17:19: | x_shared | 30000 | 45000 | 60000 | float | INFO - 07:17:19: | x_shared | 1.4 | 1.6 | 1.8 | float | INFO - 07:17:19: | x_shared | 2.5 | 5.5 | 8.5 | float | INFO - 07:17:19: | x_shared | 40 | 55 | 70 | float | INFO - 07:17:19: | x_shared | 500 | 1000 | 1500 | float | INFO - 07:17:19: | y_24 | 0.44 | 4.15006276 | 11.13 | float | INFO - 07:17:19: | y_34 | 0.44 | 1.10754577 | 1.98 | float | INFO - 07:17:19: +----------+-------------+------------+-------------+-------+ INFO - 07:17:19: Solving optimization problem with algorithm lhs: INFO - 07:17:19: ... 0%| | 0/30 [00:00`_, 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.api.get_available_doe_algorithms`. .. GENERATED FROM PYTHON SOURCE LINES 154-168 Create the :class:`.SurrogateDiscipline` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From this :class:`.Dataset`, we can build a :class:`.SurrogateDiscipline` of the :class:`.MDODiscipline`. Indeed, by means of the API function :class:`~gemseo.api.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 :meth:`~gemseo.api.create_surrogate`, we create a :class:`.SurrogateDiscipline` relying on a :class:`.LinearRegressor` and inheriting from :class:`.MDODiscipline`: .. GENERATED FROM PYTHON SOURCE LINES 168-171 .. code-block:: default synthetic_surrogate = create_surrogate("LinearRegressor", synthetic_dataset) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none INFO - 07:17:19: Build the surrogate discipline: LinReg_Dataset INFO - 07:17:19: Dataset name: Dataset INFO - 07:17:19: Dataset size: 2 INFO - 07:17:19: Surrogate model: LinearRegressor INFO - 07:17:19: Use the surrogate discipline: LinReg_Dataset INFO - 07:17:19: Inputs: x INFO - 07:17:19: Outputs: y INFO - 07:17:19: Jacobian: use surrogate model jacobian .. GENERATED FROM PYTHON SOURCE LINES 172-179 .. 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:`.MDODiscipline`: .. GENERATED FROM PYTHON SOURCE LINES 179-183 .. code-block:: default input_data = {"x": array([2.0])} out = synthetic_surrogate.execute(input_data) print(out["y"]) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none [2.] .. GENERATED FROM PYTHON SOURCE LINES 184-187 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 187-189 .. code-block:: default range_surrogate = create_surrogate("RBFRegressor", mission_dataset) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none INFO - 07:17:19: Build the surrogate discipline: RBF_DOEScenario INFO - 07:17:19: Dataset name: DOEScenario INFO - 07:17:19: Dataset size: 30 INFO - 07:17:19: Surrogate model: RBFRegressor INFO - 07:17:19: Use the surrogate discipline: RBF_DOEScenario INFO - 07:17:19: Inputs: x_shared, y_24, y_34 INFO - 07:17:19: Outputs: y_4 INFO - 07:17:19: Jacobian: use surrogate model jacobian .. GENERATED FROM PYTHON SOURCE LINES 190-197 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:`.MDODiscipline.execute` method can be used as in any other discipline to compute the outputs for given inputs: .. GENERATED FROM PYTHON SOURCE LINES 197-203 .. code-block:: default 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 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 204-209 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 209-220 .. code-block:: default design_space = design_space.filter(["y_24"]) scenario = create_scenario( range_surrogate, formulation="DisciplinaryOpt", objective_name="y_4", design_space=design_space, scenario_type="MDO", maximize_objective=True, ) scenario.execute({"max_iter": 30, "algo": "L-BFGS-B"}) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none INFO - 07:17:19: INFO - 07:17:19: *** Start MDOScenario execution *** INFO - 07:17:19: MDOScenario INFO - 07:17:19: Disciplines: Surrogate discipline: RBF_DOEScenario INFO - 07:17:19: Dataset name: DOEScenario INFO - 07:17:19: Dataset size: 30 INFO - 07:17:19: Surrogate model: RBFRegressor INFO - 07:17:19: Inputs: x_shared, y_24, y_34 INFO - 07:17:19: Outputs: y_4 INFO - 07:17:19: MDO formulation: DisciplinaryOpt INFO - 07:17:19: Optimization problem: INFO - 07:17:19: minimize -y_4(y_24) INFO - 07:17:19: with respect to y_24 INFO - 07:17:19: over the design space: INFO - 07:17:19: +------+-------------+--------------------+-------------+-------+ INFO - 07:17:19: | name | lower_bound | value | upper_bound | type | INFO - 07:17:19: +------+-------------+--------------------+-------------+-------+ INFO - 07:17:19: | y_24 | 0.44 | 0.8060924457095278 | 11.13 | float | INFO - 07:17:19: +------+-------------+--------------------+-------------+-------+ INFO - 07:17:19: Solving optimization problem with algorithm L-BFGS-B: INFO - 07:17:19: ... 0%| | 0/30 [00:00`_ 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:`.MLRegressionAlgo` base class shall be extended. See :ref:`extending-gemseo` to learn how to run |g| with external Python modules. Then, the :class:`.RegressionModelFactory` can build the new :class:`.MLRegressionAlgo` 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.080 seconds) .. _sphx_glr_download_examples_surrogate_plot_surrogate_scenario.py: .. only :: html .. container:: sphx-glr-footer :class: sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_surrogate_scenario.py ` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_surrogate_scenario.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_