!
! Copyright (C) 2017- Orbital-free DFT group at University of Florida
!
! This program is free software; you can redistribute it and/or modify 
! it under the terms of the GNU General Public License as published by 
! the Free Software Foundation; either version 2 of the License, or 
! any later version. See the file LICENSE in the root directory of the 
! present distribution, or http://www.gnu.org/copyleft/gpl.txt ,
! or contact developers via e-mail: calderin@lcalderin.net, or paper mail:
!
! Quantum Theory Project
! University of Florida
! P.O. Box 118435
! Gainesville, FL 32611
!
! This program is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.
! 
! Authors: Lazaro Calderin and Valentin Karasiev
!-----------------------------------------------------------------------
! 


module kgecvars
! kgec input and common variables

use kinds, ONLY : DP

!#if defined(__QE512) || defined(__QE52) || defined( __QE54 )
#if defined(__QE6) || defined(__QE62) || defined(__QE64)
use qevars, ONLY : prefix, stdout, ELECTRON_SI, H_PLANCK_SI, tpi,           &
                   ELECTRONMASS_SI, BOHR_RADIUS_SI, HARTREE_SI, pi, &
                   AUTOEV, conv_thr
#endif

!#if defined(__QE6) || defined(__QE62)
#if defined(__QE512) || defined(__QE52) || defined( __QE54 )
use qevars, ONLY : prefix, outdir, stdout, ELECTRON_SI, H_PLANCK_SI, tpi,   &
                   ELECTRONMASS_SI, BOHR_RADIUS_SI, HARTREE_SI, pi, &
                   AUTOEV, conv_thr 
#endif

implicit none

   ! ================ Input variables

   character(len=6) :: calculation = 'atrace' ! Cal. tensor or average trace
   
   logical :: ac = .true.                ! Frequency dependent sigma1
                                         ! (Alternating current) 
   logical :: dc = .true.                ! Direct current conductivity            

   logical :: &
   sigma1_exact   = .true.   ! Use approximated or exact formula
   logical :: &
   decomposition  = .true.   ! Separate contributions into 
                                                 ! intra-bands, degeneracies and 
                                                 ! inter-bands for sigma1

   logical :: calculate_sigma2   = .false. ! Cal. imaginary part of the conduct.
   logical :: calculate_epsilon1 = .false. ! Cal. real part of the dielectric
   logical :: calculate_epsilon2 = .false. ! Cal. imaginary part of the dielec.
   logical :: calculate_rrae     = .false. ! Cal. refraction,reflection,absorp.

   !  character(len=1) :: dc_all = 'n'      ! n=do not do dc calculations using
                                         ! all formulas for both Lorentzian
                                         ! and Gaussian delta representations.
                                         ! w=do it using same deltawidth for 
                                         ! both a Lorentzian and a Gaussian.
                                         ! h=do it matching Gaussian heigth  
                                         ! to the Lorentzian's.
                                         ! f=do it matching the Gaussian FWHM 
                                         ! to the Lorentzian's.
                                         ! a=do the three cases

   logical :: sigma1_notintra = .false.  ! Do not include intrabands
                                         ! contributions in the
                                         ! sigma1 with exact formula.

   logical :: sigma2_notintra = .false.  ! Do not include intrabands 
                                         ! contributions in sigma2.
                                         
   ! Checking options
   logical :: check_wfc   = .false. ! Check the orthogonality of wavefunctions
   logical :: check_delta = .false. ! Compare the effect of Lorentzians and 
                                   ! Gaussians as delta functions

   ! Overriding options
   logical :: non_local   = .false. ! Use a norm-conserving pseudo even when 
                                    ! the non-local corrections 
                                    ! are not implemented

   logical :: yessym      = .false. ! Over ride the no use of symmetry
   logical :: yesinv      = .false. ! Over ride the no use of inversion symm.

   logical :: writegm     = .false.  ! Read gradient matrix elements if true, else
                                    ! calculate them
   logical :: readgm      = .false. ! Read gradient matrix elements if true, else
                                    ! calculate them

   logical :: npwrecover  = .false. ! If .true., recover cores used in pw 
                                    ! parallelization to use them in the bands
                                    ! parallelization.

   ! delta function and frequency grid variables
   character(len=4) :: deltarep    = '2l' ! Representation for the delta function
                                          ! and use of ( s(w) + s(-w) )/2: 
                                          ! '1l' one for a Lorentzian, 
                                          ! '2l' one for Lorentzians, 
                                          ! '1g' for a Gaussian,
                                          ! '2g' for two Gaussians.
   real(DP) :: deltawidth  = 0.01_DP      ! Width of the representation of the 
                                          ! Dirac delta function in eV
   integer  :: nw   = 1000                ! Number of frequency points
   real(DP) :: wmin = 0.01_DP              ! Minimum frequency in eV (fixed)
   real(DP) :: wmax = 5.0_DP              ! Maximum frequency in eV
   real(DP), allocatable :: wgrid(:)      ! Frequency grid
   real(DP) :: de = 0.0_DP                ! Two energies are equal if the absolute 
                                          ! difference is
                                          ! less than this number (in eV)

   ! Also from QE: outdir (QE<6) or tmp_dir (QE>=6), prefix

   ! ================ End of input variables

   ! Other common variables
#if defined(__QE6) || defined(__QE62) || defined(__QE64)
   character(256) :: outdir ! outdir not defined in QE 6.0
#endif

   ! Gradient matrix elements ( defined and calculated in the main program )
   complex(DP), allocatable    :: psi_grad_psi(:,:,:,:)

   real(DP) :: dw                         ! Frequency step
   real(DP) :: sa                         ! Lorentzian width (delta function)
   real(DP) :: sg                         ! Gaussian width (delta function)

   integer  :: iaux=0 ! To remove the zero frequency in the approx gaussian case 
                      ! (iaux=first argument of frequency higher than 10^-12 ev)

   character(256) :: fname  ! for file names

   integer :: ios, ierr     ! Input and memory allocation error status variables

   ! Variables to recover the plane waves cores and use them in the bands
   ! parallelization
   integer                  :: nproc_kp, nproc_bands, nproc_pw,                &
                               nbnds_local, nbnds_per_process, nbnds_per_group,&
                               my_rank, my_rank_old, my_group
   

   ! \sigma in S.I. : (ohm*meter)^-1
   ! The prefactor for \sigma is
   !    2 \pi e^2 \hbar^3 / (m_e^2 \omega)
   ! That is 2 Pi electron_charge^2 hbar^3/ electron_mass^2 /volume_unit_cell
   ! Ha atomic units are used until here (see kgsigma1 and kgsigma2 modules),
   ! in those units the prefactor is
   ! 2 / \omega
   ! so we have to multiply by
   ! e^2 \hbar^3 / m_e^2 in SI units
   ! and convert the Ha atomic units to SI

   real(DP), parameter :: AU_TO_OHMM_INV = &    ! Conductivity AU to 1/(ohm m)
    ELECTRON_SI**2 * (H_PLANCK_SI/tpi)**3 / ELECTRONMASS_SI**2 &
    / BOHR_RADIUS_SI**3  &                  ! \Omega from bohr^3 to meter^3
    / HARTREE_SI         &                  ! \hbar w in Ha to J
    / BOHR_RADIUS_SI**2  &                  ! \nabla^2 in 1/Bohr^2 to 1/meter^2
    / HARTREE_SI                            ! terms of the form a/(x^2+b^2)
                                            ! in 1/Ha to 1/J

   logical :: sigma2_via_eps1mod   ! calculate sigma2 from sigma2/w through
                                   ! kgepsilon1 module. (Avoid duplicated calc.)
   
                               
contains

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

