首页 > 解决方案 > 当约束在 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,因此我很好奇最佳实践。

标签: pythonopenmdao

解决方案


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

con1: (allowable_force / applied_force) > 2

尝试:

con1: applied_force < 0.5 * allowable_force 

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

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

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


推荐阅读