Line data Source code
1 : !!****m* ABINIT/m_potential_list
2 : !! NAME
3 : !! m_potential_list
4 : !!
5 : !! FUNCTION
6 : !! This module contains the potential_list potential. It is made of list of pointers to potentials,
7 : !! and has all the functionality of a potential
8 : !! It is to represent the equation H=\sum_i H_i
9 : !! with dH/dx = \sum_i dH_i/dx
10 : !!
11 : !! Datatypes:
12 : !!
13 : !! * potential_list_t: list of abstract_potential_t, which is essentially a list of pointer to abstract_potential_t
14 : !! itself is also a effpot type, and its energy, 1st derivative to energy are the sum of all items.
15 : !! Subroutines:
16 : !! TODO: add this when F2003 doc style is determined.
17 : !!
18 : !!
19 : !! COPYRIGHT
20 : !! Copyright (C) 2001-2026 ABINIT group (hexu)
21 : !! This file is distributed under the terms of the
22 : !! GNU General Public License, see ~abinit/COPYING
23 : !! or http://www.gnu.org/copyleft/gpl.txt .
24 : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
25 : !!
26 : !! SOURCE
27 :
28 :
29 : #if defined HAVE_CONFIG_H
30 : #include "config.h"
31 : #endif
32 :
33 : #include "abi_common.h"
34 :
35 : module m_potential_list
36 : use defs_basis
37 : use m_abicore
38 : use m_errors
39 : use m_xmpi
40 : use m_mpi_scheduler, only: init_mpi_info
41 : use m_multibinit_dataset, only: multibinit_dtset_type
42 : use m_abstract_potential, only: abstract_potential_t
43 : use m_multibinit_cell, only: mbcell_t, mbsupercell_t
44 : use m_hashtable_strval, only: hash_table_t
45 :
46 : implicit none
47 : !!***
48 :
49 : !!****t* defs_abitypes/effpot_pointer_t
50 : !! NAME
51 : !! effpot_pointer_t
52 : !!
53 : !! FUNCTION
54 : !! class pointer to abstract potentials. Only here because
55 : !! Fortran does not allow array of pointers! So we must put
56 : !! pointer to an type and make an array of this type.
57 : !! It should only be used in potential_list_t.
58 : !!
59 : !! SOURCE
60 : type, private:: effpot_pointer_t ! pointer to effpot
61 : class(abstract_potential_t) , pointer :: ptr=>null()
62 : end type effpot_pointer_t
63 : !!***
64 :
65 : !!****t* defs_abitypes/potential_list_t
66 : !! NAME
67 : !! potential_list_t
68 : !!
69 : !! FUNCTION
70 : !! A potential which is made of a list of potentials.
71 : !! H=\sum_i H_i
72 : !!
73 : !! SOURCE
74 : type, public, extends(abstract_potential_t) :: potential_list_t
75 : integer :: size=0 ! size is the USED number of potentials in the list
76 : integer :: capacity=0 ! capacity is the number of places allocated for potentials
77 : type(effpot_pointer_t), allocatable :: list(:) ! A list of pointer type to potentials
78 : contains
79 : procedure :: initialize ! make an empty list
80 : procedure :: ipot ! return the i'th potential
81 : procedure :: set_supercell ! pointer to supercell and set_supercell for all pot in list
82 : procedure :: set_params
83 : procedure :: finalize
84 : procedure :: append ! add a potential to the list
85 : procedure :: calculate ! each potential in list do calculate and then sum.
86 : procedure :: get_delta_E ! currently only used in spin potential,
87 : ! to calculate energy difference when one spin changes.
88 :
89 : procedure :: get_delta_E_lwf ! currently only used in lwf potential,
90 : end type potential_list_t
91 : !!***
92 :
93 : contains
94 :
95 : !----------------------------------------------------------------------
96 : !> @brief initialize
97 : !>
98 : !----------------------------------------------------------------------
99 6 : subroutine initialize(self)
100 : class (potential_list_t), intent(inout) :: self
101 6 : self%size=0
102 6 : self%capacity=0
103 6 : self%label="ListPotential"
104 6 : end subroutine initialize
105 :
106 : !----------------------------------------------------------------------
107 : !> @brief return the i'th potential in the list
108 : !>
109 : !> @param[in] i: the index of the spin potentails
110 : ! Unfortunately, fortran does not allow things call potlist%ipot(i)%method...
111 : !----------------------------------------------------------------------
112 0 : function ipot(self, i)
113 : class (potential_list_t), target, intent(in) :: self
114 : integer, intent(in) :: i
115 : class(abstract_potential_t), pointer :: ipot
116 0 : ipot=>self%list(i)%ptr
117 0 : end function ipot
118 :
119 : !----------------------------------------------------------------------
120 : !> @brief set_supercell for every member of the potential list
121 : !> @param[in] supercell
122 : !----------------------------------------------------------------------
123 12 : subroutine set_supercell(self, supercell)
124 : class (potential_list_t), intent(inout) :: self
125 : type (mbsupercell_t), target, intent(inout) :: supercell
126 : integer :: i
127 12 : self%supercell => supercell
128 22 : do i=1, self%size
129 22 : call self%list(i)%ptr%set_supercell(supercell)
130 : end do
131 12 : end subroutine set_supercell
132 :
133 : !----------------------------------------------------------------------
134 : !> @brief finalize
135 : !----------------------------------------------------------------------
136 6 : subroutine finalize(self)
137 : class (potential_list_t) ,intent(inout) :: self
138 : integer :: i
139 16 : do i=1, self%size
140 10 : call self%list(i)%ptr%finalize()
141 : ! Intel compiler complains
142 10 : if(associated(self%list(i)%ptr)) then
143 20 : ABI_FREE(self%list(i)%ptr)
144 : endif
145 :
146 16 : nullify(self%list(i)%ptr)
147 : end do
148 6 : if (allocated(self%list)) then
149 6 : ABI_FREE(self%list)
150 : end if
151 6 : self%size=0
152 6 : self%capacity=0
153 6 : self%is_null=.True.
154 6 : self%has_displacement=.False.
155 6 : self%has_strain=.False.
156 6 : self%has_spin=.False.
157 6 : end subroutine finalize
158 :
159 :
160 : !----------------------------------------------------------------------
161 : !> @brief append a potential to the list
162 : !> It also update the has_* according to the added effpot.
163 : !> @param[in] effpot: the effective potential to be added.
164 : !----------------------------------------------------------------------
165 10 : subroutine append(self, effpot)
166 : ! Add a pointer to an effpot term to list.
167 : class (potential_list_t) :: self
168 : class (abstract_potential_t), target :: effpot
169 10 : type(effpot_pointer_t), allocatable :: temp(:)
170 10 : self%size=self%size + 1
171 10 : if(self%size==1) then
172 6 : self%capacity=8
173 54 : ABI_MALLOC(self%list, (self%capacity))
174 4 : else if ( self%size>self%capacity ) then
175 : ! fancy increasing equation to allocate new array.
176 0 : self%capacity = self%size + self%size / 4 + 8
177 0 : ABI_MALLOC(temp, (self%capacity))
178 0 : temp(:self%size-1) = self%list(:)
179 0 : ABI_MOVE_ALLOC(temp, self%list) !temp gets deallocated
180 : end if
181 10 : self%list(self%size)%ptr=>effpot
182 10 : self%is_null= (self%is_null .and. effpot%is_null)
183 10 : self%has_spin= (self%has_spin .or. effpot%has_spin)
184 10 : self%has_displacement= (self%has_displacement .or. effpot%has_displacement)
185 10 : self%has_strain= (self%has_strain.or. effpot%has_strain)
186 10 : self%has_lwf =(self%has_lwf.or. effpot%has_lwf)
187 10 : end subroutine append
188 :
189 6 : subroutine set_params(self, params)
190 : class(potential_list_t), intent(inout) :: self ! the effpot may save the states.
191 : type(multibinit_dtset_type), intent(inout) :: params
192 : integer :: i
193 16 : do i=1, self%size
194 16 : call self%list(i)%ptr%set_params(params)
195 : end do
196 6 : end subroutine set_params
197 :
198 :
199 :
200 : !----------------------------------------------------------------------
201 : !> @brief calculate energy and 1st derivatives
202 : !> The list will add the sum of all the results from its components.
203 : !> If one optional variable is passed to a subroutine, its "presence" will be kept.
204 : !> @param[in] (optional) displacement, strain, spin, lwf
205 : !> @param[out](optional) force, stress, bfield, lwf_force, energy
206 : !----------------------------------------------------------------------
207 108056 : subroutine calculate(self, displacement, strain, spin, lwf, force, stress, bfield, &
208 54028 : & lwf_force, energy, energy_table)
209 : ! calculate energy and its first derivatives.
210 : class(potential_list_t), intent(inout) :: self ! the effpot may save the states.
211 : ! inputs
212 : real(dp), optional, intent(inout) :: displacement(:,:), strain(:,:), spin(:,:), lwf(:)
213 : ! outputs
214 : real(dp), optional, intent(inout) :: force(:,:), stress(:,:), bfield(:,:), lwf_force(:), energy
215 : type(hash_table_t),optional, intent(inout) :: energy_table
216 : integer :: i
217 : ! Note
218 : ! calculate force and strain if asked to
219 34664932 : if(present(force)) force(:,:)=0.0d0
220 158340 : if(present(stress)) stress(:,:)=0.0d0
221 3517488 : if(present(bfield)) bfield(:,:)=0.0d0
222 43104028 : if(present(lwf_force)) lwf_force(:)=0.0d0
223 54028 : if(present(energy)) energy =0.0
224 124072 : do i=1, self%size
225 : call self%list(i)%ptr%calculate(displacement=displacement, strain=strain, &
226 : & spin=spin, lwf=lwf, force=force, stress=stress, bfield=bfield, &
227 488248 : lwf_force=lwf_force, energy=energy, energy_table=energy_table)
228 : end do
229 54028 : end subroutine calculate
230 :
231 : !----------------------------------------------------------------------
232 : !> @brief get_delta_E: calculate the energy difference when a given spin
233 : !> is changed. This is to be used for spin Monte Carlo. Currently the
234 : !> only supported is the spin model.
235 : !>
236 : !> @param[in] S: spin of full structure. array of (3, nspin)
237 : !> @param[in] ispin: the index of spin changed. integer
238 : !> @param[in] snew: the new value of the changed spin.
239 : !> @param[out] deltaE: the energy difference
240 : !----------------------------------------------------------------------
241 0 : subroutine get_delta_E(self, S, ispin, Snew, deltaE)
242 : class(potential_list_t), intent(inout) :: self ! the effpot may save the states.
243 : real(dp), intent(inout) :: S(:,:), Snew(:)
244 : integer, intent(in) :: ispin
245 : real(dp), intent(inout) :: deltaE
246 : integer :: i
247 0 : do i=1, self%size
248 0 : call self%list(i)%ptr%get_delta_E(S=S, ispin=ispin, Snew=Snew, deltaE=deltaE)
249 : end do
250 0 : end subroutine get_delta_E
251 :
252 : !----------------------------------------------------------------------
253 : !> @brief get_delta_E_lwf: calculate the energy difference when a given lwf
254 : !> is changed. This is to be used for spin Monte Carlo. Currently the
255 : !> only supported is the spin model.
256 : !>
257 : !> @param[in] lwf: lwf of full structure. array of (nlwf)
258 : !> @param[in] ilwf: the index of spin changed. integer
259 : !> @param[in] lwf_new: the new value of the changed spin.
260 : !> @param[out] deltaE: the energy difference
261 : !----------------------------------------------------------------------
262 0 : subroutine get_delta_E_lwf(self, lwf, ilwf, lwf_new, deltaE)
263 : ! for spin monte carlo
264 : ! calculate energy difference if one spin is moved.
265 : class(potential_list_t), intent(inout) :: self ! the effpot may save the states.
266 : real(dp), intent(inout) :: lwf(:), lwf_new
267 : integer, intent(in) :: ilwf
268 : real(dp), intent(inout) :: deltaE
269 : integer :: i
270 0 : do i=1, self%size
271 0 : call self%list(i)%ptr%get_delta_E_lwf(lwf=lwf, ilwf=ilwf, lwf_new=lwf_new, deltaE=deltaE)
272 : end do
273 0 : end subroutine get_delta_E_lwf
274 :
275 :
276 :
277 0 : end module m_potential_list
|