9 #include <unordered_set>
11 #include <boost/make_unique.hpp>
13 #include "atlas/mesh.h"
14 #include "atlas/meshgenerator.h"
15 #include "atlas/util/PolygonLocator.h"
16 #include "atlas/util/PolygonXY.h"
18 #include "eckit/mpi/Comm.h"
19 #include "ioda/distribution/AtlasDistribution.h"
20 #include "ioda/distribution/DistributionFactory.h"
21 #include "oops/util/Logger.h"
43 void assignRecord(std::size_t recNum,
const eckit::geometry::Point2 & point);
49 bool isInMyDomain(
const eckit::geometry::Point2 & point)
const;
53 std::unique_ptr<atlas::util::PolygonLocator>
locator_;
61 eckit::LocalConfiguration gridConfig(config,
"grid");
62 atlas::util::Config atlasConfig(gridConfig);
64 atlas::Grid grid(atlasConfig);
66 atlasConfig.set(
"type", grid.meshgenerator().getString(
"type"));
67 atlas::MeshGenerator generator(atlasConfig);
69 mesh_ = generator.generate(grid);
70 if (
mesh_->nb_partitions() != atlas::mpi::comm().size()) {
71 std::stringstream msg;
72 msg <<
"The number of mesh partitions, " <<
mesh_->nb_partitions()
73 <<
", is different from the number of MPI processes, " << atlas::mpi::comm().size();
74 throw eckit::Exception(msg.str(), Here());
77 locator_ = boost::make_unique<atlas::util::PolygonLocator>(
78 atlas::util::ListPolygonXY(
mesh_.polygons()),
mesh_.projection());
82 const eckit::geometry::Point2 & point) {
83 if (recNum == nextRecordToAssign_) {
84 const bool myRecord = isInMyDomain(point);
85 oops::Log::debug() <<
"RecordAssigner::assignRecord(): is " << recNum <<
" my record? "
86 << myRecord << std::endl;
88 myRecords_.insert(recNum);
89 ++nextRecordToAssign_;
92 ASSERT(recNum < nextRecordToAssign_);
97 return myRecords_.find(recNum) != myRecords_.end();
101 const atlas::idx_t partition = (*locator_)(point);
102 oops::Log::debug() <<
"RecordAssigner::isInMyDomain(): Polygon locator says "
103 << point <<
" is in domain " << partition << std::endl;
104 return partition == atlas::mpi::comm().rank();
112 const eckit::Configuration & config)
116 oops::Log::trace() <<
"AtlasDistribution constructed" << std::endl;
120 oops::Log::trace() <<
"AtlasDistribution destructed" << std::endl;
124 const std::size_t locNum,
125 const eckit::geometry::Point2 & point) {
Assigns records to MPI ranks for the AtlasDistribution.
void assignRecord(std::size_t recNum, const eckit::geometry::Point2 &point)
std::size_t nextRecordToAssign_
std::unordered_set< std::size_t > myRecords_
bool isInMyDomain(const eckit::geometry::Point2 &point) const
std::unique_ptr< atlas::util::PolygonLocator > locator_
RecordAssigner(const eckit::Configuration &config)
bool isMyRecord(std::size_t recNum) const
Returns true if record recNum has been assigned to the calling process, false otherwise.
AtlasDistribution(const eckit::mpi::Comm &comm, const eckit::Configuration &config)
bool isMyRecord(std::size_t recNum) const override
Returns true if record RecNum has been assigned to the calling PE during a previous call to assignRec...
std::string name() const override
void assignRecord(const std::size_t recNum, const std::size_t locNum, const eckit::geometry::Point2 &point) override
If the record RecNum has not yet been assigned to a PE, assigns it to the appropriate PE.
std::unique_ptr< RecordAssigner > recordAssigner_
~AtlasDistribution() override
A class able to instantiate objects of type T, which should be a subclass of Distribution.
Implements some methods of Distribution in a manner suitable for distributions storing each observati...
void assignRecord(const std::size_t RecNum, const std::size_t LocNum, const eckit::geometry::Point2 &point) override
If the record RecNum has not yet been assigned to a PE, assigns it to the appropriate PE.
static DistributionMaker< AtlasDistribution > maker(DIST_NAME)