double BasisAngle( const Epetra_MultiVector& S, const Epetra_MultiVector& T ) { // // Computes the largest acute angle between the two orthogonal basis // if (S.NumVectors() != T.NumVectors()) { return acos( 0.0 ); } else { int lwork, info = 0; int m = S.NumVectors(), n = T.NumVectors(); int num_vecs = ( m < n ? m : n ); double U[ 1 ], Vt[ 1 ]; lwork = 3*m*n; std::vector<double> work( lwork ); std::vector<double> theta( num_vecs ); Epetra_LAPACK lapack; Epetra_LocalMap localMap( S.NumVectors(), 0, S.Map().Comm() ); Epetra_MultiVector Pvec( localMap, T.NumVectors() ); info = Pvec.Multiply( 'T', 'N', 1.0, S, T, 0.0 ); // // Perform SVD on S^T*T // lapack.GESVD( 'N', 'N', num_vecs, num_vecs, Pvec.Values(), Pvec.Stride(), &theta[0], U, 1, Vt, 1, &work[0], &lwork, &info ); assert( info == 0 ); return (acos( theta[num_vecs-1] ) ); } // // Default return statement, should never be executed. // return acos( 0.0 ); }
void IncSVDPOD::incStep(int lup) { Epetra_LAPACK lapack; // perform gram-schmidt expansion // expand() will update bases U_ and V_, factor B_, as well as counters curRank_ and numProc_ this->expand(lup); // compute the SVD of B const int lwork = 5*curRank_; int info; Epetra_SerialDenseMatrix Uhat(::Copy,B_->A(),B_->LDA(),curRank_,curRank_), Vhat(curRank_,curRank_); std::vector<double> Shat(curRank_), work(lwork); // Note: this actually stores Vhat^T (we remedy this below) lapack.GESVD('O','A',curRank_,curRank_,Uhat.A(),Uhat.LDA(),&Shat[0],Uhat.A(),Uhat.LDA(),Vhat.A(),Vhat.LDA(),&work[0],&lwork,&info); TEUCHOS_TEST_FOR_EXCEPTION(info!=0,std::logic_error,"RBGen::IncSVDPOD::incStep(): GESVD return info != 0"); // use filter to determine new rank std::vector<int> keepind = filter_->filter(Shat); std::vector<int> truncind(curRank_-keepind.size()); { std::vector<int> allind(curRank_); for (int i=0; i<curRank_; i++) { allind[i] = i; } set_difference(allind.begin(),allind.end(),keepind.begin(),keepind.end(),truncind.begin()); // Vhat actually contains Vhat^T; correct this here Epetra_SerialDenseMatrix Ucopy(Uhat), Vcopy(curRank_,curRank_); std::vector<double> Scopy(Shat); for (int j=0; j<curRank_; j++) { for (int i=0; i<curRank_; i++) { Vcopy(i,j) = Vhat(j,i); } } // put the desired sigmas at the front of Uhat, Vhat for (unsigned int j=0; j<keepind.size(); j++) { std::copy(&Ucopy(0,keepind[j]),&Ucopy(curRank_,keepind[j]),&Uhat(0,j)); std::copy(&Vcopy(0,keepind[j]),&Vcopy(curRank_,keepind[j]),&Vhat(0,j)); Shat[j] = Scopy[keepind[j]]; } for (unsigned int j=0; j<truncind.size(); j++) { std::copy(&Ucopy(0,truncind[j]),&Ucopy(curRank_,truncind[j]),&Uhat(0,keepind.size()+j)); std::copy(&Vcopy(0,truncind[j]),&Vcopy(curRank_,truncind[j]),&Vhat(0,keepind.size()+j)); Shat[keepind.size()+j] = Scopy[truncind[j]]; } } // shrink back down again // shrink() will update bases U_ and V_, as well as singular values sigma_ and curRank_ this->shrink(truncind.size(),Shat,Uhat,Vhat); // print out some info const Epetra_Comm *comm = &A_->Comm(); if (comm->MyPID() == 0 && verbLevel_ >= 2) { std::cout << "------------- IncSVDPOD::incStep() --------------" << std::endl << "| Cols Processed: " << numProc_ << std::endl << "| Current lup: " << lup << std::endl << "| Current ldown: " << truncind.size() << std::endl << "| Current rank: " << curRank_ << std::endl << "| Current sigmas: " << std::endl; for (int i=0; i<curRank_; i++) { std::cout << "| " << sigma_[i] << std::endl; } } }