Esempio n. 1
0
    def get_values(self, var, units=None):

        if units is not None and not valid_units(units):
            raise ValueError('{0} is not a valid set of units.'.format(units))

        var_in_phase = True

        if var == 'time':
            var_type = 'indep'
        elif var in self.outputs['states']:
            var_type = 'states'
        elif var in self.outputs['controls']:
            var_type = 'controls'
        elif var in self.outputs['design_parameters']:
            var_type = 'design_parameters'
        elif var in self.outputs['input_parameters']:
            var_type = 'input_parameters'
        elif var in self.outputs['control_rates']:
            var_type = 'control_rates'
        elif var in self.outputs['ode']:
            var_type = 'ode'
        else:
            var_in_phase = False

        if not var_in_phase:
            raise ValueError('Variable "{0}" not found in phase '
                             'simulation results.'.format(var))

        output = convert_units(self.outputs[var_type][var]['value'],
                               self.outputs[var_type][var]['units'], units)

        return output
Esempio n. 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 setUp(self):
        self.nn = 2

        ivc = om.IndepVarComp()
        ivc.add_output(name='A', shape=(self.nn, 5, 3), units='ft')
        ivc.add_output(name='x', shape=(self.nn, 3), units='lbf')
        ivc.add_output(name='B', shape=(self.nn, 5, 3), units='m')
        ivc.add_output(name='y', shape=(self.nn, 3), units='N')

        mvp = om.MatrixVectorProductComp(vec_size=self.nn,
                                         A_shape=(5, 3),
                                         A_units='m',
                                         x_units='N',
                                         b_units='N*m')

        mvp.add_product('c',
                        A_name='B',
                        x_name='y',
                        A_shape=(5, 3),
                        vec_size=self.nn,
                        A_units='m',
                        x_units='N',
                        b_units='N*m')

        model = om.Group()
        model.add_subsystem(name='ivc', subsys=ivc, promotes_outputs=['*'])

        model.add_subsystem(name='mat_vec_product_comp',
                            subsys=mvp,
                            promotes=['*'])

        self.p = om.Problem(model)
        self.p.setup(force_alloc_complex=True)

        A = np.random.rand(self.nn, 5, 3)
        x = np.random.rand(self.nn, 3)

        self.p['A'] = A
        self.p['x'] = x

        self.p['B'] = convert_units(A, 'ft', 'm')
        self.p['y'] = convert_units(x, 'lbf', 'N')

        self.p.run_model()
    def setUp(self):
        class MyModel(om.Group):
            def setup(self):
                ivc = om.IndepVarComp()
                ivc.add_output(name='A', shape=(2, 5, 3), units='ft')
                ivc.add_output(name='x', shape=(2, 3), units='lbf')

                mvp = om.MatrixVectorProductComp(vec_size=2,
                                                 A_shape=(5, 3),
                                                 A_units='m',
                                                 x_units='N',
                                                 b_units='N*m')

                self.add_subsystem('ivc', ivc, promotes_outputs=['*'])
                self.add_subsystem('mvp', mvp, promotes=['*'])

            def configure(self):
                self.ivc.add_output(name='B', shape=(2, 5, 3), units='m')
                self.ivc.add_output(name='y', shape=(2, 3), units='N')

                self.mvp.add_product('c',
                                     A_name='B',
                                     x_name='y',
                                     A_shape=(5, 3),
                                     vec_size=2,
                                     A_units='m',
                                     x_units='N',
                                     b_units='N*m')

        self.p = om.Problem(MyModel())
        self.p.setup(force_alloc_complex=True)

        A = np.random.rand(2, 5, 3)
        x = np.random.rand(2, 3)

        self.p['A'] = A
        self.p['x'] = x

        self.p['B'] = convert_units(A, 'ft', 'm')
        self.p['y'] = convert_units(x, 'lbf', 'N')

        self.p.run_model()
    def test_results(self):

        for i in range(self.nn):
            # b = Ax
            A_i = self.p['A'][i, :, :]
            x_i = self.p['x'][i, :]
            b_i = self.p.get_val('mat_vec_product_comp.b',
                                 units='ft*lbf')[i, :]

            expected_i = np.dot(A_i, x_i)
            np.testing.assert_almost_equal(b_i, expected_i)

            # c = Ay
            y_i = self.p['y'][i, :]
            c_i = self.p.get_val('mat_vec_product_comp.c', units='N*m')[i, :]

            expected_i = np.dot(convert_units(A_i, 'ft', 'm'), y_i)
            np.testing.assert_almost_equal(c_i, expected_i)

            # b & c should match after unit conversion
            np.testing.assert_almost_equal(convert_units(b_i, 'ft*lbf', 'N*m'),
                                           c_i)
