
Gulf Stream: Benchmark DUACS sea surface height maps
2023-04-27 DUACS_SSH_BENCHMARK_DEMO
Authors: CLS & Datlas Copyright: 2023 CLS & Datlas License: MIT
Gulf Stream: Benchmark of DUACS sea surface height maps
Gulf Stream: Benchmark of DUACS sea surface height maps
The notebook aims to evaluate the sea surface height maps produced by the DUACS system.
<h5> These maps are equivalent to the SEALEVEL_GLO_PHY_L4_MY_008_047 product distributed by the Copernicus Marine Service, except that a nadir altimeter (SARAL/Altika, SEALEVEL_GLO_PHY_L3_MY_008_062 product) has been excluded from the mapping. </h5>
<h5> We provide below a demonstration of the validation of these maps against the independent SSH data from the Saral/AltiKa altimeter distributed by CMEMS </h5>
General Note 1: Execute each cell through the button from the top MENU (or keyboard shortcut Shift + Enter). General Note 2: If, for any reason, the kernel is not working anymore, in the top MENU, click on the button. Then, in the top MENU, click on “Cell” and select “Run All Above Selected Cell”. ***
Learning outcomes
At the end of this notebook you will know:
How you can evaluated sea surface height maps with independent alongtrack data: statistical and spectral analysis
[1]:
from glob import glob
import numpy as np
import os
[2]:
import sys
sys.path.append('..')
from src.mod_plot import *
from src.mod_stat import *
from src.mod_spectral import *
[3]:
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
Parameters
Parameters
[4]:
time_min = '2019-01-01' # time min for analysis
time_max = '2019-12-31' # time max for analysis
output_dir = '../results' # output directory path
os.system(f'mkdir -p {output_dir}')
# Gulf Stream region
region = 'GS'
lon_min = 295 # domain min longitude
lon_max = 305 # domain max longitude
lat_min = 33. # domain min latitude
lat_max = 43. # domain max latitude
box_lonlat_GS = {'lon_min':lon_min,'lon_max':lon_max,'lat_min':lat_min,'lat_max':lat_max}
method_name = 'DUACS'
stat_output_filename = f'{output_dir}/stat_sla_duacs_geos_GS.nc' # output statistical analysis filename
lambda_min = 65. # minimun spatial scale in kilometer to consider on the filtered signal
lambda_max = 500. # maximum spatial scale in kilometer to consider on the filtered signal
psd_output_filename = f'{output_dir}/psd_sla_duacs_geos_GS.nc' # output spectral analysis filename
segment_lenght = 1000. # spectral parameer: along-track segment lenght in kilometer to consider in the spectral analysis
Input files
Input files
Sea Surface Height from Saral/AltiKa
[5]:
%%time
list_of_file = sorted(glob('../data/independent_alongtrack/indep_nadir_GS.nc'))
ds_alg = xr.open_mfdataset(list_of_file, combine='nested', concat_dim='time')
ds_alg = ds_alg.where((ds_alg.time >= np.datetime64(time_min)) & (ds_alg.time <= np.datetime64(time_max)), drop=True)
ds_alg = ds_alg.sortby('time')
ds_alg
CPU times: user 68.3 ms, sys: 12.9 ms, total: 81.2 ms
Wall time: 85.5 ms
[5]:
<xarray.Dataset>
Dimensions: (time: 37177)
Coordinates:
* time (time) datetime64[ns] 2019-01-01T22:10:01.073445888 ... 2...
longitude (time) float64 dask.array<chunksize=(37177,), meta=np.ndarray>
latitude (time) float64 dask.array<chunksize=(37177,), meta=np.ndarray>
Data variables:
cycle (time) float64 dask.array<chunksize=(37177,), meta=np.ndarray>
track (time) float64 dask.array<chunksize=(37177,), meta=np.ndarray>
sla_unfiltered (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
sla_filtered (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
dac (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
ocean_tide (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
internal_tide (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
lwe (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
mdt (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
tpa_correction (time) float32 dask.array<chunksize=(37177,), meta=np.ndarray>
Attributes: (12/44)
Conventions: CF-1.6
Metadata_Conventions: Unidata Dataset Discovery v1.0
cdm_data_type: Swath
comment: Sea surface height measured by altimeter...
contact: servicedesk.cmems@mercator-ocean.eu
creator_email: servicedesk.cmems@mercator-ocean.eu
... ...
summary: SSALTO/DUACS Delayed-Time Level-3 sea su...
time_coverage_duration: P24H11M29.716548S
time_coverage_end: 2019-01-01T23:36:52Z
time_coverage_resolution: P1S
time_coverage_start: 2018-12-31T23:25:22Z
title: DT Altika Drifting Phase Global Ocean Al...Sea Surface Height maps to evaluate
[6]:
%%time
list_of_maps = sorted(glob('../data/maps/DUACS_GS.nc'))
ds_maps = xr.open_mfdataset(list_of_maps, combine='nested', concat_dim='time')
ds_maps = ds_maps.sel(time=slice(time_min, time_max))
ds_maps
CPU times: user 39.1 ms, sys: 6.14 ms, total: 45.3 ms
Wall time: 69.9 ms
[6]:
<xarray.Dataset>
Dimensions: (latitude: 44, longitude: 44, time: 365)
Coordinates:
* latitude (latitude) float32 32.62 32.88 33.12 33.38 ... 42.88 43.12 43.38
* longitude (longitude) float64 294.6 294.9 295.1 295.4 ... 304.9 305.1 305.4
* time (time) datetime64[ns] 2019-01-01 2019-01-02 ... 2019-12-31
Data variables:
sla (time, latitude, longitude) float64 dask.array<chunksize=(365, 44, 44), meta=np.ndarray>
ugosa (time, latitude, longitude) float64 dask.array<chunksize=(365, 44, 44), meta=np.ndarray>
vgosa (time, latitude, longitude) float64 dask.array<chunksize=(365, 44, 44), meta=np.ndarray>
adt (time, latitude, longitude) float64 dask.array<chunksize=(365, 44, 44), meta=np.ndarray>
ugos (time, latitude, longitude) float64 dask.array<chunksize=(365, 44, 44), meta=np.ndarray>
vgos (time, latitude, longitude) float64 dask.array<chunksize=(365, 44, 44), meta=np.ndarray>
Statistical & Spectral Analysis
Statistical & Spectral Analysis
2.1 Interpolate sea surface height maps onto along-track positions
[7]:
ds_interp = run_interpolation(ds_maps, ds_alg)
ds_interp = ds_interp.dropna('time')
ds_interp
2023-07-04 14:34:05 INFO fetch data from 2019-01-01 00:00:00 to 2019-02-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-01-31 00:00:00 to 2019-03-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-02-28 00:00:00 to 2019-04-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-03-31 00:00:00 to 2019-05-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-04-30 00:00:00 to 2019-06-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-05-31 00:00:00 to 2019-07-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-06-30 00:00:00 to 2019-08-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-07-31 00:00:00 to 2019-09-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-08-31 00:00:00 to 2019-10-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-09-30 00:00:00 to 2019-11-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-10-31 00:00:00 to 2019-12-01 00:00:00
2023-07-04 14:34:05 INFO fetch data from 2019-11-30 00:00:00 to 2019-12-31 00:00:00
[7]:
<xarray.Dataset>
Dimensions: (time: 37073)
Coordinates:
* time (time) datetime64[ns] 2019-01-01T22:10:01.073445888 .....
Data variables: (12/13)
cycle (time) float64 126.0 126.0 126.0 ... 136.0 136.0 136.0
track (time) float64 36.0 36.0 36.0 36.0 ... 391.0 391.0 391.0
sla_unfiltered (time) float32 0.124 0.177 0.163 ... 0.152 0.181 0.176
sla_filtered (time) float32 0.151 0.161 0.166 ... 0.151 0.169 0.178
dac (time) float32 0.058 0.059 0.059 ... -0.059 -0.059 -0.06
ocean_tide (time) float32 0.172 0.172 0.173 ... -0.339 -0.342 -0.349
... ...
lwe (time) float32 -0.044 -0.043 -0.043 ... -0.047 -0.047
mdt (time) float32 -0.174 -0.172 -0.17 ... -0.173 -0.17
tpa_correction (time) float32 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
longitude (time) float64 305.0 304.9 304.9 ... 297.6 297.6 297.6
latitude (time) float64 42.99 42.93 42.87 ... 42.86 42.92 42.98
msla_interpolated (time) float64 0.1328 0.1322 0.1284 ... 0.106 0.11412.2 Compute grid boxes statistics & statistics by regime (coastal, offshore low variability, offshore high variability)
Once the maps have been interpolated to the position of the along-track, it is possible to calculate different statistics on the time series SLA_alongtrack and SLA_maps.
We propose below the following statistics: error variance maps (static by 1°x1° box), explained variance maps, temporal evolution of global error variance and explained variance.
These statistics are also applied to the filtered signals focusing on the 65-500km scale range. A bandpass filter is applied before calculating the scores.
[8]:
compute_stat_scores(ds_interp, lambda_min, lambda_max, stat_output_filename,method_name)
2023-07-04 14:34:05 INFO Compute mapping error all scales
2023-07-04 14:34:05 INFO Compute mapping error for scales between 65.0 and 500.0 km
2023-07-04 14:34:06 INFO Compute binning statistics
2023-07-04 14:34:07 INFO Compute statistics by oceanic regime
2023-07-04 14:34:31 INFO Stat file saved as: ../results/stat_sla_duacs_geos_GS.nc
[9]:
# Plot gridded stats
# Hvplot
# plot_stat_score_map(stat_output_filename)
# Matplotlib
plot_stat_score_map_png(stat_output_filename,region=region,box_lonlat=box_lonlat_GS)
[10]:
plot_stat_score_timeseries(stat_output_filename)
[10]:
[11]:
plot_stat_by_regimes(stat_output_filename)
[11]:
| mapping_err_var [m²] | sla_unfiltered_var [m²] | mapping_err_filtered_var [m²] | sla_filtered_var [m²] | var_score_allscale | var_score_filtered | |
|---|---|---|---|---|---|---|
| coastal | 0.001673 | 0.012362 | 0.000474 | 0.008133 | 0.864663 | 0.941740 |
| offshore_highvar | 0.004331 | 0.075310 | 0.001669 | 0.034653 | 0.942486 | 0.951841 |
| offshore_lowvar | 0.001736 | 0.017152 | 0.000561 | 0.010251 | 0.898770 | 0.945300 |
| equatorial_band | NaN | NaN | NaN | NaN | NaN | NaN |
| arctic | NaN | NaN | NaN | NaN | NaN | NaN |
| antarctic | NaN | NaN | NaN | NaN | NaN | NaN |
2.3 Compute Spectral scores
[12]:
compute_psd_scores_v2(ds_interp, psd_output_filename, lenght_scale=segment_lenght,method_name=method_name)
2023-07-04 14:34:38 INFO Segment computation...
2023-07-04 14:34:38 INFO Spectral analysis...
2023-07-04 14:34:41 INFO Saving ouput...
2023-07-04 14:34:45 INFO PSD file saved as: ../results/psd_sla_duacs_geos_GS.nc
[13]:
# Plot effective resolution
# Hvplot
# plot_effective_resolution(psd_output_filename)
# Matplotlib
plot_effective_resolution_png(psd_output_filename,region=region,box_lonlat=box_lonlat_GS)
[14]:
plot_psd_scores(psd_output_filename)
[14]: