miltp3
C MILTP3 SOURCE GOUNAND 05/02/16 21:16:19 5029 $ XLFIL,XDTOL,XSPIV,NNZMLU, $ ALU,JLU,JU,NNZLU, $ IWORK,JWORK,RWORK,LWORK, $ KWORK,QWORK, $ IPERM,JPERM, $ IMPR,IRET) IMPLICIT REAL*8 (A-H,O-Z) IMPLICIT INTEGER (I-N) C*********************************************************************** C NOM : MILTP3 C DESCRIPTION : C Calcul du préconditionneur ILUTP d'une matrice Morse C ILUT : Incomplete LU factorization with dual truncation strategy C La matrice Morse est au format CSR (Column Sparse Row) C Le préconditionneur est au format MSR (Modified Sparse Row, C stockage de l'inverse de la diagonale) (ALU, JLU). C JU est un tableau supplémentaire pour le repérage des diagonales. C (voir la doc. de Sparskit version 2) C C LANGAGE : FORTRAN 77 (sauf E/S) C AUTEUR : Stéphane GOUNAND (CEA/DRN/DMT/SEMT/LTMF) C mél : gounand@semt2.smts.cea.fr C REFERENCE (bibtex-like) : C @BOOK{templates, C AUTHOR={R.Barrett, M.Berry, T.F.Chan, J.Demmel, J.Donato, C J.Dongarra, V.Eijkhout, R.Pozo, C.Romine, C H. Van der Vorst}, C TITLE={Templates for the Solution of Linear Systems : C Building Blocks for Iterative Methods}, C PUBLISHER={SIAM}, YEAR={1994}, ADDRESS={Philadelphia,PA} } C -> URL : http://www.netlib.org/templates/Templates.html C Sparskit : a basic tool kit for sparse matrix computations C Version 2 (Youcef Saad) C -> URL : http://www.cs.umn.edu/Research/arpa/SPARSKIT/sparskit.html C REMARQUES : C Quelques parties pourraient être améliorés : C - l'algorithme de quicksplit (cf.qsplit.eso) C - la partie où l'on doit effectuer l'élimination dans le bon ordre C pourrait utiliser un algorithme de tri type quicksort C C C On garde absolument tous les termes qui seraient dans ILU(0). C C C*********************************************************************** C APPELES : QSPLIT C APPELE PAR : PRILUT C*********************************************************************** C ENTREES : NTT,NNZA,A,JA,IA,XLFIL,XDTOL,NNZMLU,IVARI C ENTREES/SORTIES : IWORK,JWORK,RWORK (tableaux de travail) C SORTIES : ALU,JLU,JU,NNZLU C CODE RETOUR (IRET) : = 0 si tout s'est bien passé C*********************************************************************** C VERSION : v1, 26/04/04, version initiale C HISTORIQUE : v1, 26/04/04, création C HISTORIQUE : C HISTORIQUE : C*********************************************************************** C Prière de PRENDRE LE TEMPS de compléter les commentaires C en cas de modification de ce sous-programme afin de faciliter C la maintenance ! C*********************************************************************** -INC PPARAM -INC CCOPTIO -INC CCREEL * .. Scalar Arguments .. INTEGER NTT,NNZA,NNZMLU,NNZLU INTEGER IMPR,IRET REAL*8 XDTOL,XLFIL * .. * .. Array Arguments .. REAL*8 A(NNZA),ALU(NNZMLU+1) INTEGER JA(NNZA),IA(NTT+1),JU(NTT),JLU(NNZMLU+1) INTEGER IWORK(NTT) INTEGER JWORK(NTT) REAL*8 RWORK(NTT) INTEGER KWORK(NTT) REAL*8 QWORK(NTT) LOGICAL LWORK(NTT) INTEGER IPERM(NTT) INTEGER JPERM(NTT) * * .. Variables locales * .. Parameters * .. C Nombre de pivots petits INTEGER NBPIVP C Nombre de pivots inférieurs à 0 INTEGER NBPIVI * INTEGER ILFIL,ILFILL,ILFILU INTEGER COL,COLLU INTEGER IJA,ILEN,ILENL,ILENU,ITT,ISTRT,ISTOP INTEGER JJL,JPOS,JROW,KJL,KLU INTEGER LEN,LENL,LENU INTEGER JU0,ITMP LOGICAL LTMP,LFACT,LPIV,LFOUND REAL*8 XNTLIG * REAL*8 XPOND1,XPOND2 * * Executable statements * IF (XLFIL.LT.1.D0) THEN WRITE(IOIMP,*) 'XLFIL.LT.1.D0 non acceptable' GOTO 9999 ENDIF NBPIVP=0 NBPIVI=0 c----------------------------------------------------------------------- c initialize ju0 (points to next element to be added to alu,jlu) c and pointer array. c----------------------------------------------------------------------- JU0=NTT+2 JLU(1)=JU0 * * Initialize permutation arrays and lwork * DO ITT=1,NTT JWORK(ITT)=0 IPERM(ITT)=ITT JPERM(ITT)=ITT *!!!!!!!!!!!!!! LWORK(ITT)=.FALSE. ENDDO * * On boucle sur les ddl * DO 1 ITT=1,NTT * Calcul de la norme de la ittème ligne ISTRT=IA(ITT) ISTOP=IA(ITT+1)-1 TNORM=ZERO DO 11 IJA=ISTRT,ISTOP TNORM=TNORM+ABS(A(IJA)) 11 CONTINUE TNORM=TNORM/DBLE(ISTOP-ISTRT+1) IF (TNORM.LE.XPETIT) THEN WRITE(IOIMP,*) 'La ligne ',ITT,' est nulle...' GOTO 9999 ENDIF * On stocke la ittème ligne de A dans IWORK,RWORK en distinguant les * parties triangulaires inférieures et supérieurs. * * On peut le programmer autrement compte tenu du fait que les * colonnes sont ordonnées * LENU=1 LENL=0 IWORK(ITT)=ITT JWORK(ITT)=ITT LWORK(ITT)=.TRUE. DO 12 IJA=ISTRT,ISTOP *! COL=JA(IJA) COL=JPERM(JA(IJA)) VAL=A(IJA) IF (COL.LT.ITT) THEN LENL=LENL+1 IWORK(LENL)=COL RWORK(LENL)=VAL *!!!!!!!!!!!!!! LWORK(LENL)=.TRUE. JWORK(COL) =LENL ELSEIF (COL.EQ.ITT) THEN RWORK(ITT)=VAL ELSE LENU=LENU+1 JPOS=ITT+LENU-1 IWORK(JPOS)=COL RWORK(JPOS)=VAL *!!!!!!!!!!!!!! LWORK(JPOS)=.TRUE. JWORK(COL) =JPOS ENDIF 12 CONTINUE * On a enlevé les stratégies bizarres XNTLIG=DBLE(NNZA)/DBLE(NTT) *!! ILFIL=INT(XNTLIG*XLFIL/2.D0) ILFIL=INT(XNTLIG*(XLFIL-1.D0)/2.D0) ILFILL=ILFIL ILFILU=ILFIL * Elimination avec les lignes précédentes JJL=0 LEN=0 13 CONTINUE JJL=JJL+1 IF (JJL.LE.LENL) THEN c----------------------------------------------------------------------- c in order to do the elimination in the correct order we must select c the smallest column index among jw(k), k=jj+1, ..., lenl. c----------------------------------------------------------------------- JROW=IWORK(JJL) KJL=JJL c determine smallest column index DO 132 ILENL=JJL+1,LENL IF (IWORK(ILENL).LT.JROW) THEN JROW=IWORK(ILENL) KJL=ILENL ENDIF 132 CONTINUE IF (KJL.NE.JJL) THEN ITMP=IWORK(JJL) IWORK(JJL)=IWORK(KJL) IWORK(KJL)=ITMP JWORK(JROW)=JJL JWORK(ITMP)=KJL RTMP=RWORK(JJL) RWORK(JJL)=RWORK(KJL) RWORK(KJL)=RTMP *!!!!!!!!!!!!!! LTMP=LWORK(JJL) LWORK(JJL)=LWORK(KJL) LWORK(KJL)=LTMP ENDIF c zero out element in row by setting jw(n+jrow) to zero. JWORK(JROW)=0 c get the multiplier for row to be eliminated (jrow). FACT=RWORK(JJL)*ALU(JROW) LFACT=LWORK(JJL) *!!!!!!!!!!!!!! IF (ABS(FACT).LE.XDTOL.AND.(.NOT.LFACT)) THEN * IF (ABS(FACT).LE.XDTOL) THEN GOTO 13 ENDIF c c combine current row and row jrow c DO 134 KLU=JU(JROW),JLU(JROW+1)-1 TERMLU=FACT*ALU(KLU) *! COLLU =JLU(KLU) COLLU =JPERM(JLU(KLU)) JPOS =JWORK(COLLU) IF (COLLU.GE.ITT) THEN c dealing with upper part (including diagonal) IF (JPOS.EQ.0) THEN c this is a fill-in element LENU=LENU+1 IF (LENU.GT.NTT-ITT+1) THEN WRITE(IOIMP,*) 'pb. matrice U' GOTO 9999 ENDIF IWORK(ITT+LENU-1)=COLLU JWORK(COLLU)=ITT+LENU-1 RWORK(ITT+LENU-1)=-TERMLU LWORK(ITT+LENU-1)=.FALSE. ELSE c this is not a fill-in element RWORK(JPOS)=RWORK(JPOS)-TERMLU ENDIF ELSE c dealing with lower part. IF (JPOS.EQ.0) THEN c this is a fill-in element LENL=LENL+1 IF (LENL.GT.ITT-1) THEN WRITE(IOIMP,*) 'pb. matrice L' WRITE(IOIMP,*) 'LENL=',LENL WRITE(IOIMP,*) 'ITT=',ITT GOTO 9999 ENDIF IWORK(LENL) =COLLU JWORK(COLLU)=LENL RWORK(LENL) =-TERMLU LWORK(LENL) =.FALSE. ELSE c this is not a fill-in element RWORK(JPOS)=RWORK(JPOS)-TERMLU ENDIF ENDIF 134 CONTINUE c store this pivot element -- (from left to right -- no danger of c overlap with the working elements in L (pivots). LEN=LEN+1 * ????????? LWORK(LEN)=LFACT RWORK(LEN)=FACT IWORK(LEN)=JROW GOTO 13 ENDIF c reset double-pointer to zero (U-part including diagonal) DO 14 ILENU=1,LENU JWORK(IWORK(ITT+ILENU-1))=0 14 CONTINUE c update L-matrix LENL=LEN * * First store elements of the ilu(0) factorization * LEN2=0 DO ILENL=1,LENL IF (LWORK(ILENL)) THEN LEN2=LEN2+1 KWORK(LEN2)=IWORK(ILENL) QWORK(LEN2)=RWORK(ILENL) ENDIF ENDDO LENIL0=LEN2 * then the fill-in elements DO ILENL=1,LENL IF (.NOT.LWORK(ILENL)) THEN LEN2=LEN2+1 KWORK(LEN2)=IWORK(ILENL) QWORK(LEN2)=RWORK(ILENL) ENDIF ENDDO IF (LEN2.NE.LENL) THEN WRITE(IOIMP,*) 'Erreur de programmation 1' GOTO 9999 ENDIF LENFIL=LENL-LENIL0 * sort the fill-in elements by quick-split LEN=MIN(LENFIL,ILFILL) c sort by quick-split $ IMPR,IRET) c store L-part -- in original coordinates DO 15 ILEN=1,LENIL0+LEN ALU(JU0)=QWORK(ILEN) JLU(JU0)=IPERM(KWORK(ILEN)) JU0=JU0+1 15 CONTINUE * c save pointer to beginning of row ii of U JU(ITT)=JU0 c update U-matrix -- first apply dropping strategy LEN=0 DO 16 ILEN=1,LENU-1 IF (ABS(RWORK(ITT+ILEN)).GT.XDTOL*TNORM) THEN LEN=LEN+1 RWORK(ITT+LEN)=RWORK(ITT+ILEN) IWORK(ITT+LEN)=IWORK(ITT+ILEN) *!!!!!!!!!!!!!! LWORK(ITT+LEN)=LWORK(ITT+ILEN) ENDIF 16 CONTINUE LENU=LEN+1 * * First store elements of the ilu(0) factorization * LEN2=ITT-1 DO ILENU=ITT,ITT+LENU-1 IF (LWORK(ILENU)) THEN LEN2=LEN2+1 KWORK(LEN2)=IWORK(ILENU) QWORK(LEN2)=RWORK(ILENU) ENDIF ENDDO LENIL0=LEN2-ITT+1 * then the fill-in elements DO ILENU=ITT,ITT+LENU-1 IF (.NOT.LWORK(ILENU)) THEN LEN2=LEN2+1 KWORK(LEN2)=IWORK(ILENU) QWORK(LEN2)=RWORK(ILENU) ENDIF ENDDO IF (LEN2-ITT+1.NE.LENU) THEN WRITE(IOIMP,*) 'Erreur de programmation 2' GOTO 9999 ENDIF LENFIL=LENU-LENIL0 * sort the fill-in elements by quicksplit *!!!!!!!! LEN=MIN(LENFIL,ILFILU) *!! LEN=MIN(LENU,ILFILU+1) *!!! LEN=MIN(LENU,ILFILU) $ IMPR,IRET) C WRITE(IOIMP,*) 'NTT=',NTT C WRITE(IOIMP,*) 'ITT=',ITT C WRITE(IOIMP,*) 'ILFILU=',ILFILU C WRITE(IOIMP,*) 'LEN=',LEN C WRITE(IOIMP,*) 'LENU=',LENU C DO JTT=ITT,NTT C WRITE(IOIMP,*) 'JTT=',JTT C WRITE(IOIMP,*) 'IWORK(JTT)=',IWORK(JTT) C WRITE(IOIMP,*) 'RWORK(JTT)=',RWORK(JTT) C WRITE(IOIMP,*) 'LWORK(JTT)=',LWORK(JTT) C ENDDO C DO JTT=ITT,NTT C WRITE(IOIMP,*) 'JTT=',JTT C WRITE(IOIMP,*) 'KWORK(JTT)=',KWORK(JTT) C WRITE(IOIMP,*) 'QWORK(JTT)=',QWORK(JTT) C ENDDO * * Determine next pivot * IMAX=ITT XMAX=XMAX/XSPIV LPIV=.TRUE. * On pivote même si xspiv.EQ.zero si la diagonale est petite LPIV=.TRUE. ELSE LPIV=.FALSE. ENDIF * * WRITE(IOIMP,*) 'LPIV=',LPIV IF (LPIV) THEN DO ILEN=ITT+1,ITT+LENIL0+LEN-1 XCOU=ABS(QWORK(ILEN)) IF (XCOU.GT.XMAX) THEN IMAX=ILEN XMAX=XCOU ENDIF ENDDO * On ne cherche le max que dans le ilu0 sauf si on ne trouve rien C LFOUND=.FALSE. C DO ILEN=ITT+1,ITT+LENIL0-1 C XCOU=ABS(QWORK(ILEN)) C IF (XCOU.GT.XMAX) THEN C IMAX=ILEN C XMAX=XCOU C LFOUND=.TRUE. C ENDIF C ENDDO C IF (.NOT.LFOUND) THEN C DO ILEN=ITT+LENIL0,ITT+LENIL0+LEN-1 C XCOU=ABS(QWORK(ILEN)) C IF (XCOU.GT.XMAX) THEN C IMAX=ILEN C XMAX=XCOU C ENDIF C ENDDO C ENDIF * * Echange des valeurs * XTMP=QWORK(ITT) * * Update de la numérotation ancienne * ITMP=IPERM(ITT) IPERM(ITT)=IPERM(JMAX) IPERM(JMAX)=ITMP * * Update de la numérotation nouvelle * JPERM(IPERM(ITT))=ITT JPERM(IPERM(JMAX))=JMAX ENDIF * c copy U-Part in original coordinates * DO 17 ILEN=ITT+1,ITT+LENIL0+LEN-1 JLU(JU0)=IPERM(KWORK(ILEN)) ALU(JU0)=QWORK(ILEN) JU0=JU0+1 17 CONTINUE c store inverse of diagonal element of u VALPIV=QWORK(ITT) WRITE(IOIMP,*) 'Pivot',ITT,' nul : ', $ 'le préconditionnement ILUTPGO2 est impossible.' IRET=-2 GOTO 9999 ELSE NBPIVP=NBPIVP+1 ENDIF NBPIVI=NBPIVI+1 ENDIF ENDIF ALU(ITT)=ONE/VALPIV c update pointer to beginning of next row of U. JLU(ITT+1)=JU0 1 CONTINUE NNZLU=JLU(NTT+1)-1 C C Permutation des colonnes de LU C DO KLU=JLU(1),JLU(NTT+1)-1 JLU(KLU)=JPERM(JLU(KLU)) ENDDO C C Permutation des colonnes de A C DO IJA=IA(1),IA(NTT+1)-1 JA(IJA)=JPERM(JA(IJA)) ENDDO * * Warning(s) * IF (IMPR.GT.0) THEN IF (NBPIVP.GT.0) THEN WRITE(IOIMP,*) 'WARNING !', ENDIF *! IF (NBPIVI.GT.0) THEN *! WRITE(IOIMP,*) 'WARNING !', *! $ ' miltp3 :',NBPIVI,' pivot(s) < 0' *! ENDIF ENDIF * * Normal termination * IRET=0 RETURN * * Error handling * 9999 CONTINUE IRET=1 WRITE(IOIMP,*) 'An error was detected in miltp3.eso' RETURN * * End of MILTP3 * END
© Cast3M 2003 - Tous droits réservés.
Mentions légales