LCOV - code coverage report
Current view: top level - src/motion - vibrational_analysis.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:24d69ee) Lines: 98.2 % 605 594
Test Date: 2026-09-03 07:32:15 Functions: 100.0 % 7 7

            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 Module performing a vibrational analysis
      10              : !> \note
      11              : !>      Numerical accuracy for parallel runs:
      12              : !>       Each replica starts the SCF run from the one optimized
      13              : !>       in a previous run. It may happen then energies and derivatives
      14              : !>       of a serial run and a parallel run could be slightly different
      15              : !>       'cause of a different starting density matrix.
      16              : !>       Exact results are obtained using:
      17              : !>          EXTRAPOLATION USE_GUESS in QS section (Teo 08.2006)
      18              : !> \author Teodoro Laino 08.2006
      19              : ! **************************************************************************************************
      20              : MODULE vibrational_analysis
      21              :    USE atomic_kind_types,               ONLY: get_atomic_kind
      22              :    USE cell_types,                      ONLY: cell_type
      23              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      24              :                                               cp_blacs_env_release,&
      25              :                                               cp_blacs_env_type
      26              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      27              :                                               cp_fm_struct_release,&
      28              :                                               cp_fm_struct_type
      29              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      30              :                                               cp_fm_release,&
      31              :                                               cp_fm_set_all,&
      32              :                                               cp_fm_set_element,&
      33              :                                               cp_fm_type,&
      34              :                                               cp_fm_write_unformatted
      35              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      36              :                                               cp_logger_get_default_io_unit,&
      37              :                                               cp_logger_type
      38              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      39              :                                               cp_print_key_unit_nr
      40              :    USE cp_result_methods,               ONLY: get_results,&
      41              :                                               test_for_result
      42              :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      43              :                                               cp_subsys_type
      44              :    USE f77_interface,                   ONLY: f_env_add_defaults,&
      45              :                                               f_env_rm_defaults,&
      46              :                                               f_env_type
      47              :    USE force_env_types,                 ONLY: force_env_get,&
      48              :                                               force_env_type
      49              :    USE global_types,                    ONLY: global_environment_type
      50              :    USE grrm_utils,                      ONLY: write_grrm
      51              :    USE header,                          ONLY: vib_header
      52              :    USE input_constants,                 ONLY: do_rep_blocked
      53              :    USE input_section_types,             ONLY: section_type,&
      54              :                                               section_vals_get,&
      55              :                                               section_vals_get_subs_vals,&
      56              :                                               section_vals_type,&
      57              :                                               section_vals_val_get
      58              :    USE kinds,                           ONLY: default_string_length,&
      59              :                                               dp
      60              :    USE mathconstants,                   ONLY: pi
      61              :    USE mathlib,                         ONLY: diamat_all
      62              :    USE message_passing,                 ONLY: mp_para_env_type
      63              :    USE mode_selective,                  ONLY: ms_vb_anal
      64              :    USE molden_utils,                    ONLY: write_vibrations_molden
      65              :    USE molecule_kind_list_types,        ONLY: molecule_kind_list_type
      66              :    USE molecule_kind_types,             ONLY: fixd_constraint_type,&
      67              :                                               get_molecule_kind,&
      68              :                                               molecule_kind_type
      69              :    USE motion_utils,                    ONLY: rot_ana,&
      70              :                                               thrs_motion
      71              :    USE particle_list_types,             ONLY: particle_list_type
      72              :    USE particle_methods,                ONLY: write_particle_matrix
      73              :    USE particle_types,                  ONLY: particle_type
      74              :    USE physcon,                         ONLY: &
      75              :         a_bohr, angstrom, bohr, boltzmann, c_light, debye, e_mass, h_bar, hertz, joule, kelvin, &
      76              :         kjmol, massunit, n_avogadro, pascal, vibfac, wavenumbers
      77              :    USE replica_methods,                 ONLY: rep_env_calc_e_f,&
      78              :                                               rep_env_create
      79              :    USE replica_types,                   ONLY: rep_env_release,&
      80              :                                               replica_env_type
      81              :    USE scine_utils,                     ONLY: write_scine
      82              :    USE util,                            ONLY: sort
      83              : #include "../base/base_uses.f90"
      84              : 
      85              :    IMPLICIT NONE
      86              :    PRIVATE
      87              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'vibrational_analysis'
      88              :    LOGICAL, PARAMETER                   :: debug_this_module = .FALSE.
      89              : 
      90              :    PUBLIC :: vb_anal
      91              : 
      92              : CONTAINS
      93              : 
      94              : ! **************************************************************************************************
      95              : !> \brief Module performing a vibrational analysis
      96              : !> \param input ...
      97              : !> \param input_declaration ...
      98              : !> \param para_env ...
      99              : !> \param globenv ...
     100              : !> \author Teodoro Laino 08.2006
     101              : ! **************************************************************************************************
     102           56 :    SUBROUTINE vb_anal(input, input_declaration, para_env, globenv)
     103              :       TYPE(section_vals_type), POINTER                   :: input
     104              :       TYPE(section_type), POINTER                        :: input_declaration
     105              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     106              :       TYPE(global_environment_type), POINTER             :: globenv
     107              : 
     108              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'vb_anal'
     109              :       CHARACTER(LEN=1), DIMENSION(3), PARAMETER          :: lab = ["X", "Y", "Z"]
     110              : 
     111              :       CHARACTER(LEN=default_string_length)               :: description_d, description_p
     112              :       INTEGER :: handle, i, icoord, icoordm, icoordp, ierr, imap, iounit, ip1, ip2, iparticle1, &
     113              :          iparticle2, iseq, iw, j, k, natoms, ncoord, nfrozen, nrep, nres, nRotTrM, nvib, &
     114              :          output_unit, output_unit_eig, prep, print_grrm, print_namd, print_scine, proc_dist_type
     115           56 :       INTEGER, DIMENSION(:), POINTER                     :: Clist, Mlist
     116              :       LOGICAL :: calc_intens, calc_thchdata, do_mode_tracking, intens_ir, intens_raman, &
     117              :          keep_rotations, row_force, something_frozen
     118              :       REAL(KIND=dp)                                      :: a1, a2, a3, conver, dummy, dx, &
     119              :                                                             inertia(3), minimum_energy, norm, &
     120              :                                                             tc_press, tc_temp, tmp
     121           56 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: H_eigval1, H_eigval2, HeigvalDfull, &
     122           56 :                                                             konst, mass, pos0, rmass
     123           56 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Hessian, Hessian_umw, Hint1, Hint2, &
     124           56 :                                                             Hint2Dfull, MatM
     125              :       REAL(KIND=dp), DIMENSION(3)                        :: D_deriv, d_print
     126              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: P_deriv, p_print
     127           56 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: depol_p, depol_u, depp, depu, din, &
     128           56 :                                                             intensities_d, intensities_p, pin
     129           56 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: D, Dfull, dip_deriv, RotTrM
     130           56 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: polar_deriv, tmp_dip
     131           56 :       REAL(KIND=dp), DIMENSION(:, :, :, :), POINTER      :: tmp_polar
     132              :       TYPE(cell_type), POINTER                           :: cell
     133              :       TYPE(cp_logger_type), POINTER                      :: logger
     134              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     135              :       TYPE(f_env_type), POINTER                          :: f_env
     136           56 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     137              :       TYPE(replica_env_type), POINTER                    :: rep_env
     138              :       TYPE(section_vals_type), POINTER                   :: force_env_section, &
     139              :                                                             mode_tracking_section, print_section, &
     140              :                                                             vib_section
     141              : 
     142           56 :       CALL timeset(routineN, handle)
     143           56 :       NULLIFY (D, RotTrM, cell, logger, subsys, f_env, particles, rep_env, intensities_d, intensities_p, &
     144           56 :                vib_section, print_section, depol_p, depol_u)
     145           56 :       logger => cp_get_default_logger()
     146           56 :       vib_section => section_vals_get_subs_vals(input, "VIBRATIONAL_ANALYSIS")
     147           56 :       print_section => section_vals_get_subs_vals(vib_section, "PRINT")
     148              :       output_unit = cp_print_key_unit_nr(logger, &
     149              :                                          print_section, &
     150              :                                          "PROGRAM_RUN_INFO", &
     151           56 :                                          extension=".vibLog")
     152           56 :       iounit = cp_logger_get_default_io_unit(logger)
     153              :       ! for output of cartesian frequencies and eigenvectors of the
     154              :       ! Hessian that can be used for initialisation of MD calculations
     155              :       output_unit_eig = cp_print_key_unit_nr(logger, &
     156              :                                              print_section, &
     157              :                                              "CARTESIAN_EIGS", &
     158              :                                              extension=".eig", &
     159              :                                              file_status="REPLACE", &
     160              :                                              file_action="WRITE", &
     161              :                                              do_backup=.TRUE., &
     162           56 :                                              file_form="UNFORMATTED")
     163              : 
     164           56 :       CALL section_vals_val_get(vib_section, "DX", r_val=dx)
     165           56 :       CALL section_vals_val_get(vib_section, "NPROC_REP", i_val=prep)
     166           56 :       CALL section_vals_val_get(vib_section, "PROC_DIST_TYPE", i_val=proc_dist_type)
     167           56 :       row_force = (proc_dist_type == do_rep_blocked)
     168           56 :       CALL section_vals_val_get(vib_section, "FULLY_PERIODIC", l_val=keep_rotations)
     169           56 :       CALL section_vals_val_get(vib_section, "INTENSITIES", l_val=calc_intens)
     170           56 :       CALL section_vals_val_get(vib_section, "THERMOCHEMISTRY", l_val=calc_thchdata)
     171           56 :       CALL section_vals_val_get(vib_section, "TC_TEMPERATURE", r_val=tc_temp)
     172           56 :       CALL section_vals_val_get(vib_section, "TC_PRESSURE", r_val=tc_press)
     173              : 
     174           56 :       tc_temp = tc_temp*kelvin
     175           56 :       tc_press = tc_press*pascal
     176              : 
     177           56 :       intens_ir = .FALSE.
     178           56 :       intens_raman = .FALSE.
     179              : 
     180           56 :       mode_tracking_section => section_vals_get_subs_vals(vib_section, "MODE_SELECTIVE")
     181           56 :       CALL section_vals_get(mode_tracking_section, explicit=do_mode_tracking)
     182           56 :       nrep = MAX(1, para_env%num_pe/prep)
     183           56 :       prep = para_env%num_pe/nrep
     184           56 :       iw = cp_print_key_unit_nr(logger, print_section, "BANNER", extension=".vibLog")
     185           56 :       CALL vib_header(iw, nrep, prep)
     186           56 :       CALL cp_print_key_finished_output(iw, logger, print_section, "BANNER")
     187              :       ! Just one force_env allowed
     188           56 :       force_env_section => section_vals_get_subs_vals(input, "FORCE_EVAL")
     189              :       ! Create Replica Environments
     190              :       CALL rep_env_create(rep_env, para_env=para_env, input=input, &
     191           56 :                           input_declaration=input_declaration, nrep=nrep, prep=prep, row_force=row_force)
     192           56 :       IF (ASSOCIATED(rep_env)) THEN
     193           56 :          CALL f_env_add_defaults(f_env_id=rep_env%f_env_id, f_env=f_env)
     194           56 :          CALL force_env_get(f_env%force_env, subsys=subsys)
     195           56 :          CALL cp_subsys_get(subsys, cell=cell)
     196           56 :          particles => subsys%particles%els
     197              :          ! Decide which kind of Vibrational Analysis to perform
     198           56 :          IF (do_mode_tracking) THEN
     199              :             CALL ms_vb_anal(input, rep_env, para_env, globenv, particles, &
     200           24 :                             nrep, calc_intens, dx, output_unit, logger, cell)
     201           24 :             CALL f_env_rm_defaults(f_env, ierr)
     202              :          ELSE
     203           32 :             CALL get_moving_atoms(force_env=f_env%force_env, Ilist=Mlist)
     204           32 :             something_frozen = SIZE(particles) /= SIZE(Mlist)
     205           32 :             natoms = SIZE(Mlist)
     206           32 :             ncoord = natoms*3
     207           96 :             ALLOCATE (Clist(ncoord))
     208           96 :             ALLOCATE (mass(natoms))
     209           96 :             ALLOCATE (pos0(ncoord))
     210          128 :             ALLOCATE (Hessian(ncoord, ncoord))
     211           96 :             ALLOCATE (Hessian_umw(ncoord, ncoord))
     212           32 :             IF (calc_intens) THEN
     213           16 :                description_d = '[DIPOLE]'
     214           64 :                ALLOCATE (tmp_dip(ncoord, 3, 2))
     215          936 :                tmp_dip = 0._dp
     216           16 :                description_p = '[POLAR]'
     217           80 :                ALLOCATE (tmp_polar(ncoord, 3, 3, 2))
     218         2808 :                tmp_polar = 0._dp
     219              :             END IF
     220          296 :             Clist = 0
     221          120 :             DO i = 1, natoms
     222           88 :                imap = Mlist(i)
     223           88 :                Clist((i - 1)*3 + 1) = (imap - 1)*3 + 1
     224           88 :                Clist((i - 1)*3 + 2) = (imap - 1)*3 + 2
     225           88 :                Clist((i - 1)*3 + 3) = (imap - 1)*3 + 3
     226           88 :                mass(i) = particles(imap)%atomic_kind%mass
     227           88 :                CPASSERT(mass(i) > 0.0_dp)
     228           88 :                mass(i) = SQRT(mass(i))
     229           88 :                pos0((i - 1)*3 + 1) = particles(imap)%r(1)
     230           88 :                pos0((i - 1)*3 + 2) = particles(imap)%r(2)
     231          120 :                pos0((i - 1)*3 + 3) = particles(imap)%r(3)
     232              :             END DO
     233              :             !
     234              :             ! Determine the principal axes of inertia.
     235              :             ! Generation of coordinates in the rotating and translating frame
     236              :             !
     237           32 :             IF (something_frozen) THEN
     238            4 :                nRotTrM = 0
     239           12 :                ALLOCATE (RotTrM(natoms*3, nRotTrM))
     240              :             ELSE
     241              :                CALL rot_ana(particles, RotTrM, nRotTrM, print_section, &
     242           28 :                             keep_rotations, mass_weighted=.TRUE., natoms=natoms, inertia=inertia)
     243              :             END IF
     244              :             ! Generate the suitable rototranslating basis set
     245           32 :             nvib = 3*natoms - nRotTrM
     246              :             IF (.FALSE.) THEN !option full in build_D_matrix, at the moment not enabled
     247              :                !but dimensions of D must be adjusted in this case
     248              :                ALLOCATE (D(3*natoms, 3*natoms))
     249              :             ELSE
     250          160 :                ALLOCATE (D(3*natoms, nvib))
     251              :             END IF
     252              :             CALL build_D_matrix(RotTrM, nRotTrM, D, full=.FALSE., &
     253           32 :                                 natoms=natoms)
     254              :             !
     255              :             ! Loop on atoms and coordinates
     256              :             !
     257         2672 :             Hessian = HUGE(0.0_dp)
     258         2672 :             Hessian_umw = HUGE(0.0_dp)
     259           32 :             IF (output_unit > 0) WRITE (output_unit, '(/,T2,A)') "VIB| Vibrational Analysis Info"
     260          206 :             DO icoordp = 1, ncoord, nrep
     261          174 :                icoord = icoordp - 1
     262          456 :                DO j = 1, nrep
     263         2820 :                   DO i = 1, ncoord
     264         2538 :                      imap = Clist(i)
     265         2820 :                      rep_env%r(imap, j) = pos0(i)
     266              :                   END DO
     267          456 :                   IF (icoord + j <= ncoord) THEN
     268          264 :                      imap = Clist(icoord + j)
     269          264 :                      rep_env%r(imap, j) = rep_env%r(imap, j) + Dx
     270              :                   END IF
     271              :                END DO
     272          174 :                CALL rep_env_calc_e_f(rep_env, calc_f=.TRUE.)
     273              : 
     274          488 :                DO j = 1, nrep
     275          282 :                   IF (calc_intens) THEN
     276          140 :                      IF (icoord + j <= ncoord) THEN
     277          132 :                         IF (test_for_result(results=rep_env%results(j)%results, &
     278              :                                             description=description_d)) THEN
     279              :                            CALL get_results(results=rep_env%results(j)%results, &
     280              :                                             description=description_d, &
     281          132 :                                             n_rep=nres)
     282              :                            CALL get_results(results=rep_env%results(j)%results, &
     283              :                                             description=description_d, &
     284              :                                             values=tmp_dip(icoord + j, :, 1), &
     285          132 :                                             nval=nres)
     286          132 :                            intens_ir = .TRUE.
     287          528 :                            d_print(:) = tmp_dip(icoord + j, :, 1)
     288              :                         END IF
     289          132 :                         IF (test_for_result(results=rep_env%results(j)%results, &
     290              :                                             description=description_p)) THEN
     291              :                            CALL get_results(results=rep_env%results(j)%results, &
     292              :                                             description=description_p, &
     293           12 :                                             n_rep=nres)
     294              :                            CALL get_results(results=rep_env%results(j)%results, &
     295              :                                             description=description_p, &
     296              :                                             values=tmp_polar(icoord + j, :, :, 1), &
     297           12 :                                             nval=nres)
     298           12 :                            intens_raman = .TRUE.
     299          156 :                            p_print(:, :) = tmp_polar(icoord + j, :, :, 1)
     300              :                         END IF
     301              :                      END IF
     302              :                   END IF
     303          456 :                   IF (icoord + j <= ncoord) THEN
     304         2640 :                      DO i = 1, ncoord
     305         2376 :                         imap = Clist(i)
     306         2640 :                         Hessian(i, icoord + j) = rep_env%f(imap, j)
     307              :                      END DO
     308          264 :                      imap = Clist(icoord + j)
     309              :                      ! Dump Info
     310          264 :                      IF (output_unit > 0) THEN
     311           75 :                         iparticle1 = imap/3
     312           75 :                         IF (MOD(imap, 3) /= 0) iparticle1 = iparticle1 + 1
     313              :                         WRITE (output_unit, '(T2,A,I5,A,I5,3A)') &
     314           75 :                            "VIB| REPLICA Nr.", j, "- Energy and Forces for particle:", &
     315           75 :                            iparticle1, "  coordinate: ", lab(imap - (iparticle1 - 1)*3), &
     316          150 :                            " + D"//TRIM(lab(imap - (iparticle1 - 1)*3))
     317              :                         WRITE (output_unit, '(T2,A,T43,A,T57,F24.12)') &
     318           75 :                            "VIB|", "Total energy:", rep_env%f(rep_env%ndim + 1, j)
     319           75 :                         WRITE (output_unit, '(T2,"VIB|",T10,"ATOM",T33,3(9X,A,7X))') lab(1), lab(2), lab(3)
     320          276 :                         DO i = 1, natoms
     321          201 :                            imap = Mlist(i)
     322              :                            WRITE (output_unit, '(T2,"VIB|",T12,A,T30,3(2X,F15.9))') &
     323          201 :                               particles(imap)%atomic_kind%name, &
     324         1080 :                               rep_env%f((imap - 1)*3 + 1:(imap - 1)*3 + 3, j)
     325              :                         END DO
     326           75 :                         IF (intens_ir) THEN
     327           33 :                            WRITE (output_unit, '(T3,A)') 'Dipole moment [Debye]'
     328              :                            WRITE (output_unit, '(T5,3(A,F14.8,1X),T60,A,T67,F14.8)') &
     329           33 :                               'X=', d_print(1)*debye, 'Y=', d_print(2)*debye, 'Z=', d_print(3)*debye, &
     330          165 :                               'Total=', SQRT(SUM(d_print(1:3)**2))*debye
     331              :                         END IF
     332           75 :                         IF (intens_raman) THEN
     333              :                            WRITE (output_unit, '(T2,A)') &
     334            6 :                               'POLAR| Polarizability tensor [a.u.]'
     335              :                            WRITE (output_unit, '(T2,A,T24,3(1X,F18.12))') &
     336            6 :                               'POLAR| xx,yy,zz', p_print(1, 1), p_print(2, 2), p_print(3, 3)
     337              :                            WRITE (output_unit, '(T2,A,T24,3(1X,F18.12))') &
     338            6 :                               'POLAR| xy,xz,yz', p_print(1, 2), p_print(1, 3), p_print(2, 3)
     339              :                            WRITE (output_unit, '(T2,A,T24,3(1X,F18.12),/)') &
     340            6 :                               'POLAR| yx,zx,zy', p_print(2, 1), p_print(3, 1), p_print(3, 2)
     341              :                         END IF
     342              :                      END IF
     343              :                   END IF
     344              :                END DO
     345              :             END DO
     346          206 :             DO icoordm = 1, ncoord, nrep
     347          174 :                icoord = icoordm - 1
     348          456 :                DO j = 1, nrep
     349         2820 :                   DO i = 1, ncoord
     350         2538 :                      imap = Clist(i)
     351         2820 :                      rep_env%r(imap, j) = pos0(i)
     352              :                   END DO
     353          456 :                   IF (icoord + j <= ncoord) THEN
     354          264 :                      imap = Clist(icoord + j)
     355          264 :                      rep_env%r(imap, j) = rep_env%r(imap, j) - Dx
     356              :                   END IF
     357              :                END DO
     358          174 :                CALL rep_env_calc_e_f(rep_env, calc_f=.TRUE.)
     359              : 
     360          488 :                DO j = 1, nrep
     361          282 :                   IF (calc_intens) THEN
     362          140 :                      IF (icoord + j <= ncoord) THEN
     363          132 :                         k = (icoord + j + 2)/3
     364          132 :                         IF (test_for_result(results=rep_env%results(j)%results, &
     365              :                                             description=description_d)) THEN
     366              :                            CALL get_results(results=rep_env%results(j)%results, &
     367              :                                             description=description_d, &
     368          132 :                                             n_rep=nres)
     369              :                            CALL get_results(results=rep_env%results(j)%results, &
     370              :                                             description=description_d, &
     371              :                                             values=tmp_dip(icoord + j, :, 2), &
     372          132 :                                             nval=nres)
     373              :                            tmp_dip(icoord + j, :, 1) = (tmp_dip(icoord + j, :, 1) - &
     374          528 :                                                         tmp_dip(icoord + j, :, 2))/(2.0_dp*Dx*mass(k))
     375          528 :                            d_print(:) = tmp_dip(icoord + j, :, 1)
     376              :                         END IF
     377          132 :                         IF (test_for_result(results=rep_env%results(j)%results, &
     378              :                                             description=description_p)) THEN
     379              :                            CALL get_results(results=rep_env%results(j)%results, &
     380              :                                             description=description_p, &
     381           12 :                                             n_rep=nres)
     382              :                            CALL get_results(results=rep_env%results(j)%results, &
     383              :                                             description=description_p, &
     384              :                                             values=tmp_polar(icoord + j, :, :, 2), &
     385           12 :                                             nval=nres)
     386              :                            tmp_polar(icoord + j, :, :, 1) = (tmp_polar(icoord + j, :, :, 1) - &
     387          156 :                                                              tmp_polar(icoord + j, :, :, 2))/(2.0_dp*Dx*mass(k))
     388          156 :                            p_print(:, :) = tmp_polar(icoord + j, :, :, 1)
     389              :                         END IF
     390              :                      END IF
     391              :                   END IF
     392          456 :                   IF (icoord + j <= ncoord) THEN
     393          264 :                      imap = Clist(icoord + j)
     394          264 :                      iparticle1 = imap/3
     395          264 :                      IF (MOD(imap, 3) /= 0) iparticle1 = iparticle1 + 1
     396          264 :                      ip1 = (icoord + j)/3
     397          264 :                      IF (MOD(icoord + j, 3) /= 0) ip1 = ip1 + 1
     398              :                      ! Dump Info
     399          264 :                      IF (output_unit > 0) THEN
     400              :                         WRITE (output_unit, '(T2,A,I5,A,I5,3A)') &
     401           75 :                            "VIB| REPLICA Nr.", j, "- Energy and Forces for particle:", &
     402           75 :                            iparticle1, "  coordinate: ", lab(imap - (iparticle1 - 1)*3), &
     403          150 :                            " - D"//TRIM(lab(imap - (iparticle1 - 1)*3))
     404              :                         WRITE (output_unit, '(T2,A,T43,A,T57,F24.12)') &
     405           75 :                            "VIB|", "Total energy:", rep_env%f(rep_env%ndim + 1, j)
     406           75 :                         WRITE (output_unit, '(T2,"VIB|",T10,"ATOM",T33,3(9X,A,7X))') lab(1), lab(2), lab(3)
     407          276 :                         DO i = 1, natoms
     408          201 :                            imap = Mlist(i)
     409              :                            WRITE (output_unit, '(T2,"VIB|",T12,A,T30,3(2X,F15.9))') &
     410          201 :                               particles(imap)%atomic_kind%name, &
     411         1080 :                               rep_env%f((imap - 1)*3 + 1:(imap - 1)*3 + 3, j)
     412              :                         END DO
     413           75 :                         IF (intens_ir) THEN
     414           33 :                            WRITE (output_unit, '(T3,A)') 'Dipole moment [Debye]'
     415              :                            WRITE (output_unit, '(T5,3(A,F14.8,1X),T60,A,T67,F14.8)') &
     416           33 :                               'X=', d_print(1)*debye, 'Y=', d_print(2)*debye, 'Z=', d_print(3)*debye, &
     417          165 :                               'Total=', SQRT(SUM(d_print(1:3)**2))*debye
     418              :                         END IF
     419           75 :                         IF (intens_raman) THEN
     420              :                            WRITE (output_unit, '(T2,A)') &
     421            6 :                               'POLAR| Polarizability tensor [a.u.]'
     422              :                            WRITE (output_unit, '(T2,A,T24,3(1X,F18.12))') &
     423            6 :                               'POLAR| xx,yy,zz', p_print(1, 1), p_print(2, 2), p_print(3, 3)
     424              :                            WRITE (output_unit, '(T2,A,T24,3(1X,F18.12))') &
     425            6 :                               'POLAR| xy,xz,yz', p_print(1, 2), p_print(1, 3), p_print(2, 3)
     426              :                            WRITE (output_unit, '(T2,A,T24,3(1X,F18.12),/)') &
     427            6 :                               'POLAR| yx,zx,zy', p_print(2, 1), p_print(3, 1), p_print(3, 2)
     428              :                         END IF
     429              :                      END IF
     430         2640 :                      DO iseq = 1, ncoord
     431         2376 :                         imap = Clist(iseq)
     432         2376 :                         iparticle2 = imap/3
     433         2376 :                         IF (MOD(imap, 3) /= 0) iparticle2 = iparticle2 + 1
     434         2376 :                         ip2 = iseq/3
     435         2376 :                         IF (MOD(iseq, 3) /= 0) ip2 = ip2 + 1
     436         2376 :                         tmp = Hessian(iseq, icoord + j) - rep_env%f(imap, j)
     437              :                         ! Un-mass-weighted Hessian_umw and mass-weighted Hessian
     438              :                         ! are both stored to make isotope post-processing easier
     439         2376 :                         Hessian_umw(iseq, icoord + j) = -tmp/(2.0_dp*Dx)
     440         2640 :                         Hessian(iseq, icoord + j) = Hessian_umw(iseq, icoord + j)*1E6_dp/(mass(ip1)*mass(ip2))
     441              :                      END DO
     442              :                   END IF
     443              :                END DO
     444              :             END DO
     445              : 
     446              :             ! restore original particle positions for output
     447          120 :             DO i = 1, natoms
     448           88 :                imap = Mlist(i)
     449          384 :                particles(imap)%r(1:3) = pos0((i - 1)*3 + 1:(i - 1)*3 + 3)
     450              :             END DO
     451           88 :             DO j = 1, nrep
     452          550 :                DO i = 1, ncoord
     453          462 :                   imap = Clist(i)
     454          518 :                   rep_env%r(imap, j) = pos0(i)
     455              :                END DO
     456              :             END DO
     457           32 :             CALL rep_env_calc_e_f(rep_env, calc_f=.TRUE.)
     458           32 :             j = 1
     459           32 :             minimum_energy = rep_env%f(rep_env%ndim + 1, j)
     460           32 :             IF (output_unit > 0) THEN
     461              :                WRITE (output_unit, '(T2,A)') &
     462           10 :                   "VIB| ", " Minimum Structure - Energy and Forces:"
     463              :                WRITE (output_unit, '(T2,A,T43,A,T57,F24.12)') &
     464           10 :                   "VIB|", "Total energy:", rep_env%f(rep_env%ndim + 1, j)
     465           10 :                WRITE (output_unit, '(T2,"VIB|",T10,"ATOM",T33,3(9X,A,7X))') lab(1), lab(2), lab(3)
     466           35 :                DO i = 1, natoms
     467           25 :                   imap = Mlist(i)
     468              :                   WRITE (output_unit, '(T2,"VIB|",T12,A,T30,3(2X,F15.9))') &
     469           25 :                      particles(imap)%atomic_kind%name, &
     470          135 :                      rep_env%f((imap - 1)*3 + 1:(imap - 1)*3 + 3, j)
     471              :                END DO
     472              :             END IF
     473              : 
     474              :             ! Dump Info
     475           32 :             IF (output_unit > 0) THEN
     476              :                WRITE (output_unit, '(/,T2,A)') &
     477           10 :                   "VIB| Hessian (before multiplying by 1E6/(sqrt(mass_i)*sqrt(mass_j)))"
     478              :                CALL write_particle_matrix(Hessian_umw, particles, output_unit, el_per_part=3, &
     479           10 :                                           Ilist=Mlist)
     480              :                WRITE (output_unit, '(/,T2,A)') &
     481           10 :                   "VIB| Hessian in cartesian coordinates (mass weighted)"
     482              :                CALL write_particle_matrix(Hessian, particles, output_unit, el_per_part=3, &
     483           10 :                                           Ilist=Mlist)
     484              :             END IF
     485              : 
     486           32 :             CALL write_va_hessian(vib_section, para_env, ncoord, globenv, Hessian, logger)
     487              : 
     488              :             ! Enforce symmetry in the Hessian
     489          296 :             DO i = 1, ncoord
     490         1616 :                DO j = i, ncoord
     491              :                   ! Take the upper diagonal part
     492         1584 :                   Hessian(j, i) = Hessian(i, j)
     493              :                END DO
     494              :             END DO
     495              :             !
     496              :             ! Print GRMM interface file
     497              :             print_grrm = cp_print_key_unit_nr(logger, force_env_section, "PRINT%GRRM", &
     498           32 :                                               file_position="REWIND", extension=".rrm")
     499           32 :             IF (print_grrm > 0) THEN
     500            7 :                DO i = 1, natoms
     501            5 :                   imap = Mlist(i)
     502           37 :                   particles(imap)%f(1:3) = rep_env%f((imap - 1)*3 + 1:(imap - 1)*3 + 3, 1)
     503              :                END DO
     504            8 :                ALLOCATE (Hint1(ncoord, ncoord), rmass(ncoord))
     505            7 :                DO i = 1, natoms
     506            5 :                   imap = Mlist(i)
     507           22 :                   rmass(3*(imap - 1) + 1:3*(imap - 1) + 3) = mass(imap)
     508              :                END DO
     509           17 :                DO i = 1, ncoord
     510          134 :                   DO j = 1, ncoord
     511          132 :                      Hint1(j, i) = Hessian(j, i)*rmass(i)*rmass(j)*1.0E-6_dp
     512              :                   END DO
     513              :                END DO
     514            2 :                nfrozen = SIZE(particles) - natoms
     515              :                CALL write_grrm(print_grrm, f_env%force_env, particles, minimum_energy, &
     516            2 :                                hessian=Hint1, fixed_atoms=nfrozen)
     517            2 :                DEALLOCATE (Hint1, rmass)
     518              :             END IF
     519           32 :             CALL cp_print_key_finished_output(print_grrm, logger, force_env_section, "PRINT%GRRM")
     520              :             !
     521              :             ! Print SCINE interface file
     522              :             print_scine = cp_print_key_unit_nr(logger, force_env_section, "PRINT%SCINE", &
     523           32 :                                                file_position="REWIND", extension=".scine")
     524           32 :             IF (print_scine > 0) THEN
     525            4 :                DO i = 1, natoms
     526            3 :                   imap = Mlist(i)
     527           22 :                   particles(imap)%f(1:3) = rep_env%f((imap - 1)*3 + 1:(imap - 1)*3 + 3, 1)
     528              :                END DO
     529            1 :                nfrozen = SIZE(particles) - natoms
     530            1 :                CPASSERT(nfrozen == 0)
     531            1 :                CALL write_scine(print_scine, f_env%force_env, particles, minimum_energy, hessian=Hessian)
     532              :             END IF
     533           32 :             CALL cp_print_key_finished_output(print_scine, logger, force_env_section, "PRINT%SCINE")
     534              :             !
     535              :             ! Print NEWTONX interface file
     536              :             print_namd = cp_print_key_unit_nr(logger, print_section, "NAMD_PRINT", &
     537              :                                               extension=".eig", file_status="REPLACE", &
     538              :                                               file_action="WRITE", do_backup=.TRUE., &
     539           32 :                                               file_form="UNFORMATTED")
     540           32 :             IF (print_namd > 0) THEN
     541              :                ! NewtonX requires normalized Cartesian frequencies and eigenvectors
     542              :                ! in full matrix format (ncoord x ncoord)
     543              :                NULLIFY (Dfull)
     544            3 :                ALLOCATE (Dfull(ncoord, ncoord))
     545            3 :                ALLOCATE (Hint2Dfull(SIZE(Dfull, 2), SIZE(Dfull, 2)))
     546            3 :                ALLOCATE (HeigvalDfull(SIZE(Dfull, 2)))
     547            3 :                ALLOCATE (MatM(ncoord, ncoord))
     548            2 :                ALLOCATE (rmass(SIZE(Dfull, 2)))
     549           91 :                Dfull = 0.0_dp
     550              :                ! Dfull in dimension of degrees of freedom
     551            1 :                CALL build_D_matrix(RotTrM, nRotTrM, Dfull, full=.TRUE., natoms=natoms)
     552              :                ! TEST MatM = MATMUL(TRANSPOSE(Dfull),Dfull)= 1
     553              :                ! Hessian in MWC -> Hessian in INT (Hint2Dfull)
     554         3100 :                Hint2Dfull(:, :) = MATMUL(TRANSPOSE(Dfull), MATMUL(Hessian, Dfull))
     555              :                ! Heig = L^T Hint2Dfull L
     556            1 :                CALL diamat_all(Hint2Dfull, HeigvalDfull)
     557              :                ! TEST  MatM = MATMUL(TRANSPOSE(Hint2Dfull),Hint2Dfull) = 1
     558              :                ! TEST MatM=MATMUL(TRANSPOSE(MATMUL(Dfull,Hint2Dfull)),MATMUL(Dfull,Hint2Dfull)) = 1
     559            1 :                MatM = 0.0_dp
     560            4 :                DO i = 1, natoms
     561           13 :                   DO j = 1, 3
     562           12 :                      MatM((i - 1)*3 + j, (i - 1)*3 + j) = 1.0_dp/mass(i) ! mass is sqrt(mass)
     563              :                   END DO
     564              :                END DO
     565              :                ! Dfull = Cartesian displacements of the normal modes
     566         3190 :                Dfull = MATMUL(MatM, MATMUL(Dfull, Hint2Dfull))  !Dfull=D L / sqrt(m)
     567           10 :                DO i = 1, ncoord
     568              :                   ! Renormalize displacements
     569           90 :                   norm = 1.0_dp/SUM(Dfull(:, i)*Dfull(:, i))
     570            9 :                   rmass(i) = norm/massunit
     571           91 :                   Dfull(:, i) = SQRT(norm)*(Dfull(:, i))
     572              :                END DO
     573            1 :                CALL write_eigs_unformatted(print_namd, ncoord, HeigvalDfull, Dfull)
     574            1 :                DEALLOCATE (HeigvalDfull)
     575            1 :                DEALLOCATE (Hint2Dfull)
     576            1 :                DEALLOCATE (Dfull)
     577            1 :                DEALLOCATE (MatM)
     578            1 :                DEALLOCATE (rmass)
     579              :             END IF !print_namd
     580              :             !
     581              :             nvib = ncoord - nRotTrM
     582           64 :             ALLOCATE (H_eigval1(ncoord))
     583           96 :             ALLOCATE (H_eigval2(SIZE(D, 2)))
     584           96 :             ALLOCATE (Hint1(ncoord, ncoord))
     585          128 :             ALLOCATE (Hint2(SIZE(D, 2), SIZE(D, 2)))
     586           64 :             ALLOCATE (rmass(SIZE(D, 2)))
     587           64 :             ALLOCATE (konst(SIZE(D, 2)))
     588           32 :             IF (calc_intens) THEN
     589           48 :                ALLOCATE (dip_deriv(3, SIZE(D, 2)))
     590          216 :                dip_deriv = 0.0_dp
     591           48 :                ALLOCATE (polar_deriv(3, 3, SIZE(D, 2)))
     592          666 :                polar_deriv = 0.0_dp
     593              :             END IF
     594           64 :             ALLOCATE (intensities_d(SIZE(D, 2)))
     595           64 :             ALLOCATE (intensities_p(SIZE(D, 2)))
     596           64 :             ALLOCATE (depol_p(SIZE(D, 2)))
     597           64 :             ALLOCATE (depol_u(SIZE(D, 2)))
     598          140 :             intensities_d = 0._dp
     599          140 :             intensities_p = 0._dp
     600          140 :             depol_p = 0._dp
     601          140 :             depol_u = 0._dp
     602         2672 :             Hint1(:, :) = Hessian
     603           32 :             CALL diamat_all(Hint1, H_eigval1)
     604           32 :             IF (output_unit > 0) THEN
     605           10 :                WRITE (output_unit, '(/,T2,A)') "VIB| Cartesian Low frequencies ---"
     606           29 :                DO i = 1, ncoord, 5
     607              :                   WRITE (output_unit, '(T2,A,T6,5(1X,ES14.7E2))') &
     608           29 :                      "VIB|", H_eigval1(i:MIN(i + 4, ncoord))
     609              :                END DO
     610           10 :                WRITE (output_unit, '(/,T2,A)') "VIB| Eigenvectors before removal of rotations and translations"
     611              :                CALL write_particle_matrix(Hint1, particles, output_unit, el_per_part=3, &
     612           10 :                                           Ilist=Mlist)
     613              :             END IF
     614              :             ! write frequencies and eigenvectors to cartesian eig file
     615           32 :             IF (output_unit_eig > 0) THEN
     616           16 :                CALL write_eigs_unformatted(output_unit_eig, ncoord, H_eigval1, Hint1)
     617              :             END IF
     618           32 :             IF (nvib /= 0) THEN
     619        42254 :                Hint2(:, :) = MATMUL(TRANSPOSE(D), MATMUL(Hessian, D))
     620           32 :                IF (calc_intens) THEN
     621           64 :                   DO i = 1, 3
     622         4678 :                      dip_deriv(i, :) = MATMUL(tmp_dip(:, i, 1), D)
     623              :                   END DO
     624           64 :                   DO i = 1, 3
     625          208 :                      DO j = 1, 3
     626        14034 :                         polar_deriv(i, j, :) = MATMUL(tmp_polar(:, i, j, 1), D)
     627              :                      END DO
     628              :                   END DO
     629              :                END IF
     630           32 :                CALL diamat_all(Hint2, H_eigval2)
     631           32 :                IF (output_unit > 0) THEN
     632           10 :                   WRITE (output_unit, '(/,T2,"VIB| Frequencies after removal of the rotations and translations")')
     633              :                   ! Frequency at the moment are in a.u
     634           10 :                   WRITE (output_unit, '(/,T2,A)') "VIB| Internal  Low frequencies ---"
     635           21 :                   DO i = 1, SIZE(D, 2), 5
     636              :                      WRITE (output_unit, '(T2,A,T6,5(1X,ES14.7E2))') &
     637           21 :                         "VIB|", H_eigval2(i:MIN(i + 4, SIZE(D, 2)))
     638              :                   END DO
     639              :                END IF
     640           32 :                Hessian = 0.0_dp
     641          120 :                DO i = 1, natoms
     642          384 :                   DO j = 1, 3
     643          352 :                      Hessian((i - 1)*3 + j, (i - 1)*3 + j) = 1.0_dp/mass(i)
     644              :                   END DO
     645              :                END DO
     646              :                ! Cartesian displacements of the normal modes
     647        83744 :                D = MATMUL(Hessian, MATMUL(D, Hint2))
     648          140 :                DO i = 1, nvib
     649         1098 :                   norm = 1.0_dp/SUM(D(:, i)*D(:, i))
     650              :                   ! Reduced Masess
     651          108 :                   rmass(i) = norm/massunit
     652              :                   ! Renormalize displacements and convert in Angstrom
     653         1098 :                   D(:, i) = SQRT(norm)*D(:, i)
     654          108 :                   IF (calc_intens) THEN
     655           50 :                      D_deriv = 0._dp
     656          232 :                      DO j = 1, nvib
     657          778 :                         D_deriv(:) = D_deriv(:) + dip_deriv(:, j)*Hint2(j, i)
     658              :                      END DO
     659          200 :                      intensities_d(i) = NORM2(D_deriv)
     660           50 :                      P_deriv = 0._dp
     661          232 :                      DO j = 1, nvib
     662              :                         ! P_deriv has units bohr^2/sqrt(a.u.)
     663         2416 :                         P_deriv(:, :) = P_deriv(:, :) + polar_deriv(:, :, j)*Hint2(j, i)
     664              :                      END DO
     665              :                      ! P_deriv now has units A^2/sqrt(amu)
     666              :                      conver = angstrom**2*SQRT(massunit)
     667          650 :                      P_deriv(:, :) = P_deriv(:, :)*conver
     668              :                      ! this is wron, just for testing
     669           50 :                      a1 = (P_deriv(1, 1) + P_deriv(2, 2) + P_deriv(3, 3))/3.0_dp
     670              :                      a2 = (P_deriv(1, 1) - P_deriv(2, 2))**2 + &
     671              :                           (P_deriv(2, 2) - P_deriv(3, 3))**2 + &
     672           50 :                           (P_deriv(3, 3) - P_deriv(1, 1))**2
     673           50 :                      a3 = (P_deriv(1, 2)**2 + P_deriv(2, 3)**2 + P_deriv(3, 1)**2)
     674           50 :                      intensities_p(i) = 45.0_dp*a1*a1 + 7.0_dp/2.0_dp*(a2 + 6.0_dp*a3)
     675              :                      ! to avoid division by zero:
     676           50 :                      dummy = 45.0_dp*a1*a1 + 4.0_dp/2.0_dp*(a2 + 6.0_dp*a3)
     677           50 :                      IF (dummy > 5.E-7_dp) THEN
     678              :                         ! depolarization of plane polarized incident light
     679              :                         depol_p(i) = 3.0_dp/2.0_dp*(a2 + 6.0_dp*a3)/(45.0_dp*a1*a1 + &
     680            2 :                                                                      4.0_dp/2.0_dp*(a2 + 6.0_dp*a3))
     681              :                         ! depolarization of unpolarized (natural) incident light
     682              :                         depol_u(i) = 6.0_dp/2.0_dp*(a2 + 6.0_dp*a3)/(45.0_dp*a1*a1 + &
     683            2 :                                                                      7.0_dp/2.0_dp*(a2 + 6.0_dp*a3))
     684              :                      ELSE
     685           48 :                         depol_p(i) = -1.0_dp
     686           48 :                         depol_u(i) = -1.0_dp
     687              :                      END IF
     688              :                   END IF
     689              :                   ! Convert frequencies to cm^-1
     690          108 :                   H_eigval2(i) = SIGN(1.0_dp, H_eigval2(i))*SQRT(ABS(H_eigval2(i))*massunit)*vibfac/1000.0_dp
     691              :                   ! Force constant in au, conversion to mdyne/A is 15.57
     692          140 :                   konst(i) = SIGN(1.0_dp, H_eigval2(i))*rmass(i)*massunit*(2.0_dp*pi*c_light*100*ABS(H_eigval2(i))*h_bar/joule)**2
     693              :                END DO
     694           32 :                IF (calc_intens) THEN
     695           16 :                   IF (iounit > 0) THEN
     696            8 :                      IF (.NOT. intens_ir) THEN
     697            0 :                         WRITE (iounit, '(T2,"VIB| No IR intensities available. Check input")')
     698              :                      END IF
     699            8 :                      IF (.NOT. intens_raman) THEN
     700            7 :                         WRITE (iounit, '(T2,"VIB| No Raman intensities available. Check input")')
     701              :                      END IF
     702              :                   END IF
     703              :                END IF
     704              :                ! Dump Info
     705           32 :                iw = cp_logger_get_default_io_unit(logger)
     706           32 :                IF (iw > 0) THEN
     707           16 :                   NULLIFY (din, pin, depp, depu)
     708           16 :                   IF (intens_ir) din => intensities_d
     709           16 :                   IF (intens_raman) pin => intensities_p
     710            1 :                   IF (intens_raman) depp => depol_p
     711           16 :                   IF (intens_raman) depu => depol_u
     712           16 :                   CALL vib_out(iw, nvib, D, konst, rmass, H_eigval2, particles, Mlist, din, pin, depp, depu)
     713              :                END IF
     714           32 :                IF (.NOT. something_frozen .AND. calc_thchdata) THEN
     715            2 :                   CALL get_thch_values(H_eigval2, iw, mass, nvib, inertia, 1, minimum_energy, tc_temp, tc_press)
     716              :                END IF
     717              :                CALL write_vibrations_molden(input, particles, H_eigval2, D, intensities_d, calc_intens, &
     718           32 :                                             dump_only_positive=.FALSE., logger=logger, list=Mlist, cell=cell)
     719              :             ELSE
     720            0 :                IF (output_unit > 0) THEN
     721            0 :                   WRITE (output_unit, '(T2,"VIB| No further vibrational info. Detected a single atom")')
     722              :                END IF
     723              :             END IF
     724              :             ! Deallocate working arrays
     725           32 :             DEALLOCATE (RotTrM)
     726           32 :             DEALLOCATE (Clist)
     727           32 :             DEALLOCATE (Mlist)
     728           32 :             DEALLOCATE (H_eigval1)
     729           32 :             DEALLOCATE (H_eigval2)
     730           32 :             DEALLOCATE (Hint1)
     731           32 :             DEALLOCATE (Hint2)
     732           32 :             DEALLOCATE (rmass)
     733           32 :             DEALLOCATE (konst)
     734           32 :             DEALLOCATE (mass)
     735           32 :             DEALLOCATE (pos0)
     736           32 :             DEALLOCATE (D)
     737           32 :             DEALLOCATE (Hessian)
     738           32 :             DEALLOCATE (Hessian_umw)
     739           32 :             IF (calc_intens) THEN
     740           16 :                DEALLOCATE (dip_deriv)
     741           16 :                DEALLOCATE (polar_deriv)
     742           16 :                DEALLOCATE (tmp_dip)
     743           16 :                DEALLOCATE (tmp_polar)
     744              :             END IF
     745           32 :             DEALLOCATE (intensities_d)
     746           32 :             DEALLOCATE (intensities_p)
     747           32 :             DEALLOCATE (depol_p)
     748           32 :             DEALLOCATE (depol_u)
     749           32 :             CALL f_env_rm_defaults(f_env, ierr)
     750              :          END IF
     751              :       END IF
     752           56 :       CALL cp_print_key_finished_output(output_unit, logger, print_section, "PROGRAM_RUN_INFO")
     753           56 :       CALL cp_print_key_finished_output(output_unit_eig, logger, print_section, "CARTESIAN_EIGS")
     754           56 :       CALL rep_env_release(rep_env)
     755           56 :       CALL timestop(handle)
     756          112 :    END SUBROUTINE vb_anal
     757              : 
     758              : ! **************************************************************************************************
     759              : !> \brief give back a list of moving atoms
     760              : !> \param force_env ...
     761              : !> \param Ilist ...
     762              : !> \author Teodoro Laino 08.2006
     763              : ! **************************************************************************************************
     764           32 :    SUBROUTINE get_moving_atoms(force_env, Ilist)
     765              :       TYPE(force_env_type), POINTER                      :: force_env
     766              :       INTEGER, DIMENSION(:), POINTER                     :: Ilist
     767              : 
     768              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'get_moving_atoms'
     769              : 
     770              :       INTEGER                                            :: handle, i, ii, ikind, j, ndim, &
     771              :                                                             nfixed_atoms, nfixed_atoms_total, nkind
     772           32 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ifixd_list, work
     773              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     774           32 :       TYPE(fixd_constraint_type), DIMENSION(:), POINTER  :: fixd_list
     775              :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
     776           32 :       TYPE(molecule_kind_type), DIMENSION(:), POINTER    :: molecule_kind_set
     777              :       TYPE(molecule_kind_type), POINTER                  :: molecule_kind
     778              :       TYPE(particle_list_type), POINTER                  :: particles
     779           32 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     780              : 
     781           32 :       CALL timeset(routineN, handle)
     782           32 :       CALL force_env_get(force_env=force_env, subsys=subsys)
     783              : 
     784              :       CALL cp_subsys_get(subsys=subsys, particles=particles, &
     785           32 :                          molecule_kinds=molecule_kinds)
     786              : 
     787           32 :       nkind = molecule_kinds%n_els
     788           32 :       molecule_kind_set => molecule_kinds%els
     789           32 :       particle_set => particles%els
     790              : 
     791              :       ! Count the number of fixed atoms
     792           32 :       nfixed_atoms_total = 0
     793          114 :       DO ikind = 1, nkind
     794           82 :          molecule_kind => molecule_kind_set(ikind)
     795           82 :          CALL get_molecule_kind(molecule_kind, nfixd=nfixed_atoms)
     796          114 :          nfixed_atoms_total = nfixed_atoms_total + nfixed_atoms
     797              :       END DO
     798           32 :       ndim = SIZE(particle_set) - nfixed_atoms_total
     799           32 :       CPASSERT(ndim >= 0)
     800           96 :       ALLOCATE (Ilist(ndim))
     801              : 
     802           32 :       IF (nfixed_atoms_total /= 0) THEN
     803           12 :          ALLOCATE (ifixd_list(nfixed_atoms_total))
     804            8 :          ALLOCATE (work(nfixed_atoms_total))
     805            4 :          nfixed_atoms_total = 0
     806           12 :          DO ikind = 1, nkind
     807            8 :             molecule_kind => molecule_kind_set(ikind)
     808            8 :             CALL get_molecule_kind(molecule_kind, fixd_list=fixd_list)
     809           12 :             IF (ASSOCIATED(fixd_list)) THEN
     810           14 :                DO ii = 1, SIZE(fixd_list)
     811           14 :                   IF (.NOT. fixd_list(ii)%restraint%active) THEN
     812            6 :                      nfixed_atoms_total = nfixed_atoms_total + 1
     813            6 :                      ifixd_list(nfixed_atoms_total) = fixd_list(ii)%fixd
     814              :                   END IF
     815              :                END DO
     816              :             END IF
     817              :          END DO
     818            4 :          CALL sort(ifixd_list, nfixed_atoms_total, work)
     819              : 
     820            4 :          ndim = 0
     821            4 :          j = 1
     822           14 :          Loop_count: DO i = 1, SIZE(particle_set)
     823           14 :             DO WHILE (i > ifixd_list(j))
     824            4 :                j = j + 1
     825           14 :                IF (j > nfixed_atoms_total) EXIT Loop_count
     826              :             END DO
     827           14 :             IF (i /= ifixd_list(j)) THEN
     828            4 :                ndim = ndim + 1
     829            4 :                Ilist(ndim) = i
     830              :             END IF
     831              :          END DO Loop_count
     832            4 :          DEALLOCATE (ifixd_list)
     833            4 :          DEALLOCATE (work)
     834              :       ELSE
     835              :          i = 1
     836              :          ndim = 0
     837              :       END IF
     838          116 :       DO j = i, SIZE(particle_set)
     839           84 :          ndim = ndim + 1
     840          116 :          Ilist(ndim) = j
     841              :       END DO
     842           32 :       CALL timestop(handle)
     843              : 
     844           32 :    END SUBROUTINE get_moving_atoms
     845              : 
     846              : ! **************************************************************************************************
     847              : !> \brief Dumps results of the vibrational analysis
     848              : !> \param iw ...
     849              : !> \param nvib ...
     850              : !> \param D ...
     851              : !> \param k ...
     852              : !> \param m ...
     853              : !> \param freq ...
     854              : !> \param particles ...
     855              : !> \param Mlist ...
     856              : !> \param intensities_d ...
     857              : !> \param intensities_p ...
     858              : !> \param depol_p ...
     859              : !> \param depol_u ...
     860              : !> \author Teodoro Laino 08.2006
     861              : ! **************************************************************************************************
     862           16 :    SUBROUTINE vib_out(iw, nvib, D, k, m, freq, particles, Mlist, intensities_d, intensities_p, &
     863              :                       depol_p, depol_u)
     864              :       INTEGER, INTENT(IN)                                :: iw, nvib
     865              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: D
     866              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: k, m, freq
     867              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     868              :       INTEGER, DIMENSION(:), POINTER                     :: Mlist
     869              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: intensities_d, intensities_p, depol_p, &
     870              :                                                             depol_u
     871              : 
     872              :       CHARACTER(LEN=2)                                   :: element_symbol
     873              :       INTEGER                                            :: from, iatom, icol, j, jatom, katom, &
     874              :                                                             natom, to
     875              :       REAL(KIND=dp)                                      :: fint, pint
     876              : 
     877           16 :       fint = 42.255_dp*massunit*debye**2*bohr**2
     878           16 :       pint = 1.0_dp
     879           16 :       natom = SIZE(D, 1)
     880           16 :       WRITE (UNIT=iw, FMT="(/,T2,'VIB|',T30,'NORMAL MODES - CARTESIAN DISPLACEMENTS')")
     881           16 :       WRITE (UNIT=iw, FMT="(T2,'VIB|')")
     882           36 :       DO jatom = 1, nvib, 3
     883           20 :          from = jatom
     884           20 :          to = MIN(from + 2, nvib)
     885              :          WRITE (UNIT=iw, FMT="(T2,'VIB|',13X,3(8X,I5,8X))") &
     886           74 :             (icol, icol=from, to)
     887              :          WRITE (UNIT=iw, FMT="(T2,'VIB|Frequency (cm^-1)',3(1X,ES17.10E2,2X))") &
     888           20 :             (freq(icol), icol=from, to)
     889           20 :          IF (ASSOCIATED(intensities_d)) THEN
     890              :             WRITE (UNIT=iw, FMT="(T2,'VIB|IR int (KM/Mole) ',3(1X,ES17.10E2,2X))") &
     891           34 :                (fint*intensities_d(icol)**2, icol=from, to)
     892              :          END IF
     893           20 :          IF (ASSOCIATED(intensities_p)) THEN
     894              :             WRITE (UNIT=iw, FMT="(T2,'VIB|Raman (A^4/amu)  ',3(1X,ES17.10E2,2X))") &
     895            2 :                (pint*intensities_p(icol), icol=from, to)
     896              :             WRITE (UNIT=iw, FMT="(T2,'VIB|Depol Ratio (P)  ',3(1X,ES17.10E2,2X))") &
     897            2 :                (depol_p(icol), icol=from, to)
     898              :             WRITE (UNIT=iw, FMT="(T2,'VIB|Depol Ratio (U)  ',3(1X,ES17.10E2,2X))") &
     899            2 :                (depol_u(icol), icol=from, to)
     900              :          END IF
     901              :          WRITE (UNIT=iw, FMT="(T2,'VIB|Red.Masses (a.u.)',3(1X,ES17.10E2,2X))") &
     902           20 :             (m(icol), icol=from, to)
     903              :          WRITE (UNIT=iw, FMT="(T2,'VIB|Frc consts (a.u.)',3(1X,ES17.10E2,2X))") &
     904           20 :             (k(icol), icol=from, to)
     905           20 :          WRITE (UNIT=iw, FMT="(T2,' ATOM',2X,'EL',10X,3(3X,'  X  ',1X,'  Y  ',1X,'  Z  '))")
     906           79 :          DO iatom = 1, natom, 3
     907           59 :             katom = iatom/3
     908           59 :             IF (MOD(iatom, 3) /= 0) katom = katom + 1
     909              :             CALL get_atomic_kind(atomic_kind=particles(Mlist(katom))%atomic_kind, &
     910           59 :                                  element_symbol=element_symbol)
     911              :             WRITE (UNIT=iw, FMT="(T2,I5,2X,A2,10X,3(3X,2(F5.2,1X),F5.2))") &
     912           59 :                Mlist(katom), element_symbol, &
     913          798 :                ((D(iatom + j, icol), j=0, 2), icol=from, to)
     914              :          END DO
     915           36 :          WRITE (UNIT=iw, FMT="(/)")
     916              :       END DO
     917              : 
     918           16 :    END SUBROUTINE vib_out
     919              : 
     920              : ! **************************************************************************************************
     921              : !> \brief Generates the transformation matrix from hessian in cartesian into
     922              : !>      internal coordinates (based on Gram-Schmidt orthogonalization)
     923              : !> \param mat ...
     924              : !> \param dof ...
     925              : !> \param Dout ...
     926              : !> \param full ...
     927              : !> \param natoms ...
     928              : !> \author Teodoro Laino 08.2006
     929              : ! **************************************************************************************************
     930           33 :    SUBROUTINE build_D_matrix(mat, dof, Dout, full, natoms)
     931              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: mat
     932              :       INTEGER, INTENT(IN)                                :: dof
     933              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: Dout
     934              :       LOGICAL, OPTIONAL                                  :: full
     935              :       INTEGER, INTENT(IN)                                :: natoms
     936              : 
     937              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'build_D_matrix'
     938              : 
     939              :       INTEGER                                            :: handle, i, ifound, iseq, j, nvib
     940              :       LOGICAL                                            :: my_full
     941              :       REAL(KIND=dp)                                      :: norm
     942           33 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: work
     943           33 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: D
     944              : 
     945           33 :       CALL timeset(routineN, handle)
     946           33 :       my_full = .TRUE.
     947           33 :       IF (PRESENT(full)) my_full = full
     948              :       ! Generate the missing vectors of the orthogonal basis set
     949           33 :       nvib = 3*natoms - dof
     950          132 :       ALLOCATE (work(3*natoms))
     951          132 :       ALLOCATE (D(3*natoms, 3*natoms))
     952              :       ! Check First orthogonality in the first element of the basis set
     953          195 :       DO i = 1, dof
     954         1602 :          D(:, i) = mat(:, i)
     955          576 :          DO j = i + 1, dof
     956         3810 :             norm = DOT_PRODUCT(mat(:, i), mat(:, j))
     957          543 :             IF (ABS(norm) > thrs_motion) THEN
     958            0 :                CPWARN("Orthogonality error in transformation matrix")
     959              :             END IF
     960              :          END DO
     961              :       END DO
     962              :       ! Generate the nvib orthogonal vectors
     963              :       iseq = 0
     964              :       ifound = 0
     965          180 :       DO WHILE (ifound /= nvib)
     966          147 :          iseq = iseq + 1
     967          147 :          CPASSERT(iseq <= 3*natoms)
     968          147 :          work = 0.0_dp
     969          147 :          work(iseq) = 1.0_dp
     970              :          ! Gram Schmidt orthogonalization
     971         1124 :          DO i = 1, dof + ifound
     972        10742 :             norm = DOT_PRODUCT(work, D(:, i))
     973        10889 :             work(:) = work - norm*D(:, i)
     974              :          END DO
     975              :          ! Check norm of the new generated vector
     976         1488 :          norm = NORM2(work)
     977          180 :          IF (norm >= 10E4_dp*thrs_motion) THEN
     978              :             ! Accept new vector
     979          111 :             ifound = ifound + 1
     980         1128 :             D(:, dof + ifound) = work/norm
     981              :          END IF
     982              :       END DO
     983           33 :       CPASSERT(dof + ifound == 3*natoms)
     984           33 :       IF (my_full) THEN
     985           91 :          Dout = D
     986              :       ELSE
     987         1130 :          Dout = D(:, dof + 1:)
     988              :       END IF
     989           33 :       DEALLOCATE (work)
     990           33 :       DEALLOCATE (D)
     991           33 :       CALL timestop(handle)
     992           33 :    END SUBROUTINE build_D_matrix
     993              : 
     994              : ! **************************************************************************************************
     995              : !> \brief Calculate a few thermochemical  properties from vibrational analysis
     996              : !>         It is supposed to work for molecules in the gas phase and without constraints
     997              : !> \param freqs ...
     998              : !> \param iw ...
     999              : !> \param mass ...
    1000              : !> \param nvib ...
    1001              : !> \param inertia ...
    1002              : !> \param spin ...
    1003              : !> \param totene ...
    1004              : !> \param temp ...
    1005              : !> \param pressure ...
    1006              : !> \author MI 10:2015
    1007              : ! **************************************************************************************************
    1008              : 
    1009            2 :    SUBROUTINE get_thch_values(freqs, iw, mass, nvib, inertia, spin, totene, temp, pressure)
    1010              : 
    1011              :       REAL(KIND=dp), DIMENSION(:)                        :: freqs
    1012              :       INTEGER, INTENT(IN)                                :: iw
    1013              :       REAL(KIND=dp), DIMENSION(:)                        :: mass
    1014              :       INTEGER, INTENT(IN)                                :: nvib
    1015              :       REAL(KIND=dp), INTENT(IN)                          :: inertia(3)
    1016              :       INTEGER, INTENT(IN)                                :: spin
    1017              :       REAL(KIND=dp), INTENT(IN)                          :: totene, temp, pressure
    1018              : 
    1019              :       INTEGER                                            :: i, natoms, sym_num
    1020              :       REAL(KIND=dp) :: el_entropy, entropy, exp_min_one, fact, fact2, freq_arg, freq_arg2, &
    1021              :          freqsum, Gibbs, heat_capacity, inertia_kg(3), mass_tot, one_min_exp, partition_function, &
    1022              :          rot_cv, rot_energy, rot_entropy, rot_part_func, rotvibtra, tran_cv, tran_energy, &
    1023              :          tran_enthalpy, tran_entropy, tran_part_func, vib_cv, vib_energy, vib_entropy, &
    1024              :          vib_part_func, zpe
    1025            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: mass_kg
    1026              : 
    1027              : !    temp = 273.150_dp ! in Kelvin
    1028              : !    pressure = 101325.0_dp ! in Pascal
    1029              : 
    1030            2 :       freqsum = 0.0_dp
    1031            4 :       DO i = 1, nvib
    1032            4 :          freqsum = freqsum + freqs(i)
    1033              :       END DO
    1034              : 
    1035              : !   ZPE
    1036            2 :       zpe = 0.5_dp*(h_bar*2._dp*pi)*freqsum*(hertz/wavenumbers)*n_avogadro
    1037              : 
    1038            2 :       el_entropy = (n_avogadro*boltzmann)*LOG(REAL(spin, KIND=dp))
    1039              : !
    1040            2 :       natoms = SIZE(mass)
    1041            6 :       ALLOCATE (mass_kg(natoms))
    1042            6 :       mass_kg(:) = mass(:)**2*e_mass
    1043            6 :       mass_tot = SUM(mass_kg)
    1044            8 :       inertia_kg = inertia*e_mass*(a_bohr**2)
    1045              : 
    1046              : !   ROTATIONAL: Partition function and Entropy
    1047            2 :       sym_num = 1
    1048            2 :       fact = temp*2.0_dp*boltzmann/(h_bar*h_bar)
    1049            2 :       IF (inertia_kg(1)*inertia_kg(2)*inertia_kg(3) > 1.0_dp) THEN
    1050            0 :          rot_part_func = fact*fact*fact*inertia_kg(1)*inertia_kg(2)*inertia_kg(3)*pi
    1051            0 :          rot_part_func = SQRT(rot_part_func)
    1052            0 :          rot_entropy = n_avogadro*boltzmann*(LOG(rot_part_func) + 1.5_dp)
    1053            0 :          rot_energy = 1.5_dp*n_avogadro*boltzmann*temp
    1054            0 :          rot_cv = 1.5_dp*n_avogadro*boltzmann
    1055              :       ELSE
    1056              :          !linear molecule
    1057            2 :          IF (inertia_kg(1) > 1.0_dp) THEN
    1058            0 :             rot_part_func = fact*inertia_kg(1)
    1059            2 :          ELSE IF (inertia_kg(2) > 1.0_dp) THEN
    1060            0 :             rot_part_func = fact*inertia_kg(2)
    1061              :          ELSE
    1062            2 :             rot_part_func = fact*inertia_kg(3)
    1063              :          END IF
    1064            2 :          rot_entropy = n_avogadro*boltzmann*(LOG(rot_part_func) + 1.0_dp)
    1065            2 :          rot_energy = n_avogadro*boltzmann*temp
    1066            2 :          rot_cv = n_avogadro*boltzmann
    1067              :       END IF
    1068              : 
    1069              : !   TRANSLATIONAL: Partition function and Entropy
    1070            2 :       tran_part_func = (boltzmann*temp)**2.5_dp/(pressure*(h_bar*2.0_dp*pi)**3.0_dp)*(2.0_dp*pi*mass_tot)**1.5_dp
    1071            2 :       tran_entropy = n_avogadro*boltzmann*(LOG(tran_part_func) + 2.5_dp)
    1072            2 :       tran_energy = 1.5_dp*n_avogadro*boltzmann*temp
    1073            2 :       tran_enthalpy = 2.5_dp*n_avogadro*boltzmann*temp
    1074            2 :       tran_cv = 2.5_dp*n_avogadro*boltzmann
    1075              : 
    1076              : !   VIBRATIONAL:  Partition function and Entropy
    1077            2 :       vib_part_func = 1.0_dp
    1078            2 :       vib_energy = 0.0_dp
    1079            2 :       vib_entropy = 0.0_dp
    1080            2 :       vib_cv = 0.0_dp
    1081            2 :       fact = 2.0_dp*pi*h_bar/boltzmann/temp*hertz/wavenumbers
    1082            2 :       fact2 = 2.0_dp*pi*h_bar*hertz/wavenumbers
    1083            4 :       DO i = 1, nvib
    1084            2 :          freq_arg = fact*freqs(i)
    1085            2 :          freq_arg2 = fact2*freqs(i)
    1086            2 :          exp_min_one = EXP(freq_arg) - 1.0_dp
    1087            2 :          one_min_exp = 1.0_dp - EXP(-freq_arg)
    1088              : !dbg
    1089              : !  write(*,*) 'freq ', i, freqs(i), exp_min_one , one_min_exp
    1090              : !  note: this is based on the rigid-rotor harmonic oscillator (RRHO) model, which
    1091              : !  behaves badly with very low frequencies that make exp_min_one and one_min_exp
    1092              : !  numerically close to 0 and cause divergence of the vib_entropy term; perhaps
    1093              : !  implementing the quasi-RRHO methods (Grimme/Minenkov) can address this problem.
    1094              : !      vib_part_func = vib_part_func*(1.0_dp/(1.0_dp - exp(-fact*freqs(i))))
    1095            2 :          vib_part_func = vib_part_func*(1.0_dp/one_min_exp)
    1096              : !      vib_energy = vib_energy + fact2*freqs(i)*0.5_dp+fact2*freqs(i)/(exp(fact*freqs(i))-1.0_dp)
    1097            2 :          vib_energy = vib_energy + freq_arg2*0.5_dp + freq_arg2/exp_min_one
    1098              : !      vib_entropy = vib_entropy +fact*freqs(i)/(exp(fact*freqs(i))-1.0_dp)-log(1.0_dp - exp(-fact*freqs(i)))
    1099            2 :          vib_entropy = vib_entropy + freq_arg/exp_min_one - LOG(one_min_exp)
    1100              : !      vib_cv = vib_cv + fact*fact*freqs(i)*freqs(i)*exp(fact*freqs(i))/(exp(fact*freqs(i))-1.0_dp)/(exp(fact*freqs(i))-1.0_dp)
    1101            4 :          vib_cv = vib_cv + freq_arg*freq_arg*EXP(freq_arg)/exp_min_one/exp_min_one
    1102              :       END DO
    1103            2 :       vib_energy = vib_energy*n_avogadro ! it contains already ZPE
    1104            2 :       vib_entropy = vib_entropy*(n_avogadro*boltzmann)
    1105            2 :       vib_cv = vib_cv*(n_avogadro*boltzmann)
    1106              : 
    1107              : !   SUMMARY
    1108              : !dbg
    1109              : !    write(*,*) 'part ', rot_part_func,tran_part_func,vib_part_func
    1110              :       partition_function = rot_part_func*tran_part_func*vib_part_func
    1111              : !dbg
    1112              : !    write(*,*) 'entropy ', el_entropy,rot_entropy,tran_entropy,vib_entropy
    1113              : 
    1114            2 :       entropy = el_entropy + rot_entropy + tran_entropy + vib_entropy
    1115              : !dbg
    1116              : !    write(*,*) 'energy ', rot_energy , tran_enthalpy , vib_energy, totene*kjmol*1000.0_dp
    1117              : 
    1118            2 :       rotvibtra = rot_energy + tran_enthalpy + vib_energy
    1119              : !dbg
    1120              : !    write(*,*) 'cv ', rot_cv, tran_cv, vib_cv
    1121            2 :       heat_capacity = vib_cv + tran_cv + rot_cv
    1122              : 
    1123              : !   Free energy in J/mol: internal energy + PV - TS
    1124            2 :       Gibbs = vib_energy + rot_energy + tran_enthalpy - temp*entropy
    1125              : 
    1126            2 :       DEALLOCATE (mass_kg)
    1127              : 
    1128            2 :       IF (iw > 0) THEN
    1129            1 :          WRITE (UNIT=iw, FMT="(/,T2,'VIB|',T30,'NORMAL MODES - THERMOCHEMICAL DATA')")
    1130            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|',T16,'[q = gamma only, rigid-rotor harmonic oscillator (RRHO) model]')")
    1131              : 
    1132            1 :          WRITE (UNIT=iw, FMT="(/,T2,'VIB|', T10, 'Symmetry number:',T65,I16)") sym_num
    1133            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|', T10, 'Temperature [K]:',T65,F16.2)") temp
    1134            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|', T10, 'Pressure [Pa]:',T65,F16.2)") pressure
    1135              : 
    1136            1 :          WRITE (UNIT=iw, FMT="(/,T2,'VIB|', T10, 'Electronic energy (U) [kJ/mol]:',T55,F26.8)") totene*kjmol
    1137            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|', T10, 'Zero-point correction [kJ/mol]:',T55,F26.8)") zpe/1000.0_dp
    1138            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|', T10, 'Entropy [kJ/(mol K)]:',T55,F26.8)") entropy/1000.0_dp
    1139            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|', T10, 'Enthalpy correction (H-U) [kJ/mol]:',T55,F26.8)") rotvibtra/1000.0_dp
    1140            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|', T10, 'Gibbs energy correction [kJ/mol]:',T55,F26.8)") Gibbs/1000.0_dp
    1141            1 :          WRITE (UNIT=iw, FMT="(T2,'VIB|', T10, 'Heat capacity [kJ/(mol*K)]:',T65,F16.8)") heat_capacity/1000.0_dp
    1142            1 :          WRITE (UNIT=iw, FMT="(/)")
    1143              :       END IF
    1144              : 
    1145            2 :    END SUBROUTINE get_thch_values
    1146              : 
    1147              : ! **************************************************************************************************
    1148              : !> \brief write out the non-orthogalized, i.e. without rotation and translational symmetry removed,
    1149              : !>        eigenvalues and eigenvectors of the Cartesian Hessian in unformatted binary file
    1150              : !> \param unit : the output unit to write to
    1151              : !> \param dof  : total degrees of freedom, i.e. the rank of the Hessian matrix
    1152              : !> \param eigenvalues  : eigenvalues of the Hessian matrix
    1153              : !> \param eigenvectors : matrix with each column being the eigenvectors of the Hessian matrix
    1154              : !> \author Lianheng Tong - 2016/04/20
    1155              : ! **************************************************************************************************
    1156           17 :    SUBROUTINE write_eigs_unformatted(unit, dof, eigenvalues, eigenvectors)
    1157              :       INTEGER, INTENT(IN)                                :: unit, dof
    1158              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: eigenvalues
    1159              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: eigenvectors
    1160              : 
    1161              :       CHARACTER(len=*), PARAMETER :: routineN = 'write_eigs_unformatted'
    1162              : 
    1163              :       INTEGER                                            :: handle, jj
    1164              : 
    1165           17 :       CALL timeset(routineN, handle)
    1166           17 :       IF (unit > 0) THEN
    1167              :          ! degrees of freedom, i.e. the rank
    1168           17 :          WRITE (unit) dof
    1169              :          ! eigenvalues in one record
    1170           17 :          WRITE (unit) eigenvalues(1:dof)
    1171              :          ! eigenvectors: each record contains an eigenvector
    1172          158 :          DO jj = 1, dof
    1173          158 :             WRITE (unit) eigenvectors(1:dof, jj)
    1174              :          END DO
    1175              :       END IF
    1176           17 :       CALL timestop(handle)
    1177              : 
    1178           17 :    END SUBROUTINE write_eigs_unformatted
    1179              : 
    1180              : !**************************************************************************************************
    1181              : !> \brief Write the Hessian matrix into a (unformatted) binary file
    1182              : !> \param vib_section vibrational analysis section
    1183              : !> \param para_env mpi environment
    1184              : !> \param ncoord 3 times the number of atoms
    1185              : !> \param globenv global environment
    1186              : !> \param Hessian the Hessian matrix
    1187              : !> \param logger the logger
    1188              : ! **************************************************************************************************
    1189           64 :    SUBROUTINE write_va_hessian(vib_section, para_env, ncoord, globenv, Hessian, logger)
    1190              : 
    1191              :       TYPE(section_vals_type), POINTER                   :: vib_section
    1192              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1193              :       INTEGER                                            :: ncoord
    1194              :       TYPE(global_environment_type), POINTER             :: globenv
    1195              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Hessian
    1196              :       TYPE(cp_logger_type), POINTER                      :: logger
    1197              : 
    1198              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'write_va_hessian'
    1199              : 
    1200              :       INTEGER                                            :: handle, hesunit, i, j, ndf
    1201              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1202              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_hes
    1203              :       TYPE(cp_fm_type)                                   :: hess_mat
    1204              : 
    1205           32 :       CALL timeset(routineN, handle)
    1206              : 
    1207              :       hesunit = cp_print_key_unit_nr(logger, vib_section, "PRINT%HESSIAN", &
    1208              :                                      extension=".hess", file_form="UNFORMATTED", file_action="WRITE", &
    1209           32 :                                      file_position="REWIND")
    1210              : 
    1211           32 :       NULLIFY (blacs_env)
    1212              :       CALL cp_blacs_env_create(blacs_env, para_env, globenv%blacs_grid_layout, &
    1213           32 :                                globenv%blacs_repeatable)
    1214           32 :       ndf = ncoord
    1215              :       CALL cp_fm_struct_create(fm_struct_hes, para_env=para_env, context=blacs_env, &
    1216           32 :                                nrow_global=ndf, ncol_global=ndf)
    1217           32 :       CALL cp_fm_create(hess_mat, fm_struct_hes, name="hess_mat")
    1218           32 :       CALL cp_fm_set_all(hess_mat, alpha=0.0_dp, beta=0.0_dp)
    1219              : 
    1220          296 :       DO i = 1, ncoord
    1221         2672 :          DO j = 1, ncoord
    1222         2640 :             CALL cp_fm_set_element(hess_mat, i, j, Hessian(i, j))
    1223              :          END DO
    1224              :       END DO
    1225           32 :       CALL cp_fm_write_unformatted(hess_mat, hesunit)
    1226              : 
    1227           32 :       CALL cp_print_key_finished_output(hesunit, logger, vib_section, "PRINT%HESSIAN")
    1228              : 
    1229           32 :       CALL cp_fm_struct_release(fm_struct_hes)
    1230           32 :       CALL cp_fm_release(hess_mat)
    1231           32 :       CALL cp_blacs_env_release(blacs_env)
    1232              : 
    1233           32 :       CALL timestop(handle)
    1234              : 
    1235           32 :    END SUBROUTINE write_va_hessian
    1236              : 
    1237           66 : END MODULE vibrational_analysis
        

Generated by: LCOV version 2.0-1