UFO
ProfileIndices.cc
Go to the documentation of this file.
1 /*
2  * (C) Crown copyright 2020, 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 <algorithm>
9 #include <utility>
10 
12 
13 namespace ufo {
14  ProfileIndices::ProfileIndices(ioda::ObsSpace &obsdb,
15  const DataHandlerParameters &options,
16  const std::vector <bool> &apply)
17  : obsdb_(obsdb),
18  options_(options),
19  apply_(apply),
20  profileNums_(obsdb.recnum())
21  {
22  this->reset();
23 
24  // Determine unique profile numbers.
25  uniqueProfileNums_.insert(profileNums_.begin(), profileNums_.end());
26 
27  // If not sorting observations, ensure number of profiles is consistent
28  // with quantity reported by obsdb.
29  // (If sorting is imposed, nothing is assumed about the ordering of the input data
30  // so this validation should not be performed.)
31  if (!profileNums_.empty() &&
32  obsdb_.obs_sort_var().empty() &&
35  }
36  }
37 
39  {
40  // Do not proceed if there are no profiles on the current processor.
41  if (profileNums_.empty())
42  return;
43 
46  profIndex_ = 0;
47 
48  // If sorting observations, point to beginning of record index iterator
49  if (!obsdb_.obs_sort_var().empty() &&
50  obsdb_.obs_sort_order() == "descending") {
51  profidx_current_ = obsdb_.recidx_begin();
52  }
53  }
54 
56  {
57  profileIndices_.clear();
58 
59  // Do not proceed if there are no profiles on the current processor.
60  if (profileNums_.empty()) {
61  oops::Log::debug() << "No profiles found in the sample" << std::endl;
62  return;
63  }
64 
65  // Determine indices in the full sample that correspond to
66  // the profile ID to be found.
67  // The method used to fill the profile indices depends upon the sorting chosen.
68  if (obsdb_.obs_sort_var().empty()) {
69  // If no sorting has been specified just increment indices
71  if (apply_[profIndex_]) {
72  profileIndices_.emplace_back(profIndex_);
73  }
74  profIndex_++;
75  }
76  } else {
77  if (obsdb_.obs_sort_order() == "descending") {
78  // Sort variable (usually pressure) in descending order
79  // Sorted indices for the current profile
80  const std::vector<std::size_t> profidx_sorted = profidx_current_->second;
81  auto it_profidx_sorted = profidx_sorted.begin();
83  if (apply_[profIndex_]) {
84  profileIndices_.emplace_back(*it_profidx_sorted);
85  }
86  profIndex_++;
87  std::advance(it_profidx_sorted, 1);
88  }
89  } else {
90  // This will not work for pressures in ascending order
91  throw eckit::BadParameter("sort order is ascending.", Here());
92  }
93  }
94 
95  // Number of levels to which QC checks should be applied
96  numProfileLevels_ = static_cast<int> (profileIndices_.size());
97 
98  if (numProfileLevels_ > 0) {
99  oops::Log::debug() << "First and last profile indices: " << profileIndices_.front()
100  << ", " << profileIndices_.back() << std::endl;
101  }
102 
103  // Replace with maxlev if defined (a legacy of the OPS code)
104  if (options_.maxlev.value() != boost::none) {
105  numProfileLevels_ = std::min(options_.maxlev.value().get(), numProfileLevels_);
106  }
107 
108  // Update counters and iterators (if used)
109 
110  // Current profile number
112 
113  // Return value indicates whether or not the end of the entire sample has been reached
114  if (profIndex_ < profileNums_.size()) {
115  // Next profile number to find
117  // Iterator corresponding to next profile
118  if (!obsdb_.obs_sort_var().empty() &&
119  obsdb_.obs_sort_order() == "descending") {
120  std::advance(profidx_current_, 1);
121  }
122  }
123  }
124 
126  {
127  const auto &it = uniqueProfileNums_.find(profileNumCurrent_);
128  return std::distance(uniqueProfileNums_.begin(), it);
129  }
130 
132  // If no sorting is performed on the observations it is possible that
133  // two separate profiles could (inadvertently) have the same value of the group variable.
134  // This would lead to an incorrect value of nrecs.
135  // This routine ensures that nrecs is the same as the actual number of profiles in the sample.
136 
137  size_t profNum = profileNums_[0];
138  std::vector <size_t> allProfileNums = {profNum};
139  for (size_t j = 0; j < profileNums_.size(); ++j) {
140  size_t profNum_j = profileNums_[j];
141  if (profNum_j != profNum) {
142  allProfileNums.emplace_back(profNum_j);
143  profNum = profNum_j;
144  }
145  }
146 
147  if (allProfileNums.size() != obsdb_.nrecs()) {
148  throw eckit::BadValue("incorrect number of profiles in unsorted sample", Here());
149  }
150  }
151 } // namespace ufo
Options controlling the operation of the EntireSampleDataHandler and ProfileDataHandler classes.
oops::OptionalParameter< int > maxlev
oops::Parameter< bool > ValidateTotalNumProf
If not sorting observations, ensure number of profiles is consistent.
size_t profileNumToFind_
Next profile number to find in the sample.
ProfileIndices(ioda::ObsSpace &obsdb, const DataHandlerParameters &options, const std::vector< bool > &apply)
const std::vector< bool > & apply_
Observations to apply the filter to.
int numProfileLevels_
Number of profile levels to which QC checks should be applied.
ioda::ObsSpace & obsdb_
Observation database.
void validateTotalNumProf()
Ensure number of profiles is consistent with quantity reported by obsdb.
size_t profileNumCurrent_
Current profile number in the sample.
std::set< size_t > uniqueProfileNums_
Unique profile numbers for the entire sample.
ProfIdxIter profidx_current_
Iterator pointing to current profile index (initially points to beginning).
const std::vector< size_t > profileNums_
Profile numbers for the entire sample.
size_t getProfileNumCurrent() const
Get number of current profile, accounting for distribution across processors.
const DataHandlerParameters & options_
Configurable parameters.
void updateNextProfileIndices()
Determine indices in entire sample for the next profile.
void reset()
Reset profile indices to point to the beginning of the sample.
std::vector< size_t > profileIndices_
Indices for this profile.
float distance(const Point &a, const Point &b)
Returns the distance between the two cartesian-mapped Point arguments
Definition: RunCRTM.h:27