为什么每个 Gauss-Seidel 迭代都会执行两次组件? (OpenMDAO 2.4.0)

Why are components executed two times for each Gauss-Seidel iteration? (OpenMDAO 2.4.0)

我一直在使用 NonLinearBlockGS 作为 nonlinear_solver 用于由 ExplicitComponents 组成的 MDO 系统,这按预期工作。首先,我将其与简单的数学函数一起使用(因此 运行time << 1s),但现在我还实现了一个具有多个显式组件的系统,这些组件的 运行 时间约为一分钟或更长时间。那时我注意到 NonLinearBlockGS 求解器实际上需要 运行 耦合系统中的工具每次迭代两次。这些运行来源于求解器_run_iterator()方法中的self._iter_execute()self._run_apply()(文件[=18=中的classSolver ]).

我的主要问题是,每次迭代是否真的需要两个 运行,如果需要,为什么?

似乎第一个组件 运行 (self.iter_execute()) 使用了对需要收敛的反馈变量的初始猜测,然后 运行 在更新任何前馈时按顺序对组件进行数据。这是我对 Gauss-Seidel 期望的步骤。但是然后第二个组件 运行 (self._run_apply()) 运行 再次使用第一个 运行 产生的更新反馈变量对组件进行更新,同时保持前馈在其中首先运行。如果我没记错的话,此信息将(仅)用于评估该迭代的收敛性 (self._iter_get_norm())。

与其把这第二个运行放在迭代里面,直接继续下一个迭代不是更高效吗?在那次迭代中,我们可以使用反馈变量的新值并执行另一个 self._iter_execute() 更新前馈数据,然后根据这两次迭代之间的结果差异评估收敛性。当然这意味着我们至少需要两次迭代来评估收敛性,但它每次迭代节省了一个组件运行。 (这实际上是我在 MATLAB 中用于收敛这些组件的现有实现,并且按预期工作,因此它找到了相同的收敛设计,但组件数量减半 运行s。)

所以另一种表达方式是:为什么我们在进行高斯-赛德尔收敛时每次迭代都需要 self._run_apply()? (这可以关闭吗?)

您的问题有几个不同的方面。首先,我将介绍 solve_nonlinearapply_nonlinear 的细节。使用 OpenMDAO 的底层数学算法,基于 MAUD frameworksolve_nonlinear 仅计算输出值的值(不设置残差)。 apply_nonlinear 仅计算残差(不设置输出)。 对于 ExplicitComponent 的子 classes,用户只实现了一个 compute 方法,基础 class 实现了 solve_nonlinearapply_nonlinear 使用compute.

正如您所描述的,在 OpenMDAO V2.4 当前实现的 NonlinearBlockGaussSeidel 中,每次迭代都会对其组执行一次递归 solve_nonlinear 调用,然后调用 apply_nonlinear 检查残差并寻找收敛。

但是,您也说得对,我们可以更有效地执行此操作。您建议对算法进行的修改会起作用,我们将把它放在 V2.6 的开发管道中(截至本 post,我们即将发布 V2.5,然后没时间将其添加到该版本中)