openMDAO:ExecComp maximum() 的使用是否会干扰不受设计变量影响的约束?

openMDAO: Does the use of ExecComp maximum() interfere with constraints not being affected by design variables?

当 运行 我收到大型模型上的优化驱动程序时:

DerivativesWarning:Constraints or objectives [('max_current.current_constraint.current_constraint', inds=[0]), ('max_current.continuous_current_constraint.continuous_current_constraint', inds=[0])] cannot be impacted by the design variables of the problem.

我阅读了 提出的类似问题的答案。

这些值确实随着设计变量的变化而变化,并且在优化过程中满足这两个约束。

我原以为这是因为那些组件的 ExecComp 使用了 maximum(),因为这是我模型中唯一使用 maximum 函数的地方,但是当使用 maximum() 函数设置一个简单问题时以类似的方式我没有收到错误。

我的模型使用循环的显式组件,N2 图的左下角有连接,NLBGS 正在收敛整个模型。我目前认为这是由于仅使用了显式组件和 NLBGS 而不是隐式组件。

感谢您为解决此警告提供的任何见解。

下面是一个使用maximum()的简单脚本,不会报错。 (我非常确定就是这样)当我创建一个最小的工作示例时,它以与我的较大模型类似的方式给出错误,我将上传它。

import openmdao.api as om

prob=om.Problem()
prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.driver.options['tol'] = 1e-6
prob.driver.options['maxiter'] = 80
prob.driver.options['disp'] = True

indeps = prob.model.add_subsystem('indeps', om.IndepVarComp())
indeps.add_output('x', val=2.0, units=None)
prob.model.promotes('indeps', outputs=['*'])

prob.model.add_subsystem('y_func_1',
                         om.ExecComp('y_func_1 = x'),
                         promotes_inputs=['x'],
                         promotes_outputs=['y_func_1'])
prob.model.add_subsystem('y_func_2',
                         om.ExecComp('y_func_2 = x**2'),
                         promotes_inputs=['x'],
                         promotes_outputs=['y_func_2'])
prob.model.add_subsystem('y_max',
                         om.ExecComp('y_max = maximum( y_func_1 , y_func_2 )'),
                         promotes_inputs=['y_func_1',
                                          'y_func_2'],
                         promotes_outputs=['y_max'])
prob.model.add_subsystem('y_check',
                         om.ExecComp('y_check = y_max - 1.1'),
                         promotes_inputs=['*'],
                         promotes_outputs=['*'])

prob.model.add_constraint('y_check', lower=0.0)

prob.model.add_design_var('x', lower=0.0, upper=2.0)
prob.model.add_objective('x')

prob.setup()
prob.run_driver()

print(prob.get_val('x'))

在此上下文中 maximum 函数存在问题。从技术上讲,最大功能是不可微的;至少在其值为最大值的索引可能发生变化时不会。如果最大值不发生变化,那么它是可微分的......但你并不需要 max 函数。

在做基于梯度的事情时,一种正确的、可区分的处理最大值的方法是使用 KS 函数。 OpenMDAO 提供了实现它的KSComp。还有其他类型的函数(例如 p-norm,您也可以使用)。

然而,即使 maximum 在技术上不可区分......你可以 sort-of/kind-of 摆脱它。至少,numpy(ExecComp 使用)允许您将 complex-step 微分应用于 maximum 函数,它似乎给出了 non-zero 导数。因此,虽然它在技术上不正确,但您可以也许 摆脱它。至少,它不太可能是你问题的核心。

您提到使用 NLBGS,并且您有循环的组件。你的测试用例纯粹是前馈的(这里是你的测试用例中的 N2 )。 。这是一个重要的区别。

这里的问题是你的导数,而不是 maximum 函数。由于您有一个非线性求解器,您需要做一些事情来获得正确的导数。在 example Sellar optimization 中,模型使用此行:prob.model.approx_totals(),它告诉 OpenMDAO 在整个模型(包括非线性求解器)中 finite-difference。这很简单,并使示例紧凑。无论您的组件是否定义导数,它也都有效。然而,它很慢并且存在数值困难。因此,使用“真正的”问题需要您自担风险。

如果你不包括那个(你上面的例子没有,所以我假设你的真正问题也没有)那么你基本上是在告诉 OpenMDAO 你想使用解析导数(耶!他们是如此更棒了)。这意味着您需要一个线性求解器来匹配您的非线性求解器。对于您刚开始遇到的大多数问题,您只需在模型顶部放置一个 DirectSolver 即可,一切都会迎刃而解。对于更高级的模型,您需要更复杂的线性求解器结构……但那是一个不同的问题。

试一试: prob.model.linear_solver = om.DirectSolver()

不管你是否有耦合(循环),这应该给你 non-zero 总导数。