28  use, 
intrinsic :: iso_fortran_env
 
   73  integer, 
parameter ::   &
 
   96    logical          :: constant_velocity
 
   99    real(real64)     :: current_temperature
 
  101    real(real64), 
allocatable :: oldforce(:, :)
 
  104    real(real64), 
allocatable :: old_pos(:, :)
 
  106    real(real64) :: old_cell_force(3,3)
 
  107    real(real64), 
public :: stress(3,3)
 
  108    real(real64) :: cell_vel(3,3)
 
  111    type(nose_hoover_t) :: nh(1:2)
 
  112    type(tdf_t) :: temperature_function
 
  114    logical :: drive_ions
 
  115    type(ion_td_displacement_t), 
allocatable ::  td_displacements(:)
 
  116    type(ions_t),     
pointer :: ions_t0
 
  118    real(real64), 
public :: ionic_scale
 
  123    real(real64), 
allocatable :: pos(:, :)
 
  124    real(real64), 
allocatable :: vel(:, :)
 
  125    real(real64), 
allocatable :: old_pos(:, :)
 
  126    type(nose_hoover_t) :: nh(1:2)
 
  131    real(real64), 
allocatable :: pos(:, :)
 
  132    real(real64), 
allocatable :: vel(:, :)
 
  133    real(real64), 
allocatable :: old_pos(:, :)
 
  140    use iso_c_binding, 
only: c_ptr
 
  141    type(ion_dynamics_t), 
intent(out)   :: this
 
  142    type(namespace_t),    
intent(in)    :: namespace
 
  143    type(ions_t),         
intent(inout) :: ions
 
  145    integer :: i, j, iatom, ierr
 
  146    real(real64)   :: xx(ions%space%dim), temperature, sigma, kin1, kin2
 
  147    type(c_ptr) :: random_gen_pointer
 
  148    type(read_coords_info) :: xyz
 
  149    character(len=100)  :: temp_function_name
 
  150    logical :: have_velocities
 
  154    character(len=200) :: expression
 
  158    have_velocities = .false.
 
  159    this%drive_ions = .false.
 
  193      write(
message(1),
'(a)') 
'Input: TDIonicTimeScale must be positive.' 
  211    call parse_variable(namespace, 
'IonsConstantVelocity', .false., this%constant_velocity)
 
  214    if (this%constant_velocity) 
then 
  241    if (
parse_block(namespace, 
'IonsTimeDependentDisplacements', blk) == 0) 
then 
  244      safe_allocate(this%td_displacements(1:ions%natoms))
 
  245      this%td_displacements(1:ions%natoms)%move = .false.
 
  246      if (ndisp > 0) this%drive_ions =.
true.
 
  250        this%td_displacements(iatom)%move = .
true.
 
  253        call tdf_read(this%td_displacements(iatom)%fx, namespace, trim(expression), ierr)
 
  255          write(
message(1),
'(3A)') 
'Could not find "', trim(expression), 
'" in the TDFunctions block:' 
  261        call tdf_read(this%td_displacements(iatom)%fy, namespace, trim(expression), ierr)
 
  263          write(
message(1),
'(3A)') 
'Could not find "', trim(expression), 
'" in the TDFunctions block:' 
  268        call tdf_read(this%td_displacements(iatom)%fz, namespace, trim(expression), ierr)
 
  270          write(
message(1),
'(3A)') 
'Could not find "', trim(expression), 
'" in the TDFunctions block:' 
  276      safe_allocate(this%ions_t0)
 
  299    call parse_variable(namespace, 
'Thermostat', thermo_none, this%thermostat)
 
  303    if (this%thermostat /= thermo_none) 
then 
  305      have_velocities = .
true.
 
  307      if (this%drive_ions) 
then 
  308        call messages_write(
'You cannot use a Thermostat and IonsConstantVelocity or IonsTimeDependentDisplacements')
 
  325      call parse_variable(namespace, 
'TemperatureFunction', 
'temperature', temp_function_name)
 
  327      call tdf_read(this%temperature_function, namespace, temp_function_name, ierr)
 
  330        message(1) = 
"You have enabled a thermostat but Octopus could not find" 
  331        message(2) = 
