Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Harmonise AreaDefinition namings in EUM geos readers and sort geos areas in areas.yaml #1485

Merged
merged 30 commits into from
Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a24f21f
implement naming functions in eum_base
ameraner Dec 11, 2020
40d94eb
make native reader use new naming functions
ameraner Dec 11, 2020
b3e1b2c
make fci reader use new naming functions
ameraner Dec 11, 2020
713b547
make hrit reader use new naming functions
ameraner Dec 11, 2020
5be2072
make nc reader use new naming functions and update documents links
ameraner Dec 11, 2020
2eab9b8
move methods from eum_base to _geos_area
ameraner Dec 11, 2020
8f86327
make naming methods more general and move information input to readers
ameraner Dec 11, 2020
351c28c
sort areas.yaml for geos areas
ameraner Dec 14, 2020
916cb14
fix service naming
ameraner Dec 14, 2020
6914118
add seviri areas.yaml and add deprecation comments
ameraner Dec 14, 2020
24c35d4
replace globe for disk in area descriptions to close https://github.c…
ameraner Dec 14, 2020
44591de
remove unnecessary else
ameraner Dec 14, 2020
7c31f2c
use get for service mode dictionary retrieval and add "unknown" fallback
ameraner Dec 14, 2020
dcb70ff
change tests to check area_id rather than proj_id, and remove unneces…
ameraner Dec 14, 2020
f82773f
fix native tests
ameraner Dec 14, 2020
4b23ba8
move get_service_mode tests to eum_base and update
ameraner Dec 14, 2020
287637c
add unknown input tests for get_service_mode
ameraner Dec 14, 2020
3804dbd
fix hrit tests
ameraner Dec 14, 2020
ce8ef99
add tests for new function in _geos_area and update docstrings
ameraner Dec 14, 2020
19c273c
add description for South America
ameraner Dec 14, 2020
5170605
update resolution docstring
ameraner Dec 14, 2020
d62aaf2
add test also for second window in HRV HRIT
ameraner Dec 14, 2020
d11ce5d
fix documentation link for seviri_base
ameraner Dec 14, 2020
3fbe54c
add service_desc to docstring in get_geos_area_naming
ameraner Dec 15, 2020
b23d8b6
limit areas.yaml line characters to 79
ameraner Dec 15, 2020
c260490
add notices about different area extents in native and netcdf get_are…
ameraner Dec 16, 2020
4b32101
Merge branch 'master' into feature-harmonise_EUM_area_naming
ameraner Dec 16, 2020
af33f67
fix sve area description
ameraner Dec 16, 2020
69eb991
use empty strings for proj_id, remove formatting of proj_id and add d…
ameraner Dec 16, 2020
c2f56cd
delete comment on proj_id on wrong line and add note to get_area_defi…
ameraner Dec 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
509 changes: 330 additions & 179 deletions satpy/etc/areas.yaml

Large diffs are not rendered by default.

63 changes: 60 additions & 3 deletions satpy/readers/_geos_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,8 @@ def sampling_to_lfac_cfac(sampling):
Appendix E.2.


.. _MSG Ground Segment LRIT HRIT Mission Specific Implementation: http://www.eumetsat.int/\
website/wcm/idc/idcplg?IdcService=GET_FILE&dDocName=PDF_TEN_05057_SPE_MSG_LRIT_HRI\
&RevisionSelectionMethod=LatestReleased&Rendition=Web
.. _MSG Ground Segment LRIT HRIT Mission Specific Implementation:
https://www-cdn.eumetsat.int/files/2020-04/pdf_ten_05057_spe_msg_lrit_hri.pdf

Args:
sampling: float
Expand All @@ -166,3 +165,61 @@ def sampling_to_lfac_cfac(sampling):
Line/column scaling factor (deg-1)
"""
return 2.0 ** 16 / np.rad2deg(sampling)


def get_geos_area_naming(input_dict):
"""Get a dictionary containing formatted AreaDefinition naming.

