def test_simple_axis1(self): a = np.arange(12).reshape(3, 4) r = Linear1dExtrapolator(interp1d(np.arange(4), a, axis=1)) # check non-extrapolation given the Extrapolator object np.testing.assert_array_equal(r(0), np.array([0., 4., 8.])) # check the result's shape in a 1d array (of len 0 & 1) np.testing.assert_array_equal(r(np.array(0)), np.array([0., 4., 8.])) np.testing.assert_array_equal(r(np.array([0])), np.array([[0.], [4.], [8.]])) # check extrapolation below the minimum value (and check the equivalent 0d & 1d arrays) np.testing.assert_array_equal(r(-1), np.array([-1., 3., 7.])) np.testing.assert_array_equal(r(np.array(-1)), np.array([-1., 3., 7.])) np.testing.assert_array_equal(r(np.array([-1])), np.array([[-1.], [3.], [7.]])) # check extrapolation above the maximum value np.testing.assert_array_equal(r(3), np.array([3., 7., 11.])) np.testing.assert_array_equal(r(2.5), np.array([2.5, 6.5, 10.5])) # 2 Non-extrapolation point np.testing.assert_array_equal( r(np.array([1.5, 2])), np.array([[1.5, 2.], [5.5, 6.], [9.5, 10.]])) # 1 Non-extrapolation point & 1 upper value extrapolation np.testing.assert_array_equal( r(np.array([1.5, 5])), np.array([[1.5, 5.], [5.5, 9.], [9.5, 13.]])) # 2 upper value extrapolation np.testing.assert_array_equal( r(np.array([4.5, 5])), np.array([[4.5, 5.], [8.5, 9.], [12.5, 13.]])) # 1 lower value extrapolation & 1 Non-extrapolation point np.testing.assert_array_equal( r(np.array([-0.5, 1.5])), np.array([[-0.5, 1.5], [3.5, 5.5], [7.5, 9.5]])) # 2 lower value extrapolation np.testing.assert_array_equal( r(np.array([-1.5, -1])), np.array([[-1.5, -1.], [2.5, 3.], [6.5, 7.]])) # 2 lower value extrapolation, 2 Non-extrapolation point & 2 upper value extrapolation np.testing.assert_array_equal( r(np.array([-1.5, -1, 1.5, 2, 4.5, 5])), np.array([[-1.5, -1., 1.5, 2., 4.5, 5.], [2.5, 3., 5.5, 6., 8.5, 9.], [6.5, 7., 9.5, 10., 12.5, 13.]]))
def test_variable_gradient(self): a = np.array([[2, 4, 8], [0, 5, 11]]) r = Linear1dExtrapolator(interp1d(np.arange(2), a, axis=0)) np.testing.assert_array_equal(r(0), np.array([ 2., 4., 8.])) np.testing.assert_array_equal(r(-1), np.array([ 4., 3., 5.])) np.testing.assert_array_equal(r(3), np.array([ -4., 7., 17.])) np.testing.assert_array_equal(r(2.5), np.array([ -3. , 6.5, 15.5])) np.testing.assert_array_equal(r(np.array([1.5, 2])), np.array([[ -1. , 5.5, 12.5], [ -2. , 6. , 14. ]])) np.testing.assert_array_equal(r(np.array([-1.5, 3.5])), np.array([[ 5. , 2.5, 3.5], [ -5. , 7.5, 18.5]]))
def test_simple_axis0(self): a = np.arange(12.).reshape(3, 4) r = Linear1dExtrapolator(interp1d(np.arange(3), a, axis=0)) np.testing.assert_array_equal(r(0), np.array([0., 1., 2., 3.])) np.testing.assert_array_equal(r(-1), np.array([-4., -3., -2., -1.])) np.testing.assert_array_equal(r(3), np.array([12., 13., 14., 15.])) np.testing.assert_array_equal(r(2.5), np.array([10., 11., 12., 13.])) # 2 Non-extrapolation point np.testing.assert_array_equal( r(np.array([1.5, 2])), np.array([[6., 7., 8., 9.], [8., 9., 10., 11.]])) # 1 Non-extrapolation point & 1 upper value extrapolation np.testing.assert_array_equal( r(np.array([1.5, 3])), np.array([[6., 7., 8., 9.], [12., 13., 14., 15.]])) # 2 upper value extrapolation np.testing.assert_array_equal( r(np.array([2.5, 3])), np.array([[10., 11., 12., 13.], [12., 13., 14., 15.]])) # 1 lower value extrapolation & 1 Non-extrapolation point np.testing.assert_array_equal( r(np.array([-1, 1.5])), np.array([[-4., -3., -2., -1.], [6., 7., 8., 9.]])) # 2 lower value extrapolation np.testing.assert_array_equal( r(np.array([-1.5, -1])), np.array([[-6., -5., -4., -3.], [-4., -3., -2., -1.]])) # 2 lower value extrapolation, 2 Non-extrapolation point & 2 upper value extrapolation np.testing.assert_array_equal( r(np.array([-1.5, -1, 1, 1.5, 2.5, 3])), np.array([[-6., -5., -4., -3.], [-4., -3., -2., -1.], [4., 5., 6., 7.], [6., 7., 8., 9.], [10., 11., 12., 13.], [12., 13., 14., 15.]]))
def _regularise(grib_message): """ Transform a reduced grid to a regular grid using interpolation. Uses 1d linear interpolation at constant latitude to make the grid regular. If the longitude dimension is circular then this is taken into account by the interpolation. If the longitude dimension is not circular then extrapolation is allowed to make sure all end regular grid points get a value. In practice this extrapolation is likely to be minimal. """ # Make sure to read any missing values as NaN. gribapi.grib_set_double(grib_message, "missingValue", np.nan) # Get full longitude values, these describe the longitude value of # *every* point in the grid, they are not 1d monotonic coordinates. lons = gribapi.grib_get_double_array(grib_message, "longitudes") # Compute the new longitude coordinate for the regular grid. new_nx = max(gribapi.grib_get_long_array(grib_message, "pl")) new_x_step = (max(lons) - min(lons)) / (new_nx - 1) if gribapi.grib_get_long(grib_message, "iScansNegatively"): new_x_step *= -1 new_lons = np.arange(new_nx) * new_x_step + lons[0] # Get full latitude and data values, these describe the latitude and # data values of *every* point in the grid, they are not 1d monotonic # coordinates. lats = gribapi.grib_get_double_array(grib_message, "latitudes") values = gribapi.grib_get_double_array(grib_message, "values") # Retrieve the distinct latitudes from the GRIB message. GRIBAPI docs # don't specify if these points are guaranteed to be oriented correctly so # the safe option is to sort them into ascending (south-to-north) order # and then reverse the order if necessary. new_lats = gribapi.grib_get_double_array(grib_message, "distinctLatitudes") new_lats.sort() if not gribapi.grib_get_long(grib_message, "jScansPositively"): new_lats = new_lats[::-1] ny = new_lats.shape[0] # Use 1d linear interpolation along latitude circles to regularise the # reduced data. cyclic = _longitude_is_cyclic(new_lons) new_values = np.empty([ny, new_nx], dtype=values.dtype) for ilat, lat in enumerate(new_lats): idx = np.where(lats == lat) llons = lons[idx] vvalues = values[idx] if cyclic: # For cyclic data we insert dummy points at each end to ensure # we can interpolate to all output longitudes using pure # interpolation. cgap = (360 - llons[-1] - llons[0]) llons = np.concatenate( (llons[0:1] - cgap, llons, llons[-1:] + cgap)) vvalues = np.concatenate( (vvalues[-1:], vvalues, vvalues[0:1])) fixed_latitude_interpolator = scipy.interpolate.interp1d( llons, vvalues) else: # Allow extrapolation for non-cyclic data sets to ensure we can # interpolate to all output longitudes. fixed_latitude_interpolator = Linear1dExtrapolator( scipy.interpolate.interp1d(llons, vvalues)) new_values[ilat] = fixed_latitude_interpolator(new_lons) new_values = new_values.flatten() # Set flags for the regularised data. if np.isnan(new_values).any(): # Account for any missing data. gribapi.grib_set_double(grib_message, "missingValue", np.inf) gribapi.grib_set(grib_message, "bitmapPresent", 1) new_values = np.where(np.isnan(new_values), np.inf, new_values) gribapi.grib_set_long(grib_message, "Nx", int(new_nx)) gribapi.grib_set_double(grib_message, "iDirectionIncrementInDegrees", float(new_x_step)) gribapi.grib_set_double_array(grib_message, "values", new_values) gribapi.grib_set_long(grib_message, "jPointsAreConsecutive", 0) gribapi.grib_set_long(grib_message, "PLPresent", 0)
def test_simple_3d_axis1(self): a = np.arange(24.).reshape(3, 4, 2) r = Linear1dExtrapolator(interp1d(np.arange(4.), a, axis=1)) # a: # [[[ 0 1] # [ 2 3] # [ 4 5] # [ 6 7]] # # [[ 8 9] # [10 11] # [12 13] # [14 15]] # # [[16 17] # [18 19] # [20 21] # [22 23]] # ] np.testing.assert_array_equal( r(0), np.array([[0., 1.], [8., 9.], [16., 17.]])) np.testing.assert_array_equal( r(1), np.array([[2., 3.], [10., 11.], [18., 19.]])) np.testing.assert_array_equal( r(-1), np.array([[-2., -1.], [6., 7.], [14., 15.]])) np.testing.assert_array_equal( r(4), np.array([[8., 9.], [16., 17.], [24., 25.]])) np.testing.assert_array_equal( r(0.25), np.array([[0.5, 1.5], [8.5, 9.5], [16.5, 17.5]])) np.testing.assert_array_equal( r(-0.25), np.array([[-0.5, 0.5], [7.5, 8.5], [15.5, 16.5]])) np.testing.assert_array_equal( r(4.25), np.array([[8.5, 9.5], [16.5, 17.5], [24.5, 25.5]])) np.testing.assert_array_equal( r(np.array([0.5, 1])), np.array([[[1., 2.], [2., 3.]], [[9., 10.], [10., 11.]], [[17., 18.], [18., 19.]]])) np.testing.assert_array_equal( r(np.array([0.5, 4])), np.array([[[1., 2.], [8., 9.]], [[9., 10.], [16., 17.]], [[17., 18.], [24., 25.]]])) np.testing.assert_array_equal( r(np.array([-0.5, 0.5])), np.array([[[-1., 0.], [1., 2.]], [[7., 8.], [9., 10.]], [[15., 16.], [17., 18.]]])) np.testing.assert_array_equal( r(np.array([-1.5, -1, 0.5, 1, 4.5, 5])), np.array([[[-3., -2.], [-2., -1.], [1., 2.], [2., 3.], [9., 10.], [10., 11.]], [[5., 6.], [6., 7.], [9., 10.], [10., 11.], [17., 18.], [18., 19.]], [[13., 14.], [14., 15.], [17., 18.], [18., 19.], [25., 26.], [26., 27.]]]))