Last commit for src/ext/xsflib.f90: 5874abaa643d4472a2aa9d1c5dbe454dadbd8d1f

Initial commit of the AENET code.

Bruno Mundim [2017-01-02 17:48:39]
Initial commit of the AENET code.
!-----------------------------------------------------------------------
! xsflib.f90 -  A library with I/O routines to parse the XCrysDen
!               Structure File format (XSF).
!-----------------------------------------------------------------------
!+ This file is part of the AENET package.
!+
!+ Copyright (C) 2012-2016 Nongnuch Artrith and Alexander Urban
!+
!+ 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 3 of the License, or
!+ (at your option) any later version.
!+
!+ 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.
!+
!+ You should have received a copy of the GNU General Public License
!+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
!-----------------------------------------------------------------------
! Currently, the XSF format is supported by (at least) the following
! free molecular graphics tools: XCrysDen, JMol, Vesta, VMD
!-----------------------------------------------------------------------
! 2011-02-11 Alexander Urban (AU), Nongnuch Artrith (NA)
! 2011-11-07 -- changed names and syntax to conform with other
!               packages, e.g. cooCart instead of coorat
! 2013-05-23 -- (1) allow unsorted atom types; atoms of the same
!               do no longer need to be consecutive in the file
!               (2) use io_unit() instead of fix file unit number
! 2013-08-24 -- support for isolated structures
!-----------------------------------------------------------------------