Args:
input_dict: dict
Dictionary with keys `platform_name`, `instrument_name`, `service_name`, `service_desc`, `resolution` .
The resolution is expected in meters.
Returns:
area_naming_dict with `area_id`, `description`, `proj_id` keys, values are strings.
"""
area_naming_dict = {}

resolution_strings = get_resolution_and_unit_strings(input_dict['resolution'])

area_naming_dict['area_id'] = '{}_{}_{}_{}{}'.format(input_dict['platform_name'].lower(),
input_dict['instrument_name'].lower(),
input_dict['service_name'].lower(),
resolution_strings['value'],
resolution_strings['unit']
)

area_naming_dict['description'] = '{} {} {} area definition ' \
'with {} {} resolution'.format(input_dict['platform_name'].upper(),
input_dict['instrument_name'].upper(),
input_dict['service_desc'],
resolution_strings['value'],
resolution_strings['unit']
)

# same as area_id but without resolution. This key on the way to be deprecated
area_naming_dict['proj_id'] = '{}_{}_{}'.format(input_dict['platform_name'].lower(),
input_dict['instrument_name'].lower(),
input_dict['service_name'].lower()
)

return area_naming_dict


def get_resolution_and_unit_strings(resolution):
"""Get the resolution value and unit as strings.

If the resolution is larger than 1000 m, use kilometer as unit. If lower, use meter.

Args:
resolution: scalar
Resolution in meters.

Returns:
Dictionary with `value` and `unit` keys, values are strings.
"""
if resolution >= 1000:
return {'value': '{:.0f}'.format(resolution*1e-3),
'unit': 'km'}

return {'value': '{:.0f}'.format(resolution),
'unit': 'm'}
15 changes: 15 additions & 0 deletions satpy/readers/eum_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,18 @@ def recarray2dict(arr):
res[key] = data.squeeze()

return res


def get_service_mode(instrument_name, ssp_lon):
"""Get information about service mode for a given instrument and subsatellite longitude."""
service_modes = {'seviri': {'0.0': {'service_name': 'fes', 'service_desc': 'Full Earth Scanning service'},
'9.5': {'service_name': 'rss', 'service_desc': 'Rapid Scanning Service'},
'41.5': {'service_name': 'iodc', 'service_desc': 'Indian Ocean Data Coverage service'}
},
'fci': {'0.0': {'service_name': 'fdss', 'service_desc': 'Full Disk Scanning Service'},
'9.5': {'service_name': 'rss', 'service_desc': 'Rapid Scanning Service'},
},
}
unknown_modes = {'service_name': 'unknown', 'service_desc': 'unknown'}

return service_modes.get(instrument_name, unknown_modes).get('{:.1f}'.format(ssp_lon), unknown_modes)
18 changes: 11 additions & 7 deletions satpy/readers/fci_l1c_fdhsi.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@

from pyresample import geometry
from netCDF4 import default_fillvals
from satpy.readers._geos_area import get_geos_area_naming
from satpy.readers.eum_base import get_service_mode

from .netcdf_utils import NetCDF4FileHandler

Expand Down Expand Up @@ -337,15 +339,17 @@ def get_area_def(self, key, info=None):
'units': 'm',
"sweep": sweep}

# follow the format <platform>_<instrument>_<service>_<resolution>
area_id_name = 'mtg_fci_fdss_{:.0f}km'.format(key['resolution']/1000)
area_id_description = 'FCI Full-Disk Scanning Service area definition with {:.0f} km resolution' \
''.format(key['resolution']/1000)
area_naming_input_dict = {'platform_name': 'mtg',
'instrument_name': 'fci',
'resolution': int(key['resolution'])
}
area_naming = get_geos_area_naming({**area_naming_input_dict,
**get_service_mode('fci', lon_0)})

area = geometry.AreaDefinition(
area_id_name,
area_id_description,
"FCI Full-Disk Scanning Service geostationary projection",
area_naming['area_id'],
area_naming['description'],
area_naming['proj_id'],
proj_dict,
ncols,
nlines,
Expand Down
11 changes: 1 addition & 10 deletions satpy/readers/seviri_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

References:
MSG Level 1.5 Image Data Format Description
https://www.eumetsat.int/website/wcm/idc/idcplg?IdcService=GET_FILE&dDocName=PDF_TEN_05105_MSG_IMG_DATA&RevisionSelectionMethod=LatestReleased&Rendition=Web
https://www-cdn.eumetsat.int/files/2020-05/pdf_ten_05105_msg_img_data.pdf

"""