Esempio n. 6
0
    def test_units(self):
        import openmdao.api as om
        from openmdao.utils.units import convert_units

        n = 10

        model = om.Group()

        model.add_subsystem('indep', om.IndepVarComp('x', val=range(n), units='ft'))
        model.add_subsystem('ks', om.KSComp(width=n, units='m'))

        model.connect('indep.x', 'ks.g')

        prob = om.Problem(model=model)
        prob.setup()
        prob.run_model()

        # KS is expressed in meters, while the independent variable 'x' is in feet
        assert_near_equal(prob['ks.KS'][0], convert_units(max(prob['indep.x']), 'ft', 'm'),
                          tolerance=1e-8)

        assert_near_equal(convert_units(prob['ks.KS'][0], 'm', 'ft'), max(prob['indep.x']),
                          tolerance=1e-8)
Esempio n. 7
0
def _get_variable_values_with_new_units(
    variables: VariableIO, var_names_and_new_units: Dict[str, str]
):
    """
    Returns the value of the requested variable names with respect to their new units in the order
    in which their were given. This function works only for variable of value with shape=1 or float.

    :param variables: instance containing variables information
    :param var_names_and_new_units: dictionnary of the variable names as keys and units as value
    :return: values of the requested variables with respect to their new units
    """
    new_values = []
    for variable_name, unit in var_names_and_new_units.items():
        new_values.append(
            convert_units(variables[variable_name].value[0], variables[variable_name].units, unit,)
        )

    return new_values
    def test_results(self):

        for i in range(self.nn):
            # b = Ax
            A_i = self.p['A'][i, :, :]
            x_i = self.p['x'][i, :]
            b_i = self.p.get_val('mat_vec_product_comp.b',
                                 units='ft*lbf')[i, :]

            expected_i = np.dot(A_i, x_i)
            np.testing.assert_almost_equal(b_i, expected_i)

            # c = Bx
            B_i = self.p['B'][i, :, :]
            c_i = self.p.get_val('mat_vec_product_comp.c', units='N*m')[i, :]

            expected_i = np.dot(B_i, convert_units(x_i, 'lbf', 'N'))
            np.testing.assert_almost_equal(c_i, expected_i)
Esempio n. 9
0
def _has_val_mismatch(discretes, names, units, vals):
    """
    Return True if any of the given values don't match, subject to unit conversion.

    Parameters
    ----------
    discretes : set-like
        Set of discrete variable names.
    names : list
        List of variable names.
    units : list
        List of units corresponding to names.
    vals : list
        List of values corresponding to names.

    Returns
    -------
    bool
        True if a mismatch was found, otherwise False.
    """
    if len(names) < 2:
        return False

    uset = set(units)
    if '' in uset and len(uset) > 1:
        # at least one case has no units and at least one does, so there must be a mismatch
        return True

    u0 = v0 = _UNSET
    for n, u, v in zip(names, units, vals):
        if n in discretes:
            continue
        if u0 is _UNSET:
            u0 = u
            v0 = v
        else:
            if u != u0:
                # convert units
                v = convert_units(v, u, new_units=u0)

            if np.linalg.norm(v - v0) > 1e-10:
                return True

    return False
Esempio n. 10
0
    def test_units_compute_totals(self):
        p = om.Problem()

        p.model.add_subsystem('stuff', om.ExecComp(['y = x', 'cy = x'],
                                                   x={'units': 'inch'},
                                                   y={'units': 'kg'},
                                                   cy={'units': 'kg'}),
                              promotes=['*'])

        p.model.add_design_var('x', units='ft')
        p.model.add_objective('y', units='lbm')
        p.model.add_constraint('cy', units='lbm', lower=0)

        p.setup()

        p['x'] = 1.0
        p.run_model()

        J_driver = p.driver._compute_totals()

        fact = convert_units(1.0, 'kg/inch', 'lbm/ft')
        assert_near_equal(J_driver['stuff.y', 'x'][0,0], fact, 1e-5)
        assert_near_equal(J_driver['stuff.cy', 'x'][0,0], fact, 1e-5)
Esempio n. 11
0
    def check_variables(cls, variables: VariableList) -> List[CheckRecord]:
        """
        Check values of provided variables against registered limits.

        :param variables:
        :return: the list of checks
        """
        records: List[CheckRecord] = []

        for var in variables:
            for limit_definitions in cls._limit_definitions.values():
                if var.name in limit_definitions:
                    limit_def = limit_definitions[var.name]
                    value = convert_units(var.value, var.units,
                                          limit_def.units)
                    if value < limit_def.lower:
                        status = ValidityStatus.TOO_LOW
                        limit = limit_def.lower
                    elif value > limit_def.upper:
                        status = ValidityStatus.TOO_HIGH
                        limit = limit_def.upper
                    else:
                        status = ValidityStatus.OK
                        limit = None

                    records.append(
                        CheckRecord(
                            var.name,
                            status,
                            limit,
                            limit_def.units,
                            var.value,
                            var.units,
                            limit_definitions.source_file,
                            limit_definitions.logger_name,
                        ))
        return records
