8 #ifndef OOPS_RUNS_LOCALENSEMBLEDA_H_
9 #define OOPS_RUNS_LOCALENSEMBLEDA_H_
16 #include "eckit/config/LocalConfiguration.h"
33 #include "oops/util/DateTime.h"
34 #include "oops/util/Duration.h"
35 #include "oops/util/Logger.h"
57 instantiateLocalEnsembleSolverFactory<MODEL, OBS>();
58 instantiateObsErrorFactory<OBS>();
59 instantiateObsFilterFactory<OBS>();
60 instantiateVariableChangeFactory<MODEL>();
69 int execute(
const eckit::Configuration & fullConfig)
const {
71 const util::DateTime winbgn(fullConfig.getString(
"window begin"));
72 const util::Duration winlen(fullConfig.getString(
"window length"));
73 const util::DateTime winend(winbgn + winlen);
74 Log::info() <<
"Observation window from " << winbgn <<
" to " << winend << std::endl;
77 const eckit::LocalConfiguration geometryConfig(fullConfig,
"geometry");
81 eckit::LocalConfiguration obsConfig(fullConfig,
"observations");
83 const eckit::LocalConfiguration driverConfig(fullConfig,
"driver");
87 bool update_obsconfig = driverConfig.getBool(
"update obs config with geometry info",
false);
96 const eckit::LocalConfiguration bgConfig(fullConfig,
"background");
100 const size_t nens = ens_xx.
size();
105 std::unique_ptr<LocalSolver_> solver =
109 bool do_test_prints = driverConfig.getBool(
"do test prints",
true);
110 if (do_test_prints) {
111 for (
size_t jj = 0; jj < nens; ++jj) {
112 Log::test() <<
"Initial state for member " << jj+1 <<
":" << ens_xx[jj] << std::endl;
117 bool readFromDisk = driverConfig.getBool(
"read HX from disk",
false);
118 Observations_ yb_mean = solver->computeHofX(ens_xx, 0, readFromDisk);
119 Log::test() <<
"H(x) ensemble background mean: " << std::endl << yb_mean << std::endl;
123 Log::test() <<
"background y - H(x): " << std::endl << ombg << std::endl;
126 bool observerOnly = driverConfig.getBool(
"run as observer only",
false);
133 if (do_test_prints) {
134 Log::test() <<
"Background mean :" << bkg_mean << std::endl;
144 Log::info() <<
"Beginning core local solver..." << std::endl;
146 solver->measurementUpdate(bkg_pert, i, ana_pert);
148 Log::info() <<
"Local solver completed." << std::endl;
155 for (
size_t jj = 0; jj < nens; ++jj) {
156 ens_xx[jj] = bkg_mean;
157 ens_xx[jj] += ana_pert[jj];
163 if (do_test_prints) {
164 Log::test() <<
"Analysis mean :" << ana_mean << std::endl;
166 bool save_xamean = driverConfig.getBool(
"save posterior mean",
false);
168 eckit::LocalConfiguration outConfig(fullConfig,
"output");
169 outConfig.set(
"member", 0);
170 ana_mean.
write(outConfig);
174 bool save_ens = driverConfig.getBool(
"save posterior ensemble",
true);
177 for (
size_t jj=0; jj < nens; ++jj) {
179 eckit::LocalConfiguration outConfig(fullConfig,
"output");
180 outConfig.set(
"member", mymember);
181 ens_xx[jj].write(outConfig);
187 bool save_xbmean = driverConfig.getBool(
"save prior mean",
false);
189 eckit::LocalConfiguration outConfig(fullConfig,
"output mean prior");
190 outConfig.set(
"member", 0);
191 bkg_mean.
write(outConfig);
195 bool save_mean_increment = driverConfig.getBool(
"save posterior mean increment",
false);
196 if (save_mean_increment) {
197 eckit::LocalConfiguration outConfig(fullConfig,
"output increment");
198 outConfig.set(
"member", 0);
199 for (
size_t itime = 0; itime < ana_mean.
size(); ++itime) {
200 Increment_ ana_increment(ana_pert[0][itime],
false);
201 ana_increment.
diff(ana_mean[itime], bkg_mean[itime]);
202 ana_increment.
write(outConfig);
203 if (do_test_prints) {
204 Log::test() <<
"Analysis mean increment :" << ana_increment << std::endl;
210 bool save_variance = driverConfig.getBool(
"save prior variance",
false);
212 eckit::LocalConfiguration outConfig(fullConfig,
"output variance prior");
213 outConfig.set(
"member", 0);
214 std::string strOut(
"Forecast variance :");
215 saveVariance(outConfig, bkg_pert, do_test_prints, strOut);
219 save_variance = driverConfig.getBool(
"save posterior variance",
false);
221 eckit::LocalConfiguration outConfig(fullConfig,
"output variance posterior");
222 outConfig.set(
"member", 0);
223 std::string strOut(
"Analysis variance :");
224 saveVariance(outConfig, ana_pert, do_test_prints, strOut);
231 bool do_posterior_observer = driverConfig.getBool(
"do posterior observer",
true);
232 if (do_posterior_observer) {
233 Observations_ ya_mean = solver->computeHofX(ens_xx, 1,
false);
234 Log::test() <<
"H(x) ensemble analysis mean: " << std::endl << ya_mean << std::endl;
239 Log::test() <<
"analysis y - H(x): " << std::endl << oman << std::endl;
242 Log::test() <<
"ombg RMS: " << ombg.
rms() << std::endl
243 <<
"oman RMS: " << oman.
rms() << std::endl;
254 return "oops::LocalEnsembleDA<" + MODEL::name() +
", " + OBS::name() +
">";
258 eckit::LocalConfiguration & obsConfig)
const {
259 std::vector<double> patchCenter(2, 0.0);
260 double patchRadius = 0.0;
264 eckit::geometry::Point2 gptmp;
265 const double radius_earth = 6.371e6;
266 const double deg2rad = 3.14159265/180.0;
275 cosXmean += cos(gptmp.x()*
deg2rad);
276 sinXmean += sin(gptmp.x()*
deg2rad);
280 cosXmean = cosXmean/
static_cast<double>(n);
281 sinXmean = sinXmean/
static_cast<double>(n);
282 patchCenter[0] = atan2(sinXmean, cosXmean)/
deg2rad;
283 patchCenter[1] = ymean/
static_cast<double>(n);
286 eckit::geometry::Point2 center(patchCenter[0], patchCenter[1]);
289 double dist = eckit::geometry::Sphere::distance(radius_earth, center, *i);
290 patchRadius = fmax(patchRadius, dist);
292 Log::debug() <<
"patch center=" << patchCenter
293 <<
" patch radius=" << patchRadius << std::endl;
296 std::vector<eckit::LocalConfiguration> obsConfigs = obsConfig.getSubConfigurations();
297 for (
auto & conf : obsConfigs) {
298 conf.set(
"obs space.center", patchCenter);
299 conf.set(
"obs space.radius", patchRadius);
301 eckit::LocalConfiguration tmp;
302 tmp.set(
"observations", obsConfigs);
303 obsConfig = tmp.getSubConfiguration(
"observations");
307 const bool do_test_prints,
const std::string & strOut)
const {
309 size_t nens = perts.
size();
310 const double nc = 1.0/(
static_cast<double>(nens) - 1.0);
311 for (
size_t itime = 0; itime < perts[0].
size(); ++itime) {
313 for (
size_t iens = 0; iens < nens; ++iens) {
319 var.
write(outConfig);
320 if (do_test_prints) {
321 Log::test() << strOut << var << std::endl;
const eckit::mpi::Comm & getComm() const
Difference between two observation vectors.
void save(const std::string &) const
Save departures values.
Geometry class used in oops; subclass of interface class interface::Geometry.
Ensemble of 4D increments.
size_t size() const
Accessors.
Increment class used in oops.
Application for local ensemble data assimilation.
Departures< OBS > Departures_
virtual ~LocalEnsembleDA()=default
StateEnsemble4D< MODEL > StateEnsemble4D_
int execute(const eckit::Configuration &fullConfig) const
IncrementEnsemble4D< MODEL > IncrementEnsemble4D_
GeometryIterator< MODEL > GeometryIterator_
Observations< OBS > Observations_
void saveVariance(const eckit::LocalConfiguration &outConfig, const IncrementEnsemble4D_ &perts, const bool do_test_prints, const std::string &strOut) const
void updateConfigWithPatchGeometry(const Geometry_ &geometry, eckit::LocalConfiguration &obsConfig) const
LocalEnsembleDA(const eckit::mpi::Comm &comm=oops::mpi::world())
ObsSpaces< OBS > ObsSpaces_
std::string appname() const
Increment< MODEL > Increment_
LocalEnsembleSolver< MODEL, OBS > LocalSolver_
Geometry< MODEL > Geometry_
State4D< MODEL > State4D_
static std::unique_ptr< LocalEnsembleSolver< MODEL, OBS > > create(ObsSpaces_ &, const Geometry_ &, const eckit::Configuration &, size_t, const State4D_ &)
Base class for LETKF-type solvers.
void save() const
Save files.
Four dimensional state (vector of 3D States)
size_t size() const
Get 3D model state.
void write(const eckit::Configuration &) const
I/O.
const Variables & variables() const
Information.
State4D_ mean() const
calculate ensemble mean
unsigned int size() const
Accessors.
GeometryIterator_ end() const
Iterator to the past-the-end gridpoint of Geometry (only used in LocalEnsembleDA)
GeometryIterator_ begin() const
Iterator to the first gridpoint of Geometry (only used in LocalEnsembleDA)
void schur_product_with(const Increment &other)
Compute Schur product of this Increment with other, assign to this Increment.
void diff(const State_ &state1, const State_ &state2)
Set this Increment to be difference between state1 and state2.
void write(const eckit::Configuration &) const
Write this Increment out to file.
real(8), parameter deg2rad
const eckit::mpi::Comm & myself()
Default communicator with each MPI task by itself.
const eckit::mpi::Comm & world()
Default communicator with all MPI tasks (ie MPI_COMM_WORLD)
The namespace for the main oops code.