module xsflib

  use io, only: io_adjustl,  &
                io_isfigure, &
                io_isletter, &
                io_readnext, &
                io_readval,  &
                io_split,    &
                io_lower,    &
                io_unit,     &
                io_upper

  implicit none
  private

  public :: xsf_init,  &
            xsf_final


  !--------------------------------------------------------------------!
  ! LENLINE : max. length of lines (number of char's) in input file    !
  !--------------------------------------------------------------------!

  integer, parameter, private :: LENLINE = 1024

  !---------------------------- structure -----------------------------!
  ! nAtoms             : total number of atoms                         !
  ! nTypes             : number of atom types / atomic species         !
  ! unitCellVol        : unit cell volume                              !
  ! latticeVec(i,j)    : i-th component of the j-th lattice vector     !
  ! atomTypeName(ityp) : name of atomic species ityp; ityp = 1, nTypes !
  ! nAtomsOfType(ityp) : number of atoms of atomic species ityp        !
  ! cooCart(i,iat)     : i-th component of the cartesian coordinates   !
  !                      of atom number iat                            !
  ! forCart(i,iat)     : same for the cartesian forces                 !
  !                                                                    !
  !------------------------------ output ------------------------------!
  ! hasOutput          : .true., if file contains output information   !
  ! hasForces          : .true., if forces are present                 !
  ! E_tot              : total energy                                  !
  ! E_coh              : cohesive energy                               !
  !--------------------------------------------------------------------!

  logical,                                       public :: pbc
  integer,                                       public :: nAtoms
  integer,                                       public :: nTypes
  double precision,                              public :: unitCellVol
  double precision, dimension(3,3),              public :: latticeVec
  character(len=2), dimension(:),   allocatable, public :: atomTypeName
  integer,          dimension(:),   allocatable, public :: nAtomsOfType
  integer,          dimension(:),   allocatable, public :: atomType
  double precision, dimension(:,:), allocatable, public :: cooCart
  double precision, dimension(:,:), allocatable, public :: forCart

  logical,                                       public :: hasOutput
  logical,                                       public :: hasForces
  double precision,                              public :: E_tot
  double precision,                              public :: E_coh

  !--------------------------------------------------------------------!
  !                              PRIVATE                               !
  !                                                                    !
  ! iline   : number of the current line of the input file             !
  ! line    : input buffer for single line from the input file         !
  !--------------------------------------------------------------------!

  integer,                private :: iline
  character(len=LENLINE), private :: line
  integer,                private :: u_in

contains

  subroutine xsf_init(file)

    implicit none

    character(len=*), intent(in) :: file

    logical                      :: fexists
    integer                      :: status

    character(len=LENLINE)       :: species

    inquire(file=trim(file), exist=fexists)
    if (.not. fexists) then
       write(0,*) 'Error: File not found: ', trim(file)
       stop
    end if

    ! initial values:
    hasOutput  = .false.
    hasForces  = .false.
    pbc        = .false.
    E_coh      = 0.0d0
    E_tot      = 0.0d0

    u_in = io_unit()
    open(u_in, file=trim(file), status='old', action='read')

    iline = 1
    read_input : do

       read(u_in, '(A)', iostat=status) line
       if (status /= 0) exit read_input
       iline = iline + 1

       ! skip blank lines
       if (len_trim(line) == 0) cycle read_input

       ! cohesive energy
       if (index(line, 'cohesive energy') > 0) then
          call io_readval(line, name='cohesive energy', val=E_coh)
          hasOutput = .true.
          cycle read_input
       end if

       ! total energy
       if (index(line, 'total energy') > 0) then
          call io_readval(line, name='total energy', val=E_tot)
          hasOutput = .true.
          cycle read_input
       end if

       ! skip all remaining comments
       line = trim(adjustl(line))
       if (line(1:1) == '#') cycle read_input

       ! lattice vectors
       if (index(line, 'PRIMVEC') > 0) then
          pbc = .true.
          read(u_in, *) latticeVec(1:3, 1)
          read(u_in, *) latticeVec(1:3, 2)
          read(u_in, *) latticeVec(1:3, 3)
          iline = iline + 3
          cycle read_input
       end if

       ! coordinates of periodic structures
       primcoord : if (index(line, 'PRIMCOORD') > 0) then
          read(u_in, *) nAtoms
          iline = iline + 1
          call xsf_count_atoms_and_types(nAtoms, nTypes, species, hasForces)
          call xsf_malloc()
          call io_split(species, atomTypeName)
          call xsf_read_coordinates()
          cycle read_input
       end if primcoord

       ! coordinates of isolated structures
       atoms : if (index(line, 'ATOMS') > 0) then
          call xsf_count_atoms_and_types(nAtoms, nTypes, species, hasForces)
          call xsf_malloc()
          call io_split(species, atomTypeName)
          call xsf_read_coordinates()
          cycle read_input
       end if atoms

    end do read_input

    close(u_in)

    if (pbc) then
       ! unit cell volume:
       unitCellVol = latticeVec(1,1)*latticeVec(2,2)*latticeVec(3,3) &
                   + latticeVec(2,1)*latticeVec(3,2)*latticeVec(1,3) &
                   + latticeVec(3,1)*latticeVec(1,2)*latticeVec(2,3) &
                   - latticeVec(3,1)*latticeVec(2,2)*latticeVec(1,3) &
                   - latticeVec(1,1)*latticeVec(3,2)*latticeVec(2,3) &
                   - latticeVec(2,1)*latticeVec(1,2)*latticeVec(3,3)
    end if

  end subroutine xsf_init

  !--------------------------------------------------------------------!

  subroutine xsf_final()

    implicit none

    if (allocated(cooCart)) then
       deallocate(cooCart, atomType, atomTypeName, nAtomsOfType)
    end if
    if (allocated(forCart)) deallocate(forCart)

  end subroutine xsf_final



  !====================================================================!
  !                                                                    !
  !                        auxiliary procedures                        !
  !                                                                    !
  !====================================================================!



  !--------------------------------------------------------------------!
  !                          allocate memory                           !
  !--------------------------------------------------------------------!

  subroutine xsf_malloc()

    implicit none

    !-----------------------  module variables ------------------------!
    ! nAtoms, nTypes, hasForces                                        !
    !------------------------------------------------------------------!

    if (allocated(cooCart)) then
       write(0,*) 'Warning: attempted double memory allocation in XSF module.'
       return
    end if

    if (hasForces) then
       allocate(cooCart(3,nAtoms), nAtomsOfType(nTypes), &
                atomTypeName(nTypes), atomType(nAtoms),  &
                forCart(3,nAtoms))
    else
       allocate(cooCart(3,nAtoms), nAtomsOfType(nTypes), &
                atomTypeName(nTypes), atomType(nAtoms))
    end if

  end subroutine xsf_malloc

  !--------------------------------------------------------------------!
  !              atom type index for given atom type name              !
  !--------------------------------------------------------------------!

  function xsf_itype(el) result(itype)

    implicit none

    !------------------------ module variables ------------------------!
    ! nTypes, atomTypeName                                             !
    !------------------------------------------------------------------!

    character(len=*), intent(in) :: el
    integer                      :: itype

    itype = 1
    do while(itype <= nTypes)
       if (trim(adjustl(el)) == trim(adjustl(atomTypeName(itype)))) then
          exit
       end if
       itype = itype + 1
    end do
    if (itype > nTypes) itype = -1

  end function xsf_itype

  !--------------------------------------------------------------------!
  !                   count atoms and atomic species                   !
  !                                                                    !
  ! Assumes that the next line contains the species, coordinates, and  !
  ! possibly forces of the FIRST atom.                                 !
  !                                                                    !
  ! The string 'species' is used to store all chemical symbols in one  !
  ! pass.  512 characters are more than enough to store all chemical   !
  ! symbols of the PSE separated by a blank.                           !
  !--------------------------------------------------------------------!

  subroutine xsf_count_atoms_and_types(natoms, ntypes, species, hasforces)

    implicit none

    !------------------------------------------------------------------!
    ! natoms     number of atoms                                       !
    ! ntypes     number of atomic species                              !
    ! species    character string continaing all atomic species        !
    ! hasforces  .true., iff atomic forces are present                 !
    !------------------------------------------------------------------!

    integer,          intent(out) :: natoms
    integer,          intent(out) :: ntypes
    character(len=*), intent(out) :: species
    logical,          intent(out) :: hasforces

    !------------------------ module variables ------------------------!
    ! u_in, iline, line                                                !
    !------------------------------------------------------------------!

    character(len=2)       :: el
    character(len=LENLINE) :: str
    integer                :: stat
    integer                :: i, k

    ntypes    = 0
    natoms    = 0
    species   = ' '
    hasforces = .false.

    ! count atoms and types
    count : do
       read(u_in, '(A)', iostat=stat) str
       if (stat /= 0) exit count
       if (len_trim(str) == 0) exit count
       line = str
       read(line, *) el
       ! blanks are used to distinguish, e.g., 'S' from 'Sn'
       if (index(species,' ' // trim(el) // ' ' ) == 0) then
          species = trim(species) // ' ' // trim(el) // ' '
          ntypes   = ntypes + 1
       end if
       natoms = natoms + 1
    end do count

    ! are forces present?
    ! --> count records in final atom line
    k = 0
    i = 1
    do while (i > 0)
       k = k + 1
       call io_readnext(line, i, str)
    end do
    if (k >= 7) hasForces = .true.

    ! rewind to original position in file
    rewind(u_in)
    do i = 1, iline-1
       read(u_in, *)
    end do

  end subroutine xsf_count_atoms_and_types

  !--------------------------------------------------------------------!
  !                    read coordinates and forces                     !
  !--------------------------------------------------------------------!

  subroutine xsf_read_coordinates()

    implicit none

    !------------------------ module variables ------------------------!
    ! line, iline, nAtoms, nTypes, atomType, nAtomsOfType, cooCart,    !
    ! forCart                                                          !
    !------------------------------------------------------------------!

    integer          :: iat, itype
    character(len=2) :: el

    ! read Cartesian coordinates and forces
    do iat = 1, nAtoms
       read(u_in, '(A)') line
       iline = iline + 1
       if (hasForces) then
          read(line, *) el, cooCart(1:3,iat), forCart(1:3,iat)
       else
          read(line, *) el, cooCart(1:3,iat)
       end if
       itype = xsf_itype(el)
       atomType(iat) = itype
       nAtomsOfType(itype) = nAtomsOfType(itype) + 1
    end do

  end subroutine xsf_read_coordinates

end module xsflib
ViewGit