Example #1
0
    def _build_model(self, input_ivc: om.IndepVarComp = None) -> om.Group:
        """
        Builds the model as defined in the configuration file.

        The model is initialized as a new group and populated with subsystems
        indicated in configuration file.

        :return: the built model
        """

        model = FASTOADModel()
        model.active_submodels = self._serializer.data.get(KEY_SUBMODELS, {})

        if input_ivc:
            model.add_subsystem("fastoad_inputs", input_ivc, promotes=["*"])

        model_definition = self._serializer.data.get(KEY_MODEL)

        try:
            if KEY_COMPONENT_ID in model_definition:
                # The defined model is only one system
                system_id = model_definition[KEY_COMPONENT_ID]
                sub_component = RegisterOpenMDAOSystem.get_system(system_id)
                model.add_subsystem("system", sub_component, promotes=["*"])
            else:
                # The defined model is a group
                self._parse_problem_table(model, model_definition)

        except FASTConfigurationBaseKeyBuildingError as err:
            log_err = err.__class__(err, KEY_MODEL)
            _LOGGER.error(log_err)
            raise log_err

        return model
    def _build_model(self, problem: FASTOADProblem):
        """
        Builds the problem model as defined in the configuration file.

        The problem model is populated with subsystems indicated in configuration file.
        """

        model = problem.model
        model.active_submodels = self._serializer.data.get(KEY_SUBMODELS, {})

        model_definition = self._serializer.data.get(KEY_MODEL)

        try:
            if KEY_COMPONENT_ID in model_definition:
                # The defined model is only one system
                system_id = model_definition[KEY_COMPONENT_ID]
                sub_component = RegisterOpenMDAOSystem.get_system(system_id)
                model.add_subsystem("system", sub_component, promotes=["*"])
            else:
                # The defined model is a group
                self._parse_problem_table(model, model_definition)

        except FASTConfigurationBaseKeyBuildingError as err:
            log_err = err.__class__(err, KEY_MODEL)
            _LOGGER.error(log_err)
            raise log_err
Example #3
0
    def load(self, conf_file):
        """
        Reads the problem definition

        :param conf_file: Path to the file to open or a file descriptor
        """

        self._conf_file = pth.abspath(
            conf_file)  # for resolving relative paths
        conf_dirname = pth.dirname(self._conf_file)

        if pth.splitext(self._conf_file)[-1] == ".toml":
            self._serializer = _TOMLSerializer()
            _LOGGER.warning(
                "TOML-formatted configuration files are deprecated. Please use YAML format."
            )
        else:
            self._serializer = _YAMLSerializer()
        self._serializer.read(self._conf_file)

        # Syntax validation
        with open_text(resources, JSON_SCHEMA_NAME) as json_file:
            json_schema = json.loads(json_file.read())
        validate(self._serializer.data, json_schema)
        # Issue a simple warning for unknown keys at root level
        for key in self._serializer.data:
            if key not in json_schema["properties"].keys():
                _LOGGER.warning(
                    'Configuration file: "%s" is not a FAST-OAD key.', key)

        # Looking for modules to register
        module_folder_paths = self._serializer.data.get(KEY_FOLDERS)
        if isinstance(module_folder_paths, str):
            module_folder_paths = [module_folder_paths]
        if module_folder_paths:
            for folder_path in module_folder_paths:
                folder_path = pth.join(conf_dirname, str(folder_path))
                if not pth.exists(folder_path):
                    _LOGGER.warning("SKIPPED %s: it does not exist.",
                                    folder_path)
                else:
                    RegisterOpenMDAOSystem.explore_folder(folder_path)

        # Settings submodels
        submodel_specs = self._serializer.data.get(KEY_SUBMODELS, {})
        for submodel_requirement, submodel_id in submodel_specs.items():
            RegisterSubmodel.active_models[submodel_requirement] = submodel_id
