IODA Bundle
ObsTable.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2009-2016 ECMWF.
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  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #include "lorenz95/ObsTable.h"
12 
13 #include <algorithm>
14 #include <cmath>
15 #include <fstream>
16 #include <iostream>
17 #include <map>
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "eckit/config/LocalConfiguration.h"
24 #include "eckit/exception/Exceptions.h"
25 
26 #include "lorenz95/ObsIterator.h"
27 #include "oops/mpi/mpi.h"
28 #include "oops/util/abor1_cpp.h"
29 #include "oops/util/DateTime.h"
30 #include "oops/util/Duration.h"
31 #include "oops/util/Logger.h"
32 #include "oops/util/missingValues.h"
33 #include "oops/util/Random.h"
34 #include "oops/util/stringFunctions.h"
35 
36 namespace sf = util::stringfunctions;
37 
38 // -----------------------------------------------------------------------------
39 namespace lorenz95 {
40 // -----------------------------------------------------------------------------
41 
42 ObsTable::ObsTable(const eckit::Configuration & config, const eckit::mpi::Comm & comm,
43  const util::DateTime & bgn, const util::DateTime & end,
44  const eckit::mpi::Comm & timeComm)
45  : oops::ObsSpaceBase(config, comm, bgn, end), winbgn_(bgn), winend_(end), comm_(timeComm),
46  obsvars_()
47 {
48  oops::Log::trace() << "ObsTable::ObsTable starting" << std::endl;
49  nameIn_.clear();
50  nameOut_.clear();
51  if (config.has("obsdatain")) {
52  nameIn_ = config.getString("obsdatain");
53  otOpen(nameIn_);
54  }
55  // Generate locations etc... if required
56  if (config.has("generate")) {
57  const eckit::LocalConfiguration gconf(config, "generate");
58  generateDistribution(gconf);
59  }
60  if (config.has("obsdataout")) {
61  nameOut_ = config.getString("obsdataout");
62  sf::swapNameMember(config, nameOut_);
63  }
64  oops::Log::trace() << "ObsTable::ObsTable created nobs = " << nobs() << std::endl;
65 }
66 
67 // -----------------------------------------------------------------------------
68 
70  oops::Log::trace() << "ObsTable::ObsTable destructed" << std::endl;
71 }
72 
73 // -----------------------------------------------------------------------------
74 
75 void ObsTable::save() const {
76  if (!nameOut_.empty()) otWrite(nameOut_);
77 }
78 
79 // -----------------------------------------------------------------------------
80 
81 bool ObsTable::has(const std::string & col) const {
82  return (data_.find(col) != data_.end());
83 }
84 
85 // -----------------------------------------------------------------------------
86 
87 void ObsTable::putdb(const std::string & col, const std::vector<int> & vec) const {
88  std::vector<double> tmp(vec.size());
89  int intmiss = util::missingValue(int());
90  double doublemiss = util::missingValue(double());
91  for (size_t jobs = 0; jobs < vec.size(); ++jobs) {
92  if (vec[jobs] == intmiss) {
93  tmp[jobs] = doublemiss;
94  } else {
95  tmp[jobs] = static_cast<double>(vec[jobs]);
96  }
97  }
98  this->putdb(col, tmp);
99 }
100 
101 // -----------------------------------------------------------------------------
102 
103 void ObsTable::putdb(const std::string & col, const std::vector<float> & vec) const {
104  std::vector<double> tmp(vec.size());
105  float floatmiss = util::missingValue(float());
106  double doublemiss = util::missingValue(double());
107  for (size_t jobs = 0; jobs < vec.size(); ++jobs) {
108  if (vec[jobs] == floatmiss) {
109  tmp[jobs] = doublemiss;
110  } else {
111  tmp[jobs] = static_cast<double>(vec[jobs]);
112  }
113  }
114  this->putdb(col, tmp);
115 }
116 
117 // -----------------------------------------------------------------------------
118 
119 void ObsTable::putdb(const std::string & col, const std::vector<double> & vec) const {
120  ASSERT(vec.size() == nobs());
121  if (data_.find(col) != data_.end()) {
122  oops::Log::info() << "ObsTable::putdb over-writing " << col << std::endl;
123  data_[col] = vec;
124  } else {
125  data_.insert(std::pair<std::string, std::vector<double> >(col, vec));
126  }
127 }
128 
129 // -----------------------------------------------------------------------------
130 
131 void ObsTable::getdb(const std::string & col, std::vector<int> & vec) const {
132  std::vector<double> tmp;
133  this->getdb(col, tmp);
134  int intmiss = util::missingValue(int());
135  double doublemiss = util::missingValue(double());
136  vec.resize(nobs());
137  for (size_t jobs = 0; jobs < nobs(); ++jobs) {
138  if (tmp[jobs] == doublemiss) {
139  vec[jobs] = intmiss;
140  } else {
141  vec[jobs] = lround(tmp[jobs]);
142  }
143  }
144 }
145 
146 // -----------------------------------------------------------------------------
147 
148 void ObsTable::getdb(const std::string & col, std::vector<float> & vec) const {
149  std::vector<double> tmp;
150  this->getdb(col, tmp);
151  float floatmiss = util::missingValue(float());
152  double doublemiss = util::missingValue(double());
153  vec.resize(nobs());
154  for (size_t jobs = 0; jobs < nobs(); ++jobs) {
155  if (tmp[jobs] == doublemiss) {
156  vec[jobs] = floatmiss;
157  } else {
158  vec[jobs] = static_cast<float>(tmp[jobs]);
159  }
160  }
161 }
162 
163 // -----------------------------------------------------------------------------
164 
165 void ObsTable::getdb(const std::string & col, std::vector<double> & vec) const {
166  std::map<std::string, std::vector<double> >::const_iterator ic = data_.find(col);
167  if (ic == data_.end()) {
168  oops::Log::error() << "ObsTable::getdb " << col << " not found." << std::endl;
169  ABORT("ObsTable::getdb column not found");
170  }
171  vec.resize(nobs());
172  for (unsigned int jobs = 0; jobs < nobs(); ++jobs) {
173  vec[jobs] = ic->second[jobs];
174  }
175 }
176 
177 // -----------------------------------------------------------------------------
178 
179 void ObsTable::generateDistribution(const eckit::Configuration & config) {
180  oops::Log::trace() << "ObsTable::generateDistribution starting" << std::endl;
181 
182  util::Duration first(config.getString("begin"));
183  util::Duration last(winend_-winbgn_);
184  if (config.has("end")) {
185  last = util::Duration(config.getString("end"));
186  }
187  util::Duration freq(config.getString("obs_frequency"));
188 
189  int nobstimes = 0;
190  util::Duration step(first);
191  while (step <= last) {
192  ++nobstimes;
193  step += freq;
194  }
195 
196  const unsigned int nobs_locations = config.getInt("obs_density");
197  const unsigned int nobs = nobs_locations*nobstimes;
198  double dx = 1.0/static_cast<double>(nobs_locations);
199 
200  times_.resize(nobs);
201  locations_.resize(nobs);
202 
203  unsigned int iobs = 0;
204  util::DateTime now(winbgn_);
205  step = first;
206  while (step <= last) {
207  now = winbgn_ + step;
208  for (unsigned int jobs = 0; jobs < nobs_locations; ++jobs) {
209  double xpos = jobs*dx;
210  times_[iobs] = now;
211  locations_[iobs] = xpos;
212  ++iobs;
213  }
214  step += freq;
215  }
216  ASSERT(iobs == nobs);
217 
218 // Generate obs error
219  const double err = config.getDouble("obs_error");
220  std::vector<double> obserr(nobs);
221  for (unsigned int jj = 0; jj < nobs; ++jj) {
222  obserr[jj] = err;
223  }
224  this->putdb("ObsError", obserr);
225 
226  oops::Log::trace() << "ObsTable::generateDistribution done, nobs= " << nobs << std::endl;
227 }
228 
229 // -----------------------------------------------------------------------------
230 
231 void ObsTable::random(std::vector<double> & data) const {
232  util::NormalDistribution<double> x(data.size(), 0.0, 1.0, getSeed());
233  for (size_t jj = 0; jj < data.size(); ++jj) data[jj] = x[jj];
234 }
235 
236 // -----------------------------------------------------------------------------
237 // ObsTable Private Methods
238 // -----------------------------------------------------------------------------
239 
240 void ObsTable::otOpen(const std::string & filename) {
241  oops::Log::trace() << "ObsTable::ot_read starting" << std::endl;
242  std::ifstream fin(filename.c_str());
243  if (!fin.is_open()) ABORT("ObsTable::otOpen: Error opening file: " + filename);
244 
245  int ncol, nobs;
246  fin >> ncol;
247 
248  std::vector<std::string> colnames;
249  for (int jc = 0; jc < ncol; ++jc) {
250  std::string col;
251  fin >> col;
252  colnames.push_back(col);
253  }
254 
255  fin >> nobs;
256  locations_.clear();
257  std::vector<double> newcol;
258  for (int jc = 0; jc < ncol; ++jc) {
259  ASSERT(data_.find(colnames[jc]) == data_.end());
260  data_.insert(std::pair<std::string, std::vector<double> >(colnames[jc], newcol));
261  }
262 
263  times_.clear();
264  for (int jobs = 0; jobs < nobs; ++jobs) {
265  int jjj;
266  fin >> jjj;
267  ASSERT(jjj == jobs);
268  std::string sss;
269  fin >> sss;
270  util::DateTime ttt(sss);
271  bool inside = ttt > winbgn_ && ttt <= winend_;
272 
273  if (inside) times_.push_back(ttt);
274  double loc;
275  fin >> loc;
276  if (inside) locations_.push_back(loc);
277  for (std::map<std::string, std::vector<double> >::iterator jo = data_.begin();
278  jo != data_.end(); ++jo) {
279  double val;
280  fin >> val;
281  if (inside) jo->second.push_back(val);
282  }
283  }
284 
285  fin.close();
286  oops::Log::trace() << "ObsTable::ot_read done" << std::endl;
287 }
288 
289 // -----------------------------------------------------------------------------
290 
291 void ObsTable::otWrite(const std::string & filename) const {
292  oops::Log::trace() << "ObsTable::otWrite writing " << filename << std::endl;
293 
294  const size_t ioproc = 0;
295 
296  int nobs = times_.size();
297  if (comm_.size() > 1) comm_.allReduceInPlace(nobs, eckit::mpi::Operation::SUM);
298 
299  std::vector<util::DateTime> timebuff(nobs);
300  oops::mpi::gather(comm_, times_, timebuff, ioproc);
301 
302  std::vector<double> locbuff(nobs);
303  oops::mpi::gather(comm_, locations_, locbuff, ioproc);
304 
305  std::vector<double> datasend(times_.size() * data_.size());
306  size_t iobs = 0;
307  for (size_t jobs = 0; jobs < times_.size(); ++jobs) {
308  for (auto jo = data_.begin(); jo != data_.end(); ++jo) {
309  datasend[iobs] = jo->second[jobs];
310  ++iobs;
311  }
312  }
313  std::vector<double> databuff(data_.size() * nobs);
314  oops::mpi::gather(comm_, datasend, databuff, ioproc);
315 
316  if (comm_.rank() == ioproc) {
317  std::ofstream fout(filename.c_str());
318  if (!fout.is_open()) ABORT("ObsTable::otWrite: Error opening file: " + filename);
319 
320  int ncol = data_.size();
321  fout << ncol << std::endl;
322 
323  for (auto jo = data_.begin(); jo != data_.end(); ++jo)
324  fout << jo->first << std::endl;
325 
326  fout << nobs << std::endl;
327 
328  size_t iii = 0;
329  for (int jobs = 0; jobs < nobs; ++jobs) {
330  fout << jobs;
331  fout << " " << timebuff[jobs];
332  fout << " " << locbuff[jobs];
333  for (int jcol = 0; jcol < ncol; ++jcol) {
334  fout << " " << databuff[iii];
335  ++iii;
336  }
337  fout << std::endl;
338  }
339 
340  fout.close();
341  }
342 
343  oops::Log::trace() << "ObsTable::otWrite done" << std::endl;
344 }
345 
346 // -----------------------------------------------------------------------------
348  return ObsIterator(locations_, 0);
349 }
350 // -----------------------------------------------------------------------------
352  return ObsIterator(locations_, locations_.size());
353 }
354 // -----------------------------------------------------------------------------
355 
356 void ObsTable::print(std::ostream & os) const {
357  os << "ObsTable: assimilation window = " << winbgn_ << " to " << winend_ << std::endl;
358  os << "ObsTable: file in = " << nameIn_ << ", file out = " << nameOut_;
359 }
360 
361 // -----------------------------------------------------------------------------
362 
363 } // namespace lorenz95
Iterator over all observations.
void random(std::vector< double > &) const
Definition: ObsTable.cc:231
std::vector< double > locations_
Definition: ObsTable.h:81
void print(std::ostream &) const
Definition: ObsTable.cc:356
std::string nameIn_
Definition: ObsTable.h:86
bool has(const std::string &col) const
Definition: ObsTable.cc:81
void getdb(const std::string &, std::vector< int > &) const
Definition: ObsTable.cc:131
unsigned int nobs() const
Definition: ObsTable.h:61
void otWrite(const std::string &) const
Definition: ObsTable.cc:291
const eckit::mpi::Comm & comm_
Definition: ObsTable.h:84
ObsIterator begin() const
iterator to the first observation
Definition: ObsTable.cc:347
const util::DateTime winbgn_
Definition: ObsTable.h:77
void save() const
Definition: ObsTable.cc:75
const util::DateTime winend_
Definition: ObsTable.h:78
std::map< std::string, std::vector< double > > data_
Definition: ObsTable.h:82
ObsIterator end() const
iterator to the observation past-the-last
Definition: ObsTable.cc:351
ObsTable(const eckit::Configuration &, const eckit::mpi::Comm &, const util::DateTime &, const util::DateTime &, const eckit::mpi::Comm &)
Definition: ObsTable.cc:42
std::string nameOut_
Definition: ObsTable.h:87
void generateDistribution(const eckit::Configuration &)
Definition: ObsTable.cc:179
std::vector< util::DateTime > times_
Definition: ObsTable.h:80
void otOpen(const std::string &)
Definition: ObsTable.cc:240
void putdb(const std::string &, const std::vector< int > &) const
Definition: ObsTable.cc:87
int64_t getSeed() const
Definition: ObsSpaceBase.h:42
The namespace for the L95 model.
void gather(const eckit::mpi::Comm &comm, const std::vector< double > &send, std::vector< double > &recv, const size_t root)
Definition: oops/mpi/mpi.cc:96
The namespace for the main oops code.