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

Generated by: LCOV version 2.0-1