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
35 use mpi_oct_m
39 use parser_oct_m
42 use unit_oct_m
45 implicit none
46
47 private
48 public :: &
49 system_t, &
61 system_end, &
64
65 type :: barrier_t
66 logical :: active
67 float :: target_time
68 end type barrier_t
69
70 integer, parameter, public :: &
71 NUMBER_BARRIERS = 1, &
73
77 type, extends(interaction_partner_t), abstract :: system_t
78 private
79 type(iteration_counter_t), public :: iteration
80 class(algorithm_t), pointer, public :: algo => null()
81
82 type(integer_list_t), public :: supported_interactions
83 type(interaction_list_t), public :: interactions
84
85 type(mpi_grp_t), public :: grp
86
87 type(barrier_t) :: barrier(NUMBER_BARRIERS)
88 float, public :: kinetic_energy
89 float, public :: potential_energy
90 float, public :: internal_energy
91 float, public :: total_energy
92
93 contains
94 procedure :: execute_algorithm => system_execute_algorithm
95 procedure :: reset_iteration_counters => system_reset_iteration_counters
96 procedure :: init_algorithm => system_init_algorithm
97 procedure :: algorithm_finished => system_algorithm_finished
98 procedure :: init_iteration_counters => system_init_iteration_counters
99 procedure :: init_all_interactions => system_init_all_interactions
100 procedure :: init_parallelization => system_init_parallelization
101 procedure :: update_couplings => system_update_couplings
102 procedure :: update_interactions => system_update_interactions
103 procedure :: update_interactions_start => system_update_interactions_start
104 procedure :: update_interactions_finish => system_update_interactions_finish
105 procedure :: propagation_start => system_propagation_start
106 procedure :: propagation_finish => system_propagation_finish
107 procedure :: iteration_info => system_iteration_info
108 procedure :: restart_write => system_restart_write
109 procedure :: restart_read => system_restart_read
110 procedure :: output_start => system_output_start
111 procedure :: output_write => system_output_write
112 procedure :: output_finish => system_output_finish
113 procedure :: process_is_slave => system_process_is_slave
114 procedure :: start_barrier => system_start_barrier
115 procedure :: end_barrier => system_end_barrier
116 procedure :: arrived_at_barrier => system_arrived_at_barrier
117 procedure :: arrived_at_any_barrier => system_arrived_at_any_barrier
118 procedure :: update_potential_energy => system_update_potential_energy
119 procedure :: update_internal_energy => system_update_internal_energy
120 procedure :: update_total_energy => system_update_total_energy
121 procedure(system_init_interaction), deferred :: init_interaction
122 procedure(system_initial_conditions), deferred :: initial_conditions
123 procedure(system_do_algorithmic_operation), deferred :: do_algorithmic_operation
124 procedure(system_is_tolerance_reached), deferred :: is_tolerance_reached
125 procedure(system_restart_write_data), deferred :: restart_write_data
126 procedure(system_restart_read_data), deferred :: restart_read_data
127 procedure(system_update_kinetic_energy), deferred :: update_kinetic_energy
128 end type system_t
129
130 abstract interface
131
132 ! ---------------------------------------------------------
134 subroutine system_init_interaction(this, interaction)
135 import system_t
136 import interaction_t
137 class(system_t), target, intent(inout) :: this
138 class(interaction_t), intent(inout) :: interaction
139 end subroutine system_init_interaction
140
141 ! ---------------------------------------------------------
143 subroutine system_initial_conditions(this)
144 import system_t
145 class(system_t), intent(inout) :: this
146 end subroutine system_initial_conditions
147
148 ! ---------------------------------------------------------
155 logical function system_do_algorithmic_operation(this, operation, updated_quantities) result(done)
156 import system_t
158 class(system_t), intent(inout) :: this
159 class(algorithmic_operation_t), intent(in) :: operation
160 integer, allocatable, intent(out) :: updated_quantities(:)
162
163 ! ---------------------------------------------------------
165 logical function system_is_tolerance_reached(this, tol)
166 use, intrinsic :: iso_fortran_env
167 import system_t
168 class(system_t), intent(in) :: this
169 float, intent(in) :: tol
170 end function system_is_tolerance_reached
172 ! ---------------------------------------------------------
174 import system_t
175 class(system_t), intent(inout) :: this
176 end subroutine system_store_current_status
177
178 ! ---------------------------------------------------------
180 import system_t
181 class(system_t), intent(inout) :: this
184 ! ---------------------------------------------------------
185 ! this function returns true if restart data could be read
186 logical function system_restart_read_data(this)
187 import system_t
188 class(system_t), intent(inout) :: this
191 import system_t
192 class(system_t), intent(inout) :: this
195 end interface
202 private
203 contains
204 procedure :: add => system_list_add_node
205 procedure :: contains => system_list_contains
209 private
210 contains
211 procedure :: get_next => system_iterator_get_next
212 end type system_iterator_t
213
214contains
215
216 ! ---------------------------------------------------------
229 subroutine system_execute_algorithm(this)
230 class(system_t), intent(inout) :: this
231
232 type(algorithmic_operation_t) :: operation
233 logical :: all_updated, at_barrier, operation_done
234 type(event_handle_t) :: debug_handle
235 integer :: iq, iuq
236 integer, allocatable :: updated_quantities(:)
237
240 at_barrier = .false.
241
242 do while (.not. at_barrier)
243
244 operation = this%algo%get_current_operation()
245
246 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("dt_operation", operation), &
247 system_iteration=this%iteration, algo_iteration=this%algo%iteration)
248
249 ! First try to execute the operation as a system specific operation
250 operation_done = this%do_algorithmic_operation(operation, updated_quantities)
251 if (allocated(updated_quantities)) then
252 ! Update the quantities iteration counters
253 do iuq = 1, size(updated_quantities)
254 iq = updated_quantities(iuq)
255 call this%quantities(iq)%iteration%set(this%algo%iteration + 1)
256 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("quantity", quantity_label(iq), &
257 this%quantities(iq)%iteration, "set"))
258 end do
259 end if
260
261 ! If not done, we try to execute it as an algorithm-specific operation.
262 if (.not. operation_done) then
263 operation_done = this%algo%do_operation(operation)
264 else
265 call this%algo%next()
266 end if
267
268 ! If still not done, the operation must be a generic operation
269 if (.not. operation_done) then
271 select case (operation%id)
272 case (skip)
273 ! Do nothing
274 call this%algo%next()
275
276 case (iteration_done)
277 ! Increment the system iteration by one
278 this%iteration = this%iteration + 1
279 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("system", "", this%iteration, "tick"))
280
281 ! Recompute the total energy
282 call this%update_total_energy()
283
284 ! Write output
285 call this%output_write()
286
287 ! Update elapsed time
288 call this%algo%update_elapsed_time()
290 ! Print information about the current iteration
291 ! (NB: needs to be done after marking the propagation step as finished,
292 ! so that the timings are correct)
293 call this%iteration_info()
294
295 call this%algo%next()
296
297 case (rewind_algorithm)
298 if (.not. this%arrived_at_any_barrier() .and. .not. this%algorithm_finished()) then
299 ! Reset propagator for next step if not waiting at barrier and if
300 ! the algorithm is not finished
301 call this%algo%rewind()
302 else
303 at_barrier = .true.
304 end if
305
306 case (update_couplings)
307 ! We increment by one algorithmic step
308 this%algo%iteration = this%algo%iteration + 1
309 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("propagator", "", &
310 this%algo%iteration, "tick"))
311
312 ! Try to update all needed quantities from the interaction partners
313 all_updated = this%update_couplings()
314
315 ! Move to next algorithm step if all couplings have been
316 ! updated. Otherwise try again later.
317 if (all_updated) then
318 call this%algo%next()
319 else
320 this%algo%iteration = this%algo%iteration - 1
321 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("propagator", "", &
322 this%algo%iteration, "reverse"))
323 end if
324
325 ! Couplings are implicit barriers
326 at_barrier = .true.
327
329 ! Update all the interactions
330 call this%update_interactions()
331 call this%algo%next()
332
333 case default
334 message(1) = "Unsupported algorithmic operation."
335 write(message(2), '(A,A,A)') trim(operation%id), ": ", trim(operation%label)
336 call messages_fatal(2, namespace=this%namespace)
337 end select
338 end if
339
340 call multisystem_debug_write_event_out(debug_handle, system_iteration=this%iteration, algo_iteration=this%algo%iteration)
341 end do
342
344 end subroutine system_execute_algorithm
345
346 ! ---------------------------------------------------------
347 subroutine system_reset_iteration_counters(this, accumulated_iterations)
348 class(system_t), intent(inout) :: this
349 integer, intent(in) :: accumulated_iterations
350
351 integer :: iq
352 type(interaction_iterator_t) :: iter
353 class(interaction_t), pointer :: interaction
354
355 character(len=MAX_INFO_LEN) :: extended_label
356
358
359 ! Propagator counter
360 this%algo%iteration = this%algo%iteration - accumulated_iterations
361 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("propagator", "", this%algo%iteration, "reset"))
362
363 ! Interaction counters
364 call iter%start(this%interactions)
365 do while (iter%has_next())
366 interaction => iter%get_next()
367 interaction%iteration = interaction%iteration - accumulated_iterations
368
369 extended_label = trim(interaction%label)//"-"//trim(interaction%partner%namespace%get())
370 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t( "interaction", extended_label, &
371 interaction%iteration, "reset"))
372 end do
373
374 ! Internal quantities counters
375 do iq = 1, max_quantities
376 if (this%quantities(iq)%required) then
377 this%quantities(iq)%iteration = this%quantities(iq)%iteration - accumulated_iterations
378 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("quantity", quantity_label(iq), &
379 this%quantities(iq)%iteration, "reset"))
380 end if
381 end do
382
385
386 ! ---------------------------------------------------------
393 subroutine system_init_all_interactions(this)
394 class(system_t), intent(inout) :: this
395
396 type(interaction_iterator_t) :: iter
397 class(interaction_t), pointer :: interaction
398 integer :: timing
399
401
402 !%Variable InteractionTiming
403 !%Type integer
404 !%Default timing_exact
405 !%Section Time-Dependent::Propagation
406 !%Description
407 !% A parameter to determine if interactions should use the quantities
408 !% at the exact iteration or if retardation is allowed.
409 !%Option timing_exact 1
410 !% Only allow interactions at the exact iterations required by the algorithms behing executed
411 !%Option timing_retarded 2
412 !% Allow retarded interactions
413 !%End
414 call parse_variable(this%namespace, 'InteractionTiming', timing_exact, timing)
415 if (.not. varinfo_valid_option('InteractionTiming', timing)) then
416 call messages_input_error(this%namespace, 'InteractionTiming')
417 end if
418 call messages_print_var_option('InteractionTiming', timing, namespace=this%namespace)
419
420 call iter%start(this%interactions)
421 do while (iter%has_next())
422 interaction => iter%get_next()
423 select type (interaction)
424 type is (ghost_interaction_t)
425 ! Skip the ghost interactions
426 class default
427 call this%init_interaction(interaction)
428 call interaction%partner%init_interaction_as_partner(interaction)
429 interaction%timing = timing
430
431 ! Sanity check for interaction timing and algorithm step
432 if (interaction%timing == timing_exact) then
433 select type (partner => interaction%partner)
434 class is (system_t)
435 if (this%algo%iteration%global_step() /= partner%algo%iteration%global_step() .and. &
436 .not. all(partner%quantities(interaction%couplings_from_partner)%always_available)) then
437 write(message(1), '(2a)') "InteractionTiming was set to exact timing, but systems ", &
438 trim(this%namespace%get())
439 write(message(2), '(3a)') "and ", trim(partner%namespace%get()), " have incompatible steps."
440 call messages_fatal(2, namespace=this%namespace)
441 end if
442 end select
443 end if
444 end select
445 end do
446
448 end subroutine system_init_all_interactions
449
450 ! ---------------------------------------------------------
451 logical function system_update_couplings(this) result(all_updated)
452 class(system_t), intent(inout) :: this
453
454 class(interaction_t), pointer :: interaction
455 type(interaction_iterator_t) :: iter
456
458
459 all_updated = .true.
460 call iter%start(this%interactions)
461 do while (iter%has_next())
462 interaction => iter%get_next()
463
464 select type (partner => interaction%partner)
465 class is (system_t)
466 ! If the partner is a system, we can only update its couplings if it
467 ! is not too much behind the requested iteration
468 if (partner%algo%iteration + 1 >= this%algo%iteration) then
469 call interaction%update_partner_couplings(this%algo%iteration)
470 end if
471
472 class default
473 ! Partner that are not systems can have their couplings updated at any iteration
474 call interaction%update_partner_couplings(this%algo%iteration)
475 end select
476
477 all_updated = all_updated .and. interaction%partner_couplings_up_to_date
478 end do
479
481 end function system_update_couplings
482
483 ! ---------------------------------------------------------
484 subroutine system_update_interactions(this)
485 class(system_t), intent(inout) :: this
486
487 integer :: iq, q_id, n_quantities
488 class(interaction_t), pointer :: interaction
489 type(interaction_iterator_t) :: iter
490
492
493 ! Some systems might need to perform some specific operations before the
494 ! update.
495 call this%update_interactions_start()
496
497 !Loop over all interactions
498 call iter%start(this%interactions)
499 do while (iter%has_next())
500 interaction => iter%get_next()
501
502 ! Update the system quantities that will be needed for computing the interaction
503 if (allocated(interaction%system_quantities)) then
504 n_quantities = size(interaction%system_quantities)
505 else
506 n_quantities = 0
507 end if
508 do iq = 1, n_quantities
509 ! Get requested quantity ID
510 q_id = interaction%system_quantities(iq)
511
512 if (.not. this%quantities(q_id)%iteration == this%algo%iteration) then
513 ! The requested quantity is not at the requested iteration, so we try to update it
514
515 if (.not. this%quantities(q_id)%updated_on_demand) then
516 ! Quantity must be at the correct iteration, otherwise the algorithm and
517 ! the interaction are incompatible
518 if (.not. this%quantities(q_id)%iteration == this%algo%iteration .and. &
519 .not. this%quantities(q_id)%always_available) then
520 write(message(1), '(5a)') "Interaction ", trim(interaction%label), " is incompatible with the selected algorithm."
521 write(message(2), '(3a)') "The interaction requires the ", trim(quantity_label(q_id)), &
522 " at a iteration it is not available."
523 call messages_fatal(2, namespace=this%namespace)
524 end if
525
526 ! We do not need to update quantities that are not updated on
527 ! demand, as the algorithm takes care of doing that, so move on to
528 ! next quantity
529 cycle
530 end if
531
532 ! Sanity check: it should never happen that the quantity is in advance
533 ! with respect to the requested iteration.
534 if (this%quantities(q_id)%iteration > this%algo%iteration) then
535 message(1) = "The quantity iteration is in advance compared to the requested iteration."
536 call messages_fatal(1, namespace=this%namespace)
537 end if
538
539 call this%update_quantity(q_id)
540 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("quantity", quantity_label(q_id), &
541 this%quantities(q_id)%iteration, "set"))
542 end if
543
544 end do
545
546 call interaction%update(this%algo%iteration)
547 end do
548
549 ! Some systems might need to perform some specific operations after all the
550 ! interactions have been updated
551 call this%update_interactions_finish()
552
554 end subroutine system_update_interactions
555
556 ! ---------------------------------------------------------
557 subroutine system_update_interactions_start(this)
558 class(system_t), intent(inout) :: this
559
561
562 ! By default nothing is done just before updating the interactions. Child
563 ! classes that wish to change this behaviour should override this method.
564
567
568 ! ---------------------------------------------------------
569 subroutine system_update_interactions_finish(this)
570 class(system_t), intent(inout) :: this
571
573
574 ! By default nothing is done just after updating the interactions. Child
575 ! classes that wish to change this behaviour should override this method.
576
579
580 ! ---------------------------------------------------------
581 subroutine system_restart_write(this)
582 class(system_t), intent(inout) :: this
583
584 logical :: restart_write
585 type(interaction_iterator_t) :: iter
586 class(interaction_t), pointer :: interaction
587 integer :: ii
588
589 push_sub(system_restart_write)
590
591 call parse_variable(this%namespace, 'RestartWrite', .true., restart_write)
592
593 if (restart_write) then
594 ! do some generic restart steps here
595 ! write iteration counter restart data
596 call this%iteration%restart_write('restart_iteration_system', this%namespace)
597 call this%algo%iteration%restart_write('restart_iteration_propagator', this%namespace)
598 call iter%start(this%interactions)
599 do while (iter%has_next())
600 interaction => iter%get_next()
601 call interaction%restart_write(this%namespace)
602 end do
603 do ii = 1, max_quantities
604 if (this%quantities(ii)%required) then
605 call this%quantities(ii)%iteration%restart_write('restart_iteration_quantity_'//trim(quantity_label(ii)), &
606 this%namespace)
607 end if
608 end do
609 ! the following call is delegated to the corresponding system
610 call this%restart_write_data()
611 message(1) = "Wrote restart data for system "//trim(this%namespace%get())
612 call messages_info(1, namespace=this%namespace)
613 end if
614
615 pop_sub(system_restart_write)
616 end subroutine system_restart_write
617
618 ! ---------------------------------------------------------
619 ! this function returns true if restart data could be read
620 logical function system_restart_read(this)
621 class(system_t), intent(inout) :: this
622
623 type(interaction_iterator_t) :: iter
624 class(interaction_t), pointer :: interaction
625 integer :: ii
626
627 push_sub(system_restart_read)
628
629 ! do some generic restart steps here
630 ! read iteration data
631 system_restart_read = this%iteration%restart_read('restart_iteration_system', this%namespace)
633 this%algo%iteration%restart_read('restart_iteration_propagator', this%namespace)
634 call iter%start(this%interactions)
635 do while (iter%has_next())
636 interaction => iter%get_next()
637 system_restart_read = system_restart_read .and. interaction%restart_read(this%namespace)
638 ! reduce by one because of the first UPDATE_INTERACTIONS
639 interaction%iteration = interaction%iteration - 1
640 end do
641 do ii = 1, max_quantities
642 if (this%quantities(ii)%required) then
644 this%quantities(ii)%iteration%restart_read('restart_iteration_quantity_'//trim(quantity_label(ii)), &
645 this%namespace)
646 end if
647 if (this%quantities(ii)%updated_on_demand) then
648 ! decrease iteration by one for on-demand quantities to account for initial update_interactions step
649 this%quantities(ii)%iteration = this%quantities(ii)%iteration - 1
650 end if
651 end do
652 ! the following call is delegated to the corresponding system
653 system_restart_read = system_restart_read .and. this%restart_read_data()
654
655 if (system_restart_read) then
656 message(1) = "Successfully read restart data for system "//trim(this%namespace%get())
657 call messages_info(1, namespace=this%namespace)
658 end if
659
660 pop_sub(system_restart_read)
661 end function system_restart_read
662
663 ! ---------------------------------------------------------
664 subroutine system_output_start(this)
665 class(system_t), intent(inout) :: this
666
667 push_sub(system_output_start)
668
669 ! By default nothing is done to regarding output. Child classes that wish
670 ! to change this behaviour should override this method.
671
672 pop_sub(system_output_start)
673 end subroutine system_output_start
674
675 ! ---------------------------------------------------------
676 subroutine system_output_write(this)
677 class(system_t), intent(inout) :: this
678
679 push_sub(system_output_write)
680
681 ! By default nothing is done to regarding output. Child classes that wish
682 ! to change this behaviour should override this method.
683
684 pop_sub(system_output_write)
685 end subroutine system_output_write
686
687 ! ---------------------------------------------------------
688 subroutine system_output_finish(this)
689 class(system_t), intent(inout) :: this
690
691 push_sub(system_output_finish)
692
693 ! By default nothing is done to regarding output. Child classes that wish
694 ! to change this behaviour should override this method.
695
696 pop_sub(system_output_finish)
697 end subroutine system_output_finish
698
699 ! ---------------------------------------------------------
700 subroutine system_init_algorithm(this, factory)
701 class(system_t), intent(inout) :: this
702 class(algorithm_factory_t), intent(in) :: factory
703
704 integer :: ii
705
706 push_sub(system_init_algorithm)
707
708 call messages_experimental('Multi-system framework')
709
710 this%algo => factory%create(this)
711
712 call this%init_iteration_counters()
713
714 do ii = 1, number_barriers
715 this%barrier(ii)%active = .false.
716 this%barrier(ii)%target_time = m_zero
717 end do
718
719 pop_sub(system_init_algorithm)
720 end subroutine system_init_algorithm
721
722 ! ---------------------------------------------------------------------------------------
723 recursive function system_algorithm_finished(this) result(finished)
724 class(system_t), intent(in) :: this
725 logical :: finished
726
727 finished = this%algo%finished()
728
729 end function system_algorithm_finished
730
731 ! ---------------------------------------------------------
732 subroutine system_init_iteration_counters(this)
733 class(system_t), intent(inout) :: this
734
735 type(interaction_iterator_t) :: iter
736 class(interaction_t), pointer :: interaction
737
739
740 ! Initialize algorithm and system counters
741 call this%algo%init_iteration_counters()
742
743 ! Interactions counters
744 call iter%start(this%interactions)
745 do while (iter%has_next())
746 interaction => iter%get_next()
747 interaction%iteration = this%algo%iteration - 1
748 end do
749
750 ! Required quantities counters
751 where (this%quantities%required)
752 this%quantities%iteration = this%algo%iteration
753 end where
754 where (this%quantities%updated_on_demand)
755 this%quantities%iteration = this%algo%iteration - 1
756 end where
757
759 end subroutine system_init_iteration_counters
761 ! ---------------------------------------------------------
762 subroutine system_propagation_start(this)
763 class(system_t), intent(inout) :: this
764
765 logical :: all_updated
766 type(event_handle_t) :: debug_handle
767 integer, allocatable :: updated_quantities(:)
768
770
771 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_propagation_start"), &
772 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
773
774 ! Update interactions at initial iteration
775 all_updated = this%update_couplings()
776 if (.not. all_updated) then
777 message(1) = "Unable to update interactions when initializing the propagation."
778 call messages_fatal(1, namespace=this%namespace)
779 end if
780 call this%update_interactions()
781
782 ! System-specific and propagator-specific initialization step
783 if (this%algo%start_operation%id /= skip) then
784 if (.not. this%do_algorithmic_operation(this%algo%start_operation, updated_quantities)) then
785 message(1) = "Unsupported algorithmic operation."
786 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
787 call messages_fatal(2, namespace=this%namespace)
788 else if (allocated(updated_quantities)) then
789 message(1) = "Update of quantities not allowed in algorithmic operation."
790 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
791 call messages_fatal(2, namespace=this%namespace)
792 end if
793 end if
794
795 ! Compute the total energy at the beginning of the simulation
796 call this%update_total_energy()
797
798 ! Start output
799 call this%output_start()
800
801 ! Write header for propagation log
802 call messages_print_with_emphasis(msg="Multi-system propagation", namespace=this%namespace)
803 write(message(1), '(a6,1x,a14,1x,a13,1x,a10,1x,a15)') 'Iter', 'Time', 'Energy', 'SC Steps', 'Elapsed Time'
804 call messages_info(1, namespace=this%namespace)
805 call messages_print_with_emphasis(namespace=this%namespace)
806
807 ! Rewind propagator (will also set the initial time to compute the elapsed time)
808 call this%algo%rewind()
809
810 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
811
813 end subroutine system_propagation_start
814
815 ! ---------------------------------------------------------
817 class(system_t), intent(inout) :: this
818 type(event_handle_t) :: debug_handle
819
820 integer, allocatable :: updated_quantities(:)
821
823
824 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_propagation_finish"), &
825 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
826
827 ! Finish output
828 call this%output_finish()
829
830 ! System-specific and propagator-specific finalization step
831 if (this%algo%final_operation%id /= skip) then
832 if (.not. this%do_algorithmic_operation(this%algo%final_operation, updated_quantities)) then
833 message(1) = "Unsupported algorithmic operation."
834 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
835 call messages_fatal(2, namespace=this%namespace)
836 else if (allocated(updated_quantities)) then
837 message(1) = "Update of quantities not allowed in algorithmic operation."
838 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
839 call messages_fatal(2, namespace=this%namespace)
840 end if
841 end if
842
843 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
844
847
848 ! ---------------------------------------------------------
849 subroutine system_iteration_info(this)
850 class(system_t), intent(in) :: this
851
852 float :: energy
853 character(len=40) :: fmt
854
855 push_sub(system_iteration_info)
856
857 energy = units_from_atomic(units_out%energy, this%total_energy)
858 if (abs(energy) >= 1e5) then
859 fmt = '(i7,1x,f14.6,1X,es13.6,1X,i9,1X,'
860 else
861 fmt = '(i7,1x,f14.6,1X,f13.6,1X,i9,1X,'
862 end if
863 if (this%algo%elapsed_time < 1e-3) then
864 fmt = trim(fmt)//'es13.3)'
865 else
866 fmt = trim(fmt)//'f13.3)'
867 end if
868
869 write(message(1), fmt) this%iteration%counter(), &
870 units_from_atomic(units_out%time, this%iteration%value()), energy, &
871 0, this%algo%elapsed_time
872 call messages_info(1, namespace=this%namespace)
873
874 pop_sub(system_iteration_info)
875 end subroutine system_iteration_info
876
877 ! ---------------------------------------------------------
878 logical function system_process_is_slave(this)
879 class(system_t), intent(in) :: this
880
882
883 ! By default an MPI process is not a slave
885
887 end function system_process_is_slave
888
889 ! ---------------------------------------------------------
890 subroutine system_end(this)
891 class(system_t), intent(inout) :: this
892
893 type(interaction_iterator_t) :: iter
894 class(interaction_t), pointer :: interaction
895
896 push_sub(system_end)
897
898 ! No call to safe_deallocate macro here, as it gives an ICE with gfortran
899 if (associated(this%algo)) then
900 deallocate(this%algo)
901 end if
902
903 call iter%start(this%interactions)
904 do while (iter%has_next())
905 interaction => iter%get_next()
906 if (associated(interaction)) then
907 deallocate(interaction)
908 end if
909 end do
910
911 pop_sub(system_end)
912 end subroutine system_end
913
914 ! ---------------------------------------------------------
915 subroutine system_list_add_node(this, partner)
916 class(system_list_t) :: this
917 class(interaction_partner_t), target :: partner
918
919 push_sub(system_list_add_node)
920
921 select type (partner)
922 class is (system_t)
923 call this%add_ptr(partner)
924 class default
925 assert(.false.)
926 end select
927
928 pop_sub(system_list_add_node)
929 end subroutine system_list_add_node
930
931 ! ---------------------------------------------------------
932 recursive logical function system_list_contains(this, partner) result(contains)
933 class(system_list_t) :: this
934 class(interaction_partner_t), target :: partner
935
936 type(partner_iterator_t) :: iterator
937 class(interaction_partner_t), pointer :: system
938
939 push_sub(system_list_contains)
940
941 contains = .false.
942
943 select type (partner)
944 class is (system_t)
945
946 call iterator%start(this)
947 do while (iterator%has_next() .and. .not. contains)
948 system => iterator%get_next()
949 contains = associated(system, partner)
950 end do
951
952 class default
953 contains = .false.
954 end select
955
956 pop_sub(system_list_contains)
957 end function system_list_contains
958
959 ! ---------------------------------------------------------
960 function system_iterator_get_next(this) result(system)
961 class(system_iterator_t), intent(inout) :: this
962 class(system_t), pointer :: system
963
965
966 select type (ptr => this%get_next_ptr())
967 class is (system_t)
968 system => ptr
969 class default
970 assert(.false.)
971 end select
972
975
976 ! ---------------------------------------------------------
980 subroutine system_init_parallelization(this, grp)
981 class(system_t), intent(inout) :: this
982 type(mpi_grp_t), intent(in) :: grp
983
985
986 call mpi_grp_copy(this%grp, grp)
987 call messages_update_mpi_grp(this%namespace, grp)
988
990 end subroutine system_init_parallelization
991
992
993
994 ! ---------------------------------------------------------
995 subroutine system_start_barrier(this, target_time, barrier_index)
996 class(system_t), intent(inout) :: this
997 float, intent(in) :: target_time
998 integer, intent(in) :: barrier_index
1000 push_sub(system_start_barrier)
1001
1002 this%barrier(barrier_index)%active = .true.
1003 this%barrier(barrier_index)%target_time = target_time
1004
1005 pop_sub(system_start_barrier)
1006 end subroutine system_start_barrier
1007
1008 ! ---------------------------------------------------------
1009 subroutine system_end_barrier(this, barrier_index)
1010 class(system_t), intent(inout) :: this
1011 integer, intent(in) :: barrier_index
1012
1013 push_sub(system_end_barrier)
1014
1015 this%barrier(barrier_index)%active = .false.
1016 this%barrier(barrier_index)%target_time = m_zero
1017
1018 pop_sub(system_end_barrier)
1019 end subroutine system_end_barrier
1020
1021 ! ---------------------------------------------------------
1022 logical function system_arrived_at_barrier(this, barrier_index)
1023 class(system_t), intent(inout) :: this
1024 integer, intent(in) :: barrier_index
1025
1026 type(iteration_counter_t) :: iteration
1027
1029
1031 if (this%barrier(barrier_index)%active) then
1032 iteration = this%iteration + 1
1033 if (iteration%value() > this%barrier(barrier_index)%target_time) then
1035 end if
1036 end if
1037
1039 end function system_arrived_at_barrier
1040
1041 ! ---------------------------------------------------------
1042 logical function system_arrived_at_any_barrier(this)
1043 class(system_t), intent(inout) :: this
1045 integer :: ii
1046
1048
1050 do ii = 1, number_barriers
1052 .or. this%arrived_at_barrier(ii)
1053 end do
1054
1057
1058
1059 ! ---------------------------------------------------------
1065 class(system_t), intent(inout) :: this
1066
1067 type(interaction_iterator_t) :: iter
1068 class(interaction_t), pointer :: interaction
1069
1071
1072 this%potential_energy = m_zero
1073
1074 call iter%start(this%interactions)
1075 do while (iter%has_next())
1076 interaction => iter%get_next()
1077 if(.not. interaction%intra_interaction) then
1078 call interaction%calculate_energy()
1079 this%potential_energy = this%potential_energy + interaction%energy
1080 end if
1081 end do
1082
1084 end subroutine system_update_potential_energy
1085
1086 ! ---------------------------------------------------------
1091 subroutine system_update_internal_energy(this)
1092 class(system_t), intent(inout) :: this
1094 type(interaction_iterator_t) :: iter
1095 class(interaction_t), pointer :: interaction
1096
1098
1099 this%internal_energy = m_zero
1100 call iter%start(this%interactions)
1101 do while (iter%has_next())
1102 interaction => iter%get_next()
1103 if(interaction%intra_interaction) then
1104 call interaction%calculate_energy()
1105 this%internal_energy = this%internal_energy + interaction%energy
1106 end if
1107 end do
1108
1110 end subroutine system_update_internal_energy
1111
1112 ! ---------------------------------------------------------
1116 subroutine system_update_total_energy(this)
1117 class(system_t), intent(inout) :: this
1118
1120
1121 call this%update_kinetic_energy()
1122 this%total_energy = this%kinetic_energy
1123
1125 call this%update_potential_energy()
1126 this%total_energy = this%total_energy + this%potential_energy
1127
1129 call this%update_internal_energy()
1130 this%total_energy = this%total_energy + this%internal_energy
1131
1133 end subroutine system_update_total_energy
1134
1135end module system_oct_m
1136
1137!! Local Variables:
1138!! mode: f90
1139!! coding: utf-8
1140!! End:
Execute one operation that is part of a larger algorithm. Returns true if the operation was successfu...
Definition: system.F90:239
initialize a given interaction of the system
Definition: system.F90:218
set initial conditions for a system
Definition: system.F90:227
check whether a system has reached a given tolerance
Definition: system.F90:249
This module defines the abstract interfact for algorithm factories.
This module implements the basic elements defining algorithms.
Definition: algorithm.F90:132
character(len=algo_label_len), parameter, public update_interactions
Definition: algorithm.F90:163
character(len=algo_label_len), parameter, public rewind_algorithm
Definition: algorithm.F90:163
character(len=algo_label_len), parameter, public update_couplings
Definition: algorithm.F90:163
character(len=algo_label_len), parameter, public iteration_done
Definition: algorithm.F90:163
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:163
real(8), parameter, public m_zero
Definition: global.F90:167
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 implements fully polymorphic linked lists, and some specializations thereof.
Definition: linked_list.F90:96
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:910
character(len=512), private msg
Definition: messages.F90:156
subroutine, public messages_update_mpi_grp(namespace, mpigrp)
Definition: messages.F90:362
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:603
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:151
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:400
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:702
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1077
subroutine mpi_grp_copy(mpi_grp_out, mpi_grp_in)
Definition: mpi.F90:396
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:107
character(len=17), dimension(max_quantities), parameter, public quantity_label
Definition: quantity.F90:134
integer, parameter, public max_quantities
Definition: quantity.F90:116
This module implements the abstract system type.
Definition: system.F90:109
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:1201
subroutine system_iteration_info(this)
Definition: system.F90:934
subroutine, public system_init_iteration_counters(this)
Definition: system.F90:817
integer, parameter, public barrier_restart
Definition: system.F90:154
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:1176
logical function system_arrived_at_any_barrier(this)
Definition: system.F90:1127
recursive logical function system_list_contains(this, partner)
Definition: system.F90:1017
subroutine system_init_all_interactions(this)
initialize all interactions of this system
Definition: system.F90:478
subroutine, public system_restart_write(this)
Definition: system.F90:666
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:1149
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:1065
subroutine system_output_start(this)
Definition: system.F90:749
subroutine system_update_interactions_start(this)
Definition: system.F90:642
subroutine system_start_barrier(this, target_time, barrier_index)
Definition: system.F90:1080
subroutine, public system_propagation_finish(this)
Definition: system.F90:901
subroutine, public system_end(this)
Definition: system.F90:975
subroutine system_output_write(this)
Definition: system.F90:761
subroutine system_update_interactions_finish(this)
Definition: system.F90:654
subroutine, public system_execute_algorithm(this)
perform one or more algorithmic operations
Definition: system.F90:314
subroutine system_update_interactions(this)
Definition: system.F90:569
class(system_t) function, pointer system_iterator_get_next(this)
Definition: system.F90:1045
logical function system_update_couplings(this)
Definition: system.F90:536
logical function system_process_is_slave(this)
Definition: system.F90:963
logical function system_arrived_at_barrier(this, barrier_index)
Definition: system.F90:1107
recursive logical function system_algorithm_finished(this)
Definition: system.F90:808
logical function, public system_restart_read(this)
Definition: system.F90:705
subroutine system_output_finish(this)
Definition: system.F90:773
subroutine system_list_add_node(this, partner)
Definition: system.F90:1000
subroutine, public system_propagation_start(this)
Definition: system.F90:847
subroutine, public system_reset_iteration_counters(this, accumulated_iterations)
Definition: system.F90:432
subroutine, public system_init_algorithm(this, factory)
Definition: system.F90:785
subroutine system_end_barrier(this, barrier_index)
Definition: system.F90:1094
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:123
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:154
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
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:132
handle to keep track of in- out- events
These classes extends the list and list iterator to create a system list.
Definition: system.F90:285
Abstract class for systems.
Definition: system.F90:161
int true(void)