Source code for pyrfu.models.igrf
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Built-on imports
import os
import warnings
from typing import Any, Optional, Tuple
# 3rd party imports
import numpy as np
import pandas as pd
from numpy.typing import NDArray
from scipy import interpolate
__author__ = "Louis Richard"
__email__ = "louisr@irfu.se"
__copyright__ = "Copyright 2020-2024"
__license__ = "MIT"
__version__ = "2.4.13"
__status__ = "Prototype"
[docs]def igrf(
time: NDArray[Any], flag: Optional[str] = None
) -> Tuple[NDArray[np.float64], NDArray[np.float64]]:
r"""Returns magnetic dipole latitude and longitude of the IGRF model
Parameters
----------
time : numpy.ndarray
Times in unix format.
flag : str
Default is dipole.
Returns
-------
tuple
Tuple containing latitude and longitude as numpy arrays.
Raises
------
NotImplementedError
If flag is not dipole.
"""
if flag is None:
flag = "dipole"
# Root path
# root_path = os.getcwd()
path = os.sep.join(
[os.path.dirname(os.path.abspath(__file__)), "igrf13coeffs.csv"],
)
df = pd.read_csv(path)
# construct IGRF coefficient matrices
years_igrf = df.loc[0][3:].to_list()
years_igrf[-1] = float(years_igrf[-1].split("-")[0]) + 5.0
# read in all IGRF coefficients from file
i_igrf = df.loc[1:,].values
i_igrf[:, -1] = i_igrf[:, -2] + 5.0 * i_igrf[:, -1].astype(np.float64)
h_igrf = i_igrf[i_igrf[:, 0] == "h", 1:].astype(np.float64)
g_igrf = i_igrf[i_igrf[:, 0] == "g", 1:].astype(np.float64)
# timeVec = irf_time(t,'vector');
# yearRef = timeVec(:,1);
year_ref = (time * 1e9).astype("datetime64[ns]")
year_ref = year_ref.astype("datetime64[Y]")
year_ref = year_ref.astype(np.int64) + 1970
year_ref_unix = (year_ref - 1970).astype("datetime64[Y]")
year_ref_unix = year_ref_unix.astype("datetime64[ns]").astype(np.int64) / 1e9
if np.min(year_ref) < np.min(years_igrf):
warnings.warn(
"requested time is earlier than the first available IGRF model; "
"extrapolating in past",
category=UserWarning,
)
if flag.lower() == "dipole":
tck_g0_igrf = interpolate.interp1d(
years_igrf,
g_igrf[0, 2:],
kind="linear",
fill_value="extrapolate",
)
tck_g1_igrf = interpolate.interp1d(
years_igrf,
g_igrf[1, 2:],
kind="linear",
fill_value="extrapolate",
)
tck_h0_igrf = interpolate.interp1d(
years_igrf,
h_igrf[0, 2:],
kind="linear",
fill_value="extrapolate",
)
g01 = tck_g0_igrf(year_ref + (time - year_ref_unix) / (365.25 * 86400))
g11 = tck_g1_igrf(year_ref + (time - year_ref_unix) / (365.25 * 86400))
h11 = tck_h0_igrf(year_ref + (time - year_ref_unix) / (365.25 * 86400))
lambda_ = np.arctan(h11 / g11)
phi = np.pi / 2
phi -= np.arcsin((g11 * np.cos(lambda_) + h11 * np.sin(lambda_)) / g01)
else:
raise NotImplementedError("input flag is not recognized")
out = (np.rad2deg(lambda_), np.rad2deg(phi))
return out