Source code for gemseo.algos.doe.morris_doe.morris_doe

# 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.
"""The DOE used by the Morris sensitivity analysis."""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING
from typing import ClassVar
from typing import Optional
from typing import TextIO
from typing import Union

from numpy import vstack

from gemseo.algos.doe.base_doe_library import BaseDOELibrary
from gemseo.algos.doe.base_doe_library import DOEAlgorithmDescription
from gemseo.algos.doe.factory import DOELibraryFactory
from gemseo.algos.doe.morris_doe.settings.morris_doe_settings import MorrisDOE_Settings
from gemseo.typing import MutableStrKeyMapping
from gemseo.typing import RealArray

if TYPE_CHECKING:
    from gemseo.algos.design_space import DesignSpace

OptionType = Optional[Union[str, int, float, bool, list[str], Path, TextIO, RealArray]]


[docs] class MorrisDOE(BaseDOELibrary): """The DOE used by the Morris sensitivity analysis. This DOE algorithm applies the :class:`.OATDOE` algorithm at :math:`r` points. The number of samples is equal to :math:`r(1+d)` where :math:`d` is the space dimension. """ ALGORITHM_INFOS: ClassVar[dict[str, DOEAlgorithmDescription]] = { "MorrisDOE": DOEAlgorithmDescription( algorithm_name="MorrisDOE", description="The DOE used by the Morris sensitivity analysis.", internal_algorithm_name="MorrisDOE", library_name="MorrisDOE", Settings=MorrisDOE_Settings, ) } def __init__(self, algo_name: str = "MorrisDOE") -> None: # noqa:D107 super().__init__(algo_name) def _generate_unit_samples( self, design_space: DesignSpace, n_samples: int, doe_algo_name: str, doe_algo_settings: MutableStrKeyMapping, step: float, ) -> RealArray: """ Args: n_samples: The maximum number of samples required by the user. If 0, deduce it from the design space dimension and ``doe_algo_settings``. doe_algo_name: The name of the DOE algorithm to repeat the OAT DOE. doe_algo_settings: The settings of the DOE algorithm to repeat the OAT DOE. step: The relative step of the OAT DOE. Raises: ValueError: When the number of samples is lower than the dimension of the input space plus one. """ # noqa: D205, D212 factory = DOELibraryFactory() doe_algo = factory.create(doe_algo_name) oat_algo = factory.create("OATDOE") dimension = design_space.dimension n_replicates = doe_algo_settings.get("n_samples", 5) if n_samples > 0: n_replicates = n_samples // (dimension + 1) if n_replicates == 0: msg = ( f"The number of samples ({n_samples}) must be " "at least equal to the dimension of the input space plus one " f"({dimension}+1={dimension + 1})." ) raise ValueError(msg) # If possible, set the number of samples of the DOE algorithm n_samples_available = set( doe_algo.ALGORITHM_INFOS[doe_algo_name].Settings.model_fields ).intersection(["n_samples", "samples"]) if n_samples_available and doe_algo_name != "CustomDOE": doe_algo_settings[n_samples_available.pop()] = n_replicates base_options = {"variables_space": dimension, "unit_sampling": True} initial_points = doe_algo.compute_doe(**base_options, **doe_algo_settings) return vstack([ oat_algo.compute_doe(**base_options, step=step, initial_point=initial_point) for initial_point in initial_points ])