0

我正在尝试使用 OpenMDAO 作为验证手段来解决MDO 测试套件中的问题。我面临的问题是为给定问题选择优化器/算法。

以下是通过 IDF 方法制定的套件中丙烷燃烧问题的代码。我尝试使用 pyOptSparseDriver 中提供的 SLSQP 和 NSGA2 来解决。但是两个优化器都给出了次优的解决方案。

    from __future__ import print_function, division
    import numpy as np
    import time
    from openmdao.api import *

    class PropaneDis1(Component):
        def __init__(self):
            super(PropaneDis1, self).__init__()

            self.add_param('z1', 1.0)
            self.add_param('y3', np.ones(3))

            self.add_output('y1', val=np.ones(2))

        def solve_nonlinear(self, params, unknowns, resids):

            z1 = params['z1']
            y31 = params['y3'][0]

            y12 = 3.0 - z1
            y11 = z1*y31/y12

            unknowns['y1'] = np.array([y11, y12])

    class PropaneDis2(Component):
        def __init__(self):
            super(PropaneDis2, self).__init__()

            self.add_param('z1', val= 0.0)
            self.add_param('y1', val= np.ones(2))
            self.add_param('y3', val= np.ones(3))

            self.add_output('y2', val=np.ones(2))

        def solve_nonlinear(self, params, unknowns, resids):

            z1 = params['z1']
            y12 = params['y1'][1]
            y33 = params['y3'][2]

            y21 = 0.1*z1*y33/(40.0*y12)
            y22 = 0.1*(z1**2)*y33/(40.0*(y12**2))

            unknowns['y2'] = np.array([y21, y22])

    class PropaneDis3(Component):
        def __init__(self):
            super(PropaneDis3, self).__init__()

            self.add_param('z1', val=0.0)
            self.add_param('y1', val=np.ones(2))
            self.add_param('y2', val=np.ones(2))
            self.add_param('x3', val=np.ones(3))

            self.add_output('y3', val=np.ones(3))

        def solve_nonlinear(self, params, unknowns, resids):

            z1 = params['z1']
            y11 = params['y1'][0]
            x31 = params['x3'][0]
            y12 = params['y1'][1]
            x32 = params['x3'][1]
            x33 = params['x3'][2]
            y21 = params['y2'][0]
            y22 = params['y2'][1]

            y31 = (8.0 - 2*y11 - x32 - x33)/2.0
            y32 = 4*10.0 - 2*x31
            y33 = z1 + y11 + x31 + y12 + x32 + x33 + y21 + y22 + y31 + y32

            unknowns['y3'] = np.array([y31, y32, y33])


    class PropaneIDF(Group):

        def __init__(self):
            super(PropaneIDF, self).__init__()

            self.add('pz1', IndepVarComp('z1', val=1.0), promotes=['*'])
            self.add('px3', IndepVarComp('x3', val=np.array([20.0,1.5,1.0])), promotes=['*'])
            self.add('py1t', IndepVarComp('y1t', val=np.array([1.0,1.0])), promotes=['*'])
            self.add('py2t', IndepVarComp('y2t', val=np.array([1.0,1.0])), promotes=['*'])
            self.add('py3t', IndepVarComp('y3t', val=np.array([1.0,1.0,1.0])), promotes=['*'])

            self.add('d1', PropaneDis1(), promotes=['z1', 'y1'])
            self.add('d2', PropaneDis2(), promotes=['z1', 'y2'])
            self.add('d3', PropaneDis3(), promotes=['z1', 'x3', 'y3'])

            self.connect('y1t', 'd2.y1')
            self.connect('y1t', 'd3.y1')

            self.connect('y2t', 'd3.y2')

            self.connect('y3t', 'd1.y3')
            self.connect('y3t', 'd2.y3')

            self.add('con_cmp1', ExecComp('f2=2*z1 + y1[0] + y1[1] + x3[2] + y2[0] + y3[1] + 2*y2[1] - 10.0'
                     , z1=0.0, y1=np.zeros(2), y2=np.zeros(2), y3=np.zeros(3), x3=np.zeros(3))
                     , promotes=['*'])
            self.add('con_cmp2', ExecComp('f6=abs(y1[0]*y1[1])**0.5 - x3[1]*abs(40.0*z1/y3[2])**0.5'
                     , z1=0.0, y1=np.zeros(2), y3=np.ones(3), x3=np.zeros(3))
                     , promotes=['*'])
            self.add('con_cmp3', ExecComp('f7=abs(z1*y1[0])**0.5 - x3[2]*abs(40.0*y1[1]/y3[2])**0.5'
                     , z1=0.0, y1=np.zeros(2), y3=np.ones(3), x3=np.zeros(3))
                     , promotes=['*'])
            self.add('con_cmp4', ExecComp('f9=z1*(x3[0]**0.5) - y1[1]*y3[1]*(40.0/y3[2])**0.5'
                     , z1=0.0, y1=np.zeros(2), y3=np.zeros(3), x3=np.zeros(3))
                     , promotes=['*'])

            self.add('con_cmp51', ExecComp('con51=y1t[0] - y1[0]', y1t=np.zeros(2), y1=np.zeros(2)), promotes=['*'])
            self.add('con_cmp52', ExecComp('con52=y1t[1] - y1[1]', y1t=np.zeros(2), y1=np.zeros(2)), promotes=['*'])

            self.add('con_cmp61', ExecComp('con61=y2t[0] - y2[0]', y2t=np.zeros(2), y2=np.zeros(2)), promotes=['*'])
            self.add('con_cmp62', ExecComp('con62=y2t[1] - y2[1]', y2t=np.zeros(2), y2=np.zeros(2)), promotes=['*'])

            self.add('con_cmp71', ExecComp('con71=y3t[0] - y3[0]', y3t=np.zeros(3), y3=np.zeros(3)), promotes=['*'])
            self.add('con_cmp72', ExecComp('con72=y3t[1] - y3[1]', y3t=np.zeros(3), y3=np.zeros(3)), promotes=['*'])
            self.add('con_cmp73', ExecComp('con73=y3t[2] - y3[2]', y3t=np.zeros(3), y3=np.zeros(3)), promotes=['*'])

            self.add('obj_cmp', ExecComp('obj=2*z1 + y1[0] + y1[1] + x3[2] + y2[0] + y3[1] + 2*y2[1] - 10.0 +\
                                         abs(y1[0]*y1[1])**0.5 - x3[1]*abs(40.0*z1/y3[2])**0.5+\
                                         abs(z1*y1[0])**0.5 - x3[2]*abs(40.0*y1[1]/y3[2])**0.5+\
                                         z1*(x3[0]**0.5) - y1[1]*y3[1]*(40.0/y3[2])**0.5 '
                     , z1=0.0, y1=np.zeros(2), y2=np.zeros(2), y3=np.zeros(3), x3=np.zeros(3))
                     , promotes=['*'])

            self.fd_options['force_fd']=True
            self.fd_options['step_size']=1.0e-12

    top = Problem()
    top.root = PropaneIDF()

    top.driver = pyOptSparseDriver()
    top.driver.options['optimizer']='SLSQP'

    top.driver.add_desvar('z1', lower=0.0, upper=20.0)
    top.driver.add_desvar('x3', lower=np.array([0.0, 0.0, 0.0]), upper=np.array([20.0, 20.0, 20.0]))
    top.driver.add_desvar('y1t', lower=np.array([0.0, 0.0]), upper=np.array([20.0, 20.0]))
    top.driver.add_desvar('y2t', lower=np.array([0.0, 0.0]), upper=np.array([20.0, 20.0]))
    top.driver.add_desvar('y3t', lower=np.array([0.0, 0.0, 0.0]), upper=np.array([20.0, 20.0, 20.0]))

    top.driver.add_objective('obj')

    top.driver.add_constraint('con51', equals=0.0)
    top.driver.add_constraint('con52', equals=0.0)
    top.driver.add_constraint('con61', equals=0.0)
    top.driver.add_constraint('con62', equals=0.0)
    top.driver.add_constraint('con71', equals=0.0)
    top.driver.add_constraint('con72', equals=0.0)
    top.driver.add_constraint('con73', equals=0.0)

    top.driver.add_constraint('f2', lower=0.0)
    top.driver.add_constraint('f6', lower=0.0)
    top.driver.add_constraint('f7', lower=0.0)
    top.driver.add_constraint('f9', lower=0.0)
    # top.driver.add_constraint('f2', equals=0.0)
    # top.driver.add_constraint('f6', equals=0.0)
    # top.driver.add_constraint('f7', equals=0.0)
    # top.driver.add_constraint('f9', equals=0.0)

    top.setup()
    tt = time.time()

    top.run()