Expand Down Expand Up @@ -432,15 +432,6 @@ def calculate_area_extent(area_dict):
return tuple(aex)


def get_service_mode(ssp_lon):
"""Get information about whether we're dealing with data from the FES, RSS or IODC service mode."""
seviri_service_modes = {'0.0': {'name': 'FES', 'desc': 'Full Earth scanning service'},
'9.5': {'name': 'RSS', 'desc': 'Rapid scanning service'},
'41.5': {'name': 'IODC', 'desc': 'Indian Ocean data coverage service'}}

return seviri_service_modes['%.1f' % ssp_lon]


def get_padding_area(shape, dtype):
"""Create a padding area filled with no data."""
if np.issubdtype(dtype, np.floating):
Expand Down
35 changes: 19 additions & 16 deletions satpy/readers/seviri_l1b_hrit.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,13 @@
- `Conversion from radiances to reflectances for SEVIRI warm channels`_


.. _MSG Level 1.5 Image Format Description: http://www.eumetsat.int/website/wcm/idc/idcplg?IdcService=GET_FILE&dDocName=
PDF_TEN_05105_MSG_IMG_DATA&RevisionSelectionMethod=LatestReleased&Rendition=Web
.. _MSG Level 1.5 Image Format Description: https://www-cdn.eumetsat.int/files/2020-05/pdf_ten_05105_msg_img_data.pdf

.. _Radiometric Calibration of MSG SEVIRI Level 1.5 Image Data in Equivalent Spectral Blackbody Radiance:
https://www.eumetsat.int/website/wcm/idc/idcplg?IdcService=GET_FILE&dDocName=PDF_TEN_MSG_SEVIRI_RAD_CALIB&
RevisionSelectionMethod=LatestReleased&Rendition=Web
https://www-cdn.eumetsat.int/files/2020-04/pdf_ten_msg_seviri_rad_calib.pdf

.. _Conversion from radiances to reflectances for SEVIRI warm channels:
https://www.eumetsat.int/website/wcm/idc/idcplg?IdcService=GET_FILE&dDocName=PDF_MSG_SEVIRI_RAD2REFL&
RevisionSelectionMethod=LatestReleased&Rendition=Web
https://www-cdn.eumetsat.int/files/2020-04/pdf_msg_seviri_rad2refl.pdf

