LinearRunOnce#

The simplest linear solver in OpenMDAO is LinearRunOnce, which sequentially calls apply_linear and solve_linear once on each subsystem. It is directly analogous to applying a single pass of the chain rule to the whole system without any iteration at the top level. This linear solver can only be used in systems where the following conditions are satisfied:

  1. System does not contain a cycle, though subsystems may.

  2. System does not contain any implicit states, though subsystems may.

However, subsystems can contain cycles or implicit states, provided that they are using the appropriate solver such as ScipyKrylov.

Here is an example of using LinearRunOnce to calculate the derivatives across a simple model with the Paraboloid component.

Paraboloid class definition

class Paraboloid(om.ExplicitComponent):
    """
    Evaluates the equation f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3.
    """

    def setup(self):
        self.add_input('x', val=0.0)
        self.add_input('y', val=0.0)

        self.add_output('f_xy', val=0.0)

    def setup_partials(self):
        self.declare_partials('*', '*')

    def compute(self, inputs, outputs):
        """
        f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3

        Optimal solution (minimum): x = 6.6667; y = -7.3333
        """
        x = inputs['x']
        y = inputs['y']

        outputs['f_xy'] = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0

    def compute_partials(self, inputs, partials):
        """
        Jacobian for our paraboloid.
        """
        x = inputs['x']
        y = inputs['y']

        partials['f_xy', 'x'] = 2.0*x - 6.0 + y
        partials['f_xy', 'y'] = 2.0*y + 8.0 + x

import openmdao.api as om
from openmdao.test_suite.components.paraboloid import Paraboloid

prob = om.Problem()
model = prob.model

model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])

model.linear_solver = om.LinearRunOnce()

prob.setup(check=False, mode='fwd')

prob.set_val('x', 0.0)
prob.set_val('y', 0.0)

prob.run_model()

of = ['f_xy']
wrt = ['x', 'y']
derivs = prob.compute_totals(of=of, wrt=wrt, return_format='dict')

print(derivs['f_xy']['x'], [[-6.0]])
print(derivs['f_xy']['y'], [[8.0]])
[1790952160.110898] [runnervm8df0l:7209 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x556a251a8100 failed to create UD QP TX wr:256 sge:6 inl:64 resp:0 RX wr:4096 sge:1 resp:0 failed: Operation not supported
[1790952160.111148] [runnervm8df0l:7209 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error
[[-6.]] [[-6.0]]
[[8.]] [[8.0]]
[runnervm8df0l:07209] pml_ucx.c:313  Error: Failed to create UCP worker

LinearRunOnce Options#

OptionDefaultAcceptable ValuesAcceptable TypesDescription
aitken_initial_factor1.0N/AN/Ainitial value for Aitken relaxation factor
aitken_max_factor1.5N/AN/Aupper limit for Aitken relaxation factor
aitken_min_factor0.1N/AN/Alower limit for Aitken relaxation factor
assemble_jacFalse[True, False]['bool']Activates use of assembled jacobian by this solver.
iprint1N/A['int']whether to print output
use_aitkenFalse[True, False]['bool']set to True to use Aitken relaxation

LinearRunOnce Constructor#

The call signature for the LinearRunOnce constructor is:

LinearRunOnce.__init__(**kwargs)

Initialize all attributes.