37 use,
intrinsic :: iso_fortran_env
71 type(lattice_vectors_t) :: latt
74 type(atom_t),
allocatable :: atom(:)
76 type(symmetries_t) :: symm
78 type(distributed_t) :: atoms_dist
80 integer,
allocatable :: map_symm_atoms(:,:)
81 integer,
allocatable :: inv_map_symm_atoms(:,:)
83 real(real64),
allocatable :: equilibrium_pos(:,:)
89 real(real64),
allocatable :: pos_displacements(:,:)
90 real(real64),
allocatable :: vel_displacements(:,:)
94 class(species_wrapper_t),
allocatable :: species(:)
95 logical :: only_user_def
96 logical,
private :: species_time_dependent
98 logical :: force_total_enforce
99 type(ion_interaction_t) :: ion_interaction
102 logical,
private :: apply_global_force
103 type(tdf_t),
private :: global_force_function
106 generic ::
assignment(=) => copy
139 procedure ions_constructor
146 type(namespace_t),
intent(in) :: namespace
147 logical,
optional,
intent(in) :: print_info
148 type(lattice_vectors_t),
optional,
intent(out) :: latt_inp
149 class(ions_t),
pointer :: ions
151 type(read_coords_info) :: xyz
152 integer :: ia, ierr, idir
153 character(len=100) :: function_name
154 real(real64) :: mindist
155 real(real64),
allocatable :: factor(:)
156 integer,
allocatable :: site_type(:)
157 logical,
allocatable :: spherical_site(:)
158 real(real64),
parameter :: threshold = 1e-5_real64
159 type(species_factory_t) :: factory
161 integer :: displacement_mode
162 real(real64) :: amp_pos, amp_vel
164 logical :: in_ensemble
170 ions%namespace = namespace
172 ions%space =
space_t(namespace)
185 message(1) =
"Coordinates have not been defined."
194 safe_allocate(ions%atom(1:ions%natoms))
195 do ia = 1, ions%natoms
196 call atom_init(ions%atom(ia), ions%space%dim, xyz%atom(ia)%label)
197 ions%pos(:,ia) = xyz%atom(ia)%x(1:ions%space%dim)
199 ions%fixed(ia) = .not. xyz%atom(ia)%move
203 if (
allocated(xyz%latvec))
then
213 do ia = 1, ions%natoms
214 ions%pos(:, ia) = ions%latt%red_to_cart(ions%pos(:, ia))
221 safe_allocate_source_a(ions%equilibrium_pos, ions%pos)
226 do ia = 1, ions%natoms
227 ions%mass(ia) = ions%atom(ia)%species%get_mass()
228 ions%charge(ia) = ions%atom(ia)%species%get_zval()
242 call parse_variable(namespace,
'InitialDisplacementMode', 0, displacement_mode)
252 call parse_variable(namespace,
'InitialDisplacementAmplitudePos', 1.0_real64, amp_pos)
262 call parse_variable(namespace,
'InitialDisplacementAmplitudeVel', 1.0_real64, amp_vel)
264 if (displacement_mode>0)
then
266 message(1) =
"Random displacements are disabled when InitialDisplacementMode > 0."
269 safe_allocate(ions%pos_displacements(1:ions%space%dim, 1:ions%natoms))
270 safe_allocate(ions%vel_displacements(1:ions%space%dim, 1:ions%natoms))
272 call ions%single_mode_displacements(displacement_mode, amp_pos, amp_vel)
275 ions%pos = ions%pos + ions%pos_displacements
283 if(in_ensemble .and. displacement_mode==0)
then
292 call parse_variable(namespace,
'EnsembleTemperature', 0.0_real64, t)
294 safe_allocate(ions%pos_displacements(1:ions%space%dim, 1:ions%natoms))
295 safe_allocate(ions%vel_displacements(1:ions%space%dim, 1:ions%natoms))
296 call ions%init_random_displacements(t)
299 ions%pos = ions%pos + ions%pos_displacements
310 if (
present(latt_inp))
then
317 if (ions%space%has_mixed_periodicity())
then
318 safe_allocate(factor(ions%space%dim))
319 do idir = 1, ions%space%periodic_dim
322 do idir = ions%space%periodic_dim + 1, ions%space%dim
323 factor(idir) =
m_one/norm2(ions%latt%rlattice(1:ions%space%dim, idir))
325 call ions%latt%scale(factor)
326 safe_deallocate_a(factor)
330 if (ions%natoms > 1)
then
332 if (mindist < threshold)
then
333 write(
message(1),
'(a)')
"Some of the atoms seem to sit too close to each other."
334 write(
message(2),
'(a)')
"Please review your input files and the output geometry (in 'static/')."
335 write(
message(3),
'(a, f12.6, 1x, a)')
"Minimum distance = ", &
341 call ions%write_xyz(trim(
static_dir)//
'/geometry')
345 message(1) =
"It cannot be correct to run with physical atoms so close."
351 safe_allocate(spherical_site(1:ions%natoms))
352 safe_allocate(site_type(1:ions%natoms))
353 do ia = 1, ions%natoms
354 select type(spec => ions%atom(ia)%species)
356 spherical_site(ia) = .false.
358 spherical_site(ia) = .false.
360 spherical_site(ia) = .false.
362 spherical_site(ia) = .false.
364 spherical_site(ia) = .
true.
367 site_type(ia) = ions%atom(ia)%species%get_index()
370 ions%symm =
symmetries_t(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type, spherical_site)
372 safe_deallocate_a(spherical_site)
373 safe_deallocate_a(site_type)
376 call ions%generate_mapping_symmetric_atoms()
388 call parse_variable(namespace,
'ForceTotalEnforce', .false., ions%force_total_enforce)
404 ions%apply_global_force = .
true.
406 call parse_variable(namespace,
'TDGlobalForce',
'none', function_name)
407 call tdf_read(ions%global_force_function, namespace, trim(function_name), ierr)
410 call messages_write(
"You have enabled the GlobalForce option but Octopus could not find")
411 call messages_write(
"the '"//trim(function_name)//
"' function in the TDFunctions block.")
417 ions%apply_global_force = .false.
428 type(
ions_t),
intent(inout) :: ions
430 logical,
optional,
intent(in) :: print_info
432 logical :: print_info_, spec_user_defined
433 integer :: i, j, k, ispin
439 if (
present(print_info))
then
440 print_info_ = print_info
444 atoms1:
do i = 1, ions%natoms
448 ions%nspecies = ions%nspecies + 1
452 allocate(ions%species(1:ions%nspecies))
456 ions%only_user_def = .
true.
457 atoms2:
do i = 1, ions%natoms
462 ions%species(k)%s => factory%create_from_input(ions%namespace, ions%atom(j)%get_label(), k)
464 select type(spec => ions%species(k)%s)
468 ions%only_user_def = .false.
471 select type(spec => ions%species(k)%s)
473 if (ions%space%dim /= 3)
then
474 message(1) =
"Pseudopotentials may only be used with Dimensions = 3."
479 if (ions%space%is_periodic() .and. ions%space%periodic_dim /= 2)
then
480 message(1) =
"Periodic jelium slab can only be used if PeriodicDim = 2"
491 ispin = min(2, ispin)
493 if (print_info_)
then
496 do i = 1, ions%nspecies
497 spec => ions%species(i)%s
498 call spec%build(ions%namespace, ispin, ions%space%dim, print_info=print_info_)
500 if (print_info_)
then
513 call parse_variable(ions%namespace,
'SpeciesTimeDependent', .false., ions%species_time_dependent)
515 do i = 1,ions%nspecies
516 select type(spec=>ions%species(i)%s)
518 spec_user_defined = .
true.
521 if (ions%species_time_dependent .and. .not. spec_user_defined)
then
526 do i = 1, ions%natoms
527 do j = 1, ions%nspecies
540 class(
ions_t),
intent(out) :: ions_out
541 class(
ions_t),
intent(in) :: ions_in
547 ions_out%latt = ions_in%latt
549 ions_out%natoms = ions_in%natoms
550 safe_allocate(ions_out%atom(1:ions_out%natoms))
551 ions_out%atom = ions_in%atom
553 ions_out%nspecies = ions_in%nspecies
554 allocate(ions_out%species(1:ions_out%nspecies))
555 ions_out%species = ions_in%species
557 ions_out%only_user_def = ions_in%only_user_def
561 safe_allocate(ions_out%map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops))
562 ions_out%map_symm_atoms = ions_in%map_symm_atoms
563 safe_allocate(ions_out%inv_map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops))
564 ions_out%inv_map_symm_atoms = ions_in%inv_map_symm_atoms
572 class(
ions_t),
intent(inout) :: this
588 class(
ions_t),
target,
intent(inout) :: this
593 select type (interaction)
611 class(
ions_t),
intent(inout) :: ions
612 real(real64),
intent(in) :: T
615 integer(int64) :: seed
620 real(real64),
allocatable :: sigmaP(:)
621 real(real64),
allocatable :: muP(:)
622 real(real64),
allocatable :: sigmaQ(:)
623 real(real64),
allocatable :: muQ(:)
624 real(real64),
allocatable :: genP(:)
625 real(real64),
allocatable :: genQ(:)
628 real(real64) :: beta_half
629 real(real64),
allocatable :: pos_displacements(:), vel_displacements(:)
630 real(real64),
allocatable :: l_m(:), prefactor(:)
632 integer :: imode, idim, iatom, i, iline
633 integer :: num_real_modes
635 real(real64),
parameter :: low_temperature_tolerance = 1.0e-6_real64
641 seed = ions%namespace%get_hash32()
643 message(1) =
"Create initial random displacements for ions."
646 write(
message(1),
'("namespace = ",A)') ions%namespace%get()
647 write(
message(2),
'("seed = ",I0)') seed
652 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
654 num_real_modes = phonons%num_modes
656 if (num_real_modes == 0)
then
658 ions%pos_displacements =
m_zero
659 ions%vel_displacements =
m_zero
667 call wigner%init(num_real_modes, seed)
670 safe_allocate(sigmap(1:num_real_modes))
671 safe_allocate(sigmaq(1:num_real_modes))
672 safe_allocate(mup(1:num_real_modes))
673 safe_allocate(muq(1:num_real_modes))
674 safe_allocate(genp(1:num_real_modes))
675 safe_allocate(genq(1:num_real_modes))
677 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
678 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
679 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
681 safe_allocate(l_m(1:num_real_modes))
684 if (t < low_temperature_tolerance)
then
686 sigmap = 1.0_real64/2.0_real64
687 sigmaq = 1.0_real64/2.0_real64
690 sigmap = 1.0_real64/
sqrt((2.0_real64 *
tanh(beta_half * phonons%frequencies)))
691 sigmaq = 1.0_real64/
sqrt((2.0_real64 *
tanh(beta_half * phonons%frequencies)))
696 l_m =
sqrt(2.0_real64/(
unit_amu%factor * phonons%frequencies)) * phonons%alpha
699 do iatom = 1, ions%natoms
700 do idim = 1, ions%space%dim
701 prefactor(i) = 1.0_real64/
sqrt(ions%mass(iatom)/
unit_amu%factor * phonons%num_super)
707 genq = wigner%get(sigmaq, muq,
wigner_q) * l_m
712 ions%pos_displacements =
m_zero
713 ions%vel_displacements =
m_zero
717 do imode = 1, num_real_modes
719 pos_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genq(imode)
720 vel_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genp(imode)
723 write(
message(iline),
'("Displacements for mode ",I4)') imode
724 do iatom=1, ions%natoms
726 write(
message(iline),
'(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
729 write(
message(iline),
'("Velocities for mode ",I4)') imode
730 do iatom=1, ions%natoms
732 write(
message(iline),
'(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
737 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
738 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
742 safe_deallocate_a(sigmap)
743 safe_deallocate_a(sigmaq)
744 safe_deallocate_a(mup)
745 safe_deallocate_a(muq)
746 safe_deallocate_a(genp)
747 safe_deallocate_a(genq)
748 safe_deallocate_a(l_m)
750 safe_deallocate_a(prefactor)
751 safe_deallocate_a(pos_displacements)
752 safe_deallocate_a(vel_displacements)
764 class(
ions_t),
intent(inout) :: ions
765 integer,
intent(in) :: mode
766 real(real64),
optional,
intent(in) :: amplitude_pos
767 real(real64),
optional,
intent(in) :: amplitude_vel
770 integer :: num_real_modes, i, iatom, idim
771 real(real64) :: l_m, genP, genQ
773 real(real64),
allocatable :: pos_displacements(:), vel_displacements(:), prefactor(:)
778 write(
message(1),
'("Create displacements for mode ", I4)') mode
782 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
784 num_real_modes = phonons%num_modes
786 if (mode > num_real_modes)
then
787 write(
message(1),
'("Requested mode ",I0," exceeds number of available modes (",I0,")")') mode, num_real_modes
794 ions%pos_displacements =
m_zero
795 ions%vel_displacements =
m_zero
797 l_m =
sqrt(2.0_real64/(
unit_amu%factor * phonons%frequencies(mode))) * phonons%alpha(mode)
799 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
800 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
801 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
804 do iatom = 1, ions%natoms
805 do idim=1, ions%space%dim
806 prefactor(i) = 1.0_real64/
sqrt(ions%mass(iatom)/
unit_amu%factor * phonons%num_super)
812 genq = amplitude_pos * l_m
813 genp = amplitude_vel / (l_m *
unit_amu%factor)
815 pos_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genq
816 vel_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genp
818 write(
message(1),
'("Displacements for mode ",I4)') mode
820 do iatom=1, ions%natoms
821 write(
message(1),
'(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
824 write(
message(1),
'("Velocities for mode ",I4)') mode
826 do iatom=1, ions%natoms
827 write(
message(1),
'(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
832 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
833 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
835 safe_deallocate_a(pos_displacements)
836 safe_deallocate_a(vel_displacements)
837 safe_deallocate_a(prefactor)
845 class(
ions_t),
intent(inout) :: this
850 if(
allocated(this%vel_displacements))
then
851 this%vel = this%vel + this%vel_displacements
859 class(
ions_t),
intent(inout) :: this
860 character(len=*),
intent(in) :: label
875 class(
ions_t),
intent(in) :: partner
880 select type (interaction)
890 class(
ions_t),
intent(inout) :: partner
895 select type (interaction)
906 class(
ions_t),
intent(inout) :: this
912 do iatom = 1, this%natoms
913 this%pos(:, iatom) = this%latt%fold_into_cell(this%pos(:, iatom))
920 real(real64) function ions_min_distance(this, real_atoms_only) result(rmin)
921 class(
ions_t),
intent(in) :: this
922 logical,
optional,
intent(in) :: real_atoms_only
924 integer :: iatom, jatom, idir
925 real(real64) :: xx(this%space%dim)
926 logical :: real_atoms_only_
929 if (this%natoms == 1 .and. .not. this%space%is_periodic())
then
934 push_sub(ions_min_distance)
943 do iatom = 1, this%natoms
947 if (real_atoms_only_) cycle
949 do jatom = iatom + 1, this%natoms
953 if (real_atoms_only_) cycle
955 xx = abs(this%pos(:, iatom) - this%pos(:, jatom))
956 if (this%space%is_periodic())
then
957 xx = this%latt%cart_to_red(xx)
958 do idir = 1, this%space%periodic_dim
961 xx = this%latt%red_to_cart(xx)
963 rmin = min(norm2(xx), rmin)
967 if (.not. (this%only_user_def .and. real_atoms_only_))
then
969 do idir = 1, this%space%periodic_dim
970 rmin = min(rmin, norm2(this%latt%rlattice(:,idir)))
975 if(rmin < huge(rmin)/1e6_real64)
then
976 rmin = anint(rmin*1e6_real64)*1.0e-6_real64
979 pop_sub(ions_min_distance)
988 time_dependent = this%species_time_dependent
994 real(real64) function ions_val_charge(this, mask) result(val_charge)
995 class(
ions_t),
intent(in) :: this
996 logical,
optional,
intent(in) :: mask(:)
1000 if (
present(mask))
then
1001 val_charge = -sum(this%charge, mask=mask)
1003 val_charge = -sum(this%charge)
1011 class(
ions_t),
intent(in) :: this
1012 logical,
optional,
intent(in) :: mask(:)
1013 real(real64) :: dipole(this%space%dim)
1020 do ia = 1, this%natoms
1021 if (
present(mask))
then
1022 if (.not. mask(ia)) cycle
1024 dipole = dipole + this%charge(ia)*this%pos(:, ia)
1026 dipole = p_proton_charge*dipole
1033 class(
ions_t),
intent(inout) :: this
1034 real(real64),
intent(in) :: xx(this%space%dim)
1040 do iatom = 1, this%natoms
1041 this%pos(:, iatom) = this%pos(:, iatom) - xx
1049 class(
ions_t),
intent(inout) :: this
1050 real(real64),
intent(in) :: from(this%space%dim)
1051 real(real64),
intent(in) :: from2(this%space%dim)
1052 real(real64),
intent(in) :: to(this%space%dim)
1055 real(real64) :: m1(3, 3), m2(3, 3)
1056 real(real64) :: m3(3, 3), f2(3), per(3)
1057 real(real64) :: alpha, r
1061 if (this%space%dim /= 3)
then
1062 call messages_not_implemented(
"ions_rotate in other than 3 dimensions", namespace=this%namespace)
1066 m1 = diagonal_matrix(3, m_one)
1069 if (abs(to(2)) > 1d-150)
then
1070 alpha =
atan2(to(2), to(1))
1071 call rotate(m1, alpha, 3)
1073 alpha =
atan2(norm2(to(1:2)), to(3))
1074 call rotate(m1, -alpha, 2)
1077 f2 = matmul(m1, from)
1082 if (r > m_zero)
then
1089 m2 = diagonal_matrix(3, m_one)
1090 alpha =
atan2(per(1), per(2))
1091 call rotate(m2, -alpha, 3)
1094 m3 = diagonal_matrix(3, m_one)
1095 alpha =
acos(min(sum(from*to), m_one))
1096 call rotate(m3, -alpha, 2)
1099 m2 = matmul(transpose(m2), matmul(m3, m2))
1102 per = matmul(m2, matmul(m1, from2))
1103 alpha =
atan2(per(1), per(2))
1104 call rotate(m2, -alpha, 3)
1107 m1 = matmul(transpose(m1), matmul(m2, m1))
1111 do iatom = 1, this%natoms
1112 f2 = this%pos(:, iatom)
1113 this%pos(:, iatom) = matmul(m1, f2)
1120 subroutine rotate(m, angle, dir)
1121 real(real64),
intent(inout) :: m(3, 3)
1122 real(real64),
intent(in) :: angle
1123 integer,
intent(in) :: dir
1125 real(real64) :: aux(3, 3), ca, sa
1163 class(
ions_t),
intent(in) :: this
1164 real(real64),
intent(in) :: time
1165 real(real64) :: force(this%space%dim)
1171 if (this%apply_global_force)
then
1172 force(1) = tdf(this%global_force_function, time)
1179 subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
1180 class(
ions_t),
intent(in) :: this
1181 character(len=*),
intent(in) :: fname
1182 logical,
optional,
intent(in) :: append
1183 character(len=*),
optional,
intent(in) :: comment
1184 logical,
optional,
intent(in) :: reduce_coordinates
1186 integer :: iatom, idim, iunit
1187 character(len=6) position
1188 character(len=19) :: frmt
1189 real(real64) :: red(this%space%dim)
1191 if (.not. this%grp%is_root())
return
1196 if (
present(append))
then
1197 if (append) position =
'append'
1199 if(.not.optional_default(reduce_coordinates, .false.))
then
1200 iunit = io_open(trim(fname)//
'.xyz', this%namespace, action=
'write', position=position)
1202 iunit = io_open(trim(fname)//
'.xyz_red', this%namespace, action=
'write', position=position)
1205 write(iunit,
'(i4)') this%natoms
1206 if (
present(comment))
then
1207 write(iunit,
'(1x,a)') comment
1209 write(iunit,
'(1x,a,a)')
'units: ', trim(units_abbrev(units_out%length_xyz_file))
1212 write(unit=frmt, fmt=
"(a5,i2.2,a4,i2.2,a6)")
"(6x,a", label_len,
",2x,", this%space%dim,
"f15.9)"
1213 do iatom = 1, this%natoms
1214 if(.not.optional_default(reduce_coordinates, .false.))
then
1215 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, &
1216 (units_from_atomic(units_out%length_xyz_file, this%pos(idim, iatom)), idim=1, this%space%dim)
1218 red = this%latt%cart_to_red(this%pos(:, iatom))
1219 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, (red(idim), idim=1, this%space%dim)
1222 call io_close(iunit)
1233 class(
ions_t),
intent(in) :: this
1234 character(len=*),
optional,
intent(in) :: fname
1235 character(len=*),
optional,
intent(in) :: comment
1237 integer :: iatom, idim, iunit
1238 character(len=:),
allocatable :: fname_, comment_
1239 character(len=10) :: format_string
1243 if (.not. this%grp%is_root())
then
1248 comment_ = optional_default(comment,
"")
1249 fname_ = optional_default(fname,
"POSCAR")
1251 iunit = io_open(trim(fname_), this%namespace, action=
'write')
1253 write(iunit,
'(A)') comment_
1254 write(iunit,
'("1.0")')
1256 write(format_string,
'("(",I1,A,")")') this%space%dim,
'F15.10'
1257 do idim=1, this%space%dim
1258 write(iunit, format_string) units_from_atomic(unit_angstrom, this%latt%rlattice(:,idim))
1261 do iatom = 1, this%natoms
1262 write(iunit,
'(A)', advance=
'NO') trim(this%atom(iatom)%label)//
" "
1264 write(iunit,
'("")')
1265 write(iunit,
'(A)') repeat(
"1 ", this%natoms)
1266 write(iunit,
'("direct")')
1267 write(format_string,
'("(",I1,A,")")') this%space%dim,
'F15.10'
1268 do iatom=1, this%natoms
1269 write(iunit, format_string) this%latt%cart_to_red(this%pos(:, iatom))
1272 call io_close(iunit)
1279 use iso_fortran_env,
only: real64
1280 class(
ions_t),
intent(inout) :: this
1281 character(len=*),
intent(in) :: fname
1282 character(len=*),
optional,
intent(in) :: comment
1284 integer :: iatom, idir, iunit, ios
1285 character(len=256) :: line
1286 character(len=LABEL_LEN) :: label
1287 character(len=:),
allocatable :: coordstr
1288 real(real64) :: tmp(this%space%dim)
1292 iunit = io_open(trim(fname)//
'.xyz', this%namespace, action=
'read', position=
'rewind')
1295 read(iunit,
'(i4)') this%natoms
1296 if (
present(comment))
then
1303 do iatom = 1, this%natoms
1306 read(iunit,
'(A)', iostat=ios) line
1308 call io_close(iunit)
1309 message(1) =
"Error reading XYZ atom line"
1310 call messages_fatal(1, namespace=this%namespace)
1314 if (len_trim(line) < label_len)
then
1315 call io_close(iunit)
1316 message(1) =
"XYZ file: atom line too short for label"
1317 call messages_fatal(1, namespace=this%namespace)
1319 label = line(1:label_len)
1322 if (len(line) > label_len)
then
1323 coordstr = adjustl(line(label_len+1:))
1325 call io_close(iunit)
1326 message(1) =
"XYZ file: no coordinate data after label"
1327 call messages_fatal(1, namespace=this%namespace)
1331 read(coordstr, *, iostat=ios) (tmp(idir), idir=1, this%space%dim)
1333 call io_close(iunit)
1334 message(1) =
"XYZ file: malformed coordinate fields"
1335 call messages_fatal(1, namespace=this%namespace)
1339 this%pos(:, iatom) = units_to_atomic(units_out%length_xyz_file, tmp)
1343 call io_close(iunit)
1352 class(
ions_t),
intent(in) :: this
1353 character(len=*),
intent(in) :: dir
1355 type(lattice_iterator_t) :: latt_iter
1356 real(real64) :: radius, pos(this%space%dim)
1357 integer :: iatom, icopy, iunit
1361 radius = maxval(m_half*norm2(this%latt%rlattice(:,1:this%space%periodic_dim), dim=1))*(m_one + m_epsilon)
1362 latt_iter = lattice_iterator_t(this%latt, radius)
1364 if (this%grp%is_root())
then
1366 iunit = io_open(trim(dir)//
'/crystal.xyz', this%namespace, action=
'write')
1368 write(iunit,
'(i9)') this%natoms*latt_iter%n_cells
1369 write(iunit,
'(a)')
'#generated by Octopus'
1371 do iatom = 1, this%natoms
1372 do icopy = 1, latt_iter%n_cells
1373 pos = units_from_atomic(units_out%length, this%pos(:, iatom) + latt_iter%get(icopy))
1374 write(iunit,
'(a, 99f12.6)') this%atom(iatom)%label, pos
1378 call io_close(iunit)
1386 class(
ions_t),
intent(in) :: this
1387 character(len=*),
intent(in) :: dir, fname
1389 integer :: iunit, iatom, idir
1390 real(real64) :: force(this%space%dim), center(this%space%dim)
1391 character(len=20) frmt
1393 if (.not. this%grp%is_root())
return
1397 call io_mkdir(dir, this%namespace)
1398 iunit = io_open(trim(dir)//
'/'//trim(fname)//
'.bild', this%namespace, action=
'write', &
1401 write(frmt,
'(a,i0,a)')
'(a,2(', this%space%dim,
'f16.6,1x))'
1403 write(iunit,
'(a)')
'.comment : force vectors in ['//trim(units_abbrev(units_out%force))//
']'
1405 write(iunit,
'(a)')
'.color red'
1407 do iatom = 1, this%natoms
1408 center = units_from_atomic(units_out%length, this%pos(:, iatom))
1409 force = units_from_atomic(units_out%force, this%tot_force(:, iatom))
1410 write(iunit,
'(a,1x,i4,1x,a2,1x,a6,1x,f10.6,a)')
'.comment :', iatom, trim(this%atom(iatom)%label), &
1411 'force:', norm2(force),
'['//trim(units_abbrev(units_out%force))//
']'
1412 write(iunit,fmt=trim(frmt))
'.arrow', (center(idir), idir = 1, this%space%dim), &
1413 (center(idir) + force(idir), idir = 1, this%space%dim)
1417 call io_close(iunit)
1424 class(
ions_t),
intent(in) :: this
1425 character(len=*),
intent(in) :: filename
1426 logical,
optional,
intent(in) :: ascii
1428 integer :: iunit, iatom, ierr
1430 real(real64),
allocatable :: data(:, :)
1431 integer,
allocatable :: idata(:, :)
1432 character(len=MAX_PATH_LEN) :: fullname
1436 assert(this%space%dim == 3)
1438 ascii_ = optional_default(ascii, .
true.)
1440 fullname = trim(filename)//
".vtk"
1442 iunit = io_open(trim(fullname), this%namespace, action=
'write')
1444 write(iunit,
'(1a)')
'# vtk DataFile Version 3.0 '
1445 write(iunit,
'(6a)')
'Generated by octopus ', trim(conf%version),
' - git: ', &
1446 trim(conf%git_commit),
" configuration: ", trim(conf%config_time)
1449 write(iunit,
'(1a)')
'ASCII'
1451 write(iunit,
'(1a)')
'BINARY'
1454 write(iunit,
'(1a)')
'DATASET POLYDATA'
1456 write(iunit,
'(a,i9,a)')
'POINTS ', this%natoms,
' double'
1459 do iatom = 1, this%natoms
1460 write(iunit,
'(3f12.6)') this%pos(1:3, iatom)
1463 call io_close(iunit)
1464 safe_allocate(
data(1:3, 1:this%natoms))
1465 do iatom = 1, this%natoms
1466 data(1:3, iatom) = this%pos(1:3, iatom)
1468 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(3*this%natoms),
data, &
1469 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1470 safe_deallocate_a(data)
1471 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1472 write(iunit,
'(1a)')
''
1475 write(iunit,
'(a,2i9)')
'VERTICES ', this%natoms, 2*this%natoms
1478 do iatom = 1, this%natoms
1479 write(iunit,
'(2i9)') 1, iatom - 1
1482 call io_close(iunit)
1483 safe_allocate(idata(1:2, 1:this%natoms))
1484 do iatom = 1, this%natoms
1486 idata(2, iatom) = iatom - 1
1488 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(2*this%natoms), idata, &
1489 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1490 safe_deallocate_a(idata)
1491 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1492 write(iunit,
'(1a)')
''
1495 write(iunit,
'(a,i9)')
'POINT_DATA', this%natoms
1496 write(iunit,
'(a)')
'SCALARS element integer'
1497 write(iunit,
'(a)')
'LOOKUP_TABLE default'
1500 do iatom = 1, this%natoms
1501 write(iunit,
'(i9)') nint(this%atom(iatom)%species%get_z())
1504 call io_close(iunit)
1506 safe_allocate(idata(1:this%natoms, 1))
1508 do iatom = 1, this%natoms
1509 idata(iatom, 1) = nint(this%atom(iatom)%species%get_z())
1512 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(this%natoms), idata, &
1513 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1515 safe_deallocate_a(idata)
1517 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1518 write(iunit,
'(1a)')
''
1521 call io_close(iunit)
1528 class(
ions_t),
intent(in) :: this
1529 real(real64) :: current(this%space%dim)
1536 do iatom = this%atoms_dist%start, this%atoms_dist%end
1537 current = current + p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom)
1540 if (this%atoms_dist%parallel)
then
1541 call comm_allreduce(this%atoms_dist%mpi_grp, current, dim=this%space%dim)
1549 class(
ions_t),
intent(in) :: this
1550 real(real64) :: abs_current(this%space%dim)
1556 abs_current = m_zero
1557 do iatom = this%atoms_dist%start, this%atoms_dist%end
1558 abs_current = abs_current + abs(p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom))
1561 if (this%atoms_dist%parallel)
then
1562 call comm_allreduce(this%atoms_dist%mpi_grp, abs_current, dim=this%space%dim)
1570 type(
ions_t),
intent(inout) :: ions
1576 call distributed_end(ions%atoms_dist)
1578 call ion_interaction_end(ions%ion_interaction)
1580 safe_deallocate_a(ions%atom)
1583 if(
allocated(ions%species))
then
1584 do i = 1, ions%nspecies
1586 if(
associated(ions%species(i)%s))
deallocate(ions%species(i)%s)
1588 deallocate(ions%species)
1592 safe_deallocate_a(ions%pos_displacements)
1593 safe_deallocate_a(ions%vel_displacements)
1595 call charged_particles_end(ions)
1597 safe_deallocate_a(ions%map_symm_atoms)
1598 safe_deallocate_a(ions%inv_map_symm_atoms)
1608 class(
ions_t),
intent(inout) :: ions
1609 type(lattice_vectors_t),
intent(in) :: latt
1610 logical,
intent(in) :: symmetrize
1615 call ions%latt%update(latt%rlattice)
1618 if (symmetrize)
then
1619 call symmetries_update_lattice_vectors(ions%symm, latt, ions%space%dim)
1632 class(
ions_t),
intent(inout) :: ions
1634 integer :: iatom, iop, iatom_symm, dim4symms
1635 real(real64) :: ratom(ions%space%dim)
1639 safe_allocate(ions%map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1640 safe_allocate(ions%inv_map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1643 dim4symms = min(3, ions%space%dim)
1646 do iop = 1, ions%symm%nops
1647 do iatom = 1, ions%natoms
1649 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom))
1651 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1654 do iatom_symm = 1, ions%natoms
1655 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec))
exit
1658 if (iatom_symm > ions%natoms)
then
1659 write(message(1),
'(a,i6)')
'Internal error: could not find symmetric partner for atom number', iatom
1660 write(message(2),
'(a,i3,a)')
'with symmetry operation number ', iop,
'.'
1661 call messages_fatal(2, namespace=ions%namespace)
1664 ions%map_symm_atoms(iatom, iop) = iatom_symm
1665 ions%inv_map_symm_atoms(iatom_symm, iop) = iatom
1670 do iop = 1, ions%symm%nops_nonsymmorphic
1671 do iatom = 1, ions%natoms
1673 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom))
1675 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1678 do iatom_symm = 1, ions%natoms
1679 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec))
exit
1682 if (iatom_symm > ions%natoms)
then
1683 write(message(1),
'(a,i6)')
'Internal error: could not find symmetric partner for atom number', iatom
1684 write(message(2),
'(a,i3,a)')
'with symmetry operation number ', iop,
'.'
1685 call messages_fatal(2, namespace=ions%namespace)
1688 ions%map_symm_atoms(iatom, ions%symm%nops+iop) = iatom_symm
1689 ions%inv_map_symm_atoms(iatom_symm, ions%symm%nops+iop) = iatom
1704 integer :: iatom, iop, iatom_sym
1705 real(real64) :: ratom(ions%space%dim)
1706 real(real64),
allocatable :: new_pos(:,:)
1710 safe_allocate(new_pos(1:ions%space%dim, 1:ions%natoms))
1712 do iatom = 1, ions%natoms
1713 new_pos(:, iatom) = m_zero
1716 do iop = 1, ions%symm%nops
1717 iatom_sym = ions%inv_map_symm_atoms(iatom, iop)
1718 ratom = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom_sym))
1719 ratom = ions%latt%fold_into_cell(ratom)
1720 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1724 do iop = 1, ions%symm%nops_nonsymmorphic
1725 iatom_sym = ions%inv_map_symm_atoms(iatom, iop + ions%symm%nops)
1726 ratom = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom_sym))
1727 ratom = ions%latt%fold_into_cell(ratom)
1728 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1731 new_pos(:, iatom) = new_pos(:, iatom) / (ions%symm%nops + ions%symm%nops_nonsymmorphic)
1740 class(
ions_t),
intent(inout) :: ions
1742 type(spglibdataset) :: spg_dataset
1743 character(len=11) :: symbol
1744 integer,
allocatable :: site_type(:)
1745 integer :: space_group, ia
1747 if(.not. ions%space%is_periodic())
return
1751 safe_allocate(site_type(1:ions%natoms))
1752 do ia = 1, ions%natoms
1753 site_type(ia) = ions%atom(ia)%species%get_index()
1756 spg_dataset = symmetries_get_spg_dataset(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type)
1758 safe_deallocate_a(site_type)
1760 if (spg_dataset%spglib_error /= 0)
then
1765 space_group = spg_dataset%spacegroup_number
1766 symbol = spg_dataset%international_symbol
1768 write(message(1),
'(a, i4)')
'Info: Space group No. ', space_group
1769 write(message(2),
'(2a)')
'Info: International: ', trim(symbol)
1770 call messages_info(2, namespace=ions%namespace)
--------------— axpy ---------------— Constant times a vector plus a vector.
double acos(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
double tanh(double __x) __attribute__((__nothrow__
double atan2(double __y, double __x) __attribute__((__nothrow__
double floor(double __x) __attribute__((__nothrow__
subroutine rotate(m, angle, dir)
subroutine, public atom_init(this, dim, label, species)
subroutine, public atom_get_species(this, species)
subroutine, public atom_set_species(this, species)
This module contains interfaces for BLAS routines You should not use these routines directly....
This module handles the calculation mode.
integer, parameter, public p_strategy_states
parallelization in states
subroutine, public charged_particles_copy(this, cp_in)
subroutine, public charged_particles_init_interaction_as_partner(partner, interaction)
subroutine, public charged_particles_update_quantity(this, label)
subroutine, public charged_particles_init_interaction(this, interaction)
subroutine, public charged_particles_copy_quantities_to_interaction(partner, interaction)
subroutine, public charged_particles_init(this, np)
The init routine is a module level procedure This has the advantage that different classes can have d...
subroutine, public distributed_nullify(this, total)
subroutine, public distributed_init(this, total, comm, tag, scalapack_compat)
Distribute N instances across M processes of communicator comm
subroutine, public distributed_copy(in, out)
@Brief Create a copy of a distributed instance
real(real64), parameter, public m_huge
real(real64), parameter, public m_zero
character(len= *), parameter, public static_dir
real(real64), parameter, public p_kb
Boltzmann constant in Ha/K.
real(real64), parameter, public m_half
real(real64), parameter, public m_one
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
subroutine, public io_mkdir(fname, namespace, parents)
subroutine, public ion_interaction_init_parallelization(this, natoms, mc)
subroutine, public ion_interaction_init(this, namespace, space, natoms)
subroutine ions_init_interaction(this, interaction)
subroutine ions_update_lattice_vectors(ions, latt, symmetrize)
Regenerate the ions information after update of the lattice vectors.
class(ions_t) function, pointer ions_constructor(namespace, print_info, latt_inp)
subroutine ions_fold_atoms_into_cell(this)
subroutine ions_single_mode_displacements(ions, mode, amplitude_pos, amplitude_vel)
apply initial displacements and velocities corresponding to a given phonon mode
real(real64) function, dimension(this%space%dim) ions_global_force(this, time)
subroutine ions_copy(ions_out, ions_in)
real(real64) function, dimension(this%space%dim) ions_current(this)
subroutine ions_update_quantity(this, label)
subroutine ions_generate_mapping_symmetric_atoms(ions)
Given the symmetries of the system, we create a mapping that tell us for each atom and symmetry,...
subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
subroutine ions_init_species(ions, factory, print_info)
subroutine ions_finalize(ions)
subroutine ions_initialize(this)
real(real64) function, dimension(this%space%dim) ions_abs_current(this)
subroutine ions_read_xyz(this, fname, comment)
subroutine ions_write_vtk_geometry(this, filename, ascii)
subroutine ions_rotate(this, from, from2, to)
subroutine ions_translate(this, xx)
subroutine ions_symmetrize_atomic_coord(ions)
Symmetrizes atomic coordinates by applying all symmetries.
subroutine ions_print_spacegroup(ions)
Prints the spacegroup of the system for periodic systems.
real(real64) function ions_min_distance(this, real_atoms_only)
subroutine ions_init_random_displacements(ions, T)
create random displacements for positions and velocities
real(real64) function, dimension(this%space%dim) ions_dipole(this, mask)
subroutine ions_write_bild_forces_file(this, dir, fname)
subroutine ions_write_crystal(this, dir)
This subroutine creates a crystal by replicating the geometry and writes the result to dir.
logical function ions_has_time_dependent_species(this)
subroutine ions_partition(this, mc)
subroutine ions_init_interaction_as_partner(partner, interaction)
subroutine ions_copy_quantities_to_interaction(partner, interaction)
subroutine ions_write_poscar(this, fname, comment)
Writes the positions of the ions in POSCAR format.
real(real64) function ions_val_charge(this, mask)
This module is intended to contain "only mathematical" functions and procedures.
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
character(len=512), private msg
subroutine, public messages_warning(no_lines, all_nodes, namespace)
subroutine, public messages_obsolete_variable(namespace, name, rep)
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)
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
subroutine mpi_grp_init(grp, comm)
Initialize MPI group instance.
This module handles the communicators for the various parallelization strategies.
logical function, public parse_is_defined(namespace, name)
This module provides a class for (classical) phonon modes.
integer, parameter, public read_coords_reduced
subroutine, public read_coords_init(gf)
integer, parameter, public xyz_flags_move
subroutine, public read_coords_end(gf)
subroutine, public read_coords_read(what, gf, space, namespace)
subroutine, public species_factory_init(factory, namespace)
subroutine, public species_factory_end(factory)
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_t), public unit_amu
Mass in atomic mass units (AKA Dalton).
type(unit_system_t), public units_out
integer, parameter, public wigner_q
integer, parameter, public wigner_p
abstract interaction class
surrogate interaction class to avoid circular dependencies between modules.
Stores all communicators and groups.
This class describes phonon modes, which are specified by their frequencies and eigenvectors.
An abstract class for species. Derived classes include jellium, all electron, and pseudopotential spe...
Class describing a Wigner distribution for sampling initial conditions in multi-trajectory Ehrenfest ...