UFO
CLWRetMW.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 <algorithm>
11 #include <cmath>
12 #include <iomanip>
13 #include <iostream>
14 #include <set>
15 #include <string>
16 #include <vector>
17 
18 #include "ioda/ObsDataVector.h"
19 #include "oops/util/IntSetParser.h"
20 #include "ufo/filters/Variable.h"
21 #include "ufo/utils/Constants.h"
22 
23 namespace ufo {
24 
26 
27 CLWRetMW::CLWRetMW(const eckit::LocalConfiguration & conf)
28  : invars_() {
29  // Initialize options
30  options_.deserialize(conf);
31 
32  // Check required parameters
33  // Get variable group types for CLW retrieval from option
34  ASSERT(options_.varGroup.value().size() == 1 || options_.varGroup.value().size() == 2);
35  ASSERT((options_.ch238.value() != boost::none && options_.ch314.value() != boost::none) ||
36  (options_.ch37v.value() != boost::none && options_.ch37h.value() != boost::none) ||
37  (options_.ch18v.value() != boost::none && options_.ch18h.value() != boost::none &&
38  options_.ch36v.value() != boost::none && options_.ch36h.value() != boost::none));
39 
40  if (options_.ch238.value() != boost::none && options_.ch314.value() != boost::none) {
41  // For AMSUA and ATMS retrievals
42  // Get channels for CLW retrieval from options
43  const std::vector<int> channels = {options_.ch238.value().get(), options_.ch314.value().get()};
44  ASSERT(options_.ch238.value().get() != 0 && options_.ch314.value().get() != 0
45  && channels.size() == 2);
46  // Include list of required data from ObsSpace
47  for (size_t igrp = 0; igrp < options_.varGroup.value().size(); ++igrp) {
48  invars_ += Variable("brightness_temperature@" + options_.varGroup.value()[igrp], channels);
49  }
50  invars_ += Variable("brightness_temperature@" + options_.testBias.value(), channels);
51  invars_ += Variable("sensor_zenith_angle@MetaData");
52 
53  // Include list of required data from GeoVaLs
54  invars_ += Variable("average_surface_temperature_within_field_of_view@GeoVaLs");
55  invars_ += Variable("water_area_fraction@GeoVaLs");
56  invars_ += Variable("surface_temperature_where_sea@GeoVaLs");
57 
58  } else if (options_.ch37v.value() != boost::none && options_.ch37h.value() != boost::none) {
59  // For cloud index like GMI's.
60  // Get channels for CLW retrieval from options
61  const std::vector<int> channels = {options_.ch37v.value().get(), options_.ch37h.value().get()};
62 
63  ASSERT(options_.ch37v.value().get() != 0 && options_.ch37h.value().get() != 0 &&
64  channels.size() == 2);
65  // Include list of required data from ObsSpace
66  for (size_t igrp = 0; igrp < options_.varGroup.value().size(); ++igrp) {
67  invars_ += Variable("brightness_temperature@" + options_.varGroup.value()[igrp], channels);
68  }
69  invars_ += Variable("brightness_temperature@" + options_.testBias.value(), channels);
70  // Include list of required data from ObsDiag
71  invars_ += Variable("brightness_temperature_assuming_clear_sky@ObsDiag" , channels);
72 
73  // Include list of required data from GeoVaLs
74  invars_ += Variable("water_area_fraction@GeoVaLs");
75  } else if (options_.ch18v.value() != boost::none && options_.ch18h.value() != boost::none &&
76  options_.ch36v.value() != boost::none && options_.ch36h.value() != boost::none) {
77  const std::vector<int> channels = {options_.ch18v.value().get(), options_.ch18h.value().get(),
78  options_.ch36v.value().get(), options_.ch36h.value().get()};
79  ASSERT(options_.ch18v.value().get() != 0 && options_.ch18h.value().get() != 0 &&
80  options_.ch36v.value().get() != 0 && options_.ch36h.value().get() != 0 &&
81  channels.size() == 4);
82  const std::vector<float> &sys_bias = options_.origbias.value().get();
83  ASSERT(options_.origbias.value() != boost::none);
84  // Include list of required data from ObsSpace
85  for (size_t igrp = 0; igrp < options_.varGroup.value().size(); ++igrp) {
86  invars_ += Variable("brightness_temperature@" + options_.varGroup.value()[igrp], channels);
87  }
88  invars_ += Variable("brightness_temperature@" + options_.testBias.value(), channels);
89  // Include list of required data from GeoVaLs
90  invars_ += Variable("water_area_fraction@GeoVaLs");
91  }
92 }
93 
94 // -----------------------------------------------------------------------------
95 
97 
98 // -----------------------------------------------------------------------------
99 
101  ioda::ObsDataVector<float> & out) const {
102  // Get required parameters
103  const std::vector<std::string> &vargrp = options_.varGroup.value();
104 
105  // Get dimension
106  const size_t nlocs = in.nlocs();
107  const size_t ngrps = vargrp.size();
108 
109  // Get area fraction of each surface type
110  std::vector<float> water_frac(nlocs);
111  in.get(Variable("water_area_fraction@GeoVaLs"), water_frac);
112 
113  // --------------- amsua or atms --------------------------
114  if (options_.ch238.value() != boost::none && options_.ch314.value() != boost::none) {
115  const std::vector<int> channels = {options_.ch238.value().get(), options_.ch314.value().get()};
116 
117  // Get variables from ObsSpace
118  // Get sensor zenith angle
119  std::vector<float> szas(nlocs);
120  in.get(Variable("sensor_zenith_angle@MetaData"), szas);
121 
122  // Get variables from GeoVaLs
123  // Get average surface temperature in FOV
124  std::vector<float> tsavg(nlocs);
125  in.get(Variable("average_surface_temperature_within_field_of_view@GeoVaLs"), tsavg);
126 
127  // Calculate retrieved cloud liquid water
128  std::vector<float> bt238(nlocs), bt314(nlocs);
129  for (size_t igrp = 0; igrp < ngrps; ++igrp) {
130  // Get data based on group type
131  in.get(Variable("brightness_temperature@" + vargrp[igrp], channels)[0], bt238);
132  in.get(Variable("brightness_temperature@" + vargrp[igrp], channels)[1], bt314);
133  // Get bias based on group type
134  if (options_.addBias.value() == vargrp[igrp]) {
135  std::vector<float> bias238(nlocs), bias314(nlocs);
136  if (in.has(Variable("brightness_temperature@" + options_.testBias.value(), channels)[0])) {
137  in.get(Variable("brightness_temperature@" + options_.testBias.value(), channels)[0],
138  bias238);
139  in.get(Variable("brightness_temperature@" + options_.testBias.value(), channels)[1],
140  bias314);
141  } else {
142  bias238.assign(nlocs, 0.0f);
143  bias314.assign(nlocs, 0.0f);
144  }
145  // Add bias correction to the assigned group (only for ObsValue; H(x) already includes bias
146  // correction
147  if (options_.addBias.value() == "ObsValue") {
148  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
149  bt238[iloc] = bt238[iloc] - bias238[iloc];
150  bt314[iloc] = bt314[iloc] - bias314[iloc];
151  }
152  }
153  }
154 
155  // Compute the cloud liquid water
156  cloudLiquidWater(szas, tsavg, water_frac, bt238, bt314, out[igrp]);
157  }
158  // -------------------- GMI ---------------------------
159  } else if (options_.ch37v.value() != boost::none && options_.ch37h.value() != boost::none) {
160  const std::vector<int> channels = {options_.ch37v.value().get(), options_.ch37h.value().get()};
161  // Indices of data at channeles 37v and 37h in the above array "channels"
162  const int jch37v = 0;
163  const int jch37h = 1;
164  std::vector<float> bt_clr_37v(nlocs), bt_clr_37h(nlocs);
165  in.get(Variable("brightness_temperature_assuming_clear_sky@ObsDiag" , channels)
166  [jch37v], bt_clr_37v);
167  in.get(Variable("brightness_temperature_assuming_clear_sky@ObsDiag" , channels)
168  [jch37h], bt_clr_37h);
169  // Calculate retrieved cloud liquid water
170  std::vector<float> bt37v(nlocs), bt37h(nlocs);
171  for (size_t igrp = 0; igrp < ngrps; ++igrp) {
172  // Get data based on group type
173  in.get(Variable("brightness_temperature@" + vargrp[igrp], channels) [jch37v], bt37v);
174  in.get(Variable("brightness_temperature@" + vargrp[igrp], channels) [jch37h], bt37h);
175  // Get bias based on group type
176  if (options_.addBias.value() == vargrp[igrp]) {
177  std::vector<float> bias37v(nlocs), bias37h(nlocs);
178  if (in.has(Variable("brightness_temperature@" + options_.testBias.value(), channels)
179  [jch37v])) {
180  in.get(Variable("brightness_temperature@" + options_.testBias.value(), channels)
181  [jch37v], bias37v);
182  in.get(Variable("brightness_temperature@" + options_.testBias.value(), channels)
183  [jch37h], bias37h);
184  } else {
185  bias37v.assign(nlocs, 0.0f);
186  bias37h.assign(nlocs, 0.0f);
187  }
188  // Add bias correction to the assigned group (only for ObsValue; H(x) already includes bias
189  // correction
190  if (options_.addBias.value() == "ObsValue") {
191  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
192  bt37v[iloc] = bt37v[iloc] - bias37v[iloc];
193  bt37h[iloc] = bt37h[iloc] - bias37h[iloc];
194  }
195  }
196  }
197 
198 
199  // Compute cloud index
200  CIret_37v37h_diff(bt_clr_37v, bt_clr_37h, water_frac, bt37v, bt37h, out[igrp]);
201  }
202  // -------------------- amsr2 ---------------------------
203  } else if (options_.ch18v.value() != boost::none && options_.ch18h.value() != boost::none &&
204  options_.ch36v.value() != boost::none && options_.ch36h.value() != boost::none) {
205  const std::vector<int> channels = {options_.ch18v.value().get(), options_.ch18h.value().get(),
206  options_.ch36v.value().get(), options_.ch36h.value().get()};
207  const int jch18v = 0;
208  const int jch18h = 1;
209  const int jch36v = 2;
210  const int jch36h = 3;
211  // systematic bias for channels 1-14.
212  const std::vector<float> &sys_bias = options_.origbias.value().get();
213  // Calculate retrieved cloud liquid water
214  std::vector<float> bt18v(nlocs), bt18h(nlocs), bt36v(nlocs), bt36h(nlocs);
215 
216  for (size_t igrp = 0; igrp < ngrps; ++igrp) {
217  // Get data based on group type
218  const Variable btVar("brightness_temperature@" + vargrp[igrp], channels);
219  in.get(btVar[jch18v], bt18v);
220  in.get(btVar[jch18h], bt18h);
221  in.get(btVar[jch36v], bt36v);
222  in.get(btVar[jch36h], bt36h);
223  // Get bias based on group type
224  if (options_.addBias.value() == vargrp[igrp]) {
225  std::vector<float> bias18v(nlocs), bias18h(nlocs);
226  std::vector<float> bias36v(nlocs), bias36h(nlocs);
227  if (in.has(Variable("brightness_temperature@" + options_.testBias.value(), channels)
228  [jch36v])) {
229  const Variable testBias("brightness_temperature@" + options_.testBias.value(), channels);
230  in.get(testBias[jch18v], bias18v);
231  in.get(testBias[jch18h], bias18h);
232  in.get(testBias[jch36v], bias36v);
233  in.get(testBias[jch36h], bias36h);
234  } else {
235  bias18v.assign(nlocs, 0.0f);
236  bias18h.assign(nlocs, 0.0f);
237  bias36v.assign(nlocs, 0.0f);
238  bias36h.assign(nlocs, 0.0f);
239  }
240  // Add bias correction to the assigned group (only for ObsValue; H(x) already includes bias
241  // correction
242  if (options_.addBias.value() == "ObsValue") {
243  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
244  bt18v[iloc] = bt18v[iloc] - bias18v[iloc];
245  bt18h[iloc] = bt18h[iloc] - bias18h[iloc];
246  bt36v[iloc] = bt36v[iloc] - bias36v[iloc];
247  bt36h[iloc] = bt36h[iloc] - bias36h[iloc];
248  }
249  }
250  }
251  // correct systematic bias.
252  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
253  bt18v[iloc] = bt18v[iloc] - sys_bias[6];
254  bt18h[iloc] = bt18h[iloc] - sys_bias[7];
255  bt36v[iloc] = bt36v[iloc] - sys_bias[10];
256  bt36h[iloc] = bt36h[iloc] - sys_bias[11];
257  }
258  // Compute cloud index
259  clw_retr_amsr2(bt18v, bt18h, bt36v, bt36h, out[igrp]);
260  }
261  }
262 }
263 
264 // -----------------------------------------------------------------------------
265 
266 void CLWRetMW::cloudLiquidWater(const std::vector<float> & szas,
267  const std::vector<float> & tsavg,
268  const std::vector<float> & water_frac,
269  const std::vector<float> & bt238,
270  const std::vector<float> & bt314,
271  std::vector<float> & out) {
272  ///
273  /// \brief Retrieve cloud liquid water from AMSU-A 23.8 GHz and 31.4 GHz channels.
274  ///
275  /// Reference: Grody et al. (2001)
276  /// Determination of precipitable water and cloud liquid water over oceans from
277  /// the NOAA 15 advanced microwave sounding unit
278  ///
279  const float t0c = Constants::t0c;
280  const float d1 = 0.754, d2 = -2.265;
281  const float c1 = 8.240, c2 = 2.622, c3 = 1.846;
282  for (size_t iloc = 0; iloc < water_frac.size(); ++iloc) {
283  if (water_frac[iloc] >= 0.99) {
284  float cossza = cos(Constants::deg2rad * szas[iloc]);
285  float d0 = c1 - (c2 - c3 * cossza) * cossza;
286  if (tsavg[iloc] > t0c - 1.0 && bt238[iloc] <= 284.0 && bt314[iloc] <= 284.0
287  && bt238[iloc] > 0.0 && bt314[iloc] > 0.0) {
288  out[iloc] = cossza * (d0 + d1 * std::log(285.0 - bt238[iloc])
289  + d2 * std::log(285.0 - bt314[iloc]));
290  out[iloc] = std::max(0.f, out[iloc]);
291  } else {
292  out[iloc] = getBadValue();
293  }
294  }
295  }
296 }
297 
298 // -----------------------------------------------------------------------------
299 
300 // -----------------------------------------------------------------------------
301 
302 void CLWRetMW::CIret_37v37h_diff(const std::vector<float> & bt_clr_37v,
303  const std::vector<float> & bt_clr_37h,
304  const std::vector<float> & water_frac,
305  const std::vector<float> & bt37v,
306  const std::vector<float> & bt37h,
307  std::vector<float> & out) {
308  ///
309  /// \brief Retrieve cloud index from GMI 37V and 37H channels.
310  ///
311  /// GMI cloud index: 1.0 - (Tb_37v - Tb_37h)/(Tb_37v_clr - Tb_37h_clr), in which
312  /// Tb_37v_clr and Tb_37h_clr for calculated Tb at 37 V and 37H GHz from module values
313  /// assuming in clear-sky condition. Tb_37v and Tb_37h are Tb observations at 37 V and 37H GHz.
314  ///
315  for (size_t iloc = 0; iloc < water_frac.size(); ++iloc) {
316  if (water_frac[iloc] >= 0.99) {
317  if (bt37h[iloc] <= bt37v[iloc]) {
318  out[iloc] = 1.0 - (bt37v[iloc] - bt37h[iloc])/(bt_clr_37v[iloc] - bt_clr_37h[iloc]);
319  out[iloc] = std::max(0.f, out[iloc]);
320  } else {
321  out[iloc] = getBadValue();
322  }
323  } else {
324  out[iloc] = getBadValue();
325  }
326  }
327 }
328 
329 // -----------------------------------------------------------------------------
330 /// \brief Retrieve AMSR2_GCOM-W1 cloud liquid water.
331 /// This retrieval function is taken from the subroutine "retrieval_amsr2()" in GSI.
332 void CLWRetMW::clw_retr_amsr2(const std::vector<float> & bt18v,
333  const std::vector<float> & bt18h,
334  const std::vector<float> & bt36v,
335  const std::vector<float> & bt36h,
336  std::vector<float> & out) {
337  float clw;
338  std::vector<float> pred_var_clw(2);
339  // intercepts
340  const float a0_clw = -0.65929;
341  // regression coefficients
342  float regr_coeff_clw[3] = {-0.00013, 1.64692, -1.51916};
343 
344  for (size_t iloc = 0; iloc < bt18v.size(); ++iloc) {
345  if (bt18v[iloc] <= bt18h[iloc]) {
346  out[iloc] = getBadValue();
347  } else if (bt36v[iloc] <= bt36h[iloc]) {
348  out[iloc] = getBadValue();
349  } else {
350  // Calculate predictors
351  pred_var_clw[0] = log(bt18v[iloc] - bt18h[iloc]);
352  pred_var_clw[1] = log(bt36v[iloc] - bt36h[iloc]);
353  clw = a0_clw + bt36h[iloc]*regr_coeff_clw[0];
354  for (size_t nvar_clw=0; nvar_clw < pred_var_clw.size(); ++nvar_clw) {
355  clw = clw + (pred_var_clw[nvar_clw] * regr_coeff_clw[nvar_clw+1]);
356  }
357  clw = std::max(0.0f, clw);
358  clw = std::min(6.0f, clw);
359  out[iloc] = clw;
360  }
361  }
362 }
363 // -----------------------------------------------------------------------------
365  return invars_;
366 }
367 
368 // -----------------------------------------------------------------------------
369 
370 } // namespace ufo
CLWRetMWParameters options_
Definition: CLWRetMW.h:121
static void cloudLiquidWater(const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, std::vector< float > &)
Definition: CLWRetMW.cc:266
void compute(const ObsFilterData &, ioda::ObsDataVector< float > &) const
compute the result of the function
Definition: CLWRetMW.cc:100
static float getBadValue()
Definition: CLWRetMW.h:117
static void CIret_37v37h_diff(const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, std::vector< float > &)
Definition: CLWRetMW.cc:302
const ufo::Variables & requiredVariables() const
geovals required to compute the function
Definition: CLWRetMW.cc:364
CLWRetMW(const eckit::LocalConfiguration &=eckit::LocalConfiguration())
Definition: CLWRetMW.cc:27
static void clw_retr_amsr2(const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, const std::vector< float > &, std::vector< float > &)
Retrieve AMSR2_GCOM-W1 cloud liquid water. This retrieval function is taken from the subroutine "retr...
Definition: CLWRetMW.cc:332
ufo::Variables invars_
Definition: CLWRetMW.h:120
oops::OptionalParameter< int > ch37h
Definition: CLWRetMW.h:69
oops::OptionalParameter< std::vector< float > > origbias
Definition: CLWRetMW.h:77
oops::OptionalParameter< int > ch238
Definition: CLWRetMW.h:37
oops::OptionalParameter< int > ch18v
Definition: CLWRetMW.h:74
oops::OptionalParameter< int > ch37v
Definition: CLWRetMW.h:70
oops::Parameter< std::string > testBias
Definition: CLWRetMW.h:63
oops::Parameter< std::string > addBias
Definition: CLWRetMW.h:58
oops::RequiredParameter< std::vector< std::string > > varGroup
Definition: CLWRetMW.h:51
oops::OptionalParameter< int > ch18h
For retrieving AMSR2 cloud liquid water.
Definition: CLWRetMW.h:73
oops::OptionalParameter< int > ch314
Definition: CLWRetMW.h:43
oops::OptionalParameter< int > ch36v
Definition: CLWRetMW.h:76
oops::OptionalParameter< int > ch36h
Definition: CLWRetMW.h:75
ObsFilterData provides access to all data related to an ObsFilter.
size_t nlocs() const
Returns the number of locations in the associated ObsSpace.
bool has(const Variable &varname) const
Returns true if variable varname is known to ObsFilterData, false otherwise.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
constexpr int clw
Definition: QCflags.h:28
real(kind_real), parameter, public t0c
integer function nlocs(this)
Return the number of observational locations in this Locations object.
Definition: RunCRTM.h:27
static ObsFunctionMaker< CLWRetMW > makerCLWRetMW_("CLWRetMW")
static constexpr double deg2rad
Definition: Constants.h:21
static constexpr double t0c
Definition: Constants.h:24