Compare commits

...

89 Commits

Author SHA1 Message Date
d90ff5df69 Ellipsoid-Auswahl angepasst 2026-02-11 13:44:53 +01:00
59ad560f36 Abgabe fertig 2026-02-11 12:08:46 +01:00
5a293a823a revert 4f7b9aaef0
revert Delete Tests/gha_resultsKarney.pkl
2026-02-11 11:00:48 +00:00
36b62059fc revert 798cace25d
revert Delete Tests/gha_resultsPanou.pkl
2026-02-11 11:00:33 +00:00
57a086f6cb revert b8d07307aa
revert Delete Tests/gha_resultsRandom.pkl
2026-02-11 11:00:23 +00:00
b8d07307aa Delete Tests/gha_resultsRandom.pkl 2026-02-11 10:58:53 +00:00
798cace25d Delete Tests/gha_resultsPanou.pkl 2026-02-11 10:58:47 +00:00
4f7b9aaef0 Delete Tests/gha_resultsKarney.pkl 2026-02-11 10:58:42 +00:00
1fbfb555a4 wraps 2026-02-10 21:10:11 +01:00
Tammo.Weber
db05f7b6db Merge remote-tracking branch 'origin/main' 2026-02-10 12:36:04 +01:00
Tammo.Weber
73e3694a2a Ausgabe von alpha GHA1 2026-02-10 12:35:35 +01:00
ffc8d3fbce Fehlermeldung dashboard 2026-02-10 11:36:15 +01:00
Tammo.Weber
fd02694ae4 Platzsparen 2026-02-09 21:36:46 +01:00
e1ac0415e7 Merge remote-tracking branch 'origin/main' 2026-02-09 16:28:55 +01:00
e7641ba64f , 2026-02-09 16:28:15 +01:00
Tammo.Weber
fc9bc5defb Optimierung 2026-02-09 15:30:24 +01:00
Tammo.Weber
2864ce50ff s kleiner 0 2026-02-09 11:50:07 +01:00
Tammo.Weber
b44c25928e Merge remote-tracking branch 'origin/main' 2026-02-09 11:45:29 +01:00
Tammo.Weber
67248f9ca9 Anpassungen im Plot 2026-02-09 11:44:52 +01:00
Tammo.Weber
71c13c568a Fehlerkorrektur 2026-02-09 11:43:50 +01:00
19887e4ac5 Merge remote-tracking branch 'origin/main' 2026-02-09 11:29:38 +01:00
737e4730aa dashboard streckenelemente kleiner 0 zulässig 2026-02-09 11:29:15 +01:00
Tammo.Weber
020d282420 Merge remote-tracking branch 'origin/main' 2026-02-09 10:17:11 +01:00
Tammo.Weber
cefa98e3b7 Zweiter Parameter bei GHA1 ana 2026-02-09 10:16:57 +01:00
e8624159e2 karney gruppen 2026-02-08 19:31:52 +01:00
Tammo.Weber
cfab70ac55 Meldung wenn Berechung fehlschlägt 2026-02-08 17:51:55 +01:00
ee85e8b0e6 . 2026-02-08 16:28:59 +01:00
02ce0c0b4a nochmal 2026-02-07 22:03:07 +01:00
3fd967e843 Exceptions einheitlich 2026-02-07 19:35:15 +01:00
322ac94299 Exceptions einheitlich 2026-02-07 19:34:54 +01:00
49d03786dc GHA1 ana richtig aufgerufen im Dashboard und im Test 2026-02-07 18:07:25 +01:00
ef99294502 all points 2026-02-06 16:28:34 +01:00
b3a73270c2 Merge remote-tracking branch 'origin/main' 2026-02-06 16:25:40 +01:00
7a425eae77 Lets go 2026-02-06 16:25:27 +01:00
Tammo.Weber
bd411a8cd7 Merge remote-tracking branch 'origin/main' 2026-02-06 16:01:25 +01:00
Tammo.Weber
d6f9bc4302 Kleinere Anpassungen und Fehler abfangen 2026-02-06 16:01:15 +01:00
50326ba246 Nice 2026-02-06 15:49:36 +01:00
Tammo.Weber
0eeb35f173 GHA1 ES mit Linie, Legende 2026-02-06 15:06:48 +01:00
2954c0ee3a Punktliste 2 2026-02-06 14:43:43 +01:00
476b51071b Merge remote-tracking branch 'origin/main' 2026-02-06 14:30:26 +01:00
a836d2d534 Punktliste 2026-02-06 14:30:11 +01:00
Tammo.Weber
7a2a843285 kleinere Optimierungen 2026-02-06 14:10:48 +01:00
Tammo.Weber
9591045ee2 GHA1 ES implementiert 2026-02-06 13:06:32 +01:00
Tammo.Weber
81ca8a4770 GHA1 analytisch Ordnung variabel 2026-02-06 12:35:55 +01:00
6e63b3c965 Geile Änderungen 2026-02-06 11:32:48 +01:00
af8ac02e5b Merge remote-tracking branch 'origin/main' 2026-02-06 11:24:33 +01:00
e14869691b turbomäßige Anpassungen 2026-02-06 11:24:13 +01:00
Tammo.Weber
f68d11c031 Einmal ein Rechtschreibfehler und einmal in rad ausgegeben. 2026-02-06 11:15:42 +01:00
Tammo.Weber
5d4ed35f17 Anpassungen bei Zwischespeicherung etc. 2026-02-05 22:48:58 +01:00
Tammo.Weber
2ba4dad30d Merge remote-tracking branch 'origin/main'
# Conflicts:
#	GHA_triaxial/gha2_num.py
2026-02-05 21:44:28 +01:00
Tammo.Weber
dd5cf2d6a8 merge 2026-02-05 21:43:26 +01:00
Tammo.Weber
9f0554039c merge 2026-02-05 21:40:39 +01:00
a864cd9279 ES1 in Tests 2026-02-05 21:35:48 +01:00
e894c7089a final 2026-02-05 21:29:20 +01:00
f75672ec36 henreick 2026-02-05 21:03:59 +01:00
e11edd2a43 henreick 2026-02-05 21:01:06 +01:00
82444208d7 gha1_ES 2026-02-05 19:20:09 +01:00
36e243d6d4 Anpassungen 2026-02-05 16:54:28 +01:00
ac1436a7f7 stopfitness=1e-14 2026-02-05 15:58:11 +01:00
09ae06e9b2 ell2 2026-02-05 15:56:09 +01:00
39641b5293 ell 2026-02-05 15:52:22 +01:00
Tammo.Weber
19c1625a11 Merge remote-tracking branch 'origin/main' 2026-02-05 13:04:56 +01:00
Tammo.Weber
c240da85c1 Eingabe Berechnungsparameter 2026-02-05 13:04:31 +01:00
fb4faf9aa4 Fehler in der Umrechnung korrigiert 2026-02-05 11:36:44 +01:00
c15de91154 Merge remote-tracking branch 'origin/main' 2026-02-05 11:14:05 +01:00
77c7a6f9ab Umstrukturierung 2026-02-05 11:12:17 +01:00
Tammo.Weber
4689a77f37 Ausgabe der alphas 2026-02-05 11:07:08 +01:00
Tammo.Weber
8113d743c0 Merge remote-tracking branch 'origin/main' 2026-02-05 10:59:45 +01:00
Tammo.Weber
a3ec069c1a Änderungen mergen 2026-02-05 10:59:17 +01:00
4e2491d967 Umbenennung, Umstrukturierung, Doc-Strings 2026-02-04 22:59:07 +01:00
96e489a116 Darstellung aller Parameterlinien konstant 2026-02-04 11:41:43 +01:00
3930b3207a ES GHA1 aus dashboard entfernt 2026-02-04 11:26:40 +01:00
0aa56f448c Merge remote-tracking branch 'origin/main' 2026-02-04 11:24:01 +01:00
9b4eaaef0b kleine Anpassungen 2026-02-04 11:23:33 +01:00
Tammo.Weber
1532c97111 Koordinatenart für den Plot wählbar 2026-02-03 21:45:24 +01:00
Tammo.Weber
d80492a9e5 Funktioniert jetzt mit allen Panou 2026-02-02 18:38:17 +01:00
ab20352cbf Merge remote-tracking branch 'refs/remotes/origin/main2'
# Conflicts:
#	GHA_triaxial/ES_gha2.py
2026-01-18 22:31:00 +01:00
aa7175c3c4 Umrechnungs-Test, Tabellen 2026-01-18 22:29:29 +01:00
fee5de0041 Konflikte gelöst, gha2_ES aber noch nicht wieder im Dashboard aufgerufen 2026-01-18 22:11:01 +01:00
d7076e3001 Konflikte gelöst, gha2_ES aber noch nicht wieder im Dashboard aufgerufen 2026-01-18 21:53:57 +01:00
07212dcc97 Algorithmen Test 2026-01-17 18:51:47 +01:00
Tammo.Weber
505aee6de7 Kleinere Anpassungen 2026-01-13 20:46:15 +01:00
Tammo.Weber
048b6979d8 Import 2026-01-13 20:00:06 +01:00
39f5dbdd95 Berechnungen Kugel 2026-01-13 16:52:45 +01:00
de35fb786f Merge remote-tracking branch 'origin/main' 2026-01-13 16:15:19 +01:00
9dfb959eb0 Berechnungen Biaxial 2026-01-13 16:15:00 +01:00
Tammo.Weber
7addf7f13e Merge remote-tracking branch 'origin/main' 2026-01-13 15:56:33 +01:00
Tammo.Weber
35c1f413ef Layout und Eingaben 2026-01-13 15:56:22 +01:00
Tammo.Weber
e4b7b08517 Plot repariert 2026-01-13 14:09:36 +01:00
46 changed files with 17074 additions and 2584 deletions

View File

@@ -1,364 +0,0 @@
import numpy as np
import plotly.graph_objects as go
from ellipsoide import EllipsoidTriaxial
def ell2cart(ell: EllipsoidTriaxial, beta, lamb):
x = ell.ax * np.cos(beta) * np.cos(lamb)
y = ell.ay * np.cos(beta) * np.sin(lamb)
z = ell.b * np.sin(beta)
return np.array([x, y, z], dtype=float)
def liouville(ell: EllipsoidTriaxial, beta, lamb, alpha):
k = (ell.Ee**2) / (ell.Ex**2)
c_sq = (np.cos(beta)**2 + k * np.sin(beta)**2) * np.sin(alpha)**2 \
+ k * np.cos(lamb)**2 * np.cos(alpha)**2
return c_sq
def normalize_angles(beta, lamb):
beta = np.clip(beta, -np.pi / 2.0, np.pi / 2.0)
lamb = (lamb + np.pi) % (2 * np.pi) - np.pi
return beta, lamb
def compute_azimuth(beta0: float, lamb0: float,
beta1: float, lamb1: float) -> float:
dlam = lamb1 - lamb0
y = np.cos(beta1) * np.sin(dlam)
x = np.cos(beta0) * np.sin(beta1) - np.sin(beta0) * np.cos(beta1) * np.cos(dlam)
alpha = np.arctan2(y, x)
return alpha
def sphere_forward_step(beta0: float,
lamb0: float,
alpha0: float,
s: float,
R: float) -> tuple[float, float]:
delta = s / R
sin_beta0 = np.sin(beta0)
cos_beta0 = np.cos(beta0)
sin_beta2 = sin_beta0 * np.cos(delta) + cos_beta0 * np.sin(delta) * np.cos(alpha0)
beta2 = np.arcsin(sin_beta2)
y = np.sin(alpha0) * np.sin(delta) * cos_beta0
x = np.cos(delta) - sin_beta0 * sin_beta2
dlam = np.arctan2(y, x)
lamb2 = lamb0 + dlam
beta2, lamb2 = normalize_angles(beta2, lamb2)
return beta2, lamb2
def local_step_objective(candidate: np.ndarray,
beta_start: float,
lamb_start: float,
alpha_prev: float,
c_target: float,
step_length: float,
ell: EllipsoidTriaxial,
beta_pred: float,
lamb_pred: float,
w_L: float = 5.0,
w_d: float = 5.0,
w_p: float = 2.0,
w_a: float = 2.0) -> float:
beta1, lamb1 = candidate
beta1, lamb1 = normalize_angles(beta1, lamb1)
P0 = ell2cart(ell, beta_start, lamb_start)
P1 = ell2cart(ell, beta1, lamb1)
d = np.linalg.norm(P1 - P0)
alpha1 = compute_azimuth(beta_start, lamb_start, beta1, lamb1)
c1 = liouville(ell, beta1, lamb1, alpha1)
J_L = (c1 - c_target) ** 2
J_d = (d - step_length) ** 2
d_beta = beta1 - beta_pred
d_lamb = lamb1 - lamb_pred
d_ang2 = d_beta**2 + (np.cos(beta_pred) * d_lamb)**2
J_p = d_ang2
d_alpha = np.arctan2(np.sin(alpha1 - alpha_prev),
np.cos(alpha1 - alpha_prev))
J_a = d_alpha**2
return w_L * J_L + w_d * J_d + w_p * J_p + w_a * J_a
def ES_CMA_step(beta_start: float,
lamb_start: float,
alpha_prev: float,
c_target: float,
step_length: float,
ell: EllipsoidTriaxial,
beta_pred: float,
lamb_pred: float,
sigma0: float,
stopfitness: float = 1e-18) -> tuple[float, float]:
N = 2
xmean = np.array([beta_pred, lamb_pred], dtype=float)
sigma = sigma0
stopeval = int(400 * N**2)
lamb = 30
mu = 1
weights = np.array([1.0])
mueff = 1.0
cc = (4 + mueff / N) / (N + 4 + 2 * mueff / N)
cs = (mueff + 2) / (N + mueff + 5)
c1 = 2 / ((N + 1.3)**2 + mueff)
cmu = min(1 - c1,
2 * (mueff - 2 + 1/mueff) / ((N + 2)**2 + mueff))
damps = 1 + 2 * max(0, np.sqrt((mueff - 1) / (N + 1)) - 1) + cs
pc = np.zeros(N)
ps = np.zeros(N)
B = np.eye(N)
D = np.eye(N)
C = B @ D @ (B @ D).T
eigeneval = 0
chiN = np.sqrt(N) * (1 - 1 / (4 * N) + 1 / (21 * N**2))
counteval = 0
arx = np.zeros((N, lamb))
arz = np.zeros((N, lamb))
arfitness = np.zeros(lamb)
while counteval < stopeval:
for k in range(lamb):
arz[:, k] = np.random.randn(N)
arx[:, k] = xmean + sigma * (B @ D @ arz[:, k])
arfitness[k] = local_step_objective(
arx[:, k],
beta_start, lamb_start,
alpha_prev,
c_target,
step_length,
ell,
beta_pred, lamb_pred
)
counteval += 1
idx = np.argsort(arfitness)
arfitness = arfitness[idx]
arindex = idx
xold = xmean.copy()
xmean = arx[:, arindex[:mu]] @ weights
zmean = arz[:, arindex[:mu]] @ weights
ps = (1 - cs) * ps + np.sqrt(cs * (2 - cs) * mueff) * (B @ zmean)
norm_ps = np.linalg.norm(ps)
hsig = norm_ps / np.sqrt(1 - (1 - cs)**(2 * counteval / lamb)) / chiN < 1.4 + 2 / (N + 1)
hsig = 1.0 if hsig else 0.0
pc = (1 - cc) * pc + hsig * np.sqrt(cc * (2 - cc) * mueff) * (B @ D @ zmean)
BDz = B @ D @ arz[:, arindex[:mu]]
C = (1 - c1 - cmu) * C \
+ c1 * (np.outer(pc, pc) + (1 - hsig) * cc * (2 - cc) * C) \
+ cmu * BDz @ np.diag(weights) @ BDz.T
sigma = sigma * np.exp((cs / damps) * (norm_ps / chiN - 1))
if counteval - eigeneval > lamb / ((c1 + cmu) * N * 10):
eigeneval = counteval
C = (C + C.T) / 2.0
eigvals, B = np.linalg.eigh(C)
D = np.diag(np.sqrt(np.maximum(eigvals, 1e-20)))
if arfitness[0] <= stopfitness:
break
xmin = arx[:, arindex[0]]
beta1, lamb1 = normalize_angles(xmin[0], xmin[1])
return beta1, lamb1
def march_geodesic(beta1: float,
lamb1: float,
alpha1: float,
S_total: float,
step_length: float,
ell: EllipsoidTriaxial):
beta_curr = beta1
lamb_curr = lamb1
alpha_curr = alpha1
betas = [beta_curr]
lambs = [lamb_curr]
alphas = [alpha_curr]
c_target = liouville(ell, beta_curr, lamb_curr, alpha_curr)
total_distance = 0.0
R_sphere = ell.ax
sigma0 = 1e-10
while total_distance < S_total - 1e-6:
remaining = S_total - total_distance
this_step = min(step_length, remaining)
beta_pred, lamb_pred = sphere_forward_step(
beta_curr, lamb_curr, alpha_curr,
this_step, R_sphere
)
beta_next, lamb_next = ES_CMA_step(
beta_curr, lamb_curr, alpha_curr,
c_target,
this_step,
ell,
beta_pred,
lamb_pred,
sigma0=sigma0
)
P_curr = ell2cart(ell, beta_curr, lamb_curr)
P_next = ell2cart(ell, beta_next, lamb_next)
d_step = np.linalg.norm(P_next - P_curr)
total_distance += d_step
alpha_next = compute_azimuth(beta_curr, lamb_curr, beta_next, lamb_next)
beta_curr, lamb_curr, alpha_curr = beta_next, lamb_next, alpha_next
betas.append(beta_curr)
lambs.append(lamb_curr)
alphas.append(alpha_curr)
return np.array(betas), np.array(lambs), np.array(alphas), total_distance
if __name__ == "__main__":
ell = EllipsoidTriaxial.init_name("BursaSima1980round")
beta1 = np.deg2rad(10.0)
lamb1 = np.deg2rad(10.0)
alpha1 = 0.7494562507041596 # Ergebnis 20°, 20°
STEP_LENGTH = 500.0
S_total = 1542703.1458877102
betas, lambs, alphas, S_real = march_geodesic(
beta1, lamb1, alpha1,
S_total,
STEP_LENGTH,
ell
)
print("Anzahl Schritte:", len(betas) - 1)
print("Resultierende Gesamtstrecke (Chord, Ellipsoid):", S_real, "m")
print("Letzter Punkt (beta, lambda) in Grad:",
np.rad2deg(betas[-1]), np.rad2deg(lambs[-1]))
def plot_geodesic_3d(ell: EllipsoidTriaxial,
betas: np.ndarray,
lambs: np.ndarray,
n_beta: int = 60,
n_lamb: int = 120):
beta_grid = np.linspace(-np.pi/2, np.pi/2, n_beta)
lamb_grid = np.linspace(-np.pi, np.pi, n_lamb)
B, L = np.meshgrid(beta_grid, lamb_grid, indexing="ij")
Xs = ell.ax * np.cos(B) * np.cos(L)
Ys = ell.ay * np.cos(B) * np.sin(L)
Zs = ell.b * np.sin(B)
Xp = ell.ax * np.cos(betas) * np.cos(lambs)
Yp = ell.ay * np.cos(betas) * np.sin(lambs)
Zp = ell.b * np.sin(betas)
fig = go.Figure()
fig.add_trace(
go.Surface(
x=Xs,
y=Ys,
z=Zs,
opacity=0.6,
showscale=False,
colorscale="Viridis",
name="Ellipsoid"
)
)
fig.add_trace(
go.Scatter3d(
x=Xp,
y=Yp,
z=Zp,
mode="lines+markers",
line=dict(width=5, color="red"),
marker=dict(size=4, color="black"),
name="ES-CMA Schritte"
)
)
fig.add_trace(
go.Scatter3d(
x=[Xp[0]], y=[Yp[0]], z=[Zp[0]],
mode="markers",
marker=dict(size=6, color="green"),
name="Start"
)
)
fig.add_trace(
go.Scatter3d(
x=[Xp[-1]], y=[Yp[-1]], z=[Zp[-1]],
mode="markers",
marker=dict(size=6, color="blue"),
name="Ende"
)
)
fig.update_layout(
title="ES-CMA",
scene=dict(
xaxis_title="X [m]",
yaxis_title="Y [m]",
zaxis_title="Z [m]",
aspectmode="data"
)
)
fig.show()
plot_geodesic_3d(ell, betas, lambs)

View File

@@ -1,7 +1,8 @@
import numpy as np import numpy as np
from numpy.typing import NDArray
def felli(x): def felli(x: NDArray) -> float:
N = x.shape[0] N = x.shape[0]
if N < 2: if N < 2:
raise ValueError("dimension must be greater than one") raise ValueError("dimension must be greater than one")
@@ -9,10 +10,9 @@ def felli(x):
return float(np.sum((1e6 ** exponents) * (x ** 2))) return float(np.sum((1e6 ** exponents) * (x ** 2)))
def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-10, stopeval=None, def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-14, stopeval=2000,
func_args=(), func_kwargs=None, seed=None, func_args=(), func_kwargs=None, seed=0,
bestEver = np.inf, noImproveGen = 0, absTolImprove = 1e-12, maxNoImproveGen = 100, sigmaImprove = 1e-12): bestEver=np.inf, noImproveGen=0, absTolImprove=1e-12, maxNoImproveGen=100, sigmaImprove=1e-12):
if func_kwargs is None: if func_kwargs is None:
func_kwargs = {} func_kwargs = {}
@@ -27,7 +27,7 @@ def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-10, stopeval=None
N = xmean.shape[0] N = xmean.shape[0]
if stopeval is None: if stopeval is None:
stopeval = int(1e3 * N**2) stopeval = int(1e3 * N ** 2)
# Strategy parameter setting: Selection # Strategy parameter setting: Selection
lambda_ = 4 + int(np.floor(3 * np.log(N))) lambda_ = 4 + int(np.floor(3 * np.log(N)))
@@ -37,14 +37,14 @@ def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-10, stopeval=None
weights = np.log(mu + 0.5) - np.log(np.arange(1, int(mu) + 1)) weights = np.log(mu + 0.5) - np.log(np.arange(1, int(mu) + 1))
mu = int(np.floor(mu)) mu = int(np.floor(mu))
weights = weights / np.sum(weights) weights = weights / np.sum(weights)
mueff = np.sum(weights)**2 / np.sum(weights**2) mueff = np.sum(weights) ** 2 / np.sum(weights ** 2)
# Strategy parameter setting: Adaptation # Strategy parameter setting: Adaptation
cc = (4 + mueff / N) / (N + 4 + 2 * mueff / N) cc = (4 + mueff / N) / (N + 4 + 2 * mueff / N)
cs = (mueff + 2) / (N + mueff + 5) cs = (mueff + 2) / (N + mueff + 5)
c1 = 2 / ((N + 1.3)**2 + mueff) c1 = 2 / ((N + 1.3) ** 2 + mueff)
cmu = min(1 - c1, cmu = min(1 - c1,
2 * (mueff - 2 + 1 / mueff) / ((N + 2)**2 + 2 * mueff)) 2 * (mueff - 2 + 1 / mueff) / ((N + 2) ** 2 + 2 * mueff))
damps = 1 + 2 * max(0, np.sqrt((mueff - 1) / (N + 1)) - 1) + cs damps = 1 + 2 * max(0, np.sqrt((mueff - 1) / (N + 1)) - 1) + cs
# Initialize dynamic (internal) strategy parameters and constants # Initialize dynamic (internal) strategy parameters and constants
@@ -54,7 +54,7 @@ def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-10, stopeval=None
D = np.eye(N) D = np.eye(N)
C = B @ D @ (B @ D).T C = B @ D @ (B @ D).T
eigeneval = 0 eigeneval = 0
chiN = np.sqrt(N) * (1 - 1/(4*N) + 1/(21 * N**2)) chiN = np.sqrt(N) * (1 - 1 / (4 * N) + 1 / (21 * N ** 2))
# Generation Loop # Generation Loop
counteval = 0 counteval = 0
@@ -64,7 +64,7 @@ def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-10, stopeval=None
gen = 0 gen = 0
print(f' [CMA-ES] Start: lambda = {lambda_}, sigma ={round(sigma, 6)}, stopeval = {stopeval}') # print(f' [CMA-ES] Start: lambda = {lambda_}, sigma ={round(sigma, 6)}, stopeval = {stopeval}')
while counteval < stopeval: while counteval < stopeval:
gen += 1 gen += 1
@@ -91,27 +91,24 @@ def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-10, stopeval=None
bestEver = fbest bestEver = fbest
noImproveGen = 0 noImproveGen = 0
else: else:
noImproveGen = noImproveGen + 1 noImproveGen += 1
if gen == 1 or gen % 50 == 0:
if gen == 1 or gen%50==0: # print(f' [CMA-ES] Gen {gen}, best = {round(fbest, 6)}, sigma = {sigma:.3g}')
print(f' [CMA-ES] Gen {gen}, best = {round(fbest, 6)}, sigma = {sigma:.3g}') pass
if noImproveGen >= maxNoImproveGen: if noImproveGen >= maxNoImproveGen:
print(f' [CMA-ES] Abbruch: keine Verbesserung > {round(absTolImprove, 3)} in {maxNoImproveGen} Generationen.') # print(f' [CMA-ES] Abbruch: keine Verbesserung > {round(absTolImprove, 3)} in {maxNoImproveGen} Generationen.')
break break
if sigma < sigmaImprove: if sigma < sigmaImprove:
print(f' [CMA-ES] Abbruch: sigma zu klein {sigma:.3g}') # print(f' [CMA-ES] Abbruch: sigma zu klein {sigma:.3g}')
break break
# Cumulation: Update evolution paths # Cumulation: Update evolution paths
ps = (1 - cs) * ps + np.sqrt(cs * (2 - cs) * mueff) * (B @ zmean) ps = (1 - cs) * ps + np.sqrt(cs * (2 - cs) * mueff) * (B @ zmean)
norm_ps = np.linalg.norm(ps) norm_ps = np.linalg.norm(ps)
hsig = norm_ps / np.sqrt(1 - (1 - cs)**(2 * counteval / lambda_)) / chiN < \ hsig = norm_ps / np.sqrt(1 - (1 - cs) ** (2 * counteval / lambda_)) / chiN < (1.4 + 2 / (N + 1))
(1.4 + 2 / (N + 1))
hsig = 1.0 if hsig else 0.0 hsig = 1.0 if hsig else 0.0
pc = (1 - cc) * pc + hsig * np.sqrt(cc * (2 - cc) * mueff) * (B @ D @ zmean) pc = (1 - cc) * pc + hsig * np.sqrt(cc * (2 - cc) * mueff) * (B @ D @ zmean)
@@ -140,16 +137,17 @@ def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-10, stopeval=None
# Escape flat fitness, or better terminate? # Escape flat fitness, or better terminate?
if arfitness[0] == arfitness[int(np.ceil(0.7 * lambda_)) - 1]: if arfitness[0] == arfitness[int(np.ceil(0.7 * lambda_)) - 1]:
sigma = sigma * np.exp(0.2 + cs / damps) sigma = sigma * np.exp(0.2 + cs / damps)
print(' [CMA-ES] stopfitness erreicht.') # print(' [CMA-ES] stopfitness erreicht.')
#print("warning: flat fitness, consider reformulating the objective") # print("warning: flat fitness, consider reformulating the objective")
break
#print(f"{counteval}: {arfitness[0]}") # print(f"{counteval}: {arfitness[0]}")
#Final Message # Final Message
#print(f"{counteval}: {arfitness[0]}") # print(f"{counteval}: {arfitness[0]}")
xmin = arx[:, arindex[0]] xmin = arx[:, arindex[0]]
bestValue = arfitness[0] bestValue = arfitness[0]
print(f' [CMA-ES] Ende: Gen = {gen}, best = {round(bestValue, 6)}') # print(f' [CMA-ES] Ende: Gen = {gen}, best = {round(bestValue, 6)}')
return xmin return xmin

247
ES/gha1_ES.py Normal file
View File