subroutine kgecvars_check
use qevars, ONLY : mp_bcast, ionode_id, world_comm, tmp_dir
use apawgm, ONLY : use_real_spherical_harm

   call mp_bcast( tmp_dir, ionode_id, world_comm )        
   call mp_bcast( outdir,  ionode_id, world_comm )        
   call mp_bcast( prefix,  ionode_id, world_comm )
   call mp_bcast( calculation, ionode_id, world_comm )        
   call mp_bcast( dc, ionode_id, world_comm )
   call mp_bcast( ac, ionode_id, world_comm )
   call mp_bcast( sigma1_exact, ionode_id, world_comm )
   call mp_bcast( decomposition, ionode_id, world_comm )
   call mp_bcast( calculate_sigma2, ionode_id, world_comm )
   call mp_bcast( calculate_epsilon1, ionode_id, world_comm )
   call mp_bcast( calculate_epsilon2, ionode_id, world_comm )
   call mp_bcast( calculate_rrae, ionode_id, world_comm )
   call mp_bcast( sigma1_notintra, ionode_id, world_comm )
   call mp_bcast( sigma2_notintra, ionode_id, world_comm )
   call mp_bcast( check_wfc, ionode_id, world_comm ) 
   call mp_bcast( check_delta, ionode_id, world_comm )
   call mp_bcast( non_local, ionode_id, world_comm ) 
   call mp_bcast( yessym, ionode_id, world_comm ) 
   call mp_bcast( yesinv, ionode_id, world_comm ) 
   call mp_bcast( writegm, ionode_id, world_comm )
   call mp_bcast( readgm, ionode_id, world_comm )
   call mp_bcast( npwrecover, ionode_id, world_comm )
   call mp_bcast( deltarep, ionode_id, world_comm ) 
   call mp_bcast( deltawidth, ionode_id, world_comm )
   call mp_bcast( nw, ionode_id, world_comm )
   call mp_bcast( wmin, ionode_id, world_comm )
   call mp_bcast( wmax, ionode_id, world_comm )
   call mp_bcast( de, ionode_id, world_comm )
   call mp_bcast( use_real_spherical_harm, ionode_id, world_comm )
   call mp_bcast( sigma2_via_eps1mod, ionode_id, world_comm )
