SUBROUTINE PCGQS(NN,AA,LENAA,MAXA,PP,YP,RHO,START,WORK,IFLAG) C C THIS SUBROUTINE SOLVES A SYSTEM OF EQUATION USING THE METHOD OF C CONJUGATE GRADIENTS. THE SYSTEM TO BE SOLVED IS IN THE FORM C C (AUG)*X = B, C C WHERE C C +-- --+ +- -+ C | | | | | C | AA | -PP | | | C AUG = | | | , B = | -RHO | C +--------------+ | | C | YP | | | C +-- --+ +- -+ C C C C THE SYSTEM IS SOLVED BY SPLITTING AUG INTO TWO MATRICES C AUG = M + L, WHERE C C +- -+ +- -+ C | | | | | C | AA | C | | -PP-C | C M = | | | , L = U * [E(NN+1)**T], U = | | , C +------+---+ +-------+ C | C | D | | 0 | C +- -+ +- -+ C C E(NN+1) IS THE (NN+1) X 1 VECTOR CONSISTING OF ALL ZEROS EXCEPT FOR C A '1' IN ITS LAST POSITION. C C THE FINAL SOLUTION VECTOR, X, IS GIVEN BY C C +- -+ C | [SOL(U)]*[E(NN+1)**T] | C X = | I - ----------------------------- | * SOL(B) C | {[(SOL(U))**T]*E(NN+1)}+1.0 | C +- -+ C C WHERE SOL(A)=[M**(-1)]*A. THE TWO SYSTEMS (MZ=U, MZ=B) ARE SOLVED C BY A PRECONDITIONED CONJUGATE GRADIENT ALGORITHM. C C C ON INPUT: C C NN = THE DIMENSION OF THE MATRIX PACKED IN AA. C C AA(1:LENAA) CONTAINS THE MATRIX AA, STORED IN PACKED SKYLINE C FORMAT. LENAA AND MAXA DESCRIBE THE DATA STRUCTURE. C C LENAA = THE LENGTH OF THE ONE-DIMENSIONAL ARRAY AA. C C MAXA(1:NN+2) IN ITS FIRST N+1 COMPONENTS CONTAINS THE INDICES OF C THE DIAGONAL ELEMENTS OF THE MATRIX STORED IN AA. C MAXA(NN+2) IS ASSIGNED THE VALUE LENNAA + NN + 2. C C AS AN EXAMPLE OF THE PACKED SKYLINE STORAGE FORMAT, CONSIDER THE C SYMMETRIC MATRIX C C C +-- --+ C | 1 3 0 0 0 | C | 3 2 0 7 0 | C | 0 0 4 6 0 | C | 0 7 6 5 9 | C | 0 0 0 9 8 | C +-- --+ C C THIS WOULD RESULT IN NN=5, LENAA=9, MAXA=(1,2,4,5,8,10,16), C AND AA=(1,2,3,4,5,6,7,8,9). C C PP(1:NN) = THE NEGATIVE OF THE LAST COLUMN OF AUG. C C YP(1:NN+1) = THE LAST ROW OF AUG. C C RHO(1:NN+1) = THE NEGATIVE OF THE RIGHT HAND SIDE OF THE EQUATION TO C BE SOLVED. C C WORK(1:6*(NN+1)+LENAA) IS A WORK ARRAY DIVIDED UP AS FOLLOWS: C C WORK(1:NN+1) = TEMPORARY WORKING STORAGE. C C WORK(NN+2:2*NN+2) = INTERMEDIATE SOLUTION VECTOR Z FOR MZ=U. C THE INPUT VALUE IS USED AS THE INITIAL ESTIMATE FOR Z. C C WORK(2*NN+3:3*NN+3) = INTERMEDIATE SOLUTION VECTOR Z FOR MZ=B. C C WORK(3*NN+4:4*NN+4) = STORAGE FOR THE RESIDUAL VECTORS. C C WORK(4*NN+5:5*NN+5) = STORAGE FOR THE DIRECTION VECTORS. C C WORK(5*NN+6:6*NN+6+LENAA) = STORAGE FOR THE PRECONDITIONING C MATRIX Q. C C C ON OUTPUT: C C NN, AA, LENAA, MAXA, PP, YP, AND RHO ARE UNCHANGED. C C START(1:N+1) CONTAINS THE SOLUTION VECTOR X. C C IFLAG IS UNCHANGED UNLESS THE CONJUGATE GRADIENT ITERATION C FAILS TO CONVERGE IN 10*(NN+1) ITERATIONS (MOST LIKELY DUE C TO A SINGULAR JACOBIAN MATRIX). IN THIS CASE, PCGQS RETURNS C IFLAG = 4, AND DOES NOT COMPUTE X. C C C CALLS D1MACH, DAXPY, DCOPY, DDOT, DNRM2, DSCAL, GMFADS, MULTDS, C SOLVDS. C C ***** DECLARATIONS ***** C C FUNCTION DECLARATIONS C DOUBLE PRECISION D1MACH, DDOT, DNRM2 C C LOCAL VARIABLES C DOUBLE PRECISION AB, AU, BB, BU, DZNRM, PBNPRD, PUNPRD, $ RBNPRD, RBTOL, RNPRD, RUNPRD, RUTOL, TEMP, ZLEN, ZTOL INTEGER DIR, IMAX, J, LENQ, NP1, Q, RES, ZB, ZU LOGICAL STILLU, STILLB C C SCALAR ARGUMENTS C INTEGER NN, LENAA, IFLAG C C ARRAY DECLARATIONS C DOUBLE PRECISION AA(LENAA), PP(NN), YP(NN+1), RHO(NN+1), $ START(NN+1), WORK(6*(NN+1)+LENAA) INTEGER MAXA(NN+2) C C ***** END OF DECLARATIONS ***** C C ***** FIRST EXECUTABLE STATEMENT ***** C C SET UP BASES FOR VECTORS STORED IN WORK ARRAY. C NP1=NN+1 ZU=NN+2 ZB=(2*NN)+3 RES=(3*NN)+4 DIR=(4*NN)+5 Q=(5*NN)+6 C C INITIALIZE PRECONDITIONING MATRIX Q, SET VALUES OF MAXA(NN+1) C AND MAXA(NN+2), COMPUTE PRECONDITIONER. C CALL DCOPY(LENAA,AA,1,WORK(Q),1) CALL DCOPY(NP1,YP,1,WORK(Q+LENAA),1) MAXA(NN+1)=LENAA+1 MAXA(NN+2)=LENAA+NN+2 LENQ = MAXA(NN+2)-1 CALL GMFADS(NP1,WORK(Q),LENQ,MAXA) C C COMPUTE ALL TOLERANCES NEEDED FOR EXIT CRITERIA. C CALL DCOPY(NN,PP,1,WORK,1) WORK(NP1)=0.0 CALL DAXPY(NP1,1.0D0,YP,1,WORK,1) IMAX=10*NP1 STILLU=.TRUE. STILLB=.TRUE. ZTOL=100.0*D1MACH(4) RUTOL=ZTOL*DNRM2(NP1,WORK,1) RBTOL=ZTOL*DNRM2(NP1,RHO,1) C C ***** END OF INITIALIZATION ***** C C ***** SOLVE SYSTEM M Z = U ***** C C COMPUTE INITIAL RESIDUAL VECTOR FOR THE SYSTEM M Z = U . C RES = (Q**(-1))*(U - M*Z.) * CALL MULTDS(WORK(RES),AA,WORK(ZU),MAXA,NN,LENAA) WORK(RES+NN)= DDOT(NN,YP,1,WORK(ZU),1) CALL DAXPY(NP1,WORK(ZU+NN),YP,1,WORK(RES),1) CALL DSCAL(NP1,-1.0D0,WORK(RES),1) CALL DAXPY(NN,-1.0D0,PP,1,WORK(RES),1) CALL DAXPY(NN,-1.0D0,YP,1,WORK(RES),1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK(RES)) C C COMPUTE INITIAL DIRECTION VECTOR. C DIR = (A**T)*(Q**(-T))*RES. C CALL DCOPY(NP1,WORK(RES),1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL MULTDS(WORK(DIR),AA,WORK,MAXA,NN,LENAA) WORK(DIR+NN)=DDOT(NN,YP,1,WORK,1) CALL DAXPY(NP1,WORK(NP1),YP,1,WORK(DIR),1) C C COMPUTE INITIAL INNER PRODUCTS. C RUNPRD=DDOT(NP1,WORK(RES),1,WORK(RES),1) PUNPRD=DDOT(NP1,WORK(DIR),1,WORK(DIR),1) C C REPEAT UNTIL CONVERGENCE OR TOO MANY ITERATIONS. C J=1 C C DO WHILE ((STILLU) .AND. (J .LE. IMAX)) 100 IF (.NOT. ((STILLU) .AND. (J .LE. IMAX)) ) GO TO 200 C C IF ||RESIDUAL|| IS STILL NOT SMALL ENOUGH, CONTINUE. C IF (SQRT(RUNPRD) .GT. RUTOL) THEN C C IF DIRECTION VECTOR IS ZERO, THEN RE-COMPUTE RESIDUAL, C DIRECTION VECTOR, AND INNER PRODUCTS FROM SCRATCH C (RATHER THAN FROM UPDATES OF PREVIOUS VALUES). C IF (PUNPRD .EQ. 0.0) THEN C C COMPUTE RESIDUAL. C CALL MULTDS(WORK(RES),AA,WORK(ZU),MAXA,NN,LENAA) WORK(RES+NN)= DDOT(NN,YP,1,WORK(ZU),1) CALL DAXPY(NP1,WORK(ZU+NN),YP,1,WORK(RES),1) CALL DSCAL(NP1,-1.0D0,WORK(RES),1) CALL DAXPY(NN,-1.0D0,PP,1,WORK(RES),1) CALL DAXPY(NN,-1.0D0,YP,1,WORK(RES),1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK(RES)) C C COMPUTE DIRECTION VECTOR. C CALL DCOPY(NP1,WORK(RES),1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL MULTDS(WORK(DIR),AA,WORK,MAXA,NN,LENAA) WORK(DIR+NN)=DDOT(NN,YP,1,WORK,1) CALL DAXPY(NP1,WORK(NP1),YP,1,WORK(DIR),1) C C COMPUTE INNER PRODUCTS C RUNPRD=DDOT(NP1,WORK(RES),1,WORK(RES),1) PUNPRD=DDOT(NP1,WORK(DIR),1,WORK(DIR),1) C C CHECK FOR CONVERGENCE. C IF (SQRT(RUNPRD) .LE. RUTOL) THEN STILLU=.FALSE. ENDIF ENDIF IF (STILLU) THEN C C UPDATE SOLUTION VECTOR. C Z = Z + AU*DIR, WHERE AU= RUNPRD/PUNPRD. C AU=RUNPRD/PUNPRD CALL DAXPY(NP1,AU,WORK(DIR),1,WORK(ZU),1) C C COMPUTE RELATIVE CHANGE IN THE SOLUTION. C DZNRM=AU*SQRT(PUNPRD) ZLEN=DNRM2(NP1,WORK(ZU),1) C C IF RELATIVE CHANGE IN SOLUTIONS IS SMALL ENOUGH, EXIT. C IF ( (DZNRM/ZLEN) .LT. ZTOL) STILLU=.FALSE. ENDIF ELSE STILLU=.FALSE. ENDIF C C IF NO EXIT CRITERIA FOR MZ=U HAVE BEEN MET, UPDATE RESIDUAL, C DIRECTION VECTORS, AND INNER PRODUCTS FOR NEXT ITERATION. C IF (STILLU) THEN C C UPDATE RESIDUAL VECTOR; COMPUTE . C RES = RES - AU*(Q**(-1))*M*DIR. C CALL MULTDS(WORK,AA,WORK(DIR),MAXA,NN,LENAA) WORK(NP1)=DDOT(NN,YP,1,WORK(DIR),1) CALL DAXPY(NP1,WORK(DIR+NN),YP,1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL DAXPY(NP1,-AU,WORK,1,WORK(RES),1) RNPRD=DDOT(NP1,WORK(RES),1,WORK(RES),1) C C UPDATE DIRECTION VECTOR; COMPUTE . C DIR = (M**T)*(Q**(-T))*RES + BU*DIR, C WHERE BU = RNPRD/RUNPRD. (NOTE: START IS USED AS C A WORK ARRAY HERE). C BU=RNPRD/RUNPRD RUNPRD=RNPRD CALL DCOPY(NP1,WORK(RES),1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL MULTDS(START,AA,WORK,MAXA,NN,LENAA) START(NP1)=DDOT(NN,YP,1,WORK,1) CALL DAXPY(NP1,WORK(NP1),YP,1,START,1) CALL DAXPY(NP1,BU,WORK(DIR),1,START,1) CALL DCOPY(NP1,START,1,WORK(DIR),1) PUNPRD=DDOT(NP1,WORK(DIR),1,WORK(DIR),1) ENDIF C J=J+1 GO TO 100 200 CONTINUE C END DO C C SET ERROR FLAG IF THE CONJUGATE GRADIENT ITERATION DID NOT CONVERGE. C IF (J .GT. IMAX) THEN IFLAG=4 RETURN ENDIF C C ***** END OF M Z = U SYSTEM ***** C C ***** SOLVE SYSTEM M Z = B ***** C C C COMPUTE INITIAL RESIDUAL VECTOR FOR THE SYSTEM M Z = B . C CALL MULTDS(WORK(RES),AA,WORK(ZB),MAXA,NN,LENAA) WORK(RES+NN)=DDOT(NN,YP,1,WORK(ZB),1) CALL DAXPY(NP1,WORK(ZB+NN),YP,1,WORK(RES),1) CALL DSCAL(NP1,-1.0D0,WORK(RES),1) CALL DAXPY(NP1,-1.0D0,RHO,1,WORK(RES),1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK(RES)) C C COMPUTE INITIAL DIRECTION VECTOR. C CALL DCOPY(NP1,WORK(RES),1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL MULTDS(WORK(DIR),AA,WORK,MAXA,NN,LENAA) WORK(DIR+NN)=DDOT(NN,YP,1,WORK,1) CALL DAXPY(NP1,WORK(NP1),YP,1,WORK(DIR),1) C C COMPUTE INITIAL INNER PRODUCTS. C RBNPRD=DDOT(NP1,WORK(RES),1,WORK(RES),1) PBNPRD=DDOT(NP1,WORK(DIR),1,WORK(DIR),1) C C REPEAT UNTIL CONVERGENCE, OR TOO MANY ITERATIONS. C J=1 C C DO WHILE ( STILLB .AND. (J .LE. IMAX) ) 300 IF (.NOT. ( STILLB .AND. (J .LE. IMAX) ) ) GO TO 400 C C IF ||RESIDUAL|| IS STILL NOT SMALL ENOUGH, CONTINUE. C IF (SQRT(RBNPRD) .GT. RBTOL) THEN C C IF DIRECTION VECTOR IS ZERO, RE-COMPUTE RESIDUAL, C DIRECTION VECTOR, AND INNER PRODUCTS FROM SCRATCH. C IF (PBNPRD .EQ. 0.0) THEN C C COMPUTE RESIDUAL. C CALL MULTDS(WORK(RES),AA,WORK(ZB),MAXA,NN,LENAA) WORK(RES+NN)=DDOT(NN,YP,1,WORK(ZB),1) CALL DAXPY(NP1,WORK(ZB+NN),YP,1,WORK(RES),1) CALL DSCAL(NP1,-1.0D0,WORK(RES),1) CALL DAXPY(NP1,-1.0D0,RHO,1,WORK(RES),1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK(RES)) C C COMPUTE DIRECTION VECTOR. C CALL DCOPY(NP1,WORK(RES),1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL MULTDS(WORK(DIR),AA,WORK,MAXA,NN,LENAA) WORK(DIR+NN)=DDOT(NN,YP,1,WORK,1) CALL DAXPY(NP1,WORK(NP1),YP,1,WORK(DIR),1) C C COMPUTE INNER PRODUCTS. C RBNPRD=DDOT(NP1,WORK(RES),1,WORK(RES),1) PBNPRD=DDOT(NP1,WORK(DIR),1,WORK(DIR),1) C C CHECK FOR CONVERGENCE. C IF (SQRT(RBNPRD) .LE. RBTOL) THEN STILLB=.FALSE. ENDIF ENDIF IF (STILLB) THEN C C UPDATE SOLUTION VECTOR. C Z = Z + AB*DIR, WHERE AB=RBNPRD/PBNPRD. C AB=RBNPRD/PBNPRD CALL DAXPY(NP1,AB,WORK(DIR),1,WORK(ZB),1) C C COMPUTE RELATIVE CHANGE IN SOLUTIONS. C DZNRM=AB*SQRT(PBNPRD) ZLEN=DNRM2(NP1,WORK(ZB),1) C C IF RELATIVE CHANGE IN SOLUTIONS IS SMALL ENOUGH, EXIT. C IF ( (DZNRM/ZLEN) .LT. ZTOL) STILLB=.FALSE. ENDIF ELSE STILLB=.FALSE. ENDIF C C IF NO EXIT CRITERIA FOR MZ=B HAVE BEEN MET, UPDATE RESIDUAL, C DIRECTION VECTORS, AND INNER PRODUCTS. C IF (STILLB) THEN C C UPDATE RESIDUAL VECTOR; COMPUTE . C RES = RES - AB*(Q**(-1))*M*DIR. C CALL MULTDS(WORK,AA,WORK(DIR),MAXA,NN,LENAA) WORK(NP1)=DDOT(NN,YP,1,WORK(DIR),1) CALL DAXPY(NP1,WORK(DIR+NN),YP,1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL DAXPY(NP1,-AB,WORK,1,WORK(RES),1) RNPRD=DDOT(NP1,WORK(RES),1,WORK(RES),1) C C UPDATE DIRECTION VECTOR; COMPUTE . C DIR = (M**T)*(Q**(-T))*RES + BB*DIR, C WHERE BB=RNPRD/RBNPRD. C (NOTE: START IS USED AS A WORK ARRAY HERE). C BB=RNPRD/RBNPRD RBNPRD=RNPRD CALL DCOPY(NP1,WORK(RES),1,WORK,1) CALL SOLVDS(NP1,WORK(Q),LENQ,MAXA,WORK) CALL MULTDS(START,AA,WORK,MAXA,NN,LENAA) START(NP1)=DDOT(NN,YP,1,WORK,1) CALL DAXPY(NP1,WORK(NP1),YP,1,START,1) CALL DAXPY(NP1,BB,WORK(DIR),1,START,1) CALL DCOPY(NP1,START,1,WORK(DIR),1) PBNPRD=DDOT(NP1,WORK(DIR),1,WORK(DIR),1) ENDIF C J=J+1 GO TO 300 400 CONTINUE C END DO C C SET ERROR FLAG IF THE CONJUGATE GRADIENT ITERATION DID NOT CONVERGE. C IF (J .GT. IMAX) THEN IFLAG=4 RETURN ENDIF C C ***** END OF M Z = B SYSTEM ***** C C COMPUTE FINAL SOLUTION VECTOR X, AND RETURN IT IN START. C TEMP=-WORK(ZB+NN)/(1.0D0+WORK(ZU+NN)) CALL DCOPY(NP1,WORK(ZB),1,START,1) CALL DAXPY(NP1,TEMP,WORK(ZU),1,START,1) C RETURN END .