RBGen  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RBGen_IncSVDPOD.cpp
1 #include "RBGen_IncSVDPOD.h"
2 #include "AnasaziSVQBOrthoManager.hpp"
3 #include "AnasaziBasicOrthoManager.hpp"
5 #include "Epetra_SerialDenseMatrix.h"
6 #include "Epetra_LAPACK.h"
7 #include "Epetra_LocalMap.h"
8 #include "Epetra_Comm.h"
9 
10 namespace RBGen {
11 
13  isInitialized_(false),
14  filter_(Teuchos::null),
15  maxBasisSize_(0),
16  curRank_(0),
17  sigma_(0),
18  numProc_(0),
19  maxNumPasses_(-1),
20  curNumPasses_(0),
21  tol_(1e-12),
22  lmin_(0),
23  lmax_(0),
24  startRank_(0),
25  timerComp_("Total Elapsed Time"),
26  debug_(false),
27  verbLevel_(0),
28  resNorms_(0),
29  Vlocal_(true)
30  {}
31 
33  if (curRank_ == 0 || isInitialized_ == false) {
34  return Teuchos::null;
35  }
36  return Teuchos::rcp( new Epetra_MultiVector(::View,*U_,0,curRank_) );
37  }
38 
40  if (curRank_ == 0 || isInitialized_ == false) {
41  return Teuchos::null;
42  }
43  return Teuchos::rcp( new Epetra_MultiVector(::View,*V_,0,curRank_) );
44  }
45 
46  std::vector<double> IncSVDPOD::getSingularValues() const {
47  std::vector<double> ret(sigma_.begin(),sigma_.begin()+curRank_);
48  return ret;
49  }
50 
54 
55  using Teuchos::rcp;
56 
57  // Get the "Reduced Basis Method" sublist.
58  Teuchos::ParameterList rbmethod_params = params->sublist( "Reduced Basis Method" );
59 
60  // Get the maximum basis size
61  maxBasisSize_ = rbmethod_params.get<int>("Max Basis Size");
62  TEUCHOS_TEST_FOR_EXCEPTION(maxBasisSize_ < 2,std::invalid_argument,"\"Max Basis Size\" must be at least 2.");
63 
64  // Get a filter
65  filter_ = rbmethod_params.get<Teuchos::RCP<Filter<double> > >("Filter",Teuchos::null);
66  if (filter_ == Teuchos::null) {
67  int k = rbmethod_params.get("Rank",(int)5);
68  filter_ = rcp( new RangeFilter<double>(LARGEST,k,k) );
69  }
70 
71  // Get convergence tolerance
72  tol_ = rbmethod_params.get<double>("Convergence Tolerance",tol_);
73 
74  // Get debugging flag
75  debug_ = rbmethod_params.get<bool>("IncSVD Debug",debug_);
76 
77  // Get verbosity level
78  verbLevel_ = rbmethod_params.get<int>("IncSVD Verbosity Level",verbLevel_);
79 
80  // Get an Anasazi orthomanager
81  if (rbmethod_params.isType<
82  Teuchos::RCP< Anasazi::OrthoManager<double,Epetra_MultiVector> >
83  >("Ortho Manager")
84  )
85  {
86  ortho_ = rbmethod_params.get<
88  >("Ortho Manager");
89  TEUCHOS_TEST_FOR_EXCEPTION(ortho_ == Teuchos::null,std::invalid_argument,"User specified null ortho manager.");
90  }
91  else {
92  std::string omstr = rbmethod_params.get("Ortho Manager","DGKS");
93  if (omstr == "SVQB") {
94  ortho_ = rcp( new Anasazi::SVQBOrthoManager<double,Epetra_MultiVector,Epetra_Operator>() );
95  }
96  else { // if omstr == "DGKS"
97  ortho_ = rcp( new Anasazi::BasicOrthoManager<double,Epetra_MultiVector,Epetra_Operator>() );
98  }
99  }
100 
101  // Lmin,Lmax,Kstart
102  lmin_ = rbmethod_params.get("Min Update Size",1);
103  TEUCHOS_TEST_FOR_EXCEPTION(lmin_ < 1 || lmin_ >= maxBasisSize_,std::invalid_argument,
104  "Method requires 1 <= min update size < max basis size.");
105  lmax_ = rbmethod_params.get("Max Update Size",maxBasisSize_);
106  TEUCHOS_TEST_FOR_EXCEPTION(lmin_ > lmax_,std::invalid_argument,"Max update size must be >= min update size.");
107 
108  startRank_ = rbmethod_params.get("Start Rank",lmin_);
109  TEUCHOS_TEST_FOR_EXCEPTION(startRank_ < 1 || startRank_ > maxBasisSize_,std::invalid_argument,
110  "Starting rank must be in [1,maxBasisSize_)");
111  // MaxNumPasses
112  maxNumPasses_ = rbmethod_params.get("Maximum Number Passes",maxNumPasses_);
113  TEUCHOS_TEST_FOR_EXCEPTION(maxNumPasses_ != -1 && maxNumPasses_ <= 0, std::invalid_argument,
114  "Maximum number passes must be -1 or > 0.");
115  // Save the pointer to the snapshot matrix
116  TEUCHOS_TEST_FOR_EXCEPTION(ss == Teuchos::null,std::invalid_argument,"Input snapshot matrix cannot be null.");
117  A_ = ss;
118 
119  // MaxNumCols
120  maxNumCols_ = A_->NumVectors();
121  maxNumCols_ = rbmethod_params.get("Maximum Number Columns",maxNumCols_);
122  TEUCHOS_TEST_FOR_EXCEPTION(maxNumCols_ < A_->NumVectors(), std::invalid_argument,
123  "Maximum number of columns must be at least as many as in the initializing data set.");
124 
125  // V locally replicated or globally distributed
126  // this must be true for now
127  // Vlocal_ = rbmethod_params.get("V Local",Vlocal_);
128 
129  // Allocate space for the factorization
130  sigma_.reserve( maxBasisSize_ );
131  U_ = Teuchos::null;
132  V_ = Teuchos::null;
133  U_ = rcp( new Epetra_MultiVector(ss->Map(),maxBasisSize_,false) );
134  if (Vlocal_) {
135  Epetra_LocalMap lclmap(maxNumCols_,0,ss->Comm());
136  V_ = rcp( new Epetra_MultiVector(lclmap,maxBasisSize_,false) );
137  }
138  else {
139  Epetra_Map gblmap(maxNumCols_,0,ss->Comm());
140  V_ = rcp( new Epetra_MultiVector(gblmap,maxBasisSize_,false) );
141  }
142  B_ = rcp( new Epetra_SerialDenseMatrix(maxBasisSize_,maxBasisSize_) );
143  resNorms_.reserve(maxBasisSize_);
144 
145  // clear counters
146  numProc_ = 0;
147  curNumPasses_ = 0;
148 
149  // we are now initialized, albeit with null rank
150  isInitialized_ = true;
151  }
152 
154  // Reset the pointer for the snapshot matrix
155  // Note: We will not assume that it is non-null; user could be resetting our
156  // pointer in order to delete the original snapshot set
157  A_ = new_ss;
158  isInitialized_ = false;
159  }
160 
162 
163  //
164  // perform enough incremental updates to consume the entire snapshot set
165  Teuchos::TimeMonitor lcltimer(timerComp_);
166 
167  // check that we have a valid snapshot set: user may have cleared
168  // it using Reset()
169  TEUCHOS_TEST_FOR_EXCEPTION(A_ == Teuchos::null,std::logic_error,
170  "computeBasis() requires non-null snapshot set.");
171 
172  // check that we are initialized, i.e., data structures match the data set
173  TEUCHOS_TEST_FOR_EXCEPTION(isInitialized_==false,std::logic_error,
174  "RBGen::IncSVDPOD::computeBasis(): Solver must be initialized.");
175 
176  // reset state
177  curRank_ = 0;
178  numProc_ = 0;
179  curNumPasses_ = 0;
180 
181  // print out some info
182  const Epetra_Comm *comm = &A_->Comm();
183  while (curNumPasses_ < maxNumPasses_ || maxNumPasses_ == -1) {
184 
185  // make pass
186  makePass();
187 
188  // get residuals
189  std::vector<double> resnorms = this->getResNorms();
190 
191  // check residuals for convergence
192  int numConverged = 0;
193  for (int i=0; i<curRank_; i++) {
194  if (resnorms[i] <= tol_) {
195  numConverged++;
196  }
197  }
198  if (comm->MyPID() == 0 && verbLevel_ >= 1) {
199  std::cout << "| Num converged: " << numConverged << std::endl
200  << "| Resid norms: " << std::endl;
201  for (int i=0; i<curRank_; i++) {
202  std::cout << "| " << resnorms[i] << std::endl;
203  }
204  }
205  if (numConverged == curRank_) break;
206  }
207  }
208 
209 
210  void IncSVDPOD::incStep(int lup) {
211 
212  Epetra_LAPACK lapack;
213 
214  // perform gram-schmidt expansion
215  // expand() will update bases U_ and V_, factor B_, as well as counters curRank_ and numProc_
216  this->expand(lup);
217 
218  // compute the SVD of B
219  const int lwork = 5*curRank_;
220  int info;
221  Epetra_SerialDenseMatrix Uhat(::Copy,B_->A(),B_->LDA(),curRank_,curRank_), Vhat(curRank_,curRank_);
222  std::vector<double> Shat(curRank_), work(lwork);
223 
224  // Note: this actually stores Vhat^T (we remedy this below)
225  lapack.GESVD('O','A',curRank_,curRank_,Uhat.A(),Uhat.LDA(),&Shat[0],Uhat.A(),Uhat.LDA(),Vhat.A(),Vhat.LDA(),&work[0],&lwork,&info);
226  TEUCHOS_TEST_FOR_EXCEPTION(info!=0,std::logic_error,"RBGen::IncSVDPOD::incStep(): GESVD return info != 0");
227 
228  // use filter to determine new rank
229  std::vector<int> keepind = filter_->filter(Shat);
230  std::vector<int> truncind(curRank_-keepind.size());
231  {
232  std::vector<int> allind(curRank_);
233  for (int i=0; i<curRank_; i++) {
234  allind[i] = i;
235  }
236  set_difference(allind.begin(),allind.end(),keepind.begin(),keepind.end(),truncind.begin());
237 
238  // Vhat actually contains Vhat^T; correct this here
239  Epetra_SerialDenseMatrix Ucopy(Uhat), Vcopy(curRank_,curRank_);
240  std::vector<double> Scopy(Shat);
241  for (int j=0; j<curRank_; j++) {
242  for (int i=0; i<curRank_; i++) {
243  Vcopy(i,j) = Vhat(j,i);
244  }
245  }
246  // put the desired sigmas at the front of Uhat, Vhat
247  for (unsigned int j=0; j<keepind.size(); j++) {
248  std::copy(&Ucopy(0,keepind[j]),&Ucopy(curRank_,keepind[j]),&Uhat(0,j));
249  std::copy(&Vcopy(0,keepind[j]),&Vcopy(curRank_,keepind[j]),&Vhat(0,j));
250  Shat[j] = Scopy[keepind[j]];
251  }
252  for (unsigned int j=0; j<truncind.size(); j++) {
253  std::copy(&Ucopy(0,truncind[j]),&Ucopy(curRank_,truncind[j]),&Uhat(0,keepind.size()+j));
254  std::copy(&Vcopy(0,truncind[j]),&Vcopy(curRank_,truncind[j]),&Vhat(0,keepind.size()+j));
255  Shat[keepind.size()+j] = Scopy[truncind[j]];
256  }
257  }
258 
259  // shrink back down again
260  // shrink() will update bases U_ and V_, as well as singular values sigma_ and curRank_
261  this->shrink(truncind.size(),Shat,Uhat,Vhat);
262 
263  // print out some info
264  const Epetra_Comm *comm = &A_->Comm();
265  if (comm->MyPID() == 0 && verbLevel_ >= 2) {
266  std::cout
267  << "------------- IncSVDPOD::incStep() --------------" << std::endl
268  << "| Cols Processed: " << numProc_ << std::endl
269  << "| Current lup: " << lup << std::endl
270  << "| Current ldown: " << truncind.size() << std::endl
271  << "| Current rank: " << curRank_ << std::endl
272  << "| Current sigmas: " << std::endl;
273  for (int i=0; i<curRank_; i++) {
274  std::cout << "| " << sigma_[i] << std::endl;
275  }
276  }
277 
278  }
279 
280  const std::vector<double> & IncSVDPOD::getResNorms() {
281  return resNorms_;
282  }
283 
284 
285 } // end of RBGen namespace
286 
287 
void Reset(const Teuchos::RCP< Epetra_MultiVector > &new_ss)
Reset the snapshot set used to compute the reduced basis.
T & get(const std::string &name, T def_value)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
std::vector< double > getSingularValues() const
Return the singular values.
void GESVD(const char JOBU, const char JOBVT, const int M, const int N, float *A, const int LDA, float *S, float *U, const int LDU, float *VT, const int LDVT, float *WORK, const int *LWORK, int *INFO) const
Teuchos::RCP< const Epetra_MultiVector > getRightBasis() const
Return a basis for the right singular subspace.
Teuchos::RCP< const Epetra_MultiVector > getBasis() const
Return a basis for the left singular subspace.
virtual int MyPID() const =0
void computeBasis()
Computes bases for the left and (optionally) right singular subspaces, along with singular vaues...
double * A() const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void Initialize(const Teuchos::RCP< Teuchos::ParameterList > &params, const Teuchos::RCP< const Epetra_MultiVector > &init, const Teuchos::RCP< RBGen::FileIOHandler< Epetra_Operator > > &fileio=Teuchos::null)
Initialize the method with the given parameter list and snapshot set.
const std::vector< double > & getResNorms()
Return the scaled residual norms.
IncSVDPOD()
Default constructor.
bool isType(const std::string &name) const
Range-based filter.
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")