LCOV - code coverage report
Current view: top level - src - mixed_cdft_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 89.3 % 1039 928
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 12 12

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

Generated by: LCOV version 2.0-1