33 use,
intrinsic :: iso_fortran_env
68 integer,
parameter :: &
69 OUTPUT_COORDINATES = 1, &
74 type(c_ptr),
public :: output_handle(2)
75 type(space_t),
public :: space
77 real(real64),
allocatable,
public :: mass(:)
78 real(real64),
allocatable,
public :: pos(:,:)
79 real(real64),
allocatable,
public :: vel(:,:)
80 real(real64),
allocatable,
public :: tot_force(:,:)
81 real(real64),
allocatable,
public :: lj_epsilon(:)
82 real(real64),
allocatable,
public :: lj_sigma(:)
83 logical,
allocatable,
public :: fixed(:)
84 type(propagator_data_t),
public :: prop_data
114 class(classical_particles_t),
intent(inout) :: this
115 integer,
intent(in) :: np
120 safe_allocate(this%mass(1:np))
122 safe_allocate(this%pos(1:this%space%dim, 1:np))
124 safe_allocate(this%vel(1:this%space%dim, 1:np))
126 safe_allocate(this%tot_force(1:this%space%dim, 1:np))
128 safe_allocate(this%fixed(1:np))
130 safe_allocate(this%lj_epsilon(1:np))
132 safe_allocate(this%lj_sigma(1:np))
137 allocate(this%supported_interactions(0))
138 allocate(this%supported_interactions_as_partner(0))
143 this%quantities(
position)%updated_on_demand = .false.
144 this%quantities(
velocity)%updated_on_demand = .false.
147 this%quantities(
mass)%updated_on_demand = .false.
148 this%quantities(
mass)%always_available = .
true.
155 class(classical_particles_t),
intent(out) :: this
156 class(classical_particles_t),
intent(in) :: cp_in
161 safe_allocate_source_a(this%mass, cp_in%mass)
162 safe_allocate_source_a(this%pos, cp_in%pos)
163 safe_allocate_source_a(this%vel, cp_in%vel)
164 safe_allocate_source_a(this%tot_force, cp_in%tot_force)
165 safe_allocate_source_a(this%fixed, cp_in%fixed)
167 this%kinetic_energy = cp_in%kinetic_energy
169 this%quantities = cp_in%quantities
170 this%supported_interactions = cp_in%supported_interactions
172 this%quantities(
mass)%updated_on_demand = .false.
174 this%prop_data = cp_in%prop_data
186 select type (interaction)
188 message(1) =
"Trying to initialize an unsupported interaction by classical particles."
199 integer,
allocatable,
intent(out) :: updated_quantities(:)
202 real(real64),
allocatable :: tmp_pos(:,:,:), tmp_vel(:,:,:)
203 real(real64) :: factor
209 select type (prop => this%algo)
212 select case (operation%id)
214 this%prop_data%save_pos(:, 1:this%np) = this%pos(:, 1:this%np)
215 this%prop_data%save_vel(:, 1:this%np) = this%vel(:, 1:this%np)
218 if (.not. this%prop_data%initialized)
then
219 call this%prop_data%initialize(prop, this%space%dim, this%np)
221 if (this%fixed(ip))
then
222 this%prop_data%acc(:, ip) =
m_zero
224 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
230 call this%prop_data%end()
233 call this%prop_data%end()
236 this%pos(:, 1:this%np) = this%pos(:, 1:this%np) + prop%dt * this%vel(:, 1:this%np) &
237 +
m_half * prop%dt**2 * this%prop_data%acc(:, 1:this%np)
241 do ii =
size(this%prop_data%prev_acc, dim=3) - 1, 1, -1
242 this%prop_data%prev_acc(:, 1:this%np, ii + 1) = this%prop_data%prev_acc(:, 1:this%np, ii)
245 this%prop_data%prev_acc(:, ip, 1) = this%prop_data%acc(:, ip)
246 if (this%fixed(ip))
then
249 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
254 this%vel(:, 1:this%np) = this%vel(:, 1:this%np) &
255 +
m_half * prop%dt * (this%prop_data%prev_acc(:, 1:this%np, 1) + this%prop_data%acc(:, 1:this%np))
259 if (.not. this%prop_data%initialized)
then
260 call this%prop_data%initialize(prop, this%space%dim, this%np)
262 if (this%fixed(ip))
then
263 this%prop_data%acc(:, ip) =
m_zero
265 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
267 this%prop_data%prev_acc(:, ip, 1) = this%prop_data%acc(:, ip)
272 this%pos(:, 1:this%np) = this%pos(:, 1:this%np) + prop%dt * this%vel(:, 1:this%np) + &
273 m_one/6.0_real64 * prop%dt**2 * (
m_four*this%prop_data%acc(:, 1:this%np) - this%prop_data%prev_acc(:, 1:this%np, 1))
275 if (.not. prop%predictor_corrector)
then
280 this%vel(:, 1:this%np) = this%vel(:, 1:this%np) + &
281 m_one/6.0_real64 * prop%dt * (
m_two * this%prop_data%acc(:, 1:this%np) + &
282 5.0_real64 * this%prop_data%prev_acc(:, 1:this%np, 1) - this%prop_data%prev_acc(:, 1:this%np, 2))
286 this%pos(:, 1:this%np) = this%prop_data%save_pos(:, 1:this%np) &
287 + prop%dt * this%prop_data%save_vel(:, 1:this%np) &
288 +
m_one/6.0_real64 * prop%dt**2 * (this%prop_data%acc(:, 1:this%np) &
289 +
m_two * this%prop_data%prev_acc(:, 1:this%np, 1))
293 this%vel(:, 1:this%np) = this%prop_data%save_vel(:, 1:this%np) &
294 +
m_half * prop%dt * (this%prop_data%acc(:, 1:this%np) + this%prop_data%prev_acc(:, 1:this%np, 1))
298 if (.not. this%prop_data%initialized)
then
299 call this%prop_data%initialize(prop, this%space%dim, this%np)
300 this%prop_data%prev_pos(:, 1:this%np, 1) = this%pos(:, 1:this%np)
301 this%prop_data%prev_vel(:, 1:this%np, 1) = this%vel(:, 1:this%np)
305 call this%prop_data%end()
308 this%pos(:, 1:this%np) = 1.5_real64*this%prop_data%save_pos(:, 1:this%np) &
309 -
m_half*this%prop_data%prev_pos(:, 1:this%np, 1)
310 this%vel(:, 1:this%np) = 1.5_real64*this%prop_data%save_vel(:, 1:this%np) &
311 -
m_half*this%prop_data%prev_vel(:, 1:this%np, 1)
312 this%prop_data%prev_pos(:, 1:this%np, 1) = this%prop_data%save_pos(:, 1:this%np)
313 this%prop_data%prev_vel(:, 1:this%np, 1) = this%prop_data%save_vel(:, 1:this%np)
318 if (this%fixed(ip))
then
319 this%prop_data%hamiltonian_elements(:, ip) =
m_zero
321 this%prop_data%hamiltonian_elements(:, ip) = this%tot_force(:, ip) / (this%mass(ip) * this%pos(:, ip) +
m_epsilon)
326 safe_allocate(tmp_pos(1:this%space%dim, 1:this%np, 1:2))
327 safe_allocate(tmp_vel(1:this%space%dim, 1:this%np, 1:2))
333 tmp_pos(:, 1:this%np, 1) = this%prop_data%save_pos(:, 1:this%np)
334 tmp_vel(:, 1:this%np, 1) = this%prop_data%save_vel(:, 1:this%np)
335 this%pos(:, 1:this%np) = this%prop_data%save_pos(:, 1:this%np)
336 this%vel(:, 1:this%np) = this%prop_data%save_vel(:, 1:this%np)
340 factor = factor * prop%dt / ii
343 tmp_pos(:, ip, 2) = tmp_vel(:, ip, 1)
344 tmp_vel(:, ip, 2) = this%prop_data%hamiltonian_elements(:, ip) * tmp_pos(:, ip, 1)
346 tmp_pos(:, ip, 1) = tmp_pos(:, ip, 2)
347 tmp_vel(:, ip, 1) = tmp_vel(:, ip, 2)
349 this%pos(:, ip) = this%pos(:, ip) + factor * tmp_pos(:, ip, 1)
350 this%vel(:, ip) = this%vel(:, ip) + factor * tmp_vel(:, ip, 1)
353 safe_deallocate_a(tmp_pos)
354 safe_deallocate_a(tmp_vel)
359 if (.not. this%is_tolerance_reached(prop%scf_tol))
then
360 this%pos(:, 1:this%np) =
m_half*(this%pos(:, 1:this%np) + this%prop_data%save_pos(:, 1:this%np))
361 this%vel(:, 1:this%np) =
m_half*(this%vel(:, 1:this%np) + this%prop_data%save_vel(:, 1:this%np))
371 call profiling_out(trim(this%namespace%get())//
":"//trim(operation%id))
378 real(real64),
intent(in) :: tol
381 real(real64) :: change, max_change
388 change = sum((this%prop_data%prev_tot_force(1:this%space%dim, ip) - this%tot_force(1:this%space%dim, ip))**2) / &
390 if (change > max_change)
then
394 converged = max_change < tol**2
397 write(
message(1),
'(a, e13.6, a, e13.6)')
"Debug: -- Maximum change in acceleration ", &
398 sqrt(max_change),
" and tolerance ", tol
408 integer,
intent(in) :: iq
413 assert(this%quantities(iq)%updated_on_demand)
417 message(1) =
"Incompatible quantity."
431 select type (interaction)
433 message(1) =
"Unsupported interaction."
447 select type (interaction)
449 message(1) =
"Unsupported interaction."
463 select type (prop => this%algo)
465 if (prop%predictor_corrector)
then
466 this%prop_data%prev_tot_force(1:this%space%dim, 1:this%np) = this%tot_force(1:this%space%dim, 1:this%np)
482 this%tot_force(1:this%space%dim, 1:this%np) =
m_zero
483 call iter%start(this%interactions)
484 do while (iter%has_next())
485 select type (interaction => iter%get_next())
487 this%tot_force(1:this%space%dim, 1:this%np) = this%tot_force(1:this%space%dim, 1:this%np) + &
488 interaction%force(1:this%space%dim, 1:this%np)
504 select type (algo => this%algo)
509 iteration = this%iteration%counter()
510 if (iteration > 0)
then
512 iteration = iteration + 1
515 call io_mkdir(
'td.general', this%namespace)
517 call write_iter_init(this%output_handle(output_coordinates), iteration, dt, &
520 trim(
io_workpath(
"td.general/energy", this%namespace)))
524 if (iteration == 0)
then
525 call this%output_write()
549 integer :: idir, ii, ip
550 character(len=50) :: aux
551 real(real64) :: tmp(this%space%dim)
557 if (this%iteration%counter() == 0)
then
561 '############################################################################')
569 do idir = 1, this%space%dim
570 write(aux,
'(a2,i3,a1,i3,a1)')
'x(', ip,
',', idir,
')'
575 do idir = 1, this%space%dim
576 write(aux,
'(a2,i3,a1,i3,a1)')
'v(', ip,
',', idir,
')'
581 do idir = 1, this%space%dim
582 write(aux,
'(a2,i3,a1,i3,a1)')
'f(', ip,
',', idir,
')'
592 do idir = 1, this%space%dim
597 do idir = 1, this%space%dim
602 do idir = 1, this%space%dim
609 '############################################################################')
618 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
623 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
628 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
634 if (this%iteration%counter() == 0)
then
638 '############################################################################')
660 '############################################################################')
678 integer :: restart_file_unit
687 call profiling_in(trim(this%namespace%get())//
":"//
"RESTART_WRITE")
690 restart_file_unit =
io_open(
'restart/'//
td_dir//
'restart_classical_particles', this%namespace, action=
'write')
691 write(restart_file_unit, *) this%np
692 write(restart_file_unit, *) this%mass(:)
693 write(restart_file_unit, *) this%pos(:,:)
694 write(restart_file_unit, *) this%vel(:,:)
695 write(restart_file_unit, *) this%tot_force(:,:)
698 if (this%iteration%counter() > 0)
then
700 call this%prop_data%restart_write(this%namespace, this%algo)
703 message(1) =
"Successfully wrote restart data for system "//trim(this%namespace%get())
706 call profiling_out(trim(this%namespace%get())//
":"//
"RESTART_WRITE")
714 integer :: restart_file_unit
717 call profiling_in(trim(this%namespace%get())//
":"//
"RESTART_READ")
720 restart_file_unit =
io_open(
'restart/'//
td_dir//
'restart_classical_particles', this%namespace, action=
'read', die=.false.)
721 if (restart_file_unit > 0)
then
722 read(restart_file_unit, *) this%np
723 read(restart_file_unit, *) this%mass(:)
724 read(restart_file_unit, *) this%pos(:,:)
725 read(restart_file_unit, *) this%vel(:,:)
726 read(restart_file_unit, *) this%tot_force(:,:)
728 call this%prop_data%initialize(this%algo, this%space%dim, this%np)
729 if (this%iteration%counter() > 0)
then
741 message(1) =
"Successfully read restart data for system "//trim(this%namespace%get())
746 call profiling_out(trim(this%namespace%get())//
":"//
"RESTART_READ")
758 this%kinetic_energy =
m_zero
760 this%kinetic_energy = this%kinetic_energy +
m_half * this%mass(ip) * sum(this%vel(:, ip)**2)
769 logical,
optional,
intent(in) :: mask(:)
770 logical,
optional,
intent(in) :: pseudo
771 real(real64) :: pos(this%space%dim)
773 real(real64) ::
mass, total_mass
778 assert(.not. this%space%is_periodic())
784 if (
present(mask))
then
785 if (.not. mask(ip)) cycle
790 pos = pos +
mass*this%pos(:, ip)
791 total_mass = total_mass +
mass
801 real(real64) :: vel(this%space%dim)
803 real(real64) ::
mass, total_mass
812 total_mass = total_mass +
mass
813 vel = vel +
mass*this%vel(:, ip)
823 real(real64) :: pos(this%space%dim)
825 real(real64) :: xmin(this%space%dim), xmax(this%space%dim)
833 do idir = 1, this%space%dim
834 if (this%pos(idir, ip) > xmax(idir)) xmax(idir) = this%pos(idir, ip)
835 if (this%pos(idir, ip) < xmin(idir)) xmin(idir) = this%pos(idir, ip)
839 pos = (xmax + xmin)/
m_two
847 real(real64),
intent(out) :: x(this%space%dim)
848 real(real64),
intent(out) :: x2(this%space%dim)
851 real(real64) :: rmax, r, r2
855 assert(.not. this%space%is_periodic())
860 do jp = 1, this%np/2 + 1
861 r = norm2(this%pos(:, ip) - this%pos(:, jp))
864 x = this%pos(:, ip) - this%pos(:, jp)
873 r2 = sum(x * this%pos(:, ip))
874 r = norm2(this%pos(:, ip) - r2*x)
877 x2 = this%pos(:, ip) - r2*x
889 real(real64),
intent(out) :: x(this%space%dim)
890 real(real64),
intent(out) :: x2(this%space%dim)
891 logical,
intent(in) :: pseudo
893 real(real64) ::
mass, tinertia(this%space%dim, this%space%dim), eigenvalues(this%space%dim)
894 integer :: ii, jj, ip
899 assert(.not. this%space%is_periodic())
905 if (.not. pseudo)
mass = this%mass(ip)
906 do ii = 1, this%space%dim
907 tinertia(ii, :) = tinertia(ii, :) -
mass*this%pos(ii, ip)*this%pos(:, ip)
908 tinertia(ii, ii) = tinertia(ii, ii) +
mass*sum(this%pos(:, ip)**2)
915 write(
message(1),
'(a)')
'Moment of pseudo-inertia tensor [' // trim(
units_abbrev(unit)) //
']'
917 write(
message(1),
'(a)')
'Moment of inertia tensor [amu*' // trim(
units_abbrev(unit)) //
']'
920 call output_tensor(tinertia, this%space%dim, unit, write_average = .
true., namespace=this%namespace)
929 jj = maxloc(abs(tinertia(:,ii)), dim = 1)
930 if (tinertia(jj,ii) <
m_zero) tinertia(:,ii) = -tinertia(:,ii)
944 safe_deallocate_a(this%mass)
945 safe_deallocate_a(this%pos)
946 safe_deallocate_a(this%vel)
947 safe_deallocate_a(this%tot_force)
948 safe_deallocate_a(this%fixed)
949 safe_deallocate_a(this%lj_epsilon)
950 safe_deallocate_a(this%lj_sigma)
Writes to the corresponding file and adds one to the iteration. Must be called after write_iter_init(...
This module implements the basic elements defining algorithms.
subroutine classical_particles_output_finish(this)
subroutine classical_particles_axis_large(this, x, x2)
logical function classical_particles_is_tolerance_reached(this, tol)
subroutine classical_particles_output_write(this)
integer, parameter output_energy
logical function classical_particles_do_algorithmic_operation(this, operation, updated_quantities)
subroutine classical_particles_update_kinetic_energy(this)
subroutine classical_particles_axis_inertia(this, x, x2, pseudo)
This subroutine assumes that the origin of the coordinates is the center of mass of the system.
subroutine classical_particles_output_start(this)
logical function classical_particles_restart_read_data(this)
subroutine, public classical_particles_init_interaction_as_partner(partner, interaction)
subroutine, public classical_particles_end(this)
subroutine, public classical_particles_init(this, np)
The init routine is a module level procedure This has the advantage that different classes can have d...
subroutine, public classical_particles_copy(this, cp_in)
subroutine classical_particles_update_interactions_finish(this)
subroutine, public classical_particles_update_quantity(this, iq)
subroutine classical_particles_update_interactions_start(this)
subroutine, public classical_particles_copy_quantities_to_interaction(partner, interaction)
real(real64) function, dimension(this%space%dim) classical_particles_center_of_mass_vel(this)
subroutine, public classical_particles_init_interaction(this, interaction)
subroutine, public classical_particles_restart_write_data(this)
real(real64) function, dimension(this%space%dim) classical_particles_center_of_mass(this, mask, pseudo)
real(real64) function, dimension(this%space%dim) classical_particles_center(this)
type(debug_t), save, public debug
real(real64), parameter, public m_two
real(real64), parameter, public m_huge
real(real64), parameter, public m_zero
real(real64), parameter, public m_four
real(real64), parameter, public m_epsilon
character(len= *), parameter, public td_dir
real(real64), parameter, public m_half
real(real64), parameter, public m_one
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
subroutine, public io_close(iunit, grp)
character(len=max_path_len) function, public io_workpath(path, namespace)
subroutine, public io_mkdir(fname, namespace, parents)
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
logical function mpi_grp_is_root(grp)
Is the current MPI process of grpcomm, root.
This module implements the multisystem debug functionality.
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
character(len=algo_label_len), parameter, public beeman_start
character(len=algo_label_len), parameter, public beeman_finish
character(len=algo_label_len), parameter, public beeman_compute_acc
character(len=algo_label_len), parameter, public beeman_correct_pos
character(len=algo_label_len), parameter, public beeman_predict_pos
character(len=algo_label_len), parameter, public beeman_correct_vel
character(len=algo_label_len), parameter, public beeman_predict_vel
character(len=algo_label_len), parameter, public expmid_2step_predict_dt
character(len=algo_label_len), parameter, public expmid_2step_finish
character(len=algo_label_len), parameter, public expmid_2step_correct_dt_2
character(len=algo_label_len), parameter, public update_hamiltonian
character(len=algo_label_len), parameter, public expmid_2step_predict_dt_2
character(len=algo_label_len), parameter, public expmid_2step_start
This module implements the basic propagator framework.
character(len=algo_label_len), parameter, public store_current_status
character(len=30), parameter, public verlet_start
character(len=30), parameter, public verlet_compute_acc
character(len=30), parameter, public verlet_update_pos
character(len=30), parameter, public verlet_finish
character(len=30), parameter, public verlet_compute_vel
This module defines the quantity_t class and the IDs for quantities, which can be exposed by a system...
integer, parameter, public velocity
integer, parameter, public position
integer, parameter, public mass
This module implements the abstract system type.
subroutine, public system_end(this)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
character(len=20) pure function, public units_abbrev(this)
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
This module is intended to contain simple general-purpose utility functions and procedures.
subroutine, public output_tensor(tensor, ndim, unit, write_average, iunit, namespace)
Explicit interfaces to C functions, defined in write_iter_low.cc.
Descriptor of one algorithmic operation.
These class extend the list and list iterator to make an interaction list.
surrogate interaction class to avoid circular dependencies between modules.
Abstract class implementing propagators.
Abstract class for systems.