@@ -0,0 +1,247 @@
from __future__ import annotations
from typing import List, Tuple
import numpy as np
from numpy.typing import NDArray
import winkelumrechnungen as wu
from ES.Hansen_ES_CMA import escma
from GHA_triaxial.gha1_ana import gha1_ana
from GHA_triaxial.gha1_approx import gha1_approx
from GHA_triaxial.utils import jacobi_konstante
from ellipsoid_triaxial import EllipsoidTriaxial
from utils_angle import wrap_mpi_pi
def ENU_beta_omega(beta: float, omega: float, ell: EllipsoidTriaxial) \
-> Tuple[NDArray, NDArray, NDArray, float, float, NDArray]:
"""
Analytische ENU-Basis in ellipsoidische Koordinaten (β, ω) nach Karney (2025), S. 2
:param beta: Beta Koordinate
:param omega: Omega Koordinate
:param ell: Ellipsoid
:return: E_hat = Einheitsrichtung entlang wachsendem ω (East)
N_hat = Einheitsrichtung entlang wachsendem β (North)
U_hat = Einheitsnormale (Up)
En & Nn = Längen der unnormierten Ableitungen
R (XYZ) = Punkt in XYZ
"""
# Berechnungshilfen
omega = wrap_mpi_pi(omega)
cb = np.cos(beta)
sb = np.sin(beta)
co = np.cos(omega)
so = np.sin(omega)
# D = sqrt(a^2 - c^2)
D = np.sqrt(ell.ax*ell.ax - ell.b*ell.b)
# Sx = sqrt(a^2 - b^2 sin^2β - c^2 cos^2β)
Sx = np.sqrt(ell.ax*ell.ax - ell.ay*ell.ay*(sb*sb) - ell.b*ell.b*(cb*cb))
# Sz = sqrt(a^2 sin^2ω + b^2 cos^2ω - c^2)
Sz = np.sqrt(ell.ax*ell.ax*(so*so) + ell.ay*ell.ay*(co*co) - ell.b*ell.b)
# Karney Gl. (4)
X = ell.ax * co * Sx / D
Y = ell.ay * cb * so
Z = ell.b * sb * Sz / D
R = np.array([X, Y, Z], dtype=float)
# --- Ableitungen - Karney Gl. (5a,b,c)---
# E = ∂R/∂ω
dX_dw = -ell.ax * so * Sx / D
dY_dw = ell.ay * cb * co
dZ_dw = ell.b * sb * (so * co * (ell.ax*ell.ax - ell.ay*ell.ay) / Sz) / D
E = np.array([dX_dw, dY_dw, dZ_dw], dtype=float)
# N = ∂R/∂β
dX_db = ell.ax * co * (sb * cb * (ell.b*ell.b - ell.ay*ell.ay) / Sx) / D
dY_db = -ell.ay * sb * so
dZ_db = ell.b * cb * Sz / D
N = np.array([dX_db, dY_db, dZ_db], dtype=float)
# U = Grad(x^2/a^2 + y^2/b^2 + z^2/c^2 - 1)
U = np.array([X/(ell.ax*ell.ax), Y/(ell.ay*ell.ay), Z/(ell.b*ell.b)], dtype=float)
En = float(np.linalg.norm(E))
Nn = float(np.linalg.norm(N))
Un = float(np.linalg.norm(U))
N_hat = N / Nn
E_hat = E / En
U_hat = U / Un
E_hat -= float(np.dot(E_hat, N_hat)) * N_hat
E_hat = E_hat / max(np.linalg.norm(E_hat), 1e-18)
return E_hat, N_hat, U_hat, En, Nn, R
def azimuth_at_ESpoint(P_prev: NDArray, P_curr: NDArray, E_hat_curr: NDArray, N_hat_curr: NDArray, U_hat_curr: NDArray) -> float:
"""
Berechnet das Azimut in der lokalen Tangentialebene am aktuellen Punkt P_curr, gemessen
an der Bewegungsrichtung vom vorherigen Punkt P_prev nach P_curr.
:param P_prev: vorheriger Punkt
:param P_curr: aktueller Punkt
:param E_hat_curr: Einheitsvektor der lokalen Tangentialrichtung am Punkt P_curr
:param N_hat_curr: Einheitsvektor der lokalen Tangentialrichtung am Punkt P_curr
:param U_hat_curr: Einheitsnormalenvektor am Punkt P_curr
:return: Azimut in Radiant
"""
v = (P_curr - P_prev).astype(float)
vT = v - float(np.dot(v, U_hat_curr)) * U_hat_curr
vTn = max(np.linalg.norm(vT), 1e-18)
vT_hat = vT / vTn
sE = float(np.dot(vT_hat, E_hat_curr))
sN = float(np.dot(vT_hat, N_hat_curr))
return wrap_mpi_pi(float(np.arctan2(sE, sN)))
def optimize_next_point(beta_i: float, omega_i: float, alpha_i: float, ds: float, gamma0: float,
ell: EllipsoidTriaxial, maxSegLen: float = 1000.0, sigma0: float = None) -> Tuple[float, float, NDArray, float]:
"""
Berechnung der 1. GHA mithilfe der CMA-ES.
Die CMA-ES optimiert sukzessive einen Punkt, der maxSegLen vom vorherigen Punkt entfernt und zusätzlich auf der
geodätischen Linien liegt. Somit entsteht ein Geodäten ähnlicher Polygonzug auf der Oberfläche des dreiachsigen Ellipsoids.
:param beta_i: Beta Koordinate am Punkt i
:param omega_i: Omega Koordinate am Punkt i
:param alpha_i: Azimut am Punkt i
:param ds: Gesamtlänge
:param gamma0: Jacobi-Konstante am Startpunkt
:param ell: Ellipsoid
:param maxSegLen: maximale Segmentlänge
:param sigma0:
:return:
"""
# Startbasis
E_i, N_i, U_i, En_i, Nn_i, P_i = ENU_beta_omega(beta_i, omega_i, ell)
# Prediktor: dβ ≈ ds cosα / |N|, dω ≈ ds sinα / |E|
En_eff = max(En_i, 1e-9)
Nn_eff = max(Nn_i, 1e-9)
d_beta = ds * np.cos(alpha_i) / Nn_eff
d_omega = ds * np.sin(alpha_i) / En_eff
# optional: harte Schritt-Clamps (verhindert wrap-chaos)
d_beta = float(np.clip(d_beta, -0.2, 0.2)) # rad
d_omega = float(np.clip(d_omega, -0.2, 0.2)) # rad
# d_beta = ds * float(np.cos(alpha_i)) / Nn_i
# d_omega = ds * float(np.sin(alpha_i)) / En_i
beta_pred = beta_i + d_beta
omega_pred = wrap_mpi_pi(omega_i + d_omega)
xmean = np.array([beta_pred, omega_pred], dtype=float)
if sigma0 is None:
R0 = (ell.ax + ell.ay + ell.b) / 3
sigma0 = 1e-5 * (ds / R0)
def fitness(x: NDArray) -> float:
"""
Fitnessfunktion: Fitnesscheck erfolgt anhand der Segmentlänge und der Jacobi-Konstante.
Die Segmentlänge muss möglichst gut zum Sollwert passen. Die Jacobi-Konstante am Punkt x muss zur
Jacobi-Konstanten am Startpunkt passen, damit der Polygonzug auf derselben geodätischen Linie bleibt.
:param x: Koordinate in beta, lambda aus der CMA-ES
:return: Fitnesswert (f)
"""
beta = x[0]
omega = wrap_mpi_pi(x[1])
P = ell.ell2cart_karney(beta, omega) # in kartesischer Koordinaten
d = float(np.linalg.norm(P - P_i)) # Distanz zwischen
# maxSegLen einhalten
J_len = ((d - ds) / ds) ** 2
w_len = 1.0
# Azimut für Jacobi-Konstante
E_j, N_j, U_j, _, _, _ = ENU_beta_omega(beta, omega, ell)
alpha_end = azimuth_at_ESpoint(P_i, P, E_j, N_j, U_j)
# Jacobi-Konstante
g_end = jacobi_konstante(beta, omega, alpha_end, ell)
J_gamma = (g_end - gamma0) ** 2
w_gamma = 10
f = float(w_len * J_len + w_gamma * J_gamma)
return f
xb = escma(fitness, N=2, xmean=xmean, sigma=sigma0) # Aufruf CMA-ES
beta_best = xb[0]
omega_best = wrap_mpi_pi(xb[1])
P_best = ell.ell2cart_karney(beta_best, omega_best)
E_j, N_j, U_j, _, _, _ = ENU_beta_omega(beta_best, omega_best, ell)
alpha_end = azimuth_at_ESpoint(P_i, P_best, E_j, N_j, U_j)
return beta_best, omega_best, P_best, alpha_end
def gha1_ES(ell: EllipsoidTriaxial, beta0: float, omega0: float, alpha0: float, s_total: float, maxSegLen: float = 1000, all_points: bool = False)\
-> Tuple[NDArray, float, NDArray] | Tuple[NDArray, float]:
"""
Aufruf der 1. GHA mittels CMA-ES
:param ell: Ellipsoid
:param beta0: Beta Startkoordinate
:param omega0: Omega Startkoordinate
:param alpha0: Azimut Startkoordinate
:param s_total: Gesamtstrecke
:param maxSegLen: maximale Segmentlänge
:param all_points: Alle Punkte ausgeben?
:return: Zielpunkt Pk, Azimut am Zielpunkt und Punktliste
"""
beta = float(beta0)
omega = wrap_mpi_pi(float(omega0))
alpha = wrap_mpi_pi(float(alpha0))
gamma0 = jacobi_konstante(beta, omega, alpha, ell) # Referenz-γ0
P_all: List[NDArray] = [ell.ell2cart_karney(beta, omega)]
alpha_end: List[float] = [alpha]
s_acc = 0.0
step = 0
nsteps_est = int(np.ceil(s_total / maxSegLen))
while s_acc < s_total - 1e-9:
step += 1
ds = min(maxSegLen, s_total - s_acc)
# print(f"[GHA1-ES] Step {step}/{nsteps_est} ds={ds:.3f} m s_acc={s_acc:.3f} m beta={beta:.6f} omega={omega:.6f} alpha={alpha:.6f}")
beta, omega, P, alpha = optimize_next_point(beta_i=beta, omega_i=omega, alpha_i=alpha, ds=ds, gamma0=gamma0,
ell=ell, maxSegLen=maxSegLen)
s_acc += ds
P_all.append(P)
alpha_end.append(wrap_mpi_pi(alpha))
if step > nsteps_est + 50:
raise RuntimeError("GHA1_ES: Zu viele Schritte vermutlich Konvergenzproblem / falsche Azimut-Konvention.")
Pk = P_all[-1]
alpha1 = float(alpha_end[-1])
if all_points:
return Pk, alpha1, np.array(P_all)
else:
return Pk, alpha1
if __name__ == "__main__":
ell = EllipsoidTriaxial.init_name("BursaSima1980round")
s = 180000
# alpha0 = 3
alpha0 = wu.gms2rad([5, 0, 0])
beta = 0
omega = 0
P0 = ell.ell2cart(beta, omega)
point1, alpha1 = gha1_ana(ell, P0, alpha0=alpha0, s=s, maxM=100, maxPartCircum=32)
point1app, alpha1app = gha1_approx(ell, P0, alpha0=alpha0, s=s, ds=1000)
res, alpha, points = gha1_ES(ell, beta0=beta, omega0=-omega, alpha0=alpha0, s_total=s, maxSegLen=1000)
print(point1)
print(res)
print(alpha)
print(points)
# print("alpha1 (am Endpunkt):", res.alpha1)
print(res - point1)
print(point1app - point1, "approx")

182
ES/gha2_ES.py Normal file
View File

@@ -0,0 +1,182 @@
from typing import Tuple
import numpy as np
import plotly.graph_objects as go
from numpy.typing import NDArray
from ES.Hansen_ES_CMA import escma
from GHA_triaxial.gha2_num import gha2_num
from GHA_triaxial.utils import sigma2alpha
from ellipsoid_triaxial import EllipsoidTriaxial
def Sehne(P1: NDArray, P2: NDArray) -> float:
"""
Berechnung der 3D-Distanz zwischen zwei kartesischen Punkten
:param P1: kartesische Koordinate Punkt 1
:param P2: kartesische Koordinate Punkt 2
:return: Bogenlänge s
"""
R12 = P2-P1
s = float(np.linalg.norm(R12))
return s
def gha2_ES(ell: EllipsoidTriaxial, P0: NDArray, Pk: NDArray, maxSegLen: float = None, all_points: bool = False) -> Tuple[float, float, float, NDArray] | Tuple[float, float, float]:
"""
Berechnen der 2. GHA mithilfe der CMA-ES.
Die CMA-ES optimiert sukzessive den Mittelpunkt zwischen Start- und Zielpunkt. Der Abbruch der Berechnung erfolgt, wenn alle Segmentlängen <= maxSegLen sind.
Die Distanzen zwischen den einzelnen Punkten werden als direkte 3D-Distanzen berechnet und aufaddiert.
:param ell: Ellipsoid
:param P0: Startpunkt
:param Pk: Zielpunkt
:param maxSegLen: maximale Segmentlänge
:param all_points: Ergebnisliste mit allen Punkte, die wahlweise mit ausgegeben wird
:return: Richtungswinkel in RAD des Start- und Zielpunktes und Gesamtlänge
"""
P_left: NDArray = None
P_right: NDArray = None
def midpoint_fitness(x: tuple) -> float:
"""
Fitness für einen Mittelpunkt P_middle zwischen P_left und P_right auf dem triaxialen Ellipsoid:
- Minimiert d(P_left, P_middle) + d(P_middle, P_right)
- Erzwingt d(P_left,P_middle) ≈ d(P_middle,P_right) (echter Mittelpunkt im Sinne der Polygonkette)
:param x: enthält die Startwerte von u und v
:return: Fitnesswert (f)
"""
nonlocal P_left, P_right, ell
u, v = x
P_middle = ell.para2cart(u, v)
d1 = Sehne(P_left, P_middle)
d2 = Sehne(P_middle, P_right)
base = d1 + d2
# midpoint penalty (dimensionslos)
# relative Differenz, skaliert über verschiedene Segmentlängen
denom = max(base, 1e-9)
pen_equal = ((d1 - d2) / denom) ** 2
w_equal = 10.0
f = base + denom * w_equal * pen_equal
return f
R0 = (ell.ax + ell.ay + ell.b) / 3
if maxSegLen is None:
maxSegLen = R0 * 1 / (637.4*2) # 10km Segment bei mittleren Erdradius
sigma_uv_nom = 1e-3 * (maxSegLen / R0) # ~1e-5
points: list[NDArray] = [P0, Pk]
startIter = 0
level = 0
while True:
seg_lens = [Sehne(points[i], points[i+1]) for i in range(len(points)-1)]
max_len = max(seg_lens)
if max_len <= maxSegLen:
break
level += 1
new_points: list[NDArray] = [points[0]]
for i in range(len(points) - 1):
A = points[i]
B = points[i+1]
dAB = Sehne(A, B)
# print(dAB)
if dAB > maxSegLen:
# global P_left, P_right
P_left, P_right = A, B
Au, Av = ell.cart2para(A)
Bu, Bv = ell.cart2para(B)
u0 = (Au + Bu) / 2
v0 = Av + 0.5 * np.arctan2(np.sin(Bv - Av), np.cos(Bv - Av))
xmean = [u0, v0]
sigmaStep = sigma_uv_nom * (Sehne(A, B) / maxSegLen)
u, v = escma(midpoint_fitness, N=2, xmean=xmean, sigma=sigmaStep) # Aufruf CMA-ES
P_next = ell.para2cart(u, v)
new_points.append(P_next)
startIter += 1
maxIter = 10000
if startIter > maxIter:
raise RuntimeError("GHA2_ES: maximale Iterationen überschritten")
new_points.append(B)
points = new_points
# print(f"[Level {level}] Punkte: {len(points)} | max Segment: {max_len:.3f} m")
P_all = np.vstack(points)
totalLen = float(np.sum(np.linalg.norm(P_all[1:] - P_all[:-1], axis=1)))
if len(points) >= 3:
p0i = ell.point_onto_ellipsoid(P0 + 10.0 * (points[1] - P0) / np.linalg.norm(points[1] - P0))
sigma0 = (p0i - P0) / np.linalg.norm(p0i - P0)
alpha0 = sigma2alpha(ell, sigma0, P0)
p1i = ell.point_onto_ellipsoid(Pk - 10.0 * (Pk - points[-2]) / np.linalg.norm(Pk - points[-2]))
sigma1 = (Pk - p1i) / np.linalg.norm(Pk - p1i)
alpha1 = sigma2alpha(ell, sigma1, Pk)
else:
alpha0 = None
alpha1 = None
if all_points:
return alpha0, alpha1, totalLen, P_all
return alpha0, alpha1, totalLen
def show_points(points: NDArray, pointsES: NDArray, p0: NDArray, p1: NDArray):
"""
Anzeigen der Punkte
:param points: wahre Punkte der Linie
:param pointsES: Punkte der Linie aus ES
:param p0: wahrer Startpunkt
:param p1: wahrer Endpunkt
"""
fig = go.Figure()
fig.add_scatter3d(x=pointsES[:, 0], y=pointsES[:, 1], z=pointsES[:, 2],
mode='lines', line=dict(color="green", width=3), name="Numerisch")
fig.add_scatter3d(x=points[:, 0], y=points[:, 1], z=points[:, 2],
mode='lines', line=dict(color="red", width=3), name="ES")
fig.add_scatter3d(x=[p0[0]], y=[p0[1]], z=[p0[2]],
mode='markers', marker=dict(color="black"), name="P0")
fig.add_scatter3d(x=[p1[0]], y=[p1[1]], z=[p1[2]],
mode='markers', marker=dict(color="black"), name="P1")
fig.update_layout(
scene=dict(xaxis_title='X [km]',
yaxis_title='Y [km]',
zaxis_title='Z [km]',
aspectmode='data'))
fig.show()
if __name__ == '__main__':
ell = EllipsoidTriaxial.init_name("Bursa1970")
beta0, lamb0 = (0.2, 0.1)
P0 = ell.ell2cart(beta0, lamb0)
beta1, lamb1 = (0.3, 0.2)
P1 = ell.ell2cart(beta1, lamb1)
alpha0, alpha1, s_num, betas, lambs = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=1000, all_points=True)
points_num = []
for beta, lamb in zip(betas, lambs):
points_num.append(ell.ell2cart(beta, lamb))
points_num = np.array(points_num)
alpha0, alpha1, s, points = gha2_ES(ell, P0, P1)
print(s_num)
print(s)
print(alpha0)
print(alpha1)
print(s - s_num)
show_points(points, points_num, P0, P1)

View File

@@ -1,25 +0,0 @@
from numpy import *
import scipy as sp
def gha1(re, phi_p1, lambda_p1, A_p1, s):
psi_p1 = re.phi2psi(phi_p1)
A_0 = arcsin(cos(psi_p1) * sin(A_p1))
temp = sin(psi_p1) / cos(A_0)
sigma_p1 = arcsin(sin(psi_p1) / cos(A_0))
sqrt_sigma = lambda sigma: sqrt(1 + re.e_ ** 2 * cos(A_0) ** 2 * sin(sigma) ** 2)
int_sqrt_sigma = lambda sigma: sp.integrate.quad(sqrt_sigma, sigma_p1, sigma)[0]
f_sigma_p2i = lambda sigma_p2i: (int_sqrt_sigma(sigma_p2i) - s / re.b)
sigma_p2_0 = sigma_p1 + s / re.a
sigma_p2 = sp.optimize.newton(f_sigma_p2i, sigma_p2_0)
psi_p2 = arcsin(cos(A_0) * sin(sigma_p2))
phi_p2 = re.psi2phi(psi_p2)
A_p2 = arcsin(sin(A_0) / cos(psi_p2))
f_d_lambda = lambda sigma: sin(A_0) * sqrt_sigma(sigma) / (1 - cos(A_0)**2 * sin(sigma)**2)
d_lambda = sqrt(1-re.e**2) * sp.integrate.quad(f_d_lambda, sigma_p1, sigma_p2)[0]
lambda_p2 = lambda_p1 + d_lambda
return phi_p2, lambda_p2, A_p2

View File

@@ -1,107 +0,0 @@
from numpy import sin, cos, pi, sqrt, tan, arcsin, arccos, arctan
import ausgaben as aus
def gha1(re, phi_p1, lambda_p1, A_p1, s, eps):
"""
Berechnung der 1. Geodätische Hauptaufgabe nach Gauß´schen Mittelbreitenformeln
:param re: Klasse Ellipsoid
:param phi_p1: Breite Punkt 1
:param lambda_p1: Länge Punkt 1
:param A_p1: Azimut der geodätischen Linie in Punkt 1
:param s: Strecke zu Punkt 2
:param eps: Abbruchkriterium für Winkelgrößen
:return: Breite, Länge, Azimut von Punkt 2
"""
t = lambda phi: tan(phi)
eta = lambda phi: sqrt(re.e_ ** 2 * cos(phi) ** 2)
F1 = lambda A, phi, s: 1 + (2 + 3 * t(phi)**2 + 2 * eta(phi)**2) / (24 * re.N(phi) ** 2) * sin(A) ** 2 * s ** 2 \
+ (t(phi)**2 - 1) * eta(phi) ** 2 / (8 * re.N(phi) ** 2) * cos(A) ** 2 * s ** 2
F2 = lambda A, phi, s: 1 + t(phi) ** 2 / (24 * re.N(phi) ** 2) * sin(A) ** 2 * s ** 2 \
- (1 + eta(phi)**2 - 9 * eta(phi)**2 * t(phi)**2) / (24 * re.N(phi) ** 2) * cos(A) ** 2 * s ** 2
F3 = lambda A, phi, s: 1 + (1 + eta(phi)**2) / (12 * re.N(phi) ** 2) * sin(A) ** 2 * s ** 2 \
+ (3 + 8 * eta(phi)**2) / (24 * re.N(phi) ** 2) * cos(A) ** 2 * s ** 2
phi_p2_i = lambda A, phi: phi_p1 + cos(A) / re.M(phi) * s * F1(A, phi, s)
lambda_p2_i = lambda A, phi: lambda_p1 + sin(A) / (re.N(phi) * cos(phi)) * s * F2(A, phi, s)
A_p2_i = lambda A, phi: A_p1 + sin(A) * tan(phi) / re.N(phi) * s * F3(A, phi, s)
phi_p0_i = lambda phi2: (phi_p1 + phi2) / 2
A_p1_i = lambda A2: (A_p1 + A2) / 2
phi_p0 = []
A_p0 = []
phi_p2 = []
lambda_p2 = []
A_p2 = []
# 1. Näherung für P2
phi_p2.append(phi_p1 + cos(A_p1) / re.M(phi_p1) * s)
lambda_p2.append(lambda_p1 + sin(A_p1) / (re.N(phi_p1) * cos(phi_p1)) * s)
A_p2.append(A_p1 + sin(A_p1) * tan(phi_p1) / re.N(phi_p1) * s)
while True:
# Berechnug P0 durch Mittelbildung
phi_p0.append(phi_p0_i(phi_p2[-1]))
A_p0.append(A_p1_i(A_p2[-1]))
# Berechnung P2
phi_p2.append(phi_p2_i(A_p0[-1], phi_p0[-1]))
lambda_p2.append(lambda_p2_i(A_p0[-1], phi_p0[-1]))
A_p2.append(A_p2_i(A_p0[-1], phi_p0[-1]))
# Abbruchkriterium
if abs(phi_p2[-2] - phi_p2[-1]) < eps and \
abs(lambda_p2[-2] - lambda_p2[-1]) < eps and \
abs(A_p2[-2] - A_p2[-1]) < eps:
break
nks = 5
for i in range(len(phi_p2)):
print(f"P2[{i}]: {aus.gms('phi', phi_p2[i], nks)}\t{aus.gms('lambda', lambda_p2[i], nks)}\t{aus.gms('A', A_p2[i], nks)}")
if i != len(phi_p2)-1:
print(f"P0[{i}]: {aus.gms('phi', phi_p0[i], nks)}\t\t\t\t\t\t\t\t{aus.gms('A', A_p0[i], nks)}")
return phi_p2, lambda_p2, A_p2
def gha2(re, phi_p1, lambda_p1, phi_p2, lambda_p2):
"""
Berechnung der 2. Geodätische Hauptaufgabe nach Gauß´schen Mittelbreitenformeln
:param re: Klasse Ellipsoid
:param phi_p1: Breite Punkt 1
:param lambda_p1: Länge Punkt 1
:param phi_p2: Breite Punkt 2
:param lambda_p2: Länge Punkt 2
:return: Länge der geodätischen Linie, Azimut von P1 nach P2, Azimut von P2 nach P1
"""
t = lambda phi: tan(phi)
eta = lambda phi: sqrt(re.e_ ** 2 * cos(phi) ** 2)
phi_0 = (phi_p1 + phi_p2) / 2
d_phi = phi_p2 - phi_p1
d_lambda = lambda_p2 - lambda_p1
f_A = lambda phi: (2 + 3*t(phi)**2 + 2*eta(phi)**2) / 24
f_B = lambda phi: ((t(phi)**2 - 1) * eta(phi)**2) / 8
# f_C = lambda phi: (t(phi)**2) / 24
f_D = lambda phi: (1 + eta(phi)**2 - 9 * eta(phi)**2 * t(phi)**2) / 24
F1 = lambda phi: d_phi * re.M(phi) * (1 - f_A(phi) * d_lambda ** 2 * cos(phi) ** 2 -
f_B(phi) * d_phi ** 2 / re.V(phi) ** 4)
F2 = lambda phi: d_lambda * re.N(phi) * cos(phi) * (1 - 1 / 24 * d_lambda ** 2 * sin(phi) ** 2 +
f_D(phi) * d_phi ** 2 / re.V(phi) ** 4)
s = sqrt(F1(phi_0) ** 2 + F2(phi_0) ** 2)
A_0 = arctan(F2(phi_0) / F1(phi_0))
d_A = d_lambda * sin(phi_0) * (1 + (1 + eta(phi_0) ** 2) / 12 * s ** 2 * sin(A_0) ** 2 / re.N(phi_0) ** 2 +
(3 + 8 * eta(phi_0) ** 2) / 24 * s ** 2 * cos(A_0) ** 2 / re.N(phi_0) ** 2)
A_p1 = A_0 - d_A / 2
A_p2 = A_0 + d_A / 2
A_p2_p1 = A_p2 + pi
return s, A_p1, A_p2_p1

View File

@@ -1,21 +0,0 @@
import runge_kutta as rk
from numpy import sin, cos, tan
import winkelumrechnungen as wu
from ellipsoide import EllipsoidBiaxial
import numpy as np
def gha1(re: EllipsoidBiaxial, x0, y0, z0, A0, s, num):
phi0, lamb0, h0 = re.cart2ell(0.001, wu.gms2rad([0, 0, 0.001]), x0, y0, z0)
def buildODE():
def ODE(s, v):
phi, lam, A = v
dphi = cos(A) * re.V(phi) ** 3 / re.c
dlam = sin(A) * re.V(phi) / (cos(phi) * re.c)
dA = tan(phi) * sin(A) * re.V(phi) / re.c
return np.array([dphi, dlam, dA])
return ODE
_, funktionswerte = rk.rk4(buildODE(), 0, np.array([phi0, lamb0, A0]), s, num)
coords = re.ell2cart(funktionswerte[-1][0], funktionswerte[-1][1], h0)
return coords

View File

@@ -1,228 +0,0 @@
import numpy as np
from numpy import arccos
from Hansen_ES_CMA import escma
from ellipsoide import EllipsoidTriaxial
from numpy.typing import NDArray
import plotly.graph_objects as go
from GHA_triaxial.panou_2013_2GHA_num import gha2_num
from utils import sigma2alpha
ell_ES: EllipsoidTriaxial = None
P_start: NDArray = None
P_prev: NDArray = None
P_next: NDArray = None
P_end: NDArray = None
stepLen: float = None
def Bogenlaenge(P1: NDArray, P2: NDArray) -> float:
"""
Berechnung der mittleren Bogenlänge zwischen zwei kartesischen Punkten
:param P1: kartesische Koordinate Punkt 1
:param P2: kartesische Koordinate Punkt 2
:return: Bogenlänge s
"""
R1 = np.linalg.norm(P1)
R2 = np.linalg.norm(P2)
R = 0.5 * (R1 + R2)
theta = arccos(P1 @ P2 / (R1 * R2))
s = float(R * theta)
return s
def gha2_ES(ell: EllipsoidTriaxial, P0: NDArray, Pk: NDArray, stepLenTarget: float = None, sigmaStep: float = 1e-5, stopeval: int = 1000, maxSteps: int = 10000, all_points: bool = False):
"""
Berechnen der 2. GHA mithilfe der CMA-ES.
Die CMA-ES optimiert sukzessive einzelne Punkte, die einen definierten Abstand (stepLenTarget) zum vorherigen und den kürzesten
Abstand zum Zielpunkt aufweisen. Der Abbruch der Optimierung erfolgt, wenn die Restdistanz zwischen vorherigen und Zielpunkt die
'stepLenTarget' unterschreitet. Die Distanzen zwischen den einzelnen Punkten werden als mittlere Bogenlänge berechnet und aufaddiert.
:param ell: Parameter des triaxialen Ellipsoids
:param P0: Startpunkt
:param Pk: Zielpunkt
:param stepLenTarget: Abstand zwischen vorherigen und optimierten Punkt
:param sigmaStep: Sigma Startwert für die CMA-ES (Suchraum um den zu optimierenden Punkt)
:param stopeval: maximale Iterationen
:param maxSteps: maximale Anzahl der zu optimierenden Punkte
:param all_points: Ergebnisliste mit allen Punkte, die wahlweise mit ausgegeben werden kann
:return: Richtungswinkel des Start- und Zielpunktes, totalLen
"""
global ell_ES, P_start, P_prev, P_next, P_end, stepLen
ell_ES = ell
P_start = P0
P_end = Pk
if stepLenTarget is None:
R0 = (ell.ax + ell.ay + ell.b) / 3
stepLenTarget = R0 * 1 / 600
stepLen = stepLenTarget
P_all = [P_start]
totalLen = 0
P_prev = P_start
for i in range(1, maxSteps):
d_remain = Bogenlaenge(P_prev, P_end)
# Abbruch: letzter "Rest-Schritt" ist < 10 km -> Ziel anhängen
if d_remain <= stepLen:
P_all.append(P_end)
totalLen += d_remain
print(f'[Punkt {i}] Stop: Restdistanz {round(d_remain, 3)} m <= {round(stepLen, 3)} m, Ziel angehängt.')
break
# Globals für Fitness: aktueller Start(P0) und Ziel(Pk)
# P0 = P_prev;
# Pk = P_end;
# Näherung für die ES ermitteln
# % d = P_end - P_prev;
# % L = Bogenlaenge(P_prev, P_end);
# % t = min(stepLen / L, 1.0);
# % Q = P_prev + t * d;
# % q = [Q(1) / a;
# Q(2) / b;
# Q(3) / c];
# % nq = norm(q);
# % q = q / nq;
# %q
# entspricht[cos(u)
# cos(v);
# cos(u)
# sin(v);
# sin(u)] auf
# Einheitskugel
#arg_u = max(-1, min(1, q(3)));
#
# %Quadrantenabfrage
#u0 = mod(asin(arg_u) + pi / 2, pi) - pi / 2;
#v0 = atan2(q(2), q(1));
#xmean_init = [u0;v0];
xmean_init = ell.point_onto_ellipsoid(P_prev + stepLen * (P_end - P_prev) / np.linalg.norm(P_end - P_prev))
# [~, ~, aux] = geoLength(xmean_init);
# print('Startguess: d_step=%.3f (soll %.3f), d_to_target=%.3f\n', aux(1), stepLen, aux(2));
print(f'[Punkt {i}] Optimiere nächsten Punkt: Restdistanz = {round(d_remain, 3)} m')
xmean_init = np.array(ell_ES.cart2para(xmean_init))
u, v = escma(geoLength, N=2, xmean=xmean_init, sigma=sigmaStep, stopfitness=-np.inf, stopeval=stopeval)
P_next = ell.para2cart(u, v)
d_step = Bogenlaenge(P_prev, P_next)
d_new = Bogenlaenge(P_next, P_end)
d_old = Bogenlaenge(P_prev, P_end)
print(f'[Punkt {i}] Ergebnis: Schritt = {round(d_step, 3)} m (soll {round(stepLen, 3)}), Rest neu = {round(d_new, 3)} m')
# Sicherheitscheck: wenn wir nicht näher kommen, abbrechen
if d_new >= d_old:
print(f'Punkt {i}: Neuer Punkt ist nicht naeher am Ziel ({d_old} -> {d_new}). Abbruch.')
P_all.append(P_end)
totalLen += Bogenlaenge(P_prev, P_end)
break
P_all.append(P_next)
totalLen += d_step
P_prev = P_next
print('Maximale Schrittanzahl erreicht.')
P_all.append(P_end)
totalLen += Bogenlaenge(P_prev, P_end)
p0i = ell.point_onto_ellipsoid(P0 + 10 * (P_all[1] - P0) / np.linalg.norm(P_all[1] - P0))
sigma0 = (p0i - P0) / np.linalg.norm(p0i - P0)
alpha0 = sigma2alpha(ell_ES, sigma0, P0)
p1i = ell.point_onto_ellipsoid(Pk - 10 * (Pk - P_all[-2]) / np.linalg.norm(Pk - P_all[-2]))
sigma1 = (Pk - p1i) / np.linalg.norm(Pk - p1i)
alpha1 = sigma2alpha(ell_ES, sigma1, Pk)
if all_points:
return alpha0, alpha1, totalLen, np.array(P_all)
else:
return alpha0, alpha1, totalLen
def geoLength(P_candidate: Tuple) -> float:
"""
Berechung der Fitness eines Kandidaten anhand der Strecken
:param P_candidate: Kandidat in parametrischen Koordinaten
:return: Fitness-Wert
"""
# P_candidate = [u;v] des naechsten Punktes.
# Ziel: Distanz zum Ziel minimieren, aber Schrittlaenge ~ stepLenTarget erzwingen.
u, v = P_candidate
global ell_ES, P_start, P_prev, P_next, P_end, stepLen
# Punkt auf Ellipsoid
P_next = ell_ES.para2cart(u, v)
# Distanzen
d_step = Bogenlaenge(P_prev, P_next)
d_to_target = Bogenlaenge(P_end, P_next)
d_prev_to_target = Bogenlaenge(P_end, P_prev)
# Penalties(dimensionslos)
pen_step = ((d_step - stepLen) / stepLen)**2
# falls Punkt "weg" vom Ziel geht, extra bestrafen
pen_away = max(0.0, (d_to_target - d_prev_to_target) / stepLen)**2
# Gewichtungen
alpha = 1e2
# Schrittlaenge sehr hart
gamma = 1e2 # "nicht weg vom Ziel" hart
f = d_to_target * (1 + alpha * pen_step + gamma * pen_away)
# Für Debug / Extraktion
# aux = [d_step, d_to_target]
return f # , P_candidate, aux
def show_points(points: NDArray, pointsES: NDArray, p0: NDArray, p1: NDArray):
"""
Anzeigen der Punkte
:param points: wahre Punkte der Linie
:param pointsES: Punkte der Linie aus ES
:param p0: wahrer Startpunkt
:param p1: wahrer Endpunkt
"""
fig = go.Figure()
fig.add_scatter3d(x=pointsES[:, 0], y=pointsES[:, 1], z=pointsES[:, 2],
mode='lines', line=dict(color="green", width=3), name="Numerisch")
fig.add_scatter3d(x=points[:, 0], y=points[:, 1], z=points[:, 2],
mode='lines', line=dict(color="red", width=3), name="ES")
fig.add_scatter3d(x=[p0[0]], y=[p0[1]], z=[p0[2]],
mode='markers', marker=dict(color="black"), name="P0")
fig.add_scatter3d(x=[p1[0]], y=[p1[1]], z=[p1[2]],
mode='markers', marker=dict(color="black"), name="P1")
fig.update_layout(
scene=dict(xaxis_title='X [km]',
yaxis_title='Y [km]',
zaxis_title='Z [km]',
aspectmode='data'))
fig.show()
if __name__ == '__main__':
ell = EllipsoidTriaxial.init_name("Fiction")
beta0, lamb0 = (0.2, 0.1)
P0 = ell.ell2cart(beta0, lamb0)
beta1, lamb1 = (0.7, 0.3)
P1 = ell.ell2cart(beta1, lamb1)
alpha0, alpha1, s_num, betas, lambs = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=10000, all_points=True)
points_num = []
for beta, lamb in zip(betas, lambs):
points_num.append(ell.ell2cart(beta, lamb))
points_num = np.array(points_num)
alpha0, alpha1, s, points = gha2_ES(ell, P0, P1, all_points=True, sigmaStep=1e-5)
print(s - s_num)
show_points(points, points_num, P0, P1)

