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