首页 > 解决方案 > 由于有限差分步长,区分不正确的小部分和不匹配的正确部分

问题描述

有问题的代码:

class SecondPanelCoordinateInPanelReferenceFrame(om.ExplicitComponent):

    def initialize(self):
        self.options.declare('n', types=int)

    def setup(self):
        n = self.options['n']

        self.add_input('panel_angles', shape=(n,))
        self.add_input('second_panel_coordinate_relative_positions', shape=(2, n))

        self.add_output('second_panel_coordinate_transformed_positions', shape=(2, n))

        self.declare_partials('second_panel_coordinate_transformed_positions', 'panel_angles',
                              rows=np.arange(n),
                              cols=np.arange(n))
        self.declare_partials('second_panel_coordinate_transformed_positions', 'second_panel_coordinate_relative_positions',
                              rows=np.tile(np.arange(n), 2),
                              cols=np.arange(2*n))

    def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
        self.second_panel_coordinate_relative_positions = inputs['second_panel_coordinate_relative_positions']
        self.panel_angles = inputs['panel_angles']

        self.x2r = self.second_panel_coordinate_relative_positions[0, :]  # x2r = x coordinate number 2, relative
        self.y2r = self.second_panel_coordinate_relative_positions[1, :]

        self.cos_angles = np.cos(self.panel_angles)
        self.sin_angles = np.sin(self.panel_angles)

        second_panel_coordinate_transformed_positions = np.zeros_like(self.second_panel_coordinate_relative_positions)
        second_panel_coordinate_transformed_positions[0, :] = self.x2r*self.cos_angles + self.y2r*self.sin_angles

        outputs['second_panel_coordinate_transformed_positions'] = second_panel_coordinate_transformed_positions

    def compute_partials(self, inputs, partials, discrete_inputs=None):

        partials['second_panel_coordinate_transformed_positions',
                 'panel_angles'] = self.y2r*self.cos_angles - self.x2r*self.sin_angles

        partials['second_panel_coordinate_transformed_positions',
                 'second_panel_coordinate_relative_positions'] = np.concatenate([self.cos_angles, self.sin_angles])

我非常有信心我已经正确编写了 second_panel_coordinate_transformed_positions wrt panel_angles 的部分。但是,在运行 check_partials() 时,它会在数量级上标记出相当大的差异。

  InfluenceCoefficientMatrixGroup.SecondPanelCoordinateInPanelReferenceFrame: 'second_panel_coordinate_transformed_positions' wrt 'panel_angles'
    Forward Magnitude : 8.659561e-17
         Fd Magnitude : 7.071696e-07 (fd:forward)
    Absolute Error (Jfor  - Jfd) : 7.071696e-07

    Relative Error (Jfor  - Jfd) : 1.000000e+00 *

    Raw Forward Derivative (Jfor)
[[6.123234e-17 0.000000e+00]
 [0.000000e+00 6.123234e-17]
 [0.000000e+00 0.000000e+00]
 [0.000000e+00 0.000000e+00]]

    Raw FD Derivative (Jfd)
[[-5.0004445e-07  0.0000000e+00]
 [ 0.0000000e+00 -5.0004445e-07]
 [ 0.0000000e+00  0.0000000e+00]
 [ 0.0000000e+00  0.0000000e+00]]

前向和有限差分部分都非常接近于 0,我不确定我的部分是否正确,或者由于有限步长导致的错误是否比我在这里预期的更强烈。我怎样才能找出问题所在?

标签: openmdao

解决方案


当导数的绝对值非常小时,忽略相对误差通常是可以的。

在这种情况下,由于您的计算函数是复数安全的,我们可以使用复数步来获得更准确的部分近似值。

import openmdao.api as om
import numpy as np

class SecondPanelCoordinateInPanelReferenceFrame(om.ExplicitComponent):

    def initialize(self):
        self.options.declare('n', types=int)

    def setup(self):
        n = self.options['n']

        self.add_input('panel_angles', shape=(n,))
        self.add_input('second_panel_coordinate_relative_positions', shape=(2, n))
        self.add_output('second_panel_coordinate_transformed_positions', shape=(2, n))

        self.declare_partials('second_panel_coordinate_transformed_positions', 'panel_angles',
                              rows=np.arange(n),
                              cols=np.arange(n))
        self.declare_partials('second_panel_coordinate_transformed_positions', 'second_panel_coordinate_relative_positions',
                              rows=np.tile(np.arange(n), 2),
                              cols=np.arange(2*n))

    def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
        self.second_panel_coordinate_relative_positions = inputs['second_panel_coordinate_relative_positions']
        self.panel_angles = inputs['panel_angles']

        self.x2r = self.second_panel_coordinate_relative_positions[0, :]  # x2r = x coordinate number 2, relative
        self.y2r = self.second_panel_coordinate_relative_positions[1, :]

        self.cos_angles = np.cos(self.panel_angles)
        self.sin_angles = np.sin(self.panel_angles)

        second_panel_coordinate_transformed_positions = np.zeros_like(self.second_panel_coordinate_relative_positions)
        second_panel_coordinate_transformed_positions[0, :] = self.x2r*self.cos_angles + self.y2r*self.sin_angles

        outputs['second_panel_coordinate_transformed_positions'] = second_panel_coordinate_transformed_positions

    def compute_partials(self, inputs, partials, discrete_inputs=None):
        self.second_panel_coordinate_relative_positions = inputs['second_panel_coordinate_relative_positions']
        self.panel_angles = inputs['panel_angles']

        self.x2r = self.second_panel_coordinate_relative_positions[0, :]  # x2r = x coordinate number 2, relative
        self.y2r = self.second_panel_coordinate_relative_positions[1, :]

        self.cos_angles = np.cos(self.panel_angles)
        self.sin_angles = np.sin(self.panel_angles)

        partials['second_panel_coordinate_transformed_positions',
                 'panel_angles'] = self.y2r*self.cos_angles - self.x2r*self.sin_angles

        partials['second_panel_coordinate_transformed_positions',
                 'second_panel_coordinate_relative_positions'] = np.concatenate([self.cos_angles, self.sin_angles])