SLSQP 解决方案 -

    Optimization using pyOpt_sparse
    ================================================================================

            Objective Function: _objfunc

        Solution:
    --------------------------------------------------------------------------------
        Total Time:                    0.1535
           User Objective Time :       0.0183
           User Sensitivity Time :     0.0806
           Interface Time :            0.0534
           Opt Solver Time:            0.0013
        Calls to Objective Function :      10
        Calls to Sens Function :            7

        Objectives:
            Name        Value        Optimum
            obj        14.3997             0

       Variables (c - continuous, i - integer, d - discrete):
               Name      Type       Value       Lower Bound  Upper Bound
            z1_0      c       2.130827       0.00e+00     2.00e+01
            x3_0      c      20.000000       0.00e+00     2.00e+01
            x3_1      c       0.000000       0.00e+00     2.00e+01
            x3_2      c      -0.000000       0.00e+00     2.00e+01
           y1t_0      c       3.645641       0.00e+00     2.00e+01
           y1t_1      c       0.869179       0.00e+00     2.00e+01
           y2t_0      c       0.180723       0.00e+00     2.00e+01
           y2t_1      c       0.679352       0.00e+00     2.00e+01
           y3t_0      c       1.691004       0.00e+00     2.00e+01
           y3t_1      c      -0.000000       0.00e+00     2.00e+01
           y3t_2      c      20.000000       0.00e+00     2.00e+01

       Constraints (i - inequality, e - equality):
            Name    Type                    Bounds
           con51      i        0.00e+00 <= -0.499951 <= 0.00e+00
           con52      i        0.00e+00 <= 0.000006 <= 0.00e+00
           con61      i        0.00e+00 <= 0.058146 <= 0.00e+00
           con62      i        0.00e+00 <= 0.378850 <= 0.00e+00
           con71      i        0.00e+00 <= 1.336646 <= 0.00e+00
           con72      i        0.00e+00 <= -0.000000 <= 0.00e+00
           con73      i        0.00e+00 <= -7.860081 <= 0.00e+00
             f2       i        0.00e+00 <= -0.000000 <= 1.00e+20
             f6       i        0.00e+00 <= 1.898220 <= 1.00e+20
             f7       i        0.00e+00 <= 2.972127 <= 1.00e+20
             f9       i        0.00e+00 <= 9.529347 <= 1.00e+20

    --------------------------------------------------------------------------------

