LCOV - code coverage report
Current view: top level - src - mode_selective.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:92574dc) Lines: 92.2 % 747 689
Test Date: 2026-09-24 01:27:39 Functions: 92.3 % 13 12

            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 mdoe selective 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 Florian Schiffmann 08.2006
      19              : ! **************************************************************************************************
      20              : MODULE mode_selective
      21              :    USE bfgs_optimizer,                  ONLY: bfgs_read_restart_header
      22              :    USE cell_types,                      ONLY: cell_type
      23              :    USE cp_files,                        ONLY: close_file,&
      24              :                                               open_file
      25              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      26              :                                               cp_logger_get_default_io_unit,&
      27              :                                               cp_logger_type
      28              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      29              :                                               cp_print_key_unit_nr
      30              :    USE cp_result_methods,               ONLY: get_results
      31              :    USE global_types,                    ONLY: global_environment_type
      32              :    USE ieee_arithmetic,                 ONLY: ieee_is_finite
      33              :    USE input_constants,                 ONLY: bfgs_direct,&
      34              :                                               bfgs_inverse,&
      35              :                                               ms_guess_atomic,&
      36              :                                               ms_guess_bfgs,&
      37              :                                               ms_guess_molden,&
      38              :                                               ms_guess_restart,&
      39              :                                               ms_guess_restart_vec
      40              :    USE input_section_types,             ONLY: section_vals_get,&
      41              :                                               section_vals_get_subs_vals,&
      42              :                                               section_vals_type,&
      43              :                                               section_vals_val_get
      44              :    USE iso_fortran_env,                 ONLY: iostat_end
      45              :    USE kinds,                           ONLY: default_path_length,&
      46              :                                               default_string_length,&
      47              :                                               dp,&
      48              :                                               max_line_length
      49              :    USE mathlib,                         ONLY: diamat_all
      50              :    USE message_passing,                 ONLY: mp_para_env_type
      51              :    USE molden_utils,                    ONLY: write_vibrations_molden
      52              :    USE particle_types,                  ONLY: particle_type
      53              :    USE physcon,                         ONLY: bohr,&
      54              :                                               debye,&
      55              :                                               massunit,&
      56              :                                               vibfac
      57              :    USE replica_methods,                 ONLY: rep_env_calc_e_f
      58              :    USE replica_types,                   ONLY: replica_env_type
      59              :    USE util,                            ONLY: sort
      60              : #include "./base/base_uses.f90"
      61              : 
      62              :    IMPLICIT NONE
      63              : 
      64              :    PRIVATE
      65              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mode_selective'
      66              :    LOGICAL, PARAMETER                   :: debug_this_module = .FALSE.
      67              :    REAL(KIND=dp), PARAMETER             :: bfgs_guess_degeneracy_tol = 1.0E-8_dp
      68              : 
      69              :    TYPE ms_vib_type
      70              :       INTEGER                                  :: mat_size = -1
      71              :       INTEGER                                  :: select_id = -1
      72              :       INTEGER, DIMENSION(:), POINTER           :: inv_atoms => NULL()
      73              :       REAL(KIND=dp)                            :: eps(2) = 0.0_dp
      74              :       REAL(KIND=dp)                            :: sel_freq = 0.0_dp
      75              :       REAL(KIND=dp)                            :: low_freq = 0.0_dp
      76              :       REAL(KIND=dp), POINTER, DIMENSION(:, :)    :: b_vec => NULL()
      77              :       REAL(KIND=dp), POINTER, DIMENSION(:, :)    :: delta_vec => NULL()
      78              :       REAL(KIND=dp), POINTER, DIMENSION(:, :)    :: ms_force => NULL()
      79              :       REAL(KIND=dp), DIMENSION(:), POINTER     :: eig_bfgs => NULL()
      80              :       REAL(KIND=dp), DIMENSION(:), POINTER     :: f_range => NULL()
      81              :       REAL(KIND=dp), DIMENSION(:), POINTER     :: inv_range => NULL()
      82              :       REAL(KIND=dp), POINTER, DIMENSION(:)     :: step_b => NULL()
      83              :       REAL(KIND=dp), POINTER, DIMENSION(:)     :: step_r => NULL()
      84              :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: b_mat => NULL()
      85              :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: dip_deriv => NULL()
      86              :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: hes_bfgs => NULL()
      87              :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: s_mat => NULL()
      88              :       INTEGER                                  :: initial_guess = -1
      89              :    END TYPE ms_vib_type
      90              : 
      91              :    PUBLIC :: ms_vb_anal
      92              : 
      93              : CONTAINS
      94              : ! **************************************************************************************************
      95              : !> \brief Module performing a vibrational analysis
      96              : !> \param input ...
      97              : !> \param rep_env ...
      98              : !> \param para_env ...
      99              : !> \param globenv ...
     100              : !> \param particles ...
     101              : !> \param nrep ...
     102              : !> \param calc_intens ...
     103              : !> \param dx ...
     104              : !> \param output_unit ...
     105              : !> \param logger ...
     106              : !> \param cell simulation cell
     107              : !> \author Teodoro Laino 08.2006
     108              : ! **************************************************************************************************
     109           28 :    SUBROUTINE ms_vb_anal(input, rep_env, para_env, globenv, particles, &
     110              :                          nrep, calc_intens, dx, output_unit, logger, cell)
     111              :       TYPE(section_vals_type), POINTER                   :: input
     112              :       TYPE(replica_env_type), POINTER                    :: rep_env
     113              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     114              :       TYPE(global_environment_type), POINTER             :: globenv
     115              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     116              :       INTEGER                                            :: nrep
     117              :       LOGICAL                                            :: calc_intens
     118              :       REAL(KIND=dp)                                      :: dx
     119              :       INTEGER                                            :: output_unit
     120              :       TYPE(cp_logger_type), POINTER                      :: logger
     121              :       TYPE(cell_type), POINTER                           :: cell
     122              : 
     123              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ms_vb_anal'
     124              : 
     125              :       CHARACTER(LEN=default_string_length)               :: description
     126              :       INTEGER                                            :: handle, i, ip1, j, natoms, ncoord
     127              :       LOGICAL                                            :: converged
     128           28 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: mass, pos0
     129           28 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: tmp_deriv
     130           28 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: tmp_dip
     131              :       TYPE(ms_vib_type)                                  :: ms_vib
     132              : 
     133           28 :       CALL timeset(routineN, handle)
     134           28 :       converged = .FALSE.
     135           28 :       natoms = SIZE(particles)
     136           28 :       ncoord = 3*natoms
     137          112 :       ALLOCATE (mass(3*natoms))
     138         1068 :       DO i = 1, natoms
     139         4188 :          DO j = 1, 3
     140         3120 :             mass((i - 1)*3 + j) = particles(i)%atomic_kind%mass
     141         4160 :             mass((i - 1)*3 + j) = SQRT(mass((i - 1)*3 + j))
     142              :          END DO
     143              :       END DO
     144              :       ! Allocate working arrays
     145          112 :       ALLOCATE (ms_vib%delta_vec(ncoord, nrep))
     146           84 :       ALLOCATE (ms_vib%b_vec(ncoord, nrep))
     147           84 :       ALLOCATE (ms_vib%step_r(nrep))
     148           56 :       ALLOCATE (ms_vib%step_b(nrep))
     149           28 :       IF (calc_intens) THEN
     150           22 :          description = '[DIPOLE]'
     151           88 :          ALLOCATE (tmp_dip(nrep, 3, 2))
     152           66 :          ALLOCATE (ms_vib%dip_deriv(3, nrep))
     153              :       END IF
     154              :       CALL MS_initial_moves(para_env, nrep, input, globenv, ms_vib, &
     155              :                             particles, &
     156              :                             mass, &
     157              :                             dx, &
     158           28 :                             calc_intens, logger)
     159           28 :       ncoord = 3*natoms
     160           84 :       ALLOCATE (pos0(ncoord))
     161          112 :       ALLOCATE (ms_vib%ms_force(ncoord, nrep))
     162         1068 :       DO i = 1, natoms
     163         4188 :          DO j = 1, 3
     164         4160 :             pos0((i - 1)*3 + j) = particles((i))%r(j)
     165              :          END DO
     166              :       END DO
     167          186 :       ncoord = 3*natoms
     168              :       DO
     169        26952 :          ms_vib%ms_force = HUGE(0.0_dp)
     170          384 :          DO i = 1, nrep
     171        26952 :             DO j = 1, ncoord
     172        26766 :                rep_env%r(j, i) = pos0(j) + ms_vib%step_r(i)*ms_vib%delta_vec(j, i)
     173              :             END DO
     174              :          END DO
     175          186 :          CALL rep_env_calc_e_f(rep_env, calc_f=.TRUE.)
     176              : 
     177          384 :          DO i = 1, nrep
     178          198 :             IF (calc_intens) THEN
     179              :                CALL get_results(results=rep_env%results(i)%results, &
     180              :                                 description=description, &
     181          168 :                                 n_rep=ip1)
     182              :                CALL get_results(results=rep_env%results(i)%results, &
     183              :                                 description=description, &
     184              :                                 values=tmp_dip(i, :, 1), &
     185          168 :                                 nval=ip1)
     186              :             END IF
     187        26952 :             DO j = 1, ncoord
     188        26766 :                ms_vib%ms_force(j, i) = rep_env%f(j, i)
     189              :             END DO
     190              :          END DO
     191          384 :          DO i = 1, nrep
     192        26952 :             DO j = 1, ncoord
     193        26766 :                rep_env%r(j, i) = pos0(j) - ms_vib%step_r(i)*ms_vib%delta_vec(j, i)
     194              :             END DO
     195              :          END DO
     196          186 :          CALL rep_env_calc_e_f(rep_env, calc_f=.TRUE.)
     197          186 :          IF (calc_intens) THEN
     198          336 :             DO i = 1, nrep
     199              :                CALL get_results(results=rep_env%results(i)%results, &
     200              :                                 description=description, &
     201          168 :                                 n_rep=ip1)
     202              :                CALL get_results(results=rep_env%results(i)%results, &
     203              :                                 description=description, &
     204              :                                 values=tmp_dip(i, :, 2), &
     205          168 :                                 nval=ip1)
     206         1008 :                ms_vib%dip_deriv(:, ms_vib%mat_size + i) = (tmp_dip(i, :, 1) - tmp_dip(i, :, 2))/(2*ms_vib%step_b(i))
     207              :             END DO
     208              :          END IF
     209              : 
     210              :          CALL evaluate_H_update_b(rep_env, ms_vib, input, nrep, &
     211              :                                   particles, &
     212              :                                   mass, &
     213              :                                   converged, &
     214              :                                   dx, calc_intens, &
     215          186 :                                   output_unit, logger, cell)
     216          186 :          IF (converged) EXIT
     217          186 :          IF (calc_intens) THEN
     218          438 :             ALLOCATE (tmp_deriv(3, ms_vib%mat_size))
     219         4034 :             tmp_deriv = ms_vib%dip_deriv
     220          146 :             DEALLOCATE (ms_vib%dip_deriv)
     221          438 :             ALLOCATE (ms_vib%dip_deriv(3, ms_vib%mat_size + nrep))
     222         4034 :             ms_vib%dip_deriv(:, 1:ms_vib%mat_size) = tmp_deriv(:, 1:ms_vib%mat_size)
     223          146 :             DEALLOCATE (tmp_deriv)
     224              :          END IF
     225              :       END DO
     226           28 :       DEALLOCATE (ms_vib%ms_force)
     227           28 :       DEALLOCATE (pos0)
     228           28 :       DEALLOCATE (ms_vib%step_r)
     229           28 :       DEALLOCATE (ms_vib%step_b)
     230           28 :       DEALLOCATE (ms_vib%b_vec)
     231           28 :       DEALLOCATE (ms_vib%delta_vec)
     232           28 :       DEALLOCATE (mass)
     233           28 :       DEALLOCATE (ms_vib%b_mat)
     234           28 :       DEALLOCATE (ms_vib%s_mat)
     235           28 :       IF (ms_vib%select_id == 3) THEN
     236           12 :          DEALLOCATE (ms_vib%inv_atoms)
     237              :       END IF
     238           28 :       IF (ASSOCIATED(ms_vib%eig_bfgs)) THEN
     239            0 :          DEALLOCATE (ms_vib%eig_bfgs)
     240              :       END IF
     241           28 :       IF (ASSOCIATED(ms_vib%hes_bfgs)) THEN
     242            0 :          DEALLOCATE (ms_vib%hes_bfgs)
     243              :       END IF
     244           28 :       IF (calc_intens) THEN
     245           22 :          DEALLOCATE (ms_vib%dip_deriv)
     246           22 :          DEALLOCATE (tmp_dip)
     247              :       END IF
     248           28 :       CALL timestop(handle)
     249           84 :    END SUBROUTINE ms_vb_anal
     250              : ! **************************************************************************************************
     251              : !> \brief Generates the first displacement vector for a mode selctive vibrational
     252              : !>      analysis. At the moment this is a random number for selected atoms
     253              : !> \param para_env ...
     254              : !> \param nrep ...
     255              : !> \param input ...
     256              : !> \param globenv ...
     257              : !> \param ms_vib ...
     258              : !> \param particles ...
     259              : !> \param mass ...
     260              : !> \param dx ...
     261              : !> \param calc_intens ...
     262              : !> \param logger ...
     263              : !> \author Florian Schiffmann 11.2007
     264              : ! **************************************************************************************************
     265           28 :    SUBROUTINE MS_initial_moves(para_env, nrep, input, globenv, ms_vib, particles, &
     266           28 :                                mass, dx, &
     267              :                                calc_intens, logger)
     268              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     269              :       INTEGER                                            :: nrep
     270              :       TYPE(section_vals_type), POINTER                   :: input
     271              :       TYPE(global_environment_type), POINTER             :: globenv
     272              :       TYPE(ms_vib_type)                                  :: ms_vib
     273              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     274              :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     275              :       REAL(KIND=dp)                                      :: dx
     276              :       LOGICAL                                            :: calc_intens
     277              :       TYPE(cp_logger_type), POINTER                      :: logger
     278              : 
     279              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'MS_initial_moves'
     280              : 
     281              :       INTEGER                                            :: guess, handle, i, j, jj, k, m, &
     282              :                                                             n_rep_val, natoms, ncoord
     283           28 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: map_atoms
     284           28 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
     285              :       LOGICAL                                            :: do_involved_atoms, ionode
     286              :       REAL(KIND=dp)                                      :: my_val, norm
     287              :       TYPE(section_vals_type), POINTER                   :: involved_at_section, ms_vib_section
     288              : 
     289           28 :       CALL timeset(routineN, handle)
     290           28 :       NULLIFY (ms_vib%eig_bfgs, ms_vib%f_range, ms_vib%hes_bfgs, ms_vib%inv_range)
     291           28 :       ms_vib_section => section_vals_get_subs_vals(input, "VIBRATIONAL_ANALYSIS%MODE_SELECTIVE")
     292           28 :       CALL section_vals_val_get(ms_vib_section, "INITIAL_GUESS", i_val=guess)
     293           28 :       CALL section_vals_val_get(ms_vib_section, "EPS_MAX_VAL", r_val=ms_vib%eps(1))
     294           28 :       CALL section_vals_val_get(ms_vib_section, "EPS_NORM", r_val=ms_vib%eps(2))
     295           28 :       CALL section_vals_val_get(ms_vib_section, "RANGE", n_rep_val=n_rep_val)
     296           28 :       ms_vib%select_id = 0
     297           28 :       IF (n_rep_val /= 0) THEN
     298            2 :          CALL section_vals_val_get(ms_vib_section, "RANGE", r_vals=ms_vib%f_range)
     299            2 :          IF (ms_vib%f_range(1) > ms_vib%f_range(2)) THEN
     300            0 :             my_val = ms_vib%f_range(2)
     301            0 :             ms_vib%f_range(2) = ms_vib%f_range(1)
     302            0 :             ms_vib%f_range(1) = my_val
     303              :          END IF
     304            2 :          ms_vib%select_id = 2
     305              :       END IF
     306           28 :       CALL section_vals_val_get(ms_vib_section, "FREQUENCY", r_val=ms_vib%sel_freq)
     307           28 :       CALL section_vals_val_get(ms_vib_section, "LOWEST_FREQUENCY", r_val=ms_vib%low_freq)
     308           28 :       IF (ms_vib%sel_freq > 0._dp) ms_vib%select_id = 1
     309           28 :       involved_at_section => section_vals_get_subs_vals(ms_vib_section, "INVOLVED_ATOMS")
     310           28 :       CALL section_vals_get(involved_at_section, explicit=do_involved_atoms)
     311           28 :       IF (do_involved_atoms) THEN
     312           12 :          CALL section_vals_val_get(involved_at_section, "INVOLVED_ATOMS", n_rep_val=n_rep_val)
     313           12 :          jj = 0
     314           24 :          DO k = 1, n_rep_val
     315           12 :             CALL section_vals_val_get(involved_at_section, "INVOLVED_ATOMS", i_rep_val=k, i_vals=tmplist)
     316           48 :             DO j = 1, SIZE(tmplist)
     317           36 :                jj = jj + 1
     318              :             END DO
     319              :          END DO
     320           12 :          IF (jj >= 1) THEN
     321           12 :             natoms = jj
     322           36 :             ALLOCATE (ms_vib%inv_atoms(natoms))
     323           12 :             jj = 0
     324           24 :             DO m = 1, n_rep_val
     325           12 :                CALL section_vals_val_get(involved_at_section, "INVOLVED_ATOMS", i_rep_val=m, i_vals=tmplist)
     326           48 :                DO j = 1, SIZE(tmplist)
     327           36 :                   ms_vib%inv_atoms(j) = tmplist(j)
     328              :                END DO
     329              :             END DO
     330           12 :             ms_vib%select_id = 3
     331              :          END IF
     332           12 :          CALL section_vals_val_get(involved_at_section, "RANGE", n_rep_val=n_rep_val)
     333           12 :          IF (n_rep_val /= 0) THEN
     334            0 :             CALL section_vals_val_get(involved_at_section, "RANGE", r_vals=ms_vib%inv_range)
     335            0 :             IF (ms_vib%inv_range(1) > ms_vib%inv_range(2)) THEN
     336            0 :                ms_vib%inv_range(2) = my_val
     337            0 :                ms_vib%inv_range(2) = ms_vib%inv_range(1)
     338            0 :                ms_vib%inv_range(1) = my_val
     339              :             END IF
     340              :          END IF
     341              :       END IF
     342           28 :       IF (ms_vib%select_id == 0) THEN
     343            0 :          CPABORT("no frequency, range or involved atoms specified ")
     344              :       END IF
     345           28 :       ionode = para_env%is_source()
     346           12 :       SELECT CASE (guess)
     347              :       CASE (ms_guess_atomic)
     348           12 :          ms_vib%initial_guess = 1
     349           12 :          CALL section_vals_val_get(ms_vib_section, "ATOMS", n_rep_val=n_rep_val)
     350           12 :          jj = 0
     351           22 :          DO k = 1, n_rep_val
     352           10 :             CALL section_vals_val_get(ms_vib_section, "ATOMS", i_rep_val=k, i_vals=tmplist)
     353           42 :             DO j = 1, SIZE(tmplist)
     354           30 :                jj = jj + 1
     355              :             END DO
     356              :          END DO
     357           12 :          IF (jj < 1) THEN
     358            2 :             natoms = SIZE(particles)
     359            6 :             ALLOCATE (map_atoms(natoms))
     360           14 :             DO j = 1, natoms
     361           14 :                map_atoms(j) = j
     362              :             END DO
     363              :          ELSE
     364           10 :             natoms = jj
     365           30 :             ALLOCATE (map_atoms(natoms))
     366           10 :             jj = 0
     367           20 :             DO m = 1, n_rep_val
     368           10 :                CALL section_vals_val_get(ms_vib_section, "ATOMS", i_rep_val=m, i_vals=tmplist)
     369           40 :                DO j = 1, SIZE(tmplist)
     370           30 :                   map_atoms(j) = tmplist(j)
     371              :                END DO
     372              :             END DO
     373              :          END IF
     374              : 
     375              :          ! apply random displacement along the mass weighted nuclear cartesian coordinates
     376          526 :          ms_vib%b_vec = 0._dp
     377          526 :          ms_vib%delta_vec = 0._dp
     378           12 :          jj = 0
     379              : 
     380           28 :          DO i = 1, nrep
     381           56 :             DO j = 1, natoms
     382          176 :                DO k = 1, 3
     383          120 :                   jj = (map_atoms(j) - 1)*3 + k
     384          160 :                   ms_vib%b_vec(jj, i) = ABS(globenv%gaussian_rng_stream%next())
     385              :                END DO
     386              :             END DO
     387          514 :             norm = NORM2(ms_vib%b_vec(:, i))
     388          526 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/norm
     389              :          END DO
     390              : 
     391           12 :          IF (nrep > 1) THEN
     392           44 :             DO k = 1, 10
     393          124 :                DO j = 1, nrep
     394          280 :                   DO i = 1, nrep
     395          240 :                      IF (i /= j) THEN
     396              :                         ms_vib%b_vec(:, j) = &
     397         1520 :                            ms_vib%b_vec(:, j) - DOT_PRODUCT(ms_vib%b_vec(:, j), ms_vib%b_vec(:, i))*ms_vib%b_vec(:, i)
     398              :                         ms_vib%b_vec(:, j) = &
     399         1520 :                            ms_vib%b_vec(:, j)/NORM2(ms_vib%b_vec(:, j))
     400              :                      END IF
     401              :                   END DO
     402              :                END DO
     403              :             END DO
     404              :          END IF
     405              : 
     406           12 :          ms_vib%mat_size = 0
     407          474 :          DO i = 1, SIZE(ms_vib%b_vec, 1)
     408          972 :             ms_vib%delta_vec(i, :) = ms_vib%b_vec(i, :)/mass(i)
     409              :          END DO
     410              :       CASE (ms_guess_bfgs)
     411              : 
     412            8 :          ms_vib%initial_guess = 2
     413            8 :          CALL bfgs_guess(ms_vib_section, ms_vib, particles, mass, para_env, nrep)
     414            8 :          ms_vib%mat_size = 0
     415              : 
     416              :       CASE (ms_guess_restart_vec)
     417              : 
     418            4 :          ms_vib%initial_guess = 3
     419              :          ncoord = 3*SIZE(particles)
     420            4 :          CALL rest_guess(ms_vib_section, para_env, ms_vib, mass, ionode, particles, nrep, calc_intens)
     421              : 
     422            4 :          ms_vib%mat_size = 0
     423              :       CASE (ms_guess_restart)
     424            0 :          ms_vib%initial_guess = 4
     425              :          ncoord = 3*SIZE(particles)
     426            0 :          CALL rest_guess(ms_vib_section, para_env, ms_vib, mass, ionode, particles, nrep, calc_intens)
     427              : 
     428              :       CASE (ms_guess_molden)
     429            4 :          ms_vib%initial_guess = 5
     430            4 :          ncoord = 3*SIZE(particles)
     431            4 :          CALL molden_guess(ms_vib_section, input, para_env, ms_vib, mass, ncoord, nrep, logger)
     432           32 :          ms_vib%mat_size = 0
     433              :       END SELECT
     434         6404 :       CALL para_env%bcast(ms_vib%b_vec)
     435         6404 :       CALL para_env%bcast(ms_vib%delta_vec)
     436           60 :       DO i = 1, nrep
     437         3188 :          ms_vib%step_r(i) = dx/NORM2(ms_vib%delta_vec(:, i))
     438         3216 :          ms_vib%step_b(i) = NORM2(ms_vib%step_r(i)*ms_vib%b_vec(:, i))
     439              :       END DO
     440           28 :       CALL timestop(handle)
     441              : 
     442           56 :    END SUBROUTINE MS_initial_moves
     443              : 
     444              : ! **************************************************************************************************
     445              : !> \brief Read a legacy or tagged BFGS restart as a direct ionic Hessian.
     446              : !> \param unit File unit
     447              : !> \param ncoord Number of ionic coordinates needed by mode-selective analysis
     448              : !> \param hessian Direct ionic Hessian
     449              : ! **************************************************************************************************
     450            4 :    SUBROUTINE read_bfgs_guess_hessian(unit, ncoord, hessian)
     451              :       INTEGER, INTENT(IN)                                :: unit, ncoord
     452              :       REAL(KIND=dp), DIMENSION(ncoord, ncoord), &
     453              :          INTENT(OUT)                                     :: hessian
     454              : 
     455              :       INTEGER                                            :: i, ios, stored_method, stored_ndf, &
     456              :                                                             stored_type
     457              :       LOGICAL                                            :: tagged
     458              :       REAL(KIND=dp)                                      :: extra
     459            4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: column, eigenvalues
     460            4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: stored_matrix
     461              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: cell_frame, reference_cell
     462              : 
     463              :       CALL bfgs_read_restart_header(unit, stored_method, stored_ndf, stored_type, tagged, &
     464            4 :                                     reference_cell, cell_frame)
     465              : 
     466            4 :       IF (.NOT. tagged) THEN
     467              :          ! Legacy restart: preserve the historical behaviour. Reading ncoord values from
     468              :          ! the first ncoord records also extracts the ionic block from a CELL_OPT Hessian.
     469            0 :          DO i = 1, ncoord
     470            0 :             READ (unit, IOSTAT=ios) hessian(:, i)
     471            0 :             IF (ios /= 0) CPABORT("Error while reading legacy BFGS Hessian")
     472              :          END DO
     473              :          RETURN
     474              :       END IF
     475              : 
     476            4 :       IF (stored_ndf < ncoord) THEN
     477            0 :          CPABORT("BFGS restart matrix is smaller than the mode-selective ionic Hessian")
     478              :       END IF
     479              : 
     480            2 :       SELECT CASE (stored_method)
     481              :       CASE (bfgs_direct)
     482            6 :          ALLOCATE (column(stored_ndf))
     483          356 :          DO i = 1, stored_ndf
     484          354 :             READ (unit, IOSTAT=ios) column(:)
     485          354 :             IF (ios /= 0) CPABORT("Truncated BFGS restart matrix")
     486        63012 :             IF (.NOT. ALL(ieee_is_finite(column(:)))) CPABORT("Non-finite BFGS restart matrix")
     487        63014 :             IF (i <= ncoord) hessian(:, i) = column(1:ncoord)
     488              :          END DO
     489            2 :          DEALLOCATE (column)
     490              : 
     491              :       CASE (bfgs_inverse)
     492           12 :          ALLOCATE (stored_matrix(stored_ndf, stored_ndf), eigenvalues(stored_ndf))
     493          275 :          DO i = 1, stored_ndf
     494          273 :             READ (unit, IOSTAT=ios) stored_matrix(:, i)
     495          275 :             IF (ios /= 0) CPABORT("Truncated inverse BFGS restart matrix")
     496              :          END DO
     497        40820 :          IF (.NOT. ALL(ieee_is_finite(stored_matrix(:, :)))) THEN
     498            0 :             CPABORT("Non-finite inverse BFGS restart matrix")
     499              :          END IF
     500              : 
     501              :          ! Invert the complete matrix before taking the ionic block. For CELL_OPT,
     502              :          ! inverse(H_RR) is not in general equal to the RR block of inverse(H).
     503            2 :          CALL diamat_all(stored_matrix, eigenvalues)
     504          275 :          IF (.NOT. ALL(ieee_is_finite(eigenvalues(:)))) THEN
     505            0 :             CPABORT("Non-finite inverse BFGS restart spectrum")
     506              :          END IF
     507          275 :          IF (MINVAL(eigenvalues(:)) <= 0.0_dp) THEN
     508            0 :             CPABORT("Inverse BFGS restart matrix is not positive definite")
     509              :          END IF
     510          275 :          eigenvalues(:) = 1.0_dp/eigenvalues(:)
     511          275 :          IF (.NOT. ALL(ieee_is_finite(eigenvalues(:)))) THEN
     512            0 :             CPABORT("Unrepresentable inverse BFGS restart matrix")
     513              :          END IF
     514          275 :          DO i = 1, stored_ndf
     515              :             stored_matrix(1:ncoord, i) = &
     516        40244 :                SQRT(eigenvalues(i))*stored_matrix(1:ncoord, i)
     517              :          END DO
     518            4 :          hessian(:, :) = MATMUL(stored_matrix(1:ncoord, :), &
     519            2 :                                 TRANSPOSE(stored_matrix(1:ncoord, :)))
     520            2 :          DEALLOCATE (stored_matrix, eigenvalues)
     521              : 
     522              :       CASE DEFAULT
     523            4 :          CPABORT("Unknown matrix representation in BFGS restart")
     524              :       END SELECT
     525              : 
     526              :       ! Tagged files have a known matrix dimension, so reject trailing/corrupt data.
     527            4 :       READ (unit, IOSTAT=ios) extra
     528            4 :       IF (ios /= iostat_end) CPABORT("Extra data in BFGS restart matrix")
     529              :       MARK_USED(stored_type)
     530              :       MARK_USED(reference_cell)
     531              :       MARK_USED(cell_frame)
     532            4 :    END SUBROUTINE read_bfgs_guess_hessian
     533              : 
     534              : ! **************************************************************************************************
     535              : !> \brief ...
     536              : !> \param ms_vib_section ...
     537              : !> \param ms_vib ...
     538              : !> \param particles ...
     539              : !> \param mass ...
     540              : !> \param para_env ...
     541              : !> \param nrep ...
     542              : !> \author Florian Schiffmann 11.2007
     543              : ! **************************************************************************************************
     544            8 :    SUBROUTINE bfgs_guess(ms_vib_section, ms_vib, particles, mass, para_env, nrep)
     545              : 
     546              :       TYPE(section_vals_type), POINTER                   :: ms_vib_section
     547              :       TYPE(ms_vib_type)                                  :: ms_vib
     548              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     549              :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     550              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     551              :       INTEGER                                            :: nrep
     552              : 
     553              :       CHARACTER(LEN=default_path_length)                 :: hes_filename
     554              :       INTEGER                                            :: hesunit, i, j, jj, k, natoms, ncoord, &
     555              :                                                             output_unit
     556            8 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
     557              :       REAL(KIND=dp)                                      :: my_val, norm
     558            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tmp
     559              :       TYPE(cp_logger_type), POINTER                      :: logger
     560              : 
     561           16 :       logger => cp_get_default_logger()
     562            8 :       output_unit = cp_logger_get_default_io_unit(logger)
     563              : 
     564            8 :       natoms = SIZE(particles)
     565            8 :       ncoord = 3*natoms
     566              : 
     567           32 :       ALLOCATE (ms_vib%hes_bfgs(ncoord, ncoord))
     568           24 :       ALLOCATE (ms_vib%eig_bfgs(ncoord))
     569              : 
     570            8 :       IF (para_env%is_source()) THEN
     571            4 :          CALL section_vals_val_get(ms_vib_section, "RESTART_FILE_NAME", c_val=hes_filename)
     572            4 :          IF (hes_filename == "") hes_filename = "HESSIAN"
     573              :          CALL open_file(file_name=hes_filename, file_status="OLD", &
     574            4 :                         file_form="UNFORMATTED", file_action="READ", unit_number=hesunit)
     575           12 :          ALLOCATE (tmp(ncoord))
     576           12 :          ALLOCATE (tmplist(ncoord))
     577              : 
     578            4 :          CALL read_bfgs_guess_hessian(hesunit, ncoord, ms_vib%hes_bfgs)
     579            4 :          CALL close_file(hesunit)
     580            4 :          IF (output_unit > 0) THEN
     581              :             WRITE (output_unit, FMT="(/,T2,A)") &
     582            4 :                "*** Initial Hessian has been read successfully ***"
     583              :          END IF
     584          625 :          DO i = 1, ncoord
     585       102712 :             DO j = 1, ncoord
     586       102708 :                ms_vib%hes_bfgs(i, j) = ms_vib%hes_bfgs(i, j)/(mass(i)*mass(j))
     587              :             END DO
     588              :          END DO
     589              : 
     590            4 :          CALL diamat_all(ms_vib%hes_bfgs, ms_vib%eig_bfgs)
     591            4 :          tmp(:) = 0._dp
     592            4 :          IF (ms_vib%select_id == 1) my_val = (ms_vib%sel_freq/vibfac)**2/massunit
     593            4 :          IF (ms_vib%select_id == 2) my_val = (((ms_vib%f_range(2) + ms_vib%f_range(1))*0.5_dp)/vibfac)**2/massunit
     594            4 :          IF (ms_vib%select_id == 1 .OR. ms_vib%select_id == 2) THEN
     595          178 :             DO i = 1, ncoord
     596          178 :                tmp(i) = ABS(my_val - ms_vib%eig_bfgs(i))
     597              :             END DO
     598            3 :          ELSE IF (ms_vib%select_id == 3) THEN
     599            3 :             CALL bfgs_canonicalize_degenerate_modes(ms_vib%hes_bfgs, ms_vib%eig_bfgs)
     600          447 :             DO i = 1, ncoord
     601         1332 :                DO j = 1, SIZE(ms_vib%inv_atoms)
     602         3996 :                   DO k = 1, 3
     603         2664 :                      jj = (ms_vib%inv_atoms(j) - 1)*3 + k
     604         3552 :                      tmp(i) = tmp(i) + SQRT(ms_vib%hes_bfgs(jj, i)**2)
     605              :                   END DO
     606              :                END DO
     607          447 :                IF ((SIGN(1._dp, ms_vib%eig_bfgs(i))*SQRT(ABS(ms_vib%eig_bfgs(i))*massunit)*vibfac) <= 400._dp) tmp(i) = 0._dp
     608              :             END DO
     609          447 :             tmp(:) = -tmp(:)
     610              :          END IF
     611            4 :          CALL sort(tmp, ncoord, tmplist)
     612            8 :          DO i = 1, nrep
     613          625 :             ms_vib%b_vec(:, i) = ms_vib%hes_bfgs(:, tmplist(i))
     614          625 :             norm = NORM2(ms_vib%b_vec(:, i))
     615          629 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/norm
     616              :          END DO
     617          625 :          DO i = 1, SIZE(ms_vib%b_vec, 1)
     618         1246 :             ms_vib%delta_vec(i, :) = ms_vib%b_vec(i, :)/mass(i)
     619              :          END DO
     620            4 :          DEALLOCATE (tmp)
     621            4 :          DEALLOCATE (tmplist)
     622              :       END IF
     623              : 
     624         2508 :       CALL para_env%bcast(ms_vib%b_vec)
     625         2508 :       CALL para_env%bcast(ms_vib%delta_vec)
     626              : 
     627            8 :       DEALLOCATE (ms_vib%hes_bfgs)
     628            8 :       DEALLOCATE (ms_vib%eig_bfgs)
     629            8 :       ms_vib%mat_size = 0
     630              : 
     631            8 :    END SUBROUTINE bfgs_guess
     632              : 
     633              : ! **************************************************************************************************
     634              : !> \brief Replace arbitrary bases of near-degenerate BFGS eigenspaces by deterministic ones.
     635              : !>        This leaves the existing involved-atom scoring and mode ordering unchanged.
     636              : !> \param modes Orthonormal Hessian eigenvectors
     637              : !> \param eigenvalues Ascending Hessian eigenvalues
     638              : ! **************************************************************************************************
     639            3 :    SUBROUTINE bfgs_canonicalize_degenerate_modes(modes, eigenvalues)
     640              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: modes
     641              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: eigenvalues
     642              : 
     643              :       INTEGER                                            :: first, last, n
     644              :       REAL(KIND=dp)                                      :: cutoff, scale
     645              : 
     646            3 :       n = SIZE(eigenvalues)
     647            3 :       CPASSERT(SIZE(modes, 1) == n .AND. SIZE(modes, 2) == n)
     648            3 :       cutoff = (400.0_dp/vibfac)**2/massunit
     649              : 
     650            3 :       first = 1
     651          396 :       DO WHILE (first <= n)
     652          393 :          IF (eigenvalues(first) <= cutoff) THEN
     653          124 :             first = first + 1
     654          124 :             CYCLE
     655              :          END IF
     656              :          last = first
     657          320 :          DO WHILE (last < n)
     658          317 :             scale = MAX(ABS(eigenvalues(first)), ABS(eigenvalues(last + 1)))
     659          317 :             IF (eigenvalues(last + 1) - eigenvalues(first) > bfgs_guess_degeneracy_tol*scale) EXIT
     660          269 :             last = last + 1
     661              :          END DO
     662          269 :          IF (last > first) CALL bfgs_canonical_modes(modes(:, first:last))
     663          269 :          first = last + 1
     664              :       END DO
     665            3 :    END SUBROUTINE bfgs_canonicalize_degenerate_modes
     666              : 
     667              : ! **************************************************************************************************
     668              : !> \brief Fix a subspace basis using projections of Cartesian coordinate axes.
     669              : !> \param modes Orthonormal basis, replaced by a deterministic orthonormal basis
     670              : ! **************************************************************************************************
     671            3 :    SUBROUTINE bfgs_canonical_modes(modes)
     672              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: modes
     673              : 
     674              :       INTEGER                                            :: i, j, k, m, n, pass, pivot
     675              :       REAL(KIND=dp)                                      :: maximum, norm
     676            3 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: norms, projection, vector
     677            3 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: residual, rotation
     678              : 
     679            3 :       n = SIZE(modes, 1)
     680            3 :       m = SIZE(modes, 2)
     681           36 :       ALLOCATE (residual(n, m), rotation(m, m), norms(n), projection(n), vector(m))
     682         4917 :       residual(:, :) = modes(:, :)
     683            3 :       rotation(:, :) = 0.0_dp
     684           57 :       DO j = 1, m
     685       133434 :          norms(:) = SUM(residual(:, :)**2, DIM=2)
     686         4914 :          maximum = MAXVAL(norms)
     687         2329 :          pivot = 1
     688         2329 :          DO i = 1, n
     689         2329 :             IF (norms(i) >= maximum*(1.0_dp - bfgs_guess_degeneracy_tol)) THEN
     690              :                pivot = i
     691              :                EXIT
     692              :             END IF
     693              :          END DO
     694         1482 :          vector(:) = residual(pivot, :)
     695          162 :          DO pass = 1, 2
     696         1536 :             DO k = 1, j - 1
     697        80178 :                vector(:) = vector(:) - DOT_PRODUCT(rotation(:, k), vector)*rotation(:, k)
     698              :             END DO
     699              :          END DO
     700         1482 :          norm = NORM2(vector)
     701           54 :          CPASSERT(norm > SQRT(EPSILON(1.0_dp)))
     702         1482 :          rotation(:, j) = vector(:)/norm
     703       130002 :          projection(:) = MATMUL(residual, rotation(:, j))
     704         1485 :          DO k = 1, m
     705       130002 :             residual(:, k) = residual(:, k) - projection(:)*rotation(k, j)
     706              :          END DO
     707              :       END DO
     708          369 :       residual(:, :) = MATMUL(modes, rotation)
     709         4917 :       modes(:, :) = residual(:, :)
     710            3 :       DEALLOCATE (residual, rotation, norms, projection, vector)
     711            3 :    END SUBROUTINE bfgs_canonical_modes
     712              : 
     713              : ! **************************************************************************************************
     714              : !> \brief ...
     715              : !> \param ms_vib_section ...
     716              : !> \param para_env ...
     717              : !> \param ms_vib ...
     718              : !> \param mass ...
     719              : !> \param ionode ...
     720              : !> \param particles ...
     721              : !> \param nrep ...
     722              : !> \param calc_intens ...
     723              : !> \author Florian Schiffmann 11.2007
     724              : ! **************************************************************************************************
     725            4 :    SUBROUTINE rest_guess(ms_vib_section, para_env, ms_vib, mass, ionode, particles, nrep, calc_intens)
     726              : 
     727              :       TYPE(section_vals_type), POINTER                   :: ms_vib_section
     728              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     729              :       TYPE(ms_vib_type)                                  :: ms_vib
     730              :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     731              :       LOGICAL                                            :: ionode
     732              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     733              :       INTEGER                                            :: nrep
     734              :       LOGICAL                                            :: calc_intens
     735              : 
     736              :       CHARACTER(LEN=default_path_length)                 :: ms_filename
     737              :       INTEGER                                            :: hesunit, i, j, mat, natoms, ncoord, &
     738              :                                                             output_unit, stat, statint
     739            4 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ind
     740            4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval
     741            4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: approx_H
     742              :       TYPE(cp_logger_type), POINTER                      :: logger
     743              : 
     744            4 :       logger => cp_get_default_logger()
     745            4 :       output_unit = cp_logger_get_default_io_unit(logger)
     746              : 
     747            4 :       natoms = SIZE(particles)
     748            4 :       ncoord = 3*natoms
     749            4 :       IF (calc_intens) THEN
     750            4 :          DEALLOCATE (ms_vib%dip_deriv)
     751              :       END IF
     752              : 
     753            4 :       IF (ionode) THEN
     754              : 
     755            2 :          CALL section_vals_val_get(ms_vib_section, "RESTART_FILE_NAME", c_val=ms_filename)
     756            2 :          IF (ms_filename == "") ms_filename = "MS_RESTART"
     757              :          CALL open_file(file_name=ms_filename, &
     758              :                         file_status="UNKNOWN", &
     759              :                         file_form="UNFORMATTED", &
     760              :                         file_action="READ", &
     761            2 :                         unit_number=hesunit)
     762            2 :          READ (UNIT=hesunit, IOSTAT=stat) mat
     763            2 :          CPASSERT(stat == 0)
     764            2 :          ms_vib%mat_size = mat
     765              :       END IF
     766            4 :       CALL para_env%bcast(ms_vib%mat_size)
     767           16 :       ALLOCATE (ms_vib%b_mat(ncoord, ms_vib%mat_size))
     768           12 :       ALLOCATE (ms_vib%s_mat(ncoord, ms_vib%mat_size))
     769            4 :       IF (calc_intens) THEN
     770           12 :          ALLOCATE (ms_vib%dip_deriv(3, ms_vib%mat_size + nrep))
     771              :       END IF
     772            4 :       IF (ionode) THEN
     773            2 :          statint = 0
     774         3384 :          READ (UNIT=hesunit) ms_vib%b_mat
     775         3384 :          READ (UNIT=hesunit, IOSTAT=stat) ms_vib%s_mat
     776            2 :          IF (stat /= 0 .AND. output_unit > 0) THEN
     777            0 :             WRITE (output_unit, FMT="(/,T2,A)") "**  Error while reading MS_RESTART **"
     778              :          END IF
     779            2 :          IF (calc_intens) THEN
     780            2 :             READ (UNIT=hesunit, IOSTAT=statint) ms_vib%dip_deriv(:, 1:ms_vib%mat_size)
     781            2 :             IF (statint /= 0 .AND. output_unit > 0) WRITE (output_unit, FMT="(/,T2,A)") "**  Error while reading MS_RESTART,", &
     782            0 :                "intensities are requested but not present in restart file **"
     783              :          END IF
     784            2 :          CALL close_file(hesunit)
     785            2 :          IF (stat == 0 .AND. statint == 0 .AND. output_unit > 0) THEN
     786            2 :             WRITE (output_unit, FMT="(/,T2,A)") "*** MS_RESTART has been read successfully ***"
     787              :          END IF
     788              :       END IF
     789        13532 :       CALL para_env%bcast(ms_vib%b_mat)
     790        13532 :       CALL para_env%bcast(ms_vib%s_mat)
     791          340 :       IF (calc_intens) CALL para_env%bcast(ms_vib%dip_deriv)
     792           16 :       ALLOCATE (approx_H(ms_vib%mat_size, ms_vib%mat_size))
     793           12 :       ALLOCATE (eigenval(ms_vib%mat_size))
     794           12 :       ALLOCATE (ind(ms_vib%mat_size))
     795              : 
     796              :       CALL dgemm('T', 'N', ms_vib%mat_size, ms_vib%mat_size, SIZE(ms_vib%s_mat, 1), 1._dp, ms_vib%b_mat, SIZE(ms_vib%b_mat, 1), &
     797            4 :                  ms_vib%s_mat, SIZE(ms_vib%s_mat, 1), 0._dp, approx_H, ms_vib%mat_size)
     798            4 :       CALL diamat_all(approx_H, eigenval)
     799              : 
     800            4 :       CALL select_vector(ms_vib, nrep, mass, ncoord, approx_H, eigenval, ind, ms_vib%b_vec)
     801            4 :       IF (ms_vib%initial_guess /= 4) THEN
     802              : 
     803          716 :          ms_vib%b_vec = 0._dp
     804            8 :          DO i = 1, nrep
     805           42 :             DO j = 1, ms_vib%mat_size
     806         6768 :                ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i) + approx_H(j, ind(i))*ms_vib%b_mat(:, j)
     807              :             END DO
     808         1424 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/NORM2(ms_vib%b_vec(:, i))
     809              :          END DO
     810              : 
     811            4 :          DEALLOCATE (ms_vib%s_mat)
     812            4 :          DEALLOCATE (ms_vib%b_mat)
     813            4 :          IF (calc_intens) THEN
     814            4 :             DEALLOCATE (ms_vib%dip_deriv)
     815           12 :             ALLOCATE (ms_vib%dip_deriv(3, nrep))
     816              :          END IF
     817              :       END IF
     818            4 :       DEALLOCATE (approx_H)
     819            4 :       DEALLOCATE (eigenval)
     820            4 :       DEALLOCATE (ind)
     821            8 :       DO i = 1, nrep
     822          716 :          ms_vib%delta_vec(:, i) = ms_vib%b_vec(:, i)/mass(:)
     823              :       END DO
     824              : 
     825            4 :    END SUBROUTINE rest_guess
     826              : 
     827              : ! **************************************************************************************************
     828              : !> \brief ...
     829              : !> \param ms_vib_section ...
     830              : !> \param input ...
     831              : !> \param para_env ...
     832              : !> \param ms_vib ...
     833              : !> \param mass ...
     834              : !> \param ncoord ...
     835              : !> \param nrep ...
     836              : !> \param logger ...
     837              : !> \author Florian Schiffmann 11.2007
     838              : ! **************************************************************************************************
     839            4 :    SUBROUTINE molden_guess(ms_vib_section, input, para_env, ms_vib, mass, ncoord, nrep, logger)
     840              :       TYPE(section_vals_type), POINTER                   :: ms_vib_section, input
     841              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     842              :       TYPE(ms_vib_type)                                  :: ms_vib
     843              :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     844              :       INTEGER                                            :: ncoord, nrep
     845              :       TYPE(cp_logger_type), POINTER                      :: logger
     846              : 
     847              :       CHARACTER(LEN=2)                                   :: at_name
     848              :       CHARACTER(LEN=default_path_length)                 :: ms_filename
     849              :       CHARACTER(LEN=max_line_length)                     :: info
     850              :       INTEGER                                            :: i, istat, iw, j, jj, k, nvibs, &
     851              :                                                             output_molden, output_unit, stat
     852            4 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
     853              :       LOGICAL                                            :: reading_vib
     854              :       REAL(KIND=dp)                                      :: my_val, norm
     855            4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: freq, tmp
     856            4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: modes
     857            8 :       REAL(KIND=dp), DIMENSION(3, ncoord/3)              :: pos
     858              : 
     859            8 :       output_unit = cp_logger_get_default_io_unit(logger)
     860              : 
     861            4 :       CALL section_vals_val_get(ms_vib_section, "RESTART_FILE_NAME", c_val=ms_filename)
     862            4 :       IF (ms_filename == "") output_molden = &
     863              :          cp_print_key_unit_nr(logger, input, "VIBRATIONAL_ANALYSIS%PRINT%MOLDEN_VIB", &
     864              :                               extension=".mol", file_status='UNKNOWN', &
     865            0 :                               file_action="READ")
     866            4 :       IF (para_env%is_source()) THEN
     867              : 
     868            2 :          IF (ms_filename == "") THEN
     869            0 :             iw = output_molden
     870              :          ELSE
     871              :             CALL open_file(file_name=TRIM(ms_filename), &
     872              :                            file_status="UNKNOWN", &
     873              :                            file_form="FORMATTED", &
     874              :                            file_action="READ", &
     875            2 :                            unit_number=iw)
     876              :          END IF
     877            2 :          info = ""
     878            2 :          READ (iw, *) info
     879            2 :          READ (iw, *) info
     880            2 :          istat = 0
     881            2 :          nvibs = 0
     882            2 :          reading_vib = .FALSE.
     883          140 :          DO
     884          142 :             READ (iw, *, IOSTAT=stat) info
     885          142 :             istat = istat + stat
     886          142 :             IF (TRIM(ADJUSTL(info)) == "[FR-COORD]") EXIT
     887              : 
     888          140 :             CPASSERT(stat == 0)
     889              : 
     890          140 :             IF (reading_vib) nvibs = nvibs + 1
     891          140 :             IF (TRIM(ADJUSTL(info)) == "[FREQ]") reading_vib = .TRUE.
     892              :          END DO
     893            2 :          REWIND (iw)
     894            2 :          istat = 0
     895            2 :          READ (iw, *, IOSTAT=stat) info
     896            2 :          istat = istat + stat
     897            2 :          READ (iw, *, IOSTAT=stat) info
     898            2 :          istat = istat + stat
     899              :          ! Skip [Atoms] section
     900          118 :          DO
     901          120 :             READ (iw, *, IOSTAT=stat) info
     902          120 :             istat = istat + stat
     903          120 :             CPASSERT(stat == 0)
     904          120 :             IF (TRIM(ADJUSTL(info)) == "[FREQ]") EXIT
     905              :          END DO
     906              :          ! Read frequencies and modes
     907            6 :          ALLOCATE (freq(nvibs))
     908            8 :          ALLOCATE (modes(ncoord, nvibs))
     909              : 
     910           22 :          DO i = 1, nvibs
     911           20 :             READ (iw, *, IOSTAT=stat) freq(i)
     912           22 :             istat = istat + stat
     913              :          END DO
     914            2 :          READ (iw, *) info
     915          120 :          DO i = 1, ncoord/3
     916          118 :             READ (iw, *, IOSTAT=stat) at_name, pos(:, i)
     917          120 :             istat = istat + stat
     918              :          END DO
     919            2 :          READ (iw, *) info
     920           22 :          DO i = 1, nvibs
     921           20 :             READ (iw, *) info
     922           20 :             istat = istat + stat
     923         1202 :             DO j = 1, ncoord/3
     924         1180 :                k = (j - 1)*3 + 1
     925         1180 :                READ (iw, *, IOSTAT=stat) modes(k:k + 2, i)
     926         1200 :                istat = istat + stat
     927              :             END DO
     928              :          END DO
     929            2 :          IF (ms_filename /= "") CALL close_file(iw)
     930            2 :          IF (output_unit > 0) THEN
     931            2 :             IF (istat /= 0) THEN
     932            0 :                WRITE (output_unit, FMT="(/,T2,A)") "**  Error while reading MOLDEN file **"
     933              :             ELSE
     934            2 :                WRITE (output_unit, FMT="(/,T2,A)") "*** MOLDEN file has been read successfully ***"
     935              :             END IF
     936              :          END IF
     937              :          !!!!!!!    select modes     !!!!!!
     938            4 :          ALLOCATE (tmp(nvibs))
     939            2 :          tmp(:) = 0.0_dp
     940            6 :          ALLOCATE (tmplist(nvibs))
     941            2 :          IF (ms_vib%select_id == 1) my_val = ms_vib%sel_freq
     942            2 :          IF (ms_vib%select_id == 2) my_val = (ms_vib%f_range(2) + ms_vib%f_range(1))*0.5_dp
     943            2 :          IF (ms_vib%select_id == 1 .OR. ms_vib%select_id == 2) THEN
     944           11 :             DO i = 1, nvibs
     945           11 :                tmp(i) = ABS(my_val - freq(i))
     946              :             END DO
     947            1 :          ELSE IF (ms_vib%select_id == 3) THEN
     948           11 :             DO i = 1, nvibs
     949           30 :                DO j = 1, SIZE(ms_vib%inv_atoms)
     950           90 :                   DO k = 1, 3
     951           60 :                      jj = (ms_vib%inv_atoms(j) - 1)*3 + k
     952           80 :                      tmp(i) = tmp(i) + SQRT(modes(jj, i)**2)
     953              :                   END DO
     954              :                END DO
     955           11 :                IF (freq(i) <= 400._dp) tmp(i) = 0._dp
     956              :             END DO
     957           11 :             tmp(:) = -tmp(:)
     958              :          END IF
     959            2 :          CALL sort(tmp, nvibs, tmplist)
     960            4 :          DO i = 1, nrep
     961          356 :             ms_vib%b_vec(:, i) = modes(:, tmplist(i))*mass(:)
     962          356 :             norm = NORM2(ms_vib%b_vec(:, i))
     963          358 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/norm
     964              :          END DO
     965            4 :          DO i = 1, nrep
     966          358 :             ms_vib%delta_vec(:, i) = ms_vib%b_vec(:, i)/mass(:)
     967              :          END DO
     968              : 
     969            2 :          DEALLOCATE (freq)
     970            2 :          DEALLOCATE (modes)
     971            2 :          DEALLOCATE (tmp)
     972            2 :          DEALLOCATE (tmplist)
     973              : 
     974              :       END IF
     975         1428 :       CALL para_env%bcast(ms_vib%b_vec)
     976         1428 :       CALL para_env%bcast(ms_vib%delta_vec)
     977              : 
     978            4 :       IF (ms_filename == "") CALL cp_print_key_finished_output(output_molden, logger, input, &
     979            0 :                                                                "VIBRATIONAL_ANALYSIS%PRINT%MOLDEN_VIB")
     980            4 :    END SUBROUTINE molden_guess
     981              : 
     982              : ! **************************************************************************************************
     983              : !> \brief Davidson algorithm for to generate a approximate Hessian for mode
     984              : !>      selective vibrational analysis
     985              : !> \param rep_env ...
     986              : !> \param ms_vib ...
     987              : !> \param input ...
     988              : !> \param nrep ...
     989              : !> \param particles ...
     990              : !> \param mass ...
     991              : !> \param converged ...
     992              : !> \param dx ...
     993              : !> \param calc_intens ...
     994              : !> \param output_unit_ms ...
     995              : !> \param logger ...
     996              : !> \param cell simulation cell
     997              : !> \author Florian Schiffmann 11.2007
     998              : ! **************************************************************************************************
     999          186 :    SUBROUTINE evaluate_H_update_b(rep_env, ms_vib, input, nrep, &
    1000              :                                   particles, &
    1001          186 :                                   mass, &
    1002              :                                   converged, dx, &
    1003              :                                   calc_intens, output_unit_ms, logger, cell)
    1004              :       TYPE(replica_env_type), POINTER                    :: rep_env
    1005              :       TYPE(ms_vib_type)                                  :: ms_vib
    1006              :       TYPE(section_vals_type), POINTER                   :: input
    1007              :       INTEGER                                            :: nrep
    1008              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
    1009              :       REAL(Kind=dp), DIMENSION(:)                        :: mass
    1010              :       LOGICAL                                            :: converged
    1011              :       REAL(KIND=dp)                                      :: dx
    1012              :       LOGICAL                                            :: calc_intens
    1013              :       INTEGER                                            :: output_unit_ms
    1014              :       TYPE(cp_logger_type), POINTER                      :: logger
    1015              :       TYPE(cell_type), POINTER                           :: cell
    1016              : 
    1017              :       INTEGER                                            :: i, j, jj, k, natoms, ncoord
    1018          186 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ind
    1019              :       LOGICAL                                            :: dump_only_positive
    1020          186 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval, freq
    1021          186 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: approx_H, H_save, residuum, tmp_b, tmp_s
    1022          372 :       REAL(KIND=dp), DIMENSION(2, nrep)                  :: criteria
    1023          186 :       REAL(Kind=dp), DIMENSION(:), POINTER               :: intensities
    1024              : 
    1025          186 :       natoms = SIZE(particles)
    1026          186 :       ncoord = 3*natoms
    1027          186 :       nrep = SIZE(rep_env%f, 2)
    1028              : 
    1029              :       !!!!!!!!   reallocate and update the davidson matrices   !!!!!!!!!!
    1030          186 :       IF (ms_vib%mat_size /= 0) THEN
    1031              : 
    1032          790 :          ALLOCATE (tmp_b(3*natoms, ms_vib%mat_size))
    1033          474 :          ALLOCATE (tmp_s(3*natoms, ms_vib%mat_size))
    1034              : 
    1035       167174 :          tmp_b(:, :) = ms_vib%b_mat
    1036       167174 :          tmp_s(:, :) = ms_vib%s_mat
    1037              : 
    1038          158 :          DEALLOCATE (ms_vib%b_mat)
    1039          158 :          DEALLOCATE (ms_vib%s_mat)
    1040              :       END IF
    1041              : 
    1042          930 :       ALLOCATE (ms_vib%b_mat(3*natoms, ms_vib%mat_size + nrep))
    1043          558 :       ALLOCATE (ms_vib%s_mat(3*natoms, ms_vib%mat_size + nrep))
    1044              : 
    1045       193968 :       ms_vib%s_mat = 0.0_dp
    1046              : 
    1047        26646 :       DO i = 1, 3*natoms
    1048        26460 :          IF (ms_vib%mat_size /= 0) THEN
    1049       189354 :             DO j = 1, ms_vib%mat_size
    1050       166014 :                ms_vib%b_mat(i, j) = tmp_b(i, j)
    1051       189354 :                ms_vib%s_mat(i, j) = tmp_s(i, j)
    1052              :             END DO
    1053              :          END IF
    1054        53214 :          DO j = 1, nrep
    1055        53028 :             ms_vib%b_mat(i, ms_vib%mat_size + j) = ms_vib%b_vec(i, j)
    1056              :          END DO
    1057              :       END DO
    1058              : 
    1059          186 :       IF (ms_vib%mat_size /= 0) THEN
    1060          158 :          DEALLOCATE (tmp_s)
    1061          158 :          DEALLOCATE (tmp_b)
    1062              :       END IF
    1063              : 
    1064          186 :       ms_vib%mat_size = ms_vib%mat_size + nrep
    1065              : 
    1066          744 :       ALLOCATE (approx_H(ms_vib%mat_size, ms_vib%mat_size))
    1067          558 :       ALLOCATE (H_save(ms_vib%mat_size, ms_vib%mat_size))
    1068          558 :       ALLOCATE (eigenval(ms_vib%mat_size))
    1069              : 
    1070              :       !!!!!!!!!!!!  calculate the new derivativ and the approximate hessian
    1071              : 
    1072          384 :       DO i = 1, nrep
    1073        26952 :          DO j = 1, 3*natoms
    1074        26766 :             ms_vib%s_mat(j, ms_vib%mat_size - nrep + i) = -(ms_vib%ms_force(j, i) - rep_env%f(j, i))/(2*ms_vib%step_b(i)*mass(j))
    1075              :          END DO
    1076              :       END DO
    1077              : 
    1078              :       CALL dgemm('T', 'N', ms_vib%mat_size, ms_vib%mat_size, SIZE(ms_vib%s_mat, 1), 1._dp, ms_vib%b_mat, SIZE(ms_vib%b_mat, 1), &
    1079          186 :                  ms_vib%s_mat, SIZE(ms_vib%s_mat, 1), 0._dp, approx_H, ms_vib%mat_size)
    1080        14730 :       H_save(:, :) = approx_H
    1081              : 
    1082          186 :       CALL diamat_all(approx_H, eigenval)
    1083              : 
    1084              :       !!!!!!!!!!!! select eigenvalue(s) and vector(s) and calculate the new displacement vector
    1085          558 :       ALLOCATE (ind(ms_vib%mat_size))
    1086          744 :       ALLOCATE (residuum(SIZE(ms_vib%s_mat, 1), nrep))
    1087              : 
    1088          186 :       CALL select_vector(ms_vib, nrep, mass, ncoord, approx_H, eigenval, ind, residuum, criteria)
    1089              : 
    1090          384 :       DO i = 1, nrep
    1091         9240 :          DO j = 1, natoms
    1092        35622 :             DO k = 1, 3
    1093        26568 :                jj = (j - 1)*3 + k
    1094        35424 :                ms_vib%delta_vec(jj, i) = ms_vib%b_vec(jj, i)/mass(jj)
    1095              :             END DO
    1096              :          END DO
    1097              :       END DO
    1098              : 
    1099          384 :       DO i = 1, nrep
    1100        26766 :          ms_vib%step_r(i) = dx/NORM2(ms_vib%delta_vec(:, i))
    1101        26952 :          ms_vib%step_b(i) = NORM2(ms_vib%step_r(i)*ms_vib%b_vec(:, i))
    1102              :       END DO
    1103          186 :       converged = .FALSE.
    1104              :       IF (MAXVAL(criteria(1, :)) <= ms_vib%eps(1) .AND. MAXVAL(criteria(2, :)) &
    1105          582 :           <= ms_vib%eps(2) .OR. ms_vib%mat_size >= ncoord) converged = .TRUE.
    1106          558 :       ALLOCATE (freq(nrep))
    1107          384 :       DO i = 1, nrep
    1108          384 :          freq(i) = SQRT(ABS(eigenval(ind(i)))*massunit)*vibfac
    1109              :       END DO
    1110              : 
    1111              :       !!!   write information and output   !!!
    1112          186 :       IF (converged) THEN
    1113          226 :          eigenval(:) = SIGN(1._dp, eigenval(:))*SQRT(ABS(eigenval(:))*massunit)*vibfac
    1114          112 :          ALLOCATE (tmp_b(ncoord, ms_vib%mat_size))
    1115           28 :          tmp_b = 0._dp
    1116           84 :          ALLOCATE (tmp_s(3, ms_vib%mat_size))
    1117           28 :          tmp_s = 0._dp
    1118           28 :          IF (calc_intens) THEN
    1119           66 :             ALLOCATE (intensities(ms_vib%mat_size))
    1120          190 :             intensities = 0._dp
    1121              :          END IF
    1122          226 :          DO i = 1, ms_vib%mat_size
    1123         2472 :             DO j = 1, ms_vib%mat_size
    1124       361716 :                tmp_b(:, i) = tmp_b(:, i) + approx_H(j, i)*ms_vib%b_mat(:, j)/mass(:)
    1125              :             END DO
    1126        53362 :             tmp_b(:, i) = tmp_b(:, i)/NORM2(tmp_b(:, i))
    1127              :          END DO
    1128           28 :          IF (calc_intens) THEN
    1129          190 :             DO i = 1, ms_vib%mat_size
    1130         2280 :                DO j = 1, ms_vib%mat_size
    1131         8616 :                   tmp_s(:, i) = tmp_s(:, i) + ms_vib%dip_deriv(:, j)*approx_H(j, i)
    1132              :                END DO
    1133          694 :                IF (calc_intens) intensities(i) = NORM2(tmp_s(:, i))
    1134              :             END DO
    1135              :          END IF
    1136           28 :          IF (calc_intens) THEN
    1137              :             CALL ms_out(output_unit_ms, converged, freq, criteria, ms_vib, &
    1138              :                         input, nrep, approx_H, eigenval, calc_intens, &
    1139           22 :                         intensities=intensities, logger=logger)
    1140              :          ELSE
    1141              :             CALL ms_out(output_unit_ms, converged, freq, criteria, ms_vib, &
    1142            6 :                         input, nrep, approx_H, eigenval, calc_intens, logger=logger)
    1143              :          END IF
    1144           28 :          dump_only_positive = ms_vib%low_freq > 0.0_dp
    1145              :          CALL write_vibrations_molden(input, particles, eigenval, tmp_b, intensities, calc_intens, &
    1146           28 :                                       dump_only_positive=dump_only_positive, logger=logger, cell=cell)
    1147           28 :          IF (calc_intens) THEN
    1148           22 :             DEALLOCATE (intensities)
    1149              :          END IF
    1150           28 :          DEALLOCATE (tmp_b)
    1151           28 :          DEALLOCATE (tmp_s)
    1152              :       END IF
    1153              : 
    1154          186 :       IF (.NOT. converged) CALL ms_out(output_unit_ms, converged, freq, criteria, &
    1155          158 :                                        ms_vib, input, nrep, approx_H, eigenval, calc_intens, logger=logger)
    1156              : 
    1157          186 :       DEALLOCATE (freq)
    1158          186 :       DEALLOCATE (approx_H)
    1159          186 :       DEALLOCATE (eigenval)
    1160          186 :       DEALLOCATE (residuum)
    1161          186 :       DEALLOCATE (ind)
    1162              : 
    1163          372 :    END SUBROUTINE evaluate_H_update_b
    1164              : 
    1165              : ! **************************************************************************************************
    1166              : !> \brief writes the output for a mode tracking calculation
    1167              : !> \param ms_vib ...
    1168              : !> \param nrep ...
    1169              : !> \param mass ...
    1170              : !> \param ncoord ...
    1171              : !> \param approx_H ...
    1172              : !> \param eigenval ...
    1173              : !> \param ind ...
    1174              : !> \param residuum ...
    1175              : !> \param criteria ...
    1176              : !> \author Florian Schiffmann 11.2007
    1177              : ! **************************************************************************************************
    1178          190 :    SUBROUTINE select_vector(ms_vib, nrep, mass, ncoord, approx_H, eigenval, ind, residuum, criteria)
    1179              : 
    1180              :       TYPE(ms_vib_type)                                  :: ms_vib
    1181              :       INTEGER                                            :: nrep
    1182              :       REAL(Kind=dp), DIMENSION(:)                        :: mass
    1183              :       INTEGER                                            :: ncoord
    1184              :       REAL(KIND=dp), DIMENSION(:, :)                     :: approx_H
    1185              :       REAL(Kind=dp), DIMENSION(:)                        :: eigenval
    1186              :       INTEGER, DIMENSION(:)                              :: ind
    1187              :       REAL(KIND=dp), DIMENSION(:, :)                     :: residuum
    1188              :       REAL(KIND=dp), DIMENSION(2, nrep), OPTIONAL        :: criteria
    1189              : 
    1190              :       INTEGER                                            :: i, j, jj, k
    1191              :       REAL(KIND=dp)                                      :: my_val, norm
    1192          190 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tmp
    1193          190 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: tmp_b
    1194              : 
    1195          570 :       ALLOCATE (tmp(ms_vib%mat_size))
    1196              : 
    1197          306 :       SELECT CASE (ms_vib%select_id)
    1198              :       CASE (1)
    1199          116 :          my_val = (ms_vib%sel_freq/(vibfac))**2/massunit
    1200         1006 :          DO i = 1, ms_vib%mat_size
    1201         1006 :             tmp(i) = ABS(my_val - eigenval(i))
    1202              :          END DO
    1203          116 :          CALL sort(tmp, (ms_vib%mat_size), ind)
    1204        15892 :          residuum = 0._dp
    1205          238 :          DO j = 1, nrep
    1206         1152 :             DO i = 1, ms_vib%mat_size
    1207       144040 :                residuum(:, j) = residuum(:, j) + approx_H(i, ind(j))*(ms_vib%s_mat(:, i) - eigenval(ind(j))*ms_vib%b_mat(:, i))
    1208              :             END DO
    1209              :          END DO
    1210              :       CASE (2)
    1211            6 :          CALL get_vibs_in_range(ms_vib, approx_H, eigenval, residuum, nrep, ind)
    1212              :       CASE (3)
    1213              : 
    1214          272 :          ALLOCATE (tmp_b(ncoord, ms_vib%mat_size))
    1215           68 :          tmp_b = 0._dp
    1216              : 
    1217          392 :          DO i = 1, ms_vib%mat_size
    1218         2428 :             DO j = 1, ms_vib%mat_size
    1219       372400 :                tmp_b(:, i) = tmp_b(:, i) + approx_H(j, i)*ms_vib%b_mat(:, j)/mass(:)
    1220              :             END DO
    1221       113000 :             tmp_b(:, i) = tmp_b(:, i)/NORM2(tmp_b(:, i))
    1222              :          END DO
    1223           68 :          tmp = 0._dp
    1224          392 :          DO i = 1, ms_vib%mat_size
    1225          972 :             DO j = 1, SIZE(ms_vib%inv_atoms)
    1226         2916 :                DO k = 1, 3
    1227         1944 :                   jj = (ms_vib%inv_atoms(j) - 1)*3 + k
    1228         2592 :                   tmp(i) = tmp(i) + SQRT(tmp_b(jj, i)**2)
    1229              :                END DO
    1230              :             END DO
    1231          392 :             IF (.NOT. ASSOCIATED(ms_vib%inv_range)) THEN
    1232          324 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) <= 400._dp) tmp(i) = 0._dp
    1233              :             ELSE
    1234            0 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) <= ms_vib%inv_range(1)) tmp(i) = 0._dp
    1235            0 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) >= ms_vib%inv_range(2)) tmp(i) = 0._dp
    1236              :             END IF
    1237              :          END DO
    1238          392 :          tmp(:) = -tmp(:)
    1239           68 :          CALL sort(tmp, (ms_vib%mat_size), ind)
    1240        11650 :          residuum(:, :) = 0._dp
    1241              : 
    1242          136 :          DO j = 1, nrep
    1243          460 :             DO i = 1, ms_vib%mat_size
    1244        56696 :                residuum(:, j) = residuum(:, j) + approx_H(i, ind(j))*(ms_vib%s_mat(:, i) - eigenval(ind(j))*ms_vib%b_mat(:, i))
    1245              :             END DO
    1246              :          END DO
    1247          258 :          DEALLOCATE (tmp_b)
    1248              :       END SELECT
    1249              : 
    1250          392 :       DO j = 1, nrep
    1251         1678 :          DO i = 1, ms_vib%mat_size
    1252       400968 :             residuum(:, j) = residuum(:, j) - DOT_PRODUCT(residuum(:, j), ms_vib%b_mat(:, i))*ms_vib%b_mat(:, i)
    1253              :          END DO
    1254              :       END DO
    1255          190 :       IF (PRESENT(criteria)) THEN
    1256          384 :          DO i = 1, nrep
    1257        26766 :             criteria(1, i) = MAXVAL((residuum(:, i)))
    1258        26952 :             criteria(2, i) = NORM2(residuum(:, i))
    1259              :          END DO
    1260              :       END IF
    1261              : 
    1262          392 :       DO i = 1, nrep
    1263        27478 :          norm = NORM2(residuum(:, i))
    1264        27668 :          residuum(:, i) = residuum(:, i)/norm
    1265              :       END DO
    1266              : 
    1267         2090 :       DO k = 1, 10
    1268         4110 :          DO j = 1, nrep
    1269        14880 :             DO i = 1, ms_vib%mat_size
    1270      4007660 :                residuum(:, j) = residuum(:, j) - DOT_PRODUCT(residuum(:, j), ms_vib%b_mat(:, i))*ms_vib%b_mat(:, i)
    1271      4009680 :                residuum(:, j) = residuum(:, j)/NORM2(residuum(:, j))
    1272              :             END DO
    1273         3920 :             IF (nrep > 1) THEN
    1274          720 :                DO i = 1, nrep
    1275          720 :                   IF (i /= j) THEN
    1276         4560 :                      residuum(:, j) = residuum(:, j) - DOT_PRODUCT(residuum(:, j), residuum(:, i))*residuum(:, i)
    1277         4560 :                      residuum(:, j) = residuum(:, j)/NORM2(residuum(:, j))
    1278              :                   END IF
    1279              :                END DO
    1280              :             END IF
    1281              :          END DO
    1282              :       END DO
    1283        27668 :       ms_vib%b_vec = residuum
    1284          190 :       DEALLOCATE (tmp)
    1285          190 :    END SUBROUTINE select_vector
    1286              : 
    1287              : ! **************************************************************************************************
    1288              : !> \brief writes the output for a mode tracking calculation
    1289              : !> \param iw ...
    1290              : !> \param converged ...
    1291              : !> \param freq ...
    1292              : !> \param criter ...
    1293              : !> \param ms_vib ...
    1294              : !> \param input ...
    1295              : !> \param nrep ...
    1296              : !> \param approx_H ...
    1297              : !> \param eigenval ...
    1298              : !> \param calc_intens ...
    1299              : !> \param intensities ...
    1300              : !> \param logger ...
    1301              : !> \author Florian Schiffmann 11.2007
    1302              : ! **************************************************************************************************
    1303          186 :    SUBROUTINE ms_out(iw, converged, freq, criter, ms_vib, input, nrep, &
    1304          186 :                      approx_H, eigenval, calc_intens, intensities, logger)
    1305              : 
    1306              :       INTEGER                                            :: iw
    1307              :       LOGICAL                                            :: converged
    1308              :       REAL(KIND=dp), DIMENSION(:)                        :: freq
    1309              :       REAL(KIND=dp), DIMENSION(:, :)                     :: criter
    1310              :       TYPE(ms_vib_type)                                  :: ms_vib
    1311              :       TYPE(section_vals_type), POINTER                   :: input
    1312              :       INTEGER                                            :: nrep
    1313              :       REAL(KIND=dp), DIMENSION(:, :)                     :: approx_H
    1314              :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
    1315              :       LOGICAL                                            :: calc_intens
    1316              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: intensities
    1317              :       TYPE(cp_logger_type), POINTER                      :: logger
    1318              : 
    1319              :       REAL(KIND=dp), PARAMETER                           :: eps_criter1 = 1.0E-07_dp, &
    1320              :                                                             eps_criter2 = 1.0E-06_dp
    1321              : 
    1322              :       INTEGER                                            :: i, j, msunit
    1323              :       REAL(KIND=dp)                                      :: crit_a, crit_b, fint, gintval
    1324          186 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: residuum
    1325              :       TYPE(section_vals_type), POINTER                   :: ms_vib_section
    1326              : 
    1327              :       ms_vib_section => section_vals_get_subs_vals(input, &
    1328          186 :                                                    "VIBRATIONAL_ANALYSIS%MODE_SELECTIVE")
    1329              : 
    1330          186 :       fint = 42.255_dp*massunit*debye**2*bohr**2
    1331              : 
    1332          186 :       IF (converged) THEN
    1333           28 :          IF (iw > 0) THEN
    1334           14 :             WRITE (iw, '(T2,A)') "MS| DAVIDSON ALGORITHM CONVERGED"
    1335           30 :             DO i = 1, nrep
    1336           30 :                WRITE (iw, '(T2,"MS| TRACKED FREQUENCY (",I0,") IS:",F12.6,3X,A)') i, freq(i), 'cm-1'
    1337              :             END DO
    1338           42 :             ALLOCATE (residuum(SIZE(ms_vib%b_mat, 1)))
    1339           14 :             WRITE (iw, '( /, 1X, 79("-") )')
    1340           14 :             WRITE (iw, '( 25X, A)') 'FREQUENCY AND CONVERGENCE LIST'
    1341           14 :             IF (PRESENT(intensities)) THEN
    1342           11 :                WRITE (iw, '(3X,5(4X, A))') 'FREQUENCY', 'INT[KM/Mole]', 'MAXVAL CRITERIA', 'NORM CRITERIA', 'CONVERGENCE'
    1343              :             ELSE
    1344            3 :                WRITE (iw, '(3X,5(4X, A))') 'FREQUENCY', 'MAXVAL CRITERIA', 'NORM CRITERIA', 'CONVERGENCE'
    1345              :             END IF
    1346          113 :             DO i = 1, SIZE(ms_vib%b_mat, 2)
    1347           99 :                residuum = 0._dp
    1348         1236 :                DO j = 1, SIZE(ms_vib%b_mat, 2)
    1349       180858 :                   residuum(:) = residuum(:) + approx_H(j, i)*(ms_vib%s_mat(:, j) - eigenval(i)*ms_vib%b_mat(:, j))
    1350              :                END DO
    1351         1236 :                DO j = 1, ms_vib%mat_size
    1352       360480 :                   residuum(:) = residuum(:) - DOT_PRODUCT(residuum(:), ms_vib%b_mat(:, j))*ms_vib%b_mat(:, j)
    1353              :                END DO
    1354        13383 :                crit_a = MAXVAL(residuum(:))
    1355        13383 :                crit_b = NORM2(residuum)
    1356          113 :                IF (PRESENT(intensities)) THEN
    1357           84 :                   gintval = fint*intensities(i)**2
    1358           84 :                   IF (crit_a <= ms_vib%eps(1) .AND. crit_b <= ms_vib%eps(2)) THEN
    1359           30 :                      IF (eigenval(i) > ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,1X,F12.6,3X,E12.3,7X,E12.3,11X,A)') &
    1360           28 :                         'VIB|', eigenval(i), gintval, crit_a, crit_b, 'YES'
    1361              :                   ELSE
    1362           54 :                      IF (eigenval(i) > ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,1X,F12.6,3X,E12.3,7X,E12.3,11X,A)') &
    1363           54 :                         'VIB|', eigenval(i), gintval, crit_a, crit_b, 'NO'
    1364              :                   END IF
    1365              :                ELSE
    1366           15 :                   IF (crit_a <= ms_vib%eps(1) .AND. crit_b <= ms_vib%eps(2)) THEN
    1367           14 :                      IF (eigenval(i) > ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,5X,E12.6,5X,E12.3,11X,A)') &
    1368            8 :                         'VIB|', eigenval(i), crit_a, crit_b, 'YES'
    1369              :                   ELSE
    1370            1 :                      IF (eigenval(i) > ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,5X,E12.6,5X,E12.3,11X,A)') &
    1371            1 :                         'VIB|', eigenval(i), crit_a, crit_b, 'NO'
    1372              :                   END IF
    1373              :                END IF
    1374              :             END DO
    1375           14 :             DEALLOCATE (residuum)
    1376              : 
    1377              :             msunit = cp_print_key_unit_nr(logger, ms_vib_section, &
    1378              :                                           "PRINT%MS_RESTART", extension=".bin", middle_name="MS_RESTART", &
    1379              :                                           file_status="REPLACE", file_form="UNFORMATTED", &
    1380           14 :                                           file_action="WRITE")
    1381              : 
    1382           14 :             IF (msunit > 0) THEN
    1383           14 :                WRITE (UNIT=msunit) ms_vib%mat_size
    1384        13397 :                WRITE (UNIT=msunit) ms_vib%b_mat
    1385        13397 :                WRITE (UNIT=msunit) ms_vib%s_mat
    1386          350 :                IF (calc_intens) WRITE (UNIT=msunit) ms_vib%dip_deriv
    1387              :             END IF
    1388              : 
    1389              :             CALL cp_print_key_finished_output(msunit, logger, ms_vib_section, &
    1390           14 :                                               "PRINT%MS_RESTART")
    1391              :          END IF
    1392              :       ELSE
    1393          158 :          IF (iw > 0) THEN
    1394              :             msunit = cp_print_key_unit_nr(logger, ms_vib_section, &
    1395              :                                           "PRINT%MS_RESTART", extension=".bin", middle_name="MS_RESTART", &
    1396              :                                           file_status="REPLACE", file_form="UNFORMATTED", &
    1397           79 :                                           file_action="WRITE")
    1398              : 
    1399           79 :             IF (msunit > 0) THEN
    1400           79 :                WRITE (UNIT=msunit) ms_vib%mat_size
    1401        83587 :                WRITE (UNIT=msunit) ms_vib%b_mat
    1402        83587 :                WRITE (UNIT=msunit) ms_vib%s_mat
    1403         2023 :                IF (calc_intens) WRITE (UNIT=msunit) ms_vib%dip_deriv
    1404              :             END IF
    1405              : 
    1406              :             CALL cp_print_key_finished_output(msunit, logger, ms_vib_section, &
    1407           79 :                                               "PRINT%MS_RESTART")
    1408              : 
    1409           79 :             WRITE (iw, '(T2,A,3X,I6)') "MS| ITERATION STEP", ms_vib%mat_size/nrep
    1410          162 :             DO i = 1, nrep
    1411          162 :                IF (criter(1, i) <= eps_criter1 .AND. (criter(2, i)) <= eps_criter2) THEN
    1412            1 :                   WRITE (iw, '(T2,A,3X,F12.6,A)') "MS| TRACKED MODE ", freq(i), "cm-1  IS  CONVERGED"
    1413              :                ELSE
    1414           82 :                   WRITE (iw, '(T2,A,3X,F12.6,A)') "MS| TRACKED MODE ", freq(i), "cm-1  NOT  CONVERGED"
    1415              :                END IF
    1416              :             END DO
    1417              :          END IF
    1418              :       END IF
    1419              : 
    1420          186 :    END SUBROUTINE ms_out
    1421              : 
    1422              : ! **************************************************************************************************
    1423              : !> \brief ...
    1424              : !> \param ms_vib ...
    1425              : !> \param approx_H ...
    1426              : !> \param eigenval ...
    1427              : !> \param residuum ...
    1428              : !> \param nrep ...
    1429              : !> \param ind ...
    1430              : !> \author Florian Schiffmann 11.2007
    1431              : ! **************************************************************************************************
    1432            6 :    SUBROUTINE get_vibs_in_range(ms_vib, approx_H, eigenval, residuum, nrep, ind)
    1433              : 
    1434              :       TYPE(ms_vib_type)                                  :: ms_vib
    1435              :       REAL(KIND=dp), DIMENSION(:, :)                     :: approx_H
    1436              :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
    1437              :       REAL(KIND=dp), DIMENSION(:, :)                     :: residuum
    1438              :       INTEGER                                            :: nrep
    1439              :       INTEGER, DIMENSION(:)                              :: ind
    1440              : 
    1441              :       INTEGER                                            :: count1, count2, i, j
    1442            6 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: map2
    1443            6 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: map1
    1444            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tmp, tmp1
    1445            6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: tmp_resid
    1446              :       REAL(KIND=dp), DIMENSION(2)                        :: myrange
    1447              : 
    1448           18 :       myrange(:) = (ms_vib%f_range(:)/(vibfac))**2/massunit
    1449            6 :       count1 = 0
    1450            6 :       count2 = 0
    1451          126 :       residuum = 0.0_dp
    1452            6 :       ms_vib%mat_size = SIZE(ms_vib%b_mat, 2)
    1453           18 :       ALLOCATE (map1(SIZE(eigenval), 2))
    1454           18 :       ALLOCATE (tmp(SIZE(eigenval)))
    1455           30 :       DO i = 1, SIZE(eigenval)
    1456           24 :          IF (ABS(eigenval(i) - myrange(1)) + ABS(eigenval(i) - myrange(2)) <= &
    1457            6 :              ABS(myrange(1) - myrange(2)) + myrange(1)*0.001_dp) THEN
    1458            0 :             count1 = count1 + 1
    1459            0 :             map1(count1, 1) = i
    1460              :          ELSE
    1461           24 :             count2 = count2 + 1
    1462           24 :             map1(count2, 2) = i
    1463           24 :             tmp(count2) = MIN(ABS(eigenval(i) - myrange(1)), ABS(eigenval(i) - myrange(2)))
    1464              :          END IF
    1465              :       END DO
    1466              : 
    1467            6 :       IF (count1 == nrep) THEN
    1468            0 :          DO j = 1, count1
    1469            0 :             DO i = 1, ms_vib%mat_size
    1470            0 :             residuum(:, j) = residuum(:, j) + approx_H(i, map1(j, 1))*(ms_vib%s_mat(:, i) - eigenval(map1(j, 1))*ms_vib%b_mat(:, i))
    1471            0 :                ind(j) = map1(j, 1)
    1472              :             END DO
    1473              :          END DO
    1474            6 :       ELSE IF (count1 > nrep) THEN
    1475            0 :          ALLOCATE (tmp_resid(SIZE(ms_vib%b_mat, 1), count1))
    1476            0 :          ALLOCATE (tmp1(count1))
    1477            0 :          ALLOCATE (map2(count1))
    1478            0 :          tmp_resid = 0._dp
    1479            0 :          DO j = 1, count1
    1480            0 :             DO i = 1, ms_vib%mat_size
    1481              :                tmp_resid(:, j) = tmp_resid(:, j) + approx_H(i, map1(j, 1))* &
    1482            0 :                                  (ms_vib%s_mat(:, i) - eigenval(map1(j, 1))*ms_vib%b_mat(:, i))
    1483              :             END DO
    1484              :          END DO
    1485              : 
    1486            0 :          DO j = 1, count1
    1487            0 :             DO i = 1, ms_vib%mat_size
    1488            0 :                tmp_resid(:, j) = tmp_resid(:, j) - DOT_PRODUCT(tmp_resid(:, j), ms_vib%b_mat(:, i))*ms_vib%b_mat(:, i)
    1489              :             END DO
    1490            0 :             tmp(j) = MAXVAL(tmp_resid(:, j))
    1491              :          END DO
    1492            0 :          CALL sort(tmp, count1, map2)
    1493            0 :          DO j = 1, nrep
    1494            0 :             residuum(:, j) = tmp_resid(:, map2(count1 + 1 - j))
    1495            0 :             ind(j) = map1(map2(count1 + 1 - j), 1)
    1496              :          END DO
    1497            0 :          DEALLOCATE (tmp_resid)
    1498            0 :          DEALLOCATE (tmp1)
    1499            0 :          DEALLOCATE (map2)
    1500            6 :       ELSE IF (count1 < nrep) THEN
    1501              : 
    1502           18 :          ALLOCATE (map2(count2))
    1503            6 :          IF (count1 /= 0) THEN
    1504            0 :             DO j = 1, count1
    1505            0 :                DO i = 1, ms_vib%mat_size
    1506              :                   residuum(:, j) = residuum(:, j) + approx_H(i, map1(j, 1))* &
    1507            0 :                                    (ms_vib%s_mat(:, i) - eigenval(map1(j, 1))*ms_vib%b_mat(:, i))
    1508              :                END DO
    1509            0 :                ind(j) = map1(j, 1)
    1510              :             END DO
    1511              :          END IF
    1512            6 :          CALL sort(tmp, count2, map2)
    1513           18 :          DO j = 1, nrep - count1
    1514           60 :             DO i = 1, ms_vib%mat_size
    1515              :                residuum(:, count1 + j) = residuum(:, count1 + j) + approx_H(i, map1(map2(j), 2)) &
    1516          492 :                                          *(ms_vib%s_mat(:, i) - eigenval(map1(map2(j), 2))*ms_vib%b_mat(:, i))
    1517              :             END DO
    1518           18 :             ind(count1 + j) = map1(map2(j), 2)
    1519              :          END DO
    1520              : 
    1521            6 :          DEALLOCATE (map2)
    1522              :       END IF
    1523              : 
    1524            6 :       DEALLOCATE (map1)
    1525            6 :       DEALLOCATE (tmp)
    1526              : 
    1527            6 :    END SUBROUTINE get_vibs_in_range
    1528            0 : END MODULE mode_selective
        

Generated by: LCOV version 2.0-1