UFO
ObsErrorModelRamp.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 <set>
13 #include <string>
14 #include <vector>
15 
16 #include "ioda/ObsDataVector.h"
17 #include "oops/util/IntSetParser.h"
18 #include "oops/util/missingValues.h"
19 #include "ufo/filters/Variable.h"
20 #include "ufo/utils/Constants.h"
21 
22 namespace ufo {
23 
24 static ObsFunctionMaker<ObsErrorModelRamp>
25  makerRamp_("ObsErrorModelRamp");
26 
27 // -----------------------------------------------------------------------------
28 
29 ObsErrorModelRamp::ObsErrorModelRamp(const eckit::LocalConfiguration config)
30  : invars_() {
31  // Initialize options
32  options_.deserialize(config);
33 
34  // Initialize y-variable
35  eckit::LocalConfiguration yconf;
36  yconf.set("name", classname());
37  if (options_.chlist.value() != boost::none) {
38  yconf.set("channels", options_.chlist.value().get());
39  }
40  yconf.set("options", config);
41  Variable yvar(yconf);
42 
43  // Initialize x-variable
44  const Variable &xvar = options_.xvar.value();
45  ASSERT(xvar.size() == 1 ||
46  xvar.size() == yvar.size());
47  invars_ += xvar;
48 
49  // Get piece-wise parameters from options
50  const std::vector<float> &x0 = options_.x0.value();
51  const std::vector<float> &x1 = options_.x1.value();
52  const std::vector<float> &err0 = options_.err0.value();
53  const std::vector<float> &err1 = options_.err1.value();
54 
55  // Check parameter sizes/values
56  ASSERT(yvar.size() == x0.size());
57  ASSERT(yvar.size() == x1.size());
58  ASSERT(yvar.size() == err0.size());
59  ASSERT(yvar.size() == err1.size());
60  for (size_t i = 0; i < yvar.size(); ++i) {
61  ASSERT(x1[i] >= x0[i]);
62  ASSERT(err0[i] > 0.0);
63  ASSERT(err1[i] > 0.0);
64  }
65  if (options_.x2.value() != boost::none && options_.err2.value() != boost::none) {
66  const std::vector<float> &x2 = options_.x2.value().get();
67  const std::vector<float> &err2 = options_.err2.value().get();
68  ASSERT(x2.size() == yvar.size());
69  ASSERT(err2.size() == yvar.size());
70  for (size_t i = 0; i < yvar.size(); ++i) {
71  ASSERT(x2[i] >= x1[i]);
72  ASSERT(err2[i] > 0.0);
73  }
74  }
75 }
76 
77 // -----------------------------------------------------------------------------
78 
79 ObsErrorModelRamp::~ObsErrorModelRamp() {}
80 
81 // -----------------------------------------------------------------------------
82 
83 void ObsErrorModelRamp::compute(const ObsFilterData & in,
84  ioda::ObsDataVector<float> & out) const {
85  const float missing = util::missingValue(missing);
86 
87  // Get piece-wise parameters from options
88  const std::vector<float> &x0 = options_.x0.value();
89  const std::vector<float> &x1 = options_.x1.value();
90  const std::vector<float> &err0 = options_.err0.value();
91  const std::vector<float> &err1 = options_.err1.value();
92 
93  // Check out size
94  ASSERT(out.nvars() == x0.size());
95 
96  // Compute x values
97  const Variable &xvar = options_.xvar.value();
98  ioda::ObsDataVector<float> xvals(in.obsspace(), xvar.toOopsVariables());
99  in.get(xvar, xvals);
100 
101  // Optional save of the xfunc values
102  if (options_.save) xvals.save("ObsFunction");
103 
104  float slope;
105 
106  // Optional extra ramp function
107  std::vector<float> x2;
108  std::vector<float> err2;
109  bool cal_err2_x2 = false;
110  float slope2 = missing;
111  if (options_.x2.value() != boost::none && options_.err2.value() != boost::none) {
112  x2 = options_.x2.value().get();
113  err2 = options_.x2.value().get();
114  cal_err2_x2 = true;
115  }
116  // Loop over selected variables
117  for (size_t jvar = 0; jvar < out.nvars(); ++jvar) {
118  size_t ivar = std::min(jvar, xvar.size() - 1);
119 
120  // Calculate slope of ramp for this variable
121  if (x1[jvar] > x0[jvar]) {
122  slope = (err1[jvar] - err0[jvar]) / (x1[jvar] - x0[jvar]);
123  } else {
124  slope = missing;
125  }
126  if (cal_err2_x2) {
127  if (x2[jvar] > x1[jvar]) {
128  slope2 = (err2[jvar] - err1[jvar]) / (x2[jvar] - x1[jvar]);
129  } else {
130  slope2 = missing;
131  }
132  }
133 
134  // Calculate piece-wise function value across locations
135  for (size_t iloc = 0; iloc < in.nlocs(); ++iloc) {
136  out[jvar][iloc] = missing;
137  if (xvals[ivar][iloc] != missing) {
138  if (xvals[ivar][iloc] <= x0[jvar]) {
139  out[jvar][iloc] = err0[jvar];
140  } else if (xvals[ivar][iloc] < x1[jvar] && slope != missing) {
141  out[jvar][iloc] = err0[jvar] + slope * (xvals[ivar][iloc] - x0[jvar]);
142  } else if (cal_err2_x2) {
143  if (xvals[ivar][iloc] < x2[jvar] && slope2 != missing) {
144  out[jvar][iloc] = err1[jvar] + slope2 * (xvals[ivar][iloc] - x1[jvar]);
145  } else {
146  out[jvar][iloc] = err2[jvar];
147  }
148  } else {
149  out[jvar][iloc] = err1[jvar];
150  }
151  }
152  }
153  }
154 }
155 
156 // -----------------------------------------------------------------------------
157 
158 const ufo::Variables & ObsErrorModelRamp::requiredVariables() const {
159  return invars_;
160 }
161 
162 // -----------------------------------------------------------------------------
163 
164 } // namespace ufo
constexpr int missing
Definition: QCflags.h:20
Definition: RunCRTM.h:27
static ObsFunctionMaker< ObsErrorModelRamp > makerRamp_("ObsErrorModelRamp")