BasisTransform.f90 Source File


Source Code

MODULE MOD_BASISTRANSFORM
! **************************************************************************
!
!  This module transforms the wave function from the relativistic kappa-mu
!  representation in spin spherical harmonics representation to the real
!  l,m,s basis in real spherical harmonics representation
!
!  all subroutines have been taken from the Jülich-München code except for
!  "wavefunc_transpose"
!
! created July 2011 by Pascal Kordt
!
! calling:
! CALL SINGLE_TRANSFORM(LCUT,(LCUT+1)**2),RLL) 
!
! **************************************************************************

CONTAINS

  !       SUBROUTINE WAVEFUNC_TRANSFORM(LCUT,LMCUT,NRMAX,RLLVEC)
  ! 
  !       IMPLICIT NONE
  ! 
  !       INTEGER, INTENT(IN) :: LCUT, LMCUT, NRMAX
  !       INTEGER             :: RNUM
  !       DOUBLE COMPLEX          :: RLLVEC(LMCUT,LMCUT,NRMAX) 
  ! 
  ! !      DO RNUM=1,NRMAX
  !       CALL SINGLE_TRANSFORM(LCUT,LMCUT,RLLVEC(:,:,50))
  !       write(*,*) "alles in Budda"
  !       stop
  ! c      WRITE(*,*) RLLVEC(1,1,1)
  ! !      END DO
  ! 
  !       END SUBROUTINE

  SUBROUTINE RLL_TRANSFORM(RLL,lmaxatom,mode)
    IMPLICIT NONE
    DOUBLE COMPLEX :: RLL(:,:,:)
    INTEGER        :: lmaxatom
    CHARACTER (len=*) :: mode
    INTEGER        :: lmsize,ir,nrmax

    IF (MODE/='RLM>REL' .and. MODE/='REL>RLM') THEN
      STOP '[RLL_TRANSFORM] mode not known'
    END IF

    LMSIZE=2*(lmaxatom+1)**2

    IF ( 2*LMSIZE/=UBOUND(RLL,1) ) THEN 
      STOP '[BasisTransform] LMSIZE in RLL not equal'
    END IF
    IF (   LMSIZE/=UBOUND(RLL,2) ) THEN
      STOP '[BasisTransform] LMSIZE in RLL not equal'
    END IF

    NRMAX=UBOUND(RLL,3)

    DO IR=1,NRMAX
      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, RLL(1:lmsize,1:lmsize,ir),mode)
      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, RLL(lmsize+1:2*lmsize,1:lmsize,ir),mode)
    END DO

  END SUBROUTINE RLL_TRANSFORM

  SUBROUTINE VLL_TRANSFORM(VLL,lmaxatom)
    IMPLICIT NONE
    DOUBLE COMPLEX :: VLL(:,:,:)
    INTEGER        :: lmaxatom

    INTEGER        :: lmsize,ir,nrmax

    LMSIZE=2*(lmaxatom+1)**2

    IF ( 2*LMSIZE/=UBOUND(VLL,1) ) THEN 
      STOP '[BasisTransform] LMSIZE in VLL not equal'
    END IF
    IF (  2*LMSIZE/=UBOUND(VLL,2) ) THEN
      STOP '[BasisTransform] LMSIZE in VLL not equal'
    END IF

    NRMAX=UBOUND(VLL,3)

    DO IR=1,NRMAX
      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, VLL(1:lmsize,1:lmsize,ir),'RLM>REL')
      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, VLL(lmsize+1:2*lmsize,1:lmsize,ir),'RLM>REL')
      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, VLL(1:lmsize,lmsize+1:2*lmsize,ir),'RLM>REL')
      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, VLL(lmsize+1:2*lmsize,lmsize+1:2*lmsize,ir),'RLM>REL')
    END DO

  END SUBROUTINE VLL_TRANSFORM



  SUBROUTINE JLK_TRANSFORM(RLL,lmaxatom,loflm)
    IMPLICIT NONE
    DOUBLE COMPLEX,allocatable :: RLL(:,:)
    INTEGER        :: lmaxatom
    INTEGER        :: loflm(:)

    INTEGER        :: lmsize,ir,nrmax,LM
    DOUBLE COMPLEX, allocatable :: RLL2(:,:),RLL3(:,:)
    DOUBLE COMPLEX, allocatable :: MAT(:,:),MAT2(:,:)

    LMSIZE= 2*(lmaxatom+1)**2

    IF (2*LMSIZE/=ubound(LOFLM,1)) STOP '[WAVEFN2] loflm bound'
    NRMAX=ubound(RLL,2)

    ALLOCATE ( RLL2(LMSIZE,NRMAX),  RLL3(LMSIZE,NRMAX)  )
    ALLOCATE ( MAT (LMSIZE,LMSIZE), MAT2(LMSIZE,LMSIZE) )
    MAT=(0.0D0,0.0D0)
    MAT2=(0.0D0,0.0D0)

    DO IR=1,NRMAX
      DO LM=1,LMSIZE
        MAT(LM,LM)=RLL(LOFLM(LM),IR)
      END DO !LM
      DO LM=LMSIZE+1,2*LMSIZE
        MAT2(LM-LMSIZE,LM-LMSIZE)=RLL(LOFLM(LM),IR)
      END DO !LM

      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, MAT,'RLM>REL')

      call SINGLE_TRANSFORM(lmaxatom,(lmaxatom+1)**2, MAT2,'RLM>REL')

      DO LM=1,LMSIZE
        RLL2(LM,IR)=MAT(LM,LM)
      END DO !LM
      DO LM=1,LMSIZE
        RLL3(LM,IR)=MAT2(LM,LM)
      END DO !LM

      MAT=(0.0D0,0.0D0)
      MAT2=(0.0D0,0.0D0)

    END DO

    DEALLOCATE(RLL)
    ALLOCATE(RLL(2*LMSIZE,nrmax))

    DO IR=1,NRMAX
      DO LM=1,LMSIZE
        RLL(LM,IR)=RLL2(LM,IR)
      END DO !LM
      DO LM=LMSIZE+1,2*LMSIZE
        RLL(LM,IR)=RLL3(LM-LMSIZE,IR)
      END DO !LM
    END DO !IR

  END SUBROUTINE JLK_TRANSFORM



  SUBROUTINE SINGLE_TRANSFORM(LCUT,LMCUT,RLL,MODE)

    IMPLICIT NONE

    INTEGER, INTENT(IN) :: LCUT,LMCUT

    ! local variables
    INTEGER :: NLMAX,NKMMAX,NMUEMAX, NKMPMAX,NKMAX,LINMAX 

    DOUBLE COMPLEX :: RC(2*LMCUT,2*LMCUT), CREL(2*LMCUT,2*LMCUT), RREL(2*LMCUT,2*LMCUT), RLL_REL(2*LMCUT,2*LMCUT), RLL_NR(2*LMCUT,2*LMCUT), RLL(2*LMCUT,2*LMCUT)
    CHARACTER(LEN=7) :: MODE

    !       IF (.not. present(mode) ) mode='REL>RLM'
    !  prepare the transformation
    NLMAX     = LCUT+1 
    NKMMAX    = 2*NLMAX**2
    NMUEMAX   = 2*NLMAX
    NKMPMAX   = (NKMMAX+2*NLMAX)
    NKMAX     = 2*NLMAX-1
    LINMAX    = (2*NLMAX*(2*NLMAX-1))

    CALL DRVBASTRANS(RC,CREL,RREL,NLMAX,NKMMAX,NMUEMAX,NKMPMAX,NKMAX,LINMAX)

    RLL_REL=0.0d0
    RLL_NR=0.0d0

    ! Relativistic kappa-mu (REL, spin spherical harmonics)
    ! to real l-m basis (RLM, real spherical hamonics)

    CALL CHANGEREP(RLL(1,1),mode,RLL_NR(1,1), NKMMAX,NKMMAX,RC,CREL,RREL,'T_Real',0)

    RLL(:,:) = RLL_NR(:,:)

  END SUBROUTINE SINGLE_TRANSFORM



  SUBROUTINE CHANGEREP(A,MODE,B,N,M,RC,CREL,RREL,TEXT,LTEXT)
    !   ********************************************************************
    !   *                                                                  *
    !   *   change the representation of matrix A and store in B           *
    !   *   according to MODE:                                             *
    !   *                                                                  *
    !   *   RLM>REL   non-relat. REAL spher. harm.  >   (kappa,mue)        *
    !   *   REL>RLM   (kappa,mue)  > non-relat. REAL spher. harm.          *
    !   *   CLM>REL   non-relat. CMPLX. spher. harm.  >   (kappa,mue)      *
    !   *   REL>CLM   (kappa,mue)  > non-relat. CMPLX. spher. harm.        *
    !   *   RLM>CLM   non-relat. REAL spher. harm.  >  CMPLX. spher. harm. *
    !   *   CLM>RLM   non-relat. CMPLX. spher. harm.  >  REAL spher. harm. *
    !   *                                                                  *
    !   *   the non-relat. representations include the  spin index         *
    !   *                                                                  *
    !   *   for LTEXT > 0 the new matrix  B  is printed                    *
    !   *                                                                  *
    !   ********************************************************************
    
    IMPLICIT NONE
    
    ! PARAMETER definitions
    !
    DOUBLE COMPLEX C1,C0
    PARAMETER (C1=(1.0D0,0.0D0),C0=(0.0D0,0.0D0))
    
    ! Dummy arguments
    INTEGER LTEXT,M,N
    CHARACTER (len=7) MODE
    CHARACTER (len=*) :: TEXT
    DOUBLE COMPLEX A(M,M),B(M,M),CREL(M,M),RC(M,M),RREL(M,M)
    
    ! Local variables
    INTEGER KEY
    DOUBLE COMPLEX W1(M,M)

    !---------------------- transform MAT from (kappa,mue) to REAL (l,ml,ms)
    IF ( MODE.EQ.'REL>RLM' ) THEN
       CALL ZGEMM('N','N',N,N,N,C1,RREL,M,A,M,C0,W1,M)
       CALL ZGEMM('N','C',N,N,N,C1,W1,M,RREL,M,C0,B,M)
       KEY = 2
    ELSE IF ( MODE.EQ.'RLM>REL' ) THEN
       CALL ZGEMM('C','N',N,N,N,C1,RREL,M,A,M,C0,W1,M)
       CALL ZGEMM('N','N',N,N,N,C1,W1,M,RREL,M,C0,B,M)
       KEY = 3
    ELSE IF ( MODE.EQ.'REL>CLM' ) THEN
       CALL ZGEMM('N','N',N,N,N,C1,CREL,M,A,M,C0,W1,M)
       CALL ZGEMM('N','C',N,N,N,C1,W1,M,CREL,M,C0,B,M)
       KEY = 2
    ELSE IF ( MODE.EQ.'CLM>REL' ) THEN
       CALL ZGEMM('C','N',N,N,N,C1,CREL,M,A,M,C0,W1,M)
       CALL ZGEMM('N','N',N,N,N,C1,W1,M,CREL,M,C0,B,M)
       KEY = 3
    ELSE IF ( MODE.EQ.'CLM>RLM' ) THEN
       CALL ZGEMM('N','N',N,N,N,C1,RC,M,A,M,C0,W1,M)
       CALL ZGEMM('N','C',N,N,N,C1,W1,M,RC,M,C0,B,M)
       KEY = 2
    ELSE IF ( MODE.EQ.'RLM>CLM' ) THEN
       CALL ZGEMM('C','N',N,N,N,C1,RC,M,A,M,C0,W1,M)
       CALL ZGEMM('N','N',N,N,N,C1,W1,M,RC,M,C0,B,M)
       KEY = 2
    ELSE
       WRITE (*,*) ' MODE = ',MODE
       STOP 'in <ROTATE>  MODE not allowed'
    END IF
    
    ! show the input matrix
    !      IF ( LTEXT.GT.0 ) CALL CMATSTR(TEXT,LTEXT,A,N,M,KEY,KEY,0,1D-8,6)
    ! show the output matrix
    IF ( LTEXT.GT.0 ) CALL CMATSTR(TEXT,LTEXT,B,N,M,KEY,KEY,0,1D-8,6)
    !     IF ( LTEXT.GT.0 ) CALL CMATSTR(TEXT,LTEXT,B,N,M,KEY,KEY,0,1D-12,6)
  END SUBROUTINE



  SUBROUTINE BASTRMAT(LMAX,CGC,RC,CREL,RREL,NKMMAX,NKMPMAX)
    !   ********************************************************************
    !   *                                                                  *
    !   *    INITIALIZE TRANSFORMATION MATRIX THAT TAKES MATRICES FROM     *
    !   *    RELATIVISTIC  TO  REAL SPERICAL HARM.  REPRESENTATION         *
    !   *                                                                  *
    !   *    this is a special version of <STRSMAT> passing the            *
    !   *    full BASis TRansformation MATrices  RC, CREL and RREL         *
    !   *                                                                  *
    !   * 13/01/98  HE                                                     *
    !   ********************************************************************
    IMPLICIT NONE

    ! PARAMETER definitions
    DOUBLE COMPLEX CI,C1,C0
    PARAMETER (CI=(0.0D0,1.0D0),C1=(1.0D0,0.0D0),C0=(0.0D0,0.0D0))
    ! Dummy arguments
    INTEGER LMAX,NKMMAX,NKMPMAX
    DOUBLE PRECISION  CGC(NKMPMAX,2)
    DOUBLE COMPLEX CREL(NKMMAX,NKMMAX),RC(NKMMAX,NKMMAX), RREL(NKMMAX,NKMMAX)
    ! Local variables
    INTEGER I,IKM,J,JP05,K,L,LM,LNR,M,MUEM05,MUEP05,NK,NKM,NLM
    DOUBLE PRECISION  W

    NK = 2*(LMAX+1) + 1
    NLM = (LMAX+1)**2
    NKM = 2*NLM
    !     ===================================================
    !     INDEXING:
    !     IKM  = L*2*(J+1/2) + J + MUE + 1
    !     LM   = L*(L+1)     +     M   + 1
    !     ===================================================
    !
    ! ----------------------------------------------------------------------
    ! CREL  transforms from  COMPLEX (L,M,S)  to  (KAP,MUE) - representation
    !                 |LAM> = sum[LC] |LC> * CREL(LC,LAM)
    ! ----------------------------------------------------------------------
    CALL CINIT(NKMMAX*NKMMAX,CREL)
    
    LM = 0
    DO LNR = 0,LMAX
       DO M = -LNR,LNR
          LM = LM + 1
    
          IKM = 0
          DO K = 1,NK
             L = K/2
             IF ( 2*L.EQ.K ) THEN
                JP05 = L
             ELSE
                JP05 = L + 1
             END IF
    
             DO MUEM05 = -JP05,(JP05-1)
                MUEP05 = MUEM05 + 1
                IKM = IKM + 1
    
                IF ( L.EQ.LNR ) THEN
                   IF ( MUEP05.EQ.M ) CREL(LM,IKM) = CGC(IKM,1)
                   IF ( MUEM05.EQ.M ) CREL(LM+NLM,IKM) = CGC(IKM,2)
                END IF
    
             END DO
          END DO
    
       END DO
    END DO
    
    ! ----------------------------------------------------------------------
    !    RC  transforms from  REAL to  COMPLEX (L,M,S) - representation
    !                 |LC> = sum[LR] |LR> * RC(LR,LC)
    ! ----------------------------------------------------------------------
    CALL CINIT(NKMMAX*NKMMAX,RC)
    
    W = 1.0D0/SQRT(2.0D0)
    
    DO L = 0,LMAX
       DO M = -L,L
          I = L*(L+1) + M + 1
          J = L*(L+1) - M + 1
    
          IF ( M.LT.0 ) THEN
             RC(I,I) = -CI*W
             RC(J,I) = W
             RC(I+NLM,I+NLM) = -CI*W
             RC(J+NLM,I+NLM) = W
          END IF
          IF ( M.EQ.0 ) THEN
             RC(I,I) = C1
             RC(I+NLM,I+NLM) = C1
          END IF
          IF ( M.GT.0 ) THEN
             RC(I,I) = W*(-1.0D0)**M
             RC(J,I) = CI*W*(-1.0D0)**M
             RC(I+NLM,I+NLM) = W*(-1.0D0)**M
             RC(J+NLM,I+NLM) = CI*W*(-1.0D0)**M
          END IF
       END DO
    END DO
    
    ! ----------------------------------------------------------------------
    ! RREL  transforms from   REAL (L,M,S)  to  (KAP,MUE) - representation
    !                 |LAM> = sum[LR] |LR> * RREL(LR,LAM)
    ! ----------------------------------------------------------------------
    
    CALL ZGEMM('N','N',NKM,NKM,NKM,C1,RC,NKMMAX,CREL,NKMMAX,C0,RREL, NKMMAX)
  
  END SUBROUTINE




  SUBROUTINE CALCCGC(LTAB,KAPTAB,NMUETAB,CGC,NKMAX,NMUEMAX,NKMPMAX)
    !   ********************************************************************
    !   *                                                                  *
    !   *   CLEBSCH-GORDON-COEFFICIENTS     CGC(IKM,IS)                    *
    !   *                                                                  *
    !   *   IKM NUMBERS  CGC  FOR INCREASING  K  AND  MUE                  *
    !   *   IKM  = L*2*(J+1/2) + J + MUE + 1                               *
    !   *   IS= 1/2  SPIN DOWN/UP                                          *
    !   *                                                                  *
    !   ********************************************************************
    IMPLICIT NONE
    
    ! Dummy arguments
    INTEGER NKMAX,NKMPMAX,NMUEMAX
    DOUBLE PRECISION  CGC(NKMPMAX,2)
    INTEGER KAPTAB(NMUEMAX),LTAB(NMUEMAX),NMUETAB(NMUEMAX)
    ! Local variables
    INTEGER IKM,K,KAPPA,M
    DOUBLE PRECISION  J,L,MUE,TWOLP1
    
    IKM = 0
    DO K = 1,(NKMAX+1)
       L = LTAB(K)
       KAPPA = KAPTAB(K)
       J = ABS(KAPPA) - 0.5D0
       MUE = -J - 1.0D0
       TWOLP1 = 2.0D0*L + 1.0D0
    
       IF ( KAPPA.LT.0 ) THEN
          ! J = L + 1/2
          DO M = 1,NMUETAB(K)
    
             MUE = MUE + 1.0D0
             IKM = IKM + 1
             CGC(IKM,1) = DSQRT((L-MUE+0.5D0)/TWOLP1)
             CGC(IKM,2) = DSQRT((L+MUE+0.5D0)/TWOLP1)
          END DO
       ELSE
          ! J = L - 1/2
          DO M = 1,NMUETAB(K)
    
             MUE = MUE + 1.0D0
             IKM = IKM + 1
             CGC(IKM,1) = DSQRT((L+MUE+0.5D0)/TWOLP1)
             CGC(IKM,2) = -DSQRT((L-MUE+0.5D0)/TWOLP1)
    
          END DO
       END IF
    
    
    END DO
  
  END SUBROUTINE



  SUBROUTINE DRVBASTRANS(RC,CREL,RREL, NLMAX,NKMMAX,NMUEMAX,NKMPMAX,NKMAX,LINMAX)
    IMPLICIT NONE
    ! Dummy arguments
    INTEGER LINMAX,NKMAX,NKMMAX,NKMPMAX,NLMAX,NMUEMAX
    DOUBLE COMPLEX CREL(NKMMAX,NKMMAX),RC(NKMMAX,NKMMAX), RREL(NKMMAX,NKMMAX)
    
    ! Local variables
    DOUBLE PRECISION  CGC(NKMPMAX,2)
    INTEGER I,IL,IMUE,IPRINT, KAPTAB(NMUEMAX),LTAB(NMUEMAX),MMAX,NMUETAB(NMUEMAX),  NSOLLM(NLMAX,NMUEMAX)

    IF (NKMMAX.NE.2*NLMAX**2) STOP ' Check NLMAX,NKMMAX in < DRVBASTRANS > '
    IF (NMUEMAX.NE.2*NLMAX) STOP ' Check NLMAX,NMUEMAX in < DRVBASTRANS > '
    IF (NKMPMAX.NE.(NKMMAX+2*NLMAX)) STOP ' Check NLMAX,NKMMAX,NKMPMAX in < DRVBASTRANS > '
    IF (NKMAX.NE.2*NLMAX-1) STOP ' Check NLMAX,NKMAX in < DRVBASTRANS > '
    IF (LINMAX.NE.(2*NLMAX*(2*NLMAX-1))) STOP ' Check NLMAX,LINMAX in < DRVBASTRANS > '
    
    IPRINT = 0
    
    DO I = 1,NMUEMAX
       LTAB(I) = I/2
       IF ( 2*LTAB(I).EQ.I ) THEN
          KAPTAB(I) = LTAB(I)
       ELSE
          KAPTAB(I) = -LTAB(I) - 1
       END IF
       NMUETAB(I) = 2*ABS(KAPTAB(I))
    END DO
    
    DO IL = 1,NLMAX
       MMAX = 2*IL
       DO IMUE = 1,MMAX
          IF ( (IMUE.EQ.1) .OR. (IMUE.EQ.MMAX) ) THEN
             NSOLLM(IL,IMUE) = 1
          ELSE
             NSOLLM(IL,IMUE) = 2
          END IF
       END DO
    END DO
    
    !      CALL IKMLIN(IPRINT,NSOLLM,IKM1LIN,IKM2LIN,NLMAX,NMUEMAX,LINMAX,
    !     &            NLMAX)
    
    CALL CALCCGC(LTAB,KAPTAB,NMUETAB,CGC,NKMAX,NMUEMAX,NKMPMAX)
    
    ! ---------------------------- now calculate the transformation matrices
    !
    !      CALL STRSMAT(NLMAX-1,CGC,SRREL,NRREL,IRREL,NKMMAX,NKMPMAX)
    
    CALL BASTRMAT(NLMAX-1,CGC,RC,CREL,RREL,NKMMAX,NKMPMAX)
    
    RETURN
  END SUBROUTINE DRVBASTRANS




  SUBROUTINE CINIT(N,A)
    !-----------------------------------------------------------------------
    !     initialize the first n values of a complex array a with zero
    !-----------------------------------------------------------------------
    !     .. Scalar Arguments ..
    INTEGER N
    !     .. Array Arguments ..
    DOUBLE COMPLEX A(*)
    !     .. Local Scalars ..
    INTEGER I
    DOUBLE COMPLEX CZERO
    parameter(CZERO=(0.0d0,0.0d0))
    !     ..
    DO I = 1,N
      A(I) = CZERO
    END DO
  END SUBROUTINE CINIT



  SUBROUTINE CMATSTR(STR,LSTR,A,N,M,MLIN,MCOL,IJQ,TOLP,K_FMT_FIL)
    !   ********************************************************************
    !   *                                                                  *
    !   *   writes structure of COMPLEX   NxN   matrix   A                 *
    !   *                                                                  *
    !   *   M           is the actual array - size used for   A            *
    !   *   MLIN/COL    MODE for line and column indexing                  *
    !   *               0: plain, 1: (l,ml), 2: (l,ml,ms), 3: (kap,mue)    *
    !   *   TOL         tolerance for difference                           *
    !   *   IJQ         if IJQ > 1000    pick  IQ-JQ-block matrix          *
    !   *               assuming  IJQ = IQ*1000 + JQ                       *
    !   *               else: no IQ-JQ-indexing                            *
    !   *   K_FMT_FIL   output channel                                     *
    !   *               a negative sign suppresses table at the end        *
    !   *                                                                  *
    !   *   any changes should be done in RMATSTR as well !!!!!!!!!!!!!!!  *
    !   *                                                                  *
    !   ********************************************************************
    IMPLICIT NONE

    ! PARAMETER definitions
    DOUBLE COMPLEX CI
    PARAMETER (CI=(0.0D0,1.0D0))
    ! Dummy arguments
    INTEGER IJQ,K_FMT_FIL,LSTR,M,MCOL,MLIN,N
    CHARACTER (len=*) :: STR
    DOUBLE PRECISION  TOLP
    DOUBLE COMPLEX A(M,M)
    ! Local variables
    DOUBLE COMPLEX B(N,N),CA,CB,ARG,DTAB(0:N*N)
    CHARACTER CHAR
    LOGICAL SAME,SMALL
    CHARACTER (len=1) CTAB(0:N*N),VZ(-1:+1)
    DOUBLE PRECISION DBLE
    CHARACTER (len=150) FMT1,FMT2,FMT3,FMT4
    INTEGER I,I1,IC0,ID,IL,ILSEP(20),IPT(218),IQ,ISL,IW(M),J,J0,JP,JQ,K,L3,LF,MM,N1,N2,N3,NC,ND,NFIL,NK,NM,NM1,NM2,NM3,NNON0,NSL
    INTEGER ICHAR,ISIGN,NINT
    DOUBLE PRECISION  TOL

    DATA VZ/'-',' ',' '/

    SMALL(ARG) = ABS(ARG*TOL).LT.1.0D0

    SAME(CA,CB) = SMALL(1.0D0-CA/CB)

    NFIL = ABS(K_FMT_FIL)

    TOL = 1.0D0/TOLP

    !----------------------------------------------- set block indices IQ JQ

    IF ( IJQ.GT.1000 ) THEN
       IQ = IJQ/1000
       JQ = IJQ - IQ*1000
       IF ( IQ*N.GT.M .OR. IQ*N.GT.M ) THEN
          WRITE (6,99002) IJQ,IQ,JQ,IQ*N,JQ*N,N,M
          RETURN
       END IF
    ELSE
       IQ = 1
       JQ = 1
    END IF

    !----------------------------------------------------- copy matrix block

    J0 = N*(JQ-1)
    DO J = 1,N
       I1 = N*(IQ-1)+1
       JP = J0 + J
       CALL ZCOPY(N,A(I1,JP),1,B(1,J),1)
    END DO

    !------------------------------------------------ set up character table

    NC = 0
    DO I = 1,26
       NC = NC + 1
       IPT(NC) = 62 + I
    END DO
    DO I = 1,8
       NC = NC + 1
       IPT(NC) = 96 + I
    END DO
    DO I = 10,26
       NC = NC + 1
       IPT(NC) = 96 + I
    END DO
    DO I = 191,218
       NC = NC + 1
       IPT(NC) = I
    END DO
    DO I = 35,38
       NC = NC + 1
       IPT(NC) = I
    END DO
    DO I = 40,42
       NC = NC + 1
       IPT(NC) = I
    END DO
    DO I = 91,93
       NC = NC + 1
       IPT(NC) = I
    END DO

    !---------------------------------------------------------------- header
    IC0 = ICHAR('0')
    N3 = N/100
    N2 = N/10 - N3*10
    N1 = N - N2*10 - N3*100

    IF ( N.LE.18 ) THEN
       FMT1 = '(8X,I3,''|'','
       FMT2 = '( 9X,''--|'','
       FMT3 = '( 9X,'' #|'','
       FMT4 = '( 9X,''  |'','
    ELSE
       FMT1 = '(   I4,''|'','
       FMT2 = '( 2X,''--|'','
       FMT3 = '( 2X,'' #|'','
       FMT4 = '( 2X,''  |'','
    END IF

    LF = 11
    L3 = 11
    IF ( MCOL.EQ.0 ) THEN
       FMT1 = FMT1(1:LF)//CHAR(IC0+N3)//CHAR(IC0+N2)//CHAR(IC0+N1)//'( 2A1),''|'',I3)'
       FMT2 = FMT2(1:LF)//CHAR(IC0+N3)//CHAR(IC0+N2)//CHAR(IC0+N1)//'(''--''),''|'',I3)'
       FMT3 = FMT3(1:LF)//'60(2X,I2))'
       FMT4 = FMT4(1:LF)//'60(I2,2X))'
       LF = 21
    ELSE
       IF ( MCOL.EQ.1 ) THEN
          NK = NINT(SQRT(DBLE(N)))
       ELSE IF ( MCOL.EQ.2 ) THEN
          NK = NINT(SQRT(DBLE(N/2)))
       ELSE IF ( MCOL.EQ.3 ) THEN
          NK = 2*NINT(SQRT(DBLE(N/2))) - 1
       END IF
       DO K = 1,NK
          IF ( MCOL.LE.2 ) THEN
             NM = 2*K - 1
          ELSE
             NM = 2*((K+1)/2)
          END IF
          NM2 = NM/10
          NM1 = NM - NM2*10
          NM3 = NM/2
          FMT1 = FMT1(1:LF)//CHAR(IC0+NM2)//CHAR(IC0+NM1)//'( 2A1),''|'','
          FMT2 = FMT2(1:LF)//CHAR(IC0+NM2)//CHAR(IC0+NM1)//'(''--''),''|'','

          IF ( MCOL.LE.2 ) THEN
             DO MM = 1,NM
                IF ( MOD(MM,2).EQ.MOD(K,2) ) THEN
                   FMT3 = FMT3(1:L3)//'2X,'
                   FMT4 = FMT4(1:L3)//'I2,'
                ELSE
                   FMT3 = FMT3(1:L3)//'I2,'
                   FMT4 = FMT4(1:L3)//'2X,'
                END IF
                L3 = L3 + 3
             END DO
             FMT3 = FMT3(1:L3)//'''|'','
             FMT4 = FMT4(1:L3)//'''|'','
             L3 = L3 + 4
          ELSE
             FMT3 = FMT3(1:LF)//CHAR(IC0+NM3)//'(2X,I2),''|'','
             FMT4 = FMT4(1:LF)//CHAR(IC0+NM3)//'(I2,2X),''|'','
             L3 = L3 + 13
          END IF
          LF = LF + 13
       END DO
       IF ( MCOL.EQ.2 ) THEN
          FMT1 = FMT1(1:LF)//FMT1(12:LF)
          FMT2 = FMT2(1:LF)//FMT2(12:LF)
          FMT3 = FMT3(1:L3)//FMT3(12:L3)
          FMT4 = FMT4(1:L3)//FMT4(12:L3)
          LF = 2*LF - 11
          L3 = 2*L3 - 11
       END IF
       FMT1 = FMT1(1:LF)//'I3)'
       FMT2 = FMT2(1:LF)//'I3)'
       FMT3 = FMT3(1:L3)//'I3)'
       FMT4 = FMT4(1:L3)//'I3)'
    END IF
    IF ( MLIN.EQ.0 ) THEN
       NSL = 1
       ILSEP(1) = N
    ELSE IF ( MLIN.EQ.1 ) THEN
       NSL = NINT(SQRT(DBLE(N)))
       DO IL = 1,NSL
          ILSEP(IL) = IL**2
       END DO
    ELSE IF ( MLIN.EQ.2 ) THEN
       NSL = NINT(SQRT(DBLE(N/2)))
       DO IL = 1,NSL
          ILSEP(IL) = IL**2
       END DO
       DO IL = 1,NSL
          ILSEP(NSL+IL) = ILSEP(NSL) + IL**2
       END DO
       NSL = 2*NSL
    ELSE IF ( MLIN.EQ.3 ) THEN
       NSL = 2*NINT(SQRT(DBLE(N/2))) - 1
       ILSEP(1) = 2
       DO K = 2,NSL
          ILSEP(K) = ILSEP(K-1) + 2*((K+1)/2)
       END DO
    END IF


    WRITE (NFIL,99001) STR(1:LSTR)
    IF ( IJQ.GT.1000 ) WRITE (NFIL,99003) IQ,JQ
    WRITE (NFIL,FMT3) (I,I=2,N,2)
    WRITE (NFIL,FMT4) (I,I=1,N,2)
    WRITE (NFIL,FMT=FMT2)
    !------------------------------------------------------------ header end
    NNON0 = 0
    ND = 0
    CTAB(0) = ' '
    DTAB(0) = 9999D0

    DO I = 1,N
       DO J = 1,N
          IF ( .NOT.SMALL(B(I,J)) ) THEN
             NNON0 = NNON0 + 1
             DO ID = 1,ND
                IF ( SAME(B(I,J),+DTAB(ID)) ) THEN
                   IW(J) = +ID
                   GOTO 50
                END IF
                IF ( SAME(B(I,J),-DTAB(ID)) ) THEN
                   IW(J) = -ID
                   GOTO 50
                END IF
             END DO
    !----------------------------------------------------------- new element
             ND = ND + 1
             IW(J) = ND
             DTAB(ND) = B(I,J)
             IF ( ABS(DTAB(ND)-1.0D0)*TOL.LT.1.0D0 ) THEN
                CTAB(ND) = '1'
             ELSE IF ( ABS(DTAB(ND)+1.0D0)*TOL.LT.1.0D0 ) THEN
                DTAB(ND) = +1.0D0
                CTAB(ND) = '1'
                IW(J) = -ND
             ELSE IF ( ABS(DTAB(ND)-CI)*TOL.LT.1.0D0 ) THEN
                CTAB(ND) = 'i'
             ELSE IF ( ABS(DTAB(ND)+CI)*TOL.LT.1.0D0 ) THEN
                DTAB(ND) = +CI
                CTAB(ND) = 'i'
                IW(J) = -ND
             ELSE
                CTAB(ND) = CHAR(IPT(1+MOD((ND+1),NC)))
             END IF
          ELSE
             IW(J) = 0
          END IF
    50      END DO
    !------------------------------------------------------------ write line
       WRITE (NFIL,FMT=FMT1) I, (VZ(ISIGN(1,IW(J))),CTAB(ABS(IW(J))),J=1, N),I

       DO ISL = 1,NSL
          IF ( I.EQ.ILSEP(ISL) ) WRITE (NFIL,FMT=FMT2)
       END DO
    END DO

    !------------------------------------------------------------------ foot
    WRITE (NFIL,FMT4) (I,I=1,N,2)
    WRITE (NFIL,FMT3) (I,I=2,N,2)

    IF ( K_FMT_FIL.GT.0 ) THEN
       WRITE (NFIL,99004) (ID,CTAB(ID),DTAB(ID),ID=1,ND)
       WRITE (NFIL,99005) NNON0,TOLP,N*N - NNON0,TOLP
    ELSE
       WRITE (NFIL,*) ' '
    END IF

    99001 FORMAT (/,8X,A,/)
    99002 FORMAT (/,1X,79('*'),/,10X,'inconsistent call of <CMATSTR>',/,10X, 'argument IJQ =',I8,'  implies IQ=',I3,'   JQ=',I3,/,10X, 'IQ*N=',I6,' > M   or   JQ*N=',I6,' > M   for N =',I4, ' M=',I4,/,1X,79('*'),/)
    99003 FORMAT (8X,'IQ-JQ-block  for  IQ = ',I3,'   JQ = ',I3,/)
    99004 FORMAT (/,8X,'symbols used:',/,(8X,I3,3X,A1,2X,2F20.12))
    99005 FORMAT (/,8X,I5,' elements   >',1PE9.1,/, 8X,I5,' elements   <',1PE9.1,/)
  END SUBROUTINE CMATSTR

END MODULE