import datetime
import os
from enum import Enum
import numpy as np
from numba import jit
from gtsimulation.Global import Units, Regions
from gtsimulation.MagneticFields import AbsBfield
from gtsimulation.MagneticFields.Magnetosphere.Functions.gauss import LoadGaussCoeffs
[docs]
class GaussModels(Enum):
IGRF = 1
CHAOS = 2
CM = 3
COV_OBS = 4
LCS = 5
SIFM = 6
DIFI = 7
[docs]
class GaussTypes(Enum):
core = 1
static = 2
ionosphere = 3
versions_dict = {GaussModels.IGRF: [13, 14],
GaussModels.CHAOS: [7.18, 8.5],
GaussModels.CM: [6],
GaussModels.COV_OBS: [2],
GaussModels.LCS: [1],
GaussModels.DIFI: [6],
GaussModels.SIFM: [None]}
[docs]
class Gauss(AbsBfield):
ToMeters = Units.km2m
def __init__(self, date: datetime.datetime, model: GaussModels | str, model_type: GaussTypes | str, version=None,
coord: int = 1, **kwargs):
super().__init__(**kwargs)
self.Region = Regions.Magnetosphere
self.Units = "km"
self.Model = model if isinstance(model_type, GaussModels) else GaussModels[model]
self.type = model_type if isinstance(model_type, GaussTypes) else GaussTypes[model_type]
self.version = version
self.Date = date
self.coord = coord
self.txt_file_loc = ""
self.mat_file_loc = ""
self.npy_file_loc = ""
self.SetFullModelName()
self.g, self.h, self.gh = LoadGaussCoeffs(self.npy_file_loc, self.Date)
[docs]
def CalcBfield(self, x, y, z, **kwargs):
coord = self.coord
gh = self.gh
Bx, By, Bz = self.__calc_b(x, y, z, coord, gh)
return Bx, By, Bz
@staticmethod
@jit(nopython=True, fastmath=True)
def __calc_b(x, y, z, coord, gh):
altitude = np.sqrt(x ** 2 + y ** 2 + z ** 2)
phi = np.arctan2(y, x)
theta = np.arccos(z / altitude)
lat = np.pi/2 - theta
Rearth_km = 6371.2
costheta = np.cos(theta)
sintheta = np.sin(theta)
# if coord == 0:
# # TODO: to fix r calculation
# a = 6378.137
# f = 1 / 298.257223563
# b = a * (1 - f)
#
# rho = np.hypot(a * sintheta, b * costheta)
# r = np.sqrt(
# altitude ** 2 + 2 * altitude * rho + (a ** 4 * sintheta ** 2 + b ** 4 * costheta ** 2) / (rho ** 2))
# cd = (altitude + rho) / r
# sd = (a ** 2 - b ** 2) / rho * costheta * sintheta / r
# oldcos = costheta
# costheta = costheta * cd - sintheta * sd
# sintheta = sintheta * cd + oldcos * sd
# else:
r = altitude
cd = 1
sd = 0
nmax = np.sqrt(len(gh) + 1) - 1
cosphi = np.cos(np.arange(1, nmax + 1) * phi)
sinphi = np.sin(np.arange(1, nmax + 1) * phi)
Pmax = int((nmax + 1) * (nmax + 2) / 2)
Br = 0.
Bt = 0.
Bp = 0.
P = np.zeros(Pmax)
P[0] = 1
P[2] = sintheta
dP = np.zeros(Pmax)
dP[0] = 0
dP[2] = costheta
m = 1
n = 0
coefindex = 0
a_r = (Rearth_km / r) ** 2
for Pindex in range(1, Pmax):
if n < m:
m = 0
n += 1
a_r *= (Rearth_km / r)
if m < n and Pindex != 2:
last1n = Pindex - n
last2n = Pindex - 2 * n + 1
P[Pindex] = (2 * n - 1) / np.sqrt(n ** 2 - m ** 2) * costheta * P[last1n] - np.sqrt(
((n - 1) ** 2 - m ** 2) / (n ** 2 - m ** 2)) * P[last2n]
dP[Pindex] = (2 * n - 1) / np.sqrt(n ** 2 - m ** 2) * (
costheta * dP[last1n] - sintheta * P[last1n]) - np.sqrt(
((n - 1) ** 2 - m ** 2) / (n ** 2 - m ** 2)) * dP[last2n]
elif Pindex != 2:
lastn = Pindex - n - 1
P[Pindex] = np.sqrt(1 - 1 / (2 * m)) * sintheta * P[lastn]
dP[Pindex] = np.sqrt(1 - 1 / (2 * m)) * (sintheta * dP[lastn] + costheta * P[lastn])
if m == 0:
coef = a_r * gh[coefindex]
Br += (n + 1) * coef * P[Pindex]
Bt -= coef * dP[Pindex]
coefindex += 1
else:
coef = a_r * (gh[coefindex] * cosphi[m - 1] + gh[coefindex + 1] * sinphi[m - 1])
Br += (n + 1) * coef * P[Pindex]
Bt -= coef * dP[Pindex]
if sintheta == 0:
Bp -= costheta * a_r * (-gh[coefindex] * sinphi[m - 1] + gh[coefindex] * cosphi[m - 1]) * \
dP[Pindex]
else:
Bp -= 1 / sintheta * a_r * m * (
-gh[coefindex] * sinphi[m - 1] + gh[coefindex+1] * cosphi[m - 1]) * P[Pindex]
coefindex += 2
m += 1
Bx = -Bt
By = Bp
Bz = -Br
# if coord == 0:
# Bx_old = Bx
# Bx = Bx * cd + Bz * sd
# Bz = Bz * cd - Bx_old * sd
My = np.array([[-np.sin(lat), 0., np.cos(lat)],
[0, 1., 0],
[-np.cos(lat), 0., -np.sin(lat)]])
Mz = np.array([[np.cos(phi), np.sin(phi), 0.],
[-np.sin(phi), np.cos(phi), 0.],
[0., 0., 1.]])
B = np.array([Bx, By, Bz]) @ My @ Mz
Bx = B[0]
By = B[1]
Bz = B[2]
return Bx, By, Bz
[docs]
def UpdateState(self, new_date):
self.Date = new_date
self.g, self.h, self.gh = LoadGaussCoeffs(self.npy_file_loc, self.Date)
[docs]
def SetFullModelName(self):
assert self.version in versions_dict[self.Model]
txt_file = ""
mat_file = ""
npy_file = ""
loc = os.path.dirname(os.path.realpath(__file__))
if self.Model == GaussModels.IGRF:
self.ModelName = self.Model.name + str(self.version)
assert self.type == GaussTypes.core
txt_file = self.ModelName.lower() + 'coeffs.txt'
mat_file = self.ModelName.lower() + 'coeffs.mat'
npy_file = self.ModelName.lower() + 'coeffs.npy'
elif self.Model == GaussModels.CHAOS:
self.ModelName = self.Model.name + '-' + str(self.version)
assert self.type != GaussTypes.ionosphere
txt_file = self.ModelName + "_" + self.type.name + '.shc.txt'
mat_file = self.ModelName + "_" + self.type.name + '.mat'
npy_file = self.ModelName + "_" + self.type.name + '.npy'
elif self.Model == GaussModels.CM:
self.ModelName = self.Model.name + str(self.version)
if self.type == GaussTypes.core:
txt_file = 'MCO_' + self.ModelName + '.shc.txt'
mat_file = 'MCO_' + self.ModelName + '.mat'
npy_file = 'MCO_' + self.ModelName + '.npy'
elif self.type == GaussTypes.static:
txt_file = 'MLI_' + self.ModelName + '.shc.txt'
mat_file = 'MLI_' + self.ModelName + '.mat'
npy_file = 'MLI_' + self.ModelName + '.npy'
elif self.type == GaussTypes.ionosphere:
txt_file = 'MIO_' + self.ModelName + '.shc.txt'
mat_file = 'MIO_' + self.ModelName + '.mat'
npy_file = 'MIO_' + self.ModelName + '.npy'
elif self.Model == GaussModels.COV_OBS:
self.ModelName = self.Model.name + ".x" + str(self.version) + "-int"
txt_file = self.ModelName + '.shc.txt'
mat_file = self.ModelName + '.mat'
npy_file = self.ModelName + '.npy'
elif self.Model == GaussModels.LCS:
self.ModelName = self.Model.name + '-' + str(self.version)
assert self.type == GaussTypes.static
txt_file = self.ModelName + '.shc.txt'
mat_file = self.ModelName + '.mat'
npy_file = self.ModelName + '.npy'
elif self.Model == GaussModels.DIFI:
self.ModelName = self.Model.name + str(self.version)
assert self.type == GaussTypes.ionosphere
txt_file = self.ModelName + '.txt'
mat_file = self.ModelName + '.mat'
npy_file = self.ModelName + '.npy'
elif self.Model == GaussModels.SIFM:
self.ModelName = self.Model.name
assert self.type != GaussTypes.ionosphere
txt_file = self.ModelName + ".shc.txt"
mat_file = self.ModelName + "_" + self.type.name + ".mat"
npy_file = self.ModelName + "_" + self.type.name + ".npy"
self.txt_file_loc = loc + os.sep + self.ModelName + os.sep + txt_file
self.mat_file_loc = loc + os.sep + self.ModelName + os.sep + mat_file
self.npy_file_loc = loc + os.sep + self.ModelName + os.sep + npy_file
[docs]
def to_string(self):
s = f"""{self.Model.name}
Type: {self.type.name}
Version: {self.version}"""
return s