Source code for satpy.readers.aapp_mhs_amsub_l1c

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2020, 2021, 2022 Pytroll developers

# 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/>.

"""Reader for the AAPP AMSU-B/MHS level-1c data.

https://nwp-saf.eumetsat.int/site/download/documentation/aapp/NWPSAF-MF-UD-003_Formats_v8.0.pdf

"""

import logging

import dask.array as da
import numpy as np

from satpy.readers.aapp_l1b import AAPPL1BaseFileHandler, create_xarray
from satpy.utils import get_legacy_chunk_size

logger = logging.getLogger(__name__)


CHUNK_SIZE = get_legacy_chunk_size()
LINE_CHUNK = CHUNK_SIZE ** 2 // 90

MHS_AMSUB_CHANNEL_NAMES = ['1', '2', '3', '4', '5']
MHS_AMSUB_ANGLE_NAMES = ['sensor_zenith_angle', 'sensor_azimuth_angle',
                         'solar_zenith_angle', 'solar_azimuth_difference_angle']

MHS_AMSUB_PLATFORM_IDS2NAMES = {15: 'NOAA-15',
                                16: 'NOAA-16',
                                17: 'NOAA-17',
                                18: 'NOAA-18',
                                19: 'NOAA-19',
                                1: 'Metop-B',
                                2: 'Metop-A',
                                3: 'Metop-C',
                                4: 'Metop simulator'}

MHS_AMSUB_PLATFORMS = ['Metop-A', 'Metop-B', 'Metop-C', 'NOAA-18', 'NOAA-19']


[docs] class MHS_AMSUB_AAPPL1CFile(AAPPL1BaseFileHandler): """Reader for AMSU-B/MHS L1C files created from the AAPP software.""" def __init__(self, filename, filename_info, filetype_info): """Initialize object information by reading the input file.""" super().__init__(filename, filename_info, filetype_info) self.channels = {i: None for i in MHS_AMSUB_CHANNEL_NAMES} self.units = {i: 'brightness_temperature' for i in MHS_AMSUB_CHANNEL_NAMES} self._channel_names = MHS_AMSUB_CHANNEL_NAMES self._angle_names = MHS_AMSUB_ANGLE_NAMES self._set_filedata_layout() self.read() self._get_platform_name(MHS_AMSUB_PLATFORM_IDS2NAMES) self._get_sensorname()
[docs] def _set_filedata_layout(self): """Set the file data type/layout.""" self._header_offset = HEADER_LENGTH self._scan_type = _SCANTYPE self._header_type = _HEADERTYPE
[docs] def _get_sensorname(self): """Get the sensor name from the header.""" if self._header['instrument'][0] == 11: self.sensor = 'amsub' elif self._header['instrument'][0] == 12: self.sensor = 'mhs' else: raise IOError("Sensor neither MHS nor AMSU-B!")
[docs] def get_angles(self, angle_id): """Get sun-satellite viewing angles.""" satz = self._data["angles"][:, :, 0] * 1e-2 sata = self._data["angles"][:, :, 1] * 1e-2 sunz = self._data["angles"][:, :, 2] * 1e-2 suna = self._data["angles"][:, :, 3] * 1e-2 name_to_variable = dict(zip(MHS_AMSUB_ANGLE_NAMES, (satz, sata, sunz, suna))) return create_xarray(name_to_variable[angle_id])
[docs] def navigate(self, coordinate_id): """Get the longitudes and latitudes of the scene.""" lons, lats = self._get_coordinates_in_degrees() if coordinate_id == 'longitude': return create_xarray(lons) if coordinate_id == 'latitude': return create_xarray(lats) raise KeyError("Coordinate {} unknown.".format(coordinate_id))
[docs] def _get_coordinates_in_degrees(self): lons = self._data["latlon"][:, :, 1] * 1e-4 lats = self._data["latlon"][:, :, 0] * 1e-4 return lons, lats
[docs] def _calibrate_active_channel_data(self, key): """Calibrate active channel data only.""" return self.calibrate(key)
[docs] def calibrate(self, dataset_id): """Calibrate the data.""" units = {'brightness_temperature': 'K'} mask = True idx = ['1', '2', '3', '4', '5'].index(dataset_id['name']) ds = create_xarray( _calibrate(self._data, idx, dataset_id['calibration'], mask=mask)) ds.attrs['units'] = units[dataset_id['calibration']] ds.attrs.update(dataset_id._asdict()) return ds
[docs] def _calibrate(data, chn, calib_type, mask=True): """Calibrate channel data. *calib_type* in brightness_temperature. """ if calib_type not in ['brightness_temperature']: raise ValueError('Calibration ' + calib_type + ' unknown!') channel = da.from_array(data["btemps"][:, :, chn] / 100., chunks=(LINE_CHUNK, 90)) mask &= channel != 0 if calib_type == 'counts': return channel channel = channel.astype(np.float64) return da.where(mask, channel, np.nan)
HEADER_LENGTH = 1152*4 _HEADERTYPE = np.dtype([("siteid", "S3"), ("cfill_1", "S1"), ("l1bsite", "S3"), ("cfill_2", "S1"), ("versnb", "<i4"), ("versyr", "<i4"), ("versdy", "<i4"), ("hdrcnt", "<i4"), ("satid", "<i4"), ("instrument", "<i4"), ("satht", "<i4"), ("period", "<i4"), ("startorbit", "<i4"), ("startdatayr", "<i4"), ("startdatady", "<i4"), ("startdatatime", "<i4"), ("endorbit", "<i4"), ("enddatayr", "<i4"), ("enddatady", "<i4"), ("enddatatime", "<i4"), ("scnlin", "<i4"), ("misscnlin", "<i4"), ("vnantennacorr", "<i4"), ("spare", "<i4"), ("tempradcnv", "<i4", (3, 5)), ("wmosatid", "<i4"), ("filler", "<i4", (1114,)), ]) _SCANTYPE = np.dtype([("scnlin", "<i4"), ("scnlinyr", "<i4"), ("scnlindy", "<i4"), ("scnlintime", "<i4"), ("qualind", "<i4"), ("scnlinqual", "<i4"), ("chanqual", "<i4", (5, )), ("instrtemp", "<i4"), ("spare1", "<i4", (2, )), # Navigation ("latlon", "<i4", (90, 2)), # lat/lon in degrees for Bnfovs: # first : 10^4 x (latitude) # second : 10^4 x (longitude) ("angles", "<i4", (90, 4)), # scan angles for Bnfovs: # first: 10^2 x (local zenith angle) # second: 10^2 x (local azimuth angle) # third: 10^2 x (solar zenith angle) # fourth: 10^2 x (solar azimuth angle) ("scalti", "<i4"), # sat altitude above reference ellipsoid, km*10 ("spare2", "<i4", (2, )), # Calibration ("btemps", "<i4", (90, 5)), # BT data for Bnfovs 10^2 x scene Tb (K), channels 1-5 ("dataqual", "<i4", (90, )), ("filler", "<i4", (55, )) ])