Exemple #1
0
    def _get_problem_inputs(
            self,
            problem: FASTOADProblem) -> Tuple[om.IndepVarComp, VariableList]:
        """
        Reads input file for the configure problem.

        Needed variables are returned as an IndepVarComp instance while unused variables are
        returned as a VariableList instance.

        :param problem: problem with missing inputs. setup() must have been run.
        :return: IVC of needed input variables, VariableList with unused variables.
        """
        mandatory, optional = get_unconnected_input_names(problem,
                                                          promoted_names=True)
        needed_variable_names = mandatory + optional

        input_variables = DataFile(self.input_file_path)

        unused_variables = VariableList([
            var for var in input_variables
            if var.name not in needed_variable_names
        ])
        for name in unused_variables.names():
            del input_variables[name]

        nan_variable_names = [
            var.name for var in input_variables if np.all(np.isnan(var.value))
        ]
        if nan_variable_names:
            raise FASTConfigurationNanInInputFile(self.input_file_path,
                                                  nan_variable_names)

        input_ivc = input_variables.to_ivc()
        return input_ivc, unused_variables
Exemple #2
0
def _data_weight_decomposition(variables: VariableList, owe=None):
    """
    Returns the two level weight decomposition of MTOW and optionally the decomposition of owe
    subcategories.

    :param variables: instance containing variables information
    :param owe: value of OWE, if provided names of owe subcategories will be provided
    :return: variable values, names and optionally owe subcategories names
    """
    category_values = []
    category_names = []
    owe_subcategory_names = []
    for variable in variables.names():
        name_split = variable.split(":")
        if isinstance(name_split, list) and len(name_split) == 4:
            if name_split[0] + name_split[1] + name_split[
                    3] == "dataweightmass" and not ("aircraft"
                                                    in name_split[2]):
                category_values.append(
                    convert_units(variables[variable].value[0],
                                  variables[variable].units, "kg"))
                category_names.append(name_split[2])
                if owe:
                    owe_subcategory_names.append(
                        name_split[2] + "<br>" +
                        str(int(variables[variable].value[0])) + " [kg] (" +
                        str(round(variables[variable].value[0] / owe *
                                  100, 1)) + "%)")
    if owe:
        result = category_values, category_names, owe_subcategory_names
    else:
        result = category_values, category_names, None

    return result
    def _get_problem_inputs(self) -> Tuple[VariableList, VariableList]:
        """
        Reads input file for the configured problem.

        Needed variables and unused variables are
        returned as a VariableList instance.

        :return: VariableList of needed input variables, VariableList with unused variables.
        """

        problem_variables = VariableList().from_problem(self)
        problem_inputs_names = [var.name for var in problem_variables if var.is_input]

        input_variables = DataFile(self.input_file_path)

        unused_variables = VariableList(
            [var for var in input_variables if var.name not in problem_inputs_names]
        )
        for name in unused_variables.names():
            del input_variables[name]

        nan_variable_names = [var.name for var in input_variables if np.all(np.isnan(var.value))]
        if nan_variable_names:
            raise FASTOpenMDAONanInInputFile(self.input_file_path, nan_variable_names)

        return input_variables, unused_variables
    def read_variables(self, data_source: Union[str, IO]) -> VariableList:

        variables = VariableList()

        parser = etree.XMLParser(remove_blank_text=True, remove_comments=True)
        tree = etree.parse(data_source, parser)
        root = tree.getroot()
        for elem in root.iter():
            units = elem.attrib.get(self.xml_unit_attribute, None)
            is_input = elem.attrib.get(self.xml_io_attribute, None)
            if units:
                # Ensures compatibility with OpenMDAO units
                for legacy_chars, om_chars in self.unit_translation.items():
                    units = re.sub(legacy_chars, om_chars, units)
                    units = units.replace(legacy_chars, om_chars)
            value = None
            if elem.text:
                value = get_float_list_from_string(elem.text)

            if value is not None:
                try:
                    path_tags = [
                        ancestor.tag for ancestor in elem.iterancestors()
                    ]
                    path_tags.reverse()
                    path_tags.append(elem.tag)
                    xpath = "/".join(path_tags[1:])  # Do not use root tag
                    name = self._translator.get_variable_name(xpath)
                except FastXpathTranslatorXPathError as err:
                    _LOGGER.warning(
                        "The xpath %s does not have any variable "
                        "affected in the translator.",
                        err.xpath,
                    )
                    continue

                if name not in variables.names():
                    # Add Variable
                    if is_input is not None:
                        is_input = is_input == "True"

                    variables[name] = {
                        "value": value,
                        "units": units,
                        "is_input": is_input
                    }
                else:
                    raise FastXmlFormatterDuplicateVariableError(
                        "Variable %s is defined in more than one place in file %s"
                        % (name, data_source))

        return variables
