(git:34ef472)
pint_qtb.F
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------------------------!
2 ! CP2K: A general program to perform molecular dynamics simulations !
3 ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 ! !
5 ! SPDX-License-Identifier: GPL-2.0-or-later !
6 !--------------------------------------------------------------------------------------------------!
7 
8 ! **************************************************************************************************
9 !> \brief Methods to apply the QTB thermostat to PI runs.
10 !> Based on the PILE implementation from Felix Uhl (pint_pile.F)
11 !> \author Fabien Brieuc
12 !> \par History
13 !> 02.2018 created [Fabien Brieuc]
14 ! **************************************************************************************************
15 MODULE pint_qtb
16  USE cp_files, ONLY: open_file
18  cp_logger_type
21  USE fft_lib, ONLY: fft_1dm,&
24  USE fft_plan, ONLY: fft_plan_type
25  USE fft_tools, ONLY: fwfft,&
27  fft_type
31  section_vals_type,&
33  USE kinds, ONLY: dp
34  USE mathconstants, ONLY: pi,&
35  twopi
36  USE message_passing, ONLY: mp_para_env_type
37  USE parallel_rng_types, ONLY: gaussian,&
39  rng_stream_type,&
41  USE pint_io, ONLY: pint_write_line
42  USE pint_types, ONLY: normalmode_env_type,&
43  pint_env_type,&
44  qtb_therm_type
45 #include "../base/base_uses.f90"
46 
47  IMPLICIT NONE
48 
49  PRIVATE
50 
51  PUBLIC :: pint_qtb_step, &
52  pint_qtb_init, &
55 
56  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pint_qtb'
57 
58 CONTAINS
59 
60 ! ***************************************************************************
61 !> \brief initializes the data for a QTB run
62 !> \brief ...
63 !> \param qtb_therm ...
64 !> \param pint_env ...
65 !> \param normalmode_env ...
66 !> \param section ...
67 ! **************************************************************************************************
68  SUBROUTINE pint_qtb_init(qtb_therm, pint_env, normalmode_env, section)
69  TYPE(qtb_therm_type), POINTER :: qtb_therm
70  TYPE(pint_env_type), INTENT(INOUT) :: pint_env
71  TYPE(normalmode_env_type), POINTER :: normalmode_env
72  TYPE(section_vals_type), POINTER :: section
73 
74  CHARACTER(LEN=rng_record_length) :: rng_record
75  INTEGER :: i, j, p
76  LOGICAL :: restart
77  REAL(kind=dp) :: dti2, ex
78  REAL(kind=dp), DIMENSION(3, 2) :: initial_seed
79  TYPE(section_vals_type), POINTER :: rng_section
80 
81  IF (pint_env%propagator%prop_kind /= propagator_rpmd) THEN
82  cpabort("QTB is designed to work with the RPMD propagator only")
83  END IF
84 
85  pint_env%e_qtb = 0.0_dp
86  ALLOCATE (qtb_therm)
87  qtb_therm%thermostat_energy = 0.0_dp
88 
89  !Get input parameters
90  CALL section_vals_val_get(section, "TAU", r_val=qtb_therm%tau)
91  CALL section_vals_val_get(section, "LAMBDA", r_val=qtb_therm%lamb)
92  CALL section_vals_val_get(section, "TAUCUT", r_val=qtb_therm%taucut)
93  CALL section_vals_val_get(section, "LAMBCUT", r_val=qtb_therm%lambcut)
94  CALL section_vals_val_get(section, "FP", i_val=qtb_therm%fp)
95  CALL section_vals_val_get(section, "NF", i_val=qtb_therm%nf)
96  CALL section_vals_val_get(section, "THERMOSTAT_ENERGY", r_val=qtb_therm%thermostat_energy)
97 
98  p = pint_env%p
99  dti2 = 0.5_dp*pint_env%dt
100  ALLOCATE (qtb_therm%c1(p))
101  ALLOCATE (qtb_therm%c2(p))
102  ALLOCATE (qtb_therm%g_fric(p))
103  ALLOCATE (qtb_therm%massfact(p, pint_env%ndim))
104 
105  !Initialize everything
106  qtb_therm%g_fric(1) = 1.0_dp/qtb_therm%tau
107  DO i = 2, p
108  qtb_therm%g_fric(i) = sqrt((1.d0/qtb_therm%tau)**2 + (qtb_therm%lamb)**2* &
109  normalmode_env%lambda(i))
110  END DO
111  DO i = 1, p
112  ex = -dti2*qtb_therm%g_fric(i)
113  qtb_therm%c1(i) = exp(ex)
114  ex = qtb_therm%c1(i)*qtb_therm%c1(i)
115  qtb_therm%c2(i) = sqrt(1.0_dp - ex)
116  END DO
117  DO j = 1, pint_env%ndim
118  DO i = 1, pint_env%p
119  qtb_therm%massfact(i, j) = sqrt(1.0_dp/pint_env%mass_fict(i, j))
120  END DO
121  END DO
122 
123  !prepare Random number generator
124  NULLIFY (rng_section)
125  rng_section => section_vals_get_subs_vals(section, &
126  subsection_name="RNG_INIT")
127  CALL section_vals_get(rng_section, explicit=restart)
128  IF (restart) THEN
129  CALL section_vals_val_get(rng_section, "_DEFAULT_KEYWORD_", &
130  i_rep_val=1, c_val=rng_record)
131  qtb_therm%gaussian_rng_stream = rng_stream_type_from_record(rng_record)
132  ELSE
133  initial_seed(:, :) = real(pint_env%thermostat_rng_seed, dp)
134  qtb_therm%gaussian_rng_stream = rng_stream_type( &
135  name="qtb_rng_gaussian", distribution_type=gaussian, &
136  extended_precision=.true., &
137  seed=initial_seed)
138  END IF
139 
140  !Initialization of the QTB random forces
141  CALL pint_qtb_forces_init(pint_env, normalmode_env, qtb_therm, restart)
142 
143  END SUBROUTINE pint_qtb_init
144 
145 ! **************************************************************************************************
146 !> \brief ...
147 !> \param vold ...
148 !> \param vnew ...
149 !> \param p ...
150 !> \param ndim ...
151 !> \param masses ...
152 !> \param qtb_therm ...
153 ! **************************************************************************************************
154  SUBROUTINE pint_qtb_step(vold, vnew, p, ndim, masses, qtb_therm)
155  REAL(kind=dp), DIMENSION(:, :), POINTER :: vold, vnew
156  INTEGER, INTENT(IN) :: p, ndim
157  REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: masses
158  TYPE(qtb_therm_type), POINTER :: qtb_therm
159 
160  CHARACTER(len=*), PARAMETER :: routinen = 'pint_qtb_step'
161 
162  INTEGER :: handle, i, ibead, idim
163  REAL(kind=dp) :: delta_ekin
164 
165  CALL timeset(routinen, handle)
166  delta_ekin = 0.0_dp
167 
168  !update random forces
169  DO ibead = 1, p
170  qtb_therm%cpt(ibead) = qtb_therm%cpt(ibead) + 1
171  !new random forces at every qtb_therm%step
172  IF (qtb_therm%cpt(ibead) == 2*qtb_therm%step(ibead)) THEN
173  IF (ibead == 1) THEN
174  !update the rng status
175  DO i = 1, qtb_therm%nf - 1
176  qtb_therm%rng_status(i) = qtb_therm%rng_status(i + 1)
177  END DO
178  CALL qtb_therm%gaussian_rng_stream%dump(qtb_therm%rng_status(qtb_therm%nf))
179  END IF
180  DO idim = 1, ndim
181  !update random numbers
182  DO i = 1, qtb_therm%nf - 1
183  qtb_therm%r(i, ibead, idim) = qtb_therm%r(i + 1, ibead, idim)
184  END DO
185  qtb_therm%r(qtb_therm%nf, ibead, idim) = qtb_therm%gaussian_rng_stream%next()
186  !compute new random force through the convolution product
187  qtb_therm%rf(ibead, idim) = 0.0_dp
188  DO i = 1, qtb_therm%nf
189  qtb_therm%rf(ibead, idim) = qtb_therm%rf(ibead, idim) + &
190  qtb_therm%h(i, ibead)*qtb_therm%r(i, ibead, idim)
191  END DO
192  END DO
193  qtb_therm%cpt(ibead) = 0
194  END IF
195  END DO
196 
197  !perform MD step
198  DO idim = 1, ndim
199  DO ibead = 1, p
200  vnew(ibead, idim) = qtb_therm%c1(ibead)*vold(ibead, idim) + &
201  qtb_therm%massfact(ibead, idim)*qtb_therm%c2(ibead)* &
202  qtb_therm%rf(ibead, idim)
203  delta_ekin = delta_ekin + masses(ibead, idim)*( &
204  vnew(ibead, idim)*vnew(ibead, idim) - &
205  vold(ibead, idim)*vold(ibead, idim))
206  END DO
207  END DO
208 
209  qtb_therm%thermostat_energy = qtb_therm%thermostat_energy - 0.5_dp*delta_ekin
210 
211  CALL timestop(handle)
212  END SUBROUTINE pint_qtb_step
213 
214 ! ***************************************************************************
215 !> \brief releases the qtb environment
216 !> \param qtb_therm qtb data to be released
217 ! **************************************************************************************************
218  SUBROUTINE pint_qtb_release(qtb_therm)
219 
220  TYPE(qtb_therm_type), INTENT(INOUT) :: qtb_therm
221 
222  DEALLOCATE (qtb_therm%c1)
223  DEALLOCATE (qtb_therm%c2)
224  DEALLOCATE (qtb_therm%g_fric)
225  DEALLOCATE (qtb_therm%massfact)
226  DEALLOCATE (qtb_therm%rf)
227  DEALLOCATE (qtb_therm%h)
228  DEALLOCATE (qtb_therm%r)
229  DEALLOCATE (qtb_therm%cpt)
230  DEALLOCATE (qtb_therm%step)
231  DEALLOCATE (qtb_therm%rng_status)
232 
233  END SUBROUTINE pint_qtb_release
234 
235 ! ***************************************************************************
236 !> \brief returns the qtb kinetic energy contribution
237 !> \param pint_env ...
238 ! **************************************************************************************************
239  SUBROUTINE pint_calc_qtb_energy(pint_env)
240  TYPE(pint_env_type), INTENT(INOUT) :: pint_env
241 
242  IF (ASSOCIATED(pint_env%qtb_therm)) THEN
243  pint_env%e_qtb = pint_env%qtb_therm%thermostat_energy
244  END IF
245 
246  END SUBROUTINE pint_calc_qtb_energy
247 
248 ! ***************************************************************************
249 !> \brief initialize the QTB random forces
250 !> \param pint_env ...
251 !> \param normalmode_env ...
252 !> \param qtb_therm ...
253 !> \param restart ...
254 !> \author Fabien Brieuc
255 ! **************************************************************************************************
256  SUBROUTINE pint_qtb_forces_init(pint_env, normalmode_env, qtb_therm, restart)
257  TYPE(pint_env_type), INTENT(IN) :: pint_env
258  TYPE(normalmode_env_type), POINTER :: normalmode_env
259  TYPE(qtb_therm_type), POINTER :: qtb_therm
260  LOGICAL :: restart
261 
262  CHARACTER(len=*), PARAMETER :: routinen = 'pint_qtb_forces_init'
263 
264  COMPLEX(KIND=dp) :: tmp1
265  COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:) :: filter
266  INTEGER :: handle, i, ibead, idim, log_unit, ndim, &
267  nf, p, print_level, step
268  REAL(kind=dp) :: aa, bb, correct, dt, dw, fcut, h, kt, &
269  tmp, w
270  REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: fp
271  REAL(kind=dp), DIMENSION(:), POINTER :: fp1
272  TYPE(cp_logger_type), POINTER :: logger
273  TYPE(fft_plan_type) :: plan
274  TYPE(mp_para_env_type), POINTER :: para_env
275 
276  CALL timeset(routinen, handle)
277 
278  IF (fft_type /= 3) CALL cp_warn(__location__, "The FFT library in use cannot"// &
279  " handle transformation of an arbitrary length.")
280 
281  p = pint_env%p
282  ndim = pint_env%ndim
283  dt = pint_env%dt
284  IF (mod(qtb_therm%nf, 2) /= 0) qtb_therm%nf = qtb_therm%nf + 1
285  nf = qtb_therm%nf
286 
287  para_env => pint_env%logger%para_env
288 
289  ALLOCATE (qtb_therm%rng_status(nf))
290  ALLOCATE (qtb_therm%h(nf, p))
291  ALLOCATE (qtb_therm%step(p))
292 
293  !initialize random forces on ionode only
294  IF (para_env%is_source()) THEN
295 
296  NULLIFY (logger)
297  logger => cp_get_default_logger()
298  print_level = logger%iter_info%print_level
299 
300  !physical temperature (T) not the simulation one (TxP)
301  kt = pint_env%kT*pint_env%propagator%temp_sim2phys
302 
303  ALLOCATE (fp(nf/2))
304  ALLOCATE (filter(0:nf - 1))
305 
306  IF (print_level == debug_print_level) THEN
307  !create log file if print_level is debug
308  CALL open_file(file_name=trim(logger%iter_info%project_name)//".qtbLog", &
309  file_action="WRITE", file_status="UNKNOWN", unit_number=log_unit)
310  WRITE (log_unit, '(A)') ' # Log file for the QTB random forces generation'
311  WRITE (log_unit, '(A)') ' # ------------------------------------------------'
312  WRITE (log_unit, '(A,I5)') ' # Number of beads P = ', p
313  WRITE (log_unit, '(A,I6)') ' # Number of dimension 3*N = ', ndim
314  WRITE (log_unit, '(A,I4)') ' # Number of filter parameters Nf=', nf
315  END IF
316 
317  DO ibead = 1, p
318  !fcut is adapted to the NM freq.
319  !Note that lambda is the angular free ring freq. squared
320  fcut = sqrt((1.d0/qtb_therm%taucut)**2 + (qtb_therm%lambcut)**2* &
321  normalmode_env%lambda(ibead))
322  fcut = fcut/twopi
323  !new random forces are drawn every step
324  qtb_therm%step(ibead) = nint(1.0_dp/(2.0_dp*fcut*dt))
325  IF (qtb_therm%step(ibead) == 0) qtb_therm%step(ibead) = 1
326  step = qtb_therm%step(ibead)
327  !effective timestep h = step*dt = 1/(2*fcut)
328  h = step*dt
329  !angular freq. step - dw = 2*pi/(nf*h) = 2*wcut/nf
330  dw = twopi/(nf*h)
331 
332  !generate f_P function
333  IF (qtb_therm%fp == 0) THEN
334  CALL pint_qtb_computefp0(pint_env, fp, fp1, dw, aa, bb, log_unit, ibead, print_level)
335  ELSE
336  CALL pint_qtb_computefp1(pint_env, fp, fp1, dw, aa, bb, log_unit, ibead, print_level)
337  END IF
338  fp = p*kt*fp ! fp is now in cp2k energy units
339 
340  IF (print_level == debug_print_level) THEN
341  WRITE (log_unit, '(A,I4,A)') ' # -------- NM ', ibead, ' --------'
342  WRITE (log_unit, '(A,I4,A)') ' # New random forces every ', step, ' MD steps'
343  WRITE (log_unit, '(A,ES13.3,A)') ' # Angular cutoff freq. = ', twopi*fcut*4.1341e4_dp, ' rad/ps'
344  WRITE (log_unit, '(A,ES13.3,A)') ' # Free ring polymer angular freq.= ', &
345  sqrt(normalmode_env%lambda(ibead))*4.1341e4_dp, ' rad/ps'
346  WRITE (log_unit, '(A,ES13.3,A)') ' # Friction coeff. = ', qtb_therm%g_fric(ibead)*4.1341e4_dp, ' THz'
347  WRITE (log_unit, '(A,ES13.3,A)') ' # Angular frequency step dw = ', dw*4.1341e4_dp, ' rad/ps'
348  END IF
349 
350  !compute the filter in Fourier space
351  IF (p == 1) THEN
352  filter(0) = sqrt(kt)*(1.0_dp, 0.0_dp)
353  ELSE IF (qtb_therm%fp == 1 .AND. ibead == 1) THEN
354  filter(0) = sqrt(p*kt)*(1.0_dp, 0.0_dp)
355  ELSE
356  filter(0) = sqrt(p*kt*fp1(1))*(1.0_dp, 0.0_dp)
357  END IF
358  DO i = 1, nf/2
359  w = i*dw
360  tmp = 0.5_dp*w*h
361  correct = sin(tmp)/tmp
362  filter(i) = sqrt(fp(i))/correct*(1.0_dp, 0.0_dp)
363  filter(nf - i) = conjg(filter(i))
364  END DO
365 
366  !compute the filter in time space - FFT
367  CALL pint_qtb_fft(filter, filter, plan, nf)
368  !reordering + normalisation
369  !normalisation : 1/nf comes from the DFT, 1/sqrt(step) is to
370  !take into account the effective timestep h = step*dt and
371  !1/sqrt(2.0_dp) is to take into account the fact that the
372  !same random force is used for the two thermostat "half-steps"
373  DO i = 0, nf/2 - 1
374  tmp1 = filter(i)/(nf*sqrt(2.0_dp*step))
375  filter(i) = filter(nf/2 + i)/(nf*sqrt(2.0_dp*step))
376  filter(nf/2 + i) = tmp1
377  END DO
378 
379  DO i = 0, nf - 1
380  qtb_therm%h(i + 1, ibead) = real(filter(i), dp)
381  END DO
382  END DO
383 
384  DEALLOCATE (filter)
385  DEALLOCATE (fp)
386  IF (p > 1) DEALLOCATE (fp1)
387  END IF
388 
389  CALL para_env%bcast(qtb_therm%h)
390  CALL para_env%bcast(qtb_therm%step)
391 
392  ALLOCATE (qtb_therm%r(nf, p, ndim))
393  ALLOCATE (qtb_therm%cpt(p))
394  ALLOCATE (qtb_therm%rf(p, ndim))
395 
396  IF (restart) THEN
397  CALL pint_qtb_restart(pint_env, qtb_therm)
398  ELSE
399  !update the rng status
400  DO i = 1, qtb_therm%nf
401  CALL qtb_therm%gaussian_rng_stream%dump(qtb_therm%rng_status(i))
402  END DO
403  !if no restart then initialize random numbers from scratch
404  qtb_therm%cpt = 0
405  DO idim = 1, ndim
406  DO ibead = 1, p
407  DO i = 1, nf
408  qtb_therm%r(i, ibead, idim) = qtb_therm%gaussian_rng_stream%next()
409  END DO
410  END DO
411  END DO
412  END IF
413 
414  !compute the first random forces
415  DO idim = 1, ndim
416  DO ibead = 1, p
417  qtb_therm%rf(ibead, idim) = 0.0_dp
418  DO i = 1, nf
419  qtb_therm%rf(ibead, idim) = qtb_therm%rf(ibead, idim) + &
420  qtb_therm%h(i, ibead)*qtb_therm%r(i, ibead, idim)
421  END DO
422  END DO
423  END DO
424 
425  CALL timestop(handle)
426  END SUBROUTINE pint_qtb_forces_init
427 
428 ! ***************************************************************************
429 !> \brief control the generation of the first random forces in the case
430 !> of a restart
431 !> \param pint_env ...
432 !> \param qtb_therm ...
433 !> \author Fabien Brieuc
434 ! **************************************************************************************************
435  SUBROUTINE pint_qtb_restart(pint_env, qtb_therm)
436  TYPE(pint_env_type), INTENT(IN) :: pint_env
437  TYPE(qtb_therm_type), POINTER :: qtb_therm
438 
439  INTEGER :: begin, i, ibead, idim, istep
440 
441  begin = pint_env%first_step - mod(pint_env%first_step, qtb_therm%step(1)) - &
442  (qtb_therm%nf - 1)*qtb_therm%step(1)
443 
444  IF (begin <= 0) THEN
445  qtb_therm%cpt = 0
446  !update the rng status
447  DO i = 1, qtb_therm%nf
448  CALL qtb_therm%gaussian_rng_stream%dump(qtb_therm%rng_status(i))
449  END DO
450  !first random numbers initialized from scratch
451  DO idim = 1, pint_env%ndim
452  DO ibead = 1, pint_env%p
453  DO i = 1, qtb_therm%nf
454  qtb_therm%r(i, ibead, idim) = qtb_therm%gaussian_rng_stream%next()
455  END DO
456  END DO
457  END DO
458  begin = 1
459  ELSE
460  qtb_therm%cpt(1) = 2*(qtb_therm%step(1) - 1)
461  DO ibead = 2, pint_env%p
462  qtb_therm%cpt(ibead) = 2*mod(begin - 1, qtb_therm%step(ibead))
463  END DO
464  END IF
465 
466  !from istep = 1,2*(the last previous MD step - begin) because
467  !the thermostat step is called two times per MD step
468  !DO istep = 2*begin, 2*pint_env%first_step
469  DO istep = 1, 2*(pint_env%first_step - begin + 1)
470  DO ibead = 1, pint_env%p
471  qtb_therm%cpt(ibead) = qtb_therm%cpt(ibead) + 1
472  !new random forces at every qtb_therm%step
473  IF (qtb_therm%cpt(ibead) == 2*qtb_therm%step(ibead)) THEN
474  IF (ibead == 1) THEN
475  !update the rng status
476  DO i = 1, qtb_therm%nf - 1
477  qtb_therm%rng_status(i) = qtb_therm%rng_status(i + 1)
478  END DO
479  CALL qtb_therm%gaussian_rng_stream%dump(qtb_therm%rng_status(qtb_therm%nf))
480  END IF
481  DO idim = 1, pint_env%ndim
482  !update random numbers
483  DO i = 1, qtb_therm%nf - 1
484  qtb_therm%r(i, ibead, idim) = qtb_therm%r(i + 1, ibead, idim)
485  END DO
486  qtb_therm%r(qtb_therm%nf, ibead, idim) = qtb_therm%gaussian_rng_stream%next()
487  END DO
488  qtb_therm%cpt(ibead) = 0
489  END IF
490  END DO
491  END DO
492 
493  END SUBROUTINE pint_qtb_restart
494 
495 ! ***************************************************************************
496 !> \brief compute the f_P^(0) function necessary for coupling QTB with PIMD
497 !> \param pint_env ...
498 !> \param fp stores the computed function on the grid used for the generation
499 !> of the filter h
500 !> \param fp1 stores the computed function on an larger and finer grid
501 !> \param dw angular frequency step
502 !> \param aa ...
503 !> \param bb ...
504 !> \param log_unit ...
505 !> \param ibead ...
506 !> \param print_level ...
507 !> \author Fabien Brieuc
508 ! **************************************************************************************************
509  SUBROUTINE pint_qtb_computefp0(pint_env, fp, fp1, dw, aa, bb, log_unit, ibead, print_level)
510  TYPE(pint_env_type), INTENT(IN) :: pint_env
511  REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: fp
512  REAL(kind=dp), DIMENSION(:), POINTER :: fp1
513  REAL(kind=dp), INTENT(IN) :: dw, aa, bb
514  INTEGER, INTENT(IN) :: log_unit, ibead, print_level
515 
516  CHARACTER(len=200) :: line
517  INTEGER :: i, j, k, n, niter, nx, p
518  INTEGER, ALLOCATABLE, DIMENSION(:, :) :: kk
519  REAL(kind=dp) :: dx, dx1, err, fprev, hbokt, malpha, op, &
520  r2, tmp, w, x1, xmax, xmin, xx
521  REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: h, x, x2
522  REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: fpxk, xk, xk2
523 
524  n = SIZE(fp)
525  p = pint_env%p
526 
527  !using the physical temperature (T) not the simulation one (TxP)
528  hbokt = 1.0_dp/(pint_env%kT*pint_env%propagator%temp_sim2phys)
529 
530  !P = 1 : standard QTB
531  !fp = theta(w, T) / kT
532  IF (p == 1) THEN
533  DO j = 1, n
534  w = j*dw
535  tmp = hbokt*w
536  fp(j) = tmp*(0.5_dp + 1.0_dp/(exp(tmp) - 1.0_dp))
537  END DO
538 
539  IF (print_level == debug_print_level) THEN
540  WRITE (log_unit, '(A)') ' # ------------------------------------------------'
541  WRITE (log_unit, '(A)') ' # computed fp^(0) function'
542  WRITE (log_unit, '(A)') ' # i, w(a.u.), fp'
543  DO j = 1, n
544  WRITE (log_unit, *) j, j*dw, j*0.5_dp*hbokt*dw, fp(j)
545  END DO
546  END IF
547  ! P > 1: QTB-PIMD
548  ELSE
549  !**** initialization ****
550  dx1 = 0.5_dp*hbokt*dw
551  xmin = 1.0e-7_dp !these values allows for an acceptable
552  dx = 0.05_dp !ratio between accuracy, computing time and
553  xmax = 10000.0_dp !memory requirement - tested for P up to 1024
554  nx = int((xmax - xmin)/dx) + 1
555  nx = nx + nx/5 !add 20% points to avoid any problems at the end
556  !of the interval (probably unnecessary)
557  IF (ibead == 1) THEN
558  op = 1.0_dp/p
559  malpha = op !mixing parameter alpha = 1/P
560  niter = 30 !30 iterations are enough to converge
561 
562  IF (print_level == debug_print_level) THEN
563  WRITE (log_unit, '(A)') ' # ------------------------------------------------'
564  WRITE (log_unit, '(A)') ' # computing fp^(0) function'
565  WRITE (log_unit, '(A)') ' # parameters used:'
566  WRITE (log_unit, '(A,ES13.3)') ' # dx = ', dx
567  WRITE (log_unit, '(A,ES13.3)') ' # xmin = ', xmin
568  WRITE (log_unit, '(A,ES13.3)') ' # xmax = ', xmax
569  WRITE (log_unit, '(A,I8,I8)') ' # nx, n = ', nx, n
570  END IF
571 
572  ALLOCATE (x(nx))
573  ALLOCATE (x2(nx))
574  ALLOCATE (h(nx))
575  ALLOCATE (fp1(nx))
576  ALLOCATE (xk(p - 1, nx))
577  ALLOCATE (xk2(p - 1, nx))
578  ALLOCATE (kk(p - 1, nx))
579  ALLOCATE (fpxk(p - 1, nx))
580 
581  ! initialize fp(x)
582  ! fp1 = fp(x) = h(x/P)
583  ! fpxk = fp(xk) = h(xk/P)
584  DO j = 1, nx
585  x(j) = xmin + (j - 1)*dx
586  x2(j) = x(j)**2
587  h(j) = x(j)/tanh(x(j))
588  IF (x(j) <= 1.0e-10_dp) h(j) = 1.0_dp
589  fp1(j) = op*x(j)/tanh(x(j)*op)
590  IF (x(j)*op <= 1.0e-10_dp) fp1(j) = 1.0_dp
591  DO k = 1, p - 1
592  xk2(k, j) = x2(j) + (p*sin(k*pi*op))**2
593  xk(k, j) = sqrt(xk2(k, j))
594  kk(k, j) = nint((xk(k, j) - xmin)/dx) + 1
595  fpxk(k, j) = xk(k, j)*op/tanh(xk(k, j)*op)
596  IF (xk(k, j)*op <= 1.0e-10_dp) fpxk(k, j) = 1.0_dp
597  END DO
598  END DO
599 
600  ! **** resolution ****
601  ! compute fp(x)
602  DO i = 1, niter
603  err = 0.0_dp
604  DO j = 1, nx
605  tmp = 0.0_dp
606  DO k = 1, p - 1
607  tmp = tmp + fpxk(k, j)*x2(j)/xk2(k, j)
608  END DO
609  fprev = fp1(j)
610  fp1(j) = malpha*(h(j) - tmp) + (1.0_dp - malpha)*fp1(j)
611  IF (j <= n) err = err + abs(1.0_dp - fp1(j)/fprev) ! compute "errors"
612  END DO
613  err = err/n
614 
615  ! Linear regression on the last 20% of the F_P function
616  CALL pint_qtb_linreg(fp1(8*nx/10:nx), x(8*nx/10:nx), aa, bb, r2, log_unit, print_level)
617 
618  ! compute the new F_P(xk*sqrt(P))
619  ! through linear interpolation
620  ! or linear extrapolation if outside of the range
621  DO j = 1, nx
622  DO k = 1, p - 1
623  IF (kk(k, j) < nx) THEN
624  fpxk(k, j) = fp1(kk(k, j)) + (fp1(kk(k, j) + 1) - fp1(kk(k, j)))/dx* &
625  (xk(k, j) - x(kk(k, j)))
626  ELSE
627  fpxk(k, j) = aa*xk(k, j) + bb
628  END IF
629  END DO
630  END DO
631  END DO
632 
633  IF (print_level == debug_print_level) THEN
634  ! **** tests ****
635  WRITE (log_unit, '(A,ES9.3)') ' # average error during computation: ', err
636  WRITE (log_unit, '(A,ES9.3)') ' # slope of F_P at high freq. - theoretical: ', op
637  WRITE (log_unit, '(A,ES9.3)') ' # slope of F_P at high freq. - calculated: ', aa
638  WRITE (log_unit, '(A,F6.3)') ' # F_P at zero freq. - theoretical: ', 1.0_dp
639  WRITE (log_unit, '(A,F6.3)') ' # F_P at zero freq. - calculated: ', fp1(1)
640  ELSE IF (print_level > silent_print_level) THEN
641  CALL pint_write_line("QTB| Initialization of random forces using fP0 function")
642  CALL pint_write_line("QTB| Computation of fP0 function")
643  WRITE (line, '(A,ES9.3)') 'QTB| average error ', err
644  CALL pint_write_line(trim(line))
645  WRITE (line, '(A,ES9.3)') 'QTB| slope at high frequency - theoretical: ', op
646  CALL pint_write_line(trim(line))
647  WRITE (line, '(A,ES9.3)') 'QTB| slope at high frequency - calculated: ', aa
648  CALL pint_write_line(trim(line))
649  WRITE (line, '(A,F6.3)') 'QTB| value at zero frequency - theoretical: ', 1.0_dp
650  CALL pint_write_line(trim(line))
651  WRITE (line, '(A,F6.3)') 'QTB| value at zero frequency - calculated: ', fp1(1)
652  CALL pint_write_line(trim(line))
653  END IF
654 
655  IF (print_level == debug_print_level) THEN
656  ! **** write solution ****
657  WRITE (log_unit, '(A)') ' # ------------------------------------------------'
658  WRITE (log_unit, '(A)') ' # computed fp function'
659  WRITE (log_unit, '(A)') ' # i, w(a.u.), x, fp'
660  DO j = 1, nx
661  WRITE (log_unit, *) j, j*dw, xmin + (j - 1)*dx, fp1(j)
662  END DO
663  END IF
664 
665  DEALLOCATE (x)
666  DEALLOCATE (x2)
667  DEALLOCATE (h)
668  DEALLOCATE (xk)
669  DEALLOCATE (xk2)
670  DEALLOCATE (kk)
671  DEALLOCATE (fpxk)
672  END IF
673 
674  ! compute values of fP on the grid points for the current NM
675  ! through linear interpolation / regression
676  DO j = 1, n
677  x1 = j*dx1
678  k = nint((x1 - xmin)/dx) + 1
679  IF (k > nx) THEN
680  fp(j) = aa*x1 + bb
681  ELSE IF (k <= 0) THEN
682  CALL pint_write_line("QTB| error in fp computation x < xmin")
683  cpabort("Error in fp computation (x < xmin) in initialization of QTB random forces")
684  ELSE
685  xx = xmin + (k - 1)*dx
686  IF (x1 > xx) THEN
687  fp(j) = fp1(k) + (fp1(k + 1) - fp1(k))/dx*(x1 - xx)
688  ELSE
689  fp(j) = fp1(k) + (fp1(k) - fp1(k - 1))/dx*(x1 - xx)
690  END IF
691  END IF
692  END DO
693 
694  END IF
695 
696  END SUBROUTINE pint_qtb_computefp0
697 
698 ! ***************************************************************************
699 !> \brief compute the f_P^(1) function necessary for coupling QTB with PIMD
700 !> \param pint_env ...
701 !> \param fp stores the computed function on the grid used for the generation
702 !> of the filter h
703 !> \param fp1 stores the computed function on an larger and finer grid
704 !> \param dw angular frequency step
705 !> \param aa ...
706 !> \param bb ...
707 !> \param log_unit ...
708 !> \param ibead ...
709 !> \param print_level ...
710 !> \author Fabien Brieuc
711 ! **************************************************************************************************
712  SUBROUTINE pint_qtb_computefp1(pint_env, fp, fp1, dw, aa, bb, log_unit, ibead, print_level)
713  TYPE(pint_env_type), INTENT(IN) :: pint_env
714  REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: fp
715  REAL(kind=dp), DIMENSION(:), POINTER :: fp1
716  REAL(kind=dp) :: dw, aa, bb
717  INTEGER, INTENT(IN) :: log_unit, ibead, print_level
718 
719  CHARACTER(len=200) :: line
720  INTEGER :: i, j, k, n, niter, nx, p
721  INTEGER, ALLOCATABLE, DIMENSION(:, :) :: kk
722  REAL(kind=dp) :: dx, dx1, err, fprev, hbokt, malpha, op, &
723  op1, r2, tmp, tmp1, xmax, xmin, xx
724  REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: h, x, x2
725  REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: fpxk, xk, xk2
726 
727  n = SIZE(fp)
728  p = pint_env%p
729 
730  !using the physical temperature (T) not the simulation one (TxP)
731  hbokt = 1.0_dp/(pint_env%kT*pint_env%propagator%temp_sim2phys)
732 
733  !Centroid NM (ibead=1) : classical
734  !fp = 1
735  IF (ibead == 1) THEN
736  DO j = 1, n
737  fp(j) = 1.0_dp
738  END DO
739  ELSE
740  !**** initialization ****
741  dx1 = 0.5_dp*hbokt*dw
742  xmin = 1.0e-3_dp !these values allows for an acceptable
743  dx = 0.05_dp !ratio between accuracy, computing time and
744  xmax = 10000.0_dp !memory requirement - tested for P up to 1024
745  nx = int((xmax - xmin)/dx) + 1
746  nx = nx + nx/5 !add 20% points to avoid problem at the end
747  !of the interval (probably unnecessary)
748  op = 1.0_dp/p
749  IF (ibead == 2) THEN
750  op1 = 1.0_dp/(p - 1)
751  malpha = op !mixing parameter alpha = 1/P
752  niter = 40 !40 iterations are enough to converge
753 
754  IF (print_level == debug_print_level) THEN
755  ! **** write solution ****
756  WRITE (log_unit, '(A)') ' # ------------------------------------------------'
757  WRITE (log_unit, '(A)') ' # computing fp^(1) function'
758  WRITE (log_unit, '(A)') ' # parameters used:'
759  WRITE (log_unit, '(A,ES13.3)') ' # dx = ', dx
760  WRITE (log_unit, '(A,ES13.3)') ' # xmin = ', xmin
761  WRITE (log_unit, '(A,ES13.3)') ' # xmax = ', xmax
762  WRITE (log_unit, '(A,I8,I8)') ' # nx, n = ', nx, n
763  END IF
764 
765  ALLOCATE (x(nx))
766  ALLOCATE (x2(nx))
767  ALLOCATE (h(nx))
768  ALLOCATE (fp1(nx))
769  ALLOCATE (xk(p - 1, nx))
770  ALLOCATE (xk2(p - 1, nx))
771  ALLOCATE (kk(p - 1, nx))
772  ALLOCATE (fpxk(p - 1, nx))
773 
774  ! initialize F_P(x) = f_P(x_1)
775  ! fp1 = fp(x) = h(x/(P-1))
776  ! fpxk = fp(xk) = h(xk/(P-1))
777  DO j = 1, nx
778  x(j) = xmin + (j - 1)*dx
779  x2(j) = x(j)**2
780  h(j) = x(j)/tanh(x(j))
781  IF (x(j) <= 1.0e-10_dp) h(j) = 1.0_dp
782  fp1(j) = op1*x(j)/tanh(x(j)*op1)
783  IF (x(j)*op1 <= 1.0e-10_dp) fp1(j) = 1.0_dp
784  DO k = 1, p - 1
785  xk2(k, j) = x2(j) + (p*sin(k*pi*op))**2
786  xk(k, j) = sqrt(xk2(k, j) - (p*sin(pi*op))**2)
787  kk(k, j) = nint((xk(k, j) - xmin)/dx) + 1
788  fpxk(k, j) = xk(k, j)*op1/tanh(xk(k, j)*op1)
789  IF (xk(k, j)*op1 <= 1.0e-10_dp) fpxk(k, j) = 1.0_dp
790  END DO
791  END DO
792 
793  ! **** resolution ****
794  ! compute fp(x)
795  DO i = 1, niter
796  err = 0.0_dp
797  DO j = 1, nx
798  tmp = 0.0_dp
799  DO k = 2, p - 1
800  tmp = tmp + fpxk(k, j)*x2(j)/xk2(k, j)
801  END DO
802  fprev = fp1(j)
803  tmp1 = 1.0_dp + (p*sin(pi*op)/x(j))**2
804  fp1(j) = malpha*tmp1*(h(j) - 1.0_dp - tmp) + (1.0_dp - malpha)*fp1(j)
805  IF (j <= n) err = err + abs(1.0_dp - fp1(j)/fprev) ! compute "errors"
806  END DO
807  err = err/n
808 
809  ! Linear regression on the last 20% of the F_P function
810  CALL pint_qtb_linreg(fp1(8*nx/10:nx), x(8*nx/10:nx), aa, bb, r2, log_unit, print_level)
811 
812  ! compute the new F_P(xk*sqrt(P))
813  ! through linear interpolation
814  ! or linear extrapolation if outside of the range
815  DO j = 1, nx
816  DO k = 1, p - 1
817  IF (kk(k, j) < nx) THEN
818  fpxk(k, j) = fp1(kk(k, j)) + (fp1(kk(k, j) + 1) - fp1(kk(k, j)))/dx* &
819  (xk(k, j) - x(kk(k, j)))
820  ELSE
821  fpxk(k, j) = aa*xk(k, j) + bb
822  END IF
823  END DO
824  END DO
825  END DO
826 
827  IF (print_level == debug_print_level) THEN
828  ! **** tests ****
829  WRITE (log_unit, '(A,ES9.3)') ' # average error during computation: ', err
830  WRITE (log_unit, '(A,ES9.3)') ' # slope of F_P at high freq. - theoretical: ', op1
831  WRITE (log_unit, '(A,ES9.3)') ' # slope of F_P at high freq. - calculated: ', aa
832  ELSE IF (print_level > silent_print_level) THEN
833  CALL pint_write_line("QTB| Initialization of random forces using fP1 function")
834  CALL pint_write_line("QTB| Computation of fP1 function")
835  WRITE (line, '(A,ES9.3)') 'QTB| average error ', err
836  CALL pint_write_line(trim(line))
837  WRITE (line, '(A,ES9.3)') 'QTB| slope at high frequency - theoretical: ', op1
838  CALL pint_write_line(trim(line))
839  WRITE (line, '(A,ES9.3)') 'QTB| slope at high frequency - calculated: ', aa
840  CALL pint_write_line(trim(line))
841  END IF
842 
843  IF (print_level == debug_print_level) THEN
844  ! **** write solution ****
845  WRITE (log_unit, '(A)') ' # ------------------------------------------------'
846  WRITE (log_unit, '(A)') ' # computed fp function'
847  WRITE (log_unit, '(A)') ' # i, w(a.u.), x, fp'
848  DO j = 1, nx
849  WRITE (log_unit, *) j, j*dw, xmin + (j - 1)*dx, fp1(j)
850  END DO
851  END IF
852 
853  DEALLOCATE (x2)
854  DEALLOCATE (h)
855  DEALLOCATE (xk)
856  DEALLOCATE (xk2)
857  DEALLOCATE (kk)
858  DEALLOCATE (fpxk)
859  END IF
860 
861  ! compute values of fP on the grid points for the current NM
862  ! trough linear interpolation / regression
863  DO j = 1, n
864  tmp = (j*dx1)**2 - (p*sin(pi*op))**2
865  IF (tmp < 0.d0) THEN
866  fp(j) = fp1(1)
867  ELSE
868  tmp = sqrt(tmp)
869  k = nint((tmp - xmin)/dx) + 1
870  IF (k > nx) THEN
871  fp(j) = aa*tmp + bb
872  ELSE IF (k <= 0) THEN
873  fp(j) = fp1(1)
874  ELSE
875  xx = xmin + (k - 1)*dx
876  IF (tmp > xx) THEN
877  fp(j) = fp1(k) + (fp1(k + 1) - fp1(k))/dx*(tmp - xx)
878  ELSE
879  fp(j) = fp1(k) + (fp1(k) - fp1(k - 1))/dx*(tmp - xx)
880  END IF
881  END IF
882  END IF
883  END DO
884 
885  END IF
886 
887  END SUBROUTINE pint_qtb_computefp1
888 
889 ! ***************************************************************************
890 !> \brief perform a simple linear regression - y(x) = a*x + b
891 !> \param y ...
892 !> \param x ...
893 !> \param a ...
894 !> \param b ...
895 !> \param r2 ...
896 !> \param log_unit ...
897 !> \param print_level ...
898 !> \author Fabien Brieuc
899 ! **************************************************************************************************
900  SUBROUTINE pint_qtb_linreg(y, x, a, b, r2, log_unit, print_level)
901  REAL(kind=dp), DIMENSION(:) :: y, x
902  REAL(kind=dp) :: a, b, r2
903  INTEGER :: log_unit, print_level
904 
905  CHARACTER(len=200) :: line
906  INTEGER :: i, n
907  REAL(kind=dp) :: xav, xvar, xycov, yav, yvar
908 
909  n = SIZE(y)
910 
911  xav = 0.0_dp
912  yav = 0.0_dp
913  xycov = 0.0_dp
914  xvar = 0.0_dp
915  yvar = 0.0_dp
916 
917  DO i = 1, n
918  xav = xav + x(i)
919  yav = yav + y(i)
920  xycov = xycov + x(i)*y(i)
921  xvar = xvar + x(i)**2
922  yvar = yvar + y(i)**2
923  END DO
924 
925  xav = xav/n
926  yav = yav/n
927  xycov = xycov/n
928  xycov = xycov - xav*yav
929  xvar = xvar/n
930  xvar = xvar - xav**2
931  yvar = yvar/n
932  yvar = yvar - yav**2
933 
934  a = xycov/xvar
935  b = yav - a*xav
936 
937  r2 = xycov/sqrt(xvar*yvar)
938 
939  IF (r2 < 0.9_dp) THEN
940  IF (print_level == debug_print_level) THEN
941  WRITE (log_unit, '(A, E10.3)') '# possible error during linear regression: r^2 = ', r2
942  ELSE IF (print_level > silent_print_level) THEN
943  WRITE (line, '(A,E10.3)') 'QTB| possible error during linear regression: r^2 = ', r2
944  CALL pint_write_line(trim(line))
945  END IF
946  END IF
947 
948  END SUBROUTINE pint_qtb_linreg
949 
950 ! **************************************************************************************************
951 !> \brief ...
952 !> \param z_in ...
953 !> \param z_out ...
954 !> \param plan ...
955 !> \param n ...
956 ! **************************************************************************************************
957  SUBROUTINE pint_qtb_fft(z_in, z_out, plan, n)
958 
959  INTEGER :: n
960  TYPE(fft_plan_type) :: plan
961  COMPLEX(KIND=dp), DIMENSION(n) :: z_out, z_in
962 
963  INTEGER :: stat
964 
965  CALL fft_create_plan_1dm(plan, fft_type, fwfft, .false., n, 1, z_in, z_out, fft_plan_style)
966  CALL fft_1dm(plan, z_in, z_out, 1.d0, stat)
967  CALL fft_destroy_plan(plan)
968  END SUBROUTINE pint_qtb_fft
969 
970 END MODULE
Utility routines to open and close files. Tracking of preconnections.
Definition: cp_files.F:16
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
Definition: cp_files.F:308
various routines to log and control the output. The idea is that decisions about where to log should ...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer, parameter, public debug_print_level
integer, parameter, public silent_print_level
Definition: fft_lib.F:7
subroutine, public fft_create_plan_1dm(plan, fft_type, fsign, trans, n, m, zin, zout, plan_style)
...
Definition: fft_lib.F:212
subroutine, public fft_destroy_plan(plan)
...
Definition: fft_lib.F:241
subroutine, public fft_1dm(plan, zin, zout, scale, stat)
...
Definition: fft_lib.F:261
Type to store data about a (1D or 3D) FFT, including FFTW plan.
Definition: fft_plan.F:18
integer, save, public fft_plan_style
Definition: fft_tools.F:156
integer, parameter, public fwfft
Definition: fft_tools.F:145
integer, save, public fft_type
Definition: fft_tools.F:153
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public propagator_rpmd
objects that represent the structure of input sections and the data contained in an input section
recursive type(section_vals_type) function, pointer, public section_vals_get_subs_vals(section_vals, subsection_name, i_rep_section, can_return_null)
returns the values of the requested subsection
subroutine, public section_vals_get(section_vals, ref_count, n_repetition, n_subs_vals_rep, section, explicit)
returns various attributes about the section_vals
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Definition of mathematical constants and functions.
Definition: mathconstants.F:16
real(kind=dp), parameter, public pi
real(kind=dp), parameter, public twopi
Interface to the message passing library MPI.
Parallel (pseudo)random number generator (RNG) for multiple streams and substreams of random numbers.
type(rng_stream_type) function, public rng_stream_type_from_record(rng_record)
Create a RNG stream from a record given as an internal file (string).
integer, parameter, public rng_record_length
integer, parameter, public gaussian
I/O subroutines for pint_env.
Definition: pint_io.F:13
subroutine, public pint_write_line(line)
Writes out a line of text to the default output unit.
Definition: pint_io.F:76
Methods to apply the QTB thermostat to PI runs. Based on the PILE implementation from Felix Uhl (pint...
Definition: pint_qtb.F:15
subroutine, public pint_qtb_step(vold, vnew, p, ndim, masses, qtb_therm)
...
Definition: pint_qtb.F:155
subroutine, public pint_calc_qtb_energy(pint_env)
returns the qtb kinetic energy contribution
Definition: pint_qtb.F:240
subroutine, public pint_qtb_release(qtb_therm)
releases the qtb environment
Definition: pint_qtb.F:219
subroutine, public pint_qtb_init(qtb_therm, pint_env, normalmode_env, section)
initializes the data for a QTB run
Definition: pint_qtb.F:69