-- mode: F90 --!
!!-*- mode: F90 -*-! !------------------------------------------------------------! ! Copyright (C) 2026 Wannier Developer Group ! ! ! ! This library is free software; you can redistribute it ! ! and/or modify it under the terms of the GNU Lesser General ! ! Public License as published by the Free Software ! ! Foundation; either version 2.1 of the License, or (at your ! ! option) any later version. ! ! ! ! This library is distributed in the hope that it will be ! ! useful,but WITHOUT ANY WARRANTY; without even the implied ! ! warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ! ! PURPOSE. See the GNU Lesser General Public License for ! ! more details. ! ! ! ! You should have received a copy of the GNU Lesser General ! ! Public License along with this library; if not, see ! ! <https://www.gnu.org/licenses/>. ! ! ! ! The webpage of the Wannier90 code is ! ! <https://www.wannier.org>. ! ! ! ! The Wannier90 code is hosted on GitHub ! ! <https://github.com/wannier-developers/wannier90> ! !------------------------------------------------------------! module w90_library_c !Fortran 2018: Assumed-length character dummy argument ‘keyword’ at (1) of procedure ‘cset_option_int’ with BIND(C) attribute use iso_c_binding use w90_library, only: w90_disentangle_f => w90_disentangle, & w90_get_centres_f => w90_get_centres, w90_get_gkpb_f => w90_get_gkpb, & w90_get_nn_f => w90_get_nn, w90_get_nnkp_f => w90_get_nnkp, & w90_get_proj_f => w90_get_proj, & w90_get_num_excl_bands_f => w90_get_num_excl_bands, & w90_get_excl_bands_f => w90_get_excl_bands, & w90_print_info_f => w90_print_info, & w90_get_spreads_f => w90_get_spreads, w90_input_setopt_ff => w90_input_setopt, & w90_input_reader_f => w90_input_reader, & w90_project_overlap_f => w90_project_overlap, & w90_set_eigval_f => w90_set_eigval, w90_set_m_local_f => w90_set_m_local, & w90_set_u_matrix_f => w90_set_u_matrix, w90_set_u_opt_f => w90_set_u_opt, & w90_wannierise_f => w90_wannierise, w90_set_option, & w90_set_comm_ff => w90_set_comm, lib_common_type, & w90_get_fortran_stderr, w90_get_fortran_stdout implicit none public type, bind(c) :: w90_data type(c_ptr) :: caddr end type contains subroutine w90_create(w90_obj) bind(c) !! return a c-pointer to a instance of the wannier90 library data structure type(lib_common_type), pointer :: common_data type(w90_data) :: w90_obj !if (c_associated(w90_obj%caddr)) return ! we can't distinguish an uninitialised pointer (junk) from valid one here; test is reliable. ! -> policy: this function *always* creates a new object allocate (common_data) w90_obj%caddr = c_loc(common_data) end subroutine subroutine w90_delete(w90_obj) bind(c) !! deallocates/clears a c-pointer to a instance of the wannier90 library data structure implicit none type(w90_data) :: w90_obj type(lib_common_type), pointer :: w90_fptr if (.not. c_associated(w90_obj%caddr)) return call c_f_pointer(w90_obj%caddr, w90_fptr) deallocate (w90_fptr) w90_obj%caddr = C_NULL_PTR end subroutine subroutine w90_get_nk(w90_obj, n) bind(c) ! return the number of k-points implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: n type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: ndat call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(n, ndat) ndat = w90_fptr%num_kpts end subroutine subroutine w90_get_nw(w90_obj, n) bind(c) ! return the number of wfs implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: n type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: ndat call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(n, ndat) ndat = w90_fptr%num_wann end subroutine subroutine w90_get_nn(w90_obj, n, ierr) bind(c) ! return the number of adjacent k-points in finite difference scheme implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: n type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: ndat integer(kind=c_int) :: istderr, istdout, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(n, ndat) call w90_get_nn_f(w90_fptr, ndat, istdout, istderr, ierr) end subroutine subroutine w90_get_gkpb(w90_obj, gkpb, ierr) bind(c) ! return the g-offset of adjacent k-points in finite difference scheme implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: gkpb type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: nfptr(:, :, :) integer(kind=c_int) :: istderr, istdout, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(gkpb, nfptr, [3, w90_fptr%num_kpts, w90_fptr%kmesh_info%nntot]) call w90_get_gkpb_f(w90_fptr, nfptr, istdout, istderr, ierr) end subroutine subroutine w90_get_nnkp(w90_obj, nnkp, ierr) bind(c) ! return the indexing of adjacent k-points in finite difference scheme implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: nnkp type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: nfptr(:, :) integer(kind=c_int) :: istderr, istdout, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(nnkp, nfptr, [w90_fptr%num_kpts, w90_fptr%kmesh_info%nntot]) call w90_get_nnkp_f(w90_fptr, nfptr, istdout, istderr, ierr) end subroutine subroutine w90_input_setopt_f(w90_obj, seedname, ierr) bind(c) ! specify parameters through the library interface implicit none type(w90_data), value :: w90_obj character(*, kind=c_char) :: seedname type(lib_common_type), pointer :: w90_fptr integer(kind=c_int) :: istderr, istdout, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_input_setopt_ff(w90_fptr, seedname, istdout, istderr, ierr) end subroutine subroutine w90_input_reader(w90_obj, ierr) bind(c) ! read (optional) parameters from .win file implicit none type(w90_data), value :: w90_obj type(lib_common_type), pointer :: w90_fptr integer(kind=c_int) :: istderr, istdout, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_input_reader_f(w90_fptr, istdout, istderr, ierr) end subroutine subroutine w90_project_overlap(w90_obj, ierr) bind(c) implicit none type(w90_data), value :: w90_obj type(lib_common_type), pointer :: w90_fptr integer(kind=c_int) :: istdout, istderr, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_project_overlap_f(w90_fptr, istdout, istderr, ierr) end subroutine subroutine w90_print_info(w90_obj, ierr) bind(c) implicit none type(w90_data), value :: w90_obj type(lib_common_type), pointer :: w90_fptr integer(kind=c_int) :: istdout, istderr, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_print_info_f(w90_fptr, istdout, istderr, ierr) end subroutine subroutine w90_set_eigval(w90_obj, eigval_cptr) bind(c) ! copy a pointer to eigenvalue data implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: eigval_cptr real(kind=c_double), pointer :: eigval_fptr(:, :) type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(eigval_cptr, eigval_fptr, [w90_fptr%num_bands, w90_fptr%num_kpts]) call w90_set_eigval_f(w90_fptr, eigval_fptr) end subroutine subroutine w90_set_m_local(w90_obj, m_cptr) bind(c) ! copy a pointer to m-matrix data implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: m_cptr complex(kind=c_double_complex), pointer :: fptr(:, :, :, :) type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(m_cptr, fptr, [w90_fptr%num_bands, w90_fptr%num_bands, w90_fptr%kmesh_info%nntot, w90_fptr%num_kpts]) call w90_set_m_local_f(w90_fptr, fptr) end subroutine subroutine w90_set_u_matrix(w90_obj, a_cptr) bind(c) ! copy pointer to u-matrix implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: a_cptr complex(kind=c_double_complex), pointer :: a_fptr(:, :, :) type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(a_cptr, a_fptr, [w90_fptr%num_wann, w90_fptr%num_wann, w90_fptr%num_kpts]) ! these are reversed wrt c call w90_set_u_matrix_f(w90_fptr, a_fptr) end subroutine subroutine w90_set_u_opt(w90_obj, a_cptr) bind(c) ! copy pointer to u-matrix (also used for initial projections) implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: a_cptr complex(kind=c_double_complex), pointer :: a_fptr(:, :, :) type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(a_cptr, a_fptr, [w90_fptr%num_bands, w90_fptr%num_wann, w90_fptr%num_kpts]) ! these are reversed wrt c call w90_set_u_opt_f(w90_fptr, a_fptr) end subroutine subroutine w90_disentangle(w90_obj, ierr) bind(c) implicit none type(w90_data), value :: w90_obj type(lib_common_type), pointer :: w90_fptr integer(kind=c_int) :: istdout, istderr, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_disentangle_f(w90_fptr, istdout, istderr, ierr) end subroutine subroutine w90_wannierise(w90_obj, ierr) bind(c) implicit none type(w90_data), value :: w90_obj type(lib_common_type), pointer :: w90_fptr integer(kind=c_int) :: istdout, istderr, ierr call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_wannierise_f(w90_fptr, istdout, istderr, ierr) end subroutine subroutine w90_get_centres(w90_obj, centres) bind(c) ! returns the centres of calulated mlwfs implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: centres type(lib_common_type), pointer :: w90_fptr real(kind=c_double), pointer :: fcentres(:, :) call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(centres, fcentres, [3, w90_fptr%num_wann]) call w90_get_centres_f(w90_fptr, fcentres) end subroutine subroutine w90_get_spreads(w90_obj, spreads) bind(c) ! returns the spreads of calulated mlwfs implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: spreads type(lib_common_type), pointer :: w90_fptr real(kind=c_double), pointer :: fspreads(:) call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(spreads, fspreads, [w90_fptr%num_wann]) call w90_get_spreads_f(w90_fptr, fspreads) end subroutine subroutine w90_get_nproj(w90_obj, n) bind(c) ! return the number of projectors implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: n type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: n_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(n, n_fptr) n_fptr = size(w90_fptr%proj_input) end subroutine subroutine w90_get_proj(w90_obj, n, site, l, m, s, rad, x, z, sqa, zona, ierr) bind(c) ! probes projectors configured in the library object implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: n, site, l, m, s, rad, x, z, sqa, zona integer(kind=c_int) :: ierr type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: n_fptr, l_fptr(:), m_fptr(:), s_fptr(:), rad_fptr(:) real(kind=c_double), pointer :: site_fptr(:, :), x_fptr(:, :), z_fptr(:, :), sqa_fptr(:, :), zona_fptr(:) integer(kind=c_int) :: nproj integer(kind=c_int) :: istderr, istdout call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(n, n_fptr) nproj = n_fptr call c_f_pointer(site, site_fptr, [3, nproj]) call c_f_pointer(l, l_fptr, [nproj]) call c_f_pointer(m, m_fptr, [nproj]) call c_f_pointer(s, s_fptr, [nproj]) call c_f_pointer(rad, rad_fptr, [nproj]) call c_f_pointer(x, x_fptr, [3, nproj]) call c_f_pointer(z, z_fptr, [3, nproj]) call c_f_pointer(sqa, sqa_fptr, [3, nproj]) call c_f_pointer(zona, zona_fptr, [nproj]) call w90_get_proj_f(w90_fptr, n_fptr, site_fptr, l_fptr, m_fptr, s_fptr, rad_fptr, x_fptr, z_fptr, sqa_fptr, zona_fptr, & istdout, istderr, ierr) end subroutine subroutine w90_get_num_excl_bands(w90_obj, num_excl_bands) bind(c) ! return the number of excluded bands implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: num_excl_bands type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: n_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(num_excl_bands, n_fptr) call w90_get_num_excl_bands_f(w90_fptr, n_fptr) end subroutine subroutine w90_get_excl_bands(w90_obj, excl_bands, ierr) bind(c) ! return the excluded bands implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: excl_bands type(lib_common_type), pointer :: w90_fptr integer(kind=c_int), pointer :: excl_bands_fptr(:) integer(kind=c_int), allocatable :: temp_excl(:) integer(kind=c_int) :: istderr, istdout, ierr integer :: nex call w90_get_fortran_stderr(istderr) call w90_get_fortran_stdout(istdout) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_get_num_excl_bands_f(w90_fptr, nex) if (nex == 0) then ! no excluded bands, just return an empty array return end if allocate (temp_excl(nex)) call w90_get_excl_bands_f(w90_fptr, temp_excl, istdout, istderr, ierr) ! copy to the output pointer call c_f_pointer(excl_bands, excl_bands_fptr, [nex]) excl_bands_fptr = temp_excl deallocate (temp_excl) end subroutine subroutine w90_set_option_double_f(w90_obj, keyword, cdble) bind(c) implicit none type(w90_data), value :: w90_obj character(*, kind=c_char) :: keyword real(kind=c_double), value :: cdble type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_set_option(w90_fptr, keyword, cdble) end subroutine subroutine w90_set_option_double1d_f(w90_obj, keyword, arg_cptr, x) bind(c) implicit none type(w90_data), value :: w90_obj character(*, kind=c_char) :: keyword type(c_ptr), value :: arg_cptr integer(kind=c_int), value :: x type(lib_common_type), pointer :: w90_fptr real(kind=c_double), pointer :: fptr(:) call c_f_pointer(arg_cptr, fptr, [x]) call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_set_option(w90_fptr, keyword, fptr) end subroutine subroutine w90_set_option_double2d_f(w90_obj, keyword, arg_cptr, x, y) bind(c) implicit none type(w90_data), value :: w90_obj character(*, kind=c_char) :: keyword type(c_ptr), value :: arg_cptr integer(kind=c_int), value :: x, y type(lib_common_type), pointer :: w90_fptr real(kind=c_double), pointer :: fptr(:, :) call c_f_pointer(arg_cptr, fptr, [y, x]) ! these are reversed wrt c call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_set_option(w90_fptr, keyword, fptr) end subroutine subroutine w90_set_option_int_f(w90_obj, keyword, cint) bind(c) implicit none type(w90_data), value :: w90_obj character(*, kind=c_char) :: keyword integer(kind=c_int), value :: cint type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_set_option(w90_fptr, keyword, cint) end subroutine subroutine w90_set_option_int1d_f(w90_obj, keyword, arg_cptr, x) bind(c) implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: arg_cptr character(*, kind=c_char) :: keyword integer(kind=c_int), value :: x integer(kind=c_int), pointer :: fptr(:) type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(arg_cptr, fptr, [x]) call w90_set_option(w90_fptr, keyword, fptr) end subroutine subroutine w90_set_option_int2d_f(w90_obj, keyword, arg_cptr, x, y) bind(c) implicit none type(w90_data), value :: w90_obj type(c_ptr), value :: arg_cptr character(*, kind=c_char) :: keyword integer(kind=c_int), value :: x, y integer(kind=c_int), pointer :: fptr(:, :) type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call c_f_pointer(arg_cptr, fptr, [y, x]) ! these are reversed wrt c call w90_set_option(w90_fptr, keyword, fptr) end subroutine subroutine w90_set_option_logical_f(w90_obj, keyword, boolarg) bind(c) implicit none type(w90_data), value :: w90_obj character(*, kind=c_char) :: keyword logical(kind=c_bool), value :: boolarg logical :: fbool type(lib_common_type), pointer :: w90_fptr fbool = boolarg call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_set_option(w90_fptr, keyword, fbool) end subroutine subroutine w90_set_option_text_f(w90_obj, keyword, text) bind(c) implicit none type(w90_data), value :: w90_obj character(*, kind=c_char) :: keyword character(*, kind=c_char) :: text type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_set_option(w90_fptr, keyword, text) end subroutine subroutine w90_set_option_text2d_f(w90_obj, keyword, text) bind(c) implicit none type(w90_data), value :: w90_obj character(*, kind=c_char), intent(in) :: keyword ! len=* automatically picks up the 'max_len' we set in CFI_establish character(len=*, kind=c_char), intent(in) :: text(:) type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) call w90_set_option(w90_fptr, keyword, text) end subroutine #ifdef W90_MPI subroutine w90_set_comm_f(w90_obj, comm) bind(c) #ifdef W90_MPI08 use mpi_f08 #endif implicit none #ifdef W90_MPIH include 'mpif.h' #endif integer(kind=c_int), intent(in) :: comm #ifdef W90_MPI08 type(mpi_comm) :: comm08 #endif type(w90_data), intent(in), value :: w90_obj type(lib_common_type), pointer :: w90_fptr call c_f_pointer(w90_obj%caddr, w90_fptr) #ifdef W90_MPI08 ! Manually assign the integer to the type's internal handle comm08%MPI_VAL = comm call w90_set_comm_ff(w90_fptr, comm08) #else call w90_set_comm_ff(w90_fptr, comm) #endif end subroutine #endif end module w90_library_c