【问题标题】:Why are outputs from the first component not passed to the second's inputs directly in a coupled group using a NonlinearBlockGS solver?为什么使用 NonlinearBlockGS 求解器在耦合组中第一个组件的输出不直接传递到第二个组件的输入?
【发布时间】:2018-11-02 13:27:12
【问题描述】:

我遇到了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。这不是我在使用Gauss-Seidel 方法时所期望的。

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

我在这里做错了吗?我可以做些什么来确保B 在第一次运行时获得a 的更新值?

【问题讨论】:

    标签: python openmdao


    【解决方案1】:

    在 OpenMDAO 中,变量被定义为所有其他变量的隐式函数。与基于流的架构相比,这是一个主要区别,其中组件被定义为显式函数。请参阅 [基于流的架构和 MAUD 架构][1]。在 OpenMDAO 中,非线性方程组被求解残差。所以这是正常的,第一步在组件B中使用默认值作为输入aB.a的输入是A.a,所以B.a在第一次计算中将等于默认为A.a)

    如果a 在您的系统B 中不是有效值,请使用合适的默认值对其进行初始化(现在您只在设置中指定形状,而不是值。)。添加输入的方法的签名是add_input(self, name, val=1.0, shape=None, src_indices=None, flat_src_indices=None, units=None, desc=''),所以如果你不指定它,你的默认值为1.0。 我重写了你的类,从变量设置中定义的初始值开始。对于组件B a 是从A 的设置传递的,而不是A 的第一次计算。同样适用于组件A 中的b。在此之后,求解器将尝试最小化残差,将 B.a-A.aB.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]))
    

    求解器的第一步:

    =
    C
    =
    A: x = 3, b = 4, a = 11
    B: x = 3, a = 1e+00, b = 2
    

    [1]:https://i.stack.imgur.com/ygBdn.png Hwang,JT 和 Martins,JRRA:“用于耦合异构数值模型和计算耦合导数的计算架构”

    【讨论】:

      猜你喜欢
      • 2015-10-19
      • 1970-01-01
      • 2018-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-05
      • 2016-02-20
      • 1970-01-01
      相关资源
      最近更新 更多