Exemple #5
0
    def _filter_variables(variables: VariableList,
                          only: Sequence[str] = None,
                          ignore: Sequence[str] = None) -> VariableList:
        """
        filters the variables such that the ones in arg only are kept and the ones in
        arg ignore are removed.

        Elements of `only` and `ignore` can be variable names or Unix-shell-style patterns.
        In any case, filter is case-sensitive.

        :param variables:
        :param only: List of OpenMDAO variable names that should be written. Other names will be
                     ignored. If None, all variables will be written.
        :param ignore: List of OpenMDAO variable names that should be ignored when writing
        :return: filtered variables
        """

        # Dev note: We use sets, but sets of Variable instances do
        # not work. Do we work with variable names instead.
        # FIXME: Variable instances are now hashable, so set of Variable instances should now work

        var_names = variables.names()

        if only is None:
            used_var_names = set(var_names)
        else:
            used_var_names = set()
            for pattern in only:
                used_var_names.update([
                    variable.name for variable in variables
                    if fnmatchcase(variable.name, pattern)
                ])

        if ignore is not None:
            for pattern in ignore:
                used_var_names.difference_update([
                    variable.name for variable in variables
                    if fnmatchcase(variable.name, pattern)
                ])

        # It could be simpler, but I want to keep the order
        used_variables = VariableList()
        for var in variables:
            if var.name in used_var_names:
                used_variables.append(var)
        return used_variables
Exemple #6
0
def list_variables(
    configuration_file_path: str,
    out: Union[IO, str] = sys.stdout,
    overwrite: bool = False,
    force_text_output: bool = False,
):
    """
    Writes list of variables for the :class:`FASTOADProblem` specified in configuration_file_path.

    List is generally written as text. It can be displayed as a scrollable table view if:
    - function is used in an interactive IPython shell
    - out == sys.stdout
    - force_text_output == False

    :param configuration_file_path:
    :param out: the output stream or a path for the output file
    :param overwrite: if True and out parameter is a file path, the file will be written even if one
                      already exists
    :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
    :raise FastFileExistsError: if overwrite==False and out parameter is a file path and the file
                                exists
    """
    conf = FASTOADProblemConfigurator(configuration_file_path)
    problem = conf.get_problem()
    problem.setup()

    # Extracting inputs and outputs
    variables = VariableList.from_problem(problem, get_promoted_names=False)
    variables.sort(key=lambda var: var.name)
    input_variables = VariableList([var for var in variables if var.is_input])
    output_variables = VariableList(
        [var for var in variables if not var.is_input])

    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")
        table_width = MAX_TABLE_WIDTH
    else:
        if out == sys.stdout and InteractiveShell.initialized(
        ) and not force_text_output:
            # Here we display the variable list as VariableViewer in a notebook
            for var in input_variables:
                var.metadata["I/O"] = "IN"
            for var in output_variables:
                var.metadata["I/O"] = "OUT"

            df = ((input_variables + output_variables).to_dataframe()[[
                "I/O", "name", "desc"
            ]].rename(columns={
                "name": "Name",
                "desc": "Description"
            }))
            display(HTML(df.to_html()))
            return

        # Here we continue with text output
        out_file = out
        table_width = min(get_terminal_size().columns, MAX_TABLE_WIDTH) - 1

    pd.set_option("display.max_colwidth", 1000)
    max_name_length = np.max([
        len(name)
        for name in input_variables.names() + output_variables.names()
    ])
    description_text_width = table_width - max_name_length - 2

    def _write_variables(out_f, variables):
        """Writes variables and their description as a pandas DataFrame"""
        df = variables.to_dataframe()

        # Create a new Series where description are wrapped on several lines if needed.
        # Each line becomes an element of the Series
        df["desc"] = [
            "\n".join(tw.wrap(s, description_text_width)) for s in df["desc"]
        ]
        new_desc = df.desc.str.split("\n", expand=True).stack()

        # Create a Series for name that will match new_desc Series. Variable name will be in front of
        # first line of description. An empty string will be in front of other lines.
        new_name = [
            df.name.loc[i] if j == 0 else "" for i, j in new_desc.index
        ]

        # Create the DataFrame that will be displayed
        new_df = pd.DataFrame({"NAME": new_name, "DESCRIPTION": new_desc})

        out_f.write(
            new_df.to_string(
                index=False,
                columns=["NAME", "DESCRIPTION"],
                justify="center",
                formatters={  # Formatters are needed for enforcing left justification
                    "NAME": ("{:%s}" % max_name_length).format,
                    "DESCRIPTION": ("{:%s}" % description_text_width).format,
                },
            )
        )
        out_file.write("\n")

    def _write_text_with_line(txt: str, line_length: int):
        """ Writes a line of given length with provided text inside """
        out_file.write("-" + txt + "-" * (line_length - 1 - len(txt)) + "\n")

    # Inputs
    _write_text_with_line(" INPUTS OF THE PROBLEM ", table_width)
    _write_variables(out_file, input_variables)

    # Outputs
    out_file.write("\n")
    _write_text_with_line(" OUTPUTS OF THE PROBLEM ", table_width)
    _write_variables(out_file, output_variables)
    _write_text_with_line("", table_width)

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