LCOV - code coverage report
Current view: top level - src - molden_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:1155b05) Lines: 59.5 % 247 147
Test Date: 2026-03-21 06:31:29 Functions: 100.0 % 3 3

            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  Functions handling the MOLDEN format. Split from mode_selective.
      10              : !> \author Teodoro Laino, 03.2009
      11              : ! **************************************************************************************************
      12              : MODULE molden_utils
      13              :    USE atomic_kind_types,               ONLY: get_atomic_kind
      14              :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      15              :                                               gto_basis_set_type
      16              :    USE cell_types,                      ONLY: cell_type
      17              :    USE cp_array_utils,                  ONLY: cp_1d_r_p_type
      18              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm
      19              :    USE cp_fm_types,                     ONLY: cp_fm_get_info,&
      20              :                                               cp_fm_get_submatrix,&
      21              :                                               cp_fm_type
      22              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      23              :                                               cp_logger_type
      24              :    USE cp_output_handling,              ONLY: cp_p_file,&
      25              :                                               cp_print_key_finished_output,&
      26              :                                               cp_print_key_should_output,&
      27              :                                               cp_print_key_unit_nr
      28              :    USE input_constants,                 ONLY: gto_cartesian,&
      29              :                                               gto_spherical
      30              :    USE input_section_types,             ONLY: section_vals_type,&
      31              :                                               section_vals_val_get
      32              :    USE kinds,                           ONLY: dp
      33              :    USE mathconstants,                   ONLY: pi
      34              :    USE orbital_pointers,                ONLY: nco,&
      35              :                                               nso
      36              :    USE orbital_transformation_matrices, ONLY: orbtramat
      37              :    USE particle_types,                  ONLY: particle_type
      38              :    USE periodic_table,                  ONLY: get_ptable_info
      39              :    USE physcon,                         ONLY: angstrom,&
      40              :                                               massunit
      41              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      42              :                                               get_qs_kind_set,&
      43              :                                               qs_kind_type
      44              :    USE qs_mo_types,                     ONLY: mo_set_type
      45              : #include "./base/base_uses.f90"
      46              : 
      47              :    IMPLICIT NONE
      48              : 
      49              :    PRIVATE
      50              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'molden_utils'
      51              :    LOGICAL, PARAMETER                   :: debug_this_module = .FALSE.
      52              : 
      53              :    INTEGER, PARAMETER                   :: molden_lmax = 4
      54              :    INTEGER, PARAMETER                   :: molden_ncomax = (molden_lmax + 1)*(molden_lmax + 2)/2 ! 15
      55              : 
      56              :    PUBLIC :: write_vibrations_molden, write_mos_molden
      57              : 
      58              : CONTAINS
      59              : 
      60              : ! **************************************************************************************************
      61              : !> \brief Write out the MOs in molden format for visualisation
      62              : !> \param mos the set of MOs (both spins, if UKS)
      63              : !> \param qs_kind_set for basis set info
      64              : !> \param particle_set particles data structure, for positions and kinds
      65              : !> \param print_section input section containing relevant print key
      66              : !> \param cell ...
      67              : !> \param unoccupied_orbs optional: unoccupied orbital coefficients from make_lumo_gpw
      68              : !> \param unoccupied_evals optional: unoccupied orbital eigenvalues
      69              : !> \author MattW, IainB
      70              : ! **************************************************************************************************
      71        10605 :    SUBROUTINE write_mos_molden(mos, qs_kind_set, particle_set, print_section, cell, &
      72        10605 :                                unoccupied_orbs, unoccupied_evals)
      73              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
      74              :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      75              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
      76              :       TYPE(section_vals_type), POINTER                   :: print_section
      77              :       TYPE(cell_type), OPTIONAL, POINTER                 :: cell
      78              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN), &
      79              :          OPTIONAL                                        :: unoccupied_orbs
      80              :       TYPE(cp_1d_r_p_type), DIMENSION(:), INTENT(IN), &
      81              :          OPTIONAL                                        :: unoccupied_evals
      82              : 
      83              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'write_mos_molden'
      84              :       CHARACTER(LEN=molden_lmax+1), PARAMETER            :: angmom = "spdfg"
      85              : 
      86              :       CHARACTER(LEN=15)                                  :: fmtstr1, fmtstr2
      87              :       CHARACTER(LEN=2)                                   :: element_symbol
      88              :       INTEGER :: gto_kind, handle, i, iatom, icgf, icol, ikind, ipgf, irow, irow_in, iset, isgf, &
      89              :          ishell, ispin, iw, lshell, ncgf, ncol_global, ndigits, nrow_global, nset, nsgf, numos, &
      90              :          unit_choice, z
      91        10605 :       INTEGER, DIMENSION(:), POINTER                     :: npgf, nshell
      92        10605 :       INTEGER, DIMENSION(:, :), POINTER                  :: l
      93              :       INTEGER, DIMENSION(molden_ncomax, 0:molden_lmax)   :: orbmap
      94              :       LOGICAL                                            :: print_warn, write_cell, write_nval
      95              :       REAL(KIND=dp)                                      :: expzet, prefac, scale_factor, zeff
      96        10605 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: cmatrix, smatrix
      97        10605 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: zet
      98        10605 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: gcc
      99              :       TYPE(cp_logger_type), POINTER                      :: logger
     100              :       TYPE(gto_basis_set_type), POINTER                  :: orb_basis_set
     101              : 
     102        10605 :       CALL timeset(routineN, handle)
     103              : 
     104        10605 :       logger => cp_get_default_logger()
     105        10605 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, print_section, ""), cp_p_file)) THEN
     106              : 
     107              :          iw = cp_print_key_unit_nr(logger, print_section, "", &
     108           28 :                                    extension=".molden", file_status='REPLACE')
     109              : 
     110           28 :          print_warn = .TRUE.
     111              : 
     112           28 :          CALL section_vals_val_get(print_section, "UNIT", i_val=unit_choice)
     113           28 :          IF (unit_choice == 2) THEN
     114              :             scale_factor = angstrom
     115              :          ELSE
     116           28 :             scale_factor = 1.0_dp
     117              :          END IF
     118              : 
     119           28 :          CALL section_vals_val_get(print_section, "NDIGITS", i_val=ndigits)
     120           28 :          ndigits = MIN(MAX(3, ndigits), 30)
     121           28 :          WRITE (UNIT=fmtstr1, FMT='("(I6,1X,ES",I0,".",I0,")")') ndigits + 7, ndigits
     122           28 :          WRITE (UNIT=fmtstr2, FMT='("((T51,2F",I0,".",I0,"))")') ndigits + 10, ndigits
     123              : 
     124           28 :          CALL section_vals_val_get(print_section, "GTO_KIND", i_val=gto_kind)
     125           28 :          CALL section_vals_val_get(print_section, "WRITE_CELL", l_val=write_cell)
     126           28 :          CALL section_vals_val_get(print_section, "WRITE_NVAL", l_val=write_nval)
     127              : 
     128           28 :          IF (mos(1)%use_mo_coeff_b) THEN
     129              :             ! we are using the dbcsr mo_coeff
     130              :             ! we copy it to the fm anyway
     131            0 :             DO ispin = 1, SIZE(mos)
     132            0 :                IF (.NOT. ASSOCIATED(mos(ispin)%mo_coeff_b)) THEN
     133            0 :                   CPASSERT(.FALSE.)
     134              :                END IF
     135              :                CALL copy_dbcsr_to_fm(mos(ispin)%mo_coeff_b, &
     136            0 :                                      mos(ispin)%mo_coeff) !fm->dbcsr
     137              :             END DO
     138              :          END IF
     139              : 
     140           28 :          IF (iw > 0) THEN
     141           14 :             WRITE (iw, '(T2,A)') "[Molden Format]"
     142           14 :             IF (write_cell) THEN
     143            0 :                IF (unit_choice == 2) THEN
     144            0 :                   WRITE (iw, '(T2,A)') "[Cell] Angs"
     145              :                ELSE
     146            0 :                   WRITE (iw, '(T2,A)') "[Cell] AU"
     147              :                END IF
     148              :                WRITE (iw, '(T2,3(F12.6,3X))') &
     149            0 :                   cell%hmat(1, 1)*scale_factor, cell%hmat(2, 1)*scale_factor, cell%hmat(3, 1)*scale_factor
     150              :                WRITE (iw, '(T2,3(F12.6,3X))') &
     151            0 :                   cell%hmat(1, 2)*scale_factor, cell%hmat(2, 2)*scale_factor, cell%hmat(3, 2)*scale_factor
     152              :                WRITE (iw, '(T2,3(F12.6,3X))') &
     153            0 :                   cell%hmat(1, 3)*scale_factor, cell%hmat(2, 3)*scale_factor, cell%hmat(3, 3)*scale_factor
     154              :             END IF
     155           14 :             IF (unit_choice == 2) THEN
     156            0 :                WRITE (iw, '(T2,A)') "[Atoms] Angs"
     157              :             ELSE
     158           14 :                WRITE (iw, '(T2,A)') "[Atoms] AU"
     159              :             END IF
     160          152 :             DO i = 1, SIZE(particle_set)
     161              :                CALL get_atomic_kind(atomic_kind=particle_set(i)%atomic_kind, &
     162          138 :                                     element_symbol=element_symbol)
     163          138 :                CALL get_ptable_info(element_symbol, number=z)
     164              : 
     165              :                WRITE (iw, '(T2,A2,I6,I6,3X,3(F12.6,3X))') &
     166          566 :                   element_symbol, i, z, particle_set(i)%r(:)*scale_factor
     167              :             END DO
     168           14 :             IF (write_nval) THEN
     169            0 :                WRITE (iw, '(T2,A)') "[Nval]"
     170            0 :                DO i = 1, SIZE(qs_kind_set)
     171            0 :                   CALL get_qs_kind(qs_kind_set(i), zeff=zeff)
     172              :                   WRITE (iw, '(T2,A,1X,I6)') &
     173            0 :                      TRIM(ADJUSTL(qs_kind_set(i)%element_symbol)), NINT(zeff)
     174              :                END DO
     175              :             END IF
     176              : 
     177           14 :             WRITE (iw, '(T2,A)') "[GTO]"
     178              : 
     179          152 :             DO i = 1, SIZE(particle_set)
     180              :                CALL get_atomic_kind(atomic_kind=particle_set(i)%atomic_kind, kind_number=ikind, &
     181          138 :                                     element_symbol=element_symbol)
     182          138 :                CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
     183          290 :                IF (ASSOCIATED(orb_basis_set)) THEN
     184          138 :                   WRITE (iw, '(T2,I8,I8)') i, 0
     185              :                   CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
     186              :                                          nset=nset, &
     187              :                                          npgf=npgf, &
     188              :                                          nshell=nshell, &
     189              :                                          l=l, &
     190              :                                          zet=zet, &
     191          138 :                                          gcc=gcc)
     192              : 
     193          434 :                   DO iset = 1, nset
     194          784 :                      DO ishell = 1, nshell(iset)
     195          350 :                         lshell = l(ishell, iset)
     196          646 :                         IF (lshell <= molden_lmax) THEN
     197              :                            WRITE (UNIT=iw, FMT='(T25,A2,4X,I4,4X,F4.2)') &
     198          350 :                               angmom(lshell + 1:lshell + 1), npgf(iset), 1.0_dp
     199              :                            ! MOLDEN expects the contraction coefficient of spherical NOT CARTESIAN NORMALISED
     200              :                            ! functions. So we undo the normalisation factors included in the gccs
     201              :                            ! Reverse engineered from basis_set_types, normalise_gcc_orb
     202          350 :                            prefac = 2_dp**lshell*(2/pi)**0.75_dp
     203          350 :                            expzet = 0.25_dp*(2*lshell + 3.0_dp)
     204              :                            WRITE (UNIT=iw, FMT=fmtstr2) &
     205         2264 :                               (zet(ipgf, iset), gcc(ipgf, ishell, iset)/(prefac*zet(ipgf, iset)**expzet), &
     206         2614 :                                ipgf=1, npgf(iset))
     207              :                         ELSE
     208            0 :                            IF (print_warn) THEN
     209              :                               CALL cp_warn(__LOCATION__, &
     210            0 :                                            "MOLDEN format does not support Gaussian orbitals with l > 4.")
     211            0 :                               print_warn = .FALSE.
     212              :                            END IF
     213              :                         END IF
     214              :                      END DO
     215              :                   END DO
     216              : 
     217          138 :                   WRITE (iw, '(A4)') "    "
     218              : 
     219              :                END IF
     220              : 
     221              :             END DO
     222              : 
     223           14 :             IF (gto_kind == gto_spherical) THEN
     224           14 :                WRITE (iw, '(T2,A)') "[5D7F]"
     225           14 :                WRITE (iw, '(T2,A)') "[9G]"
     226              :             END IF
     227              : 
     228           14 :             WRITE (iw, '(T2,A)') "[MO]"
     229              :          END IF
     230              : 
     231              :          !------------------------------------------------------------------------
     232              :          ! convert from CP2K to MOLDEN format ordering
     233              :          ! http://www.cmbi.ru.nl/molden/molden_format.html
     234              :          !"The following order of D, F and G functions is expected:
     235              :          !
     236              :          !   5D: D 0, D+1, D-1, D+2, D-2
     237              :          !   6D: xx, yy, zz, xy, xz, yz
     238              :          !
     239              :          !   7F: F 0, F+1, F-1, F+2, F-2, F+3, F-3
     240              :          !  10F: xxx, yyy, zzz, xyy, xxy, xxz, xzz, yzz, yyz, xyz
     241              :          !
     242              :          !   9G: G 0, G+1, G-1, G+2, G-2, G+3, G-3, G+4, G-4
     243              :          !  15G: xxxx yyyy zzzz xxxy xxxz yyyx yyyz zzzx zzzy,
     244              :          !       xxyy xxzz yyzz xxyz yyxz zzxy
     245              :          !"
     246              :          ! CP2K has x in the outer (slower loop), so
     247              :          ! xx, xy, xz, yy, yz,zz for l=2, for instance
     248              :          !
     249              :          ! iorb_cp2k = orbmap(iorb_molden, l), l = 0 .. 4
     250              :          ! -----------------------------------------------------------------------
     251           28 :          IF (iw > 0) THEN
     252           14 :             IF (gto_kind == gto_cartesian) THEN
     253              :                ! -----------------------------------------------------------------
     254              :                ! Use cartesian (6D, 10F, 15G) representation.
     255              :                ! This is only format VMD can process.
     256              :                ! -----------------------------------------------------------------
     257              :                orbmap = RESHAPE([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &
     258              :                                  1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &
     259              :                                  1, 4, 6, 2, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &
     260              :                                  1, 7, 10, 4, 2, 3, 6, 9, 8, 5, 0, 0, 0, 0, 0, &
     261              :                                  1, 11, 15, 2, 3, 7, 12, 10, 14, 4, 6, 13, 5, 8, 9], &
     262            0 :                                 [molden_ncomax, molden_lmax + 1])
     263           14 :             ELSE IF (gto_kind == gto_spherical) THEN
     264              :                ! -----------------------------------------------------------------
     265              :                ! Use spherical (5D, 7F, 9G) representation.
     266              :                ! -----------------------------------------------------------------
     267              :                orbmap = RESHAPE([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &
     268              :                                  3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &
     269              :                                  3, 4, 2, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &
     270              :                                  4, 5, 3, 6, 2, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, &
     271              :                                  5, 6, 4, 7, 3, 8, 2, 9, 1, 0, 0, 0, 0, 0, 0], &
     272           14 :                                 [molden_ncomax, molden_lmax + 1])
     273              :             END IF
     274              :          END IF
     275              : 
     276           72 :          DO ispin = 1, SIZE(mos)
     277              :             CALL cp_fm_get_info(mos(ispin)%mo_coeff, &
     278              :                                 nrow_global=nrow_global, &
     279           44 :                                 ncol_global=ncol_global)
     280          176 :             ALLOCATE (smatrix(nrow_global, ncol_global))
     281           44 :             CALL cp_fm_get_submatrix(mos(ispin)%mo_coeff, smatrix)
     282              : 
     283           44 :             IF (iw > 0) THEN
     284           22 :                IF (gto_kind == gto_cartesian) THEN
     285            0 :                   CALL get_qs_kind_set(qs_kind_set, ncgf=ncgf, nsgf=nsgf)
     286              : 
     287            0 :                   ALLOCATE (cmatrix(ncgf, ncgf))
     288              : 
     289            0 :                   cmatrix = 0.0_dp
     290              : 
     291              :                   ! Transform spherical MOs to Cartesian MOs
     292              : 
     293            0 :                   icgf = 1
     294            0 :                   isgf = 1
     295            0 :                   DO iatom = 1, SIZE(particle_set)
     296            0 :                      NULLIFY (orb_basis_set)
     297            0 :                      CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
     298              :                      CALL get_qs_kind(qs_kind_set(ikind), &
     299            0 :                                       basis_set=orb_basis_set)
     300            0 :                      IF (ASSOCIATED(orb_basis_set)) THEN
     301              :                         CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
     302              :                                                nset=nset, &
     303              :                                                nshell=nshell, &
     304            0 :                                                l=l)
     305            0 :                         DO iset = 1, nset
     306            0 :                            DO ishell = 1, nshell(iset)
     307            0 :                               lshell = l(ishell, iset)
     308              :                               CALL dgemm("T", "N", nco(lshell), mos(ispin)%nmo, nso(lshell), 1.0_dp, &
     309              :                                          orbtramat(lshell)%c2s, nso(lshell), &
     310              :                                          smatrix(isgf, 1), nsgf, 0.0_dp, &
     311            0 :                                          cmatrix(icgf, 1), ncgf)
     312            0 :                               icgf = icgf + nco(lshell)
     313            0 :                               isgf = isgf + nso(lshell)
     314              :                            END DO
     315              :                         END DO
     316              :                      END IF
     317              :                   END DO ! iatom
     318              :                END IF
     319              : 
     320           96 :                DO icol = 1, mos(ispin)%nmo
     321              :                   ! index of the first basis function for the given atom, set, and shell
     322           74 :                   irow = 1
     323              : 
     324              :                   ! index of the first basis function in MOLDEN file.
     325              :                   ! Due to limitation of the MOLDEN format, basis functions with l > molden_lmax
     326              :                   ! cannot be exported, so we need to renumber atomic orbitals
     327           74 :                   irow_in = 1
     328              : 
     329           74 :                   WRITE (iw, '(A,ES20.10)') 'Ene=', mos(ispin)%eigenvalues(icol)
     330           74 :                   IF (ispin < 2) THEN
     331           63 :                      WRITE (iw, '(A)') 'Spin= Alpha'
     332              :                   ELSE
     333           11 :                      WRITE (iw, '(A)') 'Spin= Beta'
     334              :                   END IF
     335           74 :                   WRITE (iw, '(A,F12.7)') 'Occup=', mos(ispin)%occupation_numbers(icol)
     336              : 
     337          544 :                   DO iatom = 1, SIZE(particle_set)
     338          448 :                      NULLIFY (orb_basis_set)
     339              :                      CALL get_atomic_kind(particle_set(iatom)%atomic_kind, &
     340          448 :                                           element_symbol=element_symbol, kind_number=ikind)
     341              :                      CALL get_qs_kind(qs_kind_set(ikind), &
     342          448 :                                       basis_set=orb_basis_set)
     343          970 :                      IF (ASSOCIATED(orb_basis_set)) THEN
     344              :                         CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
     345              :                                                nset=nset, &
     346              :                                                nshell=nshell, &
     347          448 :                                                l=l)
     348              : 
     349          448 :                         IF (gto_kind == gto_cartesian) THEN
     350              :                            ! ----------------------------------------------
     351              :                            ! Use cartesian (6D, 10F, 15G) representation.
     352              :                            ! ----------------------------------------------
     353            0 :                            icgf = 1
     354            0 :                            DO iset = 1, nset
     355            0 :                               DO ishell = 1, nshell(iset)
     356            0 :                                  lshell = l(ishell, iset)
     357              : 
     358            0 :                                  IF (lshell <= molden_lmax) THEN
     359              :                                     CALL print_coeffs(iw, fmtstr1, ndigits, irow_in, orbmap(:, lshell), &
     360            0 :                                                       cmatrix(irow:irow + nco(lshell) - 1, icol))
     361            0 :                                     irow_in = irow_in + nco(lshell)
     362              :                                  END IF
     363              : 
     364            0 :                                  irow = irow + nco(lshell)
     365              :                               END DO ! ishell
     366              :                            END DO
     367              : 
     368          448 :                         ELSE IF (gto_kind == gto_spherical) THEN
     369              :                            ! ----------------------------------------------
     370              :                            ! Use spherical (5D, 7F, 9G) representation.
     371              :                            ! ----------------------------------------------
     372         1544 :                            DO iset = 1, nset
     373         2880 :                               DO ishell = 1, nshell(iset)
     374         1336 :                                  lshell = l(ishell, iset)
     375              : 
     376         1336 :                                  IF (lshell <= molden_lmax) THEN
     377              :                                     CALL print_coeffs(iw, fmtstr1, ndigits, irow_in, orbmap(:, lshell), &
     378         1336 :                                                       smatrix(irow:irow + nso(lshell) - 1, icol))
     379         1336 :                                     irow_in = irow_in + nso(lshell)
     380              :                                  END IF
     381              : 
     382         2432 :                                  irow = irow + nso(lshell)
     383              :                               END DO
     384              :                            END DO
     385              :                         END IF
     386              : 
     387              :                      END IF
     388              :                   END DO ! iatom
     389              :                END DO
     390              :             END IF
     391              : 
     392           44 :             IF (ALLOCATED(cmatrix)) DEALLOCATE (cmatrix)
     393          116 :             IF (ALLOCATED(smatrix)) DEALLOCATE (smatrix)
     394              :          END DO
     395              : 
     396              :          ! Write unoccupied (virtual) orbitals if provided; only used with OT
     397           28 :          IF (PRESENT(unoccupied_orbs) .AND. PRESENT(unoccupied_evals)) THEN
     398            0 :             DO ispin = 1, SIZE(unoccupied_orbs)
     399              :                CALL cp_fm_get_info(unoccupied_orbs(ispin), &
     400              :                                    nrow_global=nrow_global, &
     401            0 :                                    ncol_global=numos)
     402            0 :                ALLOCATE (smatrix(nrow_global, numos))
     403            0 :                CALL cp_fm_get_submatrix(unoccupied_orbs(ispin), smatrix)
     404              : 
     405            0 :                IF (iw > 0) THEN
     406            0 :                   IF (gto_kind == gto_cartesian) THEN
     407            0 :                      CALL get_qs_kind_set(qs_kind_set, ncgf=ncgf, nsgf=nsgf)
     408            0 :                      ALLOCATE (cmatrix(ncgf, numos))
     409            0 :                      cmatrix = 0.0_dp
     410              : 
     411            0 :                      icgf = 1
     412            0 :                      isgf = 1
     413            0 :                      DO iatom = 1, SIZE(particle_set)
     414            0 :                         NULLIFY (orb_basis_set)
     415            0 :                         CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
     416            0 :                         CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
     417            0 :                         IF (ASSOCIATED(orb_basis_set)) THEN
     418              :                            CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
     419            0 :                                                   nset=nset, nshell=nshell, l=l)
     420            0 :                            DO iset = 1, nset
     421            0 :                               DO ishell = 1, nshell(iset)
     422            0 :                                  lshell = l(ishell, iset)
     423              :                                  CALL dgemm("T", "N", nco(lshell), numos, nso(lshell), 1.0_dp, &
     424              :                                             orbtramat(lshell)%c2s, nso(lshell), &
     425              :                                             smatrix(isgf, 1), nsgf, 0.0_dp, &
     426            0 :                                             cmatrix(icgf, 1), ncgf)
     427            0 :                                  icgf = icgf + nco(lshell)
     428            0 :                                  isgf = isgf + nso(lshell)
     429              :                               END DO
     430              :                            END DO
     431              :                         END IF
     432              :                      END DO
     433              :                   END IF
     434              : 
     435            0 :                   DO icol = 1, numos
     436            0 :                      irow = 1
     437            0 :                      irow_in = 1
     438              : 
     439            0 :                      WRITE (iw, '(A,ES20.10)') 'Ene=', unoccupied_evals(ispin)%array(icol)
     440            0 :                      IF (ispin < 2) THEN
     441            0 :                         WRITE (iw, '(A)') 'Spin= Alpha'
     442              :                      ELSE
     443            0 :                         WRITE (iw, '(A)') 'Spin= Beta'
     444              :                      END IF
     445            0 :                      WRITE (iw, '(A,F12.7)') 'Occup=', 0.0_dp
     446              : 
     447            0 :                      DO iatom = 1, SIZE(particle_set)
     448            0 :                         NULLIFY (orb_basis_set)
     449              :                         CALL get_atomic_kind(particle_set(iatom)%atomic_kind, &
     450            0 :                                              element_symbol=element_symbol, kind_number=ikind)
     451            0 :                         CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
     452            0 :                         IF (ASSOCIATED(orb_basis_set)) THEN
     453              :                            CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
     454            0 :                                                   nset=nset, nshell=nshell, l=l)
     455              : 
     456            0 :                            IF (gto_kind == gto_cartesian) THEN
     457            0 :                               icgf = 1
     458            0 :                               DO iset = 1, nset
     459            0 :                                  DO ishell = 1, nshell(iset)
     460            0 :                                     lshell = l(ishell, iset)
     461            0 :                                     IF (lshell <= molden_lmax) THEN
     462              :                                        CALL print_coeffs(iw, fmtstr1, ndigits, irow_in, orbmap(:, lshell), &
     463            0 :                                                          cmatrix(irow:irow + nco(lshell) - 1, icol))
     464            0 :                                        irow_in = irow_in + nco(lshell)
     465              :                                     END IF
     466            0 :                                     irow = irow + nco(lshell)
     467              :                                  END DO
     468              :                               END DO
     469            0 :                            ELSE IF (gto_kind == gto_spherical) THEN
     470            0 :                               DO iset = 1, nset
     471            0 :                                  DO ishell = 1, nshell(iset)
     472            0 :                                     lshell = l(ishell, iset)
     473            0 :                                     IF (lshell <= molden_lmax) THEN
     474              :                                        CALL print_coeffs(iw, fmtstr1, ndigits, irow_in, orbmap(:, lshell), &
     475            0 :                                                          smatrix(irow:irow + nso(lshell) - 1, icol))
     476            0 :                                        irow_in = irow_in + nso(lshell)
     477              :                                     END IF
     478            0 :                                     irow = irow + nso(lshell)
     479              :                                  END DO
     480              :                               END DO
     481              :                            END IF
     482              : 
     483              :                         END IF
     484              :                      END DO ! iatom
     485              :                   END DO ! icol
     486              :                END IF
     487              : 
     488            0 :                IF (ALLOCATED(cmatrix)) DEALLOCATE (cmatrix)
     489            0 :                IF (ALLOCATED(smatrix)) DEALLOCATE (smatrix)
     490              :             END DO ! ispin
     491              :          END IF
     492              : 
     493           28 :          CALL cp_print_key_finished_output(iw, logger, print_section, "")
     494              : 
     495              :       END IF
     496              : 
     497        10605 :       CALL timestop(handle)
     498              : 
     499        21210 :    END SUBROUTINE write_mos_molden
     500              : 
     501              : ! **************************************************************************************************
     502              : !> \brief Output MO coefficients formatted correctly for MOLDEN, omitting those <= 1E(-digits)
     503              : !> \param iw       output file unit
     504              : !> \param fmtstr1  format string
     505              : !> \param ndigits  number of significant digits in MO coefficients
     506              : !> \param irow_in  index of the first atomic orbital: mo_coeff(orbmap(1))
     507              : !> \param orbmap   array to map Gaussian functions from MOLDEN to CP2K ordering
     508              : !> \param mo_coeff MO coefficients
     509              : ! **************************************************************************************************
     510         1336 :    SUBROUTINE print_coeffs(iw, fmtstr1, ndigits, irow_in, orbmap, mo_coeff)
     511              :       INTEGER, INTENT(in)                                :: iw
     512              :       CHARACTER(LEN=*), INTENT(in)                       :: fmtstr1
     513              :       INTEGER, INTENT(in)                                :: ndigits, irow_in
     514              :       INTEGER, DIMENSION(molden_ncomax), INTENT(in)      :: orbmap
     515              :       REAL(KIND=dp), DIMENSION(:), INTENT(in)            :: mo_coeff
     516              : 
     517              :       INTEGER                                            :: orbital
     518              : 
     519        21376 :       DO orbital = 1, molden_ncomax
     520        21376 :          IF (orbmap(orbital) /= 0) THEN
     521         2504 :             IF (ABS(mo_coeff(orbmap(orbital))) >= 10.0_dp**(-ndigits)) THEN
     522         1573 :                WRITE (iw, fmtstr1) irow_in + orbital - 1, mo_coeff(orbmap(orbital))
     523              :             END IF
     524              :          END IF
     525              :       END DO
     526              : 
     527         1336 :    END SUBROUTINE print_coeffs
     528              : 
     529              : ! **************************************************************************************************
     530              : !> \brief writes the output for vibrational analysis in MOLDEN format
     531              : !> \param input ...
     532              : !> \param particles ...
     533              : !> \param freq ...
     534              : !> \param eigen_vec ...
     535              : !> \param intensities ...
     536              : !> \param calc_intens ...
     537              : !> \param dump_only_positive ...
     538              : !> \param logger ...
     539              : !> \param list array of mobile atom indices
     540              : !> \author Florian Schiffmann 11.2007
     541              : ! **************************************************************************************************
     542           54 :    SUBROUTINE write_vibrations_molden(input, particles, freq, eigen_vec, intensities, calc_intens, &
     543              :                                       dump_only_positive, logger, list)
     544              : 
     545              :       TYPE(section_vals_type), POINTER                   :: input
     546              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     547              :       REAL(KIND=dp), DIMENSION(:)                        :: freq
     548              :       REAL(KIND=dp), DIMENSION(:, :)                     :: eigen_vec
     549              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: intensities
     550              :       LOGICAL, INTENT(in)                                :: calc_intens, dump_only_positive
     551              :       TYPE(cp_logger_type), POINTER                      :: logger
     552              :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: list
     553              : 
     554              :       CHARACTER(len=*), PARAMETER :: routineN = 'write_vibrations_molden'
     555              : 
     556              :       CHARACTER(LEN=2)                                   :: element_symbol
     557              :       INTEGER                                            :: handle, i, iw, j, k, l, z
     558           54 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: my_list
     559              :       REAL(KIND=dp)                                      :: fint
     560              : 
     561           54 :       CALL timeset(routineN, handle)
     562              : 
     563              :       iw = cp_print_key_unit_nr(logger, input, "VIBRATIONAL_ANALYSIS%PRINT%MOLDEN_VIB", &
     564           54 :                                 extension=".mol", file_status='REPLACE')
     565              : 
     566           54 :       IF (iw > 0) THEN
     567           27 :          CPASSERT(MOD(SIZE(eigen_vec, 1), 3) == 0)
     568           27 :          CPASSERT(SIZE(freq, 1) == SIZE(eigen_vec, 2))
     569           81 :          ALLOCATE (my_list(SIZE(particles)))
     570              :          ! Either we have a list of the subset of mobile atoms,
     571              :          ! Or the eigenvectors must span the full space (all atoms)
     572           27 :          IF (PRESENT(list)) THEN
     573           57 :             my_list(:) = 0
     574           54 :             DO i = 1, SIZE(list)
     575           54 :                my_list(list(i)) = i
     576              :             END DO
     577              :          ELSE
     578           12 :             CPASSERT(SIZE(particles) == SIZE(eigen_vec, 1)/3)
     579          443 :             DO i = 1, SIZE(my_list)
     580          443 :                my_list(i) = i
     581              :             END DO
     582              :          END IF
     583           27 :          WRITE (iw, '(T2,A)') "[Molden Format]"
     584           27 :          WRITE (iw, '(T2,A)') "[Atoms] AU"
     585          500 :          DO i = 1, SIZE(particles)
     586              :             CALL get_atomic_kind(atomic_kind=particles(i)%atomic_kind, &
     587          473 :                                  element_symbol=element_symbol)
     588          473 :             CALL get_ptable_info(element_symbol, number=z)
     589              : 
     590              :             WRITE (iw, '(T2,A2,I8,I8,3X,3(F12.6,3X))') &
     591         1919 :                element_symbol, i, z, particles(i)%r(:)
     592              : 
     593              :          END DO
     594           27 :          WRITE (iw, '(T2,A)') "[FREQ]"
     595          159 :          DO i = 1, SIZE(freq, 1)
     596          159 :             IF ((.NOT. dump_only_positive) .OR. (freq(i) >= 0._dp)) WRITE (iw, '(T5,F12.6)') freq(i)
     597              :          END DO
     598           27 :          WRITE (iw, '(T2,A)') "[FR-COORD]"
     599          500 :          DO i = 1, SIZE(particles)
     600              :             CALL get_atomic_kind(atomic_kind=particles(i)%atomic_kind, &
     601          473 :                                  element_symbol=element_symbol)
     602              :             WRITE (iw, '(T2,A2,3X,3(F12.6,3X))') &
     603         1919 :                element_symbol, particles(i)%r(:)
     604              :          END DO
     605           27 :          WRITE (iw, '(T2,A)') "[FR-NORM-COORD]"
     606           27 :          l = 0
     607          159 :          DO i = 1, SIZE(eigen_vec, 2)
     608          159 :             IF ((.NOT. dump_only_positive) .OR. (freq(i) >= 0._dp)) THEN
     609          132 :                l = l + 1
     610          132 :                WRITE (iw, '(T2,A,1X,I6)') "vibration", l
     611         4071 :                DO j = 1, SIZE(particles)
     612         4071 :                   IF (my_list(j) /= 0) THEN
     613         3927 :                      k = (my_list(j) - 1)*3
     614         3927 :                      WRITE (iw, '(T2,3(F12.6,3X))') eigen_vec(k + 1, i), eigen_vec(k + 2, i), eigen_vec(k + 3, i)
     615              :                   ELSE
     616           12 :                      WRITE (iw, '(T2,3(F12.6,3X))') 0.0_dp, 0.0_dp, 0.0_dp
     617              :                   END IF
     618              :                END DO
     619              :             END IF
     620              :          END DO
     621           27 :          IF (calc_intens) THEN
     622           18 :             fint = massunit
     623              :             ! intensity units are a.u./amu
     624           18 :             WRITE (iw, '(T2,A)') "[INT]"
     625          118 :             DO i = 1, SIZE(intensities)
     626          118 :                IF ((.NOT. dump_only_positive) .OR. (freq(i) >= 0._dp)) WRITE (iw, '(3X,F18.6)') fint*intensities(i)**2
     627              :             END DO
     628              :          END IF
     629           27 :          DEALLOCATE (my_list)
     630              :       END IF
     631           54 :       CALL cp_print_key_finished_output(iw, logger, input, "VIBRATIONAL_ANALYSIS%PRINT%MOLDEN_VIB")
     632              : 
     633           54 :       CALL timestop(handle)
     634              : 
     635           54 :    END SUBROUTINE write_vibrations_molden
     636              : 
     637              : END MODULE molden_utils
        

Generated by: LCOV version 2.0-1