Source code for vacumm.diag.dynamics

# -*- coding: utf8 -*-
"""Diagnostic about dynamics"""
# Copyright or © or Copr. Actimar/IFREMER (2010-2015)
#
# This software is a computer program whose purpose is to provide
# utilities for handling oceanographic and atmospheric data,
# with the ultimate goal of validating the MARS model from IFREMER.
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software.  You can  use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and,  more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#

import numpy as N, cdms2, MV2
from vacumm import VACUMMError
from vacumm.data.cf import format_var, format_grid
from vacumm.misc.phys.constants import GRAVITY as default_gravity
from vacumm.misc.axes import isaxis
from vacumm.misc.grid.regridding import shiftgrid
from vacumm.misc.grid import set_grid, get_axis_slices, resol
from vacumm.misc.filters import generic2d

[docs]def barotropic_geostrophic_velocity(ssh, dxy=None, gravity=default_gravity, cyclic=False, format_axes=True, getu=True, getv=True, filter=None): """Get barotropic geostropic velocity from SSH on a C-grid .. note:: ssh is supposed to be at T points, ubt is computed at V points, and vbt is computed at U points. .. todo:: Rewrite it using :mod:`vacumm.data.misc.arakawa` and defining a limited number of algorithms for different staggering configurations. :Params: - **ssh**: Sea surface height. - **dxy**, optional: Horizontal resolutions (m). Resolution along X and Y are respectively at U and V points. Possible forms: - ``res``: A scalar meaning a constant resolution along X and Y. - ``(dx,dy)``: A tuple of resolutions along X and Y. - ``None``: Resolution is estimated using :func:`~vacumm.misc.grid.misc.resol`. :Return: ``(ubt,vbt)`` """ if not getu and not getv: return # Init masked if getu: ugbt = format_var(ssh*MV2.masked, 'ugbt', format_axes=False) if getv: vgbt = format_var(ssh*MV2.masked, 'vgbt', format_axes=False) # Grid tgrid = ssh.getGrid() if getu: ugrid = shiftgrid(tgrid, ishift=0.5) if getv: vgrid = shiftgrid(tgrid, jshift=0.5) if format_axes: if getv: format_grid(ugrid, 'u') if getu: format_grid(vgrid, 'v') if getu: set_grid(ugbt, vgrid) if getv: set_grid(vgbt, ugrid) # Resolutions if dxy is None: dxt, dyt = resol(ssh, proj=True, mode='local') dxu = 0.5*(dxt[:, 1:]+dxt[:, :-1]) ; del dxt dyv = 0.5*(dyt[1:, :]+dyt[:-1, :]) ; del dyt elif not isinstance(dxy, (list, tuple)): dxu = dyv = dxy else: dxu, dyv = dxy if getv and isinstance(dxu, N.ndarray): if cdms2.isVariable(dxu): dxu = dxu.asma() if dxu.ndim==1: dxu.shape = 1, -1 if dxu.shape[1]==ssh.shape[-1]: dxu = dxu[:, :-1] if getu and isinstance(dyv, N.ndarray): if cdms2.isVariable(dyv): dyv = dyv.asma() if dyv.ndim==1: dyv.shape = -1, 1 if dyv.shape[0]==ssh.shape[-2]: dyv = dyv[:-1] # Get geostrophic factor f0 = coriolis_parameter(ssh, gravity=gravity, fromvar=True).asma() bad = f0==0. f0[bad] = 1. f0[bad] = N.ma.masked ; del bad gf = gravity/f0 ; del f0 # Computes sshm = ssh.asma() sshm = sshm*gf ; del gf if getu: ugbt[..., :-1, :] = -N.ma.diff(sshm, axis=-2)/dyv ; del dyv if getv: vgbt[..., :-1] = N.ma.diff(sshm, axis=-1)/dxu ; del dxu del sshm if getu and cyclic: ugbt[..., -1] = ugbt[..., 0] if not getu: return vgbt elif not getv: return ugbt return ugbt, vgbt
[docs]def coriolis_parameter(lat, gravity=default_gravity, fromvar=False, format_axes=False): """Get the coriolis parameters computed at each latitude :Params: - **lat**: Latitude or a variable with latitude coordinates. - **gravity**, optional: Gravity. - **fromvar**, optional: If True, lat is supposed to be a MV2 array with latitude coordinates. """ # Latitude if fromvar: if not cdms2.isVariable(lat): raise VACUMMError('lat must a MV2 array because fromvar is True') latv = lat*0 lat = lat.getLatitude() if lat is None: raise VACUMMError('lat must a MV2 array with a latitude axis because fromvar is True') if cdms2.isVariable(lat): lat=lat.asma() # 2D axes if lat.shape!=latv.shape: if len(lat.shape)==2: latv[:] = N.ma.resize(lat, latv.shape) else: yaxis = latv.getOrder().index('y') new_shape = len(latv.shape)*[1] new_shape[yaxis] = latv.shape[yaxis] tile_shape = list(latv.shape) tile_shape[yaxis] = 1 latv[:] = N.tile(lat[:].reshape(new_shape), tile_shape) else: latv = lat if not N.ndim(lat) else lat[:] # Compute f0 = 2*N.ma.sin(N.pi*latv/180.) # f0 *= 2*N.pi/(24.*3600.) f0 *= 2*N.pi/(86164.) # 86164 = sidereal day.... # Format if N.isscalar(f0): return f0 f0 = MV2.asarray(f0) if not fromvar and isaxis(lat) and f0.ndim==1: f0.setAxis(0, lat) return format_var(f0, 'corio', format_axes=format_axes)
[docs]def kinetic_energy(sshuv, gravity=default_gravity, format_axes=None, dxy=None): """Compute kinetic energy in m2.s-2 either from SSH or velocity on C-grid .. todo:: Rewrite it using :mod:`vacumm.data.misc.arakawa` and defining a limited number of algorithms for different staggering configurations. :Params: - **sshuv**: SSH or (U,V). - If SSH, geostrophic velocity is computed at U and V points using :func:`barotropic_geostrophic_velocity`. - If (U,V), velocities are supposed to be at V and U points. - **dxy**, optional: Horizontal resolutions (see :func:`barotropic_geostrophic_velocity`). :Return: KE at T points. """ # Init and get velocities if cdms2.isVariable(sshuv): # from SSH ke = sshuv*MV2.masked u, v = barotropic_geostrophic_velocity(sshuv, dxy=dxy, gravity=gravity, format_axes=format_axes) if format_axes is None: format_axes = False else: # from (U,V) u, v = sshuv ke = u*MV2.masked if format_axes is None: format_axes = True gridt = shiftgrid(u.getGrid(), jshift=1) set_grid(ke, gridt) # Sum contributions uf = u.filled(0.) vf = v.filled(0.) ke[..., 1:, :] = uf[..., 1:, :]**2 ke[..., 1:, :] += uf[..., :-1, :]**2 ke[..., 1:] += vf[..., 1:]**2 ke[..., 1:] += vf[..., :-1]**2 # Weight and mask count = N.zeros(ke.shape, 'i') gu = 1-N.ma.getmaskarray(u).astype('i') gv = 1-N.ma.getmaskarray(v).astype('i') count[1:] = gu[:-1] count[1:] += gu[1:] count[:, 1:] += gv[:, :-1] count[:, 1:] += gv[:, 1:] del gu, gv mask = count==0 count[mask] = 1 ke[:] /= count ke[:] = MV2.masked_where(mask, ke, copy=0) del mask, count # Format if format_axes: format_grid(gridt, 't') return format_var(ke, "ke", format_axes=False)
eddy_kinetic_energy = kinetic_energy