Source code for gemseo.problems.disciplines_factory
# 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 - initial API and implementation and/or
# initial documentation
# :author: Francois Gallard
# OTHER AUTHORS - MACROSCOPIC CHANGES
"""Factory to create disciplines."""
from __future__ import annotations
from copy import deepcopy
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from gemseo.core import discipline
from gemseo.core.base_factory import BaseFactory
from gemseo.core.discipline import MDODiscipline
from gemseo.core.grammars.json_grammar import JSONGrammar
if TYPE_CHECKING:
from collections.abc import Mapping
[docs]
class DisciplinesFactory(BaseFactory):
"""The **DisciplinesFactory** is used to create :class:`.MDODiscipline` objects.
Three types of directories are scanned
to import the :class:`.MDODiscipline` classes:
- the environment variable "GEMSEO_PATH" may contain
the list of directories to scan,
- the present directory (:doc:`gemseo.problems`) contains some
benchmark test cases,
"""
_CLASS = MDODiscipline
_MODULE_NAMES = (
"gemseo.problems",
"gemseo.core",
"gemseo.disciplines",
"gemseo.wrappers",
)
def __init__(self) -> None: # noqa: D107
# Defines the benchmark problems to be imported
super().__init__()
self.__base_grammar = JSONGrammar("MDODiscipline_options")
base_gram_path = Path(discipline.__file__).parent / "MDODiscipline_options.json"
self.__base_grammar.update_from_file(base_gram_path)
self.__base_grammar_names = self.__base_grammar.keys()
[docs]
def create(self, discipline_name: str, **options):
"""Create an :class:`.MDODiscipline` from its name.
Args:
discipline_name: The name of the discipline
**options: The options of the discipline,
both the options to be passed to the constructor
and the options that are generic to all the disciplines.
Returns:
The discipline.
"""
common_options, specific_options = self.__filter_common_options(options)
self.__base_grammar.validate(common_options)
discipline = super().create(discipline_name, **specific_options)
if "linearization_mode" in common_options:
discipline.linearization_mode = common_options["linearization_mode"]
cache_options = self.__filter_options_with_prefix(common_options, "cache")
if cache_options:
discipline.set_cache_policy(**cache_options)
jacobian_options = self.__filter_options_with_prefix(common_options, "jac")
if jacobian_options:
discipline.set_jacobian_approximation(**jacobian_options)
return discipline
@staticmethod
def __filter_options_with_prefix(
options: Mapping[str, Any], prefix: str
) -> dict[str, Any]:
"""Filter the options whose names start with a prefix.
Args:
options: The options of the disciplines.
prefix: The prefix.
Returns:
The options whose names start with a prefix.
"""
return {k: v for k, v in options.items() if k.startswith(prefix)}
def __filter_common_options(self, options):
"""Separate options.
Args:
options: The options of the discipline.
Returns:
The options common to all the disciplines,
and the options specific to the current discipline.
"""
common_option_names = self.__base_grammar_names
common_options = {k: v for k, v in options.items() if k in common_option_names}
specific_options = {k: v for k, v in options.items() if k not in common_options}
return common_options, specific_options
@property
def disciplines(self) -> list[str]:
"""The names of the available disciplines."""
return self.class_names
[docs]
def get_options_grammar(
self, name: str, write_schema: bool = False, schema_path: str | None = None
) -> JSONGrammar:
"""Get the options default values for the given class name.
Args:
name: The name of the class.
schema_path: the output json file path. If ``None``: input.json or
output.json depending on grammar type.
write_schema: Whether to write the schema files
Returns:
The JSON grammar of the options.
"""
disc_gram = super().get_options_grammar(name, write_schema, schema_path)
option_grammar = deepcopy(self.__base_grammar)
option_grammar.update(disc_gram)
return option_grammar