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"])
私がモデル化しようとしているものとして、正規分布した 'x_p'が与えられた場合、並列化されたサンプリングを使って' f_xy'の期待値を求めたいと思います。私はこれを私の本当の問題に近づけるためのつながりを加えました。 – kilojoules
ソース '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])'という行にあります。ここでは、各売り手システムのx_pをどこかの出力にする必要があるソース 'x_p'に接続していますが、何も提供されていません。元の例では、 'Randomize'によって提供される 'dist_x'に接続しています。マッチするには、Randomizeコンポーネントのdist_xからx_pに名前を変更するか、代わりに 'dist_x'に接続する必要があります。 (そうするには、ソースインデックスのコメントを外す必要があります) –