145
GHA_triaxial/gha1_ana.py Normal file
View File

@@ -0,0 +1,145 @@
import math
from math import comb
from typing import Tuple
import numpy as np
from numpy import arctan2, cos, sin
from numpy.typing import NDArray
import winkelumrechnungen as wu
from GHA_triaxial.utils import pq_para
from ellipsoid_triaxial import EllipsoidTriaxial
from utils_angle import wrap_0_2pi
def gha1_ana_step(ell: EllipsoidTriaxial, point: NDArray, alpha0: float, s: float, maxM: int) -> Tuple[NDArray, float]:
"""
Panou, Korakitits 2020, 5ff.
:param ell: Ellipsoid
:param point: Punkt in kartesischen Koordinaten
:param alpha0: Azimut im Startpunkt
:param s: Strecke
:param maxM: maximale Ordnung
:return: Zwischenpunkt, Azimut im Zwischenpunkt
"""
x, y, z = point
# S. 6
x_m = [x]
y_m = [y]
z_m = [z]
p, q = pq_para(ell, point)
# 48-50
x_m.append(p[0] * sin(alpha0) + q[0] * cos(alpha0))
y_m.append(p[1] * sin(alpha0) + q[1] * cos(alpha0))
z_m.append(p[2] * sin(alpha0) + q[2] * cos(alpha0))
# 34
H_ = lambda p: np.sum([comb(p, p - i) * (x_m[p - i] * x_m[i] +
1 / (1 - ell.ee ** 2) ** 2 * y_m[p - i] * y_m[i] +
1 / (1 - ell.ex ** 2) ** 2 * z_m[p - i] * z_m[i])
for i in range(0, p + 1)])
# 35
h_ = lambda q: np.sum([comb(q, q-j) * (x_m[q-j+1] * x_m[j+1] +
1 / (1 - ell.ee ** 2) * y_m[q-j+1] * y_m[j+1] +
1 / (1 - ell.ex ** 2) * z_m[q-j+1] * z_m[j+1])
for j in range(0, q+1)])
# 31
hH_ = lambda t: 1/H_(0) * (h_(t) - np.sum([comb(t, l-1) * H_(t+1-l) * hH_t[l-1] for l in range(1, t+1)]))
# 28-30
x_ = lambda m: - np.sum([comb(m-2, k) * hH_t[m-2-k] * x_m[k] for k in range(0, m-2+1)])
y_ = lambda m: -1 / (1-ell.ee**2) * np.sum([comb(m-2, k) * hH_t[m-2-k] * y_m[k] for k in range(0, m-2+1)])
z_ = lambda m: -1 / (1-ell.ex**2) * np.sum([comb(m-2, k) * hH_t[m-2-k] * z_m[k] for k in range(0, m-2+1)])
hH_t = []
a_m = []
b_m = []
c_m = []
for m in range(0, maxM+1):
if m >= 2:
hH_t.append(hH_(m-2))
x_m.append(x_(m))
y_m.append(y_(m))
z_m.append(z_(m))
fact_m = math.factorial(m)
# 22-24
a_m.append(x_m[m] / fact_m)
b_m.append(y_m[m] / fact_m)
c_m.append(z_m[m] / fact_m)
# 19-21
x_s = 0
for a in reversed(a_m):
x_s = x_s * s + a
y_s = 0
for b in reversed(b_m):
y_s = y_s * s + b
z_s = 0
for c in reversed(c_m):
z_s = z_s * s + c
p1 = np.array([x_s, y_s, z_s])
p_s, q_s = pq_para(ell, p1)
# 57-59
dx_s = 0
for i, a in reversed(list(enumerate(a_m[1:], start=1))):
dx_s = dx_s * s + i * a
dy_s = 0
for i, b in reversed(list(enumerate(b_m[1:], start=1))):
dy_s = dy_s * s + i * b
dz_s = 0
for i, c in reversed(list(enumerate(c_m[1:], start=1))):
dz_s = dz_s * s + i * c
# 52-53
sigma = np.array([dx_s, dy_s, dz_s])
P = float(p_s @ sigma)
Q = float(q_s @ sigma)
# 51
alpha1 = arctan2(P, Q)
if alpha1 < 0:
alpha1 += 2 * np.pi
return p1, wrap_0_2pi(alpha1)
def gha1_ana(ell: EllipsoidTriaxial, point: NDArray, alpha0: float, s: float, maxM: int, maxPartCircum: int = 4) -> Tuple[NDArray, float]:
"""
:param ell: Ellipsoid
:param point: Punkt in kartesischen Koordinaten
:param alpha0: Azimut im Startpunkt
:param s: Strecke
:param maxM: maximale Ordnung
:param maxPartCircum: maximale Aufteilung (1/x halber Ellipsoidumfang)
:return: Zielpunkt, Azimut im Zielpunkt
"""
if s > np.pi / maxPartCircum * ell.ax:
s /= 2
point_step, alpha_step = gha1_ana(ell, point, alpha0, s, maxM, maxPartCircum)
point_end, alpha_end = gha1_ana(ell, point_step, alpha_step, s, maxM, maxPartCircum)
else:
point_end, alpha_end = gha1_ana_step(ell, point, alpha0, s, maxM)
_, _, h = ell.cart2geod(point_end, "ligas3")
if h > 1e-5:
raise Exception("GHA1_ana: explodiert, Punkt liegt nicht mehr auf dem Ellipsoid")
return point_end, wrap_0_2pi(alpha_end)
if __name__ == "__main__":
ell = EllipsoidTriaxial.init_name("BursaSima1980round")
p0 = ell.ell2cart(wu.deg2rad(10), wu.deg2rad(20))
p1, alpha1 = gha1_ana(ell, p0, wu.deg2rad(36), 200000, 70)
print(p1, wu.rad2gms(alpha1))

View File

@@ -1,10 +1,18 @@
import numpy as np from typing import Tuple
from ellipsoide import EllipsoidTriaxial
from panou import louville_constant, func_sigma_ell, gha1_ana
import plotly.graph_objects as go
import winkelumrechnungen as wu
def gha1_approx(ell: EllipsoidTriaxial, p0: np.ndarray, alpha0: float, s: float, ds: float, all_points: bool = False) -> Tuple[NDArray, float] | Tuple[NDArray, float, NDArray]: import numpy as np
import plotly.graph_objects as go
from numpy import cos, sin
from numpy.typing import NDArray
import winkelumrechnungen as wu
from GHA_triaxial.utils import louville_constant, pq_ell
from ellipsoid_triaxial import EllipsoidTriaxial
from utils_angle import wrap_0_2pi
def gha1_approx(ell: EllipsoidTriaxial, p0: np.ndarray, alpha0: float, s: float, ds: float, all_points: bool = False) \
-> Tuple[NDArray, float] | Tuple[NDArray, float, NDArray, NDArray]:
""" """
Berechung einer Näherungslösung der ersten Hauptaufgabe Berechung einer Näherungslösung der ersten Hauptaufgabe
:param ell: Ellipsoid :param ell: Ellipsoid
@@ -19,27 +27,47 @@ def gha1_approx(ell: EllipsoidTriaxial, p0: np.ndarray, alpha0: float, s: float,
points = [p0] points = [p0]
alphas = [alpha0] alphas = [alpha0]
s_curr = 0.0 s_curr = 0.0
last_sigma = None
last_p = None
while s_curr < s: while s_curr < s:
ds_step = min(ds, s - s_curr) ds_step = min(ds, s - s_curr)
if ds_step < 1e-8: if ds_step < 1e-8:
break break
p1 = points[-1] p1 = points[-1]
alpha1 = alphas[-1] alpha1 = alphas[-1]
sigma = func_sigma_ell(ell, p1, alpha1)
p, q = pq_ell(ell, p1)
if last_p is not None and np.dot(p, last_p) < 0:
p = -p
q = -q
last_p = p
sigma = p * sin(alpha1) + q * cos(alpha1)
if last_sigma is not None and np.dot(sigma, last_sigma) < 0:
sigma = -sigma
alpha1 += np.pi
alpha1 = wrap_0_2pi(alpha1)
p2 = p1 + ds_step * sigma p2 = p1 + ds_step * sigma
p2 = ell.point_onto_ellipsoid(p2) p2 = ell.point_onto_ellipsoid(p2)
ds_step = np.linalg.norm(p2 - p1)
points.append(p2) dalpha = 1e-9
dalpha = 1e-6
l2 = louville_constant(ell, p2, alpha1) l2 = louville_constant(ell, p2, alpha1)
dl_dalpha = (louville_constant(ell, p2, alpha1+dalpha) - l2) / dalpha dl_dalpha = (louville_constant(ell, p2, alpha1+dalpha) - l2) / dalpha
alpha2 = alpha1 + (l0 - l2) / dl_dalpha if abs(dl_dalpha) < 1e-20:
alphas.append(alpha2) alpha2 = alpha1 + 0
else:
alpha2 = alpha1 + (l0 - l2) / dl_dalpha
points.append(p2)
alphas.append(wrap_0_2pi(alpha2))
ds_step = np.linalg.norm(p2 - p1)
s_curr += ds_step s_curr += ds_step
last_sigma = sigma
pass
if all_points: if all_points:
return points[-1], alphas[-1], np.array(points) return points[-1], alphas[-1], np.array(points), np.array(alphas)
else: else:
return points[-1], alphas[-1] return points[-1], alphas[-1]
@@ -70,11 +98,11 @@ def show_points(points: NDArray, p0: NDArray, p1: NDArray):
if __name__ == '__main__': if __name__ == '__main__':
ell = EllipsoidTriaxial.init_name("BursaSima1980round") ell = EllipsoidTriaxial.init_name("KarneyTest2024")
P0 = ell.para2cart(0, 0) P0 = ell.ell2cart(wu.deg2rad(15), wu.deg2rad(15))
alpha0 = wu.deg2rad(90) alpha0 = wu.deg2rad(270)
s = 1000000 s = 1
P1_ana, alpha1_ana = gha1_ana(ell, P0, alpha0, s, maxM=60, maxPartCircum=32) P1_app, alpha1_app, points, alphas = gha1_approx(ell, P0, alpha0, s, ds=0.1, all_points=True)
P1_app, alpha1_app, points = gha1_approx(ell, P0, alpha0, s, ds=5000, all_points=True) # P1_ana, alpha1_ana = gha1_ana(ell, P0, alpha0, s, maxM=40, maxPartCircum=32)
show_points(points, P0, P1_ana) # print(np.linalg.norm(P1_app - P1_ana))
print(np.linalg.norm(P1_app - P1_ana)) # show_points(points, P0, P0)

133
GHA_triaxial/gha1_num.py Normal file
View File

@@ -0,0 +1,133 @@
from typing import Callable, List, Tuple
import numpy as np
from numpy import arctan2, cos, sin
from numpy.typing import NDArray
import GHA_triaxial.numeric_examples_karney as ne_karney
import runge_kutta as rk
import winkelumrechnungen as wu
from GHA_triaxial.gha1_ana import gha1_ana
from GHA_triaxial.utils import alpha_ell2para, pq_ell
from ellipsoid_triaxial import EllipsoidTriaxial
from utils_angle import wrap_0_2pi
def buildODE(ell: EllipsoidTriaxial) -> Callable:
"""
Aufbau des DGL-Systems
:param ell: Ellipsoid
:return: DGL-System
"""
def ODE(s: float, v: NDArray) -> NDArray:
"""
DGL-System
:param s: unabhängige Variable
:param v: abhängige Variablen
:return: Ableitungen der abhängigen Variablen
"""
x, dxds, y, dyds, z, dzds = v
H = ell.func_H(np.array([x, y, z]))
h = dxds ** 2 + 1 / (1 - ell.ee ** 2) * dyds ** 2 + 1 / (1 - ell.ex ** 2) * dzds ** 2
ddx = -(h / H) * x
ddy = -(h / H) * y / (1 - ell.ee ** 2)
ddz = -(h / H) * z / (1 - ell.ex ** 2)
return np.array([dxds, ddx, dyds, ddy, dzds, ddz])
return ODE
def gha1_num(ell: EllipsoidTriaxial, point: NDArray, alpha0: float, s: float, num: int, all_points: bool = False) -> Tuple[NDArray, float] | Tuple[NDArray, float, List]:
"""
Panou, Korakitits 2019
:param ell: Ellipsoid
:param point: Punkt in kartesischen Koordinaten
:param alpha0: Azimut im Startpunkt
:param s: Strecke
:param num: Anzahl Zwischenpunkte
:param all_points: Ausgabe aller Punkte?
:return: Zielpunkt, Azimut im Zielpunkt (, alle Punkte)
"""
phi, lam, _ = ell.cart2geod(point, "ligas3")
p0 = ell.geod2cart(phi, lam, 0)
x0, y0, z0 = p0
p, q = pq_ell(ell, p0)
dxds0 = p[0] * sin(alpha0) + q[0] * cos(alpha0)
dyds0 = p[1] * sin(alpha0) + q[1] * cos(alpha0)
dzds0 = p[2] * sin(alpha0) + q[2] * cos(alpha0)
v_init = np.array([x0, dxds0, y0, dyds0, z0, dzds0])
ode = buildODE(ell)
_, werte = rk.rk4(ode, 0, v_init, s, num)
x1, dx1ds, y1, dy1ds, z1, dz1ds = werte[-1]
point1 = np.array([x1, y1, z1])
p1, q1 = pq_ell(ell, point1)
sigma = np.array([dx1ds, dy1ds, dz1ds])
P = float(p1 @ sigma)
Q = float(q1 @ sigma)
alpha1 = arctan2(P, Q)
alpha1 = wrap_0_2pi(alpha1)
_, _, h = ell.cart2geod(point1, "ligas3")
if h > 1e-5:
raise Exception("GHA1_num: explodiert, Punkt liegt nicht mehr auf dem Ellipsoid")
if all_points:
return point1, alpha1, werte
else:
return point1, alpha1
if __name__ == "__main__":
# ell = ellipsoide.EllipsoidTriaxial.init_name("BursaSima1980round")
# diffs_panou = []
# examples_panou = ne_panou.get_random_examples(5)
# for example in examples_panou:
# beta0, lamb0, beta1, lamb1, _, alpha0_ell, alpha1_ell, s = example
# P0 = ell.ell2cart(beta0, lamb0)
#
# P1_num, alpha1_num = gha1_num(ell, P0, alpha0_ell, s, 100)
# beta1_num, lamb1_num = ell.cart2ell(P1_num)
#
# _, _, alpha0_para = alpha_ell2para(ell, beta0, lamb0, alpha0_ell)
# P1_ana, alpha1_ana = gha1_ana(ell, P0, alpha0_para, s, 60)
# beta1_ana, lamb1_ana = ell.cart2ell(P1_ana)
# diffs_panou.append((abs(beta1-beta1_num), abs(lamb1-lamb1_num), abs(beta1-beta1_ana), abs(lamb1-lamb1_ana)))
# diffs_panou = np.array(diffs_panou)
# mask_360 = (diffs_panou > 359) & (diffs_panou < 361)
# diffs_panou[mask_360] = np.abs(diffs_panou[mask_360] - 360)
# print(diffs_panou)
ell: EllipsoidTriaxial = EllipsoidTriaxial.init_name("KarneyTest2024")
diffs_karney = []
# examples_karney = ne_karney.get_examples((30499, 30500, 40500))
examples_karney = ne_karney.get_random_examples(20)
for example in examples_karney:
beta0, lamb0, alpha0_ell, beta1, lamb1, alpha1_ell, s = example
P0 = ell.ell2cart(beta0, lamb0)
P1_num, alpha1_num = gha1_num(ell, P0, alpha0_ell, s, 10000)
beta1_num, lamb1_num = ell.cart2ell(P1_num)
try:
_, _, alpha0_para = alpha_ell2para(ell, beta0, lamb0, alpha0_ell)
P1_ana, alpha1_ana = gha1_ana(ell, P0, alpha0_para, s, 45, maxPartCircum=32)
beta1_ana, lamb1_ana = ell.cart2ell(P1_ana)
except:
beta1_ana, lamb1_ana = np.inf, np.inf
diffs_karney.append((wu.rad2deg(abs(beta1-beta1_num)), wu.rad2deg(abs(lamb1-lamb1_num)), wu.rad2deg(abs(beta1-beta1_ana)), wu.rad2deg(abs(lamb1-lamb1_ana))))
diffs_karney = np.array(diffs_karney)
mask_360 = (diffs_karney > 359) & (diffs_karney < 361)
diffs_karney[mask_360] = np.abs(diffs_karney[mask_360] - 360)
print(diffs_karney)

View File

@@ -1,15 +1,16 @@
import numpy as np
from ellipsoide import EllipsoidTriaxial
from GHA_triaxial.panou_2013_2GHA_num import gha2_num
import plotly.graph_objects as go
import winkelumrechnungen as wu
from numpy.typing import NDArray
from typing import Tuple from typing import Tuple
from utils import sigma2alpha import numpy as np
import plotly.graph_objects as go
from numpy.typing import NDArray
import winkelumrechnungen as wu
from GHA_triaxial.gha2_num import gha2_num
from GHA_triaxial.utils import sigma2alpha
from ellipsoid_triaxial import EllipsoidTriaxial
def gha2(ell: EllipsoidTriaxial, p0: NDArray, p1: NDArray, ds: float, all_points: bool = False) -> Tuple[float, float, float] | Tuple[float, float, float, NDArray]: def gha2_approx(ell: EllipsoidTriaxial, p0: NDArray, p1: NDArray, ds: float, all_points: bool = False) -> Tuple[float, float, float] | Tuple[float, float, float, NDArray]:
""" """
Numerische Approximation für die zweite Hauptaufgabe Numerische Approximation für die zweite Hauptaufgabe
:param ell: Ellipsoid :param ell: Ellipsoid
@@ -83,16 +84,16 @@ def show_points(points: NDArray, points_app: NDArray, p0: NDArray, p1: NDArray):
if __name__ == '__main__': if __name__ == '__main__':
ell = EllipsoidTriaxial.init_name("KarneyTest2024") ell = EllipsoidTriaxial.init_name("Bursa1970")
beta0, lamb0 = (0.2, 0.1) beta0, lamb0 = (0.1, 0.1)
P0 = ell.ell2cart(beta0, lamb0) P0 = ell.ell2cart(beta0, lamb0)
beta1, lamb1 = (0.7, 0.3) beta1, lamb1 = (0.3, np.pi)
P1 = ell.ell2cart(beta1, lamb1) P1 = ell.ell2cart(beta1, lamb1)
alpha0_app, alpha1_app, s_app, points = gha2(ell, P0, P1, ds=1e-4, all_points=True) alpha0_app, alpha1_app, s_app, points = gha2_approx(ell, P0, P1, ds=100, all_points=True)
print("done")
alpha0, alpha1, s, betas, lambs = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=5000, all_points=True) alpha0, alpha1, s, betas, lambs = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=10000, all_points=True)
points_ana = [] points_ana = []
for beta, lamb in zip(betas, lambs): for beta, lamb in zip(betas, lambs):
points_ana.append(ell.ell2cart(beta, lamb)) points_ana.append(ell.ell2cart(beta, lamb))

643
GHA_triaxial/gha2_num.py Normal file
View File

