Source code for swot_simulator.plugins.ssh.hycom

# Copyright (c) 2020 CNES/JPL
#
# All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
"""
Interpolation of the SSH HYCOM
==============================
"""
import os
import re
import numpy as np
import pyinterp
import pyinterp.backends.xarray
import xarray as xr

from . import detail


[docs]class HYCOM(detail.CartesianGridHandler): """ Interpolation of the SSH HYCOM """ #: Decode the product date encoded from the file name. #hycom_GLBu0.08_191_2012031900_t012.nc PATTERN = re.compile( r"hycom_GLBu0.08_191_(\d{4})(\d{2})(\d{2})(\d{2})_t\d{3}.nc").search
[docs] def load_ts(self): """Loading in memory the time axis of the time series""" items = [] length = -1 for root, _, files in os.walk(self.path): for item in files: match = self.PATTERN(item) if match is not None or True: filename = os.path.join(root, item) items.append( (np.datetime64(f"{match.group(1)}-{match.group(2)}-" f"{match.group(3)}"), filename)) length = max(length, len(filename)) # The time series is encoded in a structured Numpy array containing # the date and path to the file. ts = np.array(items, dtype={ 'names': ('date', 'path'), 'formats': ('datetime64[s]', f'U{length}') }) self.ts = ts[np.argsort(ts["date"])] # The frequency between the grids must be constant. frequency = set(np.diff(self.ts["date"].astype(np.int64))) if len(frequency) > 1: raise RuntimeError( "Time series does not have a constant step between two " f"grids: {frequency} seconds") elif len(frequency) != 1: raise RuntimeError("Check that your list of data is not empty") # The frequency is stored in order to load the grids required to # interpolate the SSH. self.dt = np.timedelta64(frequency.pop(), 's')
[docs] def load_dataset( self, first_date: np.datetime64, last_date: np.datetime64) -> pyinterp.backends.xarray.Grid3D: """Loads the 3D cube describing the SSH in time and space.""" if first_date < self.ts["date"][0] or last_date > self.ts["date"][-1]: raise IndexError( f"period [{first_date}, {last_date}] is out of range: " f"[{self.ts['date'][0]}, {self.ts['date'][-1]}]") first_date -= self.dt last_date += self.dt selected = self.ts["path"][:] ds = xr.open_mfdataset(selected, concat_dim="time", combine="nested", decode_times=False) ds = ds.sel(depth=0) x_axis = pyinterp.Axis(ds.variables["lon"][:], is_circle=True) y_axis = pyinterp.Axis(ds.variables["lat"][:]) hours = (ds.variables['time'][:].data * 3600000000).astype('timedelta64[us]') time = np.datetime64('2000') + hours z_axis = pyinterp.TemporalAxis(time) var = ds.surf_el[:].T return pyinterp.Grid3D(x_axis, y_axis, z_axis, var)
[docs] def interpolate(self, lon: np.ndarray, lat: np.ndarray, time: np.ndarray) -> np.ndarray: """Interpolate the SSH to the required coordinates""" interpolator = self.load_dataset(time.min(), time.max()) ssh = pyinterp.trivariate(interpolator, lon.flatten(), lat.flatten(), time, bounds_error=True, interpolator='bilinear').reshape(lon.shape) return ssh