当约束在 OpenMDAO 中计算为无穷大时,最好的处理方法是什么?

What's the best way to handle when a constraint evaluates to infinity in OpenMDAO?

如问题所述,我想知道当约束或函数通常计算为无穷大时的最佳实践。

例如,假设我们限制零件的安全系数,其中该系数计算为

safety_factor = np.divide(allowable_force, applied_force)

在施加的力为 0 的情况下,safety_factor 计算为无穷大。由于当施加的力接近 0 时安全系数的极限是无穷大,因此从数学上来说这是可以检验的。假设安全系数被约束在2以上,无穷大大于2,因此应该满足约束。然而在实践中,这会导致设计变量在下一次迭代中转向 NaN。

这可以在下面的简单示例代码中看到

import openmdao.api as om 
import numpy as np

class A(om.ExplicitComponent):

    def setup(self):
        self.add_input('x')
        self.add_output('y')
        self.add_output('y2')

    def compute(self, inputs, outputs):
        outputs['y'] = inputs['x']**2
        outputs['y2']= np.inf

if __name__ == '__main__':

    prob = om.Problem()
    model = prob.model

    idv = model.add_subsystem('idv', om.IndepVarComp(), promotes=['*'])
    idv.add_output('x')
    model.add_subsystem('A', A(), promotes=['*'])

    model.add_design_var('x')

    model.add_constraint('x', lower=2)
    model.add_constraint('y2', lower=2)
    model.add_objective('y')

    # Setup Optimization
    prob.driver = om.ScipyOptimizeDriver()
    prob.driver.options['optimizer'] = 'SLSQP'
    prob.driver.options['maxiter'] = 5
    prob.driver.options['debug_print'] = ['desvars', 'nl_cons', 'objs', 'totals']
    model.approx_totals()

    prob.setup()
    prob.run_driver()

    print('---')
    print(prob['y'])

尽管 y2 始终大于 2,但设计变量 x 的计算结果仍为 NaN。我做了一个快速修复,我只是检查约束是否无限并将其替换为通用的非常大的浮点数(例如 999999999),但这看起来不是很 pythonic,因此我很好奇最佳实践。

我认为最好的处理方法是通过重新排列方程式来避免它。而不是

con1: (allowable_force / applied_force) > 2

尝试:

con1: applied_force < 0.5 * allowable_force 

那里没有除法,所以你没有除以零。

您一定要避免 inf 或 NaN 预计会经常出现在您的变量中的情况,因为您的求解器和优化器可能无法收敛或找到正确的搜索方向。

但是,对于无法避免的组件输出计算,有时我们不得不在输出太接近于零时将其替换为较小的值。这也会在导数中引入不连续性,这也可能是一个问题。