Esempio n. 12
0
def mass_breakdown_sun_plot(aircraft_file_path: str, file_formatter=None):
    """
    Returns a figure sunburst plot of the mass breakdown.
    On the left a MTOW sunburst and on the right a OWE sunburst.
    Different designs can be superposed by providing an existing fig.
    Each design can be provided a name.

    :param aircraft_file_path: path of data file
    :param file_formatter: the formatter that defines the format of data file. If not provided,
                           default format will be assumed.
    :return: sunburst plot figure
    """
    variables = VariableIO(aircraft_file_path, file_formatter).read()

    var_names_and_new_units = {
        "data:weight:aircraft:MTOW": "kg",
        "data:weight:aircraft:OWE": "kg",
        "data:weight:aircraft:payload": "kg",
        "data:weight:aircraft:sizing_onboard_fuel_at_takeoff": "kg",
    }

    # pylint: disable=unbalanced-tuple-unpacking # It is balanced for the parameters provided
    mtow, owe, payload, onboard_fuel_at_takeoff = _get_variable_values_with_new_units(
        variables, var_names_and_new_units)

    # TODO: Deal with this in a more generic manner ?
    if round(mtow, 6) == round(owe + payload + onboard_fuel_at_takeoff, 6):
        mtow = owe + payload + onboard_fuel_at_takeoff

    fig = make_subplots(
        1,
        2,
        specs=[[{
            "type": "domain"
        }, {
            "type": "domain"
        }]],
    )

    fig.add_trace(
        go.Sunburst(
            labels=[
                "MTOW" + "<br>" + str(int(mtow)) + " [kg]",
                "payload" + "<br>" + str(int(payload)) + " [kg] (" +
                str(round(payload / mtow * 100, 1)) + "%)",
                "onboard_fuel_at_takeoff" + "<br>" +
                str(int(onboard_fuel_at_takeoff)) + " [kg] (" +
                str(round(onboard_fuel_at_takeoff / mtow * 100, 1)) + "%)",
                "OWE" + "<br>" + str(int(owe)) + " [kg] (" +
                str(round(owe / mtow * 100, 1)) + "%)",
            ],
            parents=[
                "",
                "MTOW" + "<br>" + str(int(mtow)) + " [kg]",
                "MTOW" + "<br>" + str(int(mtow)) + " [kg]",
                "MTOW" + "<br>" + str(int(mtow)) + " [kg]",
            ],
            values=[mtow, payload, onboard_fuel_at_takeoff, owe],
            branchvalues="total",
        ),
        1,
        1,
    )

    # Get data:weight 2-levels decomposition
    categories_values, categories_names, categories_labels = _data_weight_decomposition(
        variables, owe=owe)

    sub_categories_values = []
    sub_categories_names = []
    sub_categories_parent = []
    for variable in variables.names():
        name_split = variable.split(":")
        if isinstance(name_split, list) and len(name_split) >= 5:
            parent_name = name_split[2]
            if parent_name in categories_names and name_split[-1] == "mass":
                variable_name = "_".join(name_split[3:-1])
                sub_categories_values.append(
                    convert_units(variables[variable].value[0],
                                  variables[variable].units, "kg"))
                sub_categories_parent.append(
                    categories_labels[categories_names.index(parent_name)])
                sub_categories_names.append(variable_name)

    # Define figure data
    figure_labels = ["OWE" + "<br>" + str(int(owe)) + " [kg]"]
    figure_labels.extend(categories_labels)
    figure_labels.extend(sub_categories_names)
    figure_parents = [""]
    for _ in categories_names:
        figure_parents.append("OWE" + "<br>" + str(int(owe)) + " [kg]")
    figure_parents.extend(sub_categories_parent)
    figure_values = [owe]
    figure_values.extend(categories_values)
    figure_values.extend(sub_categories_values)

    # Plot figure
    fig.add_trace(
        go.Sunburst(
            labels=figure_labels,
            parents=figure_parents,
            values=figure_values,
            branchvalues="total",
        ),
        1,
        2,
    )

    fig.update_layout(title_text="Mass Breakdown", title_x=0.5)

    return fig
Esempio n. 13
0
    def get_values(self, var, nodes=None, units=None):
        """
        Retrieve the values of the given variable at the given
        subset of nodes.

        Parameters
        ----------
        var : str
            The variable whose values are to be returned.  This may be
            the name 'time', the name of a state, control, or parameter,
            or the path to a variable in the ODEFunction of the phase.
        nodes : str
            The name of the node subset.
        units : str
            The units in which the values should be expressed.  Must be compatible
            with the corresponding units inside the phase.

        Returns
        -------
        ndarray
            An array of the values at the requested node subset.  The
            node index is the first dimension of the ndarray.
        """
        if nodes is None:
            nodes = 'all'

        gd = self.grid_data

        var_type = self._classify_var(var)

        op = dict(self.list_outputs(explicit=True, values=True, units=True, shape=True,
                                    out_stream=None))

        if units is not None:
            if not valid_units(units):
                raise ValueError('Units {0} is not a valid units identifier'.format(units))

        var_prefix = '{0}.'.format(self.pathname) if self.pathname else ''

        path_map = {'time': 'time.{0}',
                    'state': 'indep_states.states:{0}',
                    'indep_control': 'control_interp_comp.control_values:{0}',
                    'input_control': 'control_interp_comp.control_values:{0}',
                    'design_parameter': 'design_params.design_parameters:{0}',
                    'input_parameter': 'input_params.input_parameters:{0}_out',
                    'control_rate': 'control_interp_comp.control_rates:{0}',
                    'control_rate2': 'control_interp_comp.control_rates:{0}',
                    'ode': 'rhs_all.{0}'}

        if var_type == 'state':
            var_path = var_prefix + path_map[var_type].format(var)
            output_units = op[var_path]['units']
            output_value = convert_units(op[var_path]['value'][gd.input_maps['state_input_to_disc'],
                                                               ...], output_units, units)

        elif var_type in ('input_control', 'indep_control'):
            var_path = var_prefix + path_map[var_type].format(var)
            output_units = op[var_path]['units']

            vals = op[var_path]['value']
            output_value = convert_units(vals, output_units, units)

        elif var_type in ('design_parameter', 'input_parameter', 'traj_design_parameter',
                          'traj_input_parameter'):
            var_path = var_prefix + path_map[var_type].format(var)
            output_units = op[var_path]['units']

            output_value = convert_units(op[var_path]['value'], output_units, units)
            output_value = np.repeat(output_value, gd.num_nodes, axis=0)

        elif var_type == 'ode':
            rhs_all_outputs = dict(self.rhs_all.list_outputs(out_stream=None, values=True,
                                                             shape=True, units=True))
            prom2abs_all = self.rhs_all._var_allprocs_prom2abs_list
            abs_path_all = prom2abs_all['output'][var][0]
            output_value = rhs_all_outputs[abs_path_all]['value']
            output_units = rhs_all_outputs[abs_path_all]['units']
            output_value = convert_units(output_value, output_units, units)
        else:
            var_path = var_prefix + path_map[var_type].format(var)
            output_units = op[var_path]['units']
            output_value = convert_units(op[var_path]['value'], output_units, units)

        # Always return a column vector
        if len(output_value.shape) == 1:
            output_value = np.reshape(output_value, (gd.num_nodes, 1))

        return output_value[gd.subset_node_indices[nodes], ...]
