Amogh Kulkarni
Amogh Kulkarni

Reputation: 153

OpenMDAO: Replacing ExecComps with normal Components changes output

I was running the code of 'Sellar exmaple' from the tutorials. According to the docs given on the tutorial page, the ExecComp is just a shorthand for declaring a normal Component. So I tried redefining the ExecComps in the example as normal Components and use them in the same example.

The ExecComps in the example are defined as follows -

self.add('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=['*'])
self.add('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['*'])
self.add('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['*'])

The normal Components which I defined are as follows -

Objective component

class SellarObjective(Component):
    def __init__(self):
        super(SellarObjective, self).__init__()    
        self.add_param('x', val=0.0)
        self.add_param('y2', val=0.0)
        self.add_param('y1', val=0.0)
        self.add_param('z', val=np.zeros(2))    
        self.add_output('obj', val=0.0)

    def solve_nonlinear(self, params, unknowns, resids):
        unknowns['obj'] = params['x']**2 + params['z'][0] + params['y1'] + exp(-params['y2'])

    def linearize(self, params, unknowns, resids):
        J = {}
        J['obj', 'x'] = 2 * params['x']
        J['obj', 'y2'] = (-1) * exp(-params['y2'])
        J['obj', 'y1'] = 1.0
        J['obj', 'z[0]'] = 1.0
        return J

Constraint 1

class SellarConstraint1(Component):
    def __init__(self):
        super(SellarConstraint1, self).__init__()

        self.add_param('y1', val=0.0)
        self.add_output('con1', val=0.0)

    def solve_nonlinear(self, params, unknowns, resids):
        unknowns['con1'] = 3.16 - params['y1']

    def linearize(self, params, unknowns, resids):
        J = {}
        J['con1', 'y1'] = -1.0
        return J

Constraint 2

class SellarConstraint2(Component):
    def __init__(self):
        super(SellarConstraint2, self).__init__()
        self.add_param('y2', val=0.0)
        self.add_output('con2', val=0.0)

    def solve_nonlinear(self, params, unknowns, resids):
        unknowns['con2'] = params['y2'] - 24.0

    def linearize(self, params, unknowns, resids):
        J = {}
        J['con2', 'y2'] = 1.0
        return J

And I instantiate these newly declared Components in the re-written implementation as -

self.add('obj_cmp', SellarObjective(), promotes=['*'])
self.add('con_cmp1', SellarConstraint1(), promotes=['*'])
self.add('con_cmp2', SellarConstraint2(), promotes=['*'])

Everything else in the code is same as that of the tutorial. But after executing both of them, when I compare the results - results don't match.

Am I missing something obvious here? Thank you for your time.

Upvotes: 0

Views: 54

Answers (1)

Justin Gray
Justin Gray

Reputation: 5710

There are two minor issues with your replacement objective class:

  1. the objective is a function of z[1], no z[0]
  2. the derivative of the objective with respect to z is an array, and you can't use z[1] as the key. You must use z instead.

Correct your objective comp to the following, and it should work:

class SellarObjective(Component):
    def __init__(self):
        super(SellarObjective, self).__init__()    
        self.add_param('x', val=0.0)
        self.add_param('y2', val=0.0)
        self.add_param('y1', val=0.0)
        self.add_param('z', val=np.zeros(2))    
        self.add_output('obj', val=0.0)

    def solve_nonlinear(self, params, unknowns, resids):
        unknowns['obj'] = params['x']**2 + params['z'][1] + params['y1'] + np.exp(-params['y2'])

    def linearize(self, params, unknowns, resids):
        J = {}
        J['obj', 'x'] = 2 * params['x']
        J['obj', 'y2'] = (-1) * np.exp(-params['y2'])
        J['obj', 'y1'] = 1.0
        J['obj', 'z'] = np.array([[0,1],])
        return J

Upvotes: 1

Related Questions