kilojoules
kilojoules

Reputation: 10083

openmdao compute gradient of constraints but not objective

How can I compute the gradient of my constraints without computing the gradient of my objective? I've tried this,

self._problem().compute_totals(of=self.consList, wrt=self._dvlist,
                                            return_format='array')

but this still calls the objective function gradients. (self.consList is a list with one element, which is the name of my constraint component).

Here is an example of this issue:

import openmdao.api as om

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


class comp1(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', 2, units="degF")
        self.add_output('y1', 2, units="degF")

    def setup_partials(self):
        self.declare_partials('y1', ['x'])

    def compute(self, inputs, outputs):
        outputs['y1'] = 2.0 * inputs['x']

    def compute_partials(self, inputs, J):
        print('I need these partials')
        J['y1', 'x'] = 2.0

class comp2(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', 2, units="degF")
        self.add_output('y2', 2, units="degF")

    def setup_partials(self):
        self.declare_partials('y2', ['x'])

    def compute(self, inputs, outputs):
        outputs['y2'] = 3.0 * inputs['x']

    def compute_partials(self, inputs, J):
        print('I dont need these partials')
        J['y2', 'x'] = 3.0
        
model.add_subsystem('comp1', comp1(), promotes=['*'])
model.add_subsystem('comp2', comp2(), promotes=['*'])

model.set_input_defaults('x', 35.0, units='degF')

model.add_design_var('x', units='degC', lower=0.0, upper=100.0)
model.add_constraint('y1', units='degC', lower=0.0, upper=100.0)
model.add_objective('y2', units='degC')

prob.setup()
prob.run_model()

print('computing constraint partials')
res = prob.driver._compute_totals(of='y1', wrt='x')

Upvotes: 0

Views: 84

Answers (1)

kilojoules
kilojoules

Reputation: 10083

You could add a custom attribute to stop your model from computing the gradient of the second component:

import openmdao.api as om

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


class comp1(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', 2, units="degF")
        self.add_output('y1', 2, units="degF")

    def setup_partials(self):
        self.declare_partials('y1', ['x'])

    def compute(self, inputs, outputs):
        outputs['y1'] = 2.0 * inputs['x']

    def compute_partials(self, inputs, J):
        print('I need these partials')
        J['y1', 'x'] = 2.0

class comp2(om.ExplicitComponent):
    def setup(self):
        self.add_input('x', 2, units="degF")
        self.add_output('y2', 2, units="degF")
        self.skip_partial = False

    def setup_partials(self):
        self.declare_partials('y2', ['x'])

    def compute(self, inputs, outputs):
        outputs['y2'] = 3.0 * inputs['x']

    def compute_partials(self, inputs, J):
        if self.skip_partial: return
        print('I dont need these partials')
        J['y2', 'x'] = 3.0
        
model.add_subsystem('comp1', comp1(), promotes=['*'])
model.add_subsystem('comp2', comp2(), promotes=['*'])

model.set_input_defaults('x', 35.0, units='degF')

model.add_design_var('x', units='degC', lower=0.0, upper=100.0)
model.add_constraint('y1', units='degC', lower=0.0, upper=100.0)
model.add_objective('y2', units='degC')

prob.setup()
prob.run_model()
prob.model._subsystems_myproc[2].skip_partial = True

print('computing constraint partials')
res = prob.driver._compute_totals(of='y1', wrt='x')

Upvotes: 0

Related Questions