-
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
implement a procedure to carry out a regridding from high to low resolution (binning) #191
implement a procedure to carry out a regridding from high to low resolution (binning) #191
Conversation
@wdeconinck , @odlomax This PR covers the implementation of the regridding procedure (from high to low resolution). |
Thanks, @mo-lormi Could you add some of the outputs to this PR so we can easily have a look? |
This looks very nice! I am curious as a bystander why you haven't used the interpolation elements. Perhaps if you had it would have worked for any grid? https://github.com/ecmwf/atlas/blob/develop/src/atlas/interpolation/element/Quad2D.h Maybe out of scope though! |
I carried out further testing. The procedure also works for a different type of grid (function space: StructuredColumns). The following plots refer to two fields:
(note -- It seems that a set of contiguous cells is missing in both plots. Thus, further investigation is needed) |
@mo-lormi concerning the "missing" part in the Gmsh plot, is nothing to worry about. That's because the StructuredColumns fields are unlike NodeColumns and don't have extra duplicated nodes at 360 degrees. |
@wdeconinck thanks for this info ... To take into account this point, I will need to update the procedure. |
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.
Thank you and sorry for the delayed review. Please see my in-code comments.
inline idx_t N() const { return N_; } | ||
|
||
// Return the areas of the faces/cells | ||
Field gridCellArea(const FunctionSpace&) const; |
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.
In order to encapsulate as much as possible the grid from objects like Field, FunctionSpace, Mesh,
I would avoid this function.
Possibly you could create a different function
double CubedSphere::gridCellArea(idx_t index);
The grid itself should have all possible information needed to compute just a single cell value.
Then where needed fill a container such as std::vector
or atlas::Field
or ...
But in this case here, I think you could just compute the cellArea within the loop where you compute the weights, avoiding the entire allocation of a container.
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.
@wdeconinck ... good point. However, there is reason why the method CubedSphere::gridCellArea()
has been designed and implemented in this way.
So far, at the MO, we have identified at least two workflow steps where this function is needed: one is the evaluation of the area weights matrix within the interpolation/binning procedure (this PR); the other one is the evaluation of the Jc term, a penalty term associated with the gravity wave constraints for the cost function.
Thus, we thought that having a function signature for CubedSphere::gridCellArea()
based on the FunctionSpace
data type could make it general enough to be used in different contexts.
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 managed to boil this down to this standalone function, independent of functionspace
// Area around nodes of cubed sphere mesh
Field CubedSphereNodalArea(const Mesh& mesh) {
constexpr auto deg2rad = M_PI / 180.;
const auto& proj = mesh.projection();
auto lonlat = array::make_view<double, 2>(mesh.nodes().lonlat());
auto gcell_area_field = Field("grid_cell_areas", make_datatype<double>(), array::make_shape(mesh.nodes().size()));
auto gcell_area_fview = array::make_view<double, 1>(gcell_area_field);
double gcell_area_cs = [&] {
/******* CUBED_SPHERE SPECIFIC *********/
// (grid_res * grid_res) = no. of cells on a tile
ATLAS_ASSERT(CubedSphereGrid(mesh.grid()));
auto grid_res = CubedSphereGrid(mesh.grid()).N();
// area of a grid cell (cubed-sphere coord. system)
return M_PI/(2*grid_res) * M_PI/(2*grid_res);
}();
for (size_t i = 0; i < gcell_area_fview.size(); i++) {
PointLonLat loc = PointLonLat(lonlat(i, atlas::LON), lonlat(i, atlas::LAT));
double cos_lat = std::cos(deg2rad * loc.lat());
double grid_jac_det = 1/proj.jacobian(loc).determinant();
// area of a grid cell (geographic coord. system)
gcell_area_fview(i) = grid_jac_det * gcell_area_cs * cos_lat ; /****** USE gcell_area_cs here ******/
}
return gcell_area_field;
}
Possibly with more thought this could be made even more independent of CubedSphere.
What happens to the Binning procedure if the combination does not happen to be "grid == CubedSphere && functionspace == NodeColumns" ?
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.
@wdeconinck ... thanks for this.
Where do you think this function should be stored? In which file, class,...?
If you tell me where I should define the function, I will do a test with it. Thanks ...
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 could be a mesh-action, similar to https://github.com/ecmwf/atlas/blob/develop/src/atlas/mesh/actions/BuildCellCentres.h
So putting it parallel to this file, and following its design is a good idea.
You can then "register" this field within the mesh.nodes() and could be reused later.
What happens to the Binning procedure if the combination does not happen to be "grid == CubedSphere && functionspace == NodeColumns" ?
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.
functionspace == NodeColumns
The binning procedure works also for "functionspace == StructuredColumns" (grid type: "O").
I implemented a test to check this scenario, see here.
@wdeconinck thanks again for the comments and suggestions. |
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 so much for this contribution and addressing all my suggestions. 🙏
@wdeconinck thanks again. |
This will be released in 0.38.0 some time this week. |
* release/0.38.0: (47 commits) Update Changelog Version 0.38.0 implement a procedure to carry out a regridding from high to low resolution (binning) (#191) Fixes opposite pole coordinates (#202) Avoid silent errors accessing Fieldset fields by ambiguous names (#210) Made sure cubed-sphere interpolation method always sets metadata. (#208) Add fortran interface for node-to-edge connectivity building (#209) Removed redundant headers. Fixed SphericalVector. Fixed StructuredInterpolation2D. Added failing tests. Update ci.yml to fix notification (#207) Add notifications to github workflows Remove float in Triag2D intersection algorithm (#203) Fixup: use C++17 uncaught_exceptions (extra s in exceptions) Disable logging of ATLAS_TRACE during stack unwinding (e.g. when exception is thrown) Add GPU offloading capability with OpenACC support to Native WrappedDataStore Add C++ OpenACC test for some sanity Refactor OpenACC support and implement for Native arrays Enable use of CUDA for Native arrays ...
Description
This PR is intended to extend the group of the interpolation operations, in particular to:
Rigridding from high to low resolution via binning ...
method: binning
binning matrix: B = N A^T W
area weights matrix: W
interpolation matrix: A
normalization factor matrix: N
Acceptance Criteria (Definition of Done)
All the tests pass.