LCOV - code coverage report
Current view: top level - src/emd - rt_propagation_output.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:5064cfc) Lines: 95.8 % 660 632
Test Date: 2026-03-04 06:45:10 Functions: 100.0 % 15 15

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

Generated by: LCOV version 2.0-1