LCOV - code coverage report
Current view: top level - src - mode_selective.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 91.9 % 665 611
Test Date: 2025-12-04 06:27:48 Functions: 90.0 % 10 9

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 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 /= 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) > 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 > 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 >= 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 /= 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) > 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 > 1) THEN
     382           44 :             DO k = 1, 10
     383          124 :                DO j = 1, nrep
     384          280 :                   DO i = 1, nrep
     385          240 :                      IF (i /= 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) <= 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 /= 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 /= "") 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) <= 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 /= 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 /= 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 /= 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, :)) <= ms_vib%eps(1) .AND. MAXVAL(criteria(2, :)) &
     928          834 :           <= ms_vib%eps(2) .OR. ms_vib%mat_size >= 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 > 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) <= 400._dp) tmp(i) = 0._dp
    1056              :             ELSE
    1057            0 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) <= ms_vib%inv_range(1)) tmp(i) = 0._dp
    1058            0 :                IF ((SIGN(1._dp, eigenval(i))*SQRT(ABS(eigenval(i))*massunit)*vibfac) >= 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 > 1) THEN
    1097          720 :                DO i = 1, nrep
    1098          720 :                   IF (i /= 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 > 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 <= ms_vib%eps(1) .AND. crit_b <= ms_vib%eps(2)) THEN
    1179           28 :                      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)') &
    1180           26 :                         'VIB|', eigenval(i), gintval, crit_a, crit_b, 'YES'
    1181              :                   ELSE
    1182           47 :                      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)') &
    1183           47 :                         'VIB|', eigenval(i), gintval, crit_a, crit_b, 'NO'
    1184              :                   END IF
    1185              :                ELSE
    1186           12 :                   IF (crit_a <= ms_vib%eps(1) .AND. crit_b <= ms_vib%eps(2)) THEN
    1187           12 :                      IF (eigenval(i) > 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) > 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 > 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) <= 1E-7 .AND. (criter(2, i)) <= 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)) <= &
    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 == 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 > 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 < nrep) THEN
    1321              : 
    1322           18 :          ALLOCATE (map2(count2))
    1323            6 :          IF (count1 /= 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 2.0-1