@@ -0,0 +1,643 @@
from typing import Tuple
import numpy as np
from numpy.typing import NDArray
import GHA_triaxial.numeric_examples_karney as ne_karney
import GHA_triaxial.numeric_examples_panou as ne_panou
import ausgaben as aus
import winkelumrechnungen as wu
from ellipsoid_triaxial import EllipsoidTriaxial
from runge_kutta import rk4, rk4_end, rk4_integral
from utils_angle import cot, wrap_0_2pi, wrap_mpi_pi
def norm_a(a: float) -> float:
a = float(a) % (2 * np.pi)
return a
def azimut(E: float, G: float, dbeta_du: float, dlamb_du: float) -> float:
north = np.sqrt(E) * dbeta_du
east = np.sqrt(G) * dlamb_du
return norm_a(np.arctan2(east, north))
def sph_azimuth(beta1, lam1, beta2, lam2):
dlam = wrap_mpi_pi(lam2 - lam1)
y = np.sin(dlam) * np.cos(beta2)
x = np.cos(beta1) * np.sin(beta2) - np.sin(beta1) * np.cos(beta2) * np.cos(dlam)
a = np.arctan2(y, x)
if a < 0:
a += 2 * np.pi
return a
# Panou 2013
def gha2_num(
ell: EllipsoidTriaxial,
beta_0: float,
lamb_0: float,
beta_1: float,
lamb_1: float,
n: int = 16000,
epsilon: float = 10**-12,
iter_max: int = 30,
all_points: bool = False,
) -> Tuple[float, float, float] | Tuple[float, float, float, NDArray, NDArray]:
"""
:param ell: Ellipsoid
:param beta_0: Beta Punkt 0
:param lamb_0: Lambda Punkt 0
:param beta_1: Beta Punkt 1
:param lamb_1: Lambda Punkt 1
:param n: Anzahl Schritte
:param epsilon: Genauigkeit
:param iter_max: Maximale Iterationen
:param all_points: Ausgabe aller Punkte
:return: Azimut Startpunkt, Azumit Zielpunkt, Strecke
"""
ax2 = float(ell.ax) * float(ell.ax)
ay2 = float(ell.ay) * float(ell.ay)
b2 = float(ell.b) * float(ell.b)
Ex2 = float(ell.Ex) * float(ell.Ex)
Ey2 = float(ell.Ey) * float(ell.Ey)
Ee2 = float(ell.Ee) * float(ell.Ee)
Ey4 = Ey2 * Ey2
Ee4 = Ee2 * Ee2
two_pi = 2.0 * np.pi
# Berechnung Koeffizienten, Gaußschen Fundamentalgrößen 1. Ordnung sowie deren Ableitungen
def BETA_LAMBDA(beta, lamb):
sb = np.sin(beta)
cb = np.cos(beta)
sl = np.sin(lamb)
cl = np.cos(lamb)
sb2 = sb * sb
cb2 = cb * cb
sl2 = sl * sl
cl2 = cl * cl
s2b = 2.0 * sb * cb
c2b = cb2 - sb2
s2l = 2.0 * sl * cl
c2l = cl2 - sl2
denB = Ex2 - Ey2 * sb2
denL = Ex2 - Ee2 * cl2
BETA = (ay2 * sb2 + b2 * cb2) / denB
LAMBDA = (ax2 * sl2 + ay2 * cl2) / denL
BETA_ = (ax2 * Ey2 * s2b) / (denB * denB)
LAMBDA_ = -(b2 * Ee2 * s2l) / (denL * denL)
BETA__ = (2.0 * ax2 * Ey4 * (s2b * s2b)) / (denB * denB * denB) + (2.0 * ax2 * Ey2 * c2b) / (
denB * denB
)
LAMBDA__ = (2.0 * b2 * Ee4 * (s2l * s2l)) / (denL * denL * denL) - (2.0 * b2 * Ee2 * s2l) / (
denL * denL
)
Q = Ey2 * cb2 + Ee2 * sl2
E = BETA * Q
G = LAMBDA * Q
E_beta = BETA_ * Q - BETA * Ey2 * s2b
E_lamb = BETA * Ee2 * s2l
G_beta = -LAMBDA * Ey2 * s2b
G_lamb = LAMBDA_ * Q + LAMBDA * Ee2 * s2l
E_beta_beta = BETA__ * Q - 2.0 * BETA_ * Ey2 * s2b - 2.0 * BETA * Ey2 * c2b
E_beta_lamb = BETA_ * Ee2 * s2l
E_lamb_lamb = 2.0 * BETA * Ee2 * c2l
G_beta_beta = -2.0 * LAMBDA * Ey2 * c2b
G_beta_lamb = -LAMBDA_ * Ey2 * s2b
G_lamb_lamb = LAMBDA__ * Q + 2.0 * LAMBDA_ * Ee2 * s2l + 2.0 * LAMBDA * Ee2 * c2l
return (
BETA,
LAMBDA,
E,
G,
BETA_,
LAMBDA_,
BETA__,
LAMBDA__,
E_beta,
E_lamb,
G_beta,
G_lamb,
E_beta_beta,
E_beta_lamb,
E_lamb_lamb,
G_beta_beta,
G_beta_lamb,
G_lamb_lamb,
)
# Berechnung der ODE Koeffizienten für Fall 1 (lambda_0 != lambda_1)
def p_coef(beta, lamb):
(
BETA,
LAMBDA,
E,
G,
BETA_,
LAMBDA_,
BETA__,
LAMBDA__,
E_beta,
E_lamb,
G_beta,
G_lamb,
E_beta_beta,
E_beta_lamb,
E_lamb_lamb,
G_beta_beta,
G_beta_lamb,
G_lamb_lamb,
) = BETA_LAMBDA(beta, lamb)
p_3 = -0.5 * (E_lamb / G)
p_2 = (G_beta / G) - 0.5 * (E_beta / E)
p_1 = 0.5 * (G_lamb / G) - (E_lamb / E)
p_0 = 0.5 * (G_beta / E)
p_33 = -0.5 * ((E_beta_lamb * G - E_lamb * G_beta) / (G**2))
p_22 = ((G * G_beta_beta - G_beta * G_beta) / (G**2)) - 0.5 * (
(E * E_beta_beta - E_beta * E_beta) / (E**2)
)
p_11 = 0.5 * ((G * G_beta_lamb - G_beta * G_lamb) / (G**2)) - (
(E * E_beta_lamb - E_beta * E_lamb) / (E**2)
)
p_00 = 0.5 * ((E * G_beta_beta - E_beta * G_beta) / (E**2))
return BETA, LAMBDA, E, G, p_3, p_2, p_1, p_0, p_33, p_22, p_11, p_00
# Berechnung der ODE Koeffizienten für Fall 2 (lambda_0 == lambda_1)
def q_coef(beta, lamb):
(
BETA,
LAMBDA,
E,
G,
BETA_,
LAMBDA_,
BETA__,
LAMBDA__,
E_beta,
E_lamb,
G_beta,
G_lamb,
E_beta_beta,
E_beta_lamb,
E_lamb_lamb,
G_beta_beta,
G_beta_lamb,
G_lamb_lamb,
) = BETA_LAMBDA(beta, lamb)
q_3 = -0.5 * (G_beta / E)
q_2 = (E_lamb / E) - 0.5 * (G_lamb / G)
q_1 = 0.5 * (E_beta / E) - (G_beta / G)
q_0 = 0.5 * (E_lamb / G)
q_33 = -0.5 * ((E * G_beta_lamb - E_lamb * G_lamb) / (E**2))
q_22 = ((E * E_lamb_lamb - E_lamb * E_lamb) / (E**2)) - 0.5 * (
(G * G_lamb_lamb - G_lamb * G_lamb) / (G**2)
)
q_11 = 0.5 * ((E * E_beta_lamb - E_beta * E_lamb) / (E**2)) - (
(G * G_beta_lamb - G_beta * G_lamb) / (G**2)
)
q_00 = 0.5 * ((E_lamb_lamb * G - E_lamb * G_lamb) / (G**2))
return BETA, LAMBDA, E, G, q_3, q_2, q_1, q_0, q_33, q_22, q_11, q_00
def integrand_lambda(lamb, y):
beta = y[0]
beta_p = y[1]
(_, _, E, G, *_) = BETA_LAMBDA(beta, lamb)
return np.sqrt(E * beta_p**2 + G)
def integrand_beta(beta, y):
lamb = y[0]
lamb_p = y[1]
(_, _, E, G, *_) = BETA_LAMBDA(beta, lamb)
return np.sqrt(E + G * lamb_p**2)
def solve_lambda_branch(beta0, lamb0, beta1, lamb1_target, N_run, N_newt, it_max):
dlamb = float(lamb1_target - lamb0)
if abs(dlamb) < 1e-15:
return None
sgn = 1.0 if dlamb >= 0.0 else -1.0
def ode_lamb(lamb, v):
beta, beta_p, X3, X4 = v
(_, _, _, _, p_3, p_2, p_1, p_0, p_33, p_22, p_11, p_00) = p_coef(beta, lamb)
dbeta = beta_p
dbeta_p = p_3 * beta_p**3 + p_2 * beta_p**2 + p_1 * beta_p + p_0
dX3 = X4
dX4 = (p_33 * beta_p**3 + p_22 * beta_p**2 + p_11 * beta_p + p_00) * X3 + (
3 * p_3 * beta_p**2 + 2 * p_2 * beta_p + p_1
) * X4
return np.array([dbeta, dbeta_p, dX3, dX4], dtype=float)
alpha0_sph = sph_azimuth(beta0, lamb0, beta1, lamb1_target)
(_, _, E0, G0, *_) = BETA_LAMBDA(beta0, lamb0)
beta_p0_sph = np.sqrt(G0 / E0) * cot(alpha0_sph)
def solve_newton(beta_p0_init: float):
beta_p0 = float(beta_p0_init)
for _ in range(it_max):
v0 = np.array([beta0, beta_p0, 0.0, 1.0], dtype=float)
_, y_end = rk4_end(ode_lamb, lamb0, v0, dlamb, N_newt)
beta_end, _, X3_end, _ = y_end
delta = beta_end - beta1
if abs(delta) < epsilon:
return True, beta_p0
if abs(X3_end) < 1e-20:
return False, None
step = delta / X3_end
step = float(np.clip(step, -0.5, 0.5))
beta_p0 -= step
return False, None
seeds = [beta_p0_sph, -beta_p0_sph, 0.5 * beta_p0_sph, 2.0 * beta_p0_sph]
best = None
for seed in seeds:
ok, sol = solve_newton(seed)
if not ok:
continue
v0_sol = np.array([beta0, sol, 0.0, 1.0], dtype=float)
_, _, s_val = rk4_integral(ode_lamb, lamb0, v0_sol, dlamb, N_run, integrand_lambda)
if (best is None) or (s_val < best[0]):
best = (float(s_val), float(sol))
if best is None:
return None
return best[0], best[1], sgn, dlamb, ode_lamb
def solve_beta_branch(beta0, lamb0, beta1, lamb1, N_run, N_newt, it_max):
dbeta = float(beta1 - beta0)
if abs(dbeta) < 1e-15:
return None
sgn = 1.0 if dbeta >= 0.0 else -1.0
def ode_beta(beta, v):
lamb, lamb_p, Y3, Y4 = v
(_, _, _, _, q_3, q_2, q_1, q_0, q_33, q_22, q_11, q_00) = q_coef(beta, lamb)
dlamb = lamb_p
dlamb_p = q_3 * lamb_p**3 + q_2 * lamb_p**2 + q_1 * lamb_p + q_0
dY3 = Y4
dY4 = (q_33 * lamb_p**3 + q_22 * lamb_p**2 + q_11 * lamb_p + q_00) * Y3 + (
3 * q_3 * lamb_p**2 + 2 * q_2 * lamb_p + q_1
) * Y4
return np.array([dlamb, dlamb_p, dY3, dY4], dtype=float)
def solve_newton(lamb_p0_init: float):
lamb_p0 = float(lamb_p0_init)
for _ in range(it_max):
v0 = np.array([lamb0, lamb_p0, 0.0, 1.0], dtype=float)
_, y_end = rk4_end(ode_beta, beta0, v0, dbeta, N_newt)
lamb_end, _, Y3_end, _ = y_end
delta = lamb_end - lamb1
if abs(delta) < epsilon:
return True, lamb_p0
if abs(Y3_end) < 1e-20:
return False, None
step = delta / Y3_end
step = float(np.clip(step, -1.0, 1.0))
lamb_p0 -= step
return False, None
seeds = [0.0, 0.25, -0.25, 1.0, -1.0]
best = None
for seed in seeds:
ok, sol = solve_newton(seed)
if not ok:
continue
v0_sol = np.array([lamb0, sol, 0.0, 1.0], dtype=float)
_, _, s_val = rk4_integral(ode_beta, beta0, v0_sol, dbeta, N_run, integrand_beta)
if (best is None) or (s_val < best[0]):
best = (float(s_val), float(sol))
if best is None:
return None
return best[0], best[1], sgn, dbeta, ode_beta
lamb0 = float(wrap_mpi_pi(lamb_0))
lamb1 = float(wrap_mpi_pi(lamb_1))
beta0 = float(beta_0)
beta1 = float(beta_1)
N_full = int(n)
if N_full < 2:
N_full = 2
if all_points:
N_fast = min(2000, max(400, N_full // 10))
else:
N_fast = min(1500, max(300, N_full // 12))
k0 = int(np.round((lamb0 - lamb1) / two_pi))
lamb_targets = []
for dk in (-1, 0, 1):
lt = lamb1 + two_pi * float(k0 + dk)
dl = lt - lamb0
if abs(dl) <= np.pi + 1e-12:
lamb_targets.append(float(lt))
if not lamb_targets:
lamb_targets = [float(lamb1 + two_pi * float(k0))]
best_fast = None
for lt in lamb_targets:
if abs(lt - lamb0) >= 1e-15:
res = solve_lambda_branch(beta0, lamb0, beta1, lt, N_fast, min(N_fast, 800), min(iter_max, 12))
if res is None:
continue
s_fast, beta_p0_fast, sgn_fast, dlamb_fast, _ = res
cand = ("lambda", s_fast, lt, beta_p0_fast, sgn_fast, dlamb_fast)
else:
res = solve_beta_branch(beta0, lamb0, beta1, lamb1, N_fast, min(N_fast, 800), min(iter_max, 12))
if res is None:
continue
s_fast, lamb_p0_fast, sgn_fast, dbeta_fast, _ = res
cand = ("beta", s_fast, lt, lamb_p0_fast, sgn_fast, dbeta_fast)
if (best_fast is None) or (cand[1] < best_fast[1]):
best_fast = cand
if best_fast is None:
if abs(lamb1 - lamb0) >= 1e-15:
best_fast = ("lambda", 0.0, lamb1, None, 1.0, float(lamb1 - lamb0))
else:
best_fast = ("beta", 0.0, lamb1, None, 1.0, float(beta1 - beta0))
if best_fast[0] == "lambda":
lt = float(best_fast[2])
dlamb = float(lt - lamb0)
sgn = 1.0 if dlamb >= 0.0 else -1.0
def ode_lamb(lamb, v):
beta, beta_p, X3, X4 = v
(_, _, _, _, p_3, p_2, p_1, p_0, p_33, p_22, p_11, p_00) = p_coef(beta, lamb)
dbeta = beta_p
dbeta_p = p_3 * beta_p**3 + p_2 * beta_p**2 + p_1 * beta_p + p_0
dX3 = X4
dX4 = (p_33 * beta_p**3 + p_22 * beta_p**2 + p_11 * beta_p + p_00) * X3 + (
3 * p_3 * beta_p**2 + 2 * p_2 * beta_p + p_1
) * X4
return np.array([dbeta, dbeta_p, dX3, dX4], dtype=float)
alpha0_sph = sph_azimuth(beta0, lamb0, beta1, lt)
(_, _, E0, G0, *_) = BETA_LAMBDA(beta0, lamb0)
beta_p0_sph = np.sqrt(G0 / E0) * cot(alpha0_sph)
beta_p0_init = best_fast[3]
if beta_p0_init is None:
beta_p0_init = beta_p0_sph
beta_p0_init = float(beta_p0_init)
N_newton = min(N_full, 4000)
def solve_newton_refine(beta_p0_init: float):
beta_p0 = float(beta_p0_init)
for _ in range(iter_max):
v0 = np.array([beta0, beta_p0, 0.0, 1.0], dtype=float)
_, y_end = rk4_end(ode_lamb, lamb0, v0, dlamb, N_newton)
beta_end, _, X3_end, _ = y_end
delta = beta_end - beta1
if abs(delta) < epsilon:
return True, beta_p0
if abs(X3_end) < 1e-20:
return False, None
step = delta / X3_end
step = float(np.clip(step, -0.5, 0.5))
beta_p0 -= step
return False, None
ok, beta_p0_sol = solve_newton_refine(beta_p0_init)
if not ok:
seeds = [beta_p0_sph, -beta_p0_sph, 0.5 * beta_p0_sph, 2.0 * beta_p0_sph]
best = None
for seed in seeds:
ok_s, sol_s = solve_newton_refine(seed)
if not ok_s:
continue
v0_s = np.array([beta0, sol_s, 0.0, 1.0], dtype=float)
_, _, s_s = rk4_integral(ode_lamb, lamb0, v0_s, dlamb, min(N_full, 2000), integrand_lambda)
if (best is None) or (s_s < best[0]):
best = (float(s_s), float(sol_s))
if best is None:
raise RuntimeError("GHA2_num: Keine Startwert-Variante konvergiert (lambda-Fall)")
beta_p0_sol = best[1]
beta_p0 = float(beta_p0_sol)
v0_final = np.array([beta0, beta_p0, 0.0, 1.0], dtype=float)
if all_points:
lamb_list, states = rk4(ode_lamb, lamb0, v0_final, dlamb, N_full, False)
lamb_arr = np.array(lamb_list, dtype=float)
beta_arr = np.array([st[0] for st in states], dtype=float)
beta_p_arr = np.array([st[1] for st in states], dtype=float)
(_, _, E_start, G_start, *_) = BETA_LAMBDA(beta_arr[0], lamb_arr[0])
(_, _, E_end, G_end, *_) = BETA_LAMBDA(beta_arr[-1], lamb_arr[-1])
alpha_0 = azimut(E_start, G_start, dbeta_du=beta_p_arr[0] * sgn, dlamb_du=1.0 * sgn)
alpha_1 = azimut(E_end, G_end, dbeta_du=beta_p_arr[-1] * sgn, dlamb_du=1.0 * sgn)
integrand = np.zeros(N_full + 1, dtype=float)
for i in range(N_full + 1):
(_, _, Ei, Gi, *_) = BETA_LAMBDA(beta_arr[i], lamb_arr[i])
integrand[i] = np.sqrt(Ei * beta_p_arr[i] ** 2 + Gi)
h = abs(dlamb) / N_full
if N_full % 2 == 0:
S = integrand[0] + integrand[-1] + 4.0 * np.sum(integrand[1:-1:2]) + 2.0 * np.sum(
integrand[2:-1:2]
)
s = h / 3.0 * S
else:
s = np.trapz(integrand, dx=h)
return float(wrap_0_2pi(alpha_0)), float(wrap_0_2pi(alpha_1)), float(s), beta_arr, lamb_arr
_, y_end, s = rk4_integral(ode_lamb, lamb0, v0_final, dlamb, N_full, integrand_lambda)
beta_end, beta_p_end, _, _ = y_end
(_, _, E_start, G_start, *_) = BETA_LAMBDA(beta0, lamb0)
alpha_0 = azimut(E_start, G_start, dbeta_du=beta_p0 * sgn, dlamb_du=1.0 * sgn)
(_, _, E_end, G_end, *_) = BETA_LAMBDA(float(beta_end), float(lamb0 + dlamb))
alpha_1 = azimut(E_end, G_end, dbeta_du=float(beta_p_end) * sgn, dlamb_du=1.0 * sgn)
return float(wrap_0_2pi(alpha_0)), float(wrap_0_2pi(alpha_1)), float(s)
# Fall 2 (lambda_0 == lambda_1)
N = int(n)
dbeta = float(beta_1 - beta_0)
if abs(dbeta) < 1e-15:
if all_points:
return 0.0, 0.0, 0.0, np.array([]), np.array([])
return 0.0, 0.0, 0.0
sgn = 1.0 if dbeta >= 0.0 else -1.0
def ode_beta(beta, v):
lamb, lamb_p, Y3, Y4 = v
(_, _, _, _, q_3, q_2, q_1, q_0, q_33, q_22, q_11, q_00) = q_coef(beta, lamb)
dlamb = lamb_p
dlamb_p = q_3 * lamb_p**3 + q_2 * lamb_p**2 + q_1 * lamb_p + q_0
dY3 = Y4
dY4 = (q_33 * lamb_p**3 + q_22 * lamb_p**2 + q_11 * lamb_p + q_00) * Y3 + (
3 * q_3 * lamb_p**2 + 2 * q_2 * lamb_p + q_1
) * Y4
return np.array([dlamb, dlamb_p, dY3, dY4], dtype=float)
lamb_p0 = float(best_fast[3]) if (best_fast[0] == "beta" and best_fast[3] is not None) else 0.0
for _ in range(iter_max):
v0 = np.array([lamb0, lamb_p0, 0.0, 1.0], dtype=float)
_, y_end = rk4_end(ode_beta, beta0, v0, dbeta, N)
lamb_end, _, Y3_end, _ = y_end
delta = lamb_end - lamb1
if abs(delta) < epsilon:
break
if abs(Y3_end) < 1e-20:
raise RuntimeError("GHA2_num: Ableitung ~ 0 im beta-Fall")
step = delta / Y3_end
step = float(np.clip(step, -1.0, 1.0))
lamb_p0 -= step
v0_final = np.array([lamb0, lamb_p0, 0.0, 1.0], dtype=float)
if all_points:
beta_list, states = rk4(ode_beta, beta0, v0_final, dbeta, N, False)
beta_arr = np.array(beta_list, dtype=float)
lamb_arr = np.array([st[0] for st in states], dtype=float)
lamb_p_arr = np.array([st[1] for st in states], dtype=float)
(_, _, E_start, G_start, *_) = BETA_LAMBDA(beta_arr[0], lamb_arr[0])
(_, _, E_end, G_end, *_) = BETA_LAMBDA(beta_arr[-1], lamb_arr[-1])
alpha_0 = azimut(E_start, G_start, dbeta_du=1.0 * sgn, dlamb_du=lamb_p_arr[0] * sgn)
alpha_1 = azimut(E_end, G_end, dbeta_du=1.0 * sgn, dlamb_du=lamb_p_arr[-1] * sgn)
integrand = np.zeros(N + 1, dtype=float)
for i in range(N + 1):
(_, _, Ei, Gi, *_) = BETA_LAMBDA(beta_arr[i], lamb_arr[i])
integrand[i] = np.sqrt(Ei + Gi * lamb_p_arr[i] ** 2)
h = abs(dbeta) / N
if N % 2 == 0:
S = integrand[0] + integrand[-1] + 4.0 * np.sum(integrand[1:-1:2]) + 2.0 * np.sum(
integrand[2:-1:2]
)
s = h / 3.0 * S
else:
s = np.trapz(integrand, dx=h)
return float(wrap_0_2pi(alpha_0)), float(wrap_0_2pi(alpha_1)), float(s), beta_arr, lamb_arr
_, y_end, s = rk4_integral(ode_beta, beta0, v0_final, dbeta, N, integrand_beta)
lamb_end, lamb_p_end, _, _ = y_end
(_, _, E_start, G_start, *_) = BETA_LAMBDA(beta0, lamb0)
alpha_0 = azimut(E_start, G_start, dbeta_du=1.0 * sgn, dlamb_du=lamb_p0 * sgn)
(_, _, E_end, G_end, *_) = BETA_LAMBDA(beta1, float(lamb_end))
alpha_1 = azimut(E_end, G_end, dbeta_du=1.0 * sgn, dlamb_du=float(lamb_p_end) * sgn)
return float(wrap_0_2pi(alpha_0)), float(wrap_0_2pi(alpha_1)), float(s)
if __name__ == "__main__":
ell = EllipsoidTriaxial.init_name("BursaSima1980round")
beta1 = np.deg2rad(75)
lamb1 = np.deg2rad(-90)
beta2 = np.deg2rad(75)
lamb2 = np.deg2rad(66)
a0, a1, s = gha2_num(ell, beta1, lamb1, beta2, lamb2, n=100)
print(aus.gms("a0", a0, 4))
print(aus.gms("a1", a1, 4))
print("s: ", s)
# print(aus.gms("a2", a2, 4))
# print(s)
cart1 = ell.para2cart(0, 0)
cart2 = ell.para2cart(0.4, 1.4)
beta1, lamb1 = ell.cart2ell(cart1)
beta2, lamb2 = ell.cart2ell(cart2)
a1, a2, s = gha2_num(ell, beta1, lamb1, beta2, lamb2, n=5000)
print(s)
ell = EllipsoidTriaxial.init_name("BursaSima1980round")
diffs_panou = []
examples_panou = ne_panou.get_random_examples(4)
for example in examples_panou:
beta0, lamb0, beta1, lamb1, _, alpha0, alpha1, s = example
P0 = ell.ell2cart(beta0, lamb0)
try:
alpha0_num, alpha1_num, s_num = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=4000, iter_max=10)
diffs_panou.append(
(wu.rad2deg(abs(alpha0 - alpha0_num)), wu.rad2deg(abs(alpha1 - alpha1_num)), abs(s - s_num)))
except:
print(f"Fehler für {beta0}, {lamb0}, {beta1}, {lamb1}")
diffs_panou = np.array(diffs_panou)
print(diffs_panou)
ell = EllipsoidTriaxial.init_name("KarneyTest2024")
diffs_karney = []
# examples_karney = ne_karney.get_examples((30500, 40500))
examples_karney = ne_karney.get_random_examples(2)
for example in examples_karney:
beta0, lamb0, alpha0, beta1, lamb1, alpha1, s = example
try:
alpha0_num, alpha1_num, s_num = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=4000, iter_max=10)
diffs_karney.append((wu.rad2deg(abs(alpha0-alpha0_num)), wu.rad2deg(abs(alpha1-alpha1_num)), abs(s-s_num)))
except:
print(f"Fehler für {beta0}, {lamb0}, {beta1}, {lamb1}")
diffs_karney = np.array(diffs_karney)
print(diffs_karney)
pass

View File

@@ -1,6 +1,12 @@
import random import random
from typing import List
import winkelumrechnungen as wu import winkelumrechnungen as wu
from typing import List, Tuple from GHA_triaxial.utils import jacobi_konstante
from ellipsoid_triaxial import EllipsoidTriaxial
ell = EllipsoidTriaxial.init_name("KarneyTest2024")
file_path = r"Karney_2024_Testset.txt"
def line2example(line: str) -> List: def line2example(line: str) -> List:
""" """
@@ -26,7 +32,7 @@ def get_random_examples(num: int, seed: int = None) -> List:
""" """
if seed is not None: if seed is not None:
random.seed(seed) random.seed(seed)
with open("Karney_2024_Testset.txt") as datei: with open(file_path) as datei:
lines = datei.readlines() lines = datei.readlines()
examples = [] examples = []
for i in range(num): for i in range(num):
@@ -41,7 +47,7 @@ def get_examples(l_i: List) -> List:
:param l_i: Liste von Indizes :param l_i: Liste von Indizes
:return: Liste mit Beispielen :return: Liste mit Beispielen
""" """
with open("Karney_2024_Testset.txt") as datei: with open(file_path) as datei:
lines = datei.readlines() lines = datei.readlines()
examples = [] examples = []
for i in l_i: for i in l_i:
@@ -50,5 +56,63 @@ def get_examples(l_i: List) -> List:
return examples return examples
def get_random_examples_gamma(group: str, num: int, seed: int = None, length: str = None) -> List:
"""
Zufällige Beispiele aus Karney in Gruppen nach Einteilung anhand der Jacobi-Konstanten
:param group: Gruppe
:param num: Anzahl
:param seed: Random-Seed
:param length: long oder short, sond egal
:return: Liste mit Beispielen
"""
eps = 1e-20
long_short = 2
if seed is not None:
random.seed(seed)
with open(file_path) as datei:
lines = datei.readlines()
examples = []
i = 0
while len(examples) < num and i < len(lines):
example = line2example(lines[random.randint(0, len(lines) - 1)])
if example in examples:
continue
i += 1
beta0, lamb0, alpha0_ell, beta1, lamb1, alpha1_ell, s = example
gamma = jacobi_konstante(beta0, lamb0, alpha0_ell, ell)
if group not in ["a", "b", "c", "d", "e", "de"]:
break
elif group == "a" and not 1 >= gamma >= 0.01:
continue
elif group == "b" and not 0.01 > gamma > eps:
continue
elif group == "c" and not abs(gamma) <= eps:
continue
elif group == "d" and not -eps > gamma > -1e-17:
continue
elif group == "e" and not -1e-17 >= gamma >= -1:
continue
elif group == "de" and not -eps > gamma > -1:
continue
if length == "short":
if example[6] < long_short:
examples.append(example)
elif length == "long":
if example[6] >= long_short:
examples.append(example)
else:
examples.append(example)
return examples
if __name__ == "__main__": if __name__ == "__main__":
get_random_examples(10) examples_a = get_random_examples_gamma("a", 10, 42)
examples_b = get_random_examples_gamma("b", 10, 42)
examples_c = get_random_examples_gamma("c", 10, 42)
examples_d = get_random_examples_gamma("d", 10, 42)
examples_e = get_random_examples_gamma("e", 10, 42)
pass

View File

@@ -72,33 +72,33 @@ table3 = [
wu.gms2rad([0, -1, 27.9705]), wu.gms2rad([0, 0, 16.0490]), 8888783.7815) wu.gms2rad([0, -1, 27.9705]), wu.gms2rad([0, 0, 16.0490]), 8888783.7815)
] ]
table4 = [ # table4 = [
(wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(90), 1.00000000000, # (wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(90), 1.00000000000,
wu.gms2rad([90, 0, 0.0000]), wu.gms2rad([90, 0, 0.0000]), 10018754.1714), # wu.gms2rad([90, 0, 0.0000]), wu.gms2rad([90, 0, 0.0000]), 10018754.1714),
#
# (wu.deg2rad(1), wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(179.5), 0.30320665822,
# wu.gms2rad([17, 39, 11.0942]), wu.gms2rad([162, 20, 58.9032]), 19884417.8083),
#
# (wu.deg2rad(5), wu.deg2rad(0), wu.deg2rad(-80), wu.deg2rad(170), 0.03104258442,
# wu.gms2rad([178, 12, 51.5083]), wu.gms2rad([10, 17, 52.6423]), 11652530.7514),
#
# (wu.deg2rad(30), wu.deg2rad(0), wu.deg2rad(-75), wu.deg2rad(120), 0.24135347134,
# wu.gms2rad([163, 49, 4.4615]), wu.gms2rad([68, 49, 50.9617]), 14057886.8752),
#
# (wu.deg2rad(60), wu.deg2rad(0), wu.deg2rad(-60), wu.deg2rad(40), 0.19408499032,
# wu.gms2rad([157, 9, 33.5589]), wu.gms2rad([157, 9, 33.5589]), 13767414.8267),
#
# (wu.deg2rad(75), wu.deg2rad(0), wu.deg2rad(-30), wu.deg2rad(0.5), 0.00202789418,
# wu.gms2rad([179, 33, 3.8613]), wu.gms2rad([179, 51, 57.0077]), 11661713.4496),
#
# (wu.deg2rad(80), wu.deg2rad(0), wu.deg2rad(-5), wu.deg2rad(120), 0.15201222384,
# wu.gms2rad([61, 5, 33.9600]), wu.gms2rad([171, 13, 22.0148]), 11105138.2902),
#
# (wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(60), wu.deg2rad(0), 0.00000000000,
# wu.gms2rad([0, 0, 0.0000]), wu.gms2rad([0, 0, 0.0000]), 6663348.2060)
# ]
(wu.deg2rad(1), wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(179.5), 0.30320665822, tables = [table1, table2, table3]
wu.gms2rad([17, 39, 11.0942]), wu.gms2rad([162, 20, 58.9032]), 19884417.8083),
(wu.deg2rad(5), wu.deg2rad(0), wu.deg2rad(-80), wu.deg2rad(170), 0.03104258442,
wu.gms2rad([178, 12, 51.5083]), wu.gms2rad([10, 17, 52.6423]), 11652530.7514),
(wu.deg2rad(30), wu.deg2rad(0), wu.deg2rad(-75), wu.deg2rad(120), 0.24135347134,
wu.gms2rad([163, 49, 4.4615]), wu.gms2rad([68, 49, 50.9617]), 14057886.8752),
(wu.deg2rad(60), wu.deg2rad(0), wu.deg2rad(-60), wu.deg2rad(40), 0.19408499032,
wu.gms2rad([157, 9, 33.5589]), wu.gms2rad([157, 9, 33.5589]), 13767414.8267),
(wu.deg2rad(75), wu.deg2rad(0), wu.deg2rad(-30), wu.deg2rad(0.5), 0.00202789418,
wu.gms2rad([179, 33, 3.8613]), wu.gms2rad([179, 51, 57.0077]), 11661713.4496),
(wu.deg2rad(80), wu.deg2rad(0), wu.deg2rad(-5), wu.deg2rad(120), 0.15201222384,
wu.gms2rad([61, 5, 33.9600]), wu.gms2rad([171, 13, 22.0148]), 11105138.2902),
(wu.deg2rad(0), wu.deg2rad(0), wu.deg2rad(60), wu.deg2rad(0), 0.00000000000,
wu.gms2rad([0, 0, 0.0000]), wu.gms2rad([0, 0, 0.0000]), 6663348.2060)
]
tables = [table1, table2, table3, table4]
def get_example(table: int, example: int) -> Tuple: def get_example(table: int, example: int) -> Tuple:
""" """
@@ -110,18 +110,25 @@ def get_example(table: int, example: int) -> Tuple:
table -= 1 table -= 1
example -= 1 example -= 1
tables = get_tables() tables = get_tables()
return tables[table][example] beta0, lamb0, beta1, lamb1, _, alpha0_ell, alpha1_ell, s = tables[table][example]
return beta0, lamb0, alpha0_ell, beta1, lamb1, alpha1_ell, s
def get_tables() -> List: def get_tables() -> List:
""" """
Rückgabe aller Tabellen Rückgabe aller Tabellen
:return: Alle Tabellen :return: Alle Tabellen
""" """
return tables sorted_tables = []
for table in tables:
sorted_tables.append([])
for example in table:
beta0, lamb0, beta1, lamb1, _, alpha0_ell, alpha1_ell, s = example
sorted_tables[-1].append((beta0, lamb0, alpha0_ell, beta1, lamb1, alpha1_ell, s))
return sorted_tables
def get_random_examples(num: int, seed: int = None) -> List: def get_random_examples(num: int, seed: int = None) -> List:
""" """
Rückgabe zufäliger Beispiele Rückgabe zufälliger Beispiele
:param num: Anzahl Beispiele :param num: Anzahl Beispiele
:param seed: Random-Seed :param seed: Random-Seed
:return: :return:
@@ -131,7 +138,7 @@ def get_random_examples(num: int, seed: int = None) -> List:
examples = [] examples = []
for i in range(num): for i in range(num):
table = random.randint(1, 4) table = random.randint(1, 3)
if table == 4: if table == 4:
example = random.randint(1, 8) example = random.randint(1, 8)
else: else:

View File