NSGA2 的解决方案 -

    Optimization using pyOpt_sparse
    ================================================================================

            Objective Function: _objfunc

        Solution:
    --------------------------------------------------------------------------------
        Total Time:                  107.5302
           User Objective Time :      62.5869
           User Sensitivity Time :     0.0000
           Interface Time :           41.6987
           Opt Solver Time:            3.2446
        Calls to Objective Function :   99981
        Calls to Sens Function :            0

        Objectives:
            Name        Value        Optimum
            obj        7.67208             0

       Variables (c - continuous, i - integer, d - discrete):
               Name      Type       Value       Lower Bound  Upper Bound
            z1_0      c       2.184051       0.00e+00     2.00e+01
            x3_0      c      20.000000       0.00e+00     2.00e+01
            x3_1      c       0.000000       0.00e+00     2.00e+01
            x3_2      c       0.000000       0.00e+00     2.00e+01
           y1t_0      c       3.757993       0.00e+00     2.00e+01
           y1t_1      c       0.815949       0.00e+00     2.00e+01
           y2t_0      c       0.193249       0.00e+00     2.00e+01
           y2t_1      c       0.746901       0.00e+00     2.00e+01
           y3t_0      c       1.592243       0.00e+00     2.00e+01
           y3t_1      c      -0.000000       0.00e+00     2.00e+01
           y3t_2      c      20.000000       0.00e+00     2.00e+01

       Constraints (i - inequality, e - equality):
            Name    Type                    Bounds
           con51      i        0.00e+00 <= 0.173682 <= 0.00e+00
           con52      i        0.00e+00 <= -0.520903 <= 0.00e+00
           con61      i        0.00e+00 <= -0.122582 <= 0.00e+00
           con62      i        0.00e+00 <= -0.292454 <= 0.00e+00
           con71      i        0.00e+00 <= -0.120713 <= 0.00e+00
           con72      i        0.00e+00 <= 0.000372 <= 0.00e+00
           con73      i        0.00e+00 <= -7.729249 <= 0.00e+00
             f2       i        0.00e+00 <= 0.143730 <= 1.00e+20
             f6       i        0.00e+00 <= 1.641686 <= 1.00e+20
             f7       i        0.00e+00 <= 1.957046 <= 1.00e+20
             f9       i        0.00e+00 <= 3.929613 <= 1.00e+20

    ----------------------------------------------------------------------

我知道问题不在于定义,因为我尝试使用约束 f2、f6、f7 和 f9 作为等式约束 (=0) 而不是下限来运行问题,我得到了最优值。

那么,我应该研究哪些其他优化器?或者是否有任何其他问题让我对优化器的问题感到困惑。

提前致谢。

4

1 回答 1

0

首先,查看 SLSQP 输出,优化器根本无法提供可行的解决方案。具体来说,约束 con51 到 con73 有许多违规行为。这些是替换学科组件之间循环依赖关系的兼容性方程,因此优化器似乎无法收敛多学科耦合。

我已经使用了您的代码并尝试了一些事情,包括转换为 MDF 配置并将非线性求解器切换到 Newton 以查看它如何处理收敛单个 MDA 循环(因此我还取出了优化器)。假设其他设计变量保持在初始条件,我让它收敛到一个不错的 1e-10 容差:

y1 [ 1.  2.]
y2 [ 0.05886036  0.02943018]
y3 [  2.          38.          47.08829054]

请注意,y3 的收敛值远远超出了您在 IDF 下使用 y3t 作为设计变量时指定的上限:

top.driver.add_desvar('y3t', lower=np.array([0.0, 0.0, 0.0]),
                             upper=np.array([10.0, 10.0, 10.0]))

我不确定您的上限在哪里,因为我没有在丙烷问题中看到它们。更重要的是,我无法将我在您的代码中看到的内容与 MDO 测试套件链接中指定的内容相匹配。我怀疑可能有一些错误,但无法验证任何内容。

于 2016-05-31T15:21:00.493 回答