UFO
TemporalThinning.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019 Met Office UK
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 
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <functional>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "eckit/config/Configuration.h"
18 #include "ioda/ObsDataVector.h"
19 #include "ioda/ObsSpace.h"
20 #include "oops/base/Variables.h"
21 #include "oops/util/DateTime.h"
22 #include "oops/util/Duration.h"
23 #include "oops/util/Logger.h"
26 
27 namespace ufo {
28 
29 namespace {
30 
31 struct Observation {
32  size_t id;
33  util::DateTime time;
34  int priority = 0;
35 };
36 
37 /// \brief Responsible for the selection of observations to retain.
39  public:
40  TemporalThinner(const std::vector<size_t> &validObsIds,
41  const std::vector<util::DateTime> &times,
42  const std::vector<int> *priorities,
43  const RecursiveSplitter &splitter,
44  const TemporalThinningParameters &options);
45 
46  std::vector<bool> identifyThinnedObservations(size_t totalNumObservations) const;
47 
48  private:
49  typedef std::vector<size_t>::const_iterator ForwardValidObsIndexIterator;
50  typedef std::vector<size_t>::const_reverse_iterator BackwardValidObsIndexIterator;
51 
52  Observation getObservation(size_t validObsIndex) const {
53  Observation obs;
54  obs.id = validObsIds_[validObsIndex];
55  obs.time = times_[obs.id];
56  if (priorities_)
57  obs.priority = (*priorities_)[obs.id];
58  return obs;
59  }
60 
61  util::DateTime getTime(size_t validObsIndex) const {
62  return times_[validObsIds_[validObsIndex]];
63  }
64 
65  int getPriority(size_t validObsIndex) const {
66  ASSERT(priorities_ != nullptr);
67  return (*priorities_)[validObsIds_[validObsIndex]];
68  }
69 
70  bool hasPriorities() const {
71  return priorities_ != nullptr;
72  }
73 
74  /// Thin the valid observations with indices from the specified range. The first observation
75  /// to retain must be taken at or after \p deadline.
76  void thinRangeForwards(ForwardValidObsIndexIterator validIndicesBegin,
77  ForwardValidObsIndexIterator validIndicesEnd,
78  util::DateTime deadline,
79  std::vector<bool> &isThinned) const;
80 
81  /// Thin the valid observations with indices from the specified range. The first observation
82  /// to retain must be taken at or before \p deadline.
83  void thinRangeBackwards(BackwardValidObsIndexIterator validIndicesBegin,
84  BackwardValidObsIndexIterator validIndicesEnd,
85  util::DateTime deadline,
86  std::vector<bool> &isThinned) const;
87 
88  /// \brief Common implementation shared by thinRangeForwards() and thinRangeBackwards().
89  ///
90  /// \tparam Iterator
91  /// Iterator visiting indices of observations in chronological (reverse chronological) order
92  /// when thinning forwards (backwards).
93  /// \tparam IsPast
94  /// Binary functor taking two parameters of type util::DateTime and returning true if and only
95  /// if the first argument is later (earlier) than the second when thinning forwards (backwards).
96  /// \tparam IsAtOrPast
97  /// Binary functor taking two parameters of type util::DateTime and returning true if and only
98  /// if the first argument is later (earlier) than or equal to the second when thinning forwards
99  /// (backwards).
100  /// \tparam Advance
101  /// Binary functor taking two parameters of types util::DateTime and util::Duration and
102  /// returning the datetime obtained by adding (subtracting) the second argument to (from) the
103  /// first argument when thinning forwards (backwards).
104  template <typename Iterator, typename IsPast, typename IsAtOrPast, typename Advance>
105  void thinRange(Iterator validIndicesBegin,
106  Iterator validIndicesEnd,
107  util::DateTime deadline,
108  IsPast isPast,
109  IsAtOrPast isAtOrPast,
110  Advance advance,
111  std::vector<bool> &isThinned) const;
112 
113  /// Return an iterator to the first observation to be retained.
114  ForwardValidObsIndexIterator findSeed(
115  ForwardValidObsIndexIterator validObsIndicesBegin,
116  ForwardValidObsIndexIterator validObsIndicesEnd,
117  util::DateTime seedTime) const;
118 
119  /// Return an iterator to the valid observation taken at a time closest to \p targetTime.
120  /// In case of a tie, the later (more recent) observation is selected.
121  ForwardValidObsIndexIterator findNearest(
122  ForwardValidObsIndexIterator validObsIndicesBegin,
123  ForwardValidObsIndexIterator validObsIndicesEnd,
124  util::DateTime targetTime) const;
125 
126  private:
127  const std::vector<size_t> &validObsIds_;
128  const std::vector<util::DateTime> &times_;
129  const std::vector<int> *priorities_;
132 };
133 
134 TemporalThinner::TemporalThinner(const std::vector<size_t> &validObsIds,
135  const std::vector<util::DateTime> &times,
136  const std::vector<int> *priorities,
137  const RecursiveSplitter &splitter,
138  const TemporalThinningParameters &options) :
139  validObsIds_(validObsIds),
140  times_(times),
141  priorities_(priorities),
142  splitter_(splitter),
143  options_(options)
144 {}
145 
146 std::vector<bool> TemporalThinner::identifyThinnedObservations(size_t totalNumObservations) const {
147  std::vector<bool> isThinned(totalNumObservations, false);
148 
150  if (options_.seedTime.value() == boost::none) {
151  util::DateTime deadline = getTime(*group.begin());
152  thinRangeForwards(group.begin(), group.end(), deadline, isThinned);
153  } else {
154  const ForwardValidObsIndexIterator seedIt = findSeed(
155  group.begin(), group.end(), *options_.seedTime.value());
156  Observation seed = getObservation(*seedIt);
157  {
158  util::DateTime deadline = seed.time + options_.minSpacing;
159  thinRangeForwards(seedIt + 1, group.end(), deadline, isThinned);
160  }
161  {
162  const BackwardValidObsIndexIterator seedRevIt(seedIt + 1);
163  const BackwardValidObsIndexIterator revEnd(group.begin());
164  util::DateTime deadline = seed.time - options_.minSpacing;
165  thinRangeBackwards(seedRevIt, revEnd, seed.time, isThinned);
166  }
167  }
168  }
169 
170  return isThinned;
171 }
172 
174  ForwardValidObsIndexIterator validIndicesEnd,
175  util::DateTime deadline,
176  std::vector<bool> &isThinned) const {
177  thinRange(validIndicesBegin, validIndicesEnd, deadline,
178  std::greater<util::DateTime>(),
179  std::greater_equal<util::DateTime>(),
180  // Unfortunately in C++11 std::plus requires both arguments to be of the same type
181  [](const util::DateTime &time, const util::Duration &offset) { return time + offset; },
182  isThinned);
183 }
184 
186  BackwardValidObsIndexIterator validIndicesBegin,
187  BackwardValidObsIndexIterator validIndicesEnd,
188  util::DateTime deadline,
189  std::vector<bool> &isThinned) const {
190  thinRange(validIndicesBegin, validIndicesEnd, deadline,
191  std::less<util::DateTime>(),
192  std::less_equal<util::DateTime>(),
193  [](const util::DateTime &time, const util::Duration &offset) { return time - offset; },
194  isThinned);
195 }
196 
197 template <typename Iterator, typename IsPast, typename IsAtOrPast, typename Advance>
198 void TemporalThinner::thinRange(Iterator validIndicesBegin,
199  Iterator validIndicesEnd,
200  util::DateTime deadline,
201  IsPast isPast,
202  IsAtOrPast isAtOrPast,
203  Advance advance,
204  std::vector<bool> &isThinned) const {
205  boost::optional<Observation> best;
206  for (Iterator it = validIndicesBegin; it != validIndicesEnd; ++it) {
207  const size_t validObsIndex = *it;
208  Observation current = getObservation(validObsIndex);
209  if (best != boost::none) {
210  // We're looking for a higher-priority observation at or before the deadline
211  if (isPast(current.time, deadline)) {
212  // We haven't found one
213  deadline = advance(best->time, options_.minSpacing);
214  best = boost::none;
215  // The decision whether to thin 'current' will be taken in the next if statement
216  } else {
217  if (current.priority > best->priority) {
218  isThinned[best->id] = true;
219  best = current;
220  } else {
221  isThinned[current.id] = true;
222  }
223  }
224  }
225 
226  if (best == boost::none) {
227  // We're looking for an observation at or after the deadline
228  if (isAtOrPast(current.time, deadline)) {
229  best = current;
230  deadline = advance(best->time, options_.tolerance);
231  } else {
232  isThinned[current.id] = true;
233  }
234  }
235  }
236 }
237 
239  ForwardValidObsIndexIterator validObsIndicesBegin,
240  ForwardValidObsIndexIterator validObsIndicesEnd,
241  util::DateTime seedTime) const {
242  const ForwardValidObsIndexIterator nearestToSeedIt = findNearest(
243  validObsIndicesBegin, validObsIndicesEnd, seedTime);
244  if (!hasPriorities()) {
245  return nearestToSeedIt;
246  }
247 
248  util::DateTime nearestToSeedTime = getObservation(*nearestToSeedIt).time;
249 
250  ForwardValidObsIndexIterator acceptableBegin = std::lower_bound(
251  validObsIndicesBegin, nearestToSeedIt,
252  nearestToSeedTime - options_.tolerance,
253  [&](size_t validObsIndexA, const util::DateTime &timeB)
254  { return getTime(validObsIndexA) < timeB; });
255  ForwardValidObsIndexIterator acceptableEnd = std::upper_bound(
256  acceptableBegin, validObsIndicesEnd,
257  nearestToSeedTime + options_.tolerance,
258  [&](const util::DateTime &timeA, size_t validObsIndexB)
259  { return timeA < getTime(validObsIndexB); });
260 
261  // Find the element with highest priority in the acceptable range.
262  return std::max_element(acceptableBegin, acceptableEnd,
263  [&](size_t validObsIndexA, size_t validObsIndexB)
264  { return getPriority(validObsIndexA) < getPriority(validObsIndexB); });
265 }
266 
268  ForwardValidObsIndexIterator validObsIndicesBegin,
269  ForwardValidObsIndexIterator validObsIndicesEnd,
270  util::DateTime targetTime) const {
271  ASSERT_MSG(validObsIndicesEnd - validObsIndicesBegin != 0,
272  "The range of observation indices must not be empty");
273 
274  auto isEarlierThan = [&](size_t validObsIndexA, const util::DateTime &timeB) {
275  return getTime(validObsIndexA) < timeB;
276  };
277  const ForwardValidObsIndexIterator firstGreaterOrEqualToTargetIt =
278  std::lower_bound(validObsIndicesBegin, validObsIndicesEnd, targetTime, isEarlierThan);
279  if (firstGreaterOrEqualToTargetIt == validObsIndicesBegin) {
280  return firstGreaterOrEqualToTargetIt;
281  }
282  if (firstGreaterOrEqualToTargetIt == validObsIndicesEnd) {
283  // All observations were taken before targetTime. Return the iterator pointing to the
284  // last valid element of the range.
285  return validObsIndicesEnd - 1;
286  }
287 
288  const ForwardValidObsIndexIterator lastLessThanTargetIt =
289  firstGreaterOrEqualToTargetIt - 1;
290 
291  Observation firstGreaterOrEqualToTarget = getObservation(*firstGreaterOrEqualToTargetIt);
292  Observation lastLessThanTarget = getObservation(*lastLessThanTargetIt);
293 
294  // Prefer the later observation if there's a tie
295  if ((firstGreaterOrEqualToTarget.time - targetTime).toSeconds() <=
296  (targetTime - lastLessThanTarget.time).toSeconds()) {
297  return firstGreaterOrEqualToTargetIt;
298  } else {
299  return lastLessThanTargetIt;
300  }
301 }
302 
303 } // namespace
304 
305 TemporalThinning::TemporalThinning(ioda::ObsSpace & obsdb, const eckit::Configuration & config,
306  std::shared_ptr<ioda::ObsDataVector<int> > flags,
307  std::shared_ptr<ioda::ObsDataVector<float> > obserr)
308  : FilterBase(obsdb, config, flags, obserr)
309 {
310  oops::Log::debug() << "TemporalThinning: config = " << config_ << std::endl;
311 
313  options_->deserialize(config);
314 }
315 
316 // Required for the correct destruction of options_.
318 {}
319 
320 void TemporalThinning::applyFilter(const std::vector<bool> & apply,
321  const Variables & filtervars,
322  std::vector<std::vector<bool>> & flagged) const {
323  const std::vector<bool> isThinned = identifyThinnedObservations(apply);
324 
325  flagThinnedObservations(isThinned, flagged);
326 
327  if (filtervars.size() != 0) {
328  oops::Log::trace() << "TemporalThinning: flagged? = " << flagged[0] << std::endl;
329  }
330 }
331 
333  const std::vector<bool> & apply) const {
334  std::vector<size_t> validObsIds = getValidObservationIds(apply);
335 
336  RecursiveSplitter splitter(validObsIds.size());
337  groupObservationsByCategory(validObsIds, splitter);
338 
339  std::vector<util::DateTime> times(obsdb_.nlocs());
340  obsdb_.get_db("MetaData", "datetime", times);
341  splitter.sortGroupsBy([&times, &validObsIds](size_t obsIndexA, size_t obsIndexB)
342  { return times[validObsIds[obsIndexA]] < times[validObsIds[obsIndexB]]; });
343 
344  std::unique_ptr<ioda::ObsDataVector<int>> prioritiesDataVector = getObservationPriorities();
345  const ioda::ObsDataRow<int> *priorities =
346  prioritiesDataVector ? &(*prioritiesDataVector)[0] : nullptr;
347 
348  TemporalThinner thinner(validObsIds, times, priorities, splitter, *options_);
349  return thinner.identifyThinnedObservations(apply.size());
350 }
351 
353  const std::vector<bool> & apply) const {
354  std::vector<size_t> validObsIds;
355  for (size_t obsId = 0; obsId < apply.size(); ++obsId)
356  if (apply[obsId] && (*flags_)[0][obsId] == QCflags::pass)
357  validObsIds.push_back(obsId);
358  return validObsIds;
359 }
360 
361 void TemporalThinning::groupObservationsByCategory(const std::vector<size_t> &validObsIds,
362  RecursiveSplitter &splitter) const {
363  boost::optional<Variable> categoryVariable = options_->categoryVariable;
364  if (categoryVariable == boost::none)
365  return;
366 
367  ioda::ObsDataVector<int> obsDataVector(obsdb_, categoryVariable.get().variable(),
368  categoryVariable.get().group());
369  ioda::ObsDataRow<int> &category = obsDataVector[0];
370 
371  std::vector<int> validObsCategories(validObsIds.size());
372  for (size_t validObsIndex = 0; validObsIndex < validObsIds.size(); ++validObsIndex)
373  validObsCategories[validObsIndex] = category[validObsIds[validObsIndex]];
374  splitter.groupBy(validObsCategories);
375 }
376 
377 std::unique_ptr<ioda::ObsDataVector<int>> TemporalThinning::getObservationPriorities() const {
378  std::unique_ptr<ioda::ObsDataVector<int>> priorities;
379  if (options_->priorityVariable.value() != boost::none) {
380  const ufo::Variable priorityVariable = options_->priorityVariable.value().get();
381  priorities.reset(new ioda::ObsDataVector<int>(
382  obsdb_, priorityVariable.variable(), priorityVariable.group()));
383  }
384  return priorities;
385 }
386 
388  const std::vector<bool> & isThinned,
389  std::vector<std::vector<bool>> & flagged) const {
390  for (std::vector<bool> & variableFlagged : flagged)
391  for (size_t obsId = 0; obsId < isThinned.size(); ++obsId)
392  if (isThinned[obsId])
393  variableFlagged[obsId] = true;
394 }
395 
396 void TemporalThinning::print(std::ostream & os) const {
397  os << "TemporalThinning: config = " << config_ << std::endl;
398 }
399 
400 } // namespace ufo
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::splitter_
const RecursiveSplitter & splitter_
Definition: TemporalThinning.cc:130
ufo::anonymous_namespace{TemporalThinning.cc}::Observation
Definition: TemporalThinning.cc:31
ufo::anonymous_namespace{TemporalThinning.cc}::Observation::time
util::DateTime time
Definition: TemporalThinning.cc:33
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::getObservation
Observation getObservation(size_t validObsIndex) const
Definition: TemporalThinning.cc:52
ufo::RecursiveSplitter::Group
A range of indices of all array elements belonging to a particular equivalence class.
Definition: src/ufo/utils/RecursiveSplitter.h:67
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::validObsIds_
const std::vector< size_t > & validObsIds_
Definition: TemporalThinning.cc:127
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::hasPriorities
bool hasPriorities() const
Definition: TemporalThinning.cc:70
ufo::RecursiveSplitter::sortGroupsBy
void sortGroupsBy(Compare comp)
Sort the elements in each equivalence class in ascending order.
Definition: src/ufo/utils/RecursiveSplitter.h:329
ufo::QCflags::pass
constexpr int pass
Definition: QCflags.h:14
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::options_
const TemporalThinningParameters & options_
Definition: TemporalThinning.cc:131
ufo::Variables
Definition: src/ufo/filters/Variables.h:24
TemporalThinning.h
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::priorities_
const std::vector< int > * priorities_
Definition: TemporalThinning.cc:129
ufo::TemporalThinning::applyFilter
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
Definition: TemporalThinning.cc:320
TemporalThinningParameters.h
ufo::RecursiveSplitter::multiElementGroups
MultiElementGroupRange multiElementGroups() const
Return the range of equivalence classes consisting of more than one element.
Definition: src/ufo/utils/RecursiveSplitter.h:293
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::thinRange
void thinRange(Iterator validIndicesBegin, Iterator validIndicesEnd, util::DateTime deadline, IsPast isPast, IsAtOrPast isAtOrPast, Advance advance, std::vector< bool > &isThinned) const
Common implementation shared by thinRangeForwards() and thinRangeBackwards().
Definition: TemporalThinning.cc:198
ufo_radiancerttov_utils_mod::debug
logical, public debug
Definition: ufo_radiancerttov_utils_mod.F90:100
ufo::FilterBase::obsdb_
ioda::ObsSpace & obsdb_
Definition: FilterBase.h:59
ufo::TemporalThinning::flagThinnedObservations
void flagThinnedObservations(const std::vector< bool > &isThinned, std::vector< std::vector< bool >> &flagged) const
Definition: TemporalThinning.cc:387
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::findSeed
ForwardValidObsIndexIterator findSeed(ForwardValidObsIndexIterator validObsIndicesBegin, ForwardValidObsIndexIterator validObsIndicesEnd, util::DateTime seedTime) const
Return an iterator to the first observation to be retained.
Definition: TemporalThinning.cc:238
ufo::FilterBase
FilterBase: Base class for UFO QC filters.
Definition: FilterBase.h:42
ufo::RecursiveSplitter
Partitions an array into groups of elements equivalent according to certain criteria.
Definition: src/ufo/utils/RecursiveSplitter.h:63
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::thinRangeForwards
void thinRangeForwards(ForwardValidObsIndexIterator validIndicesBegin, ForwardValidObsIndexIterator validIndicesEnd, util::DateTime deadline, std::vector< bool > &isThinned) const
Definition: TemporalThinning.cc:173
ufo
Definition: RunCRTM.h:27
ufo::anonymous_namespace{TemporalThinning.cc}::Observation::priority
int priority
Definition: TemporalThinning.cc:34
ufo::Variables::size
size_t size() const
Definition: Variables.cc:92
ufo::RecursiveSplitter::groupBy
void groupBy(const std::vector< size_t > &categories)
Split existing equivalence classes according to a new criterion.
Definition: src/ufo/utils/RecursiveSplitter.h:275
ufo::TemporalThinning::options_
std::unique_ptr< TemporalThinningParameters > options_
Definition: src/ufo/filters/TemporalThinning.h:74
ufo::FilterBase::flags_
std::shared_ptr< ioda::ObsDataVector< int > > flags_
Definition: FilterBase.h:61
ufo::TemporalThinningParameters
Options controlling the operation of the TemporalThinning filter.
Definition: TemporalThinningParameters.h:27
ufo::TemporalThinning::TemporalThinning
TemporalThinning(ioda::ObsSpace &obsdb, const eckit::Configuration &config, std::shared_ptr< ioda::ObsDataVector< int > > flags, std::shared_ptr< ioda::ObsDataVector< float > > obserr)
Definition: TemporalThinning.cc:305
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::thinRangeBackwards
void thinRangeBackwards(BackwardValidObsIndexIterator validIndicesBegin, BackwardValidObsIndexIterator validIndicesEnd, util::DateTime deadline, std::vector< bool > &isThinned) const
Definition: TemporalThinning.cc:185
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner
Responsible for the selection of observations to retain.
Definition: TemporalThinning.cc:38
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::ForwardValidObsIndexIterator
std::vector< size_t >::const_iterator ForwardValidObsIndexIterator
Definition: TemporalThinning.cc:49
ufo::TemporalThinning::identifyThinnedObservations
std::vector< bool > identifyThinnedObservations(const std::vector< bool > &apply) const
Definition: TemporalThinning.cc:332
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::times_
const std::vector< util::DateTime > & times_
Definition: TemporalThinning.cc:128
ufo::TemporalThinning::groupObservationsByCategory
void groupObservationsByCategory(const std::vector< size_t > &validObsIds, RecursiveSplitter &splitter) const
Definition: TemporalThinning.cc:361
ufo::TemporalThinning::getValidObservationIds
std::vector< size_t > getValidObservationIds(const std::vector< bool > &apply) const
Definition: TemporalThinning.cc:352
ufo::Variable::group
const std::string & group() const
Definition: Variable.cc:117
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::BackwardValidObsIndexIterator
std::vector< size_t >::const_reverse_iterator BackwardValidObsIndexIterator
Definition: TemporalThinning.cc:50
ufo::Variable::variable
const std::string & variable() const
Definition: Variable.cc:100
ioda::ObsDataVector< int >
ufo::FilterBase::config_
const eckit::LocalConfiguration config_
Definition: FilterBase.h:60
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::getPriority
int getPriority(size_t validObsIndex) const
Definition: TemporalThinning.cc:65
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::findNearest
ForwardValidObsIndexIterator findNearest(ForwardValidObsIndexIterator validObsIndicesBegin, ForwardValidObsIndexIterator validObsIndicesEnd, util::DateTime targetTime) const
Definition: TemporalThinning.cc:267
ufo::anonymous_namespace{TemporalThinning.cc}::Observation::id
size_t id
Definition: TemporalThinning.cc:32
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::getTime
util::DateTime getTime(size_t validObsIndex) const
Definition: TemporalThinning.cc:61
ufo::TemporalThinning::print
void print(std::ostream &) const override
Definition: TemporalThinning.cc:396
ufo::TemporalThinningParameters::tolerance
oops::Parameter< util::Duration > tolerance
Definition: TemporalThinningParameters.h:39
ufo::Variable
Definition: Variable.h:23
ufo::TemporalThinning::~TemporalThinning
~TemporalThinning() override
Definition: TemporalThinning.cc:317
ufo::TemporalThinning::getObservationPriorities
std::unique_ptr< ioda::ObsDataVector< int > > getObservationPriorities() const
Definition: TemporalThinning.cc:377
ufo::anonymous_namespace{TemporalThinning.cc}::TemporalThinner::identifyThinnedObservations
std::vector< bool > identifyThinnedObservations(size_t totalNumObservations) const
Definition: TemporalThinning.cc:146
RecursiveSplitter.h
ufo::TemporalThinningParameters::minSpacing
oops::Parameter< util::Duration > minSpacing
Minimum spacing between two successive retained observations.
Definition: TemporalThinningParameters.h:32
ufo::TemporalThinningParameters::seedTime
oops::OptionalParameter< util::DateTime > seedTime
Definition: TemporalThinningParameters.h:47