Ry10
Ry10

Reputation: 87

Passing gradients between components; pass_by_obj output

I have a situation where the gradient of one component is by necessity calculated in another component. What I have attempted to do is just have the gradient be an output from the first component and an input to the second component. I have set it to be pass_by_obj so that it doesn't affect other calculations. Any recommendations on whether or not this would be the best way to do it would be appreciated. Nevertheless, I am getting an error when using check_partial_derivatives(). It seems to be an error for any output that is specified as pass_by_obj. Here is a simple case:

import numpy as np
from openmdao.api import Group, Problem, Component, ScipyGMRES, ExecComp, IndepVarComp

class Comp1(Component):
    def __init__(self):
        super(Comp1, self).__init__()
        self.add_param('x', shape=1)

        self.add_output('y', shape=1)
        self.add_output('dz_dy', shape=1, pass_by_obj=True)

    def solve_nonlinear(self, params, unknowns, resids):

        x = params['x']

        unknowns['y'] = 4.0*x + 1.0
        unknowns['dz_dy'] = 2.0*x

    def linearize(self, params, unknowns, resids):

        J = {}
        J['y', 'x'] = 4.0
        return J

class Comp2(Component):
    def __init__(self):
        super(Comp2, self).__init__()
        self.add_param('y', shape=1)
        self.add_param('dz_dy', shape=1, pass_by_obj=True)

        self.add_output('z', shape=1)

    def solve_nonlinear(self, params, unknowns, resids):
        y = params['y']
        unknowns['z'] = y*2.0

    def linearize(self, params, unknowns, resids):
        J = {}
        J['z', 'y'] = params['dz_dy']
        return J

class TestGroup(Group):
    def __init__(self):
        super(TestGroup, self).__init__()
        self.add('x', IndepVarComp('x', 0.0), promotes=['*'])
        self.add('c1', Comp1(), promotes=['*'])
        self.add('c2', Comp2(), promotes=['*'])

p = Problem()
p.root = TestGroup()
p.setup(check=False)

p['x'] = 2.0

p.run()

print p['z']
print 'gradients'
test_grad = open('partial_gradients_test.txt', 'w')
partial = p.check_partial_derivatives(out_stream=test_grad)

I get the following error message:

partial = p.check_partial_derivatives(out_stream=test_grad)
  File "/usr/local/lib/python2.7/site-packages/openmdao/core/problem.py", line 1699, in check_partial_derivatives
    dresids._dat[u_name].val[idx] = 1.0
TypeError: '_ByObjWrapper' object does not support item assignment

I asked before about the params being checked for pass_by_obj in check_partial_derivatives() and it might be simply a matter of checking the unknowns for pass_by_obj as well.

Upvotes: 0

Views: 61

Answers (1)

Justin Gray
Justin Gray

Reputation: 5710

the error you're getting is another bug related to check_partial_derivatives function. It should be easy enough to fix, but in the meantime you can just remove the pass_by_obj setting. Since you're computing a value in one component and passing it to another, there isn't a need to do pass_by_obj at all (and it will be more efficient if you don't).

You said that you did it so that it "doesn't affect other calculations", but I don't quite know what you mean by that. It won't affect anything unless you use it in the solve_nonlinear method.

Upvotes: 0

Related Questions