Skip to main content

Implicit Relationships

The ImplicitOperation class provides users with a way to solve for variables in implicit relationships. It is possible to compute outputs implicitly by defining a residual variable in terms of the output and inputs.

In the first example, we solve a quadratic equation. This quadratic has two solutions: 1 and 3. Depending on the starting value of the output variable, CSDL will find one root or the other. The second and third examples show how to perform a bracketed search.

from csdl_om import Simulatorfrom csdl import Model, ScipyKrylov, NewtonSolver, NonlinearBlockGSimport numpy as np

class ExampleApplyNonlinear(Model):
    def define(self):        # define internal model that defines a residual        model = Model()        a = model.declare_variable('a', val=1)        b = model.declare_variable('b', val=-4)        c = model.declare_variable('c', val=3)        x = model.declare_variable('x')        y = a * x**2 + b * x + c        model.register_output('y', y)
        solve_quadratic = self.create_implicit_operation(model)        solve_quadratic.declare_state('x', residual='y')        solve_quadratic.nonlinear_solver = NewtonSolver(            solve_subsystems=False,            maxiter=100,            iprint=False,        )        solve_quadratic.linear_solver = ScipyKrylov()
        a = self.declare_variable('a', val=1)        b = self.declare_variable('b', val=-4)        c = self.declare_variable('c', val=3)        x = solve_quadratic(a, b, c)

sim = Simulator(ExampleApplyNonlinear())sim.run()

from csdl.examples.valid.ex_implicit_apply_nonlinear import examplefrom csdl_om import Simulatorsim = example(Simulator)
print('using default x=1')sim.run()print('x', sim['x'].shape)print(sim['x'])
print('')print('')print('setting x=1.9')sim['x'] = 1.9sim.run()print('x', sim['x'].shape)print(sim['x'])
print('')print('')print('setting x=2.1')sim['x'] = 2.1sim.run()print('x', sim['x'].shape)print(sim['x'])

The expressions for the residuals will will be part of a Model within the generated ImplicitOperation object.

For problems where the residual may converge for multiple solutions, or where the residual is difficult to converge over some interval, csdl provides an API for bracketing solutions.

from csdl_om import Simulatorfrom csdl import Model, ScipyKrylov, NewtonSolver, NonlinearBlockGSimport numpy as np

class ExampleBracketedScalar(Model):
    def define(self):        model = Model()        a = model.declare_variable('a')        b = model.declare_variable('b')        c = model.declare_variable('c')        x = model.declare_variable('x')        y = a * x**2 + b * x + c        model.register_output('y', y)
        solve_quadratic = self.create_implicit_operation(model)        solve_quadratic.declare_state('x', residual='y', bracket=(0, 2))
        a = self.declare_variable('a', val=1)        b = self.declare_variable('b', val=-4)        c = self.declare_variable('c', val=3)        x = solve_quadratic(a, b, c)

sim = Simulator(ExampleBracketedScalar())sim.run()
print('x', sim['x'].shape)print(sim['x'])
[1.]

Brackets may also be specified for multidimensional array values.

from csdl_om import Simulatorfrom csdl import Model, ScipyKrylov, NewtonSolver, NonlinearBlockGSimport numpy as np

class ExampleBracketedArray(Model):
    def define(self):        model = Model()        a = model.declare_variable('a', shape=(2, ))        b = model.declare_variable('b', shape=(2, ))        c = model.declare_variable('c', shape=(2, ))        x = model.declare_variable('x', shape=(2, ))        y = a * x**2 + b * x + c        model.register_output('y', y)
        solve_quadratic = self.create_implicit_operation(model)        solve_quadratic.declare_state('x',                                      residual='y',                                      bracket=(                                          np.array([0, 2.]),                                          np.array([2, np.pi], ),                                      ))
        a = model.declare_variable('a', val=[1, -1])        b = model.declare_variable('b', val=[-4, 4])        c = model.declare_variable('c', val=[3, -3])        x = solve_quadratic(a, b, c)

sim = Simulator(ExampleBracketedArray())sim.run()
print('x', sim['x'].shape)print(sim['x'])
[1. 3.]