📄 orthog.cc
字号:
//// orthog.cc//// Copyright (C) 1996 Limit Point Systems, Inc.//// Author: Curtis Janssen <cljanss@ca.sandia.gov>// Maintainer: LPS//// This file is part of the SC Toolkit.//// The SC Toolkit is free software; you can redistribute it and/or modify// it under the terms of the GNU Library General Public License as published by// the Free Software Foundation; either version 2, or (at your option)// any later version.//// The SC Toolkit is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Library General Public License for more details.//// You should have received a copy of the GNU Library General Public License// along with the SC Toolkit; see the file COPYING.LIB. If not, write to// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.//// The U.S. Government is granted a limited license as per AL 91-7.//#ifdef __GNUC__#pragma implementation#endif#include <stdlib.h>#include <math.h>#include <iostream>#include <chemistry/qc/basis/orthog.h>#include <math/scmat/elemop.h>#include <math/scmat/blocked.h>using namespace std;using namespace sc;OverlapOrthog::OverlapOrthog( OrthogMethod method, const RefSymmSCMatrix &overlap, const Ref<SCMatrixKit> &result_kit, double lindep_tolerance, int debug){ reinit(method,overlap,result_kit,lindep_tolerance,debug);}voidOverlapOrthog::reinit( OrthogMethod method, const RefSymmSCMatrix &overlap, const Ref<SCMatrixKit> &result_kit, double lindep_tolerance, int debug){ orthog_method_ = method; overlap_ = overlap; lindep_tol_ = lindep_tolerance; debug_ = debug; dim_ = overlap_.dim(); result_kit_ = result_kit;}Ref<OverlapOrthog>OverlapOrthog::copy() const{ Ref<OverlapOrthog> orthog = new OverlapOrthog(orthog_method_, overlap_, result_kit_, lindep_tol_, debug_); orthog->orthog_trans_ = orthog_trans_.copy(); orthog->orthog_trans_inverse_ = orthog_trans_inverse_.copy(); orthog->orthog_dim_ = orthog_dim_; orthog->min_orthog_res_ = min_orthog_res_; orthog->max_orthog_res_ = max_orthog_res_; return orthog;}// computes intermediates needed to form orthogonalization matrices// and their inverses.voidOverlapOrthog::compute_overlap_eig(RefSCMatrix& overlap_eigvec, RefDiagSCMatrix& overlap_isqrt_eigval, RefDiagSCMatrix& overlap_sqrt_eigval){ // first calculate S RefSymmSCMatrix M = overlap_; // Diagonalize M to get m and U RefSCMatrix U(M.dim(), M.dim(), M.kit()); RefDiagSCMatrix m(M.dim(), M.kit()); M.diagonalize(m,U); M = 0; Ref<SCElementMaxAbs> maxabsop = new SCElementMaxAbs; m.element_op(maxabsop.pointer()); double maxabs = maxabsop->result(); double s_tol = lindep_tol_ * maxabs; double minabs = maxabs; BlockedDiagSCMatrix *bm = dynamic_cast<BlockedDiagSCMatrix*>(m.pointer()); bool blocked; int nblocks; if (bm == 0) { blocked = false; nblocks = 1; } else { blocked = true; nblocks = bm->nblocks(); } int i, j; double *pm_sqrt = new double[m->dim()->n()]; double *pm_isqrt = new double[m->dim()->n()]; int *pm_index = new int[m->dim()->n()]; int *nfunc = new int[nblocks]; int nfunctot = 0; int nlindep = 0; for (i=0; i<nblocks; i++) { nfunc[i] = 0; if (blocked && bm->block(i).null()) continue; int n; if (blocked) n = bm->block(i)->dim()->n(); else n = m->dim()->n(); double *pm = new double[n]; if (blocked) bm->block(i)->convert(pm); else m->convert(pm); for (j=0; j<n; j++) { if (pm[j] > s_tol) { if (pm[j] < minabs) { minabs = pm[j]; } pm_sqrt[nfunctot] = sqrt(pm[j]); pm_isqrt[nfunctot] = 1.0/pm_sqrt[nfunctot]; pm_index[nfunctot] = j; nfunc[i]++; nfunctot++; } else if (orthog_method_ == Symmetric) { pm_sqrt[nfunctot] = 0.0; pm_isqrt[nfunctot] = 0.0; pm_index[nfunctot] = j; nfunc[i]++; nfunctot++; nlindep++; } else { nlindep++; } } delete[] pm; } if (nlindep > 0 && orthog_method_ == Symmetric) { ExEnv::out0() << indent << "WARNING: " << nlindep << " basis function" << (dim_.n()-orthog_dim_.n()>1?"s":"") << " ignored in symmetric orthogonalization." << endl; } // make sure all nodes end up with exactly the same data MessageGrp::get_default_messagegrp()->bcast(nfunctot); MessageGrp::get_default_messagegrp()->bcast(nfunc, nblocks); MessageGrp::get_default_messagegrp()->bcast(pm_sqrt,nfunctot); MessageGrp::get_default_messagegrp()->bcast(pm_isqrt,nfunctot); MessageGrp::get_default_messagegrp()->bcast(pm_index,nfunctot); if (orthog_method_ == Symmetric) { orthog_dim_ = new SCDimension(m->dim()->blocks(), "ortho basis (symmetric)"); } else { orthog_dim_ = new SCDimension(nfunctot, nblocks, nfunc, "ortho basis (canonical)"); for (i=0; i<nblocks; i++) { orthog_dim_->blocks()->set_subdim(i, new SCDimension(nfunc[i])); } } overlap_eigvec = result_kit_->matrix(dim_, orthog_dim_); if (orthog_method_ == Symmetric) { overlap_eigvec.assign(U); } else { BlockedSCMatrix *bev = dynamic_cast<BlockedSCMatrix*>(overlap_eigvec.pointer()); BlockedSCMatrix *bU = dynamic_cast<BlockedSCMatrix*>(U.pointer()); int ifunc = 0; for (i=0; i<bev->nblocks(); i++) { if (bev->block(i).null()) continue; for (j=0; j<nfunc[i]; j++) { RefSCVector col = bU->block(i)->get_column(pm_index[ifunc]); bev->block(i)->assign_column(col,j); col = 0; ifunc++; } } } overlap_sqrt_eigval = result_kit_->diagmatrix(orthog_dim_); overlap_sqrt_eigval->assign(pm_sqrt); overlap_isqrt_eigval = result_kit_->diagmatrix(orthog_dim_); overlap_isqrt_eigval->assign(pm_isqrt); delete[] nfunc; delete[] pm_sqrt; delete[] pm_isqrt; delete[] pm_index; max_orthog_res_ = maxabs; min_orthog_res_ = minabs; if (debug_ > 1) { overlap_.print("S"); overlap_eigvec.print("S eigvec"); overlap_isqrt_eigval.print("s^(-1/2) eigval"); overlap_sqrt_eigval.print("s^(1/2) eigval"); }}voidOverlapOrthog::compute_symmetric_orthog(){ RefSCMatrix overlap_eigvec; RefDiagSCMatrix overlap_isqrt_eigval; RefDiagSCMatrix overlap_sqrt_eigval; compute_overlap_eig(overlap_eigvec, overlap_isqrt_eigval, overlap_sqrt_eigval); orthog_trans_ = overlap_eigvec * overlap_isqrt_eigval * overlap_eigvec.t(); orthog_trans_inverse_ = overlap_eigvec * overlap_sqrt_eigval * overlap_eigvec.t();}voidOverlapOrthog::compute_canonical_orthog(){ RefSCMatrix overlap_eigvec; RefDiagSCMatrix overlap_isqrt_eigval; RefDiagSCMatrix overlap_sqrt_eigval; compute_overlap_eig(overlap_eigvec, overlap_isqrt_eigval, overlap_sqrt_eigval); orthog_trans_ = overlap_isqrt_eigval * overlap_eigvec.t(); orthog_trans_inverse_ = overlap_eigvec * overlap_sqrt_eigval;}voidOverlapOrthog::compute_gs_orthog(){ // Orthogonalize each subblock of the overlap. max_orthog_res_ = 1.0; min_orthog_res_ = 1.0; BlockedSymmSCMatrix *S = dynamic_cast<BlockedSymmSCMatrix *>(overlap_.pointer()); int nblock = S->nblocks(); Ref<BlockedSCMatrixKit> kit = dynamic_cast<BlockedSCMatrixKit*>(S->kit().pointer()); Ref<SCMatrixKit> subkit = kit->subkit(); RefSCMatrix *blockorthogs = new RefSCMatrix[nblock]; int *nblockorthogs = new int[nblock]; int northog = 0; for (int i=0; i<nblock; i++) { RefSymmSCMatrix Sblock = S->block(i); if (Sblock.null()) { blockorthogs[i] = 0; nblockorthogs[i] = 0; continue; } RefSCDimension dim = Sblock->dim(); RefSCMatrix blockorthog(dim,dim,subkit); blockorthog->unit(); double res; int nblockorthog = blockorthog->schmidt_orthog_tol(Sblock, lindep_tol_, &res); if (res < min_orthog_res_) min_orthog_res_ = res; blockorthogs[i] = blockorthog; nblockorthogs[i] = nblockorthog; northog += nblockorthog; } // Construct the orthog basis SCDimension object. Ref<SCBlockInfo> blockinfo = new SCBlockInfo(northog, nblock, nblockorthogs); for (int i=0; i<nblock; i++) { blockinfo->set_subdim(i, new SCDimension(nblockorthogs[i])); } orthog_dim_ = new SCDimension(blockinfo, "ortho (Gram-Schmidt)"); // Replace each blockorthog by a matrix with only linear independent columns for (int i=0; i<nblock; i++) { if (nblockorthogs[i] == 0) continue; RefSCMatrix old_blockorthog = blockorthogs[i]; blockorthogs[i] = subkit->matrix(dim_->blocks()->subdim(i), orthog_dim_->blocks()->subdim(i)); blockorthogs[i].assign_subblock(old_blockorthog, 0, dim_->blocks()->subdim(i).n()-1, 0, orthog_dim_->blocks()->subdim(i).n()-1); } // Compute the inverse of each orthogonalization block. RefSCMatrix *inverse_blockorthogs = new RefSCMatrix[nblock]; for (int i=0; i<nblock; i++) { if (nblockorthogs[i] == 0) { inverse_blockorthogs[i] = 0; } else { inverse_blockorthogs[i] = blockorthogs[i].gi(); } } // Construct the complete transformation matrices orthog_trans_ = result_kit_->matrix(dim_, orthog_dim_); orthog_trans_inverse_ = result_kit_->matrix(orthog_dim_, dim_); orthog_trans_.assign(0.0); orthog_trans_inverse_.assign(0.0); BlockedSCMatrix *X = dynamic_cast<BlockedSCMatrix*>(orthog_trans_.pointer()); BlockedSCMatrix *Xi = dynamic_cast<BlockedSCMatrix*>(orthog_trans_inverse_.pointer()); for (int i=0; i<nblock; i++) { if (nblockorthogs[i] == 0) continue; int nrow = blockorthogs[i].rowdim().n(); int ncol = blockorthogs[i].coldim().n(); X->block(i).assign_subblock(blockorthogs[i], 0, nrow-1, 0, ncol-1, 0, 0); Xi->block(i).assign_subblock(inverse_blockorthogs[i], 0, ncol-1, 0, nrow-1, 0, 0); } orthog_trans_ = orthog_trans_.t(); orthog_trans_inverse_ = orthog_trans_inverse_.t(); delete[] blockorthogs; delete[] inverse_blockorthogs; delete[] nblockorthogs;}voidOverlapOrthog::compute_orthog_trans(){ switch(orthog_method_) { case GramSchmidt: ExEnv::out0() << indent << "Using Gram-Schmidt orthogonalization." << endl; compute_gs_orthog(); break; case Symmetric: compute_symmetric_orthog(); ExEnv::out0() << indent << "Using symmetric orthogonalization." << endl; break; case Canonical: compute_canonical_orthog(); ExEnv::out0() << indent << "Using canonical orthogonalization." << endl; break; default: ExEnv::outn() << "OverlapOrthog::compute_orthog_trans(): bad orthog method" << endl; abort(); } ExEnv::out0() << indent << "n(basis): "; for (int i=0; i<dim_->blocks()->nblock(); i++) { ExEnv::out0() << scprintf(" %5d", dim_->blocks()->size(i)); } ExEnv::out0() << endl; if (dim_.n() != orthog_dim_.n()) { ExEnv::out0() << indent << "n(orthog basis): "; for (int i=0; i<orthog_dim_->blocks()->nblock(); i++) { ExEnv::out0() << scprintf(" %5d", orthog_dim_->blocks()->size(i)); } ExEnv::out0() << endl; ExEnv::out0() << indent << "WARNING: " << dim_.n() - orthog_dim_.n() << " basis function" << (dim_.n()-orthog_dim_.n()>1?"s":"") << " discarded." << endl; } ExEnv::out0() << indent << "Maximum orthogonalization residual = " << max_orthog_res_ << endl << indent << "Minimum orthogonalization residual = " << min_orthog_res_ << endl; if (debug_ > 0) { dim_.print(); orthog_dim_.print(); if (debug_ > 1) { orthog_trans_.print("basis to orthog basis"); orthog_trans_inverse_.print("basos to orthog basis inverse"); (orthog_trans_*overlap_ *orthog_trans_.t()).print("X*S*X'",ExEnv::out0(),14); (orthog_trans_inverse_.t()*overlap_.gi() *orthog_trans_inverse_).print("X'^(-1)*S^(-1)*X^(-1)", ExEnv::out0(),14); (orthog_trans_ *orthog_trans_inverse_).print("X*X^(-1)",ExEnv::out0(),14); } }}// returns the orthogonalization matrixRefSCMatrixOverlapOrthog::basis_to_orthog_basis(){ if (orthog_trans_.null()) { compute_orthog_trans(); } return orthog_trans_;}RefSCMatrixOverlapOrthog::basis_to_orthog_basis_inverse(){ if (orthog_trans_inverse_.null()) { compute_orthog_trans(); } return orthog_trans_inverse_;}RefSCDimensionOverlapOrthog::dim(){ return dim_;}RefSCDimensionOverlapOrthog::orthog_dim(){ if (orthog_dim_.null()) compute_orthog_trans(); return orthog_dim_;}/////////////////////////////////////////////////////////////////////////////// Local Variables:// mode: c++// c-file-style: "CLJ-CONDENSED"// End:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -