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
thopri
BoBEAS
Commits
529f0301
Commit
529f0301
authored
5 years ago
by
jelt
Browse files
Options
Download
Email Patches
Plain Diff
Add bathy processing files
parent
492680b9
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
389 additions
and
0 deletions
+389
-0
SCRIPTS/Generate_NEMO_Forcing.py
SCRIPTS/Generate_NEMO_Forcing.py
+327
-0
SCRIPTS/bathymetry_fill.m
SCRIPTS/bathymetry_fill.m
+30
-0
SCRIPTS/python_mask.py
SCRIPTS/python_mask.py
+32
-0
No files found.
SCRIPTS/Generate_NEMO_Forcing.py
0 → 100755
View file @
529f0301
#
#====================== DOCSTRING ============================
"""
Generate ERA5 atmospheric forcing for NEMO
So far to prduce a year by a year - need to be automated
--------------------------------------------------------------
"""
__author__
=
"Nicolas Bruneau"
__copyright__
=
"Copyright 2018, NOC"
__email__
=
"nibrun@noc.ac.uk"
__date__
=
"2018-05"
#====================== USR PARAMS ===========================
Year_init
=
2016
## First year to process
Year_end
=
2017
## Last one [included]
East
=
110
## East Border
West
=
60
## West Border
North
=
30
## North Border
South
=
0
## South Border
path_ERA5
=
'/projectsa/NEMO/Forcing/ERA5/'
## ROOT PATH OD ERA5 DATA
path_EXTRACT
=
'./EXTRACTION_AMM7/'
## WHERE TO EXTRACT YOUR REGION
path_FORCING
=
'./FORCING/'
## NEMO FORCING
clean
=
False
## Clean extraction (longest bit)
sph_ON
=
True
## Compute specific humidity or not
#================== NEMO DOCUMENTATION =======================
"""
See the manual in section SBC for more details on the way data
are used in NEMO
The time variable from the netcdf is not used
"""
#====================== LOAD MODULES =========================
import
os
,
sys
,
glob
import
subprocess
import
numpy
as
np
import
datetime
from
netCDF4
import
Dataset
,
MFDataset
import
netcdftime
import
matplotlib.pyplot
as
plt
from
matplotlib.mlab
import
griddata
import
scipy.spatial.qhull
as
qhull
#====================== VARIABLE DEF =========================
var_path
=
{
't2m'
:
'INST'
,
\
'msl'
:
'INST'
,
\
'u10'
:
'INST'
,
\
'v10'
:
'INST'
,
\
'strd'
:
"CUMUL"
,
\
'ssrd'
:
"CUMUL"
,
\
'sf'
:
"CUMUL"
,
\
'tp'
:
"CUMUL"
,
\
}
#var_path = { 'msl' : 'INST', \
# 'u10' : 'INST', \
# 'strd' : "CUMUL", \
# 'ssrd' : "CUMUL", \
# 'sf' : "CUMUL", \
# }
#var_path = { 't2m' : 'INST', \
# 'v10' : 'INST', \
# 'tp' : "CUMUL", \
# }
if
sph_ON
:
var_path
[
'sp'
]
=
'INST'
var_path
[
'd2m'
]
=
'INST'
#===================== INTERNAL FCTNS ========================
help_tosec
=
np
.
vectorize
(
lambda
x
:
x
.
total_seconds
()
)
def
Read_NetCDF
(
fname
,
KeyVar
)
:
'Read NetCDF file'
if
"*"
in
fname
:
nc
=
MFDataset
(
fname
,
'r'
)
else
:
nc
=
Dataset
(
fname
,
'r'
)
## Get time using the time variable
Time_Var
=
nc
.
variables
[
'time'
]
dt
=
Time_Var
[:][
1
]
-
Time_Var
[:][
0
]
Time_H
=
np
.
arange
(
Time_Var
[:][
0
],
Time_Var
[:][
0
]
+
dt
*
Time_Var
[:].
size
,
dt
)
try
:
Tref
=
netcdftime
.
utime
(
Time_Var
.
units
,
calendar
=
Time_Var
.
calendar
)
except
:
Tref
=
netcdftime
.
utime
(
Time_Var
.
units
,
calendar
=
"gregorian"
)
Time
=
Tref
.
num2date
(
Time_H
)
print
"====================++++"
## Get Coordinates
try
:
Lon
=
nc
.
variables
[
'longitude'
][:]
Lat
=
nc
.
variables
[
'latitude'
][:]
LON
,
LAT
=
np
.
meshgrid
(
Lon
,
Lat
)
except
:
LON
=
nc
.
variables
[
'lon'
][:]
LAT
=
nc
.
variables
[
'lat'
][:]
## Get Variable
dum
=
nc
.
variables
[
KeyVar
]
Var
=
dum
[:]
ind
=
(
Var
==
dum
.
_FillValue
)
Var
[
ind
]
=
np
.
nan
#Var = Var / dum.scale_factor + dum.add_offset
ind
=
(
np
.
isnan
(
Var
))
Var
[
ind
]
=
-
9999999
print
Time
[
0
],
Time
[
-
1
],
Var
.
shape
,
Time
.
shape
,
np
.
sum
(
ind
)
try
:
return
Time
,
LON
,
LAT
,
Var
,
dum
.
units
,
dum
.
long_name
except
:
return
Time
,
LON
,
LAT
,
Var
,
dum
.
units
,
dum
.
standard_name
#=================== MANIPULATE NetCDF =======================
def
compute_scale_and_offset
(
Var
,
n
):
'http://james.hiebert.name/blog/work/2015/04/18/NetCDF-Scale-Factors/'
Vmin
=
np
.
nanmin
(
Var
)
Vmax
=
np
.
nanmax
(
Var
)
print
"scaleoffset"
,
Vmin
,
Vmax
# stretch/compress data to the available packed range
scale_factor
=
(
Vmax
-
Vmin
)
/
(
2
**
n
-
1
)
# translate the range to be symmetric about zero
add_offset
=
Vmin
+
2
**
(
n
-
1
)
*
scale_factor
return
scale_factor
,
add_offset
def
Add_Variable
(
nc
,
vName
,
vDim
,
vVal
,
long_name
=
None
,
units
=
None
,
standard_name
=
None
,
fill_value
=
None
)
:
"Add a variable with its attributes in a netcdf file"
if
vName
not
in
[
'time'
,
'lon'
,
'lat'
,]
:
fprec
=
'i'
else
:
fprec
=
'f8'
if
fill_value
!=
None
:
nc
.
createVariable
(
vName
,
fprec
,
vDim
,
fill_value
=
fill_value
,
zlib
=
True
,
complevel
=
5
)
else
:
nc
.
createVariable
(
vName
,
fprec
,
vDim
,
zlib
=
True
,
complevel
=
5
)
if
long_name
!=
None
:
nc
.
variables
[
vName
].
long_name
=
long_name
if
units
!=
None
:
nc
.
variables
[
vName
].
units
=
units
if
standard_name
!=
None
:
nc
.
variables
[
vName
].
standard_name
=
standard_name
if
vName
not
in
[
'time'
,
'lon'
,
'lat'
,]
:
sc
,
off
=
compute_scale_and_offset
(
vVal
,
16
)
nc
.
variables
[
vName
].
scale_factor
=
sc
nc
.
variables
[
vName
].
add_offset
=
off
nc
.
variables
[
vName
][:]
=
vVal
# np.floor((vVal-off)/sc)
def
Create_Dimensions
(
nc
,
lon_name
,
nLon
,
lat_name
,
nLat
)
:
"Create NetCDF dimensions time, nx, ny"
nc
.
createDimension
(
lon_name
,
nLon
)
nc
.
createDimension
(
lat_name
,
nLat
)
nc
.
createDimension
(
'time'
,
None
)
def
Create_NetCDF_core
(
nc
,
tDim
,
tRef
,
tVal
,
sDim
,
sVal_lon
,
sVal_lat
)
:
"Create Lon, Lat and Time variables"
# WRITE TIME INFO
tUnit
=
"days since {0} UTC"
.
format
(
tRef
.
strftime
(
"%Y-%m-%d %H:%M:%S"
)
);
tCal
=
"standard"
Tref
=
netcdftime
.
utime
(
tUnit
,
calendar
=
tCal
)
Add_Variable
(
nc
,
'time'
,
(
'time'
),
Tref
.
date2num
(
tVal
),
\
long_name
=
"time since {0}"
.
format
(
tUnit
)
,
\
units
=
tUnit
)
nc
.
variables
[
'time'
].
calendar
=
tCal
#nc.variables['time'].base_date = np.array( [ tRef.year, tRef.month, tRef.day, tRef.hour ] )
# WRITE LON INFO
Add_Variable
(
nc
,
'lon'
,
sDim
,
sVal_lon
,
long_name
=
'Longitude'
,
\
units
=
'degree_east'
,
standard_name
=
'longitude'
)
# WRITE L INFOT
Add_Variable
(
nc
,
'lat'
,
sDim
,
sVal_lat
,
long_name
=
'Latitude'
,
\
units
=
'degree_north'
,
standard_name
=
'latitude'
)
def
Create_Attributes
(
nc
)
:
"Add some info - I do it at the end as I had issue with not properly readable netcdf if not"
nc
.
Description
=
'ERA5 Atmospheric conditions for AMM15 NEMO3.6'
nc
.
Author
=
'Prepare_ERA5.py'
nc
.
Created
=
datetime
.
datetime
.
now
().
strftime
(
"%Y-%m-%d %H:%M:%S"
)
nc
.
Conventions
=
"CF-1.0"
nc
.
close
()
#======================= EXTRACTION ==========================
def
Extract
(
fin
,
fout
,
clean
=
True
)
:
if
clean
:
os
.
system
(
"rm {0}"
.
format
(
fout
)
)
if
not
os
.
path
.
exists
(
fout
)
:
command
=
"ncks -d latitude,{0},{1} -d longitude,{2},{3} {4} {5}"
.
format
(
np
.
float
(
South
),
np
.
float
(
North
),
\
np
.
float
(
West
),
np
.
float
(
East
),
fin
,
fout
)
print
command
os
.
system
(
command
)
def
datetime_range
(
start
,
end
,
delta
):
current
=
[
start
,
]
while
current
[
-
1
]
<
end
:
current
.
append
(
current
[
-
1
]
+
delta
)
return
np
.
array
(
current
)
#======================= CORE PROGR ==========================
## load NCO
os
.
system
(
"module load nco/gcc/4.4.2.ncwa"
)
os
.
system
(
"mkdir {0} {1}"
.
format
(
path_EXTRACT
,
path_FORCING
)
)
if
West
<
0
:
West
=
360.
+
West
if
East
<
0
:
East
=
360.
+
East
## Loop over each variable
for
iVar
,
pVar
in
var_path
.
iteritems
()
:
print
"================== {0} - {1} =================="
.
format
(
iVar
,
pVar
)
##---------- EXTRACT ALL DATA FOR DOMAIN ----------------
for
iY
in
range
(
Year_init
,
Year_end
+
1
)
:
## Files
finput
=
"{0}/{1}/{2}/{2}_{3}.nc"
.
format
(
path_ERA5
,
pVar
,
iVar
,
iY
)
foutput
=
"./{2}/{0}_{1}.nc"
.
format
(
iVar
,
iY
,
path_EXTRACT
)
## Extract the subdomain
Extract
(
finput
,
foutput
,
clean
=
clean
)
##---------- LOAD FULLL TIME SERIES IN MEMORY -----------
Time
,
Lon
,
Lat
,
dum
,
Units
,
Name
=
Read_NetCDF
(
"./{1}/{0}_*.nc"
.
format
(
iVar
,
path_EXTRACT
),
iVar
)
dt
=
Time
[
1
]
-
Time
[
0
]
## assume to be constant in time
dt2
=
datetime
.
timedelta
(
seconds
=
dt
.
total_seconds
()
/
2.
)
##---------- SOME PREPROCESSING -------------------------
if
pVar
==
'INST'
:
## Add time step for last hour - copy the last input
dumA
=
np
.
concatenate
(
[
dum
,
dum
[
-
1
][
np
.
newaxis
,...]
],
axis
=
0
)
TimeA
=
np
.
array
(
Time
.
tolist
()
+
[
Time
[
-
1
],]
)
## instantaneous field every hour. we center it in mid-time step (00:30) as it
## is what NEMO assumes according to documentation
dumC
=
(
dumA
[
0
:
-
1
]
+
dumA
[
1
::]
)
/
2.0
TimeC
=
TimeA
[
0
:
-
1
]
+
dt2
## shift half time step positively due to averaging
suffix
=
''
elif
pVar
==
'CUMUL'
:
## Add time step for first 6h - copy the first input
nshift
=
6
dumA
=
np
.
repeat
(
dum
[
None
,
0
,...],
nshift
,
axis
=
0
)
dumA
=
np
.
concatenate
(
[
dumA
,
dum
],
axis
=
0
)
TimeA
=
np
.
array
(
[
Time
[
0
]
-
dt
*
(
nshift
-
i
)
for
i
in
range
(
nshift
)
]
)
TimeA
=
np
.
concatenate
(
[
TimeA
,
Time
],
axis
=
0
)
## Cumulated field comes from forecast and are therefore shifter in time
## we need to account for it properly for the beginning of the time series.
## first value is reapeated
dumC
=
dumA
/
dt
.
total_seconds
()
## convert as a rate
TimeC
=
TimeA
-
dt2
## shift half time step negatively as cumulated period
suffix
=
'/s'
if
iVar
in
[
'sf'
,
'tp'
,
]:
print
"convert m to mm for"
,
iVar
dumC
*=
1000.
Units
=
'mm'
if
iVar
in
[
'ssrd'
,
'strd'
,
]:
dumC
[(
dumC
<
0.
)]
=
0.
print
"negative values set to 0"
,
iVar
else
:
print
"Values in var_path variables are expected to be CUMUL or INST"
print
" given {0} for {1}"
.
format
(
pVar
,
iVar
)
sys
.
exit
()
##---------- OUTPUT A FILE PER YEAR ---------------------
for
iY
in
range
(
Year_init
,
Year_end
+
1
)
:
indT
=
(
TimeC
>=
datetime
.
datetime
(
iY
,
1
,
1
)
)
\
*
(
TimeC
<
datetime
.
datetime
(
iY
+
1
,
1
,
1
)
)
if
iVar
in
[
"d2m"
,
"sp"
]
:
Fout
=
"./{2}/forSPH_ERA5_{0}_y{1}.nc"
.
format
(
iVar
.
upper
(),
iY
,
path_FORCING
)
else
:
Fout
=
"./{2}/ERA5_{0}_y{1}.nc"
.
format
(
iVar
.
upper
(),
iY
,
path_FORCING
)
nc
=
Dataset
(
Fout
,
'w'
,
format
=
'NETCDF4_CLASSIC'
)
Create_Dimensions
(
nc
,
'nLon'
,
Lon
.
shape
[
1
],
'nLat'
,
Lat
.
shape
[
0
]
)
Create_NetCDF_core
(
nc
,
(
'time'
),
TimeC
[
indT
][
0
],
TimeC
[
indT
],
(
'nLat'
,
'nLon'
),
Lon
[::
-
1
,:],
Lat
[::
-
1
,:]
)
Add_Variable
(
nc
,
iVar
.
upper
(),
(
'time'
,
'nLat'
,
'nLon'
),
dumC
[
indT
,::
-
1
,:],
units
=
Units
+
suffix
,
standard_name
=
Name
,
fill_value
=-
999999
)
Create_Attributes
(
nc
)
##---------- PROCESS SPECIFIC HUMIDITY ----------------------
## Compute Specific Humidity according to ECMWF documentation
if
sph_ON
:
for
iY
in
range
(
Year_init
,
Year_end
+
1
)
:
Time
,
Lon
,
Lat
,
d2m
,
dUnits
,
dName
=
Read_NetCDF
(
"./{1}/forSPH_ERA5_D2M_y{0}.nc"
.
format
(
iY
,
path_FORCING
),
'D2M'
)
Time
,
Lon
,
Lat
,
sp
,
dUnits
,
dName
=
Read_NetCDF
(
"./{1}/forSPH_ERA5_SP_y{0}.nc"
.
format
(
iY
,
path_FORCING
),
'SP'
)
esat
=
611.21
*
np
.
exp
(
17.502
*
(
d2m
-
273.16
)
/
(
d2m
-
32.19
)
)
dyrvap
=
287.0597
/
461.5250
dVar
=
dyrvap
*
esat
/
(
sp
-
(
1
-
dyrvap
)
*
esat
)
Units
=
"1"
;
Name
=
"Specific Humidity"
indT
=
(
Time
>=
datetime
.
datetime
(
iY
,
1
,
1
)
)
\
*
(
Time
<
datetime
.
datetime
(
iY
+
1
,
1
,
1
)
)
Fout
=
"./{1}/ERA5_SPH_y{0}.nc"
.
format
(
iY
,
path_FORCING
)
nc
=
Dataset
(
Fout
,
'w'
,
format
=
'NETCDF4_CLASSIC'
)
Create_Dimensions
(
nc
,
'nLon'
,
Lon
.
shape
[
1
],
'nLat'
,
Lat
.
shape
[
0
]
)
Create_NetCDF_core
(
nc
,
(
'time'
),
Time
[
indT
][
0
],
Time
[
indT
],
(
'nLat'
,
'nLon'
),
Lon
[:,:],
Lat
[:,:]
)
Add_Variable
(
nc
,
"SPH"
,
(
'time'
,
'nLat'
,
'nLon'
),
dVar
[
indT
,:,:],
units
=
Units
,
standard_name
=
Name
,
fill_value
=-
999999
)
Create_Attributes
(
nc
)
##---------- WRITE NAMELIST ---------------------------------
print
"
\n
EXAMPLE of core namelist with ERA5 for NEMO"
print
" the interpolation weights need to be generated using the usual method"
print
" using: scripgrid.exe, scrip.exe, scripshape.exe from TOOLS/WEIGHTS/
\n
"
print
" &namsbc_core"
print
" cn_dir='./fluxes_ERA5/',"
print
" ln_taudif=.false.,"
print
" rn_pfac = 1.0,"
print
" rn_vfac = 1.,"
print
" rn_zqt = 2.,"
print
" rn_zu = 10.,"
print
" sn_humi='ERA5_SPH' ,1,'SPH' ,.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','',"
print
" sn_prec='ERA5_TP' ,1,'TP' ,.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','',"
print
" sn_qlw ='ERA5_STRD',1,'STRD',.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','',"
print
" sn_qsr ='ERA5_SSRD',1,'SSRD',.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','',"
print
" sn_snow='ERA5_SF' ,1,'SF' ,.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','',"
print
" sn_tair='ERA5_T2M' ,1,'T2M' ,.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','',"
print
" sn_wndi='ERA5_U10' ,1,'U10' ,.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','U1',"
print
" sn_wndj='ERA5_V10' ,1,'V10' ,.true.,.false.,'yearly','weights_era5_amm15_bicubic.nc','V1',"
print
" /
\n
"
sys
.
exit
()
This diff is collapsed.
Click to expand it.
SCRIPTS/bathymetry_fill.m
0 → 100755
View file @
529f0301
clear
all
clc
fname
=
'bathy_meter.nc'
;
B
=
ncread
(
fname
,
'Bathymetry'
);
x
=
ncread
(
fname
,
'nav_lon'
);
y
=
ncread
(
fname
,
'nav_lat'
);
B
(
isnan
(
B
))
=
0
;
% make landsea mask
A
=-
B
;
A
(
A
==
0
)
=
1
;
A
(
A
<
0
)
=
0
;
% put land border on east coast
A
(
end
,:)
=
1
;
% fill closed spaces
A1
=
imfill
(
A
,
'holes'
);
B
(
A1
==
1
)
=
nan
;
% update bathymetry
ncid
=
netcdf
.
open
(
fname
,
'WRITE'
);
varid
=
netcdf
.
inqVarID
(
ncid
,
'Bathymetry'
);
netcdf
.
putVar
(
ncid
,
varid
,
B
)
This diff is collapsed.
Click to expand it.
SCRIPTS/python_mask.py
0 → 100755
View file @
529f0301
from
netCDF4
import
Dataset
import
numpy
as
np
coorfile
=
'./FORCING/ERA5_MSL_y2016.nc'
## One ERA forcing file generated previously
maskfile
=
'my_era5_LSM.nc'
## Land Sea Mask from ncks
outfile
=
'ERA5_LSM.nc'
## Output file
#----------------------------------------------------------------------------
## READ SRC BATHYMETRY
nc_c
=
Dataset
(
coorfile
,
'r'
)
lon_src
=
nc_c
.
variables
[
'lon'
][:]
lat_src
=
nc_c
.
variables
[
'lat'
][:]
nc_c
.
close
()
print
coorfile
,
"loaded"
,
lon_src
.
shape
## READ SRC BATHYMETRY
nc_src
=
Dataset
(
maskfile
,
'r'
)
msk_src
=
nc_src
.
variables
[
'lsm'
][
0
,::
-
1
]
print
maskfile
,
"loaded"
,
msk_src
.
shape
msk_src
[(
msk_src
==
0.
)]
=
-
1
## NETCDF OUTPUT
ncout
=
Dataset
(
outfile
,
'w'
,
format
=
'NETCDF3_CLASSIC'
)
ncout
.
createDimension
(
'nlat'
,
msk_src
.
shape
[
0
]
)
ncout
.
createDimension
(
'nlon'
,
msk_src
.
shape
[
1
]
)
lon
=
ncout
.
createVariable
(
'lon'
,
'f4'
,
(
'nlat'
,
'nlon'
,),
zlib
=
'True'
)
lat
=
ncout
.
createVariable
(
'lat'
,
'f4'
,
(
'nlat'
,
'nlon'
,),
zlib
=
'True'
)
lon
[:]
=
lon_src
;
lat
[:]
=
lat_src
bout
=
ncout
.
createVariable
(
"LSM"
,
'f4'
,
(
'nlat'
,
'nlon'
,),
zlib
=
'True'
,
fill_value
=-
999.
)
bout
[:]
=
msk_src
ncout
.
close
()
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