Source code for openmdao.jacobians.dictionary_jacobian

"""Define the DictionaryJacobian class."""
from __future__ import division

import numpy as np
from six.moves import range
from scipy.sparse import csc_matrix

from openmdao.jacobians.jacobian import Jacobian


_full_slice = slice(None)


[docs]class DictionaryJacobian(Jacobian): """ No global <Jacobian>; use dictionary of user-supplied sub-Jacobians. Attributes ---------- _iter_keys : list of (vname, vname) tuples List of tuples of variable names that match subjacs in the this Jacobian. """
[docs] def __init__(self, system, **kwargs): """ Initialize all attributes. Parameters ---------- system : System Parent system to this jacobian. **kwargs : dict options dictionary. """ super(DictionaryJacobian, self).__init__(system, **kwargs) self._iter_keys = {}
def _iter_abs_keys(self, system, vec_name): """ Iterate over subjacs keyed by absolute names. This includes only subjacs that have been set and are part of the current system. Parameters ---------- system : System System that is updating this jacobian. vec_name : str The name of the current RHS vector. Returns ------- list List of keys matching this jacobian for the current system. """ entry = (system.pathname, vec_name) if entry not in self._iter_keys: ncol = system._vectors['residual'][vec_name]._ncol subjacs = self._subjacs_info keys = [] for res_name in system._var_relevant_names[vec_name]['output']: for type_ in ('output', 'input'): for name in system._var_relevant_names[vec_name][type_]: key = (res_name, name) if key in subjacs: keys.append(key) self._iter_keys[entry] = keys return self._iter_keys[entry] def _apply(self, system, d_inputs, d_outputs, d_residuals, mode): """ Compute matrix-vector product. Parameters ---------- system : System System that is updating this jacobian. d_inputs : Vector inputs linear vector. d_outputs : Vector outputs linear vector. d_residuals : Vector residuals linear vector. mode : str 'fwd' or 'rev'. """ # avoid circular import from openmdao.core.explicitcomponent import ExplicitComponent fwd = mode == 'fwd' d_res_names = d_residuals._names d_out_names = d_outputs._names d_inp_names = d_inputs._names if not d_out_names and not d_inp_names: return rflat = d_residuals._views_flat oflat = d_outputs._views_flat iflat = d_inputs._views_flat ncol = d_residuals._ncol subjacs_info = self._subjacs_info is_explicit = isinstance(system, ExplicitComponent) with system._unscaled_context(outputs=[d_outputs], residuals=[d_residuals]): for abs_key in self._iter_abs_keys(system, d_residuals._name): subjac_info = subjacs_info[abs_key] if self._randomize: subjac = self._randomize_subjac(subjac_info['value'], abs_key) else: subjac = subjac_info['value'] res_name, other_name = abs_key if res_name in d_res_names: if other_name in d_out_names: # skip the matvec mult completely for identity subjacs if is_explicit and res_name is other_name: if fwd: rflat[res_name] -= oflat[other_name] else: oflat[other_name] -= rflat[res_name] continue if fwd: left_vec = rflat[res_name] right_vec = oflat[other_name] else: left_vec = oflat[other_name] right_vec = rflat[res_name] elif other_name in d_inp_names: if fwd: left_vec = rflat[res_name] right_vec = iflat[other_name] else: left_vec = iflat[other_name] right_vec = rflat[res_name] else: continue rows = subjac_info['rows'] if rows is not None: # our homegrown COO format linds, rinds = rows, subjac_info['cols'] if not fwd: linds, rinds = rinds, linds if self._under_complex_step: # bincount only works with float, so split into parts if ncol > 1: for i in range(ncol): prod = right_vec[:, i][rinds] * subjac left_vec[:, i].real += np.bincount(linds, prod.real, minlength=left_vec.shape[0]) left_vec[:, i].imag += np.bincount(linds, prod.imag, minlength=left_vec.shape[0]) else: prod = right_vec[rinds] * subjac left_vec[:].real += np.bincount(linds, prod.real, minlength=left_vec.size) left_vec[:].imag += np.bincount(linds, prod.imag, minlength=left_vec.size) else: if ncol > 1: for i in range(ncol): left_vec[:, i] += np.bincount(linds, right_vec[:, i][rinds] * subjac, minlength=left_vec.shape[0]) else: left_vec[:] += np.bincount(linds, right_vec[rinds] * subjac, minlength=left_vec.size) else: if not fwd: subjac = subjac.transpose() left_vec += subjac.dot(right_vec)