Search code examples
openmdao

How to use an external code component within the optimization framework


Hi I am trying to use the paraboloid external code component to get the same results as in the paraboloid optimization problem (openmdao v 2.2.0).

So in my mind the independent variables x,y should be updated and thus changing the input file of the external component to minimize the output f.
Not that I got this working but I basically add the external component's output to be the objective and the independent variables to be the design variables etc (see code below). But more importantly I have a problem to conceptually understand how the optimizer would know the derivatives in such external codes. I tried 'COBYLA' thinking that could be a way to go gradient-free approach but there seems to be a bug in the iprint statement, since I can not run the example paraboloid optimization either.

I think I have a similar problem with surrogates. For example I use Metamodelunstructured component to find my surrogate which performs well if I ask for a known value. But I do not see how to couple this component's output to be the objective of the optimizer. I think I am doing the right thing by giving the model objective. but not sure...

The answer might be that I am completely off from the optimization logic if so please refer me to the related papers for the algorithms behind.

Thanks in advance

from openmdao.api import Problem, Group, IndepVarComp
from openmdao.api import  ScipyOptimizeDriver
from openmdao.components.tests.test_external_code import ParaboloidExternalCode

top = Problem()
top.model = model = Group()

# create and connect inputs
model.add_subsystem('p1', IndepVarComp('x', 3.0))
model.add_subsystem('p2', IndepVarComp('y', -4.0))
model.add_subsystem('p', ParaboloidExternalCode())

model.connect('p1.x', 'p.x')
model.connect('p2.y', 'p.y')

top.driver = ScipyOptimizeDriver()
top.driver.options['optimizer'] = 'SLSQP'

top.model.add_design_var('p1.x', lower=-50, upper=50)
top.model.add_design_var('p2.y', lower=-50, upper=50)
top.model.add_objective('p.f_xy')
top.driver.options['tol'] = 1e-9
top.driver.options['disp'] = True
top.setup()
top.run_driver()
# minimum value
# location of the minimum
print(top['p1.x'])
print(top['p2.y'])

Solution

  • So, I think the main thing you are asking is how to provide derivatives for external codes. I think there are really two options for this.

    1. Finite difference across the external component.

    The test example doesn't show how to do this, which is unfortunate, but you do this the same way that you would declare derivatives fd for a pure python component, namely by adding this line to the external component's setup method:

    self.declare_partials(of='*', wrt='*', method='fd')
    
    1. Provide another external method to calculate the derivatives, and wrap it in the "compute_partials" method.

    We do this with CFD codes that provide an adjoint solution. You could possibly also use automatic differentiation on the external source code to produce a callable function in this way. However, I think method 1 is what you are asking for here.