-
Notifications
You must be signed in to change notification settings - Fork 27
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
Enable convertSphericalToCartesian to handle latitudes across poles #68
Enable convertSphericalToCartesian to handle latitudes across poles #68
Conversation
@wdeconinck, pinging you as requested. |
I think this is a great development, thanks @fmahebert . Indeed for some numerics in Atlas, there can be stencil points that are placed "across the pole". Regarding the boolean flag, I would remove it, as well as the exception throwing. |
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## develop #68 +/- ##
===========================================
- Coverage 62.53% 62.51% -0.02%
===========================================
Files 777 777
Lines 44012 44067 +55
===========================================
+ Hits 27523 27550 +27
- Misses 16489 16517 +28
... and 2 files with indirect coverage changes Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report in Codecov by Sentry. |
Done. The second commit halfway undoes the first commit, so this'll be easier to review as a total diff. |
For increased safety, I could handle cases where latitudes are outside [-270,270] ("across two poles") either by throwing an exception or by generalizing the normalization a bit more. Opinions on this? |
That would be even more robust yes, preferably by generalising normalisation more. |
I've made the normalisation of the latitudes more robust and added a new test case. I think I'm satisfied, let me know what you think. |
src/eckit/geometry/Sphere.cc
Outdated
const auto& normalise_latitude = normalise_longitude; | ||
const bool lat_across_pole = (normalise_latitude(Alonlat[1], -90.) > 90.); | ||
|
||
const double lambda_deg = normalise_longitude(Alonlat[0] + (lat_across_pole ? 180. : 0.), -180.); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi - Maybe I am missing something but I can't quite see how you are dealing with the South Pole.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const bool lat_across_pole = (normalise_latitude(Alonlat[1], -90.) > 90.);
does not apply normalisation to the used latitude. It just checks if values are between -90 and +90.
normalise_latitude(Alonlat[1], -90.)
-> always value between -90. and 270.
So I'm wondering, how is this different from
const bool lat_across_pole=(Alonlat[1] > 90. || Alonlat[1] < -90.);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the input latitude has sufficiently large values that it "wraps around the poles" a few times, then the two are different. This is because a point can have very large latitudes but still be in the same hemisphere. As an extreme example, consider (lon,lat) = (x,370)
; this point is also (x,10)
, in the same hemisphere, and the coordinates can be "fixed" without needing to shift the longitude to x+180
.
In this example...
(Alonlat[1] > 90. || Alonlat[1] < -90.)
would evaluate to true, even though we do not want to shift the longitude valuenormalise_latitude(Alonlat[1], -90.)
returns 10, which is in [-90,90], consistent with not editing the longitude
Does that help? Or have I missed something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MarekWlasak the statement normalise_latitude(Alonlat[1], -90.)
means that points "below the south pole" are re-labeled with a latitude "above the north pole"... e.g. lat=-100 --> lat=260
. Using the normalise_latitude
function avoids writing complicated branching to achieve the desired behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I need to write more documentation? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fmahebert - I see ... but that creates a discontinuity at the pole. I am not too fussed provided it does not break existing atlas functionality (e.g with structuredcolumns).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MarekWlasak can you clarify what discontinuity you're referring to? This is just choosing a consistent "branch cut" of the periodic coordinates before converting to cartesian coordinates... I don't expect anything will be discontinuous in the output space...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fmahebert - I was misunderstanding the use case. All is well.
I would like @pmaciel to review this as this may have impact to https://github.com/ecmwf/mir |
Hi @MarekWlasak, this is a very welcome change, because it addresses a fundamental issue on the assumptions regarding spherical coordinates: that we normalise the longitude, but not the latitude -- asserting that latitudes are within [-90, 90]. Let me add that this is an improvement, definitely. I have recently written very similar code to handle exactly this case (for a different project, this code returns normalised coordinates):
`
Whichever direction we do, this can be brought in quite quickly, as this code is really well tested. So discussion should take place first. |
@pmaciel Thanks for your feedback. I'll be happy to address (2), if the conclusion after discussing (1) is to proceed. |
@pmaciel @wdeconinck Is there any update on whether item (1) is satisfactory? I don't want to put in the work for (2) if the PR will be rejected, but if doing (2) would help acceptance, I can do it now, just let me know... |
Hi @fmahebert, sorry to not get back sooner. We decided to proceed with (1), ie. remove these assertions and apply similar changes to the remainder of the code. The other classes/method I listed is not comprehensive, but sufficient for this PR, could you please do these too? I suggest to rename normalise_longitude to normalise_angle (and remove normalise_latitude). |
367690a
to
9ec49f1
Compare
@pmaciel Thanks! I've added 3 commits that make the same change to methods I've also added a 4th commit that pulls all this common logic into a helper function — this may be a tad less efficient (a few more computations and stack variables), but should be easier to maintain. Up to you if you want this commit, if not I'll revert it. |
Hi @fmahebert , @ytremolet, sorry for the late reply. Yes, for me this is done -- thank you for the contribution. I'm currently working on additional functionality that will supercede this (it will include a PointLonLat type, similar to Atlas/MIR) but in the meantime this is a great addition. We will follow this with changes downstream to protect against wrongly calculated latitudes. |
@fmahebert please note, recently a PR was merged into the develop brach moving the code base to C++17 (as a minimum requirement). This is planned for a release soon. Can you please rebase your PR to an updated develop tree? Thanks! (sorry for the extra work!) |
9ec49f1
to
03347f5
Compare
@pmaciel I've rebased; please let me know if there's anything else. Your described future developments on this front sound good too :) |
…riate (API change, to preserve operational behaviour), ./format-sources.sh, cleanup
From internal discussions, so that we can smoothly transition the behaviour, I've added an extra argument (bool normalise_angle = false) where appropriate. This is an API change, to make optional the assertion -90<=lat<=90 (which is still the default ebhaviour), so you might need minor adaptations. I've made the necesary changes, including updating the new unit tests. @fmahebert the changes we're proposing are pending your approval. |
Feature/normalise lats across poles
@pmaciel Sorry for the slower response this time; I've merged your commit and added a tiny test fix as well. |
For what I can see there is a missing test for the assert / throw, when normalise_angle = false, ie. EXPECT_THROWS(...) |
Added some new test statements for the throw |
I am getting a compile failure with this: /home/d03/frwd/cylc-run/eckit-68/share/mo-bundle/eckit/tests/geometry/test_polygon.cc:388:0: error: unterminated argument list invoking macro "EXPECT_THROWS_AS" /home/d03/frwd/cylc-run/eckit-68/share/mo-bundle/eckit/tests/geometry/test_polygon.cc: In function 'void eckit::test::test_88(std::__cxx11::string&, int&, int)': This is with gnu 7.3.0. |
As per error message "unterminated argument list", there is a parenthesis missing to be closed. |
... serves me right for pushing an "easy" fix without compiling! 🙃 Fixed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks ok now
Thanks @pmaciel @tlmquintino and @wdeconinck for iterating on this! |
@tlmquintino, @simondsmart, please could we create a tagged release with this API change, so I can ensure this API exists in Atlas with a version check? |
…oles Enable convertSphericalToCartesian to handle latitudes across poles
@wdeconinck just released with tag 1.24.0 |
The atlas library generates points with latitudes outside the usual [-90°, 90°] interval, for example halo points on a regular Gaussian grid. Passing these points through eckit's
convertSphericalToCartesian
throws an exception because the code expects latitudes within the usual interval.This PR preserves the current default behavior, but adds the option to renormalise points with latitudes "across the pole".
(I'd be happy to update the PR to remove the bool and always apply the renormalisation, if that is the preferred behavior. This would enable the change to propagate transparently to atlas without adding the bool, but would affect users who relied on the exception for points outside [-90,90]).