#!/usr/bin/env python3
# encoding: utf-8
# Copyright (C) 2014 Space Science and Engineering Center (SSEC),
# University of Wisconsin-Madison.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This file is part of the polar2grid software package. Polar2grid takes
# satellite observation data, remaps it, and writes it to a file format for
# input into another program.
# Documentation: http://www.ssec.wisc.edu/software/polar2grid/
"""Functions that handle polar2grid data types."""
import logging
import numpy as np
log = logging.getLogger(__name__)
DTYPE_UINT8 = "uint1"
DTYPE_UINT16 = "uint2"
DTYPE_UINT32 = "uint4"
DTYPE_UINT64 = "uint8"
DTYPE_INT8 = "int1"
DTYPE_INT16 = "int2"
DTYPE_INT32 = "int4"
DTYPE_INT64 = "int8"
DTYPE_FLOAT32 = "real4"
DTYPE_FLOAT64 = "real8"
NUMPY_DTYPE_STRS = [
"uint8",
"uint16",
"uint32",
"uint64",
"int8",
"int16",
"int32",
"int64",
"float32",
"float64",
]
# Map data type to np type for conversion
str2dtype = {
DTYPE_UINT8: np.uint8,
DTYPE_UINT16: np.uint16,
DTYPE_UINT32: np.uint32,
DTYPE_UINT64: np.uint64,
DTYPE_INT8: np.int8,
DTYPE_INT16: np.int16,
DTYPE_INT32: np.int32,
DTYPE_INT64: np.int64,
DTYPE_FLOAT32: np.float32,
DTYPE_FLOAT64: np.float64,
}
dtype2str = dict((v, k) for k, v in str2dtype.items())
# Map data type to valid data range
# Since float32 is polar2grid's intermediate type, float32 and float64 don't
# get clipped
dtype2range = {
DTYPE_UINT8: (0, 2**8 - 1),
DTYPE_UINT16: (0, 2**16 - 1),
DTYPE_UINT32: (0, 2**32 - 1),
DTYPE_UINT64: (0, 2**64 - 1),
DTYPE_INT8: (-1 * (2**7), 2**7 - 1),
DTYPE_INT16: (-1 * (2**15), 2**15 - 1),
DTYPE_INT32: (-1 * (2**31), 2**31 - 1),
DTYPE_INT64: (-1 * (2**63), 2**63 - 1),
DTYPE_FLOAT32: None,
DTYPE_FLOAT64: None,
}
[docs]def normalize_dtype_string(dtype_str):
if dtype_str in str2dtype:
return dtype_str
else:
msg = "Unknown data type string '%s'" % (dtype_str,)
log.error(msg)
raise ValueError(msg)
[docs]def str_to_dtype(dtype_str):
if np.issubclass_(dtype_str, np.number):
# if they gave us a np dtype
return dtype_str
elif isinstance(dtype_str, str) and hasattr(np, dtype_str):
# they gave us the np name of the dtype
return getattr(np, dtype_str)
try:
return str2dtype[dtype_str]
except KeyError:
raise ValueError("Not a valid data type string: %s" % (dtype_str,))
[docs]def dtype_to_str(numpy_dtype):
if isinstance(numpy_dtype, str):
# if they gave us a string, make sure it's valid
return normalize_dtype_string(numpy_dtype)
try:
return dtype2str[np.dtype(numpy_dtype).type]
except KeyError:
raise ValueError("Unsupported np data type: %r" % (numpy_dtype,))
[docs]def clip_to_data_type(data, data_type):
if np.issubdtype(np.dtype(data_type), np.floating):
return data
info = np.iinfo(data_type)
rmin = info.min
rmax = info.max
log.debug("Clipping data to a %d - %d data range" % (rmin, rmax))
return data.clip(rmin, rmax)
[docs]def int_or_float(val):
"""Convert a string to integer or float.
If we can't make it an integer then make it a float.
"""
try:
return int(val)
except ValueError:
return float(val)