diff --git a/satpy/etc/readers/thr3mi_l1c_nc.yaml b/satpy/etc/readers/thr3mi_l1c_nc.yaml
new file mode 100644
index 0000000000..6d31fe79ae
--- /dev/null
+++ b/satpy/etc/readers/thr3mi_l1c_nc.yaml
@@ -0,0 +1,301 @@
+reader:
+ name: thr3mi_l1c_nc
+ short_name: 3MI L1C RAD NetCDF4
+ long_name: EPS-SG 3MI L1C Radiance (NetCDF4)
+ description: >
+ Reader for EUMETSAT EPS-SG 3MI Multi-Angle Polarimeter Level 1C Radiance files in NetCDF4 format per PFS
+ sensors: [3mi]
+ reader: !!python/name:satpy.readers.yaml_reader.FileYAMLReader
+
+ data_identification_keys:
+ name:
+ required: true
+ # wavelength:
+ # type: !!python/name:satpy.dataset.dataid.WavelengthRange
+ view:
+ enum:
+ - view1
+ - view2
+ - view3
+ - view4
+ - view5
+ - view6
+ - view7
+ - view8
+ - view9
+ - view10
+ - view11
+ - view12
+ - view13
+ - view14
+ transitive: true
+ polarization:
+ transitive: true
+ # modifiers:
+ # default: []
+ # type: !!python/name:satpy.dataset.dataid.ModifierTuple
+
+
+file_types:
+ # EUMETSAT EPS-SG Multi-view, Multi-channel, Multi-polarisation Imager (3MI) Level 1C Radiance files in NetCDF4 format
+ nc_3mi_l1c_rad:
+
+ file_reader: !!python/name:satpy.readers.thr3mi_l1c_nc.Thr3miL1cNCFileHandler
+ file_patterns: ['W_XX-EUMETSAT-Darmstadt,SAT,{spacecraft_name:s}-3MI-1C-RAD_C_EUMT_{creation_time:%Y%m%d%H%M%S}_{mission_type:s}_{environment:s}_{sensing_start_time:%Y%m%d%H%M%S}_{sensing_end_time:%Y%m%d%H%M%S}_{disposition_mode:s}_{processing_mode:s}____.nc']
+
+datasets:
+
+# --- Coordinates ---
+ lon_pixels:
+ name: lon_pixels
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/geolocation_data/longitude
+ file_key_overlap: /dimension/overlaps
+ standard_name: longitude
+
+ lat_pixels:
+ name: lat_pixels
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/geolocation_data/latitude
+ file_key_overlap: /dimension/overlaps
+ standard_name: latitude
+
+# --- Measurement data ---
+ 3mi_410:
+ name: 3mi_410
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0410/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 1
+ wavelength: [0.410, 0.420, 0.430]
+
+ 3mi_443:
+ name: 3mi_443
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0443/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 2
+ wavelength: [0.433, 0.443, 0.453]
+
+ 3mi_490:
+ name: 3mi_490
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0490/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ overlaps: number_overlaps
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 3
+ wavelength: [0.480, 0.490, 0.500]
+
+ 3mi_555:
+ name: 3mi_555
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0555/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 4
+ wavelength: [0.545, 0.555, 0.565]
+
+ 3mi_670:
+ name: 3mi_670
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0670/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 5
+ wavelength: [0.660, 0.670, 0.680]
+
+ 3mi_763:
+ name: 3mi_763
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0763/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 6
+ wavelength: [0.753, 0.763, 0.773]
+
+ 3mi_765:
+ name: 3mi_765
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0765/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 7
+ wavelength: [0.745, 0.765, 0.785]
+
+ 3mi_865:
+ name: 3mi_865
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0865/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 8
+ wavelength: [0.845, 0.865, 0.885]
+
+ 3mi_910:
+ name: 3mi_910
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0910/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 9
+ wavelength: [0.900, 0.910, 0.920]
+
+ 3mi_1370:
+ name: 3mi_1370
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0910/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 10
+ wavelength: [1.360, 1.370, 1.380]
+
+ 3mi_1650:
+ name: 3mi_1650
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0910/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 11
+ wavelength: [1.640, 1.650, 1.660]
+
+ 3mi_2130:
+ name: 3mi_2130
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/measurement_data/r_0910/reflectance_
+ file_key_overlap: /dimension/overlaps
+ coordinates: [lat_pixels, lon_pixels]
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12]
+ polarization: [I, Q, U]
+ calibration:
+ reflectance:
+ standard_name: reflectance_factor
+ units: ""
+ radiance:
+ standard_name: toa_outgoing_radiance_per_unit_wavelength
+ chan_solar_index: 12
+ wavelength: [2.120, 2.130, 2.140]
+
+#-------------------------------------------------------------------------------------------------------------------------------------
+
+ # --- Geometric data ---
+ solar_zenith:
+ name: solar_zenith_angle
+ standard_name: solar_zenith_angle
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/geolocation_data/solar_zenith_angle
+ file_key_overlap: /dimension/overlaps
+ file_key001: data/overlap_001/geolocation_data/solar_zenith_angle
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ coordinates: [lat_pixels, lon_pixels]
+
+ relative_azimuth:
+ name: relative_azimuth_angle
+ standard_name: relative_azimuth_angle
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/geolocation_data/relative_azimuth_angle
+ file_key_overlap: /dimension/overlaps
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ coordinates: [lat_pixels, lon_pixels]
+
+ sensor_zenith:
+ name: sensor_zenith_angle
+ standard_name: sensor_zenith_angle
+ file_type: nc_3mi_l1c_rad
+ file_key: data/overlap_XXX/geolocation_data/satellite_zenith_angle
+ file_key_overlap: /dimension/overlaps
+ view: [view1, view2, view3, view4, view5, view6, view7, view8, view9, view10, view11, view12, view13, view14]
+ coordinates: [lat_pixels, lon_pixels]
+
+
+
diff --git a/satpy/readers/thr3mi_l1c_nc.py b/satpy/readers/thr3mi_l1c_nc.py
new file mode 100644
index 0000000000..a9e460337c
--- /dev/null
+++ b/satpy/readers/thr3mi_l1c_nc.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 Satpy developers
+#
+# 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 .
+"""EUMETSAT EPS-SG Multi-view, Multi-channel, Multi-polarisation Imager (3MI) Level 1C products reader.
+
+The ``3mi_l1c_nc`` reader reads EPS-SG 3MI L1C image data in netCDF format. The format is explained
+in the `EPS-SG 3MI Level 1C Product Format Specification`_. Details of format and test data can be
+found at:
+https://user.eumetsat.int/resources/user-guides/metop-sg-3-mi-l1b-and-l1c-data-guide
+
+This version is an initial draft trial version.
+
+"""
+
+import logging
+from datetime import datetime
+import xarray as xr
+from satpy.readers.netcdf_utils import NetCDF4FileHandler
+
+logger = logging.getLogger(__name__)
+
+
+class Thr3miL1cNCFileHandler(NetCDF4FileHandler):
+
+ """Base reader class for 3MI products in netCDF format.
+
+ Args:
+ filename (str): File to read
+ filename_info (dict): Dictionary with filename information
+ filetype_info (dict): Dictionary with filetype information
+
+ """
+
+ def __init__(self, filename, filename_info, filetype_info, **kwargs):
+ """Prepare the class for dataset reading."""
+ super().__init__(filename, filename_info, filetype_info, auto_maskandscale=True)
+
+ def _standardize_dims(self, variable):
+ """Standardize dims to y, note only 1D data for 3MI"""
+
+ # lat/lon dimensions
+ if 'geo_reference_grid_cells' in variable.dims:
+ variable = variable.rename({'geo_reference_grid_cells': 'y'})
+ return variable
+
+ def get_dataset(self, dataset_id, dataset_info):
+ """Get dataset using file_key in dataset_info."""
+ var_key_xxx = dataset_info['file_key']
+ var_key_overlap = dataset_info['file_key_overlap']
+ view_key = 0
+ try:
+ number_overlaps = self[var_key_overlap]
+ except KeyError:
+ logger.warning("Could not find key %s in NetCDF file, no valid Dataset created", var_key_overlap)
+ return None
+
+ # Loop over the number of overlaps present in the granule
+ for i_overlap in range(number_overlaps):
+ # set file_key for current overlap
+ str_overlap = '0' + '0' + str(i_overlap)
+ var_key = var_key_xxx.replace('XXX', str_overlap)
+ # Radiance data has multiple views and polarisations, geolocation not.
+ # If radiance data then get the view and append the polarisation.
+ if var_key[-9:] != 'longitude' and var_key[-8:] != 'latitude':
+ view_key = dataset_info['view']
+ var_key = var_key + dataset_info['polarization']
+
+ logger.debug('Reading in file to get dataset with key %s.', var_key)
+ try:
+ variable = self[var_key]
+ except KeyError:
+ logger.warning("Could not find key %s in NetCDF file, no valid Dataset created", var_key)
+ return None
+ if i_overlap > 0:
+ if var_key[-9:] != 'longitude' and var_key[-8:] != 'latitude':
+ variable = xr.concat([variable[:, view_key], variable_old[:, view_key]], dim="geo_reference_grid_cells")
+ else:
+ variable = xr.concat([variable, variable_old], dim="geo_reference_grid_cells")
+ variable_old = variable.copy(deep=True)
+ # Manage the attributes of the dataset
+ variable.attrs.setdefault('units', None)
+ variable.attrs.update(dataset_info)
+ variable.attrs.update(self._get_global_attributes())
+ variable = self._standardize_dims(variable)
+ return variable
+
+ def _get_global_attributes(self):
+ """Create a dictionary of global attributes to be added to all datasets."""
+ attributes = {
+ 'filename': self.filename,
+ 'start_time': self.start_time,
+ 'end_time': self.end_time,
+ 'spacecraft_name': self.spacecraft_name,
+ 'ssp_lon': self.ssp_lon,
+ 'sensor': self.sensor,
+ 'filename_start_time': self.filename_info['sensing_start_time'],
+ 'filename_end_time': self.filename_info['sensing_end_time'],
+ 'platform_name': self.spacecraft_name,
+ }
+
+ # Add a "quality_group" item to the dictionary with all the variables and attributes
+ # which are found in the 'quality' group of the 3MI product
+ quality_group = self['quality']
+ quality_dict = {}
+ for key in quality_group:
+ # Add the values (as Numpy array) of each variable in the group where possible
+ try:
+ quality_dict[key] = quality_group[key].values
+ except ValueError:
+ quality_dict[key] = None
+ # Add the attributes of the quality group
+ quality_dict.update(quality_group.attrs)
+
+ attributes['quality_group'] = quality_dict
+
+ return attributes
+
+ @property
+ def start_time(self):
+ """Get observation start time."""
+ try:
+ start_time = datetime.strptime(self['/attr/sensing_start_time_utc'], '%Y%m%d%H%M%S.%f')
+ except ValueError:
+ start_time = datetime.strptime(self['/attr/sensing_start_time_utc'], '%Y-%m-%d %H:%M:%S.%f')
+ return start_time
+
+ @property
+ def end_time(self):
+ """Get observation end time."""
+ try:
+ end_time = datetime.strptime(self['/attr/sensing_end_time_utc'], '%Y%m%d%H%M%S.%f')
+ except ValueError:
+ end_time = datetime.strptime(self['/attr/sensing_end_time_utc'], '%Y-%m-%d %H:%M:%S.%f')
+ return end_time
+
+ @property
+ def spacecraft_name(self):
+ """Return spacecraft name."""
+ return self['/attr/spacecraft']
+
+ @property
+ def sensor(self):
+ """Return sensor."""
+ return self['/attr/instrument']
+
+ @property
+ def ssp_lon(self):
+ """Return subsatellite point longitude."""
+ # This parameter is not applicable to 3MI
+ return None
\ No newline at end of file
diff --git a/satpy/tests/reader_tests/test_thr3mi_l1c_nc.py b/satpy/tests/reader_tests/test_thr3mi_l1c_nc.py
new file mode 100644
index 0000000000..b0e4b03e72
--- /dev/null
+++ b/satpy/tests/reader_tests/test_thr3mi_l1c_nc.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 Satpy developers
+#
+# 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 .
+
+"""The Thr3mi_l1c_nc reader tests package."""
+
+import datetime
+import os
+import unittest
+import uuid
+#from unittest import mock
+
+import numpy as np
+import pytest
+import xarray as xr
+from netCDF4 import Dataset
+
+from satpy.readers.thr3mi_l1c_nc import Thr3miL1cNCFileHandler
+
+TEST_FILE = "test_file_thr3mi_l1c_nc.nc"
+
+
+class TestThr3miNCL1cFileHandler(unittest.TestCase):
+ """Test the Thr3miNCL1cFileHandler reader."""
+
+ def setUp(self):
+ """Set up the test."""
+ # Easiest way to test the reader is to create a test netCDF file on the fly
+ # uses a UUID to avoid permission conflicts during execution of tests in parallel
+ self.test_file_name = TEST_FILE + str(uuid.uuid1()) + ".nc"
+
+ with Dataset(self.test_file_name, "w") as nc:
+ # Add global attributes
+ nc.sensing_start_time_utc = "20170920173040.888"
+ nc.sensing_end_time_utc = "20170920174117.555"
+ nc.spacecraft = "test_spacecraft"
+ nc.instrument = "test_instrument"
+
+ nc.createDimension("overlaps", 1)
+
+ # Create data group
+ g1 = nc.createGroup("data")
+
+ # Create data/measurement_data group
+ g1_1 = g1.createGroup("overlap_000")
+
+ # Add dimensions to data/measurement_data group
+ g1_1.createDimension("geo_reference_grid_cells", 10)
+ g1_1.createDimension("viewing_directions_VNIR", 3)
+
+ g1_1_1 = g1_1.createGroup("measurement_data")
+ g1_1_2 = g1_1.createGroup("geolocation_data")
+
+ g1_1_1_1 = g1_1_1.createGroup("r_865")
+
+ # Add variables to data/measurement_data group
+ reflectance_Q = g1_1_1_1.createVariable("reflectance_", np.float32,
+ dimensions=("geo_reference_grid_cells", "viewing_directions_VNIR"))
+ reflectance_Q[:,0] = 75.
+ reflectance_Q[:,1] = 76.
+ reflectance_Q.test_attr = "attr"
+
+ lon = g1_1_2.createVariable("longitude",
+ np.float32,
+ dimensions=("geo_reference_grid_cells"))
+ lon[:] = 150.
+ lat = g1_1_2.createVariable("latitude",
+ np.float32,
+ dimensions=("geo_reference_grid_cells"))
+ lat[:] = 12.
+
+ # Create quality group
+ g2 = nc.createGroup("quality")
+
+ # Add dimensions to quality group
+ g2.createDimension("gap_items", 2)
+
+ # Add variables to quality group
+ var = g2.createVariable("duration_of_product", np.double, dimensions=())
+ var[:] = 1.0
+ var = g2.createVariable("duration_of_data_present", np.double, dimensions=())
+ var[:] = 2.0
+ var = g2.createVariable("duration_of_data_missing", np.double, dimensions=())
+ var[:] = 3.0
+ var = g2.createVariable("duration_of_data_degraded", np.double, dimensions=())
+ var[:] = 4.0
+ var = g2.createVariable("gap_start_time_utc", np.double, dimensions=("gap_items",))
+ var[:] = [5.0, 6.0]
+ var = g2.createVariable("gap_end_time_utc", np.double, dimensions=("gap_items",))
+ var[:] = [7.0, 8.0]
+
+ # Filename info valid for all readers
+ filename_info = {
+ "creation_time": datetime.datetime(year=2017, month=9, day=22,
+ hour=22, minute=40, second=10),
+ "sensing_start_time": datetime.datetime(year=2017, month=9, day=20,
+ hour=12, minute=30, second=30),
+ "sensing_end_time": datetime.datetime(year=2017, month=9, day=20,
+ hour=18, minute=30, second=50)
+ }
+
+ # Create a reader
+ self.reader = Thr3miL1cNCFileHandler(
+ filename=self.test_file_name,
+ filename_info=filename_info,
+ filetype_info={}
+ )
+
+ def tearDown(self):
+ """Remove the previously created test file."""
+ # Catch Windows PermissionError for removing the created test file.
+ try:
+ os.remove(self.test_file_name)
+ except OSError:
+ pass
+
+ def test_file_reading(self):
+ """Test the file product reading."""
+ # Checks that the basic functionalities are correctly executed
+ expected_start_time = datetime.datetime(year=2017, month=9, day=20,
+ hour=17, minute=30, second=40, microsecond=888000)
+ assert self.reader.start_time == expected_start_time
+
+ expected_end_time = datetime.datetime(year=2017, month=9, day=20,
+ hour=17, minute=41, second=17, microsecond=555000)
+ assert self.reader.end_time == expected_end_time
+
+ assert self.reader.spacecraft_name == "test_spacecraft"
+ assert self.reader.sensor == "test_instrument"
+ assert self.reader.ssp_lon is None
+
+ # Checks that the global attributes are correctly read
+ expected_global_attributes = {
+ "filename": self.test_file_name,
+ "start_time": expected_start_time,
+ "end_time": expected_end_time,
+ "spacecraft_name": "test_spacecraft",
+ "ssp_lon": None,
+ "sensor": "test_instrument",
+ "filename_start_time": datetime.datetime(year=2017, month=9, day=20,
+ hour=12, minute=30, second=30),
+ "filename_end_time": datetime.datetime(year=2017, month=9, day=20,
+ hour=18, minute=30, second=50),
+ "platform_name": "test_spacecraft",
+ "quality_group": {
+ "duration_of_product": 1.,
+ "duration_of_data_present": 2.,
+ "duration_of_data_missing": 3.,
+ "duration_of_data_degraded": 4.,
+ "gap_start_time_utc": (5., 6.),
+ "gap_end_time_utc": (7., 8.)
+ }
+ }
+
+ global_attributes = self.reader._get_global_attributes()
+ # Since the global_attributes dictionary contains numpy arrays,
+ # it is not possible to peform a simple equality test
+ # Must iterate on all keys to confirm that the dictionaries are equal
+ assert global_attributes.keys() == expected_global_attributes.keys()
+ for key in expected_global_attributes:
+ if key not in ["quality_group"]:
+ # Quality check must be valid for both iterable and not iterable elements
+ try:
+ equal = all(global_attributes[key] == expected_global_attributes[key])
+ except (TypeError, ValueError):
+ equal = global_attributes[key] == expected_global_attributes[key]
+ assert equal
+ else:
+ assert global_attributes[key].keys() == expected_global_attributes[key].keys()
+ for inner_key in global_attributes[key]:
+ # Equality check must be valid for both iterable and not iterable elements
+ try:
+ equal = all(global_attributes[key][inner_key] == expected_global_attributes[key][inner_key])
+ except (TypeError, ValueError):
+ equal = global_attributes[key][inner_key] == expected_global_attributes[key][inner_key]
+ assert equal
+
+
+ def test_standardize_dims(self):
+ """Test the standardize dims function."""
+ test_variable = xr.DataArray(
+ dims=("geo_reference_grid_cells"),
+ name="test_data",
+ attrs={
+ "key_1": "value_lat_1",
+ "key_2": "value_lat_2"
+ },
+ data=np.ones((10)) * 1.
+ )
+ out_variable = self.reader._standardize_dims(test_variable)
+ print("out_variable ", out_variable)
+ assert np.allclose(out_variable.values, np.ones(10))
+ assert out_variable.dims == ("y",)
+ assert out_variable.attrs["key_1"] == "value_lat_1"
+
+
+
+
+