Loading [MathJax]/jax/input/TeX/config.js
OOPS
All Classes Namespaces Files Functions Variables Typedefs Macros Pages
LocalEnsembleSolver.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2020 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 
8 #ifndef OOPS_ASSIMILATION_LOCALENSEMBLESOLVER_H_
9 #define OOPS_ASSIMILATION_LOCALENSEMBLESOLVER_H_
10 
11 #include <map>
12 #include <memory>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "eckit/config/Configuration.h"
18 #include "eckit/config/LocalConfiguration.h"
19 #include "oops/base/Departures.h"
21 #include "oops/base/Geometry.h"
23 #include "oops/base/Model.h"
25 #include "oops/base/ObsEnsemble.h"
26 #include "oops/base/ObsErrors.h"
27 #include "oops/base/Observations.h"
28 #include "oops/base/Observers.h"
30 #include "oops/base/ObsSpaces.h"
31 #include "oops/base/State.h"
36 #include "oops/util/ConfigFunctions.h"
37 #include "oops/util/Logger.h"
38 #include "oops/util/Timer.h"
39 
40 namespace oops {
41 
42 /// \brief Base class for LETKF-type solvers
43 template <typename MODEL, typename OBS>
64  typedef std::vector<std::shared_ptr<ObsData_>> ObsDataVec_;
65 
66  public:
67  static const std::string classname() {return "oops::LocalEnsembleSolver";}
68 
69  /// initialize solver with \p obspaces, \p geometry, full \p config and \p nens ensemble size
70  LocalEnsembleSolver(ObsSpaces_ & obspaces, const Geometry_ & geometry,
71  const eckit::Configuration & config, size_t nens, const State4D_ & xbmean);
72  virtual ~LocalEnsembleSolver() = default;
73 
74  /// computes ensemble H(\p xx), returns mean H(\p xx), saves as hofx \p iteration
75  virtual Observations_ computeHofX(const StateEnsemble4D_ & xx, size_t iteration,
76  bool readFromDisk);
77 
78  /// update background ensemble \p bg to analysis ensemble \p an at a grid point location \p i
79  virtual void measurementUpdate(const IncrementEnsemble4D_ & bg,
80  const GeometryIterator_ & i, IncrementEnsemble4D_ & an) = 0;
81 
82  /// copy \p an[\p i] = \p bg[\p i] (e.g. when there are no local observations to update state)
83  virtual void copyLocalIncrement(const IncrementEnsemble4D_ & bg,
84  const GeometryIterator_ & i, IncrementEnsemble4D_ & an) const;
85 
86  /// compute H(x) based on 4D state \p xx and put the result into \p yy. Also sets up
87  /// R_ based on the QC filters run during H(x)
88  void computeHofX4D(const eckit::Configuration &, const State4D_ &, Observations_ &);
89  /// accessor to obs localizations
90  const ObsLocalizations_ & obsloc() const {return obsloc_;}
91 
92  protected:
93  const Geometry_ & geometry_; ///< Geometry associated with the updated states
94  const ObsSpaces_ & obspaces_; ///< ObsSpaces used in the update
95  Departures_ omb_; ///< obs - mean(H(x)); set in computeHofX method
96  DeparturesEnsemble_ Yb_; ///< ensemble perturbations in the observation space;
97  /// set in computeHofX method
98  std::unique_ptr<ObsErrors_> R_; ///< observation errors, set in computeHofX method
99  std::unique_ptr<Departures_> invVarR_; ///< inverse observation error variance; set in
100  /// computeHofX method
101 
102  private:
103  const eckit::LocalConfiguration obsconf_; // configuration for observations
104  ObsLocalizations_ obsloc_; ///< observation space localization
105 };
106 
107 // -----------------------------------------------------------------------------
108 
109 template <typename MODEL, typename OBS>
111  const Geometry_ & geometry,
112  const eckit::Configuration & config, size_t nens,
113  const State4D_ & xbmean)
114  : geometry_(geometry), obspaces_(obspaces), omb_(obspaces_), Yb_(obspaces_, nens),
115  obsconf_(config, "observations"), obsloc_(obsconf_, obspaces_) {}
116 
117 // -----------------------------------------------------------------------------
118 
119 template <typename MODEL, typename OBS>
120 void LocalEnsembleSolver<MODEL, OBS>::computeHofX4D(const eckit::Configuration & config,
121  const State4D_ & xx, Observations_ & yy) {
122  // compute forecast length from State4D times
123  const std::vector<util::DateTime> times = xx.validTimes();
124  const util::Duration flength = times[times.size()-1] - times[0];
125  // observation window is passed to PseudoModel as the default model time step.
126  // This is required when State4D has a single state: in this case if the default
127  // model time step is not specified, it will be set to zero and no observations
128  // will be processed during the "forecast"
129  const util::Duration winlen = obspaces_.windowEnd() - obspaces_.windowStart();
130 
131  // Setup PseudoModelState4D
132  std::unique_ptr<PseudoModel_> pseudomodel(new PseudoModel_(xx, winlen));
133  const Model_ model(std::move(pseudomodel));
134  // Setup model and obs biases; obs errors
135  ModelAux_ moderr(geometry_, eckit::LocalConfiguration());
136  ObsAux_ obsaux(obspaces_, obsconf_);
137  R_.reset(new ObsErrors_(obsconf_, obspaces_));
138  // Setup and run the model forecast with observers
139  State_ init_xx = xx[0];
141  Observers_ hofx(obspaces_, obsconf_);
142 
143  hofx.initialize(geometry_, obsaux, *R_, post, config);
144  model.forecast(init_xx, moderr, flength, post);
145  hofx.finalize(yy);
146 }
147 
148 // -----------------------------------------------------------------------------
149 
150 template <typename MODEL, typename OBS>
152  size_t iteration, bool readFromDisk) {
153  util::Timer timer(classname(), "computeHofX");
154 
155  ASSERT(ens_xx.size() == Yb_.size());
156 
157  const size_t nens = ens_xx.size();
158  ObsEnsemble_ obsens(obspaces_, nens);
159 
160  if (readFromDisk) {
161  // read hofx from disk
162  Log::debug() << "Read H(X) from disk" << std::endl;
163  for (size_t jj = 0; jj < nens; ++jj) {
164  obsens[jj].read("hofx"+std::to_string(iteration)+"_"+std::to_string(jj+1));
165  Log::test() << "H(x) for member " << jj+1 << ":" << std::endl << obsens[jj] << std::endl;
166  }
167  R_.reset(new ObsErrors_(obsconf_, obspaces_));
168  } else {
169  // compute and save H(x)
170  Log::debug() << "Computing H(X) online" << std::endl;
171 
172  // save QC filters and ob errors to be used for all other members
173  // do not save H(X) (saved explicitly below)
174  eckit::LocalConfiguration config;
175 
176  // save hofx means that hofx will be written out into ObsSpace;
177  // if run computeHofX4D several times with save hofx on,
178  // the hofx will be overwritten,
179  // unless each time specifying iteration differently in the passed config.
180  config.set("save hofx", false);
181  config.set("save qc", false);
182  config.set("save obs errors", false);
183  config.set("iteration", std::to_string(iteration));
184 
185  for (size_t jj = 0; jj < nens; ++jj) {
186  computeHofX4D(config, ens_xx[jj], obsens[jj]);
187  Log::test() << "H(x) for member " << jj+1 << ":" << std::endl << obsens[jj] << std::endl;
188  obsens[jj].save("hofx"+std::to_string(iteration)+"_"+std::to_string(jj+1));
189  }
190 
191  // Compute H(mean(Xb))
192  State4D_ xx_mean = ens_xx.mean();
193  Observations_ y_mean_xb(obspaces_);
194 
195  // set QC for the mean
196  config.set("save qc", true);
197  config.set("save obs errors", true);
198 
199  computeHofX4D(config, xx_mean, y_mean_xb);
200 
201  y_mean_xb.save("hofx_y_mean_xb"+std::to_string(iteration));
202 
203  // QC flags and Obs errors are set to that of the H(mean(Xb))
204  R_->save("ObsError");
205  }
206  // set inverse variances
207  invVarR_.reset(new Departures_(R_->inverseVariance()));
208 
209  // calculate H(x) ensemble mean
210  Observations_ yb_mean(obsens.mean());
211 
212  // calculate H(x) ensemble perturbations
213  for (size_t iens = 0; iens < nens; ++iens) {
214  Yb_[iens] = obsens[iens] - yb_mean;
215  Yb_[iens].mask(*invVarR_);
216  }
217 
218  // calculate obs departures and mask with qc flag
219  Observations_ yobs(obspaces_, "ObsValue");
220  omb_ = yobs - yb_mean;
221  omb_.mask(*invVarR_);
222 
223  // return mean H(x)
224  return yb_mean;
225 }
226 
227 // -----------------------------------------------------------------------------
228 
229 template <typename MODEL, typename OBS>
231  const GeometryIterator_ & i,
232  IncrementEnsemble4D_ & ana_pert) const {
233  // ana_pert[i]=bkg_pert[i]
234  for (size_t itime=0; itime < bkg_pert[0].size(); ++itime) {
235  for (size_t iens=0; iens < bkg_pert.size(); ++iens) {
236  LocalIncrement gp = bkg_pert[iens][itime].getLocal(i);
237  ana_pert[iens][itime].setLocal(gp, i);
238  }
239  }
240 }
241 
242 // =============================================================================
243 
244 /// \brief factory for LETKF solvers
245 template <typename MODEL, typename OBS>
250  public:
251  static std::unique_ptr<LocalEnsembleSolver<MODEL, OBS>> create(ObsSpaces_ &, const Geometry_ &,
252  const eckit::Configuration &,
253  size_t, const State4D_ &);
254  virtual ~LocalEnsembleSolverFactory() = default;
255  protected:
256  explicit LocalEnsembleSolverFactory(const std::string &);
257  private:
259  const eckit::Configuration &, size_t,
260  const State4D_ &) = 0;
261  static std::map < std::string, LocalEnsembleSolverFactory<MODEL, OBS> * > & getMakers() {
262  static std::map < std::string, LocalEnsembleSolverFactory<MODEL, OBS> * > makers_;
263  return makers_;
264  }
265 };
266 
267 // -----------------------------------------------------------------------------
268 
269 template<class MODEL, class OBS, class T>
274 
275  virtual LocalEnsembleSolver<MODEL, OBS> * make(ObsSpaces_ & obspaces, const Geometry_ & geometry,
276  const eckit::Configuration & conf, size_t nens,
277  const State4D_ & xbmean)
278  { return new T(obspaces, geometry, conf, nens, xbmean); }
279  public:
280  explicit LocalEnsembleSolverMaker(const std::string & name)
281  : LocalEnsembleSolverFactory<MODEL, OBS>(name) {}
282 };
283 
284 // =============================================================================
285 
286 template <typename MODEL, typename OBS>
288  if (getMakers().find(name) != getMakers().end()) {
289  throw std::runtime_error(name + " already registered in local ensemble solver factory.");
290  }
291  getMakers()[name] = this;
292 }
293 
294 // -----------------------------------------------------------------------------
295 
296 template <typename MODEL, typename OBS>
297 std::unique_ptr<LocalEnsembleSolver<MODEL, OBS>>
299  const eckit::Configuration & conf, size_t nens,
300  const State4D_ & xbmean) {
301  Log::trace() << "LocalEnsembleSolver<MODEL, OBS>::create starting" << std::endl;
302  const std::string id = conf.getString("local ensemble DA.solver");
303  typename std::map<std::string, LocalEnsembleSolverFactory<MODEL, OBS>*>::iterator
304  jloc = getMakers().find(id);
305  if (jloc == getMakers().end()) {
306  Log::error() << id << " does not exist in local ensemble solver factory." << std::endl;
307  Log::error() << "LETKF solver Factory has " << getMakers().size() << " elements:" << std::endl;
308  for (typename std::map<std::string, LocalEnsembleSolverFactory<MODEL, OBS>*>::const_iterator
309  jj = getMakers().begin(); jj != getMakers().end(); ++jj) {
310  Log::error() << "A " << jj->first << " LocalEnsembleSolver" << std::endl;
311  }
312  throw std::runtime_error(id + " does not exist in local ensemble solver factory.");
313  }
314  std::unique_ptr<LocalEnsembleSolver<MODEL, OBS>>
315  ptr(jloc->second->make(obspaces, geometry, conf, nens, xbmean));
316  Log::trace() << "LocalEnsembleSolver<MODEL, OBS>::create done" << std::endl;
317  return ptr;
318 }
319 
320 // -----------------------------------------------------------------------------
321 
322 } // namespace oops
323 #endif // OOPS_ASSIMILATION_LOCALENSEMBLESOLVER_H_
Ensemble of Departures (can hold ensemble perturbations in the observation space)
Difference between two observation vectors.
Definition: Departures.h:44
Geometry class used in oops; subclass of interface class interface::Geometry.
Ensemble of 4D increments.
size_t size() const
Accessors.
virtual ~LocalEnsembleSolverFactory()=default
LocalEnsembleSolverFactory(const std::string &)
static std::map< std::string, LocalEnsembleSolverFactory< MODEL, OBS > * > & getMakers()
virtual LocalEnsembleSolver< MODEL, OBS > * make(ObsSpaces_ &, const Geometry_ &, const eckit::Configuration &, size_t, const State4D_ &)=0
static std::unique_ptr< LocalEnsembleSolver< MODEL, OBS > > create(ObsSpaces_ &, const Geometry_ &, const eckit::Configuration &, size_t, const State4D_ &)
Base class for LETKF-type solvers.
Observations< OBS > Observations_
GeometryIterator< MODEL > GeometryIterator_
const Geometry_ & geometry_
Geometry associated with the updated states.
const ObsLocalizations_ & obsloc() const
accessor to obs localizations
std::unique_ptr< Departures_ > invVarR_
PseudoModelState4D< MODEL > PseudoModel_
virtual void copyLocalIncrement(const IncrementEnsemble4D_ &bg, const GeometryIterator_ &i, IncrementEnsemble4D_ &an) const
copy an[i] = bg i \a
void computeHofX4D(const eckit::Configuration &, const State4D_ &, Observations_ &)
ObsAuxControls< OBS > ObsAux_
std::unique_ptr< ObsErrors_ > R_
observation errors, set in computeHofX method
ObsLocalizations_ obsloc_
observation space localization
const ObsSpaces_ & obspaces_
ObsSpaces used in the update.
ObsLocalizations< MODEL, OBS > ObsLocalizations_
virtual Observations_ computeHofX(const StateEnsemble4D_ &xx, size_t iteration, bool readFromDisk)
computes ensemble H(xx), returns mean H(xx), saves as hofx iteration
Observers< MODEL, OBS > Observers_
std::vector< std::shared_ptr< ObsData_ > > ObsDataVec_
virtual void measurementUpdate(const IncrementEnsemble4D_ &bg, const GeometryIterator_ &i, IncrementEnsemble4D_ &an)=0
update background ensemble bg to analysis ensemble an at a grid point location i
DeparturesEnsemble< OBS > DeparturesEnsemble_
StateEnsemble4D< MODEL > StateEnsemble4D_
ObsDataVector< OBS, int > ObsData_
LocalEnsembleSolver(ObsSpaces_ &obspaces, const Geometry_ &geometry, const eckit::Configuration &config, size_t nens, const State4D_ &xbmean)
initialize solver with obspaces, geometry, full config and nens ensemble size
Departures_ omb_
obs - mean(H(x)); set in computeHofX method
IncrementEnsemble4D< MODEL > IncrementEnsemble4D_
ObsEnsemble< OBS > ObsEnsemble_
static const std::string classname()
virtual ~LocalEnsembleSolver()=default
const eckit::LocalConfiguration obsconf_
ModelAuxControl< MODEL > ModelAux_
LocalEnsembleSolverMaker(const std::string &name)
virtual LocalEnsembleSolver< MODEL, OBS > * make(ObsSpaces_ &obspaces, const Geometry_ &geometry, const eckit::Configuration &conf, size_t nens, const State4D_ &xbmean)
Auxiliary state related to model (could be e.g. model bias), not used at the moment.
Abstract nonlinear forecast model used by high level algorithms and applications.
void forecast(State_ &xx, const ModelAux_ &, const util::Duration &len, PostProcessor< State_ > &post) const
Run the forecast from state xx for len time, with post postprocessors Does not need to be implemented...
Holds a vector of ObsAuxControl.
ObsDataVector is a vector templated on data type, in the observation space.
Ensemble of observations (can hold ensemble of H(x))
Definition: ObsEnsemble.h:21
Observations_ mean() const
Compute ensemble mean.
Definition: ObsEnsemble.h:58
Container for ObsErrors for all observation types that are used in DA.
Definition: ObsErrors.h:34
Container for ObsLocalizations for all observation types that are used in DA.
Observations Class.
Definition: Observations.h:35
void save(const std::string &) const
Save/read observations values.
Definition: Observations.h:141
Computes observation operator (from GeoVaLs), applies bias correction and runs QC filters.
Definition: Observers.h:36
void initialize(const Geometry_ &, const ObsAuxCtrls_ &, ObsErrors_ &, PostProc_ &, const eckit::Configuration &=eckit::LocalConfiguration())
Initializes variables, obs bias, obs filters (could be different for different iterations.
Definition: Observers.h:98
void finalize(Observations_ &)
Computes H(x) from the filled in GeoVaLs.
Definition: Observers.h:115
Control model post processing.
Definition: PostProcessor.h:30
Four dimensional state (vector of 3D States)
Definition: State4D.h:29
const std::vector< util::DateTime > validTimes() const
Definition: State4D.h:107
Ensemble of 4D states.
State4D_ mean() const
calculate ensemble mean
unsigned int size() const
Accessors.
State class used in oops; subclass of interface class interface::State.
int error
Definition: compare.py:168
The namespace for the main oops code.