17 #include "ioda/ObsSpace.h"
18 #include "ioda/ObsVector.h"
20 #include "oops/util/IntSetParser.h"
21 #include "oops/util/Logger.h"
22 #include "oops/util/Random.h"
33 : conf_(
conf), odb_(odb), prednames_(0), jobs_(0), variances_(0), preconditioner_(0),
34 ht_rinv_h_(0), obs_num_(0), analysis_variances_(0), minimal_required_obs_number_(0) {
35 oops::Log::trace() <<
"ObsBiasCovariance::Constructor starting" << std::endl;
38 if (
conf_.has(
"obs bias.jobs")) {
39 const std::set<int> jobs = oops::parseIntSet(
conf_.getString(
"obs bias.jobs"));
40 jobs_.assign(jobs.begin(), jobs.end());
44 if (
conf_.has(
"obs bias.predictors")) {
45 std::vector<eckit::LocalConfiguration> confs;
46 conf_.get(
"obs bias.predictors", confs);
47 for (std::size_t j = 0; j < confs.size(); ++j) {
56 conf_.getUnsigned(
"obs bias.covariance.minimal required obs number");
59 if (
conf_.has(
"obs bias.covariance.variance range")) {
60 const std::vector<double>
61 range =
conf_.getDoubleVector(
"obs bias.covariance.variance range");
62 ASSERT(range.size() == 2);
68 if (
conf_.has(
"obs bias.covariance.step size")) {
73 if (
conf_.has(
"obs bias.covariance.largest analysis variance")) {
75 conf_.getDouble(
"obs bias.covariance.largest analysis variance");
99 if (
conf_.has(
"obs bias.covariance.prior")) {
101 const double inflation_ratio =
102 conf.getDouble(
"obs bias.covariance.prior.inflation.ratio");
105 const double large_inflation_ratio =
106 conf.getDouble(
"obs bias.covariance.prior.inflation.ratio for small dataset");
115 for (std::size_t j = 0; j <
jobs_.size(); ++j) {
117 large_inflation_ratio : inflation_ratio;
118 for (std::size_t p = 0; p <
prednames_.size(); ++p) {
120 if (inflation > inflation_ratio)
131 oops::Log::trace() <<
"ObsBiasCovariance::Constructor is done" << std::endl;
137 oops::Log::trace() <<
"ObsBiasCovariance::read from file " << std::endl;
140 const std::vector<std::string> gsi_predictors = {
"constant",
142 "cloud_liquid_water",
143 "lapse_rate_order_2",
145 "cosine_of_latitude_times_orbit_node",
148 "scan_angle_order_4",
149 "scan_angle_order_3",
150 "scan_angle_order_2",
154 const std::string sensor =
conf.getString(
"obs bias.sensor");
156 if (
conf.has(
"obs bias.covariance.prior.datain")) {
157 const std::string filename =
conf.getString(
"obs bias.covariance.prior.datain");
158 std::ifstream infile(filename);
160 if (infile.is_open())
168 while (infile >> ich)
173 if (nusis == sensor) {
174 auto ijob = std::find(
jobs_.begin(),
jobs_.end(), nuchan);
175 if (ijob !=
jobs_.end()) {
177 obs_num_[j] =
static_cast<int>(number);
179 for (
auto & item : gsi_predictors) {
188 for (
auto & item : gsi_predictors)
192 for (
auto & item : gsi_predictors)
197 oops::Log::trace() <<
"ObsBiasCovariance::read from prior file: "
198 << filename <<
" Done " << std::endl;
200 oops::Log::error() <<
"Unable to open file : " << filename << std::endl;
201 ABORT(
"Unable to open bias correction coeffs variance prior file ");
205 oops::Log::trace() <<
"ObsBiasCovariance::read is done " << std::endl;
211 oops::Log::trace() <<
"ObsBiasCovariance::write to file " << std::endl;
212 oops::Log::trace() <<
"ObsBiasCovariance::write is not implemented " << std::endl;
213 oops::Log::trace() <<
"ObsBiasCovariance::write is done " << std::endl;
219 oops::Log::trace() <<
"ObsBiasCovariance::linearize starts" << std::endl;
222 const int jouter = innerConf.getInt(
"iteration");
228 const std::string group_name =
"EffectiveQC" + std::to_string(jouter-1);
229 const std::vector<std::string> vars =
odb_.obsvariables().variables();
230 std::vector<int> qc_flags(
odb_.nlocs(), 999);
231 for (std::size_t j = 0; j < vars.size(); ++j) {
232 if (
odb_.has(group_name , vars[j])) {
233 odb_.get_db(group_name, vars[j], qc_flags);
234 obs_num_[j] = std::count(qc_flags.begin(), qc_flags.end(), 0);
236 throw eckit::UserError(
"Unable to find QC flags : " + vars[j] +
"@" + group_name);
241 if (
odb_.isDistributed())
249 ioda::ObsVector r_inv(
odb_,
"EffectiveError",
true);
252 std::size_t nvars = r_inv.nvars();
253 for (
size_t vv = 0; vv < nvars; ++vv) {
254 for (
size_t ii = 0; ii < r_inv.nlocs(); ++ii) {
255 if (r_inv[ii*nvars + vv] !=
missing) {
256 r_inv[ii*nvars + vv] = 1.0f / pow(r_inv[ii*nvars + vv], 2);
258 r_inv[ii*nvars + vv] = 0.0f;
264 if (
odb_.isDistributed())
270 for (std::size_t p = 0; p <
prednames_.size(); ++p) {
272 const ioda::ObsVector predx(
odb_,
prednames_[p] +
"Predictor",
true);
275 ASSERT(r_inv.nlocs() == predx.nlocs());
276 std::size_t nvars = predx.nvars();
278 for (
size_t vv = 0; vv < nvars; ++vv) {
279 for (
size_t ii = 0; ii < predx.nlocs(); ++ii)
281 pow(predx[ii*nvars + vv], 2) * r_inv[ii*nvars + vv];
286 if (
odb_.isDistributed())
291 for (std::size_t j = 0; j <
jobs_.size(); ++j) {
293 for (std::size_t p = 0; p <
prednames_.size(); ++p)
300 for (std::size_t j = 0; j <
jobs_.size(); ++j) {
301 for (std::size_t p = 0; p <
prednames_.size(); ++p) {
317 oops::Log::trace() <<
"ObsBiasCovariance::linearize is done" << std::endl;
324 oops::Log::trace() <<
"ObsBiasCovariance::multiply starts" << std::endl;
326 for (std::size_t jj = 0; jj <
variances_.size(); ++jj) {
330 oops::Log::trace() <<
"ObsBiasCovariance::multiply is done" << std::endl;
337 oops::Log::trace() <<
"ObsBiasCovariance::inverseMultiply starts" << std::endl;
339 for (std::size_t jj = 0; jj <
variances_.size(); ++jj) {
343 oops::Log::trace() <<
"ObsBiasCovariance::inverseMultiply is done" << std::endl;
349 oops::Log::trace() <<
"ObsBiasCovariance::randomize starts" << std::endl;
351 static util::NormalDistribution<double> dist(
variances_.size());
352 for (std::size_t jj = 0; jj <
variances_.size(); ++jj) {
353 dx[jj] = dist[jj] * std::sqrt(
variances_[jj]);
356 oops::Log::trace() <<
"ObsBiasCovariance::randomize is done" << std::endl;