OOPS
LocalEnsembleDA.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019-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_RUNS_LOCALENSEMBLEDA_H_
9 #define OOPS_RUNS_LOCALENSEMBLEDA_H_
10 
11 #include <memory>
12 #include <string>
13 
14 #include "eckit/config/LocalConfiguration.h"
18 #include "oops/base/Departures.h"
21 #include "oops/base/Observations.h"
22 #include "oops/base/ObsSpaces.h"
27 #include "oops/mpi/mpi.h"
28 #include "oops/runs/Application.h"
29 #include "oops/util/DateTime.h"
30 #include "oops/util/Duration.h"
31 #include "oops/util/Logger.h"
32 
33 
34 namespace oops {
35 
36 /// \brief Application for local ensemble data assimilation
37 template <typename MODEL, typename OBS> class LocalEnsembleDA : public Application {
47 
48  public:
49 // -----------------------------------------------------------------------------
50 
51  explicit LocalEnsembleDA(const eckit::mpi::Comm & comm = oops::mpi::world()) : Application(comm) {
52  instantiateLocalEnsembleSolverFactory<MODEL, OBS>();
53  instantiateObsErrorFactory<OBS>();
54  instantiateObsFilterFactory<OBS>();
55  }
56 
57 // -----------------------------------------------------------------------------
58 
59  virtual ~LocalEnsembleDA() = default;
60 
61 // -----------------------------------------------------------------------------
62 
63  int execute(const eckit::Configuration & fullConfig) const {
64  // Setup observation window
65  const util::DateTime winbgn(fullConfig.getString("window begin"));
66  const util::Duration winlen(fullConfig.getString("window length"));
67  const util::DateTime winend(winbgn + winlen);
68  const util::DateTime winhalf = winbgn + winlen/2;
69  Log::info() << "Observation window from " << winbgn << " to " << winend << std::endl;
70 
71  // Setup geometry
72  const eckit::LocalConfiguration geometryConfig(fullConfig, "geometry");
73  const Geometry_ geometry(geometryConfig, this->getComm());
74 
75  // Setup observations
76  ObsSpaces_ obsdb(fullConfig, this->getComm(), winbgn, winend);
77  Observations_ yobs(obsdb, "ObsValue");
78 
79  // Get background configurations
80  const eckit::LocalConfiguration bgConfig(fullConfig, "background");
81 
82  // Read all ensemble members
83  StateEnsemble4D_ ens_xx(geometry, bgConfig);
84  const size_t nens = ens_xx.size();
85  const Variables statevars = ens_xx.variables();
86 
87  // set up solver
88  std::unique_ptr<LocalSolver_> solver =
89  LocalEnsembleSolverFactory<MODEL, OBS>::create(obsdb, geometry, fullConfig, nens);
90  const eckit::LocalConfiguration driverConfig(fullConfig, "driver");
91 
92 
93  for (size_t jj = 0; jj < nens; ++jj) {
94  // TODO(Travis) change the way input file name is specified, make
95  // more similar to how the output ens config is done
96  Log::test() << "Initial state for member " << jj+1 << ":" << ens_xx[jj] << std::endl;
97  }
98 
99  // compute H(x)
100  bool readFromDisk = driverConfig.getBool("read HX from disk", false);
101  Observations_ yb_mean = solver->computeHofX(ens_xx, 0, readFromDisk);
102  Log::test() << "H(x) ensemble background mean: " << std::endl << yb_mean << std::endl;
103 
104  Departures_ ombg(yobs - yb_mean);
105  ombg.save("ombg");
106  Log::test() << "background y - H(x): " << std::endl << ombg << std::endl;
107 
108  // quit early if running in observer-only mode
109  bool observerOnly = driverConfig.getBool("run as observer only", false);
110  if (observerOnly) {return 0;}
111 
112  // calculate background mean
113  State4D_ bkg_mean = ens_xx.mean();
114  Log::test() << "Background mean :" << bkg_mean << std::endl;
115 
116  // calculate background ensemble perturbations
117  IncrementEnsemble4D_ bkg_pert(ens_xx, bkg_mean, statevars);
118  // TODO(Travis) optionally save the background mean / standard deviation
119 
120  // initialize empty analysis perturbations
121  IncrementEnsemble4D_ ana_pert(geometry, statevars, ens_xx[0].validTimes(), bkg_pert.size());
122 
123  // run the solver at each gridpoint
124  Log::info() << "Beginning core local solver..." << std::endl;
125  for (GeometryIterator_ i = geometry.begin(); i != geometry.end(); ++i) {
126  solver->measurementUpdate(bkg_pert, i, ana_pert);
127  }
128  Log::info() << "Local solver completed." << std::endl;
129 
130  // calculate final analysis states
131  for (size_t jj = 0; jj < nens; ++jj) {
132  ens_xx[jj] = bkg_mean;
133  ens_xx[jj] += ana_pert[jj];
134  }
135 
136  // TODO(Travis) optionally save analysis standard deviation
137 
138  // save the analysis mean
139  State4D_ ana_mean = ens_xx.mean(); // calculate analysis mean
140  Log::info() << "Analysis mean :" << ana_mean << std::endl;
141  eckit::LocalConfiguration outConfig(fullConfig, "output");
142  outConfig.set("member", 0);
143  ana_mean.write(outConfig);
144 
145  // save the analysis ensemble
146  size_t mymember;
147  for (size_t jj=0; jj < nens; ++jj) {
148  mymember = jj+1;
149  eckit::LocalConfiguration outConfig(fullConfig, "output");
150  outConfig.set("member", mymember);
151  ens_xx[jj].write(outConfig);
152  }
153 
154  // posterior observer
155  // note: if H(X) is read from file, it might have used different time slots for observation
156  // then LETKF background/analysis perturbations.
157  // hence one might not expect that oman and omaf are comparable
158  // TODO(#926) make explicit separation of background and forecast states in yaml config
159  bool do_posterior_observer = driverConfig.getBool("do posterior observer", true);
160  if (do_posterior_observer) {
161  Observations_ ya_mean = solver->computeHofX(ens_xx, 1, false);
162  Log::test() << "H(x) ensemble analysis mean: " << std::endl << ya_mean << std::endl;
163 
164  // calculate analysis obs departures
165  Departures_ oman(yobs - ya_mean);
166  oman.save("oman");
167  Log::test() << "analysis y - H(x): " << std::endl << oman << std::endl;
168 
169  // display overall background/analysis RMS stats
170  Log::test() << "ombg RMS: " << ombg.rms() << std::endl
171  << "oman RMS: " << oman.rms() << std::endl;
172  }
173 
174  return 0;
175  }
176 
177 // -----------------------------------------------------------------------------
178 
179  private:
180  std::string appname() const {
181  return "oops::LocalEnsembleDA<" + MODEL::name() + ", " + OBS::name() + ">";
182  }
183 
184 // -----------------------------------------------------------------------------
185 };
186 
187 } // namespace oops
188 #endif // OOPS_RUNS_LOCALENSEMBLEDA_H_
oops
The namespace for the main oops code.
Definition: ErrorCovarianceL95.cc:22
instantiateObsFilterFactory.h
oops::GeometryIterator
Definition: oops/interface/GeometryIterator.h:32
StateEnsemble4D.h
oops::LocalEnsembleDA::Departures_
Departures< OBS > Departures_
Definition: LocalEnsembleDA.h:38
ObsSpaces.h
mpi.h
oops::LocalEnsembleDA::ObsSpaces_
ObsSpaces< OBS > ObsSpaces_
Definition: LocalEnsembleDA.h:43
oops::Departures::save
void save(const std::string &) const
Save departures values.
Definition: oops/base/Departures.h:226
oops::LocalEnsembleDA::execute
int execute(const eckit::Configuration &fullConfig) const
Definition: LocalEnsembleDA.h:63
oops::LocalEnsembleSolverFactory::create
static std::unique_ptr< LocalEnsembleSolver< MODEL, OBS > > create(ObsSpaces_ &, const Geometry_ &, const eckit::Configuration &, size_t)
Definition: LocalEnsembleSolver.h:210
oops::StateEnsemble4D::size
unsigned int size() const
Accessors.
Definition: StateEnsemble4D.h:38
instantiateObsErrorFactory.h
oops::LocalEnsembleDA::LocalSolver_
LocalEnsembleSolver< MODEL, OBS > LocalSolver_
Definition: LocalEnsembleDA.h:42
Departures.h
oops::State4D::write
void write(const eckit::Configuration &) const
Definition: State4D.h:127
oops::StateEnsemble4D::variables
const Variables & variables() const
Information.
Definition: StateEnsemble4D.h:43
Observations.h
oops::interface::Geometry::end
GeometryIterator_ end() const
Iterator to the last gridpoint fo Geometry (only used in LocalEnsembleDA)
Definition: oops/interface/Geometry.h:161
oops::LocalEnsembleDA::StateEnsemble4D_
StateEnsemble4D< MODEL > StateEnsemble4D_
Definition: LocalEnsembleDA.h:46
oops::LocalEnsembleSolver
Base class for LETKF-type solvers.
Definition: LocalEnsembleSolver.h:34
oops::LocalEnsembleDA::LocalEnsembleDA
LocalEnsembleDA(const eckit::mpi::Comm &comm=oops::mpi::world())
Definition: LocalEnsembleDA.h:51
LocalEnsembleSolver.h
oops::Departures
Difference between two observation vectors.
Definition: oops/base/Departures.h:44
Application.h
oops::Application::getComm
const eckit::mpi::Comm & getComm() const
Definition: Application.h:36
instantiateLocalEnsembleSolverFactory.h
oops::IncrementEnsemble4D::size
unsigned int size() const
Accessors.
Definition: IncrementEnsemble4D.h:61
oops::LocalEnsembleDA::Observations_
Observations< OBS > Observations_
Definition: LocalEnsembleDA.h:44
oops::IncrementEnsemble4D
Ensemble of 4D inrements.
Definition: IncrementEnsemble4D.h:37
oops::State4D
Four dimensional state.
Definition: State4D.h:35
IncrementEnsemble4D.h
oops::StateEnsemble4D::mean
State4D_ mean() const
calculate ensemble mean
Definition: StateEnsemble4D.h:68
oops::Geometry
Geometry class used in oops; subclass of interface class above.
Definition: oops/interface/Geometry.h:189
oops::LocalEnsembleDA::appname
std::string appname() const
Definition: LocalEnsembleDA.h:180
oops::Departures::rms
double rms() const
Definition: oops/base/Departures.h:193
State4D.h
oops::LocalEnsembleDA
Application for local ensemble data assimilation.
Definition: LocalEnsembleDA.h:37
oops::Observations
Observations Class.
Definition: oops/base/Departures.h:30
oops::LocalEnsembleDA::IncrementEnsemble4D_
IncrementEnsemble4D< MODEL > IncrementEnsemble4D_
Definition: LocalEnsembleDA.h:41
oops::StateEnsemble4D
Ensemble of 4D states.
Definition: StateEnsemble4D.h:26
oops::Application
Definition: Application.h:29
oops::LocalEnsembleDA::GeometryIterator_
GeometryIterator< MODEL > GeometryIterator_
Definition: LocalEnsembleDA.h:40
GeometryIterator.h
oops::LocalEnsembleDA::State4D_
State4D< MODEL > State4D_
Definition: LocalEnsembleDA.h:45
oops::mpi::world
const eckit::mpi::Comm & world()
Default communicator with all MPI tasks (ie MPI_COMM_WORLD)
Definition: oops/mpi/mpi.cc:22
oops::Variables
Definition: oops/base/Variables.h:23
oops::ObsSpaces
Definition: ObsSpaces.h:41
oops::LocalEnsembleDA::~LocalEnsembleDA
virtual ~LocalEnsembleDA()=default
oops::interface::Geometry::begin
GeometryIterator_ begin() const
Iterator to the first gridpoint of Geometry (only used in LocalEnsembleDA)
Definition: oops/interface/Geometry.h:141
Geometry.h
oops::LocalEnsembleDA::Geometry_
Geometry< MODEL > Geometry_
Definition: LocalEnsembleDA.h:39