RBGen  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RBGen_ISVDMultiSDA.cpp
1 #include "RBGen_ISVDMultiSDA.h"
3 #include "Epetra_LAPACK.h"
4 #include "Epetra_BLAS.h"
5 #include "Epetra_Comm.h"
6 
7 namespace RBGen {
8 
10 
12  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,
13  "RBGen::ISVDMultiSDA::updateBasis(): this routine not supported.");
14  }
15  void ISVDMultiSDA::makePass() {
16  Epetra_LAPACK lapack;
17  Epetra_BLAS blas;
18 
19  bool firstPass = (curRank_ == 0);
20  const int numCols = A_->NumVectors();
21  TEUCHOS_TEST_FOR_EXCEPTION( !firstPass && (numProc_ != numCols), std::logic_error,
22  "RBGen::ISVDMultiSDA::makePass(): after first pass, numProc should be numCols");
23 
24  // compute W = I - Z T Z^T from current V_
26  double *Z_A, *AZT_A;
27  int Z_LDA, AZT_LDA;
28  int oldRank = 0;
29  double Rerr;
30  if (!firstPass) {
31  // we want Z = [Z1 Z2] = [V G]
32  // second block == G is already achieved from previous pass
33  // we need to put V in the first block
34  {
35  Epetra_MultiVector Z1(::View,*workZ_,0,curRank_);
36  Epetra_MultiVector lclV(::View,*V_,0,curRank_);
37  Z1 = lclV;
38  }
39  // get a pointer to [Z1 Z2]
40  lclZ = Teuchos::rcp( new Epetra_MultiVector(::View,*workZ_,0,2*curRank_) );
41 
42  //
43  // compute the Householder QR factorization of the current right basis
44  // [V G] = W*[R,0]'
45  //
46  int info, lwork = 2*curRank_;
47  std::vector<double> tau(2*curRank_), work(lwork);
48  info = lclZ->ExtractView(&Z_A,&Z_LDA);
49  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
50  "RBGen::ISVDMultiSDA::makePass(): error calling ExtractView on Epetra_MultiVector Z.");
51  lapack.GEQRF(numCols,2*curRank_,Z_A,Z_LDA,&tau[0],&work[0],lwork,&info);
52  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
53  "RBGen::ISVDMultiSDA::makePass(): error calling GEQRF on current right basis while constructing next pass coefficients.");
54  if (debug_) {
55  // we just took the QR factorization of [V G]
56  // V is has orthonormal columns, so that the leading part of R should
57  // be diagonal, with unit elements (\pm 1)
58  // check it
59  Rerr = 0;
60  for (int j=0; j<curRank_; j++) {
61  for (int i=0; i<j; i++) {
62  Rerr += abs(Z_A[j*Z_LDA+i]);
63  }
64  Rerr += abs(abs(Z_A[j*Z_LDA+j]) - 1.0);
65  }
66  }
67  // compute the block representation
68  // W = I - Z T Z^T
69  lapack.LARFT('F','C',numCols,2*curRank_,Z_A,Z_LDA,&tau[0],workT_->A(),workT_->LDA());
70  // LARFT left upper tri block of Z unchanged
71  // note: it should currently contain R factor of [V G]
72  //
73  // we need to set it to:
74  // [1 0 0 ... 0]
75  // [ 1 0 ... 0]
76  // [ .... ]
77  // [ 1]
78  //
79  // see documentation for LARFT
80  for (int j=0; j<2*curRank_; j++) {
81  Z_A[j*Z_LDA+j] = 1.0;
82  for (int i=0; i<j; i++) {
83  Z_A[j*Z_LDA+i] = 0.0;
84  }
85  }
86  // compute part of A W: A Z T
87  // put this in workAZT_
88  // first, A Z (this consumes a pass through A)
89  lclAZT = Teuchos::rcp( new Epetra_MultiVector(::View,*workAZT_,0,2*curRank_) );
90  info = lclAZT->Multiply('N','N',1.0,*A_,*lclZ,0.0);
91  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
92  "RBGen::ISVDMultiSDA::makePass(): Error calling Epetra_MultiVector::Multiply() for A*Z");
93  // second, (A Z) T (in situ, as T is upper triangular)
94  info = lclAZT->ExtractView(&AZT_A,&AZT_LDA);
95  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
96  "RBGen::ISVDMultiSDA::makePass(): error calling ExtractView on Epetra_MultiVector AZ.");
97  blas.TRMM('R','U','N','N',numCols,2*curRank_,1.0,workT_->A(),workT_->LDA(),AZT_A,AZT_LDA);
98  // save oldRank: it tells us the width of Z
99  oldRank = curRank_;
100 
101  curRank_ = 0;
102  numProc_ = 0;
103  }
104  else { // firstPass == true
105  curRank_ = 0;
106  numProc_ = 0;
107  }
108 
109  while (numProc_ < numCols) {
110  //
111  // determine lup
112  //
113  // want lup >= lmin
114  // lup <= lmax
115  // need lup <= numCols - numProc
116  // lup <= maxBasisSize - curRank
117  //
118  int lup;
119  if (curRank_ == 0) {
120  // first step uses startRank_
121  // this is not affected by lmin,lmax
122  lup = startRank_;
123  }
124  else {
125  // this value minimizes overall complexity, assuming fixed rank
126  lup = (int)(curRank_ / Teuchos::ScalarTraits<double>::squareroot(2.0));
127  // contrain to [lmin,lmax]
128  lup = (lup < lmin_ ? lmin_ : lup);
129  lup = (lup > lmax_ ? lmax_ : lup);
130  }
131  //
132  // now cap lup via maxBasisSize and the available data
133  // these caps apply to all lup, as a result of memory and data constraints
134  //
135  // available data
136  lup = (lup > numCols - numProc_ ? numCols - numProc_ : lup);
137  // available memory
138  lup = (lup > maxBasisSize_ - curRank_ ? maxBasisSize_ - curRank_ : lup);
139 
140  // get view of new vectors
141  {
142  const Epetra_MultiVector Aplus(::View,*A_,numProc_,lup);
143  Epetra_MultiVector Unew(::View,*U_,curRank_,lup);
144  // put them in U
145  if (firstPass) {
146  // new vectors are just Aplus
147  Unew = Aplus;
148  }
149  else {
150  // new vectors are Aplus - (A Z T) Z_i^T
151  // specifically, Aplus - (A Z T) Z(numProc:numProc+lup-1,1:2*oldRank)^T
152  Epetra_LocalMap lclmap(lup,0,A_->Comm());
153  Epetra_MultiVector Zi(::View,lclmap,&Z_A[numProc_],Z_LDA,2*oldRank);
154  Unew = Aplus;
155  int info = Unew.Multiply('N','T',-1.0,*lclAZT,Zi,1.0);
156  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
157  "RBGen::ISVDMultiSDA::makePass(): Error calling Epetra_MultiVector::Multiply() for A*Wi");
158  }
159  }
160 
161  // perform the incremental step
162  incStep(lup);
163  }
164 
165  // compute W V = V - Z T Z^T V
166  // Z^T V is 2*oldRank x curRank
167  // T Z^T V is 2*oldRank x curRank
168  // we need T Z^T V in a local Epetra_MultiVector
169  if (!firstPass) {
170  double *TZTV_A;
171  int TZTV_LDA;
172  int info;
173  // get pointer to current V
174  Epetra_MultiVector lclV(::View,*V_,0,curRank_);
175  // create (local) multivector for T Z^T V
176  Epetra_LocalMap lclmap(2*oldRank,0,A_->Comm());
177  Epetra_MultiVector TZTV(lclmap,curRank_,false);
178  // multiply Z^T V
179  info = TZTV.Multiply('T','N',1.0,*lclZ,lclV,0.0);
180  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
181  "RBGen::ISVDMultiSDA::makePass(): Error calling Epetra_MultiVector::Multiply() for Z^T V.");
182  // get pointer to data in Z^T V
183  info = TZTV.ExtractView(&TZTV_A,&TZTV_LDA);
184  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
185  "RBGen::ISVDMultiSDA::makePass(): error calling ExtractView on Epetra_MultiVector TZTV.");
186  // multiply T (Z^T V)
187  blas.TRMM('L','U','N','N',2*oldRank,curRank_,1.0,workT_->A(),workT_->LDA(),TZTV_A,TZTV_LDA);
188  // multiply V - Z (T Z^T V)
189  info = lclV.Multiply('N','N',-1.0,*lclZ,TZTV,1.0);
190  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
191  "RBGen::ISVDMultiSDA::makePass(): Error calling Epetra_MultiVector::Multiply() for W V.");
192  }
193 
194  //
195  // compute the new residuals
196  // we know that A V = U S
197  // if, in addition, A^T U = V S, then have singular subspaces
198  // check residuals A^T U - V S, scaling the i-th column by sigma[i]
199  //
200  // store A^T U - V S into the second block of workZ_
201  // we will need it on the next pass
202  //
203  {
204  Epetra_MultiVector Z2(::View,*workZ_,curRank_,curRank_);
205  Epetra_MultiVector Ulcl(::View,*U_,0,curRank_);
206  Epetra_MultiVector Vlcl(::View,*V_,0,curRank_);
207  // compute A^T U
208  int info = Z2.Multiply('T','N',1.0,*A_,Ulcl,0.0);
209  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
210  "RBGen::IncSVD::computeBasis(): Error calling Epetra_MultiVector::Multiply for A^T U.");
211  Epetra_LocalMap Smap(curRank_,0,A_->Comm());
212  Epetra_MultiVector S(Smap,curRank_,true); // "true" inits to zero
213  for (int i=0; i<curRank_; i++) {
214  S[i][i] = sigma_[i];
215  }
216  // subtract V S from A^T U
217  info = Z2.Multiply('N','N',-1.0,Vlcl,S,1.0);
218  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
219  "RBGen::IncSVD::computeBasis(): Error calling Epetra_MultiVector::Multiply for V S.");
220 
221  //
222  // compute residual norms
223  resNorms_.resize(curRank_);
224  Z2.Norm2(&resNorms_[0]);
225  // scale by sigmas
226  for (int i=0; i<curRank_; i++) {
227  if (sigma_[i] != 0.0) {
228  resNorms_[i] /= sigma_[i];
229  }
230  }
231  }
232 
233  //
234  // debugging checks
235  std::vector<double> errnorms(curRank_);
236  if (debug_) {
237  int info;
238  // Check that A V = U Sigma
239  // get pointers to current U and V, create workspace for A V - U Sigma
240  Epetra_MultiVector work(U_->Map(),curRank_,false),
241  curU(::View,*U_,0,curRank_),
242  curV(::View,*V_,0,curRank_);
243  // create local MV for sigmas
244  Epetra_LocalMap lclmap(curRank_,0,A_->Comm());
245  Epetra_MultiVector curS(lclmap,curRank_,true);
246  for (int i=0; i<curRank_; i++) {
247  curS[i][i] = sigma_[i];
248  }
249  info = work.Multiply('N','N',1.0,curU,curS,0.0);
250  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
251  "RBGen::ISVDMultiSDA::makePass(): Error calling Epetra_MultiVector::Multiply() for debugging U S.");
252  info = work.Multiply('N','N',-1.0,*A_,curV,1.0);
253  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
254  "RBGen::ISVDMultiSDA::makePass(): Error calling Epetra_MultiVector::Multiply() for debugging U S - A V.");
255  work.Norm2(&errnorms[0]);
256  for (int i=0; i<curRank_; i++) {
257  if (sigma_[i] != 0.0) {
258  errnorms[i] /= sigma_[i];
259  }
260  }
261  }
262 
263  // update pass counter
264  curNumPasses_++;
265 
266  // print out some info
267  const Epetra_Comm *comm = &A_->Comm();
268  if (comm->MyPID() == 0 && verbLevel_ >= 1) {
269  std::cout
270  << "------------- ISVDMultiSDA::makePass() -----------" << std::endl
271  << "| Number of passes: " << curNumPasses_ << std::endl
272  << "| Current rank: " << curRank_ << std::endl
273  << "| Current sigmas: " << std::endl;
274  for (int i=0; i<curRank_; i++) {
275  std::cout << "| " << sigma_[i] << std::endl;
276  }
277  if (debug_) {
278  std::cout << "|DBG US-AV norms: " << std::endl;
279  for (int i=0; i<curRank_; i++) {
280  std::cout << "|DBG " << errnorms[i] << std::endl;
281  }
282  if (!firstPass) {
283  std::cout << "|DBG R-I norm: " << Rerr << std::endl;
284  }
285  }
286  }
287 
288  return;
289  }
290 
295  )
296  {
297  // workAZT has room for A * Z * T, where Z * T has 2*maxBasisSize vectors
298  // ergo, workAZT has 2*maxBasisSize vectors
299  workAZT_ = Teuchos::rcp( new Epetra_MultiVector(ss->Map(),2*maxBasisSize_,false) );
300 
301  // workZ = [V G],
302  // where V is the current right basis and G is the gradient A^T U - V S
303  // ergo, workZ has 2*maxBasisSize_ vectors
304  Epetra_LocalMap lclmap(ss->NumVectors(),0,ss->Comm());
305  workZ_ = Teuchos::rcp( new Epetra_MultiVector(lclmap,2*maxBasisSize_,false) );
306 
307  // workT contains the T factor:
308  // W R = [V G]
309  // W = I - V T V^T
310  // Ergo, workT is 2*maxBasisSize by 2*maxBasisSize
311  workT_ = Teuchos::rcp( new Epetra_SerialDenseMatrix(2*maxBasisSize_,2*maxBasisSize_) );
312  }
313 
314 } // end of RBGen namespace
void TRMM(const char SIDE, const char UPLO, const char TRANSA, const char DIAG, const int M, const int N, const float ALPHA, const float *A, const int LDA, float *B, const int LDB) const
#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
void updateBasis(const Teuchos::RCP< Epetra_MultiVector > &update_ss)
Update the current basis by appending new snapshots.
virtual int MyPID() const =0
double * A() const
ISVDMultiSDA()
Default constructor.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void LARFT(const char DIRECT, const char STOREV, const int N, const int K, double *V, const int LDV, double *TAU, double *T, const int LDT) const
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.