"the '"//trim(temp_function_name)//
"' function in the TDFunctions block." 
  347        this%nh(2)%mass = this%nh(1)%mass
 
  352        safe_allocate(this%old_pos(1:ions%space%dim, 1:ions%natoms))
 
  354        this%old_pos = ions%pos
 
  376      have_velocities = .
true.
 
  383      do i = 1, ions%natoms
 
  386          sigma = 
sqrt(temperature / ions%mass(i))
 
  392        call mpi_world%bcast(ions%vel(:, i), ions%space%dim, mpi_double_precision, 0)
 
  399      call ions%update_kinetic_energy()
 
  400      kin1 = ions%kinetic_energy
 
  402      xx = ions%center_of_mass_vel()
 
  403      do i = 1, ions%natoms
 
  404        ions%vel(:, i) = ions%vel(:, i) - xx
 
  407      call ions%update_kinetic_energy()
 
  408      kin2 = ions%kinetic_energy
 
  410      do i = 1, ions%natoms
 
  411        ions%vel(:, i) =  
sqrt(kin1/kin2)*ions%vel(:, i)
 
  414      call ions%update_kinetic_energy()
 
  416      write(
message(1),
'(a,f10.4,1x,a)') 
'Info: Initial velocities randomly distributed with T =', &
 
  418      write(
message(2),
'(2x,a,f8.4,1x,a)') 
'<K>       =', &
 
  421      write(
message(3),
'(2x,a,f8.4,1x,a)') 
'3/2 k_B T =', &
 
  480        have_velocities = .
true.
 
  482        if (ions%natoms /= xyz%n) 
then 
  483          write(
message(1), 
'(a,i4,a,i4)') 
'I need exactly ', ions%natoms, 
' velocities, but I found ', xyz%n
 
  488        do i = 1, ions%natoms
 
  499    call ions%update_kinetic_energy()
 
  509    call parse_variable(namespace, 
'MoveIons', have_velocities, this%move_ions)
 
  512    if (this%move_ions .and. ions%space%periodic_dim == 1) 
then 
  514        'Moving ions for a 1D periodic system is not allowed, as forces are incorrect.')
 
  518      safe_allocate(this%oldforce(1:ions%space%dim, 1:ions%natoms))
 
  521    this%old_cell_force = 
m_zero 
  535    safe_deallocate_a(this%oldforce)
 
  537    if (this%thermostat /= thermo_none) 
then 
  538      call tdf_end(this%temperature_function)
 
  541    if (this%drive_ions .and. 
allocated(this%td_displacements)) 
then 
  542      if (any(this%td_displacements(1:this%ions_t0%natoms)%move)) 
then 
  547      safe_deallocate_a(this%td_displacements)
 
  557    type(
ions_t),         
intent(inout) :: ions
 
  558    real(real64),         
intent(in)    :: time
 
  559    real(real64),         
intent(in)    :: dt
 
  563    real(real64) :: dr(3)
 
  576    if (this%thermostat /= thermo_none) 
then 
  579      if (this%current_temperature < 
m_zero) 
then 
  580        write(
message(1), 
'(a, f10.3, 3a, f10.3, 3a)') &
 
  581          "Negative temperature (", &
 
  588      this%current_temperature = 
m_zero 
  593      do iatom = 1, ions%natoms
 
  594        if (ions%fixed(iatom)) cycle
 
  596        if (.not. this%drive_ions) 
then 
  598          ions%pos(:, iatom) = ions%pos(:, iatom) + dt*ions%vel(:, iatom) + &
 
  599            m_half*dt**2 / ions%mass(iatom) * ions%tot_force(:, iatom)
 
  601          this%oldforce(:, iatom) = ions%tot_force(:, iatom)
 
  604          if (this%constant_velocity) 
then 
  605            ions%pos(:, iatom) = ions%pos(:, iatom) + dt*ions%vel(:, iatom)
 
  609          if (this%td_displacements(iatom)%move) 
