def test_interpolate_downsample(tstart, tend, n, data, method): """Check interpolate then downsamples gives sensible results""" dmax = data.max() dmin = data.min() if dmax + dmin < 0: data -= 10 * np.abs(dmax) if "dropped" in data.attrs: data.attrs["dropped"] -= 10 * np.abs(dmax) else: data += 10 * np.abs(dmin) if "dropped" in data.attrs: data.attrs["dropped"] += 10 * np.abs(dmin) if tstart > tend: tstart, tend = tend, tstart times = data.coords["t"] original_freq = (len(times) - 1) / float(times[-1] - times[0]) new_times = times.sel(t=slice(tstart + 0.5 / original_freq, tend - 0.5 / original_freq)) assume(len(new_times) > 1) new_tstart = float(new_times[0]) new_tend = float(new_times[-1]) frequency = (n - 1) / (tend - tstart) result = convert_in_time(tstart, tend, frequency, data, "cubic") result2 = convert_in_time(new_tstart, new_tend, original_freq, result, method) assert np.all(result2.values == approx( data.sel(t=new_times).values, rel=1e-1, abs=1e-2, nan_ok=True)) if "dropped" in data.attrs: assert np.all(result2.attrs["dropped"].values == approx( data.attrs["dropped"].sel(t=new_times).values, rel=1e-1, abs=1e-2))
def test_invalid_start_time(tstart, tend, n, data, method): """Test an exception is raised when tstart falls outside of the available data.""" frequency = (n - 1) / (tend - tstart) # This frequency is not exactly the one which will actually be # used when binning, so make extra offset to ensure outside of # range. tstart -= 1.0 / frequency + 1e-8 assume(abs(tend - tstart) * frequency >= 2.0) with raises(ValueError, match="Start time|first bin"): convert_in_time(tstart, tend, frequency, data, method)
def test_call_bin(tstart, tend, frequency_factor, data, method): """Check binning is used when a low frequency is specified.""" if tstart > tend: tstart, tend = tend, tstart times = data.coords["t"] original_freq = (len(times) - 1) / float(times[-1] - times[0]) frequency = frequency_factor * original_freq with patch("indica.converters.time.bin_in_time"): convert_in_time(tstart, tend, frequency, data, method) from indica.converters.time import bin_in_time bin_in_time.assert_called_with(tstart, tend, frequency, data)
def test_call_interpolate(tstart, tend, frequency_factor, data, method): """Check interpolation is used when a high frequency is specified.""" if tstart > tend: tstart, tend = tend, tstart times = data.coords["t"] original_freq = (len(times) - 1) / float(times[-1] - times[0]) frequency = frequency_factor * original_freq with patch("indica.converters.time.interpolate_in_time"): from indica.converters.time import interpolate_in_time convert_in_time(tstart, tend, frequency, data, method) interpolate_in_time.assert_called_with(tstart, tend, frequency, data, method)
def test_correct_time_values(tstart, tend, n, data, method): """Check always have requested time values.""" if tstart > tend: tstart, tend = tend, tstart frequency = (n - 1) / (tend - tstart) assume((tend - tstart) * frequency >= 2.0) result = convert_in_time(tstart, tend, frequency, data, method) time_arrays = [result.coords["t"]] if "error" in data.attrs: time_arrays.append(result.attrs["error"].coords["t"]) if "dropped" in data.attrs: time_arrays.append(result.attrs["dropped"].coords["t"]) if "error" in data.attrs: time_arrays.append( result.attrs["dropped"].attrs["error"].coords["t"]) for times in time_arrays: tdiffs = times[1:] - times[:-1] length = len(times) actual_frequency = (length - 1) / (tend - tstart) assert times[0] == approx(tstart) assert times[-1] == approx(tend) if length >= 2: assert np.all(tdiffs == approx(float(tdiffs[0]))) assert abs(frequency - actual_frequency) < abs(frequency - length / (tend - tstart)) assert abs(frequency - actual_frequency) < abs(frequency - (length - 2) / (tend - tstart))
def test_interpolate_linear_data(tstart, tend, n, times, a, b, abs_err, method): """Test interpolate/downsample on linear data""" def count_floor(count): floor = np.floor(count) if np.isclose(floor, count, 1e-12, 1e-12): floor -= 1 return floor def count_ceil(count): ceil = np.ceil(count) if np.isclose(ceil, count, 1e-12, 1e-12): ceil += 1 return ceil data = linear_data_array(a, b, times, abs_err) if tstart > tend: tstart, tend = tend, tstart original_frequency = 1 / (times[1] - times[0]) frequency = (n - 1) / (tend - tstart) tstart += 0.5 / frequency tend -= 0.5 / frequency assume(tstart < tend) assume((tend - tstart) * frequency >= 2.0) result = convert_in_time(tstart, tend, frequency, data, method) new_times = result.coords["t"] expected = a * new_times + b if frequency / original_frequency <= 0.2: assert np.all(result.values == approx( expected.values, abs=max(1e-12, 0.5 * np.abs(a) / original_frequency))) else: assert np.all(result.values == approx(expected.values)) assert np.all(result.attrs["error"].values == approx(abs_err))
def test_unchanged_axes(tstart, tend, n, data, method): """Check other axes unchanged""" if tstart > tend: tstart, tend = tend, tstart frequency = (n - 1) / (tend - tstart) assume((tend - tstart) * frequency >= 2.0) result = convert_in_time(tstart, tend, frequency, data, method) all_results = [(result, data)] if "error" in data.attrs: all_results.append((result.attrs["error"].coords["t"], data.attrs["error"].coords["t"])) if "dropped" in data.attrs: all_results.append((result.attrs["dropped"].coords["t"], data.attrs["dropped"].coords["t"])) if "error" in data.attrs: all_results.append(( result.attrs["dropped"].attrs["error"].coords["t"], data.attrs["dropped"].attrs["error"].coords["t"], )) for res, orig in all_results: assert res.dims == orig.dims for dim, coords in res.coords.items(): if dim == "t": continue assert np.all(coords == orig.coords[dim])
def test_unchanged_attrs(tstart, tend, n, data, method): """Check other axes unchanged""" if tstart > tend: tstart, tend = tend, tstart frequency = (n - 1) / (tend - tstart) assume((tend - tstart) * frequency >= 2.0) result = convert_in_time(tstart, tend, frequency, data, method) # Strip any provenance until this is implemented strip_provenance(data) strip_provenance(result) assert set(result.attrs) == set(data.attrs) for key, val in result.attrs.items(): if key == "error" or key == "dropped": continue assert data.attrs[key] == val