Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
NOCSurfaceProcesses
AirSeaFluxCode
Commits
22be86dd
Commit
22be86dd
authored
5 years ago
by
sbiri
Browse files
Options
Download
Email Patches
Plain Diff
UA and ERA5 algorithms added
parent
9b617551
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
985 additions
and
350 deletions
+985
-350
flux_calc_v3.py
flux_calc_v3.py
+417
-266
flux_subs.py
flux_subs.py
+568
-84
No files found.
flux_calc_v3.py
View file @
22be86dd
import
numpy
as
np
import
numpy
as
np
import
sys
import
sys
import
logging
import
logging
from
flux_subs
import
get_heights
,
cdn_calc
,
cd_calc
,
get_skin
,
psim_calc
,
\
from
flux_subs
import
(
kappa
,
CtoK
,
get_heights
,
cdn_calc
,
cd_calc
,
get_skin
,
psit_calc
,
ctcq_calc
,
ctcqn_calc
,
get_gust
,
gc
,
q_calc
,
qsea_calc
,
qsat26sea
,
qsat26air
,
\
psim_calc
,
psit_calc
,
ctcq_calc
,
ctcqn_calc
,
get_gust
,
visc_air
,
psit_26
,
psiu_26
,
psiu_40
,
cd_C35
gc
,
q_calc
,
qsea_calc
,
qsat26sea
,
qsat26air
,
visc_air
,
psit_26
,
psiu_26
,
psiu_40
,
cd_C35
,
charnock_C35
)
def
flux_calc_v3
(
spd
,
T
,
SST
,
lat
,
RH
,
P
,
hin
,
hout
,
wcp
,
sigH
,
zi
=
600
,
\
Rl
=
None
,
Rs
=
None
,
jcool
=
1
,
method
=
"Smith80"
,
n
=
20
):
def
flux_calc_v3_1
(
spd
,
T
,
SST
,
lat
,
RH
,
P
,
hin
,
hout
,
wcp
,
sigH
,
zi
=
600
,
"""
Rl
=
None
,
Rs
=
None
,
jcool
=
1
,
meth
=
"S88"
,
n
=
10
):
inputs:
""" Calculates momentum and heat fluxes using different parameterizations
flux method ("Smith80","Smith88","LP82","HEXOS","HEXOSwave","YT96","COARE3.0","COARE3.5","LY04")
spd : relative wind speed in m/s (is assumed as magnitude difference between wind
Parameters
and surface current vectors)
----------
T : air temperature in K (will convert if < 200)
meth : str
SST : sea surface temperature in K (will convert if < 200)
"S80","S88","LP82","YT96","UA","HEXOS","HEXOSwave",
lat : latitude
"LY04","C30","C35","ERA5"
rh : relative humidity in %, default 80% for C35
spd : float
P : air pressure, default 1013 for C35
relative wind speed in m/s (is assumed as magnitude difference
hin : sensor heights in m (array of 1->3 values: 1 -> u=t=q; 2 -> u,t=q; 3 -> u,t,q ) default 10m
between wind and surface current vectors)
hout: default heights are 10m
T : float
wcp : phase speed of dominant waves (m/s) called in COARE3.5
air temperature in K (will convert if < 200)
sigH: significant wave height (m) called in COARE3.5
SST : float
zi : PBL height (m) called in COARE3.5
sea surface temperature in K (will convert if < 200)
Rl : downward longwave radiation (W/m^2)
lat : float
Rs : downward shortwave radiation (W/m^2)
latitude (deg)
jcool: 0 if sst is true ocean skin temperature called in COARE3.5
RH : float
n : number of iterations, for COARE3.5 set to 10
relative humidity in %
outputs:
P : float
res : which contains 1. tau 2. sensible heat 3. latent heat 4. Monin-Obhukov length (monob)
air pressure
5. drag coefficient (cd) 6. neutral drag coefficient (cdn) 7. ct 8. ctn 9. cq 10. cqn
hin : float
11.tsrv 12. tsr 13. qsr 14. usr 15. psim 16. psit 17. u10n 18. t10n 19. tv10n
sensor heights in m (array of 1->3 values: 1 -> u=t=q; /
20. q10n 21. zo 22. zot 23. zoq 24. urefs 25.trefs 26. qrefs 27. iterations
2 -> u,t=q; 3 -> u,t,q ) default 10m
ind : the indices in the matrix for the points that did not converge after the maximum number of iterations
hout : float
based on bform.f and flux_calc.R modified and ported to python by S. Biri
output height, default is 10m
wcp : float
phase speed of dominant waves (m/s) called in C35
sigH : float
significant wave height (m) called in C35
zi : int
PBL height (m) called in C35
Rl : float
downward longwave radiation (W/m^2)
Rs : float
downward shortwave radiation (W/m^2)
jcool : bool
0 if sst is true ocean skin temperature called in C35
n : int
number of iterations, for C35 set to 10
out : str
format in which to save output ('output.nc' or None)
Returns
-------
res : array that contains
1. momentum flux (W/m^2)
2. sensible heat (W/m^2)
3. latent heat (W/m^2)
4. Monin-Obhukov length (mb)
5. drag coefficient (cd)
6. neutral drag coefficient (cdn)
7. heat exhange coefficient (ct)
8. neutral heat exhange coefficient (ctn)
9. moisture exhange coefficient (cq)
10. neutral moisture exhange coefficient (cqn)
11. star virtual temperature (tsrv)
12. star temperature (tsr)
13. star humidity (qsr)
14. star velocity (usr)
15. momentum stability function (psim)
16. heat stability funciton (psit)
17. 10m neutral velocity (u10n)
18. 10m neutral temperature (t10n)
19. 10m neutral virtual temperature (tv10n)
20. 10m neutral specific humidity (q10n)
21. surface roughness length (zo)
22. heat roughness length (zot)
23. moisture roughness length (zoq)
24. velocity at reference height (urefs)
25. temperature at reference height (trefs)
26. specific humidity at reference height (qrefs)
27. number of iterations until convergence
ind : int
the indices in the matrix for the points that did not converge
after the maximum number of iterations
The code is based on bform.f and flux_calc.R modified by S. Biri
"""
"""
logging
.
basicConfig
(
filename
=
'flux_calc.log'
,
level
=
logging
.
INFO
)
logging
.
basicConfig
(
filename
=
'flux_calc.log'
,
kappa
,
CtoK
=
0.4
,
273.16
# von Karman's constant; conversion factor from degC to K
format
=
'%(asctime)s %(message)s'
,
level
=
logging
.
INFO
)
ref_ht
,
tlapse
=
10
,
0.0098
# reference height, lapse rate
ref_ht
,
tlapse
=
10
,
0.0098
# reference height, lapse rate
hh_in
=
get_heights
(
hin
)
# heights of input measurements/fields
hh_in
=
get_heights
(
hin
)
# heights of input measurements/fields
hh_out
=
get_heights
(
hout
)
# desired height of output variables,default is 10
hh_out
=
get_heights
(
hout
)
# desired height of output variables
g
=
gc
(
lat
,
None
)
# acceleration due to gravity
if
np
.
all
(
np
.
isnan
(
lat
)):
# set latitude to 45deg if empty
ctn
,
ct
,
cqn
,
cq
=
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
,
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
,
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
,
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
lat
=
45
*
np
.
ones
(
np
.
shape
(
spd
))
g
=
gc
(
lat
,
None
)
# acceleration due to gravity
ctn
,
ct
,
cqn
,
cq
=
(
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
,
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
,
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
,
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
)
# if input values are nan break
# if input values are nan break
if
(
np
.
all
(
np
.
isnan
(
spd
))
or
np
.
all
(
np
.
isnan
(
T
))
or
np
.
all
(
np
.
isnan
(
SST
))):
if
(
np
.
all
(
np
.
isnan
(
spd
))
or
np
.
all
(
np
.
isnan
(
T
))
or
np
.
all
(
np
.
isnan
(
SST
))):
sys
.
exit
(
"input wind, T or SST is empty"
)
sys
.
exit
(
"input wind, T or SST is empty"
)
logging
.
debug
(
'all input is nan'
)
logging
.
debug
(
'all input is nan'
)
if
(
np
.
all
(
np
.
isnan
(
RH
))
or
np
.
all
(
np
.
isnan
(
P
))):
if
(
np
.
all
(
np
.
isnan
(
RH
))
and
meth
==
"C35"
):
if
(
method
==
"COARE3.5"
):
RH
=
np
.
ones
(
np
.
shape
(
spd
))
*
80
# if empty set to default for COARE3.5
RH
=
np
.
ones
(
np
.
shape
(
spd
))
*
80
else
:
P
=
np
.
ones
(
np
.
shape
(
spd
))
*
1013
sys
.
exit
(
"input RH is empty"
)
else
:
logging
.
debug
(
'input RH is empty'
)
sys
.
exit
(
"input RH or P is empty"
)
if
(
np
.
all
(
np
.
isnan
(
P
))
and
meth
==
"C35"
):
if
(
np
.
all
(
spd
[
~
np
.
isnan
(
spd
)]
==
0
)
and
method
!=
"COARE3.0"
):
P
=
np
.
ones
(
np
.
shape
(
spd
))
*
1013
# if empty set to default for COARE3.5
sys
.
exit
(
"wind cannot be zero when method other than COARE3.0"
)
else
:
logging
.
debug
(
'all velocity input is zero'
)
sys
.
exit
(
"input P is empty"
)
if
(
np
.
all
(
np
.
isnan
(
Rl
))
and
method
==
"COARE3.5"
):
logging
.
debug
(
'input P is empty'
)
Rl
=
np
.
ones
(
np
.
shape
(
spd
))
*
370
# set to default
if
(
np
.
all
(
np
.
isnan
(
Rl
))
and
meth
==
"C35"
):
if
(
np
.
all
(
np
.
isnan
(
Rs
))
and
method
==
"COARE3.5"
):
Rl
=
np
.
ones
(
np
.
shape
(
spd
))
*
370
# set to default for COARE3.5
Rs
=
np
.
ones
(
np
.
shape
(
spd
))
*
150
# set to default
if
(
np
.
all
(
np
.
isnan
(
Rs
))
and
meth
==
"C35"
):
if
(
np
.
all
(
np
.
isnan
(
zi
))
and
method
==
"COARE3.5"
):
Rs
=
np
.
ones
(
np
.
shape
(
spd
))
*
150
# set to default for COARE3.5
zi
=
600
# set to default
if
(
np
.
all
(
np
.
isnan
(
zi
))
and
meth
==
"C35"
):
### additional parameters for COARE3.5
zi
=
600
# set to default for COARE3.5
waveage
,
seastate
=
1
,
1
elif
((
np
.
all
(
np
.
isnan
(
zi
))
and
meth
==
"ERA5"
)
or
(
np
.
all
(
np
.
isnan
(
zi
))
and
meth
==
"UA"
)):
zi
=
1000
# additional parameters for C35
waveage
,
seastate
=
1
,
1
if
np
.
isnan
(
wcp
[
0
]):
if
np
.
isnan
(
wcp
[
0
]):
wcp
=
np
.
ones
(
np
.
shape
(
spd
))
*
np
.
nan
wcp
=
np
.
ones
(
np
.
shape
(
spd
))
*
np
.
nan
waveage
=
0
waveage
=
0
if
np
.
isnan
(
sigH
[
0
]):
if
np
.
isnan
(
sigH
[
0
]):
sigH
=
np
.
ones
(
np
.
shape
(
spd
))
*
np
.
nan
sigH
=
np
.
ones
(
np
.
shape
(
spd
))
*
np
.
nan
seastate
=
0
seastate
=
0
if
waveage
and
seastate
:
if
waveage
and
seastate
:
print
(
'Using seastate dependent parameterization'
)
print
(
'Using seastate dependent parameterization'
)
logging
.
info
(
'Using seastate dependent parameterization'
)
logging
.
info
(
'Using seastate dependent parameterization'
)
...
@@ -75,190 +135,298 @@ def flux_calc_v3(spd, T, SST, lat, RH, P, hin, hout, wcp, sigH, zi = 600, \
...
@@ -75,190 +135,298 @@ def flux_calc_v3(spd, T, SST, lat, RH, P, hin, hout, wcp, sigH, zi = 600, \
print
(
'Using waveage dependent parameterization'
)
print
(
'Using waveage dependent parameterization'
)
logging
.
info
(
'Using waveage dependent parameterization'
)
logging
.
info
(
'Using waveage dependent parameterization'
)
####
####
Ta
=
np
.
where
(
np
.
nanmax
(
T
)
<
200
,
np
.
copy
(
T
)
+
CtoK
+
tlapse
*
hh_in
[
1
],
np
.
copy
(
T
)
+
tlapse
*
hh_in
[
1
])
# convert to Kelvin if needed
Ta
=
np
.
where
(
np
.
nanmax
(
T
)
<
200
,
np
.
copy
(
T
)
+
CtoK
+
tlapse
*
hh_in
[
1
],
sst
=
np
.
where
(
np
.
nanmax
(
SST
)
<
200
,
np
.
copy
(
SST
)
+
CtoK
,
np
.
copy
(
SST
))
np
.
copy
(
T
)
+
tlapse
*
hh_in
[
1
])
# convert to Kelvin if needed
if
(
method
==
"COARE3.5"
):
sst
=
np
.
where
(
np
.
nanmax
(
SST
)
<
200
,
np
.
copy
(
SST
)
+
CtoK
,
np
.
copy
(
SST
))
qsea
=
qsat26sea
(
sst
,
P
)
/
1000
# surface water specific humidity (g/kg)
if
(
meth
==
"C35"
):
Q
,
_
=
qsat26air
(
T
,
P
,
RH
)
# specific humidity of air (g/kg)
qsea
=
qsat26sea
(
sst
,
P
)
/
1000
# surface water specific humidity (g/kg)
qair
=
Q
/
1000
;
del
Q
Q
,
_
=
qsat26air
(
T
,
P
,
RH
)
# specific humidity of air (g/kg)
logging
.
info
(
'method %s | qsea:%s, qair:%s'
,
method
,
np
.
ma
.
median
(
qsea
),
np
.
ma
.
median
(
qair
))
qair
=
Q
/
1000
del
Q
logging
.
info
(
'method %s | qsea:%s, qair:%s'
,
meth
,
np
.
ma
.
median
(
qsea
[
~
np
.
isnan
(
qsea
)]),
np
.
ma
.
median
(
qair
[
~
np
.
isnan
(
qair
)]))
else
:
else
:
qsea
=
qsea_calc
(
sst
,
P
)
qsea
=
qsea_calc
(
sst
,
P
)
qair
=
q_calc
(
Ta
,
RH
,
P
)
qair
=
q_calc
(
Ta
,
RH
,
P
)
logging
.
info
(
'method %s | qsea:%s, qair:%s'
,
method
,
np
.
ma
.
median
(
qsea
),
np
.
ma
.
median
(
qair
))
logging
.
info
(
'method %s | qsea:%s, qair:%s'
,
meth
,
np
.
ma
.
median
(
qsea
[
~
np
.
isnan
(
qsea
)]),
np
.
ma
.
median
(
qair
[
~
np
.
isnan
(
qair
)]))
if
(
np
.
all
(
np
.
isnan
(
qsea
))
or
np
.
all
(
np
.
isnan
(
qair
))):
if
(
np
.
all
(
np
.
isnan
(
qsea
))
or
np
.
all
(
np
.
isnan
(
qair
))):
print
(
"qsea and qair cannot be nan"
)
print
(
"qsea and qair cannot be nan"
)
logging
.
debug
(
'method %s qsea and qair cannot be nan | sst:%s, Ta:%s, P:%s, RH:%s'
,
method
,
np
.
ma
.
median
(
sst
),
np
.
ma
.
median
(
Ta
),
np
.
ma
.
median
(
P
),
np
.
ma
.
median
(
RH
))
logging
.
debug
(
'method %s qsea and qair cannot be nan | sst:%s, Ta:%s,'
'P:%s, RH:%s'
,
meth
,
np
.
ma
.
median
(
sst
[
~
np
.
isnan
(
sst
)]),
np
.
ma
.
median
(
Ta
[
~
np
.
isnan
(
Ta
)]),
np
.
ma
.
median
(
P
[
~
np
.
isnan
(
P
)]),
np
.
ma
.
median
(
RH
[
~
np
.
isnan
(
RH
)]))
# first guesses
# first guesses
inan
=
np
.
where
(
np
.
isnan
(
spd
+
T
+
SST
+
lat
+
RH
+
P
))
inan
=
np
.
where
(
np
.
isnan
(
spd
+
T
+
SST
+
lat
+
RH
+
P
))
t10n
,
q10n
=
np
.
copy
(
Ta
),
np
.
copy
(
qair
)
t10n
,
q10n
=
np
.
copy
(
Ta
),
np
.
copy
(
qair
)
tv10n
=
t10n
*
(
1
+
0.61
*
q10n
)
tv10n
=
t10n
*
(
1
+
0.61
*
q10n
)
rho
=
(
0.34838
*
P
)
/
(
tv10n
)
rho
=
(
0.34838
*
P
)
/
(
tv10n
)
rhoa
=
P
*
100
/
(
287.1
*
(
T
+
CtoK
)
*
(
1
+
0.61
*
qair
))
# difference with rho is that it uses T instead of Ta (which includes lapse rate)
rhoa
=
P
*
100
/
(
287.1
*
(
T
+
CtoK
)
*
(
1
+
0.61
*
qair
))
lv
=
(
2.501
-
0.00237
*
(
SST
)
)
*
1e6
lv
=
(
2.501
-
0.00237
*
SST
)
*
1e6
dt
=
sst
-
Ta
dt
=
sst
-
Ta
dq
=
qsea
-
qair
dq
=
qsea
-
qair
if
(
meth
od
==
"C
OARE3.
5"
):
if
(
meth
==
"C
3
5"
):
cp
=
1004.67
#
cpa = 1004.67, cpv = cpa*(1+0.84*Q)
cp
=
1004.67
#
cpa = 1004.67, cpv = cpa*(1+0.84*Q)
wetc
=
0.622
*
lv
*
qsea
/
(
287.1
*
sst
**
2
)
wetc
=
0.622
*
lv
*
qsea
/
(
287.1
*
sst
**
2
)
ug
=
0.5
*
np
.
ones
(
np
.
shape
(
spd
))
ug
=
0.5
*
np
.
ones
(
np
.
shape
(
spd
))
wind
=
np
.
sqrt
(
np
.
copy
(
spd
)
**
2
+
ug
**
2
)
wind
=
np
.
sqrt
(
np
.
copy
(
spd
)
**
2
+
ug
**
2
)
dter
=
0.3
*
np
.
ones
(
np
.
shape
(
spd
))
#
cool skin temperature depression
dter
=
0.3
*
np
.
ones
(
np
.
shape
(
spd
))
#
cool skin temperature depression
dqer
=
wetc
*
dter
dqer
=
wetc
*
dter
Rnl
=
0.97
*
(
5.67e-8
*
(
SST
-
dter
*
jcool
+
CtoK
)
**
4
-
Rl
)
Rnl
=
0.97
*
(
5.67e-8
*
(
SST
-
dter
*
jcool
+
CtoK
)
**
4
-
Rl
)
u10
=
wind
*
np
.
log
(
10
/
1e-4
)
/
np
.
log
(
hh_in
[
0
]
/
1e-4
)
u10
=
wind
*
np
.
log
(
10
/
1e-4
)
/
np
.
log
(
hh_in
[
0
]
/
1e-4
)
usr
=
0.035
*
u10
usr
=
0.035
*
u10
u10n
=
np
.
copy
(
u10
)
u10n
=
np
.
copy
(
u10
)
zo
=
0.011
*
usr
**
2
/
g
+
0.11
*
visc_air
(
T
)
/
usr
zo
=
0.011
*
usr
**
2
/
g
+
0.11
*
visc_air
(
T
)
/
usr
cdn
=
(
kappa
/
np
.
log
(
10
/
zo
))
**
2
cdn
=
(
kappa
/
np
.
log
(
10
/
zo
))
**
2
cqn
=
0.00115
*
np
.
ones
(
np
.
shape
(
spd
))
cqn
=
0.00115
*
np
.
ones
(
np
.
shape
(
spd
))
ctn
=
cqn
/
np
.
sqrt
(
cdn
)
ctn
=
cqn
/
np
.
sqrt
(
cdn
)
cd
=
(
kappa
/
np
.
log
(
hh_in
[
0
]
/
zo
))
**
2
cd
=
(
kappa
/
np
.
log
(
hh_in
[
0
]
/
zo
))
**
2
ct
=
kappa
/
np
.
log
(
hh_in
[
1
]
/
10
/
np
.
exp
(
kappa
/
ctn
))
ct
=
kappa
/
np
.
log
(
hh_in
[
1
]
/
10
/
np
.
exp
(
kappa
/
ctn
))
CC
=
kappa
*
ct
/
cd
CC
=
kappa
*
ct
/
cd
Ribcu
=
-
hh_in
[
0
]
/
zi
/
0.004
/
1.2
**
3
Ribcu
=
-
hh_in
[
0
]
/
zi
/
0.004
/
1.2
**
3
Ribu
=
-
g
*
hh_in
[
0
]
/
(
T
+
CtoK
)
*
((
dt
-
dter
*
jcool
)
+
0.61
*
(
T
+
CtoK
)
*
(
dq
))
/
wind
**
2
Ribu
=
(
-
g
*
hh_in
[
0
]
/
(
T
+
CtoK
)
*
((
dt
-
dter
*
jcool
)
+
0.61
*
(
T
+
CtoK
)
*
(
dq
))
/
zetu
=
np
.
where
(
Ribu
<
0
,
CC
*
Ribu
/
(
1
+
Ribu
/
Ribcu
),
CC
*
Ribu
*
(
1
+
27
/
9
*
Ribu
/
CC
))
wind
**
2
)
k50
=
np
.
where
(
zetu
>
50
)
# stable with very thin M-O length relative to zu
zetu
=
np
.
where
(
Ribu
<
0
,
CC
*
Ribu
/
(
1
+
Ribu
/
Ribcu
),
CC
*
Ribu
*
(
1
+
27
/
9
*
Ribu
/
CC
))
k50
=
np
.
where
(
zetu
>
50
)
# stable, very thin M-O relative to zu
monob
=
hh_in
[
0
]
/
zetu
monob
=
hh_in
[
0
]
/
zetu
gf
=
wind
/
spd
gf
=
wind
/
spd
usr
=
wind
*
kappa
/
(
np
.
log
(
hh_in
[
0
]
/
zo
)
-
psiu_40
(
hh_in
[
0
]
/
monob
))
usr
=
wind
*
kappa
/
(
np
.
log
(
hh_in
[
0
]
/
zo
)
-
psiu_40
(
hh_in
[
0
]
/
monob
))
tsr
=
-
(
dt
-
dter
*
jcool
)
*
kappa
/
(
np
.
log
(
hh_in
[
1
]
/
10
/
np
.
exp
(
kappa
/
ctn
))
-
psit_26
(
hh_in
[
1
]
/
monob
))
tsr
=
(
-
(
dt
-
dter
*
jcool
)
*
kappa
/
(
np
.
log
(
hh_in
[
1
]
/
10
/
np
.
exp
(
kappa
/
ctn
))
-
qsr
=
-
(
dq
-
wetc
*
dter
*
jcool
)
*
kappa
/
(
np
.
log
(
hh_in
[
2
]
/
10
/
np
.
exp
(
kappa
/
ctn
))
-
psit_26
(
hh_in
[
2
]
/
monob
))
psit_26
(
hh_in
[
1
]
/
monob
)))
tsrv
=
tsr
+
0.61
*
(
T
+
CtoK
)
*
qsr
qsr
=
(
-
(
dq
-
wetc
*
dter
*
jcool
)
*
kappa
/
(
np
.
log
(
hh_in
[
2
]
/
10
/
ac
=
np
.
zeros
((
len
(
spd
),
3
))
np
.
exp
(
kappa
/
ctn
))
-
psit_26
(
hh_in
[
2
]
/
monob
)))
tsrv
=
tsr
+
0.61
*
(
T
+
CtoK
)
*
qsr
ac
=
np
.
zeros
((
len
(
spd
),
3
))
charn
=
0.011
*
np
.
ones
(
np
.
shape
(
spd
))
charn
=
0.011
*
np
.
ones
(
np
.
shape
(
spd
))
charn
=
np
.
where
(
wind
>
10
,
0.011
+
(
wind
-
10
)
/
(
18
-
10
)
*
(
0.018
-
0.011
),
np
.
where
(
wind
>
18
,
0.018
,
0.011
))
charn
=
np
.
where
(
wind
>
10
,
0.011
+
(
wind
-
10
)
/
(
18
-
10
)
*
(
0.018
-
0.011
),
ac
[:,
0
]
=
charn
np
.
where
(
wind
>
18
,
0.018
,
0.011
))
ac
[:,
0
]
=
charn
else
:
else
:
cp
=
1004.67
*
(
1
+
0.00084
*
qsea
)
cp
=
1004.67
*
(
1
+
0.00084
*
qsea
)
wind
,
u10n
=
np
.
copy
(
spd
),
np
.
copy
(
spd
)
u10n
=
np
.
copy
(
spd
)
cdn
=
cdn_calc
(
u10n
,
Ta
,
None
,
method
)
monob
=
-
100
*
np
.
ones
(
u10n
.
shape
)
# Monin-Obukhov length
psim
,
psit
,
psiq
=
np
.
zeros
(
u10n
.
shape
),
np
.
zeros
(
u10n
.
shape
),
np
.
zeros
(
u10n
.
shape
)
psim
[
inan
],
psit
[
inan
],
psiq
[
inan
]
=
np
.
nan
,
np
.
nan
,
np
.
nan
cd
=
cd_calc
(
cdn
,
hh_in
[
0
],
ref_ht
,
psim
)
zo
=
0.0001
*
np
.
ones
(
u10n
.
shape
)
zo
[
inan
]
=
np
.
nan
monob
=
-
100
*
np
.
ones
(
u10n
.
shape
)
# Monin-Obukhov length
monob
[
inan
]
=
np
.
nan
monob
[
inan
]
=
np
.
nan
cdn
=
cdn_calc
(
u10n
,
Ta
,
None
,
meth
)
psim
,
psit
,
psiq
=
(
np
.
zeros
(
u10n
.
shape
),
np
.
zeros
(
u10n
.
shape
),
np
.
zeros
(
u10n
.
shape
))
psim
[
inan
],
psit
[
inan
],
psiq
[
inan
]
=
np
.
nan
,
np
.
nan
,
np
.
nan
cd
=
cd_calc
(
cdn
,
hh_in
[
0
],
ref_ht
,
psim
)
tsr
,
tsrv
=
np
.
zeros
(
u10n
.
shape
),
np
.
zeros
(
u10n
.
shape
)
qsr
=
np
.
zeros
(
u10n
.
shape
)
tsr
[
inan
],
tsrv
[
inan
],
qsr
[
inan
]
=
np
.
nan
,
np
.
nan
,
np
.
nan
if
(
meth
==
"UA"
):
wind
=
np
.
sqrt
(
np
.
power
(
np
.
copy
(
spd
),
2
)
+
np
.
power
(
0.5
,
2
))
zo
,
zot
=
0.0001
*
np
.
ones
(
u10n
.
shape
),
0.0001
*
np
.
ones
(
u10n
.
shape
)
zol
=
hh_in
[
0
]
/
monob
elif
(
meth
==
"ERA5"
):
wind
=
np
.
sqrt
(
np
.
power
(
np
.
copy
(
spd
),
2
)
+
np
.
power
(
0.5
,
2
))
usr
=
np
.
sqrt
(
cd
*
wind
**
2
)
Ribu
=
((
g
*
hh_in
[
0
]
*
((
2
*
(
Ta
-
sst
))
/
(
Ta
+
sst
-
g
*
hh_in
[
0
])
+
0.61
*
(
qair
-
qsea
)))
/
np
.
power
(
wind
,
2
))
zo
=
0.11
*
visc_air
(
Ta
)
/
usr
+
0.018
*
np
.
power
(
usr
,
2
)
/
g
zot
=
0.40
*
visc_air
(
Ta
)
/
usr
zol
=
(
Ribu
*
((
np
.
log
((
hh_in
[
0
]
+
zo
)
/
zo
)
-
psim_calc
((
hh_in
[
0
]
+
zo
)
/
monob
,
meth
)
+
psim_calc
(
zo
/
monob
,
meth
))
/
(
np
.
log
((
hh_in
[
0
]
+
zo
)
/
zot
)
-
psit_calc
((
hh_in
[
0
]
+
zo
)
/
monob
,
meth
)
+
psit_calc
(
zot
/
monob
,
meth
))))
else
:
wind
=
np
.
copy
(
spd
)
zo
=
0.0001
*
np
.
ones
(
u10n
.
shape
)
zo
[
inan
]
=
np
.
nan
usr
=
np
.
sqrt
(
cd
*
wind
**
2
)
usr
=
np
.
sqrt
(
cd
*
wind
**
2
)
tsr
,
tsrv
,
qsr
=
np
.
zeros
(
u10n
.
shape
),
np
.
zeros
(
u10n
.
shape
),
np
.
zeros
(
u10n
.
shape
)
# tolerance for u,t,q,usr,tsr,qsr
tsr
[
inan
],
tsrv
[
inan
],
qsr
[
inan
]
=
np
.
nan
,
np
.
nan
,
np
.
nan
tol
=
np
.
array
([
0.01
,
0.01
,
5e-05
,
0.005
,
0.001
,
5e-07
])
tol
=
np
.
array
([
0.01
,
0.01
,
5e-05
,
0.005
,
0.001
,
5e-07
])
# tolerance u,t,q,usr,tsr,qsr
it
=
0
it
=
0
ind
=
np
.
where
(
spd
>
0
)
ind
=
np
.
where
(
spd
>
0
)
ii
=
True
ii
=
True
itera
=
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
itera
=
np
.
zeros
(
spd
.
shape
)
*
np
.
nan
while
np
.
any
(
ii
):
while
np
.
any
(
ii
):
it
+=
1
it
+=
1
# print('iter: '+str(it)+', p: '+str(np.shape(ind)[1]))
# print('iter: '+str(it)+', p: '+str(np.shape(ind)[1]))
if
it
>
n
:
if
it
>
n
:
break
break
if
(
method
==
"COARE3.5"
):
if
(
meth
==
"C35"
):
### This allows all iterations regardless of convergence as in original
old
=
np
.
array
([
np
.
copy
(
u10n
[
ind
]),
np
.
copy
(
usr
[
ind
]),
zet
=
kappa
*
g
*
hh_in
[
0
]
/
(
T
+
CtoK
)
*
(
tsr
+
0.61
*
(
T
+
CtoK
)
*
qsr
)
/
(
usr
**
2
)
np
.
copy
(
tsr
[
ind
]),
np
.
copy
(
qsr
[
ind
])])
monob
=
hh_in
[
0
]
/
zet
zet
=
(
kappa
*
g
[
ind
]
*
hh_in
[
0
]
/
(
T
[
ind
]
+
CtoK
)
*
(
tsr
[
ind
]
+
0.61
*
zo
,
cd
,
ct
,
cq
=
cd_C35
(
u10n
,
wind
,
usr
,
ac
[:,
0
],
monob
,(
T
+
CtoK
),
hh_in
,
lat
)
(
T
[
ind
]
+
CtoK
)
*
qsr
[
ind
])
/
(
usr
[
ind
]
**
2
))
usr
=
wind
*
cd
monob
[
ind
]
=
hh_in
[
0
]
/
zet
qsr
=-
(
dq
-
wetc
*
dter
*
jcool
)
*
cq
zo
[
ind
],
cd
[
ind
],
ct
[
ind
],
cq
[
ind
]
=
cd_C35
(
u10n
[
ind
],
wind
[
ind
],
tsr
=-
(
dt
-
dter
*
jcool
)
*
ct
usr
[
ind
],
ac
[
ind
,
0
],
tsrv
=
tsr
+
0.61
*
(
T
+
CtoK
)
*
qsr
monob
[
ind
],
ug
=
get_gust
((
T
+
CtoK
),
usr
,
tsrv
,
zi
,
lat
)
# gustiness
(
T
[
ind
]
+
CtoK
),
hh_in
,
wind
=
np
.
sqrt
(
np
.
copy
(
spd
)
**
2
+
ug
**
2
)
lat
[
ind
])
gf
=
wind
/
spd
usr
[
ind
]
=
wind
[
ind
]
*
cd
[
ind
]
dter
,
dqer
=
get_skin
(
sst
,
qsea
,
rhoa
,
jcool
,
Rl
,
Rs
,
Rnl
,
cp
,
lv
,
usr
,
tsr
,
qsr
,
lat
)
qsr
[
ind
]
=
-
(
dq
[
ind
]
-
wetc
[
ind
]
*
dter
[
ind
]
*
jcool
)
*
cq
[
ind
]
Rnl
=
0.97
*
(
5.67e-8
*
(
SST
-
dter
*
jcool
+
CtoK
)
**
4
-
Rl
)
tsr
[
ind
]
=
-
(
dt
[
ind
]
-
dter
[
ind
]
*
jcool
)
*
ct
[
ind
]
if
it
==
1
:
# save first iteration solution for case of zetu>50
tsrv
[
ind
]
=
tsr
[
ind
]
+
0.61
*
(
T
[
ind
]
+
CtoK
)
*
qsr
[
ind
]
usr50
,
tsr50
,
qsr50
,
L50
=
usr
[
k50
],
tsr
[
k50
],
qsr
[
k50
],
monob
[
k50
]
ug
[
ind
]
=
get_gust
(
1.2
,
(
T
[
ind
]
+
CtoK
),
usr
[
ind
],
tsrv
[
ind
],
dter50
,
dqer50
=
dter
[
k50
],
dqer
[
k50
]
zi
,
lat
[
ind
])
# gustiness
u10n
=
usr
/
kappa
/
gf
*
np
.
log
(
10
/
zo
)
wind
[
ind
]
=
np
.
sqrt
(
np
.
copy
(
spd
[
ind
])
**
2
+
ug
[
ind
]
**
2
)
ac
=
charnock_C35
(
wind
,
u10n
,
usr
,
seastate
,
waveage
,
wcp
,
sigH
,
lat
)
gf
=
wind
/
spd
new
=
np
.
array
([
np
.
copy
(
u10n
),
np
.
copy
(
usr
),
np
.
copy
(
tsr
),
np
.
copy
(
qsr
)])
dter
[
ind
],
dqer
[
ind
]
=
get_skin
(
sst
[
ind
],
qsea
[
ind
],
rhoa
[
ind
],
### otherwise iterations stop when u,usr,tsr,qsr converge but gives different results than above option
Rl
[
ind
],
Rs
[
ind
],
Rnl
[
ind
],
cp
,
# old=np.array([np.copy(u10n[ind]),np.copy(usr[ind]),np.copy(tsr[ind]),np.copy(qsr[ind])])
lv
[
ind
],
usr
[
ind
],
tsr
[
ind
],
# zet=kappa*g[ind]*hh_in[0]/(T[ind]+CtoK)*(tsr[ind] +0.61*(T[ind]+CtoK)*qsr[ind])/(usr[ind]**2)
qsr
[
ind
],
lat
[
ind
])
# monob[ind]=hh_in[0]/zet
Rnl
=
0.97
*
(
5.67e-8
*
(
SST
-
dter
*
jcool
+
CtoK
)
**
4
-
Rl
)
# zo[ind],cd[ind],ct[ind],cq[ind]=cd_C35(u10n[ind],wind[ind],usr[ind],ac[ind,0],monob[ind],(T[ind]+CtoK),hh_in,lat[ind])
if
it
==
1
:
# save first iteration solution for case of zetu>50
# usr[ind]=wind[ind]*cd[ind]
usr50
,
tsr50
,
qsr50
,
L50
=
(
usr
[
k50
],
tsr
[
k50
],
qsr
[
k50
],
# qsr[ind]=-(dq[ind]-wetc[ind]*dter[ind]*jcool)*cq[ind]
monob
[
k50
])
# tsr[ind]=-(dt[ind]-dter[ind]*jcool)*ct[ind]
dter50
,
dqer50
=
dter
[
k50
],
dqer
[
k50
]
# tsrv[ind]=tsr[ind]+0.61*(T[ind]+CtoK)*qsr[ind]
u10n
[
ind
]
=
usr
[
ind
]
/
kappa
/
gf
[
ind
]
*
np
.
log
(
10
/
zo
[
ind
])
# ug[ind] = get_gust((T[ind]+CtoK),usr[ind],tsrv[ind],zi,lat[ind]) # gustiness
ac
[
ind
][:]
=
charnock_C35
(
wind
[
ind
],
u10n
[
ind
],
usr
[
ind
],
seastate
,
# wind[ind] = np.sqrt(np.copy(spd[ind])**2 + ug[ind]**2)
waveage
,
wcp
[
ind
],
sigH
[
ind
],
lat
[
ind
])
# gf=wind/spd
new
=
np
.
array
([
np
.
copy
(
u10n
[
ind
]),
np
.
copy
(
usr
[
ind
]),
# dter[ind], dqer[ind]=get_skin(sst[ind],qsea[ind],rhoa[ind],jcool,Rl[ind],Rs[ind],Rnl[ind],cp,lv[ind],usr[ind],tsr[ind],qsr[ind],lat[ind])
np
.
copy
(
tsr
[
ind
]),
np
.
copy
(
qsr
[
ind
])])
# Rnl=0.97*(5.67e-8*(SST-dter*jcool+CtoK)**4-Rl)
d
=
np
.
abs
(
new
-
old
)
# if it==1: # save first iteration solution for case of zetu>50
ind
=
np
.
where
((
d
[
0
,:]
>
tol
[
0
])
+
(
d
[
1
,:]
>
tol
[
3
])
+
# usr50,tsr50,qsr50,L50=usr[k50],tsr[k50],qsr[k50],monob[k50]
(
d
[
2
,:]
>
tol
[
4
])
+
(
d
[
3
,:]
>
tol
[
5
]))
# dter50, dqer50=dter[k50], dqer[k50]
itera
[
ind
]
=
np
.
ones
(
1
)
*
it
# u10n[ind] = usr[ind]/kappa/gf[ind]*np.log(10/zo[ind])
if
np
.
shape
(
ind
)[
0
]
==
0
:
# ac[ind][:]=charnock_C35(wind[ind],u10n[ind],usr[ind],seastate,waveage,wcp[ind],sigH[ind],lat[ind])
break
# new=np.array([np.copy(u10n[ind]),np.copy(usr[ind]),np.copy(tsr[ind]),np.copy(qsr[ind])])
else
:
# print(str(it)+'L= '+str(monob),file=open('/noc/mpoc/surface_data/sbiri/SAMOS/C35_int.txt','a'))
ii
=
((
d
[
0
,:]
>
tol
[
0
])
+
(
d
[
1
,:]
>
tol
[
3
])
+
(
d
[
2
,:]
>
tol
[
4
])
+
# print(str(it)+'dter= '+str(dter),file=open('/noc/mpoc/surface_data/sbiri/SAMOS/C35_int.txt','a'))
(
d
[
3
,:]
>
tol
[
5
]))
# print(str(it)+'ac= '+str(ac[:,0]),file=open('/noc/mpoc/surface_data/sbiri/SAMOS/C35_int.txt','a'))
# d=np.abs(new-old)
# ind=np.where((d[0,:]>tol[0])+(d[1,:]>tol[3])+(d[2,:]>tol[4])+(d[3,:]>tol[5]))
# itera[ind]=np.ones(1)*it
# if np.shape(ind)[0]==0:
# break
# else:
# ii = (d[0,:]>tol[0])+(d[1,:]>tol[3])+(d[2,:]>tol[4])+(d[3,:]>tol[5])
else
:
else
:
old
=
np
.
array
([
np
.
copy
(
u10n
[
ind
]),
np
.
copy
(
t10n
[
ind
]),
np
.
copy
(
q10n
[
ind
]),
np
.
copy
(
usr
[
ind
]),
np
.
copy
(
tsr
[
ind
]),
np
.
copy
(
qsr
[
ind
])])
old
=
np
.
array
([
np
.
copy
(
u10n
[
ind
]),
np
.
copy
(
t10n
[
ind
]),
cdn
[
ind
]
=
cdn_calc
(
u10n
[
ind
],
Ta
[
ind
],
None
,
method
)
np
.
copy
(
q10n
[
ind
]),
np
.
copy
(
usr
[
ind
]),
np
.
copy
(
tsr
[
ind
]),
np
.
copy
(
qsr
[
ind
])])
cdn
[
ind
]
=
cdn_calc
(
u10n
[
ind
],
Ta
[
ind
],
None
,
meth
)
if
(
np
.
all
(
np
.
isnan
(
cdn
))):
if
(
np
.
all
(
np
.
isnan
(
cdn
))):
break
#
sys.exit("cdn cannot be nan")
break
#
sys.exit("cdn cannot be nan")
logging
.
debug
(
'%s at iteration %s cdn
negative
'
,
meth
od
,
it
)
logging
.
debug
(
'
break
%s at iteration %s cdn
<0
'
,
meth
,
it
)
zo
[
ind
]
=
ref_ht
/
np
.
exp
(
kappa
/
np
.
sqrt
(
cdn
[
ind
]))
zo
[
ind
]
=
ref_ht
/
np
.
exp
(
kappa
/
np
.
sqrt
(
cdn
[
ind
]))
psim
[
ind
]
=
psim_calc
(
hh_in
[
0
]
/
monob
[
ind
],
meth
od
)
psim
[
ind
]
=
psim_calc
(
hh_in
[
0
]
/
monob
[
ind
],
meth
)
cd
[
ind
]
=
cd_calc
(
cdn
[
ind
],
hh_in
[
0
],
ref_ht
,
psim
[
ind
])
cd
[
ind
]
=
cd_calc
(
cdn
[
ind
],
hh_in
[
0
],
ref_ht
,
psim
[
ind
])
ctn
[
ind
],
cqn
[
ind
]
=
ctcqn_calc
(
hh_in
[
1
]
/
monob
[
ind
],
cdn
[
ind
],
u10n
[
ind
],
zo
[
ind
],
Ta
[
ind
],
method
)
ctn
[
ind
],
cqn
[
ind
]
=
ctcqn_calc
(
hh_in
[
1
]
/
monob
[
ind
],
cdn
[
ind
],
psit
[
ind
]
=
psit_calc
(
hh_in
[
1
]
/
monob
[
ind
],
method
)
u10n
[
ind
],
zo
[
ind
],
Ta
[
ind
],
meth
)
psiq
[
ind
]
=
psit_calc
(
hh_in
[
2
]
/
monob
[
ind
],
method
)
psit
[
ind
]
=
psit_calc
(
hh_in
[
1
]
/
monob
[
ind
],
meth
)
ct
[
ind
],
cq
[
ind
]
=
ctcq_calc
(
cdn
[
ind
],
cd
[
ind
],
ctn
[
ind
],
cqn
[
ind
],
hh_in
[
1
],
hh_in
[
2
],
ref_ht
,
psit
[
ind
],
psiq
[
ind
])
psiq
[
ind
]
=
psit_calc
(
hh_in
[
2
]
/
monob
[
ind
],
meth
)
usr
[
ind
]
=
np
.
sqrt
(
cd
[
ind
]
*
wind
[
ind
]
**
2
)
ct
[
ind
],
cq
[
ind
]
=
ctcq_calc
(
cdn
[
ind
],
cd
[
ind
],
ctn
[
ind
],
cqn
[
ind
],
hh_in
[
1
],
hh_in
[
2
],
ref_ht
,
psit
[
ind
],
psiq
[
ind
])
usr
[
ind
]
=
np
.
sqrt
(
cd
[
ind
]
*
wind
[
ind
]
**
2
)
tsr
[
ind
]
=
ct
[
ind
]
*
wind
[
ind
]
*
(
-
dt
[
ind
])
/
usr
[
ind
]
tsr
[
ind
]
=
ct
[
ind
]
*
wind
[
ind
]
*
(
-
dt
[
ind
])
/
usr
[
ind
]
qsr
[
ind
]
=
cq
[
ind
]
*
wind
[
ind
]
*
(
-
dq
[
ind
])
/
usr
[
ind
]
qsr
[
ind
]
=
cq
[
ind
]
*
wind
[
ind
]
*
(
-
dq
[
ind
])
/
usr
[
ind
]
fact
=
(
np
.
log
(
hh_in
[
1
]
/
ref_ht
)
-
psit
[
ind
])
/
kappa
if
(
meth
==
"UA"
):
t10n
[
ind
]
=
Ta
[
ind
]
-
(
tsr
[
ind
]
*
fact
)
zot
[
ind
]
=
10
/
(
np
.
exp
(
kappa
**
2
/
(
ctn
[
ind
]
*
np
.
log
(
10
/
zo
[
ind
]))))
fact
=
(
np
.
log
(
hh_in
[
2
]
/
ref_ht
)
-
psiq
[
ind
])
/
kappa
zol
[
ind
]
=
hh_in
[
0
]
/
monob
[
ind
]
q10n
[
ind
]
=
qair
[
ind
]
-
(
qsr
[
ind
]
*
fact
)
t10n
[
ind
]
=
np
.
where
(
zol
[
ind
]
<-
0.465
,
Ta
[
ind
]
-
(
tsr
[
ind
]
/
kappa
)
*
(
np
.
log
((
-
0.465
*
monob
[
ind
])
/
zot
[
ind
])
-
psit_calc
(
-
0.465
,
meth
)
+
0.8
*
(
np
.
power
(
0.465
,
-
1
/
3
)
-
np
.
power
(
-
zol
[
ind
],
-
1
/
3
))),
\
np
.
where
((
zol
[
ind
]
>-
0.465
)
&
(
zol
[
ind
]
<
0
),
Ta
[
ind
]
-
(
tsr
[
ind
]
/
kappa
)
*
(
np
.
log
(
hh_in
[
1
]
/
zot
[
ind
])
-
psit_calc
(
zol
[
ind
],
meth
)),
\
np
.
where
((
zol
[
ind
]
>
0
)
&
(
zol
[
ind
]
<
1
),
Ta
[
ind
]
-
(
tsr
[
ind
]
/
kappa
)
*
(
np
.
log
(
hh_in
[
1
]
/
zot
[
ind
])
+
5
*
monob
[
ind
]),
Ta
[
ind
]
-
(
tsr
[
ind
]
/
kappa
)
*
(
np
.
log
(
monob
[
ind
]
/
zot
[
ind
])
+
5
+
5
*
np
.
log
(
monob
[
ind
])
+
monob
[
ind
]
-
1
))))
# Zeng et al. 1998 (11-14)
q10n
[
ind
]
=
np
.
where
(
zol
[
ind
]
<-
0.465
,
qair
[
ind
]
-
(
qsr
[
ind
]
/
kappa
)
*
(
np
.
log
((
-
0.465
*
monob
[
ind
])
/
zot
[
ind
])
-
psit_calc
(
-
0.465
,
meth
)
+
0.8
*
(
np
.
power
(
0.465
,
-
1
/
3
)
-
np
.
power
(
-
zol
[
ind
],
-
1
/
3
))),
\
np
.
where
((
zol
[
ind
]
>-
0.465
)
&
(
zol
[
ind
]
<
0
),
qair
[
ind
]
-
(
qsr
[
ind
]
/
kappa
)
*
(
np
.
log
(
hh_in
[
1
]
/
zot
[
ind
])
-
psit_calc
(
zol
[
ind
],
meth
)),
\
np
.
where
((
zol
[
ind
]
>
0
)
&
(
zol
[
ind
]
<
1
),
\
qair
[
ind
]
-
(
qsr
[
ind
]
/
kappa
)
*
(
np
.
log
(
hh_in
[
1
]
/
zot
[
ind
])
+
5
*
monob
[
ind
]),
qair
[
ind
]
-
(
qsr
[
ind
]
/
kappa
)
*
(
np
.
log
(
monob
[
ind
]
/
zot
[
ind
])
+
5
+
5
*
np
.
log
(
monob
[
ind
])
+
monob
[
ind
]
-
1
))))
else
:
fact
=
(
np
.
log
(
hh_in
[
1
]
/
ref_ht
)
-
psit
[
ind
])
/
kappa
t10n
[
ind
]
=
Ta
[
ind
]
-
(
tsr
[
ind
]
*
fact
)
fact
=
(
np
.
log
(
hh_in
[
2
]
/
ref_ht
)
-
psiq
[
ind
])
/
kappa
q10n
[
ind
]
=
qair
[
ind
]
-
(
qsr
[
ind
]
*
fact
)
tv10n
[
ind
]
=
t10n
[
ind
]
*
(
1
+
0.61
*
q10n
[
ind
])
tv10n
[
ind
]
=
t10n
[
ind
]
*
(
1
+
0.61
*
q10n
[
ind
])
tsrv
[
ind
]
=
tsr
[
ind
]
+
0.61
*
t10n
[
ind
]
*
qsr
[
ind
]
tsrv
[
ind
]
=
tsr
[
ind
]
+
0.61
*
t10n
[
ind
]
*
qsr
[
ind
]
monob
[
ind
]
=
(
tv10n
[
ind
]
*
usr
[
ind
]
**
2
)
/
(
g
[
ind
]
*
kappa
*
tsrv
[
ind
])
if
(
meth
==
"ERA5"
):
psim
[
ind
]
=
psim_calc
(
hh_in
[
0
]
/
monob
[
ind
],
method
)
zol
[
ind
]
=
(
kappa
*
g
[
ind
]
*
hh_in
[
0
]
/
Ta
[
ind
]
*
(
tsr
[
ind
]
+
psit
[
ind
]
=
psit_calc
(
hh_in
[
1
]
/
monob
[
ind
],
method
)
0.61
*
Ta
[
ind
]
*
qsr
[
ind
])
/
(
usr
[
ind
]
**
2
))
psiq
[
ind
]
=
psit_calc
(
hh_in
[
2
]
/
monob
[
ind
],
method
)
monob
[
ind
]
=
hh_in
[
0
]
/
zol
[
ind
]
u10n
[
ind
]
=
wind
[
ind
]
-
(
usr
[
ind
]
/
kappa
)
*
(
np
.
log
(
hh_in
[
0
]
/
ref_ht
)
-
psim
[
ind
])
else
:
u10n
[
u10n
<
0
]
=
np
.
nan
# 0.5*old[0,np.where(u10n<0)]
monob
[
ind
]
=
(
tv10n
[
ind
]
*
usr
[
ind
]
**
2
)
/
(
g
[
ind
]
*
kappa
*
tsrv
[
ind
])
new
=
np
.
array
([
np
.
copy
(
u10n
[
ind
]),
np
.
copy
(
t10n
[
ind
]),
np
.
copy
(
q10n
[
ind
]),
np
.
copy
(
usr
[
ind
]),
np
.
copy
(
tsr
[
ind
]),
np
.
copy
(
qsr
[
ind
])])
psim
[
ind
]
=
psim_calc
(
hh_in
[
0
]
/
monob
[
ind
],
meth
)
d
=
np
.
abs
(
new
-
old
)
psit
[
ind
]
=
psit_calc
(
hh_in
[
1
]
/
monob
[
ind
],
meth
)
ind
=
np
.
where
((
d
[
0
,:]
>
tol
[
0
])
+
(
d
[
1
,:]
>
tol
[
1
])
+
(
d
[
2
,:]
>
tol
[
2
])
+
(
d
[
3
,:]
>
tol
[
3
])
+
(
d
[
4
,:]
>
tol
[
4
])
+
(
d
[
5
,:]
>
tol
[
5
]))
psiq
[
ind
]
=
psit_calc
(
hh_in
[
2
]
/
monob
[
ind
],
meth
)
itera
[
ind
]
=
np
.
ones
(
1
)
*
it
if
(
meth
==
"UA"
):
if
np
.
shape
(
ind
)[
0
]
==
0
:
u10n
[
ind
]
=
np
.
where
(
zol
[
ind
]
<-
1.574
,(
usr
[
ind
]
/
kappa
)
*
break
((
np
.
log
(
-
1.574
*
monob
[
ind
]
/
zo
[
ind
])
-
psim_calc
(
-
1.574
,
meth
))
+
1.14
*
(
np
.
power
(
-
monob
[
ind
],
1
/
3
)
-
np
.
power
(
1.574
,
1
/
3
))),
\
np
.
where
((
zol
[
ind
]
>-
1.574
)
&
(
zol
[
ind
]
<
0
),
(
usr
[
ind
]
/
kappa
)
*
(
np
.
log
(
ref_ht
/
zo
[
ind
])
-
psim_calc
(
zol
[
ind
])),
\
np
.
where
((
zol
[
ind
]
>
0
)
&
(
zol
[
ind
]
<
1
),
(
usr
[
ind
]
/
kappa
)
*
(
np
.
log
(
ref_ht
/
zo
[
ind
])
+
5
*
zol
[
ind
]),(
usr
[
ind
]
/
kappa
)
*
(
np
.
log
(
monob
[
ind
]
/
zo
[
ind
])
+
5
+
5
*
np
.
log
(
zol
[
ind
])
+
zol
[
ind
]
-
1
))))
# Zeng et al. 1998 (7-10)
u10n
[
u10n
<
0
]
=
np
.
nan
wind
[
ind
]
=
np
.
sqrt
(
np
.
power
(
np
.
copy
(
spd
[
ind
]),
2
)
+
np
.
power
(
get_gust
(
1
,
Ta
[
ind
],
usr
[
ind
],
tsrv
[
ind
],
zi
,
lat
[
ind
]),
2
))
# Zeng et al. 1998 (20)
elif
(
meth
==
"ERA5"
):
wind
[
ind
]
=
np
.
sqrt
(
np
.
copy
(
spd
[
ind
])
**
2
+
(
get_gust
(
1
,
Ta
[
ind
],
usr
[
ind
],
tsrv
[
ind
],
zi
,
lat
[
ind
]))
**
2
)
u10n
[
ind
]
=
(
wind
[
ind
]
-
(
usr
[
ind
]
/
kappa
)
*
(
np
.
log
(
hh_in
[
0
]
/
ref_ht
)
-
psim
[
ind
]))
u10n
[
u10n
<
0
]
=
np
.
nan
else
:
else
:
ii
=
(
d
[
0
,
ind
]
>
tol
[
0
])
+
(
d
[
1
,
ind
]
>
tol
[
1
])
+
(
d
[
2
,
ind
]
>
tol
[
2
])
+
(
d
[
3
,
ind
]
>
tol
[
3
])
+
(
d
[
4
,
ind
]
>
tol
[
4
])
+
(
d
[
5
,
ind
]
>
tol
[
5
])
u10n
[
ind
]
=
(
wind
[
ind
]
-
(
usr
[
ind
]
/
kappa
)
*
(
np
.
log
(
hh_in
[
0
]
/
ref_ht
)
-
psim
[
ind
]))
u10n
[
u10n
<
0
]
=
np
.
nan
# 0.5*old[0,np.where(u10n<0)]
new
=
np
.
array
([
np
.
copy
(
u10n
[
ind
]),
np
.
copy
(
t10n
[
ind
]),
np
.
copy
(
q10n
[
ind
]),
np
.
copy
(
usr
[
ind
]),
np
.
copy
(
tsr
[
ind
]),
np
.
copy
(
qsr
[
ind
])])
d
=
np
.
abs
(
new
-
old
)
ind
=
np
.
where
((
d
[
0
,
:]
>
tol
[
0
])
+
(
d
[
1
,
:]
>
tol
[
1
])
+
(
d
[
2
,
:]
>
tol
[
2
])
+
(
d
[
3
,
:]
>
tol
[
3
])
+
(
d
[
4
,
:]
>
tol
[
4
])
+
(
d
[
5
,
:]
>
tol
[
5
]))
itera
[
ind
]
=
np
.
ones
(
1
)
*
it
if
np
.
shape
(
ind
)[
0
]
==
0
:
break
else
:
ii
=
((
d
[
0
,
ind
]
>
tol
[
0
])
+
(
d
[
1
,
ind
]
>
tol
[
1
])
+
(
d
[
2
,
ind
]
>
tol
[
2
])
+
(
d
[
3
,
ind
]
>
tol
[
3
])
+
(
d
[
4
,
ind
]
>
tol
[
4
])
+
(
d
[
5
,
ind
]
>
tol
[
5
]))
# calculate output parameters
# calculate output parameters
if
(
meth
od
==
"C
OARE3.
5"
):
if
(
meth
==
"C
3
5"
):
usr
[
k50
],
tsr
[
k50
],
qsr
[
k50
],
monob
[
k50
]
=
usr50
,
tsr50
,
qsr50
,
L50
usr
[
k50
],
tsr
[
k50
],
qsr
[
k50
],
monob
[
k50
]
=
usr50
,
tsr50
,
qsr50
,
L50
dter
[
k50
],
dqer
[
k50
]
=
dter50
,
dqer50
dter
[
k50
],
dqer
[
k50
]
=
dter50
,
dqer50
rhoa
=
P
*
100
/
(
287.1
*
(
T
+
CtoK
)
*
(
1
+
0.61
*
qair
))
rhoa
=
P
*
100
/
(
287.1
*
(
T
+
CtoK
)
*
(
1
+
0.61
*
qair
))
rr
=
zo
*
usr
/
visc_air
(
T
+
CtoK
)
rr
=
zo
*
usr
/
visc_air
(
T
+
CtoK
)
zoq
=
np
.
where
(
5.8e-5
/
rr
**
0.72
>
1.6e-4
,
1.6e-4
,
5.8e-5
/
rr
**
0.72
)
zoq
=
np
.
where
(
5.8e-5
/
rr
**
0.72
>
1.6e-4
,
1.6e-4
,
5.8e-5
/
rr
**
0.72
)
zot
=
zoq
zot
=
zoq
psiT
=
psit_26
(
hh_in
[
1
]
/
monob
)
psiT
=
psit_26
(
hh_in
[
1
]
/
monob
)
psi10T
=
psit_26
(
10
/
monob
)
psi10T
=
psit_26
(
10
/
monob
)
psi
=
psiu_26
(
hh_in
[
0
]
/
monob
)
psi
=
psiu_26
(
hh_in
[
0
]
/
monob
)
psirf
=
psiu_26
(
hh_out
[
0
]
/
monob
)
psirf
=
psiu_26
(
hh_out
[
0
]
/
monob
)
q10
=
qair
+
qsr
/
kappa
*
(
np
.
log
(
10
/
hh_in
[
2
])
-
psi10T
+
psiT
)
q10
=
qair
+
qsr
/
kappa
*
(
np
.
log
(
10
/
hh_in
[
2
])
-
psi10T
+
psiT
)
tau
=
rhoa
*
usr
*
usr
/
gf
tau
=
rhoa
*
usr
*
usr
/
gf
sensible
=
-
rhoa
*
cp
*
usr
*
tsr
sensible
=
-
rhoa
*
cp
*
usr
*
tsr
latent
=
-
rhoa
*
lv
*
usr
*
qsr
latent
=
-
rhoa
*
lv
*
usr
*
qsr
cd
=
tau
/
rhoa
/
wind
/
np
.
where
(
spd
<
0.1
,
0.1
,
spd
)
cd
=
tau
/
rhoa
/
wind
/
np
.
where
(
spd
<
0.1
,
0.1
,
spd
)
cdn
=
1000
*
kappa
**
2
/
np
.
log
(
10
/
zo
)
**
2
cdn
=
1000
*
kappa
**
2
/
np
.
log
(
10
/
zo
)
**
2
ct
=
-
usr
*
tsr
/
wind
/
(
dt
-
dter
*
jcool
)
ct
=
-
usr
*
tsr
/
wind
/
(
dt
-
dter
*
jcool
)
ctn
=
1000
*
kappa
**
2
/
np
.
log
(
10
/
zo
)
/
np
.
log
(
10
/
zot
)
ctn
=
1000
*
kappa
**
2
/
np
.
log
(
10
/
zo
)
/
np
.
log
(
10
/
zot
)
...
@@ -267,12 +435,15 @@ def flux_calc_v3(spd, T, SST, lat, RH, P, hin, hout, wcp, sigH, zi = 600, \
...
@@ -267,12 +435,15 @@ def flux_calc_v3(spd, T, SST, lat, RH, P, hin, hout, wcp, sigH, zi = 600, \
psim
=
psiu_26
(
hh_in
[
0
]
/
monob
)
psim
=
psiu_26
(
hh_in
[
0
]
/
monob
)
psit
=
psit_26
(
hh_in
[
1
]
/
monob
)
psit
=
psit_26
(
hh_in
[
1
]
/
monob
)
u10n
=
u10
+
psiu_26
(
10
/
monob
)
*
usr
/
kappa
/
gf
u10n
=
u10
+
psiu_26
(
10
/
monob
)
*
usr
/
kappa
/
gf
t10n
=
T
+
tsr
/
kappa
*
(
np
.
log
(
10
/
hh_in
[
1
])
-
psi10T
+
psiT
)
+
tlapse
*
(
hh_in
[
1
]
-
10
)
+
psi10T
*
tsr
/
kappa
t10n
=
(
T
+
tsr
/
kappa
*
(
np
.
log
(
10
/
hh_in
[
1
])
-
psi10T
+
psiT
)
+
tlapse
*
(
hh_in
[
1
]
-
10
)
+
psi10T
*
tsr
/
kappa
)
q10n
=
q10
+
psi10T
*
qsr
/
kappa
q10n
=
q10
+
psi10T
*
qsr
/
kappa
tv10n
=
t10n
*
(
1
+
0.61
*
q10n
)
tv10n
=
t10n
*
(
1
+
0.61
*
q10n
)
urefs
=
spd
+
usr
/
kappa
/
gf
*
(
np
.
log
(
hh_out
[
0
]
/
hh_in
[
0
])
-
psirf
+
psi
)
urefs
=
spd
+
usr
/
kappa
/
gf
*
(
np
.
log
(
hh_out
[
0
]
/
hh_in
[
0
])
-
psirf
+
psi
)
trefs
=
T
+
tsr
/
kappa
*
(
np
.
log
(
hh_out
[
1
]
/
hh_in
[
1
])
-
psit_26
(
hh_out
[
1
]
/
monob
)
+
psiT
)
+
tlapse
*
(
hh_in
[
1
]
-
hh_out
[
1
])
trefs
=
(
T
+
tsr
/
kappa
*
(
np
.
log
(
hh_out
[
1
]
/
hh_in
[
1
])
-
qrefs
=
qair
+
qsr
/
kappa
*
(
np
.
log
(
hh_out
[
2
]
/
hh_in
[
2
])
-
psit_26
(
hh_out
[
2
]
/
monob
)
+
psiT
)
psit_26
(
hh_out
[
1
]
/
monob
)
+
psiT
)
+
tlapse
*
(
hh_in
[
1
]
-
hh_out
[
1
]))
qrefs
=
(
qair
+
qsr
/
kappa
*
(
np
.
log
(
hh_out
[
2
]
/
hh_in
[
2
])
-
psit_26
(
hh_out
[
2
]
/
monob
)
+
psiT
))
else
:
else
:
rho
=
(
0.34838
*
P
)
/
(
tv10n
)
rho
=
(
0.34838
*
P
)
/
(
tv10n
)
t10n
=
t10n
-
(
273.16
+
tlapse
*
ref_ht
)
t10n
=
t10n
-
(
273.16
+
tlapse
*
ref_ht
)
...
@@ -282,59 +453,39 @@ def flux_calc_v3(spd, T, SST, lat, RH, P, hin, hout, wcp, sigH, zi = 600, \
...
@@ -282,59 +453,39 @@ def flux_calc_v3(spd, T, SST, lat, RH, P, hin, hout, wcp, sigH, zi = 600, \
zo
=
ref_ht
/
np
.
exp
(
kappa
/
cdn
**
0.5
)
zo
=
ref_ht
/
np
.
exp
(
kappa
/
cdn
**
0.5
)
zot
=
ref_ht
/
(
np
.
exp
(
kappa
**
2
/
(
ctn
*
np
.
log
(
ref_ht
/
zo
))))
zot
=
ref_ht
/
(
np
.
exp
(
kappa
**
2
/
(
ctn
*
np
.
log
(
ref_ht
/
zo
))))
zoq
=
ref_ht
/
(
np
.
exp
(
kappa
**
2
/
(
cqn
*
np
.
log
(
ref_ht
/
zo
))))
zoq
=
ref_ht
/
(
np
.
exp
(
kappa
**
2
/
(
cqn
*
np
.
log
(
ref_ht
/
zo
))))
urefs
=
spd
-
(
usr
/
kappa
)
*
(
np
.
log
(
hh_in
[
0
]
/
hh_out
[
0
])
-
psim
+
psim_calc
(
hh_out
[
0
]
/
monob
,
method
))
urefs
=
(
spd
-
(
usr
/
kappa
)
*
(
np
.
log
(
hh_in
[
0
]
/
hh_out
[
0
])
-
psim
+
trefs
=
Ta
-
(
tsr
/
kappa
)
*
(
np
.
log
(
hh_in
[
1
]
/
hh_out
[
1
])
-
psit
+
psit_calc
(
hh_out
[
0
]
/
monob
,
method
))
psim_calc
(
hh_out
[
0
]
/
monob
,
meth
)))
trefs
=
(
Ta
-
(
tsr
/
kappa
)
*
(
np
.
log
(
hh_in
[
1
]
/
hh_out
[
1
])
-
psit
+
psit_calc
(
hh_out
[
0
]
/
monob
,
meth
)))
trefs
=
trefs
-
(
273.16
+
tlapse
*
hh_out
[
1
])
trefs
=
trefs
-
(
273.16
+
tlapse
*
hh_out
[
1
])
qrefs
=
qair
-
(
qsr
/
kappa
)
*
(
np
.
log
(
hh_in
[
2
]
/
hh_out
[
2
])
-
psit
+
psit_calc
(
hh_out
[
2
]
/
monob
,
method
))
qrefs
=
(
qair
-
(
qsr
/
kappa
)
*
(
np
.
log
(
hh_in
[
2
]
/
hh_out
[
2
])
-
res
=
np
.
zeros
((
27
,
len
(
spd
)))
psit
+
psit_calc
(
hh_out
[
2
]
/
monob
,
meth
)))
res
[
0
][:]
=
tau
res
=
np
.
zeros
((
27
,
len
(
spd
)))
res
[
1
][:]
=
sensible
res
[
0
][:]
=
tau
res
[
2
][:]
=
latent
res
[
1
][:]
=
sensible
res
[
3
][:]
=
monob
res
[
2
][:]
=
latent
res
[
4
][:]
=
cd
res
[
3
][:]
=
monob
res
[
5
][:]
=
cdn
res
[
4
][:]
=
cd
res
[
6
][:]
=
ct
res
[
5
][:]
=
cdn
res
[
7
][:]
=
ctn
res
[
6
][:]
=
ct
res
[
8
][:]
=
cq
res
[
7
][:]
=
ctn
res
[
9
][:]
=
cqn
res
[
8
][:]
=
cq
res
[
10
][:]
=
tsrv
res
[
9
][:]
=
cqn
res
[
11
][:]
=
tsr
res
[
10
][:]
=
tsrv
res
[
12
][:]
=
qsr
res
[
11
][:]
=
tsr
res
[
13
][:]
=
usr
res
[
12
][:]
=
qsr
res
[
14
][:]
=
psim
res
[
13
][:]
=
usr
res
[
15
][:]
=
psit
res
[
14
][:]
=
psim
res
[
16
][:]
=
u10n
res
[
15
][:]
=
psit
res
[
17
][:]
=
t10n
res
[
16
][:]
=
u10n
res
[
18
][:]
=
tv10n
res
[
17
][:]
=
t10n
res
[
19
][:]
=
q10n
res
[
18
][:]
=
tv10n
res
[
20
][:]
=
zo
res
[
19
][:]
=
q10n
res
[
21
][:]
=
zot
res
[
20
][:]
=
zo
res
[
22
][:]
=
zoq
res
[
21
][:]
=
zot
res
[
23
][:]
=
urefs
res
[
22
][:]
=
zoq
res
[
24
][:]
=
trefs
res
[
23
][:]
=
urefs
res
[
25
][:]
=
qrefs
res
[
24
][:]
=
trefs
res
[
26
][:]
=
itera
res
[
25
][:]
=
qrefs
res
[
26
][:]
=
itera
return
res
,
ind
return
res
,
ind
def
charnock_C35
(
wind
,
u10n
,
usr
,
seastate
,
waveage
,
wcp
,
sigH
,
lat
):
g
=
gc
(
lat
,
None
)
a1
,
a2
=
0.0017
,
-
0.0050
charnC
=
np
.
where
(
u10n
>
19
,
a1
*
19
+
a2
,
a1
*
u10n
+
a2
)
A
,
B
=
0.114
,
0.622
#wave-age dependent coefficients
Ad
,
Bd
=
0.091
,
2.0
#Sea-state/wave-age dependent coefficients
charnW
=
A
*
(
usr
/
wcp
)
**
B
zoS
=
sigH
*
Ad
*
(
usr
/
wcp
)
**
Bd
charnS
=
(
zoS
*
g
)
/
usr
**
2
charn
=
np
.
where
(
wind
>
10
,
0.011
+
(
wind
-
10
)
/
(
18
-
10
)
*
(
0.018
-
0.011
),
np
.
where
(
wind
>
18
,
0.018
,
0.011
*
np
.
ones
(
np
.
shape
(
wind
))))
if
waveage
:
if
seastate
:
charn
=
charnS
else
:
charn
=
charnW
else
:
charn
=
charnC
ac
=
np
.
zeros
((
len
(
wind
),
3
))
ac
[:,
0
]
=
charn
ac
[:,
1
]
=
charnC
ac
[:,
2
]
=
charnW
return
ac
\ No newline at end of file
This diff is collapsed.
Click to expand it.
flux_subs.py
View file @
22be86dd
import
numpy
as
np
import
numpy
as
np
""" Conversion factor for [:math:`^
\\
circ` C] to [:math:`^
\\
circ` K] """
CtoK
=
273.16
# 273.15
CtoK
=
273.16
# 273.15
""" von Karman's constant """
""" Conversion factor for (^\circ\,C) to (^
\\
circ
\\
,K) """
kappa
=
0.4
# NOTE: 0.41
kappa
=
0.4
# NOTE: 0.41
""" von Karman's constant """
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
charnock_C35
(
wind
,
u10n
,
usr
,
seastate
,
waveage
,
wcp
,
sigH
,
lat
):
def
charnock_C35
(
wind
,
u10n
,
usr
,
seastate
,
waveage
,
wcp
,
sigH
,
lat
):
""" Calculates Charnock number following Edson et al. 2013 based on
C35 matlab code (coare35vn.m)
Parameters
----------
wind : float
wind speed (m/s)
u10n : float
neutral 10m wind speed (m/s)
usr : float
friction velocity (m/s)
seastate : bool
0 or 1
waveage : bool
0 or 1
wcp : float
phase speed of dominant waves (m/s)
sigH : float
significant wave height (m)
lat : float
latitude (deg)
Returns
-------
ac : float
Charnock number
"""
g
=
gc
(
lat
,
None
)
g
=
gc
(
lat
,
None
)
a1
,
a2
=
0.0017
,
-
0.0050
a1
,
a2
=
0.0017
,
-
0.0050
charnC
=
np
.
where
(
u10n
>
19
,
a1
*
19
+
a2
,
a1
*
u10n
+
a2
)
charnC
=
np
.
where
(
u10n
>
19
,
a1
*
19
+
a2
,
a1
*
u10n
+
a2
)
...
@@ -34,6 +62,37 @@ def charnock_C35(wind, u10n, usr, seastate, waveage, wcp, sigH, lat):
...
@@ -34,6 +62,37 @@ def charnock_C35(wind, u10n, usr, seastate, waveage, wcp, sigH, lat):
def
cd_C35
(
u10n
,
wind
,
usr
,
charn
,
monob
,
Ta
,
hh_in
,
lat
):
def
cd_C35
(
u10n
,
wind
,
usr
,
charn
,
monob
,
Ta
,
hh_in
,
lat
):
""" Calculates exchange coefficients following Edson et al. 2013 based on
C35 matlab code (coare35vn.m)
Parameters
----------
u10n : float
neutral 10m wind speed (m/s)
wind : float
wind speed (m/s)
charn : float
Charnock number
monob : float
Monin-Obukhov stability length
Ta : float
air temperature (K)
hh_in : float
input sensor's height (m)
lat : float
latitude (deg)
Returns
-------
zo : float
surface roughness (m)
cdhf : float
drag coefficient
cthf : float
heat exchange coefficient
cqhf : float
moisture exchange coefficient
"""
g
=
gc
(
lat
,
None
)
g
=
gc
(
lat
,
None
)
zo
=
charn
*
usr
**
2
/
g
+
0.11
*
visc_air
(
Ta
)
/
usr
# surface roughness
zo
=
charn
*
usr
**
2
/
g
+
0.11
*
visc_air
(
Ta
)
/
usr
# surface roughness
rr
=
zo
*
usr
/
visc_air
(
Ta
)
rr
=
zo
*
usr
/
visc_air
(
Ta
)
...
@@ -47,15 +106,31 @@ def cd_C35(u10n, wind, usr, charn, monob, Ta, hh_in, lat):
...
@@ -47,15 +106,31 @@ def cd_C35(u10n, wind, usr, charn, monob, Ta, hh_in, lat):
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
cdn_calc
(
u10n
,
Ta
,
Tp
,
method
=
"Smith80"
):
def
cdn_calc
(
u10n
,
Ta
,
Tp
,
method
=
"S80"
):
if
(
method
==
"Smith80"
):
""" Calculates neutral drag coefficient
Parameters
----------
u10n : float
neutral 10m wind speed (m/s)
Ta : float
air temperature (K)
Tp : float
wave period
method : str
Returns
-------
cdn : float
"""
if
(
method
==
"S80"
):
cdn
=
np
.
where
(
u10n
<=
3
,
(
0.61
+
0.567
/
u10n
)
*
0.001
,
cdn
=
np
.
where
(
u10n
<=
3
,
(
0.61
+
0.567
/
u10n
)
*
0.001
,
(
0.61
+
0.063
*
u10n
)
*
0.001
)
(
0.61
+
0.063
*
u10n
)
*
0.001
)
elif
(
method
==
"LP82"
):
elif
(
method
==
"LP82"
):
cdn
=
np
.
where
((
u10n
<
11
)
&
(
u10n
>=
4
),
1.2
*
0.001
,
cdn
=
np
.
where
((
u10n
<
11
)
&
(
u10n
>=
4
),
1.2
*
0.001
,
np
.
where
((
u10n
<=
25
)
&
(
u10n
>=
11
),
np
.
where
((
u10n
<=
25
)
&
(
u10n
>=
11
),
(
0.49
+
0.065
*
u10n
)
*
0.001
,
1.14
*
0.001
))
(
0.49
+
0.065
*
u10n
)
*
0.001
,
1.14
*
0.001
))
elif
(
method
==
"S
mith
88"
or
method
==
"C
OARE3.
0"
or
elif
(
method
==
"S88"
or
method
==
"C
3
0"
or
method
==
"COARE4.0"
or
method
==
"UA"
or
method
==
"ERA5"
):
method
==
"COARE4.0"
or
method
==
"UA"
or
method
==
"ERA5"
):
cdn
=
cdn_from_roughness
(
u10n
,
Ta
,
None
,
method
)
cdn
=
cdn_from_roughness
(
u10n
,
Ta
,
None
,
method
)
elif
(
method
==
"HEXOS"
):
elif
(
method
==
"HEXOS"
):
...
@@ -64,7 +139,7 @@ def cdn_calc(u10n, Ta, Tp, method="Smith80"):
...
@@ -64,7 +139,7 @@ def cdn_calc(u10n, Ta, Tp, method="Smith80"):
elif
(
method
==
"HEXOSwave"
):
elif
(
method
==
"HEXOSwave"
):
cdn
=
cdn_from_roughness
(
u10n
,
Ta
,
Tp
,
method
)
cdn
=
cdn_from_roughness
(
u10n
,
Ta
,
Tp
,
method
)
elif
(
method
==
"YT96"
):
elif
(
method
==
"YT96"
):
# for u<3 same as S
mith
80
# for u<3 same as S80
cdn
=
np
.
where
((
u10n
<
6
)
&
(
u10n
>=
3
),
cdn
=
np
.
where
((
u10n
<
6
)
&
(
u10n
>=
3
),
(
0.29
+
3.1
/
u10n
+
7.7
/
u10n
**
2
)
*
0.001
,
(
0.29
+
3.1
/
u10n
+
7.7
/
u10n
**
2
)
*
0.001
,
np
.
where
((
u10n
<=
26
)
&
(
u10n
>=
6
),
np
.
where
((
u10n
<=
26
)
&
(
u10n
>=
6
),
...
@@ -78,7 +153,23 @@ def cdn_calc(u10n, Ta, Tp, method="Smith80"):
...
@@ -78,7 +153,23 @@ def cdn_calc(u10n, Ta, Tp, method="Smith80"):
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
cdn_from_roughness
(
u10n
,
Ta
,
Tp
,
method
=
"Smith88"
):
def
cdn_from_roughness
(
u10n
,
Ta
,
Tp
,
method
=
"S88"
):
""" Calculates neutral drag coefficient from roughness length
Parameters
----------
u10n : float
neutral 10m wind speed (m/s)
Ta : float
air temperature (K)
Tp : float
wave period
method : str
Returns
-------
cdn : float
"""
g
,
tol
=
9.812
,
0.000001
g
,
tol
=
9.812
,
0.000001
cdn
,
usr
=
np
.
zeros
(
Ta
.
shape
),
np
.
zeros
(
Ta
.
shape
)
cdn
,
usr
=
np
.
zeros
(
Ta
.
shape
),
np
.
zeros
(
Ta
.
shape
)
cdnn
=
(
0.61
+
0.063
*
u10n
)
*
0.001
cdnn
=
(
0.61
+
0.063
*
u10n
)
*
0.001
...
@@ -86,13 +177,13 @@ def cdn_from_roughness(u10n, Ta, Tp, method="Smith88"):
...
@@ -86,13 +177,13 @@ def cdn_from_roughness(u10n, Ta, Tp, method="Smith88"):
for
it
in
range
(
5
):
for
it
in
range
(
5
):
cdn
=
np
.
copy
(
cdnn
)
cdn
=
np
.
copy
(
cdnn
)
usr
=
np
.
sqrt
(
cdn
*
u10n
**
2
)
usr
=
np
.
sqrt
(
cdn
*
u10n
**
2
)
if
(
method
==
"S
mith
88"
):
if
(
method
==
"S88"
):
# .....Charnock roughness length (equn 4 in Smith 88)
# .....Charnock roughness length (equn 4 in Smith 88)
zc
=
0.011
*
np
.
power
(
usr
,
2
)
/
g
zc
=
0.011
*
np
.
power
(
usr
,
2
)
/
g
# .....smooth surface roughness length (equn 6 in Smith 88)
# .....smooth surface roughness length (equn 6 in Smith 88)
zs
=
0.11
*
visc_air
(
Ta
)
/
usr
zs
=
0.11
*
visc_air
(
Ta
)
/
usr
zo
=
zc
+
zs
# .....equns 7 & 8 in Smith 88 to calculate new CDN
zo
=
zc
+
zs
# .....equns 7 & 8 in Smith 88 to calculate new CDN
elif
(
method
==
"C
OARE3.
0"
):
elif
(
method
==
"C
3
0"
):
zc
=
0.011
+
(
u10n
-
10
)
/
(
18
-
10
)
*
(
0.018
-
0.011
)
zc
=
0.011
+
(
u10n
-
10
)
/
(
18
-
10
)
*
(
0.018
-
0.011
)
zc
=
np
.
where
(
u10n
<
10
,
0.011
,
np
.
where
(
u10n
>
18
,
0.018
,
zc
))
zc
=
np
.
where
(
u10n
<
10
,
0.011
,
np
.
where
(
u10n
>
18
,
0.018
,
zc
))
zs
=
0.11
*
visc_air
(
Ta
)
/
usr
zs
=
0.11
*
visc_air
(
Ta
)
/
usr
...
@@ -116,9 +207,32 @@ def cdn_from_roughness(u10n, Ta, Tp, method="Smith88"):
...
@@ -116,9 +207,32 @@ def cdn_from_roughness(u10n, Ta, Tp, method="Smith88"):
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
ctcqn_calc
(
zol
,
cdn
,
u10n
,
zo
,
Ta
,
method
=
"Smith80"
):
def
ctcqn_calc
(
zol
,
cdn
,
u10n
,
zo
,
Ta
,
method
=
"S80"
):
if
(
method
==
"Smith80"
or
method
==
"Smith88"
or
method
==
"YT96"
):
""" Calculates neutral heat and moisture exchange coefficients
cqn
=
np
.
ones
(
Ta
.
shape
)
*
1.20
*
0.001
# from Smith88
Parameters
----------
zol : float
height over MO length
cdn : float
neatral drag coefficient
u10n : float
neutral 10m wind speed (m/s)
zo : float
surface roughness (m)
Ta : float
air temperature (K)
method : str
Returns
-------
ctn : float
neutral heat exchange coefficient
cqn : float
neutral moisture exchange coefficient
"""
if
(
method
==
"S80"
or
method
==
"S88"
or
method
==
"YT96"
):
cqn
=
np
.
ones
(
Ta
.
shape
)
*
1.20
*
0.001
# from S88
ctn
=
np
.
ones
(
Ta
.
shape
)
*
1.00
*
0.001
ctn
=
np
.
ones
(
Ta
.
shape
)
*
1.00
*
0.001
elif
(
method
==
"LP82"
):
elif
(
method
==
"LP82"
):
cqn
=
np
.
where
((
zol
<=
0
)
&
(
u10n
>
4
)
&
(
u10n
<
14
),
1.15
*
0.001
,
cqn
=
np
.
where
((
zol
<=
0
)
&
(
u10n
>
4
)
&
(
u10n
<
14
),
1.15
*
0.001
,
...
@@ -128,7 +242,7 @@ def ctcqn_calc(zol, cdn, u10n, zo, Ta, method="Smith80"):
...
@@ -128,7 +242,7 @@ def ctcqn_calc(zol, cdn, u10n, zo, Ta, method="Smith80"):
elif
(
method
==
"HEXOS"
or
method
==
"HEXOSwave"
):
elif
(
method
==
"HEXOS"
or
method
==
"HEXOSwave"
):
cqn
=
np
.
where
((
u10n
<=
23
)
&
(
u10n
>=
3
),
1.1
*
0.001
,
np
.
nan
)
cqn
=
np
.
where
((
u10n
<=
23
)
&
(
u10n
>=
3
),
1.1
*
0.001
,
np
.
nan
)
ctn
=
np
.
where
((
u10n
<=
18
)
&
(
u10n
>=
3
),
1.1
*
0.001
,
np
.
nan
)
ctn
=
np
.
where
((
u10n
<=
18
)
&
(
u10n
>=
3
),
1.1
*
0.001
,
np
.
nan
)
elif
(
method
==
"C
OARE3.
0"
or
method
==
"COARE4.0"
):
elif
(
method
==
"C
3
0"
or
method
==
"COARE4.0"
):
usr
=
(
cdn
*
u10n
**
2
)
**
0.5
usr
=
(
cdn
*
u10n
**
2
)
**
0.5
rr
=
zo
*
usr
/
visc_air
(
Ta
)
rr
=
zo
*
usr
/
visc_air
(
Ta
)
zoq
=
5.5e-5
/
rr
**
0.6
zoq
=
5.5e-5
/
rr
**
0.6
...
@@ -162,6 +276,23 @@ def ctcqn_calc(zol, cdn, u10n, zo, Ta, method="Smith80"):
...
@@ -162,6 +276,23 @@ def ctcqn_calc(zol, cdn, u10n, zo, Ta, method="Smith80"):
def
cd_calc
(
cdn
,
height
,
ref_ht
,
psim
):
def
cd_calc
(
cdn
,
height
,
ref_ht
,
psim
):
""" Calculates drag coefficient at reference height
Parameters
----------
cdn : float
neutral drag coefficient
height : float
original sensor height (m)
ref_ht : float
reference height (m)
psim : float
momentum stability function
Returns
-------
cd : float
"""
cd
=
(
cdn
*
np
.
power
(
1
+
np
.
sqrt
(
cdn
)
*
np
.
power
(
kappa
,
-
1
)
*
cd
=
(
cdn
*
np
.
power
(
1
+
np
.
sqrt
(
cdn
)
*
np
.
power
(
kappa
,
-
1
)
*
(
np
.
log
(
height
/
ref_ht
)
-
psim
),
-
2
))
(
np
.
log
(
height
/
ref_ht
)
-
psim
),
-
2
))
return
cd
return
cd
...
@@ -169,16 +300,56 @@ def cd_calc(cdn, height, ref_ht, psim):
...
@@ -169,16 +300,56 @@ def cd_calc(cdn, height, ref_ht, psim):
def
ctcq_calc
(
cdn
,
cd
,
ctn
,
cqn
,
h_t
,
h_q
,
ref_ht
,
psit
,
psiq
):
def
ctcq_calc
(
cdn
,
cd
,
ctn
,
cqn
,
h_t
,
h_q
,
ref_ht
,
psit
,
psiq
):
""" Calculates heat and moisture exchange coefficients at reference height
Parameters
----------
cdn : float
neutral drag coefficient
cd : float
drag coefficient at reference height
ctn : float
neutral heat exchange coefficient
cqn : float
neutral moisture exchange coefficient
h_t : float
original temperature sensor height (m)
h_q : float
original moisture sensor height (m)
ref_ht : float
reference height (m)
psit : float
heat stability function
psiq : float
moisture stability function
Returns
-------
ct : float
cq : float
"""
ct
=
ctn
*
(
cd
/
cdn
)
**
0.5
/
(
1
+
ctn
*
((
np
.
log
(
h_t
/
ref_ht
)
-
psit
)
/
(
kappa
*
cdn
**
0.5
)))
ct
=
ctn
*
(
cd
/
cdn
)
**
0.5
/
(
1
+
ctn
*
((
np
.
log
(
h_t
/
ref_ht
)
-
psit
)
/
(
kappa
*
cdn
**
0.5
)))
cq
=
cqn
*
(
cd
/
cdn
)
**
0.5
/
(
1
+
cqn
*
((
np
.
log
(
h_q
/
ref_ht
)
-
psiq
)
/
(
kappa
*
cdn
**
0.5
)))
cq
=
cqn
*
(
cd
/
cdn
)
**
0.5
/
(
1
+
cqn
*
((
np
.
log
(
h_q
/
ref_ht
)
-
psiq
)
/
(
kappa
*
cdn
**
0.5
)))
return
ct
,
cq
return
ct
,
cq
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
psim_calc
(
zol
,
method
=
"Smith80"
):
def
psim_calc
(
zol
,
method
=
"S80"
):
""" Calculates momentum stability function
Parameters
----------
zol : float
height over MO length
method : str
Returns
-------
psim : float
"""
coeffs
=
get_stabco
(
method
)
coeffs
=
get_stabco
(
method
)
alpha
,
beta
,
gamma
=
coeffs
[
0
],
coeffs
[
1
],
coeffs
[
2
]
alpha
,
beta
,
gamma
=
coeffs
[
0
],
coeffs
[
1
],
coeffs
[
2
]
if
(
method
==
"C
OARE3.
0"
or
method
==
"COARE4.0"
):
if
(
method
==
"C
3
0"
or
method
==
"COARE4.0"
):
psim
=
np
.
where
(
zol
<
0
,
psim_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
),
psim
=
np
.
where
(
zol
<
0
,
psim_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
),
psim_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
))
psim_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
))
elif
(
method
==
"ERA5"
):
elif
(
method
==
"ERA5"
):
...
@@ -191,10 +362,22 @@ def psim_calc(zol, method="Smith80"):
...
@@ -191,10 +362,22 @@ def psim_calc(zol, method="Smith80"):
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
psit_calc
(
zol
,
method
=
"Smith80"
):
def
psit_calc
(
zol
,
method
=
"S80"
):
""" Calculates heat stability function
Parameters
----------
zol : float
height over MO length
method : str
Returns
-------
psit : float
"""
coeffs
=
get_stabco
(
method
)
coeffs
=
get_stabco
(
method
)
alpha
,
beta
,
gamma
=
coeffs
[
0
],
coeffs
[
1
],
coeffs
[
2
]
alpha
,
beta
,
gamma
=
coeffs
[
0
],
coeffs
[
1
],
coeffs
[
2
]
if
(
method
==
"C
OARE3.
0"
or
method
==
"COARE4.0"
):
if
(
method
==
"C
3
0"
or
method
==
"COARE4.0"
):
psit
=
np
.
where
(
zol
<
0
,
psi_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
),
psit
=
np
.
where
(
zol
<
0
,
psi_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
),
psi_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
))
psi_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
))
elif
(
method
==
"ERA5"
):
elif
(
method
==
"ERA5"
):
...
@@ -207,8 +390,18 @@ def psit_calc(zol, method="Smith80"):
...
@@ -207,8 +390,18 @@ def psit_calc(zol, method="Smith80"):
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
get_stabco
(
method
=
"Smith80"
):
def
get_stabco
(
method
=
"S80"
):
if
(
method
==
"Smith80"
or
method
==
"Smith88"
or
method
==
"LY04"
or
""" Gives the coefficients
\\
alpha,
\\
beta,
\\
gamma for stability functions
Parameters
----------
method : str
Returns
-------
coeffs : float
"""
if
(
method
==
"S80"
or
method
==
"S88"
or
method
==
"LY04"
or
method
==
"UA"
or
method
==
"ERA5"
):
method
==
"UA"
or
method
==
"ERA5"
):
alpha
,
beta
,
gamma
=
16
,
0.25
,
5
# Smith 1980, from Dyer (1974)
alpha
,
beta
,
gamma
=
16
,
0.25
,
5
# Smith 1980, from Dyer (1974)
elif
(
method
==
"LP82"
):
elif
(
method
==
"LP82"
):
...
@@ -217,7 +410,7 @@ def get_stabco(method="Smith80"):
...
@@ -217,7 +410,7 @@ def get_stabco(method="Smith80"):
alpha
,
beta
,
gamma
=
16
,
0.25
,
8
alpha
,
beta
,
gamma
=
16
,
0.25
,
8
elif
(
method
==
"YT96"
):
elif
(
method
==
"YT96"
):
alpha
,
beta
,
gamma
=
20
,
0.25
,
5
alpha
,
beta
,
gamma
=
20
,
0.25
,
5
elif
(
method
==
"C
OARE3.
0"
or
method
==
"COARE4.0"
):
elif
(
method
==
"C
3
0"
or
method
==
"COARE4.0"
):
# use separate subroutine
# use separate subroutine
alpha
,
beta
,
gamma
=
15
,
1
/
3
,
5
# not sure about gamma=34.15
alpha
,
beta
,
gamma
=
15
,
1
/
3
,
5
# not sure about gamma=34.15
else
:
else
:
...
@@ -231,6 +424,22 @@ def get_stabco(method="Smith80"):
...
@@ -231,6 +424,22 @@ def get_stabco(method="Smith80"):
def
psi_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
):
def
psi_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates heat stability function for unstable conditions
for method C30
Parameters
----------
zol : float
height over MO length
alpha : float
beta : float
gamma : float
constants given by get_stabco
Returns
-------
psit : float
"""
x
=
(
1
-
alpha
*
zol
)
**
0.5
# Kansas unstable
x
=
(
1
-
alpha
*
zol
)
**
0.5
# Kansas unstable
psik
=
2
*
np
.
log
((
1
+
x
)
/
2.
)
psik
=
2
*
np
.
log
((
1
+
x
)
/
2.
)
y
=
(
1
-
34.15
*
zol
)
**
beta
y
=
(
1
-
34.15
*
zol
)
**
beta
...
@@ -242,7 +451,21 @@ def psi_conv_coare3(zol, alpha, beta, gamma):
...
@@ -242,7 +451,21 @@ def psi_conv_coare3(zol, alpha, beta, gamma):
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
psi_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
):
# Stable
def
psi_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates heat stability function for stable conditions
for method C30
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psi : float
"""
c
=
np
.
where
(
0.35
*
zol
>
50
,
50
,
0.35
*
zol
)
# Stable
c
=
np
.
where
(
0.35
*
zol
>
50
,
50
,
0.35
*
zol
)
# Stable
psit
=
-
((
1
+
2
*
zol
/
3
)
**
1.5
+
0.6667
*
(
zol
-
14.28
)
/
np
.
exp
(
c
)
+
8.525
)
psit
=
-
((
1
+
2
*
zol
/
3
)
**
1.5
+
0.6667
*
(
zol
-
14.28
)
/
np
.
exp
(
c
)
+
8.525
)
return
psit
return
psit
...
@@ -250,6 +473,20 @@ def psi_stab_coare3(zol, alpha, beta, gamma): # Stable
...
@@ -250,6 +473,20 @@ def psi_stab_coare3(zol, alpha, beta, gamma): # Stable
def
psi_stab_era5
(
zol
,
alpha
,
beta
,
gamma
):
def
psi_stab_era5
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates heat stability function for stable conditions
for method ERA5
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psit : float
"""
# eq (3.22) p. 39 IFS Documentation cy46r1
# eq (3.22) p. 39 IFS Documentation cy46r1
a
,
b
,
c
,
d
=
1
,
2
/
3
,
5
,
0.35
a
,
b
,
c
,
d
=
1
,
2
/
3
,
5
,
0.35
psit
=
-
b
*
(
zol
-
c
/
d
)
*
np
.
exp
(
-
d
*
zol
)
-
np
.
power
(
1
+
(
2
/
3
)
*
a
*
zol
,
1.5
)
-
(
b
*
c
)
/
d
+
1
psit
=
-
b
*
(
zol
-
c
/
d
)
*
np
.
exp
(
-
d
*
zol
)
-
np
.
power
(
1
+
(
2
/
3
)
*
a
*
zol
,
1.5
)
-
(
b
*
c
)
/
d
+
1
...
@@ -257,6 +494,19 @@ def psi_stab_era5(zol, alpha, beta, gamma):
...
@@ -257,6 +494,19 @@ def psi_stab_era5(zol, alpha, beta, gamma):
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
psi_conv
(
zol
,
alpha
,
beta
,
gamma
):
def
psi_conv
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates heat stability function for unstable conditions
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psit : float
"""
xtmp
=
(
1
-
alpha
*
zol
)
**
beta
xtmp
=
(
1
-
alpha
*
zol
)
**
beta
psit
=
2
*
np
.
log
((
1
+
xtmp
**
2
)
*
0.5
)
psit
=
2
*
np
.
log
((
1
+
xtmp
**
2
)
*
0.5
)
return
psit
return
psit
...
@@ -264,30 +514,65 @@ def psi_conv(zol, alpha, beta, gamma):
...
@@ -264,30 +514,65 @@ def psi_conv(zol, alpha, beta, gamma):
def
psi_stab
(
zol
,
alpha
,
beta
,
gamma
):
def
psi_stab
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates heat stability function for stable conditions
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psit : float
"""
psit
=
-
gamma
*
zol
psit
=
-
gamma
*
zol
return
psit
return
psit
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
psit_26
(
zet
):
def
psit_26
(
zol
):
"""
""" Computes temperature structure function as in C35
computes temperature structure function as in COARE3.5
Parameters
----------
zol : float
height over MO length
Returns
-------
psi : float
"""
"""
dz
et
=
np
.
where
(
0.35
*
z
et
>
50
,
50
,
0.35
*
z
et
)
# stable
dz
ol
=
np
.
where
(
0.35
*
z
ol
>
50
,
50
,
0.35
*
z
ol
)
# stable
psi
=
-
((
1
+
0.6667
*
z
et
)
**
1.5
+
0.6667
*
(
z
et
-
14.28
)
*
np
.
exp
(
-
dz
et
)
+
8.525
)
psi
=
-
((
1
+
0.6667
*
z
ol
)
**
1.5
+
0.6667
*
(
z
ol
-
14.28
)
*
np
.
exp
(
-
dz
ol
)
+
8.525
)
k
=
np
.
where
(
z
et
<
0
)
# unstable
k
=
np
.
where
(
z
ol
<
0
)
# unstable
x
=
(
1
-
15
*
z
et
[
k
])
**
0.5
x
=
(
1
-
15
*
z
ol
[
k
])
**
0.5
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
x
=
(
1
-
34.15
*
z
et
[
k
])
**
0.3333
x
=
(
1
-
34.15
*
z
ol
[
k
])
**
0.3333
psic
=
(
1.5
*
np
.
log
((
1
+
x
+
x
**
2
)
/
3
)
-
np
.
sqrt
(
3
)
*
np
.
arctan
((
1
+
2
*
x
)
/
psic
=
(
1.5
*
np
.
log
((
1
+
x
+
x
**
2
)
/
3
)
-
np
.
sqrt
(
3
)
*
np
.
arctan
((
1
+
2
*
x
)
/
np
.
sqrt
(
3
))
+
4
*
np
.
arctan
(
1
)
/
np
.
sqrt
(
3
))
np
.
sqrt
(
3
))
+
4
*
np
.
arctan
(
1
)
/
np
.
sqrt
(
3
))
f
=
z
et
[
k
]
**
2
/
(
1
+
z
et
[
k
]
**
2
)
f
=
z
ol
[
k
]
**
2
/
(
1
+
z
ol
[
k
]
**
2
)
psi
[
k
]
=
(
1
-
f
)
*
psik
+
f
*
psic
psi
[
k
]
=
(
1
-
f
)
*
psik
+
f
*
psic
return
psi
return
psi
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
psim_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
):
def
psim_conv_coare3
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates momentum stability function for unstable conditions
for method C30
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psim : float
"""
x
=
(
1
-
15
*
zol
)
**
0.25
# Kansas unstable
x
=
(
1
-
15
*
zol
)
**
0.25
# Kansas unstable
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
+
np
.
log
((
1
+
x
*
x
)
/
2
)
-
2
*
np
.
arctan
(
x
)
+
2
*
np
.
arctan
(
1
)
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
+
np
.
log
((
1
+
x
*
x
)
/
2
)
-
2
*
np
.
arctan
(
x
)
+
2
*
np
.
arctan
(
1
)
y
=
(
1
-
10.15
*
zol
)
**
0.3333
# Convective
y
=
(
1
-
10.15
*
zol
)
**
0.3333
# Convective
...
@@ -300,6 +585,20 @@ def psim_conv_coare3(zol, alpha, beta, gamma):
...
@@ -300,6 +585,20 @@ def psim_conv_coare3(zol, alpha, beta, gamma):
def
psim_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
):
def
psim_stab_coare3
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates momentum stability function for stable conditions
for method C30
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psim : float
"""
c
=
np
.
where
(
0.35
*
zol
>
50
,
50
,
0.35
*
zol
)
# Stable
c
=
np
.
where
(
0.35
*
zol
>
50
,
50
,
0.35
*
zol
)
# Stable
psim
=
-
((
1
+
1
*
zol
)
**
1.0
+
0.6667
*
(
zol
-
14.28
)
/
np
.
exp
(
-
c
)
+
8.525
)
psim
=
-
((
1
+
1
*
zol
)
**
1.0
+
0.6667
*
(
zol
-
14.28
)
/
np
.
exp
(
-
c
)
+
8.525
)
return
psim
return
psim
...
@@ -307,6 +606,20 @@ def psim_stab_coare3(zol, alpha, beta, gamma):
...
@@ -307,6 +606,20 @@ def psim_stab_coare3(zol, alpha, beta, gamma):
def
psim_stab_era5
(
zol
,
alpha
,
beta
,
gamma
):
def
psim_stab_era5
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates momentum stability function for stable conditions
for method ERA5
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psim : float
"""
# eq (3.22) p. 39 IFS Documentation cy46r1
# eq (3.22) p. 39 IFS Documentation cy46r1
a
,
b
,
c
,
d
=
1
,
2
/
3
,
5
,
0.35
a
,
b
,
c
,
d
=
1
,
2
/
3
,
5
,
0.35
psim
=
-
b
*
(
zol
-
c
/
d
)
*
np
.
exp
(
-
d
*
zol
)
-
a
*
zol
-
(
b
*
c
)
/
d
psim
=
-
b
*
(
zol
-
c
/
d
)
*
np
.
exp
(
-
d
*
zol
)
-
a
*
zol
-
(
b
*
c
)
/
d
...
@@ -315,6 +628,19 @@ def psim_stab_era5(zol, alpha, beta, gamma):
...
@@ -315,6 +628,19 @@ def psim_stab_era5(zol, alpha, beta, gamma):
def
psim_conv
(
zol
,
alpha
,
beta
,
gamma
):
def
psim_conv
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates momentum stability function for unstable conditions
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psim : float
"""
xtmp
=
(
1
-
alpha
*
zol
)
**
beta
xtmp
=
(
1
-
alpha
*
zol
)
**
beta
psim
=
(
2
*
np
.
log
((
1
+
xtmp
)
*
0.5
)
+
np
.
log
((
1
+
xtmp
**
2
)
*
0.5
)
-
psim
=
(
2
*
np
.
log
((
1
+
xtmp
)
*
0.5
)
+
np
.
log
((
1
+
xtmp
**
2
)
*
0.5
)
-
2
*
np
.
arctan
(
xtmp
)
+
np
.
pi
/
2
)
2
*
np
.
arctan
(
xtmp
)
+
np
.
pi
/
2
)
...
@@ -323,50 +649,112 @@ def psim_conv(zol, alpha, beta, gamma):
...
@@ -323,50 +649,112 @@ def psim_conv(zol, alpha, beta, gamma):
def
psim_stab
(
zol
,
alpha
,
beta
,
gamma
):
def
psim_stab
(
zol
,
alpha
,
beta
,
gamma
):
""" Calculates momentum stability function for stable conditions
Parameters
----------
zol : float
height over MO length
alpha, beta, gamma : float
constants given by get_stabco
Returns
-------
psim : float
"""
psim
=
-
gamma
*
zol
psim
=
-
gamma
*
zol
return
psim
return
psim
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
psiu_26
(
zet
):
def
psiu_26
(
zol
):
""" Computes velocity structure function C35
Parameters
----------
zol : float
height over MO length
Returns
-------
psi : float
"""
"""
computes velocity structure function COARE3.5
dzol
=
np
.
where
(
0.35
*
zol
>
50
,
50
,
0.35
*
zol
)
# stable
"""
dzet
=
np
.
where
(
0.35
*
zet
>
50
,
50
,
0.35
*
zet
)
# stable
a
,
b
,
c
,
d
=
0.7
,
3
/
4
,
5
,
0.35
a
,
b
,
c
,
d
=
0.7
,
3
/
4
,
5
,
0.35
psi
=
-
(
a
*
z
et
+
b
*
(
z
et
-
c
/
d
)
*
np
.
exp
(
-
dz
et
)
+
b
*
c
/
d
)
psi
=
-
(
a
*
z
ol
+
b
*
(
z
ol
-
c
/
d
)
*
np
.
exp
(
-
dz
ol
)
+
b
*
c
/
d
)
k
=
np
.
where
(
z
et
<
0
)
# unstable
k
=
np
.
where
(
z
ol
<
0
)
# unstable
x
=
(
1
-
15
*
z
et
[
k
])
**
0.25
x
=
(
1
-
15
*
z
ol
[
k
])
**
0.25
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
+
np
.
log
((
1
+
x
**
2
)
/
2
)
-
2
*
np
.
arctan
(
x
)
+
2
*
np
.
arctan
(
1
)
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
+
np
.
log
((
1
+
x
**
2
)
/
2
)
-
2
*
np
.
arctan
(
x
)
+
2
*
np
.
arctan
(
1
)
x
=
(
1
-
10.15
*
z
et
[
k
])
**
0.3333
x
=
(
1
-
10.15
*
z
ol
[
k
])
**
0.3333
psic
=
(
1.5
*
np
.
log
((
1
+
x
+
x
**
2
)
/
3
)
-
np
.
sqrt
(
3
)
*
np
.
arctan
((
1
+
2
*
x
)
/
np
.
sqrt
(
3
))
+
psic
=
(
1.5
*
np
.
log
((
1
+
x
+
x
**
2
)
/
3
)
-
np
.
sqrt
(
3
)
*
np
.
arctan
((
1
+
2
*
x
)
/
np
.
sqrt
(
3
))
+
4
*
np
.
arctan
(
1
)
/
np
.
sqrt
(
3
))
4
*
np
.
arctan
(
1
)
/
np
.
sqrt
(
3
))
f
=
z
et
[
k
]
**
2
/
(
1
+
z
et
[
k
]
**
2
)
f
=
z
ol
[
k
]
**
2
/
(
1
+
z
ol
[
k
]
**
2
)
psi
[
k
]
=
(
1
-
f
)
*
psik
+
f
*
psic
psi
[
k
]
=
(
1
-
f
)
*
psik
+
f
*
psic
return
psi
return
psi
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
def
psiu_40
(
zet
):
def
psiu_40
(
zol
):
"""
""" Computes velocity structure function C35
computes velocity structure function COARE3.5
Parameters
----------
zol : float
height over MO length
Returns
-------
psi : float
"""
"""
dz
et
=
np
.
where
(
0.35
*
z
et
>
50
,
50
,
0.35
*
z
et
)
# stable
dz
ol
=
np
.
where
(
0.35
*
z
ol
>
50
,
50
,
0.35
*
z
ol
)
# stable
a
,
b
,
c
,
d
=
1
,
3
/
4
,
5
,
0.35
a
,
b
,
c
,
d
=
1
,
3
/
4
,
5
,
0.35
psi
=
-
(
a
*
z
et
+
b
*
(
z
et
-
c
/
d
)
*
np
.
exp
(
-
dz
et
)
+
b
*
c
/
d
)
psi
=
-
(
a
*
z
ol
+
b
*
(
z
ol
-
c
/
d
)
*
np
.
exp
(
-
dz
ol
)
+
b
*
c
/
d
)
k
=
np
.
where
(
z
et
<
0
)
# unstable
k
=
np
.
where
(
z
ol
<
0
)
# unstable
x
=
(
1
-
18
*
z
et
[
k
])
**
0.25
x
=
(
1
-
18
*
z
ol
[
k
])
**
0.25
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
+
np
.
log
((
1
+
x
**
2
)
/
2
)
-
2
*
np
.
arctan
(
x
)
+
2
*
np
.
arctan
(
1
)
psik
=
2
*
np
.
log
((
1
+
x
)
/
2
)
+
np
.
log
((
1
+
x
**
2
)
/
2
)
-
2
*
np
.
arctan
(
x
)
+
2
*
np
.
arctan
(
1
)
x
=
(
1
-
10
*
z
et
[
k
])
**
0.3333
x
=
(
1
-
10
*
z
ol
[
k
])
**
0.3333
psic
=
(
1.5
*
np
.
log
((
1
+
x
+
x
**
2
)
/
3
)
-
np
.
sqrt
(
3
)
*
np
.
arctan
((
1
+
2
*
x
)
/
np
.
sqrt
(
3
))
+
psic
=
(
1.5
*
np
.
log
((
1
+
x
+
x
**
2
)
/
3
)
-
np
.
sqrt
(
3
)
*
np
.
arctan
((
1
+
2
*
x
)
/
np
.
sqrt
(
3
))
+
4
*
np
.
arctan
(
1
)
/
np
.
sqrt
(
3
))
4
*
np
.
arctan
(
1
)
/
np
.
sqrt
(
3
))
f
=
z
et
[
k
]
**
2
/
(
1
+
z
et
[
k
]
**
2
)
f
=
z
ol
[
k
]
**
2
/
(
1
+
z
ol
[
k
]
**
2
)
psi
[
k
]
=
(
1
-
f
)
*
psik
+
f
*
psic
psi
[
k
]
=
(
1
-
f
)
*
psik
+
f
*
psic
return
psi
return
psi
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
def
get_skin
(
sst
,
qsea
,
rho
,
jcool
,
Rl
,
Rs
,
Rnl
,
cp
,
lv
,
usr
,
tsr
,
qsr
,
lat
):
def
get_skin
(
sst
,
qsea
,
rho
,
Rl
,
Rs
,
Rnl
,
cp
,
lv
,
usr
,
tsr
,
qsr
,
lat
):
""" Computes cool skin
Parameters
----------
sst : float
sea surface temperature ($^\circ$\,C)
qsea : float
specific humidity over sea (g/kg)
rho : float
density of air (kg/m^3)
Rl : float
downward longwave radiation (W/m^2)
Rs : float
downward shortwave radiation (W/m^2)
cp : float
specific heat of air at constant pressure
lv : float
latent heat of vaporization
usr : float
friction velocity
tsr : float
star temperature
qsr : float
star humidity
lat : float
latitude
Returns
-------
dter : float
dqer : float
"""
# coded following Saunders (1967) with lambda = 6
# coded following Saunders (1967) with lambda = 6
g
=
gc
(
lat
,
None
)
g
=
gc
(
lat
,
None
)
if
(
np
.
nanmin
(
sst
)
>
200
):
# if Ta in Kelvin convert to Celsius
if
(
np
.
nanmin
(
sst
)
>
200
):
# if Ta in Kelvin convert to Celsius
...
@@ -397,6 +785,27 @@ def get_skin(sst, qsea, rho, jcool, Rl, Rs, Rnl, cp, lv, usr, tsr, qsr, lat):
...
@@ -397,6 +785,27 @@ def get_skin(sst, qsea, rho, jcool, Rl, Rs, Rnl, cp, lv, usr, tsr, qsr, lat):
def
get_gust
(
beta
,
Ta
,
usr
,
tsrv
,
zi
,
lat
):
def
get_gust
(
beta
,
Ta
,
usr
,
tsrv
,
zi
,
lat
):
""" Computes gustiness
Parameters
----------
beta : float
constant
Ta : float
air temperature (K)
usr : float
friction velocity (m/s)
tsrv : float
star virtual temperature of air (K)
zi : int
scale height of the boundary layer depth (m)
lat : float
latitude
Returns
-------
ug : float
"""
if
(
np
.
max
(
Ta
)
<
200
):
# convert to K if in Celsius
if
(
np
.
max
(
Ta
)
<
200
):
# convert to K if in Celsius
Ta
=
Ta
+
273.16
Ta
=
Ta
+
273.16
if
np
.
isnan
(
zi
):
if
np
.
isnan
(
zi
):
...
@@ -410,6 +819,17 @@ def get_gust(beta, Ta, usr, tsrv, zi, lat):
...
@@ -410,6 +819,17 @@ def get_gust(beta, Ta, usr, tsrv, zi, lat):
def
get_heights
(
h
):
def
get_heights
(
h
):
""" Reads input heights for velocity, temperature and humidity
Parameters
----------
h : float
input heights (m)
Returns
-------
hh : array
"""
hh
=
np
.
zeros
(
3
)
hh
=
np
.
zeros
(
3
)
if
(
type
(
h
)
==
float
or
type
(
h
)
==
int
):
if
(
type
(
h
)
==
float
or
type
(
h
)
==
int
):
hh
[
0
],
hh
[
1
],
hh
[
2
]
=
h
,
h
,
h
hh
[
0
],
hh
[
1
],
hh
[
2
]
=
h
,
h
,
h
...
@@ -422,10 +842,17 @@ def get_heights(h):
...
@@ -422,10 +842,17 @@ def get_heights(h):
def
svp_calc
(
T
):
def
svp_calc
(
T
):
"""
""" Calculates saturation vapour pressure
calculates saturation vapour pressure
T is in Kelvin
Parameters
svp in mb, pure water
----------
T : float
temperature (K)
Returns
-------
svp : float
in mb, pure water
"""
"""
if
(
np
.
nanmin
(
T
)
<
200
):
# if T in Celsius convert to Kelvin
if
(
np
.
nanmin
(
T
)
<
200
):
# if T in Celsius convert to Kelvin
T
=
T
+
273.16
T
=
T
+
273.16
...
@@ -435,10 +862,19 @@ def svp_calc(T):
...
@@ -435,10 +862,19 @@ def svp_calc(T):
def
qsea_calc
(
sst
,
pres
):
def
qsea_calc
(
sst
,
pres
):
"""
""" Computes specific humidity of the sea surface air
sst in Kelvin
pres in mb
Parameters
qsea in kg/kg
----------
sst : float
sea surface temperature (K)
pres : float
pressure (mb)
Returns
-------
qsea : float
(kg/kg)
"""
"""
if
(
np
.
nanmin
(
sst
)
<
200
):
# if sst in Celsius convert to Kelvin
if
(
np
.
nanmin
(
sst
)
<
200
):
# if sst in Celsius convert to Kelvin
sst
=
sst
+
273.16
sst
=
sst
+
273.16
...
@@ -451,11 +887,20 @@ def qsea_calc(sst, pres):
...
@@ -451,11 +887,20 @@ def qsea_calc(sst, pres):
def
q_calc
(
Ta
,
rh
,
pres
):
def
q_calc
(
Ta
,
rh
,
pres
):
"""
""" Computes specific humidity following Haltiner and Martin p.24
rh in %
air in K, if not it will be converted to K
Parameters
pres in mb
----------
qair in kg/kg, as in Haltiner and Martin p.24
Ta : float
air temperature (K)
rh : float
relative humidity (%)
pres : float
air pressure (mb)
Returns
-------
qair : float, (kg/kg)
"""
"""
if
(
np
.
nanmin
(
Ta
)
<
200
):
# if sst in Celsius convert to Kelvin
if
(
np
.
nanmin
(
Ta
)
<
200
):
# if sst in Celsius convert to Kelvin
Ta
=
Ta
+
273.15
Ta
=
Ta
+
273.15
...
@@ -466,9 +911,18 @@ def q_calc(Ta, rh, pres):
...
@@ -466,9 +911,18 @@ def q_calc(Ta, rh, pres):
def
bucksat
(
T
,
P
):
def
bucksat
(
T
,
P
):
"""
""" Computes saturation vapor pressure (mb) as in C35
computes saturation vapor pressure [mb] as in COARE3.5
given T [degC] and P [mb]
Parameters
----------
T : float
temperature ($^
\\
circ$
\\
,C)
P : float
pressure (mb)
Returns
-------
exx : float
"""
"""
T
=
np
.
asarray
(
T
)
T
=
np
.
asarray
(
T
)
if
(
np
.
nanmin
(
T
)
>
200
):
# if Ta in Kelvin convert to Celsius
if
(
np
.
nanmin
(
T
)
>
200
):
# if Ta in Kelvin convert to Celsius
...
@@ -479,9 +933,18 @@ def bucksat(T, P):
...
@@ -479,9 +933,18 @@ def bucksat(T, P):
def
qsat26sea
(
T
,
P
):
def
qsat26sea
(
T
,
P
):
"""
""" Computes surface saturation specific humidity (g/kg) as in C35
computes surface saturation specific humidity [g/kg] as in COARE3.5
given T [degC] and P [mb]
Parameters
----------
T : float
temperature ($^
\\
circ$
\\
,C)
P : float
pressure (mb)
Returns
-------
qs : float
"""
"""
T
=
np
.
asarray
(
T
)
T
=
np
.
asarray
(
T
)
if
(
np
.
nanmin
(
T
)
>
200
):
# if Ta in Kelvin convert to Celsius
if
(
np
.
nanmin
(
T
)
>
200
):
# if Ta in Kelvin convert to Celsius
...
@@ -494,9 +957,19 @@ def qsat26sea(T, P):
...
@@ -494,9 +957,19 @@ def qsat26sea(T, P):
def
qsat26air
(
T
,
P
,
rh
):
def
qsat26air
(
T
,
P
,
rh
):
"""
""" Computes saturation specific humidity (g/kg) as in C35
computes saturation specific humidity [g/kg] as in COARE3.5
given T [degC] and P [mb]
Parameters
----------
T : float
temperature ($^\circ$\,C)
P : float
pressure (mb)
Returns
-------
q : float
em : float
"""
"""
T
=
np
.
asarray
(
T
)
T
=
np
.
asarray
(
T
)
if
(
np
.
nanmin
(
T
)
>
200
):
# if Ta in Kelvin convert to Celsius
if
(
np
.
nanmin
(
T
)
>
200
):
# if Ta in Kelvin convert to Celsius
...
@@ -509,13 +982,19 @@ def qsat26air(T, P, rh):
...
@@ -509,13 +982,19 @@ def qsat26air(T, P, rh):
def
gc
(
lat
,
lon
=
None
):
def
gc
(
lat
,
lon
=
None
):
"""
""" Computes gravity relative to latitude
computes gravity relative to latitude
inputs:
Parameters
lat : latitudes in deg
----------
lon : longitudes (optional)
lat : float
output:
latitude ($^\circ$)
gc: gravity constant
lon : float
longitude ($^\circ$, optional)
Returns
-------
gc : float
gravity constant (m/s^2)
"""
"""
gamma
=
9.7803267715
gamma
=
9.7803267715
c1
=
0.0052790414
c1
=
0.0052790414
...
@@ -535,13 +1014,18 @@ def gc(lat, lon=None):
...
@@ -535,13 +1014,18 @@ def gc(lat, lon=None):
def
visc_air
(
Ta
):
def
visc_air
(
Ta
):
"""
""" Computes the kinematic viscosity of dry air as a function of air temp.
Computes the kinematic viscosity of dry air as a function of air temp.
following Andreas (1989), CRREL Report 89-11.
following Andreas (1989), CRREL Report 89-11.
input:
Ta : air temperature [Celsius]
Parameters
output
----------
visa : kinematic viscosity [m^2/s]
Ta : float
air temperature ($^\circ$\,C)
Returns
-------
visa : float
kinematic viscosity (m^2/s)
"""
"""
Ta
=
np
.
asarray
(
Ta
)
Ta
=
np
.
asarray
(
Ta
)
if
(
np
.
nanmin
(
Ta
)
>
200
):
# if Ta in Kelvin convert to Celsius
if
(
np
.
nanmin
(
Ta
)
>
200
):
# if Ta in Kelvin convert to Celsius
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment