LCOV - code coverage report
Current view: top level - src - mode_selective.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 611 665 91.9 %
Date: 2024-12-21 06:28:57 Functions: 9 10 90.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 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 cp_files,                        ONLY: close_file,&
      22             :                                               open_file
      23             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      24             :                                               cp_logger_get_default_io_unit,&
      25             :                                               cp_logger_type
      26             :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      27             :                                               cp_print_key_unit_nr
      28             :    USE cp_result_methods,               ONLY: get_results
      29             :    USE global_types,                    ONLY: global_environment_type
      30             :    USE input_constants,                 ONLY: ms_guess_atomic,&
      31             :                                               ms_guess_bfgs,&
      32             :                                               ms_guess_molden,&
      33             :                                               ms_guess_restart,&
      34             :                                               ms_guess_restart_vec
      35             :    USE input_section_types,             ONLY: section_vals_get,&
      36             :                                               section_vals_get_subs_vals,&
      37             :                                               section_vals_type,&
      38             :                                               section_vals_val_get
      39             :    USE kinds,                           ONLY: default_path_length,&
      40             :                                               default_string_length,&
      41             :                                               dp,&
      42             :                                               max_line_length
      43             :    USE mathlib,                         ONLY: diamat_all
      44             :    USE message_passing,                 ONLY: mp_para_env_type
      45             :    USE molden_utils,                    ONLY: write_vibrations_molden
      46             :    USE particle_types,                  ONLY: particle_type
      47             :    USE physcon,                         ONLY: bohr,&
      48             :                                               debye,&
      49             :                                               massunit,&
      50             :                                               vibfac
      51             :    USE replica_methods,                 ONLY: rep_env_calc_e_f
      52             :    USE replica_types,                   ONLY: replica_env_type
      53             :    USE util,                            ONLY: sort
      54             : #include "./base/base_uses.f90"
      55             : 
      56             :    IMPLICIT NONE
      57             : 
      58             :    PRIVATE
      59             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mode_selective'
      60             :    LOGICAL, PARAMETER                   :: debug_this_module = .FALSE.
      61             : 
      62             :    TYPE ms_vib_type
      63             :       INTEGER                                  :: mat_size = -1
      64             :       INTEGER                                  :: select_id = -1
      65             :       INTEGER, DIMENSION(:), POINTER           :: inv_atoms => NULL()
      66             :       REAL(KIND=dp)                            :: eps(2) = 0.0_dp
      67             :       REAL(KIND=dp)                            :: sel_freq = 0.0_dp
      68             :       REAL(KIND=dp)                            :: low_freq = 0.0_dp
      69             :       REAL(KIND=dp), POINTER, DIMENSION(:, :)    :: b_vec => NULL()
      70             :       REAL(KIND=dp), POINTER, DIMENSION(:, :)    :: delta_vec => NULL()
      71             :       REAL(KIND=dp), POINTER, DIMENSION(:, :)    :: ms_force => NULL()
      72             :       REAL(KIND=dp), DIMENSION(:), POINTER     :: eig_bfgs => NULL()
      73             :       REAL(KIND=dp), DIMENSION(:), POINTER     :: f_range => NULL()
      74             :       REAL(KIND=dp), DIMENSION(:), POINTER     :: inv_range => NULL()
      75             :       REAL(KIND=dp), POINTER, DIMENSION(:)     :: step_b => NULL()
      76             :       REAL(KIND=dp), POINTER, DIMENSION(:)     :: step_r => NULL()
      77             :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: b_mat => NULL()
      78             :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: dip_deriv => NULL()
      79             :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: hes_bfgs => NULL()
      80             :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: s_mat => NULL()
      81             :       INTEGER                                  :: initial_guess = -1
      82             :    END TYPE ms_vib_type
      83             : 
      84             :    PUBLIC :: ms_vb_anal
      85             : 
      86             : CONTAINS
      87             : ! **************************************************************************************************
      88             : !> \brief Module performing a vibrational analysis
      89             : !> \param input ...
      90             : !> \param rep_env ...
      91             : !> \param para_env ...
      92             : !> \param globenv ...
      93             : !> \param particles ...
      94             : !> \param nrep ...
      95             : !> \param calc_intens ...
      96             : !> \param dx ...
      97             : !> \param output_unit ...
      98             : !> \param logger ...
      99             : !> \author Teodoro Laino 08.2006
     100             : ! **************************************************************************************************
     101          24 :    SUBROUTINE ms_vb_anal(input, rep_env, para_env, globenv, particles, &
     102             :                          nrep, calc_intens, dx, output_unit, logger)
     103             :       TYPE(section_vals_type), POINTER                   :: input
     104             :       TYPE(replica_env_type), POINTER                    :: rep_env
     105             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     106             :       TYPE(global_environment_type), POINTER             :: globenv
     107             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     108             :       INTEGER                                            :: nrep
     109             :       LOGICAL                                            :: calc_intens
     110             :       REAL(KIND=dp)                                      :: dx
     111             :       INTEGER                                            :: output_unit
     112             :       TYPE(cp_logger_type), POINTER                      :: logger
     113             : 
     114             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ms_vb_anal'
     115             : 
     116             :       CHARACTER(LEN=default_string_length)               :: description
     117             :       INTEGER                                            :: handle, i, ip1, j, natoms, ncoord
     118             :       LOGICAL                                            :: converged
     119          24 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: mass, pos0
     120          24 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: tmp_deriv
     121          24 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: tmp_dip
     122             :       TYPE(ms_vib_type)                                  :: ms_vib
     123             : 
     124          24 :       CALL timeset(routineN, handle)
     125          24 :       converged = .FALSE.
     126          24 :       natoms = SIZE(particles)
     127          24 :       ncoord = 3*natoms
     128          96 :       ALLOCATE (mass(3*natoms))
     129         886 :       DO i = 1, natoms
     130        3472 :          DO j = 1, 3
     131        2586 :             mass((i - 1)*3 + j) = particles(i)%atomic_kind%mass
     132        3448 :             mass((i - 1)*3 + j) = SQRT(mass((i - 1)*3 + j))
     133             :          END DO
     134             :       END DO
     135             :       ! Allocate working arrays
     136          96 :       ALLOCATE (ms_vib%delta_vec(ncoord, nrep))
     137          72 :       ALLOCATE (ms_vib%b_vec(ncoord, nrep))
     138          72 :       ALLOCATE (ms_vib%step_r(nrep))
     139          48 :       ALLOCATE (ms_vib%step_b(nrep))
     140          24 :       IF (calc_intens) THEN
     141          20 :          description = '[DIPOLE]'
     142          80 :          ALLOCATE (tmp_dip(nrep, 3, 2))
     143          60 :          ALLOCATE (ms_vib%dip_deriv(3, nrep))
     144             :       END IF
     145             :       CALL MS_initial_moves(para_env, nrep, input, globenv, ms_vib, &
     146             :                             particles, &
     147             :                             mass, &
     148             :                             dx, &
     149          24 :                             calc_intens, logger)
     150          24 :       ncoord = 3*natoms
     151          72 :       ALLOCATE (pos0(ncoord))
     152          96 :       ALLOCATE (ms_vib%ms_force(ncoord, nrep))
     153         886 :       DO i = 1, natoms
     154        3472 :          DO j = 1, 3
     155        3448 :             pos0((i - 1)*3 + j) = particles((i))%r(j)
     156             :          END DO
     157             :       END DO
     158         162 :       ncoord = 3*natoms
     159             :       DO
     160       23178 :          ms_vib%ms_force = HUGE(0.0_dp)
     161         336 :          DO i = 1, nrep
     162       23178 :             DO j = 1, ncoord
     163       23016 :                rep_env%r(j, i) = pos0(j) + ms_vib%step_r(i)*ms_vib%delta_vec(j, i)
     164             :             END DO
     165             :          END DO
     166         162 :          CALL rep_env_calc_e_f(rep_env, calc_f=.TRUE.)
     167             : 
     168         336 :          DO i = 1, nrep
     169         174 :             IF (calc_intens) THEN
     170             :                CALL get_results(results=rep_env%results(i)%results, &
     171             :                                 description=description, &
     172         150 :                                 n_rep=ip1)
     173             :                CALL get_results(results=rep_env%results(i)%results, &
     174             :                                 description=description, &
     175             :                                 values=tmp_dip(i, :, 1), &
     176         150 :                                 nval=ip1)
     177             :             END IF
     178       23178 :             DO j = 1, ncoord
     179       23016 :                ms_vib%ms_force(j, i) = rep_env%f(j, i)
     180             :             END DO
     181             :          END DO
     182         336 :          DO i = 1, nrep
     183       23178 :             DO j = 1, ncoord
     184       23016 :                rep_env%r(j, i) = pos0(j) - ms_vib%step_r(i)*ms_vib%delta_vec(j, i)
     185             :             END DO
     186             :          END DO
     187         162 :          CALL rep_env_calc_e_f(rep_env, calc_f=.TRUE.)
     188         162 :          IF (calc_intens) THEN
     189         300 :             DO i = 1, nrep
     190             :                CALL get_results(results=rep_env%results(i)%results, &
     191             :                                 description=description, &
     192         150 :                                 n_rep=ip1)
     193             :                CALL get_results(results=rep_env%results(i)%results, &
     194             :                                 description=description, &
     195             :                                 values=tmp_dip(i, :, 2), &
     196         150 :                                 nval=ip1)
     197         900 :                ms_vib%dip_deriv(:, ms_vib%mat_size + i) = (tmp_dip(i, :, 1) - tmp_dip(i, :, 2))/(2*ms_vib%step_b(i))
     198             :             END DO
     199             :          END IF
     200             : 
     201             :          CALL evaluate_H_update_b(rep_env, ms_vib, input, nrep, &
     202             :                                   particles, &
     203             :                                   mass, &
     204             :                                   converged, &
     205             :                                   dx, calc_intens, &
     206         162 :                                   output_unit, logger)
     207         162 :          IF (converged) EXIT
     208         162 :          IF (calc_intens) THEN
     209         390 :             ALLOCATE (tmp_deriv(3, ms_vib%mat_size))
     210        3730 :             tmp_deriv = ms_vib%dip_deriv
     211         130 :             DEALLOCATE (ms_vib%dip_deriv)
     212         390 :             ALLOCATE (ms_vib%dip_deriv(3, ms_vib%mat_size + nrep))
     213        3730 :             ms_vib%dip_deriv(:, 1:ms_vib%mat_size) = tmp_deriv(:, 1:ms_vib%mat_size)
     214         130 :             DEALLOCATE (tmp_deriv)
     215             :          END IF
     216             :       END DO
     217          24 :       DEALLOCATE (ms_vib%ms_force)
     218          24 :       DEALLOCATE (pos0)
     219          24 :       DEALLOCATE (ms_vib%step_r)
     220          24 :       DEALLOCATE (ms_vib%step_b)
     221          24 :       DEALLOCATE (ms_vib%b_vec)
     222          24 :       DEALLOCATE (ms_vib%delta_vec)
     223          24 :       DEALLOCATE (mass)
     224          24 :       DEALLOCATE (ms_vib%b_mat)
     225          24 :       DEALLOCATE (ms_vib%s_mat)
     226          24 :       IF (ms_vib%select_id == 3) THEN
     227           8 :          DEALLOCATE (ms_vib%inv_atoms)
     228             :       END IF
     229          24 :       IF (ASSOCIATED(ms_vib%eig_bfgs)) THEN
     230           0 :          DEALLOCATE (ms_vib%eig_bfgs)
     231             :       END IF
     232          24 :       IF (ASSOCIATED(ms_vib%hes_bfgs)) THEN
     233           0 :          DEALLOCATE (ms_vib%hes_bfgs)
     234             :       END IF
     235          24 :       IF (calc_intens) THEN
     236          20 :          DEALLOCATE (ms_vib%dip_deriv)
     237          20 :          DEALLOCATE (tmp_dip)
     238             :       END IF
     239          24 :       CALL timestop(handle)
     240          72 :    END SUBROUTINE ms_vb_anal
     241             : ! **************************************************************************************************
     242             : !> \brief Generates the first displacement vector for a mode selctive vibrational
     243             : !>      analysis. At the moment this is a random number for selected atoms
     244             : !> \param para_env ...
     245             : !> \param nrep ...
     246             : !> \param input ...
     247             : !> \param globenv ...
     248             : !> \param ms_vib ...
     249             : !> \param particles ...
     250             : !> \param mass ...
     251             : !> \param dx ...
     252             : !> \param calc_intens ...
     253             : !> \param logger ...
     254             : !> \author Florian Schiffmann 11.2007
     255             : ! **************************************************************************************************
     256          24 :    SUBROUTINE MS_initial_moves(para_env, nrep, input, globenv, ms_vib, particles, &
     257          24 :                                mass, dx, &
     258             :                                calc_intens, logger)
     259             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     260             :       INTEGER                                            :: nrep
     261             :       TYPE(section_vals_type), POINTER                   :: input
     262             :       TYPE(global_environment_type), POINTER             :: globenv
     263             :       TYPE(ms_vib_type)                                  :: ms_vib
     264             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     265             :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     266             :       REAL(KIND=dp)                                      :: dx
     267             :       LOGICAL                                            :: calc_intens
     268             :       TYPE(cp_logger_type), POINTER                      :: logger
     269             : 
     270             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'MS_initial_moves'
     271             : 
     272             :       INTEGER                                            :: guess, handle, i, j, jj, k, m, &
     273             :                                                             n_rep_val, natoms, ncoord
     274          24 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: map_atoms
     275          24 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
     276             :       LOGICAL                                            :: do_involved_atoms, ionode
     277             :       REAL(KIND=dp)                                      :: my_val, norm
     278             :       TYPE(section_vals_type), POINTER                   :: involved_at_section, ms_vib_section
     279             : 
     280          24 :       CALL timeset(routineN, handle)
     281          24 :       NULLIFY (ms_vib%eig_bfgs, ms_vib%f_range, ms_vib%hes_bfgs, ms_vib%inv_range)
     282          24 :       ms_vib_section => section_vals_get_subs_vals(input, "VIBRATIONAL_ANALYSIS%MODE_SELECTIVE")
     283          24 :       CALL section_vals_val_get(ms_vib_section, "INITIAL_GUESS", i_val=guess)
     284          24 :       CALL section_vals_val_get(ms_vib_section, "EPS_MAX_VAL", r_val=ms_vib%eps(1))
     285          24 :       CALL section_vals_val_get(ms_vib_section, "EPS_NORM", r_val=ms_vib%eps(2))
     286          24 :       CALL section_vals_val_get(ms_vib_section, "RANGE", n_rep_val=n_rep_val)
     287          24 :       ms_vib%select_id = 0
     288          24 :       IF (n_rep_val .NE. 0) THEN
     289           2 :          CALL section_vals_val_get(ms_vib_section, "RANGE", r_vals=ms_vib%f_range)
     290           2 :          IF (ms_vib%f_range(1) .GT. ms_vib%f_range(2)) THEN
     291           0 :             my_val = ms_vib%f_range(2)
     292           0 :             ms_vib%f_range(2) = ms_vib%f_range(1)
     293           0 :             ms_vib%f_range(1) = my_val
     294             :          END IF
     295           2 :          ms_vib%select_id = 2
     296             :       END IF
     297          24 :       CALL section_vals_val_get(ms_vib_section, "FREQUENCY", r_val=ms_vib%sel_freq)
     298          24 :       CALL section_vals_val_get(ms_vib_section, "LOWEST_FREQUENCY", r_val=ms_vib%low_freq)
     299          24 :       IF (ms_vib%sel_freq .GT. 0._dp) ms_vib%select_id = 1
     300          24 :       involved_at_section => section_vals_get_subs_vals(ms_vib_section, "INVOLVED_ATOMS")
     301          24 :       CALL section_vals_get(involved_at_section, explicit=do_involved_atoms)
     302          24 :       IF (do_involved_atoms) THEN
     303           8 :          CALL section_vals_val_get(involved_at_section, "INVOLVED_ATOMS", n_rep_val=n_rep_val)
     304           8 :          jj = 0
     305          16 :          DO k = 1, n_rep_val
     306           8 :             CALL section_vals_val_get(involved_at_section, "INVOLVED_ATOMS", i_rep_val=k, i_vals=tmplist)
     307          32 :             DO j = 1, SIZE(tmplist)
     308          24 :                jj = jj + 1
     309             :             END DO
     310             :          END DO
     311           8 :          IF (jj .GE. 1) THEN
     312           8 :             natoms = jj
     313          24 :             ALLOCATE (ms_vib%inv_atoms(natoms))
     314           8 :             jj = 0
     315          16 :             DO m = 1, n_rep_val
     316           8 :                CALL section_vals_val_get(involved_at_section, "INVOLVED_ATOMS", i_rep_val=m, i_vals=tmplist)
     317          32 :                DO j = 1, SIZE(tmplist)
     318          24 :                   ms_vib%inv_atoms(j) = tmplist(j)
     319             :                END DO
     320             :             END DO
     321           8 :             ms_vib%select_id = 3
     322             :          END IF
     323           8 :          CALL section_vals_val_get(involved_at_section, "RANGE", n_rep_val=n_rep_val)
     324           8 :          IF (n_rep_val .NE. 0) THEN
     325           0 :             CALL section_vals_val_get(involved_at_section, "RANGE", r_vals=ms_vib%inv_range)
     326           0 :             IF (ms_vib%inv_range(1) .GT. ms_vib%inv_range(2)) THEN
     327           0 :                ms_vib%inv_range(2) = my_val
     328           0 :                ms_vib%inv_range(2) = ms_vib%inv_range(1)
     329           0 :                ms_vib%inv_range(1) = my_val
     330             :             END IF
     331             :          END IF
     332             :       END IF
     333          24 :       IF (ms_vib%select_id == 0) &
     334           0 :          CPABORT("no frequency, range or involved atoms specified ")
     335          24 :       ionode = para_env%is_source()
     336          12 :       SELECT CASE (guess)
     337             :       CASE (ms_guess_atomic)
     338          12 :          ms_vib%initial_guess = 1
     339          12 :          CALL section_vals_val_get(ms_vib_section, "ATOMS", n_rep_val=n_rep_val)
     340          12 :          jj = 0
     341          22 :          DO k = 1, n_rep_val
     342          10 :             CALL section_vals_val_get(ms_vib_section, "ATOMS", i_rep_val=k, i_vals=tmplist)
     343          42 :             DO j = 1, SIZE(tmplist)
     344          30 :                jj = jj + 1
     345             :             END DO
     346             :          END DO
     347          12 :          IF (jj < 1) THEN
     348           2 :             natoms = SIZE(particles)
     349           6 :             ALLOCATE (map_atoms(natoms))
     350          14 :             DO j = 1, natoms
     351          14 :                map_atoms(j) = j
     352             :             END DO
     353             :          ELSE
     354          10 :             natoms = jj
     355          30 :             ALLOCATE (map_atoms(natoms))
     356          10 :             jj = 0
     357          20 :             DO m = 1, n_rep_val
     358          10 :                CALL section_vals_val_get(ms_vib_section, "ATOMS", i_rep_val=m, i_vals=tmplist)
     359          40 :                DO j = 1, SIZE(tmplist)
     360          30 :                   map_atoms(j) = tmplist(j)
     361             :                END DO
     362             :             END DO
     363             :          END IF
     364             : 
     365             :          ! apply random displacement along the mass weighted nuclear cartesian coordinates
     366         526 :          ms_vib%b_vec = 0._dp
     367         526 :          ms_vib%delta_vec = 0._dp
     368          12 :          jj = 0
     369             : 
     370          28 :          DO i = 1, nrep
     371          56 :             DO j = 1, natoms
     372         176 :                DO k = 1, 3
     373         120 :                   jj = (map_atoms(j) - 1)*3 + k
     374         160 :                   ms_vib%b_vec(jj, i) = ABS(globenv%gaussian_rng_stream%next())
     375             :                END DO
     376             :             END DO
     377         514 :             norm = SQRT(DOT_PRODUCT(ms_vib%b_vec(:, i), ms_vib%b_vec(:, i)))
     378         526 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/norm
     379             :          END DO
     380             : 
     381          12 :          IF (nrep .GT. 1) THEN
     382          44 :             DO k = 1, 10
     383         124 :                DO j = 1, nrep
     384         280 :                   DO i = 1, nrep
     385         240 :                      IF (i .NE. j) THEN
     386             :                         ms_vib%b_vec(:, j) = &
     387        1520 :                            ms_vib%b_vec(:, j) - DOT_PRODUCT(ms_vib%b_vec(:, j), ms_vib%b_vec(:, i))*ms_vib%b_vec(:, i)
     388             :                         ms_vib%b_vec(:, j) = &
     389        1520 :                            ms_vib%b_vec(:, j)/SQRT(DOT_PRODUCT(ms_vib%b_vec(:, j), ms_vib%b_vec(:, j)))
     390             :                      END IF
     391             :                   END DO
     392             :                END DO
     393             :             END DO
     394             :          END IF
     395             : 
     396          12 :          ms_vib%mat_size = 0
     397         474 :          DO i = 1, SIZE(ms_vib%b_vec, 1)
     398         972 :             ms_vib%delta_vec(i, :) = ms_vib%b_vec(i, :)/mass(i)
     399             :          END DO
     400             :       CASE (ms_guess_bfgs)
     401             : 
     402           4 :          ms_vib%initial_guess = 2
     403           4 :          CALL bfgs_guess(ms_vib_section, ms_vib, particles, mass, para_env, nrep)
     404           4 :          ms_vib%mat_size = 0
     405             : 
     406             :       CASE (ms_guess_restart_vec)
     407             : 
     408           4 :          ms_vib%initial_guess = 3
     409           4 :          ncoord = 3*SIZE(particles)
     410           4 :          CALL rest_guess(ms_vib_section, para_env, ms_vib, mass, ionode, particles, nrep, calc_intens)
     411             : 
     412           4 :          ms_vib%mat_size = 0
     413             :       CASE (ms_guess_restart)
     414           0 :          ms_vib%initial_guess = 4
     415           0 :          ncoord = 3*SIZE(particles)
     416           0 :          CALL rest_guess(ms_vib_section, para_env, ms_vib, mass, ionode, particles, nrep, calc_intens)
     417             : 
     418             :       CASE (ms_guess_molden)
     419           4 :          ms_vib%initial_guess = 5
     420           4 :          ncoord = 3*SIZE(particles)
     421           4 :          CALL molden_guess(ms_vib_section, input, para_env, ms_vib, mass, ncoord, nrep, logger)
     422          28 :          ms_vib%mat_size = 0
     423             :       END SELECT
     424        5324 :       CALL para_env%bcast(ms_vib%b_vec)
     425        5324 :       CALL para_env%bcast(ms_vib%delta_vec)
     426          52 :       DO i = 1, nrep
     427        2650 :          ms_vib%step_r(i) = dx/SQRT(DOT_PRODUCT(ms_vib%delta_vec(:, i), ms_vib%delta_vec(:, i)))
     428        2674 :          ms_vib%step_b(i) = SQRT(DOT_PRODUCT(ms_vib%step_r(i)*ms_vib%b_vec(:, i), ms_vib%step_r(i)*ms_vib%b_vec(:, i)))
     429             :       END DO
     430          24 :       CALL timestop(handle)
     431             : 
     432          48 :    END SUBROUTINE MS_initial_moves
     433             : 
     434             : ! **************************************************************************************************
     435             : !> \brief ...
     436             : !> \param ms_vib_section ...
     437             : !> \param ms_vib ...
     438             : !> \param particles ...
     439             : !> \param mass ...
     440             : !> \param para_env ...
     441             : !> \param nrep ...
     442             : !> \author Florian Schiffmann 11.2007
     443             : ! **************************************************************************************************
     444           4 :    SUBROUTINE bfgs_guess(ms_vib_section, ms_vib, particles, mass, para_env, nrep)
     445             : 
     446             :       TYPE(section_vals_type), POINTER                   :: ms_vib_section
     447             :       TYPE(ms_vib_type)                                  :: ms_vib
     448             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     449             :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     450             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     451             :       INTEGER                                            :: nrep
     452             : 
     453             :       CHARACTER(LEN=default_path_length)                 :: hes_filename
     454             :       INTEGER                                            :: hesunit, i, j, jj, k, natoms, ncoord, &
     455             :                                                             output_unit, stat
     456           4 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
     457             :       REAL(KIND=dp)                                      :: my_val, norm
     458           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tmp
     459             :       TYPE(cp_logger_type), POINTER                      :: logger
     460             : 
     461           8 :       logger => cp_get_default_logger()
     462           4 :       output_unit = cp_logger_get_default_io_unit(logger)
     463             : 
     464           4 :       natoms = SIZE(particles)
     465           4 :       ncoord = 3*natoms
     466             : 
     467          16 :       ALLOCATE (ms_vib%hes_bfgs(ncoord, ncoord))
     468          12 :       ALLOCATE (ms_vib%eig_bfgs(ncoord))
     469             : 
     470           4 :       IF (para_env%is_source()) THEN
     471           2 :          CALL section_vals_val_get(ms_vib_section, "RESTART_FILE_NAME", c_val=hes_filename)
     472           2 :          IF (hes_filename == "") hes_filename = "HESSIAN"
     473             :          CALL open_file(file_name=hes_filename, file_status="OLD", &
     474           2 :                         file_form="UNFORMATTED", file_action="READ", unit_number=hesunit)
     475           6 :          ALLOCATE (tmp(ncoord))
     476           6 :          ALLOCATE (tmplist(ncoord))
     477             : 
     478             :          ! should use the cp_fm_read_unformatted...
     479         356 :          DO i = 1, ncoord
     480         356 :             READ (UNIT=hesunit, IOSTAT=stat) ms_vib%hes_bfgs(:, i)
     481             :          END DO
     482           2 :          CALL close_file(hesunit)
     483           2 :          IF (output_unit > 0) THEN
     484           2 :             IF (stat /= 0) THEN
     485           0 :                WRITE (output_unit, FMT="(/,T2,A)") "**  Error while reading HESSIAN **"
     486             :             ELSE
     487             :                WRITE (output_unit, FMT="(/,T2,A)") &
     488           2 :                   "*** Initial Hessian has been read successfully ***"
     489             :             END IF
     490             :          END IF
     491         356 :          DO i = 1, ncoord
     492       63014 :             DO j = 1, ncoord
     493       63012 :                ms_vib%hes_bfgs(i, j) = ms_vib%hes_bfgs(i, j)/(mass(i)*mass(j))
     494             :             END DO
     495             :          END DO
     496             : 
     497           2 :          CALL diamat_all(ms_vib%hes_bfgs, ms_vib%eig_bfgs)
     498         356 :          tmp(:) = 0._dp
     499           2 :          IF (ms_vib%select_id == 1) my_val = (ms_vib%sel_freq/vibfac)**2/massunit
     500           2 :          IF (ms_vib%select_id == 2) my_val = (((ms_vib%f_range(2) + ms_vib%f_range(1))*0.5_dp)/vibfac)**2/massunit
     501           2 :          IF (ms_vib%select_id == 1 .OR. ms_vib%select_id == 2) THEN
     502         178 :             DO i = 1, ncoord
     503         178 :                tmp(i) = ABS(my_val - ms_vib%eig_bfgs(i))
     504             :             END DO
     505           1 :          ELSE IF (ms_vib%select_id == 3) THEN
     506         178 :             DO i = 1, ncoord
     507         531 :                DO j = 1, SIZE(ms_vib%inv_atoms)
     508        1593 :                   DO k = 1, 3
     509        1062 :                      jj = (ms_vib%inv_atoms(j) - 1)*3 + k
     510        1416 :                      tmp(i) = tmp(i) + SQRT(ms_vib%hes_bfgs(jj, i)**2)
     511             :                   END DO
     512             :                END DO
     513         178 :                IF ((SIGN(1._dp, ms_vib%eig_bfgs(i))*SQRT(ABS(ms_vib%eig_bfgs(i))*massunit)*vibfac) .LE. 400._dp) tmp(i) = 0._dp
     514             :             END DO
     515         178 :             tmp(:) = -tmp(:)
     516             :          END IF
     517           2 :          CALL sort(tmp, ncoord, tmplist)
     518           4 :          DO i = 1, nrep
     519         356 :             ms_vib%b_vec(:, i) = ms_vib%hes_bfgs(:, tmplist(i))
     520         356 :             norm = SQRT(DOT_PRODUCT(ms_vib%b_vec(:, i), ms_vib%b_vec(:, i)))
     521         358 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/norm
     522             :          END DO
     523         356 :          DO i = 1, SIZE(ms_vib%b_vec, 1)
     524         710 :             ms_vib%delta_vec(i, :) = ms_vib%b_vec(i, :)/mass(i)
     525             :          END DO
     526           2 :          DEALLOCATE (tmp)
     527           2 :          DEALLOCATE (tmplist)
     528             :       END IF
     529             : 
     530        1428 :       CALL para_env%bcast(ms_vib%b_vec)
     531        1428 :       CALL para_env%bcast(ms_vib%delta_vec)
     532             : 
     533           4 :       DEALLOCATE (ms_vib%hes_bfgs)
     534           4 :       DEALLOCATE (ms_vib%eig_bfgs)
     535           4 :       ms_vib%mat_size = 0
     536             : 
     537           4 :    END SUBROUTINE bfgs_guess
     538             : 
     539             : ! **************************************************************************************************
     540             : !> \brief ...
     541             : !> \param ms_vib_section ...
     542             : !> \param para_env ...
     543             : !> \param ms_vib ...
     544             : !> \param mass ...
     545             : !> \param ionode ...
     546             : !> \param particles ...
     547             : !> \param nrep ...
     548             : !> \param calc_intens ...
     549             : !> \author Florian Schiffmann 11.2007
     550             : ! **************************************************************************************************
     551           4 :    SUBROUTINE rest_guess(ms_vib_section, para_env, ms_vib, mass, ionode, particles, nrep, calc_intens)
     552             : 
     553             :       TYPE(section_vals_type), POINTER                   :: ms_vib_section
     554             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     555             :       TYPE(ms_vib_type)                                  :: ms_vib
     556             :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     557             :       LOGICAL                                            :: ionode
     558             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     559             :       INTEGER                                            :: nrep
     560             :       LOGICAL                                            :: calc_intens
     561             : 
     562             :       CHARACTER(LEN=default_path_length)                 :: ms_filename
     563             :       INTEGER                                            :: hesunit, i, j, mat, natoms, ncoord, &
     564             :                                                             output_unit, stat, statint
     565           4 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ind
     566           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval
     567           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: approx_H
     568             :       TYPE(cp_logger_type), POINTER                      :: logger
     569             : 
     570           4 :       logger => cp_get_default_logger()
     571           4 :       output_unit = cp_logger_get_default_io_unit(logger)
     572             : 
     573           4 :       natoms = SIZE(particles)
     574           4 :       ncoord = 3*natoms
     575           4 :       IF (calc_intens) THEN
     576           4 :          DEALLOCATE (ms_vib%dip_deriv)
     577             :       END IF
     578             : 
     579           4 :       IF (ionode) THEN
     580             : 
     581           2 :          CALL section_vals_val_get(ms_vib_section, "RESTART_FILE_NAME", c_val=ms_filename)
     582           2 :          IF (ms_filename == "") ms_filename = "MS_RESTART"
     583             :          CALL open_file(file_name=ms_filename, &
     584             :                         file_status="UNKNOWN", &
     585             :                         file_form="UNFORMATTED", &
     586             :                         file_action="READ", &
     587           2 :                         unit_number=hesunit)
     588           2 :          READ (UNIT=hesunit, IOSTAT=stat) mat
     589           2 :          CPASSERT(stat == 0)
     590           2 :          ms_vib%mat_size = mat
     591             :       END IF
     592           4 :       CALL para_env%bcast(ms_vib%mat_size)
     593          16 :       ALLOCATE (ms_vib%b_mat(ncoord, ms_vib%mat_size))
     594          12 :       ALLOCATE (ms_vib%s_mat(ncoord, ms_vib%mat_size))
     595           4 :       IF (calc_intens) THEN
     596          12 :          ALLOCATE (ms_vib%dip_deriv(3, ms_vib%mat_size + nrep))
     597             :       END IF
     598           4 :       IF (ionode) THEN
     599           2 :          statint = 0
     600        3384 :          READ (UNIT=hesunit, IOSTAT=stat) ms_vib%b_mat
     601        3384 :          READ (UNIT=hesunit, IOSTAT=stat) ms_vib%s_mat
     602           2 :          IF (calc_intens) READ (UNIT=hesunit, IOSTAT=statint) ms_vib%dip_deriv(:, 1:ms_vib%mat_size)
     603           2 :          IF (statint /= 0 .AND. output_unit > 0) WRITE (output_unit, FMT="(/,T2,A)") "**  Error while reading MS_RESTART,", &
     604           0 :             "intensities are requested but not present in restart file **"
     605           2 :          CALL close_file(hesunit)
     606           2 :          IF (output_unit > 0) THEN
     607           2 :             IF (stat /= 0) THEN
     608           0 :                WRITE (output_unit, FMT="(/,T2,A)") "**  Error while reading MS_RESTART **"
     609             :             ELSE
     610           2 :                WRITE (output_unit, FMT="(/,T2,A)") "*** RESTART has been read successfully ***"
     611             :             END IF
     612             :          END IF
     613             :       END IF
     614       13532 :       CALL para_env%bcast(ms_vib%b_mat)
     615       13532 :       CALL para_env%bcast(ms_vib%s_mat)
     616         340 :       IF (calc_intens) CALL para_env%bcast(ms_vib%dip_deriv)
     617          16 :       ALLOCATE (approx_H(ms_vib%mat_size, ms_vib%mat_size))
     618          12 :       ALLOCATE (eigenval(ms_vib%mat_size))
     619          12 :       ALLOCATE (ind(ms_vib%mat_size))
     620             : 
     621             :       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), &
     622           4 :                  ms_vib%s_mat, SIZE(ms_vib%s_mat, 1), 0._dp, approx_H, ms_vib%mat_size)
     623           4 :       CALL diamat_all(approx_H, eigenval)
     624             : 
     625           4 :       CALL select_vector(ms_vib, nrep, mass, ncoord, approx_H, eigenval, ind, ms_vib%b_vec)
     626           4 :       IF (ms_vib%initial_guess .NE. 4) THEN
     627             : 
     628         716 :          ms_vib%b_vec = 0._dp
     629           8 :          DO i = 1, nrep
     630          42 :             DO j = 1, ms_vib%mat_size
     631        6768 :                ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i) + approx_H(j, ind(i))*ms_vib%b_mat(:, j)
     632             :             END DO
     633        1424 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/SQRT(DOT_PRODUCT(ms_vib%b_vec(:, i), ms_vib%b_vec(:, i)))
     634             :          END DO
     635             : 
     636           4 :          DEALLOCATE (ms_vib%s_mat)
     637           4 :          DEALLOCATE (ms_vib%b_mat)
     638           4 :          IF (calc_intens) THEN
     639           4 :             DEALLOCATE (ms_vib%dip_deriv)
     640          12 :             ALLOCATE (ms_vib%dip_deriv(3, nrep))
     641             :          END IF
     642             :       END IF
     643           4 :       DEALLOCATE (approx_H)
     644           4 :       DEALLOCATE (eigenval)
     645           4 :       DEALLOCATE (ind)
     646           8 :       DO i = 1, nrep
     647         716 :          ms_vib%delta_vec(:, i) = ms_vib%b_vec(:, i)/mass(:)
     648             :       END DO
     649             : 
     650           4 :    END SUBROUTINE rest_guess
     651             : 
     652             : ! **************************************************************************************************
     653             : !> \brief ...
     654             : !> \param ms_vib_section ...
     655             : !> \param input ...
     656             : !> \param para_env ...
     657             : !> \param ms_vib ...
     658             : !> \param mass ...
     659             : !> \param ncoord ...
     660             : !> \param nrep ...
     661             : !> \param logger ...
     662             : !> \author Florian Schiffmann 11.2007
     663             : ! **************************************************************************************************
     664           4 :    SUBROUTINE molden_guess(ms_vib_section, input, para_env, ms_vib, mass, ncoord, nrep, logger)
     665             :       TYPE(section_vals_type), POINTER                   :: ms_vib_section, input
     666             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     667             :       TYPE(ms_vib_type)                                  :: ms_vib
     668             :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     669             :       INTEGER                                            :: ncoord, nrep
     670             :       TYPE(cp_logger_type), POINTER                      :: logger
     671             : 
     672             :       CHARACTER(LEN=2)                                   :: at_name
     673             :       CHARACTER(LEN=default_path_length)                 :: ms_filename
     674             :       CHARACTER(LEN=max_line_length)                     :: info
     675             :       INTEGER                                            :: i, istat, iw, j, jj, k, nvibs, &
     676             :                                                             output_molden, output_unit, stat
     677           4 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
     678             :       LOGICAL                                            :: reading_vib
     679             :       REAL(KIND=dp)                                      :: my_val, norm
     680           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: freq, tmp
     681           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: modes
     682           8 :       REAL(KIND=dp), DIMENSION(3, ncoord/3)              :: pos
     683             : 
     684           8 :       output_unit = cp_logger_get_default_io_unit(logger)
     685             : 
     686           4 :       CALL section_vals_val_get(ms_vib_section, "RESTART_FILE_NAME", c_val=ms_filename)
     687           4 :       IF (ms_filename == "") output_molden = &
     688             :          cp_print_key_unit_nr(logger, input, "VIBRATIONAL_ANALYSIS%PRINT%MOLDEN_VIB", &
     689             :                               extension=".mol", file_status='UNKNOWN', &
     690           0 :                               file_action="READ")
     691           4 :       IF (para_env%is_source()) THEN
     692             : 
     693           2 :          IF (ms_filename == "") THEN
     694           0 :             iw = output_molden
     695             :          ELSE
     696             :             CALL open_file(file_name=TRIM(ms_filename), &
     697             :                            file_status="UNKNOWN", &
     698             :                            file_form="FORMATTED", &
     699             :                            file_action="READ", &
     700           2 :                            unit_number=iw)
     701             :          END IF
     702           2 :          info = ""
     703           2 :          READ (iw, *, IOSTAT=stat) info
     704           2 :          READ (iw, *, IOSTAT=stat) info
     705           2 :          istat = 0
     706           2 :          nvibs = 0
     707           2 :          reading_vib = .FALSE.
     708         140 :          DO
     709         142 :             READ (iw, *, IOSTAT=stat) info
     710         142 :             istat = istat + stat
     711         142 :             IF (TRIM(ADJUSTL(info)) == "[FR-COORD]") EXIT
     712             : 
     713         140 :             CPASSERT(stat == 0)
     714             : 
     715         140 :             IF (reading_vib) nvibs = nvibs + 1
     716         140 :             IF (TRIM(ADJUSTL(info)) == "[FREQ]") reading_vib = .TRUE.
     717             :          END DO
     718           2 :          REWIND (iw)
     719           2 :          istat = 0
     720           2 :          READ (iw, *, IOSTAT=stat) info
     721           2 :          istat = istat + stat
     722           2 :          READ (iw, *, IOSTAT=stat) info
     723           2 :          istat = istat + stat
     724             :          ! Skip [Atoms] section
     725         118 :          DO
     726         120 :             READ (iw, *, IOSTAT=stat) info
     727         120 :             istat = istat + stat
     728         120 :             CPASSERT(stat == 0)
     729         120 :             IF (TRIM(ADJUSTL(info)) == "[FREQ]") EXIT
     730             :          END DO
     731             :          ! Read frequencies and modes
     732           6 :          ALLOCATE (freq(nvibs))
     733           8 :          ALLOCATE (modes(ncoord, nvibs))
     734             : 
     735          22 :          DO i = 1, nvibs
     736          20 :             READ (iw, *, IOSTAT=stat) freq(i)
     737          22 :             istat = istat + stat
     738             :          END DO
     739           2 :          READ (iw, *) info
     740         120 :          DO i = 1, ncoord/3
     741         118 :             READ (iw, *, IOSTAT=stat) at_name, pos(:, i)
     742         120 :             istat = istat + stat
     743             :          END DO
     744           2 :          READ (iw, *) info
     745          22 :          DO i = 1, nvibs
     746          20 :             READ (iw, *) info
     747          20 :             istat = istat + stat
     748        1202 :             DO j = 1, ncoord/3
     749        1180 :                k = (j - 1)*3 + 1
     750        1180 :                READ (iw, *, IOSTAT=stat) modes(k:k + 2, i)
     751        1200 :                istat = istat + stat
     752             :             END DO
     753             :          END DO
     754           2 :          IF (ms_filename .NE. "") CALL close_file(iw)
     755           2 :          IF (output_unit > 0) THEN
     756           2 :             IF (istat /= 0) THEN
     757           0 :                WRITE (output_unit, FMT="(/,T2,A)") "**  Error while reading MOLDEN file **"
     758             :             ELSE
     759           2 :                WRITE (output_unit, FMT="(/,T2,A)") "*** MOLDEN file has been read successfully ***"
     760             :             END IF
     761             :          END IF
     762             :          !!!!!!!    select modes     !!!!!!
     763           4 :          ALLOCATE (tmp(nvibs))
     764          22 :          tmp(:) = 0.0_dp
     765           6 :          ALLOCATE (tmplist(nvibs))
     766           2 :          IF (ms_vib%select_id == 1) my_val = ms_vib%sel_freq
     767           2 :          IF (ms_vib%select_id == 2) my_val = (ms_vib%f_range(2) + ms_vib%f_range(1))*0.5_dp
     768           2 :          IF (ms_vib%select_id == 1 .OR. ms_vib%select_id == 2) THEN
     769          11 :             DO i = 1, nvibs
     770          11 :                tmp(i) = ABS(my_val - freq(i))
     771             :             END DO
     772           1 :          ELSE IF (ms_vib%select_id == 3) THEN
     773          11 :             DO i = 1, nvibs
     774          30 :                DO j = 1, SIZE(ms_vib%inv_atoms)
     775          90 :                   DO k = 1, 3
     776          60 :                      jj = (ms_vib%inv_atoms(j) - 1)*3 + k
     777          80 :                      tmp(i) = tmp(i) + SQRT(modes(jj, i)**2)
     778             :                   END DO
     779             :                END DO
     780          11 :                IF (freq(i) .LE. 400._dp) tmp(i) = 0._dp
     781             :             END DO
     782          11 :             tmp(:) = -tmp(:)
     783             :          END IF
     784           2 :          CALL sort(tmp, nvibs, tmplist)
     785           4 :          DO i = 1, nrep
     786         356 :             ms_vib%b_vec(:, i) = modes(:, tmplist(i))*mass(:)
     787         356 :             norm = SQRT(DOT_PRODUCT(ms_vib%b_vec(:, i), ms_vib%b_vec(:, i)))
     788         358 :             ms_vib%b_vec(:, i) = ms_vib%b_vec(:, i)/norm
     789             :          END DO
     790           4 :          DO i = 1, nrep
     791         358 :             ms_vib%delta_vec(:, i) = ms_vib%b_vec(:, i)/mass(:)
     792             :          END DO
     793             : 
     794           2 :          DEALLOCATE (freq)
     795           2 :          DEALLOCATE (modes)
     796           2 :          DEALLOCATE (tmp)
     797           2 :          DEALLOCATE (tmplist)
     798             : 
     799             :       END IF
     800        1428 :       CALL para_env%bcast(ms_vib%b_vec)
     801        1428 :       CALL para_env%bcast(ms_vib%delta_vec)
     802             : 
     803           4 :       IF (ms_filename == "") CALL cp_print_key_finished_output(output_molden, logger, input, &
     804           0 :                                                                "VIBRATIONAL_ANALYSIS%PRINT%MOLDEN_VIB")
     805           4 :    END SUBROUTINE molden_guess
     806             : 
     807             : ! **************************************************************************************************
     808             : !> \brief Davidson algorithm for to generate a approximate Hessian for mode
     809             : !>      selective vibrational analysis
     810             : !> \param rep_env ...
     811             : !> \param ms_vib ...
     812             : !> \param input ...
     813             : !> \param nrep ...
     814             : !> \param particles ...
     815             : !> \param mass ...
     816             : !> \param converged ...
     817             : !> \param dx ...
     818             : !> \param calc_intens ...
     819             : !> \param output_unit_ms ...
     820             : !> \param logger ...
     821             : !> \author Florian Schiffmann 11.2007
     822             : ! **************************************************************************************************
     823         162 :    SUBROUTINE evaluate_H_update_b(rep_env, ms_vib, input, nrep, &
     824             :                                   particles, &
     825         162 :                                   mass, &
     826             :                                   converged, dx, &
     827             :                                   calc_intens, output_unit_ms, logger)
     828             :       TYPE(replica_env_type), POINTER                    :: rep_env
     829             :       TYPE(ms_vib_type)                                  :: ms_vib
     830             :       TYPE(section_vals_type), POINTER                   :: input
     831             :       INTEGER                                            :: nrep
     832             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     833             :       REAL(Kind=dp), DIMENSION(:)                        :: mass
     834             :       LOGICAL                                            :: converged
     835             :       REAL(KIND=dp)                                      :: dx
     836             :       LOGICAL                                            :: calc_intens
     837             :       INTEGER                                            :: output_unit_ms
     838             :       TYPE(cp_logger_type), POINTER                      :: logger
     839             : 
     840             :       INTEGER                                            :: i, j, jj, k, natoms, ncoord
     841         162 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ind
     842             :       LOGICAL                                            :: dump_only_positive
     843         162 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval, freq
     844         162 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: approx_H, H_save, residuum, tmp_b, tmp_s
     845         324 :       REAL(KIND=dp), DIMENSION(2, nrep)                  :: criteria
     846         162 :       REAL(Kind=dp), DIMENSION(:), POINTER               :: intensities
     847             : 
     848         162 :       natoms = SIZE(particles)
     849         162 :       ncoord = 3*natoms
     850         162 :       nrep = SIZE(rep_env%f, 2)
     851             : 
     852             :       !!!!!!!!   reallocate and update the davidson matrices   !!!!!!!!!!
     853         162 :       IF (ms_vib%mat_size .NE. 0) THEN
     854             : 
     855         690 :          ALLOCATE (tmp_b(3*natoms, ms_vib%mat_size))
     856         414 :          ALLOCATE (tmp_s(3*natoms, ms_vib%mat_size))
     857             : 
     858      153792 :          tmp_b(:, :) = ms_vib%b_mat
     859      153792 :          tmp_s(:, :) = ms_vib%s_mat
     860             : 
     861         138 :          DEALLOCATE (ms_vib%b_mat)
     862         138 :          DEALLOCATE (ms_vib%s_mat)
     863             :       END IF
     864             : 
     865         810 :       ALLOCATE (ms_vib%b_mat(3*natoms, ms_vib%mat_size + nrep))
     866         486 :       ALLOCATE (ms_vib%s_mat(3*natoms, ms_vib%mat_size + nrep))
     867             : 
     868      176832 :       ms_vib%s_mat = 0.0_dp
     869             : 
     870       22896 :       DO i = 1, 3*natoms
     871       22734 :          IF (ms_vib%mat_size .NE. 0) THEN
     872      172878 :             DO j = 1, ms_vib%mat_size
     873      152730 :                ms_vib%b_mat(i, j) = tmp_b(i, j)
     874      172878 :                ms_vib%s_mat(i, j) = tmp_s(i, j)
     875             :             END DO
     876             :          END IF
     877       45738 :          DO j = 1, nrep
     878       45576 :             ms_vib%b_mat(i, ms_vib%mat_size + j) = ms_vib%b_vec(i, j)
     879             :          END DO
     880             :       END DO
     881             : 
     882         162 :       IF (ms_vib%mat_size .NE. 0) THEN
     883         138 :          DEALLOCATE (tmp_s)
     884         138 :          DEALLOCATE (tmp_b)
     885             :       END IF
     886             : 
     887         162 :       ms_vib%mat_size = ms_vib%mat_size + nrep
     888             : 
     889         648 :       ALLOCATE (approx_H(ms_vib%mat_size, ms_vib%mat_size))
     890         486 :       ALLOCATE (H_save(ms_vib%mat_size, ms_vib%mat_size))
     891         486 :       ALLOCATE (eigenval(ms_vib%mat_size))
     892             : 
     893             :       !!!!!!!!!!!!  calculate the new derivativ and the approximate hessian
     894             : 
     895         336 :       DO i = 1, nrep
     896       23178 :          DO j = 1, 3*natoms
     897       23016 :             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))
     898             :          END DO
     899             :       END DO
     900             : 
     901             :       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), &
     902         162 :                  ms_vib%s_mat, SIZE(ms_vib%s_mat, 1), 0._dp, approx_H, ms_vib%mat_size)
     903       14006 :       H_save(:, :) = approx_H
     904             : 
     905         162 :       CALL diamat_all(approx_H, eigenval)
     906             : 
     907             :       !!!!!!!!!!!! select eigenvalue(s) and vector(s) and calculate the new displacement vector
     908         486 :       ALLOCATE (ind(ms_vib%mat_size))
     909         648 :       ALLOCATE (residuum(SIZE(ms_vib%s_mat, 1), nrep))
     910             : 
     911         162 :       CALL select_vector(ms_vib, nrep, mass, ncoord, approx_H, eigenval, ind, residuum, criteria)
     912             : 
     913         336 :       DO i = 1, nrep
     914        7950 :          DO j = 1, natoms
     915       30630 :             DO k = 1, 3
     916       22842 :                jj = (j - 1)*3 + k
     917       30456 :                ms_vib%delta_vec(jj, i) = ms_vib%b_vec(jj, i)/mass(jj)
     918             :             END DO
     919             :          END DO
     920             :       END DO
     921             : 
     922         336 :       DO i = 1, nrep
     923       23016 :          ms_vib%step_r(i) = dx/SQRT(DOT_PRODUCT(ms_vib%delta_vec(:, i), ms_vib%delta_vec(:, i)))
     924       23178 :          ms_vib%step_b(i) = SQRT(DOT_PRODUCT(ms_vib%step_r(i)*ms_vib%b_vec(:, i), ms_vib%step_r(i)*ms_vib%b_vec(:, i)))
     925             :       END DO
     926         162 :       converged = .FALSE.
     927             :       IF (MAXVAL(criteria(1, :)) .LE. ms_vib%eps(1) .AND. MAXVAL(criteria(2, :)) &
     928         834 :           .LE. ms_vib%eps(2) .OR. ms_vib%mat_size .GE. ncoord) converged = .TRUE.
     929         486 :       ALLOCATE (freq(nrep))
     930         336 :       DO i = 1, nrep
     931         336 :          freq(i) = SQRT(ABS(eigenval(ind(i)))*massunit)*vibfac
     932             :       END DO
     933             : 
     934             :       !!!   write information and output   !!!
     935         162 :       IF (converged) THEN
     936         198 :          eigenval(:) = SIGN(1._dp, eigenval(:))*SQRT(ABS(eigenval(:))*massunit)*vibfac
     937          96 :          ALLOCATE (tmp_b(ncoord, ms_vib%mat_size))
     938       23040 :          tmp_b = 0._dp
     939          72 :          ALLOCATE (tmp_s(3, ms_vib%mat_size))
     940         720 :          tmp_s = 0._dp
     941          24 :          IF (calc_intens) THEN
     942          60 :             ALLOCATE (intensities(ms_vib%mat_size))
     943         170 :             intensities = 0._dp
     944             :          END IF
     945         198 :          DO i = 1, ms_vib%mat_size
     946        2268 :             DO j = 1, ms_vib%mat_size
     947      331218 :                tmp_b(:, i) = tmp_b(:, i) + approx_H(j, i)*ms_vib%b_mat(:, j)/mass(:)
     948             :             END DO
     949       45882 :             tmp_b(:, i) = tmp_b(:, i)/SQRT(DOT_PRODUCT(tmp_b(:, i), tmp_b(:, i)))
     950             :          END DO
     951          24 :          IF (calc_intens) THEN
     952         170 :             DO i = 1, ms_vib%mat_size
     953        2100 :                DO j = 1, ms_vib%mat_size
     954        7950 :                   tmp_s(:, i) = tmp_s(:, i) + ms_vib%dip_deriv(:, j)*approx_H(j, i)
     955             :                END DO
     956         620 :                IF (calc_intens) intensities(i) = SQRT(DOT_PRODUCT(tmp_s(:, i), tmp_s(:, i)))
     957             :             END DO
     958             :          END IF
     959          24 :          IF (calc_intens) THEN
     960             :             CALL ms_out(output_unit_ms, converged, freq, criteria, ms_vib, &
     961             :                         input, nrep, approx_H, eigenval, calc_intens, &
     962          20 :                         intensities=intensities, logger=logger)
     963             :          ELSE
     964             :             CALL ms_out(output_unit_ms, converged, freq, criteria, ms_vib, &
     965           4 :                         input, nrep, approx_H, eigenval, calc_intens, logger=logger)
     966             :          END IF
     967          24 :          dump_only_positive = ms_vib%low_freq .GT. 0.0_dp
     968             :          CALL write_vibrations_molden(input, particles, eigenval, tmp_b, intensities, calc_intens, &
     969          24 :                                       dump_only_positive=dump_only_positive, logger=logger)
     970          24 :          IF (calc_intens) THEN
     971          20 :             DEALLOCATE (intensities)
     972             :          END IF
     973          24 :          DEALLOCATE (tmp_b)
     974          24 :          DEALLOCATE (tmp_s)
     975             :       END IF
     976             : 
     977         162 :       IF (.NOT. converged) CALL ms_out(output_unit_ms, converged, freq, criteria, &
     978         138 :                                        ms_vib, input, nrep, approx_H, eigenval, calc_intens, logger=logger)
     979             : 
     980         162 :       DEALLOCATE (freq)
     981         162 :       DEALLOCATE (approx_H)
     982         162 :       DEALLOCATE (eigenval)
     983         162 :       DEALLOCATE (residuum)
     984         162 :       DEALLOCATE (ind)
     985             : 
     986         324 :    END SUBROUTINE evaluate_H_update_b
     987             : 
     988             : ! **************************************************************************************************
     989             : !> \brief writes the output for a mode tracking calculation
     990             : !> \param ms_vib ...
     991             : !> \param nrep ...
     992             : !> \param mass ...
     993             : !> \param ncoord ...
     994             : !> \param approx_H ...
     995             : !> \param eigenval ...
     996             : !> \param ind ...
     997             : !> \param residuum ...
     998             : !> \param criteria ...
     999             : !> \author Florian Schiffmann 11.2007
    1000             : ! **************************************************************************************************
    1001         166 :    SUBROUTINE select_vector(ms_vib, nrep, mass, ncoord, approx_H, eigenval, ind, residuum, criteria)
    1002             : 
    1003             :       TYPE(ms_vib_type)                                  :: ms_vib
    1004             :       INTEGER                                            :: nrep
    1005             :       REAL(Kind=dp), DIMENSION(:)                        :: mass
    1006             :       INTEGER                                            :: ncoord
    1007             :       REAL(KIND=dp), DIMENSION(:, :)                     :: approx_H
    1008             :       REAL(Kind=dp), DIMENSION(:)                        :: eigenval
    1009             :       INTEGER, DIMENSION(:)                              :: ind
    1010             :       REAL(KIND=dp), DIMENSION(:, :)                     :: residuum
    1011             :       REAL(KIND=dp), DIMENSION(2, nrep), OPTIONAL        :: criteria
    1012             : 
    1013             :       INTEGER                                            :: i, j, jj, k
    1014             :       REAL(KIND=dp)                                      :: my_val, norm
    1015         166 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tmp
    1016         166 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: tmp_b
    1017             : 
    1018         498 :       ALLOCATE (tmp(ms_vib%mat_size))
    1019             : 
    1020         282 :       SELECT CASE (ms_vib%select_id)
    1021             :       CASE (1)
    1022         116 :          my_val = (ms_vib%sel_freq/(vibfac))**2/massunit
    1023        1006 :          DO i = 1, ms_vib%mat_size
    1024        1006 :             tmp(i) = ABS(my_val - eigenval(i))
    1025             :          END DO
    1026         116 :          CALL sort(tmp, (ms_vib%mat_size), ind)
    1027       15892 :          residuum = 0._dp
    1028         238 :          DO j = 1, nrep
    1029        1152 :             DO i = 1, ms_vib%mat_size
    1030      144040 :                residuum(:, j) = residuum(:, j) + approx_H(i, ind(j))*(ms_vib%s_mat(:, i) - eigenval(ind(j))*ms_vib%b_mat(:, i))
    1031             :             END DO
    1032             :          END DO
    1033             :       CASE (2)
    1034           6 :          CALL get_vibs_in_range(ms_vib, approx_H, eigenval, residuum, nrep, ind)
    1035             :       CASE (3)
    1036             : 
    1037         176 :          ALLOCATE (tmp_b(ncoord, ms_vib%mat_size))
    1038       39560 :          tmp_b = 0._dp
    1039             : 
    1040         266 :          DO i = 1, ms_vib%mat_size
    1041        1728 :             DO j = 1, ms_vib%mat_size
    1042      268290 :                tmp_b(:, i) = tmp_b(:, i) + approx_H(j, i)*ms_vib%b_mat(:, j)/mass(:)
    1043             :             END DO
    1044       78854 :             tmp_b(:, i) = tmp_b(:, i)/SQRT(DOT_PRODUCT(tmp_b(:, i), tmp_b(:, i)))
    1045             :          END DO
    1046         266 :          tmp = 0._dp
    1047         266 :          DO i = 1, ms_vib%mat_size
    1048         666 :             DO j = 1, SIZE(ms_vib%inv_atoms)
    1049        1998 :                DO k = 1, 3
    1050        1332 :                   jj = (ms_vib%inv_atoms(j) - 1)*3 + k
    1051        1776 :                   tmp(i) = tmp(i) + SQRT(tmp_b(jj, i)**2)
    1052             :                END DO
    1053             :             END DO
    1054         266 :             IF (.NOT. ASSOCIATED(ms_vib%inv_range)) THEN
    1055         222 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) .LE. 400._dp) tmp(i) = 0._dp
    1056             :             ELSE
    1057           0 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) .LE. ms_vib%inv_range(1)) tmp(i) = 0._dp
    1058           0 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) .GE. ms_vib%inv_range(2)) tmp(i) = 0._dp
    1059             :             END IF
    1060             :          END DO
    1061         266 :          tmp(:) = -tmp(:)
    1062          44 :          CALL sort(tmp, (ms_vib%mat_size), ind)
    1063        7876 :          residuum(:, :) = 0._dp
    1064             : 
    1065          88 :          DO j = 1, nrep
    1066         310 :             DO i = 1, ms_vib%mat_size
    1067       39560 :                residuum(:, j) = residuum(:, j) + approx_H(i, ind(j))*(ms_vib%s_mat(:, i) - eigenval(ind(j))*ms_vib%b_mat(:, i))
    1068             :             END DO
    1069             :          END DO
    1070         210 :          DEALLOCATE (tmp_b)
    1071             :       END SELECT
    1072             : 
    1073         344 :       DO j = 1, nrep
    1074        1528 :          DO i = 1, ms_vib%mat_size
    1075      366822 :             residuum(:, j) = residuum(:, j) - DOT_PRODUCT(residuum(:, j), ms_vib%b_mat(:, i))*ms_vib%b_mat(:, i)
    1076             :          END DO
    1077             :       END DO
    1078         166 :       IF (PRESENT(criteria)) THEN
    1079         336 :          DO i = 1, nrep
    1080       23190 :             criteria(1, i) = MAXVAL((residuum(:, i)))
    1081       23178 :             criteria(2, i) = SQRT(DOT_PRODUCT(residuum(:, i), residuum(:, i)))
    1082             :          END DO
    1083             :       END IF
    1084             : 
    1085         344 :       DO i = 1, nrep
    1086       23728 :          norm = SQRT(DOT_PRODUCT(residuum(:, i), residuum(:, i)))
    1087       23894 :          residuum(:, i) = residuum(:, i)/norm
    1088             :       END DO
    1089             : 
    1090        1826 :       DO k = 1, 10
    1091        3606 :          DO j = 1, nrep
    1092       13620 :             DO i = 1, ms_vib%mat_size
    1093     3666440 :                residuum(:, j) = residuum(:, j) - DOT_PRODUCT(residuum(:, j), ms_vib%b_mat(:, i))*ms_vib%b_mat(:, i)
    1094     3668220 :                residuum(:, j) = residuum(:, j)/SQRT(DOT_PRODUCT(residuum(:, j), residuum(:, j)))
    1095             :             END DO
    1096        3440 :             IF (nrep .GT. 1) THEN
    1097         720 :                DO i = 1, nrep
    1098         720 :                   IF (i .NE. j) THEN
    1099        4560 :                      residuum(:, j) = residuum(:, j) - DOT_PRODUCT(residuum(:, j), residuum(:, i))*residuum(:, i)
    1100        4560 :                      residuum(:, j) = residuum(:, j)/SQRT(DOT_PRODUCT(residuum(:, j), residuum(:, j)))
    1101             :                   END IF
    1102             :                END DO
    1103             :             END IF
    1104             :          END DO
    1105             :       END DO
    1106       23894 :       ms_vib%b_vec = residuum
    1107         166 :       DEALLOCATE (tmp)
    1108         166 :    END SUBROUTINE select_vector
    1109             : 
    1110             : ! **************************************************************************************************
    1111             : !> \brief writes the output for a mode tracking calculation
    1112             : !> \param iw ...
    1113             : !> \param converged ...
    1114             : !> \param freq ...
    1115             : !> \param criter ...
    1116             : !> \param ms_vib ...
    1117             : !> \param input ...
    1118             : !> \param nrep ...
    1119             : !> \param approx_H ...
    1120             : !> \param eigenval ...
    1121             : !> \param calc_intens ...
    1122             : !> \param intensities ...
    1123             : !> \param logger ...
    1124             : !> \author Florian Schiffmann 11.2007
    1125             : ! **************************************************************************************************
    1126         162 :    SUBROUTINE ms_out(iw, converged, freq, criter, ms_vib, input, nrep, &
    1127         162 :                      approx_H, eigenval, calc_intens, intensities, logger)
    1128             : 
    1129             :       INTEGER                                            :: iw
    1130             :       LOGICAL                                            :: converged
    1131             :       REAL(KIND=dp), DIMENSION(:)                        :: freq
    1132             :       REAL(KIND=dp), DIMENSION(:, :)                     :: criter
    1133             :       TYPE(ms_vib_type)                                  :: ms_vib
    1134             :       TYPE(section_vals_type), POINTER                   :: input
    1135             :       INTEGER                                            :: nrep
    1136             :       REAL(KIND=dp), DIMENSION(:, :)                     :: approx_H
    1137             :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
    1138             :       LOGICAL                                            :: calc_intens
    1139             :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: intensities
    1140             :       TYPE(cp_logger_type), POINTER                      :: logger
    1141             : 
    1142             :       INTEGER                                            :: i, j, msunit, stat
    1143             :       REAL(KIND=dp)                                      :: crit_a, crit_b, fint, gintval
    1144         162 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: residuum
    1145             :       TYPE(section_vals_type), POINTER                   :: ms_vib_section
    1146             : 
    1147             :       ms_vib_section => section_vals_get_subs_vals(input, &
    1148         162 :                                                    "VIBRATIONAL_ANALYSIS%MODE_SELECTIVE")
    1149             : 
    1150         162 :       fint = 42.255_dp*massunit*debye**2*bohr**2
    1151             : 
    1152         162 :       IF (converged) THEN
    1153          24 :          IF (iw .GT. 0) THEN
    1154          12 :             WRITE (iw, '(T2,A)') "MS| DAVIDSON ALGORITHM CONVERGED"
    1155          26 :             DO i = 1, nrep
    1156          26 :                WRITE (iw, '(T2,"MS| TRACKED FREQUENCY (",I0,") IS:",F12.6,3X,A)') i, freq(i), 'cm-1'
    1157             :             END DO
    1158          36 :             ALLOCATE (residuum(SIZE(ms_vib%b_mat, 1)))
    1159          12 :             WRITE (iw, '( /, 1X, 79("-") )')
    1160          12 :             WRITE (iw, '( 25X, A)') 'FREQUENCY AND CONVERGENCE LIST'
    1161          12 :             IF (PRESENT(intensities)) THEN
    1162          10 :                WRITE (iw, '(3X,5(4X, A))') 'FREQUENCY', 'INT[KM/Mole]', 'MAXVAL CRITERIA', 'NORM CRITERIA', 'CONVERGENCE'
    1163             :             ELSE
    1164           2 :                WRITE (iw, '(3X,5(4X, A))') 'FREQUENCY', 'MAXVAL CRITERIA', 'NORM CRITERIA', 'CONVERGENCE'
    1165             :             END IF
    1166          99 :             DO i = 1, SIZE(ms_vib%b_mat, 2)
    1167       11508 :                residuum = 0._dp
    1168        1134 :                DO j = 1, SIZE(ms_vib%b_mat, 2)
    1169      165609 :                   residuum(:) = residuum(:) + approx_H(j, i)*(ms_vib%s_mat(:, j) - eigenval(i)*ms_vib%b_mat(:, j))
    1170             :                END DO
    1171        1134 :                DO j = 1, ms_vib%mat_size
    1172      330084 :                   residuum(:) = residuum(:) - DOT_PRODUCT(residuum(:), ms_vib%b_mat(:, j))*ms_vib%b_mat(:, j)
    1173             :                END DO
    1174       11595 :                crit_a = MAXVAL(residuum(:))
    1175       11508 :                crit_b = SQRT(DOT_PRODUCT(residuum, residuum))
    1176          99 :                IF (PRESENT(intensities)) THEN
    1177          75 :                   gintval = fint*intensities(i)**2
    1178          75 :                   IF (crit_a .LE. ms_vib%eps(1) .AND. crit_b .LE. ms_vib%eps(2)) THEN
    1179          28 :                      IF (eigenval(i) .GT. ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,1X,F12.6,3X,E12.3,7X,E12.3,11X,A)') &
    1180          26 :                         'VIB|', eigenval(i), gintval, crit_a, crit_b, 'YES'
    1181             :                   ELSE
    1182          47 :                      IF (eigenval(i) .GT. ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,1X,F12.6,3X,E12.3,7X,E12.3,11X,A)') &
    1183          47 :                         'VIB|', eigenval(i), gintval, crit_a, crit_b, 'NO'
    1184             :                   END IF
    1185             :                ELSE
    1186          12 :                   IF (crit_a .LE. ms_vib%eps(1) .AND. crit_b .LE. ms_vib%eps(2)) THEN
    1187          12 :                      IF (eigenval(i) .GT. ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,5X,E12.6,5X,E12.3,11X,A)') &
    1188           6 :                         'VIB|', eigenval(i), crit_a, crit_b, 'YES'
    1189             :                   ELSE
    1190           0 :                      IF (eigenval(i) .GT. ms_vib%low_freq) WRITE (iw, '(2X,A,2X,F9.3,5X,E12.6,5X,E12.3,11X,A)') &
    1191           0 :                         'VIB|', eigenval(i), crit_a, crit_b, 'NO'
    1192             :                   END IF
    1193             :                END IF
    1194             :             END DO
    1195          12 :             DEALLOCATE (residuum)
    1196             : 
    1197             :             msunit = cp_print_key_unit_nr(logger, ms_vib_section, &
    1198             :                                           "PRINT%MS_RESTART", extension=".bin", middle_name="MS_RESTART", &
    1199             :                                           file_status="REPLACE", file_form="UNFORMATTED", &
    1200          12 :                                           file_action="WRITE")
    1201             : 
    1202          12 :             IF (msunit > 0) THEN
    1203          12 :                WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%mat_size
    1204       11520 :                WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%b_mat
    1205       11520 :                WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%s_mat
    1206         312 :                IF (calc_intens) WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%dip_deriv
    1207             :             END IF
    1208             : 
    1209             :             CALL cp_print_key_finished_output(msunit, logger, ms_vib_section, &
    1210          12 :                                               "PRINT%MS_RESTART")
    1211             :          END IF
    1212             :       ELSE
    1213         138 :          IF (iw .GT. 0) THEN
    1214             :             msunit = cp_print_key_unit_nr(logger, ms_vib_section, &
    1215             :                                           "PRINT%MS_RESTART", extension=".bin", middle_name="MS_RESTART", &
    1216             :                                           file_status="REPLACE", file_form="UNFORMATTED", &
    1217          69 :                                           file_action="WRITE")
    1218             : 
    1219          69 :             IF (msunit > 0) THEN
    1220          69 :                WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%mat_size
    1221       76896 :                WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%b_mat
    1222       76896 :                WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%s_mat
    1223        1869 :                IF (calc_intens) WRITE (UNIT=msunit, IOSTAT=stat) ms_vib%dip_deriv
    1224             :             END IF
    1225             : 
    1226             :             CALL cp_print_key_finished_output(msunit, logger, ms_vib_section, &
    1227          69 :                                               "PRINT%MS_RESTART")
    1228             : 
    1229          69 :             WRITE (iw, '(T2,A,3X,I6)') "MS| ITERATION STEP", ms_vib%mat_size/nrep
    1230         142 :             DO i = 1, nrep
    1231         142 :                IF (criter(1, i) .LE. 1E-7 .AND. (criter(2, i)) .LE. 1E-6) THEN
    1232           1 :                   WRITE (iw, '(T2,A,3X,F12.6,A)') "MS| TRACKED MODE ", freq(i), "cm-1  IS  CONVERGED"
    1233             :                ELSE
    1234          72 :                   WRITE (iw, '(T2,A,3X,F12.6,A)') "MS| TRACKED MODE ", freq(i), "cm-1  NOT  CONVERGED"
    1235             :                END IF
    1236             :             END DO
    1237             :          END IF
    1238             :       END IF
    1239             : 
    1240         162 :    END SUBROUTINE ms_out
    1241             : 
    1242             : ! **************************************************************************************************
    1243             : !> \brief ...
    1244             : !> \param ms_vib ...
    1245             : !> \param approx_H ...
    1246             : !> \param eigenval ...
    1247             : !> \param residuum ...
    1248             : !> \param nrep ...
    1249             : !> \param ind ...
    1250             : !> \author Florian Schiffmann 11.2007
    1251             : ! **************************************************************************************************
    1252           6 :    SUBROUTINE get_vibs_in_range(ms_vib, approx_H, eigenval, residuum, nrep, ind)
    1253             : 
    1254             :       TYPE(ms_vib_type)                                  :: ms_vib
    1255             :       REAL(KIND=dp), DIMENSION(:, :)                     :: approx_H
    1256             :       REAL(KIND=dp), DIMENSION(:)                        :: eigenval
    1257             :       REAL(KIND=dp), DIMENSION(:, :)                     :: residuum
    1258             :       INTEGER                                            :: nrep
    1259             :       INTEGER, DIMENSION(:)                              :: ind
    1260             : 
    1261             :       INTEGER                                            :: count1, count2, i, j
    1262           6 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: map2
    1263           6 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: map1
    1264           6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tmp, tmp1
    1265           6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: tmp_resid
    1266             :       REAL(KIND=dp), DIMENSION(2)                        :: myrange
    1267             : 
    1268          18 :       myrange(:) = (ms_vib%f_range(:)/(vibfac))**2/massunit
    1269           6 :       count1 = 0
    1270           6 :       count2 = 0
    1271         126 :       residuum = 0.0_dp
    1272           6 :       ms_vib%mat_size = SIZE(ms_vib%b_mat, 2)
    1273          18 :       ALLOCATE (map1(SIZE(eigenval), 2))
    1274          18 :       ALLOCATE (tmp(SIZE(eigenval)))
    1275          30 :       DO i = 1, SIZE(eigenval)
    1276          24 :          IF (ABS(eigenval(i) - myrange(1)) + ABS(eigenval(i) - myrange(2)) .LE. &
    1277           6 :              ABS(myrange(1) - myrange(2)) + myrange(1)*0.001_dp) THEN
    1278           0 :             count1 = count1 + 1
    1279           0 :             map1(count1, 1) = i
    1280             :          ELSE
    1281          24 :             count2 = count2 + 1
    1282          24 :             map1(count2, 2) = i
    1283          24 :             tmp(count2) = MIN(ABS(eigenval(i) - myrange(1)), ABS(eigenval(i) - myrange(2)))
    1284             :          END IF
    1285             :       END DO
    1286             : 
    1287           6 :       IF (count1 .EQ. nrep) THEN
    1288           0 :          DO j = 1, count1
    1289           0 :             DO i = 1, ms_vib%mat_size
    1290           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))
    1291           0 :                ind(j) = map1(j, 1)
    1292             :             END DO
    1293             :          END DO
    1294           6 :       ELSE IF (count1 .GT. nrep) THEN
    1295           0 :          ALLOCATE (tmp_resid(SIZE(ms_vib%b_mat, 1), count1))
    1296           0 :          ALLOCATE (tmp1(count1))
    1297           0 :          ALLOCATE (map2(count1))
    1298           0 :          tmp_resid = 0._dp
    1299           0 :          DO j = 1, count1
    1300           0 :             DO i = 1, ms_vib%mat_size
    1301             :                tmp_resid(:, j) = tmp_resid(:, j) + approx_H(i, map1(j, 1))* &
    1302           0 :                                  (ms_vib%s_mat(:, i) - eigenval(map1(j, 1))*ms_vib%b_mat(:, i))
    1303             :             END DO
    1304             :          END DO
    1305             : 
    1306           0 :          DO j = 1, count1
    1307           0 :             DO i = 1, ms_vib%mat_size
    1308           0 :                tmp_resid(:, j) = tmp_resid(:, j) - DOT_PRODUCT(tmp_resid(:, j), ms_vib%b_mat(:, i))*ms_vib%b_mat(:, i)
    1309             :             END DO
    1310           0 :             tmp(j) = MAXVAL(tmp_resid(:, j))
    1311             :          END DO
    1312           0 :          CALL sort(tmp, count1, map2)
    1313           0 :          DO j = 1, nrep
    1314           0 :             residuum(:, j) = tmp_resid(:, map2(count1 + 1 - j))
    1315           0 :             ind(j) = map1(map2(count1 + 1 - j), 1)
    1316             :          END DO
    1317           0 :          DEALLOCATE (tmp_resid)
    1318           0 :          DEALLOCATE (tmp1)
    1319           0 :          DEALLOCATE (map2)
    1320           6 :       ELSE IF (count1 .LT. nrep) THEN
    1321             : 
    1322          18 :          ALLOCATE (map2(count2))
    1323           6 :          IF (count1 .NE. 0) THEN
    1324           0 :             DO j = 1, count1
    1325           0 :                DO i = 1, ms_vib%mat_size
    1326             :                   residuum(:, j) = residuum(:, j) + approx_H(i, map1(j, 1))* &
    1327           0 :                                    (ms_vib%s_mat(:, i) - eigenval(map1(j, 1))*ms_vib%b_mat(:, i))
    1328             :                END DO
    1329           0 :                ind(j) = map1(j, 1)
    1330             :             END DO
    1331             :          END IF
    1332           6 :          CALL sort(tmp, count2, map2)
    1333          18 :          DO j = 1, nrep - count1
    1334          60 :             DO i = 1, ms_vib%mat_size
    1335             :                residuum(:, count1 + j) = residuum(:, count1 + j) + approx_H(i, map1(map2(j), 2)) &
    1336         492 :                                          *(ms_vib%s_mat(:, i) - eigenval(map1(map2(j), 2))*ms_vib%b_mat(:, i))
    1337             :             END DO
    1338          18 :             ind(count1 + j) = map1(map2(j), 2)
    1339             :          END DO
    1340             : 
    1341           6 :          DEALLOCATE (map2)
    1342             :       END IF
    1343             : 
    1344           6 :       DEALLOCATE (map1)
    1345           6 :       DEALLOCATE (tmp)
    1346             : 
    1347           6 :    END SUBROUTINE get_vibs_in_range
    1348           0 : END MODULE mode_selective

Generated by: LCOV version 1.15