Octopus
system.F90
Go to the documentation of this file.
1!! Copyright (C) 2019 N. Tancogne-Dejean
2!! Copyright (C) 2020 M. Oliveira, Heiko Appel
3!! Copyright (C) 2021 S. Ohlmann
4!!
5!! This program is free software; you can redistribute it and/or modify
6!! it under the terms of the GNU General Public License as published by
7!! the Free Software Foundation; either version 2, or (at your option)
8!! any later version.
9!!
10!! This program is distributed in the hope that it will be useful,
11!! but WITHOUT ANY WARRANTY; without even the implied warranty of
12!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13!! GNU General Public License for more details.
14!!
15!! You should have received a copy of the GNU General Public License
16!! along with this program; if not, write to the Free Software
17!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18!! 02110-1301, USA.
19!!
20
21#include "global.h"
22
25module system_oct_m
28 use debug_oct_m
30 use global_oct_m
36 use mpi_oct_m
40 use parser_oct_m
43 use unit_oct_m
46 implicit none
47
48 private
49 public :: &
50 system_t, &
63 system_end, &
66
67 type :: barrier_t
68 logical :: active
69 real(real64) :: target_time
70 end type barrier_t
71
72 integer, parameter, public :: &
73 NUMBER_BARRIERS = 1, &
75
79 type, extends(interaction_partner_t), abstract :: system_t
80 private
81 type(iteration_counter_t), public :: iteration
82 class(algorithm_t), pointer, public :: algo => null()
83
84 integer, allocatable, public :: supported_interactions(:)
85 type(interaction_list_t), public :: interactions
86
87 type(mpi_grp_t), public :: grp
88
89 type(barrier_t) :: barrier(NUMBER_BARRIERS)
90 real(real64), public :: kinetic_energy
91 real(real64), public :: potential_energy
92 real(real64), public :: internal_energy
93 real(real64), public :: total_energy
94
95 contains
96 procedure :: execute_algorithm => system_execute_algorithm
97 procedure :: reset_iteration_counters => system_reset_iteration_counters
98 procedure :: new_algorithm => system_new_algorithm
99 procedure :: algorithm_finished => system_algorithm_finished
100 procedure :: init_iteration_counters => system_init_iteration_counters
101 procedure :: create_interactions => system_create_interactions
102 procedure :: init_parallelization => system_init_parallelization
103 procedure :: update_couplings => system_update_couplings
104 procedure :: update_interactions => system_update_interactions
105 procedure :: update_interactions_start => system_update_interactions_start
106 procedure :: update_interactions_finish => system_update_interactions_finish
107 procedure :: algorithm_start => system_algorithm_start
108 procedure :: algorithm_finish => system_algorithm_finish
109 procedure :: iteration_info => system_iteration_info
110 procedure :: restart_write => system_restart_write
111 procedure :: restart_read => system_restart_read
112 procedure :: output_start => system_output_start
113 procedure :: output_write => system_output_write
114 procedure :: output_finish => system_output_finish
115 procedure :: process_is_slave => system_process_is_slave
116 procedure :: start_barrier => system_start_barrier
117 procedure :: end_barrier => system_end_barrier
118 procedure :: arrived_at_barrier => system_arrived_at_barrier
119 procedure :: arrived_at_any_barrier => system_arrived_at_any_barrier
120 procedure :: update_potential_energy => system_update_potential_energy
121 procedure :: update_internal_energy => system_update_internal_energy
122 procedure :: update_total_energy => system_update_total_energy
123 procedure(system_init_interaction), deferred :: init_interaction
124 procedure(system_initialize), deferred :: initialize
125 procedure(system_do_algorithmic_operation), deferred :: do_algorithmic_operation
126 procedure(system_is_tolerance_reached), deferred :: is_tolerance_reached
127 procedure(system_restart_write_data), deferred :: restart_write_data
128 procedure(system_restart_read_data), deferred :: restart_read_data
129 procedure(system_update_kinetic_energy), deferred :: update_kinetic_energy
130 end type system_t
131
132 abstract interface
133
134 ! ---------------------------------------------------------
140 subroutine system_init_interaction(this, interaction)
141 import system_t
142 import interaction_t
143 class(system_t), target, intent(inout) :: this
144 class(interaction_t), intent(inout) :: interaction
145 end subroutine system_init_interaction
146
147 ! ---------------------------------------------------------
149 subroutine system_initialize(this)
150 import system_t
151 class(system_t), intent(inout) :: this
152 end subroutine system_initialize
153
154 ! ---------------------------------------------------------
164 logical function system_do_algorithmic_operation(this, operation, updated_quantities) result(done)
165 import system_t
167 class(system_t), intent(inout) :: this
168 class(algorithmic_operation_t), intent(in) :: operation
169 integer, allocatable, intent(out) :: updated_quantities(:)
171
172 ! ---------------------------------------------------------
174 logical function system_is_tolerance_reached(this, tol)
175 use, intrinsic :: iso_fortran_env
176 import system_t
177 class(system_t), intent(in) :: this
178 real(real64), intent(in) :: tol
179 end function system_is_tolerance_reached
181 ! ---------------------------------------------------------
186 import system_t
187 class(system_t), intent(inout) :: this
188 end subroutine system_store_current_status
190 ! ---------------------------------------------------------
192 import system_t
193 class(system_t), intent(inout) :: this
196 ! ---------------------------------------------------------
197 ! this function returns true if restart data could be read
198 logical function system_restart_read_data(this)
199 import system_t
200 class(system_t), intent(inout) :: this
203 import system_t
204 class(system_t), intent(inout) :: this
207 end interface
214 private
215 contains
216 procedure :: add => system_list_add_node
217 procedure :: contains => system_list_contains
221 private
222 contains
223 procedure :: get_next => system_iterator_get_next
224 end type system_iterator_t
225
226contains
227
228 ! ---------------------------------------------------------
241 subroutine system_execute_algorithm(this)
242 class(system_t), intent(inout) :: this
243
244 type(algorithmic_operation_t) :: operation
245 logical :: all_updated, at_barrier, operation_done
246 type(event_handle_t) :: debug_handle
247 integer :: iq, iuq
248 integer, allocatable :: updated_quantities(:)
249
251
252 at_barrier = .false.
253
254 do while (.not. at_barrier)
255
256 operation = this%algo%get_current_operation()
258 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("dt_operation", operation), &
259 system_iteration=this%iteration, algo_iteration=this%algo%iteration)
260
261 ! First try to execute the operation as a system specific operation
262 operation_done = this%do_algorithmic_operation(operation, updated_quantities)
263 if (allocated(updated_quantities)) then
264 ! Update the quantities iteration counters
265 do iuq = 1, size(updated_quantities)
266 iq = updated_quantities(iuq)
267 call this%quantities(iq)%iteration%set(this%algo%iteration + 1)
268 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("quantity", quantity_label(iq), &
269 this%quantities(iq)%iteration, "set"))
270 end do
271 end if
272
273 ! If not done, we try to execute it as an algorithm-specific operation.
274 if (.not. operation_done) then
275 operation_done = this%algo%do_operation(operation)
276 else
277 call this%algo%next()
278 end if
279
280 ! If still not done, the operation must be a generic operation
281 if (.not. operation_done) then
282
283 select case (operation%id)
284 case (skip)
285 ! Do nothing
286 call this%algo%next()
287
288 case (iteration_done)
289 ! Increment the system iteration by one
290 this%iteration = this%iteration + 1
291 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("system", "", this%iteration, "tick"))
292
293 ! Recompute the total energy
294 call this%update_total_energy()
296 ! Write output
297 call this%output_write()
298
299 ! Update elapsed time
300 call this%algo%update_elapsed_time()
301
302 ! Print information about the current iteration
303 ! (NB: needs to be done after marking the execution step as finished,
304 ! so that the timings are correct)
305 call this%iteration_info()
307 call this%algo%next()
308
310 if (.not. this%algo%finished()) then
311 if (.not. this%arrived_at_any_barrier()) then
312 ! Reset propagator for next step if not waiting at barrier
313 call this%algo%rewind()
314 else
315 at_barrier = .true.
316 end if
317 else
318 if (this%algo%continues_after_finished()) then
319 call this%algo%rewind()
320 else
321 at_barrier = .true.
322 end if
323 end if
324
325 case (update_couplings)
326 ! We increment by one algorithmic step
327 this%algo%iteration = this%algo%iteration + 1
328 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("algorithm", "", &
329 this%algo%iteration, "tick"))
330
331 ! Try to update all needed quantities from the interaction partners
332 all_updated = this%update_couplings()
333
334 ! Move to next algorithm step if all couplings have been
335 ! updated. Otherwise roll back the iteration counter and try again later.
336 if (all_updated) then
337 call this%algo%next()
338 else
339 this%algo%iteration = this%algo%iteration - 1
340 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("algorithm", "", &
341 this%algo%iteration, "reverse"))
342 end if
343
344 ! Couplings are implicit barriers
345 at_barrier = .true.
346
348 ! Update all the interactions
349 call this%update_interactions()
350 call this%algo%next()
351
352 case default
353 message(1) = "Unsupported algorithmic operation."
354 write(message(2), '(A,A,A)') trim(operation%id), ": ", trim(operation%label)
355 call messages_fatal(2, namespace=this%namespace)
356 end select
357 end if
358
359 call multisystem_debug_write_event_out(debug_handle, system_iteration=this%iteration, algo_iteration=this%algo%iteration)
360 end do
361
363 end subroutine system_execute_algorithm
364
365 ! ---------------------------------------------------------
366 subroutine system_reset_iteration_counters(this, accumulated_iterations)
367 class(system_t), intent(inout) :: this
368 integer, intent(in) :: accumulated_iterations
369
370 integer :: iq
371 type(interaction_iterator_t) :: iter
372 class(interaction_t), pointer :: interaction
373
374 character(len=MAX_INFO_LEN) :: extended_label
375
377
378 ! Propagator counter
379 this%algo%iteration = this%algo%iteration - accumulated_iterations
380 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("algorithm", "", this%algo%iteration, "reset"))
381
382 ! Interaction counters
383 call iter%start(this%interactions)
384 do while (iter%has_next())
385 interaction => iter%get_next()
386 interaction%iteration = interaction%iteration - accumulated_iterations
387
388 extended_label = trim(interaction%label)//"-"//trim(interaction%partner%namespace%get())
389 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t( "interaction", extended_label, &
390 interaction%iteration, "reset"))
391 end do
392
393 ! Internal quantities counters
394 do iq = 1, max_quantities
395 if (this%quantities(iq)%required) then
396 this%quantities(iq)%iteration = this%quantities(iq)%iteration - accumulated_iterations
397 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("quantity", quantity_label(iq), &
398 this%quantities(iq)%iteration, "reset"))
399 end if
400 end do
401
404
405
406 ! ---------------------------------------------------------
419 recursive subroutine system_create_interactions(this, interaction_factory, available_partners)
420 class(system_t), intent(inout) :: this
421 class(interactions_factory_abst_t), intent(in) :: interaction_factory
422 class(partner_list_t), target, intent(in) :: available_partners
423
424 logical :: in_list
425 integer :: i, ip, interaction_type
426 type(partner_list_t) :: partners
427 type(partner_iterator_t) :: iter
428 class(interaction_partner_t), pointer :: partner
429 class(interaction_t), pointer :: interaction
430 type(interactions_factory_options_t), allocatable :: options(:)
431
433
434 ! Sanity checks
435 assert(allocated(this%supported_interactions))
436 assert(allocated(this%supported_interactions_as_partner))
437
438
439 ! All systems need to be connected to make sure they remain synchronized.
440 ! We enforce that be adding a ghost interaction between all systems.
441 ! Note that this recursively adds subsystems of containers.
442 call iter%start(available_partners)
443 do while (iter%has_next())
444 partner => iter%get_next()
445 call partner%add_partners_to_list(partners)
446 end do
447
448 call iter%start(partners)
449 do while (iter%has_next())
450 partner => iter%get_next()
451
452 ! No self-interaction
453 if (partner%namespace%get() == this%namespace%get()) cycle
454
455 call this%interactions%add(ghost_interaction_t(partner))
456 end do
457
458
459 ! Now create the non-ghost interactions:
460 ! Here we only add systems to the parters list, which support the given interaction as a partner
461 ! Note that ensemble containers do not add their subsystems to the list.
462 ! (see ensemble_oct_m::ensemble_add_parters_to_list())
463
464 call partners%empty()
465
466 ! Get options to use to create all the interactions supported by this system
467 allocate(options(0)) ! Workaround to avoid a gfortran warning
468 options = interaction_factory%options(this%namespace, this%supported_interactions)
469
470 ! Loop over all interactions supported by this system and create them according to the provided options
471 do i = 1, size(this%supported_interactions)
472 interaction_type = this%supported_interactions(i)
473
474 ! Supported interactions should only appear once in the corresponding
475 ! list, otherwise more than one interaction of the same type will be
476 ! created
477 assert(count(this%supported_interactions == interaction_type) == 1)
478
479 ! Get the list of partners that support this interaction type
480 call iter%start(available_partners)
481 do while (iter%has_next())
482 partner => iter%get_next()
483 call partner%add_partners_to_list(partners, interaction_type)
484 end do
485
486 ! Create list of partners for this interaction taking into account the selected mode
487 select case (options(i)%mode)
488 case (all_partners)
489 ! Use all available partners, so no need to modify the list
490
491 case (no_partners)
492 ! No partners for this interaction, so empty the list
493 call partners%empty()
494
495 case (only_partners)
496 ! Start with full list and remove the partners not listed in the options
497 call iter%start(partners)
498 do while (iter%has_next())
499 partner => iter%get_next()
500 in_list = .false.
501 do ip = 1, size(options(i)%partners)
502 if (partner%namespace%is_contained_in(options(i)%partners(ip))) then
503 in_list = .true.
504 exit
505 end if
506 end do
507 if (.not. in_list) then
508 call partners%delete(partner)
509 end if
510 end do
511
513 ! Start with full list and remove the partners listed in the options
514 do ip = 1, size(options(i)%partners)
515 call iter%start(partners)
516 do while (iter%has_next())
517 partner => iter%get_next()
518 if (partner%namespace%is_contained_in(options(i)%partners(ip))) then
519 call partners%delete(partner)
520 end if
521 end do
522 end do
523
524 end select
525
526 ! Now actually create the interactions for the selected partners
527 call iter%start(partners)
528 do while (iter%has_next())
529 partner => iter%get_next()
530
531 interaction => interaction_factory%create(interaction_type, partner)
532
533
534 ! Set flag for self-interaction
535 interaction%intra_interaction = partner%namespace%get() == this%namespace%get()
536
537 ! Set timing and perform sanity checks
538 interaction%timing = options(i)%timing
539 if (interaction%timing == timing_exact) then
540 select type (partner => interaction%partner)
541 class is (system_t)
542 if (this%algo%iteration%global_step() /= partner%algo%iteration%global_step() .and. &
543 .not. all(partner%quantities(interaction%couplings_from_partner)%always_available)) then
544 write(message(1), '(2a)') "InteractionTiming was set to exact timing, but systems ", &
545 trim(this%namespace%get())
546 write(message(2), '(3a)') "and ", trim(partner%namespace%get()), " have incompatible steps."
547 call messages_fatal(2, namespace=this%namespace)
548 end if
549 end select
550 end if
551
552 ! Initialize interaction from system and from partner
553 call this%init_interaction(interaction)
554 call interaction%partner%init_interaction_as_partner(interaction)
555
556 !Mark all the quantities needed by the interaction from the system and the partner as required
557 if (allocated(interaction%system_quantities)) then
558 this%quantities(interaction%system_quantities)%required = .true.
559 end if
560 if (allocated(interaction%couplings_from_partner)) then
561 partner%quantities(interaction%couplings_from_partner)%required = .true.
562 end if
563
564 ! Add interaction to list
565 call this%interactions%add(interaction)
566 end do
567
568 ! Empty partner list for next interaction
569 call partners%empty()
570 end do
571
573 end subroutine system_create_interactions
574
575 ! ---------------------------------------------------------
581 logical function system_update_couplings(this) result(all_updated)
582 class(system_t), intent(inout) :: this
583
584 class(interaction_t), pointer :: interaction
585 type(interaction_iterator_t) :: iter
586
588
589 all_updated = .true.
590 call iter%start(this%interactions)
591 do while (iter%has_next())
592 interaction => iter%get_next()
593
594 select type (partner => interaction%partner)
595 class is (system_t)
596 ! If the partner is a system, we can only update its couplings if it
597 ! is not too much behind the requested iteration
598 if (partner%algo%iteration + 1 >= this%algo%iteration) then
599 call interaction%update_partner_couplings(this%algo%iteration)
600 end if
601
602 class default
603 ! Partner that are not systems can have their couplings updated at any iteration
604 call interaction%update_partner_couplings(this%algo%iteration)
605 end select
606
607 all_updated = all_updated .and. interaction%partner_couplings_up_to_date
608 end do
609
611 end function system_update_couplings
612
613 ! ---------------------------------------------------------
618 subroutine system_update_interactions(this)
619 class(system_t), intent(inout) :: this
620
621 integer :: iq, q_id, n_quantities
622 class(interaction_t), pointer :: interaction
623 type(interaction_iterator_t) :: iter
624
626
627 ! Some systems might need to perform some specific operations before the
628 ! update.
629 call this%update_interactions_start()
630
631 !Loop over all interactions
632 call iter%start(this%interactions)
633 do while (iter%has_next())
634 interaction => iter%get_next()
635
636 ! Update the system quantities that will be needed for computing the interaction
637 if (allocated(interaction%system_quantities)) then
638 n_quantities = size(interaction%system_quantities)
639 else
640 n_quantities = 0
641 end if
642 do iq = 1, n_quantities
643 ! Get requested quantity ID
644 q_id = interaction%system_quantities(iq)
645
646 if (.not. this%quantities(q_id)%iteration == this%algo%iteration) then
647 ! The requested quantity is not at the requested iteration, so we try to update it
648
649 if (.not. this%quantities(q_id)%updated_on_demand) then
650 ! Quantity must be at the correct iteration, otherwise the algorithm and
651 ! the interaction are incompatible
652 if (.not. this%quantities(q_id)%iteration == this%algo%iteration .and. &
653 .not. this%quantities(q_id)%always_available) then
654 write(message(1), '(5a)') "Interaction ", trim(interaction%label), " is incompatible with the selected algorithm."
655 write(message(2), '(3a)') "The interaction requires the ", trim(quantity_label(q_id)), &
656 " at a iteration it is not available."
657 call messages_fatal(2, namespace=this%namespace)
658 end if
659
660 ! We do not need to update quantities that are not updated on
661 ! demand, as the algorithm takes care of doing that, so move on to
662 ! next quantity
663 cycle
664 end if
665
666 ! Sanity check: it should never happen that the quantity is in advance
667 ! with respect to the requested iteration.
668 if (this%quantities(q_id)%iteration > this%algo%iteration) then
669 message(1) = "The quantity iteration is in advance compared to the requested iteration."
670 call messages_fatal(1, namespace=this%namespace)
671 end if
672
673 call this%update_quantity(q_id)
675 this%quantities(q_id)%iteration, "set"))
676 end if
677
678 end do
679
680 call interaction%update(this%algo%iteration)
681 end do
682
683 ! Some systems might need to perform some specific operations after all the
684 ! interactions have been updated
685 call this%update_interactions_finish()
686
688 end subroutine system_update_interactions
689
690 ! ---------------------------------------------------------
691 subroutine system_update_interactions_start(this)
692 class(system_t), intent(inout) :: this
693
695
696 ! By default nothing is done just before updating the interactions. Child
697 ! classes that wish to change this behaviour should override this method.
698
701
702 ! ---------------------------------------------------------
703 subroutine system_update_interactions_finish(this)
704 class(system_t), intent(inout) :: this
705
707
708 ! By default nothing is done just after updating the interactions. Child
709 ! classes that wish to change this behaviour should override this method.
710
713
714 ! ---------------------------------------------------------
715 subroutine system_restart_write(this)
716 class(system_t), intent(inout) :: this
717
718 logical :: restart_write
719 type(interaction_iterator_t) :: iter
720 class(interaction_t), pointer :: interaction
721 integer :: ii
722
723 push_sub(system_restart_write)
724
725 call parse_variable(this%namespace, 'RestartWrite', .true., restart_write)
726
727 if (restart_write) then
728 ! do some generic restart steps here
729 ! write iteration counter restart data
730 call this%iteration%restart_write('restart_iteration_system', this%namespace)
731 call this%algo%iteration%restart_write('restart_iteration_algorithm', this%namespace)
732 call iter%start(this%interactions)
733 do while (iter%has_next())
734 interaction => iter%get_next()
735 call interaction%restart_write(this%namespace)
736 end do
737 do ii = 1, max_quantities
738 if (this%quantities(ii)%required) then
739 call this%quantities(ii)%iteration%restart_write('restart_iteration_quantity_'//trim(quantity_label(ii)), &
740 this%namespace)
741 end if
742 end do
743 ! the following call is delegated to the corresponding system
744 call this%restart_write_data()
745 message(1) = "Wrote restart data for system "//trim(this%namespace%get())
746 call messages_info(1, namespace=this%namespace)
747 end if
748
749 pop_sub(system_restart_write)
750 end subroutine system_restart_write
751
752 ! ---------------------------------------------------------
753 ! this function returns true if restart data could be read
754 logical function system_restart_read(this)
755 class(system_t), intent(inout) :: this
756
757 type(interaction_iterator_t) :: iter
758 class(interaction_t), pointer :: interaction
759 integer :: ii
760
761 push_sub(system_restart_read)
762
763 ! do some generic restart steps here
764 ! read iteration data
765 system_restart_read = this%iteration%restart_read('restart_iteration_system', this%namespace)
767 this%algo%iteration%restart_read('restart_iteration_algorithm', this%namespace)
768 call iter%start(this%interactions)
769 do while (iter%has_next())
770 interaction => iter%get_next()
771 system_restart_read = system_restart_read .and. interaction%restart_read(this%namespace)
772 ! reduce by one because of the first UPDATE_INTERACTIONS
773 interaction%iteration = interaction%iteration - 1
774 end do
775 do ii = 1, max_quantities
776 if (this%quantities(ii)%required) then
778 this%quantities(ii)%iteration%restart_read('restart_iteration_quantity_'//trim(quantity_label(ii)), &
779 this%namespace)
780 end if
781 if (this%quantities(ii)%updated_on_demand) then
782 ! decrease iteration by one for on-demand quantities to account for initial update_interactions step
783 this%quantities(ii)%iteration = this%quantities(ii)%iteration - 1
784 end if
785 end do
786 ! the following call is delegated to the corresponding system
787 system_restart_read = system_restart_read .and. this%restart_read_data()
788
789 if (system_restart_read) then
790 message(1) = "Successfully read restart data for system "//trim(this%namespace%get())
791 call messages_info(1, namespace=this%namespace)
792 end if
793
794 pop_sub(system_restart_read)
795 end function system_restart_read
797 ! ---------------------------------------------------------
798 subroutine system_output_start(this)
799 class(system_t), intent(inout) :: this
800
801 push_sub(system_output_start)
802
803 ! By default nothing is done to regarding output. Child classes that wish
804 ! to change this behaviour should override this method.
805
806 pop_sub(system_output_start)
807 end subroutine system_output_start
809 ! ---------------------------------------------------------
810 subroutine system_output_write(this)
811 class(system_t), intent(inout) :: this
812
813 push_sub(system_output_write)
814
815 ! By default nothing is done to regarding output. Child classes that wish
816 ! to change this behaviour should override this method.
817
818 pop_sub(system_output_write)
819 end subroutine system_output_write
820
821 ! ---------------------------------------------------------
822 subroutine system_output_finish(this)
823 class(system_t), intent(inout) :: this
824
825 push_sub(system_output_finish)
826
827 ! By default nothing is done to regarding output. Child classes that wish
828 ! to change this behaviour should override this method.
829
830 pop_sub(system_output_finish)
831 end subroutine system_output_finish
832
833 ! ---------------------------------------------------------
834 subroutine system_new_algorithm(this, factory)
835 class(system_t), intent(inout) :: this
836 class(algorithm_factory_t), intent(in) :: factory
837
838 integer :: ii
839
840 push_sub(system_new_algorithm)
841
842 call messages_experimental('Multi-system framework')
843
844 this%algo => factory%create(this)
845
846 call this%init_iteration_counters()
848 do ii = 1, number_barriers
849 this%barrier(ii)%active = .false.
850 this%barrier(ii)%target_time = m_zero
851 end do
852
853 pop_sub(system_new_algorithm)
854 end subroutine system_new_algorithm
855
856 ! ---------------------------------------------------------------------------------------
857 recursive function system_algorithm_finished(this) result(finished)
858 class(system_t), intent(in) :: this
859 logical :: finished
860
861 finished = this%algo%finished()
862
863 end function system_algorithm_finished
864
865 ! ---------------------------------------------------------
871 !
872 subroutine system_init_iteration_counters(this)
873 class(system_t), intent(inout) :: this
874
875 type(interaction_iterator_t) :: iter
876 class(interaction_t), pointer :: interaction
877
879
880 ! Initialize algorithm and system counters
881 call this%algo%init_iteration_counters()
882
883 ! Interactions counters
884 call iter%start(this%interactions)
885 do while (iter%has_next())
886 interaction => iter%get_next()
887 interaction%iteration = this%algo%iteration - 1
888 end do
889
890 ! Required quantities counters
891 where (this%quantities%required)
892 this%quantities%iteration = this%algo%iteration
893 end where
894
895 ! On demand quantities will be updated before first use,
896 ! hence we set the iteration counter one iteration behind the algorithms iteration counter
897 where (this%quantities%updated_on_demand)
898 this%quantities%iteration = this%algo%iteration - 1
899 end where
900
902 end subroutine system_init_iteration_counters
904 ! ---------------------------------------------------------
905 subroutine system_algorithm_start(this)
906 class(system_t), intent(inout) :: this
907
908 logical :: all_updated
909 type(event_handle_t) :: debug_handle
910 integer, allocatable :: updated_quantities(:)
911
912 push_sub(system_algorithm_start)
913
914 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_algorithm_start"), &
915 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
916
917 ! Update interactions at initial iteration
918 all_updated = this%update_couplings()
919 if (.not. all_updated) then
920 message(1) = "Unable to update interactions when initializing the algorithm."
921 call messages_fatal(1, namespace=this%namespace)
922 end if
923 call this%update_interactions()
924
925 ! System-specific and algorithm-specific initialization step
926 if (this%algo%start_operation%id /= skip) then
927 if (.not. this%do_algorithmic_operation(this%algo%start_operation, updated_quantities)) then
928 message(1) = "Unsupported algorithmic operation."
929 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
930 call messages_fatal(2, namespace=this%namespace)
931 else if (allocated(updated_quantities)) then
932 message(1) = "Update of quantities not allowed in algorithmic operation."
933 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
934 call messages_fatal(2, namespace=this%namespace)
935 end if
936 end if
937
938 ! Compute the total energy at the beginning of the simulation
939 call this%update_total_energy()
940
941 ! Start output
942 call this%output_start()
943
944 ! Write header for execution log
945 call this%algo%write_output_header()
946
947 ! Rewind algorithm (will also set the initial time to compute the elapsed time)
948 call this%algo%rewind()
949
950 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
951
953 end subroutine system_algorithm_start
954
955 ! ---------------------------------------------------------
956 subroutine system_algorithm_finish(this)
957 class(system_t), intent(inout) :: this
958 type(event_handle_t) :: debug_handle
959
960 integer, allocatable :: updated_quantities(:)
961
963
964 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_algorithm_finish"), &
965 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
966
967 ! Finish output
968 call this%output_finish()
969
970 ! System-specific and algorithm-specific finalization step
971 if (this%algo%final_operation%id /= skip) then
972 if (.not. this%do_algorithmic_operation(this%algo%final_operation, updated_quantities)) then
973 message(1) = "Unsupported algorithmic operation."
974 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
975 call messages_fatal(2, namespace=this%namespace)
976 else if (allocated(updated_quantities)) then
977 message(1) = "Update of quantities not allowed in algorithmic operation."
978 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
979 call messages_fatal(2, namespace=this%namespace)
980 end if
981 end if
982
983 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
984
986 end subroutine system_algorithm_finish
987
988 ! ---------------------------------------------------------
989 subroutine system_iteration_info(this)
990 class(system_t), intent(in) :: this
991
992 real(real64) :: energy
993 character(len=40) :: fmt
994
995 push_sub(system_iteration_info)
996
997 energy = units_from_atomic(units_out%energy, this%total_energy)
998 if (abs(energy) >= 1e5) then
999 fmt = '(i7,1x,f14.6,1X,es13.6,1X,i9,1X,'
1000 else
1001 fmt = '(i7,1x,f14.6,1X,f13.6,1X,i9,1X,'
1002 end if
1003 if (this%algo%elapsed_time < 1e-3) then
1004 fmt = trim(fmt)//'es13.3)'
1005 else
1006 fmt = trim(fmt)//'f13.3)'
1007 end if
1008
1009 write(message(1), fmt) this%iteration%counter(), &
1010 units_from_atomic(units_out%time, this%iteration%value()), energy, &
1011 0, this%algo%elapsed_time
1012 call messages_info(1, namespace=this%namespace)
1013
1014 pop_sub(system_iteration_info)
1015 end subroutine system_iteration_info
1016
1017 ! ---------------------------------------------------------
1018 logical function system_process_is_slave(this)
1019 class(system_t), intent(in) :: this
1020
1021 push_sub(system_process_is_slave)
1022
1023 ! By default an MPI process is not a slave
1024 system_process_is_slave = .false.
1025
1027 end function system_process_is_slave
1028
1029 ! ---------------------------------------------------------
1030 subroutine system_end(this)
1031 class(system_t), intent(inout) :: this
1032
1033 type(interaction_iterator_t) :: iter
1034 class(interaction_t), pointer :: interaction
1035
1036 push_sub(system_end)
1037
1038 ! No call to safe_deallocate macro here, as it gives an ICE with gfortran
1039 if (associated(this%algo)) then
1040 deallocate(this%algo)
1041 end if
1042
1043 call iter%start(this%interactions)
1044 do while (iter%has_next())
1045 interaction => iter%get_next()
1046 if (associated(interaction)) then
1047 deallocate(interaction)
1048 end if
1049 end do
1050
1051 pop_sub(system_end)
1052 end subroutine system_end
1053
1054 ! ---------------------------------------------------------
1056 subroutine system_list_add_node(this, partner)
1057 class(system_list_t) :: this
1058 class(interaction_partner_t), target :: partner
1059
1060 push_sub(system_list_add_node)
1061
1062 select type (partner)
1063 class is (system_t)
1064 call this%add_ptr(partner)
1065 class default
1066 assert(.false.)
1067 end select
1068
1069 pop_sub(system_list_add_node)
1070 end subroutine system_list_add_node
1071
1072 ! ---------------------------------------------------------
1073 recursive logical function system_list_contains(this, partner) result(contains)
1074 class(system_list_t) :: this
1075 class(interaction_partner_t), target :: partner
1076
1077 type(partner_iterator_t) :: iterator
1078 class(interaction_partner_t), pointer :: system
1079
1080 push_sub(system_list_contains)
1081
1082 contains = .false.
1083
1084 select type (partner)
1085 class is (system_t)
1086
1087 call iterator%start(this)
1088 do while (iterator%has_next() .and. .not. contains)
1089 system => iterator%get_next()
1090 contains = associated(system, partner)
1091 end do
1092
1093 class default
1094 contains = .false.
1095 end select
1096
1097 pop_sub(system_list_contains)
1098 end function system_list_contains
1099
1100 ! ---------------------------------------------------------
1101 function system_iterator_get_next(this) result(system)
1102 class(system_iterator_t), intent(inout) :: this
1103 class(system_t), pointer :: system
1104
1105 push_sub(system_iterator_get_next)
1106
1107 select type (ptr => this%get_next_ptr())
1108 class is (system_t)
1109 system => ptr
1110 class default
1111 assert(.false.)
1112 end select
1113
1115 end function system_iterator_get_next
1116
1117 ! ---------------------------------------------------------
1121 subroutine system_init_parallelization(this, grp)
1122 class(system_t), intent(inout) :: this
1123 type(mpi_grp_t), intent(in) :: grp
1124
1126
1127 call mpi_grp_copy(this%grp, grp)
1128 call messages_update_mpi_grp(this%namespace, grp)
1129
1131 end subroutine system_init_parallelization
1132
1133
1134
1135 ! ---------------------------------------------------------
1136 subroutine system_start_barrier(this, target_time, barrier_index)
1137 class(system_t), intent(inout) :: this
1138 real(real64), intent(in) :: target_time
1139 integer, intent(in) :: barrier_index
1140
1141 push_sub(system_start_barrier)
1142
1143 this%barrier(barrier_index)%active = .true.
1144 this%barrier(barrier_index)%target_time = target_time
1145
1146 pop_sub(system_start_barrier)
1147 end subroutine system_start_barrier
1148
1149 ! ---------------------------------------------------------
1150 subroutine system_end_barrier(this, barrier_index)
1151 class(system_t), intent(inout) :: this
1152 integer, intent(in) :: barrier_index
1153
1154 push_sub(system_end_barrier)
1155
1156 this%barrier(barrier_index)%active = .false.
1157 this%barrier(barrier_index)%target_time = m_zero
1158
1159 pop_sub(system_end_barrier)
1160 end subroutine system_end_barrier
1161
1162 ! ---------------------------------------------------------
1163 logical function system_arrived_at_barrier(this, barrier_index)
1164 class(system_t), intent(inout) :: this
1165 integer, intent(in) :: barrier_index
1167 type(iteration_counter_t) :: iteration
1168
1170
1172 if (this%barrier(barrier_index)%active) then
1173 iteration = this%iteration + 1
1174 if (iteration%value() > this%barrier(barrier_index)%target_time) then
1176 end if
1177 end if
1178
1180 end function system_arrived_at_barrier
1181
1182 ! ---------------------------------------------------------
1183 logical function system_arrived_at_any_barrier(this)
1184 class(system_t), intent(inout) :: this
1185
1186 integer :: ii
1187
1189
1191 do ii = 1, number_barriers
1193 .or. this%arrived_at_barrier(ii)
1194 end do
1195
1198
1199
1200 ! ---------------------------------------------------------
1205 subroutine system_update_potential_energy(this)
1206 class(system_t), intent(inout) :: this
1207
1208 type(interaction_iterator_t) :: iter
1209 class(interaction_t), pointer :: interaction
1210
1212
1213 this%potential_energy = m_zero
1215 call iter%start(this%interactions)
1216 do while (iter%has_next())
1217 interaction => iter%get_next()
1218 if(.not. interaction%intra_interaction) then
1219 call interaction%calculate_energy()
1220 this%potential_energy = this%potential_energy + interaction%energy
1221 end if
1222 end do
1223
1225 end subroutine system_update_potential_energy
1226
1227 ! ---------------------------------------------------------
1232 subroutine system_update_internal_energy(this)
1233 class(system_t), intent(inout) :: this
1234
1235 type(interaction_iterator_t) :: iter
1236 class(interaction_t), pointer :: interaction
1237
1239
1240 this%internal_energy = m_zero
1241 call iter%start(this%interactions)
1242 do while (iter%has_next())
1243 interaction => iter%get_next()
1244 if(interaction%intra_interaction) then
1245 call interaction%calculate_energy()
1246 this%internal_energy = this%internal_energy + interaction%energy
1247 end if
1248 end do
1249
1251 end subroutine system_update_internal_energy
1252
1253 ! ---------------------------------------------------------
1257 subroutine system_update_total_energy(this)
1258 class(system_t), intent(inout) :: this
1259
1261
1262 call this%update_kinetic_energy()
1263 this%total_energy = this%kinetic_energy
1264
1266 call this%update_potential_energy()
1267 this%total_energy = this%total_energy + this%potential_energy
1268
1270 call this%update_internal_energy()
1271 this%total_energy = this%total_energy + this%internal_energy
1272
1274 end subroutine system_update_total_energy
1275
1277
1278!! Local Variables:
1279!! mode: f90
1280!! coding: utf-8
1281!! End:
Execute one operation that is part of a larger algorithm. Returns true if the operation was successfu...
Definition: system.F90:257
initialize a given interaction of the system
Definition: system.F90:233
set initial conditions for a system
Definition: system.F90:242
check whether a system has reached a given tolerance
Definition: system.F90:267
For some algorithms it might be necessary to store the status of a system at a given algorithmic step...
Definition: system.F90:278
This module defines the abstract interfact for algorithm factories.
This module implements the basic elements defining algorithms.
Definition: algorithm.F90:141
character(len=algo_label_len), parameter, public update_interactions
Definition: algorithm.F90:172
character(len=algo_label_len), parameter, public rewind_algorithm
Definition: algorithm.F90:172
character(len=algo_label_len), parameter, public update_couplings
Definition: algorithm.F90:172
character(len=algo_label_len), parameter, public iteration_done
Definition: algorithm.F90:172
character(len=algo_label_len), parameter, public skip
Operations that can be used by any algorithm and, therefore, should be implemented by all systems.
Definition: algorithm.F90:172
real(real64), parameter, public m_zero
Definition: global.F90:187
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 only_partners
This module implements fully polymorphic linked lists, and some specializations thereof.
subroutine, public messages_update_mpi_grp(namespace, mpigrp)
Definition: messages.F90:377
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:420
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1097
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:624
subroutine mpi_grp_copy(mpi_grp_out, mpi_grp_in)
Definition: mpi.F90:403
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...
Definition: quantity.F90:137
character(len=17), dimension(max_quantities), parameter, public quantity_label
Definition: quantity.F90:165
integer, parameter, public max_quantities
Definition: quantity.F90:146
This module implements the abstract system type.
Definition: system.F90:118
subroutine, public system_algorithm_start(this)
Definition: system.F90:999
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,...
Definition: system.F90:1351
subroutine system_iteration_info(this)
Definition: system.F90:1083
subroutine, public system_init_iteration_counters(this)
Initialize the iteration counters of the system and its interactions, algorithms and quantities.
Definition: system.F90:966
integer, parameter, public barrier_restart
Definition: system.F90:165
subroutine system_update_internal_energy(this)
Calculate the internal energy of the system. The internal energy is defined as the sum of all energie...
Definition: system.F90:1326
logical function system_arrived_at_any_barrier(this)
Definition: system.F90:1277
recursive logical function system_list_contains(this, partner)
Definition: system.F90:1167
subroutine, public system_restart_write(this)
Definition: system.F90:809
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...
Definition: system.F90:1299
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:1215
subroutine system_output_start(this)
Definition: system.F90:892
subroutine system_update_interactions_start(this)
Definition: system.F90:785
subroutine, public system_algorithm_finish(this)
Definition: system.F90:1050
subroutine system_start_barrier(this, target_time, barrier_index)
Definition: system.F90:1230
recursive subroutine, public system_create_interactions(this, interaction_factory, available_partners)
create the interactions of the system
Definition: system.F90:513
subroutine, public system_end(this)
Definition: system.F90:1124
subroutine system_output_write(this)
Definition: system.F90:904
subroutine system_update_interactions_finish(this)
Definition: system.F90:797
subroutine, public system_execute_algorithm(this)
perform one or more algorithmic operations
Definition: system.F90:335
subroutine system_update_interactions(this)
Attempt to update all interactions of the system.
Definition: system.F90:712
class(system_t) function, pointer system_iterator_get_next(this)
Definition: system.F90:1195
logical function system_update_couplings(this)
Update the couplings (quantities) of the interaction partners.
Definition: system.F90:675
logical function system_process_is_slave(this)
Definition: system.F90:1112
logical function system_arrived_at_barrier(this, barrier_index)
Definition: system.F90:1257
recursive logical function system_algorithm_finished(this)
Definition: system.F90:951
logical function, public system_restart_read(this)
Definition: system.F90:848
subroutine, public system_new_algorithm(this, factory)
Definition: system.F90:928
subroutine system_output_finish(this)
Definition: system.F90:916
subroutine system_list_add_node(this, partner)
add system to list
Definition: system.F90:1150
subroutine, public system_reset_iteration_counters(this, accumulated_iterations)
Definition: system.F90:460
subroutine system_end_barrier(this, barrier_index)
Definition: system.F90:1244
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
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.
Definition: algorithm.F90:163
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
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.
Definition: mpi.F90:142
handle to keep track of in- out- events
These classes extends the list and list iterator to create a system list.
Definition: system.F90:306
Abstract class for systems.
Definition: system.F90:172
int true(void)