
Benchmark DUACS sea surface height maps
2023-04-27 DUACS_SSH_BENCHMARK_DEMO
Authors: CLS & Datlas Copyright: 2023 CLS & Datlas License: MIT
Benchmark of DUACS sea surface height maps
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}')
method_name = 'DUACS'
stat_output_filename = f'{output_dir}/stat_sla_duacs_geos.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.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/alg/2019/*.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 52.5 s, sys: 6.28 s, total: 58.8 s
Wall time: 1min 3s
[5]:
<xarray.Dataset>
Dimensions: (time: 14437696)
Coordinates:
* time (time) datetime64[ns] 2019-01-01T00:04:07.003014144 ... 2...
longitude (time) float64 dask.array<chunksize=(44621,), meta=np.ndarray>
latitude (time) float64 dask.array<chunksize=(44621,), meta=np.ndarray>
Data variables:
cycle (time) float64 dask.array<chunksize=(44621,), meta=np.ndarray>
track (time) float64 dask.array<chunksize=(44621,), meta=np.ndarray>
sla_unfiltered (time) float32 dask.array<chunksize=(44621,), meta=np.ndarray>
sla_filtered (time) float32 dask.array<chunksize=(44621,), meta=np.ndarray>
dac (time) float32 dask.array<chunksize=(44621,), meta=np.ndarray>
ocean_tide (time) float32 dask.array<chunksize=(44621,), meta=np.ndarray>
internal_tide (time) float32 dask.array<chunksize=(44621,), meta=np.ndarray>
lwe (time) float32 dask.array<chunksize=(44621,), meta=np.ndarray>
mdt (time) float32 dask.array<chunksize=(44621,), meta=np.ndarray>
tpa_correction (time) float32 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
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_global_allsat-alg/*.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 6.2 s, sys: 741 ms, total: 6.94 s
Wall time: 8.42 s
[6]:
<xarray.Dataset>
Dimensions: (latitude: 720, longitude: 1440, time: 365)
Coordinates:
* latitude (latitude) float32 -89.88 -89.62 -89.38 ... 89.38 89.62 89.88
* longitude (longitude) float64 0.125 0.375 0.625 0.875 ... 359.4 359.6 359.9
* time (time) datetime64[ns] 2019-01-01 2019-01-02 ... 2019-12-31
Data variables:
sla (time, latitude, longitude) float64 dask.array<chunksize=(1, 720, 1440), meta=np.ndarray>
ugosa (time, latitude, longitude) float64 dask.array<chunksize=(1, 720, 1440), meta=np.ndarray>
vgosa (time, latitude, longitude) float64 dask.array<chunksize=(1, 720, 1440), meta=np.ndarray>
adt (time, latitude, longitude) float64 dask.array<chunksize=(1, 720, 1440), meta=np.ndarray>
ugos (time, latitude, longitude) float64 dask.array<chunksize=(1, 720, 1440), meta=np.ndarray>
vgos (time, latitude, longitude) float64 dask.array<chunksize=(1, 720, 1440), 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-07 16:55:04 INFO fetch data from 2019-01-01 00:00:00 to 2019-02-01 00:00:00
2023-07-07 16:55:06 INFO fetch data from 2019-01-31 00:00:00 to 2019-03-01 00:00:00
2023-07-07 16:55:09 INFO fetch data from 2019-02-28 00:00:00 to 2019-04-01 00:00:00
2023-07-07 16:55:11 INFO fetch data from 2019-03-31 00:00:00 to 2019-05-01 00:00:00
2023-07-07 16:55:13 INFO fetch data from 2019-04-30 00:00:00 to 2019-06-01 00:00:00
2023-07-07 16:55:16 INFO fetch data from 2019-05-31 00:00:00 to 2019-07-01 00:00:00
2023-07-07 16:55:18 INFO fetch data from 2019-06-30 00:00:00 to 2019-08-01 00:00:00
2023-07-07 16:55:20 INFO fetch data from 2019-07-31 00:00:00 to 2019-09-01 00:00:00
2023-07-07 16:55:23 INFO fetch data from 2019-08-31 00:00:00 to 2019-10-01 00:00:00
2023-07-07 16:55:25 INFO fetch data from 2019-09-30 00:00:00 to 2019-11-01 00:00:00
2023-07-07 16:55:28 INFO fetch data from 2019-10-31 00:00:00 to 2019-12-01 00:00:00
2023-07-07 16:55:30 INFO fetch data from 2019-11-30 00:00:00 to 2019-12-31 00:00:00
[7]:
<xarray.Dataset>
Dimensions: (time: 14348023)
Coordinates:
* time (time) datetime64[ns] 2019-01-01T00:04:07.003014144 .....
Data variables: (12/13)
cycle (time) float64 126.0 126.0 126.0 ... 136.0 136.0 136.0
track (time) float64 9.0 9.0 9.0 9.0 ... 408.0 408.0 408.0
sla_unfiltered (time) float32 0.127 0.101 0.07 ... 0.007 0.056 0.01
sla_filtered (time) float32 0.117 0.128 0.142 ... 0.03 0.031 0.027
dac (time) float32 0.303 0.299 0.296 ... 0.172 0.171 0.172
ocean_tide (time) float32 -0.091 -0.096 -0.099 ... -0.304 -0.314
... ...
lwe (time) float32 -0.019 -0.019 -0.019 ... 0.014 0.014 0.016
mdt (time) float32 -0.104 -0.106 -0.108 ... -1.138 -1.154
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 64.42 64.33 64.25 ... 246.7 246.6 246.3
latitude (time) float64 69.9 69.95 70.01 ... -69.27 -69.32 -69.55
msla_interpolated (time) float64 0.1568 0.1544 0.1564 ... 0.0136 0.021172.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.
[9]:
compute_stat_scores(ds_interp, lambda_min, lambda_max, stat_output_filename,method_name)
2023-07-07 16:58:30 INFO Compute mapping error all scales
2023-07-07 16:58:31 INFO Compute mapping error for scales between 65.0 and 500.0 km
2023-07-07 16:59:49 INFO Compute binning statistics
2023-07-07 17:00:09 INFO Compute statistics by oceanic regime
2023-07-07 17:01:03 INFO Stat file saved as: ../results/stat_sla_duacs_geos.nc
[10]:
# Plot gridded stats
# Hvplot
# plot_stat_score_map(stat_output_filename)
# Matplotlib
plot_stat_score_map_png(stat_output_filename)
[13]:
plot_stat_score_timeseries(stat_output_filename)
[13]:
[14]:
plot_stat_by_regimes(stat_output_filename)
[14]:
| 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.002611 | 0.008254 | 0.000572 | 0.001804 | 0.683678 | 0.682788 |
| offshore_highvar | 0.003125 | 0.053255 | 0.001055 | 0.021749 | 0.941316 | 0.951509 |
| offshore_lowvar | 0.001258 | 0.006296 | 0.000234 | 0.001775 | 0.800111 | 0.868348 |
| equatorial_band | 0.001404 | 0.005963 | 0.000311 | 0.000533 | 0.764560 | 0.415881 |
| arctic | 0.002303 | 0.006915 | 0.000417 | 0.001006 | 0.667031 | 0.585653 |
| antarctic | 0.003287 | 0.002323 | 0.000696 | 0.000754 | -0.415025 | 0.077469 |
2.3 Compute Spectral scores
[15]:
compute_psd_scores_v2(ds_interp, psd_output_filename, lenght_scale=segment_lenght,method_name=method_name)
2023-07-05 17:03:17 INFO Segment computation...
2023-07-05 17:03:33 INFO Spectral analysis...
2023-07-05 17:19:27 INFO Saving ouput...
2023-07-05 17:19:35 INFO PSD file saved as: ../results/psd_sla_duacs_geos.nc
[16]:
# Plot effective resolution
# Hvplot
# plot_effective_resolution(psd_output_filename)
# Matplotlib
plot_effective_resolution_png(psd_output_filename)
[17]:
plot_psd_scores(psd_output_filename)
[17]:
The interactive plot above allows you to explore the spectral metrics by latitude / longitude box
[ ]: