UFO
ProfileCheckTime.cc
Go to the documentation of this file.
1 /*
2  * (C) Crown copyright 2020, Met Office
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 
8 #include <set>
9 #include <utility>
10 
12 
13 namespace ufo {
14 
15  static ProfileCheckMaker<ProfileCheckTime>
17 
20  : ProfileCheckBase(options)
21  {}
22 
24  {
25  oops::Log::debug() << " Time check" << std::endl;
26 
27  const size_t numProfileLevels = profileDataHandler.getNumProfileLevels();
28  const bool ModelLevels = options_.modellevels.value();
29  const std::vector <int> &ObsType =
30  profileDataHandler.get<int>(ufo::VariableNames::ObsType);
31  const std::vector <float> &level_time =
32  profileDataHandler.get<float>(ufo::VariableNames::obs_level_time);
33  const std::vector <float> &pressures =
34  profileDataHandler.get<float>(ufo::VariableNames::obs_air_pressure);
35  std::vector <int> &uFlags =
36  profileDataHandler.get<int>(ufo::VariableNames::qcflags_eastward_wind);
37  std::vector <int> &vFlags =
38  profileDataHandler.get<int>(ufo::VariableNames::qcflags_northward_wind);
39 
40  if (!oops::allVectorsSameNonZeroSize(ObsType, pressures, uFlags, vFlags)) {
41  oops::Log::warning() << "At least one vector is the wrong size. "
42  << "Time checks will not be performed." << std::endl;
43  oops::Log::warning() << "Vector sizes: "
44  << oops::listOfVectorSizes(ObsType, pressures, uFlags, vFlags)
45  << std::endl;
46  return;
47  }
48 
49  // Flag any observations that appear outside of the current time window.
50  // The variable level_time is equal to the number of seconds relative to
51  // the middle of the time window. level_time is compared to half of the
52  // assimilation window length.
53  const float halfWindowLength = 0.5 * (profileDataHandler.getObsdb().windowEnd() -
54  profileDataHandler.getObsdb().windowStart()).toSeconds();
55  // Time QC flags. A value of true indicates an observation
56  // lies outside the time window.
57  // These flags are used in subsequent background checks.
58  std::vector <int> timeFlags(numProfileLevels, false);
59  if (!level_time.empty() && !ModelLevels) {
60  for (size_t jlev = 0; jlev < numProfileLevels; ++jlev) {
61  const float leveltime = level_time[jlev];
62  if (leveltime == missingValueFloat) continue;
63  timeFlags[jlev] = (leveltime < (-halfWindowLength - 0.5) ||
64  leveltime > (halfWindowLength - 0.5));
65  }
66  }
67 
68  // Reject sonde wind values for short period after launch.
69  const float SondeLaunchWindRej = options_.TimeCheck_SondeLaunchWindRej.value();
70  // Firstly determine surface pressure.
71  float PSurf = 0.0;
72  if (!uFlags.empty() && SondeLaunchWindRej > 0.0 &&
73  !ModelLevels &&
75  PSurf = pressures[0];
76  for (size_t jlev = 0;
77  jlev < std::min(static_cast<int>(numProfileLevels), 10);
78  ++jlev) {
80  PSurf = pressures[jlev];
81  break;
82  }
83  }
84  }
85 
86  // If surface pressure is nonzero, perform the wind rejection.
87  if (PSurf > 0.0) {
88  int NWindRej = 0; // Number of wind levels rejected
89  const float PLimit = PSurf - SondeLaunchWindRej * 100.0; // Convert from hPa to Pa
90  for (size_t jlev = 0; jlev < numProfileLevels; ++jlev) {
91  if (pressures[jlev] > 0.0 && pressures[jlev] < PLimit) break;
92  if (!uFlags.empty()) uFlags[jlev] |= ufo::MetOfficeQCFlags::Elem::PermRejectFlag;
93  if (!vFlags.empty()) vFlags[jlev] |= ufo::MetOfficeQCFlags::Elem::PermRejectFlag;
94  NWindRej++;
95  }
96  oops::Log::debug() << "Wind rejection: "
97  << "Psurf = " << PSurf * 0.01 << " hPa, "
98  << "NWindRej = " << NWindRej << std::endl;
99  }
100 
101  // Store the time flags for use in later checks.
102  profileDataHandler.set<int>(ufo::VariableNames::qcflags_time, std::move(timeFlags));
103  }
104 } // namespace ufo
Options controlling the operation of the ConventionalProfileProcessing filter.
oops::Parameter< float > TimeCheck_SondeLaunchWindRej
Threshold relative to surface pressure for rejecting levels (hPa)
oops::Parameter< bool > modellevels
Have the observation and model values been averaged onto model levels?
Profile QC checker base class.
const float missingValueFloat
Missing value (float)
const ConventionalProfileProcessingParameters & options_
Configurable parameters.
void runCheck(ProfileDataHandler &profileDataHandler) override
Run check.
ProfileCheckTime(const ConventionalProfileProcessingParameters &options)
Retrieve and store data for individual profiles. To do this, first the vector of values in the entire...
std::vector< T > & get(const std::string &fullname)
void set(const std::string &fullname, std::vector< T > &&vec_in)
int getNumProfileLevels() const
Return number of levels to which QC checks should be applied.
ioda::ObsSpace & getObsdb()
Return obsdb.
@ SurfaceLevelFlag
Surface Level.
@ PermRejectFlag
Blacklisted data.
Definition: RunCRTM.h:27
static ProfileCheckMaker< ProfileCheckTime > makerProfileCheckTime_("Time")
static constexpr const char *const qcflags_eastward_wind
static constexpr const char *const qcflags_northward_wind
static constexpr const char *const qcflags_time
static constexpr const char *const obs_level_time
Definition: VariableNames.h:86
static constexpr const char *const ObsType
Definition: VariableNames.h:87
static constexpr const char *const obs_air_pressure
Definition: VariableNames.h:18