8 #ifndef OOPS_ASSIMILATION_DRPBLOCKLANCZOSMINIMIZER_H_
9 #define OOPS_ASSIMILATION_DRPBLOCKLANCZOSMINIMIZER_H_
11 #include <Eigen/Dense>
19 #include "eckit/config/Configuration.h"
20 #include "eckit/mpi/Comm.h"
30 #include "oops/util/dot_product.h"
31 #include "oops/util/formats.h"
32 #include "oops/util/Logger.h"
46 const std::string
classname()
const override {
return "DRPBlockLanczosMinimizer";}
52 const double,
const int,
const double)
override;
56 const eckit::mpi::Comm &,
CtrlInc_ &);
58 const eckit::mpi::Comm &,
CtrlInc_ &);
62 const eckit::mpi::Comm &,
CtrlInc_ &);
83 template<
typename MODEL,
typename OBS>
86 :
DRMinimizer<MODEL, OBS>(J), members_(conf.getInt(
"members")),
88 tasks_per_member_(ntasks_/members_), global_task_(
oops::mpi::
world().rank()),
89 mymember_(global_task_ / tasks_per_member_), local_task_(global_task_%tasks_per_member_),
90 diagConf_(conf), outerLoop_(0) {}
94 template<
typename MODEL,
typename OBS>
97 const double costJ0Jb,
const double costJ0JoJc,
98 const int maxiter,
const double tolerance) {
99 eigenvec_ zerov = Eigen::VectorXd::Zero(members_);
100 eigenmat_ zeromm = Eigen::MatrixXd::Zero(members_, members_);
111 std::vector<std::unique_ptr<CtrlInc_>> Zbase;
112 std::vector<std::unique_ptr<CtrlInc_>> Vbase;
121 std::vector<eigenmat_> ALPHAS;
122 std::vector<eigenmat_> BETAS;
127 double norm_iiter = 0;
129 double normReduction = 1;
130 double normReductionIter = 1;
132 int iterTotal = maxiter;
134 bool complexValues =
false;
137 eigenmat_ norm_red_all(maxiter, members_);
144 std::string CommGeoStr =
"comm_geo_" + std::to_string(local_task_);
145 char const *CommGeoName = CommGeoStr.c_str();
146 const eckit::mpi::Comm & CommGeo =
oops::mpi::world().split(local_task_, CommGeoName);
147 Log::info() <<
"Geo communicators created, for task 0 of member 0: "
148 << CommGeo.name() <<
" of size " << CommGeo.size() << std::endl;
152 norm0 = sqrt(dot_product(zz, rr));
155 mqrgs(zz, vv, beta0, rr, gestag, CommGeo, temp1, temp2);
157 Vbase.emplace_back(std::unique_ptr<CtrlInc_>(
new CtrlInc_(vv)));
158 Zbase.emplace_back(std::unique_ptr<CtrlInc_>(
new CtrlInc_(zz)));
160 for (
int iiter = 0; iiter < maxiter && normReductionIter > tolerance; ++iiter) {
161 Log::info() <<
"BlockBLanczos starting iteration " << iiter+1 <<
" for rank: " << mymember_
167 HtRinvH0(zz, ww, HtRinvH, gestag, CommGeo, temp1);
172 for (
int jiter = 0; jiter < iiter + 1; ++jiter) {
173 get_proj(ww, *Zbase[jiter], alpha, gestag, CommGeo, temp1);
174 apply_proj(ww, *Vbase[jiter], alpha, gestag, CommGeo, temp1);
178 get_proj(ww, zz, projsol, gestag, CommGeo, temp1);
181 mqrgs(zz, vv, beta, ww, gestag, CommGeo, temp1, temp2);
183 Zbase.emplace_back(std::unique_ptr<CtrlInc_>(
new CtrlInc_(zz)));
184 Vbase.emplace_back(std::unique_ptr<CtrlInc_>(
new CtrlInc_(vv)));
185 ALPHAS.push_back(alpha);
186 BETAS.push_back(beta);
191 eigenvec_ ss_loc = (ss.block(iiter*members_, 0, members_, members_)).col(mymember_);
194 norm_iiter = sqrt(temp.dot(ss_loc));
195 normReduction = norm_iiter / norm0;
197 const double costJ0 = costJ0Jb + costJ0JoJc;
198 double costJ = costJ0;
202 for (
int ll = 0; ll < iiter+1; ++ll) {
203 SSLK = - (ss.block(ll*members_, 0, members_, members_));
208 apply_proj(temp2, *Zbase[ll], SSLK, gestag, CommGeo, temp1);
209 costJ -= 0.5 * dot_product(temp2, rr);
212 Log::info() <<
"BlockBLanczos end of iteration " << iiter+1 << std::endl;
216 norm_red_loc[iiter] = normReduction;
217 costj_loc[iiter] = costJ;
219 oops::mpi::world().allReduce(normReduction, normReductionIter, eckit::mpi::max());
220 if (normReductionIter < tolerance) {
221 Log::info() <<
"DRPBlockLanczos: Achieved required reduction in residual norm." << std::endl;
233 Eigen::IOFormat HeavyFmt(-2, 0,
", ",
";\n");
234 Eigen::IOFormat TestFmt(-1, 0,
", ",
";\n");
237 for (
int ll = 0; ll < iterTotal; ++ll) {
238 SSLK = - (ss.block(ll*members_, 0, members_, members_));
239 apply_proj(xh, *Vbase[ll], SSLK, gestag, CommGeo, temp1);
240 apply_proj(xx, *Zbase[ll], SSLK, gestag, CommGeo, temp1);
242 tmp_norm = norm_red_all.block(ll, 0, 1, members_);
243 tmp_costj = costj_all.block(ll, 0, 1, members_);
245 Log::info() <<
" Norm reduction all members (" << std::setw(2) << ll+1 <<
") = "
246 << tmp_norm.format(HeavyFmt) << std::endl;
247 Log::info() <<
" Quadratic cost function all members: J (" << std::setw(2) << ll+1 <<
") = "
248 << tmp_costj.format(HeavyFmt) << std::endl;
249 Log::test() <<
" Norm reduction all members (" << std::setw(2) << ll+1 <<
") = "
250 << tmp_norm.format(TestFmt) << std::endl;
251 Log::test() <<
" Quadratic cost function all members: J (" << std::setw(2) << ll+1 <<
") = "
252 << tmp_costj.format(TestFmt) << std::endl;
255 eckit::mpi::deleteComm(CommGeoName);
257 return normReduction;
264 template<
typename MODEL,
typename OBS>
268 const eckit::mpi::Comm & comm,
273 eigenvec_ alpha_loc = Eigen::VectorXd::Zero(members_);
277 for (
int p = 0; p < mymember_; p++) {
278 tag_rcv = p * members_ + mymember_ + tag * members_ * members_;
279 tag_send = mymember_ * members_ + p + tag * members_ * members_;
282 alpha_loc(p) = dot_product(incr_rcv, www);
285 alpha_loc(mymember_) = dot_product(incr_tosend, www);
287 for (
int p = mymember_ + 1; p < members_; p++) {
288 tag_rcv = p * members_ + mymember_ + tag * members_ * members_;
289 tag_send = mymember_ * members_ + p + tag * members_ * members_;
292 alpha_loc(p) = dot_product(incr_rcv, www);
301 template<
typename MODEL,
typename OBS>
305 const eckit::mpi::Comm & comm,
310 eigenvec_ alpha_loc = alpha_mat.col(mymember_);
314 for (
int p = 0; p < mymember_; p++) {
315 tag_rcv = p * members_ + mymember_ + tag * members_ * members_;
316 tag_send = mymember_ * members_ + p + tag * members_ * members_;
319 incr_tochange.
axpy(-alpha_loc(p), incr_rcv);
322 incr_tochange.
axpy(-alpha_loc(mymember_), incr_tosend);
324 for (
int p = mymember_ + 1; p < members_; p++) {
325 tag_rcv = p * members_ + mymember_ + tag * members_ * members_;
326 tag_send = mymember_ * members_ + p + tag * members_ * members_;
329 incr_tochange.
axpy(-alpha_loc(p), incr_rcv);
336 template<
typename MODEL,
typename OBS>
340 const eckit::mpi::Comm & comm,
343 eigenvec_ beta_loc = Eigen::VectorXd::Zero(members_);
350 for (
int p = 0; p < mymember_; p++) {
351 tag_rcv_v = p * members_ + mymember_ + tag * members_ * members_;
352 tag_rcv_z = p * members_ + mymember_ + (tag + 1) * members_ * members_;
355 beta_loc(p) = dot_product(www, z_other) / dot_product(v_other, z_other);
356 vvv.
axpy(-beta_loc(p), v_other);
357 zzz.
axpy(-beta_loc(p), z_other);
360 for (
int p = mymember_ + 1; p < members_; p++) {
361 tag_send_v = mymember_ * members_ + p + tag * members_ * members_;
362 tag_send_z = mymember_ * members_ + p + (tag + 1) * members_ * members_;
368 beta_loc(mymember_) = sqrt(std::max(dot_product(vvv, zzz), 1e-15));
370 vvv *= (1 / beta_loc(mymember_));
371 zzz *= (1 / beta_loc(mymember_));
375 for (
int ii = 0; ii < members_; ++ii) {
376 for (
int jj = ii + 1; jj < members_; ++jj) {
377 beta_mat(ii, jj) = beta_mat(ii, jj) * beta_mat(ii, ii);
386 template<
typename MODEL,
typename OBS>
388 const HtRinvH_ & HtRinvH,
int & tag,
389 const eckit::mpi::Comm & comm,
CtrlInc_ & z_other) {
397 if (mymember_ == 0) {
398 for (
int ii = 1; ii < members_; ++ii) {
399 tag_rcv_z = members_ * ii + tag * members_ * members_;
402 tag_send_w = members_ * ii + (tag + 1) * members_ * members_;
407 tag_send_z = mymember_ * members_ + tag * members_ * members_;
409 tag_rcv_w = mymember_ * members_ + (tag + 1) * members_ * members_;
void multiply(const CtrlInc_ &x, CtrlInc_ &bx) const
void zero()
Linear algebra operators.
void axpy(const double, const ControlIncrement &)
DR (Derber and Rosati) Minimizers.
Eigen::MatrixXd eigenmat_
void mqrgs(CtrlInc_ &, CtrlInc_ &, eigenmat_ &, const CtrlInc_ &, int &, const eckit::mpi::Comm &, CtrlInc_ &, CtrlInc_ &)
void get_proj(const CtrlInc_ &, const CtrlInc_ &, eigenmat_ &, int &, const eckit::mpi::Comm &, CtrlInc_ &)
ControlIncrement< MODEL, OBS > CtrlInc_
void apply_proj(CtrlInc_ &, const CtrlInc_ &, const eigenmat_ &, int &, const eckit::mpi::Comm &, CtrlInc_ &)
double solve(CtrlInc_ &, CtrlInc_ &, CtrlInc_ &, const Bmat_ &, const HtRinvH_ &, const double, const double, const int, const double) override
const int tasks_per_member_
~DRPBlockLanczosMinimizer()
void HtRinvH0(const CtrlInc_ &, CtrlInc_ &, const HtRinvH_ &, int &, const eckit::mpi::Comm &, CtrlInc_ &)
Eigen::VectorXd eigenvec_
const std::string classname() const override
eckit::LocalConfiguration diagConf_
HtRinvHMatrix< MODEL, OBS > HtRinvH_
CostFunction< MODEL, OBS > CostFct_
BMatrix< MODEL, OBS > Bmat_
DRPBlockLanczosMinimizer(const eckit::Configuration &, const CostFct_ &)
void multiply(const CtrlInc_ &dx, CtrlInc_ &dz) const
void allGather(const eckit::mpi::Comm &comm, const Eigen::VectorXd &sendbuf, Eigen::MatrixXd &recvbuf)
void send(const eckit::mpi::Comm &comm, const SERIALIZABLE &sendobj, const int dest, const int tag)
Extend eckit Comm for Serializable oops objects.
const eckit::mpi::Comm & world()
Default communicator with all MPI tasks (ie MPI_COMM_WORLD)
void receive(const eckit::mpi::Comm &comm, SERIALIZABLE &recvobj, const int source, const int tag)
The namespace for the main oops code.
void writeKrylovBasis(const eckit::Configuration &config, const ControlIncrement< MODEL, OBS > &dx, const int &loop)
void printQuadraticCostFunction(int iteration, const double &costJ, const double &costJb, const double &costJoJc)
void blockTriDiagSolve(const std::vector< Eigen::MatrixXd > &alphas, const std::vector< Eigen::MatrixXd > &betas, const Eigen::MatrixXd &beta0, Eigen::MatrixXd &ss, bool &complexValues, const int members)
void printNormReduction(int iteration, const double &grad, const double &norm)