"""

Expand All @@ -162,7 +159,7 @@

import satpy.readers.utils as utils
from pyresample import geometry
from satpy.readers.eum_base import recarray2dict, time_cds_short
from satpy.readers.eum_base import recarray2dict, time_cds_short, get_service_mode
from satpy.readers.hrit_base import (HRITFileHandler, ancillary_text,
annotation_header, base_hdr_map,
image_data_function)
Expand All @@ -172,8 +169,7 @@
pad_data_horizontally)
from satpy.readers.seviri_l1b_native_hdr import (hrit_epilogue, hrit_prologue,
impf_configuration)
from satpy.readers._geos_area import get_area_extent, get_area_definition

from satpy.readers._geos_area import get_area_extent, get_area_definition, get_geos_area_naming

logger = logging.getLogger('hrit_msg')

Expand Down Expand Up @@ -629,13 +625,20 @@ def get_area_def(self, dsid):
else:
pdict['scandir'] = 'S2N'

area_naming_input_dict = {'platform_name': 'msg',
'instrument_name': 'seviri',
'resolution': int(dsid['resolution'])
}
area_naming = get_geos_area_naming({**area_naming_input_dict,
**get_service_mode('seviri', pdict['ssp_lon'])})

# Compute area definition for non-HRV channels:
if dsid['name'] != 'HRV':
pdict['loff'] = loff - nlines
aex = self._get_area_extent(pdict)
pdict['a_name'] = 'geosmsg'
pdict['a_desc'] = 'MSG/SEVIRI low resolution channel area'
pdict['p_id'] = 'msg_lowres'
pdict['a_name'] = area_naming['area_id']
pdict['a_desc'] = area_naming['description']
pdict['p_id'] = area_naming['proj_id']
area = get_area_definition(pdict, aex)
self.area = area
return self.area
Expand All @@ -647,8 +650,8 @@ def get_area_def(self, dsid):
* pdict['nlines'])

# Or, if we are processing HRV:
pdict['a_name'] = 'geosmsg_hrv'
pdict['p_id'] = 'msg_hires'
pdict['a_name'] = area_naming['area_id']
pdict['p_id'] = area_naming['proj_id']
bounds = self.epilogue['ImageProductionStats']['ActualL15CoverageHRV'].copy()
if self.fill_hrv:
bounds['UpperEastColumnActual'] = 1
Expand All @@ -667,15 +670,15 @@ def get_area_def(self, dsid):
pdict['nlines'] = upper_south_line
pdict['loff'] = loff - upper_south_line
pdict['coff'] = lower_coff
pdict['a_desc'] = 'MSG/SEVIRI high resolution channel, lower window'
pdict['a_desc'] = area_naming['description']
lower_area_extent = self._get_area_extent(pdict)
lower_area = get_area_definition(pdict, lower_area_extent)

# Now the upper window
pdict['nlines'] = nlines - upper_south_line
pdict['loff'] = loff - pdict['nlines'] - upper_south_line
pdict['coff'] = upper_coff
pdict['a_desc'] = 'MSG/SEVIRI high resolution channel, upper window'
pdict['a_desc'] = area_naming['description']
upper_area_extent = self._get_area_extent(pdict)
upper_area = get_area_definition(pdict, upper_area_extent)

Expand Down
24 changes: 12 additions & 12 deletions satpy/readers/seviri_l1b_native.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@
from pyresample import geometry

from satpy.readers.file_handlers import BaseFileHandler
from satpy.readers.eum_base import recarray2dict
from satpy.readers.eum_base import recarray2dict, get_service_mode
from satpy.readers.seviri_base import (SEVIRICalibrationHandler,
CHANNEL_NAMES, CALIB, SATNUM,
dec10216, VISIR_NUM_COLUMNS,
VISIR_NUM_LINES, HRV_NUM_COLUMNS, HRV_NUM_LINES,
VIS_CHANNELS, get_service_mode, pad_data_horizontally, pad_data_vertically)
VIS_CHANNELS, pad_data_horizontally, pad_data_vertically)
from satpy.readers.seviri_l1b_native_hdr import (GSDTRecords, native_header,
native_trailer)
from satpy.readers._geos_area import get_area_definition
from satpy.readers._geos_area import get_area_definition, get_geos_area_naming

logger = logging.getLogger('native_msg')

Expand Down Expand Up @@ -287,16 +287,16 @@ def get_area_def(self, dataset_id):
pdict['h'] = self.mda['projection_parameters']['h']
pdict['ssp_lon'] = self.mda['projection_parameters']['ssp_longitude']

if dataset_id['name'] == 'HRV':
res = 1.0
pdict['p_id'] = 'seviri_hrv'
else:
res = 3.0
pdict['p_id'] = 'seviri_visir'
area_naming_input_dict = {'platform_name': 'msg',
'instrument_name': 'seviri',
'resolution': int(dataset_id['resolution'])
}
area_naming = get_geos_area_naming({**area_naming_input_dict,
**get_service_mode('seviri', pdict['ssp_lon'])})

service_mode = get_service_mode(pdict['ssp_lon'])
pdict['a_name'] = 'msg_seviri_%s_%.0fkm' % (service_mode['name'], res)
pdict['a_desc'] = 'SEVIRI %s area definition with %.0f km resolution' % (service_mode['desc'], res)
pdict['a_name'] = area_naming['area_id']
pdict['a_desc'] = area_naming['description']
pdict['p_id'] = area_naming['proj_id']

area_extent = self.get_area_extent(dataset_id)
areas = list()
Expand Down
30 changes: 18 additions & 12 deletions satpy/readers/seviri_l1b_nc.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,24 @@
function.

References:

- `MSG Level 1.5 Image Data Format Description`_
- `Conversion from radiances to reflectances for SEVIRI warm channels`_

.. _MSG Level 1.5 Image Data Format Description:
https://www.eumetsat.int/website/wcm/idc/idcplg?IdcService=GET_FILE&dDocName=PDF_TEN_05105_MSG_IMG_DATA&
RevisionSelectionMethod=LatestReleased&Rendition=Web
https://www-cdn.eumetsat.int/files/2020-05/pdf_ten_05105_msg_img_data.pdf

.. _Conversion from radiances to reflectances for SEVIRI warm channels:
https://www.eumetsat.int/website/wcm/idc/idcplg?IdcService=GET_FILE&dDocName=PDF_MSG_SEVIRI_RAD2REFL&
RevisionSelectionMethod=LatestReleased&Rendition=Web
https://www-cdn.eumetsat.int/files/2020-04/pdf_msg_seviri_rad2refl.pdf

"""

