求解器选择:NonlinearBlockGS 与 NewtonSolver

Solver selection : NonlinearBlockGS vs NewtonSolver

我有两个 openmdao 组,它们之间存在循环依赖关系。我使用 Complex 步骤计算导数。我有一个用于依赖项的非线性求解器,并使用 SLSQP 优化我的 objective 函数。问题在于非线性求解器的选择。当我使用 NonlinearBlockGS 时,优化在 12 次迭代中成功。但是,当我将 NewtonSolverDirectsolverScipyKrylov 一起使用时,即使使用 maxiter=2000,优化也会失败(超出迭代限制)。循环连接收敛,只是设计变量没有达到最优值。连续迭代中设计变量之间的差异按 1e-5 的顺序排列。这增加了所需的迭代次数。此外,当我将初始猜测更改为更接近最佳值的值时,它会起作用。

为了进一步检查,我将模型转换为 IDF(通过创建耦合变量和一致性约束的副本),从而不再需要求解器。现在5次迭代优化成功,结果与使用NonlinearBlockGS时的结果相似。

为什么会这样?我错过了什么吗?我什么时候应该使用 NewtonSolver 而不是其他人?我知道不看代码很难回答。但只是我的代码很长,包含多个组件,我无法用玩具模型重现这个问题。因此,非常感谢任何一般见解。

没有看到代码,你是对的,很难给出具体细节。

从广义上讲,牛顿有时会比 NLBGS 更难收敛(注意:这并非绝对正确,但这是一个很好的经验法则)。所以我猜想发生的事情是,在你的第一次或第二次迭代中,牛顿求解器实际上并没有收敛。您可以通过设置 newton.options['iprint']=2 并在优化器迭代时查看迭代历史来检查这一点。

当您在优化中使用求解器时,您还要确保 set it to throw an error on non-convergence. 一些优化器可以处理此错误,并且会在线搜索时回溯,这一点很重要。其他人只会死去。无论哪种方式,它都很重要。否则,您最终会给优化器一个它不知道未收敛的未收敛情况。

这很糟糕,原因有二。首先,它得到的 objective 和约束值是错误的!其次,也许更重要的是,它计算出的导数是错误的!您可以 [在理论手册中] 阅读详细信息,但总而言之,OpenMDAO 使用的分析导数方法假设残差已变为 0。如果不是这种情况,数学就会崩溃。即使您使用的是完整模型 finite-difference,non-convergenced 模型也是一个问题。当你尝试 FD 时,你只会得到嘈杂的垃圾。2

因此,假设您已正确设置模型,并且线性求解器设置了问题(这听起来像您做的,因为它适用于 NLBGS),那么牛顿求解器很可能不是收敛。使用 iprint,可能与 driver debug printing 结合使用,自己检查一下。如果是这样,您需要弄清楚如何让牛顿表现得更好。

有一些tips here that are pretty general. You could also try using the armijo line search,往往可以以牺牲一些速度为代价稳定牛顿求解

最后...牛顿并不是在所有情况下的最佳答案。如果 NLBGS 更稳定,计算成本更低,你应该使用它。我赞赏你希望让它与牛顿一起工作的愿望。你绝对应该查明为什么不是,但如果事实证明牛顿不能可靠地解决你的耦合问题,那也没关系!