@@ -1,360 +0,0 @@
import numpy as np
from numpy import sin, cos, sqrt, arctan2
import ellipsoide
import runge_kutta as rk
import winkelumrechnungen as wu
from scipy.special import factorial as fact
from math import comb
import GHA_triaxial.numeric_examples_panou as ne_panou
import GHA_triaxial.numeric_examples_karney as ne_karney
from ellipsoide import EllipsoidTriaxial
from typing import Callable, Tuple, List
from numpy.typing import NDArray
def pq_ell(ell: EllipsoidTriaxial, point: NDArray) -> Tuple[NDArray, NDArray]:
"""
Berechnung von p und q in elliptischen Koordinaten
Panou, Korakitits 2019
:param ell: Ellipsoid
:param point: Punkt
:return: p und q
"""
x, y, z = point
n = ell.func_n(point)
beta, lamb = ell.cart2ell(point)
B = ell.Ex ** 2 * cos(beta) ** 2 + ell.Ee ** 2 * sin(beta) ** 2
L = ell.Ex ** 2 - ell.Ee ** 2 * cos(lamb) ** 2
c1 = x ** 2 + y ** 2 + z ** 2 - (ell.ax ** 2 + ell.ay ** 2 + ell.b ** 2)
c0 = (ell.ax ** 2 * ell.ay ** 2 + ell.ax ** 2 * ell.b ** 2 + ell.ay ** 2 * ell.b ** 2 -
(ell.ay ** 2 + ell.b ** 2) * x ** 2 - (ell.ax ** 2 + ell.b ** 2) * y ** 2 - (
ell.ax ** 2 + ell.ay ** 2) * z ** 2)
t2 = (-c1 + sqrt(c1 ** 2 - 4 * c0)) / 2
F = ell.Ey ** 2 * cos(beta) ** 2 + ell.Ee ** 2 * sin(lamb) ** 2
p1 = -sqrt(L / (F * t2)) * ell.ax / ell.Ex * sqrt(B) * sin(lamb)
p2 = sqrt(L / (F * t2)) * ell.ay * cos(beta) * cos(lamb)
p3 = 1 / sqrt(F * t2) * (ell.b * ell.Ee ** 2) / (2 * ell.Ex) * sin(beta) * sin(2 * lamb)
p = np.array([p1, p2, p3])
q = np.array([n[1] * p[2] - n[2] * p[1],
n[2] * p[0] - n[0] * p[2],
n[0] * p[1] - n[1] * p[0]])
return p, q
def buildODE(ell: EllipsoidTriaxial) -> Callable:
"""
Aufbau des DGL-Systems
:param ell: Ellipsoid
:return: DGL-System
"""
def ODE(s: float, v: NDArray) -> NDArray:
"""
DGL-System
:param s: unabhängige Variable
:param v: abhängige Variablen
:return: Ableitungen der abhängigen Variablen
"""
x, dxds, y, dyds, z, dzds = v
H = ell.func_H(np.array([x, y, z]))
h = dxds**2 + 1/(1-ell.ee**2)*dyds**2 + 1/(1-ell.ex**2)*dzds**2
ddx = -(h/H)*x
ddy = -(h/H)*y/(1-ell.ee**2)
ddz = -(h/H)*z/(1-ell.ex**2)
return np.array([dxds, ddx, dyds, ddy, dzds, ddz])
return ODE
def gha1_num(ell: EllipsoidTriaxial, point: NDArray, alpha0: float, s: float, num: int, all_points: bool = False) -> Tuple[NDArray, float] | Tuple[NDArray, float, List]:
"""
Panou, Korakitits 2019
:param ell:
:param point:
:param alpha0:
:param s:
:param num:
:param all_points:
:return:
"""
phi, lam, _ = ell.cart2geod(point, "ligas3")
p0 = ell.geod2cart(phi, lam, 0)
x0, y0, z0 = p0
p, q = pq_ell(ell, p0)
dxds0 = p[0] * sin(alpha0) + q[0] * cos(alpha0)
dyds0 = p[1] * sin(alpha0) + q[1] * cos(alpha0)
dzds0 = p[2] * sin(alpha0) + q[2] * cos(alpha0)
v_init = np.array([x0, dxds0, y0, dyds0, z0, dzds0])
ode = buildODE(ell)
_, werte = rk.rk4(ode, 0, v_init, s, num)
x1, dx1ds, y1, dy1ds, z1, dz1ds = werte[-1]
point1 = np.array([x1, y1, z1])
p1, q1 = pq_ell(ell, point1)
sigma = np.array([dx1ds, dy1ds, dz1ds])
P = float(p1 @ sigma)
Q = float(q1 @ sigma)
alpha1 = arctan2(P, Q)
if alpha1 < 0:
alpha1 += 2 * np.pi
if all_points:
return point1, alpha1, werte
else:
return point1, alpha1
# ---------------------------------------------------------------------------------------------------------------------
def pq_para(ell: EllipsoidTriaxial, point: NDArray) -> Tuple[NDArray, NDArray]:
"""
Berechnung von p und q in parametrischen Koordinaten
Panou, Korakitits 2020
:param ell: Ellipsoid
:param point: Punkt
:return: p und q
"""
n = ell.func_n(point)
u, v = ell.cart2para(point)
# 41-47
G = sqrt(1 - ell.ex ** 2 * cos(u) ** 2 - ell.ee ** 2 * sin(u) ** 2 * sin(v) ** 2)
q = np.array([-1 / G * sin(u) * cos(v),
-1 / G * sqrt(1 - ell.ee ** 2) * sin(u) * sin(v),
1 / G * sqrt(1 - ell.ex ** 2) * cos(u)])
p = np.array([q[1] * n[2] - q[2] * n[1],
q[2] * n[0] - q[0] * n[2],
q[0] * n[1] - q[1] * n[0]])
t1 = np.dot(n, q)
t2 = np.dot(n, p)
t3 = np.dot(p, q)
if not (t1 < 1e-10 or t1 > 1-1e-10) and not (t2 < 1e-10 or t2 > 1-1e-10) and not (t3 < 1e-10 or t3 > 1-1e-10):
raise Exception("Fehler in den normierten Vektoren")
return p, q
def gha1_ana_step(ell: EllipsoidTriaxial, point: NDArray, alpha0: float, s: float, maxM: int) -> Tuple[NDArray, float]:
"""
Panou, Korakitits 2020, 5ff.
:param ell:
:param point:
:param alpha0:
:param s:
:param maxM:
:return:
"""
x, y, z = point
# S. 6
x_m = [x]
y_m = [y]
z_m = [z]
p, q = pq_para(ell, point)
# 48-50
x_m.append(p[0] * sin(alpha0) + q[0] * cos(alpha0))
y_m.append(p[1] * sin(alpha0) + q[1] * cos(alpha0))
z_m.append(p[2] * sin(alpha0) + q[2] * cos(alpha0))
# 34
H_ = lambda p: np.sum([comb(p, p - i) * (x_m[p - i] * x_m[i] +
1 / (1 - ell.ee ** 2) ** 2 * y_m[p - i] * y_m[i] +
1 / (1 - ell.ex ** 2) ** 2 * z_m[p - i] * z_m[i])
for i in range(0, p + 1)])
# 35
h_ = lambda q: np.sum([comb(q, q-j) * (x_m[q-j+1] * x_m[j+1] +
1 / (1 - ell.ee ** 2) * y_m[q-j+1] * y_m[j+1] +
1 / (1 - ell.ex ** 2) * z_m[q-j+1] * z_m[j+1])
for j in range(0, q+1)])
# 31
hH_ = lambda t: 1/H_(0) * (h_(t) - np.sum([comb(t, l-1) * H_(t+1-l) * hH_t[l-1] for l in range(1, t+1)]))
# 28-30
x_ = lambda m: - np.sum([comb(m-2, k) * hH_t[m-2-k] * x_m[k] for k in range(0, m-2+1)])
y_ = lambda m: -1 / (1-ell.ee**2) * np.sum([comb(m-2, k) * hH_t[m-2-k] * y_m[k] for k in range(0, m-2+1)])
z_ = lambda m: -1 / (1-ell.ex**2) * np.sum([comb(m-2, k) * hH_t[m-2-k] * z_m[k] for k in range(0, m-2+1)])
hH_t = []
a_m = []
b_m = []
c_m = []
for m in range(0, maxM+1):
if m >= 2:
hH_t.append(hH_(m-2))
x_m.append(x_(m))
y_m.append(y_(m))
z_m.append(z_(m))
fact_m = fact(m)
# 22-24
a_m.append(x_m[m] / fact_m)
b_m.append(y_m[m] / fact_m)
c_m.append(z_m[m] / fact_m)
# 19-21
x_s = 0
for a in reversed(a_m):
x_s = x_s * s + a
y_s = 0
for b in reversed(b_m):
y_s = y_s * s + b
z_s = 0
for c in reversed(c_m):
z_s = z_s * s + c
p1 = np.array([x_s, y_s, z_s])
p_s, q_s = pq_para(ell, p1)
# 57-59
dx_s = 0
for i, a in reversed(list(enumerate(a_m[1:], start=1))):
dx_s = dx_s * s + i * a
dy_s = 0
for i, b in reversed(list(enumerate(b_m[1:], start=1))):
dy_s = dy_s * s + i * b
dz_s = 0
for i, c in reversed(list(enumerate(c_m[1:], start=1))):
dz_s = dz_s * s + i * c
# 52-53
sigma = np.array([dx_s, dy_s, dz_s])
P = float(p_s @ sigma)
Q = float(q_s @ sigma)
# 51
alpha1 = arctan2(P, Q)
if alpha1 < 0:
alpha1 += 2 * np.pi
return p1, alpha1
def gha1_ana(ell: EllipsoidTriaxial, point: NDArray, alpha0: float, s: float, maxM: int, maxPartCircum: int = 4) -> Tuple[NDArray, float]:
if s > np.pi / maxPartCircum * ell.ax:
s /= 2
point_step, alpha_step = gha1_ana(ell, point, alpha0, s, maxM, maxPartCircum)
point_end, alpha_end = gha1_ana(ell, point_step, alpha_step, s, maxM, maxPartCircum)
else:
point_end, alpha_end = gha1_ana_step(ell, point, alpha0, s, maxM)
_, _, h = ell.cart2geod(point_end, "ligas3")
if h > 1e-5:
raise Exception("Analyitsche Methode ist explodiert, Punkt liegt nicht mehr auf dem Ellpsoid")
return point_end, alpha_end
def alpha_para2ell(ell: EllipsoidTriaxial, u: float, v: float, alpha_para: float) -> Tuple[float, float, float]:
point = ell.para2cart(u, v)
beta, lamb = ell.para2ell(u, v)
p_para, q_para = pq_para(ell, point)
sigma_para = p_para * sin(alpha_para) + q_para * cos(alpha_para)
p_ell, q_ell = pq_ell(ell, point)
alpha_ell = arctan2(p_ell @ sigma_para, q_ell @ sigma_para)
sigma_ell = p_ell * sin(alpha_ell) + q_ell * cos(alpha_ell)
if np.linalg.norm(sigma_para - sigma_ell) > 1e-12:
raise Exception("Alpha Umrechnung fehlgeschlagen")
return beta, lamb, alpha_ell
def alpha_ell2para(ell: EllipsoidTriaxial, beta: float, lamb: float, alpha_ell: float) -> Tuple[float, float, float]:
point = ell.ell2cart(beta, lamb)
u, v = ell.ell2para(beta, lamb)
p_ell, q_ell = pq_ell(ell, point)
sigma_ell = p_ell * sin(alpha_ell) + q_ell * cos(alpha_ell)
p_para, q_para = pq_para(ell, point)
alpha_para = arctan2(p_para @ sigma_ell, q_para @ sigma_ell)
sigma_para = p_para * sin(alpha_para) + q_para * cos(alpha_para)
if np.linalg.norm(sigma_para - sigma_ell) > 1e-12:
raise Exception("Alpha Umrechnung fehlgeschlagen")
return u, v, alpha_para
def func_sigma_ell(ell: EllipsoidTriaxial, point: NDArray, alpha: float) -> NDArray:
p, q = pq_ell(ell, point)
sigma = p * sin(alpha) + q * cos(alpha)
return sigma
def func_sigma_para(ell: EllipsoidTriaxial, point: NDArray, alpha: float) -> NDArray:
p, q = pq_para(ell, point)
sigma = p * sin(alpha) + q * cos(alpha)
return sigma
def louville_constant(ell: EllipsoidTriaxial, p0: NDArray, alpha: float) -> float:
beta, lamb = ell.cart2ell(p0)
l = ell.Ey**2 * cos(beta)**2 * sin(alpha)**2 - ell.Ee**2 * sin(lamb)**2 * cos(alpha)**2
return l
def louville_l2c(ell: EllipsoidTriaxial, l: float) -> float:
return sqrt((l + ell.Ee**2) / ell.Ex**2)
def louville_c2l(ell: EllipsoidTriaxial, c: float) -> float:
return ell.Ex**2 * c**2 - ell.Ee**2
if __name__ == "__main__":
# ell = ellipsoide.EllipsoidTriaxial.init_name("BursaSima1980round")
# diffs_panou = []
# examples_panou = ne_panou.get_random_examples(5)
# for example in examples_panou:
# beta0, lamb0, beta1, lamb1, _, alpha0_ell, alpha1_ell, s = example
# P0 = ell.ell2cart(beta0, lamb0)
#
# P1_num, alpha1_num = gha1_num(ell, P0, alpha0_ell, s, 100)
# beta1_num, lamb1_num = ell.cart2ell(P1_num)
#
# _, _, alpha0_para = alpha_ell2para(ell, beta0, lamb0, alpha0_ell)
# P1_ana, alpha1_ana = gha1_ana(ell, P0, alpha0_para, s, 60)
# beta1_ana, lamb1_ana = ell.cart2ell(P1_ana)
# diffs_panou.append((abs(beta1-beta1_num), abs(lamb1-lamb1_num), abs(beta1-beta1_ana), abs(lamb1-lamb1_ana)))
# diffs_panou = np.array(diffs_panou)
# mask_360 = (diffs_panou > 359) & (diffs_panou < 361)
# diffs_panou[mask_360] = np.abs(diffs_panou[mask_360] - 360)
# print(diffs_panou)
ell = ellipsoide.EllipsoidTriaxial.init_name("KarneyTest2024")
diffs_karney = []
# examples_karney = ne_karney.get_examples((30499, 30500, 40500))
examples_karney = ne_karney.get_random_examples(20)
for example in examples_karney:
beta0, lamb0, alpha0_ell, beta1, lamb1, alpha1_ell, s = example
P0 = ell.ell2cart(beta0, lamb0)
P1_num, alpha1_num = gha1_num(ell, P0, alpha0_ell, s, 5000)
beta1_num, lamb1_num = ell.cart2ell(P1_num)
try:
_, _, alpha0_para = alpha_ell2para(ell, beta0, lamb0, alpha0_ell)
P1_ana, alpha1_ana = gha1_ana(ell, P0, alpha0_para, s, 30, maxPartCircum=16)
beta1_ana, lamb1_ana = ell.cart2ell(P1_ana)
except:
beta1_ana, lamb1_ana = np.inf, np.inf
diffs_karney.append((wu.rad2deg(abs(beta1-beta1_num)), wu.rad2deg(abs(lamb1-lamb1_num)), wu.rad2deg(abs(beta1-beta1_ana)), wu.rad2deg(abs(lamb1-lamb1_ana))))
diffs_karney = np.array(diffs_karney)
mask_360 = (diffs_karney > 359) & (diffs_karney < 361)
diffs_karney[mask_360] = np.abs(diffs_karney[mask_360] - 360)
print(diffs_karney)

View File

@@ -1,435 +0,0 @@
import numpy as np
from ellipsoide import EllipsoidTriaxial
import runge_kutta as rk
import GHA_triaxial.numeric_examples_karney as ne_karney
import GHA_triaxial.numeric_examples_panou as ne_panou
import winkelumrechnungen as wu
from typing import Tuple
from numpy.typing import NDArray
# Panou 2013
def gha2_num(ell: EllipsoidTriaxial, beta_1: float, lamb_1: float, beta_2: float, lamb_2: float,
n: int = 16000, epsilon: float = 10**-12, iter_max: int = 30, all_points: bool = False
) -> Tuple[float, float, float] | Tuple[float, float, float, NDArray, NDArray]:
"""
:param ell: triaxiales Ellipsoid
:param beta_1: reduzierte ellipsoidische Breite Punkt 1
:param lamb_1: elllipsoidische Länge Punkt 1
:param beta_2: reduzierte ellipsoidische Breite Punkt 2
:param lamb_2: elllipsoidische Länge Punkt 2
:param n: Anzahl Schritte
:param epsilon:
:param iter_max: Maximale Anzhal Iterationen
:param all_points:
:return:
"""
# h_x, h_y, h_e entsprechen E_x, E_y, E_e
def arccot(x):
return np.arctan2(1.0, x)
def BETA_LAMBDA(beta, lamb):
BETA = (ell.ay**2 * np.sin(beta)**2 + ell.b**2 * np.cos(beta)**2) / (ell.Ex**2 - ell.Ey**2 * np.sin(beta)**2)
LAMBDA = (ell.ax**2 * np.sin(lamb)**2 + ell.ay**2 * np.cos(lamb)**2) / (ell.Ex**2 - ell.Ee**2 * np.cos(lamb)**2)
# Erste Ableitungen von ΒETA und LAMBDA
BETA_ = (ell.ax**2 * ell.Ey**2 * np.sin(2*beta)) / (ell.Ex**2 - ell.Ey**2 * np.sin(beta)**2)**2
LAMBDA_ = - (ell.b**2 * ell.Ee**2 * np.sin(2*lamb)) / (ell.Ex**2 - ell.Ee**2 * np.cos(lamb)**2)**2
# Zweite Ableitungen von ΒETA und LAMBDA
BETA__ = ((2 * ell.ax**2 * ell.Ey**4 * np.sin(2*beta)**2) / (ell.Ex**2 - ell.Ey**2 * np.sin(beta)**2)**3) + ((2 * ell.ax**2 * ell.Ey**2 * np.cos(2*beta)) / (ell.Ex**2 - ell.Ey**2 * np.sin(beta)**2)**2)
LAMBDA__ = (((2 * ell.b**2 * ell.Ee**4 * np.sin(2*lamb)**2) / (ell.Ex**2 - ell.Ee**2 * np.cos(lamb)**2)**3) -
((2 * ell.b**2 * ell.Ee**2 * np.sin(2*lamb)) / (ell.Ex**2 - ell.Ee**2 * np.cos(lamb)**2)**2))
E = BETA * (ell.Ey ** 2 * np.cos(beta) ** 2 + ell.Ee ** 2 * np.sin(lamb) ** 2)
F = 0
G = LAMBDA * (ell.Ey ** 2 * np.cos(beta) ** 2 + ell.Ee ** 2 * np.sin(lamb) ** 2)
# Erste Ableitungen von E und G
E_beta = BETA_ * (ell.Ey**2 * np.cos(beta)**2 + ell.Ee**2 * np.sin(lamb)**2) - BETA * ell.Ey**2 * np.sin(2*beta)
E_lamb = BETA * ell.Ee**2 * np.sin(2*lamb)
G_beta = - LAMBDA * ell.Ey**2 * np.sin(2*beta)
G_lamb = LAMBDA_ * (ell.Ey**2 * np.cos(beta)**2 + ell.Ee**2 * np.sin(lamb)**2) + LAMBDA * ell.Ee**2 * np.sin(2*lamb)
# Zweite Ableitungen von E und G
E_beta_beta = BETA__ * (ell.Ey**2 * np.cos(beta)**2 + ell.Ee**2 * np.sin(lamb)**2) - 2 * BETA_ * ell.Ey**2 * np.sin(2*beta) - 2 * BETA * ell.Ey**2 * np.cos(2*beta)
E_beta_lamb = BETA_ * ell.Ee**2 * np.sin(2*lamb)
E_lamb_lamb = 2 * BETA * ell.Ee**2 * np.cos(2*lamb)
G_beta_beta = - 2 * LAMBDA * ell.Ey**2 * np.cos(2*beta)
G_beta_lamb = - LAMBDA_ * ell.Ey**2 * np.sin(2*beta)
G_lamb_lamb = LAMBDA__ * (ell.Ey**2 * np.cos(beta)**2 + ell.Ee**2 * np.sin(lamb)**2) + 2 * LAMBDA_ * ell.Ee**2 * np.sin(2*lamb) + 2 * LAMBDA * ell.Ee**2 * np.cos(2*lamb)
return (BETA, LAMBDA, E, G,
BETA_, LAMBDA_, BETA__, LAMBDA__,
E_beta, E_lamb, G_beta, G_lamb,
E_beta_beta, E_beta_lamb, E_lamb_lamb,
G_beta_beta, G_beta_lamb, G_lamb_lamb)
def p_coef(beta, lamb):
(BETA, LAMBDA, E, G,
BETA_, LAMBDA_, BETA__, LAMBDA__,
E_beta, E_lamb, G_beta, G_lamb,
E_beta_beta, E_beta_lamb, E_lamb_lamb,
G_beta_beta, G_beta_lamb, G_lamb_lamb) = BETA_LAMBDA(beta, lamb)
p_3 = - 0.5 * (E_lamb / G)
p_2 = (G_beta / G) - 0.5 * (E_beta / E)
p_1 = 0.5 * (G_lamb / G) - (E_lamb / E)
p_0 = 0.5 * (G_beta / E)
p_33 = - 0.5 * ((E_beta_lamb * G - E_lamb * G_beta) / (G ** 2))
p_22 = ((G * G_beta_beta - G_beta * G_beta) / (G ** 2)) - 0.5 * ((E * E_beta_beta - E_beta * E_beta) / (E ** 2))
p_11 = 0.5 * ((G * G_beta_lamb - G_beta * G_lamb) / (G ** 2)) - ((E * E_beta_lamb - E_beta * E_lamb) / (E ** 2))
p_00 = 0.5 * ((E * G_beta_beta - E_beta * G_beta) / (E ** 2))
return (BETA, LAMBDA, E, G,
p_3, p_2, p_1, p_0,
p_33, p_22, p_11, p_00)
def q_coef(beta, lamb):
(BETA, LAMBDA, E, G,
BETA_, LAMBDA_, BETA__, LAMBDA__,
E_beta, E_lamb, G_beta, G_lamb,
E_beta_beta, E_beta_lamb, E_lamb_lamb,
G_beta_beta, G_beta_lamb, G_lamb_lamb) = BETA_LAMBDA(beta, lamb)
q_3 = - 0.5 * (G_beta / E)
q_2 = (E_lamb / E) - 0.5 * (G_lamb / G)
q_1 = 0.5 * (E_beta / E) - (G_beta / G)
q_0 = 0.5 * (E_lamb / G)
q_33 = - 0.5 * ((E * G_beta_lamb - E_lamb * G_lamb) / (E ** 2))
q_22 = ((E * E_lamb_lamb - E_lamb * E_lamb) / (E ** 2)) - 0.5 * ((G * G_lamb_lamb - G_lamb * G_lamb) / (G ** 2))
q_11 = 0.5 * ((E * E_beta_lamb - E_beta * E_lamb) / (E ** 2)) - ((G * G_beta_lamb - G_beta * G_lamb) / (G ** 2))
q_00 = 0.5 * ((E_lamb_lamb * G - E_lamb * G_lamb) / (G ** 2))
return (BETA, LAMBDA, E, G,
q_3, q_2, q_1, q_0,
q_33, q_22, q_11, q_00)
if lamb_1 != lamb_2:
# def functions():
# def f_beta(lamb, beta, beta_p, X3, X4):
# return beta_p
#
# def f_beta_p(lamb, beta, beta_p, X3, X4):
# (BETA, LAMBDA, E, G,
# p_3, p_2, p_1, p_0,
# p_33, p_22, p_11, p_00) = p_coef(beta, lamb)
# return p_3 * beta_p ** 3 + p_2 * beta_p ** 2 + p_1 * beta_p + p_0
#
# def f_X3(lamb, beta, beta_p, X3, X4):
# return X4
#
# def f_X4(lamb, beta, beta_p, X3, X4):
# (BETA, LAMBDA, E, G,
# p_3, p_2, p_1, p_0,
# p_33, p_22, p_11, p_00) = p_coef(beta, lamb)
# return (p_33 * beta_p ** 3 + p_22 * beta_p ** 2 + p_11 * beta_p + p_00) * X3 + \
# (3 * p_3 * beta_p ** 2 + 2 * p_2 * beta_p + p_1) * X4
#
# return [f_beta, f_beta_p, f_X3, f_X4]
def buildODElamb():
def ODE(lamb, v):
beta, beta_p, X3, X4 = v
(BETA, LAMBDA, E, G,
p_3, p_2, p_1, p_0,
p_33, p_22, p_11, p_00) = p_coef(beta, lamb)
dbeta = beta_p
dbeta_p = p_3 * beta_p ** 3 + p_2 * beta_p ** 2 + p_1 * beta_p + p_0
dX3 = X4
dX4 = (p_33 * beta_p ** 3 + p_22 * beta_p ** 2 + p_11 * beta_p + p_00) * X3 + \
(3 * p_3 * beta_p ** 2 + 2 * p_2 * beta_p + p_1) * X4
return np.array([dbeta, dbeta_p, dX3, dX4])
return ODE
N = n
dlamb = lamb_2 - lamb_1
if abs(dlamb) < 1e-15:
beta_0 = 0.0
else:
beta_0 = (beta_2 - beta_1) / (lamb_2 - lamb_1)
converged = False
iterations = 0
# funcs = functions()
ode_lamb = buildODElamb()
for i in range(iter_max):
iterations = i + 1
# startwerte = [lamb_1, beta_1, beta_0, 0.0, 1.0]
startwerte = np.array([beta_1, beta_0, 0.0, 1.0])
# werte = rk.verfahren(funcs, startwerte, dlamb, N)
lamb_list, werte = rk.rk4(ode_lamb, lamb_1, startwerte, dlamb, N, False)
# lamb_end, beta_end, beta_p_end, X3_end, X4_end = werte[-1]
lamb_end = lamb_list[-1]
beta_end, beta_p_end, X3_end, X4_end = werte[-1]
d_beta_end_d_beta0 = X3_end
delta = beta_end - beta_2
if abs(delta) < epsilon:
converged = True
break
if abs(d_beta_end_d_beta0) < 1e-20:
raise RuntimeError("Abbruch.")
max_step = 0.5
step = delta / d_beta_end_d_beta0
if abs(step) > max_step:
step = np.sign(step) * max_step
beta_0 = beta_0 - step
if not converged:
raise RuntimeError("konvergiert nicht.")
# Z
# werte = rk.verfahren(funcs, [lamb_1, beta_1, beta_0, 0.0, 1.0], dlamb, N, False)
lamb_list, werte = rk.rk4(ode_lamb, lamb_1, np.array([beta_1, beta_0, 0.0, 1.0]), dlamb, N, False)
beta_arr = np.zeros(N + 1)
# lamb_arr = np.zeros(N + 1)
lamb_arr = np.array(lamb_list)
beta_p_arr = np.zeros(N + 1)
for i, state in enumerate(werte):
# lamb_arr[i] = state[0]
# beta_arr[i] = state[1]
# beta_p_arr[i] = state[2]
beta_arr[i] = state[0]
beta_p_arr[i] = state[1]
(_, _, E1, G1,
*_) = BETA_LAMBDA(beta_arr[0], lamb_arr[0])
(_, _, E2, G2,
*_) = BETA_LAMBDA(beta_arr[-1], lamb_arr[-1])
alpha_1 = arccot(np.sqrt(E1 / G1) * beta_p_arr[0])
alpha_2 = arccot(np.sqrt(E2 / G2) * beta_p_arr[-1])
integrand = np.zeros(N + 1)
for i in range(N + 1):
(_, _, Ei, Gi,
*_) = BETA_LAMBDA(beta_arr[i], lamb_arr[i])
integrand[i] = np.sqrt(Ei * beta_p_arr[i] ** 2 + Gi)
h = abs(dlamb) / N
if N % 2 == 0:
S = integrand[0] + integrand[-1] \
+ 4.0 * np.sum(integrand[1:-1:2]) \
+ 2.0 * np.sum(integrand[2:-1:2])
s = h / 3.0 * S
else:
s = np.trapz(integrand, dx=h)
beta0 = beta_arr[0]
lamb0 = lamb_arr[0]
c = np.sqrt(
(np.cos(beta0) ** 2 + (ell.Ee**2 / ell.Ex**2) * np.sin(beta0) ** 2) * np.sin(alpha_1) ** 2
+ (ell.Ee**2 / ell.Ex**2) * np.cos(lamb0) ** 2 * np.cos(alpha_1) ** 2
)
if all_points:
return alpha_1, alpha_2, s, beta_arr, lamb_arr
else:
return alpha_1, alpha_2, s
else: # lamb_1 == lamb_2
N = n
dbeta = beta_2 - beta_1
if abs(dbeta) < 10**-15:
if all_points:
return 0, 0, 0, np.array([]), np.array([])
else:
return 0, 0, 0
lamb_0 = 0
converged = False
iterations = 0
# def functions_beta():
# def g_lamb(beta, lamb, lamb_p, Y3, Y4):
# return lamb_p
#
# def g_lamb_p(beta, lamb, lamb_p, Y3, Y4):
# (BETA, LAMBDA, E, G,
# q_3, q_2, q_1, q_0,
# q_33, q_22, q_11, q_00) = q_coef(beta, lamb)
# return q_3 * lamb_p ** 3 + q_2 * lamb_p ** 2 + q_1 * lamb_p + q_0
#
# def g_Y3(beta, lamb, lamb_p, Y3, Y4):
# return Y4
#
# def g_Y4(beta, lamb, lamb_p, Y3, Y4):
# (BETA, LAMBDA, E, G,
# q_3, q_2, q_1, q_0,
# q_33, q_22, q_11, q_00) = q_coef(beta, lamb)
# return (q_33 * lamb_p ** 3 + q_22 * lamb_p ** 2 + q_11 * lamb_p + q_00) * Y3 + \
# (3 * q_3 * lamb_p ** 2 + 2 * q_2 * lamb_p + q_1) * Y4
#
# return [g_lamb, g_lamb_p, g_Y3, g_Y4]
def buildODEbeta():
def ODE(beta, v):
lamb, lamb_p, Y3, Y4 = v
(BETA, LAMBDA, E, G,
q_3, q_2, q_1, q_0,
q_33, q_22, q_11, q_00) = q_coef(beta, lamb)
dlamb = lamb_p
dlamb_p = q_3 * lamb_p ** 3 + q_2 * lamb_p ** 2 + q_1 * lamb_p + q_0
dY3 = Y4
dY4 = (q_33 * lamb_p ** 3 + q_22 * lamb_p ** 2 + q_11 * lamb_p + q_00) * Y3 + \
(3 * q_3 * lamb_p ** 2 + 2 * q_2 * lamb_p + q_1) * Y4
return np.array([dlamb, dlamb_p, dY3, dY4])
return ODE
# funcs_beta = functions_beta()
ode_beta = buildODEbeta()
for i in range(iter_max):
iterations = i + 1
startwerte = [lamb_1, lamb_0, 0.0, 1.0]
# werte = rk.verfahren(funcs_beta, startwerte, dbeta, N, False)
beta_list, werte = rk.rk4(ode_beta, beta_1, startwerte, dbeta, N, False)
beta_end = beta_list[-1]
# beta_end, lamb_end, lamb_p_end, Y3_end, Y4_end = werte[-1]
lamb_end, lamb_p_end, Y3_end, Y4_end = werte[-1]
d_lamb_end_d_lambda0 = Y3_end
delta = lamb_end - lamb_2
if abs(delta) < epsilon:
converged = True
break
if abs(d_lamb_end_d_lambda0) < 1e-20:
raise RuntimeError("Abbruch (Ableitung ~ 0).")
max_step = 1.0
step = delta / d_lamb_end_d_lambda0
if abs(step) > max_step:
step = np.sign(step) * max_step
lamb_0 = lamb_0 - step
# werte = rk.verfahren(funcs_beta, [beta_1, lamb_1, lamb_0, 0.0, 1.0], dbeta, N, False)
beta_list, werte = rk.rk4(ode_beta, beta_1, np.array([lamb_1, lamb_0, 0.0, 1.0]), dbeta, N, False)
# beta_arr = np.zeros(N + 1)
beta_arr = np.array(beta_list)
lamb_arr = np.zeros(N + 1)
lambda_p_arr = np.zeros(N + 1)
for i, state in enumerate(werte):
# beta_arr[i] = state[0]
# lamb_arr[i] = state[1]
# lambda_p_arr[i] = state[2]
lamb_arr[i] = state[0]
lambda_p_arr[i] = state[1]
# Azimute
(BETA1, LAMBDA1, E1, G1,
*_) = BETA_LAMBDA(beta_arr[0], lamb_arr[0])
(BETA2, LAMBDA2, E2, G2,
*_) = BETA_LAMBDA(beta_arr[-1], lamb_arr[-1])
alpha_1 = (np.pi / 2.0) - arccot(np.sqrt(LAMBDA1 / BETA1) * lambda_p_arr[0])
alpha_2 = (np.pi / 2.0) - arccot(np.sqrt(LAMBDA2 / BETA2) * lambda_p_arr[-1])
integrand = np.zeros(N + 1)
for i in range(N + 1):
(_, _, Ei, Gi,
*_) = BETA_LAMBDA(beta_arr[i], lamb_arr[i])
integrand[i] = np.sqrt(Ei + Gi * lambda_p_arr[i] ** 2)
h = abs(dbeta) / N
if N % 2 == 0:
S = integrand[0] + integrand[-1] \
+ 4.0 * np.sum(integrand[1:-1:2]) \
+ 2.0 * np.sum(integrand[2:-1:2])
s = h / 3.0 * S
else:
s = np.trapz(integrand, dx=h)
if all_points:
return alpha_1, alpha_2, s, beta_arr, lamb_arr
else:
return alpha_1, alpha_2, s
if __name__ == "__main__":
# ell = EllipsoidTriaxial.init_name("Fiction")
# # beta1 = np.deg2rad(75)
# # lamb1 = np.deg2rad(-90)
# # beta2 = np.deg2rad(75)
# # lamb2 = np.deg2rad(66)
# # a1, a2, s = gha2_num(ell, beta1, lamb1, beta2, lamb2)
# # print(aus.gms("a1", a1, 4))
# # print(aus.gms("a2", a2, 4))
# # print(s)
# cart1 = ell.para2cart(0, 0)
# cart2 = ell.para2cart(0.4, 1.4)
# beta1, lamb1 = ell.cart2ell(cart1)
# beta2, lamb2 = ell.cart2ell(cart2)
#
# a1, a2, s = gha2_num(ell, beta1, lamb1, beta2, lamb2, n=5000)
# print(s)
# ell = EllipsoidTriaxial.init_name("BursaSima1980round")
# diffs_panou = []
# examples_panou = ne_panou.get_random_examples(4)
# for example in examples_panou:
# beta0, lamb0, beta1, lamb1, _, alpha0, alpha1, s = example
# P0 = ell.ell2cart(beta0, lamb0)
# try:
# alpha0_num, alpha1_num, s_num = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=4000, iter_max=10)
# diffs_panou.append(
# (wu.rad2deg(abs(alpha0 - alpha0_num)), wu.rad2deg(abs(alpha1 - alpha1_num)), abs(s - s_num)))
# except:
# print(f"Fehler für {beta0}, {lamb0}, {beta1}, {lamb1}")
# diffs_panou = np.array(diffs_panou)
# print(diffs_panou)
#
# ell = EllipsoidTriaxial.init_name("KarneyTest2024")
# diffs_karney = []
# # examples_karney = ne_karney.get_examples((30500, 40500))
# examples_karney = ne_karney.get_random_examples(2)
# for example in examples_karney:
# beta0, lamb0, alpha0, beta1, lamb1, alpha1, s = example
#
# try:
# alpha0_num, alpha1_num, s_num = gha2_num(ell, beta0, lamb0, beta1, lamb1, n=4000, iter_max=10)
# diffs_karney.append((wu.rad2deg(abs(alpha0-alpha0_num)), wu.rad2deg(abs(alpha1-alpha1_num)), abs(s-s_num)))
# except:
# print(f"Fehler für {beta0}, {lamb0}, {beta1}, {lamb1}")
# diffs_karney = np.array(diffs_karney)
# print(diffs_karney)
pass

