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 spec_user_defined = .false.
516 do i = 1,ions%nspecies
517 select type(spec=>ions%species(i)%s)
519 spec_user_defined = .
true.
522 if (ions%species_time_dependent .and. .not. spec_user_defined)
then
527 do i = 1, ions%natoms
528 do j = 1, ions%nspecies
541 class(
ions_t),
intent(out) :: ions_out
542 class(
ions_t),
intent(in) :: ions_in
548 ions_out%latt = ions_in%latt
550 ions_out%natoms = ions_in%natoms
551 safe_allocate(ions_out%atom(1:ions_out%natoms))
552 ions_out%atom = ions_in%atom
554 ions_out%nspecies = ions_in%nspecies
555 allocate(ions_out%species(1:ions_out%nspecies))
556 ions_out%species = ions_in%species
558 ions_out%only_user_def = ions_in%only_user_def
562 safe_allocate(ions_out%map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops + ions_in%symm%nops_nonsymmorphic))
563 ions_out%map_symm_atoms = ions_in%map_symm_atoms
564 safe_allocate(ions_out%inv_map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops + ions_in%symm%nops_nonsymmorphic))
565 ions_out%inv_map_symm_atoms = ions_in%inv_map_symm_atoms
573 class(
ions_t),
intent(inout) :: this
589 class(
ions_t),
target,
intent(inout) :: this
594 select type (interaction)
612 class(
ions_t),
intent(inout) :: ions
613 real(real64),
intent(in) :: T
616 integer(int64) :: seed
621 real(real64),
allocatable :: sigmaP(:)
622 real(real64),
allocatable :: muP(:)
623 real(real64),
allocatable :: sigmaQ(:)
624 real(real64),
allocatable :: muQ(:)
625 real(real64),
allocatable :: genP(:)
626 real(real64),
allocatable :: genQ(:)
629 real(real64) :: beta_half
630 real(real64),
allocatable :: pos_displacements(:), vel_displacements(:)
631 real(real64),
allocatable :: l_m(:), prefactor(:)
633 integer :: imode, idim, iatom, i, iline
634 integer :: num_real_modes
636 real(real64),
parameter :: low_temperature_tolerance = 1.0e-6_real64
642 seed = ions%namespace%get_hash32()
644 message(1) =
"Create initial random displacements for ions."
647 write(
message(1),
'("namespace = ",A)') ions%namespace%get()
648 write(
message(2),
'("seed = ",I0)') seed
653 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
655 num_real_modes = phonons%num_modes
657 if (num_real_modes == 0)
then
659 ions%pos_displacements =
m_zero
660 ions%vel_displacements =
m_zero
668 call wigner%init(num_real_modes, seed)
671 safe_allocate(sigmap(1:num_real_modes))
672 safe_allocate(sigmaq(1:num_real_modes))
673 safe_allocate(mup(1:num_real_modes))
674 safe_allocate(muq(1:num_real_modes))
675 safe_allocate(genp(1:num_real_modes))
676 safe_allocate(genq(1:num_real_modes))
678 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
679 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
680 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
682 safe_allocate(l_m(1:num_real_modes))
685 if (t < low_temperature_tolerance)
then
687 sigmap = 1.0_real64/2.0_real64
688 sigmaq = 1.0_real64/2.0_real64
691 sigmap = 1.0_real64/
sqrt((2.0_real64 *
tanh(beta_half * phonons%frequencies)))
692 sigmaq = 1.0_real64/
sqrt((2.0_real64 *
tanh(beta_half * phonons%frequencies)))
697 l_m =
sqrt(2.0_real64/(
unit_amu%factor * phonons%frequencies)) * phonons%alpha
700 do iatom = 1, ions%natoms
701 do idim = 1, ions%space%dim
702 prefactor(i) = 1.0_real64/
sqrt(ions%mass(iatom)/
unit_amu%factor * phonons%num_super)
708 genq = wigner%get(sigmaq, muq,
wigner_q) * l_m
713 ions%pos_displacements =
m_zero
714 ions%vel_displacements =
m_zero
718 do imode = 1, num_real_modes
720 pos_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genq(imode)
721 vel_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genp(imode)
724 write(
message(iline),
'("Displacements for mode ",I4)') imode
725 do iatom=1, ions%natoms
727 write(
message(iline),
'(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
730 write(
message(iline),
'("Velocities for mode ",I4)') imode
731 do iatom=1, ions%natoms
733 write(
message(iline),
'(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
738 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
739 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
743 safe_deallocate_a(sigmap)
744 safe_deallocate_a(sigmaq)
745 safe_deallocate_a(mup)
746 safe_deallocate_a(muq)
747 safe_deallocate_a(genp)
748 safe_deallocate_a(genq)
749 safe_deallocate_a(l_m)
751 safe_deallocate_a(prefactor)
752 safe_deallocate_a(pos_displacements)
753 safe_deallocate_a(vel_displacements)
765 class(
ions_t),
intent(inout) :: ions
766 integer,
intent(in) :: mode
767 real(real64),
optional,
intent(in) :: amplitude_pos
768 real(real64),
optional,
intent(in) :: amplitude_vel
771 integer :: num_real_modes, i, iatom, idim
772 real(real64) :: l_m, genP, genQ
774 real(real64),
allocatable :: pos_displacements(:), vel_displacements(:), prefactor(:)
779 write(
message(1),
'("Create displacements for mode ", I4)') mode
783 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
785 num_real_modes = phonons%num_modes
787 if (mode > num_real_modes)
then
788 write(
message(1),
'("Requested mode ",I0," exceeds number of available modes (",I0,")")') mode, num_real_modes
795 ions%pos_displacements =
m_zero
796 ions%vel_displacements =
m_zero
798 l_m =
sqrt(2.0_real64/(
unit_amu%factor * phonons%frequencies(mode))) * phonons%alpha(mode)
800 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
801 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
802 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
805 do iatom = 1, ions%natoms
806 do idim=1, ions%space%dim
807 prefactor(i) = 1.0_real64/
sqrt(ions%mass(iatom)/
unit_amu%factor * phonons%num_super)
813 genq = amplitude_pos * l_m
814 genp = amplitude_vel / (l_m *
unit_amu%factor)
816 pos_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genq
817 vel_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genp
819 write(
message(1),
'("Displacements for mode ",I4)') mode
821 do iatom=1, ions%natoms
822 write(
message(1),
'(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
825 write(
message(1),
'("Velocities for mode ",I4)') mode
827 do iatom=1, ions%natoms
828 write(
message(1),
'(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
833 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
834 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
836 safe_deallocate_a(pos_displacements)
837 safe_deallocate_a(vel_displacements)
838 safe_deallocate_a(prefactor)
846 class(
ions_t),
intent(inout) :: this
851 if(
allocated(this%vel_displacements))
then
852 this%vel = this%vel + this%vel_displacements
860 class(
ions_t),
intent(inout) :: this
861 character(len=*),
intent(in) :: label
876 class(
ions_t),
intent(in) :: partner
881 select type (interaction)
891 class(
ions_t),
intent(inout) :: partner
896 select type (interaction)
907 class(
ions_t),
intent(inout) :: this
913 do iatom = 1, this%natoms
914 this%pos(:, iatom) = this%latt%fold_into_cell(this%pos(:, iatom))
921 real(real64) function ions_min_distance(this, real_atoms_only) result(rmin)
922 class(
ions_t),
intent(in) :: this
923 logical,
optional,
intent(in) :: real_atoms_only
925 integer :: iatom, jatom, idir
926 real(real64) :: xx(this%space%dim)
927 logical :: real_atoms_only_
930 if (this%natoms == 1 .and. .not. this%space%is_periodic())
then
935 push_sub(ions_min_distance)
944 do iatom = 1, this%natoms
948 if (real_atoms_only_) cycle
950 do jatom = iatom + 1, this%natoms
954 if (real_atoms_only_) cycle
956 xx = abs(this%pos(:, iatom) - this%pos(:, jatom))
957 if (this%space%is_periodic())
then
958 xx = this%latt%cart_to_red(xx)
959 do idir = 1, this%space%periodic_dim
962 xx = this%latt%red_to_cart(xx)
964 rmin = min(norm2(xx), rmin)
968 if (.not. (this%only_user_def .and. real_atoms_only_))
then
970 do idir = 1, this%space%periodic_dim
971 rmin = min(rmin, norm2(this%latt%rlattice(:,idir)))
976 if(rmin < huge(rmin)/1e6_real64)
then
977 rmin = anint(rmin*1e6_real64)*1.0e-6_real64
980 pop_sub(ions_min_distance)
989 time_dependent = this%species_time_dependent
995 real(real64) function ions_val_charge(this, mask) result(val_charge)
996 class(
ions_t),
intent(in) :: this
997 logical,
optional,
intent(in) :: mask(:)
1001 if (
present(mask))
then
1002 val_charge = -sum(this%charge, mask=mask)
1004 val_charge = -sum(this%charge)
1012 class(
ions_t),
intent(in) :: this
1013 logical,
optional,
intent(in) :: mask(:)
1014 real(real64) :: dipole(this%space%dim)
1021 do ia = 1, this%natoms
1022 if (
present(mask))
then
1023 if (.not. mask(ia)) cycle
1025 dipole = dipole + this%charge(ia)*this%pos(:, ia)
1027 dipole = p_proton_charge*dipole
1034 class(
ions_t),
intent(inout) :: this
1035 real(real64),
intent(in) :: xx(this%space%dim)
1041 do iatom = 1, this%natoms
1042 this%pos(:, iatom) = this%pos(:, iatom) - xx
1050 class(
ions_t),
intent(inout) :: this
1051 real(real64),
intent(in) :: from(this%space%dim)
1052 real(real64),
intent(in) :: from2(this%space%dim)
1053 real(real64),
intent(in) :: to(this%space%dim)
1056 real(real64) :: m1(3, 3), m2(3, 3)
1057 real(real64) :: m3(3, 3), f2(3), per(3)
1058 real(real64) :: alpha, r
1062 if (this%space%dim /= 3)
then
1063 call messages_not_implemented(
"ions_rotate in other than 3 dimensions", namespace=this%namespace)
1067 m1 = diagonal_matrix(3, m_one)
1070 if (abs(to(2)) > 1d-150)
then
1071 alpha =
atan2(to(2), to(1))
1072 call rotate(m1, alpha, 3)
1074 alpha =
atan2(norm2(to(1:2)), to(3))
1075 call rotate(m1, -alpha, 2)
1078 f2 = matmul(m1, from)
1083 if (r > m_zero)
then
1090 m2 = diagonal_matrix(3, m_one)
1091 alpha =
atan2(per(1), per(2))
1092 call rotate(m2, -alpha, 3)
1095 m3 = diagonal_matrix(3, m_one)
1096 alpha =
acos(min(sum(from*to), m_one))
1097 call rotate(m3, -alpha, 2)
1100 m2 = matmul(transpose(m2), matmul(m3, m2))
1103 per = matmul(m2, matmul(m1, from2))
1104 alpha =
atan2(per(1), per(2))
1105 call rotate(m2, -alpha, 3)
1108 m1 = matmul(transpose(m1), matmul(m2, m1))
1112 do iatom = 1, this%natoms
1113 f2 = this%pos(:, iatom)
1114 this%pos(:, iatom) = matmul(m1, f2)
1121 subroutine rotate(m, angle, dir)
1122 real(real64),
intent(inout) :: m(3, 3)
1123 real(real64),
intent(in) :: angle
1124 integer,
intent(in) :: dir
1126 real(real64) :: aux(3, 3), ca, sa
1164 class(
ions_t),
intent(in) :: this
1165 real(real64),
intent(in) :: time
1166 real(real64) :: force(this%space%dim)
1172 if (this%apply_global_force)
then
1173 force(1) = tdf(this%global_force_function, time)
1180 subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
1181 class(
ions_t),
intent(in) :: this
1182 character(len=*),
intent(in) :: fname
1183 logical,
optional,
intent(in) :: append
1184 character(len=*),
optional,
intent(in) :: comment
1185 logical,
optional,
intent(in) :: reduce_coordinates
1187 integer :: iatom, idim, iunit
1188 character(len=6) position
1189 character(len=19) :: frmt
1190 real(real64) :: red(this%space%dim)
1192 if (.not. this%grp%is_root())
return
1197 if (
present(append))
then
1198 if (append) position =
'append'
1200 if(.not.optional_default(reduce_coordinates, .false.))
then
1201 iunit = io_open(trim(fname)//
'.xyz', this%namespace, action=
'write', position=position)
1203 iunit = io_open(trim(fname)//
'.xyz_red', this%namespace, action=
'write', position=position)
1206 write(iunit,
'(i4)') this%natoms
1207 if (
present(comment))
then
1208 write(iunit,
'(1x,a)') comment
1210 write(iunit,
'(1x,a,a)')
'units: ', trim(units_abbrev(units_out%length_xyz_file))
1213 write(unit=frmt, fmt=
"(a5,i2.2,a4,i2.2,a6)")
"(6x,a", label_len,
",2x,", this%space%dim,
"f15.9)"
1214 do iatom = 1, this%natoms
1215 if(.not.optional_default(reduce_coordinates, .false.))
then
1216 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, &
1217 (units_from_atomic(units_out%length_xyz_file, this%pos(idim, iatom)), idim=1, this%space%dim)
1219 red = this%latt%cart_to_red(this%pos(:, iatom))
1220 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, (red(idim), idim=1, this%space%dim)
1223 call io_close(iunit)
1234 class(
ions_t),
intent(in) :: this
1235 character(len=*),
optional,
intent(in) :: fname
1236 character(len=*),
optional,
intent(in) :: comment
1238 integer :: iatom, idim, iunit
1239 character(len=:),
allocatable :: fname_, comment_
1240 character(len=10) :: format_string
1244 if (.not. this%grp%is_root())
then
1249 comment_ = optional_default(comment,
"")
1250 fname_ = optional_default(fname,
"POSCAR")
1252 iunit = io_open(trim(fname_), this%namespace, action=
'write')
1254 write(iunit,
'(A)') comment_
1255 write(iunit,
'("1.0")')
1257 write(format_string,
'("(",I1,A,")")') this%space%dim,
'F15.10'
1258 do idim=1, this%space%dim
1259 write(iunit, format_string) units_from_atomic(unit_angstrom, this%latt%rlattice(:,idim))
1262 do iatom = 1, this%natoms
1263 write(iunit,
'(A)', advance=
'NO') trim(this%atom(iatom)%label)//
" "
1265 write(iunit,
'("")')
1266 write(iunit,
'(A)') repeat(
"1 ", this%natoms)
1267 write(iunit,
'("direct")')
1268 write(format_string,
'("(",I1,A,")")') this%space%dim,
'F15.10'
1269 do iatom=1, this%natoms
1270 write(iunit, format_string) this%latt%cart_to_red(this%pos(:, iatom))
1273 call io_close(iunit)
1280 use iso_fortran_env,
only: real64
1281 class(
ions_t),
intent(inout) :: this
1282 character(len=*),
intent(in) :: fname
1283 character(len=*),
optional,
intent(in) :: comment
1285 integer :: iatom, idir, iunit, ios
1286 character(len=256) :: line
1287 character(len=LABEL_LEN) :: label
1288 character(len=:),
allocatable :: coordstr
1289 real(real64) :: tmp(this%space%dim)
1293 iunit = io_open(trim(fname)//
'.xyz', this%namespace, action=
'read', position=
'rewind')
1296 read(iunit,
'(i4)') this%natoms
1297 if (
present(comment))
then
1304 do iatom = 1, this%natoms
1307 read(iunit,
'(A)', iostat=ios) line
1309 call io_close(iunit)
1310 message(1) =
"Error reading XYZ atom line"
1311 call messages_fatal(1, namespace=this%namespace)
1315 if (len_trim(line) < label_len)
then
1316 call io_close(iunit)
1317 message(1) =
"XYZ file: atom line too short for label"
1318 call messages_fatal(1, namespace=this%namespace)
1320 label = line(1:label_len)
1323 if (len(line) > label_len)
then
1324 coordstr = adjustl(line(label_len+1:))
1326 call io_close(iunit)
1327 message(1) =
"XYZ file: no coordinate data after label"
1328 call messages_fatal(1, namespace=this%namespace)
1332 read(coordstr, *, iostat=ios) (tmp(idir), idir=1, this%space%dim)
1334 call io_close(iunit)
1335 message(1) =
"XYZ file: malformed coordinate fields"
1336 call messages_fatal(1, namespace=this%namespace)
1340 this%pos(:, iatom) = units_to_atomic(units_out%length_xyz_file, tmp)
1344 call io_close(iunit)
1353 class(
ions_t),
intent(in) :: this
1354 character(len=*),
intent(in) :: dir
1356 type(lattice_iterator_t) :: latt_iter
1357 real(real64) :: radius, pos(this%space%dim)
1358 integer :: iatom, icopy, iunit
1362 radius = maxval(m_half*norm2(this%latt%rlattice(:,1:this%space%periodic_dim), dim=1))*(m_one + m_epsilon)
1363 latt_iter = lattice_iterator_t(this%latt, radius)
1365 if (this%grp%is_root())
then
1367 iunit = io_open(trim(dir)//
'/crystal.xyz', this%namespace, action=
'write')
1369 write(iunit,
'(i9)') this%natoms*latt_iter%n_cells
1370 write(iunit,
'(a)')
'#generated by Octopus'
1372 do iatom = 1, this%natoms
1373 do icopy = 1, latt_iter%n_cells
1374 pos = units_from_atomic(units_out%length, this%pos(:, iatom) + latt_iter%get(icopy))
1375 write(iunit,
'(a, 99f12.6)') this%atom(iatom)%label, pos
1379 call io_close(iunit)
1387 class(
ions_t),
intent(in) :: this
1388 character(len=*),
intent(in) :: dir, fname
1390 integer :: iunit, iatom, idir
1391 real(real64) :: force(this%space%dim), center(this%space%dim)
1392 character(len=20) frmt
1394 if (.not. this%grp%is_root())
return
1398 call io_mkdir(dir, this%namespace)
1399 iunit = io_open(trim(dir)//
'/'//trim(fname)//
'.bild', this%namespace, action=
'write', &
1402 write(frmt,
'(a,i0,a)')
'(a,2(', this%space%dim,
'f16.6,1x))'
1404 write(iunit,
'(a)')
'.comment : force vectors in ['//trim(units_abbrev(units_out%force))//
']'
1406 write(iunit,
'(a)')
'.color red'
1408 do iatom = 1, this%natoms
1409 center = units_from_atomic(units_out%length, this%pos(:, iatom))
1410 force = units_from_atomic(units_out%force, this%tot_force(:, iatom))
1411 write(iunit,
'(a,1x,i4,1x,a2,1x,a6,1x,f10.6,a)')
'.comment :', iatom, trim(this%atom(iatom)%label), &
1412 'force:', norm2(force),
'['//trim(units_abbrev(units_out%force))//
']'
1413 write(iunit,fmt=trim(frmt))
'.arrow', (center(idir), idir = 1, this%space%dim), &
1414 (center(idir) + force(idir), idir = 1, this%space%dim)
1418 call io_close(iunit)
1425 class(
ions_t),
intent(in) :: this
1426 character(len=*),
intent(in) :: filename
1427 logical,
optional,
intent(in) :: ascii
1429 integer :: iunit, iatom, ierr
1431 real(real64),
allocatable :: data(:, :)
1432 integer,
allocatable :: idata(:, :)
1433 character(len=MAX_PATH_LEN) :: fullname
1437 assert(this%space%dim == 3)
1439 ascii_ = optional_default(ascii, .
true.)
1441 fullname = trim(filename)//
".vtk"
1443 iunit = io_open(trim(fullname), this%namespace, action=
'write')
1445 write(iunit,
'(1a)')
'# vtk DataFile Version 3.0 '
1446 write(iunit,
'(6a)')
'Generated by octopus ', trim(conf%version),
' - git: ', &
1447 trim(conf%git_commit),
" configuration: ", trim(conf%config_time)
1450 write(iunit,
'(1a)')
'ASCII'
1452 write(iunit,
'(1a)')
'BINARY'
1455 write(iunit,
'(1a)')
'DATASET POLYDATA'
1457 write(iunit,
'(a,i9,a)')
'POINTS ', this%natoms,
' double'
1460 do iatom = 1, this%natoms
1461 write(iunit,
'(3f12.6)') this%pos(1:3, iatom)
1464 call io_close(iunit)
1465 safe_allocate(
data(1:3, 1:this%natoms))
1466 do iatom = 1, this%natoms
1467 data(1:3, iatom) = this%pos(1:3, iatom)
1469 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(3*this%natoms),
data, &
1470 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1471 safe_deallocate_a(data)
1472 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1473 write(iunit,
'(1a)')
''
1476 write(iunit,
'(a,2i9)')
'VERTICES ', this%natoms, 2*this%natoms
1479 do iatom = 1, this%natoms
1480 write(iunit,
'(2i9)') 1, iatom - 1
1483 call io_close(iunit)
1484 safe_allocate(idata(1:2, 1:this%natoms))
1485 do iatom = 1, this%natoms
1487 idata(2, iatom) = iatom - 1
1489 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(2*this%natoms), idata, &
1490 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1491 safe_deallocate_a(idata)
1492 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1493 write(iunit,
'(1a)')
''
1496 write(iunit,
'(a,i9)')
'POINT_DATA', this%natoms
1497 write(iunit,
'(a)')
'SCALARS element integer'
1498 write(iunit,
'(a)')
'LOOKUP_TABLE default'
1501 do iatom = 1, this%natoms
1502 write(iunit,
'(i9)') nint(this%atom(iatom)%species%get_z())
1505 call io_close(iunit)
1507 safe_allocate(idata(1:this%natoms, 1))
1509 do iatom = 1, this%natoms
1510 idata(iatom, 1) = nint(this%atom(iatom)%species%get_z())
1513 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(this%natoms), idata, &
1514 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1516 safe_deallocate_a(idata)
1518 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1519 write(iunit,
'(1a)')
''
1522 call io_close(iunit)
1529 class(
ions_t),
intent(in) :: this
1530 real(real64) :: current(this%space%dim)
1537 do iatom = this%atoms_dist%start, this%atoms_dist%end
1538 current = current + p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom)
1541 if (this%atoms_dist%parallel)
then
1542 call comm_allreduce(this%atoms_dist%mpi_grp, current, dim=this%space%dim)
1550 class(
ions_t),
intent(in) :: this
1551 real(real64) :: abs_current(this%space%dim)
1557 abs_current = m_zero
1558 do iatom = this%atoms_dist%start, this%atoms_dist%end
1559 abs_current = abs_current + abs(p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom))
1562 if (this%atoms_dist%parallel)
then
1563 call comm_allreduce(this%atoms_dist%mpi_grp, abs_current, dim=this%space%dim)
1571 type(
ions_t),
intent(inout) :: ions
1577 call distributed_end(ions%atoms_dist)
1579 call ion_interaction_end(ions%ion_interaction)
1581 safe_deallocate_a(ions%atom)
1584 if(
allocated(ions%species))
then
1585 do i = 1, ions%nspecies
1587 if(
associated(ions%species(i)%s))
deallocate(ions%species(i)%s)
1589 deallocate(ions%species)
1593 safe_deallocate_a(ions%pos_displacements)
1594 safe_deallocate_a(ions%vel_displacements)
1596 call charged_particles_end(ions)
1598 safe_deallocate_a(ions%map_symm_atoms)
1599 safe_deallocate_a(ions%inv_map_symm_atoms)
1609 class(
ions_t),
intent(inout) :: ions
1610 type(lattice_vectors_t),
intent(in) :: latt
1611 logical,
intent(in) :: symmetrize
1616 call ions%latt%update(latt%rlattice)
1619 if (symmetrize)
then
1620 call symmetries_update_lattice_vectors(ions%symm, latt, ions%space%dim)
1633 class(
ions_t),
intent(inout) :: ions
1635 integer :: iatom, iop, iatom_symm, dim4symms
1636 real(real64) :: ratom(ions%space%dim)
1640 safe_allocate(ions%map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1641 safe_allocate(ions%inv_map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1644 dim4symms = min(3, ions%space%dim)
1647 do iop = 1, ions%symm%nops
1648 do iatom = 1, ions%natoms
1650 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom))
1652 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1655 do iatom_symm = 1, ions%natoms
1656 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec))
exit
1659 if (iatom_symm > ions%natoms)
then
1660 write(message(1),
'(a,i6)')
'Internal error: could not find symmetric partner for atom number', iatom
1661 write(message(2),
'(a,i3,a)')
'with symmetry operation number ', iop,
'.'
1662 call messages_fatal(2, namespace=ions%namespace)
1665 ions%map_symm_atoms(iatom, iop) = iatom_symm
1666 ions%inv_map_symm_atoms(iatom_symm, iop) = iatom
1671 do iop = 1, ions%symm%nops_nonsymmorphic
1672 do iatom = 1, ions%natoms
1674 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom))
1676 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1679 do iatom_symm = 1, ions%natoms
1680 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec))
exit
1683 if (iatom_symm > ions%natoms)
then
1684 write(message(1),
'(a,i6)')
'Internal error: could not find symmetric partner for atom number', iatom
1685 write(message(2),
'(a,i3,a)')
'with symmetry operation number ', iop,
'.'
1686 call messages_fatal(2, namespace=ions%namespace)
1689 ions%map_symm_atoms(iatom, ions%symm%nops+iop) = iatom_symm
1690 ions%inv_map_symm_atoms(iatom_symm, ions%symm%nops+iop) = iatom
1705 integer :: iatom, iop, iatom_sym
1706 real(real64) :: ratom(ions%space%dim)
1707 real(real64),
allocatable :: new_pos(:,:)
1711 safe_allocate(new_pos(1:ions%space%dim, 1:ions%natoms))
1713 do iatom = 1, ions%natoms
1714 new_pos(:, iatom) = m_zero
1717 do iop = 1, ions%symm%nops
1718 iatom_sym = ions%inv_map_symm_atoms(iatom, iop)
1719 ratom = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom_sym))
1720 ratom = ions%latt%fold_into_cell(ratom)
1721 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1725 do iop = 1, ions%symm%nops_nonsymmorphic
1726 iatom_sym = ions%inv_map_symm_atoms(iatom, iop + ions%symm%nops)
1727 ratom = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom_sym))
1728 ratom = ions%latt%fold_into_cell(ratom)
1729 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1732 new_pos(:, iatom) = new_pos(:, iatom) / (ions%symm%nops + ions%symm%nops_nonsymmorphic)
1742 class(
ions_t),
intent(inout) :: ions
1744 type(spglibdataset) :: spg_dataset
1745 character(len=11) :: symbol
1746 integer,
allocatable :: site_type(:)
1747 integer :: space_group, ia
1749 if(.not. ions%space%is_periodic())
return
1753 safe_allocate(site_type(1:ions%natoms))
1754 do ia = 1, ions%natoms
1755 site_type(ia) = ions%atom(ia)%species%get_index()
1758 spg_dataset = symmetries_get_spg_dataset(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type)
1760 safe_deallocate_a(site_type)
1762 if (spg_dataset%spglib_error /= 0)
then
1767 space_group = spg_dataset%spacegroup_number
1768 symbol = spg_dataset%international_symbol
1770 write(message(1),
'(a, i4)')
'Info: Space group No. ', space_group
1771 write(message(2),
'(2a)')
'Info: International: ', trim(symbol)
1772 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 ...