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

Generated by: LCOV version 2.0-1