IODA
DistributionUtils.cc
Go to the documentation of this file.
1 /*
2  * (C) Crown copyright 2021, Met Office
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  */
7 
8 #include "eckit/config/LocalConfiguration.h"
9 
10 #include "ioda/distribution/Accumulator.h"
11 #include "ioda/distribution/Distribution.h"
12 #include "ioda/distribution/DistributionUtils.h"
13 #include "ioda/distribution/InefficientDistribution.h"
14 #include "ioda/distribution/ReplicaOfNonoverlappingDistribution.h"
15 #include "ioda/distribution/ReplicaOfGeneralDistribution.h"
16 
17 #include "oops/util/DateTime.h"
18 #include "oops/util/missingValues.h"
19 
20 namespace ioda {
21 
22 namespace {
23 
24 template <typename T>
25 std::size_t globalNumNonMissingObsImpl(const Distribution &dist,
26  std::size_t numVariables, const std::vector<T> &v) {
27  const T missingValue = util::missingValue(missingValue);
28  const std::size_t numLocations = v.size() / numVariables;
29 
30  // Local reduction
31  std::unique_ptr<Accumulator<std::size_t>> accumulator = dist.createAccumulator<std::size_t>();
32  for (size_t loc = 0, element = 0; loc < numLocations; ++loc) {
33  std::size_t term = 0;
34  for (size_t var = 0; var < numVariables; ++var, ++element)
35  if (v[element] != missingValue)
36  ++term;
37  accumulator->addTerm(loc, term);
38  }
39  // Global reduction
40  return accumulator->computeResult();
41 }
42 
43 template <typename T>
44 double dotProductImpl(const Distribution &dist,
45  std::size_t numVariables,
46  const std::vector<T> &v1,
47  const std::vector<T> &v2) {
48  ASSERT(v1.size() == v2.size());
49  const T missingValue = util::missingValue(missingValue);
50  const std::size_t numLocations = v1.size() / numVariables;
51 
52  // Local reduction
53  std::unique_ptr<Accumulator<double>> accumulator = dist.createAccumulator<double>();
54  for (size_t loc = 0, element = 0; loc < numLocations; ++loc) {
55  double term = 0;
56  for (size_t var = 0; var < numVariables; ++var, ++element)
57  if (v1[element] != missingValue && v2[element] != missingValue)
58  term += v1[element] * v2[element];
59  accumulator->addTerm(loc, term);
60  }
61  // Global reduction
62  return accumulator->computeResult();
63 }
64 
65 } // namespace
66 
67 // -----------------------------------------------------------------------------
68 double dotProduct(const Distribution &dist,
69  std::size_t numVariables,
70  const std::vector<double> &v1,
71  const std::vector<double> &v2) {
72  return dotProductImpl(dist, numVariables, v1, v2);
73 }
74 
75 double dotProduct(const Distribution &dist,
76  std::size_t numVariables,
77  const std::vector<float> &v1,
78  const std::vector<float> &v2) {
79  return dotProductImpl(dist, numVariables, v1, v2);
80 }
81 
82 double dotProduct(const Distribution &dist,
83  std::size_t numVariables,
84  const std::vector<int> &v1,
85  const std::vector<int> &v2) {
86  return dotProductImpl(dist, numVariables, v1, v2);
87 }
88 
89 // -----------------------------------------------------------------------------
90 std::size_t globalNumNonMissingObs(const Distribution &dist,
91  std::size_t numVariables,
92  const std::vector<double> &v) {
93  return globalNumNonMissingObsImpl(dist, numVariables, v);
94 }
95 
96 std::size_t globalNumNonMissingObs(const Distribution &dist,
97  std::size_t numVariables,
98  const std::vector<float> &v) {
99  return globalNumNonMissingObsImpl(dist, numVariables, v);
100 }
101 
102 std::size_t globalNumNonMissingObs(const Distribution &dist,
103  std::size_t numVariables,
104  const std::vector<int> &v) {
105  return globalNumNonMissingObsImpl(dist, numVariables, v);
106 }
107 
108 std::size_t globalNumNonMissingObs(const Distribution &dist,
109  std::size_t numVariables,
110  const std::vector<std::string> &v) {
111  return globalNumNonMissingObsImpl(dist, numVariables, v);
112 }
113 
114 std::size_t globalNumNonMissingObs(const Distribution &dist,
115  std::size_t numVariables,
116  const std::vector<util::DateTime> &v) {
117  return globalNumNonMissingObsImpl(dist, numVariables, v);
118 }
119 
120 // -----------------------------------------------------------------------------
121 std::shared_ptr<Distribution> createReplicaDistribution(
122  const eckit::mpi::Comm & comm,
123  std::shared_ptr<const Distribution> master,
124  const std::vector<std::size_t> &masterRecordNums) {
125  if (master->isNonoverlapping())
126  return std::make_shared<ReplicaOfNonoverlappingDistribution>(comm, std::move(master));
127  else if (master->isIdentity())
128  return std::make_shared<InefficientDistribution>(comm, eckit::LocalConfiguration());
129  else
130  return std::make_shared<ReplicaOfGeneralDistribution>(comm, std::move(master),
131  masterRecordNums);
132 }
133 
134 } // namespace ioda
class for distributing obs across multiple process elements
std::unique_ptr< Accumulator< T > > createAccumulator() const
Create an object that can be used to calculate the sum of a location-dependent quantity over location...
double dotProductImpl(const Distribution &dist, std::size_t numVariables, const std::vector< T > &v1, const std::vector< T > &v2)
std::size_t globalNumNonMissingObsImpl(const Distribution &dist, std::size_t numVariables, const std::vector< T > &v)
double dotProduct(const Distribution &dist, std::size_t numVariables, const std::vector< double > &v1, const std::vector< double > &v2)
std::size_t globalNumNonMissingObs(const Distribution &dist, std::size_t numVariables, const std::vector< double > &v)
std::shared_ptr< Distribution > createReplicaDistribution(const eckit::mpi::Comm &comm, std::shared_ptr< const Distribution > master, const std::vector< std::size_t > &masterRecordNums)
Create a suitable replica distribution for the distribution master.