0
我修改了test_brute_force.py
以試圖並行化拋物面模型的採樣(請參閱下面的代碼)。我收到錯誤'sellars': promoted name 'sellar99.p1.f_xy' matches multiple unknowns: ('sellars.sellar99.p1.f_xy', 'sellars.sellar99.p1.f_xy')
。這個錯誤是什麼意思?爲什麼沒有test_brute_force.py
面對這個錯誤?OpenMDAO並行採樣/爲什麼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"])
至於我想模型,我想找到'f_xy'的期望值,使用並行採樣,給定一個正態分佈的'x_p'。我添加了這些連接以使它更接近我真正的問題。 – kilojoules
現在我得到錯誤'Source'p1.x_p'無法連接到目標'sellars.sellar0.x':'p1.x_p'不存在。「爲什麼dist_z中沒有出現類似的錯誤原始的例子?我們將root初始化爲一個空的Group(),我很驚訝我們可以無誤地引用dist_z。 – kilojoules
因此,問題出現在這一行'root.connect('x_p','sellars。'+ name +'。x')#,src_indices = [i])'。在這裏,你將每個sellar系統中的x_p連接到一個源'x_p',它需要在某處輸出,但不是由任何東西提供的。在最初的例子中,我們連接到由'Randomize'提供的'dist_x'。爲了匹配,您需要在隨機化組件中將dist_x重命名爲x_p,或者連接到'dist_x'。 (並且要這樣做,您必須取消源代碼索引) –