read_vasp Subroutine

public subroutine read_vasp(self, unit, error)

Arguments

Type IntentOptional Attributes Name
type(structure_type), intent(out) :: self

Instance of the molecular structure data

integer, intent(in) :: unit

File handle

type(error_type), intent(out), allocatable :: error

Error handling


Source Code

subroutine read_vasp(self, unit, error)

   !> Instance of the molecular structure data
   type(structure_type), intent(out) :: self

   !> File handle
   integer, intent(in) :: unit

   !> Error handling
   type(error_type), allocatable, intent(out) :: error

   logical :: selective, cartesian
   integer :: i, j, k, nn, ntype, natoms, izp, stat, pos, lnum
   integer, allocatable :: ncount(:)
   real(wp) :: ddum, latvec(3), scalar, coord(3), lattice(3, 3)
   real(wp), allocatable :: xyz(:, :)
   type(token_type) :: token
   character(len=:), allocatable :: line, comment
   character(len=2*symbol_length), allocatable :: args(:), args2(:)
   character(len=symbol_length), allocatable :: sym(:)
   type(structure_info) :: info

   selective = .false. ! Selective dynamics
   cartesian = .true.  ! Cartesian or direct
   lattice = 0
   stat = 0
   lnum = 0

   ntype = 0
   ! first line contains the symbols of different atom types
   call next_line(unit, line, pos, lnum, stat)
   if (stat /= 0) then
      call fatal_error(error, "Unexpected end of input encountered")
      return
   end if

   call parse_line(" " // line, args, ntype)
   call move_alloc(line, comment)

   ! this line contains the global scaling factor,
   call next_line(unit, line, pos, lnum, stat)
   if (stat /= 0) then
      call fatal_error(error, "Unexpected end of input encountered")
      return
   end if
   call read_next_token(line, pos, token, ddum, stat)
   if (stat /= 0) then
      call io_error(error, "Cannot read scaling factor", &
         & line, token, filename(unit), lnum, "expected real value")
      return
   end if
   ! the Ang->au conversion is included in the scaling factor
   scalar = ddum*aatoau

   ! reading the lattice constants
   do i = 1, 3
      call next_line(unit, line, pos, lnum, stat)
      if (stat /= 0) then
         call fatal_error(error, "Unexpected end of lattice vectors encountered")
         return
      end if
      call read_next_token(line, pos, token, latvec(1), stat)
      if (stat == 0) &
         call read_next_token(line, pos, token, latvec(2), stat)
      if (stat == 0) &
         call read_next_token(line, pos, token, latvec(3), stat)
      if (stat /= 0) then
         call io_error(error, "Cannot read lattice vectors from input", &
            & line, token, filename(unit), lnum, "expected real value")
         return
      end if
      lattice(:, i) = latvec * scalar
   end do
   ! Either here are the numbers of each element,
   ! or (>vasp.5.1) here are the element symbols
   call next_line(unit, line, pos, lnum, stat)
   if (stat /= 0) then
      call fatal_error(error, "Unexpected end of input encountered")
      return
   end if

   ! try to verify that first element is actually a number
   i = max(verify(line, ' '), 1)
   j = scan(line(i:), ' ') - 2 + i
   if (j < i) j = len_trim(line)

   ! CONTCAR files have additional Element line here since vasp.5.1
   if (verify(line(i:j), '1234567890') /= 0) then
      call parse_line(" " // line, args, ntype)
      call next_line(unit, line, pos, lnum, stat)
      if (stat /= 0) then
         call fatal_error(error, "Unexpected end of input encountered")
         return
      end if
   else
      deallocate(comment)
   end if
   call parse_line(" " // line, args2, nn)
   if (nn /= ntype) then
      call fatal_error(error, 'Number of atom types mismatches the number of counts')
      return
   end if

   allocate(ncount(nn), source = 0)
   do i = 1, nn
      read(args2(i), *, iostat=stat) ncount(i)
      izp = to_number(args(i))
      if (izp < 1 .or. ncount(i) < 1) then
         call fatal_error(error, "Unknown element '"//trim(args(i))//"' encountered")
         return
      end if
   end do

   natoms = sum(ncount)
   allocate(sym(natoms))
   allocate(xyz(3, natoms))

   k = 0
   do i = 1, nn
      do j = 1, ncount(i)
         k = k+1
         sym(k) = trim(args(i))
      end do
   end do

   call next_line(unit, line, pos, lnum, stat)
   if (stat /= 0) then
      call fatal_error(error, "Could not read POSCAR")
      return
   end if
   line = adjustl(line)
   if (line(:1).eq.'s' .or. line(:1).eq.'S') then
      selective = .true.
      call next_line(unit, line, pos, lnum, stat)
      if (stat /= 0) then
         call fatal_error(error, "Unexpected end of input encountered")
         return
      end if
      line = adjustl(line)
   end if

   cartesian = (line(:1).eq.'c' .or. line(:1).eq.'C' .or. &
      &         line(:1).eq.'k' .or. line(:1).eq.'K')
   do i = 1, natoms
      call next_line(unit, line, pos, lnum, stat)
      if (stat /= 0) then
         call fatal_error(error, "Unexpected end of geometry encountered")
         return
      end if
      call read_next_token(line, pos, token, coord(1), stat)
      if (stat == 0) &
         call read_next_token(line, pos, token, coord(2), stat)
      if (stat == 0) &
         call read_next_token(line, pos, token, coord(3), stat)
      if (stat /= 0) then
         call io_error(error, "Cannot read geometry from input", &
            & line, token, filename(unit), lnum, "expected real value")
         return
      end if

      if (cartesian) then
         xyz(:, i) = coord*scalar
      else
         xyz(:, i) = matmul(lattice, coord)
      end if

   end do

   ! save information about this POSCAR for later
   info = structure_info(scale=ddum, selective=selective, cartesian=cartesian)
   call new(self, sym, xyz, lattice=lattice, info=info)
   if (allocated(comment)) self%comment = comment

end subroutine read_vasp