diff --git a/doc_src/_examples/api/plot_discipline.py b/doc_src/_examples/api/plot_discipline.py index f9a233a48a19a143db3a9ce44450e0ec3de77084..bf5a7cbc0e5122ce3c8c846093201da81f9c50f1 100644 --- a/doc_src/_examples/api/plot_discipline.py +++ b/doc_src/_examples/api/plot_discipline.py @@ -82,14 +82,14 @@ addition.execute({"x1": array([1.0]), "x2": array([2.0])}) # %% # Get all inputs/outputs # ---------------------- -# The :func:`~gemseo.disciplines.utils.get_all_inputs` function can list all the inputs +# The :func:`.get_all_inputs` function can list all the inputs # of a list of disciplines, including the sub-disciplines if the # argument ``recursive`` (default: ``False``) is ``True``, # merging the input data from the discipline grammars. E.g. get_all_inputs(disciplines) # %% -# The :func:`~gemseo.disciplines.utils.get_all_outputs` function can list all the inputs +# The :func:`.get_all_outputs` function can list all the inputs # of a list of disciplines, including the sub-disciplines if the # argument ``recursive`` (default: ``False``) is ``True``, # merging the input data from the discipline grammars. E.g. diff --git a/doc_src/_examples/api/plot_mda.py b/doc_src/_examples/api/plot_mda.py index c95b7f52294e8ae536288c4e12123c6d07c828a4..8d3179a0aa917ac7fd22880e6c62d1104e6edad8 100644 --- a/doc_src/_examples/api/plot_mda.py +++ b/doc_src/_examples/api/plot_mda.py @@ -67,8 +67,8 @@ settings_model = MDAGaussSeidel_Settings() # %% # Create an MDA # ------------- -# The high-level function :func:`~gemseo.create_mda` can be used -# to create a scenario: +# The high-level function :func:`.create_mda` can be used +# to create an MDA: disciplines = create_discipline(["Sellar1", "Sellar2"]) mda = create_mda("MDAGaussSeidel", disciplines) output_data = mda.execute() diff --git a/doc_src/_examples/api/plot_sampling.py b/doc_src/_examples/api/plot_sampling.py index b044e0eae21b60f01ff3b4a1f15524c76904a641..218a6bcdfdb5e468fe739fadc6bb7b0d164a196f 100644 --- a/doc_src/_examples/api/plot_sampling.py +++ b/doc_src/_examples/api/plot_sampling.py @@ -14,7 +14,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Sample several disciplines. -========================== +============================== The :class:`.DOEScenario` class is used to solve trade-off studies, based on a design space, an objective and optional constraints. diff --git a/doc_src/_examples/api/plot_scenario.py b/doc_src/_examples/api/plot_scenario.py index d246b6e1f30c15dd035933586d4499b010940721..2d00569352eb8188a8f8f86e1ee97d9c01b0d485 100644 --- a/doc_src/_examples/api/plot_scenario.py +++ b/doc_src/_examples/api/plot_scenario.py @@ -50,7 +50,7 @@ configure_logger() # # Get available scenario type # --------------------------- -# The high-level function :func:`~gemseo.get_available_scenario_types` can be used +# The high-level function :func:`.get_available_scenario_types` can be used # to get the available scenario types (:class:`.MDOScenario` and # :class:`.DOEScenario`). get_available_scenario_types() @@ -130,7 +130,7 @@ get_scenario_differentiation_modes() # use :func:`.monitor_scenario`. # The first argument is the scenario to monitor, and the second is an # observer object, that is notified by its update(atom) method, which takes an -# :class:`~gemseo.core.execution_sequence.ExecutionSequence` as argument. +# :class:`.ExecutionSequence` as argument. # This method will be called every time a discipline status changes. # The atom represents a discipline's position in the process. One discipline # can have multiple atoms, since one discipline can be used in multiple diff --git a/doc_src/_examples/coupling/n2_chart.py b/doc_src/_examples/coupling/n2_chart.py index ba9e95419e8923462c3a6432e322922fe2e41b01..7d39ee354b3a5f5fad7e3ebfafa7c4d2400222c0 100644 --- a/doc_src/_examples/coupling/n2_chart.py +++ b/doc_src/_examples/coupling/n2_chart.py @@ -19,7 +19,7 @@ # :author: Matthias De Lozzo # OTHER AUTHORS - MACROSCOPIC CHANGES """N2 chart. -======== +============ """ from __future__ import annotations diff --git a/doc_src/_examples/dataset/use_cases/plot_burgers.py b/doc_src/_examples/dataset/use_cases/plot_burgers.py index 5c4a279633df3895317a6723c096aea7bfc7fc7f..7b09947d5ea12b082eeeebdb4863c4ab2ba7bac5 100644 --- a/doc_src/_examples/dataset/use_cases/plot_burgers.py +++ b/doc_src/_examples/dataset/use_cases/plot_burgers.py @@ -37,7 +37,7 @@ configure_logger() # Load Burgers' dataset # ----------------------- # We can easily load this dataset -# by means of the high-level function :func:`~gemseo.create_benchmark_dataset`: +# by means of the high-level function :func:`.create_benchmark_dataset`: dataset = create_benchmark_dataset("BurgersDataset") dataset diff --git a/doc_src/_examples/exterior_penalty/plot_exterior_penalty_sobieski.py b/doc_src/_examples/exterior_penalty/plot_exterior_penalty_sobieski.py index 061b49ad2c4ef9e4e59780c7b30c0ae1b5ca8d1a..2b8bb73beda6285320fc81194d095d78e44022fb 100644 --- a/doc_src/_examples/exterior_penalty/plot_exterior_penalty_sobieski.py +++ b/doc_src/_examples/exterior_penalty/plot_exterior_penalty_sobieski.py @@ -25,10 +25,11 @@ Example for exterior penalty applied to the Sobieski test case. # .. seealso:: # # To start with a simpler MDO problem, and for a detailed description -# of how to plug a test case into |g|, see :ref:`sellar_mdo`. +# of how to plug a test case into |g|, see +# :ref:`sphx_glr_examples_mdo_plot_sellar.py`. # # -# .. _sobieski_use_case: +# .. _sobieski_exterior_penalty: # # Solving with an :ref:`MDF formulation ` # -------------------------------------------------------- @@ -148,7 +149,7 @@ get_available_formulations() get_all_outputs(disciplines) get_all_inputs(disciplines) # %% -# From these :class:`~gemseo.core.discipline.Discipline`, design space, +# From these :class:`.Discipline`, design space, # :ref:`MDO formulation ` name and objective function name, # we build the scenario: scenario = create_scenario( diff --git a/doc_src/_examples/formulations/plot_sobieski_bilevel_bcd_example.py b/doc_src/_examples/formulations/plot_sobieski_bilevel_bcd_example.py index 340fb4dd9ac3d865424f47e2315390972ce5cb4a..f98a697d3d87e3c2e619ab9c2ba6d1538e1ee2c8 100644 --- a/doc_src/_examples/formulations/plot_sobieski_bilevel_bcd_example.py +++ b/doc_src/_examples/formulations/plot_sobieski_bilevel_bcd_example.py @@ -18,8 +18,8 @@ # :author: Fabian Castañeda # OTHER AUTHORS - MACROSCOPIC CHANGES """ -BiLevel BCD-based MDO on the Sobieski SSBJ test case -================================================ +BiLevel BCD-based MDO on the Sobieski SSBJ test case. +===================================================== """ # %% diff --git a/doc_src/_examples/mdo/plot_sellar.py b/doc_src/_examples/mdo/plot_sellar.py index f6e20e35453cbaa0f5b620a327a92ba7930d7b65..146824c5d514cb98e435a07aba0654a0c0e24f13 100644 --- a/doc_src/_examples/mdo/plot_sellar.py +++ b/doc_src/_examples/mdo/plot_sellar.py @@ -67,7 +67,7 @@ configure_logger() # In this section, # we define the Sellar disciplines by sub-classing the :class:`.Discipline` class. # For each class, -# the constructor and the _run method are overriden: +# the constructor and the _run method are overridden: # # - In the constructor, # the input and output grammar are created. @@ -75,7 +75,7 @@ configure_logger() # at the discipline execution. # The default inputs are also defined, # in case of the user does not provide them at the discipline execution. -# - In the _run method is implemented the concrete computation of the discipline. +# - In the ``_run`` method is implemented the concrete computation of the discipline. # The returned NumPy arrays can then be used to compute the output values. # They can then be stored in the :attr:`!Discipline.data` dictionary. # If the discipline execution is successful. diff --git a/doc_src/_examples/mdo/plot_sobieski_use_case.py b/doc_src/_examples/mdo/plot_sobieski_use_case.py index 3b6b4ff1b9479bfafc877161edfdf0994a4d4526..3712aafff6be5f0b7d38a248391bdd699b2f9d42 100644 --- a/doc_src/_examples/mdo/plot_sobieski_use_case.py +++ b/doc_src/_examples/mdo/plot_sobieski_use_case.py @@ -29,7 +29,7 @@ Application: Sobieski's Super-Sonic Business Jet (MDO) # .. 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`. +# of how to plug a test case to |g|, see :ref:`sphx_glr_examples_mdo_plot_sellar.py`. # # # .. _sobieski_use_case: diff --git a/doc_src/_examples/optimization_problem/plot_simple_optimization_example.py b/doc_src/_examples/optimization_problem/plot_simple_optimization_example.py new file mode 100644 index 0000000000000000000000000000000000000000..20709279bed9934d3f9d05caf5ac0fe837b3b54a --- /dev/null +++ b/doc_src/_examples/optimization_problem/plot_simple_optimization_example.py @@ -0,0 +1,316 @@ +# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com +# +# This work is licensed under a BSD 0-Clause License. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, +# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# Contributors: +# INITIAL AUTHORS - API and implementation and/or documentation +# :author: François Gallard +# OTHER AUTHORS - MACROSCOPIC CHANGES +""" +How to solve an optimization problem +==================================== +""" + +# %% +# Although the |g| library is dedicated to the :term:`MDO`, it can also be used +# for mono-disciplinary optimization problems. +# This example presents some analytical test cases. + +# %% +# Imports +# ******* +from __future__ import annotations + +import numpy as np +from scipy import optimize + +from gemseo import configure_logger +from gemseo import create_design_space +from gemseo import create_discipline +from gemseo import create_scenario +from gemseo import execute_post +from gemseo import get_available_opt_algorithms + +# %% +# Optimization based on a design of experiments +# ********************************************* +# Let :math:`(P)` be a simple optimization problem: +# +# .. math:: +# +# (P) = \left\{ +# \begin{aligned} +# & \underset{x\in\mathbb{N}^2}{\text{minimize}} +# & & f(x) = x_1 + x_2 \\ +# & \text{subject to} +# & & -5 \leq x \leq 5 +# \end{aligned} +# \right. +# +# In this section, we will see how to use |g| to solve this problem :math:`(P)` by +# means of a Design Of Experiments (:term:`DOE`) +# +# Define the objective function +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Firstly, by means of the :func:`.create_discipline` high-level function, +# we create a :class:`.Discipline` of :class:`.AutoPyDiscipline` type +# from a Python function. +# We also configure the |g| logger with the :func:`.configure_logger` function. + +configure_logger() + + +def f(x1=0.0, x2=0.0): + y = x1 + x2 + return y + + +discipline = create_discipline("AutoPyDiscipline", py_func=f) + +# %% +# Now, we want to minimize this :class:`.Discipline` over a design of experiments (DOE). + +# %% +# Define the design space +# ~~~~~~~~~~~~~~~~~~~~~~~ +# For that, by means of the :func:`.create_design_space` API function, +# we define the :class:`.DesignSpace` :math:`[-5, 5]\times[-5, 5]` +# by using its :meth:`~.DesignSpace.add_variable` method. + +design_space = create_design_space() +design_space.add_variable("x1", 1, lower_bound=-5, upper_bound=5, type_="integer") +design_space.add_variable("x2", 1, lower_bound=-5, upper_bound=5, type_="integer") + +# %% +# Define the DOE scenario +# ~~~~~~~~~~~~~~~~~~~~~~~ +# Then, by means of the :func:`.create_scenario` high-level function, +# we define a :class:`.DOEScenario` from the :class:`.Discipline` +# and the :class:`.DesignSpace` defined above: + +scenario = create_scenario( + discipline, + "y", + design_space, + formulation_name="DisciplinaryOpt", + scenario_type="DOE", +) + +# %% +# Execute the DOE scenario +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Lastly, we solve the :class:`.OptimizationProblem` included in the +# :class:`.DOEScenario` defined above by minimizing the objective function over a +# design of experiments included in the :class:`.DesignSpace`. +# Precisely, we choose a +# `full factorial design `_ +# of size :math:`11^2`: + +scenario.execute(algo_name="PYDOE_FULLFACT", n_samples=11**2) + +# %% +# The optimum results can be found in the execution log. It is also possible to +# extract them from the :attr:`.BaseScenario.optimization_result`. + +optimization_result = scenario.optimization_result +print( + f"The solution of P is (x*,f(x*)) = ({optimization_result.x_opt}, {optimization_result.f_opt})" +) + +# %% +# Optimization based on a quasi-Newton method by means of the `SciPy `_ library +# ************************************************************************************************* +# Let :math:`(P)` be a simple optimization problem: +# +# .. math:: +# +# (P) = \left\{ +# \begin{aligned} +# & \underset{x}{\text{minimize}} +# & & f(x) = \sin(x) - \exp(x) \\ +# & \text{subject to} +# & & -2 \leq x \leq 2 +# \end{aligned} +# \right. +# +# In this section, we will see how to use |g| to solve this problem :math:`(P)` +# by means of an optimizer directly used from the `SciPy `_ library. +# +# Define the objective function +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Firstly, we create the objective function and its gradient as standard Python +# functions: + + +def g(x=0): + y = np.sin(x) - np.exp(x) + return y + + +def dgdx(x=0): + y = np.cos(x) - np.exp(x) + return y + + +# %% +# Minimize the objective function +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Now, we can minimize this Python function over its design space by means of +# the `L-BFGS-B algorithm `_ +# implemented in the function ``scipy.optimize.fmin_l_bfgs_b``. + +x_0 = -0.5 * np.ones(1) +opt = optimize.fmin_l_bfgs_b(g, x_0, fprime=dgdx, bounds=[(-0.2, 2.0)]) +x_opt, f_opt, _ = opt + +# %% +# Then, we can display the solution of our optimization problem with the following code: + +print(f"The solution of P is (x*,f(x*)) = ({x_opt[0]}, {f_opt}).") + +# %% +# .. seealso:: +# +# You can find the SciPy implementation of the L-BFGS-B algorithm +# `by clicking here +# `_. + +# %% +# Optimization based on a quasi-Newton method by means of the |g| optimization interface +# ************************************************************************************** +# Let :math:`(P)` be a simple optimization problem: +# +# .. math:: +# +# (P) = \left\{ +# \begin{aligned} +# & \underset{x}{\text{minimize}} +# & & f(x) = \sin(x) - \exp(x) \\ +# & \text{subject to} +# & & -2 \leq x \leq 2 +# \end{aligned} +# \right. +# +# In this section, we will see how to use |g| to solve this problem :math:`(P)` +# by means of an optimizer +# from `SciPy `_ called through the optimization interface of |g|. +# +# Define the objective function +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Firstly, by means of the :func:`.create_discipline` high-level function, +# we create an :class:`.Discipline` of :class:`.AutoPyDiscipline` type +# from a Python function: + + +def g(x=0): + y = np.sin(x) - np.exp(x) + return y + + +def dgdx(x=0): + y = np.cos(x) - np.exp(x) + return y + + +discipline = create_discipline("AutoPyDiscipline", py_func=g, py_jac=dgdx) + +# %% +# Now, we can to minimize this :class:`.Discipline` over a design space, +# by means of a quasi-Newton method from the initial point :math:`0.5`. +# +# Define the design space +# ~~~~~~~~~~~~~~~~~~~~~~~ +# For that, by means of the :func:`.create_design_space` high-level function, +# we define the :class:`.DesignSpace` :math:`[-2., 2.]` +# with initial value :math:`0.5` +# by using its :meth:`~.DesignSpace.add_variable` method. + +design_space = create_design_space() +design_space.add_variable( + "x", 1, lower_bound=-2.0, upper_bound=2.0, value=-0.5 * np.ones(1) +) + +# %% +# Define the optimization problem +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Then, by means of the :func:`.create_scenario` high-level function, +# we define an :class:`.MDOScenario` from the :class:`.Discipline` +# and the :class:`.DesignSpace` defined above: + +scenario = create_scenario( + discipline, + "y", + design_space, + formulation_name="DisciplinaryOpt", + scenario_type="MDO", +) + +# %% +# Execute the optimization problem +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Lastly, we solve the :class:`.OptimizationProblem` included in the :class:`.MDOScenario` +# defined above by minimizing the objective function over the :class:`.DesignSpace`. +# Precisely, we choose the +# `L-BFGS-B algorithm `_ +# implemented in the function ``scipy.optimize.fmin_l_bfgs_b`` and +# indirectly called by means of the class :class:`.OptimizationLibraryFactory` +# and of its function :meth:`~.BaseAlgoFactory.execute`: + +scenario.execute(algo_name="L-BFGS-B", max_iter=100) + +# %% +# The optimization results are displayed in the log file. They can also be +# obtained using the following code: + +optimization_result = scenario.optimization_result +print( + f"The solution of P is (x*,f(x*)) = ({optimization_result.x_opt}, {optimization_result.f_opt})." +) + +# %% +# +# .. seealso:: +# +# You can find the `SciPy `_ implementation of the +# `L-BFGS-B algorithm `_ +# algorithm `by clicking here +# `_. +# +# In order to get the list of available optimization algorithms, use: + +algo_list = get_available_opt_algorithms() +print(f"Available algorithms: {algo_list}") + +# %% +# Saving and post-processing +# ************************** +# After the resolution of the +# :class:`~gemseo.algos.optimization_problem.OptimizationProblem`, +# we can export the results into an :term:`HDF` file: + +problem = scenario.formulation.optimization_problem +problem.to_hdf("my_optim.hdf5") + +# %% +# We can also post-process the optimization history by means of the function +# :func:`.execute_post`, +# either from the :class:`~gemseo.algos.optimization_problem.OptimizationProblem`: + +execute_post(problem, post_name="OptHistoryView", save=False, show=True) + +# %% +# or from the :term:`HDF` file created above: + +execute_post("my_optim.hdf5", post_name="OptHistoryView", save=False, show=True) diff --git a/doc_src/_examples/scalable/plot_diagonal.py b/doc_src/_examples/scalable/plot_diagonal.py index 932b4cfd0f7038553d54935e1b5f7b7bef003390..04f629c69ab6fd9eee7f8afc6679fcd4181c61bb 100644 --- a/doc_src/_examples/scalable/plot_diagonal.py +++ b/doc_src/_examples/scalable/plot_diagonal.py @@ -23,7 +23,7 @@ Scalable diagonal discipline ============================ Let us consider the -:class:`~gemseo.problems.mdo.sobieski.disciplines.SobieskiAerodynamics` discipline. +:class:`.SobieskiAerodynamics` discipline. We want to build its :class:`.DataDrivenScalableDiscipline` counterpart, using a :class:`.ScalableDiagonalModel` diff --git a/doc_src/_examples/scenario/plot_gantt_chart.py b/doc_src/_examples/scenario/plot_gantt_chart.py index 3ac00d997f4deec93c08ef2b9ce6698e43fd5113..5c7a8f5cc925b6fbc4862c6144b8ca1092d08328 100644 --- a/doc_src/_examples/scenario/plot_gantt_chart.py +++ b/doc_src/_examples/scenario/plot_gantt_chart.py @@ -52,7 +52,7 @@ configure_logger() # %% # Create the scenario -# ------------------ +# ------------------- # First, we define the Sobieski's SSBJ problem as a scenario. # # For this, diff --git a/doc_src/_examples/surrogate/plot_surrogate_scenario.py b/doc_src/_examples/surrogate/plot_surrogate_scenario.py index 1cea5601fef0ee0259f8356ee512a5c10778a320..16a08426bbfe4af33591d289ce3f82c68983cea6 100644 --- a/doc_src/_examples/surrogate/plot_surrogate_scenario.py +++ b/doc_src/_examples/surrogate/plot_surrogate_scenario.py @@ -32,8 +32,9 @@ 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`. +built using |g|' :term:`DOE` capabilities. +See :ref:`sphx_glr_examples_formulations_plot_doe_sobieski_mdf_example.py` and +:ref:`sphx_glr_examples_mdo_plot_sellar.py`. 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 diff --git a/doc_src/_examples/uncertainty/statistics/plot_param_stats.py b/doc_src/_examples/uncertainty/statistics/plot_param_stats.py index 762eac19287bd6dbc6749a28ccbb49c401bc3ed3..b99737504f645b012e0a23298f0e471b9a59f083 100644 --- a/doc_src/_examples/uncertainty/statistics/plot_param_stats.py +++ b/doc_src/_examples/uncertainty/statistics/plot_param_stats.py @@ -67,7 +67,7 @@ data # %% # Create a :class:`.OTParametricStatistics` object -# ---------------------------------------------- +# ------------------------------------------------ # We create a :class:`.OTParametricStatistics` object # from this data encapsulated in a :class:`.Dataset`: diff --git a/doc_src/_index/toctree.inc b/doc_src/_index/toctree.inc index 8f2c51104980c9c27919a9f44f51576959bb658a..afb544cc5da47c5034e19ddf5c15cd9e7d1238a9 100644 --- a/doc_src/_index/toctree.inc +++ b/doc_src/_index/toctree.inc @@ -39,22 +39,6 @@ C. Scenario D. Post-processing -.. raw:: latex - - \part{Tutorials} - -.. toctree:: - :caption: Tutorials - :maxdepth: 1 - :hidden: - - Solve an optimization problem - Solve an MDO problem - Carry out a trade-off study - Build a scalable model (Sellar) - Build a scalable model (Aerostructure) - Application: Sobieski's SSBJ - See the benchmark problems .. raw:: latex diff --git a/doc_src/_index/tutorials.inc b/doc_src/_index/tutorials.inc deleted file mode 100644 index 7cc23324ff76343b85ffdc24f19addcdf30b2432..0000000000000000000000000000000000000000 --- a/doc_src/_index/tutorials.inc +++ /dev/null @@ -1,21 +0,0 @@ -.. - Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com - - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 - International License. To view a copy of this license, visit - http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative - Commons, PO Box 1866, Mountain View, CA 94042, USA. - -.. - Contributors: - :author: Matthias De Lozzo - -Learn the basics of |g| through a series of tutorials: - - - Tutorial 1: Solve an optimization problem - :ref:`See more... ` - - Tutorial 2: Solve a :term:`MDO` problem - :ref:`See more... ` - - Tutorial 3: Carry out a trade-off study - :ref:`See more... ` - - Tutorial 4: Build a :ref:`scalable model ` (Sellar) - :ref:`See more... ` - - Tutorial 5: Build a :ref:`scalable model ` (Aerostructure) - :ref:`See more... ` - - Application: Sobieski's SSBJ - :ref:`See more... ` - - Problems: Train with benchmark problems - :ref:`See more... ` diff --git a/doc_src/examples_and_tutorials.rst b/doc_src/examples.rst similarity index 82% rename from doc_src/examples_and_tutorials.rst rename to doc_src/examples.rst index 9bf5ddaa262af0851ea3beb5d9eebc698f216296..aa589305a7a32aaed5750356d4809110fd72993b 100644 --- a/doc_src/examples_and_tutorials.rst +++ b/doc_src/examples.rst @@ -10,13 +10,12 @@ Contributors: :author: Matthias De Lozzo -.. _examples_and_tutorials: +.. _examples: -Examples and tutorials -====================== +Examples +======== .. toctree:: :maxdepth: 2 examples/index.rst - tutorials/index.rst diff --git a/doc_src/faq.rst b/doc_src/faq.rst index ca088ab4e421b9c5ec212913a9be4c870c1b6f5f..992aec43a0b79bf7c55faef0bc881019f0ff976e 100644 --- a/doc_src/faq.rst +++ b/doc_src/faq.rst @@ -36,7 +36,7 @@ This means that you must specify an objective function. The :term:`DOE` won't try to minimize it but it will be set as an objective in the visualizations. -.. seealso:: For more details, we invite you to read our tutorial :ref:`sobieski_doe`. +.. seealso:: For more details, we invite you to read our example :ref:`sphx_glr_examples_formulations_plot_doe_sobieski_mdf_example.py`. Create a simple optimization on a single discipline --------------------------------------------------- @@ -67,7 +67,7 @@ Coupling a simulation software to |g| See :ref:`Interfacing simulation software `. -.. seealso:: We invite you to discover all the steps in this tutorial :ref:`sellar_mdo`. +.. seealso:: We invite you to discover all the steps in this example :ref:`sphx_glr_examples_mdo_plot_sellar.py`. Extend |g| features ------------------- diff --git a/doc_src/index.rst b/doc_src/index.rst index 740c5951f119c929186e0fb93bb52a1396d66f45..f22ad594e68c3e4c1334bb25b372d150d8cb9485 100644 --- a/doc_src/index.rst +++ b/doc_src/index.rst @@ -408,7 +408,7 @@ Its GNU LGPL v3.0 open-source license makes it commercially usable (`see licence :maxdepth: 2 User guide - Examples + Examples API documentation Cheat sheets About us diff --git a/doc_src/interface/software_connection.rst b/doc_src/interface/software_connection.rst index f9e60dcfb55eb6f3305eefc54334c4d4dd124b6c..7eb8dfde228cbf04004562dc70acdf7a5a4a84ad 100644 --- a/doc_src/interface/software_connection.rst +++ b/doc_src/interface/software_connection.rst @@ -237,7 +237,7 @@ which is error-prone. From the previous JSON grammar of the Sobieski Mission discipline, we can illustrate the interest of the data check. -The :class:`~gemseo.problems.mdo.sobieski.disciplines.SobieskiMission` will check any data passed to its :meth:`.Discipline.execute` method before +The :class:`.SobieskiMission` will check any data passed to its :meth:`.Discipline.execute` method before calling :meth:`!Discipline._run`. .. code-block:: python @@ -259,7 +259,7 @@ as well as the rules. ERROR - 15:15:19 : JSON Grammar schema = {u'name': u'SobieskiMission_input', 'required': [u'x_shared', u'y_14', u'y_24', u'y_34'], u'id': u'#SobieskiMission_input', u'$schema': u'http://json-schema.org/draft-04/schema', 'type': u'object', 'properties': {u'y_24': {'items': {'type': u'number'}, 'type': u'array'}, u'x_shared': {'items': {'type': u'number'}, 'type': u'array'}, u'y_34': {'items': {'type': u'number'}, 'type': u'array'}, u'y_14': {'items': {'type': u'number'}, 'type': u'array'}}} The existence of required inputs is also checked before running. -The wrapper :class:`~gemseo.problems.mdo.sobieski.disciplines.SobieskiMission` has :attr:`!Discipline.default_input_data` set for all its inputs, so +The wrapper :class:`.SobieskiMission` has :attr:`!Discipline.default_input_data` set for all its inputs, so we need first to erase them to show that. .. code-block:: python @@ -354,4 +354,4 @@ that will: #. Update the :attr:`!Discipline.status` to DONE or FAILED. #. Update accumulated execution time :attr:`!ExecutionStatistics.execution_time`. -A complete example of discipline integration is given in :ref:`sellar_mdo`. +A complete example of discipline integration is given in :ref:`sphx_glr_examples_mdo_plot_sellar.py`. diff --git a/doc_src/mdo/mdo_formulations.rst b/doc_src/mdo/mdo_formulations.rst index d084a20674cd9d3c43b859c6c6be77db97e7fb69..391fbc7d38ae480df7d559dafaa381dcf63d03bb 100644 --- a/doc_src/mdo/mdo_formulations.rst +++ b/doc_src/mdo/mdo_formulations.rst @@ -42,8 +42,8 @@ These implement the classical formulations: In the following, general concepts about the formulations are given. The :ref:`mdf_formulation` and :ref:`idf_formulation` text is integrally taken from the paper :cite:`Vanaret2017`. -To see how to setup practical test cases with such formulations, please see :ref:`sellar_mdo` and -:ref:`sphx_glr_examples_mdo_plot_sobieski_use_case.py`. +To see how to setup practical test cases with such formulations, please see +:ref:`sphx_glr_examples_mdo_plot_sellar.py` and :ref:`sphx_glr_examples_mdo_plot_sobieski_use_case.py`. .. seealso:: @@ -99,7 +99,8 @@ z\}`. For details on the MDAs and coupled derivatives, see :ref:`mda` and :ref:`jacobian_assembly`. -An example of an MDO study using an MDF formulation can be found in the :ref:`Sellar MDO tutorial ` +An example of an MDO study using an MDF formulation can be found in the :ref:`sphx_glr_examples_mdo_plot_sellar.py` +example. .. warning:: diff --git a/doc_src/mdo/optimization.rst b/doc_src/mdo/optimization.rst index 784778dd638daec21d8123be3ae5fa6b737f7204..b6c8bcc682b4f6eb319112a8a78a2287cabdb3de 100644 --- a/doc_src/mdo/optimization.rst +++ b/doc_src/mdo/optimization.rst @@ -18,7 +18,8 @@ Optimization and DOE framework In this section we describe |g|'s optimization and DOE framework. The standard way to use |g| is through an :class:`.MDOScenario`, which -automatically creates an :class:`.OptimizationProblem` from a :ref:`MDO formulation ` and a set of :class:`~gemseo.core.discipline.Discipline`. +automatically creates an :class:`.OptimizationProblem` from an :ref:`MDO formulation ` and a set of +:class:`.Discipline`. However, one may be interested in directly creating an :class:`.OptimizationProblem` using the class :class:`.OptimizationProblem`, which can be solved using an :term:`optimization algorithm` or sampled with a :term:`DOE algorithm`. @@ -32,42 +33,50 @@ Setting up an :class:`.OptimizationProblem` ------------------------------------------- The :class:`.OptimizationProblem` class is composed of at least a -:class:`~gemseo.algos.design_space.DesignSpace` created from :func:`.create_design_space` which describes the :term:`design variables`: +:class:`.DesignSpace` created from :func:`.create_design_space` which describes the :term:`design variables`: -.. code:: +.. code:: python - from gemseo. api import create_design_space + from gemseo import configure_logger + from gemseo import create_design_space from numpy import ones + + configure_logger() + design_space = create_design_space() design_space.add_variable("x", 1, lower_bound=-2., upper_bound=2., - value=-0.5 * np.ones(1)) + value=-0.5 * ones(1)) -and an objective function, of type :class:`~gemseo.core.mdofunctions.mdo_function.MDOFunction`. The :class:`~gemseo.core.mdofunctions.mdo_function.MDOFunction` is callable and requires at least +and an objective function, of type :class:`.MDOFunction`. The :class:`.MDOFunction` is callable and requires at least a function pointer to be instantiated. It supports expressions and the +, -, \ * operators: -.. code:: +.. code:: python + + from gemseo.core.mdo_functions.mdo_function import MDOFunction + from numpy import cos + from numpy import exp + from numpy import sin - from gemseo.algos import MDOFunction - f_1 = MDOFunction(np.sin, name="f_1", jac=np.cos, expr="sin(x)") - f_2 = MDOFunction(np.exp, name="f_2", jac=np.exp, expr="exp(x)") + f_1 = MDOFunction(sin, name="f_1", jac=cos, expr="sin(x)") + f_2 = MDOFunction(exp, name="f_2", jac=exp, expr="exp(x)") f_1_sub_f_2 = f_1 - f_2 -From this :class:`~gemseo.algos.design_space.DesignSpace`, an :class:`.OptimizationProblem` is built: +From this :class:`.DesignSpace`, an :class:`.OptimizationProblem` is built: -.. code:: +.. code:: python - from gemseo.algos import OptimizationProblem, MDOFunction, + from gemseo.algos.optimization_problem import OptimizationProblem problem = OptimizationProblem(design_space) -To set the objective :class:`.MDOFunction`, the attribute :attr:`!OptimizationProblem.objective` of class :class:`.OptimizationProblem` +To set the objective :class:`.MDOFunction`, the attribute :attr:`.OptimizationProblem.objective` of class :class:`.OptimizationProblem` must be set with the objective function pointer: -.. code:: +.. code:: python problem.objective = f_1_sub_f_2 -Similarly the :attr:`!OptimizationProblem.constraints` attribute must be set with a list of inequality or equality constraints. -The :class:`!MDOFunction.f_type` attribute of :class:`.MDOFunction` shall be set to ``"eq"`` or ``"ineq"`` to declare the type of constraint to equality or inequality. +Similarly the :attr:`.OptimizationProblem.constraints` attribute must be set with a list of inequality or equality constraints. +The :attr:`.MDOFunction.f_type` attribute of :class:`.MDOFunction` shall be set to ``"eq"`` or ``"ineq"`` to declare the type of constraint to equality or inequality. .. warning:: @@ -78,26 +87,26 @@ Solving the problem by optimization Once the optimization problem created, it can be solved using one of the available optimization algorithms from the :class:`.OptimizationLibraryFactory`, -by means of the function :meth:`!.OptimizationLibraryFactory.execute` +by means of the function :meth:`.BaseOptimizationLibrary.execute` whose mandatory arguments are the :class:`.OptimizationProblem` and the optimization algorithm name. For example, in the case of the `L-BFGS-B algorithm `_ with normalized design space, we have: -.. code:: +.. code:: python - from gemseo.algos import OptimizationLibraryFactory - opt = OptimizationLibraryFactory().execute(problem, "L-BFGS-B", + from gemseo.algos.opt.factory import OptimizationLibraryFactory + opt = OptimizationLibraryFactory().execute(problem, algo_name="L-BFGS-B", normalize_design_space=True) - print "Optimum = " + str(opt) + print(f"Optimum = {opt.f_opt}") Note that the `L-BFGS-B algorithm `_ is implemented in the external library `SciPy `_ -and interfaced with |g| through the class :class:`~gemseo.algos.opt.scipy_local.scipy_local.ScipyOpt`. +and interfaced with |g| through the class :class:`.ScipyOpt`. The list of available algorithms depend on the local setup of |g|, and the installed optimization libraries. It can be obtained using : -.. code:: +.. code:: python algo_list = OptimizationLibraryFactory().algorithms print(f"Available algorithms: {algo_list}") @@ -106,7 +115,7 @@ The optimization history can be saved to the disk for further analysis, without having to re execute the optimization. For that, we use the function :meth:`.OptimizationProblem.to_hdf`: -.. code:: +.. code:: python problem.to_hdf("simple_opt.hdf5") @@ -116,9 +125,9 @@ Solving the problem by DOE :term:`DOE` algorithms can also be used to sample the design space and observe the value of the objective and constraints -.. code:: +.. code:: python - from gemseo.algos import DOELibraryFactory + from gemseo.algos.doe.factory import DOELibraryFactory # And solve it with |g| interface opt = DOELibraryFactory().execute( @@ -130,14 +139,14 @@ Results analysis The optimization history can be plotted using one of the post processing tools, see the :ref:`post-processing ` page. -.. code:: +.. code:: python from gemseo import execute_post - execute_post(problem, "OptHistoryView", save=True, file_path="simple_opt") + execute_post(problem, post_name="OptHistoryView", save=True, file_path="simple_opt") # Also works from disk - execute_post("my_optim.hdf5", "OptHistoryView", save=True, file_path="opt_view_from_disk") + execute_post("my_optim.hdf5", post_name="OptHistoryView", save=True, file_path="opt_view_from_disk") .. _fig-ssbj-mdf-obj: @@ -156,7 +165,7 @@ DOE algorithms `pyDOE `_, and `OpenTURNS `_. To list the available DOE algorithms in the current |g| configuration, use -:meth:`gemseo.get_available_doe_algorithms`. +:func:`.get_available_doe_algorithms`. The set of plots below shows plots using various available algorithms. diff --git a/doc_src/ode/ode_discipline.rst b/doc_src/ode/ode_discipline.rst index f76824a263432d8d28a584a7dfef56b6631657cb..6e825a3cd6258948803f091c2b36e860f5c4e9db 100644 --- a/doc_src/ode/ode_discipline.rst +++ b/doc_src/ode/ode_discipline.rst @@ -75,7 +75,7 @@ the dynamics of the components of the system. ODE Classes organization --------------- +------------------------ Here is the UML diagram of the classes in |g| for the solution of ODEs. diff --git a/doc_src/ode/ode_problem.rst b/doc_src/ode/ode_problem.rst index 10582bb7f465bb2d29ef4fe4ee1ff86fb31f1207..75631a54263fb2a25431e81510319b877ff72ab8 100644 --- a/doc_src/ode/ode_problem.rst +++ b/doc_src/ode/ode_problem.rst @@ -76,6 +76,7 @@ An instance of :class:`.ODEProblem` is used to represent an IVP. In order to solve it, it is necessary to instantiate an :class:`.ODESolverLibraryFactory` and execute it: .. code:: + ODESolverLibraryFactory().execute(problem=problem, algo_name=algo_name, **kwargs) The method ``execute`` of :class:`ODESolverLibraryFactory` takes as arguments the :class:`.ODEProblem` diff --git a/doc_src/problems/aerostructure_description.rst b/doc_src/problems/aerostructure_description.rst index 11411ca8b3a0a660f70908980df32baa8b05f765..1e92f0ce21ea4576a5494f48fcf97a2fc8b07418 100644 --- a/doc_src/problems/aerostructure_description.rst +++ b/doc_src/problems/aerostructure_description.rst @@ -13,9 +13,7 @@ Aerostructure problem --------------------- -The Sobieski's SSBJ test case is considered in the different tutorials: - -- :ref:`aerostruct_toy_example` +The Aerostructure problem is considered in the :ref:`sphx_glr_examples_scalable_plot_problem.py` example. Description of the problem ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -24,7 +22,8 @@ The Aerostructure problem is defined by analytical functions: .. include:: aerostructure_problem_definition.inc -The Aerostructure disciplines are also available with analytic derivatives in the classes :class:`~gemseo.problems.aerostructure.aerostructure.Mission`, :class:`~gemseo.problems.aerostructure.aerostructure.Aerodynamics` and :class:`~gemseo.problems.aerostructure.aerostructure.Structure`, as well as a :class:`~gemseo.problems.aerostructure.aerostructure_design_space.AerostructureDesignSpace`: +The Aerostructure disciplines are also available with analytic derivatives in the classes :class:`.Mission`, +:class:`.Aerodynamics` and :class:`.Structure`, as well as a :class:`.AerostructureDesignSpace`: Creation of the disciplines ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -40,7 +39,7 @@ To create the aerostructure disciplines, use the function :func:`.create_discipl Importation of the design space ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To import the aerostructure design space, use the class ``create_discipline``: +The :class:`.AerostructureDesignSpace` class can be imported as follows: .. code-block:: python @@ -67,4 +66,4 @@ Then, you can visualize it with ``print(design_space)``: .. seealso:: - See :ref:`aerostruct_toy_example` to see an application of this problem. + See :ref:`sphx_glr_examples_scalable_plot_problem.py` to see an application of this problem. diff --git a/doc_src/problems/sellar_description.rst b/doc_src/problems/sellar_description.rst index 79a59f9762f696c03b28b6ad5545532bc9b5186f..d8afac75ba6e699d971dacffea57833f1287a0a2 100644 --- a/doc_src/problems/sellar_description.rst +++ b/doc_src/problems/sellar_description.rst @@ -13,10 +13,10 @@ Sellar's problem ---------------- -The Sellar's problem is considered in different tutorials: +The Sellar's problem is considered in different examples: - :ref:`sphx_glr_examples_mdo_plot_gemseo_in_10_minutes.py` -- :ref:`sellar_mdo` +- :ref:`sphx_glr_examples_mdo_plot_sellar.py` Description of the problem ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -30,7 +30,7 @@ The Sellar disciplines are also available with analytic derivatives in |g|, as w Creation of the disciplines ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To create the Sellar disciplines, use the function ``create_discipline``: +To create the Sellar disciplines, use the function :func:`.create_discipline`: .. code:: @@ -41,7 +41,7 @@ To create the Sellar disciplines, use the function ``create_discipline``: Importation of the design space ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To import the Sellar design space, use the class ``create_discipline``: +The :class:`.SellarDesignSpace` can be imported as follows: .. code-block:: python @@ -68,4 +68,4 @@ Then, you can visualize it with ``print(design_space)``: .. seealso:: - See :ref:`sellar_mdo` to create the Sellar problem from scratch + See :ref:`sphx_glr_examples_mdo_plot_sellar.py` to create the Sellar problem from scratch. diff --git a/doc_src/problems/sobieski_description.rst b/doc_src/problems/sobieski_description.rst index 86f4bbae1f50c6d1180a3208ff71ad25336273a8..c6a4015ab9462f0c8477c0afdc8846b0b419b918 100644 --- a/doc_src/problems/sobieski_description.rst +++ b/doc_src/problems/sobieski_description.rst @@ -13,9 +13,9 @@ Sobieski's SSBJ test case ------------------------- -The Sobieski's SSBJ test case is considered in the different tutorials: +The Sobieski's SSBJ test case is considered in the different examples: -- :ref:`sobieski_doe` +- :ref:`sphx_glr_examples_formulations_plot_doe_sobieski_mdf_example.py` - :ref:`sphx_glr_examples_mdo_plot_sobieski_use_case.py` .. start_description @@ -73,12 +73,12 @@ an output of the discipline no. *i* and an input of the discipline no. *j*. Input variables ~~~~~~~~~~~~~~~ -.. figure:: /tutorials/ssbj/figs/SSBJ.png +.. figure:: /problems/sobieski_figures/SSBJ.png :scale: 100 % The planform variables -.. figure:: /tutorials/ssbj/figs/SupersonicAirfoil.png +.. figure:: /problems/sobieski_figures/SupersonicAirfoil.png :scale: 100 % The airfoils variables diff --git a/doc_src/tutorials/ssbj/figs/SSBJ.png b/doc_src/problems/sobieski_figures/SSBJ.png similarity index 100% rename from doc_src/tutorials/ssbj/figs/SSBJ.png rename to doc_src/problems/sobieski_figures/SSBJ.png diff --git a/doc_src/tutorials/ssbj/figs/SupersonicAirfoil.png b/doc_src/problems/sobieski_figures/SupersonicAirfoil.png similarity index 100% rename from doc_src/tutorials/ssbj/figs/SupersonicAirfoil.png rename to doc_src/problems/sobieski_figures/SupersonicAirfoil.png diff --git a/doc_src/scenario/monitoring.rst b/doc_src/scenario/monitoring.rst index fd183d0633a4e35acce13b862bb99e3e68a98a9e..031836aa0cb3b7a449023814273b7fe0df75995d 100644 --- a/doc_src/scenario/monitoring.rst +++ b/doc_src/scenario/monitoring.rst @@ -15,7 +15,8 @@ Monitoring the execution of a scenario ====================================== -When a scenario is executed (see :ref:`sellar_mdo` for building a scenario), |g| logs the last computed value of the objective +When a scenario is executed (see :ref:`sphx_glr_examples_mdo_plot_sellar.py` for building a scenario), +|g| logs the last computed value of the objective function. But a finer monitoring may be needed, especially in case of crash. In a situation like this, the current execution status of the :class:`.Discipline` is useful as well. diff --git a/doc_src/software/system_architecture.rst b/doc_src/software/system_architecture.rst index bf44d108ab90b065a1be0bfa930260aaadc153a0..fc01dd6358be245c37ff8f789da65ef5cdff56c7 100644 --- a/doc_src/software/system_architecture.rst +++ b/doc_src/software/system_architecture.rst @@ -189,59 +189,60 @@ Main classes The high level classes that are key in the architecture are: -- :class:`~gemseo.scenarios.mdo_scenario.MDOScenario` builds the process from a set of inputs, several +- :class:`.MDOScenario` builds the process from a set of inputs, several disciplines and a formulation. It is one of the main interface class - for the :term:`MDO user`. The :class:`~gemseo.scenarios.mdo_scenario.MDOScenario` triggers the overall optimization + for the :term:`MDO user`. The :class:`.MDOScenario` triggers the overall optimization process when its ``execute()`` method is called. Through this class, the user provides an initial solution, user constraints, and bounds on the :term:`design variables`. The user may also generate visualization of the scenario - execution, such as convergence plots of the algorithm (see :ref:`sellar_mdo`). + execution, such as convergence plots of the algorithm (see + :ref:`sphx_glr_examples_mdo_plot_sellar.py`). -- :class:`~gemseo.scenarios.doe_scenario.DOEScenario` builds the process from a set of inputs, several +- :class:`.DOEScenario` builds the process from a set of inputs, several disciplines and a formulation. It is the second main interface class - for the :term:`MDO user`. The :class:`~gemseo.scenarios.doe_scenario.DOEScenario` triggers the overall trade-off process + for the :term:`MDO user`. The :class:`.DOEScenario` triggers the overall trade-off process when its ``execute()`` method is called. Through this class, the user provides a design space, some outputs to monitor (objective and constraints) and a number of samples. The user may also generate visualization of the scenario execution, such as convergence plots of - the algorithm . As the :class:`~gemseo.scenarios.mdo_scenario.MDOScenario`, the - :class:`~gemseo.scenarios.doe_scenario.DOEScenario` makes the link between all the following classes. It - is mainly handled by the :term:`MDO integrator`. Both :class:`~gemseo.scenarios.mdo_scenario.MDOScenario` and :class:`~gemseo.scenarios.doe_scenario.DOEScenario` - inherit from the :class:`~gemseo.scenarios.base_scenario.BaseScenario` class that defines common features + the algorithm . As the :class:`.MDOScenario`, the + :class:`.DOEScenario` makes the link between all the following classes. It + is mainly handled by the :term:`MDO integrator`. Both :class:`.MDOScenario` and :class:`.DOEScenario` + inherit from the :class:`.BaseScenario` class that defines common features (bounds, constraints, …). -- :class:`~gemseo.core.discipline.Discipline` represents a wrapped :term:`simulation software` program or a chain of wrapped +- :class:`.Discipline` represents a wrapped :term:`simulation software` program or a chain of wrapped software. It can either be a link to a :term:`discipline` integrated within a :term:`workflow engine`, or can be inherited to integrate a :term:`simulation software` directly. Its inputs and outputs are - represented in a **Grammar** (see :class:`~gemseo.core.grammars.simple_grammar.SimpleGrammar` or :class:`~gemseo.core.grammars.json_grammar.JSONGrammar`). + represented in a **Grammar** (see :class:`.SimpleGrammar` or :class:`.JSONGrammar`). -- :class:`~gemseo.formulations.base_mdo_formulation.BaseMDOFormulation` describes the :term:`MDO formulation` (*e.g.* :term:`MDF` and :term:`IDF`) - used by the :class:`~gemseo.scenarios.base_scenario.BaseScenario` to generate the :class:`~gemseo.algos.optimization_problem.OptimizationProblem`. +- :class:`.BaseMDOFormulation` describes the :term:`MDO formulation` (*e.g.* :term:`MDF` and :term:`IDF`) + used by the :class:`~gemseo.scenarios.base_scenario.BaseScenario` to generate the :class:`.OptimizationProblem`. The :term:`MDO user` or the :term:`MDO integrator` may either provide the name of the - formulation, or a class, or an instance, to the :class:`~gemseo.scenarios.base_scenario.BaseScenario` - (:class:`~gemseo.scenarios.mdo_scenario.MDOScenario` or\ :class:`~gemseo.scenarios.doe_scenario.DOEScenario`) . The :term:`MDO formulations designer` may create, implement, + formulation, or a class, or an instance, to the :class:`.BaseScenario` + (:class:`.MDOScenario` or\ :class:`.DOEScenario`) . The :term:`MDO formulations designer` may create, implement, test or maintain :term:`MDO formulations ` with this class. -- :class:`~gemseo.algos.optimization_problem.OptimizationProblem` describes the mathematical functions of the +- :class:`.OptimizationProblem` describes the mathematical functions of the optimization problem (:term:`objective function` and :term:`constraints`, along with the :term:`design variables`. It is - generated by the :class:`~gemseo.formulations.base_mdo_formulation.BaseMDOFormulation`, and solved by the :term:`optimization algorithm`. It has an + generated by the :class:`.BaseMDOFormulation`, and solved by the :term:`optimization algorithm`. It has an internal database that stores the calls to its functions by the :term:`optimization algorithm` to avoid duplicate computations. It can be stored on disk and analyzed *a posteriori* by post-processing available in |g|. -- :class:`~gemseo.algos.design_space.DesignSpace` is an attribute of the :class:`~gemseo.algos.optimization_problem.OptimizationProblem` that describes the :term:`design variables`, +- :class:`.DesignSpace` is an attribute of the :class:`.OptimizationProblem` that describes the :term:`design variables`, their bounds, their type (float or integer), and current value. This object can be read from a file. Two low-level classes at the core of |g| are crucial for the understanding of its basic principles: -- :class:`~gemseo.core.mdofunctions.mdo_function.MDOFunction` instances (for the :term:`objective function` and the possible constraints) are - generated by the :class:`~gemseo.formulations.base_mdo_formulation.BaseMDOFormulation`. Depending on the formulation, +- :class:`.MDOFunction` instances (for the :term:`objective function` and the possible constraints) are + generated by the :class:`.BaseMDOFormulation`. Depending on the formulation, constraints may be generated as well (*e.g.* consistency constraints in :term:`IDF`). -- :class:`~gemseo.core.mdofunctions.mdo_discipline_adapter_generator.DisciplineAdapterGenerator` is a utility class that handles the - :class:`~gemseo.core.mdofunctions.mdo_function.MDOFunction` generation for a given :class:`~gemseo.core.discipline.Discipline`. +- :class:`.DisciplineAdapterGenerator` is a utility class that handles the + :class:`.MDOFunction` generation for a given :class:`.Discipline`. It is a key class for the :term:`MDO formulations designer`. diff --git a/doc_src/tutorials/aerostruct/Aerodynamics_drag_1D_interpolation.png b/doc_src/tutorials/aerostruct/Aerodynamics_drag_1D_interpolation.png deleted file mode 100644 index ed7f8afb524dd209af65900da9250e42d3f4afe5..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/Aerodynamics_drag_1D_interpolation.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/Aerodynamics_forces_1D_interpolation.png b/doc_src/tutorials/aerostruct/Aerodynamics_forces_1D_interpolation.png deleted file mode 100644 index f42a85cf6c547ff6ec5303f791b72c954e7729c8..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/Aerodynamics_forces_1D_interpolation.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/Aerodynamics_lift_1D_interpolation.png b/doc_src/tutorials/aerostruct/Aerodynamics_lift_1D_interpolation.png deleted file mode 100644 index d11ac70d5cf1716f92a5b97442b32baa48600439..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/Aerodynamics_lift_1D_interpolation.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/OAD_range_1D_interpolation.png b/doc_src/tutorials/aerostruct/OAD_range_1D_interpolation.png deleted file mode 100644 index 431b5b63cef6f0de5845ced5972e3ccec8f660a0..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/OAD_range_1D_interpolation.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/Structure_RF_1D_interpolation.png b/doc_src/tutorials/aerostruct/Structure_RF_1D_interpolation.png deleted file mode 100644 index 913b450480f5853047758f9ddaf57b8b51ec8867..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/Structure_RF_1D_interpolation.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/Structure_displ_1D_interpolation.png b/doc_src/tutorials/aerostruct/Structure_displ_1D_interpolation.png deleted file mode 100644 index ad939a686ffb6a6750a73ce22d607ea07f381483..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/Structure_displ_1D_interpolation.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/Structure_mass_1D_interpolation.png b/doc_src/tutorials/aerostruct/Structure_mass_1D_interpolation.png deleted file mode 100644 index f636873ff836aff83af4b9e0b4f60ed7704d3205..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/Structure_mass_1D_interpolation.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/aerostruct_toy_example.rst b/doc_src/tutorials/aerostruct/aerostruct_toy_example.rst deleted file mode 100644 index eeec11465532ff00f3c204d751e92e1dcf5e5153..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/aerostruct/aerostruct_toy_example.rst +++ /dev/null @@ -1,267 +0,0 @@ -.. - Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com - - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 - International License. To view a copy of this license, visit - http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative - Commons, PO Box 1866, Mountain View, CA 94042, USA. - -.. - Contributors: - :author: Matthias De Lozzo - -.. _aerostruct_toy_example: - -MDO formulations and scalable models for a toy example in aerostructure -======================================================================= - -This tutorial describes how to build and run a scalable problem by means of |g| for the :ref:`Sobieski SSBJ aerostructure problem `. - -Creation of the disciplines -*************************** - -In this tutorial, we are creating the disciplines from their analytic formulation using the :class:`~gemseo.disciplines.analytic.AnalyticDiscipline` discipline class. -We also configure the GEMSEO logger with the :func:`configure_logger` function. - -.. code:: - - from typing import Iterable - - from gemseo import configure_logger - from gemseo import create_discipline - from gemseo.core.discipline.discipline import Discipline - - configure_logger() - - def create_disciplines() -> Iterable[Discipline]: - """Create the disciplines (aero, structure, OAD) with analytic formulas. - - Returns: - The disciplines (aero, structure, OAD). - """ - aero_formulas = {"drag": "0.1*((sweep/360)**2 + 200 + thick_airfoils**2-thick_airfoils -4*displ)", - "forces": "10*sweep + 0.2*thick_airfoils-0.2*displ", - "lift": "(sweep + 0.2*thick_airfoils-2.*displ)/3000."} - aerodynamics = create_discipline("AnalyticDiscipline", name="Aerodynamics", - expressions=aero_formulas) - struc_formulas = {"mass": "4000*(sweep/360)**3 + 200000 + 100*thick_panels +200.0*forces", - "RF": "-3*sweep + -6*thick_panels+0.1*forces+55" - , - "displ": "2*sweep + 3*thick_panels-2.*forces"} - structure = create_discipline("AnalyticDiscipline", name="structure", - expressions=struc_formulas) - oad_formulas = {"range": "8e11*lift/(mass*drag)"} - oad = create_discipline("AnalyticDiscipline", name="OAD", - expressions=oad_formulas) - return [aerodynamics, structure, oad] - - disciplines = create_disciplines() - - -Description of the MDO study -**************************** - -The goal of this study is to maximize the range :math:`range` with respect to the design parameters which are: - - - :math:`thick\_airfoils` - - :math:`thick\_panels` - - :math:`sweep` - -Different MDO formulations can be considered to address this study. - -Monolithic formulations ------------------------ - -Monolithic formulations can be used to address this MDO study: - - - Multiple Discipline Feasible (:class:`.MDF`): a Multiple Disciplinary Analysis is performed for each optimisation iteration to converge the coupling variables disciplines to their equilibrium values - - Individual Discipline Feasible (:class:`.IDF`): the coupling variables equalities between the disciplines are set as constraints of the optimizer. - -MDF -^^^ - -The :class:`.MDF` formulation for the current problem is as follows: - -.. code:: - - Optimization problem: - Minimize: -range(sweep, thick_airfoils, thick_panels) - With respect to: - sweep, thick_airfoils, thick_panels - Subject to constraints: - lift(sweep, thick_airfoils, thick_panels) = lift + -0.5 = 0 - RF(sweep, thick_airfoils, thick_panels) = RF + -0.5 <= 0 - -The XDSM for the MDF formulation is displayed below: - -.. figure:: xdsm_mdf.png - - -IDF -^^^ - -The :class:`.IDF` formulation for the current problem is as follows: - -.. code:: - - Optimization problem: - Minimize: -range(mass, drag, lift) - With respect to: - sweep, thick_airfoils, thick_panels, mass, drag, forces, displ, lift - Subject to constraints: - drag_lift_forces(sweep, thick_airfoils, displ) = drag(sweep, thick_airfoils, displ) - drag = 0 - lift(sweep, thick_airfoils, displ) - lift = 0 - forces(sweep, thick_airfoils, displ) - forces = 0 - mass_displ(sweep, thick_panels, forces) = mass(sweep, thick_panels, forces) - mass = 0 - displ(sweep, thick_panels, forces) - displ = 0 - lift(sweep, thick_airfoils, displ) = lift + -0.5 = 0 - RF(sweep, thick_panels, forces) = RF + -0.5 <= 0 - -As previously stressed, the coupling variables have become optimization variables in this MDO formulation. The XDSM for the IDF formulation is as follows: - -.. figure:: xdsm_idf.png - -BiLevel -------- - -A :class:`.BiLevel` formulation can be considered for the following MDO problem. It consists of performing optimizations at two levels: - - - at the system level, an optimization is made with respect to the shared design variables - - at the discipline level, for each discipline, an optimization is made with respect to the local discipline design variable. - -Discipline optimizations are performed in parallel. MDAs are performed at the beginning and at the end of each system level optimization iteration in order to get converged coupling variables. - -System level -^^^^^^^^^^^^ - -The optimization problem for the system level reads: - -.. code:: - - Optimization problem: - Minimize: -range(sweep) - With respect to: - sweep - Subject to constraints: - lift(sweep) = lift + -0.5 = 0 - RF(sweep) = RF + -0.5 <= 0 - -Aerodynamics level -^^^^^^^^^^^^^^^^^^ - -The optimization problem for the aerodynamics discipline level reads: - -.. code:: - - Optimization sub-problem: - Minimize: -range(thick_airfoils) - With respect to: - thick_panels - Subject to constraints: - lift(thick_airfoils) = lift + -0.5 <= 0 - -Structure level -^^^^^^^^^^^^^^^ - -The optimization problem for the structure discipline level reads: - -.. code:: - - Optimization sub-problem: - Minimize: -range(thick_panels) - With respect to: - thick_panels - Subject to constraints: - RF(thick_panels) = RF + -0.5 <= 0 - -.. figure:: xdsm_bilevel.png - - The XDSM for the bi-level formulation - -The scalable problem -******************** - -In this section, we are going to build a scalable problem from the aerostructure problem. Further information on the scalable problem methodology can be found :ref:`here `. - -Build the interpolation functions ---------------------------------- - -We build the interpolation functions from the disciplines: - -.. code:: - - from gemseo.problems.mdo.aerostructure.aerostructure_design_space import AerostructureDesignSpace - from gemseo.problems.mdo.scalable.data_driven.diagonal import ScalableDiagonalModel - - - def create_scalable_models(disciplines: Iterable[Discipline], n_samples: int = 20, - fill_factor: float = 0.8) -> Iterable[ScalableDiagonalModel]: - """Create the scalable disciplines. - - Args: - disciplines: The disciplines. - n_samples: The number of samples. - fill_factor: The fill factor. - - Returns: - The scalable models. - """ - design_space = AerostructureDesignSpace() - design_space.set_current_value(design_space.get_current_value().real) - sizes = design_space.variable_sizes - scalable_models = [] - for discipline in disciplines: - discipline.set_cache(cache_type=discipline.CacheType.MEMORY_FULL) - output = next(iter(discipline.output_grammar.names)) - disc_design_space = deepcopy(design_space) - disc_design_space.filter(discipline.input_grammar.names) - scenario = create_scenario([discipline], "DisciplinaryOpt", output, - disc_design_space, scenario_type="DOE") - scenario.execute(algo_name="DiagonalDOE", n_samples=n_samples) - scalable_model = ScalableDiagonalModel( - discipline.cache.to_dataset(), sizes, fill_factor=fill_factor - ) - scalable_models.append(scalable_model) - return scalable_models - -.. code:: - - scalable_models = create_scalable_models(disciplines) - -Plot the interpolation function -------------------------------- - -We can easily plot the interpolation functions: - -.. code:: - - for scalable_model in scalable_models: - scalable_model.plot_1d_interpolations(save=True) - -We obtain the following plots for the three disciplines. - -Aerodynamics -^^^^^^^^^^^^ - -+-------------------------------------------------------+------------------------------------------------------+-------------------------------------------------------+ -| .. figure:: Aerodynamics_drag_1D_interpolation.png | .. figure:: Aerodynamics_lift_1D_interpolation.png | .. figure:: Aerodynamics_forces_1D_interpolation.png | -+-------------------------------------------------------+------------------------------------------------------+-------------------------------------------------------+ -| Interpolation of drag(sweep, thickAirfoils, displ) | Interpolation of lift(sweep, thickAirfoils, displ)| Interpolation of forces(sweep, thickAirfoils, displ) | -+-------------------------------------------------------+------------------------------------------------------+-------------------------------------------------------+ - -Structure -^^^^^^^^^ - -+-------------------------------------------------------+-------------------------------------------------------+-------------------------------------------------------+ -| .. figure:: Structure_RF_1D_interpolation.png | .. figure:: Structure_mass_1D_interpolation.png | .. figure:: Structure_displ_1D_interpolation.png | -+-------------------------------------------------------+-------------------------------------------------------+-------------------------------------------------------+ -| Interpolation of RF(sweep, thickPanels, forces) | Interpolation of mass(sweep, thickAirfoils, forces)| Interpolation of displ(sweep, thickAirfoils, forces) | -+-------------------------------------------------------+-------------------------------------------------------+-------------------------------------------------------+ - -OAD -^^^ - -.. figure:: OAD_range_1D_interpolation.png - :width: 30% - - Interpolation of range(lift, mass, drag) diff --git a/doc_src/tutorials/aerostruct/figures/xdsm_bilevel.png b/doc_src/tutorials/aerostruct/figures/xdsm_bilevel.png deleted file mode 100644 index 23db952f83038bd0ab4be6853e66232ea1aadec9..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/figures/xdsm_bilevel.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/figures/xdsm_idf.png b/doc_src/tutorials/aerostruct/figures/xdsm_idf.png deleted file mode 100644 index 273fa3f56e1768a87c1ce40c9fddaa84a271103b..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/figures/xdsm_idf.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/figures/xdsm_mdf.png b/doc_src/tutorials/aerostruct/figures/xdsm_mdf.png deleted file mode 100644 index fcc7cd35c7df6739accf8bf55e034755cf46f39e..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/figures/xdsm_mdf.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/xdsm_bilevel.png b/doc_src/tutorials/aerostruct/xdsm_bilevel.png deleted file mode 100644 index 23db952f83038bd0ab4be6853e66232ea1aadec9..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/xdsm_bilevel.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/xdsm_idf.png b/doc_src/tutorials/aerostruct/xdsm_idf.png deleted file mode 100644 index 273fa3f56e1768a87c1ce40c9fddaa84a271103b..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/xdsm_idf.png and /dev/null differ diff --git a/doc_src/tutorials/aerostruct/xdsm_mdf.png b/doc_src/tutorials/aerostruct/xdsm_mdf.png deleted file mode 100644 index fcc7cd35c7df6739accf8bf55e034755cf46f39e..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/aerostruct/xdsm_mdf.png and /dev/null differ diff --git a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_hessian_approx.png b/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_hessian_approx.png deleted file mode 100644 index e2e003a005597fa264e7d49b110be985d732ff4d..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_hessian_approx.png and /dev/null differ diff --git a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_obj_history.png b/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_obj_history.png deleted file mode 100644 index 2646a2535bc114f168eae4200890af33c8772341..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_obj_history.png and /dev/null differ diff --git a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_variables_history.png b/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_variables_history.png deleted file mode 100644 index 836cfa4e3bd38a41870a3225cda07e93dbfb23e0..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_variables_history.png and /dev/null differ diff --git a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_x_xstar_history.png b/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_x_xstar_history.png deleted file mode 100644 index 92f64cb6fe721aa1dca4c56f51e1b4db54c12813..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/basics_of_optimization/opt_view_from_disk_x_xstar_history.png and /dev/null differ diff --git a/doc_src/tutorials/basics_of_optimization/simple_opt_example.py b/doc_src/tutorials/basics_of_optimization/simple_opt_example.py deleted file mode 100644 index 50e98a7707d47e2d7fee2efc4284745a43af7516..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/basics_of_optimization/simple_opt_example.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com -# -# This work is licensed under a BSD 0-Clause License. -# -# Permission to use, copy, modify, and/or distribute this software -# for any purpose with or without fee is hereby granted. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -# THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, -# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING -# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from __future__ import annotations - -import numpy as np -from scipy import optimize - -from gemseo import create_design_space -from gemseo import create_discipline -from gemseo import create_scenario -from gemseo import execute_post -from gemseo import get_available_opt_algorithms - -# PART 1 - - -def f(x1=0.0, x2=0.0): - y = x1 + x2 - return y - - -discipline = create_discipline("AutoPyDiscipline", py_func=f) - -design_space = create_design_space() -design_space.add_variable("x1", lower_bound=-5, upper_bound=5, type_="integer") -design_space.add_variable("x2", lower_bound=-5, upper_bound=5, type_="integer") - -scenario = create_scenario( - discipline, - "y", - design_space, - scenario_type="DOE", - formulation_name="DisciplinaryOpt", -) -scenario.execute(algo_name="PYDOE_FULLFACT", n_samples=11**2) - -opt_results = scenario.optimization_result -print(f"The solution of P is (x*, f(x*)) = ({opt_results.x_opt}, {opt_results.f_opt})") - - -# PART 2 - - -def g(x=0): - y = np.sin(x) - np.exp(x) - return y - - -def dgdx(x=0): - y = np.cos(x) - np.exp(x) - return y - - -x_0 = -0.5 * np.ones(1) -opt = optimize.fmin_l_bfgs_b(g, x_0, fprime=dgdx, bounds=[(-0.2, 2.0)]) -x_opt, f_opt, _ = opt -print(f"The solution of P is (x*, f(x*)) = ({x_opt[0]}, {f_opt[0]})") - - -# PART 3 - -discipline = create_discipline("AutoPyDiscipline", py_func=g, py_jac=dgdx) - -design_space = create_design_space() -design_space.add_variable( - "x", lower_bound=-2.0, upper_bound=2.0, value=-0.5 * np.ones(1) -) - -scenario = create_scenario( - discipline, "y", design_space, formulation_name="DisciplinaryOpt" -) -scenario.execute(algo_name="L-BFGS-B", max_iter=100) - -opt_results = scenario.optimization_result -print(f"The solution of P is (x*,f(x*)) = ({opt_results.x_opt}, {opt_results.f_opt})") - -algo_list = get_available_opt_algorithms() -print("Available algorithms:" + str(algo_list)) - -# POST TREATMENTS - -problem = scenario.formulation.optimization_problem -problem.to_hdf("my_optim.hdf5") -execute_post(problem, "OptHistoryView", save=True, file_path="opt_view_with_doe") -# or execute_post("my_optim.hdf5", "OptHistoryView", save=True, -# file_path="opt_view_from_disk") diff --git a/doc_src/tutorials/basics_of_optimization/simple_opt_example.rst b/doc_src/tutorials/basics_of_optimization/simple_opt_example.rst deleted file mode 100644 index 3f672f126b88b7ed61c56d88fa63ed33859ef9eb..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/basics_of_optimization/simple_opt_example.rst +++ /dev/null @@ -1,347 +0,0 @@ -.. - Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com - - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 - International License. To view a copy of this license, visit - http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative - Commons, PO Box 1866, Mountain View, CA 94042, USA. - -.. - Contributors: - :author: Matthias De Lozzo - -.. _simple_opt_example: - -Tutorial: How to solve an optimization problem -============================================== - -Although the library |g| is dedicated to the :term:`MDO`, it can also be used for mono-disciplinary optimization problems. -This tutorial presents some examples on analytical test cases. - -1. Optimization based on a design of experiments -************************************************ - -Let :math:`(P)` be a simple optimization problem: - -.. math:: - - (P) = \left\{ - \begin{aligned} - & \underset{x\in\mathbb{N}^2}{\text{minimize}} - & & f(x) = x_1 + x_2 \\ - & \text{subject to} - & & -5 \leq x \leq 5 - \end{aligned} - \right. - -In this subsection, we will see how to use |g| to solve this problem :math:`(P)` by means of a Design Of Experiments (DOE) - -1.a. Define the objective function -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Firstly, by means of the :func:`.create_discipline` API function, -we create an :class:`.Discipline` of :class:`.AutoPyDiscipline` type -from a python function. -We also configure the GEMSEO logger with the :func:`configure_logger` function. - - -.. code:: python - - from gemseo import configure_logger - from gemseo import create_discipline - - configure_logger() - - def f(x1=0., x2=0.): - y = x1 + x2 - return y - - discipline = create_discipline("AutoPyDiscipline", py_func=f) - -Now, we want to minimize this :class:`.Discipline` over a design of experiments (DOE). - -1.b. Define the design space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For that, by means of the :func:`.create_design_space` API function, -we define the :class:`.DesignSpace` :math:`[-5, 5]\times[-5, 5]` -by using its :meth:`~.DesignSpace.add_variable` method. - -.. code:: python - - from gemseo import create_design_space - - design_space = create_design_space() - design_space.add_variable("x1", 1, lower_bound=-5, upper_bound=5, type_="integer") - design_space.add_variable("x2", 1, lower_bound=-5, upper_bound=5, type_="integer") - -1.c. Define the DOE scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Then, by means of the :func:`.create_scenario` API function, -we define a :class:`.DOEScenario` from the :class:`.Discipline` -and the :class:`.DesignSpace` defined above: - -.. code:: python - - from gemseo import create_scenario - - scenario = create_scenario( - discipline, "DisciplinaryOpt", "y", design_space, scenario_type="DOE" - ) - -1.d. Execute the DOE scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Lastly, we solve the :class:`.OptimizationProblem` included in the :class:`.DOEScenario` -defined above by minimizing the objective function over a design of experiments included in the :class:`.DesignSpace`. -Precisely, we choose a `full factorial design `_ of size :math:`11^2`: - -.. code:: python - - scenario.execute(algo_name="PYDOE_FULLFACT", n_samples=11**2) - -The optimum results can be found in the execution log. It is also possible to -extract them from the :attr:`.Scenario.optimization_result`. - -.. code:: python - - optimization_result = scenario.optimization_result - print(f"The solution of P is (x*,f(x*)) = ({optimization_result.x_opt}, {optimization_result.f_opt})") - -which yields: - -.. code:: bash - - The solution of P is (x*,f(x*)) = ([-5, -5], -10.0). - -2. Optimization based on a quasi-Newton method by means of the library `scipy `_ -**************************************************************************************************** - -Let :math:`(P)` be a simple optimization problem: - -.. math:: - - (P) = \left\{ - \begin{aligned} - & \underset{x}{\text{minimize}} - & & f(x) = \sin(x) - \exp(x) \\ - & \text{subject to} - & & -2 \leq x \leq 2 - \end{aligned} - \right. - -In this subsection, we will see how to use |g| to solve this problem :math:`(P)` by means of an optimizer -directly used from the library `SciPy `_. - -2.a. Define the objective function -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Firstly, we create the objective function and its gradient as standard python functions: - -.. code-block:: python - - import numpy as np - - def g(x=0): - y = np.sin(x) - np.exp(x) - return y - - def dgdx(x=0): - y = np.cos(x) - np.exp(x) - return y - -2.b. Minimize the objective function -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now, we can minimize this python function over its design space by means of -the `L-BFGS-B algorithm `_ implemented in the function ``scipy.optimize.fmin_l_bfgs_b``. - -.. code-block:: python - - from scipy import optimize - - x_0 = -0.5 * np.ones(1) - opt = optimize.fmin_l_bfgs_b(g, x_0, fprime=dgdx, bounds=[(-.2, 2.)]) - x_opt, f_opt, _ = opt - -Then, we can display the solution of our optimization problem with the following code: - -.. code:: - - print(f"The solution of P is (x*,f(x*)) = ({x_opt[0]}, {f_opt}).") - -which gives: - -.. code:: bash - - The solution of P is (x*,f(x*)) = (-0.2, -1.017400083873043). - -.. seealso:: - - You can found the scipy implementation of the L-BFGS-B algorithm `by clicking here `_. - -3. Optimization based on a quasi-Newton method by means of the |g| optimization interface -***************************************************************************************** - -Let :math:`(P)` be a simple optimization problem: - -.. math:: - - (P) = \left\{ - \begin{aligned} - & \underset{x}{\text{minimize}} - & & f(x) = \sin(x) - \exp(x) \\ - & \text{subject to} - & & -2 \leq x \leq 2 - \end{aligned} - \right. - -In this subsection, we will see how to use |g| to solve this problem :math:`(P)` by means of an optimizer -from `SciPy `_ called through the optimization interface of |g|. - -3.a. Define the objective function -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Firstly, by means of the :func:`.create_discipline` API function, -we create an :class:`.Discipline` of :class:`.AutoPyDiscipline` type -from a python function: - -.. code-block:: python - - import numpy as np - from gemseo import create_discipline - - def g(x=0): - y = np.sin(x) - np.exp(x) - return y - - def dgdx(x=0): - y = np.cos(x) - np.exp(x) - return y - - discipline = create_discipline("AutoPyDiscipline", py_func=g, py_jac=dgdx) - -Now, we can to minimize this :class:`.Discipline` over a design space, -by means of a quasi-Newton method from the initial point :math:`0.5`. - -3.b. Define the design space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For that, by means of the :func:`.create_design_space` API function, -we define the :class:`.DesignSpace` :math:`[-2., 2.]` -with initial value :math:`0.5` -by using its :meth:`~.DesignSpace.add_variable` method. - -.. code:: - - from gemseo import create_design_space - - design_space = create_design_space() - design_space.add_variable("x", 1, lower_bound=-2., upper_bound=2., value=-0.5 * np.ones(1)) - -3.c. Define the optimization problem -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Then, by means of the :func:`.create_scenario` API function, -we define an :class:`.MDOScenario` from the :class:`.Discipline` -and the :class:`.DesignSpace` defined above: - -.. code:: - - from gemseo import create_scenario - - scenario = create_scenario( - discipline, "DisciplinaryOpt", "y", design_space, scenario_type="MDO" - ) - -3.d. Execute the optimization problem -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Lastly, we solve the :class:`.OptimizationProblem` included in the :class:`.MDOScenario` -defined above by minimizing the objective function over the :class:`.DesignSpace`. -Precisely, we choose the `L-BFGS-B algorithm `_ -implemented in the function ``scipy.optimize.fmin_l_bfgs_b`` and -indirectly called by means of the class :class:`.OptimizationLibraryFactory` and of its function :meth:`~.BaseAlgoFactory.execute`: - -.. code-block:: python - - scenario.execute(algo_name="L-BFGS-B", max_iter=100) - -The optimization results are displayed in the log file. They can also be -obtained using the following code: - -.. code:: - - optimization_result = scenario.optimization_result - print(f"The solution of P is (x*,f(x*)) = ({optimization_result.x_opt}, {optimization_result.f_opt}).") - - -which yields: - -.. code:: - - The solution of P is (x*,f(x*)) = (-1.29, -1.24). - -.. seealso:: - - You can find the `SciPy `_ implementation of the `L-BFGS-B algorithm `_ algorithm `by clicking here `_. - -.. tip:: - - In order to get the list of available optimization algorithms, use: - - .. code:: - - from gemseo import get_available_opt_algorithms - - algo_list = get_available_opt_algorithms() - print(f"Available algorithms: {algo_list}") - - which gives: - - .. code:: - - Available algorithms: ['NLOPT_SLSQP', 'L-BFGS-B', 'SLSQP', 'NLOPT_COBYLA', 'NLOPT_BFGS', 'NLOPT_NEWUOA', 'TNC', 'P-L-BFGS-B', 'NLOPT_MMA', 'NLOPT_BOBYQA', 'ODD'] - - -4. Saving and post-processing -***************************** - -After the resolution of the :class:`~gemseo.algos.optimization_problem.OptimizationProblem`, we can export the results into a :term:`HDF` file: - -.. code:: - - problem = scenario.formulation.optimization_problem - problem.to_hdf("my_optim.hdf5") - -We can also post-process the optimization history by means of the function :func:`.execute_post`, -either from the :class:`~gemseo.algos.optimization_problem.OptimizationProblem`: - -.. code:: - - from gemseo import execute_post - - execute_post(problem, "OptHistoryView", save=True, file_path="opt_view_with_doe") - -or from the :term:`HDF` file created above: - -.. code:: - - from gemseo import execute_post - - execute_post("my_optim.hdf5", "OptHistoryView", save=True, file_path="opt_view_from_disk") - -This command produces a series of PDF files: - -.. image:: opt_view_from_disk_variables_history.png - :scale: 50% - -.. image:: opt_view_from_disk_obj_history.png - :scale: 50% - -.. image:: opt_view_from_disk_x_xstar_history.png - :scale: 50% - -.. image:: opt_view_from_disk_hessian_approx.png - :scale: 50% diff --git a/doc_src/tutorials/index.rst b/doc_src/tutorials/index.rst deleted file mode 100644 index 5b9b70cd3047e99dc5da26ea5bb59695eba81321..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/index.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. - Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com - - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 - International License. To view a copy of this license, visit - http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative - Commons, PO Box 1866, Mountain View, CA 94042, USA. - - -.. - Contributors: - :author: Matthias De Lozzo - -:parenttoc: True - -.. _tutorials_sg: - -Tutorials -========= - -.. toctree:: - :maxdepth: 1 - - Solve an optimization problem - Solve an MDO problem - Carry out a trade-off study - Build a scalable model (Sellar) - Build a scalable model (Aerostructure) diff --git a/doc_src/tutorials/scalable/scalable.rst b/doc_src/tutorials/scalable/scalable.rst deleted file mode 100644 index c25a2e38d348475d7b97bea546e2e8be5f534463..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/scalable/scalable.rst +++ /dev/null @@ -1,203 +0,0 @@ -.. - Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com - - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 - International License. To view a copy of this license, visit - http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative - Commons, PO Box 1866, Mountain View, CA 94042, USA. - -.. - Contributors: - :author: Matthias De Lozzo - -.. _sellar_scalable: - -Tutorial: Build a scalable model -==================================== - -In this tutorial, -we are going to build a scalable version -of the :class:`.Sellar1` :class:`.Discipline`. -As a reminder, its expression reads: - -:math:`y_1(x_{shared},x_{local},y_2)=\sqrt{x_{shared,1}^2+x_{shared,2}+x_{local}-0.2y_2}`. - -.. seealso:: - - - The Sellar's problem is described in :ref:`Sellar's problem `. - - The scalable problem is described in :ref:`scalable`. - -1. Overview ------------ - -The expected outputs sizes are specified in a dictionary. The keys are the output names and the values are the sizes. -Here, we take 5 for the dimension of all outputs (here "y\_1", which is of dimension 1 in the standard :class:`.Sellar1`). - -2. Creation of the discipline ------------------------------ - -First of all, we create the reference :class:`.Discipline`: with the help of the :class:`~gemseo.create_discipline` API function and the argument ``"Sellar1"``. As a reminder, this argument refers to the class :class:`.Sellar1`, which is internally known by |g| by means of the :class:`.DisciplineFactory`. - -.. code:: - - from gemseo import create_discipline - - sellar = create_discipline("Sellar1") - -.. tip:: - - It is possible to implement a new discipline in a directory outside of the |g| directory (see :ref:`extending-gemseo`). - Then, the user has to create a new class :class:`!NewDiscipline` inheriting from :class:`.Discipline`. - Then, the code reads: - - .. code:: - - from gemseo import create_discipline - - newdiscipline = create_discipline("NewDiscipline") - -Then, the scalable discipline can be created. - -2. Creation of the scalable discipline --------------------------------------- - -In |g|, scalable disciplines are defined by the class :class:`.DataDrivenScalableDiscipline` that inherits from :class:`.Discipline`. - -Such a scalable discipline takes as mandatory arguments: - -- a ``hdf_file_path`` with its ``hdf_node_path`` storing the evaluations of the :class:`.Discipline`, here ``sellar``, over a :class:`.DiagonalDOE`, -- a ``sizes`` dictionary describing the required sizes of inputs and outputs, -- a ``fill_factor`` describing the probability of connection between an input and an output in the :class:`.DataDrivenScalableDiscipline`, - -and optional ones : - -- a ``comp_dep`` matrix (default: ``None``) that establishes the selection of a single original component for each scalable component, -- a ``inpt_dep`` matrix (default: ``None``) that establishes the dependency of outputs w.r.t. inputs, -- a ``force_input_dependency`` assertion (default: ``False``) describing that for any output, force dependency with at least on input, -- a ``allow_unused_inputs`` assertion (default: ``False``) describing the possibility to have an input with no dependence with any output -- a ``seed`` (default: ``1``) - -2.1. Sample the discipline -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``hdf_file_path`` file is built from the :func:`.create_scenario` API function applied to the :class:`.Discipline` instance, ``sellar``, -with ``DOE`` scenario type and the following :class:`.DesignSpace`: - -.. code:: - - from gemseo.problems.mdo.sellar.sellar_design_space import SellarDesignSpace - - design_space = SellarDesignSpace() - -The DOE algorithm is ``'DiagonalDOE'`` and use a sampling of size ``n_samples=30``: - -.. code:: - - from gemseo import create_scenario - - sellar.set_cache(cache_type='HDF5_cache', cache_tolerance=1e-6, cache_hdf_file='sellar.hdf5') - output = list(sellar.output_grammar.names)[0] - scenario = create_scenario([sellar], 'DisciplinaryOpt', output, - design_space, scenario_type='DOE') - scenario.execute(algo_name='DiagonalDOE', n_samples=30) - -A :class:`.DiagonalDOE` consists of equispaced points located on the diagonal of the design space. - -2.2. Define the input and output dimensions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A scalable discipline is a discipline version for which inputs and outputs can take arbitrary dimensions: - -.. code:: - - # Set the size of input and output variables at 5 - # - Number of n_x = number_of_inputs*variable_sizes - # - Number of n_y = number_of_outputs*variable_sizes - variable_sizes = 5 - input_names = sellar.get_input_data_names() - output_names = list(sellar.output_grammar.names) - sizes = {name: variable_sizes for name in input_names + output_names} - -The ``sizes`` of the inputs are specified in a dictionary at the construction of the :class:`.DataDrivenScalableDiscipline` instance. - -Lastly, we define the density factor for the matrix S describing the dependencies between the inputs and the outputs of the discipline: - -.. code:: - - # Density factor for the dependency matrix S - fill_factor = 0.6 - -From this, we can create the :class:`.DataDrivenScalableDiscipline` by means of the API function :func:`.create_discipline`: - -.. code:: - - # Creation of the scalable discipline - scalable_sellar = create_discipline('DataDrivenScalableDiscipline', - hdf_file_path='sellar.hdf5', - hdf_node_path='Sellar1', - sizes=sizes, - fill_factor=fill_factor) - -3. Run the scalable discipline ------------------------------- - -After its creation, -the scalable discipline can be executed -by means of the :meth:`.Discipline.execute` method. -For this, -we build an input dictionary. -Remember that the inputs and outputs shall all be in :math:`(0,1)` (see :ref:`scalable`). -Here we take :math:`( 0. , 0.2, 0.4, 0.6, 0.8)` -for all inputs of the discipline ("x\_shared", "x\_local", and "y\_2"). - -.. code:: - - from numpy import arange - - input_data = {name: arange(variable_sizes) / float(variable_sizes) - for name in input_names} - print(scalable_sellar.execute(input_data)['y_1']) - -The output of the discipline is: - -.. code:: - - [0.64353709 0.3085585 0.36497918 0.48043751 0.56740874] - -of dimension 5, as expected. - -Arbitrary input dimensions arrays can be provided. Here, only three components for all inputs and outputs are considered: - -.. code:: - - variable_sizes = 3 - sizes = {name: variable_sizes for name in input_names + output_names} - scalable_sellar = create_discipline('DataDrivenScalableDiscipline', - hdf_file_path='sellar.hdf5', - hdf_node_path='Sellar1', - sizes=sizes, - fill_factor=fill_factor) - input_data = {name: arange(variable_sizes) / float(variable_sizes) - for name in input_names} - - print(scalable_sellar.execute(input_data)['y_1']) - -The scalable discipline outputs different values : - -.. code:: - - [ 0.45727936 0.45727936 0.52084604] - -We can see that multiple components of the output may be identical, because the original Sellar problem is of very low dimensions (1 or 2). -Therefore, the combinatorial effects that the scalable methodology uses to generate the outputs is not exploited (see :ref:`scalable`). -We obtain different output components in higher dimension. - -4. Perspectives ---------------- - -This :class:`.DataDrivenScalableDiscipline` can now be included as any other in an :class:`.MDOScenario` to compare the scalability of MDO or coupling strategies. - -Such a :class:`.DataDrivenScalableDiscipline` as two main advantages: - -- The execution time shall be very small even for thousands of inputs and outputs. -- Analytical derivatives are also available (Jacobian matrices), even if the original discipline has no analytic derivatives. diff --git a/doc_src/tutorials/scalable/scalable_sellar.py b/doc_src/tutorials/scalable/scalable_sellar.py deleted file mode 100644 index ba30972b90c0b2313fcaf1eda5f0f2a1c1a7b0e5..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/scalable/scalable_sellar.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com -# -# This work is licensed under a BSD 0-Clause License. -# -# Permission to use, copy, modify, and/or distribute this software -# for any purpose with or without fee is hereby granted. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -# THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, -# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING -# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# Contributors: -# INITIAL AUTHORS - initial API and implementation -# and/or initial documentation -# @author: Francois Gallard -# OTHER AUTHORS - MACROSCOPIC CHANGES -from __future__ import annotations - -from numpy import arange - -from gemseo import create_discipline -from gemseo.problems.mdo.sellar.sellar_design_space import SellarDesignSpace - -sellar = create_discipline("Sellar1") -design_space = SellarDesignSpace() -input_names = sellar.io.input_grammar.names -output_names = sellar.io.output_grammar.names -var_lb = {name: design_space.get_lower_bound(name) for name in input_names} -var_ub = {name: design_space.get_upper_bound(name) for name in input_names} - -variable_sizes = 5 -sizes = dict.fromkeys(input_names + output_names, variable_sizes) -scalable_sellar = create_discipline( - "ScalableFittedDiscipline", - discipline=sellar, - var_lb=var_lb, - var_ub=var_ub, - sizes=sizes, - fill_factor=0.6, -) - -input_data = { - name: arange(variable_sizes) / float(variable_sizes) for name in input_names -} -print(scalable_sellar.execute(input_data)["y_1"]) - -variable_sizes = 3 -sizes = dict.fromkeys(input_names + output_names, variable_sizes) -scalable_sellar = create_discipline( - "ScalableFittedDiscipline", - discipline=sellar, - var_lb=var_lb, - var_ub=var_ub, - sizes=sizes, - fill_factor=0.6, -) - -input_data = { - name: arange(variable_sizes) / float(variable_sizes) for name in input_names -} -print(scalable_sellar.execute(input_data)["y_1"]) diff --git a/doc_src/tutorials/sellar/nutshell.rst b/doc_src/tutorials/sellar/nutshell.rst deleted file mode 100644 index 875980340f96bfc4a6642bfbc66133569fd28a9f..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/sellar/nutshell.rst +++ /dev/null @@ -1,730 +0,0 @@ -.. - Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com - - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 - International License. To view a copy of this license, visit - http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative - Commons, PO Box 1866, Mountain View, CA 94042, USA. - -.. - Contributors: - :author: Francois Gallard, Charlie Vanaret - -.. _sellar_mdo: - -Tutorial: How to solve an MDO problem -===================================== - -This tutorial describes how to solve an MDO problem by means of |g|. -For that, we consider the :ref:`Sellar problem `. - -Step 1 : Creation of disciplines --------------------------------- - -In order to solve the :ref:`Sellar problem ` with |g|, -we need first to model this set of equations as a **multidisciplinary problem**. - -For that, the problem is decomposed into three :term:`disciplines `. - -What defines an :class:`.Discipline` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A discipline is a set of calculations that produces a set of -vector outputs from a set of vector inputs, using either equations or an external software, -or a :term:`workflow engine`. - -Programmatically speaking, in |g|, an :class:`.Discipline` is defined by three elements : - -- the **input grammar** : the set of rules that defines valid input data, -- the **output grammar** : the set of rules that defines valid output data, -- the **method to compute the output data from the input data**, - here the :meth:`!Discipline._run` method. - -The disciplines are all subclasses of :class:`.Discipline`, from which they must inherit. - -.. seealso:: - - The :term:`grammar` is a very powerful and key concept. - There are multiple ways of creating grammars in |g|. - The preferred one for integrating simulation processes is the use of a :term:`JSON schema`, - but is not detailed here for the sake of simplicity. - For more explanations about grammars, see :ref:`software_connection`. - -.. warning:: - - All the inputs and outputs names of the disciplines in a scenario shall be consistent. - - - |g| assumes that the data are tagged by their names - with a global convention in the whole process. - - What two disciplines call "X" shall be the same "X". - For instance, the coupling variables are detected thanks to these conventions. - -1.1. Define the input and output grammars of the discipline -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We create a class for each discipline inheriting from :class:`.Discipline`. -After having called the super constructor :meth:`!Discipline.__init__`, -we complete the constructor of the new discipline -by declaring the :ref:`Sellar ` discipline input data names :attr:`!Discipline.input_grammar` -and discipline output data names :attr:`!Discipline.output_grammar` -in a straightforward way with :meth:`.BaseGrammar.update_from_names` . - -.. warning:: - - These inputs and outputs shall be `NumPy `_ arrays of numbers. - The grammars will check this at each execution - and prevent any discipline from running with invalid data, - or raise an error if outputs are invalid, - which happens sometimes with simulation software... - -For example, in the case of Sellar 1, we build: - -.. code:: - - from gemseo.core.discipline import Discipline - from numpy import array, ones - - class Sellar1(Discipline): - - def __init__(self): - super().__init__() - self.input_grammar.update_from_names(['x_local', 'x_shared', 'y_2']) - self.output_grammar.update_from_names(['y_1']) - -.. seealso:: - - An alternative way to declare the inputs and outputs - is the usage of :term:`JSON schema`, see :ref:`software_connection`. - This gives more control on the type of data - that are considered valid inputs and outputs. - In our case, it would look like this for the input declaration: - - .. code:: - - { - "name": "Sellar1_input", - "required": ["x_local","x_shared","y_1","y_2"], - "properties": { - "x_local": { - "items": { - "type": "number", - "id": "0" - }, - "type": "array", - "id": "x_local" - }, - "x_shared": { - "items": { - "type": "number", - "id": "0" - }, - "type": "array", - "id": "x_shared" - }, - "y_1": { - "items": { - "type": "number", - "id": "0" - }, - "type": "array", - "id": "y_1" - }, - "y_2": { - "items": { - "type": "number", - "id": "0" - }, - "type": "array", - "id": "y_2" - } - }, - "$schema": "http://json-schema.org/draft-04/schema", - "type": "object", - "id": "#Sellar1_input" - } - - -1.2. Define the execution of the discipline -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once the inputs and outputs have been declared in the constructor of the discipline, -the abstract :meth:`!Discipline._run` method of :class:`.Discipline` -shall be overloaded by the discipline to define how outputs are computed from inputs. - -.. seealso:: - - The method is protected (starts with "_") - because it shall not be called from outside the discipline. - External calls that trigger the discipline execution - use the :meth:`.Discipline.execute` public method from the base class, - which provides additional services before and after calling :meth:`!Discipline._run`. - These services, - such as data checks by the grammars, - are provided by |g| - and the integrator of the discipline does not need to implement them. - -First, -the data values shall be retrieved. For each input declared in the input grammar, -|g| will pass the values as arrays to the :class:`.Discipline` -during the execution of the process. -Within the :meth:`!Discipline._run` method of the discipline, -the input data can be retrieved using the :meth:`.Discipline.get_input_data` method -which returns a dictionary. - -.. tip:: - - The list of all inputs names can also be retrieved - using the method :attr:`.Discipline.input_grammar.names`: - - .. code:: - - sellar1 = Sellar1() - print(sellar1.input_grammar.names) - # ['x_shared', 'y_2', 'x_local'] - -Then, the computed outputs shall be stored in the :attr:`!Discipline.local_data`: - -.. code:: - - def _run(self, input_data): - x_local = input_data["x_local"] - x_shared = input_data["x_shared"] - y_2 = input_data["y_2"] - y_1 = array([(x_shared[0] ** 2 + x_shared[1] + x_local[0] - 0.2 * y_2[0])**0.5]) - return {"y_1": y_1} - -The other Sellar :class:`.Discipline` are created in a similar way. - - -1.3. How to define derivatives (optional) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The :class:`.Discipline` may also provide the derivatives of their outputs -with respect to their inputs, i.e. their Jacobians. -This is useful for :term:`gradient-based optimization` -or :ref:`mda` based on the :term:`Newton method`. -For a vector of inputs :math:`x` and a vector of outputs :math:`y`, -the Jacobian of the discipline is :math:`\frac{\partial y}{\partial x}`. - -The discipline shall provide a method to compute the Jacobian for a given set of inputs. -This is made by overloading the abstract :meth:`!Discipline._compute_jacobian` method -of :class:`.Discipline`. -The discipline may have multiple inputs and multiple outputs. -To store the multiple Jacobian matrices associated to all the inputs and outputs, -|g| uses a dictionary of dictionaries structure. -This data structure is sparse and makes easy the access and the iteration -over the elements of the Jacobian. - -Here is an example of a jacobian definition for the Sellar1 discipline. -The method :meth:`!Discipline._init_jacobian` fills the dict of dict structure -with dense null matrices of the right sizes. -Note that all Jacobians must be 2D matrices, -which avoids ambiguity. - -.. code:: - - from numpy import atleast_2d - - def _compute_jacobian(self, input_names=(), output_names=()): - """ - Computes the jacobian - - Args: - inputs: The linearization should be performed with respect - to inputs list. If None, linearization should - be performed wrt all inputs (Default value = None) - outputs: The linearization should be performed on outputs list. - If None, linearization should be performed - on all outputs (Default value = None) - """ - # Initialize all matrices to zeros - self._init_jacobian(fill_missing_keys=True) - x_local = self.local_data['x_local'] - x_shared = self.local_data['x_shared'] - y_2 = self.local_data['y_2'] - - inv_denom = 1. / (self.compute_y_1(x_local, x_shared, y_2)) - self.jac['y_1'] = {} - self.jac['y_1']['x_local'] = atleast_2d(array([0.5 * inv_denom])) - self.jac['y_1']['x_shared'] = atleast_2d(array( - [x_shared[0] * inv_denom, 0.5 * inv_denom])) - self.jac['y_1']['y_2'] = atleast_2d(array([-0.1 * inv_denom])) - -Synthetic Python code -~~~~~~~~~~~~~~~~~~~~~ - -In summary, -here is the Python code for the three disciplines of the :ref:`Sellar `. - -.. code:: - - from math import exp, sqrt - from gemseo import Discipline - - class Sellar1(Discipline): - - def __init__(self): - super().__init__() - self.input_grammar.update_from_names(['x_local', 'x_shared', 'y_2']) - self.output_grammar.update_from_names(['y_1']) - - def _run(self, input_data): - x_local = input_data["x_local"] - x_shared = input_data["x_shared"] - y_2 = input_data["y_2"] - return {'y_1': array([compute_y_1(x_shared, x_local, y_2)])} - - def compute_y_1(x_shared, x_local, y_2): - return sqrt(x_shared[0] ** 2 + x_shared[1] + x_local[0] - 0.2 * y_2[0]) - - def _compute_jacobian(self, input_names=(), output_names=()): - x_local = self.local_data['x_local'] - x_shared = self.local_data['x_shared'] - y_2 = self.local_data['y_2'] - self._init_jacobian(input_names, output_names, fill_missing_keys=True) - inv_denom = 1. / (self.compute_y_1(x_local, x_shared, y_2)) - self.jac['y_1'] = {} - self.jac['y_1']['x_local'] = atleast_2d(array([0.5 * inv_denom])) - self.jac['y_1']['x_shared'] = atleast_2d(array( - [x_shared[0] * inv_denom, 0.5 * inv_denom])) - self.jac['y_1']['y_2'] = atleast_2d(array([-0.1 * inv_denom])) - - class Sellar2(Discipline): - - def __init__(self): - super().__init__() - self.input_grammar.update_from_names(['x_shared', 'y_1']) - self.output_grammar.update_from_names(['y_2']) - - def _run(self, input_data): - x_shared = input_data["x_shared"] - y_1 = input_data["y_1"] - return {'y_2': array([abs(y_1) + x_shared[0] + x_shared[1]])} - - def _compute_jacobian(self, input_names=(), output_names=()): - self._init_jacobian(input_names, output_names, fill_missing_keys=True) - y_1 = self.local_data['y_1'] - self.jac['y_2'] = {} - self.jac['y_2']['x_local'] = zeros((1, 1)) - self.jac['y_2']['x_shared'] = ones((1, 2)) - if y_1[0] < 0.: - self.jac['y_1']['y_1'] = -ones((1, 1)) - elif y_1[0] == 0.: - self.jac['y_2']['y_1'] = zeros((1, 1)) - else: - self.jac['y_2']['y_1'] = ones((1, 1)) - - class SellarSystem(Discipline): - - def __init__(self): - super().__init__() - self.input_grammar.update_from_names(['x_local', 'x_shared', 'y_1', 'y_2']) - self.output_grammar.update_from_names(['obj', 'c_1', 'c_2']) - - def _run(self, input_data): - x_local = input_data["x_local"] - x_shared = input_data["x_shared"] - y_1 = input_data["y_1"] - y_2 = input_data["y_2"] - return { - 'obj': array([x_local[0] ** 2 + x_shared[1] + y_1[0] ** 2 + exp(-y_2[0])]), - 'c_1': array([3.16 - y_1[0]**2]), - 'c_2': array([y_2[0] - 24.]), - } - - def _compute_jacobian(self, input_names=(), output_names=()): - self._init_jacobian(input_names, output_names, fill_missing_keys=True) - x_local = self.local_data['x_local'] - y_1 = self.local_data['y_1'] - y_2 = self.local_data['y_2'] - self.jac['c_1']['y_1'] = atleast_2d(array([-2. * y_1])) - self.jac['c_2']['y_2'] = ones((1, 1)) - self.jac['obj']['x_local'] = atleast_2d(array([2. * x_local[0]])) - self.jac['obj']['x_shared'] = atleast_2d(array([0., 1.])) - self.jac['obj']['y_1'] = atleast_2d(array([2. * y_1[0]])) - self.jac['obj']['y_2'] = atleast_2d(array([-exp(-y_2[0])])) - -Shortcut -~~~~~~~~ - -The classes :class:`.Sellar1`, :class:`.Sellar2` and :class:`.SellarSystem` are available -in the directory **gemseo/problems/sellar**. -Consequently, you just need to import them and use it! - -.. code:: - - from gemseo.problems.mdo.sellar.sellar_1 import Sellar1 - from gemseo.problems.mdo.sellar.sellar_2 import Sellar2 - from gemseo.problems.mdo.sellar.sellar_system import SellarSystem - - disciplines = [Sellar1(), Sellar2(), SellarSystem()] - -A more simple alternative consists in -using the :func:`.create_discipline` API function: - -.. code:: - - from gemseo import create_discipline - - disciplines = create_discipline(['Sellar1', 'Sellar2', 'SellarSystem']) - -Going further -~~~~~~~~~~~~~ - -For more information about the connection of software with |g|, -in particular the concepts and what goes on under the hood, -please see :ref:`software_connection`. - - -Step 2: Creation and execution of the MDO scenario --------------------------------------------------- - -From the :class:`.Discipline`, we build the :term:`scenario`. -The scenario is responsible for the creation and execution of the whole :term:`process`. -It will: - -1. build an :term:`optimization problem` using a :term:`MDO formulation`, -2. connect it to a selected :term:`optimization algorithm`, -3. solve the optimization problems -4. post-process the results. - -For that, -we use the class :class:`.MDOScenario` -which is defined by different :class:`.Discipline` and a common :class:`.DesignSpace`. - -2.1. Create the :class:`.Discipline` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To instantiate the :class:`.MDOScenario`, -we need first the :class:`.Discipline` instances. - -.. code:: - - from gemseo import create_discipline - - disciplines = create_discipline(['Sellar1', 'Sellar2', 'SellarSystem']) - -.. _sellar_mdo_design_space: - -2.2. Create the :class:`.DesignSpace` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Then, by means of the API function :meth:`gemseo.create_design_space`, -we build the :class:`.DesignSpace`, -which defines the design variables, -with their bounds and values: - -.. code:: - - from numpy import ones, array - from gemseo import create_design_space - - design_space = create_design_space() - design_space.add_variable('x_local', 1, lower_bound=0., upper_bound=10., value=ones(1)) - design_space.add_variable('x_shared', 2, lower_bound=(-10, 0.), upper_bound=(10., 10.), value=array([4., 3.])) - design_space.add_variable('y_1', 1, lower_bound=-100., upper_bound=100., value=ones(1)) - design_space.add_variable('y_2', 1, lower_bound=-100., upper_bound=100., value=ones(1)) - - -.. warning:: - - Here, we also add the coupling variables in the :class:`.DesignSpace`, - even if we are going to use a :ref:`MDF formulation `, - which computes the coupling using an :ref:`mda`: - - - The formulation will by itself remove the coupling variables - from the optimization unknowns, - but will use the values as default values - for the inputs of the :class:`.Discipline`. - - This will also be convenient - when we will switch to the :ref:`IDF `, - which uses the coupling variables as optimization unknowns. - - Alternatively, one can perform :ref:`MDF ` - without coupling variables in the :class:`.DesignSpace`, - but set the default values of the inputs - using the :attr:`.Discipline.default_input_data` attribute to the three disciplines: - - .. code:: - - discipline[0].default_input_data = {'y_2': ones(1)} - discipline[1].default_input_data = {'y_1': ones(1)} - discipline[2].default_input_data = {'y_1': ones(1), 'y_2': ones(1)} - -.. _sellar_mdo_create_scenario: - -2.3. Create the :class:`.MDOScenario` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Then, by means of the API function :meth:`gemseo.create_scenario`, -we create the process which is an :class:`.MDOScenario`. -The scenario delegates the creation of an :class:`.OptimizationProblem` -to the :class:`.BaseMDOFormulation`. -We choose the :term:`MDF` formulation, -which solves a coupling problem (:ref:`mda`) -at each iteration to compute the coupling variables, -here the :math:`y_1` and :math:`y_2` variables, -from both :math:`x_{local}` and :math:`x_{shared}` variables. -To be executable, -the scenario needs at least an objective function. -The constraints being optional. -The name of the objective function shall be one of the outputs of the disciplines. -Here, -the SellarSystem discipline outputs "obj", "c_1", and "c_2", -which are declared as, respectively, the objective function and inequality constraints. - -.. code:: - - from gemseo import create_scenario - - scenario = create_scenario(disciplines, 'MDF', 'obj', design_space) - -Users may add constraints to the :term:`optimization problem`. - -.. code:: - - scenario.add_constraint('c_1', 'ineq') - scenario.add_constraint('c_2', 'ineq') - -The execution of the process is triggered -through the resolution of the optimization problem by an optimizer. -The name of the optimizer and its options are given to the scenario -as input data in a Python dictionary. -Here the :term:`SLSQP` algorithm is a :term:`gradient-based optimization` algorithm. -The disciplines that we integrated provide no analytical derivatives, -so we need first to tell the scenario to use finite differences -to compute the derivatives using :meth:`.BaseScenario.set_differentiation_method`. - -.. code:: - - scenario.set_differentiation_method('finite_differences', 1e-6) - -.. _sellar_mdo_execute_scenario: - -2.4. Solve the :class:`.OptimizationProblem` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Then, we can run the scenario by calling the :meth:`.Discipline.execute` method of the scenario. - -.. code:: - - scenario.execute(algo_name=SLSQP, max_iter=10) - - -The logging message provides substantial information about the process setup, execution and results. - -.. code:: - - INFO - 17:36:02: *** Start MDO Scenario execution *** - INFO - 17:36:02: MDOScenario - INFO - 17:36:02: Disciplines: Sellar1 Sellar2 SellarSystem - INFO - 17:36:02: MDOFormulation: MDF - INFO - 17:36:02: Algorithm: SLSQP - INFO - 17:36:02: Optimization problem: - INFO - 17:36:02: Minimize: obj(x, z) - INFO - 17:36:02: With respect to: x, z - INFO - 17:36:02: Subject to constraints: - INFO - 17:36:02: c_1(x, z) <= 0.0 - INFO - 17:36:02: c_2(x, z) <= 0.0 - INFO - 17:36:02: Design Space: - INFO - 17:36:02: +------+-------------+-------+-------------+-------+ - INFO - 17:36:02: | name | lower_bound | value | upper_bound | type | - INFO - 17:36:02: +------+-------------+-------+-------------+-------+ - INFO - 17:36:02: | x | 0 | 1 | 10 | float | - INFO - 17:36:02: | z | -10 | 4 | 10 | float | - INFO - 17:36:02: | z | 0 | 3 | 10 | float | - INFO - 17:36:02: +------+-------------+-------+-------------+-------+ - INFO - 17:36:02: Optimization: 0%| | 0/15 [00:00` very easily. -Basically you just need to change the name of the formulation in the script. - -.. tip:: - - Available formulations can be obtained through the API function - :meth:`gemseo.get_available_formulations()`. The following Python lines - - .. code:: - - from gemseo import get_available_formulations - - print(get_available_formulations()) - - give: - - .. code:: - - ['IDF', 'BiLevel', 'MDF', 'DisciplinaryOpt'] - -Here, we are going to try the :ref:`IDF formulation `, -which is another classical :ref:`MDO formulation ` -along with :term:`MDF`: - -.. code:: - - scenario = MDOScenario(disciplines, 'IDF', objective_name='obj', design_space=design_space) - -In IDF, -all disciplines are executed independently, -and the coupling variables are unknown from the optimizer. -In fact, -the optimizer will solve the coupling problem -simultaneously with the optimization problem -by adding so-called consistency constraints (see :ref:`MDO_formulations`). -The :class:`.IDF` class will create the consistency equality constraints for you. - -The logging message shows that the generated optimization problem is different, -while the disciplines remain the same. -One can note the consistency equality constraints, -used to solve the coupling problem. -The design space now contains the coupling variables. - -.. code:: - - *** Start MDO Scenario execution *** - MDOScenario: - Disciplines: Sellar1 Sellar2 SellarSystem - MDOFormulation: IDF - Algorithm: SLSQP - - Optimization problem: - Minimize: obj(x_loca, x_shared, y_1, y_2) - With respect to: - x_local, x_shared, y_1, y_2 - Subject to constraints: - y_1(x_local, x_shared, y_2) = y_1(x_local, x_shared, y_2) - y_1 = 0 - y_2(x_shared, y_1) = y_2(x_shared, y_1) - y_2 = 0 - c_1(x_local, x_shared, y_1, y_2) <= 0 - c_2(x_local, x_shared, y_1, y_2) <= 0 - Design Space: - +-------------+-------------+-------+-------------+-------+ - | name | lower_bound | value | upper_bound | type | - +-------------+-------------+-------+-------------+-------+ - | x_local | 0 | 1 | 10 | float | - | x_shared | -10 | 4 | 10 | float | - | x_shared | 0 | 3 | 10 | float | - | y_1 | -100 | 1 | 100 | float | - | y_2 | -100 | 1 | 100 | float | - +-------------+-------------+-------+-------------+-------+ - -The results are similar, -and the execution duration is 4 times shorter than in the previous case. -Indeed, -the :ref:`IDF formulation ` does not need -to solve an :ref:`mda` at each step, -and is often more efficient in low dimension. - -.. code:: - - Optimization: 0%| | 0/15 [00:00 None: - super().__init__() - # Initialize the grammars to define inputs and outputs - self.input_grammar.update_from_names(["x", "z", "y_0", "y_1"]) - self.output_grammar.update_from_names(["obj", "c_1", "c_2"]) - # Default inputs define what data to use when the inputs are not - # provided to the execute method - - # self.default_input_data = {"x": ones(1), "z": array([4., 3.]), - # "y_0": ones(1), "y_1": ones(1)} - - def _run(self, input_data: StrKeyMapping) -> StrKeyMapping | None: - # The run method defines what happens at execution - # ie how outputs are computed from inputs - x = input_data["x"] - z = input_data["z"] - y_0 = input_data["y_0"] - y_1 = input_data["y_1"] - return { - "obj": array([x[0] ** 2 + z[1] + y_0[0] ** 2 + exp(-y_1[0])]), - "c_1": array([3.16 - y_0[0] ** 2]), - "c_2": array([y_1[0] - 24.0]), - } - - -class Sellar1(Discipline): - def __init__(self, residual_form=False) -> None: - super().__init__() - self.input_grammar.update_from_names(["x", "z", "y_1"]) - self.output_grammar.update_from_names(["y_0"]) - - # self.default_input_data = {"x": ones(1), "z": array([4., 3.]), - # "y_0": ones(1), "y_1": ones(1)} - - def _run(self, input_data: StrKeyMapping) -> StrKeyMapping | None: - x = input_data["x"] - z = input_data["z"] - y_1 = input_data["y_1"] - return {"y_0": array([(z[0] ** 2 + z[1] + x[0] - 0.2 * y_1[0]) ** 0.5])} - - -class Sellar2(Discipline): - def __init__(self, residual_form=False) -> None: - super().__init__() - self.input_grammar.update_from_names_from_names(["z", "y_0"]) - self.output_grammar.update_from_names_from_names(["y_1"]) - - # self.default_input_data = {"x": ones(1), "z": array([4., 3.]), - # "y_0": ones(1), "y_1": ones(1)} - - def _run(self, input_data: StrKeyMapping) -> StrKeyMapping | None: - z = input_data["z"] - y_0 = input_data["y_0"] - return {"y_1": array([abs(y_0[0]) + z[0] + z[1]])} - - -def run_process() -> None: - # Instantiate disciplines - disciplines = [Sellar1(), Sellar2(), SellarSystem()] - - # Creates the design space - design_space = DesignSpace() - design_space.add_variable("x", lower_bound=0.0, upper_bound=10.0, value=ones(1)) - design_space.add_variable( - "z", - 2, - lower_bound=(-10, 0.0), - upper_bound=(10.0, 10.0), - value=array([4.0, 3.0]), - ) - design_space.add_variable( - "y_0", lower_bound=-100.0, upper_bound=100.0, value=ones(1) - ) - design_space.add_variable( - "y_1", lower_bound=-100.0, upper_bound=100.0, value=ones(1) - ) - - # Build scenario which links the disciplines with the formulation and - # The optimization algorithm - scenario = MDOScenario( - disciplines, - "obj", - design_space, - formulation_name="MDF", - ) - - # Set the design constraints - scenario.add_constraint("c_1", constraint_type="ineq") - scenario.add_constraint("c_2", constraint_type="ineq") - - # USe finite differences since the disciplines do not provide derivatives - scenario.set_differentiation_method("finite_differences") - - # Execute scenario with the inputs of the MDO scenario as a dict - scenario.execute(algo_name="SLSQP", max_iter=15) - - # Generate a plot of the history in a file - scenario.post_process(post_name="OptHistoryView", save=True, show=True) - - scenario.save_optimization_history(file_path="sellar_history.h5") - - -if __name__ == "__main__": - run_process() diff --git a/doc_src/tutorials/sellar/sellar_obj.png b/doc_src/tutorials/sellar/sellar_obj.png deleted file mode 100644 index 98b820b79c552e8da81c0289acb9d92fd8b6ed59..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/sellar/sellar_obj.png and /dev/null differ diff --git a/doc_src/tutorials/sellar/sellar_x.png b/doc_src/tutorials/sellar/sellar_x.png deleted file mode 100644 index e6c74c9d67a0162c11782099055101c115bb4fa0..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/sellar/sellar_x.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/doe_scenarios_construction.rst b/doc_src/tutorials/ssbj/doe_scenarios_construction.rst deleted file mode 100644 index a999406ff6d94dd002ade16c2fc1c101e9405c71..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/ssbj/doe_scenarios_construction.rst +++ /dev/null @@ -1,406 +0,0 @@ -.. - Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com - - This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 - International License. To view a copy of this license, visit - http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative - Commons, PO Box 1866, Mountain View, CA 94042, USA. - -.. - Contributors: - :author: Matthias De Lozzo - -.. _sobieski_doe: - -Tutorial: How to carry out a trade-off study -============================================ - -This tutorial describes how to carry out a trade-off study by means of |g|. For that, we consider the :ref:`Sobieski problem `. - -Trade-off studies are implemented in the class :class:`~gemseo.scenarios.doe_scenario.DOEScenario`. - -All the post-processing tools presented in :ref:`post_processing` for :class:`~gemseo.scenarios.mdo_scenario.MDOScenario` -remain valid for trade-off studies, as well as the additional tools presented below. - -Similarities between trade-off studies and optimization problems ----------------------------------------------------------------- - -Trade-off studies are supported by capabilities of :term:`Design Of Experiments `. But, -when comparing an optimization scenario and a trade-off scenario, similarities appear: - -+------------------------------------+-----------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------+ -| Feature | MDO Scenario (implemented in :class:`~gemseo.scenarios.mdo_scenario.MDOScenario`) | Trade-off study (implemented in :class:`~gemseo.scenarios.doe_scenario.DOEScenario`) | -+====================================+===================================================================================+===========================================================================================+ -| Sample evaluation | The sample :math:`i+1` requires the evaluation of the sample :math:`i`. | The sequence is defined *a priori* by a :term:`DOE`; an iteration corresponds to a sample | -+------------------------------------+-----------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------+ -| Constraint and objective functions | They guide the convergence of an optimization problem. | They are only monitored evaluated outputs. | -+------------------------------------+-----------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------+ -| Constraint and objective functions | They are not directly outputs of a :term:`discipline`. | They are not directly outputs of a :term:`discipline`. | -+------------------------------------+-----------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------+ -| Constraint and objective functions | They can be computed by an :ref:`mda` for instance (e.g. MDF) | They can be computed by an :ref:`mda` for instance. | -+------------------------------------+-----------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------+ -| Constraint and objective functions | Target values can be used for the :term:`coupling variables` (e.g. IDF). | Target values can be used for the :term:`coupling variables`. | -+------------------------------------+-----------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------+ - -That is why in |g|, - -- the :term:`DOE` sample evaluations are performed on the objective and constraint functions generated by an :term:`MDO formulation`, - -exactly as - -- the :term:`optimization algorithm` evaluates the objective and constraint functions to solve the :term:`optimization problem`. - -A key advantage of this approach is that the :term:`DOE` is based on a formalized MDO problem. - -Besides, from the implementation point of view, **all existing methods developed for optimization can be used for trade-off without any change**. - -Finally, this smoothes the transition between a :term:`DOE` study and an MDO study, and makes the :term:`DOE` -an ideal preparatory step for MDO. - -Trade-offs based on a :ref:`MDF formulation ` ---------------------------------------------------------------- - -As mentioned previously, a trade-off script and an optimization script are very similar. -For example, a :term:`MDF` trade-off study includes an :ref:`mda` sampling with respect to the :term:`design variables` -provided by the :term:`DOE algorithm`. - -1. Define the :class:`.Discipline` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We first instantiate the :class:`~gemseo.core.discipline.Discipline`: - -.. code:: - - from gemseo import create_discipline - - disciplines = create_discipline(["SobieskiPropulsion", "SobieskiAerodynamics", - "SobieskiMission", "SobieskiStructure"]) - -2. Define the :class:`.DesignSpace` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Then, by means of the API function :func:`.read_design_space`, -we load the :class:`~gemseo.algos.design_space.DesignSpace`, like for :class:`~gemseo.scenarios.mdo_scenario.MDOScenario`. - -.. code:: - - from gemseo import read_design_space - - input_file = join(dirname(__file__), "sobieski_design_space.csv") - design_space = read_design_space(input_file) - -3. Define the trade-off study -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Initialization -^^^^^^^^^^^^^^ - -The :ref:`MDF formulation ` is selected to build the :class:`~gemseo.scenarios.doe_scenario.DOEScenario`, like for :class:`~gemseo.scenarios.mdo_scenario.MDOScenario`. - -.. code:: - - from gemseo import create_scenario - - scenario = create_scenario(disciplines, - formulation_name="MDF", - objective_name="y_4", - design_space=design_space, - scenario_type="DOE", - maximize_objective=True) - -Constraint monitoring -^^^^^^^^^^^^^^^^^^^^^ - -We choose here to monitor the constraints, similarly to the MDO study: - -.. code:: - - for constraint in ["g_1", "g_2", "g_3"]: - scenario.add_constraint(constraint, 'ineq') - -This is optional since the driver is not able to ensure these constraints, but it is -the only way to observe an output which is not an objective, in order to -benefit from the post processing plots associated to these constraints. -Besides, this does not increase the cost of the scenario execution, -since the constraints are computed by the :ref:`Sobieski ` disciplines in all -cases, and a buffer system in avoids to call twice a discipline in a row -with identical inputs, and directly returns the buffered outputs. - -Optimization options -^^^^^^^^^^^^^^^^^^^^ - -The DOE algorithm options are passed as inputs of the :class:`~gemseo.scenarios.mdo_scenario.MDOScenario`. -The number of samples is specified, as well as the "criterion" option which is the center option of pyDOE centering the points within the sampling intervals. -The sensitivity of the outputs with respect to the design variables may be computed, -thanks to the coupled derivatives capabilities, to this aim the 'eval\_jac' setting parameter is set to True. - -.. seealso:: - - In this tutorial, the design is based on :term:`LHS` from - `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 DOE algorithms in the current |g| configuration, use - :meth:`gemseo.get_available_doe_algorithms`: - - .. code:: - - from gemseo import get_available_doe_algorithms - - get_available_doe_algorithms() - - which gives: - - .. code:: - - ['PYDOE_FF2N', 'OT_FACTORIAL', 'OT_FAURE', 'OT_HASELGROVE', 'OT_REVERSE_HALTON', 'OT_HALTON', 'PYDOE_CCDESIGN', 'OT_SOBOL', 'PYDOE_FULLFACT', 'OT_FULLFACT', 'OT_AXIAL', 'lhs', 'OT_LHSC', 'OT_MONTE_CARLO', 'OT_RANDOM', 'OT_COMPOSITE', 'CustomDOE', 'PYDOE_PBDESIGN', 'OT_LHS', 'PYDOE_BBDESIGN'] - - -4. Execute the trade-off study -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The scenario outputs is executed: - -.. code:: - - scenario.execute(algo_name='lhs', n_samples=30, eval_jac=True, criterion='center') - -5. Visualize the results -~~~~~~~~~~~~~~~~~~~~~~~~ - -The scenario outputs can be saved to disk as : - -.. code:: - - scenario.save_optimization_history(“DOE_MDF.h5”, file_format=“hdf5”) - scenario.save_optimization_history(“DOE_MDF.xml”,file_format=“ggobi”) - - -All the :ref:`post-processing ` tools are available for :term:`DOE`, e.g. - -.. code:: - - scenario.post_process("OptHistoryView", save=True) - - -Trade-offs based on a :ref:`bi-level formulation ` ------------------------------------------------------------------------ - -The construction of MDO scenarios or trade-off studies based on a :ref:`bi-level formulation ` is available. - -Presentation of the bi-level trade-off -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The :term:`bi-level` process, shown in the next figure, is described as follows: - -#. build a :term:`DOE` with respect to the :term:`shared design variables`, with :term:`local design variables` fixed at their default values, - -#. for each sample of the :term:`DOE`, - - #. perform an :ref:`mda`, - #. for each sub-discipline, perform a disciplinary optimization with respect to its :term:`local design variables`, - #. perform an :ref:`mda` with optimal :term:`local design variables` to ensure equilibrium. - -The :ref:`MDO formulation ` (:class:`~gemseo.formulations.bilevel.BiLevel` object) takes care of creating the :ref:`mda`, and -building this chain of executions. - -.. figure:: figs/BLISS_flowchart_V0_platform.png - :scale: 15% - - Description of the bilevel formulation process for trade-off - -For :ref:`Sobieski's use case `, the objective function is the range from the -`Breguet-Leduc equation `_: - -.. math:: - - Range = V. - \underbrace{\left(\frac{L}{D}\right)}_{aerodynamics}.\underbrace{\frac - {1}{SFC}}_{propulsion} - \underbrace{\ln\left(\frac{W_T}{W_T-W_F}\right)}_{structure} - \label{eqn:sobieski_range} - -In this equation, each term is related to one of the three disciplines: aerodynamics, structure and propulsion. Therefore, in order to -maximize the range, the disciplines should: - -- maximize :math:`(L/D)` with respect to aerodynamics variables - :math:`x_2`, - -- minimize the Specific Fuel Consumption :math:`SFC` with respect to - propulsion variables :math:`x_3`, - -- maximize :math:`\frac{W_T}{W_T-W_F}` with respect to structure - variables :math:`x_1`. - -1. Define the disciplines -~~~~~~~~~~~~~~~~~~~~~~~~~ - -We first instantiate the :class:`~gemseo.core.discipline.Discipline`: - -.. code:: - - from gemseo import create_discipline - - prop, aero, mission, struct = create_discipline(["SobieskiPropulsion", "SobieskiAerodynamics", - "SobieskiMission", "SobieskiStructure"]) - -2. Define the disciplinary design spaces -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Then, for each disciplinary scenario, we - -#. load the design space (function :func:`.read_design_space` -#. keep only the design variables that are of interest for the scenario (function :meth:`~gemseo.algos.design_space.DesignSpace.filter`): - -.. code:: - - from copy import deepcopy - from gemseo import read_design_space - - input_file = join(dirname(__file__), "sobieski_design_space.csv") - design_space = read_design_space(input_file) - design_space_prop = deepcopy(design_space).filter("x_3") - design_space_aero = deepcopy(design_space).filter("x_2") - design_space_struct = deepcopy(design_space).filter("x_1") - design_space_mission = deepcopy(design_space).filter("x_shared") - -3'. Define the disciplinary scenarios -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The propulsion scenario minimizes the fuel specific consumption: - -.. code:: - - sc_prop = create_scenario(prop, - formulation_name="DisciplinaryOpt", - objective_name="y_34", - design_space=design_space_prop, - name="PropulsionScenario") - -The aerodynamic scenario maximizes lift over drag: - -.. code:: - - sc_aero = create_scenario(aero, - formulation_name="DisciplinaryOpt", - objective_name="y_24", - design_space=design_space_aero, - name="AerodynamicsScenario", - maximize_objective=True) - -The structure scenario maximizes :math:`log \frac{aircraft total weight}{aircraft total weight - fuel weight}`: - -.. code:: - - sc_struct = create_scenario(struct, - formulation_name="DisciplinaryOpt", - objective_name="y_11", - design_space=design_space_struct, - name="StructureScenario", - maximize_objective=True) - -The range computation is added as a fourth discipline of the system scenario, which maximizes it: - -.. code:: - - sub_disciplines = [sc_prop, sc_aero, sc_struct] - sub_disciplines.append(mission) - - for sub_sc in sub_disciplines[0:3]: - sub_sc.set_algorithm("LL-BFGS-B", max_iter=20) - -Please also note that it is compulsory to set the default inputs of the first three disciplines, which are MDO scenarios. Thus, we have to set the optimization algorithm and the maximum number of iterations for each of them. - -3''. Define the main scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In a bi-level formulation, disciplinary optimizations are driven by the -main (system-level) scenario which is a :term:`DOE` (trade-off study), or an optimization -process with respect to the :term:`system design variables` (optimization problem). - -.. code:: - - system_scenario = create_scenario(sub_disciplines, - formulation_name="BiLevel", - objective_name="y_4", - parallel_scenarios=False, - # This is mandatory when doing - # a DOE in parallel if we want - # reproducible - # results, dont reuse previous xopt - reset_x0_before_opt=True, - design_space=deepcopy( - design_space).filter("x_shared"), - maximize_objective=True, - scenario_type="DOE") - # This is mandatory when doing - # a DOE in parallel if we want always exactly the same - # results, dont warm start mda1 to have exactly the same - # process whatever the execution order and process dispatch - system_scenario.formulation.mda1.warm_start = False - system_scenario.formulation.mda2.warm_start = False - - -4. Execute the trade-off study -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Similarly to the disciplinary optimization scenarios, we create a -dictionary of options (including all :term:`DOE` settings) for the main scenario execution. - -.. code:: - - system_scenario.execute(algo_name="PYDOE_LHS", n_samples=30) - - -Comparison of trade-off results: :ref:`bi-level ` versus :ref:`MDF ` formulations ------------------------------------------------------------------------------------------------------------------------ - -The aim of this section is to show the difference between :term:`MDF` and bi-level -trade-off studies presented in the previous section. - -For MDF, the DOE requires -a design space reduced to the sole :term:`system design variables`, while the bi-level scenario involves disciplinary sub-optimization -on the :term:`local design variables`. - -Some figures -~~~~~~~~~~~~ - -As shown in the next figures, the bi-level scenario execution allows to reach a higher range than the MDF based scenario. -This result highlights the interest of optimizing with respect to the :term:`local design variables` when updating the :term:`system design variables`. - - -.. figure:: figs/History_DOE_bilevel_shared.png - :scale: 12% - - Bilevel DOE history - -.. figure:: figs/History_DOE_MDF_shared.png - :scale: 12% - - MDF DOE history - - -.. figure:: figs/scatter_plot_compare_mdf_bilevel_zoom.png - :scale: 17% - - Comparison of and bi-level trade-off for a DOE of 30 samples - -Remarks on the performance -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One can note that with a of 30 samples, the best range found (about -1200 :math:`nm`) is nowhere near the optimum found by the optimization -process (a range of 3963 :math:`nm` in less than 10 iterations). -The last figure illustrates a trade-off study with 10,000 samples. Again, the best -sample found (around 2600 :math:`nm`) without any constraint -consideration, is far from the optimal value. This example suggests that -the sub-optimality trap is much more likely to happen with a trade-off -study than with an optimization process. - - -.. figure:: figs/History_DOE_10000_obj.png - - Objective function history for a DOE of 10,000 samples with MDF - formulation diff --git a/doc_src/tutorials/ssbj/figs/BLISS_flowchart_V0_platform.png b/doc_src/tutorials/ssbj/figs/BLISS_flowchart_V0_platform.png deleted file mode 100644 index 0165b328898fa81eb6dfab8f4c00a60283c61b2f..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/BLISS_flowchart_V0_platform.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/Hessian_quadapprox_idf.png b/doc_src/tutorials/ssbj/figs/Hessian_quadapprox_idf.png deleted file mode 100644 index b842a504c54ad4c700ed121d652684cba5b17e33..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/Hessian_quadapprox_idf.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/History_DOE_10000_obj.png b/doc_src/tutorials/ssbj/figs/History_DOE_10000_obj.png deleted file mode 100644 index 7113b0217782a138be2a1e99b67cabc59de27203..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/History_DOE_10000_obj.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/History_DOE_MDF_shared.png b/doc_src/tutorials/ssbj/figs/History_DOE_MDF_shared.png deleted file mode 100644 index 0283c9bf87826858aa958d83bd7ff861cd067966..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/History_DOE_MDF_shared.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/History_DOE_bilevel_shared.png b/doc_src/tutorials/ssbj/figs/History_DOE_bilevel_shared.png deleted file mode 100644 index 8e3bdbd32dba648740bb571263f99ea04a5740f1..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/History_DOE_bilevel_shared.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/History_IDF_objective.png b/doc_src/tutorials/ssbj/figs/History_IDF_objective.png deleted file mode 100644 index f210db91507152750808e87ff13ebe1dc4661874..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/History_IDF_objective.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/MDOScenario_SOM_v100.png b/doc_src/tutorials/ssbj/figs/MDOScenario_SOM_v100.png deleted file mode 100644 index 65b03aeef685a1e76f886cba2919c8ca82896d7a..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/MDOScenario_SOM_v100.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/Scatter_DOE_MDF_shared.png b/doc_src/tutorials/ssbj/figs/Scatter_DOE_MDF_shared.png deleted file mode 100644 index 5bee2fa6b270317ad79e64cdd3e0baf77dc346f2..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/Scatter_DOE_MDF_shared.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/Scatter_DOE_bilevel_shared.png b/doc_src/tutorials/ssbj/figs/Scatter_DOE_bilevel_shared.png deleted file mode 100644 index bcf863146705afcc6912b7c28ac1315a502d8e83..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/Scatter_DOE_bilevel_shared.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/Sobieski_IDF_eq_constraints.png b/doc_src/tutorials/ssbj/figs/Sobieski_IDF_eq_constraints.png deleted file mode 100644 index 0364cc85fb9ca6d926389626f408def68dd90376..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/Sobieski_IDF_eq_constraints.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/Sobieski_IDF_ineq_constraints.png b/doc_src/tutorials/ssbj/figs/Sobieski_IDF_ineq_constraints.png deleted file mode 100644 index 8541f343a4842d97f36f9060c1d16aff53510401..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/Sobieski_IDF_ineq_constraints.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/Sobieski_MDF_constrained_dv_obj.png b/doc_src/tutorials/ssbj/figs/Sobieski_MDF_constrained_dv_obj.png deleted file mode 100644 index 6e20ec531c419d87e62865215947e3b52783b267..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/Sobieski_MDF_constrained_dv_obj.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/Sobieski_MDF_ineq_constraints.png b/doc_src/tutorials/ssbj/figs/Sobieski_MDF_ineq_constraints.png deleted file mode 100644 index 8ad53471b80928dc9a7a81b5bdd9e68779da4f50..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/Sobieski_MDF_ineq_constraints.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/convert_all.sh b/doc_src/tutorials/ssbj/figs/convert_all.sh deleted file mode 100644 index e2beb520d115eda4bb54b5f37e1512ddef01a567..0000000000000000000000000000000000000000 --- a/doc_src/tutorials/ssbj/figs/convert_all.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -find . -type f -name '*.pdf' -print0 | - while IFS= read -r -d '' file - do convert -verbose -density 500 "${file}" "${file%.*}.png" - done diff --git a/doc_src/tutorials/ssbj/figs/mdf_boxplot.png b/doc_src/tutorials/ssbj/figs/mdf_boxplot.png deleted file mode 100644 index a8eeb0d04a1061f8838bc64d8346f216bbd736d9..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/mdf_boxplot.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/mdf_gradient_sensitivity.png b/doc_src/tutorials/ssbj/figs/mdf_gradient_sensitivity.png deleted file mode 100644 index 03cd01a84802d0e34dd0a4cd35cb1e02f1ff3663..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/mdf_gradient_sensitivity.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/mdf_hessian_approx.png b/doc_src/tutorials/ssbj/figs/mdf_hessian_approx.png deleted file mode 100644 index 330f14a7a5300081a09351513423effa9769f15b..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/mdf_hessian_approx.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/mdf_para_coord_des_vars.png b/doc_src/tutorials/ssbj/figs/mdf_para_coord_des_vars.png deleted file mode 100644 index e71a9e39d44f65790728c772a565db30333c6ffc..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/mdf_para_coord_des_vars.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/mdf_para_coord_funcs.png b/doc_src/tutorials/ssbj/figs/mdf_para_coord_funcs.png deleted file mode 100644 index be677e1256a32902db430400550d5c69298b4a5d..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/mdf_para_coord_funcs.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/mdf_parallel_zoom.png b/doc_src/tutorials/ssbj/figs/mdf_parallel_zoom.png deleted file mode 100644 index db3c3060083a3de96c10f8f21e9db6df866413e8..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/mdf_parallel_zoom.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/mdf_quad_approx.png b/doc_src/tutorials/ssbj/figs/mdf_quad_approx.png deleted file mode 100644 index 7a446f9cf06b545ba9e7282509e62fcdb15729b6..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/mdf_quad_approx.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/quadapprox_idf.png b/doc_src/tutorials/ssbj/figs/quadapprox_idf.png deleted file mode 100644 index b7ae69f775a0849f54d0577f778cf7268dfb05e5..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/quadapprox_idf.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/scatter_plot_compare_mdf_bilevel_zoom.png b/doc_src/tutorials/ssbj/figs/scatter_plot_compare_mdf_bilevel_zoom.png deleted file mode 100644 index 8b23e98d454005402e54c8c1e9b83592607563b6..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/scatter_plot_compare_mdf_bilevel_zoom.png and /dev/null differ diff --git a/doc_src/tutorials/ssbj/figs/som_fine.png b/doc_src/tutorials/ssbj/figs/som_fine.png deleted file mode 100644 index b14dc1a772370fd117f0097252e879807dd87073..0000000000000000000000000000000000000000 Binary files a/doc_src/tutorials/ssbj/figs/som_fine.png and /dev/null differ diff --git a/src/gemseo/problems/ode/springs/__init__.py b/src/gemseo/problems/ode/springs/__init__.py index 3294fb625e77b3347c49346f2ba52bef3deb1fd8..64a54f517f70cd8a24f5df5ebc197d7423ba98e0 100644 --- a/src/gemseo/problems/ode/springs/__init__.py +++ b/src/gemseo/problems/ode/springs/__init__.py @@ -15,7 +15,7 @@ r"""A problem illustrating how to couple instances of :class:`.ODEDiscipline`. -Consider a system of :math:`n` point masses with masses :math:`m_1$, :math:`m_2$,... +Consider a system of :math:`n` point masses with masses :math:`m_1`, :math:`m_2`,... :math:`m_n` connected in series by springs. The displacement of the point masses relative to the position at rest are denoted by :math:`x_1`, :math:`x_2`,... :math:`x_n`. Each spring has stiffness :math:`k_1`, :math:`k_2`,... :math:`k_{n+1}`. @@ -28,7 +28,7 @@ The extremities of the first and last spring are fixed. This means that by conve For :math:`n=2`, the system is as follows: -.. asciiart:: +.. code:: | | | k1 ________ k2 ________ k3 |