def _configure(self): """ Configure this system to assign children settings. Also tag component if it provides a guess_nonlinear. """ self._has_guess = overrides_method('guess_nonlinear', self, ImplicitComponent) new_apply_linear = getattr(self, 'apply_linear', None) new_apply_multi_linear = getattr(self, 'apply_multi_linear', None) new_solve_multi_linear = getattr(self, 'solve_multi_linear', None) self.matrix_free = (overrides_method('apply_linear', self, ImplicitComponent) or (new_apply_linear is not None and self._inst_functs['apply_linear'] != new_apply_linear)) self.has_apply_multi_linear = (overrides_method('apply_multi_linear', self, ImplicitComponent) or (new_apply_multi_linear is not None and self._inst_functs['apply_multi_linear'] != new_apply_multi_linear)) self.has_solve_multi_linear = (overrides_method('solve_multi_linear', self, ImplicitComponent) or (new_solve_multi_linear is not None and self._inst_functs['solve_multi_linear'] != new_solve_multi_linear)) self.supports_multivecs = self.has_apply_multi_linear or self.has_solve_multi_linear self.matrix_free |= self.has_apply_multi_linear
def _configure(self): """ Configure this system to assign children settings. Also tag component if it provides a guess_nonlinear. """ self._has_guess = overrides_method('guess_nonlinear', self, ImplicitComponent) new_apply_linear = getattr(self, 'apply_linear', None) new_apply_multi_linear = getattr(self, 'apply_multi_linear', None) new_solve_multi_linear = getattr(self, 'solve_multi_linear', None) self.matrix_free = (overrides_method('apply_linear', self, ImplicitComponent) or (new_apply_linear is not None and self._inst_functs['apply_linear'] != new_apply_linear)) self.has_apply_multi_linear = (overrides_method('apply_multi_linear', self, ImplicitComponent) or (new_apply_multi_linear is not None and self._inst_functs['apply_multi_linear'] != new_apply_multi_linear)) self.has_solve_multi_linear = (overrides_method('solve_multi_linear', self, ImplicitComponent) or (new_solve_multi_linear is not None and self._inst_functs['solve_multi_linear'] != new_solve_multi_linear)) self.supports_multivecs = self.has_apply_multi_linear or self.has_solve_multi_linear self.matrix_free |= self.has_apply_multi_linear
def compute(self, inputs, outputs): """ Predict outputs. If the training flag is set, train the metamodel first. Parameters ---------- inputs : Vector unscaled, dimensional input variables read via inputs[key] outputs : Vector unscaled, dimensional output variables read via outputs[key] """ if self.train: # train first self._train() # predict for current inputs if self._vectorize is None: inputs = self._vec_to_array(inputs) else: inputs = self._vec_to_array2d(inputs) for name, shape in self._surrogate_output_names: surrogate = self._metadata(name).get('surrogate') if surrogate is None: raise RuntimeError( "Metamodel '%s': No surrogate specified for output '%s'" % (self.pathname, name)) else: if self._vectorize is None: # one input, one prediction predicted = surrogate.predict(inputs) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, outputs[name].shape) elif overrides_method('vectorized_predict', surrogate, SurrogateModel): # multiple inputs flattened, one prediction of multiple outputs predicted = surrogate.vectorized_predict(inputs.flat) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, outputs[name].shape) else: # multiple inputs, multiple predictions if isinstance(shape, tuple): output_shape = (self._vectorize, ) + shape else: output_shape = (self._vectorize, ) predicted = np.zeros(output_shape) rmse = self._metadata(name)['rmse'] = [] for i in range(self._vectorize): pred_i = surrogate.predict(inputs[i]) predicted[i] = np.reshape(pred_i, shape) if isinstance(predicted[i], tuple): # rmse option rmse.append(predicted[i][1]) predicted[i] = predicted[i][0] outputs[name] = np.reshape(predicted, output_shape)
def _configure(self): """ Configure this system to assign children settings and detect if matrix_free. """ new_jacvec_prod = getattr(self, 'compute_jacvec_product', None) new_multi_jacvec_prod = getattr(self, 'compute_multi_jacvec_product', None) self.supports_multivecs = (overrides_method('compute_multi_jacvec_product', self, ExplicitComponent) or (new_multi_jacvec_prod is not None and new_multi_jacvec_prod != self._inst_functs['compute_multi_jacvec_product'])) self.matrix_free = self.supports_multivecs or ( overrides_method('compute_jacvec_product', self, ExplicitComponent) or (new_jacvec_prod is not None and new_jacvec_prod != self._inst_functs['compute_jacvec_product']))
def _configure(self): """ Configure this system to assign children settings and detect if matrix_free. """ new_jacvec_prod = getattr(self, 'compute_jacvec_product', None) new_multi_jacvec_prod = getattr(self, 'compute_multi_jacvec_product', None) self.supports_multivecs = (overrides_method('compute_multi_jacvec_product', self, ExplicitComponent) or (new_multi_jacvec_prod is not None and new_multi_jacvec_prod != self._inst_functs['compute_multi_jacvec_product'])) self.matrix_free = self.supports_multivecs or ( overrides_method('compute_jacvec_product', self, ExplicitComponent) or (new_jacvec_prod is not None and new_jacvec_prod != self._inst_functs['compute_jacvec_product']))
def __init__(self, **kwargs): """ Store some bound methods so we can detect runtime overrides. """ super().__init__(**kwargs) self._inst_functs = {name: getattr(self, name, None) for name in _inst_functs} self._has_compute_partials = overrides_method('compute_partials', self, ExplicitComponent) self.options.undeclare('assembled_jac_type')
def compute(self, inputs, outputs): """ Predict outputs. If the training flag is set, train the metamodel first. Parameters ---------- inputs : Vector unscaled, dimensional input variables read via inputs[key] outputs : Vector unscaled, dimensional output variables read via outputs[key] """ if self.train: # train first self._train() # predict for current inputs if self._vectorize is None: inputs = self._vec_to_array(inputs) else: inputs = self._vec_to_array2d(inputs) for name, shape in self._surrogate_output_names: surrogate = self._metadata(name).get('surrogate') if surrogate is None: raise RuntimeError("Metamodel '%s': No surrogate specified for output '%s'" % (self.pathname, name)) else: if self._vectorize is None: # one input, one prediction predicted = surrogate.predict(inputs) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, outputs[name].shape) elif overrides_method('vectorized_predict', surrogate, SurrogateModel): # multiple inputs flattened, one prediction of multiple outputs predicted = surrogate.vectorized_predict(inputs.flat) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, outputs[name].shape) else: # multiple inputs, multiple predictions if isinstance(shape, tuple): output_shape = (self._vectorize,) + shape else: output_shape = (self._vectorize,) predicted = np.zeros(output_shape) rmse = self._metadata(name)['rmse'] = [] for i in range(self._vectorize): pred_i = surrogate.predict(inputs[i]) predicted[i] = np.reshape(pred_i, shape) if isinstance(predicted[i], tuple): # rmse option rmse.append(predicted[i][1]) predicted[i] = predicted[i][0] outputs[name] = np.reshape(predicted, output_shape)
def compute_partials(self, inputs, partials): """ Compute sub-jacobian parts. The model is assumed to be in an unscaled state. Parameters ---------- inputs : Vector unscaled, dimensional input variables read via inputs[key] partials : Jacobian sub-jac components written to partials[output_name, input_name] """ vec_size = self.options['vec_size'] if vec_size > 1: flat_inputs = self._vec_to_array_vectorized(inputs) else: flat_inputs = self._vec_to_array(inputs) for out_name, out_shape in self._surrogate_output_names: surrogate = self._metadata(out_name).get('surrogate') if vec_size > 1: out_size = np.prod(out_shape) for j in range(vec_size): flat_input = flat_inputs[j] if overrides_method('linearize', surrogate, SurrogateModel): derivs = surrogate.linearize(flat_input) idx = 0 for in_name, sz in self._surrogate_input_names: j1 = j * out_size * sz j2 = j1 + out_size * sz partials[out_name, in_name][j1:j2] = derivs[:, idx:idx + sz].flat idx += sz else: if overrides_method('linearize', surrogate, SurrogateModel): sjac = surrogate.linearize(flat_inputs) idx = 0 for in_name, sz in self._surrogate_input_names: partials[(out_name, in_name)] = sjac[:, idx:idx + sz] idx += sz
def _configure(self): """ Configure this system to assign children settings. Also tag component if it provides a guess_nonlinear. """ new_apply_linear = getattr(self, 'apply_linear', None) self.matrix_free = (overrides_method('apply_linear', self, Component) or (new_apply_linear is not None and new_apply_linear != self._initial_apply_linear))
def compute_partials(self, inputs, partials): """ Compute sub-jacobian parts. The model is assumed to be in an unscaled state. Parameters ---------- inputs : Vector unscaled, dimensional input variables read via inputs[key] partials : Jacobian sub-jac components written to partials[output_name, input_name] """ vec_size = self.options['vec_size'] if vec_size > 1: flat_inputs = self._vec_to_array_vectorized(inputs) else: flat_inputs = self._vec_to_array(inputs) for out_name, out_shape in self._surrogate_output_names: surrogate = self._metadata(out_name).get('surrogate') if vec_size > 1: out_size = np.prod(out_shape) for j in range(vec_size): flat_input = flat_inputs[j] if overrides_method('linearize', surrogate, SurrogateModel): derivs = surrogate.linearize(flat_input) idx = 0 for in_name, sz in self._surrogate_input_names: j1 = j * out_size * sz j2 = j1 + out_size * sz partials[out_name, in_name][j1:j2] = derivs[:, idx:idx + sz].flat idx += sz else: if overrides_method('linearize', surrogate, SurrogateModel): sjac = surrogate.linearize(flat_inputs) idx = 0 for in_name, sz in self._surrogate_input_names: partials[(out_name, in_name)] = sjac[:, idx:idx + sz] idx += sz
def __init__(self, **kwargs): """ Store some bound methods so we can detect runtime overrides. Parameters ---------- **kwargs : dict of keyword arguments available here and in all descendants of this system. """ super(ExplicitComponent, self).__init__(**kwargs) self._inst_functs = {name: getattr(self, name, None) for name in _inst_functs} self._has_compute_partials = overrides_method('compute_partials', self, ExplicitComponent)
def __init__(self, **kwargs): """ Store some bound methods so we can detect runtime overrides. Parameters ---------- **kwargs : dict of keyword arguments Keyword arguments that will be mapped into the Component options. """ super(ExplicitComponent, self).__init__(**kwargs) self._inst_functs = {name: getattr(self, name, None) for name in _inst_functs} self._has_compute_partials = overrides_method('compute_partials', self, ExplicitComponent)
def __init__(self, **kwargs): """ Store some bound methods so we can detect runtime overrides. Parameters ---------- **kwargs : dict of keyword arguments available here and in all descendants of this system. """ super(ExplicitComponent, self).__init__(**kwargs) self._inst_functs = {name: getattr(self, name, None) for name in _inst_functs} self._has_compute_partials = overrides_method('compute_partials', self, ExplicitComponent)
def __init__(self, **kwargs): """ Store some bound methods so we can detect runtime overrides. Parameters ---------- **kwargs : dict of keyword arguments Keyword arguments that will be mapped into the Component options. """ super(ExplicitComponent, self).__init__(**kwargs) self._inst_functs = {name: getattr(self, name, None) for name in _inst_functs} self._has_compute_partials = overrides_method('compute_partials', self, ExplicitComponent) self.options.undeclare('assembled_jac_type')
def sys_recurse(system, all_states): subs = system._subsystems_myproc if len(subs) == 0: # Skip implicit components that appear to solve themselves. from openmdao.core.implicitcomponent import ImplicitComponent if overrides_method('solve_nonlinear', system, ImplicitComponent): return all_states.extend(system._list_states()) else: for subsys in subs: sub_nl = subsys.nonlinear_solver if sub_nl and sub_nl.supports['implicit_components']: continue sys_recurse(subsys, all_states)
def sys_recurse(system, all_states): subs = system._subsystems_myproc if len(subs) == 0: # Skip implicit components that appear to solve themselves. from openmdao.core.implicitcomponent import ImplicitComponent if overrides_method('solve_nonlinear', system, ImplicitComponent): return all_states.extend(system._list_states()) else: for subsys in subs: sub_nl = subsys.nonlinear_solver if sub_nl and sub_nl.supports['implicit_components']: continue sys_recurse(subsys, all_states)
def _setup_partials(self, recurse=True): """ Process all partials and approximations that the user declared. Metamodel needs to declare its partials after inputs and outputs are known. Parameters ---------- recurse : bool Whether to call this method in subsystems. """ super(MetaModelUnStructuredComp, self)._setup_partials() vec_size = self.options['vec_size'] if vec_size > 1: # Sparse specification of partials for vectorized models. for wrt, n_wrt in self._surrogate_input_names: for of, shape_of in self._surrogate_output_names: n_of = np.prod(shape_of) rows = np.repeat(np.arange(n_of), n_wrt) cols = np.tile(np.arange(n_wrt), n_of) nnz = len(rows) rows = np.tile(rows, vec_size) + np.repeat( np.arange(vec_size), nnz) * n_of cols = np.tile(cols, vec_size) + np.repeat( np.arange(vec_size), nnz) * n_wrt self._declare_partials(of=of, wrt=wrt, rows=rows, cols=cols) else: # Dense specification of partials for non-vectorized models. self._declare_partials( of=[name[0] for name in self._surrogate_output_names], wrt=[name[0] for name in self._surrogate_input_names]) # warn the user that if they don't explicitly set options for fd, # the defaults will be used # get a list of approximated partials declared_partials = set() for of, wrt, method, fd_options in self._approximated_partials: pattern_matches = self._find_partial_matches(of, wrt) for of_bundle, wrt_bundle in product(*pattern_matches): of_pattern, of_matches = of_bundle wrt_pattern, wrt_matches = wrt_bundle for rel_key in product(of_matches, wrt_matches): abs_key = rel_key2abs_key(self, rel_key) declared_partials.add(abs_key) non_declared_partials = [] for of, n_of in self._surrogate_output_names: has_derivs = False surrogate = self._metadata(of).get('surrogate') if surrogate: has_derivs = overrides_method('linearize', surrogate, SurrogateModel) if not has_derivs: for wrt, n_wrt in self._surrogate_input_names: abs_key = rel_key2abs_key(self, (of, wrt)) if abs_key not in declared_partials: non_declared_partials.append(abs_key) if non_declared_partials: msg = "Because the MetaModelUnStructuredComp '{}' uses a surrogate " \ "which does not define a linearize method,\nOpenMDAO will use " \ "finite differences to compute derivatives. Some of the derivatives " \ "will be computed\nusing default finite difference " \ "options because they were not explicitly declared.\n".format(self.name) msg += "The derivatives computed using the defaults are:\n" for abs_key in non_declared_partials: msg += " {}, {}\n".format(*abs_key) simple_warning(msg, RuntimeWarning) for out_name, out_shape in self._surrogate_output_names: surrogate = self._metadata(out_name).get('surrogate') if surrogate and not overrides_method('linearize', surrogate, SurrogateModel): self._approx_partials( of=out_name, wrt=[name[0] for name in self._surrogate_input_names], method='fd') if "fd" not in self._approx_schemes: self._approx_schemes['fd'] = FiniteDifference()
def _get_tree_dict(system, component_execution_orders, component_execution_index, is_parallel=False): """Get a dictionary representation of the system hierarchy.""" tree_dict = OrderedDict() tree_dict['name'] = system.name tree_dict['type'] = 'subsystem' if not isinstance(system, Group): tree_dict['subsystem_type'] = 'component' tree_dict['is_parallel'] = is_parallel if isinstance(system, ImplicitComponent): tree_dict['component_type'] = 'implicit' elif isinstance(system, ExecComp): tree_dict['component_type'] = 'exec' elif isinstance(system, (MetaModelStructuredComp, MetaModelUnStructuredComp)): tree_dict['component_type'] = 'metamodel' elif isinstance(system, IndepVarComp): tree_dict['component_type'] = 'indep' elif isinstance(system, ExplicitComponent): tree_dict['component_type'] = 'explicit' else: tree_dict['component_type'] = None component_execution_orders[ system.pathname] = component_execution_index[0] component_execution_index[0] += 1 children = [] for typ in ['input', 'output']: for abs_name in system._var_abs_names[typ]: children.append(_get_var_dict(system, typ, abs_name)) for prom_name in system._var_discrete[typ]: children.append(_get_var_dict(system, typ, prom_name)) else: if isinstance(system, ParallelGroup): is_parallel = True tree_dict['component_type'] = None tree_dict['subsystem_type'] = 'group' tree_dict['is_parallel'] = is_parallel children = [ _get_tree_dict(s, component_execution_orders, component_execution_index, is_parallel) for s in system._subsystems_myproc ] if system.comm.size > 1: if system._subsystems_myproc: sub_comm = system._subsystems_myproc[0].comm if sub_comm.rank != 0: children = [] children_lists = system.comm.allgather(children) children = [] for children_list in children_lists: children.extend(children_list) if isinstance(system, ImplicitComponent): if overrides_method('solve_linear', system, ImplicitComponent): tree_dict['linear_solver'] = "solve_linear" else: tree_dict['linear_solver'] = "" if overrides_method('solve_nonlinear', system, ImplicitComponent): tree_dict['nonlinear_solver'] = "solve_nonlinear" else: tree_dict['nonlinear_solver'] = "" else: if system.linear_solver: tree_dict['linear_solver'] = system.linear_solver.SOLVER else: tree_dict['linear_solver'] = "" if system.nonlinear_solver: tree_dict['nonlinear_solver'] = system.nonlinear_solver.SOLVER else: tree_dict['nonlinear_solver'] = "" tree_dict['children'] = children if not tree_dict['name']: tree_dict['name'] = 'root' tree_dict['type'] = 'root' return tree_dict
def _check_solvers(problem, logger): """ Search over all solvers and raise an error for unsupported configurations. Report any implicit component that does not implement solve_nonlinear and solve_linear or have an iterative nonlinear and linear solver upstream of it. Report any cycles that do not have an iterative nonlinear solver and either an iterative linear solver or a DirectSolver upstream of it. Parameters ---------- problem : <Problem> The problem being checked. logger : object The object that manages logging output. """ iter_nl_depth = iter_ln_depth = np.inf for sys in problem.model.system_iter(include_self=True, recurse=True): path = sys.pathname depth = 0 if path == '' else len(path.split('.')) # if this system is below both a nonlinear and linear solver, then skip checks if (depth > iter_nl_depth) and (depth > iter_ln_depth): continue # determine if this system is a group and has cycles if isinstance(sys, Group): graph = sys.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) sub2i = {sub.name: i for i, sub in enumerate(sys._subsystems_allprocs)} has_cycles = [sorted(s, key=lambda n: sub2i[n]) for s in sccs if len(s) > 1] else: has_cycles = [] # determine if this system has states (is an implicit component) has_states = isinstance(sys, ImplicitComponent) # determine if this system has iterative solvers or implements the solve methods # for handling cycles and implicit components if depth > iter_nl_depth: is_iter_nl = True else: is_iter_nl = ( (sys.nonlinear_solver and 'maxiter' in sys.nonlinear_solver.options) or (has_states and overrides_method('solve_nonlinear', sys, ImplicitComponent)) ) iter_nl_depth = depth if is_iter_nl else np.inf if depth > iter_ln_depth: is_iter_ln = True else: is_iter_ln = ( (sys.linear_solver and ('maxiter' in sys.linear_solver.options or isinstance(sys.linear_solver, DirectSolver))) or (has_states and overrides_method('solve_linear', sys, ImplicitComponent)) ) iter_ln_depth = depth if is_iter_ln else np.inf # if there are cycles, then check for iterative nonlinear and linear solvers if has_cycles: if not is_iter_nl: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "nonlinear solver." % (path, has_cycles)) logger.warning(msg) if not is_iter_ln: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "linear solver." % (path, has_cycles)) logger.warning(msg) # if there are implicit components, check for iterative solvers or the appropriate # solve methods if has_states: if not is_iter_nl: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative nonlinear solver and does not implement 'solve_nonlinear'." % (sys.__class__.__name__, path)) logger.warning(msg) if not is_iter_ln: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative linear solver and does not implement 'solve_linear'." % (sys.__class__.__name__, path)) logger.warning(msg)
def _check_solvers(problem, logger): """ Search over all solvers and raise an error for unsupported configurations. Report any implicit component that does not implement solve_nonlinear and solve_linear or have an iterative nonlinear and linear solver upstream of it. Report any cycles that do not have an iterative nonlinear solver and either an iterative linear solver or a DirectSolver upstream of it. Parameters ---------- problem : <Problem> The problem being checked. logger : object The object that manages logging output. """ iter_nl_depth = iter_ln_depth = np.inf for sys in problem.model.system_iter(include_self=True, recurse=True): path = sys.pathname depth = 0 if path == '' else len(path.split('.')) # if this system is below both a nonlinear and linear solver, then skip checks if (depth > iter_nl_depth) and (depth > iter_ln_depth): continue # determine if this system is a group and has cycles if isinstance(sys, Group): graph = sys.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) allsubs = sys._subsystems_allprocs has_cycles = [sorted(s, key=lambda n: allsubs[n].index) for s in sccs if len(s) > 1] else: has_cycles = [] # determine if this system has states (is an implicit component) has_states = isinstance(sys, ImplicitComponent) # determine if this system has iterative solvers or implements the solve methods # for handling cycles and implicit components if depth > iter_nl_depth: is_iter_nl = True else: is_iter_nl = ( (sys.nonlinear_solver and 'maxiter' in sys.nonlinear_solver.options) or (has_states and overrides_method('solve_nonlinear', sys, ImplicitComponent)) ) iter_nl_depth = depth if is_iter_nl else np.inf if depth > iter_ln_depth: is_iter_ln = True else: is_iter_ln = ( (sys.linear_solver and ('maxiter' in sys.linear_solver.options or isinstance(sys.linear_solver, DirectSolver))) or (has_states and overrides_method('solve_linear', sys, ImplicitComponent)) ) iter_ln_depth = depth if is_iter_ln else np.inf # if there are cycles, then check for iterative nonlinear and linear solvers if has_cycles: if not is_iter_nl: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "nonlinear solver." % (path, has_cycles)) logger.warning(msg) if not is_iter_ln: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "linear solver." % (path, has_cycles)) logger.warning(msg) # if there are implicit components, check for iterative solvers or the appropriate # solve methods if has_states: if not is_iter_nl: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative nonlinear solver and does not implement 'solve_nonlinear'." % (sys.__class__.__name__, path)) logger.warning(msg) if not is_iter_ln: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative linear solver and does not implement 'solve_linear'." % (sys.__class__.__name__, path)) logger.warning(msg)
def _setup_partials(self, recurse=True): """ Process all partials and approximations that the user declared. Metamodel needs to declare its partials after inputs and outputs are known. Parameters ---------- recurse : bool Whether to call this method in subsystems. """ super(MetaModelUnStructuredComp, self)._setup_partials() vec_size = self.options['vec_size'] if vec_size > 1: vec_arange = np.arange(vec_size) # Sparse specification of partials for vectorized models. for wrt, n_wrt in self._surrogate_input_names: for of, shape_of in self._surrogate_output_names: n_of = np.prod(shape_of) rows = np.repeat(np.arange(n_of), n_wrt) cols = np.tile(np.arange(n_wrt), n_of) repeat = np.repeat(vec_arange, len(rows)) rows = np.tile(rows, vec_size) + repeat * n_of cols = np.tile(cols, vec_size) + repeat * n_wrt dct = { 'rows': rows, 'cols': cols, 'dependent': True, } self._declare_partials(of=of, wrt=wrt, dct=dct) else: dct = { 'value': None, 'dependent': True, } # Dense specification of partials for non-vectorized models. self._declare_partials( of=tuple([name[0] for name in self._surrogate_output_names]), wrt=tuple([name[0] for name in self._surrogate_input_names]), dct=dct) # warn the user that if they don't explicitly set options for fd, # the defaults will be used # get a list of approximated partials declared_partials = set([ key for key, dct in iteritems(self._subjacs_info) if 'method' in dct and dct['method'] ]) non_declared_partials = [] for of, n_of in self._surrogate_output_names: has_derivs = False surrogate = self._metadata(of).get('surrogate') if surrogate: has_derivs = overrides_method('linearize', surrogate, SurrogateModel) if not has_derivs: for wrt, n_wrt in self._surrogate_input_names: abs_key = rel_key2abs_key(self, (of, wrt)) if abs_key not in declared_partials: non_declared_partials.append(abs_key) if non_declared_partials: msg = "Because the MetaModelUnStructuredComp '{}' uses a surrogate " \ "which does not define a linearize method,\nOpenMDAO will use " \ "finite differences to compute derivatives. Some of the derivatives " \ "will be computed\nusing default finite difference " \ "options because they were not explicitly declared.\n".format(self.name) msg += "The derivatives computed using the defaults are:\n" for abs_key in non_declared_partials: msg += " {}, {}\n".format(*abs_key) simple_warning(msg, RuntimeWarning) for out_name, out_shape in self._surrogate_output_names: surrogate = self._metadata(out_name).get('surrogate') if surrogate and not overrides_method('linearize', surrogate, SurrogateModel): self._approx_partials( of=out_name, wrt=[name[0] for name in self._surrogate_input_names], method='fd') self._get_approx_scheme('fd')
def _setup_partials(self): """ Process all partials and approximations that the user declared. Metamodel needs to declare its partials after inputs and outputs are known. """ super()._setup_partials() vec_size = self.options['vec_size'] if vec_size > 1: vec_arange = np.arange(vec_size) # Sparse specification of partials for vectorized models. for wrt, n_wrt in self._surrogate_input_names: for of, shape_of in self._surrogate_output_names: n_of = np.prod(shape_of) rows = np.repeat(np.arange(n_of), n_wrt) cols = np.tile(np.arange(n_wrt), n_of) repeat = np.repeat(vec_arange, len(rows)) rows = np.tile(rows, vec_size) + repeat * n_of cols = np.tile(cols, vec_size) + repeat * n_wrt dct = { 'rows': rows, 'cols': cols, 'dependent': True, } self._declare_partials(of=of, wrt=wrt, dct=dct) else: dct = { 'value': None, 'dependent': True, } # Dense specification of partials for non-vectorized models. self._declare_partials( of=tuple([name[0] for name in self._surrogate_output_names]), wrt=tuple([name[0] for name in self._surrogate_input_names]), dct=dct) # Support for user declaring fd partials in a child class and assigning new defaults. # We want a warning for all partials that were not explicitly declared. declared_partials = set([ key for key, dct in self._subjacs_info.items() if 'method' in dct and dct['method'] ]) # Gather undeclared fd partials on surrogates that don't support analytic derivatives. # While we do this, declare the missing ones. non_declared_partials = [] for of, _ in self._surrogate_output_names: surrogate = self._metadata(of).get('surrogate') if surrogate and not overrides_method('linearize', surrogate, SurrogateModel): wrt_list = [name[0] for name in self._surrogate_input_names] self._approx_partials(of=of, wrt=wrt_list, method='fd') for wrt in wrt_list: abs_key = rel_key2abs_key(self, (of, wrt)) if abs_key not in declared_partials: non_declared_partials.append(abs_key) if non_declared_partials: self._get_approx_scheme('fd') msg = "Because the MetaModelUnStructuredComp '{}' uses a surrogate " \ "which does not define a linearize method,\nOpenMDAO will use " \ "finite differences to compute derivatives. Some of the derivatives " \ "will be computed\nusing default finite difference " \ "options because they were not explicitly declared.\n".format(self.name) msg += "The derivatives computed using the defaults are:\n" for abs_key in non_declared_partials: msg += " {}, {}\n".format(*abs_key) issue_warning(msg, category=DerivativesWarning)
def _get_tree_dict(system, is_parallel=False): """Get a dictionary representation of the system hierarchy.""" tree_dict = { 'name': system.name if system.name else 'root', 'type': 'subsystem' if system.name else 'root', 'class': system.__class__.__name__, 'expressions': None, 'nonlinear_solver': "", 'nonlinear_solver_options': None, 'linear_solver': "", 'linear_solver_options': None, } is_implicit = False if isinstance(system, Group): if MPI and isinstance(system, ParallelGroup): is_parallel = True tree_dict['component_type'] = None tree_dict['subsystem_type'] = 'group' tree_dict['is_parallel'] = is_parallel children = [ _get_tree_dict(s, is_parallel) for s in system._subsystems_myproc ] if system.comm.size > 1: if system._subsystems_myproc: sub_comm = system._subsystems_myproc[0].comm if sub_comm.rank != 0: children = [] children_lists = system.comm.allgather(children) children = [] for children_list in children_lists: children.extend(children_list) if system.linear_solver: tree_dict['linear_solver'] = system.linear_solver.SOLVER tree_dict['linear_solver_options'] = { k: _serialize_single_option(opt) for k, opt in system.linear_solver.options._dict.items() } if system.nonlinear_solver: tree_dict['nonlinear_solver'] = system.nonlinear_solver.SOLVER tree_dict['nonlinear_solver_options'] = { k: _serialize_single_option(opt) for k, opt in system.nonlinear_solver.options._dict.items() } if system.nonlinear_solver.SOLVER == NewtonSolver.SOLVER: tree_dict[ 'solve_subsystems'] = system._nonlinear_solver.options[ 'solve_subsystems'] else: tree_dict['subsystem_type'] = 'component' tree_dict['is_parallel'] = is_parallel if isinstance(system, ImplicitComponent): is_implicit = True tree_dict['component_type'] = 'implicit' if overrides_method('solve_linear', system, ImplicitComponent): tree_dict['linear_solver'] = "solve_linear" elif system.linear_solver: tree_dict['linear_solver'] = system.linear_solver.SOLVER tree_dict['linear_solver_options'] = { k: _serialize_single_option(opt) for k, opt in system.linear_solver.options._dict.items() } if overrides_method('solve_nonlinear', system, ImplicitComponent): tree_dict['nonlinear_solver'] = "solve_nonlinear" elif system.nonlinear_solver: tree_dict['nonlinear_solver'] = system.nonlinear_solver.SOLVER tree_dict['nonlinear_solver_options'] = { k: _serialize_single_option(opt) for k, opt in system.nonlinear_solver.options._dict.items() } elif isinstance(system, ExecComp): tree_dict['component_type'] = 'exec' tree_dict['expressions'] = system._exprs elif isinstance(system, (MetaModelStructuredComp, MetaModelUnStructuredComp)): tree_dict['component_type'] = 'metamodel' elif isinstance(system, IndepVarComp): tree_dict['component_type'] = 'indep' elif isinstance(system, ExplicitComponent): tree_dict['component_type'] = 'explicit' else: tree_dict['component_type'] = None children = [] for typ in ['input', 'output']: for abs_name in system._var_abs2meta[typ]: children.append( _get_var_dict(system, typ, abs_name, is_parallel, is_implicit)) for prom_name in system._var_discrete[typ]: children.append( _get_var_dict(system, typ, prom_name, is_parallel, is_implicit)) tree_dict['children'] = children options = {} slv = {'linear_solver', 'nonlinear_solver'} for k, opt in system.options._dict.items(): # need to handle solvers separate because they are classes or instances if k in slv: try: options[k] = opt['val'].SOLVER except KeyError: options[k] = opt['value'].SOLVER else: options[k] = _serialize_single_option(opt) tree_dict['options'] = options return tree_dict
def _get_tree_dict(system, component_execution_orders, component_execution_index): """Get a dictionary representation of the system hierarchy.""" tree_dict = OrderedDict() tree_dict['name'] = system.name tree_dict['type'] = 'subsystem' if not isinstance(system, Group): tree_dict['subsystem_type'] = 'component' component_execution_orders[ system.pathname] = component_execution_index[0] component_execution_index[0] += 1 children = [] for typ in ['input', 'output']: for ind, abs_name in enumerate(system._var_abs_names[typ]): meta = system._var_abs2meta[abs_name] name = system._var_abs2prom[typ][abs_name] var_dict = OrderedDict() var_dict['name'] = name if typ == 'input': var_dict['type'] = 'param' elif typ == 'output': isimplicit = isinstance(system, ImplicitComponent) var_dict['type'] = 'unknown' var_dict['implicit'] = isimplicit var_dict['dtype'] = type(meta['value']).__name__ children.append(var_dict) else: tree_dict['subsystem_type'] = 'group' children = [ _get_tree_dict(s, component_execution_orders, component_execution_index) for s in system._subsystems_myproc ] if system.comm.size > 1: if system._subsystems_myproc: sub_comm = system._subsystems_myproc[0].comm if sub_comm.rank != 0: children = [] children_lists = system.comm.allgather(children) children = [] for children_list in children_lists: children.extend(children_list) if isinstance(system, ImplicitComponent): if overrides_method('solve_linear', system, ImplicitComponent): tree_dict['linear_solver'] = "solve_linear" else: tree_dict['linear_solver'] = "" else: if system.linear_solver: tree_dict['linear_solver'] = system.linear_solver.SOLVER else: tree_dict['linear_solver'] = "" if isinstance(system, ImplicitComponent): if overrides_method('solve_nonlinear', system, ImplicitComponent): tree_dict['nonlinear_solver'] = "solve_nonlinear" else: tree_dict['nonlinear_solver'] = "" else: if system.nonlinear_solver: tree_dict['nonlinear_solver'] = system.nonlinear_solver.SOLVER else: tree_dict['nonlinear_solver'] = "" tree_dict['children'] = children if not tree_dict['name']: tree_dict['name'] = 'root' tree_dict['type'] = 'root' return tree_dict
def compute(self, inputs, outputs): """ Predict outputs. If the training flag is set, train the metamodel first. Parameters ---------- inputs : Vector unscaled, dimensional input variables read via inputs[key] outputs : Vector unscaled, dimensional output variables read via outputs[key] """ vec_size = self.options['vec_size'] # train first if self.train: self._train() # predict for current inputs if vec_size > 1: flat_inputs = self._vec_to_array_vectorized(inputs) else: flat_inputs = self._vec_to_array(inputs) for name, shape in self._surrogate_output_names: surrogate = self._metadata(name).get('surrogate') if vec_size == 1: # Non vectorized. predicted = surrogate.predict(flat_inputs) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, shape) elif overrides_method('vectorized_predict', surrogate, SurrogateModel): # Vectorized; surrogate provides vectorized computation. # TODO: This code is untested because no surrogates provide this option. predicted = surrogate.vectorized_predict(flat_inputs.flat) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, shape) else: # Vectorized; must call surrogate multiple times. if isinstance(shape, tuple): output_shape = (vec_size, ) + shape else: output_shape = (vec_size, ) predicted = np.zeros(output_shape) rmse = self._metadata(name)['rmse'] = [] for i in range(vec_size): pred_i = surrogate.predict(flat_inputs[i]) if isinstance(pred_i, tuple): # rmse option rmse.append(pred_i[1]) pred_i = pred_i[0] predicted[i] = np.reshape(pred_i, shape) outputs[name] = np.reshape(predicted, output_shape)
def compute(self, inputs, outputs): """ Predict outputs. If the training flag is set, train the metamodel first. Parameters ---------- inputs : Vector unscaled, dimensional input variables read via inputs[key] outputs : Vector unscaled, dimensional output variables read via outputs[key] """ vec_size = self.options['vec_size'] # train first if self.train: self._train() # predict for current inputs if vec_size > 1: flat_inputs = self._vec_to_array_vectorized(inputs) else: flat_inputs = self._vec_to_array(inputs) for name, shape in self._surrogate_output_names: surrogate = self._metadata(name).get('surrogate') if vec_size == 1: # Non vectorized. predicted = surrogate.predict(flat_inputs) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, shape) elif overrides_method('vectorized_predict', surrogate, SurrogateModel): # Vectorized; surrogate provides vectorized computation. # TODO: This code is untested because no surrogates provide this option. predicted = surrogate.vectorized_predict(flat_inputs.flat) if isinstance(predicted, tuple): # rmse option self._metadata(name)['rmse'] = predicted[1] predicted = predicted[0] outputs[name] = np.reshape(predicted, shape) else: # Vectorized; must call surrogate multiple times. if isinstance(shape, tuple): output_shape = (vec_size, ) + shape else: output_shape = (vec_size, ) predicted = np.zeros(output_shape) rmse = self._metadata(name)['rmse'] = [] for i in range(vec_size): pred_i = surrogate.predict(flat_inputs[i]) if isinstance(pred_i, tuple): # rmse option rmse.append(pred_i[1]) pred_i = pred_i[0] predicted[i] = np.reshape(pred_i, shape) outputs[name] = np.reshape(predicted, output_shape)
def _get_tree_dict(system, component_execution_orders, component_execution_index, is_parallel=False): """Get a dictionary representation of the system hierarchy.""" tree_dict = OrderedDict() tree_dict['name'] = system.name tree_dict['type'] = 'subsystem' if not isinstance(system, Group): tree_dict['subsystem_type'] = 'component' tree_dict['is_parallel'] = is_parallel if isinstance(system, ImplicitComponent): tree_dict['component_type'] = 'implicit' elif isinstance(system, ExecComp): tree_dict['component_type'] = 'exec' elif isinstance(system, (MetaModelStructuredComp, MetaModelUnStructuredComp)): tree_dict['component_type'] = 'metamodel' elif isinstance(system, IndepVarComp): tree_dict['component_type'] = 'indep' elif isinstance(system, ExplicitComponent): tree_dict['component_type'] = 'explicit' else: tree_dict['component_type'] = None component_execution_orders[system.pathname] = component_execution_index[0] component_execution_index[0] += 1 children = [] for typ in ['input', 'output']: for ind, abs_name in enumerate(system._var_abs_names[typ]): meta = system._var_abs2meta[abs_name] name = system._var_abs2prom[typ][abs_name] var_dict = OrderedDict() var_dict['name'] = name if typ == 'input': var_dict['type'] = 'param' elif typ == 'output': isimplicit = isinstance(system, ImplicitComponent) var_dict['type'] = 'unknown' var_dict['implicit'] = isimplicit var_dict['dtype'] = type(meta['value']).__name__ children.append(var_dict) else: if isinstance(system, ParallelGroup): is_parallel = True tree_dict['component_type'] = None tree_dict['subsystem_type'] = 'group' tree_dict['is_parallel'] = is_parallel children = [_get_tree_dict(s, component_execution_orders, component_execution_index, is_parallel) for s in system._subsystems_myproc] if system.comm.size > 1: if system._subsystems_myproc: sub_comm = system._subsystems_myproc[0].comm if sub_comm.rank != 0: children = [] children_lists = system.comm.allgather(children) children = [] for children_list in children_lists: children.extend(children_list) if isinstance(system, ImplicitComponent): if overrides_method('solve_linear', system, ImplicitComponent): tree_dict['linear_solver'] = "solve_linear" else: tree_dict['linear_solver'] = "" else: if system.linear_solver: tree_dict['linear_solver'] = system.linear_solver.SOLVER else: tree_dict['linear_solver'] = "" if isinstance(system, ImplicitComponent): if overrides_method('solve_nonlinear', system, ImplicitComponent): tree_dict['nonlinear_solver'] = "solve_nonlinear" else: tree_dict['nonlinear_solver'] = "" else: if system.nonlinear_solver: tree_dict['nonlinear_solver'] = system.nonlinear_solver.SOLVER else: tree_dict['nonlinear_solver'] = "" tree_dict['children'] = children if not tree_dict['name']: tree_dict['name'] = 'root' tree_dict['type'] = 'root' return tree_dict
def _setup_partials(self, recurse=True): """ Process all partials and approximations that the user declared. Metamodel needs to declare its partials after inputs and outputs are known. Parameters ---------- recurse : bool Whether to call this method in subsystems. """ super(MetaModelUnStructuredComp, self)._setup_partials() vec_size = self.options['vec_size'] if vec_size > 1: # Sparse specification of partials for vectorized models. for wrt, n_wrt in self._surrogate_input_names: for of, shape_of in self._surrogate_output_names: n_of = np.prod(shape_of) rows = np.repeat(np.arange(n_of), n_wrt) cols = np.tile(np.arange(n_wrt), n_of) nnz = len(rows) rows = np.tile(rows, vec_size) + np.repeat(np.arange(vec_size), nnz) * n_of cols = np.tile(cols, vec_size) + np.repeat(np.arange(vec_size), nnz) * n_wrt self._declare_partials(of=of, wrt=wrt, rows=rows, cols=cols) else: # Dense specification of partials for non-vectorized models. self._declare_partials(of=[name[0] for name in self._surrogate_output_names], wrt=[name[0] for name in self._surrogate_input_names]) # warn the user that if they don't explicitly set options for fd, # the defaults will be used # get a list of approximated partials declared_partials = set() for of, wrt, method, fd_options in self._approximated_partials: pattern_matches = self._find_partial_matches(of, wrt) for of_bundle, wrt_bundle in product(*pattern_matches): of_pattern, of_matches = of_bundle wrt_pattern, wrt_matches = wrt_bundle for rel_key in product(of_matches, wrt_matches): abs_key = rel_key2abs_key(self, rel_key) declared_partials.add(abs_key) non_declared_partials = [] for of, n_of in self._surrogate_output_names: has_derivs = False surrogate = self._metadata(of).get('surrogate') if surrogate: has_derivs = overrides_method('linearize', surrogate, SurrogateModel) if not has_derivs: for wrt, n_wrt in self._surrogate_input_names: abs_key = rel_key2abs_key(self, (of, wrt)) if abs_key not in declared_partials: non_declared_partials.append(abs_key) if non_declared_partials: msg = "Because the MetaModelUnStructuredComp '{}' uses a surrogate " \ "which does not define a linearize method,\nOpenMDAO will use " \ "finite differences to compute derivatives. Some of the derivatives " \ "will be computed\nusing default finite difference " \ "options because they were not explicitly declared.\n".format(self.name) msg += "The derivatives computed using the defaults are:\n" for abs_key in non_declared_partials: msg += " {}, {}\n".format(*abs_key) simple_warning(msg, RuntimeWarning) for out_name, out_shape in self._surrogate_output_names: surrogate = self._metadata(out_name).get('surrogate') if surrogate and not overrides_method('linearize', surrogate, SurrogateModel): self._approx_partials(of=out_name, wrt=[name[0] for name in self._surrogate_input_names], method='fd') if "fd" not in self._approx_schemes: self._approx_schemes['fd'] = FiniteDifference()
def _get_tree_dict(system, component_execution_orders, component_execution_index, is_parallel=False): """Get a dictionary representation of the system hierarchy.""" tree_dict = OrderedDict() tree_dict['name'] = system.name tree_dict['type'] = 'subsystem' tree_dict['class'] = system.__class__.__name__ tree_dict['expressions'] = None if not isinstance(system, Group): tree_dict['subsystem_type'] = 'component' tree_dict['is_parallel'] = is_parallel if isinstance(system, ImplicitComponent): tree_dict['component_type'] = 'implicit' elif isinstance(system, ExecComp): tree_dict['component_type'] = 'exec' tree_dict['expressions'] = system._exprs elif isinstance(system, (MetaModelStructuredComp, MetaModelUnStructuredComp)): tree_dict['component_type'] = 'metamodel' elif isinstance(system, IndepVarComp): tree_dict['component_type'] = 'indep' elif isinstance(system, ExplicitComponent): tree_dict['component_type'] = 'explicit' else: tree_dict['component_type'] = None component_execution_orders[system.pathname] = component_execution_index[0] component_execution_index[0] += 1 children = [] for typ in ['input', 'output']: for abs_name in system._var_abs_names[typ]: children.append(_get_var_dict(system, typ, abs_name)) for prom_name in system._var_discrete[typ]: children.append(_get_var_dict(system, typ, prom_name)) else: if isinstance(system, ParallelGroup): is_parallel = True tree_dict['component_type'] = None tree_dict['subsystem_type'] = 'group' tree_dict['is_parallel'] = is_parallel children = [] for s in system._subsystems_myproc: if (s.name != '_auto_ivc'): children.append(_get_tree_dict(s, component_execution_orders, component_execution_index, is_parallel)) if system.comm.size > 1: if system._subsystems_myproc: sub_comm = system._subsystems_myproc[0].comm if sub_comm.rank != 0: children = [] children_lists = system.comm.allgather(children) children = [] for children_list in children_lists: children.extend(children_list) if isinstance(system, ImplicitComponent): if overrides_method('solve_linear', system, ImplicitComponent): tree_dict['linear_solver'] = "solve_linear" tree_dict['linear_solver_options'] = None elif system.linear_solver: tree_dict['linear_solver'] = system.linear_solver.SOLVER options = {k: system.linear_solver.options[k] for k in system.linear_solver.options} tree_dict['linear_solver_options'] = options else: tree_dict['linear_solver'] = "" tree_dict['linear_solver_options'] = None if overrides_method('solve_nonlinear', system, ImplicitComponent): tree_dict['nonlinear_solver'] = "solve_nonlinear" tree_dict['nonlinear_solver_options'] = None elif system.nonlinear_solver: tree_dict['nonlinear_solver'] = system.nonlinear_solver.SOLVER options = {k: system.nonlinear_solver.options[k] for k in system.nonlinear_solver.options} tree_dict['nonlinear_solver_options'] = options else: tree_dict['nonlinear_solver'] = "" tree_dict['nonlinear_solver_options'] = None else: if system.linear_solver: tree_dict['linear_solver'] = system.linear_solver.SOLVER options = {k: system.linear_solver.options[k] for k in system.linear_solver.options} tree_dict['linear_solver_options'] = options else: tree_dict['linear_solver'] = "" tree_dict['linear_solver_options'] = None if system.nonlinear_solver: tree_dict['nonlinear_solver'] = system.nonlinear_solver.SOLVER options = {k: system.nonlinear_solver.options[k] for k in system.nonlinear_solver.options} tree_dict['nonlinear_solver_options'] = options if system.nonlinear_solver.SOLVER == NewtonSolver.SOLVER: tree_dict['solve_subsystems'] = system._nonlinear_solver.options['solve_subsystems'] else: tree_dict['nonlinear_solver'] = "" tree_dict['nonlinear_solver_options'] = None tree_dict['children'] = children options = {} for k in system.options: # need to handle solvers separate because they are classes or instances if k in ['linear_solver', 'nonlinear_solver']: options[k] = system.options[k].SOLVER else: if system.options._dict[k]['value'] is _UNDEFINED: options[k] = str(system.options._dict[k]['value']) else: options[k] = system.options._dict[k]['value'] tree_dict['options'] = options if not tree_dict['name']: tree_dict['name'] = 'root' tree_dict['type'] = 'root' return tree_dict