IODA
ObsSpace.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2017-2020 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/ObsSpace.h"
9 
10 #include <algorithm>
11 #include <memory>
12 #include <numeric>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "eckit/config/Configuration.h"
18 
19 #include "ioda/core/LocalObsSpaceParameters.h"
20 
21 #include "oops/util/abor1_cpp.h"
22 #include "oops/util/DateTime.h"
23 #include "oops/util/Duration.h"
24 #include "oops/util/Logger.h"
25 
26 #include "atlas/util/Earth.h"
27 
28 
29 namespace ioda {
30 
31 // -----------------------------------------------------------------------------
32 /*!
33  * \details Config based constructor for an ObsSpace object. This constructor will read
34  * in from the obs file and transfer the variables into the obs container. Obs
35  * falling outside the DA timing window, specified by bgn and end, will be
36  * discarded before storing them in the obs container.
37  *
38  * \param[in] config ECKIT configuration segment holding obs types specs
39  * \param[in] bgn DateTime object holding the start of the DA timing window
40  * \param[in] end DateTime object holding the end of the DA timing window
41  */
42 ObsSpace::ObsSpace(const eckit::Configuration & config, const eckit::mpi::Comm & comm,
43  const util::DateTime & bgn, const util::DateTime & end,
44  const eckit::mpi::Comm & time)
45  : oops::ObsSpaceBase(config, comm, bgn, end),
46  localopts_(), obsspace_(new ObsData(config, comm, bgn, end, time)),
47  localobs_(obsspace_->nlocs()), isLocal_(false),
48  obsdist_()
49 {
50  oops::Log::trace() << "ioda::ObsSpaces starting" << std::endl;
51  std::iota(localobs_.begin(), localobs_.end(), 0);
52  oops::Log::trace() << "ioda::ObsSpace done" << std::endl;
53 }
54 
55 // -----------------------------------------------------------------------------
56 /*!
57  * \details Second constructor for an ObsSpace object.
58  * This constructor will search for observations within a distance specified
59  * in the \p conf from a specified \p refPoint.
60  */
62  const eckit::geometry::Point2 & refPoint,
63  const eckit::Configuration & conf)
64  : oops::ObsSpaceBase(eckit::LocalConfiguration(), os.comm(), os.windowStart(), os.windowEnd()),
65  localopts_(new LocalObsSpaceParameters()), obsspace_(os.obsspace_),
66  localobs_(), isLocal_(true),
67  obsdist_()
68 {
69  oops::Log::trace() << "ioda::ObsSpace for LocalObs starting" << std::endl;
70  localopts_->deserialize(conf);
71 
72  if ( localopts_->searchMethod == SearchMethod::BRUTEFORCE ) {
73  oops::Log::trace() << "ioda::ObsSpace searching via brute force" << std::endl;
74 
75  std::size_t nlocs = obsspace_->nlocs();
76  std::vector<float> lats(nlocs);
77  std::vector<float> lons(nlocs);
78 
79  // Get latitudes and longitudes of all observations.
80  obsspace_ -> get_db("MetaData", "longitude", lons);
81  obsspace_ -> get_db("MetaData", "latitude", lats);
82 
83  for (unsigned int jj = 0; jj < nlocs; ++jj) {
84  eckit::geometry::Point2 searchPoint(lons[jj], lats[jj]);
85  double localDist = localopts_->distance(refPoint, searchPoint);
86  if ( localDist < localopts_->lengthscale ) {
87  localobs_.push_back(jj);
88  obsdist_.push_back(localDist);
89  }
90  }
91  const boost::optional<int> & maxnobs = localopts_->maxnobs;
92  if ( (maxnobs != boost::none) && (localobs_.size() > *maxnobs ) ) {
93  for (unsigned int jj = 0; jj < localobs_.size(); ++jj) {
94  oops::Log::debug() << "Before sort [i, d]: " << localobs_[jj]
95  << " , " << obsdist_[jj] << std::endl;
96  }
97  // Construct a temporary paired vector to do the sorting
98  std::vector<std::pair<std::size_t, double>> localObsIndDistPair;
99  for (unsigned int jj = 0; jj < obsdist_.size(); ++jj) {
100  localObsIndDistPair.push_back(std::make_pair(localobs_[jj], obsdist_[jj]));
101  }
102 
103  // Use a lambda function to implement an ascending sort.
104  sort(localObsIndDistPair.begin(), localObsIndDistPair.end(),
105  [](const std::pair<std::size_t, double> & p1,
106  const std::pair<std::size_t, double> & p2){
107  return(p1.second < p2.second);
108  });
109 
110  // Unpair the sorted pair vector
111  for (unsigned int jj = 0; jj < obsdist_.size(); ++jj) {
112  localobs_[jj] = localObsIndDistPair[jj].first;
113  obsdist_[jj] = localObsIndDistPair[jj].second;
114  }
115 
116  // Truncate to maxNobs length
117  localobs_.resize(*maxnobs);
118  obsdist_.resize(*maxnobs);
119  }
120  } else {
121  oops::Log::trace() << "ioda::ObsSpace searching via KDTree" << std::endl;
122 
123  if ( localopts_->distanceType == DistanceType::CARTESIAN)
124  ABORT("ObsSpace:: search method must be 'brute_force' when using 'cartesian' distance");
125 
126  ObsData::KDTree & kdtree = obsspace_->getKDTree();
127 
128  // Using the radius of the earth
129  eckit::geometry::Point3 refPoint3D;
130  atlas::util::Earth::convertSphericalToCartesian(refPoint, refPoint3D);
131  double alpha = (localopts_->lengthscale / localopts_->radius_earth)/ 2.0; // angle in radians
132  double chordLength = 2.0*localopts_->radius_earth * sin(alpha); // search radius in 3D space
133 
134  auto closePoints = kdtree.findInSphere(refPoint3D, chordLength);
135 
136  // put closePoints back into localobs_ and obsdist_
137  for (unsigned int jj = 0; jj < closePoints.size(); ++jj) {
138  localobs_.push_back(closePoints[jj].payload()); // observation
139  obsdist_.push_back(closePoints[jj].distance()); // distance
140  }
141 
142  // The obs are sorted in the kdtree call
143  const boost::optional<int> & maxnobs = localopts_->maxnobs;
144  if ( (maxnobs != boost::none) && (localobs_.size() > *maxnobs ) ) {
145  // Truncate to maxNobs length
146  localobs_.resize(*maxnobs);
147  obsdist_.resize(*maxnobs);
148  }
149  }
150  oops::Log::trace() << "ioda::ObsSpace for LocalObs done" << std::endl;
151 }
152 
153 // -----------------------------------------------------------------------------
154 /*!
155  * \details Destructor for an ObsSpace object. This destructor will clean up the ObsSpace
156  * object and optionally write out the contents of the obs container into
157  * the output file. The save-to-file operation is invoked when an output obs
158  * file is specified in the ECKIT configuration segment associated with the
159  * ObsSpace object.
160  */
162  oops::Log::trace() << "ioda::~ObsSpace done" << std::endl;
163 }
164 
165 // -----------------------------------------------------------------------------
166 
167 void ObsSpace::get_db(const std::string & group, const std::string & name,
168  std::vector<int> & vdata) const {
169  if ( isLocal_ ) {
170  std::vector<int> vdataTmp(obsspace_ -> nlocs());
171  obsspace_->get_db(group, name, vdataTmp);
172  for (unsigned int ii = 0; ii < localobs_.size(); ++ii) {
173  vdata[ii] = vdataTmp[localobs_[ii]];
174  }
175  } else {
176  obsspace_->get_db(group, name, vdata);
177  }
178 }
179 
180 // -----------------------------------------------------------------------------
181 
182 void ObsSpace::get_db(const std::string & group, const std::string & name,
183  std::vector<float> & vdata) const {
184  if ( isLocal_ ) {
185  std::vector<float> vdataTmp(obsspace_->nlocs());
186  obsspace_->get_db(group, name, vdataTmp);
187  for (unsigned int ii = 0; ii < localobs_.size(); ++ii) {
188  vdata[ii] = vdataTmp[localobs_[ii]];
189  }
190  } else {
191  obsspace_->get_db(group, name, vdata);
192  }
193 }
194 
195 // -----------------------------------------------------------------------------
196 
197 void ObsSpace::get_db(const std::string & group, const std::string & name,
198  std::vector<double> & vdata) const {
199  if ( isLocal_ ) {
200  std::vector<double> vdataTmp(obsspace_->nlocs());
201  obsspace_->get_db(group, name, vdataTmp);
202  for (unsigned int ii = 0; ii < localobs_.size(); ++ii) {
203  vdata[ii] = vdataTmp[localobs_[ii]];
204  }
205  } else {
206  obsspace_->get_db(group, name, vdata);
207  }
208 }
209 
210 // -----------------------------------------------------------------------------
211 
212 void ObsSpace::get_db(const std::string & group, const std::string & name,
213  std::vector<std::string> & vdata) const {
214  if ( isLocal_ ) {
215  std::vector<std::string> vdataTmp(obsspace_->nlocs());
216  obsspace_->get_db(group, name, vdataTmp);
217  for (unsigned int ii = 0; ii < localobs_.size(); ++ii) {
218  vdata[ii] = vdataTmp[localobs_[ii]];
219  }
220  } else {
221  obsspace_->get_db(group, name, vdata);
222  }
223 }
224 
225 // -----------------------------------------------------------------------------
226 
227 void ObsSpace::get_db(const std::string & group, const std::string & name,
228  std::vector<util::DateTime> & vdata) const {
229  if ( isLocal_ ) {
230  std::vector<util::DateTime> vdataTmp(obsspace_->nlocs());
231  obsspace_->get_db(group, name, vdataTmp);
232  for (unsigned int ii = 0; ii < localobs_.size(); ++ii) {
233  vdata[ii] = vdataTmp[localobs_[ii]];
234  }
235  } else {
236  obsspace_->get_db(group, name, vdata);
237  }
238 }
239 
240 // -----------------------------------------------------------------------------
241 
242 void ObsSpace::put_db(const std::string & group, const std::string & name,
243  const std::vector<int> & vdata) {
244  obsspace_->put_db(group, name, vdata);
245 }
246 
247 // -----------------------------------------------------------------------------
248 
249 void ObsSpace::put_db(const std::string & group, const std::string & name,
250  const std::vector<float> & vdata) {
251  obsspace_->put_db(group, name, vdata);
252 }
253 
254 // -----------------------------------------------------------------------------
255 
256 void ObsSpace::put_db(const std::string & group, const std::string & name,
257  const std::vector<double> & vdata) {
258  obsspace_->put_db(group, name, vdata);
259 }
260 
261 // -----------------------------------------------------------------------------
262 
263 void ObsSpace::put_db(const std::string & group, const std::string & name,
264  const std::vector<std::string> & vdata) {
265  obsspace_->put_db(group, name, vdata);
266 }
267 
268 // -----------------------------------------------------------------------------
269 
270 void ObsSpace::put_db(const std::string & group, const std::string & name,
271  const std::vector<util::DateTime> & vdata) {
272  obsspace_->put_db(group, name, vdata);
273 }
274 
275 // -----------------------------------------------------------------------------
276 /*!
277  * \details This method checks for the existence of the group, name combination
278  * in the obs container. If the combination exists, "true" is returned,
279  * otherwise "false" is returned.
280  */
281 
282 bool ObsSpace::has(const std::string & group, const std::string & name) const {
283  return obsspace_->has(group, name);
284 }
285 
286 // -----------------------------------------------------------------------------
287 /*!
288  * \details This method returns the data type of the variable stored in the obs
289  * container.
290  */
291 
292 ObsDtype ObsSpace::dtype(const std::string & group, const std::string & name) const {
293  return obsspace_->dtype(group, name);
294 }
295 
296 // -----------------------------------------------------------------------------
297 /*!
298  * \details This method returns the setting of the YAML configuration
299  * parameter: obsdatain.obsgrouping.group variable
300  */
301 std::string ObsSpace::obs_group_var() const {
302  return obsspace_->obs_group_var();
303 }
304 
305 // -----------------------------------------------------------------------------
306 /*!
307  * \details This method returns the setting of the YAML configuration
308  * parameter: obsdatain.obsgrouping.sort variable
309  */
310 std::string ObsSpace::obs_sort_var() const {
311  return obsspace_->obs_sort_var();
312 }
313 
314 // -----------------------------------------------------------------------------
315 /*!
316  * \details This method returns the setting of the YAML configuration
317  * parameter: obsdatain.obsgrouping.sort order
318  */
319 std::string ObsSpace::obs_sort_order() const {
320  return obsspace_->obs_sort_order();
321 }
322 
323 
324 // -----------------------------------------------------------------------------
325 /*!
326  * \details This method returns the number of unique locations in the input
327  * obs file. Note that nlocs from the obs container may be smaller
328  * than nlocs from the input obs file due to the removal of obs outside
329  * the DA timing window and/or due to distribution of obs across
330  * multiple process elements.
331  */
332 std::size_t ObsSpace::gnlocs() const {
333  return obsspace_->gnlocs();
334 }
335 
336 // -----------------------------------------------------------------------------
337 /*!
338  * \details This method returns the number of unique locations in the obs
339  * container. Note that nlocs from the obs container may be smaller
340  * than nlocs from the input obs file due to the removal of obs outside
341  * the DA timing window and/or due to distribution of obs across
342  * multiple process elements.
343  */
344 std::size_t ObsSpace::nlocs() const {
345  if ( isLocal_ ) {
346  return localobs_.size();
347  } else {
348  return obsspace_->nlocs();
349  }
350 }
351 
352 // -----------------------------------------------------------------------------
353 /*!
354  * \details This method returns the number of unique records in the obs
355  * container. A record is an atomic unit of locations that belong
356  * together such as a single radiosonde sounding.
357  */
358 std::size_t ObsSpace::nrecs() const {
359  return obsspace_->nrecs();
360 }
361 
362 // -----------------------------------------------------------------------------
363 /*!
364  * \details This method returns the number of unique variables in the obs
365  * container. "Variables" refers to the quantities that can be
366  * assimilated as opposed to meta data.
367  */
368 std::size_t ObsSpace::nvars() const {
369  return obsspace_->nvars();
370 }
371 
372 // -----------------------------------------------------------------------------
373 /*!
374  * \details This method returns a reference to the record number vector
375  * data member. This is for read only access.
376  */
377 const std::vector<std::size_t> & ObsSpace::recnum() const {
378  return obsspace_->recnum();
379 }
380 
381 // -----------------------------------------------------------------------------
382 /*!
383  * \details This method returns a reference to the index vector
384  * data member. This is for read only access.
385  */
386 const std::vector<std::size_t> & ObsSpace::index() const {
387  return obsspace_->index();
388 }
389 
390 // -----------------------------------------------------------------------------
391 /*!
392  * \details This method returns the begin iterator associated with the
393  * recidx_ data member.
394  */
396  return obsspace_->recidx_begin();
397 }
398 
399 // -----------------------------------------------------------------------------
400 /*!
401  * \details This method returns the end iterator associated with the
402  * recidx_ data member.
403  */
405  return obsspace_->recidx_end();
406 }
407 
408 // -----------------------------------------------------------------------------
409 /*!
410  * \details This method returns a boolean value indicating whether the
411  * given record number exists in the recidx_ data member.
412  */
413 bool ObsSpace::recidx_has(const std::size_t RecNum) const {
414  return obsspace_->recidx_has(RecNum);
415 }
416 
417 // -----------------------------------------------------------------------------
418 /*!
419  * \details This method returns the current record number, pointed to by the
420  * given iterator, from the recidx_ data member.
421  */
422 std::size_t ObsSpace::recidx_recnum(const RecIdxIter & Irec) const {
423  return obsspace_->recidx_recnum(Irec);
424 }
425 
426 // -----------------------------------------------------------------------------
427 /*!
428  * \details This method returns the current vector, pointed to by the
429  * given iterator, from the recidx_ data member.
430  */
431 const std::vector<std::size_t> & ObsSpace::recidx_vector(const RecIdxIter & Irec) const {
432  return obsspace_->recidx_vector(Irec);
433 }
434 
435 // -----------------------------------------------------------------------------
436 /*!
437  * \details This method returns the current vector, pointed to by the
438  * given iterator, from the recidx_ data member.
439  */
440 const std::vector<std::size_t> & ObsSpace::recidx_vector(const std::size_t RecNum) const {
441  return obsspace_->recidx_vector(RecNum);
442 }
443 
444 // -----------------------------------------------------------------------------
445 /*!
446  * \details This method returns the all of the record numbers from the
447  * recidx_ data member (ie, all the key values) in a vector.
448  */
449 std::vector<std::size_t> ObsSpace::recidx_all_recnums() const {
450  return obsspace_->recidx_all_recnums();
451 }
452 
453 // -----------------------------------------------------------------------------
454 /*!
455  * \details This method provides a way to print an ObsSpace object in an output
456  * stream. It simply prints a dummy message for now.
457  */
458 void ObsSpace::print(std::ostream & os) const {
459  os << *obsspace_;
460 }
461 
462 
463 // -----------------------------------------------------------------------------
464 /*!
465  * \details This method provides a means for printing Jo in
466  * an output stream. For now a dummy message is printed.
467  */
468 void ObsSpace::printJo(const ObsVector & dy, const ObsVector & grad) {
469  obsspace_->printJo(dy, grad);
470 }
471 
472 // -----------------------------------------------------------------------------
473 
474 } // namespace ioda
ioda::ObsSpace::obs_group_var
std::string obs_group_var() const
Definition: ObsSpace.cc:301
ioda::ObsSpace::recnum
const std::vector< std::size_t > & recnum() const
Definition: ObsSpace.cc:377
ioda::ObsSpace::obs_sort_var
std::string obs_sort_var() const
Definition: ObsSpace.cc:310
ioda::ObsSpace::print
void print(std::ostream &) const
Definition: ObsSpace.cc:458
ioda::ObsSpace::get_db
void get_db(const std::string &group, const std::string &name, std::vector< int > &vdata) const
Definition: ObsSpace.cc:167
oops
Definition: LocalObsSpaceParameters.h:58
ioda::ObsSpace::obsspace_
std::shared_ptr< ObsData > obsspace_
Definition: src/ObsSpace.h:114
ioda::ObsSpace::index
const std::vector< std::size_t > & index() const
Definition: ObsSpace.cc:386
ioda::ObsSpace::nrecs
std::size_t nrecs() const
Definition: ObsSpace.cc:358
ioda::ObsSpace::has
bool has(const std::string &, const std::string &) const
Definition: ObsSpace.cc:282
ObsSpace.h
ioda::ObsSpace::recidx_begin
const RecIdxIter recidx_begin() const
Definition: ObsSpace.cc:395
ioda::ObsSpace::localopts_
std::unique_ptr< LocalObsSpaceParameters > localopts_
Definition: src/ObsSpace.h:115
ioda::ObsSpace::recidx_recnum
std::size_t recidx_recnum(const RecIdxIter &Irec) const
Definition: ObsSpace.cc:422
ioda::ObsSpace::recidx_has
bool recidx_has(const std::size_t RecNum) const
Definition: ObsSpace.cc:413
ioda::ObsData
Observation Data.
Definition: ObsData.h:87
ioda::DistanceType::CARTESIAN
@ CARTESIAN
ioda::ObsSpace::obs_sort_order
std::string obs_sort_order() const
Definition: ObsSpace.cc:319
ioda
Definition: IodaUtils.cc:13
ioda::ObsSpace::obsdist_
std::vector< double > obsdist_
Definition: src/ObsSpace.h:118
ioda::ObsSpace::isLocal_
bool isLocal_
Definition: src/ObsSpace.h:117
ioda::ObsVector
ObsVector class to handle vectors in observation space for IODA.
Definition: src/ObsVector.h:34
ioda::ObsSpace::printJo
void printJo(const ObsVector &, const ObsVector &)
Definition: ObsSpace.cc:468
eckit
Definition: LocalObsSpaceParameters.h:24
ioda::SearchMethod::BRUTEFORCE
@ BRUTEFORCE
ioda::ObsSpace::recidx_vector
const std::vector< std::size_t > & recidx_vector(const RecIdxIter &Irec) const
Definition: ObsSpace.cc:431
ioda::ObsSpace::recidx_all_recnums
std::vector< std::size_t > recidx_all_recnums() const
Definition: ObsSpace.cc:449
ioda::ObsSpace::nlocs
std::size_t nlocs() const
Definition: ObsSpace.cc:344
ioda::ObsSpace::dtype
ObsDtype dtype(const std::string &, const std::string &) const
Definition: ObsSpace.cc:292
ioda::ObsSpace::RecIdxIter
RecIdxMap::const_iterator RecIdxIter
Definition: src/ObsSpace.h:39
ioda::LocalObsSpaceParameters
Options controlling local observations subsetting.
Definition: LocalObsSpaceParameters.h:78
ioda::ObsSpace::put_db
void put_db(const std::string &group, const std::string &name, const std::vector< int > &vdata)
Definition: ObsSpace.cc:242
ioda::ObsDtype
ObsDtype
Definition: ObsData.h:63
ioda::ObsSpace::recidx_end
const RecIdxIter recidx_end() const
Definition: ObsSpace.cc:404
ioda::ObsData::KDTree
eckit::KDTreeMemory< TreeTrait > KDTree
Definition: ObsData.h:95
ioda::ObsSpace::gnlocs
std::size_t gnlocs() const
Definition: ObsSpace.cc:332
ioda::ObsSpace::ObsSpace
ObsSpace(const eckit::Configuration &, const eckit::mpi::Comm &, const util::DateTime &, const util::DateTime &, const eckit::mpi::Comm &)
Definition: ObsSpace.cc:42
ioda::ObsSpace::nvars
std::size_t nvars() const
Definition: ObsSpace.cc:368
ioda::ObsSpace::~ObsSpace
~ObsSpace()
Definition: ObsSpace.cc:161
ioda::ObsSpace
Observation Space View.
Definition: src/ObsSpace.h:35
ioda::ObsSpace::localobs_
std::vector< std::size_t > localobs_
Definition: src/ObsSpace.h:116