new program file for JB2008
This commit is contained in:
parent
b9c064acc9
commit
7145ef616d
457
pyatmos/jb2008/JB2008_subfunc.py
Normal file
457
pyatmos/jb2008/JB2008_subfunc.py
Normal file
@ -0,0 +1,457 @@
|
||||
import numpy as np
|
||||
from numba import jit
|
||||
|
||||
from ..utils import Const
|
||||
|
||||
@jit(nopython=True)
|
||||
def JB2008(AMJD,YRDAY,SUN,SAT,F10,F10B,S10,S10B,M10,M10B,Y10,Y10B,DSTDTC):
|
||||
'''
|
||||
Jacchia-Bowman 2008 Model Atmosphere
|
||||
|
||||
This is the CIRA "Integration Form" of a Jacchia Model.
|
||||
There are no tabular values of density. Instead, the barometricequation and diffusion equation are integrated numerically using
|
||||
the Newton-Coates method to produce the density profile up to the input position.
|
||||
|
||||
INPUT:
|
||||
AMJD : Date and Time, in modified Julian Days and Fraction (MJD = JD-2400000.5)
|
||||
SUN[0] : Right Ascension of Sun (radians)
|
||||
SUN[1] : Declination of Sun (radians)
|
||||
SAT[0] : Right Ascension of Position (radians)
|
||||
SAT[1] : Geocentric Latitude of Position (radians)
|
||||
SAT[2] : Height of Position (km)
|
||||
F10 : 10.7-cm Solar Flux (1.0E-22*W/(M**2*Hz)) (Tabular time 1.0 day earlier)
|
||||
F10B : 10.7-cm Solar Flux, ave. 81-day centered on the input time (Tabular time 1.0 day earlier)
|
||||
S10 : EUV index (26-34 nm) scaled to F10 (Tabular time 1.0 day earlier)
|
||||
S10B : EUV 81-day ave. centered index (Tabular time 1.0 day earlier)
|
||||
M10 : MG2 index scaled to F10 (Tabular time 2.0 days earlier)
|
||||
M10B : MG2 81-day ave. centered index (Tabular time 2.0 days earlier)
|
||||
Y10 : Solar X-Ray & Lya index scaled to F10 (Tabular time 5.0 days earlier)
|
||||
Y10B : Solar X-Ray & Lya 81-day ave. centered index (Tabular time 5.0 days earlier)
|
||||
DSTDTC : Temperature change computed from Dst index
|
||||
|
||||
OUTPUT:
|
||||
TEMP(1): Exospheric Temperature above Input Position (K)
|
||||
TEMP(2): Temperature at Input Position (K)
|
||||
RHO : Total Mass-Desnity at Input Position (kg/m**3)
|
||||
|
||||
Reference:
|
||||
Bowman, Bruce R., etc. : "A New Empirical Thermospheric
|
||||
Density Model JB2008 Using New Solar and Geomagnetic Indices",
|
||||
AIAA/AAS 2008, COSPAR CIRA 2008 Model
|
||||
|
||||
Note:
|
||||
The program is translated from the fortran source code written by Bruce R Bowman (HQ AFSPC, Space Analysis Division), 2008
|
||||
|
||||
'''
|
||||
|
||||
# The alpha are the thermal diffusion coefficients in Eq. (6)
|
||||
TEMP = np.zeros(2)
|
||||
ALPHA = np.zeros(5)
|
||||
ALPHA[4] = -0.38
|
||||
|
||||
# AL10 is DLOG(10.0)
|
||||
AL10 = Const.al10
|
||||
|
||||
# The AMW are the molecular weights in order: N2, O2, O, Ar, He & H
|
||||
AMW = np.array([28.0134,31.9988,15.9994,39.9480,4.0026,1.00797])
|
||||
|
||||
# AVOGAD is Avogadro's number in mks units (molecules/kmol)
|
||||
AVOGAD = Const.avogad
|
||||
|
||||
PI = Const.pi
|
||||
TWOPI,FOURPI = Const.twopi,Const.fourpi
|
||||
PIOV2,PIOV4 = Const.pivo2,Const.pivo4
|
||||
|
||||
# The FRAC are the assumed sea-level volume fractions in order: N2, O2, Ar, and He
|
||||
FRAC = np.array([0.7811,0.20955,9.34e-3,1.289e-5])
|
||||
|
||||
# RSTAR is the universal gas-constant in mks units (joules/K/kmol)
|
||||
RSTAR = Const.rstar
|
||||
|
||||
# The R# are values used to establish height step sizes in the regimes 90km to 105km, 105km to 500km and 500km upward.
|
||||
R1,R2,R3 = 0.01,0.025,0.075
|
||||
|
||||
# The WT are weights for the Newton-Cotes Five-Point Quad. formula
|
||||
WT = np.array([7,32,12,32,7])*2/45
|
||||
|
||||
# The CHT are coefficients for high altitude density correction
|
||||
CHT = np.array([0.22,-0.2e-2,0.115e-2,-0.211e-5])
|
||||
DEGRAD = Const.degrad
|
||||
|
||||
# Equation (14)
|
||||
FN = (F10B/240)**0.25
|
||||
if FN > 1: FN = 1
|
||||
FSB = F10B*FN + S10B*(1 - FN)
|
||||
TSUBC = 392.4 + 3.227*FSB + 0.298*(F10-F10B) + 2.259*(S10-S10B) + 0.312*(M10-M10B) + 0.178*(Y10-Y10B)
|
||||
|
||||
# Equation (15)
|
||||
ETA = np.abs(SAT[1] - SUN[1])/2
|
||||
THETA = np.abs(SAT[1] + SUN[1])/2
|
||||
|
||||
# Equation (16)
|
||||
H = SAT[0] - SUN[0]
|
||||
TAU = H - 0.64577182 + 0.10471976 * np.sin(H + 0.75049158)
|
||||
|
||||
GLAT,ZHT = SAT[1],SAT[2]
|
||||
GLST = H + PI
|
||||
GLSTHR = (GLST/DEGRAD)*(24/360)
|
||||
if GLSTHR >= 24: GLSTHR -= 24
|
||||
if GLSTHR < 0: GLSTHR += 24
|
||||
|
||||
# Equation (17)
|
||||
C = np.cos(ETA)**2.5
|
||||
S = np.sin(THETA)**2.5
|
||||
|
||||
DF = S + (C - S) * np.abs(np.cos(0.5 * TAU))**3
|
||||
TSUBL = TSUBC * (1 + 0.31 * DF)
|
||||
|
||||
# Compute correction to dTc for local solar time and lat correction
|
||||
DTCLST = DTSUB(F10,GLSTHR,GLAT,ZHT)
|
||||
|
||||
# Compute the local exospheric temperature.
|
||||
# Add geomagnetic storm effect from input dTc value
|
||||
|
||||
TEMP[0] = TSUBL + DSTDTC
|
||||
TINF = TEMP[0] + DTCLST
|
||||
|
||||
# Equation (9)
|
||||
TSUBX = 444.3807 + 0.02385 * TINF - 392.8292 * np.exp(-0.0021357 * TINF)
|
||||
|
||||
# Equation (11)
|
||||
GSUBX = 0.054285714 * (TSUBX - 183)
|
||||
|
||||
# The TC array will be an argument in the call to XLOCAL, which evaluates Equation (10) or Equation (13)
|
||||
TC = np.zeros(4)
|
||||
TC[0],TC[1] = TSUBX,GSUBX
|
||||
|
||||
# A AND GSUBX/A OF Equation (13)
|
||||
TC[2] = (TINF - TSUBX)/PIOV2
|
||||
TC[3] = GSUBX/TC[2]
|
||||
|
||||
# Equation (5)
|
||||
Z1 = 90
|
||||
Z2 = min(SAT[2],105)
|
||||
AL = np.log(Z2/Z1)
|
||||
N = int(AL/R1) + 1
|
||||
ZR = np.exp(AL/N)
|
||||
AMBAR1 = XAMBAR(Z1)
|
||||
TLOC1 = XLOCAL(Z1,TC)
|
||||
ZEND = Z1
|
||||
SUM2 = 0
|
||||
AIN = AMBAR1 * XGRAV(Z1)/TLOC1
|
||||
|
||||
for I in range(N):
|
||||
Z = ZEND
|
||||
ZEND = ZR * Z
|
||||
DZ = 0.25 * (ZEND-Z)
|
||||
SUM1 = WT[0]*AIN
|
||||
|
||||
for J in range(1,5):
|
||||
Z += DZ
|
||||
AMBAR2 = XAMBAR(Z)
|
||||
TLOC2 = XLOCAL(Z,TC)
|
||||
GRAVL = XGRAV(Z)
|
||||
AIN = AMBAR2 * GRAVL/TLOC2
|
||||
SUM1 += WT[J] * AIN
|
||||
SUM2 += DZ * SUM1
|
||||
|
||||
FACT1 = 1e3/RSTAR
|
||||
RHO = 3.46e-6 * AMBAR2 * TLOC1 * np.exp(-FACT1*SUM2) /AMBAR1 /TLOC2
|
||||
|
||||
# Equation (2)
|
||||
ANM = AVOGAD * RHO
|
||||
AN = ANM/AMBAR2
|
||||
|
||||
# Equation (3)
|
||||
FACT2 = ANM/28.96
|
||||
ALN = np.zeros(6)
|
||||
ALN[0] = np.log(FRAC[0]*FACT2)
|
||||
ALN[3] = np.log(FRAC[2]*FACT2)
|
||||
ALN[4] = np.log(FRAC[3]*FACT2)
|
||||
|
||||
# Equation (4)
|
||||
ALN[1] = np.log(FACT2 * (1 + FRAC[1]) - AN)
|
||||
ALN[2] = np.log(2 * (AN - FACT2))
|
||||
|
||||
if SAT[2] <= 105:
|
||||
TEMP[1] = TLOC2
|
||||
# Put in negligible hydrogen for use in DO-LOOP 13
|
||||
ALN[5] = ALN[4] - 25
|
||||
else:
|
||||
# Equation (6)
|
||||
Z3 = min(SAT[2],500)
|
||||
AL = np.log(Z3/Z)
|
||||
N = int(AL/R2) + 1
|
||||
ZR = np.exp(AL/N)
|
||||
SUM2 = 0
|
||||
AIN = GRAVL/TLOC2
|
||||
|
||||
for I in range(N):
|
||||
Z = ZEND
|
||||
ZEND = ZR * Z
|
||||
DZ = 0.25 * (ZEND - Z)
|
||||
SUM1 = WT[0] * AIN
|
||||
for J in range(1,5):
|
||||
Z += DZ
|
||||
TLOC3 = XLOCAL(Z,TC)
|
||||
GRAVL = XGRAV(Z)
|
||||
AIN = GRAVL/TLOC3
|
||||
SUM1 += WT[J] * AIN
|
||||
SUM2 += DZ * SUM1
|
||||
|
||||
Z4 = max(SAT[2],500)
|
||||
AL = np.log(Z4/Z)
|
||||
R = R2
|
||||
if SAT[2] > 500: R = R3
|
||||
N = int(AL/R) + 1
|
||||
ZR = np.exp(AL/N)
|
||||
SUM3 = 0
|
||||
for I in range(N):
|
||||
Z = ZEND
|
||||
ZEND = ZR * Z
|
||||
DZ = 0.25 * (ZEND - Z)
|
||||
SUM1 = WT[0] * AIN
|
||||
for J in range(1,5):
|
||||
Z += DZ
|
||||
TLOC4 = XLOCAL(Z,TC)
|
||||
GRAVL = XGRAV(Z)
|
||||
AIN = GRAVL/TLOC4
|
||||
SUM1 += WT[J] * AIN
|
||||
SUM3 += DZ * SUM1
|
||||
|
||||
if SAT[2] <= 500:
|
||||
T500 = TLOC4
|
||||
TEMP[1] = TLOC3
|
||||
ALTR = np.log(TLOC3/TLOC2)
|
||||
FACT2 = FACT1 * SUM2
|
||||
HSIGN = 1
|
||||
else:
|
||||
T500 = TLOC3
|
||||
TEMP[1] = TLOC4
|
||||
ALTR = np.log(TLOC4/TLOC2)
|
||||
FACT2 = FACT1 * (SUM2 + SUM3)
|
||||
HSIGN = -1
|
||||
|
||||
ALN[:-1] -= (1 + ALPHA) * ALTR + FACT2 * AMW[:-1]
|
||||
# Equation (7) - Note that in CIRA72, AL10T5 = DLOG10(T500)
|
||||
AL10T5 = np.log10(TINF)
|
||||
ALNH5 = (5.5 * AL10T5 - 39.4) * AL10T5 + 73.13
|
||||
ALN[5] = AL10 * (ALNH5 + 6) + HSIGN * (np.log(TLOC4/TLOC3) + FACT1 * SUM3 * AMW[5])
|
||||
|
||||
# Equation (24) - J70 Seasonal-Latitudinal Variation
|
||||
TRASH = (AMJD - 36204) / 365.2422
|
||||
CAPPHI = TRASH%1
|
||||
DLRSL = 0.02 * (SAT[2] - 90) * np.exp(-0.045 * (SAT[2] - 90)) * np.sign(SAT[1]) * np.sin(TWOPI * CAPPHI+ 1.72) * np.sin(SAT[1])**2
|
||||
|
||||
# Equation (23) - Computes the semiannual variation
|
||||
DLRSA = 0
|
||||
if Z < 2e3:
|
||||
# Use new semiannual model
|
||||
FZZ,GTZ,DLRSA = SEMIAN08(YRDAY,ZHT,F10B,S10B,M10B)
|
||||
if FZZ < 0: DLRSA = 0
|
||||
|
||||
# Sum the delta-log-rhos and apply to the number densities.
|
||||
# In CIRA72 the following equation contains an actual sum, namely DLR = AL10 * (DLRGM + DLRSA + DLRSL)
|
||||
# However, for Jacchia 70, there is no DLRGM or DLRSA.
|
||||
|
||||
DLR = AL10 * (DLRSL + DLRSA)
|
||||
ALN += DLR
|
||||
# Compute mass-density and mean-molecular-weight and convert number density logs from natural to common.
|
||||
AN = np.exp(ALN)
|
||||
SUMNM = (AN*AMW).sum()
|
||||
AL10N = ALN/AL10
|
||||
RHO = SUMNM/AVOGAD
|
||||
|
||||
# Compute the high altitude exospheric density correction factor
|
||||
FEX = 1
|
||||
|
||||
if ZHT >= 1e3 and ZHT < 1.5e3:
|
||||
ZETA = (ZHT - 1e3) * 0.002
|
||||
ZETA2 = ZETA**2
|
||||
ZETA3 = ZETA**3
|
||||
F15C = CHT[0] + CHT[1]*F10B + (CHT[2] + CHT[3]*F10B)*1.5e3
|
||||
F15C_ZETA = (CHT[2] + CHT[3]*F10B) * 500
|
||||
FEX2 = 3 * F15C - F15C_ZETA - 3
|
||||
FEX3 = F15C_ZETA - 2 * F15C + 2
|
||||
FEX = 1 + FEX2 * ZETA2 + FEX3 * ZETA3
|
||||
|
||||
if ZHT >= 1.5e3: FEX = CHT[0] + CHT[1]*F10B + CHT[2]*ZHT + CHT[3]*F10B*ZHT
|
||||
|
||||
# Apply the exospheric density correction factor.
|
||||
RHO *= FEX
|
||||
|
||||
return TEMP,RHO
|
||||
|
||||
@jit(nopython=True)
|
||||
def XAMBAR(Z):
|
||||
'''
|
||||
Evaluates Equation (1)
|
||||
'''
|
||||
C = np.array([28.15204,-8.5586e-2,1.2840e-4,-1.0056e-5,-1.0210e-5,1.5044e-6,9.9826e-8])
|
||||
DZ = Z - 100
|
||||
AMB = C[6]
|
||||
for i in range(5,-1,-1): AMB = DZ * AMB + C[i]
|
||||
return AMB
|
||||
|
||||
@jit(nopython=True)
|
||||
def XGRAV(Z):
|
||||
'''
|
||||
Evaluates Equation (8)
|
||||
'''
|
||||
return 9.80665/(1 + Z/6356.766)**2
|
||||
|
||||
@jit(nopython=True)
|
||||
def XLOCAL(Z,TC):
|
||||
'''
|
||||
Evaluates Equation (10) or Equation (13), depending on Z
|
||||
'''
|
||||
DZ = Z - 125
|
||||
if DZ > 0:
|
||||
XLOCAL = TC[0] + TC[2] * np.arctan(TC[3]*DZ*(1 + 4.5e-6*DZ**2.5))
|
||||
else:
|
||||
XLOCAL = ((-9.8204695e-6 * DZ - 7.3039742e-4) * DZ**2 + 1)* DZ * TC[1] + TC[0]
|
||||
return XLOCAL
|
||||
|
||||
@jit(nopython=True)
|
||||
def DTSUB (F10,XLST,XLAT,ZHT):
|
||||
'''
|
||||
COMPUTE dTc correction for Jacchia-Bowman model
|
||||
|
||||
Calling Args:
|
||||
|
||||
F10 = (I) F10 FLUX
|
||||
XLST = (I) LOCAL SOLAR TIME (HOURS 0-23.999)
|
||||
XLAT = (I) XLAT = SAT LAT (RAD)
|
||||
ZHT = (I) ZHT = HEIGHT (KM)
|
||||
DTC = (O) dTc correction
|
||||
'''
|
||||
B = np.array([-4.57512297, -5.12114909, -69.3003609,\
|
||||
203.716701, 703.316291, -1943.49234,\
|
||||
1106.51308, -174.378996, 1885.94601,\
|
||||
-7093.71517, 9224.54523, -3845.08073,\
|
||||
-6.45841789, 40.9703319, -482.006560,\
|
||||
1818.70931, -2373.89204, 996.703815,36.1416936])
|
||||
C = np.array([-15.5986211, -5.12114909, -69.3003609,\
|
||||
203.716701, 703.316291, -1943.49234,\
|
||||
1106.51308, -220.835117, 1432.56989,\
|
||||
-3184.81844, 3289.81513, -1353.32119,\
|
||||
19.9956489, -12.7093998, 21.2825156,\
|
||||
-2.75555432, 11.0234982, 148.881951,\
|
||||
-751.640284, 637.876542, 12.7093998,\
|
||||
-21.2825156, 2.75555432])
|
||||
DTC = 0
|
||||
tx = XLST/24
|
||||
ycs = np.cos(XLAT)
|
||||
F = (F10 - 100)/100
|
||||
|
||||
# calculates dTc
|
||||
if ZHT >= 120 and ZHT <= 200:
|
||||
H = (ZHT - 200)/50
|
||||
DTC200 = C[16] + C[17]*tx*ycs + C[18]*tx**2*ycs + C[19]*tx**3*ycs + C[20]*F*ycs + C[21]*tx*F*ycs + C[22]*tx**2*F*ycs
|
||||
|
||||
sum_ = C[0] + B[1]*F + C[2]*tx*F + C[3]*tx**2*F + C[4]*tx**3*F + C[5]*tx**4*F + C[6]*tx**5*F +\
|
||||
C[7]*tx*ycs + C[8]*tx**2*ycs + C[9]*tx**3*ycs + C[10]*tx**4*ycs + C[11]*tx**5*ycs + C[12]*ycs+\
|
||||
C[13]*F*ycs + C[14]*tx*F*ycs + C[15]*tx**2*F*ycs
|
||||
|
||||
DTC200DZ = sum_
|
||||
CC = 3*DTC200 - DTC200DZ
|
||||
DD = DTC200 - CC
|
||||
ZP = (ZHT-120)/80
|
||||
DTC = CC*ZP*ZP + DD*ZP*ZP*ZP
|
||||
|
||||
if ZHT > 200 and ZHT <= 240:
|
||||
H = (ZHT - 200)/50
|
||||
sum_ = C[0]*H + B[1]*F*H + C[2]*tx*F*H + C[3]*tx**2*F*H + C[4]*tx**3*F*H + C[5]*tx**4*F*H + C[6]*tx**5*F*H+\
|
||||
C[7]*tx*ycs*H + C[8]*tx**2*ycs*H + C[9]*tx**3*ycs*H + C[10]*tx**4*ycs*H + C[11]*tx**5*ycs*H + C[12]*ycs*H+\
|
||||
C[13]*F*ycs*H + C[14]*tx*F*ycs*H + C[15]*tx**2*F*ycs*H + C[16] + C[17]*tx*ycs + C[18]*tx**2*ycs +\
|
||||
C[19]*tx**3*ycs + C[20]*F*ycs + C[21]*tx*F*ycs + C[22]*tx**2*F*ycs
|
||||
DTC = sum_
|
||||
|
||||
if ZHT > 240 and ZHT <= 300.0:
|
||||
H = 0.8
|
||||
sum_ = C[0]*H + B[1]*F*H + C[2]*tx*F*H + C[3]*tx**2*F*H + C[4]*tx**3*F*H + C[5]*tx**4*F*H + C[6]*tx**5*F*H +\
|
||||
C[7]*tx*ycs*H + C[8]*tx**2*ycs*H + C[9]*tx**3*ycs*H + C[10]*tx**4*ycs*H + C[11]*tx**5*ycs*H + C[12]*ycs*H+\
|
||||
C[13]*F*ycs*H + C[14]*tx*F*ycs*H + C[15]*tx**2*F*ycs*H + C[16] + C[17]*tx*ycs + C[18]*tx**2*ycs +\
|
||||
C[19]*tx**3*ycs + C[20]*F*ycs + C[21]*tx*F*ycs + C[22]*tx**2*F*ycs
|
||||
AA = sum_
|
||||
BB = C[0] + B[1]*F + C[2]*tx*F + C[3]*tx**2*F + C[4]*tx**3*F + C[5]*tx**4*F + C[6]*tx**5*F +\
|
||||
C[7]*tx*ycs + C[8]*tx**2*ycs + C[9]*tx**3*ycs + C[10]*tx**4*ycs + C[11]*tx**5*ycs + C[12]*ycs +\
|
||||
C[13]*F*ycs + C[14]*tx*F*ycs + C[15]*tx**2*F*ycs
|
||||
H = 3
|
||||
sum_ = B[0] + B[1]*F + B[2]*tx*F + B[3]*tx**2*F + B[4]*tx**3*F + B[5]*tx**4*F + B[6]*tx**5*F + \
|
||||
B[7]*tx*ycs + B[8]*tx**2*ycs + B[9]*tx**3*ycs + B[10]*tx**4*ycs + B[11]*tx**5*ycs + B[12]*H*ycs +\
|
||||
B[13]*tx*H*ycs + B[14]*tx**2*H*ycs + B[15]*tx**3*H*ycs + B[16]*tx**4*H*ycs + B[17]*tx**5*H*ycs + B[18]*ycs
|
||||
DTC300 = sum_
|
||||
sum_ = B[12]*ycs + B[13]*tx*ycs + B[14]*tx**2*ycs + B[15]*tx**3*ycs + B[16]*tx**4*ycs + B[17]*tx**5*ycs
|
||||
DTC300DZ = sum_
|
||||
CC = 3*DTC300 - DTC300DZ - 3*AA - 2*BB
|
||||
DD = DTC300 - AA - BB - CC
|
||||
ZP = (ZHT-240)/60
|
||||
DTC = AA + BB*ZP + CC*ZP*ZP + DD*ZP*ZP*ZP
|
||||
|
||||
if ZHT > 300 and ZHT <= 600:
|
||||
H = ZHT/100
|
||||
sum_ = B[0] + B[1]*F + B[2]*tx*F + B[3]*tx**2*F + B[4]*tx**3*F + B[5]*tx**4*F + B[6]*tx**5*F +\
|
||||
B[7]*tx*ycs + B[8]*tx**2*ycs + B[9]*tx**3*ycs + B[10]*tx**4*ycs + B[11]*tx**5*ycs + B[12]*H*ycs +\
|
||||
B[13]*tx*H*ycs + B[14]*tx**2*H*ycs + B[15]*tx**3*H*ycs + B[16]*tx**4*H*ycs + B[17]*tx**5*H*ycs + B[18]*ycs
|
||||
DTC = sum_
|
||||
|
||||
if ZHT > 600 and ZHT <= 800.0:
|
||||
ZP = (ZHT - 600)/100
|
||||
HP = 6
|
||||
AA = B[0] + B[1]*F + B[2]*tx*F + B[3]*tx**2*F + B[4]*tx**3*F + B[5]*tx**4*F + B[6]*tx**5*F +\
|
||||
B[7]*tx*ycs + B[8]*tx**2*ycs + B[9]*tx**3*ycs + B[10]*tx**4*ycs + B[11]*tx**5*ycs + B[12]*HP*ycs +\
|
||||
B[13]*tx*HP*ycs + B[14]*tx**2*HP*ycs+ B[15]*tx**3*HP*ycs + B[16]*tx**4*HP*ycs + B[17]*tx**5*HP*ycs + B[18]*ycs
|
||||
BB = B[12]*ycs + B[13]*tx*ycs + B[14]*tx**2*ycs + B[15]*tx**3*ycs + B[16]*tx**4*ycs + B[17]*tx**5*ycs
|
||||
CC = -(3*AA+4*BB)/4
|
||||
DD = (AA+BB)/4
|
||||
DTC = AA + BB*ZP + CC*ZP*ZP + DD*ZP*ZP*ZP
|
||||
return DTC
|
||||
|
||||
@jit(nopython=True)
|
||||
def SEMIAN08 (DAY,HT,F10B,S10B,M10B):
|
||||
'''
|
||||
COMPUTE SEMIANNUAL VARIATION (DELTA LOG RHO)
|
||||
|
||||
INPUT DAY, HEIGHT, F10B, S10B, M10B FSMB
|
||||
025. 650. 150. 148. 147. 151.
|
||||
OUTPUT FUNCTIONS FZ, GT, AND DEL LOG RHO VALUE
|
||||
|
||||
DAY (I) DAY OF YEAR
|
||||
HT (I) HEIGHT (KM)
|
||||
F10B (I) AVE 81-DAY CENTERED F10
|
||||
S10B (I) AVE 81-DAY CENTERED S10
|
||||
M10B (I) AVE 81-DAY CENTERED M10
|
||||
FZZ (O) SEMIANNUAL AMPLITUDE
|
||||
GTZ (O) SEMIANNUAL PHASE FUNCTION
|
||||
DRLOG (O) DELTA LOG RHO
|
||||
'''
|
||||
TWOPI = Const.twopi
|
||||
|
||||
# FZ GLOBAL MODEL VALUES
|
||||
# 1997-2006 FIT:
|
||||
FZM = np.array([0.2689,-0.01176, 0.02782,-0.02782, 0.3470e-3])
|
||||
|
||||
# GT GLOBAL MODEL VALUES
|
||||
# 1997-2006 FIT:
|
||||
GTM = np.array([-0.3633, 0.08506, 0.2401,-0.1897, -0.2554,-0.01790, 0.5650e-3,-0.6407e-3,-0.3418e-2,-0.1252e-2])
|
||||
|
||||
# COMPUTE NEW 81-DAY CENTERED SOLAR INDEX FOR FZ
|
||||
FSMB = F10B - 0.7*S10B - 0.04*M10B
|
||||
HTZ = HT/1e3
|
||||
FZZ = FZM[0] + FZM[1]*FSMB + FZM[2]*FSMB*HTZ + FZM[3]*FSMB*HTZ**2 + FZM[4]*FSMB**2*HTZ
|
||||
|
||||
# COMPUTE DAILY 81-DAY CENTERED SOLAR INDEX FOR GT
|
||||
FSMB = F10B - 0.75*S10B - 0.37*M10B
|
||||
|
||||
TAU = (DAY-1)/365
|
||||
SIN1P = np.sin(TWOPI*TAU)
|
||||
COS1P = np.cos(TWOPI*TAU)
|
||||
SIN2P = np.sin(2*TWOPI*TAU)
|
||||
COS2P = np.cos(2*TWOPI*TAU)
|
||||
|
||||
GTZ = GTM[0] + GTM[1]*SIN1P + GTM[2]*COS1P + GTM[3]*SIN2P + GTM[4]*COS2P + GTM[5]*FSMB + GTM[6]*FSMB*SIN1P + GTM[7]*FSMB*COS1P + GTM[8]*FSMB*SIN2P + GTM[9]*FSMB*COS2P
|
||||
if FZZ < 1e-6: FZZ = 1e-6
|
||||
DRLOG = FZZ*GTZ
|
||||
|
||||
return FZZ,GTZ,DRLOG
|
58
pyatmos/jb2008/jb2008.py
Normal file
58
pyatmos/jb2008/jb2008.py
Normal file
@ -0,0 +1,58 @@
|
||||
import numpy as np
|
||||
from astropy.coordinates import get_sun
|
||||
from astropy.time import Time
|
||||
|
||||
from .JB2008_subfunc import JB2008
|
||||
from .spaceweather import get_sw
|
||||
from ..utils.utils import ydhms_days
|
||||
from ..class_atmos import ATMOS
|
||||
|
||||
def jb2008(t,location,swdata):
|
||||
"""
|
||||
JB2008 is an empirical, global reference atmospheric model of the Earth from 90 km above the sea level to the exosphere up to 2500 km.
|
||||
A primary use of this model is to aid predictions of satellite orbital decay due to the atmospheric drag.
|
||||
|
||||
Usage:
|
||||
jb08 = jb2008(t,(lat,lon,alt),swdata)
|
||||
|
||||
Inputs:
|
||||
t -> [str] time(UTC)
|
||||
location -> [tuple/list] geodetic latitude[degree], longitude[degree], and altitude[km]
|
||||
|
||||
Output:
|
||||
jb08 -> instance of class ATMOS, where its attributes include
|
||||
rho -> [float] total mass density[kg/m^3]
|
||||
T -> [tuple] local temperature[K]
|
||||
|
||||
Examples:
|
||||
>>> from pyatmos import download_sw_jb2008,read_sw_jb2008
|
||||
>>> # Download or update the space weather file from https://sol.spacenvironment.net
|
||||
>>> swfile = download_sw_jb2008()
|
||||
>>> # Read the space weather data
|
||||
>>> swdata = read_sw_jb2008(swfile)
|
||||
>>>
|
||||
>>> from pyatmos import jb2008
|
||||
>>> # Set a specific time and location
|
||||
>>> t = '2014-07-22 22:18:45' # time(UTC)
|
||||
>>> lat,lon,alt = 25,102,600 # latitude, longitude in [degree], and altitude in [km]
|
||||
>>> jb08 = jb2008(t,(lat,lon,alt),swdata)
|
||||
>>> print(jb08.rho) # [kg/m^3]
|
||||
>>> print(jb08.T) # [K]
|
||||
"""
|
||||
|
||||
lat,lon,h = location
|
||||
t = Time(t,location=(str(lon)+'d',str(lat)+'d'))
|
||||
AMJD = t.mjd
|
||||
ydhms = np.array(t.yday.split(':'),dtype=float)
|
||||
YRDAY = ydhms_days(ydhms)
|
||||
sunpos = get_sun(t)
|
||||
SUN = (sunpos.ra.rad,sunpos.dec.rad)
|
||||
sat_ra = t.sidereal_time('mean').rad
|
||||
SAT = (sat_ra,np.deg2rad(lat),h)
|
||||
|
||||
F10,F10B,S10,S10B,M10,M10B,Y10,Y10B,DTCVAL = get_sw(swdata,AMJD)
|
||||
TEMP,RHO = JB2008(AMJD,YRDAY,SUN,SAT,F10,F10B,S10,S10B,M10,M10B,Y10,Y10B,DTCVAL)
|
||||
|
||||
info = {'rho':RHO,'T':TEMP[1]}
|
||||
|
||||
return ATMOS(info)
|
131
pyatmos/jb2008/spaceweather.py
Normal file
131
pyatmos/jb2008/spaceweather.py
Normal file
@ -0,0 +1,131 @@
|
||||
import numpy as np
|
||||
from datetime import datetime,timedelta
|
||||
from os import path,makedirs,remove
|
||||
from pathlib import Path
|
||||
|
||||
from ..utils.try_download import tqdm_request
|
||||
from ..utils import Const
|
||||
|
||||
def download_sw_jb2008(direc=None):
|
||||
'''
|
||||
Download or update the space weather data from www.celestrak.com
|
||||
|
||||
Usage:
|
||||
swfile = download_sw([direc])
|
||||
|
||||
Inputs:
|
||||
direc -> [str, optional] Directory for storing the space weather data
|
||||
|
||||
Outputs:
|
||||
swfile -> [str] Path of the space weather data
|
||||
|
||||
Examples:
|
||||
>>> swfile = download_sw()
|
||||
>>> swfile = download_sw('sw-data/')
|
||||
'''
|
||||
|
||||
if direc is None:
|
||||
home = str(Path.home())
|
||||
direc = home + '/src/sw-data/'
|
||||
|
||||
swfile1 = direc + 'SOLFSMY.TXT'
|
||||
url1 = 'https://sol.spacenvironment.net/JB2008/indices/SOLFSMY.TXT'
|
||||
|
||||
# The file DTCFILE.TXT is generated from DSTFILE.TXT and SOLRESAP.TXT
|
||||
swfile2 = direc + 'DTCFILE.TXT'
|
||||
url2 = 'https://sol.spacenvironment.net/JB2008/indices/DTCFILE.TXT'
|
||||
|
||||
if not path.exists(direc): makedirs(direc)
|
||||
if not path.exists(swfile1):
|
||||
desc1 = 'Downloading the space weather data {:s} from Space Environment Technologies(SET)'.format('SOLFSMY.TXT')
|
||||
desc2 = 'Downloading the space weather data {:s} from Space Environment Technologies(SET)'.format('DTCFILE.TXT')
|
||||
tqdm_request(url1,direc,'SOLFSMY.TXT',desc1)
|
||||
tqdm_request(url2,direc,'DTCFILE.TXT',desc2)
|
||||
else:
|
||||
modified_time = datetime.fromtimestamp(path.getmtime(swfile1))
|
||||
if datetime.now() > modified_time + timedelta(days=1):
|
||||
remove(swfile1)
|
||||
remove(swfile2)
|
||||
desc1 = 'Updating the space weather data {:s} from Space Environment Technologies(SET)'.format('SOLFSMY.TXT')
|
||||
desc2 = 'Updating the space weather data {:s} from Space Environment Technologies(SET)'.format('DTCFILE.TXT')
|
||||
tqdm_request(url1,direc,'SOLFSMY.TXT',desc1)
|
||||
tqdm_request(url2,direc,'DTCFILE.TXT',desc2)
|
||||
else:
|
||||
print('The space weather data in {:s} is already the latest.'.format(direc))
|
||||
return [swfile1,swfile2]
|
||||
|
||||
def read_sw_jb2008(swfile):
|
||||
'''
|
||||
Parse and read the space weather data
|
||||
|
||||
Usage:
|
||||
sw_obs_pre = read_sw(swfile)
|
||||
|
||||
Inputs:
|
||||
swfile -> [str] Path of the space weather data
|
||||
|
||||
Outputs:
|
||||
sw_obs_pre -> [2d str array] Content of the space weather data
|
||||
|
||||
Examples:
|
||||
>>> swfile = 'sw-data/SW-All.txt'
|
||||
>>> sw_obs_pre = read_sw(swfile)
|
||||
>>> print(sw_obs_pre)
|
||||
[['2020' '01' '07' ... '72.4' '68.0' '71.0']
|
||||
['2020' '01' '06' ... '72.4' '68.1' '70.9']
|
||||
...
|
||||
...
|
||||
['1957' '10' '02' ... '253.3' '267.4' '231.7']
|
||||
['1957' '10' '01' ... '269.3' '266.6' '230.9']]
|
||||
'''
|
||||
swfile1,swfile2 = swfile
|
||||
sw_data1 = np.loadtxt(swfile1,usecols=range(2,11))
|
||||
sw_data2 = np.loadtxt(swfile2,usecols=range(3,27),dtype=int)
|
||||
|
||||
return (sw_data1,sw_data2)
|
||||
|
||||
def get_sw(sw_data,t_mjd):
|
||||
'''
|
||||
Extract the necessary parameters describing the solar activity and geomagnetic activity from the space weather data.
|
||||
INPUT T1950 AND READ FILE FOR VALUES FOR F10, S10, M10, AND Y10
|
||||
READ ONE TIME AND STORE ALL FILE VALUES IN COMMON FOR RETRIEVAL
|
||||
Usage:
|
||||
f107A,f107,ap,aph = get_sw(SW_OBS_PRE,t_ymd,hour)
|
||||
|
||||
Inputs:
|
||||
SW_OBS_PRE -> [2d str array] Content of the space weather data
|
||||
t_ymd -> [str array or list] ['year','month','day']
|
||||
hour -> []
|
||||
|
||||
Outputs:
|
||||
f107A -> [float] 81-day average of F10.7 flux
|
||||
f107 -> [float] daily F10.7 flux for previous day
|
||||
ap -> [int] daily magnetic index
|
||||
aph -> [float array] 3-hour magnetic index
|
||||
|
||||
Examples:
|
||||
>>> f107A,f107,ap,aph = get_sw(SW_OBS_PRE,t_ymd,hour)
|
||||
'''
|
||||
sw_data1,sw_data2 = sw_data
|
||||
sw_mjd = sw_data1[:,0] - 2400000.5
|
||||
J_, = np.where(sw_mjd-0.5 < t_mjd)
|
||||
j = J_[-1]
|
||||
|
||||
# USE 1 DAY LAG FOR F10 AND S10 FOR JB2008
|
||||
dlag = j-1
|
||||
F10,F10B,S10,S10B = sw_data1[dlag,1:5]
|
||||
|
||||
# USE 2 DAY LAG FOR M10 FOR JB2008
|
||||
dlag = j-2
|
||||
M10,M10B = sw_data1[dlag,5:7]
|
||||
|
||||
# USE 5 DAY LAG FOR Y10 FOR JB2008
|
||||
dlag = j-5
|
||||
Y10,Y10B = sw_data1[dlag,7:9]
|
||||
|
||||
t_dmjd = t_mjd - sw_mjd[j] + 0.5
|
||||
x = Const.x
|
||||
y = sw_data2[j:j+2].flatten()
|
||||
DTCVAL = np.interp(t_dmjd,x,y)
|
||||
|
||||
return F10,F10B,S10,S10B,M10,M10B,Y10,Y10B,DTCVAL
|
Loading…
x
Reference in New Issue
Block a user