Source code for uwsift.workspace.guidebook

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
guidebook.py
~~~~~~~~~~~~

PURPOSE
This module is the "scientific expert knowledge" that is consulted.



:author: R.K.Garcia <rayg@ssec.wisc.edu>
:copyright: 2014 by University of Wisconsin Regents, see AUTHORS for more details
:license: GPLv3, see LICENSE for more details
"""
__author__ = "rayg"
__docformat__ = "reStructuredText"

import logging

from uwsift.common import INVALID_COLOR_LIMITS, Info, Instrument, Platform
from uwsift.view.colormap import DEFAULT_IR, DEFAULT_UNKNOWN, DEFAULT_VIS

LOG = logging.getLogger(__name__)
GUIDEBOOKS: dict = {}


[docs] class Guidebook(object): """ guidebook which knows about AHI, ABI, AMI bands, timing, file naming conventions """
[docs] def channel_siblings(self, uuid, infos): """Determine the channel siblings of a given dataset. :param uuid: uuid of the dataset we're interested in :param infos: datasetinfo_dict sequence, available datasets :return: (list,offset:int): list of [uuid,uuid,uuid] for siblings in order; offset of where the input is found in list """ return None, None
[docs] def time_siblings(self, uuid, infos): """Determine the time siblings of a given dataset. :param uuid: uuid of the dataset we're interested in :param infos: datasetinfo_dict sequence, available datasets :return: (list,offset:int): list of [uuid,uuid,uuid] for siblings in order; offset of where the input is found in list """ return None, None
DEFAULT_COLORMAPS = { "toa_bidirectional_reflectance": DEFAULT_VIS, "toa_brightness_temperature": DEFAULT_IR, "brightness_temperature": DEFAULT_IR, "height_at_cloud_top": "Cloud Top Height", "air_temperature": DEFAULT_IR, "relative_humidity": DEFAULT_IR, # 'thermodynamic_phase_of_cloud_water_particles_at_cloud_top': 'Cloud Phase', } _NW_GOESR_ABI = { Instrument.ABI: { # http://www.goes-r.gov/education/ABI-bands-quick-info.html 1: 0.47, 2: 0.64, 3: 0.86, 4: 1.37, 5: 1.6, 6: 2.2, 7: 3.9, 8: 6.2, 9: 6.9, 10: 7.3, 11: 8.4, 12: 9.6, 13: 10.3, 14: 11.2, 15: 12.3, 16: 13.3, }, } _NW_HIMAWARI_AHI = { Instrument.AHI: { 1: 0.47, 2: 0.51, 3: 0.64, 4: 0.86, 5: 1.6, 6: 2.3, 7: 3.9, 8: 6.2, 9: 6.9, 10: 7.3, 11: 8.6, 12: 9.6, 13: 10.4, 14: 11.2, 15: 12.4, 16: 13.3, }, } # Instrument -> Band Number -> Nominal Wavelength NOMINAL_WAVELENGTHS = { Platform.HIMAWARI_8: _NW_HIMAWARI_AHI, Platform.HIMAWARI_9: _NW_HIMAWARI_AHI, Platform.GOES_16: _NW_GOESR_ABI, Platform.GOES_17: _NW_GOESR_ABI, Platform.GOES_18: _NW_GOESR_ABI, Platform.GOES_19: _NW_GOESR_ABI, } # CF compliant Standard Names (should be provided by input files or the workspace) # Instrument -> Band Number -> Standard Name _SN_GOESR_ABI = { Instrument.ABI: { 1: "toa_bidirectional_reflectance", 2: "toa_bidirectional_reflectance", 3: "toa_bidirectional_reflectance", 4: "toa_bidirectional_reflectance", 5: "toa_bidirectional_reflectance", 6: "toa_bidirectional_reflectance", 7: "toa_brightness_temperature", 8: "toa_brightness_temperature", 9: "toa_brightness_temperature", 10: "toa_brightness_temperature", 11: "toa_brightness_temperature", 12: "toa_brightness_temperature", 13: "toa_brightness_temperature", 14: "toa_brightness_temperature", 15: "toa_brightness_temperature", 16: "toa_brightness_temperature", } } _SN_HIMAWARI_AHI = { Instrument.AHI: { 1: "toa_bidirectional_reflectance", 2: "toa_bidirectional_reflectance", 3: "toa_bidirectional_reflectance", 4: "toa_bidirectional_reflectance", 5: "toa_bidirectional_reflectance", 6: "toa_bidirectional_reflectance", 7: "toa_brightness_temperature", 8: "toa_brightness_temperature", 9: "toa_brightness_temperature", 10: "toa_brightness_temperature", 11: "toa_brightness_temperature", 12: "toa_brightness_temperature", 13: "toa_brightness_temperature", 14: "toa_brightness_temperature", 15: "toa_brightness_temperature", 16: "toa_brightness_temperature", }, } STANDARD_NAMES = { Platform.HIMAWARI_8: _SN_HIMAWARI_AHI, Platform.HIMAWARI_9: _SN_HIMAWARI_AHI, Platform.GOES_16: _SN_GOESR_ABI, Platform.GOES_17: _SN_GOESR_ABI, } BT_STANDARD_NAMES = ["toa_brightness_temperature", "brightness_temperature", "air_temperature"]
[docs] class ABI_AHI_Guidebook(Guidebook): "e.g. HS_H08_20150714_0030_B10_FLDK_R20.merc.tif" _cache = None # {uuid:metadata-dictionary, ...} def __init__(self): self._cache = {}
[docs] def collect_info(self, info): """Collect information that may not come from the dataset. This method should only be called once to "fill in" metadata that isn't originally known about an opened file. The provided `info` is used as a starting point, but is not modified by this method. """ z = {} band_short_name = info.get(Info.DATASET_NAME, "???") # FIXME: Don't use pure DATASET_NAME since resolution should not be part of the SHORT_NAME # And/or don't use SHORT_NAME for grouping if Info.SHORT_NAME not in info: z[Info.SHORT_NAME] = band_short_name else: z[Info.SHORT_NAME] = info[Info.SHORT_NAME] if Info.LONG_NAME not in info: z[Info.LONG_NAME] = info.get(Info.SHORT_NAME, z[Info.SHORT_NAME]) z.setdefault(Info.STANDARD_NAME, info.get(Info.STANDARD_NAME, "unknown")) if info.get(Info.UNITS, z.get(Info.UNITS)) in ["K", "Kelvin"]: z[Info.UNITS] = "kelvin" return z
def _is_refl(self, info): return info.get(Info.STANDARD_NAME) == "toa_bidirectional_reflectance" def _is_bt(self, info): return info.get(Info.STANDARD_NAME) in BT_STANDARD_NAMES
[docs] def valid_range(self, info): from uwsift.workspace.utils.metadata_utils import get_default_climits configured_climits = get_default_climits(info) if configured_climits != INVALID_COLOR_LIMITS: valid_range = configured_climits elif self._is_refl(info): valid_range = (-0.012, 1.192) if info[Info.UNITS] == "%": # Reflectance/visible data limits valid_range = (valid_range[0] * 100.0, valid_range[1] * 100.0) elif self._is_bt(info): # BT data limits valid_range = (-109.0 + 273.15, 55 + 273.15) elif "valid_min" in info: valid_range = (info["valid_min"], info["valid_max"]) elif "valid_range" in info: valid_range = tuple(info["valid_range"]) elif "flag_values" in info: valid_range = (min(info["flag_values"]), max(info["flag_values"])) else: valid_range = None return valid_range
[docs] def default_colormap(self, info): return DEFAULT_COLORMAPS.get(info.get(Info.STANDARD_NAME), DEFAULT_UNKNOWN)
def _default_display_time(self, info): # FUTURE: This can be customized by the user when = info.get(Info.SCHED_TIME, info.get(Info.OBS_TIME)) if when is None: dtime = "--:--:--" elif "model_time" in info: dtime = "{}Z +{}h".format(info["model_time"].strftime("%Y-%m-%d %H:%M"), when.strftime("%H")) else: dtime = when.strftime("%Y-%m-%d %H:%M:%S") return dtime def _default_display_name(self, info, display_time=None): # FUTURE: This can be customized by the user platform = info.get(Info.PLATFORM, "-unknown-") instrument = info.get(Info.INSTRUMENT, "-unknown-") short_name = info.get(Info.SHORT_NAME, "-unknown-") standard_name = info.get(Info.STANDARD_NAME, "") if standard_name == "toa_bidirectional_reflectance": label = " Refl" # Don't remove the leading space elif standard_name == "toa_brightness_temperature": label = " BT" # Don't remove the leading space else: label = "" if display_time is None: display_time = info.get(Info.DISPLAY_TIME, self._default_display_time(info)) display_name = f"{platform.value} {instrument.value} {short_name}{label} {display_time}" return display_name