LCOV - code coverage report
Current view: top level - src/78_effpot - m_spin_mc_mover.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 71 0
Test Date: 2026-11-10 15:53:16 Functions: 0.0 % 12 0
Branches: 0.0 % 86 0

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_spin_mc_mover
       2                 :             : !! NAME
       3                 :             : !! m_spin_mc_mover
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !! This module contains the spin Markov chain Monte Carlo functions for spin mover .
       7                 :             : !!
       8                 :             : !!
       9                 :             : !! Datatypes:
      10                 :             : !!
      11                 :             : !! * spin_mc_t : MCMC. It defines how to move spins 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_spin_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                 :             :     implicit none
      41                 :             : !!***
      42                 :             :     private
      43                 :             : 
      44                 :             :     !----------------------------------------------------------------------
      45                 :             :     !> @brief An helper type to run spin dynamics
      46                 :             :     ! The Metropolis-Hasting algorithm is used.
      47                 :             :     !----------------------------------------------------------------------
      48                 :             :     type,public :: spin_mc_t
      49                 :             :        real(dp), allocatable :: S(:,:) ! the spin for the whole structure
      50                 :             :        real(dp) ::  Sold(3), Snew(3) ! old and new S for one spin
      51                 :             :        real(dp) :: angle   ! an angle to rotate by average
      52                 :             :        real(dp) :: energy, deltaE ! energy and the change of energy when change one spin
      53                 :             :        real(dp) :: temperature
      54                 :             :        real(dp) :: beta  ! 1/(kb T)
      55                 :             :        integer :: nspin   ! number of spins
      56                 :             :        integer :: nstep  ! number of steps
      57                 :             :        integer :: imove ! index of spin to be moved
      58                 :             :        integer :: naccept  ! number of accepted steps
      59                 :             :        integer :: nattempt ! number of attempted steps
      60                 :             :      contains
      61                 :             :        procedure :: initialize
      62                 :             :        procedure :: finalize
      63                 :             :        procedure, private :: attempt
      64                 :             :        procedure, private :: accept
      65                 :             :        procedure, private :: reject
      66                 :             :        procedure, private :: run_one_step
      67                 :             :        procedure :: run_MC
      68                 :             :     end type spin_mc_t
      69                 :             : 
      70                 :             : 
      71                 :             :   contains
      72                 :             :     !----------------------------------------------------------------------
      73                 :             :     !> @brief initialize mc helper class
      74                 :             :     !>
      75                 :             :     !> @param[in]  nspin: number of spins
      76                 :             :     !> @param[in]  angle: a angle to rotate
      77                 :             :     !> @param[in]  temperature: temperature
      78                 :             :     !----------------------------------------------------------------------
      79                 :           0 :     subroutine initialize(self, nspin, angle, temperature)
      80                 :             :       class(spin_mc_t), intent(inout) :: self
      81                 :             :       integer, intent(in) :: nspin
      82                 :             :       real(dp), intent(in) :: angle, temperature
      83                 :           0 :       self%nspin=nspin
      84                 :           0 :       self%nstep=self%nspin
      85   [ #  #  #  #  :           0 :       ABI_MALLOC(self%S, (3, self%nspin))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
      86                 :           0 :       self%angle=angle
      87                 :           0 :       self%temperature=temperature
      88                 :           0 :       self%beta=1.0/temperature ! Kb in a.u. is 1.
      89         [ #  # ]:           0 :       self%Sold(:)=0.0_dp
      90         [ #  # ]:           0 :       self%Snew(:)=0.0_dp
      91                 :           0 :       self%naccept=0
      92                 :           0 :       self%nattempt=0
      93                 :           0 :     end subroutine initialize
      94                 :             : 
      95                 :             :     !----------------------------------------------------------------------
      96                 :             :     !> @brief finalize
      97                 :             :     !----------------------------------------------------------------------
      98                 :           0 :     subroutine finalize(self)
      99                 :             :       class(spin_mc_t), intent(inout) :: self
     100         [ #  # ]:           0 :       if (allocated(self%S)) then
     101                 :           0 :          ABI_FREE(self%S)
     102                 :             :       end if
     103         [ #  # ]:           0 :       self%Sold=zero
     104         [ #  # ]:           0 :       self%Snew=zero
     105                 :           0 :       self%nspin=0
     106                 :           0 :       self%nstep=0
     107                 :           0 :     end subroutine finalize
     108                 :             : 
     109                 :             : 
     110                 :             :     !----------------------------------------------------------------------
     111                 :             :     !> @brief run one monte carlo step
     112                 :             :     !> @param[in]   rngL rundom number generator
     113                 :             :     !> @param[in] effpot: effective spin potential
     114                 :             :     !----------------------------------------------------------------------
     115                 :           0 :    subroutine run_one_step(self, rng, effpot)
     116                 :             :      class(spin_mc_t) :: self
     117                 :             :      class(rng_t) :: rng
     118                 :             :      class(abstract_potential_t), intent(inout) :: effpot
     119                 :             :      real(dp) :: r
     120                 :             : 
     121                 :             :      ! try to change spin
     122                 :           0 :      r=self%attempt(rng, effpot)
     123                 :             :      ! metropolis-hastings
     124                 :           0 :      self%nattempt = self%nattempt+1
     125         [ #  # ]:           0 :      if(rng%rand_unif_01()< min(1.0_dp, r) ) then
     126                 :           0 :         self%naccept=self%naccept+1
     127                 :           0 :         call self%accept()
     128                 :             :         !print *, "accepted"
     129                 :             :      else
     130                 :           0 :         call self%reject()
     131                 :             :         !print *, "rejected"
     132                 :             :      end if
     133                 :           0 :    end subroutine run_one_step
     134                 :             : 
     135                 :             :    !----------------------------------------------------------------------
     136                 :             :    !> @brief run a number of MC steps. Since one step only changes
     137                 :             :    !> too little things, a few steps are bunched as one. Then things like
     138                 :             :    !> output or calculation of observables are done after the big step.
     139                 :             :    !>
     140                 :             :    !> @param[in]  rng: random number generator
     141                 :             :    !> @param[in]  effpot:  the spin potential
     142                 :             :    !> @param[in]  S_in:  the intial spin state
     143                 :             :    !> @param[out]  etot:  the final total energy
     144                 :             :    !----------------------------------------------------------------------
     145   [ #  #  #  #  :           0 :    subroutine run_MC(self, rng, effpot, S_in, etot, bfield)
                   #  # ]
     146                 :             :      class(spin_mc_t), intent(inout) :: self
     147                 :             :      type(rng_t) :: rng
     148                 :             :      class(abstract_potential_t), intent(inout) :: effpot
     149                 :             :      real(dp), intent(inout) :: S_in(3,self%nspin)
     150                 :             :      real(dp), intent(out) ::  etot
     151                 :             :      real(dp), optional,intent(inout) :: bfield(:,:)
     152                 :             :      real(dp) :: etmp
     153                 :             : 
     154                 :             :      integer :: i
     155   [ #  #  #  # ]:           0 :      self%S(:,:)=S_in(:,:)
     156         [ #  # ]:           0 :      call effpot%calculate(spin=S_in, energy=self%energy, bfield=bfield)
     157         [ #  # ]:           0 :      do i = 1, self%nstep
     158                 :           0 :         call self%run_one_step(rng, effpot)
     159                 :             :      end do
     160   [ #  #  #  # ]:           0 :      S_in(:, :)=self%S(:,:)
     161                 :             :      !call effpot%calculate(spin=self%S, energy=self%energy, bfield=bfield)
     162                 :             :      !print *, self%energy
     163                 :           0 :      etot=self%energy
     164         [ #  # ]:           0 :      call effpot%calculate(spin=S_in, energy=etmp, bfield=bfield)
     165                 :             :      !print *, "energy: ", self%energy, etmp, self%energy-etmp
     166                 :           0 :    end subroutine run_MC
     167                 :             : 
     168                 :             :    !----------------------------------------------------------------------
     169                 :             :    !> @brief accept the trail step, which update the spin and energy
     170                 :             :    !----------------------------------------------------------------------
     171                 :           0 :    subroutine accept(self)
     172                 :             :      class(spin_mc_t), intent(inout) :: self
     173         [ #  # ]:           0 :      self%S(:,self%imove)=self%Snew(:)
     174                 :           0 :      self%energy=self%energy+self%deltaE
     175                 :           0 :    end subroutine accept
     176                 :             : 
     177                 :             :    !----------------------------------------------------------------------
     178                 :             :    !> @brief reject the trail step, changes nothing.
     179                 :             :    !----------------------------------------------------------------------
     180                 :           0 :    subroutine reject(self)
     181                 :             :      class(spin_mc_t), intent(inout) :: self
     182                 :             :      ! do nothing.
     183                 :           0 :      ABI_UNUSED_A(self)
     184                 :           0 :    end subroutine reject
     185                 :             : 
     186                 :             :    !----------------------------------------------------------------------
     187                 :             :    !> @brief define a trail step  using Hinzke_nowak method and calculate energy difference
     188                 :             :    !----------------------------------------------------------------------
     189                 :           0 :    function attempt(self,rng, effpot) result(r)
     190                 :             :      class(spin_mc_t) :: self
     191                 :             :      class(rng_t) :: rng
     192                 :             :      class(abstract_potential_t), intent(inout) :: effpot
     193                 :             :      real(dp) :: r
     194                 :             :      ! choose one site
     195                 :           0 :      self%imove = rng%rand_choice(self%nspin)
     196         [ #  # ]:           0 :      self%Sold(:)= self%S(:,self%imove)
     197                 :           0 :      self%deltaE=0.0
     198                 :           0 :      call move_hinzke_nowak(rng, self%Sold, self%Snew, self%angle)
     199                 :           0 :      call effpot%get_delta_E( self%S, self%imove, self%Snew, self%deltaE)
     200                 :             :      !print *, "delta E", self%deltaE
     201                 :           0 :      r=exp(-self%deltaE *self%beta)
     202                 :           0 :    end function attempt
     203                 :             : 
     204                 :             :    !----------------------------------------------------------------------
     205                 :             :    !> @brief  rotate the  spin by the average of angle (normal distribution)
     206                 :             :    !----------------------------------------------------------------------
     207                 :           0 :    subroutine move_angle(rng, Sold, Snew, angle)
     208                 :             :      type(rng_t) :: rng
     209                 :             :      real(dp), intent(in) :: Sold(3), angle
     210                 :             :      real(dp), intent(out) :: Snew(3)
     211                 :           0 :      call rng%rand_normal_array(Snew, 3)
     212         [ #  # ]:           0 :      Snew(:)=Sold(:) + Snew(:)*angle
     213   [ #  #  #  #  :           0 :      Snew(:)=Snew(:)/norm2(Snew)
             #  #  #  # ]
     214                 :           0 :    end subroutine move_angle
     215                 :             : 
     216                 :             :    !----------------------------------------------------------------------
     217                 :             :    !> @brief  flip one spin
     218                 :             :    !----------------------------------------------------------------------
     219                 :             :    subroutine move_flip(Sold, Snew)
     220                 :             :      real(dp), intent(in) :: Sold(3)
     221                 :             :      real(dp), intent(out) :: Snew(3)
     222         [ #  # ]:           0 :      Snew(:)=-Sold(:)
     223                 :             :    end subroutine move_flip
     224                 :             : 
     225                 :             :    !----------------------------------------------------------------------
     226                 :             :    !> @brief  set spin to random orientation
     227                 :             :    !----------------------------------------------------------------------
     228                 :           0 :    subroutine move_uniform(rng, Snew)
     229                 :             :      type(rng_t), intent(inout) :: rng
     230                 :             :      real(dp), intent(out) :: Snew(3)
     231                 :           0 :      call rng%rand_normal_array(Snew, 3)
     232   [ #  #  #  #  :           0 :      Snew(:)=Snew(:)/norm2(Snew)
             #  #  #  # ]
     233                 :           0 :    end subroutine move_uniform
     234                 :             : 
     235                 :             :    !----------------------------------------------------------------------
     236                 :             :    !> @brief combine rotate, flip and random set.
     237                 :             :    !----------------------------------------------------------------------
     238                 :           0 :    subroutine move_hinzke_nowak(rng, Sold, Snew, angle)
     239                 :             :      type(rng_t), intent(inout) :: rng
     240                 :             :      real(dp), intent(in) :: Sold(3), angle
     241                 :             :      real(dp), intent(out) :: Snew(3)
     242                 :             :      integer :: move
     243                 :           0 :      move=rng%rand_choice(3)
     244                 :           0 :      select case (move)
     245                 :             :      case (1)
     246                 :           0 :         call move_angle(rng, Sold, Snew, angle)
     247                 :             :      case(2)
     248                 :           0 :         call move_flip(Sold, Snew)
     249                 :             :      case(3)
     250                 :           0 :         call move_uniform(rng, Snew)
     251                 :             :      case default
     252   [ #  #  #  # ]:           0 :         call move_angle(rng, Sold, Snew, angle)
     253                 :             :      end select
     254                 :           0 :    end subroutine move_hinzke_nowak
     255                 :             : 
     256   [ #  #  #  #  :           0 : end module m_spin_mc_mover
          #  #  #  #  #  
                #  #  # ]
        

Generated by: LCOV version 2.3-1