16 #include "eckit/config/Configuration.h"
17 #include "eckit/geometry/Point2.h"
18 #include "eckit/geometry/Sphere.h"
20 #include "ioda/ObsDataVector.h"
21 #include "ioda/ObsSpace.h"
22 #include "oops/util/Duration.h"
23 #include "oops/util/Logger.h"
24 #include "oops/util/missingValues.h"
45 void get_locs(
const std::vector<std::size_t> & rSort,
const size_t & i1,
const size_t & i2,
46 const size_t & ilocs,
size_t & ii1,
size_t & ii2)
57 if ( rSort.size() == 1 ) {
61 }
else if ( rSort.size() == 2 ) {
66 if ( (i1 == 0) && (i2 == 0) ) {
72 }
else if ( ilocs == rSort.size()-1 ) {
86 (i1 == -1) ? ii1 = rSort.size()-1 : ii1 = i1;
87 (i2 == -1) ? ii2 = rSort.size()-1 : ii2 = i2;
89 (i1 > rSort.size()-1) ? ii1 = rSort.size()-1 : ii1 = i1;
90 (i2 > rSort.size()-1) ? ii2 = rSort.size()-1 : ii2 = i2;
99 std::vector<std::vector<bool>> & flagged)
const {
104 const std::string strInd_ =
config_.getString(
"independent",
"");
105 const std::string strDep_ =
config_.getString(
"dependent",
"");
106 size_t i1 =
config_.getInt(
"i1", 0);
107 size_t i2 =
config_.getInt(
"i2", 0);
114 oops::Log::debug() <<
"ObsDerivativeCheck: Independent Var = " << strInd_ << std::endl;
115 oops::Log::debug() <<
"ObsDerivativeCheck: Dependent Var = " << strDep_ << std::endl;
118 const size_t nlocs_ =
obsdb_.nlocs();
119 std::vector<float> dydx(nlocs_);
132 if ( strInd_ ==
"datetime" ) {
133 std::vector<util::DateTime> varIndT_(nlocs_);
134 obsdb_.get_db(
"MetaData", strInd_, varIndT_);
135 ioda::ObsSpace::RecIdxIter irec;
136 if ( strDep_ ==
"distance" ) {
139 for ( irec =
obsdb_.recidx_begin(); irec !=
obsdb_.recidx_end(); ++irec ) {
140 std:: size_t rNum =
obsdb_.recidx_recnum(irec);
141 std::vector<std::size_t> rSort =
obsdb_.recidx_vector(irec);
142 for (
size_t ilocs = 0; ilocs < rSort.size(); ++ilocs) {
143 get_locs(rSort, i1, i2, ilocs, ii1, ii2);
146 dydx[rSort[ilocs]] = 0.0;
149 eckit::geometry::Point2 Ob1(varDepX_[
"longitude"][rSort[ii2]],
150 varDepY_[
"latitude"][rSort[ii2]]);
151 eckit::geometry::Point2 Ob2(varDepX_[
"longitude"][rSort[ii1]],
152 varDepY_[
"latitude"][rSort[ii1]]);
156 dydx[rSort[ilocs]] = dist_m /
157 (varIndT_[rSort[ii2]] - varIndT_[rSort[ii1]]).toSeconds();
163 for ( irec =
obsdb_.recidx_begin(); irec !=
obsdb_.recidx_end(); ++irec ) {
164 std:: size_t rNum =
obsdb_.recidx_recnum(irec);
165 std::vector<std::size_t> rSort =
obsdb_.recidx_vector(irec);
166 for (
size_t ilocs = 0; ilocs < rSort.size(); ++ilocs) {
167 get_locs(rSort, i1, i2, ilocs, ii1, ii2);
170 dydx[rSort[ilocs]] = 0.0;
173 dydx[rSort[ilocs]] = (varDep_[strDep_][rSort[ii2]] -
174 varDep_[strDep_][rSort[ii1]]) /
175 (varIndT_[rSort[ii2]] -
176 varIndT_[rSort[ii1]]).toSeconds();
182 }
else if ( strInd_ ==
"distance" ) {
186 ioda::ObsSpace::RecIdxIter irec;
187 for ( irec =
obsdb_.recidx_begin(); irec !=
obsdb_.recidx_end(); ++irec ) {
188 std:: size_t rNum =
obsdb_.recidx_recnum(irec);
189 std::vector<std::size_t> rSort =
obsdb_.recidx_vector(irec);
190 for (
size_t ilocs = 0; ilocs < rSort.size(); ++ilocs) {
191 get_locs(rSort, i1, i2, ilocs, ii1, ii2);
194 dydx[rSort[ilocs]] = 0.0;
197 eckit::geometry::Point2 Ob1(varIndX_[
"longitude"][rSort[ii2]],
198 varIndY_[
"latitude"][rSort[ii2]]);
199 eckit::geometry::Point2 Ob2(varIndX_[
"longitude"][rSort[ii1]],
200 varIndY_[
"latitude"][rSort[ii1]]);
203 dydx[rSort[ilocs]] = (varDep_[strDep_][rSort[ii2]] - varDep_[strDep_][rSort[ii1]]) /
212 ioda::ObsSpace::RecIdxIter irec;
213 for ( irec =
obsdb_.recidx_begin(); irec !=
obsdb_.recidx_end(); ++irec ) {
214 std:: size_t rNum =
obsdb_.recidx_recnum(irec);
215 std::vector<std::size_t> rSort =
obsdb_.recidx_vector(irec);
216 for (
size_t ilocs = 0; ilocs < rSort.size(); ++ilocs) {
217 get_locs(rSort, i1, i2, ilocs, ii1, ii2);
219 dydx[rSort[ilocs]] = 0.0;
221 dydx[rSort[ilocs]] = (varDep_[strDep_][rSort[ii2]] - varDep_[strDep_][rSort[ii1]]) /
222 (varInd_[strInd_][rSort[ii2]] - varInd_[strInd_][rSort[ii1]]);
229 for (
size_t jv = 0; jv < filtervars.
nvars(); ++jv) {
230 for (
size_t jobs = 0; jobs <
obsdb_.nlocs(); ++jobs) {
232 if (dydx[jobs] > maxddx && maxddx !=
missing) flagged[jv][jobs] = flagged[jv][jobs] =
true;
233 if (dydx[jobs] < minddx && minddx !=
missing) flagged[jv][jobs] = flagged[jv][jobs] =
true;
242 os <<
"ObsDerivativeCheck: config = " <<
config_ << std::endl;
Base class for UFO QC filters.
const eckit::LocalConfiguration config_
ObsDerivativeCheck(ioda::ObsSpace &, const eckit::Configuration &, std::shared_ptr< ioda::ObsDataVector< int > >, std::shared_ptr< ioda::ObsDataVector< float > >)
void print(std::ostream &) const override
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
size_t nvars() const
Return the number of constituent "primitive" (single-channel) variables.
float distance(const Point &a, const Point &b)
Returns the distance between the two cartesian-mapped Point arguments
void get_locs(const std::vector< std::size_t > &rSort, const size_t &i1, const size_t &i2, const size_t &ilocs, size_t &ii1, size_t &ii2)
static constexpr double mean_earth_rad