UFO
SatName.cc
Go to the documentation of this file.
1 /*
2  * (C) Crown copyright 2021, 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 "ufo/filters/SatName.h"
9 
10 #include <algorithm>
11 #include <iostream>
12 #include <map>
13 #include <set>
14 #include <sstream>
15 #include <string>
16 #include <vector>
17 #include "ioda/distribution/Accumulator.h"
18 #include "ioda/ObsDataVector.h"
19 #include "ioda/ObsSpace.h"
20 #include "oops/util/Logger.h"
21 #include "ufo/filters/QCflags.h"
22 #include "ufo/utils/StringUtils.h"
23 
24 namespace ufo {
25 
26 // With floats std::to_string may yield unexpected results, so use stringstream instead
27 template < typename Type > std::string to_str(const Type & t)
28 {
29  std::ostringstream os;
30  os << t;
31  return os.str ();
32 }
33 
34 std::string get_channel_name(int SatID, float centralFrequency, int satobchannel,
35  const std::vector<SatIDRangeParameters> &SatIDRanges) {
36  for (const SatIDRangeParameters &SatIDRange : SatIDRanges) {
37  if (SatIDRange.minSatID <= SatID && SatID <= SatIDRange.maxSatID) {
38  for (const FrequencyBandParameters &frequencyBand : SatIDRange.Satellite_comp.value()) {
39  if (frequencyBand.minFrequency <= centralFrequency &&
40  centralFrequency <= frequencyBand.maxFrequency &&
41  (frequencyBand.satobchannel.value() == boost::none ||
42  satobchannel == *frequencyBand.satobchannel.value())) {
43  return frequencyBand.windChannel;
44  }
45  }
46  }
47  }
48  return missing_value_string;
49 }
50 std::string get_sat_name(int SatID, const std::vector<SatIDRangeParameters> &SatIDRanges) {
51  for (const SatIDRangeParameters &SatIDRange : SatIDRanges) {
52  for (const SatnameParameters &SatNames : SatIDRange.Satellite_id.value()) {
53  if (SatID == SatNames.Satnumber.value()) {
54  return SatNames.Satname;
55  }
56  }
57  }
58  return missing_value_string;
59 }
60 
61 // -----------------------------------------------------------------------------
62 SatName::SatName(ioda::ObsSpace & obsdb, const Parameters_ & parameters,
63  std::shared_ptr<ioda::ObsDataVector<int> > flags,
64  std::shared_ptr<ioda::ObsDataVector<float> > obserr)
65  : FilterBase(obsdb, parameters, flags, obserr), parameters_(parameters)
66 {
67  oops::Log::debug() << "SatName: config (constructor) = " << parameters_ << std::endl;
68 }
69 
70 // -----------------------------------------------------------------------------
72 // -----------------------------------------------------------------------------
73 /*! \brief A filter that creates a string variable that makes it simpler to
74  * identify Atmospheric Motion Vector (AMV) / Satwind observations by
75  * combining satellite and channel information. This is useful for later
76  * AMV processing where we want to apply filters to subsets of observations.
77  *
78  * \details To identify the type of motion that has been tracked, AMV BUFR observations
79  * are supplied with a channel central frequency (Hz) and a wind computation method:
80  *
81  * 002023 SATELLITE DERIVED WIND COMPUTATION METHOD
82  * * 0 Reserved
83  * * 1 INFRARED MOTION OBSERVED IN THE INFRARED CHANNEL
84  * * 2 VISIBLE MOTION OBSERVED IN THE VISIBLE CHANNEL
85  * * 3 VAPOUR CLOUD MOTION OBSERVED IN THE WATER VAPOUR CHANNEL
86  * * 4 COMBINATION MOTION OBSERVED IN A COMBINATION OF SPECTRAL CHANNELS
87  * * 5 VAPOUR CLEAR MOTION OBSERVED IN THE WATER VAPOUR CHANNEL IN CLEAR AIR
88  * * 6 OZONE MOTION OBSERVED IN THE OZONE CHANNEL
89  * * 7 VAPOUR MOTION OBSERVED IN WATER VAPOUR CHANNEL (CLOUD OR CLEAR)
90  * * 13 Root-mean-square
91  *
92  * The most common use of the wind computation method is to distinguish between clear-sky and
93  * cloudy water vapour targets.
94  *
95  * This filter combines this channel information, together with the satellite name, to
96  * create a string that defines the satellite/channel combination of each observation.
97  * We also output a diagnostic variable which provides information on unidentified
98  * satellites or channels.
99  *
100  * Required :
101  * * "MetaData", "sensor_central_frequency"
102  * * "MetaData", "satellite_identifier"
103  * * "MetaData", "wind_computation_method"
104  *
105  * Outputs:
106  * * "MetaData", "satwind_id"
107  * * "Diag", "satwind_id"
108  *
109  * Example:
110  * The following yaml will attempt to identify two infrared channels with computation method
111  * value of 1 and central frequencies falling betwen the min and max frequency bounds.
112  * If there are observations that match these conditions they are labelled with the respective
113  * "wind channel" string.
114  * If observations are identified from GOES-16 (platform number 270) they are also labelled with
115  * the respective "Sat name" string.
116  * This will fill MetaData/satwind_id with values "GOES16ir112","GOES16ir38" if these are present
117  * in the observations.
118  * If either the satellite or channel are not identified, then MetaData/satwind_id is set to
119  * "MISSING". To help track down why observations are set to missing we also output a diagnostic
120  * string variable, Diag/satwind_id. When the observation is not identified, this has the form:
121  * id<satellite identifier>_comp<cloud motion method>_freq<central frequency>.
122  * E.g. if the satellite is identified but the channel is not: "GOES16_comp3_freq0.484317e14",
123  * if the satellite is not identified but the channel is: "id270ir112".
124  *
125  * \code{.unparsed}
126  * obs filters:
127  * - filter: satname
128  * SatName assignments:
129  * - min WMO Satellite id: 1
130  * max WMO Satellite id: 999
131  * Satellite_comp:
132  * - satobchannel: 1
133  * min frequency: 2.6e+13
134  * max frequency: 2.7e+13
135  * wind channel: ir112
136  * - satobchannel: 1
137  * min frequency: 7.5e+13
138  * max frequency: 8.2e+13
139  * wind channel: ir38
140  * Satellite_id:
141  * - Sat ID: 270
142  * Sat name: GOES16
143  * \endcode
144  *
145  */
146 
147 void SatName::applyFilter(const std::vector<bool> & apply,
148  const Variables & filtervars,
149  std::vector<std::vector<bool>> & flagged) const {
150  std::vector<float> cfreq(obsdb_.nlocs());
151  std::vector<int> satid(obsdb_.nlocs());
152  std::vector<int> compm(obsdb_.nlocs());
153  // initialise output vectors to missing data string
154  std::vector<std::string> wind_id(obsdb_.nlocs(), missing_value_string);
155  std::vector<std::string> diag_id(obsdb_.nlocs(), missing_value_string);
156  // get variables from ObsSpace
157  obsdb_.get_db("MetaData", "sensor_central_frequency", cfreq);
158  obsdb_.get_db("MetaData", "satellite_identifier", satid);
159  obsdb_.get_db("MetaData", "wind_computation_method", compm);
160  // define counter variables to be summed over all processors at the end of the routine
161  std::unique_ptr<ioda::Accumulator<size_t>> countSatAccumulator =
162  obsdb_.distribution()->createAccumulator<size_t>();
163  std::unique_ptr<ioda::Accumulator<size_t>> countChanAccumulator =
164  obsdb_.distribution()->createAccumulator<size_t>();
165 
166  for (size_t jobs = 0; jobs < obsdb_.nlocs(); ++jobs) {
167  std::string satellite_name;
168  std::string channel_name;
169  satellite_name = get_sat_name(satid[jobs], parameters_.SatNameAssignments.value());
170  channel_name = get_channel_name(satid[jobs], cfreq[jobs], compm[jobs],
172  // if both satellite and channel have been identified, then combine and fill wind_id
173  if (satellite_name != missing_value_string &&
174  channel_name != missing_value_string) {
175  wind_id[jobs] = satellite_name + channel_name;
176  }
177  // if the satellite has not been identified then output the satid number to the diagnostic,
178  // otherwise output the found satellite name
179  std::string satellite_diag;
180  if (satellite_name == missing_value_string) {
181  satellite_diag = "id" + to_str(satid[jobs]);
182  countSatAccumulator->addTerm(jobs, 1);
183  } else {
184  satellite_diag = satellite_name;
185  }
186  // if the channel has not been identified then output the computation method and
187  // central frequency to the diagnostic, otherwise output the found channel name
188  std::string channel_diag;
189  if (channel_name == missing_value_string) {
190  channel_diag = "_comp" + to_str(compm[jobs]) +
191  "_freq" + to_str(cfreq[jobs]/1.0e14) + "e14";
192  countChanAccumulator->addTerm(jobs, 1);
193  } else {
194  channel_diag = channel_name;
195  }
196  // combine diagnostic strings and fill diag_id
197  diag_id[jobs] = satellite_diag + channel_diag;
198  }
199  obsdb_.put_db("MetaData", "satwind_id", wind_id);
200  obsdb_.put_db("Diag", "satwind_id", diag_id);
201  // sum number of unidentified satellites and channels
202  const std::size_t count_missing_sat = countSatAccumulator->computeResult();
203  const std::size_t count_missing_chan = countChanAccumulator->computeResult();
204  oops::Log::info() << "SatName: " << count_missing_sat
205  << " observations with unidentified satellite id" << std::endl;
206  oops::Log::info() << "SatName: " << count_missing_chan
207  << " observations with unidentified channel" << std::endl;
208  }
209 // -----------------------------------------------------------------------------
210 void SatName::print(std::ostream & os) const {
211  os << "SatName: config = " << parameters_ << std::endl;
212 }
213 // -----------------------------------------------------------------------------
214 } // namespace ufo
Base class for UFO QC filters.
Definition: FilterBase.h:45
ioda::ObsSpace & obsdb_
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
A filter that creates a string variable that makes it simpler to identify Atmospheric Motion Vector (...
Definition: SatName.cc:147
Parameters_ parameters_
Definition: SatName.h:89
SatName(ioda::ObsSpace &, const Parameters_ &, std::shared_ptr< ioda::ObsDataVector< int > >, std::shared_ptr< ioda::ObsDataVector< float > >)
Definition: SatName.cc:62
void print(std::ostream &) const override
Definition: SatName.cc:210
oops::Parameter< std::vector< SatIDRangeParameters > > SatNameAssignments
Definition: SatName.h:72
logical, parameter t
Definition: RunCRTM.h:27
std::string get_sat_name(int SatID, const std::vector< SatIDRangeParameters > &SatIDRanges)
Definition: SatName.cc:50
static const std::string missing_value_string
Definition: SatName.h:32
std::string to_str(const Type &t)
Definition: SatName.cc:27
std::string get_channel_name(int SatID, float centralFrequency, int satobchannel, const std::vector< SatIDRangeParameters > &SatIDRanges)
Definition: SatName.cc:34