Source code for pytcl.magnetism.igrf

"""
International Geomagnetic Reference Field (IGRF) implementation.

The IGRF is a standard mathematical description of the Earth's main
magnetic field, used widely in studies of the Earth's interior,
its ionosphere and magnetosphere, and in various applications.

References
----------
- Alken et al., "International Geomagnetic Reference Field: the
  thirteenth generation," Earth, Planets and Space, 2021.
- https://www.ngdc.noaa.gov/IAGA/vmod/igrf.html
"""

import warnings
from typing import NamedTuple, Optional

import numpy as np

from pytcl.magnetism.wmm import (
    MagneticCoefficients,
    MagneticResult,
    wmm,
)


[docs] class IGRFModel(NamedTuple): """IGRF model for a specific epoch. Attributes ---------- epoch : float Reference epoch year. coeffs : MagneticCoefficients Spherical harmonic coefficients. valid_from : float Start of validity period. valid_to : float End of validity period. """ epoch: float coeffs: MagneticCoefficients valid_from: float valid_to: float
# Official IGRF-13 coefficients for epoch 2020.0 with 2020-2025 secular # variation, extracted from the IAGA igrf13coeffs.txt distribution file: # columns are n, m, g (nT), h (nT), g_dot (nT/yr), h_dot (nT/yr) _IGRF13_2020_COF = """\ 1 0 -29404.8 0.0 5.7 0.0 1 1 -1450.9 4652.5 7.4 -25.9 2 0 -2499.6 0.0 -11.0 0.0 2 1 2982.0 -2991.6 -7.0 -30.2 2 2 1677.0 -734.6 -2.1 -22.4 3 0 1363.2 0.0 2.2 0.0 3 1 -2381.2 -82.1 -5.9 6.0 3 2 1236.2 241.9 3.1 -1.1 3 3 525.7 -543.4 -12.0 0.5 4 0 903.0 0.0 -1.2 0.0 4 1 809.5 281.9 -1.6 -0.1 4 2 86.3 -158.4 -5.9 6.5 4 3 -309.4 199.7 5.2 3.6 4 4 48.0 -349.7 -5.1 -5.0 5 0 -234.3 0.0 -0.3 0.0 5 1 363.2 47.7 0.5 0.0 5 2 187.8 208.3 -0.6 2.5 5 3 -140.7 -121.2 0.2 -0.6 5 4 -151.2 32.3 1.3 3.0 5 5 13.5 98.9 0.9 0.3 6 0 66.0 0.0 -0.5 0.0 6 1 65.5 -19.1 -0.3 0.0 6 2 72.9 25.1 0.4 -1.6 6 3 -121.5 52.8 1.3 -1.3 6 4 -36.2 -64.5 -1.4 0.8 6 5 13.5 8.9 0.0 0.0 6 6 -64.7 68.1 0.9 1.0 7 0 80.6 0.0 -0.1 0.0 7 1 -76.7 -51.5 -0.2 0.6 7 2 -8.2 -16.9 0.0 0.6 7 3 56.5 2.2 0.7 -0.8 7 4 15.8 23.5 0.1 -0.2 7 5 6.4 -2.2 -0.5 -1.1 7 6 -7.2 -27.2 -0.8 0.1 7 7 9.8 -1.8 0.8 0.3 8 0 23.7 0.0 0.0 0.0 8 1 9.7 8.4 0.1 -0.2 8 2 -17.6 -15.3 -0.1 0.6 8 3 -0.5 12.8 0.4 -0.2 8 4 -21.1 -11.7 -0.1 0.5 8 5 15.3 14.9 0.4 -0.3 8 6 13.7 3.6 0.3 -0.4 8 7 -16.5 -6.9 -0.1 0.5 8 8 -0.3 2.8 0.4 0.0 9 0 5.0 0.0 0.0 0.0 9 1 8.4 -23.4 0.0 0.0 9 2 2.9 11.0 0.0 0.0 9 3 -1.5 9.8 0.0 0.0 9 4 -1.1 -5.1 0.0 0.0 9 5 -13.2 -6.3 0.0 0.0 9 6 1.1 7.8 0.0 0.0 9 7 8.8 0.4 0.0 0.0 9 8 -9.3 -1.4 0.0 0.0 9 9 -11.9 9.6 0.0 0.0 10 0 -1.9 0.0 0.0 0.0 10 1 -6.2 3.4 0.0 0.0 10 2 -0.1 -0.2 0.0 0.0 10 3 1.7 3.6 0.0 0.0 10 4 -0.9 4.8 0.0 0.0 10 5 0.7 -8.6 0.0 0.0 10 6 -0.9 -0.1 0.0 0.0 10 7 1.9 -4.3 0.0 0.0 10 8 1.4 -3.4 0.0 0.0 10 9 -2.4 -0.1 0.0 0.0 10 10 -3.8 -8.8 0.0 0.0 11 0 3.0 0.0 0.0 0.0 11 1 -1.4 0.0 0.0 0.0 11 2 -2.5 2.5 0.0 0.0 11 3 2.3 -0.6 0.0 0.0 11 4 -0.9 -0.4 0.0 0.0 11 5 0.3 0.6 0.0 0.0 11 6 -0.7 -0.2 0.0 0.0 11 7 -0.1 -1.7 0.0 0.0 11 8 1.4 -1.6 0.0 0.0 11 9 -0.6 -3.0 0.0 0.0 11 10 0.2 -2.0 0.0 0.0 11 11 3.1 -2.6 0.0 0.0 12 0 -2.0 0.0 0.0 0.0 12 1 -0.1 -1.2 0.0 0.0 12 2 0.5 0.5 0.0 0.0 12 3 1.3 1.4 0.0 0.0 12 4 -1.2 -1.8 0.0 0.0 12 5 0.7 0.1 0.0 0.0 12 6 0.3 0.8 0.0 0.0 12 7 0.5 -0.2 0.0 0.0 12 8 -0.3 0.6 0.0 0.0 12 9 -0.5 0.2 0.0 0.0 12 10 0.1 -0.9 0.0 0.0 12 11 -1.1 0.0 0.0 0.0 12 12 -0.3 0.5 0.0 0.0 13 0 0.1 0.0 0.0 0.0 13 1 -0.9 -0.9 0.0 0.0 13 2 0.5 0.6 0.0 0.0 13 3 0.7 1.4 0.0 0.0 13 4 -0.3 -0.4 0.0 0.0 13 5 0.8 -1.3 0.0 0.0 13 6 0.0 -0.1 0.0 0.0 13 7 0.8 0.3 0.0 0.0 13 8 0.0 -0.1 0.0 0.0 13 9 0.4 0.5 0.0 0.0 13 10 0.1 0.5 0.0 0.0 13 11 0.5 -0.4 0.0 0.0 13 12 -0.5 -0.4 0.0 0.0 13 13 -0.4 -0.6 0.0 0.0 """
[docs] def create_igrf13_coefficients() -> MagneticCoefficients: """ Create IGRF-13 model coefficients for epoch 2020. Returns ------- coeffs : MagneticCoefficients IGRF-13 spherical harmonic coefficients (epoch 2020.0, with 2020-2025 secular variation), embedded verbatim from the official IAGA igrf13coeffs.txt distribution. Examples -------- >>> coeffs = create_igrf13_coefficients() >>> coeffs.epoch 2020.0 >>> coeffs.n_max 13 Notes ----- IGRF-13 is valid from 1900.0 to 2025.0. This function returns the coefficients for the 2020.0 epoch; for earlier epochs the historical tables should be interpolated. IGRF-13's validity window ends 2025.0 and it is superseded by :func:`create_igrf14_coefficients` / ``IGRF14``, the default for :func:`igrf` since v2.8.0. IGRF-13 is retained for reproducibility of results computed against it. Calls with ``year`` beyond 2025.0 extrapolate the 2020-2025 secular variation (``g_dot``/``h_dot``) linearly past the model's official range -- treat results for ``year > 2025.0`` as an unofficial extrapolation, not IGRF-13 output. """ n_max = 13 g = np.zeros((n_max + 1, n_max + 1)) h = np.zeros((n_max + 1, n_max + 1)) g_dot = np.zeros((n_max + 1, n_max + 1)) h_dot = np.zeros((n_max + 1, n_max + 1)) for line in _IGRF13_2020_COF.strip().split("\n"): n_s, m_s, g_s, h_s, gd_s, hd_s = line.split() n, m = int(n_s), int(m_s) g[n, m] = float(g_s) h[n, m] = float(h_s) g_dot[n, m] = float(gd_s) h_dot[n, m] = float(hd_s) return MagneticCoefficients( g=g, h=h, g_dot=g_dot, h_dot=h_dot, epoch=2020.0, n_max=n_max )
IGRF13 = create_igrf13_coefficients() # The complete 14th-generation IAGA distribution file igrf14coeffs.txt, # embedded verbatim (all epochs 1900.0-2025.0 plus the 2025-30 secular # variation). Retrieved 2026-08-26 from # https://www.ngdc.noaa.gov/IAGA/vmod/coeffs/igrf14coeffs.txt; the copy in # tests/fixtures/magnetism/ pins its sha256 and the validation suite checks # this constant against it byte for byte. _IGRF14_COF = """\ # 14th Generation International Geomagnetic Reference Field Schmidt semi-normalised spherical harmonic coefficients, degree n=1,13 # in units nanoTesla for IGRF and definitive DGRF main-field models (degree n=1,8 nanoTesla/year for secular variation (SV)) c/s deg ord IGRF IGRF IGRF IGRF IGRF IGRF IGRF IGRF IGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF DGRF IGRF SV g/h n m 1900.0 1905.0 1910.0 1915.0 1920.0 1925.0 1930.0 1935.0 1940.0 1945.0 1950.0 1955.0 1960.0 1965.0 1970.0 1975.0 1980.0 1985.0 1990.0 1995.0 2000.0 2005.0 2010.0 2015.0 2020.0 2025.0 2025-30 g 1 0 -31543 -31464 -31354 -31212 -31060 -30926 -30805 -30715 -30654 -30594 -30554 -30500 -30421 -30334 -30220 -30100 -29992 -29873 -29775 -29692 -29619.4 -29554.63 -29496.57 -29441.46 -29403.41 -29350.0 12.6 g 1 1 -2298 -2298 -2297 -2306 -2317 -2318 -2316 -2306 -2292 -2285 -2250 -2215 -2169 -2119 -2068 -2013 -1956 -1905 -1848 -1784 -1728.2 -1669.05 -1586.42 -1501.77 -1451.37 -1410.3 10.0 h 1 1 5922 5909 5898 5875 5845 5817 5808 5812 5821 5810 5815 5820 5791 5776 5737 5675 5604 5500 5406 5306 5186.1 5077.99 4944.26 4795.99 4653.35 4545.5 -21.5 g 2 0 -677 -728 -769 -802 -839 -893 -951 -1018 -1106 -1244 -1341 -1440 -1555 -1662 -1781 -1902 -1997 -2072 -2131 -2200 -2267.7 -2337.24 -2396.06 -2445.88 -2499.78 -2556.2 -11.2 g 2 1 2905 2928 2948 2956 2959 2969 2980 2984 2981 2990 2998 3003 3002 2997 3000 3010 3027 3044 3059 3070 3068.4 3047.69 3026.34 3012.20 2981.96 2950.9 -5.3 h 2 1 -1061 -1086 -1128 -1191 -1259 -1334 -1424 -1520 -1614 -1702 -1810 -1898 -1967 -2016 -2047 -2067 -2129 -2197 -2279 -2366 -2481.6 -2594.50 -2708.54 -2845.41 -2991.72 -3133.6 -27.3 g 2 2 924 1041 1176 1309 1407 1471 1517 1550 1566 1578 1576 1581 1590 1594 1611 1632 1663 1687 1686 1681 1670.9 1657.76 1668.17 1676.35 1676.85 1648.7 -8.3 h 2 2 1121 1065 1000 917 823 728 644 586 528 477 381 291 206 114 25 -68 -200 -306 -373 -413 -458.0 -515.43 -575.73 -642.17 -734.62 -814.2 -11.1 g 3 0 1022 1037 1058 1084 1111 1140 1172 1206 1240 1282 1297 1302 1302 1297 1287 1276 1281 1296 1314 1335 1339.6 1336.30 1339.85 1350.33 1363.00 1360.9 -1.5 g 3 1 -1469 -1494 -1524 -1559 -1600 -1645 -1692 -1740 -1790 -1834 -1889 -1944 -1992 -2038 -2091 -2144 -2180 -2208 -2239 -2267 -2288.0 -2305.83 -2326.54 -2352.26 -2380.80 -2404.2 -4.4 h 3 1 -330 -357 -389 -421 -445 -462 -480 -494 -499 -499 -476 -462 -414 -404 -366 -333 -336 -310 -284 -262 -227.6 -198.86 -160.40 -115.29 -81.96 -56.9 3.8 g 3 2 1256 1239 1223 1212 1205 1202 1205 1215 1232 1255 1274 1288 1289 1292 1278 1260 1251 1247 1248 1249 1252.1 1246.39 1232.10 1225.85 1236.06 1243.8 0.4 h 3 2 3 34 62 84 103 119 133 146 163 186 206 216 224 240 251 262 271 284 293 302 293.4 269.72 251.75 245.04 241.80 237.6 -0.2 g 3 3 572 635 705 778 839 881 907 918 916 913 896 882 878 856 838 830 833 829 802 759 714.5 672.51 633.73 581.69 525.60 453.4 -15.6 h 3 3 523 480 425 360 293 229 166 101 43 -11 -46 -83 -130 -165 -196 -223 -252 -297 -352 -427 -491.1 -524.72 -537.03 -538.70 -542.52 -549.6 -3.9 g 4 0 876 880 884 887 889 891 896 903 914 944 954 958 957 957 952 946 938 936 939 940 932.3 920.55 912.66 907.42 902.82 894.7 -1.7 g 4 1 628 643 660 678 695 711 727 744 762 776 792 796 800 804 800 791 782 780 780 780 786.8 797.96 808.97 813.68 809.47 799.6 -2.3 h 4 1 195 203 211 218 220 216 205 188 169 144 136 133 135 148 167 191 212 232 247 262 272.6 282.07 286.48 283.54 282.10 278.6 -1.3 g 4 2 660 653 644 631 616 601 584 565 550 544 528 510 504 479 461 438 398 361 325 290 250.0 210.65 166.58 120.49 86.18 55.8 -5.8 h 4 2 -69 -77 -90 -109 -134 -163 -195 -226 -252 -276 -278 -274 -278 -269 -266 -265 -257 -249 -240 -236 -231.9 -225.23 -211.03 -188.43 -158.50 -134.0 4.1 g 4 3 -361 -380 -400 -416 -424 -426 -422 -415 -405 -421 -408 -397 -394 -390 -395 -405 -419 -424 -423 -418 -403.0 -379.86 -356.83 -334.85 -309.47 -281.1 5.4 h 4 3 -210 -201 -189 -173 -153 -130 -109 -90 -72 -55 -37 -23 3 13 26 39 53 69 84 97 119.8 145.15 164.46 180.95 199.75 212.0 1.6 g 4 4 134 146 160 178 199 217 234 249 265 304 303 290 269 252 234 216 199 170 141 122 111.3 100.00 89.40 70.38 47.44 12.0 -6.8 h 4 4 -75 -65 -55 -51 -57 -70 -90 -114 -141 -178 -210 -230 -255 -269 -279 -288 -297 -297 -299 -306 -303.8 -305.36 -309.72 -329.23 -350.30 -375.4 -4.1 g 5 0 -184 -192 -201 -211 -221 -230 -237 -241 -241 -253 -240 -229 -222 -219 -216 -218 -218 -214 -214 -214 -218.8 -227.00 -230.87 -232.91 -234.42 -232.9 0.6 g 5 1 328 328 327 327 326 326 327 329 334 346 349 360 362 358 359 356 357 355 353 352 351.4 354.41 357.29 360.14 363.26 369.0 1.3 h 5 1 -210 -193 -172 -148 -122 -96 -72 -51 -33 -12 3 15 16 19 26 31 46 47 46 46 43.8 42.72 44.58 46.98 47.52 45.3 -0.5 g 5 2 264 259 253 245 236 226 218 211 208 194 211 230 242 254 262 264 261 253 245 235 222.3 208.95 200.26 192.35 187.86 187.2 0.0 h 5 2 53 56 57 58 58 58 60 64 71 95 103 110 125 128 139 148 150 150 154 165 171.9 180.25 189.01 196.98 208.36 220.0 2.1 g 5 3 5 -1 -9 -16 -23 -28 -32 -33 -33 -20 -20 -23 -26 -31 -42 -59 -74 -93 -109 -118 -130.4 -136.54 -141.05 -140.94 -140.73 -138.7 0.7 h 5 3 -33 -32 -33 -34 -38 -44 -53 -64 -75 -67 -87 -98 -117 -126 -139 -152 -151 -154 -153 -143 -133.1 -123.45 -118.06 -119.14 -121.43 -122.9 0.5 g 5 4 -86 -93 -102 -111 -119 -125 -131 -136 -141 -142 -147 -152 -156 -157 -160 -159 -162 -164 -165 -166 -168.6 -168.05 -163.17 -157.40 -151.16 -141.9 2.3 h 5 4 -124 -125 -126 -126 -125 -122 -118 -115 -113 -119 -122 -121 -114 -97 -91 -83 -78 -75 -69 -55 -39.3 -19.57 -0.01 15.98 32.09 42.9 1.7 g 5 5 -16 -26 -38 -51 -62 -69 -74 -76 -76 -82 -76 -69 -63 -62 -56 -49 -48 -46 -36 -17 -12.9 -13.55 -8.03 4.30 13.98 20.9 1.0 h 5 5 3 11 21 32 43 51 58 64 69 82 80 78 81 81 83 88 92 95 97 107 106.3 103.85 101.04 100.12 99.14 106.2 1.9 g 6 0 63 62 62 61 61 61 60 59 57 59 54 47 46 45 43 45 48 53 61 68 72.3 73.60 72.78 69.55 65.97 64.3 -0.2 g 6 1 61 60 58 57 55 54 53 53 54 57 57 57 58 61 64 66 66 65 65 67 68.2 69.56 68.69 67.57 65.56 63.8 -0.3 h 6 1 -9 -7 -5 -2 0 3 4 4 4 6 -1 -9 -10 -11 -12 -13 -15 -16 -16 -17 -17.4 -20.33 -20.90 -20.61 -19.22 -18.4 0.3 g 6 2 -11 -11 -11 -10 -10 -9 -9 -8 -7 6 4 3 1 8 15 28 42 51 59 68 74.2 76.74 75.92 72.79 72.96 76.7 0.8 h 6 2 83 86 89 93 96 99 102 104 105 100 99 96 99 100 100 99 93 88 82 72 63.7 54.75 44.18 33.30 25.02 16.8 -1.6 g 6 3 -217 -221 -224 -228 -233 -238 -242 -246 -249 -246 -247 -247 -237 -228 -212 -198 -192 -185 -178 -170 -160.9 -151.34 -141.40 -129.85 -121.57 -115.7 1.2 h 6 3 2 4 5 8 11 14 19 25 33 16 33 48 60 68 72 75 71 69 69 67 65.1 63.63 61.54 58.74 52.76 48.9 -0.4 g 6 4 -58 -57 -54 -51 -46 -40 -32 -25 -18 -25 -16 -8 -1 4 2 1 4 4 3 -1 -5.9 -14.58 -22.83 -28.93 -36.06 -40.9 -0.8 h 6 4 -35 -32 -29 -26 -22 -18 -16 -15 -15 -9 -12 -16 -20 -32 -37 -41 -43 -48 -52 -58 -61.2 -63.53 -66.26 -66.64 -64.40 -59.8 0.8 g 6 5 59 57 54 49 44 39 32 25 18 21 12 7 -2 1 3 6 14 16 18 19 16.9 14.58 13.10 13.14 13.60 14.9 0.4 h 6 5 36 32 28 23 18 13 8 4 0 -16 -12 -12 -11 -8 -6 -4 -2 -1 1 1 0.7 0.24 3.02 7.35 8.96 10.9 0.7 g 6 6 -90 -92 -95 -98 -101 -103 -104 -106 -107 -104 -105 -107 -113 -111 -112 -111 -108 -102 -96 -93 -90.4 -86.36 -78.09 -70.85 -64.80 -60.8 0.9 h 6 6 -69 -67 -65 -62 -57 -52 -46 -40 -33 -39 -30 -24 -17 -7 1 11 17 21 24 36 43.8 50.94 55.40 62.41 68.04 72.8 0.9 g 7 0 70 70 71 72 73 73 74 74 74 70 65 65 67 75 72 71 72 74 77 77 79.0 79.88 80.44 81.29 80.54 79.6 -0.1 g 7 1 -55 -54 -54 -54 -54 -54 -54 -53 -53 -40 -55 -56 -56 -57 -57 -56 -59 -62 -64 -72 -74.0 -74.46 -75.00 -75.99 -76.63 -76.9 -0.1 h 7 1 -45 -46 -47 -48 -49 -50 -51 -52 -52 -45 -35 -50 -55 -61 -70 -77 -82 -83 -80 -69 -64.6 -61.14 -57.80 -54.27 -51.50 -48.9 0.6 g 7 2 0 0 1 2 2 3 4 4 4 0 2 2 5 4 1 1 2 3 2 1 0.0 -1.65 -4.55 -6.79 -8.23 -8.8 -0.1 h 7 2 -13 -14 -14 -14 -14 -14 -15 -17 -18 -18 -17 -24 -28 -27 -27 -26 -27 -27 -26 -25 -24.2 -22.57 -21.20 -19.53 -16.85 -14.4 0.5 g 7 3 34 33 32 31 29 27 25 23 20 0 1 10 15 13 14 16 21 24 26 28 33.3 38.73 45.24 51.82 56.45 59.3 0.5 h 7 3 -10 -11 -12 -12 -13 -14 -14 -14 -14 2 0 -4 -6 -2 -4 -5 -5 -2 0 4 6.2 6.82 6.54 5.59 2.36 -1.0 -0.7 g 7 4 -41 -41 -40 -38 -37 -35 -34 -33 -31 -29 -40 -32 -32 -26 -22 -14 -12 -6 -1 5 9.1 12.30 14.00 15.07 15.80 15.8 -0.1 h 7 4 -1 0 1 2 4 5 6 7 7 6 10 8 7 6 8 10 16 20 21 24 24.0 25.35 24.96 24.45 23.56 23.5 0.0 g 7 5 -21 -20 -19 -18 -16 -14 -12 -11 -9 -10 -7 -11 -7 -6 -2 0 1 4 5 4 6.9 9.37 10.46 9.32 6.30 2.5 -0.8 h 7 5 28 28 28 28 28 29 29 29 29 28 36 28 23 26 23 22 18 17 17 17 14.8 10.93 7.03 3.27 -2.19 -7.4 -0.9 g 7 6 18 18 18 19 19 19 18 18 17 15 5 9 17 13 13 12 11 10 9 8 7.3 5.42 1.64 -2.88 -7.21 -11.2 -0.8 h 7 6 -12 -12 -13 -15 -16 -17 -18 -19 -20 -17 -18 -20 -18 -23 -23 -23 -23 -23 -23 -24 -25.4 -26.32 -27.61 -27.50 -27.19 -25.1 0.5 g 7 7 6 6 6 6 6 6 6 6 5 29 19 18 8 1 -2 -5 -2 0 0 -2 -1.2 1.94 4.92 6.61 9.77 14.3 0.9 h 7 7 -22 -22 -22 -22 -22 -21 -20 -19 -19 -22 -16 -18 -17 -12 -11 -12 -10 -7 -4 -6 -5.8 -4.64 -3.28 -2.32 -1.90 -2.2 -0.3 g 8 0 11 11 11 11 11 11 11 11 11 13 22 11 15 13 14 14 18 21 23 25 24.4 24.80 24.41 23.98 23.66 23.1 -0.1 g 8 1 8 8 8 8 7 7 7 7 7 7 15 9 6 5 6 6 6 6 5 6 6.6 7.62 8.21 8.89 9.74 10.9 0.2 h 8 1 8 8 8 8 8 8 8 8 8 12 5 10 11 7 7 6 7 8 10 11 11.9 11.20 10.84 10.04 8.43 7.2 -0.3 g 8 2 -4 -4 -4 -4 -3 -3 -3 -3 -3 -8 -4 -6 -4 -4 -2 -1 0 0 -1 -6 -9.2 -11.73 -14.50 -16.78 -17.49 -17.5 0.0 h 8 2 -14 -15 -15 -15 -15 -15 -15 -15 -14 -21 -22 -15 -14 -12 -15 -16 -18 -19 -19 -21 -21.5 -20.88 -20.03 -18.26 -15.23 -12.6 0.4 g 8 3 -9 -9 -9 -9 -9 -9 -9 -9 -10 -5 -1 -14 -11 -14 -13 -12 -11 -11 -10 -9 -7.9 -6.88 -5.59 -3.16 -0.49 2.0 0.4 h 8 3 7 7 6 6 6 6 5 5 5 -12 0 5 7 9 6 4 4 5 6 8 8.5 9.83 11.83 13.18 12.83 11.5 -0.3 g 8 4 1 1 1 2 2 2 2 1 1 9 11 6 2 0 -3 -8 -7 -9 -12 -14 -16.6 -18.11 -19.34 -20.56 -21.07 -21.8 -0.1 h 8 4 -13 -13 -13 -13 -14 -14 -14 -15 -15 -7 -21 -23 -18 -16 -17 -19 -22 -23 -22 -23 -21.5 -19.71 -17.41 -14.60 -11.76 -9.7 0.4 g 8 5 2 2 2 3 4 4 5 6 6 7 15 10 10 8 5 4 4 4 3 9 9.1 10.17 11.61 13.33 15.28 16.9 0.3 h 8 5 5 5 5 5 5 5 5 5 5 2 -8 3 4 4 6 6 9 11 12 15 15.5 16.22 16.71 16.16 14.94 12.7 -0.5 g 8 6 -9 -8 -8 -8 -7 -7 -6 -6 -5 -10 -13 -7 -5 -1 0 0 3 4 4 6 7.0 9.36 10.85 11.76 13.65 14.9 0.1 h 8 6 16 16 16 16 17 17 18 18 19 18 17 23 23 24 21 18 16 14 12 11 8.9 7.61 6.96 5.69 3.62 0.7 -0.6 g 8 7 5 5 5 6 6 7 8 8 9 7 5 6 10 11 11 10 6 4 2 -5 -7.9 -11.25 -14.05 -15.98 -16.59 -16.8 0.0 h 8 7 -5 -5 -5 -5 -5 -5 -5 -5 -5 3 -4 -4 1 -3 -6 -10 -13 -15 -16 -16 -14.9 -12.76 -10.74 -9.10 -6.90 -5.2 0.3 g 8 8 8 8 8 8 8 8 8 7 7 2 -1 9 8 4 3 1 -1 -4 -6 -7 -7.0 -4.87 -3.54 -2.02 -0.34 1.0 0.3 h 8 8 -18 -18 -18 -18 -19 -19 -19 -19 -19 -11 -17 -13 -20 -17 -16 -17 -15 -11 -10 -4 -2.1 -0.06 1.64 2.26 2.90 3.9 0.2 g 9 0 8 8 8 8 8 8 8 8 8 5 3 4 4 8 8 7 5 5 4 4 5.0 5.58 5.50 5.33 5.03 4.7 0.0 g 9 1 10 10 10 10 10 10 10 10 10 -21 -7 9 6 10 10 10 10 10 9 9 9.4 9.76 9.45 8.83 8.36 8.0 0.0 h 9 1 -20 -20 -20 -20 -20 -20 -20 -20 -21 -27 -24 -11 -18 -22 -21 -21 -21 -21 -20 -20 -19.7 -20.11 -20.54 -21.77 -23.44 -24.8 0.0 g 9 2 1 1 1 1 1 1 1 1 1 1 -1 -4 0 2 2 2 1 1 1 3 3.0 3.58 3.45 3.02 2.84 3.0 0.0 h 9 2 14 14 14 14 14 14 14 15 15 17 19 12 12 15 16 16 16 15 15 15 13.4 12.69 11.51 10.76 11.04 12.1 0.0 g 9 3 -11 -11 -11 -11 -11 -11 -12 -12 -12 -11 -25 -5 -9 -13 -12 -12 -12 -12 -12 -10 -8.4 -6.94 -5.27 -3.22 -1.48 -0.2 0.0 h 9 3 5 5 5 5 5 5 5 5 5 29 12 7 2 7 6 7 9 9 11 12 12.5 12.67 12.75 11.74 9.86 8.3 0.0 g 9 4 12 12 12 12 12 12 12 11 11 3 10 2 1 10 10 10 9 9 9 8 6.3 5.01 3.13 0.67 -1.14 -2.5 0.0 h 9 4 -3 -3 -3 -3 -3 -3 -3 -3 -3 -9 2 6 0 -4 -4 -4 -5 -6 -7 -6 -6.2 -6.72 -7.14 -6.74 -5.13 -3.4 0.0 g 9 5 1 1 1 1 1 1 1 1 1 16 5 4 4 -1 -1 -1 -3 -3 -4 -8 -8.9 -10.76 -12.38 -13.20 -13.22 -13.1 0.0 h 9 5 -2 -2 -2 -2 -2 -2 -2 -3 -3 4 2 -2 -3 -5 -5 -5 -6 -6 -7 -8 -8.4 -8.16 -7.42 -6.88 -6.20 -5.3 0.0 g 9 6 -2 -2 -2 -2 -2 -2 -2 -2 -2 -3 -5 1 -1 -1 0 -1 -1 -1 -2 -1 -1.5 -1.25 -0.76 -0.10 1.08 2.4 0.0 h 9 6 8 8 8 8 9 9 9 9 9 9 8 10 9 10 10 10 9 9 9 8 8.4 8.10 7.97 7.79 7.79 7.2 0.0 g 9 7 2 2 2 2 2 2 3 3 3 -4 -2 2 -2 5 3 4 7 7 7 10 9.3 8.76 8.43 8.68 8.82 8.6 0.0 h 9 7 10 10 10 10 10 10 10 11 11 6 8 7 8 10 11 11 10 9 8 5 3.8 2.92 2.14 1.04 0.40 -0.6 0.0 g 9 8 -1 0 0 0 0 0 0 0 1 -3 3 2 3 1 1 1 2 1 1 -2 -4.3 -6.66 -8.42 -9.06 -9.23 -8.7 0.0 h 9 8 -2 -2 -2 -2 -2 -2 -2 -2 -2 1 -11 -6 0 -4 -2 -3 -6 -7 -7 -8 -8.2 -7.73 -6.08 -3.89 -1.44 0.8 0.0 g 9 9 -1 -1 -1 -1 -1 -1 -2 -2 -2 -4 8 5 -1 -2 -1 -2 -5 -5 -6 -8 -8.2 -9.22 -10.08 -10.54 -11.86 -12.8 0.0 h 9 9 2 2 2 2 2 2 2 2 2 8 -7 5 5 1 1 1 2 2 2 3 4.8 6.01 7.01 8.44 9.60 9.8 0.0 g 10 0 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -8 -3 1 -2 -3 -3 -4 -4 -3 -3 -2.6 -2.17 -1.94 -2.01 -1.84 -1.3 0.0 g 10 1 -4 -4 -4 -4 -4 -4 -4 -4 -4 11 4 -5 -3 -3 -3 -3 -4 -4 -4 -6 -6.0 -6.12 -6.24 -6.26 -6.25 -6.4 0.0 h 10 1 2 2 2 2 2 2 2 2 2 5 13 -4 4 2 1 1 1 1 2 1 1.7 2.19 2.73 3.28 3.38 3.3 0.0 g 10 2 2 2 2 2 2 2 2 2 2 1 -1 -1 4 2 2 2 2 3 2 2 1.7 1.42 0.89 0.17 -0.11 0.2 0.0 h 10 2 1 1 1 1 1 1 1 1 1 1 -2 0 1 1 1 1 0 0 1 0 0.0 0.10 -0.10 -0.40 -0.18 0.1 0.0 g 10 3 -5 -5 -5 -5 -5 -5 -5 -5 -5 2 13 2 0 -5 -5 -5 -5 -5 -5 -4 -3.1 -2.35 -1.07 0.55 1.66 2.0 0.0 h 10 3 2 2 2 2 2 2 2 2 2 -20 -10 -8 0 2 3 3 3 3 3 4 4.0 4.46 4.71 4.55 3.50 2.5 0.0 g 10 4 -2 -2 -2 -2 -2 -2 -2 -2 -2 -5 -4 -3 -1 -2 -1 -2 -2 -2 -2 -1 -0.5 -0.15 -0.16 -0.55 -0.86 -1.0 0.0 h 10 4 6 6 6 6 6 6 6 6 6 -1 2 -2 2 6 4 4 6 6 6 5 4.9 4.76 4.44 4.40 4.86 5.4 0.0 g 10 5 6 6 6 6 6 6 6 6 6 -1 4 7 4 4 6 5 5 5 4 4 3.7 3.06 2.45 1.70 0.65 -0.5 0.0 h 10 5 -4 -4 -4 -4 -4 -4 -4 -4 -4 -6 -3 -4 -5 -4 -4 -4 -4 -4 -4 -5 -5.9 -6.58 -7.22 -7.92 -8.62 -9.0 0.0 g 10 6 4 4 4 4 4 4 4 4 4 8 12 4 6 4 4 4 3 3 3 2 1.0 0.29 -0.33 -0.67 -0.88 -0.9 0.0 h 10 6 0 0 0 0 0 0 0 0 0 6 6 1 1 0 0 -1 0 0 0 -1 -1.2 -1.01 -0.96 -0.61 -0.11 0.4 0.0 g 10 7 0 0 0 0 0 0 0 0 0 -1 3 -2 1 0 1 1 1 1 1 2 2.0 2.06 2.13 2.13 1.88 1.5 0.0 h 10 7 -2 -2 -2 -2 -2 -2 -2 -1 -1 -4 -3 -3 -1 -2 -1 -1 -1 -1 -2 -2 -2.9 -3.47 -3.95 -4.16 -4.26 -4.2 0.0 g 10 8 2 2 2 1 1 1 1 2 2 -3 2 6 -1 2 0 0 2 2 3 5 4.2 3.77 3.09 2.33 1.44 0.9 0.0 h 10 8 4 4 4 4 4 4 4 4 4 -2 6 7 6 3 3 3 4 4 3 1 0.2 -0.86 -1.99 -2.85 -3.43 -3.8 0.0 g 10 9 2 2 2 2 3 3 3 3 3 5 10 -2 2 2 3 3 3 3 3 1 0.3 -0.21 -1.03 -1.80 -2.38 -2.6 0.0 h 10 9 0 0 0 0 0 0 0 0 0 0 11 -1 0 0 1 1 0 0 -1 -2 -2.2 -2.31 -1.97 -1.12 -0.10 0.9 0.0 g 10 10 0 0 0 0 0 0 0 0 0 -2 3 0 0 0 -1 -1 0 0 0 0 -1.1 -2.09 -2.80 -3.59 -3.84 -3.9 0.0 h 10 10 -6 -6 -6 -6 -6 -6 -6 -6 -6 -2 8 -3 -7 -6 -4 -5 -6 -6 -6 -7 -7.4 -7.93 -8.31 -8.72 -8.84 -9.0 0.0 g 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2.7 2.95 3.05 3.00 2.96 3.0 0.0 g 11 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.7 -1.60 -1.48 -1.40 -1.36 -1.4 0.0 h 11 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0.26 0.13 0.00 -0.02 0.0 0.0 g 11 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.9 -1.88 -2.03 -2.30 -2.51 -2.5 0.0 h 11 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.3 1.44 1.67 2.11 2.50 2.8 0.0 g 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.5 1.44 1.65 2.08 2.31 2.4 0.0 h 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.9 -0.77 -0.66 -0.60 -0.55 -0.6 0.0 g 11 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.1 -0.31 -0.51 -0.79 -0.85 -0.6 0.0 h 11 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2.6 -2.27 -1.76 -1.05 -0.39 0.1 0.0 g 11 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0.29 0.54 0.58 0.28 0.0 0.0 h 11 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.9 0.90 0.85 0.76 0.62 0.5 0.0 g 11 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.7 -0.79 -0.79 -0.70 -0.66 -0.6 0.0 h 11 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.7 -0.58 -0.39 -0.20 -0.21 -0.3 0.0 g 11 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0.53 0.37 0.14 -0.07 -0.1 0.0 h 11 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2.8 -2.69 -2.51 -2.12 -1.66 -1.2 0.0 g 11 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.7 1.80 1.79 1.70 1.44 1.1 0.0 h 11 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.9 -1.08 -1.27 -1.44 -1.60 -1.7 0.0 g 11 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0.16 0.12 -0.22 -0.59 -1.0 0.0 h 11 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.2 -1.58 -2.11 -2.57 -2.98 -2.9 0.0 g 11 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.2 0.96 0.75 0.44 0.18 -0.1 0.0 h 11 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.9 -1.90 -1.94 -2.01 -1.97 -1.8 0.0 g 11 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4.0 3.99 3.75 3.49 3.09 2.6 0.0 h 11 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.9 -1.39 -1.86 -2.34 -2.51 -2.3 0.0 g 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2.2 -2.15 -2.12 -2.09 -2.00 -2.0 0.0 g 12 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.3 -0.29 -0.21 -0.16 -0.13 -0.1 0.0 h 12 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.55 -0.87 -1.08 -1.15 -1.2 0.0 g 12 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0.21 0.30 0.46 0.43 0.4 0.0 h 12 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.23 0.27 0.37 0.52 0.6 0.0 g 12 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.9 0.89 1.04 1.23 1.28 1.2 0.0 h 12 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2.5 2.38 2.13 1.75 1.37 1.0 0.0 g 12 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2 -0.38 -0.63 -0.89 -1.14 -1.2 0.0 h 12 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2.6 -2.63 -2.49 -2.19 -1.81 -1.5 0.0 g 12 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.9 0.96 0.95 0.85 0.71 0.6 0.0 h 12 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0.61 0.49 0.27 0.08 0.0 0.0 g 12 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.5 -0.30 -0.11 0.10 0.31 0.5 0.0 h 12 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.40 0.59 0.72 0.71 0.6 0.0 g 12 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.46 0.52 0.54 0.49 0.5 0.0 h 12 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0 0.01 0.00 -0.09 -0.15 -0.2 0.0 g 12 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.3 -0.35 -0.39 -0.37 -0.26 -0.1 0.0 h 12 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0 0.02 0.13 0.29 0.55 0.8 0.0 g 12 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.36 -0.37 -0.43 -0.47 -0.5 0.0 h 12 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.28 0.27 0.23 0.16 0.1 0.0 g 12 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.1 0.08 0.21 0.22 0.09 -0.2 0.0 h 12 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.9 -0.87 -0.86 -0.89 -0.93 -0.9 0.0 g 12 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2 -0.49 -0.77 -0.94 -1.13 -1.2 0.0 h 12 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.34 -0.23 -0.16 -0.04 0.1 0.0 g 12 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.08 0.04 -0.03 -0.33 -0.7 0.0 h 12 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.8 0.88 0.87 0.72 0.52 0.2 0.0 g 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2 -0.16 -0.09 -0.02 0.08 0.2 0.0 g 13 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.9 -0.88 -0.89 -0.92 -0.93 -0.9 0.0 h 13 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.9 -0.76 -0.87 -0.88 -0.88 -0.9 0.0 g 13 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.30 0.31 0.42 0.53 0.6 0.0 h 13 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0.33 0.30 0.49 0.64 0.7 0.0 g 13 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0.28 0.42 0.63 0.72 0.7 0.0 h 13 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.8 1.72 1.66 1.56 1.40 1.2 0.0 g 13 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.43 -0.45 -0.42 -0.30 -0.2 0.0 h 13 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.54 -0.59 -0.50 -0.38 -0.3 0.0 g 13 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.3 1.18 1.08 0.96 0.75 0.5 0.0 h 13 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.0 -1.07 -1.14 -1.24 -1.31 -1.3 0.0 g 13 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.37 -0.31 -0.19 -0.01 0.1 0.0 h 13 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.1 -0.04 -0.07 -0.10 -0.09 -0.1 0.0 g 13 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0.75 0.78 0.81 0.76 0.7 0.0 h 13 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0.63 0.54 0.42 0.29 0.2 0.0 g 13 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.4 -0.26 -0.18 -0.13 -0.05 0.0 0.0 h 13 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.21 0.10 -0.04 -0.11 -0.2 0.0 g 13 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.35 0.38 0.38 0.37 0.3 0.0 h 13 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.6 0.53 0.49 0.48 0.47 0.5 0.0 g 13 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.1 -0.05 0.02 0.08 0.13 0.2 0.0 h 13 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.38 0.44 0.48 0.54 0.6 0.0 g 13 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4 0.41 0.42 0.46 0.45 0.4 0.0 h 13 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2 -0.22 -0.25 -0.30 -0.41 -0.6 0.0 g 13 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0 -0.10 -0.26 -0.35 -0.46 -0.5 0.0 h 13 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.5 -0.57 -0.53 -0.43 -0.36 -0.3 0.0 g 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 -0.18 -0.26 -0.36 -0.40 -0.4 0.0 h 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.9 -0.82 -0.79 -0.71 -0.60 -0.5 0.0 """ def _parse_igrf14_table() -> tuple[ np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray ]: """Parse the embedded IAGA table into per-epoch coefficient arrays. Returns ``(epochs, g, h, g_sv, h_sv)`` where ``g``/``h`` have shape ``(n_epochs, n_max + 1, n_max + 1)`` in nT and ``g_sv``/``h_sv`` hold the published secular variation for the interval after the final epoch, in nT/year. """ lines = [ ln for ln in _IGRF14_COF.splitlines() if ln.strip() and not ln.startswith("#") ] # lines[0] labels each column's model class (IGRF/DGRF/SV); lines[1] # holds the epoch years, ending with the SV validity range ("2025-30") epochs = np.array([float(tok) for tok in lines[1].split()[3:-1]]) n_max = 13 n_epochs = len(epochs) g = np.zeros((n_epochs, n_max + 1, n_max + 1)) h = np.zeros((n_epochs, n_max + 1, n_max + 1)) g_sv = np.zeros((n_max + 1, n_max + 1)) h_sv = np.zeros((n_max + 1, n_max + 1)) for ln in lines[2:]: toks = ln.split() n, m = int(toks[1]), int(toks[2]) vals = [float(tok) for tok in toks[3:]] if toks[0] == "g": g[:, n, m] = vals[:-1] g_sv[n, m] = vals[-1] else: h[:, n, m] = vals[:-1] h_sv[n, m] = vals[-1] return epochs, g, h, g_sv, h_sv _IGRF14_EPOCHS, _IGRF14_G, _IGRF14_H, _IGRF14_G_SV, _IGRF14_H_SV = _parse_igrf14_table()
[docs] def create_igrf14_coefficients(year: Optional[float] = None) -> MagneticCoefficients: """ Create IGRF-14 model coefficients for a given decimal year. Parameters ---------- year : float, optional Decimal year selecting the coefficient epoch. Default is the IGRF-14 reference epoch, 2025.0. Returns ------- coeffs : MagneticCoefficients Spherical harmonic coefficients whose linear time term reproduces the IGRF-14 field at ``year``. At or after 2025.0 this is the reference-epoch main field with the published 2025-2030 secular variation as ``g_dot``/``h_dot``. Within 1900.0-2025.0 it is the main field of the five-year epoch at or below ``year``, with the slope of the bracketing interval as the time term, so a field evaluation at ``year`` linearly interpolates the two neighboring epochs. Before 1900.0 the 1900-1905 slope extrapolates backwards, with a warning. Examples -------- >>> coeffs = create_igrf14_coefficients() >>> coeffs.epoch 2025.0 >>> coeffs.g[1, 0] -29350.0 >>> create_igrf14_coefficients(2012.5).epoch 2010.0 Notes ----- Port of ``getIGRFCoeffs.m`` from the MATLAB library (epoch selection and interpolation; the Schmidt semi-normalized coefficients are kept in nT for :func:`pytcl.magnetism.wmm.wmm`-style evaluation rather than fully normalized in Tesla). Deviation from the MATLAB original: a warning is emitted for years beyond 2030.0, the end of the published secular-variation window. ``getIGRFCoeffs.m`` extrapolates forward silently; the IGRF-13 model embedded in this library previously did the same past 2025.0, and that silence is exactly how it went stale unnoticed. """ if year is None: year = float(_IGRF14_EPOCHS[-1]) first = float(_IGRF14_EPOCHS[0]) last = float(_IGRF14_EPOCHS[-1]) if year < first: warnings.warn( f"The year is before the first epoch ({first}) of the IGRF-14 " "tables; values are extrapolated backwards from the " "1900-1905 interval.", stacklevel=2, ) if year > last + 5.0: warnings.warn( f"The year is beyond {last + 5.0}, the end of the IGRF-14 " "secular-variation validity window; treat the result as an " "unofficial extrapolation. For predicting the field forward " "prefer the current WMM.", stacklevel=2, ) n_max = 13 if year >= last: idx = len(_IGRF14_EPOCHS) - 1 g_dot = _IGRF14_G_SV h_dot = _IGRF14_H_SV else: idx = max(int(np.searchsorted(_IGRF14_EPOCHS, year, side="right")) - 1, 0) span = _IGRF14_EPOCHS[idx + 1] - _IGRF14_EPOCHS[idx] g_dot = (_IGRF14_G[idx + 1] - _IGRF14_G[idx]) / span h_dot = (_IGRF14_H[idx + 1] - _IGRF14_H[idx]) / span return MagneticCoefficients( g=_IGRF14_G[idx].copy(), h=_IGRF14_H[idx].copy(), g_dot=g_dot.copy(), h_dot=h_dot.copy(), epoch=float(_IGRF14_EPOCHS[idx]), n_max=n_max, )
IGRF14 = create_igrf14_coefficients()
[docs] def igrf( lat: float, lon: float, h: float = 0.0, year: float = 2025.0, coeffs: Optional[MagneticCoefficients] = None, ) -> MagneticResult: """ Compute magnetic field using IGRF model. Parameters ---------- lat : float Geodetic latitude in radians. lon : float Longitude in radians. h : float, optional Height above WGS84 ellipsoid in km. Default 0. year : float, optional Decimal year. Default 2025.0, the IGRF-14 reference epoch. coeffs : MagneticCoefficients, optional Model coefficients. Default: IGRF-14 coefficients selected for ``year`` by :func:`create_igrf14_coefficients`, interpolating the 1900.0-2025.0 epoch tables and warning outside the model's validity window. Returns ------- result : MagneticResult Magnetic field components and derived quantities. Examples -------- >>> import numpy as np >>> result = igrf(np.radians(45), np.radians(-75), 0, 2023.0) >>> print(f"Total field: {result.F:.0f} nT") Total field: 53341 nT """ if coeffs is None: coeffs = create_igrf14_coefficients(year) # Same geodetic evaluation as the WMM (WGS84 geodetic-to-geocentric # conversion, Schmidt-normalized synthesis, frame rotation) return wmm(lat, lon, h, year, coeffs)
[docs] def igrf_declination( lat: float, lon: float, h: float = 0.0, year: float = 2025.0, ) -> float: """ Compute magnetic declination using IGRF. Parameters ---------- lat : float Geodetic latitude in radians. lon : float Longitude in radians. h : float, optional Height in km. Default 0. year : float, optional Decimal year. Default 2025.0. Returns ------- D : float Declination in radians. Examples -------- >>> import numpy as np >>> from pytcl.magnetism import igrf_declination >>> # Declination at Denver (40°N, 105°W) >>> lat = np.radians(40) >>> lon = np.radians(-105) >>> D = igrf_declination(lat, lon, 1.6, 2023.0) >>> # Denver lies west of the agonic line: easterly declination (~8° E) >>> print(f"Declination: {np.degrees(D):.1f}°") Declination: 7.8° >>> bool(0 < D < 0.35) # East is positive True """ return igrf(lat, lon, h, year).D
[docs] def igrf_inclination( lat: float, lon: float, h: float = 0.0, year: float = 2025.0, ) -> float: """ Compute magnetic inclination using IGRF. Parameters ---------- lat : float Geodetic latitude in radians. lon : float Longitude in radians. h : float, optional Height in km. Default 0. year : float, optional Decimal year. Default 2025.0. Returns ------- I : float Inclination in radians. Examples -------- >>> import numpy as np >>> from pytcl.magnetism import igrf_inclination >>> # Inclination comparison: equator vs pole >>> I_eq = igrf_inclination(0, 0, 0, 2023.0) # Equator >>> I_pole = igrf_inclination(np.radians(85), 0, 0, 2023.0) # Near pole >>> # The dip equator is offset from the geographic equator; at (0°N, 0°E) >>> # in the Gulf of Guinea the inclination is moderately negative (~-30°) >>> bool(-0.6 < I_eq < 0) True >>> bool(abs(I_pole) > 1.4) # ~80+ degrees near the pole True """ return igrf(lat, lon, h, year).I
[docs] def dipole_moment(coeffs: MagneticCoefficients = IGRF14) -> float: """ Compute the centered dipole moment. Parameters ---------- coeffs : MagneticCoefficients, optional Model coefficients. Default IGRF14. Returns ------- M : float Dipole moment in nT * km^3. Notes ----- The dipole moment is computed from the n=1 Gauss coefficients: M = a^3 * sqrt(g10^2 + g11^2 + h11^2) Examples -------- >>> from pytcl.magnetism import dipole_moment, IGRF14 >>> # Compute Earth's dipole moment from IGRF-14 >>> M = dipole_moment(IGRF14) >>> # Earth's dipole moment is approximately 7.9 × 10^22 A·m² >>> # In nT·km³ units, this is about 7.9 × 10^15 >>> 7e15 < M < 8.5e15 True """ a = 6371.2 # Reference radius in km g10 = coeffs.g[1, 0] g11 = coeffs.g[1, 1] h11 = coeffs.h[1, 1] M = a**3 * np.sqrt(g10**2 + g11**2 + h11**2) return M
[docs] def dipole_axis( coeffs: MagneticCoefficients = IGRF14, ) -> tuple[float, float]: """ Compute the geocentric dipole axis direction. Parameters ---------- coeffs : MagneticCoefficients, optional Model coefficients. Default IGRF14. Returns ------- lat : float Latitude of the north geomagnetic pole in radians. lon : float Longitude of the north geomagnetic pole in radians. Notes ----- The geomagnetic pole is where the centered dipole axis intersects the Earth's surface. Examples -------- >>> import numpy as np >>> from pytcl.magnetism import dipole_axis, IGRF14 >>> # Compute geomagnetic pole location >>> lat, lon = dipole_axis(IGRF14) >>> # Geomagnetic north pole is around 80.7°N, 72.5°W (epoch 2025) >>> print(f"{np.degrees(lat):.2f}°N, {np.degrees(lon):.2f}°E") 80.79°N, -72.76°E >>> bool(70 < np.degrees(lat) < 85) True >>> bool(-100 < np.degrees(lon) < -60) True """ g10 = coeffs.g[1, 0] g11 = coeffs.g[1, 1] h11 = coeffs.h[1, 1] # The dipole moment vector is proportional to (g11, h11, g10); the # NORTH geomagnetic pole lies along its antipode (g10 < 0 for Earth) b0 = np.sqrt(g10**2 + g11**2 + h11**2) theta = np.arccos(-g10 / b0) phi = np.arctan2(-h11, -g11) # Convert colatitude to latitude lat = np.pi / 2 - theta return lat, phi
[docs] def magnetic_north_pole( year: float = 2025.0, coeffs: Optional[MagneticCoefficients] = None, ) -> tuple[float, float]: """ Compute the location of the magnetic north pole. The magnetic north pole is where the field is vertical (inclination = 90°). This differs from the geomagnetic pole due to non-dipole field contributions. Parameters ---------- year : float, optional Decimal year. Default 2025.0. coeffs : MagneticCoefficients, optional Model coefficients. Default: IGRF-14 coefficients selected for ``year`` by :func:`create_igrf14_coefficients`. Returns ------- lat : float Latitude of magnetic north pole in radians. lon : float Longitude of magnetic north pole in radians. Notes ----- This uses an iterative search starting from the dipole pole. The magnetic pole moves over time. Examples -------- >>> import numpy as np >>> from pytcl.magnetism import magnetic_north_pole, dipole_axis >>> # Magnetic north pole location (2023) >>> lat, lon = magnetic_north_pole(2023.0) >>> # The pole has drifted past 86°N toward the Siberian side of >>> # the Arctic (east longitude), around 86°N, 146°E in 2023 >>> bool(75 < np.degrees(lat) < 90) True >>> bool(130 < np.degrees(lon) < 180) True >>> # Compare with geomagnetic pole >>> geo_lat, geo_lon = dipole_axis() >>> # Magnetic pole differs from geomagnetic pole >>> bool(abs(lat - geo_lat) > 0.01) # Different locations True """ from scipy.optimize import minimize if coeffs is None: coeffs = create_igrf14_coefficients(year) lat_cap = np.radians(89.9) def horizontal_intensity(x: np.ndarray) -> float: # Keep the search off the exact geographic pole, where the # synthesis's singularity guard makes H spuriously zero if abs(x[0]) > lat_cap: return 1e9 return float(igrf(x[0], x[1], 0.0, year, coeffs).H) # Coarse grid over the Arctic to find the global basin (the H surface # has local minima that trap a single descent), then refine best = (np.inf, np.pi / 2, 0.0) for lat_deg in np.arange(78.0, 89.5, 1.0): for lon_deg in np.arange(-180.0, 180.0, 10.0): x = np.array([np.radians(lat_deg), np.radians(lon_deg)]) val = horizontal_intensity(x) if val < best[0]: best = (val, x[0], x[1]) result = minimize( horizontal_intensity, np.array([best[1], best[2]]), method="Nelder-Mead", options={"xatol": 1e-6, "fatol": 1e-3, "maxiter": 500}, ) lat, lon = float(result.x[0]), float(result.x[1]) return lat, lon
__all__ = [ "IGRFModel", "IGRF13", "IGRF14", "create_igrf13_coefficients", "create_igrf14_coefficients", "igrf", "igrf_declination", "igrf_inclination", "dipole_moment", "dipole_axis", "magnetic_north_pole", ]