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
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
|