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

Use native iris functions in multi-model statistics #1150

Merged
merged 11 commits into from
Jun 7, 2021
Merged

Conversation

Peter9192
Copy link
Contributor

@Peter9192 Peter9192 commented May 28, 2021

Description

Split off from #968 to separate the lazy and eager evaluation pathways.

This PR re-implements the multi-model statistics preprocessor. This implementation delegates more of the work to native iris functions. This enables, among others, lazy evaluation for some common operators. The actual implementation of that lazy pathway is implemented in #968.

Related to #781


Checklist

It is the responsibility of the author to make sure the pull request is ready to review. The icons indicate whether the item will be subject to the 🛠 Technical or 🧪 Scientific review.


To help with the number pull requests:

@Peter9192 Peter9192 changed the title Eager mmstats Use native iris functions in multi-model statistics May 28, 2021
@Peter9192
Copy link
Contributor Author

@zklaus as promised I've split off the refactoring from the lazy multi-model stats.
@valeriupredoi perhaps you can have a quick look at this, since you've already seen all these changes in #968?

There's 2 regression tests failing now with some annoying rounding errors due to numpy changing the dtype on masked data. If you agree I'll re-generate the reference data for the regression tests so we get green lights from CircleCI.

@Peter9192 Peter9192 marked this pull request as ready for review May 28, 2021 15:29
@bouweandela bouweandela added this to the v2.3.0 milestone May 28, 2021
@bouweandela
Copy link
Member

There's 2 regression tests failing now with some annoying rounding errors due to numpy changing the dtype on masked data. If you agree I'll re-generate the reference data for the regression tests so we get green lights from CircleCI.

Masks are stored as fill values in netcdf files, so it seems unlikely that regenerating the reference data will change the data type of the resulting masks.

@Peter9192
Copy link
Contributor Author

There's 2 regression tests failing now with some annoying rounding errors due to numpy changing the dtype on masked data. If you agree I'll re-generate the reference data for the regression tests so we get green lights from CircleCI.

Masks are stored as fill values in netcdf files, so it seems unlikely that regenerating the reference data will change the data type of the resulting masks.

The point is that whenever the input data is a masked array, (even if mask is set to false everywhere) iris.analysis.MEAN will call np.ma.mean, and this one changes the dtype on the data (so also where it's not masked). This is what causes the precision error.

@valeriupredoi
Copy link
Contributor

cheers @Peter9192 - thanks to @bouweandela nudging me, I am now looking at this 🍺

Copy link
Contributor

@valeriupredoi valeriupredoi left a comment

Choose a reason for hiding this comment

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

very nice implementation @Peter9192 - I left a few comments here and there, not anything serious. I'll have a look at the CI tests now then approve 👍

esmvalcore/preprocessor/_multimodel.py Outdated Show resolved Hide resolved
esmvalcore/preprocessor/_multimodel.py Show resolved Hide resolved
esmvalcore/preprocessor/_multimodel.py Show resolved Hide resolved
esmvalcore/preprocessor/_multimodel.py Outdated Show resolved Hide resolved
esmvalcore/preprocessor/_multimodel.py Outdated Show resolved Hide resolved

result_slices.append(collapsed_slice)

result_cube = iris.cube.CubeList(result_slices).merge_cube()
Copy link
Contributor

Choose a reason for hiding this comment

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

can this fail now? or we've already processed those cubes to a point where it will never fail

Copy link
Contributor Author

@Peter9192 Peter9192 Jun 7, 2021

Choose a reason for hiding this comment

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

I would say it shouldn't, but apparently it can fail indeed. E.g. if you calculate the mean of integer arrays [1, 2] and [3, 3] one index at a time, you'll end up concatenating int(2) and float(2.5), which fails. Normally all input should be dtype float32 and if dtype is preserved in the calculations, that shoudn't happen.

We already correct for this by explicity casting astype, but just in case, I'll add a try/except clause here as well, with a nice message.

esmvalcore/preprocessor/_multimodel.py Outdated Show resolved Hide resolved
@valeriupredoi
Copy link
Contributor

ah gotcha - so the tests fail coz of the same issue I pointed out in the code, time points are not quite equal, tests can be fixed by upping the rtol and I'd do the same in the code too, use allclose with some higher rtol but maybe not 1 coz that's be they really are different 😁

Copy link
Contributor

@valeriupredoi valeriupredoi left a comment

Choose a reason for hiding this comment

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

pre-emptive approval, but please fix the 2 tests and have a look at me comments too. Apart from that - really nice work! 👍

@Peter9192
Copy link
Contributor Author

Thanks for the review V, I'm on it

@Peter9192
Copy link
Contributor Author

I think I covered all your comments @valeriupredoi. It's just those 2 regression tests that keep failing with precision errors. As I said before, I think we should just regenerate the sample data and merge. I don't think an unsurprising 0.00001% difference in a test result is worth our time and effort.

@Peter9192
Copy link
Contributor Author

@zklaus @valeriupredoi Note that I just regenerated the sample data for the failing tests. They both reported a
Max relative difference: 2.4267516e-07 which is almost certainly due to a back and forth conversion to dtype float64 that's introduced because we switched from explicitly allocating the output array to having iris generate it for us.

If you agree that's okay, this PR can be merged. Otherwise, feel free to suggest/commit a different solution.

@zklaus zklaus added enhancement New feature or request preprocessor Related to the preprocessor labels Jun 7, 2021
@zklaus
Copy link

zklaus commented Jun 7, 2021

Thanks, I am happy with this. Could you just make a quick pass through the checklist, tick the things that are present, and strike out those you deem inapplicable? I started with this, but wanted explicit confirmation from you on backwards compatibility and potential changes in dependencies.

@valeriupredoi
Copy link
Contributor

excellent work, Peter! Yes, let's get this in - I'd like to carry on the discussion about (almost) equal time (and not only) coords - but defo not here, and in a different issue 🍺

@Peter9192
Copy link
Contributor Author

@zklaus done, there's no changes to the user interface, and while scipy is removed as a direct dependency for mm-stats, it's still used in many other places in the code, so I think we're good there 👍

@axel-lauer
Copy link
Contributor

We already discussed the problem introduced with too strict iris checks when averaging near-surface air temperature 'tas' as it is reported by some models at 1.5 m, by other models at 2.0 m. From the scientific point of view, regarding this as an error makes no sense as @ruthlorenz nicely explained at our last monthly meeting. Here is another example why these iris checks can be too strict and yet not useful from a scientific point of view:

Variables on hybrid vertical levels (e.g. clw) have to be converted to pressure or height levels to be processed by most diagnostics. For this conversion, some models provide an auxiliary coordinate 'p0'. Calculating the multi-model mean over such datasets converted to pressure or height levels fails because "p0" is kept after converting the vertical levels but (as expected) not identical in all models. p0 contains no useful information any more after vertical coordinate transformation has been done. Yet, this results in a failure to calculate the multi-model mean over such 3-dim variables (e.g. 3-dim cloud variables).

@Peter9192
Copy link
Contributor Author

@axel-lauer Is this the same issue as described in #1213 and addressed in #1220?

@zklaus
Copy link

zklaus commented Jul 12, 2021

The tas issue is discussed at ESMValGroup/ESMValTool#2218 (comment) and #1204. Turns out there never was a problem; it was just a misdiagnosis.

I think the vertical levels are a different issue. @axel-lauer, could you please open a new issue for that, including the failing recipe, and perhaps also add it to ESMValGroup/ESMValTool#2218?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request preprocessor Related to the preprocessor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants