我修改test_brute_force.py
以尝试并行化Paraboloid模型的采样(参见下面的代码)。我收到错误'sellars': promoted name 'sellar99.p1.f_xy' matches multiple unknowns: ('sellars.sellar99.p1.f_xy', 'sellars.sellar99.p1.f_xy')
。这个错误是什么意思?为什么test_brute_force.py
没有遇到此错误?
from __future__ import print_function
from florisse.floris import AEPGroup
import unittest
from six.moves import range
from six import iteritems
import numpy as np
from openmdao.api import Problem, Group, ParallelGroup, \
Component, IndepVarComp, ExecComp, \
Driver, ScipyOptimizer, SqliteRecorder
from openmdao.core.mpi_wrap import MPI
if MPI:
from openmdao.core.petsc_impl import PetscImpl as impl
else:
from openmdao.api import BasicImpl as impl
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('x_p', val=6.0)
self.add_param('y', val=-7.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['x_p']
y = params['y']
unknowns['f_xy'] = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0
def linearize(self, params, unknowns, resids):
""" Jacobian for our paraboloid."""
x = params['x_p']
y = params['y']
J = {}
J['f_xy', 'x_p'] = 2.0*x - 6.0 + y
J['f_xy', 'y'] = 2.0*y + 8.0 + x
return J
pboidGroup = Group()
pboidGroup.add('p1', Paraboloid(), promotes=['x_p', 'y'])
pboidGroup.add('p2', Paraboloid(), promotes=['x_p', 'y'])
pboidGroup.connect('p1.x_p', 'p2.x_p')
pboidGroup.connect('p1.x_p', 'p2.y')
class Randomize(Component):
""" add random uncertainty to params and distribute
Args
----
n : number of points to generate for each param
params : collection of (name, value, std_dev) specifying the params
that are to be randommized.
"""
def __init__(self, n=0, params=[]):
super(Randomize, self).__init__()
self.dists = {}
for name, value, std_dev in params:
# add param
self.add_param(name, val=value)
# add an output array var to distribute the modified param values
if isinstance(value, np.ndarray):
shape = (n, value.size)
else:
shape = (n, 1)
# generate a standard normal distribution (size n) for this param
self.dists[name] = np.random.normal(0.0, std_dev, n*shape[1]).reshape(shape)
#self.dists[name] = std_dev*np.random.normal(0.0, 1.0, n*shape[1]).reshape(shape)
self.add_output('dist_'+name, val=np.zeros(shape))
def solve_nonlinear(self, params, unknowns, resids):
""" add random uncertainty to params
"""
for name, dist in iteritems(self.dists):
unknowns['dist_'+name] = params[name] + dist
def linearize(self, params, unknowns, resids):
""" derivatives
"""
J = {}
for u in unknowns:
name = u.split('_', 1)[1]
for p in params:
shape = (unknowns[u].size, params[p].size)
if p == name:
J[u, p] = np.eye(shape[0], shape[1])
else:
J[u, p] = np.zeros(shape)
return J
class Collector(Component):
""" collect the inputs and compute the mean of each
Args
----
n : number of points to collect for each input
names : collection of `Str` specifying the names of the inputs to
collect and the resulting outputs.
"""
def __init__(self, n=10, names=[]):
super(Collector, self).__init__()
self.names = names
# create n params for each input
for i in range(n):
for name in names:
self.add_param('%s_%i' % (name, i), val=0.)
# create an output for the mean of each input
for name in names:
self.add_output(name, val=0.)
def solve_nonlinear(self, params, unknowns, resids):
""" compute the mean of each input
"""
inputs = {}
for p in params:
name = p.split('_', 1)[0]
if name not in inputs:
inputs[name] = data = [0.0, 0.0]
else:
data = inputs[name]
data[0] += 1
data[1] += params[p]
for name in self.names:
unknowns[name] = inputs[name][1]/inputs[name][0]
def linearize(self, params, unknowns, resids):
""" derivatives
"""
J = {}
for p in params:
name, idx = p.split('_', 1)
for u in unknowns:
if u == name:
J[u, p] = 1
else:
J[u, p] = 0
return J
class BruteForceSellarProblem(Problem):
""" Performs optimization on the Sellar problem.
Applies a normal distribution to the design vars and runs all of the
samples, then collects the values of all of the outputs, calculates
the mean of those and stuffs that back into the unknowns vector.
This is the brute force version that just stamps out N separate
sellar models in a parallel group and sets the input of each
one to be one of these random design vars.
Args
----
n : number of randomized points to generate for each input value
derivs : if True, use user-defined derivatives, else use Finite Difference
"""
def __init__(self, n=10, derivs=False):
super(BruteForceSellarProblem, self).__init__(impl=impl)
root = self.root = Group()
if not derivs:
root.deriv_options['type'] = 'fd'
sellars = root.add('sellars', ParallelGroup())
for i in range(n):
name = 'sellar%i' % i
sellars.add(name, pboidGroup)
#sellars.add(name, SellarDerivatives())
root.connect('x_p', 'sellars.'+name+'.x')#, src_indices=[i])
#root.connect('yaw0', 'sellars.'+name+'.yaw0')#, src_indices=[i])
#root.connect('dist_z', 'sellars.'+name+'.z', src_indices=[i*2, i*2+1])
root.connect('sellars.'+name+'.f_xy', 'collect.obj_%i' % i)
#root.connect('sellars.'+name+'.con1', 'collect.con1_%i' % i)
#root.connect('sellars.'+name+'.con2', 'collect.con2_%i' % i)
root.add('indep', IndepVarComp([
('x', 1.0),
('z', np.array([5.0, 2.0]))
]),
promotes=['x', 'z'])
root.add('random', Randomize(n=n, params=[
# name, value, std dev
('x', 1.0, 1e-2),
('z', np.array([5.0, 2.0]), 1e-2)
]),
promotes=['x', 'z', 'dist_x', 'dist_z'])
root.add('collect', Collector(n=n, names=['obj', 'con1', 'con2']),
promotes=['obj', 'con1', 'con2'])
# top level driver setup
self.driver = ScipyOptimizer()
self.driver.options['optimizer'] = 'SLSQP'
self.driver.options['tol'] = 1.0e-8
self.driver.options['maxiter'] = 50
self.driver.options['disp'] = False
self.driver.add_desvar('z', lower=np.array([-10.0, 0.0]),
upper=np.array([ 10.0, 10.0]))
self.driver.add_desvar('x', lower=0.0, upper=10.0)
self.driver.add_objective('obj')
self.driver.add_constraint('con1', upper=0.0)
self.driver.add_constraint('con2', upper=0.0)
prob = BruteForceSellarProblem(100, derivs=False)
prob.setup(check=False)
prob.run()
print(prob["obj"])
答案 0 :(得分:1)
我不完全确定你想要建模什么,或者应该与什么相关联,但我可以让你超越那个错误。问题是您在循环中多次添加抛物面组pboidGroup
的相同实例,而OpenMDAO不支持在多个位置使用相同的组件实例。您需要每次都创建一个新实例。
要解决这个问题,我只是将代码移动到接近使用位置的循环中,因此在循环中我们得到:
pboidGroup = Group()
pboidGroup.add('p1', Paraboloid())
pboidGroup.add('p2', Paraboloid())
pboidGroup.connect('p1.x_p', 'p2.x_p')
pboidGroup.connect('p1.x_p', 'p2.y')
name = 'sellar%i' % i
sellars.add(name, pboidGroup)
#sellars.add(name, SellarDerivatives())
现在我已经完成了,我在连接中遇到错误,我不确定x_p是什么意思在根目录中(可能需要IndepVarComp),但是这可能会让你超过停工点。