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_