LCOV - code coverage report
Current view: top level - src - qs_vcd_utils.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 395 446 88.6 %
Date: 2024-12-21 06:28:57 Functions: 5 5 100.0 %

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

Generated by: LCOV version 1.15