pygeodesy 25.12.31__py2.py3-none-any.whl → 26.2.2__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/__init__.py +9 -9
- pygeodesy/albers.py +5 -5
- pygeodesy/auxilats/auxDLat.py +2 -3
- pygeodesy/auxilats/auxLat.py +7 -8
- pygeodesy/cartesianBase.py +2 -2
- pygeodesy/constants.py +6 -1
- pygeodesy/datums.py +5 -8
- pygeodesy/ellipsoids.py +9 -8
- pygeodesy/elliptic.py +543 -149
- pygeodesy/fmath.py +2 -2
- pygeodesy/formy.py +10 -249
- pygeodesy/fsums.py +43 -27
- pygeodesy/geod3solve.py +18 -3
- pygeodesy/geoids.py +120 -73
- pygeodesy/heights.py +8 -7
- pygeodesy/internals.py +10 -3
- pygeodesy/lazily.py +13 -6
- pygeodesy/lcc.py +3 -7
- pygeodesy/named.py +13 -9
- pygeodesy/trf.py +1 -1
- pygeodesy/triaxials/bases.py +64 -42
- pygeodesy/triaxials/triaxial3.py +40 -43
- pygeodesy/triaxials/triaxial5.py +17 -49
- pygeodesy/utily.py +7 -7
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/METADATA +10 -10
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/RECORD +28 -28
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/WHEEL +0 -0
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/top_level.txt +0 -0
pygeodesy/elliptic.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
|
-
u'''I{Karney}'s elliptic
|
|
4
|
+
u'''I{Karney}'s elliptic integrals and elliptic and ellipse functions.
|
|
5
5
|
|
|
6
6
|
Class L{Elliptic} transcoded from I{Charles Karney}'s C++ class U{EllipticFunction
|
|
7
7
|
<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1EllipticFunction.html>}
|
|
@@ -76,36 +76,38 @@ U{22<https://DLMF.NIST.gov/22>}.
|
|
|
76
76
|
from __future__ import division as _; del _ # noqa: E702 ;
|
|
77
77
|
|
|
78
78
|
from pygeodesy.basics import copysign0, map2, neg, neg_
|
|
79
|
-
from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, \
|
|
80
|
-
_EPStol as _TolJAC, _0_0, _0_25, \
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
from pygeodesy.constants import _EPSjam as _TolJAM # PYCHOK used!
|
|
79
|
+
from pygeodesy.constants import EPS, EPS_2, INF, NAN, PI, PI_2, PI_4, PI2, \
|
|
80
|
+
_EPStol as _TolJAC, _0_0, _0_25, _0_5, _1_0, \
|
|
81
|
+
_2_0, _3_0, _4_0, _6_0, _8_0, _64_0, _180_0, \
|
|
82
|
+
_360_0, _flipsign, _over, _1_over
|
|
83
|
+
from pygeodesy.constants import _10_0, _EPSjam as _TolJAM, MANT_DIG as _DIG53 # PYCHOK used!
|
|
85
84
|
# from pygeodesy.errors import _ValueError # from .fsums
|
|
86
|
-
from pygeodesy.fmath import favg, Fdot_,
|
|
85
|
+
from pygeodesy.fmath import favg, Fdot, Fdot_, fhorner, hypot, hypot1, \
|
|
86
|
+
zqrt, _operator
|
|
87
87
|
from pygeodesy.fsums import Fsum, _fsum, _ValueError
|
|
88
88
|
from pygeodesy.internals import _Enum, typename
|
|
89
|
-
from pygeodesy.interns import NN, _delta_, _DOT_, _f_, _invalid_, \
|
|
90
|
-
|
|
89
|
+
from pygeodesy.interns import NN, _delta_, _DOT_, _f_, _invalid_, _invokation_, \
|
|
90
|
+
_negative_, _SPACE_
|
|
91
91
|
from pygeodesy.karney import _K_2_0, _norm180, _signBit, _sincos2
|
|
92
|
-
|
|
93
|
-
from pygeodesy.named import _Named, _NamedTuple,
|
|
94
|
-
from pygeodesy.props import _allPropertiesOf_n, Property_RO,
|
|
92
|
+
from pygeodesy.lazily import _ALL_LAZY, _FOR_DOCS
|
|
93
|
+
from pygeodesy.named import callername, _Named, _NamedTuple, Fmt, unstr
|
|
94
|
+
from pygeodesy.props import _allPropertiesOf_n, Property_RO, property_ROnce, \
|
|
95
|
+
_update_all
|
|
95
96
|
# from pygeodesy.streprs import Fmt, unstr # from .named
|
|
96
97
|
from pygeodesy.units import Scalar, Scalar_
|
|
97
98
|
from pygeodesy.utily import atan2 # sincos2 as _sincos2
|
|
98
99
|
|
|
99
100
|
from math import asin, asinh, atan, ceil, cosh, fabs, floor, radians, \
|
|
100
101
|
sin, sinh, sqrt, tan, tanh # tan as _tan
|
|
102
|
+
# import operator as _operator # from .fmath
|
|
101
103
|
|
|
102
104
|
__all__ = _ALL_LAZY.elliptic
|
|
103
|
-
__version__ = '
|
|
105
|
+
__version__ = '26.01.20'
|
|
104
106
|
|
|
105
107
|
_TolRD = zqrt(EPS * 0.002)
|
|
106
108
|
_TolRF = zqrt(EPS * 0.030)
|
|
107
109
|
_TolRG0 = _TolJAC * 2.7
|
|
108
|
-
|
|
110
|
+
_MAXIT = 32 # Max depth, 6-18 sufficient
|
|
109
111
|
|
|
110
112
|
|
|
111
113
|
class _Cs(_Enum):
|
|
@@ -114,6 +116,314 @@ class _Cs(_Enum):
|
|
|
114
116
|
pass
|
|
115
117
|
|
|
116
118
|
|
|
119
|
+
class Elliperim(object):
|
|
120
|
+
'''Singleton with various methods to compute the perimeter of an ellipse.
|
|
121
|
+
'''
|
|
122
|
+
_Ek = None
|
|
123
|
+
_k = _2_0 # 0 < _k < 1
|
|
124
|
+
_TOL53 = sqrt(EPS_2) # sqrt(pow(_0_5, _DIG53))
|
|
125
|
+
_TOL53_53 = _TOL53 / _DIG53 # "flat" b/a tolerance, 1.9e-10
|
|
126
|
+
# assert _DIG53 == 53
|
|
127
|
+
|
|
128
|
+
def AGM(self, a, b, maxit=_DIG53):
|
|
129
|
+
'''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using the U{AGM
|
|
130
|
+
<https://PaulBourke.net/geometry/ellipsecirc>} (Arithmetic-Geometric Mean) method.
|
|
131
|
+
|
|
132
|
+
@kwarg maxit: Number of iterations (C{int}).
|
|
133
|
+
|
|
134
|
+
@return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
135
|
+
|
|
136
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}} or no convergence for B{C{maxit}} iterations.
|
|
137
|
+
'''
|
|
138
|
+
_, p, a, b = self._pab4(a, b)
|
|
139
|
+
if p is None:
|
|
140
|
+
t = self._TOL53
|
|
141
|
+
m = -1
|
|
142
|
+
c = a + b
|
|
143
|
+
ds = [c**2]
|
|
144
|
+
_d = ds.append
|
|
145
|
+
for _ in range(maxit): # 4..5 trips
|
|
146
|
+
b = sqrt(a * b)
|
|
147
|
+
a = c * _0_5
|
|
148
|
+
c = a + b
|
|
149
|
+
d = a - b
|
|
150
|
+
m *= 2
|
|
151
|
+
_d(d**2 * m)
|
|
152
|
+
if d <= (b * t):
|
|
153
|
+
break
|
|
154
|
+
else: # PYCHOK no cover
|
|
155
|
+
raise _convergenceError(maxit, _over(d, b), t)
|
|
156
|
+
p = _over(_fsum(ds) * PI, c) # nonfinites=True
|
|
157
|
+
return p
|
|
158
|
+
|
|
159
|
+
def arc(self, a, b, deg2, deg1=0):
|
|
160
|
+
'''Compute the length of U{elliptic arc<https://www.JohnDCook.com/blog/2022/11/02/elliptic-arc-length/>}
|
|
161
|
+
C{(B{deg2} - B{deg1})}, both counter-clockwise from semi-axis B{C{a}} to B{C{b}} of the ellipse.
|
|
162
|
+
|
|
163
|
+
@arg deg2: End angle of the elliptic arc (C{degrees}).
|
|
164
|
+
@kwarg deg1: Start angle of the elliptic arc (C{degrees}).
|
|
165
|
+
|
|
166
|
+
@return: Arc length, signed (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
167
|
+
|
|
168
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
169
|
+
'''
|
|
170
|
+
return self.arc_(a, b, radians(deg2), (radians(deg1) if deg1 else _0_0))
|
|
171
|
+
|
|
172
|
+
def arc_(self, a, b, rad2, rad1=0):
|
|
173
|
+
'''Compute the length of U{elliptic arc<https://www.JohnDCook.com/blog/2022/11/02/elliptic-arc-length/>}
|
|
174
|
+
C{(B{rad2} - B{rad1})}, both counter-clockwise from semi-axis B{C{a}} to B{C{b}} of the ellipse.
|
|
175
|
+
|
|
176
|
+
@arg rad2: End angle of the elliptic arc (C{radians}).
|
|
177
|
+
@kwarg rad1: Start angle of the elliptic arc (C{radians}).
|
|
178
|
+
|
|
179
|
+
@return: Arc length, signed (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
180
|
+
|
|
181
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
182
|
+
'''
|
|
183
|
+
r, p, a, b = self._pab4(a, b)
|
|
184
|
+
if p is None:
|
|
185
|
+
_e = self._ellipe or self._ellipE
|
|
186
|
+
k = (b / a)**2
|
|
187
|
+
r = PI_2 if r else _0_0
|
|
188
|
+
p = self._arc(_e, k, rad2 + r)
|
|
189
|
+
r += rad1
|
|
190
|
+
if r:
|
|
191
|
+
p -= self._arc(_e, k, r)
|
|
192
|
+
p *= a
|
|
193
|
+
else:
|
|
194
|
+
p *= (rad2 - rad1) / PI2
|
|
195
|
+
return p
|
|
196
|
+
|
|
197
|
+
def _arc(self, _e, k, r):
|
|
198
|
+
t, r = divmod(r, PI2)
|
|
199
|
+
p = _e(k, r)
|
|
200
|
+
if t: # + t * perimeter
|
|
201
|
+
t *= _e(k) * _4_0
|
|
202
|
+
p += t
|
|
203
|
+
return p
|
|
204
|
+
|
|
205
|
+
def Arc43(self, a, b):
|
|
206
|
+
'''Compute the perimeter (and arcs) of an ellipse with semi-axes B{C{a}} and B{C{b}}
|
|
207
|
+
using the U{4-Arc<https://PaulBourke.net/geometry/ellipsecirc>} approximation.
|
|
208
|
+
|
|
209
|
+
@return: 3-Tuple C{(p, Ra, Rb)} with perimeter C{p}, arc radius C{Ra} at the
|
|
210
|
+
major and arc radius C{Rb} at the minor semi-axis (C{meter}, same
|
|
211
|
+
units as semi-axes B{C{a}} and B{C{b}}.
|
|
212
|
+
|
|
213
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
214
|
+
'''
|
|
215
|
+
r, p, a, b = self._pab4(a, b)
|
|
216
|
+
if p is None:
|
|
217
|
+
h = hypot(a, b)
|
|
218
|
+
p = atan2(b, a)
|
|
219
|
+
s, c = _sincos2(p)
|
|
220
|
+
L = (h - (a - b)) * _0_5
|
|
221
|
+
Ra = _over(L, c)
|
|
222
|
+
Rb = _over(h - L, s)
|
|
223
|
+
p = (p * Rb + (PI_2 - p) * Ra) * _4_0
|
|
224
|
+
elif a > b: # flat
|
|
225
|
+
Ra, Rb = _0_0, _1_over(b) # INF
|
|
226
|
+
else: # circle
|
|
227
|
+
Ra, Rb = a, b
|
|
228
|
+
return (p, Rb, Ra) if r else (p, Ra, Rb)
|
|
229
|
+
|
|
230
|
+
# def CR(self, a, b):
|
|
231
|
+
# '''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using U{Rackauckas'
|
|
232
|
+
# <https://www.ChrisRackauckas.com/assets/Papers/ChrisRackauckas-The_Circumference_of_an_Ellipse.pdf>}
|
|
233
|
+
# approximation, also U{here<https://ExtremeLearning.com.AU/a-formula-for-the-perimeter-of-an-ellipse>}.
|
|
234
|
+
#
|
|
235
|
+
# @return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
236
|
+
#
|
|
237
|
+
# @raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
238
|
+
# '''
|
|
239
|
+
# _, p, a, b = self._pab4(a, b)
|
|
240
|
+
# if p is None:
|
|
241
|
+
# p = a + b
|
|
242
|
+
# h = ((a - b) / p)**2
|
|
243
|
+
# p *= (fhorner(h, 135168, -85760, -5568, 3867) /
|
|
244
|
+
# fhorner(h, 135168, -119552, 22208, 345)) * PI
|
|
245
|
+
# return p
|
|
246
|
+
|
|
247
|
+
def E2k(self, a, b):
|
|
248
|
+
'''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using L{E(k)
|
|
249
|
+
<Elliptic.cE>}, the complete C{elliptic} integral of the 2nd kind.
|
|
250
|
+
|
|
251
|
+
@return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
252
|
+
|
|
253
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
254
|
+
'''
|
|
255
|
+
return self._ellip2k(a, b, self._ellipE)
|
|
256
|
+
|
|
257
|
+
def e2k(self, a, b, E_ab=None):
|
|
258
|
+
'''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using U{SciPy's
|
|
259
|
+
ellipe<https://www.JohnDCook.com/perimeter_ellipse.html>} function or method
|
|
260
|
+
C{E_ab}, otherwise C{None}.
|
|
261
|
+
|
|
262
|
+
@kwarg E_ab: Alternate C{Elliperim}C{(a, b)} method to use in case C{SciPy's
|
|
263
|
+
ellipe} is not available.
|
|
264
|
+
|
|
265
|
+
@return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
266
|
+
|
|
267
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
268
|
+
'''
|
|
269
|
+
p = self._ellipe
|
|
270
|
+
if callable(p): # p is not None
|
|
271
|
+
p = self._ellip2k(a, b, p)
|
|
272
|
+
elif callable(E_ab): # and E_ab is not Elliperim.e2k
|
|
273
|
+
p = E_ab(a, b)
|
|
274
|
+
return p
|
|
275
|
+
|
|
276
|
+
def _ellipE(self, k, phi=None):
|
|
277
|
+
'''(INTERNAL) Get the in- C{fE(phi, k)} or complete C{cE(k)} integral of the 2nd kind.
|
|
278
|
+
'''
|
|
279
|
+
if self._k != k: # or self._Ek is None
|
|
280
|
+
self._k = k
|
|
281
|
+
self._Ek = _Elliptic(k)
|
|
282
|
+
return self._Ek.cE if phi is None else self._Ek.fE(phi)
|
|
283
|
+
|
|
284
|
+
@property_ROnce
|
|
285
|
+
def _ellipe(self):
|
|
286
|
+
'''(INTERNAL) Wrap functions C{scipy.special.ellipe} and C{-.ellipeinc}, I{once}.
|
|
287
|
+
'''
|
|
288
|
+
try:
|
|
289
|
+
from scipy.special import ellipe, ellipeinc
|
|
290
|
+
|
|
291
|
+
def _ellipe(k, phi=None):
|
|
292
|
+
m = _1_0 - k
|
|
293
|
+
p = ellipe(m) if phi is None else ellipeinc(phi, m)
|
|
294
|
+
return float(p)
|
|
295
|
+
|
|
296
|
+
except (AttributeError, ImportError):
|
|
297
|
+
_ellipe = None
|
|
298
|
+
return _ellipe # overwrite property_ROnce
|
|
299
|
+
|
|
300
|
+
def _ellip2k(self, a, b, _ellip):
|
|
301
|
+
'''(INTERNAL) Helper for methods C{E2k} and C{e2k}.
|
|
302
|
+
'''
|
|
303
|
+
_, p, a, b = self._pab4(a, b)
|
|
304
|
+
if p is None: # see .ellipsoids.Ellipsoid.L
|
|
305
|
+
k = (b / a)**2
|
|
306
|
+
p = _ellip(k) * a * _4_0
|
|
307
|
+
return p
|
|
308
|
+
|
|
309
|
+
def GK(self, a, b):
|
|
310
|
+
'''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using the U{Gauss-Kummer
|
|
311
|
+
<https://www.JohnDCook.com/blog/2023/05/28/approximate-ellipse-perimeter>} series, and U{here
|
|
312
|
+
<https://MathWorld.Wolfram.com/Gauss-KummerSeries.html>}, C{B{b / a} > 0.75}.
|
|
313
|
+
|
|
314
|
+
@return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
315
|
+
|
|
316
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
317
|
+
'''
|
|
318
|
+
p, h = self._ph2(a, b)
|
|
319
|
+
if h:
|
|
320
|
+
p *= fhorner(h**2, *self._GKs) * PI
|
|
321
|
+
return p
|
|
322
|
+
|
|
323
|
+
@property_ROnce
|
|
324
|
+
def _GKs(self):
|
|
325
|
+
'''(INTERNAL) Compute the Gauss-Kummer coefficients, I{once} from U{numerators
|
|
326
|
+
<https://OEIS.org/A056981>} and U{denominators<https://OEIS.org/A056982>}.
|
|
327
|
+
'''
|
|
328
|
+
return (1, 1 / 4, 1 / 64, 1 / 256, 25 / 16384, 49 / 65536,
|
|
329
|
+
441 / 1048576, 1089 / 4194304) # overwrite property_ROnce
|
|
330
|
+
|
|
331
|
+
def HG(self, a, b, maxit=_DIG53):
|
|
332
|
+
'''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using the U{HG
|
|
333
|
+
<https://web.Tecnico.ULisboa.PT/~mcasquilho/compute/com/,ellips/PerimeterOfEllipse.pdf>}
|
|
334
|
+
(HyperGeometric Gauss-Kummer) series.
|
|
335
|
+
|
|
336
|
+
@kwarg maxit: Number of iterations (C{int}), sufficient for C{B{b / a} > 0.125}.
|
|
337
|
+
|
|
338
|
+
@return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
339
|
+
|
|
340
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}} or no convergence for B{C{maxit}} iterations.
|
|
341
|
+
'''
|
|
342
|
+
p, h = self._ph2(a, b)
|
|
343
|
+
if h:
|
|
344
|
+
hs = self._HGs(h, max(maxit, _DIG53))
|
|
345
|
+
p *= _fsum(hs) * PI # nonfinites=True
|
|
346
|
+
return p
|
|
347
|
+
|
|
348
|
+
def _HGs(self, h, maxit):
|
|
349
|
+
'''(INTERNAL) Yield the C{HG} terms.
|
|
350
|
+
'''
|
|
351
|
+
s = _1_0
|
|
352
|
+
yield s
|
|
353
|
+
p = t = -1
|
|
354
|
+
for u in range(-1, maxit * 2, 2):
|
|
355
|
+
t *= u / (u + 3) * h
|
|
356
|
+
t2 = t**2
|
|
357
|
+
s += t2
|
|
358
|
+
yield t2
|
|
359
|
+
if s == p: # 44 trips
|
|
360
|
+
break
|
|
361
|
+
p = s
|
|
362
|
+
else: # PYCHOK no cover
|
|
363
|
+
raise _convergenceError(maxit, s, s - t2)
|
|
364
|
+
|
|
365
|
+
# def LS(self, a, b):
|
|
366
|
+
# '''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using the U{Linderholm-Segal
|
|
367
|
+
# <https://www.JohnDCook.com/blog/2021/03/24/perimeter-of-an-ellipse>} formula, aka C{3/2 norm}.
|
|
368
|
+
#
|
|
369
|
+
# @return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
370
|
+
#
|
|
371
|
+
# @raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
372
|
+
# '''
|
|
373
|
+
# _, p, a, b = self._pab4(a, b)
|
|
374
|
+
# if p is None:
|
|
375
|
+
# n = pow(a, _1_5) + pow(b, _1_5)
|
|
376
|
+
# p = pow(n * _0_5, _2_3rd) * PI2
|
|
377
|
+
# return p
|
|
378
|
+
|
|
379
|
+
def _pab4(self, a, b):
|
|
380
|
+
r = a < b
|
|
381
|
+
if r:
|
|
382
|
+
a, b = b, a
|
|
383
|
+
if a > b:
|
|
384
|
+
if b > (a * self._TOL53_53):
|
|
385
|
+
p = None
|
|
386
|
+
elif b < 0: # PYCHOK no cover
|
|
387
|
+
t = callername() # underOK=True
|
|
388
|
+
t = _DOT_(typename(self), t)
|
|
389
|
+
t = unstr(t, b, a) if r else \
|
|
390
|
+
unstr(t, a, b)
|
|
391
|
+
raise _ValueError(t)
|
|
392
|
+
else: # "flat"
|
|
393
|
+
p = a * _4_0
|
|
394
|
+
else: # circle
|
|
395
|
+
p = a * PI2
|
|
396
|
+
return r, p, a, b
|
|
397
|
+
|
|
398
|
+
def _ph2(self, a, b):
|
|
399
|
+
_, p, a, b = self._pab4(a, b)
|
|
400
|
+
if p is None:
|
|
401
|
+
p = a + b
|
|
402
|
+
h = (a - b) / p
|
|
403
|
+
else:
|
|
404
|
+
h = None
|
|
405
|
+
return p, h
|
|
406
|
+
|
|
407
|
+
def R2(self, a, b):
|
|
408
|
+
'''Compute the perimeter of an ellipse with semi-axes B{C{a}} and B{C{b}} using U{Ramanujan's
|
|
409
|
+
2nd<https://PaulBourke.net/geometry/ellipsecirc>} approximation, C{B{b / a} > 0.9}.
|
|
410
|
+
|
|
411
|
+
@return: Perimeter (C{meter}, same units as semi-axes B{C{a}} and B{C{b}}).
|
|
412
|
+
|
|
413
|
+
@raise ValueError: Invalid B{C{a}} or B{C{b}}.
|
|
414
|
+
'''
|
|
415
|
+
p, h = self._ph2(a, b)
|
|
416
|
+
if h:
|
|
417
|
+
h *= _3_0 * h
|
|
418
|
+
h /= sqrt(_4_0 - h) + _10_0 # /= chokes PyChecker?
|
|
419
|
+
p *= (h + _1_0) * PI
|
|
420
|
+
return p
|
|
421
|
+
|
|
422
|
+
if not _FOR_DOCS: # PYCHOK force epydoc
|
|
423
|
+
Elliperim = Elliperim() # singleton
|
|
424
|
+
del _FOR_DOCS
|
|
425
|
+
|
|
426
|
+
|
|
117
427
|
class Elliptic(_Named):
|
|
118
428
|
'''Elliptic integrals and functions.
|
|
119
429
|
|
|
@@ -154,31 +464,55 @@ class Elliptic(_Named):
|
|
|
154
464
|
'''
|
|
155
465
|
return self._alphap2
|
|
156
466
|
|
|
467
|
+
def _B3(self, x):
|
|
468
|
+
'''(INTERNAL) Bulirsch' sncndn routine.
|
|
469
|
+
'''
|
|
470
|
+
# Numerische Mathematik 7, 1965, p 89
|
|
471
|
+
# implements DLMF Eqs 22.17.2 - 22.17.4
|
|
472
|
+
c, d, cd, mn = self._B4
|
|
473
|
+
sn, cn = _sincos2(x * cd)
|
|
474
|
+
dn = _1_0
|
|
475
|
+
if sn:
|
|
476
|
+
a = cn / sn
|
|
477
|
+
c *= a
|
|
478
|
+
for m, n in mn:
|
|
479
|
+
a *= c
|
|
480
|
+
c *= dn
|
|
481
|
+
dn = (n + a) / (m + a)
|
|
482
|
+
a = c / m
|
|
483
|
+
a = _1_over(hypot1(c))
|
|
484
|
+
sn = _flipsign(a, sn)
|
|
485
|
+
cn = sn * c
|
|
486
|
+
if d: # and _signBit(self.kp2): # implied
|
|
487
|
+
cn, dn = dn, cn
|
|
488
|
+
sn = sn / d # /= chokes PyChecker
|
|
489
|
+
return sn, cn, dn
|
|
490
|
+
|
|
157
491
|
@Property_RO
|
|
158
|
-
def
|
|
492
|
+
def _B4(self):
|
|
159
493
|
'''(INTERNAL) Get Bulirsch' 4-tuple C{(c, d, cd, mn)}.
|
|
160
494
|
'''
|
|
161
|
-
|
|
495
|
+
a = p = _1_0
|
|
496
|
+
b, d = self.kp2, 0 # kp2 >= 0 always here
|
|
162
497
|
if _signBit(b): # PYCHOK no cover
|
|
163
|
-
d =
|
|
164
|
-
b =
|
|
165
|
-
d =
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
498
|
+
d = a - b
|
|
499
|
+
b = neg(b / d)
|
|
500
|
+
d = sqrt(d)
|
|
501
|
+
mn = []
|
|
502
|
+
_mn = mn.append
|
|
503
|
+
for i in range(1, _MAXIT): # GEOGRAPHICLIB_PANIC
|
|
504
|
+
b = sqrt(p * b)
|
|
505
|
+
_mn((a, b))
|
|
170
506
|
c = favg(a, b)
|
|
171
507
|
r = fabs(a - b)
|
|
172
|
-
if r <= (a * _TolJAC): # 6 trips, quadratic
|
|
508
|
+
if r <= (a * _TolJAC): # 4..6 trips, quadratic
|
|
173
509
|
self._iteration += i
|
|
174
510
|
break
|
|
175
|
-
|
|
176
|
-
b *= a
|
|
177
|
-
a = c
|
|
511
|
+
p, a = a, c
|
|
178
512
|
else: # PYCHOK no cover
|
|
179
|
-
raise _convergenceError(r
|
|
513
|
+
raise _convergenceError(_MAXIT, _over(r, p), _TolJAC)
|
|
180
514
|
cd = (c * d) if d else c
|
|
181
|
-
return c, d, cd, tuple(reversed(
|
|
515
|
+
return c, d, cd, tuple(reversed(mn))
|
|
182
516
|
|
|
183
517
|
@Property_RO
|
|
184
518
|
def cD(self):
|
|
@@ -202,15 +536,15 @@ class Elliptic(_Named):
|
|
|
202
536
|
cD = float(D)
|
|
203
537
|
# Complete elliptic integral E(k), Carlson eq. 4.2
|
|
204
538
|
# <https://DLMF.NIST.gov/19.25.E1>
|
|
205
|
-
cE =
|
|
539
|
+
cE = self._cE(kp2)
|
|
206
540
|
# Complete elliptic integral K(k), Carlson eq. 4.1
|
|
207
541
|
# <https://DLMF.NIST.gov/19.25.E1>
|
|
208
|
-
cK =
|
|
542
|
+
cK = self._cK(kp2)
|
|
209
543
|
cKE = float(D.fmul(k2))
|
|
210
544
|
eps = k2 / (sqrt(kp2) + _1_0)**2
|
|
211
545
|
|
|
212
546
|
except Exception as X:
|
|
213
|
-
raise _ellipticError(self
|
|
547
|
+
raise _ellipticError(self, k2=k2, kp2=kp2, cause=X)
|
|
214
548
|
else:
|
|
215
549
|
cD = cK = cKE = INF
|
|
216
550
|
cE = _1_0
|
|
@@ -230,6 +564,9 @@ class Elliptic(_Named):
|
|
|
230
564
|
'''
|
|
231
565
|
return self._cDEKEeps.cE
|
|
232
566
|
|
|
567
|
+
def _cE(self, kp2): # compl integr 2nd kind
|
|
568
|
+
return _rG2(kp2, _1_0, self, PI_=PI_2)
|
|
569
|
+
|
|
233
570
|
@Property_RO
|
|
234
571
|
def cG(self):
|
|
235
572
|
'''Get Legendre's complete geodesic longitude integral
|
|
@@ -274,8 +611,8 @@ class Elliptic(_Named):
|
|
|
274
611
|
cH = float(_RD(_0_0, _1_0, kp2, _3_0 / kp2, self)) if kp2 else _1_0
|
|
275
612
|
|
|
276
613
|
except Exception as X:
|
|
277
|
-
raise _ellipticError(self
|
|
278
|
-
|
|
614
|
+
raise _ellipticError(self, kp2=kp2, alpha2 =alpha2,
|
|
615
|
+
alphap2=alphap2, cause=X)
|
|
279
616
|
return _Cs(cG=cG, cH=cH, cPi=cPi)
|
|
280
617
|
|
|
281
618
|
@Property_RO
|
|
@@ -292,6 +629,9 @@ class Elliptic(_Named):
|
|
|
292
629
|
'''
|
|
293
630
|
return self._cDEKEeps.cK
|
|
294
631
|
|
|
632
|
+
def _cK(self, kp2): # compl integr 1st kind
|
|
633
|
+
return _rF2(kp2, _1_0, self)
|
|
634
|
+
|
|
295
635
|
@Property_RO
|
|
296
636
|
def cKE(self):
|
|
297
637
|
'''Get the difference between the complete integrals of the
|
|
@@ -414,24 +754,24 @@ class Elliptic(_Named):
|
|
|
414
754
|
phi = PI * r / E2 # phi in [-PI_2, PI_2)
|
|
415
755
|
Phi = Fsum(phi)
|
|
416
756
|
# first order correction
|
|
417
|
-
phi = Phi.fsum_(
|
|
757
|
+
phi = Phi.fsum_(-sin(phi * _2_0) * self.eps * _0_5)
|
|
418
758
|
# self._iteration = 0
|
|
419
759
|
# For kp2 close to zero use asin(r / cE) or J. P. Boyd,
|
|
420
760
|
# Applied Math. and Computation 218, 7005-7013 (2012)
|
|
421
761
|
# <https://DOI.org/10.1016/j.amc.2011.12.021>
|
|
422
762
|
_Phi2 = Phi.fsum2f_ # aggregate
|
|
423
|
-
for i in range(1,
|
|
763
|
+
for i in range(1, _MAXIT): # GEOGRAPHICLIB_PANIC
|
|
424
764
|
sn, cn, dn = self._sncndn3(phi)
|
|
425
765
|
if dn:
|
|
426
766
|
sn = self.fE(sn, cn, dn)
|
|
427
767
|
phi, d = _Phi2((r - sn) / dn)
|
|
428
768
|
else: # PYCHOK no cover
|
|
429
|
-
d = _0_0 # XXX
|
|
769
|
+
d = _0_0 # XXX continue?
|
|
430
770
|
if fabs(d) < _TolJAC: # 3-4 trips
|
|
431
771
|
self._iteration += i
|
|
432
772
|
break
|
|
433
773
|
else: # PYCHOK no cover
|
|
434
|
-
raise _convergenceError(d, _TolJAC)
|
|
774
|
+
raise _convergenceError(_MAXIT, d, _TolJAC)
|
|
435
775
|
return Phi.fsum_(n * PI) if n else phi
|
|
436
776
|
|
|
437
777
|
@Property_RO
|
|
@@ -698,7 +1038,8 @@ class Elliptic(_Named):
|
|
|
698
1038
|
x *= r # phi
|
|
699
1039
|
for a, c in ac:
|
|
700
1040
|
p = x
|
|
701
|
-
|
|
1041
|
+
a = asin(c * sin(x) / a)
|
|
1042
|
+
x = favg(a, x)
|
|
702
1043
|
if self.k2 < 0: # Sala Eq. 5.8
|
|
703
1044
|
x = p - x
|
|
704
1045
|
else: # PYCHOK no cover
|
|
@@ -714,20 +1055,22 @@ class Elliptic(_Named):
|
|
|
714
1055
|
# assert b and c
|
|
715
1056
|
if c < 0: # Sala Eq. 5.8
|
|
716
1057
|
r = sqrt(b)
|
|
717
|
-
b =
|
|
1058
|
+
b = _1_over(b)
|
|
718
1059
|
# c *= b # unused
|
|
719
|
-
ac
|
|
720
|
-
|
|
1060
|
+
ac = [] # [(a, sqrt(c))] unused
|
|
1061
|
+
_ac = ac.append
|
|
1062
|
+
for _ in range(_MAXIT): # GEOGRAPHICLIB_PANIC
|
|
721
1063
|
b = sqrt(a * b)
|
|
722
1064
|
c = favg(a, -b)
|
|
723
1065
|
a = favg(a, b) # == PI_2 / K
|
|
724
|
-
|
|
725
|
-
if c <= (a * _TolJAM): # 7
|
|
726
|
-
self._iteration += i
|
|
1066
|
+
_ac((a, c))
|
|
1067
|
+
if c <= (a * _TolJAM): # 7..18 trips, quadratic
|
|
727
1068
|
break
|
|
728
1069
|
else: # PYCHOK no cover
|
|
729
|
-
raise _convergenceError(c
|
|
730
|
-
|
|
1070
|
+
raise _convergenceError(_MAXIT, _over(c, a), _TolJAM)
|
|
1071
|
+
i = len(ac)
|
|
1072
|
+
r *= 2**i * a
|
|
1073
|
+
self._iteration += i
|
|
731
1074
|
return r, tuple(reversed(ac))
|
|
732
1075
|
|
|
733
1076
|
@Property_RO
|
|
@@ -811,30 +1154,11 @@ class Elliptic(_Named):
|
|
|
811
1154
|
if self.kp2:
|
|
812
1155
|
if jam: # Jacobi amplitude, C++ v 2.4
|
|
813
1156
|
sn, cn, dn = self._sncndn3(self._jam(x))
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
# Numerische Mathematik 7, 78-90 (1965).
|
|
817
|
-
# Implements DLMF Eqs 22.17.2 - 22.17.4
|
|
818
|
-
c, d, cd, mn = self._b4
|
|
819
|
-
sn, cn = _sincos2(x * cd)
|
|
820
|
-
dn = _1_0
|
|
821
|
-
if sn:
|
|
822
|
-
a = cn / sn
|
|
823
|
-
c *= a
|
|
824
|
-
for m, n in mn:
|
|
825
|
-
a *= c
|
|
826
|
-
c *= dn
|
|
827
|
-
dn = (n + a) / (m + a)
|
|
828
|
-
a = c / m
|
|
829
|
-
a = _1_0 / hypot1(c)
|
|
830
|
-
sn = neg(a) if _signBit(sn) else a
|
|
831
|
-
cn = sn * c
|
|
832
|
-
if d: # and _signBit(self.kp2): # implied
|
|
833
|
-
cn, dn = dn, cn
|
|
834
|
-
sn = sn / d # /= chokes PyChecker
|
|
1157
|
+
else:
|
|
1158
|
+
sn, cn, dn = self._B3(x)
|
|
835
1159
|
else:
|
|
836
1160
|
sn = tanh(x) # accurate for large abs(x)
|
|
837
|
-
cn = dn =
|
|
1161
|
+
cn = dn = _1_over(cosh(x))
|
|
838
1162
|
|
|
839
1163
|
except Exception as X:
|
|
840
1164
|
raise _ellipticError(self.sncndn, x, kp2=self.kp2, cause=X)
|
|
@@ -888,6 +1212,17 @@ class Elliptic(_Named):
|
|
|
888
1212
|
except Exception as X:
|
|
889
1213
|
raise _ellipticError(Elliptic.fRF, x, y, z, cause=X)
|
|
890
1214
|
|
|
1215
|
+
@staticmethod
|
|
1216
|
+
def _fRF3RD(x, z, m): # in .auxilats.AuxDLat.DE, -.AuxLat.Rectifying
|
|
1217
|
+
y = _1_0 - m
|
|
1218
|
+
try: # float(RF(x, y, z) - RD(x, y, z, 3 / m))
|
|
1219
|
+
R = _RF3(x, y, z)
|
|
1220
|
+
if m:
|
|
1221
|
+
R -= _RD(x, y, z, _3_0 / m)
|
|
1222
|
+
except Exception as X:
|
|
1223
|
+
raise _ellipticError(Elliptic._fRF3RD, x, y, z, m, cause=X)
|
|
1224
|
+
return float(R)
|
|
1225
|
+
|
|
891
1226
|
@staticmethod
|
|
892
1227
|
def fRG(x, y, z=0):
|
|
893
1228
|
'''Symmetric or complete symmetric integral of the second kind
|
|
@@ -922,19 +1257,25 @@ class Elliptic(_Named):
|
|
|
922
1257
|
except Exception as X:
|
|
923
1258
|
raise _ellipticError(Elliptic.fRJ, x, y, z, p, cause=X)
|
|
924
1259
|
|
|
925
|
-
@staticmethod
|
|
926
|
-
def _RFRD(x, y, z, m): # in .auxilats.AuxDLat.DE, -.AuxLat.Rectifying
|
|
927
|
-
try: # float(RF(x, y, z) - RD(x, y, z, 3 / m))
|
|
928
|
-
R = _RF3(x, y, z)
|
|
929
|
-
if m:
|
|
930
|
-
R -= _RD(x, y, z, _3_0 / m)
|
|
931
|
-
except Exception as X:
|
|
932
|
-
raise _ellipticError(Elliptic._RFRD, x, y, z, m, cause=X)
|
|
933
|
-
return float(R)
|
|
934
|
-
|
|
935
1260
|
_allPropertiesOf_n(16, Elliptic) # PYCHOK assert, see Elliptic.reset
|
|
936
1261
|
|
|
937
1262
|
|
|
1263
|
+
class _Elliptic(Elliptic):
|
|
1264
|
+
'''(INTERNAL) Low overhead C{Elliptic} for C{Elliperim._ellipE}.
|
|
1265
|
+
'''
|
|
1266
|
+
_alpha2 = _0_0
|
|
1267
|
+
_alphap2 = _1_0
|
|
1268
|
+
cE = _0_0 # overide Property_RO
|
|
1269
|
+
_iteration = 0
|
|
1270
|
+
|
|
1271
|
+
def __init__(self, k): # k == kp2
|
|
1272
|
+
self._k2 = _1_0 - k
|
|
1273
|
+
self._kp2 = k # 0 < k < 1
|
|
1274
|
+
# assert self.kp2 and self.k2
|
|
1275
|
+
self.cE = self._cE(k) # override Property_RO
|
|
1276
|
+
# self.cK = self._cK(k) # ditto
|
|
1277
|
+
|
|
1278
|
+
|
|
938
1279
|
class EllipticError(_ValueError):
|
|
939
1280
|
'''Elliptic function, integral, convergence or other L{Elliptic} issue.
|
|
940
1281
|
'''
|
|
@@ -948,6 +1289,24 @@ class Elliptic3Tuple(_NamedTuple):
|
|
|
948
1289
|
_Units_ = ( Scalar, Scalar, Scalar)
|
|
949
1290
|
|
|
950
1291
|
|
|
1292
|
+
class _Hdot(dict):
|
|
1293
|
+
'''(INTERNAL) Caching helper for C{_Horner} and C{_RF3}.
|
|
1294
|
+
'''
|
|
1295
|
+
def __call__(self, F, h, *Xys):
|
|
1296
|
+
k = Xys[1] # unique key
|
|
1297
|
+
ys = self.get(k, None)
|
|
1298
|
+
if ys is None:
|
|
1299
|
+
self[k] = ys = tuple((y / h) for y in Xys[1::2])
|
|
1300
|
+
try:
|
|
1301
|
+
D = Fdot(Xys[0::2], *ys, f2product=True)
|
|
1302
|
+
except (OverflowError, TypeError, ValueError):
|
|
1303
|
+
ts = map(_operator.mul, Xys[0::2], ys)
|
|
1304
|
+
D = Fsum(*ts, nonfinites=True) # _Ksum(0, 0, *ts)
|
|
1305
|
+
return D.fmul(F) # Fsum
|
|
1306
|
+
|
|
1307
|
+
_Hdot = _Hdot() # PYCHOK singleton
|
|
1308
|
+
|
|
1309
|
+
|
|
951
1310
|
class _List(list):
|
|
952
1311
|
'''(INTERNAL) Helper for C{_RD}, C{_RF3} and C{_RJ}.
|
|
953
1312
|
'''
|
|
@@ -974,12 +1333,12 @@ class _List(list):
|
|
|
974
1333
|
a = L.a0(5 if y else 3)
|
|
975
1334
|
t = L.threshold(Tol)
|
|
976
1335
|
m = 1
|
|
977
|
-
for i in range(
|
|
1336
|
+
for i in range(_MAXIT):
|
|
978
1337
|
d = fabs(a * m)
|
|
979
1338
|
if d > t: # 3-6 trips
|
|
980
1339
|
break
|
|
981
1340
|
s = map2(sqrt, L) # sqrt(x), sqrt(y), sqrt(z) [, sqrt(p)]
|
|
982
|
-
Q =
|
|
1341
|
+
Q = _Qdot3(*s) # (s[0] * s[1], s[1] * s[2], s[2] * s[0])
|
|
983
1342
|
a = Q(a) # An = sum(An, *Q)) / 4
|
|
984
1343
|
L[:] = map(Q, L) # x = sum(x, *Q) / 4, ...
|
|
985
1344
|
if y: # yield only if used
|
|
@@ -987,7 +1346,7 @@ class _List(list):
|
|
|
987
1346
|
yield a, m, r, s # L[2] is next z
|
|
988
1347
|
m *= 4
|
|
989
1348
|
else: # PYCHOK no cover
|
|
990
|
-
raise _convergenceError(d, t, thresh=True)
|
|
1349
|
+
raise _convergenceError(_MAXIT, d, t, thresh=True)
|
|
991
1350
|
yield a, m, None, () # sentinel: same a, next m, no r and s
|
|
992
1351
|
if inst:
|
|
993
1352
|
inst._iteration += i
|
|
@@ -997,7 +1356,7 @@ class _List(list):
|
|
|
997
1356
|
'''
|
|
998
1357
|
# assert am
|
|
999
1358
|
a0 = self._a0
|
|
1000
|
-
_am =
|
|
1359
|
+
_am = _1_over(am)
|
|
1001
1360
|
for x in xs:
|
|
1002
1361
|
yield (a0 - x) * _am
|
|
1003
1362
|
|
|
@@ -1008,7 +1367,7 @@ class _List(list):
|
|
|
1008
1367
|
return max(fabs(x - a0) for x in self) / Tol
|
|
1009
1368
|
|
|
1010
1369
|
|
|
1011
|
-
# class
|
|
1370
|
+
# class _Qdot3(Fsum):
|
|
1012
1371
|
# '''(INTERNAL) "Quarter" 3-dot product.
|
|
1013
1372
|
# '''
|
|
1014
1373
|
# def __init__(self, x, y, z, *unused): # PYCHOK signature
|
|
@@ -1018,15 +1377,12 @@ class _List(list):
|
|
|
1018
1377
|
# return (self + a).fover(_4_0)
|
|
1019
1378
|
|
|
1020
1379
|
|
|
1021
|
-
class
|
|
1380
|
+
class _Qdot3(list):
|
|
1022
1381
|
'''(INTERNAL) "Quarter" 3-dot product.
|
|
1023
1382
|
'''
|
|
1024
1383
|
def __init__(self, x, y, z, *unused): # PYCHOK signature
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
except (OverflowError, TypeError, ValueError):
|
|
1028
|
-
D = Fsum(x * y, y * z, z * x, nonfinites=True)
|
|
1029
|
-
list.__init__(self, (0,) + D.partials) # NOT D.fsum2()!
|
|
1384
|
+
R = _Rdot(x, y, z, _0_0).partials
|
|
1385
|
+
list.__init__(self, (0,) + R) # NOT R.fsum2()!
|
|
1030
1386
|
|
|
1031
1387
|
def __call__(self, a):
|
|
1032
1388
|
try:
|
|
@@ -1040,31 +1396,35 @@ class _Qot3(list):
|
|
|
1040
1396
|
return _fsum(self) # nonfinites=True
|
|
1041
1397
|
|
|
1042
1398
|
|
|
1043
|
-
def
|
|
1044
|
-
'''(INTERNAL) Yield Carlson 3-tuples C{(xn, yn,
|
|
1399
|
+
def _abm3(x, y, inst=None):
|
|
1400
|
+
'''(INTERNAL) Yield Carlson 3-tuples C{(xn, yn, m)}.
|
|
1045
1401
|
'''
|
|
1046
|
-
a, b = sqrt(x), sqrt(y)
|
|
1402
|
+
a, b = sqrt(x), (sqrt(y) if y != _1_0 else y)
|
|
1047
1403
|
if b > a:
|
|
1048
1404
|
b, a = a, b
|
|
1049
|
-
|
|
1050
|
-
|
|
1405
|
+
yield a, -b, _0_5 # (x0 + y0)**2 * _0_5
|
|
1406
|
+
m = -1
|
|
1407
|
+
for i in range(_MAXIT):
|
|
1051
1408
|
d = fabs(a - b)
|
|
1052
|
-
if d <= (a * _TolRG0): #
|
|
1409
|
+
if d <= (a * _TolRG0): # 2..4 trips
|
|
1053
1410
|
break
|
|
1054
|
-
|
|
1055
|
-
a = favg(
|
|
1056
|
-
b = sqrt(
|
|
1411
|
+
p = a
|
|
1412
|
+
a = favg(p, b)
|
|
1413
|
+
b = sqrt(p * b)
|
|
1414
|
+
yield a, b, m # (xi - yi)**2 * m
|
|
1415
|
+
m *= 2
|
|
1057
1416
|
else: # PYCHOK no cover
|
|
1058
|
-
raise _convergenceError(d
|
|
1417
|
+
raise _convergenceError(_MAXIT, _over(d, p), _TolRG0)
|
|
1059
1418
|
if inst:
|
|
1060
1419
|
inst._iteration += i
|
|
1420
|
+
yield a, b, 0 # sentinel: m = 0
|
|
1061
1421
|
|
|
1062
1422
|
|
|
1063
|
-
def _convergenceError(d, tol, **thresh):
|
|
1423
|
+
def _convergenceError(maxit, d, tol, **thresh):
|
|
1064
1424
|
'''(INTERNAL) Format a no-convergence Error.
|
|
1065
1425
|
'''
|
|
1066
1426
|
t = Fmt.no_convergence(d, tol, **thresh)
|
|
1067
|
-
return
|
|
1427
|
+
return _ValueError(maxit=maxit, txt=t)
|
|
1068
1428
|
|
|
1069
1429
|
|
|
1070
1430
|
def _deltaX(sn, cn, dn, cX, fX):
|
|
@@ -1076,7 +1436,7 @@ def _deltaX(sn, cn, dn, cX, fX):
|
|
|
1076
1436
|
|
|
1077
1437
|
if _signBit(cn):
|
|
1078
1438
|
sn, cn = neg_(sn, cn)
|
|
1079
|
-
r = fX(sn, cn, dn) * PI_2
|
|
1439
|
+
r = fX(sn, cn, dn) * _over(PI_2, cX)
|
|
1080
1440
|
return r - atan2(sn, cn)
|
|
1081
1441
|
|
|
1082
1442
|
except Exception as X:
|
|
@@ -1084,6 +1444,28 @@ def _deltaX(sn, cn, dn, cX, fX):
|
|
|
1084
1444
|
raise _ellipticError(n, sn, cn, dn, cause=X)
|
|
1085
1445
|
|
|
1086
1446
|
|
|
1447
|
+
def elliperim(a, b, *deg2_1):
|
|
1448
|
+
'''Compute the perimeter or an arc of an ellipse with semi-axes C{a} and C{b} using
|
|
1449
|
+
method L{Elliperim.e2k}, L{Elliperim.E2k} or L{Elliperim.arc}.
|
|
1450
|
+
|
|
1451
|
+
@arg deg2_1: Optional, arc end and start angle (C{degrees}), see method L{Elliperim.arc}.
|
|
1452
|
+
|
|
1453
|
+
@return: The perimeter or arc length (C{scalar}, same units as C{a} and C{b}).
|
|
1454
|
+
'''
|
|
1455
|
+
return Elliperim.arc(a, b, *deg2_1) if deg2_1 else Elliperim.e2k(a, b, Elliperim.E2k)
|
|
1456
|
+
|
|
1457
|
+
|
|
1458
|
+
def elliperim_(a, b, *rad2_1):
|
|
1459
|
+
'''Compute the perimeter or an arc of an ellipse with semi-axes C{a} and C{b} using
|
|
1460
|
+
method L{Elliperim.e2k}, L{Elliperim.E2k} or L{Elliperim.arc_}.
|
|
1461
|
+
|
|
1462
|
+
@arg rad2_1: Optional, arc end and start angle (C{radians}), see method L{Elliperim.arc_}.
|
|
1463
|
+
|
|
1464
|
+
@return: The perimeter or arc length (C{scalar}, same units as C{a} and C{b}).
|
|
1465
|
+
'''
|
|
1466
|
+
return Elliperim.arc_(a, b, *rad2_1) if rad2_1 else Elliperim.e2k(a, b, Elliperim.E2k)
|
|
1467
|
+
|
|
1468
|
+
|
|
1087
1469
|
def _ellipticError(where, *args, **kwds_cause_txt):
|
|
1088
1470
|
'''(INTERNAL) Format an L{EllipticError}.
|
|
1089
1471
|
'''
|
|
@@ -1099,7 +1481,7 @@ def _ellipticError(where, *args, **kwds_cause_txt):
|
|
|
1099
1481
|
return EllipticError(u, cause=x, txt=t)
|
|
1100
1482
|
|
|
1101
1483
|
|
|
1102
|
-
def
|
|
1484
|
+
def _Hsum(S, e1, E2, E3, E4, E5, over):
|
|
1103
1485
|
'''(INTERNAL) Horner-like form for C{_RD} and C{_RJ} below.
|
|
1104
1486
|
'''
|
|
1105
1487
|
E22 = E2**2
|
|
@@ -1108,16 +1490,17 @@ def _Horner(S, e1, E2, E3, E4, E5, over):
|
|
|
1108
1490
|
# + 3*E5/26 - E2**3/16 + 3*E3**2/40 + 3*E2*E4/20
|
|
1109
1491
|
# + 45*E2**2*E3/272 - 9*(E3*E4+E2*E5)/68)
|
|
1110
1492
|
# converted to Horner-like form ...
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
S
|
|
1114
|
-
S +=
|
|
1115
|
-
S +=
|
|
1116
|
-
S +=
|
|
1117
|
-
S +=
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1493
|
+
_1 = _1_0
|
|
1494
|
+
h = 4084080
|
|
1495
|
+
S *= e1
|
|
1496
|
+
S += _Hdot(E5, h, E2, -540540, _1, 471240)
|
|
1497
|
+
S += _Hdot(E4, h, E2, 612612, E3, -540540, _1, -556920)
|
|
1498
|
+
S += _Hdot(E3, h, E2, -706860, E22, 675675, E3, 306306, _1, 680680)
|
|
1499
|
+
S += _Hdot(E2, h, E2, 417690, E22, -255255, _1, -875160)
|
|
1500
|
+
S += _1
|
|
1501
|
+
if over:
|
|
1502
|
+
e1 *= over
|
|
1503
|
+
return S.fdiv(e1) # Fsum
|
|
1121
1504
|
|
|
1122
1505
|
|
|
1123
1506
|
def _3over(a, b):
|
|
@@ -1148,7 +1531,7 @@ def _rC(x, y):
|
|
|
1148
1531
|
raise _ellipticError(Elliptic.fRC, x, y)
|
|
1149
1532
|
|
|
1150
1533
|
|
|
1151
|
-
def _RD(x, y, z, over=
|
|
1534
|
+
def _RD(x, y, z, over=_0_0, inst=None):
|
|
1152
1535
|
'''(INTERNAL) Carlson, eqs 2.28 - 2.34.
|
|
1153
1536
|
'''
|
|
1154
1537
|
L = _List(x, y, z)
|
|
@@ -1157,21 +1540,32 @@ def _RD(x, y, z, over=_1_0, inst=None):
|
|
|
1157
1540
|
if s:
|
|
1158
1541
|
S += _over(_3_0, (r + z) * s[2] * m)
|
|
1159
1542
|
z = L[2] # s[2] = sqrt(z)
|
|
1160
|
-
|
|
1543
|
+
m *= a
|
|
1544
|
+
x, y = L.rescale(-m, x, y)
|
|
1161
1545
|
xy = x * y
|
|
1162
1546
|
z = (x + y) / _3_0
|
|
1163
1547
|
z2 = z**2
|
|
1164
|
-
return
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1548
|
+
return _Hsum(S, sqrt(a) * m,
|
|
1549
|
+
(xy - z2 * _6_0),
|
|
1550
|
+
(xy * _3_0 - z2 * _8_0) * z,
|
|
1551
|
+
(xy - z2) * z2 * _3_0,
|
|
1552
|
+
(xy * z2 * z), over) # Fsum
|
|
1553
|
+
|
|
1554
|
+
|
|
1555
|
+
def _Rdot(x, y, z, start3):
|
|
1556
|
+
'''(INTERNAL) "Rotated" C{dot}.
|
|
1557
|
+
'''
|
|
1558
|
+
try:
|
|
1559
|
+
R = Fdot_(x, y, y, z, z, x, start3, _3_0, f2product=True)
|
|
1560
|
+
except (OverflowError, TypeError, ValueError):
|
|
1561
|
+
R = Fsum(x * y, y * z, z * x, start3 * _3_0, nonfinites=True)
|
|
1562
|
+
return R
|
|
1169
1563
|
|
|
1170
1564
|
|
|
1171
1565
|
def _rF2(x, y, inst=None): # 2-arg version, z=0
|
|
1172
1566
|
'''(INTERNAL) Carlson, eqs 2.36 - 2.38.
|
|
1173
1567
|
'''
|
|
1174
|
-
for a, b,
|
|
1568
|
+
for a, b, m in _abm3(x, y, inst): # PYCHOK yield
|
|
1175
1569
|
pass
|
|
1176
1570
|
return _over(PI, a + b) # float
|
|
1177
1571
|
|
|
@@ -1192,24 +1586,22 @@ def _RF3(x, y, z, inst=None): # 3-arg version
|
|
|
1192
1586
|
# (1 - E2/10 + E3/14 + E2**2/24 - 3*E2*E3/44
|
|
1193
1587
|
# - 5*E2**3/208 + 3*E3**2/104 + E2**2*E3/16)
|
|
1194
1588
|
# converted to Horner-like form ...
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
S
|
|
1198
|
-
|
|
1589
|
+
_1 = _1_0
|
|
1590
|
+
h = 240240
|
|
1591
|
+
S = _Hdot(e3, h, e4, 15015, e3, 6930, e2, -16380, _1, 17160)
|
|
1592
|
+
S += _Hdot(e2, h, e4, -5775, e2, 10010, _1, -24024)
|
|
1593
|
+
S += _1
|
|
1594
|
+
return S.fdiv(sqrt(a)) # Fsum
|
|
1199
1595
|
|
|
1200
1596
|
|
|
1201
1597
|
def _rG2(x, y, inst=None, PI_=PI_4): # 2-args
|
|
1202
1598
|
'''(INTERNAL) Carlson, eqs 2.36 - 2.39.
|
|
1203
1599
|
'''
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
for a, b,
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
m *= 2
|
|
1210
|
-
else:
|
|
1211
|
-
S += (a + b)**2 * _0_5
|
|
1212
|
-
return S.fmul(PI_).fover(a + b) # float
|
|
1600
|
+
rs = [] # len 2..7, incl sentinel
|
|
1601
|
+
_r = rs.append
|
|
1602
|
+
for a, b, m in _abm3(x, y, inst): # PYCHOK yield
|
|
1603
|
+
_r((a - b)**2 * m)
|
|
1604
|
+
return _over(_fsum(rs) * PI_, a + b) # nonfinites=True, float
|
|
1213
1605
|
|
|
1214
1606
|
|
|
1215
1607
|
def _rG3(x, y, z): # 3-arg version
|
|
@@ -1223,7 +1615,7 @@ def _rG3(x, y, z): # 3-arg version
|
|
|
1223
1615
|
return R.fover(_2_0) # float
|
|
1224
1616
|
|
|
1225
1617
|
|
|
1226
|
-
def _RJ(x, y, z, p, over=
|
|
1618
|
+
def _RJ(x, y, z, p, over=_0_0, inst=None):
|
|
1227
1619
|
'''(INTERNAL) Carlson, eqs 2.17 - 2.25.
|
|
1228
1620
|
'''
|
|
1229
1621
|
def _xyzp(x, y, z, p):
|
|
@@ -1244,17 +1636,18 @@ def _RJ(x, y, z, p, over=_1_0, inst=None):
|
|
|
1244
1636
|
S += r / (d * m)
|
|
1245
1637
|
else: # PYCHOK no cover
|
|
1246
1638
|
return NAN
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1639
|
+
m *= a
|
|
1640
|
+
x, y, z = L.rescale(m, x, y, z)
|
|
1641
|
+
p = neg(Fsum(x, y, z).fover(_2_0))
|
|
1642
|
+
p2 = p**2
|
|
1643
|
+
p3 = p2 * p
|
|
1644
|
+
E2 = _Rdot(x, y, z, -p2)
|
|
1645
|
+
E2p = E2 * p
|
|
1646
|
+
xyz = x * y * z
|
|
1647
|
+
return _Hsum(S.fmul(_6_0), sqrt(a) * m, E2,
|
|
1648
|
+
Fsum(p3 * _4_0, xyz, E2p, E2p),
|
|
1649
|
+
Fsum(p3 * _3_0, E2p, xyz, xyz).fmul(p),
|
|
1650
|
+
p2 * xyz, over) # Fsum
|
|
1258
1651
|
|
|
1259
1652
|
|
|
1260
1653
|
class _RJfma(object):
|
|
@@ -1264,7 +1657,8 @@ class _RJfma(object):
|
|
|
1264
1657
|
self._Rj = _RJ(*args)
|
|
1265
1658
|
|
|
1266
1659
|
def ma(self, b, c):
|
|
1267
|
-
r =
|
|
1660
|
+
r = self._Rj._fma(b, c, nonfinites=True)
|
|
1661
|
+
# assert r is not self._Rj
|
|
1268
1662
|
return float(r)
|
|
1269
1663
|
|
|
1270
1664
|
# **) MIT License
|