then 
  611            dr(1:3)=(/ real(
tdf(this%td_displacements(iatom)%fx,time), real64), &
 
  612              real(
tdf(this%td_displacements(iatom)%fy,time), real64), &
 
  613              real(tdf(this%td_displacements(iatom)%fz,time), real64) /)
 
  615            ions%pos(:, iatom) = this%ions_t0%pos(:, iatom) + dr(1:ions%space%dim)
 
  631      do iatom = 1, ions%natoms
 
  632        ions%pos(:, iatom) = ions%pos(:, iatom) + 
m_half*dt*ions%vel(:, iatom)
 
  638    if (ions%space%is_periodic()) 
then 
  639      call ions%fold_atoms_into_cell()
 
  660    type(
ions_t),         
intent(inout) :: ions
 
  662    real(real64) :: g1, g2, ss, uk, dt, temp
 
  668    call ions%update_kinetic_energy()
 
  669    uk = ions%kinetic_energy
 
  671    temp = this%current_temperature
 
  673    g2 = (this%nh(1)%mass*this%nh(1)%vel**2 - temp)/this%nh(2)%mass
 
  674    this%nh(2)%vel = this%nh(2)%vel + g2*dt/
m_four 
  675    this%nh(1)%vel = this%nh(1)%vel*
exp(-this%nh(2)%vel*dt/8.0_real64)
 
  677    g1 = (
m_two*uk - 
m_three*ions%natoms*temp)/this%nh(1)%mass
 
  678    this%nh(1)%vel = this%nh(1)%vel + g1*dt/
m_four 
  679    this%nh(1)%vel = this%nh(1)%vel*
exp(-this%nh(2)%vel*dt/8.0_real64)
 
  680    this%nh(1)%pos = this%nh(1)%pos + this%nh(1)%vel*dt/
m_two 
  681    this%nh(2)%pos = this%nh(2)%pos + this%nh(2)%vel*dt/
m_two 
  685    ions%vel = ss*ions%vel
 
  689    this%nh(1)%vel = this%nh(1)%vel*
exp(-this%nh(2)%vel*dt/8.0_real64)
 
  690    g1 = (
m_two*uk - 
m_three*ions%natoms*temp)/this%nh(1)%mass
 
  691    this%nh(1)%vel = this%nh(1)%vel + g1*dt/
m_four 
  692    this%nh(1)%vel = this%nh(1)%vel*
exp(-this%nh(2)%vel*dt/8.0_real64)
 
  694    g2 = (this%nh(1)%mass*this%nh(1)%vel**2 - temp)/this%nh(2)%mass
 
  695    this%nh(2)%vel = this%nh(2)%vel + g2*dt/
m_four 
  704    type(
ions_t),         
intent(inout) :: ions
 
  705    logical, 
optional,    
intent(out)   :: atoms_moved
 
  707    integer      :: iatom, periodic_dim
 
  711    if (this%drive_ions) 
return 
  715    if (
present(atoms_moved)) atoms_moved = this%thermostat == 
thermo_nh 
  720      do iatom = 1, ions%natoms
 
  721        if (ions%fixed(iatom)) cycle
 
  723        ions%vel(:, iatom) = ions%vel(:, iatom) &
 
  724          + this%dt/ions%mass(iatom) * 
m_half * (this%oldforce(:, iatom) + &
 
  725          ions%tot_force(:, iatom))
 
  731      do iatom = 1, ions%natoms
 
  732        ions%vel(:, iatom) = ions%vel(:, iatom) + this%dt*ions%tot_force(:, iatom) / ions%mass(iatom)
 
  733        ions%pos(:, iatom) = ions%pos(:, iatom) + 
m_half*this%dt*ions%vel(:, iatom)
 
  743      ions%vel = scal*ions%vel
 
  746    if (ions%space%is_periodic()) 
then 
  747      periodic_dim = ions%space%periodic_dim
 
  748      this%cell_vel(1:periodic_dim, 1:periodic_dim) = this%cell_vel(1:periodic_dim, 1:periodic_dim) &
 
  749        +  this%dt* 
m_half * (this%old_cell_force(1:periodic_dim, 1:periodic_dim) + this%stress(1:periodic_dim, 1:periodic_dim))
 
  759    type(
ions_t),         
intent(in)    :: ions
 
  760    real(real64),         
intent(inout) :: q(:, :)
 
  761    real(real64),         
