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(:)
85 type(propagator_data_t),
public :: prop_data
115 class(classical_particles_t),
intent(inout) :: this
116 integer,
intent(in) :: np
121 safe_allocate(this%mass(1:np))
123 safe_allocate(this%pos(1:this%space%dim, 1:np))
125 safe_allocate(this%vel(1:this%space%dim, 1:np))
127 safe_allocate(this%tot_force(1:this%space%dim, 1:np))
129 safe_allocate(this%fixed(1:np))
131 safe_allocate(this%lj_epsilon(1:np))
133 safe_allocate(this%lj_sigma(1:np))
138 allocate(this%supported_interactions(0))
139 allocate(this%supported_interactions_as_partner(0))
142 call this%quantities%add(
quantity_t(
"position", updated_on_demand = .false.))
143 call this%quantities%add(
quantity_t(
"velocity", updated_on_demand = .false.))
146 call this%quantities%add(
quantity_t(
"mass", updated_on_demand = .false., always_available=.
true.))
153 class(classical_particles_t),
intent(out) :: this
154 class(classical_particles_t),
intent(in) :: cp_in
159 safe_allocate_source_a(this%mass, cp_in%mass)
160 safe_allocate_source_a(this%pos, cp_in%pos)
161 safe_allocate_source_a(this%vel, cp_in%vel)
162 safe_allocate_source_a(this%tot_force, cp_in%tot_force)
163 safe_allocate_source_a(this%fixed, cp_in%fixed)
165 this%kinetic_energy = cp_in%kinetic_energy
167 this%quantities = cp_in%quantities
168 this%supported_interactions = cp_in%supported_interactions
170 this%prop_data = cp_in%prop_data
182 select type (interaction)
184 message(1) =
"Trying to initialize an unsupported interaction by classical particles."
195 character(len=:),
allocatable,
intent(out) :: updated_quantities(:)
198 real(real64),
allocatable :: tmp_pos(:,:,:), tmp_vel(:,:,:)
199 real(real64) :: factor
202 call profiling_in(trim(this%namespace%get())//
":"//trim(operation%id))
205 select type (prop => this%algo)
208 select case (operation%id)
210 this%prop_data%save_pos(:, 1:this%np) = this%pos(:, 1:this%np)
211 this%prop_data%save_vel(:, 1:this%np) = this%vel(:, 1:this%np)
214 if (.not. this%prop_data%initialized)
then
215 call this%prop_data%initialize(prop, this%space%dim, this%np)
217 if (this%fixed(ip))
then
218 this%prop_data%acc(:, ip) =
m_zero
220 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
226 call this%prop_data%end()
229 call this%prop_data%end()
232 this%pos(:, 1:this%np) = this%pos(:, 1:this%np) + prop%dt * this%vel(:, 1:this%np) &
233 +
m_half * prop%dt**2 * this%prop_data%acc(:, 1:this%np)
234 updated_quantities = [
"position"]
237 do ii =
size(this%prop_data%prev_acc, dim=3) - 1, 1, -1
238 this%prop_data%prev_acc(:, 1:this%np, ii + 1) = this%prop_data%prev_acc(:, 1:this%np, ii)
241 this%prop_data%prev_acc(:, ip, 1) = this%prop_data%acc(:, ip)
242 if (this%fixed(ip))
then
243 this%prop_data%acc(:, ip) =
m_zero
245 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
250 this%vel(:, 1:this%np) = this%vel(:, 1:this%np) &
251 +
m_half * prop%dt * (this%prop_data%prev_acc(:, 1:this%np, 1) + this%prop_data%acc(:, 1:this%np))
252 updated_quantities = [
"velocity"]
255 if (.not. this%prop_data%initialized)
then
256 call this%prop_data%initialize(prop, this%space%dim, this%np)
258 if (this%fixed(ip))
then
259 this%prop_data%acc(:, ip) =
m_zero
261 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
263 this%prop_data%prev_acc(:, ip, 1) = this%prop_data%acc(:, ip)
268 this%pos(:, 1:this%np) = this%pos(:, 1:this%np) + prop%dt * this%vel(:, 1:this%np) + &
269 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))
271 if (.not. prop%predictor_corrector)
then
272 updated_quantities = [
"position"]
276 this%vel(:, 1:this%np) = this%vel(:, 1:this%np) + &
277 m_one/6.0_real64 * prop%dt * (
m_two * this%prop_data%acc(:, 1:this%np) + &
278 5.0_real64 * this%prop_data%prev_acc(:, 1:this%np, 1) - this%prop_data%prev_acc(:, 1:this%np, 2))
279 updated_quantities = [
"velocity"]
282 this%pos(:, 1:this%np) = this%prop_data%save_pos(:, 1:this%np) &
283 + prop%dt * this%prop_data%save_vel(:, 1:this%np) &
284 +
m_one/6.0_real64 * prop%dt**2 * (this%prop_data%acc(:, 1:this%np) &
285 +
m_two * this%prop_data%prev_acc(:, 1:this%np, 1))
286 updated_quantities = [
"position"]
289 this%vel(:, 1:this%np) = this%prop_data%save_vel(:, 1:this%np) &
290 +
m_half * prop%dt * (this%prop_data%acc(:, 1:this%np) + this%prop_data%prev_acc(:, 1:this%np, 1))
291 updated_quantities = [
"velocity"]
294 if (.not. this%prop_data%initialized)
then
295 call this%prop_data%initialize(prop, this%space%dim, this%np)
296 this%prop_data%prev_pos(:, 1:this%np, 1) = this%pos(:, 1:this%np)
297 this%prop_data%prev_vel(:, 1:this%np, 1) = this%vel(:, 1:this%np)
301 call this%prop_data%end()
304 this%pos(:, 1:this%np) = 1.5_real64*this%prop_data%save_pos(:, 1:this%np) &
305 -
m_half*this%prop_data%prev_pos(:, 1:this%np, 1)
306 this%vel(:, 1:this%np) = 1.5_real64*this%prop_data%save_vel(:, 1:this%np) &
307 -
m_half*this%prop_data%prev_vel(:, 1:this%np, 1)
308 this%prop_data%prev_pos(:, 1:this%np, 1) = this%prop_data%save_pos(:, 1:this%np)
309 this%prop_data%prev_vel(:, 1:this%np, 1) = this%prop_data%save_vel(:, 1:this%np)
310 updated_quantities = [
"position",
"velocity"]
314 if (this%fixed(ip))
then
315 this%prop_data%hamiltonian_elements(:, ip) =
m_zero
317 this%prop_data%hamiltonian_elements(:, ip) = this%tot_force(:, ip) / (this%mass(ip) * this%pos(:, ip) +
m_epsilon)
322 safe_allocate(tmp_pos(1:this%space%dim, 1:this%np, 1:2))
323 safe_allocate(tmp_vel(1:this%space%dim, 1:this%np, 1:2))
329 tmp_pos(:, 1:this%np, 1) = this%prop_data%save_pos(:, 1:this%np)
330 tmp_vel(:, 1:this%np, 1) = this%prop_data%save_vel(:, 1:this%np)
331 this%pos(:, 1:this%np) = this%prop_data%save_pos(:, 1:this%np)
332 this%vel(:, 1:this%np) = this%prop_data%save_vel(:, 1:this%np)
336 factor = factor * prop%dt / ii
339 tmp_pos(:, ip, 2) = tmp_vel(:, ip, 1)
340 tmp_vel(:, ip, 2) = this%prop_data%hamiltonian_elements(:, ip) * tmp_pos(:, ip, 1)
342 tmp_pos(:, ip, 1) = tmp_pos(:, ip, 2)
343 tmp_vel(:, ip, 1) = tmp_vel(:, ip, 2)
345 this%pos(:, ip) = this%pos(:, ip) + factor * tmp_pos(:, ip, 1)
346 this%vel(:, ip) = this%vel(:, ip) + factor * tmp_vel(:, ip, 1)
349 safe_deallocate_a(tmp_pos)
350 safe_deallocate_a(tmp_vel)
351 updated_quantities = [
"position",
"velocity"]
355 if (.not. this%is_tolerance_reached(prop%scf_tol))
then
356 this%pos(:, 1:this%np) =
m_half*(this%pos(:, 1:this%np) + this%prop_data%save_pos(:, 1:this%np))
357 this%vel(:, 1:this%np) =
m_half*(this%vel(:, 1:this%np) + this%prop_data%save_vel(:, 1:this%np))
358 updated_quantities = [
"position",
"velocity"]
369 call profiling_out(trim(this%namespace%get())//
":"//trim(operation%id))
376 real(real64),
intent(in) :: tol
379 real(real64) :: change, max_change
386 change = sum((this%prop_data%prev_tot_force(1:this%space%dim, ip) - this%tot_force(1:this%space%dim, ip))**2) / &
388 if (change > max_change)
then
392 converged = max_change < tol**2
394 write(
message(1),
'(a, e13.6, a, e13.6)')
"Debug: -- Maximum change in acceleration ", &
395 sqrt(max_change),
" and tolerance ", tol
404 character(len=*),
intent(in) :: label
410 message(1) =
"Incompatible quantity."
424 select type (interaction)
426 message(1) =
"Unsupported interaction."
440 select type (interaction)
442 message(1) =
"Unsupported interaction."
456 select type (prop => this%algo)
458 if (prop%predictor_corrector)
then
459 this%prop_data%prev_tot_force(1:this%space%dim, 1:this%np) = this%tot_force(1:this%space%dim, 1:this%np)
475 this%tot_force(1:this%space%dim, 1:this%np) =
m_zero
476 call iter%start(this%interactions)
477 do while (iter%has_next())
478 select type (interaction => iter%get_next())
480 this%tot_force(1:this%space%dim, 1:this%np) = this%tot_force(1:this%space%dim, 1:this%np) + &
481 interaction%force(1:this%space%dim, 1:this%np)
497 select type (algo => this%algo)
502 iteration = this%iteration%counter()
503 if (iteration > 0)
then
505 iteration = iteration + 1
508 call io_mkdir(
'td.general', this%namespace)
510 call write_iter_init(this%output_handle(output_coordinates), iteration, dt, &
513 trim(
io_workpath(
"td.general/energy", this%namespace)))
517 if (iteration == 0)
then
518 call this%output_write()
542 integer :: idir, ii, ip
543 character(len=50) :: aux
544 real(real64) :: tmp(this%space%dim)
550 if (this%iteration%counter() == 0)
then
554 '############################################################################')
562 do idir = 1, this%space%dim
563 write(aux,
'(a2,i3,a1,i3,a1)')
'x(', ip,
',', idir,
')'
568 do idir = 1, this%space%dim
569 write(aux,
'(a2,i3,a1,i3,a1)')
'v(', ip,
',', idir,
')'
574 do idir = 1, this%space%dim
575 write(aux,
'(a2,i3,a1,i3,a1)')
'f(', ip,
',', idir,
')'
585 do idir = 1, this%space%dim
590 do idir = 1, this%space%dim
595 do idir = 1, this%space%dim
602 '############################################################################')
611 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
616 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
621 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
627 if (this%iteration%counter() == 0)
then
631 '############################################################################')
653 '############################################################################')
671 integer :: restart_file_unit
680 call profiling_in(trim(this%namespace%get())//
":"//
"RESTART_WRITE")
683 restart_file_unit =
io_open(
'restart/'//
td_dir//
'restart_classical_particles', this%namespace, action=
'write')
684 write(restart_file_unit, *) this%np
685 write(restart_file_unit, *) this%mass(:)
686 write(restart_file_unit, *) this%pos(:,:)
687 write(restart_file_unit, *) this%vel(:,:)
688 write(restart_file_unit, *) this%tot_force(:,:)
691 if (this%iteration%counter() > 0)
then
693 call this%prop_data%restart_write(this%namespace, this%algo)
696 message(1) =
"Successfully wrote restart data for system "//trim(this%namespace%get())
699 call profiling_out(trim(this%namespace%get())//
":"//
"RESTART_WRITE")
707 integer :: restart_file_unit
710 call profiling_in(trim(this%namespace%get())//
":"//
"RESTART_READ")
713 restart_file_unit =
io_open(
'restart/'//
td_dir//
'restart_classical_particles', this%namespace, action=
'read', die=.false.)
714 if (restart_file_unit /= -1)
then
715 read(restart_file_unit, *) this%np
716 read(restart_file_unit, *) this%mass(:)
717 read(restart_file_unit, *) this%pos(:,:)
718 read(restart_file_unit, *) this%vel(:,:)
719 read(restart_file_unit, *) this%tot_force(:,:)
721 call this%prop_data%initialize(this%algo, this%space%dim, this%np)
722 if (this%iteration%counter() > 0)
then
734 message(1) =
"Successfully read restart data for system "//trim(this%namespace%get())
738 message(1) =
"Failed to read restart data for system "//trim(this%namespace%get())
743 call profiling_out(trim(this%namespace%get())//
":"//
"RESTART_READ")
755 this%kinetic_energy =
m_zero
757 this%kinetic_energy = this%kinetic_energy +
m_half * this%mass(ip) * sum(this%vel(:, ip)**2)
766 logical,
optional,
intent(in) :: mask(:)
767 logical,
optional,
intent(in) :: pseudo
768 real(real64) :: pos(this%space%dim)
770 real(real64) :: mass, total_mass
775 assert(.not. this%space%is_periodic())
781 if (
present(mask))
then
782 if (.not. mask(ip)) cycle
787 pos = pos + mass*this%pos(:, ip)
788 total_mass = total_mass + mass
798 real(real64) :: vel(this%space%dim)
800 real(real64) :: mass, total_mass
809 total_mass = total_mass + mass
810 vel = vel + mass*this%vel(:, ip)
820 real(real64) :: pos(this%space%dim)
822 real(real64) :: xmin(this%space%dim), xmax(this%space%dim)
830 do idir = 1, this%space%dim
831 if (this%pos(idir, ip) > xmax(idir)) xmax(idir) = this%pos(idir, ip)
832 if (this%pos(idir, ip) < xmin(idir)) xmin(idir) = this%pos(idir, ip)
836 pos = (xmax + xmin)/
m_two
844 real(real64),
intent(out) :: x(this%space%dim)
845 real(real64),
intent(out) :: x2(this%space%dim)
848 real(real64) :: rmax, r, r2
852 assert(.not. this%space%is_periodic())
857 do jp = 1, this%np/2 + 1
858 r = norm2(this%pos(:, ip) - this%pos(:, jp))
861 x = this%pos(:, ip) - this%pos(:, jp)
870 r2 = sum(x * this%pos(:, ip))
871 r = norm2(this%pos(:, ip) - r2*x)
874 x2 = this%pos(:, ip) - r2*x
886 real(real64),
intent(out) :: x(this%space%dim)
887 real(real64),
intent(out) :: x2(this%space%dim)
888 logical,
intent(in) :: pseudo
890 real(real64) :: mass, tinertia(this%space%dim, this%space%dim), eigenvalues(this%space%dim)
891 integer :: ii, jj, ip
896 assert(.not. this%space%is_periodic())
902 if (.not. pseudo) mass = this%mass(ip)
903 do ii = 1, this%space%dim
904 tinertia(ii, :) = tinertia(ii, :) - mass*this%pos(ii, ip)*this%pos(:, ip)
905 tinertia(ii, ii) = tinertia(ii, ii) + mass*sum(this%pos(:, ip)**2)
912 write(
message(1),
'(a)')
'Moment of pseudo-inertia tensor [' // trim(
units_abbrev(unit)) //
']'
914 write(
message(1),
'(a)')
'Moment of inertia tensor [amu*' // trim(
units_abbrev(unit)) //
']'
917 call output_tensor(tinertia, this%space%dim, unit, write_average = .
true., namespace=this%namespace)
926 jj = maxloc(abs(tinertia(:,ii)), dim = 1)
927 if (tinertia(jj,ii) <
m_zero) tinertia(:,ii) = -tinertia(:,ii)
941 safe_deallocate_a(this%mass)
942 safe_deallocate_a(this%pos)
943 safe_deallocate_a(this%vel)
944 safe_deallocate_a(this%tot_force)
945 safe_deallocate_a(this%fixed)
946 safe_deallocate_a(this%lj_epsilon)
947 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)
subroutine, public classical_particles_update_quantity(this, label)
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 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)
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)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, 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...
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.
Systems (system_t) can expose quantities that can be used to calculate interactions with other system...
Abstract class for systems.