37 use,
intrinsic :: iso_fortran_env
72 type(lattice_vectors_t) :: latt
75 type(atom_t),
allocatable :: atom(:)
77 type(symmetries_t) :: symm
79 type(distributed_t) :: atoms_dist
81 integer,
allocatable :: map_symm_atoms(:,:)
82 integer,
allocatable :: inv_map_symm_atoms(:,:)
84 real(real64),
allocatable :: equilibrium_pos(:,:)
90 real(real64),
allocatable :: pos_displacements(:,:)
91 real(real64),
allocatable :: vel_displacements(:,:)
95 class(species_wrapper_t),
allocatable :: species(:)
96 logical :: only_user_def
97 logical,
private :: species_time_dependent
99 logical :: force_total_enforce
100 type(ion_interaction_t) :: ion_interaction
103 logical,
private :: apply_global_force
104 type(tdf_t),
private :: global_force_function
107 generic ::
assignment(=) => copy
140 procedure ions_constructor
146 function ions_constructor(namespace, grp, print_info, latt_inp)
result(ions)
147 type(namespace_t),
intent(in) :: namespace
148 type(mpi_grp_t),
optional,
intent(in) :: grp
149 logical,
optional,
intent(in) :: print_info
150 type(lattice_vectors_t),
optional,
intent(out) :: latt_inp
151 class(ions_t),
pointer :: ions
153 type(read_coords_info) :: xyz
154 integer :: ia, ierr, idir
155 character(len=100) :: function_name
156 real(real64) :: mindist
157 real(real64),
allocatable :: factor(:)
158 integer,
allocatable :: site_type(:)
159 logical,
allocatable :: spherical_site(:)
160 real(real64),
parameter :: threshold = 1e-5_real64
161 type(species_factory_t) :: factory
163 integer :: displacement_mode
164 real(real64) :: amp_pos, amp_vel
166 logical :: in_ensemble
172 ions%namespace = namespace
173 ions%space =
space_t(namespace)
177 if (
present(grp))
then
194 message(1) =
"Coordinates have not been defined."
203 safe_allocate(ions%atom(1:ions%natoms))
204 do ia = 1, ions%natoms
205 call atom_init(ions%atom(ia), ions%space%dim, xyz%atom(ia)%label)
206 ions%pos(:,ia) = xyz%atom(ia)%x(1:ions%space%dim)
208 ions%fixed(ia) = .not. xyz%atom(ia)%move
212 if (
allocated(xyz%latvec))
then
222 do ia = 1, ions%natoms
223 ions%pos(:, ia) = ions%latt%red_to_cart(ions%pos(:, ia))
230 safe_allocate_source_a(ions%equilibrium_pos, ions%pos)
235 do ia = 1, ions%natoms
236 ions%mass(ia) = ions%atom(ia)%species%get_mass()
237 ions%charge(ia) = ions%atom(ia)%species%get_zval()
251 call parse_variable(namespace,
'InitialDisplacementMode', 0, displacement_mode)
261 call parse_variable(namespace,
'InitialDisplacementAmplitudePos', 1.0_real64, amp_pos)
271 call parse_variable(namespace,
'InitialDisplacementAmplitudeVel', 1.0_real64, amp_vel)
273 if (displacement_mode>0)
then
275 message(1) =
"Random displacements are disabled when InitialDisplacementMode > 0."
278 safe_allocate(ions%pos_displacements(1:ions%space%dim, 1:ions%natoms))
279 safe_allocate(ions%vel_displacements(1:ions%space%dim, 1:ions%natoms))
281 call ions%single_mode_displacements(displacement_mode, amp_pos, amp_vel)
284 ions%pos = ions%pos + ions%pos_displacements
292 if(in_ensemble .and. displacement_mode==0)
then
301 call parse_variable(namespace,
'EnsembleTemperature', 0.0_real64, t)
303 safe_allocate(ions%pos_displacements(1:ions%space%dim, 1:ions%natoms))
304 safe_allocate(ions%vel_displacements(1:ions%space%dim, 1:ions%natoms))
305 call ions%init_random_displacements(t)
308 ions%pos = ions%pos + ions%pos_displacements
319 if (
present(latt_inp))
then
326 if (ions%space%has_mixed_periodicity())
then
327 safe_allocate(factor(ions%space%dim))
328 do idir = 1, ions%space%periodic_dim
331 do idir = ions%space%periodic_dim + 1, ions%space%dim
332 factor(idir) =
m_one/norm2(ions%latt%rlattice(1:ions%space%dim, idir))
334 call ions%latt%scale(factor)
335 safe_deallocate_a(factor)
339 if (ions%natoms > 1)
then
341 if (mindist < threshold)
then
342 write(
message(1),
'(a)')
"Some of the atoms seem to sit too close to each other."
343 write(
message(2),
'(a)')
"Please review your input files and the output geometry (in 'static/')."
344 write(
message(3),
'(a, f12.6, 1x, a)')
"Minimum distance = ", &
350 call ions%write_xyz(trim(
static_dir)//
'/geometry')
354 message(1) =
"It cannot be correct to run with physical atoms so close."
360 safe_allocate(spherical_site(1:ions%natoms))
361 safe_allocate(site_type(1:ions%natoms))
362 do ia = 1, ions%natoms
363 select type(spec => ions%atom(ia)%species)
365 spherical_site(ia) = .false.
367 spherical_site(ia) = .false.
369 spherical_site(ia) = .false.
371 spherical_site(ia) = .false.
373 spherical_site(ia) = .
true.
376 site_type(ia) = ions%atom(ia)%species%get_index()
379 ions%symm =
symmetries_t(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type, spherical_site)
381 safe_deallocate_a(spherical_site)
382 safe_deallocate_a(site_type)
385 call ions%generate_mapping_symmetric_atoms()
397 call parse_variable(namespace,
'ForceTotalEnforce', .false., ions%force_total_enforce)
413 ions%apply_global_force = .
true.
415 call parse_variable(namespace,
'TDGlobalForce',
'none', function_name)
416 call tdf_read(ions%global_force_function, namespace, trim(function_name), ierr)
419 call messages_write(
"You have enabled the GlobalForce option but Octopus could not find")
420 call messages_write(
"the '"//trim(function_name)//
"' function in the TDFunctions block.")
426 ions%apply_global_force = .false.
437 type(
ions_t),
intent(inout) :: ions
439 logical,
optional,
intent(in) :: print_info
441 logical :: print_info_, spec_user_defined
442 integer :: i, j, k, ispin
448 if (
present(print_info))
then
449 print_info_ = print_info
453 atoms1:
do i = 1, ions%natoms
457 ions%nspecies = ions%nspecies + 1
461 allocate(ions%species(1:ions%nspecies))
465 ions%only_user_def = .
true.
466 atoms2:
do i = 1, ions%natoms
471 ions%species(k)%s => factory%create_from_input(ions%namespace, ions%atom(j)%get_label(), k)
473 select type(spec => ions%species(k)%s)
477 ions%only_user_def = .false.
480 select type(spec => ions%species(k)%s)
482 if (ions%space%dim /= 3)
then
483 message(1) =
"Pseudopotentials may only be used with Dimensions = 3."
488 if (ions%space%is_periodic() .and. ions%space%periodic_dim /= 2)
then
489 message(1) =
"Periodic jelium slab can only be used if PeriodicDim = 2"
500 ispin = min(2, ispin)
502 if (print_info_)
then
505 do i = 1, ions%nspecies
506 spec => ions%species(i)%s
507 call spec%build(ions%namespace, ispin, ions%space%dim, print_info=print_info_)
509 if (print_info_)
then
522 call parse_variable(ions%namespace,
'SpeciesTimeDependent', .false., ions%species_time_dependent)
524 spec_user_defined = .false.
525 do i = 1,ions%nspecies
526 select type(spec=>ions%species(i)%s)
528 spec_user_defined = .
true.
531 if (ions%species_time_dependent .and. .not. spec_user_defined)
then
536 do i = 1, ions%natoms
537 do j = 1, ions%nspecies
550 class(
ions_t),
intent(out) :: ions_out
551 class(
ions_t),
intent(in) :: ions_in
557 ions_out%latt = ions_in%latt
559 ions_out%natoms = ions_in%natoms
560 safe_allocate(ions_out%atom(1:ions_out%natoms))
561 ions_out%atom = ions_in%atom
563 ions_out%nspecies = ions_in%nspecies
564 allocate(ions_out%species(1:ions_out%nspecies))
565 ions_out%species = ions_in%species
567 ions_out%only_user_def = ions_in%only_user_def
571 safe_allocate(ions_out%map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops + ions_in%symm%nops_nonsymmorphic))
572 ions_out%map_symm_atoms = ions_in%map_symm_atoms
573 safe_allocate(ions_out%inv_map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops + ions_in%symm%nops_nonsymmorphic))
574 ions_out%inv_map_symm_atoms = ions_in%inv_map_symm_atoms
582 class(
ions_t),
intent(inout) :: this
598 class(
ions_t),
target,
intent(inout) :: this
603 select type (interaction)
621 class(
ions_t),
intent(inout) :: ions
622 real(real64),
intent(in) :: T
625 integer(int64) :: seed
630 real(real64),
allocatable :: sigmaP(:)
631 real(real64),
allocatable :: muP(:)
632 real(real64),
allocatable :: sigmaQ(:)
633 real(real64),
allocatable :: muQ(:)
634 real(real64),
allocatable :: genP(:)
635 real(real64),
allocatable :: genQ(:)
638 real(real64) :: beta_half
639 real(real64),
allocatable :: pos_displacements(:), vel_displacements(:)
640 real(real64),
allocatable :: l_m(:), prefactor(:)
642 integer :: imode, idim, iatom, i, iline
643 integer :: num_real_modes
645 real(real64),
parameter :: low_temperature_tolerance = 1.0e-6_real64
651 seed = ions%namespace%get_hash32()
653 message(1) =
"Create initial random displacements for ions."
656 write(
message(1),
'("namespace = ",A)') ions%namespace%get()
657 write(
message(2),
'("seed = ",I0)') seed
662 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
664 num_real_modes = phonons%num_modes
666 if (num_real_modes == 0)
then
668 ions%pos_displacements =
m_zero
669 ions%vel_displacements =
m_zero
677 call wigner%init(num_real_modes, seed)
680 safe_allocate(sigmap(1:num_real_modes))
681 safe_allocate(sigmaq(1:num_real_modes))
682 safe_allocate(mup(1:num_real_modes))
683 safe_allocate(muq(1:num_real_modes))
684 safe_allocate(genp(1:num_real_modes))
685 safe_allocate(genq(1:num_real_modes))
687 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
688 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
689 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
691 safe_allocate(l_m(1:num_real_modes))
694 if (t < low_temperature_tolerance)
then
696 sigmap = 1.0_real64/2.0_real64
697 sigmaq = 1.0_real64/2.0_real64
700 sigmap = 1.0_real64/
sqrt((2.0_real64 *
tanh(beta_half * phonons%frequencies)))
701 sigmaq = 1.0_real64/
sqrt((2.0_real64 *
tanh(beta_half * phonons%frequencies)))
706 l_m =
sqrt(2.0_real64/(
unit_amu%factor * phonons%frequencies)) * phonons%alpha
709 do iatom = 1, ions%natoms
710 do idim = 1, ions%space%dim
711 prefactor(i) = 1.0_real64/
sqrt(ions%mass(iatom)/
unit_amu%factor * phonons%num_super)
717 genq = wigner%get(sigmaq, muq,
wigner_q) * l_m
722 ions%pos_displacements =
m_zero
723 ions%vel_displacements =
m_zero
727 do imode = 1, num_real_modes
729 pos_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genq(imode)
730 vel_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genp(imode)
733 write(
message(iline),
'("Displacements for mode ",I4)') imode
734 do iatom=1, ions%natoms
736 write(
message(iline),
'(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
739 write(
message(iline),
'("Velocities for mode ",I4)') imode
740 do iatom=1, ions%natoms
742 write(
message(iline),
'(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
747 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
748 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
752 safe_deallocate_a(sigmap)
753 safe_deallocate_a(sigmaq)
754 safe_deallocate_a(mup)
755 safe_deallocate_a(muq)
756 safe_deallocate_a(genp)
757 safe_deallocate_a(genq)
758 safe_deallocate_a(l_m)
760 safe_deallocate_a(prefactor)
761 safe_deallocate_a(pos_displacements)
762 safe_deallocate_a(vel_displacements)
774 class(
ions_t),
intent(inout) :: ions
775 integer,
intent(in) :: mode
776 real(real64),
optional,
intent(in) :: amplitude_pos
777 real(real64),
optional,
intent(in) :: amplitude_vel
780 integer :: num_real_modes, i, iatom, idim
781 real(real64) :: l_m, genP, genQ
783 real(real64),
allocatable :: pos_displacements(:), vel_displacements(:), prefactor(:)
788 write(
message(1),
'("Create displacements for mode ", I4)') mode
792 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
794 num_real_modes = phonons%num_modes
796 if (mode > num_real_modes)
then
797 write(
message(1),
'("Requested mode ",I0," exceeds number of available modes (",I0,")")') mode, num_real_modes
804 ions%pos_displacements =
m_zero
805 ions%vel_displacements =
m_zero
807 l_m =
sqrt(2.0_real64/(
unit_amu%factor * phonons%frequencies(mode))) * phonons%alpha(mode)
809 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
810 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
811 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
814 do iatom = 1, ions%natoms
815 do idim=1, ions%space%dim
816 prefactor(i) = 1.0_real64/
sqrt(ions%mass(iatom)/
unit_amu%factor * phonons%num_super)
822 genq = amplitude_pos * l_m
823 genp = amplitude_vel / (l_m *
unit_amu%factor)
825 pos_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genq
826 vel_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genp
828 write(
message(1),
'("Displacements for mode ",I4)') mode
830 do iatom=1, ions%natoms
831 write(
message(1),
'(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
834 write(
message(1),
'("Velocities for mode ",I4)') mode
836 do iatom=1, ions%natoms
837 write(
message(1),
'(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
842 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
843 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
845 safe_deallocate_a(pos_displacements)
846 safe_deallocate_a(vel_displacements)
847 safe_deallocate_a(prefactor)
855 class(
ions_t),
intent(inout) :: this
860 if(
allocated(this%vel_displacements))
then
861 this%vel = this%vel + this%vel_displacements
869 class(
ions_t),
intent(inout) :: this
870 character(len=*),
intent(in) :: label
885 class(
ions_t),
intent(in) :: partner
890 select type (interaction)
900 class(
ions_t),
intent(inout) :: partner
905 select type (interaction)
916 class(
ions_t),
intent(inout) :: this
922 do iatom = 1, this%natoms
923 this%pos(:, iatom) = this%latt%fold_into_cell(this%pos(:, iatom))
930 real(real64) function ions_min_distance(this, real_atoms_only) result(rmin)
931 class(
ions_t),
intent(in) :: this
932 logical,
optional,
intent(in) :: real_atoms_only
934 integer :: iatom, jatom, idir
935 real(real64) :: xx(this%space%dim)
936 logical :: real_atoms_only_
939 if (this%natoms == 1 .and. .not. this%space%is_periodic())
then
944 push_sub(ions_min_distance)
953 do iatom = 1, this%natoms
957 if (real_atoms_only_) cycle
959 do jatom = iatom + 1, this%natoms
963 if (real_atoms_only_) cycle
965 xx = abs(this%pos(:, iatom) - this%pos(:, jatom))
966 if (this%space%is_periodic())
then
967 xx = this%latt%cart_to_red(xx)
968 do idir = 1, this%space%periodic_dim
971 xx = this%latt%red_to_cart(xx)
973 rmin = min(norm2(xx), rmin)
977 if (.not. (this%only_user_def .and. real_atoms_only_))
then
979 do idir = 1, this%space%periodic_dim
980 rmin = min(rmin, norm2(this%latt%rlattice(:,idir)))
985 if(rmin < huge(rmin)/1e6_real64)
then
986 rmin = anint(rmin*1e6_real64)*1.0e-6_real64
989 pop_sub(ions_min_distance)
998 time_dependent = this%species_time_dependent
1004 real(real64) function ions_val_charge(this, mask) result(val_charge)
1005 class(
ions_t),
intent(in) :: this
1006 logical,
optional,
intent(in) :: mask(:)
1010 if (
present(mask))
then
1011 val_charge = -sum(this%charge, mask=mask)
1013 val_charge = -sum(this%charge)
1021 class(
ions_t),
intent(in) :: this
1022 logical,
optional,
intent(in) :: mask(:)
1023 real(real64) :: dipole(this%space%dim)
1030 do ia = 1, this%natoms
1031 if (
present(mask))
then
1032 if (.not. mask(ia)) cycle
1034 dipole = dipole + this%charge(ia)*this%pos(:, ia)
1036 dipole = p_proton_charge*dipole
1043 class(
ions_t),
intent(inout) :: this
1044 real(real64),
intent(in) :: xx(this%space%dim)
1050 do iatom = 1, this%natoms
1051 this%pos(:, iatom) = this%pos(:, iatom) - xx
1059 class(
ions_t),
intent(inout) :: this
1060 real(real64),
intent(in) :: from(this%space%dim)
1061 real(real64),
intent(in) :: from2(this%space%dim)
1062 real(real64),
intent(in) :: to(this%space%dim)
1065 real(real64) :: m1(3, 3), m2(3, 3)
1066 real(real64) :: m3(3, 3), f2(3), per(3)
1067 real(real64) :: alpha, r
1071 if (this%space%dim /= 3)
then
1072 call messages_not_implemented(
"ions_rotate in other than 3 dimensions", namespace=this%namespace)
1076 m1 = diagonal_matrix(3, m_one)
1079 if (abs(to(2)) > 1d-150)
then
1080 alpha =
atan2(to(2), to(1))
1081 call rotate(m1, alpha, 3)
1083 alpha =
atan2(norm2(to(1:2)), to(3))
1084 call rotate(m1, -alpha, 2)
1087 f2 = matmul(m1, from)
1092 if (r > m_zero)
then
1099 m2 = diagonal_matrix(3, m_one)
1100 alpha =
atan2(per(1), per(2))
1101 call rotate(m2, -alpha, 3)
1104 m3 = diagonal_matrix(3, m_one)
1105 alpha =
acos(min(sum(from*to), m_one))
1106 call rotate(m3, -alpha, 2)
1109 m2 = matmul(transpose(m2), matmul(m3, m2))
1112 per = matmul(m2, matmul(m1, from2))
1113 alpha =
atan2(per(1), per(2))
1114 call rotate(m2, -alpha, 3)
1117 m1 = matmul(transpose(m1), matmul(m2, m1))
1121 do iatom = 1, this%natoms
1122 f2 = this%pos(:, iatom)
1123 this%pos(:, iatom) = matmul(m1, f2)
1130 subroutine rotate(m, angle, dir)
1131 real(real64),
intent(inout) :: m(3, 3)
1132 real(real64),
intent(in) :: angle
1133 integer,
intent(in) :: dir
1135 real(real64) :: aux(3, 3), ca, sa
1173 class(
ions_t),
intent(in) :: this
1174 real(real64),
intent(in) :: time
1175 real(real64) :: force(this%space%dim)
1181 if (this%apply_global_force)
then
1182 force(1) = tdf(this%global_force_function, time)
1189 subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
1190 class(
ions_t),
intent(in) :: this
1191 character(len=*),
intent(in) :: fname
1192 logical,
optional,
intent(in) :: append
1193 character(len=*),
optional,
intent(in) :: comment
1194 logical,
optional,
intent(in) :: reduce_coordinates
1196 integer :: iatom, idim, iunit
1197 character(len=6) position
1198 character(len=19) :: frmt
1199 real(real64) :: red(this%space%dim)
1201 if (.not. this%grp%is_root())
return
1206 if (
present(append))
then
1207 if (append) position =
'append'
1209 if(.not.optional_default(reduce_coordinates, .false.))
then
1210 iunit = io_open(trim(fname)//
'.xyz', this%namespace, action=
'write', position=position)
1212 iunit = io_open(trim(fname)//
'.xyz_red', this%namespace, action=
'write', position=position)
1215 write(iunit,
'(i4)') this%natoms
1216 if (
present(comment))
then
1217 write(iunit,
'(1x,a)') comment
1219 write(iunit,
'(1x,a,a)')
'units: ', trim(units_abbrev(units_out%length_xyz_file))
1222 write(unit=frmt, fmt=
"(a5,i2.2,a4,i2.2,a6)")
"(6x,a", label_len,
",2x,", this%space%dim,
"f15.9)"
1223 do iatom = 1, this%natoms
1224 if(.not.optional_default(reduce_coordinates, .false.))
then
1225 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, &
1226 (units_from_atomic(units_out%length_xyz_file, this%pos(idim, iatom)), idim=1, this%space%dim)
1228 red = this%latt%cart_to_red(this%pos(:, iatom))
1229 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, (red(idim), idim=1, this%space%dim)
1232 call io_close(iunit)
1243 class(
ions_t),
intent(in) :: this
1244 character(len=*),
optional,
intent(in) :: fname
1245 character(len=*),
optional,
intent(in) :: comment
1247 integer :: iatom, idim, iunit
1248 character(len=:),
allocatable :: fname_, comment_
1249 character(len=10) :: format_string
1253 if (.not. this%grp%is_root())
then
1258 comment_ = optional_default(comment,
"")
1259 fname_ = optional_default(fname,
"POSCAR")
1261 iunit = io_open(trim(fname_), this%namespace, action=
'write')
1263 write(iunit,
'(A)') comment_
1264 write(iunit,
'("1.0")')
1266 write(format_string,
'("(",I1,A,")")') this%space%dim,
'F15.10'
1267 do idim=1, this%space%dim
1268 write(iunit, format_string) units_from_atomic(unit_angstrom, this%latt%rlattice(:,idim))
1271 do iatom = 1, this%natoms
1272 write(iunit,
'(A)', advance=
'NO') trim(this%atom(iatom)%label)//
" "
1274 write(iunit,
'("")')
1275 write(iunit,
'(A)') repeat(
"1 ", this%natoms)
1276 write(iunit,
'("direct")')
1277 write(format_string,
'("(",I1,A,")")') this%space%dim,
'F15.10'
1278 do iatom=1, this%natoms
1279 write(iunit, format_string) this%latt%cart_to_red(this%pos(:, iatom))
1282 call io_close(iunit)
1289 use iso_fortran_env,
only: real64
1290 class(
ions_t),
intent(inout) :: this
1291 character(len=*),
intent(in) :: fname
1292 character(len=*),
optional,
intent(in) :: comment
1294 integer :: iatom, idir, iunit, ios
1295 character(len=256) :: line
1296 character(len=LABEL_LEN) :: label
1297 character(len=:),
allocatable :: coordstr
1298 real(real64) :: tmp(this%space%dim)
1302 iunit = io_open(trim(fname)//
'.xyz', this%namespace, action=
'read', position=
'rewind')
1305 read(iunit,
'(i4)') this%natoms
1306 if (
present(comment))
then
1313 do iatom = 1, this%natoms
1316 read(iunit,
'(A)', iostat=ios) line
1318 call io_close(iunit)
1319 message(1) =
"Error reading XYZ atom line"
1320 call messages_fatal(1, namespace=this%namespace)
1324 if (len_trim(line) < label_len)
then
1325 call io_close(iunit)
1326 message(1) =
"XYZ file: atom line too short for label"
1327 call messages_fatal(1, namespace=this%namespace)
1329 label = line(1:label_len)
1332 if (len(line) > label_len)
then
1333 coordstr = adjustl(line(label_len+1:))
1335 call io_close(iunit)
1336 message(1) =
"XYZ file: no coordinate data after label"
1337 call messages_fatal(1, namespace=this%namespace)
1341 read(coordstr, *, iostat=ios) (tmp(idir), idir=1, this%space%dim)
1343 call io_close(iunit)
1344 message(1) =
"XYZ file: malformed coordinate fields"
1345 call messages_fatal(1, namespace=this%namespace)
1349 this%pos(:, iatom) = units_to_atomic(units_out%length_xyz_file, tmp)
1353 call io_close(iunit)
1362 class(
ions_t),
intent(in) :: this
1363 character(len=*),
intent(in) :: dir
1365 type(lattice_iterator_t) :: latt_iter
1366 real(real64) :: radius, pos(this%space%dim)
1367 integer :: iatom, icopy, iunit
1371 radius = maxval(m_half*norm2(this%latt%rlattice(:,1:this%space%periodic_dim), dim=1))*(m_one + m_epsilon)
1372 latt_iter = lattice_iterator_t(this%latt, radius)
1374 if (this%grp%is_root())
then
1376 iunit = io_open(trim(dir)//
'/crystal.xyz', this%namespace, action=
'write')
1378 write(iunit,
'(i9)') this%natoms*latt_iter%n_cells
1379 write(iunit,
'(a)')
'#generated by Octopus'
1381 do iatom = 1, this%natoms
1382 do icopy = 1, latt_iter%n_cells
1383 pos = units_from_atomic(units_out%length, this%pos(:, iatom) + latt_iter%get(icopy))
1384 write(iunit,
'(a, 99f12.6)') this%atom(iatom)%label, pos
1388 call io_close(iunit)
1396 class(
ions_t),
intent(in) :: this
1397 character(len=*),
intent(in) :: dir, fname
1399 integer :: iunit, iatom, idir
1400 real(real64) :: force(this%space%dim), center(this%space%dim)
1401 character(len=20) frmt
1403 if (.not. this%grp%is_root())
return
1407 call io_mkdir(dir, this%namespace)
1408 iunit = io_open(trim(dir)//
'/'//trim(fname)//
'.bild', this%namespace, action=
'write', &
1411 write(frmt,
'(a,i0,a)')
'(a,2(', this%space%dim,
'f16.6,1x))'
1413 write(iunit,
'(a)')
'.comment : force vectors in ['//trim(units_abbrev(units_out%force))//
']'
1415 write(iunit,
'(a)')
'.color red'
1417 do iatom = 1, this%natoms
1418 center = units_from_atomic(units_out%length, this%pos(:, iatom))
1419 force = units_from_atomic(units_out%force, this%tot_force(:, iatom))
1420 write(iunit,
'(a,1x,i4,1x,a2,1x,a6,1x,f10.6,a)')
'.comment :', iatom, trim(this%atom(iatom)%label), &
1421 'force:', norm2(force),
'['//trim(units_abbrev(units_out%force))//
']'
1422 write(iunit,fmt=trim(frmt))
'.arrow', (center(idir), idir = 1, this%space%dim), &
1423 (center(idir) + force(idir), idir = 1, this%space%dim)
1427 call io_close(iunit)
1434 class(
ions_t),
intent(in) :: this
1435 character(len=*),
intent(in) :: filename
1436 logical,
optional,
intent(in) :: ascii
1438 integer :: iunit, iatom, ierr
1440 real(real64),
allocatable :: data(:, :)
1441 integer,
allocatable :: idata(:, :)
1442 character(len=MAX_PATH_LEN) :: fullname
1446 assert(this%space%dim == 3)
1448 ascii_ = optional_default(ascii, .
true.)
1450 fullname = trim(filename)//
".vtk"
1452 iunit = io_open(trim(fullname), this%namespace, action=
'write')
1454 write(iunit,
'(1a)')
'# vtk DataFile Version 3.0 '
1455 write(iunit,
'(6a)')
'Generated by octopus ', trim(conf%version),
' - git: ', &
1456 trim(conf%git_commit),
" configuration: ", trim(conf%config_time)
1459 write(iunit,
'(1a)')
'ASCII'
1461 write(iunit,
'(1a)')
'BINARY'
1464 write(iunit,
'(1a)')
'DATASET POLYDATA'
1466 write(iunit,
'(a,i9,a)')
'POINTS ', this%natoms,
' double'
1469 do iatom = 1, this%natoms
1470 write(iunit,
'(3f12.6)') this%pos(1:3, iatom)
1473 call io_close(iunit)
1474 safe_allocate(
data(1:3, 1:this%natoms))
1475 do iatom = 1, this%natoms
1476 data(1:3, iatom) = this%pos(1:3, iatom)
1478 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(3*this%natoms),
data, &
1479 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1480 safe_deallocate_a(data)
1481 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1482 write(iunit,
'(1a)')
''
1485 write(iunit,
'(a,2i9)')
'VERTICES ', this%natoms, 2*this%natoms
1488 do iatom = 1, this%natoms
1489 write(iunit,
'(2i9)') 1, iatom - 1
1492 call io_close(iunit)
1493 safe_allocate(idata(1:2, 1:this%natoms))
1494 do iatom = 1, this%natoms
1496 idata(2, iatom) = iatom - 1
1498 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(2*this%natoms), idata, &
1499 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1500 safe_deallocate_a(idata)
1501 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1502 write(iunit,
'(1a)')
''
1505 write(iunit,
'(a,i9)')
'POINT_DATA', this%natoms
1506 write(iunit,
'(a)')
'SCALARS element integer'
1507 write(iunit,
'(a)')
'LOOKUP_TABLE default'
1510 do iatom = 1, this%natoms
1511 write(iunit,
'(i9)') nint(this%atom(iatom)%species%get_z())
1514 call io_close(iunit)
1516 safe_allocate(idata(1:this%natoms, 1))
1518 do iatom = 1, this%natoms
1519 idata(iatom, 1) = nint(this%atom(iatom)%species%get_z())
1522 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(this%natoms), idata, &
1523 ierr, nohead = .
true., fendian = io_binary_is_little_endian())
1525 safe_deallocate_a(idata)
1527 iunit = io_open(trim(fullname), this%namespace, action=
'write', position =
'append')
1528 write(iunit,
'(1a)')
''
1531 call io_close(iunit)
1538 class(
ions_t),
intent(in) :: this
1539 real(real64) :: current(this%space%dim)
1546 do iatom = this%atoms_dist%start, this%atoms_dist%end
1547 current = current + p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom)
1550 if (this%atoms_dist%parallel)
then
1551 call comm_allreduce(this%atoms_dist%mpi_grp, current, dim=this%space%dim)
1559 class(
ions_t),
intent(in) :: this
1560 real(real64) :: abs_current(this%space%dim)
1566 abs_current = m_zero
1567 do iatom = this%atoms_dist%start, this%atoms_dist%end
1568 abs_current = abs_current + abs(p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom))
1571 if (this%atoms_dist%parallel)
then
1572 call comm_allreduce(this%atoms_dist%mpi_grp, abs_current, dim=this%space%dim)
1580 type(
ions_t),
intent(inout) :: ions
1586 call distributed_end(ions%atoms_dist)
1588 call ion_interaction_end(ions%ion_interaction)
1590 safe_deallocate_a(ions%atom)
1593 if(
allocated(ions%species))
then
1594 do i = 1, ions%nspecies
1596 if(
associated(ions%species(i)%s))
deallocate(ions%species(i)%s)
1598 deallocate(ions%species)
1602 safe_deallocate_a(ions%pos_displacements)
1603 safe_deallocate_a(ions%vel_displacements)
1605 call charged_particles_end(ions)
1607 safe_deallocate_a(ions%map_symm_atoms)
1608 safe_deallocate_a(ions%inv_map_symm_atoms)
1618 class(
ions_t),
intent(inout) :: ions
1619 type(lattice_vectors_t),
intent(in) :: latt
1620 logical,
intent(in) :: symmetrize
1625 call ions%latt%update(latt%rlattice)
1628 if (symmetrize)
then
1629 call symmetries_update_lattice_vectors(ions%symm, latt, ions%space%dim)
1642 class(
ions_t),
intent(inout) :: ions
1644 integer :: iatom, iop, iatom_symm, dim4symms
1645 real(real64) :: ratom(ions%space%dim)
1649 safe_allocate(ions%map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1650 safe_allocate(ions%inv_map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1653 dim4symms = min(3, ions%space%dim)
1656 do iop = 1, ions%symm%nops
1657 do iatom = 1, ions%natoms
1659 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom))
1661 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1664 do iatom_symm = 1, ions%natoms
1665 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec))
exit
1668 if (iatom_symm > ions%natoms)
then
1669 write(message(1),
'(a,i6)')
'Internal error: could not find symmetric partner for atom number', iatom
1670 write(message(2),
'(a,i3,a)')
'with symmetry operation number ', iop,
'.'
1671 call messages_fatal(2, namespace=ions%namespace)
1674 ions%map_symm_atoms(iatom, iop) = iatom_symm
1675 ions%inv_map_symm_atoms(iatom_symm, iop) = iatom
1680 do iop = 1, ions%symm%nops_nonsymmorphic
1681 do iatom = 1, ions%natoms
1683 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom))
1685 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1688 do iatom_symm = 1, ions%natoms
1689 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec))
exit
1692 if (iatom_symm > ions%natoms)
then
1693 write(message(1),
'(a,i6)')
'Internal error: could not find symmetric partner for atom number', iatom
1694 write(message(2),
'(a,i3,a)')
'with symmetry operation number ', iop,
'.'
1695 call messages_fatal(2, namespace=ions%namespace)
1698 ions%map_symm_atoms(iatom, ions%symm%nops+iop) = iatom_symm
1699 ions%inv_map_symm_atoms(iatom_symm, ions%symm%nops+iop) = iatom
1714 integer :: iatom, iop, iatom_sym
1715 real(real64) :: ratom(ions%space%dim)
1716 real(real64),
allocatable :: new_pos(:,:)
1720 safe_allocate(new_pos(1:ions%space%dim, 1:ions%natoms))
1722 do iatom = 1, ions%natoms
1723 new_pos(:, iatom) = m_zero
1726 do iop = 1, ions%symm%nops
1727 iatom_sym = ions%inv_map_symm_atoms(iatom, iop)
1728 ratom = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom_sym))
1729 ratom = ions%latt%fold_into_cell(ratom)
1730 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1734 do iop = 1, ions%symm%nops_nonsymmorphic
1735 iatom_sym = ions%inv_map_symm_atoms(iatom, iop + ions%symm%nops)
1736 ratom = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom_sym))
1737 ratom = ions%latt%fold_into_cell(ratom)
1738 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1741 new_pos(:, iatom) = new_pos(:, iatom) / (ions%symm%nops + ions%symm%nops_nonsymmorphic)
1751 class(
ions_t),
intent(inout) :: ions
1753 type(spglibdataset) :: spg_dataset
1754 character(len=11) :: symbol
1755 integer,
allocatable :: site_type(:)
1756 integer :: space_group, ia
1758 if(.not. ions%space%is_periodic())
return
1762 safe_allocate(site_type(1:ions%natoms))
1763 do ia = 1, ions%natoms
1764 site_type(ia) = ions%atom(ia)%species%get_index()
1767 spg_dataset = symmetries_get_spg_dataset(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type)
1769 safe_deallocate_a(site_type)
1771 if (spg_dataset%spglib_error /= 0)
then
1776 space_group = spg_dataset%spacegroup_number
1777 symbol = spg_dataset%international_symbol
1779 write(message(1),
'(a, i4)')
'Info: Space group No. ', space_group
1780 write(message(2),
'(2a)')
'Info: International: ', trim(symbol)
1781 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)
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.
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)
class(ions_t) function, pointer ions_constructor(namespace, grp, print_info, latt_inp)
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)
type(mpi_grp_t), public mpi_world
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)
This module implements the abstract system type.
subroutine, public system_init_parallelization(this, grp)
Basic functionality: copy the MPI group. This function needs to be implemented by extended types that...
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 ...