为什么我的 guess_nonlinear() 的输入都是 1?

问题描述

我的完整问题的 N2 图如下。

Full N2 diagram

问题耦合部分的 N2 图如下。

Coupled N2

我有一个 DirectSolver 处理 LLTForces 和 ImplicitLiftingLine 之间的耦合,还有一个 LNBGS 求解器处理 LiftingLineGroup 和 TestCL 之间的耦合。

问题的要点在这里https://gist.github.com/eufren/31c0e569ed703b2aea3e2ef5360610f7

我已经在 ImplicitLiftingLine 上实现了 guess_nonlinear(),它应该使用来自 LLTGeometry 的各种输出,基于控制方程的线性化形式对涡流强度给出一个很好的初始猜测。

def guess_nonlinear(self,inputs,outputs,resids):
    freestream_unit_vector = inputs['freestream_unit_vector']
    freestream_veLocity = inputs['freestream_veLocity']
    n = inputs['normal_vectors']
    A = inputs['surface_areas']
    l = inputs['bound_vortices']
    ic_tot = inputs['influence_coefficients_total']

    v_inf = freestream_veLocity
    v_inf_vec = v_inf*freestream_unit_vector

    lin_numerator = np.pi * v_inf * A * np.sum(n * v_inf_vec,axis=1)
    lin_denominator = (np.linalg.norm(np.cross(v_inf_vec,l),axis=1) - np.pi * v_inf * A * np.sum(np.sum(n * ic_tot,axis=2),axis=1))
    lin_vtx_str = lin_numerator / lin_denominator

    outputs['vortex_strengths'] = lin_vtx_str

然而,当问题第一次运行时,任何没有用 p.set_val() 显式设置的输入都是 1。这会导致 guess_nonlinear() 给出错误输出,因此系统无法收敛:

enter image description here

据我所知,LLT 组的执行顺序是正确的,几何组件应该在隐式组件之前执行。我很困惑为什么在运行代码时这似乎并没有真正发生,而是这些输入采用了它们的认值。

我需要更改什么才能使其正常工作?此外,我发现在优化过程中很难让 LNBGS 收敛(因此添加了 guess_nonlinear())——只有 DirectSolver 可以顺利通过优化,但对于大量 LLT 节点来说速度非常慢)。如何改进线性和非线性求解器的选择,提高迭代求解器的可靠性?

解决方法

注意:感谢提供可测试的示例。它使找出问题的答案变得更加简单。您的问题有点微妙,如果没有可运行的代码,我将无法给出好的答案

你的第一个问题:“为什么所有的输入都是 1”

“简短”答案 您已将非线性求解器置于模型层次结构的较高位置,然后包含一个计算输入值的关键前体组件。通过将求解器下移到模型的较低级别,我能够确保前体组件 (LTTGeometry) 在您到达隐式组件的 guess_nonlinear 之前运行并具有有效输出。>

这是您所拥有的(注意隐式求解器包含 LTTGeometry,即使数据循环不需要该组件:n2 of bad solver structure

我将非线性求解器和线性求解器都移到了 LTTCycle 组中,然后允许 LTTGeometry 组件在进入非线性求解器和 guess_nonlinear 步骤之前执行: enter image description here

我的修复只是部分正确,因为 TestCL 组件有一个二次循环,它也需要求解器,但没有求解器。但是,该循环仍然不涉及 LTTGeometry 组。因此,完全正确的解决方法是首先重构您的顶级几何模型,然后将 LTTCycleTestCL 组放在一起,以便您可以仅对它们运行求解器。对于您的测试问题,这比我想做的要多一些,但您可以从上面调整后的 N2 中看到总体思路。

长答案 OpenMDAO 中的 guess_nonlinear 序列运行显式组件或组的计算方法。它遵循执行层次结构,并调用它找到的任何 guess_nonlinear。因此,这意味着您模型中的任何显式组件都不会被执行,它们的输出不会使用计算值更新,并且这些计算值不会传递到下游组件的输入。

当您有很深的模型层次结构时,事情会变得有点棘手。 guess_nonlinear 方法被称为非线性求解器过程的第一步。如果您在顶层有一个 NonLinearRunOnce 求解器,它将沿着计算链向下,在每个子节点上调用 computesolve_nonlinear,并在每个子节点之后进行数据传输。如果其中一个子节点恰好是具有非线性求解器的组,那么该求解器将在其子节点(具有 NonLinearRunOnce 求解器的顶级组的孙子节点)上调用 guess_nonlinear 作为第一步。因此,由该组的兄弟级计算的任何输出都是有效的,但尚未计算出孙级级别的任何输出。

您可能想知道为什么不让 guess_nonlinear 方法为任何显式组件调用计算?这里很难平衡权衡。如果您假设所有显式组件的运行成本都非常低,那么运行计算方法可能有意义 --- 或者可能没有。在很大程度上取决于循环数据结构。如果组中的某个早期组件需要从后面的组件中进行猜测,那么运行其计算根本不会对您有多大帮助。或许更重要的是,并非所有显式组件运行起来都很便宜。您可能有一个非常昂贵的计算,并且将计算作为猜测过程的一部分调用会太昂贵。

这里的妥协是,如果您需要某种顶级猜测过程,您可以implement guess_nonlinear at the group level。这样做不太常见,但它可以让您完全控制发生的事情。您可以按任意顺序调用您需要调用的任何内容。

所以要记住的绝对关键是,当调用 guess_nonlinear 时,您唯一可用的数据是在执行包含求解器之前计算的任何数据。这意味着在您到达包含求解器的模型范围之前计算的任何内容(不是具有 guess_method 本身的组件的范围)。

您的第二个问题:“当节点数量变大时,我如何加快速度?”

这个根本不可能给出一个通用的答案。我注意到您已经指定了稀疏偏导数。这是一个很好的开始,但如果它对您来说仍然不够快,那么这意味着您已经达到了 DirectSolver 所能达到的极限。您注意到这个求解器是唯一可以让您顺利完成优化的求解器,我认为这意味着 ScipyKryloventer link description herePetscKrylov 不能很好地收敛线性系统 --- 在至少不是他们自己。这并不奇怪,因为 krylov 求解器几乎总是需要某种预处理器......这就是我不能提供通用答案的原因。为大规模计算设置高效的线性求解器是一个棘手的问题。如果你查阅文献,你会发现一些很好的建议。您还可以研究诸如 VSPAero 之类的开源实现以获取一些提示。

实际上,您已经达到了简单线性求解器所能提供的极限。从这一点来看,OpenMDAO 可以通过更轻松地实现一些预处理来提供一些帮助,但您必须自己承担数学方面的问题。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...