Octopus
multisystem.F90
Go to the documentation of this file.
1!! Copyright (C) 2019-2020 M. Oliveira, Heiko Appel
2!! Copyright (C) 2021 S. Ohlmann
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
47 use debug_oct_m
48 use global_oct_m
53 use io_oct_m
55 use loct_oct_m
57 use mpi_oct_m
60 use parser_oct_m
62 use system_oct_m
64 implicit none
65
66 private
67 public :: &
71
78 type, extends(system_t), abstract :: multisystem_t
79 type(system_list_t) :: list
80 contains
81 procedure :: execute_algorithm => multisystem_execute_algorithm
82 procedure :: init_parallelization => multisystem_init_parallelization
83 procedure :: next_time_on_largest_dt => multisystem_next_time_on_largest_dt
84 procedure :: reset_iteration_counters => multisystem_reset_iteration_counters
85 procedure :: init_algorithm => multisystem_init_algorithm
86 procedure :: algorithm_finished => multisystem_algorithm_finished
87 procedure :: init_iteration_counters => multisystem_init_iteration_counters
88 procedure :: propagation_start => multisystem_propagation_start
89 procedure :: propagation_finish => multisystem_propagation_finish
90 procedure :: init_all_interactions => multisystem_init_all_interactions
91 procedure :: init_interaction => multisystem_init_interaction
92 procedure :: write_interaction_graph => multisystem_write_interaction_graph
93 procedure :: initial_conditions => multisystem_initial_conditions
94 procedure :: do_algorithmic_operation => multisystem_do_algorithmic_operation
95 procedure :: is_tolerance_reached => multisystem_is_tolerance_reached
96 procedure :: update_quantity => multisystem_update_quantity
97 procedure :: init_interaction_as_partner => multisystem_init_interaction_as_partner
98 procedure :: copy_quantities_to_interaction => multisystem_copy_quantities_to_interaction
99 procedure :: process_is_slave => multisystem_process_is_slave
100 procedure :: start_barrier => multisystem_start_barrier
101 procedure :: end_barrier => multisystem_end_barrier
102 procedure :: arrived_at_barrier => multisystem_arrived_at_barrier
103 procedure :: restart_write => multisystem_restart_write
104 procedure :: restart_read => multisystem_restart_read
105 procedure :: restart_write_data => multisystem_restart_write_data
106 procedure :: restart_read_data => multisystem_restart_read_data
107 procedure :: update_kinetic_energy => multisystem_update_kinetic_energy
108 procedure :: update_potential_energy => multisystem_update_potential_energy
109 procedure :: update_internal_energy => multisystem_update_internal_energy
110 procedure :: get_flat_list => multisystem_get_flat_list
111 end type multisystem_t
112
113contains
114
115 ! ---------------------------------------------------------------------------------------
120 recursive subroutine multisystem_init(this, namespace, factory)
121 class(multisystem_t), intent(inout) :: this
122 type(namespace_t), intent(in) :: namespace
123 class(system_factory_abst_t), intent(in) :: factory
124
125 integer :: isys, system_type, ic
126 character(len=128) :: system_name
127 type(block_t) :: blk
129 push_sub(multisystem_init)
130
131 this%namespace = namespace
132
133 if (parse_block(this%namespace, factory%block_name(), blk) == 0) then
134
135 do isys = 1, parse_block_n(blk)
136 ! Parse system name and type
137 call parse_block_string(blk, isys - 1, 0, system_name)
138 if (len_trim(system_name) == 0) then
139 call messages_input_error(this%namespace, factory%block_name(), 'All systems must have a name')
140 end if
142 if (index(trim(system_name), parser_varname_excluded_characters(ic:ic)) /= 0) then
143 call messages_input_error(this%namespace, factory%block_name(), &
144 'Illegal character "' // parser_varname_excluded_characters(ic:ic) // '" in system name', row=isys-1, column=0)
145 end if
146 end do
147 call parse_block_integer(blk, isys - 1, 1, system_type)
148
149 call multisystem_create_system(this, system_name, system_type, isys, factory)
150 end do
151 call parse_block_end(blk)
152 else
153 message(1) = "Input error while reading block "//trim(this%namespace%get())//"."//trim(factory%block_name())
154 call messages_fatal(1, namespace=this%namespace)
155 end if
156
157 pop_sub(multisystem_init)
158 end subroutine multisystem_init
159
160 ! ---------------------------------------------------------------------------------------
163 recursive subroutine multisystem_create_system(this, system_name, system_type, isys, factory)
164 class(multisystem_t), intent(inout) :: this
165 character(len=128), intent(in) :: system_name
166 integer, intent(in) :: system_type
167 integer, intent(in) :: isys
168 class(system_factory_abst_t), intent(in) :: factory
170 type(system_iterator_t) :: iter
171 class(system_t), pointer :: sys, other
175 ! Create folder to store system files.
176 ! Needs to be done before creating the system as this in turn might create subfolders.
177 call io_mkdir(system_name, namespace=this%namespace)
179 ! Create system
180 sys => factory%create(this%namespace, system_name, system_type)
181 if (.not. associated(sys)) then
182 call messages_input_error(this%namespace, factory%block_name(), 'Unknown system type.')
183 end if
185 ! Check that the system is unique
186 call iter%start(this%list)
187 do while (iter%has_next())
188 other => iter%get_next()
189 if (sys%namespace == other%namespace) then
190 call messages_input_error(this%namespace, factory%block_name(), 'Duplicated system in multi-system', &
191 row=isys-1, column=0)
192 end if
193 end do
195 ! Add system to list of systems
196 call this%list%add(sys)
197
199 end subroutine multisystem_create_system
200
201 ! ---------------------------------------------------------------------------------------
204 recursive subroutine multisystem_init_parallelization(this, grp)
205 class(multisystem_t), intent(inout) :: this
206 type(mpi_grp_t), intent(in) :: grp
207
208 type(system_iterator_t) :: iter
209 class(system_t), pointer :: sys
210 type(mpi_grp_t) :: sys_grp
211
213
214 call system_init_parallelization(this, grp)
215
216 ! Now parallelize over systems in this multisystem
217 call iter%start(this%list)
218 do while (iter%has_next())
219 sys => iter%get_next()
220 ! for now, duplicate communicator - more complicated parallelization schemes can be implemented here
221 call mpi_grp_duplicate(sys_grp, grp)
222 call sys%init_parallelization(sys_grp)
223 end do
224
227
228 ! ---------------------------------------------------------------------------------------
229 recursive function multisystem_next_time_on_largest_dt(this) result(next_time_on_largest_dt)
230 class(multisystem_t), intent(inout) :: this
231 float :: next_time_on_largest_dt
232
233 type(system_iterator_t) :: iter
234 class(system_t), pointer :: system
235 type(iteration_counter_t) :: iteration
236
238
239 next_time_on_largest_dt = m_zero
240 call iter%start(this%list)
241 do while (iter%has_next())
242 system => iter%get_next()
243 select type (system)
244 class is (multisystem_t)
245 next_time_on_largest_dt = max(next_time_on_largest_dt, system%next_time_on_largest_dt())
246 class default
247 iteration = system%iteration + 1
248 next_time_on_largest_dt = max(next_time_on_largest_dt, iteration%value())
249 end select
250 end do
251
254
255 ! ---------------------------------------------------------------------------------------
256 recursive subroutine multisystem_execute_algorithm(this)
257 class(multisystem_t), intent(inout) :: this
258
259 type(system_iterator_t) :: iter
260 class(system_t), pointer :: system
261
262 type(event_handle_t) :: debug_handle
263
265
266 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("multisystem_dt_operation"), &
267 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
268
269 ! Multisystem
270 call system_execute_algorithm(this)
271
272 ! Subsystems
273 call iter%start(this%list)
274 do while (iter%has_next())
275 system => iter%get_next()
276 call system%execute_algorithm()
277 end do
278
279 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
280
282 end subroutine multisystem_execute_algorithm
283
284 ! ---------------------------------------------------------------------------------------
285 recursive subroutine multisystem_reset_iteration_counters(this, accumulated_iterations)
286 class(multisystem_t), intent(inout) :: this
287 integer, intent(in) :: accumulated_iterations
289 type(system_iterator_t) :: iter
290 class(system_t), pointer :: system
291
293
294 ! Multisystem iteration counters
295 call system_reset_iteration_counters(this, accumulated_iterations)
296
297 ! Subsystems iteration counters
298 call iter%start(this%list)
299 do while (iter%has_next())
300 system => iter%get_next()
301 call system%reset_iteration_counters(accumulated_iterations)
302 end do
303
306
307 ! ---------------------------------------------------------------------------------------
308 recursive subroutine multisystem_init_algorithm(this, factory)
309 class(multisystem_t), intent(inout) :: this
310 class(algorithm_factory_t), intent(in) :: factory
311
312 type(system_iterator_t) :: iter
313 class(system_t), pointer :: system
314
316
317 ! Now initialized the propagators of the subsystems
318 call iter%start(this%list)
319 do while (iter%has_next())
320 system => iter%get_next()
321 call system%init_algorithm(factory)
322 end do
323
324 ! Initialize the propagator of the multisystem. By default the
325 ! multisystem itself and its own quantities are kept unchanged
326 ! by using the static propagator. However, the subsystems are allowed to have
327 ! their own propagators and those do not have to be static.
328 ! Needs to be done after initializing the subsystems propagators,
329 ! as we use the largest dt of the subsystems.
330 this%algo => factory%create_static(this)
331 call this%algo%rewind()
332
334
336 end subroutine multisystem_init_algorithm
337
338 ! ---------------------------------------------------------------------------------------
339 recursive function multisystem_algorithm_finished(this) result(finished)
340 class(multisystem_t), intent(in) :: this
341 logical :: finished
342
343 type(system_iterator_t) :: iter
344 class(system_t), pointer :: system
345
346 ! Check if multisystem itself is finished
347 finished = this%algo%finished()
348
349 ! Check subsystems
350 call iter%start(this%list)
351 do while (iter%has_next())
352 system => iter%get_next()
353 finished = finished .and. system%algorithm_finished()
354 end do
355
357
358 ! ---------------------------------------------------------------------------------------
361 recursive subroutine multisystem_init_iteration_counters(this)
362 class(multisystem_t), intent(inout) :: this
363
364 type(system_iterator_t) :: iter
365 class(system_t), pointer :: system
366
368
369 ! initialize multisystem iteration counters
371
372 ! initialize iteration counters of subsystems
373 call iter%start(this%list)
374 do while (iter%has_next())
375 system => iter%get_next()
376 call system%init_iteration_counters()
377 end do
378
381
382 ! ---------------------------------------------------------------------------------------
385 recursive subroutine multisystem_propagation_start(this)
386 class(multisystem_t), intent(inout) :: this
387
388 type(system_iterator_t) :: iter
389 class(system_t), pointer :: system
390
391 type(event_handle_t) :: debug_handle
394
395 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("multisystem_propagation_start"), &
396 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
397
398 ! Start the propagation of the multisystem
399 call system_propagation_start(this)
400
401 ! Now start the propagation of the subsystems
402 call iter%start(this%list)
403 do while (iter%has_next())
404 system => iter%get_next()
405 call system%propagation_start()
406 end do
407
408 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
409
411 end subroutine multisystem_propagation_start
412
413 ! ---------------------------------------------------------------------------------------
416 recursive subroutine multisystem_propagation_finish(this)
417 class(multisystem_t), intent(inout) :: this
418
419 type(system_iterator_t) :: iter
420 class(system_t), pointer :: system
421
422 type(event_handle_t) :: debug_handle
425
426 debug_handle = multisystem_debug_write_event_in(this%namespace, event_function_call_t("multisystem_propagation_finish"), &
427 system_iteration = this%iteration, algo_iteration = this%algo%iteration)
428
429 ! Finish the propagation of the multisystem
431
432 ! Now finish the propagation of the subsystems
433 call iter%start(this%list)
434 do while (iter%has_next())
435 system => iter%get_next()
436 call system%propagation_finish()
437 end do
438
439 call multisystem_debug_write_event_out(debug_handle, system_iteration = this%iteration, algo_iteration = this%algo%iteration)
440
442 end subroutine multisystem_propagation_finish
443
444 ! ---------------------------------------------------------
451 recursive subroutine multisystem_init_all_interactions(this)
452 class(multisystem_t), intent(inout) :: this
453
454 type(interaction_iterator_t) :: iter_i
455 class(interaction_t), pointer :: interaction
456 type(system_iterator_t) :: iter_s
457 class(system_t), pointer :: system
458
460
461 ! Initialize interactions directly owned by the multisystem
462 call iter_i%start(this%interactions)
463 do while (iter_i%has_next())
464 interaction => iter_i%get_next()
465 select type (interaction)
466 type is (ghost_interaction_t)
467 ! Skip the ghost interactions
468 class default
469 call this%init_interaction(interaction)
470 call interaction%partner%init_interaction_as_partner(interaction)
471 interaction%timing = timing_exact
472 end select
473 end do
474
475 ! Initialize interactions owned by the subsystems
476 call iter_s%start(this%list)
477 do while (iter_s%has_next())
478 system => iter_s%get_next()
479 call system%init_all_interactions()
480 end do
481
484
485 ! ---------------------------------------------------------
491
492 subroutine multisystem_init_interaction(this, interaction)
493 class(multisystem_t), target, intent(inout) :: this
494 class(interaction_t), intent(inout) :: interaction
495
497
498 ! The multisystem class should never know about any specific interaction.
499 ! Only classes that extend it can know about specific interactions.
500 ! Such classes should override this method to add new supported interactions.
501 message(1) = "Trying to initialize an interaction in the multi-system container class"
502 call messages_fatal(1, namespace=this%namespace)
503
505 end subroutine multisystem_init_interaction
506
507 ! ---------------------------------------------------------------------------------------
510 recursive subroutine multisystem_write_interaction_graph(this, iunit, include_ghosts)
511 class(multisystem_t), intent(in) :: this
512 integer, intent(in) :: iunit
513 logical, intent(in) :: include_ghosts
514
515 class(system_t), pointer :: system
516 class(interaction_t), pointer :: interaction
517 type(system_iterator_t) :: sys_iter
518 type(interaction_iterator_t) :: inter_iter
519
521
522 ! Loop over all the subsystems
523 call sys_iter%start(this%list)
524 do while (sys_iter%has_next())
525 system => sys_iter%get_next()
526
527 ! Loop over the interactions that this subsystem has
528 call inter_iter%start(system%interactions)
529 do while (inter_iter%has_next())
530 interaction => inter_iter%get_next()
531
532 ! Write interaction to DOT graph if this interaction has a partner
533 select type (interaction)
534 type is (ghost_interaction_t)
535 if (include_ghosts) then
536 write(iunit, '(2x,a)') '"' + trim(system%namespace%get()) + '" -> "' + trim(interaction%partner%namespace%get()) + &
537 '" [label="'+ interaction%label + '"];'
538 end if
539 ! Do not include systems connected by ghost interactions
540 class default
541 write(iunit, '(2x,a)') '"' + trim(system%namespace%get()) + '" -> "' + trim(interaction%partner%namespace%get()) + &
542 '" [label="'+ interaction%label + '"];'
543 end select
544 end do
545
546 ! If this subsystem is also a multisystem, then we also need to traverse it
547 select type (system)
548 class is (multisystem_t)
549 call system%write_interaction_graph(iunit, include_ghosts)
550 end select
551 end do
552
555
556 ! ---------------------------------------------------------
557 recursive subroutine multisystem_initial_conditions(this)
558 class(multisystem_t), intent(inout) :: this
559
560 type(system_iterator_t) :: iter
561 class(system_t), pointer :: system
562
564
565 call iter%start(this%list)
566 do while (iter%has_next())
567 system => iter%get_next()
568 call system%initial_conditions()
569 end do
570
572 end subroutine multisystem_initial_conditions
573
574 ! ---------------------------------------------------------
575 logical function multisystem_do_algorithmic_operation(this, operation, updated_quantities) result(done)
576 class(multisystem_t), intent(inout) :: this
577 class(algorithmic_operation_t), intent(in) :: operation
578 integer, allocatable, intent(out) :: updated_quantities(:)
579
581
582 ! Currently there are no multisystem specific algorithmic operations
583 done = .false.
584
587
588 ! ---------------------------------------------------------
589 recursive logical function multisystem_is_tolerance_reached(this, tol) result(converged)
590 class(multisystem_t), intent(in) :: this
591 float, intent(in) :: tol
592
593 type(system_iterator_t) :: iter
594 class(system_t), pointer :: system
595
597
598 converged = .true.
599 call iter%start(this%list)
600 do while (iter%has_next())
601 system => iter%get_next()
602 if (.not. system%is_tolerance_reached(tol)) converged = .false.
603 end do
604
607
608 ! ---------------------------------------------------------
609 subroutine multisystem_update_quantity(this, iq)
610 class(multisystem_t), intent(inout) :: this
611 integer, intent(in) :: iq
612
614
615 ! The multisystem class should never know about any specific quantities.
616 ! Only classes that extend it can know about specific quantities.
617 ! Such classes should override this method to add new supported quantities.
618 message(1) = "Trying to update a quantity in the multi-system container class"
619 call messages_fatal(1, namespace=this%namespace)
620
622 end subroutine multisystem_update_quantity
623
624 ! ---------------------------------------------------------
625 subroutine multisystem_init_interaction_as_partner(partner, interaction)
626 class(multisystem_t), intent(in) :: partner
627 class(interaction_surrogate_t), intent(inout) :: interaction
628
630
631 ! The multisystem class should never know about any specific interaction.
632 ! Only classes that extend it can know about specific interactions.
633 ! Such classes should override this method to add new supported interactions.
634 message(1) = "Trying to initialize an interaction as partner in the multi-system container class"
635 call messages_fatal(1, namespace=partner%namespace)
636
639
640 ! ---------------------------------------------------------
641 subroutine multisystem_copy_quantities_to_interaction(partner, interaction)
642 class(multisystem_t), intent(inout) :: partner
643 class(interaction_surrogate_t), intent(inout) :: interaction
644
646
647 ! The multisystem class should never know about any specific quantities.
648 ! Only classes that extend it can know about specific quantities.
649 ! Such classes should override this method to add new supported quantities.
650 message(1) = "Trying to copy quantities to interaction in the multi-system container class"
651 call messages_fatal(1, namespace=partner%namespace)
652
655
656 ! ---------------------------------------------------------
657 recursive logical function multisystem_process_is_slave(this) result(is_slave)
658 class(multisystem_t), intent(in) :: this
660 type(system_iterator_t) :: iter
661 class(system_t), pointer :: system
662
664
665 is_slave = .false.
666 call iter%start(this%list)
667 do while (iter%has_next())
668 system => iter%get_next()
669 if (system%process_is_slave()) is_slave = .true.
670 end do
671
674
675 !--------------------------------------------------------------------
679 recursive subroutine multisystem_update_kinetic_energy(this)
680 class(multisystem_t), intent(inout) :: this
681
683
684 ! We currently do not have the center of mass coordinates implemented for multisystems,
685 ! hence we set the kinetic energy to zero.
686 ! The kinetic energies of the constituents are contributing to the internal energy.
687
688 this%kinetic_energy = m_zero
689
692
693 !---------------------------------------------------------
694 recursive subroutine multisystem_update_internal_energy(this)
695 class(multisystem_t), intent(inout) :: this
696
697 class(system_t), pointer :: system
698 class(system_t), pointer :: system_2
699 type(system_iterator_t) :: system_iter
700 type(system_iterator_t) :: system_iter_2
701
703
704 ! The internal energy of the multisystem contains the kinetic and internal energies of the consistuents
705 !TODO: the kinetic energy wrt the center of mass motion should be subtracted.
706
707 this%internal_energy = m_zero
708
709 call system_iter%start(this%list)
710 do while (system_iter%has_next())
711
712 system => system_iter%get_next()
713
714 ! First add the kinetic energies of the subsystems
715 call system%update_kinetic_energy()
716 this%internal_energy = this%internal_energy + system%kinetic_energy
717
718 ! First add the internal energies of the subsystems
719 call system%update_internal_energy()
720 this%internal_energy = this%internal_energy + system%internal_energy
721
722 ! Now add the (inter-) interactions between the systems in the container.
723 call system_iter_2%start(this%list)
724 do while(system_iter_2%has_next())
726 system_2 => system_iter_2%get_next()
727
728 ! exclude self-interactions (intra-interactions) as they are included in the internal energy
729 ! of the subsystem, which was already added above.
730 if(.not. associated(system, system_2)) then
731 this%internal_energy = this%internal_energy + multisystem_pair_energy(system, system_2)
732 end if
733 end do ! system_iter_2
734
735 end do ! system_iter
736
739
740 ! ---------------------------------------------------------
754 class(multisystem_t), intent(inout) :: this
755
756 type(system_iterator_t) :: system_iter
757 class(system_t), pointer :: system
758 type(interaction_iterator_t) :: interaction_iter
759 class(interaction_t), pointer :: interaction
760 type(system_list_t) :: flat_list
761
764 this%potential_energy = m_zero
765
766 ! We need to handle interactions of the container itself:
768
769 ! generate a list of all systems inside the container and its subcontainers:
770 call this%get_flat_list(flat_list)
771
772 ! loop over all systems inside the container
773 call system_iter%start(flat_list)
774 do while (system_iter%has_next())
775
776 system => system_iter%get_next()
777
778 ! Even though we are not using the potential energy of the subsystems here, we need to trigger their calculation
779 call system%update_potential_energy()
780
781 ! loop over all interactions and discard those with partners inside the container
782 call interaction_iter%start(system%interactions)
783 do while (interaction_iter%has_next())
784 interaction => interaction_iter%get_next()
785 if(.not. flat_list%contains(interaction%partner) .and. .not. interaction%intra_interaction) then
786 call interaction%calculate_energy()
787 this%potential_energy = this%potential_energy + interaction%energy
788 end if
789 end do
790
791 end do
792
795
796 ! ---------------------------------------------------------
803 recursive float function multisystem_pair_energy(partner_A, partner_B) result(pair_energy)
804 class(interaction_partner_t), intent(in) :: partner_a
805 class(interaction_partner_t), intent(in) :: partner_b
806
807 class(system_t), pointer :: system_a
808 class(system_t), pointer :: system_b
809 type(system_iterator_t) :: system_iterator_a
810 type(system_iterator_t) :: system_iterator_b
811
813
814 pair_energy = m_zero
815
816 select type(partner_a)
817 class is (multisystem_t) ! partner_A is container
818
819 call system_iterator_a%start(partner_a%list)
820 do while( system_iterator_a%has_next() )
821
822 system_a => system_iterator_a%get_next()
823
824 select type(partner_b)
825 class is (multisystem_t)
826
827 call system_iterator_b%start(partner_b%list)
828 do while( system_iterator_b%has_next() )
829 system_b => system_iterator_b%get_next()
830 pair_energy = pair_energy + multisystem_pair_energy(system_a, system_b)
831 end do
832
833 class is (system_t)
834 pair_energy = pair_energy + interaction_energy(partner_a, partner_b)
835 class default
836 assert(.false.) ! partner_A must be a system_t
837 end select
838 end do
839
840 class is (system_t) ! partner_A is non-container system
841
842 select type(partner_b)
843 class is (multisystem_t) ! partner_B is container
844
845 call system_iterator_b%start(partner_b%list)
846 do while( system_iterator_b%has_next() )
847 system_b => system_iterator_b%get_next()
848 pair_energy = pair_energy + multisystem_pair_energy(partner_a, system_b)
849 end do
850
851 class default ! both partner_A and partner_B are explicit: we need to calculate
852 pair_energy = pair_energy + interaction_energy(partner_a, partner_b)
853 end select
854
855 class default
856 assert(.false.)
857 end select
858
860
861 contains
862
863 float function interaction_energy(system, partner) result (energy)
864 class(system_t), target, intent(in) :: system
865 class(interaction_partner_t), target, intent(in) :: partner
866
867 type(interaction_iterator_t) :: interaction_iterator
868 class(interaction_t), pointer :: interaction
869
870 energy = m_zero
871
872 call interaction_iterator%start(system%interactions)
873 do while(interaction_iterator%has_next())
874 interaction => interaction_iterator%get_next()
875 if( associated(interaction%partner, partner)) then
876 call interaction%calculate_energy()
877 energy = energy + interaction%energy
878 end if
879 end do
880 end function interaction_energy
881
882 end function multisystem_pair_energy
883
884
885 ! ---------------------------------------------------------
888 recursive subroutine multisystem_get_flat_list(this, flat_list)
889 class(multisystem_t), intent(in) :: this
890 type(system_list_t), intent(out) :: flat_list
891
892 class(interaction_partner_t), pointer :: partner
893 type(partner_iterator_t) :: iterator
894
896
897 call iterator%start(this%list)
898 do while (iterator%has_next())
899 partner => iterator%get_next()
900
901 call flat_list%add(partner)
902
903 select type (partner)
904 class is (multisystem_t)
905 ! Also include the subsystems of a multisystem
906 call partner%get_flat_list(flat_list)
907 end select
908
909 end do
910
912
913 end subroutine multisystem_get_flat_list
914
915 ! ---------------------------------------------------------
916 recursive subroutine multisystem_end(this)
917 class(multisystem_t), intent(inout) :: this
918
919 type(system_iterator_t) :: iter
920 class(system_t), pointer :: system
921
922 push_sub(multisystem_end)
923
924 call iter%start(this%list)
925 do while (iter%has_next())
926 system => iter%get_next()
927 if (associated(system)) then
928 deallocate(system)
929 end if
930 end do
931
932 call system_end(this)
933
934 pop_sub(multisystem_end)
935 end subroutine multisystem_end
936
937 ! ---------------------------------------------------------
938 recursive subroutine multisystem_start_barrier(this, target_time, barrier_index)
939 class(multisystem_t), intent(inout) :: this
940 float, intent(in) :: target_time
941 integer, intent(in) :: barrier_index
942
943 type(system_iterator_t) :: iter
944 class(system_t), pointer :: system
945
948 call iter%start(this%list)
949 do while (iter%has_next())
950 system => iter%get_next()
951 call system%start_barrier(target_time, barrier_index)
952 end do
953
955 end subroutine multisystem_start_barrier
956
957 ! ---------------------------------------------------------
958 recursive subroutine multisystem_end_barrier(this, barrier_index)
959 class(multisystem_t), intent(inout) :: this
960 integer, intent(in) :: barrier_index
961
962 type(system_iterator_t) :: iter
963 class(system_t), pointer :: system
964
966
967 call iter%start(this%list)
968 do while (iter%has_next())
969 system => iter%get_next()
970 call system%end_barrier(barrier_index)
971 end do
974 end subroutine multisystem_end_barrier
975
976 ! ---------------------------------------------------------
977 recursive logical function multisystem_arrived_at_barrier(this, barrier_index)
978 class(multisystem_t), intent(inout) :: this
979 integer, intent(in) :: barrier_index
980
981 type(system_iterator_t) :: iter
982 class(system_t), pointer :: system
983
985
987 call iter%start(this%list)
988 do while (iter%has_next())
989 system => iter%get_next()
991 system%arrived_at_barrier(barrier_index)
992 end do
993
996
997 ! ---------------------------------------------------------
998 recursive subroutine multisystem_restart_write(this)
999 class(multisystem_t), intent(inout) :: this
1001 type(system_iterator_t) :: iter
1002 class(system_t), pointer :: system
1003
1005
1006 ! do generic restart steps
1007 call system_restart_write(this)
1008
1009 ! loop over all subsystems
1010 call iter%start(this%list)
1011 do while (iter%has_next())
1012 system => iter%get_next()
1013 call system%restart_write()
1014 end do
1015 message(1) = "Wrote restart data for multisystem "//trim(this%namespace%get())
1016 call messages_info(1, namespace=this%namespace)
1017
1019 end subroutine multisystem_restart_write
1020
1021 ! ---------------------------------------------------------
1022 recursive logical function multisystem_restart_read(this)
1023 class(multisystem_t), intent(inout) :: this
1024
1025 type(system_iterator_t) :: iter
1026 class(system_t), pointer :: system
1027
1028 push_sub(multisystem_restart_read)
1029
1030 ! read generic restart data
1032 call iter%start(this%list)
1033 do while (iter%has_next())
1034 system => iter%get_next()
1035 ! TODO: adapt logics here for consistent restarting
1037 system%restart_read()
1038 end do
1039
1040 if (multisystem_restart_read) then
1041 message(1) = "Successfully read restart data for multisystem "//trim(this%namespace%get())
1042 call messages_info(1, namespace=this%namespace)
1043 end if
1044
1046 end function multisystem_restart_read
1047
1048 ! ---------------------------------------------------------
1049 subroutine multisystem_restart_write_data(this)
1050 class(multisystem_t), intent(inout) :: this
1051
1053
1054 ! do not write restart data for multisystem_t
1055
1057 end subroutine multisystem_restart_write_data
1058
1059 ! ---------------------------------------------------------
1060 ! this function returns true if restart data could be read
1061 logical function multisystem_restart_read_data(this)
1062 class(multisystem_t), intent(inout) :: this
1063
1065
1067
1070
1071end module multisystem_oct_m
real(8) function interaction_energy(system, partner)
This module defines the abstract interfact for algorithm factories.
This module implements the basic elements defining algorithms.
Definition: algorithm.F90:132
real(8), parameter, public m_zero
Definition: global.F90:167
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
integer, parameter, public timing_exact
This module defines classes and functions for interaction partners.
Definition: io.F90:105
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:345
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:603
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:151
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:400
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:702
subroutine mpi_grp_duplicate(mpi_grp_out, mpi_grp_in)
Definition: mpi.F90:406
This module implements the multisystem debug functionality.
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 implements the abstract multisystem class.
recursive subroutine, public multisystem_end(this)
recursive subroutine multisystem_init_all_interactions(this)
initialize all interactions of the multisystem
recursive logical function multisystem_process_is_slave(this)
recursive subroutine, public multisystem_init(this, namespace, factory)
initialize the multisystem class
recursive logical function multisystem_arrived_at_barrier(this, barrier_index)
recursive subroutine multisystem_init_algorithm(this, factory)
recursive subroutine multisystem_update_internal_energy(this)
recursive subroutine multisystem_restart_write(this)
recursive real(8) function multisystem_pair_energy(partner_A, partner_B)
This function calculates the complete interaction energy between partner_A and partner_B,...
subroutine multisystem_init_interaction(this, interaction)
initialize a specific interaction
subroutine multisystem_update_quantity(this, iq)
subroutine multisystem_update_potential_energy(this)
Calculate the potential energy for a container.
recursive subroutine multisystem_create_system(this, system_name, system_type, isys, factory)
create a system in the container
recursive subroutine multisystem_reset_iteration_counters(this, accumulated_iterations)
recursive logical function multisystem_restart_read(this)
subroutine multisystem_init_interaction_as_partner(partner, interaction)
recursive subroutine multisystem_propagation_start(this)
call the propagation_start routine for all contained systems
recursive logical function multisystem_is_tolerance_reached(this, tol)
recursive subroutine multisystem_propagation_finish(this)
call the propagation_finish routine for all contained systems
recursive subroutine multisystem_initial_conditions(this)
subroutine multisystem_copy_quantities_to_interaction(partner, interaction)
recursive real(8) function multisystem_next_time_on_largest_dt(this)
recursive subroutine multisystem_execute_algorithm(this)
recursive subroutine multisystem_init_parallelization(this, grp)
brief initialize the parallelization of the multisystem
recursive subroutine multisystem_get_flat_list(this, flat_list)
Generate a list of all systems contained in a multisystem, including those inside child containers.
logical function multisystem_restart_read_data(this)
subroutine multisystem_restart_write_data(this)
recursive subroutine multisystem_end_barrier(this, barrier_index)
recursive subroutine multisystem_update_kinetic_energy(this)
Calculate the kinetic energy: The kinetic energy of a container (multisystem) is defined by the kinet...
recursive subroutine multisystem_init_iteration_counters(this)
initialize the iteration counters of the contained systems
recursive subroutine multisystem_start_barrier(this, target_time, barrier_index)
recursive logical function multisystem_algorithm_finished(this)
recursive subroutine multisystem_write_interaction_graph(this, iunit, include_ghosts)
write a graphical representation of the interactions
logical function multisystem_do_algorithmic_operation(this, operation, updated_quantities)
character(len=27), parameter, public parser_varname_excluded_characters
Definition: parser.F90:143
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:568
This module defines the abstract class for the system factory.
This module implements the abstract system type.
Definition: system.F90:109
subroutine, public system_init_iteration_counters(this)
Definition: system.F90:817
subroutine, public system_restart_write(this)
Definition: system.F90:666
subroutine, public system_update_potential_energy(this)
Calculate the potential energy of the system. The potential energy is defined as the sum of all energ...
Definition: system.F90:1149
subroutine, public system_init_parallelization(this, grp)
Basic functionality: copy the MPI group. This function needs to be implemented by extended types that...
Definition: system.F90:1065
subroutine, public system_propagation_finish(this)
Definition: system.F90:901
subroutine, public system_end(this)
Definition: system.F90:975
subroutine, public system_execute_algorithm(this)
perform one or more algorithmic operations
Definition: system.F90:314
logical function, public system_restart_read(this)
Definition: system.F90:705
subroutine, public system_propagation_start(this)
Definition: system.F90:847
subroutine, public system_reset_iteration_counters(this, accumulated_iterations)
Definition: system.F90:432
Abstract class for the algorithm factories.
Descriptor of one algorithmic operation.
Definition: algorithm.F90:154
The ghost ineraction is a dummy interaction, which needs to be setup between otherwise non-interactin...
These class extend the list and list iterator to make an interaction list.
abstract interaction class
abstract class for general interaction partners
surrogate interaction class to avoid circular dependencies between modules.
This class implements the iteration counter used by the multisystem algorithms. As any iteration coun...
This is defined even when running serial.
Definition: mpi.F90:132
handle to keep track of in- out- events
the abstract multisystem class
These classes extends the list and list iterator to create a system list.
Definition: system.F90:285
Abstract class for systems.
Definition: system.F90:161
int true(void)