LCOV - code coverage report
Current view: top level - src/78_effpot - m_lattice_io_netcdf.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 87.8 % 123 108
Test Date: 2026-09-19 15:24:51 Functions: 77.8 % 9 7

            Line data    Source code
       1              : !!****m* ABINIT/m_lattice_harmonic_primitive_potential
       2              : !! NAME
       3              : !! m_lattice_harmonic_primitive_potential
       4              : !!
       5              : !! FUNCTION
       6              : !! This module contains the example lattice primitive potential. It is not the
       7              : !! one really used. The purpose of this is to show how to extend multibinit
       8              : !! to new degree of freedom
       9              : !!
      10              : !! Datatypes:
      11              : !!  lattice_harmonic_primitive_potential_t
      12              : !!
      13              : !! Subroutines:
      14              : !!
      15              : !! COPYRIGHT
      16              : !! Copyright (C) 2001-2026 ABINIT group (hexu)
      17              : !! This file is distributed under the terms of the
      18              : !! GNU General Public License, see ~abinit/COPYING
      19              : !! or http://www.gnu.org/copyleft/gpl.txt .
      20              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      21              : !!
      22              : !! SOURCE
      23              : 
      24              : 
      25              : #if defined HAVE_CONFIG_H
      26              : #include "config.h"
      27              : #endif
      28              : #include "abi_common.h"
      29              : 
      30              : module m_lattice_harmonic_primitive_potential
      31              :   use, intrinsic :: iso_c_binding
      32              :   !use m_dynamic_array, only: int_array_type, real_array_type, int2d_array_type
      33              :   use defs_basis
      34              :   use m_abicore
      35              :   use m_errors
      36              :   use m_nctk
      37              : #if defined HAVE_NETCDF
      38              :   use netcdf
      39              : #endif
      40              :   use m_xmpi
      41              :   use m_mathfuncs, only: eigensh
      42              :   use m_multibinit_dataset, only: multibinit_dtset_type
      43              :   use m_multibinit_cell, only: mbcell_t, mbsupercell_t
      44              :   use m_primitive_potential, only: primitive_potential_t
      45              :   use m_abstract_potential, only: abstract_potential_t
      46              :   use m_dynamic_array, only: int2d_array_type
      47              :   use m_supercell_maker, only: supercell_maker_t
      48              :   use m_spmat_ndcoo, only: ndcoo_mat_t
      49              :   use m_lattice_harmonic_potential, only: lattice_harmonic_potential_t
      50              :   implicit none
      51              :   private
      52              :   !!***
      53              : 
      54              : 
      55              :   !-------------------------------------------------------------------!
      56              :   ! An harmonic potential which has only the IFC (with no dipole-dipole)
      57              :   !
      58              :   ! IFC is written in a coefficient matrix M(R, i, j)=val
      59              :   !-------------------------------------------------------------------!
      60              :   type, public, extends(primitive_potential_t) :: lattice_harmonic_primitive_potential_t
      61              :      integer :: natom    ! number of atoms
      62              :      type(ndcoo_mat_t) :: coeff  !  A N-dimensional COO matrix.
      63              :                                  !  The indices are (ind_R, i, j). Note that xyz is included in i and j.
      64              :      integer, allocatable :: Rlist(:,:) ! The list of R points (3, number of R-points)
      65              :                                         !. Rlist(:, ind_R) is a R-vector.
      66              :      real(dp) :: ref_energy=0.0                  ! reference energy
      67              :    contains
      68              :      procedure:: initialize
      69              :      procedure:: finalize
      70              :      procedure :: load_from_files   ! load potential from files listed in files file
      71              :      procedure :: load_from_netcdf  ! load potential from a netcdf file
      72              :      procedure:: fill_supercell     ! fill a supercell potential
      73              :      procedure :: get_hamk          ! generate hamiltonian for one k point.
      74              :      procedure :: get_eigen         ! eigen values and eigen vectors
      75              :   end type lattice_harmonic_primitive_potential_t
      76              : 
      77              : contains
      78              : 
      79              :   !-------------------------------------------------------------------!
      80              :   ! Initialize
      81              :   !  Input:
      82              :   !    primcell: the reference primitive cell.
      83              :   !-------------------------------------------------------------------!
      84            5 :   subroutine initialize(self, primcell)
      85              :     class(lattice_harmonic_primitive_potential_t), intent(inout) :: self
      86              :     type(mbcell_t), target, intent(inout) :: primcell
      87              :     !integer, intent(in) :: nspin
      88            5 :     self%primcell=>primcell
      89            5 :     self%label="lattice_harmonic_primitive_potential"
      90            5 :     self%has_spin=.False.
      91            5 :     self%has_displacement=.True.
      92            5 :     self%has_strain=.False.
      93            5 :     self%has_lwf=.False.
      94            5 :   end subroutine initialize
      95              : 
      96              : 
      97              :   !-------------------------------------------------------------------!
      98              :   ! Finalize
      99              :   !-------------------------------------------------------------------!
     100            5 :   subroutine finalize(self)
     101              :     class(lattice_harmonic_primitive_potential_t), intent(inout) :: self
     102            5 :     call self%coeff%finalize()
     103            5 :     ABI_FREE(self%Rlist)
     104            5 :     nullify(self%primcell)
     105            5 :     self%natom=0
     106            5 :     self%label="Destroyed lattice_harmonic_primitive_potential"
     107            5 :     call self%primitive_potential_t%finalize()
     108            5 :   end subroutine finalize
     109              : 
     110              : 
     111              :   !-------------------------------------------------------------------!
     112              :   ! Load from files:
     113              :   !> params: parameters
     114              :   !> fnames: file names from files file
     115              :   !-------------------------------------------------------------------!
     116            5 :   subroutine load_from_files(self, params, fnames)
     117              :     class(lattice_harmonic_primitive_potential_t), intent(inout) :: self
     118              :     type(multibinit_dtset_type), intent(in) :: params
     119              :     character(len=fnlen), intent(in) :: fnames(:)
     120              :     ABI_UNUSED(fnames)
     121            5 :     if(trim(params%latt_pot_fname)=='') then
     122            0 :        call self%load_from_netcdf(fnames(3))
     123              :     else
     124            5 :         call self%load_from_netcdf(params%latt_pot_fname)
     125              :     end if
     126            5 :   end subroutine load_from_files
     127              : 
     128              :   !-------------------------------------------------------------------!
     129              :   ! load potential from netcdf file
     130              :   ! Note that the lattic part of the primitive cell is also loaded.
     131              :   ! Input:
     132              :   !  fname: filename
     133              :   !-------------------------------------------------------------------!
     134            5 :   subroutine load_from_netcdf(self, fname)
     135              :     class(lattice_harmonic_primitive_potential_t), intent(inout) :: self
     136              :     character(len=fnlen), intent(in) :: fname
     137              :     integer :: ncid, ierr
     138              :     integer :: iR, nR, natom, natom3
     139              :     real(dp) :: ref_energy
     140              :     real(dp) :: cell(3,3)
     141            5 :     real(dp), allocatable :: xcart(:,:), masses(:)
     142            5 :     integer, allocatable :: zion(:)
     143            5 :     real(dp), allocatable :: ifc_vallist(:,:,:)
     144              :     integer :: varid, i, j
     145              : #if defined HAVE_NETCDF
     146            5 :     ierr=nf90_open(trim(fname), NF90_NOWRITE, ncid)
     147            5 :     NCF_CHECK_MSG(ierr, "Open netcdf file "//trim(fname))
     148              : 
     149            5 :     ierr=nctk_get_dim(ncid, "ifc_nR" , nR)
     150            5 :     ierr=nctk_get_dim(ncid, "natom", natom)
     151            5 :     ierr=nctk_get_dim(ncid, "natom3", natom3)
     152              : 
     153              : 
     154           15 :     ABI_MALLOC(masses, (natom))
     155           15 :     ABI_MALLOC(xcart, (3, natom))
     156           15 :     ABI_MALLOC(zion,(natom))
     157              : 
     158           25 :     ABI_MALLOC(ifc_vallist, (natom3, natom3, nR))
     159           15 :     ABI_MALLOC(self%Rlist,(3, nR))
     160              : 
     161              : 
     162            5 :     ierr =nf90_inq_varid(ncid, "ref_energy", varid)
     163            5 :     NCF_CHECK_MSG(ierr, "ref_energy")
     164            5 :     ierr = nf90_get_var(ncid, varid, ref_energy)
     165            5 :     NCF_CHECK_MSG(ierr, "ref_energy")
     166              : 
     167              : 
     168            5 :     ierr =nf90_inq_varid(ncid, "ref_masses", varid)
     169            5 :     NCF_CHECK_MSG(ierr, "ref_masses")
     170            5 :     ierr = nf90_get_var(ncid, varid, masses)
     171            5 :     NCF_CHECK_MSG(ierr, "ref_masses")
     172              : 
     173            5 :     ierr =nf90_inq_varid(ncid, "ref_xcart", varid)
     174            5 :     NCF_CHECK_MSG(ierr, "ref_xcart")
     175            5 :     ierr = nf90_get_var(ncid, varid, xcart)
     176            5 :     NCF_CHECK_MSG(ierr, "ref_xcart")
     177              : 
     178            5 :     ierr =nf90_inq_varid(ncid, "ref_cell", varid)
     179            5 :     NCF_CHECK_MSG(ierr, "rec_cell")
     180            5 :     ierr = nf90_get_var(ncid, varid, cell)
     181            5 :     NCF_CHECK_MSG(ierr, "ref_cell")
     182              : 
     183            5 :     ierr =nf90_inq_varid(ncid, "ref_zion", varid)
     184            5 :     NCF_CHECK_MSG(ierr, "ref_zion")
     185            5 :     ierr = nf90_get_var(ncid, varid, zion)
     186            5 :     NCF_CHECK_MSG(ierr, "ref_zion")
     187              : 
     188              :     ! Unit conversions
     189            5 :     ref_energy = ref_energy * eV_Ha
     190           30 :     masses(:)  = masses(:) * amu_emass
     191           65 :     cell(:,:) = cell(:,:) / Bohr_Ang
     192          105 :     xcart(:,:) = xcart(:,:) /Bohr_Ang
     193              : 
     194            5 :     self%natom=natom
     195            5 :     self%ref_energy=ref_energy
     196            5 :     call self%primcell%set_lattice(natom, cell, xcart, masses, zion)
     197              : 
     198           20 :     call self%coeff%initialize([ nR, natom3, natom3 ])
     199            5 :     ierr =nf90_inq_varid(ncid, "ifc_Rlist", varid)
     200            5 :     NCF_CHECK_MSG(ierr, "ifc_Rlist")
     201            5 :     ierr = nf90_get_var(ncid, varid, self%Rlist)
     202            5 :     NCF_CHECK_MSG(ierr, "ifc_Rlist")
     203              : 
     204            5 :     ierr =nf90_inq_varid(ncid, "ifc_vallist", varid)
     205            5 :     NCF_CHECK_MSG(ierr, "ifc_vallist")
     206            5 :     ierr = nf90_get_var(ncid, varid, ifc_vallist)
     207            5 :     NCF_CHECK_MSG(ierr, "ifc_vallist")
     208              : 
     209        32540 :     ifc_vallist(:,:,:) = ifc_vallist(:,:,:) * eV_Ha * (Bohr_Ang * Bohr_Ang)
     210              : 
     211          140 :     do iR =1, nR
     212         2165 :        do i=1 , natom3
     213        32535 :           do j=1, natom3
     214        32400 :              if (abs(ifc_vallist(j, i, iR))>1e-3) then
     215              :                 ! NOTE: in fortran the order of index in reversed when reading netcdf array.
     216        11460 :                 call self%coeff%add_entry([iR, i, j], ifc_vallist(j, i, iR))
     217              :              end if
     218              :           end do
     219              :        end do
     220              :     end do
     221              : 
     222            5 :     ierr=nf90_close(ncid)
     223            5 :     NCF_CHECK_MSG(ierr, "Close netcdf file")
     224              : 
     225            5 :     ABI_FREE(masses)
     226            5 :     ABI_FREE(xcart)
     227            5 :     ABI_FREE(zion)
     228            5 :     ABI_FREE(ifc_vallist)
     229              : #else
     230              :     NETCDF_NOTENABLED_ERROR()
     231              : #endif
     232              : 
     233            5 :   end subroutine load_from_netcdf
     234              : 
     235              : 
     236              :   !-------------------------------------------------------------------!
     237              :   !Fill supercell
     238              :   ! Inputs:
     239              :   !  scmaker : supercell_maker_t
     240              :   ! Output:
     241              :   !  scpot: a class pointer to an ABSTRACT potential.
     242              :   !         Not a harmonic potential because this is inherited from
     243              :   !         an abstract_primitive_potential_t, which doesn't know
     244              :   !         the type of the supercell potential.
     245              :   !
     246              :   !-------------------------------------------------------------------!
     247            5 :   subroutine fill_supercell(self, scmaker, params, scpot, supercell)
     248              :     use m_spmat_convert, only: COO_to_dense
     249              : 
     250              :     class(lattice_harmonic_primitive_potential_t) , intent(inout) :: self
     251              :     type(supercell_maker_t),                        intent(inout) :: scmaker
     252              :     type(multibinit_dtset_type),                    intent(inout) :: params
     253              :     class(abstract_potential_t), pointer,           intent(inout) :: scpot
     254              :     type(mbsupercell_t), target :: supercell
     255              : 
     256              :     integer :: natom, sc_natom
     257              :     integer :: inz, iR, R(3), i, j, icell
     258            5 :     integer, allocatable :: ilist_sc(:), jlist_sc(:), Rlist_sc(:,:)
     259              :     real(dp):: val
     260              : 
     261            5 :     ABI_UNUSED_A(params)
     262              : 
     263              : 
     264            5 :     natom=self%natom
     265            5 :     sc_natom= natom* scmaker%ncells
     266              : 
     267              :     !! NOTE: the code below can be used as a pattern to build supercell from primitivecell.
     268              :     ! Step 1: allocate the scpot as a corresponding supercell potential
     269            5 :     ABI_MALLOC_TYPE_SCALAR(lattice_harmonic_potential_t, scpot)
     270              :     ! Fortran does not know the functions specific to the derived class pointer.
     271              :     ! Only the ones inheritated from abstract class,
     272              :     ! unless select type is used:
     273              :     select type(scpot)
     274              :     type is (lattice_harmonic_potential_t)
     275            5 :        call scpot%initialize(sc_natom)
     276            5 :        call scpot%set_supercell(supercell)
     277              :        ! IFC is an COO_mat_t, which has the index of R1, R2, R3, i, j and the value of val
     278              :        ! list of index R: coeff%ind%data(1, 1:coeff%nnz)
     279              :        ! list of i: coeff%ind%data(2, 1:coeff%nnz)
     280              :        ! list of j: coeff%ind%data(3, 1:coeff%nnz)
     281              :        ! IFC: (ind) = val
     282         2870 :        do inz =1 , self%coeff%nnz
     283              :           ! For each non-zero entry in the coeff matrix
     284              :           ! get the R, i, and j, val
     285         2865 :           iR=self%coeff%ind%data(1,inz)
     286        11460 :           R(:) = self%Rlist(:, iR)
     287         2865 :           i=self%coeff%ind%data(2, inz)
     288         2865 :           j=self%coeff%ind%data(3, inz)
     289         2865 :           val=self%coeff%val%data(inz)
     290              :           ! translate i to i in supercell.
     291              :           ! No need to allocate, it is done by trans_i . but remember to deallocate!
     292              :           ! nbasis is the number in one primitive cell.
     293              :           ! e.g. there are 3*natom possible i (3: x, y, z) in each primitive cell.
     294         2865 :           call scmaker%trans_i(nbasis=self%natom*3, i=i, i_sc=ilist_sc )
     295              :           ! translate j, Rj to supercell.
     296         2865 :           call scmaker%trans_j_and_Rj(nbasis=self%natom*3, j=j, Rj=R, j_sc=jlist_sc, Rj_sc=Rlist_sc)
     297              :           ! values are repeated in cells
     298       534614 :           do icell=1, scmaker%ncells
     299       534609 :              call scpot%add_term(ilist_sc(icell), jlist_sc(icell), val )
     300              :           end do
     301              :        end do
     302              : 
     303           10 :        call scpot%set_ref_energy(self%ref_energy * scmaker%ncells)
     304              : 
     305              :        ! Test the phonon energy
     306              :        !call COO_to_dense(scpot%coeff, real_sc_evecs)
     307              :        !sc_evecs(:,:) = real_sc_evecs(:,:)
     308              :        !call eigensh(sc_evals, sc_evecs)
     309              : 
     310              :     end select
     311              : 
     312              : 
     313            5 :     ABI_SFREE(ilist_sc)
     314            5 :     ABI_SFREE(jlist_sc)
     315            5 :     ABI_SFREE(Rlist_sc)
     316              : 
     317            5 :     ABI_UNUSED_A(params)
     318              : 
     319            5 :   end subroutine fill_supercell
     320              : 
     321              : 
     322              :   !-------------------------------------------------------------------!
     323              :   ! calculate hamiltonian at k point (or more precisely, q point)
     324              :   ! H_ij(k) = sum_R H_ij(R) exp( i2pi k.dot.R)
     325              :   !-------------------------------------------------------------------!
     326            0 :   subroutine get_hamk(self, kpoint, hamk)
     327              :     class(lattice_harmonic_primitive_potential_t), intent(in) :: self
     328              :     real(dp), intent(in) :: kpoint(3)
     329              :     complex(dp), intent(inout) :: hamk(:,:)
     330              :     integer :: inz, iR, R(3), i, j
     331              :     real(dp) :: val
     332            0 :     hamk(:,:) = cmplx(0.0,0.0)
     333            0 :     do inz =1, self%coeff%nnz
     334            0 :        iR=self%coeff%ind%data(1,inz)
     335            0 :        R(:) = self%Rlist(:, iR)
     336            0 :        i=self%coeff%ind%data(2, inz)
     337            0 :        j=self%coeff%ind%data(3, inz)
     338            0 :        val=self%coeff%val%data(inz)
     339            0 :        hamk(i, j) =hamk(i, j) + val*exp(cmplx(0.0,2.0) *pi * dot_product(kpoint, R))
     340              :     end do
     341            0 :   end subroutine get_hamk
     342              : 
     343              :   !-------------------------------------------------------------------!
     344              :   !calculate eigenvalue and eigen vector
     345              :   !-------------------------------------------------------------------!
     346            0 :   subroutine get_eigen(self, kpoint, evals, evecs)
     347              :     class(lattice_harmonic_primitive_potential_t), intent(in) :: self
     348              :     real(dp), intent(in) :: kpoint(3)
     349              :     real(dp), intent(inout) :: evals(:)
     350              :     complex(dp), intent(inout) :: evecs(:,:)
     351            0 :     call self%get_hamk(kpoint, evecs)
     352              :     ! The evecs array is reused both as the matrix and eigenvectors.
     353            0 :     call eigensh(evals, evecs)
     354            0 :   end subroutine get_eigen
     355              : 
     356           20 : end module m_lattice_harmonic_primitive_potential
        

Generated by: LCOV version 2.3-1