11 #ifndef TEST_DISTRIBUTION_DISTRIBUTION_H_
12 #define TEST_DISTRIBUTION_DISTRIBUTION_H_
22 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
24 #include <boost/noncopyable.hpp>
26 #include "eckit/config/LocalConfiguration.h"
27 #include "eckit/geometry/Point2.h"
28 #include "eckit/mpi/Comm.h"
29 #include "eckit/testing/Test.h"
31 #include "oops/mpi/mpi.h"
32 #include "oops/runs/Test.h"
33 #include "oops/test/TestEnvironment.h"
34 #include "oops/util/DateTime.h"
35 #include "oops/util/Logger.h"
37 #include "ioda/distribution/Distribution.h"
38 #include "ioda/distribution/DistributionFactory.h"
46 template <>
struct VectorPrintSelector<float> {
typedef VectorPrintSimple selector; };
47 template <>
struct VectorPrintSelector<
util::DateTime> {
typedef VectorPrintSimple selector; };
48 template <>
struct VectorPrintSelector<
util::Duration> {
typedef VectorPrintSimple selector; };
57 const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
58 std::vector<eckit::LocalConfiguration> dist_types;
59 const eckit::mpi::Comm & MpiComm = oops::mpi::world();
61 std::string TestDistType;
63 std::unique_ptr<ioda::Distribution> TestDist;
67 conf.get(
"distribution types", dist_types);
68 for (std::size_t i = 0; i < dist_types.size(); ++i) {
69 oops::Log::debug() <<
"Distribution::DistributionTypes: conf: " << dist_types[i] << std::endl;
71 TestDistType = dist_types[i].getString(
"distribution");
72 oops::Log::debug() <<
"Distribution::DistType: " << TestDistType << std::endl;
74 DistName = dist_types[i].getString(
"specs.name");
75 eckit::LocalConfiguration DistConfig;
76 DistConfig.set(
"distribution", DistName);
78 EXPECT(TestDist.get());
85 const eckit::Configuration &MyRankConfig,
87 const std::vector<std::size_t> &Index,
88 const std::vector<std::size_t> &Recnums) {
90 std::size_t ExpectedNlocs = MyRankConfig.getUnsigned(
"nlocs");
91 std::size_t ExpectedNrecs = MyRankConfig.getUnsigned(
"nrecs");
92 std::size_t ExpectedNPatchLocs = MyRankConfig.getUnsigned(
"nPatchLocs");
93 std::vector<std::size_t> ExpectedIndex =
94 MyRankConfig.getUnsignedVector(
"index");
95 std::vector<std::size_t> ExpectedRecnums =
96 MyRankConfig.getUnsignedVector(
"recnums");
97 std::vector<std::size_t> ExpectedPatchIndex =
98 MyRankConfig.getUnsignedVector(
"patchIndex");
99 const std::vector<std::size_t> ExpectedAllGatherv =
100 config.getUnsignedVector(
"specs.allgatherv");
102 std::vector<bool> patchBool(Index.size());
103 std::vector<std::size_t> PatchLocsThisPE;
105 for (std::size_t j = 0; j < Index.size(); ++j) {
106 if (patchBool[j]) {PatchLocsThisPE.push_back(Index[j]);}
110 std::size_t
Nlocs = Index.size();
111 std::size_t Nrecs = std::set<std::size_t>(Recnums.begin(), Recnums.end()).size();
112 std::size_t NPatchLocs = PatchLocsThisPE.size();
114 oops::Log::debug() <<
"Location Index: " << Index << std::endl;
115 oops::Log::debug() <<
"PatchLocsThisPE: " << PatchLocsThisPE << std::endl;
116 oops::Log::debug() <<
"Nlocs: " <<
Nlocs <<
" Nrecs: " << Nrecs
117 <<
" NPatchLocs" << NPatchLocs << std::endl;
119 EXPECT_EQUAL(
Nlocs, ExpectedNlocs);
120 EXPECT_EQUAL(Nrecs, ExpectedNrecs);
121 EXPECT_EQUAL(NPatchLocs, ExpectedNPatchLocs);
124 EXPECT_EQUAL(Index, ExpectedIndex);
125 EXPECT_EQUAL(Recnums, ExpectedRecnums);
126 EXPECT_EQUAL(PatchLocsThisPE, ExpectedPatchIndex);
133 const std::vector<std::size_t> ExpectedAllGathervSizeT = ExpectedAllGatherv;
134 std::vector<size_t> AllGathervSizeT = Index;
136 EXPECT_EQUAL(AllGathervSizeT, ExpectedAllGathervSizeT);
143 std::vector<size_t> ExpectedGlobalUniqueConsecutiveLocationIndices(
Nlocs);
144 std::vector<size_t> GlobalUniqueConsecutiveLocationIndices(
Nlocs);
145 for (
size_t loc = 0; loc <
Nlocs; ++loc) {
146 const std::vector<size_t>::iterator it = std::find(
147 AllGathervSizeT.begin(), AllGathervSizeT.end(), Index[loc]);
148 ASSERT(it != AllGathervSizeT.end());
149 ExpectedGlobalUniqueConsecutiveLocationIndices[loc] = it - AllGathervSizeT.begin();
150 GlobalUniqueConsecutiveLocationIndices[loc] =
154 EXPECT_EQUAL(GlobalUniqueConsecutiveLocationIndices,
155 ExpectedGlobalUniqueConsecutiveLocationIndices);
160 std::vector<int> ExpectedAllGathervInt(ExpectedAllGatherv.begin(),
161 ExpectedAllGatherv.end());
162 std::vector<int> AllGathervInt(Index.begin(), Index.end());
164 EXPECT_EQUAL(AllGathervInt, ExpectedAllGathervInt);
169 std::vector<float> ExpectedAllGathervFloat(ExpectedAllGatherv.begin(),
170 ExpectedAllGatherv.end());
171 std::vector<float> AllGathervFloat(Index.begin(), Index.end());
173 EXPECT_EQUAL(AllGathervFloat, ExpectedAllGathervFloat);
178 std::vector<double> ExpectedAllGathervDouble(ExpectedAllGatherv.begin(),
179 ExpectedAllGatherv.end());
180 std::vector<double> AllGathervDouble(Index.begin(), Index.end());
182 EXPECT_EQUAL(AllGathervDouble, ExpectedAllGathervDouble);
187 auto numberToString = [](std::size_t x) {
return std::to_string(x); };
188 std::vector<std::string> ExpectedAllGathervString;
189 std::transform(ExpectedAllGatherv.begin(), ExpectedAllGatherv.end(),
190 std::back_inserter(ExpectedAllGathervString), numberToString);
191 std::vector<std::string> AllGathervString;
193 std::back_inserter(AllGathervString), numberToString);
195 EXPECT_EQUAL(AllGathervString, ExpectedAllGathervString);
200 auto numberToDateTime = [](std::size_t x) {
return util::DateTime(2000, 1, 1, 0, 0, x); };
201 std::vector<util::DateTime> ExpectedAllGathervDateTime;
202 std::transform(ExpectedAllGatherv.begin(), ExpectedAllGatherv.end(),
203 std::back_inserter(ExpectedAllGathervDateTime), numberToDateTime);
204 std::vector<util::DateTime> AllGathervDateTime;
206 std::back_inserter(AllGathervDateTime), numberToDateTime);
208 EXPECT_EQUAL(AllGathervDateTime, ExpectedAllGathervDateTime);
215 const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
216 std::vector<eckit::LocalConfiguration> dist_types;
217 const eckit::mpi::Comm & MpiComm = oops::mpi::world();
219 std::string TestDistType;
220 std::string DistName;
221 std::unique_ptr<ioda::Distribution> TestDist;
223 std::size_t MyRank = MpiComm.rank();
226 conf.get(
"distribution types", dist_types);
227 for (std::size_t i = 0; i < dist_types.size(); ++i) {
228 oops::Log::debug() <<
"Distribution::DistributionTypes: conf: "
229 << dist_types[i] << std::endl;
231 TestDistType = dist_types[i].getString(
"distribution");
232 oops::Log::debug() <<
"Distribution::DistType: " << TestDistType << std::endl;
236 std::string MyRankCfgName =
"specs.rank" + std::to_string(MyRank);
237 eckit::LocalConfiguration MyRankConfig = dist_types[i].getSubConfiguration(MyRankCfgName);
238 oops::Log::debug() <<
"Distribution::DistributionTypes: "
239 << MyRankCfgName <<
": " << MyRankConfig << std::endl;
242 std::size_t Gnlocs = dist_types[i].getInt(
"specs.gnlocs");
243 std::vector<double> glats(Gnlocs, 0);
244 std::vector<double> glons(Gnlocs, 0);
246 DistName = dist_types[i].getString(
"specs.name");
247 if (DistName ==
"Halo") {
248 glats = dist_types[i].getDoubleVector(
"specs.latitude");
249 glons = dist_types[i].getDoubleVector(
"specs.longitude");
251 MyRankConfig.set(
"distribution", DistName);
253 EXPECT(TestDist.get());
258 std::vector<std::size_t> Groups(Gnlocs, 0);
259 if (dist_types[i].has(
"specs.obsgrouping")) {
260 Groups = dist_types[i].getUnsignedVector(
"specs.obsgrouping");
262 std::iota(Groups.begin(), Groups.end(), 0);
266 std::vector<std::size_t> Index;
267 std::vector<std::size_t> Recnums;
268 for (std::size_t j = 0; j < Gnlocs; ++j) {
269 std::size_t RecNum = Groups[j];
270 eckit::geometry::Point2 point(glons[j], glats[j]);
271 TestDist->assignRecord(RecNum, j, point);
272 if (TestDist->isMyRecord(RecNum)) {
274 Recnums.push_back(RecNum);
277 TestDist->computePatchLocs();
279 testDistribution(dist_types[i], MyRankConfig, TestDist.get(), Index, Recnums);
289 const eckit::LocalConfiguration topLevelConf(::test::TestEnvironment::config());
291 const util::DateTime winBegin(topLevelConf.getString(
"window begin"));
292 const util::DateTime winEnd(topLevelConf.getString(
"window end"));
294 const eckit::mpi::Comm & MpiComm = oops::mpi::world();
295 const std::size_t MyRank = MpiComm.rank();
297 const eckit::LocalConfiguration & obsConf = topLevelConf.getSubConfiguration(
"observations");
299 for (
const eckit::LocalConfiguration & conf : obsConf.getSubConfigurations()) {
300 eckit::LocalConfiguration obsspaceConf(conf,
"obs space");
301 ioda::ObsSpace obsspace(obsspaceConf, MpiComm, winBegin, winEnd, oops::mpi::myself());
305 std::string MyRankConfName =
"specs.rank" + std::to_string(MyRank);
306 eckit::LocalConfiguration MyRankConf(conf, MyRankConfName);
307 oops::Log::debug() <<
"MyRankConf: "
308 << MyRankConfName <<
": " << MyRankConf << std::endl;
322 std::string
testid()
const override {
return "test::Distribution";}
325 std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
327 ts.emplace_back(
CASE(
"distribution/Distribution/testConstructor")
329 ts.emplace_back(
CASE(
"distribution/Distribution/testDistributionConstructedManually")
331 ts.emplace_back(
CASE(
"distribution/Distribution/testDistributionConstructedByObsSpace")
static std::unique_ptr< Distribution > create(const eckit::mpi::Comm &comm, const eckit::Configuration &config)
Create a Distribution object implementing a particular method of distributing observations across mul...
class for distributing obs across multiple process elements
virtual void allGatherv(std::vector< size_t > &x) const =0
Gather observation data from all processes and deliver the combined data to all processes.
virtual void patchObs(std::vector< bool > &isPatchObs) const =0
Sets each element of the provided vector to true if the corresponding location is a "patch obs",...
virtual size_t globalUniqueConsecutiveLocationIndex(size_t loc) const =0
Map the index of a location held on the calling process to the index of the corresponding element of ...
Observation data class for IODA.
const std::vector< std::size_t > & recnum() const
return reference to the record number vector
const std::vector< std::size_t > & index() const
return reference to the index vector
std::shared_ptr< const Distribution > distribution() const
return MPI distribution object
void register_tests() const override
void clear() const override
std::string testid() const override
void testDistribution(const eckit::Configuration &config, const eckit::Configuration &MyRankConfig, const ioda::Distribution *TestDist, const std::vector< std::size_t > &Index, const std::vector< std::size_t > &Recnums)
void testDistributionConstructedByObsSpace()
CASE("Derived variable and unit conversion methods")
void testDistributionConstructedManually()