intent(inout) :: v(:, :)
 
  762    real(real64),         
intent(in)    :: fold(:, :)
 
  763    real(real64),         
intent(in)    :: dt
 
  770    do iatom = 1, ions%natoms
 
  771      v(iatom, 1:ions%space%dim) = v(iatom, 1:ions%space%dim) / ions%mass(iatom)
 
  775    do iatom = 1, ions%natoms
 
  776      if (ions%fixed(iatom)) cycle
 
  777      q(iatom, 1:ions%space%dim) = q(iatom, 1:ions%space%dim) + dt * v(iatom, 1:ions%space%dim) + &
 
  778        m_half*dt**2 / ions%mass(iatom) * fold(iatom, 1:ions%space%dim)
 
  782    do iatom = 1, ions%natoms
 
  783      v(iatom, 1:ions%space%dim) = ions%mass(iatom) * v(iatom, 1:ions%space%dim)
 
  794    type(
ions_t),         
intent(in)    :: ions
 
  795    real(real64),         
intent(inout) :: v(:, :)
 
  796    real(real64),         
intent(in)    :: fold(:, :)
 
  797    real(real64),         
intent(in)    :: fnew(:, :)
 
  798    real(real64),         
intent(in)    :: dt
 
  805    do iatom = 1, ions%natoms
 
  806      v(iatom, 1:ions%space%dim) = v(iatom, 1:ions%space%dim) / ions%mass(iatom)
 
  810    do iatom = 1, ions%natoms
 
  811      if (ions%fixed(iatom)) cycle
 
  812      v(iatom, 1:ions%space%dim) = v(iatom, 1:ions%space%dim) &
 
  813        + dt / ions%mass(iatom) * 
m_half * (fold(iatom, 1:ions%space%dim) + fnew(iatom, 1:ions%space%dim))
 
  817    do iatom = 1, ions%natoms
 
  818      v(iatom, 1:ions%space%dim) = ions%mass(iatom) * v(iatom, 1:ions%space%dim)
 
  828    type(
ions_t),         
intent(in)    :: ions
 
  835    safe_allocate(state%pos(1:ions%space%dim, 1:ions%natoms))
 
  836    safe_allocate(state%vel(1:ions%space%dim, 1:ions%natoms))
 
  842      safe_allocate(state%old_pos(1:ions%space%dim, 1:ions%natoms))
 
  843      state%old_pos(1:ions%space%dim, 1:ions%natoms) = this%old_pos(1:ions%space%dim, 1:ions%natoms)
 
  844      state%nh(1:2)%pos = this%nh(1:2)%pos
 
  845      state%nh(1:2)%vel = this%nh(1:2)%vel
 
  855    type(
ions_t),         
intent(inout) :: ions
 
  866      this%old_pos(1:ions%space%dim, 1:ions%natoms) = state%old_pos(1:ions%space%dim, 1:ions%natoms)
 
  867      this%nh(1:2)%pos = state%nh(1:2)%pos
 
  868      this%nh(1:2)%vel = state%nh(1:2)%vel
 
  869      safe_deallocate_a(state%old_pos)
 
  872    safe_deallocate_a(state%pos)
 
  873    safe_deallocate_a(state%vel)
 
  883    ions_move = this%move_ions
 
  892    drive_ions = this%drive_ions
 
  900    type(ions_t),          
intent(in) :: ions
 
  903    real(real64) :: kinetic_energy
 
  905    kinetic_energy = m_zero
 
  906    do iatom = 1, ions%natoms
 
  907      kinetic_energy = kinetic_energy + &
 
  908        m_half * ions%mass(iatom) * sum(ions%vel(:, iatom)**2)
 
  910    temperature = m_two/m_three*kinetic_energy/ions%natoms
 
  919    if (this%move_ions) 
then 
  920      this%move_ions = .false.
 
  932    this%move_ions = .
true.
 
  938    type(restart_t),      
intent(in)  :: restart
 
  939    integer,              
