test_legendre.py 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
  1. import math
  2. import warnings
  3. import numpy as np
  4. import pytest
  5. from numpy.testing import assert_equal, assert_allclose
  6. from scipy import special
  7. from scipy.special import (legendre_p, legendre_p_all, assoc_legendre_p,
  8. assoc_legendre_p_all, sph_legendre_p, sph_legendre_p_all)
  9. # Base polynomials come from Abrahmowitz and Stegan
  10. class TestLegendre:
  11. def test_legendre(self):
  12. leg0 = special.legendre(0)
  13. leg1 = special.legendre(1)
  14. leg2 = special.legendre(2)
  15. leg3 = special.legendre(3)
  16. leg4 = special.legendre(4)
  17. leg5 = special.legendre(5)
  18. assert_equal(leg0.c, [1])
  19. assert_equal(leg1.c, [1,0])
  20. assert_allclose(leg2.c, np.array([3, 0, -1])/2.0,
  21. atol=1.5e-13, rtol=0)
  22. assert_allclose(leg3.c, np.array([5, 0, -3, 0])/2.0,
  23. atol=1.5e-7, rtol=0)
  24. assert_allclose(leg4.c, np.array([35, 0, -30, 0, 3])/8.0,
  25. atol=1.5e-7, rtol=0)
  26. assert_allclose(leg5.c, np.array([63, 0, -70, 0, 15, 0])/8.0,
  27. atol=1.5e-7, rtol=0)
  28. class TestLegendreP:
  29. @pytest.mark.parametrize("shape", [(10,), (4, 9), (3, 5, 7)])
  30. def test_ode(self, shape):
  31. rng = np.random.default_rng(1234)
  32. n = rng.integers(0, 100, shape)
  33. x = rng.uniform(-1, 1, shape)
  34. p, p_jac, p_hess = legendre_p(n, x, diff_n=2)
  35. assert p.shape == shape
  36. assert p_jac.shape == p.shape
  37. assert p_hess.shape == p_jac.shape
  38. err = (1 - x * x) * p_hess - 2 * x * p_jac + n * (n + 1) * p
  39. np.testing.assert_allclose(err, 0, atol=1e-10)
  40. @pytest.mark.parametrize("n_max", [1, 2, 4, 8, 16, 32])
  41. @pytest.mark.parametrize("x_shape", [(10,), (4, 9), (3, 5, 7)])
  42. def test_all_ode(self, n_max, x_shape):
  43. rng = np.random.default_rng(1234)
  44. x = rng.uniform(-1, 1, x_shape)
  45. p, p_jac, p_hess = legendre_p_all(n_max, x, diff_n=2)
  46. n = np.arange(n_max + 1)
  47. n = np.expand_dims(n, axis = tuple(range(1, x.ndim + 1)))
  48. assert p.shape == (len(n),) + x.shape
  49. assert p_jac.shape == p.shape
  50. assert p_hess.shape == p_jac.shape
  51. err = (1 - x * x) * p_hess - 2 * x * p_jac + n * (n + 1) * p
  52. np.testing.assert_allclose(err, 0, atol=1e-10)
  53. class TestAssocLegendreP:
  54. def test_assoc_legendre_gh23101(self):
  55. z = np.array([-1, -.5, 0, .5, 1])
  56. expected = assoc_legendre_p_1_0(z)
  57. result = assoc_legendre_p(1, 0, z)
  58. assert_allclose(np.squeeze(result), expected)
  59. expected = assoc_legendre_p_3_0(z)
  60. result = assoc_legendre_p(3, 0, z)
  61. assert_allclose(np.squeeze(result), expected)
  62. @pytest.mark.parametrize("shape", [(10,), (4, 9), (3, 5, 7, 10)])
  63. @pytest.mark.parametrize("m_max", [5, 4])
  64. @pytest.mark.parametrize("n_max", [7, 10])
  65. def test_lpmn(self, shape, n_max, m_max):
  66. rng = np.random.default_rng(1234)
  67. x = rng.uniform(-0.99, 0.99, shape)
  68. p_all, p_all_jac, p_all_hess = \
  69. assoc_legendre_p_all(n_max, m_max, x, diff_n=2)
  70. n = np.arange(n_max + 1)
  71. n = np.expand_dims(n, axis = tuple(range(1, x.ndim + 2)))
  72. m = np.concatenate([np.arange(m_max + 1), np.arange(-m_max, 0)])
  73. m = np.expand_dims(m, axis = (0,) + tuple(range(2, x.ndim + 2)))
  74. x = np.expand_dims(x, axis = (0, 1))
  75. p, p_jac, p_hess = assoc_legendre_p(n, m, x, diff_n=2)
  76. np.testing.assert_allclose(p, p_all)
  77. np.testing.assert_allclose(p_jac, p_all_jac)
  78. np.testing.assert_allclose(p_hess, p_all_hess)
  79. @pytest.mark.parametrize("shape", [(10,), (4, 9), (3, 5, 7, 10)])
  80. @pytest.mark.parametrize("norm", [True, False])
  81. def test_ode(self, shape, norm):
  82. rng = np.random.default_rng(1234)
  83. n = rng.integers(0, 10, shape)
  84. m = rng.integers(-10, 10, shape)
  85. x = rng.uniform(-1, 1, shape)
  86. p, p_jac, p_hess = assoc_legendre_p(n, m, x, norm=norm, diff_n=2)
  87. assert p.shape == shape
  88. assert p_jac.shape == p.shape
  89. assert p_hess.shape == p_jac.shape
  90. np.testing.assert_allclose((1 - x * x) * p_hess,
  91. 2 * x * p_jac - (n * (n + 1) - m * m / (1 - x * x)) * p,
  92. rtol=1e-05, atol=1e-08)
  93. @pytest.mark.parametrize("shape", [(10,), (4, 9), (3, 5, 7)])
  94. def test_all(self, shape):
  95. rng = np.random.default_rng(1234)
  96. n_max = 20
  97. m_max = 20
  98. x = rng.uniform(-0.99, 0.99, shape)
  99. p, p_jac, p_hess = assoc_legendre_p_all(n_max, m_max, x, diff_n=2)
  100. m = np.concatenate([np.arange(m_max + 1), np.arange(-m_max, 0)])
  101. n = np.arange(n_max + 1)
  102. n = np.expand_dims(n, axis = tuple(range(1, x.ndim + 2)))
  103. m = np.expand_dims(m, axis = (0,) + tuple(range(2, x.ndim + 2)))
  104. np.testing.assert_allclose((1 - x * x) * p_hess,
  105. 2 * x * p_jac - (n * (n + 1) - m * m / (1 - x * x)) * p,
  106. rtol=1e-05, atol=1e-08)
  107. @pytest.mark.parametrize("shape", [(10,), (4, 9), (3, 5, 7)])
  108. @pytest.mark.parametrize("norm", [True, False])
  109. def test_specific(self, shape, norm):
  110. rng = np.random.default_rng(1234)
  111. x = rng.uniform(-0.99, 0.99, shape)
  112. p, p_jac = assoc_legendre_p_all(4, 4, x, norm=norm, diff_n=1)
  113. np.testing.assert_allclose(p[0, 0],
  114. assoc_legendre_p_0_0(x, norm=norm))
  115. np.testing.assert_allclose(p[0, 1], 0)
  116. np.testing.assert_allclose(p[0, 2], 0)
  117. np.testing.assert_allclose(p[0, 3], 0)
  118. np.testing.assert_allclose(p[0, 4], 0)
  119. np.testing.assert_allclose(p[0, -3], 0)
  120. np.testing.assert_allclose(p[0, -2], 0)
  121. np.testing.assert_allclose(p[0, -1], 0)
  122. np.testing.assert_allclose(p[1, 0],
  123. assoc_legendre_p_1_0(x, norm=norm))
  124. np.testing.assert_allclose(p[1, 1],
  125. assoc_legendre_p_1_1(x, norm=norm))
  126. np.testing.assert_allclose(p[1, 2], 0)
  127. np.testing.assert_allclose(p[1, 3], 0)
  128. np.testing.assert_allclose(p[1, 4], 0)
  129. np.testing.assert_allclose(p[1, -4], 0)
  130. np.testing.assert_allclose(p[1, -3], 0)
  131. np.testing.assert_allclose(p[1, -2], 0)
  132. np.testing.assert_allclose(p[1, -1],
  133. assoc_legendre_p_1_m1(x, norm=norm))
  134. np.testing.assert_allclose(p[2, 0],
  135. assoc_legendre_p_2_0(x, norm=norm))
  136. np.testing.assert_allclose(p[2, 1],
  137. assoc_legendre_p_2_1(x, norm=norm))
  138. np.testing.assert_allclose(p[2, 2],
  139. assoc_legendre_p_2_2(x, norm=norm))
  140. np.testing.assert_allclose(p[2, 3], 0)
  141. np.testing.assert_allclose(p[2, 4], 0)
  142. np.testing.assert_allclose(p[2, -4], 0)
  143. np.testing.assert_allclose(p[2, -3], 0)
  144. np.testing.assert_allclose(p[2, -2],
  145. assoc_legendre_p_2_m2(x, norm=norm))
  146. np.testing.assert_allclose(p[2, -1],
  147. assoc_legendre_p_2_m1(x, norm=norm))
  148. np.testing.assert_allclose(p[3, 0],
  149. assoc_legendre_p_3_0(x, norm=norm))
  150. np.testing.assert_allclose(p[3, 1],
  151. assoc_legendre_p_3_1(x, norm=norm))
  152. np.testing.assert_allclose(p[3, 2],
  153. assoc_legendre_p_3_2(x, norm=norm))
  154. np.testing.assert_allclose(p[3, 3],
  155. assoc_legendre_p_3_3(x, norm=norm))
  156. np.testing.assert_allclose(p[3, 4], 0)
  157. np.testing.assert_allclose(p[3, -4], 0)
  158. np.testing.assert_allclose(p[3, -3],
  159. assoc_legendre_p_3_m3(x, norm=norm))
  160. np.testing.assert_allclose(p[3, -2],
  161. assoc_legendre_p_3_m2(x, norm=norm))
  162. np.testing.assert_allclose(p[3, -1],
  163. assoc_legendre_p_3_m1(x, norm=norm))
  164. np.testing.assert_allclose(p[4, 0],
  165. assoc_legendre_p_4_0(x, norm=norm))
  166. np.testing.assert_allclose(p[4, 1],
  167. assoc_legendre_p_4_1(x, norm=norm))
  168. np.testing.assert_allclose(p[4, 2],
  169. assoc_legendre_p_4_2(x, norm=norm))
  170. np.testing.assert_allclose(p[4, 3],
  171. assoc_legendre_p_4_3(x, norm=norm))
  172. np.testing.assert_allclose(p[4, 4],
  173. assoc_legendre_p_4_4(x, norm=norm))
  174. np.testing.assert_allclose(p[4, -4],
  175. assoc_legendre_p_4_m4(x, norm=norm))
  176. np.testing.assert_allclose(p[4, -3],
  177. assoc_legendre_p_4_m3(x, norm=norm))
  178. np.testing.assert_allclose(p[4, -2],
  179. assoc_legendre_p_4_m2(x, norm=norm))
  180. np.testing.assert_allclose(p[4, -1],
  181. assoc_legendre_p_4_m1(x, norm=norm))
  182. np.testing.assert_allclose(p_jac[0, 0],
  183. assoc_legendre_p_0_0_jac(x, norm=norm))
  184. np.testing.assert_allclose(p_jac[0, 1], 0)
  185. np.testing.assert_allclose(p_jac[0, 2], 0)
  186. np.testing.assert_allclose(p_jac[0, 3], 0)
  187. np.testing.assert_allclose(p_jac[0, 4], 0)
  188. np.testing.assert_allclose(p_jac[0, -4], 0)
  189. np.testing.assert_allclose(p_jac[0, -3], 0)
  190. np.testing.assert_allclose(p_jac[0, -2], 0)
  191. np.testing.assert_allclose(p_jac[0, -1], 0)
  192. np.testing.assert_allclose(p_jac[1, 0],
  193. assoc_legendre_p_1_0_jac(x, norm=norm))
  194. np.testing.assert_allclose(p_jac[1, 1],
  195. assoc_legendre_p_1_1_jac(x, norm=norm))
  196. np.testing.assert_allclose(p_jac[1, 2], 0)
  197. np.testing.assert_allclose(p_jac[1, 3], 0)
  198. np.testing.assert_allclose(p_jac[1, 4], 0)
  199. np.testing.assert_allclose(p_jac[1, -4], 0)
  200. np.testing.assert_allclose(p_jac[1, -3], 0)
  201. np.testing.assert_allclose(p_jac[1, -2], 0)
  202. np.testing.assert_allclose(p_jac[1, -1],
  203. assoc_legendre_p_1_m1_jac(x, norm=norm))
  204. np.testing.assert_allclose(p_jac[2, 0],
  205. assoc_legendre_p_2_0_jac(x, norm=norm))
  206. np.testing.assert_allclose(p_jac[2, 1],
  207. assoc_legendre_p_2_1_jac(x, norm=norm))
  208. np.testing.assert_allclose(p_jac[2, 2],
  209. assoc_legendre_p_2_2_jac(x, norm=norm))
  210. np.testing.assert_allclose(p_jac[2, 3], 0)
  211. np.testing.assert_allclose(p_jac[2, 4], 0)
  212. np.testing.assert_allclose(p_jac[2, -4], 0)
  213. np.testing.assert_allclose(p_jac[2, -3], 0)
  214. np.testing.assert_allclose(p_jac[2, -2],
  215. assoc_legendre_p_2_m2_jac(x, norm=norm))
  216. np.testing.assert_allclose(p_jac[2, -1],
  217. assoc_legendre_p_2_m1_jac(x, norm=norm))
  218. np.testing.assert_allclose(p_jac[3, 0],
  219. assoc_legendre_p_3_0_jac(x, norm=norm))
  220. np.testing.assert_allclose(p_jac[3, 1],
  221. assoc_legendre_p_3_1_jac(x, norm=norm))
  222. np.testing.assert_allclose(p_jac[3, 2],
  223. assoc_legendre_p_3_2_jac(x, norm=norm))
  224. np.testing.assert_allclose(p_jac[3, 3],
  225. assoc_legendre_p_3_3_jac(x, norm=norm))
  226. np.testing.assert_allclose(p_jac[3, 4], 0)
  227. np.testing.assert_allclose(p_jac[3, -4], 0)
  228. np.testing.assert_allclose(p_jac[3, -3],
  229. assoc_legendre_p_3_m3_jac(x, norm=norm))
  230. np.testing.assert_allclose(p_jac[3, -2],
  231. assoc_legendre_p_3_m2_jac(x, norm=norm))
  232. np.testing.assert_allclose(p_jac[3, -1],
  233. assoc_legendre_p_3_m1_jac(x, norm=norm))
  234. np.testing.assert_allclose(p_jac[4, 0],
  235. assoc_legendre_p_4_0_jac(x, norm=norm))
  236. np.testing.assert_allclose(p_jac[4, 1],
  237. assoc_legendre_p_4_1_jac(x, norm=norm))
  238. np.testing.assert_allclose(p_jac[4, 2],
  239. assoc_legendre_p_4_2_jac(x, norm=norm))
  240. np.testing.assert_allclose(p_jac[4, 3],
  241. assoc_legendre_p_4_3_jac(x, norm=norm))
  242. np.testing.assert_allclose(p_jac[4, 4],
  243. assoc_legendre_p_4_4_jac(x, norm=norm))
  244. np.testing.assert_allclose(p_jac[4, -4],
  245. assoc_legendre_p_4_m4_jac(x, norm=norm))
  246. np.testing.assert_allclose(p_jac[4, -3],
  247. assoc_legendre_p_4_m3_jac(x, norm=norm))
  248. np.testing.assert_allclose(p_jac[4, -2],
  249. assoc_legendre_p_4_m2_jac(x, norm=norm))
  250. np.testing.assert_allclose(p_jac[4, -1],
  251. assoc_legendre_p_4_m1_jac(x, norm=norm))
  252. @pytest.mark.parametrize("m_max", [7])
  253. @pytest.mark.parametrize("n_max", [10])
  254. @pytest.mark.parametrize("x", [1, -1])
  255. def test_all_limits(self, m_max, n_max, x):
  256. p, p_jac = assoc_legendre_p_all(n_max, m_max, x, diff_n=1)
  257. n = np.arange(n_max + 1)
  258. np.testing.assert_allclose(p_jac[:, 0],
  259. pow(x, n + 1) * n * (n + 1) / 2)
  260. np.testing.assert_allclose(p_jac[:, 1],
  261. np.where(n >= 1, pow(x, n) * np.inf, 0))
  262. np.testing.assert_allclose(p_jac[:, 2],
  263. np.where(n >= 2, -pow(x, n + 1) * (n + 2) * (n + 1) * n * (n - 1) / 4, 0))
  264. np.testing.assert_allclose(p_jac[:, -2],
  265. np.where(n >= 2, -pow(x, n + 1) / 4, 0))
  266. np.testing.assert_allclose(p_jac[:, -1],
  267. np.where(n >= 1, -pow(x, n) * np.inf, 0))
  268. for m in range(3, m_max + 1):
  269. np.testing.assert_allclose(p_jac[:, m], 0)
  270. np.testing.assert_allclose(p_jac[:, -m], 0)
  271. class TestMultiAssocLegendreP:
  272. @pytest.mark.parametrize("shape", [(1000,), (4, 9), (3, 5, 7)])
  273. @pytest.mark.parametrize("branch_cut", [2, 3])
  274. @pytest.mark.parametrize("z_min, z_max", [(-10 - 10j, 10 + 10j),
  275. (-1, 1), (-10j, 10j)])
  276. @pytest.mark.parametrize("norm", [True, False])
  277. def test_specific(self, shape, branch_cut, z_min, z_max, norm):
  278. rng = np.random.default_rng(1234)
  279. z = rng.uniform(z_min.real, z_max.real, shape) + \
  280. 1j * rng.uniform(z_min.imag, z_max.imag, shape)
  281. p, p_jac = assoc_legendre_p_all(4, 4,
  282. z, branch_cut=branch_cut, norm=norm, diff_n=1)
  283. np.testing.assert_allclose(p[0, 0],
  284. assoc_legendre_p_0_0(z, branch_cut=branch_cut, norm=norm))
  285. np.testing.assert_allclose(p[0, 1], 0)
  286. np.testing.assert_allclose(p[0, 2], 0)
  287. np.testing.assert_allclose(p[0, 3], 0)
  288. np.testing.assert_allclose(p[0, 4], 0)
  289. np.testing.assert_allclose(p[0, -4], 0)
  290. np.testing.assert_allclose(p[0, -3], 0)
  291. np.testing.assert_allclose(p[0, -2], 0)
  292. np.testing.assert_allclose(p[0, -1], 0)
  293. np.testing.assert_allclose(p[1, 0],
  294. assoc_legendre_p_1_0(z, branch_cut=branch_cut, norm=norm))
  295. np.testing.assert_allclose(p[1, 1],
  296. assoc_legendre_p_1_1(z, branch_cut=branch_cut, norm=norm))
  297. np.testing.assert_allclose(p[1, 2], 0)
  298. np.testing.assert_allclose(p[1, 3], 0)
  299. np.testing.assert_allclose(p[1, 4], 0)
  300. np.testing.assert_allclose(p[1, -4], 0)
  301. np.testing.assert_allclose(p[1, -3], 0)
  302. np.testing.assert_allclose(p[1, -2], 0)
  303. np.testing.assert_allclose(p[1, -1],
  304. assoc_legendre_p_1_m1(z, branch_cut=branch_cut, norm=norm))
  305. np.testing.assert_allclose(p[2, 0],
  306. assoc_legendre_p_2_0(z, branch_cut=branch_cut, norm=norm))
  307. np.testing.assert_allclose(p[2, 1],
  308. assoc_legendre_p_2_1(z, branch_cut=branch_cut, norm=norm))
  309. np.testing.assert_allclose(p[2, 2],
  310. assoc_legendre_p_2_2(z, branch_cut=branch_cut, norm=norm))
  311. np.testing.assert_allclose(p[2, 3], 0)
  312. np.testing.assert_allclose(p[2, 4], 0)
  313. np.testing.assert_allclose(p[2, -4], 0)
  314. np.testing.assert_allclose(p[2, -3], 0)
  315. np.testing.assert_allclose(p[2, -2],
  316. assoc_legendre_p_2_m2(z, branch_cut=branch_cut, norm=norm))
  317. np.testing.assert_allclose(p[2, -1],
  318. assoc_legendre_p_2_m1(z, branch_cut=branch_cut, norm=norm))
  319. np.testing.assert_allclose(p[3, 0],
  320. assoc_legendre_p_3_0(z, branch_cut=branch_cut, norm=norm))
  321. np.testing.assert_allclose(p[3, 1],
  322. assoc_legendre_p_3_1(z, branch_cut=branch_cut, norm=norm))
  323. np.testing.assert_allclose(p[3, 2],
  324. assoc_legendre_p_3_2(z, branch_cut=branch_cut, norm=norm))
  325. np.testing.assert_allclose(p[3, 3],
  326. assoc_legendre_p_3_3(z, branch_cut=branch_cut, norm=norm))
  327. np.testing.assert_allclose(p[3, 4], 0)
  328. np.testing.assert_allclose(p[3, -4], 0)
  329. np.testing.assert_allclose(p[3, -3],
  330. assoc_legendre_p_3_m3(z, branch_cut=branch_cut, norm=norm))
  331. np.testing.assert_allclose(p[3, -2],
  332. assoc_legendre_p_3_m2(z, branch_cut=branch_cut, norm=norm))
  333. np.testing.assert_allclose(p[3, -1],
  334. assoc_legendre_p_3_m1(z, branch_cut=branch_cut, norm=norm))
  335. np.testing.assert_allclose(p[4, 0],
  336. assoc_legendre_p_4_0(z, branch_cut=branch_cut, norm=norm))
  337. np.testing.assert_allclose(p[4, 1],
  338. assoc_legendre_p_4_1(z, branch_cut=branch_cut, norm=norm))
  339. np.testing.assert_allclose(p[4, 2],
  340. assoc_legendre_p_4_2(z, branch_cut=branch_cut, norm=norm))
  341. np.testing.assert_allclose(p[4, 3],
  342. assoc_legendre_p_4_3(z, branch_cut=branch_cut, norm=norm))
  343. np.testing.assert_allclose(p[4, 4],
  344. assoc_legendre_p_4_4(z, branch_cut=branch_cut, norm=norm))
  345. np.testing.assert_allclose(p[4, -4],
  346. assoc_legendre_p_4_m4(z, branch_cut=branch_cut, norm=norm))
  347. np.testing.assert_allclose(p[4, -3],
  348. assoc_legendre_p_4_m3(z, branch_cut=branch_cut, norm=norm))
  349. np.testing.assert_allclose(p[4, -2],
  350. assoc_legendre_p_4_m2(z, branch_cut=branch_cut, norm=norm))
  351. np.testing.assert_allclose(p[4, -1],
  352. assoc_legendre_p_4_m1(z, branch_cut=branch_cut, norm=norm))
  353. np.testing.assert_allclose(p_jac[0, 0],
  354. assoc_legendre_p_0_0_jac(z, branch_cut=branch_cut, norm=norm))
  355. np.testing.assert_allclose(p_jac[0, 1], 0)
  356. np.testing.assert_allclose(p_jac[0, 2], 0)
  357. np.testing.assert_allclose(p_jac[0, 3], 0)
  358. np.testing.assert_allclose(p_jac[0, 4], 0)
  359. np.testing.assert_allclose(p_jac[0, -4], 0)
  360. np.testing.assert_allclose(p_jac[0, -3], 0)
  361. np.testing.assert_allclose(p_jac[0, -2], 0)
  362. np.testing.assert_allclose(p_jac[0, -1], 0)
  363. np.testing.assert_allclose(p_jac[1, 0],
  364. assoc_legendre_p_1_0_jac(z, branch_cut=branch_cut, norm=norm))
  365. np.testing.assert_allclose(p_jac[1, 1],
  366. assoc_legendre_p_1_1_jac(z, branch_cut=branch_cut, norm=norm))
  367. np.testing.assert_allclose(p_jac[1, 2], 0)
  368. np.testing.assert_allclose(p_jac[1, 3], 0)
  369. np.testing.assert_allclose(p_jac[1, 4], 0)
  370. np.testing.assert_allclose(p_jac[1, -4], 0)
  371. np.testing.assert_allclose(p_jac[1, -3], 0)
  372. np.testing.assert_allclose(p_jac[1, -2], 0)
  373. np.testing.assert_allclose(p_jac[1, -1],
  374. assoc_legendre_p_1_m1_jac(z, branch_cut=branch_cut, norm=norm))
  375. np.testing.assert_allclose(p_jac[2, 0],
  376. assoc_legendre_p_2_0_jac(z, branch_cut=branch_cut, norm=norm))
  377. np.testing.assert_allclose(p_jac[2, 1],
  378. assoc_legendre_p_2_1_jac(z, branch_cut=branch_cut, norm=norm))
  379. np.testing.assert_allclose(p_jac[2, 2],
  380. assoc_legendre_p_2_2_jac(z, branch_cut=branch_cut, norm=norm))
  381. np.testing.assert_allclose(p_jac[2, 3], 0)
  382. np.testing.assert_allclose(p_jac[2, 4], 0)
  383. np.testing.assert_allclose(p_jac[2, -4], 0)
  384. np.testing.assert_allclose(p_jac[2, -3], 0)
  385. np.testing.assert_allclose(p_jac[2, -2],
  386. assoc_legendre_p_2_m2_jac(z, branch_cut=branch_cut, norm=norm))
  387. np.testing.assert_allclose(p_jac[2, -1],
  388. assoc_legendre_p_2_m1_jac(z, branch_cut=branch_cut, norm=norm))
  389. np.testing.assert_allclose(p_jac[3, 0],
  390. assoc_legendre_p_3_0_jac(z, branch_cut=branch_cut, norm=norm))
  391. np.testing.assert_allclose(p_jac[3, 1],
  392. assoc_legendre_p_3_1_jac(z, branch_cut=branch_cut, norm=norm))
  393. np.testing.assert_allclose(p_jac[3, 2],
  394. assoc_legendre_p_3_2_jac(z, branch_cut=branch_cut, norm=norm))
  395. np.testing.assert_allclose(p_jac[3, 3],
  396. assoc_legendre_p_3_3_jac(z, branch_cut=branch_cut, norm=norm))
  397. np.testing.assert_allclose(p_jac[3, 4], 0)
  398. np.testing.assert_allclose(p_jac[3, -4], 0)
  399. np.testing.assert_allclose(p_jac[3, -3],
  400. assoc_legendre_p_3_m3_jac(z, branch_cut=branch_cut, norm=norm))
  401. np.testing.assert_allclose(p_jac[3, -2],
  402. assoc_legendre_p_3_m2_jac(z, branch_cut=branch_cut, norm=norm))
  403. np.testing.assert_allclose(p_jac[3, -1],
  404. assoc_legendre_p_3_m1_jac(z, branch_cut=branch_cut, norm=norm))
  405. np.testing.assert_allclose(p_jac[4, 0],
  406. assoc_legendre_p_4_0_jac(z, branch_cut=branch_cut, norm=norm))
  407. np.testing.assert_allclose(p_jac[4, 1],
  408. assoc_legendre_p_4_1_jac(z, branch_cut=branch_cut, norm=norm))
  409. np.testing.assert_allclose(p_jac[4, 2],
  410. assoc_legendre_p_4_2_jac(z, branch_cut=branch_cut, norm=norm))
  411. np.testing.assert_allclose(p_jac[4, 3],
  412. assoc_legendre_p_4_3_jac(z, branch_cut=branch_cut, norm=norm))
  413. np.testing.assert_allclose(p_jac[4, 4],
  414. assoc_legendre_p_4_4_jac(z, branch_cut=branch_cut, norm=norm))
  415. np.testing.assert_allclose(p_jac[4, -4],
  416. assoc_legendre_p_4_m4_jac(z, branch_cut=branch_cut, norm=norm))
  417. np.testing.assert_allclose(p_jac[4, -3],
  418. assoc_legendre_p_4_m3_jac(z, branch_cut=branch_cut, norm=norm))
  419. np.testing.assert_allclose(p_jac[4, -2],
  420. assoc_legendre_p_4_m2_jac(z, branch_cut=branch_cut, norm=norm))
  421. np.testing.assert_allclose(p_jac[4, -1],
  422. assoc_legendre_p_4_m1_jac(z, branch_cut=branch_cut, norm=norm))
  423. class TestSphLegendreP:
  424. @pytest.mark.parametrize("shape", [(10,), (4, 9), (3, 5, 7)])
  425. def test_specific(self, shape):
  426. rng = np.random.default_rng(1234)
  427. theta = rng.uniform(-np.pi, np.pi, shape)
  428. p, p_jac = sph_legendre_p_all(4, 4, theta, diff_n=1)
  429. np.testing.assert_allclose(p[0, 0],
  430. sph_legendre_p_0_0(theta))
  431. np.testing.assert_allclose(p[0, 1], 0)
  432. np.testing.assert_allclose(p[0, 2], 0)
  433. np.testing.assert_allclose(p[0, 3], 0)
  434. np.testing.assert_allclose(p[0, 4], 0)
  435. np.testing.assert_allclose(p[0, -3], 0)
  436. np.testing.assert_allclose(p[0, -2], 0)
  437. np.testing.assert_allclose(p[0, -1], 0)
  438. np.testing.assert_allclose(p[1, 0],
  439. sph_legendre_p_1_0(theta))
  440. np.testing.assert_allclose(p[1, 1],
  441. sph_legendre_p_1_1(theta))
  442. np.testing.assert_allclose(p[1, 2], 0)
  443. np.testing.assert_allclose(p[1, 3], 0)
  444. np.testing.assert_allclose(p[1, 4], 0)
  445. np.testing.assert_allclose(p[1, -4], 0)
  446. np.testing.assert_allclose(p[1, -3], 0)
  447. np.testing.assert_allclose(p[1, -2], 0)
  448. np.testing.assert_allclose(p[1, -1],
  449. sph_legendre_p_1_m1(theta))
  450. np.testing.assert_allclose(p[2, 0],
  451. sph_legendre_p_2_0(theta))
  452. np.testing.assert_allclose(p[2, 1],
  453. sph_legendre_p_2_1(theta))
  454. np.testing.assert_allclose(p[2, 2],
  455. sph_legendre_p_2_2(theta))
  456. np.testing.assert_allclose(p[2, 3], 0)
  457. np.testing.assert_allclose(p[2, 4], 0)
  458. np.testing.assert_allclose(p[2, -4], 0)
  459. np.testing.assert_allclose(p[2, -3], 0)
  460. np.testing.assert_allclose(p[2, -2],
  461. sph_legendre_p_2_m2(theta))
  462. np.testing.assert_allclose(p[2, -1],
  463. sph_legendre_p_2_m1(theta))
  464. np.testing.assert_allclose(p[3, 0],
  465. sph_legendre_p_3_0(theta))
  466. np.testing.assert_allclose(p[3, 1],
  467. sph_legendre_p_3_1(theta))
  468. np.testing.assert_allclose(p[3, 2],
  469. sph_legendre_p_3_2(theta))
  470. np.testing.assert_allclose(p[3, 3],
  471. sph_legendre_p_3_3(theta))
  472. np.testing.assert_allclose(p[3, 4], 0)
  473. np.testing.assert_allclose(p[3, -4], 0)
  474. np.testing.assert_allclose(p[3, -3],
  475. sph_legendre_p_3_m3(theta))
  476. np.testing.assert_allclose(p[3, -2],
  477. sph_legendre_p_3_m2(theta))
  478. np.testing.assert_allclose(p[3, -1],
  479. sph_legendre_p_3_m1(theta))
  480. np.testing.assert_allclose(p[4, 0],
  481. sph_legendre_p_4_0(theta))
  482. np.testing.assert_allclose(p[4, 1],
  483. sph_legendre_p_4_1(theta))
  484. np.testing.assert_allclose(p[4, 2],
  485. sph_legendre_p_4_2(theta))
  486. np.testing.assert_allclose(p[4, 3],
  487. sph_legendre_p_4_3(theta))
  488. np.testing.assert_allclose(p[4, 4],
  489. sph_legendre_p_4_4(theta))
  490. np.testing.assert_allclose(p[4, -4],
  491. sph_legendre_p_4_m4(theta))
  492. np.testing.assert_allclose(p[4, -3],
  493. sph_legendre_p_4_m3(theta))
  494. np.testing.assert_allclose(p[4, -2],
  495. sph_legendre_p_4_m2(theta))
  496. np.testing.assert_allclose(p[4, -1],
  497. sph_legendre_p_4_m1(theta))
  498. np.testing.assert_allclose(p_jac[0, 0],
  499. sph_legendre_p_0_0_jac(theta))
  500. np.testing.assert_allclose(p_jac[0, 1], 0)
  501. np.testing.assert_allclose(p_jac[0, 2], 0)
  502. np.testing.assert_allclose(p_jac[0, 3], 0)
  503. np.testing.assert_allclose(p_jac[0, 4], 0)
  504. np.testing.assert_allclose(p_jac[0, -3], 0)
  505. np.testing.assert_allclose(p_jac[0, -2], 0)
  506. np.testing.assert_allclose(p_jac[0, -1], 0)
  507. np.testing.assert_allclose(p_jac[1, 0],
  508. sph_legendre_p_1_0_jac(theta))
  509. np.testing.assert_allclose(p_jac[1, 1],
  510. sph_legendre_p_1_1_jac(theta))
  511. np.testing.assert_allclose(p_jac[1, 2], 0)
  512. np.testing.assert_allclose(p_jac[1, 3], 0)
  513. np.testing.assert_allclose(p_jac[1, 4], 0)
  514. np.testing.assert_allclose(p_jac[1, -4], 0)
  515. np.testing.assert_allclose(p_jac[1, -3], 0)
  516. np.testing.assert_allclose(p_jac[1, -2], 0)
  517. np.testing.assert_allclose(p_jac[1, -1],
  518. sph_legendre_p_1_m1_jac(theta))
  519. np.testing.assert_allclose(p_jac[2, 0],
  520. sph_legendre_p_2_0_jac(theta))
  521. np.testing.assert_allclose(p_jac[2, 1],
  522. sph_legendre_p_2_1_jac(theta))
  523. np.testing.assert_allclose(p_jac[2, 2],
  524. sph_legendre_p_2_2_jac(theta))
  525. np.testing.assert_allclose(p_jac[2, 3], 0)
  526. np.testing.assert_allclose(p_jac[2, 4], 0)
  527. np.testing.assert_allclose(p_jac[2, -4], 0)
  528. np.testing.assert_allclose(p_jac[2, -3], 0)
  529. np.testing.assert_allclose(p_jac[2, -2],
  530. sph_legendre_p_2_m2_jac(theta))
  531. np.testing.assert_allclose(p_jac[2, -1],
  532. sph_legendre_p_2_m1_jac(theta))
  533. np.testing.assert_allclose(p_jac[3, 0],
  534. sph_legendre_p_3_0_jac(theta))
  535. np.testing.assert_allclose(p_jac[3, 1],
  536. sph_legendre_p_3_1_jac(theta))
  537. np.testing.assert_allclose(p_jac[3, 2],
  538. sph_legendre_p_3_2_jac(theta))
  539. np.testing.assert_allclose(p_jac[3, 3],
  540. sph_legendre_p_3_3_jac(theta))
  541. np.testing.assert_allclose(p_jac[3, 4], 0)
  542. np.testing.assert_allclose(p_jac[3, -4], 0)
  543. np.testing.assert_allclose(p_jac[3, -3],
  544. sph_legendre_p_3_m3_jac(theta))
  545. np.testing.assert_allclose(p_jac[3, -2],
  546. sph_legendre_p_3_m2_jac(theta))
  547. np.testing.assert_allclose(p_jac[3, -1],
  548. sph_legendre_p_3_m1_jac(theta))
  549. np.testing.assert_allclose(p_jac[4, 0],
  550. sph_legendre_p_4_0_jac(theta))
  551. np.testing.assert_allclose(p_jac[4, 1],
  552. sph_legendre_p_4_1_jac(theta))
  553. np.testing.assert_allclose(p_jac[4, 2],
  554. sph_legendre_p_4_2_jac(theta))
  555. np.testing.assert_allclose(p_jac[4, 3],
  556. sph_legendre_p_4_3_jac(theta))
  557. np.testing.assert_allclose(p_jac[4, 4],
  558. sph_legendre_p_4_4_jac(theta))
  559. np.testing.assert_allclose(p_jac[4, -4],
  560. sph_legendre_p_4_m4_jac(theta))
  561. np.testing.assert_allclose(p_jac[4, -3],
  562. sph_legendre_p_4_m3_jac(theta))
  563. np.testing.assert_allclose(p_jac[4, -2],
  564. sph_legendre_p_4_m2_jac(theta))
  565. np.testing.assert_allclose(p_jac[4, -1],
  566. sph_legendre_p_4_m1_jac(theta))
  567. @pytest.mark.parametrize("shape", [(10,), (4, 9), (3, 5, 7, 10)])
  568. def test_ode(self, shape):
  569. rng = np.random.default_rng(1234)
  570. n = rng.integers(0, 10, shape)
  571. m = rng.integers(-10, 10, shape)
  572. theta = rng.uniform(-np.pi, np.pi, shape)
  573. p, p_jac, p_hess = sph_legendre_p(n, m, theta, diff_n=2)
  574. assert p.shape == shape
  575. assert p_jac.shape == p.shape
  576. assert p_hess.shape == p_jac.shape
  577. np.testing.assert_allclose(np.sin(theta) * p_hess, -np.cos(theta) * p_jac
  578. - (n * (n + 1) * np.sin(theta) - m * m / np.sin(theta)) * p,
  579. rtol=1e-05, atol=1e-08)
  580. class TestLegendreFunctions:
  581. """
  582. @pytest.mark.parametrize("m_max", [3])
  583. @pytest.mark.parametrize("n_max", [5])
  584. @pytest.mark.parametrize("z", [-1])
  585. def test_clpmn_all_limits(self, m_max, n_max, z):
  586. rng = np.random.default_rng(1234)
  587. type = 2
  588. p, p_jac = special.clpmn_all(m_max, n_max, type, z, diff_n=1)
  589. n = np.arange(n_max + 1)
  590. np.testing.assert_allclose(p_jac[0], pow(z, n + 1) * n * (n + 1) / 2)
  591. np.testing.assert_allclose(p_jac[1], np.where(n >= 1, pow(z, n) * np.inf, 0))
  592. np.testing.assert_allclose(p_jac[2], np.where(n >= 2,
  593. -pow(z, n + 1) * (n + 2) * (n + 1) * n * (n - 1) / 4, 0))
  594. np.testing.assert_allclose(p_jac[-2], np.where(n >= 2, -pow(z, n + 1) / 4, 0))
  595. np.testing.assert_allclose(p_jac[-1], np.where(n >= 1, -pow(z, n) * np.inf, 0))
  596. for m in range(3, m_max + 1):
  597. np.testing.assert_allclose(p_jac[m], 0)
  598. np.testing.assert_allclose(p_jac[-m], 0)
  599. """
  600. def test_lpmv(self):
  601. lp = special.lpmv(0, 2, .5)
  602. assert_allclose(lp, -0.125, atol=1.5e-7, rtol=0)
  603. lp = special.lpmv(0, 40, .001)
  604. assert_allclose(lp, 0.1252678976534484, atol=1.5e-7, rtol=0)
  605. # XXX: this is outside the domain of the current implementation,
  606. # so ensure it returns a NaN rather than a wrong answer.
  607. with np.errstate(all='ignore'):
  608. lp = special.lpmv(-1,-1,.001)
  609. assert lp != 0 or np.isnan(lp)
  610. def test_lqmn(self):
  611. lqmnf = special.lqmn(0, 2, .5)
  612. lqf = special.lqn(2, .5)
  613. assert_allclose(lqmnf[0][0], lqf[0], atol=1.5e-4, rtol=0)
  614. assert_allclose(lqmnf[1][0], lqf[1], atol=1.5e-4, rtol=0)
  615. def test_lqmn_gt1(self):
  616. """algorithm for real arguments changes at 1.0001
  617. test against analytical result for m=2, n=1
  618. """
  619. x0 = 1.0001
  620. delta = 0.00002
  621. for x in (x0-delta, x0+delta):
  622. lq = special.lqmn(2, 1, x)[0][-1, -1]
  623. expected = 2/(x*x-1)
  624. assert_allclose(lq, expected, atol=1.5e-7, rtol=0)
  625. def test_lqmn_shape(self):
  626. a, b = special.lqmn(4, 4, 1.1)
  627. assert_equal(a.shape, (5, 5))
  628. assert_equal(b.shape, (5, 5))
  629. a, b = special.lqmn(4, 0, 1.1)
  630. assert_equal(a.shape, (5, 1))
  631. assert_equal(b.shape, (5, 1))
  632. def test_lqn(self):
  633. lqf = special.lqn(2, .5)
  634. assert_allclose(lqf, (np.array([0.5493, -0.7253, -0.8187]),
  635. np.array([1.3333, 1.216, -0.8427])),
  636. atol=1.5e-4, rtol=0)
  637. @pytest.mark.parametrize("function", [special.lqn])
  638. @pytest.mark.parametrize("n", [1, 2, 4, 8, 16, 32])
  639. @pytest.mark.parametrize("z_complex", [False, True])
  640. @pytest.mark.parametrize("z_inexact", [False, True])
  641. @pytest.mark.parametrize(
  642. "input_shape",
  643. [
  644. (), (1, ), (2, ), (2, 1), (1, 2), (2, 2), (2, 2, 1), (2, 2, 2)
  645. ]
  646. )
  647. def test_array_inputs_lxn(self, function, n, z_complex, z_inexact, input_shape):
  648. """Tests for correct output shapes."""
  649. rng = np.random.default_rng(1234)
  650. if z_inexact:
  651. z = rng.integers(-3, 3, size=input_shape)
  652. else:
  653. z = rng.uniform(-1, 1, size=input_shape)
  654. if z_complex:
  655. z = 1j * z + 0.5j * z
  656. with warnings.catch_warnings():
  657. warnings.simplefilter("ignore", category=DeprecationWarning)
  658. P_z, P_d_z = function(n, z)
  659. assert P_z.shape == (n + 1, ) + input_shape
  660. assert P_d_z.shape == (n + 1, ) + input_shape
  661. @pytest.mark.parametrize("function", [special.lqmn])
  662. @pytest.mark.parametrize(
  663. "m,n",
  664. [(0, 1), (1, 2), (1, 4), (3, 8), (11, 16), (19, 32)]
  665. )
  666. @pytest.mark.parametrize("z_inexact", [False, True])
  667. @pytest.mark.parametrize(
  668. "input_shape", [
  669. (), (1, ), (2, ), (2, 1), (1, 2), (2, 2), (2, 2, 1)
  670. ]
  671. )
  672. def test_array_inputs_lxmn(self, function, m, n, z_inexact, input_shape):
  673. """Tests for correct output shapes and dtypes."""
  674. rng = np.random.default_rng(1234)
  675. if z_inexact:
  676. z = rng.integers(-3, 3, size=input_shape)
  677. else:
  678. z = rng.uniform(-1, 1, size=input_shape)
  679. P_z, P_d_z = function(m, n, z)
  680. assert P_z.shape == (m + 1, n + 1) + input_shape
  681. assert P_d_z.shape == (m + 1, n + 1) + input_shape
  682. @pytest.mark.parametrize("function", [special.lqmn])
  683. @pytest.mark.parametrize(
  684. "m,n",
  685. [(0, 1), (1, 2), (1, 4), (3, 8), (11, 16), (19, 32)]
  686. )
  687. @pytest.mark.parametrize(
  688. "input_shape", [
  689. (), (1, ), (2, ), (2, 1), (1, 2), (2, 2), (2, 2, 1)
  690. ]
  691. )
  692. def test_array_inputs_clxmn(self, function, m, n, input_shape):
  693. """Tests for correct output shapes and dtypes."""
  694. rng = np.random.default_rng(1234)
  695. z = rng.uniform(-1, 1, size=input_shape)
  696. z = 1j * z + 0.5j * z
  697. with warnings.catch_warnings():
  698. warnings.simplefilter("ignore", category=DeprecationWarning)
  699. P_z, P_d_z = function(m, n, z)
  700. assert P_z.shape == (m + 1, n + 1) + input_shape
  701. assert P_d_z.shape == (m + 1, n + 1) + input_shape
  702. def assoc_legendre_factor(n, m, norm):
  703. if norm:
  704. return (math.sqrt((2 * n + 1) *
  705. math.factorial(n - m) / (2 * math.factorial(n + m))))
  706. return 1
  707. def assoc_legendre_p_0_0(z, *, branch_cut=2, norm=False):
  708. fac = assoc_legendre_factor(0, 0, norm)
  709. return np.full_like(z, fac)
  710. def assoc_legendre_p_1_0(z, *, branch_cut=2, norm=False):
  711. fac = assoc_legendre_factor(1, 0, norm)
  712. return fac * z
  713. def assoc_legendre_p_1_1(z, *, branch_cut=2, norm=False):
  714. branch_sign = np.where(branch_cut == 3, np.where(np.signbit(np.real(z)), 1, -1), -1)
  715. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  716. fac = assoc_legendre_factor(1, 1, norm)
  717. w = np.sqrt(np.where(branch_cut == 3, z * z - 1, 1 - z * z))
  718. return branch_cut_sign * branch_sign * fac * w
  719. def assoc_legendre_p_1_m1(z, *, branch_cut=2, norm=False):
  720. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  721. fac = assoc_legendre_factor(1, -1, norm)
  722. return (-branch_cut_sign * fac *
  723. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 2)
  724. def assoc_legendre_p_2_0(z, *, branch_cut=2, norm=False):
  725. fac = assoc_legendre_factor(2, 0, norm)
  726. return fac * (3 * z * z - 1) / 2
  727. def assoc_legendre_p_2_1(z, *, branch_cut=2, norm=False):
  728. fac = assoc_legendre_factor(2, 1, norm)
  729. return (3 * fac * z *
  730. assoc_legendre_p_1_1(z, branch_cut=branch_cut))
  731. def assoc_legendre_p_2_2(z, *, branch_cut=2, norm=False):
  732. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  733. fac = assoc_legendre_factor(2, 2, norm)
  734. return 3 * branch_cut_sign * fac * (1 - z * z)
  735. def assoc_legendre_p_2_m2(z, *, branch_cut=2, norm=False):
  736. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  737. fac = assoc_legendre_factor(2, -2, norm)
  738. return branch_cut_sign * fac * (1 - z * z) / 8
  739. def assoc_legendre_p_2_m1(z, *, branch_cut=2, norm=False):
  740. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  741. fac = assoc_legendre_factor(2, -1, norm)
  742. return (-branch_cut_sign * fac * z *
  743. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 2)
  744. def assoc_legendre_p_3_0(z, *, branch_cut=2, norm=False):
  745. fac = assoc_legendre_factor(3, 0, norm)
  746. return fac * (5 * z * z - 3) * z / 2
  747. def assoc_legendre_p_3_1(z, *, branch_cut=2, norm=False):
  748. fac = assoc_legendre_factor(3, 1, norm)
  749. return (3 * fac * (5 * z * z - 1) *
  750. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 2)
  751. def assoc_legendre_p_3_2(z, *, branch_cut=2, norm=False):
  752. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  753. fac = assoc_legendre_factor(3, 2, norm)
  754. return 15 * branch_cut_sign * fac * (1 - z * z) * z
  755. def assoc_legendre_p_3_3(z, *, branch_cut=2, norm=False):
  756. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  757. fac = assoc_legendre_factor(3, 3, norm)
  758. return (15 * branch_cut_sign * fac * (1 - z * z) *
  759. assoc_legendre_p_1_1(z, branch_cut=branch_cut))
  760. def assoc_legendre_p_3_m3(z, *, branch_cut=2, norm=False):
  761. fac = assoc_legendre_factor(3, -3, norm)
  762. return (fac * (z * z - 1) *
  763. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 48)
  764. def assoc_legendre_p_3_m2(z, *, branch_cut=2, norm=False):
  765. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  766. fac = assoc_legendre_factor(3, -2, norm)
  767. return branch_cut_sign * fac * (1 - z * z) * z / 8
  768. def assoc_legendre_p_3_m1(z, *, branch_cut=2, norm=False):
  769. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  770. fac = assoc_legendre_factor(3, -1, norm)
  771. return (branch_cut_sign * fac * (1 - 5 * z * z) *
  772. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 8)
  773. def assoc_legendre_p_4_0(z, *, branch_cut=2, norm=False):
  774. fac = assoc_legendre_factor(4, 0, norm)
  775. return fac * ((35 * z * z - 30) * z * z + 3) / 8
  776. def assoc_legendre_p_4_1(z, *, branch_cut=2, norm=False):
  777. fac = assoc_legendre_factor(4, 1, norm)
  778. return (5 * fac * (7 * z * z - 3) * z *
  779. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 2)
  780. def assoc_legendre_p_4_2(z, *, branch_cut=2, norm=False):
  781. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  782. fac = assoc_legendre_factor(4, 2, norm)
  783. return 15 * branch_cut_sign * fac * ((8 - 7 * z * z) * z * z - 1) / 2
  784. def assoc_legendre_p_4_3(z, *, branch_cut=2, norm=False):
  785. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  786. fac = assoc_legendre_factor(4, 3, norm)
  787. return (105 * branch_cut_sign * fac * (1 - z * z) * z *
  788. assoc_legendre_p_1_1(z, branch_cut=branch_cut))
  789. def assoc_legendre_p_4_4(z, *, branch_cut=2, norm=False):
  790. fac = assoc_legendre_factor(4, 4, norm)
  791. return 105 * fac * np.square(z * z - 1)
  792. def assoc_legendre_p_4_m4(z, *, branch_cut=2, norm=False):
  793. fac = assoc_legendre_factor(4, -4, norm)
  794. return fac * np.square(z * z - 1) / 384
  795. def assoc_legendre_p_4_m3(z, *, branch_cut=2, norm=False):
  796. fac = assoc_legendre_factor(4, -3, norm)
  797. return (fac * (z * z - 1) * z *
  798. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 48)
  799. def assoc_legendre_p_4_m2(z, *, branch_cut=2, norm=False):
  800. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  801. fac = assoc_legendre_factor(4, -2, norm)
  802. return branch_cut_sign * fac * ((8 - 7 * z * z) * z * z - 1) / 48
  803. def assoc_legendre_p_4_m1(z, *, branch_cut=2, norm=False):
  804. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  805. fac = assoc_legendre_factor(4, -1, norm)
  806. return (branch_cut_sign * fac * (3 - 7 * z * z) * z *
  807. assoc_legendre_p_1_1(z, branch_cut=branch_cut) / 8)
  808. def assoc_legendre_p_1_1_jac_div_z(z, branch_cut=2):
  809. branch_sign = np.where(branch_cut == 3, np.where(np.signbit(np.real(z)), 1, -1), -1)
  810. out11_div_z = (-branch_sign /
  811. np.sqrt(np.where(branch_cut == 3, z * z - 1, 1 - z * z)))
  812. return out11_div_z
  813. def assoc_legendre_p_0_0_jac(z, *, branch_cut=2, norm=False):
  814. return np.zeros_like(z)
  815. def assoc_legendre_p_1_0_jac(z, *, branch_cut=2, norm=False):
  816. fac = assoc_legendre_factor(1, 0, norm)
  817. return np.full_like(z, fac)
  818. def assoc_legendre_p_1_1_jac(z, *, branch_cut=2, norm=False):
  819. fac = assoc_legendre_factor(1, 1, norm)
  820. return (fac * z *
  821. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut))
  822. def assoc_legendre_p_1_m1_jac(z, *, branch_cut=2, norm=False):
  823. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  824. fac = assoc_legendre_factor(1, -1, norm)
  825. return (-branch_cut_sign * fac * z *
  826. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 2)
  827. def assoc_legendre_p_2_0_jac(z, *, branch_cut=2, norm=False):
  828. fac = assoc_legendre_factor(2, 0, norm)
  829. return 3 * fac * z
  830. def assoc_legendre_p_2_1_jac(z, *, branch_cut=2, norm=False):
  831. fac = assoc_legendre_factor(2, 1, norm)
  832. return (3 * fac * (2 * z * z - 1) *
  833. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut))
  834. def assoc_legendre_p_2_2_jac(z, *, branch_cut=2, norm=False):
  835. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  836. fac = assoc_legendre_factor(2, 2, norm)
  837. return -6 * branch_cut_sign * fac * z
  838. def assoc_legendre_p_2_m1_jac(z, *, branch_cut=2, norm=False):
  839. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  840. fac = assoc_legendre_factor(2, -1, norm)
  841. return (branch_cut_sign * fac * (1 - 2 * z * z) *
  842. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 2)
  843. def assoc_legendre_p_2_m2_jac(z, *, branch_cut=2, norm=False):
  844. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  845. fac = assoc_legendre_factor(2, -2, norm)
  846. return -branch_cut_sign * fac * z / 4
  847. def assoc_legendre_p_3_0_jac(z, *, branch_cut=2, norm=False):
  848. fac = assoc_legendre_factor(3, 0, norm)
  849. return 3 * fac * (5 * z * z - 1) / 2
  850. def assoc_legendre_p_3_1_jac(z, *, branch_cut=2, norm=False):
  851. fac = assoc_legendre_factor(3, 1, norm)
  852. return (3 * fac * (15 * z * z - 11) * z *
  853. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 2)
  854. def assoc_legendre_p_3_2_jac(z, *, branch_cut=2, norm=False):
  855. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  856. fac = assoc_legendre_factor(3, 2, norm)
  857. return 15 * branch_cut_sign * fac * (1 - 3 * z * z)
  858. def assoc_legendre_p_3_3_jac(z, *, branch_cut=2, norm=False):
  859. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  860. fac = assoc_legendre_factor(3, 3, norm)
  861. return (45 * branch_cut_sign * fac * (1 - z * z) * z *
  862. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut))
  863. def assoc_legendre_p_3_m3_jac(z, *, branch_cut=2, norm=False):
  864. fac = assoc_legendre_factor(3, -3, norm)
  865. return (fac * (z * z - 1) * z *
  866. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 16)
  867. def assoc_legendre_p_3_m2_jac(z, *, branch_cut=2, norm=False):
  868. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  869. fac = assoc_legendre_factor(3, -2, norm)
  870. return branch_cut_sign * fac * (1 - 3 * z * z) / 8
  871. def assoc_legendre_p_3_m1_jac(z, *, branch_cut=2, norm=False):
  872. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  873. fac = assoc_legendre_factor(3, -1, norm)
  874. return (branch_cut_sign * fac * (11 - 15 * z * z) * z *
  875. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 8)
  876. def assoc_legendre_p_4_0_jac(z, *, branch_cut=2, norm=False):
  877. fac = assoc_legendre_factor(4, 0, norm)
  878. return 5 * fac * (7 * z * z - 3) * z / 2
  879. def assoc_legendre_p_4_1_jac(z, *, branch_cut=2, norm=False):
  880. fac = assoc_legendre_factor(4, 1, norm)
  881. return (5 * fac * ((28 * z * z - 27) * z * z + 3) *
  882. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 2)
  883. def assoc_legendre_p_4_2_jac(z, *, branch_cut=2, norm=False):
  884. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  885. fac = assoc_legendre_factor(4, 2, norm)
  886. return 30 * branch_cut_sign * fac * (4 - 7 * z * z) * z
  887. def assoc_legendre_p_4_3_jac(z, *, branch_cut=2, norm=False):
  888. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  889. fac = assoc_legendre_factor(4, 3, norm)
  890. return (105 * branch_cut_sign * fac * ((5 - 4 * z * z) * z * z - 1) *
  891. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut))
  892. def assoc_legendre_p_4_4_jac(z, *, branch_cut=2, norm=False):
  893. fac = assoc_legendre_factor(4, 4, norm)
  894. return 420 * fac * (z * z - 1) * z
  895. def assoc_legendre_p_4_m4_jac(z, *, branch_cut=2, norm=False):
  896. fac = assoc_legendre_factor(4, -4, norm)
  897. return fac * (z * z - 1) * z / 96
  898. def assoc_legendre_p_4_m3_jac(z, *, branch_cut=2, norm=False):
  899. fac = assoc_legendre_factor(4, -3, norm)
  900. return (fac * ((4 * z * z - 5) * z * z + 1) *
  901. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 48)
  902. def assoc_legendre_p_4_m2_jac(z, *, branch_cut=2, norm=False):
  903. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  904. fac = assoc_legendre_factor(4, -2, norm)
  905. return branch_cut_sign * fac * (4 - 7 * z * z) * z / 12
  906. def assoc_legendre_p_4_m1_jac(z, *, branch_cut=2, norm=False):
  907. branch_cut_sign = np.where(branch_cut == 3, -1, 1)
  908. fac = assoc_legendre_factor(4, -1, norm)
  909. return (branch_cut_sign * fac * ((27 - 28 * z * z) * z * z - 3) *
  910. assoc_legendre_p_1_1_jac_div_z(z, branch_cut=branch_cut) / 8)
  911. def sph_legendre_factor(n, m):
  912. return assoc_legendre_factor(n, m, norm=True) / np.sqrt(2 * np.pi)
  913. def sph_legendre_p_0_0(theta):
  914. fac = sph_legendre_factor(0, 0)
  915. return np.full_like(theta, fac)
  916. def sph_legendre_p_1_0(theta):
  917. fac = sph_legendre_factor(1, 0)
  918. return fac * np.cos(theta)
  919. def sph_legendre_p_1_1(theta):
  920. fac = sph_legendre_factor(1, 1)
  921. return -fac * np.abs(np.sin(theta))
  922. def sph_legendre_p_1_m1(theta):
  923. fac = sph_legendre_factor(1, -1)
  924. return fac * np.abs(np.sin(theta)) / 2
  925. def sph_legendre_p_2_0(theta):
  926. fac = sph_legendre_factor(2, 0)
  927. return fac * (3 * np.square(np.cos(theta)) - 1) / 2
  928. def sph_legendre_p_2_1(theta):
  929. fac = sph_legendre_factor(2, 1)
  930. return -3 * fac * np.abs(np.sin(theta)) * np.cos(theta)
  931. def sph_legendre_p_2_2(theta):
  932. fac = sph_legendre_factor(2, 2)
  933. return 3 * fac * (1 - np.square(np.cos(theta)))
  934. def sph_legendre_p_2_m2(theta):
  935. fac = sph_legendre_factor(2, -2)
  936. return fac * (1 - np.square(np.cos(theta))) / 8
  937. def sph_legendre_p_2_m1(theta):
  938. fac = sph_legendre_factor(2, -1)
  939. return fac * np.cos(theta) * np.abs(np.sin(theta)) / 2
  940. def sph_legendre_p_3_0(theta):
  941. fac = sph_legendre_factor(3, 0)
  942. return (fac * (5 * np.square(np.cos(theta)) - 3) *
  943. np.cos(theta) / 2)
  944. def sph_legendre_p_3_1(theta):
  945. fac = sph_legendre_factor(3, 1)
  946. return (-3 * fac * (5 * np.square(np.cos(theta)) - 1) *
  947. np.abs(np.sin(theta)) / 2)
  948. def sph_legendre_p_3_2(theta):
  949. fac = sph_legendre_factor(3, 2)
  950. return (-15 * fac * (np.square(np.cos(theta)) - 1) *
  951. np.cos(theta))
  952. def sph_legendre_p_3_3(theta):
  953. fac = sph_legendre_factor(3, 3)
  954. return -15 * fac * np.power(np.abs(np.sin(theta)), 3)
  955. def sph_legendre_p_3_m3(theta):
  956. fac = sph_legendre_factor(3, -3)
  957. return fac * np.power(np.abs(np.sin(theta)), 3) / 48
  958. def sph_legendre_p_3_m2(theta):
  959. fac = sph_legendre_factor(3, -2)
  960. return (-fac * (np.square(np.cos(theta)) - 1) *
  961. np.cos(theta) / 8)
  962. def sph_legendre_p_3_m1(theta):
  963. fac = sph_legendre_factor(3, -1)
  964. return (fac * (5 * np.square(np.cos(theta)) - 1) *
  965. np.abs(np.sin(theta)) / 8)
  966. def sph_legendre_p_4_0(theta):
  967. fac = sph_legendre_factor(4, 0)
  968. return (fac * (35 * np.square(np.square(np.cos(theta))) -
  969. 30 * np.square(np.cos(theta)) + 3) / 8)
  970. def sph_legendre_p_4_1(theta):
  971. fac = sph_legendre_factor(4, 1)
  972. return (-5 * fac * (7 * np.square(np.cos(theta)) - 3) *
  973. np.cos(theta) * np.abs(np.sin(theta)) / 2)
  974. def sph_legendre_p_4_2(theta):
  975. fac = sph_legendre_factor(4, 2)
  976. return (-15 * fac * (7 * np.square(np.cos(theta)) - 1) *
  977. (np.square(np.cos(theta)) - 1) / 2)
  978. def sph_legendre_p_4_3(theta):
  979. fac = sph_legendre_factor(4, 3)
  980. return -105 * fac * np.power(np.abs(np.sin(theta)), 3) * np.cos(theta)
  981. def sph_legendre_p_4_4(theta):
  982. fac = sph_legendre_factor(4, 4)
  983. return 105 * fac * np.square(np.square(np.cos(theta)) - 1)
  984. def sph_legendre_p_4_m4(theta):
  985. fac = sph_legendre_factor(4, -4)
  986. return fac * np.square(np.square(np.cos(theta)) - 1) / 384
  987. def sph_legendre_p_4_m3(theta):
  988. fac = sph_legendre_factor(4, -3)
  989. return (fac * np.power(np.abs(np.sin(theta)), 3) *
  990. np.cos(theta) / 48)
  991. def sph_legendre_p_4_m2(theta):
  992. fac = sph_legendre_factor(4, -2)
  993. return (-fac * (7 * np.square(np.cos(theta)) - 1) *
  994. (np.square(np.cos(theta)) - 1) / 48)
  995. def sph_legendre_p_4_m1(theta):
  996. fac = sph_legendre_factor(4, -1)
  997. return (fac * (7 * np.square(np.cos(theta)) - 3) *
  998. np.cos(theta) * np.abs(np.sin(theta)) / 8)
  999. def sph_legendre_p_0_0_jac(theta):
  1000. return np.zeros_like(theta)
  1001. def sph_legendre_p_1_0_jac(theta):
  1002. fac = sph_legendre_factor(1, 0)
  1003. return -fac * np.sin(theta)
  1004. def sph_legendre_p_1_1_jac(theta):
  1005. fac = sph_legendre_factor(1, 1)
  1006. return -fac * np.cos(theta) * (2 * np.heaviside(np.sin(theta), 1) - 1)
  1007. def sph_legendre_p_1_m1_jac(theta):
  1008. fac = sph_legendre_factor(1, -1)
  1009. return fac * np.cos(theta) * (2 * np.heaviside(np.sin(theta), 1) - 1) / 2
  1010. def sph_legendre_p_2_0_jac(theta):
  1011. fac = sph_legendre_factor(2, 0)
  1012. return -3 * fac * np.cos(theta) * np.sin(theta)
  1013. def sph_legendre_p_2_1_jac(theta):
  1014. fac = sph_legendre_factor(2, 1)
  1015. return (3 * fac * (-np.square(np.cos(theta)) *
  1016. (2 * np.heaviside(np.sin(theta), 1) - 1) +
  1017. np.abs(np.sin(theta)) * np.sin(theta)))
  1018. def sph_legendre_p_2_2_jac(theta):
  1019. fac = sph_legendre_factor(2, 2)
  1020. return 6 * fac * np.sin(theta) * np.cos(theta)
  1021. def sph_legendre_p_2_m2_jac(theta):
  1022. fac = sph_legendre_factor(2, -2)
  1023. return fac * np.sin(theta) * np.cos(theta) / 4
  1024. def sph_legendre_p_2_m1_jac(theta):
  1025. fac = sph_legendre_factor(2, -1)
  1026. return (-fac * (-np.square(np.cos(theta)) *
  1027. (2 * np.heaviside(np.sin(theta), 1) - 1) +
  1028. np.abs(np.sin(theta)) * np.sin(theta)) / 2)
  1029. def sph_legendre_p_3_0_jac(theta):
  1030. fac = sph_legendre_factor(3, 0)
  1031. return 3 * fac * (1 - 5 * np.square(np.cos(theta))) * np.sin(theta) / 2
  1032. def sph_legendre_p_3_1_jac(theta):
  1033. fac = sph_legendre_factor(3, 1)
  1034. return (3 * fac * (11 - 15 * np.square(np.cos(theta))) * np.cos(theta) *
  1035. (2 * np.heaviside(np.sin(theta), 1) - 1) / 2)
  1036. def sph_legendre_p_3_2_jac(theta):
  1037. fac = sph_legendre_factor(3, 2)
  1038. return 15 * fac * (3 * np.square(np.cos(theta)) - 1) * np.sin(theta)
  1039. def sph_legendre_p_3_3_jac(theta):
  1040. fac = sph_legendre_factor(3, 3)
  1041. return -45 * fac * np.abs(np.sin(theta)) * np.sin(theta) * np.cos(theta)
  1042. def sph_legendre_p_3_m3_jac(theta):
  1043. fac = sph_legendre_factor(3, -3)
  1044. return fac * np.abs(np.sin(theta)) * np.sin(theta) * np.cos(theta) / 16
  1045. def sph_legendre_p_3_m2_jac(theta):
  1046. fac = sph_legendre_factor(3, -2)
  1047. return fac * (3 * np.square(np.cos(theta)) - 1) * np.sin(theta) / 8
  1048. def sph_legendre_p_3_m1_jac(theta):
  1049. fac = sph_legendre_factor(3, -1)
  1050. return (-fac * (11 - 15 * np.square(np.cos(theta))) *
  1051. np.cos(theta) *
  1052. (2 * np.heaviside(np.sin(theta), 1) - 1) / 8)
  1053. def sph_legendre_p_4_0_jac(theta):
  1054. fac = sph_legendre_factor(4, 0)
  1055. return (-5 * fac * (7 * np.square(np.cos(theta)) - 3) *
  1056. np.sin(theta) * np.cos(theta) / 2)
  1057. def sph_legendre_p_4_1_jac(theta):
  1058. fac = sph_legendre_factor(4, 1)
  1059. return (5 * fac * (-3 + 27 * np.square(np.cos(theta)) -
  1060. 28 * np.square(np.square(np.cos(theta)))) *
  1061. (2 * np.heaviside(np.sin(theta), 1) - 1) / 2)
  1062. def sph_legendre_p_4_2_jac(theta):
  1063. fac = sph_legendre_factor(4, 2)
  1064. return (30 * fac * (7 * np.square(np.cos(theta)) - 4) *
  1065. np.sin(theta) * np.cos(theta))
  1066. def sph_legendre_p_4_3_jac(theta):
  1067. fac = sph_legendre_factor(4, 3)
  1068. return (-105 * fac * (4 * np.square(np.cos(theta)) - 1) *
  1069. np.abs(np.sin(theta)) * np.sin(theta))
  1070. def sph_legendre_p_4_4_jac(theta):
  1071. fac = sph_legendre_factor(4, 4)
  1072. return (-420 * fac * (np.square(np.cos(theta)) - 1) *
  1073. np.sin(theta) * np.cos(theta))
  1074. def sph_legendre_p_4_m4_jac(theta):
  1075. fac = sph_legendre_factor(4, -4)
  1076. return (-fac * (np.square(np.cos(theta)) - 1) *
  1077. np.sin(theta) * np.cos(theta) / 96)
  1078. def sph_legendre_p_4_m3_jac(theta):
  1079. fac = sph_legendre_factor(4, -3)
  1080. return (fac * (4 * np.square(np.cos(theta)) - 1) *
  1081. np.abs(np.sin(theta)) * np.sin(theta) / 48)
  1082. def sph_legendre_p_4_m2_jac(theta):
  1083. fac = sph_legendre_factor(4, -2)
  1084. return (fac * (7 * np.square(np.cos(theta)) - 4) * np.sin(theta) *
  1085. np.cos(theta) / 12)
  1086. def sph_legendre_p_4_m1_jac(theta):
  1087. fac = sph_legendre_factor(4, -1)
  1088. return (-fac * (-3 + 27 * np.square(np.cos(theta)) -
  1089. 28 * np.square(np.square(np.cos(theta)))) *
  1090. (2 * np.heaviside(np.sin(theta), 1) - 1) / 8)