-
Notifications
You must be signed in to change notification settings - Fork 42
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
Parallel transport generic vector interpolation method. #163
Parallel transport generic vector interpolation method. #163
Conversation
make_view calls erroneously in loop body.
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## develop #163 +/- ##
===========================================
+ Coverage 79.92% 80.02% +0.10%
===========================================
Files 853 857 +4
Lines 63199 63498 +299
===========================================
+ Hits 50511 50817 +306
+ Misses 12688 12681 -7 ☔ View full report in Codecov by Sentry. |
Your updates to exclusively rely on Eigen is potentially problematic.
|
Thanks, @wdeconinck, I've replaced the optional compilation with pre-processor macros in relevant files. It builds and runs properly on my system with I did some digging in the current eckit sparse matrix. It does indeed prune out zero-valued triples (see here). This means all the real, imaginary and magnitude matrices can have different sparsity. The simplest in-code solution was to use Eigen directly. Minimal code changes would be required if the current eckit I'm going to open an issue which details what I think are the to-do items (hopefully) for follow-up PRs. |
That does seem like a sensible optimisation, but prevents us from fusing the two loops indeed, and then Eigen matrix solution is appropriate. |
Its probably worth pointing out, I could fuse the the horizontal and vertical component loops, at the expense of adding some more complicated code. |
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.
It was still good to have it in this file, but not guarded by #if ATLAS_HAVE_EIGEN
if that makes sense.
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.
I can see that it adds unnecessary marcro mess. I'm just marvelling at how the factories can register at run time instead of compile time!
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.
What I meant is what I added to your branch with a96057e
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.
Ah! That looks far safer!
… Write test for 3-vector field (note: this works when hacking current 2-vector test).
added tests for 3-vector and 2 vector fields.
Nice cleanup. |
Yeah, I just saw. What's confusing is that all the GitHub Actions pass on the JCSDA-internal fork end. I guess I've got two options:
What would you suggest? |
It's certainly worth a try. Should at least help diagnose the problem! 😊 |
#define atlas_omp_parallel_for for | ||
#endif | ||
#endif | ||
|
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.
Thanks, @wdeconinck. Hit it with macros until the problem goes away! ❤
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.
The problem indeed went away 😃
const auto sourceVector = Complex(sourceVars(0), sourceVars(1)); | ||
const auto targetVector = complexWeight * sourceVector; | ||
targetVars(0) += targetVector.real(); | ||
targetVars(1) += targetVector.imag(); |
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.
Without going into the detailed maths, why do you have to
targetView.assign(0)
and then use +=
for the targetVars ? Can this not be replaced with just =
?
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.
Never mind, I understand, due to the matrix multiply internally.
But perhaps performance can be gained if the assign(0)
could be removed and done inside the matrixMultiply
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.
It's because each target element (named targetVars
here) has a contribution from multiple source elements (sourceVars
). If I changed +=
to =
, it would set the target element to the last source element on that row of the matrix.
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.
I could do the assign(0.)
within matrixMultiply
function, but it would have to be on the first line, and therefore be the equivalent operation as it currently is. The SparseMatrixForEach
is the only function that has knowledge of i
as a whole row, but it doesn't know what functor
is doing (it's used in a couple of different contexts).
I suspect details like this will have to be refactored to remove code duplication when the adjoint methods are added. In that context, you don't assign zero to the array you're writing to.
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.
OK it can stay as-is. We should not attempt premature optimisation now.
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 @odlomax,
as discussed this is a great contribution! As you see, I've only commented on technical details, because it looks like everything is well thought of. I admit, I think there is a bit overuse of templates to pass functors (when we really only handle the real and complex cases), but it is certainly not an important concern at the moment.
I've already put the "course" method as part of a revised eckit geometry library. I look forward to have ready the more flexible sparse matrix container and the sparse linear algebra backend too, as we discussed. It will happen in the coming months, and will also simplify much of the workarounds you had to painfuly go through.
I'm already aproving the PR -- this is ready to merge!
src/atlas/interpolation/method/sphericalvector/SphericalVector.h
Outdated
Show resolved
Hide resolved
src/atlas/interpolation/method/sphericalvector/SphericalVector.h
Outdated
Show resolved
Hide resolved
src/atlas/interpolation/method/sphericalvector/SphericalVector.cc
Outdated
Show resolved
Hide resolved
src/atlas/interpolation/method/sphericalvector/SphericalVector.cc
Outdated
Show resolved
Hide resolved
src/atlas/interpolation/method/sphericalvector/SphericalVector.cc
Outdated
Show resolved
Hide resolved
src/atlas/interpolation/method/sphericalvector/SphericalVector.cc
Outdated
Show resolved
Hide resolved
return; | ||
} | ||
|
||
ATLAS_ASSERT_MSG(sourceField.variables() == 2 || sourceField.variables() == 3, |
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.
Shouldn't this assertion come right at the beggining of the method?
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.
I'd also have to check that the field was a vector type. By this point in the function, it definitely is.
Thanks, @pmaciel, @wdeconinck, I had a lot of fun with this one. I freely admit I'm a template addict. If only we had C++ 20, I could at least throw a few concepts on them! I need to follow this up with an implementation of the adjoint methods. Shall I push @pmaciel's suggested changes to this PR, or the next one? |
Since they're only technical would prefer that it's merged with the suggested changes :-) |
…-internal/atlas into feature/parallel_transport
It is done! Thanks, @pmaciel 🙂 |
Thanks @odlomax for addressing further review. I will merge today when all tests have passed. This will be super useful. |
Again, thanks @wdeconinck and @pmaciel. Always a pleasure. |
Hi @wdeconinck,
I'm experimenting with a new method I've cooked up to perform geometry-agnostic vector interpolation. Essentially, it works out the angular difference between North and a great-circle arc connecting a source and a target point, then rotates the source field vector to match the target field vector.
The upshot of this is that we require
four interpolation matrices instead of the usual onecomplex interpolation weights, but the results look promising. I've experimented below, interpolating from a CS-LFR-48 to an O48 (the interpolation method knows nothing about the cubed-sphere).Here are some figures showing the results so far:
Fig 1: Eastward component of test field on CS-LFR-48 grid
Fig 2: Northward component of test field on CS-LFR-48 grid
Fig 3: Interpolation error when mapped on to O48 gird. Vector field components treated as independent scalars.
Fig 4: Interpolation error when mapped on to O48 gird. Source vectors rotated to match target vectors.
tl;dr I've made the error of interpolating winds over the poles go away, and I believe it will work for all matrix-based interpolation methods.
I'll try and get it finished up over the next week or so.