/* pcgsolver.c -- The preconditioned conjugate gradient solver(s) Implemented solver/preconditioner: preconditioned cg-solver with * diagonal scaling only * incomplete Cholesky on full matrix Most functions are based on: H.R. Schwarz: FORTRAN-Programme zur Methode der finiten Elemente, Teubner, 1981 The present version is based on the c-code by Martin Ruecker and Ernst Rank of the Technical University of Munich */ #include #include #include #include "CalculiX.h" #define GOOD 0 #define BAD 1 #define FALSE 0 #define TRUE 1 /* Prototyping */ int cgsolver (double *A, double *x, double *b, int neq, int len, int *ia, int *iz,double *eps, int *niter, int precFlg); void PCG (double *A, double *x, double *b, int neq, int len, int *ia, int *iz,double *eps, int *niter, int precFlg, double *rho, double *r, double *g, double *C, double *z); void CG (double *A, double *x, double *b, int neq, int len, int *ia, int *iz,double *eps, int *niter,double *r, double *p, double *z); void Scaling (double *A, double *b, int neq, int *ia, int *iz, double *d); void MatVecProduct (double *A, double *p, int neq, int *ia, int *iz, double *z); void PreConditioning (double *A, int neq, int len, int *ia, int *iz, double alpha, int precFlg,double *C, int *ier); void Mrhor (double *C, int neq, int *ia, int *iz, double *r, double *rho); void InnerProduct (double *a, double *b, int n, double *Sum); /* ********************************************************************** The (preconditioned) conjugate gradient solver parameter: A compact row oriented storage of lower left of matrix A neq order of A, number of equations len number of non zero entries in Matrix A ia column indices of corresponding elements in Matrix A iz row indices (diagonal elements indices) x solution vector b right hand side eps required accuracy -> residual niter maximum number of iterations -> number of iterations precFlg preconditioning flag The compact row oriented storage of sparse quadratic matrices is decsribed in H.R. Schwarz: FORTRAN-Programme zur Methode der finiten Elemente, pp.66-67, Teubner, 1981 ********************************************************************** */ int cgsolver (double *A, double *x, double *b, int neq, int len, int *ia, int *iz, double *eps, int *niter, int precFlg) { int i=0; double *Factor=NULL,*r=NULL,*p=NULL,*z=NULL,*C=NULL,*g=NULL,*rho=NULL; /* reduce row and column indices by 1 (FORTRAN->C) */ for (i=0; i residual niter maximum number of iterations -> number of iterations precFlg preconditioning flag The function corresponds to function PACHCG() in H.R. Schwarz: FORTRAN-Pro- gramme zur Methode der finiten Elemente, p.115, Teubner, 1981 ********************************************************************** */ void PCG (double *A, double *x, double *b, int neq, int len, int *ia, int *iz,double *eps, int *niter, int precFlg, double *rho, double *r, double *g, double *C, double *z) { int i=0, k=0, ncg=0,iam,ier=0; double alpha=0.0, ekm1=0.0, rrho=0.0; double rrho1=0.0, gz=0.0, qk=0.0; double c1=0.005,qam,err,ram=0; /* initialize result and residual vectors */ qam=0.;iam=0; for (i=0; i1.e-20){qam+=err;iam++;} } if(iam>0) qam=qam/iam; else {*niter=0;return;} /* preconditioning */ printf("Cholesky preconditioning\n\n"); printf("alpha=%f\n",alpha); PreConditioning(A,neq,len,ia,iz,alpha,precFlg,C,&ier); while (ier==0) { if (alpha<=0.0) alpha=0.005; alpha += alpha; printf("alpha=%f\n",alpha); PreConditioning(A,neq,len,ia,iz,alpha,precFlg,C,&ier); } /* solving the system of equations using the iterative solver */ printf("Solving the system of equations using the iterative solver\n\n"); /* main iteration loop */ for (k=1; k<=*niter; k++, ncg++) { /* solve M rho = r, M=C CT */ Mrhor(C,neq,ia,iz,r,rho); /* inner product (r,rho) */ InnerProduct(r,rho,neq,&rrho); /* If working with Penalty-terms for boundary conditions you can get numerical troubles because RRHO becomes a very large value. With at least two iterations the result may be better !!! */ /* convergency check */ printf("iteration= %d, error= %e, limit=%e\n",ncg,ram,c1*qam); if (k!=1 && (ram<=c1*qam)) break; if (k!=1) { ekm1 = rrho/rrho1; for (i=0; iram) ram=err; } rrho1 = rrho; } if(k==*niter){ printf("*ERROR in PCG: no convergence;"); FORTRAN(stop,()); } *eps = rrho; *niter = ncg; return; } /* ********************************************************************** Scaling the equation system A x + b = 0 The equation system is scaled in consideration of keeping the symmetry in such a way that the diagonal elements of matrix A are 1. This is performed by the diagonal matrix Ds with the diagonal elements d_i = 1/sqrt(a_ii). The given equation system Ax+b=0 is transformed into -1 - - - Ds A Ds Ds x + Ds b = 0 or A x + b = 0 _ _ with the scaled Matrix A= Ds A Ds and the scaled right hand side b= Ds b. The scaling factor Ds is needed later for backscaling of the solution vector _ -1 _ x = Ds x resp. x = Ds x parameter: A compact row oriented storage of lower left of matrix A b right hand side neq order of A, number of equations ia column indices iz row indices (diagonal elements indices) The function corresponds to function SCALKO() in H.R. Schwarz: FORTRAN-Pro- gramme zur Methode der finiten Elemente, p.105, Teubner, 1981 ********************************************************************** */ void Scaling (double *A, double *b, int neq, int *ia, int *iz, double *d) { int i=0, j=0, jlo=0, jup=0; /* extract diagonal vector from matrix A */ for (i=0; i Ax+b=0: negative sign) */ for (i=0; iia[j]) break; if (ia[l]0; i--) { rho[i] /= C[iz[i]]; jlo = iz[i-1]+1; /*..first non-zero element in current row...... */ jup = iz[i]-1; /*..diagonal element in current row............ */ for (j=jlo; j<=jup; j++) /*..all non-zero off-diagonal element.......... */ rho[ia[j]] -= C[j]*rho[i]; } return; } /*--------------------------------------------------------------------------------- */ /*--Calculation of the inner product of two (distributed) vectors------------------ */ /*--------------------------------------------------------------------------------- */ void InnerProduct (double *a, double *b, int n, double *Sum) { int i=0; /*..local vectors.................................................................. */ *Sum=0.; for (i=0; i residual -- */ /*-- niter maximum number of iterations -> number of iterations -- */ /*--------------------------------------------------------------------------------- */ void CG (double *A, double *x, double *b, int neq, int len, int *ia, int *iz, double *eps, int *niter, double *r, double *p, double *z) { int i=0, k=0, ncg=0,iam; double ekm1=0.0,c1=0.005,qam,ram=0.,err; double rr=0.0, pz=0.0, qk=0.0, rro=0.0; /* solving the system of equations using the iterative solver */ printf("Solving the system of equations using the iterative solver\n\n"); /*..initialize result, search and residual vectors................................. */ qam=0.;iam=0; for (i=0; i1.e-20){qam+=err;iam++;} } if(iam>0) qam=qam/neq; else {*niter=0;return;} /*else qam=0.01;*/ /*..main iteration loop............................................................ */ for (k=1; k<=(*niter); k++, ncg++) { /*......inner product rT r......................................................... */ InnerProduct(r,r,neq,&rr); printf("iteration= %d, error= %e, limit=%e\n",ncg,ram,c1*qam); /*......If working with Penalty-terms for boundary conditions you can get nume-.... */ /*......rical troubles because RR becomes a very large value. With at least two.... */ /*......iterations the result may be better !!!.................................... */ /*......convergency check.......................................................... */ if (k!=1 && (ram<=c1*qam)) break; /*......new search vector.......................................................... */ if (k!=1) { ekm1 = rr/rro; for (i=0; iram) ram=err; } /*......store previous residual.................................................... */ rro = rr; } if(k==*niter){ printf("*ERROR in PCG: no convergence;"); FORTRAN(stop,()); } *eps = rr; /*..return residual............................ */ *niter = ncg; /*..return number of iterations................ */ /*..That's it...................................................................... */ return; } /*--------------------------------------------------------------------------------- */