Esempio n. 14
0
def view_connections(root,
                     outfile='connections.html',
                     show_browser=True,
                     show_values=True,
                     precision=6,
                     title=None):
    """
    Generate a self-contained html file containing a detailed connection viewer.

    Optionally pops up a web browser to view the file.

    Parameters
    ----------
    root : system or Problem
        The root for the desired tree.

    outfile : str, optional
        The name of the output html file.  Defaults to 'connections.html'.

    show_browser : bool, optional
        If True, pop up a browser to view the generated html file.
        Defaults to True.

    show_values : bool, optional
        If True, retrieve the values and display them.

    precision : int, optional
        Sets the precision for displaying array values.

    title : str, optional
        Sets the title of the web page.
    """
    if MPI and MPI.COMM_WORLD.rank != 0:
        return

    # since people will be used to passing the Problem as the first arg to
    # the N2 diagram funct, allow them to pass a Problem here as well.
    if isinstance(root, Problem):
        system = root.model
    else:
        system = root

    input_srcs = system._problem_meta['connections']

    connections = {
        tgt: src
        for tgt, src in input_srcs.items() if src is not None
    }

    src2tgts = defaultdict(list)
    units = {}
    for n, data in system._var_allprocs_abs2meta.items():
        u = data.get('units', '')
        if u is None:
            u = ''
        units[n] = u

    vals = {}

    with printoptions(precision=precision, suppress=True, threshold=10000):

        for t in system._var_abs_names['input']:
            tmeta = system._var_abs2meta[t]
            idxs = tmeta['src_indices']

            s = connections[t]
            if show_values:
                if s.startswith('_auto_ivc.'):
                    val = system.get_val(t,
                                         indices=idxs,
                                         flat=True,
                                         get_remote=True,
                                         from_src=False)
                else:
                    val = system.get_val(t,
                                         indices=idxs,
                                         flat=True,
                                         get_remote=True)

                    # if there's a unit conversion, express the value in the
                    # units of the target
                    if units[t] and s in system._outputs:
                        val = convert_units(val, units[s], units[t])
            else:
                val = ''

            src2tgts[s].append(t)

            vals[t] = val

    NOCONN = '[NO CONNECTION]'
    vals[NOCONN] = ''

    src_systems = set()
    tgt_systems = set()
    for s in system._var_abs_names['output']:
        parts = s.split('.')
        for i in range(len(parts)):
            src_systems.add('.'.join(parts[:i]))

    for t in system._var_abs_names['input']:
        parts = t.split('.')
        for i in range(len(parts)):
            tgt_systems.add('.'.join(parts[:i]))

    src_systems = [{'name': n} for n in sorted(src_systems)]
    src_systems.insert(1, {'name': NOCONN})
    tgt_systems = [{'name': n} for n in sorted(tgt_systems)]
    tgt_systems.insert(1, {'name': NOCONN})

    tprom = system._var_allprocs_abs2prom['input']
    sprom = system._var_allprocs_abs2prom['output']

    table = []
    idx = 1  # unique ID for use by Tabulator
    for tgt, src in connections.items():
        usrc = units[src]
        utgt = units[tgt]
        if usrc != utgt:
            # prepend these with '!' so they'll be colored red
            if usrc:
                usrc = '!' + units[src]
            if utgt:
                utgt = '!' + units[tgt]

        row = {
            'id': idx,
            'src': src,
            'sprom': sprom[src],
            'sunits': usrc,
            'val': _val2str(vals[tgt]),
            'tunits': utgt,
            'tprom': tprom[tgt],
            'tgt': tgt
        }
        table.append(row)
        idx += 1

    # add rows for unconnected sources
    for src in system._var_abs_names['output']:
        if src not in src2tgts:
            if show_values:
                v = _val2str(system._outputs[src])
            else:
                v = ''
            row = {
                'id': idx,
                'src': src,
                'sprom': sprom[src],
                'sunits': units[src],
                'val': v,
                'tunits': '',
                'tprom': NOCONN,
                'tgt': NOCONN
            }
            table.append(row)
            idx += 1

    if title is None:
        title = ''

    data = {
        'title': title,
        'table': table,
        'show_values': show_values,
    }

    viewer = 'connect_table.html'

    code_dir = os.path.dirname(os.path.abspath(__file__))
    libs_dir = os.path.join(code_dir, 'libs')
    style_dir = os.path.join(code_dir, 'style')

    with open(os.path.join(code_dir, viewer), "r") as f:
        template = f.read()

    with open(os.path.join(libs_dir, 'tabulator.min.js'), "r") as f:
        tabulator_src = f.read()

    with open(os.path.join(style_dir, 'tabulator.min.css'), "r") as f:
        tabulator_style = f.read()

    jsontxt = json.dumps(data)

    with open(outfile, 'w') as f:
        s = template.replace("<connection_data>", jsontxt)
        s = s.replace("<tabulator_src>", tabulator_src)
        s = s.replace("<tabulator_style>", tabulator_style)
        f.write(s)

    if show_browser:
        webview(outfile)
Esempio n. 15
0
    def get_values(self, var, phases=None, units=None, flat=False):
        """
        Returns the values of the given variable from the given phases, if provided.
        If the variable is not present in one ore more phases, it will be returned as
        numpy.nan at each time step.

        Parameters
        ----------
        var : str
            The variable whose values are to be returned.
        phases : Sequence, None
            The phases from which the values are desired.  If None, included all Phases.
        units : str, None
            The units in which the values are desired.
        flat : bool
            If False return the values in a dictionary keyed by phase name.  If True,
            return a single array incorporating values from all phases.

        Returns
        -------
        dict or np.array
            If flat=False, a dictionary of the values of the variable in each phase will be
            returned, keyed by Phase name.  If the values are not present in a subset of the phases,
            return numpy.nan at each time point in those phases.

        Raises
        ------
        KeyError
            If the given variable is not found in any phase, a KeyError is raised.

        """

        if units is not None and not valid_units(units):
            raise ValueError('{0} is not a valid set of units.'.format(units))

        phases = self.get_phase_names() if phases is None else phases

        return_vals = dict([(phase_name, {}) for phase_name in phases])

        var_in_traj = False

        times = {}
        time_units = None

        for phase_name in phases:
            var_in_phase = True

            # Gather times for the purposes of flattening the returned values
            # Note the adjustment to the last time, for the purposes of sorting only
            if time_units is None:
                time_units = self.outputs['phases'][phase_name]['indep'][
                    'time']['units']
            times[phase_name] = convert_units(
                self.outputs['phases'][phase_name]['indep']['time']['value'],
                self.outputs['phases'][phase_name]['indep']['time']['units'],
                time_units)
            times[phase_name][-1, ...] -= 1.0E-15

            if var == 'time':
                var_type = 'indep'
            elif var in self.outputs['phases'][phase_name]['states']:
                var_type = 'states'
            elif var in self.outputs['phases'][phase_name]['controls']:
                var_type = 'controls'
            elif var in self.outputs['phases'][phase_name][
                    'design_parameters']:
                var_type = 'design_parameters'
            elif var in self.outputs['phases'][phase_name]['input_parameters']:
                var_type = 'input_parameters'
            elif var.endswith('_rate') \
                    and var[:-5] in self.outputs['phases'][phase_name]['controls']:
                var_type = 'control_rates'
            elif var.endswith('_rate2') \
                    and var[:-6] in self.outputs['phases'][phase_name]['controls']:
                var_type = 'control_rates'
            elif var in self.outputs['phases'][phase_name]['ode']:
                var_type = 'ode'
            else:
                var_in_phase = False

            if var_in_phase:
                var_in_traj = True
                output = convert_units(
                    self.outputs['phases'][phase_name][var_type][var]['value'],
                    self.outputs['phases'][phase_name][var_type][var]['units'],
                    units)
            else:
                indep_var = list(
                    self.outputs['phases'][phase_name]['indep'].keys())[0]
                n = len(self.outputs['phases'][phase_name]['indep'][indep_var]
                        ['value'])
                output = np.empty(n)
                output[:] = np.nan

            if not var_in_traj:
                raise KeyError('Variable "{0}" not found in trajectory '
                               'simulation results.'.format(var))

            return_vals[phase_name] = output

        if flat:
            time_array = np.concatenate([times[pname] for pname in phases])
            sort_idxs = np.argsort(time_array, axis=0).ravel()
            return_vals = np.concatenate(
                [return_vals[pname] for pname in phases])[sort_idxs, ...]

        return return_vals