201
GHA_triaxial/utils.py Normal file
View File

@@ -0,0 +1,201 @@
from __future__ import annotations
from typing import Tuple
import numpy as np
from numpy import arctan2, cos, sin, sqrt
from numpy.typing import NDArray
from ellipsoid_triaxial import EllipsoidTriaxial
from utils_angle import wrap_0_2pi
def sigma2alpha(ell: EllipsoidTriaxial, sigma: NDArray, point: NDArray) -> float:
"""
Berechnung des Azimuts an einem Punkt anhand der Ableitung zu den kartesischen Koordinaten
:param ell: Ellipsoid
:param sigma: Ableitungsvektor ver kartesischen Koordinaten
:param point: Punkt
:return: Azimuts
"""
p, q = pq_ell(ell, point)
P = float(p @ sigma)
Q = float(q @ sigma)
alpha = arctan2(P, Q)
return wrap_0_2pi(alpha)
def alpha_para2ell(ell: EllipsoidTriaxial, u: float, v: float, alpha_para: float) -> Tuple[float, float, float]:
"""
Umrechnung des Azimuts bezogen auf parametrische Koordinaten zu ellipsoidischen
:param ell: Ellipsoid
:param u: parametrische Breite
:param v: parametrische Länge
:param alpha_para: Azimut bezogen auf parametrische Koordinaten
:return: Azimut bezogen auf ellipsoidische Koordinaten
"""
point = ell.para2cart(u, v)
beta, lamb = ell.para2ell(u, v)
p_para, q_para = pq_para(ell, point)
sigma_para = p_para * sin(alpha_para) + q_para * cos(alpha_para)
p_ell, q_ell = pq_ell(ell, point)
alpha_ell = arctan2(p_ell @ sigma_para, q_ell @ sigma_para)
sigma_ell = p_ell * sin(alpha_ell) + q_ell * cos(alpha_ell)
if np.linalg.norm(sigma_para - sigma_ell) > 1e-7:
raise Exception("alpha_para2ell: Differenz in den Richtungsableitungen")
return beta, lamb, wrap_0_2pi(alpha_ell)
def alpha_ell2para(ell: EllipsoidTriaxial, beta: float, lamb: float, alpha_ell: float) -> Tuple[float, float, float]:
"""
Umrechnung des Azimuts bezogen auf ellipsoidische Koordinaten zu parametrischen
:param ell: Ellipsoid
:param beta: ellipsoidische Breite
:param lamb: ellipsoidische Länge
:param alpha_ell: Azimut bezogen auf ellipsoidische Koordinaten
:return: Azimut bezogen auf parametrische Koordinaten
"""
point = ell.ell2cart(beta, lamb)
u, v = ell.ell2para(beta, lamb)
p_ell, q_ell = pq_ell(ell, point)
sigma_ell = p_ell * sin(alpha_ell) + q_ell * cos(alpha_ell)
p_para, q_para = pq_para(ell, point)
alpha_para = arctan2(p_para @ sigma_ell, q_para @ sigma_ell)
sigma_para = p_para * sin(alpha_para) + q_para * cos(alpha_para)
if np.linalg.norm(sigma_para - sigma_ell) > 1e-7:
raise Exception("alpha_ell2para: Differenz in den Richtungsableitungen")
return u, v, wrap_0_2pi(alpha_para)
def func_sigma_ell(ell: EllipsoidTriaxial, point: NDArray, alpha_ell: float) -> NDArray:
"""
Berechnung der Richtungsableitungen in kartesischen Koordinaten aus ellipsoidischem Azimut
Panou (2019) [6]
:param ell: Ellipsoid
:param point: Punkt in kartesischen Koordinaten
:param alpha_ell: ellipsoidischer Azimut
:return: Richtungsableitungen in kartesischen Koordinaten
"""
p, q = pq_ell(ell, point)
sigma = p * sin(alpha_ell) + q * cos(alpha_ell)
return sigma
def func_sigma_para(ell: EllipsoidTriaxial, point: NDArray, alpha_para: float) -> NDArray:
"""
Berechnung der Richtungsableitungen in kartesischen Koordinaten aus parametischem Azimut
Panou, Korakitis (2019) [6]
:param ell: Ellipsoid
:param point: Punkt in kartesischen Koordinaten
:param alpha_para: parametrischer Azimut
:return: Richtungsableitungen in kartesischen Koordinaten
"""
p, q = pq_para(ell, point)
sigma = p * sin(alpha_para) + q * cos(alpha_para)
return sigma
def louville_constant(ell: EllipsoidTriaxial, p0: NDArray, alpha_ell: float) -> float:
"""
Berechnung der Louville Konstanten
Panou, Korakitis (2019) [6]
:param ell: Ellipsoid
:param p0: Punkt in kartesischen Koordinaten
:param alpha_ell: ellipsoidischer Azimut
:return:
"""
beta, lamb = ell.cart2ell(p0)
l = ell.Ey**2 * cos(beta)**2 * sin(alpha_ell)**2 - ell.Ee**2 * sin(lamb)**2 * cos(alpha_ell)**2
return l
def pq_ell(ell: EllipsoidTriaxial, point: NDArray) -> Tuple[NDArray, NDArray]:
"""
Berechnung von p (Tangente entlang konstantem beta) und q (Tangente entlang konstantem lambda)
Panou, Korakitits (2019) [5f.]
:param ell: Ellipsoid
:param point: Punkt
:return: p und q
"""
n = ell.func_n(point)
beta, lamb = ell.cart2ell(point)
if abs(cos(beta)) < 1e-15 and abs(np.sin(lamb)) < 1e-15:
if beta > 0:
p = np.array([0, -1, 0])
else:
p = np.array([0, 1, 0])
else:
B = ell.Ex ** 2 * cos(beta) ** 2 + ell.Ee ** 2 * sin(beta) ** 2
L = ell.Ex ** 2 - ell.Ee ** 2 * cos(lamb) ** 2
_, t2 = ell.func_t12(point)
F = ell.Ey ** 2 * cos(beta) ** 2 + ell.Ee ** 2 * sin(lamb) ** 2
p1 = -sqrt(L / (F * t2)) * ell.ax / ell.Ex * sqrt(B) * sin(lamb)
p2 = sqrt(L / (F * t2)) * ell.ay * cos(beta) * cos(lamb)
p3 = 1 / sqrt(F * t2) * (ell.b * ell.Ee ** 2) / (2 * ell.Ex) * sin(beta) * sin(2 * lamb)
p = np.array([p1, p2, p3])
p = p / np.linalg.norm(p)
q = np.array([n[1] * p[2] - n[2] * p[1],
n[2] * p[0] - n[0] * p[2],
n[0] * p[1] - n[1] * p[0]])
q = q / np.linalg.norm(q)
return p, q
def pq_para(ell: EllipsoidTriaxial, point: NDArray) -> Tuple[NDArray, NDArray]:
"""
Berechnung von p (Tangente entlang konstantem u) und q (Tangente entlang konstantem v)
Panou, Korakitits (2020)
:param ell: Ellipsoid
:param point: Punkt
:return: p und q
"""
n = ell.func_n(point)
u, v = ell.cart2para(point)
# 41-47
G = sqrt(1 - ell.ex ** 2 * cos(u) ** 2 - ell.ee ** 2 * sin(u) ** 2 * sin(v) ** 2)
q = np.array([-1 / G * sin(u) * cos(v),
-1 / G * sqrt(1 - ell.ee ** 2) * sin(u) * sin(v),
1 / G * sqrt(1 - ell.ex ** 2) * cos(u)])
p = np.array([q[1] * n[2] - q[2] * n[1],
q[2] * n[0] - q[0] * n[2],
q[0] * n[1] - q[1] * n[0]])
p = p / np.linalg.norm(p)
q = q / np.linalg.norm(q)
return p, q
def jacobi_konstante(beta: float, omega: float, alpha: float, ell: EllipsoidTriaxial) -> float:
"""
Jacobi-Konstante nach Karney (2025), Gl. (14)
:param beta: Beta Koordinate
:param omega: Omega Koordinate
:param alpha: Azimut alpha
:param ell: Ellipsoid
:return: Jacobi-Konstante
"""
gamma_jacobi = float((ell.k ** 2) * (np.cos(beta) ** 2) * (np.sin(alpha) ** 2) - (ell.k_ ** 2) * (np.sin(omega) ** 2) * (np.cos(alpha) ** 2))
return gamma_jacobi
if __name__ == "__main__":
ell = EllipsoidTriaxial.init_name("KarneyTest2024")
alpha_para = 0
u, v = ell.ell2para(np.pi/2, 0)
alpha_ell = alpha_para2ell(ell, u, v, alpha_para)
pass

View File

@@ -10,7 +10,7 @@ def xyz(x: float, y: float, z: float, stellen: int) -> str:
:param stellen: Anzahl Nachkommastellen :param stellen: Anzahl Nachkommastellen
:return: String zur Ausgabe der Koordinaten :return: String zur Ausgabe der Koordinaten
""" """
return f"""x = {(round(x,stellen))} m y = {(round(y,stellen))} m z = {(round(z,stellen))} m""" return f"""x = {(round(x, stellen))} m y = {(round(y, stellen))} m z = {(round(z, stellen))} m"""
def gms(name: str, rad: float, stellen: int) -> str: def gms(name: str, rad: float, stellen: int) -> str:
@@ -21,5 +21,5 @@ def gms(name: str, rad: float, stellen: int) -> str:
:param stellen: Anzahl Nachkommastellen :param stellen: Anzahl Nachkommastellen
:return: String zur Ausgabe des Winkels :return: String zur Ausgabe des Winkels
""" """
gms = wu.rad2gms(rad) values = wu.rad2gms(rad)
return f"{name} = {int(gms[0])}° {int(gms[1])}' {round(gms[2],stellen):.{stellen}f}''" return f"{name} = {int(values[0])}° {int(values[1])}' {round(values[2], stellen):.{stellen}f}''"

File diff suppressed because it is too large Load Diff

View File

