为什么每个 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_nonlinear
与 apply_nonlinear
的细节。使用 OpenMDAO 的底层数学算法,基于 MAUD framework , solve_nonlinear
仅计算输出值的值(不设置残差)。 apply_nonlinear
仅计算残差(不设置输出)。
对于 ExplicitComponent
的子 classes,用户只实现了一个 compute
方法,基础 class 实现了 solve_nonlinear
和 apply_nonlinear
使用compute
.
正如您所描述的,在 OpenMDAO V2.4 当前实现的 NonlinearBlockGaussSeidel 中,每次迭代都会对其组执行一次递归 solve_nonlinear
调用,然后调用 apply_nonlinear
检查残差并寻找收敛。
但是,您也说得对,我们可以更有效地执行此操作。您建议对算法进行的修改会起作用,我们将把它放在 V2.6 的开发管道中(截至本 post,我们即将发布 V2.5,然后没时间将其添加到该版本中)
我一直在使用 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_nonlinear
与 apply_nonlinear
的细节。使用 OpenMDAO 的底层数学算法,基于 MAUD framework , solve_nonlinear
仅计算输出值的值(不设置残差)。 apply_nonlinear
仅计算残差(不设置输出)。
对于 ExplicitComponent
的子 classes,用户只实现了一个 compute
方法,基础 class 实现了 solve_nonlinear
和 apply_nonlinear
使用compute
.
正如您所描述的,在 OpenMDAO V2.4 当前实现的 NonlinearBlockGaussSeidel 中,每次迭代都会对其组执行一次递归 solve_nonlinear
调用,然后调用 apply_nonlinear
检查残差并寻找收敛。
但是,您也说得对,我们可以更有效地执行此操作。您建议对算法进行的修改会起作用,我们将把它放在 V2.6 的开发管道中(截至本 post,我们即将发布 V2.5,然后没时间将其添加到该版本中)