我遇到一个Group
问题,该问题包括OpenMDAO中其子系统之间的反馈。我正在使用NonlinearBlockBS
求解器。我希望高斯-赛德尔(Gauss-Seidel)求解器可以依次运行子系统,将早期模块的输出传递给其他模块的输入。但是,当我在OpenMDAO中实现此功能时,似乎并没有发生这种情况。
我制作了一个示例脚本来演示此问题:
class A(ExplicitComponent):
def setup(self):
self.add_input('x', shape=1)
self.add_input('b', shape=1)
self.add_output('a', shape=1)
def compute(self, inputs, outputs):
outputs['a'] = inputs['x'] + 2 * inputs['b']
print('A: x = {:1.0f}, b = {:1.0f}, a = {:1.0f}'.format(inputs['x'][0], inputs['b'][0], outputs['a'][0]))
class B(ExplicitComponent):
def setup(self):
self.add_input('x', shape=1)
self.add_input('a', shape=1)
self.add_output('b', shape=1)
def compute(self, inputs, outputs):
outputs['b'] = inputs['x'] - 0.5 * inputs['a']
print('B: x = {:1.0f}, a = {:1.0}, b = {:1.0f}'.format(inputs['x'][0], inputs['a'][0], outputs['b'][0]))
if __name__ == '__main__':
ivc = IndepVarComp()
ivc.add_output('x', val=3.)
coupled_group = Group()
coupled_group.add_subsystem('A', A(), promotes=['*'])
coupled_group.add_subsystem('B', B(), promotes=['*'])
coupled_group.nonlinear_solver = NonlinearBlockGS()
prob = Problem()
model = prob.model = Group()
model.add_subsystem('I', ivc, promotes=['*'])
model.add_subsystem('C', coupled_group, promotes=['*'])
prob.setup()
prob.run_model()
两个组件A
和B
由它们的输出a
和b
耦合。它们还共享参数x
,该参数最初由IndepVarComp
设置。运行时,代码将产生以下输出:
=
C
=
A: x = 3, b = 1, a = 7
B: x = 3, a = 1, b = 4
A: x = 3, b = 1, a = 7
B: x = 3, a = 7, b = 1
A: x = 3, b = 1, a = 7
B: x = 3, a = 7, b = 1
NL: NLBGS Converged in 1 iterations
由b
作为输入的A
参数在第一次运行A
时尚未定义。因此,它的初始值为1。这是预期的。然后运行B
,它应该获取A
,a = 7
的输出,但是a
的初始猜测也设置为1。这不是我期望的使用高斯-塞德尔方法时。
在B
运行之后a
没有获得A
的更新值的事实并不影响在这种情况下该系统收敛到正确解的事实。但是,在我的情况下,a = 1
不是B
的有效输入。因此系统无法收敛。
我在这里做错什么了吗?我该怎么做才能确保B
在第一次运行时就获得a
的更新值?
答案 0 :(得分:5)
在OpenMDAO中,变量被定义为所有其他变量的隐式函数。与将组件定义为显式功能的基于流程的体系结构相比,这是一个主要区别。请参阅[基于流的体系结构和MAUD体系结构] [1]。替代地,在OpenMDAO中,求解非线性方程组的残差。因此,通常,第一步是在组件B
中将默认值用于输入a
(B.a
的输入为A.a
,因此{{1} }在第一次计算中将等于默认值B.a
)
如果A.a
在系统a
中不是有效值,请使用适当的默认值对其进行初始化(现在您仅在设置中指定形状,而不是值)。添加输入方法的签名为B
,因此,如果未指定,则默认值为1.0。
我重写了您的类,以在设置中为变量定义的初始值开始。对于组件add_input(self, name, val=1.0, shape=None, src_indices=None, flat_src_indices=None, units=None, desc='')
,B
是通过a
的设置传递的,而不是A
的第一次计算。组件A
中的b
也是如此。此后,求解器将尝试使残差最小化,以将A
和B.a-A.a
驱动为零。
B.b-A.b
求解器的第一步:
class A(ExplicitComponent):
def setup(self):
self.add_input('x', shape=1)
self.add_input('b', val=2)
self.add_output('a', val=1)
def compute(self, inputs, outputs):
outputs['a'] = inputs['x'] + 2 * inputs['b']
print('A: x = {:1.0f}, b = {:1.0f}, a = {:1.0f}'.format(inputs['x'][0], inputs['b'][0], outputs['a'][0]))
class B(ExplicitComponent):
def setup(self):
self.add_input('x', shape=1)
self.add_input('a', val=3)
self.add_output('b', val=4)
def compute(self, inputs, outputs):
outputs['b'] = inputs['x'] - 0.5 * inputs['a']
print('B: x = {:1.0f}, a = {:1.0}, b = {:1.0f}'.format(inputs['x'][0], inputs['a'][0], outputs['b'][0]))
[1]:https://i.stack.imgur.com/ygBdn.png HRA的黄某和JRRA的马丁斯:“一种用于异构数据模型和耦合衍生变量耦合的计算架构”