70 real(real64) :: target_time
73 integer,
parameter,
public :: &
74 NUMBER_BARRIERS = 1, &
82 type(iteration_counter_t),
public :: iteration
83 class(algorithm_t),
pointer,
public :: algo => null()
85 integer,
allocatable,
public :: supported_interactions(:)
86 type(interaction_list_t),
public :: interactions
88 type(mpi_grp_t),
public :: grp
90 type(barrier_t) :: barrier(NUMBER_BARRIERS)
91 real(real64),
public :: kinetic_energy
92 real(real64),
public :: potential_energy
93 real(real64),
public :: internal_energy
95 real(real64),
public :: total_energy
125 procedure(system_init_interaction),
deferred :: init_interaction
126 procedure(system_initialize),
deferred :: initialize
127 procedure(system_do_algorithmic_operation),
deferred :: do_algorithmic_operation
128 procedure(system_is_tolerance_reached),
deferred :: is_tolerance_reached
129 procedure(system_restart_write_data),
deferred :: restart_write_data
130 procedure(system_restart_read_data),
deferred :: restart_read_data
131 procedure(system_update_kinetic_energy),
deferred :: update_kinetic_energy
145 class(system_t),
target,
intent(inout) :: this
146 class(interaction_t),
intent(inout) :: interaction
153 class(system_t),
intent(inout) :: this
169 class(
system_t),
intent(inout) :: this
171 character(len=:),
allocatable,
intent(out) :: updated_quantities(:)
177 use,
intrinsic :: iso_fortran_env
180 real(real64),
intent(in) :: tol
189 class(
system_t),
intent(inout) :: this
244 class(
system_t),
intent(inout) :: this
247 logical :: all_updated, at_barrier, operation_done
251 character(len=:),
allocatable :: updated_quantities(:)
257 do while (.not. at_barrier)
259 operation = this%algo%get_current_operation()
262 system_iteration=this%iteration, algo_iteration=this%algo%iteration)
265 operation_done = this%do_algorithmic_operation(operation, updated_quantities)
266 if (
allocated(updated_quantities))
then
268 do i = 1,
size(updated_quantities)
269 quantity => this%quantities%get(updated_quantities(i))
270 call quantity%iteration%set(this%algo%iteration + 1)
272 quantity%iteration,
"set"))
277 if (.not. operation_done)
then
278 operation_done = this%algo%do_operation(operation)
280 call this%algo%next()
284 if (.not. operation_done)
then
286 select case (operation%id)
289 call this%algo%next()
293 this%iteration = this%iteration + 1
297 call this%update_total_energy()
300 call this%output_write()
303 call this%algo%update_elapsed_time()
308 call this%iteration_info()
310 call this%algo%next()
313 if (.not. this%algo%finished())
then
314 if (.not. this%arrived_at_any_barrier())
then
316 call this%algo%rewind()
321 if (this%algo%continues_after_finished())
then
322 call this%algo%rewind()
330 this%algo%iteration = this%algo%iteration + 1
332 this%algo%iteration,
"tick"))
335 all_updated = this%update_couplings()
339 if (all_updated)
then
340 call this%algo%next()
342 this%algo%iteration = this%algo%iteration - 1
344 this%algo%iteration,
"reverse"))
352 call this%update_interactions()
353 call this%algo%next()
356 message(1) =
"Unsupported algorithmic operation."
357 write(
message(2),
'(A,A,A)') trim(operation%id),
": ", trim(operation%label)
370 class(
system_t),
intent(inout) :: this
371 integer,
intent(in) :: accumulated_iterations
378 character(len=MAX_INFO_LEN) :: extended_label
383 this%algo%iteration = this%algo%iteration - accumulated_iterations
387 call iter%start(this%interactions)
388 do while (iter%has_next())
389 interaction => iter%get_next()
390 interaction%iteration = interaction%iteration - accumulated_iterations
392 extended_label = trim(interaction%label)//
"-"//trim(interaction%partner%namespace%get())
394 interaction%iteration,
"reset"))
398 call qiter%start(this%interactions)
399 do while(qiter%has_next())
400 quantity => qiter%get_next()
401 quantity%iteration = quantity%iteration - accumulated_iterations
403 quantity%iteration,
"reset"))
424 class(
system_t),
intent(inout) :: this
430 integer :: i, ip, iq, interaction_type
440 assert(
allocated(this%supported_interactions))
441 assert(
allocated(this%supported_interactions_as_partner))
447 call iter%start(available_partners)
448 do while (iter%has_next())
449 partner => iter%get_next()
450 call partner%add_partners_to_list(partners)
453 call iter%start(partners)
454 do while (iter%has_next())
455 partner => iter%get_next()
458 if (partner%namespace%get() == this%namespace%get()) cycle
469 call partners%empty()
473 options = interaction_factory%options(this%namespace, this%supported_interactions)
476 do i = 1,
size(this%supported_interactions)
477 interaction_type = this%supported_interactions(i)
482 assert(count(this%supported_interactions == interaction_type) == 1)
485 call iter%start(available_partners)
486 do while (iter%has_next())
487 partner => iter%get_next()
488 call partner%add_partners_to_list(partners, interaction_type)
492 select case (options(i)%mode)
498 call partners%empty()
502 call iter%start(partners)
503 do while (iter%has_next())
504 partner => iter%get_next()
506 do ip = 1,
size(options(i)%partners)
507 if (partner%namespace%is_contained_in(options(i)%partners(ip)))
then
512 if (.not. in_list)
then
513 call partners%delete(partner)
519 do ip = 1,
size(options(i)%partners)
520 call iter%start(partners)
521 do while (iter%has_next())
522 partner => iter%get_next()
523 if (partner%namespace%is_contained_in(options(i)%partners(ip)))
then
524 call partners%delete(partner)
532 call iter%start(partners)
533 do while (iter%has_next())
534 partner => iter%get_next()
536 interaction => interaction_factory%create(interaction_type, partner)
540 interaction%intra_interaction = partner%namespace%get() == this%namespace%get()
543 interaction%timing = options(i)%timing
545 select type (partner => interaction%partner)
547 if (this%algo%iteration%global_step() /= partner%algo%iteration%global_step() .and. &
548 .not. all(partner%quantities%always_available(interaction%couplings_from_partner)))
then
549 write(
message(1),
'(2a)')
"InteractionTiming was set to exact timing, but systems ", &
550 trim(this%namespace%get())
551 write(
message(2),
'(3a)')
"and ", trim(partner%namespace%get()),
" have incompatible steps."
558 call this%init_interaction(interaction)
559 call interaction%partner%init_interaction_as_partner(interaction)
562 if (
allocated(interaction%system_quantities))
then
563 do iq = 1,
size(interaction%system_quantities)
564 if (.not.
associated(this%quantities%get(interaction%system_quantities(iq))))
then
565 write(
message(1),
'(5a)')
"Interaction '", trim(interaction%label),
"' requires quantity '", &
566 trim(interaction%system_quantities(iq)),
"'"
567 write(
message(2),
'(3a)')
"from system '", trim(this%namespace%get()),
"' but it is not available."
572 if (
allocated(interaction%couplings_from_partner))
then
573 do iq = 1,
size(interaction%couplings_from_partner)
574 if (.not.
associated(partner%quantities%get(interaction%couplings_from_partner(iq))))
then
575 write(
message(1),
'(5a)')
"Interaction '", trim(interaction%label),
"' requires coupling '", &
576 trim(interaction%couplings_from_partner(iq)),
"'"
577 write(
message(2),
'(3a)')
"from partner '", trim(partner%namespace%get()),
"' but it is not available."
584 call this%interactions%add(interaction)
588 call partners%empty()
601 class(
system_t),
intent(inout) :: this
609 call iter%start(this%interactions)
610 do while (iter%has_next())
611 interaction => iter%get_next()
613 select type (partner => interaction%partner)
617 if (partner%algo%iteration + 1 >= this%algo%iteration)
then
618 call interaction%update_partner_couplings(this%algo%iteration)
623 call interaction%update_partner_couplings(this%algo%iteration)
626 all_updated = all_updated .and. interaction%partner_couplings_up_to_date
638 class(
system_t),
intent(inout) :: this
640 integer :: iq, n_quantities
649 call this%update_interactions_start()
652 call iter%start(this%interactions)
653 do while (iter%has_next())
654 interaction => iter%get_next()
657 if (
allocated(interaction%system_quantities))
then
658 n_quantities =
size(interaction%system_quantities)
662 do iq = 1, n_quantities
664 quantity => this%quantities%get(interaction%system_quantities(iq))
666 if (.not. quantity%iteration == this%algo%iteration)
then
671 if (quantity%iteration > this%algo%iteration)
then
672 message(1) =
"The quantity "//trim(quantity%label)//
" is in advance compared to the requested iteration."
673 message(2) =
"The interaction is "//trim(interaction%label)//
"."
678 if (quantity%updated_on_demand)
then
679 call this%update_on_demand_quantity(quantity, this%algo%iteration)
684 if (.not. quantity%iteration == this%algo%iteration .and. .not. quantity%always_available)
then
685 write(
message(1),
'(5a)')
"Interaction ", trim(interaction%label),
" is incompatible with the selected algorithm."
686 write(
message(2),
'(3a)')
"The interaction requires the ", trim(quantity%label), &
687 " at an iteration it is not available."
695 call interaction%update(this%algo%iteration)
700 call this%update_interactions_finish()
707 class(
system_t),
intent(inout) :: this
719 class(
system_t),
intent(inout) :: this
731 class(
system_t),
intent(inout) :: this
733 logical :: restart_write
744 if (restart_write)
then
747 call this%iteration%restart_write(
'restart_iteration_system', this%namespace)
748 call this%algo%iteration%restart_write(
'restart_iteration_algorithm', this%namespace)
749 call iter%start(this%interactions)
750 do while (iter%has_next())
751 interaction => iter%get_next()
752 call interaction%restart_write(this%namespace)
754 call qiter%start(this%quantities)
755 do while (qiter%has_next())
756 quantity => qiter%get_next()
757 call quantity%iteration%restart_write(
'restart_iteration_quantity_'//trim(quantity%label), &
761 call this%restart_write_data()
762 message(1) =
"Wrote restart data for system "//trim(this%namespace%get())
772 class(
system_t),
intent(inout) :: this
783 system_restart_read = this%iteration%restart_read(
'restart_iteration_system', this%namespace)
785 this%algo%iteration%restart_read(
'restart_iteration_algorithm', this%namespace)
786 call iter%start(this%interactions)
787 do while (iter%has_next())
788 interaction => iter%get_next()
791 interaction%iteration = interaction%iteration - 1
793 call qiter%start(this%quantities)
794 do while (qiter%has_next())
795 quantity => qiter%get_next()
797 quantity%iteration%restart_read(
'restart_iteration_quantity_'//trim(quantity%label), &
799 if (quantity%updated_on_demand)
then
801 quantity%iteration = quantity%iteration - 1
808 message(1) =
"Successfully read restart data for system "//trim(this%namespace%get())
817 class(
system_t),
intent(inout) :: this
829 class(
system_t),
intent(inout) :: this
841 class(
system_t),
intent(inout) :: this
853 class(
system_t),
intent(inout) :: this
862 this%algo => factory%create(this)
864 call this%init_iteration_counters()
866 do ii = 1, number_barriers
867 this%barrier(ii)%active = .false.
868 this%barrier(ii)%target_time =
m_zero
879 finished = this%algo%finished()
891 class(
system_t),
intent(inout) :: this
901 call this%algo%init_iteration_counters()
904 call iter%start(this%interactions)
905 do while (iter%has_next())
906 interaction => iter%get_next()
907 interaction%iteration = this%algo%iteration - 1
911 call qiter%start(this%quantities)
912 do while (qiter%has_next())
913 quantity => qiter%get_next()
914 if (quantity%updated_on_demand)
then
917 quantity%iteration = this%algo%iteration - 1
919 quantity%iteration = this%algo%iteration
928 class(
system_t),
intent(inout) :: this
930 logical :: all_updated
932 character(len=:),
allocatable :: updated_quantities(:)
937 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
940 all_updated = this%update_couplings()
941 if (.not. all_updated)
then
942 message(1) =
"Unable to update interactions when initializing the algorithm."
945 call this%update_interactions()
948 if (this%algo%start_operation%id /=
skip)
then
949 if (.not. this%do_algorithmic_operation(this%algo%start_operation, updated_quantities))
then
950 message(1) =
"Unsupported algorithmic operation."
951 write(
message(2),
'(A,A,A)') trim(this%algo%start_operation%id),
": ", trim(this%algo%start_operation%label)
954 if (
allocated(updated_quantities))
then
955 message(1) =
"Update of quantities not allowed in algorithmic operation."
956 write(
message(2),
'(A,A,A)') trim(this%algo%start_operation%id),
": ", trim(this%algo%start_operation%label)
962 call this%update_total_energy()
965 call this%output_start()
968 call this%algo%write_output_header()
971 call this%algo%rewind()
980 class(
system_t),
intent(inout) :: this
983 character(len=:),
allocatable :: updated_quantities(:)
988 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
991 call this%output_finish()
994 if (this%algo%final_operation%id /=
skip)
then
995 if (.not. this%do_algorithmic_operation(this%algo%final_operation, updated_quantities))
then
996 message(1) =
"Unsupported algorithmic operation."
997 write(
message(2),
'(A,A,A)') trim(this%algo%final_operation%id),
": ", trim(this%algo%final_operation%label)
1000 if (
allocated(updated_quantities))
then
1001 message(1) =
"Update of quantities not allowed in algorithmic operation."
1002 write(
message(2),
'(A,A,A)') trim(this%algo%final_operation%id),
": ", trim(this%algo%final_operation%label)
1007 call this%algo%print_speed()
1016 class(
system_t),
intent(in) :: this
1018 real(real64) :: energy
1019 character(len=40) :: fmt
1024 if (abs(energy) >= 1e5)
then
1025 fmt =
'(i7,1x,f14.6,1X,es13.6,1X,i9,1X,'
1027 fmt =
'(i7,1x,f14.6,1X,f13.6,1X,i9,1X,'
1029 if (this%algo%elapsed_time < 1e-3)
then
1030 fmt = trim(fmt)//
'es13.3)'
1032 fmt = trim(fmt)//
'f13.3)'
1035 write(
message(1), fmt) this%iteration%counter(), &
1037 0, this%algo%elapsed_time
1045 class(
system_t),
intent(in) :: this
1057 class(
system_t),
intent(inout) :: this
1065 if (
associated(this%algo))
then
1066 deallocate(this%algo)
1069 call iter%start(this%interactions)
1070 do while (iter%has_next())
1071 interaction => iter%get_next()
1072 if (
associated(interaction))
then
1073 deallocate(interaction)
1088 select type (partner)
1090 call this%add_ptr(partner)
1110 select type (partner)
1113 call iterator%start(this)
1114 do while (iterator%has_next() .and. .not. contains)
1115 system => iterator%get_next()
1116 contains =
associated(system, partner)
1133 select type (ptr => this%get_next_ptr())
1148 class(
system_t),
intent(inout) :: this
1163 class(
system_t),
intent(inout) :: this
1164 real(real64),
intent(in) :: target_time
1165 integer,
intent(in) :: barrier_index
1169 this%barrier(barrier_index)%active = .
true.
1170 this%barrier(barrier_index)%target_time = target_time
1178 integer,
intent(in) :: barrier_index
1182 this%barrier(barrier_index)%active = .false.
1183 this%barrier(barrier_index)%target_time =
m_zero
1190 class(
system_t),
intent(inout) :: this
1191 integer,
intent(in) :: barrier_index
1198 if (this%barrier(barrier_index)%active)
then
1199 iteration = this%iteration + 1
1200 if (iteration%value() > this%barrier(barrier_index)%target_time)
then
1210 class(
system_t),
intent(inout) :: this
1217 do ii = 1, number_barriers
1219 .or. this%arrived_at_barrier(ii)
1232 class(
system_t),
intent(inout) :: this
1239 this%potential_energy =
m_zero
1241 call iter%start(this%interactions)
1242 do while (iter%has_next())
1243 interaction => iter%get_next()
1244 if(.not. interaction%intra_interaction)
then
1245 call interaction%calculate_energy()
1246 this%potential_energy = this%potential_energy + interaction%energy
1259 class(
system_t),
intent(inout) :: this
1266 this%internal_energy =
m_zero
1267 call iter%start(this%interactions)
1268 do while (iter%has_next())
1269 interaction => iter%get_next()
1270 if(interaction%intra_interaction)
then
1271 call interaction%calculate_energy()
1272 this%internal_energy = this%internal_energy + interaction%energy
1288 call this%update_kinetic_energy()
1289 this%total_energy = this%kinetic_energy
1292 call this%update_potential_energy()
1293 this%total_energy = this%total_energy + this%potential_energy
1296 call this%update_internal_energy()
1297 this%total_energy = this%total_energy + this%internal_energy
Execute one operation that is part of a larger algorithm. Returns true if the operation was successfu...
initialize a given interaction of the system
set initial conditions for a system
check whether a system has reached a given tolerance
For some algorithms it might be necessary to store the status of a system at a given algorithmic step...
This module defines the abstract interfact for algorithm factories.
This module implements the basic elements defining algorithms.
character(len=algo_label_len), parameter, public update_interactions
character(len=algo_label_len), parameter, public rewind_algorithm
character(len=algo_label_len), parameter, public update_couplings
character(len=algo_label_len), parameter, public iteration_done
character(len=algo_label_len), parameter, public skip
Operations that can be used by any algorithm and, therefore, should be implemented by all systems.
real(real64), parameter, public m_zero
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
integer, parameter, public timing_exact
This module defines classes and functions for interaction partners.
This module defines the abstract class for the interaction factory.
integer, parameter, public no_partners
integer, parameter, public all_except
integer, parameter, public only_partners
integer, parameter, public all_partners
This module implements fully polymorphic linked lists, and some specializations thereof.
subroutine, public messages_update_mpi_grp(namespace, mpigrp)
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_experimental(name, namespace)
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
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.
This module implements the multisystem debug functionality.
subroutine, public multisystem_debug_write_marker(system_namespace, event)
type(event_handle_t) function, public multisystem_debug_write_event_in(system_namespace, event, extra, system_iteration, algo_iteration, interaction_iteration, partner_iteration, requested_iteration)
subroutine, public multisystem_debug_write_event_out(handle, extra, update, system_iteration, algo_iteration, interaction_iteration, partner_iteration, requested_iteration)
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_algorithm_start(this)
subroutine, public system_update_total_energy(this)
Calculate the total energy of the system. The total energy is defined as the sum of the kinetic,...
subroutine system_iteration_info(this)
subroutine, public system_init_iteration_counters(this)
Initialize the iteration counters of the system and its interactions, algorithms and quantities.
integer, parameter, public barrier_restart
subroutine system_update_internal_energy(this)
Calculate the internal energy of the system. The internal energy is defined as the sum of all energie...
logical function system_arrived_at_any_barrier(this)
recursive logical function system_list_contains(this, partner)
subroutine, public system_restart_write(this)
subroutine, public system_update_potential_energy(this)
Calculate the potential energy of the system. The potential energy is defined as the sum of all energ...
subroutine, public system_init_parallelization(this, grp)
Basic functionality: copy the MPI group. This function needs to be implemented by extended types that...
subroutine system_output_start(this)
subroutine system_update_interactions_start(this)
subroutine, public system_algorithm_finish(this)
subroutine system_start_barrier(this, target_time, barrier_index)
recursive subroutine, public system_create_interactions(this, interaction_factory, available_partners)
create the interactions of the system
subroutine, public system_end(this)
subroutine system_output_write(this)
subroutine system_update_interactions_finish(this)
subroutine, public system_execute_algorithm(this)
perform one or more algorithmic operations
subroutine system_update_interactions(this)
Attempt to update all interactions of the system.
class(system_t) function, pointer system_iterator_get_next(this)
logical function system_update_couplings(this)
Update the couplings (quantities) of the interaction partners.
logical function system_process_is_slave(this)
logical function system_arrived_at_barrier(this, barrier_index)
recursive logical function system_algorithm_finished(this)
logical function, public system_restart_read(this)
subroutine, public system_new_algorithm(this, factory)
subroutine system_output_finish(this)
subroutine system_list_add_node(this, partner)
add system to list
subroutine, public system_reset_iteration_counters(this, accumulated_iterations)
subroutine system_end_barrier(this, barrier_index)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
Abstract class for the algorithm factories.
Descriptor of one algorithmic operation.
The ghost ineraction is a dummy interaction, which needs to be setup between otherwise non-interactin...
These class extend the list and list iterator to make an interaction list.
abstract interaction class
abstract class for general interaction partners
iterator for the list of partners
abstract class for interaction factories
type for storing options to be used when creating a given interaction
This class implements the iteration counter used by the multisystem algorithms. As any iteration coun...
This class implements an iterator for the polymorphic linked list.
This is defined even when running serial.
events marking a function call
handle to keep track of in- out- events
events marking an iteration update
Systems (system_t) can expose quantities that can be used to calculate interactions with other system...
These classes extends the list and list iterator to create a system list.
Abstract class for systems.