Coverage for pesummary/utils/interpolate.py: 61.1%

54 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2025-11-05 13:38 +0000

1# Licensed under an MIT style license -- see LICENSE.md 

2 

3from scipy.interpolate import interp1d, RectBivariateSpline as _RectBivariateSpline 

4import numpy as np 

5 

6__author__ = [ 

7 "Charlie Hoy <charlie.hoy@ligo.org>", 

8] 

9 

10 

11class BoundedInterp1d(object): 

12 """Return a bounded 1-D interpolant. Interpolating outside of the bounded 

13 domain simply returns 0. 

14 

15 Parameters 

16 ---------- 

17 x: np.array 

18 A 1-D array of real values. 

19 y: np.array 

20 A N-D array of real values. The length of y along the interpolation axis 

21 must be equal to the length of x. 

22 xlow: float, optional 

23 the lower bound of the bounded domain 

24 xhigh: float, optional 

25 the upper bound of the bounded domain 

26 **kwargs: dict, optional 

27 all kwargs passed to scipy.interpolate.interp1d 

28 """ 

29 def __init__(self, x, y, xlow=-np.inf, xhigh=np.inf, **kwargs): 

30 if xlow > np.min(x): 

31 self._xlow = xlow 

32 else: 

33 self._xlow = np.min(x) 

34 if xhigh < np.max(x): 

35 self._xhigh = xhigh 

36 else: 

37 self._xhigh = np.max(x) 

38 self._complex = np.iscomplexobj(y) 

39 self._interp_real = interp1d(x, np.real(y), **kwargs) 

40 if self._complex: 

41 self._interp_imaginary = interp1d(x, np.imag(y), **kwargs) 

42 

43 @property 

44 def xlow(self): 

45 return self._xlow 

46 

47 @property 

48 def xhigh(self): 

49 return self._xhigh 

50 

51 def __call__(self, pts): 

52 pts = np.atleast_1d(pts) 

53 result = np.zeros_like(pts) 

54 within_bounds = np.ones_like(pts, dtype='bool') 

55 within_bounds[(pts < self.xlow) | (pts > self.xhigh)] = False 

56 result[within_bounds] = self._interp_real(pts[within_bounds]) 

57 if self._complex: 

58 result[within_bounds] += 1j * self._interp_imaginary( 

59 pts[within_bounds] 

60 ) 

61 return result 

62 

63 

64class RectBivariateSpline(_RectBivariateSpline): 

65 """A modified version of scipy.interpolant.RectBivariateSpline to add 

66 kwargs that were previously available in the deprecated 

67 scipy.interpolant.interp2d. 

68 

69 Parameters 

70 ---------- 

71 x: np.ndarray 

72 data points in the x direction 

73 y: np.ndarray 

74 data points in the y direction 

75 z: np.ndarray 

76 2d array of data points with shape (x.size, y.size) 

77 bounds_error: bool, optional 

78 If True, a ValueError is raised when interpolated values outside of 

79 the range [min(x), max(x)] and [min(y), max(y)] are requested. If False, 

80 fill_value is used when fill_value is not None. Default False 

81 fill_value: float, optional 

82 the value to use when interpolated values outside of the range 

83 [min(x), max(x)] and [min(y), max(y)] are requested. Default None 

84 """ 

85 def __init__(self, x, y, z, bounds_error=False, fill_value=None, **kwargs): 

86 self.x_min = np.min(x) 

87 self.x_max = np.max(x) 

88 self.y_min = np.min(y) 

89 self.y_max = np.max(y) 

90 self.bounds_error = bounds_error 

91 self.fill_value = fill_value 

92 super(RectBivariateSpline, self).__init__(x=x, y=y, z=z, **kwargs) 

93 

94 def __call__(self, x, y, *args, **kwargs): 

95 result = super(RectBivariateSpline, self).__call__(x=x, y=y, *args, **kwargs) 

96 if self.bounds_error or self.fill_value is not None: 

97 out_of_bounds_x = (x < self.x_min) | (x > self.x_max) 

98 out_of_bounds_y = (y < self.y_min) | (y > self.y_max) 

99 any_out_of_bounds_x = np.any(out_of_bounds_x) 

100 any_out_of_bounds_y = np.any(out_of_bounds_y) 

101 if self.bounds_error and (any_out_of_bounds_x or any_out_of_bounds_y): 

102 raise ValueError( 

103 "x and y are out of range. Please ensure that x is in range " 

104 "[{}, {}] and y is in range [{}, {}]".format( 

105 self.x_min, self.x_max, self.y_min, self.y_max 

106 ) 

107 ) 

108 if self.fill_value is not None: 

109 if any_out_of_bounds_x: 

110 result[out_of_bounds_x, :] = self.fill_value 

111 if any_out_of_bounds_y: 

112 result[:, out_of_bounds_y] = self.fill_value 

113 return result