Example #1
0
    def assertAlmostEqual64(self, actual, desired, atol=2e-15, rtol=2e-3):
        '''Assert numerical equivalence with packed data.

    Test closeness of ``actual`` to ``desired`` data, where the latter are
    specified as a base64 packed data string (see :func:`nutils.numeric.pack`
    and :func:`nutils.numeric.unpack` for details on packing). The primary use
    case is embedded regression testing.

    The ``atol`` and ``rtol`` arguments are used for both unpacking and
    equivalence testing and cannot be changed independently of the base64 string.
    Doing so will raise an exception with a suggested update.

    Args
    ----
    actual : :class:`float` array
      The obtained data.
    desired : :class:`str`
      The desired data in the form of a base64 string.
    atol : :class:`float`
      Absolute tolerance
    rtol : :class:`float`
      Relative tolerance
    '''

        try:
            desired = numeric.unpack(
                numpy.frombuffer(zlib.decompress(binascii.a2b_base64(desired)),
                                 dtype=numpy.int16), atol,
                rtol).reshape(actual.shape)
        except Exception as e:
            status = ['failed to decode data: {}'.format(e)]
        else:
            error = abs(actual - desired)
            spacing = numpy.sqrt(atol**2 + (desired * rtol)**2)
            fail = numpy.logical_xor(numpy.isnan(actual), numpy.isnan(desired))
            numpy.greater(error, spacing, where=~numpy.isnan(error), out=fail)
            nfail = fail.sum()
            if not nfail:
                return
            status = [
                '{}/{} values do not match up to atol={:.2e}, rtol={:.2e}:'.
                format(nfail, fail.size, atol, rtol)
            ]
            status.extend(
                '{} desired: {:+.4e}, actual: {:+.4e}, spacing: {:.1e}'.format(
                    list(index), desired[index], actual[index], spacing[index])
                for index in zip(*fail.nonzero()))
            if nfail > 10:
                status[6:-5] = '...',
        status.append('If this is expected, update the base64 string to:')
        with warnings.via(status.append):
            s = binascii.b2a_base64(
                zlib.compress(
                    numeric.pack(actual, atol, rtol, numpy.int16).tobytes(),
                    9)).decode().rstrip()
        status.extend(s[i:i + 80] for i in range(0, len(s), 80))
        self.fail('\n'.join(status))
Example #2
0
  def assertAlmostEqual64(self, actual, desired, atol=2e-15, rtol=2e-3):
    '''Assert numerical equivalence with packed data.

    Test closeness of ``actual`` to ``desired`` data, where the latter are
    specified as a base64 packed data string (see :func:`nutils.numeric.pack`
    and :func:`nutils.numeric.unpack` for details on packing). The primary use
    case is embedded regression testing.

    The ``atol`` and ``rtol`` arguments are used for both unpacking and
    equivalence testing and cannot be changed independently of the base64 string.
    Doing so will raise an exception with a suggested update.

    Args
    ----
    actual : :class:`float` array
      The obtained data.
    desired : :class:`str`
      The desired data in the form of a base64 string.
    atol : :class:`float`
      Absolute tolerance
    rtol : :class:`float`
      Relative tolerance
    '''

    try:
      desired = numeric.unpack(numpy.frombuffer(zlib.decompress(binascii.a2b_base64(desired)), dtype=numpy.int16), atol, rtol).reshape(actual.shape)
    except Exception as e:
      status = ['failed to decode data: {}'.format(e)]
    else:
      error = abs(actual - desired)
      spacing = numpy.sqrt(atol**2 + (desired*rtol)**2)
      fail = numpy.logical_xor(numpy.isnan(actual), numpy.isnan(desired))
      numpy.greater(error, spacing, where=~numpy.isnan(error), out=fail)
      nfail = fail.sum()
      if not nfail:
        return
      status = ['{}/{} values do not match up to atol={:.2e}, rtol={:.2e}:'.format(nfail, fail.size, atol, rtol)]
      status.extend('{} desired: {:+.4e}, actual: {:+.4e}, spacing: {:.1e}'.format(list(index), desired[index], actual[index], spacing[index]) for index in zip(*fail.nonzero()))
      if nfail > 10:
        status[6:-5] = '...',
    status.append('If this is expected, update the base64 string to:')
    with warnings.via(status.append):
      s = binascii.b2a_base64(zlib.compress(numeric.pack(actual, atol, rtol, numpy.int16).tobytes(), 9)).decode().rstrip()
    status.extend(s[i:i+80] for i in range(0, len(s), 80))
    self.fail('\n'.join(status))