pygeodesy 24.3.24__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- PyGeodesy-24.3.24.dist-info/METADATA +272 -0
- PyGeodesy-24.3.24.dist-info/RECORD +115 -0
- PyGeodesy-24.3.24.dist-info/WHEEL +6 -0
- PyGeodesy-24.3.24.dist-info/top_level.txt +1 -0
- pygeodesy/LICENSE +21 -0
- pygeodesy/__init__.py +615 -0
- pygeodesy/__main__.py +103 -0
- pygeodesy/albers.py +867 -0
- pygeodesy/auxilats/_CX_4.py +218 -0
- pygeodesy/auxilats/_CX_6.py +314 -0
- pygeodesy/auxilats/_CX_8.py +475 -0
- pygeodesy/auxilats/__init__.py +54 -0
- pygeodesy/auxilats/__main__.py +86 -0
- pygeodesy/auxilats/auxAngle.py +548 -0
- pygeodesy/auxilats/auxDLat.py +302 -0
- pygeodesy/auxilats/auxDST.py +296 -0
- pygeodesy/auxilats/auxLat.py +848 -0
- pygeodesy/auxilats/auxily.py +272 -0
- pygeodesy/azimuthal.py +1150 -0
- pygeodesy/basics.py +892 -0
- pygeodesy/booleans.py +2031 -0
- pygeodesy/cartesianBase.py +1062 -0
- pygeodesy/clipy.py +704 -0
- pygeodesy/constants.py +516 -0
- pygeodesy/css.py +660 -0
- pygeodesy/datums.py +752 -0
- pygeodesy/deprecated/__init__.py +61 -0
- pygeodesy/deprecated/bases.py +40 -0
- pygeodesy/deprecated/classes.py +262 -0
- pygeodesy/deprecated/consterns.py +54 -0
- pygeodesy/deprecated/datum.py +40 -0
- pygeodesy/deprecated/functions.py +375 -0
- pygeodesy/deprecated/nvector.py +48 -0
- pygeodesy/deprecated/rhumbBase.py +32 -0
- pygeodesy/deprecated/rhumbaux.py +33 -0
- pygeodesy/deprecated/rhumbsolve.py +33 -0
- pygeodesy/deprecated/rhumbx.py +33 -0
- pygeodesy/dms.py +986 -0
- pygeodesy/ecef.py +1348 -0
- pygeodesy/elevations.py +279 -0
- pygeodesy/ellipsoidalBase.py +1224 -0
- pygeodesy/ellipsoidalBaseDI.py +913 -0
- pygeodesy/ellipsoidalExact.py +343 -0
- pygeodesy/ellipsoidalGeodSolve.py +343 -0
- pygeodesy/ellipsoidalKarney.py +403 -0
- pygeodesy/ellipsoidalNvector.py +685 -0
- pygeodesy/ellipsoidalVincenty.py +590 -0
- pygeodesy/ellipsoids.py +2476 -0
- pygeodesy/elliptic.py +1198 -0
- pygeodesy/epsg.py +243 -0
- pygeodesy/errors.py +804 -0
- pygeodesy/etm.py +1190 -0
- pygeodesy/fmath.py +1013 -0
- pygeodesy/formy.py +1818 -0
- pygeodesy/frechet.py +865 -0
- pygeodesy/fstats.py +760 -0
- pygeodesy/fsums.py +1898 -0
- pygeodesy/gars.py +358 -0
- pygeodesy/geodesicw.py +581 -0
- pygeodesy/geodesicx/_C4_24.py +1699 -0
- pygeodesy/geodesicx/_C4_27.py +2395 -0
- pygeodesy/geodesicx/_C4_30.py +3301 -0
- pygeodesy/geodesicx/__init__.py +48 -0
- pygeodesy/geodesicx/__main__.py +91 -0
- pygeodesy/geodesicx/gx.py +1382 -0
- pygeodesy/geodesicx/gxarea.py +535 -0
- pygeodesy/geodesicx/gxbases.py +154 -0
- pygeodesy/geodesicx/gxline.py +669 -0
- pygeodesy/geodsolve.py +426 -0
- pygeodesy/geohash.py +914 -0
- pygeodesy/geoids.py +1884 -0
- pygeodesy/hausdorff.py +892 -0
- pygeodesy/heights.py +1155 -0
- pygeodesy/interns.py +687 -0
- pygeodesy/iters.py +545 -0
- pygeodesy/karney.py +919 -0
- pygeodesy/ktm.py +633 -0
- pygeodesy/latlonBase.py +1766 -0
- pygeodesy/lazily.py +960 -0
- pygeodesy/lcc.py +684 -0
- pygeodesy/ltp.py +1107 -0
- pygeodesy/ltpTuples.py +1563 -0
- pygeodesy/mgrs.py +721 -0
- pygeodesy/named.py +1324 -0
- pygeodesy/namedTuples.py +683 -0
- pygeodesy/nvectorBase.py +695 -0
- pygeodesy/osgr.py +781 -0
- pygeodesy/points.py +1686 -0
- pygeodesy/props.py +628 -0
- pygeodesy/resections.py +1048 -0
- pygeodesy/rhumb/__init__.py +46 -0
- pygeodesy/rhumb/aux_.py +397 -0
- pygeodesy/rhumb/bases.py +1148 -0
- pygeodesy/rhumb/ekx.py +563 -0
- pygeodesy/rhumb/solve.py +572 -0
- pygeodesy/simplify.py +647 -0
- pygeodesy/solveBase.py +472 -0
- pygeodesy/sphericalBase.py +724 -0
- pygeodesy/sphericalNvector.py +1264 -0
- pygeodesy/sphericalTrigonometry.py +1447 -0
- pygeodesy/streprs.py +627 -0
- pygeodesy/trf.py +2079 -0
- pygeodesy/triaxials.py +1484 -0
- pygeodesy/units.py +969 -0
- pygeodesy/unitsBase.py +349 -0
- pygeodesy/ups.py +538 -0
- pygeodesy/utily.py +1231 -0
- pygeodesy/utm.py +762 -0
- pygeodesy/utmups.py +318 -0
- pygeodesy/utmupsBase.py +517 -0
- pygeodesy/vector2d.py +785 -0
- pygeodesy/vector3d.py +968 -0
- pygeodesy/vector3dBase.py +1049 -0
- pygeodesy/webmercator.py +383 -0
- pygeodesy/wgrs.py +439 -0
pygeodesy/elliptic.py
ADDED
|
@@ -0,0 +1,1198 @@
|
|
|
1
|
+
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
u'''I{Karney}'s elliptic functions and integrals.
|
|
5
|
+
|
|
6
|
+
Class L{Elliptic} transcoded from I{Charles Karney}'s C++ class U{EllipticFunction
|
|
7
|
+
<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1EllipticFunction.html>}
|
|
8
|
+
to pure Python, including symmetric integrals L{Elliptic.fRC}, L{Elliptic.fRD},
|
|
9
|
+
L{Elliptic.fRF}, L{Elliptic.fRG} and L{Elliptic.fRJ} as C{static methods}.
|
|
10
|
+
|
|
11
|
+
Python method names follow the C++ member functions, I{except}:
|
|
12
|
+
|
|
13
|
+
- member functions I{without arguments} are mapped to Python properties
|
|
14
|
+
prefixed with C{"c"}, for example C{E()} is property C{cE},
|
|
15
|
+
|
|
16
|
+
- member functions with 1 or 3 arguments are renamed to Python methods
|
|
17
|
+
starting with an C{"f"}, example C{E(psi)} to C{fE(psi)} and C{E(sn,
|
|
18
|
+
cn, dn)} to C{fE(sn, cn, dn)},
|
|
19
|
+
|
|
20
|
+
- other Python method names conventionally start with a lower-case
|
|
21
|
+
letter or an underscore if private.
|
|
22
|
+
|
|
23
|
+
Following is a copy of I{Karney}'s U{EllipticFunction.hpp
|
|
24
|
+
<https://GeographicLib.SourceForge.io/C++/doc/EllipticFunction_8hpp_source.html>}
|
|
25
|
+
file C{Header}.
|
|
26
|
+
|
|
27
|
+
Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2008-2023)
|
|
28
|
+
and licensed under the MIT/X11 License. For more information, see the
|
|
29
|
+
U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
|
|
30
|
+
|
|
31
|
+
B{Elliptic integrals and functions.}
|
|
32
|
+
|
|
33
|
+
This provides the elliptic functions and integrals needed for
|
|
34
|
+
C{Ellipsoid}, C{GeodesicExact}, and C{TransverseMercatorExact}. Two
|
|
35
|
+
categories of function are provided:
|
|
36
|
+
|
|
37
|
+
- functions to compute U{symmetric elliptic integrals
|
|
38
|
+
<https://DLMF.NIST.gov/19.16.i>}
|
|
39
|
+
|
|
40
|
+
- methods to compute U{Legrendre's elliptic integrals
|
|
41
|
+
<https://DLMF.NIST.gov/19.2.ii>} and U{Jacobi elliptic
|
|
42
|
+
functions<https://DLMF.NIST.gov/22.2>}.
|
|
43
|
+
|
|
44
|
+
In the latter case, an object is constructed giving the modulus
|
|
45
|
+
C{k} (and optionally the parameter C{alpha}). The modulus (and
|
|
46
|
+
parameter) are always passed as squares which allows C{k} to be
|
|
47
|
+
pure imaginary. (Confusingly, Abramowitz and Stegun call C{m = k**2}
|
|
48
|
+
the "parameter" and C{n = alpha**2} the "characteristic".)
|
|
49
|
+
|
|
50
|
+
In geodesic applications, it is convenient to separate the incomplete
|
|
51
|
+
integrals into secular and periodic components, e.g.
|
|
52
|
+
|
|
53
|
+
I{C{E(phi, k) = (2 E(k) / pi) [ phi + delta E(phi, k) ]}}
|
|
54
|
+
|
|
55
|
+
where I{C{delta E(phi, k)}} is an odd periodic function with
|
|
56
|
+
period I{C{pi}}.
|
|
57
|
+
|
|
58
|
+
The computation of the elliptic integrals uses the algorithms given
|
|
59
|
+
in U{B. C. Carlson, Computation of real or complex elliptic integrals
|
|
60
|
+
<https://DOI.org/10.1007/BF02198293>} (also available U{here
|
|
61
|
+
<https://ArXiv.org/pdf/math/9409227.pdf>}), Numerical Algorithms 10,
|
|
62
|
+
13--26 (1995) with the additional optimizations given U{here
|
|
63
|
+
<https://DLMF.NIST.gov/19.36.i>}.
|
|
64
|
+
|
|
65
|
+
The computation of the Jacobi elliptic functions uses the algorithm
|
|
66
|
+
given in U{R. Bulirsch, Numerical Calculation of Elliptic Integrals
|
|
67
|
+
and Elliptic Functions<https://DOI.org/10.1007/BF01397975>},
|
|
68
|
+
Numerische Mathematik 7, 78--90 (1965).
|
|
69
|
+
|
|
70
|
+
The notation follows U{NIST Digital Library of Mathematical Functions
|
|
71
|
+
<https://DLMF.NIST.gov>} chapters U{19<https://DLMF.NIST.gov/19>} and
|
|
72
|
+
U{22<https://DLMF.NIST.gov/22>}.
|
|
73
|
+
'''
|
|
74
|
+
# make sure int/int division yields float quotient, see .basics
|
|
75
|
+
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
76
|
+
|
|
77
|
+
from pygeodesy.basics import copysign0, map2, neg, neg_
|
|
78
|
+
from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, \
|
|
79
|
+
_EPStol as _TolJAC, _0_0, _1_64th, \
|
|
80
|
+
_0_25, _0_5, _1_0, _2_0, _N_2_0, \
|
|
81
|
+
_3_0, _4_0, _6_0, _8_0, _180_0, \
|
|
82
|
+
_360_0, _over
|
|
83
|
+
# from pygeodesy.errors import _ValueError # from .fmath
|
|
84
|
+
from pygeodesy.fmath import fdot, hypot1, zqrt, _ValueError
|
|
85
|
+
from pygeodesy.fsums import Fsum, _sum, _ALL_LAZY
|
|
86
|
+
from pygeodesy.interns import NN, _delta_, _DOT_, _dunder_nameof, _f_, \
|
|
87
|
+
_invalid_, _invokation_, _negative_, _SPACE_
|
|
88
|
+
from pygeodesy.karney import _K_2_0, _norm180, _signBit, _sincos2
|
|
89
|
+
# from pygeodesy.lazily import _ALL_LAZY # from .fsums
|
|
90
|
+
from pygeodesy.named import _Named, _NamedTuple, Fmt, unstr
|
|
91
|
+
from pygeodesy.props import _allPropertiesOf_n, Property_RO, _update_all
|
|
92
|
+
# from pygeodesy.streprs import Fmt, unstr # from .named
|
|
93
|
+
from pygeodesy.units import Scalar, Scalar_
|
|
94
|
+
# from pygeodesy.utily import sincos2 as _sincos2 # from .karney
|
|
95
|
+
|
|
96
|
+
from math import asinh, atan, atan2, ceil, cosh, fabs, floor, \
|
|
97
|
+
radians, sin, sqrt, tanh
|
|
98
|
+
|
|
99
|
+
__all__ = _ALL_LAZY.elliptic
|
|
100
|
+
__version__ = '24.03.22'
|
|
101
|
+
|
|
102
|
+
_TolRD = zqrt(EPS * 0.002)
|
|
103
|
+
_TolRF = zqrt(EPS * 0.030)
|
|
104
|
+
_TolRG0 = _TolJAC * 2.7
|
|
105
|
+
_TRIPS = 21 # Max depth, 7 might be sufficient
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class _Cs(object):
|
|
109
|
+
'''(INTERAL) Complete integrals cache.
|
|
110
|
+
'''
|
|
111
|
+
def __init__(self, **kwds):
|
|
112
|
+
self.__dict__ = kwds
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class _D(list):
|
|
116
|
+
'''(INTERNAL) Deferred C{Fsum}.
|
|
117
|
+
'''
|
|
118
|
+
def __call__(self, s):
|
|
119
|
+
try: # Fsum *= s
|
|
120
|
+
return Fsum(*self).fmul(s)
|
|
121
|
+
except ValueError: # Fsum(NAN) exception
|
|
122
|
+
return _sum(self) * s
|
|
123
|
+
|
|
124
|
+
def __iadd__(self, x):
|
|
125
|
+
list.append(self, x)
|
|
126
|
+
return self
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class Elliptic(_Named):
|
|
130
|
+
'''Elliptic integrals and functions.
|
|
131
|
+
|
|
132
|
+
@see: I{Karney}'s U{Detailed Description<https://GeographicLib.SourceForge.io/
|
|
133
|
+
C++/doc/classGeographicLib_1_1EllipticFunction.html#details>}.
|
|
134
|
+
'''
|
|
135
|
+
# _alpha2 = 0
|
|
136
|
+
# _alphap2 = 0
|
|
137
|
+
# _eps = EPS
|
|
138
|
+
# _k2 = 0
|
|
139
|
+
# _kp2 = 0
|
|
140
|
+
|
|
141
|
+
def __init__(self, k2=0, alpha2=0, kp2=None, alphap2=None, name=NN):
|
|
142
|
+
'''Constructor, specifying the C{modulus} and C{parameter}.
|
|
143
|
+
|
|
144
|
+
@kwarg name: Optional name (C{str}).
|
|
145
|
+
|
|
146
|
+
@see: Method L{Elliptic.reset} for further details.
|
|
147
|
+
|
|
148
|
+
@note: If only elliptic integrals of the first and second kinds
|
|
149
|
+
are needed, use C{B{alpha2}=0}, the default value. In
|
|
150
|
+
that case, we have C{Π(φ, 0, k) = F(φ, k), G(φ, 0, k) =
|
|
151
|
+
E(φ, k)} and C{H(φ, 0, k) = F(φ, k) - D(φ, k)}.
|
|
152
|
+
'''
|
|
153
|
+
self.reset(k2=k2, alpha2=alpha2, kp2=kp2, alphap2=alphap2)
|
|
154
|
+
|
|
155
|
+
if name:
|
|
156
|
+
self.name = name
|
|
157
|
+
|
|
158
|
+
@Property_RO
|
|
159
|
+
def alpha2(self):
|
|
160
|
+
'''Get α^2, the square of the parameter (C{float}).
|
|
161
|
+
'''
|
|
162
|
+
return self._alpha2
|
|
163
|
+
|
|
164
|
+
@Property_RO
|
|
165
|
+
def alphap2(self):
|
|
166
|
+
'''Get α'^2, the square of the complementary parameter (C{float}).
|
|
167
|
+
'''
|
|
168
|
+
return self._alphap2
|
|
169
|
+
|
|
170
|
+
@Property_RO
|
|
171
|
+
def cD(self):
|
|
172
|
+
'''Get Jahnke's complete integral C{D(k)} (C{float}),
|
|
173
|
+
U{defined<https://DLMF.NIST.gov/19.2.E6>}.
|
|
174
|
+
'''
|
|
175
|
+
return self._cDEKEeps.cD
|
|
176
|
+
|
|
177
|
+
@Property_RO
|
|
178
|
+
def _cDEKEeps(self):
|
|
179
|
+
'''(INTERNAL) Get the complete integrals D, E, K and KE plus C{eps}.
|
|
180
|
+
'''
|
|
181
|
+
k2, kp2 = self.k2, self.kp2
|
|
182
|
+
if k2:
|
|
183
|
+
if kp2:
|
|
184
|
+
try:
|
|
185
|
+
self._iteration = 0
|
|
186
|
+
# D(k) = (K(k) - E(k))/k2, Carlson eq.4.3
|
|
187
|
+
# <https://DLMF.NIST.gov/19.25.E1>
|
|
188
|
+
D = _RD(self, _0_0, kp2, _1_0, _3_0)
|
|
189
|
+
cD = float(D)
|
|
190
|
+
# Complete elliptic integral E(k), Carlson eq. 4.2
|
|
191
|
+
# <https://DLMF.NIST.gov/19.25.E1>
|
|
192
|
+
cE = _rG2(self, kp2, _1_0, PI_=PI_2)
|
|
193
|
+
# Complete elliptic integral K(k), Carlson eq. 4.1
|
|
194
|
+
# <https://DLMF.NIST.gov/19.25.E1>
|
|
195
|
+
cK = _rF2(self, kp2, _1_0)
|
|
196
|
+
cKE = float(D.fmul(k2))
|
|
197
|
+
eps = k2 / (sqrt(kp2) + _1_0)**2
|
|
198
|
+
|
|
199
|
+
except Exception as e:
|
|
200
|
+
raise _ellipticError(self.reset, k2=k2, kp2=kp2, cause=e)
|
|
201
|
+
else:
|
|
202
|
+
cD = cK = cKE = INF
|
|
203
|
+
cE = _1_0
|
|
204
|
+
eps = k2
|
|
205
|
+
else:
|
|
206
|
+
cD = PI_4
|
|
207
|
+
cE = cK = PI_2
|
|
208
|
+
cKE = _0_0 # k2 * cD
|
|
209
|
+
eps = EPS
|
|
210
|
+
|
|
211
|
+
return _Cs(cD=cD, cE=cE, cK=cK, cKE=cKE, eps=eps)
|
|
212
|
+
|
|
213
|
+
@Property_RO
|
|
214
|
+
def cE(self):
|
|
215
|
+
'''Get the complete integral of the second kind C{E(k)}
|
|
216
|
+
(C{float}), U{defined<https://DLMF.NIST.gov/19.2.E5>}.
|
|
217
|
+
'''
|
|
218
|
+
return self._cDEKEeps.cE
|
|
219
|
+
|
|
220
|
+
@Property_RO
|
|
221
|
+
def cG(self):
|
|
222
|
+
'''Get Legendre's complete geodesic longitude integral
|
|
223
|
+
C{G(α^2, k)} (C{float}).
|
|
224
|
+
'''
|
|
225
|
+
return self._cGHPi.cG
|
|
226
|
+
|
|
227
|
+
@Property_RO
|
|
228
|
+
def _cGHPi(self):
|
|
229
|
+
'''(INTERNAL) Get the complete integrals G, H and Pi.
|
|
230
|
+
'''
|
|
231
|
+
alpha2, alphap2, kp2 = self.alpha2, self.alphap2, self.kp2
|
|
232
|
+
try:
|
|
233
|
+
self._iteration = 0
|
|
234
|
+
if alpha2:
|
|
235
|
+
if alphap2:
|
|
236
|
+
if kp2: # <https://DLMF.NIST.gov/19.25.E2>
|
|
237
|
+
cK = self.cK
|
|
238
|
+
Rj = _RJ(self, _0_0, kp2, _1_0, alphap2, _3_0)
|
|
239
|
+
cG = float(Rj * (alpha2 - self.k2) + cK) # G(alpha2, k)
|
|
240
|
+
cH = -float(Rj * alphap2 - cK) # H(alpha2, k)
|
|
241
|
+
cPi = float(Rj * alpha2 + cK) # Pi(alpha2, k)
|
|
242
|
+
else:
|
|
243
|
+
cG = cH = _rC(self, _1_0, alphap2)
|
|
244
|
+
cPi = INF # XXX or NAN?
|
|
245
|
+
else:
|
|
246
|
+
cG = cH = cPi = INF # XXX or NAN?
|
|
247
|
+
else:
|
|
248
|
+
cG, cPi = self.cE, self.cK
|
|
249
|
+
# H = K - D but this involves large cancellations if k2 is near 1.
|
|
250
|
+
# So write (for alpha2 = 0)
|
|
251
|
+
# H = int(cos(phi)**2 / sqrt(1-k2 * sin(phi)**2), phi, 0, pi/2)
|
|
252
|
+
# = 1 / sqrt(1-k2) * int(sin(phi)**2 / sqrt(1-k2/kp2 * sin(phi)**2,...)
|
|
253
|
+
# = 1 / kp * D(i * k/kp)
|
|
254
|
+
# and use D(k) = RD(0, kp2, 1) / 3, so
|
|
255
|
+
# H = 1/kp * RD(0, 1/kp2, 1) / 3
|
|
256
|
+
# = kp2 * RD(0, 1, kp2) / 3
|
|
257
|
+
# using <https://DLMF.NIST.gov/19.20.E18>. Equivalently
|
|
258
|
+
# RF(x, 1) - RD(0, x, 1) / 3 = x * RD(0, 1, x) / 3 for x > 0
|
|
259
|
+
# For k2 = 1 and alpha2 = 0, we have
|
|
260
|
+
# H = int(cos(phi),...) = 1
|
|
261
|
+
cH = float(_RD(self, _0_0, _1_0, kp2, _3_0 / kp2)) if kp2 else _1_0
|
|
262
|
+
|
|
263
|
+
except Exception as e:
|
|
264
|
+
raise _ellipticError(self.reset, kp2=kp2, alpha2 =alpha2,
|
|
265
|
+
alphap2=alphap2, cause=e)
|
|
266
|
+
return _Cs(cG=cG, cH=cH, cPi=cPi)
|
|
267
|
+
|
|
268
|
+
@Property_RO
|
|
269
|
+
def cH(self):
|
|
270
|
+
'''Get Cayley's complete geodesic longitude difference integral
|
|
271
|
+
C{H(α^2, k)} (C{float}).
|
|
272
|
+
'''
|
|
273
|
+
return self._cGHPi.cH
|
|
274
|
+
|
|
275
|
+
@Property_RO
|
|
276
|
+
def cK(self):
|
|
277
|
+
'''Get the complete integral of the first kind C{K(k)}
|
|
278
|
+
(C{float}), U{defined<https://DLMF.NIST.gov/19.2.E4>}.
|
|
279
|
+
'''
|
|
280
|
+
return self._cDEKEeps.cK
|
|
281
|
+
|
|
282
|
+
@Property_RO
|
|
283
|
+
def cKE(self):
|
|
284
|
+
'''Get the difference between the complete integrals of the
|
|
285
|
+
first and second kinds, C{K(k) − E(k)} (C{float}).
|
|
286
|
+
'''
|
|
287
|
+
return self._cDEKEeps.cKE
|
|
288
|
+
|
|
289
|
+
@Property_RO
|
|
290
|
+
def cPi(self):
|
|
291
|
+
'''Get the complete integral of the third kind C{Pi(α^2, k)}
|
|
292
|
+
(C{float}), U{defined<https://DLMF.NIST.gov/19.2.E7>}.
|
|
293
|
+
'''
|
|
294
|
+
return self._cGHPi.cPi
|
|
295
|
+
|
|
296
|
+
def deltaD(self, sn, cn, dn):
|
|
297
|
+
'''Jahnke's periodic incomplete elliptic integral.
|
|
298
|
+
|
|
299
|
+
@arg sn: sin(φ).
|
|
300
|
+
@arg cn: cos(φ).
|
|
301
|
+
@arg dn: sqrt(1 − k2 * sin(2φ)).
|
|
302
|
+
|
|
303
|
+
@return: Periodic function π D(φ, k) / (2 D(k)) - φ (C{float}).
|
|
304
|
+
|
|
305
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
306
|
+
'''
|
|
307
|
+
return _deltaX(sn, cn, dn, self.cD, self.fD)
|
|
308
|
+
|
|
309
|
+
def deltaE(self, sn, cn, dn):
|
|
310
|
+
'''The periodic incomplete integral of the second kind.
|
|
311
|
+
|
|
312
|
+
@arg sn: sin(φ).
|
|
313
|
+
@arg cn: cos(φ).
|
|
314
|
+
@arg dn: sqrt(1 − k2 * sin(2φ)).
|
|
315
|
+
|
|
316
|
+
@return: Periodic function π E(φ, k) / (2 E(k)) - φ (C{float}).
|
|
317
|
+
|
|
318
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
319
|
+
'''
|
|
320
|
+
return _deltaX(sn, cn, dn, self.cE, self.fE)
|
|
321
|
+
|
|
322
|
+
def deltaEinv(self, stau, ctau):
|
|
323
|
+
'''The periodic inverse of the incomplete integral of the second kind.
|
|
324
|
+
|
|
325
|
+
@arg stau: sin(τ)
|
|
326
|
+
@arg ctau: cos(τ)
|
|
327
|
+
|
|
328
|
+
@return: Periodic function E^−1(τ (2 E(k)/π), k) - τ (C{float}).
|
|
329
|
+
|
|
330
|
+
@raise EllipticError: No convergence.
|
|
331
|
+
'''
|
|
332
|
+
try:
|
|
333
|
+
if _signBit(ctau): # pi periodic
|
|
334
|
+
stau, ctau = neg_(stau, ctau)
|
|
335
|
+
t = atan2(stau, ctau)
|
|
336
|
+
return self._Einv(t * self.cE / PI_2) - t
|
|
337
|
+
|
|
338
|
+
except Exception as e:
|
|
339
|
+
raise _ellipticError(self.deltaEinv, stau, ctau, cause=e)
|
|
340
|
+
|
|
341
|
+
def deltaF(self, sn, cn, dn):
|
|
342
|
+
'''The periodic incomplete integral of the first kind.
|
|
343
|
+
|
|
344
|
+
@arg sn: sin(φ).
|
|
345
|
+
@arg cn: cos(φ).
|
|
346
|
+
@arg dn: sqrt(1 − k2 * sin(2φ)).
|
|
347
|
+
|
|
348
|
+
@return: Periodic function π F(φ, k) / (2 K(k)) - φ (C{float}).
|
|
349
|
+
|
|
350
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
351
|
+
'''
|
|
352
|
+
return _deltaX(sn, cn, dn, self.cK, self.fF)
|
|
353
|
+
|
|
354
|
+
def deltaG(self, sn, cn, dn):
|
|
355
|
+
'''Legendre's periodic geodesic longitude integral.
|
|
356
|
+
|
|
357
|
+
@arg sn: sin(φ).
|
|
358
|
+
@arg cn: cos(φ).
|
|
359
|
+
@arg dn: sqrt(1 − k2 * sin(2φ)).
|
|
360
|
+
|
|
361
|
+
@return: Periodic function π G(φ, k) / (2 G(k)) - φ (C{float}).
|
|
362
|
+
|
|
363
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
364
|
+
'''
|
|
365
|
+
return _deltaX(sn, cn, dn, self.cG, self.fG)
|
|
366
|
+
|
|
367
|
+
def deltaH(self, sn, cn, dn):
|
|
368
|
+
'''Cayley's periodic geodesic longitude difference integral.
|
|
369
|
+
|
|
370
|
+
@arg sn: sin(φ).
|
|
371
|
+
@arg cn: cos(φ).
|
|
372
|
+
@arg dn: sqrt(1 − k2 * sin(2φ)).
|
|
373
|
+
|
|
374
|
+
@return: Periodic function π H(φ, k) / (2 H(k)) - φ (C{float}).
|
|
375
|
+
|
|
376
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
377
|
+
'''
|
|
378
|
+
return _deltaX(sn, cn, dn, self.cH, self.fH)
|
|
379
|
+
|
|
380
|
+
def deltaPi(self, sn, cn, dn):
|
|
381
|
+
'''The periodic incomplete integral of the third kind.
|
|
382
|
+
|
|
383
|
+
@arg sn: sin(φ).
|
|
384
|
+
@arg cn: cos(φ).
|
|
385
|
+
@arg dn: sqrt(1 − k2 * sin(2φ)).
|
|
386
|
+
|
|
387
|
+
@return: Periodic function π Π(φ, α2, k) / (2 Π(α2, k)) - φ
|
|
388
|
+
(C{float}).
|
|
389
|
+
|
|
390
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
391
|
+
'''
|
|
392
|
+
return _deltaX(sn, cn, dn, self.cPi, self.fPi)
|
|
393
|
+
|
|
394
|
+
def _Einv(self, x):
|
|
395
|
+
'''(INTERNAL) Helper for C{.deltaEinv} and C{.fEinv}.
|
|
396
|
+
'''
|
|
397
|
+
E2 = self.cE * _2_0
|
|
398
|
+
n = floor(x / E2 + _0_5)
|
|
399
|
+
r = x - E2 * n # r in [-cE, cE)
|
|
400
|
+
# linear approximation
|
|
401
|
+
phi = PI * r / E2 # phi in [-PI_2, PI_2)
|
|
402
|
+
Phi = Fsum(phi)
|
|
403
|
+
# first order correction
|
|
404
|
+
phi = Phi.fsum_(self.eps * sin(phi * _2_0) / _N_2_0)
|
|
405
|
+
# For kp2 close to zero use asin(r / cE) or J. P. Boyd,
|
|
406
|
+
# Applied Math. and Computation 218, 7005-7013 (2012)
|
|
407
|
+
# <https://DOI.org/10.1016/j.amc.2011.12.021>
|
|
408
|
+
_Phi2, self._iteration = Phi.fsum2_, 0 # aggregate
|
|
409
|
+
for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
|
|
410
|
+
sn, cn, dn = self._sncndn3(phi)
|
|
411
|
+
if dn:
|
|
412
|
+
sn = self.fE(sn, cn, dn)
|
|
413
|
+
phi, d = _Phi2((r - sn) / dn)
|
|
414
|
+
else: # PYCHOK no cover
|
|
415
|
+
d = _0_0 # XXX continue?
|
|
416
|
+
if fabs(d) < _TolJAC: # 3-4 trips
|
|
417
|
+
_iterations(self, i)
|
|
418
|
+
break
|
|
419
|
+
else: # PYCHOK no cover
|
|
420
|
+
raise _convergenceError(d, _TolJAC)
|
|
421
|
+
return Phi.fsum_(n * PI) if n else phi
|
|
422
|
+
|
|
423
|
+
@Property_RO
|
|
424
|
+
def eps(self):
|
|
425
|
+
'''Get epsilon (C{float}).
|
|
426
|
+
'''
|
|
427
|
+
return self._cDEKEeps.eps
|
|
428
|
+
|
|
429
|
+
def fD(self, phi_or_sn, cn=None, dn=None):
|
|
430
|
+
'''Jahnke's incomplete elliptic integral in terms of
|
|
431
|
+
Jacobi elliptic functions.
|
|
432
|
+
|
|
433
|
+
@arg phi_or_sn: φ or sin(φ).
|
|
434
|
+
@kwarg cn: C{None} or cos(φ).
|
|
435
|
+
@kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
|
|
436
|
+
|
|
437
|
+
@return: D(φ, k) as though φ ∈ (−π, π] (C{float}),
|
|
438
|
+
U{defined<https://DLMF.NIST.gov/19.2.E4>}.
|
|
439
|
+
|
|
440
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
441
|
+
'''
|
|
442
|
+
def _fD(sn, cn, dn):
|
|
443
|
+
r = fabs(sn)**3
|
|
444
|
+
if r:
|
|
445
|
+
r = float(_RD(self, cn**2, dn**2, _1_0, _3_0 / r))
|
|
446
|
+
return r
|
|
447
|
+
|
|
448
|
+
return self._fXf(phi_or_sn, cn, dn, self.cD,
|
|
449
|
+
self.deltaD, _fD)
|
|
450
|
+
|
|
451
|
+
def fDelta(self, sn, cn):
|
|
452
|
+
'''The C{Delta} amplitude function.
|
|
453
|
+
|
|
454
|
+
@arg sn: sin(φ).
|
|
455
|
+
@arg cn: cos(φ).
|
|
456
|
+
|
|
457
|
+
@return: sqrt(1 − k2 * sin(2φ)) (C{float}).
|
|
458
|
+
'''
|
|
459
|
+
try:
|
|
460
|
+
k2 = self.k2
|
|
461
|
+
s = (self.kp2 + cn**2 * k2) if k2 > 0 else (
|
|
462
|
+
(_1_0 - sn**2 * k2) if k2 < 0 else self.kp2)
|
|
463
|
+
return sqrt(s) if s else _0_0
|
|
464
|
+
|
|
465
|
+
except Exception as e:
|
|
466
|
+
raise _ellipticError(self.fDelta, sn, cn, k2=k2, cause=e)
|
|
467
|
+
|
|
468
|
+
def fE(self, phi_or_sn, cn=None, dn=None):
|
|
469
|
+
'''The incomplete integral of the second kind in terms of
|
|
470
|
+
Jacobi elliptic functions.
|
|
471
|
+
|
|
472
|
+
@arg phi_or_sn: φ or sin(φ).
|
|
473
|
+
@kwarg cn: C{None} or cos(φ).
|
|
474
|
+
@kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
|
|
475
|
+
|
|
476
|
+
@return: E(φ, k) as though φ ∈ (−π, π] (C{float}),
|
|
477
|
+
U{defined<https://DLMF.NIST.gov/19.2.E5>}.
|
|
478
|
+
|
|
479
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
480
|
+
'''
|
|
481
|
+
def _fE(sn, cn, dn):
|
|
482
|
+
'''(INTERNAL) Core of C{.fE}.
|
|
483
|
+
'''
|
|
484
|
+
if sn:
|
|
485
|
+
sn2, cn2, dn2 = sn**2, cn**2, dn**2
|
|
486
|
+
kp2, k2 = self.kp2, self.k2
|
|
487
|
+
if k2 <= 0: # Carlson, eq. 4.6, <https://DLMF.NIST.gov/19.25.E9>
|
|
488
|
+
Ei = _RF3(self, cn2, dn2, _1_0)
|
|
489
|
+
if k2:
|
|
490
|
+
Ei -= _RD(self, cn2, dn2, _1_0, _3over(k2, sn2))
|
|
491
|
+
elif kp2 >= 0: # k2 > 0, <https://DLMF.NIST.gov/19.25.E10>
|
|
492
|
+
Ei = _over(k2 * fabs(cn), dn) # float
|
|
493
|
+
if kp2:
|
|
494
|
+
Ei += (_RD( self, cn2, _1_0, dn2, _3over(k2, sn2)) +
|
|
495
|
+
_RF3(self, cn2, dn2, _1_0)) * kp2
|
|
496
|
+
else: # kp2 < 0, <https://DLMF.NIST.gov/19.25.E11>
|
|
497
|
+
Ei = _over(dn, fabs(cn))
|
|
498
|
+
Ei -= _RD(self, dn2, _1_0, cn2, _3over(kp2, sn2))
|
|
499
|
+
Ei *= fabs(sn)
|
|
500
|
+
ei = float(Ei)
|
|
501
|
+
else: # PYCHOK no cover
|
|
502
|
+
ei = _0_0
|
|
503
|
+
return ei
|
|
504
|
+
|
|
505
|
+
return self._fXf(phi_or_sn, cn, dn, self.cE,
|
|
506
|
+
self.deltaE, _fE)
|
|
507
|
+
|
|
508
|
+
def fEd(self, deg):
|
|
509
|
+
'''The incomplete integral of the second kind with
|
|
510
|
+
the argument given in C{degrees}.
|
|
511
|
+
|
|
512
|
+
@arg deg: Angle (C{degrees}).
|
|
513
|
+
|
|
514
|
+
@return: E(π B{C{deg}} / 180, k) (C{float}).
|
|
515
|
+
|
|
516
|
+
@raise EllipticError: No convergence.
|
|
517
|
+
'''
|
|
518
|
+
if _K_2_0:
|
|
519
|
+
e = round((deg - _norm180(deg)) / _360_0)
|
|
520
|
+
elif fabs(deg) < _180_0:
|
|
521
|
+
e = _0_0
|
|
522
|
+
else:
|
|
523
|
+
e = ceil(deg / _360_0 - _0_5)
|
|
524
|
+
deg -= e * _360_0
|
|
525
|
+
return self.fE(radians(deg)) + e * self.cE * _4_0
|
|
526
|
+
|
|
527
|
+
def fEinv(self, x):
|
|
528
|
+
'''The inverse of the incomplete integral of the second kind.
|
|
529
|
+
|
|
530
|
+
@arg x: Argument (C{float}).
|
|
531
|
+
|
|
532
|
+
@return: φ = 1 / E(B{C{x}}, k), such that E(φ, k) = B{C{x}}
|
|
533
|
+
(C{float}).
|
|
534
|
+
|
|
535
|
+
@raise EllipticError: No convergence.
|
|
536
|
+
'''
|
|
537
|
+
try:
|
|
538
|
+
return self._Einv(x)
|
|
539
|
+
except Exception as e:
|
|
540
|
+
raise _ellipticError(self.fEinv, x, cause=e)
|
|
541
|
+
|
|
542
|
+
def fF(self, phi_or_sn, cn=None, dn=None):
|
|
543
|
+
'''The incomplete integral of the first kind in terms of
|
|
544
|
+
Jacobi elliptic functions.
|
|
545
|
+
|
|
546
|
+
@arg phi_or_sn: φ or sin(φ).
|
|
547
|
+
@kwarg cn: C{None} or cos(φ).
|
|
548
|
+
@kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
|
|
549
|
+
|
|
550
|
+
@return: F(φ, k) as though φ ∈ (−π, π] (C{float}),
|
|
551
|
+
U{defined<https://DLMF.NIST.gov/19.2.E4>}.
|
|
552
|
+
|
|
553
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
554
|
+
'''
|
|
555
|
+
def _fF(sn, cn, dn):
|
|
556
|
+
r = fabs(sn)
|
|
557
|
+
if r:
|
|
558
|
+
r = float(_RF3(self, cn**2, dn**2, _1_0).fmul(r))
|
|
559
|
+
return r
|
|
560
|
+
|
|
561
|
+
return self._fXf(phi_or_sn, cn, dn, self.cK,
|
|
562
|
+
self.deltaF, _fF)
|
|
563
|
+
|
|
564
|
+
def fG(self, phi_or_sn, cn=None, dn=None):
|
|
565
|
+
'''Legendre's geodesic longitude integral in terms of
|
|
566
|
+
Jacobi elliptic functions.
|
|
567
|
+
|
|
568
|
+
@arg phi_or_sn: φ or sin(φ).
|
|
569
|
+
@kwarg cn: C{None} or cos(φ).
|
|
570
|
+
@kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
|
|
571
|
+
|
|
572
|
+
@return: G(φ, k) as though φ ∈ (−π, π] (C{float}).
|
|
573
|
+
|
|
574
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
575
|
+
|
|
576
|
+
@note: Legendre expresses the longitude of a point on the
|
|
577
|
+
geodesic in terms of this combination of elliptic
|
|
578
|
+
integrals in U{Exercices de Calcul Intégral, Vol 1
|
|
579
|
+
(1811), p 181<https://Books.Google.com/books?id=
|
|
580
|
+
riIOAAAAQAAJ&pg=PA181>}.
|
|
581
|
+
|
|
582
|
+
@see: U{Geodesics in terms of elliptic integrals<https://
|
|
583
|
+
GeographicLib.SourceForge.io/C++/doc/geodesic.html#geodellip>}
|
|
584
|
+
for the expression for the longitude in terms of this function.
|
|
585
|
+
'''
|
|
586
|
+
return self._fXa(phi_or_sn, cn, dn, self.alpha2 - self.k2,
|
|
587
|
+
self.cG, self.deltaG)
|
|
588
|
+
|
|
589
|
+
def fH(self, phi_or_sn, cn=None, dn=None):
|
|
590
|
+
'''Cayley's geodesic longitude difference integral in terms of
|
|
591
|
+
Jacobi elliptic functions.
|
|
592
|
+
|
|
593
|
+
@arg phi_or_sn: φ or sin(φ).
|
|
594
|
+
@kwarg cn: C{None} or cos(φ).
|
|
595
|
+
@kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
|
|
596
|
+
|
|
597
|
+
@return: H(φ, k) as though φ ∈ (−π, π] (C{float}).
|
|
598
|
+
|
|
599
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
600
|
+
|
|
601
|
+
@note: Cayley expresses the longitude difference of a point
|
|
602
|
+
on the geodesic in terms of this combination of
|
|
603
|
+
elliptic integrals in U{Phil. Mag. B{40} (1870), p 333
|
|
604
|
+
<https://Books.Google.com/books?id=Zk0wAAAAIAAJ&pg=PA333>}.
|
|
605
|
+
|
|
606
|
+
@see: U{Geodesics in terms of elliptic integrals<https://
|
|
607
|
+
GeographicLib.SourceForge.io/C++/doc/geodesic.html#geodellip>}
|
|
608
|
+
for the expression for the longitude in terms of this function.
|
|
609
|
+
'''
|
|
610
|
+
return self._fXa(phi_or_sn, cn, dn, -self.alphap2,
|
|
611
|
+
self.cH, self.deltaH)
|
|
612
|
+
|
|
613
|
+
def fPi(self, phi_or_sn, cn=None, dn=None):
|
|
614
|
+
'''The incomplete integral of the third kind in terms of
|
|
615
|
+
Jacobi elliptic functions.
|
|
616
|
+
|
|
617
|
+
@arg phi_or_sn: φ or sin(φ).
|
|
618
|
+
@kwarg cn: C{None} or cos(φ).
|
|
619
|
+
@kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
|
|
620
|
+
|
|
621
|
+
@return: Π(φ, α2, k) as though φ ∈ (−π, π] (C{float}).
|
|
622
|
+
|
|
623
|
+
@raise EllipticError: Invalid invokation or no convergence.
|
|
624
|
+
'''
|
|
625
|
+
if dn is None and cn is not None: # and isscalar(phi_or_sn)
|
|
626
|
+
dn = self.fDelta(phi_or_sn, cn) # in .triaxial
|
|
627
|
+
return self._fXa(phi_or_sn, cn, dn, self.alpha2,
|
|
628
|
+
self.cPi, self.deltaPi)
|
|
629
|
+
|
|
630
|
+
def _fXa(self, phi_or_sn, cn, dn, aX, cX, deltaX):
|
|
631
|
+
'''(INTERNAL) Helper for C{.fG}, C{.fH} and C{.fPi}.
|
|
632
|
+
'''
|
|
633
|
+
def _fX(sn, cn, dn):
|
|
634
|
+
if sn:
|
|
635
|
+
cn2, dn2 = cn**2, dn**2
|
|
636
|
+
R = _RF3(self, cn2, dn2, _1_0)
|
|
637
|
+
if aX:
|
|
638
|
+
sn2 = sn**2
|
|
639
|
+
p = sn2 * self.alphap2 + cn2
|
|
640
|
+
R += _RJ(self, cn2, dn2, _1_0, p, _3over(aX, sn2))
|
|
641
|
+
R *= fabs(sn)
|
|
642
|
+
r = float(R)
|
|
643
|
+
else: # PYCHOK no cover
|
|
644
|
+
r = _0_0
|
|
645
|
+
return r
|
|
646
|
+
|
|
647
|
+
return self._fXf(phi_or_sn, cn, dn, cX, deltaX, _fX)
|
|
648
|
+
|
|
649
|
+
def _fXf(self, phi_or_sn, cn, dn, cX, deltaX, fX):
|
|
650
|
+
'''(INTERNAL) Helper for C{.fD}, C{.fE}, C{.fF} and C{._fXa}.
|
|
651
|
+
'''
|
|
652
|
+
self._iteration = 0 # aggregate
|
|
653
|
+
phi = sn = phi_or_sn
|
|
654
|
+
if cn is dn is None: # fX(phi) call
|
|
655
|
+
sn, cn, dn = self._sncndn3(phi)
|
|
656
|
+
if fabs(phi) >= PI:
|
|
657
|
+
return (deltaX(sn, cn, dn) + phi) * cX / PI_2
|
|
658
|
+
# fall through
|
|
659
|
+
elif cn is None or dn is None:
|
|
660
|
+
n = NN(_f_, deltaX.__name__[5:])
|
|
661
|
+
raise _ellipticError(n, sn, cn, dn)
|
|
662
|
+
|
|
663
|
+
if _signBit(cn): # enforce usual trig-like symmetries
|
|
664
|
+
xi = cX * _2_0 - fX(sn, cn, dn)
|
|
665
|
+
else:
|
|
666
|
+
xi = fX(sn, cn, dn) if cn > 0 else cX
|
|
667
|
+
return copysign0(xi, sn)
|
|
668
|
+
|
|
669
|
+
@Property_RO
|
|
670
|
+
def k2(self):
|
|
671
|
+
'''Get k^2, the square of the modulus (C{float}).
|
|
672
|
+
'''
|
|
673
|
+
return self._k2
|
|
674
|
+
|
|
675
|
+
@Property_RO
|
|
676
|
+
def kp2(self):
|
|
677
|
+
'''Get k'^2, the square of the complementary modulus (C{float}).
|
|
678
|
+
'''
|
|
679
|
+
return self._kp2
|
|
680
|
+
|
|
681
|
+
def reset(self, k2=0, alpha2=0, kp2=None, alphap2=None): # MCCABE 13
|
|
682
|
+
'''Reset the modulus, parameter and the complementaries.
|
|
683
|
+
|
|
684
|
+
@kwarg k2: Modulus squared (C{float}, NINF <= k^2 <= 1).
|
|
685
|
+
@kwarg alpha2: Parameter squared (C{float}, NINF <= α^2 <= 1).
|
|
686
|
+
@kwarg kp2: Complementary modulus squared (C{float}, k'^2 >= 0).
|
|
687
|
+
@kwarg alphap2: Complementary parameter squared (C{float}, α'^2 >= 0).
|
|
688
|
+
|
|
689
|
+
@raise EllipticError: Invalid B{C{k2}}, B{C{alpha2}}, B{C{kp2}}
|
|
690
|
+
or B{C{alphap2}}.
|
|
691
|
+
|
|
692
|
+
@note: The arguments must satisfy C{B{k2} + B{kp2} = 1} and
|
|
693
|
+
C{B{alpha2} + B{alphap2} = 1}. No checking is done
|
|
694
|
+
that these conditions are met to enable accuracy to be
|
|
695
|
+
maintained, e.g., when C{k} is very close to unity.
|
|
696
|
+
'''
|
|
697
|
+
if self.__dict__:
|
|
698
|
+
_update_all(self, _Named.iteration._uname, Base=Property_RO)
|
|
699
|
+
|
|
700
|
+
self._k2 = Scalar_(k2=k2, Error=EllipticError, low=None, high=_1_0)
|
|
701
|
+
self._kp2 = Scalar_(kp2=((_1_0 - k2) if kp2 is None else kp2), Error=EllipticError)
|
|
702
|
+
|
|
703
|
+
self._alpha2 = Scalar_(alpha2=alpha2, Error=EllipticError, low=None, high=_1_0)
|
|
704
|
+
self._alphap2 = Scalar_(alphap2=((_1_0 - alpha2) if alphap2 is None else alphap2),
|
|
705
|
+
Error=EllipticError)
|
|
706
|
+
|
|
707
|
+
# Values of complete elliptic integrals for k = 0,1 and alpha = 0,1
|
|
708
|
+
# K E D
|
|
709
|
+
# k = 0: pi/2 pi/2 pi/4
|
|
710
|
+
# k = 1: inf 1 inf
|
|
711
|
+
# Pi G H
|
|
712
|
+
# k = 0, alpha = 0: pi/2 pi/2 pi/4
|
|
713
|
+
# k = 1, alpha = 0: inf 1 1
|
|
714
|
+
# k = 0, alpha = 1: inf inf pi/2
|
|
715
|
+
# k = 1, alpha = 1: inf inf inf
|
|
716
|
+
#
|
|
717
|
+
# G(0, k) = Pi(0, k) = H(1, k) = E(k)
|
|
718
|
+
# H(0, k) = K(k) - D(k)
|
|
719
|
+
# Pi(alpha2, 0) = G(alpha2, 0) = pi / (2 * sqrt(1 - alpha2))
|
|
720
|
+
# H( alpha2, 0) = pi / (2 * (sqrt(1 - alpha2) + 1))
|
|
721
|
+
# Pi(alpha2, 1) = inf
|
|
722
|
+
# G( alpha2, 1) = H(alpha2, 1) = RC(1, alphap2)
|
|
723
|
+
|
|
724
|
+
def sncndn(self, x):
|
|
725
|
+
'''The Jacobi elliptic function.
|
|
726
|
+
|
|
727
|
+
@arg x: The argument (C{float}).
|
|
728
|
+
|
|
729
|
+
@return: An L{Elliptic3Tuple}C{(sn, cn, dn)} with
|
|
730
|
+
C{*n(B{x}, k)}.
|
|
731
|
+
|
|
732
|
+
@raise EllipticError: No convergence.
|
|
733
|
+
'''
|
|
734
|
+
self._iteration = 0 # reset
|
|
735
|
+
try: # Bulirsch's sncndn routine, p 89.
|
|
736
|
+
if self.kp2:
|
|
737
|
+
c, d, cd, mn = self._sncndn4
|
|
738
|
+
dn = _1_0
|
|
739
|
+
sn, cn = _sincos2(x * cd)
|
|
740
|
+
if sn:
|
|
741
|
+
a = cn / sn
|
|
742
|
+
c *= a
|
|
743
|
+
for m, n in reversed(mn):
|
|
744
|
+
a *= c
|
|
745
|
+
c *= dn
|
|
746
|
+
dn = (n + a) / (m + a)
|
|
747
|
+
a = c / m
|
|
748
|
+
a = _1_0 / hypot1(c)
|
|
749
|
+
sn = neg(a) if _signBit(sn) else a
|
|
750
|
+
cn = c * sn
|
|
751
|
+
if d and _signBit(self.kp2):
|
|
752
|
+
cn, dn = dn, cn
|
|
753
|
+
sn = sn / d # /= chokes PyChecker
|
|
754
|
+
else:
|
|
755
|
+
sn = tanh(x)
|
|
756
|
+
cn = dn = _1_0 / cosh(x)
|
|
757
|
+
|
|
758
|
+
except Exception as e:
|
|
759
|
+
raise _ellipticError(self.sncndn, x, kp2=self.kp2, cause=e)
|
|
760
|
+
|
|
761
|
+
return Elliptic3Tuple(sn, cn, dn, iteration=self._iteration)
|
|
762
|
+
|
|
763
|
+
def _sncndn3(self, phi):
|
|
764
|
+
'''(INTERNAL) Helper for C{.fEinv} and C{._fXf}.
|
|
765
|
+
'''
|
|
766
|
+
sn, cn = _sincos2(phi)
|
|
767
|
+
return sn, cn, self.fDelta(sn, cn)
|
|
768
|
+
|
|
769
|
+
@Property_RO
|
|
770
|
+
def _sncndn4(self):
|
|
771
|
+
'''(INTERNAL) Get Bulirsch' 4-tuple C{(c, d, cd, mn)}.
|
|
772
|
+
'''
|
|
773
|
+
# Bulirsch's sncndn routine, p 89.
|
|
774
|
+
d, mc = 0, self.kp2
|
|
775
|
+
if _signBit(mc):
|
|
776
|
+
d = _1_0 - mc
|
|
777
|
+
mc = neg(mc / d)
|
|
778
|
+
d = sqrt(d)
|
|
779
|
+
|
|
780
|
+
mn, a = [], _1_0
|
|
781
|
+
for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
|
|
782
|
+
mc = sqrt(mc)
|
|
783
|
+
mn.append((a, mc))
|
|
784
|
+
c = (a + mc) * _0_5
|
|
785
|
+
r = fabs(mc - a)
|
|
786
|
+
t = _TolJAC * a
|
|
787
|
+
if r <= t: # 6 trips, quadratic
|
|
788
|
+
_iterations(self, i)
|
|
789
|
+
break
|
|
790
|
+
mc *= a
|
|
791
|
+
a = c
|
|
792
|
+
else: # PYCHOK no cover
|
|
793
|
+
raise _convergenceError(r, t)
|
|
794
|
+
cd = (c * d) if d else c
|
|
795
|
+
return c, d, cd, mn
|
|
796
|
+
|
|
797
|
+
@staticmethod
|
|
798
|
+
def fRC(x, y):
|
|
799
|
+
'''Degenerate symmetric integral of the first kind C{RC(x, y)}.
|
|
800
|
+
|
|
801
|
+
@return: C{RC(x, y)}, equivalent to C{RF(x, y, y)}.
|
|
802
|
+
|
|
803
|
+
@see: U{C{RC} definition<https://DLMF.NIST.gov/19.2.E17>} and
|
|
804
|
+
U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
|
|
805
|
+
'''
|
|
806
|
+
return _rC(None, x, y)
|
|
807
|
+
|
|
808
|
+
@staticmethod
|
|
809
|
+
def fRD(x, y, z, *over):
|
|
810
|
+
'''Degenerate symmetric integral of the third kind C{RD(x, y, z)}.
|
|
811
|
+
|
|
812
|
+
@return: C{RD(x, y, z) / over}, equivalent to C{RJ(x, y, z, z)
|
|
813
|
+
/ over} with C{over} typically 3.
|
|
814
|
+
|
|
815
|
+
@see: U{C{RD} definition<https://DLMF.NIST.gov/19.16.E5>} and
|
|
816
|
+
U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
|
|
817
|
+
'''
|
|
818
|
+
try:
|
|
819
|
+
return float(_RD(None, x, y, z, *over))
|
|
820
|
+
except Exception as e:
|
|
821
|
+
raise _ellipticError(Elliptic.fRD, x, y, z, *over, cause=e)
|
|
822
|
+
|
|
823
|
+
@staticmethod
|
|
824
|
+
def fRF(x, y, z=0):
|
|
825
|
+
'''Symmetric or complete symmetric integral of the first kind
|
|
826
|
+
C{RF(x, y, z)} respectively C{RF(x, y)}.
|
|
827
|
+
|
|
828
|
+
@return: C{RF(x, y, z)} or C{RF(x, y)} for missing or zero B{C{z}}.
|
|
829
|
+
|
|
830
|
+
@see: U{C{RF} definition<https://DLMF.NIST.gov/19.16.E1>} and
|
|
831
|
+
U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
|
|
832
|
+
'''
|
|
833
|
+
try:
|
|
834
|
+
return float(_RF3(None, x, y, z)) if z else _rF2(None, x, y)
|
|
835
|
+
except Exception as e:
|
|
836
|
+
raise _ellipticError(Elliptic.fRF, x, y, z, cause=e)
|
|
837
|
+
|
|
838
|
+
@staticmethod
|
|
839
|
+
def fRG(x, y, z=0):
|
|
840
|
+
'''Symmetric or complete symmetric integral of the second kind
|
|
841
|
+
C{RG(x, y, z)} respectively C{RG(x, y)}.
|
|
842
|
+
|
|
843
|
+
@return: C{RG(x, y, z)} or C{RG(x, y)} for missing or zero B{C{z}}.
|
|
844
|
+
|
|
845
|
+
@see: U{C{RG} definition<https://DLMF.NIST.gov/19.16.E3>},
|
|
846
|
+
U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>} and
|
|
847
|
+
U{RG<https://GeographicLib.SourceForge.io/C++/doc/
|
|
848
|
+
EllipticFunction_8cpp_source.html#l00096>} version 2.3.
|
|
849
|
+
'''
|
|
850
|
+
try:
|
|
851
|
+
return _rG2(None, x, y) if z == 0 else (
|
|
852
|
+
_rG2(None, z, x) if y == 0 else (
|
|
853
|
+
_rG2(None, y, z) if x == 0 else _rG3(None, x, y, z)))
|
|
854
|
+
except Exception as e:
|
|
855
|
+
t = _negative_ if min(x, y, z) < 0 else NN
|
|
856
|
+
raise _ellipticError(Elliptic.fRG, x, y, z, cause=e, txt=t)
|
|
857
|
+
|
|
858
|
+
@staticmethod
|
|
859
|
+
def fRJ(x, y, z, p):
|
|
860
|
+
'''Symmetric integral of the third kind C{RJ(x, y, z, p)}.
|
|
861
|
+
|
|
862
|
+
@return: C{RJ(x, y, z, p)}.
|
|
863
|
+
|
|
864
|
+
@see: U{C{RJ} definition<https://DLMF.NIST.gov/19.16.E2>} and
|
|
865
|
+
U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
|
|
866
|
+
'''
|
|
867
|
+
try:
|
|
868
|
+
return float(_RJ(None, x, y, z, p))
|
|
869
|
+
except Exception as e:
|
|
870
|
+
raise _ellipticError(Elliptic.fRJ, x, y, z, p, cause=e)
|
|
871
|
+
|
|
872
|
+
@staticmethod
|
|
873
|
+
def _RFRD(x, y, z, m):
|
|
874
|
+
# in .auxilats.AuxDLat.DE, .auxilats.AuxLat.Rectifying
|
|
875
|
+
try: # float(RF(x, y, z) - RD(x, y, z, 3 / m))
|
|
876
|
+
R = _RF3(None, x, y, z)
|
|
877
|
+
if m:
|
|
878
|
+
R -= _RD(None, x, y, z, _3_0 / m)
|
|
879
|
+
except Exception as e:
|
|
880
|
+
raise _ellipticError(Elliptic._RFRD, x, y, z, m, cause=e)
|
|
881
|
+
return float(R)
|
|
882
|
+
|
|
883
|
+
_allPropertiesOf_n(15, Elliptic) # # PYCHOK assert, see Elliptic.reset
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
class EllipticError(_ValueError):
|
|
887
|
+
'''Elliptic function, integral, convergence or other L{Elliptic} issue.
|
|
888
|
+
'''
|
|
889
|
+
pass
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
class Elliptic3Tuple(_NamedTuple):
|
|
893
|
+
'''3-Tuple C{(sn, cn, dn)} all C{scalar}.
|
|
894
|
+
'''
|
|
895
|
+
_Names_ = ('sn', 'cn', 'dn')
|
|
896
|
+
_Units_ = ( Scalar, Scalar, Scalar)
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
class _L(list):
|
|
900
|
+
'''(INTERNAL) Helper for C{_RD}, C{_RF3} and C{_RJ}.
|
|
901
|
+
'''
|
|
902
|
+
_a0 = None
|
|
903
|
+
# _xyzp = ()
|
|
904
|
+
|
|
905
|
+
def __init__(self, *xyzp): # x, y, z [, p]
|
|
906
|
+
list.__init__(self, xyzp)
|
|
907
|
+
self._xyzp = xyzp
|
|
908
|
+
|
|
909
|
+
def a0(self, n):
|
|
910
|
+
'''Compute the initial C{a}.
|
|
911
|
+
'''
|
|
912
|
+
t = tuple(self)
|
|
913
|
+
m = n - len(t)
|
|
914
|
+
if m > 0:
|
|
915
|
+
t += t[-1:] * m
|
|
916
|
+
try:
|
|
917
|
+
a = Fsum(*t).fover(n)
|
|
918
|
+
except ValueError: # Fsum(NAN) exception
|
|
919
|
+
a = _sum(t) / n
|
|
920
|
+
self._a0 = a
|
|
921
|
+
return a
|
|
922
|
+
|
|
923
|
+
def amrs4(self, inst, y, Tol):
|
|
924
|
+
'''Yield Carlson 4-tuples C{(An, mul, lam, s)} plus sentinel, with
|
|
925
|
+
C{lam = fdot(sqrt(x), ... (z))} and C{s = (sqrt(x), ... (p))}.
|
|
926
|
+
'''
|
|
927
|
+
L = self
|
|
928
|
+
a = L.a0(5 if y else 3)
|
|
929
|
+
m = 1
|
|
930
|
+
t = max(fabs(a - _) for _ in L) / Tol
|
|
931
|
+
for i in range(_TRIPS):
|
|
932
|
+
d = fabs(a * m)
|
|
933
|
+
if d > t: # 3-6 trips
|
|
934
|
+
_iterations(inst, i)
|
|
935
|
+
break
|
|
936
|
+
s = map2(sqrt, L) # sqrt(x), srqt(y), sqrt(z) [, sqrt(p)]
|
|
937
|
+
try:
|
|
938
|
+
r = fdot(s[:3], s[1], s[2], s[0]) # sqrt(x) * sqrt(y) + ...
|
|
939
|
+
except ValueError: # Fsum(NAN) exception
|
|
940
|
+
r = _sum(s[i] * s[(i + 1) % 3] for i in range(3))
|
|
941
|
+
L[:] = [(r + _) * _0_25 for _ in L]
|
|
942
|
+
a = (r + a) * _0_25
|
|
943
|
+
if y: # yield only if used
|
|
944
|
+
yield a, m, r, s # L[2] is next z
|
|
945
|
+
m *= 4
|
|
946
|
+
else: # PYCHOK no cover
|
|
947
|
+
raise _convergenceError(d, t, thresh=True)
|
|
948
|
+
yield a, m, None, () # sentinel: same a, next m, no r and s
|
|
949
|
+
|
|
950
|
+
def rescale(self, am, *xs):
|
|
951
|
+
'''Rescale C{x}, C{y}, ...
|
|
952
|
+
'''
|
|
953
|
+
# assert am
|
|
954
|
+
a0 = self._a0
|
|
955
|
+
for x in xs:
|
|
956
|
+
yield (a0 - x) / am
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
def _ab2(inst, x, y):
|
|
960
|
+
'''(INTERNAL) Yield Carlson 2-tuples C{(xn, yn)}.
|
|
961
|
+
'''
|
|
962
|
+
a, b = sqrt(x), sqrt(y)
|
|
963
|
+
if b > a:
|
|
964
|
+
a, b = b, a
|
|
965
|
+
yield a, b # initial x0, y0
|
|
966
|
+
for i in range(_TRIPS):
|
|
967
|
+
d = fabs(a - b)
|
|
968
|
+
t = _TolRG0 * a
|
|
969
|
+
if d <= t: # 3-4 trips
|
|
970
|
+
_iterations(inst, i)
|
|
971
|
+
break
|
|
972
|
+
a, b = ((a + b) * _0_5), sqrt(a * b)
|
|
973
|
+
yield a, b # xn, yn
|
|
974
|
+
else: # PYCHOK no cover
|
|
975
|
+
raise _convergenceError(d, t)
|
|
976
|
+
|
|
977
|
+
|
|
978
|
+
def _convergenceError(d, tol, **thresh):
|
|
979
|
+
'''(INTERNAL) Format a no-convergence Error.
|
|
980
|
+
'''
|
|
981
|
+
t = Fmt.no_convergence(d, tol, **thresh)
|
|
982
|
+
return ValueError(t) # txt only
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
def _deltaX(sn, cn, dn, cX, fX):
|
|
986
|
+
'''(INTERNAL) Helper for C{Elliptic.deltaD} thru C{.deltaPi}.
|
|
987
|
+
'''
|
|
988
|
+
try:
|
|
989
|
+
if cn is None or dn is None:
|
|
990
|
+
raise ValueError(_invalid_)
|
|
991
|
+
|
|
992
|
+
if _signBit(cn):
|
|
993
|
+
sn, cn = neg_(sn, cn)
|
|
994
|
+
r = fX(sn, cn, dn) * PI_2 / cX
|
|
995
|
+
return r - atan2(sn, cn)
|
|
996
|
+
|
|
997
|
+
except Exception as e:
|
|
998
|
+
n = NN(_delta_, fX.__name__[1:])
|
|
999
|
+
raise _ellipticError(n, sn, cn, dn, cause=e)
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
def _ellipticError(where, *args, **kwds_cause_txt):
|
|
1003
|
+
'''(INTERNAL) Format an L{EllipticError}.
|
|
1004
|
+
'''
|
|
1005
|
+
def _x_t_kwds(cause=None, txt=NN, **kwds):
|
|
1006
|
+
return cause, txt, kwds
|
|
1007
|
+
|
|
1008
|
+
x, t, kwds = _x_t_kwds(**kwds_cause_txt)
|
|
1009
|
+
|
|
1010
|
+
n = _dunder_nameof(where, where)
|
|
1011
|
+
n = _DOT_(Elliptic.__name__, n)
|
|
1012
|
+
n = _SPACE_(_invokation_, n)
|
|
1013
|
+
u = unstr(n, *args, **kwds)
|
|
1014
|
+
return EllipticError(u, cause=x, txt=t)
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
def _Horner(S, e1, E2, E3, E4, E5, *over):
|
|
1018
|
+
'''(INTERNAL) Horner form for C{_RD} and C{_RJ} below.
|
|
1019
|
+
'''
|
|
1020
|
+
E22 = E2**2
|
|
1021
|
+
# Polynomial is <https://DLMF.NIST.gov/19.36.E2>
|
|
1022
|
+
# (1 - 3*E2/14 + E3/6 + 9*E2**2/88 - 3*E4/22 - 9*E2*E3/52
|
|
1023
|
+
# + 3*E5/26 - E2**3/16 + 3*E3**2/40 + 3*E2*E4/20
|
|
1024
|
+
# + 45*E2**2*E3/272 - 9*(E3*E4+E2*E5)/68)
|
|
1025
|
+
# converted to Horner-like form ...
|
|
1026
|
+
F = Fsum
|
|
1027
|
+
e = e1 * 4084080
|
|
1028
|
+
S *= e
|
|
1029
|
+
S += F(E2 * -540540, 471240).fmul(E5)
|
|
1030
|
+
S += F(E2 * 612612, E3 * -540540, -556920).fmul(E4)
|
|
1031
|
+
S += F(E2 * -706860, E22 * 675675, E3 * 306306, 680680).fmul(E3)
|
|
1032
|
+
S += F(E2 * 417690, E22 * -255255, -875160).fmul(E2)
|
|
1033
|
+
S += 4084080
|
|
1034
|
+
return S.fdiv((over[0] * e) if over else e) # Fsum
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
def _iterations(inst, i):
|
|
1038
|
+
'''(INTERNAL) Aggregate iterations B{C{i}}.
|
|
1039
|
+
'''
|
|
1040
|
+
if inst and i > 0:
|
|
1041
|
+
inst._iteration += i
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
def _3over(a, b):
|
|
1045
|
+
'''(INTERNAL) Return C{3 / (a * b)}.
|
|
1046
|
+
'''
|
|
1047
|
+
return _over(_3_0, a * b)
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
def _rC(unused, x, y):
|
|
1051
|
+
'''(INTERNAL) Defined only for C{y != 0} and C{x >= 0}.
|
|
1052
|
+
'''
|
|
1053
|
+
d = x - y
|
|
1054
|
+
if d < 0: # catch NaN
|
|
1055
|
+
# <https://DLMF.NIST.gov/19.2.E18>
|
|
1056
|
+
d = -d
|
|
1057
|
+
r = atan(sqrt(d / x)) if x > 0 else PI_2
|
|
1058
|
+
elif d == 0: # XXX d < EPS0? or EPS02 or _EPSmin
|
|
1059
|
+
d, r = y, _1_0
|
|
1060
|
+
elif y > 0: # <https://DLMF.NIST.gov/19.2.E19>
|
|
1061
|
+
r = asinh(sqrt(d / y)) # atanh(sqrt((x - y) / x))
|
|
1062
|
+
elif y < 0: # <https://DLMF.NIST.gov/19.2.E20>
|
|
1063
|
+
r = asinh(sqrt(-x / y)) # atanh(sqrt(x / (x - y)))
|
|
1064
|
+
else: # PYCHOK no cover
|
|
1065
|
+
raise _ellipticError(Elliptic.fRC, x, y)
|
|
1066
|
+
return r / sqrt(d) # float
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
def _RD(inst, x, y, z, *over):
|
|
1070
|
+
'''(INTERNAL) Carlson, eqs 2.28 - 2.34.
|
|
1071
|
+
'''
|
|
1072
|
+
L = _L(x, y, z)
|
|
1073
|
+
S = _D()
|
|
1074
|
+
for a, m, r, s in L.amrs4(inst, True, _TolRF):
|
|
1075
|
+
if s:
|
|
1076
|
+
S += _over(_3_0, (r + z) * s[2] * m)
|
|
1077
|
+
z = L[2] # s[2] = sqrt(z)
|
|
1078
|
+
x, y = L.rescale(-a * m, x, y)
|
|
1079
|
+
xy = x * y
|
|
1080
|
+
z = (x + y) / _3_0
|
|
1081
|
+
z2 = z**2
|
|
1082
|
+
return _Horner(S(_1_0), sqrt(a) * a * m,
|
|
1083
|
+
xy - _6_0 * z2,
|
|
1084
|
+
(xy * _3_0 - _8_0 * z2) * z,
|
|
1085
|
+
(xy - z2) * _3_0 * z2,
|
|
1086
|
+
xy * z2 * z, *over) # Fsum
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
def _rF2(inst, x, y): # 2-arg version, z=0
|
|
1090
|
+
'''(INTERNAL) Carlson, eqs 2.36 - 2.38.
|
|
1091
|
+
'''
|
|
1092
|
+
for a, b in _ab2(inst, x, y): # PYCHOK yield
|
|
1093
|
+
pass
|
|
1094
|
+
return _over(PI, a + b) # float
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
def _RF3(inst, x, y, z): # 3-arg version
|
|
1098
|
+
'''(INTERNAL) Carlson, eqs 2.2 - 2.7.
|
|
1099
|
+
'''
|
|
1100
|
+
L = _L(x, y, z)
|
|
1101
|
+
for a, m, _, _ in L.amrs4(inst, False, _TolRF):
|
|
1102
|
+
pass
|
|
1103
|
+
x, y = L.rescale(a * m, x, y)
|
|
1104
|
+
z = neg(x + y)
|
|
1105
|
+
xy = x * y
|
|
1106
|
+
e2 = xy - z**2
|
|
1107
|
+
e3 = xy * z
|
|
1108
|
+
e4 = e2**2
|
|
1109
|
+
# Polynomial is <https://DLMF.NIST.gov/19.36.E1>
|
|
1110
|
+
# (1 - E2/10 + E3/14 + E2**2/24 - 3*E2*E3/44
|
|
1111
|
+
# - 5*E2**3/208 + 3*E3**2/104 + E2**2*E3/16)
|
|
1112
|
+
# converted to Horner-like form ...
|
|
1113
|
+
S = Fsum(e4 * 15015, e3 * 6930, e2 * -16380, 17160).fmul(e3)
|
|
1114
|
+
S += Fsum(e4 * -5775, e2 * 10010, -24024).fmul(e2)
|
|
1115
|
+
S += 240240
|
|
1116
|
+
return S.fdiv(sqrt(a) * 240240) # Fsum
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
def _rG2(inst, x, y, PI_=PI_4): # 2-args
|
|
1120
|
+
'''(INTERNAL) Carlson, eqs 2.36 - 2.39.
|
|
1121
|
+
'''
|
|
1122
|
+
m = -1 # neg!
|
|
1123
|
+
S = _D()
|
|
1124
|
+
# assert not S
|
|
1125
|
+
for a, b in _ab2(inst, x, y): # PYCHOK yield
|
|
1126
|
+
if S:
|
|
1127
|
+
S += (a - b)**2 * m
|
|
1128
|
+
m *= 2
|
|
1129
|
+
else: # initial
|
|
1130
|
+
S += (a + b)**2 * _0_5
|
|
1131
|
+
return S(PI_).fover(a + b)
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
def _rG3(inst, x, y, z): # 3-arg version
|
|
1135
|
+
'''(INTERNAL) C{x}, C{y} and C{z} all non-zero, see C{.fRG}.
|
|
1136
|
+
'''
|
|
1137
|
+
R = _RF3(inst, x, y, z) * z
|
|
1138
|
+
rd = (x - z) * (z - y) # - (y - z)
|
|
1139
|
+
if rd: # Carlson, eq 1.7
|
|
1140
|
+
R += _RD(inst, x, y, z, _3_0 / rd)
|
|
1141
|
+
R += sqrt(x * y / z)
|
|
1142
|
+
return R.fover(_2_0)
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
def _RJ(inst, x, y, z, p, *over):
|
|
1146
|
+
'''(INTERNAL) Carlson, eqs 2.17 - 2.25.
|
|
1147
|
+
'''
|
|
1148
|
+
def _xyzp(x, y, z, p):
|
|
1149
|
+
return (x + p) * (y + p) * (z + p)
|
|
1150
|
+
|
|
1151
|
+
L = _L(x, y, z, p)
|
|
1152
|
+
n = neg(_xyzp(x, y, z, -p))
|
|
1153
|
+
S = _D()
|
|
1154
|
+
for a, m, _, s in L.amrs4(inst, True, _TolRD):
|
|
1155
|
+
if s:
|
|
1156
|
+
d = _xyzp(*s)
|
|
1157
|
+
if d:
|
|
1158
|
+
if n:
|
|
1159
|
+
rc = _rC(inst, _1_0, n / d**2 + _1_0)
|
|
1160
|
+
n *= _1_64th # /= chokes PyChecker
|
|
1161
|
+
else:
|
|
1162
|
+
rc = _1_0 # == _rC(None, _1_0, _1_0)
|
|
1163
|
+
S += rc / (d * m)
|
|
1164
|
+
else: # PYCHOK no cover
|
|
1165
|
+
return NAN
|
|
1166
|
+
x, y, z = L.rescale(a * m, x, y, z)
|
|
1167
|
+
p = Fsum(x, y, z).fover(_N_2_0)
|
|
1168
|
+
p2 = p**2
|
|
1169
|
+
p3 = p2 * p
|
|
1170
|
+
E2 = Fsum(x * y, x * z, y * z, -p2 * _3_0)
|
|
1171
|
+
E2p = E2 * p
|
|
1172
|
+
xyz = x * y * z
|
|
1173
|
+
return _Horner(S(_6_0), sqrt(a) * a * m, E2,
|
|
1174
|
+
Fsum(p3 * _4_0, xyz, E2p * _2_0),
|
|
1175
|
+
Fsum(p3 * _3_0, E2p, xyz * _2_0).fmul(p),
|
|
1176
|
+
xyz * p2, *over) # Fsum
|
|
1177
|
+
|
|
1178
|
+
# **) MIT License
|
|
1179
|
+
#
|
|
1180
|
+
# Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
|
|
1181
|
+
#
|
|
1182
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
1183
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
1184
|
+
# to deal in the Software without restriction, including without limitation
|
|
1185
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
1186
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
1187
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
1188
|
+
#
|
|
1189
|
+
# The above copyright notice and this permission notice shall be included
|
|
1190
|
+
# in all copies or substantial portions of the Software.
|
|
1191
|
+
#
|
|
1192
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
1193
|
+
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1194
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
1195
|
+
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
1196
|
+
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
1197
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
1198
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|