UFO
TrackCheck.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2020 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 <map>
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"
24 #include "oops/util/sqr.h"
27 #include "ufo/utils/Constants.h"
30 
31 namespace ufo {
32 
33 TrackCheck::TrackObservation::TrackObservation(float latitude, float longitude,
34  const util::DateTime &time, float pressure)
35  : obsLocationTime_(latitude, longitude, time), pressure_(pressure),
36  rejectedInPreviousSweep_(false), rejectedBeforePreviousSweep_(false),
37  numNeighborsVisitedInPreviousSweep_{NO_PREVIOUS_SWEEP, NO_PREVIOUS_SWEEP}
38 {}
39 
41  const TrackObservation &buddyObs,
42  const TrackCheckParameters &options,
43  const PiecewiseLinearInterpolation &maxValidSpeedAtPressure,
44  float referencePressure) const {
45  CheckResults results;
46  util::Duration temporalDistance = abs(buddyObs.obsLocationTime_.time() -
47  this->obsLocationTime_.time());
48  const float spatialDistance = TrackCheckUtils::distance(this->obsLocationTime_.location(),
49  buddyObs.obsLocationTime_.location());
50 
51  // Estimate the speed and check if it is within the allowed range
52  const float conservativeSpeedEstimate =
53  (spatialDistance - options.spatialResolution) /
54  (temporalDistance + options.temporalResolution).toSeconds();
55  const float maxSpeed = maxValidSpeedAtPressure(referencePressure);
56  results.speedCheckResult = TrackCheckUtils::CheckResult(conservativeSpeedEstimate <= maxSpeed);
57 
58  // Estimate the climb rate and check if it is within the allowed range
59  if (options.maxClimbRate.value() != boost::none) {
60  const float pressureDiff = std::abs(pressure_ - buddyObs.pressure_);
61  const float conservativeClimbRateEstimate =
62  pressureDiff / (temporalDistance + options.temporalResolution).toSeconds();
63  results.climbRateCheckResult =
65  (conservativeClimbRateEstimate <= *options.maxClimbRate.value());
66  }
67 
68  const int resolutionMultiplier = options.distinctBuddyResolutionMultiplier;
69  results.isBuddyDistinct =
70  temporalDistance > resolutionMultiplier * options.temporalResolution &&
71  spatialDistance > resolutionMultiplier * options.spatialResolution;
72 
73  return results;
74 }
75 
77  checkCounter_.registerCheckResult(results.speedCheckResult);
78  checkCounter_.registerCheckResult(results.climbRateCheckResult);
79 }
80 
82  checkCounter_.unregisterCheckResult(results.speedCheckResult);
83  checkCounter_.unregisterCheckResult(results.climbRateCheckResult);
84 }
85 
87  rejectedBeforePreviousSweep_ = rejected();
88  rejectedInPreviousSweep_ = rejectedInSweep;
89 }
90 
92  return this->checkCounter_.failedChecksFraction();
93 }
94 
95 
96 TrackCheck::TrackCheck(ioda::ObsSpace & obsdb, const eckit::Configuration & config,
97  std::shared_ptr<ioda::ObsDataVector<int> > flags,
98  std::shared_ptr<ioda::ObsDataVector<float> > obserr)
99  : FilterBase(obsdb, config, flags, obserr)
100 {
101  oops::Log::debug() << "TrackCheck: config = " << config_ << std::endl;
102 
103  options_.reset(new TrackCheckParameters());
104  options_->deserialize(config);
105 }
106 
107 // Required for the correct destruction of options_.
109 {}
110 
111 void TrackCheck::applyFilter(const std::vector<bool> & apply,
112  const Variables & filtervars,
113  std::vector<std::vector<bool>> & flagged) const {
114  const std::vector<size_t> validObsIds = TrackCheckUtils::getValidObservationIds(apply, flags_);
115 
116  RecursiveSplitter splitter(validObsIds.size());
118  TrackCheckUtils::sortTracksChronologically(validObsIds, splitter, obsdb_);
119 
122 
123  std::vector<bool> isRejected(apply.size(), false);
124  for (auto track : splitter.multiElementGroups()) {
125  identifyRejectedObservationsInTrack(track.begin(), track.end(), validObsIds,
126  obsPressureLoc, maxSpeedByPressure, isRejected);
127  }
128  TrackCheckUtils::flagRejectedObservations(isRejected, flagged);
129 
130  if (filtervars.size() != 0) {
131  oops::Log::trace() << "TrackCheck: flagged? = " << flagged[0] << std::endl;
132  }
133 }
134 
136  ObsGroupPressureLocationTime obsPressureLoc;
138  obsPressureLoc.pressures.resize(obsdb_.nlocs());
139  obsdb_.get_db("MetaData", "air_pressure", obsPressureLoc.pressures);
140  return obsPressureLoc;
141 }
142 
144  const std::map<float, float> &maxSpeedInterpolationPoints =
145  options_->maxSpeedInterpolationPoints.value();
146 
147  std::vector<double> pressures, maxSpeeds;
148  pressures.reserve(maxSpeedInterpolationPoints.size());
149  maxSpeeds.reserve(maxSpeedInterpolationPoints.size());
150 
151  // The interpolator needs to produce speeds in km/s rather than m/s because observation
152  // locations are expressed in kilometers.
153  const int metersPerKm = 1000;
154  for (const auto &pressureAndMaxSpeed : maxSpeedInterpolationPoints) {
155  pressures.push_back(pressureAndMaxSpeed.first);
156  maxSpeeds.push_back(pressureAndMaxSpeed.second / metersPerKm);
157  }
158 
159  return PiecewiseLinearInterpolation(std::move(pressures), std::move(maxSpeeds));
160 }
161 
163  std::vector<size_t>::const_iterator trackObsIndicesBegin,
164  std::vector<size_t>::const_iterator trackObsIndicesEnd,
165  const std::vector<size_t> &validObsIds,
166  const ObsGroupPressureLocationTime &obsPressureLoc,
167  const PiecewiseLinearInterpolation &maxValidSpeedAtPressure,
168  std::vector<bool> &isRejected) const {
169 
170  std::vector<TrackObservation> trackObservations = collectTrackObservations(
171  trackObsIndicesBegin, trackObsIndicesEnd, validObsIds, obsPressureLoc);
172  std::vector<float> workspace;
173 
174  while (sweepOverObservations(trackObservations, maxValidSpeedAtPressure, workspace) ==
176  // can't exit the loop yet
177  }
178 
179  flagRejectedTrackObservations(trackObsIndicesBegin, trackObsIndicesEnd,
180  validObsIds, trackObservations, isRejected);
181 }
182 
183 std::vector<TrackCheck::TrackObservation> TrackCheck::collectTrackObservations(
184  std::vector<size_t>::const_iterator trackObsIndicesBegin,
185  std::vector<size_t>::const_iterator trackObsIndicesEnd,
186  const std::vector<size_t> &validObsIds,
187  const ObsGroupPressureLocationTime &obsPressureLoc) const {
188  std::vector<TrackObservation> trackObservations;
189  trackObservations.reserve(trackObsIndicesEnd - trackObsIndicesBegin);
190  for (std::vector<size_t>::const_iterator it = trackObsIndicesBegin;
191  it != trackObsIndicesEnd; ++it) {
192  const size_t obsId = validObsIds[*it];
193  trackObservations.push_back(TrackObservation(obsPressureLoc.locationTimes.latitudes[obsId],
194  obsPressureLoc.locationTimes.longitudes[obsId],
195  obsPressureLoc.locationTimes.datetimes[obsId],
196  obsPressureLoc.pressures[obsId]));
197  }
198  return trackObservations;
199 }
200 
202  std::vector<TrackObservation> &trackObservations,
203  const PiecewiseLinearInterpolation &maxValidSpeedAtPressure,
204  std::vector<float> &workspace) const {
205 
206  std::vector<float> &failedChecksFraction = workspace;
207  failedChecksFraction.assign(trackObservations.size(), 0.0f);
208 
209  for (int obsIdx = 0; obsIdx < trackObservations.size(); ++obsIdx) {
210  TrackObservation &obs = trackObservations[obsIdx];
211  if (obs.rejected())
212  continue;
213 
214  for (Direction dir : { FORWARD, BACKWARD}) {
215  const bool firstSweep = obs.numNeighborsVisitedInPreviousSweep(dir) == NO_PREVIOUS_SWEEP;
216  const int numNeighborsVisitedInPreviousSweep =
217  firstSweep ? 0 : obs.numNeighborsVisitedInPreviousSweep(dir);
218  int numNewDistinctBuddiesToVisit = firstSweep ? options_->numDistinctBuddiesPerDirection : 0;
219 
220  auto getNthNeighbor = [&trackObservations, obsIdx, dir](int n) -> const TrackObservation* {
221  const int neighborObsIdx = obsIdx + (dir == FORWARD ? n : -n);
222  if (neighborObsIdx < 0 || neighborObsIdx >= trackObservations.size())
223  return nullptr; // We've reached the end of the track
224  else
225  return &trackObservations[neighborObsIdx];
226  };
227 
228  float minPressureBetween = obs.pressure();
229  int neighborIdx = 1;
230  const TrackObservation *neighborObs = getNthNeighbor(neighborIdx);
231  for (; neighborIdx <= numNeighborsVisitedInPreviousSweep && neighborObs != nullptr;
232  neighborObs = getNthNeighbor(++neighborIdx)) {
233  // Strictly speaking, neighborObs->pressure should be disregarded if neighborObs has already
234  // been rejected. However, that would force us to check each pair of observations anew
235  // whenever an observation between them is rejected, whereas as things stand, we only
236  // need to "undo" checks against rejected observations.
237  minPressureBetween = std::min(minPressureBetween, neighborObs->pressure());
238  if (neighborObs->rejectedInPreviousSweep()) {
239  CheckResults results = obs.checkAgainstBuddy(*neighborObs, *options_,
240  maxValidSpeedAtPressure, minPressureBetween);
241  obs.unregisterCheckResults(results);
242  if (results.isBuddyDistinct) {
243  // The rejected distinct buddy needs to be replaced with another
244  ++numNewDistinctBuddiesToVisit;
245  }
246  }
247  }
248 
249  for (; numNewDistinctBuddiesToVisit > 0 && neighborObs != nullptr;
250  neighborObs = getNthNeighbor(++neighborIdx)) {
251  minPressureBetween = std::min(minPressureBetween, neighborObs->pressure());
252  if (!neighborObs->rejected()) {
253  CheckResults results = obs.checkAgainstBuddy(*neighborObs, *options_,
254  maxValidSpeedAtPressure, minPressureBetween);
255  obs.registerCheckResults(results);
256  if (results.isBuddyDistinct)
257  --numNewDistinctBuddiesToVisit;
258  }
259  }
260 
261  const int numNeighborsVisitedInThisSweep = neighborIdx - 1;
262  assert(numNeighborsVisitedInThisSweep >= numNeighborsVisitedInPreviousSweep);
263  obs.setNumNeighborsVisitedInPreviousSweep(dir, numNeighborsVisitedInThisSweep);
264  } // end of loop over directions
265 
266  failedChecksFraction[obsIdx] = obs.getFailedChecksFraction();
267  }
268 
269  const float maxFailedChecksFraction = *std::max_element(failedChecksFraction.begin(),
270  failedChecksFraction.end());
271  const float failedChecksThreshold = options_->rejectionThreshold * maxFailedChecksFraction;
272  if (failedChecksThreshold <= 0)
274 
275  for (int obsIdx = 0; obsIdx < trackObservations.size(); ++obsIdx) {
276  const bool rejected = failedChecksFraction[obsIdx] > failedChecksThreshold;
277  trackObservations[obsIdx].registerSweepOutcome(rejected);
278  }
279 
281 }
282 
284  std::vector<size_t>::const_iterator trackObsIndicesBegin,
285  std::vector<size_t>::const_iterator trackObsIndicesEnd,
286  const std::vector<size_t> &validObsIds,
287  const std::vector<TrackObservation> &trackObservations,
288  std::vector<bool> &isRejected) const {
289  auto trackObsIndexIt = trackObsIndicesBegin;
290  auto trackObsIt = trackObservations.begin();
291  for (; trackObsIndexIt != trackObsIndicesEnd; ++trackObsIndexIt, ++trackObsIt)
292  if (trackObsIt->rejected())
293  isRejected[validObsIds[*trackObsIndexIt]] = true;
294 }
295 
296 void TrackCheck::print(std::ostream & os) const {
297  os << "TrackCheck: config = " << config_ << std::endl;
298 }
299 
300 } // namespace ufo
ufo::TrackCheck::collectObsPressuresLocationsTimes
ObsGroupPressureLocationTime collectObsPressuresLocationsTimes() const
Definition: TrackCheck.cc:135
ufo::TrackCheckUtils::SweepResult::ANOTHER_SWEEP_REQUIRED
@ ANOTHER_SWEEP_REQUIRED
ufo::TrackCheck::CheckResults::isBuddyDistinct
bool isBuddyDistinct
Definition: src/ufo/filters/TrackCheck.h:64
ufo::TrackCheck::collectTrackObservations
std::vector< TrackObservation > collectTrackObservations(std::vector< size_t >::const_iterator trackObsIndicesBegin, std::vector< size_t >::const_iterator trackObsIndicesEnd, const std::vector< size_t > &validObsIds, const ObsGroupPressureLocationTime &obsPressureLoc) const
Definition: TrackCheck.cc:183
ufo::TrackCheck::print
void print(std::ostream &) const override
Definition: TrackCheck.cc:296
ufo::Variables
Definition: src/ufo/filters/Variables.h:24
ufo::TrackCheck::TrackObservation
Attributes of an observation belonging to a track.
Definition: src/ufo/filters/TrackCheck.h:87
ufo::TrackCheckUtils::getValidObservationIds
std::vector< size_t > getValidObservationIds(const std::vector< bool > &apply, const std::shared_ptr< ioda::ObsDataVector< int >> &flags)
Definition: TrackCheckUtils.cc:66
TrackCheck.h
PiecewiseLinearInterpolation.h
ufo::TrackCheck::TrackObservation::TrackObservation
TrackObservation(float latitude, float longitude, const util::DateTime &time, float pressure)
Definition: TrackCheck.cc:33
ufo::TrackCheck::TrackObservation::setNumNeighborsVisitedInPreviousSweep
void setNumNeighborsVisitedInPreviousSweep(Direction dir, int num)
Definition: src/ufo/filters/TrackCheck.h:99
ufo::TrackCheckUtils::ObsLocationTime::location
const Point & location() const
Definition: TrackCheckUtils.h:62
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::TrackCheck::makeMaxSpeedByPressureInterpolation
PiecewiseLinearInterpolation makeMaxSpeedByPressureInterpolation() const
Returns an interpolator mapping pressures (in Pa) to maximum accepted speeds (in km/s).
Definition: TrackCheck.cc:143
ufo::TrackCheck::TrackObservation::obsLocationTime_
TrackCheckUtils::ObsLocationTime obsLocationTime_
Definition: src/ufo/filters/TrackCheck.h:126
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::TrackCheck::Direction
Direction
Definition: src/ufo/filters/TrackCheck.h:55
ufo::TrackCheck::FORWARD
@ FORWARD
Definition: src/ufo/filters/TrackCheck.h:55
ufo::TrackCheck::TrackObservation::registerSweepOutcome
void registerSweepOutcome(bool rejectedInSweep)
Definition: TrackCheck.cc:86
ufo::TrackCheckParameters::spatialResolution
oops::Parameter< float > spatialResolution
Definition: TrackCheckParameters.h:46
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::TrackCheckParameters
Options controlling the operation of the track check filter.
Definition: TrackCheckParameters.h:31
ufo::TrackCheckUtils::ObsGroupLocationTimes::datetimes
std::vector< util::DateTime > datetimes
Definition: TrackCheckUtils.h:55
ufo::TrackCheck::CheckResults::climbRateCheckResult
TrackCheckUtils::CheckResult climbRateCheckResult
Definition: src/ufo/filters/TrackCheck.h:66
ufo
Definition: RunCRTM.h:27
ufo::TrackCheckUtils::SweepResult
SweepResult
Definition: TrackCheckUtils.h:48
ufo::TrackCheck::CheckResults::speedCheckResult
TrackCheckUtils::CheckResult speedCheckResult
Definition: src/ufo/filters/TrackCheck.h:65
ufo::TrackCheck::ObsGroupPressureLocationTime::pressures
std::vector< float > pressures
Definition: src/ufo/filters/TrackCheck.h:73
ufo::Variables::size
size_t size() const
Definition: Variables.cc:92
ufo::TrackCheckParameters::maxClimbRate
oops::OptionalParameter< float > maxClimbRate
Maximum allowed rate of ascent and descent (Pa/s). If not set, climb rate checks are disabled.
Definition: TrackCheckParameters.h:66
ufo::TrackCheck::TrackObservation::rejected
bool rejected() const
Definition: src/ufo/filters/TrackCheck.h:93
ufo::PiecewiseLinearInterpolation
Represents a piecewise linear interpolation of a set of data points.
Definition: src/ufo/utils/PiecewiseLinearInterpolation.h:17
ufo::TrackCheck::flagRejectedTrackObservations
void flagRejectedTrackObservations(std::vector< size_t >::const_iterator trackObsIndicesBegin, std::vector< size_t >::const_iterator trackObsIndicesEnd, const std::vector< size_t > &validObsIds, const std::vector< TrackObservation > &trackObservations, std::vector< bool > &isRejected) const
Definition: TrackCheck.cc:283
ufo::TrackCheck::TrackObservation::numNeighborsVisitedInPreviousSweep
int numNeighborsVisitedInPreviousSweep(Direction dir) const
Definition: src/ufo/filters/TrackCheck.h:96
ufo::TrackCheck::identifyRejectedObservationsInTrack
void identifyRejectedObservationsInTrack(std::vector< size_t >::const_iterator trackObsIndicesBegin, std::vector< size_t >::const_iterator trackObsIndicesEnd, const std::vector< size_t > &validObsIds, const ObsGroupPressureLocationTime &obsPressureLoc, const PiecewiseLinearInterpolation &maxSpeedByPressure, std::vector< bool > &isRejected) const
Definition: TrackCheck.cc:162
ufo::FilterBase::flags_
std::shared_ptr< ioda::ObsDataVector< int > > flags_
Definition: FilterBase.h:61
ufo::QCflags::track
constexpr int track
Definition: QCflags.h:26
TrackCheckParameters.h
ufo::TrackCheckUtils::groupObservationsByStation
void groupObservationsByStation(const std::vector< size_t > &validObsIds, RecursiveSplitter &splitter, const eckit::Configuration &config, const ioda::ObsSpace &obsdb)
Definition: TrackCheckUtils.cc:75
ufo::TrackCheck::ObsGroupPressureLocationTime::locationTimes
TrackCheckUtils::ObsGroupLocationTimes locationTimes
Definition: src/ufo/filters/TrackCheck.h:72
ufo::TrackCheck::TrackObservation::registerCheckResults
void registerCheckResults(const CheckResults &result)
Definition: TrackCheck.cc:76
ufo::TrackCheck::TrackObservation::pressure_
float pressure_
Definition: src/ufo/filters/TrackCheck.h:128
ufo::TrackCheck::NO_PREVIOUS_SWEEP
static const int NO_PREVIOUS_SWEEP
Definition: src/ufo/filters/TrackCheck.h:69
ufo::TrackCheckUtils::collectObservationsLocations
ObsGroupLocationTimes collectObservationsLocations(const ioda::ObsSpace &obsdb)
Definition: TrackCheckUtils.cc:145
ufo::TrackCheckParameters::temporalResolution
oops::Parameter< util::Duration > temporalResolution
Definition: TrackCheckParameters.h:37
ufo::TrackCheckUtils::ObsGroupLocationTimes::latitudes
std::vector< float > latitudes
Definition: TrackCheckUtils.h:53
ufo::abs
util::Duration abs(const util::Duration &duration)
Definition: TrackCheckUtils.h:31
ufo::TrackCheck::ObsGroupPressureLocationTime
Definition: src/ufo/filters/TrackCheck.h:71
ufo::TrackCheck::TrackObservation::unregisterCheckResults
void unregisterCheckResults(const CheckResults &result)
Definition: TrackCheck.cc:81
TrackCheckUtils.h
ufo::TrackCheck::sweepOverObservations
TrackCheckUtils::SweepResult sweepOverObservations(std::vector< TrackObservation > &trackObservations, const PiecewiseLinearInterpolation &maxValidSpeedAtPressure, std::vector< float > &workspace) const
Definition: TrackCheck.cc:201
ufo::TrackCheck::~TrackCheck
~TrackCheck() override
Definition: TrackCheck.cc:108
ioda::ObsDataVector< int >
ufo::TrackCheckUtils::ObsLocationTime::time
const util::DateTime & time() const
Definition: TrackCheckUtils.h:63
ufo::FilterBase::config_
const eckit::LocalConfiguration config_
Definition: FilterBase.h:60
ufo::TrackCheckUtils::SweepResult::NO_MORE_SWEEPS_REQUIRED
@ NO_MORE_SWEEPS_REQUIRED
ufo::TrackCheck::TrackObservation::rejectedInPreviousSweep
bool rejectedInPreviousSweep() const
Definition: src/ufo/filters/TrackCheck.h:91
ufo::TrackCheckUtils::distance
float distance(const Point &a, const Point &b)
Returns the distance between the two cartesian-mapped Point arguments
Definition: TrackCheckUtils.cc:51
ufo::TrackCheck::TrackCheck
TrackCheck(ioda::ObsSpace &obsdb, const eckit::Configuration &config, std::shared_ptr< ioda::ObsDataVector< int > > flags, std::shared_ptr< ioda::ObsDataVector< float > > obserr)
Definition: TrackCheck.cc:96
ufo::TrackCheck::applyFilter
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
Definition: TrackCheck.cc:111
ufo::TrackCheck::options_
std::unique_ptr< TrackCheckParameters > options_
Definition: src/ufo/filters/TrackCheck.h:180
Constants.h
ufo::TrackCheckUtils::sortTracksChronologically
void sortTracksChronologically(const std::vector< size_t > &validObsIds, RecursiveSplitter &splitter, const ioda::ObsSpace &obsdb)
Definition: TrackCheckUtils.cc:135
ufo::TrackCheck::TrackObservation::getFailedChecksFraction
float getFailedChecksFraction()
Definition: TrackCheck.cc:91
ufo::TrackCheckUtils::flagRejectedObservations
void flagRejectedObservations(const std::vector< bool > &isRejected, std::vector< std::vector< bool > > &flagged)
Definition: TrackCheckUtils.cc:160
RecursiveSplitter.h
ufo::TrackCheckUtils::ObsGroupLocationTimes::longitudes
std::vector< float > longitudes
Definition: TrackCheckUtils.h:54
ufo::TrackCheckParameters::distinctBuddyResolutionMultiplier
oops::Parameter< int > distinctBuddyResolutionMultiplier
Definition: TrackCheckParameters.h:62
ufo::TrackCheck::CheckResults
Results of cross-checking an observation with another (a "buddy").
Definition: src/ufo/filters/TrackCheck.h:58
ufo::TrackCheck::TrackObservation::pressure
float pressure() const
Definition: src/ufo/filters/TrackCheck.h:90
ufo::TrackCheck::BACKWARD
@ BACKWARD
Definition: src/ufo/filters/TrackCheck.h:55
ufo::TrackCheck::TrackObservation::checkAgainstBuddy
CheckResults checkAgainstBuddy(const TrackObservation &buddyObs, const TrackCheckParameters &options, const PiecewiseLinearInterpolation &maxValidSpeedAtPressure, float referencePressure) const
Definition: TrackCheck.cc:40
ufo::TrackCheckUtils::CheckResult
CheckResult
Definition: TrackCheckUtils.h:42