为什么不使用NonlinearBlockGS解算器将第一个组件的输出直接传递给耦合组中的第二个组件的输入?

时间:2018-11-02 13:27:12

标签: python openmdao

我遇到一个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()

两个组件AB由它们的输出ab耦合。它们还共享参数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,它应该获取Aa = 7的输出,但是a的初始猜测也设置为1。这不是我期望的使用高斯-塞德尔方法时。

B运行之后a没有获得A的更新值的事实并不影响在这种情况下该系统收敛到正确解的事实。但是,在我的情况下,a = 1不是B的有效输入。因此系统无法收敛。

我在这里做错什么了吗?我该怎么做才能确保B在第一次运行时就获得a的更新值?

1 个答案:

答案 0 :(得分:5)

在OpenMDAO中,变量被定义为所有其他变量的隐式函数。与将组件定义为显式功能的基于流程的体系结构相比,这是一个主要区别。请参阅[基于流的体系结构和MAUD体系结构] [1]。替代地,在OpenMDAO中,求解非线性方程组的残差。因此,通常,第一步是在组件B中将默认值用于输入aB.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也是如此。此后,求解器将尝试使残差最小化,以将AB.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的马丁斯:“一种用于异构数据模型和耦合衍生变量耦合的计算架构”