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 ! All systems need to be connected to make sure they remain synchronized.
428 ! We enforce that be adding a ghost interaction between all systems.
429 call iter%start(available_partners)
430 do while (iter%has_next())
431 partner => iter%get_next()
432 call partner%add_partners_to_list(partners)
433 end do
434 call iter%start(partners)
435 do while (iter%has_next())
436 partner => iter%get_next()
437
438 ! No self-interaction
439 if (partner%namespace%get() == this%namespace%get()) cycle
440
441 call this%interactions%add(ghost_interaction_t(partner))
442 end do
443 call partners%empty()
444
445 ! Get options to use to create all the interactions supported by this system
446 allocate(options(0)) ! Workaround to avoid a gfortran warning
447 options = interaction_factory%options(this%namespace, this%supported_interactions)
449 ! Loop over all interactions supported by this system and create them according to the provided options
450 do i = 1, size(this%supported_interactions)
451 interaction_type = this%supported_interactions(i)
452
453 ! Supported interactions should only appear once in the corresponding
454 ! list, otherwise more than one interaction of the same type will be
455 ! created
456 assert(count(this%supported_interactions == interaction_type) == 1)
457
458 ! Get the list of partners that support this interaction type
459 call iter%start(available_partners)
460 do while (iter%has_next())
461 partner => iter%get_next()
462 call partner%add_partners_to_list(partners, interaction_type)
463 end do
464
465 ! Create list of partners for this interaction taking into account the selected mode
466 select case (options(i)%mode)
467 case (all_partners)
468 ! Use all available partners, so no need to modify the list
469
470 case (no_partners)
471 ! No partners for this interaction, so empty the list
472 call partners%empty()
473
474 case (only_partners)
475 ! Start with full list and remove the partners not listed in the options
476 call iter%start(partners)
477 do while (iter%has_next())
478 partner => iter%get_next()
479 in_list = .false.
480 do ip = 1, size(options(i)%partners)
481 if (partner%namespace%is_contained_in(options(i)%partners(ip))) then
482 in_list = .true.
483 exit
484 end if
485 end do
486 if (.not. in_list) then
487 call partners%delete(partner)
488 end if
489 end do
490
491 case (all_except)
492 ! Start with full list and remove the partners listed in the options
493 do ip = 1, size(options(i)%partners)
494 call iter%start(partners)
495 do while (iter%has_next())
496 partner => iter%get_next()
497 if (partner%namespace%is_contained_in(options(i)%partners(ip))) then
498 call partners%delete(partner)
499 end if
500 end do
501 end do
502
503 end select
504
505 ! Now actually create the interactions for the selected partners
506 call iter%start(partners)
507 do while (iter%has_next())
508 partner => iter%get_next()
509
510 interaction => interaction_factory%create(interaction_type, partner)
511
512 ! Set flag for self-interaction
513 interaction%intra_interaction = partner%namespace%get() == this%namespace%get()
514
515 ! Set timing and perform sanity checks
516 interaction%timing = options(i)%timing
517 if (interaction%timing == timing_exact) then
518 select type (partner => interaction%partner)
519 class is (system_t)
520 if (this%algo%iteration%global_step() /= partner%algo%iteration%global_step() .and. &
521 .not. all(partner%quantities(interaction%couplings_from_partner)%always_available)) then
522 write(message(1), '(2a)') "InteractionTiming was set to exact timing, but systems ", &
523 trim(this%namespace%get())
524 write(message(2), '(3a)') "and ", trim(partner%namespace%get()), " have incompatible steps."
525 call messages_fatal(2, namespace=this%namespace)
526 end if
527 end select
528 end if
529
530 ! Initialize interaction from system and from partner
531 call this%init_interaction(interaction)
532 call interaction%partner%init_interaction_as_partner(interaction)
533
534 !Mark all the quantities needed by the interaction from the system and the partner as required
535 if (allocated(interaction%system_quantities)) then
536 this%quantities(interaction%system_quantities)%required = .true.
537 end if
538 if (allocated(interaction%couplings_from_partner)) then
539 partner%quantities(interaction%couplings_from_partner)%required = .true.
540 end if
541
542 ! Add interaction to list
543 call this%interactions%add(interaction)
544 end do
545
546 ! Empty partner list for next interaction
547 call partners%empty()
548 end do
549
551 end subroutine system_create_interactions
552
553 ! ---------------------------------------------------------
559 logical function system_update_couplings(this) result(all_updated)
560 class(system_t), intent(inout) :: this
561
562 class(interaction_t), pointer :: interaction
563 type(interaction_iterator_t) :: iter
564
566
567 all_updated = .true.
568 call iter%start(this%interactions)
569 do while (iter%has_next())
570 interaction => iter%get_next()
571
572 select type (partner => interaction%partner)
573 class is (system_t)
574 ! If the partner is a system, we can only update its couplings if it
575 ! is not too much behind the requested iteration
576 if (partner%algo%iteration + 1 >= this%algo%iteration) then
577 call interaction%update_partner_couplings(this%algo%iteration)
578 end if
579
580 class default
581 ! Partner that are not systems can have their couplings updated at any iteration
582 call interaction%update_partner_couplings(this%algo%iteration)
583 end select
584
585 all_updated = all_updated .and. interaction%partner_couplings_up_to_date
586 end do
587
589 end function system_update_couplings
590
591 ! ---------------------------------------------------------
596 subroutine system_update_interactions(this)
597 class(system_t), intent(inout) :: this
598
599 integer :: iq, q_id, n_quantities
600 class(interaction_t), pointer :: interaction
601 type(interaction_iterator_t) :: iter
602
604
605 ! Some systems might need to perform some specific operations before the
606 ! update.
607 call this%update_interactions_start()
608
609 !Loop over all interactions
610 call iter%start(this%interactions)
611 do while (iter%has_next())
612 interaction => iter%get_next()
613
614 ! Update the system quantities that will be needed for computing the interaction
615 if (allocated(interaction%system_quantities)) then
616 n_quantities = size(interaction%system_quantities)
617 else
618 n_quantities = 0
619 end if
620 do iq = 1, n_quantities
621 ! Get requested quantity ID
622 q_id = interaction%system_quantities(iq)
623
624 if (.not. this%quantities(q_id)%iteration == this%algo%iteration) then
625 ! The requested quantity is not at the requested iteration, so we try to update it
626
627 if (.not. this%quantities(q_id)%updated_on_demand) then
628 ! Quantity must be at the correct iteration, otherwise the algorithm and
629 ! the interaction are incompatible
630 if (.not. this%quantities(q_id)%iteration == this%algo%iteration .and. &
631 .not. this%quantities(q_id)%always_available) then
632 write(message(1), '(5a)') "Interaction ", trim(interaction%label), " is incompatible with the selected algorithm."
633 write(message(2), '(3a)') "The interaction requires the ", trim(quantity_label(q_id)), &
634 " at a iteration it is not available."
635 call messages_fatal(2, namespace=this%namespace)
636 end if
637
638 ! We do not need to update quantities that are not updated on
639 ! demand, as the algorithm takes care of doing that, so move on to
640 ! next quantity
641 cycle
642 end if
643
644 ! Sanity check: it should never happen that the quantity is in advance
645 ! with respect to the requested iteration.
646 if (this%quantities(q_id)%iteration > this%algo%iteration) then
647 message(1) = "The quantity iteration is in advance compared to the requested iteration."
648 call messages_fatal(1, namespace=this%namespace)
649 end if
650
651 call this%update_quantity(q_id)
653 this%quantities(q_id)%iteration, "set"))
654 end if
655
656 end do
657
658 call interaction%update(this%algo%iteration)
659 end do
660
661 ! Some systems might need to perform some specific operations after all the
662 ! interactions have been updated
663 call this%update_interactions_finish()
664
666 end subroutine system_update_interactions
667
668 ! ---------------------------------------------------------
669 subroutine system_update_interactions_start(this)
670 class(system_t), intent(inout) :: this
671
673
674 ! By default nothing is done just before updating the interactions. Child
675 ! classes that wish to change this behaviour should override this method.
676
679
680 ! ---------------------------------------------------------
681 subroutine system_update_interactions_finish(this)
682 class(system_t), intent(inout) :: this
683
685
686 ! By default nothing is done just after updating the interactions. Child
687 ! classes that wish to change this behaviour should override this method.
688
691
692 ! ---------------------------------------------------------
693 subroutine system_restart_write(this)
694 class(system_t), intent(inout) :: this
695
696 logical :: restart_write
697 type(interaction_iterator_t) :: iter
698 class(interaction_t), pointer :: interaction
699 integer :: ii
700
701 push_sub(system_restart_write)
702
703 call parse_variable(this%namespace, 'RestartWrite', .true., restart_write)
704
705 if (restart_write) then
706 ! do some generic restart steps here
707 ! write iteration counter restart data
708 call this%iteration%restart_write('restart_iteration_system', this%namespace)
709 call this%algo%iteration%restart_write('restart_iteration_propagator', this%namespace)
710 call iter%start(this%interactions)
711 do while (iter%has_next())
712 interaction => iter%get_next()
713 call interaction%restart_write(this%namespace)
714 end do
715 do ii = 1, max_quantities
716 if (this%quantities(ii)%required) then
717 call this%quantities(ii)%iteration%restart_write('restart_iteration_quantity_'//trim(quantity_label(ii)), &
718 this%namespace)
719 end if
720 end do
721 ! the following call is delegated to the corresponding system
722 call this%restart_write_data()
723 message(1) = "Wrote restart data for system "//trim(this%namespace%get())
724 call messages_info(1, namespace=this%namespace)
725 end if
726
727 pop_sub(system_restart_write)
728 end subroutine system_restart_write
729
730 ! ---------------------------------------------------------
731 ! this function returns true if restart data could be read
732 logical function system_restart_read(this)
733 class(system_t), intent(inout) :: this
734
735 type(interaction_iterator_t) :: iter
736 class(interaction_t), pointer :: interaction
737 integer :: ii
738
739 push_sub(system_restart_read)
740
741 ! do some generic restart steps here
742 ! read iteration data
743 system_restart_read = this%iteration%restart_read('restart_iteration_system', this%namespace)
745 this%algo%iteration%restart_read('restart_iteration_propagator', this%namespace)
746 call iter%start(this%interactions)
747 do while (iter%has_next())
748 interaction => iter%get_next()
749 system_restart_read = system_restart_read .and. interaction%restart_read(this%namespace)
750 ! reduce by one because of the first UPDATE_INTERACTIONS
751 interaction%iteration = interaction%iteration - 1
752 end do
753 do ii = 1, max_quantities
754 if (this%quantities(ii)%required) then
756 this%quantities(ii)%iteration%restart_read('restart_iteration_quantity_'//trim(quantity_label(ii)), &
757 this%namespace)
758 end if
759 if (this%quantities(ii)%updated_on_demand) then
760 ! decrease iteration by one for on-demand quantities to account for initial update_interactions step
761 this%quantities(ii)%iteration = this%quantities(ii)%iteration - 1
762 end if
763 end do
764 ! the following call is delegated to the corresponding system
765 system_restart_read = system_restart_read .and. this%restart_read_data()
766
767 if (system_restart_read) then
768 message(1) = "Successfully read restart data for system "//trim(this%namespace%get())
769 call messages_info(1, namespace=this%namespace)
770 end if
771
772 pop_sub(system_restart_read)
773 end function system_restart_read
775 ! ---------------------------------------------------------
776 subroutine system_output_start(this)
777 class(system_t), intent(inout) :: this
778
779 push_sub(system_output_start)
780
781 ! By default nothing is done to regarding output. Child classes that wish
782 ! to change this behaviour should override this method.
783
784 pop_sub(system_output_start)
785 end subroutine system_output_start
787 ! ---------------------------------------------------------
788 subroutine system_output_write(this)
789 class(system_t), intent(inout) :: this
790
791 push_sub(system_output_write)
792
793 ! By default nothing is done to regarding output. Child classes that wish
794 ! to change this behaviour should override this method.
795
796 pop_sub(system_output_write)
797 end subroutine system_output_write
798
799 ! ---------------------------------------------------------
800 subroutine system_output_finish(this)
801 class(system_t), intent(inout) :: this
802
803 push_sub(system_output_finish)
804
805 ! By default nothing is done to regarding output. Child classes that wish
806 ! to change this behaviour should override this method.
807
808 pop_sub(system_output_finish)
809 end subroutine system_output_finish
810
811 ! ---------------------------------------------------------
812 subroutine system_init_algorithm(this, factory)
813 class(system_t), intent(inout) :: this
814 class(algorithm_factory_t), intent(in) :: factory
815
816 integer :: ii
817
818 push_sub(system_init_algorithm)
819
820 call messages_experimental('Multi-system framework')
821
822 this%algo => factory%create(this)
823
824 call this%init_iteration_counters()
826 do ii = 1, number_barriers
827 this%barrier(ii)%active = .false.
828 this%barrier(ii)%target_time = m_zero
829 end do
830
831 pop_sub(system_init_algorithm)
832 end subroutine system_init_algorithm
833
834 ! ---------------------------------------------------------------------------------------
835 recursive function system_algorithm_finished(this) result(finished)
836 class(system_t), intent(in) :: this
837 logical :: finished
838
839 finished = this%algo%finished()
840
841 end function system_algorithm_finished
842
843 ! ---------------------------------------------------------
849 !
850 subroutine system_init_iteration_counters(this)
851 class(system_t), intent(inout) :: this
852
853 type(interaction_iterator_t) :: iter
854 class(interaction_t), pointer :: interaction
855
857
858 ! Initialize algorithm and system counters
859 call this%algo%init_iteration_counters()
860
861 ! Interactions counters
862 call iter%start(this%interactions)
863 do while (iter%has_next())
864 interaction => iter%get_next()
865 interaction%iteration = this%algo%iteration - 1
866 end do
867
868 ! Required quantities counters
869 where (this%quantities%required)
870 this%quantities%iteration = this%algo%iteration
871 end where
872
873 ! On demand quantities will be updated before first use,
874 ! hence we set the iteration counter one iteration behind the algorithms iteration counter
875 where (this%quantities%updated_on_demand)
876 this%quantities%iteration = this%algo%iteration - 1
877 end where
878
880 end subroutine system_init_iteration_counters
882 ! ---------------------------------------------------------
883 subroutine system_propagation_start(this)
884 class(system_t), intent(inout) :: this
885
886 logical :: all_updated
887 type(event_handle_t) :: debug_handle
888 integer, allocatable :: updated_quantities(:)
889
891
892 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_propagation_start"), &
893 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
894
895 ! Update interactions at initial iteration
896 all_updated = this%update_couplings()
897 if (.not. all_updated) then
898 message(1) = "Unable to update interactions when initializing the propagation."
899 call messages_fatal(1, namespace=this%namespace)
900 end if
901 call this%update_interactions()
902
903 ! System-specific and propagator-specific initialization step
904 if (this%algo%start_operation%id /= skip) then
905 if (.not. this%do_algorithmic_operation(this%algo%start_operation, updated_quantities)) then
906 message(1) = "Unsupported algorithmic operation."
907 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
908 call messages_fatal(2, namespace=this%namespace)
909 else if (allocated(updated_quantities)) then
910 message(1) = "Update of quantities not allowed in algorithmic operation."
911 write(message(2), '(A,A,A)') trim(this%algo%start_operation%id), ": ", trim(this%algo%start_operation%label)
912 call messages_fatal(2, namespace=this%namespace)
913 end if
914 end if
915
916 ! Compute the total energy at the beginning of the simulation
917 call this%update_total_energy()
918
919 ! Start output
920 call this%output_start()
921
922 ! Write header for propagation log
923 call messages_print_with_emphasis(msg="Multi-system propagation", namespace=this%namespace)
924 write(message(1), '(a6,1x,a14,1x,a13,1x,a10,1x,a15)') 'Iter', 'Time', 'Energy', 'SC Steps', 'Elapsed Time'
925 call messages_info(1, namespace=this%namespace)
926 call messages_print_with_emphasis(namespace=this%namespace)
927
928 ! Rewind propagator (will also set the initial time to compute the elapsed time)
929 call this%algo%rewind()
930
931 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
932
934 end subroutine system_propagation_start
935
936 ! ---------------------------------------------------------
937 subroutine system_propagation_finish(this)
938 class(system_t), intent(inout) :: this
939 type(event_handle_t) :: debug_handle
940
941 integer, allocatable :: updated_quantities(:)
942
944
945 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("system_propagation_finish"), &
946 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
947
948 ! Finish output
949 call this%output_finish()
950
951 ! System-specific and propagator-specific finalization step
952 if (this%algo%final_operation%id /= skip) then
953 if (.not. this%do_algorithmic_operation(this%algo%final_operation, updated_quantities)) then
954 message(1) = "Unsupported algorithmic operation."
955 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
956 call messages_fatal(2, namespace=this%namespace)
957 else if (allocated(updated_quantities)) then
958 message(1) = "Update of quantities not allowed in algorithmic operation."
959 write(message(2), '(A,A,A)') trim(this%algo%final_operation%id), ": ", trim(this%algo%final_operation%label)
960 call messages_fatal(2, namespace=this%namespace)
961 end if
962 end if
963
964 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
965
967 end subroutine system_propagation_finish
968
969 ! ---------------------------------------------------------
970 subroutine system_iteration_info(this)
971 class(system_t), intent(in) :: this
972
973 real(real64) :: energy
974 character(len=40) :: fmt
975
977
978 energy = units_from_atomic(units_out%energy, this%total_energy)
979 if (abs(energy) >= 1e5) then
980 fmt = '(i7,1x,f14.6,1X,es13.6,1X,i9,1X,'
981 else
982 fmt = '(i7,1x,f14.6,1X,f13.6,1X,i9,1X,'
983 end if
984 if (this%algo%elapsed_time < 1e-3) then
985 fmt = trim(fmt)//'es13.3)'
986 else
987 fmt = trim(fmt)//'f13.3)'
988 end if
989
990 write(message(1), fmt) this%iteration%counter(), &
991 units_from_atomic(units_out%time, this%iteration%value()), energy, &
992 0, this%algo%elapsed_time
993 call messages_info(1, namespace=this%namespace)
994
995 pop_sub(system_iteration_info)
996 end subroutine system_iteration_info
997
998 ! ---------------------------------------------------------
999 logical function system_process_is_slave(this)
1000 class(system_t), intent(in) :: this
1001
1002 push_sub(system_process_is_slave)
1003
1004 ! By default an MPI process is not a slave
1005 system_process_is_slave = .false.
1006
1008 end function system_process_is_slave
1009
1010 ! ---------------------------------------------------------
1011 subroutine system_end(this)
1012 class(system_t), intent(inout) :: this
1013
1014 type(interaction_iterator_t) :: iter
1015 class(interaction_t), pointer :: interaction
1016
1017 push_sub(system_end)
1018
1019 ! No call to safe_deallocate macro here, as it gives an ICE with gfortran
1020 if (associated(this%algo)) then
1021 deallocate(this%algo)
1022 end if
1023
1024 call iter%start(this%interactions)
1025 do while (iter%has_next())
1026 interaction => iter%get_next()
1027 if (associated(interaction)) then
1028 deallocate(interaction)
1029 end if
1030 end do
1031
1032 pop_sub(system_end)
1033 end subroutine system_end
1034
1035 ! ---------------------------------------------------------
1036 subroutine system_list_add_node(this, partner)
1037 class(system_list_t) :: this
1038 class(interaction_partner_t), target :: partner
1039
1040 push_sub(system_list_add_node)
1041
1042 select type (partner)
1043 class is (system_t)
1044 call this%add_ptr(partner)
1045 class default
1046 assert(.false.)
1047 end select
1048
1049 pop_sub(system_list_add_node)
1050 end subroutine system_list_add_node
1051
1052 ! ---------------------------------------------------------
1053 recursive logical function system_list_contains(this, partner) result(contains)
1054 class(system_list_t) :: this
1055 class(interaction_partner_t), target :: partner
1056
1057 type(partner_iterator_t) :: iterator
1058 class(interaction_partner_t), pointer :: system
1059
1060 push_sub(system_list_contains)
1061
1062 contains = .false.
1064 select type (partner)
1065 class is (system_t)
1066
1067 call iterator%start(this)
1068 do while (iterator%has_next() .and. .not. contains)
1069 system => iterator%get_next()
1070 contains = associated(system, partner)
1071 end do
1072
1073 class default
1074 contains = .false.
1075 end select
1076
1077 pop_sub(system_list_contains)
1078 end function system_list_contains
1079
1080 ! ---------------------------------------------------------
1081 function system_iterator_get_next(this) result(system)
1082 class(system_iterator_t), intent(inout) :: this
1083 class(system_t), pointer :: system
1084
1085 push_sub(system_iterator_get_next)
1086
1087 select type (ptr => this%get_next_ptr())
1088 class is (system_t)
1089 system => ptr
1090 class default
1091 assert(.false.)
1092 end select
1093
1095 end function system_iterator_get_next
1096
1097 ! ---------------------------------------------------------
1101 subroutine system_init_parallelization(this, grp)
1102 class(system_t), intent(inout) :: this
1103 type(mpi_grp_t), intent(in) :: grp
1106
1107 call mpi_grp_copy(this%grp, grp)
1108 call messages_update_mpi_grp(this%namespace, grp)
1109
1111 end subroutine system_init_parallelization
1112
1113
1114
1115 ! ---------------------------------------------------------
1116 subroutine system_start_barrier(this, target_time, barrier_index)
1117 class(system_t), intent(inout) :: this
1118 real(real64), intent(in) :: target_time
1119 integer, intent(in) :: barrier_index
1120
1121 push_sub(system_start_barrier)
1122
1123 this%barrier(barrier_index)%active = .true.
1124 this%barrier(barrier_index)%target_time = target_time
1125
1126 pop_sub(system_start_barrier)
1127 end subroutine system_start_barrier
1128
1129 ! ---------------------------------------------------------
1130 subroutine system_end_barrier(this, barrier_index)
1131 class(system_t), intent(inout) :: this
1132 integer, intent(in) :: barrier_index
1133
1134 push_sub(system_end_barrier)
1135
1136 this%barrier(barrier_index)%active = .false.
1137 this%barrier(barrier_index)%target_time = m_zero
1138
1139 pop_sub(system_end_barrier)
1140 end subroutine system_end_barrier
1141
1142 ! ---------------------------------------------------------
1143 logical function system_arrived_at_barrier(this, barrier_index)
1144 class(system_t), intent(inout) :: this
1145 integer, intent(in) :: barrier_index
1147 type(iteration_counter_t) :: iteration
1148
1150
1152 if (this%barrier(barrier_index)%active) then
1153 iteration = this%iteration + 1
1154 if (iteration%value() > this%barrier(barrier_index)%target_time) then
1156 end if
1157 end if
1158
1160 end function system_arrived_at_barrier
1161
1162 ! ---------------------------------------------------------
1163 logical function system_arrived_at_any_barrier(this)
1164 class(system_t), intent(inout) :: this
1165
1166 integer :: ii
1167
1169
1171 do ii = 1, number_barriers
1173 .or. this%arrived_at_barrier(ii)
1174 end do
1175
1178
1179
1180 ! ---------------------------------------------------------
1185 subroutine system_update_potential_energy(this)
1186 class(system_t), intent(inout) :: this
1187
1188 type(interaction_iterator_t) :: iter
1189 class(interaction_t), pointer :: interaction
1190
1192
1193 this%potential_energy = m_zero
1195 call iter%start(this%interactions)
1196 do while (iter%has_next())
1197 interaction => iter%get_next()
1198 if(.not. interaction%intra_interaction) then
1199 call interaction%calculate_energy()
1200 this%potential_energy = this%potential_energy + interaction%energy
1201 end if
1202 end do
1203
1205 end subroutine system_update_potential_energy
1206
1207 ! ---------------------------------------------------------
1212 subroutine system_update_internal_energy(this)
1213 class(system_t), intent(inout) :: this
1214
1215 type(interaction_iterator_t) :: iter
1216 class(interaction_t), pointer :: interaction
1217
1219
1220 this%internal_energy = m_zero
1221 call iter%start(this%interactions)
1222 do while (iter%has_next())
1223 interaction => iter%get_next()
1224 if(interaction%intra_interaction) then
1225 call interaction%calculate_energy()
1226 this%internal_energy = this%internal_energy + interaction%energy
1227 end if
1228 end do
1229
1231 end subroutine system_update_internal_energy
1232
1233 ! ---------------------------------------------------------
1237 subroutine system_update_total_energy(this)
1238 class(system_t), intent(inout) :: this
1239
1241
1242 call this%update_kinetic_energy()
1243 this%total_energy = this%kinetic_energy
1244
1246 call this%update_potential_energy()
1247 this%total_energy = this%total_energy + this%potential_energy
1248
1250 call this%update_internal_energy()
1251 this%total_energy = this%total_energy + this%internal_energy
1252
1254 end subroutine system_update_total_energy
1255
1257
1258!! Local Variables:
1259!! mode: f90
1260!! coding: utf-8
1261!! 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:398
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:1331
subroutine system_iteration_info(this)
Definition: system.F90:1064
subroutine, public system_init_iteration_counters(this)
Initialize the iteration counters of the system and its interactions, algorithms and quantities.
Definition: system.F90:944
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:1306
logical function system_arrived_at_any_barrier(this)
Definition: system.F90:1257
recursive logical function system_list_contains(this, partner)
Definition: system.F90:1147
subroutine, public system_restart_write(this)
Definition: system.F90:787
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:1279
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:1195
subroutine system_output_start(this)
Definition: system.F90:870
subroutine system_update_interactions_start(this)
Definition: system.F90:763
subroutine system_start_barrier(this, target_time, barrier_index)
Definition: system.F90:1210
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:1031
subroutine, public system_end(this)
Definition: system.F90:1105
subroutine system_output_write(this)
Definition: system.F90:882
subroutine system_update_interactions_finish(this)
Definition: system.F90:775
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:690
class(system_t) function, pointer system_iterator_get_next(this)
Definition: system.F90:1175
logical function system_update_couplings(this)
Update the couplings (quantities) of the interaction partners.
Definition: system.F90:653
logical function system_process_is_slave(this)
Definition: system.F90:1093
logical function system_arrived_at_barrier(this, barrier_index)
Definition: system.F90:1237
recursive logical function system_algorithm_finished(this)
Definition: system.F90:929
logical function, public system_restart_read(this)
Definition: system.F90:826
subroutine system_output_finish(this)
Definition: system.F90:894
subroutine system_list_add_node(this, partner)
Definition: system.F90:1130
subroutine, public system_propagation_start(this)
Definition: system.F90:977
subroutine, public system_reset_iteration_counters(this, accumulated_iterations)
Definition: system.F90:449
subroutine, public system_init_algorithm(this, factory)
Definition: system.F90:906
subroutine system_end_barrier(this, barrier_index)
Definition: system.F90:1224
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:139
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)