8 #ifndef OOPS_RUNS_LOCALENSEMBLEDA_H_
9 #define OOPS_RUNS_LOCALENSEMBLEDA_H_
16 #include "eckit/config/LocalConfiguration.h"
32 #include "oops/util/DateTime.h"
33 #include "oops/util/Duration.h"
34 #include "oops/util/Logger.h"
56 instantiateLocalEnsembleSolverFactory<MODEL, OBS>();
57 instantiateObsErrorFactory<OBS>();
58 instantiateObsFilterFactory<OBS>();
67 int execute(
const eckit::Configuration & fullConfig)
const {
69 const util::DateTime winbgn(fullConfig.getString(
"window begin"));
70 const util::Duration winlen(fullConfig.getString(
"window length"));
71 const util::DateTime winend(winbgn + winlen);
72 Log::info() <<
"Observation window from " << winbgn <<
" to " << winend << std::endl;
75 const eckit::LocalConfiguration geometryConfig(fullConfig,
"geometry");
79 eckit::LocalConfiguration obsConfig(fullConfig,
"observations");
81 const eckit::LocalConfiguration driverConfig(fullConfig,
"driver");
85 bool update_obsconfig = driverConfig.getBool(
"update obs config with geometry info",
false);
94 const eckit::LocalConfiguration bgConfig(fullConfig,
"background");
98 const size_t nens = ens_xx.
size();
102 std::unique_ptr<LocalSolver_> solver =
105 bool do_test_prints = driverConfig.getBool(
"do test prints",
true);
106 if (do_test_prints) {
107 for (
size_t jj = 0; jj < nens; ++jj) {
108 Log::test() <<
"Initial state for member " << jj+1 <<
":" << ens_xx[jj] << std::endl;
113 bool readFromDisk = driverConfig.getBool(
"read HX from disk",
false);
114 Observations_ yb_mean = solver->computeHofX(ens_xx, 0, readFromDisk);
115 Log::test() <<
"H(x) ensemble background mean: " << std::endl << yb_mean << std::endl;
119 Log::test() <<
"background y - H(x): " << std::endl << ombg << std::endl;
122 bool observerOnly = driverConfig.getBool(
"run as observer only",
false);
130 if (do_test_prints) {
131 Log::test() <<
"Background mean :" << bkg_mean << std::endl;
141 Log::info() <<
"Beginning core local solver..." << std::endl;
143 solver->measurementUpdate(bkg_pert,
i, ana_pert);
145 Log::info() <<
"Local solver completed." << std::endl;
152 for (
size_t jj = 0; jj < nens; ++jj) {
153 ens_xx[jj] = bkg_mean;
154 ens_xx[jj] += ana_pert[jj];
160 if (do_test_prints) {
161 Log::test() <<
"Analysis mean :" << ana_mean << std::endl;
163 bool save_xamean = driverConfig.getBool(
"save posterior mean",
false);
165 eckit::LocalConfiguration outConfig(fullConfig,
"output");
166 outConfig.set(
"member", 0);
167 ana_mean.
write(outConfig);
171 bool save_ens = driverConfig.getBool(
"save posterior ensemble",
true);
174 for (
size_t jj=0; jj < nens; ++jj) {
176 eckit::LocalConfiguration outConfig(fullConfig,
"output");
177 outConfig.set(
"member", mymember);
178 ens_xx[jj].write(outConfig);
184 bool save_xbmean = driverConfig.getBool(
"save prior mean",
false);
186 eckit::LocalConfiguration outConfig(fullConfig,
"output mean prior");
187 outConfig.set(
"member", 0);
188 bkg_mean.
write(outConfig);
192 bool save_mean_increment = driverConfig.getBool(
"save posterior mean increment",
false);
193 if (save_mean_increment) {
194 eckit::LocalConfiguration outConfig(fullConfig,
"output increment");
195 outConfig.set(
"member", 0);
196 for (
size_t itime = 0; itime < ana_mean.
size(); ++itime) {
197 Increment_ ana_increment(ana_pert[0][itime],
false);
198 ana_increment.
diff(ana_mean[itime], bkg_mean[itime]);
199 ana_increment.
write(outConfig);
200 if (do_test_prints) {
201 Log::test() <<
"Analysis mean increment :" << ana_increment << std::endl;
207 bool save_variance = driverConfig.getBool(
"save prior variance",
false);
209 eckit::LocalConfiguration outConfig(fullConfig,
"output variance prior");
210 outConfig.set(
"member", 0);
211 std::string strOut(
"Forecast variance :");
212 saveVariance(outConfig, bkg_pert, do_test_prints, strOut);
216 save_variance = driverConfig.getBool(
"save posterior variance",
false);
218 eckit::LocalConfiguration outConfig(fullConfig,
"output variance posterior");
219 outConfig.set(
"member", 0);
220 std::string strOut(
"Analysis variance :");
221 saveVariance(outConfig, ana_pert, do_test_prints, strOut);
228 bool do_posterior_observer = driverConfig.getBool(
"do posterior observer",
true);
229 if (do_posterior_observer) {
230 Observations_ ya_mean = solver->computeHofX(ens_xx, 1,
false);
231 Log::test() <<
"H(x) ensemble analysis mean: " << std::endl << ya_mean << std::endl;
236 Log::test() <<
"analysis y - H(x): " << std::endl << oman << std::endl;
240 <<
"oman RMS: " << oman.
rms() << std::endl;
255 eckit::LocalConfiguration & obsConfig)
const {
256 std::vector<double> patchCenter(2, 0.0);
257 double patchRadius = 0.0;
261 eckit::geometry::Point2 gptmp;
262 const double radius_earth = 6.371e6;
263 const double deg2rad = 3.14159265/180.0;
272 cosXmean += cos(gptmp.x()*
deg2rad);
273 sinXmean += sin(gptmp.x()*
deg2rad);
277 cosXmean = cosXmean/
static_cast<double>(n);
278 sinXmean = sinXmean/
static_cast<double>(n);
279 patchCenter[0] = atan2(sinXmean, cosXmean)/
deg2rad;
280 patchCenter[1] = ymean/
static_cast<double>(n);
283 eckit::geometry::Point2 center(patchCenter[0], patchCenter[1]);
286 double dist = eckit::geometry::Sphere::distance(radius_earth, center, *
i);
287 patchRadius = fmax(patchRadius, dist);
289 Log::debug() <<
"patch center=" << patchCenter
290 <<
" patch radius=" << patchRadius << std::endl;
293 std::vector<eckit::LocalConfiguration> obsConfigs = obsConfig.getSubConfigurations();
294 for (
auto & conf : obsConfigs) {
295 conf.set(
"obs space.center", patchCenter);
296 conf.set(
"obs space.radius", patchRadius);
298 eckit::LocalConfiguration tmp;
299 tmp.set(
"observations", obsConfigs);
300 obsConfig = tmp.getSubConfiguration(
"observations");
304 const bool do_test_prints,
const std::string & strOut)
const {
306 size_t nens = perts.
size();
307 const double nc = 1.0/(
static_cast<double>(nens) - 1.0);
308 for (
size_t itime = 0; itime < perts[0].
size(); ++itime) {
310 for (
size_t iens = 0; iens < nens; ++iens) {
316 var.
write(outConfig);
317 if (do_test_prints) {
318 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)
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.