forked from pytroll/satpy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add reader for EarthCARE MSI L1c data.
- Loading branch information
Showing
3 changed files
with
395 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
sensor_name: visir/ec_msi | ||
|
||
|
||
modifiers: | ||
sunz_corrected: | ||
modifier: !!python/name:satpy.modifiers.SunZenithCorrector | ||
|
||
rayleigh_corrected: | ||
modifier: !!python/name:satpy.modifiers.PSPRayleighReflectance | ||
atmosphere: us-standard | ||
aerosol_type: rayleigh_only | ||
prerequisites: | ||
- name: VIS | ||
modifiers: [sunz_corrected] | ||
optional_prerequisites: | ||
- satellite_azimuth_angle | ||
- satellite_zenith_angle | ||
- solar_azimuth_angle | ||
- solar_zenith_angle | ||
|
||
composites: | ||
natural_color_nocorr: | ||
compositor: !!python/name:satpy.composites.GenericCompositor | ||
prerequisites: | ||
- SWIR1 | ||
- NIR | ||
- VIS | ||
standard_name: natural_color | ||
|
||
natural_color: | ||
compositor: !!python/name:satpy.composites.GenericCompositor | ||
prerequisites: | ||
- name: SWIR1 | ||
modifiers: [sunz_corrected] | ||
- name: NIR | ||
modifiers: [sunz_corrected] | ||
- name: VIS | ||
modifiers: [sunz_corrected] | ||
standard_name: natural_color |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,262 @@ | ||
reader: | ||
name: msi_l1c_earthcare | ||
short_name: MSI EarthCARE | ||
long_name: Multispectral Imager for EarthCARE | ||
description: Multispectral Imager for EarthCARE Level 1C (regridded) Reader | ||
status: Nominal | ||
supports_fsspec: true | ||
sensors: [ec_msi] | ||
reader: !!python/name:satpy.readers.yaml_reader.FileYAMLReader | ||
|
||
|
||
file_types: | ||
msi_l1c_earthcare_rgr: | ||
file_reader: !!python/name:satpy.readers.msi_ec_l1c_h5.MSIECL1CFileHandler | ||
file_patterns: | ||
- '{mission_id:s}_{processing_institute:s}_{sensor_id:s}_{file_id:s}_{proc_level:s}_{start_time:%Y%m%dT%H%M%S}Z_{end_time:%Y%m%dT%H%M%S}Z_{orbit_number:s}{frame_id:s}.h5' | ||
|
||
|
||
datasets: | ||
# Science measurement datasets | ||
VIS: | ||
name: VIS | ||
sensor: ec_msi | ||
wavelength: [0.66, 0.67, 0.68] | ||
resolution: 500 | ||
calibration: | ||
reflectance: | ||
standard_name: toa_bidirectional_reflectance | ||
units: "%" | ||
radiance: | ||
standard_name: toa_outgoing_radiance | ||
units: W m-2 sr-1 | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values | ||
band_index: 0 | ||
coordinates: [longitude, latitude] | ||
NIR: | ||
name: NIR | ||
sensor: ec_msi | ||
wavelength: [0.855, 0.865, 0.875] | ||
resolution: 500 | ||
calibration: | ||
reflectance: | ||
standard_name: toa_bidirectional_reflectance | ||
units: "%" | ||
radiance: | ||
standard_name: toa_outgoing_radiance | ||
units: W m-2 sr-1 | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values | ||
band_index: 1 | ||
coordinates: [longitude, latitude] | ||
SWIR1: | ||
name: SWIR1 | ||
sensor: ec_msi | ||
wavelength: [1.64, 1.67, 1.70] | ||
resolution: 500 | ||
calibration: | ||
reflectance: | ||
standard_name: toa_bidirectional_reflectance | ||
units: "%" | ||
radiance: | ||
standard_name: toa_outgoing_radiance | ||
units: W m-2 sr-1 | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values | ||
band_index: 2 | ||
coordinates: [longitude, latitude] | ||
SWIR2: | ||
name: SWIR2 | ||
sensor: ec_msi | ||
wavelength: [2.16, 2.21, 2.26] | ||
resolution: 500 | ||
calibration: | ||
reflectance: | ||
standard_name: toa_bidirectional_reflectance | ||
units: "%" | ||
radiance: | ||
standard_name: toa_outgoing_radiance | ||
units: W m-2 sr-1 | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values | ||
band_index: 3 | ||
coordinates: [longitude, latitude] | ||
TIR1: | ||
name: TIR1 | ||
sensor: ec_msi | ||
wavelength: [8.35, 8.80, 9.25] | ||
resolution: 500 | ||
calibration: | ||
brightness_temperature: | ||
standard_name: toa_brightness_temperature | ||
units: "K" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values | ||
band_index: 4 | ||
coordinates: [longitude, latitude] | ||
TIR2: | ||
name: TIR2 | ||
sensor: ec_msi | ||
wavelength: [10.35, 10.80, 11.25] | ||
resolution: 500 | ||
calibration: | ||
brightness_temperature: | ||
standard_name: toa_brightness_temperature | ||
units: "K" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values | ||
band_index: 5 | ||
coordinates: [longitude, latitude] | ||
TIR3: | ||
name: TIR3 | ||
sensor: ec_msi | ||
wavelength: [11.55,12.00,12.45] | ||
resolution: 500 | ||
calibration: | ||
brightness_temperature: | ||
standard_name: toa_brightness_temperature | ||
units: "K" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values | ||
band_index: 6 | ||
coordinates: [longitude, latitude] | ||
|
||
# Relative error datasets | ||
VIS_rel_error: | ||
name: VIS_rel_error | ||
sensor: ec_msi | ||
resolution: 500 | ||
standard_name: relative_error_in_toa_radiance | ||
units: "%" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values_relative_error | ||
band_index: 0 | ||
NIR_rel_error: | ||
name: NIR_rel_error | ||
sensor: ec_msi | ||
resolution: 500 | ||
standard_name: relative_error_in_toa_radiance | ||
units: "%" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values_relative_error | ||
band_index: 1 | ||
SWIR1_rel_error: | ||
name: SWIR1_rel_error | ||
sensor: ec_msi | ||
resolution: 500 | ||
standard_name: relative_error_in_toa_radiance | ||
units: "%" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values_relative_error | ||
band_index: 2 | ||
SWIR2_rel_error: | ||
name: SWIR2_rel_error | ||
sensor: ec_msi | ||
resolution: 500 | ||
standard_name: relative_error_in_toa_radiance | ||
units: "%" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values_relative_error | ||
band_index: 3 | ||
TIR1_rel_error: | ||
name: TIR1_rel_error | ||
sensor: ec_msi | ||
resolution: 500 | ||
standard_name: relative_error_in_toa_brightness_temperature | ||
units: "%" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values_relative_error | ||
band_index: 4 | ||
TIR2_rel_error: | ||
name: TIR2_rel_error | ||
sensor: ec_msi | ||
resolution: 500 | ||
standard_name: relative_error_in_toa_brightness_temperature | ||
units: "%" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values_relative_error | ||
band_index: 5 | ||
TIR3_rel_error: | ||
name: TIR3_rel_error | ||
sensor: ec_msi | ||
resolution: 500 | ||
standard_name: relative_error_in_toa_brightness_temperature | ||
units: "%" | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/pixel_values_relative_error | ||
band_index: 6 | ||
|
||
# Geolocation data | ||
longitude: | ||
name: longitude | ||
units: degrees_east | ||
standard_name: longitude | ||
resolution: 500 | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/longitude | ||
latitude: | ||
name: latitude | ||
units: degrees_north | ||
standard_name: latitude | ||
resolution: 500 | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/latitude | ||
solar_azimuth_angle: | ||
name: solar_azimuth_angle | ||
units: degree | ||
standard_name: solar_azimuth_angle | ||
resolution: 500 | ||
coordinates: [longitude, latitude] | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/solar_azimuth_angle | ||
sensor_azimuth_angle: | ||
name: sensor_azimuth_angle | ||
units: degree | ||
standard_name: sensor_azimuth_angle | ||
resolution: 500 | ||
coordinates: [longitude, latitude] | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/sensor_azimuth_angle | ||
sensor_view_angle: | ||
name: sensor_zenith_angle | ||
units: degree | ||
standard_name: sensor_zenith_angle | ||
resolution: 500 | ||
coordinates: [longitude, latitude] | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: NonStandard/sensor_view_angle | ||
solar_zenith_angle: | ||
name: solar_zenith_angle | ||
units: degree | ||
standard_name: solar_zenith_angle | ||
resolution: 500 | ||
coordinates: [longitude, latitude] | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: NonStandard/solar_zenith_angle | ||
|
||
# Ancillary data | ||
land_flag: | ||
name: land_water_mask | ||
units: 1 | ||
standard_name: land_water_mask | ||
resolution: 500 | ||
coordinates: [longitude, latitude] | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/land_flag | ||
surface_elevation: | ||
name: surface_elevation | ||
units: m | ||
standard_name: surface_elevation | ||
resolution: 500 | ||
coordinates: [longitude, latitude] | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: ScienceData/surface_elevation | ||
surface_index: | ||
name: surface_index | ||
units: 1 | ||
standard_name: surface_index | ||
resolution: 500 | ||
coordinates: [longitude, latitude] | ||
file_type: msi_l1c_earthcare_rgr | ||
file_key: NonStandard/surface_index |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
# Copyright (c) 2024. | ||
# | ||
# This file is part of satpy. | ||
# | ||
# satpy 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. | ||
# | ||
# satpy 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 | ||
# satpy. If not, see <http://www.gnu.org/licenses/>. | ||
"""A reader for Level 1C data produced by the MSI instrument aboard EarthCARE.""" | ||
import logging | ||
|
||
from satpy.readers.hdf5_utils import HDF5FileHandler | ||
from satpy.utils import get_legacy_chunk_size | ||
|
||
LOG = logging.getLogger(__name__) | ||
CHUNK_SIZE = get_legacy_chunk_size() | ||
|
||
|
||
class MSIECL1CFileHandler(HDF5FileHandler): | ||
"""File handler for MSI L1c H5 files.""" | ||
|
||
def __init__(self, filename, filename_info, filetype_info): | ||
"""Init the file handler.""" | ||
super(MSIECL1CFileHandler, self).__init__(filename, | ||
filename_info, | ||
filetype_info) | ||
|
||
@property | ||
def end_time(self): | ||
"""Get end time.""" | ||
return self.filename_info["end_time"] | ||
|
||
@property | ||
def start_time(self): | ||
"""Get start time.""" | ||
return self.filename_info["start_time"] | ||
|
||
def get_dataset(self, dataset_id, ds_info): | ||
"""Load data variable and metadata and calibrate if needed.""" | ||
file_key = ds_info.get("file_key", dataset_id["name"]) | ||
data = self[file_key] | ||
|
||
# Band data is stored in a 3d array (Band x Along_Track x Across_Track). | ||
# This means we have to select a single 2d array for a given band, | ||
# and the correct index is given in the reader YAML. | ||
band_index = ds_info.get("band_index") | ||
if band_index is not None: | ||
data = data[band_index] | ||
|
||
# The dataset has incorrect units attribute (due to storing multiple types). Fix it here. | ||
data.attrs.update(ds_info) | ||
data.attrs.update({"units": ds_info.get("units")}) | ||
|
||
# VIS/SWIR data can have radiance or reflectance calibration. | ||
if "calibration" in ds_info: | ||
if ds_info["calibration"].name == "reflectance": | ||
data = self._calibrate(data, band_index) | ||
elif ds_info["calibration"].name not in ["radiance", "brightness_temperature"]: | ||
raise ValueError(f"Unknown calibration type:{ds_info['calibration'].name}") | ||
|
||
# Rename dimensions, as some have incorrect names (notably the pixel value data). | ||
if "dim_1" in data.dims: | ||
data = data.rename({"dim_1": "y", "dim_2": "x"}) | ||
|
||
# The dimension list is usually a reference to an H5 variable, which is problematic | ||
# when making a copy of the data. This sorts out the dimensions and sets them correctly | ||
# following the process done in the OMPS reader. | ||
if "DIMENSION_LIST" in data.attrs: | ||
data.attrs.pop("DIMENSION_LIST") | ||
dimensions = self.get_reference(file_key, "DIMENSION_LIST") | ||
dim_dict = {} | ||
# We have to loop over dimensions to match dim sizes as the pixel data is 3d rather than 2d. | ||
for i in range(0, len(data.dims)): | ||
c_dim = data.dims[i] | ||
for r_dim in dimensions: | ||
if data.shape[i] == r_dim[0].shape[0]: | ||
dim_dict[c_dim] = r_dim[0] | ||
data.assign_coords(dim_dict) | ||
return data | ||
|
||
def _calibrate(self, data, band_index): | ||
"""Calibrate the data.""" | ||
sol_irrad = self["NonStandard/solar_irradiance"] | ||
|
||
return 100 * data / sol_irrad[band_index] |