Source code for gemseo.core.chains.initialization_chain

# 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: Francois Gallard
#    OTHER AUTHORS   - MACROSCOPIC CHANGES
"""MDA input data initialization."""

from __future__ import annotations

from typing import TYPE_CHECKING

from gemseo.core.chains.chain import MDOChain
from gemseo.utils.string_tools import pretty_str

if TYPE_CHECKING:
    from collections.abc import Iterable
    from collections.abc import Sequence

    from gemseo.core.discipline import Discipline


[docs] def order_disciplines_from_default_inputs( disciplines: Sequence[Discipline], raise_error: bool = True, available_data_names: Iterable[str] = (), ) -> list[Discipline] | list[str]: """Order disciplines such that all their input values are defined. It is particularly useful in the case of MDAs when not all default_input_data are available, and the execution order is not obvious to compute initial values for all couplings. From the default inputs of the disciplines, use a greedy algorithm to detect sequentially the disciplines that can be executed, and records the execution order. Raises: ValueError: When a discipline cannot be initialized. Args: disciplines: The disciplines to compute the initialization of. raise_error: Whether to raise an exception when the algorithm fails. available_data_names: The data names that are assumed to be available at runtime, in addition to the default_input_data. Returns: The ordered disciplines when the algorithm succeeds, or, if raise_error=False, the inputs that are missing. """ ordered_discs = [] remaining_discs = list(disciplines) available_data_names = list(available_data_names) while remaining_discs: removed_discs = [] for disc in remaining_discs: required_inputs = set(disc.io.input_grammar) if not required_inputs.difference( disc.io.input_grammar.defaults ).difference(available_data_names): available_data_names.extend(disc.io.output_grammar) removed_discs.append(disc) if not removed_discs: disc_names = sorted(d.name for d in remaining_discs) missing_inputs = sorted( { in_name for disc in remaining_discs for in_name in disc.io.input_grammar }.difference(available_data_names) ) if raise_error: msg = ( "Cannot compute the inputs " f"{pretty_str(missing_inputs, sort=False)}, " "for the following disciplines " f"{pretty_str(disc_names, sort=False)}." ) raise ValueError(msg) return missing_inputs ordered_discs.extend(removed_discs) for disc in removed_discs: remaining_discs.remove(disc) return ordered_discs
[docs] class MDOInitializationChain(MDOChain): """An initialization process for a set of disciplines. This MDOChain subclass computes the initialization for the computation of a set of disciplines. It is particularly useful in the case of MDAs when not all default_input_data are available, and the execution order is not obvious to compute initial values for all couplings. From the default inputs of the disciplines, use a greedy algorithm to detect sequentially the disciplines that can be executed, and records the execution order. The couplings are ignored, and therefore, a true MDA must be used afterward to ensure consistency. """ def __init__( # noqa:D107 self, disciplines: Sequence[Discipline], name: str = "", available_data_names: Iterable[str] = (), ) -> None: """ Args: available_data_names: The data names that are assumed to be available at runtime, in addition to the default_input_data. """ # noqa:D205 D212 D415 disc_ordered = order_disciplines_from_default_inputs( disciplines, available_data_names=available_data_names ) super().__init__(disciplines=disc_ordered, name=name)