LCOV - code coverage report
Current view: top level - src/pseudopotentials - atom_upf.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 93.6 % 595 557
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 15 15

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Routines that process Quantum Espresso UPF files.
      10              : !> \par History
      11              : !>    * 07.2018 CP2K-SIRIUS interface [Juerg Hutter]
      12              : !>    * 02.2016 created [Juerg Hutter]
      13              : ! **************************************************************************************************
      14              : MODULE atom_upf
      15              :    USE cp_parser_methods,               ONLY: parser_get_next_line,&
      16              :                                               parser_get_object,&
      17              :                                               parser_test_next_token
      18              :    USE cp_parser_types,                 ONLY: cp_parser_type,&
      19              :                                               parser_create,&
      20              :                                               parser_release
      21              :    USE ieee_arithmetic,                 ONLY: ieee_is_finite
      22              :    USE kinds,                           ONLY: default_string_length,&
      23              :                                               dp
      24              :    USE periodic_table,                  ONLY: get_ptable_info,&
      25              :                                               ptable
      26              :    USE upf_types,                       ONLY: atom_upfpot_type,&
      27              :                                               upf_partial_waves_type,&
      28              :                                               upf_radial_weights,&
      29              :                                               upf_release
      30              : #include "../base/base_uses.f90"
      31              : 
      32              :    IMPLICIT NONE
      33              : 
      34              :    PRIVATE
      35              :    PUBLIC  :: atom_read_upf, atom_upfpot_type, atom_release_upf, upf_radial_weights, upf_partial_waves_type
      36              : 
      37              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'atom_upf'
      38              : 
      39              : ! **************************************************************************************************
      40              : 
      41              : CONTAINS
      42              : 
      43              : ! **************************************************************************************************
      44              : !> \brief ...
      45              : !> \param pot ...
      46              : !> \param upf_filename ...
      47              : !> \param read_header ...
      48              : !> \param read_augmentation Import scalar USPP augmentation and optional full partial waves explicitly.
      49              : !>        This reader option does not enable USPP in a calculation method.
      50              : ! **************************************************************************************************
      51           38 :    SUBROUTINE atom_read_upf(pot, upf_filename, read_header, read_augmentation)
      52              : 
      53              :       TYPE(atom_upfpot_type)                             :: pot
      54              :       CHARACTER(len=*), INTENT(IN)                       :: upf_filename
      55              :       LOGICAL, INTENT(IN), OPTIONAL                      :: read_header, read_augmentation
      56              : 
      57              :       CHARACTER(LEN=2)                                   :: symbol
      58              :       INTEGER                                            :: l, ncore, nel
      59              :       LOGICAL                                            :: readall, readaug
      60              : 
      61           38 :       IF (PRESENT(read_header)) THEN
      62            2 :          readall = .NOT. read_header
      63              :       ELSE
      64           36 :          readall = .TRUE.
      65              :       END IF
      66           38 :       readaug = .FALSE.
      67           38 :       IF (PRESENT(read_augmentation)) readaug = read_augmentation
      68              : 
      69              :       ! filename
      70           38 :       pot%filename = ADJUSTL(TRIM(upf_filename))
      71              : 
      72              :       ! Ignore json potentials as SIRIUS will parse those on its own.
      73           38 :       l = LEN_TRIM(pot%filename)
      74           38 :       IF (l >= 5) THEN
      75           38 :          IF (pot%filename(l - 4:l) == '.json') THEN
      76            0 :             pot%zion = 0.0_dp
      77            0 :             RETURN
      78              :          END IF
      79              :       END IF
      80              : 
      81           38 :       CALL atom_read_upf_v2(pot, upf_filename, readall, readaug)
      82              : 
      83              :       ! set up econf
      84          190 :       IF (SUM(pot%econf) == 0) THEN
      85           38 :          symbol = ADJUSTL(TRIM(pot%symbol))
      86           38 :          CALL get_ptable_info(symbol, number=ncore)
      87          190 :          pot%econf(0:3) = ptable(ncore)%e_conv(0:3)
      88           38 :          nel = NINT(ncore - pot%zion)
      89            0 :          SELECT CASE (nel)
      90              :          CASE DEFAULT
      91            0 :             CPABORT("Unknown Core State")
      92              :          CASE (0)
      93              :             ! no core electron
      94              :          CASE (2)
      95           50 :             pot%econf(0:3) = pot%econf(0:3) - ptable(2)%e_conv(0:3)
      96              :          CASE (10)
      97            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(10)%e_conv(0:3)
      98              :          CASE (18)
      99            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(18)%e_conv(0:3)
     100              :          CASE (28)
     101           30 :             pot%econf(0:3) = pot%econf(0:3) - ptable(18)%e_conv(0:3)
     102            6 :             pot%econf(2) = pot%econf(2) - 10
     103              :          CASE (36)
     104            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(36)%e_conv(0:3)
     105              :          CASE (46)
     106            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(36)%e_conv(0:3)
     107            0 :             pot%econf(2) = pot%econf(2) - 10
     108              :          CASE (54)
     109            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(54)%e_conv(0:3)
     110              :          CASE (60)
     111            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(36)%e_conv(0:3)
     112            0 :             pot%econf(2) = pot%econf(2) - 10
     113            0 :             pot%econf(3) = pot%econf(3) - 14
     114              :          CASE (62)
     115              :             ! [Kr] 4d10 4f14 5s2 core, with 5p semicore in the valence (e.g. Pt).
     116           10 :             pot%econf(0:3) = pot%econf(0:3) - [10, 18, 20, 14]
     117              :          CASE (68)
     118            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(54)%e_conv(0:3)
     119            0 :             pot%econf(3) = pot%econf(3) - 14
     120              :          CASE (78)
     121            0 :             pot%econf(0:3) = pot%econf(0:3) - ptable(54)%e_conv(0:3)
     122            0 :             pot%econf(2) = pot%econf(2) - 10
     123           38 :             pot%econf(3) = pot%econf(3) - 14
     124              :          END SELECT
     125              :          !
     126          190 :          CPASSERT(ALL(pot%econf >= 0))
     127              :       END IF
     128              : 
     129              :       ! name
     130           38 :       IF (pot%pname == "") THEN
     131           38 :          pot%pname = ADJUSTL(TRIM(pot%symbol))
     132              :       END IF
     133              : 
     134              :    END SUBROUTINE atom_read_upf
     135              : 
     136              : ! **************************************************************************************************
     137              : !> \brief ...
     138              : !> \param pot ...
     139              : !> \param upf_filename ...
     140              : !> \param readall ...
     141              : !> \param readaug Read scalar USPP augmentation arrays.
     142              : ! **************************************************************************************************
     143           38 :    SUBROUTINE atom_read_upf_v2(pot, upf_filename, readall, readaug)
     144              : 
     145              :       TYPE(atom_upfpot_type)                             :: pot
     146              :       CHARACTER(len=*), INTENT(IN)                       :: upf_filename
     147              :       LOGICAL, INTENT(IN)                                :: readall, readaug
     148              : 
     149              :       CHARACTER(LEN=default_string_length)               :: nametag
     150              :       INTEGER                                            :: ib, ntag
     151              :       LOGICAL                                            :: at_end
     152              :       TYPE(cp_parser_type)                               :: parser
     153              : 
     154           38 :       ntag = 0
     155           38 :       CALL parser_create(parser, upf_filename, apply_preprocessing=.FALSE.)
     156              :       DO
     157              :          at_end = .FALSE.
     158        18948 :          CALL parser_get_next_line(parser, 1, at_end)
     159        18948 :          IF (at_end) EXIT
     160        18948 :          CALL parser_get_object(parser, nametag, lower_to_upper=.TRUE.)
     161        18948 :          IF (nametag(1:1) /= "<") CYCLE
     162          640 :          IF (ntag == 0) THEN
     163              :             ! we are looking for UPF tag
     164           38 :             IF (nametag(2:4) == "UPF") THEN
     165           38 :                CALL parser_get_object(parser, nametag, lower_to_upper=.TRUE.)
     166              :                ! read UPF file version
     167           38 :                CALL parser_get_object(parser, nametag, lower_to_upper=.TRUE.)
     168           38 :                pot%version = TRIM(nametag)
     169           38 :                CPASSERT(nametag(1:5) == "2.0.1")
     170           38 :                CALL parser_get_object(parser, nametag, lower_to_upper=.TRUE.)
     171           38 :                CPASSERT(nametag(1:1) == ">")
     172              :                ntag = 1
     173              :             END IF
     174          564 :          ELSE IF (ntag == 1) THEN
     175              :             ! we are looking for 1st level tags
     176          564 :             IF (nametag(2:8) == "PP_INFO") THEN
     177           28 :                CPASSERT(nametag(9:9) == ">")
     178           28 :                CALL upf_info_section(parser, pot)
     179          536 :             ELSE IF (nametag(2:10) == "PP_HEADER") THEN
     180           38 :                IF (.NOT. (nametag(11:11) == ">")) THEN
     181           38 :                   CALL upf_header_option(parser, pot)
     182              :                END IF
     183           38 :                IF (readaug .AND. pot%is_ultrasoft .AND. .NOT. pot%is_paw .AND. pot%has_wfc) THEN
     184            2 :                   CPASSERT(.NOT. ALLOCATED(pot%partial_waves))
     185            2 :                   ALLOCATE (pot%partial_waves)
     186              :                END IF
     187          498 :             ELSE IF (nametag(2:8) == "PP_MESH") THEN
     188           38 :                IF (.NOT. (nametag(9:9) == ">")) THEN
     189           32 :                   CALL upf_mesh_option(parser, pot)
     190              :                END IF
     191           38 :                CALL upf_mesh_section(parser, pot)
     192          460 :             ELSE IF (nametag(2:8) == "PP_NLCC") THEN
     193            6 :                IF (nametag(9:9) == ">") THEN
     194            0 :                   CALL upf_nlcc_section(parser, pot, .FALSE.)
     195              :                ELSE
     196            6 :                   CALL upf_nlcc_section(parser, pot, .TRUE.)
     197              :                END IF
     198          454 :             ELSE IF (nametag(2:9) == "PP_LOCAL") THEN
     199           38 :                IF (nametag(10:10) == ">") THEN
     200            6 :                   CALL upf_local_section(parser, pot, .FALSE.)
     201              :                ELSE
     202           32 :                   CALL upf_local_section(parser, pot, .TRUE.)
     203              :                END IF
     204          416 :             ELSE IF (nametag(2:12) == "PP_NONLOCAL") THEN
     205           38 :                CPASSERT(nametag(13:13) == ">")
     206           38 :                CALL upf_nonlocal_section(parser, pot, readaug)
     207          378 :             ELSE IF (nametag(2:13) == "PP_SEMILOCAL") THEN
     208            2 :                CALL upf_semilocal_section(parser, pot)
     209          376 :             ELSE IF (nametag(2:9) == "PP_PSWFC") THEN
     210              :                ! skip section for now
     211          338 :             ELSE IF (nametag(2:12) == "PP_FULL_WFC") THEN
     212            4 :                IF (ALLOCATED(pot%partial_waves)) THEN
     213            2 :                   CALL upf_full_wfc_section(parser, pot%partial_waves, nametag, pot%mesh_size, pot%number_of_proj)
     214              :                END IF
     215          334 :             ELSE IF (nametag(2:11) == "PP_RHOATOM") THEN
     216              :                ! skip section for now
     217          306 :             ELSE IF (nametag(2:7) == "PP_PAW") THEN
     218              :                ! skip section for now
     219          306 :             ELSE IF (nametag(2:6) == "/UPF>") THEN
     220              :                EXIT
     221              :             END IF
     222              :          END IF
     223              :       END DO
     224           38 :       CALL parser_release(parser)
     225              : 
     226           38 :       CPASSERT(ntag > 0)
     227              : 
     228              :       ! rescale projectors
     229           38 :       IF (ALLOCATED(pot%beta)) THEN
     230           38 :          CPASSERT(ALLOCATED(pot%r) .AND. ALLOCATED(pot%rab))
     231          108 :          DO ib = 1, pot%number_of_proj
     232          108 :             IF (pot%r(1) == 0.0_dp) THEN
     233        39456 :                pot%beta(2:, ib) = pot%beta(2:, ib)/pot%r(2:)
     234              :             ELSE
     235        11532 :                pot%beta(:, ib) = pot%beta(:, ib)/pot%r(:)
     236              :             END IF
     237              :          END DO
     238              :       END IF
     239              : 
     240              :       ! test for not supported options
     241           38 :       IF (readall) THEN
     242           36 :          IF (pot%is_ultrasoft .AND. .NOT. readaug) THEN
     243            0 :             CPABORT("UPF ultrasoft pseudopotential not implemented")
     244              :          END IF
     245           36 :          IF (pot%is_paw) THEN
     246            0 :             CPABORT("UPF PAW potential not implemented")
     247              :          END IF
     248              :       END IF
     249           38 :       IF (readaug .AND. pot%is_ultrasoft .AND. .NOT. pot%is_paw) THEN
     250            6 :          CPASSERT(ALLOCATED(pot%qij) .AND. ALLOCATED(pot%qijl))
     251              :       END IF
     252              : 
     253           38 :       IF (ALLOCATED(pot%partial_waves)) THEN
     254            2 :          CPASSERT(ALLOCATED(pot%partial_waves%ae_wfc))
     255            2 :          CPASSERT(ALLOCATED(pot%partial_waves%ps_wfc))
     256            6 :          CPASSERT(ALL(pot%partial_waves%angular_momenta == pot%lbeta))
     257              :       END IF
     258              : 
     259          114 :    END SUBROUTINE atom_read_upf_v2
     260              : 
     261              : ! **************************************************************************************************
     262              : !> \brief ...
     263              : !> \param parser ...
     264              : !> \param pot ...
     265              : ! **************************************************************************************************
     266           28 :    SUBROUTINE upf_info_section(parser, pot)
     267              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     268              :       TYPE(atom_upfpot_type)                             :: pot
     269              : 
     270              :       CHARACTER(LEN=default_string_length)               :: line, string
     271              :       INTEGER                                            :: icount, iline
     272              :       LOGICAL                                            :: at_end
     273              : 
     274           28 :       icount = 0
     275              :       DO
     276          558 :          CALL parser_get_next_line(parser, 1, at_end)
     277          558 :          CPASSERT(.NOT. at_end)
     278          558 :          iline = parser%buffer%present_line_number
     279          558 :          line = TRIM(parser%buffer%input_lines(iline))
     280          558 :          CALL parser_get_object(parser, string)
     281          558 :          IF (string(1:10) == "</PP_INFO>") EXIT
     282          530 :          icount = icount + 1
     283          530 :          IF (icount > pot%maxinfo) CYCLE
     284          530 :          pot%info(icount) = line
     285              :       END DO
     286           28 :       pot%maxinfo = icount
     287              : 
     288           28 :    END SUBROUTINE upf_info_section
     289              : 
     290              : ! **************************************************************************************************
     291              : !> \brief ...
     292              : !> \param parser ...
     293              : !> \param pot ...
     294              : ! **************************************************************************************************
     295           38 :    SUBROUTINE upf_header_option(parser, pot)
     296              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     297              :       TYPE(atom_upfpot_type)                             :: pot
     298              : 
     299              :       CHARACTER(LEN=default_string_length)               :: string
     300              :       LOGICAL                                            :: at_end
     301              : 
     302              :       DO
     303          834 :          IF (parser_test_next_token(parser) == "EOL") THEN
     304          704 :             CALL parser_get_next_line(parser, 1, at_end)
     305         1538 :             CPASSERT(.NOT. at_end)
     306              :          END IF
     307          834 :          CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     308          834 :          IF (string == "/>") EXIT
     309           38 :          SELECT CASE (string)
     310              :          CASE ("GENERATED")
     311           28 :             CALL parser_get_object(parser, pot%generated, allow_empty=.TRUE.)
     312              :          CASE ("AUTHOR")
     313           28 :             CALL parser_get_object(parser, pot%author, allow_empty=.TRUE.)
     314              :          CASE ("DATE")
     315           28 :             CALL parser_get_object(parser, pot%date, allow_empty=.TRUE.)
     316              :          CASE ("COMMENT")
     317           28 :             CALL parser_get_object(parser, pot%comment, allow_empty=.TRUE.)
     318              :          CASE ("ELEMENT")
     319           38 :             CALL parser_get_object(parser, pot%symbol)
     320           38 :             CPASSERT(2 <= LEN(pot%symbol))
     321              :          CASE ("PSEUDO_TYPE")
     322           38 :             CALL parser_get_object(parser, pot%pseudo_type)
     323              :          CASE ("RELATIVISTIC")
     324           28 :             CALL parser_get_object(parser, pot%relativistic)
     325              :          CASE ("IS_ULTRASOFT")
     326           36 :             CALL parser_get_object(parser, pot%is_ultrasoft)
     327              :          CASE ("IS_PAW")
     328           34 :             CALL parser_get_object(parser, pot%is_paw)
     329              :          CASE ("IS_COULOMB")
     330           28 :             CALL parser_get_object(parser, pot%is_coulomb)
     331              :          CASE ("HAS_SO")
     332           28 :             CALL parser_get_object(parser, pot%has_so)
     333              :          CASE ("HAS_WFC")
     334           34 :             CALL parser_get_object(parser, pot%has_wfc)
     335              :          CASE ("HAS_GIPAW")
     336           28 :             CALL parser_get_object(parser, pot%has_gipaw)
     337              :          CASE ("PAW_AS_GIPAW")
     338           22 :             CALL parser_get_object(parser, pot%paw_as_gipaw)
     339              :          CASE ("CORE_CORRECTION")
     340           28 :             CALL parser_get_object(parser, pot%core_correction)
     341              :          CASE ("FUNCTIONAL")
     342           28 :             CALL parser_get_object(parser, pot%functional)
     343              :          CASE ("Z_VALENCE")
     344           38 :             CALL parser_get_object(parser, pot%zion)
     345              :          CASE ("TOTAL_PSENERGY")
     346           28 :             CALL parser_get_object(parser, pot%total_psenergy)
     347              :          CASE ("WFC_CUTOFF")
     348           22 :             CALL parser_get_object(parser, pot%wfc_cutoff)
     349              :          CASE ("RHO_CUTOFF")
     350           28 :             CALL parser_get_object(parser, pot%rho_cutoff)
     351              :          CASE ("L_MAX")
     352           38 :             CALL parser_get_object(parser, pot%l_max)
     353              :          CASE ("L_MAX_RHO")
     354           22 :             CALL parser_get_object(parser, pot%l_max_rho)
     355              :          CASE ("L_LOCAL")
     356           28 :             CALL parser_get_object(parser, pot%l_local)
     357              :          CASE ("MESH_SIZE")
     358           38 :             CALL parser_get_object(parser, pot%mesh_size)
     359              :          CASE ("NUMBER_OF_WFC")
     360           34 :             CALL parser_get_object(parser, pot%number_of_wfc)
     361              :          CASE ("NUMBER_OF_PROJ")
     362           38 :             CALL parser_get_object(parser, pot%number_of_proj)
     363              :          CASE DEFAULT
     364            0 :             CPWARN(string)
     365              :             CALL cp_abort(__LOCATION__, "Error while parsing UPF header: "// &
     366          796 :                           "Adjust format of delimiters ... only double quotes are admissible.")
     367              :          END SELECT
     368              :       END DO
     369              : 
     370           38 :    END SUBROUTINE upf_header_option
     371              : 
     372              : ! **************************************************************************************************
     373              : !> \brief ...
     374              : !> \param parser ...
     375              : !> \param pot ...
     376              : ! **************************************************************************************************
     377           32 :    SUBROUTINE upf_mesh_option(parser, pot)
     378              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     379              :       TYPE(atom_upfpot_type)                             :: pot
     380              : 
     381              :       CHARACTER(LEN=default_string_length)               :: string
     382              :       INTEGER                                            :: jj
     383              :       LOGICAL                                            :: at_end
     384              : 
     385              :       DO
     386          152 :          IF (parser_test_next_token(parser) == "EOL") THEN
     387           22 :             CALL parser_get_next_line(parser, 1, at_end)
     388          174 :             CPASSERT(.NOT. at_end)
     389              :          END IF
     390          152 :          CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     391          152 :          IF (string == ">") EXIT
     392           32 :          SELECT CASE (string)
     393              :          CASE ("DX")
     394           22 :             CALL parser_get_object(parser, pot%dx)
     395              :          CASE ("XMIN")
     396           22 :             CALL parser_get_object(parser, pot%xmin)
     397              :          CASE ("RMAX")
     398           22 :             CALL parser_get_object(parser, pot%rmax)
     399              :          CASE ("MESH")
     400           32 :             CALL parser_get_object(parser, jj)
     401           32 :             CPASSERT(pot%mesh_size == jj)
     402              :          CASE ("ZMESH")
     403           22 :             CALL parser_get_object(parser, pot%zmesh)
     404              :          CASE DEFAULT
     405          120 :             CPABORT("Unknown UPF PP_MESH option <"//TRIM(string)//"> found")
     406              :          END SELECT
     407              : 
     408              :       END DO
     409              : 
     410           32 :    END SUBROUTINE upf_mesh_option
     411              : 
     412              : ! **************************************************************************************************
     413              : !> \brief ...
     414              : !> \param parser ...
     415              : !> \param pot ...
     416              : ! **************************************************************************************************
     417           38 :    SUBROUTINE upf_mesh_section(parser, pot)
     418              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     419              :       TYPE(atom_upfpot_type)                             :: pot
     420              : 
     421              :       CHARACTER(LEN=default_string_length)               :: line, string, string2
     422              :       INTEGER                                            :: icount, m, mc, ms
     423              :       LOGICAL                                            :: at_end
     424              : 
     425              :       DO
     426          190 :          CALL parser_get_next_line(parser, 1, at_end)
     427          190 :          CPASSERT(.NOT. at_end)
     428          190 :          CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     429           38 :          SELECT CASE (string)
     430              :          CASE ("<PP_R", "<PP_R>")
     431           38 :             m = pot%mesh_size
     432           38 :             ms = pot%mesh_size
     433              :             mc = 1
     434           38 :             IF (string /= "<PP_R>") THEN
     435              :                ! options
     436              :                DO
     437          118 :                   IF (parser_test_next_token(parser) == "EOL") THEN
     438            0 :                      CALL parser_get_next_line(parser, 1, at_end)
     439          118 :                      CPASSERT(.NOT. at_end)
     440              :                   END IF
     441          118 :                   CALL parser_get_object(parser, string2, lower_to_upper=.TRUE.)
     442          118 :                   IF (string2 == ">") EXIT
     443           30 :                   SELECT CASE (string2)
     444              :                   CASE ("TYPE")
     445           30 :                      CALL parser_get_object(parser, line, lower_to_upper=.TRUE.)
     446           30 :                      CPASSERT(line == "REAL")
     447              :                   CASE ("SIZE")
     448           30 :                      CALL parser_get_object(parser, ms)
     449           30 :                      CPASSERT(ms <= m)
     450              :                   CASE ("COLUMNS")
     451           28 :                      CALL parser_get_object(parser, mc)
     452              :                   CASE DEFAULT
     453           88 :                      CPABORT("Unknown UPF PP_R option <"//TRIM(string2)//"> found")
     454              :                   END SELECT
     455              :                END DO
     456              :             END IF
     457          114 :             ALLOCATE (pot%r(m))
     458        27386 :             pot%r = 0.0_dp
     459              :             icount = 1
     460        33418 :             DO WHILE (icount <= ms)
     461        33418 :                IF (parser_test_next_token(parser) == "EOL") THEN
     462         6032 :                   CALL parser_get_next_line(parser, 1, at_end)
     463         6032 :                   CPASSERT(.NOT. at_end)
     464              :                ELSE
     465        27348 :                   CALL parser_get_object(parser, pot%r(icount))
     466        60728 :                   icount = icount + 1
     467              :                END IF
     468              :             END DO
     469              :          CASE ("<PP_RAB", "<PP_RAB>")
     470           38 :             m = pot%mesh_size
     471           38 :             ms = pot%mesh_size
     472              :             mc = 1
     473           38 :             IF (string /= "<PP_RAB>") THEN
     474              :                ! options
     475              :                DO
     476          118 :                   IF (parser_test_next_token(parser) == "EOL") THEN
     477            0 :                      CALL parser_get_next_line(parser, 1, at_end)
     478          118 :                      CPASSERT(.NOT. at_end)
     479              :                   END IF
     480          118 :                   CALL parser_get_object(parser, string2, lower_to_upper=.TRUE.)
     481          118 :                   IF (string2 == ">") EXIT
     482           30 :                   SELECT CASE (string2)
     483              :                   CASE ("TYPE")
     484           30 :                      CALL parser_get_object(parser, line, lower_to_upper=.TRUE.)
     485           30 :                      CPASSERT(line == "REAL")
     486              :                   CASE ("SIZE")
     487           30 :                      CALL parser_get_object(parser, ms)
     488           30 :                      CPASSERT(ms <= m)
     489              :                   CASE ("COLUMNS")
     490           28 :                      CALL parser_get_object(parser, mc)
     491              :                   CASE DEFAULT
     492           88 :                      CPABORT("Unknown UPF PP_RAB option <"//TRIM(string2)//"> found")
     493              :                   END SELECT
     494              :                END DO
     495              :             END IF
     496          114 :             ALLOCATE (pot%rab(m))
     497        27386 :             pot%rab = 0.0_dp
     498              :             icount = 1
     499        33418 :             DO WHILE (icount <= ms)
     500        33418 :                IF (parser_test_next_token(parser) == "EOL") THEN
     501         6032 :                   CALL parser_get_next_line(parser, 1, at_end)
     502         6032 :                   CPASSERT(.NOT. at_end)
     503              :                ELSE
     504        27348 :                   CALL parser_get_object(parser, pot%rab(icount))
     505        60728 :                   icount = icount + 1
     506              :                END IF
     507              :             END DO
     508              :          CASE ("</PP_MESH>")
     509          190 :             EXIT
     510              :          CASE DEFAULT
     511              :             !
     512              :          END SELECT
     513              :       END DO
     514              : 
     515           38 :    END SUBROUTINE upf_mesh_section
     516              : 
     517              : ! **************************************************************************************************
     518              : !> \brief ...
     519              : !> \param parser ...
     520              : !> \param pot ...
     521              : !> \param options ...
     522              : ! **************************************************************************************************
     523            6 :    SUBROUTINE upf_nlcc_section(parser, pot, options)
     524              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     525              :       TYPE(atom_upfpot_type)                             :: pot
     526              :       LOGICAL, INTENT(IN)                                :: options
     527              : 
     528              :       CHARACTER(LEN=default_string_length)               :: line, string
     529              :       INTEGER                                            :: icount, m, mc, ms
     530              :       LOGICAL                                            :: at_end
     531              : 
     532            6 :       m = pot%mesh_size
     533            6 :       ms = m
     534              :       mc = 1
     535            6 :       IF (options) THEN
     536              :          DO
     537           24 :             IF (parser_test_next_token(parser) == "EOL") THEN
     538            0 :                CALL parser_get_next_line(parser, 1, at_end)
     539           24 :                CPASSERT(.NOT. at_end)
     540              :             END IF
     541           24 :             CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     542           24 :             IF (string == ">") EXIT
     543            6 :             SELECT CASE (string)
     544              :             CASE ("TYPE")
     545            6 :                CALL parser_get_object(parser, line, lower_to_upper=.TRUE.)
     546            6 :                CPASSERT(line == "REAL")
     547              :             CASE ("SIZE")
     548            6 :                CALL parser_get_object(parser, ms)
     549            6 :                CPASSERT(ms <= m)
     550              :             CASE ("COLUMNS")
     551            6 :                CALL parser_get_object(parser, mc)
     552              :             CASE DEFAULT
     553           18 :                CPABORT("Unknown UPF PP_NLCC option <"//TRIM(string)//"> found")
     554              :             END SELECT
     555              :          END DO
     556              :       END IF
     557              : 
     558           18 :       ALLOCATE (pot%rho_nlcc(m))
     559         6582 :       pot%rho_nlcc = 0.0_dp
     560              :       icount = 1
     561         8226 :       DO WHILE (icount <= ms)
     562         8226 :          IF (parser_test_next_token(parser) == "EOL") THEN
     563         1644 :             CALL parser_get_next_line(parser, 1, at_end)
     564         1644 :             CPASSERT(.NOT. at_end)
     565              :          ELSE
     566         6576 :             CALL parser_get_object(parser, pot%rho_nlcc(icount))
     567        14796 :             icount = icount + 1
     568              :          END IF
     569              :       END DO
     570              : 
     571            6 :       CALL parser_get_next_line(parser, 1, at_end)
     572            6 :       CPASSERT(.NOT. at_end)
     573            6 :       CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     574            6 :       CPASSERT(string == "</PP_NLCC>")
     575              : 
     576            6 :    END SUBROUTINE upf_nlcc_section
     577              : 
     578              : ! **************************************************************************************************
     579              : !> \brief ...
     580              : !> \param parser ...
     581              : !> \param pot ...
     582              : !> \param options ...
     583              : ! **************************************************************************************************
     584           38 :    SUBROUTINE upf_local_section(parser, pot, options)
     585              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     586              :       TYPE(atom_upfpot_type)                             :: pot
     587              :       LOGICAL, INTENT(IN)                                :: options
     588              : 
     589              :       CHARACTER(LEN=default_string_length)               :: line, string
     590              :       INTEGER                                            :: icount, m, mc, ms
     591              :       LOGICAL                                            :: at_end
     592              : 
     593           38 :       m = pot%mesh_size
     594           38 :       ms = m
     595              :       mc = 1
     596           38 :       IF (options) THEN
     597              :          DO
     598          124 :             IF (parser_test_next_token(parser) == "EOL") THEN
     599            0 :                CALL parser_get_next_line(parser, 1, at_end)
     600          124 :                CPASSERT(.NOT. at_end)
     601              :             END IF
     602          124 :             CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     603          124 :             IF (string == ">") EXIT
     604           32 :             SELECT CASE (string)
     605              :             CASE ("TYPE")
     606           32 :                CALL parser_get_object(parser, line, lower_to_upper=.TRUE.)
     607           32 :                CPASSERT(line == "REAL")
     608              :             CASE ("SIZE")
     609           32 :                CALL parser_get_object(parser, ms)
     610           32 :                CPASSERT(ms <= m)
     611              :             CASE ("COLUMNS")
     612           28 :                CALL parser_get_object(parser, mc)
     613              :             CASE DEFAULT
     614           92 :                CPABORT("Unknown UPF PP_LOCAL option <"//TRIM(string)//"> found")
     615              :             END SELECT
     616              :          END DO
     617              :       END IF
     618              : 
     619          114 :       ALLOCATE (pot%vlocal(m))
     620        27386 :       pot%vlocal = 0.0_dp
     621              :       icount = 1
     622        34240 :       DO WHILE (icount <= ms)
     623        34240 :          IF (parser_test_next_token(parser) == "EOL") THEN
     624         6854 :             CALL parser_get_next_line(parser, 1, at_end)
     625         6854 :             CPASSERT(.NOT. at_end)
     626              :          ELSE
     627        27348 :             CALL parser_get_object(parser, pot%vlocal(icount))
     628        61550 :             icount = icount + 1
     629              :          END IF
     630              :       END DO
     631              : 
     632              :       ! Ry -> Hartree
     633        27386 :       pot%vlocal = 0.5_dp*pot%vlocal
     634              : 
     635           38 :       CALL parser_get_next_line(parser, 1, at_end)
     636           38 :       CPASSERT(.NOT. at_end)
     637           38 :       CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     638           38 :       CPASSERT(string == "</PP_LOCAL>")
     639              : 
     640           38 :    END SUBROUTINE upf_local_section
     641              : 
     642              : ! **************************************************************************************************
     643              : !> \brief ...
     644              : !> \param parser ...
     645              : !> \param pot ...
     646              : !> \param readaug Import angular-resolved USPP augmentation data.
     647              : ! **************************************************************************************************
     648           38 :    SUBROUTINE upf_nonlocal_section(parser, pot, readaug)
     649              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     650              :       TYPE(atom_upfpot_type)                             :: pot
     651              :       LOGICAL, INTENT(IN)                                :: readaug
     652              : 
     653              :       CHARACTER(LEN=default_string_length)               :: line, string
     654              :       INTEGER                                            :: i1, i2, ibeta, icount, la, m, mc, ms, &
     655              :                                                             nbeta
     656              :       LOGICAL                                            :: at_end
     657              : 
     658           38 :       m = pot%mesh_size
     659           38 :       nbeta = pot%number_of_proj
     660          294 :       ALLOCATE (pot%dion(nbeta, nbeta), pot%beta(m, nbeta), pot%lbeta(nbeta))
     661          390 :       pot%dion = 0.0_dp
     662        51062 :       pot%beta = 0.0_dp
     663          108 :       pot%lbeta = -1
     664              : 
     665              :       ibeta = 0
     666              :       DO
     667          294 :          CALL parser_get_next_line(parser, 1, at_end)
     668          294 :          CPASSERT(.NOT. at_end)
     669          294 :          CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     670          332 :          IF (string(1:8) == "<PP_BETA") THEN
     671           70 :             ms = m
     672           70 :             ibeta = ibeta + 1
     673           70 :             i1 = ibeta
     674           70 :             la = 0
     675           70 :             CPASSERT(ibeta <= nbeta)
     676              :             DO
     677          516 :                IF (parser_test_next_token(parser) == "EOL") THEN
     678          266 :                   CALL parser_get_next_line(parser, 1, at_end)
     679          782 :                   CPASSERT(.NOT. at_end)
     680              :                END IF
     681          516 :                CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     682          516 :                IF (string == ">") EXIT
     683           70 :                SELECT CASE (string)
     684              :                CASE ("TYPE")
     685           58 :                   CALL parser_get_object(parser, line, lower_to_upper=.TRUE.)
     686           58 :                   CPASSERT(line == "REAL")
     687              :                CASE ("SIZE")
     688           70 :                   CALL parser_get_object(parser, ms)
     689           70 :                   CPASSERT(ms <= m)
     690              :                CASE ("COLUMNS")
     691           50 :                   CALL parser_get_object(parser, mc)
     692              :                CASE ("INDEX")
     693           70 :                   CALL parser_get_object(parser, i1)
     694           70 :                   CPASSERT(i1 <= nbeta)
     695              :                CASE ("ANGULAR_MOMENTUM")
     696           84 :                   CALL parser_get_object(parser, la)
     697              :                CASE ("LABEL")
     698           14 :                   CALL parser_get_object(parser, line, allow_empty=.TRUE.)
     699              :                   ! not used currently
     700              :                CASE ("CUTOFF_RADIUS_INDEX")
     701           50 :                   CALL parser_get_object(parser, line)
     702              :                   ! not used currently
     703              :                CASE ("CUTOFF_RADIUS")
     704           50 :                   CALL parser_get_object(parser, line)
     705              :                   ! not used currently
     706              :                CASE ("ULTRASOFT_CUTOFF_RADIUS")
     707           14 :                   CALL parser_get_object(parser, line)
     708              :                   ! not used currently
     709              :                CASE DEFAULT
     710          446 :                   CPABORT("Unknown UPF PP_BETA option <"//TRIM(string)//"> found")
     711              :                END SELECT
     712              :             END DO
     713           70 :             pot%lbeta(i1) = la
     714           70 :             icount = 1
     715        63776 :             DO WHILE (icount <= ms)
     716        63776 :                IF (parser_test_next_token(parser) == "EOL") THEN
     717        12752 :                   CALL parser_get_next_line(parser, 1, at_end)
     718        12752 :                   CPASSERT(.NOT. at_end)
     719              :                ELSE
     720        50954 :                   CALL parser_get_object(parser, pot%beta(icount, i1))
     721       114660 :                   icount = icount + 1
     722              :                END IF
     723              :             END DO
     724          224 :          ELSE IF (string(1:7) == "<PP_DIJ") THEN
     725           38 :             ms = nbeta*nbeta
     726           38 :             IF (string /= "<PP_DIJ>") THEN
     727              :                DO
     728          118 :                   IF (parser_test_next_token(parser) == "EOL") THEN
     729            0 :                      CALL parser_get_next_line(parser, 1, at_end)
     730          118 :                      CPASSERT(.NOT. at_end)
     731              :                   END IF
     732          118 :                   CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     733          118 :                   IF (string == ">") EXIT
     734           30 :                   SELECT CASE (string)
     735              :                   CASE ("TYPE")
     736           30 :                      CALL parser_get_object(parser, line, lower_to_upper=.TRUE.)
     737           30 :                      CPASSERT(line == "REAL")
     738              :                   CASE ("SIZE")
     739           30 :                      CALL parser_get_object(parser, ms)
     740           30 :                      CPASSERT(ms == nbeta*nbeta)
     741              :                   CASE ("COLUMNS")
     742           28 :                      CALL parser_get_object(parser, mc)
     743              :                   CASE DEFAULT
     744           88 :                      CPABORT("Unknown UPF PP_DIJ option <"//TRIM(string)//"> found")
     745              :                   END SELECT
     746              :                END DO
     747              :             END IF
     748              :             icount = 1
     749          398 :             DO WHILE (icount <= ms)
     750          398 :                IF (parser_test_next_token(parser) == "EOL") THEN
     751           78 :                   CALL parser_get_next_line(parser, 1, at_end)
     752           78 :                   CPASSERT(.NOT. at_end)
     753              :                ELSE
     754          282 :                   i1 = (icount - 1)/nbeta + 1
     755          282 :                   i2 = MOD(icount - 1, nbeta) + 1
     756          282 :                   CALL parser_get_object(parser, pot%dion(i1, i2))
     757          642 :                   icount = icount + 1
     758              :                END IF
     759              :             END DO
     760          186 :          ELSE IF (string(1:16) == "<PP_AUGMENTATION") THEN
     761            8 :             IF (readaug .AND. .NOT. pot%is_paw) CALL upf_augmentation_section(parser, pot)
     762          178 :          ELSE IF (string(1:14) == "</PP_NONLOCAL>") THEN
     763              :             EXIT
     764              :          END IF
     765              :       END DO
     766              : 
     767              :       ! Convert the complete beta*D*beta operator from Ry to Hartree without
     768              :       ! changing the tabulated projector amplitude. This also preserves the
     769              :       ! projector convention needed by augmentation charges and PAW duality.
     770              :       ! Some NC converters put energy units into beta and inverse energy into D;
     771              :       ! preserving their numerical beta still gives the correct operator here.
     772              :       ! The radial prefactor in PP_BETA is removed after reading the whole file.
     773          390 :       pot%dion = 0.5_dp*pot%dion
     774              : 
     775           38 :    END SUBROUTINE upf_nonlocal_section
     776              : 
     777              : ! **************************************************************************************************
     778              : !> \brief Read angular-momentum-resolved USPP augmentation in its tabulated convention.
     779              : !>        PP_Q is retained independently of the radial quadrature of PP_QIJL. Those
     780              : !>        quantities need not agree exactly in a finite-precision dataset. No energy
     781              : !>        conversion or projector normalization is applied to either augmentation array.
     782              : !> \param parser UPF token stream, positioned after the PP_AUGMENTATION tag name.
     783              : !> \param pot UPF data with the mesh and all beta angular momenta already read.
     784              : ! **************************************************************************************************
     785            6 :    SUBROUTINE upf_augmentation_section(parser, pot)
     786              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     787              :       TYPE(atom_upfpot_type), INTENT(INOUT)              :: pot
     788              : 
     789              :       CHARACTER(LEN=default_string_length)               :: string, tag, value
     790              :       INTEGER                                            :: i, j, k, l, lmax, m, nb, nc, nqf, nqlc, &
     791              :                                                             pair, size_data, tag_i, tag_j, tag_l
     792              :       LOGICAL                                            :: at_end, is_null, q_with_l, read_q, &
     793              :                                                             self_closing
     794            6 :       LOGICAL, ALLOCATABLE                               :: present_channel(:, :)
     795              : 
     796            6 :       CPASSERT(.NOT. ALLOCATED(pot%qij) .AND. .NOT. ALLOCATED(pot%qijl))
     797           18 :       CPASSERT(ALL(pot%lbeta >= 0))
     798            6 :       nb = pot%number_of_proj
     799            6 :       m = pot%mesh_size
     800           18 :       lmax = 2*MAXVAL(pot%lbeta)
     801            6 :       q_with_l = .FALSE.
     802            6 :       nqf = -1
     803            6 :       nqlc = lmax + 1
     804              :       DO
     805           24 :          IF (parser_test_next_token(parser) == "EOL") THEN
     806            0 :             CALL parser_get_next_line(parser, 1, at_end)
     807           24 :             CPASSERT(.NOT. at_end)
     808              :          END IF
     809           24 :          CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     810           24 :          IF (string == ">") EXIT
     811            6 :          SELECT CASE (string)
     812              :          CASE ("Q_WITH_L")
     813            6 :             CALL parser_get_object(parser, q_with_l)
     814              :          CASE ("NQF")
     815           12 :             CALL parser_get_object(parser, nqf)
     816              :          CASE ("NQLC")
     817            6 :             CALL parser_get_object(parser, nqlc)
     818              :          CASE DEFAULT
     819           18 :             CPABORT("Unknown UPF PP_AUGMENTATION option <"//TRIM(string)//"> found")
     820              :          END SELECT
     821              :       END DO
     822            6 :       IF (.NOT. q_with_l .OR. nqf /= 0) THEN
     823            0 :          CPABORT("Native USPP import requires angular-resolved PP_QIJL with nqf=0")
     824              :       END IF
     825            6 :       IF (nqlc == 0) nqlc = lmax + 1
     826            6 :       CPASSERT(nqlc >= lmax + 1)
     827            6 :       nc = nb*(nb + 1)/2
     828           66 :       ALLOCATE (pot%qij(nb, nb), pot%qijl(m, nc, 0:lmax), present_channel(nc, 0:lmax))
     829           42 :       pot%qij = 0.0_dp
     830          240 :       pot%qijl = 0.0_dp
     831            6 :       present_channel = .FALSE.
     832            6 :       read_q = .FALSE.
     833              :       DO
     834           64 :          CALL parser_get_next_line(parser, 1, at_end)
     835           64 :          CPASSERT(.NOT. at_end)
     836           64 :          CALL parser_get_object(parser, tag, lower_to_upper=.TRUE.)
     837           64 :          IF (tag == "</PP_AUGMENTATION>") EXIT
     838           58 :          IF (tag(1:2) == "</") CYCLE
     839           30 :          CPASSERT(tag(1:8) == "<PP_QIJL" .OR. tag == "<PP_Q" .OR. tag == "<PP_Q>")
     840           30 :          i = -1
     841           30 :          j = -1
     842           30 :          l = -1
     843           30 :          pair = -1
     844           30 :          size_data = m
     845           30 :          IF (tag == "<PP_Q" .OR. tag == "<PP_Q>") size_data = nb*nb
     846           30 :          is_null = .FALSE.
     847           30 :          self_closing = .FALSE.
     848           30 :          IF (tag /= "<PP_Q>") THEN
     849              :             DO
     850          130 :                IF (parser_test_next_token(parser) == "EOL") THEN
     851            4 :                   CALL parser_get_next_line(parser, 1, at_end)
     852          134 :                   CPASSERT(.NOT. at_end)
     853              :                END IF
     854          130 :                CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     855          130 :                IF (string == ">") EXIT
     856          108 :                IF (string == "/>") THEN
     857              :                   self_closing = .TRUE.
     858              :                   EXIT
     859              :                END IF
     860           22 :                SELECT CASE (string)
     861              :                CASE ("TYPE")
     862            2 :                   CALL parser_get_object(parser, value, lower_to_upper=.TRUE.)
     863            2 :                   CPASSERT(value == "REAL")
     864              :                CASE ("SIZE")
     865            4 :                   CALL parser_get_object(parser, size_data)
     866              :                CASE ("COLUMNS")
     867            0 :                   CALL parser_get_object(parser, value)
     868              :                CASE ("FIRST_INDEX")
     869           48 :                   CALL parser_get_object(parser, i)
     870              :                CASE ("SECOND_INDEX")
     871           48 :                   CALL parser_get_object(parser, j)
     872              :                CASE ("COMPOSITE_INDEX")
     873           48 :                   CALL parser_get_object(parser, pair)
     874              :                CASE ("ANGULAR_MOMENTUM")
     875           28 :                   CALL parser_get_object(parser, l)
     876              :                CASE ("IS_NULL")
     877            4 :                   CALL parser_get_object(parser, is_null)
     878              :                CASE DEFAULT
     879          106 :                   CPABORT("Unknown UPF augmentation array option <"//TRIM(string)//"> found")
     880              :                END SELECT
     881              :             END DO
     882              :          END IF
     883           36 :          IF (tag(1:8) == "<PP_QIJL") THEN
     884           24 :             CPASSERT(i >= 1 .AND. i <= j .AND. j <= nb)
     885           24 :             CPASSERT(pair == j*(j - 1)/2 + i)
     886           24 :             CPASSERT(l >= ABS(pot%lbeta(i) - pot%lbeta(j)))
     887           24 :             CPASSERT(l <= pot%lbeta(i) + pot%lbeta(j))
     888           24 :             CPASSERT(MODULO(pot%lbeta(i) + pot%lbeta(j) - l, 2) == 0)
     889              :             ! Cross-check the tag suffix as well as the explicit attributes.
     890           24 :             string = tag(10:)
     891          144 :             DO k = 1, LEN_TRIM(string)
     892          144 :                IF (string(k:k) == ".") string(k:k) = " "
     893              :             END DO
     894           24 :             READ (string, *) tag_i, tag_j, tag_l
     895           24 :             CPASSERT(tag_i == i .AND. tag_j == j .AND. tag_l == l)
     896           24 :             CPASSERT(.NOT. present_channel(pair, l))
     897           24 :             present_channel(pair, l) = .TRUE.
     898           24 :             IF (is_null) THEN
     899            2 :                CPASSERT(self_closing .AND. size_data == 0)
     900              :                CYCLE
     901              :             END IF
     902           22 :             CPASSERT(.NOT. self_closing .AND. size_data == m)
     903           88 :             DO k = 1, m
     904           88 :                DO WHILE (parser_test_next_token(parser) == "EOL")
     905           22 :                   CALL parser_get_next_line(parser, 1, at_end)
     906           22 :                   CPASSERT(.NOT. at_end)
     907              :                END DO
     908           88 :                CALL parser_get_object(parser, pot%qijl(k, pair, l))
     909              :             END DO
     910              :          ELSE
     911            6 :             CPASSERT(.NOT. read_q .AND. .NOT. self_closing .AND. .NOT. is_null)
     912            6 :             CPASSERT(size_data == nb*nb)
     913           18 :             DO j = 1, nb
     914           42 :                DO i = 1, nb
     915           30 :                   DO WHILE (parser_test_next_token(parser) == "EOL")
     916            6 :                      CALL parser_get_next_line(parser, 1, at_end)
     917            6 :                      CPASSERT(.NOT. at_end)
     918              :                   END DO
     919           36 :                   CALL parser_get_object(parser, pot%qij(i, j))
     920              :                END DO
     921              :             END DO
     922              :             read_q = .TRUE.
     923              :          END IF
     924              :       END DO
     925            6 :       CPASSERT(read_q)
     926           18 :       DO j = 1, nb
     927           36 :          DO i = 1, j
     928           18 :             pair = j*(j - 1)/2 + i
     929           54 :             DO l = ABS(pot%lbeta(i) - pot%lbeta(j)), pot%lbeta(i) + pot%lbeta(j), 2
     930           42 :                CPASSERT(present_channel(pair, l))
     931              :             END DO
     932              :          END DO
     933              :       END DO
     934            6 :    END SUBROUTINE upf_augmentation_section
     935              : 
     936              : ! **************************************************************************************************
     937              : !> \brief ...
     938              : !> \param parser ...
     939              : !> \param pot ...
     940              : ! **************************************************************************************************
     941            2 :    SUBROUTINE upf_semilocal_section(parser, pot)
     942              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
     943              :       TYPE(atom_upfpot_type)                             :: pot
     944              : 
     945              :       CHARACTER(LEN=default_string_length)               :: line, string
     946              :       INTEGER                                            :: i1, ib, icount, la, lmax, m, mc, ms
     947              :       LOGICAL                                            :: at_end
     948              : 
     949            2 :       m = pot%mesh_size
     950            2 :       lmax = pot%l_max
     951            8 :       ALLOCATE (pot%vsemi(m, lmax + 1))
     952         3698 :       pot%vsemi = 0.0_dp
     953              : 
     954              :       ib = 0
     955              :       DO
     956           14 :          CALL parser_get_next_line(parser, 1, at_end)
     957           14 :          CPASSERT(.NOT. at_end)
     958           14 :          CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     959           16 :          IF (string(1:7) == "<PP_VNL") THEN
     960            6 :             ms = m
     961            6 :             ib = ib + 1
     962            6 :             i1 = ib
     963            6 :             la = 0
     964            6 :             CPASSERT(ib <= lmax + 1)
     965              :             DO
     966           30 :                IF (parser_test_next_token(parser) == "EOL") THEN
     967            0 :                   CALL parser_get_next_line(parser, 1, at_end)
     968           30 :                   CPASSERT(.NOT. at_end)
     969              :                END IF
     970           30 :                CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
     971           30 :                IF (string == ">") EXIT
     972            6 :                SELECT CASE (string)
     973              :                CASE ("TYPE")
     974            6 :                   CALL parser_get_object(parser, line, lower_to_upper=.TRUE.)
     975            6 :                   CPASSERT(line == "REAL")
     976              :                CASE ("SIZE")
     977            6 :                   CALL parser_get_object(parser, ms)
     978            6 :                   CPASSERT(ms <= m)
     979              :                CASE ("COLUMNS")
     980            6 :                   CALL parser_get_object(parser, mc)
     981              :                CASE ("L")
     982            6 :                   CALL parser_get_object(parser, la)
     983              :                CASE DEFAULT
     984           24 :                   CPABORT("Unknown UPF PP_VNL option <"//TRIM(string)//"> found")
     985              :                END SELECT
     986              :             END DO
     987            6 :             i1 = la + 1
     988            6 :             icount = 1
     989         3468 :             DO WHILE (icount <= ms)
     990         3468 :                IF (parser_test_next_token(parser) == "EOL") THEN
     991          696 :                   CALL parser_get_next_line(parser, 1, at_end)
     992          696 :                   CPASSERT(.NOT. at_end)
     993              :                ELSE
     994         2766 :                   CALL parser_get_object(parser, pot%vsemi(icount, i1))
     995         6228 :                   icount = icount + 1
     996              :                END IF
     997              :             END DO
     998            8 :          ELSE IF (string(1:15) == "</PP_SEMILOCAL>") THEN
     999              :             EXIT
    1000              :          ELSE
    1001              :             !
    1002              :          END IF
    1003              :       END DO
    1004              :       ! Ry -> Hartree
    1005         3698 :       pot%vsemi = 0.5_dp*pot%vsemi
    1006              : 
    1007            2 :    END SUBROUTINE upf_semilocal_section
    1008              : 
    1009              : ! **************************************************************************************************
    1010              : !> \brief Skip complete XML comment lines before original full-wave data.
    1011              : !> \param parser ...
    1012              : !> \param at_end ...
    1013              : ! **************************************************************************************************
    1014           26 :    SUBROUTINE upf_next_line(parser, at_end)
    1015              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
    1016              :       LOGICAL, INTENT(OUT)                               :: at_end
    1017              : 
    1018           26 :       CHARACTER(LEN=:), ALLOCATABLE                      :: line
    1019              :       LOGICAL                                            :: in_comment
    1020              : 
    1021           26 :       in_comment = .FALSE.
    1022            0 :       DO
    1023           26 :          CALL parser_get_next_line(parser, 1, at_end)
    1024           26 :          IF (at_end) THEN
    1025            0 :             CPASSERT(.NOT. in_comment)
    1026           26 :             RETURN
    1027              :          END IF
    1028           26 :          line = ADJUSTL(parser%buffer%input_lines(parser%buffer%present_line_number))
    1029           26 :          IF (.NOT. in_comment .AND. INDEX(line, '<!--') /= 1) RETURN
    1030            0 :          in_comment = INDEX(line, '-->') == 0
    1031              :       END DO
    1032           52 :    END SUBROUTINE upf_next_line
    1033              : 
    1034              : ! **************************************************************************************************
    1035              : !> \brief Read an original full-wave array without normalization or unit conversion.
    1036              : !> \param parser ...
    1037              : !> \param tag ...
    1038              : !> \param values ...
    1039              : !> \param index_value ...
    1040              : !> \param angular_momentum ...
    1041              : ! **************************************************************************************************
    1042            8 :    SUBROUTINE upf_real_array(parser, tag, values, index_value, angular_momentum)
    1043              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
    1044              :       CHARACTER(LEN=*), INTENT(IN)                       :: tag
    1045              :       REAL(dp), INTENT(OUT)                              :: values(:)
    1046              :       INTEGER, INTENT(OUT), OPTIONAL                     :: index_value, angular_momentum
    1047              : 
    1048              :       CHARACTER(LEN=default_string_length)               :: name, string, value
    1049              :       INTEGER                                            :: i, last, n
    1050              :       LOGICAL                                            :: at_end
    1051              : 
    1052            8 :       n = SIZE(values)
    1053            8 :       last = LEN_TRIM(tag)
    1054            8 :       IF (PRESENT(index_value)) index_value = -1
    1055            8 :       IF (PRESENT(angular_momentum)) angular_momentum = -1
    1056            8 :       IF (tag(last:last) == ">") THEN
    1057            0 :          name = tag(2:last - 1)
    1058              :       ELSE
    1059            8 :          name = tag(2:last)
    1060              :          DO
    1061           24 :             IF (parser_test_next_token(parser) == "EOL") THEN
    1062            0 :                CALL upf_next_line(parser, at_end)
    1063           24 :                CPASSERT(.NOT. at_end)
    1064              :             END IF
    1065           24 :             CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
    1066           24 :             IF (string == ">") EXIT
    1067            8 :             SELECT CASE (string)
    1068              :             CASE ("TYPE")
    1069            2 :                CALL parser_get_object(parser, value, lower_to_upper=.TRUE.)
    1070            2 :                CPASSERT(value == "REAL")
    1071              :             CASE ("SIZE")
    1072            2 :                CALL parser_get_object(parser, n)
    1073            2 :                CPASSERT(n == SIZE(values))
    1074              :             CASE ("COLUMNS")
    1075            0 :                CALL parser_get_object(parser, value)
    1076              :             CASE ("INDEX")
    1077            4 :                CPASSERT(PRESENT(index_value))
    1078            4 :                CALL parser_get_object(parser, index_value)
    1079              :             CASE ("L")
    1080            8 :                CPASSERT(PRESENT(angular_momentum))
    1081            8 :                CALL parser_get_object(parser, angular_momentum)
    1082              :             CASE ("LABEL")
    1083            0 :                CALL parser_get_object(parser, value, allow_empty=.TRUE.)
    1084              :             CASE DEFAULT
    1085           28 :                CPABORT("Unknown UPF "//TRIM(name)//" option <"//TRIM(string)//"> found")
    1086              :             END SELECT
    1087              :          END DO
    1088              :       END IF
    1089           32 :       DO i = 1, n
    1090           32 :          DO WHILE (parser_test_next_token(parser) == "EOL")
    1091            8 :             CALL upf_next_line(parser, at_end)
    1092            8 :             CPASSERT(.NOT. at_end)
    1093              :          END DO
    1094           32 :          CALL parser_get_object(parser, values(i))
    1095              :       END DO
    1096           32 :       CPASSERT(ALL(ieee_is_finite(values)))
    1097            8 :       CALL upf_next_line(parser, at_end)
    1098            8 :       CPASSERT(.NOT. at_end)
    1099            8 :       CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
    1100            8 :       CPASSERT(string == "</"//TRIM(name)//">")
    1101            8 :    END SUBROUTINE upf_real_array
    1102              : 
    1103              : ! **************************************************************************************************
    1104              : !> \brief Import projector-indexed AE and PS partial waves, retaining r*phi(r).
    1105              : !> \param parser ...
    1106              : !> \param waves ...
    1107              : !> \param opening_tag ...
    1108              : !> \param mesh_size ...
    1109              : !> \param number_of_proj ...
    1110              : ! **************************************************************************************************
    1111            2 :    SUBROUTINE upf_full_wfc_section(parser, waves, opening_tag, mesh_size, number_of_proj)
    1112              :       TYPE(cp_parser_type), INTENT(INOUT)                :: parser
    1113              : 
    1114              :       CLASS(upf_partial_waves_type), INTENT(INOUT)        :: waves
    1115              :       CHARACTER(LEN=*), INTENT(IN)                       :: opening_tag
    1116              :       INTEGER, INTENT(IN)                                :: mesh_size, number_of_proj
    1117              : 
    1118              :       CHARACTER(LEN=default_string_length)               :: string, suffix, tag
    1119              :       INTEGER                                            :: i, index_value, ios, l, last, m, n, nb, &
    1120              :                                                             wave_type
    1121              :       LOGICAL                                            :: at_end
    1122            2 :       LOGICAL, ALLOCATABLE                               :: found(:, :)
    1123            2 :       REAL(dp), ALLOCATABLE                              :: values(:)
    1124              : 
    1125            2 :       nb = number_of_proj
    1126            2 :       m = mesh_size
    1127            2 :       CPASSERT(nb > 0 .AND. m > 0)
    1128            2 :       CPASSERT(.NOT. ALLOCATED(waves%ae_wfc) .AND. .NOT. ALLOCATED(waves%ps_wfc))
    1129            2 :       CPASSERT(.NOT. ALLOCATED(waves%angular_momenta))
    1130            2 :       IF (opening_tag /= "<PP_FULL_WFC>") THEN
    1131            2 :          DO
    1132            4 :             IF (parser_test_next_token(parser) == "EOL") THEN
    1133            0 :                CALL upf_next_line(parser, at_end)
    1134            4 :                CPASSERT(.NOT. at_end)
    1135              :             END IF
    1136            4 :             CALL parser_get_object(parser, string, lower_to_upper=.TRUE.)
    1137            4 :             IF (string == ">") EXIT
    1138            2 :             CPASSERT(string == "NUMBER_OF_WFC")
    1139            2 :             CALL parser_get_object(parser, n)
    1140            4 :             CPASSERT(n == nb)
    1141              :          END DO
    1142              :       END IF
    1143           16 :       ALLOCATE (waves%ae_wfc(m, nb), waves%ps_wfc(m, nb), waves%angular_momenta(nb))
    1144           10 :       ALLOCATE (found(nb, 2), values(m))
    1145            2 :       found = .FALSE.
    1146            6 :       waves%angular_momenta = -1
    1147           18 :       DO
    1148           10 :          CALL upf_next_line(parser, at_end)
    1149           10 :          CPASSERT(.NOT. at_end)
    1150           10 :          CALL parser_get_object(parser, tag, lower_to_upper=.TRUE.)
    1151           10 :          IF (tag == "</PP_FULL_WFC>") EXIT
    1152              :          SELECT CASE (tag(1:10))
    1153              :          CASE ("<PP_AEWFC.")
    1154            4 :             wave_type = 1
    1155              :          CASE ("<PP_PSWFC.")
    1156            4 :             wave_type = 2
    1157              :          CASE DEFAULT
    1158            8 :             CPABORT("Unknown UPF full partial-wave tag "//TRIM(tag))
    1159              :          END SELECT
    1160            8 :          last = LEN_TRIM(tag)
    1161            8 :          IF (tag(last:last) == ">") last = last - 1
    1162            8 :          suffix = tag(11:last)
    1163            8 :          READ (suffix, *, IOSTAT=ios) i
    1164            8 :          CPASSERT(ios == 0)
    1165            8 :          CPASSERT(i >= 1 .AND. i <= nb)
    1166            8 :          CPASSERT(.NOT. found(i, wave_type))
    1167            8 :          CALL upf_real_array(parser, tag, values, index_value, l)
    1168            8 :          IF (index_value /= -1) THEN
    1169            4 :             CPASSERT(index_value == i)
    1170              :          END IF
    1171            8 :          CPASSERT(l >= 0)
    1172            8 :          IF (waves%angular_momenta(i) >= 0) THEN
    1173            4 :             CPASSERT(l == waves%angular_momenta(i))
    1174              :          END IF
    1175            8 :          waves%angular_momenta(i) = l
    1176            8 :          IF (wave_type == 1) THEN
    1177           16 :             waves%ae_wfc(:, i) = values
    1178              :          ELSE
    1179           16 :             waves%ps_wfc(:, i) = values
    1180              :          END IF
    1181            8 :          found(i, wave_type) = .TRUE.
    1182              :       END DO
    1183           14 :       CPASSERT(ALL(found))
    1184            2 :    END SUBROUTINE upf_full_wfc_section
    1185              : 
    1186              : ! **************************************************************************************************
    1187              : !> \brief ...
    1188              : !> \param upfpot ...
    1189              : ! **************************************************************************************************
    1190        11760 :    PURE SUBROUTINE atom_release_upf(upfpot)
    1191              : 
    1192              :       TYPE(atom_upfpot_type), INTENT(INOUT)              :: upfpot
    1193              : 
    1194              :       ! Intrinsic assignment releases all allocatable components, including NLCC,
    1195              :       ! and clears metadata before this temporary is reused for another KIND.
    1196        11760 :       CALL upf_release(upfpot)
    1197              : 
    1198        11760 :    END SUBROUTINE atom_release_upf
    1199              : ! **************************************************************************************************
    1200              : 
    1201              : END MODULE atom_upf
        

Generated by: LCOV version 2.0-1