Last commit for src/generate.f90: 5874abaa643d4472a2aa9d1c5dbe454dadbd8d1f

Initial commit of the AENET code.

Bruno Mundim [2017-01-02 17:48:39]
Initial commit of the AENET code.
!-----------------------------------------------------------------------
!      generate.f90 - generate training sets for use with train.x
!-----------------------------------------------------------------------
!+ 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/>.
!-----------------------------------------------------------------------
! 2011-10-19 Alexander Urban (AU), Nongnuch Artrith (NA)
!-----------------------------------------------------------------------

program generate

  use aeio,     only: aeio_readline,        &
                      aeio_header,          &
                      aeio_timestamp,       &
                      aeio_print_copyright, &
                      PATHLEN, LINELEN

  use geometry, only: geo_init,          &
                      geo_final,         &
                      geo_itype_of_name, &
                      geo_type_conv,     &
                      pbc,               &
                      latticeVec,        &
                      nAtoms,            &
                      nTypes,            &
                      atomType,          &
                      atomTypeName,      &
                      cooLatt,           &
                      cooCart,           &
                      forCart,           &
                      hasEnergy,         &
                      hasForces,         &
                      cohesiveEnergy,    &
                      totalEnergy

  use input,    only: InputData,         &
                      read_InpGenerate,  &
                      del_InputData

  use io,       only: io_adjustl,        &
                      io_center,         &
                      io_lower,          &
                      io_readnext,       &
                      io_unit

  use lclist,   only: lcl_init,          &
                      lcl_final,         &
                      lcl_print_info,    &
                      lcl_nmax_nbdist,   &
                      lcl_nbdist_cart

  use sfsetup,  only: Setup,                 &
                      read_Setup_parameters, &
                      save_Setup,            &
                      del_Setup,             &
                      stp_init,              &
                      stp_final,             &
                      stp_get_range,         &
                      stp_print_info,        &
                      stp_eval,              &
                      sfval

  use timing,   only: tng_init,          &
                      tng_final,         &
                      tng_timing,        &
                      tng_timing2,       &
                      tng_timing3,       &
                      tng_dump

  use trainset, only: TrnSet,                 &
                      new_TrnSet,             &
                      close_TrnSet,           &
                      ts_print_info,          &
                      ts_write_header,        &
                      ts_write_sf_info,       &
                      ts_write_atom_info,     &
                      ts_write_structure_info

  implicit none

  !--------------------------------------------------------------------!
  ! stp(i)         structural fingerprint basis setup for atom type i  !
  ! r_min, r_max   lower and upper bound for atomic interactions       !
  ! ts             training set reference                              !
  !                                                                    !
  ! nnb_max, nnb   max. and actual number of neighboring atoms         !
  ! nbcoo(i,j)     i-th component of the coordinates of the j-th       !
  !                neighboring atom                                    !
  ! nbdist(i)      distance of the i-th neighbor                       !
  !                                                                    !
  ! E_coh          cohesive energy                                     !
  ! nFiles_inv     = 1/inp%nStrucs                                     !
  !                                                                    !
  ! inFile         name of the input file for the generate.x program   !
  ! cooFile        name of the currently active structure file         !
  ! keyword        the last keyword read from the input file           !
  !                                                                    !
  ! do_debug       if .true., additional files containing debugging    !
  !                info will be created                                !
  !                                                                    !
  ! u_*            file units                                          !
  !--------------------------------------------------------------------!

  type(InputData)                                :: inp

  type(Setup),       dimension(:),   allocatable :: stp
  double precision                               :: r_min, r_max
  type(TrnSet)                                   :: ts

  integer                                        :: nnb_max, nnb
  double precision,  dimension(:,:), allocatable :: nbcoo
  double precision,  dimension(:),   allocatable :: nbdist
  integer,           dimension(:),   allocatable :: nbtype

  double precision                               :: E_coh
  integer                                        :: ifile
  double precision                               :: nFiles_inv

  character(len=PATHLEN)                         :: inFile
  character(len=PATHLEN)                         :: cooFile
  character(len=LINELEN)                         :: keyword

  integer                                        :: itype1
  integer                                        :: itype, iatom

  integer                                        :: iline
  character(len=1024)                            :: line

  integer                                        :: u_in, u_tng
  logical                                        :: do_debug = .false.
  integer                                        :: u_dbg, idbg

  integer :: i

  ! timing registers
  integer, parameter :: R_GEO = 1, R_NBL = 2, R_SF = 3

  !-------------------------- initialization --------------------------!

  call initialize(inFile)

  inp = read_InpGenerate(inFile)
  allocate(stp(inp%nTypes))
  call load_symmfunc_setups(inp, stp)

  ! call parse_input(inFile)

  if (inp%do_timing) then
     u_tng = io_unit()
     call tng_init(unit=u_tng, file='generate.time', registers=3)
     write(*,*) 'Timing info will be written to: ', 'generate.time'
     write(*,*)
  end if
  if (do_debug) then
     u_dbg = io_unit()
     open(u_dbg, file='generate.debug', status='replace', action='write')
  end if

  ! get interaction range and max. number of atoms within range
  call stp_get_range(inp%nTypes, stp, r_min, r_max)
  nnb_max = lcl_nmax_nbdist(r_min, r_max)
  allocate(nbcoo(3,nnb_max), nbdist(nnb_max), nbtype(nnb_max))

  ! initialize workspace for structural fingerprint basis:
  call stp_init(inp%nTypes, stp, nnb_max)
  if (inp%do_timing) call tng_timing('Structural fingerprint basis initialized.')

  call aeio_header('Generation of training set started')
  write(*,*)

  write(*,*) 'Number of atom types  : ', trim(io_adjustl(inp%nTypes))
  write(*,'(1x,"types                 : ")', advance='no')
  do itype = 1, inp%nTypes
     if (mod(itype,7) == 0) write(*,'(29x)')
     write(*,'(A5,1x)', advance='no') inp%typeName(itype)
  end do
  write(*,*)
  write(*,*) "Number of structures  : ", trim(io_adjustl(inp%nStrucs))
  write(*,*)

  !-------------- write basis function settings to stdout -------------!

  call aeio_header("Structural fingerprint basis set-up")
  write(*,*)

  do itype1 = 1, inp%nTypes
     call stp_print_info(stp(itype1))
  end do

  !----------- write training set header to the output file -----------!

  ts = new_TrnSet(inp%nTypes, inp%typeName, inp%atomicEnergy, &
                  inp%nStrucs, trim(inp%outFileName))

  if (inp%do_timing) call tng_timing('Training set file started.')

  !------------------ iterate over coordinates files ------------------!

  call aeio_header("Adding structures to the training set")
  write(*,*)

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

  iline = 0
  do
     ! forward until the FILES keyword:
     call aeio_readline(u_in, iline, line)
     read(line,*) keyword
     if (trim(keyword) == 'FILES') then
        read(u_in,*)
        exit
     end if
  end do

  ! header for stdout
  write(*,'("#",A6,2x,A6,2x,A6,2x,A15,2x,A)') &
       'N', 'nAtoms', 'nTypes', 'E/atom', 'structure file (xsf)'

  nFiles_inv = 1.0d0/dble(inp%nStrucs)
  structures : do ifile = 1, inp%nStrucs

     if (inp%do_timing) call tng_timing('Structure: '// io_adjustl(ifile))

     call aeio_readline(u_in, iline, line)
     cooFile = trim(line)

     call geo_init(cooFile, 'xsf')
     if (inp%do_timing) call tng_timing3(register=R_GEO)
     if (.not. (hasForces .and. hasEnergy)) then
        write(0,*) ">>>", hasForces, hasEnergy
        write(0,*) "Error: incomplete output data in : ", trim(cooFile)
        call finalize()
        stop
     end if

     if (nTypes > inp%nTypes) then
        write(*,*) 'Skipping ', trim(adjustl(cooFile)), &
                   ': too many atomic species'
        call geo_final()
        cycle structures
     end if

     if (abs(cohesiveEnergy) /= 0.0d0) then
        E_coh = cohesiveEnergy
     else
        ! if only the total energy is available, we have to calculate
        ! the cohesive energy at this point
        E_coh = totalEnergy
        do iatom = 1, nAtoms
           itype1 = atomType(iatom)
           itype1 = geo_type_conv(itype1, nTypes, atomTypeName, &
                                  inp%nTypes, inp%typeName)
           E_coh = E_coh - inp%atomicEnergy(itype1)
        end do
     end if

     write(*,'(1x,I6,2x,I6,2x,I6,2x,ES15.8,2x,A)') &
          ifile, nAtoms, nTypes, E_coh/dble(nAtoms), &
          trim(adjustl(cooFile))

     call lcl_init(r_min, r_max, latticeVec, nAtoms, atomType, cooLatt, pbc)
     if (inp%do_timing) call tng_timing3(register=R_NBL)

     ! write structure info (atoms, types, energy) to training set file:
     call ts_write_structure_info(ts, cooFile, nAtoms, nTypes, E_coh)

     atoms : do iatom = 1, nAtoms

        ! determine the training atom type of atom `iatom' in global
        ! index terms
        itype1 = atomType(iatom)
        itype1 = geo_type_conv(itype1, nTypes, atomTypeName, &
                               inp%nTypes, inp%typeName)

        ! assert that atom type is included in the set-ups:
        if (itype1 == 0) then
           write(0,*) "Error: not a valid structure    : ", trim(cooFile)
           write(0,*) "       Additional species found."
           call finalize()
           stop
        end if

        ! write atom info (species, forces) to training set file:
        call ts_write_atom_info(ts, itype1, cooCart(iatom), forCart(iatom))

        ! get all atoms within cut-off:
        nnb = nnb_max
        call lcl_nbdist_cart(iatom, nnb, nbcoo, nbdist, r_cut=r_max, nbtype=nbtype)
        if (inp%do_timing) call tng_timing3(register=R_NBL)
        write(*,'(1x,I6,2x,A2,2x,I6)') &
             iatom, trim(atomTypeName(atomType(iatom))), nnb

        ! convert atom types to global index:
        do i = 1, nnb
           nbtype(i) = geo_type_conv(nbtype(i), nTypes, atomTypeName, &
                                    inp%nTypes, inp%typeName)
           if (nbtype(i) == 0) then
              write(0,*) "Error: atom type not found in setup."
              call finalize()
              stop
           end if
        end do

        ! evaluate the structural fingerprint basis function set-up:
        call stp_eval(itype1, cooCart(iatom), nnb, nbcoo, nbtype, stp(itype1))
        !!$ call stp_eval(itype1, cooCart(iatom), nnb, nbcoo, nbtype, &
        !!$               stp(itype1), deriv=.true.)

        if (do_debug) then
           do idbg = 1, stp(itype1)%nsf
              write(u_dbg,'(1x,ES15.8,1x)', advance='no') sfval(idbg)
           end do
           write(u_dbg,*)
        end if

        if (inp%do_timing) call tng_timing3(register=R_SF)

        ! write basis function values and derivatives
        ! to the training set file:
        call ts_write_sf_info(ts, stp(itype1))

     end do atoms

     if (inp%do_timing) then
        call tng_dump(R_GEO, 'time spent reading geometries (so far)')
        call tng_dump(R_NBL, 'time spent in the neighbor list (so far)')
        call tng_dump(R_SF,  'time spent evaluating structural fingerprints (so far)')
     end if

     call lcl_final()
     call geo_final()

  end do structures
  write(*,*)

  if (inp%do_timing) then
     call tng_timing('Loop over structures done.')
     call tng_dump(R_GEO, 'total time spent reading geometries')
     call tng_dump(R_NBL, 'total time spent in the neighbor list')
     call tng_dump(R_SF,  'total time spent evaluating structural fingerprints')
  end if

  !--------- save basis function setups with final statistics ---------!

  call ts_print_info(ts)

  !----------------------------- finalize -----------------------------!

  deallocate(nbcoo, nbdist, nbtype)
  close(u_in)

  call close_TrnSet(ts, stp=stp(1:inp%nTypes))
  call finalize()


contains !=============================================================!


  subroutine initialize(inFile)

    implicit none

    character(len=*), intent(out) :: inFile

    integer :: nargs
    logical :: fexists

    call aeio_header("generate.x - training set generation", char='=')
    write(*,*)

    call aeio_print_copyright('2015-2016', 'Nongnuch Artrith and Alexander Urban')

    nargs = command_argument_count()
    if (nargs < 1) then
       write(0,*) "Error: No input file provided."
       call print_usage()
       call finalize()
       stop
    end if

    call get_command_argument(1, value=inFile)
    inquire(file=trim(inFile), exist=fexists)
    if (.not. fexists) then
       write(0,*) "Error: File not found: ", trim(inFile)
       call print_usage()
       call finalize()
       stop
    end if

  end subroutine initialize

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

  subroutine finalize()

    implicit none

    integer :: itype

    if (allocated(stp)) then
       call stp_final(inp%nTypes, stp)
       do itype = 1, inp%nTypes
          call del_Setup(stp(itype))
       end do
       deallocate(stp, inp%typeName, inp%atomicEnergy)
    end if

    if (ts%init) call close_TrnSet(ts)

    if (allocated(nbcoo)) deallocate(nbcoo, nbdist)

    if (inp%do_timing) call tng_final()
    if (do_debug)  close(u_dbg)

    call aeio_header(aeio_timestamp(), char=' ')
    call aeio_header("Training set generation done.", char='=')

  end subroutine finalize

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

  subroutine print_usage()

    implicit none

    write(*,*)
    write(*,*) "generate.x -- Generate training sets for use with `train.x'"
    write(*,'(1x,70("-"))')
    write(*,*) 'Usage: generate.x <input-file>'
    write(*,*)
    write(*,*) 'See the documentation or the source code for a description of the '
    write(*,*) 'input file format.'
    write(*,*)

  end subroutine print_usage

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

  subroutine load_symmfunc_setups(inp, stp)

    implicit none

    type(InputData),           intent(in)  :: inp
    type(Setup), dimension(:), intent(out) :: stp

    integer :: i

    do i = 1, inp%nTypes
       stp(i) = read_Setup_parameters(inp%setupFile(i), inp%typeName(:))
       if (.not. (trim(stp(i)%atomtype) == trim(inp%typeName(i)))) then
          write(0,*) "Error: Inconsistent atom type in setup:"
          write(0,*) "       type expected : ", trim(inp%typeName(i))
          write(0,*) "       type found    : ", trim(stp(i)%atomtype)
          call finalize()
          stop
       end if
    end do

  end subroutine load_symmfunc_setups

end program generate
ViewGit