Esempio n. 16
0
def view_connections(root,
                     outfile='connections.html',
                     show_browser=True,
                     src_filter='',
                     tgt_filter='',
                     precision=6):
    """
    Generate a self-contained html file containing a detailed connection viewer.

    Optionally pops up a web browser to view the file.

    Parameters
    ----------
    root : system or Problem
        The root for the desired tree.

    outfile : str, optional
        The name of the output html file.  Defaults to 'connections.html'.

    show_browser : bool, optional
        If True, pop up a browser to view the generated html file.
        Defaults to True.

    src_filter : str, optional
        If defined, use this as the initial value for the source system filter.

    tgt_filter : str, optional
        If defined, use this as the initial value for the target system filter.

    precision : int, optional
        Sets the precision for displaying array values.
    """
    if MPI and MPI.COMM_WORLD.rank != 0:
        return

    # since people will be used to passing the Problem as the first arg to
    # the N2 diagram funct, allow them to pass a Problem here as well.
    if isinstance(root, Problem):
        system = root.model
    else:
        system = root

    input_srcs = system._conn_global_abs_in2out

    connections = {
        tgt: src
        for tgt, src in iteritems(input_srcs) if src is not None
    }

    src2tgts = defaultdict(list)
    units = {
        n: data.get('units', '')
        for n, data in iteritems(system._var_allprocs_abs2meta)
    }
    vals = {}

    with printoptions(precision=precision, suppress=True, threshold=10000):

        for t in system._var_abs_names['input']:
            tmeta = system._var_abs2meta[t]
            idxs = tmeta['src_indices']

            if t in connections:
                s = connections[t]
                val = _get_output(system, s, idxs)

                # if there's a unit conversion, express the value in the
                # units of the target
                if units[t] and val != "<on remote_proc>":
                    val = convert_units(val, units[s], units[t])

                src2tgts[s].append(t)
            else:  # unconnected param
                val = _get_input(system, t, None)

            if isinstance(val, np.ndarray):
                val = np.array2string(val)
            else:
                val = str(val)

            vals[t] = val

        noconn_srcs = sorted(
            (n for n in system._var_abs_names['output'] if n not in src2tgts),
            reverse=True)
        for s in noconn_srcs:
            vals[s] = str(system._outputs[s])

    vals['NO CONNECTION'] = ''

    src_systems = set()
    tgt_systems = set()
    for s in system._var_abs_names['output']:
        parts = s.split('.')
        for i in range(len(parts)):
            src_systems.add('.'.join(parts[:i]))

    for t in system._var_abs_names['input']:
        parts = t.split('.')
        for i in range(len(parts)):
            tgt_systems.add('.'.join(parts[:i]))

    # reverse sort so that "NO CONNECTION" shows up at the bottom
    src2tgts['NO CONNECTION'] = sorted(
        [t for t in system._var_abs_names['input'] if t not in connections],
        reverse=True)

    src_systems = [{'name': n} for n in sorted(src_systems)]
    src_systems.insert(1, {'name': "NO CONNECTION"})
    tgt_systems = [{'name': n} for n in sorted(tgt_systems)]
    tgt_systems.insert(1, {'name': "NO CONNECTION"})

    data = {
        'src2tgts': sorted(iteritems(src2tgts)),
        'proms': None,
        'units': units,
        'vals': vals,
        'src_systems': src_systems,
        'tgt_systems': tgt_systems,
        'noconn_srcs': noconn_srcs,
        'src_filter': src_filter,
        'tgt_filter': tgt_filter,
    }

    viewer = 'connect_table.html'

    code_dir = os.path.dirname(os.path.abspath(__file__))

    with open(os.path.join(code_dir, viewer), "r") as f:
        template = f.read()

    graphjson = json.dumps(data)

    with open(outfile, 'w') as f:
        s = template.replace("<connection_data>", graphjson)
        f.write(s)

    if show_browser:
        webview(outfile)
