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 :: init_algorithm => system_init_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 :: propagation_start => system_propagation_start
108 procedure :: propagation_finish => system_propagation_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_initial_conditions), deferred :: initial_conditions
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 ! ---------------------------------------------------------
136 subroutine system_init_interaction(this, interaction)
137 import system_t
138 import interaction_t
139 class(system_t), target, intent(inout) :: this
140 class(interaction_t), intent(inout) :: interaction
141 end subroutine system_init_interaction
142
143 ! ---------------------------------------------------------
145 subroutine system_initial_conditions(this)
146 import system_t
147 class(system_t), intent(inout) :: this
148 end subroutine system_initial_conditions
149
150 ! ---------------------------------------------------------
160 logical function system_do_algorithmic_operation(this, operation, updated_quantities) result(done)
161 import system_t
163 class(system_t), intent(inout) :: this
164 class(algorithmic_operation_t), intent(in) :: operation
165 integer, allocatable, intent(out) :: updated_quantities(:)
167
168 ! ---------------------------------------------------------
170 logical function system_is_tolerance_reached(this, tol)
171 use, intrinsic :: iso_fortran_env
172 import system_t
173 class(system_t), intent(in) :: this
174 real(real64), intent(in) :: tol
176
177 ! ---------------------------------------------------------
181 subroutine system_store_current_status(this)
182 import system_t
183 class(system_t), intent(inout) :: this
186 ! ---------------------------------------------------------
187 subroutine system_restart_write_data(this)
188 import system_t
189 class(system_t), intent(inout) :: this
192 ! ---------------------------------------------------------
193 ! this function returns true if restart data could be read
194 logical function system_restart_read_data(this)
195 import system_t
196 class(system_t), intent(inout) :: this
199 import system_t
200 class(system_t), intent(inout) :: this
203 end interface
210 private
211 contains
212 procedure :: add => system_list_add_node
213 procedure :: contains => system_list_contains
217 private
218 contains
219 procedure :: get_next => system_iterator_get_next
222contains
223
224 ! ---------------------------------------------------------
237 subroutine system_execute_algorithm(this)
238 class(system_t), intent(inout) :: this
239
240 type(algorithmic_operation_t) :: operation
241 logical :: all_updated, at_barrier, operation_done
242 type(event_handle_t) :: debug_handle
243 integer :: iq, iuq
244 integer, allocatable :: updated_quantities(:)
245
247
248 at_barrier = .false.
249
250 do while (.not. at_barrier)
251
252 operation = this%algo%get_current_operation()
254 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("dt_operation", operation), &
255 system_iteration=this%iteration, algo_iteration=this%algo%iteration)
256
257 ! First try to execute the operation as a system specific operation
258 operation_done = this%do_algorithmic_operation(operation, updated_quantities)
259 if (allocated(updated_quantities)) then
260 ! Update the quantities iteration counters
261 do iuq = 1, size(updated_quantities)
262 iq = updated_quantities(iuq)
263 call this%quantities(iq)%iteration%set(this%algo%iteration + 1)
264 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("quantity", quantity_label(iq), &
265 this%quantities(iq)%iteration, "set"))
266 end do
267 end if
268
269 ! If not done, we try to execute it as an algorithm-specific operation.
270 if (.not. operation_done) then
271 operation_done = this%algo%do_operation(operation)
272 else
273 call this%algo%next()
274 end if
275
276 ! If still not done, the operation must be a generic operation
277 if (.not. operation_done) then
278
279 select case (operation%id)
280 case (skip)
281 ! Do nothing
282 call this%algo%next()
283
284 case (iteration_done)
285 ! Increment the system iteration by one
286 this%iteration = this%iteration + 1
287 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("system", "", this%iteration, "tick"))
288
289 ! Recompute the total energy
290 call this%update_total_energy()
292 ! Write output
293 call this%output_write()
294
295 ! Update elapsed time
296 call this%algo%update_elapsed_time()
297
298 ! Print information about the current iteration
299 ! (NB: needs to be done after marking the propagation step as finished,
300 ! so that the timings are correct)
301 call this%iteration_info()
303 call this%algo%next()
304
306 if (.not. this%arrived_at_any_barrier() .and. .not. this%algorithm_finished()) then
307 ! Reset propagator for next step if not waiting at barrier and if
308 ! the algorithm is not finished
309 call this%algo%rewind()
310 else
311 at_barrier = .true.
312 end if
313
314 case (update_couplings)
315 ! We increment by one algorithmic step
316 this%algo%iteration = this%algo%iteration + 1
317 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("propagator", "", &
318 this%algo%iteration, "tick"))
319
320 ! Try to update all needed quantities from the interaction partners
321 all_updated = this%update_couplings()
322
323 ! Move to next algorithm step if all couplings have been
324 ! updated. Otherwise roll back the iteration counter and try again later.
325 if (all_updated) then
326 call this%algo%next()
327 else
328 this%algo%iteration = this%algo%iteration - 1
329 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("propagator", "", &
330 this%algo%iteration, "reverse"))
331 end if
332
333 ! Couplings are implicit barriers
334 at_barrier = .true.
335
337 ! Update all the interactions
338 call this%update_interactions()
339 call this%algo%next()
340
341 case default
342 message(1) = "Unsupported algorithmic operation."
343 write(message(2), '(A,A,A)') trim(operation%id), ": ", trim(operation%label)
344 call messages_fatal(2, namespace=this%namespace)
345 end select
346 end if
347
348 call multisystem_debug_write_event_out(debug_handle, system_iteration=this%iteration, algo_iteration=this%algo%iteration)
349 end do
350
352 end subroutine system_execute_algorithm
353
354 ! ---------------------------------------------------------
355 subroutine system_reset_iteration_counters(this, accumulated_iterations)
356 class(system_t), intent(inout) :: this
357 integer, intent(in) :: accumulated_iterations
358
359 integer :: iq
360 type(interaction_iterator_t) :: iter
361 class(interaction_t), pointer :: interaction
362
363 character(len=MAX_INFO_LEN) :: extended_label
364
366
367 ! Propagator counter
368 this%algo%iteration = this%algo%iteration - accumulated_iterations
369 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("propagator", "", this%algo%iteration, "reset"))
370
371 ! Interaction counters
372 call iter%start(this%interactions)
373 do while (iter%has_next())
374 interaction => iter%get_next()
375 interaction%iteration = interaction%iteration - accumulated_iterations
376
377 extended_label = trim(interaction%label)//"-"//trim(interaction%partner%namespace%get())
378 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t( "interaction", extended_label, &
379 interaction%iteration, "reset"))
380 end do
381
382 ! Internal quantities counters
383 do iq = 1, max_quantities
384 if (this%quantities(iq)%required) then
385 this%quantities(iq)%iteration = this%quantities(iq)%iteration - accumulated_iterations
386 call multisystem_debug_write_marker(this%namespace, event_iteration_update_t("quantity", quantity_label(iq), &
387 this%quantities(iq)%iteration, "reset"))
388 end if
389 end do
390
393
394
395 ! ---------------------------------------------------------
408 recursive subroutine system_create_interactions(this, interaction_factory, available_partners)
409 class(system_t), intent(inout) :: this
410 class(interactions_factory_abst_t), intent(in) :: interaction_factory
411 class(partner_list_t), target, intent(in) :: available_partners
412
413 logical :: in_list
414 integer :: i, ip, interaction_type
415 type(partner_list_t) :: partners
416 type(partner_iterator_t) :: iter
417 class(interaction_partner_t), pointer :: partner
418 class(interaction_t), pointer :: interaction
419 type(interactions_factory_options_t), allocatable :: options(:)
420
422
423 ! Sanity checks
424 assert(allocated(this%supported_interactions))
425 assert(allocated(this%supported_interactions_as_partner))
426
427
428 ! All systems need to be connected to make sure they remain synchronized.
429 ! We enforce that be adding a ghost interaction between all systems.
430 ! Note that this recursively adds subsystems of containers.
431 call iter%start(available_partners)
432 do while (iter%has_next())
433 partner => iter%get_next()
434 call partner%add_partners_to_list(partners)
435 end do
436
437 call iter%start(partners)
438 do while (iter%has_next())
439 partner => iter%get_next()
440
441 ! No self-interaction
442 if (partner%namespace%get() == this%namespace%get()) cycle
443
444 call this%interactions%add(ghost_interaction_t(partner))
445 end do
446
447
448 ! Now create the non-ghost interactions:
449 ! Here we only add systems to the parters list, which support the given interaction as a partner
450 ! Note that ensemble containers do not add their subsystems to the list.
451 ! (see ensemble_oct_m::ensemble_add_parters_to_list())
452
453 call partners%empty()
454
455 ! Get options to use to create all the interactions supported by this system
456 allocate(options(0)) ! Workaround to avoid a gfortran warning
457 options = interaction_factory%options(this%namespace, this%supported_interactions)
458
459 ! Loop over all interactions supported by this system and create them according to the provided options
460 do i = 1, size(this%supported_interactions)
461 interaction_type = this%supported_interactions(i)
462
463 ! Supported interactions should only appear once in the corresponding
464 ! list, otherwise more than one interaction of the same type will be
465 ! created
466 assert(count(this%supported_interactions == interaction_type) == 1)
467
468 ! Get the list of partners that support this interaction type
469 call iter%start(available_partners)
470 do while (iter%has_next())
471 partner => iter%get_next()
472 call partner%add_partners_to_list(partners, interaction_type)
473 end do
474
475 ! Create list of partners for this interaction taking into account the selected mode
476 select case (options(i)%mode)
477 case (all_partners)
478 ! Use all available partners, so no need to modify the list
479
480 case (no_partners)
481 ! No partners for this interaction, so empty the list
482 call partners%empty()
483
484 case (only_partners)
485 ! Start with full list and remove the partners not listed in the options
486 call iter%start(partners)
487 do while (iter%has_next())
488 partner => iter%get_next()
489 in_list = .false.
490 do ip = 1, size(options(i)%partners)
491 if (partner%namespace%is_contained_in(options(i)%partners(ip))) then
492 in_list = .true.
493 exit
494 end if
495 end do
496 if (.not. in_list) then
497 call partners%delete(partner)
498 end if
499 end do
500
502 ! Start with full list and remove the partners listed in the options
503 do ip = 1, size(options(i)%partners)
504 call iter%start(partners)
505 do while (iter%has_next())
506 partner => iter%get_next()
507 if (partner%namespace%is_contained_in(options(i)%partners(ip))) then
508 call partners%delete(partner)
509 end if
510 end do
511 end do
512
513 end select
514
515 ! Now actually create the interactions for the selected partners
516 call iter%start(partners)
517 do while (iter%has_next())
518 partner => iter%get_next()
519
520 interaction => interaction_factory%create(interaction_type, partner)
521
522
523 ! Set flag for self-interaction
524 interaction%intra_interaction = partner%namespace%get() == this%namespace%get()
525
526 ! Set timing and perform sanity checks
527 interaction%timing = options(i)%timing
528 if (interaction%timing == timing_exact) then
529 select type (partner => interaction%partner)
530 class is (system_t)
531 if (this%algo%iteration%global_step() /= partner%algo%iteration%global_step() .and. &
532 .not. all(partner%quantities(interaction%couplings_from_partner)%always_available)) then
533 write(message(1), '(2a)') "InteractionTiming was set to exact timing, but systems ", &
534 trim(this%namespace%get())
535 write(message(2), '(3a)') "and ", trim(partner%namespace%get()), " have incompatible steps."
536 call messages_fatal(2, namespace=this%namespace)
537 end if
538 end select
539 end if
540
541 ! Initialize interaction from system and from partner
542 call this%init_interaction(interaction)
543 call interaction%partner%init_interaction_as_partner(interaction)
544
545 !Mark all the quantities needed by the interaction from the system and the partner as required
546 if (allocated(interaction%system_quantities)) then
547 this%quantities(interaction%system_quantities)%required = .true.
548 end if
549 if (allocated(interaction%couplings_from_partner)) then
550 partner%quantities(interaction%couplings_from_partner)%required = .true.
551 end if
552
553 ! Add interaction to list
554 call this%interactions%add(interaction)
555 end do
556
557 ! Empty partner list for next interaction
558 call partners%empty()
559 end do
560
562 end subroutine system_create_interactions
563
564 ! ---------------------------------------------------------
570 logical function system_update_couplings(this) result(all_updated)
571 class(system_t), intent(inout) :: this
572
573 class(interaction_t), pointer :: interaction
574 type(interaction_iterator_t) :: iter
575
577
578 all_updated = .true.
579 call iter%start(this%interactions)
580 do while (iter%has_next())
581 interaction => iter%get_next()
582
583 select type (partner => interaction%partner)
584 class is (system_t)
585 ! If the partner is a system, we can only update its couplings if it
586 ! is not too much behind the requested iteration
587 if (partner%algo%iteration + 1 >= this%algo%iteration) then
588 call interaction%update_partner_couplings(this%algo%iteration)
589 end if
590
591 class default
592 ! Partner that are not systems can have their couplings updated at any iteration
593 call interaction%update_partner_couplings(this%algo%iteration)
594 end select
595
596 all_updated = all_updated .and. interaction%partner_couplings_up_to_date
597 end do
598
600 end function system_update_couplings
601
602 ! ---------------------------------------------------------
607 subroutine system_update_interactions(this)
608 class(system_t), intent(inout) :: this
609
610 integer :: iq, q_id, n_quantities
611 class(interaction_t), pointer :: interaction
612 type(interaction_iterator_t) :: iter
613
615
616 ! Some systems might need to perform some specific operations before the
617 ! update.
618 call this%update_interactions_start()
619
620 !Loop over all interactions
621 call iter%start(this%interactions)
622 do while (iter%has_next())
623 interaction => iter%get_next()
624
625 ! Update the system quantities that will be needed for computing the interaction
626 if (allocated(interaction%system_quantities)) then
627 n_quantities = size(interaction%system_quantities)
628 else
629 n_quantities = 0
630 end if
631 do iq = 1, n_quantities
632 ! Get requested quantity ID
633 q_id = interaction%system_quantities(iq)
634
635 if (.not. this%quantities(q_id)%iteration == this%algo%iteration) then
636 ! The requested quantity is not at the requested iteration, so we try to update it
637
638 if (.not. this%quantities(q_id)%updated_on_demand) then
639 ! Quantity must be at the correct iteration, otherwise the algorithm and
640 ! the interaction are incompatible
641 if (.not. this%quantities(q_id)%iteration == this%algo%iteration .and. &
642 .not. this%quantities(q_id)%always_available) then
643 write(message(1), '(5a)') "Interaction ", trim(interaction%label), " is incompatible with the selected algorithm."
644 write(message(2), '(3a)') "The interaction requires the ", trim(quantity_label(q_id)), &
645 " at a iteration it is not available."
646 call messages_fatal(2, namespace=this%namespace)
647 end if
648
649 ! We do not need to update quantities that are not updated on
650 ! demand, as the algorithm takes care of doing that, so move on to
651 ! next quantity
652 cycle
653 end if
654
655 ! Sanity check: it should never happen that the quantity is in advance
656 ! with respect to the requested iteration.
657 if (this%quantities(q_id)%iteration > this%algo%iteration) then
658 message(1) = "The quantity iteration is in advance compared to the requested iteration."
659 call messages_fatal(1, namespace=this%namespace)
660 end if
661
662 call this%update_quantity(q_id)
664 this%quantities(q_id)%iteration, "set"))
665 end if
666
667 end do
668
669 call interaction%update(this%algo%iteration)
670 end do
671
672 ! Some systems might need to perform some specific operations after all the
673 ! interactions have been updated
674 call this%update_interactions_finish()
675
677 end subroutine system_update_interactions
678
679 ! ---------------------------------------------------------
680 subroutine system_update_interactions_start(this)
681 class(system_t), intent(inout) :: this
682
684
685 ! By default nothing is done just before updating the interactions. Child
686 ! classes that wish to change this behaviour should override this method.
687
690
691 ! ---------------------------------------------------------
692 subroutine system_update_interactions_finish(this)
693 class(system_t), intent(inout) :: this
694
696
697 ! By default nothing is done just after updating the interactions. Child
698 ! classes that wish to change this behaviour should override this method.
699
702
703 ! ---------------------------------------------------------
704 subroutine system_restart_write(this)
705 class(system_t), intent(inout) :: this
706
707 logical :: restart_write
708 type(interaction_iterator_t) :: iter
709 class(interaction_t), pointer :: interaction
710 integer :: ii
711
712 push_sub(system_restart_write)
713
714 call parse_variable(this%namespace, 'RestartWrite', .true., restart_write)
715
716 if (restart_write) then
717 ! do some generic restart steps here
718 ! write iteration counter restart data
719 call this%iteration%restart_write('restart_iteration_system', this%namespace)
720 call this%algo%iteration%restart_write('restart_iteration_propagator', this%namespace)
721 call iter%start(this%interactions)
722 do while (iter%has_next())
723 interaction => iter%get_next()
724 call interaction%restart_write(this%namespace)
725 end do
726 do ii = 1, max_quantities
727 if (this%quantities(ii)%required) then
728 call this%quantities(ii)%iteration%restart_write('restart_iteration_quantity_'//trim(quantity_label(ii)), &
729 this%namespace)
730 end if
731 end do
732 ! the following call is delegated to the corresponding system
733 call this%restart_write_data()
734 message(1) = "Wrote restart data for system "//trim(this%namespace%get())
735 call messages_info(1, namespace=this%namespace)
736 end if
737
738 pop_sub(system_restart_write)
739 end subroutine system_restart_write
740
741 ! ---------------------------------------------------------
742 ! this function returns true if restart data could be read
743 logical function system_restart_read(this)
744 class(system_t), intent(inout) :: this
745
746 type(interaction_iterator_t) :: iter
747 class(interaction_t), pointer :: interaction
748 integer :: ii
749
750 push_sub(system_restart_read)
751
752 ! do some generic restart steps here
753 ! read iteration data
754 system_restart_read = this%iteration%restart_read('restart_iteration_system', this%namespace)
756 this%algo%iteration%restart_read('restart_iteration_propagator', this%namespace)
757 call iter%start(this%interactions)
758 do while (iter%has_next())
759 interaction => iter%get_next()
760 system_restart_read = system_restart_read .and. interaction%restart_read(this%namespace)
761 ! reduce by one because of the first UPDATE_INTERACTIONS
762 interaction%iteration = interaction%iteration - 1
763 end do
764 do ii = 1, max_quantities
765 if (this%quantities(ii)%required) then
767 this%quantities(ii)%iteration%restart_read('restart_iteration_quantity_'//trim(quantity_label(ii)), &
768 this%namespace)
769 end if
770 if (this%quantities(ii)%updated_on_demand) then
771 ! decrease iteration by one for on-demand quantities to account for initial update_interactions step
772 this%quantities(ii)%iteration = this%quantities(ii)%iteration - 1
773 end if
774 end do
775 ! the following call is delegated to the corresponding system
776 system_restart_read = system_restart_read .and. this%restart_read_data()
777
778 if (system_restart_read) then
779 message(1) = "Successfully read restart data for system "//trim(this%namespace%get())
780 call messages_info(1, namespace=this%namespace)
781 end if
782
783 pop_sub(system_restart_read)
784 end function system_restart_read
786 ! ---------------------------------------------------------
787 subroutine system_output_start(this)
788 class(system_t), intent(inout) :: this
789
790 push_sub(system_output_start)
791
792 ! By default nothing is done to regarding output. Child classes that wish
793 ! to change this behaviour should override this method.
794
795 pop_sub(system_output_start)
796 end subroutine system_output_start
798 ! ---------------------------------------------------------
799 subroutine system_output_write(this)
800 class(system_t), intent(inout) :: this
801
802 push_sub(system_output_write)
803
804 ! By default nothing is done to regarding output. Child classes that wish
805 ! to change this behaviour should override this method.
806
807 pop_sub(system_output_write)
808 end subroutine system_output_write
809
810 ! ---------------------------------------------------------
811 subroutine system_output_finish(this)
812 class(system_t), intent(inout) :: this
813
814 push_sub(system_output_finish)
815
816 ! By default nothing is done to regarding output. Child classes that wish
817 ! to change this behaviour should override this method.
818
819 pop_sub(system_output_finish)
820 end subroutine system_output_finish
821
822 ! ---------------------------------------------------------
823 subroutine system_init_algorithm(this, factory)
824 class(system_t), intent(inout) :: this
825 class(algorithm_factory_t), intent(in) :: factory
826
827 integer :: ii
828
829 push_sub(system_init_algorithm)
830
831 call messages_experimental('Multi-system framework')
832
833 this%algo => factory%create(this)
834
835 call this%init_iteration_counters()
837 do ii = 1, number_barriers
838 this%barrier(ii)%active = .false.
839 this%barrier(ii)%target_time = m_zero
840 end do
841
842 pop_sub(system_init_algorithm)
843 end subroutine system_init_algorithm
844
845 ! ---------------------------------------------------------------------------------------
846 recursive function system_algorithm_finished(this) result(finished)
847 class(system_t), intent(in) :: this
848 logical :: finished
849
850 finished = this%algo%finished()
851
852 end function system_algorithm_finished
853
854 ! ---------------------------------------------------------
860 !
861 subroutine system_init_iteration_counters(this)
862 class(system_t), intent(inout) :: this
863
864 type(interaction_iterator_t) :: iter
865 class(interaction_t), pointer :: interaction
866
868
869 ! Initialize algorithm and system counters
870 call this%algo%init_iteration_counters()
871
872 ! Interactions counters
873 call iter%start(this%interactions)
874 do while (iter%has_next())
875 interaction => iter%get_next()
876 interaction%iteration = this%algo%iteration - 1
877 end do
878
879 ! Required quantities counters
880 where (this%quantities%required)
881 this%quantities%iteration = this%algo%iteration
882 end where
883
884 ! On demand quantities will be updated before first use,
885 ! hence we set the iteration counter one iteration behind the algorithms iteration counter
886 where (this%quantities%updated_on_demand)
887 this%quantities%iteration = this%algo%iteration - 1
888 end where
889
891 end subroutine system_init_iteration_counters
893 ! ---------------------------------------------------------
894 subroutine system_propagation_start(this)
895 class(system_t), intent(inout) :: this
896
897 logical :: all_updated
898 type(event_handle_t) :: debug_handle
899 integer, allocatable :: updated_quantities(:)
900
902
903 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_propagation_start"), &
904 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
905
906 ! Update interactions at initial iteration
907 all_updated = this%update_couplings()
908 if (.not. all_updated) then
909 message(1) = "Unable to update interactions when initializing the propagation."
910 call messages_fatal(1, namespace=this%namespace)
911 end if
912 call this%update_interactions()
913
914 ! System-specific and propagator-specific initialization step
915 if (this%algo%start_operation%id /= skip) then
916 if (.not. this%do_algorithmic_operation(this%algo%start_operation, updated_quantities)) then
917 message(1) = "Unsupported algorithmic operation."
918 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
919 call messages_fatal(2, namespace=this%namespace)
920 else if (allocated(updated_quantities)) then
921 message(1) = "Update of quantities not allowed in algorithmic operation."
922 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
923 call messages_fatal(2, namespace=this%namespace)
924 end if
925 end if
926
927 ! Compute the total energy at the beginning of the simulation
928 call this%update_total_energy()
929
930 ! Start output
931 call this%output_start()
932
933 ! Write header for propagation log
934 call messages_print_with_emphasis(msg="Multi-system propagation", namespace=this%namespace)
935 write(message(1), '(a6,1x,a14,1x,a13,1x,a10,1x,a15)') 'Iter', 'Time', 'Energy', 'SC Steps', 'Elapsed Time'
936 call messages_info(1, namespace=this%namespace)
937 call messages_print_with_emphasis(namespace=this%namespace)
938
939 ! Rewind propagator (will also set the initial time to compute the elapsed time)
940 call this%algo%rewind()
941
942 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
943
945 end subroutine system_propagation_start
946
947 ! ---------------------------------------------------------
948 subroutine system_propagation_finish(this)
949 class(system_t), intent(inout) :: this
950 type(event_handle_t) :: debug_handle
951
952 integer, allocatable :: updated_quantities(:)
953
955
956 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_propagation_finish"), &
957 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
958
959 ! Finish output
960 call this%output_finish()
961
962 ! System-specific and propagator-specific finalization step
963 if (this%algo%final_operation%id /= skip) then
964 if (.not. this%do_algorithmic_operation(this%algo%final_operation, updated_quantities)) then
965 message(1) = "Unsupported algorithmic operation."
966 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
967 call messages_fatal(2, namespace=this%namespace)
968 else if (allocated(updated_quantities)) then
969 message(1) = "Update of quantities not allowed in algorithmic operation."
970 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
971 call messages_fatal(2, namespace=this%namespace)
972 end if
973 end if
974
975 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
976
978 end subroutine system_propagation_finish
979
980 ! ---------------------------------------------------------
981 subroutine system_iteration_info(this)
982 class(system_t), intent(in) :: this
983
984 real(real64) :: energy
985 character(len=40) :: fmt
986
988
989 energy = units_from_atomic(units_out%energy, this%total_energy)
990 if (abs(energy) >= 1e5) then
991 fmt = '(i7,1x,f14.6,1X,es13.6,1X,i9,1X,'
992 else
993 fmt = '(i7,1x,f14.6,1X,f13.6,1X,i9,1X,'
994 end if
995 if (this%algo%elapsed_time < 1e-3) then
996 fmt = trim(fmt)//'es13.3)'
997 else
998 fmt = trim(fmt)//'f13.3)'
999 end if
1000
1001 write(message(1), fmt) this%iteration%counter(), &
1002 units_from_atomic(units_out%time, this%iteration%value()), energy, &
1003 0, this%algo%elapsed_time
1004 call messages_info(1, namespace=this%namespace)
1005
1006 pop_sub(system_iteration_info)
1007 end subroutine system_iteration_info
1008
1009 ! ---------------------------------------------------------
1010 logical function system_process_is_slave(this)
1011 class(system_t), intent(in) :: this
1012
1013 push_sub(system_process_is_slave)
1014
1015 ! By default an MPI process is not a slave
1016 system_process_is_slave = .false.
1017
1019 end function system_process_is_slave
1020
1021 ! ---------------------------------------------------------
1022 subroutine system_end(this)
1023 class(system_t), intent(inout) :: this
1024
1025 type(interaction_iterator_t) :: iter
1026 class(interaction_t), pointer :: interaction
1027
1028 push_sub(system_end)
1029
1030 ! No call to safe_deallocate macro here, as it gives an ICE with gfortran
1031 if (associated(this%algo)) then
1032 deallocate(this%algo)
1033 end if
1034
1035 call iter%start(this%interactions)
1036 do while (iter%has_next())
1037 interaction => iter%get_next()
1038 if (associated(interaction)) then
1039 deallocate(interaction)
1040 end if
1041 end do
1042
1043 pop_sub(system_end)
1044 end subroutine system_end
1045
1046 ! ---------------------------------------------------------
1048 subroutine system_list_add_node(this, partner)
1049 class(system_list_t) :: this
1050 class(interaction_partner_t), target :: partner
1051
1052 push_sub(system_list_add_node)
1053
1054 select type (partner)
1055 class is (system_t)
1056 call this%add_ptr(partner)
1057 class default
1058 assert(.false.)
1059 end select
1060
1061 pop_sub(system_list_add_node)
1062 end subroutine system_list_add_node
1063
1064 ! ---------------------------------------------------------
1065 recursive logical function system_list_contains(this, partner) result(contains)
1066 class(system_list_t) :: this
1067 class(interaction_partner_t), target :: partner
1068
1069 type(partner_iterator_t) :: iterator
1070 class(interaction_partner_t), pointer :: system
1071
1072 push_sub(system_list_contains)
1073
1074 contains = .false.
1075
1076 select type (partner)
1077 class is (system_t)
1078
1079 call iterator%start(this)
1080 do while (iterator%has_next() .and. .not. contains)
1081 system => iterator%get_next()
1082 contains = associated(system, partner)
1083 end do
1084
1085 class default
1086 contains = .false.
1087 end select
1088
1089 pop_sub(system_list_contains)
1090 end function system_list_contains
1091
1092 ! ---------------------------------------------------------
1093 function system_iterator_get_next(this) result(system)
1094 class(system_iterator_t), intent(inout) :: this
1095 class(system_t), pointer :: system
1096
1097 push_sub(system_iterator_get_next)
1098
1099 select type (ptr => this%get_next_ptr())
1100 class is (system_t)
1101 system => ptr
1102 class default
1103 assert(.false.)
1104 end select
1105
1107 end function system_iterator_get_next
1108
1109 ! ---------------------------------------------------------
1113 subroutine system_init_parallelization(this, grp)
1114 class(system_t), intent(inout) :: this
1115 type(mpi_grp_t), intent(in) :: grp
1116
1118
1119 call mpi_grp_copy(this%grp, grp)
1120 call messages_update_mpi_grp(this%namespace, grp)
1121
1123 end subroutine system_init_parallelization
1124
1125
1126
1127 ! ---------------------------------------------------------
1128 subroutine system_start_barrier(this, target_time, barrier_index)
1129 class(system_t), intent(inout) :: this
1130 real(real64), intent(in) :: target_time
1131 integer, intent(in) :: barrier_index
1132
1133 push_sub(system_start_barrier)
1134
1135 this%barrier(barrier_index)%active = .true.
1136 this%barrier(barrier_index)%target_time = target_time
1137
1138 pop_sub(system_start_barrier)
1139 end subroutine system_start_barrier
1140
1141 ! ---------------------------------------------------------
1142 subroutine system_end_barrier(this, barrier_index)
1143 class(system_t), intent(inout) :: this
1144 integer, intent(in) :: barrier_index
1145
1146 push_sub(system_end_barrier)
1147
1148 this%barrier(barrier_index)%active = .false.
1149 this%barrier(barrier_index)%target_time = m_zero
1150
1151 pop_sub(system_end_barrier)
1152 end subroutine system_end_barrier
1153
1154 ! ---------------------------------------------------------
1155 logical function system_arrived_at_barrier(this, barrier_index)
1156 class(system_t), intent(inout) :: this
1157 integer, intent(in) :: barrier_index
1159 type(iteration_counter_t) :: iteration
1160
1162
1164 if (this%barrier(barrier_index)%active) then
1165 iteration = this%iteration + 1
1166 if (iteration%value() > this%barrier(barrier_index)%target_time) then
1168 end if
1169 end if
1170
1172 end function system_arrived_at_barrier
1173
1174 ! ---------------------------------------------------------
1175 logical function system_arrived_at_any_barrier(this)
1176 class(system_t), intent(inout) :: this
1177
1178 integer :: ii
1179
1181
1183 do ii = 1, number_barriers
1185 .or. this%arrived_at_barrier(ii)
1186 end do
1187
1190
1191
1192 ! ---------------------------------------------------------
1197 subroutine system_update_potential_energy(this)
1198 class(system_t), intent(inout) :: this
1199
1200 type(interaction_iterator_t) :: iter
1201 class(interaction_t), pointer :: interaction
1202
1204
1205 this%potential_energy = m_zero
1207 call iter%start(this%interactions)
1208 do while (iter%has_next())
1209 interaction => iter%get_next()
1210 if(.not. interaction%intra_interaction) then
1211 call interaction%calculate_energy()
1212 this%potential_energy = this%potential_energy + interaction%energy
1213 end if
1214 end do
1215
1217 end subroutine system_update_potential_energy
1218
1219 ! ---------------------------------------------------------
1224 subroutine system_update_internal_energy(this)
1225 class(system_t), intent(inout) :: this
1226
1227 type(interaction_iterator_t) :: iter
1228 class(interaction_t), pointer :: interaction
1229
1231
1232 this%internal_energy = m_zero
1233 call iter%start(this%interactions)
1234 do while (iter%has_next())
1235 interaction => iter%get_next()
1236 if(interaction%intra_interaction) then
1237 call interaction%calculate_energy()
1238 this%internal_energy = this%internal_energy + interaction%energy
1239 end if
1240 end do
1241
1243 end subroutine system_update_internal_energy
1244
1245 ! ---------------------------------------------------------
1249 subroutine system_update_total_energy(this)
1250 class(system_t), intent(inout) :: this
1251
1253
1254 call this%update_kinetic_energy()
1255 this%total_energy = this%kinetic_energy
1256
1258 call this%update_potential_energy()
1259 this%total_energy = this%total_energy + this%potential_energy
1260
1262 call this%update_internal_energy()
1263 this%total_energy = this%total_energy + this%internal_energy
1264
1266 end subroutine system_update_total_energy
1267
1269
1270!! Local Variables:
1271!! mode: f90
1272!! coding: utf-8
1273!! End:
Execute one operation that is part of a larger algorithm. Returns true if the operation was successfu...
Definition: system.F90:253
initialize a given interaction of the system
Definition: system.F90:229
set initial conditions for a system
Definition: system.F90:238
check whether a system has reached a given tolerance
Definition: system.F90:263
For some algorithms it might be necessary to store the status of a system at a given algorithmic step...
Definition: system.F90:274
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_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:930
character(len=512), private msg
Definition: messages.F90:165
subroutine, public messages_update_mpi_grp(namespace, mpigrp)
Definition: messages.F90:377
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
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 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_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:1343
subroutine system_iteration_info(this)
Definition: system.F90:1075
subroutine, public system_init_iteration_counters(this)
Initialize the iteration counters of the system and its interactions, algorithms and quantities.
Definition: system.F90:955
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:1318
logical function system_arrived_at_any_barrier(this)
Definition: system.F90:1269
recursive logical function system_list_contains(this, partner)
Definition: system.F90:1159
subroutine, public system_restart_write(this)
Definition: system.F90:798
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:1291
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:1207
subroutine system_output_start(this)
Definition: system.F90:881
subroutine system_update_interactions_start(this)
Definition: system.F90:774
subroutine system_start_barrier(this, target_time, barrier_index)
Definition: system.F90:1222
recursive subroutine, public system_create_interactions(this, interaction_factory, available_partners)
create the interactions of the system
Definition: system.F90:502
subroutine, public system_propagation_finish(this)
Definition: system.F90:1042
subroutine, public system_end(this)
Definition: system.F90:1116
subroutine system_output_write(this)
Definition: system.F90:893
subroutine system_update_interactions_finish(this)
Definition: system.F90:786
subroutine, public system_execute_algorithm(this)
perform one or more algorithmic operations
Definition: system.F90:331
subroutine system_update_interactions(this)
Attempt to update all interactions of the system.
Definition: system.F90:701
class(system_t) function, pointer system_iterator_get_next(this)
Definition: system.F90:1187
logical function system_update_couplings(this)
Update the couplings (quantities) of the interaction partners.
Definition: system.F90:664
logical function system_process_is_slave(this)
Definition: system.F90:1104
logical function system_arrived_at_barrier(this, barrier_index)
Definition: system.F90:1249
recursive logical function system_algorithm_finished(this)
Definition: system.F90:940
logical function, public system_restart_read(this)
Definition: system.F90:837
subroutine system_output_finish(this)
Definition: system.F90:905
subroutine system_list_add_node(this, partner)
add system to list
Definition: system.F90:1142
subroutine, public system_propagation_start(this)
Definition: system.F90:988
subroutine, public system_reset_iteration_counters(this, accumulated_iterations)
Definition: system.F90:449
subroutine, public system_init_algorithm(this, factory)
Definition: system.F90:917
subroutine system_end_barrier(this, barrier_index)
Definition: system.F90:1236
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:302
Abstract class for systems.
Definition: system.F90:172
int true(void)