8 #ifndef OOPS_ASSIMILATION_GETKFSOLVER_H_
9 #define OOPS_ASSIMILATION_GETKFSOLVER_H_
11 #include <Eigen/Dense>
18 #include "eckit/config/LocalConfiguration.h"
34 #include "oops/util/ConfigFunctions.h"
35 #include "oops/util/Logger.h"
36 #include "oops/util/Timer.h"
48 template <
typename MODEL,
typename OBS>
63 static const std::string
classname() {
return "oops::GETKFSolver";}
82 void computeWeights(
const Eigen::VectorXd & omb,
const Eigen::MatrixXd & Yb,
83 const Eigen::MatrixXd & YbOrig,
const Eigen::VectorXd & invvarR);
106 template <
typename MODEL,
typename OBS>
108 const eckit::Configuration & config,
size_t nens)
110 nens_(nens), geometry_(geometry),
111 vertloc_(geometry_, config.getSubConfiguration(
"local ensemble DA.vertical localization")),
112 neig_(vertloc_.neig()), nanal_(neig_*nens_), HZb_(obspaces, nanal_)
118 Log::info() <<
"Multiplicative inflation multCoeff=" <<
119 inflopt.
mult << std::endl;
122 Log::info() <<
"RTPP inflation will be applied with rtppCoeff=" <<
123 inflopt.
rtpp << std::endl;
125 Log::info() <<
"RTPP inflation is not applied rtppCoeff is out of bounds (0,1], rtppCoeff="
126 << inflopt.
rtpp << std::endl;
130 Log::info() <<
"RTPS inflation will be applied with rtpsCoeff=" <<
131 inflopt.
rtps << std::endl;
133 Log::info() <<
"RTPS inflation is not applied rtpsCoeff is out of bounds (0,1], rtpsCoeff="
134 << inflopt.
rtps << std::endl;
143 template <
typename MODEL,
typename OBS>
145 size_t iteration,
bool readFromFile) {
146 util::Timer timer(classname(),
"computeHofX");
153 Log::debug() <<
"Read H(X) from disk" << std::endl;
157 for (
size_t iens = 0; iens < nens_; ++iens) {
158 for (
size_t ieig = 0; ieig < neig_; ++ieig) {
159 ytmp.
read(
"hofxm"+std::to_string(iteration)+
"_"+std::to_string(ieig+1)+
160 "_"+std::to_string(iens+1));
161 HZb_[ii] = ytmp - yb_mean;
162 Log::test() <<
"H(Zx) - ymean for member " << iens+1 <<
" eig "<< ieig+1
163 <<
" :" << std::endl << HZb_[ii] << std::endl;
168 Log::debug() <<
"Computing H(X) online" << std::endl;
174 for (
size_t iens = 0; iens < nens_; ++iens) {
175 vertloc_.modulateIncrement(dx[iens], Ztmp);
176 for (
size_t ieig = 0; ieig < neig_; ++ieig) {
178 tmpState += Ztmp[ieig];
180 eckit::LocalConfiguration config;
181 config.set(
"save hofx",
false);
182 config.set(
"save qc",
false);
183 config.set(
"save obs errors",
false);
184 this->computeHofX4D(config, tmpState, tmpObs);
185 HZb_[ii] = tmpObs - yb_mean;
186 tmpObs.
save(
"hofxm"+std::to_string(iteration)+
"_"+std::to_string(ieig+1)+
187 "_"+std::to_string(iens+1));
188 Log::test() <<
"H(Zx) - ymean for member " << iens+1 <<
" eig "<< ieig+1 <<
" :"
189 << std::endl << HZb_[ii] << std::endl;
199 template <
typename MODEL,
typename OBS>
201 const Eigen::MatrixXd & Yb,
202 const Eigen::MatrixXd & YbOrig,
203 const Eigen::VectorXd & R_invvar) {
207 util::Timer timer(classname(),
"computeWeights");
209 const int nobsl = dy.size();
212 Eigen::VectorXf dy_f = dy.cast<
float>();
213 Eigen::MatrixXf Yb_f = Yb.cast<
float>();
214 Eigen::MatrixXf YbOrig_f = YbOrig.cast<
float>();
215 Eigen::VectorXf R_invvar_f = R_invvar.cast<
float>();
217 Eigen::MatrixXf Wa_f(nanal_, this->nens_);
218 Eigen::VectorXf wa_f(nanal_);
221 const int getkf_inflation = 0;
225 wa_f.data(), Wa_f.data(),
226 R_invvar_f.data(), nanal_, neig_,
227 getkf_inflation, denkf, getkf);
228 this->Wa_ = Wa_f.cast<
double>();
229 this->wa_ = wa_f.cast<
double>();
234 template <
typename MODEL,
typename OBS>
239 util::Timer timer(classname(),
"applyWeights");
245 std::vector<double> tmp = gptmpl.
getVals();
246 size_t ngp = tmp.size();
247 Eigen::MatrixXd Xb(ngp, nens_);
250 for (
unsigned itime=0; itime < bkg_pert[0].
size(); ++itime) {
253 Xb = vertloc_.modulateIncrement(bkg_pert,
i, itime);
256 Eigen::VectorXd xa = Xb*wa_;
257 Eigen::MatrixXd Xa = Xb*Wa_;
261 Xb.resize(ngp, nens_);
262 for (
size_t iens=0; iens < nens_; ++iens) {
264 std::vector<double> tmp1 = gp.
getVals();
265 for (
size_t iv=0; iv < ngp; ++iv) {
266 Xb(iv, iens) = tmp1[iv];
273 Xa = (1-inflopt.
rtpp)*Xa+inflopt.
rtpp*Xb;
277 double eps = DBL_EPSILON;
280 Eigen::ArrayXd asprd = Xa.array().square().rowwise().sum()/(nens_-1);
281 asprd = asprd.sqrt();
282 asprd = (asprd < eps).select(eps, asprd);
285 Eigen::ArrayXd fsprd = Xb.array().square().rowwise().sum()/(nens_-1);
286 fsprd = fsprd.sqrt();
287 fsprd = (fsprd < eps).select(eps, fsprd);
290 Eigen::ArrayXd rtpsInfl = inflopt.
rtps*((fsprd-asprd)/asprd) + 1;
295 Xa.array().colwise() *= rtpsInfl;
299 for (
size_t iens=0; iens < nens_; ++iens) {
300 for (
size_t iv=0; iv < ngp; ++iv) {
301 tmp[iv] = Xa(iv, iens)+xa(iv);
304 ana_pert[iens][itime].setLocal(gptmpl,
i);
311 template <
typename MODEL,
typename OBS>
315 util::Timer timer(classname(),
"measurementUpdate");
320 this->obsloc().computeLocalization(
i, locvector);
321 locvector.
mask(*(this->invVarR_));
322 Eigen::VectorXd local_omb_vec = this->omb_.packEigen(locvector);
324 if (local_omb_vec.size() == 0) {
327 this->copyLocalIncrement(bkg_pert,
i, ana_pert);
331 Eigen::MatrixXd local_Yb_mat = this->Yb_.packEigen(locvector);
332 Eigen::MatrixXd local_HZ_mat = this->HZb_.packEigen(locvector);
334 Eigen::VectorXd local_invVarR_vec = this->invVarR_->packEigen(locvector);
336 Eigen::VectorXd localization = locvector.
packEigen(locvector);
337 local_invVarR_vec.array() *= localization.array();
338 computeWeights(local_omb_vec, local_HZ_mat, local_Yb_mat, local_invVarR_vec);
339 applyWeights(bkg_pert, ana_pert,
i);
Ensemble of Departures (can hold ensemble perturbations in the observation space)
Difference between two observation vectors.
void mask(ObsDataVec_< int >)
Mask out departures where the passed in qc flags are > 0.
Eigen::VectorXd packEigen(const Departures &) const
Pack departures in an Eigen vector (excluding departures that are masked out)
An implementation of the GETKF from Lei 2018 JAMES.
Departures< OBS > Departures_
void applyWeights(const IncrementEnsemble4D_ &, IncrementEnsemble4D_ &, const GeometryIterator_ &)
Applies weights and adds posterior inflation.
VerticalLocEV< MODEL > VerticalLocEV_
GETKFSolver(ObsSpaces_ &, const Geometry_ &, const eckit::Configuration &, size_t)
GeometryIterator< MODEL > GeometryIterator_
static const std::string classname()
DeparturesEnsemble< OBS > DeparturesEnsemble_
const Geometry_ & geometry_
IncrementEnsemble4D< MODEL > IncrementEnsemble4D_
ObsEnsemble< OBS > ObsEnsemble_
Geometry< MODEL > Geometry_
void computeWeights(const Eigen::VectorXd &omb, const Eigen::MatrixXd &Yb, const Eigen::MatrixXd &YbOrig, const Eigen::VectorXd &invvarR)
StateEnsemble4D< MODEL > StateEnsemble4D_
Observations_ computeHofX(const StateEnsemble4D_ &, size_t, bool) override
computes ensemble H(xx), returns mean H(xx), saves as hofx iteration
void measurementUpdate(const IncrementEnsemble4D_ &, const GeometryIterator_ &, IncrementEnsemble4D_ &) override
entire KF update (computeWeights+applyWeights) for a grid point GeometryIterator_
State4D< MODEL > State4D_
ObsSpaces< OBS > ObsSpaces_
Observations< OBS > Observations_
LETKFSolverParameters options_
Geometry class used in oops; subclass of interface class interface::Geometry.
Ensemble of 4D increments.
size_t size() const
Accessors.
Parameters for LETKF inflation.
double rtpsInflMax() const
double rtpsInflMin() const
Parameter< LETKFInflationParameters > infl
Base class for LETKF-type solvers.
virtual Observations_ computeHofX(const StateEnsemble4D_ &xx, size_t iteration, bool readFromDisk)
computes ensemble H(xx), returns mean H(xx), saves as hofx iteration
void setVals(std::vector< double > &)
const std::vector< double > & getVals() const
Ensemble of observations (can hold ensemble of H(x))
void save(const std::string &) const
Save/read observations values.
void read(const std::string &)
Four dimensional state (vector of 3D States)
State4D_ mean() const
calculate ensemble mean
The namespace for the main oops code.
void letkf_core_f90(const int &, const float *, const float *, const float *, float *, float *, const float *, const int &, const int &, const int &, const int &, const int &)