def test_converge_diverge_groups(self): # Test derivatives for converge-diverge-groups topology. prob = Problem() model = prob.model = ConvergeDivergeGroups() model.linear_solver = LinearRunOnce() model.g1.linear_solver = LinearRunOnce() model.g1.g2.linear_solver = LinearRunOnce() model.g3.linear_solver = LinearRunOnce() prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') prob.run_model() wrt = ['iv.x'] of = ['c7.y1'] # Make sure value is fine. assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6) J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_rel_error(self, J['c7.y1', 'iv.x'][0][0], -40.75, 1e-6) prob.setup(check=False, mode='rev') prob.run_model() J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_rel_error(self, J['c7.y1', 'iv.x'][0][0], -40.75, 1e-6)
def test_connect_src_indices(self): import numpy as np from openmdao.api import Problem, IndepVarComp, ExecComp p = Problem() p.model.add_subsystem('indep', IndepVarComp('x', np.ones(5))) p.model.add_subsystem('C1', ExecComp('y=sum(x)*2.0', x=np.zeros(3))) p.model.add_subsystem('C2', ExecComp('y=sum(x)*4.0', x=np.zeros(2))) # connect C1.x to the first 3 entries of indep.x p.model.connect('indep.x', 'C1.x', src_indices=[0, 1, 2]) # connect C2.x to the last 2 entries of indep.x # use -2 (same as 3 in this case) to show that negative indices work. p.model.connect('indep.x', 'C2.x', src_indices=[-2, 4]) p.set_solver_print(level=0) p.setup() p.run_model() assert_rel_error(self, p['C1.x'], np.ones(3)) assert_rel_error(self, p['C1.y'], 6.) assert_rel_error(self, p['C2.x'], np.ones(2)) assert_rel_error(self, p['C2.y'], 8.)
def test_globaljac_err(self): prob = Problem() model = prob.model = Group() model.add_subsystem('x_param', IndepVarComp('length', 3.0), promotes=['length']) model.add_subsystem('mycomp', TestExplCompSimpleDense(), promotes=['length', 'width', 'area']) model.linear_solver = LinearBlockJac() prob.set_solver_print(level=0) prob.model.jacobian = AssembledJacobian() prob.setup(check=False, mode='fwd') prob['width'] = 2.0 prob.run_model() of = ['area'] wrt = ['length'] with self.assertRaises(RuntimeError) as context: prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') self.assertEqual(str(context.exception), "A block linear solver 'LN: LNBJ' is being used with" " an AssembledJacobian in system ''")
def test_set_order(self): order_list = [] prob = Problem() model = prob.model model.nonlinear_solver = NonlinearRunOnce() model.add_subsystem('indeps', IndepVarComp('x', 1.)) model.add_subsystem('C1', ReportOrderComp(order_list)) model.add_subsystem('C2', ReportOrderComp(order_list)) model.add_subsystem('C3', ReportOrderComp(order_list)) model.connect('indeps.x', 'C1.x') model.connect('C1.y', 'C2.x') model.connect('C2.y', 'C3.x') prob.set_solver_print(level=0) self.assertEqual(['indeps', 'C1', 'C2', 'C3'], [s.name for s in model._static_subsystems_allprocs]) prob.setup(check=False) prob.run_model() self.assertEqual(['C1', 'C2', 'C3'], order_list) order_list[:] = [] # Big boy rules model.set_order(['indeps', 'C2', 'C1', 'C3']) prob.setup(check=False) prob.run_model() self.assertEqual(['C2', 'C1', 'C3'], order_list) # Extra with self.assertRaises(ValueError) as cm: model.set_order(['indeps', 'C2', 'junk', 'C1', 'C3']) self.assertEqual(str(cm.exception), ": subsystem(s) ['junk'] found in subsystem order but don't exist.") # Missing with self.assertRaises(ValueError) as cm: model.set_order(['indeps', 'C2', 'C3']) self.assertEqual(str(cm.exception), ": ['C1'] expected in subsystem order and not found.") # Extra and Missing with self.assertRaises(ValueError) as cm: model.set_order(['indeps', 'C2', 'junk', 'C1', 'junk2']) self.assertEqual(str(cm.exception), ": ['C3'] expected in subsystem order and not found.\n" ": subsystem(s) ['junk', 'junk2'] found in subsystem order but don't exist.") # Dupes with self.assertRaises(ValueError) as cm: model.set_order(['indeps', 'C2', 'C1', 'C3', 'C1']) self.assertEqual(str(cm.exception), ": Duplicate name(s) found in subsystem order list: ['C1']")
def test_linear_system(self): """Check against the scipy solver.""" model = Group() x = np.array([1, 2, -3]) A = np.array([[5.0, -3.0, 2.0], [1.0, 7.0, -4.0], [1.0, 0.0, 8.0]]) b = A.dot(x) model.add_subsystem('p1', IndepVarComp('A', A)) model.add_subsystem('p2', IndepVarComp('b', b)) lingrp = model.add_subsystem('lingrp', Group(), promotes=['*']) lingrp.add_subsystem('lin', LinearSystemComp(size=3, partial_type="matrix_free")) model.connect('p1.A', 'lin.A') model.connect('p2.b', 'lin.b') prob = Problem(model) prob.setup() lingrp.linear_solver = ScipyKrylov() prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['lin.x'], x, .0001) assert_rel_error(self, prob.model._residuals.get_norm(), 0.0, 1e-10)
def test_hierarchy_iprint(self): prob = Problem() model = prob.model model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0]))) sub1 = model.add_subsystem('sub1', Group()) sub2 = sub1.add_subsystem('sub2', Group()) g1 = sub2.add_subsystem('g1', SubSellar()) g2 = model.add_subsystem('g2', SubSellar()) model.connect('pz.z', 'sub1.sub2.g1.z') model.connect('sub1.sub2.g1.y2', 'g2.x') model.connect('g2.y2', 'sub1.sub2.g1.x') model.nonlinear_solver = NewtonSolver() model.linear_solver = ScipyKrylov() model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 0 g1.nonlinear_solver = NewtonSolver() g1.linear_solver = LinearBlockGS() g2.nonlinear_solver = NewtonSolver() g2.linear_solver = ScipyKrylov() g2.linear_solver.precon = LinearBlockGS() g2.linear_solver.precon.options['maxiter'] = 2 prob.set_solver_print(level=2) prob.setup(check=False) output = run_model(prob)
def test_converge_diverge(self): prob = Problem() prob.model = ConvergeDiverge() prob.setup(vector_class=PETScVector, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6) indep_list = ['iv.x'] unknown_list = ['c7.y1'] J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c7.y1', 'iv.x'][0][0], -40.75, 1e-6) prob.setup(vector_class=PETScVector, check=False, mode='rev') prob.run_model() assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6) J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c7.y1', 'iv.x'][0][0], -40.75, 1e-6) assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6)
def test_diamond(self): prob = Problem() prob.model = Diamond() prob.setup(vector_class=PETScVector, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['c4.y1'], 46.0, 1e-6) assert_rel_error(self, prob['c4.y2'], -93.0, 1e-6) indep_list = ['iv.x'] unknown_list = ['c4.y1', 'c4.y2'] J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c4.y1', 'iv.x'][0][0], 25, 1e-6) assert_rel_error(self, J['c4.y2', 'iv.x'][0][0], -40.5, 1e-6) prob.setup(vector_class=PETScVector, check=False, mode='rev') prob.run_model() assert_rel_error(self, prob['c4.y1'], 46.0, 1e-6) assert_rel_error(self, prob['c4.y2'], -93.0, 1e-6) J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c4.y1', 'iv.x'][0][0], 25, 1e-6) assert_rel_error(self, J['c4.y2', 'iv.x'][0][0], -40.5, 1e-6)
def test_debug_print_option_totals_color(self): prob = Problem() prob.model = FanInGrouped() prob.model.linear_solver = LinearBlockGS() prob.model.sub.linear_solver = LinearBlockGS() prob.model.add_design_var('iv.x1', parallel_deriv_color='par_dv') prob.model.add_design_var('iv.x2', parallel_deriv_color='par_dv') prob.model.add_design_var('iv.x3') prob.model.add_objective('c3.y') prob.driver.options['debug_print'] = ['totals'] prob.setup(check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_driver() indep_list = ['iv.x1', 'iv.x2', 'iv.x3'] unknown_list = ['c3.y'] stdout = sys.stdout strout = StringIO() sys.stdout = strout try: _ = prob.compute_totals(unknown_list, indep_list, return_format='flat_dict', debug_print=not prob.comm.rank) finally: sys.stdout = stdout output = strout.getvalue() if not prob.comm.rank: self.assertTrue('Solving color: par_dv (iv.x1, iv.x2)' in output) self.assertTrue('Solving variable: iv.x3' in output)
def test_scaled_derivs(self): prob = Problem() prob.model = model = SellarDerivatives() model.add_design_var('z') model.add_objective('obj') model.add_constraint('con1') prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() base = prob.compute_totals(of=['obj', 'con1'], wrt=['z']) prob = Problem() prob.model = model = SellarDerivatives() model.add_design_var('z', ref=2.0, ref0=0.0) model.add_objective('obj', ref=1.0, ref0=0.0) model.add_constraint('con1', lower=0, ref=2.0, ref0=0.0) prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() derivs = prob.driver._compute_totals(of=['obj_cmp.obj', 'con_cmp1.con1'], wrt=['pz.z'], return_format='dict') assert_rel_error(self, base[('con1', 'z')][0], derivs['con_cmp1.con1']['pz.z'][0], 1e-5) assert_rel_error(self, base[('obj', 'z')][0]*2.0, derivs['obj_cmp.obj']['pz.z'][0], 1e-5)
def test_solve_linear_scipy(self): """Solve implicit system with ScipyKrylov.""" # use ScipyIterativeSolver here to check for deprecation warning and verify that the deprecated # class still gets the right answer without duplicating this test. msg = "ScipyIterativeSolver is deprecated. Use ScipyKrylov instead." with assert_warning(DeprecationWarning, msg): group = TestImplicitGroup(lnSolverClass=lambda : ScipyIterativeSolver(solver=self.linear_solver_name)) p = Problem(group) p.setup(check=False) p.set_solver_print(level=0) # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.run_solve_linear(['linear'], 'fwd') output = d_outputs._data assert_rel_error(self, output, group.expected_solution, 1e-15) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.run_solve_linear(['linear'], 'rev') output = d_residuals._data assert_rel_error(self, output, group.expected_solution, 1e-15)
def test_hierarchy_iprint3(self): prob = Problem() model = prob.model model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0]))) sub1 = model.add_subsystem('sub1', Group()) sub2 = sub1.add_subsystem('sub2', Group()) g1 = sub2.add_subsystem('g1', SubSellar()) g2 = model.add_subsystem('g2', SubSellar()) model.connect('pz.z', 'sub1.sub2.g1.z') model.connect('sub1.sub2.g1.y2', 'g2.x') model.connect('g2.y2', 'sub1.sub2.g1.x') model.nonlinear_solver = NonlinearBlockJac() sub1.nonlinear_solver = NonlinearBlockJac() sub2.nonlinear_solver = NonlinearBlockJac() g1.nonlinear_solver = NonlinearBlockJac() g2.nonlinear_solver = NonlinearBlockJac() prob.set_solver_print(level=2) prob.setup(check=False) output = run_model(prob)
def test_inp_inp_promoted_w_explicit_src(self): p = Problem(model=Group()) root = p.model G1 = root.add_subsystem("G1", Group()) G2 = G1.add_subsystem("G2", Group(), promotes=['x']) G2.add_subsystem("C1", ExecComp('y=x*2.0')) G2.add_subsystem("C2", IndepVarComp('x', 1.0), promotes=['x']) G3 = root.add_subsystem("G3", Group()) G4 = G3.add_subsystem("G4", Group(), promotes=['x']) C3 = G4.add_subsystem("C3", ExecComp('y=x*2.0'), promotes=['x']) C4 = G4.add_subsystem("C4", ExecComp('y=x*2.0'), promotes=['x']) p.model.connect('G1.x', 'G3.x') p.setup(check=False) p.set_solver_print(level=0) # setting promoted name will set the value into the outputs, but will # not propagate it to the inputs. That will happen during run_model(). p['G1.x'] = 999. p.run_model() self.assertEqual(C3._inputs['x'], 999.) self.assertEqual(C4._inputs['x'], 999.)
def test_raise_no_error_on_singular(self): prob = Problem() model = prob.model comp = IndepVarComp() comp.add_output('dXdt:TAS', val=1.0) comp.add_output('accel_target', val=2.0) model.add_subsystem('des_vars', comp, promotes=['*']) teg = model.add_subsystem('thrust_equilibrium_group', subsys=Group()) teg.add_subsystem('dynamics', ExecComp('z = 2.0*thrust'), promotes=['*']) thrust_bal = BalanceComp() thrust_bal.add_balance(name='thrust', val=1207.1, lhs_name='dXdt:TAS', rhs_name='accel_target', eq_units='m/s**2', lower=-10.0, upper=10000.0) teg.add_subsystem(name='thrust_bal', subsys=thrust_bal, promotes_inputs=['dXdt:TAS', 'accel_target'], promotes_outputs=['thrust']) teg.linear_solver = DirectSolver(assemble_jac=False) teg.nonlinear_solver = NewtonSolver() teg.nonlinear_solver.options['solve_subsystems'] = True teg.nonlinear_solver.options['max_sub_solves'] = 1 teg.nonlinear_solver.options['atol'] = 1e-4 prob.setup(check=False) prob.set_solver_print(level=0) teg.linear_solver.options['err_on_singular'] = False prob.run_model()
def test_const_jacobian(self): import numpy as np from openmdao.api import Problem, Group, IndepVarComp, DirectSolver from openmdao.jacobians.tests.test_jacobian_features import SimpleCompConst model = Group(assembled_jac_type='dense') comp = IndepVarComp() for name, val in (('x', 1.), ('y1', np.ones(2)), ('y2', np.ones(2)), ('y3', np.ones(2)), ('z', np.ones((2, 2)))): comp.add_output(name, val) model.add_subsystem('input_comp', comp, promotes=['x', 'y1', 'y2', 'y3', 'z']) problem = Problem(model=model) problem.set_solver_print(0) model.linear_solver = DirectSolver(assemble_jac=True) model.add_subsystem('simple', SimpleCompConst(), promotes=['x', 'y1', 'y2', 'y3', 'z', 'f', 'g']) problem.setup(check=False) problem.run_model() totals = problem.compute_totals(['f', 'g'], ['x', 'y1', 'y2', 'y3', 'z']) assert_rel_error(self, totals['f', 'x'], [[1.]]) assert_rel_error(self, totals['f', 'z'], np.ones((1, 4))) assert_rel_error(self, totals['f', 'y1'], np.zeros((1, 2))) assert_rel_error(self, totals['f', 'y2'], np.zeros((1, 2))) assert_rel_error(self, totals['f', 'y3'], np.zeros((1, 2))) assert_rel_error(self, totals['g', 'z'], np.zeros((4, 4))) assert_rel_error(self, totals['g', 'y1'], [[1, 0], [1, 0], [0, 1], [0, 1]]) assert_rel_error(self, totals['g', 'y2'], [[1, 0], [0, 1], [1, 0], [0, 1]]) assert_rel_error(self, totals['g', 'y3'], [[1, 0], [1, 0], [0, 1], [0, 1]]) assert_rel_error(self, totals['g', 'x'], [[1], [0], [0], [1]])
def test_backtracking(self): top = Problem() top.model.add_subsystem('px', IndepVarComp('x', 1.0)) top.model.add_subsystem('comp', ImplCompTwoStates()) top.model.connect('px.x', 'comp.x') top.model.nonlinear_solver = BroydenSolver() top.model.nonlinear_solver.options['maxiter'] = 25 top.model.nonlinear_solver.options['diverge_limit'] = 0.5 top.model.nonlinear_solver.options['state_vars'] = ['comp.y', 'comp.z'] top.model.linear_solver = DirectSolver() top.setup(check=False) top.model.nonlinear_solver.linesearch = BoundsEnforceLS(bound_enforcement='vector') # Setup again because we assigned a new linesearch top.setup(check=False) top.set_solver_print(level=2) # Test lower bound: should go to the lower bound and stall top['px.x'] = 2.0 top['comp.y'] = 0.0 top['comp.z'] = 1.6 top.run_model() assert_rel_error(self, top['comp.z'], 1.5, 1e-8) # Test upper bound: should go to the upper bound and stall top['px.x'] = 0.5 top['comp.y'] = 0.0 top['comp.z'] = 2.4 top.run_model() assert_rel_error(self, top['comp.z'], 2.5, 1e-8)
def test_assert_check_partials_no_exception_expected(self): import numpy as np from openmdao.api import Problem, ExplicitComponent from openmdao.utils.assert_utils import assert_check_partials class MyComp(ExplicitComponent): def setup(self): self.add_input('x1', 3.0) self.add_input('x2', 5.0) self.add_output('y', 5.5) self.declare_partials(of='*', wrt='*') def compute(self, inputs, outputs): outputs['y'] = 3.0 * inputs['x1'] + 4.0 * inputs['x2'] def compute_partials(self, inputs, partials): """Correct derivative.""" J = partials J['y', 'x1'] = np.array([3.0]) J['y', 'x2'] = np.array([4.0]) prob = Problem() prob.model = MyComp() prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() data = prob.check_partials(out_stream=None) atol = 1.e-6 rtol = 1.e-6 assert_check_partials(data, atol, rtol)
def test_abs_array_complex_step(self): prob = Problem(model=Group()) C1 = prob.model.add_subsystem('C1', ExecComp('y=2.0*abs(x)', x=np.ones(3)*-2.0, y=np.zeros(3))) prob.setup(check=False) prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, C1._outputs['y'], np.ones(3)*4.0, 0.00001) # any positive C1.x should give a 2.0 derivative for dy/dx C1._inputs['x'] = np.ones(3)*1.0e-10 C1._linearize() assert_rel_error(self, C1._jacobian['y', 'x'], np.eye(3)*2.0, 0.00001) C1._inputs['x'] = np.ones(3)*-3.0 C1._linearize() assert_rel_error(self, C1._jacobian['y', 'x'], np.eye(3)*-2.0, 0.00001) C1._inputs['x'] = np.zeros(3) C1._linearize() assert_rel_error(self, C1._jacobian['y', 'x'], np.eye(3)*2.0, 0.00001) C1._inputs['x'] = np.array([1.5, -0.6, 2.4]) C1._linearize() expect = np.zeros((3, 3)) expect[0, 0] = 2.0 expect[1, 1] = -2.0 expect[2, 2] = 2.0 assert_rel_error(self, C1._jacobian['y', 'x'], expect, 0.00001)
def test_guess_nonlinear_resids_read_only(self): class ImpWithInitial(ImplicitComponent): def setup(self): self.add_input('x', 3.0) self.add_output('y', 4.0) def guess_nonlinear(self, inputs, outputs, resids): # inputs is read_only, should not be allowed resids['y'] = 0. group = Group() group.add_subsystem('px', IndepVarComp('x', 77.0)) group.add_subsystem('comp1', ImpWithInitial()) group.add_subsystem('comp2', ImpWithInitial()) group.connect('px.x', 'comp1.x') group.connect('comp1.y', 'comp2.x') group.nonlinear_solver = NewtonSolver() group.nonlinear_solver.options['maxiter'] = 1 prob = Problem(model=group) prob.set_solver_print(level=0) prob.setup(check=False) with self.assertRaises(ValueError) as cm: prob.run_model() self.assertEqual(str(cm.exception), "Attempt to set value of 'y' in residual vector " "when it is read only.")
def test_fan_out_grouped(self): prob = Problem(FanOutGrouped()) of=['c2.y', "c3.y"] wrt=['iv.x'] prob.setup(vector_class=PETScVector, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x']) assert_rel_error(self, J['c2.y', 'iv.x'][0][0], -6.0, 1e-6) assert_rel_error(self, J['c3.y', 'iv.x'][0][0], 15.0, 1e-6) assert_rel_error(self, prob['c2.y'], -6.0, 1e-6) assert_rel_error(self, prob['c3.y'], 15.0, 1e-6) prob.setup(vector_class=PETScVector, check=False, mode='rev') prob.run_model() J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x']) assert_rel_error(self, J['c2.y', 'iv.x'][0][0], -6.0, 1e-6) assert_rel_error(self, J['c3.y', 'iv.x'][0][0], 15.0, 1e-6) assert_rel_error(self, prob['c2.y'], -6.0, 1e-6) assert_rel_error(self, prob['c3.y'], 15.0, 1e-6)
def test_fan_in_grouped(self): prob = Problem() prob.model = FanInGrouped2() prob.setup(vector_class=PETScVector, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() indep_list = ['p1.x', 'p2.x'] unknown_list = ['c3.y'] assert_rel_error(self, prob['c3.y'], 29.0, 1e-6) J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c3.y', 'p1.x'][0][0], -6.0, 1e-6) assert_rel_error(self, J['c3.y', 'p2.x'][0][0], 35.0, 1e-6) assert_rel_error(self, prob['c3.y'], 29.0, 1e-6) prob.setup(vector_class=PETScVector, check=False, mode='rev') prob.run_model() assert_rel_error(self, prob['c3.y'], 29.0, 1e-6) J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c3.y', 'p1.x'][0][0], -6.0, 1e-6) assert_rel_error(self, J['c3.y', 'p2.x'][0][0], 35.0, 1e-6) assert_rel_error(self, prob['c3.y'], 29.0, 1e-6)
def test_const_jacobian(self): model = Group() comp = IndepVarComp() for name, val in (('x', 1.), ('y1', np.ones(2)), ('y2', np.ones(2)), ('y3', np.ones(2)), ('z', np.ones((2, 2)))): comp.add_output(name, val) model.add_subsystem('input_comp', comp, promotes=['x', 'y1', 'y2', 'y3', 'z']) problem = Problem(model=model) problem.set_solver_print(level=0) model.linear_solver = ScipyKrylov() model.jacobian = COOJacobian() model.add_subsystem('simple', SimpleCompConst(), promotes=['x', 'y1', 'y2', 'y3', 'z', 'f', 'g']) problem.setup(check=False) problem.run_model() totals = problem.compute_totals(['f', 'g'], ['x', 'y1', 'y2', 'y3', 'z']) jacobian = {} jacobian['f', 'x'] = [[1.]] jacobian['f', 'z'] = np.ones((1, 4)) jacobian['f', 'y1'] = np.zeros((1, 2)) jacobian['f', 'y2'] = np.zeros((1, 2)) jacobian['f', 'y3'] = np.zeros((1, 2)) jacobian['g', 'y1'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'y2'] = [[1, 0], [0, 1], [1, 0], [0, 1]] jacobian['g', 'y3'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'x'] = [[1], [0], [0], [1]] jacobian['g', 'z'] = np.zeros((4, 4)) assert_rel_error(self, totals, jacobian)
def test_circuit_full(self): from openmdao.api import Group, BroydenSolver, DirectSolver, Problem, IndepVarComp from openmdao.test_suite.scripts.circuit_analysis import Circuit p = Problem() model = p.model model.add_subsystem('ground', IndepVarComp('V', 0., units='V')) model.add_subsystem('source', IndepVarComp('I', 0.1, units='A')) model.add_subsystem('circuit', Circuit()) model.connect('source.I', 'circuit.I_in') model.connect('ground.V', 'circuit.Vg') p.setup() # Replace existing solver with BroydenSolver model.circuit.nonlinear_solver = BroydenSolver() model.circuit.nonlinear_solver.options['maxiter'] = 20 model.circuit.nonlinear_solver.linear_solver = DirectSolver() # set some initial guesses p['circuit.n1.V'] = 10. p['circuit.n2.V'] = 1. p.set_solver_print(level=2) p.run_model() assert_rel_error(self, p['circuit.n1.V'], 9.90830282, 1e-5) assert_rel_error(self, p['circuit.n2.V'], 0.73858486, 1e-5) # sanity check: should sum to .1 Amps assert_rel_error(self, p['circuit.R1.I'] + p['circuit.D1.I'], .1, 1e-6)
def test_fan_in_grouped_feature(self): from openmdao.api import Problem, IndepVarComp, ParallelGroup, ExecComp, PETScVector prob = Problem() model = prob.model model.add_subsystem('p1', IndepVarComp('x', 1.0)) model.add_subsystem('p2', IndepVarComp('x', 1.0)) parallel = model.add_subsystem('parallel', ParallelGroup()) parallel.add_subsystem('c1', ExecComp(['y=-2.0*x'])) parallel.add_subsystem('c2', ExecComp(['y=5.0*x'])) model.add_subsystem('c3', ExecComp(['y=3.0*x1+7.0*x2'])) model.connect("parallel.c1.y", "c3.x1") model.connect("parallel.c2.y", "c3.x2") model.connect("p1.x", "parallel.c1.x") model.connect("p2.x", "parallel.c2.x") prob.setup(vector_class=PETScVector, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['c3.y'], 29.0, 1e-6)
def test_sellar_opt(self): from openmdao.api import Problem, ScipyOptimizeDriver, ExecComp, IndepVarComp, DirectSolver from openmdao.test_suite.components.sellar_feature import SellarMDA prob = Problem() prob.model = SellarMDA() prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' # prob.driver.options['maxiter'] = 100 prob.driver.options['tol'] = 1e-8 prob.model.add_design_var('x', lower=0, upper=10) prob.model.add_design_var('z', lower=0, upper=10) prob.model.add_objective('obj') prob.model.add_constraint('con1', upper=0) prob.model.add_constraint('con2', upper=0) prob.setup() prob.set_solver_print(level=0) # Ask OpenMDAO to finite-difference across the model to compute the gradients for the optimizer prob.model.approx_totals() prob.run_driver() print('minimum found at') assert_rel_error(self, prob['x'][0], 0., 1e-5) assert_rel_error(self, prob['z'], [1.977639, 0.], 1e-5) print('minumum objective') assert_rel_error(self, prob['obj'][0], 3.18339395045, 1e-5)
def test_rev_mode_bug(self): prob = Problem() prob.model = SellarDerivatives(nonlinear_solver=NewtonSolver(), linear_solver=DirectSolver()) prob.setup(check=False, mode='rev') prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001) wrt = ['x', 'z'] of = ['obj', 'con1', 'con2'] Jbase = {} Jbase['con1', 'x'] = [[-0.98061433]] Jbase['con1', 'z'] = np.array([[-9.61002285, -0.78449158]]) Jbase['con2', 'x'] = [[0.09692762]] Jbase['con2', 'z'] = np.array([[1.94989079, 1.0775421]]) Jbase['obj', 'x'] = [[2.98061392]] Jbase['obj', 'z'] = np.array([[9.61001155, 1.78448534]]) J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') for key, val in iteritems(Jbase): assert_rel_error(self, J[key], val, .00001) # In the bug, the solver mode got switched from fwd to rev when it shouldn't # have been, causing a singular matrix and NaNs in the output. prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001)
def test_set_order_feature(self): from openmdao.api import Problem, IndepVarComp, NonlinearRunOnce from openmdao.core.tests.test_group import ReportOrderComp # this list will record the execution order of our C1, C2, and C3 components order_list = [] prob = Problem() model = prob.model model.nonlinear_solver = NonlinearRunOnce() model.add_subsystem('indeps', IndepVarComp('x', 1.)) model.add_subsystem('C1', ReportOrderComp(order_list)) model.add_subsystem('C2', ReportOrderComp(order_list)) model.add_subsystem('C3', ReportOrderComp(order_list)) prob.set_solver_print(level=0) self.assertEqual(['indeps', 'C1', 'C2', 'C3'], [s.name for s in model._static_subsystems_allprocs]) prob.setup(check=False) prob.run_model() self.assertEqual(['C1', 'C2', 'C3'], order_list) # reset the shared order list order_list[:] = [] # now swap C2 and C1 in the order model.set_order(['indeps', 'C2', 'C1', 'C3']) # after changing the order, we must call setup again prob.setup(check=False) prob.run_model() self.assertEqual(['C2', 'C1', 'C3'], order_list)
def test_solve_linear_scipy_maxiter(self): """Verify that ScipyKrylov abides by the 'maxiter' option.""" group = TestImplicitGroup(lnSolverClass=self.linear_solver_class) group.linear_solver.options['maxiter'] = 2 p = Problem(group) p.setup(check=False) p.set_solver_print(level=0) # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.run_solve_linear(['linear'], 'fwd') self.assertTrue(group.linear_solver._iter_count == 2) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.run_solve_linear(['linear'], 'rev') self.assertTrue(group.linear_solver._iter_count == 2)
def test_implicit_cycle_precon(self): prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 1.0)) model.add_subsystem('d1', SellarImplicitDis1()) model.add_subsystem('d2', SellarImplicitDis2()) model.connect('d1.y1', 'd2.y1') model.connect('d2.y2', 'd1.y2') model.nonlinear_solver = NewtonSolver() model.nonlinear_solver.options['maxiter'] = 5 model.nonlinear_solver.linesearch = BoundsEnforceLS() model.linear_solver = ScipyKrylov() model.linear_solver.precon = self.linear_solver_class() prob.setup(check=False) prob['d1.y1'] = 4.0 prob.set_solver_print() prob.run_model() res = model._residuals.get_norm() # Newton is kinda slow on this for some reason, this is how far it gets with directsolver too. self.assertLess(res, 2.0e-2)
def test_feature_simple(self): """Tests feature for adding a Scipy GMRES solver and calculating the derivatives.""" from openmdao.api import Problem, Group, IndepVarComp, ScipyKrylov from openmdao.test_suite.components.expl_comp_simple import TestExplCompSimpleDense # Tests derivatives on a simple comp that defines compute_jacvec. prob = Problem() model = prob.model model.add_subsystem('x_param', IndepVarComp('length', 3.0), promotes=['length']) model.add_subsystem('mycomp', TestExplCompSimpleDense(), promotes=['length', 'width', 'area']) model.linear_solver = ScipyKrylov() prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') prob['width'] = 2.0 prob.run_model() of = ['area'] wrt = ['length'] J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_rel_error(self, J['area', 'length'][0][0], 2.0, 1e-6)
def test_simple_array_comp2D_array_lo_hi(self): prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('widths', np.zeros((2, 2))), promotes=['*']) model.add_subsystem('comp', TestExplCompArrayDense(), promotes=['*']) model.add_subsystem('con', ExecComp('c = areas - 20.0', c=np.zeros((2, 2)), areas=np.zeros((2, 2))), promotes=['*']) model.add_subsystem('obj', ExecComp('o = areas[0, 0]', areas=np.zeros( (2, 2))), promotes=['*']) prob.set_solver_print(level=0) prob.driver = ScipyOptimizer() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False model.add_design_var('widths', lower=-50.0 * np.ones((2, 2)), upper=50.0 * np.ones((2, 2))) model.add_objective('o') model.add_constraint('c', equals=0.0) prob.setup(check=False) prob.run_driver() obj = prob['o'] assert_rel_error(self, obj, 20.0, 1e-6)
def test_raise_error_on_singular_with_densejac(self): prob = Problem() prob.model = model = Group() comp = IndepVarComp() comp.add_output('dXdt:TAS', val=1.0) comp.add_output('accel_target', val=2.0) model.add_subsystem('des_vars', comp, promotes=['*']) teg = model.add_subsystem('thrust_equilibrium_group', subsys=Group()) teg.add_subsystem('dynamics', ExecComp('z = 2.0*thrust'), promotes=['*']) thrust_bal = BalanceComp() thrust_bal.add_balance(name='thrust', val=1207.1, lhs_name='dXdt:TAS', rhs_name='accel_target', eq_units='m/s**2', lower=-10.0, upper=10000.0) teg.add_subsystem(name='thrust_bal', subsys=thrust_bal, promotes_inputs=['dXdt:TAS', 'accel_target'], promotes_outputs=['thrust']) teg.linear_solver = DirectSolver() teg.jacobian = DenseJacobian() teg.nonlinear_solver = NewtonSolver() teg.nonlinear_solver.options['solve_subsystems'] = True teg.nonlinear_solver.options['max_sub_solves'] = 1 teg.nonlinear_solver.options['atol'] = 1e-4 prob.setup(check=False) prob.set_solver_print(level=0) with self.assertRaises(RuntimeError) as cm: prob.run_model() expected_msg = "Singular entry found in 'thrust_equilibrium_group' for column associated with state/residual 'thrust_equilibrium_group.dynamics.z'." self.assertEqual(expected_msg, str(cm.exception))
def test_debug_print_option_totals(self): prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 50.0), promotes=['*']) model.add_subsystem('p2', IndepVarComp('y', 50.0), promotes=['*']) model.add_subsystem('comp', Paraboloid(), promotes=['*']) model.add_subsystem('con', ExecComp('c = - x + y'), promotes=['*']) prob.set_solver_print(level=0) prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False prob.driver.options['debug_print'] = ['totals'] model.add_design_var('x', lower=-50.0, upper=50.0) model.add_design_var('y', lower=-50.0, upper=50.0) model.add_objective('f_xy') model.add_constraint('c', upper=-15.0) prob.setup(check=False) stdout = sys.stdout strout = StringIO() sys.stdout = strout try: prob.run_driver() finally: sys.stdout = stdout output = strout.getvalue() self.assertTrue('Solving variable: comp.f_xy' in output) self.assertTrue('Solving variable: con.c' in output)
def test_sellar_group_nested(self): # This tests true nested gs. Subsolvers solve each Sellar system. Top # solver couples them together through variable x. # This version has the indepvarcomps removed so we can connect them together. class SellarModified(Group): """ Group containing the Sellar MDA. This version uses the disciplines with derivatives.""" def __init__(self): super(SellarModified, self).__init__() self.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) self.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) self.nonlinear_solver = NonlinearBlockGS() self.linear_solver = ScipyKrylov() prob = Problem() root = prob.model root.nonlinear_solver = NonlinearBlockGS() root.nonlinear_solver.options['maxiter'] = 20 root.add_subsystem('g1', SellarModified()) root.add_subsystem('g2', SellarModified()) root.connect('g1.y2', 'g2.x') root.connect('g2.y2', 'g1.x') prob.setup(check=False) prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['g1.y1'], 0.64, .00001) assert_rel_error(self, prob['g1.y2'], 0.80, .00001) assert_rel_error(self, prob['g2.y1'], 0.64, .00001) assert_rel_error(self, prob['g2.y2'], 0.80, .00001)
def test_compute_totals_basic_return_array(self): # Make sure 'array' return_format works. prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 0.0), promotes=['x']) model.add_subsystem('p2', IndepVarComp('y', 0.0), promotes=['y']) model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy']) model.add_design_var('x', lower=-50.0, upper=50.0) model.add_design_var('y', lower=-50.0, upper=50.0) model.add_objective('f_xy') prob.setup(check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_driver() of = ['comp.f_xy'] wrt = ['p1.x', 'p2.y'] derivs = prob.driver._compute_totals(of=of, wrt=wrt, return_format='array') assert_rel_error(self, derivs[0, 0], -6.0, 1e-6) assert_rel_error(self, derivs[0, 1], 8.0, 1e-6) prob.setup(check=False, mode='rev') prob.run_model() of = ['comp.f_xy'] wrt = ['p1.x', 'p2.y'] derivs = prob.driver._compute_totals(of=of, wrt=wrt, return_format='array') assert_rel_error(self, derivs[0, 0], -6.0, 1e-6) assert_rel_error(self, derivs[0, 1], 8.0, 1e-6)
def test_debug_print_option_totals_color(self): prob = Problem() prob.model = FanInGrouped() prob.model.linear_solver = LinearBlockGS() prob.model.sub.linear_solver = LinearBlockGS() prob.model.add_design_var('iv.x1', parallel_deriv_color='par_dv') prob.model.add_design_var('iv.x2', parallel_deriv_color='par_dv') prob.model.add_design_var('iv.x3') prob.model.add_objective('c3.y') prob.driver.options['debug_print'] = ['totals'] prob.setup(vector_class=vector_class, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_driver() indep_list = ['iv.x1', 'iv.x2', 'iv.x3'] unknown_list = ['c3.y'] stdout = sys.stdout strout = StringIO() sys.stdout = strout try: _ = prob.compute_totals(unknown_list, indep_list, return_format='flat_dict', debug_print=not prob.comm.rank) finally: sys.stdout = stdout output = strout.getvalue() if not prob.comm.rank: self.assertTrue('Solving color: par_dv (iv.x1, iv.x2)' in output) self.assertTrue('Solving variable: iv.x3' in output)
def test_jacobian_update_converge_limit(self): # This model needs jacobian updates to converge. prob = Problem() model = prob.model model.add_subsystem('p1', IndepVarComp('x', np.array([0, 20.0]))) model.add_subsystem('comp', SpedicatoHuang()) model.connect('p1.x', 'comp.x') model.nonlinear_solver = BroydenSolver() model.nonlinear_solver.options['state_vars'] = ['comp.y'] model.nonlinear_solver.options['maxiter'] = 20 model.nonlinear_solver.options['max_converge_failures'] = 1 model.nonlinear_solver.options['diverge_limit'] = np.inf model.nonlinear_solver.linear_solver = DirectSolver() prob.setup(check=False) prob.set_solver_print(level=2) prob.run_model() assert_rel_error(self, prob['comp.y'], np.array([-36.26230985, 10.20857237, -54.17658612]), 1e-6)
def test_vectorized_A(self): """Check against the scipy solver.""" model = Group() x = np.array([[1, 2, -3], [2, -1, 4]]) A = np.array([[[5.0, -3.0, 2.0], [1.0, 7.0, -4.0], [1.0, 0.0, 8.0]], [[2.0, 3.0, 4.0], [1.0, -1.0, -2.0], [3.0, 2.0, -2.0]]]) b = np.einsum('ijk,ik->ij', A, x) model.add_subsystem('p1', IndepVarComp('A', A)) model.add_subsystem('p2', IndepVarComp('b', b)) lingrp = model.add_subsystem('lingrp', Group(), promotes=['*']) lingrp.add_subsystem( 'lin', LinearSystemComp(size=3, vec_size=2, vectorize_A=True)) model.connect('p1.A', 'lin.A') model.connect('p2.b', 'lin.b') prob = Problem(model) prob.setup() lingrp.linear_solver = ScipyKrylov() prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['lin.x'], x, .0001) assert_rel_error(self, prob.model._residuals.get_norm(), 0.0, 1e-10) model.run_apply_nonlinear() with model._scaled_context_all(): val = model.lingrp.lin._residuals['x'] assert_rel_error(self, val, np.zeros((2, 3)), tolerance=1e-8)
def test_solve_linear_ksp_default(self): """Solve implicit system with PETScKrylov using default method.""" # use PetscKSP here to check for deprecation warning and verify that the deprecated # class still gets the right answer without duplicating this test. with warnings.catch_warnings(record=True) as w: group = TestImplicitGroup(lnSolverClass=PetscKSP) self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[0].category, DeprecationWarning)) self.assertEqual(str(w[0].message), "PetscKSP is deprecated. Use PETScKrylov instead.") p = Problem(group) p.setup(check=False) p.set_solver_print(level=0) # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.run_solve_linear(['linear'], 'fwd') output = d_outputs._data assert_rel_error(self, output, group.expected_solution, 1e-15) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.run_solve_linear(['linear'], 'rev') output = d_residuals._data assert_rel_error(self, output, group.expected_solution, 1e-15)
def test_case_tabular_thermo(self): prob = Problem() prob.model.set_input_defaults('fl_start.P', 17., units='psi') prob.model.set_input_defaults('fl_start.T', 500., units='degR') prob.model.set_input_defaults('fl_start.MN', 0.5) prob.model.set_input_defaults('fl_start.W', 100., units='lbm/s') fl_start = prob.model.add_subsystem( 'fl_start', FlowStart(thermo_method='TABULAR', thermo_data=AIR_JETA_TAB_SPEC, composition=TAB_AIR_FUEL_COMPOSITION)) fl_start.pyc_setup_output_ports( ) #note: must manually call this for stand alone element tests without a cycle group prob.set_solver_print(level=-1) prob.setup(check=False) prob['fl_start.P'] = 5.27 prob['fl_start.T'] = 444.23 prob['fl_start.W'] = 100.0 prob['fl_start.MN'] = 0.8 prob.run_model() tol = 1e-6 assert_near_equal(prob['fl_start.Fl_O:tot:P'], 5.27, tol) assert_near_equal(prob['fl_start.Fl_O:tot:T'], 444.23, tol) assert_near_equal(prob['fl_start.Fl_O:tot:h'], -24.02365656, tol) assert_near_equal(prob['fl_start.Fl_O:tot:S'], 1.66403163, tol) assert_near_equal(prob['fl_start.Fl_O:tot:gamma'], 1.40086187, tol) assert_near_equal(prob['fl_start.Fl_O:stat:W'], 100.0, tol) assert_near_equal(prob['fl_start.Fl_O:stat:MN'], 0.8, tol) assert_near_equal(prob['fl_start.Fl_O:stat:area'], 778.26812382, tol)
def test_const_jacobian(self): model = Group() comp = IndepVarComp() for name, val in (('x', 1.), ('y1', np.ones(2)), ('y2', np.ones(2)), ('y3', np.ones(2)), ('z', np.ones((2, 2)))): comp.add_output(name, val) model.add_subsystem('input_comp', comp, promotes=['x', 'y1', 'y2', 'y3', 'z']) problem = Problem(model=model) problem.set_solver_print(level=0) model.linear_solver = ScipyKrylov(assemble_jac=True) model.add_subsystem('simple', SimpleCompConst(), promotes=['x', 'y1', 'y2', 'y3', 'z', 'f', 'g']) problem.setup(check=False) problem.run_model() totals = problem.compute_totals(['f', 'g'], ['x', 'y1', 'y2', 'y3', 'z']) jacobian = {} jacobian['f', 'x'] = [[1.]] jacobian['f', 'z'] = np.ones((1, 4)) jacobian['f', 'y1'] = np.zeros((1, 2)) jacobian['f', 'y2'] = np.zeros((1, 2)) jacobian['f', 'y3'] = np.zeros((1, 2)) jacobian['g', 'y1'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'y2'] = [[1, 0], [0, 1], [1, 0], [0, 1]] jacobian['g', 'y3'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'x'] = [[1], [0], [0], [1]] jacobian['g', 'z'] = np.zeros((4, 4)) assert_rel_error(self, totals, jacobian)
def test_simple_semitotals(self, method, isplit, osplit): prob = Problem(coloring_dir=self.tempdir) model = prob.model = Group() sparsity = setup_sparsity(_BIGMASK) indeps, conns = setup_indeps(isplit, _BIGMASK.shape[1], 'indeps', 'sub.comp') model.add_subsystem('indeps', indeps) sub = model.add_subsystem('sub', CounterGroup()) sub.declare_coloring('*', method=method) comp = sub.add_subsystem( 'comp', SparseCompExplicit(sparsity, method, isplit=isplit, osplit=osplit)) for conn in conns: model.connect(*conn) for i in range(isplit): model.add_design_var('indeps.x%d' % i) for i in range(osplit): model.sub.comp.add_constraint('y%d' % i) prob.setup(check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() derivs = prob.driver._compute_totals( ) # this is when the dynamic coloring update happens start_nruns = sub._nruns derivs = prob.driver._compute_totals() self.assertEqual(sub._nruns - start_nruns, 10) _check_partial_matrix(sub, sub._jacobian._subjacs_info, sparsity, method)
def test_promote_src_indices(self): class MyComp1(ExplicitComponent): def setup(self): # this input will connect to entries 0, 1, and 2 of its source self.add_input('x', np.ones(3), src_indices=[0, 1, 2]) self.add_output('y', 1.0) def compute(self, inputs, outputs): outputs['y'] = np.sum(inputs['x']) * 2.0 class MyComp2(ExplicitComponent): def setup(self): # this input will connect to entries 3 and 4 of its source self.add_input('x', np.ones(2), src_indices=[3, 4]) self.add_output('y', 1.0) def compute(self, inputs, outputs): outputs['y'] = np.sum(inputs['x']) * 4.0 p = Problem() # by promoting the following output and inputs to 'x', they will # be automatically connected p.model.add_subsystem('indep', IndepVarComp('x', np.ones(5)), promotes_outputs=['x']) p.model.add_subsystem('C1', MyComp1(), promotes_inputs=['x']) p.model.add_subsystem('C2', MyComp2(), promotes_inputs=['x']) p.set_solver_print(level=0) p.setup() p.run_model() assert_rel_error(self, p['C1.x'], np.ones(3)) assert_rel_error(self, p['C1.y'], 6.) assert_rel_error(self, p['C2.x'], np.ones(2)) assert_rel_error(self, p['C2.y'], 8.)
def test_list_residuals_with_tol(self): from openmdao.test_suite.components.sellar import SellarImplicitDis1, SellarImplicitDis2 from openmdao.api import Problem, Group, IndepVarComp, NewtonSolver, ScipyKrylov, LinearBlockGS prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 1.0)) model.add_subsystem('d1', SellarImplicitDis1()) model.add_subsystem('d2', SellarImplicitDis2()) model.connect('d1.y1', 'd2.y1') model.connect('d2.y2', 'd1.y2') model.nonlinear_solver = NewtonSolver() model.nonlinear_solver.options['maxiter'] = 5 model.linear_solver = ScipyKrylov() model.linear_solver.precon = LinearBlockGS() prob.setup(check=False) prob.set_solver_print(level=-1) prob.run_model() resids = model.list_residuals(tol=0.01, values=False) self.assertEqual(sorted(resids), ['d2.y2',])
def test_simple_paraboloid_unconstrained_COBYLA(self): prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 50.0), promotes=['*']) model.add_subsystem('p2', IndepVarComp('y', 50.0), promotes=['*']) model.add_subsystem('comp', Paraboloid(), promotes=['*']) prob.set_solver_print(level=0) prob.driver = ScipyOptimizer() prob.driver.options['optimizer'] = 'COBYLA' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False model.add_design_var('x', lower=-50.0, upper=50.0) model.add_design_var('y', lower=-50.0, upper=50.0) model.add_objective('f_xy') prob.setup(check=False) prob.run_driver() assert_rel_error(self, prob['x'], 6.66666667, 1e-6) assert_rel_error(self, prob['y'], -7.3333333, 1e-6)
def test_converge_diverge_groups(self): # Test derivatives for converge-diverge-groups topology. prob = Problem() prob.model = ConvergeDivergeGroups() prob.model.linear_solver = self.linear_solver_class() prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') prob.run_model() wrt = ['iv.x'] of = ['c7.y1'] # Make sure value is fine. assert_near_equal(prob['c7.y1'], -102.7, 1e-6) J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_near_equal(J['c7.y1', 'iv.x'], [[-40.75]], 1e-6) prob.setup(check=False, mode='rev') prob.run_model() J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_near_equal(J['c7.y1', 'iv.x'], [[-40.75]], 1e-6)
def test_mix_same(self): # mix two identical streams and make sure you get twice the area and the same total pressure thermo = Thermo(janaf, AIR_MIX) p = Problem() p.model.set_input_defaults('P', 17., units='psi') p.model.set_input_defaults('T', 500., units='degR') p.model.set_input_defaults('MN', 0.5) p.model.set_input_defaults('W', 100., units='lbm/s') p.model.add_subsystem('start1', FlowStart(), promotes=['P', 'T', 'MN', 'W']) p.model.add_subsystem('start2', FlowStart(), promotes=['P', 'T', 'MN', 'W']) p.model.add_subsystem( 'mixer', Mixer(design=True, Fl_I1_elements=AIR_MIX, Fl_I2_elements=AIR_MIX)) connect_flow(p.model, 'start1.Fl_O', 'mixer.Fl_I1') connect_flow(p.model, 'start2.Fl_O', 'mixer.Fl_I2') p.set_solver_print(level=-1) p.setup() p['mixer.balance.P_tot'] = 17 p.run_model() tol = 2e-7 assert_near_equal(p['mixer.Fl_O:stat:area'], 2 * p['start1.Fl_O:stat:area'], tolerance=tol) assert_near_equal(p['mixer.Fl_O:tot:P'], p['P'], tolerance=tol) assert_near_equal(p['mixer.ER'], 1, tolerance=tol)
def test_sellar_state_connection(self): # Test derivatives across a converged Sellar model. prob = Problem() prob.model = SellarStateConnection( linear_solver=self.linear_solver_class(), nl_atol=1e-12) prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') prob.run_model() # Just make sure we are at the right answer assert_near_equal(prob['y1'], 25.58830273, .00001) assert_near_equal(prob['d2.y2'], 12.05848819, .00001) wrt = ['x', 'z'] of = ['obj', 'con1', 'con2'] Jbase = {} Jbase['con1', 'x'] = [[-0.98061433]] Jbase['con1', 'z'] = np.array([[-9.61002285, -0.78449158]]) Jbase['con2', 'x'] = [[0.09692762]] Jbase['con2', 'z'] = np.array([[1.94989079, 1.0775421]]) Jbase['obj', 'x'] = [[2.98061392]] Jbase['obj', 'z'] = np.array([[9.61001155, 1.78448534]]) J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') for key, val in Jbase.items(): assert_near_equal(J[key], val, .00001) prob.setup(check=False, mode='rev') prob.run_model() J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') for key, val in Jbase.items(): assert_near_equal(J[key], val, .00001)
def test_simple_matvec(self): # Tests derivatives on a simple comp that defines compute_jacvec. # Note, For DirectSolver, assemble_jac must be False for mat-vec. prob = Problem() model = prob.model model.add_subsystem('x_param', IndepVarComp('length', 3.0), promotes=['length']) model.add_subsystem('mycomp', TestExplCompSimpleJacVec(), promotes=['length', 'width', 'area']) model.linear_solver = self.linear_solver_class() prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') # Note, For DirectSolver, assemble_jac must be False for mat-vec. if isinstance(model.linear_solver, DirectSolver): model.linear_solver.options['assemble_jac'] = False prob['width'] = 2.0 prob.run_model() of = ['area'] wrt = ['length'] J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_near_equal(J['area', 'length'], [[2.0]], 1e-6) prob.setup(check=False, mode='rev') prob['width'] = 2.0 prob.run_model() J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_near_equal(J['area', 'length'], [[2.0]], 1e-6)
def runs_successfully(use_scal, coeffs): prob = Problem(model=Group()) prob.model.add_subsystem( 'row1', ScalingTestComp(row=1, coeffs=coeffs, use_scal=use_scal)) prob.model.add_subsystem( 'row2', ScalingTestComp(row=2, coeffs=coeffs, use_scal=use_scal)) prob.model.connect('row1.y', 'row2.x') prob.model.connect('row2.y', 'row1.x') prob.model.nonlinear_solver = NewtonSolver(maxiter=2, atol=1e-5, rtol=0) prob.model.nonlinear_solver.linear_solver = ScipyKrylov(maxiter=1) prob.set_solver_print(level=0) prob.setup(check=False) result = prob.run_model() success = not result[0] return success
def test_single_diamond_grouped(self): # Test derivatives for grouped diamond topology. prob = Problem() prob.model = Diamond() prob.model.linear_solver = self.linear_solver_class() prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') prob.run_model() wrt = ['iv.x'] of = ['c4.y1', 'c4.y2'] J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_near_equal(J['c4.y1', 'iv.x'], [[25]], 1e-6) assert_near_equal(J['c4.y2', 'iv.x'], [[-40.5]], 1e-6) prob.setup(check=False, mode='rev') prob.run_model() J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_near_equal(J['c4.y1', 'iv.x'], [[25]], 1e-6) assert_near_equal(J['c4.y2', 'iv.x'], [[-40.5]], 1e-6)
def test_inp_inp_promoted_w_prom_src(self): p = Problem() root = p.model G1 = root.add_subsystem("G1", Group(), promotes=['x']) G2 = G1.add_subsystem("G2", Group(), promotes=['x']) G2.add_subsystem("C1", ExecComp('y=x*2.0')) G2.add_subsystem("C2", IndepVarComp('x', 1.0), promotes=['x']) G3 = root.add_subsystem("G3", Group(), promotes=['x']) G4 = G3.add_subsystem("G4", Group(), promotes=['x']) C3 = G4.add_subsystem("C3", ExecComp('y=x*2.0'), promotes=['x']) C4 = G4.add_subsystem("C4", ExecComp('y=x*2.0'), promotes=['x']) p.setup() p.set_solver_print(level=0) # setting promoted name will set the value into the outputs, but will # not propagate it to the inputs. That will happen during run_model(). p['x'] = 999. p.run_model() self.assertEqual(C3._inputs['x'], 999.) self.assertEqual(C4._inputs['x'], 999.)
def test_feature_assert_check_partials_exception_expected(self): class MyComp(ExplicitComponent): def setup(self): self.add_input('x1', 3.0) self.add_input('x2', 5.0) self.add_output('y', 5.5) self.declare_partials(of='*', wrt='*') def compute(self, inputs, outputs): """ Compute outputs. """ outputs['y'] = 3.0 * inputs['x1'] + 4.0 * inputs['x2'] def compute_partials(self, inputs, partials): """Intentionally incorrect derivative.""" J = partials J['y', 'x1'] = np.array([4.0]) J['y', 'x2'] = np.array([40]) prob = Problem() prob.model = MyComp() prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() data = prob.check_partials(suppress_output=True) atol = 1.e-6 rtol = 1.e-6 try: assert_check_partials(data, atol, rtol) except ValueError as err: print(str(err))
def test_solve_linear_ksp_precon_left(self): """Solve implicit system with PetscKSP using a preconditioner.""" group = TestImplicitGroup(lnSolverClass=PetscKSP) precon = group.linear_solver.precon = DirectSolver() group.linear_solver.options['precon_side'] = 'left' group.linear_solver.options['ksp_type'] = 'richardson' p = Problem(group) p.setup(vector_class=PETScVector, check=False) p.set_solver_print(level=0) # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.run_linearize() group.run_solve_linear(['linear'], 'fwd') output = d_outputs._data assert_rel_error(self, output[1], group.expected_solution[0], 1e-15) assert_rel_error(self, output[5], group.expected_solution[1], 1e-15) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.run_linearize() group.run_solve_linear(['linear'], 'rev') output = d_residuals._data assert_rel_error(self, output[1], group.expected_solution[0], 3e-15) assert_rel_error(self, output[5], group.expected_solution[1], 3e-15) # test the direct solver and make sure KSP correctly recurses for _linearize precon = group.linear_solver.precon = DirectSolver() group.linear_solver.options['precon_side'] = 'left' group.linear_solver.options['ksp_type'] = 'richardson' p.setup(vector_class=PETScVector, check=False) # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.linear_solver._linearize() group.run_solve_linear(['linear'], 'fwd') output = d_outputs._data assert_rel_error(self, output[1], group.expected_solution[0], 1e-15) assert_rel_error(self, output[5], group.expected_solution[1], 1e-15) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.linear_solver._linearize() group.run_solve_linear(['linear'], 'rev') output = d_residuals._data assert_rel_error(self, output[1], group.expected_solution[0], 3e-15) assert_rel_error(self, output[5], group.expected_solution[1], 3e-15)
def test_solve_subsystems_internals(self): # Here we test that this feature is doing what it should do by counting the # number of calls in various places. class CountNewton(NewtonSolver): """ This version of Newton also counts how many times it runs in total.""" def __init__(self, **kwargs): super(CountNewton, self).__init__(**kwargs) self.total_count = 0 def _iter_execute(self): super(CountNewton, self)._iter_execute() self.total_count += 1 class CountDS(DirectSolver): """ This version of Newton also counts how many times it linearizes""" def __init__(self, **kwargs): super(CountDS, self).__init__(**kwargs) self.lin_count = 0 def _linearize(self): super(CountDS, self)._linearize() self.lin_count += 1 prob = Problem(model=DoubleSellar()) model = prob.model # each SubSellar group converges itself g1 = model.g1 g1.nonlinear_solver = CountNewton() g1.nonlinear_solver.options['rtol'] = 1.0e-5 g1.linear_solver = CountDS() # used for derivatives g2 = model.g2 g2.nonlinear_solver = CountNewton() g2.nonlinear_solver.options['rtol'] = 1.0e-5 g2.linear_solver = DirectSolver() # Converge the outer loop with Gauss Seidel, with a looser tolerance. model.nonlinear_solver = NewtonSolver() model.linear_solver = ScipyKrylov() # Enfore behavior: max_sub_solves = 0 means we run once during init model.nonlinear_solver.options['maxiter'] = 5 model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 0 prob.set_solver_print(level=0) prob.setup() prob.run_model() # Verifying subsolvers ran self.assertEqual(g1.nonlinear_solver.total_count, 2) self.assertEqual(g2.nonlinear_solver.total_count, 2) self.assertEqual(g1.linear_solver.lin_count, 2) prob = Problem(model=DoubleSellar()) model = prob.model # each SubSellar group converges itself g1 = model.g1 g1.nonlinear_solver = CountNewton() g1.nonlinear_solver.options['rtol'] = 1.0e-5 g1.linear_solver = CountDS() # used for derivatives g2 = model.g2 g2.nonlinear_solver = CountNewton() g2.nonlinear_solver.options['rtol'] = 1.0e-5 g2.linear_solver = DirectSolver() # Converge the outer loop with Gauss Seidel, with a looser tolerance. model.nonlinear_solver = NewtonSolver() model.linear_solver = ScipyKrylov() # Enforce Behavior: baseline model.nonlinear_solver.options['maxiter'] = 5 model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 5 prob.set_solver_print(level=0) prob.setup() prob.run_model() # Verifying subsolvers ran self.assertEqual(g1.nonlinear_solver.total_count, 5) self.assertEqual(g2.nonlinear_solver.total_count, 5) self.assertEqual(g1.linear_solver.lin_count, 5) prob = Problem(model=DoubleSellar()) model = prob.model # each SubSellar group converges itself g1 = model.g1 g1.nonlinear_solver = CountNewton() g1.nonlinear_solver.options['rtol'] = 1.0e-5 g1.linear_solver = CountDS() # used for derivatives g2 = model.g2 g2.nonlinear_solver = CountNewton() g2.nonlinear_solver.options['rtol'] = 1.0e-5 g2.linear_solver = DirectSolver() # Converge the outer loop with Gauss Seidel, with a looser tolerance. model.nonlinear_solver = NewtonSolver() model.linear_solver = ScipyKrylov() # Enfore behavior: max_sub_solves = 1 means we run during init and first iteration of iter_execute model.nonlinear_solver.options['maxiter'] = 5 model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 1 prob.set_solver_print(level=0) prob.setup() prob.run_model() # Verifying subsolvers ran self.assertEqual(g1.nonlinear_solver.total_count, 4) self.assertEqual(g2.nonlinear_solver.total_count, 4) self.assertEqual(g1.linear_solver.lin_count, 4)
def test_sellar_specify_linear_direct_solver(self): prob = Problem() model = prob.model model.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) proms = [ 'x', 'z', 'y1', 'state_eq.y2_actual', 'state_eq.y2_command', 'd1.y2', 'd2.y2' ] sub = model.add_subsystem('sub', Group(), promotes=proms) subgrp = sub.add_subsystem( 'state_eq_group', Group(), promotes=['state_eq.y2_actual', 'state_eq.y2_command']) subgrp.linear_solver = ScipyKrylov() subgrp.add_subsystem('state_eq', StateConnection()) sub.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1']) sub.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1']) model.connect('state_eq.y2_command', 'd1.y2') model.connect('d2.y2', 'state_eq.y2_actual') model.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']) model.connect('d2.y2', 'obj_cmp.y2') model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2']) model.connect('d2.y2', 'con_cmp2.y2') model.nonlinear_solver = NewtonSolver() # Use bad settings for this one so that problem doesn't converge. # That way, we test that we are really using Newton's Lin Solver # instead. sub.linear_solver = ScipyKrylov() sub.linear_solver.options['maxiter'] = 1 # The good solver model.nonlinear_solver.linear_solver = DirectSolver() prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['state_eq.y2_command'], 12.05848819, .00001) # Make sure we aren't iterating like crazy self.assertLess(model.nonlinear_solver._iter_count, 8) self.assertEqual(model.linear_solver._iter_count, 0)
prob[pt + '.lpt.PR'] = 10.954 prob[pt + '.fan.map.RlineMap'] = 1.9401 prob[pt + '.lpc.map.RlineMap'] = 2.1099 prob[pt + '.hpc.map.RlineMap'] = 1.9772 prob[pt + '.gearbox.trq_base'] = 22179.6 st = time.time() # prob.model.RTO.nonlinear_solver.options['maxiter']=1 # prob.model.nonlinear_solver.linesearch.options['print_bound_enforce'] = True # from openmdao.api import view_model # view_model(prob) # exit() prob.set_solver_print(level=-1) prob.set_solver_print(level=2, depth=1) prob.run_model() # prob.check_partials(comps=['OD1.gearbox'], compact_print=True) # prob.model.list_outputs(residuals=True) # prob.check_partials(compact_print=False,abs_err_tol=1e-3, rel_err_tol=1e-3) # exit() for pt in ['TOC'] + pts: viewer(prob, pt) print() print("time", time.time() - st)
def test_debug_print_option(self): prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 50.0), promotes=['*']) model.add_subsystem('p2', IndepVarComp('y', 50.0), promotes=['*']) model.add_subsystem('comp', Paraboloid(), promotes=['*']) model.add_subsystem('con', ExecComp('c = - x + y'), promotes=['*']) prob.set_solver_print(level=0) prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False prob.driver.options['debug_print'] = [ 'desvars', 'ln_cons', 'nl_cons', 'objs' ] model.add_design_var('x', lower=-50.0, upper=50.0) model.add_design_var('y', lower=-50.0, upper=50.0) model.add_objective('f_xy') model.add_constraint('c', upper=-15.0) prob.setup(check=False) stdout = sys.stdout strout = StringIO() sys.stdout = strout try: prob.run_driver() finally: sys.stdout = stdout output = strout.getvalue().split('\n') self.assertTrue( output.count("Design Vars") > 1, "Should be more than one design vars header printed") self.assertTrue( output.count("Nonlinear constraints") > 1, "Should be more than one nonlinear constraint header printed") self.assertTrue( output.count("Linear constraints") > 1, "Should be more than one linear constraint header printed") self.assertTrue( output.count("Objectives") > 1, "Should be more than one objective header printed") self.assertTrue( len([s for s in output if s.startswith('p1.x')]) > 1, "Should be more than one p1.x printed") self.assertTrue( len([s for s in output if s.startswith('p2.y')]) > 1, "Should be more than one p2.y printed") self.assertTrue( len([s for s in output if s.startswith('con.c')]) > 1, "Should be more than one con.c printed") self.assertTrue( len([s for s in output if s.startswith('comp.f_xy')]) > 1, "Should be more than one comp.f_xy printed")
def test_group_assembled_jac_with_ext_mat(self): class TwoSellarDis1(ExplicitComponent): """ Component containing Discipline 1 -- no derivatives version. """ def setup(self): self.add_input('z', val=np.zeros(2)) self.add_input('x', val=np.zeros(2)) self.add_input('y2', val=np.ones(2)) self.add_output('y1', val=np.ones(2)) self.declare_partials(of='*', wrt='*') def compute(self, inputs, outputs): z1 = inputs['z'][0] z2 = inputs['z'][1] x1 = inputs['x'] y2 = inputs['y2'] outputs['y1'][0] = z1**2 + z2 + x1[0] - 0.2 * y2[0] outputs['y1'][1] = z1**2 + z2 + x1[0] - 0.2 * y2[0] def compute_partials(self, inputs, partials): """ Jacobian for Sellar discipline 1. """ partials['y1', 'y2'] = np.array([[-0.2, 0.], [0., -0.2]]) partials['y1', 'z'] = np.array([[2.0 * inputs['z'][0], 1.0], [2.0 * inputs['z'][0], 1.0]]) partials['y1', 'x'] = np.eye(2) class TwoSellarDis2(ExplicitComponent): def setup(self): self.add_input('z', val=np.zeros(2)) self.add_input('y1', val=np.ones(2)) self.add_output('y2', val=np.ones(2)) self.declare_partials('*', '*', method='fd') def compute(self, inputs, outputs): z1 = inputs['z'][0] z2 = inputs['z'][1] y1 = inputs['y1'] # Note: this may cause some issues. However, y1 is constrained to be # above 3.16, so lets just let it converge, and the optimizer will # throw it out if y1[0].real < 0.0: y1[0] *= -1 if y1[1].real < 0.0: y1[1] *= -1 outputs['y2'][0] = y1[0]**.5 + z1 + z2 outputs['y2'][1] = y1[1]**.5 + z1 + z2 def compute_partials(self, inputs, J): y1 = inputs['y1'] if y1[0].real < 0.0: y1[0] *= -1 if y1[1].real < 0.0: y1[1] *= -1 J['y2', 'y1'] = np.array([[.5 * y1[0]**-.5, 0.], [0., .5 * y1[1]**-.5]]) J['y2', 'z'] = np.array([[1.0, 1.0], [1.0, 1.0]]) prob = Problem() model = prob.model = Group() model.add_subsystem('px', IndepVarComp('x', np.array([1.0, 1.0])), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) sup = model.add_subsystem('sup', Group(), promotes=['*']) sub1 = sup.add_subsystem('sub1', Group(), promotes=['*']) sub2 = sup.add_subsystem('sub2', Group(), promotes=['*']) d1 = sub1.add_subsystem('d1', TwoSellarDis1(), promotes=['x', 'z', 'y1', 'y2']) sub2.add_subsystem('d2', TwoSellarDis2(), promotes=['z', 'y1', 'y2']) model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1[0] - y1[1]', y1=np.array([0.0, 0.0])), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2[0] + y2[1] - 24.0', y2=np.array([0.0, 0.0])), promotes=['con2', 'y2']) model.linear_solver = LinearBlockGS() sup.linear_solver = LinearBlockGS() sub1.jacobian = DenseJacobian() sub1.linear_solver = DirectSolver() sub2.jacobian = DenseJacobian() sub2.linear_solver = DirectSolver() prob.set_solver_print(level=0) prob.setup(check=False, mode='rev') prob.run_model() of = ['con1', 'con2'] wrt = ['x', 'z'] # Make sure we don't get a size mismatch. derivs = prob.compute_totals(of=of, wrt=wrt)