intent(out) :: ierr
 
  943    if (
allocated(this%oldforce)) 
then 
  944      call drestart_write_binary(restart, 
"ion_dynamics_oldforce", 
size(this%oldforce), &
 
  954    type(restart_t),      
intent(in)    :: restart
 
  955    integer,              
intent(out)   :: ierr
 
  959    if (
allocated(this%oldforce)) 
then 
  960      call drestart_read_binary(restart, 
"ion_dynamics_oldforce", 
size(this%oldforce), &
 
  970    type(namespace_t),        
intent(in)    :: namespace
 
  971    type(grid_t),             
intent(inout) :: gr
 
  972    class(space_t),           
intent(in)    :: space
 
  973    type(poisson_t),          
intent(inout) :: psolver
 
  974    type(kpoints_t),          
intent(inout) :: kpoints
 
  975    type(multicomm_t),        
intent(in)    :: mc
 
  976    real(real64),             
intent(in)    :: qtot
 
  977    type(lattice_vectors_t),  
intent(in)    :: new_latt
 
  980    real(real64) :: length(1:space%dim)
 
  985    select type(box => gr%box)
 
  986    type is (box_parallelepiped_t)
 
  987      do idir = 1, space%dim
 
  988        length(idir) = norm2(new_latt%rlattice(1:space%dim, idir))
 
  990      call box%regenerate(space%dim, new_latt%rlattice, length, namespace)
 
  992      call messages_not_implemented(
"Grid regeneration for non-parallelepiped boxes", namespace=namespace)
 
  996    call grid_lattice_vectors_update(gr, space, namespace, mc, new_latt)
 
  999    call poisson_end(psolver)
 
 1000    call poisson_init(psolver, namespace, space, gr%der, mc, gr%stencil, qtot, verbose=.false.)
 
 1002    call kpoints_lattice_vectors_update(kpoints, new_latt)
 
Functions to generate random numbers.
 
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
 
double exp(double __x) __attribute__((__nothrow__
 
real(real64), parameter, public m_two
 
real(real64), parameter, public m_zero
 
real(real64), parameter, public m_four
 
real(real64), parameter, public m_half
 
real(real64), parameter, public m_one
 
real(real64), parameter, public m_three
 
This module implements the underlying real-space grid.
 
subroutine, public ion_dynamics_verlet_step2(ions, v, fold, fnew, dt)
A bare verlet integrator.
 
subroutine, public ion_dynamics_dump(this, restart, ierr)
 
subroutine, public ion_dynamics_verlet_step1(ions, q, v, fold, dt)
A bare verlet integrator.
 
subroutine nh_chain(this, ions)
 
subroutine, public ion_dynamics_restore_state(this, ions, state)
 
subroutine, public ion_dynamics_propagate(this, ions, time, dt, namespace)
 
subroutine, public ion_dynamics_save_state(this, ions, state)
 
logical pure function, public ion_dynamics_ions_move(this)
 
subroutine, public ion_dynamics_unfreeze(this)
Unfreezes the ionic movement.
 
subroutine, public ion_dynamics_init(this, namespace, ions)
 
subroutine, public ion_dynamics_propagate_vel(this, ions, atoms_moved)
 
subroutine, public ion_dynamics_load(this, restart, ierr)
 
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)
 
integer, parameter thermo_nh
 
logical function, public ion_dynamics_freeze(this)
Freezes the ionic movement.
 
logical pure function, public ion_dynamics_drive_ions(this)
 
real(real64) function, public ion_dynamics_temperature(ions)
This function returns the ionic temperature in energy units.
 
subroutine, public messages_warning(no_lines, all_nodes, namespace)
 
subroutine, public messages_obsolete_variable(namespace, name, rep)
 
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
 
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
 
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
 
subroutine, public messages_input_error(namespace, var, details, row, column)
 
subroutine, public messages_experimental(name, namespace)
 
logical function mpi_grp_is_root(grp)
 
type(mpi_grp_t), public mpi_world
 
This module handles the communicators for the various parallelization strategies.
 
logical function, public parse_is_defined(namespace, name)
 
integer function, public parse_block(namespace, name, blk, check_varinfo_)
 
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)
 
subroutine, public tdf_read(f, namespace, function_name, ierr)
This function initializes "f" from the TDFunctions block.
 
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
 
character(len=20) pure function, public units_abbrev(this)
 
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