9 #ifndef OOPS_ASSIMILATION_LETKFSOLVER_H_
10 #define OOPS_ASSIMILATION_LETKFSOLVER_H_
12 #include <Eigen/Dense>
17 #include "eckit/config/LocalConfiguration.h"
28 #include "oops/util/Logger.h"
29 #include "oops/util/Timer.h"
44 template <
typename MODEL,
typename OBS>
55 static const std::string
classname() {
return "oops::LETKFSolver";}
86 template <
typename MODEL,
typename OBS>
88 const eckit::Configuration & config,
size_t nens)
94 Log::info() <<
"Using EIGEN implementation of LETKF" << std::endl;
96 Log::info() <<
"Multiplicative inflation multCoeff=" <<
97 inflopt.
mult << std::endl;
100 Log::info() <<
"RTPP inflation will be applied with rtppCoeff=" <<
101 inflopt.
rtpp << std::endl;
103 Log::info() <<
"RTPP inflation is not applied rtppCoeff is out of bounds (0,1], rtppCoeff="
104 << inflopt.
rtpp << std::endl;
108 Log::info() <<
"RTPS inflation will be applied with rtpsCoeff=" <<
109 inflopt.
rtps << std::endl;
111 Log::info() <<
"RTPS inflation is not applied rtpsCoeff is out of bounds (0,1], rtpsCoeff="
112 << inflopt.
rtps << std::endl;
126 template <
typename MODEL,
typename OBS>
130 util::Timer timer(classname(),
"measurementUpdate");
133 ObsSpaces_ local_obs(this->obspaces_, *i, this->obsconf_);
136 if (local_omb.
nobs() == 0) {
139 this->copyLocalIncrement(bkg_pert, i, ana_pert);
144 ObsErrors_ local_R(this->obsconf_, local_obs);
145 computeWeights(local_omb, local_Yb, local_R);
146 applyWeights(bkg_pert, ana_pert, i);
152 template <
typename MODEL,
typename OBS>
159 util::Timer timer(classname(),
"computeWeights");
164 Eigen::MatrixXd dy = dy_oops.
packEigen();
166 Eigen::MatrixXd Yb = Yb_oops.
packEigen();
171 double infl = inflopt.
mult;
172 Eigen::MatrixXd work = Yb*(diagInvR.asDiagonal()*Yb.transpose());
173 work.diagonal() += Eigen::VectorXd::Constant(nens_, (nens_-1)/infl);
176 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(work);
177 eival_ = es.eigenvalues().real();
178 eivec_ = es.eigenvectors().real();
181 work = eivec_ * eival_.cwiseInverse().asDiagonal() * eivec_.transpose();
185 * ((nens_-1) * eival_.array().inverse()).sqrt().matrix().asDiagonal()
186 * eivec_.transpose();
189 wa_ = work * (Yb * (diagInvR.asDiagonal()*dy));
194 template <
typename MODEL,
typename OBS>
199 util::Timer timer(classname(),
"applyWeights");
204 std::vector<double> tmp1 = gptmpl.
getVals();
205 size_t ngp = tmp1.size();
208 for (
size_t itime=0; itime < bkg_pert[0].
size(); ++itime) {
210 Eigen::MatrixXd Xb(ngp, nens_);
211 for (
size_t iens=0; iens < nens_; ++iens) {
213 std::vector<double> tmp = gp.
getVals();
214 for (
size_t iv=0; iv < ngp; ++iv) {
215 Xb(iv, iens) = tmp[iv];
220 Eigen::VectorXd xa = Xb*wa_;
221 Eigen::MatrixXd Xa = Xb*Wa_;
225 Xa = (1-inflopt.
rtpp)*Xa+inflopt.
rtpp*Xb;
229 double eps = DBL_EPSILON;
232 Eigen::ArrayXd asprd = Xa.array().square().rowwise().sum()/(nens_-1);
233 asprd = asprd.sqrt();
234 asprd = (asprd < eps).select(eps, asprd);
237 Eigen::ArrayXd fsprd = Xb.array().square().rowwise().sum()/(nens_-1);
238 fsprd = fsprd.sqrt();
239 fsprd = (fsprd < eps).select(eps, fsprd);
242 Eigen::ArrayXd rtpsInfl = inflopt.
rtps*((fsprd-asprd)/asprd) + 1;
247 Xa.array().colwise() *= rtpsInfl;
251 for (
size_t iens=0; iens < nens_; ++iens) {
252 for (
size_t iv=0; iv < ngp; ++iv) {
253 tmp1[iv] = Xa(iv, iens)+xa(iv);
256 ana_pert[iens][itime].setLocal(gptmpl, i);
264 #endif // OOPS_ASSIMILATION_LETKFSOLVER_H_