LCOV - code coverage report
Current view: top level - src/78_effpot - m_spin_observables.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.9 % 98 91
Test Date: 2026-11-09 23:40:40 Functions: 63.6 % 11 7
Branches: 58.3 % 228 133

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_spin_observables
       2                 :             : !! NAME
       3                 :             : !! m_spin_observables
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !! This module contains the subroutines to calculate the observables of spin dynamics
       7                 :             : !!
       8                 :             : !!
       9                 :             : !! Datatypes:
      10                 :             : !! spin_observable_t: store data to calculate observables
      11                 :             : !! Subroutines:
      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                 :             : module m_spin_observables
      31                 :             : 
      32                 :             :   use defs_basis
      33                 :             :   use m_abicore
      34                 :             :   use m_errors
      35                 :             :   use m_xmpi
      36                 :             :   use m_spin_potential, only: spin_potential_t
      37                 :             :   use m_multibinit_cell, only: mbsupercell_t
      38                 :             :   use m_multibinit_dataset, only: multibinit_dtset_type
      39                 :             : 
      40                 :             :   implicit none
      41                 :             : 
      42                 :             :   private
      43                 :             :   !!***
      44                 :             : 
      45                 :             :   !-----------------------------------------------------------------------
      46                 :             :   !> @brief spin_observale_t: observables for spin dynamics.
      47                 :             :   !-----------------------------------------------------------------------
      48                 :             :   type, public :: spin_observable_t
      49                 :             :      ! Switches for what kind of obs should be calculated
      50                 :             :      logical :: calc_thermo_obs    ! theromostatic obs: susceptibility, specific heat...
      51                 :             :      logical :: calc_correlation_obs ! correlation function related
      52                 :             :      logical :: calc_traj_obs       ! trajectory related (winding number, etc)
      53                 :             : 
      54                 :             :      integer :: nspin, nsublatt, ntime, nscell
      55                 :             :      ! nspin: number of spin
      56                 :             :      ! nsublatt: number of sublattice (currently each spin in primitive cell is one sublattice)
      57                 :             :      ! ntime: number of time steps
      58                 :             :      ! nscell: number of cell in supercell
      59                 :             : 
      60                 :             :      real(dp) :: temperature
      61                 :             :      integer, allocatable :: isublatt(:), nspin_sub(:)
      62                 :             :      ! isublatt: index of sublattice for each spin
      63                 :             :      ! nspin_sub:
      64                 :             : 
      65                 :             :      real(dp) :: energy
      66                 :             :      real(dp), allocatable :: S(:,:), Snorm(:)
      67                 :             :      real(dp), allocatable ::  Ms_coeff(:),  Mst_sub(:, :), Mst_sub_norm(:)
      68                 :             :      ! Ms_coeff: coefficient to calcualte staggered Mst.
      69                 :             :      ! Staggerd means a phase factor is multiplied to each spin.
      70                 :             :      ! Ms_coeff is that phase factor. Mst_coeff = e ^{iq R}
      71                 :             : 
      72                 :             :      ! Mst_sub: M staggered for sublattice: \sum_(i in sublattice)\S_i phase_i
      73                 :             :      ! Mst_sub : norm of Mst_sub
      74                 :             : 
      75                 :             :      real(dp) ::  M_total(3), Mst_total(3), M_total_norm,  Mst_norm_total, Snorm_total
      76                 :             :      ! M_total: M total    \sum M_i where M_i =|S_i|
      77                 :             :      ! Mst_total: staggerd M total  |sum M_I|
      78                 :             :      ! Mst_norm : ||Mst_total||
      79                 :             :      real(dp), allocatable :: Avg_Mst_sub_norm(:)
      80                 :             :      real(dp) :: Avg_Mst_norm_total
      81                 :             : 
      82                 :             :      real(dp) :: binderU4, chi, Cv
      83                 :             :      ! binderU4: binder U4
      84                 :             :      ! chi: susceptibility
      85                 :             :      ! Cv: specific heat
      86                 :             : 
      87                 :             :      ! variables for calculate Cv
      88                 :             :      real(dp) :: avg_E_t   ! average energy E over time
      89                 :             :      real(dp) :: avg_E2_t  ! average E^2 over time
      90                 :             :      real(dp) :: avg_m_t   ! average of sum(Mst_norm_total) over t
      91                 :             :      real(dp) :: avg_m2_t  ! average of sum(Mst_norm_total**2) over t
      92                 :             :      real(dp) :: avg_m4_t  !average of sum(Mst_sub_total_norm**4) over t
      93                 :             :    contains
      94                 :             :      procedure :: initialize
      95                 :             :      procedure :: finalize
      96                 :             :      procedure :: reset
      97                 :             :      procedure :: get_staggered_M
      98                 :             :      procedure :: get_thermo_obs
      99                 :             :      procedure :: get_correlation_obs
     100                 :             :      procedure :: get_traj_obs
     101                 :             :      procedure :: get_observables
     102                 :             : 
     103                 :             :   end type spin_observable_t
     104                 :             : 
     105                 :             : contains
     106                 :             : 
     107                 :             : 
     108                 :           2 :   subroutine initialize(self, supercell, params)
     109                 :             : 
     110                 :             :     class(spin_observable_t) :: self
     111                 :             :     type(mbsupercell_t) :: supercell
     112                 :             :     type(multibinit_dtset_type) :: params
     113                 :             :     integer i
     114                 :             :     complex(dp) :: i2pi = (0.0, two_pi)
     115                 :             : 
     116                 :           2 :     self%calc_thermo_obs=  (params%spin_calc_thermo_obs ==1)
     117                 :             :     !self%calc_traj_obs= (params%spin_calc_traj_obs ==1)
     118                 :             :     !self%calc_correlation_obs=(params%spin_calc_correlation_obs ==1)
     119                 :           2 :     self%calc_traj_obs= .False.
     120                 :           2 :     self%calc_correlation_obs= .False.
     121                 :             : 
     122                 :             : 
     123                 :           2 :     self%nspin=supercell%spin%nspin
     124         [ +  + ]:         434 :     self%nsublatt=maxval(supercell%spin%ispin_prim)
     125                 :             : 
     126   [ -  +  +  -  :           6 :     ABI_MALLOC(self%S, (3, self%nspin))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     127   [ -  +  +  -  :           6 :     ABI_MALLOC(self%Snorm, (self%nspin))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     128                 :             : 
     129   [ -  +  +  -  :           6 :     ABI_MALLOC(self%isublatt,(self%nspin) )
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     130         [ +  + ]:         434 :     self%isublatt(:)=supercell%spin%ispin_prim(:)
     131                 :             : 
     132   [ -  +  +  -  :           6 :     ABI_MALLOC(self%nspin_sub, (self%nsublatt))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     133         [ +  + ]:           4 :     self%nspin_sub(:)=0
     134         [ +  + ]:         434 :     do i =1, self%nspin
     135                 :         434 :        self%nspin_sub(self%isublatt(i)) = self%nspin_sub(self%isublatt(i)) + 1
     136                 :             :     end do
     137                 :             : 
     138   [ -  +  +  -  :           6 :     ABI_MALLOC(self%Ms_coeff,(self%nspin))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     139   [ -  +  +  -  :           6 :     ABI_MALLOC(self%Mst_sub, (3, self%nsublatt))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     140   [ -  +  +  -  :           6 :     ABI_MALLOC(self%Mst_sub_norm, (self%nsublatt))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     141   [ -  +  +  -  :           4 :     ABI_MALLOC(self%Avg_Mst_sub_norm, (self%nsublatt))
          -  +  -  +  -  
                      + ]
     142                 :             : 
     143         [ +  + ]:         434 :     do i = 1, self%nspin
     144         [ +  + ]:        1730 :       self%Ms_coeff(i) = real(exp(i2pi * dot_product(params%spin_projection_qpoint, supercell%spin%rvec(:,i))))
     145                 :             :     end do
     146                 :             : 
     147                 :           2 :     call reset(self, params)
     148                 :           2 :   end subroutine initialize
     149                 :             : 
     150                 :           4 :   subroutine reset(self, params)
     151                 :             :     ! set values to zeros.
     152                 :             :     class(spin_observable_t), intent(inout) :: self
     153                 :             :     class(multibinit_dtset_type), optional, intent(in) :: params
     154   [ +  +  +  - ]:           4 :     if (present(params)) then
     155                 :           2 :        self%temperature=params%spin_temperature
     156         [ +  + ]:           8 :        self%nscell = product(params%ncell)
     157                 :             :     end if
     158                 :           4 :     self%ntime=0
     159                 :           4 :     self%Cv=0.0
     160                 :           4 :     self%binderU4=0.0
     161         [ +  + ]:          16 :     self%M_total(:) =0.0
     162                 :           4 :     self%M_total_norm=0.0
     163                 :           4 :     self%Mst_norm_total=0.0
     164   [ +  +  +  + ]:          20 :     self%Mst_sub(:,:)=0.0
     165         [ +  + ]:           8 :     self%Mst_sub_norm(:)=0.0
     166         [ +  + ]:           8 :     self%Avg_Mst_sub_norm(:) =0.0
     167                 :           4 :     self%Avg_Mst_norm_total = 0.0
     168                 :           4 :     self%avg_e_t=0.0
     169                 :           4 :     self%avg_e2_t=0.0
     170                 :             : 
     171                 :           4 :     self%avg_m_t=0.0
     172                 :           4 :     self%avg_m2_t=0.0
     173                 :           4 :     self%avg_m4_t=0.0
     174                 :           4 :   end subroutine reset
     175                 :             : 
     176                 :             :   !-----------------------------------------------------------------------
     177                 :             :   !> @brief finalize
     178                 :             :   !-----------------------------------------------------------------------
     179                 :           4 :   subroutine finalize(self)
     180                 :             :     class(spin_observable_t) :: self
     181                 :             : 
     182         [ +  + ]:           4 :     ABI_SFREE(self%isublatt)
     183         [ +  + ]:           4 :     ABI_SFREE(self%nspin_sub)
     184         [ +  + ]:           4 :     ABI_SFREE(self%S)
     185         [ +  + ]:           4 :     ABI_SFREE(self%Snorm)
     186         [ +  + ]:           4 :     ABI_SFREE(self%Ms_coeff)
     187         [ +  + ]:           4 :     ABI_SFREE(self%Mst_sub)
     188         [ +  + ]:           4 :     ABI_SFREE(self%Mst_sub_norm)
     189         [ +  + ]:           4 :     ABI_SFREE(self%Avg_Mst_sub_norm)
     190                 :             : 
     191                 :           4 :   end subroutine finalize
     192                 :             : 
     193                 :             :   !-----------------------------------------------------------------------
     194                 :             :   !> @brief set S, Snorm, and energy (after one dynamics step)
     195                 :             :   !> @param [in]  S
     196                 :             :   !> @param [in] Snorm
     197                 :             :   !> @param [in] energy
     198                 :             :   !-----------------------------------------------------------------------
     199                 :        2002 :   subroutine update(self, S, Snorm, energy)
     200                 :             :     class(spin_observable_t), intent(inout) :: self
     201                 :             :     real(dp), intent(in):: S(3,self%nspin), Snorm(self%nspin), energy
     202   [ +  -  +  -  :     1733732 :     self%S=S
          -  +  -  -  +  
                +  +  + ]
     203   [ +  -  -  +  :      436436 :     self%Snorm=Snorm
             -  -  +  + ]
     204                 :        2002 :     self%energy=energy
     205                 :        2002 :   end subroutine update
     206                 :             : 
     207                 :             :   !-----------------------------------------------------------------------
     208                 :             :   !> @brief Calculate M in each sublattice
     209                 :             :   !>  sum of S * phase factor in each sublattice
     210                 :             :   !-----------------------------------------------------------------------
     211                 :        2002 :   subroutine get_staggered_M(self)
     212                 :             : 
     213                 :             :     class(spin_observable_t), intent(inout) :: self
     214                 :             :     integer :: i, isub
     215   [ +  +  +  + ]:       10010 :     self%Mst_sub(:,:)=0.0
     216         [ +  + ]:        8008 :     self%M_total(:)=0.0
     217         [ +  + ]:      434434 :     do i = 1, self%nspin
     218                 :      432432 :        isub=self%isublatt(i)
     219         [ +  + ]:     1729728 :        self%Mst_sub(:, isub) = self%Mst_sub(:, isub) +  self%S(:, i)* self%Ms_coeff(i) * self%Snorm(i)
     220         [ +  + ]:     1731730 :        self%M_total(:) = self%M_total + self%S(:, i)*self%Snorm(i)
     221                 :             :     end do
     222                 :             : 
     223   [ +  +  +  + ]:       10010 :     self%Mst_sub_norm(:) =sqrt(sum(self%Mst_sub**2, dim=1))/self%nscell
     224         [ +  + ]:        4004 :     self%Mst_norm_total= sum(self%Mst_sub_norm(:))
     225                 :             :     !self%M_total_norm = sqrt(sum(self%M_total**2))/self%nscell
     226         [ +  + ]:      434434 :     self%Snorm_total = sum(self%Snorm)/self%nscell
     227                 :             : 
     228         [ +  + ]:        4004 :     self%avg_Mst_sub_norm(:)=(self%avg_Mst_sub_norm(:)*self%ntime + self%Mst_sub_norm(:))/(self%ntime+1)
     229                 :        2002 :     self%avg_Mst_norm_total=(self%avg_Mst_norm_total*self%ntime + self%Mst_norm_total)/(self%ntime+1)
     230                 :        2002 :   end subroutine get_staggered_M
     231                 :             : 
     232                 :             :   !-----------------------------------------------------------------------
     233                 :             :   !> @brief calculate observable related to the topology of trajectory
     234                 :             :   !> like the winding number
     235                 :             :   !-----------------------------------------------------------------------
     236                 :           0 :   subroutine get_traj_obs(self)
     237                 :             :     class(spin_observable_t) :: self
     238                 :             :     ABI_UNUSED(self%nspin)
     239                 :           0 :   end subroutine get_traj_obs
     240                 :             : 
     241                 :             :   !-----------------------------------------------------------------------
     242                 :             :   !> @brief calculate thermostatistic observables
     243                 :             :   !> Cv, binderU4 and chi
     244                 :             :   !-----------------------------------------------------------------------
     245                 :        2002 :   subroutine get_thermo_obs(self )
     246                 :             :     class(spin_observable_t) :: self
     247                 :             :     real(dp) :: avgm
     248                 :             :     ABI_UNUSED(self%nspin)
     249                 :             :     ! Cv
     250                 :        2002 :     self%avg_E_t = (self%avg_E_t*self%ntime + self%energy)/(self%ntime+1)
     251                 :        2002 :     self%avg_E2_t = (self%avg_E2_t*self%ntime + self%energy**2)/(self%ntime+1)
     252         [ -  + ]:        2002 :     if(self%temperature<1d-12) then
     253                 :           0 :        self%Cv=0.0d0
     254                 :             :     else
     255                 :        2002 :        self%Cv = (self%avg_E2_t-self%avg_E_t**2)/self%temperature**2
     256                 :             :     end if
     257                 :             : 
     258                 :             :     !
     259                 :        2002 :     avgm=self%Mst_norm_total
     260                 :             :     !avgm=self%M_total_norm
     261                 :             : 
     262                 :        2002 :     self%avg_m_t =  (self%avg_m_t*self%ntime + avgm)/(self%ntime+1)
     263                 :        2002 :     self%avg_m2_t = (self%avg_m2_t*self%ntime + avgm**2)/(self%ntime+1)
     264                 :        2002 :     self%avg_m4_t = (self%avg_m4_t*self%ntime + avgm**4)/(self%ntime+1)
     265                 :             : 
     266                 :        2002 :     self%binderU4 = 1.0-self%avg_m4_t/self%avg_m2_t**2/3.0
     267                 :             : 
     268         [ -  + ]:        2002 :     if(self%temperature<1d-12) then
     269                 :           0 :        self%chi=(self%avg_m2_t-self%avg_m_t**2)
     270                 :             :     else
     271                 :        2002 :        self%chi = (self%avg_m2_t-self%avg_m_t**2)/self%temperature
     272                 :             :     endif
     273                 :        2002 :   end subroutine get_thermo_obs
     274                 :             : 
     275                 :             : 
     276                 :             :   !-----------------------------------------------------------------------
     277                 :             :   !> @brief calculate correlation function relatated observables
     278                 :             :   !-----------------------------------------------------------------------
     279                 :           0 :   subroutine get_correlation_obs(self)
     280                 :             :     class(spin_observable_t) :: self
     281                 :             :     ABI_UNUSED(self%nspin)
     282                 :           0 :   end subroutine get_correlation_obs
     283                 :             : 
     284                 :             :   !-----------------------------------------------------------------------
     285                 :             :   !> @brief calculate all observables from input
     286                 :             :   !> @param [in] S
     287                 :             :   !> @param [in] Snorm
     288                 :             :   !> @param [in] energy
     289                 :             :   !-----------------------------------------------------------------------
     290                 :        2002 :   subroutine get_observables(self, S, Snorm, energy)
     291                 :             : 
     292                 :             :     class(spin_observable_t) :: self
     293                 :             :     real(dp), intent(in) :: S(3,self%nspin), Snorm(self%nspin), energy
     294                 :        2002 :     call update(self, S, Snorm, energy)
     295                 :        2002 :     call get_staggered_M(self)
     296                 :        2002 :     if(self%calc_traj_obs) then
     297                 :             :        call get_traj_obs(self)
     298                 :             :     end if
     299         [ +  - ]:        2002 :     if(self%calc_thermo_obs) then
     300                 :        2002 :        call get_thermo_obs(self)
     301                 :             :     end if
     302                 :             :     if(self%calc_correlation_obs) then
     303                 :             :        call get_correlation_obs(self)
     304                 :             :     endif
     305                 :        2002 :     self%ntime=self%ntime+1
     306                 :             : 
     307                 :        2002 :   end subroutine get_observables
     308                 :             : 
     309                 :             : 
     310   [ #  #  #  #  :           0 : end module m_spin_observables
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
        

Generated by: LCOV version 2.3-1