def test_reraise_error(self): prob = om.Problem(model=DoubleSellar()) model = prob.model g1 = model.g1 g1.nonlinear_solver = om.BroydenSolver() g1.nonlinear_solver.options['maxiter'] = 1 g1.nonlinear_solver.options['err_on_non_converge'] = True g1.linear_solver = om.DirectSolver(assemble_jac=True) g2 = model.g2 g2.nonlinear_solver = om.BroydenSolver() g2.nonlinear_solver.options['maxiter'] = 1 g2.nonlinear_solver.options['err_on_non_converge'] = True g2.linear_solver = om.DirectSolver(assemble_jac=True) model.nonlinear_solver = om.BroydenSolver() model.linear_solver = om.DirectSolver(assemble_jac=True) model.nonlinear_solver.options['err_on_non_converge'] = True model.nonlinear_solver.options['reraise_child_analysiserror'] = True prob.setup() with self.assertRaises(om.AnalysisError) as context: prob.run_model() msg = "Solver 'NL: BROYDEN' on system 'g1' failed to converge in 1 iterations." self.assertEqual(str(context.exception), msg)
def test_distributed_comp_states(self): prob = om.Problem() model = prob.model sub = model.add_subsystem('sub', om.Group(), promotes=['*']) sub.add_subsystem('d1', DistribExecComp( ['y1 = 28 - 0.2*y2', 'y1 = 18 - 0.2*y2'], arr_size=2), promotes=['y1', 'y2']) sub.add_subsystem('d2', DistribExecComp( ['y2 = y1**.5 + 7', 'y2 = y1**.5 - 3'], arr_size=2), promotes=['y1', 'y2']) sub.nonlinear_solver = om.BroydenSolver(state_vars=['y1', 'y2']) sub.linear_solver = om.DirectSolver() model.linear_solver = om.DirectSolver() prob.setup(check=False, force_alloc_complex=True) prob.set_solver_print(level=2) prob.run_model() np.testing.assert_allclose(prob.get_val('y1', get_remote=True), np.array([25.58830237, 17.75721382]), .00001)
def test_distributed_comp(self): prob = om.Problem() model = prob.model sub = model.add_subsystem('sub', om.Group(), promotes=['*']) sub.add_subsystem('d1', DistribExecComp( ['y1 = 28 - 0.2*y2', 'y1 = 18 - 0.2*y2'], arr_size=2), promotes=['y1', 'y2']) sub.add_subsystem('d2', DistribExecComp( ['y2 = y1**.5 + 7', 'y2 = y1**.5 - 3'], arr_size=2), promotes=['y1', 'y2']) sub.nonlinear_solver = om.BroydenSolver() sub.linear_solver = om.LinearBlockGS() model.linear_solver = om.LinearBlockGS() prob.setup(check=False, force_alloc_complex=True) with self.assertRaises(Exception) as cm: prob.run_model() self.assertEqual( str(cm.exception), "Group (sub) has a BroydenSolver solver and contains a distributed system." )
def test_circuit_options(self): import openmdao.api as om from openmdao.test_suite.scripts.circuit_analysis import Circuit p = om.Problem() model = p.model model.add_subsystem('circuit', Circuit(), promotes_inputs=[('Vg', 'V'), ('I_in', 'I')]) model.set_input_defaults('V', 0., units='V') model.set_input_defaults('I', 0.1, units='A') p.setup() # Replace existing solver with BroydenSolver model.circuit.nonlinear_solver = om.BroydenSolver() model.circuit.nonlinear_solver.options['maxiter'] = 20 model.circuit.nonlinear_solver.options['converge_limit'] = 0.1 model.circuit.nonlinear_solver.options['max_converge_failures'] = 1 # Specify states for Broyden to solve model.circuit.nonlinear_solver.options['state_vars'] = ['n1.V', 'n2.V'] # set some initial guesses p.set_val('circuit.n1.V', 10.) p.set_val('circuit.n2.V', 1.) p.set_solver_print(level=2) p.run_model() assert_near_equal(p.get_val('circuit.n1.V'), 9.90804735, 1e-5) assert_near_equal(p.get_val('circuit.n2.V'), 0.71278226, 1e-5) # sanity check: should sum to .1 Amps assert_near_equal(p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'), .1, 1e-6)
def test_feature_stall_detection_broyden(self): import openmdao.api as om prob = om.Problem() prob.model.add_subsystem('comp', om.ExecComp('y=3*x+1'), promotes=['*']) balance = prob.model.add_subsystem('balance', om.BalanceComp(), promotes=['*']) balance.add_balance('x', lower=-.1, upper=10, rhs_val=0, lhs_name='y') nl_solver = prob.model.nonlinear_solver = om.BroydenSolver() nl_solver.options['stall_limit'] = 3 nl_solver.options['stall_tol'] = 1e-8 nl_solver.options['maxiter'] = 100 prob.model.linear_solver = om.DirectSolver() prob.setup() prob.set_solver_print() prob.run_model()
def test_circuit_full(self): import openmdao.api as om from openmdao.test_suite.scripts.circuit_analysis import Circuit p = om.Problem() model = p.model model.add_subsystem('ground', om.IndepVarComp('V', 0., units='V')) model.add_subsystem('source', om.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 = om.BroydenSolver() model.circuit.nonlinear_solver.options['maxiter'] = 20 model.circuit.nonlinear_solver.linear_solver = om.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.90804735, 1e-5) assert_rel_error(self, p['circuit.n2.V'], 0.71278226, 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_mixed_jacobian(self): # Testing Broyden on a 5 state case split among 3 vars. prob = om.Problem() model = prob.model model.add_subsystem('p1', om.IndepVarComp('c', 0.01)) model.add_subsystem('mixed', MixedEquation()) model.connect('p1.c', 'mixed.c') model.nonlinear_solver = om.BroydenSolver() model.nonlinear_solver.options['state_vars'] = [ 'mixed.x12', 'mixed.x3', 'mixed.x45' ] model.nonlinear_solver.options['maxiter'] = 15 model.nonlinear_solver.linear_solver = om.DirectSolver() prob.setup() prob.run_model() assert_rel_error(self, prob['mixed.x12'], np.zeros((2, )), 1e-6) assert_rel_error(self, prob['mixed.x3'], 0.0, 1e-6) assert_rel_error(self, prob['mixed.x45'], np.zeros((2, )), 1e-6) # Normally takes about 13 iters, but takes around 4 if you calculate an initial # Jacobian. self.assertTrue(model.nonlinear_solver._iter_count < 6)
def test_distributed_comp_states(self): prob = om.Problem() model = prob.model sub = model.add_subsystem('sub', om.Group(), promotes=['*']) sub.add_subsystem('d1', DistribExecComp( ['y1 = 28 - 0.2*y2', 'y1 = 18 - 0.2*y2'], arr_size=2), promotes=['y1', 'y2']) sub.add_subsystem('d2', DistribExecComp( ['y2 = y1**.5 + 7', 'y2 = y1**.5 - 3'], arr_size=2), promotes=['y1', 'y2']) sub.nonlinear_solver = om.BroydenSolver(state_vars=['y1', 'y2']) sub.linear_solver = om.DirectSolver() model.linear_solver = om.DirectSolver() prob.setup(check=False, force_alloc_complex=True) prob.set_solver_print(level=2) prob.run_model() # TODO - prob.get not working correctly on distributed vars. Once this is fixed, we can # test all values on all ranks. if model.comm.rank == 0: assert_rel_error(self, prob.get_val('y1', get_remote=True), 25.58830237, .00001) elif model.comm.rank == 1: assert_rel_error(self, prob.get_val('y1', get_remote=True), 17.75721382, .00001)
def test_mixed_promoted_vars(self): # Testing Broyden on a 5 state case split among 3 vars. prob = om.Problem() model = prob.model model.add_subsystem('p1', om.IndepVarComp('c', 0.01)) model.add_subsystem('mixed', MixedEquation(), promotes_outputs=['x12', 'x3', 'x45']) model.connect('p1.c', 'mixed.c') model.nonlinear_solver = om.BroydenSolver() model.nonlinear_solver.options['state_vars'] = ['x12', 'x3', 'x45'] model.nonlinear_solver.options['maxiter'] = 15 model.nonlinear_solver.options['compute_jacobian'] = False prob.setup() prob.run_model() assert_rel_error(self, prob['x12'], np.zeros((2, )), 1e-6) assert_rel_error(self, prob['x3'], 0.0, 1e-6) assert_rel_error(self, prob['x45'], np.zeros((2, )), 1e-6)
def test_jacobian_update_diverge_limit(self): # This model needs jacobian updates to converge. prob = om.Problem() model = prob.model model.add_subsystem('p1', om.IndepVarComp('x', np.array([0, 20.0]))) model.add_subsystem('comp', SpedicatoHuang()) model.connect('p1.x', 'comp.x') model.nonlinear_solver = om.BroydenSolver() model.nonlinear_solver.options['state_vars'] = ['comp.y'] model.nonlinear_solver.options['maxiter'] = 20 model.nonlinear_solver.options['diverge_limit'] = 0.5 model.nonlinear_solver.linear_solver = om.DirectSolver() prob.setup() 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_backtracking(self): top = om.Problem() top.model.add_subsystem('px', om.IndepVarComp('x', 1.0)) top.model.add_subsystem('comp', ImplCompTwoStates()) top.model.connect('px.x', 'comp.x') top.model.nonlinear_solver = om.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 = om.DirectSolver() top.setup() top.model.nonlinear_solver.linesearch = om.BoundsEnforceLS( bound_enforcement='vector') # Setup again because we assigned a new linesearch top.setup() 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_circuit_full(self): p = om.Problem() model = p.model model.add_subsystem('circuit', Circuit(), promotes_inputs=[('Vg', 'V'), ('I_in', 'I')]) model.set_input_defaults('V', 0., units='V') model.set_input_defaults('I', 0.1, units='A') p.setup() # Replace existing solver with BroydenSolver model.circuit.nonlinear_solver = om.BroydenSolver() model.circuit.nonlinear_solver.options['maxiter'] = 20 model.circuit.nonlinear_solver.linear_solver = om.DirectSolver() # set some initial guesses p.set_val('circuit.n1.V', 10.) p.set_val('circuit.n2.V', 1.) p.set_solver_print(level=2) p.run_model() assert_near_equal(p.get_val('circuit.n1.V'), 9.90804735, 1e-5) assert_near_equal(p.get_val('circuit.n2.V'), 0.71278226, 1e-5) # sanity check: should sum to .1 Amps assert_near_equal( p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'), .1, 1e-6)
def test_missing_state_warning(self): # Testing Broyden on a 5 state case split among 3 vars. prob = om.Problem() model = prob.model model.add_subsystem('p1', om.IndepVarComp('c', 0.01)) model.add_subsystem('mixed', MixedEquation()) model.connect('p1.c', 'mixed.c') model.nonlinear_solver = om.BroydenSolver() model.nonlinear_solver.options['state_vars'] = ['mixed.x12'] model.nonlinear_solver.options['maxiter'] = 15 model.nonlinear_solver.options['compute_jacobian'] = False prob.setup() msg = "The following states are not covered by a solver, and may have been " \ "omitted from the BroydenSolver 'state_vars': mixed.x3, mixed.x45" with assert_warning(UserWarning, msg): prob.run_model() # Try again with promoted names. prob = om.Problem() model = prob.model model.add_subsystem('p1', om.IndepVarComp('c', 0.01)) model.add_subsystem('mixed', MixedEquation(), promotes=['*']) model.connect('p1.c', 'c') model.nonlinear_solver = om.BroydenSolver() model.nonlinear_solver.options['state_vars'] = ['x12'] model.nonlinear_solver.options['maxiter'] = 15 model.nonlinear_solver.options['compute_jacobian'] = False prob.setup() msg = "The following states are not covered by a solver, and may have been " \ "omitted from the BroydenSolver 'state_vars': x3, x45" with assert_warning(UserWarning, msg): prob.run_model()
def test_cs_around_broyden_linesearch(self): prob = om.Problem() model = prob.model sub = model.add_subsystem('sub', om.ParallelGroup(), promotes=['*']) model.add_subsystem('px', om.IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', om.IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) sub.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) sub.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) sub.nonlinear_solver = om.BroydenSolver() sub.nonlinear_solver.linesearch = om.BoundsEnforceLS( bound_enforcement='vector') sub.linear_solver = om.DirectSolver() model.linear_solver = om.DirectSolver() prob.model.add_design_var('x', lower=-100, upper=100) prob.model.add_design_var('z', lower=-100, upper=100) prob.model.add_objective('obj') prob.model.add_constraint('con1', upper=0.0) prob.model.add_constraint('con2', upper=0.0) prob.setup(check=False, force_alloc_complex=True) prob.set_solver_print(level=2) prob.run_model() assert_rel_error(self, prob.get_val('y1', get_remote=True), 25.58830237, .00001) totals = prob.check_totals(method='cs', out_stream=None) for key, val in iteritems(totals): assert_rel_error(self, val['rel error'][0], 0.0, 1e-6)
def test_cs_around_broyden_compute_jac_dense(self): # Basic sellar test. prob = om.Problem() model = prob.model sub = model.add_subsystem('sub', om.Group(), promotes=['*']) model.add_subsystem('px', om.IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', om.IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) sub.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) sub.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) sub.nonlinear_solver = om.BroydenSolver() sub.linear_solver = om.DirectSolver() model.linear_solver = om.DirectSolver() prob.model.add_design_var('x', lower=-100, upper=100) prob.model.add_design_var('z', lower=-100, upper=100) prob.model.add_objective('obj') prob.model.add_constraint('con1', upper=0.0) prob.model.add_constraint('con2', upper=0.0) prob.setup(check=False, force_alloc_complex=True) prob.set_solver_print(level=0) prob.run_model() sub.nonlinear_solver.options['compute_jacobian'] = True totals = prob.check_totals(method='cs', out_stream=None) for key, val in iteritems(totals): assert_rel_error(self, val['rel error'][0], 0.0, 1e-6)
def test_broyden(self): p = om.Problem() comp = p.model.add_subsystem('comp', QuadraticComp()) comp.nonlinear_solver = om.BroydenSolver() comp.linear_solver = om.DirectSolver() p.setup(force_alloc_complex=True) p.run_model() partials = p.check_partials(includes=['comp'], method='cs', out_stream=None) assert_check_partials(partials)
def test_error_need_direct_solver(self): # Test top level Sellar (i.e., not grouped). prob = om.Problem() model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() with self.assertRaises(ValueError) as context: prob.run_model() msg = "BroydenSolver in SellarStateConnection (<model>): Linear solver must be DirectSolver when solving the full model." self.assertEqual(str(context.exception), msg)
def test_linsearch_3_deprecation(self): prob = om.Problem() model = prob.model = SellarStateConnection( nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() model.nonlinear_solver.options['state_vars'] = ['state_eq.y2_command'] model.nonlinear_solver.options['compute_jacobian'] = False msg = 'Deprecation warning: In V 3.0, the default Broyden solver setup will change ' + \ 'to use the BoundsEnforceLS line search.' with assert_warning(DeprecationWarning, msg): prob.final_setup()
def test_error_badname(self): # Test top level Sellar (i.e., not grouped). prob = om.Problem() model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() model.nonlinear_solver.options['state_vars'] = ['junk'] with self.assertRaises(ValueError) as context: prob.run_model() msg = "BroydenSolver in SellarStateConnection (<model>): The following variable names were not found: junk" self.assertEqual(str(context.exception), msg)
def test_simple_sellar(self): # Test top level Sellar (i.e., not grouped). prob = om.Problem() model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() model.nonlinear_solver.options['state_vars'] = ['state_eq.y2_command'] model.nonlinear_solver.options['compute_jacobian'] = False prob.run_model() assert_near_equal(prob['y1'], 25.58830273, .00001) assert_near_equal(prob['state_eq.y2_command'], 12.05848819, .00001)
def test_simple_sellar_cycle(self): # Test top level Sellar (i.e., not grouped). prob = om.Problem() model = prob.model = SellarDerivatives(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() model.nonlinear_solver.options['state_vars'] = ['y1'] model.nonlinear_solver.options['compute_jacobian'] = True prob.set_solver_print(level=2) prob.run_model() assert_near_equal(prob['y1'], 25.58830273, .00001) assert_near_equal(prob['y2'], 12.05848819, .00001)
def test_sellar(self): import openmdao.api as om from openmdao.test_suite.components.sellar import SellarStateConnection prob = om.Problem() model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() model.nonlinear_solver.options['state_vars'] = ['state_eq.y2_command'] model.nonlinear_solver.options['compute_jacobian'] = False prob.set_solver_print(level=2) prob.run_model() assert_near_equal(prob['y1'], 25.58830273, .00001) assert_near_equal(prob['state_eq.y2_command'], 12.05848819, .00001)
def test_simple_sellar_full_jacobian(self): # Test top level Sellar (i.e., not grouped). prob = om.Problem() model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() model.nonlinear_solver.linear_solver = om.DirectSolver() prob.run_model() assert_near_equal(prob['y1'], 25.58830273, .00001) assert_near_equal(prob['state_eq.y2_command'], 12.05848819, .00001) # Normally takes about 5 iters, but takes around 4 if you calculate an initial # Jacobian. self.assertTrue(model.nonlinear_solver._iter_count < 5)
def test_simple_sellar_jacobian_assembled_dense(self): # Test top level Sellar (i.e., not grouped). prob = om.Problem() model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.setup() model.options['assembled_jac_type'] = 'dense' model.nonlinear_solver.linear_solver = om.DirectSolver(assemble_jac=True) prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['state_eq.y2_command'], 12.05848819, .00001) # Normally takes about 4 iters, but takes around 3 if you calculate an initial # Jacobian. self.assertTrue(model.nonlinear_solver._iter_count < 4)
def test_sellar_state_connection_fd_system(self): # Sellar model closes loop with state connection instead of a cycle. # This test is just fd. prob = om.Problem() model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(), linear_solver=om.LinearRunOnce()) prob.model.approx_totals(method='fd') prob.setup() model.nonlinear_solver.options['state_vars'] = ['state_eq.y2_command'] model.nonlinear_solver.options['compute_jacobian'] = False prob.run_model() assert_near_equal(prob['y1'], 25.58830273, .00001) assert_near_equal(prob['state_eq.y2_command'], 12.05848819, .00001) # Make sure we aren't iterating like crazy self.assertLess(prob.model.nonlinear_solver._iter_count, 6)
def test_vector(self): # Testing Broyden on a 5 state single vector case. prob = om.Problem() model = prob.model model.add_subsystem('p1', om.IndepVarComp('c', 0.01)) model.add_subsystem('vec', VectorEquation()) model.connect('p1.c', 'vec.c') model.nonlinear_solver = om.BroydenSolver() model.nonlinear_solver.options['state_vars'] = ['vec.x'] model.nonlinear_solver.options['maxiter'] = 15 model.nonlinear_solver.options['compute_jacobian'] = False prob.setup() prob.run_model() assert_rel_error(self, prob['vec.x'], np.zeros((5, )), 1e-6)
def test_distributed_comp(self): prob = om.Problem() model = prob.model sub = model.add_subsystem('sub', om.Group(), promotes=['*']) sub.add_subsystem('d1', DistribExecComp(['y1 = 28 - 0.2*y2', 'y1 = 18 - 0.2*y2'], arr_size=2), promotes=['y1', 'y2']) sub.add_subsystem('d2', DistribExecComp(['y2 = y1**.5 + 7', 'y2 = y1**.5 - 3'], arr_size=2), promotes=['y1', 'y2']) sub.nonlinear_solver = om.BroydenSolver() sub.linear_solver = om.LinearBlockGS() model.linear_solver = om.LinearBlockGS() prob.setup(check=False, force_alloc_complex=True) with self.assertRaises(Exception) as cm: prob.run_model() msg = "BroydenSolver linear solver in Group (sub) cannot be used in or above a ParallelGroup or a " + \ "distributed component." self.assertEqual(str(cm.exception), msg)
def test_circuit_options(self): import openmdao.api as om from openmdao.test_suite.scripts.circuit_analysis import Circuit p = om.Problem() model = p.model model.add_subsystem('ground', om.IndepVarComp('V', 0., units='V')) model.add_subsystem('source', om.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 = om.BroydenSolver() model.circuit.nonlinear_solver.options['maxiter'] = 20 model.circuit.nonlinear_solver.options['converge_limit'] = 0.1 model.circuit.nonlinear_solver.options['max_converge_failures'] = 1 # Specify states for Broyden to solve model.circuit.nonlinear_solver.options['state_vars'] = ['n1.V', 'n2.V'] # set some initial guesses p['circuit.n1.V'] = 10. p['circuit.n2.V'] = 1. p.set_solver_print(level=2) p.run_model() assert_near_equal(p['circuit.n1.V'], 9.90804735, 1e-5) assert_near_equal(p['circuit.n2.V'], 0.71278226, 1e-5) # sanity check: should sum to .1 Amps assert_near_equal(p['circuit.R1.I'] + p['circuit.D1.I'], .1, 1e-6)
solver_flag = 'newton' if solver_flag == 'newton': prob.model.nonlinear_solver = om.NewtonSolver(iprint=2) # solve_subsystems should almost always be turned on # it improves solver robustness prob.model.nonlinear_solver.options['solve_subsystems'] = True prob.model.nonlinear_solver.options['maxiter'] = 100 # these options control how tightly the solver converges the system prob.model.nonlinear_solver.options['atol'] = 1e-8 prob.model.nonlinear_solver.options['rtol'] = 1e-8 # the Newton solver requires a linear solver prob.model.linear_solver = om.DirectSolver() elif solver_flag == 'broyden': prob.model.nonlinear_solver = om.BroydenSolver(iprint=2) # TODO: Try using broyden with and without a computed jacobian. What happens? prob.model.nonlinear_solver.options['compute_jacobian'] = True prob.model.nonlinear_solver.options['maxiter'] = 100 # these options control how tightly the solver converges the system prob.model.nonlinear_solver.options['atol'] = 1e-8 prob.model.nonlinear_solver.options['rtol'] = 1e-8 # the Broyden solver requires a linear solver *if* options['compute_jacobian'] = True prob.model.linear_solver = om.DirectSolver() elif solver_flag == 'nlbgs': # The nonlinear block Gauss-Seidel solver is an iterative solvver # Requires no linear solver and works even without derivatives prob.model.nonlinear_solver = om.NonlinearBlockGS(iprint=2) prob.model.nonlinear_solver.options['maxiter'] = 400 prob.model.nonlinear_solver.options['atol'] = 1e-8