.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/disciplines/basics/plot_check_jacobian.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_disciplines_basics_plot_check_jacobian.py: Check the Jacobian of a discipline ================================== In this example, the Jacobian of an :class:`.MDODiscipline` is checked by derivative approximation. .. GENERATED FROM PYTHON SOURCE LINES 23-40 .. code-block:: Python from __future__ import annotations from typing import TYPE_CHECKING from numpy import array from numpy import exp from gemseo import configure_logger from gemseo.core.discipline import MDODiscipline if TYPE_CHECKING: from collections.abc import Iterable configure_logger() .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 41-48 First, we create a discipline computing :math:`f(x,y)=e^{-(1-x)^2-(1-y)^2}` and :math:`g(x,y)=x^2+y^2-1` and introduce an error in the implementation of :math:`\frac{\partial f(x,y)}{\partial x}`. .. GENERATED FROM PYTHON SOURCE LINES 48-76 .. code-block:: Python class BuggedDiscipline(MDODiscipline): def __init__(self) -> None: super().__init__() self.input_grammar.update_from_names(["x", "y"]) self.output_grammar.update_from_names(["f", "g"]) self.default_inputs = {"x": array([0.0]), "y": array([0.0])} def _run(self) -> None: x, y = self.get_inputs_by_name(["x", "y"]) self.local_data["f"] = exp(-((1 - x) ** 2) - (1 - y) ** 2) self.local_data["g"] = x**2 + y**2 - 1 def _compute_jacobian( self, inputs: Iterable[str] | None = None, outputs: Iterable[str] | None = None, ) -> None: x, y = self.get_inputs_by_name(["x", "y"]) self._init_jacobian() g_jac = self.jac["g"] g_jac["x"][:] = 2 * x g_jac["y"][:] = 2 * y f_jac = self.jac["f"] aux = 2 * exp(-((1 - x) ** 2) - (1 - y) ** 2) f_jac["x"][:] = aux # this is wrong. f_jac["y"][:] = aux * (1 - y) .. GENERATED FROM PYTHON SOURCE LINES 77-83 We want to check if the implemented Jacobian is correct. For practical applications where Jacobians are needed, this is not a simple task. GEMSEO automates such tests thanks to the :meth:`.MDODiscipline.check_jacobian` method. Finite differences (default) ---------------------------- .. GENERATED FROM PYTHON SOURCE LINES 83-91 .. code-block:: Python discipline = BuggedDiscipline() discipline.check_jacobian( input_data={"x": array([0.0]), "y": array([1.0])}, show=True, plot_result=True, step=1e-1, ) .. rst-class:: sphx-glr-script-out .. code-block:: none ERROR - 13:13:45: BuggedDiscipline Jacobian: dp f/d x is wrong by 1.9226823669921054%. INFO - 13:13:45: Approximate jacobian = INFO - 13:13:45: [[0.76978625]] INFO - 13:13:45: Provided by linearize method = INFO - 13:13:45: [[0.73575888]] INFO - 13:13:45: Difference of jacobians = INFO - 13:13:45: [[0.03402737]] ERROR - 13:13:45: BuggedDiscipline Jacobian: dp f/d y is wrong by 3.5312032605514854%. INFO - 13:13:45: Approximate jacobian = INFO - 13:13:45: [[-0.03660462]] INFO - 13:13:45: Provided by linearize method = INFO - 13:13:45: [[0.]] INFO - 13:13:45: Difference of jacobians = INFO - 13:13:45: [[-0.03660462]] ERROR - 13:13:45: BuggedDiscipline Jacobian: dp g/d x is wrong by 9.090909090909099%. INFO - 13:13:45: Approximate jacobian = INFO - 13:13:45: [[0.1]] INFO - 13:13:45: Provided by linearize method = INFO - 13:13:45: [[0.]] INFO - 13:13:45: Difference of jacobians = INFO - 13:13:45: [[0.1]] ERROR - 13:13:45: BuggedDiscipline Jacobian: dp g/d y is wrong by 3.2258064516129616%. INFO - 13:13:45: Approximate jacobian = INFO - 13:13:45: [[2.1]] INFO - 13:13:45: Provided by linearize method = INFO - 13:13:45: [[2.]] INFO - 13:13:45: Difference of jacobians = INFO - 13:13:45: [[0.1]] INFO - 13:13:45: Linearization of MDODiscipline: BuggedDiscipline is wrong. /home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.3.2/lib/python3.9/site-packages/gemseo/utils/derivatives/derivatives_approx.py:658: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator. axe.set_xticklabels(x_labels, fontsize=14) False .. GENERATED FROM PYTHON SOURCE LINES 92-98 The step here is chosen big enough to underline the truncation error. From this graph, we can see that almost all the provided components of the Jacobians (blue dots) are close but distinct from the approximated by finite differences using a step of 0.1 (red dots). This kind of graph can be used to spot implementation mistakes in fact we can already spot a large mistake in the wrong components. .. GENERATED FROM PYTHON SOURCE LINES 98-144 .. code-block:: Python # The ``derr_approx`` argument can be either ``finite_differences``, ``centered_differences`` or # ``complex_step``. # Centered differences # -------------------- discipline.check_jacobian( input_data={"x": array([0.0]), "y": array([1.0])}, derr_approx=discipline.ApproximationMode.CENTERED_DIFFERENCES, show=True, plot_result=True, step=1e-1, ) # With the same step the truncation error is in this case much smaller. # Complex step # ------------ discipline.check_jacobian( input_data={"x": array([0.0]), "y": array([1.0])}, derr_approx=discipline.ApproximationMode.COMPLEX_STEP, show=True, plot_result=True, step=1e-1, ) # With the same step the truncation error is also smaller than finite differences. # This confirms again that an implementation mistake was done. # Advantages and drawbacks of each method # --------------------------------------- # Finite differnces and complex are first-order methods, they use one # sampling point per input and the truncation error goes down linearly with the step. # Centered differences are second-order methods which use twice as many points as finite # differences and complex step. Complex step derivatives are less prone to numerical # cancellation errors so that a tiny step can be used. On the other hand complex step is # not compatible with discipline not supporting complex inputs. discipline.check_jacobian( input_data={"x": array([0.0]), "y": array([1.0])}, derr_approx=discipline.ApproximationMode.COMPLEX_STEP, show=True, plot_result=True, step=1e-10, ) .. rst-class:: sphx-glr-script-out .. code-block:: none ERROR - 13:13:46: BuggedDiscipline Jacobian: dp f/d x is wrong by 0.14163403944972192%. INFO - 13:13:46: Approximate jacobian = INFO - 13:13:46: [[0.73330393]] INFO - 13:13:46: Provided by linearize method = INFO - 13:13:46: [[0.73575888]] INFO - 13:13:46: Difference of jacobians = INFO - 13:13:46: [[-0.00245495]] INFO - 13:13:46: Jacobian: dp f/dp y succeeded. INFO - 13:13:46: Jacobian: dp g/dp x succeeded. INFO - 13:13:46: Jacobian: dp g/dp y succeeded. INFO - 13:13:46: Linearization of MDODiscipline: BuggedDiscipline is wrong. /home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.3.2/lib/python3.9/site-packages/gemseo/utils/derivatives/derivatives_approx.py:658: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator. axe.set_xticklabels(x_labels, fontsize=14) ERROR - 13:13:46: BuggedDiscipline Jacobian: dp f/d x is wrong by 0.1409521643331837%. INFO - 13:13:46: Approximate jacobian = INFO - 13:13:46: [[0.73820893]] INFO - 13:13:46: Provided by linearize method = INFO - 13:13:46: [[0.73575888]] INFO - 13:13:46: Difference of jacobians = INFO - 13:13:46: [[0.00245004]] INFO - 13:13:46: Jacobian: dp f/dp y succeeded. INFO - 13:13:46: Jacobian: dp g/dp x succeeded. INFO - 13:13:46: Jacobian: dp g/dp y succeeded. INFO - 13:13:46: Linearization of MDODiscipline: BuggedDiscipline is wrong. /home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.3.2/lib/python3.9/site-packages/gemseo/utils/derivatives/derivatives_approx.py:658: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator. axe.set_xticklabels(x_labels, fontsize=14) INFO - 13:13:46: Jacobian: dp f/dp x succeeded. INFO - 13:13:46: Jacobian: dp f/dp y succeeded. INFO - 13:13:46: Jacobian: dp g/dp x succeeded. INFO - 13:13:46: Jacobian: dp g/dp y succeeded. INFO - 13:13:46: Linearization of MDODiscipline: BuggedDiscipline is correct. /home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.3.2/lib/python3.9/site-packages/gemseo/utils/derivatives/derivatives_approx.py:658: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator. axe.set_xticklabels(x_labels, fontsize=14) True .. GENERATED FROM PYTHON SOURCE LINES 145-151 Automatic time step ------------------- Finite differences and centered differences steps need to be chosen as a trade between truncation and numerical errors. For this reason, the ``auto_set_step`` option can be used to automatically compute the step where the total error is minimized. .. GENERATED FROM PYTHON SOURCE LINES 151-159 .. code-block:: Python discipline.check_jacobian( input_data={"x": array([0.0]), "y": array([1.0])}, derr_approx=discipline.ApproximationMode.CENTERED_DIFFERENCES, show=True, plot_result=True, auto_set_step=True, ) .. rst-class:: sphx-glr-script-out .. code-block:: none INFO - 13:13:47: Set optimal step for finite differences. Estimated approximation errors = INFO - 13:13:47: [1.20985073e-07 1.20985073e-07] INFO - 13:13:47: Jacobian: dp f/dp x succeeded. INFO - 13:13:47: Jacobian: dp f/dp y succeeded. INFO - 13:13:47: Jacobian: dp g/dp x succeeded. INFO - 13:13:47: Jacobian: dp g/dp y succeeded. INFO - 13:13:47: Linearization of MDODiscipline: BuggedDiscipline is correct. /home/docs/checkouts/readthedocs.org/user_builds/gemseo/envs/5.3.2/lib/python3.9/site-packages/gemseo/utils/derivatives/derivatives_approx.py:658: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator. axe.set_xticklabels(x_labels, fontsize=14) True .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 2.203 seconds) .. _sphx_glr_download_examples_disciplines_basics_plot_check_jacobian.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_check_jacobian.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_check_jacobian.py ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_