if __name__ == '__main__':
    n = 5

    p = om.Problem(model=om.Group())

    ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])

    ivc.add_output('panel_angles', shape=(n,))
    ivc.add_output('second_panel_coordinate_relative_positions', shape=(2, n))

    p.model.add_subsystem('panel_comp', SecondPanelCoordinateInPanelReferenceFrame(n=n), promotes_inputs=['*'])

    p.setup(force_alloc_complex=True)

    p.set_val('panel_angles', np.random.rand(n))
    p.set_val('second_panel_coordinate_relative_positions', np.random.rand(2, n))

    with np.printoptions(linewidth=1024, edgeitems=1000):
        p.check_partials(method='cs')

这给了我们:

------------------------------------------------------------------
Component: SecondPanelCoordinateInPanelReferenceFrame 'panel_comp'
------------------------------------------------------------------
  panel_comp: 'second_panel_coordinate_transformed_positions' wrt 'panel_angles'
    Forward Magnitude : 9.957115e-01
         Fd Magnitude : 9.957115e-01 (cs:None)
    Absolute Error (Jfor  - Jfd) : 3.695246e-16

    Relative Error (Jfor  - Jfd) : 3.711162e-16

    Raw Forward Derivative (Jfor)
[[ 0.18045286  0.          0.          0.          0.        ]
 [ 0.         -0.54661688  0.          0.          0.        ]
 [ 0.          0.         -0.07489634  0.          0.        ]
 [ 0.          0.          0.         -0.15068612  0.        ]
 [ 0.          0.          0.          0.          0.79484104]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]]

    Raw FD Derivative (Jfd)
[[ 0.18045286  0.          0.          0.          0.        ]
 [ 0.         -0.54661688  0.          0.          0.        ]
 [ 0.          0.         -0.07489634  0.          0.        ]
 [ 0.          0.          0.         -0.15068612  0.        ]
 [ 0.          0.          0.          0.          0.79484104]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]
 [ 0.          0.          0.          0.          0.        ]]

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  panel_comp: 'second_panel_coordinate_transformed_positions' wrt 'second_panel_coordinate_relative_positions'
    Forward Magnitude : 2.236068e+00
         Fd Magnitude : 2.236068e+00 (cs:None)
    Absolute Error (Jfor  - Jfd) : 1.922963e-16

    Relative Error (Jfor  - Jfd) : 8.599751e-17

    Raw Forward Derivative (Jfor)
[[0.86465361 0.         0.         0.         0.         0.50236852 0.         0.         0.         0.        ]
 [0.         0.54817618 0.         0.         0.         0.         0.83636288 0.         0.         0.        ]
 [0.         0.         0.8643305  0.         0.         0.         0.         0.50292423 0.         0.        ]
 [0.         0.         0.         0.82015556 0.         0.         0.         0.         0.57214059 0.        ]
 [0.         0.         0.         0.         0.98318242 0.         0.         0.         0.         0.18262619]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]]

    Raw FD Derivative (Jfd)
[[0.86465361 0.         0.         0.         0.         0.50236852 0.         0.         0.         0.        ]
 [0.         0.54817618 0.         0.         0.         0.         0.83636288 0.         0.         0.        ]
 [0.         0.         0.8643305  0.         0.         0.         0.         0.50292423 0.         0.        ]
 [0.         0.         0.         0.82015556 0.         0.         0.         0.         0.57214059 0.        ]
 [0.         0.         0.         0.         0.98318242 0.         0.         0.         0.         0.18262619]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]
 [0.         0.         0.         0.         0.         0.         0.         0.         0.         0.        ]]

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

关于您的计算的一个注意事项......在一些不常见的情况下,在使用相同的输入调用计算之前调用 compute_partials。因此,通常不建议您缓存计算。


推荐阅读