UFO
ObsErrorFactorTopoRad.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019 UCAR
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 
9 
10 #include <math.h>
11 
12 #include <algorithm>
13 #include <iomanip>
14 #include <iostream>
15 #include <set>
16 #include <string>
17 #include <vector>
18 
19 #include "ioda/ObsDataVector.h"
20 #include "oops/util/IntSetParser.h"
21 #include "oops/util/missingValues.h"
22 #include "ufo/filters/Variable.h"
23 #include "ufo/utils/Constants.h"
24 #include "ufo/utils/StringUtils.h"
25 
26 namespace ufo {
27 
28 static ObsFunctionMaker<ObsErrorFactorTopoRad>
29  makerObsErrorFactorTopoRad_("ObsErrorFactorTopoRad");
30 
31 // -----------------------------------------------------------------------------
32 
33 ObsErrorFactorTopoRad::ObsErrorFactorTopoRad(const eckit::LocalConfiguration & conf)
34  : invars_() {
35  // Check options
36  options_.deserialize(conf);
37 
38  // Get channels from options
39  std::set<int> channelset = oops::parseIntSet(options_.channelList);
40  std::copy(channelset.begin(), channelset.end(), std::back_inserter(channels_));
41  ASSERT(channels_.size() > 0);
42 
43  // Get sensor information from options
44  const std::string &sensor = options_.sensor.value();
45 
46  // Get instrument and satellite from sensor
47  std::string inst, sat;
48  splitInstSat(sensor, inst, sat);
49  ASSERT(inst == "amsua" || inst == "atms" ||
50  inst == "iasi" || inst == "cris-fsr" || inst == "airs" || inst == "avhrr3");
51 
52  if (inst == "amsua" || inst == "atms") {
53  // Get test groups from options
54  const std::string &errgrp = options_.testObserr.value();
55  const std::string &flaggrp = options_.testQCflag.value();
56 
57  // Include list of required data from ObsSpace
58  invars_ += Variable("brightness_temperature@"+errgrp, channels_);
59  invars_ += Variable("brightness_temperature@"+flaggrp, channels_);
60  }
61 
62  // Include required variables from ObsDiag
63  invars_ += Variable("transmittances_of_atmosphere_layer@ObsDiag", channels_);
64 
65  // Include list of required data from GeoVaLs
66  invars_ += Variable("surface_geopotential_height@GeoVaLs");
67 }
68 
69 // -----------------------------------------------------------------------------
70 
72 
73 // -----------------------------------------------------------------------------
74 
76  ioda::ObsDataVector<float> & out) const {
77  // Get sensor information from options
78  const std::string &sensor = options_.sensor.value();
79 
80  // Get instrument and satellite from sensor
81  std::string inst, sat;
82  splitInstSat(sensor, inst, sat);
83 
84  // Get dimensions
85  size_t nlocs = in.nlocs();
86  size_t nchans = channels_.size();
87  size_t nlevs = in.nlevs(Variable("transmittances_of_atmosphere_layer@ObsDiag", channels_)[0]);
88 
89  // Get surface geopotential height
90  std::vector<float> zsges(nlocs);
91  in.get(Variable("surface_geopotential_height@GeoVaLs"), zsges);
92 
93  // Inflate obs error as a function of terrian height (>2000) and surface-to-space transmittance
94  if (inst == "iasi" || inst == "cris-fsr" || inst == "airs" || inst == "avhrr3") {
95  std::vector<float> tao_sfc(nlocs);
96  for (size_t ich = 0; ich < nchans; ++ich) {
97  in.get(Variable("transmittances_of_atmosphere_layer@ObsDiag", channels_)[ich],
98  nlevs - 1, tao_sfc);
99  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
100  out[ich][iloc] = 1.0;
101  if (zsges[iloc] > 2000.0) {
102  float factor = pow((2000.0/zsges[iloc]), 4);
103  out[ich][iloc] = sqrt(1.0 / (1.0 - (1.0 - factor) * tao_sfc[iloc]));
104  }
105  }
106  }
107  } else if (inst == "amsua" || inst == "atms") {
108  // Set channel numbers
109  int ich238, ich314, ich503, ich528, ich536, ich544, ich549, ich890;
110  if (inst == "amsua") {
111  ich238 = 1, ich314 = 2, ich503 = 3, ich528 = 4, ich536 = 5;
112  ich544 = 6, ich549 = 7, ich890 = 15;
113  } else if (inst == "atms") {
114  ich238 = 1, ich314 = 2, ich503 = 3, ich528 = 5, ich536 = 6;
115  ich544 = 7, ich549 = 8, ich890 = 16;
116  }
117 
118  float factor;
119  std::vector<int> qcflagdata;
120  std::vector<float> obserrdata;
121  const std::string &errgrp = options_.testObserr.value();
122  const std::string &flaggrp = options_.testQCflag.value();
123  const float missing = util::missingValue(missing);
124 
125  // Calculate error factors (error_factors) for each channel
126  for (size_t ichan = 0; ichan < nchans; ++ichan) {
127  size_t channel = ichan + 1;
128  in.get(Variable("brightness_temperature@"+errgrp, channels_)[ichan], obserrdata);
129  in.get(Variable("brightness_temperature@"+flaggrp, channels_)[ichan], qcflagdata);
130  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
131  out[ichan][iloc] = 1.0;
132  if (flaggrp == "PreQC") obserrdata[iloc] == missing ? qcflagdata[iloc] = 100
133  : qcflagdata[iloc] = 0;
134  (qcflagdata[iloc] != 0) ? (factor = 0.0) : (factor = 1.0);
135 
136  if (zsges[iloc] > 2000.0) {
137  if (channel <= ich544 || channel == ich890) {
138  out[ichan][iloc] = (2000.0/zsges[iloc]) * factor;
139  }
140  if ((zsges[iloc] > 4000.0) && (channel == ich549)) {
141  out[ichan][iloc] = (4000.0/zsges[iloc]) * factor;
142  }
143  if (factor > 0.0) out[ichan][iloc] = sqrt(1.0 / out[ichan][iloc]);
144  }
145  }
146  }
147  } else {
148  oops::Log::error() << "ObsErrorFactorTopoRad: Invalid instrument (sensor) specified: " << inst
149  << " The valid instruments are: iasi, cris-fsr, airs, avhrr3, "
150  << " amsua and atms"
151  << std::endl;
152  }
153 }
154 
155 // -----------------------------------------------------------------------------
156 
158  return invars_;
159 }
160 
161 // -----------------------------------------------------------------------------
162 
163 } // namespace ufo
ObsErrorFactorTopoRad(const eckit::LocalConfiguration &)
void compute(const ObsFilterData &, ioda::ObsDataVector< float > &) const
compute the result of the function
const ufo::Variables & requiredVariables() const
geovals required to compute the function
ObsErrorFactorTopoRadParameters options_
oops::RequiredParameter< std::string > channelList
List of channels to which the observation error factor applies.
oops::Parameter< std::string > testObserr
Name of the data group to which the observation error is applied (default: ObsErrorData)
oops::RequiredParameter< std::string > sensor
Name of the sensor for which the observation error factor applies.
oops::Parameter< std::string > testQCflag
Name of the data group to which the QC flag is applied (default is QCflagsData)
ObsFilterData provides access to all data related to an ObsFilter.
size_t nlocs() const
Returns the number of locations in the associated ObsSpace.
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.
constexpr int missing
Definition: QCflags.h:20
integer function nlocs(this)
Return the number of observational locations in this Locations object.
Definition: RunCRTM.h:27
static ObsFunctionMaker< ObsErrorFactorTopoRad > makerObsErrorFactorTopoRad_("ObsErrorFactorTopoRad")
void splitInstSat(const std::string &instsat, std::string &inst, std::string &sat)
Definition: StringUtils.cc:51