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

Add combined GRIB reader for both SEVIRI and FCI L2 products #2717

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

dnaviap
Copy link

@dnaviap dnaviap commented Jan 11, 2024

Add combined GRIB reader that can be used for both SEVIRI and FCI L2 products.

  • Tests added
  • Fully documented
  • Add @dnaviap to AUTHORS.md

@strandgren
Copy link
Collaborator

Thanks for working on this @dnaviap :) Before reviewing in more detail, I think we need some refactoring of the files:

  1. Instead of having a eum_l2_grib.yaml files I suggest to keep the seviri_l2_grib.yaml file (which is still there) and add the FCI cloud mask dataset in a new fci_l2_grib.yaml file. That way we don't change the user interface to the reader. That's also how it's being done for the BUFR reader (Changes to Eumetsat L2 BUFR reader #2603)
  2. eum_l2_grib.py should be compatible with both FCI and SEVIRI data, meaning that seviri_l2_grib.py should become obsolete and should therefore be removed.
  3. Similarly, the new test file test_eum_l2_grib.py should make test_seviri_l2_grib.py obsolete, meaning it can be removed as well.

@dnaviap
Copy link
Author

dnaviap commented Jan 12, 2024

The refactoring is complete and tested.

Copy link
Collaborator

@strandgren strandgren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the refactoring! :) See a couple of comments inline.

Can you please also modify the doc-string of the _scale_earth_axis method to read:

    def _scale_earth_axis(data):
        """Scale Earth axis data to make sure the value matched the expected unit [m].
        
        The earthMinorAxis value stored in the MPEF aerosol over sea product prior to December 12, 2022 has the wrong unit and this method provides a flexible work-around by making sure that all earth axis values are scaled such
        that they are on the order of millions of meters as expected by the reader. 
        
        """

That was a fix implemented by me a while ago when we noticed some issues in one of the products, and although it has been fixed in the product, the archived files will still have the issue meaning that the fix is still useful to have in the reader.

@@ -62,14 +75,23 @@ def start_time(self):
@property
def end_time(self):
"""Return the sensing end time."""
return self.start_time + timedelta(minutes=REPEAT_CYCLE_DURATION)
if self.sensor == "seviri":
return self.start_time + timedelta(minutes=REPEAT_CYCLE_DURATION)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct for RSS data where the temporal resolution is 5min. Could you add REPEAT_CYCLE_DURATION_RSS = 5 in seviri_base.py and then use the sub-satellite longitude to determine the end_time, ie.e. something like this?

delta = REPEAT_CYCLE_DURATION_RSS if self._ssp_lon == 9.5 else REPEAT_CYCLE_DURATION
return self.start_time + delta

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved

def calculate_area_extent(area_dict):
"""Calculate the area extent seen by MTG FCI instrument.

Since the center of the FCI L2 grid is located at the interface between the pixels, there are equally many
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FCI L2 grid --> FCI grids

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved

FAKE_GID = [0, 1, 2, 3, None]


class Test_EUML2GribFileHandler(unittest.TestCase):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's quite a lot of duplicate code for the SEVIRI and FCI tests, can you please have a look and see if this can be refactored and optimized a bit?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the duplicated code to a common method, please check if it is necessary to do something else

@dnaviap
Copy link
Author

dnaviap commented May 13, 2024

Thanks for the refactoring! :) See a couple of comments inline.

Can you please also modify the doc-string of the _scale_earth_axis method to read:

    def _scale_earth_axis(data):
        """Scale Earth axis data to make sure the value matched the expected unit [m].
        
        The earthMinorAxis value stored in the MPEF aerosol over sea product prior to December 12, 2022 has the wrong unit and this method provides a flexible work-around by making sure that all earth axis values are scaled such
        that they are on the order of millions of meters as expected by the reader. 
        
        """

That was a fix implemented by me a while ago when we noticed some issues in one of the products, and although it has been fixed in the product, the archived files will still have the issue meaning that the fix is still useful to have in the reader.

@dnaviap dnaviap closed this May 13, 2024
@dnaviap dnaviap reopened this May 13, 2024
Copy link
Collaborator

@strandgren strandgren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes and the refactoring @dnaviap!

I left a couple of minor comments in-line. Could you please also merge the main branch into this branch and resolve the merge conflict such that all unit tests etc. run?

if self.sensor == "seviri":
return self.start_time + timedelta(minutes=REPEAT_CYCLE_DURATION)
elif self.sensor == "fci":
return self.filename_info["end_time"]
delta = REPEAT_CYCLE_DURATION_RSS if self._ssp_lon == 9.5 else REPEAT_CYCLE_DURATION
return self.start_time + delta
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My comment only considered SEVIRI, since for SEVIRI we have a nominal repeat cycle duration of 15 minutes for FES and 5 minutes for RSS. For FCI, however, it's 10minutes. I also think we need to convert the imported integers to datetime.timedela objects? So we should have something like this instead:

if self.sensor == "seviri":
        delta = REPEAT_CYCLE_DURATION_RSS if self._ssp_lon == 9.5 else REPEAT_CYCLE_DURATION
        return self.start_time + timedelta(minutes=delta)
elif self.sensor == "fci":
        return self.filename_info["end_time"]

@@ -33,7 +32,7 @@
from satpy.readers.eum_base import get_service_mode
from satpy.readers.fci_base import calculate_area_extent as fci_calculate_area_extent
from satpy.readers.file_handlers import BaseFileHandler
from satpy.readers.seviri_base import PLATFORM_DICT, REPEAT_CYCLE_DURATION
from satpy.readers.seviri_base import PLATFORM_DICT, REPEAT_CYCLE_DURATION, REPEAT_CYCLE_DURATION_RSS
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid confusion (see e.g. comment below), perhaps rename the variables to make clear that these are SEVIRI variables:

from satpy.readers.seviri_base import (
    PLATFORM_DICT as SEVIRI_PLATFORM_DICT,
    REPEAT_CYCLE_DURATION as SEVIRI_REPEAT_CYCLE_DURATION,
    REPEAT_CYCLE_DURATION_RSS as SEVIRI_REPEAT_CYCLE_DURATION_RSS
)

# Checks that codes_release has been called after each codes_grib_new_from_file call
# (except after the last one which has returned a None)
assert self.ec_.codes_grib_new_from_file.call_count == self.ec_.codes_release.call_count + 1
self.common_checks(mock_file, dataset_id)

# Checks the basic data reading
assert REPEAT_CYCLE_DURATION == 15
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we really need this assert? It's just a constant imported from eum_base.py, and now we also have REPEAT_CYCLE_DURATION_RSS. Perhaps rather verify the start_time and end_time, which would be more useful.

In this case we have ssp_lon=9.5, so start_time should be 2019-10-20 17:45 and end_time 2019-10-20 17:50` as far as I can tell from the fake message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants