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"
42 const std::vector<util::DateTime> ×,
43 const std::vector<int> *priorities,
47 std::vector<bool> identifyThinnedObservations(
size_t totalNumObservations)
const;
55 obs.
id = validObsIds_[validObsIndex];
62 util::DateTime
getTime(
size_t validObsIndex)
const {
63 return times_[validObsIds_[validObsIndex]];
67 ASSERT(priorities_ !=
nullptr);
68 return (*priorities_)[validObsIds_[validObsIndex]];
72 return priorities_ !=
nullptr;
77 void thinRangeForwards(ForwardValidObsIndexIterator validIndicesBegin,
78 ForwardValidObsIndexIterator validIndicesEnd,
79 util::DateTime deadline,
80 std::vector<bool> &isThinned)
const;
84 void thinRangeBackwards(BackwardValidObsIndexIterator validIndicesBegin,
85 BackwardValidObsIndexIterator validIndicesEnd,
86 util::DateTime deadline,
87 std::vector<bool> &isThinned)
const;
105 template <
typename Iterator,
typename IsPast,
typename IsAtOrPast,
typename Advance>
106 void thinRange(Iterator validIndicesBegin,
107 Iterator validIndicesEnd,
108 util::DateTime deadline,
110 IsAtOrPast isAtOrPast,
112 std::vector<bool> &isThinned)
const;
115 ForwardValidObsIndexIterator findSeed(
116 ForwardValidObsIndexIterator validObsIndicesBegin,
117 ForwardValidObsIndexIterator validObsIndicesEnd,
118 util::DateTime seedTime)
const;
122 ForwardValidObsIndexIterator findNearest(
123 ForwardValidObsIndexIterator validObsIndicesBegin,
124 ForwardValidObsIndexIterator validObsIndicesEnd,
125 util::DateTime targetTime)
const;
129 const std::vector<util::DateTime> &
times_;
135 TemporalThinner::TemporalThinner(
const std::vector<size_t> &validObsIds,
136 const std::vector<util::DateTime> ×,
137 const std::vector<int> *priorities,
140 validObsIds_(validObsIds),
142 priorities_(priorities),
148 std::vector<bool> isThinned(totalNumObservations,
false);
152 util::DateTime deadline =
getTime(*group.begin());
176 util::DateTime deadline,
177 std::vector<bool> &isThinned)
const {
178 thinRange(validIndicesBegin, validIndicesEnd, deadline,
179 std::greater<util::DateTime>(),
180 std::greater_equal<util::DateTime>(),
182 [](
const util::DateTime &time,
const util::Duration &offset) {
return time + offset; },
189 util::DateTime deadline,
190 std::vector<bool> &isThinned)
const {
191 thinRange(validIndicesBegin, validIndicesEnd, deadline,
192 std::less<util::DateTime>(),
193 std::less_equal<util::DateTime>(),
194 [](
const util::DateTime &time,
const util::Duration &offset) {
return time - offset; },
198 template <
typename Iterator,
typename IsPast,
typename IsAtOrPast,
typename Advance>
200 Iterator validIndicesEnd,
201 util::DateTime deadline,
203 IsAtOrPast isAtOrPast,
205 std::vector<bool> &isThinned)
const {
206 boost::optional<Observation> best;
207 for (Iterator it = validIndicesBegin; it != validIndicesEnd; ++it) {
208 const size_t validObsIndex = *it;
210 if (best != boost::none) {
212 if (isPast(current.
time, deadline)) {
218 if (current.
priority > best->priority) {
219 isThinned[best->id] =
true;
222 isThinned[current.
id] =
true;
227 if (best == boost::none) {
229 if (isAtOrPast(current.
time, deadline)) {
233 isThinned[current.
id] =
true;
242 util::DateTime seedTime)
const {
244 validObsIndicesBegin, validObsIndicesEnd, seedTime);
246 return nearestToSeedIt;
252 validObsIndicesBegin, nearestToSeedIt,
254 [&](
size_t validObsIndexA,
const util::DateTime &timeB)
255 { return getTime(validObsIndexA) < timeB; });
257 acceptableBegin, validObsIndicesEnd,
259 [&](
const util::DateTime &timeA,
size_t validObsIndexB)
260 { return timeA < getTime(validObsIndexB); });
263 return std::max_element(acceptableBegin, acceptableEnd,
264 [&](
size_t validObsIndexA,
size_t validObsIndexB)
271 util::DateTime targetTime)
const {
272 ASSERT_MSG(validObsIndicesEnd - validObsIndicesBegin != 0,
273 "The range of observation indices must not be empty");
275 auto isEarlierThan = [&](
size_t validObsIndexA,
const util::DateTime &timeB) {
276 return getTime(validObsIndexA) < timeB;
279 std::lower_bound(validObsIndicesBegin, validObsIndicesEnd, targetTime, isEarlierThan);
280 if (firstGreaterOrEqualToTargetIt == validObsIndicesBegin) {
281 return firstGreaterOrEqualToTargetIt;
283 if (firstGreaterOrEqualToTargetIt == validObsIndicesEnd) {
286 return validObsIndicesEnd - 1;
290 firstGreaterOrEqualToTargetIt - 1;
296 if ((firstGreaterOrEqualToTarget.
time - targetTime).toSeconds() <=
297 (targetTime - lastLessThanTarget.
time).toSeconds()) {
298 return firstGreaterOrEqualToTargetIt;
300 return lastLessThanTargetIt;
309 :
FilterBase(obsdb, parameters, flags, obserr), options_(parameters)
320 std::vector<std::vector<bool>> & flagged)
const {
332 }
else if (!
obsdb_.obs_group_vars().empty()) {
342 const std::vector<bool> & apply,
345 const std::vector<size_t> validObsIds
351 "MetaData",
"datetime");
352 splitter.
sortGroupsBy([×, &validObsIds](
size_t obsIndex)
353 {
return times[validObsIds[obsIndex]]; });
357 TemporalThinner thinner(validObsIds, times, priorities.get_ptr(), splitter,
options_);
358 return thinner.identifyThinnedObservations(times.size());
363 boost::optional<std::vector<int>> priorities;
373 os <<
"TemporalThinning: config = " <<
options_ << std::endl;
Base class for UFO QC filters.
This class provides access to observations that may be held on multiple MPI ranks.
RecursiveSplitter splitObservationsIntoIndependentGroups(const std::vector< size_t > &validObsIds, bool opsCompatibilityMode=false) const
std::vector< size_t > getValidObservationIds(const std::vector< bool > &apply, const ioda::ObsDataVector< int > &flags, const Variables &filtervars, bool validIfAnyFilterVariablePassedQC=true) const
Return the IDs of observation locations that should be treated as valid by a filter.
std::vector< int > getIntVariableFromObsSpace(const std::string &group, const std::string &variable) const
Return the values of the specified variable at successive observation locations.
static ObsAccessor toObservationsSplitIntoIndependentGroupsByRecordId(const ioda::ObsSpace &obsdb)
Create an accessor to the collection of observations held in obsdb, assuming that each record can be ...
static ObsAccessor toAllObservations(const ioda::ObsSpace &obsdb)
Create an accessor to observations from the observation space obsdb, assuming that the whole set of o...
static ObsAccessor toObservationsSplitIntoIndependentGroupsByVariable(const ioda::ObsSpace &obsdb, const Variable &variable)
Create an accessor to the collection of observations held in obsdb, assuming that observations with d...
std::vector< util::DateTime > getDateTimeVariableFromObsSpace(const std::string &group, const std::string &variable) const
void flagRejectedObservations(const std::vector< bool > &isRejected, std::vector< std::vector< bool > > &flagged) const
Update flags of observations held on the current MPI rank.
std::shared_ptr< ioda::ObsDataVector< int > > flags_
A range of indices of all array elements belonging to a particular equivalence class.
Partitions an array into groups of elements equivalent according to certain criteria.
MultiElementGroupRange multiElementGroups() const
Return the range of equivalence classes consisting of more than one element.
void sortGroupsBy(const UnaryOperation &key)
Sort the elements in each equivalence class in ascending order.
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
TemporalThinning(ioda::ObsSpace &obsdb, const Parameters_ ¶meters, std::shared_ptr< ioda::ObsDataVector< int > > flags, std::shared_ptr< ioda::ObsDataVector< float > > obserr)
~TemporalThinning() override
ObsAccessor createObsAccessor() const
std::vector< bool > identifyThinnedObservations(const std::vector< bool > &apply, const Variables &filtervars, const ObsAccessor &obsAccessor) const
boost::optional< std::vector< int > > getObservationPriorities(const ObsAccessor &obsAccessor) const
void print(std::ostream &) const override
Options controlling the operation of the TemporalThinning filter.
oops::Parameter< util::Duration > minSpacing
Minimum spacing between two successive retained observations.
oops::OptionalParameter< Variable > categoryVariable
oops::OptionalParameter< Variable > priorityVariable
oops::OptionalParameter< util::DateTime > seedTime
oops::Parameter< util::Duration > tolerance
const std::string & variable() const
const std::string & group() const
Responsible for the selection of observations to retain.
Observation getObservation(size_t validObsIndex) const
const std::vector< size_t > & validObsIds_
std::vector< size_t >::const_iterator ForwardValidObsIndexIterator
ForwardValidObsIndexIterator findSeed(ForwardValidObsIndexIterator validObsIndicesBegin, ForwardValidObsIndexIterator validObsIndicesEnd, util::DateTime seedTime) const
Return an iterator to the first observation to be retained.
const std::vector< util::DateTime > & times_
void thinRangeBackwards(BackwardValidObsIndexIterator validIndicesBegin, BackwardValidObsIndexIterator validIndicesEnd, util::DateTime deadline, std::vector< bool > &isThinned) const
ForwardValidObsIndexIterator findNearest(ForwardValidObsIndexIterator validObsIndicesBegin, ForwardValidObsIndexIterator validObsIndicesEnd, util::DateTime targetTime) const
std::vector< bool > identifyThinnedObservations(size_t totalNumObservations) const
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().
util::DateTime getTime(size_t validObsIndex) const
const TemporalThinningParameters & options_
void thinRangeForwards(ForwardValidObsIndexIterator validIndicesBegin, ForwardValidObsIndexIterator validIndicesEnd, util::DateTime deadline, std::vector< bool > &isThinned) const
std::vector< size_t >::const_reverse_iterator BackwardValidObsIndexIterator
const RecursiveSplitter & splitter_
bool hasPriorities() const
int getPriority(size_t validObsIndex) const
const std::vector< int > * priorities_