LCOV - code coverage report
Current view: top level - src - casino_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 89.1 % 727 648
Test Date: 2026-10-15 00:55:44 Functions: 88.9 % 27 24

            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 Writer for CASINO gwfn.data files.
      10              : !> \par History
      11              : !>      05.2026 created [Codex]
      12              : ! **************************************************************************************************
      13              : MODULE casino_utils
      14              : 
      15              :    USE atomic_kind_types,               ONLY: get_atomic_kind
      16              :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      17              :                                               gto_basis_set_type
      18              :    USE cell_types,                      ONLY: cell_type,&
      19              :                                               pbc,&
      20              :                                               pbc_stable,&
      21              :                                               real_to_scaled
      22              :    USE cp2k_info,                       ONLY: cp2k_version
      23              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      24              :    USE cp_cfm_types,                    ONLY: cp_cfm_to_fm
      25              :    USE cp_control_types,                ONLY: dft_control_type
      26              :    USE cp_dbcsr_api,                    ONLY: dbcsr_p_type
      27              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm
      28              :    USE cp_files,                        ONLY: close_file,&
      29              :                                               open_file
      30              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      31              :                                               cp_fm_struct_release,&
      32              :                                               cp_fm_struct_type
      33              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      34              :                                               cp_fm_get_submatrix,&
      35              :                                               cp_fm_release,&
      36              :                                               cp_fm_set_all,&
      37              :                                               cp_fm_to_fm_submat_general,&
      38              :                                               cp_fm_type
      39              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      40              :                                               cp_logger_get_default_io_unit,&
      41              :                                               cp_logger_type
      42              :    USE external_potential_types,        ONLY: get_potential,&
      43              :                                               gth_potential_type,&
      44              :                                               sgp_potential_type
      45              :    USE input_constants,                 ONLY: xc_none
      46              :    USE input_section_types,             ONLY: section_vals_get,&
      47              :                                               section_vals_get_subs_vals,&
      48              :                                               section_vals_type,&
      49              :                                               section_vals_val_get
      50              :    USE kinds,                           ONLY: default_path_length,&
      51              :                                               default_string_length,&
      52              :                                               dp
      53              :    USE kpoint_methods,                  ONLY: kpoint_env_initialize,&
      54              :                                               kpoint_init_cell_index,&
      55              :                                               kpoint_initialize,&
      56              :                                               kpoint_initialize_mo_set,&
      57              :                                               kpoint_initialize_mos
      58              :    USE kpoint_types,                    ONLY: get_kpoint_env,&
      59              :                                               get_kpoint_info,&
      60              :                                               kpoint_create,&
      61              :                                               kpoint_env_p_type,&
      62              :                                               kpoint_release,&
      63              :                                               kpoint_type
      64              :    USE mathconstants,                   ONLY: pi,&
      65              :                                               rootpi
      66              :    USE message_passing,                 ONLY: mp_para_env_type
      67              :    USE orbital_pointers,                ONLY: nso
      68              :    USE particle_types,                  ONLY: particle_type
      69              :    USE qs_environment_types,            ONLY: get_qs_env,&
      70              :                                               qs_environment_type
      71              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      72              :                                               get_qs_kind_set,&
      73              :                                               qs_kind_type
      74              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      75              :                                               mo_set_type
      76              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      77              :    USE qs_scf_diagonalization,          ONLY: do_general_diag_kp
      78              :    USE qs_scf_types,                    ONLY: qs_scf_env_type
      79              :    USE qs_wannier90,                    ONLY: prepare_wannier90_scf_mos
      80              :    USE scf_control_types,               ONLY: scf_control_type
      81              :    USE string_utilities,                ONLY: lowercase
      82              : #include "./base/base_uses.f90"
      83              : 
      84              :    IMPLICIT NONE
      85              : 
      86              :    PRIVATE
      87              : 
      88              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'casino_utils'
      89              :    INTEGER, PARAMETER, PRIVATE          :: max_casino_l = 4
      90              : 
      91              :    PUBLIC :: write_casino
      92              : 
      93              : CONTAINS
      94              : 
      95              : ! **************************************************************************************************
      96              : !> \brief Write a CASINO gwfn.data file from the converged GPW/GAPW wavefunction.
      97              : !> \param qs_env the QS environment
      98              : !> \param casino_section the DFT%PRINT%CASINO input section
      99              : ! **************************************************************************************************
     100           12 :    SUBROUTINE write_casino(qs_env, casino_section)
     101              :       TYPE(qs_environment_type), INTENT(IN), POINTER     :: qs_env
     102              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: casino_section
     103              : 
     104              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'write_casino'
     105              : 
     106              :       CHARACTER(len=default_path_length)                 :: filename
     107              :       INTEGER :: ao_num, col_offset, handle, iao, iatom, ikind, ikp, ikp_loc, ikp_out, imo, ipgf, &
     108              :          iset, ishell, ishell_loc, ispin, iw, k, l, mo_num, nao_shell, natoms, nel_tot, &
     109              :          ngth_pseudo, nkp, nkp_mo, nkp_out, nmo, npseudo_atoms, nreal_k, nset, nsgf, nsgp_pseudo, &
     110              :          nspins, output_unit, periodicity, prim_num, shell_num, xc_shortcut, zatom
     111           12 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: agauge, ao_to_atom, atomic_number, cp2k_to_casino_ao, &
     112           12 :          first_shell, kp_order, prim_per_shell, shell_ang_mom, shell_type
     113              :       INTEGER, DIMENSION(2)                              :: kp_range, nmo_spin
     114           12 :       INTEGER, DIMENSION(:), POINTER                     :: npgf, nshell
     115           12 :       INTEGER, DIMENSION(:, :), POINTER                  :: l_shell_set
     116              :       LOGICAL                                            :: casino_kpoints_created, do_hf, &
     117              :                                                             do_kpoints, ghost_kind, ionode, &
     118              :                                                             periodic, pure_hf, use_real_wfn, &
     119              :                                                             write_pseudos
     120           12 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: kp_real
     121              :       REAL(KIND=dp)                                      :: cval, e_nn, eps_kpoint_real, &
     122              :                                                             hf_fraction, kdotg, pseudo_tol, sval, &
     123              :                                                             zeff
     124           12 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: coefficients, exponents, mo_scale, &
     125           12 :                                                             valence_charge
     126           12 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: coord, kvec, mo_energy, mos_sgf, &
     127           12 :                                                             mos_sgf_im, shell_position
     128              :       REAL(KIND=dp), DIMENSION(3)                        :: r_pbc, scoord, scoord_pbc
     129           12 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp, zetas
     130           12 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: gcc
     131              :       TYPE(cell_type), POINTER                           :: cell
     132              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     133              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     134              :       TYPE(cp_fm_type)                                   :: fm_dummy, fm_mo_coeff, fm_mo_coeff_im, &
     135              :                                                             kp_coeff_im, kp_coeff_re
     136              :       TYPE(cp_logger_type), POINTER                      :: logger
     137              :       TYPE(dft_control_type), POINTER                    :: dft_control
     138              :       TYPE(gth_potential_type), POINTER                  :: gth_potential
     139              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     140           12 :       TYPE(kpoint_env_p_type), DIMENSION(:), POINTER     :: kp_env
     141              :       TYPE(kpoint_type), POINTER                         :: casino_kpoints, kpoints
     142           12 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos, mos_kp
     143              :       TYPE(mp_para_env_type), POINTER                    :: para_env, para_env_inter_kp
     144           12 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     145           12 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: kind_set
     146              :       TYPE(section_vals_type), POINTER                   :: hf_section, input, xc_section
     147              :       TYPE(sgp_potential_type), POINTER                  :: sgp_potential
     148              : 
     149           12 :       CALL timeset(routineN, handle)
     150              : 
     151           12 :       NULLIFY (basis_set, blacs_env, casino_kpoints, cell, dft_control, fm_struct, gcc, &
     152           12 :                gth_potential, kind_set, kp_env, kpoints, l_shell_set, logger, mos, mos_kp, npgf, &
     153           12 :                nshell, para_env, para_env_inter_kp, particle_set, sgp_potential, xkp, zetas)
     154              : 
     155           12 :       logger => cp_get_default_logger()
     156           12 :       output_unit = cp_logger_get_default_io_unit(logger)
     157              : 
     158           12 :       CPASSERT(ASSOCIATED(qs_env))
     159              : 
     160           12 :       CALL section_vals_val_get(casino_section, "FILENAME", c_val=filename)
     161           12 :       IF (LEN_TRIM(filename) == 0) filename = "gwfn.data"
     162           12 :       CALL section_vals_val_get(casino_section, "EPS_KPOINT_REAL", r_val=eps_kpoint_real)
     163           12 :       CALL section_vals_val_get(casino_section, "WRITE_PSEUDOPOTENTIALS", l_val=write_pseudos)
     164              : 
     165           12 :       CALL get_qs_env(qs_env, para_env=para_env)
     166           12 :       ionode = para_env%is_source()
     167              : 
     168              :       CALL get_qs_env(qs_env, cell=cell, particle_set=particle_set, qs_kind_set=kind_set, &
     169              :                       natom=natoms, dft_control=dft_control, nelectron_total=nel_tot, &
     170           12 :                       do_kpoints=do_kpoints, kpoints=kpoints, blacs_env=blacs_env)
     171           12 :       casino_kpoints => kpoints
     172              :       casino_kpoints_created = .FALSE.
     173              :       CALL prepare_casino_kpoint_grid(qs_env, casino_section, do_kpoints, kpoints, &
     174           12 :                                       casino_kpoints, casino_kpoints_created)
     175           12 :       nspins = dft_control%nspins
     176           12 :       IF (nspins > 2) CPABORT("CASINO gwfn.data supports at most two spin channels.")
     177              : 
     178              :       ! label the reference method in the header: pure Hartree-Fock or DFT
     179           12 :       CALL get_qs_env(qs_env, input=input)
     180           12 :       xc_section => section_vals_get_subs_vals(input, "DFT%XC")
     181           12 :       hf_section => section_vals_get_subs_vals(xc_section, "HF")
     182           12 :       CALL section_vals_get(hf_section, explicit=do_hf)
     183           12 :       hf_fraction = 0.0_dp
     184           12 :       IF (do_hf) CALL section_vals_val_get(hf_section, "FRACTION", r_val=hf_fraction)
     185           12 :       CALL section_vals_val_get(xc_section, "XC_FUNCTIONAL%_SECTION_PARAMETERS_", i_val=xc_shortcut)
     186           12 :       pure_hf = do_hf .AND. ABS(hf_fraction - 1.0_dp) < 1.0E-12_dp .AND. xc_shortcut == xc_none
     187              : 
     188           48 :       periodicity = COUNT(cell%perd /= 0)
     189           12 :       periodic = periodicity > 0
     190           12 :       pseudo_tol = 1.0E-8_dp
     191              : 
     192           84 :       ALLOCATE (coord(3, natoms), atomic_number(natoms), valence_charge(natoms))
     193           12 :       npseudo_atoms = 0
     194           12 :       ngth_pseudo = 0
     195           12 :       nsgp_pseudo = 0
     196           36 :       DO iatom = 1, natoms
     197           96 :          coord(:, iatom) = particle_set(iatom)%r(1:3)
     198           24 :          CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
     199              :          CALL get_qs_kind(kind_set(ikind), zatom=zatom, zeff=zeff, ghost=ghost_kind, &
     200           24 :                           gth_potential=gth_potential, sgp_potential=sgp_potential)
     201           24 :          IF (ghost_kind) THEN
     202              :             ! CASINO convention for floating Gaussians: a "ghost nucleus" with charge zero
     203            2 :             atomic_number(iatom) = 0
     204            2 :             valence_charge(iatom) = 0.0_dp
     205            2 :             CYCLE
     206              :          END IF
     207           22 :          IF (ABS(zeff) < pseudo_tol) zeff = REAL(zatom, KIND=dp)
     208           22 :          atomic_number(iatom) = zatom
     209           22 :          IF (ASSOCIATED(gth_potential) .OR. ASSOCIATED(sgp_potential)) THEN
     210           12 :             atomic_number(iatom) = zatom + 200
     211           12 :             npseudo_atoms = npseudo_atoms + 1
     212           12 :             IF (ASSOCIATED(gth_potential)) ngth_pseudo = ngth_pseudo + 1
     213           12 :             IF (ASSOCIATED(sgp_potential)) nsgp_pseudo = nsgp_pseudo + 1
     214           10 :          ELSE IF (ABS(zeff - REAL(zatom, KIND=dp)) > pseudo_tol) THEN
     215            0 :             atomic_number(iatom) = zatom + 200
     216            0 :             npseudo_atoms = npseudo_atoms + 1
     217              :          END IF
     218           58 :          valence_charge(iatom) = zeff
     219              :       END DO
     220              : 
     221           12 :       IF (ionode .AND. write_pseudos .AND. nsgp_pseudo > 0) THEN
     222            2 :          CALL write_casino_sgp_pseudopotentials(kind_set, particle_set, natoms, filename, output_unit)
     223              :       END IF
     224              : 
     225           12 :       IF (periodic) THEN
     226            2 :          CALL periodic_nuclear_repulsion_energy(cell, periodicity, coord, valence_charge, e_nn)
     227              :       ELSE
     228           10 :          CALL nuclear_repulsion_energy(particle_set, kind_set, e_nn)
     229              :       END IF
     230           12 :       e_nn = e_nn/REAL(natoms, KIND=dp)
     231              : 
     232           12 :       IF (do_kpoints) THEN
     233            2 :          CALL get_kpoint_info(casino_kpoints, nkp=nkp, xkp=xkp, use_real_wfn=use_real_wfn)
     234              :       ELSE
     235           10 :          nkp = 1
     236           10 :          use_real_wfn = .TRUE.
     237              :       END IF
     238           12 :       nkp_mo = MERGE(nkp, 1, do_kpoints)
     239              : 
     240           72 :       ALLOCATE (kp_order(nkp_mo), kp_real(nkp_mo), kvec(3, nkp_mo))
     241              :       CALL build_kpoint_order(cell, periodic, do_kpoints, nkp, xkp, eps_kpoint_real, &
     242           12 :                               kp_order, kp_real, nkp_out, nreal_k, kvec)
     243           22 :       IF (do_kpoints .AND. use_real_wfn .AND. ANY(.NOT. kp_real(1:nkp_out))) THEN
     244            0 :          CPABORT("CASINO complex k-points require CP2K complex k-point wavefunctions.")
     245              :       END IF
     246              : 
     247           12 :       CALL get_qs_kind_set(kind_set, nshell=shell_num, npgf_seg=prim_num, nsgf=nsgf)
     248           12 :       ao_num = nsgf
     249              : 
     250            0 :       ALLOCATE (shell_type(shell_num), prim_per_shell(shell_num), first_shell(natoms + 1), &
     251            0 :                 shell_ang_mom(shell_num), shell_position(3, shell_num), &
     252            0 :                 exponents(prim_num), coefficients(prim_num), ao_to_atom(ao_num), &
     253          204 :                 cp2k_to_casino_ao(ao_num), mo_scale(ao_num))
     254              : 
     255           12 :       ishell = 0
     256           12 :       ipgf = 0
     257           12 :       iao = 0
     258           36 :       DO iatom = 1, natoms
     259           24 :          first_shell(iatom) = ishell + 1
     260           24 :          CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
     261           24 :          CALL get_qs_kind(kind_set(ikind), basis_set=basis_set, basis_type="ORB")
     262              :          CALL get_gto_basis_set(basis_set, nset=nset, nshell=nshell, npgf=npgf, &
     263           24 :                                 zet=zetas, gcc=gcc, l=l_shell_set)
     264           94 :          DO iset = 1, nset
     265          110 :             DO ishell_loc = 1, nshell(iset)
     266           52 :                ishell = ishell + 1
     267           52 :                l = l_shell_set(ishell_loc, iset)
     268           52 :                IF (l > max_casino_l) THEN
     269            0 :                   CPABORT("CASINO writer currently supports harmonic Gaussian shells up to g.")
     270              :                END IF
     271              :                ! CASINO's periodic Gaussian evaluator handles s, sp, p, d and f shells only
     272           52 :                IF (periodic .AND. l > 3) THEN
     273            0 :                   CPABORT("CASINO cannot evaluate g shells in periodic Gaussian calculations.")
     274              :                END IF
     275           52 :                shell_ang_mom(ishell) = l
     276           52 :                shell_type(ishell) = casino_shell_type(l)
     277           52 :                prim_per_shell(ishell) = npgf(iset)
     278          208 :                shell_position(:, ishell) = particle_set(iatom)%r(1:3)
     279              :                CALL casino_shell_coefficients(l, npgf(iset), zetas(1:npgf(iset), iset), &
     280              :                                               gcc(1:npgf(iset), ishell_loc, iset), &
     281              :                                               exponents(ipgf + 1:ipgf + npgf(iset)), &
     282           52 :                                               coefficients(ipgf + 1:ipgf + npgf(iset)))
     283           52 :                nao_shell = nso(l)
     284          112 :                DO k = 1, nao_shell
     285           60 :                   cp2k_to_casino_ao(iao + k) = iao + casino_cp2k_index(l, k)
     286           60 :                   mo_scale(iao + k) = casino_mo_scale(l, k)
     287          112 :                   ao_to_atom(iao + k) = iatom
     288              :                END DO
     289           52 :                ipgf = ipgf + npgf(iset)
     290           86 :                iao = iao + nao_shell
     291              :             END DO
     292              :          END DO
     293              :       END DO
     294           12 :       first_shell(natoms + 1) = shell_num + 1
     295           12 :       CPASSERT(ishell == shell_num)
     296           12 :       CPASSERT(ipgf == prim_num)
     297           12 :       CPASSERT(iao == ao_num)
     298              : 
     299           48 :       ALLOCATE (mo_energy(ao_num, nkp_mo*nspins))
     300           12 :       mo_energy(:, :) = 0.0_dp
     301           12 :       nmo_spin(:) = 0
     302              : 
     303           12 :       IF (do_kpoints) THEN
     304            2 :          CALL get_kpoint_info(casino_kpoints, kp_env=kp_env, kp_range=kp_range, nkp=nkp)
     305            2 :          CALL get_kpoint_env(kp_env(1)%kpoint_env, mos=mos_kp)
     306            4 :          DO ispin = 1, nspins
     307            2 :             CALL get_mo_set(mos_kp(ispin), nmo=nmo)
     308            2 :             IF (nmo < ao_num) THEN
     309            0 :                CPABORT("CASINO gwfn.data requires a complete MO set. Increase ADDED_MOS.")
     310              :             END IF
     311            6 :             nmo_spin(ispin) = nmo
     312              :          END DO
     313            6 :          mo_num = nkp*SUM(nmo_spin)
     314              :          CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
     315            2 :                                   nrow_global=nsgf, ncol_global=mo_num)
     316            2 :          CALL cp_fm_create(fm_mo_coeff, fm_struct)
     317            2 :          CALL cp_fm_set_all(fm_mo_coeff, 0.0_dp)
     318            2 :          IF (.NOT. use_real_wfn) THEN
     319            2 :             CALL cp_fm_create(fm_mo_coeff_im, fm_struct)
     320            2 :             CALL cp_fm_set_all(fm_mo_coeff_im, 0.0_dp)
     321            2 :             CALL cp_fm_create(kp_coeff_re, mos_kp(1)%cmo_coeff%matrix_struct)
     322            2 :             CALL cp_fm_create(kp_coeff_im, mos_kp(1)%cmo_coeff%matrix_struct)
     323              :          END IF
     324            2 :          CALL cp_fm_struct_release(fm_struct)
     325              : 
     326            4 :          DO ispin = 1, nspins
     327            8 :             DO ikp = 1, nkp
     328            4 :                nmo = nmo_spin(ispin)
     329            4 :                col_offset = (ikp - 1)*nmo + (ispin - 1)*nmo_spin(1)*nkp
     330            6 :                IF (ikp >= kp_range(1) .AND. ikp <= kp_range(2)) THEN
     331            4 :                   ikp_loc = ikp - kp_range(1) + 1
     332            4 :                   CALL get_kpoint_env(kp_env(ikp_loc)%kpoint_env, mos=mos_kp)
     333            4 :                   IF (use_real_wfn) THEN
     334            0 :                      IF (mos_kp(ispin)%use_mo_coeff_b) THEN
     335            0 :                         CALL copy_dbcsr_to_fm(mos_kp(ispin)%mo_coeff_b, mos_kp(ispin)%mo_coeff)
     336              :                      END IF
     337              :                   ELSE
     338            4 :                      CALL cp_cfm_to_fm(mos_kp(ispin)%cmo_coeff, kp_coeff_re, kp_coeff_im)
     339              :                   END IF
     340            4 :                   IF (use_real_wfn) THEN
     341              :                      CALL cp_fm_to_fm_submat_general(mos_kp(ispin)%mo_coeff, fm_mo_coeff, &
     342            0 :                                                      nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
     343              :                   ELSE
     344              :                      CALL cp_fm_to_fm_submat_general(kp_coeff_re, fm_mo_coeff, &
     345            4 :                                                      nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
     346              :                   END IF
     347              :                   mo_energy(1:ao_num, ikp + (ispin - 1)*nkp_mo) = &
     348           20 :                      mos_kp(ispin)%eigenvalues(1:ao_num)
     349            4 :                   IF (.NOT. use_real_wfn) THEN
     350              :                      CALL cp_fm_to_fm_submat_general(kp_coeff_im, fm_mo_coeff_im, &
     351            4 :                                                      nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
     352              :                   END IF
     353              :                ELSE
     354              :                   CALL cp_fm_to_fm_submat_general(fm_dummy, fm_mo_coeff, &
     355            0 :                                                   nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
     356            0 :                   IF (.NOT. use_real_wfn) THEN
     357              :                      CALL cp_fm_to_fm_submat_general(fm_dummy, fm_mo_coeff_im, &
     358            0 :                                                      nsgf, nmo, 1, 1, 1, col_offset + 1, blacs_env)
     359              :                   END IF
     360              :                END IF
     361              :             END DO
     362              :          END DO
     363            2 :          CALL get_kpoint_info(casino_kpoints, para_env_inter_kp=para_env_inter_kp)
     364            2 :          CALL para_env_inter_kp%sum(mo_energy)
     365              :       ELSE
     366           10 :          CALL get_qs_env(qs_env, mos=mos)
     367           22 :          DO ispin = 1, nspins
     368           12 :             CALL get_mo_set(mos(ispin), nmo=nmo)
     369           12 :             IF (nmo < ao_num) THEN
     370            0 :                CPABORT("CASINO gwfn.data requires a complete MO set. Increase ADDED_MOS.")
     371              :             END IF
     372           12 :             nmo_spin(ispin) = nmo
     373           90 :             mo_energy(1:ao_num, 1 + (ispin - 1)*nkp_mo) = mos(ispin)%eigenvalues(1:ao_num)
     374              :          END DO
     375              :       END IF
     376              : 
     377           12 :       IF (do_kpoints .AND. .NOT. use_real_wfn) THEN
     378            6 :          ALLOCATE (agauge(3*natoms))
     379            6 :          DO iatom = 1, natoms
     380            4 :             CALL real_to_scaled(scoord, particle_set(iatom)%r(1:3), cell)
     381            4 :             IF (kpoints%symmetry) THEN
     382            4 :                r_pbc = pbc_stable(particle_set(iatom)%r(1:3), cell)
     383              :             ELSE
     384            0 :                r_pbc = pbc(particle_set(iatom)%r(1:3), cell)
     385              :             END IF
     386            4 :             CALL real_to_scaled(scoord_pbc, r_pbc, cell)
     387           18 :             agauge(3*(iatom - 1) + 1:3*iatom) = NINT(scoord_pbc - scoord)
     388              :          END DO
     389              :       END IF
     390              : 
     391           12 :       IF (ionode) THEN
     392            6 :          IF (npseudo_atoms > 0) THEN
     393            3 :             WRITE (output_unit, "((T2,A,I0,A))") "CASINO| Marked ", npseudo_atoms, &
     394            6 :                " pseudopotential atoms in gwfn.data."
     395            3 :             IF (ngth_pseudo > 0) THEN
     396              :                WRITE (output_unit, "((T2,A))") &
     397            1 :                   "CASINO| GTH pseudopotentials require matching external CASINO *_pp.data files."
     398              :             END IF
     399            3 :             IF (.NOT. write_pseudos) THEN
     400              :                WRITE (output_unit, "((T2,A))") &
     401            1 :                   "CASINO| WRITE_PSEUDOPOTENTIALS is disabled; provide CASINO *_pp.data files manually."
     402              :             END IF
     403              :          END IF
     404            6 :          WRITE (output_unit, "((T2,A,A))") 'CASINO| Writing gwfn.data file ', TRIM(filename)
     405              :          CALL open_file(file_name=filename, file_status="REPLACE", file_action="WRITE", &
     406            6 :                         file_form="FORMATTED", unit_number=iw)
     407              :          CALL write_casino_header(iw, pure_hf, periodicity, nspins, e_nn, nel_tot, natoms, coord, &
     408              :                                   atomic_number, valence_charge, cell, periodic, nkp_out, nreal_k, &
     409              :                                   kvec, shell_num, ao_num, prim_num, shell_ang_mom, shell_type, &
     410            6 :                                   prim_per_shell, first_shell, exponents, coefficients, shell_position)
     411              :       END IF
     412              : 
     413           72 :       ALLOCATE (mos_sgf(nsgf, ao_num), mos_sgf_im(nsgf, ao_num))
     414           12 :       mos_sgf(:, :) = 0.0_dp
     415           12 :       mos_sgf_im(:, :) = 0.0_dp
     416              : 
     417           12 :       IF (do_kpoints) THEN
     418            4 :          DO ispin = 1, nspins
     419            6 :             DO ikp_out = 1, nkp_out
     420            2 :                ikp = kp_order(ikp_out)
     421            2 :                col_offset = (ikp - 1)*nmo_spin(ispin) + (ispin - 1)*nmo_spin(1)*nkp
     422            2 :                CALL cp_fm_get_submatrix(fm_mo_coeff, mos_sgf, 1, col_offset + 1, nsgf, ao_num)
     423            2 :                IF (.NOT. use_real_wfn) THEN
     424            2 :                   CALL cp_fm_get_submatrix(fm_mo_coeff_im, mos_sgf_im, 1, col_offset + 1, nsgf, ao_num)
     425           10 :                   DO iao = 1, ao_num
     426            8 :                      iatom = ao_to_atom(iao)
     427              :                      kdotg = 2.0_dp*pi*DOT_PRODUCT(xkp(:, ikp), &
     428           32 :                                                    REAL(agauge(3*(iatom - 1) + 1:3*iatom), KIND=dp))
     429            8 :                      cval = COS(kdotg)
     430            8 :                      sval = SIN(kdotg)
     431           42 :                      DO imo = 1, ao_num
     432              :                         CALL rotate_complex_pair(mos_sgf(cp2k_to_casino_ao(iao), imo), &
     433           40 :                                                  mos_sgf_im(cp2k_to_casino_ao(iao), imo), cval, sval)
     434              :                      END DO
     435              :                   END DO
     436              :                ELSE
     437            0 :                   mos_sgf_im(:, :) = 0.0_dp
     438              :                END IF
     439            4 :                IF (ionode) THEN
     440              :                   CALL write_casino_orbitals(iw, mos_sgf, mos_sgf_im, cp2k_to_casino_ao, mo_scale, &
     441            1 :                                              ao_num,.NOT. kp_real(ikp_out))
     442              :                END IF
     443              :             END DO
     444              :          END DO
     445              :       ELSE
     446           22 :          DO ispin = 1, nspins
     447           12 :             IF (mos(ispin)%use_mo_coeff_b) THEN
     448            0 :                CALL copy_dbcsr_to_fm(mos(ispin)%mo_coeff_b, mos(ispin)%mo_coeff)
     449              :             END IF
     450           12 :             CALL cp_fm_get_submatrix(mos(ispin)%mo_coeff, mos_sgf, 1, 1, nsgf, ao_num)
     451           12 :             mos_sgf_im(:, :) = 0.0_dp
     452           22 :             IF (ionode) THEN
     453              :                CALL write_casino_orbitals(iw, mos_sgf, mos_sgf_im, cp2k_to_casino_ao, mo_scale, &
     454            6 :                                           ao_num, .FALSE.)
     455              :             END IF
     456              :          END DO
     457              :       END IF
     458              : 
     459           12 :       IF (ionode) THEN
     460            6 :          WRITE (iw, *)
     461            6 :          IF (periodic) THEN
     462            1 :             WRITE (iw, '(A)') "EIGENVALUES"
     463            1 :             WRITE (iw, '(A)') "-----------"
     464            2 :             DO ikp_out = 1, nkp_out
     465            1 :                ikp = kp_order(ikp_out)
     466            3 :                DO ispin = 1, nspins
     467            1 :                   IF (nspins == 1) THEN
     468            1 :                      WRITE (iw, '(A,I6,3F14.8)') "k", ikp_out, kvec(:, ikp_out)
     469              :                   ELSE
     470            0 :                      WRITE (iw, '(A,I3,A,I6,3F14.8)') "spin", ispin, " k", ikp_out, kvec(:, ikp_out)
     471              :                   END IF
     472            2 :                   CALL write_real_vector(iw, mo_energy(1:ao_num, ikp + (ispin - 1)*nkp_mo))
     473              :                END DO
     474              :             END DO
     475              :          END IF
     476            6 :          CALL close_file(unit_number=iw)
     477              :       END IF
     478              : 
     479           12 :       DEALLOCATE (mos_sgf, mos_sgf_im)
     480           12 :       IF (do_kpoints) THEN
     481            2 :          CALL cp_fm_release(fm_mo_coeff)
     482            2 :          IF (.NOT. use_real_wfn) THEN
     483            2 :             CALL cp_fm_release(fm_mo_coeff_im)
     484            2 :             CALL cp_fm_release(kp_coeff_re)
     485            2 :             CALL cp_fm_release(kp_coeff_im)
     486              :          END IF
     487              :       END IF
     488           12 :       IF (casino_kpoints_created) CALL kpoint_release(casino_kpoints)
     489           12 :       IF (ALLOCATED(agauge)) DEALLOCATE (agauge)
     490            0 :       DEALLOCATE (ao_to_atom, atomic_number, coefficients, coord, cp2k_to_casino_ao, exponents, &
     491            0 :                   first_shell, kp_order, kp_real, kvec, mo_energy, mo_scale, prim_per_shell, &
     492           12 :                   shell_ang_mom, shell_position, shell_type, valence_charge)
     493              : 
     494           12 :       CALL timestop(handle)
     495           96 :    END SUBROUTINE write_casino
     496              : 
     497              : ! **************************************************************************************************
     498              : !> \brief Write CASINO pseudopotential files for the semilocal ECP kinds.
     499              : !> \param kind_set the QS kinds
     500              : !> \param particle_set the particle set
     501              : !> \param natoms the number of atoms
     502              : !> \param gwfn_filename the gwfn.data filename
     503              : !> \param output_unit output unit for log messages
     504              : ! **************************************************************************************************
     505            2 :    SUBROUTINE write_casino_sgp_pseudopotentials(kind_set, particle_set, natoms, gwfn_filename, output_unit)
     506              :       TYPE(qs_kind_type), DIMENSION(:), INTENT(IN), &
     507              :          POINTER                                         :: kind_set
     508              :       TYPE(particle_type), DIMENSION(:), INTENT(IN), &
     509              :          POINTER                                         :: particle_set
     510              :       INTEGER, INTENT(IN)                                :: natoms
     511              :       CHARACTER(LEN=*), INTENT(IN)                       :: gwfn_filename
     512              :       INTEGER, INTENT(IN)                                :: output_unit
     513              : 
     514              :       CHARACTER(LEN=2)                                   :: element_symbol
     515              :       INTEGER                                            :: iatom, ikind, zatom
     516            2 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: written
     517              :       REAL(KIND=dp)                                      :: zeff
     518              :       TYPE(sgp_potential_type), POINTER                  :: sgp_potential
     519              : 
     520            2 :       NULLIFY (sgp_potential)
     521            6 :       ALLOCATE (written(SIZE(kind_set)))
     522            2 :       written(:) = .FALSE.
     523              : 
     524            7 :       DO iatom = 1, natoms
     525              :          CALL get_atomic_kind(particle_set(iatom)%atomic_kind, element_symbol=element_symbol, &
     526            5 :                               kind_number=ikind, z=zatom)
     527            5 :          IF (written(ikind)) CYCLE
     528              : 
     529            3 :          CALL get_qs_kind(kind_set(ikind), sgp_potential=sgp_potential, zeff=zeff)
     530           10 :          IF (ASSOCIATED(sgp_potential)) THEN
     531            2 :             IF (ABS(zeff) < 1.0E-8_dp) zeff = REAL(zatom, KIND=dp)
     532              :             CALL write_casino_sgp_pseudopotential(sgp_potential, element_symbol, zatom, zeff, &
     533            2 :                                                   gwfn_filename, output_unit)
     534            2 :             written(ikind) = .TRUE.
     535              :          END IF
     536              :       END DO
     537              : 
     538            2 :       DEALLOCATE (written)
     539            2 :    END SUBROUTINE write_casino_sgp_pseudopotentials
     540              : 
     541              : ! **************************************************************************************************
     542              : !> \brief Write a CASINO tabulated pseudopotential for a CP2K semilocal ECP.
     543              : !> \param sgp_potential the CP2K semilocal Gaussian potential
     544              : !> \param element_symbol the chemical symbol
     545              : !> \param zatom the nuclear charge
     546              : !> \param zeff the ECP valence charge
     547              : !> \param gwfn_filename the gwfn.data filename
     548              : !> \param output_unit output unit for log messages
     549              : ! **************************************************************************************************
     550            2 :    SUBROUTINE write_casino_sgp_pseudopotential(sgp_potential, element_symbol, zatom, zeff, &
     551              :                                                gwfn_filename, output_unit)
     552              :       TYPE(sgp_potential_type), INTENT(IN), POINTER      :: sgp_potential
     553              :       CHARACTER(LEN=*), INTENT(IN)                       :: element_symbol
     554              :       INTEGER, INTENT(IN)                                :: zatom
     555              :       REAL(KIND=dp), INTENT(IN)                          :: zeff
     556              :       CHARACTER(LEN=*), INTENT(IN)                       :: gwfn_filename
     557              :       INTEGER, INTENT(IN)                                :: output_unit
     558              : 
     559              :       CHARACTER(LEN=default_path_length)                 :: pp_filename
     560              :       INTEGER                                            :: igrid, iw, l, local_l, ngrid, nloc, &
     561              :                                                             nsemiloc, sl_lmax
     562              :       INTEGER, DIMENSION(0:10)                           :: npot
     563              :       LOGICAL                                            :: ecp_local, ecp_semi_local, has_nlcc
     564              :       REAL(KIND=dp)                                      :: agrid, bgrid, r, rmax, rv_local
     565            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: rgrid
     566            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: rpot
     567              : 
     568              :       CALL get_potential(potential=sgp_potential, ecp_local=ecp_local, &
     569              :                          ecp_semi_local=ecp_semi_local, nloc=nloc, sl_lmax=sl_lmax, &
     570            2 :                          npot=npot, has_nlcc=has_nlcc)
     571            2 :       IF (.NOT. ecp_local .OR. nloc == 0) THEN
     572            0 :          WRITE (output_unit, "((T2,A,A,A))") "CASINO| Cannot write ", TRIM(element_symbol), &
     573            0 :             "_pp.data: only CP2K semilocal ECP potentials are supported."
     574              :          RETURN
     575              :       END IF
     576              : 
     577            2 :       local_l = MERGE(sl_lmax + 1, 0, ecp_semi_local)
     578            2 :       rmax = 100.0_dp
     579            2 :       agrid = 70.0_dp*EXP(-5.0_dp*LOG(10.0_dp))/REAL(zatom, KIND=dp)
     580            2 :       bgrid = 1.0_dp/70.0_dp
     581              : 
     582            2 :       ngrid = 0
     583         1662 :       DO
     584         1664 :          r = agrid*(EXP(bgrid*REAL(ngrid, KIND=dp)) - 1.0_dp)
     585         1664 :          IF (r > rmax) EXIT
     586         1662 :          ngrid = ngrid + 1
     587              :       END DO
     588              : 
     589           12 :       ALLOCATE (rgrid(ngrid), rpot(0:local_l, ngrid))
     590         1664 :       DO igrid = 1, ngrid
     591         1662 :          r = agrid*(EXP(bgrid*REAL(igrid - 1, KIND=dp)) - 1.0_dp)
     592         1662 :          rgrid(igrid) = r
     593              :          rv_local = casino_sgp_r_times_v(nloc, sgp_potential%nrloc(1:nloc), &
     594              :                                          sgp_potential%bloc(1:nloc), &
     595         1662 :                                          sgp_potential%aloc(1:nloc), r, zeff, .TRUE.)
     596         4988 :          DO l = 0, local_l
     597         3324 :             rpot(l, igrid) = rv_local
     598         4986 :             IF (l < local_l .AND. ecp_semi_local) THEN
     599         1662 :                nsemiloc = npot(l)
     600         1662 :                IF (nsemiloc > 0) THEN
     601              :                   rpot(l, igrid) = rpot(l, igrid) + &
     602              :                                    casino_sgp_r_times_v(nsemiloc, sgp_potential%nrpot(1:nsemiloc, l), &
     603              :                                                         sgp_potential%bpot(1:nsemiloc, l), &
     604         1662 :                                                         sgp_potential%apot(1:nsemiloc, l), r, zeff, .FALSE.)
     605              :                END IF
     606              :             END IF
     607              :          END DO
     608              :       END DO
     609         4988 :       rpot(:, :) = 2.0_dp*rpot(:, :)
     610              : 
     611            2 :       CALL casino_pp_filename(gwfn_filename, element_symbol, pp_filename)
     612              :       CALL open_file(file_name=pp_filename, file_status="REPLACE", file_action="WRITE", &
     613            2 :                      file_form="FORMATTED", unit_number=iw)
     614            2 :       WRITE (iw, '(A)') "CP2K ECP pseudopotential in real space"
     615            2 :       WRITE (iw, '(A)') "Atomic number and pseudo-charge"
     616            2 :       WRITE (iw, '(I6,1X,F18.10)') zatom, zeff
     617            2 :       WRITE (iw, '(A)') "Energy units (rydberg/hartree/ev):"
     618            2 :       WRITE (iw, '(A)') "rydberg"
     619            2 :       WRITE (iw, '(A)') "Angular momentum of local component (0=s,1=p,2=d..)"
     620            2 :       WRITE (iw, '(I6)') local_l
     621            2 :       WRITE (iw, '(A)') "NLRULE override (1) VMC/DMC (2) config gen (0 ==> input/default value)"
     622            2 :       WRITE (iw, '(2I6)') 0, 0
     623            2 :       WRITE (iw, '(A)') "Number of grid points"
     624            2 :       WRITE (iw, '(I8)') ngrid
     625            2 :       WRITE (iw, '(A)') "R(i) in atomic units"
     626         1664 :       DO igrid = 1, ngrid
     627         1664 :          WRITE (iw, '(ES20.12)') rgrid(igrid)
     628              :       END DO
     629            6 :       DO l = 0, local_l
     630            4 :          WRITE (iw, '(A,I0,A)') "r*potential (L=", l, ") in Ry"
     631         3330 :          DO igrid = 1, ngrid
     632         3328 :             WRITE (iw, '(ES20.12)') rpot(l, igrid)
     633              :          END DO
     634              :       END DO
     635            2 :       CALL close_file(unit_number=iw)
     636              : 
     637            2 :       WRITE (output_unit, "((T2,A,A))") "CASINO| Wrote pseudopotential file ", TRIM(pp_filename)
     638            2 :       IF (has_nlcc) THEN
     639            0 :          WRITE (output_unit, "((T2,A,A,A))") "CASINO| NLCC terms for ", TRIM(element_symbol), &
     640            0 :             " are not represented in CASINO *_pp.data."
     641              :       END IF
     642              : 
     643            2 :       DEALLOCATE (rgrid, rpot)
     644            4 :    END SUBROUTINE write_casino_sgp_pseudopotential
     645              : 
     646              : ! **************************************************************************************************
     647              : !> \brief Return r times a CP2K semilocal Gaussian ECP channel in Hartree.
     648              : !> \param nterm the number of Gaussian terms
     649              : !> \param nr the CP2K r**(n-2) exponents
     650              : !> \param gaussian_exponent the Gaussian exponents
     651              : !> \param coefficient the Gaussian coefficients
     652              : !> \param r the radial grid point
     653              : !> \param zeff the ECP valence charge
     654              : !> \param local_channel true for the local Coulomb-tailed channel
     655              : !> \return r times the potential value
     656              : ! **************************************************************************************************
     657         3324 :    FUNCTION casino_sgp_r_times_v(nterm, nr, gaussian_exponent, coefficient, r, zeff, local_channel) RESULT(r_times_v)
     658              :       INTEGER, INTENT(IN)                                :: nterm
     659              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nr
     660              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: gaussian_exponent, coefficient
     661              :       REAL(KIND=dp), INTENT(IN)                          :: r, zeff
     662              :       LOGICAL, INTENT(IN)                                :: local_channel
     663              :       REAL(KIND=dp)                                      :: r_times_v
     664              : 
     665              :       INTEGER                                            :: iterm
     666              : 
     667         3324 :       IF (r == 0.0_dp) THEN
     668         3324 :          r_times_v = 0.0_dp
     669              :          RETURN
     670              :       END IF
     671              : 
     672         3320 :       r_times_v = 0.0_dp
     673         3320 :       IF (local_channel) r_times_v = -zeff
     674         9960 :       DO iterm = 1, nterm
     675         6640 :          CPASSERT(nr(iterm) >= 1)
     676              :          r_times_v = r_times_v + coefficient(iterm)*r**(nr(iterm) - 1)* &
     677         9960 :                      EXP(-gaussian_exponent(iterm)*r*r)
     678              :       END DO
     679              :    END FUNCTION casino_sgp_r_times_v
     680              : 
     681              : ! **************************************************************************************************
     682              : !> \brief Build the CASINO pseudopotential filename next to gwfn.data.
     683              : !> \param gwfn_filename the gwfn.data filename
     684              : !> \param element_symbol the chemical symbol
     685              : !> \param pp_filename the CASINO pseudopotential filename
     686              : ! **************************************************************************************************
     687            2 :    SUBROUTINE casino_pp_filename(gwfn_filename, element_symbol, pp_filename)
     688              :       CHARACTER(LEN=*), INTENT(IN)                       :: gwfn_filename, element_symbol
     689              :       CHARACTER(LEN=*), INTENT(OUT)                      :: pp_filename
     690              : 
     691              :       CHARACTER(LEN=2)                                   :: symbol
     692              :       INTEGER                                            :: slash
     693              : 
     694            2 :       symbol = ADJUSTL(element_symbol)
     695            2 :       CALL lowercase(symbol)
     696            2 :       slash = INDEX(TRIM(gwfn_filename), "/", BACK=.TRUE.)
     697            2 :       IF (slash > 0) THEN
     698            0 :          pp_filename = gwfn_filename(1:slash)//TRIM(symbol)//"_pp.data"
     699              :       ELSE
     700            2 :          pp_filename = TRIM(symbol)//"_pp.data"
     701              :       END IF
     702            2 :    END SUBROUTINE casino_pp_filename
     703              : 
     704              : ! **************************************************************************************************
     705              : !> \brief Prepare the k-point object used for CASINO export.
     706              : !> \param qs_env the QS environment
     707              : !> \param casino_section the CASINO print section
     708              : !> \param do_kpoints true when the SCF used k-points
     709              : !> \param kpoints_scf the converged SCF k-point object
     710              : !> \param kpoints_out the k-point object to write
     711              : !> \param created true if kpoints_out must be released by the caller
     712              : ! **************************************************************************************************
     713           16 :    SUBROUTINE prepare_casino_kpoint_grid(qs_env, casino_section, do_kpoints, kpoints_scf, &
     714              :                                          kpoints_out, created)
     715              :       TYPE(qs_environment_type), INTENT(IN), POINTER     :: qs_env
     716              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: casino_section
     717              :       LOGICAL, INTENT(IN)                                :: do_kpoints
     718              :       TYPE(kpoint_type), POINTER                         :: kpoints_scf, kpoints_out
     719              :       LOGICAL, INTENT(OUT)                               :: created
     720              : 
     721              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'prepare_casino_kpoint_grid'
     722              : 
     723              :       CHARACTER(LEN=default_string_length)               :: kp_scheme, reuse_reason
     724              :       INTEGER                                            :: aligned_blocks, aligned_max_size, &
     725              :                                                             handle, nfull, output_unit
     726              :       INTEGER, DIMENSION(3)                              :: nkp_grid
     727           12 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
     728              :       LOGICAL                                            :: diis_step, full_grid, full_kpoint_grid, &
     729              :                                                             gamma_centered, reuse_scf_mos, &
     730              :                                                             reused_scf_mos, symmetry
     731              :       REAL(KIND=dp)                                      :: aligned_min_svalue, eps_geo, wsum
     732              :       REAL(KIND=dp), DIMENSION(3)                        :: kp_shift
     733           12 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: wkp_source
     734           12 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp_source
     735              :       TYPE(cell_type), POINTER                           :: cell
     736              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     737              :       TYPE(cp_logger_type), POINTER                      :: logger
     738           12 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks, matrix_s
     739              :       TYPE(dft_control_type), POINTER                    :: dft_control
     740           12 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     741              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     742              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     743           12 :          POINTER                                         :: sab_nl
     744           12 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     745              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     746              :       TYPE(scf_control_type), POINTER                    :: scf_control
     747              : 
     748           12 :       CALL timeset(routineN, handle)
     749              : 
     750           12 :       created = .FALSE.
     751           12 :       kpoints_out => kpoints_scf
     752           12 :       NULLIFY (blacs_env, cell, cell_to_index, dft_control, logger, matrix_ks, matrix_s, mos, &
     753           12 :                para_env, particle_set, sab_nl, scf_control, scf_env, wkp_source, xkp_source)
     754              : 
     755           12 :       IF (.NOT. do_kpoints) THEN
     756           10 :          CALL timestop(handle)
     757           10 :          RETURN
     758              :       END IF
     759            2 :       CPASSERT(ASSOCIATED(kpoints_scf))
     760              : 
     761              :       CALL get_kpoint_info(kpoints_scf, kp_scheme=kp_scheme, symmetry=symmetry, &
     762              :                            full_grid=full_grid, nkp_grid=nkp_grid, kp_shift=kp_shift, &
     763            2 :                            gamma_centered=gamma_centered, eps_geo=eps_geo)
     764            2 :       IF (.NOT. symmetry .OR. full_grid) THEN
     765            0 :          CALL timestop(handle)
     766            0 :          RETURN
     767              :       END IF
     768              : 
     769            2 :       CALL section_vals_val_get(casino_section, "FULL_KPOINT_GRID", l_val=full_kpoint_grid)
     770            2 :       IF (.NOT. full_kpoint_grid) THEN
     771            0 :          CPABORT("CASINO export requires a full k-point grid. Use PRINT%CASINO%FULL_KPOINT_GRID.")
     772              :       END IF
     773              : 
     774            2 :       SELECT CASE (TRIM(kp_scheme))
     775              :       CASE ("MONKHORST-PACK", "MACDONALD", "GENERAL")
     776              :          ! supported below
     777              :       CASE DEFAULT
     778            2 :          CPABORT("CASINO%FULL_KPOINT_GRID supports only MONKHORST-PACK, MACDONALD, and GENERAL k-points.")
     779              :       END SELECT
     780              : 
     781            2 :       logger => cp_get_default_logger()
     782            2 :       output_unit = cp_logger_get_default_io_unit(logger)
     783            2 :       CALL section_vals_val_get(casino_section, "REUSE_SCF_MOS", l_val=reuse_scf_mos)
     784              :       CALL get_qs_env(qs_env, para_env=para_env, blacs_env=blacs_env, cell=cell, &
     785              :                       particle_set=particle_set, mos=mos, dft_control=dft_control, &
     786              :                       sab_orb=sab_nl, matrix_ks_kp=matrix_ks, matrix_s_kp=matrix_s, &
     787            2 :                       scf_env=scf_env, scf_control=scf_control)
     788            2 :       CPASSERT(ASSOCIATED(para_env))
     789            2 :       CPASSERT(ASSOCIATED(blacs_env))
     790            2 :       CPASSERT(ASSOCIATED(cell))
     791            2 :       CPASSERT(ASSOCIATED(particle_set))
     792            2 :       CPASSERT(ASSOCIATED(mos))
     793            2 :       CPASSERT(ASSOCIATED(dft_control))
     794            2 :       CPASSERT(ASSOCIATED(sab_nl))
     795            2 :       CPASSERT(ASSOCIATED(matrix_ks))
     796            2 :       CPASSERT(ASSOCIATED(matrix_s))
     797            2 :       CPASSERT(ASSOCIATED(scf_env))
     798            2 :       CPASSERT(ASSOCIATED(scf_control))
     799              : 
     800            2 :       NULLIFY (kpoints_out)
     801            2 :       CALL kpoint_create(kpoints_out)
     802            2 :       kpoints_out%kp_scheme = kp_scheme
     803            2 :       kpoints_out%symmetry = .FALSE.
     804            2 :       kpoints_out%full_grid = .TRUE.
     805            2 :       kpoints_out%verbose = .FALSE.
     806            2 :       kpoints_out%use_real_wfn = .FALSE.
     807            2 :       kpoints_out%eps_geo = eps_geo
     808            2 :       kpoints_out%parallel_group_size = para_env%num_pe
     809              : 
     810            4 :       SELECT CASE (TRIM(kp_scheme))
     811              :       CASE ("MONKHORST-PACK", "MACDONALD")
     812            8 :          kpoints_out%nkp_grid(1:3) = nkp_grid(1:3)
     813            8 :          kpoints_out%kp_shift(1:3) = kp_shift(1:3)
     814            2 :          kpoints_out%gamma_centered = gamma_centered
     815            2 :          CALL kpoint_initialize(kpoints_out, particle_set, cell)
     816              :       CASE ("GENERAL")
     817            0 :          IF (.NOT. ASSOCIATED(kpoints_scf%xkp_input) .OR. &
     818              :              .NOT. ASSOCIATED(kpoints_scf%wkp_input)) THEN
     819            0 :             CPABORT("CASINO%FULL_KPOINT_GRID cannot recover the unreduced GENERAL k-point set.")
     820              :          END IF
     821            0 :          xkp_source => kpoints_scf%xkp_input
     822            0 :          wkp_source => kpoints_scf%wkp_input
     823            0 :          nfull = SIZE(wkp_source)
     824            0 :          wsum = SUM(wkp_source)
     825            0 :          IF (wsum <= 0.0_dp) CPABORT("CASINO%FULL_KPOINT_GRID found invalid GENERAL k-point weights.")
     826            0 :          kpoints_out%nkp = nfull
     827            0 :          ALLOCATE (kpoints_out%xkp(3, nfull), kpoints_out%wkp(nfull))
     828            0 :          kpoints_out%xkp(1:3, 1:nfull) = xkp_source(1:3, 1:nfull)
     829            2 :          kpoints_out%wkp(1:nfull) = wkp_source(1:nfull)/wsum
     830              :       END SELECT
     831              : 
     832            2 :       CALL kpoint_env_initialize(kpoints_out, para_env, blacs_env)
     833            2 :       CALL kpoint_initialize_mos(kpoints_out, mos)
     834            2 :       CALL kpoint_initialize_mo_set(kpoints_out)
     835            2 :       CALL kpoint_init_cell_index(kpoints_out, sab_nl, para_env, dft_control%nimages)
     836              : 
     837            2 :       reused_scf_mos = .FALSE.
     838            2 :       reuse_reason = ""
     839            2 :       aligned_blocks = 0
     840            2 :       aligned_max_size = 0
     841            2 :       aligned_min_svalue = 0.0_dp
     842            2 :       diis_step = .FALSE.
     843            2 :       IF (reuse_scf_mos) THEN
     844              :          CALL do_general_diag_kp(matrix_ks, matrix_s, kpoints_scf, scf_env, scf_control, .FALSE., &
     845            2 :                                  diis_step)
     846            2 :          CALL get_kpoint_info(kpoints_out, cell_to_index=cell_to_index)
     847              :          CALL prepare_wannier90_scf_mos(kpoints_out, kpoints_scf, matrix_s, matrix_ks, &
     848              :                                         cell_to_index, sab_nl, para_env, reused_scf_mos, &
     849              :                                         reuse_reason, aligned_blocks, aligned_max_size, &
     850            2 :                                         aligned_min_svalue)
     851              :       END IF
     852            2 :       IF (reused_scf_mos) THEN
     853            2 :          IF (output_unit > 0) THEN
     854              :             WRITE (output_unit, '(T2,A)') &
     855            1 :                "CASINO| Reused SCF MO coefficients for the full k-point grid."
     856            1 :             IF (aligned_blocks > 0) THEN
     857              :                WRITE (output_unit, '(T2,A,I0,A,I0,A,ES10.3)') &
     858            0 :                   "CASINO| Ritz-stabilized ", aligned_blocks, &
     859            0 :                   " degenerate SCF MO subspace(s); largest block has ", aligned_max_size, &
     860            0 :                   " band(s), min metric eigenvalue ", aligned_min_svalue
     861              :             END IF
     862              :          END IF
     863              :       ELSE
     864            0 :          IF (output_unit > 0) THEN
     865            0 :             IF (reuse_scf_mos) THEN
     866              :                WRITE (output_unit, '(T2,A,A)') &
     867            0 :                   "CASINO| Could not reuse SCF MOs: ", TRIM(reuse_reason)
     868              :             END IF
     869              :             WRITE (output_unit, '(T2,A)') &
     870            0 :                "CASINO| Diagonalizing the full k-point grid for export."
     871              :          END IF
     872            0 :          diis_step = .FALSE.
     873              :          CALL do_general_diag_kp(matrix_ks, matrix_s, kpoints_out, scf_env, scf_control, .FALSE., &
     874            0 :                                  diis_step)
     875              :       END IF
     876            2 :       created = .TRUE.
     877              : 
     878            2 :       CALL timestop(handle)
     879           12 :    END SUBROUTINE prepare_casino_kpoint_grid
     880              : 
     881              : ! **************************************************************************************************
     882              : !> \brief Build the CASINO k-point order with all real k-points first.
     883              : !> \param cell ...
     884              : !> \param periodic ...
     885              : !> \param do_kpoints ...
     886              : !> \param nkp_total ...
     887              : !> \param xkp ...
     888              : !> \param eps_kpoint_real ...
     889              : !> \param kp_order ...
     890              : !> \param kp_real ...
     891              : !> \param nkp_out ...
     892              : !> \param nreal_k ...
     893              : !> \param kvec ...
     894              : ! **************************************************************************************************
     895           12 :    SUBROUTINE build_kpoint_order(cell, periodic, do_kpoints, nkp_total, xkp, eps_kpoint_real, &
     896           12 :                                  kp_order, kp_real, nkp_out, nreal_k, kvec)
     897              :       TYPE(cell_type), INTENT(IN), POINTER               :: cell
     898              :       LOGICAL, INTENT(IN)                                :: periodic, do_kpoints
     899              :       INTEGER, INTENT(IN)                                :: nkp_total
     900              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     901              :          OPTIONAL, POINTER                               :: xkp
     902              :       REAL(KIND=dp), INTENT(IN)                          :: eps_kpoint_real
     903              :       INTEGER, DIMENSION(:), INTENT(OUT)                 :: kp_order
     904              :       LOGICAL, DIMENSION(:), INTENT(OUT)                 :: kp_real
     905              :       INTEGER, INTENT(OUT)                               :: nkp_out, nreal_k
     906              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT)        :: kvec
     907              : 
     908              :       INTEGER                                            :: ikp, jkp, ncomplex_k
     909           24 :       INTEGER, DIMENSION(nkp_total)                      :: complex_order, real_order
     910           10 :       LOGICAL, DIMENSION(nkp_total)                      :: used
     911              : 
     912           12 :       IF (.NOT. periodic) THEN
     913           10 :          kp_order(1) = 1
     914           10 :          kp_real(1) = .TRUE.
     915           10 :          nkp_out = 1
     916           10 :          nreal_k = 1
     917           40 :          kvec(:, 1) = 0.0_dp
     918              :          RETURN
     919              :       END IF
     920              : 
     921            2 :       IF (.NOT. do_kpoints) THEN
     922            0 :          kp_order(1) = 1
     923            0 :          kp_real(1) = .TRUE.
     924            0 :          nkp_out = 1
     925            0 :          nreal_k = 1
     926            0 :          kvec(:, 1) = 0.0_dp
     927              :          RETURN
     928              :       END IF
     929              : 
     930            6 :       used(:) = .FALSE.
     931            2 :       nreal_k = 0
     932            2 :       ncomplex_k = 0
     933              : 
     934            6 :       DO ikp = 1, nkp_total
     935            6 :          IF (is_real_kpoint(cell, xkp(:, ikp), eps_kpoint_real)) THEN
     936            0 :             used(ikp) = .TRUE.
     937            0 :             nreal_k = nreal_k + 1
     938            0 :             real_order(nreal_k) = ikp
     939              :          END IF
     940              :       END DO
     941              : 
     942            6 :       DO ikp = 1, nkp_total
     943            6 :          IF (.NOT. used(ikp)) THEN
     944            2 :             used(ikp) = .TRUE.
     945            2 :             ncomplex_k = ncomplex_k + 1
     946            2 :             complex_order(ncomplex_k) = ikp
     947            2 :             DO jkp = ikp + 1, nkp_total
     948            2 :                IF (.NOT. used(jkp)) THEN
     949            2 :                   IF (is_conjugate_kpoint(cell, xkp(:, ikp), xkp(:, jkp), eps_kpoint_real)) THEN
     950            2 :                      used(jkp) = .TRUE.
     951            2 :                      EXIT
     952              :                   END IF
     953              :                END IF
     954              :             END DO
     955              :          END IF
     956              :       END DO
     957              : 
     958            2 :       nkp_out = nreal_k + ncomplex_k
     959            2 :       DO ikp = 1, nreal_k
     960            0 :          kp_order(ikp) = real_order(ikp)
     961            0 :          kp_real(ikp) = .TRUE.
     962            2 :          kvec(:, ikp) = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), xkp(:, real_order(ikp)))
     963              :       END DO
     964            4 :       DO ikp = 1, ncomplex_k
     965            2 :          jkp = nreal_k + ikp
     966            2 :          kp_order(jkp) = complex_order(ikp)
     967            2 :          kp_real(jkp) = .FALSE.
     968           10 :          kvec(:, jkp) = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), xkp(:, complex_order(ikp)))
     969              :       END DO
     970            2 :    END SUBROUTINE build_kpoint_order
     971              : 
     972              : ! **************************************************************************************************
     973              : !> \brief Returns true for conjugate k-points modulo reciprocal lattice vectors.
     974              : !> \param cell ...
     975              : !> \param xk1 ...
     976              : !> \param xk2 ...
     977              : !> \param eps_kpoint_real ...
     978              : !> \return ...
     979              : ! **************************************************************************************************
     980            2 :    FUNCTION is_conjugate_kpoint(cell, xk1, xk2, eps_kpoint_real) RESULT(is_conjugate)
     981              :       TYPE(cell_type), INTENT(IN), POINTER               :: cell
     982              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xk1, xk2
     983              :       REAL(KIND=dp), INTENT(IN)                          :: eps_kpoint_real
     984              :       LOGICAL                                            :: is_conjugate
     985              : 
     986              :       INTEGER                                            :: idir
     987              :       REAL(KIND=dp)                                      :: reduced
     988              : 
     989            2 :       is_conjugate = .TRUE.
     990            8 :       DO idir = 1, 3
     991            8 :          IF (cell%perd(idir) /= 0) THEN
     992            6 :             reduced = xk1(idir) + xk2(idir)
     993            6 :             reduced = reduced - REAL(NINT(reduced), KIND=dp)
     994            6 :             IF (ABS(reduced) > eps_kpoint_real) THEN
     995              :                is_conjugate = .FALSE.
     996              :                EXIT
     997              :             END IF
     998              :          END IF
     999              :       END DO
    1000            2 :    END FUNCTION is_conjugate_kpoint
    1001              : 
    1002              : ! **************************************************************************************************
    1003              : !> \brief Returns true for Gamma/BZ-edge k-points where real Bloch orbitals can be used.
    1004              : !> \param cell ...
    1005              : !> \param xk ...
    1006              : !> \param eps_kpoint_real ...
    1007              : !> \return ...
    1008              : ! **************************************************************************************************
    1009            4 :    FUNCTION is_real_kpoint(cell, xk, eps_kpoint_real) RESULT(is_real)
    1010              :       TYPE(cell_type), INTENT(IN), POINTER               :: cell
    1011              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: xk
    1012              :       REAL(KIND=dp), INTENT(IN)                          :: eps_kpoint_real
    1013              :       LOGICAL                                            :: is_real
    1014              : 
    1015              :       INTEGER                                            :: idir
    1016              :       REAL(KIND=dp)                                      :: reduced
    1017              : 
    1018            4 :       is_real = .TRUE.
    1019           16 :       DO idir = 1, 3
    1020           16 :          IF (cell%perd(idir) /= 0) THEN
    1021           12 :             reduced = xk(idir) - REAL(NINT(xk(idir)), KIND=dp)
    1022            4 :             IF (ABS(reduced) > eps_kpoint_real .AND. &
    1023           16 :                 ABS(ABS(reduced) - 0.5_dp) > eps_kpoint_real) is_real = .FALSE.
    1024              :          END IF
    1025              :       END DO
    1026            4 :    END FUNCTION is_real_kpoint
    1027              : 
    1028              : ! **************************************************************************************************
    1029              : !> \brief Write all non-orbital CASINO gwfn.data sections.
    1030              : !> \param iw ...
    1031              : !> \param pure_hf reference is Hartree-Fock (no XC functional, HF fraction 1)
    1032              : !> \param periodicity ...
    1033              : !> \param nspins ...
    1034              : !> \param e_nn ...
    1035              : !> \param nel_tot ...
    1036              : !> \param natoms ...
    1037              : !> \param coord ...
    1038              : !> \param atomic_number ...
    1039              : !> \param valence_charge ...
    1040              : !> \param cell ...
    1041              : !> \param periodic ...
    1042              : !> \param nkp ...
    1043              : !> \param nreal_k ...
    1044              : !> \param kvec ...
    1045              : !> \param shell_num ...
    1046              : !> \param ao_num ...
    1047              : !> \param prim_num ...
    1048              : !> \param shell_ang_mom ...
    1049              : !> \param shell_type ...
    1050              : !> \param prim_per_shell ...
    1051              : !> \param first_shell ...
    1052              : !> \param exponents ...
    1053              : !> \param coefficients ...
    1054              : !> \param shell_position ...
    1055              : ! **************************************************************************************************
    1056           18 :    SUBROUTINE write_casino_header(iw, pure_hf, periodicity, nspins, e_nn, nel_tot, natoms, coord, &
    1057            6 :                                   atomic_number, valence_charge, cell, periodic, nkp, nreal_k, kvec, &
    1058           12 :                                   shell_num, ao_num, prim_num, shell_ang_mom, shell_type, prim_per_shell, &
    1059            6 :                                   first_shell, exponents, coefficients, shell_position)
    1060              :       INTEGER, INTENT(IN)                                :: iw
    1061              :       LOGICAL, INTENT(IN)                                :: pure_hf
    1062              :       INTEGER, INTENT(IN)                                :: periodicity, nspins
    1063              :       REAL(KIND=dp), INTENT(IN)                          :: e_nn
    1064              :       INTEGER, INTENT(IN)                                :: nel_tot, natoms
    1065              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: coord
    1066              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: atomic_number
    1067              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: valence_charge
    1068              :       TYPE(cell_type), INTENT(IN), POINTER               :: cell
    1069              :       LOGICAL, INTENT(IN)                                :: periodic
    1070              :       INTEGER, INTENT(IN)                                :: nkp, nreal_k
    1071              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: kvec
    1072              :       INTEGER, INTENT(IN)                                :: shell_num, ao_num, prim_num
    1073              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: shell_ang_mom, shell_type, &
    1074              :                                                             prim_per_shell, first_shell
    1075              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: exponents, coefficients
    1076              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: shell_position
    1077              : 
    1078              :       INTEGER                                            :: highest_ang_mom, i
    1079              : 
    1080           32 :       highest_ang_mom = MAXVAL(shell_ang_mom) + 1
    1081              : 
    1082            6 :       WRITE (iw, '(A)') "CP2K CASINO gwfn.data"
    1083            6 :       WRITE (iw, *)
    1084            6 :       WRITE (iw, '(A)') "BASIC INFO"
    1085            6 :       WRITE (iw, '(A)') "----------"
    1086            6 :       WRITE (iw, '(A)') "Generated by:"
    1087            6 :       WRITE (iw, '(1X,A)') TRIM(cp2k_version)
    1088            6 :       WRITE (iw, '(A)') "Method:"
    1089           12 :       WRITE (iw, '(A)') MERGE(" HF ", " DFT", pure_hf)
    1090            6 :       WRITE (iw, '(A)') "DFT functional:"
    1091           12 :       WRITE (iw, '(A)') MERGE(" none", " CP2K", pure_hf)
    1092            6 :       WRITE (iw, '(A)') "Periodicity:"
    1093            6 :       WRITE (iw, '(1X,I0)') periodicity
    1094            6 :       WRITE (iw, '(A)') "Spin unrestricted:"
    1095           11 :       WRITE (iw, '(1X,A)') MERGE(".true. ", ".false.", nspins > 1)
    1096            6 :       WRITE (iw, '(A)') "Nuclear repulsion energy (au/atom):"
    1097            6 :       WRITE (iw, '(1PE20.13)') e_nn
    1098            6 :       WRITE (iw, '(A)') "Number of electrons per primitive cell"
    1099            6 :       WRITE (iw, '(1X,I0)') nel_tot
    1100            6 :       WRITE (iw, *)
    1101              : 
    1102            6 :       WRITE (iw, '(A)') "GEOMETRY"
    1103            6 :       WRITE (iw, '(A)') "--------"
    1104            6 :       WRITE (iw, '(A)') "Number of atoms"
    1105            6 :       WRITE (iw, '(1X,I0)') natoms
    1106            6 :       WRITE (iw, '(A)') "Atomic positions (au)"
    1107           18 :       DO i = 1, natoms
    1108           18 :          WRITE (iw, '(3(1PE20.13))') coord(:, i)
    1109              :       END DO
    1110            6 :       WRITE (iw, '(A)') "Atomic numbers for each atom"
    1111            6 :       CALL write_integer_vector(iw, atomic_number)
    1112            6 :       WRITE (iw, '(A)') "Valence charges for each atom"
    1113            6 :       CALL write_real_vector(iw, valence_charge)
    1114            6 :       IF (.NOT. periodic) WRITE (iw, *)
    1115            6 :       IF (periodic) THEN
    1116            1 :          WRITE (iw, '(A)') "Primitive lattice vectors (au)"
    1117            4 :          DO i = 1, 3
    1118           13 :             WRITE (iw, '(3(1PE20.13))') cell%hmat(:, i)
    1119              :          END DO
    1120            1 :          WRITE (iw, *)
    1121              : 
    1122            1 :          WRITE (iw, '(A)') "K SPACE NET"
    1123            1 :          WRITE (iw, '(A)') "-----------"
    1124            1 :          WRITE (iw, '(A)') "Number of k points"
    1125            1 :          WRITE (iw, '(1X,I0)') nkp
    1126            1 :          WRITE (iw, '(A)') "Number of 'real' k points on BZ edge"
    1127            1 :          WRITE (iw, '(1X,I0)') nreal_k
    1128            1 :          WRITE (iw, '(A)') "k point coordinates (au)"
    1129            2 :          DO i = 1, nkp
    1130            2 :             WRITE (iw, '(3(1PE20.13))') kvec(:, i)
    1131              :          END DO
    1132            1 :          WRITE (iw, *)
    1133              :       END IF
    1134              : 
    1135            6 :       WRITE (iw, '(A)') "BASIS SET"
    1136            6 :       WRITE (iw, '(A)') "---------"
    1137            6 :       WRITE (iw, '(A)') "Number of Gaussian centres"
    1138            6 :       WRITE (iw, '(1X,I0)') natoms
    1139            6 :       WRITE (iw, '(A)') "Number of shells per primitive cell"
    1140            6 :       WRITE (iw, '(1X,I0)') shell_num
    1141            6 :       WRITE (iw, '(A)') "Number of basis functions ('AO') per primitive cell"
    1142            6 :       WRITE (iw, '(1X,I0)') ao_num
    1143            6 :       WRITE (iw, '(A)') "Number of Gaussian primitives per primitive cell"
    1144            6 :       WRITE (iw, '(1X,I0)') prim_num
    1145            6 :       WRITE (iw, '(A)') "Highest shell angular momentum (s/p/d/f/g... 1/2/3/4/5...)"
    1146            6 :       WRITE (iw, '(1X,I0)') highest_ang_mom
    1147            6 :       WRITE (iw, '(A)') "Code for shell types (s/sp/p/d/f... 1/2/3/4/5...)"
    1148            6 :       CALL write_integer_vector(iw, shell_type)
    1149            6 :       WRITE (iw, '(A)') "Number of primitive Gaussians in each shell"
    1150            6 :       CALL write_integer_vector(iw, prim_per_shell)
    1151            6 :       WRITE (iw, '(A)') "Sequence number of first shell on each centre"
    1152            6 :       CALL write_integer_vector(iw, first_shell)
    1153            6 :       WRITE (iw, '(A)') "Exponents of Gaussian primitives"
    1154            6 :       CALL write_real_vector(iw, exponents)
    1155            6 :       WRITE (iw, '(A)') "Correctly normalised contraction coefficients"
    1156            6 :       CALL write_real_vector(iw, coefficients)
    1157            6 :       WRITE (iw, '(A)') "Position of each shell (au)"
    1158           32 :       DO i = 1, shell_num
    1159           32 :          WRITE (iw, '(3(1PE20.13))') shell_position(:, i)
    1160              :       END DO
    1161            6 :       WRITE (iw, *)
    1162              : 
    1163            6 :       WRITE (iw, '(A)') "MULTIDETERMINANT INFORMATION"
    1164            6 :       WRITE (iw, '(A)') "----------------------------"
    1165            6 :       WRITE (iw, '(A)') "GS"
    1166            6 :       WRITE (iw, *)
    1167            6 :       WRITE (iw, '(A)') "ORBITAL COEFFICIENTS"
    1168            6 :       WRITE (iw, '(A)') "---------------------------"
    1169            6 :    END SUBROUTINE write_casino_header
    1170              : 
    1171              : ! **************************************************************************************************
    1172              : !> \brief Write one CASINO MO block for a spin/k-point.
    1173              : !> \param iw ...
    1174              : !> \param mos_sgf ...
    1175              : !> \param mos_sgf_im ...
    1176              : !> \param cp2k_to_casino_ao ...
    1177              : !> \param mo_scale ...
    1178              : !> \param ao_num ...
    1179              : !> \param complex_orbitals ...
    1180              : ! **************************************************************************************************
    1181            7 :    SUBROUTINE write_casino_orbitals(iw, mos_sgf, mos_sgf_im, cp2k_to_casino_ao, mo_scale, ao_num, &
    1182              :                                     complex_orbitals)
    1183              :       INTEGER, INTENT(IN)                                :: iw
    1184              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: mos_sgf, mos_sgf_im
    1185              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: cp2k_to_casino_ao
    1186              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: mo_scale
    1187              :       INTEGER, INTENT(IN)                                :: ao_num
    1188              :       LOGICAL, INTENT(IN)                                :: complex_orbitals
    1189              : 
    1190              :       INTEGER                                            :: iao, imo, nbuffer
    1191              :       REAL(KIND=dp), DIMENSION(4)                        :: buffer
    1192              : 
    1193            7 :       nbuffer = 0
    1194            7 :       buffer(:) = 0.0_dp
    1195           39 :       DO imo = 1, ao_num
    1196          231 :          DO iao = 1, ao_num
    1197          192 :             CALL push_real(iw, buffer, nbuffer, mo_scale(iao)*mos_sgf(cp2k_to_casino_ao(iao), imo))
    1198          224 :             IF (complex_orbitals) THEN
    1199           16 :                CALL push_real(iw, buffer, nbuffer, mo_scale(iao)*mos_sgf_im(cp2k_to_casino_ao(iao), imo))
    1200              :             END IF
    1201              :          END DO
    1202              :       END DO
    1203            7 :       IF (nbuffer > 0) WRITE (iw, '(4(1PE20.13))') buffer(1:nbuffer)
    1204            7 :    END SUBROUTINE write_casino_orbitals
    1205              : 
    1206              : ! **************************************************************************************************
    1207              : !> \brief Append one real number to a four-column output buffer.
    1208              : !> \param iw ...
    1209              : !> \param buffer ...
    1210              : !> \param nbuffer ...
    1211              : !> \param value ...
    1212              : ! **************************************************************************************************
    1213          208 :    SUBROUTINE push_real(iw, buffer, nbuffer, value)
    1214              :       INTEGER, INTENT(IN)                                :: iw
    1215              :       REAL(KIND=dp), DIMENSION(4), INTENT(INOUT)         :: buffer
    1216              :       INTEGER, INTENT(INOUT)                             :: nbuffer
    1217              :       REAL(KIND=dp), INTENT(IN)                          :: value
    1218              : 
    1219          208 :       nbuffer = nbuffer + 1
    1220          208 :       buffer(nbuffer) = value
    1221          208 :       IF (nbuffer == SIZE(buffer)) THEN
    1222           52 :          WRITE (iw, '(4(1PE20.13))') buffer
    1223           52 :          nbuffer = 0
    1224              :       END IF
    1225          208 :    END SUBROUTINE push_real
    1226              : 
    1227              : ! **************************************************************************************************
    1228              : !> \brief Write an integer vector in CASINO-friendly fixed-width columns.
    1229              : !> \param iw ...
    1230              : !> \param values ...
    1231              : ! **************************************************************************************************
    1232           24 :    SUBROUTINE write_integer_vector(iw, values)
    1233              :       INTEGER, INTENT(IN)                                :: iw
    1234              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: values
    1235              : 
    1236              :       INTEGER                                            :: i, ilast
    1237              : 
    1238           48 :       DO i = 1, SIZE(values), 8
    1239           24 :          ilast = MIN(i + 7, SIZE(values))
    1240           48 :          WRITE (iw, '(8I10)') values(i:ilast)
    1241              :       END DO
    1242           24 :    END SUBROUTINE write_integer_vector
    1243              : 
    1244              : ! **************************************************************************************************
    1245              : !> \brief Write a real vector in CASINO-friendly fixed-width columns.
    1246              : !> \param iw ...
    1247              : !> \param values ...
    1248              : ! **************************************************************************************************
    1249           19 :    SUBROUTINE write_real_vector(iw, values)
    1250              :       INTEGER, INTENT(IN)                                :: iw
    1251              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: values
    1252              : 
    1253              :       INTEGER                                            :: i, ilast
    1254              : 
    1255           78 :       DO i = 1, SIZE(values), 4
    1256           59 :          ilast = MIN(i + 3, SIZE(values))
    1257           78 :          WRITE (iw, '(4(1PE20.13))') values(i:ilast)
    1258              :       END DO
    1259           19 :    END SUBROUTINE write_real_vector
    1260              : 
    1261              : ! **************************************************************************************************
    1262              : !> \brief Rotate a complex value by exp(-i*k.g) using the TREXIO gauge convention.
    1263              : !> \param re ...
    1264              : !> \param im ...
    1265              : !> \param cval ...
    1266              : !> \param sval ...
    1267              : ! **************************************************************************************************
    1268           32 :    SUBROUTINE rotate_complex_pair(re, im, cval, sval)
    1269              :       REAL(KIND=dp), INTENT(INOUT)                       :: re, im
    1270              :       REAL(KIND=dp), INTENT(IN)                          :: cval, sval
    1271              : 
    1272              :       REAL(KIND=dp)                                      :: im_old, re_old
    1273              : 
    1274           32 :       re_old = re
    1275           32 :       im_old = im
    1276           32 :       re = cval*re_old + sval*im_old
    1277           32 :       im = -sval*re_old + cval*im_old
    1278           32 :    END SUBROUTINE rotate_complex_pair
    1279              : 
    1280              : ! **************************************************************************************************
    1281              : !> \brief Convert CP2K normalized primitive data to CASINO contraction coefficients.
    1282              : !> \param l ...
    1283              : !> \param nprim ...
    1284              : !> \param zetas ...
    1285              : !> \param gcc ...
    1286              : !> \param exponents ...
    1287              : !> \param coefficients ...
    1288              : ! **************************************************************************************************
    1289           52 :    SUBROUTINE casino_shell_coefficients(l, nprim, zetas, gcc, exponents, coefficients)
    1290              :       INTEGER, INTENT(IN)                                :: l, nprim
    1291              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zetas, gcc
    1292              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: exponents, coefficients
    1293              : 
    1294              :       INTEGER                                            :: i
    1295              :       REAL(KIND=dp)                                      :: contraction_norm, expzet, prefac, &
    1296              :                                                             prim_cart_fac
    1297          104 :       REAL(KIND=dp), DIMENSION(nprim)                    :: raw_coeff
    1298              : 
    1299           52 :       expzet = 0.25_dp*REAL(2*l + 3, KIND=dp)
    1300           52 :       prefac = 2.0_dp**l*(2.0_dp/pi)**0.75_dp
    1301          246 :       DO i = 1, nprim
    1302          194 :          prim_cart_fac = prefac*zetas(i)**expzet
    1303          246 :          raw_coeff(i) = gcc(i)/prim_cart_fac
    1304              :       END DO
    1305           52 :       contraction_norm = casino_contraction_norm(l, nprim, zetas, raw_coeff)
    1306          246 :       DO i = 1, nprim
    1307          194 :          exponents(i) = zetas(i)
    1308          246 :          coefficients(i) = raw_coeff(i)*contraction_norm*casino_primitive_norm(l, zetas(i))
    1309              :       END DO
    1310           52 :    END SUBROUTINE casino_shell_coefficients
    1311              : 
    1312              : ! **************************************************************************************************
    1313              : !> \brief Whole-contraction normalization used by CASINO's molden2qmc converter.
    1314              : !> \param l ...
    1315              : !> \param nprim ...
    1316              : !> \param zetas ...
    1317              : !> \param raw_coeff ...
    1318              : !> \return ...
    1319              : ! **************************************************************************************************
    1320           52 :    FUNCTION casino_contraction_norm(l, nprim, zetas, raw_coeff) RESULT(norm)
    1321              :       INTEGER, INTENT(IN)                                :: l, nprim
    1322              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zetas, raw_coeff
    1323              :       REAL(KIND=dp)                                      :: norm
    1324              : 
    1325              :       INTEGER                                            :: i, j
    1326              :       REAL(KIND=dp)                                      :: overlap
    1327              : 
    1328           52 :       overlap = 0.0_dp
    1329          246 :       DO i = 1, nprim
    1330         1204 :          DO j = 1, nprim
    1331              :             overlap = overlap + raw_coeff(i)*raw_coeff(j)* &
    1332         1152 :                       (2.0_dp*SQRT(zetas(i)*zetas(j))/(zetas(i) + zetas(j)))**(l + 1.5_dp)
    1333              :          END DO
    1334              :       END DO
    1335           52 :       norm = 1.0_dp/SQRT(overlap)
    1336           52 :    END FUNCTION casino_contraction_norm
    1337              : 
    1338              : ! **************************************************************************************************
    1339              : !> \brief Primitive m-independent normalization used by CASINO's Gaussian evaluator.
    1340              : !> \param l ...
    1341              : !> \param alpha ...
    1342              : !> \return ...
    1343              : ! **************************************************************************************************
    1344          194 :    FUNCTION casino_primitive_norm(l, alpha) RESULT(norm)
    1345              :       INTEGER, INTENT(IN)                                :: l
    1346              :       REAL(KIND=dp), INTENT(IN)                          :: alpha
    1347              :       REAL(KIND=dp)                                      :: norm
    1348              : 
    1349          194 :       norm = SQRT(2.0_dp**(l + 1.5_dp)*alpha**(l + 1.5_dp))/pi**0.75_dp
    1350          194 :       IF (l > 0) norm = norm*SQRT(2.0_dp**l/odd_double_factorial(2*l - 1))
    1351          194 :    END FUNCTION casino_primitive_norm
    1352              : 
    1353              : ! **************************************************************************************************
    1354              : !> \brief CASINO shell type code.
    1355              : !> \param l ...
    1356              : !> \return ...
    1357              : ! **************************************************************************************************
    1358           52 :    FUNCTION casino_shell_type(l) RESULT(shell_type)
    1359              :       INTEGER, INTENT(IN)                                :: l
    1360              :       INTEGER                                            :: shell_type
    1361              : 
    1362           52 :       IF (l == 0) THEN
    1363              :          shell_type = 1
    1364              :       ELSE
    1365            4 :          shell_type = l + 2
    1366              :       END IF
    1367           52 :    END FUNCTION casino_shell_type
    1368              : 
    1369              : ! **************************************************************************************************
    1370              : !> \brief CP2K AO index for a CASINO/MOLDEN ordered harmonic shell.
    1371              : !> \param l ...
    1372              : !> \param k ...
    1373              : !> \return ...
    1374              : ! **************************************************************************************************
    1375           60 :    FUNCTION casino_cp2k_index(l, k) RESULT(idx)
    1376              :       INTEGER, INTENT(IN)                                :: l, k
    1377              :       INTEGER                                            :: idx
    1378              : 
    1379              :       INTEGER, DIMENSION(9, 0:max_casino_l), PARAMETER :: map = RESHAPE([1, 0, 0, 0, 0, 0, 0, 0, 0 &
    1380              :          , 3, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 2, 5, 1, 0, 0, 0, 0, 4, 5, 3, 6, 2, 7, 1, 0, 0, 5, 6, 4&
    1381              :          , 7, 3, 8, 2, 9, 1], [9, max_casino_l + 1])
    1382              : 
    1383           60 :       idx = map(k, l)
    1384           60 :    END FUNCTION casino_cp2k_index
    1385              : 
    1386              : ! **************************************************************************************************
    1387              : !> \brief Scale factors converting MOLDEN harmonic MO coefficients to CASINO conventions.
    1388              : !> \param l ...
    1389              : !> \param k ...
    1390              : !> \return ...
    1391              : ! **************************************************************************************************
    1392           60 :    FUNCTION casino_mo_scale(l, k) RESULT(scale)
    1393              :       INTEGER, INTENT(IN)                                :: l, k
    1394              :       REAL(KIND=dp)                                      :: scale
    1395              : 
    1396              :       REAL(KIND=dp), DIMENSION(5), PARAMETER :: d_factor = [0.5_dp, 3.0_dp, 3.0_dp, 3.0_dp, 6.0_dp]
    1397              : 
    1398              :       INTEGER                                            :: m
    1399              : 
    1400           60 :       IF (l <= 1) THEN
    1401              :          scale = 1.0_dp
    1402              :       ELSE
    1403            0 :          m = casino_m_quantum_number(k)
    1404            0 :          scale = casino_m_dependent_factor(l, m)
    1405            0 :          IF (l == 2) scale = scale*d_factor(k)
    1406              :       END IF
    1407           60 :    END FUNCTION casino_mo_scale
    1408              : 
    1409              : ! **************************************************************************************************
    1410              : !> \brief m sequence in CASINO/MOLDEN harmonic order: 0,+1,-1,+2,-2,...
    1411              : !> \param k ...
    1412              : !> \return ...
    1413              : ! **************************************************************************************************
    1414            0 :    FUNCTION casino_m_quantum_number(k) RESULT(m)
    1415              :       INTEGER, INTENT(IN)                                :: k
    1416              :       INTEGER                                            :: m
    1417              : 
    1418            0 :       IF (k == 1) THEN
    1419              :          m = 0
    1420            0 :       ELSE IF (MOD(k, 2) == 0) THEN
    1421            0 :          m = k/2
    1422              :       ELSE
    1423            0 :          m = -(k/2)
    1424              :       END IF
    1425            0 :    END FUNCTION casino_m_quantum_number
    1426              : 
    1427              : ! **************************************************************************************************
    1428              : !> \brief CASINO m-dependent normalization factor.
    1429              : !> \param l ...
    1430              : !> \param m ...
    1431              : !> \return ...
    1432              : ! **************************************************************************************************
    1433            0 :    FUNCTION casino_m_dependent_factor(l, m) RESULT(factor)
    1434              :       INTEGER, INTENT(IN)                                :: l, m
    1435              :       REAL(KIND=dp)                                      :: factor
    1436              : 
    1437              :       INTEGER                                            :: am
    1438              :       REAL(KIND=dp)                                      :: prefactor
    1439              : 
    1440            0 :       am = ABS(m)
    1441            0 :       prefactor = MERGE(1.0_dp, 2.0_dp, am == 0)
    1442            0 :       factor = SQRT(prefactor*factorial(l - am)/factorial(l + am))
    1443            0 :    END FUNCTION casino_m_dependent_factor
    1444              : 
    1445              : ! **************************************************************************************************
    1446              : !> \brief Real factorial for small non-negative integers.
    1447              : !> \param n ...
    1448              : !> \return ...
    1449              : ! **************************************************************************************************
    1450            0 :    FUNCTION factorial(n) RESULT(value)
    1451              :       INTEGER, INTENT(IN)                                :: n
    1452              :       REAL(KIND=dp)                                      :: value
    1453              : 
    1454              :       INTEGER                                            :: i
    1455              : 
    1456            0 :       value = 1.0_dp
    1457            0 :       DO i = 2, n
    1458            0 :          value = value*REAL(i, KIND=dp)
    1459              :       END DO
    1460            0 :    END FUNCTION factorial
    1461              : 
    1462              : ! **************************************************************************************************
    1463              : !> \brief Odd double factorial.
    1464              : !> \param n ...
    1465              : !> \return ...
    1466              : ! **************************************************************************************************
    1467           28 :    FUNCTION odd_double_factorial(n) RESULT(value)
    1468              :       INTEGER, INTENT(IN)                                :: n
    1469              :       REAL(KIND=dp)                                      :: value
    1470              : 
    1471              :       INTEGER                                            :: i
    1472              : 
    1473           28 :       value = 1.0_dp
    1474           28 :       DO i = MAX(1, n), 1, -2
    1475           28 :          value = value*REAL(i, KIND=dp)
    1476              :       END DO
    1477           28 :    END FUNCTION odd_double_factorial
    1478              : 
    1479              : ! **************************************************************************************************
    1480              : !> \brief Computes the nuclear repulsion energy of a molecular system.
    1481              : !> \param particle_set ...
    1482              : !> \param kind_set ...
    1483              : !> \param e_nn ...
    1484              : ! **************************************************************************************************
    1485           10 :    SUBROUTINE nuclear_repulsion_energy(particle_set, kind_set, e_nn)
    1486              :       TYPE(particle_type), DIMENSION(:), INTENT(IN), &
    1487              :          POINTER                                         :: particle_set
    1488              :       TYPE(qs_kind_type), DIMENSION(:), INTENT(IN), &
    1489              :          POINTER                                         :: kind_set
    1490              :       REAL(KIND=dp), INTENT(OUT)                         :: e_nn
    1491              : 
    1492              :       INTEGER                                            :: i, ikind, j, jkind, natoms
    1493              :       REAL(KIND=dp)                                      :: r_ij, zeff_i, zeff_j
    1494              : 
    1495           10 :       natoms = SIZE(particle_set)
    1496           10 :       e_nn = 0.0_dp
    1497           30 :       DO i = 1, natoms
    1498           20 :          CALL get_atomic_kind(particle_set(i)%atomic_kind, kind_number=ikind)
    1499           20 :          CALL get_qs_kind(kind_set(ikind), zeff=zeff_i)
    1500           42 :          DO j = i + 1, natoms
    1501           48 :             r_ij = NORM2(particle_set(i)%r - particle_set(j)%r)
    1502           12 :             CALL get_atomic_kind(particle_set(j)%atomic_kind, kind_number=jkind)
    1503           12 :             CALL get_qs_kind(kind_set(jkind), zeff=zeff_j)
    1504           32 :             e_nn = e_nn + zeff_i*zeff_j/r_ij
    1505              :          END DO
    1506              :       END DO
    1507           10 :    END SUBROUTINE nuclear_repulsion_energy
    1508              : 
    1509              : ! **************************************************************************************************
    1510              : !> \brief Computes the CASINO-compatible 3D periodic nuclear repulsion energy.
    1511              : !> \param cell ...
    1512              : !> \param periodicity ...
    1513              : !> \param coord ...
    1514              : !> \param charge ...
    1515              : !> \param e_nn ...
    1516              : ! **************************************************************************************************
    1517            2 :    SUBROUTINE periodic_nuclear_repulsion_energy(cell, periodicity, coord, charge, e_nn)
    1518              :       TYPE(cell_type), INTENT(IN), POINTER               :: cell
    1519              :       INTEGER, INTENT(IN)                                :: periodicity
    1520              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: coord
    1521              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: charge
    1522              :       REAL(KIND=dp), INTENT(OUT)                         :: e_nn
    1523              : 
    1524              :       INTEGER                                            :: gmax, i, ig1, ig2, ig3, j, n1, n2, n3, &
    1525              :                                                             natoms, nmax
    1526              :       REAL(KIND=dp) :: alpha, alpha2, cutoff_arg, g_cut, g_sq, min_g, min_h, neut_energy, phase, &
    1527              :          r, real_cut, real_energy, recip_energy, self_energy, struc_im, struc_re, volume
    1528              :       REAL(KIND=dp), DIMENSION(3)                        :: delta, g_index, gvec, lattice_shift
    1529              : 
    1530            2 :       e_nn = 0.0_dp
    1531            2 :       IF (periodicity /= 3) RETURN
    1532              : 
    1533            2 :       volume = ABS(cell%deth)
    1534            2 :       IF (volume <= 0.0_dp) CPABORT("CASINO periodic nuclear repulsion requires a non-zero cell volume.")
    1535              : 
    1536            2 :       natoms = SIZE(charge)
    1537            2 :       IF (natoms == 0) RETURN
    1538              : 
    1539              :       min_h = HUGE(1.0_dp)
    1540              :       min_g = HUGE(1.0_dp)
    1541            8 :       DO i = 1, 3
    1542           24 :          min_h = MIN(min_h, NORM2(cell%hmat(:, i)))
    1543            6 :          g_index = 0.0_dp
    1544            6 :          g_index(i) = 1.0_dp
    1545           30 :          gvec = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), g_index)
    1546           26 :          min_g = MIN(min_g, NORM2(gvec))
    1547              :       END DO
    1548            2 :       IF (min_h <= 0.0_dp .OR. min_g <= 0.0_dp) THEN
    1549            0 :          CPABORT("CASINO periodic nuclear repulsion requires non-zero lattice vectors.")
    1550              :       END IF
    1551              : 
    1552            2 :       cutoff_arg = SQRT(-LOG(1.0E-12_dp))
    1553            2 :       alpha = rootpi*(REAL(natoms, KIND=dp)/volume)**(1.0_dp/3.0_dp)
    1554            2 :       alpha2 = alpha*alpha
    1555            2 :       real_cut = cutoff_arg/alpha
    1556            2 :       g_cut = 2.0_dp*alpha*cutoff_arg
    1557            2 :       nmax = MAX(1, CEILING(real_cut/min_h) + 1)
    1558            2 :       gmax = MAX(1, CEILING(g_cut/min_g) + 1)
    1559              : 
    1560            2 :       real_energy = 0.0_dp
    1561            6 :       DO i = 1, natoms
    1562           14 :          DO j = 1, natoms
    1563           84 :             DO n1 = -nmax, nmax
    1564          728 :                DO n2 = -nmax, nmax
    1565         6552 :                   DO n3 = -nmax, nmax
    1566         5832 :                      IF (i == j .AND. n1 == 0 .AND. n2 == 0 .AND. n3 == 0) CYCLE
    1567              :                      lattice_shift = REAL(n1, KIND=dp)*cell%hmat(:, 1) + &
    1568              :                                      REAL(n2, KIND=dp)*cell%hmat(:, 2) + &
    1569        23312 :                                      REAL(n3, KIND=dp)*cell%hmat(:, 3)
    1570        23312 :                      delta = coord(:, i) - coord(:, j) + lattice_shift
    1571        23312 :                      r = NORM2(delta)
    1572         6476 :                      IF (r <= real_cut) real_energy = real_energy + charge(i)*charge(j)*ERFC(alpha*r)/r
    1573              :                   END DO
    1574              :                END DO
    1575              :             END DO
    1576              :          END DO
    1577              :       END DO
    1578            2 :       real_energy = 0.5_dp*real_energy
    1579              : 
    1580            2 :       recip_energy = 0.0_dp
    1581           24 :       DO ig1 = -gmax, gmax
    1582          266 :          DO ig2 = -gmax, gmax
    1583         2926 :             DO ig3 = -gmax, gmax
    1584         2662 :                IF (ig1 == 0 .AND. ig2 == 0 .AND. ig3 == 0) CYCLE
    1585        10640 :                g_index = [REAL(ig1, KIND=dp), REAL(ig2, KIND=dp), REAL(ig3, KIND=dp)]
    1586        13300 :                gvec = 2.0_dp*pi*MATMUL(TRANSPOSE(cell%h_inv), g_index)
    1587        10640 :                g_sq = DOT_PRODUCT(gvec, gvec)
    1588         2660 :                IF (SQRT(g_sq) > g_cut) CYCLE
    1589              :                struc_re = 0.0_dp
    1590              :                struc_im = 0.0_dp
    1591         1212 :                DO i = 1, natoms
    1592         3232 :                   phase = DOT_PRODUCT(gvec, coord(:, i))
    1593          808 :                   struc_re = struc_re + charge(i)*COS(phase)
    1594         1212 :                   struc_im = struc_im + charge(i)*SIN(phase)
    1595              :                END DO
    1596              :                recip_energy = recip_energy + EXP(-g_sq/(4.0_dp*alpha2))/g_sq* &
    1597         2904 :                               (struc_re*struc_re + struc_im*struc_im)
    1598              :             END DO
    1599              :          END DO
    1600              :       END DO
    1601            2 :       recip_energy = 2.0_dp*pi*recip_energy/volume
    1602              : 
    1603            6 :       self_energy = -alpha*SUM(charge*charge)/rootpi
    1604            6 :       neut_energy = -pi*SUM(charge)**2/(2.0_dp*alpha2*volume)
    1605            2 :       e_nn = real_energy + recip_energy + self_energy + neut_energy
    1606              :    END SUBROUTINE periodic_nuclear_repulsion_energy
    1607              : 
    1608              : END MODULE casino_utils
        

Generated by: LCOV version 2.0-1