UFO
processWhere.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2018-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 
9 
10 #include <bitset>
11 #include <regex>
12 #include <set>
13 #include <string>
14 #include <vector>
15 
16 #include "eckit/config/LocalConfiguration.h"
17 #include "eckit/types/FloatCompare.h"
18 #include "oops/util/IntSetParser.h"
19 #include "oops/util/Logger.h"
20 #include "oops/util/missingValues.h"
21 #include "oops/util/wildcard.h"
23 #include "ufo/filters/Variables.h"
24 
25 namespace ufo {
26 
27 
28 // -----------------------------------------------------------------------------
29 ufo::Variables getAllWhereVariables(const std::vector<WhereParameters> & params) {
30  ufo::Variables vars;
31  for (const WhereParameters & currentParams : params) {
32  vars += currentParams.variable;
33  }
34  return vars;
35 }
36 
37 
38 // -----------------------------------------------------------------------------
39 template<typename T>
40 void processWhereMinMax(const std::vector<T> & data,
41  const T & vmin, const T & vmax,
42  std::vector<bool> & mask) {
43  const T not_set_value = util::missingValue(not_set_value);
44  const size_t n = data.size();
45 
46  if (vmin != not_set_value || vmax != not_set_value) {
47  for (size_t jj = 0; jj < n; ++jj) {
48  if (vmin != not_set_value && data[jj] < vmin) mask[jj] = false;
49  if (vmax != not_set_value && data[jj] > vmax) mask[jj] = false;
50  }
51  }
52 }
53 
54 
55 // -----------------------------------------------------------------------------
56 void processWhereMinMax(const std::vector<util::DateTime> & data,
57  const util::PartialDateTime & vmin, const util::PartialDateTime & vmax,
58  std::vector<bool> & mask) {
59  const util::PartialDateTime not_set_value {};
60 
61  if (vmin != not_set_value || vmax != not_set_value) {
62  for (size_t jj = 0; jj < data.size(); ++jj) {
63  if (vmin != not_set_value && vmin > data[jj]) mask[jj] = false;
64  if (vmax != not_set_value && vmax < data[jj]) mask[jj] = false;
65  }
66  }
67 }
68 
69 
70 // -----------------------------------------------------------------------------
71 void processWhereIsDefined(const std::vector<float> & data,
72  std::vector<bool> & mask) {
73  const float missing = util::missingValue(missing);
74  const size_t n = data.size();
75  for (size_t jj = 0; jj < n; ++jj) {
76  if (data[jj] == missing) mask[jj] = false;
77  }
78 }
79 
80 // -----------------------------------------------------------------------------
81 
82 void processWhereIsNotDefined(const std::vector<float> & data,
83  std::vector<bool> & mask) {
84  const float missing = util::missingValue(missing);
85  const size_t n = data.size();
86  for (size_t jj = 0; jj < n; ++jj) {
87  if (data[jj] != missing) mask[jj] = false;
88  }
89 }
90 
91 // -----------------------------------------------------------------------------
92 template <class T>
93 void processWhereIsIn(const std::vector<T> & data,
94  const std::set<T> & whitelist,
95  std::vector<bool> & mask) {
96  for (size_t jj = 0; jj < data.size(); ++jj) {
97  if (!oops::contains(whitelist, data[jj])) mask[jj] = false;
98  }
99 }
100 
101 // -----------------------------------------------------------------------------
102 void processWhereIsClose(const std::vector<float> & data,
103  const float tolerance, const bool relative,
104  const std::vector<float> & whitelist,
105  std::vector<bool> & mask) {
106  for (size_t jj = 0; jj < data.size(); ++jj) {
107  bool inlist = false;
108  for (auto testvalue : whitelist) {
109  if (relative) {
110  float relativetolerance = testvalue * tolerance;
111  if (eckit::types::is_approximately_equal(data[jj], testvalue, relativetolerance)) {
112  inlist = true;
113  break;
114  }
115  } else {
116  if (eckit::types::is_approximately_equal(data[jj], testvalue, tolerance)) {
117  inlist = true;
118  break;
119  }
120  }
121  } // testvalue
122  if (!inlist) mask[jj] = false;
123  } // jj
124 }
125 
126 // -----------------------------------------------------------------------------
127 template <class T>
128 void processWhereIsNotIn(const std::vector<T> & data,
129  const std::set<T> & blacklist,
130  std::vector<bool> & mask) {
131  const T missing = util::missingValue(missing);
132  for (size_t jj = 0; jj < data.size(); ++jj) {
133  if (data[jj] == missing || oops::contains(blacklist, data[jj])) mask[jj] = false;
134  }
135 }
136 
137 // -----------------------------------------------------------------------------
138 void processWhereIsNotIn(const std::vector<std::string> & data,
139  const std::set<std::string> & blacklist,
140  std::vector<bool> & mask) {
141  for (size_t jj = 0; jj < data.size(); ++jj) {
142  if (oops::contains(blacklist, data[jj])) mask[jj] = false;
143  }
144 }
145 
146 // -----------------------------------------------------------------------------
147 void processWhereIsNotClose(const std::vector<float> & data,
148  const float tolerance, const bool relative,
149  const std::vector<float> & blacklist,
150  std::vector<bool> & mask) {
151  const float missing = util::missingValue(missing);
152  for (size_t jj = 0; jj < data.size(); ++jj) {
153  for (auto testvalue : blacklist) {
154  if (relative) {
155  float relativetolerance = testvalue * tolerance;
156  if (data[jj] == missing ||
157  eckit::types::is_approximately_equal(data[jj], testvalue, relativetolerance)) {
158  mask[jj] = false;
159  break;
160  }
161  } else {
162  if (data[jj] == missing ||
163  eckit::types::is_approximately_equal(data[jj], testvalue, tolerance)) {
164  mask[jj] = false;
165  break;
166  }
167  }
168  } // testvalue
169  } // jj
170 }
171 
172 // -----------------------------------------------------------------------------
173 template <typename T>
174 void applyMinMax(std::vector<bool> & where, WhereParameters const & parameters,
175  ObsFilterData const & filterdata, Variable const & varname) {
176  const T not_set_value = util::missingValue(not_set_value);
177 
178  // Set vmin to the value of the 'minvalue' option if it exists; if not, leave vmin unchanged.
179  T vmin = not_set_value;
180  if (parameters.minvalue.value() != boost::none)
181  vmin = parameters.minvalue.value()->as<T>();
182  // Set vmax to the value of the 'maxvalue' option if it exists; if not, leave vmax unchanged.
183  T vmax = not_set_value;
184  if (parameters.maxvalue.value() != boost::none)
185  vmax = parameters.maxvalue.value()->as<T>();
186 
187  // Apply mask min/max
188  if (vmin != not_set_value || vmax != not_set_value) {
189  std::vector<T> data;
190  filterdata.get(varname, data);
191  processWhereMinMax(data, vmin, vmax, where);
192  }
193 }
194 
195 // -----------------------------------------------------------------------------
196 template <>
197 void applyMinMax<util::DateTime>(std::vector<bool> & where, WhereParameters const & parameters,
198  ObsFilterData const & filterdata, Variable const & varname) {
199  util::PartialDateTime vmin {}, vmax {}, not_set_value {};
200  if (parameters.minvalue.value() != boost::none)
201  vmin = parameters.minvalue.value()->as<util::PartialDateTime>();
202  if (parameters.maxvalue.value() != boost::none)
203  vmax = parameters.maxvalue.value()->as<util::PartialDateTime>();
204 
205  // Apply mask min/max
206  if (vmin != not_set_value || vmax != not_set_value) {
207  std::vector<util::DateTime> data;
208  filterdata.get(varname, data);
209  processWhereMinMax(data, vmin, vmax, where);
210  }
211 }
212 
213 // -----------------------------------------------------------------------------
214 /// \brief Process an `any_bit_set_of` keyword in a `where` clause.
215 ///
216 /// This function sets to `false` all elements of `where` corresponding to elements of `data` in
217 /// which all bits with indices `bitIndices` are zero. Bits are numbered from 0 starting from the
218 /// least significant bit.
219 ///
220 /// The vectors `data` and `where` must be of the same length.
221 ///
222 /// Example: Suppose `data` is set to [1, 3, 4, 8] and bitIndices to [0, 2]. Then this function will
223 /// set only the last element of `where` to false, since 8 is the only integer from `data` in whose
224 /// binary representation both bits 0 and 2 are zero.
225 void processWhereAnyBitSetOf(const std::vector<int> & data,
226  const std::set<int> & bitIndices,
227  std::vector<bool> & where) {
228  std::bitset<32> mask_bs;
229  for (const int &bitIndex : bitIndices) {
230  mask_bs[bitIndex] = 1;
231  }
232  const int mask = mask_bs.to_ulong();
233 
234  for (size_t jj = 0; jj < data.size(); ++jj) {
235  if ((data[jj] & mask) == 0) {
236  // None of the specified bits is set
237  where[jj] = false;
238  }
239  }
240 }
241 
242 // -----------------------------------------------------------------------------
243 /// \brief Process an `any_bit_unset_of` keyword in a `where` clause.
244 ///
245 /// This function sets to `false` all elements of `where` corresponding to elements of `data` in
246 /// which all bits with indices `bitIndices` are non-zero. Bits are numbered from 0 starting from
247 /// the least significant bit.
248 ///
249 /// The vectors `data` and `where` must be of the same length.
250 ///
251 /// Example: Suppose `data` is set to [1, 3, 4, 5] and bitIndices to [0, 2]. Then this function will
252 /// set only the last element of `where` to false, since 5 is the only integer from `data` in whose
253 /// binary representation both bits 0 and 2 are non-zero.
254 void processWhereAnyBitUnsetOf(const std::vector<int> & data,
255  const std::set<int> & bitIndices,
256  std::vector<bool> & where) {
257  std::bitset<32> mask_bs;
258  for (const int &bitIndex : bitIndices) {
259  mask_bs[bitIndex] = 1;
260  }
261  const int mask = mask_bs.to_ulong();
262 
263  for (size_t jj = 0; jj < data.size(); ++jj) {
264  if ((data[jj] & mask) == mask) {
265  // None of the specified bits is unset
266  where[jj] = false;
267  }
268  }
269 }
270 
271 // -----------------------------------------------------------------------------
272 /// \brief Process a `matches_regex` keyword in a `where` clause.
273 ///
274 /// This function sets to `false` all elements of `where` corresponding to elements of `data` that
275 /// do not match the regular expression `pattern`. The vectors `data` and `where` must be of the
276 /// same length.
277 void processWhereMatchesRegex(const std::vector<std::string> & data,
278  const std::string & pattern,
279  std::vector<bool> & where) {
280  std::regex regex(pattern);
281  for (size_t jj = 0; jj < data.size(); ++jj) {
282  if (where[jj] && !std::regex_match(data[jj], regex))
283  where[jj] = false;
284  }
285 }
286 
287 /// \brief Process a `matches_regex` keyword in a `where` clause.
288 ///
289 /// This function sets to `false` all elements of `where` corresponding to elements of `data` whose
290 /// string representations do not match the regular expression `pattern`. The vectors `data` and
291 /// `where` must be of the same length.
292 void processWhereMatchesRegex(const std::vector<int> & data,
293  const std::string & pattern,
294  std::vector<bool> & where) {
295  std::regex regex(pattern);
296  for (size_t jj = 0; jj < data.size(); ++jj) {
297  if (where[jj] && !std::regex_match(std::to_string(data[jj]), regex))
298  where[jj] = false;
299  }
300 }
301 
302 // -----------------------------------------------------------------------------
303 /// Returns true if `string` matches any of the patterns from the list `patterns`.
304 ///
305 /// The patterns may contain wildcards `*` (matching any sequence of characters) and `?` (matching
306 /// a single character).
307 bool stringMatchesAnyWildcardPattern(const std::string &string,
308  const std::vector<std::string> & patterns) {
309  return std::any_of(patterns.begin(),
310  patterns.end(),
311  [&string] (const std::string &pattern)
312  { return util::matchesWildcardPattern(string, pattern); });
313 }
314 
315 /// \brief Function used to process a `matches_wildcard` or `matches_any_wildcard` keyword in a
316 /// `where` clause.
317 ///
318 /// This function sets to `false` all elements of `where` corresponding to elements of `data` that
319 /// do not match any of the patterns from the list `patterns`. The patterns may contain wildcards
320 /// `*` (matching any sequence of characters) and `?` (matching a single character). The vectors
321 /// `data` and `where` must be of the same length.
322 void processWhereMatchesAnyWildcardPattern(const std::vector<std::string> & data,
323  const std::vector<std::string> & patterns,
324  std::vector<bool> & where) {
325  for (size_t jj = 0; jj < data.size(); ++jj) {
326  if (where[jj] && !stringMatchesAnyWildcardPattern(data[jj], patterns))
327  where[jj] = false;
328  }
329 }
330 
331 /// \overload Same as the function above, but taking a vector of integers rather than strings.
332 /// The integers are converted to strings before pattern matching.
333 void processWhereMatchesAnyWildcardPattern(const std::vector<int> & data,
334  const std::vector<std::string> & patterns,
335  std::vector<bool> & where) {
336  for (size_t jj = 0; jj < data.size(); ++jj) {
337  if (where[jj] && !stringMatchesAnyWildcardPattern(std::to_string(data[jj]), patterns))
338  where[jj] = false;
339  }
340 }
341 
342 // -----------------------------------------------------------------------------
343 void isInString(std::vector<bool> & where, std::vector<std::string> const & allowedValues,
344  ObsFilterData const & filterdata, Variable const & varname) {
345  std::vector<std::string> data;
346  std::set<std::string> whitelist(allowedValues.begin(), allowedValues.end());
347  filterdata.get(varname, data);
348  processWhereIsIn(data, whitelist, where);
349 }
350 
351 // -----------------------------------------------------------------------------
352 void isInInteger(std::vector<bool> & where, std::set<int> const & allowedValues,
353  ObsFilterData const & filterdata, Variable const & varname) {
354  std::vector<int> data;
355  filterdata.get(varname, data);
356  processWhereIsIn(data, allowedValues, where);
357 }
358 
359 // -----------------------------------------------------------------------------
360 void isNotInString(std::vector<bool> & where, std::vector<std::string> const & forbiddenValues,
361  ObsFilterData const & filterdata, Variable const & varname) {
362  std::vector<std::string> data;
363  std::set<std::string> blacklist(forbiddenValues.begin(), forbiddenValues.end());
364  filterdata.get(varname, data);
365  processWhereIsNotIn(data, blacklist, where);
366 }
367 
368 // -----------------------------------------------------------------------------
369 void isNotInInteger(std::vector<bool> & where, std::set<int> const & forbiddenValues,
370  ObsFilterData const & filterdata, Variable const & varname) {
371  std::vector<int> data;
372  filterdata.get(varname, data);
373  processWhereIsNotIn(data, forbiddenValues, where);
374 }
375 
376 // -----------------------------------------------------------------------------
377 std::vector<bool> processWhere(const std::vector<WhereParameters> & params,
378  const ObsFilterData & filterdata) {
379  const size_t nlocs = filterdata.nlocs();
380 
381 // Everywhere by default if no mask
382  std::vector<bool> where(nlocs, true);
383 
384  for (const WhereParameters &currentParams : params) {
385  const Variable &var = currentParams.variable;
386  for (size_t jvar = 0; jvar < var.size(); ++jvar) {
387  if (var.group() != "VarMetaData") {
388  const Variable varname = var[jvar];
389  ioda::ObsDtype dtype = filterdata.dtype(varname);
390 
391  if (dtype == ioda::ObsDtype::DateTime) {
392  applyMinMax<util::DateTime>(where, currentParams, filterdata, varname);
393  } else if (dtype == ioda::ObsDtype::Integer) {
394  applyMinMax<int>(where, currentParams, filterdata, varname);
395  } else {
396  applyMinMax<float>(where, currentParams, filterdata, varname);
397  }
398 
399 // Apply mask is_defined
400  if (currentParams.isDefined.value()) {
401  if (filterdata.has(varname)) {
402  std::vector<float> data;
403  filterdata.get(varname, data);
404  processWhereIsDefined(data, where);
405  } else {
406  std::fill(where.begin(), where.end(), false);
407  }
408  }
409 
410 // Apply mask is_not_defined
411  if (currentParams.isNotDefined.value()) {
412  std::vector<float> data;
413  filterdata.get(varname, data);
414  processWhereIsNotDefined(data, where);
415  }
416 
417 // Apply mask is_in
418  if (currentParams.isIn.value() != boost::none) {
419  if (dtype == ioda::ObsDtype::String) {
420  isInString(where, currentParams.isIn.value()->as<std::vector<std::string>>(),
421  filterdata, varname);
422  } else if (dtype == ioda::ObsDtype::Integer) {
423  isInInteger(where, currentParams.isIn.value()->as<std::set<int>>(),
424  filterdata, varname);
425  } else {
426  throw eckit::UserError(
427  "Only integer and string variables may be used for processWhere 'is_in'",
428  Here());
429  }
430  }
431 
432 // Apply mask is_close
433  if (currentParams.isClose.value() != boost::none) {
434  if (dtype == ioda::ObsDtype::Float) {
435  std::vector<float> data;
436  filterdata.get(varname, data);
437  if (currentParams.relativetolerance.value() == boost::none &&
438  currentParams.absolutetolerance.value() != boost::none) {
439  processWhereIsClose(data, currentParams.absolutetolerance.value().get(),
440  false, currentParams.isClose.value().get(), where);
441  } else if (currentParams.relativetolerance.value() != boost::none &&
442  currentParams.absolutetolerance.value() == boost::none) {
443  processWhereIsClose(data, currentParams.relativetolerance.value().get(),
444  true, currentParams.isClose.value().get(), where);
445  } else {
446  throw eckit::UserError(
447  "For 'is_close' one (and only one) tolerance is needed.",
448  Here());
449  }
450  } else {
451  throw eckit::UserError(
452  "Only float variables may be used for processWhere 'is_close'",
453  Here());
454  }
455  }
456 
457 // Apply mask is_not_in
458  if (currentParams.isNotIn.value() != boost::none) {
459  if (dtype == ioda::ObsDtype::String) {
460  isNotInString(where, currentParams.isNotIn.value()->as<std::vector<std::string>>(),
461  filterdata, varname);
462  } else if (dtype == ioda::ObsDtype::Integer) {
463  isNotInInteger(where, currentParams.isNotIn.value()->as<std::set<int>>(),
464  filterdata, varname);
465  } else {
466  throw eckit::UserError(
467  "Only integer and string variables may be used for processWhere 'is_not_in'",
468  Here());
469  }
470  }
471 
472 // Apply mask is_not_close
473  if (currentParams.isNotClose.value() != boost::none) {
474  if (dtype == ioda::ObsDtype::Float) {
475  std::vector<float> data;
476  filterdata.get(varname, data);
477  if (currentParams.relativetolerance.value() == boost::none &&
478  currentParams.absolutetolerance.value() != boost::none) {
479  processWhereIsNotClose(data, currentParams.absolutetolerance.value().get(),
480  false, currentParams.isNotClose.value().get(), where);
481  } else if (currentParams.relativetolerance.value() != boost::none &&
482  currentParams.absolutetolerance.value() == boost::none) {
483  processWhereIsNotClose(data, currentParams.relativetolerance.value().get(),
484  true, currentParams.isNotClose.value().get(), where);
485  } else {
486  throw eckit::UserError(
487  "For 'is_close' one (and only one) tolerance is needed.",
488  Here());
489  }
490  } else {
491  throw eckit::UserError(
492  "Only float variables may be used for processWhere 'is_not_close'",
493  Here());
494  }
495  }
496 
497 // Apply mask any_bit_set_of
498  if (currentParams.anyBitSetOf.value() != boost::none) {
499  if (dtype == ioda::ObsDtype::Integer) {
500  std::vector<int> data;
501  const std::set<int> &bitIndices = *currentParams.anyBitSetOf.value();
502  filterdata.get(varname, data);
503  processWhereAnyBitSetOf(data, bitIndices, where);
504  } else {
505  throw eckit::UserError(
506  "Only integer variables may be used for processWhere 'any_bit_set_of'",
507  Here());
508  }
509  }
510 
511 // Apply mask any_bit_unset_of
512  if (currentParams.anyBitUnsetOf.value() != boost::none) {
513  if (dtype == ioda::ObsDtype::Integer) {
514  std::vector<int> data;
515  const std::set<int> &bitIndices = *currentParams.anyBitUnsetOf.value();
516  filterdata.get(varname, data);
517  processWhereAnyBitUnsetOf(data, bitIndices, where);
518  } else {
519  throw eckit::UserError(
520  "Only integer variables may be used for processWhere 'any_bit_unset_of'",
521  Here());
522  }
523  }
524 
525 // Apply mask matches_regex
526  if (currentParams.matchesRegex.value() != boost::none) {
527  const std::string pattern = *currentParams.matchesRegex.value();
528  // Select observations for which the variable 'varname' matches the regular expression
529  // 'pattern'.
530  if (dtype == ioda::ObsDtype::Integer) {
531  std::vector<int> data;
532  filterdata.get(varname, data);
533  processWhereMatchesRegex(data, pattern, where);
534  } else if (dtype == ioda::ObsDtype::String) {
535  std::vector<std::string> data;
536  filterdata.get(varname, data);
537  processWhereMatchesRegex(data, pattern, where);
538  } else {
539  throw eckit::UserError(
540  "Only string and integer variables may be used for processWhere 'matches_regex'",
541  Here());
542  }
543  }
544 
545 // Apply mask matches_wildcard
546  if (currentParams.matchesWildcard.value() != boost::none) {
547  const std::string &pattern = *currentParams.matchesWildcard.value();
548  // Select observations for which the variable 'varname' matches the pattern
549  // 'pattern', which may contain the * and ? wildcards.
550  if (dtype == ioda::ObsDtype::Integer) {
551  std::vector<int> data;
552  filterdata.get(varname, data);
553  processWhereMatchesAnyWildcardPattern(data, {pattern}, where);
554  } else if (dtype == ioda::ObsDtype::String) {
555  std::vector<std::string> data;
556  filterdata.get(varname, data);
557  processWhereMatchesAnyWildcardPattern(data, {pattern}, where);
558  } else {
559  throw eckit::UserError(
560  "Only string and integer variables may be used for processWhere 'matches_wildcard'",
561  Here());
562  }
563  }
564 
565 // Apply mask matches_any_wildcard
566  if (currentParams.matchesAnyWildcard.value() != boost::none) {
567  const std::vector<std::string> &patterns = *currentParams.matchesAnyWildcard.value();
568  // Select observations for which the variable 'varname' matches any of the patterns
569  // 'patterns'; these may contain the * and ? wildcards.
570  if (dtype == ioda::ObsDtype::Integer) {
571  std::vector<int> data;
572  filterdata.get(varname, data);
573  processWhereMatchesAnyWildcardPattern(data, patterns, where);
574  } else if (dtype == ioda::ObsDtype::String) {
575  std::vector<std::string> data;
576  filterdata.get(varname, data);
577  processWhereMatchesAnyWildcardPattern(data, patterns, where);
578  } else {
579  throw eckit::UserError(
580  "Only string and integer variables may be used for processWhere "
581  "'matches_any_wildcard'",
582  Here());
583  }
584  }
585  }
586  }
587  }
588 // Print diagnostics for debug
589  int ii = 0;
590  for (size_t jj = 0; jj < nlocs; ++jj) {
591  if (where[jj] == false) ++ii;
592  }
593 
594  oops::Log::debug() << "processWhere: selected " << ii << " obs." << std::endl;
595  return where;
596 }
597 
598 // -----------------------------------------------------------------------------
599 
600 } // namespace ufo
ObsFilterData provides access to all data related to an ObsFilter.
size_t nlocs() const
Returns the number of locations in the associated ObsSpace.
ioda::ObsDtype dtype(const Variable &) const
Determines dtype of the provided variable.
bool has(const Variable &varname) const
Returns true if variable varname is known to ObsFilterData, false otherwise.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
const std::string & variable() const
Definition: Variable.cc:99
const std::string & group() const
Definition: Variable.cc:116
size_t size() const
Definition: Variable.cc:78
Variable variable(const size_t) const
Return a given constituent "primitive" (single-channel) variable.
Definition: Variables.cc:114
Contents of a single element of the list taken by the where option of each filter,...
oops::OptionalParameter< util::AnyOf< int, float, util::PartialDateTime > > minvalue
oops::OptionalParameter< util::AnyOf< int, float, util::PartialDateTime > > maxvalue
constexpr int missing
Definition: QCflags.h:20
bool contains(const std::set< T > &set, const T &element)
integer function nlocs(this)
Return the number of observational locations in this Locations object.
Definition: RunCRTM.h:27
void processWhereIsNotIn(const std::vector< T > &data, const std::set< T > &blacklist, std::vector< bool > &mask)
void processWhereIsDefined(const std::vector< float > &data, std::vector< bool > &mask)
Definition: processWhere.cc:71
void isNotInString(std::vector< bool > &where, std::vector< std::string > const &forbiddenValues, ObsFilterData const &filterdata, Variable const &varname)
bool stringMatchesAnyWildcardPattern(const std::string &string, const std::vector< std::string > &patterns)
void processWhereIsNotDefined(const std::vector< float > &data, std::vector< bool > &mask)
Definition: processWhere.cc:82
ufo::Variables getAllWhereVariables(const std::vector< WhereParameters > &params)
Definition: processWhere.cc:29
std::vector< bool > processWhere(const std::vector< WhereParameters > &params, const ObsFilterData &filterdata)
void processWhereIsClose(const std::vector< float > &data, const float tolerance, const bool relative, const std::vector< float > &whitelist, std::vector< bool > &mask)
void processWhereIsIn(const std::vector< T > &data, const std::set< T > &whitelist, std::vector< bool > &mask)
Definition: processWhere.cc:93
void processWhereMatchesRegex(const std::vector< std::string > &data, const std::string &pattern, std::vector< bool > &where)
Process a matches_regex keyword in a where clause.
void processWhereAnyBitUnsetOf(const std::vector< int > &data, const std::set< int > &bitIndices, std::vector< bool > &where)
Process an any_bit_unset_of keyword in a where clause.
void applyMinMax(std::vector< bool > &where, WhereParameters const &parameters, ObsFilterData const &filterdata, Variable const &varname)
void processWhereMatchesAnyWildcardPattern(const std::vector< std::string > &data, const std::vector< std::string > &patterns, std::vector< bool > &where)
Function used to process a matches_wildcard or matches_any_wildcard keyword in a where clause.
void isInInteger(std::vector< bool > &where, std::set< int > const &allowedValues, ObsFilterData const &filterdata, Variable const &varname)
void processWhereAnyBitSetOf(const std::vector< int > &data, const std::set< int > &bitIndices, std::vector< bool > &where)
Process an any_bit_set_of keyword in a where clause.
void isInString(std::vector< bool > &where, std::vector< std::string > const &allowedValues, ObsFilterData const &filterdata, Variable const &varname)
void processWhereMinMax(const std::vector< T > &data, const T &vmin, const T &vmax, std::vector< bool > &mask)
Definition: processWhere.cc:40
void processWhereIsNotClose(const std::vector< float > &data, const float tolerance, const bool relative, const std::vector< float > &blacklist, std::vector< bool > &mask)
void isNotInInteger(std::vector< bool > &where, std::set< int > const &forbiddenValues, ObsFilterData const &filterdata, Variable const &varname)