18 #include <boost/none.hpp>
19 #include <boost/optional.hpp>
20 #include "eckit/config/Configuration.h"
21 #include "ioda/ObsDataVector.h"
22 #include "ioda/ObsSpace.h"
23 #include "oops/base/Variables.h"
24 #include "oops/mpi/mpi.h"
25 #include "oops/util/DateTime.h"
26 #include "oops/util/Duration.h"
27 #include "oops/util/Logger.h"
42 :
FilterBase(obsdb, parameters, flags, obserr), options_(parameters)
51 const eckit::LocalConfiguration &conf)
63 std::vector<std::vector<bool> > & flagged)
const {
70 obsdb_.windowEnd(), oops::mpi::myself());
73 const std::vector<int> stationIds =
unitTestConfig_.getIntVector(
"station_ids_wide");
74 widerObsSpace.put_db(
"MetaData",
"station_id", stationIds);
76 const std::vector<std::string> stationIds =
78 widerObsSpace.put_db(
"MetaData",
"station_id", stationIds);
81 const std::vector<float> airTemperatures =
83 widerObsSpace.put_db(
"ObsValue",
"air_temperature", airTemperatures);
86 std::shared_ptr<ioda::ObsDataVector<float>> obserrWide(
88 std::shared_ptr<ioda::ObsDataVector<int>> qcflagsWide(
90 const oops::RequiredParameter<SurfaceObservationSubtype> &subtype =
92 const boost::optional<TrackCheckShipCoreParameters> &trackOptions =
100 eckit::LocalConfiguration configTrackCheckShip =
101 trackOptions->toConfiguration();
102 subtype.serialize(configTrackCheckShip);
104 options_.TrackCheckUtilsParameters::serialize(configTrackCheckShip);
106 trackParams.deserialize(configTrackCheckShip);
109 qcflagsWide, obserrWide);
112 const boost::optional<StuckCheckCoreParameters> &stuckOptions =
117 widerObsSpace.index().size() >
118 (stuckOptions)->numberStuckTolerance) {
125 eckit::LocalConfiguration configStuckCheck =
126 stuckOptions->toConfiguration();
127 options_.TrackCheckUtilsParameters::serialize(configStuckCheck);
129 stuckParams.deserialize(configStuckCheck);
132 qcflagsWide, obserrWide);
144 "MetaData",
"datetime");
146 "MetaData",
"latitude");
148 "MetaData",
"longitude");
150 std::map<std::string, int> stationIdMap;
156 if (statIdVar != boost::none &&
157 obsdb_.dtype(statIdVar->group(), statIdVar->variable()) == ioda::ObsDtype::String) {
160 statIdVar->group(), statIdVar->variable());
162 statIdVar->group(), statIdVar->variable());
164 std::move(windowIds.begin(), windowIds.end(), std::back_inserter(wideIds));
166 std::sort(wideIds.begin(), wideIds.end());
167 const auto endOfUnique = std::unique(wideIds.begin(), wideIds.end());
168 wideIds.erase(endOfUnique, wideIds.end());
171 for (
const std::string& value : wideIds)
172 stationIdMap[value] = index++;
177 widerObsSpace, historicalObsAccessor);
183 typedef std::tuple<util::DateTime, float, float, int, size_t> obsIdentifierData;
188 std::set<obsIdentifierData> wideFlaggedLocationIds;
190 const std::vector<int> &wideFlags = (*qcflagsWide)[0];
191 for (
size_t i = 0; i < wideFlags.size(); i++) {
193 obsIdentifierData obsLabel = {
194 wideDts.at(i), wideLats.at(i), wideLons.at(i), wideRecordIds.at(i), 0
196 while (wideFlaggedLocationIds.find(obsLabel) != wideFlaggedLocationIds.end()) {
197 (std::get<4>(obsLabel))++;
199 wideFlaggedLocationIds.insert(obsLabel);
204 "MetaData",
"datetime");
206 "MetaData",
"latitude");
208 "MetaData",
"longitude");
209 std::vector<int> windowStationIds =
getStationIds(stationIdMap,
211 obsdb_, windowObsAccessor);
215 std::map<obsIdentifierData, const size_t> locationIdToIndex;
218 obsIdentifierData obsLabel = {windowDts.at(i), windowLats.at(i), windowLons.at(i),
219 windowStationIds.at(i), 0};
222 while (locationIdToIndex.find(obsLabel) != locationIdToIndex.end()) {
223 (std::get<4>(obsLabel))++;
225 locationIdToIndex.insert(std::pair<obsIdentifierData, const size_t>(obsLabel, i));
229 struct setIntersectionComparator {
230 bool operator()(
const obsIdentifierData &lhs,
231 const std::pair<const obsIdentifierData, const size_t> &rhs) {
232 return lhs < rhs.first;
234 bool operator()(
const std::pair<const obsIdentifierData, const size_t> &lhs,
235 const obsIdentifierData &rhs) {
236 return lhs.first < rhs;
244 for (
const obsIdentifierData &
id : wideFlaggedLocationIds) {
245 if (locationIdToIndex.find(
id) != locationIdToIndex.end()) {
246 size_t locToFlag = locationIdToIndex.at(
id);
247 globalObsToFlag.at(locToFlag) =
true;
254 const boost::optional<Variable> &stationIdVar,
255 const ioda::ObsSpace &obsdb,
257 if (stationIdVar == boost::none) {
258 if (obsdb.obs_group_vars().empty()) {
263 const std::vector<size_t> &recordNumbers = obsacc.
getRecordIds();
264 return std::vector<int>(recordNumbers.begin(), recordNumbers.end());
267 switch (obsdb.dtype(stationIdVar->group(), stationIdVar->variable())) {
268 case ioda::ObsDtype::Integer:
271 stationIdVar->variable());
274 case ioda::ObsDtype::String:
276 std::vector<std::string> stringIds =
278 stationIdVar->variable());
279 std::vector<int> ints;
280 ints.reserve(stringIds.size());
281 std::transform(stringIds.begin(), stringIds.end(), std::back_inserter(ints),
282 [&stringMap](
const std::string& value) { return stringMap.at(value); });
287 throw eckit::UserError(
"Only integer and string variables may be used as station IDs",
294 os <<
"HistoryCheck: config = " <<
config_ <<
'\n';
Base class for UFO QC filters.
const eckit::LocalConfiguration config_
std::vector< int > getStationIds(const std::map< std::string, int > &stringMap, const boost::optional< Variable > &stationIdVar, const ioda::ObsSpace &obsdb, const ObsAccessor &obsacc) const
Retrieve all station ids from the ObsAccessor. If string-labelled, ids will be converted to integers.
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
void print(std::ostream &) const override
eckit::LocalConfiguration unitTestConfig_
HistoryCheck(ioda::ObsSpace &obsdb, const Parameters_ ¶meters, std::shared_ptr< ioda::ObsDataVector< int > > flags, std::shared_ptr< ioda::ObsDataVector< float > > obserr)
Options controlling the operation of history check filter.
oops::OptionalParameter< StuckCheckCoreParameters > stuckCheckParameters
oops::Parameter< bool > resetLargerObsSpaceVariables
oops::RequiredParameter< ioda::ObsTopLevelParameters > largerObsSpace
oops::RequiredParameter< SurfaceObservationSubtype > surfaceObservationSubtype
oops::RequiredParameter< util::Duration > timeBeforeStartOfWindow
Amount of time before start of assimilation window to collect for the history check.
oops::OptionalParameter< TrackCheckShipCoreParameters > trackCheckShipParameters
This class provides access to observations that may be held on multiple MPI ranks.
std::vector< std::string > getStringVariableFromObsSpace(const std::string &group, const std::string &variable) const
std::vector< int > getIntVariableFromObsSpace(const std::string &group, const std::string &variable) const
Return the values of the specified variable at successive observation locations.
std::vector< size_t > getRecordIds() const
Return the vector of IDs of records successive observation locations belong to.
std::vector< float > getFloatVariableFromObsSpace(const std::string &group, const std::string &variable) const
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.
size_t totalNumObservations() const
void preProcess() override
Options controlling the operation of stuck check filter.
Checks tracks of ships and buoys, rejecting observations whose locations and timestamps make them inc...
Options controlling the operation of the ship track check filter.
oops::OptionalParameter< Variable > stationIdVariable
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 ...