eigenvalue.cpp

来自「FreeFem++可以生成高质量的有限元网格。可以用于流体力学」· C++ 代码 · 共 803 行 · 第 1/2 页

CPP
803
字号
// -*- Mode : c++ -*-//// SUMMARY  :      // USAGE    :        // ORG      : // AUTHOR   : Frederic Hecht// E-MAIL   : hecht@ann.jussieu.fr///*  This file is part of Freefem++  Freefem++ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.  Freefem++  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 Lesser General Public License for more details.  You should have received a copy of the GNU Lesser General Public License along with Freefem++; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include <fstream>#include <iostream>#include <cassert>#include <algorithm>#include <complex>using namespace std;#include "error.hpp"#include "arpackff.hpp"#include "AFunction.hpp"#include "rgraph.hpp"#include "RNM.hpp"#include "MatriceCreuse_tpl.hpp"#include "Mesh3dn.hpp"#include "MeshPoint.hpp"#include "lgfem.hpp"#include "lgmesh3.hpp"#include "lgsolver.hpp"#include "problem.hpp"extern Block *currentblock;typedef double R;static  bool dddd=false;template<class K>void Show(int ido,KN_<K> w,const char *cmm){  cout << cmm << ido << " max " << w.max() << " min  " << w.min() << " sum  ="        << w.sum()  << endl;}template<class K,class Mat>void  DoIdoAction(int ido,int mode,KN_<K> &xx,KN_<K> &yy,KN_<K> &zz,KN_<K> &work,Mat &OP1,Mat &B){  if(mode>2) // inverse mode     switch (ido) {    case -1: //y <--- OP*x = inv[A-SIGMA*M]*M*x         if(dddd) Show(ido,xx,"  <- (xx) ");      OP1.Solve(yy,work=B*xx);      if(dddd) Show(ido,yy,"  -> (yy) ");      break;    case  1://  y <-- OP*x = inv[A-sigma*M]*z      if(dddd) Show(ido,zz,"  <- (zz) ");      OP1.Solve(yy,zz);      if(dddd) Show(ido,yy,"  -> (yy) ");      break;    case  2: //  y <--- M*x       if(dddd) Show(ido,xx,"  <- (xx) ");      yy = B*xx;      if(dddd) Show(ido,yy,"  -> (yy) ");      break;    default :      ffassert(0);    }  else // direct mode     switch (ido)      {      case -1: // y <--- OP*x = inv[M]*A*x      case  1: 	if(mode== 1)  // M = Id	  yy=OP1*xx;	else	  B.Solve(yy,work=OP1*xx);	break;      case 2: //  y <--- M*x. // not use mode = 1	yy = B*xx;	break;      default :	ffassert(0);        }}class EigenValue : public OneOperator{ public:  typedef R K;  typedef KN<K> Kn;  typedef KN_<K> Kn_;  const int cas;  class E_EV: public E_F0mps { public:      const int cas;        static basicAC_F0::name_and_type name_param[] ;    static const int n_name_param =12;    Expression nargs[n_name_param];    Expression expOP1,expB;    template<class T>    T arg(int i,Stack stack,const T & a) const{ return nargs[i] ? GetAny<T>( (*nargs[i])(stack) ): a;}    E_EV(const basicAC_F0 & args,int cc) :      cas(cc)    {      // OP1 = (A-sigma*B)              //                int nbj= args.size()-1;      args.SetNameParam(n_name_param,name_param,nargs);      expOP1=to< Matrice_Creuse<K> *>(args[0]);      expB=to< Matrice_Creuse<K> *>(args[1]);          }        AnyType operator()(Stack stack)  const;    operator aType () const { return atype<long>();}               };    E_F0 * code(const basicAC_F0 & args) const {    return new E_EV(args,cas);}    EigenValue(int c) :       OneOperator(atype<long>(),		atype<Matrice_Creuse<K> *>(),		atype<Matrice_Creuse<K> *>()),    cas(c){}    };class EigenValueC : public OneOperator{ public:  typedef Complex K;  typedef double R;  typedef KN<K> Kn;  typedef KN_<K> Kn_;  const int cas;  class E_EV: public E_F0mps { public:      const int cas;        static basicAC_F0::name_and_type name_param[] ;    static const int n_name_param =10;    Expression nargs[n_name_param];    Expression expOP1,expB;    template<class T>    T arg(int i,Stack stack,const T & a) const{ return nargs[i] ? GetAny<T>( (*nargs[i])(stack) ): a;}    E_EV(const basicAC_F0 & args,int cc) :      cas(cc)    {      // OP1 = (A-sigma*B)              //                int nbj= args.size()-1;      args.SetNameParam(n_name_param,name_param,nargs);      expOP1=to< Matrice_Creuse<K> *>(args[0]);      expB=to< Matrice_Creuse<K> *>(args[1]);          }        AnyType operator()(Stack stack)  const;    operator aType () const { return atype<long>();}               };    E_F0 * code(const basicAC_F0 & args) const {    return new E_EV(args,cas);}    EigenValueC(int c) :       OneOperator(atype<long>(),		atype<Matrice_Creuse<K> *>(),		atype<Matrice_Creuse<K> *>()),    cas(c){}  };basicAC_F0::name_and_type  EigenValue::E_EV::name_param[]= {  {   "tol", &typeid(double)  },  {   "nev",&typeid(long) },  {   "sym",&typeid(bool)},  {   "sigma",&typeid(double)},  {   "value",&typeid(KN<double> *)},  {   "vector",&typeid(pferarray) },   {   "ncv",&typeid(long) }, // the number of Arnoldi vectors generated   {   "maxit",&typeid(long)}, // the maximum number of Arnoldi iterations   {   "ivalue",&typeid(KN<double> *)},  {   "rawvector",&typeid(KNM<double> *) },  {   "resid",&typeid(KN<double> *) },  {   "mode",&typeid(long) } // 12 ieme    };basicAC_F0::name_and_type  EigenValueC::E_EV::name_param[]= {  {  "tol", &typeid(double)  },  {  "nev",&typeid(long) },  {  "sigma",&typeid(K)},  {  "value",&typeid(KN<Complex> *)},  {  "vector",&typeid(pfecarray) },   {  "ncv",&typeid(long) }, // the number of Arnoldi vectors generated   {  "maxit",&typeid(long)}, // the maximum number of Arnoldi iterations   {  "rawvector",&typeid(KNM<Complex> *) },   {  "resid",&typeid(KN<Complex> *)},  {   "mode",&typeid(long) } // 10 ieme     };AnyType EigenValue::E_EV::operator()(Stack stack)  const {  dddd = (verbosity>=200);  double tol=1e-6;  long nconv=0;   long nbev=1;  bool sym=false;  long ncv =0;  // the number of Arnoldi vectors generated   long maxit=0;  // the maximum number of Arnoldi iterations   double sigma=0;  int mode = 3; //    KN<double> * evalue=0;  KN<double> * evaluei=0;  KN<double> * resid=0;  KNM<double> * rawvector=0;  double ws,vs;           // for debugging FH ++++++++++  pferarray  evector2;  pferbasearray   evector=0;  tol=arg<double>(0,stack,0);  nbev=arg<long>(1,stack,10);  sym=arg<bool>(2,stack,false);  sigma=arg<double>(3,stack,0.0);  evalue=arg<KN<double> *>(4,stack,0);  evector2 =arg<pferarray>(5,stack,make_pair<pferbasearray,int>(0,0));   ncv= arg<long>(6,stack,0);  maxit= arg<long>(7,stack,0);  evaluei=arg<KN<double> *>(8,stack,0);  rawvector=arg<KNM<double> *>(9,stack,0);  resid=arg<KN<double> *>(10,stack,0);  mode = arg<long>(11,stack,3);      evector=evector2.first;  Matrice_Creuse<K> *pOP1 =  GetAny<Matrice_Creuse<K> *>((*expOP1)(stack));  Matrice_Creuse<K> *pB =  GetAny<Matrice_Creuse<K> *>((*expB)(stack));  double * residptr=resid? (double*) *resid : 0;  //cout << " residptr = " << residptr <<endl;    if(evalue) nbev=Max( (long)evalue->N(),nbev);    const MatriceCreuse<K> & OP1 = pOP1->A;  const MatriceCreuse<K> & B = pB->A;    long  n=OP1.n;  if(sym)    {      nbev=min(n-1,nbev);      if(!ncv) 	ncv = min(nbev*2+1,n);    }  else    {      nbev=min(nbev,n-2);      if(!ncv)     ncv = nbev*2+1;            }  ncv = max(nbev+2,ncv);  ncv = min(ncv,n);  if(!maxit)  maxit = 100*nbev;        const char *serr[10];    int err=0;    if( ! (nbev < n) )	serr[err++]="  Number of eigenvalues of OP to be computed nev <= n ";        if( (mode < 1 || mode > 5) && sym)         serr[err++]="  the mode = 1 ,2 ,3, 4, 5  ";    if( (mode < 1 || mode > 4) && !sym)         serr[err++]="  the mode = 1 ,2 ,3, 4  ";    // 2 <= NCV-NEV and NCV <= N        if( ! (   ncv <= n) && sym ) 	serr[err++]="   ( ncv <= n) (symetric  case) ";    if( ! ( (   ncv <= n) && 2 <= (ncv-nbev ) ) && !sym )	serr[err++]="   ( ncv <= n)  2 <= (ncv-nev ) ( no-symetric  case) ";        if (n != OP1.m) 	serr[err++]=" the first matrix in EigneValue is not square.";    if (n != B.n ) 	serr[err++]="Sorry the row's number of the secand matrix in EigneValue is wrong.";    if (n != B.m ) 	serr[err++]="Sorry the colum's number of the secand matrix in EigneValue is wrong.";	   if(verbosity)    if(sym)      cout << "Real symmetric eigenvalue problem: A*x - B*x*lambda" << endl;    else      cout << "Real non symmetric eigenvalue problem: A*x - B*x*lambda" << endl;              if(verbosity>9 || err)	cout << "    n " << n << ", nev "<< nbev << ", tol =" << tol << ", maxit =" << maxit 	<< ", ncv = " <<ncv << ", mode = " << mode << endl;    if(err)       {	  cerr << " list of the error " << endl;	  for (int i=0;i<err;++i)	      cerr << "\n-  " <<  serr[i] << endl;	  ExecError("Fatal Error in EigenValue (real) ");      }      KN<K> work(n);  if(sym)    {      int ido=0;      char bmat= mode == 1 ? 'I' : 'G';      char which[3]= "LM";	// larger value      //      if(mode >2) which[0] ='S'; // smaller value      int ishift=1; // Auto Shift true by default      int iparam[12]= {0,ishift,0,maxit,1,nconv,0,mode,0,0,0,0};      int ipntr[12]={ 0,0,0, 0,0,0,  0,0,0, 0,0,0 };      KN<double> workd(3*n+1);      int lworkl = ncv*(ncv+9);      KN<double> workl(lworkl+1);      KN<double> vp(ncv*n+1);      int info= (residptr !=0);      KN<double> vresid(residptr? 1: n);      if(!residptr) residptr=&vresid[0];      while (1) {		saupp(ido,bmat,n,which,nbev,tol,  residptr,  ncv,  vp, n,	      iparam,  ipntr,  workd,   workl,  lworkl, info);	if(verbosity>99) 	  cout << "    saupp ido: " << ido << " info : " << info << endl;	if(info<0) {cerr << " -- err arpack info = " << info << endl;}  	sauppError(info);	if(ido==99) break;		KN_<double>  xx(&workd[ipntr[1]],n);	KN_<double>  yy(&workd[ipntr[2]],n);	KN_<double>  zz(&workd[ipntr[3]],n);	DoIdoAction(ido,mode,xx,yy,zz,work,OP1,B);      }      nconv = iparam[5];      if(nconv==0) cerr << " -- Strange: no eigens values ??? " << endl;      // Finding eigenvalues and eigenvectors.      if(nconv)	{	  KN<double> evr(nbev);	  KNM<double> Z(n,nbev);	  int ldz=n;	  char HowMny ='A';	  int rvec=1;	  	  seupp( rvec, HowMny, evr,  Z, ldz, sigma, bmat, n,		 which,  nbev,  tol,  residptr, ncv, vp,  n, iparam,ipntr,  workd, workl,lworkl,info);	  	  if(verbosity>5)	    {	      	      cout << "Dimension of the system            : " << n              << endl;	      cout << "Number of 'requested' eigenvalues  : " << nbev  << endl;	      cout << "Number of 'converged' eigenvalues  : " << nconv          << endl;	      cout << "Number of Arnoldi vectors generated: " << ncv  << endl;	      cout << "Number of iterations taken         : " << iparam[3]  << endl;	      cout << endl;	      	      //if (prob.EigenvaluesFound()) {	      cout << "Eigenvalues:" << endl;	      for (int i=0; i<nconv; i++) {		cout << "  lambda[" << (i+1) << "]: " << evr(i) << endl;		  KN_<K> vi(Z(':',i)) ;		  if(verbosity>99)		    cout <<" Eigenvector: :" << vi << endl;	      }	      cout << endl;	    }	  	  if (evalue)	    {	      KN<double> & ev(*evalue);	      int m = Min(nconv,ev.N());	      for(int i=0;i<m;i++)		ev[i]=evr(i);	      }	  if(rawvector)	    {	      int m = Min(nconv,rawvector->M());	      ffassert(rawvector->N()==n);	      for(int i=0;i<m;i++)		{		  KN_<K> vi(Z(':',i)) ;		  		  //   cout << " ------ EV--raw " << vi.min() << " " << vi.max() << endl;		  (*rawvector)(':',i)=vi;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?