Esempio n. 17
0
def view_connections(root, outfile='connections.html', show_browser=True,
                     src_filter='', tgt_filter='', precision=6):
    """
    Generates a self-contained html file containing a detailed connection
    viewer.  Optionally pops up a web browser to view the file.

    Parameters
    ----------
    root : system or Problem
        The root for the desired tree.

    outfile : str, optional
        The name of the output html file.  Defaults to 'connections.html'.

    show_browser : bool, optional
        If True, pop up a browser to view the generated html file.
        Defaults to True.

    src_filter : str, optional
        If defined, use this as the initial value for the source system filter.

    tgt_filter : str, optional
        If defined, use this as the initial value for the target system filter.

    precision : int, optional
        Sets the precision for displaying array values.
    """
    # since people will be used to passing the Problem as the first arg to
    # the N2 diagram funct, allow them to pass a Problem here as well.
    if isinstance(root, Problem):
        system = root.model
    else:
        system = root

    input_srcs = system._conn_global_abs_in2out

    connections = {
        tgt: src for tgt, src in iteritems(input_srcs) if src is not None
    }

    src2tgts = {}
    units = {n: data.get('units','')
                for n, data in iteritems(system._var_allprocs_abs2meta)}
    vals = {}

    with printoptions(precision=precision, suppress=True, threshold=10000):

        for t in system._var_abs_names['input']:
            tmeta = system._var_abs2meta[t]
            idxs = tmeta['src_indices']
            flat = tmeta['flat_src_indices']
            if idxs is None:
                idxs = np.arange(tmeta['size'], dtype=int)

            if t in connections:
                s = connections[t]
                val = system._outputs[s]
                if isinstance(val, np.ndarray):
                    val = system._outputs[s].flatten()[idxs]
                else:
                    val = system._outputs[s]

                # if there's a unit conversion, express the value in the
                # units of the target
                if units[t]:
                    val = convert_units(val, units[s], units[t])

                if s not in src2tgts:
                    src2tgts[s] = [t]
                else:
                    src2tgts[s].append(t)
            else: # unconnected param
                val = system._inputs[t]

            if isinstance(val, np.ndarray):
                val = np.array2string(val)
            else:
                val = str(val)

            vals[t] = val

        noconn_srcs = sorted((n for n in system._var_abs_names['output']
                                if n not in src2tgts), reverse=True)
        for s in noconn_srcs:
            vals[s] = str(system._outputs[s])

    vals['NO CONNECTION'] = ''

    src_systems = set()
    tgt_systems = set()
    for s in system._var_abs_names['output']:
        parts = s.split('.')
        for i in range(len(parts)):
            src_systems.add('.'.join(parts[:i]))

    for t in system._var_abs_names['input']:
        parts = t.split('.')
        for i in range(len(parts)):
            tgt_systems.add('.'.join(parts[:i]))

    # reverse sort so that "NO CONNECTION" shows up at the bottom
    src2tgts['NO CONNECTION'] = sorted([t for t in system._var_abs_names['input']
                                    if t not in connections], reverse=True)

    src_systems = [{'name':n} for n in sorted(src_systems)]
    src_systems.insert(1, {'name': "NO CONNECTION"})
    tgt_systems = [{'name':n} for n in sorted(tgt_systems)]
    tgt_systems.insert(1, {'name': "NO CONNECTION"})

    data = {
        'src2tgts': sorted(iteritems(src2tgts)),
        'proms': None,
        'units': units,
        'vals': vals,
        'src_systems': src_systems,
        'tgt_systems': tgt_systems,
        'noconn_srcs': noconn_srcs,
        'src_filter': src_filter,
        'tgt_filter': tgt_filter,
    }

    viewer = 'connect_table.html'

    code_dir = os.path.dirname(os.path.abspath(__file__))

    with open(os.path.join(code_dir, viewer), "r") as f:
        template = f.read()

    graphjson = json.dumps(data)

    with open(outfile, 'w') as f:
        s = template.replace("<connection_data>", graphjson)
        f.write(s)

    if show_browser:
        webview(outfile)
Esempio n. 18
0
    def get_values(self, var, nodes=None, units=None):
        """
        Retrieve the values of the given variable at the given
        subset of nodes.

        Parameters
        ----------
        var : str
            The variable whose values are to be returned.  This may be
            the name 'time', the name of a state, control, or parameter,
            or the path to a variable in the ODEFunction of the phase.
        nodes : str
            The name of the node subset or None (default).
        units : str
            The units in which the values should be expressed.  Must be compatible
            with the corresponding units inside the phase.

        Returns
        -------
        ndarray
            An array of the values at the requested node subset.  The
            node index is the first dimension of the ndarray.
        """
        if nodes is None:
            nodes = 'all'

        gd = self.grid_data
        disc_node_idxs = gd.subset_node_indices['state_disc']
        col_node_idxs = gd.subset_node_indices['col']

        var_type = self._classify_var(var)

        op = dict(
            self.list_outputs(explicit=True,
                              values=True,
                              units=True,
                              shape=True,
                              out_stream=None))

        if units is not None:
            if not valid_units(units):
                raise ValueError(
                    'Units {0} is not a valid units identifier'.format(units))

        var_prefix = '{0}.'.format(self.pathname) if self.pathname else ''

        path_map = {
            'time': 'time.{0}',
            'state': ('indep_states.states:{0}', 'state_interp.state_col:{0}'),
            'indep_control': 'control_interp_comp.control_values:{0}',
            'input_control': 'control_interp_comp.control_values:{0}',
            'design_parameter': 'design_params.design_parameters:{0}',
            'input_parameter': 'input_params.input_parameters:{0}_out',
            'control_rate': 'control_interp_comp.control_rates:{0}',
            'control_rate2': 'control_interp_comp.control_rates:{0}',
            'ode': ('rhs_disc.{0}', 'rhs_col.{0}')
        }

        if var_type == 'state':
            # State and RHS values need to be interleaved since disc and col values are not
            # available from the same output
            disc_path_fmt, col_path_fmt = path_map[var_type]
            disc_path = var_prefix + disc_path_fmt.format(var)
            col_path = var_prefix + col_path_fmt.format(var)

            state_shape = op[disc_path]['shape'][1:]
            disc_units = op[disc_path]['units']
            disc_vals = op[disc_path]['value']
            col_units = op[col_path]['units']
            col_vals = op[col_path]['value']

            # If units is none, use the units from the IndepVarComp
            if units is None:
                units = disc_units

            output_value = np.zeros((gd.num_nodes, ) + state_shape)
            output_value[disc_node_idxs, ...] = \
                convert_units(disc_vals[gd.input_maps['state_input_to_disc'], ...],
                              disc_units, units)
            output_value[col_node_idxs,
                         ...] = convert_units(col_vals, col_units, units)

        elif var_type in ('indep_control', 'input_control'):
            var_path = var_prefix + path_map[var_type].format(var)
            output_units = op[var_path]['units']

            vals = op[var_path]['value']
            output_value = convert_units(vals, output_units, units)

        elif var_type in ('design_parameter', 'input_parameter',
                          'traj_design_parameter', 'traj_input_parameter'):
            var_path = var_prefix + path_map[var_type].format(var)
            output_units = op[var_path]['units']

            output_value = convert_units(op[var_path]['value'], output_units,
                                         units)
            output_value = np.repeat(output_value, gd.num_nodes, axis=0)

        elif var_type == 'ode':
            rhs_disc_outputs = dict(
                self.rhs_disc.list_outputs(out_stream=None,
                                           values=True,
                                           shape=True,
                                           units=True))
            rhs_col_outputs = dict(
                self.rhs_col.list_outputs(out_stream=None,
                                          values=True,
                                          shape=True,
                                          units=True))

            prom2abs_disc = self.rhs_disc._var_allprocs_prom2abs_list
            prom2abs_col = self.rhs_col._var_allprocs_prom2abs_list

            # Is var in prom2abs_disc['output']?
            abs_path_disc = prom2abs_disc['output'][var][0]
            abs_path_col = prom2abs_col['output'][var][0]

            shape = rhs_disc_outputs[abs_path_disc]['shape'][1:]
            disc_units = rhs_disc_outputs[abs_path_disc]['units']
            col_units = rhs_col_outputs[abs_path_col]['units']

            output_value = np.zeros((gd.num_nodes, ) + shape)

            disc_vals = rhs_disc_outputs[abs_path_disc]['value']
            col_vals = rhs_col_outputs[abs_path_col]['value']

            output_value[disc_node_idxs,
                         ...] = convert_units(disc_vals, disc_units, units)
            output_value[col_node_idxs,
                         ...] = convert_units(col_vals, col_units, units)

        else:
            var_path = var_prefix + path_map[var_type].format(var)
            output_units = op[var_path]['units']
            output_value = convert_units(op[var_path]['value'], output_units,
                                         units)

        # Always return a column vector
        if len(output_value.shape) == 1:
            output_value = np.reshape(output_value, (gd.num_nodes, 1))

        return output_value[gd.subset_node_indices[nodes], ...]