LCOV - code coverage report
Current view: top level - src - qs_vcd_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 88.5 % 445 394
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 5 5

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : MODULE qs_vcd_utils
       9              :    USE cell_types,                      ONLY: cell_type
      10              :    USE commutator_rpnl,                 ONLY: build_com_mom_nl
      11              :    USE cp_control_types,                ONLY: dft_control_type
      12              :    USE cp_dbcsr_api,                    ONLY: dbcsr_copy,&
      13              :                                               dbcsr_create,&
      14              :                                               dbcsr_init_p,&
      15              :                                               dbcsr_p_type,&
      16              :                                               dbcsr_set,&
      17              :                                               dbcsr_type_antisymmetric,&
      18              :                                               dbcsr_type_no_symmetry
      19              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      20              :    USE cp_dbcsr_operations,             ONLY: dbcsr_allocate_matrix_set,&
      21              :                                               dbcsr_deallocate_matrix_set
      22              :    USE cp_files,                        ONLY: close_file,&
      23              :                                               open_file
      24              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      25              :                                               cp_fm_get_info,&
      26              :                                               cp_fm_get_submatrix,&
      27              :                                               cp_fm_release,&
      28              :                                               cp_fm_set_submatrix,&
      29              :                                               cp_fm_type
      30              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      31              :                                               cp_logger_get_default_io_unit,&
      32              :                                               cp_logger_type,&
      33              :                                               cp_to_string
      34              :    USE cp_output_handling,              ONLY: cp_p_file,&
      35              :                                               cp_print_key_finished_output,&
      36              :                                               cp_print_key_generate_filename,&
      37              :                                               cp_print_key_should_output,&
      38              :                                               cp_print_key_unit_nr
      39              :    USE cp_result_methods,               ONLY: get_results
      40              :    USE cp_result_types,                 ONLY: cp_result_type
      41              :    USE input_constants,                 ONLY: use_mom_ref_user
      42              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      43              :                                               section_vals_type,&
      44              :                                               section_vals_val_get
      45              :    USE kinds,                           ONLY: default_path_length,&
      46              :                                               default_string_length,&
      47              :                                               dp
      48              :    USE message_passing,                 ONLY: mp_para_env_type
      49              :    USE molecule_types,                  ONLY: molecule_type
      50              :    USE moments_utils,                   ONLY: get_reference_point
      51              :    USE orbital_pointers,                ONLY: init_orbital_pointers
      52              :    USE particle_types,                  ONLY: particle_type
      53              :    USE qs_dcdr_utils,                   ONLY: dcdr_env_cleanup,&
      54              :                                               dcdr_env_init
      55              :    USE qs_environment_types,            ONLY: get_qs_env,&
      56              :                                               qs_environment_type
      57              :    USE qs_kind_types,                   ONLY: qs_kind_type
      58              :    USE qs_ks_types,                     ONLY: qs_ks_env_type
      59              :    USE qs_linres_types,                 ONLY: vcd_env_type
      60              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      61              :                                               mo_set_type
      62              :    USE qs_moments,                      ONLY: build_local_moments_der_matrix
      63              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      64              :    USE qs_operators_ao,                 ONLY: build_lin_mom_matrix
      65              :    USE qs_vcd_ao,                       ONLY: build_com_rpnl_r,&
      66              :                                               build_matrix_r_vhxc,&
      67              :                                               build_rcore_matrix,&
      68              :                                               build_rpnl_matrix,&
      69              :                                               build_tr_matrix
      70              :    USE string_utilities,                ONLY: xstring
      71              : #include "./base/base_uses.f90"
      72              : 
      73              :    IMPLICIT NONE
      74              : 
      75              :    PRIVATE
      76              :    PUBLIC :: vcd_env_cleanup, vcd_env_init
      77              :    PUBLIC :: vcd_read_restart, vcd_write_restart
      78              :    PUBLIC :: vcd_print
      79              : 
      80              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_vcd_utils'
      81              : 
      82              :    REAL(dp), DIMENSION(3, 3, 3), PARAMETER  :: Levi_Civita = RESHAPE([ &
      83              :                                                           0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, -1.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, &
      84              :                                                           0.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, -1.0_dp, 0.0_dp, 0.0_dp, &
      85              :                                                 0.0_dp, -1.0_dp, 0.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp], [3, 3, 3])
      86              : 
      87              : CONTAINS
      88              : 
      89              : ! *****************************************************************************
      90              : !> \brief Initialize the vcd environment
      91              : !> \param vcd_env ...
      92              : !> \param qs_env ...
      93              : !> \author Edward Ditler
      94              : ! **************************************************************************************************
      95            2 :    SUBROUTINE vcd_env_init(vcd_env, qs_env)
      96              :       TYPE(vcd_env_type), TARGET                         :: vcd_env
      97              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      98              : 
      99              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'vcd_env_init'
     100              : 
     101              :       INTEGER                                            :: handle, i, idir, ispin, j, natom, &
     102              :                                                             nspins, output_unit, reference, &
     103              :                                                             unit_number
     104              :       LOGICAL                                            :: explicit
     105            2 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: ref_point
     106              :       TYPE(cell_type), POINTER                           :: cell
     107              :       TYPE(cp_logger_type), POINTER                      :: logger
     108            2 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, my_matrix_hr_1d
     109              :       TYPE(dft_control_type), POINTER                    :: dft_control
     110              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     111            2 :          POINTER                                         :: sab_all, sab_orb, sap_ppnl
     112            2 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     113            2 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     114              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     115              :       TYPE(section_vals_type), POINTER                   :: lr_section, vcd_section
     116              : 
     117            2 :       CALL timeset(routineN, handle)
     118            2 :       vcd_env%do_mfp = .FALSE.
     119              : 
     120              :       ! Set up the logger
     121            2 :       NULLIFY (logger, vcd_section, lr_section)
     122            2 :       logger => cp_get_default_logger()
     123            2 :       vcd_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES%VCD")
     124              :       vcd_env%output_unit = cp_print_key_unit_nr(logger, vcd_section, "PRINT%VCD", &
     125              :                                                  extension=".data", middle_name="vcd", log_filename=.FALSE., &
     126            2 :                                                  file_position="REWIND", file_status="REPLACE")
     127              : 
     128            2 :       lr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES")
     129              :       output_unit = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", &
     130            2 :                                          extension=".linresLog")
     131            2 :       unit_number = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", extension=".linresLog")
     132              : 
     133              :       ! We can't run a NVPT/MFPT calculation without the coefficients dC/dR.
     134            2 :       CALL dcdr_env_init(vcd_env%dcdr_env, qs_env)
     135              :       ! vcd_env%dcdr_env%output_unit = vcd_env%output_unit
     136              : 
     137            2 :       IF (output_unit > 0) THEN
     138            1 :          WRITE (output_unit, "(/,T20,A,/)") "*** Start NVPT/MFPT calculation ***"
     139              :       END IF
     140              : 
     141              :       ! Just to make sure. The memory requirements are tiny.
     142            2 :       CALL init_orbital_pointers(12)
     143              : 
     144            2 :       CALL section_vals_val_get(vcd_section, "DISTRIBUTED_ORIGIN", l_val=vcd_env%distributed_origin)
     145            2 :       CALL section_vals_val_get(vcd_section, "ORIGIN_DEPENDENT_MFP", l_val=vcd_env%origin_dependent_op_mfp)
     146              : 
     147              :       ! Reference point
     148            8 :       vcd_env%magnetic_origin = 0._dp
     149            8 :       vcd_env%spatial_origin = 0._dp
     150              :       ! Get the magnetic origin from the input
     151            2 :       CALL section_vals_val_get(vcd_section, "MAGNETIC_ORIGIN", i_val=reference)
     152            2 :       CALL section_vals_val_get(vcd_section, "MAGNETIC_ORIGIN_REFERENCE", explicit=explicit)
     153            2 :       IF (explicit) THEN
     154            0 :          CALL section_vals_val_get(vcd_section, "MAGNETIC_ORIGIN_REFERENCE", r_vals=ref_point)
     155              :       ELSE
     156            2 :          IF (reference == use_mom_ref_user) THEN
     157            0 :             CPABORT("User-defined reference point should be given explicitly")
     158              :          END IF
     159              :       END IF
     160              : 
     161              :       CALL get_reference_point(rpoint=vcd_env%magnetic_origin, qs_env=qs_env, &
     162              :                                reference=reference, &
     163            2 :                                ref_point=ref_point)
     164              : 
     165              :       ! Get the spatial origin from the input
     166            2 :       CALL section_vals_val_get(vcd_section, "SPATIAL_ORIGIN", i_val=reference)
     167            2 :       CALL section_vals_val_get(vcd_section, "SPATIAL_ORIGIN_REFERENCE", explicit=explicit)
     168            2 :       IF (explicit) THEN
     169            0 :          CALL section_vals_val_get(vcd_section, "SPATIAL_ORIGIN_REFERENCE", r_vals=ref_point)
     170              :       ELSE
     171            2 :          IF (reference == use_mom_ref_user) THEN
     172            0 :             CPABORT("User-defined reference point should be given explicitly")
     173              :          END IF
     174              :       END IF
     175              : 
     176              :       CALL get_reference_point(rpoint=vcd_env%spatial_origin, qs_env=qs_env, &
     177              :                                reference=reference, &
     178            2 :                                ref_point=ref_point)
     179              : 
     180            8 :       IF (vcd_env%distributed_origin .AND. ANY(vcd_env%magnetic_origin /= vcd_env%spatial_origin)) THEN
     181            0 :          CPWARN("The magnetic and spatial origins don't match")
     182              :          ! This is fine for NVP but will give unphysical results for MFP.
     183              :       END IF
     184              : 
     185            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,3F10.6)") &
     186            1 :          'The reference point is', vcd_env%dcdr_env%ref_point
     187            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,3F10.6)") &
     188            1 :          'The magnetic origin is', vcd_env%magnetic_origin
     189            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,3F10.6)") &
     190            1 :          'The velocity origin is', vcd_env%spatial_origin
     191              : 
     192            8 :       vcd_env%magnetic_origin_atom = vcd_env%magnetic_origin
     193            8 :       vcd_env%spatial_origin_atom = vcd_env%spatial_origin
     194              : 
     195              :       CALL get_qs_env(qs_env=qs_env, &
     196              :                       ks_env=ks_env, &
     197              :                       dft_control=dft_control, &
     198              :                       sab_orb=sab_orb, &
     199              :                       sab_all=sab_all, &
     200              :                       sap_ppnl=sap_ppnl, &
     201              :                       particle_set=particle_set, &
     202              :                       matrix_ks=matrix_ks, &
     203              :                       cell=cell, &
     204            2 :                       qs_kind_set=qs_kind_set)
     205              : 
     206            2 :       natom = SIZE(particle_set)
     207            2 :       nspins = dft_control%nspins
     208              : 
     209            6 :       ALLOCATE (vcd_env%apt_el_nvpt(3, 3, natom))
     210            4 :       ALLOCATE (vcd_env%apt_nuc_nvpt(3, 3, natom))
     211            4 :       ALLOCATE (vcd_env%apt_total_nvpt(3, 3, natom))
     212            4 :       ALLOCATE (vcd_env%aat_atom_nvpt(3, 3, natom))
     213            4 :       ALLOCATE (vcd_env%aat_atom_mfp(3, 3, natom))
     214           80 :       vcd_env%apt_el_nvpt = 0._dp
     215           80 :       vcd_env%apt_nuc_nvpt = 0._dp
     216           80 :       vcd_env%apt_total_nvpt = 0._dp
     217           80 :       vcd_env%aat_atom_nvpt = 0._dp
     218           80 :       vcd_env%aat_atom_mfp = 0._dp
     219              : 
     220            8 :       ALLOCATE (vcd_env%dCV(nspins))
     221            6 :       ALLOCATE (vcd_env%dCV_prime(nspins))
     222            6 :       ALLOCATE (vcd_env%op_dV(nspins))
     223            6 :       ALLOCATE (vcd_env%op_dB(nspins))
     224            4 :       DO ispin = 1, nspins
     225            2 :          CALL cp_fm_create(vcd_env%dCV(ispin), vcd_env%dcdr_env%likemos_fm_struct(1)%struct, set_zero=.TRUE.)
     226            2 :          CALL cp_fm_create(vcd_env%dCV_prime(ispin), vcd_env%dcdr_env%likemos_fm_struct(1)%struct, set_zero=.TRUE.)
     227            2 :          CALL cp_fm_create(vcd_env%op_dV(ispin), vcd_env%dcdr_env%likemos_fm_struct(1)%struct, set_zero=.TRUE.)
     228            4 :          CALL cp_fm_create(vcd_env%op_dB(ispin), vcd_env%dcdr_env%likemos_fm_struct(1)%struct, set_zero=.TRUE.)
     229              :       END DO
     230              : 
     231            8 :       ALLOCATE (vcd_env%dCB(3))
     232            8 :       ALLOCATE (vcd_env%dCB_prime(3))
     233            8 :       DO i = 1, 3
     234            6 :          CALL cp_fm_create(vcd_env%dCB(i), vcd_env%dcdr_env%likemos_fm_struct(1)%struct, set_zero=.TRUE.)
     235            8 :          CALL cp_fm_create(vcd_env%dCB_prime(i), vcd_env%dcdr_env%likemos_fm_struct(1)%struct, set_zero=.TRUE.)
     236              :       END DO
     237              : 
     238              :       ! DBCSR matrices
     239            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%moments_der, 9, 3)
     240            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%moments_der_right, 9, 3)
     241            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%moments_der_left, 9, 3)
     242            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_difdip2, 3, 3)
     243            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_dSdV, 3)
     244            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_dSdB, 3)
     245            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_hxc_dsdv, nspins)
     246              : 
     247            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%hcom, 3)
     248            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_rcomr, 3, 3)
     249            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_rrcom, 3, 3)
     250            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_dcom, 3, 3)
     251            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_hr, nspins, 3)
     252            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_rh, nspins, 3)
     253            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_drpnl, 3)
     254            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%dipvel_ao, 3)
     255            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%dipvel_ao_delta, 3)
     256            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_rxrv, 3)
     257            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_r_rxvr, 3, 3)
     258            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_rxvr_r, 3, 3)
     259            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_r_doublecom, 3, 3)
     260              : 
     261            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_nosym_temp_33, 3, 3)
     262            2 :       CALL dbcsr_allocate_matrix_set(vcd_env%matrix_nosym_temp2_33, 3, 3)
     263           20 :       DO i = 1, 9 ! x, y, z, xx, xy, xz, yy, yz, zz
     264           74 :          DO idir = 1, 3 ! d/dx, d/dy, d/dz
     265           54 :             CALL dbcsr_init_p(vcd_env%moments_der(i, idir)%matrix)
     266           54 :             CALL dbcsr_init_p(vcd_env%moments_der_right(i, idir)%matrix)
     267           54 :             CALL dbcsr_init_p(vcd_env%moments_der_left(i, idir)%matrix)
     268              : 
     269              :             CALL dbcsr_create(vcd_env%moments_der(i, idir)%matrix, template=matrix_ks(1)%matrix, &
     270           54 :                               matrix_type=dbcsr_type_antisymmetric)
     271           54 :             CALL cp_dbcsr_alloc_block_from_nbl(vcd_env%moments_der(i, idir)%matrix, sab_orb)
     272           54 :             CALL dbcsr_set(vcd_env%moments_der(i, idir)%matrix, 0.0_dp)
     273              : 
     274              :             ! And the ones which will be multiplied by delta_(mu/nu)
     275              :             CALL dbcsr_copy(vcd_env%moments_der_right(i, idir)%matrix, &
     276           54 :                             vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     277              :             CALL dbcsr_copy(vcd_env%moments_der_left(i, idir)%matrix, &
     278           72 :                             vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     279              :          END DO
     280              :       END DO
     281              : 
     282            8 :       DO i = 1, 3
     283           24 :          DO j = 1, 3
     284           18 :             CALL dbcsr_init_p(vcd_env%matrix_difdip2(i, j)%matrix)
     285           18 :             CALL dbcsr_copy(vcd_env%matrix_difdip2(i, j)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     286           18 :             CALL dbcsr_set(vcd_env%matrix_difdip2(i, j)%matrix, 0.0_dp)
     287              : 
     288           18 :             CALL dbcsr_init_p(vcd_env%matrix_nosym_temp_33(i, j)%matrix)
     289              :             CALL dbcsr_create(vcd_env%matrix_nosym_temp_33(i, j)%matrix, template=matrix_ks(1)%matrix, &
     290           18 :                               matrix_type=dbcsr_type_no_symmetry)
     291           18 :             CALL cp_dbcsr_alloc_block_from_nbl(vcd_env%matrix_nosym_temp_33(i, j)%matrix, sab_all)
     292           18 :             CALL dbcsr_set(vcd_env%matrix_nosym_temp_33(i, j)%matrix, 0._dp)
     293              : 
     294           18 :             CALL dbcsr_init_p(vcd_env%matrix_nosym_temp2_33(i, j)%matrix)
     295              :             CALL dbcsr_create(vcd_env%matrix_nosym_temp2_33(i, j)%matrix, template=matrix_ks(1)%matrix, &
     296           18 :                               matrix_type=dbcsr_type_no_symmetry)
     297           18 :             CALL cp_dbcsr_alloc_block_from_nbl(vcd_env%matrix_nosym_temp2_33(i, j)%matrix, sab_all)
     298           24 :             CALL dbcsr_set(vcd_env%matrix_nosym_temp2_33(i, j)%matrix, 0._dp)
     299              : 
     300              :          END DO
     301            6 :          CALL dbcsr_init_p(vcd_env%matrix_dSdV(i)%matrix)
     302            6 :          CALL dbcsr_copy(vcd_env%matrix_dSdV(i)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     303            6 :          CALL dbcsr_init_p(vcd_env%matrix_dSdB(i)%matrix)
     304            8 :          CALL dbcsr_copy(vcd_env%matrix_dSdB(i)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     305              :       END DO
     306              : 
     307            4 :       DO ispin = 1, nspins
     308            2 :          CALL dbcsr_init_p(vcd_env%matrix_hxc_dsdv(ispin)%matrix)
     309            4 :          CALL dbcsr_copy(vcd_env%matrix_hxc_dsdv(ispin)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     310              :       END DO
     311              : 
     312              :       ! Things for op_dV
     313              :       ! lin_mom
     314            8 :       DO i = 1, 3
     315            6 :          CALL dbcsr_init_p(vcd_env%dipvel_ao(i)%matrix)
     316            6 :          CALL dbcsr_copy(vcd_env%dipvel_ao(i)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     317              : 
     318            6 :          CALL dbcsr_init_p(vcd_env%dipvel_ao_delta(i)%matrix)
     319            8 :          CALL dbcsr_copy(vcd_env%dipvel_ao_delta(i)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     320              :       END DO
     321              : 
     322              :       ! [V, r]
     323            8 :       DO i = 1, 3
     324            6 :          CALL dbcsr_init_p(vcd_env%hcom(i)%matrix)
     325              :          CALL dbcsr_create(vcd_env%hcom(i)%matrix, template=matrix_ks(1)%matrix, &
     326            6 :                            matrix_type=dbcsr_type_antisymmetric)
     327            6 :          CALL cp_dbcsr_alloc_block_from_nbl(vcd_env%hcom(i)%matrix, sab_orb)
     328              : 
     329            6 :          CALL dbcsr_init_p(vcd_env%matrix_rxrv(i)%matrix)
     330              :          CALL dbcsr_create(vcd_env%matrix_rxrv(i)%matrix, template=matrix_ks(1)%matrix, &
     331            6 :                            matrix_type=dbcsr_type_antisymmetric)
     332            6 :          CALL cp_dbcsr_alloc_block_from_nbl(vcd_env%matrix_rxrv(i)%matrix, sab_orb)
     333              : 
     334           26 :          DO j = 1, 3
     335           18 :             CALL dbcsr_init_p(vcd_env%matrix_rcomr(i, j)%matrix)
     336           18 :             CALL dbcsr_copy(vcd_env%matrix_rcomr(i, j)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     337           18 :             CALL dbcsr_init_p(vcd_env%matrix_rrcom(i, j)%matrix)
     338           18 :             CALL dbcsr_copy(vcd_env%matrix_rrcom(i, j)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     339           18 :             CALL dbcsr_init_p(vcd_env%matrix_dcom(i, j)%matrix)
     340           18 :             CALL dbcsr_copy(vcd_env%matrix_dcom(i, j)%matrix, matrix_ks(1)%matrix)
     341           18 :             CALL dbcsr_set(vcd_env%matrix_dcom(i, j)%matrix, 0._dp)
     342              : 
     343           18 :             CALL dbcsr_init_p(vcd_env%matrix_r_rxvr(i, j)%matrix)
     344           18 :             CALL dbcsr_copy(vcd_env%matrix_r_rxvr(i, j)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     345           18 :             CALL dbcsr_set(vcd_env%matrix_r_rxvr(i, j)%matrix, 0._dp)
     346              : 
     347           18 :             CALL dbcsr_init_p(vcd_env%matrix_rxvr_r(i, j)%matrix)
     348           18 :             CALL dbcsr_copy(vcd_env%matrix_rxvr_r(i, j)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     349           18 :             CALL dbcsr_set(vcd_env%matrix_rxvr_r(i, j)%matrix, 0._dp)
     350              : 
     351           18 :             CALL dbcsr_init_p(vcd_env%matrix_r_doublecom(i, j)%matrix)
     352           18 :             CALL dbcsr_copy(vcd_env%matrix_r_doublecom(i, j)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     353           24 :             CALL dbcsr_set(vcd_env%matrix_r_doublecom(i, j)%matrix, 0._dp)
     354              :          END DO
     355              :       END DO
     356              : 
     357              :       ! matrix_hr: nonsymmetric dbcsr matrix
     358            4 :       DO ispin = 1, nspins
     359           10 :          DO i = 1, 3
     360            6 :             CALL dbcsr_init_p(vcd_env%matrix_hr(ispin, i)%matrix)
     361            6 :             CALL dbcsr_copy(vcd_env%matrix_hr(ispin, i)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     362              : 
     363            6 :             CALL dbcsr_init_p(vcd_env%matrix_rh(ispin, i)%matrix)
     364            8 :             CALL dbcsr_copy(vcd_env%matrix_rh(ispin, i)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     365              :          END DO
     366              :       END DO
     367              : 
     368              :       ! drpnl for the operator
     369            8 :       DO i = 1, 3
     370            6 :          CALL dbcsr_init_p(vcd_env%matrix_drpnl(i)%matrix)
     371            8 :          CALL dbcsr_copy(vcd_env%matrix_drpnl(i)%matrix, vcd_env%dcdr_env%matrix_nosym_temp(1)%matrix)
     372              :       END DO
     373              : 
     374              :       ! NVP matrices
     375              :       ! hr matrices
     376            2 :       my_matrix_hr_1d => vcd_env%matrix_hr(1, 1:3)
     377              :       CALL build_rpnl_matrix(my_matrix_hr_1d, qs_kind_set, particle_set, sab_all, sap_ppnl, &
     378              :                              dft_control%qs_control%eps_ppnl, cell, [0._dp, 0._dp, 0._dp], &
     379            2 :                              direction_Or=.TRUE.)
     380              :       CALL build_tr_matrix(my_matrix_hr_1d, qs_env, qs_kind_set, "ORB", sab_all, &
     381            2 :                            direction_Or=.TRUE., rc=[0._dp, 0._dp, 0._dp])
     382            2 :       CALL build_rcore_matrix(my_matrix_hr_1d, qs_env, qs_kind_set, "ORB", sab_all, [0._dp, 0._dp, 0._dp])
     383            2 :       CALL build_matrix_r_vhxc(vcd_env%matrix_hr, qs_env, [0._dp, 0._dp, 0._dp])
     384              : 
     385            2 :       my_matrix_hr_1d => vcd_env%matrix_rh(1, 1:3)
     386              :       CALL build_rpnl_matrix(my_matrix_hr_1d, qs_kind_set, particle_set, sab_all, sap_ppnl, &
     387              :                              dft_control%qs_control%eps_ppnl, cell, [0._dp, 0._dp, 0._dp], &
     388            2 :                              direction_Or=.FALSE.)
     389              :       CALL build_tr_matrix(my_matrix_hr_1d, qs_env, qs_kind_set, "ORB", sab_all, &
     390            2 :                            direction_Or=.FALSE., rc=[0._dp, 0._dp, 0._dp])
     391            2 :       CALL build_rcore_matrix(my_matrix_hr_1d, qs_env, qs_kind_set, "ORB", sab_all, [0._dp, 0._dp, 0._dp])
     392            2 :       CALL build_matrix_r_vhxc(vcd_env%matrix_rh, qs_env, [0._dp, 0._dp, 0._dp])
     393              : 
     394              :       ! commutator terms
     395              :       ! - [V, r]
     396              :       CALL build_com_mom_nl(qs_kind_set, sab_orb, sap_ppnl, dft_control%qs_control%eps_ppnl, &
     397            2 :                             particle_set, cell=cell, matrix_rv=vcd_env%hcom)
     398              :       ! <[V, r] * r> and <r * [V, r]>
     399              :       CALL build_com_rpnl_r(vcd_env%matrix_rcomr, qs_kind_set, sab_all, sap_ppnl, &
     400            2 :                             dft_control%qs_control%eps_ppnl, particle_set, cell, .TRUE.)
     401              :       CALL build_com_rpnl_r(vcd_env%matrix_rrcom, qs_kind_set, sab_all, sap_ppnl, &
     402            2 :                             dft_control%qs_control%eps_ppnl, particle_set, cell, .FALSE.)
     403              : 
     404              :       ! lin_mom
     405            2 :       CALL build_lin_mom_matrix(qs_env, vcd_env%dipvel_ao)
     406              : 
     407              :       ! AAT
     408              :       ! The moments are set to zero and then recomputed in the routine.
     409              :       CALL build_local_moments_der_matrix(qs_env, moments_der=vcd_env%moments_der, &
     410            2 :                                           nmoments_der=2, nmoments=0, ref_point=[0._dp, 0._dp, 0._dp])
     411              : 
     412              :       ! PP terms
     413              :       CALL build_com_mom_nl(qs_kind_set, sab_orb, sap_ppnl, dft_control%qs_control%eps_ppnl, &
     414              :                             particle_set, matrix_rxrv=vcd_env%matrix_rxrv, ref_point=[0._dp, 0._dp, 0._dp], &
     415            2 :                             cell=cell)
     416              : 
     417              :       CALL build_com_mom_nl(qs_kind_set, sab_all, sap_ppnl, dft_control%qs_control%eps_ppnl, &
     418              :                             particle_set, ref_point=[0._dp, 0._dp, 0._dp], cell=cell, &
     419            2 :                             matrix_r_rxvr=vcd_env%matrix_r_rxvr)
     420              : 
     421              :       CALL build_com_mom_nl(qs_kind_set, sab_all, sap_ppnl, dft_control%qs_control%eps_ppnl, &
     422              :                             particle_set, ref_point=[0._dp, 0._dp, 0._dp], cell=cell, &
     423            2 :                             matrix_rxvr_r=vcd_env%matrix_rxvr_r)
     424              : 
     425              :       ! Done with NVP matrices
     426              : 
     427              :       CALL cp_print_key_finished_output(output_unit, logger, lr_section, &
     428            2 :                                         "PRINT%PROGRAM_RUN_INFO")
     429              : 
     430            2 :       CALL timestop(handle)
     431              : 
     432            6 :    END SUBROUTINE vcd_env_init
     433              : 
     434              : ! *****************************************************************************
     435              : !> \brief Deallocate the vcd environment
     436              : !> \param qs_env ...
     437              : !> \param vcd_env ...
     438              : !> \author Edward Ditler
     439              : ! **************************************************************************************************
     440            2 :    SUBROUTINE vcd_env_cleanup(qs_env, vcd_env)
     441              : 
     442              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     443              :       TYPE(vcd_env_type)                                 :: vcd_env
     444              : 
     445              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'vcd_env_cleanup'
     446              : 
     447              :       INTEGER                                            :: handle
     448              : 
     449            2 :       CALL timeset(routineN, handle)
     450              : 
     451              :       ! We can't run a NVPT/MFPT calculation without the coefficients dC/dR.
     452            2 :       CALL dcdr_env_cleanup(qs_env, vcd_env%dcdr_env)
     453              : 
     454            2 :       DEALLOCATE (vcd_env%apt_el_nvpt)
     455            2 :       DEALLOCATE (vcd_env%apt_nuc_nvpt)
     456            2 :       DEALLOCATE (vcd_env%apt_total_nvpt)
     457            2 :       DEALLOCATE (vcd_env%aat_atom_nvpt)
     458            2 :       DEALLOCATE (vcd_env%aat_atom_mfp)
     459              : 
     460            2 :       CALL cp_fm_release(vcd_env%dCV)
     461            2 :       CALL cp_fm_release(vcd_env%dCV_prime)
     462            2 :       CALL cp_fm_release(vcd_env%op_dV)
     463            2 :       CALL cp_fm_release(vcd_env%op_dB)
     464              : 
     465            2 :       CALL cp_fm_release(vcd_env%dCB)
     466            2 :       CALL cp_fm_release(vcd_env%dCB_prime)
     467              : 
     468              :       ! DBCSR matrices
     469              :       ! Probably, the memory requirements could be reduced by quite a bit
     470              :       ! by not storing each term in its own set of matrices.
     471              :       ! On the other hand, the memory bottleneck is usually the numerical
     472              :       ! integration grid.
     473            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%moments_der)
     474            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%moments_der_right)
     475            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%moments_der_left)
     476            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_difdip2)
     477            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_dSdV)
     478            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_dSdB)
     479            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_hxc_dsdv)
     480            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%hcom)
     481            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_rcomr)
     482            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_rrcom)
     483            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_dcom)
     484            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_hr)
     485            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_rh)
     486            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_drpnl)
     487            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%dipvel_ao)
     488            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%dipvel_ao_delta)
     489            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_rxrv)
     490            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_r_rxvr)
     491            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_rxvr_r)
     492            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_r_doublecom)
     493            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_nosym_temp_33)
     494            2 :       CALL dbcsr_deallocate_matrix_set(vcd_env%matrix_nosym_temp2_33)
     495            2 :       CALL timestop(handle)
     496              : 
     497            2 :    END SUBROUTINE vcd_env_cleanup
     498              : 
     499              : ! **************************************************************************************************
     500              : !> \brief Copied from linres_read_restart
     501              : !> \param qs_env ...
     502              : !> \param linres_section ...
     503              : !> \param vec ...
     504              : !> \param lambda ...
     505              : !> \param beta ...
     506              : !> \param tag ...
     507              : !> \author Edward Ditler
     508              : ! **************************************************************************************************
     509           18 :    SUBROUTINE vcd_read_restart(qs_env, linres_section, vec, lambda, beta, tag)
     510              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     511              :       TYPE(section_vals_type), POINTER                   :: linres_section
     512              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     513              :       INTEGER, INTENT(IN)                                :: lambda, beta
     514              :       CHARACTER(LEN=*)                                   :: tag
     515              : 
     516              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'vcd_read_restart'
     517              : 
     518              :       CHARACTER(LEN=default_path_length)                 :: filename
     519              :       CHARACTER(LEN=default_string_length)               :: my_middle
     520              :       INTEGER :: beta_tmp, handle, i, i_block, ia, ie, iostat, iounit, ispin, j, lambda_tmp, &
     521              :          max_block, n_rep_val, nao, nao_tmp, nmo, nmo_tmp, nspins, nspins_tmp, rst_unit
     522              :       LOGICAL                                            :: file_exists
     523           18 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     524              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     525              :       TYPE(cp_logger_type), POINTER                      :: logger
     526           18 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     527              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     528              :       TYPE(section_vals_type), POINTER                   :: print_key
     529              : 
     530           18 :       file_exists = .FALSE.
     531              : 
     532           18 :       CALL timeset(routineN, handle)
     533              : 
     534           18 :       NULLIFY (mos, para_env, logger, print_key, vecbuffer)
     535           18 :       logger => cp_get_default_logger()
     536              : 
     537              :       iounit = cp_print_key_unit_nr(logger, linres_section, &
     538           18 :                                     "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     539              : 
     540              :       CALL get_qs_env(qs_env=qs_env, &
     541              :                       para_env=para_env, &
     542           18 :                       mos=mos)
     543              : 
     544           18 :       nspins = SIZE(mos)
     545              : 
     546           18 :       rst_unit = -1
     547           18 :       IF (para_env%is_source()) THEN
     548              :          CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", &
     549            9 :                                    n_rep_val=n_rep_val)
     550              : 
     551            9 :          CALL XSTRING(tag, ia, ie)
     552              :          my_middle = "RESTART-"//tag(ia:ie)//TRIM("-")//TRIM(ADJUSTL(cp_to_string(beta))) &
     553            9 :                      //TRIM("-")//TRIM(ADJUSTL(cp_to_string(lambda)))
     554              : 
     555            9 :          IF (n_rep_val > 0) THEN
     556            0 :             CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", c_val=filename)
     557            0 :             CALL xstring(filename, ia, ie)
     558            0 :             filename = filename(ia:ie)//TRIM(my_middle)//".lr"
     559              :          ELSE
     560              :             ! try to read from the filename that is generated automatically from the printkey
     561            9 :             print_key => section_vals_get_subs_vals(linres_section, "PRINT%RESTART")
     562              :             filename = cp_print_key_generate_filename(logger, print_key, &
     563            9 :                                                       extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     564              :          END IF
     565            9 :          INQUIRE (FILE=filename, exist=file_exists)
     566              :          !
     567              :          ! open file
     568            9 :          IF (file_exists) THEN
     569              :             CALL open_file(file_name=TRIM(filename), &
     570              :                            file_action="READ", &
     571              :                            file_form="UNFORMATTED", &
     572              :                            file_position="REWIND", &
     573              :                            file_status="OLD", &
     574            0 :                            unit_number=rst_unit)
     575              : 
     576            0 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     577            0 :                "LINRES| Reading response wavefunctions from the restart file <"//TRIM(ADJUSTL(filename))//">"
     578              :          ELSE
     579            9 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     580            9 :                "LINRES| Restart file  <"//TRIM(ADJUSTL(filename))//"> not found"
     581              :          END IF
     582              :       END IF
     583              : 
     584           18 :       CALL para_env%bcast(file_exists)
     585              : 
     586           18 :       IF (file_exists) THEN
     587              : 
     588            0 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
     589            0 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
     590              : 
     591            0 :          ALLOCATE (vecbuffer(nao, max_block))
     592              :          !
     593              :          ! read headers
     594            0 :          IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) lambda_tmp, beta_tmp, nspins_tmp, nao_tmp
     595            0 :          CALL para_env%bcast(iostat)
     596              : 
     597            0 :          CALL para_env%bcast(beta_tmp)
     598            0 :          CALL para_env%bcast(lambda_tmp)
     599            0 :          CALL para_env%bcast(nspins_tmp)
     600            0 :          CALL para_env%bcast(nao_tmp)
     601              : 
     602              :          ! check that the number nao, nmo and nspins are
     603              :          ! the same as in the current mos
     604            0 :          IF (nspins_tmp /= nspins) THEN
     605            0 :             CPABORT("nspins not consistent")
     606              :          END IF
     607            0 :          IF (nao_tmp /= nao) CPABORT("nao not consistent")
     608              :          ! check that it's the right file
     609              :          ! the same as in the current mos
     610            0 :          IF (lambda_tmp /= lambda) CPABORT("lambda not consistent")
     611            0 :          IF (beta_tmp /= beta) CPABORT("beta not consistent")
     612              :          !
     613            0 :          DO ispin = 1, nspins
     614            0 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
     615            0 :             CALL cp_fm_get_info(mo_coeff, ncol_global=nmo)
     616              :             !
     617            0 :             IF (rst_unit > 0) READ (rst_unit) nmo_tmp
     618            0 :             CALL para_env%bcast(nmo_tmp)
     619            0 :             IF (nmo_tmp /= nmo) CPABORT("nmo not consistent")
     620              :             !
     621              :             ! read the response
     622            0 :             DO i = 1, nmo, MAX(max_block, 1)
     623            0 :                i_block = MIN(max_block, nmo - i + 1)
     624            0 :                DO j = 1, i_block
     625            0 :                   IF (rst_unit > 0) READ (rst_unit) vecbuffer(1:nao, j)
     626              :                END DO
     627            0 :                CALL para_env%bcast(vecbuffer)
     628            0 :                CALL cp_fm_set_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
     629              :             END DO
     630              :          END DO
     631              : 
     632            0 :          IF (iostat /= 0) THEN
     633            0 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     634            0 :                "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
     635              :          END IF
     636              : 
     637            0 :          DEALLOCATE (vecbuffer)
     638              : 
     639              :       END IF
     640              : 
     641           18 :       IF (para_env%is_source()) THEN
     642            9 :          IF (file_exists) CALL close_file(unit_number=rst_unit)
     643              :       END IF
     644              : 
     645           18 :       CALL timestop(handle)
     646              : 
     647           18 :    END SUBROUTINE vcd_read_restart
     648              : 
     649              : ! **************************************************************************************************
     650              : !> \brief Copied from linres_write_restart
     651              : !> \param qs_env ...
     652              : !> \param linres_section ...
     653              : !> \param vec ...
     654              : !> \param lambda ...
     655              : !> \param beta ...
     656              : !> \param tag ...
     657              : !> \author Edward Ditler
     658              : ! **************************************************************************************************
     659           18 :    SUBROUTINE vcd_write_restart(qs_env, linres_section, vec, lambda, beta, tag)
     660              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     661              :       TYPE(section_vals_type), POINTER                   :: linres_section
     662              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     663              :       INTEGER, INTENT(IN)                                :: lambda, beta
     664              :       CHARACTER(LEN=*)                                   :: tag
     665              : 
     666              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'vcd_write_restart'
     667              : 
     668              :       CHARACTER(LEN=default_path_length)                 :: filename
     669              :       CHARACTER(LEN=default_string_length)               :: my_middle, my_pos, my_status
     670              :       INTEGER                                            :: handle, i, i_block, ia, ie, iounit, &
     671              :                                                             ispin, j, max_block, nao, nmo, nspins, &
     672              :                                                             rst_unit
     673           18 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     674              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     675              :       TYPE(cp_logger_type), POINTER                      :: logger
     676           18 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     677              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     678              :       TYPE(section_vals_type), POINTER                   :: print_key
     679              : 
     680           18 :       NULLIFY (logger, mo_coeff, mos, para_env, print_key, vecbuffer)
     681              : 
     682           18 :       CALL timeset(routineN, handle)
     683              : 
     684           18 :       logger => cp_get_default_logger()
     685              : 
     686           18 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, linres_section, "PRINT%RESTART", &
     687              :                                            used_print_key=print_key), &
     688              :                 cp_p_file)) THEN
     689              : 
     690              :          iounit = cp_print_key_unit_nr(logger, linres_section, &
     691           18 :                                        "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     692              : 
     693              :          CALL get_qs_env(qs_env=qs_env, &
     694              :                          mos=mos, &
     695           18 :                          para_env=para_env)
     696              : 
     697           18 :          nspins = SIZE(mos)
     698              : 
     699           18 :          my_status = "REPLACE"
     700           18 :          my_pos = "REWIND"
     701           18 :          CALL XSTRING(tag, ia, ie)
     702              :          my_middle = "RESTART-"//tag(ia:ie)//TRIM("-")//TRIM(ADJUSTL(cp_to_string(beta))) &
     703           18 :                      //TRIM("-")//TRIM(ADJUSTL(cp_to_string(lambda)))
     704              :          rst_unit = cp_print_key_unit_nr(logger, linres_section, "PRINT%RESTART", &
     705              :                                          extension=".lr", middle_name=TRIM(my_middle), file_status=TRIM(my_status), &
     706           18 :                                          file_position=TRIM(my_pos), file_action="WRITE", file_form="UNFORMATTED")
     707              : 
     708              :          filename = cp_print_key_generate_filename(logger, print_key, &
     709           18 :                                                    extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     710              : 
     711           18 :          IF (iounit > 0) THEN
     712              :             WRITE (UNIT=iounit, FMT="(T2,A)") &
     713            9 :                "LINRES| Writing response functions to the restart file <"//TRIM(ADJUSTL(filename))//">"
     714              :          END IF
     715              : 
     716              :          !
     717              :          ! write data to file
     718              :          ! use the scalapack block size as a default for buffering columns
     719           18 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
     720           18 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
     721           72 :          ALLOCATE (vecbuffer(nao, max_block))
     722              : 
     723           18 :          IF (rst_unit > 0) WRITE (rst_unit) lambda, beta, nspins, nao
     724              : 
     725           36 :          DO ispin = 1, nspins
     726           18 :             CALL cp_fm_get_info(vec(ispin), ncol_global=nmo)
     727              : 
     728           18 :             IF (rst_unit > 0) WRITE (rst_unit) nmo
     729              : 
     730           72 :             DO i = 1, nmo, MAX(max_block, 1)
     731           18 :                i_block = MIN(max_block, nmo - i + 1)
     732           18 :                CALL cp_fm_get_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
     733              :                ! doing this in one write would increase efficiency, but breaks RESTART compatibility.
     734              :                ! to old ones, and in cases where max_block is different between runs, as might happen during
     735              :                ! restarts with a different number of CPUs
     736          108 :                DO j = 1, i_block
     737          306 :                   IF (rst_unit > 0) WRITE (rst_unit) vecbuffer(1:nao, j)
     738              :                END DO
     739              :             END DO
     740              :          END DO
     741              : 
     742           18 :          DEALLOCATE (vecbuffer)
     743              : 
     744              :          CALL cp_print_key_finished_output(rst_unit, logger, linres_section, &
     745           36 :                                            "PRINT%RESTART")
     746              :       END IF
     747              : 
     748           18 :       CALL timestop(handle)
     749              : 
     750           18 :    END SUBROUTINE vcd_write_restart
     751              : 
     752              : ! **************************************************************************************************
     753              : !> \brief Print the APTs, AATs, and sum rules
     754              : !> \param vcd_env ...
     755              : !> \param qs_env ...
     756              : !> \author Edward Ditler
     757              : ! **************************************************************************************************
     758            2 :    SUBROUTINE vcd_print(vcd_env, qs_env)
     759              :       TYPE(vcd_env_type)                                 :: vcd_env
     760              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     761              : 
     762              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'vcd_print'
     763              : 
     764              :       CHARACTER(LEN=default_string_length)               :: description
     765              :       INTEGER                                            :: alpha, beta, delta, gamma, handle, i, l, &
     766              :                                                             lambda, natom, nsubset, output_unit
     767              :       REAL(dp)                                           :: mean, standard_deviation, &
     768              :                                                             standard_deviation_sum
     769            2 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: apt_el_dcdr, apt_el_nvpt, apt_nuc_dcdr, &
     770            2 :                                                             apt_nuc_nvpt, apt_total_dcdr, &
     771            2 :                                                             apt_total_nvpt
     772            2 :       REAL(dp), DIMENSION(:, :, :, :), POINTER           :: apt_center_dcdr, apt_subset_dcdr
     773              :       REAL(kind=dp), DIMENSION(3, 3)                     :: sum_rule_0, sum_rule_0_second, &
     774              :                                                             sum_rule_1, sum_rule_2, &
     775              :                                                             sum_rule_2_second, sum_rule_3_mfp, &
     776              :                                                             sum_rule_3_second
     777              :       TYPE(cp_logger_type), POINTER                      :: logger
     778              :       TYPE(cp_result_type), POINTER                      :: results
     779            2 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
     780            2 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     781              :       TYPE(section_vals_type), POINTER                   :: vcd_section
     782              : 
     783            2 :       CALL timeset(routineN, handle)
     784              : 
     785            2 :       NULLIFY (logger)
     786              : 
     787            2 :       logger => cp_get_default_logger()
     788            2 :       output_unit = cp_logger_get_default_io_unit(logger)
     789              : 
     790            2 :       vcd_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES%VCD")
     791              : 
     792            2 :       NULLIFY (particle_set)
     793            2 :       CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, molecule_set=molecule_set)
     794            2 :       natom = SIZE(particle_set)
     795            2 :       nsubset = SIZE(molecule_set)
     796              : 
     797            2 :       apt_el_dcdr => vcd_env%dcdr_env%apt_el_dcdr
     798            2 :       apt_nuc_dcdr => vcd_env%dcdr_env%apt_nuc_dcdr
     799            2 :       apt_total_dcdr => vcd_env%dcdr_env%apt_total_dcdr
     800            2 :       apt_subset_dcdr => vcd_env%dcdr_env%apt_el_dcdr_per_subset
     801            2 :       apt_center_dcdr => vcd_env%dcdr_env%apt_el_dcdr_per_center
     802              : 
     803            2 :       apt_el_nvpt => vcd_env%apt_el_nvpt
     804            2 :       apt_nuc_nvpt => vcd_env%apt_nuc_nvpt
     805            2 :       apt_total_nvpt => vcd_env%apt_total_nvpt
     806              : 
     807            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A)") &
     808            1 :          'APT | Write the final APT matrix per atom (Position perturbation)'
     809            8 :       DO l = 1, natom
     810            6 :          IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,I3,A,F15.6)") &
     811            3 :             'APT | Atom', l, ' - GAPT ', &
     812              :             (apt_total_dcdr(1, 1, l) &
     813              :              + apt_total_dcdr(2, 2, l) &
     814            6 :              + apt_total_dcdr(3, 3, l))/3._dp
     815           26 :          DO i = 1, 3
     816           51 :             IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,F15.6,F15.6,F15.6)") "APT | ", apt_total_dcdr(i, :, l)
     817              :          END DO
     818              :       END DO
     819              : 
     820            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A)") &
     821            1 :          'NVP | Write the final APT matrix per atom (Velocity perturbation)'
     822            8 :       DO l = 1, natom
     823            6 :          IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,I3,A,F15.6)") &
     824            3 :             'NVP | Atom', l, ' - GAPT ', &
     825              :             (apt_total_nvpt(1, 1, l) &
     826              :              + apt_total_nvpt(2, 2, l) &
     827            6 :              + apt_total_nvpt(3, 3, l))/3._dp
     828           26 :          DO i = 1, 3
     829           24 :             IF (vcd_env%output_unit > 0) THEN
     830              :                WRITE (vcd_env%output_unit, "(A,F15.6,F15.6,F15.6)") &
     831           36 :                   "NVP | ", apt_total_nvpt(i, :, l)
     832              :             END IF
     833              :          END DO
     834              :       END DO
     835              : 
     836            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A)") &
     837            1 :          'NVP | Write the final AAT matrix per atom (Velocity perturbation)'
     838            8 :       DO l = 1, natom
     839            6 :          IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,I3)") &
     840            3 :             'NVP | Atom', l
     841           26 :          DO i = 1, 3
     842           24 :             IF (vcd_env%output_unit > 0) THEN
     843              :                WRITE (vcd_env%output_unit, "(A,F15.6,F15.6,F15.6)") &
     844            9 :                   "NVP | ", vcd_env%aat_atom_nvpt(i, :, l)
     845              :             END IF
     846              :          END DO
     847              :       END DO
     848              : 
     849            2 :       IF (vcd_env%do_mfp) THEN
     850            0 :          IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A)") &
     851            0 :             'MFP | Write the final AAT matrix per atom (Magnetic Field perturbation)'
     852            0 :          DO l = 1, natom
     853            0 :             IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,I3)") &
     854            0 :                'MFP | Atom', l
     855            0 :             DO i = 1, 3
     856            0 :                IF (vcd_env%output_unit > 0) THEN
     857              :                   WRITE (vcd_env%output_unit, "(A,F15.6,F15.6,F15.6)") &
     858            0 :                      "MFP | ", vcd_env%aat_atom_mfp(i, :, l)
     859              :                END IF
     860              :             END DO
     861              :          END DO
     862              :       END IF
     863              : 
     864              :       ! Get the dipole
     865            2 :       CALL get_qs_env(qs_env, results=results)
     866            2 :       description = "[DIPOLE]"
     867            2 :       CALL get_results(results=results, description=description, values=vcd_env%dcdr_env%dipole_pos(1:3))
     868              : 
     869              :       ! Sum rules [for all alpha, beta]
     870            2 :       sum_rule_0 = 0._dp
     871            2 :       sum_rule_1 = 0._dp
     872            2 :       sum_rule_2 = 0._dp
     873            2 :       sum_rule_0_second = 0._dp
     874            2 :       sum_rule_2_second = 0._dp
     875            2 :       sum_rule_3_second = 0._dp
     876            2 :       sum_rule_3_mfp = 0._dp
     877              :       standard_deviation = 0._dp
     878            2 :       standard_deviation_sum = 0._dp
     879              : 
     880            8 :       DO alpha = 1, 3
     881           26 :          DO beta = 1, 3
     882              :             ! 0: sum_lambda apt(alpha, beta, lambda)
     883           72 :             DO lambda = 1, natom
     884              :                sum_rule_0(alpha, beta) = sum_rule_0(alpha, beta) &
     885           54 :                                          + apt_total_dcdr(alpha, beta, lambda)
     886              :                sum_rule_0_second(alpha, beta) = sum_rule_0_second(alpha, beta) &
     887           72 :                                                 + apt_total_nvpt(alpha, beta, lambda)
     888              :             END DO
     889              : 
     890              :             ! 1: sum_gamma epsilon_(alpha beta gamma) mu_gamma
     891           72 :             DO gamma = 1, 3
     892              :                sum_rule_1(alpha, beta) = sum_rule_1(alpha, beta) &
     893           72 :                                          + Levi_Civita(alpha, beta, gamma)*vcd_env%dcdr_env%dipole_pos(gamma)
     894              :             END DO
     895              : 
     896              :             ! 2: sum_(lambda gamma delta) R^lambda_gamma apt(delta, alpha, lambda)
     897           72 :             DO lambda = 1, natom
     898          234 :                DO gamma = 1, 3
     899          702 :                   DO delta = 1, 3
     900              :                      sum_rule_2(alpha, beta) = sum_rule_2(alpha, beta) &
     901              :                                                + Levi_Civita(beta, gamma, delta) &
     902              :                                                *particle_set(lambda)%r(gamma) &
     903          486 :                                                *apt_total_dcdr(delta, alpha, lambda)
     904              :                      sum_rule_2_second(alpha, beta) = sum_rule_2_second(alpha, beta) &
     905              :                                                       + Levi_Civita(beta, gamma, delta) &
     906              :                                                       *particle_set(lambda)%r(gamma) &
     907          648 :                                                       *apt_total_nvpt(delta, alpha, lambda)
     908              :                   END DO
     909              :                END DO
     910              :             END DO
     911              : 
     912              :             ! 3: 2c * sum_lambda aat(alpha, beta, lambda)
     913           72 :             DO lambda = 1, natom
     914              :                sum_rule_3_second(alpha, beta) = sum_rule_3_second(alpha, beta) &
     915           72 :                                                 + vcd_env%aat_atom_nvpt(alpha, beta, lambda)
     916              :                ! + 2._dp*c_light_au*vcd_env%aat_atom_nvpt(alpha, beta, lambda)
     917              :             END DO
     918              : 
     919           24 :             IF (vcd_env%do_mfp) THEN
     920              :                ! 3: 2c * sum_lambda aat(alpha, beta, lambda)
     921            0 :                DO lambda = 1, natom
     922              :                   sum_rule_3_mfp(alpha, beta) = sum_rule_3_mfp(alpha, beta) &
     923            0 :                                                 + vcd_env%aat_atom_mfp(alpha, beta, lambda)
     924              :                END DO
     925              :             END IF
     926              : 
     927              :          END DO ! beta
     928              :       END DO   ! alpha
     929              : 
     930            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A)") "APT | Position perturbation sum rules"
     931            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(A,T19,A,T35,A,T50,A,T65,A)") &
     932            1 :          "APT |", " Total APT", "Dipole", "R * APT", "AAT"
     933              :       standard_deviation_sum = 0._dp
     934            8 :       DO alpha = 1, 3
     935           26 :          DO beta = 1, 3
     936           18 :             mean = (sum_rule_1(alpha, beta) + sum_rule_2(alpha, beta) + sum_rule_3_mfp(alpha, beta))/3
     937              :             standard_deviation = &
     938              :                SQRT((sum_rule_1(alpha, beta)**2 + sum_rule_2(alpha, beta)**2 + sum_rule_3_mfp(alpha, beta)**2)/3 &
     939           18 :                     - mean**2)
     940           18 :             standard_deviation_sum = standard_deviation_sum + standard_deviation
     941              : 
     942           18 :             IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, &
     943              :                                                 "(A,I3,I3,F15.6,F15.6,F15.6,F15.6,F15.6)") &
     944            9 :                "APT | ", &
     945            9 :                alpha, beta, &
     946            9 :                sum_rule_0(alpha, beta), &
     947            9 :                sum_rule_1(alpha, beta), &
     948            9 :                sum_rule_2(alpha, beta), &
     949            9 :                sum_rule_3_mfp(alpha, beta), &
     950           24 :                standard_deviation
     951              :          END DO
     952              :       END DO
     953            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(T73,F15.6)") standard_deviation_sum
     954              : 
     955            2 :       IF (vcd_env%output_unit > 0) THEN
     956            1 :          WRITE (vcd_env%output_unit, "(A)") "NVP | Velocity perturbation sum rules"
     957            1 :          WRITE (vcd_env%output_unit, "(A,T19,A,T35,A,T50,A,T65,A)") "NVP |", " Total APT", "Dipole", "R * APT", "AAT"
     958              :       END IF
     959              : 
     960            2 :       standard_deviation_sum = 0._dp
     961            8 :       DO alpha = 1, 3
     962           26 :          DO beta = 1, 3
     963           18 :             mean = (sum_rule_1(alpha, beta) + sum_rule_2_second(alpha, beta) + sum_rule_3_second(alpha, beta))/3
     964              :             standard_deviation = &
     965              :                SQRT((sum_rule_1(alpha, beta)**2 + sum_rule_2_second(alpha, beta)**2 + sum_rule_3_second(alpha, beta)**2)/3 &
     966           18 :                     - mean**2)
     967           18 :             standard_deviation_sum = standard_deviation_sum + standard_deviation
     968           18 :             IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, &
     969              :                                                 "(A,I3,I3,F15.6,F15.6,F15.6,F15.6,F15.6)") &
     970            9 :                "NVP | ", &
     971            9 :                alpha, &
     972            9 :                beta, &
     973            9 :                sum_rule_0_second(alpha, beta), &
     974            9 :                sum_rule_1(alpha, beta), &
     975            9 :                sum_rule_2_second(alpha, beta), &
     976            9 :                sum_rule_3_second(alpha, beta), &
     977           24 :                standard_deviation
     978              :          END DO
     979              :       END DO
     980            2 :       IF (vcd_env%output_unit > 0) WRITE (vcd_env%output_unit, "(T73,F15.6)") standard_deviation_sum
     981              : 
     982            2 :       CALL timestop(handle)
     983            2 :    END SUBROUTINE vcd_print
     984              : 
     985              : END MODULE qs_vcd_utils
        

Generated by: LCOV version 2.0-1