test_fitpack2.py 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474
  1. # Created by Pearu Peterson, June 2003
  2. import itertools
  3. import sys
  4. import warnings
  5. import numpy as np
  6. import pytest
  7. from pytest import raises as assert_raises
  8. from scipy._lib._array_api import (
  9. xp_assert_equal, xp_assert_close, assert_almost_equal, assert_array_almost_equal
  10. )
  11. from numpy import array, diff, linspace, meshgrid, ones, pi, shape
  12. from scipy.interpolate._fitpack_py import bisplrep, bisplev, splrep, spalde
  13. from scipy.interpolate._fitpack2 import (UnivariateSpline,
  14. LSQUnivariateSpline, InterpolatedUnivariateSpline,
  15. LSQBivariateSpline, SmoothBivariateSpline, RectBivariateSpline,
  16. LSQSphereBivariateSpline, SmoothSphereBivariateSpline,
  17. RectSphereBivariateSpline)
  18. from scipy._lib._testutils import _run_concurrent_barrier
  19. from scipy.interpolate import make_splrep, NdBSpline
  20. def convert_to_ndbspline(lut):
  21. tx, ty = lut.get_knots()
  22. kx, ky = lut.degrees
  23. nx, ny = len(tx), len(ty)
  24. c = lut.get_coeffs().reshape((nx - kx - 1, ny - ky - 1))
  25. return NdBSpline((tx, ty), c, (kx, ky))
  26. class TestUnivariateSpline:
  27. def test_linear_constant(self):
  28. x = [1,2,3]
  29. y = [3,3,3]
  30. lut = UnivariateSpline(x,y,k=1)
  31. assert_array_almost_equal(lut.get_knots(), [1, 3])
  32. assert_array_almost_equal(lut.get_coeffs(), [3, 3])
  33. assert abs(lut.get_residual()) < 1e-10
  34. assert_array_almost_equal(lut([1, 1.5, 2]), [3, 3, 3])
  35. @pytest.mark.parametrize("bc_type", [None, 'periodic'])
  36. def test_linear_constant_periodic(self, bc_type):
  37. x = [1,2,3]
  38. y = [3,3,3]
  39. lut = UnivariateSpline(x,y,k=1)
  40. spl = make_splrep(x, y, k=1, s=len(x), bc_type=bc_type)
  41. xp_assert_close(spl.t[1:-1], lut.get_knots(), atol=1e-15)
  42. xp_assert_close(spl.c, lut.get_coeffs(), atol=1e-15)
  43. def test_preserve_shape(self):
  44. x = [1, 2, 3]
  45. y = [0, 2, 4]
  46. lut = UnivariateSpline(x, y, k=1)
  47. arg = 2
  48. assert shape(arg) == shape(lut(arg))
  49. assert shape(arg) == shape(lut(arg, nu=1))
  50. arg = [1.5, 2, 2.5]
  51. assert shape(arg) == shape(lut(arg))
  52. assert shape(arg) == shape(lut(arg, nu=1))
  53. def test_linear_1d(self):
  54. x = [1,2,3]
  55. y = [0,2,4]
  56. lut = UnivariateSpline(x,y,k=1)
  57. assert_array_almost_equal(lut.get_knots(),[1,3])
  58. assert_array_almost_equal(lut.get_coeffs(),[0,4])
  59. assert abs(lut.get_residual()) < 1e-15
  60. assert_array_almost_equal(lut([1,1.5,2]),[0,1,2])
  61. def test_subclassing(self):
  62. # See #731
  63. class ZeroSpline(UnivariateSpline):
  64. def __call__(self, x):
  65. return 0*array(x)
  66. sp = ZeroSpline([1,2,3,4,5], [3,2,3,2,3], k=2)
  67. xp_assert_equal(sp([1.5, 2.5]), [0., 0.])
  68. def test_empty_input(self):
  69. # Test whether empty input returns an empty output. Ticket 1014
  70. x = [1,3,5,7,9]
  71. y = [0,4,9,12,21]
  72. spl = UnivariateSpline(x, y, k=3)
  73. xp_assert_equal(spl([]), array([]))
  74. def test_roots(self):
  75. x = [1, 3, 5, 7, 9]
  76. y = [0, 4, 9, 12, 21]
  77. spl = UnivariateSpline(x, y, k=3)
  78. assert_almost_equal(spl.roots()[0], 1.050290639101332)
  79. def test_roots_length(self): # for gh18335
  80. x = np.linspace(0, 50 * np.pi, 1000)
  81. y = np.cos(x)
  82. spl = UnivariateSpline(x, y, s=0)
  83. assert len(spl.roots()) == 50
  84. def test_derivatives(self):
  85. x = [1, 3, 5, 7, 9]
  86. y = [0, 4, 9, 12, 21]
  87. spl = UnivariateSpline(x, y, k=3)
  88. assert_almost_equal(spl.derivatives(3.5),
  89. [5.5152902, 1.7146577, -0.1830357, 0.3125])
  90. def test_derivatives_2(self):
  91. x = np.arange(8)
  92. y = x**3 + 2.*x**2
  93. tck = splrep(x, y, s=0)
  94. ders = spalde(3, tck)
  95. xp_assert_close(ders, [45., # 3**3 + 2*(3)**2
  96. 39., # 3*(3)**2 + 4*(3)
  97. 22., # 6*(3) + 4
  98. 6.], # 6*3**0
  99. atol=1e-15)
  100. spl = UnivariateSpline(x, y, s=0, k=3)
  101. xp_assert_close(spl.derivatives(3),
  102. ders,
  103. atol=1e-15)
  104. def test_resize_regression(self):
  105. """Regression test for #1375."""
  106. x = [-1., -0.65016502, -0.58856235, -0.26903553, -0.17370892,
  107. -0.10011001, 0., 0.10011001, 0.17370892, 0.26903553, 0.58856235,
  108. 0.65016502, 1.]
  109. y = [1.,0.62928599, 0.5797223, 0.39965815, 0.36322694, 0.3508061,
  110. 0.35214793, 0.3508061, 0.36322694, 0.39965815, 0.5797223,
  111. 0.62928599, 1.]
  112. w = [1.00000000e+12, 6.88875973e+02, 4.89314737e+02, 4.26864807e+02,
  113. 6.07746770e+02, 4.51341444e+02, 3.17480210e+02, 4.51341444e+02,
  114. 6.07746770e+02, 4.26864807e+02, 4.89314737e+02, 6.88875973e+02,
  115. 1.00000000e+12]
  116. spl = UnivariateSpline(x=x, y=y, w=w, s=None)
  117. desired = array([0.35100374, 0.51715855, 0.87789547, 0.98719344])
  118. xp_assert_close(spl([0.1, 0.5, 0.9, 0.99]), desired, atol=5e-4)
  119. def test_out_of_range_regression(self):
  120. # Test different extrapolation modes. See ticket 3557
  121. x = np.arange(5, dtype=float)
  122. y = x**3
  123. xp = linspace(-8, 13, 100)
  124. xp_zeros = xp.copy()
  125. xp_zeros[np.logical_or(xp_zeros < 0., xp_zeros > 4.)] = 0
  126. xp_clip = xp.copy()
  127. xp_clip[xp_clip < x[0]] = x[0]
  128. xp_clip[xp_clip > x[-1]] = x[-1]
  129. for cls in [UnivariateSpline, InterpolatedUnivariateSpline]:
  130. spl = cls(x=x, y=y)
  131. for ext in [0, 'extrapolate']:
  132. xp_assert_close(spl(xp, ext=ext), xp**3, atol=1e-16)
  133. xp_assert_close(cls(x, y, ext=ext)(xp), xp**3, atol=1e-16)
  134. for ext in [1, 'zeros']:
  135. xp_assert_close(spl(xp, ext=ext), xp_zeros**3, atol=1e-16)
  136. xp_assert_close(cls(x, y, ext=ext)(xp), xp_zeros**3, atol=1e-16)
  137. for ext in [2, 'raise']:
  138. assert_raises(ValueError, spl, xp, **dict(ext=ext))
  139. for ext in [3, 'const']:
  140. xp_assert_close(spl(xp, ext=ext), xp_clip**3, atol=2e-16)
  141. xp_assert_close(cls(x, y, ext=ext)(xp), xp_clip**3, atol=2e-16)
  142. # also test LSQUnivariateSpline [which needs explicit knots]
  143. t = spl.get_knots()[3:4] # interior knots w/ default k=3
  144. spl = LSQUnivariateSpline(x, y, t)
  145. xp_assert_close(spl(xp, ext=0), xp**3, atol=1e-16)
  146. xp_assert_close(spl(xp, ext=1), xp_zeros**3, atol=1e-16)
  147. assert_raises(ValueError, spl, xp, **dict(ext=2))
  148. xp_assert_close(spl(xp, ext=3), xp_clip**3, atol=1e-16)
  149. # also make sure that unknown values for `ext` are caught early
  150. for ext in [-1, 'unknown']:
  151. spl = UnivariateSpline(x, y)
  152. assert_raises(ValueError, spl, xp, **dict(ext=ext))
  153. assert_raises(ValueError, UnivariateSpline,
  154. **dict(x=x, y=y, ext=ext))
  155. def test_lsq_fpchec(self):
  156. xs = np.arange(100) * 1.
  157. ys = np.arange(100) * 1.
  158. knots = np.linspace(0, 99, 10)
  159. bbox = (-1, 101)
  160. assert_raises(ValueError, LSQUnivariateSpline, xs, ys, knots,
  161. bbox=bbox)
  162. def test_derivative_and_antiderivative(self):
  163. # Thin wrappers to splder/splantider, so light smoke test only.
  164. x = np.linspace(0, 1, 70)**3
  165. y = np.cos(x)
  166. spl = UnivariateSpline(x, y, s=0)
  167. spl2 = spl.antiderivative(2).derivative(2)
  168. xp_assert_close(spl(0.3), spl2(0.3))
  169. spl2 = spl.antiderivative(1)
  170. xp_assert_close(spl2(0.6) - spl2(0.2),
  171. spl.integral(0.2, 0.6))
  172. def test_derivative_extrapolation(self):
  173. # Regression test for gh-10195: for a const-extrapolation spline
  174. # its derivative evaluates to zero for extrapolation
  175. x_values = [1, 2, 4, 6, 8.5]
  176. y_values = [0.5, 0.8, 1.3, 2.5, 5]
  177. f = UnivariateSpline(x_values, y_values, ext='const', k=3)
  178. x = [-1, 0, -0.5, 9, 9.5, 10]
  179. xp_assert_close(f.derivative()(x), np.zeros_like(x), atol=1e-15)
  180. def test_integral_out_of_bounds(self):
  181. # Regression test for gh-7906: .integral(a, b) is wrong if both
  182. # a and b are out-of-bounds
  183. x = np.linspace(0., 1., 7)
  184. for ext in range(4):
  185. f = UnivariateSpline(x, x, s=0, ext=ext)
  186. for (a, b) in [(1, 1), (1, 5), (2, 5),
  187. (0, 0), (-2, 0), (-2, -1)]:
  188. assert abs(f.integral(a, b)) < 1e-15
  189. def test_nan(self):
  190. # bail out early if the input data contains nans
  191. x = np.arange(10, dtype=float)
  192. y = x**3
  193. w = np.ones_like(x)
  194. # also test LSQUnivariateSpline [which needs explicit knots]
  195. spl = UnivariateSpline(x, y, check_finite=True)
  196. t = spl.get_knots()[3:4] # interior knots w/ default k=3
  197. y_end = y[-1]
  198. for z in [np.nan, np.inf, -np.inf]:
  199. y[-1] = z
  200. assert_raises(ValueError, UnivariateSpline,
  201. **dict(x=x, y=y, check_finite=True))
  202. assert_raises(ValueError, InterpolatedUnivariateSpline,
  203. **dict(x=x, y=y, check_finite=True))
  204. assert_raises(ValueError, LSQUnivariateSpline,
  205. **dict(x=x, y=y, t=t, check_finite=True))
  206. y[-1] = y_end # check valid y but invalid w
  207. w[-1] = z
  208. assert_raises(ValueError, UnivariateSpline,
  209. **dict(x=x, y=y, w=w, check_finite=True))
  210. assert_raises(ValueError, InterpolatedUnivariateSpline,
  211. **dict(x=x, y=y, w=w, check_finite=True))
  212. assert_raises(ValueError, LSQUnivariateSpline,
  213. **dict(x=x, y=y, t=t, w=w, check_finite=True))
  214. def test_strictly_increasing_x(self):
  215. # Test the x is required to be strictly increasing for
  216. # UnivariateSpline if s=0 and for InterpolatedUnivariateSpline,
  217. # but merely increasing for UnivariateSpline if s>0
  218. # and for LSQUnivariateSpline; see gh-8535
  219. xx = np.arange(10, dtype=float)
  220. yy = xx**3
  221. x = np.arange(10, dtype=float)
  222. x[1] = x[0]
  223. y = x**3
  224. w = np.ones_like(x)
  225. # also test LSQUnivariateSpline [which needs explicit knots]
  226. spl = UnivariateSpline(xx, yy, check_finite=True)
  227. t = spl.get_knots()[3:4] # interior knots w/ default k=3
  228. UnivariateSpline(x=x, y=y, w=w, s=1, check_finite=True)
  229. LSQUnivariateSpline(x=x, y=y, t=t, w=w, check_finite=True)
  230. assert_raises(ValueError, UnivariateSpline,
  231. **dict(x=x, y=y, s=0, check_finite=True))
  232. assert_raises(ValueError, InterpolatedUnivariateSpline,
  233. **dict(x=x, y=y, check_finite=True))
  234. def test_increasing_x(self):
  235. # Test that x is required to be increasing, see gh-8535
  236. xx = np.arange(10, dtype=float)
  237. yy = xx**3
  238. x = np.arange(10, dtype=float)
  239. x[1] = x[0] - 1.0
  240. y = x**3
  241. w = np.ones_like(x)
  242. # also test LSQUnivariateSpline [which needs explicit knots]
  243. spl = UnivariateSpline(xx, yy, check_finite=True)
  244. t = spl.get_knots()[3:4] # interior knots w/ default k=3
  245. assert_raises(ValueError, UnivariateSpline,
  246. **dict(x=x, y=y, check_finite=True))
  247. assert_raises(ValueError, InterpolatedUnivariateSpline,
  248. **dict(x=x, y=y, check_finite=True))
  249. assert_raises(ValueError, LSQUnivariateSpline,
  250. **dict(x=x, y=y, t=t, w=w, check_finite=True))
  251. def test_invalid_input_for_univariate_spline(self):
  252. with assert_raises(ValueError) as info:
  253. x_values = [1, 2, 4, 6, 8.5]
  254. y_values = [0.5, 0.8, 1.3, 2.5]
  255. UnivariateSpline(x_values, y_values)
  256. assert "x and y should have a same length" in str(info.value)
  257. with assert_raises(ValueError) as info:
  258. x_values = [1, 2, 4, 6, 8.5]
  259. y_values = [0.5, 0.8, 1.3, 2.5, 2.8]
  260. w_values = [-1.0, 1.0, 1.0, 1.0]
  261. UnivariateSpline(x_values, y_values, w=w_values)
  262. assert "x, y, and w should have a same length" in str(info.value)
  263. with assert_raises(ValueError) as info:
  264. bbox = (-1)
  265. UnivariateSpline(x_values, y_values, bbox=bbox)
  266. assert "bbox shape should be (2,)" in str(info.value)
  267. with assert_raises(ValueError) as info:
  268. UnivariateSpline(x_values, y_values, k=6)
  269. assert "k should be 1 <= k <= 5" in str(info.value)
  270. with assert_raises(ValueError) as info:
  271. UnivariateSpline(x_values, y_values, s=-1.0)
  272. assert "s should be s >= 0.0" in str(info.value)
  273. def test_invalid_input_for_interpolated_univariate_spline(self):
  274. with assert_raises(ValueError) as info:
  275. x_values = [1, 2, 4, 6, 8.5]
  276. y_values = [0.5, 0.8, 1.3, 2.5]
  277. InterpolatedUnivariateSpline(x_values, y_values)
  278. assert "x and y should have a same length" in str(info.value)
  279. with assert_raises(ValueError) as info:
  280. x_values = [1, 2, 4, 6, 8.5]
  281. y_values = [0.5, 0.8, 1.3, 2.5, 2.8]
  282. w_values = [-1.0, 1.0, 1.0, 1.0]
  283. InterpolatedUnivariateSpline(x_values, y_values, w=w_values)
  284. assert "x, y, and w should have a same length" in str(info.value)
  285. with assert_raises(ValueError) as info:
  286. bbox = (-1)
  287. InterpolatedUnivariateSpline(x_values, y_values, bbox=bbox)
  288. assert "bbox shape should be (2,)" in str(info.value)
  289. with assert_raises(ValueError) as info:
  290. InterpolatedUnivariateSpline(x_values, y_values, k=6)
  291. assert "k should be 1 <= k <= 5" in str(info.value)
  292. def test_invalid_input_for_lsq_univariate_spline(self):
  293. x_values = [1, 2, 4, 6, 8.5]
  294. y_values = [0.5, 0.8, 1.3, 2.5, 2.8]
  295. spl = UnivariateSpline(x_values, y_values, check_finite=True)
  296. t_values = spl.get_knots()[3:4] # interior knots w/ default k=3
  297. with assert_raises(ValueError) as info:
  298. x_values = [1, 2, 4, 6, 8.5]
  299. y_values = [0.5, 0.8, 1.3, 2.5]
  300. LSQUnivariateSpline(x_values, y_values, t_values)
  301. assert "x and y should have a same length" in str(info.value)
  302. with assert_raises(ValueError) as info:
  303. x_values = [1, 2, 4, 6, 8.5]
  304. y_values = [0.5, 0.8, 1.3, 2.5, 2.8]
  305. w_values = [1.0, 1.0, 1.0, 1.0]
  306. LSQUnivariateSpline(x_values, y_values, t_values, w=w_values)
  307. assert "x, y, and w should have a same length" in str(info.value)
  308. message = "Interior knots t must satisfy Schoenberg-Whitney conditions"
  309. with assert_raises(ValueError, match=message) as info:
  310. bbox = (100, -100)
  311. LSQUnivariateSpline(x_values, y_values, t_values, bbox=bbox)
  312. with assert_raises(ValueError) as info:
  313. bbox = (-1)
  314. LSQUnivariateSpline(x_values, y_values, t_values, bbox=bbox)
  315. assert "bbox shape should be (2,)" in str(info.value)
  316. with assert_raises(ValueError) as info:
  317. LSQUnivariateSpline(x_values, y_values, t_values, k=6)
  318. assert "k should be 1 <= k <= 5" in str(info.value)
  319. def test_array_like_input(self):
  320. x_values = np.array([1, 2, 4, 6, 8.5])
  321. y_values = np.array([0.5, 0.8, 1.3, 2.5, 2.8])
  322. w_values = np.array([1.0, 1.0, 1.0, 1.0, 1.0])
  323. bbox = np.array([-100, 100])
  324. # np.array input
  325. spl1 = UnivariateSpline(x=x_values, y=y_values, w=w_values,
  326. bbox=bbox)
  327. # list input
  328. spl2 = UnivariateSpline(x=x_values.tolist(), y=y_values.tolist(),
  329. w=w_values.tolist(), bbox=bbox.tolist())
  330. xp_assert_close(spl1([0.1, 0.5, 0.9, 0.99]),
  331. spl2([0.1, 0.5, 0.9, 0.99]))
  332. def test_fpknot_oob_crash(self):
  333. # https://github.com/scipy/scipy/issues/3691
  334. x = range(109)
  335. y = [0., 0., 0., 0., 0., 10.9, 0., 11., 0.,
  336. 0., 0., 10.9, 0., 0., 0., 0., 0., 0.,
  337. 10.9, 0., 0., 0., 11., 0., 0., 0., 10.9,
  338. 0., 0., 0., 10.5, 0., 0., 0., 10.7, 0.,
  339. 0., 0., 11., 0., 0., 0., 0., 0., 0.,
  340. 10.9, 0., 0., 10.7, 0., 0., 0., 10.6, 0.,
  341. 0., 0., 10.5, 0., 0., 10.7, 0., 0., 10.5,
  342. 0., 0., 11.5, 0., 0., 0., 10.7, 0., 0.,
  343. 10.7, 0., 0., 10.9, 0., 0., 10.8, 0., 0.,
  344. 0., 10.7, 0., 0., 10.6, 0., 0., 0., 10.4,
  345. 0., 0., 10.6, 0., 0., 10.5, 0., 0., 0.,
  346. 10.7, 0., 0., 0., 10.4, 0., 0., 0., 10.8, 0.]
  347. msg = r"does not satisfy the condition abs\(fp-s\)/s < tol"
  348. with pytest.warns(UserWarning, match=msg):
  349. UnivariateSpline(x, y, k=1)
  350. def test_concurrency(self):
  351. # Check that no segfaults appear with concurrent access to
  352. # UnivariateSpline
  353. xx = np.arange(100, dtype=float)
  354. yy = xx**3
  355. x = np.arange(100, dtype=float)
  356. x[1] = x[0]
  357. spl = UnivariateSpline(xx, yy, check_finite=True)
  358. def worker_fn(_, interp, x):
  359. interp(x)
  360. _run_concurrent_barrier(10, worker_fn, spl, x)
  361. class TestLSQBivariateSpline:
  362. # NOTE: The systems in this test class are rank-deficient
  363. def test_linear_constant(self):
  364. x = [1,1,1,2,2,2,3,3,3]
  365. y = [1,2,3,1,2,3,1,2,3]
  366. z = [3,3,3,3,3,3,3,3,3]
  367. s = 0.1
  368. tx = [1+s,3-s]
  369. ty = [1+s,3-s]
  370. with pytest.warns(UserWarning, match="\nThe coefficients of the spline") as r:
  371. lut = LSQBivariateSpline(x,y,z,tx,ty,kx=1,ky=1)
  372. assert len(r) == 1
  373. assert_almost_equal(lut(2, 2), np.asarray(3.))
  374. def test_bilinearity(self):
  375. x = [1,1,1,2,2,2,3,3,3]
  376. y = [1,2,3,1,2,3,1,2,3]
  377. z = [0,7,8,3,4,7,1,3,4]
  378. s = 0.1
  379. tx = [1+s,3-s]
  380. ty = [1+s,3-s]
  381. with pytest.warns(UserWarning, match="\nThe coefficients of the spline"):
  382. # This seems to fail (ier=1, see ticket 1642).
  383. lut = LSQBivariateSpline(x,y,z,tx,ty,kx=1,ky=1)
  384. tx, ty = lut.get_knots()
  385. for xa, xb in zip(tx[:-1], tx[1:]):
  386. for ya, yb in zip(ty[:-1], ty[1:]):
  387. for t in [0.1, 0.5, 0.9]:
  388. for s in [0.3, 0.4, 0.7]:
  389. xp = xa*(1-t) + xb*t
  390. yp = ya*(1-s) + yb*s
  391. zp = (+ lut(xa, ya)*(1-t)*(1-s)
  392. + lut(xb, ya)*t*(1-s)
  393. + lut(xa, yb)*(1-t)*s
  394. + lut(xb, yb)*t*s)
  395. assert_almost_equal(lut(xp,yp), zp)
  396. def test_integral(self):
  397. x = [1,1,1,2,2,2,8,8,8]
  398. y = [1,2,3,1,2,3,1,2,3]
  399. z = array([0,7,8,3,4,7,1,3,4])
  400. s = 0.1
  401. tx = [1+s,3-s]
  402. ty = [1+s,3-s]
  403. with pytest.warns(UserWarning, match="\nThe coefficients of the spline") as r:
  404. lut = LSQBivariateSpline(x, y, z, tx, ty, kx=1, ky=1)
  405. assert len(r) == 1
  406. tx, ty = lut.get_knots()
  407. tz = lut(tx, ty)
  408. trpz = .25*(diff(tx)[:,None]*diff(ty)[None,:]
  409. * (tz[:-1,:-1]+tz[1:,:-1]+tz[:-1,1:]+tz[1:,1:])).sum()
  410. assert_almost_equal(np.asarray(lut.integral(tx[0], tx[-1], ty[0], ty[-1])),
  411. np.asarray(trpz))
  412. def test_empty_input(self):
  413. # Test whether empty inputs returns an empty output. Ticket 1014
  414. x = [1,1,1,2,2,2,3,3,3]
  415. y = [1,2,3,1,2,3,1,2,3]
  416. z = [3,3,3,3,3,3,3,3,3]
  417. s = 0.1
  418. tx = [1+s,3-s]
  419. ty = [1+s,3-s]
  420. with pytest.warns(UserWarning, match="\nThe coefficients of the spline") as r:
  421. lut = LSQBivariateSpline(x, y, z, tx, ty, kx=1, ky=1)
  422. assert len(r) == 1
  423. xp_assert_equal(lut([], []), np.zeros((0,0)))
  424. xp_assert_equal(lut([], [], grid=False), np.zeros((0,)))
  425. def test_invalid_input(self):
  426. s = 0.1
  427. tx = [1 + s, 3 - s]
  428. ty = [1 + s, 3 - s]
  429. with assert_raises(ValueError) as info:
  430. x = np.linspace(1.0, 10.0)
  431. y = np.linspace(1.0, 10.0)
  432. z = np.linspace(1.0, 10.0, num=10)
  433. LSQBivariateSpline(x, y, z, tx, ty)
  434. assert "x, y, and z should have a same length" in str(info.value)
  435. with assert_raises(ValueError) as info:
  436. x = np.linspace(1.0, 10.0)
  437. y = np.linspace(1.0, 10.0)
  438. z = np.linspace(1.0, 10.0)
  439. w = np.linspace(1.0, 10.0, num=20)
  440. LSQBivariateSpline(x, y, z, tx, ty, w=w)
  441. assert "x, y, z, and w should have a same length" in str(info.value)
  442. with assert_raises(ValueError) as info:
  443. w = np.linspace(-1.0, 10.0)
  444. LSQBivariateSpline(x, y, z, tx, ty, w=w)
  445. assert "w should be positive" in str(info.value)
  446. with assert_raises(ValueError) as info:
  447. bbox = (-100, 100, -100)
  448. LSQBivariateSpline(x, y, z, tx, ty, bbox=bbox)
  449. assert "bbox shape should be (4,)" in str(info.value)
  450. with assert_raises(ValueError) as info:
  451. LSQBivariateSpline(x, y, z, tx, ty, kx=10, ky=10)
  452. assert "The length of x, y and z should be at least (kx+1) * (ky+1)" in \
  453. str(info.value)
  454. with assert_raises(ValueError) as exc_info:
  455. LSQBivariateSpline(x, y, z, tx, ty, eps=0.0)
  456. assert "eps should be between (0, 1)" in str(exc_info.value)
  457. with assert_raises(ValueError) as exc_info:
  458. LSQBivariateSpline(x, y, z, tx, ty, eps=1.0)
  459. assert "eps should be between (0, 1)" in str(exc_info.value)
  460. def test_array_like_input(self):
  461. s = 0.1
  462. tx = np.array([1 + s, 3 - s])
  463. ty = np.array([1 + s, 3 - s])
  464. x = np.linspace(1.0, 10.0)
  465. y = np.linspace(1.0, 10.0)
  466. z = np.linspace(1.0, 10.0)
  467. w = np.linspace(1.0, 10.0)
  468. bbox = np.array([1.0, 10.0, 1.0, 10.0])
  469. with pytest.warns(UserWarning, match="\nThe coefficients of the spline") as r:
  470. # np.array input
  471. spl1 = LSQBivariateSpline(x, y, z, tx, ty, w=w, bbox=bbox)
  472. # list input
  473. spl2 = LSQBivariateSpline(x.tolist(), y.tolist(), z.tolist(),
  474. tx.tolist(), ty.tolist(), w=w.tolist(),
  475. bbox=bbox)
  476. xp_assert_close(spl1(2.0, 2.0), spl2(2.0, 2.0))
  477. assert len(r) == 2
  478. def test_unequal_length_of_knots(self):
  479. """Test for the case when the input knot-location arrays in x and y are
  480. of different lengths.
  481. """
  482. x, y = np.mgrid[0:100, 0:100]
  483. x = x.ravel()
  484. y = y.ravel()
  485. z = 3.0 * np.ones_like(x)
  486. tx = np.linspace(0.1, 98.0, 29)
  487. ty = np.linspace(0.1, 98.0, 33)
  488. with pytest.warns(UserWarning, match="\nThe coefficients of the spline") as r:
  489. lut = LSQBivariateSpline(x,y,z,tx,ty)
  490. assert len(r) == 1
  491. assert_almost_equal(lut(x, y, grid=False), z)
  492. class TestSmoothBivariateSpline:
  493. def test_linear_constant(self):
  494. x = [1,1,1,2,2,2,3,3,3]
  495. y = [1,2,3,1,2,3,1,2,3]
  496. z = [3,3,3,3,3,3,3,3,3]
  497. lut = SmoothBivariateSpline(x,y,z,kx=1,ky=1)
  498. for t in lut.get_knots():
  499. assert_array_almost_equal(t, [1, 1, 3, 3])
  500. assert_array_almost_equal(lut.get_coeffs(), [3, 3, 3, 3])
  501. assert abs(lut.get_residual()) < 1e-15
  502. assert_array_almost_equal(lut([1, 1.5, 2], [1, 1.5]), [[3, 3], [3, 3], [3, 3]])
  503. def test_linear_1d(self):
  504. x = [1,1,1,2,2,2,3,3,3]
  505. y = [1,2,3,1,2,3,1,2,3]
  506. z = [0,0,0,2,2,2,4,4,4]
  507. lut = SmoothBivariateSpline(x,y,z,kx=1,ky=1)
  508. for t in lut.get_knots():
  509. xp_assert_close(t, np.asarray([1.0, 1, 3, 3]))
  510. assert_array_almost_equal(lut.get_coeffs(), [0, 0, 4, 4])
  511. assert abs(lut.get_residual()) < 1e-15
  512. assert_array_almost_equal(lut([1,1.5,2],[1,1.5]),[[0,0],[1,1],[2,2]])
  513. def test_integral(self):
  514. x = [1,1,1,2,2,2,4,4,4]
  515. y = [1,2,3,1,2,3,1,2,3]
  516. z = array([0,7,8,3,4,7,1,3,4])
  517. with warnings.catch_warnings():
  518. # This seems to fail (ier=1, see ticket 1642).
  519. warnings.filterwarnings(
  520. "ignore", "\nThe required storage space", UserWarning)
  521. lut = SmoothBivariateSpline(x, y, z, kx=1, ky=1, s=0)
  522. tx = [1,2,4]
  523. ty = [1,2,3]
  524. tz = lut(tx, ty)
  525. trpz = .25*(diff(tx)[:,None]*diff(ty)[None,:]
  526. * (tz[:-1,:-1]+tz[1:,:-1]+tz[:-1,1:]+tz[1:,1:])).sum()
  527. assert_almost_equal(np.asarray(lut.integral(tx[0], tx[-1], ty[0], ty[-1])),
  528. np.asarray(trpz))
  529. lut2 = SmoothBivariateSpline(x, y, z, kx=2, ky=2, s=0)
  530. assert_almost_equal(np.asarray(lut2.integral(tx[0], tx[-1], ty[0], ty[-1])),
  531. np.asarray(trpz),
  532. decimal=0) # the quadratures give 23.75 and 23.85
  533. tz = lut(tx[:-1], ty[:-1])
  534. trpz = .25*(diff(tx[:-1])[:,None]*diff(ty[:-1])[None,:]
  535. * (tz[:-1,:-1]+tz[1:,:-1]+tz[:-1,1:]+tz[1:,1:])).sum()
  536. assert_almost_equal(np.asarray(lut.integral(tx[0], tx[-2], ty[0], ty[-2])),
  537. np.asarray(trpz))
  538. def test_rerun_lwrk2_too_small(self):
  539. # in this setting, lwrk2 is too small in the default run. Here we
  540. # check for equality with the bisplrep/bisplev output because there,
  541. # an automatic re-run of the spline representation is done if ier>10.
  542. x = np.linspace(-2, 2, 80)
  543. y = np.linspace(-2, 2, 80)
  544. z = x + y
  545. xi = np.linspace(-1, 1, 100)
  546. yi = np.linspace(-2, 2, 100)
  547. tck = bisplrep(x, y, z)
  548. res1 = bisplev(xi, yi, tck)
  549. interp_ = SmoothBivariateSpline(x, y, z)
  550. res2 = interp_(xi, yi)
  551. assert_almost_equal(res1, res2)
  552. def test_invalid_input(self):
  553. with assert_raises(ValueError) as info:
  554. x = np.linspace(1.0, 10.0)
  555. y = np.linspace(1.0, 10.0)
  556. z = np.linspace(1.0, 10.0, num=10)
  557. SmoothBivariateSpline(x, y, z)
  558. assert "x, y, and z should have a same length" in str(info.value)
  559. with assert_raises(ValueError) as info:
  560. x = np.linspace(1.0, 10.0)
  561. y = np.linspace(1.0, 10.0)
  562. z = np.linspace(1.0, 10.0)
  563. w = np.linspace(1.0, 10.0, num=20)
  564. SmoothBivariateSpline(x, y, z, w=w)
  565. assert "x, y, z, and w should have a same length" in str(info.value)
  566. with assert_raises(ValueError) as info:
  567. w = np.linspace(-1.0, 10.0)
  568. SmoothBivariateSpline(x, y, z, w=w)
  569. assert "w should be positive" in str(info.value)
  570. with assert_raises(ValueError) as info:
  571. bbox = (-100, 100, -100)
  572. SmoothBivariateSpline(x, y, z, bbox=bbox)
  573. assert "bbox shape should be (4,)" in str(info.value)
  574. with assert_raises(ValueError) as info:
  575. SmoothBivariateSpline(x, y, z, kx=10, ky=10)
  576. assert "The length of x, y and z should be at least (kx+1) * (ky+1)" in\
  577. str(info.value)
  578. with assert_raises(ValueError) as info:
  579. SmoothBivariateSpline(x, y, z, s=-1.0)
  580. assert "s should be s >= 0.0" in str(info.value)
  581. with assert_raises(ValueError) as exc_info:
  582. SmoothBivariateSpline(x, y, z, eps=0.0)
  583. assert "eps should be between (0, 1)" in str(exc_info.value)
  584. with assert_raises(ValueError) as exc_info:
  585. SmoothBivariateSpline(x, y, z, eps=1.0)
  586. assert "eps should be between (0, 1)" in str(exc_info.value)
  587. def test_array_like_input(self):
  588. x = np.array([1, 1, 1, 2, 2, 2, 3, 3, 3])
  589. y = np.array([1, 2, 3, 1, 2, 3, 1, 2, 3])
  590. z = np.array([3, 3, 3, 3, 3, 3, 3, 3, 3])
  591. w = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1])
  592. bbox = np.array([1.0, 3.0, 1.0, 3.0])
  593. # np.array input
  594. spl1 = SmoothBivariateSpline(x, y, z, w=w, bbox=bbox, kx=1, ky=1)
  595. # list input
  596. spl2 = SmoothBivariateSpline(x.tolist(), y.tolist(), z.tolist(),
  597. bbox=bbox.tolist(), w=w.tolist(),
  598. kx=1, ky=1)
  599. xp_assert_close(spl1(0.1, 0.5), spl2(0.1, 0.5))
  600. class TestLSQSphereBivariateSpline:
  601. def setup_method(self):
  602. # define the input data and coordinates
  603. ntheta, nphi = 70, 90
  604. theta = linspace(0.5/(ntheta - 1), 1 - 0.5/(ntheta - 1), ntheta) * pi
  605. phi = linspace(0.5/(nphi - 1), 1 - 0.5/(nphi - 1), nphi) * 2. * pi
  606. data = ones((theta.shape[0], phi.shape[0]))
  607. # define knots and extract data values at the knots
  608. knotst = theta[::5]
  609. knotsp = phi[::5]
  610. knotdata = data[::5, ::5]
  611. # calculate spline coefficients
  612. lats, lons = meshgrid(theta, phi)
  613. lut_lsq = LSQSphereBivariateSpline(lats.ravel(), lons.ravel(),
  614. data.T.ravel(), knotst, knotsp)
  615. self.lut_lsq = lut_lsq
  616. self.data = knotdata
  617. self.new_lons, self.new_lats = knotsp, knotst
  618. def test_linear_constant(self):
  619. assert abs(self.lut_lsq.get_residual()) < 1e-15
  620. assert_array_almost_equal(self.lut_lsq(self.new_lats, self.new_lons),
  621. self.data)
  622. def test_empty_input(self):
  623. assert_array_almost_equal(self.lut_lsq([], []), np.zeros((0,0)))
  624. assert_array_almost_equal(self.lut_lsq([], [], grid=False), np.zeros((0,)))
  625. def test_invalid_input(self):
  626. ntheta, nphi = 70, 90
  627. theta = linspace(0.5 / (ntheta - 1), 1 - 0.5 / (ntheta - 1),
  628. ntheta) * pi
  629. phi = linspace(0.5 / (nphi - 1), 1 - 0.5 / (nphi - 1), nphi) * 2. * pi
  630. data = ones((theta.shape[0], phi.shape[0]))
  631. # define knots and extract data values at the knots
  632. knotst = theta[::5]
  633. knotsp = phi[::5]
  634. with assert_raises(ValueError) as exc_info:
  635. invalid_theta = linspace(-0.1, 1.0, num=ntheta) * pi
  636. invalid_lats, lons = meshgrid(invalid_theta, phi)
  637. LSQSphereBivariateSpline(invalid_lats.ravel(), lons.ravel(),
  638. data.T.ravel(), knotst, knotsp)
  639. assert "theta should be between [0, pi]" in str(exc_info.value)
  640. with assert_raises(ValueError) as exc_info:
  641. invalid_theta = linspace(0.1, 1.1, num=ntheta) * pi
  642. invalid_lats, lons = meshgrid(invalid_theta, phi)
  643. LSQSphereBivariateSpline(invalid_lats.ravel(), lons.ravel(),
  644. data.T.ravel(), knotst, knotsp)
  645. assert "theta should be between [0, pi]" in str(exc_info.value)
  646. with assert_raises(ValueError) as exc_info:
  647. invalid_phi = linspace(-0.1, 1.0, num=ntheta) * 2.0 * pi
  648. lats, invalid_lons = meshgrid(theta, invalid_phi)
  649. LSQSphereBivariateSpline(lats.ravel(), invalid_lons.ravel(),
  650. data.T.ravel(), knotst, knotsp)
  651. assert "phi should be between [0, 2pi]" in str(exc_info.value)
  652. with assert_raises(ValueError) as exc_info:
  653. invalid_phi = linspace(0.0, 1.1, num=ntheta) * 2.0 * pi
  654. lats, invalid_lons = meshgrid(theta, invalid_phi)
  655. LSQSphereBivariateSpline(lats.ravel(), invalid_lons.ravel(),
  656. data.T.ravel(), knotst, knotsp)
  657. assert "phi should be between [0, 2pi]" in str(exc_info.value)
  658. lats, lons = meshgrid(theta, phi)
  659. with assert_raises(ValueError) as exc_info:
  660. invalid_knotst = np.copy(knotst)
  661. invalid_knotst[0] = -0.1
  662. LSQSphereBivariateSpline(lats.ravel(), lons.ravel(),
  663. data.T.ravel(), invalid_knotst, knotsp)
  664. assert "tt should be between (0, pi)" in str(exc_info.value)
  665. with assert_raises(ValueError) as exc_info:
  666. invalid_knotst = np.copy(knotst)
  667. invalid_knotst[0] = pi
  668. LSQSphereBivariateSpline(lats.ravel(), lons.ravel(),
  669. data.T.ravel(), invalid_knotst, knotsp)
  670. assert "tt should be between (0, pi)" in str(exc_info.value)
  671. with assert_raises(ValueError) as exc_info:
  672. invalid_knotsp = np.copy(knotsp)
  673. invalid_knotsp[0] = -0.1
  674. LSQSphereBivariateSpline(lats.ravel(), lons.ravel(),
  675. data.T.ravel(), knotst, invalid_knotsp)
  676. assert "tp should be between (0, 2pi)" in str(exc_info.value)
  677. with assert_raises(ValueError) as exc_info:
  678. invalid_knotsp = np.copy(knotsp)
  679. invalid_knotsp[0] = 2 * pi
  680. LSQSphereBivariateSpline(lats.ravel(), lons.ravel(),
  681. data.T.ravel(), knotst, invalid_knotsp)
  682. assert "tp should be between (0, 2pi)" in str(exc_info.value)
  683. with assert_raises(ValueError) as exc_info:
  684. invalid_w = array([-1.0, 1.0, 1.5, 0.5, 1.0, 1.5, 0.5, 1.0, 1.0])
  685. LSQSphereBivariateSpline(lats.ravel(), lons.ravel(), data.T.ravel(),
  686. knotst, knotsp, w=invalid_w)
  687. assert "w should be positive" in str(exc_info.value)
  688. with assert_raises(ValueError) as exc_info:
  689. LSQSphereBivariateSpline(lats.ravel(), lons.ravel(), data.T.ravel(),
  690. knotst, knotsp, eps=0.0)
  691. assert "eps should be between (0, 1)" in str(exc_info.value)
  692. with assert_raises(ValueError) as exc_info:
  693. LSQSphereBivariateSpline(lats.ravel(), lons.ravel(), data.T.ravel(),
  694. knotst, knotsp, eps=1.0)
  695. assert "eps should be between (0, 1)" in str(exc_info.value)
  696. def test_array_like_input(self):
  697. ntheta, nphi = 70, 90
  698. theta = linspace(0.5 / (ntheta - 1), 1 - 0.5 / (ntheta - 1),
  699. ntheta) * pi
  700. phi = linspace(0.5 / (nphi - 1), 1 - 0.5 / (nphi - 1),
  701. nphi) * 2. * pi
  702. lats, lons = meshgrid(theta, phi)
  703. data = ones((theta.shape[0], phi.shape[0]))
  704. # define knots and extract data values at the knots
  705. knotst = theta[::5]
  706. knotsp = phi[::5]
  707. w = ones(lats.ravel().shape[0])
  708. # np.array input
  709. spl1 = LSQSphereBivariateSpline(lats.ravel(), lons.ravel(),
  710. data.T.ravel(), knotst, knotsp, w=w)
  711. # list input
  712. spl2 = LSQSphereBivariateSpline(lats.ravel().tolist(),
  713. lons.ravel().tolist(),
  714. data.T.ravel().tolist(),
  715. knotst.tolist(),
  716. knotsp.tolist(), w=w.tolist())
  717. assert_array_almost_equal(spl1(1.0, 1.0), spl2(1.0, 1.0))
  718. class TestSmoothSphereBivariateSpline:
  719. def setup_method(self):
  720. theta = array([.25*pi, .25*pi, .25*pi, .5*pi, .5*pi, .5*pi, .75*pi,
  721. .75*pi, .75*pi])
  722. phi = array([.5 * pi, pi, 1.5 * pi, .5 * pi, pi, 1.5 * pi, .5 * pi, pi,
  723. 1.5 * pi])
  724. r = array([3, 3, 3, 3, 3, 3, 3, 3, 3])
  725. self.lut = SmoothSphereBivariateSpline(theta, phi, r, s=1E10)
  726. def test_linear_constant(self):
  727. assert abs(self.lut.get_residual()) < 1e-15
  728. assert_array_almost_equal(self.lut([1, 1.5, 2],[1, 1.5]),
  729. [[3, 3], [3, 3], [3, 3]])
  730. def test_empty_input(self):
  731. assert_array_almost_equal(self.lut([], []), np.zeros((0,0)))
  732. assert_array_almost_equal(self.lut([], [], grid=False), np.zeros((0,)))
  733. def test_invalid_input(self):
  734. theta = array([.25 * pi, .25 * pi, .25 * pi, .5 * pi, .5 * pi, .5 * pi,
  735. .75 * pi, .75 * pi, .75 * pi])
  736. phi = array([.5 * pi, pi, 1.5 * pi, .5 * pi, pi, 1.5 * pi, .5 * pi, pi,
  737. 1.5 * pi])
  738. r = array([3, 3, 3, 3, 3, 3, 3, 3, 3])
  739. with assert_raises(ValueError) as exc_info:
  740. invalid_theta = array([-0.1 * pi, .25 * pi, .25 * pi, .5 * pi,
  741. .5 * pi, .5 * pi, .75 * pi, .75 * pi,
  742. .75 * pi])
  743. SmoothSphereBivariateSpline(invalid_theta, phi, r, s=1E10)
  744. assert "theta should be between [0, pi]" in str(exc_info.value)
  745. with assert_raises(ValueError) as exc_info:
  746. invalid_theta = array([.25 * pi, .25 * pi, .25 * pi, .5 * pi,
  747. .5 * pi, .5 * pi, .75 * pi, .75 * pi,
  748. 1.1 * pi])
  749. SmoothSphereBivariateSpline(invalid_theta, phi, r, s=1E10)
  750. assert "theta should be between [0, pi]" in str(exc_info.value)
  751. with assert_raises(ValueError) as exc_info:
  752. invalid_phi = array([-.1 * pi, pi, 1.5 * pi, .5 * pi, pi, 1.5 * pi,
  753. .5 * pi, pi, 1.5 * pi])
  754. SmoothSphereBivariateSpline(theta, invalid_phi, r, s=1E10)
  755. assert "phi should be between [0, 2pi]" in str(exc_info.value)
  756. with assert_raises(ValueError) as exc_info:
  757. invalid_phi = array([1.0 * pi, pi, 1.5 * pi, .5 * pi, pi, 1.5 * pi,
  758. .5 * pi, pi, 2.1 * pi])
  759. SmoothSphereBivariateSpline(theta, invalid_phi, r, s=1E10)
  760. assert "phi should be between [0, 2pi]" in str(exc_info.value)
  761. with assert_raises(ValueError) as exc_info:
  762. invalid_w = array([-1.0, 1.0, 1.5, 0.5, 1.0, 1.5, 0.5, 1.0, 1.0])
  763. SmoothSphereBivariateSpline(theta, phi, r, w=invalid_w, s=1E10)
  764. assert "w should be positive" in str(exc_info.value)
  765. with assert_raises(ValueError) as exc_info:
  766. SmoothSphereBivariateSpline(theta, phi, r, s=-1.0)
  767. assert "s should be positive" in str(exc_info.value)
  768. with assert_raises(ValueError) as exc_info:
  769. SmoothSphereBivariateSpline(theta, phi, r, eps=-1.0)
  770. assert "eps should be between (0, 1)" in str(exc_info.value)
  771. with assert_raises(ValueError) as exc_info:
  772. SmoothSphereBivariateSpline(theta, phi, r, eps=1.0)
  773. assert "eps should be between (0, 1)" in str(exc_info.value)
  774. def test_array_like_input(self):
  775. theta = np.array([.25 * pi, .25 * pi, .25 * pi, .5 * pi, .5 * pi,
  776. .5 * pi, .75 * pi, .75 * pi, .75 * pi])
  777. phi = np.array([.5 * pi, pi, 1.5 * pi, .5 * pi, pi, 1.5 * pi, .5 * pi,
  778. pi, 1.5 * pi])
  779. r = np.array([3, 3, 3, 3, 3, 3, 3, 3, 3])
  780. w = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
  781. # np.array input
  782. spl1 = SmoothSphereBivariateSpline(theta, phi, r, w=w, s=1E10)
  783. # list input
  784. spl2 = SmoothSphereBivariateSpline(theta.tolist(), phi.tolist(),
  785. r.tolist(), w=w.tolist(), s=1E10)
  786. assert_array_almost_equal(spl1(1.0, 1.0), spl2(1.0, 1.0))
  787. class TestRectBivariateSpline:
  788. def test_defaults(self):
  789. x = array([1,2,3,4,5])
  790. y = array([1,2,3,4,5])
  791. z = array([[1,2,1,2,1],[1,2,1,2,1],[1,2,3,2,1],[1,2,2,2,1],[1,2,1,2,1]])
  792. lut = RectBivariateSpline(x,y,z)
  793. assert_array_almost_equal(lut(x,y),z)
  794. def test_evaluate(self):
  795. x = array([1,2,3,4,5])
  796. y = array([1,2,3,4,5])
  797. z = array([[1,2,1,2,1],[1,2,1,2,1],[1,2,3,2,1],[1,2,2,2,1],[1,2,1,2,1]])
  798. lut = RectBivariateSpline(x,y,z)
  799. xi = [1, 2.3, 5.3, 0.5, 3.3, 1.2, 3]
  800. yi = [1, 3.3, 1.2, 4.0, 5.0, 1.0, 3]
  801. zi = lut.ev(xi, yi)
  802. zi2 = array([lut(xp, yp)[0,0] for xp, yp in zip(xi, yi)])
  803. assert_almost_equal(zi, zi2)
  804. def test_derivatives_grid(self):
  805. x = array([1,2,3,4,5])
  806. y = array([1,2,3,4,5])
  807. z = array([[1,2,1,2,1],[1,2,1,2,1],[1,2,3,2,1],[1,2,2,2,1],[1,2,1,2,1]])
  808. dx = array([[0,0,-20,0,0],[0,0,13,0,0],[0,0,4,0,0],
  809. [0,0,-11,0,0],[0,0,4,0,0]])/6.
  810. dy = array([[4,-1,0,1,-4],[4,-1,0,1,-4],[0,1.5,0,-1.5,0],
  811. [2,.25,0,-.25,-2],[4,-1,0,1,-4]])
  812. dxdy = array([[40,-25,0,25,-40],[-26,16.25,0,-16.25,26],
  813. [-8,5,0,-5,8],[22,-13.75,0,13.75,-22],[-8,5,0,-5,8]])/6.
  814. lut = RectBivariateSpline(x,y,z)
  815. assert_array_almost_equal(lut(x,y,dx=1),dx)
  816. assert_array_almost_equal(lut(x,y,dy=1),dy)
  817. assert_array_almost_equal(lut(x,y,dx=1,dy=1),dxdy)
  818. def test_derivatives(self):
  819. x = array([1,2,3,4,5])
  820. y = array([1,2,3,4,5])
  821. z = array([[1,2,1,2,1],[1,2,1,2,1],[1,2,3,2,1],[1,2,2,2,1],[1,2,1,2,1]])
  822. dx = array([0,0,2./3,0,0])
  823. dy = array([4,-1,0,-.25,-4])
  824. dxdy = array([160,65,0,55,32])/24.
  825. lut = RectBivariateSpline(x,y,z)
  826. assert_array_almost_equal(lut(x,y,dx=1,grid=False),dx)
  827. assert_array_almost_equal(lut(x,y,dy=1,grid=False),dy)
  828. assert_array_almost_equal(lut(x,y,dx=1,dy=1,grid=False),dxdy)
  829. def make_pair_grid(self, x, y):
  830. """
  831. Create an array of (xi, yi) pairs for all xi in x and yi in y,
  832. and reshape it to the desired shape.
  833. Parameters
  834. ----------
  835. x : array_like
  836. 1D array of x-values.
  837. y : array_like
  838. 1D array of y-values.
  839. dest_shape : tuple
  840. Desired output shape.
  841. Returns
  842. -------
  843. np.ndarray
  844. Reshaped array of (x, y) pairs.
  845. """
  846. return np.array([[xi, yi] for xi in x for yi in y])
  847. def test_partial_derivative_method_grid(self):
  848. x = array([1, 2, 3, 4, 5])
  849. y = array([1, 2, 3, 4, 5])
  850. z = array([[1, 2, 1, 2, 1],
  851. [1, 2, 1, 2, 1],
  852. [1, 2, 3, 2, 1],
  853. [1, 2, 2, 2, 1],
  854. [1, 2, 1, 2, 1]])
  855. dx = array([[0, 0, -20, 0, 0],
  856. [0, 0, 13, 0, 0],
  857. [0, 0, 4, 0, 0],
  858. [0, 0, -11, 0, 0],
  859. [0, 0, 4, 0, 0]]) / 6.
  860. dy = array([[4, -1, 0, 1, -4],
  861. [4, -1, 0, 1, -4],
  862. [0, 1.5, 0, -1.5, 0],
  863. [2, .25, 0, -.25, -2],
  864. [4, -1, 0, 1, -4]])
  865. dxdy = array([[40, -25, 0, 25, -40],
  866. [-26, 16.25, 0, -16.25, 26],
  867. [-8, 5, 0, -5, 8],
  868. [22, -13.75, 0, 13.75, -22],
  869. [-8, 5, 0, -5, 8]]) / 6.
  870. lut = RectBivariateSpline(x, y, z)
  871. lut_ndbspline = convert_to_ndbspline(lut)
  872. for orders, expected in [([1, 0], dx), ([0, 1], dy), ([1, 1], dxdy)]:
  873. actual_rect = lut.partial_derivative(*orders)(x, y)
  874. actual_ndb = lut_ndbspline.derivative(orders)(
  875. self.make_pair_grid(x, y)
  876. ).reshape(expected.shape)
  877. assert_array_almost_equal(actual_rect, expected)
  878. assert_array_almost_equal(actual_ndb, expected)
  879. def test_partial_derivative_method(self):
  880. x = array([1, 2, 3, 4, 5])
  881. y = array([1, 2, 3, 4, 5])
  882. z = array([[1, 2, 1, 2, 1],
  883. [1, 2, 1, 2, 1],
  884. [1, 2, 3, 2, 1],
  885. [1, 2, 2, 2, 1],
  886. [1, 2, 1, 2, 1]])
  887. expected = {
  888. (1, 0): array([0, 0, 2./3, 0, 0]), # dx
  889. (0, 1): array([4, -1, 0, -.25, -4]), # dy
  890. (1, 1): array([160, 65, 0, 55, 32]) / 24. # dxdy
  891. }
  892. lut = RectBivariateSpline(x, y, z)
  893. lut_ndbspline = convert_to_ndbspline(lut)
  894. points = self.make_pair_grid(x, y) # shape: (25, 2)
  895. # Evaluate only the diagonal points: (x[i], y[i])
  896. diag_idx = np.arange(len(x))
  897. diag_points = points[diag_idx * len(y) + diag_idx]
  898. for orders, expected_vals in expected.items():
  899. dx, dy = orders
  900. # RectBivariateSpline result
  901. actual_rbs = lut.partial_derivative(dx, dy)(x, y, grid=False)
  902. assert_array_almost_equal(actual_rbs, expected_vals)
  903. # NdBSpline result
  904. actual_ndb = lut_ndbspline.derivative([dx, dy])(diag_points)
  905. assert_array_almost_equal(actual_ndb, expected_vals)
  906. def test_partial_derivative_order_too_large(self):
  907. x = array([0, 1, 2, 3, 4], dtype=float)
  908. y = x.copy()
  909. z = ones((x.size, y.size))
  910. lut = RectBivariateSpline(x, y, z)
  911. lut_ndbspline = convert_to_ndbspline(lut)
  912. with assert_raises(ValueError):
  913. lut.partial_derivative(4, 1)
  914. assert (lut_ndbspline.derivative([4, 1]).c == 0.0).all()
  915. def test_broadcast(self):
  916. x = array([1,2,3,4,5])
  917. y = array([1,2,3,4,5])
  918. z = array([[1,2,1,2,1],[1,2,1,2,1],[1,2,3,2,1],[1,2,2,2,1],[1,2,1,2,1]])
  919. lut = RectBivariateSpline(x,y,z)
  920. xp_assert_close(lut(x, y), lut(x[:,None], y[None,:], grid=False))
  921. def test_invalid_input(self):
  922. with assert_raises(ValueError) as info:
  923. x = array([6, 2, 3, 4, 5])
  924. y = array([1, 2, 3, 4, 5])
  925. z = array([[1, 2, 1, 2, 1], [1, 2, 1, 2, 1], [1, 2, 3, 2, 1],
  926. [1, 2, 2, 2, 1], [1, 2, 1, 2, 1]])
  927. RectBivariateSpline(x, y, z)
  928. assert "x must be strictly increasing" in str(info.value)
  929. with assert_raises(ValueError) as info:
  930. x = array([1, 2, 3, 4, 5])
  931. y = array([2, 2, 3, 4, 5])
  932. z = array([[1, 2, 1, 2, 1], [1, 2, 1, 2, 1], [1, 2, 3, 2, 1],
  933. [1, 2, 2, 2, 1], [1, 2, 1, 2, 1]])
  934. RectBivariateSpline(x, y, z)
  935. assert "y must be strictly increasing" in str(info.value)
  936. with assert_raises(ValueError) as info:
  937. x = array([1, 2, 3, 4, 5])
  938. y = array([1, 2, 3, 4, 5])
  939. z = array([[1, 2, 1, 2, 1], [1, 2, 1, 2, 1], [1, 2, 3, 2, 1],
  940. [1, 2, 2, 2, 1]])
  941. RectBivariateSpline(x, y, z)
  942. assert "x dimension of z must have same number of elements as x"\
  943. in str(info.value)
  944. with assert_raises(ValueError) as info:
  945. x = array([1, 2, 3, 4, 5])
  946. y = array([1, 2, 3, 4, 5])
  947. z = array([[1, 2, 1, 2], [1, 2, 1, 2], [1, 2, 3, 2],
  948. [1, 2, 2, 2], [1, 2, 1, 2]])
  949. RectBivariateSpline(x, y, z)
  950. assert "y dimension of z must have same number of elements as y"\
  951. in str(info.value)
  952. with assert_raises(ValueError) as info:
  953. x = array([1, 2, 3, 4, 5])
  954. y = array([1, 2, 3, 4, 5])
  955. z = array([[1, 2, 1, 2, 1], [1, 2, 1, 2, 1], [1, 2, 3, 2, 1],
  956. [1, 2, 2, 2, 1], [1, 2, 1, 2, 1]])
  957. bbox = (-100, 100, -100)
  958. RectBivariateSpline(x, y, z, bbox=bbox)
  959. assert "bbox shape should be (4,)" in str(info.value)
  960. with assert_raises(ValueError) as info:
  961. RectBivariateSpline(x, y, z, s=-1.0)
  962. assert "s should be s >= 0.0" in str(info.value)
  963. def test_array_like_input(self):
  964. x = array([1, 2, 3, 4, 5])
  965. y = array([1, 2, 3, 4, 5])
  966. z = array([[1, 2, 1, 2, 1], [1, 2, 1, 2, 1], [1, 2, 3, 2, 1],
  967. [1, 2, 2, 2, 1], [1, 2, 1, 2, 1]])
  968. bbox = array([1, 5, 1, 5])
  969. spl1 = RectBivariateSpline(x, y, z, bbox=bbox)
  970. spl2 = RectBivariateSpline(x.tolist(), y.tolist(), z.tolist(),
  971. bbox=bbox.tolist())
  972. assert_array_almost_equal(spl1(1.0, 1.0), spl2(1.0, 1.0))
  973. def test_not_increasing_input(self):
  974. # gh-8565
  975. NSamp = 20
  976. Theta = np.random.uniform(0, np.pi, NSamp)
  977. Phi = np.random.uniform(0, 2 * np.pi, NSamp)
  978. Data = np.ones(NSamp)
  979. Interpolator = SmoothSphereBivariateSpline(Theta, Phi, Data, s=3.5)
  980. NLon = 6
  981. NLat = 3
  982. GridPosLats = np.arange(NLat) / NLat * np.pi
  983. GridPosLons = np.arange(NLon) / NLon * 2 * np.pi
  984. # No error
  985. Interpolator(GridPosLats, GridPosLons)
  986. nonGridPosLats = GridPosLats.copy()
  987. nonGridPosLats[2] = 0.001
  988. with assert_raises(ValueError) as exc_info:
  989. Interpolator(nonGridPosLats, GridPosLons)
  990. assert "x must be strictly increasing" in str(exc_info.value)
  991. nonGridPosLons = GridPosLons.copy()
  992. nonGridPosLons[2] = 0.001
  993. with assert_raises(ValueError) as exc_info:
  994. Interpolator(GridPosLats, nonGridPosLons)
  995. assert "y must be strictly increasing" in str(exc_info.value)
  996. def _sample_large_2d_data(self, nx, ny):
  997. rng = np.random.default_rng(1)
  998. x = np.arange(nx)
  999. y = np.arange(ny)
  1000. z = rng.integers(0, 100, (nx, ny))
  1001. return x, y, z.astype(np.float64)
  1002. @pytest.mark.slow()
  1003. @pytest.mark.parametrize('shape', [(350, 850), (2000, 170)])
  1004. @pytest.mark.parametrize('s_tols', [(0, 1e-12, 1e-7),
  1005. (1, 7e-3, 1e-4),
  1006. (3, 2e-2, 1e-4)])
  1007. def test_spline_large_2d(self, shape, s_tols):
  1008. # Reference - https://github.com/scipy/scipy/issues/17787
  1009. nx, ny = shape
  1010. s, atol, rtol = s_tols
  1011. x, y, z = self._sample_large_2d_data(nx, ny)
  1012. spl = RectBivariateSpline(x, y, z, s=s)
  1013. z_spl = spl(x, y)
  1014. assert(not np.isnan(z_spl).any())
  1015. xp_assert_close(z_spl, z, atol=atol, rtol=rtol)
  1016. @pytest.mark.slow()
  1017. @pytest.mark.skipif(sys.maxsize <= 2**32, reason="Segfaults on 32-bit system "
  1018. "due to large input data")
  1019. def test_spline_large_2d_maxit(self):
  1020. # Reference - for https://github.com/scipy/scipy/issues/17787
  1021. nx, ny = 1000, 1700
  1022. s, atol, rtol = 2, 2e-2, 1e-12
  1023. x, y, z = self._sample_large_2d_data(nx, ny)
  1024. spl = RectBivariateSpline(x, y, z, s=s, maxit=25)
  1025. z_spl = spl(x, y)
  1026. assert(not np.isnan(z_spl).any())
  1027. xp_assert_close(z_spl, z, atol=atol, rtol=rtol)
  1028. class TestRectSphereBivariateSpline:
  1029. def test_defaults(self):
  1030. y = linspace(0.01, 2*pi-0.01, 7)
  1031. x = linspace(0.01, pi-0.01, 7)
  1032. z = array([[1,2,1,2,1,2,1],[1,2,1,2,1,2,1],[1,2,3,2,1,2,1],
  1033. [1,2,2,2,1,2,1],[1,2,1,2,1,2,1],[1,2,2,2,1,2,1],
  1034. [1,2,1,2,1,2,1]])
  1035. lut = RectSphereBivariateSpline(x,y,z)
  1036. assert_array_almost_equal(lut(x,y),z)
  1037. def test_evaluate(self):
  1038. y = linspace(0.01, 2*pi-0.01, 7)
  1039. x = linspace(0.01, pi-0.01, 7)
  1040. z = array([[1,2,1,2,1,2,1],[1,2,1,2,1,2,1],[1,2,3,2,1,2,1],
  1041. [1,2,2,2,1,2,1],[1,2,1,2,1,2,1],[1,2,2,2,1,2,1],
  1042. [1,2,1,2,1,2,1]])
  1043. lut = RectSphereBivariateSpline(x,y,z)
  1044. yi = [0.2, 1, 2.3, 2.35, 3.0, 3.99, 5.25]
  1045. xi = [1.5, 0.4, 1.1, 0.45, 0.2345, 1., 0.0001]
  1046. zi = lut.ev(xi, yi)
  1047. zi2 = array([lut(xp, yp)[0,0] for xp, yp in zip(xi, yi)])
  1048. assert_almost_equal(zi, zi2)
  1049. def test_invalid_input(self):
  1050. data = np.dot(np.atleast_2d(90. - np.linspace(-80., 80., 18)).T,
  1051. np.atleast_2d(180. - np.abs(np.linspace(0., 350., 9)))).T
  1052. with assert_raises(ValueError) as exc_info:
  1053. lats = np.linspace(-1, 170, 9) * np.pi / 180.
  1054. lons = np.linspace(0, 350, 18) * np.pi / 180.
  1055. RectSphereBivariateSpline(lats, lons, data)
  1056. assert "u should be between (0, pi)" in str(exc_info.value)
  1057. with assert_raises(ValueError) as exc_info:
  1058. lats = np.linspace(10, 181, 9) * np.pi / 180.
  1059. lons = np.linspace(0, 350, 18) * np.pi / 180.
  1060. RectSphereBivariateSpline(lats, lons, data)
  1061. assert "u should be between (0, pi)" in str(exc_info.value)
  1062. with assert_raises(ValueError) as exc_info:
  1063. lats = np.linspace(10, 170, 9) * np.pi / 180.
  1064. lons = np.linspace(-181, 10, 18) * np.pi / 180.
  1065. RectSphereBivariateSpline(lats, lons, data)
  1066. assert "v[0] should be between [-pi, pi)" in str(exc_info.value)
  1067. with assert_raises(ValueError) as exc_info:
  1068. lats = np.linspace(10, 170, 9) * np.pi / 180.
  1069. lons = np.linspace(-10, 360, 18) * np.pi / 180.
  1070. RectSphereBivariateSpline(lats, lons, data)
  1071. assert "v[-1] should be v[0] + 2pi or less" in str(exc_info.value)
  1072. with assert_raises(ValueError) as exc_info:
  1073. lats = np.linspace(10, 170, 9) * np.pi / 180.
  1074. lons = np.linspace(10, 350, 18) * np.pi / 180.
  1075. RectSphereBivariateSpline(lats, lons, data, s=-1)
  1076. assert "s should be positive" in str(exc_info.value)
  1077. def test_derivatives_grid(self):
  1078. y = linspace(0.01, 2*pi-0.01, 7)
  1079. x = linspace(0.01, pi-0.01, 7)
  1080. z = array([[1,2,1,2,1,2,1],[1,2,1,2,1,2,1],[1,2,3,2,1,2,1],
  1081. [1,2,2,2,1,2,1],[1,2,1,2,1,2,1],[1,2,2,2,1,2,1],
  1082. [1,2,1,2,1,2,1]])
  1083. lut = RectSphereBivariateSpline(x,y,z)
  1084. y = linspace(0.02, 2*pi-0.02, 7)
  1085. x = linspace(0.02, pi-0.02, 7)
  1086. xp_assert_close(lut(x, y, dtheta=1), _numdiff_2d(lut, x, y, dx=1),
  1087. rtol=1e-4, atol=1e-4)
  1088. xp_assert_close(lut(x, y, dphi=1), _numdiff_2d(lut, x, y, dy=1),
  1089. rtol=1e-4, atol=1e-4)
  1090. xp_assert_close(lut(x, y, dtheta=1, dphi=1),
  1091. _numdiff_2d(lut, x, y, dx=1, dy=1, eps=1e-6),
  1092. rtol=1e-3, atol=1e-3)
  1093. xp_assert_equal(lut(x, y, dtheta=1),
  1094. lut.partial_derivative(1, 0)(x, y))
  1095. xp_assert_equal(lut(x, y, dphi=1),
  1096. lut.partial_derivative(0, 1)(x, y))
  1097. xp_assert_equal(lut(x, y, dtheta=1, dphi=1),
  1098. lut.partial_derivative(1, 1)(x, y))
  1099. xp_assert_equal(lut(x, y, dtheta=1, grid=False),
  1100. lut.partial_derivative(1, 0)(x, y, grid=False))
  1101. xp_assert_equal(lut(x, y, dphi=1, grid=False),
  1102. lut.partial_derivative(0, 1)(x, y, grid=False))
  1103. xp_assert_equal(lut(x, y, dtheta=1, dphi=1, grid=False),
  1104. lut.partial_derivative(1, 1)(x, y, grid=False))
  1105. def test_derivatives(self):
  1106. y = linspace(0.01, 2*pi-0.01, 7)
  1107. x = linspace(0.01, pi-0.01, 7)
  1108. z = array([[1,2,1,2,1,2,1],[1,2,1,2,1,2,1],[1,2,3,2,1,2,1],
  1109. [1,2,2,2,1,2,1],[1,2,1,2,1,2,1],[1,2,2,2,1,2,1],
  1110. [1,2,1,2,1,2,1]])
  1111. lut = RectSphereBivariateSpline(x,y,z)
  1112. y = linspace(0.02, 2*pi-0.02, 7)
  1113. x = linspace(0.02, pi-0.02, 7)
  1114. assert lut(x, y, dtheta=1, grid=False).shape == x.shape
  1115. xp_assert_close(lut(x, y, dtheta=1, grid=False),
  1116. _numdiff_2d(lambda x,y: lut(x,y,grid=False), x, y, dx=1),
  1117. rtol=1e-4, atol=1e-4)
  1118. xp_assert_close(lut(x, y, dphi=1, grid=False),
  1119. _numdiff_2d(lambda x,y: lut(x,y,grid=False), x, y, dy=1),
  1120. rtol=1e-4, atol=1e-4)
  1121. xp_assert_close(lut(x, y, dtheta=1, dphi=1, grid=False),
  1122. _numdiff_2d(lambda x,y: lut(x,y,grid=False),
  1123. x, y, dx=1, dy=1, eps=1e-6),
  1124. rtol=1e-3, atol=1e-3)
  1125. def test_invalid_input_2(self):
  1126. data = np.dot(np.atleast_2d(90. - np.linspace(-80., 80., 18)).T,
  1127. np.atleast_2d(180. - np.abs(np.linspace(0., 350., 9)))).T
  1128. with assert_raises(ValueError) as exc_info:
  1129. lats = np.linspace(0, 170, 9) * np.pi / 180.
  1130. lons = np.linspace(0, 350, 18) * np.pi / 180.
  1131. RectSphereBivariateSpline(lats, lons, data)
  1132. assert "u should be between (0, pi)" in str(exc_info.value)
  1133. with assert_raises(ValueError) as exc_info:
  1134. lats = np.linspace(10, 180, 9) * np.pi / 180.
  1135. lons = np.linspace(0, 350, 18) * np.pi / 180.
  1136. RectSphereBivariateSpline(lats, lons, data)
  1137. assert "u should be between (0, pi)" in str(exc_info.value)
  1138. with assert_raises(ValueError) as exc_info:
  1139. lats = np.linspace(10, 170, 9) * np.pi / 180.
  1140. lons = np.linspace(-181, 10, 18) * np.pi / 180.
  1141. RectSphereBivariateSpline(lats, lons, data)
  1142. assert "v[0] should be between [-pi, pi)" in str(exc_info.value)
  1143. with assert_raises(ValueError) as exc_info:
  1144. lats = np.linspace(10, 170, 9) * np.pi / 180.
  1145. lons = np.linspace(-10, 360, 18) * np.pi / 180.
  1146. RectSphereBivariateSpline(lats, lons, data)
  1147. assert "v[-1] should be v[0] + 2pi or less" in str(exc_info.value)
  1148. with assert_raises(ValueError) as exc_info:
  1149. lats = np.linspace(10, 170, 9) * np.pi / 180.
  1150. lons = np.linspace(10, 350, 18) * np.pi / 180.
  1151. RectSphereBivariateSpline(lats, lons, data, s=-1)
  1152. assert "s should be positive" in str(exc_info.value)
  1153. def test_array_like_input(self):
  1154. y = linspace(0.01, 2 * pi - 0.01, 7)
  1155. x = linspace(0.01, pi - 0.01, 7)
  1156. z = array([[1, 2, 1, 2, 1, 2, 1], [1, 2, 1, 2, 1, 2, 1],
  1157. [1, 2, 3, 2, 1, 2, 1],
  1158. [1, 2, 2, 2, 1, 2, 1], [1, 2, 1, 2, 1, 2, 1],
  1159. [1, 2, 2, 2, 1, 2, 1],
  1160. [1, 2, 1, 2, 1, 2, 1]])
  1161. # np.array input
  1162. spl1 = RectSphereBivariateSpline(x, y, z)
  1163. # list input
  1164. spl2 = RectSphereBivariateSpline(x.tolist(), y.tolist(), z.tolist())
  1165. assert_array_almost_equal(spl1(x, y), spl2(x, y))
  1166. def test_negative_evaluation(self):
  1167. lats = np.array([25, 30, 35, 40, 45])
  1168. lons = np.array([-90, -85, -80, -75, 70])
  1169. mesh = np.meshgrid(lats, lons)
  1170. data = mesh[0] + mesh[1] # lon + lat value
  1171. lat_r = np.radians(lats)
  1172. lon_r = np.radians(lons)
  1173. interpolator = RectSphereBivariateSpline(lat_r, lon_r, data)
  1174. query_lat = np.radians(np.array([35, 37.5]))
  1175. query_lon = np.radians(np.array([-80, -77.5]))
  1176. data_interp = interpolator(query_lat, query_lon)
  1177. ans = np.array([[-45.0, -42.480862],
  1178. [-49.0625, -46.54315]])
  1179. assert_array_almost_equal(data_interp, ans)
  1180. def test_pole_continuity_gh_14591(self):
  1181. # regression test for https://github.com/scipy/scipy/issues/14591
  1182. # with pole_continuty=(True, True), the internal work array size
  1183. # was too small, leading to a FITPACK data validation error.
  1184. # The reproducer in gh-14591 was using a NetCDF4 file with
  1185. # 361x507 arrays, so here we trivialize array sizes to a minimum
  1186. # which still demonstrates the issue.
  1187. u = np.arange(1, 10) * np.pi / 10
  1188. v = np.arange(1, 10) * np.pi / 10
  1189. r = np.zeros((9, 9))
  1190. for p in [(True, True), (True, False), (False, False)]:
  1191. RectSphereBivariateSpline(u, v, r, s=0, pole_continuity=p)
  1192. def _numdiff_2d(func, x, y, dx=0, dy=0, eps=1e-8):
  1193. if dx == 0 and dy == 0:
  1194. return func(x, y)
  1195. elif dx == 1 and dy == 0:
  1196. return (func(x + eps, y) - func(x - eps, y)) / (2*eps)
  1197. elif dx == 0 and dy == 1:
  1198. return (func(x, y + eps) - func(x, y - eps)) / (2*eps)
  1199. elif dx == 1 and dy == 1:
  1200. return (func(x + eps, y + eps) - func(x - eps, y + eps)
  1201. - func(x + eps, y - eps) + func(x - eps, y - eps)) / (2*eps)**2
  1202. else:
  1203. raise ValueError("invalid derivative order")
  1204. class Test_DerivedBivariateSpline:
  1205. """Test the creation, usage, and attribute access of the (private)
  1206. _DerivedBivariateSpline class.
  1207. """
  1208. def setup_method(self):
  1209. x = np.concatenate(list(zip(range(10), range(10))))
  1210. y = np.concatenate(list(zip(range(10), range(1, 11))))
  1211. z = np.concatenate((np.linspace(3, 1, 10), np.linspace(1, 3, 10)))
  1212. with pytest.warns(UserWarning, match="\nThe coefficients of the spline"):
  1213. self.lut_lsq = LSQBivariateSpline(x, y, z,
  1214. linspace(0.5, 19.5, 4),
  1215. linspace(1.5, 20.5, 4),
  1216. eps=1e-2)
  1217. self.lut_smooth = SmoothBivariateSpline(x, y, z)
  1218. xx = linspace(0, 1, 20)
  1219. yy = xx + 1.0
  1220. zz = array([np.roll(z, i) for i in range(z.size)])
  1221. self.lut_rect = RectBivariateSpline(xx, yy, zz)
  1222. self.orders = list(itertools.product(range(3), range(3)))
  1223. def test_creation_from_LSQ(self):
  1224. for nux, nuy in self.orders:
  1225. lut_der = self.lut_lsq.partial_derivative(nux, nuy)
  1226. a = lut_der(3.5, 3.5, grid=False)
  1227. b = self.lut_lsq(3.5, 3.5, dx=nux, dy=nuy, grid=False)
  1228. assert a == b
  1229. def test_creation_from_Smooth(self):
  1230. for nux, nuy in self.orders:
  1231. lut_der = self.lut_smooth.partial_derivative(nux, nuy)
  1232. a = lut_der(5.5, 5.5, grid=False)
  1233. b = self.lut_smooth(5.5, 5.5, dx=nux, dy=nuy, grid=False)
  1234. assert a == b
  1235. def test_creation_from_Rect(self):
  1236. for nux, nuy in self.orders:
  1237. lut_der = self.lut_rect.partial_derivative(nux, nuy)
  1238. lut_ndspline = convert_to_ndbspline(self.lut_rect)
  1239. lut_der_ndbspline = lut_ndspline.derivative((nux, nuy))
  1240. a = lut_der(0.5, 1.5, grid=False)
  1241. a_ndbspline = lut_der_ndbspline([(0.5, 1.5)])
  1242. b = self.lut_rect(0.5, 1.5, dx=nux, dy=nuy, grid=False)
  1243. b_ndbspline = lut_ndspline([(0.5, 1.5)], nu=(nux, nuy))
  1244. assert a == b
  1245. assert_almost_equal(a_ndbspline, b_ndbspline)
  1246. def test_invalid_attribute_fp(self):
  1247. der = self.lut_rect.partial_derivative(1, 1)
  1248. lut_ndspline = convert_to_ndbspline(self.lut_rect)
  1249. der_ndbspline = lut_ndspline.derivative((1, 1))
  1250. with assert_raises(AttributeError):
  1251. der.fp
  1252. with assert_raises(AttributeError):
  1253. der_ndbspline.fp
  1254. def test_invalid_attribute_get_residual(self):
  1255. der = self.lut_smooth.partial_derivative(1, 1)
  1256. with assert_raises(AttributeError):
  1257. der.get_residual()