def get_inner_edges(graph, srcs, dests, wflow): graph = graph.subgraph(graph.nodes()) # add @in and @out nodes, rewire input srcs, etc. mod_for_derivs(graph, srcs, dests, wflow) # sort edges by src so that basevars occur before subvars edges = sorted(graph.list_connections(), key=lambda e: e[0]) return edges_to_dict(edges)
def get_inner_edges(graph, srcs, dests, wflow): graph = graph.subgraph(graph.nodes()) # add @in and @out nodes, rewire input srcs, etc. graph = mod_for_derivs(graph, srcs, dests, wflow) # sort edges by src so that basevars occur before subvars edges = sorted(graph.list_connections(), key=lambda e: e[0]) return edges_to_dict(edges)
def derivative_graph(self, inputs=None, outputs=None, fd=False, severed=None, group_nondif=True): """Returns the local graph that we use for derivatives. inputs: list of strings or tuples of strings List of input variables that we are taking derivatives with respect to. They must be within this workflow's scope. If no inputs are given, the parent driver's parameters are used. A tuple can be used to link inputs together. outputs: list of strings List of output variables that we are taking derivatives of. They must be within this workflow's scope. If no outputs are given, the parent driver's objectives and constraints are used. fd: boolean set to True to finite difference the whole model together with fake finite difference turned off. This is mainly for checking your model's analytic derivatives. severed: list If a workflow has a cylic connection, some edges must be severed. When a cyclic workflow calls this function, it passes a list of edges so that they can be severed prior to the topological sort. group_nondif: bool If True, collapse parts of the graph into PseudoAssemblies when necessary. """ if self._derivative_graph is None or group_nondif is False: # when we call with group_nondif = False, we want the union of the # passed inputs/outputs plus the inputs/outputs from the solver if group_nondif is False: tmp_inputs = [] if inputs is None else inputs tmp_outputs = [] if outputs is None else outputs inputs = None outputs = None # If inputs aren't specified, use the parameters parent_deriv_vars = list_deriv_vars(self._parent.parent) if inputs is None: if hasattr(self._parent, 'list_param_group_targets'): inputs = self._parent.list_param_group_targets() elif parent_deriv_vars[0]: inputs = parent_deriv_vars[0] else: msg = "No inputs given for derivatives." self.scope.raise_exception(msg, RuntimeError) if group_nondif is False: inputs = list(set(tmp_inputs).union(inputs)) # If outputs aren't specified, use the objectives and constraints if outputs is None: outputs = [] if hasattr(self._parent, 'get_objectives'): outputs.extend([ "%s.out0" % item.pcomp_name for item in self._parent.get_objectives().values() ]) if hasattr(self._parent, 'get_constraints'): outputs.extend([ "%s.out0" % item.pcomp_name for item in self._parent.get_constraints().values() ]) if group_nondif is False: outputs = list(set(tmp_outputs).union(outputs)) if len(outputs) == 0: if parent_deriv_vars[1]: outputs = parent_deriv_vars[1] else: msg = "No outputs given for derivatives." self.scope.raise_exception(msg, RuntimeError) graph = self.scope._depgraph # make a copy of the graph because it will be # modified by mod_for_derivs dgraph = graph.subgraph(graph.nodes()) dgraph = mod_for_derivs(dgraph, inputs, outputs, self, fd) if group_nondif: self._derivative_graph = dgraph self._group_nondifferentiables(fd, severed) else: # we're being called to determine the deriv graph # for a subsolver, so get rid of @in and @out nodes dgraph.remove_nodes_from( ['@in%d' % i for i in range(len(inputs))]) dgraph.remove_nodes_from( ['@out%d' % i for i in range(len(outputs))]) dgraph.graph['inputs'] = inputs[:] dgraph.graph['outputs'] = outputs[:] return dgraph return self._derivative_graph
def derivative_graph(self, inputs=None, outputs=None, fd=False, severed=None, group_nondif=True): """Returns the local graph that we use for derivatives. inputs: list of strings or tuples of strings List of input variables that we are taking derivatives with respect to. They must be within this workflow's scope. If no inputs are given, the parent driver's parameters are used. A tuple can be used to link inputs together. outputs: list of strings List of output variables that we are taking derivatives of. They must be within this workflow's scope. If no outputs are given, the parent driver's objectives and constraints are used. fd: boolean set to True to finite difference the whole model together with fake finite difference turned off. This is mainly for checking your model's analytic derivatives. severed: list If a workflow has a cylic connection, some edges must be severed. When a cyclic workflow calls this function, it passes a list of edges so that they can be severed prior to the topological sort. group_nondif: bool If True, collapse parts of the graph into PseudoAssemblies when necessary. """ if self._derivative_graph is None or group_nondif is False: # when we call with group_nondif = False, we want the union of the # passed inputs/outputs plus the inputs/outputs from the solver if group_nondif is False: tmp_inputs = [] if inputs is None else inputs tmp_outputs = [] if outputs is None else outputs inputs = None outputs = None # If inputs aren't specified, use the parameters if inputs is None: if hasattr(self._parent, 'list_param_group_targets'): inputs = self._parent.list_param_group_targets() else: msg = "No inputs given for derivatives." self.scope.raise_exception(msg, RuntimeError) if group_nondif is False: inputs = list(set(tmp_inputs).union(inputs)) # If outputs aren't specified, use the objectives and constraints if outputs is None: outputs = [] if hasattr(self._parent, 'get_objectives'): outputs.extend(["%s.out0" % item.pcomp_name for item in self._parent.get_objectives().values()]) if hasattr(self._parent, 'get_constraints'): outputs.extend(["%s.out0" % item.pcomp_name for item in self._parent.get_constraints().values()]) if group_nondif is False: outputs = list(set(tmp_outputs).union(outputs)) if len(outputs) == 0: msg = "No outputs given for derivatives." self.scope.raise_exception(msg, RuntimeError) graph = self.scope._depgraph # make a copy of the graph because it will be # modified by mod_for_derivs dgraph = graph.subgraph(graph.nodes()) mod_for_derivs(dgraph, inputs, outputs, self, fd) if group_nondif: self._derivative_graph = dgraph self._group_nondifferentiables(fd, severed) else: # we're being called to determine the deriv graph # for a subsolver, so get rid of @in and @out nodes dgraph.remove_nodes_from(['@in%d' % i for i in range(len(inputs))]) dgraph.remove_nodes_from(['@out%d' % i for i in range(len(outputs))]) dgraph.graph['inputs'] = inputs[:] dgraph.graph['outputs'] = outputs[:] return dgraph return self._derivative_graph