33 use,
intrinsic :: iso_fortran_env
69 integer,
parameter :: &
70 OUTPUT_COORDINATES = 1, &
75 type(c_ptr),
public :: output_handle(2)
76 type(space_t),
public :: space
78 real(real64),
allocatable,
public :: mass(:)
79 real(real64),
allocatable,
public :: pos(:,:)
80 real(real64),
allocatable,
public :: vel(:,:)
81 real(real64),
allocatable,
public :: tot_force(:,:)
82 real(real64),
allocatable,
public :: lj_epsilon(:)
83 real(real64),
allocatable,
public :: lj_sigma(:)
84 logical,
allocatable,
public :: fixed(:)
86 type(propagator_data_t),
public :: prop_data
116 class(classical_particles_t),
intent(inout) :: this
117 integer,
intent(in) :: np
122 safe_allocate(this%mass(1:np))
124 safe_allocate(this%pos(1:this%space%dim, 1:np))
126 safe_allocate(this%vel(1:this%space%dim, 1:np))
128 safe_allocate(this%tot_force(1:this%space%dim, 1:np))
130 safe_allocate(this%fixed(1:np))
132 safe_allocate(this%lj_epsilon(1:np))
134 safe_allocate(this%lj_sigma(1:np))
139 allocate(this%supported_interactions(0))
140 allocate(this%supported_interactions_as_partner(0))
143 call this%quantities%add(
quantity_t(
"position", updated_on_demand = .false.))
144 call this%quantities%add(
quantity_t(
"velocity", updated_on_demand = .false.))
147 call this%quantities%add(
quantity_t(
"mass", updated_on_demand = .false., always_available=.
true.))
154 class(classical_particles_t),
intent(out) :: this
155 class(classical_particles_t),
intent(in) :: cp_in
160 safe_allocate_source_a(this%mass, cp_in%mass)
161 safe_allocate_source_a(this%pos, cp_in%pos)
162 safe_allocate_source_a(this%vel, cp_in%vel)
163 safe_allocate_source_a(this%tot_force, cp_in%tot_force)
164 safe_allocate_source_a(this%fixed, cp_in%fixed)
166 this%kinetic_energy = cp_in%kinetic_energy
168 this%quantities = cp_in%quantities
169 this%supported_interactions = cp_in%supported_interactions
171 this%prop_data = cp_in%prop_data
183 select type (interaction)
185 message(1) =
"Trying to initialize an unsupported interaction by classical particles."
196 character(len=:),
allocatable,
intent(out) :: updated_quantities(:)
199 real(real64),
allocatable :: tmp_pos(:,:,:), tmp_vel(:,:,:)
200 real(real64) :: factor
203 call profiling_in(trim(this%namespace%get())//
":"//trim(operation%id))
206 select type (prop => this%algo)
209 select case (operation%id)
211 this%prop_data%save_pos(:, 1:this%np) = this%pos(:, 1:this%np)
212 this%prop_data%save_vel(:, 1:this%np) = this%vel(:, 1:this%np)
215 if (.not. this%prop_data%initialized)
then
216 call this%prop_data%initialize(prop, this%space%dim, this%np)
218 if (this%fixed(ip))
then
219 this%prop_data%acc(:, ip) =
m_zero
221 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
227 call this%prop_data%end()
230 call this%prop_data%end()
233 this%pos(:, 1:this%np) = this%pos(:, 1:this%np) + prop%dt * this%vel(:, 1:this%np) &
234 +
m_half * prop%dt**2 * this%prop_data%acc(:, 1:this%np)
235 updated_quantities = [
"position"]
238 do ii =
size(this%prop_data%prev_acc, dim=3) - 1, 1, -1
239 this%prop_data%prev_acc(:, 1:this%np, ii + 1) = this%prop_data%prev_acc(:, 1:this%np, ii)
242 this%prop_data%prev_acc(:, ip, 1) = this%prop_data%acc(:, ip)
243 if (this%fixed(ip))
then
244 this%prop_data%acc(:, ip) =
m_zero
246 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
251 this%vel(:, 1:this%np) = this%vel(:, 1:this%np) &
252 +
m_half * prop%dt * (this%prop_data%prev_acc(:, 1:this%np, 1) + this%prop_data%acc(:, 1:this%np))
253 updated_quantities = [
"velocity"]
256 if (.not. this%prop_data%initialized)
then
257 call this%prop_data%initialize(prop, this%space%dim, this%np)
259 if (this%fixed(ip))
then
260 this%prop_data%acc(:, ip) =
m_zero
262 this%prop_data%acc(:, ip) = this%tot_force(:, ip) / this%mass(ip)
264 this%prop_data%prev_acc(:, ip, 1) = this%prop_data%acc(:, ip)
269 this%pos(:, 1:this%np) = this%pos(:, 1:this%np) + prop%dt * this%vel(:, 1:this%np) + &
270 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))
272 if (.not. prop%predictor_corrector)
then
273 updated_quantities = [
"position"]
277 this%vel(:, 1:this%np) = this%vel(:, 1:this%np) + &
278 m_one/6.0_real64 * prop%dt * (
m_two * this%prop_data%acc(:, 1:this%np) + &
279 5.0_real64 * this%prop_data%prev_acc(:, 1:this%np, 1) - this%prop_data%prev_acc(:, 1:this%np, 2))
280 updated_quantities = [
"velocity"]
283 this%pos(:, 1:this%np) = this%prop_data%save_pos(:, 1:this%np) &
284 + prop%dt * this%prop_data%save_vel(:, 1:this%np) &
285 +
m_one/6.0_real64 * prop%dt**2 * (this%prop_data%acc(:, 1:this%np) &
286 +
m_two * this%prop_data%prev_acc(:, 1:this%np, 1))
287 updated_quantities = [
"position"]
290 this%vel(:, 1:this%np) = this%prop_data%save_vel(:, 1:this%np) &
291 +
m_half * prop%dt * (this%prop_data%acc(:, 1:this%np) + this%prop_data%prev_acc(:, 1:this%np, 1))
292 updated_quantities = [
"velocity"]
295 if (.not. this%prop_data%initialized)
then
296 call this%prop_data%initialize(prop, this%space%dim, this%np)
297 this%prop_data%prev_pos(:, 1:this%np, 1) = this%pos(:, 1:this%np)
298 this%prop_data%prev_vel(:, 1:this%np, 1) = this%vel(:, 1:this%np)
302 call this%prop_data%end()
305 this%pos(:, 1:this%np) = 1.5_real64*this%prop_data%save_pos(:, 1:this%np) &
306 -
m_half*this%prop_data%prev_pos(:, 1:this%np, 1)
307 this%vel(:, 1:this%np) = 1.5_real64*this%prop_data%save_vel(:, 1:this%np) &
308 -
m_half*this%prop_data%prev_vel(:, 1:this%np, 1)
309 this%prop_data%prev_pos(:, 1:this%np, 1) = this%prop_data%save_pos(:, 1:this%np)
310 this%prop_data%prev_vel(:, 1:this%np, 1) = this%prop_data%save_vel(:, 1:this%np)
311 updated_quantities = [
"position",
"velocity"]
315 if (this%fixed(ip))
then
316 this%prop_data%hamiltonian_elements(:, ip) =
m_zero
318 this%prop_data%hamiltonian_elements(:, ip) = this%tot_force(:, ip) / (this%mass(ip) * this%pos(:, ip) +
m_epsilon)
323 safe_allocate(tmp_pos(1:this%space%dim, 1:this%np, 1:2))
324 safe_allocate(tmp_vel(1:this%space%dim, 1:this%np, 1:2))
330 tmp_pos(:, 1:this%np, 1) = this%prop_data%save_pos(:, 1:this%np)
331 tmp_vel(:, 1:this%np, 1) = this%prop_data%save_vel(:, 1:this%np)
332 this%pos(:, 1:this%np) = this%prop_data%save_pos(:, 1:this%np)
333 this%vel(:, 1:this%np) = this%prop_data%save_vel(:, 1:this%np)
337 factor = factor * prop%dt / ii
340 tmp_pos(:, ip, 2) = tmp_vel(:, ip, 1)
341 tmp_vel(:, ip, 2) = this%prop_data%hamiltonian_elements(:, ip) * tmp_pos(:, ip, 1)
343 tmp_pos(:, ip, 1) = tmp_pos(:, ip, 2)
344 tmp_vel(:, ip, 1) = tmp_vel(:, ip, 2)
346 this%pos(:, ip) = this%pos(:, ip) + factor * tmp_pos(:, ip, 1)
347 this%vel(:, ip) = this%vel(:, ip) + factor * tmp_vel(:, ip, 1)
350 safe_deallocate_a(tmp_pos)
351 safe_deallocate_a(tmp_vel)
352 updated_quantities = [
"position",
"velocity"]
356 if (.not. this%is_tolerance_reached(prop%scf_tol))
then
357 this%pos(:, 1:this%np) =
m_half*(this%pos(:, 1:this%np) + this%prop_data%save_pos(:, 1:this%np))
358 this%vel(:, 1:this%np) =
m_half*(this%vel(:, 1:this%np) + this%prop_data%save_vel(:, 1:this%np))
359 updated_quantities = [
"position",
"velocity"]
370 call profiling_out(trim(this%namespace%get())//
":"//trim(operation%id))
377 real(real64),
intent(in) :: tol
380 real(real64) :: change, max_change
387 change = sum((this%prop_data%prev_tot_force(1:this%space%dim, ip) - this%tot_force(1:this%space%dim, ip))**2) / &
389 if (change > max_change)
then
393 converged = max_change < tol**2
395 write(
message(1),
'(a, e13.6, a, e13.6)')
"Debug: -- Maximum change in acceleration ", &
396 sqrt(max_change),
" and tolerance ", tol
405 character(len=*),
intent(in) :: label
411 message(1) =
"Incompatible quantity."
425 select type (interaction)
427 message(1) =
"Unsupported interaction."
441 select type (interaction)
443 message(1) =
"Unsupported interaction."
457 select type (prop => this%algo)
459 if (prop%predictor_corrector)
then
460 this%prop_data%prev_tot_force(1:this%space%dim, 1:this%np) = this%tot_force(1:this%space%dim, 1:this%np)
476 this%tot_force(1:this%space%dim, 1:this%np) =
m_zero
477 call iter%start(this%interactions)
478 do while (iter%has_next())
479 select type (interaction => iter%get_next())
481 this%tot_force(1:this%space%dim, 1:this%np) = this%tot_force(1:this%space%dim, 1:this%np) + &
482 interaction%force(1:this%space%dim, 1:this%np)
498 select type (algo => this%algo)
503 iteration = this%iteration%counter()
504 if (iteration > 0)
then
506 iteration = iteration + 1
509 call io_mkdir(
'td.general', this%namespace)
510 if (this%grp%is_root())
then
511 call write_iter_init(this%output_handle(output_coordinates), iteration, dt, &
512 trim(
io_workpath(
"td.general/coordinates", this%namespace)))
518 if (iteration == 0)
then
519 call this%output_write()
531 if (this%grp%is_root())
then
543 integer :: idir, ii, ip
544 character(len=50) :: aux
545 real(real64) :: tmp(this%space%dim)
547 if (.not. this%grp%is_root())
return
551 if (this%iteration%counter() == 0)
then
555 '############################################################################')
563 do idir = 1, this%space%dim
564 write(aux,
'(a2,i3,a1,i3,a1)')
'x(', ip,
',', idir,
')'
569 do idir = 1, this%space%dim
570 write(aux,
'(a2,i3,a1,i3,a1)')
'v(', ip,
',', idir,
')'
575 do idir = 1, this%space%dim
576 write(aux,
'(a2,i3,a1,i3,a1)')
'f(', ip,
',', idir,
')'
586 do idir = 1, this%space%dim
591 do idir = 1, this%space%dim
596 do idir = 1, this%space%dim
603 '############################################################################')
612 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
617 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
622 call write_iter_double(this%output_handle(output_coordinates), tmp, this%space%dim)
628 if (this%iteration%counter() == 0)
then
632 '############################################################################')
654 '############################################################################')
673 integer :: restart_file_unit
678 if (this%grp%is_root())
then
683 call profiling_in(trim(this%namespace%get())//
":"//
"RESTART_WRITE")
687 restart_file_unit = restart%open(
"restart_classical_particles")
688 if (restart%do_i_write())
then
690 write(restart_file_unit, *) this%np
691 write(restart_file_unit, *) this%mass(:)
692 write(restart_file_unit, *) this%pos(:,:)
693 write(restart_file_unit, *) this%vel(:,:)
694 write(restart_file_unit, *) this%tot_force(:,:)
697 call restart%close(restart_file_unit)
700 if (this%iteration%counter() > 0)
then
702 call this%prop_data%restart_write(this%namespace, this%algo)
705 message(1) =
"Successfully wrote restart data for system "//trim(this%namespace%get())
710 call profiling_out(trim(this%namespace%get())//
":"//
"RESTART_WRITE")
719 integer :: restart_file_unit
723 call profiling_in(trim(this%namespace%get())//
":"//
"RESTART_READ")
729 restart_file_unit = restart%open(
"restart_classical_particles")
731 if (restart_file_unit /= -1)
then
732 read(restart_file_unit, *) this%np
733 read(restart_file_unit, *) this%mass(:)
734 read(restart_file_unit, *) this%pos(:,:)
735 read(restart_file_unit, *) this%vel(:,:)
736 read(restart_file_unit, *) this%tot_force(:,:)
738 call restart%close(restart_file_unit)
739 call this%prop_data%initialize(this%algo, this%space%dim, this%np)
740 if (this%iteration%counter() > 0)
then
751 message(1) =
"Successfully read restart data for system "//trim(this%namespace%get())
755 message(1) =
"Failed to read restart data for system "//trim(this%namespace%get())
760 call profiling_out(trim(this%namespace%get())//
":"//
"RESTART_READ")
772 this%kinetic_energy =
m_zero
774 this%kinetic_energy = this%kinetic_energy +
m_half * this%mass(ip) * sum(this%vel(:, ip)**2)
783 logical,
optional,
intent(in) :: mask(:)
784 logical,
optional,
intent(in) :: pseudo
785 real(real64) :: pos(this%space%dim)
787 real(real64) :: mass, total_mass
792 assert(.not. this%space%is_periodic())
798 if (
present(mask))
then
799 if (.not. mask(ip)) cycle
804 pos = pos + mass*this%pos(:, ip)
805 total_mass = total_mass + mass
815 real(real64) :: vel(this%space%dim)
817 real(real64) :: mass, total_mass
826 total_mass = total_mass + mass
827 vel = vel + mass*this%vel(:, ip)
837 real(real64) :: pos(this%space%dim)
839 real(real64) :: xmin(this%space%dim), xmax(this%space%dim)
847 do idir = 1, this%space%dim
848 if (this%pos(idir, ip) > xmax(idir)) xmax(idir) = this%pos(idir, ip)
849 if (this%pos(idir, ip) < xmin(idir)) xmin(idir) = this%pos(idir, ip)
853 pos = (xmax + xmin)/
m_two
861 real(real64),
intent(out) :: x(this%space%dim)
862 real(real64),
intent(out) :: x2(this%space%dim)
865 real(real64) :: rmax, r, r2
869 assert(.not. this%space%is_periodic())
874 do jp = 1, this%np/2 + 1
875 r = norm2(this%pos(:, ip) - this%pos(:, jp))
878 x = this%pos(:, ip) - this%pos(:, jp)
887 r2 = sum(x * this%pos(:, ip))
888 r = norm2(this%pos(:, ip) - r2*x)
891 x2 = this%pos(:, ip) - r2*x
903 real(real64),
intent(out) :: x(this%space%dim)
904 real(real64),
intent(out) :: x2(this%space%dim)
905 logical,
intent(in) :: pseudo
907 real(real64) :: mass, tinertia(this%space%dim, this%space%dim), eigenvalues(this%space%dim)
908 integer :: ii, jj, ip
913 assert(.not. this%space%is_periodic())
919 if (.not. pseudo) mass = this%mass(ip)
920 do ii = 1, this%space%dim
921 tinertia(ii, :) = tinertia(ii, :) - mass*this%pos(ii, ip)*this%pos(:, ip)
922 tinertia(ii, ii) = tinertia(ii, ii) + mass*sum(this%pos(:, ip)**2)
929 write(
message(1),
'(a)')
'Moment of pseudo-inertia tensor [' // trim(
units_abbrev(unit)) //
']'
931 write(
message(1),
'(a)')
'Moment of inertia tensor [amu*' // trim(
units_abbrev(unit)) //
']'
934 call output_tensor(tinertia, this%space%dim, unit, write_average = .
true., namespace=this%namespace)
943 jj = maxloc(abs(tinertia(:,ii)), dim = 1)
944 if (tinertia(jj,ii) <
m_zero) tinertia(:,ii) = -tinertia(:,ii)
958 safe_deallocate_a(this%mass)
959 safe_deallocate_a(this%pos)
960 safe_deallocate_a(this%vel)
961 safe_deallocate_a(this%tot_force)
962 safe_deallocate_a(this%fixed)
963 safe_deallocate_a(this%lj_epsilon)
964 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
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.
character(len=max_path_len) function, public io_workpath(path, namespace)
construct path name from given name and namespace
subroutine, public io_mkdir(fname, namespace, parents)
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)
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 restart_type_dump
integer, parameter, public restart_td
integer, parameter, public restart_type_load
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...
restart_basic_t stores the basic information about a restart object.
Abstract class for systems.