LCOV - code coverage report
Current view: top level - src/emd - rt_propagation_output.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 95.8 % 660 632
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 15 15

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Routine for the real time propagation output.
      10              : !> \author Florian Schiffmann (02.09)
      11              : ! **************************************************************************************************
      12              : 
      13              : MODULE rt_propagation_output
      14              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      15              :    USE cell_types,                      ONLY: cell_type
      16              :    USE cp_control_types,                ONLY: dft_control_type,&
      17              :                                               rtp_control_type
      18              :    USE cp_dbcsr_api,                    ONLY: &
      19              :         dbcsr_add, dbcsr_binary_write, dbcsr_convert_offsets_to_sizes, dbcsr_copy, dbcsr_create, &
      20              :         dbcsr_deallocate_matrix, dbcsr_desymmetrize, dbcsr_distribution_type, dbcsr_filter, &
      21              :         dbcsr_get_info, dbcsr_get_occupation, dbcsr_init_p, dbcsr_iterator_blocks_left, &
      22              :         dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
      23              :         dbcsr_multiply, dbcsr_p_type, dbcsr_scale, dbcsr_set, dbcsr_type, &
      24              :         dbcsr_type_antisymmetric, dbcsr_type_no_symmetry
      25              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_checksum,&
      26              :                                               dbcsr_trace
      27              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      28              :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply,&
      29              :                                               dbcsr_allocate_matrix_set,&
      30              :                                               dbcsr_deallocate_matrix_set
      31              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale_and_add
      32              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      33              :                                               cp_fm_struct_double,&
      34              :                                               cp_fm_struct_release,&
      35              :                                               cp_fm_struct_type
      36              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      37              :                                               cp_fm_get_info,&
      38              :                                               cp_fm_release,&
      39              :                                               cp_fm_set_all,&
      40              :                                               cp_fm_type
      41              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      42              :                                               cp_logger_get_default_io_unit,&
      43              :                                               cp_logger_get_default_unit_nr,&
      44              :                                               cp_logger_type,&
      45              :                                               cp_to_string
      46              :    USE cp_output_handling,              ONLY: cp_iter_string,&
      47              :                                               cp_p_file,&
      48              :                                               cp_print_key_finished_output,&
      49              :                                               cp_print_key_should_output,&
      50              :                                               cp_print_key_unit_nr,&
      51              :                                               cp_printkey_is_on
      52              :    USE cp_realspace_grid_cube,          ONLY: cp_pw_to_cube
      53              :    USE efield_utils,                    ONLY: make_field
      54              :    USE greenx_interface,                ONLY: greenx_refine_ft
      55              :    USE input_constants,                 ONLY: ehrenfest,&
      56              :                                               real_time_propagation
      57              :    USE input_section_types,             ONLY: section_get_ivals,&
      58              :                                               section_vals_get_subs_vals,&
      59              :                                               section_vals_type
      60              :    USE kahan_sum,                       ONLY: accurate_sum
      61              :    USE kinds,                           ONLY: default_path_length,&
      62              :                                               dp
      63              :    USE machine,                         ONLY: m_flush
      64              :    USE mathconstants,                   ONLY: twopi
      65              :    USE message_passing,                 ONLY: mp_comm_type
      66              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      67              :    USE particle_list_types,             ONLY: particle_list_type
      68              :    USE particle_methods,                ONLY: get_particle_set
      69              :    USE particle_types,                  ONLY: particle_type
      70              :    USE physcon,                         ONLY: evolt,&
      71              :                                               femtoseconds
      72              :    USE pw_env_types,                    ONLY: pw_env_get,&
      73              :                                               pw_env_type
      74              :    USE pw_methods,                      ONLY: pw_zero
      75              :    USE pw_pool_types,                   ONLY: pw_pool_type
      76              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      77              :                                               pw_r3d_rs_type
      78              :    USE qs_energy_types,                 ONLY: qs_energy_type
      79              :    USE qs_environment_types,            ONLY: get_qs_env,&
      80              :                                               qs_environment_type
      81              :    USE qs_kind_types,                   ONLY: get_qs_kind_set,&
      82              :                                               qs_kind_type
      83              :    USE qs_linres_current,               ONLY: calculate_jrho_resp
      84              :    USE qs_linres_types,                 ONLY: current_env_type
      85              :    USE qs_mo_io,                        ONLY: write_rt_mos_to_restart
      86              :    USE qs_moments,                      ONLY: build_local_moment_matrix
      87              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      88              :    USE qs_operators_ao,                 ONLY: build_lin_mom_matrix
      89              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      90              :                                               qs_rho_type
      91              :    USE qs_scf_post_gpw,                 ONLY: qs_scf_post_moments,&
      92              :                                               write_mo_dependent_results,&
      93              :                                               write_mo_free_results
      94              :    USE qs_scf_post_tb,                  ONLY: scf_post_calculation_tb
      95              :    USE qs_scf_types,                    ONLY: qs_scf_env_type
      96              :    USE qs_subsys_types,                 ONLY: qs_subsys_get,&
      97              :                                               qs_subsys_type
      98              :    USE rt_projection_mo_utils,          ONLY: compute_and_write_proj_mo
      99              :    USE rt_propagation_ft,               ONLY: multi_fft
     100              :    USE rt_propagation_types,            ONLY: get_rtp,&
     101              :                                               rt_prop_type
     102              :    USE rt_propagation_utils,            ONLY: write_rtp_mo_cubes,&
     103              :                                               write_rtp_mos_to_output_unit
     104              : #include "../base/base_uses.f90"
     105              : 
     106              :    IMPLICIT NONE
     107              : 
     108              :    PRIVATE
     109              : 
     110              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rt_propagation_output'
     111              : 
     112              :    PUBLIC :: rt_prop_output, &
     113              :              rt_convergence, &
     114              :              rt_convergence_density, &
     115              :              report_density_occupation, &
     116              :              print_moments, &
     117              :              calc_local_moment, &
     118              :              print_ft
     119              : 
     120              : CONTAINS
     121              : 
     122              : ! **************************************************************************************************
     123              : !> \brief ...
     124              : !> \param qs_env ...
     125              : !> \param run_type ...
     126              : !> \param delta_iter ...
     127              : !> \param used_time ...
     128              : ! **************************************************************************************************
     129         2284 :    SUBROUTINE rt_prop_output(qs_env, run_type, delta_iter, used_time)
     130              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     131              :       INTEGER, INTENT(in)                                :: run_type
     132              :       REAL(dp), INTENT(in), OPTIONAL                     :: delta_iter, used_time
     133              : 
     134              :       INTEGER                                            :: i, n_electrons, n_proj, natom, nspin, &
     135              :                                                             output_unit, spin, unit_nr
     136         2284 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: first_sgf, last_sgf
     137         2284 :       INTEGER, DIMENSION(:), POINTER                     :: row_blk_sizes
     138              :       LOGICAL                                            :: new_file
     139              :       REAL(dp)                                           :: orthonormality, strace, tot_rho_r, trace
     140              :       REAL(kind=dp), DIMENSION(3)                        :: field, reference_point
     141         2284 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: qs_tot_rho_r
     142         2284 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: j_int
     143         2284 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     144         2284 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
     145              :       TYPE(cp_logger_type), POINTER                      :: logger
     146              :       TYPE(dbcsr_distribution_type), POINTER             :: dbcsr_dist
     147         2284 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, P_im, p_xyz, rho_new
     148              :       TYPE(dbcsr_type), POINTER                          :: tmp_ao
     149              :       TYPE(dft_control_type), POINTER                    :: dft_control
     150              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     151         2284 :          POINTER                                         :: sab_all, sab_orb
     152         2284 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     153         2284 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     154              :       TYPE(qs_rho_type), POINTER                         :: rho
     155              :       TYPE(rt_prop_type), POINTER                        :: rtp
     156              :       TYPE(section_vals_type), POINTER                   :: dft_section, input, rtp_section
     157              : 
     158         2284 :       NULLIFY (logger, dft_control)
     159              : 
     160         4568 :       logger => cp_get_default_logger()
     161              :       CALL get_qs_env(qs_env, &
     162              :                       rtp=rtp, &
     163              :                       matrix_s=matrix_s, &
     164              :                       input=input, &
     165              :                       rho=rho, &
     166              :                       particle_set=particle_set, &
     167              :                       atomic_kind_set=atomic_kind_set, &
     168              :                       qs_kind_set=qs_kind_set, &
     169              :                       dft_control=dft_control, sab_all=sab_all, sab_orb=sab_orb, &
     170         2284 :                       dbcsr_dist=dbcsr_dist)
     171              : 
     172         2284 :       rtp_section => section_vals_get_subs_vals(input, "DFT%REAL_TIME_PROPAGATION")
     173              : 
     174         2284 :       CALL get_qs_kind_set(qs_kind_set, nelectron=n_electrons)
     175         2284 :       n_electrons = n_electrons - dft_control%charge
     176              : 
     177         2284 :       CALL qs_rho_get(rho_struct=rho, tot_rho_r=qs_tot_rho_r)
     178              : 
     179         2284 :       tot_rho_r = accurate_sum(qs_tot_rho_r)
     180              : 
     181              :       output_unit = cp_print_key_unit_nr(logger, rtp_section, "PRINT%PROGRAM_RUN_INFO", &
     182         2284 :                                          extension=".scfLog")
     183              : 
     184         2284 :       IF (output_unit > 0) THEN
     185              :          WRITE (output_unit, FMT="(/,(T3,A,T40,I5))") &
     186         1142 :             "Information at iteration step:", rtp%iter
     187              :          WRITE (UNIT=output_unit, FMT="((T3,A,T41,2F20.10))") &
     188         1142 :             "Total electronic density (r-space): ", &
     189         1142 :             tot_rho_r, &
     190              :             tot_rho_r + &
     191         2284 :             REAL(n_electrons, dp)
     192              :          WRITE (UNIT=output_unit, FMT="((T3,A,T59,F22.14))") &
     193         1142 :             "Total energy:", rtp%energy_new
     194         1142 :          IF (run_type == ehrenfest) &
     195              :             WRITE (UNIT=output_unit, FMT="((T3,A,T61,F20.14))") &
     196          572 :             "Energy difference to previous iteration step:", rtp%energy_new - rtp%energy_old
     197         1142 :          IF (run_type == real_time_propagation) &
     198              :             WRITE (UNIT=output_unit, FMT="((T3,A,T61,F20.14))") &
     199          570 :             "Energy difference to initial state:", rtp%energy_new - rtp%energy_old
     200         1142 :          IF (PRESENT(delta_iter)) &
     201              :             WRITE (UNIT=output_unit, FMT="((T3,A,T61,E20.6))") &
     202         1142 :             "Convergence:", delta_iter
     203         1142 :          IF (rtp%converged) THEN
     204          307 :             IF (run_type == real_time_propagation) &
     205              :                WRITE (UNIT=output_unit, FMT="((T3,A,T61,F12.2))") &
     206          172 :                "Time needed for propagation:", used_time
     207              :             WRITE (UNIT=output_unit, FMT="(/,(T3,A,3X,F16.14))") &
     208          307 :                "CONVERGENCE REACHED", rtp%energy_new - rtp%energy_old
     209              :          END IF
     210              :       END IF
     211              : 
     212         2284 :       IF (rtp%converged) THEN
     213          614 :          IF (.NOT. rtp%linear_scaling) THEN
     214          432 :             CALL get_rtp(rtp=rtp, mos_new=mos_new)
     215              :             CALL rt_calculate_orthonormality(orthonormality, &
     216          432 :                                              mos_new, matrix_s(1)%matrix)
     217          432 :             IF (output_unit > 0) &
     218              :                WRITE (output_unit, FMT="(/,(T3,A,T60,F20.10))") &
     219          216 :                "Max deviation from orthonormalization:", orthonormality
     220              :          END IF
     221              :       END IF
     222              : 
     223         2284 :       IF (output_unit > 0) &
     224         1142 :          CALL m_flush(output_unit)
     225              :       CALL cp_print_key_finished_output(output_unit, logger, rtp_section, &
     226         2284 :                                         "PRINT%PROGRAM_RUN_INFO")
     227              : 
     228         2284 :       IF (rtp%converged) THEN
     229          614 :          dft_section => section_vals_get_subs_vals(input, "DFT")
     230          614 :          IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     231              :                                               dft_section, "REAL_TIME_PROPAGATION%PRINT%FIELD"), cp_p_file)) &
     232           30 :             CALL print_field_applied(qs_env, dft_section)
     233          614 :          CALL make_moment(qs_env)
     234          614 :          IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     235              :                                               dft_section, "REAL_TIME_PROPAGATION%PRINT%E_CONSTITUENTS"), cp_p_file)) THEN
     236            4 :             CALL print_rtp_energy_components(qs_env, dft_section)
     237              :          END IF
     238          614 :          IF (.NOT. dft_control%qs_control%dftb) THEN
     239          494 :             CALL write_available_results(qs_env=qs_env, rtp=rtp)
     240              :          END IF
     241              : 
     242          614 :          IF (rtp%linear_scaling) THEN
     243          182 :             CALL get_rtp(rtp=rtp, rho_new=rho_new)
     244              : 
     245              :             ! Probably have to rebuild the moment matrix, since atoms can also move, in principle
     246          182 :             IF (dft_control%rtp_control%save_local_moments) THEN
     247              :                ! Save the field value
     248           36 :                IF (dft_control%apply_efield_field) THEN
     249            0 :                   CALL make_field(dft_control, field, qs_env%sim_step, qs_env%sim_time)
     250            0 :                   rtp%fields(:, rtp%istep + rtp%i_start + 1) = CMPLX(field(:), 0.0, kind=dp)
     251              :                END IF
     252           36 :                IF (.NOT. dft_control%rtp_control%fixed_ions) THEN
     253            0 :                   CALL build_local_moment_matrix(qs_env, rtp%local_moments, 1, reference_point)
     254              :                END IF
     255              :                ! TODO : Is symmetric rho possible?
     256              :                ! Spin + complex parts
     257              :                ! Extensions setup
     258              :                CALL calc_local_moment(rtp%local_moments, rho_new, &
     259           36 :                                       rtp%local_moments_work, rtp%moments(:, :, rtp%istep + rtp%i_start + 1))
     260              :                ! Time 1 is zero (start) time
     261           36 :                rtp%times(rtp%istep + rtp%i_start + 1) = qs_env%sim_time
     262           36 :                output_unit = cp_logger_get_default_io_unit(logger)
     263              :                CALL print_moments(section_vals_get_subs_vals(rtp_section, "PRINT%MOMENTS"), output_unit, &
     264           36 :                                   rtp%moments(:, :, rtp%istep + rtp%i_start + 1), qs_env%sim_time, rtp%track_imag_density)
     265              :             END IF
     266              : 
     267          182 :             IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     268              :                                                  dft_section, "REAL_TIME_PROPAGATION%PRINT%RESTART"), cp_p_file)) THEN
     269           96 :                CALL write_rt_p_to_restart(rho_new, .FALSE.)
     270              :             END IF
     271          182 :             IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     272              :                                                  dft_section, "REAL_TIME_PROPAGATION%PRINT%RESTART_HISTORY"), cp_p_file)) THEN
     273            2 :                CALL write_rt_p_to_restart(rho_new, .TRUE.)
     274              :             END IF
     275          182 :             IF (.NOT. dft_control%qs_control%dftb) THEN
     276              :                !Not sure if these things could also work with dftb or not
     277          182 :                IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     278              :                                                     dft_section, "REAL_TIME_PROPAGATION%PRINT%CURRENT"), cp_p_file)) THEN
     279           64 :                   DO spin = 1, SIZE(rho_new)/2
     280           64 :                      CALL rt_current(qs_env, rho_new(2*spin)%matrix, dft_section, spin, SIZE(rho_new)/2)
     281              :                   END DO
     282              :                END IF
     283              :             END IF
     284              :          ELSE
     285          432 :             CALL get_rtp(rtp=rtp, mos_new=mos_new)
     286          432 :             IF (.NOT. dft_control%qs_control%dftb .AND. .NOT. dft_control%qs_control%xtb) THEN
     287          252 :                IF (rtp%track_imag_density) THEN
     288          174 :                   NULLIFY (P_im, p_xyz)
     289          174 :                   CALL dbcsr_allocate_matrix_set(p_xyz, 3)
     290              : 
     291              : ! Linear momentum operator
     292              : ! prepare for allocation
     293          174 :                   natom = SIZE(particle_set, 1)
     294          522 :                   ALLOCATE (first_sgf(natom))
     295          348 :                   ALLOCATE (last_sgf(natom))
     296              :                   CALL get_particle_set(particle_set, qs_kind_set, &
     297              :                                         first_sgf=first_sgf, &
     298          174 :                                         last_sgf=last_sgf)
     299          348 :                   ALLOCATE (row_blk_sizes(natom))
     300          174 :                   CALL dbcsr_convert_offsets_to_sizes(first_sgf, row_blk_sizes, last_sgf)
     301          174 :                   DEALLOCATE (first_sgf)
     302          174 :                   DEALLOCATE (last_sgf)
     303              : 
     304          174 :                   ALLOCATE (p_xyz(1)%matrix)
     305              :                   CALL dbcsr_create(matrix=p_xyz(1)%matrix, &
     306              :                                     name="p_xyz", &
     307              :                                     dist=dbcsr_dist, matrix_type=dbcsr_type_antisymmetric, &
     308              :                                     row_blk_size=row_blk_sizes, col_blk_size=row_blk_sizes, &
     309          174 :                                     mutable_work=.TRUE.)
     310          174 :                   CALL cp_dbcsr_alloc_block_from_nbl(p_xyz(1)%matrix, sab_orb)
     311          174 :                   CALL dbcsr_set(p_xyz(1)%matrix, 0.0_dp)
     312          522 :                   DO i = 2, 3
     313          348 :                      ALLOCATE (p_xyz(i)%matrix)
     314          348 :                      CALL dbcsr_copy(p_xyz(i)%matrix, p_xyz(1)%matrix, "p_xyz-"//TRIM(ADJUSTL(cp_to_string(i))))
     315          522 :                      CALL dbcsr_set(p_xyz(i)%matrix, 0.0_dp)
     316              :                   END DO
     317          174 :                   CALL build_lin_mom_matrix(qs_env, p_xyz)
     318          174 :                   DEALLOCATE (row_blk_sizes)
     319              : 
     320          174 :                   nspin = SIZE(mos_new)/2
     321          174 :                   CALL qs_rho_get(rho, rho_ao_im=P_im)
     322          522 :                   ALLOCATE (j_int(nspin, 3))
     323         1290 :                   j_int = 0.0_dp
     324              : 
     325          174 :                   NULLIFY (tmp_ao)
     326          174 :                   CALL dbcsr_init_p(tmp_ao)
     327          174 :                   CALL dbcsr_create(tmp_ao, template=matrix_s(1)%matrix, matrix_type=dbcsr_type_no_symmetry, name="tmp")
     328          174 :                   CALL cp_dbcsr_alloc_block_from_nbl(tmp_ao, sab_all)
     329          174 :                   CALL dbcsr_set(tmp_ao, 0.0_dp)
     330              : 
     331          696 :                   DO i = 1, 3
     332          522 :                      strace = 0.0_dp
     333         1290 :                      DO spin = 1, nspin
     334          594 :                         CALL dbcsr_set(tmp_ao, 0.0_dp)
     335              :                         CALL dbcsr_multiply("T", "N", 1.0_dp, P_im(spin)%matrix, p_xyz(i)%matrix, &
     336          594 :                                             0.0_dp, tmp_ao)
     337          594 :                         CALL dbcsr_trace(tmp_ao, trace)
     338          594 :                         strace = strace + trace
     339         1116 :                         j_int(spin, i) = strace
     340              :                      END DO
     341              :                   END DO
     342              : !  The term -(1/V)\int{(1/2)\sum_n f_n [\psi_n^*(t)(A(t))\psi_n(t) +cc]} missing. Is it just A(t)*number of electrons?
     343              : 
     344          174 :                   IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     345              :                                                        dft_section, "REAL_TIME_PROPAGATION%PRINT%CURRENT_INT"), cp_p_file)) THEN
     346              : 
     347            8 :                      output_unit = cp_logger_get_default_io_unit(logger)
     348              :                      unit_nr = cp_print_key_unit_nr(logger, dft_section, &
     349            8 :                                                   "REAL_TIME_PROPAGATION%PRINT%CURRENT_INT", extension=".dat", is_new_file=new_file)
     350            8 :                      IF (output_unit > 0) THEN
     351            4 :                         IF (nspin == 2) THEN
     352            2 :                            WRITE (UNIT=unit_nr, FMT="(I10,F16.6,6(F16.8,1X))") qs_env%sim_step, qs_env%sim_time*femtoseconds, &
     353            4 :                               j_int(1, 1:3), j_int(2, 1:3)
     354              :                         ELSE
     355            2 :                            WRITE (UNIT=unit_nr, FMT="(I10,F16.6,3(F16.8,1X))") qs_env%sim_step, qs_env%sim_time*femtoseconds, &
     356            4 :                               j_int(1, 1:3)
     357              :                         END IF
     358              :                      END IF
     359              :                      CALL cp_print_key_finished_output(unit_nr, logger, dft_section, &
     360            8 :                                                        "REAL_TIME_PROPAGATION%PRINT%CURRENT_INT")
     361              :                   END IF
     362          174 :                   DEALLOCATE (j_int)
     363              : 
     364          174 :                   IF (BTEST(cp_print_key_should_output(logger%iter_info, &
     365              :                                                        dft_section, "REAL_TIME_PROPAGATION%PRINT%CURRENT"), cp_p_file)) THEN
     366           24 :                      DO spin = 1, nspin
     367           24 :                         CALL rt_current(qs_env, P_im(spin)%matrix, dft_section, spin, nspin)
     368              :                      END DO
     369              :                   END IF
     370          174 :                   CALL dbcsr_deallocate_matrix(tmp_ao)
     371          174 :                   CALL dbcsr_deallocate_matrix_set(p_xyz)
     372              :                END IF
     373              : 
     374              : ! projection of molecular orbitals
     375          252 :                IF (dft_control%rtp_control%is_proj_mo) THEN
     376          112 :                   DO n_proj = 1, SIZE(dft_control%rtp_control%proj_mo_list)
     377              :                      CALL compute_and_write_proj_mo(qs_env, mos_new, &
     378          112 :                                                     dft_control%rtp_control%proj_mo_list(n_proj)%proj_mo, n_proj)
     379              :                   END DO
     380              :                END IF
     381              :             END IF
     382              :             CALL write_rt_mos_to_restart(qs_env%mos, mos_new, particle_set, &
     383          432 :                                          dft_section, qs_kind_set)
     384              :          END IF
     385              :       END IF
     386              : 
     387         2284 :       rtp%energy_old = rtp%energy_new
     388              : 
     389         2284 :       IF (.NOT. rtp%converged .AND. rtp%iter >= dft_control%rtp_control%max_iter) &
     390              :          CALL cp_abort(__LOCATION__, "EMD did not converge, either increase MAX_ITER "// &
     391            0 :                        "or use a smaller TIMESTEP")
     392              : 
     393         4568 :    END SUBROUTINE rt_prop_output
     394              : 
     395              : ! **************************************************************************************************
     396              : !> \brief computes the effective orthonormality of a set of mos given an s-matrix
     397              : !>        orthonormality is the max deviation from unity of the C^T S C
     398              : !> \param orthonormality ...
     399              : !> \param mos_new ...
     400              : !> \param matrix_s ...
     401              : !> \author Florian Schiffmann (02.09)
     402              : ! **************************************************************************************************
     403          432 :    SUBROUTINE rt_calculate_orthonormality(orthonormality, mos_new, matrix_s)
     404              :       REAL(KIND=dp), INTENT(out)                         :: orthonormality
     405              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
     406              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s
     407              : 
     408              :       CHARACTER(len=*), PARAMETER :: routineN = 'rt_calculate_orthonormality'
     409              : 
     410              :       INTEGER                                            :: handle, i, im, ispin, j, k, n, &
     411              :                                                             ncol_local, nrow_local, nspin, re
     412          432 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     413              :       REAL(KIND=dp)                                      :: alpha, max_alpha, max_beta
     414              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     415              :       TYPE(cp_fm_type)                                   :: overlap_re, svec_im, svec_re
     416              : 
     417          432 :       NULLIFY (tmp_fm_struct)
     418              : 
     419          432 :       CALL timeset(routineN, handle)
     420              : 
     421          432 :       nspin = SIZE(mos_new)/2
     422          432 :       max_alpha = 0.0_dp
     423          432 :       max_beta = 0.0_dp
     424          966 :       DO ispin = 1, nspin
     425          534 :          re = ispin*2 - 1
     426          534 :          im = ispin*2
     427              :          ! get S*C
     428          534 :          CALL cp_fm_create(svec_re, mos_new(im)%matrix_struct)
     429          534 :          CALL cp_fm_create(svec_im, mos_new(im)%matrix_struct)
     430              :          CALL cp_fm_get_info(mos_new(im), &
     431          534 :                              nrow_global=n, ncol_global=k)
     432              :          CALL cp_dbcsr_sm_fm_multiply(matrix_s, mos_new(re), &
     433          534 :                                       svec_re, k)
     434              :          CALL cp_dbcsr_sm_fm_multiply(matrix_s, mos_new(im), &
     435          534 :                                       svec_im, k)
     436              : 
     437              :          ! get C^T (S*C)
     438              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
     439              :                                   para_env=mos_new(re)%matrix_struct%para_env, &
     440          534 :                                   context=mos_new(re)%matrix_struct%context)
     441          534 :          CALL cp_fm_create(overlap_re, tmp_fm_struct)
     442              : 
     443          534 :          CALL cp_fm_struct_release(tmp_fm_struct)
     444              : 
     445              :          CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mos_new(re), &
     446          534 :                             svec_re, 0.0_dp, overlap_re)
     447              :          CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mos_new(im), &
     448          534 :                             svec_im, 1.0_dp, overlap_re)
     449              : 
     450          534 :          CALL cp_fm_release(svec_re)
     451          534 :          CALL cp_fm_release(svec_im)
     452              : 
     453              :          CALL cp_fm_get_info(overlap_re, nrow_local=nrow_local, ncol_local=ncol_local, &
     454          534 :                              row_indices=row_indices, col_indices=col_indices)
     455         1413 :          DO i = 1, nrow_local
     456         5020 :             DO j = 1, ncol_local
     457         3607 :                alpha = overlap_re%local_data(i, j)
     458         3607 :                IF (row_indices(i) == col_indices(j)) alpha = alpha - 1.0_dp
     459         4486 :                max_alpha = MAX(max_alpha, ABS(alpha))
     460              :             END DO
     461              :          END DO
     462         2568 :          CALL cp_fm_release(overlap_re)
     463              :       END DO
     464          432 :       CALL mos_new(1)%matrix_struct%para_env%max(max_alpha)
     465          432 :       CALL mos_new(1)%matrix_struct%para_env%max(max_beta)
     466          432 :       orthonormality = max_alpha
     467              : 
     468          432 :       CALL timestop(handle)
     469              : 
     470          432 :    END SUBROUTINE rt_calculate_orthonormality
     471              : 
     472              : ! **************************************************************************************************
     473              : !> \brief computes the convergence criterion for RTP and EMD
     474              : !> \param rtp ...
     475              : !> \param matrix_s Overlap matrix without the derivatives
     476              : !> \param delta_mos ...
     477              : !> \param delta_eps ...
     478              : !> \author Florian Schiffmann (02.09)
     479              : ! **************************************************************************************************
     480              : 
     481         1478 :    SUBROUTINE rt_convergence(rtp, matrix_s, delta_mos, delta_eps)
     482              :       TYPE(rt_prop_type), POINTER                        :: rtp
     483              :       TYPE(dbcsr_type), POINTER                          :: matrix_s
     484              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: delta_mos
     485              :       REAL(dp), INTENT(out)                              :: delta_eps
     486              : 
     487              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rt_convergence'
     488              :       REAL(KIND=dp), PARAMETER                           :: one = 1.0_dp, zero = 0.0_dp
     489              : 
     490              :       INTEGER                                            :: handle, i, icol, im, ispin, j, lcol, &
     491              :                                                             lrow, nao, newdim, nmo, nspin, re
     492              :       LOGICAL                                            :: double_col, double_row
     493              :       REAL(KIND=dp)                                      :: alpha, max_alpha
     494              :       TYPE(cp_fm_struct_type), POINTER                   :: newstruct, newstruct1, tmp_fm_struct
     495              :       TYPE(cp_fm_type)                                   :: work, work1, work2
     496         1478 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
     497              : 
     498         1478 :       NULLIFY (tmp_fm_struct)
     499              : 
     500         1478 :       CALL timeset(routineN, handle)
     501              : 
     502         1478 :       CALL get_rtp(rtp=rtp, mos_new=mos_new)
     503              : 
     504         1478 :       nspin = SIZE(delta_mos)/2
     505         1478 :       max_alpha = 0.0_dp
     506              : 
     507         5258 :       DO i = 1, SIZE(mos_new)
     508         5258 :          CALL cp_fm_scale_and_add(-one, delta_mos(i), one, mos_new(i))
     509              :       END DO
     510              : 
     511         3368 :       DO ispin = 1, nspin
     512         1890 :          re = ispin*2 - 1
     513         1890 :          im = ispin*2
     514              : 
     515         1890 :          double_col = .TRUE.
     516         1890 :          double_row = .FALSE.
     517              :          CALL cp_fm_struct_double(newstruct, &
     518              :                                   delta_mos(re)%matrix_struct, &
     519              :                                   delta_mos(re)%matrix_struct%context, &
     520              :                                   double_col, &
     521         1890 :                                   double_row)
     522              : 
     523         1890 :          CALL cp_fm_create(work, matrix_struct=newstruct)
     524         1890 :          CALL cp_fm_create(work1, matrix_struct=newstruct)
     525              : 
     526              :          CALL cp_fm_get_info(delta_mos(re), ncol_local=lcol, ncol_global=nmo, &
     527         1890 :                              nrow_global=nao)
     528         1890 :          CALL cp_fm_get_info(work, ncol_global=newdim)
     529              : 
     530         1890 :          CALL cp_fm_set_all(work, zero, zero)
     531              : 
     532         8132 :          DO icol = 1, lcol
     533        51268 :             work%local_data(:, icol) = delta_mos(re)%local_data(:, icol)
     534        53158 :             work%local_data(:, icol + lcol) = delta_mos(im)%local_data(:, icol)
     535              :          END DO
     536              : 
     537         1890 :          CALL cp_dbcsr_sm_fm_multiply(matrix_s, work, work1, ncol=newdim)
     538              : 
     539         1890 :          CALL cp_fm_release(work)
     540              : 
     541              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, ncol_global=nmo, &
     542              :                                   para_env=delta_mos(re)%matrix_struct%para_env, &
     543         1890 :                                   context=delta_mos(re)%matrix_struct%context)
     544              :          CALL cp_fm_struct_double(newstruct1, &
     545              :                                   tmp_fm_struct, &
     546              :                                   delta_mos(re)%matrix_struct%context, &
     547              :                                   double_col, &
     548         1890 :                                   double_row)
     549              : 
     550         1890 :          CALL cp_fm_create(work, matrix_struct=newstruct1)
     551         1890 :          CALL cp_fm_create(work2, matrix_struct=newstruct1)
     552              : 
     553              :          CALL parallel_gemm("T", "N", nmo, newdim, nao, one, delta_mos(re), &
     554         1890 :                             work1, zero, work)
     555              : 
     556              :          CALL parallel_gemm("T", "N", nmo, newdim, nao, one, delta_mos(im), &
     557         1890 :                             work1, zero, work2)
     558              : 
     559         1890 :          CALL cp_fm_get_info(work, nrow_local=lrow)
     560         5011 :          DO i = 1, lrow
     561        17796 :             DO j = 1, lcol
     562              :                alpha = SQRT((work%local_data(i, j) + work2%local_data(i, j + lcol))**2 + &
     563        12785 :                             (work%local_data(i, j + lcol) - work2%local_data(i, j))**2)
     564        15906 :                max_alpha = MAX(max_alpha, ABS(alpha))
     565              :             END DO
     566              :          END DO
     567              : 
     568         1890 :          CALL cp_fm_release(work)
     569         1890 :          CALL cp_fm_release(work1)
     570         1890 :          CALL cp_fm_release(work2)
     571         1890 :          CALL cp_fm_struct_release(tmp_fm_struct)
     572         1890 :          CALL cp_fm_struct_release(newstruct)
     573         9038 :          CALL cp_fm_struct_release(newstruct1)
     574              : 
     575              :       END DO
     576              : 
     577         1478 :       CALL delta_mos(1)%matrix_struct%para_env%max(max_alpha)
     578         1478 :       delta_eps = SQRT(max_alpha)
     579              : 
     580         1478 :       CALL timestop(handle)
     581              : 
     582         1478 :    END SUBROUTINE rt_convergence
     583              : 
     584              : ! **************************************************************************************************
     585              : !> \brief computes the convergence criterion for RTP and EMD based on the density matrix
     586              : !> \param rtp ...
     587              : !> \param delta_P ...
     588              : !> \param delta_eps ...
     589              : !> \author Samuel Andermatt (02.14)
     590              : ! **************************************************************************************************
     591              : 
     592         1612 :    SUBROUTINE rt_convergence_density(rtp, delta_P, delta_eps)
     593              : 
     594              :       TYPE(rt_prop_type), POINTER                        :: rtp
     595              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: delta_P
     596              :       REAL(dp), INTENT(out)                              :: delta_eps
     597              : 
     598              :       CHARACTER(len=*), PARAMETER :: routineN = 'rt_convergence_density'
     599              :       REAL(KIND=dp), PARAMETER                           :: one = 1.0_dp, zero = 0.0_dp
     600              : 
     601              :       INTEGER                                            :: col_atom, handle, i, ispin, row_atom
     602              :       REAL(dp)                                           :: alpha, max_alpha
     603          806 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_values
     604              :       TYPE(dbcsr_iterator_type)                          :: iter
     605          806 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho_new
     606              :       TYPE(dbcsr_type), POINTER                          :: tmp
     607              :       TYPE(mp_comm_type)                                 :: group
     608              : 
     609          806 :       CALL timeset(routineN, handle)
     610              : 
     611          806 :       CALL get_rtp(rtp=rtp, rho_new=rho_new)
     612              : 
     613         2910 :       DO i = 1, SIZE(rho_new)
     614         2910 :          CALL dbcsr_add(delta_P(i)%matrix, rho_new(i)%matrix, one, -one)
     615              :       END DO
     616              :       !get the maximum value of delta_P
     617         2910 :       DO i = 1, SIZE(delta_P)
     618              :          !square all entries of both matrices
     619         2104 :          CALL dbcsr_iterator_start(iter, delta_P(i)%matrix)
     620        12246 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     621        10142 :             CALL dbcsr_iterator_next_block(iter, row_atom, col_atom, block_values)
     622       788738 :             block_values = block_values*block_values
     623              :          END DO
     624         5014 :          CALL dbcsr_iterator_stop(iter)
     625              :       END DO
     626              :       NULLIFY (tmp)
     627          806 :       ALLOCATE (tmp)
     628          806 :       CALL dbcsr_create(tmp, template=delta_P(1)%matrix, matrix_type="N")
     629         1858 :       DO ispin = 1, SIZE(delta_P)/2
     630         1052 :          CALL dbcsr_desymmetrize(delta_P(2*ispin - 1)%matrix, tmp)
     631         1858 :          CALL dbcsr_add(delta_P(2*ispin)%matrix, tmp, one, one)
     632              :       END DO
     633              :       !the absolute values are now in the even entries of delta_P
     634          806 :       max_alpha = zero
     635         1858 :       DO ispin = 1, SIZE(delta_P)/2
     636         1052 :          CALL dbcsr_iterator_start(iter, delta_P(2*ispin)%matrix)
     637         6220 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     638         5168 :             CALL dbcsr_iterator_next_block(iter, row_atom, col_atom, block_values)
     639       398828 :             alpha = MAXVAL(block_values)
     640         6220 :             IF (alpha > max_alpha) max_alpha = alpha
     641              :          END DO
     642         2910 :          CALL dbcsr_iterator_stop(iter)
     643              :       END DO
     644          806 :       CALL dbcsr_get_info(delta_P(1)%matrix, group=group)
     645          806 :       CALL group%max(max_alpha)
     646          806 :       delta_eps = SQRT(max_alpha)
     647          806 :       CALL dbcsr_deallocate_matrix(tmp)
     648          806 :       CALL timestop(handle)
     649              : 
     650          806 :    END SUBROUTINE rt_convergence_density
     651              : 
     652              : ! **************************************************************************************************
     653              : !> \brief interface to qs_moments. Does only work for nonperiodic dipole
     654              : !> \param qs_env ...
     655              : !> \author Florian Schiffmann (02.09)
     656              : ! **************************************************************************************************
     657              : 
     658          614 :    SUBROUTINE make_moment(qs_env)
     659              : 
     660              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     661              : 
     662              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'make_moment'
     663              : 
     664              :       INTEGER                                            :: handle, output_unit
     665              :       TYPE(cp_logger_type), POINTER                      :: logger
     666              :       TYPE(dft_control_type), POINTER                    :: dft_control
     667              : 
     668          614 :       CALL timeset(routineN, handle)
     669              : 
     670          614 :       NULLIFY (dft_control)
     671              : 
     672          614 :       logger => cp_get_default_logger()
     673          614 :       output_unit = cp_logger_get_default_io_unit(logger)
     674          614 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     675          614 :       IF (dft_control%qs_control%dftb) THEN
     676          120 :          CALL scf_post_calculation_tb(qs_env, "DFTB", .FALSE.)
     677          494 :       ELSE IF (dft_control%qs_control%xtb) THEN
     678           60 :          CALL scf_post_calculation_tb(qs_env, "xTB", .FALSE.)
     679              :       ELSE
     680          434 :          CALL qs_scf_post_moments(qs_env%input, logger, qs_env, output_unit)
     681              :       END IF
     682          614 :       CALL timestop(handle)
     683              : 
     684          614 :    END SUBROUTINE make_moment
     685              : 
     686              : ! **************************************************************************************************
     687              : !> \brief Reports the sparsity pattern of the complex density matrix
     688              : !> \param filter_eps ...
     689              : !> \param rho ...
     690              : !> \author Samuel Andermatt (09.14)
     691              : ! **************************************************************************************************
     692              : 
     693          182 :    SUBROUTINE report_density_occupation(filter_eps, rho)
     694              : 
     695              :       REAL(KIND=dp)                                      :: filter_eps
     696              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho
     697              : 
     698              :       CHARACTER(len=*), PARAMETER :: routineN = 'report_density_occupation'
     699              : 
     700              :       INTEGER                                            :: handle, i, im, ispin, re, unit_nr
     701              :       REAL(KIND=dp)                                      :: eps, occ
     702              :       TYPE(cp_logger_type), POINTER                      :: logger
     703          182 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: tmp
     704              : 
     705          182 :       CALL timeset(routineN, handle)
     706              : 
     707          182 :       logger => cp_get_default_logger()
     708          182 :       unit_nr = cp_logger_get_default_io_unit(logger)
     709          182 :       NULLIFY (tmp)
     710          182 :       CALL dbcsr_allocate_matrix_set(tmp, SIZE(rho))
     711          686 :       DO i = 1, SIZE(rho)
     712          504 :          CALL dbcsr_init_p(tmp(i)%matrix)
     713          504 :          CALL dbcsr_create(tmp(i)%matrix, template=rho(i)%matrix)
     714          686 :          CALL dbcsr_copy(tmp(i)%matrix, rho(i)%matrix)
     715              :       END DO
     716          434 :       DO ispin = 1, SIZE(rho)/2
     717          252 :          re = 2*ispin - 1
     718          252 :          im = 2*ispin
     719          252 :          eps = MAX(filter_eps, 1.0E-11_dp)
     720         2338 :          DO WHILE (eps < 1.1_dp)
     721         2086 :             CALL dbcsr_filter(tmp(re)%matrix, eps)
     722         2086 :             occ = dbcsr_get_occupation(tmp(re)%matrix)
     723         3129 :             IF (unit_nr > 0) WRITE (unit_nr, FMT="((T3,A,I1,A,F15.12,A,T61,F20.10))") "Occupation of rho spin ", &
     724         2086 :                ispin, " eps ", eps, " real: ", occ
     725         2086 :             eps = eps*10
     726              :          END DO
     727          252 :          eps = MAX(filter_eps, 1.0E-11_dp)
     728         2520 :          DO WHILE (eps < 1.1_dp)
     729         2086 :             CALL dbcsr_filter(tmp(im)%matrix, eps)
     730         2086 :             occ = dbcsr_get_occupation(tmp(im)%matrix)
     731         3129 :             IF (unit_nr > 0) WRITE (unit_nr, FMT="((T3,A,I1,A,F15.12,A,T61,F20.10))") "Occupation of rho spin ", &
     732         2086 :                ispin, " eps ", eps, " imag: ", occ
     733         2086 :             eps = eps*10.0_dp
     734              :          END DO
     735              :       END DO
     736          182 :       CALL dbcsr_deallocate_matrix_set(tmp)
     737          182 :       CALL timestop(handle)
     738              : 
     739          182 :    END SUBROUTINE report_density_occupation
     740              : 
     741              : ! **************************************************************************************************
     742              : !> \brief Writes the density matrix and the atomic positions to a restart file
     743              : !> \param rho_new ...
     744              : !> \param history ...
     745              : !> \author Samuel Andermatt (09.14)
     746              : ! **************************************************************************************************
     747              : 
     748           98 :    SUBROUTINE write_rt_p_to_restart(rho_new, history)
     749              : 
     750              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho_new
     751              :       LOGICAL                                            :: history
     752              : 
     753              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'write_rt_p_to_restart'
     754              : 
     755              :       CHARACTER(LEN=default_path_length)                 :: file_name, project_name
     756              :       INTEGER                                            :: handle, im, ispin, re, unit_nr
     757              :       REAL(KIND=dp)                                      :: cs_pos
     758              :       TYPE(cp_logger_type), POINTER                      :: logger
     759              : 
     760           98 :       CALL timeset(routineN, handle)
     761           98 :       logger => cp_get_default_logger()
     762           98 :       IF (logger%para_env%is_source()) THEN
     763           49 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     764              :       ELSE
     765              :          unit_nr = -1
     766              :       END IF
     767              : 
     768           98 :       project_name = logger%iter_info%project_name
     769          234 :       DO ispin = 1, SIZE(rho_new)/2
     770          136 :          re = 2*ispin - 1
     771          136 :          im = 2*ispin
     772          136 :          IF (history) THEN
     773              :             WRITE (file_name, '(A,I0,A)') &
     774            2 :                TRIM(project_name)//"_LS_DM_SPIN_RE", ispin, "_"//TRIM(cp_iter_string(logger%iter_info))//"_RESTART.dm"
     775              :          ELSE
     776          134 :             WRITE (file_name, '(A,I0,A)') TRIM(project_name)//"_LS_DM_SPIN_RE", ispin, "_RESTART.dm"
     777              :          END IF
     778          136 :          cs_pos = dbcsr_checksum(rho_new(re)%matrix, pos=.TRUE.)
     779          136 :          IF (unit_nr > 0) THEN
     780           68 :             WRITE (unit_nr, '(T2,A,E20.8)') "Writing restart DM "//TRIM(file_name)//" with checksum: ", cs_pos
     781              :          END IF
     782          136 :          CALL dbcsr_binary_write(rho_new(re)%matrix, file_name)
     783          136 :          IF (history) THEN
     784              :             WRITE (file_name, '(A,I0,A)') &
     785            2 :                TRIM(project_name)//"_LS_DM_SPIN_IM", ispin, "_"//TRIM(cp_iter_string(logger%iter_info))//"_RESTART.dm"
     786              :          ELSE
     787          134 :             WRITE (file_name, '(A,I0,A)') TRIM(project_name)//"_LS_DM_SPIN_IM", ispin, "_RESTART.dm"
     788              :          END IF
     789          136 :          cs_pos = dbcsr_checksum(rho_new(im)%matrix, pos=.TRUE.)
     790          136 :          IF (unit_nr > 0) THEN
     791           68 :             WRITE (unit_nr, '(T2,A,E20.8)') "Writing restart DM "//TRIM(file_name)//" with checksum: ", cs_pos
     792              :          END IF
     793          234 :          CALL dbcsr_binary_write(rho_new(im)%matrix, file_name)
     794              :       END DO
     795              : 
     796           98 :       CALL timestop(handle)
     797              : 
     798           98 :    END SUBROUTINE write_rt_p_to_restart
     799              : 
     800              : ! **************************************************************************************************
     801              : !> \brief Collocation of the current and printing of it in a cube file
     802              : !> \param qs_env ...
     803              : !> \param P_im ...
     804              : !> \param dft_section ...
     805              : !> \param spin ...
     806              : !> \param nspin ...
     807              : !> \author Samuel Andermatt (06.15)
     808              : ! **************************************************************************************************
     809           48 :    SUBROUTINE rt_current(qs_env, P_im, dft_section, spin, nspin)
     810              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     811              :       TYPE(dbcsr_type), POINTER                          :: P_im
     812              :       TYPE(section_vals_type), POINTER                   :: dft_section
     813              :       INTEGER                                            :: spin, nspin
     814              : 
     815              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'rt_current'
     816              : 
     817              :       CHARACTER(len=1)                                   :: char_spin
     818              :       CHARACTER(len=14)                                  :: ext
     819              :       CHARACTER(len=2)                                   :: sdir
     820              :       INTEGER                                            :: dir, handle, print_unit
     821           48 :       INTEGER, DIMENSION(:), POINTER                     :: stride(:)
     822              :       LOGICAL                                            :: mpi_io
     823              :       TYPE(cp_logger_type), POINTER                      :: logger
     824              :       TYPE(current_env_type)                             :: current_env
     825              :       TYPE(dbcsr_type), POINTER                          :: tmp, zero
     826              :       TYPE(particle_list_type), POINTER                  :: particles
     827              :       TYPE(pw_c1d_gs_type)                               :: gs
     828              :       TYPE(pw_env_type), POINTER                         :: pw_env
     829              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     830              :       TYPE(pw_r3d_rs_type)                               :: rs
     831              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     832              : 
     833           48 :       CALL timeset(routineN, handle)
     834              : 
     835           48 :       logger => cp_get_default_logger()
     836           48 :       CALL get_qs_env(qs_env=qs_env, subsys=subsys, pw_env=pw_env)
     837           48 :       CALL qs_subsys_get(subsys, particles=particles)
     838           48 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
     839              : 
     840           48 :       NULLIFY (zero, tmp)
     841           48 :       ALLOCATE (zero, tmp)
     842           48 :       CALL dbcsr_create(zero, template=P_im)
     843           48 :       CALL dbcsr_copy(zero, P_im)
     844           48 :       CALL dbcsr_set(zero, 0.0_dp)
     845           48 :       CALL dbcsr_create(tmp, template=P_im)
     846           48 :       CALL dbcsr_copy(tmp, P_im)
     847           48 :       IF (nspin == 1) THEN
     848           32 :          CALL dbcsr_scale(tmp, 0.5_dp)
     849              :       END IF
     850           48 :       current_env%gauge = -1
     851           48 :       current_env%gauge_init = .FALSE.
     852           48 :       CALL auxbas_pw_pool%create_pw(rs)
     853           48 :       CALL auxbas_pw_pool%create_pw(gs)
     854              : 
     855              :       NULLIFY (stride)
     856           48 :       ALLOCATE (stride(3))
     857              : 
     858          192 :       DO dir = 1, 3
     859              : 
     860          144 :          CALL pw_zero(rs)
     861          144 :          CALL pw_zero(gs)
     862              : 
     863          144 :          CALL calculate_jrho_resp(zero, tmp, zero, zero, dir, dir, rs, gs, qs_env, current_env, retain_rsgrid=.TRUE.)
     864              : 
     865          576 :          stride = section_get_ivals(dft_section, "REAL_TIME_PROPAGATION%PRINT%CURRENT%STRIDE")
     866              : 
     867          144 :          IF (dir == 1) THEN
     868           48 :             sdir = "-x"
     869           96 :          ELSEIF (dir == 2) THEN
     870           48 :             sdir = "-y"
     871              :          ELSE
     872           48 :             sdir = "-z"
     873              :          END IF
     874          144 :          WRITE (char_spin, "(I1)") spin
     875              : 
     876          144 :          ext = "-SPIN-"//char_spin//sdir//".cube"
     877          144 :          mpi_io = .TRUE.
     878              :          print_unit = cp_print_key_unit_nr(logger, dft_section, "REAL_TIME_PROPAGATION%PRINT%CURRENT", &
     879              :                                            extension=ext, file_status="REPLACE", file_action="WRITE", &
     880          144 :                                            log_filename=.FALSE., mpi_io=mpi_io)
     881              : 
     882              :          CALL cp_pw_to_cube(rs, print_unit, "EMD current", particles=particles, stride=stride, &
     883          144 :                             mpi_io=mpi_io)
     884              : 
     885              :          CALL cp_print_key_finished_output(print_unit, logger, dft_section, "REAL_TIME_PROPAGATION%PRINT%CURRENT", &
     886          192 :                                            mpi_io=mpi_io)
     887              : 
     888              :       END DO
     889              : 
     890           48 :       CALL auxbas_pw_pool%give_back_pw(rs)
     891           48 :       CALL auxbas_pw_pool%give_back_pw(gs)
     892              : 
     893           48 :       CALL dbcsr_deallocate_matrix(zero)
     894           48 :       CALL dbcsr_deallocate_matrix(tmp)
     895              : 
     896           48 :       DEALLOCATE (stride)
     897              : 
     898           48 :       CALL timestop(handle)
     899              : 
     900         3504 :    END SUBROUTINE rt_current
     901              : 
     902              : ! **************************************************************************************************
     903              : !> \brief Interface routine to trigger writing of results available from normal
     904              : !>        SCF. Can write MO-dependent and MO free results (needed for call from
     905              : !>        the linear scaling code)
     906              : !>        Update: trigger also some of prints for time-dependent runs
     907              : !> \param qs_env ...
     908              : !> \param rtp ...
     909              : !> \par History
     910              : !>      2022-11 Update [Guillaume Le Breton]
     911              : ! **************************************************************************************************
     912          494 :    SUBROUTINE write_available_results(qs_env, rtp)
     913              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     914              :       TYPE(rt_prop_type), POINTER                        :: rtp
     915              : 
     916              :       CHARACTER(len=*), PARAMETER :: routineN = 'write_available_results'
     917              : 
     918              :       INTEGER                                            :: handle
     919              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     920              : 
     921          494 :       CALL timeset(routineN, handle)
     922              : 
     923          494 :       CALL get_qs_env(qs_env, scf_env=scf_env)
     924          494 :       IF (rtp%linear_scaling) THEN
     925          182 :          CALL write_mo_free_results(qs_env)
     926              :       ELSE
     927          312 :          CALL write_mo_free_results(qs_env)
     928          312 :          CALL write_mo_dependent_results(qs_env, scf_env)
     929              :          ! Time-dependent MO print
     930          312 :          CALL write_rtp_mos_to_output_unit(qs_env, rtp)
     931          312 :          CALL write_rtp_mo_cubes(qs_env, rtp)
     932              :       END IF
     933              : 
     934          494 :       CALL timestop(handle)
     935              : 
     936          494 :    END SUBROUTINE write_available_results
     937              : 
     938              : ! **************************************************************************************************
     939              : !> \brief Print the field applied to the system. Either the electric
     940              : !>        field or the vector potential depending on the gauge used
     941              : !> \param qs_env ...
     942              : !> \param dft_section ...
     943              : !> \par History
     944              : !>      2023-01  Created [Guillaume Le Breton]
     945              : ! **************************************************************************************************
     946           30 :    SUBROUTINE print_field_applied(qs_env, dft_section)
     947              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     948              :       TYPE(section_vals_type), POINTER                   :: dft_section
     949              : 
     950              :       CHARACTER(LEN=3), DIMENSION(3)                     :: rlab
     951              :       CHARACTER(LEN=default_path_length)                 :: filename
     952              :       INTEGER                                            :: i, i_step, output_unit, unit_nr
     953              :       LOGICAL                                            :: new_file
     954              :       REAL(kind=dp)                                      :: field(3)
     955              :       TYPE(cp_logger_type), POINTER                      :: logger
     956              :       TYPE(dft_control_type), POINTER                    :: dft_control
     957              :       TYPE(rt_prop_type), POINTER                        :: rtp
     958              : 
     959           30 :       NULLIFY (dft_control)
     960              : 
     961           30 :       logger => cp_get_default_logger()
     962           30 :       output_unit = cp_logger_get_default_io_unit(logger)
     963              : 
     964           30 :       CALL get_qs_env(qs_env, dft_control=dft_control, rtp=rtp)
     965              : 
     966           30 :       i_step = rtp%istep
     967              : 
     968              :       unit_nr = cp_print_key_unit_nr(logger, dft_section, &
     969           30 :                                      "REAL_TIME_PROPAGATION%PRINT%FIELD", extension=".dat", is_new_file=new_file)
     970              : 
     971           30 :       IF (output_unit > 0) THEN
     972           60 :          rlab = [CHARACTER(LEN=3) :: "X", "Y", "Z"]
     973           15 :          IF (unit_nr /= output_unit) THEN
     974           15 :             INQUIRE (UNIT=unit_nr, NAME=filename)
     975              :             WRITE (UNIT=output_unit, FMT="(/,T2,A,2(/,T3,A),/)") &
     976           15 :                "FIELD", "The field applied is written to the file:", &
     977           30 :                TRIM(filename)
     978              :          ELSE
     979            0 :             WRITE (UNIT=output_unit, FMT="(/,T2,A)") "FIELD APPLIED [a.u.]"
     980              :             WRITE (UNIT=output_unit, FMT="(T5,3(A,A,E16.8,1X))") &
     981            0 :                (TRIM(rlab(i)), "=", dft_control%rtp_control%field(i), i=1, 3)
     982              :          END IF
     983              : 
     984           15 :          IF (new_file) THEN
     985            3 :             IF (dft_control%apply_efield_field) THEN
     986            1 :                WRITE (UNIT=unit_nr, FMT='("#",5X,A,8X,A,3(6X,A))') "Step Nr.", "Time[fs]", " Field X", "   Field Y", "   Field Z"
     987            2 :             ELSE IF (dft_control%apply_vector_potential) THEN
     988            0 :                WRITE (UNIT=unit_nr, FMT='("#",5X,A,8X,A,6(6X,A))') "Step Nr.", "Time[fs]", " Field X", "   Field Y", "   Field Z", &
     989            0 :                   "  Vec. Pot. X", "  Vec. Pot. Y", "    Vec. Pot. Z"
     990              :             END IF
     991              :          END IF
     992              : 
     993           15 :          field = 0.0_dp
     994           15 :          IF (dft_control%apply_efield_field) THEN
     995            4 :             CALL make_field(dft_control, field, qs_env%sim_step, qs_env%sim_time)
     996            4 :             WRITE (UNIT=unit_nr, FMT="(I10,F16.6,3(F16.8,1X))") qs_env%sim_step, qs_env%sim_time*femtoseconds, &
     997            8 :                field(1), field(2), field(3)
     998              : !            DO i=1,3
     999              : !               IF (ABS(field(i))< 10E-10) field(i) = 0.0_dp
    1000              : !            END IF
    1001           11 :          ELSE IF (dft_control%apply_vector_potential) THEN
    1002            9 :             WRITE (UNIT=unit_nr, FMT="(I10,F16.6,6(F16.8,1X))") qs_env%sim_step, qs_env%sim_time*femtoseconds, &
    1003            9 :                dft_control%rtp_control%field(1), dft_control%rtp_control%field(2), dft_control%rtp_control%field(3), &
    1004           18 :                dft_control%rtp_control%vec_pot(1), dft_control%rtp_control%vec_pot(2), dft_control%rtp_control%vec_pot(3)
    1005              :          END IF
    1006              : 
    1007              :       END IF
    1008              : 
    1009              :       CALL cp_print_key_finished_output(unit_nr, logger, dft_section, &
    1010           30 :                                         "REAL_TIME_PROPAGATION%PRINT%FIELD")
    1011              : 
    1012           30 :    END SUBROUTINE print_field_applied
    1013              : 
    1014              : ! **************************************************************************************************
    1015              : !> \brief Print the components of the total energy used in an RTP calculation
    1016              : !> \param qs_env ...
    1017              : !> \param dft_section ...
    1018              : !> \par History
    1019              : !>      2024-02  Created [ANB]
    1020              : ! **************************************************************************************************
    1021            4 :    SUBROUTINE print_rtp_energy_components(qs_env, dft_section)
    1022              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1023              :       TYPE(section_vals_type), POINTER                   :: dft_section
    1024              : 
    1025              :       CHARACTER(LEN=default_path_length)                 :: filename
    1026              :       INTEGER                                            :: i_step, output_unit, unit_nr
    1027              :       LOGICAL                                            :: new_file
    1028              :       TYPE(cp_logger_type), POINTER                      :: logger
    1029              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1030              :       TYPE(qs_energy_type), POINTER                      :: energy
    1031              :       TYPE(rt_prop_type), POINTER                        :: rtp
    1032              : 
    1033            4 :       NULLIFY (dft_control, energy, rtp)
    1034              : 
    1035            4 :       logger => cp_get_default_logger()
    1036            4 :       output_unit = cp_logger_get_default_io_unit(logger)
    1037              : 
    1038            4 :       CALL get_qs_env(qs_env, dft_control=dft_control, rtp=rtp, energy=energy)
    1039            4 :       i_step = rtp%istep
    1040              : 
    1041              :       unit_nr = cp_print_key_unit_nr(logger, dft_section, &
    1042              :                                      "REAL_TIME_PROPAGATION%PRINT%E_CONSTITUENTS", extension=".ener", &
    1043            4 :                                      file_action="WRITE", is_new_file=new_file)
    1044              : 
    1045            4 :       IF (output_unit > 0) THEN
    1046            2 :          IF (unit_nr /= output_unit) THEN
    1047            2 :             INQUIRE (UNIT=unit_nr, NAME=filename)
    1048              :             WRITE (UNIT=output_unit, FMT="(/,T2,A,2(/,T3,A),/)") &
    1049            2 :                "ENERGY_CONSTITUENTS", "Total Energy constituents written to file:", &
    1050            4 :                TRIM(filename)
    1051              :          ELSE
    1052            0 :             WRITE (UNIT=output_unit, FMT="(/,T2,A)") "ENERGY_CONSTITUENTS"
    1053              :          END IF
    1054              : 
    1055            2 :          IF (new_file) THEN
    1056              :             ! NOTE that these are not all terms contributing to the total energy for RTP, only a selection of those
    1057              :             ! most significant / impactful. Therefore the printed components likely will not add up to the total energy.
    1058            1 :             WRITE (UNIT=unit_nr, FMT='("#",5X,A,8X,A,10(6X,A))') "Step Nr.", "Time[fs]", &
    1059            1 :                "Total ener.[a.u.]", "core[a.u.]   ", " overlap [a.u.]", "hartree[a.u.]", " exc. [a.u.] ", &
    1060            2 :                " hartree 1c[a.u.]", "exc 1c[a.u.] ", "exc admm[a.u.]", "exc 1c admm[a.u.]", "efield LG"
    1061              : 
    1062              :          END IF
    1063              :          WRITE (UNIT=unit_nr, FMT="(I10,F20.6,10(F20.9))") &
    1064            2 :             qs_env%sim_step, qs_env%sim_time*femtoseconds, &
    1065            2 :             energy%total, energy%core, energy%core_overlap, energy%hartree, energy%exc, &
    1066            4 :             energy%hartree_1c, energy%exc1, energy%exc_aux_fit, energy%exc1_aux_fit, energy%efield_core
    1067              : 
    1068              :       END IF
    1069              : 
    1070              :       CALL cp_print_key_finished_output(unit_nr, logger, dft_section, &
    1071            4 :                                         "REAL_TIME_PROPAGATION%PRINT%E_CONSTITUENTS")
    1072              : 
    1073            4 :    END SUBROUTINE print_rtp_energy_components
    1074              : 
    1075              : ! **************************************************************************************************
    1076              : !> \brief Print the dipole moments into a file
    1077              : !> \param moments_section Section of the input defining the file/stream to print the moments to
    1078              : !> \param info_unit Unit where standard output from the program is written - for add. identifiers
    1079              : !> \param moments Actual moment values (for specific time step)
    1080              : !> \param time Current simulation time
    1081              : !> \param imag_opt Whether to calculate the imaginary part
    1082              : !> \par History
    1083              : !>      10.2025  Created [Marek]
    1084              : ! **************************************************************************************************
    1085          616 :    SUBROUTINE print_moments(moments_section, info_unit, moments, time, imag_opt)
    1086              :       TYPE(section_vals_type), POINTER                   :: moments_section
    1087              :       INTEGER                                            :: info_unit
    1088              :       COMPLEX(kind=dp), DIMENSION(:, :)                  :: moments
    1089              :       REAL(kind=dp), OPTIONAL                            :: time
    1090              :       LOGICAL, OPTIONAL                                  :: imag_opt
    1091              : 
    1092              :       CHARACTER(len=14), DIMENSION(4)                    :: file_extensions
    1093              :       INTEGER                                            :: i, j, ndir, nspin, print_unit
    1094              :       LOGICAL                                            :: imaginary
    1095              :       TYPE(cp_logger_type), POINTER                      :: logger
    1096              : 
    1097              : ! Index 1 : spin, Index 2 : direction
    1098              : 
    1099          616 :       nspin = SIZE(moments, 1)
    1100          616 :       ndir = SIZE(moments, 2)
    1101              : 
    1102          616 :       IF (nspin < 1) CPABORT("Zero spin index size in print moments!")
    1103          616 :       IF (ndir < 1) CPABORT("Zero direction index size in print moments!")
    1104              : 
    1105          616 :       imaginary = .TRUE.
    1106          616 :       IF (PRESENT(imag_opt)) imaginary = imag_opt
    1107              : 
    1108              :       ! Get the program run info unit and target unit
    1109              :       ! If these are the same (most likely the case of __STD_OUT__), add
    1110              :       ! extra identifier to the printed output
    1111          616 :       file_extensions(1) = "_SPIN_A_RE.dat"
    1112          616 :       file_extensions(2) = "_SPIN_A_IM.dat"
    1113          616 :       file_extensions(3) = "_SPIN_B_RE.dat"
    1114          616 :       file_extensions(4) = "_SPIN_B_IM.dat"
    1115          616 :       logger => cp_get_default_logger()
    1116         1268 :       DO i = 1, nspin
    1117              :          ! Real part
    1118          652 :          print_unit = cp_print_key_unit_nr(logger, moments_section, extension=file_extensions(2*i - 1))
    1119          652 :          IF (print_unit == info_unit .AND. print_unit > 0) THEN
    1120              :             ! Do the output with additional suffix
    1121          211 :             WRITE (print_unit, "(A18)", advance="no") " MOMENTS_TRACE_RE|"
    1122              :          END IF
    1123          652 :          IF (print_unit > 0) THEN
    1124          230 :             IF (PRESENT(time)) WRITE (print_unit, "(E20.8E3)", advance="no") time*femtoseconds
    1125          690 :             DO j = 1, ndir - 1
    1126          690 :                WRITE (print_unit, "(E20.8E3)", advance="no") REAL(moments(i, j))
    1127              :             END DO
    1128              :             ! Write the last direction
    1129          230 :             WRITE (print_unit, "(E20.8E3)") REAL(moments(i, ndir))
    1130              :          END IF
    1131          652 :          CALL cp_print_key_finished_output(print_unit, logger, moments_section)
    1132              :          ! Same for imaginary part
    1133         1268 :          IF (imaginary) THEN
    1134          562 :             print_unit = cp_print_key_unit_nr(logger, moments_section, extension=file_extensions(2*i))
    1135          562 :             IF (print_unit == info_unit .AND. print_unit > 0) THEN
    1136              :                ! Do the output with additional suffix
    1137          211 :                WRITE (print_unit, "(A18)", advance="no") " MOMENTS_TRACE_IM|"
    1138              :             END IF
    1139          562 :             IF (print_unit > 0) THEN
    1140          230 :                IF (PRESENT(time)) WRITE (print_unit, "(E20.8E3)", advance="no") time*femtoseconds
    1141          690 :                DO j = 1, ndir - 1
    1142          690 :                   WRITE (print_unit, "(E20.8E3)", advance="no") AIMAG(moments(i, j))
    1143              :                END DO
    1144              :                ! Write the last direction
    1145          230 :                WRITE (print_unit, "(E20.8E3)") AIMAG(moments(i, ndir))
    1146              :             END IF
    1147          562 :             CALL cp_print_key_finished_output(print_unit, logger, moments_section)
    1148              :          END IF
    1149              :       END DO
    1150              : 
    1151          616 :    END SUBROUTINE print_moments
    1152              : 
    1153              : ! **************************************************************************************************
    1154              : !> \brief Calculate the values of real/imaginary parts of moments in all directions
    1155              : !> \param moment_matrices Local matrix representations of dipole (position) operator
    1156              : !> \param density_matrices Density matrices (spin and real+complex parts)
    1157              : !> \param work Extra dbcsr matrix for work
    1158              : !> \param moment Resulting moments (spin and direction)
    1159              : !> \param imag_opt Whether to calculate the imaginary part of the moment
    1160              : !> \par History
    1161              : !>      10.2025  Created [Marek]
    1162              : ! **************************************************************************************************
    1163           54 :    SUBROUTINE calc_local_moment(moment_matrices, density_matrices, work, moment, imag_opt)
    1164              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: moment_matrices, density_matrices
    1165              :       TYPE(dbcsr_type)                                   :: work
    1166              :       COMPLEX(kind=dp), DIMENSION(:, :)                  :: moment
    1167              :       LOGICAL, OPTIONAL                                  :: imag_opt
    1168              : 
    1169              :       INTEGER                                            :: i, k, nspin
    1170              :       LOGICAL                                            :: imag
    1171              :       REAL(kind=dp)                                      :: real_moment
    1172              : 
    1173           54 :       imag = .FALSE.
    1174           54 :       IF (PRESENT(imag_opt)) imag = imag_opt
    1175           54 :       nspin = SIZE(density_matrices)/2
    1176              : 
    1177          144 :       DO i = 1, nspin
    1178          414 :          DO k = 1, 3
    1179              :             CALL dbcsr_multiply("N", "N", -1.0_dp, &
    1180              :                                 density_matrices(2*i - 1)%matrix, moment_matrices(k)%matrix, &
    1181          270 :                                 0.0_dp, work)
    1182          270 :             CALL dbcsr_trace(work, real_moment)
    1183          270 :             moment(i, k) = CMPLX(real_moment, 0.0, kind=dp)
    1184          360 :             IF (imag) THEN
    1185              :                CALL dbcsr_multiply("N", "N", -1.0_dp, &
    1186              :                                    density_matrices(2*i)%matrix, moment_matrices(k)%matrix, &
    1187            0 :                                    0.0_dp, work)
    1188            0 :                CALL dbcsr_trace(work, real_moment)
    1189            0 :                moment(i, k) = moment(i, k) + CMPLX(0.0, real_moment, kind=dp)
    1190              :             END IF
    1191              :          END DO
    1192              :       END DO
    1193              : 
    1194           54 :    END SUBROUTINE calc_local_moment
    1195              : 
    1196              : ! **************************************************************************************************
    1197              : !> \brief Calculate and print the Fourier transforms + polarizabilites from moment trace
    1198              : !> \param rtp_section The RTP input section (needed to access PRINT configurations)
    1199              : !> \param moments Moment trace
    1200              : !> \param times Corresponding times
    1201              : !> \param fields Corresponding fields
    1202              : !> \param rtc rt_control_type that includes metadata
    1203              : !> \param info_opt ...
    1204              : !> \param cell If present, used to change the delta peak representation to be in units of reciprocal lattice
    1205              : !> \par History
    1206              : !>      10.2025  Created [Marek]
    1207              : ! **************************************************************************************************
    1208           30 :    SUBROUTINE print_ft(rtp_section, moments, times, fields, rtc, info_opt, cell)
    1209              :       TYPE(section_vals_type), POINTER                   :: rtp_section
    1210              :       COMPLEX(kind=dp), DIMENSION(:, :, :), POINTER      :: moments
    1211              :       REAL(kind=dp), DIMENSION(:), POINTER               :: times
    1212              :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: fields
    1213              :       TYPE(rtp_control_type), POINTER                    :: rtc
    1214              :       INTEGER, OPTIONAL                                  :: info_opt
    1215              :       TYPE(cell_type), OPTIONAL, POINTER                 :: cell
    1216              : 
    1217              :       CHARACTER(len=11), DIMENSION(2)                    :: file_extensions
    1218           30 :       CHARACTER(len=20), ALLOCATABLE, DIMENSION(:)       :: headers
    1219              :       CHARACTER(len=21)                                  :: prefix
    1220              :       CHARACTER(len=5)                                   :: prefix_format
    1221           30 :       COMPLEX(kind=dp), ALLOCATABLE, DIMENSION(:)        :: omegas_complex, omegas_pade
    1222           30 :       COMPLEX(kind=dp), ALLOCATABLE, DIMENSION(:, :)     :: field_results, field_results_pade, &
    1223           30 :                                                             pol_results, pol_results_pade, &
    1224           30 :                                                             results, results_pade, value_series
    1225              :       INTEGER                                            :: ft_unit, i, info_unit, k, n, n_elems, &
    1226              :                                                             n_pade, nspin
    1227              :       LOGICAL                                            :: do_moments_ft, do_polarizability
    1228              :       REAL(kind=dp)                                      :: damping, t0
    1229           30 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: omegas, omegas_pade_real
    1230              :       REAL(kind=dp), DIMENSION(3)                        :: delta_vec
    1231              :       TYPE(cp_logger_type), POINTER                      :: logger
    1232              :       TYPE(section_vals_type), POINTER                   :: moment_ft_section, pol_section
    1233              : 
    1234              : ! For results, using spin * direction for first index, e.g. for nspin = 2
    1235              : ! results(1,:) = (spin=1 and direction=1,:),
    1236              : ! results(5,:) = (spin=2 and direction=2,:)
    1237              : 
    1238           30 :       logger => cp_get_default_logger()
    1239              : 
    1240           30 :       moment_ft_section => section_vals_get_subs_vals(rtp_section, "PRINT%MOMENTS_FT")
    1241           30 :       pol_section => section_vals_get_subs_vals(rtp_section, "PRINT%POLARIZABILITY")
    1242              : 
    1243           30 :       nspin = SIZE(moments, 1)
    1244           30 :       n = SIZE(times)
    1245           30 :       n_elems = SIZE(rtc%print_pol_elements, 1)
    1246              : 
    1247           30 :       info_unit = -1
    1248           30 :       IF (PRESENT(info_opt)) info_unit = info_opt
    1249              : 
    1250              :       ! NOTE : Allows for at most 2 spin species
    1251           30 :       file_extensions(1) = "_SPIN_A.dat"
    1252           30 :       file_extensions(2) = "_SPIN_B.dat"
    1253              : 
    1254              :       ! Determine whether MOMENTS_FT and/or polarizability needs to be calculated
    1255           30 :       do_moments_ft = cp_printkey_is_on(logger%iter_info, moment_ft_section)
    1256           30 :       do_polarizability = cp_printkey_is_on(logger%iter_info, pol_section)
    1257           30 :       do_polarizability = do_polarizability .AND. (n_elems > 0)
    1258              : 
    1259           30 :       damping = rtc%ft_damping
    1260           30 :       t0 = rtc%ft_t0
    1261              : 
    1262              :       ! Determine field ft if polarizability required
    1263           30 :       IF (do_polarizability) THEN
    1264           30 :          ALLOCATE (field_results(3, n))
    1265           10 :          IF (rtc%apply_delta_pulse) THEN
    1266              :             ! Constant real FT
    1267            8 :             IF (PRESENT(cell)) THEN
    1268              :                delta_vec(:) = (REAL(rtc%delta_pulse_direction(1), kind=dp)*cell%h_inv(1, :) + &
    1269              :                                REAL(rtc%delta_pulse_direction(2), kind=dp)*cell%h_inv(2, :) + &
    1270              :                                REAL(rtc%delta_pulse_direction(3), kind=dp)*cell%h_inv(3, :)) &
    1271            0 :                               *twopi*rtc%delta_pulse_scale
    1272              :             ELSE
    1273           32 :                delta_vec(:) = REAL(rtc%delta_pulse_direction(:), kind=dp)*rtc%delta_pulse_scale
    1274              :             END IF
    1275           32 :             DO k = 1, 3
    1276         4256 :                field_results(k, :) = CMPLX(delta_vec(k), 0.0, kind=dp)
    1277              :             END DO
    1278              :          ELSE
    1279              :             ! Do explicit FT
    1280              :             CALL multi_fft(times, fields, field_results, &
    1281            2 :                            damping_opt=damping, t0_opt=t0, subtract_initial_opt=.TRUE.)
    1282              :          END IF
    1283              :       END IF
    1284              : 
    1285           30 :       IF (do_moments_ft .OR. do_polarizability) THEN
    1286              :          ! We need to transform at least the moments
    1287              :          ! NOTE : Might be able to save some memory by only doing FT of actually
    1288              :          ! required moments, but for now, doing FT of all moment directions
    1289           40 :          ALLOCATE (results(3*nspin, n))
    1290           30 :          ALLOCATE (omegas(n))
    1291           30 :          ALLOCATE (value_series(3*nspin, n))
    1292           20 :          DO i = 1, nspin
    1293           50 :             DO k = 1, 3
    1294         4570 :                value_series(3*(i - 1) + k, :) = moments(i, k, :)
    1295              :             END DO
    1296              :          END DO
    1297              :          ! TODO : Choose whether the initial subtraction is applied in &FT section?
    1298              :          CALL multi_fft(times, value_series, results, omegas, &
    1299           10 :                         damping_opt=damping, t0_opt=t0, subtract_initial_opt=.TRUE.)
    1300           10 :          DEALLOCATE (value_series)
    1301           20 :          DO i = 1, nspin
    1302              :             ! Output to FT file, if needed
    1303              :             ft_unit = cp_print_key_unit_nr(logger, moment_ft_section, extension=file_extensions(i), &
    1304           10 :                                            file_form="FORMATTED", file_position="REWIND")
    1305              :             ! Print header
    1306           10 :             IF (ft_unit > 0) THEN
    1307            5 :                ALLOCATE (headers(7))
    1308            5 :                headers(2) = "      x,real [at.u.]"
    1309            5 :                headers(3) = "      x,imag [at.u.]"
    1310            5 :                headers(4) = "      y,real [at.u.]"
    1311            5 :                headers(5) = "      y,imag [at.u.]"
    1312            5 :                headers(6) = "      z,real [at.u.]"
    1313            5 :                headers(7) = "      z,imag [at.u.]"
    1314            5 :                IF (info_unit == ft_unit) THEN
    1315            0 :                   headers(1) = "#        Energy [eV]"
    1316            0 :                   prefix = " MOMENTS_FT|"
    1317            0 :                   prefix_format = "(A12)"
    1318              :                   CALL print_ft_file(ft_unit, headers, omegas, results(3*(i - 1) + 1:3*(i - 1) + 3, :), &
    1319            0 :                                      prefix, prefix_format, evolt)
    1320              :                ELSE
    1321            5 :                   headers(1) = "#      omega [at.u.]"
    1322            5 :                   CALL print_ft_file(ft_unit, headers, omegas, results(3*(i - 1) + 1:3*(i - 1) + 3, :))
    1323              :                END IF
    1324            5 :                DEALLOCATE (headers)
    1325              :             END IF
    1326           20 :             CALL cp_print_key_finished_output(ft_unit, logger, moment_ft_section)
    1327              :          END DO
    1328              :       END IF
    1329              : 
    1330           30 :       IF (rtc%pade_requested .AND. (do_moments_ft .OR. do_polarizability)) THEN
    1331            6 :          ALLOCATE (omegas_complex(SIZE(omegas)))
    1332         1004 :          omegas_complex(:) = CMPLX(omegas(:), 0.0, kind=dp)
    1333            2 :          n_pade = INT((rtc%pade_e_max - rtc%pade_e_min)/rtc%pade_e_step)
    1334            6 :          ALLOCATE (omegas_pade(n_pade))
    1335            6 :          ALLOCATE (omegas_pade_real(n_pade))
    1336              :          ! Construct omegas_pade and omegas_complex
    1337         2000 :          DO i = 1, n_pade
    1338         1998 :             omegas_pade_real(i) = (i - 1)*rtc%pade_e_step + rtc%pade_e_min
    1339         2000 :             omegas_pade(i) = CMPLX(omegas_pade_real(i), 0.0, kind=dp)
    1340              :          END DO
    1341         8000 :          ALLOCATE (results_pade(nspin*3, n_pade), source=CMPLX(0.0, 0.0, kind=dp))
    1342            4 :          DO i = 1, nspin
    1343            8 :             DO k = 1, 3
    1344              :                CALL greenx_refine_ft(rtc%pade_fit_e_min, rtc%pade_fit_e_max, omegas_complex, results(3*(i - 1) + k, :), &
    1345            8 :                                      omegas_pade, results_pade(3*(i - 1) + k, :))
    1346              :             END DO
    1347              :             ! Print to a file
    1348              :             ft_unit = cp_print_key_unit_nr(logger, moment_ft_section, extension="_PADE"//file_extensions(i), &
    1349            2 :                                            file_form="FORMATTED", file_position="REWIND")
    1350            4 :             IF (ft_unit > 0) THEN
    1351            1 :                ALLOCATE (headers(7))
    1352            1 :                headers(2) = " x,real,pade [at.u.]"
    1353            1 :                headers(3) = " x,imag,pade [at.u.]"
    1354            1 :                headers(4) = " y,real,pade [at.u.]"
    1355            1 :                headers(5) = " y,imag,pade [at.u.]"
    1356            1 :                headers(6) = " z,real,pade [at.u.]"
    1357            1 :                headers(7) = " z,imag,pade [at.u.]"
    1358            1 :                IF (info_unit == ft_unit) THEN
    1359            0 :                   headers(1) = "#        Energy [eV]"
    1360            0 :                   prefix = " MOMENTS_FT_PADE|"
    1361            0 :                   prefix_format = "(A17)"
    1362              :                   CALL print_ft_file(ft_unit, headers, omegas_pade_real, results_pade(3*(i - 1) + 1:3*(i - 1) + 3, :), &
    1363            0 :                                      prefix, prefix_format, evolt)
    1364              :                ELSE
    1365            1 :                   headers(1) = "#      omega [at.u.]"
    1366            1 :                   CALL print_ft_file(ft_unit, headers, omegas_pade_real, results_pade(3*(i - 1) + 1:3*(i - 1) + 3, :))
    1367              :                END IF
    1368            1 :                DEALLOCATE (headers)
    1369              :             END IF
    1370              :          END DO
    1371              :       END IF
    1372              : 
    1373           30 :       IF (do_polarizability) THEN
    1374              :          ! get the polarizability elements, as required
    1375           40 :          ALLOCATE (pol_results(n_elems, n))
    1376           20 :          DO i = 1, nspin
    1377           40 :             DO k = 1, n_elems
    1378              :                ! NOTE - field is regularized to small value
    1379              :                pol_results(k, :) = results(3*(i - 1) + &
    1380              :                                            rtc%print_pol_elements(k, 1), :)/ &
    1381              :                                    (field_results(rtc%print_pol_elements(k, 2), :) + &
    1382         4570 :                                     1.0e-10*field_results(rtc%print_pol_elements(k, 2), 2))
    1383              :             END DO
    1384              :             ! Print to the file
    1385              :             ft_unit = cp_print_key_unit_nr(logger, pol_section, extension=file_extensions(i), &
    1386           10 :                                            file_form="FORMATTED", file_position="REWIND")
    1387           10 :             IF (ft_unit > 0) THEN
    1388           15 :                ALLOCATE (headers(2*n_elems + 1))
    1389           20 :                DO k = 1, n_elems
    1390           15 :                   WRITE (headers(2*k), "(A16,I2,I2)") "real pol. elem.", &
    1391           15 :                      rtc%print_pol_elements(k, 1), &
    1392           30 :                      rtc%print_pol_elements(k, 2)
    1393           15 :                   WRITE (headers(2*k + 1), "(A16,I2,I2)") "imag pol. elem.", &
    1394           15 :                      rtc%print_pol_elements(k, 1), &
    1395           35 :                      rtc%print_pol_elements(k, 2)
    1396              :                END DO
    1397              :                ! Write header
    1398            5 :                IF (info_unit == ft_unit) THEN
    1399            2 :                   headers(1) = "#        Energy [eV]"
    1400            2 :                   prefix = " POLARIZABILITY|"
    1401            2 :                   prefix_format = "(A16)"
    1402              :                   CALL print_ft_file(ft_unit, headers, omegas, pol_results, &
    1403            2 :                                      prefix, prefix_format, evolt)
    1404              :                ELSE
    1405            3 :                   headers(1) = "#      omega [at.u.]"
    1406            3 :                   CALL print_ft_file(ft_unit, headers, omegas, pol_results)
    1407              :                END IF
    1408            5 :                DEALLOCATE (headers)
    1409              :             END IF
    1410           20 :             CALL cp_print_key_finished_output(ft_unit, logger, pol_section)
    1411              :          END DO
    1412              :       END IF
    1413              : 
    1414              :       ! Padé polarizability
    1415           30 :       IF (rtc%pade_requested .AND. do_polarizability) THEN
    1416              :          ! Start with the field pade
    1417            6 :          ALLOCATE (field_results_pade(3, n_pade))
    1418            2 :          IF (rtc%apply_delta_pulse) THEN
    1419            8 :             DO k = 1, 3
    1420         6002 :                field_results_pade(k, :) = CMPLX(delta_vec(k), 0.0, kind=dp)
    1421              :             END DO
    1422              :          ELSE
    1423            0 :             DO k = 1, 3
    1424              :                CALL greenx_refine_ft(rtc%pade_fit_e_min, rtc%pade_fit_e_max, &
    1425              :                                      omegas_complex, field_results(k, :), &
    1426            0 :                                      omegas_pade, field_results_pade(k, :))
    1427              :             END DO
    1428              :          END IF
    1429              :          ! Allocate polarisation pade
    1430            8 :          ALLOCATE (pol_results_pade(n_elems, n_pade))
    1431              :          ! Refine
    1432            4 :          DO i = 1, nspin
    1433            8 :             DO k = 1, n_elems
    1434              :                ! NOTE : Regularization to small value
    1435              :                pol_results_pade(k, :) = results_pade(3*(i - 1) + rtc%print_pol_elements(k, 1), :)/( &
    1436              :                                         field_results_pade(rtc%print_pol_elements(k, 2), :) + &
    1437         6002 :                                         field_results_pade(rtc%print_pol_elements(k, 2), 2)*1.0e-10_dp)
    1438              :             END DO
    1439              :             ! Print to the file
    1440              :             ft_unit = cp_print_key_unit_nr(logger, pol_section, extension="_PADE"//file_extensions(i), &
    1441            2 :                                            file_form="FORMATTED", file_position="REWIND")
    1442            2 :             IF (ft_unit > 0) THEN
    1443            3 :                ALLOCATE (headers(2*n_elems + 1))
    1444            4 :                DO k = 1, n_elems
    1445            3 :                   WRITE (headers(2*k), "(A16,I2,I2)") "re,pade,pol.", &
    1446            3 :                      rtc%print_pol_elements(k, 1), &
    1447            6 :                      rtc%print_pol_elements(k, 2)
    1448            3 :                   WRITE (headers(2*k + 1), "(A16,I2,I2)") "im,pade,pol.", &
    1449            3 :                      rtc%print_pol_elements(k, 1), &
    1450            7 :                      rtc%print_pol_elements(k, 2)
    1451              :                END DO
    1452              :                ! Write header
    1453            1 :                IF (info_unit == ft_unit) THEN
    1454            1 :                   headers(1) = "#        Energy [eV]"
    1455            1 :                   prefix = " POLARIZABILITY_PADE|"
    1456            1 :                   prefix_format = "(A21)"
    1457              :                   CALL print_ft_file(ft_unit, headers, omegas_pade_real, pol_results_pade, &
    1458            1 :                                      prefix, prefix_format, evolt)
    1459              :                ELSE
    1460            0 :                   headers(1) = "#      omega [at.u.]"
    1461            0 :                   CALL print_ft_file(ft_unit, headers, omegas_pade_real, pol_results_pade)
    1462              :                END IF
    1463            1 :                DEALLOCATE (headers)
    1464              :             END IF
    1465            4 :             CALL cp_print_key_finished_output(ft_unit, logger, pol_section)
    1466              :          END DO
    1467            2 :          DEALLOCATE (field_results_pade)
    1468            2 :          DEALLOCATE (pol_results_pade)
    1469              :       END IF
    1470              : 
    1471           30 :       IF (rtc%pade_requested .AND. (do_moments_ft .OR. do_polarizability)) THEN
    1472            2 :          DEALLOCATE (omegas_complex)
    1473            2 :          DEALLOCATE (omegas_pade)
    1474            2 :          DEALLOCATE (omegas_pade_real)
    1475            2 :          DEALLOCATE (results_pade)
    1476              :       END IF
    1477              : 
    1478           30 :       IF (do_polarizability) THEN
    1479           10 :          DEALLOCATE (pol_results)
    1480           10 :          DEALLOCATE (field_results)
    1481              :       END IF
    1482              : 
    1483           30 :       IF (do_moments_ft .OR. do_polarizability) THEN
    1484           10 :          DEALLOCATE (results)
    1485           10 :          DEALLOCATE (omegas)
    1486              :       END IF
    1487           30 :    END SUBROUTINE print_ft
    1488              : 
    1489              : ! **************************************************************************************************
    1490              : !> \brief ...
    1491              : !> \param ft_unit ...
    1492              : !> \param headers ...
    1493              : !> \param xvals ...
    1494              : !> \param yvals ...
    1495              : !> \param prefix ...
    1496              : !> \param prefix_format ...
    1497              : !> \param xscale_opt ...
    1498              : ! **************************************************************************************************
    1499           12 :    SUBROUTINE print_ft_file(ft_unit, headers, xvals, yvals, prefix, prefix_format, xscale_opt)
    1500              :       INTEGER, INTENT(IN)                                :: ft_unit
    1501              :       CHARACTER(len=20), DIMENSION(:), INTENT(IN)        :: headers
    1502              :       REAL(kind=dp), DIMENSION(:), INTENT(IN)            :: xvals
    1503              :       COMPLEX(kind=dp), DIMENSION(:, :), INTENT(IN)      :: yvals
    1504              :       CHARACTER(len=21), INTENT(IN), OPTIONAL            :: prefix
    1505              :       CHARACTER(len=5), INTENT(IN), OPTIONAL             :: prefix_format
    1506              :       REAL(kind=dp), INTENT(IN), OPTIONAL                :: xscale_opt
    1507              : 
    1508              :       INTEGER                                            :: i, j, ncols, nrows
    1509              :       LOGICAL                                            :: do_prefix
    1510              :       REAL(kind=dp)                                      :: xscale
    1511              : 
    1512           12 :       do_prefix = .FALSE.
    1513           12 :       IF (PRESENT(prefix)) THEN
    1514            3 :          IF (PRESENT(prefix_format)) THEN
    1515              :             do_prefix = .TRUE.
    1516              :          ELSE
    1517            0 :             CPABORT("Printing of prefix with missing format!")
    1518              :          END IF
    1519              :       END IF
    1520              : 
    1521           12 :       xscale = 1.0_dp
    1522           12 :       IF (PRESENT(xscale_opt)) xscale = xscale_opt
    1523              : 
    1524           12 :       ncols = SIZE(yvals, 1)
    1525           12 :       nrows = SIZE(yvals, 2)
    1526              : 
    1527              :       ! Check whether enough headers for yvals and xvals is present
    1528           12 :       IF (SIZE(headers) < 2*ncols + 1) THEN
    1529            0 :          CPABORT("Not enough headers to print the file!")
    1530              :       END IF
    1531              : 
    1532           12 :       IF (SIZE(xvals) < nrows) THEN
    1533            0 :          CPABORT("Not enough xvals to print all yvals!")
    1534              :       END IF
    1535              : 
    1536           12 :       IF (ft_unit > 0) THEN
    1537              :          ! If prefix is present, write prefix
    1538              :          ! Also write energy in eV instead of at.u.
    1539           12 :          IF (do_prefix) THEN
    1540            3 :             WRITE (ft_unit, prefix_format, advance="no") prefix
    1541              :          END IF
    1542           12 :          WRITE (ft_unit, "(A20)", advance="no") headers(1)
    1543              :          ! Print the rest of the headers
    1544           72 :          DO j = 1, 2*ncols - 1
    1545           72 :             WRITE (ft_unit, "(A20)", advance="no") headers(j + 1)
    1546              :          END DO
    1547           12 :          WRITE (ft_unit, "(A20)") headers(2*ncols + 1)
    1548              :          ! Done with the headers, print actual data
    1549         3520 :          DO i = 1, nrows
    1550         3508 :             IF (do_prefix) THEN
    1551         1551 :                WRITE (ft_unit, prefix_format, advance="no") prefix
    1552              :             END IF
    1553         3508 :             WRITE (ft_unit, "(E20.8E3)", advance="no") xvals(i)*xscale
    1554        10524 :             DO j = 1, ncols - 1
    1555              :                WRITE (ft_unit, "(E20.8E3,E20.8E3)", advance="no") &
    1556        10524 :                   REAL(yvals(j, i)), AIMAG(yvals(j, i))
    1557              :             END DO
    1558              :             WRITE (ft_unit, "(E20.8E3,E20.8E3)") &
    1559         3520 :                REAL(yvals(ncols, i)), AIMAG(yvals(ncols, i))
    1560              :          END DO
    1561              :       END IF
    1562           12 :    END SUBROUTINE print_ft_file
    1563              : 
    1564              : END MODULE rt_propagation_output
        

Generated by: LCOV version 2.0-1