Octopus
ion_dynamics.F90
Go to the documentation of this file.
1!! Copyright (C) 2008 X. Andrade
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
23 use iso_c_binding
24 use debug_oct_m
25 use global_oct_m
26 use grid_oct_m
27 use ions_oct_m
28 use, intrinsic :: iso_fortran_env
33 use math_oct_m
35 use mpi_oct_m
38 use parser_oct_m
42 use space_oct_m
47 use unit_oct_m
50
51 implicit none
52
53 private
54
55 public :: &
74
75
76 integer, parameter :: &
77 THERMO_NONE = 0, &
78 thermo_scal = 1, &
79 thermo_nh = 2
80
81 integer, parameter :: &
82 CELL_MASS_PR = 1, &
84
85 type nose_hoover_t
86 private
87 real(real64) :: mass
88 real(real64) :: pos
89 real(real64) :: vel
90 end type nose_hoover_t
91
93 private
94 logical :: move
95 type(tdf_t) :: fx
96 type(tdf_t) :: fy
97 type(tdf_t) :: fz
99
100 type ion_dynamics_t
101 private
102 logical :: move_ions
103 logical :: relax_cell
104 logical :: constant_velocity
105 integer :: thermostat
106 real(real64) :: dt
107 real(real64) :: current_temperature
108
109 real(real64), allocatable :: oldforce(:, :)
110
112 real(real64), allocatable :: old_pos(:, :)
113
115 real(real64), allocatable :: cell_force(:)
116 real(real64), allocatable :: old_cell_force(:)
117 real(real64), allocatable :: cell_vel(:)
118 real(real64), allocatable :: initial_rlattice(:,:)
119 real(real64), allocatable :: strain(:)
120
121 real(real64) :: cell_mass
122 integer :: cell_mass_scheme
123
124 real(real64) :: pressure
125
127 logical :: symmetrize = .false.
128 type(symmetrizer_t), pointer :: symm
129
131 type(nose_hoover_t) :: nh(1:2)
132 type(tdf_t) :: temperature_function
133
135 logical :: drive_ions
136 type(ion_td_displacement_t), allocatable :: td_displacements(:)
137 type(ions_t), pointer :: ions_t0
138
139 real(real64), public :: ionic_scale
140 contains
141 procedure :: ions_move => ion_dynamics_ions_move
142 procedure :: cell_relax => ion_dynamics_cell_relax
143 procedure :: update_stress => ion_dynamics_update_stress
144 procedure :: is_active => ion_dynamics_is_active
145 end type ion_dynamics_t
146
147 type ion_state_t
148 private
149 real(real64), allocatable :: pos(:, :)
150 real(real64), allocatable :: vel(:, :)
151 real(real64), allocatable :: old_pos(:, :)
152 type(nose_hoover_t) :: nh(1:2)
153 end type ion_state_t
154
155 type cell_state_t
156 private
157 real(real64), allocatable :: pos(:, :)
158 real(real64), allocatable :: vel(:, :)
159 real(real64), allocatable :: old_pos(:, :)
160 end type cell_state_t
161
162contains
163
164 ! ---------------------------------------------------------
165 subroutine ion_dynamics_init(this, namespace, ions, symmetrize, symm)
166 use iso_c_binding, only: c_ptr
167 type(ion_dynamics_t), intent(out) :: this
168 type(namespace_t), intent(in) :: namespace
169 type(ions_t), intent(inout) :: ions
170 logical, intent(in) :: symmetrize
171 type(symmetrizer_t), optional, target, intent(in) :: symm
172
173 integer :: i, j, iatom, ierr, periodic_dim, ncomp, nf
174 real(real64) :: xx(ions%space%dim), temperature, sigma, kin1, kin2, tau_b, t0_energy
175 type(c_ptr) :: random_gen_pointer
176 type(read_coords_info) :: xyz
177 character(len=100) :: temp_function_name
178 logical :: have_velocities
179
180 type(block_t) :: blk
181 integer :: ndisp
182 character(len=200) :: expression
185
186 have_velocities = .false.
187 this%drive_ions = .false.
188
189 this%symmetrize = symmetrize
190 if (this%symmetrize) then
191 assert(present(symm))
192 this%symm => symm
193 else
194 nullify(this%symm)
195 end if
196
197 !%Variable TDIonicTimeScale
198 !%Type float
199 !%Default 1.0
200 !%Section Time-Dependent::Propagation
201 !%Description
202 !% This variable defines the factor between the timescale of ionic
203 !% and electronic movement. It allows reasonably fast
204 !% Born-Oppenheimer molecular-dynamics simulations based on
205 !% Ehrenfest dynamics. The value of this variable is equivalent to
206 !% the role of <math>\mu</math> in Car-Parrinello. Increasing it
207 !% linearly accelerates the time step of the ion
208 !% dynamics, but also increases the deviation of the system from the
209 !% Born-Oppenheimer surface. The default is 1, which means that both
210 !% timescales are the same. Note that a value different than 1
211 !% implies that the electrons will not follow physical behaviour.
212 !%
213 !% According to our tests, values around 10 are reasonable, but it
214 !% will depend on your system, mainly on the width of the gap.
215 !%
216 !% Important: The electronic time step will be the value of
217 !% <tt>TDTimeStep</tt> divided by this variable, so if you have determined an
218 !% optimal electronic time step (that we can call <i>dte</i>), it is
219 !% recommended that you define your time step as:
220 !%
221 !% <tt>TDTimeStep</tt> = <i>dte</i> * <tt>TDIonicTimeScale</tt>
222 !%
223 !% so you will always use the optimal electronic time step
224 !% (<a href=http://arxiv.org/abs/0710.3321>more details</a>).
225 !%End
226 call parse_variable(namespace, 'TDIonicTimeScale', m_one, this%ionic_scale)
228 if (this%ionic_scale <= m_zero) then
229 write(message(1),'(a)') 'Input: TDIonicTimeScale must be positive.'
230 call messages_fatal(1, namespace=namespace)
231 end if
233 call messages_print_var_value('TDIonicTimeScale', this%ionic_scale, namespace=namespace)
235
238 !%Variable IonsConstantVelocity
239 !%Type logical
240 !%Default no
241 !%Section Time-Dependent::Propagation
242 !%Description
243 !% (Experimental) If this variable is set to yes, the ions will
244 !% move with a constant velocity given by the initial
245 !% conditions. They will not be affected by any forces.
246 !%End
247 call parse_variable(namespace, 'IonsConstantVelocity', .false., this%constant_velocity)
248 call messages_print_var_value('IonsConstantVelocity', this%constant_velocity, namespace=namespace)
249
250 if (this%constant_velocity) then
251 call messages_experimental('IonsConstantVelocity', namespace=namespace)
252 have_velocities = .true.
253 this%drive_ions = .true.
254 end if
255
256 !%Variable IonsTimeDependentDisplacements
257 !%Type block
258 !%Section Time-Dependent::Propagation
259 !%Description
260 !% (Experimental) This variable allows you to specify a
261 !% time-dependent function describing the displacement of the ions
262 !% from their equilibrium position: <math>r(t) = r_0 + \Delta
263 !% r(t)</math>. Specify the displacements dx(t), dy(t), dz(t) as
264 !% follows, for some or all of the atoms:
265 !%
266 !% <tt>%IonsTimeDependentDisplacements
267 !% <br>&nbsp;&nbsp; atom_index | "dx(t)" | "dy(t)" | "dz(t)"
268 !% <br>%</tt>
269 !%
270 !% The displacement functions are time-dependent functions and should match one
271 !% of the function names given in the first column of the <tt>TDFunctions</tt> block.
272 !% If this block is set, the ions will not be affected by any forces.
273 !%End
274
275
276 ndisp = 0
277 if (parse_block(namespace, 'IonsTimeDependentDisplacements', blk) == 0) then
278 call messages_experimental("IonsTimeDependentDisplacements", namespace=namespace)
279 ndisp= parse_block_n(blk)
280 safe_allocate(this%td_displacements(1:ions%natoms))
281 this%td_displacements(1:ions%natoms)%move = .false.
282 if (ndisp > 0) this%drive_ions =.true.
283 if (ndisp > ions%natoms) call messages_input_error(namespace, 'IonsTimeDependentDisplacements')
284
285 do i = 1, ndisp
286 call parse_block_integer(blk, i-1, 0, iatom)
287 this%td_displacements(iatom)%move = .true.
288 if (iatom < 1 .and. iatom > ions%natoms) then
289 call messages_input_error(namespace, 'IonsTimeDependentDisplacements')
290 end if
291
292 call parse_block_string(blk, i-1, 1, expression)
293 call tdf_read(this%td_displacements(iatom)%fx, namespace, trim(expression), ierr)
294 if (ierr /= 0) then
295 write(message(1),'(3A)') 'Could not find "', trim(expression), '" in the TDFunctions block:'
296 call messages_warning(1, namespace=namespace)
297 end if
298
299
300 call parse_block_string(blk, i-1, 2, expression)
301 call tdf_read(this%td_displacements(iatom)%fy, namespace, trim(expression), ierr)
302 if (ierr /= 0) then
303 write(message(1),'(3A)') 'Could not find "', trim(expression), '" in the TDFunctions block:'
304 call messages_warning(1, namespace=namespace)
305 end if
306
307 call parse_block_string(blk, i-1, 3, expression)
308 call tdf_read(this%td_displacements(iatom)%fz, namespace, trim(expression), ierr)
309 if (ierr /= 0) then
310 write(message(1),'(3A)') 'Could not find "', trim(expression), '" in the TDFunctions block:'
311 call messages_warning(1, namespace=namespace)
312 end if
313
314 end do
315
316 safe_allocate(this%ions_t0)
317 this%ions_t0 = ions
318
319 end if
320
321
322
323
324 !%Variable Thermostat
325 !%Type integer
326 !%Default none
327 !%Section Time-Dependent::Propagation
328 !%Description
329 !% This variable selects the type of thermostat applied to
330 !% control the ionic temperature.
331 !%Option none 0
332 !% No thermostat is applied. This is the default.
333 !%Option velocity_scaling 1
334 !% Velocities are scaled to control the temperature.
335 !%Option nose_hoover 2
336 !% Nose-Hoover thermostat.
337 !%End
338
339 call parse_variable(namespace, 'Thermostat', thermo_none, this%thermostat)
340 if (.not. varinfo_valid_option('Thermostat', this%thermostat)) call messages_input_error(namespace, 'Thermostat')
341 call messages_print_var_option('Thermostat', this%thermostat, namespace=namespace)
342
343 if (this%thermostat /= thermo_none) then
344
345 have_velocities = .true.
346
347 if (this%drive_ions) then
348 call messages_write('You cannot use a Thermostat and IonsConstantVelocity or IonsTimeDependentDisplacements')
349 call messages_write('at the same time.')
350 call messages_fatal(namespace=namespace)
351 end if
352
353 call messages_experimental('Thermostat', namespace=namespace)
354
355 !%Variable TemperatureFunction
356 !%Type integer
357 !%Default "temperature"
358 !%Section Time-Dependent::Propagation
359 !%Description
360 !% If a thermostat is used, this variable indicates the name of the
361 !% function in the <tt>TDFunctions</tt> block that will be used to control the
362 !% temperature. The values of the temperature are given in
363 !% degrees Kelvin.
364 !%End
365 call parse_variable(namespace, 'TemperatureFunction', 'temperature', temp_function_name)
366
367 call tdf_read(this%temperature_function, namespace, temp_function_name, ierr)
368
369 if (ierr /= 0) then
370 message(1) = "You have enabled a thermostat but Octopus could not find"
371 message(2) = "the '"//trim(temp_function_name)//"' function in the TDFunctions block."
372 call messages_fatal(2, namespace=namespace)
373 end if
374
375 if (this%thermostat == thermo_nh) then
376 !%Variable ThermostatMass
377 !%Type float
378 !%Default 1.0
379 !%Section Time-Dependent::Propagation
380 !%Description
381 !% This variable sets the fictitious mass for the Nose-Hoover
382 !% thermostat.
383 !%End
384 call messages_obsolete_variable(namespace, 'NHMass', 'ThermostatMass')
385
386 call parse_variable(namespace, 'ThermostatMass', m_one, this%nh(1)%mass)
387 this%nh(2)%mass = this%nh(1)%mass
388
389 this%nh(1:2)%pos = m_zero
390 this%nh(1:2)%vel = m_zero
391
392 safe_allocate(this%old_pos(1:ions%space%dim, 1:ions%natoms))
393
394 this%old_pos = ions%pos
395 end if
396
397 end if
398
399 !now initialize velocities
400
401 !%Variable RandomVelocityTemp
402 !%Type float
403 !%Default 0.0
404 !%Section System::Velocities
405 !%Description
406 !% If this variable is present, <tt>Octopus</tt> will assign random
407 !% velocities to the atoms following a Boltzmann distribution with
408 !% temperature given by <tt>RandomVelocityTemp</tt> (in degrees Kelvin).
409 !% The seed for the random number generator can be modified by setting
410 !% <tt>GSL_RNG_SEED</tt> environment variable.
411 !%End
412
413 ! we now load the velocities, either from the temperature, from the input, or from a file
414 if (parse_is_defined(namespace, 'RandomVelocityTemp')) then
415
416 have_velocities = .true.
417
418 if (ions%grp%is_root()) then
419 call loct_ran_init(random_gen_pointer)
420 call parse_variable(namespace, 'RandomVelocityTemp', m_zero, temperature, unit = unit_kelvin)
421 end if
422
423 do i = 1, ions%natoms
424 !generate the velocities in the root node
425 if (ions%grp%is_root()) then
426 sigma = sqrt(temperature / ions%mass(i))
427 do j = 1, 3
428 ions%vel(j, i) = loct_ran_gaussian(random_gen_pointer, sigma)
429 end do
430 end if
431 !and send them to the others
432 call ions%grp%bcast(ions%vel(:, i), ions%space%dim, mpi_double_precision, 0)
433 end do
434
435 if (ions%grp%is_root()) then
436 call loct_ran_end(random_gen_pointer)
437 end if
438
439 call ions%update_kinetic_energy()
440 kin1 = ions%kinetic_energy
441
442 xx = ions%center_of_mass_vel()
443 do i = 1, ions%natoms
444 ions%vel(:, i) = ions%vel(:, i) - xx
445 end do
446
447 call ions%update_kinetic_energy()
448 kin2 = ions%kinetic_energy
449
450 if (kin2 > m_epsilon) then
451 do i = 1, ions%natoms
452 ions%vel(:, i) = sqrt(kin1/kin2)*ions%vel(:, i)
453 end do
454 end if
455
456 call ions%update_kinetic_energy()
457
458 write(message(1),'(a,f10.4,1x,a)') 'Info: Initial velocities randomly distributed with T =', &
460 write(message(2),'(2x,a,f8.4,1x,a)') '<K> =', &
461 units_from_atomic(units_out%energy, ions%kinetic_energy/ions%natoms), &
462 units_abbrev(units_out%energy)
463 write(message(3),'(2x,a,f8.4,1x,a)') '3/2 k_B T =', &
464 units_from_atomic(units_out%energy, (m_three/m_two)*temperature), &
465 units_abbrev(units_out%energy)
466 call messages_info(3, namespace=namespace)
467
468 else
469 !%Variable XYZVelocities
470 !%Type string
471 !%Section System::Velocities
472 !%Description
473 !% <tt>Octopus</tt> will try to read the starting velocities of the atoms from the XYZ file
474 !% specified by the variable <tt>XYZVelocities</tt>.
475 !% Note that you do not need to specify initial velocities if you are not going
476 !% to perform ion dynamics; if you are going to allow the ions to move but the velocities
477 !% are not specified, they are considered to be null.
478 !% Note: It is important for the velocities to maintain the ordering
479 !% in which the atoms were defined in the coordinates specifications.
480 !%End
481
482 !%Variable XSFVelocities
483 !%Type string
484 !%Section System::Velocities
485 !%Description
486 !% Like <tt>XYZVelocities</tt> but in XCrySDen format, as in <tt>XSFCoordinates</tt>.
487 !%End
488
489 !%Variable PDBVelocities
490 !%Type string
491 !%Section System::Velocities
492 !%Description
493 !% Like <tt>XYZVelocities</tt> but in PDB format, as in <tt>PDBCoordinates</tt>.
494 !%End
495
496 !%Variable Velocities
497 !%Type block
498 !%Section System::Velocities
499 !%Description
500 !% If <tt>XYZVelocities</tt>, <tt>PDBVelocities</tt>, and <tt>XSFVelocities</tt>
501 !% are not present, <tt>Octopus</tt> will try to fetch the initial
502 !% atomic velocities from this block. If this block is not present, <tt>Octopus</tt>
503 !% will set the initial velocities to zero. The format of this block can be
504 !% illustrated by this example:
505 !%
506 !% <tt>%Velocities
507 !% <br>&nbsp;&nbsp;'C' | -1.7 | 0.0 | 0.0
508 !% <br>&nbsp;&nbsp;'O' | &nbsp;1.7 | 0.0 | 0.0
509 !% <br>%</tt>
510 !%
511 !% It describes one carbon and one oxygen moving at the relative
512 !% velocity of 3.4 velocity units.
513 !%
514 !% Note: It is important for the velocities to maintain the ordering
515 !% in which the atoms were defined in the coordinates specifications.
516 !%End
517
518 call read_coords_init(xyz)
519 call read_coords_read('Velocities', xyz, ions%space, namespace)
520 if (xyz%source /= read_coords_err) then
521
522 have_velocities = .true.
523
524 if (ions%natoms /= xyz%n) then
525 write(message(1), '(a,i4,a,i4)') 'I need exactly ', ions%natoms, ' velocities, but I found ', xyz%n
526 call messages_fatal(1, namespace=namespace)
527 end if
528
529 ! copy information
530 do i = 1, ions%natoms
531 ions%vel(:, i) = xyz%atom(i)%x(1:ions%space%dim)
532 end do
533
534 call read_coords_end(xyz)
535
536 else
537 ions%vel = m_zero
538 end if
539 end if
540
541 call ions%update_kinetic_energy()
542
543 !%Variable MoveIons
544 !%Type logical
545 !%Section Time-Dependent::Propagation
546 !%Description
547 !% This variable controls whether atoms are moved during a time
548 !% propagation run. The default is yes when the ion velocity is
549 !% set explicitly or implicitly, otherwise is no.
550 !%End
551 call parse_variable(namespace, 'MoveIons', have_velocities, this%move_ions)
552 call messages_print_var_value('MoveIons', this%move_ions, namespace=namespace)
553
554 if (this%move_ions .and. ions%space%periodic_dim == 1) then
555 call messages_input_error(namespace, 'MoveIons', &
556 'Moving ions for a 1D periodic system is not allowed, as forces are incorrect.')
557 end if
558
559 if (this%ions_move()) then
560 safe_allocate(this%oldforce(1:ions%space%dim, 1:ions%natoms))
561 end if
562
563 if (ions%space%is_periodic()) then
564 !%Variable CellDynamics
565 !%Type logical
566 !%Section Time-Dependent::Propagation
567 !%Description
568 !% This variable controls whether the cell relaxation is done during a time
569 !% propagation run. The default is no.
570 !% This is done based on the Parrinello-Rahman equation of motion of the cell,
571 !% see Parrinello and Rahman, J. Appl. Pys. 52, 7182 (1981).
572 !% Only for periodic systems.
573 !%End
574 call parse_variable(namespace, 'CellDynamics', .false., this%relax_cell)
575 call messages_print_var_value('CellDynamics', this%relax_cell, namespace=namespace)
576
577 if (this%cell_relax()) then
578 periodic_dim = ions%space%periodic_dim
579 ncomp = periodic_dim * periodic_dim
580 safe_allocate(this%cell_force(1:ncomp))
581 this%cell_force = m_zero
582 safe_allocate(this%old_cell_force(1:ncomp))
583 this%old_cell_force = m_zero
584 safe_allocate(this%cell_vel(1:ncomp))
585 this%cell_vel = m_zero
586 ! We start from identity for the strain
587 safe_allocate(this%strain(1:ncomp))
588 this%strain = m_zero
589 ncomp = 1
590 do i = 1, periodic_dim
591 do j = i, periodic_dim
592 if(i == j) this%strain(ncomp) = m_one
593 ncomp = ncomp + 1
594 end do
595 end do
596
597 ! As we work with "reduced" quantities, the initial lattice vectors are used as a reference
598 ! and the strain is propagated from this initial reference
599 safe_allocate(this%initial_rlattice(1:periodic_dim, 1:periodic_dim))
600 this%initial_rlattice(1:periodic_dim, 1:periodic_dim) = ions%latt%rlattice(1:periodic_dim, 1:periodic_dim)
601
602 !%Variable CellMass
603 !%Type integer
604 !%Default parrinello_rahman
605 !%Section Time-Dependent::Propagation
606 !%Description
607 !% This variable selects how the fictitious mass W of the cell (barostat) is determined
608 !% in the Parrinello-Rahman equation of motion of the cell (see <tt>CellDynamics</tt>).
609 !% The value of W only affects the dynamical trajectory of the cell, not the
610 !% time-averaged or equilibrium properties (Parrinello and Rahman, J. Appl. Phys. 52, 7182 (1981)).
611 !%Option parrinello_rahman 1
612 !% The fictitious cell mass is set to the total ionic mass, W = sum_i m_i. This is a
613 !% simple, robust choice used in variable-cell ab initio molecular dynamics
614 !% (Parrinello and Rahman, J. Appl. Phys. 52, 7182 (1981); Wentzcovitch, PRB 44, 2358 (1991)).
615 !%Option martyna_tobias_klein 2
616 !% The fictitious cell mass follows Martyna, Tobias and Klein, J. Chem. Phys. 101, 4177 (1994):
617 !% W = (N_f + d) k_B T tau_b^2, where N_f is the number of ionic degrees of freedom, d the
618 !% periodic dimension, T the target temperature, and tau_b the barostat time constant
619 !% (<tt>BarostatTimeConstant</tt>). This requires a finite temperature, i.e. a <tt>Thermostat</tt>.
620 !% Since the cell is here propagated through the lattice matrix h (length units), the mass is
621 !% mapped to W = (N_f + d) k_B T tau_b^2 / V^(2/3), so that W has units of mass (V is the
622 !% cell volume, providing the natural area scale of the cell).
623 !%End
624 call parse_variable(namespace, 'CellMass', cell_mass_pr, this%cell_mass_scheme)
625 if (.not. varinfo_valid_option('CellMass', this%cell_mass_scheme)) then
626 call messages_input_error(namespace, 'CellMass')
627 end if
628 call messages_print_var_option('CellMass', this%cell_mass_scheme, namespace=namespace)
629
630 select case (this%cell_mass_scheme)
631 case (cell_mass_pr)
632 this%cell_mass = sum(ions%mass(1:ions%natoms))
633
634 case (cell_mass_mtk)
635 if (this%thermostat == thermo_none) then
636 message(1) = "CellMass = martyna_tobias_klein requires a finite temperature."
637 message(2) = "Please set a Thermostat (and the associated TemperatureFunction)."
638 call messages_fatal(2, namespace=namespace)
639 end if
640
641 !%Variable BarostatTimeConstant
642 !%Type float
643 !%Section Time-Dependent::Propagation
644 !%Description
645 !% Barostat time constant tau_b used to set the fictitious cell mass when
646 !% <tt>CellMass = martyna_tobias_klein</tt>. It should be chosen a few times longer than the
647 !% longest phonon period of the system. There is no default; it must be set explicitly.
648 !%End
649 call parse_variable(namespace, 'BarostatTimeConstant', -m_one, tau_b, units_inp%time)
650 if (tau_b <= m_zero) then
651 message(1) = "CellMass = martyna_tobias_klein requires a positive BarostatTimeConstant."
652 call messages_fatal(1, namespace=namespace)
653 end if
654
655 ! Target temperature (k_B T, in atomic energy units) at the initial time
656 t0_energy = units_to_atomic(unit_kelvin, tdf(this%temperature_function, m_zero))
657 ! Number of ionic degrees of freedom
658 nf = ions%space%dim * ions%natoms
659 this%cell_mass = (nf + periodic_dim) * t0_energy * tau_b**2 / ions%latt%rcell_volume**(m_two/m_three)
660 end select
661
662 write(message(1), '(a, es15.6, a)') "Info: Fictitious cell mass W = ", this%cell_mass, " [a.u.]"
663 call messages_info(1, namespace=namespace)
664 end if
665
666 !%Variable HydrostaticPressure
667 !%Type float
668 !%Default 0.0
669 !%Section Time-Dependent::Propagation
670 !%Description
671 !% Geometry optimization and molecular dynamics can be performed in presence of an external
672 !% hydrostatic pressure. This variable allows to set this value.
673 !% Only for periodic systems.
674 !%End
675 call parse_variable(namespace, 'HydrostaticPressure', m_zero, this%pressure)
676 else
677 this%relax_cell = .false.
678 end if
679
680
681 pop_sub(ion_dynamics_init)
682 end subroutine ion_dynamics_init
683
684
685 ! ---------------------------------------------------------
686 subroutine ion_dynamics_end(this)
687 type(ion_dynamics_t), intent(inout) :: this
688
689 push_sub(ion_dynamics_end)
690 safe_deallocate_a(this%oldforce)
691
692 if (this%thermostat /= thermo_none) then
693 call tdf_end(this%temperature_function)
694 end if
695
696 if (this%drive_ions .and. allocated(this%td_displacements)) then
697 if (any(this%td_displacements(1:this%ions_t0%natoms)%move)) then
698 ! ions end cannot be called here, otherwise the species are destroyed twice
699 ! call ions_end(this%ions_t0)
700 !AFE_DEALLOCATE_P(this%ions_t0)
701 end if
702 safe_deallocate_a(this%td_displacements)
703 end if
704
705 safe_deallocate_a(this%cell_force)
706 safe_deallocate_a(this%old_cell_force)
707 safe_deallocate_a(this%cell_vel)
708 safe_deallocate_a(this%initial_rlattice)
709
710 pop_sub(ion_dynamics_end)
711 end subroutine ion_dynamics_end
712
713
714 ! ---------------------------------------------------------
716 subroutine ion_dynamics_propagate(this, ions, time, dt, namespace)
717 type(ion_dynamics_t), intent(inout) :: this
718 type(ions_t), intent(inout) :: ions
719 real(real64), intent(in) :: time
720 real(real64), intent(in) :: dt
721 type(namespace_t), intent(in) :: namespace
722
723 integer :: iatom
724
725 push_sub(ion_dynamics_propagate)
726
727 this%dt = dt
728
729 if (this%drive_ions) then
730
731 call ion_dynamics_propagate_driven_ions(this, ions, time, dt)
732
733 else
734
735 ! Update the thermostat temperature
736 call ion_dynamics_update_temperature(this, time, namespace)
737
738 ! Conversion to reduced coordinates
739 do iatom = 1, ions%natoms
740 ions%pos(:, iatom) = ions%latt%cart_to_red(ions%pos(:, iatom))
741 ions%vel(:, iatom) = ions%latt%cart_to_red(ions%vel(:, iatom))
742 ions%tot_force(:, iatom) = ions%latt%cart_to_red(ions%tot_force(:, iatom))
743 end do
744
745 ! Get the new reduced coordinates
746 if (this%ions_move()) then
747 call ion_dynamics_propagate_ions(this, ions, dt)
748 end if
749
750 ! Updating the lattice vectors
751 if (this%cell_relax()) then
752 call ion_dynamics_propagate_cell(this, ions, dt, namespace)
753 end if
754
755 ! Get the new Cartesian coordinates
756 do iatom = 1, ions%natoms
757 ions%pos(:, iatom) = ions%latt%red_to_cart(ions%pos(:, iatom))
758 ions%vel(:, iatom) = ions%latt%red_to_cart(ions%vel(:, iatom))
759 if (allocated(this%oldforce)) then
760 this%oldforce(:, iatom) = ions%latt%red_to_cart(this%oldforce(:, iatom))
761 end if
762 ions%tot_force(:, iatom) = ions%latt%red_to_cart(ions%tot_force(:, iatom))
763 end do
764
765 end if
766
767 call ions%fold_atoms_into_cell()
768
770 end subroutine ion_dynamics_propagate
771
772
773 ! ---------------------------------------------------------
775 subroutine ion_dynamics_update_temperature(this, time, namespace)
776 type(ion_dynamics_t), intent(inout) :: this
777 real(real64), intent(in) :: time
778 type(namespace_t), intent(in) :: namespace
779
782 ! get the temperature from the tdfunction for the current time
783 if (this%thermostat /= thermo_none) then
784 this%current_temperature = units_to_atomic(unit_kelvin, tdf(this%temperature_function, time))
785
786 if (this%current_temperature < m_zero) then
787 write(message(1), '(a, f10.3, 3a, f10.3, 3a)') &
788 "Negative temperature (", &
789 units_from_atomic(unit_kelvin, this%current_temperature), " ", units_abbrev(unit_kelvin), &
790 ") at time ", &
791 units_from_atomic(units_out%time, time), " ", trim(units_abbrev(units_out%time)), "."
792 call messages_fatal(1, namespace=namespace)
793 end if
794 else
795 this%current_temperature = m_zero
796 end if
797
800
804 subroutine ion_dynamics_propagate_driven_ions(this, ions, time, dt)
805 type(ion_dynamics_t), intent(inout) :: this
806 type(ions_t), intent(inout) :: ions
807 real(real64), intent(in) :: time
808 real(real64), intent(in) :: dt
809
810 integer :: iatom
811 real(real64) :: dr(3)
812
814
815 assert(this%drive_ions)
816
817 do iatom = 1, ions%natoms
818 if (ions%fixed(iatom)) cycle
819
820 if (this%constant_velocity) then
821 ions%pos(:, iatom) = ions%pos(:, iatom) + dt*ions%vel(:, iatom)
822
823 else if (allocated(this%td_displacements)) then
824
825 if (this%td_displacements(iatom)%move) then
826 dr(1:3)=(/ real(tdf(this%td_displacements(iatom)%fx, time), real64), &
827 real(tdf(this%td_displacements(iatom)%fy, time), real64), &
828 real(tdf(this%td_displacements(iatom)%fz, time), real64) /)
829
830 ions%pos(:, iatom) = this%ions_t0%pos(:, iatom) + dr(1:ions%space%dim)
831 end if
832
833 end if
834 end do
835
838
839 ! ---------------------------------------------------------
844 subroutine ion_dynamics_propagate_ions(this, ions, dt)
845 type(ion_dynamics_t), intent(inout) :: this
846 type(ions_t), intent(inout) :: ions
847 real(real64), intent(in) :: dt
848
849 integer :: iatom
850
852
853 assert(.not. this%drive_ions)
854
855 if (this%thermostat /= thermo_nh) then
856 ! integrate using verlet
857 do iatom = 1, ions%natoms
858 if (ions%fixed(iatom)) cycle
859
860 ions%pos(:, iatom) = ions%pos(:, iatom) + dt*ions%vel(:, iatom) + &
861 m_half*dt**2 / ions%mass(iatom) * ions%tot_force(:, iatom)
862
863 this%oldforce(:, iatom) = ions%tot_force(:, iatom)
864 end do
865
866 else
867 ! for the Nose-Hoover thermostat we use a special integrator
868
869 ! The implementation of the Nose-Hoover thermostat is based on
870 ! Understanding Molecular Simulations by Frenkel and Smit,
871 ! Appendix E, page 540-542.
872
873 call nh_chain(this, ions)
874
875 do iatom = 1, ions%natoms
876 if (ions%fixed(iatom)) cycle
877
878 ions%pos(:, iatom) = ions%pos(:, iatom) + m_half*dt*ions%vel(:, iatom)
879 end do
880
881 end if
882
884 end subroutine ion_dynamics_propagate_ions
885
886 ! ---------------------------------------------------------
888 subroutine ion_dynamics_propagate_cell(this, ions, dt, namespace)
889 type(ion_dynamics_t), intent(inout) :: this
890 type(ions_t), intent(inout) :: ions
891 real(real64), intent(in) :: dt
892 type(namespace_t), intent(in) :: namespace
893
894 integer :: idir, jdir, comp
895 real(real64) :: rlattice_change(ions%space%periodic_dim*ions%space%periodic_dim)
896
898
899 rlattice_change = dt * this%cell_vel + m_half*dt**2 * this%cell_force / this%cell_mass
900
901 write(message(1),'(a,3a,a)') ' Cell force [', trim(units_abbrev(units_out%energy/units_out%length**ions%space%dim)), ']'
902 do idir = 1, ions%space%periodic_dim
903 write(message(1+idir),'(9e18.10)') (units_from_atomic(units_out%energy/units_out%length**ions%space%dim, &
904 this%cell_force(jdir + (idir-1)*ions%space%periodic_dim)), &
905 jdir = 1, ions%space%periodic_dim)
906 end do
907 call messages_info(1+ions%space%periodic_dim, namespace=ions%namespace)
908
909 write(message(1),'(a,3a,a)') ' Cell vel [', &
910 trim(units_abbrev(units_out%energy/units_out%length**ions%space%dim*units_out%time)), ']'
911 do idir = 1, ions%space%periodic_dim
912 write(message(1+idir),'(9e18.10)') (units_from_atomic(units_out%energy/units_out%length**ions%space%dim*units_out%time, &
913 this%cell_vel(jdir+ (idir-1)*ions%space%periodic_dim)), &
914 jdir = 1, ions%space%periodic_dim)
915 end do
916 call messages_info(1+ions%space%periodic_dim, namespace=ions%namespace)
917
918
919 comp = 1
920 do idir = 1, ions%space%periodic_dim
921 do jdir = 1, ions%space%periodic_dim
922 ions%latt%rlattice(idir, jdir) = ions%latt%rlattice(idir, jdir) + rlattice_change(comp)
923 comp = comp + 1
924 end do
925 end do
926
927 this%old_cell_force = this%cell_force
928
929 if (associated(this%symm)) then
930 call this%symm%symmetrize_lattice_vectors(ions%space%periodic_dim, &
931 this%initial_rlattice, ions%latt%rlattice(1:ions%space%periodic_dim, 1:ions%space%periodic_dim), this%symmetrize)
932 end if
933 call ions%update_lattice_vectors(ions%latt, this%symmetrize)
934
936 end subroutine ion_dynamics_propagate_cell
937
938
939 ! ---------------------------------------------------------
940 subroutine nh_chain(this, ions)
941 type(ion_dynamics_t), intent(inout) :: this
942 type(ions_t), intent(inout) :: ions
943
944 real(real64) :: g1, g2, ss, uk, dt, temp
945
946 push_sub(nh_chain)
947
948 dt = this%dt
949
950 call ions%update_kinetic_energy()
951 uk = ions%kinetic_energy
952
953 temp = this%current_temperature
954
955 g2 = (this%nh(1)%mass*this%nh(1)%vel**2 - temp)/this%nh(2)%mass
956 this%nh(2)%vel = this%nh(2)%vel + g2*dt/m_four
957 this%nh(1)%vel = this%nh(1)%vel*exp(-this%nh(2)%vel*dt/8.0_real64)
958
959 g1 = (m_two*uk - m_three*ions%natoms*temp)/this%nh(1)%mass
960 this%nh(1)%vel = this%nh(1)%vel + g1*dt/m_four
961 this%nh(1)%vel = this%nh(1)%vel*exp(-this%nh(2)%vel*dt/8.0_real64)
962 this%nh(1)%pos = this%nh(1)%pos + this%nh(1)%vel*dt/m_two
963 this%nh(2)%pos = this%nh(2)%pos + this%nh(2)%vel*dt/m_two
964
965 ss = exp(-this%nh(1)%vel*dt/m_two)
966
967 ions%vel = ss*ions%vel
968
969 uk = uk*ss**2
970
971 this%nh(1)%vel = this%nh(1)%vel*exp(-this%nh(2)%vel*dt/8.0_real64)
972 g1 = (m_two*uk - m_three*ions%natoms*temp)/this%nh(1)%mass
973 this%nh(1)%vel = this%nh(1)%vel + g1*dt/m_four
974 this%nh(1)%vel = this%nh(1)%vel*exp(-this%nh(2)%vel*dt/8.0_real64)
975
976 g2 = (this%nh(1)%mass*this%nh(1)%vel**2 - temp)/this%nh(2)%mass
977 this%nh(2)%vel = this%nh(2)%vel + g2*dt/m_four
978
979 pop_sub(nh_chain)
980 end subroutine nh_chain
981
982
983 ! ---------------------------------------------------------
984 subroutine ion_dynamics_propagate_vel(this, ions, atoms_moved)
985 type(ion_dynamics_t), intent(inout) :: this
986 type(ions_t), intent(inout) :: ions
987 logical, optional, intent(out) :: atoms_moved
988
989 integer :: iatom
990 real(real64) :: scal, temp
991
992 if (.not. ion_dynamics_ions_move(this)) return
993 if (this%drive_ions) return
994
996
997 if (present(atoms_moved)) atoms_moved = this%thermostat == thermo_nh
998
999 if (this%thermostat /= thermo_nh) then
1000 ! velocity verlet
1001
1002 do iatom = 1, ions%natoms
1003 if (ions%fixed(iatom)) cycle
1004
1005 ions%vel(:, iatom) = ions%vel(:, iatom) &
1006 + this%dt/ions%mass(iatom) * m_half * (this%oldforce(:, iatom) + &
1007 ions%tot_force(:, iatom))
1008
1009 end do
1010
1011 else
1012 ! the nose-hoover integration
1013 do iatom = 1, ions%natoms
1014 if (ions%fixed(iatom)) cycle
1015
1016 ions%vel(:, iatom) = ions%vel(:, iatom) + this%dt*ions%tot_force(:, iatom) / ions%mass(iatom)
1017 ions%pos(:, iatom) = ions%pos(:, iatom) + m_half*this%dt*ions%vel(:, iatom)
1018 end do
1019
1020 call nh_chain(this, ions)
1021
1022 end if
1023
1024 if (this%thermostat == thermo_scal) then
1025 temp = ion_dynamics_temperature(ions)
1026 if (temp > m_epsilon) then
1027 scal = sqrt(this%current_temperature/temp)
1028 ions%vel = scal*ions%vel
1029 end if
1030 end if
1031
1032 if (this%cell_relax()) then
1033 this%cell_vel = this%cell_vel + this%dt * m_half * (this%old_cell_force + this%cell_force) / this%cell_mass
1034 end if
1037 end subroutine ion_dynamics_propagate_vel
1038
1039
1040 ! ---------------------------------------------------------
1044 subroutine ion_dynamics_verlet_step1(ions, q, v, fold, dt)
1045 type(ions_t), intent(in) :: ions
1046 real(real64), intent(inout) :: q(:, :)
1047 real(real64), intent(inout) :: v(:, :)
1048 real(real64), intent(in) :: fold(:, :)
1049 real(real64), intent(in) :: dt
1050
1051 integer :: iatom
1052
1054
1055 ! First transform momenta to velocities
1056 do iatom = 1, ions%natoms
1057 v(iatom, 1:ions%space%dim) = v(iatom, 1:ions%space%dim) / ions%mass(iatom)
1058 end do
1059
1060 ! integrate using verlet
1061 do iatom = 1, ions%natoms
1062 if (ions%fixed(iatom)) cycle
1063 q(iatom, 1:ions%space%dim) = q(iatom, 1:ions%space%dim) + dt * v(iatom, 1:ions%space%dim) + &
1064 m_half*dt**2 / ions%mass(iatom) * fold(iatom, 1:ions%space%dim)
1065 end do
1066
1067 ! And back to momenta.
1068 do iatom = 1, ions%natoms
1069 v(iatom, 1:ions%space%dim) = ions%mass(iatom) * v(iatom, 1:ions%space%dim)
1070 end do
1071
1073 end subroutine ion_dynamics_verlet_step1
1074
1075
1076
1077 ! ---------------------------------------------------------
1079 subroutine ion_dynamics_verlet_step2(ions, v, fold, fnew, dt)
1080 type(ions_t), intent(in) :: ions
1081 real(real64), intent(inout) :: v(:, :)
1082 real(real64), intent(in) :: fold(:, :)
1083 real(real64), intent(in) :: fnew(:, :)
1084 real(real64), intent(in) :: dt
1085
1086 integer :: iatom
1087
1089
1090 ! First transform momenta to velocities
1091 do iatom = 1, ions%natoms
1092 v(iatom, 1:ions%space%dim) = v(iatom, 1:ions%space%dim) / ions%mass(iatom)
1093 end do
1094
1095 ! velocity verlet
1096 do iatom = 1, ions%natoms
1097 if (ions%fixed(iatom)) cycle
1098 v(iatom, 1:ions%space%dim) = v(iatom, 1:ions%space%dim) &
1099 + dt / ions%mass(iatom) * m_half * (fold(iatom, 1:ions%space%dim) + fnew(iatom, 1:ions%space%dim))
1100 end do
1101
1102 ! And back to momenta.
1103 do iatom = 1, ions%natoms
1104 v(iatom, 1:ions%space%dim) = ions%mass(iatom) * v(iatom, 1:ions%space%dim)
1105 end do
1106
1108 end subroutine ion_dynamics_verlet_step2
1109
1110
1111 ! ---------------------------------------------------------
1112 subroutine ion_dynamics_save_state(this, ions, state)
1113 type(ion_dynamics_t), intent(in) :: this
1114 type(ions_t), intent(in) :: ions
1115 type(ion_state_t), intent(out) :: state
1116
1117 if (.not. this%ions_move()) return
1118
1119 push_sub(ion_dynamics_save_state)
1120
1121 safe_allocate(state%pos(1:ions%space%dim, 1:ions%natoms))
1122 safe_allocate(state%vel(1:ions%space%dim, 1:ions%natoms))
1123
1124 state%pos = ions%pos
1125 state%vel = ions%vel
1126
1127 if (this%thermostat == thermo_nh) then
1128 safe_allocate(state%old_pos(1:ions%space%dim, 1:ions%natoms))
1129 state%old_pos(1:ions%space%dim, 1:ions%natoms) = this%old_pos(1:ions%space%dim, 1:ions%natoms)
1130 state%nh(1:2)%pos = this%nh(1:2)%pos
1131 state%nh(1:2)%vel = this%nh(1:2)%vel
1132 end if
1133
1135 end subroutine ion_dynamics_save_state
1136
1137
1138 ! ---------------------------------------------------------
1139 subroutine ion_dynamics_restore_state(this, ions, state)
1140 type(ion_dynamics_t), intent(inout) :: this
1141 type(ions_t), intent(inout) :: ions
1142 type(ion_state_t), intent(inout) :: state
1143
1144 assert(.not. this%cell_relax())
1145 if (.not. this%ions_move()) return
1146
1148
1149 ions%pos = state%pos
1150 ions%vel = state%vel
1151
1152 if (this%thermostat == thermo_nh) then
1153 this%old_pos(1:ions%space%dim, 1:ions%natoms) = state%old_pos(1:ions%space%dim, 1:ions%natoms)
1154 this%nh(1:2)%pos = state%nh(1:2)%pos
1155 this%nh(1:2)%vel = state%nh(1:2)%vel
1156 safe_deallocate_a(state%old_pos)
1157 end if
1158
1159 safe_deallocate_a(state%pos)
1160 safe_deallocate_a(state%vel)
1161
1163 end subroutine ion_dynamics_restore_state
1164
1165
1166 ! ---------------------------------------------------------
1167 logical pure function ion_dynamics_ions_move(this) result(ions_move)
1168 class(ion_dynamics_t), intent(in) :: this
1169
1170 ions_move = this%move_ions
1171
1172 end function ion_dynamics_ions_move
1173
1175 ! ---------------------------------------------------------
1177 logical pure function ion_dynamics_drive_ions(this) result(drive_ions)
1178 type(ion_dynamics_t), intent(in) :: this
1179
1180 drive_ions = this%drive_ions
1181
1182 end function ion_dynamics_drive_ions
1183
1184 ! ---------------------------------------------------------
1186 logical pure function ion_dynamics_cell_relax(this) result(cell_dynamics)
1187 class(ion_dynamics_t), intent(in) :: this
1188
1189 cell_dynamics = this%relax_cell
1190
1191 end function ion_dynamics_cell_relax
1192
1193 ! ---------------------------------------------------------
1195 logical pure function ion_dynamics_is_active(this) result(is_active)
1196 class(ion_dynamics_t), intent(in) :: this
1197
1198 is_active = this%relax_cell .or. this%move_ions
1199
1200 end function ion_dynamics_is_active
1201
1202
1203 ! ---------------------------------------------------------
1205 real(real64) function ion_dynamics_temperature(ions) result(temperature)
1206 type(ions_t), intent(in) :: ions
1208 integer :: iatom
1209 real(real64) :: kinetic_energy
1210
1211 kinetic_energy = m_zero
1212 do iatom = 1, ions%natoms
1213 kinetic_energy = kinetic_energy + &
1214 m_half * ions%mass(iatom) * sum(ions%vel(:, iatom)**2)
1215 end do
1216 temperature = m_two/m_three*kinetic_energy/ions%natoms
1217
1218 end function ion_dynamics_temperature
1219
1220
1221 ! ---------------------------------------------------------
1223 logical function ion_dynamics_freeze(this) result(freeze)
1224 type(ion_dynamics_t), intent(inout) :: this
1225 if (this%move_ions) then
1226 this%move_ions = .false.
1227 freeze = .true.
1228 else
1229 freeze = .false.
1230 end if
1231 end function ion_dynamics_freeze
1232
1233
1234 ! ---------------------------------------------------------
1236 subroutine ion_dynamics_unfreeze(this)
1237 type(ion_dynamics_t), intent(inout) :: this
1238 this%move_ions = .true.
1239 end subroutine ion_dynamics_unfreeze
1240
1241 ! ---------------------------------------------------------
1242 subroutine ion_dynamics_dump(this, restart, ierr)
1243 type(ion_dynamics_t), intent(in) :: this
1244 type(restart_t), intent(in) :: restart
1245 integer, intent(out) :: ierr
1246
1247 push_sub(ion_dynamics_dump)
1248
1249 if (allocated(this%oldforce)) then
1250 call restart%write_binary("ion_dynamics_oldforce", size(this%oldforce), &
1251 this%oldforce, ierr)
1252 end if
1253
1254 if( allocated(this%old_cell_force)) then
1255 call restart%write_binary("ion_dynamics_old_cell_force", size(this%old_cell_force), &
1256 this%old_cell_force, ierr)
1257 end if
1258
1259 pop_sub(ion_dynamics_dump)
1260 end subroutine ion_dynamics_dump
1261
1262 ! ---------------------------------------------------------
1263 subroutine ion_dynamics_load(this, restart, ierr)
1264 type(ion_dynamics_t), intent(inout) :: this
1265 type(restart_t), intent(in) :: restart
1266 integer, intent(out) :: ierr
1267
1268 push_sub(ion_dynamics_load)
1269
1270 if (allocated(this%oldforce)) then
1271 call restart%read_binary("ion_dynamics_oldforce", size(this%oldforce), &
1272 this%oldforce, ierr)
1273 end if
1274
1275 if( allocated(this%old_cell_force)) then
1276 call restart%read_binary("ion_dynamics_old_cell_force", size(this%old_cell_force), &
1277 this%old_cell_force, ierr)
1278 end if
1279
1280 pop_sub(ion_dynamics_load)
1281 end subroutine ion_dynamics_load
1282
1283 !----------------------------------------------------------
1285 subroutine ion_dynamics_update_stress(this, space, stress, rlattice, rcell_volume)
1286 class(ion_dynamics_t), intent(inout) :: this
1287 class(space_t), intent(in) :: space
1288 real(real64), intent(in) :: stress(3,3)
1289 real(real64), intent(in) :: rlattice(:,:)
1290 real(real64), intent(in) :: rcell_volume
1291
1292 integer :: idir, jdir, comp
1293 real(real64) :: inv_latt(space%periodic_dim, space%periodic_dim), tmp_stress(space%periodic_dim, space%periodic_dim)
1294 real(real64) :: cell_force(space%periodic_dim, space%periodic_dim)
1295
1297
1298 ! Get the inverse lattice
1299 inv_latt = rlattice(1:space%periodic_dim, 1:space%periodic_dim)
1300 call lalg_inverse(space%periodic_dim, inv_latt, 'dir')
1301
1302 ! The external hydrostatic pressure enters as a full -P on each diagonal component of the
1303 ! stress, such that at equilibrium the internal stress balances the pressure (\sigma = -P I).
1304 tmp_stress = -stress(1:space%periodic_dim, 1:space%periodic_dim)
1305 do idir = 1, space%periodic_dim
1306 tmp_stress(idir, idir) = tmp_stress(idir, idir) - this%pressure
1307 end do
1308 cell_force = matmul(tmp_stress, transpose(inv_latt)) * rcell_volume
1309
1310 comp = 1
1311 do idir = 1, space%periodic_dim
1312 do jdir = 1, space%periodic_dim
1313 this%cell_force(comp) = cell_force(idir, jdir)
1314 comp = comp + 1
1315 end do
1316 end do
1317
1318 if (debug%info) then
1319 write(message(1),'(a,3a,a)') ' Stress tensor [', trim(units_abbrev(units_out%energy/units_out%length**space%dim)), ']'
1320 do idir = 1, space%periodic_dim
1321 write(message(1+idir),'(9e18.10)') (units_from_atomic(units_out%energy/units_out%length**space%dim, stress(jdir, idir)), &
1322 jdir = 1, space%periodic_dim)
1323 end do
1324 call messages_info(1+space%periodic_dim, namespace=global_namespace)
1325 end if
1326
1328 end subroutine ion_dynamics_update_stress
1329
1330 !----------------------------------------------------------
1331 subroutine ion_dynamics_box_update(namespace, gr, space, new_latt)
1332 type(namespace_t), intent(in) :: namespace
1333 type(grid_t), intent(inout) :: gr
1334 class(space_t), intent(in) :: space
1335 type(lattice_vectors_t), intent(in) :: new_latt
1336
1337 integer :: idir
1338 real(real64) :: length(1:space%dim)
1339
1340 push_sub(ion_dynamics_box_update)
1341
1342 ! Regenerate the box
1343 select type(box => gr%box)
1344 type is (box_parallelepiped_t)
1345 do idir = 1, space%dim
1346 length(idir) = norm2(new_latt%rlattice(1:space%dim, idir))
1347 end do
1348 call box%regenerate(space%dim, new_latt%rlattice, length, namespace)
1349 class default
1350 call messages_not_implemented("Grid regeneration for non-parallelepiped boxes", namespace=namespace)
1351 end select
1352
1354 end subroutine ion_dynamics_box_update
1355
1356 !----------------------------------------------------------
1357 subroutine electrons_lattice_vectors_update(namespace, gr, space, psolver, kpoints, mc, qtot, new_latt)
1358 type(namespace_t), intent(in) :: namespace
1359 type(grid_t), intent(inout) :: gr
1360 class(space_t), intent(in) :: space
1361 type(poisson_t), intent(inout) :: psolver
1362 type(kpoints_t), intent(inout) :: kpoints
1363 type(multicomm_t), intent(in) :: mc
1364 real(real64), intent(in) :: qtot
1365 type(lattice_vectors_t), intent(in) :: new_latt
1366
1368
1369 call grid_lattice_vectors_update(gr, space, namespace, mc, new_latt)
1370
1371 !Initialize Poisson solvers
1372 call poisson_end(psolver)
1373 call poisson_init(psolver, namespace, space, gr%der, mc, gr%stencil, qtot, verbose=.false.)
1374
1375 call kpoints_lattice_vectors_update(kpoints, new_latt)
1376
1378
1381
1382end module ion_dynamics_oct_m
1383
1384!! Local Variables:
1385!! mode: f90
1386!! coding: utf-8
1387!! End:
Functions to generate random numbers.
Definition: loct_math.F90:301
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:182
double exp(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_four
Definition: global.F90:204
real(real64), parameter, public m_epsilon
Definition: global.F90:216
real(real64), parameter, public m_half
Definition: global.F90:206
real(real64), parameter, public m_one
Definition: global.F90:201
real(real64), parameter, public m_three
Definition: global.F90:203
This module implements the underlying real-space grid.
Definition: grid.F90:119
subroutine, public ion_dynamics_verlet_step2(ions, v, fold, fnew, dt)
A bare verlet integrator.
subroutine ion_dynamics_update_temperature(this, time, namespace)
Update the temperature of the ions in case of a thermostat.
subroutine, public ion_dynamics_dump(this, restart, ierr)
subroutine, public ion_dynamics_verlet_step1(ions, q, v, fold, dt)
A bare verlet integrator.
logical pure function ion_dynamics_cell_relax(this)
Is the cell dynamics activated or not.
subroutine nh_chain(this, ions)
subroutine, public ion_dynamics_restore_state(this, ions, state)
subroutine, public ion_dynamics_propagate(this, ions, time, dt, namespace)
Interface for the ion/cell dynamics.
subroutine, public ion_dynamics_save_state(this, ions, state)
subroutine, public ion_dynamics_unfreeze(this)
Unfreezes the ionic movement.
subroutine ion_dynamics_propagate_cell(this, ions, dt, namespace)
Time-evolution of the lattice vectors.
subroutine ion_dynamics_update_stress(this, space, stress, rlattice, rcell_volume)
Updates the stress tensor for the ion dynamics.
subroutine, public ion_dynamics_propagate_vel(this, ions, atoms_moved)
subroutine, public ion_dynamics_load(this, restart, ierr)
subroutine ion_dynamics_propagate_ions(this, ions, dt)
Time evolution of the ions.
subroutine, public ion_dynamics_init(this, namespace, ions, symmetrize, symm)
integer, parameter thermo_scal
subroutine, public electrons_lattice_vectors_update(namespace, gr, space, psolver, kpoints, mc, qtot, new_latt)
subroutine, public ion_dynamics_end(this)
subroutine ion_dynamics_propagate_driven_ions(this, ions, time, dt)
Move ions following a driven motion.
integer, parameter thermo_nh
logical pure function ion_dynamics_ions_move(this)
logical function, public ion_dynamics_freeze(this)
Freezes the ionic movement.
subroutine, public ion_dynamics_box_update(namespace, gr, space, new_latt)
logical pure function ion_dynamics_is_active(this)
Is the cell dynamics activated or not.
logical pure function, public ion_dynamics_drive_ions(this)
Is the ion dynamics activated or not.
integer, parameter cell_mass_mtk
real(real64) function, public ion_dynamics_temperature(ions)
This function returns the ionic temperature in energy units.
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1000
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1040
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:463
subroutine, public parse_block_string(blk, l, c, res, convert_to_c)
Definition: parser.F90:818
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:623
integer, parameter, public read_coords_err
for read_coords_info::file_type
subroutine, public read_coords_init(gf)
subroutine, public read_coords_end(gf)
subroutine, public read_coords_read(what, gf, space, namespace)
subroutine, public tdf_end(f)
Definition: tdfunction.F90:982
subroutine, public tdf_read(f, namespace, function_name, ierr)
This function initializes "f" from the TDFunctions block.
Definition: tdfunction.F90:220
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:225
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
type(unit_t), public unit_kelvin
For converting energies into temperatures.
type(unit_system_t), public units_inp
the units systems for reading and writing
int true(void)