IODA
ObsVector.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2017-2019 UCAR
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 "ioda/ObsVector.h"
9 
10 #include <math.h>
11 #include <limits>
12 
13 #include "eckit/config/LocalConfiguration.h"
14 #include "ioda/distribution/DistributionUtils.h"
15 #include "ioda/ObsDataVector.h"
16 #include "ioda/ObsSpace.h"
17 #include "oops/base/Variables.h"
18 #include "oops/util/abor1_cpp.h"
19 #include "oops/util/Logger.h"
20 #include "oops/util/missingValues.h"
21 #include "oops/util/Random.h"
22 
23 namespace ioda {
24 // -----------------------------------------------------------------------------
26  const std::string & name)
27  : obsdb_(obsdb), obsvars_(obsdb.obsvariables()),
28  nvars_(obsvars_.variables().size()), nlocs_(obsdb_.nlocs()),
29  values_(nlocs_ * nvars_),
30  missing_(util::missingValue(missing_)) {
31  oops::Log::trace() << "ObsVector::ObsVector " << name << std::endl;
32  if (!name.empty()) this->read(name);
33 }
34 // -----------------------------------------------------------------------------
36  : obsdb_(other.obsdb_), obsvars_(other.obsvars_), nvars_(other.nvars_),
37  nlocs_(other.nlocs_), values_(nlocs_ * nvars_), missing_(other.missing_) {
38  values_ = other.values_;
39  oops::Log::trace() << "ObsVector copied " << std::endl;
40 }
41 // -----------------------------------------------------------------------------
43 }
44 // -----------------------------------------------------------------------------
46  values_ = rhs.values_;
47  return *this;
48 }
49 // -----------------------------------------------------------------------------
50 ObsVector & ObsVector::operator*= (const double & zz) {
51  for (size_t jj = 0; jj < values_.size() ; ++jj) {
52  if (values_[jj] != missing_) {
53  values_[jj] = zz * values_[jj];
54  }
55  }
56  return *this;
57 }
58 // -----------------------------------------------------------------------------
60  const size_t nn = values_.size();
61  ASSERT(rhs.values_.size() == nn);
62  for (size_t jj = 0; jj < nn ; ++jj) {
63  if (values_[jj] == missing_ || rhs.values_[jj] == missing_) {
64  values_[jj] = missing_;
65  } else {
66  values_[jj] += rhs.values_[jj];
67  }
68  }
69  return *this;
70 }
71 // -----------------------------------------------------------------------------
73  const size_t nn = values_.size();
74  ASSERT(rhs.values_.size() == nn);
75  for (size_t jj = 0; jj < nn ; ++jj) {
76  if (values_[jj] == missing_ || rhs.values_[jj] == missing_) {
77  values_[jj] = missing_;
78  } else {
79  values_[jj] -= rhs.values_[jj];
80  }
81  }
82  return *this;
83 }
84 // -----------------------------------------------------------------------------
86  const size_t nn = values_.size();
87  ASSERT(rhs.values_.size() == nn);
88  for (size_t jj = 0; jj < nn ; ++jj) {
89  if (values_[jj] == missing_ || rhs.values_[jj] == missing_) {
90  values_[jj] = missing_;
91  } else {
92  values_[jj] *= rhs.values_[jj];
93  }
94  }
95  return *this;
96 }
97 // -----------------------------------------------------------------------------
99  const size_t nn = values_.size();
100  ASSERT(rhs.values_.size() == nn);
101  for (size_t jj = 0; jj < nn ; ++jj) {
102  if (values_[jj] == missing_ || rhs.values_[jj] == missing_) {
103  values_[jj] = missing_;
104  } else {
105  values_[jj] /= rhs.values_[jj];
106  }
107  }
108  return *this;
109 }
110 // -----------------------------------------------------------------------------
112  for (size_t jj = 0; jj < values_.size() ; ++jj) {
113  values_[jj] = 0.0;
114  }
115 }
116 // -----------------------------------------------------------------------------
118  std::fill(values_.begin(), values_.end(), 1.0);
119 }
120 // -----------------------------------------------------------------------------
121 void ObsVector::axpy(const double & zz, const ObsVector & rhs) {
122  const size_t nn = values_.size();
123  ASSERT(rhs.values_.size() == nn);
124  for (size_t jj = 0; jj < nn ; ++jj) {
125  if (values_[jj] == missing_ || rhs.values_[jj] == missing_) {
126  values_[jj] = missing_;
127  } else {
128  values_[jj] += zz * rhs.values_[jj];
129  }
130  }
131 }
132 // -----------------------------------------------------------------------------
133 void ObsVector::axpy(const std::vector<double> & beta, const ObsVector & y) {
134  ASSERT(y.values_.size() == values_.size());
135  ASSERT(beta.size() == nvars_);
136 
137  size_t ivec = 0;
138  for (size_t jloc = 0; jloc < nlocs_; ++jloc) {
139  for (size_t jvar = 0; jvar < nvars_; ++jvar, ++ivec) {
140  if (values_[ivec] == missing_ || y.values_[ivec] == missing_) {
141  values_[ivec] = missing_;
142  } else {
143  values_[ivec] += beta[jvar] * y.values_[ivec];
144  }
145  }
146  }
147 }
148 // -----------------------------------------------------------------------------
150  for (size_t jj = 0; jj < values_.size() ; ++jj) {
151  if (values_[jj] != missing_) {
152  values_[jj] = 1.0 / values_[jj];
153  }
154  }
155 }
156 // -----------------------------------------------------------------------------
158  util::NormalDistribution<double> x(values_.size(), 0.0, 1.0, this->getSeed());
159  for (size_t jj = 0; jj < values_.size() ; ++jj) {
160  values_[jj] = x[jj];
161  }
162 }
163 // -----------------------------------------------------------------------------
164 double ObsVector::dot_product_with(const ObsVector & other) const {
165  double zz = dotProduct(*obsdb_.distribution(), nvars_, values_, other.values_);
166  return zz;
167 }
168 // -----------------------------------------------------------------------------
169 std::vector<double> ObsVector::multivar_dot_product_with(const ObsVector & other) const {
170  std::vector<double> result(nvars_, 0);
171  for (size_t jvar = 0; jvar < nvars_; ++jvar) {
172  // fill vectors for current variable (note: if elements in values_
173  // were distributed as all locs for var1; all locs for var2; etc, we
174  // wouldn't need copies here).
175  std::vector<double> x1(nlocs_);
176  std::vector<double> x2(nlocs_);
177  for (size_t jloc = 0; jloc < nlocs_; ++jloc) {
178  x1[jloc] = values_[jvar + (jloc * nvars_)];
179  x2[jloc] = other.values_[jvar + (jloc*nvars_)];
180  }
181  result[jvar] = dotProduct(*obsdb_.distribution(), 1, x1, x2);
182  }
183  return result;
184 }
185 // -----------------------------------------------------------------------------
186 double ObsVector::rms() const {
187  double zrms = dot_product_with(*this);
188  int nobs = this->nobs();
189  if (nobs > 0) zrms = sqrt(zrms / static_cast<double>(nobs));
190 
191  return zrms;
192 }
193 // -----------------------------------------------------------------------------
194 void ObsVector::read(const std::string & name) {
195  oops::Log::trace() << "ObsVector::read, name = " << name << std::endl;
196 
197  // Read in the variables stored in obsvars_ from the group given by "name".
198  //
199  // We want to construct the vector in the order of all variable values for the
200  // first location, then all variable values for the second location, etc. This
201  // means that a single variable gets its values spread out across the vector
202  // in intervals the size of nvars_, and that the starting point for each variable
203  // in the vector is given by the index of the variable name in varnames_.
204 
205  std::size_t nlocs = obsdb_.nlocs();
206  std::vector<double> tmp(nlocs);
207  for (std::size_t jv = 0; jv < nvars_; ++jv) {
208  obsdb_.get_db(name, obsvars_.variables()[jv], tmp);
209 
210  for (std::size_t jj = 0; jj < nlocs; ++jj) {
211  std::size_t ivec = jv + (jj * nvars_);
212  values_[ivec] = tmp[jj];
213  }
214  }
215 }
216 // -----------------------------------------------------------------------------
217 void ObsVector::save(const std::string & name) const {
218  oops::Log::trace() << "ObsVector::save, name = " << name << std::endl;
219 
220  // As noted in the read method, the order is all variables at the first location,
221  // then all variables at the next location, etc.
222  std::size_t nlocs = obsdb_.nlocs();
223  std::size_t ivec;
224 
225  for (std::size_t jv = 0; jv < nvars_; ++jv) {
226  std::vector<double> tmp(nlocs);
227  for (std::size_t jj = 0; jj < tmp.size(); ++jj) {
228  ivec = jv + (jj * nvars_);
229  tmp[jj] = values_[ivec];
230  }
231  obsdb_.put_db(name, obsvars_.variables()[jv], tmp);
232  }
233 }
234 // -----------------------------------------------------------------------------
235 size_t ObsVector::packEigenSize(const ObsDataVector<int> & mask) const {
236  size_t nlocs = 0;
237  size_t ii = 0;
238  for (size_t jloc = 0; jloc < mask.nlocs(); ++jloc) {
239  for (size_t jvar = 0; jvar < mask.nvars(); ++jvar) {
240  if ((mask[jvar][jloc] <= 0) && (values_[ii] != missing_)) nlocs++;
241  ++ii;
242  }
243  }
244  return nlocs;
245 }
246 // -----------------------------------------------------------------------------
247 Eigen::VectorXd ObsVector::packEigen(const ObsDataVector<int> & mask) const {
248  Eigen::VectorXd vec(packEigenSize(mask));
249  size_t ii = 0;
250  size_t vecindex = 0;
251  for (size_t jloc = 0; jloc < mask.nlocs(); ++jloc) {
252  for (size_t jvar = 0; jvar < mask.nvars(); ++jvar) {
253  if ((mask[jvar][jloc] <= 0) && (values_[ii] != missing_)) {
254  vec(vecindex++) = values_[ii];
255  }
256  ++ii;
257  }
258  }
259  return vec;
260 }
261 // -----------------------------------------------------------------------------
263  oops::Log::trace() << "ObsVector::operator= start" << std::endl;
264  ASSERT(&rhs.space() == &obsdb_);
265  ASSERT(rhs.nvars() == nvars_);
266  ASSERT(rhs.nlocs() == nlocs_);
267  const float fmiss = util::missingValue(fmiss);
268  const double dmiss = util::missingValue(dmiss);
269  size_t ii = 0;
270  for (size_t jl = 0; jl < nlocs_; ++jl) {
271  for (size_t jv = 0; jv < nvars_; ++jv) {
272  if (rhs[jv][jl] == fmiss) {
273  values_[ii] = dmiss;
274  } else {
275  values_[ii] = static_cast<double>(rhs[jv][jl]);
276  }
277  ++ii;
278  }
279  }
280  oops::Log::trace() << "ObsVector::operator= done" << std::endl;
281 
282  return *this;
283 }
284 // -----------------------------------------------------------------------------
285 void ObsVector::mask(const ObsDataVector<int> & flags) {
286  oops::Log::trace() << "ObsVector::mask" << std::endl;
287  ASSERT(values_.size() == flags.nvars() * flags.nlocs());
288  size_t ii = 0;
289  for (size_t jj = 0; jj < flags.nlocs(); ++jj) {
290  for (size_t jv = 0; jv < flags.nvars(); ++jv) {
291  if (flags[jv][jj] > 0) values_[ii] = missing_;
292  ++ii;
293  }
294  }
295 }
296 // -----------------------------------------------------------------------------
297 unsigned int ObsVector::nobs() const {
299 
300  return nobs;
301 }
302 // -----------------------------------------------------------------------------
303 const double & ObsVector::toFortran() const {
304  return values_[0];
305 }
306 // -----------------------------------------------------------------------------
308  return values_[0];
309 }
310 // -----------------------------------------------------------------------------
311 void ObsVector::print(std::ostream & os) const {
312  double zmin = std::numeric_limits<double>::max();
313  double zmax = std::numeric_limits<double>::lowest();
314  double zrms = rms();
315  int nobs = this->nobs();
316  for (size_t jj = 0; jj < values_.size() ; ++jj) {
317  if (values_[jj] != missing_) {
318  if (values_[jj] < zmin) zmin = values_[jj];
319  if (values_[jj] > zmax) zmax = values_[jj];
320  }
321  }
322 
323  obsdb_.distribution()->min(zmin);
324  obsdb_.distribution()->max(zmax);
325 
326  if (nobs > 0) {
327  os << obsdb_.obsname() << " nobs= " << nobs << " Min="
328  << zmin << ", Max=" << zmax << ", RMS=" << zrms << std::endl;
329  } else {
330  os << obsdb_.obsname() << ": No observations." << std::endl;
331  }
332 }
333 // -----------------------------------------------------------------------------
334 } // namespace ioda
ObsDataVector<DATATYPE> handles vectors of data of type DATATYPE in observation space.
const ObsSpace & space() const
size_t nlocs() const
size_t nvars() const
Observation data class for IODA.
Definition: src/ObsSpace.h:116
void put_db(const std::string &group, const std::string &name, const std::vector< int > &vdata, const std::vector< std::string > &dimList={ "nlocs" })
transfer data from vdata to the obs container
Definition: ObsSpace.cc:306
std::shared_ptr< const Distribution > distribution() const
return MPI distribution object
Definition: src/ObsSpace.h:335
size_t nlocs() const
return the number of locations in the obs space. Note that nlocs may be smaller than global unique nl...
Definition: src/ObsSpace.h:176
void get_db(const std::string &group, const std::string &name, std::vector< int > &vdata, const std::vector< int > &chanSelect={ }) const
transfer data from the obs container to vdata
Definition: ObsSpace.cc:270
const std::string & obsname() const
return the name of the obs type being stored
Definition: src/ObsSpace.h:216
ObsVector class to handle vectors in observation space for IODA.
Definition: src/ObsVector.h:34
size_t packEigenSize(const ObsDataVector< int > &) const
Definition: ObsVector.cc:235
void read(const std::string &)
Definition: ObsVector.cc:194
std::size_t nlocs() const
Definition: src/ObsVector.h:93
void save(const std::string &) const
Definition: ObsVector.cc:217
ObsSpace & obsdb_
Associate ObsSpace object.
double rms() const
Definition: ObsVector.cc:186
void axpy(const double &beta, const ObsVector &y)
adds beta * y to the current vector
Definition: ObsVector.cc:121
ObsVector & operator*=(const double &)
Definition: ObsVector.cc:50
ObsVector & operator/=(const ObsVector &)
Definition: ObsVector.cc:98
ObsVector(ObsSpace &, const std::string &name="")
Definition: ObsVector.cc:25
void ones()
set all elements to one (used in tests)
Definition: ObsVector.cc:117
unsigned int nobs() const
Number of active observations (missing values not included) across all MPI tasks.
Definition: ObsVector.cc:297
ObsVector & operator=(const ObsVector &)
Definition: ObsVector.cc:45
std::size_t nlocs_
Eigen::VectorXd packEigen(const ObsDataVector< int > &) const
Definition: ObsVector.cc:247
ObsVector & operator-=(const ObsVector &)
Definition: ObsVector.cc:72
oops::Variables obsvars_
Variables.
const double & toFortran() const
Definition: ObsVector.cc:303
double dot_product_with(const ObsVector &other) const
global (across all MPI tasks) dot product of this with other
Definition: ObsVector.cc:164
void mask(const ObsDataVector< int > &)
Definition: ObsVector.cc:285
const double missing_
Missing data mark.
void print(std::ostream &) const
Definition: ObsVector.cc:311
std::vector< double > multivar_dot_product_with(const ObsVector &other) const
Definition: ObsVector.cc:169
std::vector< double > values_
Vector data.
ObsVector & operator+=(const ObsVector &)
Definition: ObsVector.cc:59
std::size_t nvars_
Number of variables.
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)