def test_get_inner_edges(self): self.assertEqual(len(_get_inner_edges(self.dep, ['b'], ['c'])), 6) self.assertEqual(set(_get_inner_edges(self.dep, ['b'], ['c'])), set([('b[3]','A.b'),('A.d.z','B.b[4]'),('A.c[2]','B.a.x.y'), ('B.c','C.a'),('B.d','C.b'),('C.c','c')])) dep, scope = _make_graph(comps=['A','B'], connections=[('A.c','B.a'),('A.d','B.b')], inputs=['a','b'], outputs=['c','d']) self.assertEqual(len(_get_inner_edges(dep, ['A.a'], ['B.c'])), 2) self.assertEqual(set(_get_inner_edges(dep, ['A.a'], ['B.c'])), set([('A.c','B.a'),('A.d','B.b')])) dep, scope = _make_graph(comps=['A','B', 'C'], connections=[('A.c','B.a'),('A.d','B.b'),('B.d','C.a')], inputs=['a','b'], outputs=['c','d']) self.assertEqual(set(_get_inner_edges(dep, ['A.a'], ['C.c'])), set([('A.c','B.a'),('A.d','B.b'),('B.d','C.a')])) # same output feeding two inputs dep, scope = _make_graph(comps=['A','B', 'C'], connections=[('A.d','B.a'),('A.d','B.b'),('B.d','C.a')], inputs=['a','b'], outputs=['c','d']) edges = _get_inner_edges(dep, ['A.a'], ['C.c']) self.assertEqual(set(edges), set([('A.d','B.a'),('A.d','B.b'),('B.d','C.a')])) edict = edges_to_dict(edges) self.assertEqual(len(edict), 2) self.assertEqual(set(edict['A.d']), set(['B.a','B.b'])) self.assertEqual(edict['B.d'], ['C.a']) # loop dep, scope = _make_graph(comps=['A','B', 'C'], connections=[('A.d','B.a'),('B.d','C.a'),('C.d','A.a')], inputs=['a','b'], outputs=['c','d']) self.assertEqual(set(_get_inner_edges(dep, ['A.a'], ['C.d'])), set([('A.d','B.a'),('B.d','C.a'),('C.d','A.a')]))
def calc_derivatives(self, first=False, second=False, savebase=True, required_inputs=None, required_outputs=None): """Calculate the derivatives for this non-differentiable block using Finite Difference.""" # We don't do this in __init__ because some inputs and outputs # are added after creation (for nested driver support). if self.fd is None: from openmdao.main.derivatives import FiniteDifference self.fd = FiniteDifference(self) if hasattr(self.wflow, '_severed_edges'): self.wflow.sever_edges(self.wflow._severed_edges) try: # First, linearize about operating point. # Note: Only needed for differentiable islands, which are handled # with Fake Finite Difference. # Don't do this for full-model finite difference. if first and self.ffd_order > 0: for name in self.comps: # TODO: I think the cache is blown away each time before # this is called if name in self.wflow._J_cache: continue comp = self.wflow.scope.get(name) # Assemblies need some required inputs and outputs # to calculate the Jacobians if has_interface(comp, IAssembly): # Need to know which assy bdry variables are # required, and pass them in. Cache this once. if name not in self.ffd_cache: dgraph = self.wflow.scope._depgraph inputs = [ dgraph.base_var(inp) for inp in flatten_list_of_iters(self.inputs) ] outputs = [ dgraph.base_var(outp) for outp in self.outputs ] from openmdao.main.depgraph import _get_inner_edges edges = _get_inner_edges(dgraph, inputs, outputs) req_inputs = [] req_outputs = [] for inp in inputs: comp_str, _, var_str = inp.partition('.') if comp_str == name: req_inputs.append(var_str) for inp in outputs: comp_str, _, var_str = inp.partition('.') if comp_str == name: req_outputs.append(var_str) for edge in edges: src, target = edge comp_str, _, var_str = src.partition('.') if comp_str == name: req_outputs.append(var_str) comp_str, _, var_str = target.partition('.') if comp_str == name: req_inputs.append(var_str) self.ffd_cache[name] = (req_inputs, req_outputs) req_inputs, req_outputs = self.ffd_cache[name] comp.calc_derivatives(first, second, savebase=True, required_inputs=req_inputs, required_outputs=req_outputs) # Comp list contains full graph, so don't double up on # the subdrivers. elif not has_interface(comp, IDriver): comp.calc_derivatives(first, second, True) self.J = self.fd.calculate() finally: if hasattr(self.wflow, '_severed_edges'): self.wflow.unsever_edges() return self.J
def calc_derivatives(self, first=False, second=False, savebase=True, required_inputs=None, required_outputs=None): """Calculate the derivatives for this non-differentiable block using Finite Difference.""" # We don't do this in __init__ because some inputs and outputs # are added after creation (for nested driver support). if self.fd is None: from openmdao.main.derivatives import FiniteDifference self.fd = FiniteDifference(self) if hasattr(self.wflow, '_severed_edges'): self.wflow.sever_edges(self.wflow._severed_edges) try: # First, linearize about operating point. # Note: Only needed for differentiable islands, which are handled # with Fake Finite Difference. # Don't do this for full-model finite difference. if first and self.ffd_order > 0: for name in self.comps: # TODO: I think the cache is blown away each time before # this is called if name in self.wflow._J_cache: continue comp = self.wflow.scope.get(name) # Assemblies need some required inputs and outputs # to calculate the Jacobians if has_interface(comp, IAssembly): # Need to know which assy bdry variables are # required, and pass them in. Cache this once. if name not in self.ffd_cache: dgraph = self.wflow.scope._depgraph inputs = [dgraph.base_var(inp) for inp in flatten_list_of_iters(self.inputs)] outputs = [dgraph.base_var(outp) for outp in self.outputs] from openmdao.main.depgraph import _get_inner_edges edges = _get_inner_edges(dgraph, inputs, outputs) req_inputs = [] req_outputs = [] for inp in inputs: comp_str, _, var_str = inp.partition('.') if comp_str == name: req_inputs.append(var_str) for inp in outputs: comp_str, _, var_str = inp.partition('.') if comp_str == name: req_outputs.append(var_str) for edge in edges: src, target = edge comp_str, _, var_str = src.partition('.') if comp_str == name: req_outputs.append(var_str) comp_str, _, var_str = target.partition('.') if comp_str == name: req_inputs.append(var_str) self.ffd_cache[name] = (req_inputs, req_outputs) req_inputs, req_outputs = self.ffd_cache[name] comp.calc_derivatives(first, second, savebase=True, required_inputs=req_inputs, required_outputs=req_outputs) # Comp list contains full graph, so don't double up on # the subdrivers. elif not has_interface(comp, IDriver): comp.calc_derivatives(first, second, True) self.J = self.fd.calculate() finally: if hasattr(self.wflow, '_severed_edges'): self.wflow.unsever_edges() return self.J
def test_inner_edges(self): edges = _get_inner_edges(self.dep, ['a'], ['c']) self.assertEqual(set(edges), set([('C2.s2', 'c'), ('C1.s1', 'C2.a'), ('a', 'C1.s1')]))