Compare two 2D arrays of spatial or time profiles. Each data set should contain the time or space coordinate in the first column and data series to be compared in successive columns. The coordinates in each data set do not need to be the same: The data from the second data set
(reference, sample, rtol=1e-5, atol=1e-12, xtol=1e-5)
| 31 | np.savetxt(reference_file, data, fmt='%.10e') |
| 32 | |
| 33 | def compareProfiles(reference, sample, rtol=1e-5, atol=1e-12, xtol=1e-5): |
| 34 | """ |
| 35 | Compare two 2D arrays of spatial or time profiles. Each data set should |
| 36 | contain the time or space coordinate in the first column and data series |
| 37 | to be compared in successive columns. |
| 38 | |
| 39 | The coordinates in each data set do not need to be the same: The data from |
| 40 | the second data set will be interpolated onto the coordinates in the first |
| 41 | data set before being compared. This means that the range of the "sample" |
| 42 | data set should be at least as long as the "reference" data set. |
| 43 | |
| 44 | After interpolation, each data point must satisfy a combined relative and absolute |
| 45 | error criterion specified by `rtol` and `atol`. |
| 46 | |
| 47 | If the comparison succeeds, this function returns `None`. If the comparison |
| 48 | fails, a formatted report of the differing elements is returned. |
| 49 | """ |
| 50 | if isinstance(reference, (str, PurePath)): |
| 51 | reference = np.genfromtxt(reference, delimiter=',').T |
| 52 | else: |
| 53 | reference = np.asarray(reference).T |
| 54 | |
| 55 | if isinstance(sample, (str, PurePath)): |
| 56 | sample = np.genfromtxt(sample, delimiter=',').T |
| 57 | else: |
| 58 | sample = np.asarray(sample).T |
| 59 | |
| 60 | assert reference.shape[0] == sample.shape[0] |
| 61 | |
| 62 | nVars = reference.shape[0] |
| 63 | nTimes = reference.shape[1] |
| 64 | |
| 65 | bad = [] |
| 66 | template = '{0:9.4e} {1: 3d} {2:14.7e} {3:14.7e} {4:9.3e} {5:9.3e} {6:9.3e}' |
| 67 | for i in range(1, nVars): |
| 68 | scale = max(max(abs(reference[i])), np.ptp(reference[i]), |
| 69 | max(abs(sample[i])), np.ptp(sample[i])) |
| 70 | slope = np.zeros(nTimes) |
| 71 | slope[1:] = np.diff(reference[i]) / np.diff(reference[0]) * np.ptp(reference[0]) |
| 72 | |
| 73 | comp = np.interp(reference[0], sample[0], sample[i]) |
| 74 | for j in range(nTimes): |
| 75 | a = reference[i,j] |
| 76 | b = comp[j] |
| 77 | abserr = abs(a-b) |
| 78 | relerr = abs(a-b) / (scale + atol) |
| 79 | |
| 80 | # error that can be accounted for by shifting the profile along |
| 81 | # the time / spatial coordinate |
| 82 | xerr = abserr / (abs(slope[j]) + atol) |
| 83 | |
| 84 | if abserr > atol and relerr > rtol and xerr > xtol: |
| 85 | bad.append((reference[0][j], i, a, b, abserr, relerr, xerr)) |
| 86 | |
| 87 | footer = [] |
| 88 | maxrows = 10 |
| 89 | if len(bad) > maxrows: |
| 90 | bad.sort(key=lambda row: -row[5]) |