LCOV - code coverage report
Current view: top level - src/78_effpot - m_lwf_mc_mover.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 65 0
Test Date: 2026-09-21 13:49:52 Functions: 0.0 % 10 0

            Line data    Source code
       1              : !!****m* ABINIT/m_lwf_mc_mover
       2              : !! NAME
       3              : !! m_lwf_mc_mover
       4              : !!
       5              : !! FUNCTION
       6              : !! This module contains the lwf Markov chain Monte Carlo functions for lwf mover .
       7              : !!
       8              : !!
       9              : !! Datatypes:
      10              : !!
      11              : !! * lwf_mc_t : MCMC. It defines how to move lwfs in one step,
      12              : !! attempt function: whether to accept move
      13              : !! accecpt/reject method which define what to do if move is
      14              : !! accepted or rejected!! .
      15              : !!
      16              : !! Subroutines:
      17              : !! TODO: add this when F2003 doc style is determined.
      18              : !!
      19              : !!
      20              : !! COPYRIGHT
      21              : !! Copyright (C) 2001-2026 ABINIT group (hexu)
      22              : !! This file is distributed under the terms of the
      23              : !! GNU General Public License, see ~abinit/COPYING
      24              : !! or http://www.gnu.org/copyleft/gpl.txt .
      25              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      26              : !!
      27              : !! SOURCE
      28              : 
      29              : #if defined HAVE_CONFIG_H
      30              : #include "config.h"
      31              : #endif
      32              : #include "abi_common.h"
      33              :     module m_lwf_mc_mover
      34              :     use defs_basis
      35              :     use m_abicore
      36              :     use m_errors
      37              :     use m_abstract_potential, only: abstract_potential_t
      38              :     use m_random_xoroshiro128plus, only: rng_t
      39              :     use m_hashtable_strval, only: hash_table_t
      40              :     use m_multibinit_dataset, only: multibinit_dtset_type
      41              :     use m_lwf_mover, only: lwf_mover_t
      42              :     use m_multibinit_cell, only: mbcell_t, mbsupercell_t
      43              :     implicit none
      44              : !!***
      45              :     private
      46              : 
      47              :     !----------------------------------------------------------------------
      48              :     !> @brief An helper type to run lwf dynamics
      49              :     ! The Metropolis-Hasting algorithm is used.
      50              :     !----------------------------------------------------------------------
      51              :     type,public, extends(lwf_mover_t) :: lwf_mc_t
      52              :        real(dp) :: avg_amp! an angle to rotate by average
      53              :        real(dp) ::  deltaE ! energy and the change of energy when change one lwf
      54              :        real(dp) :: lwf_new, lwf_old! energy and the change of energy when change one lwf
      55              :        real(dp) :: beta  ! 1/(kb T)
      56              :        integer :: nstep  ! number of steps
      57              :        integer :: imove ! index of lwf to be moved
      58              :        integer :: naccept  ! number of accepted steps
      59              :        integer :: nattempt
      60              :      contains
      61              :        procedure :: initialize
      62              :        procedure :: finalize
      63              :        procedure, private :: attempt
      64              :        procedure, private :: accept
      65              :        procedure, private :: reject
      66              :        procedure  :: run_one_step
      67              :        procedure :: set_temperature
      68              :        procedure, private :: run_one_mc_step
      69              :     end type lwf_mc_t
      70              : 
      71              : 
      72              :   contains
      73              : 
      74            0 :     subroutine initialize(self, params, supercell, rng)
      75              :       class(lwf_mc_t), intent(inout) :: self
      76              :       type(multibinit_dtset_type),target, intent(in) :: params
      77              :       type(mbsupercell_t),target, intent(in) :: supercell
      78              :       type(rng_t), target, intent(in) :: rng
      79            0 :       call self%lwf_mover_t%initialize(params, supercell, rng)
      80            0 :       self%nstep=self%nlwf
      81            0 :       self%avg_amp=params%lwf_mc_avg_amp
      82            0 :       self%temperature=params%lwf_temperature
      83            0 :       self%beta=1.0/self%temperature ! Kb in a.u. is 1.
      84            0 :       self%lwf_new=0.0_dp
      85            0 :       self%lwf_old=0.0_dp
      86            0 :       self%nattempt=0
      87            0 :       self%naccept=0
      88            0 :     end subroutine initialize
      89              : 
      90              :     !----------------------------------------------------------------------
      91              :     !> @brief finalize
      92              :     !----------------------------------------------------------------------
      93            0 :     subroutine finalize(self)
      94              :       class(lwf_mc_t), intent(inout) :: self
      95            0 :       call self%lwf_mover_t%finalize()
      96            0 :       self%nstep=0
      97            0 :       self%avg_amp=0.0
      98            0 :       self%temperature=0.0
      99            0 :       self%beta=0.0
     100            0 :     end subroutine finalize
     101              : 
     102            0 :     subroutine set_temperature(self, temperature)
     103              :       class(lwf_mc_t), intent(inout) :: self
     104              :       real(dp), intent(in) :: temperature
     105            0 :       call self%lwf_mover_t%set_temperature(temperature)
     106            0 :       self%temperature=temperature
     107            0 :       self%beta=1.0/self%temperature ! Kb in a.u. is 1.
     108            0 :     end subroutine set_temperature
     109              : 
     110              : 
     111              :     !----------------------------------------------------------------------
     112              :     !> @brief run one monte carlo step
     113              :     !> @param[in]   rngL rundom number generator
     114              :     !> @param[in] effpot: effective lwf potential
     115              :     !----------------------------------------------------------------------
     116            0 :    subroutine run_one_mc_step(self,  effpot)
     117              :      class(lwf_mc_t) :: self
     118              :      class(abstract_potential_t), intent(inout) :: effpot
     119              :      real(dp) :: r
     120              : 
     121              :      ! try to change lwf
     122            0 :      r=self%attempt(self%rng, effpot)
     123              :      ! metropolis-hastings
     124            0 :      self%nattempt=self%nattempt+1
     125            0 :      if(self%rng%rand_unif_01()< min(1.0_dp, r) .and. abs(self%lwf_new)<0.5 ) then
     126            0 :         self%naccept=self%naccept+1
     127            0 :         call self%accept()
     128              :      else
     129            0 :         call self%reject()
     130              :      end if
     131            0 :    end subroutine run_one_mc_step
     132              : 
     133              : 
     134              :   !-------------------------------------------------------------------!
     135              :   !> @brief: Run_one_step
     136              :   !>   effpot: the potential (which do the calculation of E and dE/dvar)
     137              :   !> param[in]: effpot
     138              :   !> param[in]: (optional) displacement
     139              :   !> param[in]: (optional) strain
     140              :   !> param[in]: (optional) spin
     141              :   !> param[in]: (optional) lwf
     142              :   ! NOTE: No need to pass the variable already saved in the mover.
     143              :   !     e.g. For spin mover, do NOT pass the spin to it.
     144              :   !    The other variables are only required if there is coupling with
     145              :   !    the mover variable.
     146              :   !-------------------------------------------------------------------!
     147            0 :   subroutine run_one_step(self, effpot, displacement, strain, spin, lwf,  energy_table)
     148              :     ! run one step. (For MC also?)
     149              :     class(lwf_mc_t), intent(inout) :: self
     150              :     real(dp), optional, intent(inout) :: displacement(:,:), strain(:,:), spin(:,:), lwf(:)
     151              :     type(hash_table_t), optional, intent(inout) :: energy_table
     152              :     class(abstract_potential_t), intent(inout) :: effpot
     153              :     integer :: i
     154              :     character(len=40) :: key
     155              : 
     156            0 :     ABI_UNUSED_A(displacement)
     157            0 :     ABI_UNUSED_A(strain)
     158            0 :     ABI_UNUSED_A(spin)
     159              : 
     160              :     !self%lwf(:)=lwf(:)
     161            0 :     self%lwf_force(:) = 0.0_dp
     162              :     ! calculate energy at first step
     163            0 :     self%energy=0.0
     164              : 
     165              : 
     166              :     call effpot%calculate( displacement=displacement, strain=strain, &
     167              :          & spin=spin, lwf=self%lwf, lwf_force=self%lwf_force, &
     168            0 :          & energy=self%energy, energy_table=energy_table)
     169              :     !print *, "Calculated energy", self%energy/self%supercell%ncell
     170              : 
     171            0 :     do i = 1, self%nstep
     172            0 :        call self%run_one_mc_step(effpot)
     173              :     end do
     174              :     !print *, "Calculated MC energy", self%energy/self%supercell%ncell
     175              :     !print *, "Accept rate:", (1.0_dp*self%naccept)/self%nattempt
     176            0 :     lwf(:)=self%lwf(:)
     177            0 :     if (present(energy_table)) then
     178            0 :        key = 'LWF energy'
     179            0 :        call energy_table%put(key, self%energy)
     180              :     end if
     181              : 
     182            0 :   end subroutine run_one_step
     183              : 
     184              : 
     185              :    !----------------------------------------------------------------------
     186              :    !> @brief accept the trail step, which update the lwf and energy
     187              :    !----------------------------------------------------------------------
     188            0 :    subroutine accept(self)
     189              :      class(lwf_mc_t), intent(inout) :: self
     190            0 :      self%lwf(self%imove)=self%lwf_new
     191            0 :      self%energy=self%energy+self%deltaE
     192              :      !print *, "E:", self%energy/self%supercell%ncell
     193            0 :    end subroutine accept
     194              : 
     195              :    !----------------------------------------------------------------------
     196              :    !> @brief reject the trail step, changes nothing.
     197              :    !----------------------------------------------------------------------
     198            0 :    subroutine reject(self)
     199              :      class(lwf_mc_t), intent(inout) :: self
     200              :      ! do nothing.
     201            0 :      ABI_UNUSED_A(self)
     202            0 :    end subroutine reject
     203              : 
     204              :    !----------------------------------------------------------------------
     205              :    !> @brief define a trail step  using Hinzke_nowak method and calculate energy difference
     206              :    !----------------------------------------------------------------------
     207            0 :    function attempt(self,rng, effpot) result(r)
     208              :      class(lwf_mc_t) :: self
     209              :      class(rng_t) :: rng
     210              :      class(abstract_potential_t), intent(inout) :: effpot
     211              :      real(dp) :: r
     212              :      ! choose one site
     213            0 :      self%imove = rng%rand_choice(self%nlwf)
     214            0 :      self%lwf_old= self%lwf(self%imove)
     215            0 :      self%deltaE=0.0
     216            0 :      call move(rng, self%lwf_old, self%lwf_new, self%avg_amp)
     217            0 :      call effpot%get_delta_E_lwf( self%lwf, self%imove, self%lwf_new, self%deltaE)
     218            0 :      r=exp(-self%deltaE *self%beta)
     219            0 :    end function attempt
     220              : 
     221              :    !----------------------------------------------------------------------
     222              :    !> @brief add to lwf by a random value.
     223              :    !----------------------------------------------------------------------
     224            0 :    subroutine move(rng, lwf_old, lwf_new, avg_amp)
     225              :      type(rng_t) :: rng
     226              :      real(dp), intent(in) :: lwf_old, avg_amp
     227              :      real(dp), intent(out) :: lwf_new
     228              :      real(dp):: dlwf
     229            0 :      dlwf=rng%rand_normal()
     230            0 :      lwf_new=lwf_old + dlwf*avg_amp
     231            0 :    end subroutine move
     232              : 
     233            0 : end module m_lwf_mc_mover
        

Generated by: LCOV version 2.3-1