8 #ifndef OOPS_GENERIC_VERTICALLOCEV_H_
9 #define OOPS_GENERIC_VERTICALLOCEV_H_
11 #include <Eigen/Dense>
17 #include "eckit/config/Configuration.h"
27 #include "oops/util/Logger.h"
28 #include "oops/util/ObjectCounter.h"
29 #include "oops/util/parameters/Parameter.h"
30 #include "oops/util/parameters/Parameters.h"
31 #include "oops/util/parameters/RequiredParameter.h"
32 #include "oops/util/Printable.h"
52 Parameter<double>
VertLocToll{
"fraction of retained variance", 1.0,
this};
56 RequiredParameter<std::string>
VertLocUnits{
"lengthscale units",
this};
58 Parameter<bool>
writeEVs{
"write eigen vectors",
false,
this};
60 Parameter<bool>
readEVs{
"read eigen vectors",
false,
this};
64 template<
typename MODEL>
66 private util::ObjectCounter<VerticalLocEV<MODEL>> {
76 static const std::string
classname() {
return "oops::VerticalLocEV";}
110 const eckit::Configuration &);
125 template<
typename MODEL>
127 const State_ & x): sqrtVertLoc_() {
132 oops::Log::info() <<
"Reading precomputed vertical localization EVs from disk" << std::endl;
136 oops::Log::info() <<
"Computing vertical localization EVs from scratch" << std::endl;
154 template<
typename MODEL>
157 for (
size_t ieig=0; ieig < neig_; ++ieig) {
158 std::vector<double> EvecRepl = replicateEigenVector(vars, ieig);
159 (*sqrtVertLoc_)[ieig].ones();
163 (*sqrtVertLoc_)[ieig].setLocal(gp, gpi);
169 template<
typename MODEL>
171 eckit::LocalConfiguration outConfig(config,
"list of eigen vectors to write");
172 sqrtVertLoc_->write(outConfig);
176 template<
typename MODEL>
178 const util::DateTime & tslot,
179 const eckit::Configuration & config) {
180 std::vector<eckit::LocalConfiguration> memberConfig;
181 config.get(
"list of eigen vectors to read", memberConfig);
182 sqrtVertLoc_ = boost::make_unique<IncrementEnsemble_>(geom, vars, tslot, memberConfig.
size());
185 for (
size_t jj = 0; jj < memberConfig.size(); ++jj) {
186 (*sqrtVertLoc_)[jj].read(memberConfig[jj]);
191 template<
typename MODEL>
193 std::string locUnits = options_.VertLocUnits;
194 oops::Log::debug() <<
"locUnits: " << locUnits << std::endl;
196 size_t nlevs = vCoord.size();
199 Eigen::MatrixXd cov = Eigen::MatrixXd::Zero(nlevs, nlevs);
200 for (
size_t jj=0; jj < nlevs; ++jj) {
201 for (
size_t ii=jj; ii < nlevs; ++ii) {
202 cov(ii, jj) =
oops::gc99(std::abs(vCoord[jj]-vCoord[ii])/options_.VertLocDist);
205 oops::Log::debug() <<
"corr: " << cov << std::endl;
212 template<
typename MODEL>
215 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(cov);
216 Evals_ = es.eigenvalues().real();
217 Evecs_ = es.eigenvectors().real();
220 Evals_.reverseInPlace();
221 Evecs_.rowwise().reverseInPlace();
225 template<
typename MODEL>
228 double evalsum = Evals_.sum();
231 if ((evalsum-Evals_.size()) > 1e-5) {
232 Log::error() <<
"VerticalLocEV trace(cov)~=cov.size: trace(cov)=" <<
233 evalsum <<
"cov.size=" << Evals_.size() << std::endl;
234 throw eckit::BadValue(
"VerticalLocEV trace(cov)~=cov.size");
240 for (
int ii=0; ii < Evals_.size(); ++ii) {
243 if (frac/evalsum >= options_.VertLocToll) {
break; }
247 oops::Log::info() <<
"Retaining frac: " << frac << std::endl;
248 oops::Log::info() <<
"Retaining neig vectors in vert. loc.: " << neig << std::endl;
252 Evals_.array() *= 1/frac;
253 for (
int ii=0; ii < Evals_.size(); ++ii) {
254 Evecs_.array().col(ii) *= std::sqrt(Evals_(ii));
258 Evecs_.conservativeResize(Eigen::NoChange, neig);
259 Evals_.conservativeResize(neig);
262 if ((evalsum-Evals_.sum()) > 1e-5) {
263 Log::error() <<
"VerticalLocEV::truncateEvecs trace(cov)~=trace(covTrunc): " <<
264 " trace(cov)=" << evalsum <<
" trace(covTrunc)=" << Evals_.sum() <<
265 " diff=" << (evalsum-Evals_.sum()) << std::endl;
266 throw eckit::BadValue(
"VerticalLocEV::truncateEvecs trace(cov)~=trace(covTrunc)");
275 template<
typename MODEL>
279 if (options_.readEVs) {
return true;}
282 Eigen::MatrixXd cov = computeCorrMatrix(geom);
285 Eigen::MatrixXd covOld = cov+cov.transpose();
286 covOld.diagonal() = covOld.diagonal()/2;
289 Eigen::MatrixXd covNew = Evecs_*Evecs_.transpose();
291 oops::Log::debug() <<
"Trace covNew " << covNew.diagonal().sum() << std::endl;
292 oops::Log::debug() <<
"Trace cov " << covOld.diagonal().sum() << std::endl;
294 oops::Log::debug() <<
"norm(covNew) " << covNew.norm() << std::endl;
295 oops::Log::debug() <<
"norm(cov) " << covOld.norm() << std::endl;
297 covNew = covNew.array() - covOld.array();
298 oops::Log::debug() <<
"norm(covNew-cov) " << covNew.norm() << std::endl;
300 bool rv = (covNew.diagonal().sum() - cov.diagonal().sum()) < 1e-5;
305 template<
typename MODEL>
319 for (
size_t ieig=0; ieig < neig_; ++ieig) {
321 for (
size_t itime=0; itime < incr.
size(); ++itime) {
322 if (EVsStoredAs3D_) {
323 incrsOut[ieig][itime] = (*sqrtVertLoc_)[ieig];
324 incrsOut[ieig][itime].schur_product_with(incr[itime]);
326 std::vector<double> EvecRepl = replicateEigenVector(vars, ieig);
331 incrsOut[ieig][itime].setLocal(gp, gpi);
339 template<
typename MODEL>
343 size_t itime)
const {
348 std::vector<double> EvecRepl;
349 if (EVsStoredAs3D_) {
350 nv = (*sqrtVertLoc_)[0].getLocal(gi).getVals().
size();
352 EvecRepl = replicateEigenVector(vars, 0);
353 nv = EvecRepl.size();
355 size_t nens = incrs.
size();
356 Eigen::MatrixXd Z(nv, neig_*nens);
357 std::vector<double> etmp2(nv);
360 for (
size_t iens=0; iens < nens; ++iens) {
361 etmp2 = incrs[iens][itime].getLocal(gi).getVals();
362 for (
size_t ieig=0; ieig < neig_; ++ieig) {
363 if (EVsStoredAs3D_) {
364 EvecRepl = (*sqrtVertLoc_)[ieig].getLocal(gi).getVals();
366 EvecRepl = replicateEigenVector(vars, ieig);
369 for (
size_t iv=0; iv < nv; ++iv) {
370 Z(iv, ii) = EvecRepl[iv]*etmp2[iv];
379 template<
typename MODEL>
383 std::vector<double> etmp(Evecs_.rows()*v.
size());
386 for (
unsigned ivar=0; ivar < v.
size(); ++ivar) {
387 for (
unsigned ilev=0; ilev < Evecs_.rows(); ++ilev) {
388 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.
Increment class used in oops.
State class used in oops; subclass of interface class interface::State.
std::vector< double > replicateEigenVector(const oops::Variables &, size_t) const
Increment4D< MODEL > Increment4D_
Eigen::MatrixXd computeCorrMatrix(const Geometry_ &)
void writeEVsToDisk(const eckit::Configuration &) const
VerticalLocalizationParameters options_
void print(std::ostream &) const
void readEVsFromDisk(const Geometry_ &, const Variables &, const util::DateTime &, const eckit::Configuration &)
void computeCorrMatrixEvec(const Eigen::MatrixXd &)
std::unique_ptr< IncrementEnsemble_ > sqrtVertLoc_
Increment< MODEL > Increment_
GeometryIterator< MODEL > GeometryIterator_
Geometry< MODEL > Geometry_
IncrementEnsemble4D< MODEL > IncrementEnsemble4D_
void modulateIncrement(const Increment4D_ &, IncrementEnsemble4D_ &) const
static const std::string classname()
IncrementEnsemble< MODEL > IncrementEnsemble_
VerticalLocEV(const eckit::Configuration &, const State_ &)
bool testTruncateEvecs(const Geometry_ &)
void populateIncrementEnsembleWithEVs(const Variables &)
Parameters for vertical localization.
RequiredParameter< double > VertLocDist
Parameter< double > VertLocToll
Parameter< bool > readEVs
Parameter< bool > writeEVs
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)
const Geometry_ & geometry() const
GeometryIterator_ begin() const
Iterator to the first gridpoint of Geometry (only used in LocalEnsembleDA)
Geometry_ geometry() const
Accessor to geometry associated with this State.
const util::DateTime validTime() const
Accessor to the time of this State.
const Variables & variables() const
Accessor to variables associated with this State.
The namespace for the main oops code.
double gc99(const double &distnorm)