-
Notifications
You must be signed in to change notification settings - Fork 43
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
Merged
wdeconinck
merged 29 commits into
ecmwf:develop
from
JCSDA-internal:feature/interpolation_binning_01
Jun 17, 2024
Merged
Changes from 12 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
236ed1f
implemented a procedure to evaluate the areas of the grid cell (grid …
mo-lormi 83beabe
implemented a procedure to carry out a regridding from high to low re…
mo-lormi 08a2f06
added test for the regridding procedure (high to low resolution)
mo-lormi 7f3705a
updated build procedure
mo-lormi 87312a5
update 03.05.24-01
mo-lormi 3f1fdfd
updated build procedure
mo-lormi 475e9f0
added check to identify and ignore an empty row
mo-lormi dbf3bea
updated setup procedure for the method 'binning'
mo-lormi 41c8e4c
update 10.05.24-01
mo-lormi 15f92a4
added flag to control the adjoint operation
mo-lormi 0f97c05
added tests to battery of tests
mo-lormi a05b292
update 10.05.24-02
mo-lormi 2494b51
merged branch develop into feature/interpolation_binning_01
mo-lormi 2d63679
added halo exchange operation before generating Gmsh data
mo-lormi 25e9b59
removed variable grid_type_
mo-lormi 1631e61
removed unnecessary namespaces
mo-lormi c9cbaeb
update 07.06.24-01
mo-lormi 4b8e336
update 07.06.24-02
mo-lormi fb36305
update 07.06.24-03
mo-lormi c0b8577
update 07.06.24-04
mo-lormi d766d88
Consistency with SphericalVector: rename 'ancillary_scheme' to 'scheme'
wdeconinck b09c2a5
Fix intent of halo_exchange and adjoint in Binning method
wdeconinck d31023e
Remove SphericalVector::adjoint_ and use base class
wdeconinck 9f8aab0
No casting to CubedSphereProjection necessary
wdeconinck 175d12f
Reduce dimensionality of area field
wdeconinck 2df6ac7
redefined the procedure to evaluate the areas of the grid cells
mo-lormi 1e45e6f
updated build procedure
mo-lormi 7aa4ec8
update 14.06.24-01
mo-lormi 9390bdc
Merge branch 'develop' into feature/interpolation_binning_01
wdeconinck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
/* | ||
* (C) Crown Copyright 2024 Met Office | ||
* | ||
* This software is licensed under the terms of the Apache Licence Version 2.0 | ||
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. | ||
*/ | ||
|
||
|
||
#include "atlas/functionspace/NodeColumns.h" | ||
#include "atlas/functionspace/StructuredColumns.h" | ||
#include "atlas/grid.h" | ||
#include "atlas/interpolation/Interpolation.h" | ||
#include "atlas/interpolation/method/binning/Binning.h" | ||
#include "atlas/interpolation/method/MethodFactory.h" | ||
#include "atlas/runtime/Trace.h" | ||
|
||
#include "eckit/config/LocalConfiguration.h" | ||
#include "eckit/linalg/SparseMatrix.h" | ||
#include "eckit/linalg/Triplet.h" | ||
#include "eckit/mpi/Comm.h" | ||
|
||
|
||
namespace atlas { | ||
namespace interpolation { | ||
namespace method { | ||
|
||
|
||
namespace { | ||
|
||
MethodBuilder<Binning> __builder("binning"); | ||
|
||
} | ||
|
||
|
||
Binning::Binning(const Config& config) : Method(config) { | ||
const auto* ptr_config = dynamic_cast<const eckit::LocalConfiguration*>(&config); | ||
interpAncillaryScheme_ = ptr_config->getSubConfiguration("ancillary_scheme"); | ||
grid_type_ = ptr_config->getString("grid_type", "ATLAS"); | ||
wdeconinck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
halo_exchange_ = ptr_config->getBool("halo_exchange", true); | ||
adjoint_ = ptr_config->getBool("adjoint", false); | ||
} | ||
|
||
|
||
void Binning::do_setup(const Grid& source, | ||
const Grid& target, | ||
const Cache&) { | ||
ATLAS_NOTIMPLEMENTED; | ||
} | ||
|
||
|
||
void Binning::do_setup(const FunctionSpace& source, | ||
const FunctionSpace& target) { | ||
ATLAS_TRACE("atlas::interpolation::method::Binning::do_setup()"); | ||
|
||
using Index = eckit::linalg::Index; | ||
using Triplet = eckit::linalg::Triplet; | ||
using SMatrix = eckit::linalg::SparseMatrix; | ||
|
||
source_ = source; | ||
target_ = target; | ||
|
||
if (target_.size() == 0) { | ||
return; | ||
} | ||
|
||
// enabling or disabling the halo exchange | ||
this->allow_halo_exchange_ = halo_exchange_; | ||
// enabling or disabling the adjoint operation | ||
this->adjoint_ = adjoint_; | ||
wdeconinck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// note that the 'source' grid for the low-to-high regridding (interpolation) | ||
// is the 'target' grid for high-to-low regridding (binning) and | ||
// the 'target' grid for the low-to-high regridding (interpolation) is the | ||
// 'source' grid for the for high-to-low regridding (binning) | ||
const auto& fs_source_interp = target_; | ||
const auto& fs_target_interp = source_; | ||
|
||
const auto interp = Interpolation( | ||
interpAncillaryScheme_, fs_source_interp, fs_target_interp); | ||
auto smx_interp_cache = atlas::interpolation::MatrixCache(interp); | ||
|
||
auto smx_interp = smx_interp_cache.matrix(); | ||
|
||
auto smx_interp_tr = smx_interp.transpose(); | ||
|
||
const auto rows_tamx = smx_interp_tr.rows(); | ||
const auto cols_tamx = smx_interp_tr.cols(); | ||
|
||
const double* ptr_tamx_data = smx_interp_tr.data(); | ||
const Index* ptr_tamx_idxs_col = smx_interp_tr.inner(); | ||
const Index* ptr_tamx_o = smx_interp_tr.outer(); | ||
|
||
// diagonal of 'area weights matrix', W | ||
auto ds_aweights = getAreaWeights(source_); | ||
|
||
auto smx_binning_els = std::vector<Triplet>{}; | ||
size_t idx_row_next = 0; | ||
|
||
for (size_t idx_row = 0; idx_row < rows_tamx; ++idx_row) { | ||
idx_row_next = (idx_row+1); | ||
// start of the indexes associated with the row 'i' | ||
size_t lbound = ptr_tamx_o[idx_row]; | ||
// start of the indexes associated with the row 'i+1' | ||
size_t ubound = ptr_tamx_o[idx_row_next]; | ||
|
||
if (lbound == ubound) | ||
continue; | ||
|
||
double sum_row = 0; | ||
for (size_t i = lbound; i < ubound; ++i) { | ||
sum_row += (ptr_tamx_data[i] * ds_aweights.at(ptr_tamx_idxs_col[i])); | ||
} | ||
|
||
// normalization factor | ||
double nfactor = 1/sum_row; | ||
|
||
for (size_t i = lbound; i < ubound; ++i) { | ||
// evaluating the non-zero elements of the binning matrix | ||
smx_binning_els.emplace_back( | ||
idx_row, ptr_tamx_idxs_col[i], | ||
(nfactor * (ptr_tamx_data[i] * ds_aweights.at(ptr_tamx_idxs_col[i])))); | ||
} | ||
} | ||
|
||
// 'binning matrix' (sparse matrix), B = N A^T W | ||
SMatrix smx_binning{rows_tamx, cols_tamx, smx_binning_els}; | ||
setMatrix(smx_binning); | ||
} | ||
|
||
|
||
void Binning::print(std::ostream&) const { | ||
ATLAS_NOTIMPLEMENTED; | ||
} | ||
|
||
|
||
std::vector<double> Binning::getAreaWeights(const FunctionSpace& fspace) const { | ||
// diagonal of 'area weights matrix', W | ||
std::vector<double> ds_aweights; | ||
|
||
if (grid_type_ == "CS-LFR") { | ||
wdeconinck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const auto csfs = atlas::functionspace::NodeColumns(fspace); | ||
|
||
const auto csgrid = atlas::CubedSphereGrid(csfs.mesh().grid()); | ||
// areas of the cells (geographic coord. system) | ||
const auto gcell_areas = csgrid.gridCellArea(fspace); | ||
|
||
auto gcell_areas_view = array::make_view<double, 2>(gcell_areas); | ||
auto is_ghost = atlas::array::make_view<int, 1>(csfs.ghost()); | ||
|
||
double total_area {0.}; | ||
for (idx_t i = 0; i < csfs.size(); i++) { | ||
if (!is_ghost[i]) { | ||
total_area += gcell_areas_view(i, 0); | ||
} | ||
} | ||
eckit::mpi::comm().allReduceInPlace(total_area, eckit::mpi::Operation::SUM); | ||
|
||
double aweight_temp {0.}; | ||
for (idx_t i = 0; i < csfs.size(); i++) { | ||
if (!is_ghost[i]) { | ||
aweight_temp = gcell_areas_view(i, 0)/total_area; | ||
ds_aweights.emplace_back(aweight_temp); | ||
} | ||
} | ||
|
||
} else { | ||
|
||
// area weights (default) | ||
ds_aweights.assign(fspace.size(), 1.); | ||
|
||
} | ||
|
||
return ds_aweights; | ||
} | ||
|
||
|
||
} // namespace method | ||
} // namespace interpolation | ||
} // namespace atlas |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* (C) Crown Copyright 2024 Met Office | ||
* | ||
* This software is licensed under the terms of the Apache Licence Version 2.0 | ||
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
#include "atlas/functionspace/FunctionSpace.h" | ||
#include "atlas/interpolation/Cache.h" | ||
#include "atlas/interpolation/method/Method.h" | ||
#include "atlas/grid/Grid.h" | ||
|
||
#include "eckit/config/Configuration.h" | ||
|
||
|
||
namespace atlas { | ||
namespace interpolation { | ||
namespace method { | ||
|
||
|
||
class Binning : public Method { | ||
public: | ||
/// @brief Binning procedure to carry out a regridding from high | ||
/// to low resolution | ||
/// | ||
/// @details This method is part of the family of the Interpolation operations; | ||
/// it relies on the evaluation of the transpose of an interpolation matrix. | ||
/// The rigridding from high to low resolution is carried out by using | ||
/// a 'binning matrix': | ||
/// binning matrix: B = N A^T W | ||
/// area weights matrix: W | ||
/// interpolation matrix: A | ||
/// normalization factor matrix: N | ||
/// | ||
/// Setup, configuration variables: | ||
/// <type>: method used to evaluate the 'B' matrix; | ||
/// value: 'binning' | ||
/// <ancillary_scheme>: method used to evaluate the 'A' matrix; | ||
/// value: 'cubedsphere-bilinear', 'structured-bilinear', ... | ||
/// <grid_type>: type of grid | ||
/// value: 'CS-LFR', 'O', ... | ||
/// <halo_exchange>: flag to control the halo exchange procedure | ||
/// value: 'true', 'false' | ||
/// <adjoint>: flag to control the adjoint operation | ||
/// value: 'true', 'false' | ||
/// | ||
Binning(const Config& config); | ||
~Binning() override {} | ||
|
||
void print(std::ostream&) const override; | ||
const FunctionSpace& source() const override { return source_; } | ||
const FunctionSpace& target() const override { return target_; } | ||
|
||
private: | ||
using Method::do_setup; | ||
void do_setup(const FunctionSpace& source, | ||
const FunctionSpace& target) override; | ||
void do_setup(const Grid& source, const Grid& target, const Cache&) override; | ||
|
||
std::vector<double> getAreaWeights(const FunctionSpace& source) const; | ||
|
||
eckit::LocalConfiguration interpAncillaryScheme_{}; | ||
|
||
FunctionSpace source_{}; | ||
FunctionSpace target_{}; | ||
|
||
std::string grid_type_{"ATLAS"}; | ||
bool halo_exchange_{true}; | ||
bool adjoint_{false}; | ||
}; | ||
|
||
|
||
} // namespace method | ||
} // namespace interpolation | ||
} // namespace atlas |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
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
oratlas::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 theFunctionSpace
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
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.
The binning procedure works also for "functionspace == StructuredColumns" (grid type: "O").
I implemented a test to check this scenario, see here.