Source code for vacumm.misc.phys.units

# -*- coding: utf8 -*-
"Unit conversions"

# 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 re
from constants import *
import numpy as N
import MV2

__all__ = [
    'kt2ms', 'ms2kt', 'deg2m', 'm2deg', 'ms2bf', 'dms2deg', 'deg2dms',
    'mph2ms', 'ms2mph', 'tometric', 'kel2degc', 'degc2kel',
    'convert_units', 'basic_proj', 'uuconvert',
    'rad2deg', 'deg2rad', 'vect2mod', 'vect2dir', 'vect2moddir',
    'moddir2vectx', 'moddir2vecty', 'moddir2vectxy',
    'strfsize', 'strpsize', 'uuconvert',
]

[docs]def uuconvert(value, oldunits, newunits): """Change units using unidata units connverter""" try: from genutil.udunits import udunits_wrap except: from unidata import udunits_wrap s, i = udunits_wrap.convert(oldunits, newunits) return value * s + i
convert_units = uuconvert ############################################################
[docs]def kt2ms(nd): """Convert nds to m/s""" return uuconvert(nd, 'kt', 'm/s')
[docs]def ms2kt(ms): """Convert m/s to nds""" return uuconvert(ms, 'm/s', 'kt')
ms2nd = ms2kt nd2ms = kt2ms
[docs]def mph2ms(mph): """Convert from mph to m/s""" return 0.44704*mph
[docs]def ms2mph(ms): """Convert from m/s to mph""" return 2.237*ms
############################################################
[docs]def deg2m(degrees, lat=None): """Convert a distance in degrees to meters - **degrees**: Distance in degrees - *lat*: optional latitude, defaults to 0. Return: Distance in meters .. seealso:: :func:`m2deg` """ if lat is None: lat = 0. else: lat = N.array(lat) return R * N.pi * degrees * N.cos(N.pi*lat/180.)/180.
[docs]def m2deg(meters, lat=None): """Convert a distance in meters to degrees - **meters**: Distance in meters - *lat*: optional latitude, defaults to 0. Return: Distance in degrees .. seealso:: :func:`deg2m` """ if lat is None: lat = 0. else: lat = N.array(lat) return meters / (R * N.pi * N.cos(N.pi*lat/180.)/180.)
[docs]def basic_proj(lon, lat, inverse=False): """Convert a position from degrees to meters like a geographic projection :Params: - **lon**: Longitude in degrees or meters. - **lat**: Latitude in degrees or meters. - **inverse**, optional: Invert the projection from meters to degrees. """ func = m2deg if inverse else deg2m return func(lon, lat), func(lat)
[docs]def ms2bf(ms): """Convert from m/s to Beauforts (wind) - **ms**: Wind speed in m/s. .. seealso:: http://fr.wikipedia.org/wiki/%C3%89chelle_de_Beaufort """ ms *= 3.6 # km/h to m/s return int(round((ms**2/9)**(1/3.)))
[docs]def dms2deg(d,m=0,s=0): """Convert from degrees/minutes/seconds to degrees - **d**: degrees - *m*: minutes [default: 0] - *s*: seconds [default: 0] .. seealso:: :func:`deg2dms` """ return (d < 0. and -1. or 1.) * (abs(d) + (m + s / 60.) /60.)
[docs]def deg2dms(deg): """Convert from degrees to degrees/minutes/seconds - **deg**: degrees .. seealso:: :func:`dms2deg` """ n, deg = deg < 0., abs(deg) d = int(deg) fm = (deg-d)*60. m = int(fm) s = (fm-m)*60. return n and -d or d, m, s
[docs]def kel2degc(tk): """Convert from degrees Kelvin to degrees Celsius - **tk**: Temperature in Kelvin. .. seealso:: http://fr.wikipedia.org/wiki/Kelvin """ #tk = tk - 273.15 # Kelvin to DegC return tk - 273.15
[docs]def degc2kel(dc): """Convert from degrees Celsius to degrees Kelvin - **dc**: Temperature in degrees Celsius. .. seealso:: http://fr.wikipedia.org/wiki/Kelvin """ #dc = dc + 273.15 # DegC to Kelvin return dc + 273.15
#def unorm(units): # """Try to normalize some units""" # units = units.strip() # if units.lower()=='m.p.h.': return 'mph' # m = re.match(r'\b(f(?:ee)?t|k?m|k(?:no)?t|kt)([\/\.\s]+|)(h(?:r)?|s(?:ec(?:ond)?)?|)(\b.*)', units.lower()) # if m is not None: # return ''.join(m.groups()) # return units
[docs]def tometric(units, value=1., munits=['m', 'm/s']): """Try to convert units to metric system using :mod:`~unidata.udunits.udunits` :Return: a float or ``None`` if conversion failed. """ if isinstance(munits, basestring): munits = [munits] for mu in munits: try: return uuconvert(value, units, mu) except: pass
[docs]def rad2deg(r): return MV2.fmod(180 * r / MV2.pi, 360)
[docs]def deg2rad(d): return MV2.pi * MV2.fmod(d, 360) / 180
[docs]def vect2mod(u, v): return MV2.sqrt(MV2.power(u, 2) + MV2.power(v, 2))
[docs]def vect2dir(u, v): return rad2deg(MV2.arctan2(v, u))
[docs]def vect2moddir(u, v): return vect2mod(u, v), vect2dir(u, v)
[docs]def moddir2vectx(m, d): return MV2.multiply(m, MV2.cos(deg2rad(d)))
[docs]def moddir2vecty(m, d): return MV2.multiply(m, MV2.sin(deg2rad(d)))
[docs]def moddir2vectxy(m, d): return moddir2vectx(m, d), moddir2vecty(m, d)
# 1 kilooctet (ko) = 10**3 octets = 1 000 octets sizeunits = { 'K':10**3, 'M':10**6, 'G':10**9, 'T':10**12, 'P':10**15, 'E':10**18, 'Z':10**21, 'Y':10**24, } # 1 kibioctet (Kio) = 2**10 octets = 1 024 octets sisizeunits = { 'K':2**10, 'M':2**20, 'G':2**30, 'T':2**40, 'P':2**50, 'E':2**60, 'Z':2**70, 'Y':2**80, }
[docs]def strfsize(size, fmt=None, si=None): """Format a size in bytes using the appropriate unit multiplicator (Ko, Mo, Kio, Mio) :Params: - **size**: the size in bytes - **fmt**: the format to use, will receive the size and the unit as format arguments (None will automatically use "%.3f %s" or "%d %s") - **si**: whether to use International System units (10^3, ...) or not (2**10, ...) :Return: a string """ if fmt is None: fmt = '%.3f %s' if float(size) % 1 else '%d %s' sortsizedict = lambda sd: reversed(sorted(sd.items(), lambda a, b: cmp(a[1],b[1]))) if si is None: units,usfx = sortsizedict(sisizeunits),'o' # naive usage else: units,usfx = (sortsizedict(sisizeunits),'io') if si else (sortsizedict(sizeunits),'o') size = float(size) for unit,thresh in units: if size >= thresh: return fmt%(size/thresh, unit) + usfx return fmt%(size) + usfx
_strpsizerex = re.compile(r'(?P<number>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)\s*(?P<unit>%s)?(?P<usfx>io|o)?'%('|'.join(sizeunits.keys())), re.IGNORECASE)
[docs]def strpsize(size, si=True): """Parse a size in Ko, Mo, Kio, Mio, ... :Params: - **size**: the size string - **si**: whether to use International System units (10^3, ...) or not (2**10, ...) :Return: the float number of bytes """ if not isinstance(size, basestring): size = '%s'%(size) m = _strpsizerex.match(size) if m: d = m.groupdict() n = float(d['number']) u = (d.get('unit') or '').upper() s = (d.get('usfx') or '').lower() if u: if s == 'io': return n * sisizeunits[u] elif si: return n * sisizeunits[u] else: return n * sizeunits[u] else: return n raise ValueError('Cannot parse size: %s'%(size))