Line data Source code
1 : !!****m* ABINIT/m_pred_nose
2 : !! NAME
3 : !! m_pred_nose
4 : !!
5 : !! FUNCTION
6 : !!
7 : !!
8 : !! COPYRIGHT
9 : !! Copyright (C) 1998-2026 ABINIT group (DCA, XG, GMR, JCC, SE)
10 : !! This file is distributed under the terms of the
11 : !! GNU General Public License, see ~abinit/COPYING
12 : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : !!
14 : !! SOURCE
15 :
16 : #if defined HAVE_CONFIG_H
17 : #include "config.h"
18 : #endif
19 :
20 : #include "abi_common.h"
21 :
22 : module m_pred_nose
23 :
24 : use defs_basis
25 : use m_abicore
26 : use m_abimover
27 : use m_abihist
28 :
29 : use m_numeric_tools, only : uniformrandom
30 : use m_geometry, only : xcart2xred, xred2xcart, metric
31 :
32 : implicit none
33 :
34 : private
35 : !!***
36 :
37 : public :: pred_nose
38 : !!***
39 :
40 : contains
41 : !!***
42 :
43 : !!****f* ABINIT/pred_nose
44 : !! NAME
45 : !! pred_nose
46 : !!
47 : !! FUNCTION
48 : !! Ionmov predictors (8) Verlet algorithm with a nose-hoover thermostat
49 : !!
50 : !! IONMOV 8:
51 : !! Given a starting point xred that is a vector of length 3*natom
52 : !! (reduced nuclei coordinates), a velocity vector (in cartesian
53 : !! coordinates), and unit cell parameters (acell and rprimd -
54 : !! without velocities in the present implementation),
55 : !! the Verlet dynamics is performed, using the gradient of the
56 : !! energy (atomic forces and stresses) as calculated by the routine scfcv.
57 : !!
58 : !! Some atoms can be kept fixed, while the propagation of unit cell
59 : !! parameters is only performed if optcell/=0.
60 : !! No more than "ntime" steps are performed.
61 : !! The time step is governed by dtion (contained in dtset)
62 : !! Returned quantities are xred, and eventually acell and rprimd
63 : !! (new ones!).
64 : !!
65 : !! See ionmov=6, but with a nose-hoover thermostat
66 : !! Velocity verlet algorithm : Swope et al JCP 76 (1982) 637
67 : !!
68 : !! INPUTS
69 : !! ab_mover <type(abimover)> : Datatype with all the information
70 : !! needed by the preditor
71 : !! itime : Index of the present iteration
72 : !! ntime : Maximal number of iterations
73 : !! zDEBUG : if true print some debugging information
74 : !!
75 : !! SIDE EFFECTS
76 : !! hist <type(abihist)> : History of positions,forces acell, rprimd, stresses
77 : !!
78 : !! SOURCE
79 :
80 20 : subroutine pred_nose(ab_mover,hist,itime,ntime,zDEBUG,iexit)
81 :
82 : !Arguments ------------------------------------
83 : !scalars
84 : type(abimover),intent(in) :: ab_mover
85 : type(abihist),intent(inout) :: hist
86 : integer,intent(in) :: itime
87 : integer,intent(in) :: ntime
88 : integer,intent(in) :: iexit
89 : logical,intent(in) :: zDEBUG
90 :
91 : !Local variables-------------------------------
92 : !scalars
93 : integer :: ii,jj,kk
94 : integer :: idum=-5
95 : real(dp),parameter :: v2tol=tol8,nosetol=tol10
96 : real(dp) :: delxi,xio,ktemp,rescale_vel
97 : real(dp) :: dnose,v2nose,xin_nose
98 : real(dp),save :: xi_nose,fsnose,snose
99 : real(dp) :: gnose
100 : real(dp) :: ucvol,ucvol_next
101 : real(dp) :: etotal
102 : logical :: ready
103 :
104 : !arrays
105 : real(dp) :: acell(3),acell_next(3)
106 : real(dp) :: rprimd(3,3),rprimd_next(3,3)
107 : real(dp) :: gprimd(3,3)
108 : real(dp) :: gmet(3,3)
109 : real(dp) :: rmet(3,3)
110 40 : real(dp) :: fcart(3,ab_mover%natom)
111 40 : real(dp) :: xred(3,ab_mover%natom),xred_next(3,ab_mover%natom)
112 40 : real(dp) :: xcart(3,ab_mover%natom),xcart_next(3,ab_mover%natom)
113 40 : real(dp) :: vel(3,ab_mover%natom),vel_temp(3,ab_mover%natom)
114 40 : real(dp) :: finose(3,ab_mover%natom),binose(3,ab_mover%natom)
115 2 : real(dp) :: vonose(3,ab_mover%natom),hnose(3,ab_mover%natom)
116 : real(dp),allocatable,save :: fcart_m(:,:),fcart_mold(:,:)
117 : real(dp) :: strten(6)
118 : character(len=500) :: message
119 :
120 : !***************************************************************************
121 : !Beginning of executable session
122 : !***************************************************************************
123 :
124 20 : if(iexit/=0)then
125 2 : ABI_SFREE(fcart_m)
126 2 : ABI_SFREE(fcart_mold)
127 : return
128 : end if
129 :
130 : !write(std_out,*) 'nose 01'
131 : !##########################################################
132 : !### 01. Allocate the arrays fcart_m and fcart_mold
133 :
134 18 : if(itime==1)then
135 2 : ABI_SFREE(fcart_m)
136 2 : ABI_SFREE(fcart_mold)
137 : end if
138 :
139 18 : if(.not.allocated(fcart_m)) then
140 6 : ABI_MALLOC(fcart_m,(3,ab_mover%natom))
141 : end if
142 18 : if(.not.allocated(fcart_mold)) then
143 6 : ABI_MALLOC(fcart_mold,(3,ab_mover%natom))
144 : end if
145 :
146 : !write(std_out,*) 'nose 02'
147 : !##########################################################
148 : !### 02. Obtain the present values from the history
149 :
150 18 : call hist2var(acell,hist,ab_mover%natom,rprimd,xred,zDEBUG)
151 18 : call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
152 :
153 198 : fcart(:,:)=hist%fcart(:,:,hist%ihist)
154 : strten(:)=hist%strten(:,hist%ihist)
155 198 : vel(:,:)=hist%vel(:,:,hist%ihist)
156 18 : etotal=hist%etot(hist%ihist)
157 :
158 18 : write(std_out,*) 'RPRIMD'
159 72 : do ii=1,3
160 72 : write(std_out,*) rprimd(:,ii)
161 : end do
162 18 : write(std_out,*) 'RMET'
163 72 : do ii=1,3
164 72 : write(std_out,*) rmet(ii,:)
165 : end do
166 :
167 : !write(std_out,*) 'nose 03'
168 : !##########################################################
169 : !### 03. Fill the vectors vin and vout
170 :
171 : !write(std_out,*) 'nose 04'
172 : !##########################################################
173 : !### 04. Initialize or update the hessian matrix
174 :
175 : !write(std_out,*) 'nose 05'
176 : !##########################################################
177 : !### 05. Compute the next values
178 :
179 : !The temperature is linear between initial and final values
180 : !It is here converted from Kelvin to Hartree (kb_HaK)
181 18 : ktemp=(ab_mover%mdtemp(1)+((ab_mover%mdtemp(2)-ab_mover%mdtemp(1))/dble(ntime-1))*(itime-1))*kb_HaK
182 :
183 : !%%% NOSE DYNAMICS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
184 :
185 : acell_next(:)=acell(:)
186 18 : ucvol_next=ucvol
187 : rprimd_next(:,:)=rprimd(:,:)
188 :
189 18 : if(itime==1)then
190 2 : snose=0.0_dp
191 2 : xi_nose=0.0_dp
192 : ! Compute twice the kinetic energy of the system, called v2nose
193 2 : v2nose=0.0_dp
194 7 : do kk=1,ab_mover%natom
195 22 : do jj=1,3
196 20 : v2nose=v2nose+vel(jj,kk)*vel(jj,kk)*ab_mover%amass(kk)
197 : end do
198 : end do
199 2 : if (zDEBUG)then
200 0 : write(std_out,*) 'itime ntime KTEMP=',itime-1,ntime-1,ktemp
201 0 : write(std_out,*) 'V2NOSE=',v2nose
202 0 : write (std_out,*) 'VEL'
203 0 : do kk=1,ab_mover%natom
204 0 : write (std_out,*) vel(:,kk)
205 : end do
206 : end if
207 :
208 : ! If there is no kinetic energy, use a random initial velocity
209 2 : if (v2nose<=v2tol) then
210 2 : v2nose=0.0_dp
211 7 : do kk=1,ab_mover%natom
212 22 : do jj=1,3
213 : ! Uniform random returns a uniform random deviate between 0.0
214 : ! and 1.0
215 : ! if it were always 0 or 1, then the following expression
216 : ! would give the requested temperature
217 : vel(jj,kk)=(1.0_dp-2.0_dp*uniformrandom(idum))*&
218 15 : & sqrt( (ab_mover%mdtemp(1)) * kb_HaK / ab_mover%amass(kk) )
219 : ! Recompute v2nose
220 15 : v2nose=v2nose+vel(jj,kk)*vel(jj,kk)*ab_mover%amass(kk)
221 20 : if (zDEBUG)then
222 0 : write(std_out,*) 'jj kk vel(jj,kk)=',jj,kk,vel(jj,kk)
223 0 : write(std_out,*) 'jj kk V2NOSE=',jj,kk,v2nose
224 : end if
225 : end do
226 : end do
227 : end if
228 2 : write(std_out,*) 'V2NOSE=',v2nose
229 :
230 : ! Now, rescale the velocities to give the proper temperature
231 2 : rescale_vel=sqrt(3.0_dp*ab_mover%natom*(ab_mover%mdtemp(1))*kb_HaK/v2nose)
232 2 : write(std_out,*) 'RESCALE_VEL=',rescale_vel
233 22 : vel(:,:)=vel(:,:)*rescale_vel
234 : ! Recompute v2nose with the rescaled velocities
235 2 : v2nose=0.0_dp
236 7 : do kk=1,ab_mover%natom
237 22 : do jj=1,3
238 20 : v2nose=v2nose+vel(jj,kk)*vel(jj,kk)*ab_mover%amass(kk)
239 : end do
240 : end do
241 : write(message, '(a)' )&
242 2 : & ' Rescaling or initializing velocities to initial temperature'
243 2 : call wrtout(std_out,message,'COLL')
244 2 : call wrtout(std_out,message,'COLL')
245 : write(message, '(2(a,es22.14))' )&
246 2 : & ' --- Scaling factor : ',rescale_vel,&
247 4 : & ' Asked T (K) ',ab_mover%mdtemp(1)
248 2 : call wrtout(std_out,message,'COLL')
249 2 : call wrtout(std_out,message,'COLL')
250 : write(message, '(a,es22.14)' )&
251 2 : & ' --- Effective temperature',v2nose/(3.0_dp*ab_mover%natom*kb_HaK)
252 2 : call wrtout(std_out,message,'COLL')
253 2 : call wrtout(std_out,message,'COLL')
254 : end if
255 :
256 63 : do kk=1,ab_mover%natom
257 198 : fcart_m(:,kk)=fcart(:,kk)/ab_mover%amass(kk)
258 : end do
259 :
260 : !First step of velocity verlet algorithm
261 18 : gnose=3*ab_mover%natom
262 :
263 : !Convert input xred (reduced coordinates) to xcart (cartesian)
264 18 : call xred2xcart(ab_mover%natom,rprimd,xcart,xred)
265 :
266 : !Calculate nose-hoover force on atoms
267 : !If first iteration, no old force are available, so use present
268 : !forces
269 38 : if (itime==1) fcart_mold(:,:)=fcart_m(:,:)
270 :
271 18 : if (zDEBUG)then
272 0 : write (std_out,*) 'FCART_MOLD'
273 0 : do kk=1,ab_mover%natom
274 0 : write (std_out,*) fcart_mold(:,kk)
275 : end do
276 0 : write (std_out,*) 'FCART_M'
277 0 : do kk=1,ab_mover%natom
278 0 : write (std_out,*) fcart_m(:,kk)
279 : end do
280 : end if
281 :
282 198 : finose(:,:)=fcart_mold(:,:)-xi_nose*vel(:,:)
283 198 : xcart(:,:)=xcart(:,:)+ab_mover%dtion*(vel(:,:)+ab_mover%dtion*finose(:,:)/2.0_dp)
284 :
285 : !Convert back to xred (reduced coordinates)
286 18 : call xcart2xred(ab_mover%natom,rprimd,xcart,xred)
287 :
288 18 : if (zDEBUG)then
289 0 : write (std_out,*) 'VEL'
290 0 : do kk=1,ab_mover%natom
291 0 : write (std_out,*) vel(:,kk)
292 : end do
293 : end if
294 :
295 : !Calculate v2nose
296 18 : v2nose=0.0_dp
297 63 : do kk=1,ab_mover%natom
298 198 : do jj=1,3
299 180 : v2nose=v2nose+vel(jj,kk)*vel(jj,kk)*ab_mover%amass(kk)
300 : end do
301 : end do
302 198 : vel(:,:)=vel(:,:)+ab_mover%dtion*finose(:,:)/2.0_dp
303 :
304 18 : if (zDEBUG)then
305 0 : write(std_out,*) 'NOSE BEFORE'
306 0 : write(std_out,*) 'FSNOSE=',fsnose
307 0 : write(std_out,*) 'SNOSE=',snose
308 0 : write(std_out,*) 'XI_NOSE=',xi_nose
309 0 : write (std_out,*) 'VEL'
310 0 : do kk=1,ab_mover%natom
311 0 : write (std_out,*) vel(:,kk)
312 : end do
313 0 : write (std_out,*) 'NOSEINERT',ab_mover%noseinert
314 : end if
315 :
316 : !Update thermostat
317 18 : fsnose=(v2nose-gnose*ktemp)/ab_mover%noseinert
318 18 : snose=snose+ab_mover%dtion*(xi_nose+ab_mover%dtion*fsnose/2.0_dp)
319 18 : xi_nose=xi_nose+ab_mover%dtion*fsnose/2.0_dp
320 18 : if (zDEBUG)then
321 0 : write(std_out,*) 'NOSE AFTER'
322 0 : write(std_out,*) 'FSNOSE=',fsnose
323 0 : write(std_out,*) 'SNOSE=',snose
324 0 : write(std_out,*) 'XI_NOSE=',xi_nose
325 0 : write (std_out,*) 'VEL'
326 0 : do kk=1,ab_mover%natom
327 0 : write (std_out,*) vel(:,kk)
328 : end do
329 : end if
330 :
331 : !Second step of the velocity Verlet algorithm, uses the 'new forces'
332 : !Calculate v2nose
333 18 : v2nose=0.0_dp
334 63 : do kk=1,ab_mover%natom
335 198 : do jj=1,3
336 180 : v2nose=v2nose+vel(jj,kk)*vel(jj,kk)*ab_mover%amass(kk)
337 : end do
338 : end do
339 198 : vel_temp(:,:)=vel(:,:)
340 :
341 18 : if (zDEBUG)then
342 0 : write(std_out,*) 'V2NOSE=',v2nose
343 0 : write (std_out,*) 'VEL'
344 0 : do kk=1,ab_mover%natom
345 0 : write (std_out,*) vel(:,kk)
346 : end do
347 0 : write (std_out,*) 'Starting Newton Raphson'
348 : end if
349 :
350 18 : xin_nose=xi_nose
351 :
352 : !Start Newton-Raphson loop
353 18 : ready=.false.
354 88 : do while (.not.ready)
355 : xio=xin_nose
356 244 : delxi=0.0D0
357 766 : vonose(:,:)=vel_temp(:,:)
358 : hnose(:,:)=-ab_mover%dtion/2.0_dp*(fcart_m(:,:)-xio*vonose(:,:))-&
359 766 : & (vel(:,:)-vonose(:,:))
360 244 : do kk=1,ab_mover%natom
361 766 : do jj=1,3
362 522 : binose(jj,kk)=vonose(jj,kk)*ab_mover%dtion/ab_mover%noseinert*ab_mover%amass(kk) ! a verifier
363 696 : delxi=delxi+hnose(jj,kk)*binose(jj,kk)
364 : end do
365 : end do
366 70 : dnose=-(xio*ab_mover%dtion/2.0D0+1.0D0)
367 : delxi=delxi-dnose*((-v2nose+gnose*ktemp)*ab_mover%dtion/2.0_dp/ &
368 70 : & ab_mover%noseinert-(xi_nose-xio))
369 70 : delxi=delxi/(-ab_mover%dtion*ab_mover%dtion/2.0_dp*v2nose/ab_mover%noseinert+dnose)
370 :
371 : ! hzeronose=-(xio-xi_nose-(v2nose-gnose*ktemp)
372 : ! *dtion/(2.0_dp*ab_mover%noseinert) )
373 : ! cibinose=-v2nose*dtion*dtion/(2.0_dp*ab_mover%noseinert)
374 : ! delxi=(delxi+hzeronose*dnose)/(dnose+cibinose)
375 :
376 : ! DEBUG
377 : ! write(message, '(a,es22.14)' )' after delxi',delxi
378 : ! call wrtout(std_out,message,'COLL')
379 : ! call wrtout(std_out,message,'COLL')
380 : ! ENDDEBUG
381 70 : v2nose=0.0_dp
382 :
383 : vel_temp(:,:)=vel_temp(:,:)+&
384 766 : & (hnose+ab_mover%dtion/2.0_dp*vonose(:,:)*delxi)/dnose
385 244 : do kk=1,ab_mover%natom
386 766 : do jj=1,3
387 : v2nose=v2nose+vel_temp(jj,kk)*&
388 696 : & vel_temp(jj,kk)*ab_mover%amass(kk)
389 : end do
390 : end do
391 : ! New guess for xi
392 70 : xin_nose=xio+delxi
393 :
394 : ! zDEBUG
395 : ! write(message, '(a,es22.14)' )' v2nose=',v2nose
396 : ! call wrtout(std_out,message,'COLL')
397 : ! call wrtout(std_out,message,'COLL')
398 : ! ENDDEBUG
399 :
400 70 : ready=.true.
401 : ! Test for convergence
402 70 : kk=0
403 70 : jj=1
404 302 : do while((kk<=ab_mover%natom).and.(jj<=3).and.ready)
405 214 : kk=kk+1
406 214 : if (kk>ab_mover%natom) then
407 57 : kk=1
408 57 : jj=jj+1
409 : end if
410 284 : if ((kk<=ab_mover%natom) .and.(jj<=3)) then
411 195 : if (abs(vel_temp(jj,kk))<1.0d-50)&
412 0 : & vel_temp(jj,kk)=1.0d-50
413 195 : if (abs((vel_temp(jj,kk)-vonose(jj,kk))&
414 51 : & /vel_temp(jj,kk))>nosetol) ready=.false.
415 : else
416 : if (xin_nose<1.0d-50) xin_nose=1.0d-50
417 19 : if (abs((xin_nose-xio)/xin_nose)>nosetol) ready=.false.
418 : end if
419 : end do ! end of while
420 :
421 : ! Enddo ready
422 : end do
423 :
424 : !Update velocities to converged value
425 198 : vel(:,:)=vel_temp(:,:)
426 18 : write(message, '(a,es14.7)' )' converged velocities for T=',ktemp
427 18 : call wrtout(std_out,message,'COLL')
428 :
429 18 : if (zDEBUG)then
430 0 : write (std_out,*) 'Final Values for NOSE'
431 0 : write (std_out,*) 'VEL'
432 0 : do kk=1,ab_mover%natom
433 0 : write (std_out,*) vel(:,kk)
434 : end do
435 0 : write (std_out,*) 'XCART'
436 0 : do kk=1,ab_mover%natom
437 0 : write (std_out,*) xcart(:,kk)
438 : end do
439 : end if
440 :
441 : !Update thermostat
442 18 : xi_nose=xin_nose
443 198 : xcart_next(:,:)=xcart(:,:)
444 : !Convert back to xred_next (reduced coordinates)
445 18 : call xcart2xred(ab_mover%natom,rprimd,xcart_next,xred_next)
446 : !Store 'new force' as 'old force'
447 198 : fcart_mold(:,:)=fcart_m(:,:)
448 :
449 : !write(std_out,*) 'nose 06'
450 : !##########################################################
451 : !### 06. Update the history with the prediction
452 :
453 : !Increase indexes
454 18 : hist%ihist=abihist_findIndex(hist,+1)
455 :
456 18 : call var2hist(acell,hist,ab_mover%natom,rprimd,xred,zDEBUG)
457 198 : hist%vel(:,:,hist%ihist)=vel(:,:)
458 18 : hist%time(hist%ihist)=real(itime,kind=dp)*ab_mover%dtion
459 :
460 : end subroutine pred_nose
461 : !!***
462 :
463 : end module m_pred_nose
464 : !!***
|