from satpy.readers.file_handlers import BaseFileHandler
from satpy.readers.seviri_base import (SEVIRICalibrationHandler,
CHANNEL_NAMES, CALIB, SATNUM)
from satpy.readers.eum_base import get_service_mode
import xarray as xr

from satpy.readers._geos_area import get_area_definition
from satpy.readers._geos_area import get_area_definition, get_geos_area_naming
from satpy import CHUNK_SIZE

import datetime
Expand Down Expand Up @@ -178,18 +177,25 @@ def get_area_def(self, dataset_id):
pdict['h'] = self.mda['projection_parameters']['h']
pdict['ssp_lon'] = self.mda['projection_parameters']['ssp_longitude']

area_naming_input_dict = {'platform_name': 'msg',
'instrument_name': 'seviri',
'resolution': int(dataset_id['resolution'])
}
area_naming = get_geos_area_naming({**area_naming_input_dict,
**get_service_mode('seviri', pdict['ssp_lon'])})

if dataset_id['name'] == 'HRV':
pdict['nlines'] = self.mda['hrv_number_of_lines']
pdict['ncols'] = self.mda['hrv_number_of_columns']
pdict['a_name'] = 'geosmsg_hrv'
pdict['a_desc'] = 'MSG/SEVIRI high resolution channel area'
pdict['p_id'] = 'msg_hires'
pdict['a_name'] = area_naming['area_id']
pdict['a_desc'] = area_naming['description']
pdict['p_id'] = area_naming['proj_id']
else:
pdict['nlines'] = self.mda['number_of_lines']
pdict['ncols'] = self.mda['number_of_columns']
pdict['a_name'] = 'geosmsg'
pdict['a_desc'] = 'MSG/SEVIRI low resolution channel area'
pdict['p_id'] = 'msg_lowres'
pdict['a_name'] = area_naming['area_id']
pdict['a_desc'] = area_naming['description']
pdict['p_id'] = area_naming['proj_id']

area = get_area_definition(pdict, self.get_area_extent(dataset_id))

Expand Down