11 #ifndef OOPS_ASSIMILATION_SPECTRALLMP_H_ 12 #define OOPS_ASSIMILATION_SPECTRALLMP_H_ 19 #include <boost/ptr_container/ptr_vector.hpp> 20 #include <boost/scoped_ptr.hpp> 22 #include "eckit/config/LocalConfiguration.h" 24 #include "oops/util/dot_product.h" 25 #include "oops/util/Logger.h" 56 void update(boost::ptr_vector<VECTOR> &, boost::ptr_vector<VECTOR> &,
57 boost::ptr_vector<VECTOR> &, std::vector<double> &, std::vector<double> &);
59 void multiply(
const VECTOR &, VECTOR &)
const;
68 boost::ptr_vector<VECTOR>
X_;
69 boost::ptr_vector<VECTOR>
U_;
74 boost::ptr_vector<VECTOR>
Y_;
75 boost::ptr_vector<VECTOR>
S_;
84 template<
typename VECTOR>
86 : maxpairs_(0), useoldpairs_(
false), RitzPrecond_(
false), maxouter_(0), update_(0)
88 maxouter_ =
conf.getInt(
"nouter");
89 Log::info() <<
"SpectralLMP: maxouter = " << maxouter_ << std::endl;
91 if (
conf.has(
"preconditioner")) {
92 const eckit::LocalConfiguration precond(
conf,
"preconditioner");
93 if (precond.has(
"maxpairs")) maxpairs_ = precond.getInt(
"maxpairs");
96 Log::info() <<
"SpectralLMP: maxpairs_ = " << maxpairs_ << std::endl;
99 if (precond.has(
"ritz")) ritz = precond.getString(
"ritz");
100 RitzPrecond_ = (ritz ==
"on" || ritz ==
"true");
101 Log::info() <<
"SpectralLMP: RitzPrecond_ = " << RitzPrecond_ << std::endl;
104 if (precond.has(
"useoldpairs")) old = precond.getString(
"useoldpairs");
105 useoldpairs_ = (old ==
"on" || old ==
"true");
106 Log::info() <<
"SpectralLMP: useoldpairs_ = " << useoldpairs_ << std::endl;
113 template<
typename VECTOR>
115 boost::ptr_vector<VECTOR> & Zhl,
116 boost::ptr_vector<VECTOR> & Zl,
117 std::vector<double> & alphas,
118 std::vector<double> & betas) {
125 usedpairIndx_.clear();
131 Log::debug() <<
"SpectralLMP size Zl = " << Zl.size() << std::endl;
132 Log::debug() <<
"SpectralLMP size Zhl = " << Zhl.size() << std::endl;
133 Log::debug() <<
"SpectralLMP size alpha = " << alphas.size() << std::endl;
134 Log::debug() <<
"SpectralLMP size beta = " << betas.size() << std::endl;
135 const unsigned nvec = Zl.size();
136 ASSERT(Zhl.size() == nvec);
140 Log::info() <<
"SpectralLMP: update " << update_ <<
", max = " << maxouter_-1 << std::endl;
141 ASSERT(alphas.size() == nvec-1);
142 ASSERT(betas.size() == nvec-1);
143 std::vector<double> evals;
144 std::vector< std::vector<double> > evecs;
150 std::vector<unsigned> convIndx;
151 unsigned oldpairIndx = 0;
152 for (
unsigned jiter = 0; jiter < nvec-1; ++jiter) {
153 double erritz = evecs[jiter][nvec-2]*betas[nvec-2];
154 double lambda = evals[jiter];
156 if (std::abs(erritz) <= 0.001*
lambda) {
157 convIndx.push_back(jiter);
158 eigvals_.push_back(
lambda);
159 omega_.push_back(erritz/
lambda);
162 if (convIndx.size() > maxpairs_) {
163 convIndx.erase(convIndx.begin());
165 if (eigvals_.size() > maxpairs_) {
166 eigvals_.erase(eigvals_.begin());
167 omega_.erase(omega_.begin());
173 usedpairIndx_.push_back(convIndx.size());
174 unsigned reduc = oldpairIndx;
175 for (
unsigned kiter = 0; kiter < usedpairIndx_.size()-1; ++kiter) {
176 if (reduc <= usedpairIndx_[kiter]) {
177 usedpairIndx_[kiter] -= reduc;
180 reduc -= usedpairIndx_[kiter];
181 usedpairIndx_[kiter] = 0;
184 unsigned counter = 0;
185 for (
unsigned kiter = 0; kiter < usedpairIndx_.size(); ++kiter) {
186 counter += usedpairIndx_[kiter];
188 ASSERT(counter <= maxpairs_);
189 Log::info() <<
"SpectralLMP: Number of inner iterations : " << Zl.size()-1 << std::endl;
190 Log::info() <<
"SpectralLMP: Number of maximum pairs : " << maxpairs_ << std::endl;
191 Log::info() <<
"SpectralLMP: Number of used total pairs : " << counter << std::endl;
192 Log::info() <<
"SpectralLMP: Number of new converged pairs : " << convIndx.size() << std::endl;
193 Log::info() <<
"SpectralLMP: Number of removed old pairs : " << oldpairIndx << std::endl;
194 for (
unsigned kiter = 0; kiter < usedpairIndx_.size(); ++kiter) {
195 Log::info() <<
"SpectralLMP: Number of used pairs from outer loop " << kiter + 1
196 <<
" : " << usedpairIndx_[kiter] << std::endl;
201 if (X_.size() != 0) {
203 unsigned minsize =
std::min(oldpairIndx, maxpairs_);
204 unsigned xsize = X_.size();
205 X_.erase(X_.begin(), X_.begin() +
std::min(xsize, minsize));
206 U_.erase(U_.begin(), U_.begin() +
std::min(xsize, minsize));
208 for (
unsigned jiter = 0; jiter < convIndx.size(); ++jiter) {
209 VECTOR * ww =
new VECTOR(Zl[0],
false);
210 for (
unsigned iiter = 0; iiter < nvec-1; ++iiter) {
211 ww->axpy(evecs[convIndx[jiter]][iiter], Zl[iiter]);
216 for (
unsigned jiter = 0; jiter < convIndx.size(); ++jiter) {
217 VECTOR * ww =
new VECTOR(Zl[0],
false);
218 for (
unsigned iiter = 0; iiter < nvec-1; ++iiter) {
219 ww->axpy(evecs[convIndx[jiter]][iiter], Zhl[iiter]);
226 Zlast_.push_back(Zl[nvec-1]);
227 Zhlast_.push_back(Zhl[nvec-1]);
233 for (
unsigned kiter = 0; kiter < usedpairIndx_.size(); ++kiter) {
234 if (usedpairIndx_[kiter] != 0) {
235 zcount.push_back(kiter);
236 VECTOR * ww =
new VECTOR(Zl[0],
false);
237 for (
unsigned jiter = 0; jiter < usedpairIndx_[kiter]; ++jiter) {
238 ww->axpy(omega_[jiter + kk], U_[jiter + kk]);
240 kk += usedpairIndx_[kiter];
248 for (
unsigned kiter = 0; kiter < usedpairIndx_.size(); ++kiter) {
249 if (usedpairIndx_[kiter] != 0) {
250 VECTOR * ww =
new VECTOR(Zl[0],
false);
251 for (
unsigned jiter = 0; jiter < usedpairIndx_[kiter]; ++jiter) {
252 ww->axpy(omega_[jiter + kk], X_[jiter + kk]);
254 kk += usedpairIndx_[kiter];
271 template<
typename VECTOR>
275 for (
unsigned iiter = 0; iiter < eigvals_.size(); ++iiter) {
276 double zeval =
std::min(10.0, eigvals_[iiter]);
278 double zz = 1.0/zeval - 1.0;
279 b.axpy(zz*dot_product(
a, X_[iiter]), U_[iiter]);
282 if (RitzPrecond_ && eigvals_.size() != 0) {
284 std::vector<double> sta;
286 for (
unsigned iiter = 0; iiter < S_.size(); ++iiter) {
287 sta.push_back(dot_product(S_[iiter],
a));
291 for (
unsigned kiter = 0; kiter < S_.size(); ++kiter) {
292 for (
unsigned iiter = 0; iiter < eigvals_.size(); ++iiter) {
293 double wxap = sta[kiter] - dot_product(
a, Zlast_[zcount[kiter]]);
294 b.axpy(wxap, Y_[kiter]);
299 for (
unsigned kiter = 0; kiter < S_.size(); ++kiter) {
300 b.axpy(-sta[kiter], Zhlast_[zcount[kiter]]);
309 #endif // OOPS_ASSIMILATION_SPECTRALLMP_H_ boost::ptr_vector< VECTOR > U_
void multiply(const VECTOR &, VECTOR &) const
std::vector< double > omega_
std::vector< VECTOR > Zlast_
std::vector< double > eigvals_
std::vector< unsigned > zcount
boost::ptr_vector< VECTOR > X_
boost::ptr_vector< VECTOR > Y_
integer(long), parameter false
std::vector< unsigned > usedpairIndx_
boost::ptr_vector< VECTOR > S_
The solvers represent matrices as objects that implement a "multiply" method.
The namespace for the main oops code.
void TriDiagSpectrum(const std::vector< double > &diag, const std::vector< double > &sub, std::vector< double > &evals, std::vector< std::vector< double > > &evecs)
subroutine, public multiply(self, geom, xctl, xmod)
SpectralLMP(const eckit::Configuration &)
void update(boost::ptr_vector< VECTOR > &, boost::ptr_vector< VECTOR > &, boost::ptr_vector< VECTOR > &, std::vector< double > &, std::vector< double > &)
subroutine, public info(self)
std::vector< VECTOR > Zhlast_
************************************************************************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