UFO
BgdDepartureAnomaly.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2021 Met Office UK
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 <memory>
9 
10 #include "ioda/distribution/Accumulator.h"
11 #include "ioda/ObsDataVector.h"
12 #include "oops/util/missingValues.h"
14 #include "ufo/filters/Variable.h"
15 
16 namespace ufo {
17 
19 
20 BgdDepartureAnomaly::BgdDepartureAnomaly(const eckit::LocalConfiguration & conf)
21  : invars_() {
22  // Initialize options
23  options_.deserialize(conf);
24 
25  // Get channels for computing the background departure
26  channels_ = {options_.obslow.value(), options_.obshigh.value()};
27 
28  // Use default or test version of HofX
29  const std::string & hofxopt = options_.testHofX.value();
30 
31  // Include list of required data from ObsSpace
32  invars_ += Variable("brightness_temperature@ObsValue", channels_);
33  invars_ += Variable("brightness_temperature@"+hofxopt, channels_);
34 
35  if (options_.ObsBias.value().size()) {
36  // Get optional bias correction
37  const std::string & biasopt = options_.ObsBias.value();
38  invars_ += Variable("brightness_temperature@"+biasopt, channels_);
39  }
40 }
41 
42 // -----------------------------------------------------------------------------
43 
45  ioda::ObsDataVector<float> & out) const {
46  // Get dimension
47  const size_t nlocs = in.nlocs();
48  const float missing = util::missingValue(missing);
49 
50  // Get obs space
51  auto & obsdb = in.obsspace();
52 
53  ASSERT(channels_.size() == 2);
54 
55  // Get observation values for required channels
56  const std::string & hofxopt = options_.testHofX.value();
57  std::vector<float> obslow(nlocs), obshigh(nlocs);
58  std::vector<float> bgdlow(nlocs), bgdhigh(nlocs);
59  in.get(Variable("brightness_temperature@ObsValue", channels_)[0], obslow);
60  in.get(Variable("brightness_temperature@ObsValue", channels_)[1], obshigh);
61  in.get(Variable("brightness_temperature@"+hofxopt, channels_)[0], bgdlow);
62  in.get(Variable("brightness_temperature@"+hofxopt, channels_)[1], bgdhigh);
63 
64  // Get bias correction if ObsBias is present in filter options
65  if (options_.ObsBias.value().size()) {
66  const std::string & biasopt = options_.ObsBias.value();
67  std::vector<float> biaslow(nlocs), biashigh(nlocs);
68  in.get(Variable("brightness_temperature@"+biasopt, channels_)[0], biaslow);
69  in.get(Variable("brightness_temperature@"+biasopt, channels_)[1], biashigh);
70 
71  // Apply bias correction
72  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
73  bgdlow[iloc] -= biaslow[iloc];
74  bgdhigh[iloc] -= biashigh[iloc];
75  }
76  }
77 
78  // Compute background departures
79 
80  // To calculate mean departures, we need to know the number of observations with non-missing
81  // departures (taking into account all MPI ranks)...
82  std::unique_ptr<ioda::Accumulator<size_t>> countAccumulator =
83  obsdb.distribution()->createAccumulator<size_t>();
84 
85  // ... and the sum of all non-missing departures
86  enum {OMB_LOW, OMB_HIGH, NUM_OMBS};
87  std::unique_ptr<ioda::Accumulator<std::vector<double>>> totalsAccumulator =
88  obsdb.distribution()->createAccumulator<double>(NUM_OMBS);
89 
90  // First, perform local reductions...
91  std::vector<float> omblow(nlocs), ombhigh(nlocs);
92  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
93  if (obslow[iloc] == missing || bgdlow[iloc] == missing ||
94  obshigh[iloc] == missing || bgdhigh[iloc] == missing) {
95  omblow[iloc] = missing;
96  ombhigh[iloc] = missing;
97  } else {
98  omblow[iloc] = obslow[iloc] - bgdlow[iloc];
99  ombhigh[iloc] = obshigh[iloc] - bgdhigh[iloc];
100  totalsAccumulator->addTerm(iloc, OMB_LOW, omblow[iloc]);
101  totalsAccumulator->addTerm(iloc, OMB_HIGH, ombhigh[iloc]);
102  countAccumulator->addTerm(iloc, 1);
103  }
104  }
105  // ... and then global reductions.
106  const std::size_t count = countAccumulator->computeResult();
107  const std::vector<double> totals = totalsAccumulator->computeResult();
108 
109  // Calculate the means
110  const double MeanOmbLow = totals[OMB_LOW] / count;
111  const double MeanOmbHigh = totals[OMB_HIGH] / count;
112 
113  // Compute anomaly difference
114  for (size_t iloc = 0; iloc < nlocs; ++iloc) {
115  if (obslow[iloc] == missing || bgdlow[iloc] == missing ||
116  obshigh[iloc] == missing || bgdhigh[iloc] == missing) {
117  out[0][iloc] = missing;
118  } else {
119  out[0][iloc] = std::abs((omblow[iloc]-MeanOmbLow) - (ombhigh[iloc]-MeanOmbHigh));
120  }
121  }
122 }
123 
124 // -----------------------------------------------------------------------------
125 
127  return invars_;
128 }
129 
130 // -----------------------------------------------------------------------------
131 
132 } // namespace ufo
BgdDepartureAnomalyParameters options_
std::vector< int > channels_
BgdDepartureAnomaly(const eckit::LocalConfiguration &=eckit::LocalConfiguration())
const ufo::Variables & requiredVariables() const
geovals required to compute the function
void compute(const ObsFilterData &, ioda::ObsDataVector< float > &) const
compute the result of the function
oops::RequiredParameter< int > obslow
Lower frequency channel number.
oops::Parameter< std::string > ObsBias
Name of the bias correction group used to apply correction to ObsValue.
oops::Parameter< std::string > testHofX
Name of the HofX group used to replace the default group (default is HofX)
oops::RequiredParameter< int > obshigh
Higher frequency channel number.
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.
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< BgdDepartureAnomaly > makerBgdDepartureAnomaly_("BgdDepartureAnomaly")
util::Duration abs(const util::Duration &duration)