示例#1
0
def assert_check_partials(data, atol=1e-6, rtol=1e-6):
    """
    Raise assertion if any entry from the return from check_partials is above a tolerance.

    Parameters
    ----------
    data : dict of dicts of dicts
            First key:
                is the component name;
            Second key:
                is the (output, input) tuple of strings;
            Third key:
                is one of ['rel error', 'abs error', 'magnitude', 'J_fd', 'J_fwd', 'J_rev'];

            For 'rel error', 'abs error', 'magnitude' the value is: A tuple containing norms for
                forward - fd, adjoint - fd, forward - adjoint.
            For 'J_fd', 'J_fwd', 'J_rev' the value is: A numpy array representing the computed
                Jacobian for the three different methods of computation.
    atol : float
        Absolute error. Default is 1e-6.
    rtol : float
        Relative error. Default is 1e-6.
    """
    error_string = ''
    absrel_header = 'abs/rel'
    wrt_header = '< output > wrt < variable >'
    norm_value_header = 'norm value'
    len_absrel_width = len(absrel_header)
    norm_types = ['fwd-fd', 'rev-fd', 'fd-rev']
    len_norm_type_width = max(len(s) for s in norm_types)

    for comp in data:
        len_wrt_width = len(wrt_header)
        len_norm_width = len(norm_value_header)
        bad_derivs = []

        # Find all derivatives whose errors exceed tolerance.
        # Also, size the output to precompute column extents.
        for (var, wrt) in data[comp]:
            pair_data = data[comp][var, wrt]
            for error_type, tolerance in [('abs error', atol), ('rel error', rtol), ]:
                actual = pair_data[error_type]
                for error_val, mode in zip(actual, norm_types):
                    in_error = False

                    if error_val is None:
                        # Reverse derivatives only computed on matrix free comps.
                        continue

                    if not np.isnan(error_val):
                        if not np.allclose(error_val, 0.0, atol=tolerance):

                            if error_type == 'rel error' and mode == 'fwd-fd' and \
                               np.allclose(pair_data['J_fwd'], 0.0, atol=atol) and \
                               np.allclose(pair_data['J_fd'], 0.0, atol=atol):
                                # Special case: both fd and fwd are really tiny, so we want to
                                # ignore the rather large relative errors.
                                in_error = False
                            else:
                                # This is a bona-fide error.
                                in_error = True

                    elif error_type == 'abs error' and mode == 'fwd-fd':
                        # Either analytic or approximated derivatives contain a NaN.
                        in_error = True

                    if in_error:
                        wrt_string = '{0} wrt {1}'.format(var, wrt)
                        norm_string = '{}'.format(error_val)
                        bad_derivs.append((wrt_string, norm_string, error_type, mode))
                        len_wrt_width = max(len_wrt_width, len(wrt_string))
                        len_norm_width = max(len_norm_width, len(norm_string))

        if bad_derivs:
            comp_error_string = ''
            for wrt_string, norm_string, error_type, mode in bad_derivs:
                err_msg = '{0} | {1} | {2} | {3}'.format(
                    pad_name(wrt_string, len_wrt_width),
                    pad_name(error_type.split()[0], len_absrel_width),
                    pad_name(mode, len_norm_type_width),
                    pad_name(norm_string, len_norm_width)) + '\n'
                comp_error_string += err_msg

            name_header = 'Component: {}\n'.format(comp)
            len_name_header = len(name_header)
            header = len_name_header * '-' + '\n'
            header += name_header
            header += len_name_header * '-' + '\n'
            header += '{0} | {1} | {2} | {3}'.format(
                pad_name(wrt_header, len_wrt_width),
                pad_name(absrel_header, len_absrel_width),
                pad_name('norm', len_norm_type_width),
                pad_name(norm_value_header, len_norm_width),
            ) + '\n'
            header += '{0} | {1} | {2} | {3}'.format(
                len_wrt_width * '-',
                len_absrel_width * '-',
                len_norm_type_width * '-',
                len_norm_width * '-',
            ) + '\n'
            comp_error_string = header + comp_error_string
            error_string += comp_error_string

    # if error string then raise error with that string
    if error_string:
        header_line1 = 'Assert Check Partials failed for the following Components'
        header_line2 = 'with absolute tolerance = {} and relative tolerance = {}'.format(atol, rtol)
        header_width = max(len(header_line1), len(header_line2))
        header = '\n' + header_width * '=' + '\n'
        header += header_line1 + '\n'
        header += header_line2 + '\n'
        header += header_width * '=' + '\n'
        error_string = header + error_string
        raise ValueError(error_string)
示例#2
0
def assert_check_partials(data, atol=1e-6, rtol=1e-6):
    """
    Raise assertion if any entry from the return from check_partials is above a tolerance.

    Parameters
    ----------
    data : dict of dicts of dicts
            First key:
                is the component name;
            Second key:
                is the (output, input) tuple of strings;
            Third key:
                is one of ['rel error', 'abs error', 'magnitude', 'J_fd', 'J_fwd', 'J_rev'];

            For 'rel error', 'abs error', 'magnitude' the value is: A tuple containing norms for
                forward - fd, adjoint - fd, forward - adjoint.
            For 'J_fd', 'J_fwd', 'J_rev' the value is: A numpy array representing the computed
                Jacobian for the three different methods of computation.
    atol : float
        absolute error. Default is 1e-6.
    rtol : float
        relative error. Default is 1e-6.
    """
    error_string = ''
    absrel_header = 'abs/rel'
    wrt_header = '< output > wrt < variable >'
    norm_value_header = 'norm value'
    len_absrel_width = len(absrel_header)
    norm_types = ['fwd-fd', 'rev-fd', 'fd-rev']
    len_norm_type_width = max(len(s) for s in norm_types)
    for comp in data:
        # First do a pass to get the max widths for the columns. Also check to see if any over tol
        #  in this Component
        len_wrt_width = len(wrt_header)
        len_norm_width = len(norm_value_header)
        over_tol = False
        for (var, wrt) in data[comp]:
            for error_type, tolerance in [
                ('abs error', atol),
                ('rel error', rtol),
            ]:
                actual = data[comp][var, wrt][error_type]
                for norm, norm_type in zip(actual, norm_types):
                    if not np.isnan(norm):
                        if not np.allclose(norm, 0.0, atol=tolerance):
                            over_tol = True
                            wrt_string = '{0} wrt {1}'.format(var, wrt)
                            norm_string = '{}'.format(norm)
                            len_wrt_width = max(len_wrt_width, len(wrt_string))
                            len_norm_width = max(len_norm_width,
                                                 len(norm_string))

        if over_tol:
            comp_error_string = ''
            for (var, wrt) in data[comp]:
                for error_type, tolerance in [
                    ('abs error', atol),
                    ('rel error', rtol),
                ]:
                    actual = data[comp][var, wrt][error_type]
                    for norm, norm_type in zip(actual, norm_types):
                        if not np.isnan(norm):
                            if not np.allclose(norm, 0.0, atol=tolerance):
                                wrt_string = '{0} wrt {1}'.format(var, wrt)
                                norm_string = '{}'.format(norm)
                                err_msg = '{0} | {1} | {2} | {3}'.format(
                                    pad_name(wrt_string, len_wrt_width),
                                    pad_name(error_type.split()[0],
                                             len_absrel_width),
                                    pad_name(norm_type, len_norm_type_width),
                                    pad_name(norm_string,
                                             len_norm_width)) + '\n'
                                comp_error_string += err_msg

            name_header = 'Component: {}\n'.format(comp)
            len_name_header = len(name_header)
            header = len_name_header * '-' + '\n'
            header += name_header
            header += len_name_header * '-' + '\n'
            header += '{0} | {1} | {2} | {3}'.format(
                pad_name(wrt_header, len_wrt_width),
                pad_name(absrel_header, len_absrel_width),
                pad_name('norm', len_norm_type_width),
                pad_name(norm_value_header, len_norm_width),
            ) + '\n'
            header += '{0} | {1} | {2} | {3}'.format(
                len_wrt_width * '-',
                len_absrel_width * '-',
                len_norm_type_width * '-',
                len_norm_width * '-',
            ) + '\n'
            comp_error_string = header + comp_error_string
            error_string += comp_error_string

    # if error string then raise error with that string
    if error_string:
        header_line1 = 'Assert Check Partials failed for the following Components'
        header_line2 = 'with absolute tolerance = {} and relative tolerance = {}'.format(
            atol, rtol)
        header_width = max(len(header_line1), len(header_line2))
        header = '\n' + header_width * '=' + '\n'
        header += header_line1 + '\n'
        header += header_line2 + '\n'
        header += header_width * '=' + '\n'
        error_string = header + error_string
        raise ValueError(error_string)