Example #4
0
    def _parse_problem_table(self, group: om.Group, table: dict):
        """
        Feeds provided *group*, using definition in provided TOML *table*.

        :param group:
        :param table:
        """
        # assert isinstance(table, dict), "table should be a dictionary"

        for key, value in table.items():
            if isinstance(value, dict):  # value defines a sub-component
                if KEY_COMPONENT_ID in value:
                    # It is a non-group component, that should be registered with its ID
                    options = value.copy()
                    identifier = options.pop(KEY_COMPONENT_ID)

                    # Process option values that are relative paths
                    conf_dirname = pth.dirname(self._conf_file)
                    for name, option_value in options.items():
                        option_is_path = (name.endswith("file")
                                          or name.endswith("path")
                                          or name.endswith("dir")
                                          or name.endswith("directory")
                                          or name.endswith("folder"))
                        if (isinstance(option_value, str) and option_is_path
                                and not pth.isabs(option_value)):
                            options[name] = pth.join(conf_dirname,
                                                     option_value)

                    sub_component = RegisterOpenMDAOSystem.get_system(
                        identifier, options=options)
                    group.add_subsystem(key, sub_component, promotes=["*"])
                else:
                    # It is a Group
                    sub_component = group.add_subsystem(key,
                                                        om.Group(),
                                                        promotes=["*"])
                    try:
                        self._parse_problem_table(sub_component, value)
                    except FASTConfigurationBadOpenMDAOInstructionError as err:
                        # There has been an error while parsing an attribute.
                        # Error is relayed with key added for context
                        raise FASTConfigurationBadOpenMDAOInstructionError(
                            err, key)
            elif key == KEY_CONNECTION_ID and isinstance(value, list):
                # a list of dict currently defines only connections
                for connection_def in value:
                    group.connect(connection_def["source"],
                                  connection_def["target"])
            else:
                # value is an attribute of current component and will be literally interpreted
                try:
                    setattr(group, key, _om_eval(str(value)))  # pylint:disable=eval-used
                except Exception as err:
                    raise FASTConfigurationBadOpenMDAOInstructionError(
                        err, key, value)
Example #5
0
def _get_detailed_system_list():
    cell_list = [[
        "AVAILABLE MODULE IDENTIFIERS\n============================"
    ]]
    for identifier in sorted(RegisterOpenMDAOSystem.get_provider_ids()):
        path = BundleLoader().get_factory_path(identifier)
        domain = RegisterOpenMDAOSystem.get_provider_domain(identifier)
        description = RegisterOpenMDAOSystem.get_provider_description(
            identifier)
        if description is None:
            description = ""

        # We remove OpenMDAO's native options from the description
        component = RegisterOpenMDAOSystem.get_system(identifier)
        component.options.undeclare("assembled_jac_type")
        component.options.undeclare("distributed")

        cell_content = (
            "  IDENTIFIER:   %s\nPATH:         %s\nDOMAIN:       %s\nDESCRIPTION:  %s\n"
            % (identifier, path, domain.value,
               tw.indent(tw.dedent(description), "    ")))
        if len(list(component.options.items())) > 0:
            cell_content += component.options.to_table(fmt="grid") + "\n"

        cell_list.append([cell_content])
    cell_list.append([
        "AVAILABLE PROPULSION WRAPPER IDENTIFIERS\n========================================"
    ])
    for identifier in sorted(RegisterPropulsion.get_provider_ids()):
        path = BundleLoader().get_factory_path(identifier)
        description = RegisterPropulsion.get_provider_description(identifier)
        if description is None:
            description = ""

        cell_content = "  IDENTIFIER:   %s\nPATH:         %s\nDESCRIPTION:  %s\n" % (
            identifier,
            path,
            tw.indent(tw.dedent(description), "    "),
        )
        cell_list.append([cell_content])
    return cell_list
Example #6
0
def _get_simple_system_list():
    cell_list = [["   AVAILABLE MODULE IDENTIFIERS", "MODULE PATH"]]
    for identifier in sorted(RegisterOpenMDAOSystem.get_provider_ids()):
        path = BundleLoader().get_factory_path(identifier)
        cell_list.append([identifier, path])

    cell_list.append(["   AVAILABLE PROPULSION WRAPPER IDENTIFIERS", "MODULE PATH"])
    for identifier in sorted(RegisterPropulsion.get_provider_ids()):
        path = BundleLoader().get_factory_path(identifier)
        cell_list.append([identifier, path])

    return cell_list
