Source code for gemseo.problems.mdo.sellar.sellar_2
# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Contributors:
# INITIAL AUTHORS - API and implementation and/or documentation
# :author: Charlie Vanaret
# Francois Gallard
# OTHER AUTHORS - MACROSCOPIC CHANGES
"""The second strongly coupled discipline of the customizable Sellar MDO problem."""
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import ClassVar
from numpy import ones
from numpy import where
from scipy.sparse import csr_array
from scipy.sparse import eye
from gemseo.problems.mdo.sellar import WITH_2D_ARRAY
from gemseo.problems.mdo.sellar.base_sellar import BaseSellar
from gemseo.problems.mdo.sellar.variables import X_1
from gemseo.problems.mdo.sellar.variables import X_2
from gemseo.problems.mdo.sellar.variables import X_SHARED
from gemseo.problems.mdo.sellar.variables import Y_1
from gemseo.problems.mdo.sellar.variables import Y_2
if TYPE_CHECKING:
from collections.abc import Iterable
from gemseo.typing import RealArray
from gemseo.typing import StrKeyMapping
from gemseo.utils.compatibility.scipy import SparseArrayType
[docs]
class Sellar2(BaseSellar):
"""The discipline to compute the coupling variable :math:`y_2`."""
_INPUT_NAMES: ClassVar[tuple[str]] = (X_2, X_SHARED, Y_1)
_OUTPUT_NAMES: ClassVar[tuple[str]] = (Y_2,)
__k: float
"""The shared coefficient controlling the coupling strength."""
__eye_n: RealArray
"""The identity matrix of dimension n."""
__k_eye_n: RealArray
"""The identity matrix of dimension n multiplied by the coefficient k."""
__ones_n: RealArray
"""The (1x2) matrix of dimension n."""
__zeros_n: SparseArrayType
"""The zero matrix of dimension n."""
def __init__(self, n: int = 1, k: float = 1.0) -> None:
"""
Args:
k: The shared coefficient controlling the coupling strength
""" # noqa: D107 D205 D205 D212 D415
super().__init__(n)
self.__k = k
self.__eye_n = eye(n)
self.__ones_n = ones((n, 2))
self.__k_eye_n = k * self.__eye_n
self.__zeros_n = csr_array((n, n))
def _run(self, input_data: StrKeyMapping) -> StrKeyMapping | None:
x_2 = input_data[X_2]
x_shared = input_data[X_SHARED]
y_1 = input_data[Y_1]
if WITH_2D_ARRAY: # pragma: no cover
x_shared = x_shared[0]
out = x_shared[0] + x_shared[1] - x_2
y_2 = where(y_1.real > 0, self.__k * y_1 + out, -self.__k * y_1 + out)
inds_where = y_1.real == 0
y_2[inds_where] = out[inds_where]
return {Y_2: y_2}
def _compute_jacobian(
self,
input_names: Iterable[str] = (),
output_names: Iterable[str] = (),
) -> None:
y_1 = self.io.data[Y_1]
self.jac = {Y_2: {}}
jac = self.jac[Y_2]
jac[X_1] = self.__zeros_n
jac[X_2] = -self.__eye_n
jac[X_SHARED] = self.__ones_n
dy_2_dy_1 = self.__k_eye_n.tocsr().copy()
inds_negative = y_1.real < 0
dy_2_dy_1[inds_negative] *= -1.0
dy_2_dy_1[y_1.real == 0] = 0.0
self.jac[Y_2][Y_1] = dy_2_dy_1