@@ -1,101 +1,20 @@
import numpy as np import math
from numpy import sin, cos, arctan, arctan2, sqrt, pi, arccos
import winkelumrechnungen as wu
import jacobian_Ligas
import matplotlib.pyplot as plt
from typing import Tuple from typing import Tuple
import numpy as np
from numpy import arccos, arctan, arctan2, cos, pi, sin, sqrt
from numpy.typing import NDArray from numpy.typing import NDArray
import jacobian_Ligas
from utils_angle import wrap_mhalfpi_halfpi, wrap_mpi_pi
class EllipsoidBiaxial:
def __init__(self, a: float, b: float):
self.a = a
self.b = b
self.c = a ** 2 / b
self.e = sqrt(a ** 2 - b ** 2) / a
self.e_ = sqrt(a ** 2 - b ** 2) / b
@classmethod
def init_name(cls, name: str):
if name == "Bessel":
a = 6377397.15508
b = 6356078.96290
return cls(a, b)
elif name == "Hayford":
a = 6378388
f = 1/297
b = a - a * f
return cls(a, b)
elif name == "Krassowski":
a = 6378245
f = 298.3
b = a - a * f
return cls(a, b)
elif name == "WGS84":
a = 6378137
f = 298.257223563
b = a - a * f
return cls(a, b)
@classmethod
def init_af(cls, a: float, f: float):
b = a - a * f
return cls(a, b)
V = lambda self, phi: sqrt(1 + self.e_ ** 2 * cos(phi) ** 2)
M = lambda self, phi: self.c / self.V(phi) ** 3
N = lambda self, phi: self.c / self.V(phi)
beta2psi = lambda self, beta: arctan(self.a / self.b * np.tan(beta))
beta2phi = lambda self, beta: arctan(self.a ** 2 / self.b ** 2 * np.tan(beta))
psi2beta = lambda self, psi: arctan(self.b / self.a * np.tan(psi))
psi2phi = lambda self, psi: arctan(self.a / self.b * np.tan(psi))
phi2beta = lambda self, phi: arctan(self.b ** 2 / self.a ** 2 * np.tan(phi))
phi2psi = lambda self, phi: arctan(self.b / self.a * np.tan(phi))
phi2p = lambda self, phi: self.N(phi) * cos(phi)
def cart2ell(self, Eh, Ephi, x, y, z):
p = sqrt(x**2+y**2)
# print(f"p = {round(p, 5)} m")
lamb = arctan(y/x)
phi_null = arctan(z/p*(1-self.e**2)**-1)
hi = [0]
phii = [phi_null]
i = 0
while True:
N = self.a*(1-self.e**2*sin(phii[i])**2)**(-1/2)
h = p/cos(phii[i])-N
phi = arctan(z/p*(1-(self.e**2*N)/(N+h))**(-1))
hi.append(h)
phii.append(phi)
dh = abs(hi[i]-h)
dphi = abs(phii[i]-phi)
i = i+1
if dh < Eh:
if dphi < Ephi:
break
for i in range(len(phii)):
# print(f"P3[{i}]: {aus.gms('phi', phii[i], 5)}\th = {round(hi[i], 5)} m")
pass
return phi, lamb, h
def ell2cart(self, phi, lamb, h):
W = sqrt(1 - self.e**2 * sin(phi)**2)
N = self.a / W
x = (N+h) * cos(phi) * cos(lamb)
y = (N+h) * cos(phi) * sin(lamb)
z = (N * (1-self.e**2) + h) * sin(lamb)
return x, y, z
class EllipsoidTriaxial: class EllipsoidTriaxial:
"""
Klasse für dreiachsige Ellipsoide
Parameter: Formparameter
Funktionen: Koordinatenumrechnungen
"""
def __init__(self, ax: float, ay: float, b: float): def __init__(self, ax: float, ay: float, b: float):
self.ax = ax self.ax = ax
self.ay = ay self.ay = ay
@@ -109,12 +28,19 @@ class EllipsoidTriaxial:
self.Ex = sqrt(self.ax**2 - self.b**2) self.Ex = sqrt(self.ax**2 - self.b**2)
self.Ey = sqrt(self.ay**2 - self.b**2) self.Ey = sqrt(self.ay**2 - self.b**2)
self.Ee = sqrt(self.ax**2 - self.ay**2) self.Ee = sqrt(self.ax**2 - self.ay**2)
nenner = sqrt(max(self.ax * self.ax - self.b * self.b, 0.0))
self.k = sqrt(max(self.ay * self.ay - self.b * self.b, 0.0)) / nenner
self.k_ = sqrt(max(self.ax * self.ax - self.ay * self.ay, 0.0)) / nenner
self.e = sqrt(max(self.ax * self.ax - self.b * self.b, 0.0)) / self.ay
@classmethod @classmethod
def init_name(cls, name: str): def init_name(cls, name: str) -> EllipsoidTriaxial:
""" """
Mögliche Ellipsoide: BursaFialova1993, BursaSima1980, Eitschberger1978, Bursa1972, Bursa1970, BesselBiaxial Mögliche Ellipsoide: BursaSima1980round, KarneyTest2024, Fiction, BursaFialova1993, BursaSima1980, Eitschberger1978, Bursa1972,
Bursa1970
Panou et al (2020)
:param name: Name des dreiachsigen Ellipsoids :param name: Name des dreiachsigen Ellipsoids
:return: dreiachsiger Ellipsoid
""" """
if name == "BursaFialova1993": if name == "BursaFialova1993":
ax = 6378171.36 ax = 6378171.36
@@ -147,11 +73,6 @@ class EllipsoidTriaxial:
ay = 6378105 ay = 6378105
b = 6356754 b = 6356754
return cls(ax, ay, b) return cls(ax, ay, b)
elif name == "BesselBiaxial":
ax = 6377397.15509
ay = 6377397.15508
b = 6356078.96290
return cls(ax, ay, b)
elif name == "Fiction": elif name == "Fiction":
ax = 6000000 ax = 6000000
ay = 4000000 ay = 4000000
@@ -162,6 +83,8 @@ class EllipsoidTriaxial:
ay = 1 ay = 1
b = 1 / sqrt(2) b = 1 / sqrt(2)
return cls(ax, ay, b) return cls(ax, ay, b)
else:
raise Exception(f"EllipsoidTriaxial.init_name: Name {name} unbekannt")
def func_H(self, point: NDArray) -> float: def func_H(self, point: NDArray) -> float:
""" """
@@ -201,7 +124,12 @@ class EllipsoidTriaxial:
c0 = (self.ax ** 2 * self.ay ** 2 + self.ax ** 2 * self.b ** 2 + self.ay ** 2 * self.b ** 2 - c0 = (self.ax ** 2 * self.ay ** 2 + self.ax ** 2 * self.b ** 2 + self.ay ** 2 * self.b ** 2 -
(self.ay ** 2 + self.b ** 2) * x ** 2 - (self.ax ** 2 + self.b ** 2) * y ** 2 - ( (self.ay ** 2 + self.b ** 2) * x ** 2 - (self.ax ** 2 + self.b ** 2) * y ** 2 - (
self.ax ** 2 + self.ay ** 2) * z ** 2) self.ax ** 2 + self.ay ** 2) * z ** 2)
t2 = (-c1 + sqrt(c1 ** 2 - 4 * c0)) / 2 if c1 ** 2 - 4 * c0 < -1e-9:
raise Exception("t1, t2: Negativer Wurzelterm")
elif c1 ** 2 - 4 * c0 < 0:
t2 = 0
else:
t2 = (-c1 + sqrt(c1 ** 2 - 4 * c0)) / 2
if t2 == 0: if t2 == 0:
t2 = 1e-18 t2 = 1e-18
t1 = c0 / t2 t1 = c0 / t2
@@ -210,12 +138,9 @@ class EllipsoidTriaxial:
def ellu2cart(self, beta: float, lamb: float, u: float) -> NDArray: def ellu2cart(self, beta: float, lamb: float, u: float) -> NDArray:
""" """
Panou 2014 12ff. Panou 2014 12ff.
Elliptische Breite+Länge sind nicht gleich der geodätischen :param beta: ellipsoidische Breite
Verhältnisse des Ellipsoids bekannt, Größe verändern bis Punkt erreicht, :param lamb: ellipsoidische Länge
dann ist u die Größe entlang der z-Achse :param u: radiale Koordinate entlang der kleinen Halbachse
:param beta: ellipsoidische Breite [rad]
:param lamb: ellipsoidische Länge [rad]
:param u: Größe entlang der z-Achse
:return: Punkt in kartesischen Koordinaten :return: Punkt in kartesischen Koordinaten
""" """
x = sqrt(u**2 + self.Ex**2) * sqrt(cos(beta)**2 + self.Ee**2/self.Ex**2 * sin(beta)**2) * cos(lamb) x = sqrt(u**2 + self.Ex**2) * sqrt(cos(beta)**2 + self.Ee**2/self.Ex**2 * sin(beta)**2) * cos(lamb)
@@ -228,7 +153,7 @@ class EllipsoidTriaxial:
""" """
Panou 2014 15ff. Panou 2014 15ff.
:param point: Punkt in kartesischen Koordinaten :param point: Punkt in kartesischen Koordinaten
:return: elliptische Breite, elliptische Länge, Größe entlang der z-Achse :return: ellipsoidische Breite, ellipsoidische Länge, radiale Koordinate entlang der kleinen Halbachse
""" """
x, y, z = point x, y, z = point
c2 = self.ax**2 + self.ay**2 + self.b**2 - x**2 - y**2 - z**2 c2 = self.ax**2 + self.ay**2 + self.b**2 - x**2 - y**2 - z**2
@@ -244,7 +169,6 @@ class EllipsoidTriaxial:
s1 = 2 * sqrt(p) * cos(omega/3) - c2/3 s1 = 2 * sqrt(p) * cos(omega/3) - c2/3
s2 = 2 * sqrt(p) * cos(omega/3 - 2*pi/3) - c2/3 s2 = 2 * sqrt(p) * cos(omega/3 - 2*pi/3) - c2/3
s3 = 2 * sqrt(p) * cos(omega/3 - 4*pi/3) - c2/3 s3 = 2 * sqrt(p) * cos(omega/3 - 4*pi/3) - c2/3
# print(s1, s2, s3)
beta = arctan(sqrt((-self.b**2 - s2) / (self.ay**2 + s2))) beta = arctan(sqrt((-self.b**2 - s2) / (self.ay**2 + s2)))
if abs((-self.ay**2 - s3) / (self.ax**2 + s3)) > 1e-7: if abs((-self.ay**2 - s3) / (self.ax**2 + s3)) > 1e-7:
@@ -258,8 +182,8 @@ class EllipsoidTriaxial:
def ell2cart(self, beta: float | NDArray, lamb: float | NDArray) -> NDArray: def ell2cart(self, beta: float | NDArray, lamb: float | NDArray) -> NDArray:
""" """
Panou, Korakitis 2019 2 Panou, Korakitis 2019 2
:param beta: elliptische Breite [rad] :param beta: ellipsoidische Breite
:param lamb: elliptische Länge [rad] :param lamb: ellipsoidische Länge
:return: Punkt in kartesischen Koordinaten :return: Punkt in kartesischen Koordinaten
""" """
beta = np.asarray(beta, dtype=float) beta = np.asarray(beta, dtype=float)
@@ -267,6 +191,11 @@ class EllipsoidTriaxial:
beta, lamb = np.broadcast_arrays(beta, lamb) beta, lamb = np.broadcast_arrays(beta, lamb)
beta = np.where(
np.isclose(np.abs(beta), pi / 2, atol=1e-15),
beta * 8999999999999999 / 9000000000000000,
beta
)
B = self.Ex ** 2 * cos(beta) ** 2 + self.Ee ** 2 * sin(beta) ** 2 B = self.Ex ** 2 * cos(beta) ** 2 + self.Ee ** 2 * sin(beta) ** 2
L = self.Ex ** 2 - self.Ee ** 2 * cos(lamb) ** 2 L = self.Ex ** 2 - self.Ee ** 2 * cos(lamb) ** 2
@@ -294,8 +223,8 @@ class EllipsoidTriaxial:
def ell2cart_bektas(self, beta: float | NDArray, omega: float | NDArray) -> NDArray: def ell2cart_bektas(self, beta: float | NDArray, omega: float | NDArray) -> NDArray:
""" """
Bektas 2015 Bektas 2015
:param beta: elliptische Breite [rad] :param beta: ellipsoidische Breite
:param omega: elliptische Länge [rad] :param omega: ellipsoidische Länge
:return: Punkt in kartesischen Koordinaten :return: Punkt in kartesischen Koordinaten
""" """
x = self.ax * cos(omega) * sqrt((self.ax**2 - self.ay**2 * sin(beta)**2 - self.b**2 * cos(beta)**2) / (self.ax**2 - self.b**2)) x = self.ax * cos(omega) * sqrt((self.ax**2 - self.ay**2 * sin(beta)**2 - self.b**2 * cos(beta)**2) / (self.ax**2 - self.b**2))
@@ -307,8 +236,8 @@ class EllipsoidTriaxial:
def ell2cart_karney(self, beta: float | NDArray, lamb: float | NDArray) -> NDArray: def ell2cart_karney(self, beta: float | NDArray, lamb: float | NDArray) -> NDArray:
""" """
Karney 2025 Geographic Lib Karney 2025 Geographic Lib
:param beta: elliptische Breite [rad] :param beta: ellipsoidische Breite
:param lamb: elliptische Länge [rad] :param lamb: ellipsoidische Länge
:return: Punkt in kartesischen Koordinaten :return: Punkt in kartesischen Koordinaten
""" """
k = sqrt(self.ay**2 - self.b**2) / sqrt(self.ax**2 - self.b**2) k = sqrt(self.ay**2 - self.b**2) / sqrt(self.ax**2 - self.b**2)
@@ -318,60 +247,105 @@ class EllipsoidTriaxial:
Z = self.b * sin(beta) * sqrt(k**2 + k_**2 * sin(lamb)**2) Z = self.b * sin(beta) * sqrt(k**2 + k_**2 * sin(lamb)**2)
return np.array([X, Y, Z]) return np.array([X, Y, Z])
def cart2ell(self, point: NDArray, eps: float = 1e-12, maxI: int = 100) -> Tuple[float, float]: def cart2ell_yFake(self, point: NDArray, delta_y: float = 1e-4) -> Tuple[float, float]:
"""
Bei Fehlschlagen von cart2ell
:param point: Punkt in kartesischen Koordinaten
:param delta_y: Startwert für Suche nach kleinstmöglichem delta_y
:return: ellipsoidische Breite und Länge
"""
x, y, z = point
best_delta = np.inf
while True:
try:
y1 = y - delta_y
beta1, lamb1 = self.cart2ell(np.array([x, y1, z]), noFake=True)
point1 = self.ell2cart(beta1, lamb1)
y2 = y + delta_y
beta2, lamb2 = self.cart2ell(np.array([x, y2, z]), noFake=True)
point2 = self.ell2cart(beta2, lamb2)
pointM = (point1 + point2) / 2
actual_delta = np.linalg.norm(point - pointM)
except:
actual_delta = np.inf
if actual_delta < best_delta:
best_delta = actual_delta
delta_y /= 10
else:
delta_y *= 10
y1 = y - delta_y
beta1, lamb1 = self.cart2ell(np.array([x, y1, z]), noFake=True)
return beta1, lamb1
def cart2ell(self, point: NDArray, eps: float = 1e-12, maxI: int = 100, noFake: bool = False) -> Tuple[float, float]:
""" """
Panou, Korakitis 2019 3f. (num) Panou, Korakitis 2019 3f. (num)
:param point: Punkt in kartesischen Koordinaten :param point: Punkt in kartesischen Koordinaten
:param eps: zu erreichende Genauigkeit :param eps: zu erreichende Genauigkeit
:param maxI: maximale Anzahl Iterationen :param maxI: maximale Anzahl Iterationen
:return: elliptische Breite und Länge [rad] :param noFake: y numerisch anpassen?
:return: ellipsoidische Breite und Länge
""" """
x, y, z = point x, y, z = point
beta, lamb = self.cart2ell_panou(point) beta, lamb = self.cart2ell_panou(point)
delta_ell = np.array([np.inf, np.inf]).T delta_ell = np.array([np.inf, np.inf]).T
tiny = 1e-30
i = 0 try:
while np.sum(delta_ell) > eps and i < maxI: i = 0
x0, y0, z0 = self.ell2cart(beta, lamb) while np.linalg.norm(delta_ell) > eps and i < maxI:
delta_l = np.array([x-x0, y-y0, z-z0]).T x0, y0, z0 = self.ell2cart(beta, lamb)
delta_l = np.array([x-x0, y-y0, z-z0]).T
B = self.Ex ** 2 * cos(beta) ** 2 + self.Ee ** 2 * sin(beta) ** 2 B = max(self.Ex ** 2 * cos(beta) ** 2 + self.Ee ** 2 * sin(beta) ** 2, tiny)
L = self.Ex ** 2 - self.Ee ** 2 * cos(lamb) ** 2 L = max(self.Ex ** 2 - self.Ee ** 2 * cos(lamb) ** 2, tiny)
J = np.array([[(-self.ax * self.Ey ** 2) / (2 * self.Ex) * sin(2 * beta) / sqrt(B) * cos(lamb), J = np.array([[(-self.ax * self.Ey ** 2) / (2 * self.Ex) * sin(2 * beta) / sqrt(B) * cos(lamb),
-self.ax / self.Ex * sqrt(B) * sin(lamb)], -self.ax / self.Ex * sqrt(B) * sin(lamb)],
[-self.ay * sin(beta) * sin(lamb), [-self.ay * sin(beta) * sin(lamb),
self.ay * cos(beta) * cos(lamb)], self.ay * cos(beta) * cos(lamb)],
[self.b / self.Ex * cos(beta) * sqrt(L), [self.b / self.Ex * cos(beta) * sqrt(L),
(self.b * self.Ee ** 2) / (2 * self.Ex) * sin(beta) * sin(2 * lamb) / sqrt(L)]]) (self.b * self.Ee ** 2) / (2 * self.Ex) * sin(beta) * sin(2 * lamb) / sqrt(L)]])
N = J.T @ J N = J.T @ J
det = N[0, 0] * N[1, 1] - N[0, 1] * N[1, 0] det = N[0, 0] * N[1, 1] - N[0, 1] * N[1, 0]
if abs(det) < eps: N_inv = 1 / det * np.array([[N[1, 1], -N[0, 1]], [-N[1, 0], N[0, 0]]])
det = eps delta_ell = N_inv @ J.T @ delta_l
N_inv = 1 / det * np.array([[N[1, 1], -N[0, 1]], [-N[1, 0], N[0, 0]]]) # delta_ell, *_ = np.linalg.lstsq(J, delta_l, rcond=None)
delta_ell = N_inv @ J.T @ delta_l
beta += delta_ell[0]
lamb += delta_ell[1]
i += 1
if i == maxI: beta += delta_ell[0]
raise Exception("Umrechung ist nicht konvergiert") lamb += delta_ell[1]
i += 1
point_n = self.ell2cart(beta, lamb) if i == maxI:
delta_r = np.linalg.norm(point - point_n, axis=-1) raise Exception("Umrechnung cart2ell: nicht konvergiert")
if delta_r > 1e-4: point_n = self.ell2cart(beta, lamb)
# raise Exception("Fehler in der Umrechnung cart2ell") delta_r = np.linalg.norm(point - point_n, axis=-1)
print(f"Fehler in der Umrechnung cart2ell, deltaR = {delta_r}m") if delta_r > 1e-6:
raise Exception("Umrechnung cart2ell: Punktdifferenz")
return beta, lamb return wrap_mhalfpi_halfpi(beta), wrap_mpi_pi(lamb)
except Exception as e:
# Wenn die Berechnung fehlschlägt auf Grund von sehr kleinem y, solange anpassen, bis Umrechnung ohne Fehler
delta_y = 10 ** math.floor(math.log10(abs(self.ay/1000)))
if abs(y) < delta_y and not noFake:
return self.cart2ell_yFake(point, delta_y)
else:
raise e
def cart2ell_panou(self, point: NDArray) -> Tuple[float, float]: def cart2ell_panou(self, point: NDArray) -> Tuple[float, float]:
""" """
Panou, Korakitis 2019 2f. (analytisch -> Näherung) Panou, Korakitis 2019 2f. (analytisch -> Näherung)
:param point: Punkt in kartesischen Koordinaten :param point: Punkt in kartesischen Koordinaten
:return: elliptische Breite, elliptische Länge :return: ellipsoidische Breite und Länge
""" """
x, y, z = point x, y, z = point
@@ -397,9 +371,9 @@ class EllipsoidTriaxial:
t1, t2 = self.func_t12(point) t1, t2 = self.func_t12(point)
num_beta = max(t1 - self.b ** 2, 0) num_beta = max(t1 - self.b ** 2, 0)
den_beta = max(self.ay ** 2 - t1, 0) den_beta = max(self.ay ** 2 - t1, 1e-30)
num_lamb = max(t2 - self.ay ** 2, 0) num_lamb = max(t2 - self.ay ** 2, 0)
den_lamb = max(self.ax ** 2 - t2, 0) den_lamb = max(self.ax ** 2 - t2, 1e-30)
beta = arctan(sqrt(num_beta / den_beta)) beta = arctan(sqrt(num_beta / den_beta))
lamb = arctan(sqrt(num_lamb / den_lamb)) lamb = arctan(sqrt(num_lamb / den_lamb))
@@ -430,7 +404,7 @@ class EllipsoidTriaxial:
:param point: Punkt in kartesischen Koordinaten :param point: Punkt in kartesischen Koordinaten
:param eps: zu erreichende Genauigkeit :param eps: zu erreichende Genauigkeit
:param maxI: maximale Anzahl Iterationen :param maxI: maximale Anzahl Iterationen
:return: elliptische Breite und Länge [rad] :return: ellipsoidische Breite und Länge
""" """
x, y, z = point x, y, z = point
phi, lamb = self.cart2para(point) phi, lamb = self.cart2para(point)
@@ -449,16 +423,16 @@ class EllipsoidTriaxial:
i += 1 i += 1
if i == maxI: if i == maxI:
raise Exception("Umrechung ist nicht konvergiert") raise Exception("Umrechnung cart2ell: nicht konvergiert")
return phi, lamb return phi, lamb
def geod2cart(self, phi: float | NDArray, lamb: float | NDArray, h: float) -> NDArray: def geod2cart(self, phi: float | NDArray, lamb: float | NDArray, h: float) -> NDArray:
""" """
Ligas 2012, 250 Ligas 2012, 250
:param phi: geodätische Breite [rad] :param phi: geodätische Breite
:param lamb: geodätische Länge [rad] :param lamb: geodätische Länge
:param h: Höhe über dem Ellipsoid :param h: geodätische Höhe
:return: kartesische Koordinaten :return: kartesische Koordinaten
""" """
v = self.ax / sqrt(1 - self.ex**2*sin(phi)**2-self.ee**2*cos(phi)**2*sin(lamb)**2) v = self.ax / sqrt(1 - self.ex**2*sin(phi)**2-self.ee**2*cos(phi)**2*sin(lamb)**2)
@@ -474,7 +448,7 @@ class EllipsoidTriaxial:
:param point: Punkt in kartesischen Koordinaten :param point: Punkt in kartesischen Koordinaten
:param maxIter: maximale Anzahl Iterationen :param maxIter: maximale Anzahl Iterationen
:param maxLoa: Level of Accuracy, das erreicht werden soll :param maxLoa: Level of Accuracy, das erreicht werden soll
:return: phi, lambda, h :return: geodätische Breite, Länge, Höhe
""" """
xG, yG, zG = point xG, yG, zG = point
@@ -515,32 +489,44 @@ class EllipsoidTriaxial:
invJ, fxE = jacobian_Ligas.case2(E, F, G, np.array([xG, yG, zG]), pE) invJ, fxE = jacobian_Ligas.case2(E, F, G, np.array([xG, yG, zG]), pE)
elif mode == "ligas3": elif mode == "ligas3":
invJ, fxE = jacobian_Ligas.case3(E, F, G, np.array([xG, yG, zG]), pE) invJ, fxE = jacobian_Ligas.case3(E, F, G, np.array([xG, yG, zG]), pE)
else:
raise Exception(f"cart2geod: Modus {mode} nicht bekannt")
pEi = pE.reshape(-1, 1) - invJ @ fxE.reshape(-1, 1) pEi = pE.reshape(-1, 1) - invJ @ fxE.reshape(-1, 1)
pEi = pEi.reshape(1, -1).flatten() pEi = pEi.reshape(1, -1).flatten()
loa = sqrt((pEi[0]-pE[0])**2 + (pEi[1]-pE[1])**2 + (pEi[2]-pE[2])**2) loa = sqrt((pEi[0]-pE[0])**2 + (pEi[1]-pE[1])**2 + (pEi[2]-pE[2])**2)
pE = pEi pE = pEi
i += 1 i += 1
phi = arctan((1-self.ee**2) / (1-self.ex**2) * pE[2] / sqrt((1-self.ee**2)**2 * pE[0]**2 + pE[1]**2)) if i == maxIter and loa > maxLoa:
lamb = arctan(1/(1-self.ee**2) * pE[1]/pE[0]) act_mode = int(mode[-1])
h = np.sign(zG - pE[2]) * np.sign(pE[2]) * sqrt((pE[0] - xG) ** 2 + (pE[1] - yG) ** 2 + (pE[2] - zG) ** 2) new_mode = 3 if act_mode == 1 else act_mode - 1
phi, lamb, h = self.cart2geod(point, f"ligas{new_mode}", maxIter, maxLoa)
if xG < 0 and yG < 0: else:
lamb = -pi + lamb phi = arctan((1-self.ee**2) / (1-self.ex**2) * pE[2] / sqrt((1-self.ee**2)**2 * pE[0]**2 + pE[1]**2))
lamb = arctan(1/(1-self.ee**2) * pE[1]/pE[0])
h = np.sign(zG - pE[2]) * np.sign(pE[2]) * sqrt((pE[0] - xG) ** 2 + (pE[1] - yG) ** 2 + (pE[2] - zG) ** 2)
if h < -self.ax:
act_mode = int(mode[-1])
new_mode = 3 if act_mode == 1 else act_mode - 1
phi, lamb, h = self.cart2geod(point, f"ligas{new_mode}", maxIter, maxLoa)
else:
if xG < 0 and yG < 0:
lamb += -pi
elif xG < 0: elif xG < 0:
lamb = pi + lamb lamb += pi
if abs(zG) < eps: if abs(zG) < eps:
phi = 0 phi = 0
wrap_mhalfpi_halfpi(phi), wrap_mpi_pi(lamb)
return phi, lamb, h return wrap_mhalfpi_halfpi(phi), wrap_mpi_pi(lamb), h
def para2cart(self, u: float | NDArray, v: float | NDArray) -> NDArray: def para2cart(self, u: float | NDArray, v: float | NDArray) -> NDArray:
""" """
Panou, Korakitits 2020, 4 Panou, Korakitits 2020, 4
:param u: Parameter u :param u: parametrische Breite
:param v: Parameter v :param v: parametrische Länge
:return: Punkt in kartesischen Koordinaten :return: Punkt in kartesischen Koordinaten
""" """
x = self.ax * cos(u) * cos(v) x = self.ax * cos(u) * cos(v)
@@ -553,7 +539,7 @@ class EllipsoidTriaxial:
""" """
Panou, Korakitits 2020, 4 Panou, Korakitits 2020, 4
:param point: Punkt in kartesischen Koordinaten :param point: Punkt in kartesischen Koordinaten
:return: parametrische Koordinaten :return: parametrische Breite, Länge
""" """
x, y, z = point x, y, z = point
@@ -571,25 +557,25 @@ class EllipsoidTriaxial:
v = 2 * arctan2(v_check1, v_check2 + v_factor) v = 2 * arctan2(v_check1, v_check2 + v_factor)
else: else:
v = pi/2 - 2 * arctan2(v_check2, v_check1 + v_factor) v = pi/2 - 2 * arctan2(v_check2, v_check1 + v_factor)
wrap_mhalfpi_halfpi(u), wrap_mpi_pi(v)
return u, v return wrap_mhalfpi_halfpi(u), wrap_mpi_pi(v)
def ell2para(self, beta: float, lamb: float) -> Tuple[float, float]: def ell2para(self, beta: float, lamb: float) -> Tuple[float, float]:
""" """
Umrechung von elliptischen in parametrische Koordinaten (über kartesische Koordinaten) Umrechung von ellipsoidischen in parametrische Koordinaten (über kartesische Koordinaten)
:param beta: elliptische Breite :param beta: ellipsoidische Breite
:param lamb: elliptische Länge :param lamb: ellipsoidische Länge
:return: parametrische Koordinaten :return: parametrische Breite, Länge
""" """
cart = self.ell2cart(beta, lamb) cart = self.ell2cart(beta, lamb)
return self.cart2para(cart) return self.cart2para(cart)
def para2ell(self, u: float, v: float) -> Tuple[float, float]: def para2ell(self, u: float, v: float) -> Tuple[float, float]:
""" """
Umrechung von parametrischen in elliptische Koordinaten (über kartesische Koordinaten) Umrechung von parametrischen in ellipsoidische Koordinaten (über kartesische Koordinaten)
:param u: u :param u: parametrische Breite
:param v: v :param v: parametrische Länge
:return: elliptische Koordinaten :return: ellipsoidische Breite, Länge
""" """
cart = self.para2cart(u, v) cart = self.para2cart(u, v)
return self.cart2ell(cart) return self.cart2ell(cart)
@@ -597,12 +583,12 @@ class EllipsoidTriaxial:
def para2geod(self, u: float, v: float, mode: str = "ligas3", maxIter: int = 30, maxLoa: float = 0.005) -> Tuple[float, float, float]: def para2geod(self, u: float, v: float, mode: str = "ligas3", maxIter: int = 30, maxLoa: float = 0.005) -> Tuple[float, float, float]:
""" """
Umrechung von parametrischen in geodätische Koordinaten (über kartesische Koordinaten) Umrechung von parametrischen in geodätische Koordinaten (über kartesische Koordinaten)
:param u: u :param u: parametrische Breite
:param v: v :param v: parametrische Länge
:param mode: ligas1, ligas2, oder ligas3 :param mode: ligas1, ligas2, oder ligas3
:param maxIter: maximale Anzahl Iterationen :param maxIter: maximale Anzahl Iterationen
:param maxLoa: Level of Accuracy, das erreicht werden soll :param maxLoa: Level of Accuracy, das erreicht werden soll
:return: geodätische Koordinaten :return: geodätische Breite, Länge, Höhe
""" """
cart = self.para2cart(u, v) cart = self.para2cart(u, v)
return self.cart2geod(cart, mode, maxIter, maxLoa) return self.cart2geod(cart, mode, maxIter, maxLoa)
@@ -610,41 +596,41 @@ class EllipsoidTriaxial:
def geod2para(self, phi: float, lamb: float, h: float) -> Tuple[float, float]: def geod2para(self, phi: float, lamb: float, h: float) -> Tuple[float, float]:
""" """
Umrechung von geodätischen in parametrische Koordinaten (über kartesische Koordinaten) Umrechung von geodätischen in parametrische Koordinaten (über kartesische Koordinaten)
:param phi: u :param phi: geodätische Breite
:param lamb: v :param lamb: geodätische Länge
:param h: geodätische Höhe :param h: geodätische Höhe
:return: parametrische Koordinaten :return: parametrische Breite, Länge
""" """
cart = self.geod2cart(phi, lamb, h) cart = self.geod2cart(phi, lamb, h)
return self.cart2para(cart) return self.cart2para(cart)
def ell2geod(self, beta: float, lamb: float, mode: str = "ligas3", maxIter: int = 30, maxLoa: float = 0.005) -> Tuple[float, float, float]: def ell2geod(self, beta: float, lamb: float, mode: str = "ligas3", maxIter: int = 30, maxLoa: float = 0.005) -> Tuple[float, float, float]:
""" """
Umrechung von elliptischen in geodätische Koordinaten (über kartesische Koordinaten) Umrechung von ellipsoidischen in geodätische Koordinaten (über kartesische Koordinaten)
:param beta: elliptische Breite :param beta: ellipsoidische Breite
:param lamb: eliptische Länge :param lamb: ellipsoidische Länge
:param mode: ligas1, ligas2, oder ligas3 :param mode: ligas1, ligas2, oder ligas3
:param maxIter: maximale Anzahl Iterationen :param maxIter: maximale Anzahl Iterationen
:param maxLoa: Level of Accuracy, das erreicht werden soll :param maxLoa: Level of Accuracy, das erreicht werden soll
:return: geodätische Koordinaten :return: geodätische Breite, Länge, Höhe
""" """
cart = self.ell2cart(beta, lamb) cart = self.ell2cart(beta, lamb)
return self.cart2geod(cart, mode, maxIter, maxLoa) return self.cart2geod(cart, mode, maxIter, maxLoa)
def geod2ell(self, phi: float, lamb: float, h: float) -> Tuple[float, float]: def geod2ell(self, phi: float, lamb: float, h: float) -> Tuple[float, float]:
""" """
Umrechung von geodätischen in elliptische Koordinaten (über kartesische Koordinaten) Umrechung von geodätischen in ellipsoidische Koordinaten (über kartesische Koordinaten)
:param phi: u :param phi: geodätische Breite
:param lamb: v :param lamb: geodätische Länge
:param h: geodätische Höhe :param h: geodätische Höhe
:return: elliptische Koordinaten :return: ellipsoidische Breite, Länge
""" """
cart = self.geod2cart(phi, lamb, h) cart = self.geod2cart(phi, lamb, h)
return self.cart2ell(cart) return self.cart2ell(cart)
def point_on(self, point: NDArray) -> bool: def point_on(self, point: NDArray) -> bool:
""" """
Test, ob ein Punkt auf dem Ellipsoid liegt. Test, ob ein Punkt auf dem Ellipsoid liegt
:param point: kartesische 3D-Koordinaten :param point: kartesische 3D-Koordinaten
:return: Punkt auf dem Ellispoid? :return: Punkt auf dem Ellispoid?
""" """
@@ -677,62 +663,71 @@ class EllipsoidTriaxial:
if __name__ == "__main__": if __name__ == "__main__":
ell = EllipsoidTriaxial.init_name("BursaSima1980round") ell = EllipsoidTriaxial.init_name("KarneyTest2024")
diff_list = [] # cart = ell.ell2cart(pi/2, 0)
diffs_para = [] # print(cart)
diffs_ell = [] # cart = ell.ell2cart(pi/2*8999999999999999/9000000000000000, 0)
diffs_geod = [] # print(cart)
points = [] elli = ell.cart2ell(np.array([0, 0.0, 1/sqrt(2)]))
for v_deg in range(-180, 181, 5): print(elli)
for u_deg in range(-90, 91, 5):
v = wu.deg2rad(v_deg)
u = wu.deg2rad(u_deg)
point = ell.para2cart(u, v)
points.append(point)
elli = ell.cart2ell(point) # ell = EllipsoidTriaxial.init_name("BursaSima1980")
cart_elli = ell.ell2cart(elli[0], elli[1]) # diff_list = []
diff_ell = np.linalg.norm(point - cart_elli, axis=-1) # diffs_para = []
# diffs_ell = []
para = ell.cart2para(point) # diffs_geod = []
cart_para = ell.para2cart(para[0], para[1]) # points = []
diff_para = np.linalg.norm(point - cart_para, axis=-1) # for v_deg in range(-180, 181, 5):
# for u_deg in range(-90, 91, 5):
geod = ell.cart2geod(point, "ligas3") # v = wu.deg2rad(v_deg)
cart_geod = ell.geod2cart(geod[0], geod[1], geod[2]) # u = wu.deg2rad(u_deg)
diff_geod3 = np.linalg.norm(point - cart_geod, axis=-1) # point = ell.para2cart(u, v)
# points.append(point)
diff_list.append([v_deg, u_deg, diff_ell, diff_para, diff_geod3]) #
diffs_ell.append([diff_ell]) # elli = ell.cart2ell(point)
diffs_para.append([diff_para]) # cart_elli = ell.ell2cart(elli[0], elli[1])
diffs_geod.append([diff_geod3]) # diff_ell = np.linalg.norm(point - cart_elli, axis=-1)
#
diff_list = np.array(diff_list) # para = ell.cart2para(point)
diffs_ell = np.array(diffs_ell) # cart_para = ell.para2cart(para[0], para[1])
diffs_para = np.array(diffs_para) # diff_para = np.linalg.norm(point - cart_para, axis=-1)
diffs_geod = np.array(diffs_geod) #
# geod = ell.cart2geod(point, "ligas3")
pass # cart_geod = ell.geod2cart(geod[0], geod[1], geod[2])
points = np.array(points) # diff_geod3 = np.linalg.norm(point - cart_geod, axis=-1)
fig = plt.figure() #
ax = fig.add_subplot(projection='3d') # diff_list.append([v_deg, u_deg, diff_ell, diff_para, diff_geod3])
# diffs_ell.append([diff_ell])
sc = ax.scatter( # diffs_para.append([diff_para])
points[:, 0], # diffs_geod.append([diff_geod3])
points[:, 1], #
points[:, 2], # diff_list = np.array(diff_list)
c=diffs_ell, # Farbcode = diff # diffs_ell = np.array(diffs_ell)
cmap='viridis', # Colormap # diffs_para = np.array(diffs_para)
s=10 + 20 * diffs_ell, # optional: Größe abhängig vom diff # diffs_geod = np.array(diffs_geod)
alpha=0.8 #
) # pass
#
# Farbskala # points = np.array(points)
cbar = plt.colorbar(sc) # fig = plt.figure()
cbar.set_label("diff") # ax = fig.add_subplot(projection='3d')
#
ax.set_xlabel("X") # sc = ax.scatter(
ax.set_ylabel("Y") # points[:, 0],
ax.set_zlabel("Z") # points[:, 1],
# points[:, 2],
plt.show() # c=diffs_ell, # Farbcode = diff
# cmap='viridis', # Colormap
# s=10 + 20 * diffs_ell, # optional: Größe abhängig vom diff
# alpha=0.8
# )
#
# # Farbskala
# cbar = plt.colorbar(sc)
# cbar.set_label("diff")
#
# ax.set_xlabel("X")
# ax.set_ylabel("Y")
# ax.set_zlabel("Z")
#
# plt.show()

View File

@@ -1,6 +1,19 @@
import numpy as np from typing import Tuple
def case1(E: float, F: float, G: float, pG: np.ndarray, pE: np.ndarray): import numpy as np
from numpy.typing import NDArray
def case1(E: float, F: float, G: float, pG: NDArray, pE: NDArray) -> Tuple[NDArray, NDArray]:
"""
Aufstellen des Gleichungssystem für den ersten Fall
:param E: Konstante E
:param F: Konstante F
:param G: Konstante G
:param pG: Punkt über dem Ellipsoid
:param pE: Punkt auf dem Ellipsoid
:return: inverse Jacobi-Matrix, Gleichungssystem
"""
j11 = 2 * E * pE[0] j11 = 2 * E * pE[0]
j12 = 2 * F * pE[1] j12 = 2 * F * pE[1]
j13 = 2 * G * pE[2] j13 = 2 * G * pE[2]
@@ -23,7 +36,16 @@ def case1(E: float, F: float, G: float, pG: np.ndarray, pE: np.ndarray):
return invJ, fxE return invJ, fxE
def case2(E: float, F: float, G: float, pG: np.ndarray, pE: np.ndarray): def case2(E: float, F: float, G: float, pG: NDArray, pE: NDArray) -> Tuple[NDArray, NDArray]:
"""
Aufstellen des Gleichungssystem für den zweiten Fall
:param E: Konstante E
:param F: Konstante F
:param G: Konstante G
:param pG: Punkt über dem Ellipsoid
:param pE: Punkt auf dem Ellipsoid
:return: inverse Jacobi-Matrix, Gleichungssystem
"""
j11 = 2 * E * pE[0] j11 = 2 * E * pE[0]
j12 = 2 * F * pE[1] j12 = 2 * F * pE[1]
j13 = 2 * G * pE[2] j13 = 2 * G * pE[2]
@@ -48,7 +70,16 @@ def case2(E: float, F: float, G: float, pG: np.ndarray, pE: np.ndarray):
return invJ, fxE return invJ, fxE
def case3(E: float, F: float, G: float, pG: np.ndarray, pE: np.ndarray): def case3(E: float, F: float, G: float, pG: NDArray, pE: NDArray) -> Tuple[NDArray, NDArray]:
"""
Aufstellen des Gleichungssystem für den dritten Fall
:param E: Konstante E
:param F: Konstante F
:param G: Konstante G
:param pG: Punkt über dem Ellipsoid
:param pE: Punkt auf dem Ellipsoid
:return: inverse Jacobi-Matrix, Gleichungssystem
"""
j11 = 2 * E * pE[0] j11 = 2 * E * pE[0]
j12 = 2 * F * pE[1] j12 = 2 * F * pE[1]
j13 = 2 * G * pE[2] j13 = 2 * G * pE[2]

View File

@@ -1,78 +0,0 @@
import numpy as np
def cart2sph(x, y, z):
r = np.sqrt(x**2 + y**2 + z**2)
phi = np.atan2(z, np.sqrt(x**2 + y**2))
lamb = np.atan2(y, x)
return r, np.rad2deg(phi), np.rad2deg(lamb)
def sph2cart(r, phi, lamb):
phi_rad = np.deg2rad(phi)
lamb_rad = np.deg2rad(lamb)
x = r * np.cos(phi_rad) * np.cos(lamb_rad)
y = r * np.cos(phi_rad) * np.sin(lamb_rad)
z = r * np.sin(phi_rad)
return x, y, z
def kugel_erste_gha(R, phi_1, lamb_1, s_d, a_12):
s = s_d / R
lamb_1_rad = np.deg2rad(lamb_1)
phi_1_rad = np.deg2rad(phi_1)
a_12_rad = np.deg2rad(a_12)
sin_satz = np.sin(s) * np.sin(a_12_rad)
sin_kos = np.cos(phi_1_rad) * np.cos(s) - np.sin(phi_1_rad) * np.sin(s) * np.cos(a_12_rad)
delta_lam = np.atan2(sin_satz, sin_kos)
lamb_2_rad = lamb_1_rad + delta_lam
phi_2_rad = np.asin(np.sin(phi_1_rad) * np.cos(s) + np.cos(phi_1_rad) * np.sin(s) * np.cos(a_12_rad))
sin_satz_2 = -np.cos(phi_1_rad) * np.sin(a_12_rad)
sin_kos_2 = np.sin(s) * np.sin(phi_1_rad) - np.cos(s) * np.cos(phi_1_rad) * np.cos(a_12_rad)
a_21_rad = np.atan2(sin_satz_2, sin_kos_2)
if a_21_rad < 0:
a_21_rad += 2 * np.pi
return np.rad2deg(phi_2_rad), np.rad2deg(lamb_2_rad), np.rad2deg(a_21_rad)
def kugel_zweite_gha(R, phi_1, lamb_1, phi_2, lamb_2):
phi_1_rad = np.deg2rad(phi_1)
lamb_1_rad = np.deg2rad(lamb_1)
phi_2_rad = np.deg2rad(phi_2)
lamb_2_rad = np.deg2rad(lamb_2)
sin_satz_1 = np.cos(phi_2_rad) * np.sin(lamb_2_rad - lamb_1_rad)
sin_kos_1 = np.cos(phi_1_rad) * np.sin(phi_2_rad) - np.sin(phi_1_rad) * np.cos(phi_2_rad) * np.cos(lamb_2_rad - lamb_1_rad)
a_12_rad = np.atan2(sin_satz_1, sin_kos_1)
kos = np.sin(phi_1_rad) * np.sin(phi_2_rad) + np.cos(phi_1_rad) * np.cos(phi_2_rad) * np.cos(lamb_2_rad - lamb_1_rad)
s = np.acos(kos)
s_d = R * s
sin_satz_2 = -np.cos(phi_1_rad) * np.sin(lamb_2_rad - lamb_1_rad)
sin_kos_2 = np.cos(phi_2_rad) * np.sin(phi_1_rad) - np.sin(phi_2_rad) * np.cos(phi_1_rad) * np.cos(lamb_2_rad - lamb_1_rad)
a_21_rad = np.atan2(sin_satz_2, sin_kos_2)
if a_21_rad < 0:
a_21_rad += 2 * np.pi
return s_d, np.rad2deg(a_12_rad), np.rad2deg(a_21_rad)
if __name__ == "__main__":
R = 6378815.904 # Bern
phi_1 = 10
lamb_1 = 40
a_12 = 100
s = 10000
phi_2, lamb_2, _ = kugel_erste_gha(R, phi_1, lamb_1, s, a_12)
print(kugel_erste_gha(R, phi_1, lamb_1, s, a_12))
print(kugel_zweite_gha(R, phi_1, lamb_1, phi_2, lamb_2))

View File

@@ -0,0 +1,36 @@
from typing import Tuple
import scipy as sp
from ellipsoid_biaxial import EllipsoidBiaxial
from numpy import *
def gha1(re: EllipsoidBiaxial, phi0: float, lamb0: float, alpha0:float, s: float) -> Tuple[float, float, float]:
"""
Berechnung der 1.GHA auf einem Rotationsellipsoid nach Bessel
:param re:
:param phi0:
:param lamb0:
:param alpha0:
:param s:
:return:
"""
psi0 = re.phi2psi(phi0)
clairant = arcsin(cos(psi0) * sin(alpha0))
sigma0 = arcsin(sin(psi0) / cos(clairant))
sqrt_sigma = lambda sigma: sqrt(1 + re.e_ ** 2 * cos(clairant) ** 2 * sin(sigma) ** 2)
int_sqrt_sigma = lambda sigma: sp.integrate.quad(sqrt_sigma, sigma0, sigma)[0]
f_sigma1_i = lambda sigma1_i: (int_sqrt_sigma(sigma1_i) - s / re.b)
sigma1_0 = sigma0 + s / re.a
sigma1 = sp.optimize.newton(f_sigma1_i, sigma1_0)
psi1 = arcsin(cos(clairant) * sin(sigma1))
phi1 = re.psi2phi(psi1)
alpha1 = arcsin(sin(clairant) / cos(psi1))
f_d_lambda = lambda sigma: sin(clairant) * sqrt_sigma(sigma) / (1 - cos(clairant) ** 2 * sin(sigma) ** 2)
d_lambda = sqrt(1-re.e**2) * sp.integrate.quad(f_d_lambda, sigma0, sigma1)[0]
lamb1 = lamb0 + d_lambda
return phi1, lamb1, alpha1

View File

