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

Generated by: LCOV version 2.0-1