!   call mp_bcast( dc_all, ionode_id, world_comm )

   select case ( calculation )
    case('TENSOR','tensor')
      calculation = 'tensor'
    case('atrace', 'ATRACE')
      calculation = 'atrace'
    case default
      call errore( 'kgecvars','set calculation to either tensor or atrace', 7 )
   end select

   select case ( deltarep )
    case( 'l', 'L', '1l', '1L' )
      deltarep = '1l'
    case('2l', '2L' )
      deltarep = '2l'
    case( 'g', 'G', '1g', '1G' )
      deltarep = '1g'
    case( '2g', '2G' )
      deltarep = '2g'
    case default
      call errore( 'kgecvars','set deltarep to either l or g, 2l or 2g', 8 )
   end select

   select case ( ac )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set ac to either .true. or .false.', 8 )
   endselect 

   select case ( dc )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set dc to either .true. or .false.', 8 )
   endselect 

   if( (ac .eqv. .false.) .and. (dc .eqv. .false.) ) then
      call errore( 'kgecvars','ac and dc can not be both .false.', 8 )
   endif

   select case ( calculate_sigma2 )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set calculate_sigma2 to either .true. or .false.', 8 )
   endselect 

   select case ( calculate_epsilon1 )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set calculate_epsilon1 to either .true. or .false.', 8 )
   endselect 

   select case ( calculate_epsilon1 )
   case( .true. )  
      if( .not. calculate_sigma2 ) calculate_sigma2=.true.
   endselect 

   select case ( calculate_epsilon2 )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set calculate_epsilon2 to either .true. or .false.', 8 )
   endselect 

   select case ( calculate_rrae )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set calculate_rrae to either .true. or .false.', 8 )
   endselect 

   select case ( calculate_rrae )
   case( .true. )

      if ( .not. calculate_epsilon1   ) then
         write(stdout, '(A)') &
         ' Warning: calculate_rrae=.true. so changing calculate_epsilon1  to .true.'
        calculate_epsilon1 = .true.

        if ( .not. calculate_sigma2 ) then 
           write(stdout, '(A)') &
           ' Warning: calculate_rrae=.true. so changing calculate_sigma2  to .true.'
           calculate_sigma2 = .true.
        endif

      endif

      if ( .not. calculate_epsilon2   ) then
         write(stdout, '(A)') &
         ' Warning: calculate_rrae=.true. so changing calculate_epsilon2  to .true.'
        calculate_epsilon2 = .true.
      endif

   endselect 
        
   select case ( sigma1_notintra )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set sigma1_notintra to either .true. or .false.', 8 )
   endselect         

   select case ( sigma2_notintra )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set sigma2_notintra to either .true. or .false.', 8 )
   endselect         

   select case ( check_wfc )
   case( .true., .false.)
   case default
      call errore( 'kgecvars','set check_wfc to either .true. or .false.', 8 )
   endselect 

   select case ( check_delta )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set check_delta to either .true. or .false.', 8 )
   endselect 

   select case ( non_local )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set non_local to either .true. or .false.', 8 )
   endselect 

   select case ( yessym )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set yessym to either .true. or .false.', 8 )
   endselect 

   select case ( yesinv )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set yesinv to either .true. or .false.', 8 )
   endselect 

   if ( writegm .and. readgm ) then
      call errore( 'kgecvars','set writegm and readgm can not be both to .true.', 11 )
   endif

   select case ( writegm )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set writegm to either .true. or .false.', 8 )
   endselect 

   select case ( readgm )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set readgm to either .true. or .false.', 8 )
   endselect 

   select case ( npwrecover )
   case( .true.,  .false.)
   case default
      call errore( 'kgecvars','set npwrecover to either .true. or .false.', 8 )
   endselect 

   if ( .not. sigma1_exact ) then

      if ( decomposition ) then
         call errore( &
         'kgecvars','Decomposition not possible for the approximated formula. ', 9)
      endif

      if ( sigma1_notintra ) then
         call errore(&
  'kgecvars','sigma1_notintra=.true. only for the exact formula (sigma1_exact=.true.) ', 10)
      endif      
   
   endif  

   if( mod(nw,2) /= 0 ) then
      call errore( 'kgecvars','nw must be even', 11 )
   endif

   if ( calculate_sigma2 .and. calculate_epsilon1 ) then
      sigma2_via_eps1mod = .true.
      calculate_sigma2   = .false.
   endif

   if ( (sigma1_notintra .or. sigma2_notintra) .and. decomposition ) then
      call errore(& 
      'kgecvars','sigma1_notintra=.true. or sigma2_notintra=.true. &
       and decomposition=.true. not possible', 11 )
   endif 

!   select case( dc_all )
!   case( 'n','N','No','no' )
!      dc_all='n'
!   case( 'w', 'W' ) ! same widths means the deltawidths given is used directly as
!      dc_all='w'    ! 1/deltawidth for the gaussian exponent
!   case( 'h', 'H' )
!      dc_all='h'  
!   case( 'f', 'F' )
!      dc_all='f'
!   case( 'all', 'a', 'A', 'ALL' )
!      dc_all='a'
 !  end select   

   if ( de == 0.0_DP ) then
      de = conv_thr * 0.5_DP ! Change from Ry to Ha
   else
      de = de / AUTOEV       ! Change from eV to Ha
   endif
   
   if ( readgm ) then
      check_wfc = .false.
   endif 
 
end subroutine kgecvars_check


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

subroutine kgecvars_print
use apawgm, ONLY : use_real_spherical_harm

   write(stdout,*) ''
   write(stdout,*)           '    --------------------------------------------------------------'
   write(stdout,*)           "                Parameters for the KG conductivity"
   write(stdout,*)           '    --------------------------------------------------------------'
   write(stdout,'(A,A)')     '     Type of calculation          : ', calculation

   if( calculate_sigma2 .or. sigma2_via_eps1mod ) then
     write(stdout,*)         '    Calculate                    : Sigma1 and Sigma2'
   else
     write(stdout,*)         '    Calculate                    : Sigma1 only'
   endif
   if( calculate_epsilon1 ) then
     write(stdout,*)         '    Calculate                    : epsilon1'
   endif
   if( calculate_epsilon2 ) then
     write(stdout,*)         '    Calculate                    : epsilon2'
   endif
   if( calculate_rrae ) then
     write(stdout,*)         '    Calculate                    : spectral properties'
   endif
   if( use_real_spherical_harm ) then
     write(stdout,*)         '    Spherical Harmonics          : Real'
   else
     write(stdout,*)         '    Spherical Harmonics          : Complex'
   endif
   if (sigma1_exact ) then
    write(stdout,'(A)')      '     Formulas                     : exact'
    
   if ( sigma1_notintra ) then
       write(stdout,'(A)')    '        sigma1_notintra           : yes'
   else
       write(stdout,'(A)')    '        sigma1_notintra           : no'
   endif

   if ( sigma2_notintra ) then
       write(stdout,'(A)')    '        sigma2_notintra           : yes'
   else
       write(stdout,'(A)')    '        sigma2_notintra           : no'
   endif
   
    if ( decomposition ) then 
       write(stdout,'(A)')    '        Decomposition             : yes'
    else
       write(stdout,'(A)')    '        Decomposition             : no'
    endif
   else
    write(stdout,'(A)')      '     Formulas                     : approximated (decomposition not possible)'
   endif

   if ( deltarep == '1l' .or. deltarep == '2l' ) then
     write(stdout,'(a,f10.6,a,1a,a)') '     Delta function width (eV)    :', deltawidth,'  (', deltarep(1:1),' Lorentzian(s))'
     write(stdout,'(a,f10.6,a)') '      Gaussian width (same height):', &
                                    0.5_dp*deltawidth/sqrt(pi)   ! Same height as Lorentzian
     write(stdout,'(a,f10.6,a)') '      Gaussian width (same FWHM)  :', &
                                    deltawidth * 0.5_dp / sqrt( log(2.0_dp) ) ! Same FWHM
   endif
   if ( deltarep == '1g' .or. deltarep=='2g' ) then
     write(stdout,'(a,f10.6,a,1a,a)') '     Delta function width (eV)    :', deltawidth,'  (', deltarep(1:1),' Gaussian(s))'
   endif
   if ( check_wfc ) then
     write(stdout,'(A)') '     Check the wave functions     : yes'
   else
     write(stdout,'(A)') '     Check the wave functions     : no'
   endif
   if ( check_delta ) then
     write(stdout,'(A)') '     Check delta function rep.    : yes'
   else
     write(stdout,'(A)') '     Check delta function rep.    : no'
   endif
   if ( dc ) then
     write(stdout,'(A)') '     DC component                 : yes'
   else
     write(stdout,'(A)') '     DC component                 : no'
   endif
   if ( ac ) then
     write(stdout,'(A)') '     AC component                 : yes'
   else
     write(stdout,'(A)') '     AC component                 : no'
   endif
   if ( readgm ) then
     write(stdout,'(A)') '     Gradient matrix elements     : read'
   else
     write(stdout,'(A)') '     Gradient matrix elements     : calculate'
   endif

   write(stdout,*)       '     Energies equal. tol. (eV)   :', de * AUTOEV

   if ( npwrecover ) then
     write(stdout,'(A)') '     Recover plane waves procs.   : yes'
   else
     write(stdout,'(A)') '     Recover plane waves procs.   : no'
   endif

end subroutine kgecvars_print

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   subroutine kgec_writegm
      ! Save final gradient matrix elements
      use mp_pools,  ONLY : inter_pool_comm, intra_pool_comm, my_pool_id, me_pool
      use mp,        ONLY : mp_rank, mp_size
      use qevars,    ONLY : nbnd, nks, tmp_dir, IONODE
       
      integer :: ik, ibb1, ib2, nk, nb

      my_pool_id = mp_rank( inter_pool_comm )
      me_pool    = mp_rank( intra_pool_comm )         
      

      if (IONODE) then
        nk = mp_size( inter_pool_comm )
        nb = mp_size( intra_pool_comm )
        open(121, file='nodes-and-tasks-in-use.dat', action='write')
        write(121,*) nk, nb
        close(121)
      endif

      write(stdout,*) ''
      write(stdout,'(A)',advance='no') '     Writing the gradient matrix elements ...'

      write (fname, "('psi_grad_psi-k', i0,'_b', i0, '.dat')") my_pool_id, me_pool 
      fname=trim(tmp_dir)//fname

      open(121, file=fname,action='write')
      do ik=1, nks

      do ibb1=1, nbnds_local
      do ib2=1, nbnd
         write(121,*) psi_grad_psi(1,ib2,ibb1,ik), &
                      psi_grad_psi(2,ib2,ibb1,ik), &
                      psi_grad_psi(3,ib2,ibb1,ik)
      enddo  
      enddo
      enddo
      close(121)

      write(stdout,'(A)') ' done.'  
      
   end subroutine kgec_writegm

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   subroutine kgec_readgm

      ! Read gradient matrix elements

      use mp_pools,  ONLY : inter_pool_comm, intra_pool_comm, my_pool_id, &
                            me_pool
      use mp,        ONLY : mp_rank, mp_size, mp_bcast
      use io_global, ONLY : stdout
      use qevars,    ONLY : nbnd, nks, tmp_dir, IONODE, ionode_id, world_comm
       
      integer :: ik, ibb1, ib2, ierr, nk, nb, nk1, nb1
      logical :: file_exist
      

      my_pool_id = mp_rank( inter_pool_comm )
      me_pool    = mp_rank( intra_pool_comm )         

      if (IONODE) then

        inquire(file="./nodes-and-tasks-in-use.dat", exist=file_exist)

        if ( file_exist ) then
          open(121, file='nodes-and-tasks-in-use.dat', action='read')
          read(121,*) nk1, nb1
          close(121)
        endif

        nk = mp_size( inter_pool_comm )
        nb = mp_size( intra_pool_comm )

      endif

      call mp_bcast( file_exist, ionode_id, world_comm )
      
      if ( .not. file_exist ) then
         call errore( 'kgecvars','File nodes-and-tasks-in-use.dat does not exist (see writegm).', 10)
      endif
                   
      call mp_bcast( nk1, ionode_id, world_comm )        
      call mp_bcast( nb1, ionode_id, world_comm )        
      call mp_bcast(  nk, ionode_id, world_comm )        
      call mp_bcast(  nb, ionode_id, world_comm )        

      if ( nk1 /= nk .or. nb1 /= nb ) then
         call errore( 'kgecvars','Current nk and nb values are not the same as those used to write the grad. matrix. ', 10)
      endif


      write(stdout,*) ''
      write(stdout,'(A)',advance='no') '     Reading the gradient matrix elements ...'

      write (fname, "('psi_grad_psi-k', i0,'_b', i0, '.dat')") my_pool_id, me_pool 
      fname=trim(tmp_dir)//fname

      allocate( psi_grad_psi(1:3, 1:nbnd, 1:nbnds_local, 1:nks), STAT=ierr )
      if (ierr/=0) call errore('kgecvars','allocating psi_grad_psi', abs(ierr) )

      open(121, file=fname,action='read')
      do ik=1, nks
         do ibb1=1, nbnds_local
         do ib2=1, nbnd
            read(121,*) psi_grad_psi(1,ib2,ibb1,ik), &
                        psi_grad_psi(2,ib2,ibb1,ik), &
                        psi_grad_psi(3,ib2,ibb1,ik)
         enddo
         enddo
      enddo
      close(121)

      write(stdout,'(A)') ' done.'  
      
   end subroutine kgec_readgm


end module kgecvars
