#include #include #include #include "csolv.h" #include "csolvDlg.h" #include "complex.h" #include "spars.h" #define KLUDGE CComplexEntry::CComplexEntry() { next=NULL; x=0; c=0; } CBigComplexLinProb::CBigComplexLinProb() { n=0; } CBigComplexLinProb::~CBigComplexLinProb() { if (n==0) return; int i; CComplexEntry *uo,*ui; free(b); free(P); free(R); free(V); free(U); free(Z); free(Q); for(i=0;inext; delete uo; } while(ui!=NULL); } free(M); } int CBigComplexLinProb::Create(int d, int bw, int nodes) { int i; bdw=bw; NumNodes=nodes; b=(CComplex *)calloc(d,sizeof(CComplex)); V=(CComplex *)calloc(d,sizeof(CComplex)); P=(CComplex *)calloc(d,sizeof(CComplex)); R=(CComplex *)calloc(d,sizeof(CComplex)); U=(CComplex *)calloc(d,sizeof(CComplex)); Z=(CComplex *)calloc(d,sizeof(CComplex)); Q=(BOOL *)calloc(d,sizeof(BOOL)); M=(CComplexEntry **)calloc(d,sizeof(CComplexEntry *)); n=d; for(i=0;ic = i; } return 1; } void CBigComplexLinProb::Put(CComplex v, int p, int q) { CComplexEntry *e,*l; int i; if(qc < q) && (e->next != NULL)) { l=e; e=e->next; } if(e->c == q){ e->x=v; return; } CComplexEntry *m = new CComplexEntry; if((e->next == NULL) && (q > e->c)){ e->next = m; m->c = q; m->x = v; } else{ l->next=m; m->next=e; m->c=q; m->x=v; } return; } CComplex CBigComplexLinProb::Get(int p, int q) { CComplexEntry *e; if(qc < q) && (e->next != NULL)) e=e->next; if(e->c == q) return e->x; // if no entry in the list, this entry must be zero... return CComplex(0,0); } void CBigComplexLinProb::MultA(CComplex *X, CComplex *Y) { int i; CComplexEntry *e; for(i=0;ix*X[i]); e=M[i]->next; while(e!=NULL) { Y[i]+=(e->x*X[e->c]); Y[e->c]+=(e->x*X[i]); e=e->next; } } } void CBigComplexLinProb::MultConjA(CComplex *X, CComplex *Y) { int i; CComplexEntry *e; for(i=0;ix.Conj()*X[i]); e=M[i]->next; while(e!=NULL) { Y[i]+=(e->x.Conj()*X[e->c]); Y[e->c]+=(e->x.Conj()*X[i]); e=e->next; } } } void CBigComplexLinProb::MultAPPA(CComplex *X, CComplex *Y) { int i; MultA(X,Z); MultPC(Z,Y); for(i=0;ix; */ // SSOR preconditioner int i; CComplex c; CComplexEntry *e; c= Lambda*(2-Lambda); for(i=0;ix; e=M[i]->next; while(e!=NULL) { Y[e->c] -= e->x * Y[i] * Lambda; e=e->next; } } for(i=0;ix; // invert Upper Triangle for(i=n-1;i>=0;i--){ e=M[i]->next; while(e!=NULL) { Y[i] -= e->x * Y[e->c] * Lambda; e=e->next; } Y[i]/= M[i]->x; } } int CBigComplexLinProb::PBCGSolve(int flag) { int i; CComplex res,res_new,del,rho,pAp; double er,res_o; // quick check for most obvious sign of singularity; for(i=0;ix.re==0) && (M[i]->x.im==0)){ fprintf(stderr,"singular flag tripped."); return 0; } // initialize progress bar; TheView->SetDlgItemText(IDC_FRAME1,"BiConjugate Gradient Solver"); TheView->m_prog1.SetPos(0); int prg1=0; int prg2; // Guess for best relaxation parameter Lambda=1.5; // residual with V=0 MultPC(b,Z); res_o=abs(Dot(Z,b)); if(res_o==0) return 1; // if flag is false, initialize V with zeros; if (flag==0) for(i=0;iprg1){ prg1=prg2; prg2=(prg1*5); if(prg2>100) prg2=100; TheView->m_prog1.SetPos(prg2); TheView->InvalidateRect(NULL, FALSE); TheView->UpdateWindow(); } } while(er>(Precision*0.01)); return 1; } void CBigComplexLinProb::SetValue(int i, CComplex x) { int k,fst,lst; CComplex z; if(bdw==0){ fst=0; lst=n; } else{ fst=i-bdw; if (fst<0) fst=0; lst=i+bdw; if (lst>NumNodes) lst=NumNodes; } for(k=fst;kx=0; e=e->next; } while(e!=NULL); } } void CBigComplexLinProb::AntiPeriodicity(int i, int j) { int k,fst,lst; CComplex v1,v2,c; #ifdef KLUDGE int tmpbdw=bdw; bdw=0; #endif if (jNumNodes-1) lst=NumNodes-1; } for(k=fst;kNumNodes-1) lst=NumNodes-1; } for(k=fst;kx.re==0) && (M[i]->x.im==0)){ fprintf(stderr,"singular flag tripped."); return 0; } // initialize progress bar; TheView->SetDlgItemText(IDC_FRAME1,"QMR Solver"); TheView->m_prog1.SetPos(0); int prg1=0; int prg2; // if flag is false, initialize V with zeros; if (flag==0) for(i=0;iprg1){ prg1=prg2; prg2=(prg1*5); if(prg2>100) prg2=100; TheView->m_prog1.SetPos(prg2); TheView->InvalidateRect(NULL, FALSE); TheView->UpdateWindow(); } } while(er > Precision); return 1; } // Make into a Hermitian problem and solve. // This ought to be slower than BiPCG, but the idea is to avoid // the situations where BiPCG breaks down. // This works, but to do the whole problem this way can be // painfully slow in practice. int CBigComplexLinProb::PCGSQSolve(int flag) { int i; CComplex res,res_new,del,rho,pAp; double er,res_o; // quick check for most obvious sign of singularity; for(i=0;ix.re==0) && (M[i]->x.im==0)){ fprintf(stderr,"singular flag tripped."); return 0; } // initialize progress bar; TheView->SetDlgItemText(IDC_FRAME1,"Conjugate Gradient Solver"); TheView->m_prog1.SetPos(0); int prg1=0; int prg2; // Guess for best relaxation parameter Lambda=1.0; // Operate on RHS to scale for squared problem MultPC(b,Z); for(i=0;iprg1){ prg1=prg2; prg2=(prg1*5); if(prg2>100) prg2=100; TheView->m_prog1.SetPos(prg2); TheView->InvalidateRect(NULL, FALSE); TheView->UpdateWindow(); } } while(er>Precision); return 1; } // Make into a Hermitian problem and solve. // Just use for a few iterations to get a good starting point // for the regular BiPCG, which can sometimes get initialized // with a pathological starting point. int CBigComplexLinProb::PCGSQStart(int flag) { int i,k; CComplex res,res_new,del,rho,pAp; // quick check for most obvious sign of singularity; for(i=0;ix.re==0) && (M[i]->x.im==0)){ fprintf(stderr,"singular flag tripped."); return 0; } // Guess for best relaxation parameter Lambda=1.0; // Operate on RHS to scale for squared problem MultPC(b,Z); for(i=0;im_prog1.SetPos(0); int prg1=0; int prg2; // get starting point; singularity check; if(flag==FALSE){ TheView->SetDlgItemText(IDC_FRAME1,"Initializing Solver"); if (PCGSQStart(flag)==0) return 0; } TheView->SetDlgItemText(IDC_FRAME1,"BiConjugate Gradient Solver"); // Guess for best relaxation parameter Lambda=1.5; // residual with V from PCGSQ // if flag==TRUE, carry residual target over from the last iteration. if (flag==FALSE) { MultPC(V,Z); res_o=abs(Dot(Z,V)); if(res_o==0) return 1; } // form residual; MultA(V,R); for(i=0;iprg1){ prg1=prg2; prg2=(prg1*5); if(prg2>100) prg2=100; TheView->m_prog1.SetPos(prg2); TheView->InvalidateRect(NULL, FALSE); TheView->UpdateWindow(); } } while(er>(Precision*0.01)); return 1; }