def test_basic_grouped_bug_from_pycycle(self): prob = Problem() root = prob.root = Group() sub1 = prob.root.add('sub1', Group(), promotes=['x2']) sub1.add('src', SrcComp(), promotes = ['x2']) root.add('tgtF', TgtCompFMulti()) root.add('tgtC', TgtCompC()) root.add('tgtK', TgtCompK()) prob.root.add('px1', ParamComp('x1', 100.0), promotes=['x1']) prob.root.connect('x1', 'sub1.src.x1') prob.root.connect('x2', 'tgtF.x2') prob.root.connect('x2', 'tgtC.x2') prob.root.connect('x2', 'tgtK.x2') prob.setup(check=False) prob.run() assert_rel_error(self, prob['x2'], 100.0, 1e-6) assert_rel_error(self, prob['tgtF.x3'], 212.0, 1e-6) assert_rel_error(self, prob['tgtC.x3'], 100.0, 1e-6) assert_rel_error(self, prob['tgtK.x3'], 373.15, 1e-6) param_list = ['x1'] unknown_list = ['tgtF.x3', 'tgtC.x3', 'tgtK.x3'] J = prob.calc_gradient(param_list, unknown_list, mode='fwd', return_format='dict') assert_rel_error(self, J['tgtF.x3']['x1'][0][0], 1.8, 1e-6) assert_rel_error(self, J['tgtC.x3']['x1'][0][0], 1.0, 1e-6) assert_rel_error(self, J['tgtK.x3']['x1'][0][0], 1.0, 1e-6) J = prob.calc_gradient(param_list, unknown_list, mode='rev', return_format='dict') assert_rel_error(self, J['tgtF.x3']['x1'][0][0], 1.8, 1e-6) assert_rel_error(self, J['tgtC.x3']['x1'][0][0], 1.0, 1e-6) assert_rel_error(self, J['tgtK.x3']['x1'][0][0], 1.0, 1e-6)
def test_basic(self): size = 3 prob = Problem(Group(), impl=impl) G1 = prob.root.add('G1', ParallelGroup()) G1.add('P1', IndepVarComp('x', np.ones(size, float) * 1.0)) G1.add('P2', IndepVarComp('x', np.ones(size, float) * 2.0)) prob.root.add('C1', ABCDArrayComp(size)) prob.root.connect('G1.P1.x', 'C1.a') prob.root.connect('G1.P2.x', 'C1.b') prob.driver.add_recorder(self.recorder) self.recorder.options['record_params'] = True self.recorder.options['record_resids'] = True prob.setup(check=False) t0, t1 = run(prob) prob.cleanup() expected_params = [ ("C1.a", [1.0, 1.0, 1.0]), ("C1.b", [2.0, 2.0, 2.0]), ] expected_unknowns = [ ("G1.P1.x", np.array([1.0, 1.0, 1.0])), ("G1.P2.x", np.array([2.0, 2.0, 2.0])), ("C1.c", np.array([3.0, 3.0, 3.0])), ("C1.d", np.array([-1.0, -1.0, -1.0])), ("C1.out_string", "_C1"), ("C1.out_list", [1.5]), ] expected_resids = [ ("G1.P1.x", np.array([0.0, 0.0, 0.0])), ("G1.P2.x", np.array([0.0, 0.0, 0.0])), ("C1.c", np.array([0.0, 0.0, 0.0])), ("C1.d", np.array([0.0, 0.0, 0.0])), ("C1.out_string", ""), ("C1.out_list", []), ] self.assertIterationDataRecorded(((coordinate, (t0, t1), expected_params, expected_unknowns, expected_resids),), self.eps, prob.root)
def test_simplest_run(self): prob = Problem(root=Group()) root = prob.root root.add('x_param', ParamComp('x', 7.0)) root.add('mycomp', ExecComp('y=x*2.0')) root.connect('x_param.x', 'mycomp.x') prob.setup(check=False) prob.run() result = root.unknowns['mycomp.y'] self.assertAlmostEqual(14.0, result, 3)
def test_inp_inp_promoted_no_src2(self): p = Problem(root=Group()) root = p.root G1 = root.add("G1", Group()) G2 = G1.add("G2", Group()) C1 = G2.add("C1", ExecComp('y=x*2.0')) C2 = G2.add("C2", ExecComp('y=x*2.0')) G3 = root.add("G3", Group()) G4 = G3.add("G4", Group(), promotes=['x']) C3 = G4.add("C3", ExecComp('y=x*2.0'), promotes=['x']) C4 = G4.add("C4", ExecComp('y=x*2.0'), promotes=['x']) p.setup(check=False) self.assertEqual(p._dangling['G3.x'], set(['G3.G4.C3.x', 'G3.G4.C4.x'])) # setting promoted name should set both params mapped to that name p['G3.x'] = 999. self.assertEqual(p.root.G3.G4.C3.params['x'], 999.) self.assertEqual(p.root.G3.G4.C4.params['x'], 999.)
def test_cycle(self): prob = Problem(root=Group()) root = prob.root G1 = root.add("G1", Group()) G2 = G1.add("G2", Group()) C1 = G2.add("C1", ExecComp('y=x*2.0')) C2 = G2.add("C2", ExecComp('y=x*2.0')) C3 = G2.add("C3", ExecComp('y=x*2.0')) G2.connect("C1.y", "C3.x") G2.connect("C3.y", "C2.x") G2.connect("C2.y", "C1.x") # force wrong order G2.set_order(['C1', 'C2', 'C3']) stream = cStringIO() checks = prob.setup(out_stream=stream) auto = G2.list_auto_order() self.assertTrue(auto == ['C1', 'C3', 'C2'] or auto == ['C3', 'C2', 'C1'] or auto == ['C2', 'C1', 'C3']) self.assertTrue( "Group 'G1.G2' has the following cycles: [['C1', 'C2', 'C3']]" in stream.getvalue()) oo = checks['out_of_order'] self.assertEqual(oo[0][0], 'G1.G2') expected = { ('C2', 'C3'): 'C1', ('C3', ): 'C2', ('C2', ): 'C1', } for node, afters in oo[0][1]: self.assertEqual(node, expected[tuple(afters)])
def setup(self): self.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) self.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) sub = self.add_subsystem('sub', Group(), promotes=['x', 'z', 'y1', 'state_eq.y2_actual', 'state_eq.y2_command', 'd1.y2', 'd2.y2']) subgrp = sub.add_subsystem('state_eq_group', Group(), promotes=['state_eq.y2_actual', 'state_eq.y2_command']) subgrp.add_subsystem('state_eq', StateConnection()) sub.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1']) sub.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1']) self.connect('state_eq.y2_command', 'd1.y2') self.connect('d2.y2', 'state_eq.y2_actual') self.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0, y1=0.0, y2=0.0), promotes=['x', 'z', 'y1', 'obj']) self.connect('d2.y2', 'obj_cmp.y2') self.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) self.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2']) self.connect('d2.y2', 'con_cmp2.y2') nl = self.options['nonlinear_solver'] self.nonlinear_solver = nl() if inspect.isclass(nl) else nl if self.options['nl_atol']: self.nonlinear_solver.options['atol'] = self.options['nl_atol'] if self.options['nl_maxiter']: self.nonlinear_solver.options['maxiter'] = self.options['nl_maxiter'] ln = self.options['linear_solver'] self.linear_solver = ln() if inspect.isclass(ln) else ln if self.options['ln_atol']: self.linear_solver.options['atol'] = self.options['ln_atol'] if self.options['ln_maxiter']: self.linear_solver.options['maxiter'] = self.options['ln_maxiter']
def test_input_input_explicit_conns_no_conn(self): prob = Problem(root=Group()) root = prob.root root.add('p1', ParamComp('x', 1.0)) root.add('c1', ExecComp('y = x*2.0')) root.add('c2', ExecComp('y = x*3.0')) root.connect('c1.x', 'c2.x') # ignore warning about the unconnected params with warnings.catch_warnings(record=True) as w: warnings.simplefilter("ignore") prob.setup(check=False) prob.run() self.assertEqual(root.connections, {})
def test_auto_order2(self): # this tests the auto ordering when we have a cycle that is the full graph. p = Problem(root=Group()) root = p.root C1 = root.add("C1", ExecComp('y=x*2.0')) C2 = root.add("C2", ExecComp('y=x*2.0')) C3 = root.add("C3", ExecComp('y=x*2.0')) root.connect('C1.y', 'C3.x') root.connect('C3.y', 'C2.x') root.connect('C2.y', 'C1.x') p.setup(check=False) self.assertEqual(p.root.list_auto_order(), ['C1', 'C3', 'C2'])
def test_multiple_connect(self): root = Group() C1 = root.add('C1', ExecComp('y=x*2.0')) C2 = root.add('C2', ExecComp('y=x*2.0')) C3 = root.add('C3', ExecComp('y=x*2.0')) root.connect('C1.y', ['C2.x', 'C3.x']) root._setup_paths('') params_dict, unknowns_dict = root._setup_variables() # verify we get correct connection information connections = root._get_explicit_connections() expected_connections = {'C2.x': ['C1.y'], 'C3.x': ['C1.y']} self.assertEqual(connections, expected_connections)
def test_incompatible_units(self): prob = Problem() prob.root = Group() prob.root.add( 'uc', UnitComp(shape=1, param_name='in', out_name='out', units='degC')) prob.root.add('pc', ParamComp('x', 0., units='ft')) prob.root.connect('pc.x', 'uc.in') with self.assertRaises(TypeError) as cm: prob.setup(check=False) expected_msg = "Unit 'ft' in source 'pc.x' is incompatible with unit 'degC' in target 'uc.in'." self.assertEqual(expected_msg, str(cm.exception))
def test_invalid_unit(self): prob = Problem() prob.root = Group() prob.root.add( 'uc', UnitComp(shape=1, param_name='in', out_name='out', units='junk')) prob.root.add('pc', ParamComp('x', 0., units='ft')) prob.root.connect('pc.x', 'uc.in') with self.assertRaises(ValueError) as cm: prob.setup(check=False) expected_msg = "no unit named 'junk' is defined" self.assertEqual(expected_msg, str(cm.exception))
def build_sequence(child_factory, num_children, conns=(), parent=None): if parent is None: parent = Group() cnames = [] for i in range(num_children): child = child_factory() cname = _child_name(child, i) parent.add(cname, child) if i: for u, v in conns: parent.connect('.'.join((cnames[-1], u)), '.'.join((cname, v))) cnames.append(cname) return parent
def test_simple_matvec_subbed_like_multipoint(self): group = Group() group.add('mycomp', SimpleCompDerivMatVec(), promotes=['x', 'y']) prob = Problem() prob.root = Group() prob.root.add('sub', group, promotes=['*']) prob.root.sub.add('x_param', ParamComp('x', 1.0), promotes=['*']) prob.root.ln_solver = ScipyGMRES() prob.setup(check=False) prob.run() J = prob.calc_gradient(['x'], ['y'], mode='fwd', return_format='dict') assert_rel_error(self, J['y']['x'][0][0], 2.0, 1e-6) J = prob.calc_gradient(['x'], ['y'], mode='rev', return_format='dict') assert_rel_error(self, J['y']['x'][0][0], 2.0, 1e-6) J = prob.calc_gradient(['x'], ['y'], mode='fd', return_format='dict') assert_rel_error(self, J['y']['x'][0][0], 2.0, 1e-6) J = prob.calc_gradient(['x'], ['y'], mode='fd', return_format='array') assert_rel_error(self, J[0][0], 2.0, 1e-6)
def test_simple_jac(self): group = Group() group.add('x_param', ParamComp('x', 1.0), promotes=['*']) group.add('mycomp', ExecComp(['y=2.0*x']), promotes=['x', 'y']) prob = Problem() prob.root = group prob.root.ln_solver = ScipyGMRES() prob.setup(check=False) prob.run() J = prob.calc_gradient(['x'], ['y'], mode='fwd', return_format='dict') assert_rel_error(self, J['y']['x'][0][0], 2.0, 1e-6) J = prob.calc_gradient(['x'], ['y'], mode='rev', return_format='dict') assert_rel_error(self, J['y']['x'][0][0], 2.0, 1e-6)
def test_simple_matvec(self): group = Group() group.add('x_param', ParamComp('x', 1.0), promotes=['*']) group.add('mycomp', SimpleCompDerivMatVec(), promotes=['x', 'y']) prob = Problem() prob.root = group prob.root.ln_solver = LinearGaussSeidel() prob.setup(check=False) prob.run() J = prob.calc_gradient(['x'], ['y'], mode='fwd', return_format='dict') assert_rel_error(self, J['y']['x'][0][0], 2.0, 1e-6) J = prob.calc_gradient(['x'], ['y'], mode='rev', return_format='dict') assert_rel_error(self, J['y']['x'][0][0], 2.0, 1e-6)
def make_subtree(parent, nsubgroups, levels, ncomps, ninputs, noutputs, nconns, var_factory=float): """Construct a system subtree under the given parent group.""" if levels <= 0: return if levels == 1: # add leaf nodes create_dyncomps(parent, ncomps, ninputs, noutputs, nconns, var_factory=var_factory) else: # add more subgroup levels for i in range(nsubgroups): g = parent.add_subsystem("G%d"%i, Group()) make_subtree(g, nsubgroups, levels-1, ncomps, ninputs, noutputs, nconns, var_factory=var_factory)
def test_too_many_procs(self): prob = Problem(Group(), impl=impl) size = 5 A1 = prob.root.add('A1', ParamComp('a', np.zeros(size, float))) C1 = prob.root.add('C1', ABCDArrayComp(size)) try: prob.setup(check=False) except Exception as err: self.assertEqual( str(err), "This problem was given 2 MPI processes, " "but it requires between 1 and 1.") else: if MPI: self.fail("Exception expected")
def __init__(self): super(SingleDiamondGrouped, self).__init__() self.add('p', IndepVarComp('x', 2.0)) sub1 = self.add('sub1', Group()) sub1.add('comp1', Comp1()) sub1.add('comp2', Comp2()) sub1.add('comp3', Comp3()) self.add('comp4', Comp4()) self.connect("p.x", "sub1.comp1.x1") self.connect('sub1.comp1.y1', 'sub1.comp2.x1') self.connect('sub1.comp1.y2', 'sub1.comp3.x1') self.connect('sub1.comp2.y1', 'comp4.x1') self.connect('sub1.comp3.y1', 'comp4.x2')
def test_meta_model_structured_deprecated(self): # run same test as above, only with the deprecated component, # to ensure we get the warning and the correct answer. # self-contained, to be removed when class name goes away. import numpy as np from openmdao.api import Group, Problem, IndepVarComp from openmdao.components.meta_model_structured_comp import MetaModelStructured # deprecated import warnings with warnings.catch_warnings(record=True) as w: xor_interp = MetaModelStructured(method='slinear') self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[0].category, DeprecationWarning)) self.assertEqual(str(w[0].message), "'MetaModelStructured' has been deprecated. Use " "'MetaModelStructuredComp' instead.") # set up inputs and outputs xor_interp.add_input('x', 0.0, training_data=np.array([0.0, 1.0]), units=None) xor_interp.add_input('y', 1.0, training_data=np.array([0.0, 1.0]), units=None) xor_interp.add_output('xor', 1.0, training_data=np.array([[0.0, 1.0], [1.0, 0.0]]), units=None) # Set up the OpenMDAO model model = Group() ivc = IndepVarComp() ivc.add_output('x', 0.0) ivc.add_output('y', 1.0) model.add_subsystem('ivc', ivc, promotes=["*"]) model.add_subsystem('comp', xor_interp, promotes=["*"]) prob = Problem(model) prob.setup() # Now test out a 'fuzzy' XOR prob['x'] = 0.9 prob['y'] = 0.001242 prob.run_model() computed = prob['xor'] actual = 0.8990064 assert_almost_equal(computed, actual) # we can verify all gradients by checking against finite-difference prob.check_partials(compact_print=True)
def test_variables(self): group = Group() group.add('C1', ExecComp('y=x*2.0'), promotes=['x']) group.add("C2", ExecComp('y=x*2.0'), promotes=['y']) # paths must be initialized prior to calling _setup_variables group._setup_paths('') params_dict, unknowns_dict = group._setup_variables() self.assertEqual(list(params_dict.keys()), ['C1.x', 'C2.x']) self.assertEqual(list(unknowns_dict.keys()), ['C1.y', 'C2.y']) self.assertEqual([m['promoted_name'] for n, m in params_dict.items()], ['x', 'C2.x']) self.assertEqual( [m['promoted_name'] for n, m in unknowns_dict.items()], ['C1.y', 'y'])
def test_training_derivatives(self): import numpy as np from openmdao.api import Group, Problem, IndepVarComp from openmdao.components.meta_model_structured import MetaModelStructured # create input param training data, of sizes 25, 5, and 10 points resp. p1 = np.linspace(0, 100, 25) p2 = np.linspace(-10, 10, 5) p3 = np.linspace(0, 1, 10) # can use meshgrid to create a 3D array of test data P1, P2, P3 = np.meshgrid(p1, p2, p3, indexing='ij') f = np.sqrt(P1) + P2 * P3 # verify the shape matches the order and size of the input params print(f.shape) # Create regular grid interpolator instance interp = MetaModelStructured(method='cubic', training_data_gradients=True) interp.add_input('p1', 0.5, p1) interp.add_input('p2', 0.0, p2) interp.add_input('p3', 3.14, p3) interp.add_output('f', 0.0, f) # Set up the OpenMDAO model model = Group() model.add_subsystem('comp', interp, promotes=["*"]) prob = Problem(model) prob.setup() # set inputs prob['p1'] = 55.12 prob['p2'] = -2.14 prob['p3'] = 0.323 prob.run_model() computed = prob['f'] actual = 6.73306472 assert_almost_equal(computed, actual) # we can verify all gradients by checking against finit-difference prob.check_partials(compact_print=True)
def __init__(self): super(Model, self).__init__() self.add('px', ParamComp('x', 2.0)) self.add('comp1', SimpleComp()) sub = self.add('sub', Group()) sub.add('comp2', SimpleComp()) sub.add('comp3', SimpleComp()) self.add('comp4', SimpleComp()) self.connect('px.x', 'comp1.x') self.connect('comp1.y', 'sub.comp2.x') self.connect('sub.comp2.y', 'sub.comp3.x') self.connect('sub.comp3.y', 'comp4.x') self.sub.fd_options['force_fd'] = True
def test_includes_and_excludes(self): size = 3 prob = Problem(Group(), impl=impl) G1 = prob.root.add('G1', ParallelGroup()) G1.add('P1', IndepVarComp('x', np.ones(size, float) * 1.0)) G1.add('P2', IndepVarComp('x', np.ones(size, float) * 2.0)) prob.root.add('C1', ABCDArrayComp(size)) prob.root.connect('G1.P1.x', 'C1.a') prob.root.connect('G1.P2.x', 'C1.b') prob.driver.add_recorder(self.recorder) self.recorder.options['includes'] = ['C1.*'] self.recorder.options['excludes'] = ['*.out*'] self.recorder.options['record_params'] = True self.recorder.options['record_resids'] = True prob.setup(check=False) t0, t1 = run(prob) self.recorder.close() coordinate = ['Driver', (1, )] expected_params = [ ("C1.a", [1.0, 1.0, 1.0]), ("C1.b", [2.0, 2.0, 2.0]), ] expected_unknowns = [ ("C1.c", np.array([3.0, 3.0, 3.0])), ("C1.d", np.array([-1.0, -1.0, -1.0])), ] expected_resids = [ ("C1.c", np.array([0.0, 0.0, 0.0])), ("C1.d", np.array([0.0, 0.0, 0.0])), ] self.assertIterationDataRecorded( ((coordinate, (t0, t1), expected_params, expected_unknowns, expected_resids), ), self.eps, prob.root)
def test_distrib_idx_in_full_out(self): size = 11 p = Problem(root=Group(), impl=impl) top = p.root top.add("C1", InOutArrayComp(size)) top.add("C2", DistribInputComp(size)) top.connect('C1.outvec', 'C2.invec') p.setup(check=False) top.C1.params['invec'] = np.array(range(size, 0, -1), float) p.run() self.assertTrue( all(top.C2.unknowns['outvec'] == np.array(range(size, 0, -1), float) * 4))
def test_distrib_full_in_out(self): size = 11 p = Problem(root=Group(), impl=impl) top = p.root top.add("C1", InOutArrayComp(size)) top.add("C2", DistribCompSimple(size)) top.connect('C1.outvec', 'C2.invec') p.setup(check=False) top.C1.params['invec'] = np.ones(size, float) * 5.0 p.run() self.assertTrue( all(top.C2.unknowns['outvec'] == np.ones(size, float) * 7.5))
def setup(self): self.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) self.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) self.mda = mda = self.add_subsystem('mda', Group(), promotes=['x', 'z', 'y1', 'y2']) mda.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) mda.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) self.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0, y1=0.0, y2=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) self.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) self.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) nl = self.options['nonlinear_solver'] self.nonlinear_solver = nl() if inspect.isclass(nl) else nl if self.options['nl_atol']: self.nonlinear_solver.options['atol'] = self.options['nl_atol'] if self.options['nl_maxiter']: self.nonlinear_solver.options['maxiter'] = self.options[ 'nl_maxiter'] ln = self.options['linear_solver'] self.linear_solver = ln() if inspect.isclass(ln) else ln if self.options['ln_atol']: self.linear_solver.options['atol'] = self.options['ln_atol'] if self.options['ln_maxiter']: self.linear_solver.options['maxiter'] = self.options['ln_maxiter']
def test_sellar(self): prob = Problem() prob.root = Group() prob.root.nl_solver = RunOnce() prob.root.add('comp', ExecComp('y=x*2.0')) prob.root.add('P1', ParamComp('x', 3.0)) prob.root.connect('P1.x', 'comp.x') prob.setup(check=False) prob.run() y = prob.root.unknowns['comp.y'] assert_rel_error(self, y, 6.0, .000001) # Make sure we aren't iterating like crazy self.assertEqual(prob.root.nl_solver.iter_count, 1)
def test_simple_float(self): prob = Problem() prob.root = root = Group() root.add('x_param', IndepVarComp('x', 17.0), promotes=['x']) root.add('y_param', IndepVarComp('y', 19.0), promotes=['y']) root.add('mycomp', Paraboloid(), promotes=['x', 'y', 'f_xy']) # This will give poor FD, but good CS root.mycomp.fd_options['step_size'] = 1.0e1 root.mycomp.fd_options['force_fd'] = True root.mycomp.fd_options['form'] = 'complex_step' prob.setup(check=False) prob.run() J = prob.calc_gradient(['x'], ['f_xy'], mode='fwd', return_format='dict') assert_rel_error(self, J['f_xy']['x'][0][0], 47.0, 1e-6)
def test_conflicting_promoted_state_vars(self): # verify we get an error if we have conflicting promoted state variables root = Group() comp1 = SimpleImplicitComp() comp2 = SimpleImplicitComp() root.add('c1', comp1, promotes=['z']) # promote the state, z root.add('c2', comp2, promotes=['z']) # promote the state, z, again.. BAD prob = Problem(root) with self.assertRaises(RuntimeError) as err: prob.setup(check=False) expected_msg = "Promoted name 'z' matches multiple unknowns: ['c1.z', 'c2.z']" self.assertEqual(str(err.exception), expected_msg)
def test_array2D(self): group = Group() group.add('x_param', ParamComp('x', np.ones((2, 2))), promotes=['*']) group.add('mycomp', ArrayComp2D(), promotes=['x', 'y']) prob = Problem() prob.root = group prob.root.ln_solver = LinearGaussSeidel() prob.setup(check=False) prob.run() J = prob.calc_gradient(['x'], ['y'], mode='fwd', return_format='dict') Jbase = prob.root.mycomp._jacobian_cache diff = np.linalg.norm(J['y']['x'] - Jbase['y', 'x']) assert_rel_error(self, diff, 0.0, 1e-8) J = prob.calc_gradient(['x'], ['y'], mode='rev', return_format='dict') diff = np.linalg.norm(J['y']['x'] - Jbase['y', 'x']) assert_rel_error(self, diff, 0.0, 1e-8)