11 #ifndef OOPS_ASSIMILATION_QNEWTONLMP_H_    12 #define OOPS_ASSIMILATION_QNEWTONLMP_H_    18 #include "eckit/config/LocalConfiguration.h"    19 #include "oops/util/dot_product.h"    20 #include "oops/util/Logger.h"    22 #include <boost/scoped_ptr.hpp>    41 template<
typename VECTOR, 
typename BMATRIX> 
class QNewtonLMP {
    43   explicit QNewtonLMP(
const eckit::Configuration &);
    46   void push(
const VECTOR &, 
const VECTOR &, 
const VECTOR &, 
const double &);
    47   void update(
const BMATRIX & B);
    49   void multiply(
const VECTOR &, VECTOR &) 
const;
    52   void tmultiply(
const VECTOR &, VECTOR &) 
const;
    61   std::vector<VECTOR> 
P_;
    62   std::vector<VECTOR> 
Ph_;
    63   std::vector<VECTOR> 
AP_;
    76 template<
typename VECTOR, 
typename BMATRIX>
    78   : maxpairs_(0), maxnewpairs_(0), useoldpairs_(
false), maxouter_(0), update_(1)
    80   maxouter_ = 
conf.getInt(
"nouter");
    81   Log::info() << 
"QNewtonLMP: maxouter : " << maxouter_ << std::endl;
    83   if (
conf.has(
"preconditioner")) {
    84     const eckit::LocalConfiguration precond(
conf, 
"preconditioner");
    85     if (precond.has(
"maxpairs")) maxpairs_ = precond.getInt(
"maxpairs");
    88       if (precond.has(
"useoldpairs")) old = precond.getString(
"useoldpairs");
    89       useoldpairs_ = (old == 
"on" || old == 
"true");
    90       if (useoldpairs_ && precond.has(
"maxnewpairs")) {
    91           maxnewpairs_ = precond.getInt(
"maxnewpairs");
    92           maxnewpairs_ = 
std::min(maxpairs_, maxnewpairs_);
    94        maxnewpairs_ = maxpairs_;
   102 template<
typename VECTOR, 
typename BMATRIX>
   104                                        const VECTOR & ap, 
const double & 
rho) {
   105   ASSERT(savedP_.size() <= maxnewpairs_);
   106   if (maxnewpairs_ > 0 && update_ < maxouter_) {
   107     if (savedP_.size() == maxnewpairs_) {
   108       savedP_.erase(savedP_.begin());
   109       savedPh_.erase(savedPh_.begin());
   110       savedAP_.erase(savedAP_.begin());
   111       savedrhos_.erase(savedrhos_.begin());
   113     savedP_.push_back(
p);
   114     savedPh_.push_back(ph);
   115     savedAP_.push_back(ap);
   116     savedrhos_.push_back(1.0/
rho);
   122 template<
typename VECTOR, 
typename BMATRIX>
   124   Log::debug() << 
"QNewtonLMP size saved Ph    = " << savedPh_.size() << std::endl;
   125   Log::debug() << 
"QNewtonLMP size saved P     = " << savedP_.size() << std::endl;
   126   Log::debug() << 
"QNewtonLMP size saved AP    = " << savedAP_.size() << std::endl;
   127   Log::debug() << 
"QNewtonLMP size saved rhos  = " << savedrhos_.size() << std::endl;
   129   const unsigned nvec = savedPh_.size();
   130   ASSERT(savedP_.size() == nvec);
   131   ASSERT(savedAP_.size() == nvec);
   132   ASSERT(savedrhos_.size() == nvec);
   134   if (!useoldpairs_ || nvec >= maxpairs_) {
   140     for (
unsigned kiter = 0; kiter < usedpairIndx_.size(); ++kiter) {
   141       usedpairIndx_[kiter] = 0;
   145   if (nvec > 0 && update_ < maxouter_) {
   146     Log::info() << 
"QNewtonLMP: update " << update_ << 
", max = " << maxouter_-1 << std::endl;
   147     unsigned newpairs = 
std::min(nvec, maxpairs_);
   148     unsigned oldpairs = P_.size();
   149     unsigned rmpairs = 0;
   151     if (oldpairs + newpairs > maxpairs_) {
   152       rmpairs = oldpairs + newpairs - maxpairs_;
   153       for (
unsigned jv = 0; jv < rmpairs; ++jv) {
   154         Ph_.erase(Ph_.begin());
   155         P_.erase(P_.begin());
   156         AP_.erase(AP_.begin());
   157         BAP_.erase(BAP_.begin());
   158         rhos_.erase(rhos_.begin());
   162       unsigned removed = rmpairs;
   163       for (
unsigned kiter = 0; kiter < usedpairIndx_.size(); ++kiter) {
   164         unsigned rmiter = 
std::min(usedpairIndx_[kiter], removed);
   165         usedpairIndx_[kiter] -= rmiter;
   168       ASSERT(removed == 0);
   170     ASSERT(P_.size() == oldpairs);
   171     ASSERT(oldpairs + newpairs <= maxpairs_);
   174     for (
unsigned jv = nvec - newpairs; jv < nvec; ++jv) {
   175       P_.push_back(savedP_[jv]);
   176       Ph_.push_back(savedPh_[jv]);
   177       AP_.push_back(savedAP_[jv]);
   178       rhos_.push_back(savedrhos_[jv]);
   180       VECTOR ww(savedAP_[jv]);
   181       Bmat.multiply(savedAP_[jv], ww);
   184     ASSERT(P_.size() == oldpairs + newpairs);
   186     Log::info() << 
"Number of inner iterations       : " << nvec << std::endl;
   187     Log::info() << 
"Number of maximum pairs          : " << maxpairs_ << std::endl;
   188     Log::info() << 
"Number of used total pairs       : " << oldpairs + newpairs << std::endl;
   189     Log::info() << 
"Number of new pairs              : " << newpairs << std::endl;
   190     Log::info() << 
"Number of removed old pairs      : " << rmpairs << std::endl;
   191     for (
unsigned kiter = 0; kiter < usedpairIndx_.size(); ++kiter) {
   192       Log::info() << 
"Number of used pairs from outer loop " << kiter + 1
   193                 << 
" : "                                   << usedpairIndx_[kiter];
   206 template<
typename VECTOR, 
typename BMATRIX>
   209   const unsigned nvec = P_.size();
   211     std::vector<double> etas;
   213     for (
int iiter = nvec-1; iiter >= 0; iiter--) {
   214       double eta = dot_product(
b, P_[iiter]);
   217       b.axpy(-
eta, AP_[iiter]);
   219     b *= dot_product(AP_[nvec-1], AP_[nvec-1])/dot_product(AP_[nvec-1], Ph_[nvec-1]);
   220     for (
unsigned iiter = 0; iiter < nvec; ++iiter) {
   221       double sigma = dot_product(
b, BAP_[iiter]);
   222       sigma *= rhos_[iiter];
   223       sigma -= etas[iiter];
   224       b.axpy(-
sigma, Ph_[iiter]);
   231 template<
typename VECTOR, 
typename BMATRIX>
   234   const unsigned nvec = P_.size();
   236     std::vector<double> etas;
   238     for (
int iiter = nvec-1; iiter >= 0; iiter--) {
   239       double eta = dot_product(
b, Ph_[iiter]);
   242       b.axpy(-
eta, BAP_[iiter]);
   244     b *= dot_product(AP_[nvec-1], AP_[nvec-1])/dot_product(AP_[nvec-1], Ph_[nvec-1]);
   245     for (
unsigned iiter = 0; iiter < nvec; ++iiter) {
   246       double sigma = dot_product(
b, AP_[iiter]);
   247       sigma *= rhos_[iiter];
   248       sigma -= etas[iiter];
   249       b.axpy(-
sigma, P_[iiter]);
   258 #endif  // OOPS_ASSIMILATION_QNEWTONLMP_H_ void push(const VECTOR &, const VECTOR &, const VECTOR &, const double &)
std::vector< double > rhos_
std::vector< VECTOR > BAP_
void update(const BMATRIX &B)
QNewtonLMP(const eckit::Configuration &)
integer, parameter sigma
Flags to indicate where climatology pressure levels are pressure or sigma levels. ...
real(r8), dimension(cast_m, cast_n) p
integer(long), parameter false
void tmultiply(const VECTOR &, VECTOR &) const
The namespace for the main oops code. 
void multiply(const VECTOR &, VECTOR &) const
std::vector< VECTOR > savedP_
std::vector< VECTOR > savedAP_
subroutine, public multiply(self, geom, xctl, xmod)
std::vector< VECTOR > AP_
subroutine, public info(self)
std::vector< double > savedrhos_
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version and mpp_transmit will remain !backward compatible intent(inout) a
std::vector< unsigned > usedpairIndx_
std::vector< VECTOR > Ph_
std::vector< VECTOR > savedPh_