Example #7
0
    def load(self, conf_file):
        """
        Reads the problem definition

        :param conf_file: Path to the file to open or a file descriptor
        """

        self._conf_file = pth.abspath(
            conf_file)  # for resolving relative paths
        conf_dirname = pth.dirname(self._conf_file)

        if pth.splitext(self._conf_file)[-1] == ".toml":
            self._serializer = _TOMLSerializer()
            _LOGGER.warning(
                "TOML-formatted configuration files are deprecated. Please use YAML format."
            )
        else:
            self._serializer = _YAMLSerializer()
        self._serializer.read(self._conf_file)

        # Syntax validation
        with open_text(resources, JSON_SCHEMA_NAME) as json_file:
            json_schema = json.loads(json_file.read())
        validate(self._serializer.data, json_schema)

        # Looking for modules to register
        module_folder_paths = self._serializer.data.get(KEY_FOLDERS)
        if isinstance(module_folder_paths, str):
            module_folder_paths = [module_folder_paths]
        if module_folder_paths:
            for folder_path in module_folder_paths:
                folder_path = pth.join(conf_dirname, str(folder_path))
                if not pth.exists(folder_path):
                    _LOGGER.warning("SKIPPED %s: it does not exist.",
                                    folder_path)
                else:
                    RegisterOpenMDAOSystem.explore_folder(folder_path)
"""
Demonstrates the alternate way register components in RegisterOpenMDAOSystem.
The main way would be to use the decorator directly on class definition.
"""
#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
#  FAST is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  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 General Public License for more details.
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.

from fastoad.module_management.constants import ModelDomain
from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
from .disc2.disc2 import Disc2

RegisterOpenMDAOSystem("module_management_test.sellar.disc2",
                       domain=ModelDomain.GEOMETRY)(Disc2)
Example #9
0
def list_modules(
    source_path: Union[List[str], str] = None,
    out: Union[IO, str] = None,
    overwrite: bool = False,
    verbose: bool = False,
    force_text_output: bool = False,
):
    """
    Writes list of available systems.
    If source_path is given and if it defines paths where there are registered systems,
    they will be listed too.

    :param source_path: either a configuration file path, folder path, or list of folder path
    :param out: the output stream or a path for the output file (None means sys.stdout)
    :param overwrite: if True and out is a file path, the file will be written even if one already
                      exists
    :param verbose: if True, shows detailed information for each system
                    if False, shows only identifier and path of each system
    :param force_text_output: if True, list will be written as text, even if command is used in an
                              interactive IPython shell (Jupyter notebook). Has no effect in other
                              shells or if out parameter is not sys.stdout
    :return: path of generated file, or None if no file was generated.
    :raise FastFileExistsError: if `overwrite==False` and `out` is a file path and the file exists
    """
    if out is None:
        out = sys.stdout

    if isinstance(source_path, str):
        if pth.isfile(source_path):
            conf = FASTOADProblemConfigurator(source_path)
            conf._set_configuration_modifier(_PROBLEM_CONFIGURATOR)
            # As the problem has been configured,
            # BundleLoader now knows additional registered systems
        elif pth.isdir(source_path):
            RegisterOpenMDAOSystem.explore_folder(source_path)
        else:
            raise FileNotFoundError("Could not find %s" % source_path)
    elif isinstance(source_path, Iterable):
        for folder_path in source_path:
            if not pth.isdir(folder_path):
                _LOGGER.warning("SKIPPED %s: folder does not exist.",
                                folder_path)
            else:
                RegisterOpenMDAOSystem.explore_folder(folder_path)
    elif source_path is not None:
        raise RuntimeError("Unexpected type for source_path")

    if verbose:
        cell_list = _get_detailed_system_list()
    else:
        cell_list = _get_simple_system_list()

    if isinstance(out, str):
        out = pth.abspath(out)
        if not overwrite and pth.exists(out):
            raise FastFileExistsError(
                "File %s not written because it already exists. "
                "Use overwrite=True to bypass." % out,
                out,
            )

        make_parent_dir(out)
        out_file = open(out, "w")
    else:
        if (out == sys.stdout and InteractiveShell.initialized()
                and not force_text_output and not verbose):
            display(HTML(tabulate(cell_list, tablefmt="html")))
            return None

        out_file = out

    out_file.write(tabulate(cell_list, tablefmt="grid"))
    out_file.write("\n")

    if isinstance(out, str):
        out_file.close()
        _LOGGER.info("System list written in %s", out)
        return out

    return None
