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