Skip to content

Commit e4daac1

Browse files
odlomaxwdeconinck
andauthored
Added OpenMP to the cubed-sphere interpolator and the matching cubed sphere partitioner. (#293)
* Added OpenMP to cubed sphere interpolator and matching mesh partitioner. * Allow integer narrowing in triplet construction. * Addressed race condition. * Simplified weight triplet vector creation. * Added const to lon-lat iterator declaration in partitioner. * This might fail some CI... * This should pass CI... * Offending test case was an esoteric use case that wasn't that useful. Let's get rid of it. * Removed redundant includes. * Removed redundant helper function. * Added test to demonstrate unusual lifetime features for const references. * typo in case name * Tidied up after review. * Added check to deal with poorly performing CubedSphereIterator. --------- Co-authored-by: Willem Deconinck <willem.deconinck@ecmwf.int>
1 parent ede599c commit e4daac1

File tree

5 files changed

+76
-344
lines changed

5 files changed

+76
-344
lines changed

src/atlas/grid/detail/partitioner/MatchingMeshPartitionerCubedSphere.cc

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@
66
*/
77

88
#include "atlas/grid/detail/partitioner/MatchingMeshPartitionerCubedSphere.h"
9+
10+
#include <algorithm>
11+
#include <iterator>
12+
#include <vector>
13+
914
#include "atlas/grid/CubedSphereGrid.h"
1015
#include "atlas/grid/Iterator.h"
1116
#include "atlas/interpolation/method/cubedsphere/CellFinder.h"
1217
#include "atlas/parallel/mpi/mpi.h"
18+
#include "atlas/parallel/omp/omp.h"
19+
#include "atlas/util/Point.h"
1320

1421
namespace atlas {
1522
namespace grid {
@@ -29,14 +36,24 @@ void MatchingMeshPartitionerCubedSphere::partition(const Grid& grid, int partiti
2936
const auto edgeEpsilon = epsilon;
3037
const size_t listSize = 8;
3138

32-
// Loop over grid and set partioning[].
33-
auto lonlatIt = grid.lonlat().begin();
34-
for (gidx_t i = 0; i < grid.size(); ++i) {
35-
// This is probably more expensive than it needs to be, as it performs
36-
// a dry run of the cubedsphere interpolation method.
37-
const auto& lonlat = *lonlatIt;
38-
partitioning[i] = finder.getCell(lonlat, listSize, edgeEpsilon, epsilon).isect ? mpi_rank : -1;
39-
++lonlatIt;
39+
40+
const auto setPartitioning = [&](const auto& lonLatIt) {
41+
atlas_omp_parallel_for(gidx_t i = 0; i < grid.size(); ++i) {
42+
const auto lonLat = *(lonLatIt + i);
43+
// This is probably more expensive than it needs to be, as it performs
44+
// a dry run of the cubedsphere interpolation method.
45+
partitioning[i] = finder.getCell(lonLat, listSize, edgeEpsilon, epsilon).isect ? mpi_rank : -1;
46+
}
47+
};
48+
49+
// CubedSphereIterator::operator+=() is not implemented properly.
50+
if (CubedSphereGrid(grid)) {
51+
auto lonLats = std::vector<PointLonLat>{};
52+
lonLats.reserve(grid.size());
53+
std::copy(grid.lonlat().begin(), grid.lonlat().end(), std::back_inserter(lonLats));
54+
setPartitioning(lonLats.begin());
55+
} else {
56+
setPartitioning(grid.lonlat().begin());
4057
}
4158

4259
// AllReduce to get full partitioning array.

src/atlas/interpolation/method/cubedsphere/CubedSphereBilinear.cc

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "atlas/grid/CubedSphereGrid.h"
1111
#include "atlas/interpolation/method/MethodFactory.h"
1212
#include "atlas/interpolation/method/cubedsphere/CellFinder.h"
13+
#include "atlas/parallel/omp/omp.h"
1314
#include "atlas/util/CoordinateEnums.h"
1415

1516
namespace atlas {
@@ -37,9 +38,6 @@ void CubedSphereBilinear::do_setup(const FunctionSpace& source, const FunctionSp
3738
ATLAS_ASSERT(ncSource);
3839
ATLAS_ASSERT(target_);
3940

40-
// Enable or disable halo exchange.
41-
this->allow_halo_exchange_ = halo_exchange_;
42-
4341

4442
// return early if no output points on this partition reserve is called on
4543
// the triplets but also during the sparseMatrix constructor. This won't
@@ -54,16 +52,12 @@ void CubedSphereBilinear::do_setup(const FunctionSpace& source, const FunctionSp
5452
const auto N = CubedSphereGrid(ncSource.mesh().grid()).N();
5553
const auto tolerance = 2. * std::numeric_limits<double>::epsilon() * N;
5654

57-
// Loop over target at calculate interpolation weights.
58-
auto weights = std::vector<Triplet>{};
55+
// Weights vector is oversized. Empty triplets are ignored by Matrix constructor.
56+
auto weights = Triplets(4 * target_.size());
5957
const auto ghostView = array::make_view<int, 1>(target_.ghost());
6058
const auto lonlatView = array::make_view<double, 2>(target_.lonlat());
61-
const auto tijView = array::make_view<idx_t, 2>(ncSource.mesh().cells().field("tij"));
62-
63-
// Make vector of tile indices for each target point (needed for vector field interpolation).
64-
std::vector<idx_t> tileIndex{};
6559

66-
for (idx_t i = 0; i < target_.size(); ++i) {
60+
atlas_omp_parallel_for(idx_t i = 0; i < target_.size(); ++i) {
6761
if (!ghostView(i)) {
6862
const auto cell =
6963
finder.getCell(PointLonLat(lonlatView(i, LON), lonlatView(i, LAT)), listSize_, tolerance, tolerance);
@@ -75,24 +69,23 @@ void CubedSphereBilinear::do_setup(const FunctionSpace& source, const FunctionSp
7569
std::to_string(i) + ".");
7670
}
7771

78-
tileIndex.push_back(tijView(cell.idx, 0));
7972
const auto& isect = cell.isect;
8073
const auto& j = cell.nodes;
8174

8275
switch (cell.nodes.size()) {
8376
case (3): {
8477
// Cell is a triangle.
85-
weights.emplace_back(i, j[0], 1. - isect.u - isect.v);
86-
weights.emplace_back(i, j[1], isect.u);
87-
weights.emplace_back(i, j[2], isect.v);
78+
weights[4 * i] = Triplet(i, j[0], 1. - isect.u - isect.v);
79+
weights[4 * i + 1] = Triplet(i, j[1], isect.u);
80+
weights[4 * i + 2] = Triplet(i, j[2], isect.v);
8881
break;
8982
}
9083
case (4): {
9184
// Cell is quad.
92-
weights.emplace_back(i, j[0], (1. - isect.u) * (1. - isect.v));
93-
weights.emplace_back(i, j[1], isect.u * (1. - isect.v));
94-
weights.emplace_back(i, j[2], isect.u * isect.v);
95-
weights.emplace_back(i, j[3], (1. - isect.u) * isect.v);
85+
weights[4 * i] = Triplet(i, j[0], (1. - isect.u) * (1. - isect.v));
86+
weights[4 * i + 1] = Triplet(i, j[1], isect.u * (1. - isect.v));
87+
weights[4 * i + 2] = Triplet(i, j[2], isect.u * isect.v);
88+
weights[4 * i + 3] = Triplet(i, j[3], (1. - isect.u) * isect.v);
9689
break;
9790
}
9891
default: {
@@ -104,9 +97,6 @@ void CubedSphereBilinear::do_setup(const FunctionSpace& source, const FunctionSp
10497

10598
// fill sparse matrix and return.
10699
setMatrix(target_.size(), source_.size(), weights);
107-
108-
// Add tile index metadata to target.
109-
target_->metadata().set("tile index", tileIndex);
110100
}
111101

112102
void CubedSphereBilinear::print(std::ostream&) const {

src/atlas/interpolation/method/cubedsphere/CubedSphereBilinear.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ class CubedSphereBilinear : public Method {
3030
CubedSphereBilinear(const Config& config): Method(config) {
3131
config.get("halo", halo_);
3232
config.get("list_size", listSize_);
33-
config.get("halo_exchange", halo_exchange_);
3433
}
3534
virtual ~CubedSphereBilinear() override {}
3635

@@ -49,7 +48,6 @@ class CubedSphereBilinear : public Method {
4948

5049
int halo_{0};
5150
int listSize_{8};
52-
bool halo_exchange_{true};
5351
};
5452

5553
} // namespace method

src/tests/interpolation/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ ecbuild_add_test( TARGET atlas_test_interpolation_structured2D_to_points
129129
ecbuild_add_test( TARGET atlas_test_interpolation_cubedsphere
130130
SOURCES test_interpolation_cubedsphere.cc
131131
LIBS atlas
132-
MPI 6
132+
MPI 3
133+
OMP 3
133134
CONDITION eckit_HAVE_MPI AND MPI_SLOTS GREATER_EQUAL 6
134135
ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT}
135136
)

0 commit comments

Comments
 (0)