@@ -0,0 +1,101 @@
from typing import Tuple
from ellipsoid_biaxial import EllipsoidBiaxial
from numpy import arctan, cos, sin, sqrt, tan
def gha1(re: EllipsoidBiaxial, phi0: float, lamb0: float, alpha0: float, s: float, eps: float = 1e-12) -> Tuple[float, float, float]:
"""
Berechnung der 1. Geodätische Hauptaufgabe nach Gauß´schen Mittelbreitenformeln
:param re: Klasse Ellipsoid
:param phi0: Breite Punkt 0
:param lamb0: Länge Punkt 0
:param alpha0: Azimut der geodätischen Linie in Punkt 1
:param s: Strecke zu Punkt 1
:param eps: Abbruchkriterium für Winkelgrößen
:return: Breite, Länge, Azimut von Punkt 21
"""
t = lambda phi: tan(phi)
eta = lambda phi: sqrt(re.e_ ** 2 * cos(phi) ** 2)
F1 = lambda alpha, phi, s: 1 + (2 + 3 * t(phi) ** 2 + 2 * eta(phi) ** 2) / (24 * re.N(phi) ** 2) * sin(alpha) ** 2 * s ** 2 \
+ (t(phi)**2 - 1) * eta(phi) ** 2 / (8 * re.N(phi) ** 2) * cos(alpha) ** 2 * s ** 2
F2 = lambda alpha, phi, s: 1 + t(phi) ** 2 / (24 * re.N(phi) ** 2) * sin(alpha) ** 2 * s ** 2 \
- (1 + eta(phi)**2 - 9 * eta(phi)**2 * t(phi)**2) / (24 * re.N(phi) ** 2) * cos(alpha) ** 2 * s ** 2
F3 = lambda alpha, phi, s: 1 + (1 + eta(phi) ** 2) / (12 * re.N(phi) ** 2) * sin(alpha) ** 2 * s ** 2 \
+ (3 + 8 * eta(phi)**2) / (24 * re.N(phi) ** 2) * cos(alpha) ** 2 * s ** 2
phi1_i = lambda alpha, phi: phi0 + cos(alpha) / re.M(phi) * s * F1(alpha, phi, s)
lamb1_i = lambda alpha, phi: lamb0 + sin(alpha) / (re.N(phi) * cos(phi)) * s * F2(alpha, phi, s)
alpha1_i = lambda alpha, phi: alpha0 + sin(alpha) * tan(phi) / re.N(phi) * s * F3(alpha, phi, s)
phi_m_i = lambda phi1: (phi0 + phi1) / 2
alpha_m_i = lambda alpha1: (alpha0 + alpha1) / 2
phi_m = []
alpha_m = []
phi1 = []
lamb1 = []
alpha1 = []
# 1. Näherung für P1
phi1.append(phi0 + cos(alpha0) / re.M(phi0) * s)
lamb1.append(lamb0 + sin(alpha0) / (re.N(phi0) * cos(phi0)) * s)
alpha1.append(alpha0 + sin(alpha0) * tan(phi0) / re.N(phi0) * s)
while True:
# Berechnug P_m durch Mittelbildung
phi_m.append(phi_m_i(phi1[-1]))
alpha_m.append(alpha_m_i(alpha1[-1]))
# Berechnung P1
phi1.append(phi1_i(alpha_m[-1], phi_m[-1]))
lamb1.append(lamb1_i(alpha_m[-1], phi_m[-1]))
alpha1.append(alpha1_i(alpha_m[-1], phi_m[-1]))
# Abbruchkriterium
if abs(phi1[-2] - phi1[-1]) < eps and \
abs(lamb1[-2] - lamb1[-1]) < eps and \
abs(alpha1[-2] - alpha1[-1]) < eps:
break
return phi1[-1], lamb1[-1], alpha1[-1]
def gha2(re: EllipsoidBiaxial, phi0: float, lamb0: float, phi1: float, lamb1: float):
"""
Berechnung der 2. Geodätische Hauptaufgabe nach Gauß´schen Mittelbreitenformeln
:param re: Klasse Ellipsoid
:param phi0: Breite Punkt 1
:param lamb0: Länge Punkt 1
:param phi1: Breite Punkt 2
:param lamb1: Länge Punkt 2
:return: Länge der geodätischen Linie, Azimut von P1 nach P2, Azimut von P2 nach P1
"""
t = lambda phi: tan(phi)
eta = lambda phi: sqrt(re.e_ ** 2 * cos(phi) ** 2)
phi_0 = (phi0 + phi1) / 2
d_phi = phi1 - phi0
d_lambda = lamb1 - lamb0
f_A = lambda phi: (2 + 3*t(phi)**2 + 2*eta(phi)**2) / 24
f_B = lambda phi: ((t(phi)**2 - 1) * eta(phi)**2) / 8
# f_C = lambda phi: (t(phi)**2) / 24
f_D = lambda phi: (1 + eta(phi)**2 - 9 * eta(phi)**2 * t(phi)**2) / 24
F1 = lambda phi: d_phi * re.M(phi) * (1 - f_A(phi) * d_lambda ** 2 * cos(phi) ** 2 -
f_B(phi) * d_phi ** 2 / re.V(phi) ** 4)
F2 = lambda phi: d_lambda * re.N(phi) * cos(phi) * (1 - 1 / 24 * d_lambda ** 2 * sin(phi) ** 2 +
f_D(phi) * d_phi ** 2 / re.V(phi) ** 4)
s = sqrt(F1(phi_0) ** 2 + F2(phi_0) ** 2)
A_0 = arctan(F2(phi_0) / F1(phi_0))
d_A = d_lambda * sin(phi_0) * (1 + (1 + eta(phi_0) ** 2) / 12 * s ** 2 * sin(A_0) ** 2 / re.N(phi_0) ** 2 +
(3 + 8 * eta(phi_0) ** 2) / 24 * s ** 2 * cos(A_0) ** 2 / re.N(phi_0) ** 2)
alpha0 = A_0 - d_A / 2
alpha1 = A_0 + d_A / 2
return alpha0, alpha1, s

View File

@@ -0,0 +1,33 @@
from typing import Tuple
import numpy as np
from ellipsoid_biaxial import EllipsoidBiaxial
from numpy import cos, sin, tan
from numpy.typing import NDArray
import runge_kutta as rk
def gha1(re: EllipsoidBiaxial, phi0: float, lamb0: float, alpha0: float, s: float, num: int) -> Tuple[float, float, float]:
"""
Berechnung der 1. GHA auf einem Rotationsellipsoid mittels RK4
:param re:
:param phi0:
:param lamb0:
:param alpha0:
:param s:
:param num:
:return:
"""
def buildODE():
def ODE(s: float, v: NDArray):
phi, lam, A = v
V = re.V(phi)
dphi = cos(A) * V ** 3 / re.c
dlam = sin(A) * V / (cos(phi) * re.c)
dA = tan(phi) * sin(A) * V / re.c
return np.array([dphi, dlam, dA])
return ODE
_, funktionswerte = rk.rk4(buildODE(), 0, np.array([phi0, lamb0, alpha0]), s, num)
return funktionswerte[-1][0], funktionswerte[-1][1], funktionswerte[-1][2]

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,101 @@
{
"cells": [
{
"metadata": {},
"cell_type": "code",
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
],
"id": "a78faf7f4883772f",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"%reload_ext autoreload\n",
"%autoreload 2\n",
"import numpy as np\n",
"\n",
"import winkelumrechnungen as wu\n",
"from GHA_triaxial.utils import alpha_ell2para, alpha_para2ell\n",
"from ellipsoid_triaxial import EllipsoidTriaxial"
],
"id": "46aa84a937fea491",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"ell = EllipsoidTriaxial.init_name(\"KarneyTest2024\")\n",
"diffs = []\n",
"for beta_deg in range(-90, 91, 15):\n",
" for lamb_deg in range(-180, 180, 15):\n",
" for alpha_deg in range(0, 360, 15):\n",
" beta = wu.deg2rad(beta_deg)\n",
" lamb = wu.deg2rad(lamb_deg)\n",
" u, v = ell.ell2para(beta, lamb)\n",
" alpha = wu.deg2rad(alpha_deg)\n",
"\n",
" alpha_para_1, *_ = alpha_ell2para(ell, beta, lamb, alpha)\n",
" alpha_ell_1, *_ = alpha_para2ell(ell, u, v, alpha_para_1)\n",
" diff_1 = wu.deg2rad(abs(alpha_ell_1 - alpha))/3600\n",
"\n",
" alpha_ell_2, *_ = alpha_para2ell(ell, u, v, alpha)\n",
" alpha_para_2, *_ = alpha_ell2para(ell, beta, lamb, alpha_ell_2)\n",
" diff_2 = wu.deg2rad(abs(alpha_para_2 - alpha))/3600\n",
"\n",
" diffs.append((beta_deg, lamb_deg, alpha_deg, diff_1, diff_2))\n",
"diffs = np.array(diffs)"
],
"id": "82fc6cbbe7d5abcb",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"i_max_ell = np.argmax(diffs[:, 3])\n",
"max_ell = diffs[i_max_ell, 3]\n",
"point_max_ell = diffs[i_max_ell, :3]\n",
"\n",
"i_max_para = np.argmax(diffs[:, 4])\n",
"max_para = diffs[i_max_para, 4]\n",
"point_max_para = diffs[i_max_para, :4]\n",
"\n",
"print(f'Für elliptisches Alpha = {point_max_ell[2]}° und beta = {point_max_ell[0]}°, lamb = {point_max_ell[1]}°: diff = {max_ell}\"')\n",
"print(f'Für parametrisches Alpha = {point_max_para[2]}° und beta = {point_max_para[0]}°, lamb = {point_max_para[1]}°: diff = {max_ell}\"')\n",
"pass"
],
"id": "97b5b8c9ca5377ab",
"outputs": [],
"execution_count": null
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,246 @@
{
"cells": [
{
"metadata": {},
"cell_type": "code",
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
],
"id": "746c5b9e4c0226e7",
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"id": "initial_id",
"metadata": {
"collapsed": true
},
"source": [
"%reload_ext autoreload\n",
"%autoreload 2\n",
"from itertools import product\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import plotly.graph_objects as go\n",
"\n",
"import winkelumrechnungen as wu\n",
"from ellipsoid_triaxial import EllipsoidTriaxial"
],
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"# ellips = \"KarneyTest2024\"\n",
"ellips = \"BursaSima1980\"\n",
"# ellips = \"Fiction\"\n",
"ell: EllipsoidTriaxial = EllipsoidTriaxial.init_name(ellips)"
],
"id": "7b05ca89fcd7b331",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"def deg_range(start, stop, step):\n",
" return [float(x) for x in range(start, stop + step, step)]\n",
"\n",
"def asymptotic_range(start, direction=\"up\", max_decimals=4):\n",
" values = []\n",
" for d in range(0, max_decimals + 1):\n",
" step = 10 ** -d\n",
" if direction == \"up\":\n",
" values.append(start + (1 - step))\n",
" else:\n",
" values.append(start - (1 - step))\n",
" return values"
],
"id": "61a6b14fef0180ad",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"beta_5_85 = deg_range(5, 85, 5)\n",
"lambda_5_85 = deg_range(5, 85, 5)\n",
"beta_5_90 = deg_range(5, 90, 5)\n",
"lambda_5_90 = deg_range(5, 90, 5)\n",
"beta_0_90 = deg_range(0, 90, 5)\n",
"lambda_0_90 = deg_range(0, 90, 5)\n",
"beta_90 = [90.0]\n",
"lambda_90 = [90.0]\n",
"beta_0 = [0.0]\n",
"lambda_0 = [0.0]\n",
"beta_asym_89 = asymptotic_range(89.0, direction=\"up\")\n",
"lambda_asym_0 = asymptotic_range(1.0, direction=\"down\")"
],
"id": "f7184980a4b930b7",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"groups = {\n",
" 1: list(product(beta_5_85, lambda_5_85)),\n",
" 2: list(product(beta_0, lambda_0_90)),\n",
" 3: list(product(beta_5_85, lambda_0)),\n",
" 4: list(product(beta_90, lambda_5_90)),\n",
" 5: list(product(beta_asym_89, lambda_asym_0)),\n",
" 6: list(product(beta_5_85, lambda_90)),\n",
" 7: list(product(lambda_asym_0, lambda_0_90)),\n",
" 8: list(product(beta_0_90, lambda_asym_0)),\n",
" 9: list(product(beta_asym_89, lambda_0_90)),\n",
" 10: list(product(beta_0_90, beta_asym_89)),\n",
"}"
],
"id": "cea9fd9cce6a4fd1",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"for nr, points in groups.items():\n",
" points_cart = []\n",
" for point in points:\n",
" beta, lamb = point\n",
" cart = ell.ell2cart(wu.deg2rad(beta), wu.deg2rad(lamb))\n",
" points_cart.append(cart)\n",
" groups[nr] = points_cart"
],
"id": "17a6a130782a89ce",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"results = {}\n",
"\n",
"for nr, points in groups.items():\n",
" group_results = {\"ell\": [],\n",
" \"para\": [],\n",
" \"geod\": []}\n",
" for point in points:\n",
" elli = ell.cart2ell(point)\n",
" cart_elli = ell.ell2cart(elli[0], elli[1])\n",
" group_results[\"ell\"].append(np.linalg.norm(point - cart_elli, axis=-1))\n",
"\n",
" para = ell.cart2para(point)\n",
" cart_para = ell.para2cart(para[0], para[1])\n",
" group_results[\"para\"].append(np.linalg.norm(point - cart_para, axis=-1))\n",
"\n",
" geod = ell.cart2geod(point, \"ligas3\")\n",
" cart_geod = ell.geod2cart(geod[0], geod[1], geod[2])\n",
" group_results[\"geod\"].append(np.linalg.norm(point - cart_geod, axis=-1))\n",
"\n",
" group_results[\"ell\"] = np.array(group_results[\"ell\"])\n",
" group_results[\"para\"] = np.array(group_results[\"para\"])\n",
" group_results[\"geod\"] = np.array(group_results[\"geod\"])\n",
" results[nr] = group_results"
],
"id": "c3298ea233bca274",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"# with open(f\"conversion_results_{ellips}.pkl\", \"wb\") as f:\n",
"# pickle.dump(results, f)"
],
"id": "e1285860be416ad3",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"# with open(f\"conversion_results_{ellips}.pkl\", \"rb\") as f:\n",
"# results = pickle.load(f)"
],
"id": "d26720e34595ccbc",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"df = pd.DataFrame({\n",
" \"Gruppe\": [nr for nr in results.keys()],\n",
" \"max_Δr_ell\": [f\"{max(result[\"ell\"]):.3g}\" for result in results.values()],\n",
" \"max_Δr_para\": [f\"{max(result[\"para\"]):.3g}\" for result in results.values()],\n",
" \"max_Δr_geod\": [f\"{max(result[\"geod\"]):.3g}\" for result in results.values()]\n",
"})"
],
"id": "4e2e55e4699ec81e",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
"source": [
"fig = go.Figure(data=[go.Table(\n",
" header=dict(\n",
" values=list(df.columns),\n",
" fill_color=\"lightgrey\",\n",
" align=\"left\"\n",
" ),\n",
" cells=dict(\n",
" values=[df[col] for col in df.columns],\n",
" align=\"left\"\n",
" )\n",
")])\n",
"fig.update_layout(\n",
" template=\"simple_white\",\n",
" width=650,\n",
" height=len(groups)*20+80,\n",
" margin=dict(l=20, r=20, t=20, b=20))\n",
"\n",
"fig.show()\n",
"# fig.write_image(f\"conversion_results_{ellips}.png\", width=650, height=len(groups)*20+80, scale=2)"
],
"id": "c2fa82afef2d6e0e",
"outputs": [],
"execution_count": null
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@@ -0,0 +1,126 @@
from typing import Tuple
import numpy as np
from numpy import arctan2, cos, sin, sqrt
from numpy.typing import NDArray
import winkelumrechnungen as wu
class EllipsoidBiaxial:
"""
Klasse für Rotationsellipdoide
"""
def __init__(self, a: float, b: float):
self.a = a
self.b = b
self.c = a ** 2 / b
self.e = sqrt(a ** 2 - b ** 2) / a
self.e_ = sqrt(a ** 2 - b ** 2) / b
@classmethod
def init_name(cls, name: str) -> EllipsoidBiaxial:
"""
Erstellen eines Rotationsellipdoids nach Namen
:param name: Name des Rotationsellipsoids
:return: Rotationsellipsoid
"""
if name == "Bessel":
a = 6377397.15508
b = 6356078.96290
return cls(a, b)
elif name == "Hayford":
a = 6378388
f = 1/297
b = a - a * f
return cls(a, b)
elif name == "Krassowski":
a = 6378245
f = 298.3
b = a - a * f
return cls(a, b)
elif name == "WGS84":
a = 6378137
f = 298.257223563
b = a - a * f
return cls(a, b)
else:
raise Exception(f"EllipsoidBiaxial.init_name: Name {name} unbekannt")
@classmethod
def init_af(cls, a: float, f: float) -> EllipsoidBiaxial:
"""
Erstellen eines Rotationsellipdoids aus der großen Halbachse und der Abplattung
:param a: große Halbachse
:param f: großen Halbachse
:return: Rotationsellipsoid
"""
b = a - a * f
return cls(a, b)
V = lambda self, phi: sqrt(1 + self.e_ ** 2 * cos(phi) ** 2)
M = lambda self, phi: self.c / self.V(phi) ** 3
N = lambda self, phi: self.c / self.V(phi)
beta2psi = lambda self, beta: arctan2(self.a * sin(beta), self.b * cos(beta))
beta2phi = lambda self, beta: arctan2(self.a ** 2 * sin(beta), self.b ** 2 * cos(beta))
psi2beta = lambda self, psi: arctan2(self.b * sin(psi), self.a * cos(psi))
psi2phi = lambda self, psi: arctan2(self.a * sin(psi), self.b * cos(psi))
phi2beta = lambda self, phi: arctan2(self.b**2 * sin(phi), self.a**2 * cos(phi))
phi2psi = lambda self, phi: arctan2(self.b * sin(phi), self.a * cos(phi))
phi2p = lambda self, phi: self.N(phi) * cos(phi)
def bi_cart2ell(self, point: NDArray, Eh: float = 0.001, Ephi: float = wu.gms2rad([0, 0, 0.001])) -> Tuple[float, float, float]:
"""
Umrechnung von kartesischen in ellipsoidische Koordinaten auf einem Rotationsellipsoid
# TODO: Quelle
:param point: Punkt in kartesischen Koordinaten
:param Eh: Grenzwert für die Höhe
:param Ephi: Grenzwert für die Breite
:return: ellipsoidische Breite, Länge, geodätische Höhe
"""
x, y, z = point
lamb = arctan2(y, x)
p = sqrt(x**2+y**2)
phi_null = arctan2(z, p*(1 - self.e**2))
hi = [0]
phii = [phi_null]
i = 0
while True:
N = self.a / sqrt(1 - self.e**2 * sin(phii[i])**2)
h = p / cos(phii[i]) - N
phi = arctan2(z, p * (1-(self.e**2*N) / (N+h)))
hi.append(h)
phii.append(phi)
dh = abs(hi[i]-h)
dphi = abs(phii[i]-phi)
i += 1
if dh < Eh:
if dphi < Ephi:
break
return phi, lamb, h
def bi_ell2cart(self, phi: float, lamb: float, h: float) -> NDArray:
"""
Umrechnung von ellipsoidischen in kartesische Koordinaten auf einem Rotationsellipsoid
# TODO: Quelle
:param phi: ellipsoidische Breite
:param lamb: ellipsoidische Länge
:param h: geodätische Höhe
:return: Punkt in kartesischen Koordinaten
"""
W = sqrt(1 - self.e**2 * sin(phi)**2)
N = self.a / W
x = (N+h) * cos(phi) * cos(lamb)
y = (N+h) * cos(phi) * sin(lamb)
z = (N * (1-self.e**2) + h) * sin(phi)
return np.array([x, y, z])

100
nicht abgeben/kugel.py Normal file
View File

@@ -0,0 +1,100 @@
from typing import Tuple
import numpy as np
from numpy import arccos, arcsin, arctan2, cos, pi, sin, sqrt
from numpy.typing import NDArray
import winkelumrechnungen as wu
def cart2sph(point: NDArray) -> Tuple[float, float, float]:
"""
Umrechnung von kartesischen in sphärische Koordinaten
# TODO: Quelle
:param point: Punkt in kartesischen Koordinaten
:return: Radius, Breite, Länge
"""
x, y, z = point
r = sqrt(x**2 + y**2 + z**2)
phi = arctan2(z, sqrt(x**2 + y**2))
lamb = arctan2(y, x)
return r, phi, lamb
def sph2cart(r: float, phi: float, lamb: float) -> NDArray:
"""
Umrechnung von sphärischen in kartesische Koordinaten
# TODO: Quelle
:param r: Radius
:param phi: Breite
:param lamb: Länge
:return: Punkt in kartesischen Koordinaten
"""
x = r * cos(phi) * cos(lamb)
y = r * cos(phi) * sin(lamb)
z = r * sin(phi)
return np.array([x, y, z])
def gha1(R: float, phi0: float, lamb0: float, s: float, alpha0: float) -> Tuple[float, float]:
"""
Berechnung der 1. GHA auf der Kugel
# TODO: Quelle
:param R: Radius
:param phi0: Breite des Startpunktes
:param lamb0: Länge des Startpunktes
:param s: Strecke
:param alpha0: Azimut
:return: Breite, Länge des Zielpunktes
"""
s_ = s / R
lamb1 = lamb0 + arctan2(sin(s_) * sin(alpha0),
cos(phi0) * cos(s_) - sin(phi0) * sin(s_) * cos(alpha0))
phi1 = arcsin(sin(phi0) * cos(s_) + cos(phi0) * sin(s_) * cos(alpha0))
return phi1, lamb1
def gha2(R: float, phi0: float, lamb0: float, phi1: float, lamb1: float) -> Tuple[float, float, float]:
"""
Berechnung der 2. GHA auf der Kugel
# TODO: Quelle
:param R: Radius
:param phi0: Breite des Startpunktes
:param lamb0: Länge des Startpunktes
:param phi1: Breite des Zielpunktes
:param lamb1: Länge des Zielpunktes
:return: Azimut im Startpunkt, Azimut im Zielpunkt, Strecke
"""
s_ = arccos(sin(phi0) * sin(phi1) + cos(phi0) * cos(phi1) * cos(lamb1 - lamb0))
s = R * s_
alpha0 = arctan2(cos(phi1) * sin(lamb1 - lamb0),
cos(phi0) * sin(phi1) - sin(phi0) * cos(phi1) * cos(lamb1 - lamb0))
alpha1 = arctan2(-cos(phi0) * sin(lamb1 - lamb0),
cos(phi1) * sin(phi0) - sin(phi1) * cos(phi0) * cos(lamb1 - lamb0))
if alpha1 < 0:
alpha1 += 2 * pi
return alpha0, alpha1, s
if __name__ == "__main__":
R = 6378815.904 # Bern
phi0 = wu.deg2rad(10)
lamb0 = wu.deg2rad(40)
alpha0 = wu.deg2rad(100)
s = 10000
phi1, lamb1 = gha1(R, phi0, lamb0, s, alpha0)
alpha0_g, alpha1, s_g = gha2(R, phi0, lamb0, phi1, lamb1)
phi1 = wu.rad2deg(phi1)
lamb1 = wu.rad2deg(lamb1)
alpha0_g = wu.rad2deg(alpha0_g)
alpha1 = wu.rad2deg(alpha1)
pass

3654
nicht abgeben/plots.ipynb Normal file

File diff suppressed because one or more lines are too long

8
nicht abgeben/test.py Normal file
View File

@@ -0,0 +1,8 @@
import numpy as np
import ellipsoid_triaxial
ell = ellipsoid_triaxial.EllipsoidTriaxial.init_name("KarneyTest2024")
cart = ell.para2cart(0, np.pi/2)
print(cart)

7
requirements.txt Normal file
View File

@@ -0,0 +1,7 @@
numpy~=2.3.4
plotly~=6.4.0
pandas~=2.3.3
scipy~=1.16.3
dash-bootstrap-components~=2.0.4
dash~=4.0.0
matplotlib~=3.10.7

View File

@@ -1,7 +1,10 @@
from typing import Callable
import numpy as np import numpy as np
from numpy.typing import NDArray
def rk4(ode, t0: float, v0: np.ndarray, weite: float, schritte: int, fein: bool = False) -> tuple[list, list]: def rk4(ode: Callable, t0: float, v0: NDArray, weite: float, schritte: int, fein: bool = False) -> tuple[list, list]:
""" """
Standard Runge-Kutta Verfahren 4. Ordnung Standard Runge-Kutta Verfahren 4. Ordnung
:param ode: ODE-System als Funktion :param ode: ODE-System als Funktion
@@ -9,7 +12,7 @@ def rk4(ode, t0: float, v0: np.ndarray, weite: float, schritte: int, fein: bool
:param v0: Startwerte :param v0: Startwerte
:param weite: Integrationsweite :param weite: Integrationsweite
:param schritte: Schrittzahl :param schritte: Schrittzahl
:param fein: :param fein: Fein-Rechnung?
:return: Variable und Funktionswerte an jedem Stützpunkt :return: Variable und Funktionswerte an jedem Stützpunkt
""" """
h = weite/schritte h = weite/schritte
@@ -35,9 +38,118 @@ def rk4(ode, t0: float, v0: np.ndarray, weite: float, schritte: int, fein: bool
return t_list, werte return t_list, werte
def rk4_step(ode, t: float, v: np.ndarray, h: float) -> np.ndarray: def rk4_step(ode: Callable, t: float, v: NDArray, h: float) -> NDArray:
"""
Ein Schritt des Runge-Kutta Verfahrens 4. Ordnung
:param ode: ODE-System als Funktion
:param t: unabhängige Variable
:param v: abhängige Variablen
:param h: Schrittweite
:return: abhängige Variablen nach einem Schritt
"""
k1 = ode(t, v) k1 = ode(t, v)
k2 = ode(t + 0.5 * h, v + 0.5 * h * k1) k2 = ode(t + 0.5 * h, v + 0.5 * h * k1)
k3 = ode(t + 0.5 * h, v + 0.5 * h * k2) k3 = ode(t + 0.5 * h, v + 0.5 * h * k2)
k4 = ode(t + h, v + h * k3) k4 = ode(t + h, v + h * k3)
return v + (h / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4) return v + (h / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4)
def rk4_end(ode: Callable, t0: float, v0: NDArray, weite: float, schritte: int, fein: bool = False):
"""
Standard Runge-Kutta Verfahren 4. Ordnung, nur Ausgabe der letzten Variablenwerte
:param ode: ODE-System als Funktion
:param t0: Startwert der unabhängigen Variable
:param v0: Startwerte
:param weite: Integrationsweite
:param schritte: Schrittzahl
:param fein: Fein-Rechnung?
:return: Variable und Funktionswerte am letzten Stützpunkt
"""
h = weite / schritte
t = float(t0)
v = np.array(v0, dtype=float, copy=True)
for _ in range(schritte):
if not fein:
v_next = rk4_step(ode, t, v, h)
else:
v_grob = rk4_step(ode, t, v, h)
v_half = rk4_step(ode, t, v, 0.5 * h)
v_fein = rk4_step(ode, t + 0.5 * h, v_half, 0.5 * h)
v_next = v_fein + (v_fein - v_grob) / 15.0
t += h
v = v_next
return t, v
# RK4 mit Simpson bzw. Trapez
def rk4_integral(ode: Callable, t0: float, v0: NDArray, weite: float, schritte: int, integrand_at: Callable, fein: bool = False, simpson: bool = True):
"""
Runge-Kutta Verfahren 4. Ordnung mit Simpson bzw. Trapez
:param ode: ODE-System als Funktion
:param t0: Startwert der unabhängigen Variable
:param v0: Startwerte
:param weite: Integrationsweite
:param integrand_at: Funktion
:param schritte: Schrittzahl
:param fein: Fein-Rechnung?
:param simpson: Simpson? Wenn nein, dann Trapez
:return: Variable und Funktionswerte am letzten Stützpunkt
"""
h = weite / schritte
habs = abs(h)
t = float(t0)
v = np.array(v0, dtype=float, copy=True)
if simpson and (schritte % 2 == 0):
f0 = float(integrand_at(t, v))
odd_sum = 0.0
even_sum = 0.0
fN = None
for i in range(1, schritte + 1):
if not fein:
v_next = rk4_step(ode, t, v, h)
else:
v_grob = rk4_step(ode, t, v, h)
v_half = rk4_step(ode, t, v, 0.5 * h)
v_fein = rk4_step(ode, t + 0.5 * h, v_half, 0.5 * h)
v_next = v_fein + (v_fein - v_grob) / 15.0
t += h
v = v_next
fi = float(integrand_at(t, v))
if i == schritte:
fN = fi
elif i % 2 == 1:
odd_sum += fi
else:
even_sum += fi
S = f0 + fN + 4.0 * odd_sum + 2.0 * even_sum
s = (habs / 3.0) * S
return t, v, s
f_prev = float(integrand_at(t, v))
acc = 0.0
for _ in range(schritte):
if not fein:
v_next = rk4_step(ode, t, v, h)
else:
v_grob = rk4_step(ode, t, v, h)
v_half = rk4_step(ode, t, v, 0.5 * h)
v_fein = rk4_step(ode, t + 0.5 * h, v_half, 0.5 * h)
v_next = v_fein + (v_fein - v_grob) / 15.0
t += h
v = v_next
f_cur = float(integrand_at(t, v))
acc += 0.5 * (f_prev + f_cur)
f_prev = f_cur
s = habs * acc
return t, v, s

14
test.py
View File

@@ -1,14 +0,0 @@
import numpy as np
from scipy.special import factorial as fact
from math import comb
import matplotlib.pyplot as plt
import ellipsoide
from GHA_triaxial.panou import pq
ell = ellipsoide.EllipsoidTriaxial.init_name("Eitschberger1978")
x, y, z = ell.para2cart(0.5, 0.7)
x1 = pq(ell, x, y, z)
x2 = ell.p_q(x, y, z)
pass

View File

@@ -1,21 +0,0 @@
from numpy import arctan2
from numpy.typing import NDArray
from GHA_triaxial.panou import pq_ell
from ellipsoide import EllipsoidTriaxial
def sigma2alpha(ell: EllipsoidTriaxial, sigma: NDArray, point: NDArray) -> float:
"""
Berechnung des Richtungswinkels an einem Punkt anhand der Ableitung zu den kartesischen Koordinaten
:param ell: Ellipsoid
:param sigma: Ableitungsvektor ver kartesischen Koordinaten
:param point: Punkt
:return: Richtungswinkel
"""
p, q = pq_ell(ell, point)
P = float(p @ sigma)
Q = float(q @ sigma)
alpha = arctan2(P, Q)
return alpha

54
utils_angle.py Normal file
View File

@@ -0,0 +1,54 @@
import numpy as np
import winkelumrechnungen as wu
def arccot(x: float) -> float:
"""
Berechnung von arccot eines Winkels
:param x: Winkel
:return: arccot(Winkel)
"""
return np.arctan2(1.0, x)
def cot(x: float) -> float:
"""
Berechnung von cot eines Winkels
:param x: Winkel
:return: cot(Winkel)
"""
return np.cos(x) / np.sin(x)
def wrap_mpi_pi(x: float) -> float:
"""
Wrap eines Winkels in den Wertebereich [-π, π)
:param x: Winkel
:return: Winkel in [-π, π)
"""
return (x + np.pi) % (2 * np.pi) - np.pi
def wrap_mhalfpi_halfpi(x: float) -> float:
"""
Wrap eines Winkels in den Wertebereich [-π/2, π/2)
:param x: Winkel
:return: Winkel in [-π/2, π/2)
"""
return (x + np.pi / 2) % np.pi - np.pi / 2
def wrap_0_2pi(x: float) -> float:
"""
Wrap eines Winkels in den Wertebereich [0, 2π)
:param x: Winkel
:return: Winkel in [0, 2π)
"""
return x % (2 * np.pi)
if __name__ == "__main__":
print(wu.rad2deg(wrap_mhalfpi_halfpi(wu.deg2rad(181))))
print(wu.rad2deg(wrap_0_2pi(wu.deg2rad(181))))
print(wu.rad2deg(wrap_mpi_pi(wu.deg2rad(181))))