!--------------------------------------------------------------------------------------------------! ! CP2K: A general program to perform molecular dynamics simulations ! ! Copyright 2000-2024 CP2K developers group ! ! ! ! SPDX-License-Identifier: GPL-2.0-or-later ! !--------------------------------------------------------------------------------------------------! ! ! ************************************************************************************************** ! > \brief Creates the PW section of the input ! > \par History ! > 07.2018 created ! > \author JHU ! ************************************************************************************************** MODULE input_cp2k_pwdft #if defined(__SIRIUS) USE ISO_C_BINDING, ONLY: C_LOC USE SIRIUS, ONLY: & sirius_option_get, & sirius_option_get_section_length, sirius_option_get_info, & SIRIUS_INTEGER_TYPE, SIRIUS_NUMBER_TYPE, SIRIUS_STRING_TYPE, & SIRIUS_LOGICAL_TYPE, SIRIUS_ARRAY_TYPE, SIRIUS_INTEGER_ARRAY_TYPE, SIRIUS_LOGICAL_ARRAY_TYPE, & SIRIUS_NUMBER_ARRAY_TYPE, SIRIUS_STRING_ARRAY_TYPE, string_f2c #endif USE input_keyword_types, ONLY: keyword_create, & keyword_release, & keyword_type USE input_section_types, ONLY: section_add_keyword, & section_add_subsection, & section_create, & section_release, & section_type USE input_val_types, ONLY: char_t, & integer_t, & lchar_t, & logical_t, & real_t USE cp_output_handling, ONLY: add_last_numeric, & cp_print_key_section_create, & debug_print_level, & high_print_level, & low_print_level, & medium_print_level, & silent_print_level USE kinds, ONLY: dp USE string_utilities, ONLY: s2a #include "./base/base_uses.f90" IMPLICIT NONE PRIVATE LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE. CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'input_cp2k_pwdft' PUBLIC :: create_pwdft_section INTEGER, PARAMETER, PUBLIC :: SIRIUS_NO_VDW = -1 INTEGER, PARAMETER, PUBLIC :: SIRIUS_FUNC_VDWDF = 1 INTEGER, PARAMETER, PUBLIC :: SIRIUS_FUNC_VDWDF2 = 2 INTEGER, PARAMETER, PUBLIC :: SIRIUS_FUNC_VDWDFCX = 3 CONTAINS #if defined(__SIRIUS) ! ************************************************************************************************** !> \brief Create the input section for PW calculations using SIRIUS !> \param section the section to create !> \par History !> 07.2018 created !> \author JHU ! ************************************************************************************************** SUBROUTINE create_pwdft_section(section) TYPE(section_type), POINTER :: section TYPE(section_type), POINTER :: subsection ! ------------------------------------------------------------------------ CPASSERT(.NOT. ASSOCIATED(section)) CALL section_create(section, __LOCATION__, name="PW_DFT", & description="DFT calculation using plane waves basis can be set in this section. "// & "The backend called SIRIUS, computes the basic properties of the system, "// & "such as ground state, forces and stresses tensors which can be used by "// & "cp2k afterwards. The engine has all these features build-in, support of "// & "pseudo-potentials and full-potentials, spin-orbit coupling, collinear and "// & "non collinear magnetism, Hubbard correction, all exchange functionals "// & "supported by libxc and Van der Waals corrections (libvdwxc).") NULLIFY (subsection) CALL create_sirius_section(subsection, 'control') CALL section_add_subsection(section, subsection) CALL section_release(subsection) CALL create_sirius_section(subsection, 'parameters') CALL section_add_subsection(section, subsection) CALL section_release(subsection) CALL create_sirius_section(subsection, 'settings') CALL section_add_subsection(section, subsection) CALL section_release(subsection) CALL create_sirius_section(subsection, 'mixer') CALL section_add_subsection(section, subsection) CALL section_release(subsection) CALL create_sirius_section(subsection, 'iterative_solver') CALL section_add_subsection(section, subsection) CALL section_release(subsection) ! ! uncomment these lines when nlcg is officialy supported in cp2k ! ! CALL create_sirius_section(subsection, 'nlcg') ! CALL section_add_subsection(section, subsection) ! CALL section_release(subsection) CALL create_print_section(subsection) CALL section_add_subsection(section, subsection) CALL section_release(subsection) END SUBROUTINE create_pwdft_section ! ************************************************************************************************** !> \brief input section for PWDFT control !> \param section will contain the CONTROL section !> \param section_name ... !> \author JHU ! ************************************************************************************************** SUBROUTINE create_sirius_section(section, section_name) TYPE(section_type), POINTER :: section CHARACTER(len=*), INTENT(in) :: section_name INTEGER :: length CPASSERT(.NOT. ASSOCIATED(section)) CALL sirius_option_get_section_length(TRIM(ADJUSTL(section_name)), length) CALL section_create(section, __LOCATION__, & name=TRIM(ADJUSTL(section_name)), & description=TRIM(section_name)//" section", & n_subsections=0, & n_keywords=length, & repeats=.FALSE.) CALL fill_in_section(section, TRIM(ADJUSTL(section_name))) END SUBROUTINE create_sirius_section ! ************************************************************************************************** !> \brief ... !> \param section ... !> \param section_name ... ! ************************************************************************************************** SUBROUTINE fill_in_section(section, section_name) TYPE(section_type), POINTER :: section CHARACTER(len=*), INTENT(in) :: section_name CHARACTER(len=128) :: name CHARACTER(len=128), TARGET :: possible_values(1:16) CHARACTER(len=4096) :: description, usage INTEGER :: ctype, enum_i_val(1:16), enum_length, i, & j, length, num_possible_values INTEGER, ALLOCATABLE, DIMENSION(:), TARGET :: ivec INTEGER, TARGET :: dummy_i LOGICAL :: lvecl(1:16) LOGICAL(4), ALLOCATABLE, DIMENSION(:), TARGET :: lvec LOGICAL(4), TARGET :: dummy_l REAL(kind=dp), ALLOCATABLE, DIMENSION(:), TARGET :: rvec REAL(kind=dp), TARGET :: dummy_r TYPE(keyword_type), POINTER :: keyword ALLOCATE (ivec(1:16)) ALLOCATE (rvec(1:16)) ALLOCATE (lvec(1:16)) #ifdef __LIBVDWXC IF (section_name == "parameters") THEN NULLIFY (keyword) CALL keyword_create(keyword, __LOCATION__, name="VDW_FUNCTIONAL", & description="Select the Van der Walls functionals corrections type", & default_i_val=SIRIUS_NO_VDW, & enum_i_vals=(/SIRIUS_NO_VDW, SIRIUS_FUNC_VDWDF, SIRIUS_FUNC_VDWDF2, SIRIUS_FUNC_VDWDFCX/), & enum_c_vals=s2a("NONE", "FUNC_VDWDF", "FUNC_VDWDF2", "FUNC_VDWDFCX"), & enum_desc=s2a("No VdW correction", & "FUNC_VDWDF", & "FUNC_VDWDF2", & "FUNC_VDWDFCX")) CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) END IF #endif CALL sirius_option_get_section_length(section_name, length) DO i = 1, length NULLIFY (keyword) name = '' description = '' usage = '' CALL sirius_option_get_info(section_name, & i, & name, & 128, & ctype, & num_possible_values, & enum_length, & description, & 4096, & usage, & 4096) ! description and usage are ignored here ! it is a minor inconvenience from the api. name = TRIM(ADJUSTL(name)) ! I exclude these three keywords because one of them is for debugging ! purpose the other are replaced by a dedicated call in cp2k ! ! Moreover xc_functionals would need a special treatment. IF ((name /= 'xc_functionals') .AND. (name /= 'memory_usage') .AND. (name /= 'vk')) THEN ! we need to null char since SIRIUS interface is basically C SELECT CASE (ctype) CASE (SIRIUS_INTEGER_TYPE) CALL sirius_option_get(section_name, name, ctype, C_LOC(dummy_i)) CALL keyword_create(keyword, __LOCATION__, & name=TRIM(name), & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=integer_t, & repeats=.FALSE., & default_i_val=dummy_i) CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) CASE (SIRIUS_NUMBER_TYPE) CALL sirius_option_get(section_name, name, ctype, C_LOC(dummy_r)) CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=real_t, & repeats=.FALSE., & default_r_val=dummy_r) CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) CASE (SIRIUS_LOGICAL_TYPE) dummy_l = .FALSE. CALL sirius_option_get(section_name, name, ctype, C_LOC(dummy_l)) IF (dummy_l) THEN CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=logical_t, & repeats=.FALSE., & default_l_val=.TRUE., & lone_keyword_l_val=.TRUE.) ELSE CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=logical_t, & repeats=.FALSE., & default_l_val=.FALSE., & lone_keyword_l_val=.TRUE.) END IF CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) CASE (SIRIUS_STRING_TYPE) IF (enum_length >= 1) THEN DO j = 1, enum_length possible_values(j) = '' CALL sirius_option_get(section_name, name, ctype, C_LOC(possible_values(j)), max_length=128, enum_idx=j) enum_i_val(j) = j possible_values(j) = TRIM(ADJUSTL(possible_values(j))) END DO IF (enum_length > 1) THEN CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & repeats=.FALSE., & enum_i_vals=enum_i_val(1:enum_length), & enum_c_vals=possible_values(1:enum_length), & default_i_val=1) ELSE CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=char_t, & default_c_val=possible_values(1), & repeats=.FALSE.) END IF ELSE CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=char_t, & default_c_val='', & repeats=.FALSE.) END IF CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) CASE (SIRIUS_INTEGER_ARRAY_TYPE) CALL sirius_option_get(section_name, name, ctype, C_LOC(ivec(1)), max_length=16) IF (num_possible_values .EQ. 0) THEN CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & type_of_var=integer_t, & n_var=-1, & repeats=.FALSE.) ELSE CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & type_of_var=integer_t, & repeats=.FALSE., & n_var=num_possible_values, & default_i_vals=ivec(1:num_possible_values)) END IF CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) CASE (SIRIUS_LOGICAL_ARRAY_TYPE) CALL sirius_option_get(section_name, name, ctype, C_LOC(lvec(1)), max_length=16) DO j = 1, num_possible_values lvecl(j) = lvec(j) END DO IF (num_possible_values > 0) THEN CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & !usage=TRIM(ADJUSTL(usage)), & type_of_var=logical_t, & repeats=.FALSE., & n_var=num_possible_values, & default_l_vals=lvecl(1:num_possible_values)) ELSE CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & !usage=TRIM(ADJUSTL(usage)), & type_of_var=logical_t, & repeats=.FALSE., & n_var=-1) END IF CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) CASE (SIRIUS_NUMBER_ARRAY_TYPE) CALL sirius_option_get(section_name, name, ctype, C_LOC(rvec(1)), max_length=16) IF (num_possible_values .EQ. 0) THEN CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=real_t, & repeats=.FALSE., & n_var=-1) ELSE CALL keyword_create(keyword, __LOCATION__, & name=name, & description=TRIM(ADJUSTL(description)), & ! usage=TRIM(ADJUSTL(usage)), & type_of_var=real_t, & repeats=.FALSE., & n_var=num_possible_values, & default_r_vals=rvec(1:num_possible_values)) END IF CALL section_add_keyword(section, keyword) CALL keyword_release(keyword) CASE default END SELECT END IF END DO END SUBROUTINE fill_in_section ! ************************************************************************************************** !> \brief Create the print section for sirius !> \param section the section to create !> \author jgh ! ************************************************************************************************** SUBROUTINE create_print_section(section) TYPE(section_type), POINTER :: section TYPE(section_type), POINTER :: print_key CPASSERT(.NOT. ASSOCIATED(section)) CALL section_create(section, __LOCATION__, name="PRINT", & description="Section of possible print options in PW_DFT code.", & n_keywords=0, n_subsections=1, repeats=.FALSE.) NULLIFY (print_key) CALL create_dos_section(print_key) CALL section_add_subsection(section, print_key) CALL section_release(print_key) END SUBROUTINE create_print_section ! ************************************************************************************************** !> \brief ... !> \param print_key ... ! ************************************************************************************************** SUBROUTINE create_dos_section(print_key) TYPE(section_type), POINTER :: print_key TYPE(keyword_type), POINTER :: keyword NULLIFY (keyword) CALL cp_print_key_section_create(print_key, __LOCATION__, "DOS", & description="Print Density of States (DOS) (only available states from SCF)", & print_level=debug_print_level, common_iter_levels=1, filename="") CALL keyword_create(keyword, __LOCATION__, name="APPEND", & description="Append the DOS obtained at different iterations to the output file. "// & "By default the file is overwritten", & usage="APPEND", default_l_val=.FALSE., & lone_keyword_l_val=.TRUE.) CALL section_add_keyword(print_key, keyword) CALL keyword_release(keyword) CALL keyword_create(keyword, __LOCATION__, name="DELTA_E", & description="Histogramm energy spacing.", & usage="DELTA_E 0.0005", type_of_var=real_t, default_r_val=0.001_dp) CALL section_add_keyword(print_key, keyword) CALL keyword_release(keyword) END SUBROUTINE create_dos_section #else ! ************************************************************************************************** !> \brief ... !> \param section ... ! ************************************************************************************************** SUBROUTINE create_pwdft_section(section) TYPE(section_type), POINTER :: section CPASSERT(.NOT. ASSOCIATED(section)) CALL section_create(section, __LOCATION__, name="PW_DFT", & description="This section contains all information to run an "// & "SIRIUS PW calculation.", & n_subsections=0, & repeats=.FALSE.) END SUBROUTINE create_pwdft_section #endif END MODULE input_cp2k_pwdft