8 #ifndef OOPS_GENERIC_VERTICALLOCEV_H_
9 #define OOPS_GENERIC_VERTICALLOCEV_H_
11 #include <Eigen/Dense>
16 #include "eckit/config/Configuration.h"
24 #include "oops/util/Logger.h"
25 #include "oops/util/ObjectCounter.h"
26 #include "oops/util/parameters/Parameter.h"
27 #include "oops/util/parameters/Parameters.h"
28 #include "oops/util/parameters/RequiredParameter.h"
29 #include "oops/util/Printable.h"
49 Parameter<double>
VertLocToll{
"fraction of retained variance", 1.0,
this};
53 RequiredParameter<std::string>
VertLocUnits{
"lengthscale units",
this};
57 template<
typename MODEL>
59 private util::ObjectCounter<VerticalLocEV<MODEL>> {
66 static const std::string
classname() {
return "oops::VerticalLocEV";}
96 void print(std::ostream &)
const {}
103 template<
typename MODEL>
105 const eckit::Configuration & conf) {
107 options_.deserialize(conf);
110 Eigen::MatrixXd cov = computeCorrMatrix(geom);
112 computeCorrMatrixEvec(cov);
113 neig_ = truncateEvecs();
117 template<
typename MODEL>
119 std::string locUnits = options_.VertLocUnits;
120 oops::Log::debug() <<
"locUnits: " << locUnits << std::endl;
122 size_t nlevs = vCoord.size();
125 Eigen::MatrixXd cov = Eigen::MatrixXd::Zero(nlevs, nlevs);
126 for (
size_t jj=0; jj < nlevs; ++jj) {
127 for (
size_t ii=jj; ii < nlevs; ++ii) {
128 cov(ii, jj) =
oops::gc99(std::abs(vCoord[jj]-vCoord[ii])/options_.VertLocDist);
131 oops::Log::debug() <<
"corr: " << cov << std::endl;
138 template<
typename MODEL>
141 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(cov);
142 Evals_ = es.eigenvalues().real();
143 Evecs_ = es.eigenvectors().real();
146 Evals_.reverseInPlace();
147 Evecs_.rowwise().reverseInPlace();
151 template<
typename MODEL>
154 double evalsum = Evals_.sum();
157 if ((evalsum-Evals_.size()) > 1e-5) {
158 Log::error() <<
"VerticalLocEV trace(cov)~=cov.size: trace(cov)=" <<
159 evalsum <<
"cov.size=" << Evals_.size() << std::endl;
160 throw eckit::BadValue(
"VerticalLocEV trace(cov)~=cov.size");
166 for (
int ii=0; ii < Evals_.size(); ++ii) {
169 if (frac/evalsum >= options_.VertLocToll) {
break; }
173 oops::Log::info() <<
"Retaining frac: " << frac << std::endl;
174 oops::Log::info() <<
"Retaining neig vectors in vert. loc.: " << neig << std::endl;
178 Evals_.array() *= 1/frac;
179 for (
int ii=0; ii < Evals_.size(); ++ii) {
180 Evecs_.array().col(ii) *= std::sqrt(Evals_(ii));
184 Evecs_.conservativeResize(Eigen::NoChange, neig);
185 Evals_.conservativeResize(neig);
188 if ((evalsum-Evals_.sum()) > 1e-5) {
189 Log::error() <<
"VerticalLocEV::truncateEvecs trace(cov)~=trace(covTrunc): " <<
190 " trace(cov)=" << evalsum <<
" trace(covTrunc)=" << Evals_.sum() <<
191 " diff=" << (evalsum-Evals_.sum()) << std::endl;
192 throw eckit::BadValue(
"VerticalLocEV::truncateEvecs trace(cov)~=trace(covTrunc)");
201 template<
typename MODEL>
204 Eigen::MatrixXd cov = computeCorrMatrix(geom);
207 Eigen::MatrixXd covOld = cov+cov.transpose();
208 covOld.diagonal() = covOld.diagonal()/2;
211 Eigen::MatrixXd covNew = Evecs_*Evecs_.transpose();
213 oops::Log::debug() <<
"Trace covNew " << covNew.diagonal().sum() << std::endl;
214 oops::Log::debug() <<
"Trace cov " << covOld.diagonal().sum() << std::endl;
216 oops::Log::debug() <<
"norm(covNew) " << covNew.norm() << std::endl;
217 oops::Log::debug() <<
"norm(cov) " << covOld.norm() << std::endl;
219 covNew = covNew.array() - covOld.array();
220 oops::Log::debug() <<
"norm(covNew-cov) " << covNew.norm() << std::endl;
222 bool rv = (covNew.diagonal().sum() - cov.diagonal().sum()) < 1e-5;
227 template<
typename MODEL>
241 for (
size_t ieig=0; ieig < neig_; ++ieig) {
242 std::vector<double> EvecRepl = replicateEigenVector(vars, ieig);
244 for (
size_t itime=0; itime < incr.
size(); ++itime) {
249 incrsOut[ieig][itime].setLocal(gp, gpi);
256 template<
typename MODEL>
260 size_t itime)
const {
264 size_t nv = Evecs_.rows()*vars.
size();
265 size_t nens = incrs.
size();
266 Eigen::MatrixXd Z(nv, neig_*nens);
267 std::vector<double> etmp2(nv);
270 for (
size_t iens=0; iens < nens; ++iens) {
273 for (
size_t ieig=0; ieig < neig_; ++ieig) {
274 std::vector<double> EvecRepl = replicateEigenVector(vars, ieig);
276 for (
size_t iv=0; iv < nv; ++iv) {
277 Z(iv, ii) = EvecRepl[iv]*etmp2[iv];
284 template<
typename MODEL>
288 std::vector<double> etmp(Evecs_.rows()*v.
size());
291 for (
unsigned ivar=0; ivar < v.
size(); ++ivar) {
292 for (
unsigned ilev=0; ilev < Evecs_.rows(); ++ilev) {
293 etmp[ii] = Evecs_(ilev, ieig);
Geometry class used in oops; subclass of interface class interface::Geometry.
4D model state Increment (vector of 3D Increments)
Geometry_ geometry() const
Get geometry.
Ensemble of 4D increments.
size_t size() const
Accessors.
const std::vector< double > & getVals() const
std::vector< double > replicateEigenVector(const oops::Variables &, size_t) const
Increment4D< MODEL > Increment4D_
Eigen::MatrixXd computeCorrMatrix(const Geometry_ &)
VerticalLocalizationParameters options_
void print(std::ostream &) const
void computeCorrMatrixEvec(const Eigen::MatrixXd &)
VerticalLocEV(const Geometry_ &, const eckit::Configuration &)
GeometryIterator< MODEL > GeometryIterator_
Geometry< MODEL > Geometry_
IncrementEnsemble4D< MODEL > IncrementEnsemble4D_
void modulateIncrement(const Increment4D_ &, IncrementEnsemble4D_ &) const
static const std::string classname()
bool testTruncateEvecs(const Geometry_ &)
Parameters for vertical localization.
RequiredParameter< double > VertLocDist
Parameter< double > VertLocToll
RequiredParameter< std::string > VertLocUnits
GeometryIterator_ end() const
Iterator to the past-the-end gridpoint of Geometry (only used in LocalEnsembleDA)
std::vector< double > verticalCoord(std::string &) const
Values of vertical coordinate in units specified by string (only used in GETKF)
GeometryIterator_ begin() const
Iterator to the first gridpoint of Geometry (only used in LocalEnsembleDA)
The namespace for the main oops code.
double gc99(const double &distnorm)