0

I thought I understood the January discussion regarding using metamodels in optimization. But my attempt has failed so far. I have a bit of a twist. I want to use a metamodel of one of several disciplines, where the example discussed in January optimized on just the results of the metamodel. I built a sample problem based on the paraboloid optimization tutorial example. I added a second Component, coupled the two Components in a group and optimized it. Then I tried to swap out one of the components with a metamodel of that component. Following is the version with the real model.

from __future__ import print_function

from openmdao.api import IndepVarComp, Component, Problem, Group, ExecComp, NLGaussSeidel, ScipyOptimizer, UniformDriver, DumpRecorder, InMemoryRecorder

import math
import numpy as np

class Paraboloid(Component):
""" Evaluates the equation f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3 """

def __init__(self):
    super(Paraboloid, self).__init__()

    self.add_param('z', val=0.0)
    self.add_param('y', val=0.0)

    self.add_output('f_xy', val=0.0)

def solve_nonlinear(self, params, unknowns, resids):
    """f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3
    """

    x = params['z']
    y = params['y']

    f_xy = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0
    unknowns['f_xy'] = f_xy

def linearize(self, params, unknowns, resids):
    """ Jacobian for our paraboloid."""

    x = params['z']
    y = params['y']
    J = {}

    J['f_xy', 'z'] = 2.0*x - 6.0 + y
    J['f_xy', 'y'] = 2.0*y + 8.0 + x
    return J

class Sinx(Component):
""" Evaluates the equation f(x) = sin(x) """

def __init__(self):
    super(Sinx, self).__init__()
self.C = 50.

    self.add_param('x', val=0.0)

    self.add_output('z', val=0.0)

def solve_nonlinear(self, params, unknowns, resids):
    """f(x) = 10.* sin(x/C)
    """

    x = params['x']

    sinx = math.sin(x/self.C) *10.
    unknowns['z'] = sinx

def linearize(self, params, unknowns, resids):
    """ Jacobian for our paraboloid."""

    x = params['x']
    J = {}

    J['z', 'x'] = math.cos(x/self.C)/self.C *10.
    return J

class Mda(Group):
def __init__(self):
    super(Mda, self).__init__()

self.f1in=['x']
self.f1out=['z']
self.f2in=['z', 'y']
self.f2out=['f_xy']

self.add('x', IndepVarComp('x', 10.), promotes=['*'])
self.add('y', IndepVarComp('y', 0.), promotes=['*'])

self.add('f1', Sinx(), promotes=self.f1in+self.f1out)
self.add('f2', Paraboloid(), promotes=self.f2in+self.f2out)
self.add('obj_cmp', ExecComp('obj = f_xy'), promotes=['f_xy', 'obj'])
self.nl_solver = NLGaussSeidel()


if __name__ == "__main__":

top = Problem()

root = top.root = Mda()

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

top.driver.add_desvar('x', lower=-50, upper=50)
top.driver.add_desvar('y', lower=-50, upper=50)
top.driver.add_objective('obj')

top.setup()
top.run()

print('obj =%f at (%f,%f)'%(top['obj'],top['x'],top['y']))

Following is the class that I thought would work as the metamodel.

class SinxSurr(MetaModel):
''' Evaluate surrogate of Sinx '''
def __init__(self):
super(SinxSurr, self).__init__()

    self.add_param('x', val=0.)
    self.add_output('z', val=0., surrogate=FloatKrigingSurrogate())

And following is the part to run it:

if __name__ == "__main__":
# build training data by sampling
top = Problem()
root = top.root = Group()

root.add('sinx', Sinx())
root.add('p1', IndepVarComp('x', 50.0))
root.connect('p1.x', 'sinx.x')

top.driver = UniformDriver(num_samples=500)
top.driver.add_desvar('p1.x', lower=-50, upper=50)
top.driver.add_objective('sinx.z')
recorder = InMemoryRecorder()
top.driver.add_recorder(recorder)

top.setup()
top.run()
top.cleanup()

# retrieve sampling results from recorder
xlist=[]
slist=[]
for line in recorder.iters:
xlist.append(line['unknowns']['p1.x'])
slist.append(line['unknowns']['sinx.z'])
recorder.close()

if len(xlist) != len(slist):
print('Recorder parse failure')
sys.exit(1)
x=10.

top = Problem()
root = top.root = Mda()

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

top.driver.add_desvar('x', lower=-50, upper=50)
top.driver.add_desvar('y', lower=-50, upper=50)
top.driver.add_objective('obj')

top.setup()
top.root['f1.train:x'] = xlist
top.root['f1.train:z'] = slist
top.run()

print('obj =%f at (%f,%f)'%(top['obj'],top['x'],top['y']))

When I run it, I get the error:

Setup: Checking for potential issues...

No recorders have been specified, so no data will be saved.

The following parameters have no associated unknowns:
f1.train:x
f1.train:z

Setup: Check complete.
##############################################

Traceback (most recent call last):
  File "surrDisc.py", line 164, in <module>
top.root['f1.train:x'] = xlist
TypeError: 'Mda' object does not support item assignment

I do not understand how to interact the data from the metamodel with the Group (at least).

1 Answers1

0

Did you mean to rename the variable 'z' to 'z:float' when you made the surrogate?

self.add_output('z:float', val=0., surrogate=FloatKrigingSurrogate())

If you did want to rename it, then you'll have to explicitly connect 'f1.z:float' to 'f2.z' and also not include 'z' in the promotes that you list in self.f1out and self.f2in.

Kenneth Moore
  • 2,167
  • 1
  • 9
  • 13
  • Oops. I found that mistake earlier, modded most of the code and the error, but missed that part of the code mod in the post. When the mod is made to fix the error you noticed, I get the posted error message. – Clyde Gumbert Jun 22 '16 at 19:59
  • That line should be: `top['f1.train:x'] = xlist` – Kenneth Moore Jun 22 '16 at 20:09