Skip to content

Commit ab447bc

Browse files
committed
Pushing to glowpython2
1 parent 8940f42 commit ab447bc

File tree

4 files changed

+112
-8
lines changed

4 files changed

+112
-8
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"autoDocstringPy.customTemplatePath": ".vscode/docstring.mustache",
33
"files.associations": {
4-
"*.f": "FortranFixedForm"
4+
"*.f": "FortranFixedForm",
5+
"*.f90": "FortranFreeForm"
56
},
67
"[FortranFixedForm]": {
78
"editor.rulers": [

src/GLOW/rcolum.f90

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
! grazing height is lower than the bottom of the atmosphere supplied,
2323
! column densities are set to 'infinity', i.e., 1.0e30.
2424

25+
! Input:
26+
! CHI Zenith angle (radians)
27+
! ZZ Altitude array; cm [jmax]
28+
! ZMAJ Major species number densities (O, O2, N2); cm-3 [nmaj,jmax]
29+
! TN Neutral temperature at each altitude; K [jmax]
30+
! ZCOL Slant column density (O, O2, N2); cm-2 [nmaj,jmax]
31+
! ZVCD Vertical column density (O, O2, N2) above each altitude (cumsum); cm-2 [nmaj,jmax]
2532

2633
subroutine rcolum (chi, zz, zmaj, tn, zcol, zvcd, jmax, nmaj)
2734

@@ -88,6 +95,7 @@ end subroutine rcolum
8895

8996
!----------------------------------------------------------------------
9097

98+
! Calculate Chapman Grazing Incidence Integral
9199
real function chap (chi, z, t, i)
92100

93101
implicit none
@@ -97,18 +105,18 @@ real function chap (chi, z, t, i)
97105

98106
integer,parameter :: nmaj=3
99107
real,parameter :: pi=3.1415926536
100-
real,parameter :: re=6.37e8
101-
real,parameter :: g=978.1
108+
real,parameter :: re=6.37e8 ! cm
109+
real,parameter :: g=978.1 ! cm/s^2
102110

103111
real :: am(nmaj), gr, hn, hg, hf, sqhf
104112
real,external :: sperfc
105113

106114
data am/16., 32., 28./
107115

108-
gr=g*(re/(re+z))**2
109-
hn=1.38e-16*t/(am(i)*1.662e-24*gr)
110-
hg=(re+z)/hn
111-
hf=0.5*hg*(cos(chi)**2)
116+
gr=g*(re/(re+z))**2 ! effective g
117+
hn=1.38e-16*t/(am(i)*1.662e-24*gr) ! k_B * T / mass (amu * grams/amu or Dalton) * g
118+
hg=(re+z)/hn ! gravitational scale height
119+
hf=0.5*hg*(cos(chi)**2)
112120
sqhf=sqrt(hf)
113121
chap=sqrt(0.5*pi*hg)*sperfc(sqhf)
114122

@@ -137,6 +145,9 @@ end function sperfc
137145

138146
!----------------------------------------------------------------------
139147

148+
!Subroutine VCD
149+
! Calculates the cumulative vertical column density
150+
! for each species ZMAJ above each altitude ZZ.
140151
subroutine vcd(zz,zmaj,zvcd,jmax,nmaj)
141152

142153
implicit none
@@ -155,7 +166,7 @@ subroutine vcd(zz,zmaj,zvcd,jmax,nmaj)
155166
/ alog(zmaj(i,jmax-1)/zmaj(i,jmax))
156167
do j=jmax-1,1,-1
157168
rat = zmaj(i,j+1) / zmaj(i,j)
158-
zvcd(i,j) = zvcd(i,j+1)+zmaj(i,j)*(zz(j)-zz(j+1))/alog(rat)*(1.-rat)
169+
zvcd(i,j) = zvcd(i,j+1)+zmaj(i,j)*(zz(j)-zz(j+1))/alog(rat)*(1.0-rat)
159170
enddo
160171
enddo
161172

src/glowpython/rcolum.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# %%
2+
from __future__ import annotations
3+
from xarray import DataArray, Variable
4+
from typing import List, Tuple, Union, SupportsFloat as Numeric
5+
import numpy as np
6+
7+
# %%
8+
def rcolumn(
9+
major_den: DataArray,
10+
t_n: DataArray,
11+
chi: Numeric,
12+
) -> Tuple[DataArray, DataArray]:
13+
"""## Calculates the column density for each species at zenith angle `chi`.
14+
First, the vertical column density is calculated, and then a fit to Chapman Grazing
15+
Incidence Integral [Smith and Smith, JGR 77, 3592, 1972] is used to calculate the
16+
slant column density.
17+
- `chi` < 90 deg: Column densities are calculated directly.
18+
- `chi` > 90 deg: Column density at grazing height for 90 deg is calculated and doubled, and the column density above the grazing height is subtracted.
19+
- If grazing height is lower than the bottom of the atmosphere supplied, column densities are set to infinity (`np.inf`).
20+
21+
### Args:
22+
- `major_den (DataArray)`: Major species densities.
23+
- `t_n (DataArray)`: Neutral temperature profile.
24+
- `chi (Numeric)`: Zenith angle.
25+
26+
### Returns:
27+
- `Tuple[DataArray, DataArray]`: Column densities, vertical column densities.
28+
"""

src/glowpython/sflux.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# %%
2+
from __future__ import annotations
3+
from pathlib import Path
4+
from typing import Literal, Sequence, Tuple, Union, SupportsFloat as Numeric
5+
import numpy as np
6+
from .base import FluxSource, DATA_DIR
7+
from .glowfort import cglow as cg # type: ignore
8+
9+
# %%
10+
class Sflux:
11+
def __init__(self, kind: FluxSource | Tuple[Sequence[float], Sequence[float], Sequence[float]], data_dir: Path = DATA_DIR):
12+
self._kind = kind
13+
self._docalc = True
14+
if kind == 'Hinteregger':
15+
self._method = 'Hinteregger'
16+
ifile = data_dir / 'ssflux_hint.dat'
17+
self._data = np.loadtxt(ifile, skiprows=1)[::-1, :].T # reverse order
18+
self._fluxmask = self._data[0] < 251 & self._data[0] > 17 # 17-251 nm
19+
cg.wave1 = self._data[0]
20+
cg.wave2 = self._data[1]
21+
elif kind == 'EUVAC':
22+
self._method = 'EUVAC'
23+
ifile = data_dir / 'ssflux_euvac.dat'
24+
self._data = np.loadtxt(ifile, skiprows=1)[::-1, :].T # reverse order
25+
self._fluxmask = self._data[0] < 51 & self._data[0] > 1 # 1-51 nm
26+
cg.wave1 = self._data[0]
27+
cg.wave2 = self._data[1]
28+
elif isinstance(kind, tuple):
29+
self._method = 'custom'
30+
self._data = np.stack(kind, axis=0)
31+
if self._data.ndim != 2:
32+
raise ValueError(f"Custom flux data must be 2D, got {self._data.ndim}D.")
33+
if self._data.shape[1] != 3:
34+
raise ValueError(f"Custom flux data must have 3 columns, got {self._data.shape[1]}.")
35+
if self._data.shape[0] != 123:
36+
raise ValueError(f"Custom flux data must have 123 wavelength bins, got {self._data.shape[0]}.")
37+
if self._data[1, 0] > self._data[0, 0]:
38+
self._data = self._data[::-1, :] # reverse order
39+
cg.wave1 = self._data[:, 0]
40+
cg.wave2 = self._data[:, 1]
41+
self._docalc = False
42+
else:
43+
raise ValueError(f"Unknown flux source: {kind}. Must be 'Hinteregger', 'EUVAC', or a tuple of values.")
44+
45+
def update(self, f107: Numeric, f107a: Numeric, xuvfac: int = 3) -> None:
46+
if self._docalc:
47+
if self._data.shape[1] == 5: # Hinteregger
48+
r1 = 0.0138*(f107a - 71.5) + 0.005*(f107 - f107a + 3.9) # + 1
49+
r2 = 0.59425*(f107a - 71.5) + 0.3811*(f107 - f107a + 3.9) # + 1
50+
sflux = self._data[2] + r1 * self._data[3] + r2 * self._data[4]
51+
np.clip(sflux, 0, None, out=sflux)
52+
if xuvfac > 1e-6:
53+
sflux[self._fluxmask] *= xuvfac
54+
elif self._data.shape[1] == 4: # EUVAC
55+
p107 = (f107 + f107a)*0.5
56+
sflux = self._data[2] * (1 + self._data[3]*(p107 - 80))
57+
np.clip(sflux, 0.1*self._data[2], None, out=sflux)
58+
if xuvfac > 1e-6:
59+
sflux[self._fluxmask] *= xuvfac
60+
cg.sflux = sflux
61+
else:
62+
# Set the cg.wave1, cg.wave2, cg.sflux to these values
63+
cg.sflux = self._data[:, 2]
64+
# %%

0 commit comments

Comments
 (0)