Providing an Initial Guess for Implicit States in a Group

In the documentation for ImplicitComponent, you saw that you can provide an initial guess for implicit states within the component using it’s guess_nonlinear method.

Group also provides a guess_nonlinear method in which you can supply the starting value for implicit state variables in any of it’s subsystems.

The following example demonstrates the capability of setting the initial guess value at the group level, using the input from one component to compute the guess for another. In this case, a Discipline group solves a system of equations using a BalanceComp. It answers the question: “What is \(x\) such that \(x^2\) is equal to twice our input value”.

Group guess_nonlinear Example

Given our knowledge of the relationship between the two equations, we can supply an initial guess for the implicit state variable, \(x\), that makes it unnecessary for the solver to iterate.

import numpy as np
import openmdao.api as om


class Discipline(om.Group):

    def setup(self):
        self.add_subsystem('comp0', om.ExecComp('y=x**2'))
        self.add_subsystem('comp1', om.ExecComp('z=2*external_input'),
                           promotes_inputs=['external_input'])

        self.add_subsystem('balance', om.BalanceComp('x', lhs_name='y', rhs_name='z'),
                           promotes_outputs=['x'])

        self.connect('comp0.y', 'balance.y')
        self.connect('comp1.z', 'balance.z')

        self.connect('x', 'comp0.x')

        self.nonlinear_solver = om.NewtonSolver(iprint=2, solve_subsystems=True)
        self.linear_solver = om.DirectSolver()

    def guess_nonlinear(self, inputs, outputs, residuals):
        # Check residuals
        if np.abs(residuals['x']) > 1.0E-2:
            # inputs are addressed using full path name, regardless of promotion
            external_input = inputs['comp1.external_input']

            # balance drives x**2 = 2*external_input
            x_guess = (2*external_input)**.5

            # outputs are addressed by the their promoted names
            outputs['x'] = x_guess # perfect guess should converge in 0 iterations

p = om.Problem()

p.model.add_subsystem('discipline', Discipline(), promotes_inputs=['external_input'])

p.setup()
p.set_val('external_input', 1.)
p.run_model()

print(p.model.nonlinear_solver._iter_count)

print(p.get_val('discipline.x'))
==========
discipline
==========
NL: Newton 0 ; 0.5 1
NL: Newton 1 ; 0.125 0.25
NL: Newton 2 ; 0.00347222222 0.00694444444
NL: Newton 3 ; 3.00365244e-06 6.00730488e-06
NL: Newton 4 ; 2.25530705e-12 4.5106141e-12
NL: Newton Converged
0
[1.41421356]