Example #10
0
def list_systems(configuration_file_path: str = None,
                 out: Union[IO, str] = sys.stdout,
                 overwrite: bool = False):
    """
    Writes list of available systems.
    If configuration_file_path is given and if it defines paths where there are registered systems,
    they will be listed too.

    :param configuration_file_path:
    :param out: the output stream or a path for the output file
    :param overwrite: if True and out is a file path, the file will be written even if one already
                      exists
    :raise FastFileExistsError: if overwrite==False and out is a file path and the file exists
    """

    if configuration_file_path:
        conf = FASTOADProblemConfigurator(configuration_file_path)
        conf.load(configuration_file_path)
    # As the problem has been configured, BundleLoader now knows additional registered systems

    if isinstance(out, str):
        if not overwrite and pth.exists(out):
            raise FastFileExistsError(
                "File %s not written because it already exists. "
                "Use overwrite=True to bypass." % out,
                out,
            )

        make_parent_dir(out)
        out_file = open(out, "w")
    else:
        out_file = out
    out_file.writelines([
        "== AVAILABLE SYSTEM IDENTIFIERS " + "=" * 68 + "\n", "-" * 100 + "\n"
    ])
    for identifier in sorted(RegisterOpenMDAOSystem.get_provider_ids()):
        path = BundleLoader().get_factory_path(identifier)
        domain = RegisterOpenMDAOSystem.get_provider_domain(identifier)
        description = RegisterOpenMDAOSystem.get_provider_description(
            identifier)
        if description is None:
            description = ""
        out_file.write("  IDENTIFIER:   %s\n" % identifier)
        out_file.write("  PATH:         %s\n" % path)
        out_file.write("  DOMAIN:       %s\n" % domain.value)
        out_file.write("  DESCRIPTION:  %s\n" %
                       tw.indent(tw.dedent(description), "    "))
        out_file.write("-" * 100 + "\n")
    out_file.write("=" * 100 + "\n")

    out_file.writelines([
        "\n== AVAILABLE PROPULSION WRAPPER IDENTIFIERS " + "=" * 56 + "\n",
        "-" * 100 + "\n"
    ])
    for identifier in sorted(RegisterPropulsion.get_provider_ids()):
        path = BundleLoader().get_factory_path(identifier)
        description = RegisterPropulsion.get_provider_description(identifier)
        if description is None:
            description = ""
        out_file.write("  IDENTIFIER:   %s\n" % identifier)
        out_file.write("  PATH:         %s\n" % path)
        out_file.write("  DESCRIPTION:  %s\n" %
                       tw.indent(tw.dedent(description), "    "))
        out_file.write("-" * 100 + "\n")
    out_file.write("=" * 100 + "\n")

    if isinstance(out, str):
        out_file.close()
        _LOGGER.info("System list written in %s", out_file)
Example #11
0
"""
Demonstrates the alternate way register components in RegisterOpenMDAOSystem.
The main way would be to use the decorator directly on class definition.
"""
#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
#  FAST is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  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 General Public License for more details.
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.

from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
from .functions import Functions

RegisterOpenMDAOSystem("module_management_test.sellar.functions",
                       desc="some text",
                       options={"best_doctor": 11})(Functions)
Example #12
0
from .geometry import Geometry
from .handling_qualities.compute_static_margin import ComputeStaticMargin
from .handling_qualities.tail_sizing.compute_tail_areas import ComputeTailAreas
from .loops.compute_wing_area import ComputeWingArea
from .performances.mission.openmdao.link_mtow import ComputeMTOW
from .performances.mission.openmdao.mission import Mission
from .propulsion.fuel_propulsion.rubber_engine import (
    OMRubberEngineComponent,
    OMRubberEngineWrapper,
)
from .weight.weight import Weight


# Aerodynamics ################################################################
RegisterOpenMDAOSystem("fastoad.aerodynamics.takeoff.legacy", domain=ModelDomain.AERODYNAMICS)(
    AerodynamicsTakeoff
)
RegisterOpenMDAOSystem("fastoad.aerodynamics.landing.legacy", domain=ModelDomain.AERODYNAMICS)(
    AerodynamicsLanding
)
RegisterOpenMDAOSystem("fastoad.aerodynamics.highspeed.legacy", domain=ModelDomain.AERODYNAMICS,)(
    AerodynamicsHighSpeed
)
RegisterOpenMDAOSystem("fastoad.aerodynamics.lowspeed.legacy", domain=ModelDomain.AERODYNAMICS,)(
    AerodynamicsLowSpeed
)

# Geometry ####################################################################
RegisterOpenMDAOSystem("fastoad.geometry.legacy", domain=ModelDomain.GEOMETRY)(Geometry)

# handling qualities ##########################################################