Octopus
ions.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2021 M. Oliveira
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
22module ions_oct_m
23 use atom_oct_m
26 use iso_c_binding
27 use debug_oct_m
29 use global_oct_m
33 use io_oct_m
35 use, intrinsic :: iso_fortran_env
38 use math_oct_m
41 use mpi_oct_m
43 use parser_oct_m
47 use space_oct_m
53 use unit_oct_m
56
57 implicit none
58
59 private
60 public :: ions_t
61
62 type, extends(charged_particles_t) :: ions_t
63 ! Components are public by default
64
65 type(lattice_vectors_t) :: latt
66
67 integer :: natoms
68 type(atom_t), allocatable :: atom(:)
69
70 type(symmetries_t) :: symm
71
72 type(distributed_t) :: atoms_dist
73
74 integer, allocatable :: map_symm_atoms(:,:)
75 integer, allocatable :: inv_map_symm_atoms(:,:)
76
77
79 integer :: nspecies
80 class(species_wrapper_t), allocatable :: species(:)
81 logical :: only_user_def
82 logical, private :: species_time_dependent
83
84 logical :: force_total_enforce
85 type(ion_interaction_t) :: ion_interaction
86
88 logical, private :: apply_global_force
89 type(tdf_t), private :: global_force_function
90 contains
91 procedure :: copy => ions_copy
92 generic :: assignment(=) => copy
93 procedure :: partition => ions_partition
94 procedure :: init_interaction => ions_init_interaction
95 procedure :: initial_conditions => ions_initial_conditions
96 procedure :: update_quantity => ions_update_quantity
97 procedure :: init_interaction_as_partner => ions_init_interaction_as_partner
98 procedure :: copy_quantities_to_interaction => ions_copy_quantities_to_interaction
99 procedure :: fold_atoms_into_cell => ions_fold_atoms_into_cell
100 procedure :: min_distance => ions_min_distance
101 procedure :: has_time_dependent_species => ions_has_time_dependent_species
102 procedure :: val_charge => ions_val_charge
103 procedure :: dipole => ions_dipole
104 procedure :: translate => ions_translate
105 procedure :: rotate => ions_rotate
106 procedure :: global_force => ions_global_force
107 procedure :: write_xyz => ions_write_xyz
108 procedure :: read_xyz => ions_read_xyz
109 procedure :: write_crystal => ions_write_crystal
110 procedure :: write_bild_forces_file => ions_write_bild_forces_file
111 procedure :: write_vtk_geometry => ions_write_vtk_geometry
112 procedure :: update_lattice_vectors => ions_update_lattice_vectors
113 procedure :: symmetrize_atomic_coord => ions_symmetrize_atomic_coord
114 procedure :: generate_mapping_symmetric_atoms => ions_generate_mapping_symmetric_atoms
116 end type ions_t
117
118 interface ions_t
119 procedure ions_constructor
120 end interface ions_t
121
122contains
123
124 ! ---------------------------------------------------------
125 function ions_constructor(namespace, print_info, latt_inp) result(ions)
126 type(namespace_t), intent(in) :: namespace
127 logical, optional, intent(in) :: print_info
128 type(lattice_vectors_t), optional, intent(out) :: latt_inp
129 class(ions_t), pointer :: ions
130
131 type(read_coords_info) :: xyz
132 integer :: ia, ierr, idir
133 character(len=100) :: function_name
134 real(real64) :: mindist
135 real(real64), allocatable :: factor(:)
136 integer, allocatable :: site_type(:)
137 logical, allocatable :: spherical_site(:)
138 real(real64), parameter :: threshold = 1e-5_real64
139 type(species_factory_t) :: factory
140
141 push_sub(ions_constructor)
142
143 allocate(ions)
144
145 ions%namespace = namespace
146
147 ions%space = space_t(namespace)
148
149 call species_factory_init(factory, namespace)
150
151 ! initialize geometry
152 call read_coords_init(xyz)
153
154 ! load positions of the atoms
155 call read_coords_read('Coordinates', xyz, ions%space, namespace)
156
157 if (xyz%n < 1) then
158 message(1) = "Coordinates have not been defined."
159 call messages_fatal(1, namespace=namespace)
160 end if
162 ! Initialize parent class
163 call charged_particles_init(ions, xyz%n)
164
165 ! copy information from xyz to ions
166 ions%natoms = xyz%n
167 safe_allocate(ions%atom(1:ions%natoms))
168 do ia = 1, ions%natoms
169 call atom_init(ions%atom(ia), ions%space%dim, xyz%atom(ia)%label)
170 ions%pos(:,ia) = xyz%atom(ia)%x(1:ions%space%dim)
171 if (bitand(xyz%flags, xyz_flags_move) /= 0) then
172 ions%fixed(ia) = .not. xyz%atom(ia)%move
173 end if
174 end do
176 if (allocated(xyz%latvec)) then
177 ! Build lattice vectors from the XSF input
178 ions%latt = lattice_vectors_t(namespace, ions%space, xyz%latvec)
179 else
180 ! Build lattice vectors from input file
181 ions%latt = lattice_vectors_t(namespace, ions%space)
182 end if
183
184 ! Convert coordinates to Cartesian in case we have reduced coordinates
185 if (xyz%source == read_coords_reduced) then
186 do ia = 1, ions%natoms
187 ions%pos(:, ia) = ions%latt%red_to_cart(ions%pos(:, ia))
188 end do
189 end if
194 call ions_init_species(ions, factory, print_info=print_info)
195 call distributed_nullify(ions%atoms_dist, ions%natoms)
197 call messages_obsolete_variable(namespace, 'PDBClassical')
199 if (present(latt_inp)) then
200 ! The lattice as read from the input might be needed by some other part of the code, so we save it
201 latt_inp = ions%latt
202 end if
204 ! Now that we have processed the atomic coordinates, we renormalize the
205 ! lattice parameters along the non-periodic dimensions
206 if (ions%space%has_mixed_periodicity()) then
207 safe_allocate(factor(ions%space%dim))
208 do idir = 1, ions%space%periodic_dim
209 factor(idir) = m_one
210 end do
211 do idir = ions%space%periodic_dim + 1, ions%space%dim
212 factor(idir) = m_one/norm2(ions%latt%rlattice(1:ions%space%dim, idir))
213 end do
214 call ions%latt%scale(factor)
215 safe_deallocate_a(factor)
216 end if
217
218 ! Set the masses and charges. This needs to be done after initializing the species.
219 do ia = 1, ions%natoms
220 ions%mass(ia) = ions%atom(ia)%species%get_mass()
221 ions%charge(ia) = ions%atom(ia)%species%get_zval()
222 end do
223
224 ! Check that atoms are not too close
225 if (ions%natoms > 1) then
226 mindist = ions_min_distance(ions, real_atoms_only = .false.)
227 if (mindist < threshold) then
228 write(message(1), '(a)') "Some of the atoms seem to sit too close to each other."
229 write(message(2), '(a)') "Please review your input files and the output geometry (in 'static/')."
230 write(message(3), '(a, f12.6, 1x, a)') "Minimum distance = ", &
231 units_from_atomic(units_out%length, mindist), trim(units_abbrev(units_out%length))
232 call messages_warning(3, namespace=namespace)
233
234 ! then write out the geometry, whether asked for or not in Output variable
235 call io_mkdir(static_dir, namespace)
236 call ions%write_xyz(trim(static_dir)//'/geometry')
237 end if
238
239 if (ions_min_distance(ions, real_atoms_only = .true.) < threshold) then
240 message(1) = "It cannot be correct to run with physical atoms so close."
241 call messages_fatal(1, namespace=namespace)
242 end if
243 end if
244
245 !Initialize symmetries
246 safe_allocate(spherical_site(1:ions%natoms))
247 safe_allocate(site_type(1:ions%natoms))
248 do ia = 1, ions%natoms
249 select type(spec => ions%atom(ia)%species)
250 type is(jellium_slab_t)
251 spherical_site(ia) = .false.
253 spherical_site(ia) = .false.
254 type is(species_from_file_t)
255 spherical_site(ia) = .false.
257 spherical_site(ia) = .false.
258 class default
259 spherical_site(ia) = .true.
260 end select
261
262 site_type(ia) = ions%atom(ia)%species%get_index()
263 end do
264
265 ions%symm = symmetries_t(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type, spherical_site)
266
267 safe_deallocate_a(spherical_site)
268 safe_deallocate_a(site_type)
269
270 ! Generate the mapping of symmetric atoms
271 call ions%generate_mapping_symmetric_atoms()
272
273 call ion_interaction_init(ions%ion_interaction, namespace, ions%space, ions%natoms)
274
275 !%Variable ForceTotalEnforce
276 !%Type logical
277 !%Default no
278 !%Section Hamiltonian
279 !%Description
280 !% (Experimental) If this variable is set to "yes", then the sum
281 !% of the total forces will be enforced to be zero.
282 !%End
283 call parse_variable(namespace, 'ForceTotalEnforce', .false., ions%force_total_enforce)
284 if (ions%force_total_enforce) call messages_experimental('ForceTotalEnforce', namespace=namespace)
285
286 !%Variable TDGlobalForce
287 !%Type string
288 !%Section Time-Dependent
289 !%Description
290 !% If this variable is set, a global time-dependent force will be
291 !% applied to the ions in the x direction during a time-dependent
292 !% run. This variable defines the base name of the force, that
293 !% should be defined in the <tt>TDFunctions</tt> block. This force
294 !% does not affect the electrons directly.
295 !%End
296
297 if (parse_is_defined(namespace, 'TDGlobalForce')) then
298
299 ions%apply_global_force = .true.
300
301 call parse_variable(namespace, 'TDGlobalForce', 'none', function_name)
302 call tdf_read(ions%global_force_function, namespace, trim(function_name), ierr)
303
304 if (ierr /= 0) then
305 call messages_write("You have enabled the GlobalForce option but Octopus could not find")
306 call messages_write("the '"//trim(function_name)//"' function in the TDFunctions block.")
307 call messages_fatal(namespace=namespace)
308 end if
309
310 else
311
312 ions%apply_global_force = .false.
313
314 end if
315
316 call species_factory_end(factory)
317
318 pop_sub(ions_constructor)
319 end function ions_constructor
320
321 ! ---------------------------------------------------------
322 subroutine ions_init_species(ions, factory, print_info)
323 type(ions_t), intent(inout) :: ions
324 type(species_factory_t), intent(in) :: factory
325 logical, optional, intent(in) :: print_info
326
327 logical :: print_info_, spec_user_defined
328 integer :: i, j, k, ispin
329 class(species_t), pointer :: spec
330
331 push_sub(ions_init_species)
332
333 print_info_ = .true.
334 if (present(print_info)) then
335 print_info_ = print_info
336 end if
337 ! First, count the species
338 ions%nspecies = 0
339 atoms1: do i = 1, ions%natoms
340 do j = 1, i - 1
341 if (atom_same_species(ions%atom(j), ions%atom(i))) cycle atoms1
342 end do
343 ions%nspecies = ions%nspecies + 1
344 end do atoms1
345
346 ! Allocate the species structure.
347 allocate(ions%species(1:ions%nspecies))
348
349 ! Now, read the data.
350 k = 0
351 ions%only_user_def = .true.
352 atoms2: do i = 1, ions%natoms
353 do j = 1, i - 1
354 if (atom_same_species(ions%atom(j), ions%atom(i))) cycle atoms2
355 end do
356 k = k + 1
357 ions%species(k)%s => factory%create_from_input(ions%namespace, atom_get_label(ions%atom(j)), k)
358 ! these are the species which do not represent atoms
359 select type(spec => ions%species(k)%s)
360 class is(jellium_t)
361
362 class default
363 ions%only_user_def = .false.
364 end select
365
366 select type(spec => ions%species(k)%s)
367 type is(pseudopotential_t)
368 if (ions%space%dim /= 3) then
369 message(1) = "Pseudopotentials may only be used with Dimensions = 3."
370 call messages_fatal(1, namespace=ions%namespace)
371 end if
372
373 type is(jellium_slab_t)
374 if (ions%space%is_periodic() .and. ions%space%periodic_dim /= 2) then
375 message(1) = "Periodic jelium slab can only be used if PeriodicDim = 2"
376 call messages_fatal(1, namespace=ions%namespace)
377 end if
378 end select
379
380 end do atoms2
381
382 ! Reads the spin components. This is read here, as well as in states_init,
383 ! to be able to pass it to the pseudopotential initializations subroutine.
384 call parse_variable(ions%namespace, 'SpinComponents', 1, ispin)
385 if (.not. varinfo_valid_option('SpinComponents', ispin)) call messages_input_error(ions%namespace, 'SpinComponents')
386 ispin = min(2, ispin)
387
388 if (print_info_) then
389 call messages_print_with_emphasis(msg="Species", namespace=ions%namespace)
390 end if
391 do i = 1, ions%nspecies
392 spec => ions%species(i)%s
393 call spec%build(ions%namespace, ispin, ions%space%dim, print_info=print_info_)
394 end do
395 if (print_info_) then
396 call messages_print_with_emphasis(namespace=ions%namespace)
397 end if
398
399 !%Variable SpeciesTimeDependent
400 !%Type logical
401 !%Default no
402 !%Section System::Species
403 !%Description
404 !% When this variable is set, the potential defined in the block <tt>Species</tt> is calculated
405 !% and applied to the Hamiltonian at each time step. You must have at least one <tt>species_user_defined</tt>
406 !% type of species to use this.
407 !%End
408 call parse_variable(ions%namespace, 'SpeciesTimeDependent', .false., ions%species_time_dependent)
409 ! we must have at least one user defined species in order to have time dependency
410 do i = 1,ions%nspecies
411 select type(spec=>ions%species(i)%s)
413 spec_user_defined = .true.
414 end select
415 end do
416 if (ions%species_time_dependent .and. .not. spec_user_defined) then
417 call messages_input_error(ions%namespace, 'SpeciesTimeDependent')
418 end if
419
420 ! assign species
421 do i = 1, ions%natoms
422 do j = 1, ions%nspecies
423 if (atom_same_species(ions%atom(i), ions%species(j)%s)) then
424 call atom_set_species(ions%atom(i), ions%species(j)%s)
425 exit
426 end if
427 end do
428 end do
429
430 pop_sub(ions_init_species)
431 end subroutine ions_init_species
432
433 !--------------------------------------------------------------
434 subroutine ions_copy(ions_out, ions_in)
435 class(ions_t), intent(out) :: ions_out
436 class(ions_t), intent(in) :: ions_in
437
438 push_sub(ions_copy)
439
440 call charged_particles_copy(ions_out, ions_in)
441
442 ions_out%latt = ions_in%latt
443
444 ions_out%natoms = ions_in%natoms
445 safe_allocate(ions_out%atom(1:ions_out%natoms))
446 ions_out%atom = ions_in%atom
447
448 ions_out%nspecies = ions_in%nspecies
449 allocate(ions_out%species(1:ions_out%nspecies))
450 ions_out%species = ions_in%species
451
452 ions_out%only_user_def = ions_in%only_user_def
453
454 call distributed_copy(ions_in%atoms_dist, ions_out%atoms_dist)
455
456 safe_allocate(ions_out%map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops))
457 ions_out%map_symm_atoms = ions_in%map_symm_atoms
458 safe_allocate(ions_out%inv_map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops))
459 ions_out%inv_map_symm_atoms = ions_in%inv_map_symm_atoms
460
461
462 pop_sub(ions_copy)
463 end subroutine ions_copy
464
465 ! ---------------------------------------------------------
466 subroutine ions_partition(this, mc)
467 class(ions_t), intent(inout) :: this
468 type(multicomm_t), intent(in) :: mc
469
470 push_sub(ions_partition)
471
472 call distributed_init(this%atoms_dist, this%natoms, mc%group_comm(p_strategy_states), "atoms")
473
474 call ion_interaction_init_parallelization(this%ion_interaction, this%natoms, mc)
475
476 pop_sub(ions_partition)
477 end subroutine ions_partition
478
479 ! ---------------------------------------------------------
480 subroutine ions_init_interaction(this, interaction)
481 class(ions_t), target, intent(inout) :: this
482 class(interaction_t), intent(inout) :: interaction
483
484 push_sub(ions_init_interaction)
485
486 select type (interaction)
487 class default
488 call charged_particles_init_interaction(this, interaction)
489 end select
490
491 pop_sub(ions_init_interaction)
492 end subroutine ions_init_interaction
493
494 ! ---------------------------------------------------------
495 subroutine ions_initial_conditions(this)
496 class(ions_t), intent(inout) :: this
497
499
501 end subroutine ions_initial_conditions
502
503 ! ---------------------------------------------------------
504 subroutine ions_update_quantity(this, iq)
505 class(ions_t), intent(inout) :: this
506 integer, intent(in) :: iq
507
508 push_sub(ions_update_quantity)
509
510 ! We are only allowed to update quantities that can be updated on demand
511 assert(this%quantities(iq)%updated_on_demand)
512
513 select case (iq)
514 case default
515 ! Other quantities should be handled by the parent class
517 end select
518
519 pop_sub(ions_update_quantity)
520 end subroutine ions_update_quantity
521
522 ! ---------------------------------------------------------
523 subroutine ions_init_interaction_as_partner(partner, interaction)
524 class(ions_t), intent(in) :: partner
525 class(interaction_surrogate_t), intent(inout) :: interaction
526
528
529 select type (interaction)
530 class default
531 call charged_particles_init_interaction_as_partner(partner, interaction)
532 end select
533
536
537 ! ---------------------------------------------------------
538 subroutine ions_copy_quantities_to_interaction(partner, interaction)
539 class(ions_t), intent(inout) :: partner
540 class(interaction_surrogate_t), intent(inout) :: interaction
541
543
544 select type (interaction)
545 class default
546 ! Other interactions should be handled by the parent class
547 call charged_particles_copy_quantities_to_interaction(partner, interaction)
548 end select
549
552
553 ! ---------------------------------------------------------
554 subroutine ions_fold_atoms_into_cell(this)
555 class(ions_t), intent(inout) :: this
556
557 integer :: iatom
558
560
561 do iatom = 1, this%natoms
562 this%pos(:, iatom) = this%latt%fold_into_cell(this%pos(:, iatom))
563 end do
564
566 end subroutine ions_fold_atoms_into_cell
567
568 ! ---------------------------------------------------------
569 real(real64) function ions_min_distance(this, real_atoms_only) result(rmin)
570 class(ions_t), intent(in) :: this
571 logical, optional, intent(in) :: real_atoms_only
572
573 integer :: iatom, jatom, idir
574 real(real64) :: xx(this%space%dim)
575 logical :: real_atoms_only_
576 class(species_t), pointer :: species
577
578 if (this%natoms == 1 .and. .not. this%space%is_periodic()) then
579 rmin = m_huge
580 return
581 end if
582
583 push_sub(ions_min_distance)
584
585 real_atoms_only_ = optional_default(real_atoms_only, .false.)
586
587 rmin = m_huge
588 do iatom = 1, this%natoms
589 call atom_get_species(this%atom(iatom), species)
590 select type(species)
591 class is(jellium_t)
592 if (real_atoms_only_) cycle
593 end select
594 do jatom = iatom + 1, this%natoms
595 call atom_get_species(this%atom(jatom), species)
596 select type(species)
597 class is(jellium_t)
598 if (real_atoms_only_) cycle
599 end select
600 xx = abs(this%pos(:, iatom) - this%pos(:, jatom))
601 if (this%space%is_periodic()) then
602 xx = this%latt%cart_to_red(xx)
603 do idir = 1, this%space%periodic_dim
604 xx(idir) = xx(idir) - floor(xx(idir) + m_half)
605 end do
606 xx = this%latt%red_to_cart(xx)
607 end if
608 rmin = min(norm2(xx), rmin)
609 end do
610 end do
611
612 if (.not. (this%only_user_def .and. real_atoms_only_)) then
613 ! what if the nearest neighbors are periodic images?
614 do idir = 1, this%space%periodic_dim
615 rmin = min(rmin, norm2(this%latt%rlattice(:,idir)))
616 end do
617 end if
618
619 ! To avoid numerical instabilities, we round this to 6 digits only
620 if(rmin < huge(rmin)/1e6_real64) then
621 rmin = anint(rmin*1e6_real64)*1.0e-6_real64
622 end if
623
624 pop_sub(ions_min_distance)
625 end function ions_min_distance
626
627 ! ---------------------------------------------------------
628 logical function ions_has_time_dependent_species(this) result(time_dependent)
629 class(ions_t), intent(in) :: this
630
632
633 time_dependent = this%species_time_dependent
634
637
638 ! ---------------------------------------------------------
639 real(real64) function ions_val_charge(this, mask) result(val_charge)
640 class(ions_t), intent(in) :: this
641 logical, optional, intent(in) :: mask(:)
642
643 push_sub(ions_val_charge)
644
645 if (present(mask)) then
646 val_charge = -sum(this%charge, mask=mask)
647 else
648 val_charge = -sum(this%charge)
649 end if
650
651 pop_sub(ions_val_charge)
652 end function ions_val_charge
653
654 ! ---------------------------------------------------------
655 function ions_dipole(this, mask) result(dipole)
656 class(ions_t), intent(in) :: this
657 logical, optional, intent(in) :: mask(:)
658 real(real64) :: dipole(this%space%dim)
659
660 integer :: ia
661
662 push_sub(ions_dipole)
663
664 dipole = m_zero
665 do ia = 1, this%natoms
666 if (present(mask)) then
667 if (.not. mask(ia)) cycle
668 end if
669 dipole = dipole + this%charge(ia)*this%pos(:, ia)
670 end do
671 dipole = p_proton_charge*dipole
672
673 pop_sub(ions_dipole)
674 end function ions_dipole
675
676 ! ---------------------------------------------------------
677 subroutine ions_translate(this, xx)
678 class(ions_t), intent(inout) :: this
679 real(real64), intent(in) :: xx(this%space%dim)
680
681 integer :: iatom
682
683 push_sub(ions_translate)
684
685 do iatom = 1, this%natoms
686 this%pos(:, iatom) = this%pos(:, iatom) - xx
687 end do
688
689 pop_sub(ions_translate)
690 end subroutine ions_translate
691
692 ! ---------------------------------------------------------
693 subroutine ions_rotate(this, from, from2, to)
694 class(ions_t), intent(inout) :: this
695 real(real64), intent(in) :: from(this%space%dim)
696 real(real64), intent(in) :: from2(this%space%dim)
697 real(real64), intent(in) :: to(this%space%dim)
698
699 integer :: iatom
700 real(real64) :: m1(3, 3), m2(3, 3)
701 real(real64) :: m3(3, 3), f2(3), per(3)
702 real(real64) :: alpha, r
703
704 push_sub(ions_rotate)
705
706 if (this%space%dim /= 3) then
707 call messages_not_implemented("ions_rotate in other than 3 dimensions", namespace=this%namespace)
708 end if
709
710 ! initialize matrices
711 m1 = diagonal_matrix(3, m_one)
712
713 ! rotate the to-axis to the z-axis
714 if (abs(to(2)) > 1d-150) then
715 alpha = atan2(to(2), to(1))
716 call rotate(m1, alpha, 3)
717 end if
718 alpha = atan2(norm2(to(1:2)), to(3))
719 call rotate(m1, -alpha, 2)
720
721 ! get perpendicular to z and from
722 f2 = matmul(m1, from)
723 per(1) = -f2(2)
724 per(2) = f2(1)
725 per(3) = m_zero
726 r = norm2(per)
727 if (r > m_zero) then
728 per = per/r
729 else
730 per(2) = m_one
731 end if
733 ! rotate perpendicular axis to the y-axis
734 m2 = diagonal_matrix(3, m_one)
735 alpha = atan2(per(1), per(2))
736 call rotate(m2, -alpha, 3)
737
738 ! rotate from => to (around the y-axis)
739 m3 = diagonal_matrix(3, m_one)
740 alpha = acos(min(sum(from*to), m_one))
741 call rotate(m3, -alpha, 2)
742
743 ! join matrices
744 m2 = matmul(transpose(m2), matmul(m3, m2))
745
746 ! rotate around the z-axis to get the second axis
747 per = matmul(m2, matmul(m1, from2))
748 alpha = atan2(per(1), per(2))
749 call rotate(m2, -alpha, 3) ! second axis is now y
750
751 ! get combined transformation
752 m1 = matmul(transpose(m1), matmul(m2, m1))
753
754 ! now transform the coordinates
755 ! it is written in this way to avoid what I consider a bug in the Intel compiler
756 do iatom = 1, this%natoms
757 f2 = this%pos(:, iatom)
758 this%pos(:, iatom) = matmul(m1, f2)
759 end do
760
761 pop_sub(ions_rotate)
762 contains
763
764 ! ---------------------------------------------------------
765 subroutine rotate(m, angle, dir)
766 real(real64), intent(inout) :: m(3, 3)
767 real(real64), intent(in) :: angle
768 integer, intent(in) :: dir
769
770 real(real64) :: aux(3, 3), ca, sa
771
772 push_sub(ions_rotate.rotate)
773
774 ca = cos(angle)
775 sa = sin(angle)
776
777 aux = m_zero
778 select case (dir)
779 case (1)
780 aux(1, 1) = m_one
781 aux(2, 2) = ca
782 aux(3, 3) = ca
783 aux(2, 3) = sa
784 aux(3, 2) = -sa
785 case (2)
786 aux(2, 2) = m_one
787 aux(1, 1) = ca
788 aux(3, 3) = ca
789 aux(1, 3) = sa
790 aux(3, 1) = -sa
791 case (3)
792 aux(3, 3) = m_one
793 aux(1, 1) = ca
794 aux(2, 2) = ca
795 aux(1, 2) = sa
796 aux(2, 1) = -sa
797 end select
798
799 m = matmul(aux, m)
800
801 pop_sub(ions_rotate.rotate)
802 end subroutine rotate
803
804 end subroutine ions_rotate
805
806 ! ---------------------------------------------------------
807 function ions_global_force(this, time) result(force)
808 class(ions_t), intent(in) :: this
809 real(real64), intent(in) :: time
810 real(real64) :: force(this%space%dim)
811
812 push_sub(ions_global_force)
813
814 force = m_zero
815
816 if (this%apply_global_force) then
817 force(1) = units_to_atomic(units_inp%force, tdf(this%global_force_function, time))
818 end if
819
820 pop_sub(ions_global_force)
821 end function ions_global_force
822
823 ! ---------------------------------------------------------
824 subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
825 class(ions_t), intent(in) :: this
826 character(len=*), intent(in) :: fname
827 logical, optional, intent(in) :: append
828 character(len=*), optional, intent(in) :: comment
829 logical, optional, intent(in) :: reduce_coordinates
830
831 integer :: iatom, idim, iunit
832 character(len=6) position
833 character(len=19) :: frmt
834 real(real64) :: red(this%space%dim)
835
836 if (.not. mpi_grp_is_root(mpi_world)) return
837
838 push_sub(ions_write_xyz)
839
840 position = 'asis'
841 if (present(append)) then
842 if (append) position = 'append'
843 end if
844 if(.not.optional_default(reduce_coordinates, .false.)) then
845 iunit = io_open(trim(fname)//'.xyz', this%namespace, action='write', position=position)
846 else
847 iunit = io_open(trim(fname)//'.xyz_red', this%namespace, action='write', position=position)
848 end if
849
850 write(iunit, '(i4)') this%natoms
851 if (present(comment)) then
852 write(iunit, '(1x,a)') comment
853 else
854 write(iunit, '(1x,a,a)') 'units: ', trim(units_abbrev(units_out%length_xyz_file))
855 end if
856
857 write(unit=frmt, fmt="(a5,i2.2,a4,i2.2,a6)") "(6x,a", label_len, ",2x,", this%space%dim,"f12.6)"
858 do iatom = 1, this%natoms
859 if(.not.optional_default(reduce_coordinates, .false.)) then
860 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, &
861 (units_from_atomic(units_out%length_xyz_file, this%pos(idim, iatom)), idim=1, this%space%dim)
862 else
863 red = this%latt%cart_to_red(this%pos(:, iatom))
864 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, (red(idim), idim=1, this%space%dim)
865 end if
866 end do
867 call io_close(iunit)
868
869 pop_sub(ions_write_xyz)
870 end subroutine ions_write_xyz
871
872 ! ---------------------------------------------------------
873 subroutine ions_read_xyz(this, fname, comment)
874 class(ions_t), intent(inout) :: this
875 character(len=*), intent(in) :: fname
876 character(len=*), optional, intent(in) :: comment
877
878 integer :: iatom, idir, iunit
879 character(len=19) :: frmt, dum
880 real(real64) :: tmp(this%space%dim)
881
882 push_sub(ions_read_xyz)
883
884 iunit = io_open(trim(fname)//'.xyz', this%namespace, action='read', position='rewind')
885
886 read(iunit, '(i4)') this%natoms
887 if (present(comment)) then
888 read(iunit, *)
889 else
890 read(iunit, *)
891 end if
892 write(unit=frmt, fmt="(a5,i2.2,a4,i2.2,a6)") "(6x,a", label_len, ",2x,", this%space%dim, "f12.6)"
893 do iatom = 1, this%natoms
894 read(unit=iunit, fmt=frmt) dum, (tmp(idir), idir=1, this%space%dim)
895
896 this%pos(:, iatom) = units_to_atomic(units_out%length_xyz_file, tmp)
897 end do
898 call io_close(iunit)
899
901 end subroutine ions_read_xyz
902
903 ! ----------------------------------------------------------------
906 subroutine ions_write_crystal(this, dir)
907 class(ions_t), intent(in) :: this
908 character(len=*), intent(in) :: dir
909
910 type(lattice_iterator_t) :: latt_iter
911 real(real64) :: radius, pos(this%space%dim)
912 integer :: iatom, icopy, iunit
913
914 push_sub(ions_write_crystal)
915
916 radius = maxval(m_half*norm2(this%latt%rlattice(:,1:this%space%periodic_dim), dim=1))*(m_one + m_epsilon)
917 latt_iter = lattice_iterator_t(this%latt, radius)
918
919 if (mpi_grp_is_root(mpi_world)) then
920
921 iunit = io_open(trim(dir)//'/crystal.xyz', this%namespace, action='write')
922
923 write(iunit, '(i9)') this%natoms*latt_iter%n_cells
924 write(iunit, '(a)') '#generated by Octopus'
925
926 do iatom = 1, this%natoms
927 do icopy = 1, latt_iter%n_cells
928 pos = units_from_atomic(units_out%length, this%pos(:, iatom) + latt_iter%get(icopy))
929 write(iunit, '(a, 99f12.6)') this%atom(iatom)%label, pos
930 end do
931 end do
932
933 call io_close(iunit)
934 end if
935
936 pop_sub(ions_write_crystal)
937 end subroutine ions_write_crystal
938
939 ! ---------------------------------------------------------
940 subroutine ions_write_bild_forces_file(this, dir, fname)
941 class(ions_t), intent(in) :: this
942 character(len=*), intent(in) :: dir, fname
943
944 integer :: iunit, iatom, idir
945 real(real64) :: force(this%space%dim), center(this%space%dim)
946 character(len=20) frmt
947
948 if (.not. mpi_grp_is_root(mpi_world)) return
949
951
952 call io_mkdir(dir, this%namespace)
953 iunit = io_open(trim(dir)//'/'//trim(fname)//'.bild', this%namespace, action='write', &
954 position='asis')
955
956 write(frmt,'(a,i0,a)')'(a,2(', this%space%dim,'f16.6,1x))'
957
958 write(iunit, '(a)')'.comment : force vectors in ['//trim(units_abbrev(units_out%force))//']'
959 write(iunit, *)
960 write(iunit, '(a)')'.color red'
961 write(iunit, *)
962 do iatom = 1, this%natoms
963 center = units_from_atomic(units_out%length, this%pos(:, iatom))
964 force = units_from_atomic(units_out%force, this%tot_force(:, iatom))
965 write(iunit, '(a,1x,i4,1x,a2,1x,a6,1x,f10.6,a)') '.comment :', iatom, trim(this%atom(iatom)%label), &
966 'force:', norm2(force), '['//trim(units_abbrev(units_out%force))//']'
967 write(iunit,fmt=trim(frmt)) '.arrow', (center(idir), idir = 1, this%space%dim), &
968 (center(idir) + force(idir), idir = 1, this%space%dim)
969 write(iunit,*)
970 end do
971
972 call io_close(iunit)
973
975 end subroutine ions_write_bild_forces_file
976
977 ! -----------------------------------------------------
978 subroutine ions_write_vtk_geometry(this, filename, ascii)
979 class(ions_t), intent(in) :: this
980 character(len=*), intent(in) :: filename
981 logical, optional, intent(in) :: ascii
982
983 integer :: iunit, iatom, ierr
984 logical :: ascii_
985 real(real64), allocatable :: data(:, :)
986 integer, allocatable :: idata(:, :)
987 character(len=MAX_PATH_LEN) :: fullname
988
990
991 assert(this%space%dim == 3)
992
993 ascii_ = optional_default(ascii, .true.)
994
995 fullname = trim(filename)//".vtk"
996
997 iunit = io_open(trim(fullname), this%namespace, action='write')
998
999 write(iunit, '(1a)') '# vtk DataFile Version 3.0 '
1000 write(iunit, '(6a)') 'Generated by octopus ', trim(conf%version), ' - git: ', &
1001 trim(conf%git_commit), " configuration: ", trim(conf%config_time)
1002
1003 if (ascii_) then
1004 write(iunit, '(1a)') 'ASCII'
1005 else
1006 write(iunit, '(1a)') 'BINARY'
1007 end if
1008
1009 write(iunit, '(1a)') 'DATASET POLYDATA'
1010
1011 write(iunit, '(a,i9,a)') 'POINTS ', this%natoms, ' double'
1012
1013 if (ascii_) then
1014 do iatom = 1, this%natoms
1015 write(iunit, '(3f12.6)') this%pos(1:3, iatom)
1016 end do
1017 else
1018 call io_close(iunit)
1019 safe_allocate(data(1:3, 1:this%natoms))
1020 do iatom = 1, this%natoms
1021 data(1:3, iatom) = this%pos(1:3, iatom)
1022 end do
1023 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(3*this%natoms), data, &
1024 ierr, nohead = .true., fendian = io_binary_is_little_endian())
1025 safe_deallocate_a(data)
1026 iunit = io_open(trim(fullname), this%namespace, action='write', position = 'append')
1027 write(iunit, '(1a)') ''
1028 end if
1029
1030 write(iunit, '(a,2i9)') 'VERTICES ', this%natoms, 2*this%natoms
1031
1032 if (ascii_) then
1033 do iatom = 1, this%natoms
1034 write(iunit, '(2i9)') 1, iatom - 1
1035 end do
1036 else
1037 call io_close(iunit)
1038 safe_allocate(idata(1:2, 1:this%natoms))
1039 do iatom = 1, this%natoms
1040 idata(1, iatom) = 1
1041 idata(2, iatom) = iatom - 1
1042 end do
1043 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(2*this%natoms), idata, &
1044 ierr, nohead = .true., fendian = io_binary_is_little_endian())
1045 safe_deallocate_a(idata)
1046 iunit = io_open(trim(fullname), this%namespace, action='write', position = 'append')
1047 write(iunit, '(1a)') ''
1048 end if
1049
1050 write(iunit, '(a,i9)') 'POINT_DATA', this%natoms
1051 write(iunit, '(a)') 'SCALARS element integer'
1052 write(iunit, '(a)') 'LOOKUP_TABLE default'
1053
1054 if (ascii_) then
1055 do iatom = 1, this%natoms
1056 write(iunit, '(i9)') nint(this%atom(iatom)%species%get_z())
1057 end do
1058 else
1059 call io_close(iunit)
1060
1061 safe_allocate(idata(1:this%natoms, 1))
1062
1063 do iatom = 1, this%natoms
1064 idata(iatom, 1) = nint(this%atom(iatom)%species%get_z())
1065 end do
1066
1067 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(this%natoms), idata, &
1068 ierr, nohead = .true., fendian = io_binary_is_little_endian())
1069
1070 safe_deallocate_a(idata)
1072 iunit = io_open(trim(fullname), this%namespace, action='write', position = 'append')
1073 write(iunit, '(1a)') ''
1074 end if
1075
1076 call io_close(iunit)
1077
1079 end subroutine ions_write_vtk_geometry
1080
1081 ! ---------------------------------------------------------
1082 subroutine ions_finalize(ions)
1083 type(ions_t), intent(inout) :: ions
1084
1085 integer :: i
1086
1087 push_sub(ions_finalize)
1088
1089 call distributed_end(ions%atoms_dist)
1090
1091 call ion_interaction_end(ions%ion_interaction)
1092
1093 safe_deallocate_a(ions%atom)
1094 ions%natoms=0
1095
1096 if(allocated(ions%species)) then
1097 do i = 1, ions%nspecies
1098 !SAFE_ DEALLOCATE_P(ions%species(i)%s)
1099 if(associated(ions%species(i)%s)) deallocate(ions%species(i)%s)
1100 end do
1101 deallocate(ions%species)
1102 end if
1103 ions%nspecies=0
1104
1105 call charged_particles_end(ions)
1106
1107 safe_deallocate_a(ions%map_symm_atoms)
1108 safe_deallocate_a(ions%inv_map_symm_atoms)
1109
1110
1111 pop_sub(ions_finalize)
1112 end subroutine ions_finalize
1113
1114 !-------------------------------------------------------------------
1117 subroutine ions_update_lattice_vectors(ions, latt, symmetrize)
1118 class(ions_t), intent(inout) :: ions
1119 type(lattice_vectors_t), intent(in) :: latt
1120 logical, intent(in) :: symmetrize
1121
1123
1124 ! Update the lattice vectors
1125 call ions%latt%update(latt%rlattice)
1126
1127 ! Regenerate symmetries in Cartesian space
1128 if (symmetrize) then
1129 call symmetries_update_lattice_vectors(ions%symm, latt, ions%space%dim)
1130 end if
1131
1133 end subroutine ions_update_lattice_vectors
1134
1135 !-------------------------------------------------------------------
1142 class(ions_t), intent(inout) :: ions
1143
1144 integer :: iatom, iop, iatom_symm, dim4symms
1145 real(real64) :: ratom(ions%space%dim)
1146
1148
1149 safe_allocate(ions%map_symm_atoms(1:ions%natoms, 1:ions%symm%nops))
1150 safe_allocate(ions%inv_map_symm_atoms(1:ions%natoms, 1:ions%symm%nops))
1151
1152 ! In the 4D case, symmetries are only defined in 3D, see symmetries.F90
1153 dim4symms = min(3, ions%space%dim)
1154 ratom = m_zero
1155
1156 do iop = 1, ions%symm%nops
1157 do iatom = 1, ions%natoms
1158 !We find the atom that correspond to this one, once symmetry is applied
1159 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom))
1160
1161 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1162
1163 ! find iatom_symm
1164 do iatom_symm = 1, ions%natoms
1165 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec)) exit
1166 end do
1167
1168 if (iatom_symm > ions%natoms) then
1169 write(message(1),'(a,i6)') 'Internal error: could not find symmetric partner for atom number', iatom
1170 write(message(2),'(a,i3,a)') 'with symmetry operation number ', iop, '.'
1171 call messages_fatal(2, namespace=ions%namespace)
1172 end if
1173
1174 ions%map_symm_atoms(iatom, iop) = iatom_symm
1175 ions%inv_map_symm_atoms(iatom_symm, iop) = iatom
1176 end do
1177 end do
1178
1181
1182 !-------------------------------------------------------------------
1185 subroutine ions_symmetrize_atomic_coord(ions)
1186 class(ions_t), intent(inout) :: ions
1187
1188 integer :: iatom, iop, iatom_sym
1189 real(real64) :: ratom(ions%space%dim)
1190 real(real64), allocatable :: new_pos(:,:)
1191
1193
1194 safe_allocate(new_pos(1:ions%space%dim, 1:ions%natoms))
1195
1196 do iatom = 1, ions%natoms
1197 new_pos(:, iatom) = m_zero
1198 do iop = 1, ions%symm%nops
1199 iatom_sym = ions%inv_map_symm_atoms(iatom, iop)
1200 ratom = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom_sym))
1201 ratom = ions%latt%fold_into_cell(ratom)
1202 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1203 end do
1204 new_pos(:, iatom) = new_pos(:, iatom) / ions%symm%nops
1205 end do
1206
1207 ions%pos = new_pos
1208 safe_deallocate_a(new_pos)
1209
1211 end subroutine ions_symmetrize_atomic_coord
1212
1213
1214end module ions_oct_m
1215
1216!! Local Variables:
1217!! mode: f90
1218!! coding: utf-8
1219!! End:
double acos(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
double atan2(double __y, double __x) __attribute__((__nothrow__
double floor(double __x) __attribute__((__nothrow__
subroutine rotate(m, angle, dir)
Definition: ions.F90:859
pure character(len=len_trim(adjustl(this%label))) function, public atom_get_label(this)
Definition: atom.F90:236
subroutine, public atom_init(this, dim, label, species)
Definition: atom.F90:149
subroutine, public atom_get_species(this, species)
Definition: atom.F90:258
subroutine, public atom_set_species(this, species)
Definition: atom.F90:246
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, iq)
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
Definition: global.F90:205
character(len= *), parameter, public static_dir
Definition: global.F90:251
real(real64), parameter, public m_half
Definition: global.F90:193
real(real64), parameter, public m_one
Definition: global.F90:188
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
Definition: io.F90:114
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:354
subroutine, public ion_interaction_init_parallelization(this, natoms, mc)
subroutine, public ion_interaction_init(this, namespace, space, natoms)
subroutine ions_init_interaction(this, interaction)
Definition: ions.F90:574
subroutine ions_update_lattice_vectors(ions, latt, symmetrize)
Regenerate the ions information after update of the lattice vectors.
Definition: ions.F90:1211
class(ions_t) function, pointer ions_constructor(namespace, print_info, latt_inp)
Definition: ions.F90:219
subroutine ions_fold_atoms_into_cell(this)
Definition: ions.F90:648
real(real64) function, dimension(this%space%dim) ions_global_force(this, time)
Definition: ions.F90:901
subroutine ions_initial_conditions(this)
Definition: ions.F90:589
subroutine ions_copy(ions_out, ions_in)
Definition: ions.F90:528
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,...
Definition: ions.F90:1235
subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
Definition: ions.F90:918
subroutine ions_init_species(ions, factory, print_info)
Definition: ions.F90:416
subroutine ions_finalize(ions)
Definition: ions.F90:1176
subroutine ions_read_xyz(this, fname, comment)
Definition: ions.F90:967
subroutine ions_write_vtk_geometry(this, filename, ascii)
Definition: ions.F90:1072
subroutine ions_update_quantity(this, iq)
Definition: ions.F90:598
subroutine ions_rotate(this, from, from2, to)
Definition: ions.F90:787
subroutine ions_translate(this, xx)
Definition: ions.F90:771
subroutine ions_symmetrize_atomic_coord(ions)
Symmetrizes atomic coordinates by applying all symmetries.
Definition: ions.F90:1279
real(real64) function ions_min_distance(this, real_atoms_only)
Definition: ions.F90:663
real(real64) function, dimension(this%space%dim) ions_dipole(this, mask)
Definition: ions.F90:749
subroutine ions_write_bild_forces_file(this, dir, fname)
Definition: ions.F90:1034
subroutine ions_write_crystal(this, dir)
This subroutine creates a crystal by replicating the geometry and writes the result to dir.
Definition: ions.F90:1000
logical function ions_has_time_dependent_species(this)
Definition: ions.F90:722
subroutine ions_partition(this, mc)
Definition: ions.F90:560
subroutine ions_init_interaction_as_partner(partner, interaction)
Definition: ions.F90:617
subroutine ions_copy_quantities_to_interaction(partner, interaction)
Definition: ions.F90:632
real(real64) function ions_val_charge(this, mask)
Definition: ions.F90:733
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:930
character(len=512), private msg
Definition: messages.F90:165
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:543
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1057
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:420
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1097
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:502
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.
Definition: tdfunction.F90:218
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:223
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
abstract interaction class
surrogate interaction class to avoid circular dependencies between modules.
Stores all communicators and groups.
Definition: multicomm.F90:206
An abstract class for species. Derived classes include jellium, all electron, and pseudopotential spe...
Definition: species.F90:143
int true(void)