2
! This file is part of the SIESTA package.
4
! Copyright (c) Fundacion General Universidad Autonoma de Madrid:
5
! E.Artacho, J.Gale, A.Garcia, J.Junquera, P.Ordejon, D.Sanchez-Portal
6
! and J.M.Soler, 1996-2006.
8
! Use of this software constitutes agreement with the full conditions
9
! given in the SIESTA license, as signed by all legitimate users.
11
module m_zm_broyden_optim
12
public :: zm_broyden_optimizer
17
subroutine zm_broyden_optimizer( na, xa, fa, cell,
18
. stress, volume, dxmax,
19
. tp, ftol, strtol, varcel, relaxd)
21
c ******************************** INPUT ************************************
22
c integer na : Number of atoms in the simulation cell
23
c real*8 fa(3,na) : Atomic forces
24
c real*8 stress(3,3) : Stress tensor components
25
c real*8 volume : unit cell volume
26
c real*8 dxmax : Maximum atomic (or lattice vector) displacement
27
c real*8 tp : Target pressure
28
c real*8 ftol : Maximum force tolerance
29
c real*8 strtol : Maximum stress tolerance
30
c logical varcel : true if variable cell optimization
31
c *************************** INPUT AND OUTPUT ******************************
32
c real*8 xa(3,na) : Atomic coordinates
33
c input: current step; output: next step
34
c real*8 cell(3,3) : Matrix of the vectors defining the unit cell
35
c input: current step; output: next step
36
c cell(ix,ja) is the ix-th component of ja-th vector
37
c real*8 stress(3,3) : Stress tensor components
38
c real*8 strtol : Maximum stress tolerance
39
c ******************************** OUTPUT ***********************************
40
c logical relaxd : True when converged
41
c ***************************************************************************
46
use precision, only : dp
47
use parallel, only : Node, IONode
48
use fdf, only : fdf_block, fdf_physical
49
use m_fdf_global, only: fdf_global_get
50
use m_mpi_utils, only: broadcast
51
use units, only: kBar, Ang
52
use m_broyddj_nocomm, only: broyden_t
53
use m_broyddj_nocomm, only: broyden_reset, broyden_step,
54
$ broyden_destroy, broyden_init,
57
use zmatrix, only : VaryZmat, Zmat
58
use zmatrix, only : CartesianForce_to_ZmatForce
59
use zmatrix, only : ZmatForce,ZmatForceVar
60
use zmatrix, only : iZmattoVars,ZmatType
61
use zmatrix, only : Zmat_to_Cartesian
62
use zmatrix, only : coeffA, coeffB, iNextDept
63
use Zmatrix, only : ZmatForceTolLen, ZmatForceTolAng
64
use Zmatrix, only : ZmatMaxDisplLen, ZmatMaxDisplAng
68
C Subroutine arguments:
69
integer, intent(in) :: na
70
logical, intent(in) :: varcel
71
logical, intent(out) :: relaxd
72
real(dp), intent(in) :: fa(3,na), volume, dxmax, tp, ftol
73
real(dp), intent(inout):: xa(3,na), stress(3,3), strtol, cell(3,3)
75
C Internal variables and arrays
76
integer :: iu, ia, i, j, n, indi,indi1,vi,k
78
real(dp) :: new_volume, trace
79
real(dp) :: sxx, syy, szz, sxy, sxz, syz
80
real(dp) :: celli(3,3)
81
real(dp) :: stress_dif(3,3)
82
real(dp), dimension(:), allocatable :: gxa, gfa
83
real(dp) :: force, force1
85
C Saved internal variables:
87
logical, save :: frstme = .true.
88
logical, save :: tarstr = .false.
89
logical, save :: constant_volume
90
real(dp), save :: initial_volume
92
real(dp), save :: tstres(3,3)
93
real(dp), save :: cellin(3,3)
94
real(dp), save :: modcel(3)
95
real(dp), save :: precon
96
real(dp), save :: strain(3,3) ! Special treatment !!
98
real(dp), dimension(:), allocatable :: ftoln, dxmaxn
99
real(dp), dimension(:), allocatable :: rold, rnew, rdiff
101
type(broyden_t), save :: br
102
logical, save :: initialization_done = .false.
104
real(dp), save :: jinv0
105
integer, save :: maxit
106
logical, save :: cycle_on_maxit, variable_weight
107
logical, save :: broyden_debug
110
integer :: ndegi, ndi
113
real(dp), external :: volcel
115
c ---------------------------------------------------------------------------
117
if (.not. initialization_done) then
119
call fdf_global_get(maxit,"MD.Broyden.History.Steps",5)
120
call fdf_global_get(cycle_on_maxit,
121
$ "MD.Broyden.Cycle.On.Maxit",.true.)
122
call fdf_global_get(variable_weight,
123
$ "MD.Broyden.Variable.Weight",.false.)
124
call fdf_global_get(broyden_debug,
125
$ "MD.Broyden.Debug",.false.)
126
call fdf_global_get(jinv0,
127
$ "MD.Broyden.Initial.Inverse.Jacobian",1.0_dp)
132
$ "Broyden_optim: max_history for broyden: ", maxit
134
$ "Broyden_optim: cycle on maxit: ", cycle_on_maxit
135
if (variable_weight) write(6,'(a)')
136
$ "Broyden_optim: Variable weight not implemented yet"
138
$ "Broyden_optim: initial inverse jacobian: ", jinv0
142
call broyden_init(br,debug=broyden_debug)
143
initialization_done = .true.
149
! Find number of variables
154
if (VaryZmat(indi)) then
160
ndeg = ndeg + 6 ! Including stress
163
write(6,'(a,i6)') "Broyden_optim: No of elements: ", ndeg
168
call fdf_global_get(constant_volume,
169
. "MD.ConstantVolume", .false.)
172
tarstr = fdf_block('MD.TargetStress',iu)
174
! Look for target stress and read it if found,
175
! otherwise generate it
178
$ 'cgvc_zmatrix: Reading %block MD.TargetStress',
179
. ' (units of MD.TargetPressure).'
180
read(iu,*, end=50) sxx, syy, szz, sxy, sxz, syz
181
tstres(1,1) = - sxx * tp
182
tstres(2,2) = - syy * tp
183
tstres(3,3) = - szz * tp
184
tstres(1,2) = - sxy * tp
185
tstres(2,1) = - sxy * tp
186
tstres(1,3) = - sxz * tp
187
tstres(3,1) = - sxz * tp
188
tstres(2,3) = - syz * tp
189
tstres(3,2) = - syz * tp
193
$ 'cgvc_zmatrix: No target stress found, ',
194
. 'assuming hydrostatic MD.TargetPressure.'
203
if (constant_volume) then
205
write(6,"(a)") "***Target stress set to zero " //
206
$ "for constant-volume calculation"
208
write(6,"(/a)") 'cgvc_zmatrix: Target stress (kBar)'
210
write(6,"(a,2x,3f12.3)")
211
. 'cgvc_zmatrix:', (tstres(i,j)/kBar,j=1,3)
215
call broadcast(tstres(1:3,1:3))
217
C Moduli of original cell vectors for fractional coor scaling back to au ---
221
modcel(n) = modcel(n) + cell(j,n)*cell(j,n)
223
modcel(n) = dsqrt( modcel(n) )
226
C Scale factor for strain variables to share magnitude with coordinates
227
C ---- (a length in Bohrs typical of bond lengths ..)
229
! AG: This could better be volume^(1/3) by default
230
call fdf_global_get(precon,'MD.PreconditionVariableCell',
231
. 9.4486344d0,'Bohr')
233
C Initialize absolute strain and save initial cell vectors
234
C Initialization to 1 for numerical reasons, later substracted
236
strain(1:3,1:3) = 1.0_dp
237
cellin(1:3,1:3) = cell(1:3,1:3)
238
initial_volume = volcel(cellin)
246
C Allocate local memory
249
call memory('A','D',ndeg,'cgvc_zmatrix')
251
call memory('A','D',ndeg,'cgvc_zmatrix')
252
allocate(ftoln(ndeg))
253
call memory('A','D',ndeg,'cgvc_zmatrix')
254
allocate(dxmaxn(ndeg))
255
call memory('A','D',ndeg,'cgvc_zmatrix')
257
! print *, "zm_broyden: cell in : ", cell
258
! print *, "zm_broyden: strain in : ", strain
262
! Inverse of matrix of cell vectors (transpose of)
263
call reclat( cell, celli, 0 )
265
C Transform coordinates and forces to fractional ----------------------------
266
C but scale them again to Bohr by using the (fix) moduli of the original ----
267
C lattice vectors (allows using maximum displacement as before) -------------
268
C convergence is checked here for input forces as compared with ftol --------
272
! Loop over degrees of freedom, scaling
273
! only cartesian coordinates to fractional
277
if (VaryZmat(indi)) then
279
if (ZmatType(indi).gt.1) then
280
ftoln(ndegi) = ZmatForceTolLen
281
dxmaxn(ndegi) = ZmatMaxDisplLen
283
ftoln(ndegi) = ZmatForceTolAng
284
dxmaxn(ndegi) = ZmatMaxDisplAng
286
vi = iZmattoVars(indi)
288
force = ZmatForce(indi)
290
force = ZmatForceVar(vi)
292
relaxd=relaxd.and.(dabs(force).lt.ftoln(ndegi))
293
if (ZmatType(indi).gt.2) then
294
C Cartesian coordinate
299
gxa(ndegi) = gxa(ndegi)+
300
. celli(i,n)*Zmat(indi1)*modcel(n)
304
force1 = ZmatForce(indi1)
306
gfa(ndegi) = gfa(ndegi)+
307
. cell(i,n)*force1/modcel(n)
310
gxa(ndegi) = Zmat(indi)
317
C Symmetrizing the stress tensor --------------------------------------------
320
stress(i,j) = 0.5_dp*( stress(i,j) + stress(j,i) )
321
stress(j,i) = stress(i,j)
325
C Subtract target stress
327
stress_dif = stress - tstres
329
! Take 1/3 of the trace out here if constant-volume needed
331
if (constant_volume) then
332
trace = stress_dif(1,1) + stress_dif(2,2) + stress_dif(3,3)
334
stress_dif(i,i) = stress_dif(i,i) - trace/3.0_dp
338
C Append stress (substracting target stress) and strain to gxa and gfa ------
339
C preconditioning: scale stress and strain so as to behave similarly to x,f -
343
gfa(ndegi) = -stress_dif(i,j)*volume/precon
344
gxa(ndegi) = strain(i,j) * precon
345
dxmaxn(ndegi) = ZmatMaxDisplLen
349
C Check stress convergence
350
strtol = dabs(strtol)
353
relaxd = relaxd .and.
354
. ( dabs(stress_dif(i,j)) .lt. abs(strtol) )
360
C Set number of degrees of freedom & variables
366
if (VaryZmat(indi)) then
368
gxa(ndegi) = Zmat(indi)
369
vi = iZmattoVars(indi)
371
force = ZmatForce(indi)
373
force = ZmatForceVar(vi)
376
if (ZmatType(indi).eq.1) then
377
ftoln(ndegi) = ZmatForceTolAng
378
dxmaxn(ndegi) = ZmatMaxDisplAng
380
ftoln(ndegi) = ZmatForceTolLen
381
dxmaxn(ndegi) = ZmatMaxDisplLen
383
relaxd=relaxd.and.(dabs(force).lt.ftoln(ndegi))
390
if (relaxd) RETURN ! Will leave work arrays allocated
392
if (.not. broyden_is_setup(br)) then
393
call broyden_reset(br,ndeg,maxit,cycle_on_maxit,
396
allocate (rnew(ndeg))
397
call memory('A','D',ndeg,'zm_broyden_optimizer')
399
call broyden_step(br,gxa,gfa,w=weight,newx=rnew)
410
strain(i,j) = rnew(indi) / precon
411
strain(j,i) = strain(i,j)
415
cell = cellin + matmul(strain-1.0_dp,cellin)
416
if (constant_volume) then
417
new_volume = volcel(cell)
418
if (Node.eq.0) write(6,"(a,f12.4)")
419
$ "Volume before coercion: ", new_volume/Ang**3
420
cell = cell * (initial_volume/new_volume)**(1.0_dp/3.0_dp)
423
C Output fractional coordinates to cartesian Bohr, and copy to xa -----------
428
if (VaryZmat(indi)) then
432
if (ZmatType(j).gt.2) then
436
! Assume all three coords of this atom
439
Zmat(j)=Zmat(j)+cell(k,n)*rnew(ndi)/modcel(n)
442
Zmat(j) = rnew(ndegi)
444
Zmat(j) = Zmat(j)*coeffA(j) + coeffB(j)
450
call Zmat_to_Cartesian(xa)
454
C Return coordinates to correct arrays
459
if (VaryZmat(indi)) then
463
Zmat(j) = rnew(ndegi)*coeffA(j)+coeffB(j)
469
call Zmat_to_Cartesian(xa)
472
! print *, "zm_broyden: cell out : ", cell
473
! print *, "zm_broyden: strain out : ", strain
475
C Deallocate local memory
477
call memory('D','D',size(dxmaxn),'cgvc_zmatrix')
479
call memory('D','D',size(ftoln),'cgvc_zmatrix')
481
call memory('D','D',size(gxa),'cgvc_zmatrix')
483
call memory('D','D',size(gfa),'cgvc_zmatrix')
485
call memory('D','D',size(rnew),'cgvc_zmatrix')
488
end subroutine zm_broyden_optimizer
490
end module m_zm_broyden_optim