17 #include "ioda/ObsDataVector.h"
18 #include "ioda/ObsSpace.h"
20 #include "oops/util/Logger.h"
31 ioda::ObsSpace & obsdb,
35 :
FilterBase(obsdb, parameters, flags, obserr), parameters_(parameters)
37 oops::Log::trace() <<
"ImpactHeightCheck constructor" << std::endl;
47 oops::Log::trace() <<
"ImpactHeightCheck destructed" << std::endl;
56 std::vector<std::vector<bool>> & flagged)
const {
57 oops::Log::trace() <<
"ImpactHeightCheck post-filter" << std::endl;
58 const oops::Variables observed =
obsdb_.obsvariables();
59 const float missingFloat = util::missingValue(missingFloat);
65 const size_t nRefLevels =
data_.
nlevs(refractivityVariable);
66 std::vector<std::vector<float>> refractivity;
68 for (
size_t iLevel = 0; iLevel < nRefLevels; ++iLevel) {
69 std::vector<float> inputData;
70 data_.
get(refractivityVariable,
static_cast<int>(iLevel), inputData);
71 refractivity.push_back(inputData);
77 for (
size_t iLevel = 0; iLevel < nRefLevels; ++iLevel) {
86 if (
data_.
nlevs(modelHeightsVariable) != nRefLevels) {
87 throw eckit::BadValue(
"Model heights and refractivity must have the same number of levels",
90 std::vector<std::vector<float>> modelHeights;
93 for (
size_t iLevel = 0; iLevel < nRefLevels; ++iLevel) {
94 std::vector<float> inputData;
95 data_.
get(modelHeightsVariable,
static_cast<int>(iLevel), inputData);
96 modelHeights.push_back(inputData);
102 for (
size_t iLevel = 0; iLevel < nRefLevels; ++iLevel) {
109 std::vector<float> impactParameter;
110 data_.
get(impactVariable, impactParameter);
113 Variable radiusCurvatureParameter =
Variable(
"earth_radius_of_curvature@MetaData");
114 std::vector<float> radiusCurvature;
115 data_.
get(radiusCurvatureParameter, radiusCurvature);
118 for (
size_t iFilterVar = 0; iFilterVar < filtervars.
nvars(); ++iFilterVar) {
119 const size_t iVar = observed.find(filtervars.
variable(iFilterVar).
variable());
122 for (
size_t iObs = 0; iObs <
obsdb_.nlocs(); ++iObs) {
126 std::vector<float> refracProfile;
127 std::vector<float> heightProfile;
128 for (
size_t iLevel = 0; iLevel < nRefLevels; ++iLevel)
129 if (refractivity[iLevel][iObs] != missingFloat &&
130 modelHeights[iLevel][iObs] != missingFloat) {
131 refracProfile.push_back(refractivity[iLevel][iObs]);
132 heightProfile.push_back(modelHeights[iLevel][iObs]);
135 if (refracProfile.size() < 2) {
136 oops::Log::error() <<
"Should have at least two valid points in every profile:" <<
137 std::endl <<
"size = " << refracProfile.size() <<
" " <<
138 "iObs = " << iObs << std::endl;
139 flagged[iFilterVar][iObs] =
true;
144 " is " << refracProfile[0] <<
" to " << refracProfile.back() <<
146 oops::Log::debug() <<
"Impact height " << impactParameter[iObs] - radiusCurvature[iObs] <<
153 for (
float grad : gradient)
158 float sharpGradientImpact = std::numeric_limits<float>::lowest();
160 for (
int iLevel =
static_cast<int>(nRefLevels)-2; iLevel >= 0; --iLevel) {
161 size_t thisLevel =
static_cast<size_t>(iLevel);
162 if (gradient[thisLevel] != missingFloat &&
165 heightProfile[thisLevel],
166 radiusCurvature[iObs]);
167 oops::Log::info() <<
"Sharp refractivity gradient of " << gradient[thisLevel] <<
168 " found at " << thisLevel <<
" " << sharpGradientImpact <<
170 oops::Log::debug() << thisLevel <<
" " << refracProfile[thisLevel] <<
" " <<
171 heightProfile[thisLevel] <<
" " <<
172 radiusCurvature[thisLevel] << std::endl;
178 const float obsImpactHeight = impactParameter[iObs] - radiusCurvature[iObs];
179 oops::Log::debug() <<
"Checking minimum height " << obsImpactHeight <<
" " <<
182 radiusCurvature[iObs]) +
186 radiusCurvature[iObs]) +
188 flagged[iFilterVar][iObs] =
true;
191 oops::Log::debug() <<
"Checking maximum height " << obsImpactHeight <<
" " <<
193 radiusCurvature[iObs]) << std::endl;
194 if (obsImpactHeight >
calcImpactHeight(refracProfile.back(), heightProfile.back(),
195 radiusCurvature[iObs]))
196 flagged[iFilterVar][iObs] =
true;
206 const std::vector<float> & refrac,
207 const std::vector<float> & height)
const {
208 std::vector<float> gradient;
209 for (
size_t iLevel = 0; iLevel < refrac.size()-1; ++iLevel) {
210 gradient.push_back((refrac[iLevel+1] - refrac[iLevel]) / (height[iLevel+1] - height[iLevel]));
220 float radiusCurv)
const {
221 return 1.0E-6f * refractivity * (radiusCurv + modelHeight) + modelHeight;
227 os <<
"ImpactHeightCheck: config = " <<
parameters_ << std::endl;
Base class for UFO QC filters.
float calcImpactHeight(float, float, float) const
std::vector< float > calcVerticalGradient(const std::vector< float > &, const std::vector< float > &) const
ImpactHeightCheck(ioda::ObsSpace &, const Parameters_ &, std::shared_ptr< ioda::ObsDataVector< int > >, std::shared_ptr< ioda::ObsDataVector< float > >)
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
void print(std::ostream &) const override
Parameters controlling the operation of the ImpactHeightCheck filter.
oops::Parameter< float > sharpGradientOffset
oops::Parameter< float > surfaceOffset
Reject data within this height (in m) of the surface.
oops::Parameter< float > gradientThreshold
size_t nlevs(const Variable &) const
Returns the number of levels in the specified variable.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
std::shared_ptr< ioda::ObsDataVector< int > > flags_
const std::string & variable() const
size_t nvars() const
Return the number of constituent "primitive" (single-channel) variables.
Variable variable(const size_t) const
Return a given constituent "primitive" (single-channel) variable.