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
24 use blas_oct_m
27 use comm_oct_m
28 use iso_c_binding
29 use debug_oct_m
31 use global_oct_m
35 use io_oct_m
37 use, intrinsic :: iso_fortran_env
41 use math_oct_m
44 use mpi_oct_m
46 use parser_oct_m
51 use space_oct_m
54 use spglib_f08
57 use system_oct_m
59 use unit_oct_m
63
64 implicit none
65
66 private
67 public :: ions_t
68
69 type, extends(charged_particles_t) :: ions_t
70 ! Components are public by default
71
72 type(lattice_vectors_t) :: latt
73
74 integer :: natoms
75 type(atom_t), allocatable :: atom(:)
76
77 type(symmetries_t) :: symm
78
79 type(distributed_t) :: atoms_dist
80
81 integer, allocatable :: map_symm_atoms(:,:)
82 integer, allocatable :: inv_map_symm_atoms(:,:)
83
84 real(real64), allocatable :: equilibrium_pos(:,:)
85 ! !! for multitrajectory runs.
86 ! !!
87 ! !! This is necessary, as the displacements are added before we
88 ! !! generate the grid, but the grid should always be constructed
89 ! !! for the equilibrium positions.
90 real(real64), allocatable :: pos_displacements(:,:)
91 real(real64), allocatable :: vel_displacements(:,:)
92
93 ! Information about the species
94 integer :: nspecies
95 class(species_wrapper_t), allocatable :: species(:)
96 logical :: only_user_def
97 logical, private :: species_time_dependent
98
99 logical :: force_total_enforce
100 type(ion_interaction_t) :: ion_interaction
101
103 logical, private :: apply_global_force
104 type(tdf_t), private :: global_force_function
105 contains
106 procedure :: copy => ions_copy
107 generic :: assignment(=) => copy
108 procedure :: partition => ions_partition
109 procedure :: init_interaction => ions_init_interaction
110 procedure :: initialize => ions_initialize
111 procedure :: update_quantity => ions_update_quantity
112 procedure :: init_interaction_as_partner => ions_init_interaction_as_partner
113 procedure :: copy_quantities_to_interaction => ions_copy_quantities_to_interaction
114 procedure :: fold_atoms_into_cell => ions_fold_atoms_into_cell
115 procedure :: min_distance => ions_min_distance
116 procedure :: has_time_dependent_species => ions_has_time_dependent_species
117 procedure :: val_charge => ions_val_charge
118 procedure :: dipole => ions_dipole
119 procedure :: translate => ions_translate
120 procedure :: rotate => ions_rotate
121 procedure :: global_force => ions_global_force
122 procedure :: write_xyz => ions_write_xyz
123 procedure :: read_xyz => ions_read_xyz
124 procedure :: write_poscar => ions_write_poscar
125 procedure :: write_crystal => ions_write_crystal
126 procedure :: write_bild_forces_file => ions_write_bild_forces_file
127 procedure :: write_vtk_geometry => ions_write_vtk_geometry
128 procedure :: update_lattice_vectors => ions_update_lattice_vectors
129 procedure :: symmetrize_atomic_coord => ions_symmetrize_atomic_coord
130 procedure :: generate_mapping_symmetric_atoms => ions_generate_mapping_symmetric_atoms
131 procedure :: print_spacegroup => ions_print_spacegroup
132 procedure :: current => ions_current
133 procedure :: abs_current => ions_abs_current
134 procedure :: init_random_displacements => ions_init_random_displacements
135 procedure :: single_mode_displacements => ions_single_mode_displacements
136 final :: ions_finalize
137 end type ions_t
138
139 interface ions_t
140 procedure ions_constructor
141 end interface ions_t
142
143contains
144
145 ! ---------------------------------------------------------
146 function ions_constructor(namespace, grp, print_info, latt_inp, shared_namespace) result(ions)
147 type(namespace_t), intent(in) :: namespace
148 type(mpi_grp_t), intent(in) :: grp
149 logical, optional, intent(in) :: print_info
150 type(lattice_vectors_t), optional, intent(out) :: latt_inp
151 logical, optional, intent(in) :: shared_namespace
152 class(ions_t), pointer :: ions
153
154 type(read_coords_info) :: xyz
155 integer :: ia, ierr, idir
156 character(len=100) :: function_name
157 real(real64) :: mindist
158 real(real64), allocatable :: factor(:)
159 integer, allocatable :: site_type(:)
160 logical, allocatable :: spherical_site(:)
161 real(real64), parameter :: threshold = 1e-5_real64
162 type(species_factory_t) :: factory
163 real(real64) :: T
164 integer :: displacement_mode
165 real(real64) :: amp_pos, amp_vel
166
167 logical :: in_ensemble
168
169 push_sub_with_profile(ions_constructor)
171 allocate(ions)
173 ions%namespace = namespace
174 ions%space = space_t(namespace)
175
176 ! Electrons own the ions and share the same namespace. When it is shared, the
177 ! owning system has already registered that namespace MPI group, so we only copy the group here
178 ! to avoid a double entry in the hashmap; otherwise ions owns the namespace and registers it.
179 if (optional_default(shared_namespace, .false.)) then
180 call mpi_grp_copy(ions%grp, grp)
181 else
182 call system_init_parallelization(ions, grp)
183 end if
184
185 in_ensemble = parse_is_defined(namespace, "NumberOfReplicas")
187 call species_factory_init(factory, namespace)
188
189 ! initialize geometry
192 ! load positions of the atoms
193 call read_coords_read('Coordinates', xyz, ions%space, namespace)
195 if (xyz%n < 1) then
196 message(1) = "Coordinates have not been defined."
197 call messages_fatal(1, namespace=namespace)
198 end if
200 ! Initialize parent class
201 call charged_particles_init(ions, xyz%n)
203 ! copy information from xyz to ions
204 ions%natoms = xyz%n
205 safe_allocate(ions%atom(1:ions%natoms))
206 do ia = 1, ions%natoms
207 call atom_init(ions%atom(ia), ions%space%dim, xyz%atom(ia)%label)
208 ions%pos(:,ia) = xyz%atom(ia)%x(1:ions%space%dim)
209 if (bitand(xyz%flags, xyz_flags_move) /= 0) then
210 ions%fixed(ia) = .not. xyz%atom(ia)%move
211 end if
212 end do
214 if (allocated(xyz%latvec)) then
215 ! Build lattice vectors from the XSF input
216 ions%latt = lattice_vectors_t(namespace, ions%space, xyz%latvec)
217 else
218 ! Build lattice vectors from input file
219 ions%latt = lattice_vectors_t(namespace, ions%space)
220 end if
222 ! Convert coordinates to Cartesian in case we have reduced coordinates
223 if (xyz%source == read_coords_reduced) then
224 do ia = 1, ions%natoms
225 ions%pos(:, ia) = ions%latt%red_to_cart(ions%pos(:, ia))
226 end do
227 end if
231 ! Save the positions read from the input before applying deviations from the initial_input
232 safe_allocate_source_a(ions%equilibrium_pos, ions%pos)
233
234 call ions_init_species(ions, factory, print_info=print_info)
235
236 ! Set the masses and charges. This needs to be done after initializing the species.
237 do ia = 1, ions%natoms
238 ions%mass(ia) = ions%atom(ia)%species%get_mass()
239 ions%charge(ia) = ions%atom(ia)%species%get_zval()
240 end do
242 !%Variable InitialDisplacementMode
243 !%Type integer
244 !%Default 0
245 !%Section System
246 !%Description
247 !% When this variable is set and non-zero, the phonon modes file will be read, and ionic
248 !% positions and velocities will be displaced according to a single phonon mode.
249 !% The amplitudes can be defined with the variables:
250 !% - InitialDisplacementsAmplitudePos
251 !% - InitialDisplacementsAmplitudeVel
252 !%End
253 call parse_variable(namespace, 'InitialDisplacementMode', 0, displacement_mode)
254
255 !%Variable InitialDisplacementAmplitudePos
256 !%Type float
257 !%Default 1.0
258 !%Section System
259 !%Description
260 !% Amplitude for initial position displacement according to the phonon mode, defined by InitialDisplacementMode.
261 !% The value corresponds to the normal distributed canonical coordinates.
262 !%End
263 call parse_variable(namespace, 'InitialDisplacementAmplitudePos', 1.0_real64, amp_pos)
264
265 !%Variable InitialDisplacementAmplitudeVel
266 !%Type float
267 !%Default 1.0
268 !%Section System
269 !%Description
270 !% Amplitude for initial velocity displacement according to the phonon mode, defined by InitialDisplacementMode.
271 !% The value corresponds to the normal distributed canonical coordinates.
272 !%End
273 call parse_variable(namespace, 'InitialDisplacementAmplitudeVel', 1.0_real64, amp_vel)
274
275 if (displacement_mode>0) then
276
277 message(1) = "Random displacements are disabled when InitialDisplacementMode > 0."
278 call messages_warning(1, namespace=namespace)
279
280 safe_allocate(ions%pos_displacements(1:ions%space%dim, 1:ions%natoms))
281 safe_allocate(ions%vel_displacements(1:ions%space%dim, 1:ions%natoms))
282
283 call ions%single_mode_displacements(displacement_mode, amp_pos, amp_vel)
284
285 ! apply initial displacements
286 ions%pos = ions%pos + ions%pos_displacements
287
288 ! note that the velocity displacement needs to be applied in ions%initialize()
289
290 end if
291
292 ! Now we can apply displacements to the positions, if requested.
293 ! The random displacements are disabled if a single mode is specified,
294 if(in_ensemble .and. displacement_mode==0) then
295
296 !%Variable EnsembleTemperature
297 !%Type float
298 !%Default 0
299 !%Section Multi-Trajectory
300 !%Description
301 !% The temperature for an ensemble calculation in Kelvin
302 !%End
303 call parse_variable(namespace, 'EnsembleTemperature', 0.0_real64, t)
304
305 safe_allocate(ions%pos_displacements(1:ions%space%dim, 1:ions%natoms))
306 safe_allocate(ions%vel_displacements(1:ions%space%dim, 1:ions%natoms))
307 call ions%init_random_displacements(t)
308
309 ! apply initial displacements
310 ions%pos = ions%pos + ions%pos_displacements
311
312 ! note that the velocity displacement needs to be applied in ions%initialize()
313
314 end if
315
317 call distributed_nullify(ions%atoms_dist, ions%natoms)
318
319 call messages_obsolete_variable(namespace, 'PDBClassical')
320
321 if (present(latt_inp)) then
322 ! The lattice as read from the input might be needed by some other part of the code, so we save it
323 latt_inp = ions%latt
324 end if
325
326 ! Now that we have processed the atomic coordinates, we renormalize the
327 ! lattice parameters along the non-periodic dimensions
328 if (ions%space%has_mixed_periodicity()) then
329 safe_allocate(factor(ions%space%dim))
330 do idir = 1, ions%space%periodic_dim
331 factor(idir) = m_one
332 end do
333 do idir = ions%space%periodic_dim + 1, ions%space%dim
334 factor(idir) = m_one/norm2(ions%latt%rlattice(1:ions%space%dim, idir))
335 end do
336 call ions%latt%scale(factor)
337 safe_deallocate_a(factor)
338 end if
339
340 ! Check that atoms are not too close
341 if (ions%natoms > 1) then
342 mindist = ions_min_distance(ions, real_atoms_only = .false.)
343 if (mindist < threshold) then
344 write(message(1), '(a)') "Some of the atoms seem to sit too close to each other."
345 write(message(2), '(a)') "Please review your input files and the output geometry (in 'static/')."
346 write(message(3), '(a, f12.6, 1x, a)') "Minimum distance = ", &
347 units_from_atomic(units_out%length, mindist), trim(units_abbrev(units_out%length))
348 call messages_warning(3, namespace=namespace)
349
350 ! then write out the geometry, whether asked for or not in Output variable
351 call io_mkdir(static_dir, namespace)
352 call ions%write_xyz(trim(static_dir)//'/geometry')
353 end if
354
355 if (ions_min_distance(ions, real_atoms_only = .true.) < threshold) then
356 message(1) = "It cannot be correct to run with physical atoms so close."
357 call messages_fatal(1, namespace=namespace)
358 end if
359 end if
360
361 !Initialize symmetries
362 safe_allocate(spherical_site(1:ions%natoms))
363 safe_allocate(site_type(1:ions%natoms))
364 do ia = 1, ions%natoms
365 select type(spec => ions%atom(ia)%species)
366 type is(jellium_slab_t)
367 spherical_site(ia) = .false.
369 spherical_site(ia) = .false.
370 type is(species_from_file_t)
371 spherical_site(ia) = .false.
373 spherical_site(ia) = .false.
374 class default
375 spherical_site(ia) = .true.
376 end select
377
378 site_type(ia) = ions%atom(ia)%species%get_index()
379 end do
380
381 ions%symm = symmetries_t(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type, spherical_site)
382
383 safe_deallocate_a(spherical_site)
384 safe_deallocate_a(site_type)
385
386 ! Generate the mapping of symmetric atoms
387 call ions%generate_mapping_symmetric_atoms()
388
389 call ion_interaction_init(ions%ion_interaction, namespace, ions%space, ions%natoms)
390
391 !%Variable ForceTotalEnforce
392 !%Type logical
393 !%Default no
394 !%Section Hamiltonian
395 !%Description
396 !% (Experimental) If this variable is set to "yes", then the sum
397 !% of the total forces will be enforced to be zero.
398 !%End
399 call parse_variable(namespace, 'ForceTotalEnforce', .false., ions%force_total_enforce)
400 if (ions%force_total_enforce) call messages_experimental('ForceTotalEnforce', namespace=namespace)
401
402 !%Variable TDGlobalForce
403 !%Type string
404 !%Section Time-Dependent
405 !%Description
406 !% If this variable is set, a global time-dependent force will be
407 !% applied to the ions in the x direction during a time-dependent
408 !% run. This variable defines the base name of the force, that
409 !% should be defined in the <tt>TDFunctions</tt> block. This force
410 !% does not affect the electrons directly.
411 !%End
412
413 if (parse_is_defined(namespace, 'TDGlobalForce')) then
414
415 ions%apply_global_force = .true.
416
417 call parse_variable(namespace, 'TDGlobalForce', 'none', function_name)
418 call tdf_read(ions%global_force_function, namespace, trim(function_name), ierr)
419
420 if (ierr /= 0) then
421 call messages_write("You have enabled the GlobalForce option but Octopus could not find")
422 call messages_write("the '"//trim(function_name)//"' function in the TDFunctions block.")
423 call messages_fatal(namespace=namespace)
424 end if
425
426 else
427
428 ions%apply_global_force = .false.
429
430 end if
431
432 call species_factory_end(factory)
433
434 pop_sub_with_profile(ions_constructor)
435 end function ions_constructor
436
437 ! ---------------------------------------------------------
438 subroutine ions_init_species(ions, factory, print_info)
439 type(ions_t), intent(inout) :: ions
440 type(species_factory_t), intent(in) :: factory
441 logical, optional, intent(in) :: print_info
442
443 logical :: print_info_, spec_user_defined
444 integer :: i, j, k, ispin
445 class(species_t), pointer :: spec
446
447 push_sub_with_profile(ions_init_species)
448
449 print_info_ = .true.
450 if (present(print_info)) then
451 print_info_ = print_info
452 end if
453 ! First, count the species
454 ions%nspecies = 0
455 atoms1: do i = 1, ions%natoms
456 do j = 1, i - 1
457 if (atom_same_species(ions%atom(j), ions%atom(i))) cycle atoms1
458 end do
459 ions%nspecies = ions%nspecies + 1
460 end do atoms1
461
462 ! Allocate the species structure.
463 allocate(ions%species(1:ions%nspecies))
464
465 ! Now, read the data.
466 k = 0
467 ions%only_user_def = .true.
468 atoms2: do i = 1, ions%natoms
469 do j = 1, i - 1
470 if (atom_same_species(ions%atom(j), ions%atom(i))) cycle atoms2
471 end do
472 k = k + 1
473 ions%species(k)%s => factory%create_from_input(ions%namespace, ions%atom(j)%get_label(), k)
474 ! these are the species which do not represent atoms
475 select type(spec => ions%species(k)%s)
476 class is(jellium_t)
477
478 class default
479 ions%only_user_def = .false.
480 end select
481
482 select type(spec => ions%species(k)%s)
483 type is(pseudopotential_t)
484 if (ions%space%dim /= 3) then
485 message(1) = "Pseudopotentials may only be used with Dimensions = 3."
486 call messages_fatal(1, namespace=ions%namespace)
487 end if
488
489 type is(jellium_slab_t)
490 if (ions%space%is_periodic() .and. ions%space%periodic_dim /= 2) then
491 message(1) = "Periodic jelium slab can only be used if PeriodicDim = 2"
492 call messages_fatal(1, namespace=ions%namespace)
493 end if
494 end select
495
496 end do atoms2
497
498 ! Reads the spin components. This is read here, as well as in states_init,
499 ! to be able to pass it to the pseudopotential initializations subroutine.
500 call parse_variable(ions%namespace, 'SpinComponents', 1, ispin)
501 if (.not. varinfo_valid_option('SpinComponents', ispin)) call messages_input_error(ions%namespace, 'SpinComponents')
502 ispin = min(2, ispin)
503
504 if (print_info_) then
505 call messages_print_with_emphasis(msg="Species", namespace=ions%namespace)
506 end if
507 do i = 1, ions%nspecies
508 spec => ions%species(i)%s
509 call spec%build(ions%namespace, ispin, ions%space%dim, print_info=print_info_)
510 end do
511 if (print_info_) then
512 call messages_print_with_emphasis(namespace=ions%namespace)
513 end if
514
515 !%Variable SpeciesTimeDependent
516 !%Type logical
517 !%Default no
518 !%Section System::Species
519 !%Description
520 !% When this variable is set, the potential defined in the block <tt>Species</tt> is calculated
521 !% and applied to the Hamiltonian at each time step. You must have at least one <tt>species_user_defined</tt>
522 !% type of species to use this.
523 !%End
524 call parse_variable(ions%namespace, 'SpeciesTimeDependent', .false., ions%species_time_dependent)
525 ! we must have at least one user defined species in order to have time dependency
526 spec_user_defined = .false.
527 do i = 1,ions%nspecies
528 select type(spec=>ions%species(i)%s)
530 spec_user_defined = .true.
531 end select
532 end do
533 if (ions%species_time_dependent .and. .not. spec_user_defined) then
534 call messages_input_error(ions%namespace, 'SpeciesTimeDependent')
535 end if
536
537 ! assign species
538 do i = 1, ions%natoms
539 do j = 1, ions%nspecies
540 if (atom_same_species(ions%atom(i), ions%species(j)%s)) then
541 call atom_set_species(ions%atom(i), ions%species(j)%s)
542 exit
543 end if
544 end do
545 end do
546
547 pop_sub_with_profile(ions_init_species)
548 end subroutine ions_init_species
549
550 !--------------------------------------------------------------
551 subroutine ions_copy(ions_out, ions_in)
552 class(ions_t), intent(out) :: ions_out
553 class(ions_t), intent(in) :: ions_in
554
555 push_sub(ions_copy)
556
557 call charged_particles_copy(ions_out, ions_in)
558
559 ions_out%latt = ions_in%latt
560
561 ions_out%natoms = ions_in%natoms
562 safe_allocate(ions_out%atom(1:ions_out%natoms))
563 ions_out%atom = ions_in%atom
564
565 ions_out%nspecies = ions_in%nspecies
566 allocate(ions_out%species(1:ions_out%nspecies))
567 ions_out%species = ions_in%species
568
569 ions_out%only_user_def = ions_in%only_user_def
570
571 call distributed_copy(ions_in%atoms_dist, ions_out%atoms_dist)
572
573 safe_allocate(ions_out%map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops + ions_in%symm%nops_nonsymmorphic))
574 ions_out%map_symm_atoms = ions_in%map_symm_atoms
575 safe_allocate(ions_out%inv_map_symm_atoms(1:ions_in%natoms, 1:ions_in%symm%nops + ions_in%symm%nops_nonsymmorphic))
576 ions_out%inv_map_symm_atoms = ions_in%inv_map_symm_atoms
577
578
579 pop_sub(ions_copy)
580 end subroutine ions_copy
581
582 ! ---------------------------------------------------------
583 subroutine ions_partition(this, mc)
584 class(ions_t), intent(inout) :: this
585 type(multicomm_t), intent(in) :: mc
586
587 push_sub(ions_partition)
588
589 call distributed_init(this%atoms_dist, this%natoms, mc%group_comm(p_strategy_states), "atoms")
590
591 call ion_interaction_init_parallelization(this%ion_interaction, this%natoms, mc)
592
593 call mpi_grp_init(this%grp, mc%master_comm)
594
595 pop_sub(ions_partition)
596 end subroutine ions_partition
597
598 ! ---------------------------------------------------------
599 subroutine ions_init_interaction(this, interaction)
600 class(ions_t), target, intent(inout) :: this
601 class(interaction_t), intent(inout) :: interaction
602
603 push_sub(ions_init_interaction)
604
605 select type (interaction)
606 class default
607 call charged_particles_init_interaction(this, interaction)
608 end select
609
610 pop_sub(ions_init_interaction)
611 end subroutine ions_init_interaction
612
613 ! ---------------------------------------------------------
621 !
622 subroutine ions_init_random_displacements(ions, T)
623 class(ions_t), intent(inout) :: ions
624 real(real64), intent(in) :: T
625
626
627 integer(int64) :: seed
628
629 type(phonon_modes_t) :: phonons
630 type(wigner_distribution_t) :: wigner
631
632 real(real64), allocatable :: sigmaP(:)
633 real(real64), allocatable :: muP(:)
634 real(real64), allocatable :: sigmaQ(:)
635 real(real64), allocatable :: muQ(:)
636 real(real64), allocatable :: genP(:)
637 real(real64), allocatable :: genQ(:)
638
639
640 real(real64) :: beta_half
641 real(real64), allocatable :: pos_displacements(:), vel_displacements(:)
642 real(real64), allocatable :: l_m(:), prefactor(:)
643
644 integer :: imode, idim, iatom, i, iline
645 integer :: num_real_modes
647 real(real64), parameter :: low_temperature_tolerance = 1.0e-6_real64
648
649
651
652 ! create a unique seed for each replica, based on a hash of the full (unique) namespace string.
653 seed = ions%namespace%get_hash32()
654
655 message(1) = "Create initial random displacements for ions."
656 call messages_info(1, namespace = ions%namespace)
657
658 write(message(1), '("namespace = ",A)') ions%namespace%get()
659 write(message(2), '("seed = ",I0)') seed
660 call messages_info(2, namespace = ions%namespace, debug_only=.true.)
661
662
663 ! initialize the phonons (read info from file)
664 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
665
666 num_real_modes = phonons%num_modes
667
668 if (num_real_modes == 0) then
669
670 ions%pos_displacements = m_zero
671 ions%vel_displacements = m_zero
672
674 return
675 end if
676
677
678 ! initialize wigner distribution for phonons%num_modes modes and with given seed
679 call wigner%init(num_real_modes, seed)
680
681 ! set up widths and shifts for the Wigner function
682 safe_allocate(sigmap(1:num_real_modes))
683 safe_allocate(sigmaq(1:num_real_modes))
684 safe_allocate(mup(1:num_real_modes))
685 safe_allocate(muq(1:num_real_modes))
686 safe_allocate(genp(1:num_real_modes))
687 safe_allocate(genq(1:num_real_modes))
688
689 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
690 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
691 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
692
693 safe_allocate(l_m(1:num_real_modes))
695
696 if (t < low_temperature_tolerance) then
697 ! TODO: Implement proper low T limit
698 sigmap = 1.0_real64/2.0_real64
699 sigmaq = 1.0_real64/2.0_real64
700 else
701 beta_half = m_one / (2 * p_kb * t)
702 sigmap = 1.0_real64/sqrt((2.0_real64 * tanh(beta_half * phonons%frequencies)))
703 sigmaq = 1.0_real64/sqrt((2.0_real64 * tanh(beta_half * phonons%frequencies)))
704 end if
705 mup = m_zero
706 muq = m_zero
707
708 l_m = sqrt(2.0_real64/(unit_amu%factor * phonons%frequencies)) * phonons%alpha
709
710 i = 1
711 do iatom = 1, ions%natoms
712 do idim = 1, ions%space%dim
713 prefactor(i) = 1.0_real64/sqrt(ions%mass(iatom)/unit_amu%factor * phonons%num_super)
714 i=i+1
715 end do
716 end do
718 ! get generalized mode coords from Wigner function
719 genq = wigner%get(sigmaq, muq, wigner_q) * l_m
720 genp = wigner%get(sigmap, mup, wigner_p) / (l_m * unit_amu%factor) ! TODO: Check!!
721
722 ! construct initial displacements and velocities for ions (velocities must be applied later)
723
724 ions%pos_displacements = m_zero
725 ions%vel_displacements = m_zero
726
727 ! implement eq.(9) from Kevins paper for periodic systems
728
729 do imode = 1, num_real_modes
730
731 pos_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genq(imode)
732 vel_displacements = prefactor(:) * phonons%eigenvectors(:, imode) * genp(imode)
733
734 iline = 1
735 write(message(iline), '("Displacements for mode ",I4)') imode
736 do iatom=1, ions%natoms
737 iline = iline+1
738 write(message(iline), '(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
739 end do
740 iline = iline+1
741 write(message(iline), '("Velocities for mode ",I4)') imode
742 do iatom=1, ions%natoms
743 iline = iline+1
744 write(message(iline), '(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
745 end do
746
747 call messages_info(iline, namespace=ions%namespace)
748
749 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
750 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
751
752 end do
753
754 safe_deallocate_a(sigmap)
755 safe_deallocate_a(sigmaq)
756 safe_deallocate_a(mup)
757 safe_deallocate_a(muq)
758 safe_deallocate_a(genp)
759 safe_deallocate_a(genq)
760 safe_deallocate_a(l_m)
761
762 safe_deallocate_a(prefactor)
763 safe_deallocate_a(pos_displacements)
764 safe_deallocate_a(vel_displacements)
765
767
768 end subroutine ions_init_random_displacements
769
770
774 !
775 subroutine ions_single_mode_displacements(ions, mode, amplitude_pos, amplitude_vel)
776 class(ions_t), intent(inout) :: ions
777 integer, intent(in) :: mode
778 real(real64), optional, intent(in) :: amplitude_pos
779 real(real64), optional, intent(in) :: amplitude_vel
780
781 type(phonon_modes_t) :: phonons
782 integer :: num_real_modes, i, iatom, idim
783 real(real64) :: l_m, genP, genQ
784
785 real(real64), allocatable :: pos_displacements(:), vel_displacements(:), prefactor(:)
786
787
789
790 write(message(1), '("Create displacements for mode ", I4)') mode
791 call messages_info(1, namespace=ions%namespace)
792
793 ! initialize the phonons (read info from file)
794 call phonons%init(ions%namespace, ions%space%dim, ions%natoms, ions%space%periodic_dim > 0)
795
796 num_real_modes = phonons%num_modes
797
798 if (mode > num_real_modes) then
799 write(message(1), '("Requested mode ",I0," exceeds number of available modes (",I0,")")') mode, num_real_modes
800 call messages_fatal(1, namespace=ions%namespace)
801
803 return
804 end if
805
806 ions%pos_displacements = m_zero
807 ions%vel_displacements = m_zero
808
809 l_m = sqrt(2.0_real64/(unit_amu%factor * phonons%frequencies(mode))) * phonons%alpha(mode)
810
811 safe_allocate(pos_displacements(1:(ions%space%dim*ions%natoms)))
812 safe_allocate(vel_displacements(1:(ions%space%dim*ions%natoms)))
813 safe_allocate(prefactor(1:(ions%space%dim*ions%natoms)))
814
815 i = 1
816 do iatom = 1, ions%natoms
817 do idim=1, ions%space%dim
818 prefactor(i) = 1.0_real64/sqrt(ions%mass(iatom)/unit_amu%factor * phonons%num_super)
819 i=i+1
820 end do
821 end do
822
823 ! get generalized mode coords from Wigner function
824 genq = amplitude_pos * l_m
825 genp = amplitude_vel / (l_m * unit_amu%factor)! TODO: Check!!
826
827 pos_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genq
828 vel_displacements = prefactor(:) * phonons%eigenvectors(:, mode) * genp
829
830 write(message(1), '("Displacements for mode ",I4)') mode
831 call messages_info(1, namespace=ions%namespace)
832 do iatom=1, ions%natoms
833 write(message(1), '(3E15.5)') pos_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
834 call messages_info(1, namespace=ions%namespace)
835 end do
836 write(message(1), '("Velocities for mode ",I4)') mode
837 call messages_info(1, namespace=ions%namespace)
838 do iatom=1, ions%natoms
839 write(message(1), '(3E15.5)') vel_displacements((iatom-1)*ions%space%dim+1:(iatom-1)*ions%space%dim+ions%space%dim)
840 call messages_info(1, namespace=ions%namespace)
841 end do
842
843
844 call blas_axpy(phonons%dim, 1.0_real64, pos_displacements(1), 1, ions%pos_displacements(1,1), 1)
845 call blas_axpy(phonons%dim, 1.0_real64, vel_displacements(1), 1, ions%vel_displacements(1,1), 1)
846
847 safe_deallocate_a(pos_displacements)
848 safe_deallocate_a(vel_displacements)
849 safe_deallocate_a(prefactor)
850
852
853 end subroutine ions_single_mode_displacements
854
855 ! ---------------------------------------------------------
856 subroutine ions_initialize(this)
857 class(ions_t), intent(inout) :: this
858
859 push_sub(ions_initialize)
860
861 ! At this point, we need to apply initial velocities from the random displacements.
862 if(allocated(this%vel_displacements)) then
863 this%vel = this%vel + this%vel_displacements
864 end if
865
866 pop_sub(ions_initialize)
867 end subroutine ions_initialize
868
869 ! ---------------------------------------------------------
870 subroutine ions_update_quantity(this, label)
871 class(ions_t), intent(inout) :: this
872 character(len=*), intent(in) :: label
873
874 push_sub(ions_update_quantity)
875
876 select case (label)
877 case default
878 ! Other quantities should be handled by the parent class
879 call charged_particles_update_quantity(this, label)
880 end select
881
882 pop_sub(ions_update_quantity)
883 end subroutine ions_update_quantity
884
885 ! ---------------------------------------------------------
886 subroutine ions_init_interaction_as_partner(partner, interaction)
887 class(ions_t), intent(in) :: partner
888 class(interaction_surrogate_t), intent(inout) :: interaction
889
891
892 select type (interaction)
893 class default
894 call charged_particles_init_interaction_as_partner(partner, interaction)
895 end select
896
899
900 ! ---------------------------------------------------------
901 subroutine ions_copy_quantities_to_interaction(partner, interaction)
902 class(ions_t), intent(inout) :: partner
903 class(interaction_surrogate_t), intent(inout) :: interaction
904
906
907 select type (interaction)
908 class default
909 ! Other interactions should be handled by the parent class
910 call charged_particles_copy_quantities_to_interaction(partner, interaction)
911 end select
912
915
916 ! ---------------------------------------------------------
917 subroutine ions_fold_atoms_into_cell(this)
918 class(ions_t), intent(inout) :: this
919
920 integer :: iatom
921
923
924 do iatom = 1, this%natoms
925 this%pos(:, iatom) = this%latt%fold_into_cell(this%pos(:, iatom))
926 end do
927
929 end subroutine ions_fold_atoms_into_cell
930
931 ! ---------------------------------------------------------
932 real(real64) function ions_min_distance(this, real_atoms_only) result(rmin)
933 class(ions_t), intent(in) :: this
934 logical, optional, intent(in) :: real_atoms_only
935
936 integer :: iatom, jatom, idir
937 real(real64) :: xx(this%space%dim)
938 logical :: real_atoms_only_
939 class(species_t), pointer :: species
940
941 if (this%natoms == 1 .and. .not. this%space%is_periodic()) then
942 rmin = m_huge
943 return
944 end if
945
946 push_sub(ions_min_distance)
947
948 real_atoms_only_ = optional_default(real_atoms_only, .false.)
949
950 ! Without this line, valgrind complains about a conditional jump on uninitialized variable,
951 ! as atom_get_species has an intent(out) that causes a call to the finalizer (with Ifort)
952 nullify(species)
953
954 rmin = huge(rmin)
955 do iatom = 1, this%natoms
956 call atom_get_species(this%atom(iatom), species)
957 select type(species)
958 class is(jellium_t)
959 if (real_atoms_only_) cycle
960 end select
961 do jatom = iatom + 1, this%natoms
962 call atom_get_species(this%atom(jatom), species)
963 select type(species)
964 class is(jellium_t)
965 if (real_atoms_only_) cycle
966 end select
967 xx = abs(this%pos(:, iatom) - this%pos(:, jatom))
968 if (this%space%is_periodic()) then
969 xx = this%latt%cart_to_red(xx)
970 do idir = 1, this%space%periodic_dim
971 xx(idir) = xx(idir) - floor(xx(idir) + m_half)
972 end do
973 xx = this%latt%red_to_cart(xx)
974 end if
975 rmin = min(norm2(xx), rmin)
976 end do
977 end do
978
979 if (.not. (this%only_user_def .and. real_atoms_only_)) then
980 ! what if the nearest neighbors are periodic images?
981 do idir = 1, this%space%periodic_dim
982 rmin = min(rmin, norm2(this%latt%rlattice(:,idir)))
983 end do
984 end if
985
986 ! To avoid numerical instabilities, we round this to 6 digits only
987 if(rmin < huge(rmin)/1e6_real64) then
988 rmin = anint(rmin*1e6_real64)*1.0e-6_real64
989 end if
990
991 pop_sub(ions_min_distance)
992 end function ions_min_distance
993
994 ! ---------------------------------------------------------
995 logical function ions_has_time_dependent_species(this) result(time_dependent)
996 class(ions_t), intent(in) :: this
997
999
1000 time_dependent = this%species_time_dependent
1001
1004
1005 ! ---------------------------------------------------------
1006 real(real64) function ions_val_charge(this, mask) result(val_charge)
1007 class(ions_t), intent(in) :: this
1008 logical, optional, intent(in) :: mask(:)
1009
1010 push_sub(ions_val_charge)
1011
1012 if (present(mask)) then
1013 val_charge = -sum(this%charge, mask=mask)
1014 else
1015 val_charge = -sum(this%charge)
1016 end if
1017
1018 pop_sub(ions_val_charge)
1019 end function ions_val_charge
1020
1021 ! ---------------------------------------------------------
1022 function ions_dipole(this, mask) result(dipole)
1023 class(ions_t), intent(in) :: this
1024 logical, optional, intent(in) :: mask(:)
1025 real(real64) :: dipole(this%space%dim)
1026
1027 integer :: ia
1028
1029 push_sub(ions_dipole)
1030
1031 dipole = m_zero
1032 do ia = 1, this%natoms
1033 if (present(mask)) then
1034 if (.not. mask(ia)) cycle
1035 end if
1036 dipole = dipole + this%charge(ia)*this%pos(:, ia)
1037 end do
1038 dipole = p_proton_charge*dipole
1039
1040 pop_sub(ions_dipole)
1041 end function ions_dipole
1042
1043 ! ---------------------------------------------------------
1044 subroutine ions_translate(this, xx)
1045 class(ions_t), intent(inout) :: this
1046 real(real64), intent(in) :: xx(this%space%dim)
1047
1048 integer :: iatom
1049
1050 push_sub(ions_translate)
1051
1052 do iatom = 1, this%natoms
1053 this%pos(:, iatom) = this%pos(:, iatom) - xx
1054 end do
1055
1056 pop_sub(ions_translate)
1057 end subroutine ions_translate
1058
1059 ! ---------------------------------------------------------
1060 subroutine ions_rotate(this, from, from2, to)
1061 class(ions_t), intent(inout) :: this
1062 real(real64), intent(in) :: from(this%space%dim)
1063 real(real64), intent(in) :: from2(this%space%dim)
1064 real(real64), intent(in) :: to(this%space%dim)
1065
1066 integer :: iatom
1067 real(real64) :: m1(3, 3), m2(3, 3)
1068 real(real64) :: m3(3, 3), f2(3), per(3)
1069 real(real64) :: alpha, r
1070
1071 push_sub(ions_rotate)
1072
1073 if (this%space%dim /= 3) then
1074 call messages_not_implemented("ions_rotate in other than 3 dimensions", namespace=this%namespace)
1075 end if
1076
1077 ! initialize matrices
1078 m1 = diagonal_matrix(3, m_one)
1079
1080 ! rotate the to-axis to the z-axis
1081 if (abs(to(2)) > 1d-150) then
1082 alpha = atan2(to(2), to(1))
1083 call rotate(m1, alpha, 3)
1084 end if
1085 alpha = atan2(norm2(to(1:2)), to(3))
1086 call rotate(m1, -alpha, 2)
1087
1088 ! get perpendicular to z and from
1089 f2 = matmul(m1, from)
1090 per(1) = -f2(2)
1091 per(2) = f2(1)
1092 per(3) = m_zero
1093 r = norm2(per)
1094 if (r > m_zero) then
1095 per = per/r
1096 else
1097 per(2) = m_one
1098 end if
1099
1100 ! rotate perpendicular axis to the y-axis
1101 m2 = diagonal_matrix(3, m_one)
1102 alpha = atan2(per(1), per(2))
1103 call rotate(m2, -alpha, 3)
1104
1105 ! rotate from => to (around the y-axis)
1106 m3 = diagonal_matrix(3, m_one)
1107 alpha = acos(min(sum(from*to), m_one))
1108 call rotate(m3, -alpha, 2)
1109
1110 ! join matrices
1111 m2 = matmul(transpose(m2), matmul(m3, m2))
1112
1113 ! rotate around the z-axis to get the second axis
1114 per = matmul(m2, matmul(m1, from2))
1115 alpha = atan2(per(1), per(2))
1116 call rotate(m2, -alpha, 3) ! second axis is now y
1118 ! get combined transformation
1119 m1 = matmul(transpose(m1), matmul(m2, m1))
1120
1121 ! now transform the coordinates
1122 ! it is written in this way to avoid what I consider a bug in the Intel compiler
1123 do iatom = 1, this%natoms
1124 f2 = this%pos(:, iatom)
1125 this%pos(:, iatom) = matmul(m1, f2)
1126 end do
1127
1128 pop_sub(ions_rotate)
1129 contains
1130
1131 ! ---------------------------------------------------------
1132 subroutine rotate(m, angle, dir)
1133 real(real64), intent(inout) :: m(3, 3)
1134 real(real64), intent(in) :: angle
1135 integer, intent(in) :: dir
1136
1137 real(real64) :: aux(3, 3), ca, sa
1138
1140
1141 ca = cos(angle)
1142 sa = sin(angle)
1143
1144 aux = m_zero
1145 select case (dir)
1146 case (1)
1147 aux(1, 1) = m_one
1148 aux(2, 2) = ca
1149 aux(3, 3) = ca
1150 aux(2, 3) = sa
1151 aux(3, 2) = -sa
1152 case (2)
1153 aux(2, 2) = m_one
1154 aux(1, 1) = ca
1155 aux(3, 3) = ca
1156 aux(1, 3) = sa
1157 aux(3, 1) = -sa
1158 case (3)
1159 aux(3, 3) = m_one
1160 aux(1, 1) = ca
1161 aux(2, 2) = ca
1162 aux(1, 2) = sa
1163 aux(2, 1) = -sa
1164 end select
1165
1166 m = matmul(aux, m)
1167
1168 pop_sub(ions_rotate.rotate)
1169 end subroutine rotate
1170
1171 end subroutine ions_rotate
1172
1173 ! ---------------------------------------------------------
1174 function ions_global_force(this, time) result(force)
1175 class(ions_t), intent(in) :: this
1176 real(real64), intent(in) :: time
1177 real(real64) :: force(this%space%dim)
1178
1179 push_sub(ions_global_force)
1180
1181 force = m_zero
1182
1183 if (this%apply_global_force) then
1184 force(1) = tdf(this%global_force_function, time)
1185 end if
1186
1187 pop_sub(ions_global_force)
1188 end function ions_global_force
1189
1190 ! ---------------------------------------------------------
1191 subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
1192 class(ions_t), intent(in) :: this
1193 character(len=*), intent(in) :: fname
1194 logical, optional, intent(in) :: append
1195 character(len=*), optional, intent(in) :: comment
1196 logical, optional, intent(in) :: reduce_coordinates
1197
1198 integer :: iatom, idim, iunit
1199 character(len=6) position
1200 character(len=19) :: frmt
1201 real(real64) :: red(this%space%dim)
1202
1203 if (.not. this%grp%is_root()) return
1204
1205 push_sub(ions_write_xyz)
1206
1207 position = 'asis'
1208 if (present(append)) then
1209 if (append) position = 'append'
1210 end if
1211 if(.not.optional_default(reduce_coordinates, .false.)) then
1212 iunit = io_open(trim(fname)//'.xyz', this%namespace, action='write', position=position)
1213 else
1214 iunit = io_open(trim(fname)//'.xyz_red', this%namespace, action='write', position=position)
1215 end if
1216
1217 write(iunit, '(i4)') this%natoms
1218 if (present(comment)) then
1219 write(iunit, '(1x,a)') comment
1220 else
1221 write(iunit, '(1x,a,a)') 'units: ', trim(units_abbrev(units_out%length_xyz_file))
1222 end if
1223
1224 write(unit=frmt, fmt="(a5,i2.2,a4,i2.2,a6)") "(6x,a", label_len, ",2x,", this%space%dim,"f15.9)"
1225 do iatom = 1, this%natoms
1226 if(.not.optional_default(reduce_coordinates, .false.)) then
1227 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, &
1228 (units_from_atomic(units_out%length_xyz_file, this%pos(idim, iatom)), idim=1, this%space%dim)
1229 else
1230 red = this%latt%cart_to_red(this%pos(:, iatom))
1231 write(unit=iunit, fmt=frmt) this%atom(iatom)%label, (red(idim), idim=1, this%space%dim)
1232 end if
1233 end do
1234 call io_close(iunit)
1235
1236 pop_sub(ions_write_xyz)
1237 end subroutine ions_write_xyz
1238
1243 !
1244 subroutine ions_write_poscar(this, fname, comment)
1245 class(ions_t), intent(in) :: this
1246 character(len=*), optional, intent(in) :: fname
1247 character(len=*), optional, intent(in) :: comment
1248
1249 integer :: iatom, idim, iunit
1250 character(len=:), allocatable :: fname_, comment_
1251 character(len=10) :: format_string
1252
1253 push_sub(ions_write_poscar)
1254
1255 if (.not. this%grp%is_root()) then
1256 pop_sub(ions_write_poscar)
1257 return
1258 end if
1259
1260 comment_ = optional_default(comment, "")
1261 fname_ = optional_default(fname, "POSCAR")
1262
1263 iunit = io_open(trim(fname_), this%namespace, action='write')
1264
1265 write(iunit, '(A)') comment_ ! mandatory comment
1266 write(iunit, '("1.0")') ! scaling factor: we use 1 as lattice vectors are absolute
1267
1268 write(format_string, '("(",I1,A,")")') this%space%dim, 'F15.10'
1269 do idim=1, this%space%dim
1270 write(iunit, format_string) units_from_atomic(unit_angstrom, this%latt%rlattice(:,idim))
1271 end do
1272
1273 do iatom = 1, this%natoms
1274 write(iunit, '(A)', advance='NO') trim(this%atom(iatom)%label)//" "
1275 end do
1276 write(iunit, '("")')
1277 write(iunit, '(A)') repeat("1 ", this%natoms)
1278 write(iunit, '("direct")')
1279 write(format_string, '("(",I1,A,")")') this%space%dim, 'F15.10'
1280 do iatom=1, this%natoms
1281 write(iunit, format_string) this%latt%cart_to_red(this%pos(:, iatom))
1282 end do
1283
1284 call io_close(iunit)
1285
1287 end subroutine ions_write_poscar
1288
1289 ! ---------------------------------------------------------
1290 subroutine ions_read_xyz(this, fname, comment)
1291 use iso_fortran_env, only: real64
1292 class(ions_t), intent(inout) :: this
1293 character(len=*), intent(in) :: fname
1294 character(len=*), optional, intent(in) :: comment
1295
1296 integer :: iatom, idir, iunit, ios
1297 character(len=256) :: line
1298 character(len=LABEL_LEN) :: label
1299 character(len=:), allocatable :: coordstr
1300 real(real64) :: tmp(this%space%dim)
1301
1302 push_sub(ions_read_xyz)
1303
1304 iunit = io_open(trim(fname)//'.xyz', this%namespace, action='read', position='rewind')
1305
1306 ! --- First two lines: natoms + optional comment ------------------------
1307 read(iunit, '(i4)') this%natoms
1308 if (present(comment)) then
1309 read(iunit, *)
1310 else
1311 read(iunit, *)
1312 end if
1313
1314 ! --- Read atom lines ---------------------------------------------------
1315 do iatom = 1, this%natoms
1316
1317 ! Read entire line (safe even if long)
1318 read(iunit,'(A)', iostat=ios) line
1319 if (ios /= 0) then
1320 call io_close(iunit)
1321 message(1) = "Error reading XYZ atom line"
1322 call messages_fatal(1, namespace=this%namespace)
1323 end if
1324
1325 ! Extract fixed-length label (preserves spaces inside)
1326 if (len_trim(line) < label_len) then
1327 call io_close(iunit)
1328 message(1) = "XYZ file: atom line too short for label"
1329 call messages_fatal(1, namespace=this%namespace)
1330 end if
1331 label = line(1:label_len)
1332
1333 ! Extract remaining part for coordinates
1334 if (len(line) > label_len) then
1335 coordstr = adjustl(line(label_len+1:))
1336 else
1337 call io_close(iunit)
1338 message(1) = "XYZ file: no coordinate data after label"
1339 call messages_fatal(1, namespace=this%namespace)
1340 end if
1341
1342 ! Parse coordinates in a flexible (list-directed) way
1343 read(coordstr, *, iostat=ios) (tmp(idir), idir=1, this%space%dim)
1344 if (ios /= 0) then
1345 call io_close(iunit)
1346 message(1) = "XYZ file: malformed coordinate fields"
1347 call messages_fatal(1, namespace=this%namespace)
1348 end if
1349
1350 ! Convert and store
1351 this%pos(:, iatom) = units_to_atomic(units_out%length_xyz_file, tmp)
1352
1353 end do
1354
1355 call io_close(iunit)
1356
1357 pop_sub(ions_read_xyz)
1358 end subroutine ions_read_xyz
1359
1360 ! ----------------------------------------------------------------
1363 subroutine ions_write_crystal(this, dir)
1364 class(ions_t), intent(in) :: this
1365 character(len=*), intent(in) :: dir
1366
1367 type(lattice_iterator_t) :: latt_iter
1368 real(real64) :: radius, pos(this%space%dim)
1369 integer :: iatom, icopy, iunit
1370
1371 push_sub(ions_write_crystal)
1372
1373 radius = maxval(m_half*norm2(this%latt%rlattice(:,1:this%space%periodic_dim), dim=1))*(m_one + m_epsilon)
1374 latt_iter = lattice_iterator_t(this%latt, radius)
1375
1376 if (this%grp%is_root()) then
1377
1378 iunit = io_open(trim(dir)//'/crystal.xyz', this%namespace, action='write')
1379
1380 write(iunit, '(i9)') this%natoms*latt_iter%n_cells
1381 write(iunit, '(a)') '#generated by Octopus'
1382
1383 do iatom = 1, this%natoms
1384 do icopy = 1, latt_iter%n_cells
1385 pos = units_from_atomic(units_out%length, this%pos(:, iatom) + latt_iter%get(icopy))
1386 write(iunit, '(a, 99f12.6)') this%atom(iatom)%label, pos
1387 end do
1388 end do
1389
1390 call io_close(iunit)
1391 end if
1392
1393 pop_sub(ions_write_crystal)
1394 end subroutine ions_write_crystal
1395
1396 ! ---------------------------------------------------------
1397 subroutine ions_write_bild_forces_file(this, dir, fname)
1398 class(ions_t), intent(in) :: this
1399 character(len=*), intent(in) :: dir, fname
1400
1401 integer :: iunit, iatom, idir
1402 real(real64) :: force(this%space%dim), center(this%space%dim)
1403 character(len=20) frmt
1404
1405 if (.not. this%grp%is_root()) return
1406
1408
1409 call io_mkdir(dir, this%namespace)
1410 iunit = io_open(trim(dir)//'/'//trim(fname)//'.bild', this%namespace, action='write', &
1411 position='asis')
1412
1413 write(frmt,'(a,i0,a)')'(a,2(', this%space%dim,'f16.6,1x))'
1414
1415 write(iunit, '(a)')'.comment : force vectors in ['//trim(units_abbrev(units_out%force))//']'
1416 write(iunit, *)
1417 write(iunit, '(a)')'.color red'
1418 write(iunit, *)
1419 do iatom = 1, this%natoms
1420 center = units_from_atomic(units_out%length, this%pos(:, iatom))
1421 force = units_from_atomic(units_out%force, this%tot_force(:, iatom))
1422 write(iunit, '(a,1x,i4,1x,a2,1x,a6,1x,f10.6,a)') '.comment :', iatom, trim(this%atom(iatom)%label), &
1423 'force:', norm2(force), '['//trim(units_abbrev(units_out%force))//']'
1424 write(iunit,fmt=trim(frmt)) '.arrow', (center(idir), idir = 1, this%space%dim), &
1425 (center(idir) + force(idir), idir = 1, this%space%dim)
1426 write(iunit,*)
1427 end do
1428
1429 call io_close(iunit)
1430
1432 end subroutine ions_write_bild_forces_file
1433
1434 ! -----------------------------------------------------
1435 subroutine ions_write_vtk_geometry(this, filename, ascii)
1436 class(ions_t), intent(in) :: this
1437 character(len=*), intent(in) :: filename
1438 logical, optional, intent(in) :: ascii
1439
1440 integer :: iunit, iatom, ierr
1441 logical :: ascii_
1442 real(real64), allocatable :: data(:, :)
1443 integer, allocatable :: idata(:, :)
1444 character(len=MAX_PATH_LEN) :: fullname
1445
1446 push_sub(ions_write_vtk_geometry)
1447
1448 assert(this%space%dim == 3)
1449
1450 ascii_ = optional_default(ascii, .true.)
1451
1452 fullname = trim(filename)//".vtk"
1453
1454 iunit = io_open(trim(fullname), this%namespace, action='write')
1455
1456 write(iunit, '(1a)') '# vtk DataFile Version 3.0 '
1457 write(iunit, '(6a)') 'Generated by octopus ', trim(conf%version), ' - git: ', &
1458 trim(conf%git_commit), " configuration: ", trim(conf%config_time)
1459
1460 if (ascii_) then
1461 write(iunit, '(1a)') 'ASCII'
1462 else
1463 write(iunit, '(1a)') 'BINARY'
1464 end if
1465
1466 write(iunit, '(1a)') 'DATASET POLYDATA'
1467
1468 write(iunit, '(a,i9,a)') 'POINTS ', this%natoms, ' double'
1469
1470 if (ascii_) then
1471 do iatom = 1, this%natoms
1472 write(iunit, '(3f12.6)') this%pos(1:3, iatom)
1473 end do
1474 else
1475 call io_close(iunit)
1476 safe_allocate(data(1:3, 1:this%natoms))
1477 do iatom = 1, this%natoms
1478 data(1:3, iatom) = this%pos(1:3, iatom)
1479 end do
1480 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(3*this%natoms), data, &
1481 ierr, nohead = .true., fendian = io_binary_is_little_endian())
1482 safe_deallocate_a(data)
1483 iunit = io_open(trim(fullname), this%namespace, action='write', position = 'append')
1484 write(iunit, '(1a)') ''
1485 end if
1486
1487 write(iunit, '(a,2i9)') 'VERTICES ', this%natoms, 2*this%natoms
1488
1489 if (ascii_) then
1490 do iatom = 1, this%natoms
1491 write(iunit, '(2i9)') 1, iatom - 1
1492 end do
1493 else
1494 call io_close(iunit)
1495 safe_allocate(idata(1:2, 1:this%natoms))
1496 do iatom = 1, this%natoms
1497 idata(1, iatom) = 1
1498 idata(2, iatom) = iatom - 1
1499 end do
1500 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(2*this%natoms), idata, &
1501 ierr, nohead = .true., fendian = io_binary_is_little_endian())
1502 safe_deallocate_a(idata)
1503 iunit = io_open(trim(fullname), this%namespace, action='write', position = 'append')
1504 write(iunit, '(1a)') ''
1505 end if
1506
1507 write(iunit, '(a,i9)') 'POINT_DATA', this%natoms
1508 write(iunit, '(a)') 'SCALARS element integer'
1509 write(iunit, '(a)') 'LOOKUP_TABLE default'
1510
1511 if (ascii_) then
1512 do iatom = 1, this%natoms
1513 write(iunit, '(i9)') nint(this%atom(iatom)%species%get_z())
1514 end do
1515 else
1516 call io_close(iunit)
1517
1518 safe_allocate(idata(1:this%natoms, 1))
1519
1520 do iatom = 1, this%natoms
1521 idata(iatom, 1) = nint(this%atom(iatom)%species%get_z())
1522 end do
1523
1524 call io_binary_write(io_workpath(fullname, this%namespace), i4_to_i8(this%natoms), idata, &
1525 ierr, nohead = .true., fendian = io_binary_is_little_endian())
1526
1527 safe_deallocate_a(idata)
1528
1529 iunit = io_open(trim(fullname), this%namespace, action='write', position = 'append')
1530 write(iunit, '(1a)') ''
1531 end if
1532
1533 call io_close(iunit)
1534
1536 end subroutine ions_write_vtk_geometry
1537
1538 ! ---------------------------------------------------------
1539 function ions_current(this) result(current)
1540 class(ions_t), intent(in) :: this
1541 real(real64) :: current(this%space%dim)
1542
1543 integer :: iatom
1544
1545 push_sub(ions_current)
1546
1547 current = m_zero
1548 do iatom = this%atoms_dist%start, this%atoms_dist%end
1549 current = current + p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom)
1550 end do
1551
1552 if (this%atoms_dist%parallel) then
1553 call comm_allreduce(this%atoms_dist%mpi_grp, current, dim=this%space%dim)
1554 end if
1555
1556 pop_sub(ions_current)
1557 end function ions_current
1558
1559 ! ---------------------------------------------------------
1560 function ions_abs_current(this) result(abs_current)
1561 class(ions_t), intent(in) :: this
1562 real(real64) :: abs_current(this%space%dim)
1563
1564 integer :: iatom
1565
1566 push_sub(ions_abs_current)
1567
1568 abs_current = m_zero
1569 do iatom = this%atoms_dist%start, this%atoms_dist%end
1570 abs_current = abs_current + abs(p_proton_charge*this%atom(iatom)%species%get_zval()*this%vel(:,iatom))
1571 end do
1572
1573 if (this%atoms_dist%parallel) then
1574 call comm_allreduce(this%atoms_dist%mpi_grp, abs_current, dim=this%space%dim)
1575 end if
1576
1577 pop_sub(ions_abs_current)
1578 end function ions_abs_current
1579
1580 ! ---------------------------------------------------------
1581 subroutine ions_finalize(ions)
1582 type(ions_t), intent(inout) :: ions
1583
1584 integer :: i
1585
1586 push_sub(ions_finalize)
1587
1588 call distributed_end(ions%atoms_dist)
1589
1590 call ion_interaction_end(ions%ion_interaction)
1591
1592 safe_deallocate_a(ions%atom)
1593 ions%natoms=0
1594
1595 if(allocated(ions%species)) then
1596 do i = 1, ions%nspecies
1597 !SAFE_ DEALLOCATE_P(ions%species(i)%s)
1598 if(associated(ions%species(i)%s)) deallocate(ions%species(i)%s)
1599 end do
1600 deallocate(ions%species)
1601 end if
1602 ions%nspecies=0
1603
1604 safe_deallocate_a(ions%pos_displacements)
1605 safe_deallocate_a(ions%vel_displacements)
1606
1607 call charged_particles_end(ions)
1608
1609 safe_deallocate_a(ions%map_symm_atoms)
1610 safe_deallocate_a(ions%inv_map_symm_atoms)
1611
1612
1613 pop_sub(ions_finalize)
1614 end subroutine ions_finalize
1615
1616 !-------------------------------------------------------------------
1619 subroutine ions_update_lattice_vectors(ions, latt, symmetrize)
1620 class(ions_t), intent(inout) :: ions
1621 type(lattice_vectors_t), intent(in) :: latt
1622 logical, intent(in) :: symmetrize
1623
1625
1626 ! Update the lattice vectors
1627 call ions%latt%update(latt%rlattice)
1628
1629 ! Regenerate symmetries in Cartesian space
1630 if (symmetrize) then
1631 call symmetries_update_lattice_vectors(ions%symm, latt, ions%space%dim)
1632 end if
1633
1635 end subroutine ions_update_lattice_vectors
1636
1637 !-------------------------------------------------------------------
1644 class(ions_t), intent(inout) :: ions
1645
1646 integer :: iatom, iop, iatom_symm, dim4symms
1647 real(real64) :: ratom(ions%space%dim)
1648
1650
1651 safe_allocate(ions%map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1652 safe_allocate(ions%inv_map_symm_atoms(1:ions%natoms, 1:ions%symm%nops + ions%symm%nops_nonsymmorphic))
1653
1654 ! In the 4D case, symmetries are only defined in 3D, see symmetries.F90
1655 dim4symms = min(3, ions%space%dim)
1656 ratom = m_zero
1657
1658 do iop = 1, ions%symm%nops
1659 do iatom = 1, ions%natoms
1660 !We find the atom that correspond to this one, once symmetry is applied
1661 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom))
1662
1663 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1664
1665 ! find iatom_symm
1666 do iatom_symm = 1, ions%natoms
1667 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec)) exit
1668 end do
1669
1670 if (iatom_symm > ions%natoms) then
1671 write(message(1),'(a,i6)') 'Internal error: could not find symmetric partner for atom number', iatom
1672 write(message(2),'(a,i3,a)') 'with symmetry operation number ', iop, '.'
1673 call messages_fatal(2, namespace=ions%namespace)
1674 end if
1675
1676 ions%map_symm_atoms(iatom, iop) = iatom_symm
1677 ions%inv_map_symm_atoms(iatom_symm, iop) = iatom
1678 end do
1679 end do
1680
1681 ! Also build a map for non-symmorphic operations
1682 do iop = 1, ions%symm%nops_nonsymmorphic
1683 do iatom = 1, ions%natoms
1684 !We find the atom that correspond to this one, once symmetry is applied
1685 ratom(1:dim4symms) = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom))
1686
1687 ratom(:) = ions%latt%fold_into_cell(ratom(:))
1688
1689 ! find iatom_symm
1690 do iatom_symm = 1, ions%natoms
1691 if (all(abs(ratom(:) - ions%pos(:, iatom_symm)) < symprec)) exit
1692 end do
1693
1694 if (iatom_symm > ions%natoms) then
1695 write(message(1),'(a,i6)') 'Internal error: could not find symmetric partner for atom number', iatom
1696 write(message(2),'(a,i3,a)') 'with symmetry operation number ', iop, '.'
1697 call messages_fatal(2, namespace=ions%namespace)
1698 end if
1699
1700 ions%map_symm_atoms(iatom, ions%symm%nops+iop) = iatom_symm
1701 ions%inv_map_symm_atoms(iatom_symm, ions%symm%nops+iop) = iatom
1702 end do
1703 end do
1704
1705
1708
1709 !-------------------------------------------------------------------
1713 subroutine ions_symmetrize_atomic_coord(ions)
1714 class(ions_t), intent(inout) :: ions
1715
1716 integer :: iatom, iop, iatom_sym
1717 real(real64) :: ratom(ions%space%dim)
1718 real(real64), allocatable :: new_pos(:,:)
1719
1721
1722 safe_allocate(new_pos(1:ions%space%dim, 1:ions%natoms))
1723
1724 do iatom = 1, ions%natoms
1725 new_pos(:, iatom) = m_zero
1726
1727 ! Symmorphic operations
1728 do iop = 1, ions%symm%nops
1729 iatom_sym = ions%inv_map_symm_atoms(iatom, iop)
1730 ratom = symm_op_apply_inv_cart(ions%symm%ops(iop), ions%pos(:, iatom_sym))
1731 ratom = ions%latt%fold_into_cell(ratom)
1732 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1733 end do
1734
1735 ! Non-symmorphic operations
1736 do iop = 1, ions%symm%nops_nonsymmorphic
1737 iatom_sym = ions%inv_map_symm_atoms(iatom, iop + ions%symm%nops)
1738 ratom = symm_op_apply_inv_cart(ions%symm%non_symmorphic_ops(iop), ions%pos(:, iatom_sym))
1739 ratom = ions%latt%fold_into_cell(ratom)
1740 new_pos(:, iatom) = new_pos(:, iatom) + ratom
1741 end do
1742
1743 new_pos(:, iatom) = new_pos(:, iatom) / (ions%symm%nops + ions%symm%nops_nonsymmorphic)
1744 end do
1745
1746 ions%pos = new_pos
1747
1749 end subroutine ions_symmetrize_atomic_coord
1750
1752 subroutine ions_print_spacegroup(ions)
1753 class(ions_t), intent(inout) :: ions
1754
1755 type(spglibdataset) :: spg_dataset
1756 character(len=11) :: symbol
1757 integer, allocatable :: site_type(:)
1758 integer :: space_group, ia
1759
1760 if(.not. ions%space%is_periodic()) return
1761
1762 push_sub(ions_print_spacegroup)
1763
1764 safe_allocate(site_type(1:ions%natoms))
1765 do ia = 1, ions%natoms
1766 site_type(ia) = ions%atom(ia)%species%get_index()
1767 end do
1768
1769 spg_dataset = symmetries_get_spg_dataset(ions%namespace, ions%space, ions%latt, ions%natoms, ions%pos, site_type)
1770
1771 safe_deallocate_a(site_type)
1772
1773 if (spg_dataset%spglib_error /= 0) then
1774 pop_sub(ions_print_spacegroup)
1775 return
1776 end if
1777
1778 space_group = spg_dataset%spacegroup_number
1779 symbol = spg_dataset%international_symbol
1780
1781 write(message(1),'(a, i4)') 'Info: Space group No. ', space_group
1782 write(message(2),'(2a)') 'Info: International: ', trim(symbol)
1783 call messages_info(2, namespace=ions%namespace)
1784
1785 pop_sub(ions_print_spacegroup)
1786 end subroutine ions_print_spacegroup
1787
1788end module ions_oct_m
1789
1790!! Local Variables:
1791!! mode: f90
1792!! coding: utf-8
1793!! End:
--------------— axpy ---------------— Constant times a vector plus a vector.
Definition: blas.F90:178
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)
Definition: ions.F90:1228
subroutine, public atom_init(this, dim, label, species)
Definition: atom.F90:150
subroutine, public atom_get_species(this, species)
Definition: atom.F90:260
subroutine, public atom_set_species(this, species)
Definition: atom.F90:248
This module contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:120
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
Definition: global.F90:218
real(real64), parameter, public m_zero
Definition: global.F90:200
character(len= *), parameter, public static_dir
Definition: global.F90:279
real(real64), parameter, public p_kb
Boltzmann constant in Ha/K.
Definition: global.F90:241
real(real64), parameter, public m_half
Definition: global.F90:206
real(real64), parameter, public m_one
Definition: global.F90:201
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
Definition: io.F90:116
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:361
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:695
subroutine ions_update_lattice_vectors(ions, latt, symmetrize)
Regenerate the ions information after update of the lattice vectors.
Definition: ions.F90:1715
subroutine ions_fold_atoms_into_cell(this)
Definition: ions.F90:1013
subroutine ions_single_mode_displacements(ions, mode, amplitude_pos, amplitude_vel)
apply initial displacements and velocities corresponding to a given phonon mode
Definition: ions.F90:871
real(real64) function, dimension(this%space%dim) ions_global_force(this, time)
Definition: ions.F90:1270
subroutine ions_copy(ions_out, ions_in)
Definition: ions.F90:647
real(real64) function, dimension(this%space%dim) ions_current(this)
Definition: ions.F90:1635
subroutine ions_update_quantity(this, label)
Definition: ions.F90:966
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:1739
subroutine ions_write_xyz(this, fname, append, comment, reduce_coordinates)
Definition: ions.F90:1287
subroutine ions_init_species(ions, factory, print_info)
Definition: ions.F90:534
subroutine ions_finalize(ions)
Definition: ions.F90:1677
subroutine ions_initialize(this)
Definition: ions.F90:952
class(ions_t) function, pointer ions_constructor(namespace, grp, print_info, latt_inp, shared_namespace)
Definition: ions.F90:242
real(real64) function, dimension(this%space%dim) ions_abs_current(this)
Definition: ions.F90:1656
subroutine ions_read_xyz(this, fname, comment)
Definition: ions.F90:1386
subroutine ions_write_vtk_geometry(this, filename, ascii)
Definition: ions.F90:1531
subroutine ions_rotate(this, from, from2, to)
Definition: ions.F90:1156
subroutine ions_translate(this, xx)
Definition: ions.F90:1140
subroutine ions_symmetrize_atomic_coord(ions)
Symmetrizes atomic coordinates by applying all symmetries.
Definition: ions.F90:1809
subroutine ions_print_spacegroup(ions)
Prints the spacegroup of the system for periodic systems.
Definition: ions.F90:1848
real(real64) function ions_min_distance(this, real_atoms_only)
Definition: ions.F90:1028
subroutine ions_init_random_displacements(ions, T)
create random displacements for positions and velocities
Definition: ions.F90:718
real(real64) function, dimension(this%space%dim) ions_dipole(this, mask)
Definition: ions.F90:1118
subroutine ions_write_bild_forces_file(this, dir, fname)
Definition: ions.F90:1493
subroutine ions_write_crystal(this, dir)
This subroutine creates a crystal by replicating the geometry and writes the result to dir.
Definition: ions.F90:1459
logical function ions_has_time_dependent_species(this)
Definition: ions.F90:1091
subroutine ions_partition(this, mc)
Definition: ions.F90:679
subroutine ions_init_interaction_as_partner(partner, interaction)
Definition: ions.F90:982
subroutine ions_copy_quantities_to_interaction(partner, interaction)
Definition: ions.F90:997
subroutine ions_write_poscar(this, fname, comment)
Writes the positions of the ions in POSCAR format.
Definition: ions.F90:1340
real(real64) function ions_val_charge(this, mask)
Definition: ions.F90:1102
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:898
character(len=512), private msg
Definition: messages.F90:167
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1000
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1040
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
subroutine mpi_grp_copy(mpi_grp_out, mpi_grp_in)
MPI_THREAD_FUNNELED allows for calls to MPI from an OMP region if the thread is the team master.
Definition: mpi.F90:383
subroutine mpi_grp_init(grp, comm)
Initialize MPI group instance.
Definition: mpi.F90:341
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:463
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.
Definition: system.F90:120
subroutine, public system_init_parallelization(this, grp)
Basic functionality: copy the MPI group. This function needs to be implemented by extended types that...
Definition: system.F90:1243
subroutine, public tdf_read(f, namespace, function_name, ierr)
This function initializes "f" from the TDFunctions block.
Definition: tdfunction.F90:220
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:225
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.
Definition: multicomm.F90:208
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...
Definition: species.F90:147
Class describing a Wigner distribution for sampling initial conditions in multi-trajectory Ehrenfest ...
int true(void)