Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plot marine DA stuff #286

Merged
merged 11 commits into from
Jan 30, 2023
3 changes: 1 addition & 2 deletions scripts/exgdas_global_marine_analysis_prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,8 @@ def gen_bkg_list(bkg_path, out_path, window_begin=' ', file_type='gdas.t*.ocnf00
ufsda.mkdir(bkg_dir)

# create output directory for soca DA
anl_out = os.path.join(comout, 'ocnanal_' + os.getenv('cyc'), 'Data')
anl_out = os.path.join(anl_dir, 'Data')
ufsda.mkdir(anl_out)
ufsda.symlink(anl_out, os.path.join(anl_dir, 'Data'), remove=False)

################################################################################
# fetch observations
Expand Down
2 changes: 1 addition & 1 deletion scripts/exgdas_global_marine_analysis_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export err=$?; err_chk
# Note: ${DATA}/INPUT/MOM.res.nc points to the MOM6 history file from the start of the window
# and is used to get the valid vertical geometry of the increment
socaincr=$(ls -t ${DATA}/Data/ocn.*3dvar*.incr* | head -1)
mom6incr=${COMOUT}/inc.nc
mom6incr=${DATA}/inc.nc
( socaincr2mom6 ${socaincr} ${DATA}/INPUT/MOM.res.nc ${DATA}/soca_gridspec.nc ${mom6incr} )


Expand Down
191 changes: 191 additions & 0 deletions scripts/exgdas_global_marine_analysis_vrfy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#!/usr/bin/env python3
################################################################################
# UNIX Script Documentation Block
# . .
# Script name: exufsda_global_marine_analysis_vrfy.py
# Script description: State and observation space verification for the
# UFS Global Marine Analysis
#
# Author: Guillaume Vernieres Org: NCEP/EMC Date: 2023-01-23
#
# Abstract: This script produces figures relevant to the marine DA cycle
#
# $Id$
#
# Attributes:
# Language: Python3
#
################################################################################

import os
import numpy as np
import matplotlib.pyplot as plt
import xarray as xr
import cartopy
import cartopy.crs as ccrs


def plot_config(grid_file=[], data_file=[],
variable=[], levels=[], bounds=[], colormap=[], comout=[], lats=[]):
"""
Prepares the configuration for the plotting functions below
"""
config = {}
config['grid file'] = grid_file
config['fields file'] = data_file
config['variable'] = variable
config['levels'] = levels
config['bounds'] = bounds
config['colormap'] = colormap
config['lats'] = lats
config['comout'] = comout
config['max depth'] = 5000.0
return config


def plot_horizontal_slice(config):
"""
pcolormesh of a horizontal slice of an ocean field
"""
level = config['levels'][0]
grid = xr.open_dataset(config['grid file'])
data = xr.open_dataset(config['fields file'])
if config['variable'] in ['Temp', 'Salt', 'u', 'v']:
slice_data = np.squeeze(data[config['variable']])[level, :, :]
else:
slice_data = np.squeeze(data[config['variable']])
bounds = config['bounds']
fig, ax = plt.subplots(figsize=(8, 5), subplot_kw={'projection': ccrs.PlateCarree()})
plt.pcolormesh(np.squeeze(grid.lon),
np.squeeze(grid.lat),
slice_data,
vmin=bounds[0], vmax=bounds[1],
transform=ccrs.PlateCarree(),
cmap=config['colormap'])
plt.colorbar(label=config['variable']+' Level '+str(level), shrink=0.5, orientation='horizontal')
# ax.coastlines() # TODO: make this work on hpc
ax.gridlines(draw_labels=True)
# ax.add_feature(cartopy.feature.LAND) # TODO: make this work on hpc
dirname = os.path.join(config['comout'], config['variable'])
os.makedirs(dirname, exist_ok=True)
figname = os.path.join(dirname, config['variable']+'_Level_'+str(level))
plt.savefig(figname, bbox_inches='tight')


def plot_zonal_slice(config):
"""
pcolormesh of a zonal slice of an ocean field
"""
lat = float(config['lats'][0])
grid = xr.open_dataset(config['grid file'])
data = xr.open_dataset(config['fields file'])
lat_index = np.argmin(np.array(np.abs(np.squeeze(grid.lat)[:, 0]-lat)))
slice_data = np.squeeze(np.array(data[config['variable']].sel(yaxis_1=lat_index)))
depth = np.squeeze(np.array(grid['h'].sel(yaxis_1=lat_index)))
depth[np.where(np.abs(depth) > 10000.0)] = 0.0
depth = np.cumsum(depth, axis=0)
bounds = config['bounds']
x = np.tile(np.squeeze(grid.lon[:, lat_index]), (np.shape(depth)[0], 1))
fig, ax = plt.subplots(figsize=(8, 5))
plt.pcolormesh(x, -depth, slice_data,
vmin=bounds[0], vmax=bounds[1],
cmap=config['colormap'])
plt.colorbar(label=config['variable']+' Lat '+str(lat), shrink=0.5, orientation='horizontal')
ax.set_ylim(-config['max depth'], 0)
dirname = os.path.join(config['comout'], config['variable'])
os.makedirs(dirname, exist_ok=True)
figname = os.path.join(dirname, config['variable'] +
'zonal_lat_'+str(int(lat)) + '_' + str(int(config['max depth'])) + 'm')
plt.savefig(figname, bbox_inches='tight')


comout = os.getenv('COMOUT')
cyc = os.getenv('cyc')
bcyc = str((int(cyc) - 3) % 24)

# TODO: do not write to COM, instead dump figures in DATA and copy to COM.
grid_file = os.path.join(comout, 'gdas.t'+bcyc+'z.ocngrid.nc')

#######################################
# INCREMENT
#######################################
incr_cmap = 'RdBu'
data_file = os.path.join(comout, 'gdas.t'+cyc+'z.ocninc.nc')
config = plot_config(grid_file=grid_file,
data_file=data_file,
colormap=incr_cmap,
comout=os.path.join(comout, 'vrfy', 'incr'))

#######################################
# zonal slices

for lat in np.arange(-60, 60, 10):

for max_depth in [700.0, 5000.0]:
config['lats'] = [lat]
config['max depth'] = max_depth

# Temperature
config.update({'variable': 'Temp', 'levels': [1], 'bounds': [-.5, .5]})
plot_zonal_slice(config)

# Salinity
config.update({'variable': 'Salt', 'levels': [1], 'bounds': [-.1, .1]})
plot_zonal_slice(config)

#######################################
# Horizontal slices

# Temperature
config.update({'variable': 'Temp', 'levels': [1], 'bounds': [-1, 1]})
plot_horizontal_slice(config)

# Salinity
config.update({'variable': 'Salt', 'bounds': [-0.1, 0.1]})
plot_horizontal_slice(config)

# Sea surface height
config.update({'variable': 'ave_ssh', 'bounds': [-0.1, 0.1]})
plot_horizontal_slice(config)

#######################################
# Std Bkg. Error
#######################################
bmat_cmap = 'jet'
data_file = os.path.join(comout, 'gdas.t'+cyc+'z.ocn.bkgerr_stddev.nc')
config = plot_config(grid_file=grid_file,
data_file=data_file,
colormap=bmat_cmap,
comout=os.path.join(comout, 'vrfy', 'bkgerr'))

#######################################
# zonal slices

for lat in np.arange(-60, 60, 10):

for max_depth in [700.0, 5000.0]:
config['lats'] = [lat]
config['max depth'] = max_depth

# Temperature
config.update({'variable': 'Temp', 'levels': [1], 'bounds': [0, 1.5]})
plot_zonal_slice(config)

# Salinity
config.update({'variable': 'Salt', 'levels': [1], 'bounds': [0, .2]})
plot_zonal_slice(config)

#######################################
# Horizontal slices

# Temperature
config.update({'variable': 'Temp', 'levels': [1], 'bounds': [0, 2]})
plot_horizontal_slice(config)

# Salinity
config.update({'variable': 'Salt', 'bounds': [0, 0.2]})
plot_horizontal_slice(config)

# Sea surface height
config.update({'variable': 'ave_ssh', 'bounds': [0, 0.1]})
plot_horizontal_slice(config)
3 changes: 2 additions & 1 deletion test/soca/gw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ add_test(NAME test_gdasapp_soca_run_clean
set(jjob_list "JGDAS_GLOBAL_OCEAN_ANALYSIS_PREP"
"JGDAS_GLOBAL_OCEAN_ANALYSIS_BMAT"
"JGDAS_GLOBAL_OCEAN_ANALYSIS_RUN"
"JGDAS_GLOBAL_OCEAN_ANALYSIS_POST")
"JGDAS_GLOBAL_OCEAN_ANALYSIS_POST"
"JGDAS_GLOBAL_OCEAN_ANALYSIS_VRFY")

set(setup "")
foreach(jjob ${jjob_list})
Expand Down
2 changes: 1 addition & 1 deletion test/soca/test_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ test_file ${DATA}/Data/ocn.iter1.incr.2018-04-15T09:00:00Z.nc
test_file ${DATA}/Data/ocn.3dvarfgat_pseudo.an.2018-04-15T09:00:00Z.nc
test_file ${DATA}/Data/ocn.3dvarfgat_pseudo.an.2018-04-15T12:00:00Z.nc
test_file ${DATA}/Data/ocn.3dvarfgat_pseudo.an.2018-04-15T15:00:00Z.nc
test_file ${COMOUT}/inc.nc
test_file ${COMOUT}/ocnanal_12/inc.nc
11 changes: 8 additions & 3 deletions ush/soca/run_jjobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@


machines = {"container", "hera", "orion"}
MODS = {'JGDAS_GLOBAL_OCEAN_ANALYSIS_PREP': 'GDAS',
'JGDAS_GLOBAL_OCEAN_ANALYSIS_BMAT': 'GDAS',
'JGDAS_GLOBAL_OCEAN_ANALYSIS_RUN': 'GDAS',
'JGDAS_GLOBAL_OCEAN_ANALYSIS_POST': 'GDAS',
'JGDAS_GLOBAL_OCEAN_ANALYSIS_VRFY': 'EVA'}


class JobCard:
Expand Down Expand Up @@ -112,14 +117,14 @@ def close(self):
self.f.close()
subprocess.run(["chmod", "+x", self.name])

def modules(self):
def _modules(self, jjob):
"""
Write a section that will load the machine dependent modules
"""
if self.machine != "container":
self.f.write("module purge \n")
self.f.write("module use ${HOMEgfs}/sorc/gdas.cd/modulefiles \n")
self.f.write(f"module load GDAS/{self.machine} \n")
self.f.write(f"module load {MODS[jjob]}/{self.machine} \n")

def copy_bkgs(self):
"""
Expand Down Expand Up @@ -161,6 +166,7 @@ def jjobs(self):
"""
runjobs = "# Run jjobs\n"
for job in self.config['jjobs']:
self._modules(job) # Add module's jjob
thejob = "${HOMEgfs}/jobs/"+job
runjobs += f"{thejob} &>{job}.out\n"
self.f.write(runjobs)
Expand Down Expand Up @@ -208,7 +214,6 @@ def main():
run_card.fixconfigs() # over-write some of the config variables
run_card.header() # prepare a machine dependent header (SLURM or nothing)
run_card.export_env_vars_script()
run_card.modules()
run_card.copy_bkgs()
run_card.jjobs()
run_card.close()
Expand Down