tnccmp.py - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
 (HTM) git clone git://src.adamsgaard.dk/pism
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       tnccmp.py (5124B)
       ---
            1 #!/usr/bin/env python3
            2 from sys import argv, exit
            3 from getopt import getopt, GetoptError
            4 
            5 # @package nccmp
            6 # Compares NetCDF files by absolute max norms of difference of variables
            7 ##
            8 # Without options,
            9 # \code
           10 # nccmp.py foo.nc bar.nc
           11 # \endcode
           12 # compares all the variables in \c foo.nc and \c bar.nc.
           13 ##
           14 # Option \c -v allows selecting varibles to compare:
           15 # \code
           16 # nccmp.py -v thk,velbar_mag foo.nc bar.nc
           17 # \endcode
           18 # only compares \c thk and \c velbar_mag.
           19 ##
           20 # Option \c -t sets the tolerance:
           21 # \code
           22 # nccmp.py -t 1e-6 foo.nc bar.nc
           23 # \endcode
           24 # compares all the variables using the tolerance of 1e-6.
           25 ##
           26 # Finally, option \c -x \b excludes variables given with \c -v, instead of
           27 # selecting them for comparison.
           28 ##
           29 # Run with --help to get a "usage" message.
           30 
           31 tol = 0.0   # default tolerance is perfection
           32 
           33 
           34 def success(relative):
           35     if relative:
           36         print("Files are the same within relative tolerance %.1e" % tol)
           37     else:
           38         print("Files are the same within tolerance %.1e" % tol)
           39     exit(0)
           40 
           41 
           42 def failure():
           43     print("Files are different.")
           44     exit(1)
           45 
           46 
           47 usage = """nccmp.py compares NetCDF files by absolute max norms of difference of variables
           48 usage:
           49   nccmp.py foo.nc bar.nc            compare all variables
           50   nccmp.py -v A,B foo.nc bar.nc     compare variables A and B
           51   nccmp.py -x -v C foo.nc bar.nc    compare all variables except C
           52   nccmp.py -t 1e-6 foo.nc bar.nc    use tolerance 1e-6 instead of default of 0"""
           53 
           54 
           55 def usagefailure(message):
           56     print(message)
           57     print()
           58     print(usage)
           59     exit(2)
           60 
           61 
           62 def compare_vars(nc1, nc2, name, tol, relative=False):
           63     from numpy import squeeze, isnan, ma, finfo, fabs
           64     import numpy
           65 
           66     try:
           67         var1 = ma.array(squeeze(nc1.variables[name][:]))
           68     except:
           69         usagefailure("ERROR: VARIABLE '%s' NOT FOUND IN FILE 1" % name)
           70     try:
           71         var2 = ma.array(squeeze(nc2.variables[name][:]))
           72     except:
           73         usagefailure("ERROR: VARIABLE '%s' NOT FOUND IN FILE 2" % name)
           74 
           75     try:
           76         mask = var1.mask | var2.mask
           77     except:
           78         usagefailure("ERROR: VARIABLE '%s' OF INCOMPATIBLE SHAPES (?) IN FILES" % name)
           79 
           80     if mask.all():
           81         print('Variable %10s: no values to compare.' % name)
           82         return
           83 
           84     var1 = ma.array(var1, mask=mask)
           85     var2 = ma.array(var2, mask=mask)
           86 
           87     try:
           88         delta = abs(var1 - var2).max()
           89     except TypeError:
           90         if (var1 == var2).all():
           91             delta = 0
           92         else:
           93             delta = 1
           94 
           95     if relative:
           96         denom = max(abs(var1).max(), abs(var2).max())
           97         print("Variable %s: difference = %e, denominator = %e" % (name, delta, denom))
           98         if denom > 0:
           99             delta = delta / denom
          100             print("  Relative difference = %e" % (delta))
          101 
          102     # The actual check:
          103     #
          104     # Sometimes delta ends up being a denormalized number, which is zero
          105     # for all practical purposes, but is not zero, so we give up on
          106     # bit-for-bit equality here.
          107     if delta > tol:
          108         if tol == 0.0 and delta < 10 * finfo(float).tiny:
          109             print("Variable %s: Treating %e as zero." % (name, delta))
          110             return
          111         print("Variable %s: delta = %e, tol = %e" % (name, delta, tol))
          112         failure()
          113 
          114 
          115 def compare(file1, file2, variables, exclude, tol, relative):
          116     try:
          117         from netCDF4 import Dataset as NC
          118     except:
          119         print("netCDF4 is not installed!")
          120         exit(1)
          121 
          122     print("Comparing %s and %s" % (file1, file2))
          123 
          124     from numpy import unique, r_
          125 
          126     try:
          127         nc1 = NC(file1, 'r')
          128     except:
          129         usagefailure("ERROR: FILE '%s' CANNOT BE OPENED FOR READING" % file1)
          130     try:
          131         nc2 = NC(file2, 'r')
          132     except:
          133         usagefailure("ERROR: FILE '%s' CANNOT BE OPENED FOR READING" % file2)
          134 
          135     if (exclude == False):
          136         if len(variables) == 0:
          137             vars1 = list(nc1.variables.keys())
          138             vars2 = list(nc2.variables.keys())
          139             variables = unique(r_[vars1, vars2])
          140 
          141         for each in variables:
          142             compare_vars(nc1, nc2, each, tol, relative)
          143     else:
          144         vars1 = list(nc1.variables.keys())
          145         vars2 = list(nc2.variables.keys())
          146         vars = unique(r_[vars1, vars2])
          147 
          148         for each in vars:
          149             if (each in variables):
          150                 continue
          151             compare_vars(nc1, nc2, each, tol, relative)
          152 
          153 
          154 if __name__ == "__main__":
          155     from numpy import double
          156     try:
          157         opts, args = getopt(argv[1:], "t:v:xr", ["help", "usage"])
          158     except GetoptError:
          159         usagefailure('ERROR: INCORRECT COMMAND LINE ARGUMENTS FOR nccmp.py')
          160     file1 = ""
          161     file2 = ""
          162     variables = []
          163     exclude = False
          164     relative = False
          165     for (opt, arg) in opts:
          166         if opt == "-t":
          167             tol = double(arg)
          168         if opt == "-x":
          169             exclude = True
          170         if opt == "-r":
          171             relative = True
          172         if opt == "-v":
          173             variables = arg.split(",")
          174         if opt in ("--help", "--usage"):
          175             print(usage)
          176             exit(0)
          177 
          178     if len(args) != 2:
          179         usagefailure('ERROR: WRONG NUMBER OF ARGUMENTS FOR nccmp.py')
          180 
          181     compare(args[0], args[1], variables, exclude, tol, relative)
          182 
          183     success(relative)