RBGen  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RBGen_ISVDMultiSDB.cpp
1 #include "RBGen_ISVDMultiSDB.h"
3 #include "Epetra_LAPACK.h"
4 #include "Epetra_BLAS.h"
5 #include "Epetra_Comm.h"
6 #include "Epetra_Map.h"
7 
8 namespace RBGen {
9 
11 
13  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,
14  "RBGen::ISVDMultiSDB::updateBasis(): this routine not supported.");
15  }
16  void ISVDMultiSDB::makePass() {
17  Epetra_LAPACK lapack;
18  Epetra_BLAS blas;
19 
20  bool firstPass = (curRank_ == 0);
21  const int numCols = A_->NumVectors();
22 
23  // compute W = I - Z T Z^T from current V_
24  int oldRank = 0;
25  double Rerr;
26  if (!firstPass) {
27  // we want W = [W1 W2] = [V G]
28  // second block == G is already achieved from previous pass
29  // we need to put V in the first block
30  {
31  Epetra_MultiVector W1(::View,*workW_,0,curRank_);
32  Epetra_MultiVector lclV(::View,*V_,0,curRank_);
33  W1 = lclV;
34  }
35  // get a pointer to [W1 W2]
36  Epetra_MultiVector W12(::View,*workW_,0,2*curRank_);
37 
38  //
39  // compute the Householder QR factorization of the current right basis
40  // [V G] = W*[R,0]'
41  //
42  int info, lwork = 2*curRank_;
43  std::vector<double> tau(2*curRank_), work(lwork);
44  lapack.GEQRF(numCols,2*curRank_,W12[0],numCols,&tau[0],&work[0],lwork,&info);
45  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
46  "RBGen::ISVDMultiSDB::makePass(): error calling GEQRF on current right basis while constructing next pass coefficients.");
47  if (debug_) {
48  // we just took the QR factorization of [V G]
49  // V is has orthonormal columns, so that the leading part of R should
50  // be diagonal, with unit elements (\pm 1)
51  // check it
52  Rerr = 0;
53  for (int j=0; j<curRank_; j++) {
54  for (int i=0; i<j; i++) {
55  Rerr += abs(W12[j][i]);
56  }
57  Rerr += abs(abs(W12[j][j]) - 1.0);
58  }
59  }
60  // compute the orthonormal basis ([W_1,W_2] = [\pm V,G])
61  // will overwrite R
62  lapack.ORGQR(numCols,2*curRank_,2*curRank_,W12[0],numCols,&tau[0],&work[0],lwork,&info);
63  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
64  "RBGen::ISVDMultiSDB::makePass(): error calling ORGQR to construct next pass coefficients.");
65  // compute A [W_1 W_2]
66  {
67  Epetra_MultiVector lclAW(::View,*workAW_,0,2*curRank_);
68  info = lclAW.Multiply('N','N',1.0,*A_,W12,0.0);
69  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
70  "RBGen::ISVDMultiSDB::makePass(): Error calling Epetra_MultiVector::Multiply() for A*W");
71  }
72  // save oldRank, which indicates the width of V
73  oldRank = curRank_;
74  curRank_ = 0;
75  }
76 
77  numProc_ = 0;
78  while ( ( firstPass && numProc_ < numCols) ||
79  (!firstPass && numProc_ < 2*oldRank) ) {
80  //
81  // determine lup
82  //
83  // want lup >= lmin
84  // lup <= lmax
85  // need lup <= numCols - numProc
86  // lup <= maxBasisSize - curRank
87  //
88  int lup;
89  if (curRank_ == 0) {
90  // first step uses startRank_
91  // this is not affected by lmin,lmax
92  lup = startRank_;
93  }
94  else {
95  // this value minimizes overall complexity, assuming fixed rank
96  lup = (int)(curRank_ / Teuchos::ScalarTraits<double>::squareroot(2.0));
97  // contrain to [lmin,lmax]
98  lup = (lup < lmin_ ? lmin_ : lup);
99  lup = (lup > lmax_ ? lmax_ : lup);
100  }
101  //
102  // now cap lup via maxBasisSize and the available data
103  // these caps apply to all lup, as a result of memory and data constraints
104  //
105  // available data:
106  // if firstPass, we are consuming A (numCols vectors)
107  // if !firstPass, we are consuming A*W (2*oldRank vectors)
108  if (firstPass) {
109  lup = (lup > numCols - numProc_ ? numCols - numProc_ : lup);
110  }
111  else {
112  lup = (lup > 2*oldRank - numProc_ ? 2*oldRank - numProc_ : lup);
113  }
114  // available memory
115  lup = (lup > maxBasisSize_ - curRank_ ? maxBasisSize_ - curRank_ : lup);
116 
117  // put new vectors in U
118  {
119  Epetra_MultiVector Unew(::View,*U_,curRank_,lup);
120  if (firstPass) {
121  // new vectors are just Aplus
122  const Epetra_MultiVector Aplus(::View,*A_,numProc_,lup);
123  Unew = Aplus;
124  }
125  else {
126  // new vectors are AW
127  const Epetra_MultiVector AWplus(::View,*workAW_,numProc_,lup);
128  Unew = AWplus;
129  }
130  }
131 
132  // perform the incremental step
133  incStep(lup);
134  }
135 
136  // compute W V = V - Z T Z^T V
137  // Z^T V is 2*oldRank x curRank
138  // T Z^T V is 2*oldRank x curRank
139  // we need T Z^T V in a local Epetra_MultiVector
140  if (!firstPass) {
141  Epetra_MultiVector lclWV(::View,*workWV_,0,curRank_);
142  {
143  // create (local) map for V(1:numProc,1:curRank)
144  Epetra_LocalMap lclmap(numProc_,0,A_->Comm());
145  const Epetra_MultiVector lclV(::View,lclmap,(*V_)[0],numCols,curRank_);
146  const Epetra_MultiVector W12(::View,*workW_,0,2*oldRank);
147  int info = lclWV.Multiply('N','N',1.0,W12,lclV,0.0);
148  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
149  "RBGen::ISVDMultiSDB::makePass(): error Multiply()ing Epetra_MultiVector for W*V.");
150  }
151  Epetra_MultiVector lclV(::View,*V_,0,curRank_);
152  lclV = lclWV;
153  }
154 
155  //
156  // compute the new residuals
157  // we know that A V = U S
158  // if, in addition, A^T U = V S, then have singular subspaces
159  // check residuals A^T U - V S, scaling the i-th column by sigma[i]
160  //
161  // store A^T U - V S into the second block of workW_
162  // we will need it on the next pass
163  //
164  {
165  Epetra_MultiVector W2(::View,*workW_,curRank_,curRank_);
166  Epetra_MultiVector Ulcl(::View,*U_,0,curRank_);
167  Epetra_MultiVector Vlcl(::View,*V_,0,curRank_);
168  // compute A^T U
169  int info = W2.Multiply('T','N',1.0,*A_,Ulcl,0.0);
170  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
171  "RBGen::IncSVD::computeBasis(): Error calling Epetra_MultiVector::Multiply for A^T U.");
172  Epetra_LocalMap Smap(curRank_,0,A_->Comm());
173  Epetra_MultiVector S(Smap,curRank_,true); // "true" inits to zero
174  for (int i=0; i<curRank_; i++) {
175  S[i][i] = sigma_[i];
176  }
177  // subtract V S from A^T U
178  info = W2.Multiply('N','N',-1.0,Vlcl,S,1.0);
179  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
180  "RBGen::IncSVD::computeBasis(): Error calling Epetra_MultiVector::Multiply for V S.");
181 
182  //
183  // compute residual norms
184  resNorms_.resize(curRank_);
185  W2.Norm2(&resNorms_[0]);
186  // scale by sigmas
187  for (int i=0; i<curRank_; i++) {
188  if (sigma_[i] != 0.0) {
189  resNorms_[i] /= sigma_[i];
190  }
191  }
192  }
193 
194  //
195  // debugging checks
196  std::vector<double> errnorms(curRank_);
197  if (debug_) {
198  int info;
199  // Check that A V = U Sigma
200  // get pointers to current U and V, create workspace for A V - U Sigma
201  Epetra_MultiVector work(U_->Map(),curRank_,false),
202  curU(::View,*U_,0,curRank_),
203  curV(::View,*V_,0,curRank_);
204  // create local MV for sigmas
205  Epetra_LocalMap lclmap(curRank_,0,A_->Comm());
206  Epetra_MultiVector curS(lclmap,curRank_,true);
207  for (int i=0; i<curRank_; i++) {
208  curS[i][i] = sigma_[i];
209  }
210  info = work.Multiply('N','N',1.0,curU,curS,0.0);
211  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
212  "RBGen::ISVDMultiSDB::makePass(): Error calling Epetra_MultiVector::Multiply() for debugging U S.");
213  info = work.Multiply('N','N',-1.0,*A_,curV,1.0);
214  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
215  "RBGen::ISVDMultiSDB::makePass(): Error calling Epetra_MultiVector::Multiply() for debugging U S - A V.");
216  work.Norm2(&errnorms[0]);
217  for (int i=0; i<curRank_; i++) {
218  if (sigma_[i] != 0.0) {
219  errnorms[i] /= sigma_[i];
220  }
221  }
222  }
223 
224  // update pass counter
225  curNumPasses_++;
226 
227  // print out some info
228  const Epetra_Comm *comm = &A_->Comm();
229  if (comm->MyPID() == 0 && verbLevel_ >= 1) {
230  std::cout
231  << "------------- ISVDMultiSDB::makePass() -----------" << std::endl
232  << "| Number of passes: " << curNumPasses_ << std::endl
233  << "| Current rank: " << curRank_ << std::endl
234  << "| Current sigmas: " << std::endl;
235  for (int i=0; i<curRank_; i++) {
236  std::cout << "| " << sigma_[i] << std::endl;
237  }
238  if (debug_) {
239  std::cout << "|DBG US-AV norms: " << std::endl;
240  for (int i=0; i<curRank_; i++) {
241  std::cout << "|DBG " << errnorms[i] << std::endl;
242  }
243  if (!firstPass) {
244  std::cout << "|DBG R-I norm: " << Rerr << std::endl;
245  }
246  }
247  }
248 
249  return;
250  }
251 
256  )
257  {
258  // workAW has room for A * [V G], where each has maxBasisSize vectors
259  // ergo, workAW has 2*maxBasisSize vectors
260  workAW_ = Teuchos::rcp( new Epetra_MultiVector(ss->Map(),2*maxBasisSize_,false) );
261 
262  // workZ = [V G],
263  // where V is the current right basis and G is the gradient A^T U - V S
264  // ergo, workZ has 2*maxBasisSize_ vectors
265  Epetra_LocalMap lclmap(ss->NumVectors(),0,ss->Comm());
266  workW_ = Teuchos::rcp( new Epetra_MultiVector(lclmap,2*maxBasisSize_,false) );
267  workWV_ = Teuchos::rcp( new Epetra_MultiVector(lclmap,maxBasisSize_,false) );
268  }
269 
270 } // end of RBGen namespace
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void GEQRF(const int M, const int N, float *A, const int LDA, float *TAU, float *WORK, const int lwork, int *INFO) const
virtual int MyPID() const =0
ISVDMultiSDB()
Default constructor.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void updateBasis(const Teuchos::RCP< Epetra_MultiVector > &update_ss)
Update the current basis by appending new snapshots.
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.
void ORGQR(const int M, const int N, const int K, float *A, const int LDA, float *TAU, float *WORK, const int LWORK, int *INFO) const