LCOV - code coverage report
Current view: top level - src - mixed_cdft_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 89.6 % 1039 931
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 12 12

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Utility subroutines for mixed CDFT calculations
      10              : !> \par   History
      11              : !>                 separated from mixed_cdft_methods [01.2017]
      12              : !> \author Nico Holmberg [01.2017]
      13              : ! **************************************************************************************************
      14              : MODULE mixed_cdft_utils
      15              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      16              :    USE cell_types,                      ONLY: cell_type
      17              :    USE cp_array_utils,                  ONLY: cp_1d_i_p_type,&
      18              :                                               cp_1d_r_p_type,&
      19              :                                               cp_2d_r_p_type
      20              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      21              :                                               cp_blacs_env_type
      22              :    USE cp_control_types,                ONLY: dft_control_type
      23              :    USE cp_dbcsr_api,                    ONLY: dbcsr_desymmetrize,&
      24              :                                               dbcsr_get_info,&
      25              :                                               dbcsr_init_p,&
      26              :                                               dbcsr_p_type,&
      27              :                                               dbcsr_release,&
      28              :                                               dbcsr_release_p,&
      29              :                                               dbcsr_type
      30              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      31              :                                               copy_fm_to_dbcsr_bc
      32              :    USE cp_files,                        ONLY: open_file
      33              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      34              :                                               cp_fm_struct_release,&
      35              :                                               cp_fm_struct_type
      36              :    USE cp_fm_types,                     ONLY: cp_fm_copy_general,&
      37              :                                               cp_fm_create,&
      38              :                                               cp_fm_get_info,&
      39              :                                               cp_fm_release,&
      40              :                                               cp_fm_to_fm,&
      41              :                                               cp_fm_type
      42              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      43              :                                               cp_logger_create,&
      44              :                                               cp_logger_set,&
      45              :                                               cp_logger_type,&
      46              :                                               cp_to_string
      47              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      48              :                                               cp_print_key_unit_nr
      49              :    USE cp_realspace_grid_init,          ONLY: init_input_type
      50              :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      51              :                                               cp_subsys_type
      52              :    USE cube_utils,                      ONLY: init_cube_info,&
      53              :                                               return_cube_max_iradius
      54              :    USE d3_poly,                         ONLY: init_d3_poly_module
      55              :    USE force_env_types,                 ONLY: force_env_get,&
      56              :                                               force_env_type,&
      57              :                                               multiple_fe_list
      58              :    USE gaussian_gridlevels,             ONLY: init_gaussian_gridlevel
      59              :    USE global_types,                    ONLY: global_environment_type
      60              :    USE hirshfeld_types,                 ONLY: create_hirshfeld_type,&
      61              :                                               release_hirshfeld_type,&
      62              :                                               set_hirshfeld_info
      63              :    USE input_constants,                 ONLY: becke_cutoff_element,&
      64              :                                               mixed_cdft_parallel,&
      65              :                                               mixed_cdft_parallel_nobuild,&
      66              :                                               mixed_cdft_serial,&
      67              :                                               outer_scf_becke_constraint,&
      68              :                                               outer_scf_hirshfeld_constraint,&
      69              :                                               shape_function_gaussian
      70              :    USE input_section_types,             ONLY: section_vals_duplicate,&
      71              :                                               section_vals_get,&
      72              :                                               section_vals_get_subs_vals,&
      73              :                                               section_vals_release,&
      74              :                                               section_vals_type,&
      75              :                                               section_vals_val_get
      76              :    USE kinds,                           ONLY: default_path_length,&
      77              :                                               default_string_length,&
      78              :                                               dp
      79              :    USE message_passing,                 ONLY: mp_request_type,&
      80              :                                               mp_waitall
      81              :    USE mixed_cdft_types,                ONLY: mixed_cdft_result_type_release,&
      82              :                                               mixed_cdft_result_type_set,&
      83              :                                               mixed_cdft_settings_type,&
      84              :                                               mixed_cdft_type,&
      85              :                                               mixed_cdft_work_type_init
      86              :    USE mixed_environment_types,         ONLY: get_mixed_env,&
      87              :                                               mixed_environment_type
      88              :    USE pw_env_methods,                  ONLY: pw_env_create
      89              :    USE pw_env_types,                    ONLY: pw_env_get,&
      90              :                                               pw_env_type
      91              :    USE pw_grid_types,                   ONLY: HALFSPACE,&
      92              :                                               pw_grid_type
      93              :    USE pw_grids,                        ONLY: do_pw_grid_blocked_false,&
      94              :                                               pw_grid_create,&
      95              :                                               pw_grid_release
      96              :    USE pw_pool_types,                   ONLY: pw_pool_create,&
      97              :                                               pw_pool_p_type,&
      98              :                                               pw_pool_type
      99              :    USE qs_cdft_types,                   ONLY: cdft_control_create,&
     100              :                                               cdft_control_type
     101              :    USE qs_environment_types,            ONLY: get_qs_env,&
     102              :                                               qs_environment_type
     103              :    USE qs_kind_types,                   ONLY: create_qs_kind_set,&
     104              :                                               qs_kind_type
     105              :    USE realspace_grid_types,            ONLY: realspace_grid_desc_p_type,&
     106              :                                               realspace_grid_input_type,&
     107              :                                               realspace_grid_type,&
     108              :                                               rs_grid_create,&
     109              :                                               rs_grid_create_descriptor,&
     110              :                                               rs_grid_print
     111              : #include "./base/base_uses.f90"
     112              : 
     113              :    IMPLICIT NONE
     114              :    PRIVATE
     115              : 
     116              :    ! Public subroutines
     117              : 
     118              :    PUBLIC :: mixed_cdft_parse_settings, mixed_cdft_transfer_settings, &
     119              :              mixed_cdft_init_structures, mixed_cdft_redistribute_arrays, &
     120              :              mixed_cdft_print_couplings, map_permutation_to_states, hfun_zero, &
     121              :              mixed_cdft_release_work, mixed_cdft_read_block_diag, &
     122              :              mixed_cdft_get_blocks, mixed_cdft_diagonalize_blocks, &
     123              :              mixed_cdft_assemble_block_diag
     124              : 
     125              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mixed_cdft_utils'
     126              : 
     127              : CONTAINS
     128              : 
     129              : ! **************************************************************************************************
     130              : !> \brief Parse settings for mixed cdft calculation and check their consistency
     131              : !> \param force_env the force_env that holds the CDFT mixed_env
     132              : !> \param mixed_env the mixed_env that holds the CDFT states
     133              : !> \param mixed_cdft control section for mixed CDFT
     134              : !> \param settings container for settings related to the mixed CDFT calculation
     135              : !> \param natom the total number of atoms
     136              : !> \par History
     137              : !>       01.2017  created [Nico Holmberg]
     138              : ! **************************************************************************************************
     139           72 :    SUBROUTINE mixed_cdft_parse_settings(force_env, mixed_env, mixed_cdft, &
     140              :                                         settings, natom)
     141              :       TYPE(force_env_type), POINTER                      :: force_env
     142              :       TYPE(mixed_environment_type), POINTER              :: mixed_env
     143              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
     144              :       TYPE(mixed_cdft_settings_type)                     :: settings
     145              :       INTEGER                                            :: natom
     146              : 
     147              :       INTEGER                                            :: i, iatom, iforce_eval, igroup, &
     148              :                                                             nforce_eval, nkinds
     149           72 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: constraint_type
     150           72 :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :)           :: array_sizes
     151              :       LOGICAL                                            :: is_match
     152           72 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     153              :       TYPE(cdft_control_type), POINTER                   :: cdft_control
     154           72 :       TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:, :) :: atoms
     155           72 :       TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:, :) :: coeff
     156              :       TYPE(dft_control_type), POINTER                    :: dft_control
     157              :       TYPE(force_env_type), POINTER                      :: force_env_qs
     158              :       TYPE(pw_env_type), POINTER                         :: pw_env
     159              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     160              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     161              : 
     162           72 :       NULLIFY (dft_control, qs_env, pw_env, auxbas_pw_pool, force_env_qs, &
     163           72 :                cdft_control)
     164              :       ! Allocate storage for temporaries used for checking settings consistency
     165           72 :       settings%max_nkinds = 30
     166           72 :       nforce_eval = SIZE(force_env%sub_force_env)
     167          216 :       ALLOCATE (settings%grid_span(nforce_eval))
     168          216 :       ALLOCATE (settings%npts(3, nforce_eval))
     169          216 :       ALLOCATE (settings%cutoff(nforce_eval))
     170          144 :       ALLOCATE (settings%rel_cutoff(nforce_eval))
     171          144 :       ALLOCATE (settings%spherical(nforce_eval))
     172          216 :       ALLOCATE (settings%rs_dims(2, nforce_eval))
     173          144 :       ALLOCATE (settings%odd(nforce_eval))
     174          288 :       ALLOCATE (settings%atoms(natom, nforce_eval))
     175           72 :       IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
     176           88 :          ALLOCATE (settings%coeffs(natom, nforce_eval))
     177          154 :          settings%coeffs = 0.0_dp
     178              :       END IF
     179              :       ! Some of the checked settings are only defined for certain types of constraints
     180              :       ! We nonetheless use arrays that are large enough to contain settings for all constraints
     181              :       ! This is not completely optimal...
     182          216 :       ALLOCATE (settings%si(6, nforce_eval))
     183          216 :       ALLOCATE (settings%sb(8, nforce_eval))
     184          216 :       ALLOCATE (settings%sr(5, nforce_eval))
     185          216 :       ALLOCATE (settings%cutoffs(settings%max_nkinds, nforce_eval))
     186          144 :       ALLOCATE (settings%radii(settings%max_nkinds, nforce_eval))
     187          240 :       settings%grid_span = 0
     188          744 :       settings%npts = 0
     189          240 :       settings%cutoff = 0.0_dp
     190          240 :       settings%rel_cutoff = 0.0_dp
     191          240 :       settings%spherical = 0
     192           72 :       settings%is_spherical = .FALSE.
     193          576 :       settings%rs_dims = 0
     194          240 :       settings%odd = 0
     195           72 :       settings%is_odd = .FALSE.
     196          614 :       settings%atoms = 0
     197         1248 :       settings%si = 0
     198         1080 :       settings%sr = 0.0_dp
     199         1584 :       settings%sb = .FALSE.
     200         5280 :       settings%cutoffs = 0.0_dp
     201         5280 :       settings%radii = 0.0_dp
     202              :       ! Get information from the sub_force_envs
     203          240 :       DO iforce_eval = 1, nforce_eval
     204          168 :          IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
     205          144 :          force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
     206          144 :          IF (mixed_env%do_mixed_qmmm_cdft) THEN
     207           12 :             qs_env => force_env_qs%qmmm_env%qs_env
     208              :          ELSE
     209          132 :             CALL force_env_get(force_env_qs, qs_env=qs_env)
     210              :          END IF
     211          144 :          CALL get_qs_env(qs_env, pw_env=pw_env, dft_control=dft_control)
     212          144 :          IF (.NOT. dft_control%qs_control%cdft) &
     213              :             CALL cp_abort(__LOCATION__, &
     214              :                           "A mixed CDFT simulation with multiple force_evals was requested, "// &
     215            0 :                           "but CDFT constraints were not active in the QS section of all force_evals!")
     216          144 :          cdft_control => dft_control%qs_control%cdft_control
     217          144 :          CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
     218         1440 :          settings%bo = auxbas_pw_pool%pw_grid%bounds_local
     219              :          ! Only the rank 0 process collects info about pw_grid and CDFT
     220          216 :          IF (force_env_qs%para_env%is_source()) THEN
     221              :             ! Grid settings
     222           84 :             settings%grid_span(iforce_eval) = auxbas_pw_pool%pw_grid%grid_span
     223          336 :             settings%npts(:, iforce_eval) = auxbas_pw_pool%pw_grid%npts
     224           84 :             settings%cutoff(iforce_eval) = auxbas_pw_pool%pw_grid%cutoff
     225           84 :             settings%rel_cutoff(iforce_eval) = dft_control%qs_control%relative_cutoff
     226           84 :             IF (auxbas_pw_pool%pw_grid%spherical) settings%spherical(iforce_eval) = 1
     227          252 :             settings%rs_dims(:, iforce_eval) = auxbas_pw_pool%pw_grid%para%group%num_pe_cart
     228           84 :             IF (auxbas_pw_pool%pw_grid%grid_span == HALFSPACE) settings%odd(iforce_eval) = 1
     229              :             ! Becke constraint atoms/coeffs
     230           84 :             IF (cdft_control%natoms > SIZE(settings%atoms, 1)) &
     231              :                CALL cp_abort(__LOCATION__, &
     232              :                              "More CDFT constraint atoms than defined in mixed section. "// &
     233            0 :                              "Use default values for MIXED\MAPPING.")
     234          233 :             settings%atoms(1:cdft_control%natoms, iforce_eval) = cdft_control%atoms
     235           84 :             IF (mixed_cdft%run_type == mixed_cdft_parallel) &
     236           66 :                settings%coeffs(1:cdft_control%natoms, iforce_eval) = cdft_control%group(1)%coeff
     237              :             ! Integer type settings
     238           84 :             IF (cdft_control%type == outer_scf_becke_constraint) THEN
     239           76 :                settings%si(1, iforce_eval) = cdft_control%becke_control%cutoff_type
     240           76 :                settings%si(2, iforce_eval) = cdft_control%becke_control%cavity_shape
     241              :             END IF
     242           84 :             settings%si(3, iforce_eval) = dft_control%multiplicity
     243           84 :             settings%si(4, iforce_eval) = SIZE(cdft_control%group)
     244           84 :             settings%si(5, iforce_eval) = cdft_control%type
     245           84 :             IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
     246            8 :                settings%si(6, iforce_eval) = cdft_control%hirshfeld_control%shape_function
     247            8 :                settings%si(6, iforce_eval) = cdft_control%hirshfeld_control%gaussian_shape
     248              :             END IF
     249              :             ! Logicals
     250           84 :             IF (cdft_control%type == outer_scf_becke_constraint) THEN
     251           76 :                settings%sb(1, iforce_eval) = cdft_control%becke_control%cavity_confine
     252           76 :                settings%sb(2, iforce_eval) = cdft_control%becke_control%should_skip
     253           76 :                settings%sb(3, iforce_eval) = cdft_control%becke_control%print_cavity
     254           76 :                settings%sb(4, iforce_eval) = cdft_control%becke_control%in_memory
     255           76 :                settings%sb(5, iforce_eval) = cdft_control%becke_control%adjust
     256           76 :                settings%sb(8, iforce_eval) = cdft_control%becke_control%use_bohr
     257              :             END IF
     258           84 :             IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
     259            8 :                settings%sb(8, iforce_eval) = cdft_control%hirshfeld_control%use_bohr
     260              :             END IF
     261           84 :             settings%sb(6, iforce_eval) = cdft_control%atomic_charges
     262           84 :             settings%sb(7, iforce_eval) = qs_env%has_unit_metric
     263              :             ! Reals
     264           84 :             IF (cdft_control%type == outer_scf_becke_constraint) THEN
     265           76 :                settings%sr(1, iforce_eval) = cdft_control%becke_control%rcavity
     266           76 :                settings%sr(2, iforce_eval) = cdft_control%becke_control%rglobal
     267           76 :                settings%sr(3, iforce_eval) = cdft_control%becke_control%eps_cavity
     268              :             END IF
     269           84 :             IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
     270            8 :                settings%sr(2, iforce_eval) = cdft_control%hirshfeld_control%radius
     271              :             END IF
     272           84 :             settings%sr(4, iforce_eval) = dft_control%qs_control%eps_rho_rspace
     273           84 :             settings%sr(5, iforce_eval) = pw_env%cube_info(pw_env%auxbas_grid)%max_rad_ga
     274           84 :             IF (cdft_control%type == outer_scf_becke_constraint) THEN
     275           76 :                IF (cdft_control%becke_control%cutoff_type == becke_cutoff_element) THEN
     276           50 :                   nkinds = SIZE(cdft_control%becke_control%cutoffs_tmp)
     277           50 :                   IF (nkinds > settings%max_nkinds) &
     278              :                      CALL cp_abort(__LOCATION__, &
     279              :                                    "More than "//TRIM(cp_to_string(settings%max_nkinds))// &
     280              :                                    " unique elements were defined in BECKE_CONSTRAINT\ELEMENT_CUTOFF. Are you sure"// &
     281            0 :                                    " your input is correct? If yes, please increase max_nkinds and recompile.")
     282          150 :                   settings%cutoffs(1:nkinds, iforce_eval) = cdft_control%becke_control%cutoffs_tmp(:)
     283              :                END IF
     284           76 :                IF (cdft_control%becke_control%adjust) THEN
     285           52 :                   CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set)
     286           52 :                   IF (.NOT. SIZE(atomic_kind_set) == SIZE(cdft_control%becke_control%radii_tmp)) &
     287              :                      CALL cp_abort(__LOCATION__, &
     288              :                                    "Length of keyword BECKE_CONSTRAINT\ATOMIC_RADII does not "// &
     289            0 :                                    "match number of atomic kinds in the input coordinate file.")
     290           52 :                   nkinds = SIZE(cdft_control%becke_control%radii_tmp)
     291           52 :                   IF (nkinds > settings%max_nkinds) &
     292              :                      CALL cp_abort(__LOCATION__, &
     293              :                                    "More than "//TRIM(cp_to_string(settings%max_nkinds))// &
     294              :                                    " unique elements were defined in BECKE_CONSTRAINT\ATOMIC_RADII. Are you sure"// &
     295            0 :                                    " your input is correct? If yes, please increase max_nkinds and recompile.")
     296          156 :                   settings%radii(1:nkinds, iforce_eval) = cdft_control%becke_control%radii_tmp(:)
     297              :                END IF
     298              :             END IF
     299          108 :             IF (cdft_control%type == outer_scf_hirshfeld_constraint) THEN
     300            8 :                IF (ASSOCIATED(cdft_control%hirshfeld_control%radii)) THEN
     301            0 :                   CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set)
     302            0 :                   IF (.NOT. SIZE(atomic_kind_set) == SIZE(cdft_control%hirshfeld_control%radii)) &
     303              :                      CALL cp_abort(__LOCATION__, &
     304              :                                    "Length of keyword HIRSHFELD_CONSTRAINT&RADII does not "// &
     305            0 :                                    "match number of atomic kinds in the input coordinate file.")
     306            0 :                   nkinds = SIZE(cdft_control%hirshfeld_control%radii)
     307            0 :                   IF (nkinds > settings%max_nkinds) &
     308              :                      CALL cp_abort(__LOCATION__, &
     309              :                                    "More than "//TRIM(cp_to_string(settings%max_nkinds))// &
     310              :                                    " unique elements were defined in HIRSHFELD_CONSTRAINT&RADII. Are you sure"// &
     311            0 :                                    " your input is correct? If yes, please increase max_nkinds and recompile.")
     312            0 :                   settings%radii(1:nkinds, iforce_eval) = cdft_control%hirshfeld_control%radii(:)
     313              :                END IF
     314              :             END IF
     315              :          END IF
     316              :       END DO
     317              :       ! Make sure the grids are consistent
     318          408 :       CALL force_env%para_env%sum(settings%grid_span)
     319         1416 :       CALL force_env%para_env%sum(settings%npts)
     320          408 :       CALL force_env%para_env%sum(settings%cutoff)
     321          408 :       CALL force_env%para_env%sum(settings%rel_cutoff)
     322          408 :       CALL force_env%para_env%sum(settings%spherical)
     323         1080 :       CALL force_env%para_env%sum(settings%rs_dims)
     324          408 :       CALL force_env%para_env%sum(settings%odd)
     325           72 :       is_match = .TRUE.
     326          168 :       DO iforce_eval = 2, nforce_eval
     327           96 :          is_match = is_match .AND. (settings%grid_span(1) == settings%grid_span(iforce_eval))
     328           96 :          is_match = is_match .AND. (settings%npts(1, 1) == settings%npts(1, iforce_eval))
     329           96 :          is_match = is_match .AND. (settings%cutoff(1) == settings%cutoff(iforce_eval))
     330           96 :          is_match = is_match .AND. (settings%rel_cutoff(1) == settings%rel_cutoff(iforce_eval))
     331           96 :          is_match = is_match .AND. (settings%spherical(1) == settings%spherical(iforce_eval))
     332           96 :          is_match = is_match .AND. (settings%rs_dims(1, 1) == settings%rs_dims(1, iforce_eval))
     333           96 :          is_match = is_match .AND. (settings%rs_dims(2, 1) == settings%rs_dims(2, iforce_eval))
     334          168 :          is_match = is_match .AND. (settings%odd(1) == settings%odd(iforce_eval))
     335              :       END DO
     336           72 :       IF (.NOT. is_match) &
     337              :          CALL cp_abort(__LOCATION__, &
     338            0 :                        "Mismatch detected in the &MGRID settings of the CDFT force_evals.")
     339           72 :       IF (settings%spherical(1) == 1) settings%is_spherical = .TRUE.
     340           72 :       IF (settings%odd(1) == 1) settings%is_odd = .TRUE.
     341              :       ! Make sure CDFT settings are consistent
     342         1156 :       CALL force_env%para_env%sum(settings%atoms)
     343           72 :       IF (mixed_cdft%run_type == mixed_cdft_parallel) &
     344          286 :          CALL force_env%para_env%sum(settings%coeffs)
     345           72 :       settings%ncdft = 0
     346          224 :       DO i = 1, SIZE(settings%atoms, 1)
     347          374 :          DO iforce_eval = 2, nforce_eval
     348          374 :             IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
     349           44 :                IF (settings%atoms(i, 1) /= settings%atoms(i, iforce_eval)) is_match = .FALSE.
     350           44 :                IF (settings%coeffs(i, 1) /= settings%coeffs(i, iforce_eval)) is_match = .FALSE.
     351              :             END IF
     352              :          END DO
     353          224 :          IF (settings%atoms(i, 1) /= 0) settings%ncdft = settings%ncdft + 1
     354              :       END DO
     355           72 :       IF (.NOT. is_match .AND. mixed_cdft%run_type == mixed_cdft_parallel) &
     356              :          CALL cp_abort(__LOCATION__, &
     357              :                        "Mismatch detected in the &CDFT section of the CDFT force_evals. "// &
     358              :                        "Parallel mode mixed CDFT requires identical constraint definitions in both CDFT states. "// &
     359              :                        "Switch to serial mode or disable keyword PARALLEL_BUILD if you "// &
     360            0 :                        "want to use nonidentical constraint definitions.")
     361         2424 :       CALL force_env%para_env%sum(settings%si)
     362         2088 :       CALL force_env%para_env%sum(settings%sr)
     363          648 :       DO i = 1, SIZE(settings%sb, 1)
     364          576 :          CALL force_env%para_env%sum(settings%sb(i, 1))
     365         1416 :          DO iforce_eval = 2, nforce_eval
     366          768 :             CALL force_env%para_env%sum(settings%sb(i, iforce_eval))
     367         1344 :             IF (settings%sb(i, 1) .NEQV. settings%sb(i, iforce_eval)) is_match = .FALSE.
     368              :          END DO
     369              :       END DO
     370          504 :       DO i = 1, SIZE(settings%si, 1)
     371         1080 :          DO iforce_eval = 2, nforce_eval
     372         1008 :             IF (settings%si(i, 1) /= settings%si(i, iforce_eval)) is_match = .FALSE.
     373              :          END DO
     374              :       END DO
     375          432 :       DO i = 1, SIZE(settings%sr, 1)
     376          912 :          DO iforce_eval = 2, nforce_eval
     377          840 :             IF (settings%sr(i, 1) /= settings%sr(i, iforce_eval)) is_match = .FALSE.
     378              :          END DO
     379              :       END DO
     380           72 :       IF (.NOT. is_match) &
     381              :          CALL cp_abort(__LOCATION__, &
     382            0 :                        "Mismatch detected in the &CDFT settings of the CDFT force_evals.")
     383              :       ! Some CDFT features are currently disabled for mixed calculations: check that these features were not requested
     384           72 :       IF (mixed_cdft%dlb .AND. .NOT. settings%sb(1, 1)) &
     385              :          CALL cp_abort(__LOCATION__, &
     386            0 :                        "Parallel mode mixed CDFT load balancing requires Gaussian cavity confinement.")
     387              :       ! Check for identical constraints in case of run type serial/parallel_nobuild
     388           72 :       IF (mixed_cdft%run_type /= mixed_cdft_parallel) THEN
     389              :          ! Get array sizes
     390          250 :          ALLOCATE (array_sizes(nforce_eval, settings%si(4, 1), 2))
     391          510 :          array_sizes(:, :, :) = 0
     392          174 :          DO iforce_eval = 1, nforce_eval
     393          124 :             IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
     394          122 :             force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
     395          122 :             IF (mixed_env%do_mixed_qmmm_cdft) THEN
     396            8 :                qs_env => force_env_qs%qmmm_env%qs_env
     397              :             ELSE
     398          114 :                CALL force_env_get(force_env_qs, qs_env=qs_env)
     399              :             END IF
     400          122 :             CALL get_qs_env(qs_env, dft_control=dft_control)
     401          122 :             cdft_control => dft_control%qs_control%cdft_control
     402          172 :             IF (force_env_qs%para_env%is_source()) THEN
     403          128 :                DO igroup = 1, SIZE(cdft_control%group)
     404           64 :                   array_sizes(iforce_eval, igroup, 1) = SIZE(cdft_control%group(igroup)%atoms)
     405          126 :                   array_sizes(iforce_eval, igroup, 2) = SIZE(cdft_control%group(igroup)%coeff)
     406              :                END DO
     407              :             END IF
     408              :          END DO
     409              :          ! Sum up array sizes and check consistency
     410           50 :          CALL force_env%para_env%sum(array_sizes)
     411          410 :          IF (ANY(array_sizes(:, :, 1) /= array_sizes(1, 1, 1)) .OR. &
     412              :              ANY(array_sizes(:, :, 2) /= array_sizes(1, 1, 2))) &
     413            0 :             mixed_cdft%identical_constraints = .FALSE.
     414              :          ! Check constraint definitions
     415           50 :          IF (mixed_cdft%identical_constraints) THEN
     416              :             ! Prepare temporary storage
     417          380 :             ALLOCATE (atoms(nforce_eval, settings%si(4, 1)))
     418          330 :             ALLOCATE (coeff(nforce_eval, settings%si(4, 1)))
     419          200 :             ALLOCATE (constraint_type(nforce_eval, settings%si(4, 1)))
     420          230 :             constraint_type(:, :) = 0
     421          174 :             DO iforce_eval = 1, nforce_eval
     422          252 :                DO i = 1, settings%si(4, 1)
     423          128 :                   NULLIFY (atoms(iforce_eval, i)%array)
     424              :                   NULLIFY (coeff(iforce_eval, i)%array)
     425          384 :                   ALLOCATE (atoms(iforce_eval, i)%array(array_sizes(iforce_eval, i, 1)))
     426          384 :                   ALLOCATE (coeff(iforce_eval, i)%array(array_sizes(iforce_eval, i, 1)))
     427          346 :                   atoms(iforce_eval, i)%array(:) = 0
     428          470 :                   coeff(iforce_eval, i)%array(:) = 0
     429              :                END DO
     430              :                ! Get constraint definitions
     431          124 :                IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
     432          122 :                force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
     433          122 :                IF (mixed_env%do_mixed_qmmm_cdft) THEN
     434            8 :                   qs_env => force_env_qs%qmmm_env%qs_env
     435              :                ELSE
     436          114 :                   CALL force_env_get(force_env_qs, qs_env=qs_env)
     437              :                END IF
     438          122 :                CALL get_qs_env(qs_env, dft_control=dft_control)
     439          122 :                cdft_control => dft_control%qs_control%cdft_control
     440          172 :                IF (force_env_qs%para_env%is_source()) THEN
     441          128 :                   DO i = 1, settings%si(4, 1)
     442          173 :                      atoms(iforce_eval, i)%array(:) = cdft_control%group(i)%atoms
     443          173 :                      coeff(iforce_eval, i)%array(:) = cdft_control%group(i)%coeff
     444          126 :                      constraint_type(iforce_eval, i) = cdft_control%group(i)%constraint_type
     445              :                   END DO
     446              :                END IF
     447              :             END DO
     448              :             ! Sum up constraint definitions and check consistency
     449          100 :             DO i = 1, settings%si(4, 1)
     450          180 :                DO iforce_eval = 1, nforce_eval
     451          564 :                   CALL force_env%para_env%sum(atoms(iforce_eval, i)%array)
     452          564 :                   CALL force_env%para_env%sum(coeff(iforce_eval, i)%array)
     453          180 :                   CALL force_env%para_env%sum(constraint_type(iforce_eval, i))
     454              :                END DO
     455          126 :                DO iforce_eval = 2, nforce_eval
     456          194 :                   DO iatom = 1, SIZE(atoms(1, i)%array)
     457          120 :                      IF (atoms(1, i)%array(iatom) /= atoms(iforce_eval, i)%array(iatom)) &
     458            0 :                         mixed_cdft%identical_constraints = .FALSE.
     459          120 :                      IF (coeff(1, i)%array(iatom) /= coeff(iforce_eval, i)%array(iatom)) &
     460            2 :                         mixed_cdft%identical_constraints = .FALSE.
     461          194 :                      IF (.NOT. mixed_cdft%identical_constraints) EXIT
     462              :                   END DO
     463           76 :                   IF (constraint_type(1, i) /= constraint_type(iforce_eval, i)) &
     464            0 :                      mixed_cdft%identical_constraints = .FALSE.
     465          126 :                   IF (.NOT. mixed_cdft%identical_constraints) EXIT
     466              :                END DO
     467          100 :                IF (.NOT. mixed_cdft%identical_constraints) EXIT
     468              :             END DO
     469              :             ! Deallocate temporary storage
     470          174 :             DO iforce_eval = 1, nforce_eval
     471          302 :                DO i = 1, settings%si(4, 1)
     472          128 :                   DEALLOCATE (atoms(iforce_eval, i)%array)
     473          252 :                   DEALLOCATE (coeff(iforce_eval, i)%array)
     474              :                END DO
     475              :             END DO
     476           50 :             DEALLOCATE (atoms)
     477           50 :             DEALLOCATE (coeff)
     478           50 :             DEALLOCATE (constraint_type)
     479              :          END IF
     480           50 :          DEALLOCATE (array_sizes)
     481              :       END IF
     482              :       ! Deallocate some arrays that are no longer needed
     483           72 :       IF (mixed_cdft%identical_constraints .AND. mixed_cdft%run_type /= mixed_cdft_parallel_nobuild) THEN
     484          228 :          DO iforce_eval = 1, nforce_eval
     485          160 :             IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
     486          138 :             force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
     487          138 :             IF (mixed_env%do_mixed_qmmm_cdft) THEN
     488           12 :                qs_env => force_env_qs%qmmm_env%qs_env
     489              :             ELSE
     490          126 :                CALL force_env_get(force_env_qs, qs_env=qs_env)
     491              :             END IF
     492          138 :             CALL get_qs_env(qs_env, dft_control=dft_control)
     493          138 :             cdft_control => dft_control%qs_control%cdft_control
     494          206 :             IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
     495           22 :                IF (.NOT. dft_control%qs_control%gapw) THEN
     496           44 :                   DO i = 1, SIZE(cdft_control%group)
     497           22 :                      DEALLOCATE (cdft_control%group(i)%coeff)
     498           44 :                      DEALLOCATE (cdft_control%group(i)%atoms)
     499              :                   END DO
     500           22 :                   IF (.NOT. cdft_control%atomic_charges) DEALLOCATE (cdft_control%atoms)
     501              :                END IF
     502          116 :             ELSE IF (mixed_cdft%run_type == mixed_cdft_serial) THEN
     503          116 :                IF (iforce_eval == 1) CYCLE
     504          142 :                DO igroup = 1, SIZE(cdft_control%group)
     505          142 :                   IF (.NOT. dft_control%qs_control%gapw) THEN
     506           72 :                      DEALLOCATE (cdft_control%group(igroup)%coeff)
     507           72 :                      DEALLOCATE (cdft_control%group(igroup)%atoms)
     508              :                   END IF
     509              :                END DO
     510           70 :                IF (cdft_control%type == outer_scf_becke_constraint) THEN
     511           64 :                   IF (.NOT. cdft_control%atomic_charges) DEALLOCATE (cdft_control%atoms)
     512           64 :                   IF (cdft_control%becke_control%cavity_confine) &
     513           62 :                      CALL release_hirshfeld_type(cdft_control%becke_control%cavity_env)
     514           64 :                   IF (cdft_control%becke_control%cutoff_type == becke_cutoff_element) &
     515           42 :                      DEALLOCATE (cdft_control%becke_control%cutoffs_tmp)
     516           64 :                   IF (cdft_control%becke_control%adjust) &
     517           44 :                      DEALLOCATE (cdft_control%becke_control%radii_tmp)
     518              :                END IF
     519              :             END IF
     520              :          END DO
     521              :       END IF
     522              : 
     523          144 :    END SUBROUTINE mixed_cdft_parse_settings
     524              : 
     525              : ! **************************************************************************************************
     526              : !> \brief Transfer settings to mixed_cdft
     527              : !> \param force_env the force_env that holds the CDFT states
     528              : !> \param mixed_cdft the control section for mixed CDFT calculations
     529              : !> \param settings container for settings related to the mixed CDFT calculation
     530              : !> \par History
     531              : !>       01.2017  created [Nico Holmberg]
     532              : ! **************************************************************************************************
     533           72 :    SUBROUTINE mixed_cdft_transfer_settings(force_env, mixed_cdft, settings)
     534              :       TYPE(force_env_type), POINTER                      :: force_env
     535              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
     536              :       TYPE(mixed_cdft_settings_type)                     :: settings
     537              : 
     538              :       INTEGER                                            :: i, nkinds
     539              :       LOGICAL                                            :: is_match
     540              :       TYPE(cdft_control_type), POINTER                   :: cdft_control
     541              : 
     542           72 :       NULLIFY (cdft_control)
     543           72 :       is_match = .TRUE.
     544              :       ! Transfer global settings
     545           72 :       mixed_cdft%multiplicity = settings%si(3, 1)
     546           72 :       mixed_cdft%has_unit_metric = settings%sb(7, 1)
     547           72 :       mixed_cdft%eps_rho_rspace = settings%sr(4, 1)
     548           72 :       mixed_cdft%nconstraint = settings%si(4, 1)
     549           72 :       settings%radius = settings%sr(5, 1)
     550              :       ! Transfer settings only needed if the constraint should be built in parallel
     551           72 :       IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
     552           22 :          IF (settings%sb(6, 1)) &
     553              :             CALL cp_abort(__LOCATION__, &
     554            0 :                           "Calculation of atomic Becke charges not supported with parallel mode mixed CDFT")
     555           22 :          IF (mixed_cdft%nconstraint /= 1) &
     556              :             CALL cp_abort(__LOCATION__, &
     557            0 :                           "Parallel mode mixed CDFT does not yet support multiple constraints.")
     558              : 
     559           22 :          IF (settings%si(5, 1) /= outer_scf_becke_constraint) &
     560              :             CALL cp_abort(__LOCATION__, &
     561            0 :                           "Parallel mode mixed CDFT does not support Hirshfeld constraints.")
     562              : 
     563           66 :          ALLOCATE (mixed_cdft%cdft_control)
     564           22 :          CALL cdft_control_create(mixed_cdft%cdft_control)
     565           22 :          cdft_control => mixed_cdft%cdft_control
     566           66 :          ALLOCATE (cdft_control%atoms(settings%ncdft))
     567           66 :          cdft_control%atoms = settings%atoms(1:settings%ncdft, 1)
     568           44 :          ALLOCATE (cdft_control%group(1))
     569           66 :          ALLOCATE (cdft_control%group(1)%atoms(settings%ncdft))
     570           66 :          ALLOCATE (cdft_control%group(1)%coeff(settings%ncdft))
     571           22 :          NULLIFY (cdft_control%group(1)%weight)
     572           22 :          NULLIFY (cdft_control%group(1)%gradients)
     573           22 :          NULLIFY (cdft_control%group(1)%integrated)
     574           66 :          cdft_control%group(1)%atoms = cdft_control%atoms
     575           66 :          cdft_control%group(1)%coeff = settings%coeffs(1:settings%ncdft, 1)
     576           22 :          cdft_control%natoms = settings%ncdft
     577           22 :          cdft_control%atomic_charges = settings%sb(6, 1)
     578           22 :          cdft_control%becke_control%cutoff_type = settings%si(1, 1)
     579           22 :          cdft_control%becke_control%cavity_confine = settings%sb(1, 1)
     580           22 :          cdft_control%becke_control%should_skip = settings%sb(2, 1)
     581           22 :          cdft_control%becke_control%print_cavity = settings%sb(3, 1)
     582           22 :          cdft_control%becke_control%in_memory = settings%sb(4, 1)
     583           22 :          cdft_control%becke_control%adjust = settings%sb(5, 1)
     584           22 :          cdft_control%becke_control%cavity_shape = settings%si(2, 1)
     585           22 :          cdft_control%becke_control%use_bohr = settings%sb(8, 1)
     586           22 :          cdft_control%becke_control%rcavity = settings%sr(1, 1)
     587           22 :          cdft_control%becke_control%rglobal = settings%sr(2, 1)
     588           22 :          cdft_control%becke_control%eps_cavity = settings%sr(3, 1)
     589           22 :          nkinds = 0
     590           22 :          IF (cdft_control%becke_control%cutoff_type == becke_cutoff_element) THEN
     591         2250 :             CALL force_env%para_env%sum(settings%cutoffs)
     592          558 :             DO i = 1, SIZE(settings%cutoffs, 1)
     593          540 :                IF (settings%cutoffs(i, 1) /= settings%cutoffs(i, 2)) is_match = .FALSE.
     594          558 :                IF (settings%cutoffs(i, 1) /= 0.0_dp) nkinds = nkinds + 1
     595              :             END DO
     596           18 :             IF (.NOT. is_match) &
     597              :                CALL cp_abort(__LOCATION__, &
     598              :                              "Mismatch detected in the &BECKE_CONSTRAINT "// &
     599            0 :                              "&ELEMENT_CUTOFF settings of the two force_evals.")
     600           54 :             ALLOCATE (cdft_control%becke_control%cutoffs_tmp(nkinds))
     601           54 :             cdft_control%becke_control%cutoffs_tmp = settings%cutoffs(1:nkinds, 1)
     602              :          END IF
     603           22 :          nkinds = 0
     604           22 :          IF (cdft_control%becke_control%adjust) THEN
     605         2250 :             CALL force_env%para_env%sum(settings%radii)
     606          558 :             DO i = 1, SIZE(settings%radii, 1)
     607          540 :                IF (settings%radii(i, 1) /= settings%radii(i, 2)) is_match = .FALSE.
     608          558 :                IF (settings%radii(i, 1) /= 0.0_dp) nkinds = nkinds + 1
     609              :             END DO
     610           18 :             IF (.NOT. is_match) &
     611              :                CALL cp_abort(__LOCATION__, &
     612              :                              "Mismatch detected in the &BECKE_CONSTRAINT "// &
     613            0 :                              "&ATOMIC_RADII settings of the two force_evals.")
     614           54 :             ALLOCATE (cdft_control%becke_control%radii(nkinds))
     615           54 :             cdft_control%becke_control%radii = settings%radii(1:nkinds, 1)
     616              :          END IF
     617              :       END IF
     618              : 
     619           72 :    END SUBROUTINE mixed_cdft_transfer_settings
     620              : 
     621              : ! **************************************************************************************************
     622              : !> \brief Initialize all the structures needed for a mixed CDFT calculation
     623              : !> \param force_env the force_env that holds the CDFT mixed_env
     624              : !> \param force_env_qs the force_env that holds the qs_env, which is CDFT state specific
     625              : !> \param mixed_env the mixed_env that holds the CDFT states
     626              : !> \param mixed_cdft the control section for mixed CDFT calculations
     627              : !> \param settings container for settings related to the mixed CDFT calculation
     628              : !> \par History
     629              : !>       01.2017 created [Nico Holmberg]
     630              : ! **************************************************************************************************
     631           72 :    SUBROUTINE mixed_cdft_init_structures(force_env, force_env_qs, mixed_env, mixed_cdft, settings)
     632              :       TYPE(force_env_type), POINTER                      :: force_env, force_env_qs
     633              :       TYPE(mixed_environment_type), POINTER              :: mixed_env
     634              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
     635              :       TYPE(mixed_cdft_settings_type)                     :: settings
     636              : 
     637              :       CHARACTER(len=default_path_length)                 :: c_val, input_file_path, output_file_path
     638              :       INTEGER                                            :: i, imap, iounit, j, lp, n_force_eval, &
     639              :                                                             ncpu, nforce_eval, ntargets, offset, &
     640              :                                                             unit_nr
     641           72 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: bounds
     642              :       INTEGER, DIMENSION(2, 3)                           :: bo, bo_mixed
     643              :       INTEGER, DIMENSION(3)                              :: higher_grid_layout
     644          144 :       INTEGER, DIMENSION(:), POINTER                     :: i_force_eval, mixed_rs_dims, recvbuffer, &
     645          144 :                                                             recvbuffer2, sendbuffer
     646              :       LOGICAL                                            :: is_match
     647           72 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     648              :       TYPE(cell_type), POINTER                           :: cell_mix
     649              :       TYPE(cp_logger_type), POINTER                      :: logger
     650              :       TYPE(cp_subsys_type), POINTER                      :: subsys_mix
     651              :       TYPE(global_environment_type), POINTER             :: globenv
     652          288 :       TYPE(mp_request_type), DIMENSION(3)                :: req
     653              :       TYPE(pw_env_type), POINTER                         :: pw_env
     654              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
     655           72 :       TYPE(pw_pool_p_type), DIMENSION(:), POINTER        :: pw_pools
     656              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     657              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     658           72 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     659              :       TYPE(realspace_grid_desc_p_type), DIMENSION(:), &
     660           72 :          POINTER                                         :: rs_descs
     661              :       TYPE(realspace_grid_input_type)                    :: input_settings
     662           72 :       TYPE(realspace_grid_type), DIMENSION(:), POINTER   :: rs_grids
     663              :       TYPE(section_vals_type), POINTER :: force_env_section, force_env_sections, kind_section, &
     664              :          print_section, root_section, rs_grid_section, subsys_section
     665              : 
     666           72 :       NULLIFY (cell_mix, subsys_mix, force_env_section, subsys_section, &
     667           72 :                print_section, root_section, kind_section, force_env_sections, &
     668           72 :                rs_grid_section, auxbas_pw_pool, pw_env, pw_pools, pw_grid, &
     669           72 :                sendbuffer, qs_env, mixed_rs_dims, i_force_eval, recvbuffer, &
     670           72 :                recvbuffer2, globenv, atomic_kind_set, qs_kind_set, rs_descs, &
     671           72 :                rs_grids)
     672              : 
     673          144 :       logger => cp_get_default_logger()
     674           72 :       CALL force_env_get(force_env=force_env, force_env_section=force_env_section)
     675           72 :       print_section => section_vals_get_subs_vals(force_env_section, "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
     676           72 :       iounit = cp_print_key_unit_nr(logger, print_section, '', extension='.mixedLog')
     677           72 :       is_match = .TRUE.
     678           72 :       nforce_eval = SIZE(force_env%sub_force_env)
     679           72 :       ncpu = force_env%para_env%num_pe
     680              :       ! Get infos about the mixed subsys
     681           72 :       IF (.NOT. mixed_env%do_mixed_qmmm_cdft) THEN
     682              :          CALL force_env_get(force_env=force_env, &
     683           64 :                             subsys=subsys_mix)
     684              :       ELSE
     685              :          CALL get_qs_env(force_env_qs%qmmm_env%qs_env, &
     686            8 :                          cp_subsys=subsys_mix)
     687              :       END IF
     688              :       ! Init structures only needed when the CDFT states are treated in parallel
     689           72 :       IF (mixed_cdft%run_type == mixed_cdft_parallel) THEN
     690              :          ! Start building the mixed auxbas_pw_pool
     691           22 :          CALL pw_env_create(mixed_cdft%pw_env)
     692              :          ! Decide what kind of layout to use and setup the grid
     693              :          ! Processor mappings currently supported:
     694              :          !  (2np,1)  --> (np,1)
     695              :          !  (nx,2ny) --> (nx,ny)
     696              :          !  (nx,ny)  --> (nx*ny/2,1) (required when xc_smooth is in use and with intermediate proc counts)
     697              :          !
     698              :          ! For cases 2 and 3, dlb redistributes YZ slices from overloaded processors to underloaded processors
     699              :          ! For case 1, XZ slices are redistributed
     700              :          ! TODO: Unify mappings. Now we essentially have separate code for cases 1-2 and 3.
     701              :          !       This leads to very messy code especially with dlb turned on...
     702              :          !       In terms of memory usage, it would be beneficial to replace case 1 with 3
     703              :          !       and implement a similar arbitrary mapping to replace case 2
     704              : 
     705           22 :          mixed_cdft%is_pencil = .FALSE. ! Flag to control the first two mappings
     706           22 :          mixed_cdft%is_special = .FALSE. ! Flag to control the last mapping
     707              :          ! With xc smoothing, the grid is always (ncpu/2,1) distributed
     708              :          ! and correct behavior cannot be guaranteed for ncpu/2 > nx, so we abort...
     709           22 :          IF (ncpu/2 > settings%npts(1, 1)) &
     710            0 :             CPABORT("ncpu/2 => nx: decrease ncpu or disable xc_smoothing")
     711              :          !
     712           22 :          ALLOCATE (mixed_rs_dims(2))
     713           22 :          IF (settings%rs_dims(2, 1) /= 1) mixed_cdft%is_pencil = .TRUE.
     714           22 :          IF (.NOT. mixed_cdft%is_pencil .AND. ncpu > settings%npts(1, 1)) mixed_cdft%is_special = .TRUE.
     715           22 :          IF (mixed_cdft%is_special) THEN
     716            0 :             mixed_rs_dims = [-1, -1]
     717           22 :          ELSE IF (mixed_cdft%is_pencil) THEN
     718            0 :             mixed_rs_dims = [settings%rs_dims(1, 1), 2*settings%rs_dims(2, 1)]
     719              :          ELSE
     720           66 :             mixed_rs_dims = [2*settings%rs_dims(1, 1), 1]
     721              :          END IF
     722           22 :          IF (.NOT. mixed_env%do_mixed_qmmm_cdft) THEN
     723              :             CALL force_env_get(force_env=force_env, &
     724           18 :                                cell=cell_mix)
     725              :          ELSE
     726              :             CALL get_qs_env(force_env_qs%qmmm_env%qs_env, &
     727            4 :                             cell=cell_mix)
     728              :          END IF
     729              :          CALL pw_grid_create(pw_grid, force_env%para_env, cell_mix%hmat, grid_span=settings%grid_span(1), &
     730              :                              npts=settings%npts(:, 1), cutoff=settings%cutoff(1), &
     731              :                              spherical=settings%is_spherical, odd=settings%is_odd, &
     732              :                              fft_usage=.TRUE., ncommensurate=0, icommensurate=1, &
     733              :                              blocked=do_pw_grid_blocked_false, rs_dims=mixed_rs_dims, &
     734           22 :                              iounit=iounit)
     735              :          ! Check if the layout was successfully created
     736           22 :          IF (mixed_cdft%is_special) THEN
     737            0 :             IF (.NOT. pw_grid%para%group%num_pe_cart(2) /= 1) is_match = .FALSE.
     738           22 :          ELSE IF (mixed_cdft%is_pencil) THEN
     739            0 :             IF (.NOT. pw_grid%para%group%num_pe_cart(1) == mixed_rs_dims(1)) is_match = .FALSE.
     740              :          ELSE
     741           22 :             IF (.NOT. pw_grid%para%group%num_pe_cart(2) == 1) is_match = .FALSE.
     742              :          END IF
     743              :          IF (.NOT. is_match) &
     744              :             CALL cp_abort(__LOCATION__, &
     745              :                           "Unable to create a suitable grid distribution "// &
     746              :                           "for mixed CDFT calculations. Try decreasing the total number "// &
     747            0 :                           "of processors or disabling xc_smoothing.")
     748           22 :          DEALLOCATE (mixed_rs_dims)
     749              :          ! Create the pool
     750          220 :          bo_mixed = pw_grid%bounds_local
     751           44 :          ALLOCATE (pw_pools(1))
     752           22 :          NULLIFY (pw_pools(1)%pool)
     753           22 :          CALL pw_pool_create(pw_pools(1)%pool, pw_grid=pw_grid)
     754              :          ! Initialize Gaussian cavity confinement
     755           22 :          IF (mixed_cdft%cdft_control%becke_control%cavity_confine) THEN
     756           22 :             CALL create_hirshfeld_type(mixed_cdft%cdft_control%becke_control%cavity_env)
     757              :             CALL set_hirshfeld_info(mixed_cdft%cdft_control%becke_control%cavity_env, &
     758              :                                     shape_function_type=shape_function_gaussian, iterative=.FALSE., &
     759              :                                     radius_type=mixed_cdft%cdft_control%becke_control%cavity_shape, &
     760           22 :                                     use_bohr=mixed_cdft%cdft_control%becke_control%use_bohr)
     761              :          END IF
     762              :          ! Gaussian confinement/wavefunction overlap method needs qs_kind_set
     763              :          ! Gaussian cavity confinement also needs the auxbas_rs_grid
     764           22 :          IF (mixed_cdft%cdft_control%becke_control%cavity_confine .OR. &
     765              :              mixed_cdft%wfn_overlap_method) THEN
     766              :             print_section => section_vals_get_subs_vals(force_env_section, &
     767           22 :                                                         "PRINT%GRID_INFORMATION")
     768           22 :             ALLOCATE (mixed_cdft%pw_env%gridlevel_info)
     769              :             CALL init_gaussian_gridlevel(mixed_cdft%pw_env%gridlevel_info, &
     770              :                                          ngrid_levels=1, cutoff=settings%cutoff, &
     771              :                                          rel_cutoff=settings%rel_cutoff(1), &
     772           22 :                                          print_section=print_section)
     773           44 :             ALLOCATE (rs_descs(1))
     774          374 :             ALLOCATE (rs_grids(1))
     775          638 :             ALLOCATE (mixed_cdft%pw_env%cube_info(1))
     776           22 :             higher_grid_layout = [-1, -1, -1]
     777           22 :             CALL init_d3_poly_module()
     778              :             CALL init_cube_info(mixed_cdft%pw_env%cube_info(1), &
     779              :                                 pw_grid%dr(:), pw_grid%dh(:, :), &
     780              :                                 pw_grid%dh_inv(:, :), &
     781           22 :                                 pw_grid%orthorhombic, settings%radius)
     782           22 :             NULLIFY (root_section, force_env_section, force_env_sections, rs_grid_section)
     783           22 :             CALL force_env_get(force_env, root_section=root_section)
     784           22 :             force_env_sections => section_vals_get_subs_vals(root_section, "FORCE_EVAL")
     785           22 :             CALL multiple_fe_list(force_env_sections, root_section, i_force_eval, n_force_eval)
     786              :             CALL section_vals_duplicate(force_env_sections, force_env_section, &
     787           22 :                                         i_force_eval(2), i_force_eval(2))
     788           22 :             rs_grid_section => section_vals_get_subs_vals(force_env_section, "DFT%MGRID%RS_GRID")
     789              :             CALL init_input_type(input_settings, &
     790              :                                  nsmax=2*MAX(1, return_cube_max_iradius(mixed_cdft%pw_env%cube_info(1))) + 1, &
     791              :                                  rs_grid_section=rs_grid_section, ilevel=1, &
     792           22 :                                  higher_grid_layout=higher_grid_layout)
     793           22 :             NULLIFY (rs_descs(1)%rs_desc)
     794           22 :             CALL rs_grid_create_descriptor(rs_descs(1)%rs_desc, pw_grid, input_settings)
     795           22 :             IF (rs_descs(1)%rs_desc%distributed) higher_grid_layout = rs_descs(1)%rs_desc%group_dim
     796           22 :             CALL rs_grid_create(rs_grids(1), rs_descs(1)%rs_desc)
     797           22 :             CALL rs_grid_print(rs_grids(1), iounit)
     798           22 :             mixed_cdft%pw_env%rs_descs => rs_descs
     799           22 :             mixed_cdft%pw_env%rs_grids => rs_grids
     800              :             ! qs_kind_set
     801              :             subsys_section => section_vals_get_subs_vals(force_env_sections, "SUBSYS", &
     802           22 :                                                          i_rep_section=i_force_eval(1))
     803           22 :             kind_section => section_vals_get_subs_vals(subsys_section, "KIND")
     804           22 :             NULLIFY (qs_kind_set)
     805           22 :             CALL cp_subsys_get(subsys_mix, atomic_kind_set=atomic_kind_set)
     806              :             CALL create_qs_kind_set(qs_kind_set, atomic_kind_set, kind_section, &
     807           22 :                                     force_env%para_env, force_env_section, silent=.FALSE.)
     808           22 :             mixed_cdft%qs_kind_set => qs_kind_set
     809           22 :             DEALLOCATE (i_force_eval)
     810           22 :             CALL section_vals_release(force_env_section)
     811              :          END IF
     812              :          CALL force_env_get(force_env=force_env, &
     813           22 :                             force_env_section=force_env_section)
     814           22 :          CALL pw_grid_release(pw_grid)
     815           22 :          mixed_cdft%pw_env%auxbas_grid = 1
     816           22 :          NULLIFY (mixed_cdft%pw_env%pw_pools)
     817           22 :          mixed_cdft%pw_env%pw_pools => pw_pools
     818          220 :          bo = settings%bo
     819              :          ! Determine which processors need to exchange data when redistributing the weight/gradient
     820           22 :          IF (.NOT. mixed_cdft%is_special) THEN
     821           22 :             ALLOCATE (mixed_cdft%dest_list(2))
     822           22 :             ALLOCATE (mixed_cdft%source_list(2))
     823           22 :             imap = force_env%para_env%mepos/2
     824           66 :             mixed_cdft%dest_list = [imap, imap + force_env%para_env%num_pe/2]
     825              :             imap = MOD(force_env%para_env%mepos, force_env%para_env%num_pe/2) + &
     826           22 :                    MODULO(force_env%para_env%mepos, force_env%para_env%num_pe/2)
     827           66 :             mixed_cdft%source_list = [imap, imap + 1]
     828              :             ! Determine bounds of the data that is replicated
     829           22 :             ALLOCATE (mixed_cdft%recv_bo(4))
     830           22 :             ALLOCATE (sendbuffer(2), recvbuffer(2), recvbuffer2(2))
     831           22 :             IF (mixed_cdft%is_pencil) THEN
     832            0 :                sendbuffer = [bo_mixed(1, 2), bo_mixed(2, 2)]
     833              :             ELSE
     834           66 :                sendbuffer = [bo_mixed(1, 1), bo_mixed(2, 1)]
     835              :             END IF
     836              :             ! Communicate bounds in steps
     837              :             CALL force_env%para_env%isend(msgin=sendbuffer, dest=mixed_cdft%dest_list(1), &
     838           22 :                                           request=req(1))
     839              :             CALL force_env%para_env%irecv(msgout=recvbuffer, source=mixed_cdft%source_list(1), &
     840           22 :                                           request=req(2))
     841              :             CALL force_env%para_env%irecv(msgout=recvbuffer2, source=mixed_cdft%source_list(2), &
     842           22 :                                           request=req(3))
     843           22 :             CALL req(1)%wait()
     844              :             CALL force_env%para_env%isend(msgin=sendbuffer, dest=mixed_cdft%dest_list(2), &
     845           22 :                                           request=req(1))
     846           22 :             CALL mp_waitall(req)
     847          110 :             mixed_cdft%recv_bo(1:2) = recvbuffer
     848          110 :             mixed_cdft%recv_bo(3:4) = recvbuffer2
     849           22 :             DEALLOCATE (sendbuffer, recvbuffer, recvbuffer2)
     850              :          ELSE
     851            0 :             IF (mixed_env%do_mixed_qmmm_cdft) THEN
     852            0 :                qs_env => force_env_qs%qmmm_env%qs_env
     853              :             ELSE
     854            0 :                CALL force_env_get(force_env_qs, qs_env=qs_env)
     855              :             END IF
     856            0 :             CALL get_qs_env(qs_env, pw_env=pw_env)
     857            0 :             CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
     858              :             ! work out the pw grid points each proc holds in the two (identical) parallel proc groups
     859              :             ! note we only care about the x dir since we assume the y dir is not subdivided
     860            0 :             ALLOCATE (bounds(0:auxbas_pw_pool%pw_grid%para%group%num_pe - 1, 1:2))
     861            0 :             DO i = 0, auxbas_pw_pool%pw_grid%para%group%num_pe - 1
     862            0 :                bounds(i, 1:2) = auxbas_pw_pool%pw_grid%para%bo(1:2, 1, i, 1)
     863            0 :                bounds(i, 1:2) = bounds(i, 1:2) - auxbas_pw_pool%pw_grid%npts(1)/2 - 1
     864              :             END DO
     865              :             ! work out which procs to send my grid points
     866              :             ! first get the number of target procs per group
     867            0 :             ntargets = 0
     868            0 :             offset = -1
     869            0 :             DO i = 0, auxbas_pw_pool%pw_grid%para%group%num_pe - 1
     870            0 :                IF ((bounds(i, 1) >= bo_mixed(1, 1) .AND. bounds(i, 1) <= bo_mixed(2, 1)) .OR. &
     871            0 :                    (bounds(i, 2) >= bo_mixed(1, 1) .AND. bounds(i, 2) <= bo_mixed(2, 1))) THEN
     872            0 :                   ntargets = ntargets + 1
     873            0 :                   IF (offset == -1) offset = i
     874            0 :                ELSE IF (bounds(i, 2) > bo_mixed(2, 1)) THEN
     875              :                   EXIT
     876              :                ELSE
     877            0 :                   CYCLE
     878              :                END IF
     879              :             END DO
     880            0 :             ALLOCATE (mixed_cdft%dest_list(ntargets))
     881            0 :             ALLOCATE (mixed_cdft%dest_list_bo(2, ntargets))
     882              :             ! now determine the actual grid points to send
     883            0 :             j = 1
     884            0 :             DO i = offset, offset + ntargets - 1
     885            0 :                mixed_cdft%dest_list(j) = i
     886              :                mixed_cdft%dest_list_bo(:, j) = [bo_mixed(1, 1) + (bounds(i, 1) - bo_mixed(1, 1)), &
     887            0 :                                                 bo_mixed(2, 1) + (bounds(i, 2) - bo_mixed(2, 1))]
     888            0 :                j = j + 1
     889              :             END DO
     890            0 :             ALLOCATE (mixed_cdft%dest_list_save(ntargets), mixed_cdft%dest_bo_save(2, ntargets))
     891              :             ! We need to store backups of these arrays since they might get reallocated during dlb
     892            0 :             mixed_cdft%dest_list_save = mixed_cdft%dest_list
     893            0 :             mixed_cdft%dest_bo_save = mixed_cdft%dest_list_bo
     894              :             ! finally determine which procs will send me grid points
     895              :             ! now we need info about y dir also
     896            0 :             DEALLOCATE (bounds)
     897            0 :             ALLOCATE (bounds(0:pw_pools(1)%pool%pw_grid%para%group%num_pe - 1, 1:4))
     898            0 :             DO i = 0, pw_pools(1)%pool%pw_grid%para%group%num_pe - 1
     899            0 :                bounds(i, 1:2) = pw_pools(1)%pool%pw_grid%para%bo(1:2, 1, i, 1)
     900            0 :                bounds(i, 3:4) = pw_pools(1)%pool%pw_grid%para%bo(1:2, 2, i, 1)
     901            0 :                bounds(i, 1:2) = bounds(i, 1:2) - pw_pools(1)%pool%pw_grid%npts(1)/2 - 1
     902            0 :                bounds(i, 3:4) = bounds(i, 3:4) - pw_pools(1)%pool%pw_grid%npts(2)/2 - 1
     903              :             END DO
     904            0 :             ntargets = 0
     905            0 :             offset = -1
     906            0 :             DO i = 0, pw_pools(1)%pool%pw_grid%para%group%num_pe - 1
     907            0 :                IF ((bo(1, 1) >= bounds(i, 1) .AND. bo(1, 1) <= bounds(i, 2)) .OR. &
     908            0 :                    (bo(2, 1) >= bounds(i, 1) .AND. bo(2, 1) <= bounds(i, 2))) THEN
     909            0 :                   ntargets = ntargets + 1
     910            0 :                   IF (offset == -1) offset = i
     911            0 :                ELSE IF (bo(2, 1) < bounds(i, 1)) THEN
     912              :                   EXIT
     913              :                ELSE
     914            0 :                   CYCLE
     915              :                END IF
     916              :             END DO
     917            0 :             ALLOCATE (mixed_cdft%source_list(ntargets))
     918            0 :             ALLOCATE (mixed_cdft%source_list_bo(4, ntargets))
     919            0 :             j = 1
     920            0 :             DO i = offset, offset + ntargets - 1
     921            0 :                mixed_cdft%source_list(j) = i
     922            0 :                IF (bo(1, 1) >= bounds(i, 1) .AND. bo(2, 1) <= bounds(i, 2)) THEN
     923              :                   mixed_cdft%source_list_bo(:, j) = [bo(1, 1), bo(2, 1), &
     924            0 :                                                      bounds(i, 3), bounds(i, 4)]
     925            0 :                ELSE IF (bo(1, 1) >= bounds(i, 1) .AND. bo(1, 1) <= bounds(i, 2)) THEN
     926              :                   mixed_cdft%source_list_bo(:, j) = [bo(1, 1), bounds(i, 2), &
     927            0 :                                                      bounds(i, 3), bounds(i, 4)]
     928              :                ELSE
     929              :                   mixed_cdft%source_list_bo(:, j) = [bounds(i, 1), bo(2, 1), &
     930            0 :                                                      bounds(i, 3), bounds(i, 4)]
     931              :                END IF
     932            0 :                j = j + 1
     933              :             END DO
     934            0 :             ALLOCATE (mixed_cdft%source_list_save(ntargets), mixed_cdft%source_bo_save(4, ntargets))
     935              :             ! We need to store backups of these arrays since they might get reallocated during dlb
     936            0 :             mixed_cdft%source_list_save = mixed_cdft%source_list
     937            0 :             mixed_cdft%source_bo_save = mixed_cdft%source_list_bo
     938            0 :             DEALLOCATE (bounds)
     939              :          END IF
     940              :       ELSE
     941              :          ! Create loggers to redirect the output of all CDFT states to different files
     942              :          ! even when the states are treated in serial (the initial print of QS data [basis set etc] for
     943              :          ! all states unfortunately goes to the first log file)
     944           50 :          CALL force_env_get(force_env, root_section=root_section)
     945          224 :          ALLOCATE (mixed_cdft%sub_logger(nforce_eval - 1))
     946          124 :          DO i = 1, nforce_eval - 1
     947           74 :             IF (force_env%para_env%is_source()) THEN
     948              :                CALL section_vals_val_get(root_section, "GLOBAL%PROJECT_NAME", &
     949           37 :                                          c_val=input_file_path)
     950           37 :                lp = LEN_TRIM(input_file_path)
     951           37 :                input_file_path(lp + 1:LEN(input_file_path)) = "-r-"//ADJUSTL(cp_to_string(i + 1))
     952           37 :                lp = LEN_TRIM(input_file_path)
     953           37 :                output_file_path = input_file_path(1:lp)//".out"
     954              :                CALL open_file(file_name=output_file_path, file_status="UNKNOWN", &
     955              :                               file_action="WRITE", file_position="APPEND", &
     956           37 :                               unit_number=unit_nr)
     957              :             ELSE
     958           37 :                unit_nr = -1
     959              :             END IF
     960              :             CALL cp_logger_create(mixed_cdft%sub_logger(i)%p, &
     961              :                                   para_env=force_env%para_env, &
     962              :                                   default_global_unit_nr=unit_nr, &
     963           74 :                                   close_global_unit_on_dealloc=.FALSE.)
     964              :             ! Try to use better names for the local log if it is not too late
     965              :             CALL section_vals_val_get(root_section, "GLOBAL%OUTPUT_FILE_NAME", &
     966           74 :                                       c_val=c_val)
     967           74 :             IF (c_val /= "") THEN
     968              :                CALL cp_logger_set(mixed_cdft%sub_logger(i)%p, &
     969            0 :                                   local_filename=TRIM(c_val)//"_localLog")
     970              :             END IF
     971           74 :             CALL section_vals_val_get(root_section, "GLOBAL%PROJECT", c_val=c_val)
     972           74 :             IF (c_val /= "") THEN
     973              :                CALL cp_logger_set(mixed_cdft%sub_logger(i)%p, &
     974           74 :                                   local_filename=TRIM(c_val)//"_localLog")
     975              :             END IF
     976           74 :             IF (LEN_TRIM(c_val) > default_string_length) THEN
     977            0 :                CPWARN("The mixed CDFT project name will be truncated.")
     978              :             END IF
     979           74 :             mixed_cdft%sub_logger(i)%p%iter_info%project_name = TRIM(c_val)
     980              :             CALL section_vals_val_get(root_section, "GLOBAL%PRINT_LEVEL", &
     981          124 :                                       i_val=mixed_cdft%sub_logger(i)%p%iter_info%print_level)
     982              :          END DO
     983           50 :          IF (mixed_cdft%wfn_overlap_method) THEN
     984              :             ! qs_kind_set
     985            6 :             NULLIFY (root_section, force_env_section, force_env_sections, rs_grid_section)
     986            6 :             CALL force_env_get(force_env, root_section=root_section)
     987            6 :             force_env_sections => section_vals_get_subs_vals(root_section, "FORCE_EVAL")
     988            6 :             CALL multiple_fe_list(force_env_sections, root_section, i_force_eval, n_force_eval)
     989              :             CALL section_vals_duplicate(force_env_sections, force_env_section, &
     990            6 :                                         i_force_eval(2), i_force_eval(2))
     991              :             subsys_section => section_vals_get_subs_vals(force_env_sections, "SUBSYS", &
     992            6 :                                                          i_rep_section=i_force_eval(1))
     993            6 :             kind_section => section_vals_get_subs_vals(subsys_section, "KIND")
     994            6 :             NULLIFY (qs_kind_set)
     995            6 :             CALL cp_subsys_get(subsys_mix, atomic_kind_set=atomic_kind_set)
     996              :             CALL create_qs_kind_set(qs_kind_set, atomic_kind_set, kind_section, &
     997            6 :                                     force_env%para_env, force_env_section, silent=.FALSE.)
     998            6 :             mixed_cdft%qs_kind_set => qs_kind_set
     999            6 :             DEALLOCATE (i_force_eval)
    1000            6 :             CALL section_vals_release(force_env_section)
    1001            6 :             mixed_cdft%qs_kind_set => qs_kind_set
    1002              :          END IF
    1003              :          CALL force_env_get(force_env=force_env, &
    1004           50 :                             force_env_section=force_env_section)
    1005              :       END IF
    1006              :       ! Deallocate settings temporaries
    1007           72 :       DEALLOCATE (settings%grid_span)
    1008           72 :       DEALLOCATE (settings%npts)
    1009           72 :       DEALLOCATE (settings%spherical)
    1010           72 :       DEALLOCATE (settings%rs_dims)
    1011           72 :       DEALLOCATE (settings%odd)
    1012           72 :       DEALLOCATE (settings%atoms)
    1013           72 :       IF (mixed_cdft%run_type == mixed_cdft_parallel) &
    1014           22 :          DEALLOCATE (settings%coeffs)
    1015           72 :       DEALLOCATE (settings%cutoffs)
    1016           72 :       DEALLOCATE (settings%radii)
    1017           72 :       DEALLOCATE (settings%si)
    1018           72 :       DEALLOCATE (settings%sr)
    1019           72 :       DEALLOCATE (settings%sb)
    1020           72 :       DEALLOCATE (settings%cutoff)
    1021           72 :       DEALLOCATE (settings%rel_cutoff)
    1022              :       ! Setup mixed blacs_env for redistributing arrays during ET coupling calculation
    1023           72 :       IF (mixed_env%do_mixed_et) THEN
    1024           72 :          NULLIFY (root_section)
    1025           72 :          CALL force_env_get(force_env, globenv=globenv, root_section=root_section)
    1026              :          CALL cp_blacs_env_create(mixed_cdft%blacs_env, force_env%para_env, globenv%blacs_grid_layout, &
    1027           72 :                                   globenv%blacs_repeatable)
    1028              :       END IF
    1029              :       CALL cp_print_key_finished_output(iounit, logger, force_env_section, &
    1030           72 :                                         "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
    1031              : 
    1032          360 :    END SUBROUTINE mixed_cdft_init_structures
    1033              : 
    1034              : ! **************************************************************************************************
    1035              : !> \brief Redistribute arrays needed for an ET coupling calculation from individual CDFT states to
    1036              : !>        the mixed CDFT env, that is, move the arrays to the correct blacs context. For parallel
    1037              : !>        simulations, the array processor distributions also change from N to 2N processors.
    1038              : !> \param force_env the force_env that holds the CDFT states
    1039              : !> \par History
    1040              : !>       01.2017  created [Nico Holmberg]
    1041              : ! **************************************************************************************************
    1042           94 :    SUBROUTINE mixed_cdft_redistribute_arrays(force_env)
    1043              :       TYPE(force_env_type), POINTER                      :: force_env
    1044              : 
    1045              :       INTEGER                                            :: iforce_eval, ispin, ivar, ncol_overlap, &
    1046              :                                                             ncol_wmat, nforce_eval, nrow_overlap, &
    1047              :                                                             nrow_wmat, nspins, nvar
    1048           94 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ncol_mo, nrow_mo
    1049              :       LOGICAL                                            :: uniform_occupation
    1050           94 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: has_occupation_numbers
    1051           94 :       TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:, :) :: occno_tmp
    1052              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
    1053              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_mo, fm_struct_overlap, &
    1054              :                                                             fm_struct_tmp, fm_struct_wmat
    1055              :       TYPE(cp_fm_type)                                   :: matrix_s_tmp, mixed_matrix_s_tmp
    1056           94 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: matrix_p_tmp, mixed_matrix_p_tmp, &
    1057           94 :                                                             mixed_wmat_tmp, mo_coeff_tmp, wmat_tmp
    1058           94 :       TYPE(cp_fm_type), DIMENSION(:, :), POINTER         :: mixed_mo_coeff
    1059           94 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: density_matrix, w_matrix
    1060              :       TYPE(dbcsr_type)                                   :: desymm_tmp
    1061              :       TYPE(dbcsr_type), POINTER                          :: mixed_matrix_s
    1062              :       TYPE(dft_control_type), POINTER                    :: dft_control
    1063              :       TYPE(force_env_type), POINTER                      :: force_env_qs
    1064              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
    1065              :       TYPE(mixed_environment_type), POINTER              :: mixed_env
    1066              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1067              : 
    1068           94 :       NULLIFY (mixed_env, mixed_cdft, qs_env, dft_control, fm_struct_mo, &
    1069           94 :                fm_struct_wmat, fm_struct_overlap, fm_struct_tmp, &
    1070           94 :                mixed_mo_coeff, mixed_matrix_s, density_matrix, blacs_env, w_matrix, force_env_qs)
    1071            0 :       CPASSERT(ASSOCIATED(force_env))
    1072           94 :       mixed_env => force_env%mixed_env
    1073           94 :       nforce_eval = SIZE(force_env%sub_force_env)
    1074           94 :       CALL get_mixed_env(mixed_env, cdft_control=mixed_cdft)
    1075           94 :       CPASSERT(ASSOCIATED(mixed_cdft))
    1076           94 :       CALL mixed_cdft_work_type_init(mixed_cdft%matrix)
    1077              :       ! Get nspins and query for non-uniform occupation numbers
    1078          282 :       ALLOCATE (has_occupation_numbers(nforce_eval))
    1079          306 :       has_occupation_numbers = .FALSE.
    1080          306 :       DO iforce_eval = 1, nforce_eval
    1081          212 :          IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
    1082          176 :          force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
    1083          176 :          IF (force_env%mixed_env%do_mixed_qmmm_cdft) THEN
    1084           24 :             qs_env => force_env_qs%qmmm_env%qs_env
    1085              :          ELSE
    1086          152 :             CALL force_env_get(force_env_qs, qs_env=qs_env)
    1087              :          END IF
    1088          176 :          CALL get_qs_env(qs_env, dft_control=dft_control)
    1089          176 :          CPASSERT(ASSOCIATED(dft_control))
    1090          176 :          nspins = dft_control%nspins
    1091          176 :          IF (force_env_qs%para_env%is_source()) &
    1092          236 :             has_occupation_numbers(iforce_eval) = ALLOCATED(dft_control%qs_control%cdft_control%occupations)
    1093              :       END DO
    1094           94 :       CALL force_env%para_env%sum(has_occupation_numbers(1))
    1095          212 :       DO iforce_eval = 2, nforce_eval
    1096          118 :          CALL force_env%para_env%sum(has_occupation_numbers(iforce_eval))
    1097          118 :          IF (has_occupation_numbers(1) .NEQV. has_occupation_numbers(iforce_eval)) &
    1098              :             CALL cp_abort(__LOCATION__, &
    1099           94 :                           "Mixing of uniform and non-uniform occupations is not allowed.")
    1100              :       END DO
    1101           94 :       uniform_occupation = .NOT. has_occupation_numbers(1)
    1102           94 :       DEALLOCATE (has_occupation_numbers)
    1103              :       ! Get number of weight functions per state as well as the type of each constraint
    1104           94 :       nvar = SIZE(dft_control%qs_control%cdft_control%target)
    1105           94 :       IF (.NOT. ALLOCATED(mixed_cdft%constraint_type)) THEN
    1106          288 :          ALLOCATE (mixed_cdft%constraint_type(nvar, nforce_eval))
    1107          412 :          mixed_cdft%constraint_type(:, :) = 0
    1108           72 :          IF (mixed_cdft%identical_constraints) THEN
    1109          142 :             DO ivar = 1, nvar
    1110              :                mixed_cdft%constraint_type(ivar, :) = &
    1111          310 :                   dft_control%qs_control%cdft_control%group(ivar)%constraint_type
    1112              :             END DO
    1113              :          ELSE
    1114              :             ! Possibly couple spin and charge constraints
    1115            6 :             DO iforce_eval = 1, nforce_eval
    1116            4 :                IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
    1117            4 :                IF (force_env%mixed_env%do_mixed_qmmm_cdft) THEN
    1118            0 :                   qs_env => force_env%sub_force_env(iforce_eval)%force_env%qmmm_env%qs_env
    1119              :                ELSE
    1120            4 :                   CALL force_env_get(force_env%sub_force_env(iforce_eval)%force_env, qs_env=qs_env)
    1121              :                END IF
    1122            4 :                CALL get_qs_env(qs_env, dft_control=dft_control)
    1123            6 :                IF (force_env%sub_force_env(iforce_eval)%force_env%para_env%is_source()) THEN
    1124            4 :                   DO ivar = 1, nvar
    1125              :                      mixed_cdft%constraint_type(ivar, iforce_eval) = &
    1126            4 :                         dft_control%qs_control%cdft_control%group(ivar)%constraint_type
    1127              :                   END DO
    1128              :                END IF
    1129              :             END DO
    1130            2 :             CALL force_env%para_env%sum(mixed_cdft%constraint_type)
    1131              :          END IF
    1132              :       END IF
    1133              :       ! Transfer data from sub_force_envs to temporaries
    1134          988 :       ALLOCATE (mixed_cdft%matrix%mixed_mo_coeff(nforce_eval, nspins))
    1135           94 :       mixed_mo_coeff => mixed_cdft%matrix%mixed_mo_coeff
    1136          688 :       ALLOCATE (mixed_cdft%matrix%w_matrix(nforce_eval, nvar))
    1137           94 :       w_matrix => mixed_cdft%matrix%w_matrix
    1138           94 :       CALL dbcsr_init_p(mixed_cdft%matrix%mixed_matrix_s)
    1139           94 :       mixed_matrix_s => mixed_cdft%matrix%mixed_matrix_s
    1140           94 :       IF (mixed_cdft%calculate_metric) THEN
    1141          144 :          ALLOCATE (mixed_cdft%matrix%density_matrix(nforce_eval, nspins))
    1142           14 :          density_matrix => mixed_cdft%matrix%density_matrix
    1143              :       END IF
    1144         1488 :       ALLOCATE (mo_coeff_tmp(nforce_eval, nspins), wmat_tmp(nforce_eval, nvar))
    1145          376 :       ALLOCATE (nrow_mo(nspins), ncol_mo(nspins))
    1146          210 :       IF (mixed_cdft%calculate_metric) ALLOCATE (matrix_p_tmp(nforce_eval, nspins))
    1147           94 :       IF (.NOT. uniform_occupation) THEN
    1148          140 :          ALLOCATE (mixed_cdft%occupations(nforce_eval, nspins))
    1149          126 :          ALLOCATE (occno_tmp(nforce_eval, nspins))
    1150              :       END IF
    1151          306 :       DO iforce_eval = 1, nforce_eval
    1152              :          ! Temporary arrays need to be nulled on every process
    1153          636 :          DO ispin = 1, nspins
    1154              :             ! Valgrind 3.12/gfortran 4.8.4 oddly complains here (unconditional jump)
    1155              :             ! if mixed_cdft%calculate_metric = .FALSE. and the need to null the array
    1156              :             ! is queried with IF (mixed_cdft%calculate_metric) &
    1157          424 :             IF (.NOT. uniform_occupation) &
    1158          268 :                NULLIFY (occno_tmp(iforce_eval, ispin)%array)
    1159              :          END DO
    1160          212 :          IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
    1161              :          ! From this point onward, we access data local to the sub_force_envs
    1162              :          ! Get qs_env
    1163          176 :          force_env_qs => force_env%sub_force_env(iforce_eval)%force_env
    1164          176 :          IF (force_env%mixed_env%do_mixed_qmmm_cdft) THEN
    1165           24 :             qs_env => force_env_qs%qmmm_env%qs_env
    1166              :          ELSE
    1167          152 :             CALL force_env_get(force_env_qs, qs_env=qs_env)
    1168              :          END IF
    1169          176 :          CALL get_qs_env(qs_env, dft_control=dft_control, blacs_env=blacs_env)
    1170              :          ! Store dimensions of the transferred arrays
    1171              :          CALL dbcsr_get_info(dft_control%qs_control%cdft_control%matrix_s%matrix, &
    1172          176 :                              nfullrows_total=nrow_overlap, nfullcols_total=ncol_overlap)
    1173              :          CALL dbcsr_get_info(dft_control%qs_control%cdft_control%wmat(1)%matrix, &
    1174          176 :                              nfullrows_total=nrow_wmat, nfullcols_total=ncol_wmat)
    1175              :          ! MO Coefficients
    1176          528 :          DO ispin = 1, nspins
    1177              :             CALL cp_fm_get_info(dft_control%qs_control%cdft_control%mo_coeff(ispin), &
    1178          352 :                                 ncol_global=ncol_mo(ispin), nrow_global=nrow_mo(ispin))
    1179              :             CALL cp_fm_create(matrix=mo_coeff_tmp(iforce_eval, ispin), &
    1180              :                               matrix_struct=dft_control%qs_control%cdft_control%mo_coeff(ispin)%matrix_struct, &
    1181              :                               name="MO_COEFF_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_" &
    1182          352 :                               //TRIM(ADJUSTL(cp_to_string(ispin)))//"_MATRIX")
    1183              :             CALL cp_fm_to_fm(dft_control%qs_control%cdft_control%mo_coeff(ispin), &
    1184          528 :                              mo_coeff_tmp(iforce_eval, ispin))
    1185              :          END DO
    1186          176 :          CALL cp_fm_release(dft_control%qs_control%cdft_control%mo_coeff)
    1187              :          ! Matrix representation(s) of the weight function(s) (dbcsr -> fm)
    1188              :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nrow_wmat, ncol_global=ncol_wmat, context=blacs_env, &
    1189              :                                   para_env=force_env%sub_force_env(iforce_eval)%force_env%para_env, &
    1190          176 :                                   square_blocks=.TRUE.)
    1191          356 :          DO ivar = 1, nvar
    1192          180 :             CALL cp_fm_create(wmat_tmp(iforce_eval, ivar), fm_struct_tmp, name="w_matrix")
    1193          180 :             CALL dbcsr_desymmetrize(dft_control%qs_control%cdft_control%wmat(ivar)%matrix, desymm_tmp)
    1194          180 :             CALL copy_dbcsr_to_fm(desymm_tmp, wmat_tmp(iforce_eval, ivar))
    1195          180 :             CALL dbcsr_release(desymm_tmp)
    1196          356 :             CALL dbcsr_release_p(dft_control%qs_control%cdft_control%wmat(ivar)%matrix)
    1197              :          END DO
    1198          176 :          DEALLOCATE (dft_control%qs_control%cdft_control%wmat)
    1199          176 :          CALL cp_fm_struct_release(fm_struct_tmp)
    1200              :          ! Overlap matrix is the same for all sub_force_envs, so we just copy the first one (dbcsr -> fm)
    1201          176 :          IF (iforce_eval == 1) THEN
    1202              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nrow_overlap, &
    1203              :                                      ncol_global=ncol_overlap, context=blacs_env, &
    1204           76 :                                      para_env=force_env%sub_force_env(iforce_eval)%force_env%para_env)
    1205           76 :             CALL cp_fm_create(matrix_s_tmp, fm_struct_tmp, name="s_matrix")
    1206           76 :             CALL cp_fm_struct_release(fm_struct_tmp)
    1207           76 :             CALL dbcsr_desymmetrize(dft_control%qs_control%cdft_control%matrix_s%matrix, desymm_tmp)
    1208           76 :             CALL copy_dbcsr_to_fm(desymm_tmp, matrix_s_tmp)
    1209           76 :             CALL dbcsr_release(desymm_tmp)
    1210              :          END IF
    1211          176 :          CALL dbcsr_release_p(dft_control%qs_control%cdft_control%matrix_s%matrix)
    1212              :          ! Density_matrix (dbcsr -> fm)
    1213          176 :          IF (mixed_cdft%calculate_metric) THEN
    1214           72 :             DO ispin = 1, nspins
    1215              :                ! Size AOxAO
    1216              :                CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol_overlap, &
    1217              :                                         ncol_global=ncol_overlap, context=blacs_env, &
    1218           48 :                                         para_env=force_env%sub_force_env(iforce_eval)%force_env%para_env)
    1219           48 :                CALL cp_fm_create(matrix_p_tmp(iforce_eval, ispin), fm_struct_tmp, name="dm_matrix")
    1220           48 :                CALL cp_fm_struct_release(fm_struct_tmp)
    1221           48 :                CALL dbcsr_desymmetrize(dft_control%qs_control%cdft_control%matrix_p(ispin)%matrix, desymm_tmp)
    1222           48 :                CALL copy_dbcsr_to_fm(desymm_tmp, matrix_p_tmp(iforce_eval, ispin))
    1223           48 :                CALL dbcsr_release(desymm_tmp)
    1224           72 :                CALL dbcsr_release_p(dft_control%qs_control%cdft_control%matrix_p(ispin)%matrix)
    1225              :             END DO
    1226           24 :             DEALLOCATE (dft_control%qs_control%cdft_control%matrix_p)
    1227              :          END IF
    1228              :          ! Occupation numbers
    1229          446 :          IF (.NOT. uniform_occupation) THEN
    1230           84 :             DO ispin = 1, nspins
    1231           56 :                IF (ncol_mo(ispin) /= SIZE(dft_control%qs_control%cdft_control%occupations(ispin)%array)) &
    1232            0 :                   CPABORT("Array dimensions dont match.")
    1233           56 :                IF (force_env_qs%para_env%is_source()) THEN
    1234           84 :                   ALLOCATE (occno_tmp(iforce_eval, ispin)%array(ncol_mo(ispin)))
    1235          126 :                   occno_tmp(iforce_eval, ispin)%array = dft_control%qs_control%cdft_control%occupations(ispin)%array
    1236              :                END IF
    1237           84 :                DEALLOCATE (dft_control%qs_control%cdft_control%occupations(ispin)%array)
    1238              :             END DO
    1239           28 :             DEALLOCATE (dft_control%qs_control%cdft_control%occupations)
    1240              :          END IF
    1241              :       END DO
    1242              :       ! Create needed fm structs
    1243              :       CALL cp_fm_struct_create(fm_struct_wmat, nrow_global=nrow_wmat, ncol_global=ncol_wmat, &
    1244           94 :                                context=mixed_cdft%blacs_env, para_env=force_env%para_env)
    1245              :       CALL cp_fm_struct_create(fm_struct_overlap, nrow_global=nrow_overlap, ncol_global=ncol_overlap, &
    1246           94 :                                context=mixed_cdft%blacs_env, para_env=force_env%para_env)
    1247              :       ! Redistribute arrays with copy_general (this is not optimal for dbcsr matrices but...)
    1248              :       ! We use this method for the serial case (mixed_cdft%run_type == mixed_cdft_serial) as well to move the arrays to the
    1249              :       ! correct blacs_env, which is impossible using a simple copy of the arrays
    1250          594 :       ALLOCATE (mixed_wmat_tmp(nforce_eval, nvar))
    1251           94 :       IF (mixed_cdft%calculate_metric) &
    1252          130 :          ALLOCATE (mixed_matrix_p_tmp(nforce_eval, nspins))
    1253          306 :       DO iforce_eval = 1, nforce_eval
    1254              :          ! MO coefficients
    1255          636 :          DO ispin = 1, nspins
    1256          424 :             NULLIFY (fm_struct_mo)
    1257              :             CALL cp_fm_struct_create(fm_struct_mo, nrow_global=nrow_mo(ispin), ncol_global=ncol_mo(ispin), &
    1258          424 :                                      context=mixed_cdft%blacs_env, para_env=force_env%para_env)
    1259              :             CALL cp_fm_create(matrix=mixed_mo_coeff(iforce_eval, ispin), &
    1260              :                               matrix_struct=fm_struct_mo, &
    1261              :                               name="MO_COEFF_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_" &
    1262          424 :                               //TRIM(ADJUSTL(cp_to_string(ispin)))//"_MATRIX")
    1263              :             CALL cp_fm_copy_general(mo_coeff_tmp(iforce_eval, ispin), &
    1264              :                                     mixed_mo_coeff(iforce_eval, ispin), &
    1265          424 :                                     mixed_cdft%blacs_env%para_env)
    1266          424 :             CALL cp_fm_release(mo_coeff_tmp(iforce_eval, ispin))
    1267          636 :             CALL cp_fm_struct_release(fm_struct_mo)
    1268              :          END DO
    1269              :          ! Weight
    1270          428 :          DO ivar = 1, nvar
    1271          216 :             NULLIFY (w_matrix(iforce_eval, ivar)%matrix)
    1272          216 :             CALL dbcsr_init_p(w_matrix(iforce_eval, ivar)%matrix)
    1273              :             CALL cp_fm_create(matrix=mixed_wmat_tmp(iforce_eval, ivar), &
    1274              :                               matrix_struct=fm_struct_wmat, &
    1275          216 :                               name="WEIGHT_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_MATRIX")
    1276              :             CALL cp_fm_copy_general(wmat_tmp(iforce_eval, ivar), &
    1277              :                                     mixed_wmat_tmp(iforce_eval, ivar), &
    1278          216 :                                     mixed_cdft%blacs_env%para_env)
    1279          216 :             CALL cp_fm_release(wmat_tmp(iforce_eval, ivar))
    1280              :             ! (fm -> dbcsr)
    1281              :             CALL copy_fm_to_dbcsr_bc(mixed_wmat_tmp(iforce_eval, ivar), &
    1282          216 :                                      w_matrix(iforce_eval, ivar)%matrix)
    1283          428 :             CALL cp_fm_release(mixed_wmat_tmp(iforce_eval, ivar))
    1284              :          END DO
    1285              :          ! Density matrix (fm -> dbcsr)
    1286          306 :          IF (mixed_cdft%calculate_metric) THEN
    1287           90 :             DO ispin = 1, nspins
    1288           60 :                NULLIFY (density_matrix(iforce_eval, ispin)%matrix)
    1289           60 :                CALL dbcsr_init_p(density_matrix(iforce_eval, ispin)%matrix)
    1290              :                CALL cp_fm_create(matrix=mixed_matrix_p_tmp(iforce_eval, ispin), &
    1291              :                                  matrix_struct=fm_struct_overlap, &
    1292              :                                  name="DENSITY_"//TRIM(ADJUSTL(cp_to_string(iforce_eval)))//"_"// &
    1293           60 :                                  TRIM(ADJUSTL(cp_to_string(ispin)))//"_MATRIX")
    1294              :                CALL cp_fm_copy_general(matrix_p_tmp(iforce_eval, ispin), &
    1295              :                                        mixed_matrix_p_tmp(iforce_eval, ispin), &
    1296           60 :                                        mixed_cdft%blacs_env%para_env)
    1297           60 :                CALL cp_fm_release(matrix_p_tmp(iforce_eval, ispin))
    1298              :                CALL copy_fm_to_dbcsr_bc(mixed_matrix_p_tmp(iforce_eval, ispin), &
    1299           60 :                                         density_matrix(iforce_eval, ispin)%matrix)
    1300           90 :                CALL cp_fm_release(mixed_matrix_p_tmp(iforce_eval, ispin))
    1301              :             END DO
    1302              :          END IF
    1303              :       END DO
    1304           94 :       CALL cp_fm_struct_release(fm_struct_wmat)
    1305           94 :       DEALLOCATE (mo_coeff_tmp, wmat_tmp, mixed_wmat_tmp)
    1306           94 :       IF (mixed_cdft%calculate_metric) THEN
    1307           14 :          DEALLOCATE (matrix_p_tmp)
    1308           14 :          DEALLOCATE (mixed_matrix_p_tmp)
    1309              :       END IF
    1310              :       ! Overlap (fm -> dbcsr)
    1311              :       CALL cp_fm_create(matrix=mixed_matrix_s_tmp, &
    1312              :                         matrix_struct=fm_struct_overlap, &
    1313           94 :                         name="OVERLAP_MATRIX")
    1314           94 :       CALL cp_fm_struct_release(fm_struct_overlap)
    1315              :       CALL cp_fm_copy_general(matrix_s_tmp, &
    1316              :                               mixed_matrix_s_tmp, &
    1317           94 :                               mixed_cdft%blacs_env%para_env)
    1318           94 :       CALL cp_fm_release(matrix_s_tmp)
    1319           94 :       CALL copy_fm_to_dbcsr_bc(mixed_matrix_s_tmp, mixed_matrix_s)
    1320           94 :       CALL cp_fm_release(mixed_matrix_s_tmp)
    1321              :       ! Occupation numbers
    1322           94 :       IF (.NOT. uniform_occupation) THEN
    1323           42 :          DO iforce_eval = 1, nforce_eval
    1324           98 :             DO ispin = 1, nspins
    1325          168 :                ALLOCATE (mixed_cdft%occupations(iforce_eval, ispin)%array(ncol_mo(ispin)))
    1326          252 :                mixed_cdft%occupations(iforce_eval, ispin)%array = 0.0_dp
    1327           56 :                IF (ASSOCIATED(occno_tmp(iforce_eval, ispin)%array)) THEN
    1328          126 :                   mixed_cdft%occupations(iforce_eval, ispin)%array = occno_tmp(iforce_eval, ispin)%array
    1329           28 :                   DEALLOCATE (occno_tmp(iforce_eval, ispin)%array)
    1330              :                END IF
    1331          476 :                CALL force_env%para_env%sum(mixed_cdft%occupations(iforce_eval, ispin)%array)
    1332              :             END DO
    1333              :          END DO
    1334           14 :          DEALLOCATE (occno_tmp)
    1335              :       END IF
    1336           94 :       DEALLOCATE (ncol_mo, nrow_mo)
    1337              : 
    1338          282 :    END SUBROUTINE mixed_cdft_redistribute_arrays
    1339              : ! **************************************************************************************************
    1340              : !> \brief Routine to print out the electronic coupling(s) between CDFT states.
    1341              : !> \param force_env the force_env that holds the CDFT states
    1342              : !> \par History
    1343              : !>       11.17  created [Nico Holmberg]
    1344              : ! **************************************************************************************************
    1345           94 :    SUBROUTINE mixed_cdft_print_couplings(force_env)
    1346              :       TYPE(force_env_type), POINTER                      :: force_env
    1347              : 
    1348              :       INTEGER                                            :: iounit, ipermutation, istate, ivar, &
    1349              :                                                             jstate, nforce_eval, npermutations, &
    1350              :                                                             nvar
    1351              :       TYPE(cp_logger_type), POINTER                      :: logger
    1352              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
    1353              :       TYPE(section_vals_type), POINTER                   :: force_env_section, print_section
    1354              : 
    1355           94 :       NULLIFY (print_section, mixed_cdft)
    1356              : 
    1357           94 :       logger => cp_get_default_logger()
    1358           94 :       CPASSERT(ASSOCIATED(force_env))
    1359              :       CALL force_env_get(force_env=force_env, &
    1360           94 :                          force_env_section=force_env_section)
    1361           94 :       CALL get_mixed_env(force_env%mixed_env, cdft_control=mixed_cdft)
    1362           94 :       CPASSERT(ASSOCIATED(mixed_cdft))
    1363           94 :       print_section => section_vals_get_subs_vals(force_env_section, "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
    1364           94 :       iounit = cp_print_key_unit_nr(logger, print_section, '', extension='.mixedLog')
    1365              :       !
    1366           94 :       CPASSERT(ALLOCATED(mixed_cdft%results%strength))
    1367           94 :       CPASSERT(ALLOCATED(mixed_cdft%results%W_diagonal))
    1368           94 :       CPASSERT(ALLOCATED(mixed_cdft%results%S))
    1369           94 :       CPASSERT(ALLOCATED(mixed_cdft%results%energy))
    1370           94 :       nforce_eval = SIZE(force_env%sub_force_env)
    1371           94 :       nvar = SIZE(mixed_cdft%results%strength, 1)
    1372           94 :       npermutations = nforce_eval*(nforce_eval - 1)/2 ! Size of upper triangular part
    1373           94 :       IF (iounit > 0) THEN
    1374              :          WRITE (iounit, '(/,T3,A,T66)') &
    1375           47 :             '------------------------- CDFT coupling information --------------------------'
    1376              :          WRITE (iounit, '(T3,A,T66,(3X,F12.2))') &
    1377           47 :             'Information at step (fs):', mixed_cdft%sim_step*mixed_cdft%sim_dt
    1378          135 :          DO ipermutation = 1, npermutations
    1379           88 :             CALL map_permutation_to_states(nforce_eval, ipermutation, istate, jstate)
    1380           88 :             WRITE (iounit, '(/,T3,A)') REPEAT('#', 44)
    1381           88 :             WRITE (iounit, '(T3,A,I3,A,I3,A)') '###### CDFT states I =', istate, ' and J = ', jstate, ' ######'
    1382           88 :             WRITE (iounit, '(T3,A)') REPEAT('#', 44)
    1383          177 :             DO ivar = 1, nvar
    1384           89 :                IF (ivar > 1) &
    1385            1 :                   WRITE (iounit, '(A)') ''
    1386           89 :                WRITE (iounit, '(T3,A,T60,(3X,I18))') 'Atomic group:', ivar
    1387              :                WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1388           89 :                   'Strength of constraint I:', mixed_cdft%results%strength(ivar, istate)
    1389              :                WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1390           89 :                   'Strength of constraint J:', mixed_cdft%results%strength(ivar, jstate)
    1391              :                WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1392           89 :                   'Final value of constraint I:', mixed_cdft%results%W_diagonal(ivar, istate)
    1393              :                WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1394          177 :                   'Final value of constraint J:', mixed_cdft%results%W_diagonal(ivar, jstate)
    1395              :             END DO
    1396              :             WRITE (iounit, '(/,T3,A,T60,(3X,F18.12))') &
    1397           88 :                'Overlap between states I and J:', mixed_cdft%results%S(istate, jstate)
    1398              :             WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1399           88 :                'Charge transfer energy (J-I) (Hartree):', (mixed_cdft%results%energy(jstate) - mixed_cdft%results%energy(istate))
    1400           88 :             WRITE (iounit, *)
    1401           88 :             IF (ALLOCATED(mixed_cdft%results%rotation)) THEN
    1402           86 :                IF (ABS(mixed_cdft%results%rotation(ipermutation))*1.0E3_dp >= 0.1_dp) THEN
    1403              :                   WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1404           83 :                      'Diabatic electronic coupling (rotation, mHartree):', &
    1405          166 :                      ABS(mixed_cdft%results%rotation(ipermutation)*1.0E3_dp)
    1406              :                ELSE
    1407              :                   WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1408            3 :                      'Diabatic electronic coupling (rotation, microHartree):', &
    1409            6 :                      ABS(mixed_cdft%results%rotation(ipermutation)*1.0E6_dp)
    1410              :                END IF
    1411              :             END IF
    1412           88 :             IF (ALLOCATED(mixed_cdft%results%lowdin)) THEN
    1413           10 :                IF (ABS(mixed_cdft%results%lowdin(ipermutation))*1.0E3_dp >= 0.1_dp) THEN
    1414              :                   WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1415            9 :                      'Diabatic electronic coupling (Lowdin, mHartree):', &
    1416           18 :                      ABS(mixed_cdft%results%lowdin(ipermutation)*1.0E3_dp)
    1417              :                ELSE
    1418              :                   WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1419            1 :                      'Diabatic electronic coupling (Lowdin, microHartree):', &
    1420            2 :                      ABS(mixed_cdft%results%lowdin(ipermutation)*1.0E6_dp)
    1421              :                END IF
    1422              :             END IF
    1423           88 :             IF (ALLOCATED(mixed_cdft%results%wfn)) THEN
    1424            6 :                IF (mixed_cdft%results%wfn(ipermutation)*1.0E3_dp >= 0.1_dp) THEN
    1425              :                   WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1426            5 :                      'Diabatic electronic coupling (wfn overlap, mHartree):', &
    1427           10 :                      ABS(mixed_cdft%results%wfn(ipermutation)*1.0E3_dp)
    1428              :                ELSE
    1429              :                   WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1430            1 :                      'Diabatic electronic coupling (wfn overlap, microHartree):', &
    1431            2 :                      ABS(mixed_cdft%results%wfn(ipermutation)*1.0E6_dp)
    1432              :                END IF
    1433              :             END IF
    1434           88 :             IF (ALLOCATED(mixed_cdft%results%nonortho)) THEN
    1435              :                WRITE (iounit, '(T3,A,T60,(3X,F18.12))') &
    1436           50 :                   'Diabatic electronic coupling (nonorthogonal, Hartree):', mixed_cdft%results%nonortho(ipermutation)
    1437              :             END IF
    1438          223 :             IF (ALLOCATED(mixed_cdft%results%metric)) THEN
    1439            9 :                WRITE (iounit, *)
    1440            9 :                IF (SIZE(mixed_cdft%results%metric, 2) == 1) THEN
    1441              :                   WRITE (iounit, '(T3,A,T66,(3X,F12.6))') &
    1442            0 :                      'Coupling reliability metric (0 is ideal):', mixed_cdft%results%metric(ipermutation, 1)
    1443              :                ELSE
    1444              :                   WRITE (iounit, '(T3,A,T54,(3X,2F12.6))') &
    1445            9 :                      'Coupling reliability metric (0 is ideal):', &
    1446           18 :                      mixed_cdft%results%metric(ipermutation, 1), mixed_cdft%results%metric(ipermutation, 2)
    1447              :                END IF
    1448              :             END IF
    1449              :          END DO
    1450              :          WRITE (iounit, '(T3,A)') &
    1451           47 :             '------------------------------------------------------------------------------'
    1452              :       END IF
    1453              :       CALL cp_print_key_finished_output(iounit, logger, force_env_section, &
    1454           94 :                                         "MIXED%MIXED_CDFT%PRINT%PROGRAM_RUN_INFO")
    1455              : 
    1456           94 :    END SUBROUTINE mixed_cdft_print_couplings
    1457              : 
    1458              : ! **************************************************************************************************
    1459              : !> \brief Release storage reserved for mixed CDFT matrices
    1460              : !> \param force_env the force_env that holds the CDFT states
    1461              : !> \par History
    1462              : !>       11.17  created [Nico Holmberg]
    1463              : ! **************************************************************************************************
    1464           94 :    SUBROUTINE mixed_cdft_release_work(force_env)
    1465              :       TYPE(force_env_type), POINTER                      :: force_env
    1466              : 
    1467              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
    1468              : 
    1469           94 :       NULLIFY (mixed_cdft)
    1470              : 
    1471           94 :       CPASSERT(ASSOCIATED(force_env))
    1472           94 :       CALL get_mixed_env(force_env%mixed_env, cdft_control=mixed_cdft)
    1473           94 :       CPASSERT(ASSOCIATED(mixed_cdft))
    1474           94 :       CALL mixed_cdft_result_type_release(mixed_cdft%results)
    1475              : 
    1476           94 :    END SUBROUTINE mixed_cdft_release_work
    1477              : 
    1478              : ! **************************************************************************************************
    1479              : !> \brief Given the size of a symmetric matrix and a permutation index, returns indices (i, j) of the
    1480              : !>        off-diagonal element that corresponds to the permutation index. Assumes that the permutation
    1481              : !>        index was computed by going through the upper triangular part of the input matrix row-by-row.
    1482              : !> \param n the size of the symmetric matrix
    1483              : !> \param ipermutation the permutation index
    1484              : !> \param i the row index corresponding to ipermutation
    1485              : !> \param j the column index corresponding to ipermutation
    1486              : ! **************************************************************************************************
    1487         1248 :    SUBROUTINE map_permutation_to_states(n, ipermutation, i, j)
    1488              :       INTEGER, INTENT(IN)                                :: n, ipermutation
    1489              :       INTEGER, INTENT(OUT)                               :: i, j
    1490              : 
    1491              :       INTEGER                                            :: kcol, kpermutation, krow, npermutations
    1492              : 
    1493         1248 :       npermutations = n*(n - 1)/2 ! Size of upper triangular part
    1494         1248 :       IF (ipermutation > npermutations) &
    1495            0 :          CPABORT("Permutation index out of bounds")
    1496         1248 :       kpermutation = 0
    1497         2124 :       DO krow = 1, n
    1498         7566 :          DO kcol = krow + 1, n
    1499         6690 :             kpermutation = kpermutation + 1
    1500         7566 :             IF (kpermutation == ipermutation) THEN
    1501         1248 :                i = krow
    1502         1248 :                j = kcol
    1503         1248 :                RETURN
    1504              :             END IF
    1505              :          END DO
    1506              :       END DO
    1507              : 
    1508              :    END SUBROUTINE map_permutation_to_states
    1509              : 
    1510              : ! **************************************************************************************************
    1511              : !> \brief Determine confinement bounds along confinement dir (hardcoded to be z)
    1512              : !>        and determine the number of nonzero entries
    1513              : !>        Optionally zero entries below a given threshold
    1514              : !> \param fun input 3D potential (real space)
    1515              : !> \param th threshold for screening values
    1516              : !> \param just_zero determines if fun should only be zeroed without returning bounds/work
    1517              : !> \param bounds the confinement bounds: fun is nonzero only between these values along 3rd dimension
    1518              : !> \param work an estimate of the total number of grid points where fun is nonzero
    1519              : ! **************************************************************************************************
    1520           34 :    SUBROUTINE hfun_zero(fun, th, just_zero, bounds, work)
    1521              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: fun
    1522              :       REAL(KIND=dp), INTENT(IN)                          :: th
    1523              :       LOGICAL                                            :: just_zero
    1524              :       INTEGER, OPTIONAL                                  :: bounds(2), work
    1525              : 
    1526              :       INTEGER                                            :: i1, i2, i3, lb, n1, n2, n3, nzeroed, &
    1527              :                                                             nzeroed_total, ub
    1528              :       LOGICAL                                            :: lb_final, ub_final
    1529              : 
    1530           34 :       n1 = SIZE(fun, 1)
    1531           34 :       n2 = SIZE(fun, 2)
    1532           34 :       n3 = SIZE(fun, 3)
    1533           34 :       nzeroed_total = 0
    1534           34 :       IF (.NOT. just_zero) THEN
    1535           34 :          CPASSERT(PRESENT(bounds))
    1536           34 :          CPASSERT(PRESENT(work))
    1537              :          lb = 1
    1538              :          lb_final = .FALSE.
    1539              :          ub_final = .FALSE.
    1540              :       END IF
    1541         1586 :       DO i3 = 1, n3
    1542         1552 :          IF (.NOT. just_zero) nzeroed = 0
    1543        75920 :          DO i2 = 1, n2
    1544      1956496 :             DO i1 = 1, n1
    1545      1954944 :                IF (fun(i1, i2, i3) < th) THEN
    1546       983300 :                   IF (.NOT. just_zero) THEN
    1547       983300 :                      nzeroed = nzeroed + 1
    1548       983300 :                      nzeroed_total = nzeroed_total + 1
    1549              :                   ELSE
    1550            0 :                      fun(i1, i2, i3) = 0.0_dp
    1551              :                   END IF
    1552              :                END IF
    1553              :             END DO
    1554              :          END DO
    1555         1586 :          IF (.NOT. just_zero) THEN
    1556         1552 :             IF (nzeroed == (n2*n1)) THEN
    1557           80 :                IF (.NOT. lb_final) THEN
    1558              :                   lb = i3
    1559           56 :                ELSE IF (.NOT. ub_final) THEN
    1560            8 :                   ub = i3
    1561            8 :                   ub_final = .TRUE.
    1562              :                END IF
    1563              :             ELSE
    1564              :                IF (.NOT. lb_final) lb_final = .TRUE.
    1565              :                IF (ub_final) ub_final = .FALSE. ! Safeguard against "holes"
    1566              :             END IF
    1567              :          END IF
    1568              :       END DO
    1569           34 :       IF (.NOT. just_zero) THEN
    1570           34 :          IF (.NOT. ub_final) ub = n3
    1571           34 :          bounds(1) = lb
    1572           34 :          bounds(2) = ub
    1573          102 :          bounds = bounds - (n3/2) - 1
    1574           34 :          work = n3*n2*n1 - nzeroed_total
    1575              :       END IF
    1576              : 
    1577           34 :    END SUBROUTINE hfun_zero
    1578              : 
    1579              : ! **************************************************************************************************
    1580              : !> \brief Read input section related to block diagonalization of the mixed CDFT Hamiltonian matrix.
    1581              : !> \param force_env        the force_env that holds the CDFT states
    1582              : !> \param blocks           list of CDFT states defining the matrix blocks
    1583              : !> \param ignore_excited   flag that determines if excited states resulting from the block
    1584              : !>                         diagonalization process should be ignored
    1585              : !> \param nrecursion       integer that determines how many steps of recursive block diagonalization
    1586              : !>                         is performed (1 if disabled)
    1587              : !> \par History
    1588              : !>       01.18  created [Nico Holmberg]
    1589              : ! **************************************************************************************************
    1590            8 :    SUBROUTINE mixed_cdft_read_block_diag(force_env, blocks, ignore_excited, nrecursion)
    1591              :       TYPE(force_env_type), POINTER                      :: force_env
    1592              :       TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:), &
    1593              :          INTENT(OUT)                                     :: blocks
    1594              :       LOGICAL, INTENT(OUT)                               :: ignore_excited
    1595              :       INTEGER, INTENT(OUT)                               :: nrecursion
    1596              : 
    1597              :       INTEGER                                            :: i, j, k, l, nblk, nforce_eval
    1598            8 :       INTEGER, DIMENSION(:), POINTER                     :: tmplist
    1599              :       LOGICAL                                            :: do_recursive, explicit, has_duplicates
    1600              :       TYPE(section_vals_type), POINTER                   :: block_section, force_env_section
    1601              : 
    1602              :       EXTERNAL                                           :: dsygv
    1603              : 
    1604            8 :       NULLIFY (force_env_section, block_section)
    1605            0 :       CPASSERT(ASSOCIATED(force_env))
    1606            8 :       nforce_eval = SIZE(force_env%sub_force_env)
    1607              : 
    1608              :       CALL force_env_get(force_env=force_env, &
    1609            8 :                          force_env_section=force_env_section)
    1610            8 :       block_section => section_vals_get_subs_vals(force_env_section, "MIXED%MIXED_CDFT%BLOCK_DIAGONALIZE")
    1611              : 
    1612            8 :       CALL section_vals_get(block_section, explicit=explicit)
    1613            8 :       IF (.NOT. explicit) &
    1614              :          CALL cp_abort(__LOCATION__, &
    1615              :                        "Block diagonalization of CDFT Hamiltonian was requested, but the "// &
    1616            0 :                        "corresponding input section is missing!")
    1617              : 
    1618            8 :       CALL section_vals_val_get(block_section, "BLOCK", n_rep_val=nblk)
    1619           44 :       ALLOCATE (blocks(nblk))
    1620           28 :       DO i = 1, nblk
    1621           20 :          NULLIFY (blocks(i)%array)
    1622           20 :          CALL section_vals_val_get(block_section, "BLOCK", i_rep_val=i, i_vals=tmplist)
    1623           20 :          IF (SIZE(tmplist) < 1) &
    1624            0 :             CPABORT("Each BLOCK must contain at least 1 state.")
    1625           60 :          ALLOCATE (blocks(i)%array(SIZE(tmplist)))
    1626           66 :          blocks(i)%array(:) = tmplist(:)
    1627              :       END DO
    1628            8 :       CALL section_vals_val_get(block_section, "IGNORE_EXCITED", l_val=ignore_excited)
    1629            8 :       CALL section_vals_val_get(block_section, "RECURSIVE_DIAGONALIZATION", l_val=do_recursive)
    1630              :       ! Check that the requested states exist
    1631           28 :       DO i = 1, nblk
    1632           66 :          DO j = 1, SIZE(blocks(i)%array)
    1633           38 :             IF (blocks(i)%array(j) < 1 .OR. blocks(i)%array(j) > nforce_eval) &
    1634           20 :                CPABORT("Requested state does not exist.")
    1635              :          END DO
    1636              :       END DO
    1637              :       ! Check for duplicates
    1638            8 :       has_duplicates = .FALSE.
    1639           28 :       DO i = 1, nblk
    1640              :          ! Within same block
    1641           58 :          DO j = 1, SIZE(blocks(i)%array)
    1642           76 :             DO k = j + 1, SIZE(blocks(i)%array)
    1643           56 :                IF (blocks(i)%array(j) == blocks(i)%array(k)) has_duplicates = .TRUE.
    1644              :             END DO
    1645              :          END DO
    1646              :          ! Within different blocks
    1647           46 :          DO j = i + 1, nblk
    1648           74 :             DO k = 1, SIZE(blocks(i)%array)
    1649          122 :                DO l = 1, SIZE(blocks(j)%array)
    1650          104 :                   IF (blocks(i)%array(k) == blocks(j)%array(l)) has_duplicates = .TRUE.
    1651              :                END DO
    1652              :             END DO
    1653              :          END DO
    1654              :       END DO
    1655            8 :       IF (has_duplicates) CPABORT("Duplicate states are not allowed.")
    1656            8 :       nrecursion = 1
    1657            8 :       IF (do_recursive) THEN
    1658            2 :          IF (MODULO(nblk, 2) /= 0) THEN
    1659              :             CALL cp_warn(__LOCATION__, &
    1660              :                          "Number of blocks not divisible with 2. Recursive diagonalization not possible. "// &
    1661            0 :                          "Calculation proceeds without.")
    1662            0 :             nrecursion = 1
    1663              :          ELSE
    1664            2 :             nrecursion = nblk/2
    1665              :          END IF
    1666            2 :          IF (nrecursion /= 1 .AND. .NOT. ignore_excited) &
    1667              :             CALL cp_abort(__LOCATION__, &
    1668            0 :                           "Keyword IGNORE_EXCITED must be active for recursive diagonalization.")
    1669              :       END IF
    1670              : 
    1671           32 :    END SUBROUTINE mixed_cdft_read_block_diag
    1672              : 
    1673              : ! **************************************************************************************************
    1674              : !> \brief Assembles the matrix blocks from the mixed CDFT Hamiltonian.
    1675              : !> \param mixed_cdft the env that holds the CDFT states
    1676              : !> \param blocks  list of CDFT states defining the matrix blocks
    1677              : !> \param H_block list of Hamiltonian matrix blocks
    1678              : !> \param S_block list of overlap matrix blocks
    1679              : !> \par History
    1680              : !>       01.18  created [Nico Holmberg]
    1681              : ! **************************************************************************************************
    1682           10 :    SUBROUTINE mixed_cdft_get_blocks(mixed_cdft, blocks, H_block, S_block)
    1683              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
    1684              :       TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:)    :: blocks
    1685              :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:), &
    1686              :          INTENT(OUT)                                     :: H_block, S_block
    1687              : 
    1688              :       INTEGER                                            :: i, icol, irow, j, k, nblk
    1689              : 
    1690              :       EXTERNAL                                           :: dsygv
    1691              : 
    1692           10 :       CPASSERT(ASSOCIATED(mixed_cdft))
    1693              : 
    1694           10 :       nblk = SIZE(blocks)
    1695           98 :       ALLOCATE (H_block(nblk), S_block(nblk))
    1696           34 :       DO i = 1, nblk
    1697           24 :          NULLIFY (H_block(i)%array)
    1698           24 :          NULLIFY (S_block(i)%array)
    1699           96 :          ALLOCATE (H_block(i)%array(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
    1700           96 :          ALLOCATE (S_block(i)%array(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
    1701           24 :          icol = 0
    1702           70 :          DO j = 1, SIZE(blocks(i)%array)
    1703           46 :             irow = 0
    1704           46 :             icol = icol + 1
    1705          160 :             DO k = 1, SIZE(blocks(i)%array)
    1706           90 :                irow = irow + 1
    1707           90 :                H_block(i)%array(irow, icol) = mixed_cdft%results%H(blocks(i)%array(k), blocks(i)%array(j))
    1708          136 :                S_block(i)%array(irow, icol) = mixed_cdft%results%S(blocks(i)%array(k), blocks(i)%array(j))
    1709              :             END DO
    1710              :          END DO
    1711              :          ! Check that none of the interaction energies is repulsive
    1712          160 :          IF (ANY(H_block(i)%array >= 0.0_dp)) &
    1713              :             CALL cp_abort(__LOCATION__, &
    1714              :                           "At least one of the interaction energies within block "//TRIM(ADJUSTL(cp_to_string(i)))// &
    1715           10 :                           " is repulsive.")
    1716              :       END DO
    1717              : 
    1718           10 :    END SUBROUTINE mixed_cdft_get_blocks
    1719              : 
    1720              : ! **************************************************************************************************
    1721              : !> \brief Diagonalizes each of the matrix blocks.
    1722              : !> \param blocks  list of CDFT states defining the matrix blocks
    1723              : !> \param H_block list of Hamiltonian matrix blocks
    1724              : !> \param S_block list of overlap matrix blocks
    1725              : !> \param eigenvalues list of eigenvalues for each block
    1726              : !> \par History
    1727              : !>       01.18  created [Nico Holmberg]
    1728              : ! **************************************************************************************************
    1729           10 :    SUBROUTINE mixed_cdft_diagonalize_blocks(blocks, H_block, S_block, eigenvalues)
    1730              :       TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:)    :: blocks
    1731              :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: H_block, S_block
    1732              :       TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:), &
    1733              :          INTENT(OUT)                                     :: eigenvalues
    1734              : 
    1735              :       INTEGER                                            :: i, info, nblk, work_array_size
    1736           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: work
    1737           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: H_mat_copy, S_mat_copy
    1738              : 
    1739              :       EXTERNAL                                           :: dsygv
    1740              : 
    1741           10 :       nblk = SIZE(blocks)
    1742           54 :       ALLOCATE (eigenvalues(nblk))
    1743           34 :       DO i = 1, nblk
    1744           24 :          NULLIFY (eigenvalues(i)%array)
    1745           72 :          ALLOCATE (eigenvalues(i)%array(SIZE(blocks(i)%array)))
    1746           70 :          eigenvalues(i)%array = 0.0_dp
    1747              :          ! Workspace query
    1748           24 :          ALLOCATE (work(1))
    1749           24 :          info = 0
    1750           96 :          ALLOCATE (H_mat_copy(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
    1751           72 :          ALLOCATE (S_mat_copy(SIZE(blocks(i)%array), SIZE(blocks(i)%array)))
    1752          160 :          H_mat_copy(:, :) = H_block(i)%array(:, :) ! Need explicit copies because dsygv destroys original values
    1753          160 :          S_mat_copy(:, :) = S_block(i)%array(:, :)
    1754              :          CALL dsygv(1, 'V', 'U', SIZE(blocks(i)%array), H_mat_copy, SIZE(blocks(i)%array), &
    1755           24 :                     S_mat_copy, SIZE(blocks(i)%array), eigenvalues(i)%array, work, -1, info)
    1756           24 :          work_array_size = NINT(work(1))
    1757           24 :          DEALLOCATE (H_mat_copy, S_mat_copy)
    1758              :          ! Allocate work array
    1759           24 :          DEALLOCATE (work)
    1760           72 :          ALLOCATE (work(work_array_size))
    1761         1588 :          work = 0.0_dp
    1762              :          ! Solve Hc = eSc
    1763           24 :          info = 0
    1764              :          CALL dsygv(1, 'V', 'U', SIZE(blocks(i)%array), H_block(i)%array, SIZE(blocks(i)%array), &
    1765           24 :                     S_block(i)%array, SIZE(blocks(i)%array), eigenvalues(i)%array, work, work_array_size, info)
    1766           24 :          IF (info /= 0) THEN
    1767            0 :             IF (info > SIZE(blocks(i)%array)) THEN
    1768            0 :                CPABORT("Matrix S is not positive definite")
    1769              :             ELSE
    1770            0 :                CPABORT("Diagonalization of H matrix failed.")
    1771              :             END IF
    1772              :          END IF
    1773           34 :          DEALLOCATE (work)
    1774              :       END DO
    1775              : 
    1776           10 :    END SUBROUTINE mixed_cdft_diagonalize_blocks
    1777              : 
    1778              : ! **************************************************************************************************
    1779              : !> \brief Assembles the new block diagonalized mixed CDFT Hamiltonian and overlap matrices.
    1780              : !> \param mixed_cdft the env that holds the CDFT states
    1781              : !> \param blocks  list of CDFT states defining the matrix blocks
    1782              : !> \param H_block list of Hamiltonian matrix blocks
    1783              : !> \param eigenvalues list of eigenvalues for each block
    1784              : !> \param n size of the new Hamiltonian and overlap matrices
    1785              : !> \param iounit the output unit
    1786              : !> \par History
    1787              : !>       01.18  created [Nico Holmberg]
    1788              : ! **************************************************************************************************
    1789           10 :    SUBROUTINE mixed_cdft_assemble_block_diag(mixed_cdft, blocks, H_block, eigenvalues, &
    1790              :                                              n, iounit)
    1791              :       TYPE(mixed_cdft_type), POINTER                     :: mixed_cdft
    1792              :       TYPE(cp_1d_i_p_type), ALLOCATABLE, DIMENSION(:)    :: blocks
    1793              :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: H_block
    1794              :       TYPE(cp_1d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: eigenvalues
    1795              :       INTEGER                                            :: n, iounit
    1796              : 
    1797              :       CHARACTER(LEN=20)                                  :: ilabel, jlabel
    1798              :       CHARACTER(LEN=3)                                   :: tmp
    1799              :       INTEGER                                            :: i, icol, ipermutation, irow, j, k, l, &
    1800              :                                                             nblk, npermutations
    1801              :       LOGICAL                                            :: ignore_excited
    1802           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: H_mat, H_offdiag, S_mat, S_offdiag
    1803              : 
    1804              :       EXTERNAL                                           :: dsygv
    1805              : 
    1806           60 :       ALLOCATE (H_mat(n, n), S_mat(n, n))
    1807           10 :       nblk = SIZE(blocks)
    1808           10 :       ignore_excited = (nblk == n)
    1809              :       ! The diagonal contains the eigenvalues of each block
    1810           10 :       IF (iounit > 0) WRITE (iounit, '(/,T3,A)') "Eigenvalues of the block diagonalized states"
    1811          126 :       H_mat(:, :) = 0.0_dp
    1812          126 :       S_mat(:, :) = 0.0_dp
    1813           10 :       k = 1
    1814           34 :       DO i = 1, nblk
    1815           24 :          IF (iounit > 0) WRITE (iounit, '(T6,A,I3)') "Block", i
    1816           42 :          DO j = 1, SIZE(eigenvalues(i)%array)
    1817           28 :             H_mat(k, k) = eigenvalues(i)%array(j)
    1818           28 :             S_mat(k, k) = 1.0_dp
    1819           28 :             k = k + 1
    1820           28 :             IF (iounit > 0) THEN
    1821           14 :                IF (j == 1) THEN
    1822           12 :                   WRITE (iounit, '(T9,A,T58,(3X,F20.14))') 'Ground state energy:', eigenvalues(i)%array(j)
    1823              :                ELSE
    1824              :                   WRITE (iounit, '(T9,A,I2,A,T58,(3X,F20.14))') &
    1825            2 :                      'Excited state (', j - 1, ' ) energy:', eigenvalues(i)%array(j)
    1826              :                END IF
    1827              :             END IF
    1828           32 :             IF (ignore_excited .AND. j == 1) EXIT
    1829              :          END DO
    1830              :       END DO
    1831              :       ! Transform the off-diagonal blocks using the eigenvectors of each block
    1832           10 :       npermutations = nblk*(nblk - 1)/2
    1833           10 :       IF (iounit > 0) WRITE (iounit, '(/,T3,A)') "Interactions between block diagonalized states"
    1834           30 :       DO ipermutation = 1, npermutations
    1835           20 :          CALL map_permutation_to_states(nblk, ipermutation, i, j)
    1836              :          ! Get the untransformed off-diagonal block
    1837           80 :          ALLOCATE (H_offdiag(SIZE(blocks(i)%array), SIZE(blocks(j)%array)))
    1838           60 :          ALLOCATE (S_offdiag(SIZE(blocks(i)%array), SIZE(blocks(j)%array)))
    1839           58 :          icol = 0
    1840           58 :          DO k = 1, SIZE(blocks(j)%array)
    1841           38 :             irow = 0
    1842           38 :             icol = icol + 1
    1843          134 :             DO l = 1, SIZE(blocks(i)%array)
    1844           76 :                irow = irow + 1
    1845           76 :                H_offdiag(irow, icol) = mixed_cdft%results%H(blocks(i)%array(l), blocks(j)%array(k))
    1846          114 :                S_offdiag(irow, icol) = mixed_cdft%results%S(blocks(i)%array(l), blocks(j)%array(k))
    1847              :             END DO
    1848              :          END DO
    1849              :          ! Check that none of the interaction energies is repulsive
    1850          134 :          IF (ANY(H_offdiag >= 0.0_dp)) &
    1851              :             CALL cp_abort(__LOCATION__, &
    1852              :                           "At least one of the interaction energies between blocks "//TRIM(ADJUSTL(cp_to_string(i)))// &
    1853            0 :                           " and "//TRIM(ADJUSTL(cp_to_string(j)))//" is repulsive.")
    1854              :          ! Now transform: C_i^T * H * C_j
    1855          952 :          H_offdiag(:, :) = MATMUL(H_offdiag, H_block(j)%array)
    1856          972 :          H_offdiag(:, :) = MATMUL(TRANSPOSE(H_block(i)%array), H_offdiag)
    1857          952 :          S_offdiag(:, :) = MATMUL(S_offdiag, H_block(j)%array)
    1858          972 :          S_offdiag(:, :) = MATMUL(TRANSPOSE(H_block(i)%array), S_offdiag)
    1859              :          ! Make sure the transformation preserves the sign of elements in the S and H matrices
    1860              :          ! The S/H matrices contain only positive/negative values so that any sign flipping occurs in the
    1861              :          ! same elements in both matrices
    1862              :          ! Check for sign flipping using the S matrix
    1863           30 :          IF (ANY(S_offdiag < 0.0_dp)) THEN
    1864           58 :             DO l = 1, SIZE(S_offdiag, 2)
    1865          134 :                DO k = 1, SIZE(S_offdiag, 1)
    1866          114 :                   IF (S_offdiag(k, l) < 0.0_dp) THEN
    1867           36 :                      S_offdiag(k, l) = -1.0_dp*S_offdiag(k, l)
    1868           36 :                      H_offdiag(k, l) = -1.0_dp*H_offdiag(k, l)
    1869              :                   END IF
    1870              :                END DO
    1871              :             END DO
    1872              :          END IF
    1873           20 :          IF (ignore_excited) THEN
    1874           18 :             H_mat(i, j) = H_offdiag(1, 1)
    1875           18 :             H_mat(j, i) = H_mat(i, j)
    1876           18 :             S_mat(i, j) = S_offdiag(1, 1)
    1877           18 :             S_mat(j, i) = S_mat(i, j)
    1878              :          ELSE
    1879            2 :             irow = 1
    1880            2 :             icol = 1
    1881            2 :             DO k = 1, i - 1
    1882            2 :                irow = irow + SIZE(blocks(k)%array)
    1883              :             END DO
    1884            4 :             DO k = 1, j - 1
    1885            4 :                icol = icol + SIZE(blocks(k)%array)
    1886              :             END DO
    1887           14 :             H_mat(irow:irow + SIZE(H_offdiag, 1) - 1, icol:icol + SIZE(H_offdiag, 2) - 1) = H_offdiag(:, :)
    1888           14 :             H_mat(icol:icol + SIZE(H_offdiag, 2) - 1, irow:irow + SIZE(H_offdiag, 1) - 1) = TRANSPOSE(H_offdiag)
    1889           14 :             S_mat(irow:irow + SIZE(H_offdiag, 1) - 1, icol:icol + SIZE(H_offdiag, 2) - 1) = S_offdiag(:, :)
    1890           14 :             S_mat(icol:icol + SIZE(H_offdiag, 2) - 1, irow:irow + SIZE(H_offdiag, 1) - 1) = TRANSPOSE(S_offdiag)
    1891              :          END IF
    1892           20 :          IF (iounit > 0) THEN
    1893           10 :             WRITE (iounit, '(/,T3,A)') REPEAT('#', 39)
    1894           10 :             WRITE (iounit, '(T3,A,I3,A,I3,A)') '###### Blocks I =', i, ' and J = ', j, ' ######'
    1895           10 :             WRITE (iounit, '(T3,A)') REPEAT('#', 39)
    1896           10 :             WRITE (iounit, '(T3,A)') 'Interaction energies'
    1897           21 :             DO irow = 1, SIZE(H_offdiag, 1)
    1898           20 :                ilabel = "(ground state)"
    1899           20 :                IF (irow > 1) THEN
    1900           10 :                   IF (ignore_excited) EXIT
    1901            1 :                   WRITE (tmp, '(I3)') irow - 1
    1902            1 :                   ilabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
    1903              :                END IF
    1904           34 :                DO icol = 1, SIZE(H_offdiag, 2)
    1905           21 :                   jlabel = "(ground state)"
    1906           21 :                   IF (icol > 1) THEN
    1907           10 :                      IF (ignore_excited) EXIT
    1908            2 :                      WRITE (tmp, '(I3)') icol - 1
    1909            2 :                      jlabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
    1910              :                   END IF
    1911           24 :                   WRITE (iounit, '(T6,A,T58,(3X,F20.14))') TRIM(ilabel)//'-'//TRIM(jlabel)//':', H_offdiag(irow, icol)
    1912              :                END DO
    1913              :             END DO
    1914           10 :             WRITE (iounit, '(T3,A)') 'Overlaps'
    1915           21 :             DO irow = 1, SIZE(H_offdiag, 1)
    1916           20 :                ilabel = "(ground state)"
    1917           20 :                IF (irow > 1) THEN
    1918           10 :                   IF (ignore_excited) EXIT
    1919            1 :                   ilabel = "(excited state)"
    1920            1 :                   WRITE (tmp, '(I3)') irow - 1
    1921            1 :                   ilabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
    1922              :                END IF
    1923           34 :                DO icol = 1, SIZE(H_offdiag, 2)
    1924           21 :                   jlabel = "(ground state)"
    1925           21 :                   IF (icol > 1) THEN
    1926           10 :                      IF (ignore_excited) EXIT
    1927            2 :                      WRITE (tmp, '(I3)') icol - 1
    1928            2 :                      jlabel = "(excited state "//TRIM(ADJUSTL(tmp))//")"
    1929              :                   END IF
    1930           24 :                   WRITE (iounit, '(T6,A,T58,(3X,F20.14))') TRIM(ilabel)//'-'//TRIM(jlabel)//':', S_offdiag(irow, icol)
    1931              :                END DO
    1932              :             END DO
    1933              :          END IF
    1934           50 :          DEALLOCATE (H_offdiag, S_offdiag)
    1935              :       END DO
    1936           10 :       CALL mixed_cdft_result_type_set(mixed_cdft%results, H=H_mat, S=S_mat)
    1937              :       ! Deallocate work
    1938           10 :       DEALLOCATE (H_mat, S_mat)
    1939              : 
    1940           10 :    END SUBROUTINE mixed_cdft_assemble_block_diag
    1941              : 
    1942              : END MODULE mixed_cdft_utils
        

Generated by: LCOV version 2.0-1