LCOV - code coverage report
Current view: top level - src/78_effpot - m_lwf_potential.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 73.1 % 104 76
Test Date: 2026-11-12 07:43:35 Functions: 76.9 % 13 10
Branches: 51.1 % 178 91

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_lwf_potential
       2                 :             : !! NAME
       3                 :             : !! m_lwf_potential
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !! This module contains an LWF potential.
       7                 :             : !!
       8                 :             : !! Datatypes:
       9                 :             : !!
      10                 :             : !! Subroutines:
      11                 :             : !! TODO: add this when F2003 doc style is determined.
      12                 :             : !!
      13                 :             : !!
      14                 :             : !! COPYRIGHT
      15                 :             : !! Copyright (C) 2001-2026 ABINIT group (hexu)
      16                 :             : !! This file is distributed under the terms of the
      17                 :             : !! GNU General Public License, see ~abinit/COPYING
      18                 :             : !! or http://www.gnu.org/copyleft/gpl.txt .
      19                 :             : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      20                 :             : !!
      21                 :             : !! SOURCE
      22                 :             : 
      23                 :             : 
      24                 :             : #if defined HAVE_CONFIG_H
      25                 :             : #include "config.h"
      26                 :             : #endif
      27                 :             : 
      28                 :             : #include "abi_common.h"
      29                 :             : 
      30                 :             : 
      31                 :             : module m_lwf_potential
      32                 :             :   use defs_basis
      33                 :             :   use m_errors
      34                 :             :   use m_abicore
      35                 :             :   use m_abstract_potential, only: abstract_potential_t
      36                 :             :   use m_spmat_ndcoo, only: ndcoo_mat_t
      37                 :             :   use m_spmat_coo, only: COO_mat_t
      38                 :             :   use m_spmat_csr, only: CSR_mat_t
      39                 :             :   use m_spmat_spvec, only: sp_real_vec
      40                 :             :   use m_spmat_convert, only: spmat_convert
      41                 :             :   use m_multibinit_cell, only: mbcell_t, mbsupercell_t
      42                 :             :   use m_hashtable_strval, only: hash_table_t
      43                 :             :   use m_twobody_interaction, only: get_twobody_dEdx, get_twobody_delta_E
      44                 :             :   use m_multibinit_dataset, only: multibinit_dtset_type
      45                 :             :   use m_lattice_lwf_map, only: lwf_latt_coeff_t
      46                 :             :   implicit none
      47                 :             : !!***
      48                 :             : 
      49                 :             :   private
      50                 :             : 
      51                 :             :   type, public, extends(abstract_potential_t) :: lwf_potential_t
      52                 :             :      integer :: nlwf ! number of lwf
      53                 :             :      real(dp) :: ref_energy=0.0      ! reference energy
      54                 :             :      logical :: csr_mat_ready=.False.
      55                 :             :      type(COO_mat_t) :: coeff_coo  ! coefficient. A COO sparse matrix (3N*3N).
      56                 :             :      type(CSR_mat_t) :: coeff
      57                 :             :      type(NDCOO_mat_t) :: onebody_coeff ! onebody anharmonic
      58                 :             :      type(NDCOO_mat_t) :: coeff2 ! twobody anharmonic
      59                 :             : 
      60                 :             :      logical :: use_harmonic = .True.
      61                 :             :      !logical :: has_self_bound_term = .False.
      62                 :             :      !integer :: self_bound_order=0
      63                 :             :      !real(dp) :: self_bound_coeff=0.0_dp
      64                 :             : 
      65                 :             :      real(dp) :: beta
      66                 :             :      real(dp), allocatable :: coeff_diag(:)
      67                 :             : 
      68                 :             :      logical :: as_lattice_anharmonic=.False.
      69                 :             :      ! tmp arrays for forces and lwf
      70                 :             :      real(dp), allocatable :: lwf_force(:), lwf_amp(:)
      71                 :             :    contains
      72                 :             :      procedure :: initialize
      73                 :             :      procedure :: finalize
      74                 :             :      procedure :: use_as_lattice_anharmonic
      75                 :             :      procedure :: set_supercell
      76                 :             :      procedure :: set_ref_energy
      77                 :             :      procedure :: set_params
      78                 :             :      procedure :: calculate
      79                 :             :      procedure :: add_term
      80                 :             :      procedure :: convert_coeff_to_csr
      81                 :             :      procedure :: get_delta_E_lwf
      82                 :             :      procedure :: add_onebody_term
      83                 :             :      !procedure :: add_self_bound_term
      84                 :             :   end type lwf_potential_t
      85                 :             : 
      86                 :             : contains
      87                 :             : 
      88                 :             :   !-------------------------------------------------------------------!
      89                 :             :   ! initialize
      90                 :             :   ! Input:
      91                 :             :   !  natom: number of atoms
      92                 :             :   !-------------------------------------------------------------------!
      93                 :           1 :   subroutine initialize(self, nlwf)
      94                 :             :     class(lwf_potential_t), intent(inout) :: self
      95                 :             :     integer, intent(in) :: nlwf
      96                 :           1 :     self%has_lwf= .True.
      97                 :           1 :     self%is_null = .False.
      98                 :           1 :     self%label="lwf_potential"
      99                 :           1 :     self%nlwf=nlwf
     100                 :           1 :     self%ref_energy=0.0_dp
     101         [ +  + ]:           3 :     call self%coeff_coo%initialize(mshape= [self%nlwf, self%nlwf])
     102         [ +  + ]:           3 :     call self%onebody_coeff%initialize(mshape= [self%nlwf, -1])
     103         [ +  + ]:           3 :     call self%coeff2%initialize(mshape= [self%nlwf, self%nlwf])
     104                 :           1 :     self%csr_mat_ready=.False.
     105   [ -  +  +  -  :           3 :     ABI_MALLOC(self%coeff_diag, (self%nlwf))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     106                 :             : 
     107   [ -  +  +  -  :           2 :     ABI_MALLOC(self%lwf_force, (self%nlwf))
          -  +  -  +  -  
                      + ]
     108   [ -  +  +  -  :           2 :     ABI_MALLOC(self%lwf_amp, (self%nlwf))
          -  +  -  +  -  
                      + ]
     109                 :             : 
     110                 :           1 :   end subroutine initialize
     111                 :             : 
     112                 :             :   !-------------------------------------------------------------------!
     113                 :             :   ! Finalize
     114                 :             :   !-------------------------------------------------------------------!
     115                 :           1 :   subroutine finalize(self)
     116                 :             :     class(lwf_potential_t), intent(inout) :: self
     117                 :           1 :     self%has_displacement=.False.
     118                 :           1 :     call self%onebody_coeff%finalize()
     119                 :           1 :     call self%coeff2%finalize()
     120                 :           1 :     call self%abstract_potential_t%finalize()
     121                 :             : 
     122         [ -  + ]:           1 :     if (.not. self%csr_mat_ready) then
     123                 :           0 :        call self%coeff_coo%finalize()
     124                 :             :     else
     125                 :           1 :        call self%coeff%finalize()
     126                 :             :     end if
     127         [ +  - ]:           1 :     ABI_SFREE(self%coeff_diag)
     128                 :           1 :     self%nlwf=0
     129                 :           1 :     self%is_null=.True.
     130                 :           1 :     self%as_lattice_anharmonic=.False.
     131         [ +  - ]:           1 :     ABI_SFREE(self%lwf_force)
     132         [ +  - ]:           1 :     ABI_SFREE(self%lwf_amp)
     133                 :           1 :     self%csr_mat_ready=.False.
     134                 :           1 :   end subroutine finalize
     135                 :             : 
     136                 :           0 :   subroutine use_as_lattice_anharmonic(self)
     137                 :             :     class(lwf_potential_t), intent(inout) :: self
     138                 :           0 :     self%as_lattice_anharmonic=.True.
     139                 :           0 :     self%use_harmonic = .False.
     140                 :           0 :     self%has_displacement = .True.
     141                 :           0 :     self%has_lwf= .False.
     142                 :           0 :     self%is_null = .False.
     143                 :           0 :     self%label="latt_lwf_potential"
     144                 :           0 :   end subroutine use_as_lattice_anharmonic
     145                 :             : 
     146                 :             : 
     147                 :             : 
     148                 :             :   !===============================================================
     149                 :             :   !
     150                 :             :   !> @
     151                 :             :   !===============================================================
     152                 :             :   subroutine add_lattice_coeffs(self, ilwf, ilatt, val)
     153                 :             :     class(lwf_potential_t), intent(inout) :: self
     154                 :             :     integer , intent(in) :: ilwf, ilatt
     155                 :             :     real(dp) , intent(in) :: val
     156                 :             :     !call self%lwf_latt_coeffs(ilwf)%push(ilatt, val)
     157                 :             :     call self%supercell%lwf%lwf_latt_coeffs%coeffs%add_entry( [ilatt, ilwf], val)
     158                 :             :   end subroutine add_lattice_coeffs
     159                 :             : 
     160                 :             :   !-------------------------------------------------------------------!
     161                 :             :   ! Add a term to the potential
     162                 :             :   !-------------------------------------------------------------------!
     163                 :       67584 :   subroutine add_term(self, i,j, val)
     164                 :             :     class(lwf_potential_t), intent(inout) :: self
     165                 :             :     integer, intent(in) :: i, j
     166                 :             :     real(dp), intent(in) :: val
     167         [ +  + ]:      202752 :     call self%coeff_coo%add_entry([i,j], val)
     168                 :       67584 :   end subroutine add_term
     169                 :             : 
     170                 :        3072 :   subroutine add_onebody_term(self, i, order, val)
     171                 :             :     class(lwf_potential_t), intent(inout) :: self
     172                 :             :     integer, intent(in) :: i, order
     173                 :             :     real(dp), intent(in) :: val
     174         [ +  + ]:        9216 :     call self%onebody_coeff%add_entry([i, order], val)
     175                 :        3072 :   end subroutine add_onebody_term
     176                 :             : 
     177                 :             :   subroutine add_higher_order_term(self, i, j, orderi, orderj, val)
     178                 :             :     class(lwf_potential_t), intent(inout) :: self
     179                 :             :     integer, intent(in) :: i, j, orderi, orderj
     180                 :             :     real(dp), intent(in) :: val
     181                 :             :     call self%coeff2%add_entry([i,j, orderi, orderj], val)
     182                 :             :   end subroutine add_higher_order_term
     183                 :             : 
     184                 :       42000 :   subroutine convert_coeff_to_csr(self)
     185                 :             :     class(lwf_potential_t), intent(inout) :: self
     186         [ +  + ]:       42000 :     if (.not. self%csr_mat_ready) then
     187                 :             :        !call init_mpi_info(master, iam_master, my_rank, comm, nproc)
     188                 :             :        !if(iam_master) then
     189                 :           1 :        call spmat_convert(self%coeff_coo, self%coeff)
     190                 :           1 :        call self%coeff_coo%diag(self%coeff_diag)
     191                 :           1 :        call self%coeff_coo%finalize()
     192                 :             :        !endif
     193                 :             :        !call self%bilinear_csr_mat%sync(master=master, comm=comm, nblock=1)
     194                 :           1 :        self%csr_mat_ready=.True.
     195                 :             :        !call xmpi_bcast(self%csr_mat_ready, master, comm, ierr)
     196                 :             :     endif
     197                 :             : 
     198                 :       42000 :   end subroutine convert_coeff_to_csr
     199                 :             : 
     200                 :             : 
     201                 :             :   !-------------------------------------------------------------------!
     202                 :             :   ! Set the reference energy.
     203                 :             :   !-------------------------------------------------------------------!
     204                 :           0 :   subroutine set_ref_energy(self, ref_energy)
     205                 :             :     class(lwf_potential_t), intent(inout) :: self
     206                 :             :     real(dp), intent(in) :: ref_energy
     207                 :           0 :     self%ref_energy=ref_energy
     208                 :           0 :   end subroutine set_ref_energy
     209                 :             : 
     210                 :             :   !-------------------------------------------------------------------!
     211                 :             :   ! set_supercell
     212                 :             :   !  link the supercell with potential.
     213                 :             :   ! Inputs:
     214                 :             :   !   supercell: mbsupercell_t
     215                 :             :   !-------------------------------------------------------------------!
     216                 :           2 :   subroutine set_supercell(self, supercell)
     217                 :             :     class(lwf_potential_t), intent(inout) :: self
     218                 :             :     type(mbsupercell_t), target, intent(inout) :: supercell
     219                 :           2 :     self%supercell => supercell
     220                 :           2 :   end subroutine set_supercell
     221                 :             : 
     222                 :             : 
     223                 :             :   !-------------------------------------------------------------------!
     224                 :             :   ! calculate force and energy from harmonic potential
     225                 :             :   ! F= - IFC .matmul. displacement
     226                 :             :   ! E = 1/2 (-F) .dot. displacement = 1/2<disp|IFC|disp>
     227                 :             :   ! Input:
     228                 :             :   !   displacement: required.
     229                 :             :   !-------------------------------------------------------------------!
     230   [ -  +  -  -  :       42000 :   subroutine calculate(self, displacement, strain, spin, lwf, force, stress, bfield, lwf_force, energy, energy_table)
          -  -  +  -  +  
          -  -  +  -  +  
          -  -  -  -  +  
             -  +  -  -  
                      + ]
     231                 :             :     ! This function calculate the energy and its first derivative
     232                 :             :     ! the inputs and outputs are optional so that each effpot can adapt to its
     233                 :             :     ! own.
     234                 :             :     ! In principle, the 1st derivatives are only calculated if asked to (present). However, they can be computed if it is simply convinient to do.
     235                 :             :     class(lwf_potential_t), intent(inout) :: self  ! the effpot may save the states.
     236                 :             :     real(dp), optional, intent(inout) :: displacement(:,:), strain(:,:), spin(:,:), lwf(:)
     237                 :             :     real(dp), optional, intent(inout) :: force(:,:), stress(:,:), bfield(:,:), lwf_force(:), energy
     238                 :             :     type(hash_table_t),optional, intent(inout) :: energy_table
     239                 :             :     real(dp) :: etmp, val
     240                 :             :     integer :: i,ilwf, order
     241                 :             :     ! if present in input
     242                 :             :     ! calculate if required
     243                 :       42000 :     ABI_UNUSED_A(strain)
     244                 :       42000 :     ABI_UNUSED_A(spin)
     245                 :       42000 :     ABI_UNUSED_A(stress)
     246                 :       42000 :     ABI_UNUSED_A(bfield)
     247                 :             : 
     248                 :             :     !if(.not. present(lwf)) then
     249                 :             :     !    MSG_BUG("lwf not exist")
     250                 :             :     !end if
     251                 :             : 
     252                 :             : 
     253         [ -  + ]:       42000 :     if(self%as_lattice_anharmonic) then
     254                 :           0 :        call self%supercell%lwf%lwf_latt_coeffs%lattice_to_lwf_projection( displacement, lwf)
     255                 :             :     end if
     256                 :             : 
     257                 :             : 
     258         [ +  + ]:    43050000 :     self%lwf_force(:) =0.0_dp
     259                 :       42000 :     etmp=0.0_dp
     260                 :             :     ! Harmonic term
     261         [ +  - ]:       42000 :     if (self%use_harmonic) then
     262                 :       42000 :        call self%convert_coeff_to_csr()
     263   [ -  +  -  -  :       42000 :        call self%coeff%mv(lwf, self%lwf_force)
             -  -  -  + ]
     264         [ +  + ]:    43050000 :        etmp=etmp+0.5_dp * sum(self%lwf_force*lwf)
     265         [ +  + ]:    43050000 :        self%lwf_force(:) = -self%lwf_force(:)
     266                 :             :     end if
     267                 :             : 
     268                 :             :     ! self_bound_term as from the input parameters
     269                 :             :     !if (self%has_self_bound_term) then
     270                 :             :     !   self%lwf_force(:) = self%lwf_force(:) - &
     271                 :             :     !        & self%self_bound_coeff*self%self_bound_order* lwf**(self%self_bound_order-1)
     272                 :             :     !   etmp = etmp + &
     273                 :             :     !        & self%self_bound_coeff*sum(lwf**(self%self_bound_order))
     274                 :             :     !endif
     275                 :             : 
     276         [ +  - ]:       42000 :     if (self%onebody_coeff%nnz/= 0) then
     277         [ +  + ]:   129066000 :        do i =1, self%onebody_coeff%nnz
     278                 :   129024000 :           ilwf= self%onebody_coeff%ind%data(1, i)
     279                 :   129024000 :           order= self%onebody_coeff%ind%data(2, i)
     280                 :   129024000 :           val=self%onebody_coeff%val%data(i)
     281                 :   129024000 :           etmp= etmp + val*lwf(ilwf)**order
     282                 :   129066000 :           self%lwf_force(ilwf) =self%lwf_force(ilwf) - val*order*lwf(ilwf)**(order-1)
     283                 :             :        end do
     284                 :             :     end if
     285                 :             : 
     286                 :             :     !TODO: remove. For testing only
     287                 :             :     !etmp = etmp+ self%beta*sum(lwf(::2)**2 * lwf(1::2)**2)
     288                 :             : 
     289         [ -  + ]:       42000 :     if(self%as_lattice_anharmonic) then
     290                 :           0 :        call self%supercell%lwf%lwf_latt_coeffs%lwf_force_to_lattice(self%lwf_force, force)
     291                 :             :     else
     292         [ +  + ]:    43050000 :        lwf_force=lwf_force+self%lwf_force
     293                 :             :     end if
     294                 :             : 
     295         [ +  - ]:       42000 :     if (present(energy)) then
     296                 :       42000 :        energy=energy+etmp
     297                 :             :     endif
     298         [ +  - ]:       42000 :     if(present(energy_table)) then
     299                 :       42000 :        call energy_table%put(self%label, etmp)
     300                 :             :     endif
     301                 :       42000 :   end subroutine calculate
     302                 :             : 
     303                 :             :   !----------------------------------------------------------------------
     304                 :             :   !> @brief get_delta_E_lwf: calculate the energy difference when a given lwf
     305                 :             :   !> is changed. This is to be used for spin Monte Carlo. Currently the
     306                 :             :   !> only supported is the spin model.
     307                 :             :   !>
     308                 :             :   !> @param[in]  lwf: lwf of full structure. array of (nlwf)
     309                 :             :   !> @param[in]  ilwf: the index of spin changed. integer
     310                 :             :   !> @param[in]  lwf_new: the new value of the changed spin.
     311                 :             :   !> @param[out] deltaE: the energy difference
     312                 :             :   !----------------------------------------------------------------------
     313         [ #  # ]:           0 :   subroutine get_delta_E_lwf(self, lwf, ilwf, lwf_new, deltaE)
     314                 :             :     class(lwf_potential_t), intent(inout) :: self  ! the effpot may save the states.
     315                 :             :     real(dp),  intent(inout) :: lwf(:),  lwf_new
     316                 :             :     integer,  intent(in) :: ilwf
     317                 :             :     real(dp), intent(inout) :: deltaE
     318                 :             :     real(dp) :: tmp, dlwf, lold
     319                 :             : 
     320                 :           0 :     lold=lwf(ilwf)
     321                 :           0 :     dlwf=lwf_new-lold
     322                 :           0 :     lwf(ilwf) = lwf_new
     323                 :             : 
     324                 :           0 :     call self%convert_coeff_to_csr()
     325                 :             : 
     326                 :           0 :     deltaE=0.0_dp
     327                 :           0 :     tmp=0.0_dp
     328   [ #  #  #  #  :           0 :     call self%coeff%mv_one_row(ilwf, lwf, tmp)
             #  #  #  # ]
     329                 :           0 :     deltaE=deltaE+ tmp*dlwf - 0.5* self%coeff_diag(ilwf)*dlwf*dlwf
     330                 :             : 
     331                 :             :     ! bound term
     332                 :             :     !if (self%has_self_bound_term) then
     333                 :             :     !   deltaE= deltaE+ &
     334                 :             :     !        & self%self_bound_coeff*(lwf_new**(self%self_bound_order) &
     335                 :             :     !        & - lold**(self%self_bound_order))
     336                 :             :     !! Adding x^6 and x^8 for VO2
     337                 :             :     !    deltaE=deltaE -1.1344*(lwf_new**6-lold**6) + 0.438*(lwf_new**8-lold**8)
     338                 :             :     !end if
     339                 :             : 
     340                 :             :     ! (Q1 Q2)^2 term
     341                 :             :    ! if(modulo(ilwf, 2)==0) then
     342                 :             :    !    deltaE=deltaE+ self%beta*((lwf_new**2- lold**2)*lwf(ilwf-1)**2)
     343                 :             :    ! else
     344                 :             :    !    deltaE=deltaE+ self%beta*((lwf_new**2- lold**2)*lwf(ilwf+1)**2)
     345                 :             :    ! endif
     346                 :             : 
     347                 :             :     ! if (self%onebody_coeff%nnz/= 0) then
     348                 :             :     !    do i =1, self%onebody_coeff%nnz
     349                 :             :     !       ilwf= self%onebody_coeff%ind%data(i, 1)
     350                 :             :     !       order= self%onebody_coeff%ind%data(i, 2)
     351                 :             :     !       val=self%onebody_coeff%val%data(i)
     352                 :             :     !       deltaE= deltaE + val*self%lwf_amp(ilwf)**order
     353                 :             :     !       self%lwf_force(ilwf) =self%lwf_force(ilwf) - val*order*self%lwf_amp(ilwf)
     354                 :             :     !    end do
     355                 :             :     ! end if
     356                 :             : 
     357         [ #  # ]:           0 :     if(modulo(ilwf, 2)==0) then
     358                 :           0 :        deltaE=deltaE+ self%beta*((lwf_new**2- lold**2)*lwf(ilwf-1)**2)
     359                 :             :     else
     360                 :           0 :        deltaE=deltaE+ self%beta*((lwf_new**2- lold**2)*lwf(ilwf+1)**2)
     361                 :             :     endif
     362                 :             : 
     363                 :           0 :     lwf(ilwf)=lwf(ilwf)-dlwf
     364                 :           0 :   end subroutine get_delta_E_lwf
     365                 :             : 
     366                 :             :   !subroutine add_self_bound_term(self, order, coeff)
     367                 :             :   !  class(lwf_potential_t), intent(inout) :: self
     368                 :             :   !  integer, intent(in) :: order
     369                 :             :   !  real(dp), intent(in) :: coeff
     370                 :             :   !  if (order /= 0) then
     371                 :             :   !     self%has_self_bound_term=.True.
     372                 :             :   !     self%self_bound_order=order
     373                 :             :   !     self%self_bound_coeff=coeff
     374                 :             :   !  end if
     375                 :             :   !end subroutine add_self_bound_term
     376                 :             : 
     377                 :             :   !----------------------------------------------------------------------
     378                 :             :   !> @brief set_params: set the parameters from input file parameters
     379                 :             :   !>
     380                 :             :   !> @param[in]  params: multibinit_dtset_type: from input file
     381                 :             :   !----------------------------------------------------------------------
     382                 :           1 :   subroutine set_params(self, params)
     383                 :             :     class(lwf_potential_t), intent(inout) :: self
     384                 :             :     type(multibinit_dtset_type), intent(inout) :: params
     385                 :           1 :     self%beta=params%spin_damping
     386                 :           1 :   end subroutine set_params
     387                 :             : 
     388                 :             : 
     389   [ +  +  -  +  :           3 : end module m_lwf_potential
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
             -  +  -  + ]
        

Generated by: LCOV version 2.3-1