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"
35 const util::DateTime &time,
float pressure)
36 : obsLocationTime_(latitude, longitude, time), pressure_(pressure),
37 rejectedInPreviousSweep_(false), rejectedBeforePreviousSweep_(false),
38 numNeighborsVisitedInPreviousSweep_{NO_PREVIOUS_SWEEP, NO_PREVIOUS_SWEEP}
45 float referencePressure)
const {
48 this->obsLocationTime_.time());
53 const float conservativeSpeedEstimate =
56 const float maxSpeed = maxValidSpeedAtPressure(referencePressure);
62 const float conservativeClimbRateEstimate =
66 (conservativeClimbRateEstimate <= *options.
maxClimbRate.value());
88 rejectedBeforePreviousSweep_ = rejected();
89 rejectedInPreviousSweep_ = rejectedInSweep;
93 return this->checkCounter_.failedChecksFraction();
111 std::vector<std::vector<bool>> & flagged)
const {
114 const std::vector<size_t> validObsIds
123 std::vector<bool> isRejected(obsPressureLoc.
pressures.size(),
false);
126 obsPressureLoc, maxSpeedByPressure, isRejected);
136 return obsPressureLoc;
140 const std::map<float, float> &maxSpeedInterpolationPoints =
143 std::vector<double> pressures, maxSpeeds;
144 pressures.reserve(maxSpeedInterpolationPoints.size());
145 maxSpeeds.reserve(maxSpeedInterpolationPoints.size());
149 const int metersPerKm = 1000;
150 for (
const auto &pressureAndMaxSpeed : maxSpeedInterpolationPoints) {
151 pressures.push_back(pressureAndMaxSpeed.first);
152 maxSpeeds.push_back(pressureAndMaxSpeed.second / metersPerKm);
159 std::vector<size_t>::const_iterator trackObsIndicesBegin,
160 std::vector<size_t>::const_iterator trackObsIndicesEnd,
161 const std::vector<size_t> &validObsIds,
164 std::vector<bool> &isRejected)
const {
167 trackObsIndicesBegin, trackObsIndicesEnd, validObsIds, obsPressureLoc);
168 std::vector<float> workspace;
176 validObsIds, trackObservations, isRejected);
180 std::vector<size_t>::const_iterator trackObsIndicesBegin,
181 std::vector<size_t>::const_iterator trackObsIndicesEnd,
182 const std::vector<size_t> &validObsIds,
184 std::vector<TrackObservation> trackObservations;
185 trackObservations.reserve(trackObsIndicesEnd - trackObsIndicesBegin);
186 for (std::vector<size_t>::const_iterator it = trackObsIndicesBegin;
187 it != trackObsIndicesEnd; ++it) {
188 const size_t obsId = validObsIds[*it];
194 return trackObservations;
198 std::vector<TrackObservation> &trackObservations,
200 std::vector<float> &workspace)
const {
202 std::vector<float> &failedChecksFraction = workspace;
203 failedChecksFraction.assign(trackObservations.size(), 0.0f);
205 for (
int obsIdx = 0; obsIdx < trackObservations.size(); ++obsIdx) {
212 const int numNeighborsVisitedInPreviousSweep =
216 auto getNthNeighbor = [&trackObservations, obsIdx, dir](
int n) ->
const TrackObservation* {
217 const int neighborObsIdx = obsIdx + (dir ==
FORWARD ? n : -n);
218 if (neighborObsIdx < 0 || neighborObsIdx >= trackObservations.size())
221 return &trackObservations[neighborObsIdx];
224 float minPressureBetween = obs.
pressure();
227 for (; neighborIdx <= numNeighborsVisitedInPreviousSweep && neighborObs !=
nullptr;
228 neighborObs = getNthNeighbor(++neighborIdx)) {
233 minPressureBetween = std::min(minPressureBetween, neighborObs->
pressure());
236 maxValidSpeedAtPressure, minPressureBetween);
240 ++numNewDistinctBuddiesToVisit;
245 for (; numNewDistinctBuddiesToVisit > 0 && neighborObs !=
nullptr;
246 neighborObs = getNthNeighbor(++neighborIdx)) {
247 minPressureBetween = std::min(minPressureBetween, neighborObs->
pressure());
250 maxValidSpeedAtPressure, minPressureBetween);
253 --numNewDistinctBuddiesToVisit;
257 const int numNeighborsVisitedInThisSweep = neighborIdx - 1;
258 assert(numNeighborsVisitedInThisSweep >= numNeighborsVisitedInPreviousSweep);
265 const float maxFailedChecksFraction = *std::max_element(failedChecksFraction.begin(),
266 failedChecksFraction.end());
268 if (failedChecksThreshold <= 0)
271 for (
int obsIdx = 0; obsIdx < trackObservations.size(); ++obsIdx) {
272 const bool rejected = failedChecksFraction[obsIdx] > failedChecksThreshold;
273 trackObservations[obsIdx].registerSweepOutcome(rejected);
280 std::vector<size_t>::const_iterator trackObsIndicesBegin,
281 std::vector<size_t>::const_iterator trackObsIndicesEnd,
282 const std::vector<size_t> &validObsIds,
283 const std::vector<TrackObservation> &trackObservations,
284 std::vector<bool> &isRejected)
const {
285 auto trackObsIndexIt = trackObsIndicesBegin;
286 auto trackObsIt = trackObservations.begin();
287 for (; trackObsIndexIt != trackObsIndicesEnd; ++trackObsIndexIt, ++trackObsIt)
288 if (trackObsIt->rejected())
289 isRejected[validObsIds[*trackObsIndexIt]] =
true;
293 os <<
"TrackCheck: 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< float > getFloatVariableFromObsSpace(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_
Represents a piecewise linear interpolation of a set of data points.
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.
Attributes of an observation belonging to a track.
void registerCheckResults(const CheckResults &result)
bool rejectedInPreviousSweep() const
TrackObservation(float latitude, float longitude, const util::DateTime &time, float pressure)
float getFailedChecksFraction()
CheckResults checkAgainstBuddy(const TrackObservation &buddyObs, const TrackCheckParameters &options, const PiecewiseLinearInterpolation &maxValidSpeedAtPressure, float referencePressure) const
void setNumNeighborsVisitedInPreviousSweep(Direction dir, int num)
void unregisterCheckResults(const CheckResults &result)
TrackCheckUtils::ObsLocationTime obsLocationTime_
void registerSweepOutcome(bool rejectedInSweep)
int numNeighborsVisitedInPreviousSweep(Direction dir) const
TrackCheck(ioda::ObsSpace &obsdb, const Parameters_ ¶meters, std::shared_ptr< ioda::ObsDataVector< int > > flags, std::shared_ptr< ioda::ObsDataVector< float > > obserr)
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
TrackCheckUtils::SweepResult sweepOverObservations(std::vector< TrackObservation > &trackObservations, const PiecewiseLinearInterpolation &maxValidSpeedAtPressure, std::vector< float > &workspace) const
ObsGroupPressureLocationTime collectObsPressuresLocationsTimes(const ObsAccessor &obsAccessor) const
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
void print(std::ostream &) const override
PiecewiseLinearInterpolation makeMaxSpeedByPressureInterpolation() const
Returns an interpolator mapping pressures (in Pa) to maximum accepted speeds (in km/s).
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
static const int NO_PREVIOUS_SWEEP
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
Options controlling the operation of the track check filter.
oops::Parameter< std::map< float, float > > maxSpeedInterpolationPoints
oops::OptionalParameter< float > maxClimbRate
Maximum allowed rate of ascent and descent (Pa/s). If not set, climb rate checks are disabled.
oops::Parameter< float > rejectionThreshold
oops::Parameter< util::Duration > temporalResolution
oops::Parameter< float > spatialResolution
oops::Parameter< int > distinctBuddyResolutionMultiplier
oops::Parameter< int > numDistinctBuddiesPerDirection
std::vector< float > longitudes
std::vector< float > latitudes
std::vector< util::DateTime > datetimes
const Point & location() const
const util::DateTime & time() const
oops::OptionalParameter< Variable > stationIdVariable
ObsGroupLocationTimes collectObservationsLocations(const ObsAccessor &obsAccessor)
@ NO_MORE_SWEEPS_REQUIRED
ObsAccessor createObsAccessor(const boost::optional< Variable > &stationIdVariable, const ioda::ObsSpace &obsdb)
Create an ObsAccessor object providing access to observations that need to be checked by the current ...
void sortTracksChronologically(const std::vector< size_t > &validObsIds, const ObsAccessor &obsAccessor, RecursiveSplitter &splitter)
float distance(const Point &a, const Point &b)
Returns the distance between the two cartesian-mapped Point arguments
util::Duration abs(const util::Duration &duration)
Results of cross-checking an observation with another (a "buddy").
TrackCheckUtils::CheckResult climbRateCheckResult
TrackCheckUtils::CheckResult speedCheckResult
TrackCheckUtils::ObsGroupLocationTimes locationTimes
std::vector< float > pressures