15 #include "ioda/ObsDataVector.h"
28 const oops::Variables &simulatedVars = data.
obsspace().obsvariables();
29 std::vector<bool> rejected(
nlocs,
true);
31 std::vector<int> qcflags(
nlocs);
32 for (
size_t iv = 0; iv < simulatedVars.size(); ++iv) {
33 data.
get(
Variable(simulatedVars[iv] +
"@QCflagsData"), qcflags);
34 for (
size_t iloc = 0; iloc <
nlocs; ++iloc)
36 rejected[iloc] =
false;
47 options_.validateAndDeserialize(conf);
56 const float missingFloat = util::missingValue(
float());
57 const util::DateTime missingDateTime = util::missingValue(util::DateTime());
59 const int secondsPerDay = 60 * 60 * 24;
60 const double centuriesPerDay = 1.0 / 36525.0;
61 const double hoursPerSecond = 1.0 / 3600.0;
62 const double degreesLongitudePerHour = 15.0;
63 const double hoursPerDegreeLongitude = 1.0 / degreesLongitudePerHour;
64 const double one_over_360 = 1.0 / 360.0;
66 const util::DateTime startOfLastDayOf19thCentury(1899, 12, 31, 0, 0, 0);
72 std::vector<util::DateTime> datetimes(
nlocs);
77 std::vector<bool> rejected;
83 std::vector<float> &zenith = out[0];
84 std::fill(zenith.begin(), zenith.end(), missingFloat);
87 size_t numRejected = 0;
88 size_t numMissingLats = 0;
89 size_t numMissingLons = 0;
90 size_t numMissingDatetimes = 0;
91 size_t numOutOfRangeLats = 0;
92 size_t numOutOfRangeDatetimes = 0;
95 util::DateTime dayStart = missingDateTime;
96 util::DateTime dayEnd = missingDateTime;
100 double sinDecl, cosDecl;
102 for (
size_t loc = 0; loc <
nlocs; ++loc) {
103 if (skipRejected && rejected[loc]) {
105 oops::Log::debug() <<
"SolarZenith: ob " << loc <<
" has already been rejected"
106 <<
". Output set to missing data\n";
109 if (lats[loc] == missingFloat) {
111 oops::Log::debug() <<
"SolarZenith: missing latitude encountered for ob " << loc
112 <<
". Output set to missing data\n";
115 if (lons[loc] == missingFloat) {
117 oops::Log::debug() <<
"SolarZenith: missing longitude encountered for ob " << loc
118 <<
". Output set to missing data\n";
121 if (datetimes[loc] == missingDateTime) {
122 ++numMissingDatetimes;
123 oops::Log::debug() <<
"SolarZenith: missing datetime encountered for ob " << loc
124 <<
". Output set to missing data\n";
127 if (lats[loc] < -90 || lats[loc] > 90) {
129 oops::Log::debug() <<
"SolarZenith: latitude " << lats[loc] <<
" of ob " << loc
130 <<
" is out of range. Output set to missing data\n";
134 const util::DateTime &datetime = datetimes[loc];
136 if (datetime < dayStart || datetime >= dayEnd) {
138 int year, month, day, hour, minute, second;
139 datetime.toYYYYMMDDhhmmss(year, month, day, hour, minute, second);
140 if (year > 1950 && year <= 2200) {
141 dayStart = util::DateTime(year, month, day, 0, 0, 0);
142 dayEnd = dayStart + util::Duration(secondsPerDay);
146 const std::size_t centuryDay =
147 (dayStart - startOfLastDayOf19thCentury).toSeconds() / secondsPerDay;
148 const double rcd = centuryDay * centuriesPerDay;
149 const double rcd2 = rcd * rcd;
150 double ydeg = (rcd * 36000.769 + 279.697) * one_over_360;
151 ydeg = std::fmod(ydeg, 1.0) * 360.0;
158 eqnt = - (( 93.0 + 14.23 * rcd - 0.0144 * rcd2) * std::sin(yrad))
159 - ((432.5 - 3.71 * rcd - 0.2063 * rcd2) * std::cos(yrad))
160 + ((596.9 - 0.81 * rcd - 0.0096 * rcd2) * std::sin(2.0 * yrad))
161 - (( 1.4 + 0.28 * rcd) * std::cos(2.0 * yrad))
162 + (( 3.8 + 0.6 * rcd) * std::sin(3.0 * yrad))
163 + (( 19.5 - 0.21 * rcd - 0.0103 * rcd2) * std::cos(3.0 * yrad))
164 - (( 12.8 - 0.03 * rcd) * std::sin(4.0 * yrad));
168 const double taneqn = 0.43382 - 0.00027 * rcd;
169 const double decl = std::atan(taneqn * sinalp);
170 eqnt *= hoursPerSecond;
173 sinDecl = std::sin(decl);
174 cosDecl = std::cos(decl);
176 ++numOutOfRangeDatetimes;
177 oops::Log::debug() <<
"SolarZenith: date/time " << datetime <<
" of ob " << loc
178 <<
"is out of range. Output set to missing data\n";
183 const double lat = lats[loc];
184 const double lon = lons[loc];
187 const double sinLat = std::sin(latInRadians);
188 const double cosLat = std::cos(latInRadians);
190 const std::int64_t secondsSinceDayStart = (datetime - dayStart).toSeconds();
191 const double hoursSinceDayStart = secondsSinceDayStart * hoursPerSecond;
192 const double localSolarTimeInHours = lon * hoursPerDegreeLongitude + eqnt + hoursSinceDayStart;
195 const double hourAngleInRadians =
198 const double sinEv = sinDecl * sinLat + cosDecl * cosLat * std::cos(hourAngleInRadians);
203 if (numRejected != 0)
204 oops::Log::trace() <<
"SolarZenith: " << numMissingLats <<
" obs had already been rejected\n";
205 if (numMissingLats != 0)
206 oops::Log::trace() <<
"SolarZenith: " << numMissingLats <<
" obs had missing latitude\n";
207 if (numMissingLons != 0)
208 oops::Log::trace() <<
"SolarZenith: " << numMissingLats <<
" obs had missing longitude\n";
209 if (numOutOfRangeLats != 0)
210 oops::Log::trace() <<
"SolarZenith: " << numOutOfRangeLats
211 <<
" obs had out-of-range latitude\n";
212 if (numOutOfRangeDatetimes != 0)
213 oops::Log::trace() <<
"SolarZenith: " << numOutOfRangeDatetimes
214 <<
" obs had out-of-range datetime\n";
215 oops::Log::trace().flush();
ObsFilterData provides access to all data related to an ObsFilter.
size_t nlocs() const
Returns the number of locations in the associated ObsSpace.
ioda::ObsSpace & obsspace() const
Returns reference to ObsSpace associated with ObsFilterData.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
SolarZenith(const eckit::LocalConfiguration &conf)
SolarZenithParameters options_
void compute(const ObsFilterData &, ioda::ObsDataVector< float > &) const override
compute the result of the function
const ufo::Variables & requiredVariables() const override
geovals required to compute the function
oops::Parameter< bool > skipRejected
std::vector< bool > identifyRejectedObservations(const ObsFilterData &data)
integer function nlocs(this)
Return the number of observational locations in this Locations object.
static ObsFunctionMaker< SolarZenith > maker_("SolarZenith")
static constexpr double deg2rad
static constexpr double rad2deg