Octopus
batch.F90
Go to the documentation of this file.
1!! Copyright (C) 2008 X. Andrade, 2020 S. Ohlmann
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
39!
40module batch_oct_m
41 use accel_oct_m
43 use blas_oct_m
44 use debug_oct_m
45 use global_oct_m
47 use iso_c_binding
48 use math_oct_m
50 use mpi_oct_m
52 use types_oct_m
53
54 implicit none
55
56 private
57 public :: &
58 batch_t, &
59 batch_init, &
63
66 type batch_t
67 private
68 integer, public :: nst
69 integer, public :: dim
70 integer :: np
71 integer :: ndims
72 integer, allocatable :: ist_idim_index(:, :)
73
77 integer, allocatable, public :: ist(:)
83
84 logical :: is_allocated
85 logical :: own_memory
86 ! We also need a linear array with the states in order to calculate derivatives, etc.
87 integer, public :: nst_linear
88
89 integer :: status_of
93 integer :: status_host
102 type(type_t) :: type_of
103 integer :: device_buffer_count
104 integer :: host_buffer_count
105 logical :: special_memory
106 logical :: needs_finish_unpack
107
108
109 ! unpacked variables; linear variables are pointers with different shapes
110 real(real64), pointer, contiguous, public :: dff(:, :, :)
111 ! !! indices are (1:np, 1:dim, 1:nst)
112 complex(real64), pointer, contiguous, public :: zff(:, :, :)
113 ! !! indices are (1:np, 1:dim, 1:nst)
114 real(real64), pointer, contiguous, public :: dff_linear(:, :)
115 ! !! indices are (1:np, 1:nst_linear)
116 complex(real64), pointer, contiguous, public :: zff_linear(:, :)
117 ! !! indices are (1:np, 1:nst_linear)
118
119 ! packed variables; only rank-2 arrays due to padding to powers of 2
120 real(real64), pointer, contiguous, public :: dff_pack(:, :)
121 ! !! indices are (1:nst_linear, 1:np)
122 complex(real64), pointer, contiguous, public :: zff_pack(:, :)
123 ! !! indices are (1:nst_linear, 1:np)
124
125 integer(int64), public :: pack_size(1:2)
127 integer(int64), public :: pack_size_real(1:2)
130
131 type(accel_mem_t), public :: ff_device
132
133 contains
134 procedure :: check_compatibility_with => batch_check_compatibility_with
135 procedure :: clone_to => batch_clone_to
136 procedure :: clone_to_array => batch_clone_to_array
137 procedure :: copy_to => batch_copy_to
138 procedure :: copy_data_to => batch_copy_data_to
139 procedure :: do_pack_generic => batch_do_pack_generic
140 procedure :: do_pack_target => batch_do_pack_target
141 generic :: do_pack => do_pack_generic, do_pack_target
142 procedure :: do_unpack => batch_do_unpack
143 procedure :: finish_unpack => batch_finish_unpack
144 procedure :: end => batch_end
145 procedure :: inv_index => batch_inv_index
146 procedure :: is_packed => batch_is_packed
147 procedure :: ist_idim_to_linear => batch_ist_idim_to_linear
148 procedure :: linear_to_idim => batch_linear_to_idim
149 procedure :: linear_to_ist => batch_linear_to_ist
150 procedure :: pack_total_size => batch_pack_total_size
151 procedure :: remote_access_start => batch_remote_access_start
152 procedure :: remote_access_stop => batch_remote_access_stop
153 procedure :: status => batch_status
154 procedure :: type => batch_type
155 procedure :: type_as_int => batch_type_as_integer
156 procedure, private :: dallocate_unpacked_host => dbatch_allocate_unpacked_host
157
158 procedure, private :: zallocate_unpacked_host => zbatch_allocate_unpacked_host
159
160 procedure, private :: allocate_unpacked_host => batch_allocate_unpacked_host
162 procedure, private :: dallocate_packed_host => dbatch_allocate_packed_host
164 procedure, private :: zallocate_packed_host => zbatch_allocate_packed_host
166 procedure, private :: allocate_packed_host => batch_allocate_packed_host
168 procedure, private :: allocate_packed_device => batch_allocate_packed_device
169
170 procedure, private :: deallocate_unpacked_host => batch_deallocate_unpacked_host
171
172 procedure, private :: deallocate_packed_host => batch_deallocate_packed_host
173
174 procedure, private :: deallocate_packed_device => batch_deallocate_packed_device
175
176 end type batch_t
177
178 !--------------------------------------------------------------
182 interface batch_init
183 module procedure dbatch_init_with_memory_3
185 module procedure dbatch_init_with_memory_2
186 module procedure zbatch_init_with_memory_2
187 module procedure dbatch_init_with_memory_1
189 end interface batch_init
190
191 integer, public, parameter :: &
192 batch_not_packed = 0, & !< functions are stored in CPU memory, unpacked order
193 batch_packed = 1, &
195
196 integer, parameter :: cl_pack_max_buffer_size = 4
199contains
201 !--------------------------------------------------------------
208 !
209 subroutine batch_end(this, copy)
210 class(batch_t), intent(inout) :: this
211 logical, optional, intent(in) :: copy
213
214 push_sub(batch_end)
216 if (this%own_memory .and. this%is_packed()) then
217 !deallocate directly to avoid unnecessary copies
218 if (this%status() == batch_device_packed) then
219 call this%deallocate_packed_device()
220 end if
221 if (this%status() == batch_packed .or. this%status_host == batch_packed) then
222 call this%deallocate_packed_host()
223 end if
224 this%status_of = batch_not_packed
225 this%status_host = batch_not_packed
226 this%host_buffer_count = 0
227 this%device_buffer_count = 0
228 end if
229 if (this%status() == batch_device_packed) call this%do_unpack(copy, force = .true.)
230 if (this%status() == batch_packed) call this%do_unpack(copy, force = .true.)
232 if (this%is_allocated) then
233 call this%deallocate_unpacked_host()
234 end if
236 safe_deallocate_a(this%ist_idim_index)
237 safe_deallocate_a(this%ist)
239 pop_sub(batch_end)
240 end subroutine batch_end
242 !--------------------------------------------------------------
248 class(batch_t), intent(inout) :: this
252 this%is_allocated = .false.
254 if (this%special_memory) then
255 if (associated(this%dff)) then
256 call deallocate_hardware_aware(c_loc(this%dff(1,1,1)), int(this%np, int64)*this%dim*this%nst*8)
257 end if
258 if (associated(this%zff)) then
259 call deallocate_hardware_aware(c_loc(this%zff(1,1,1)), int(this%np, int64)*this%dim*this%nst*16)
260 end if
261 else
262 safe_deallocate_p(this%dff)
263 safe_deallocate_p(this%zff)
264 end if
265 nullify(this%dff)
266 nullify(this%dff_linear)
267 nullify(this%zff)
268 nullify(this%zff_linear)
271 end subroutine batch_deallocate_unpacked_host
272
273 !--------------------------------------------------------------
278 subroutine batch_deallocate_packed_host(this)
279 class(batch_t), intent(inout) :: this
280
282
283 if (this%special_memory) then
284 if (associated(this%dff_pack)) then
285 call deallocate_hardware_aware(c_loc(this%dff_pack(1,1)), int(this%pack_size(1), int64)*this%pack_size(2)*8)
286 end if
287 if (associated(this%zff_pack)) then
288 call deallocate_hardware_aware(c_loc(this%zff_pack(1,1)), int(this%pack_size(1), int64)*this%pack_size(2)*16)
289 end if
290 else
291 safe_deallocate_p(this%dff_pack)
292 safe_deallocate_p(this%zff_pack)
293 end if
294 nullify(this%dff_pack)
295 nullify(this%zff_pack)
296
298 end subroutine batch_deallocate_packed_host
299
300 !--------------------------------------------------------------
302 !
303 subroutine batch_deallocate_packed_device(this)
304 class(batch_t), intent(inout) :: this
305
307
308 call accel_release_buffer(this%ff_device)
309
311 end subroutine batch_deallocate_packed_device
312
313 !--------------------------------------------------------------
317 !
318 subroutine batch_allocate_unpacked_host(this)
319 class(batch_t), intent(inout) :: this
320
322
323 if (this%type() == type_float) then
324 call this%dallocate_unpacked_host()
325 else if (this%type() == type_cmplx) then
326 call this%zallocate_unpacked_host()
327 end if
328
330 end subroutine batch_allocate_unpacked_host
331
332 !--------------------------------------------------------------
336 !
337 subroutine batch_allocate_packed_host(this)
338 class(batch_t), intent(inout) :: this
339
341
342 if (this%type() == type_float) then
343 call this%dallocate_packed_host()
344 else if (this%type() == type_cmplx) then
345 call this%zallocate_packed_host()
346 end if
347
349 end subroutine batch_allocate_packed_host
350
351 !--------------------------------------------------------------
355 !
356 subroutine batch_allocate_packed_device(this)
357 class(batch_t), intent(inout) :: this
358
360
361 call accel_create_buffer(this%ff_device, accel_mem_read_write, this%type(), &
362 product(this%pack_size))
363
365 end subroutine batch_allocate_packed_device
366
367 !--------------------------------------------------------------
374 subroutine batch_init_empty (this, dim, nst, np)
375 type(batch_t), intent(out) :: this
376 integer, intent(in) :: dim
377 integer, intent(in) :: nst
378 integer, intent(in) :: np
379
380 push_sub(batch_init_empty)
381
382 this%is_allocated = .false.
383 this%own_memory = .false.
384 this%special_memory = .false.
385 this%needs_finish_unpack = .false.
386 this%nst = nst
387 this%dim = dim
388 this%type_of = type_none
389
390 this%nst_linear = nst*dim
391
392 this%np = np
393 this%device_buffer_count = 0
394 this%host_buffer_count = 0
395 this%status_of = batch_not_packed
396 this%status_host = batch_not_packed
397
398 this%ndims = 2
399 safe_allocate(this%ist_idim_index(1:this%nst_linear, 1:this%ndims))
400 safe_allocate(this%ist(1:this%nst))
401
402 nullify(this%dff, this%zff, this%dff_linear, this%zff_linear)
403 nullify(this%dff_pack, this%zff_pack)
404
405 pop_sub(batch_init_empty)
406 end subroutine batch_init_empty
407
408 !--------------------------------------------------------------
414 subroutine batch_clone_to(this, dest, pack, copy_data, new_np, special, dest_type)
415 class(batch_t), intent(in) :: this
416 class(batch_t), allocatable, intent(out) :: dest
417 logical, optional, intent(in) :: pack
419 logical, optional, intent(in) :: copy_data
421 integer, optional, intent(in) :: new_np
422 logical, optional, intent(in) :: special
424 type(type_t), optional, intent(in) :: dest_type
425
426 push_sub(batch_clone_to)
427
428 if (.not. allocated(dest)) then
429 safe_allocate_type(batch_t, dest)
430 else
431 message(1) = "Internal error: destination batch in batch_clone_to has been previously allocated."
433 end if
434
435 call this%copy_to(dest, pack, copy_data, new_np, special, dest_type)
436
437 pop_sub(batch_clone_to)
438 end subroutine batch_clone_to
439
440 !--------------------------------------------------------------
441
442 subroutine batch_clone_to_array(this, dest, n_batches, pack, copy_data, new_np, special, dest_type)
443 class(batch_t), intent(in) :: this
444 class(batch_t), allocatable, intent(out) :: dest(:)
445 integer, intent(in) :: n_batches
446 logical, optional, intent(in) :: pack
448 logical, optional, intent(in) :: copy_data
450 integer, optional, intent(in) :: new_np
451 logical, optional, intent(in) :: special
453 type(type_t), optional, intent(in) :: dest_type
454
455 integer :: ib
456
457 push_sub(batch_clone_to_array)
458
459 if (.not. allocated(dest)) then
460 safe_allocate_type_array(batch_t, dest, (1:n_batches))
461 else
462 message(1) = "Internal error: destination batch in batch_clone_to_array has been previously allocated."
463 call messages_fatal(1)
464 end if
465
466 do ib = 1, n_batches
467 call this%copy_to(dest(ib), pack, copy_data, new_np, special, dest_type)
468 end do
470 pop_sub(batch_clone_to_array)
471 end subroutine batch_clone_to_array
472
473 !--------------------------------------------------------------
478 subroutine batch_copy_to(this, dest, pack, copy_data, new_np, special, dest_type)
479 class(batch_t), intent(in) :: this
480 class(batch_t), intent(out) :: dest
481 logical, optional, intent(in) :: pack
483 logical, optional, intent(in) :: copy_data
485 integer, optional, intent(in) :: new_np
486 logical, optional, intent(in) :: special
488 type(type_t), optional, intent(in) :: dest_type
489
490 logical :: host_packed, special_
491 integer :: np_
492 type(type_t) :: type_
493
494 push_sub(batch_copy_to)
495
496 np_ = optional_default(new_np, this%np)
497
498 host_packed = this%host_buffer_count > 0
499 ! use special memory here only for batches not on the GPU to avoid allocating
500 ! pinned memory for temporary batches because that leads to a severe performance
501 ! decrease for GPU runs (up to 20x)
502 if (present(special)) then
503 special_ = this%special_memory
504 else
505 special_ = this%special_memory .and. .not. this%device_buffer_count > 0
506 end if
507
508 if (present(dest_type)) then
509 type_ = dest_type
510 else
511 type_ = this%type()
512 end if
513
514 if (type_ == type_float) then
515 call dbatch_init(dest, this%dim, 1, this%nst, np_, packed=host_packed, special=special_)
516 else if (type_ == type_cmplx) then
517 call zbatch_init(dest, this%dim, 1, this%nst, np_, packed=host_packed, special=special_)
518 else
519 message(1) = "Internal error: unknown batch type in batch_copy_to."
520 call messages_fatal(1)
521 end if
522
523 if (this%status() /= dest%status() .and. optional_default(pack, this%is_packed())) call dest%do_pack(copy = .false.)
524
525 dest%ist_idim_index(1:this%nst_linear, 1:this%ndims) = this%ist_idim_index(1:this%nst_linear, 1:this%ndims)
526 dest%ist(1:this%nst) = this%ist(1:this%nst)
527
528 if (optional_default(copy_data, .false.)) then
529 assert(np_ == this%np)
530 call this%copy_data_to(min(this%np, np_), dest)
531 end if
532
533 pop_sub(batch_copy_to)
534 end subroutine batch_copy_to
535
536 ! ----------------------------------------------------
541 type(type_t) pure function batch_type(this) result(btype)
542 class(batch_t), intent(in) :: this
543
544 btype = this%type_of
545
546 end function batch_type
547
548 ! ----------------------------------------------------
550 integer pure function batch_type_as_integer(this) result(itype)
551 class(batch_t), intent(in) :: this
552
553 type(type_t) :: btype
554
555 itype = 0
556 btype = this%type()
557 if (btype == type_float) itype = 1
558 if (btype == type_cmplx) itype = 2
559
560 end function batch_type_as_integer
561
562 ! ----------------------------------------------------
567 integer pure function batch_status(this) result(bstatus)
568 class(batch_t), intent(in) :: this
569
570 bstatus = this%status_of
571 end function batch_status
572
573 ! ----------------------------------------------------
574
575 logical pure function batch_is_packed(this) result(in_buffer)
576 class(batch_t), intent(in) :: this
577
578 in_buffer = (this%device_buffer_count > 0) .or. (this%host_buffer_count > 0)
579 end function batch_is_packed
580
581 ! ----------------------------------------------------
582
583 integer(int64) function batch_pack_total_size(this) result(size)
584 class(batch_t), intent(inout) :: this
585
586 size = this%np
587 if (accel_is_enabled()) size = accel_padded_size(size)
588 size = size*pad_pow2(this%nst_linear)*types_get_size(this%type())
589
590 end function batch_pack_total_size
591
592 ! ----------------------------------------------------
593
599 subroutine batch_do_pack_generic(this, copy, async)
600 class(batch_t), intent(inout) :: this
601 logical, optional, intent(in) :: copy
602 logical, optional, intent(in) :: async
604
605 integer :: source, target
606
607 ! no push_sub, called too frequently
608
609 ! get source and target states for this batch
610 source = this%status()
611 select case (source)
613 if (accel_is_enabled()) then
614 target = batch_device_packed
615 else
616 target = batch_packed
617 end if
619 target = batch_device_packed
620 end select
621
622 call this%do_pack(target, copy, async)
623
624 end subroutine batch_do_pack_generic
625
630 subroutine batch_do_pack_target(this, target, copy, async, cpu_only)
631 class(batch_t), intent(inout) :: this
632 integer, intent(in) :: target
633 logical, optional, intent(in) :: copy
634 logical, optional, intent(in) :: async
636 logical, optional, intent(in) :: cpu_only
637
638 logical :: copy_
639 logical :: async_
640 integer :: source
641
642 ! no push_sub, called too frequently
643
644 call profiling_in("BATCH_DO_PACK")
646 copy_ = optional_default(copy, .true.)
647
648 async_ = optional_default(async, .false.)
649
650 ! get source state for this batch
651 source = this%status()
652
653 ! only do something if target is different from source
654 if (source /= target) then
655 select case (target)
657 call this%allocate_packed_device()
658 this%status_of = batch_device_packed ! Note that this%status_host remains untouched.
659
660 if (copy_) then
661 select case (source)
663 ! copy from unpacked host array to device
665 case (batch_packed)
666 ! copy from packed host array to device
667 call batch_write_packed_to_device(this, async_)
668 end select
669 end if
671 call this%allocate_packed_host()
672 this%status_of = batch_packed
673 this%status_host = batch_packed
674
675 if (copy_) then
676 if (this%type() == type_float) then
677 call dbatch_pack_copy(this)
678 else if (this%type() == type_cmplx) then
679 call zbatch_pack_copy(this)
680 end if
681 end if
682 if (this%own_memory) call this%deallocate_unpacked_host()
683 case (batch_not_packed)
684 call messages_not_implemented("Error: batch_do_pack called with BATCH_NOT_PACKED as target.")
685 end select
686 end if
687
688 select case (target)
690 this%device_buffer_count = this%device_buffer_count + 1
691 case (batch_packed)
692 this%host_buffer_count = this%host_buffer_count + 1
693 end select
695 call profiling_out("BATCH_DO_PACK")
696 end subroutine batch_do_pack_target
697
698
699 ! ----------------------------------------------------
704 subroutine batch_do_unpack(this, copy, force, async)
705 class(batch_t), intent(inout) :: this
706 logical, optional, intent(in) :: copy
707 logical, optional, intent(in) :: force
708 logical, optional, intent(in) :: async
710
711 logical :: copy_, force_, async_
712 integer :: source, target
713
714 push_sub(batch_do_unpack)
715
716 call profiling_in("BATCH_DO_UNPACK")
717
718 copy_ = optional_default(copy, .true.)
719
720 force_ = optional_default(force, .false.)
721
722 async_ = optional_default(async, .false.)
723
724 ! get source and target states for this batch
725 source = this%status()
726 select case (source)
727 case (batch_not_packed)
728 target = source
729 case (batch_packed)
730 target = batch_not_packed
732 target = this%status_host
733 end select
734
735 ! only do something if target is different from source
736 if (source /= target) then
737 select case (source)
738 case (batch_packed)
739 if (this%host_buffer_count == 1 .or. force_) then
740 if (this%own_memory) call this%allocate_unpacked_host()
741 ! unpack from packed_host to unpacked_host
742 if (copy_ .or. this%own_memory) then
743 if (this%type() == type_float) then
744 call dbatch_unpack_copy(this)
745 else if (this%type() == type_cmplx) then
746 call zbatch_unpack_copy(this)
747 end if
748 end if
749 call this%deallocate_packed_host()
750 this%status_host = target
751 this%status_of = target
752 this%host_buffer_count = 1
753 end if
754 this%host_buffer_count = this%host_buffer_count - 1
756 if (this%device_buffer_count == 1 .or. force_) then
757 if (copy_) then
758 select case (target)
759 ! unpack from packed_device to unpacked_host
760 case (batch_not_packed)
762 ! unpack from packed_device to packed_host
763 case (batch_packed)
764 call batch_read_device_to_packed(this, async_)
765 end select
766 end if
767 if (async_) then
768 this%needs_finish_unpack = .true.
769 else
770 call this%deallocate_packed_device()
771 end if
772 this%status_of = target
773 this%device_buffer_count = 1
774 end if
775 this%device_buffer_count = this%device_buffer_count - 1
776 end select
777 end if
778
779 call profiling_out("BATCH_DO_UNPACK")
780
781 pop_sub(batch_do_unpack)
782 end subroutine batch_do_unpack
783
784 ! ----------------------------------------------------
786 subroutine batch_finish_unpack(this)
787 class(batch_t), intent(inout) :: this
788
789 push_sub(batch_finish_unpack)
790 if (this%needs_finish_unpack) then
791 call accel_finish()
792 call this%deallocate_packed_device()
793 this%needs_finish_unpack = .false.
794 end if
795 pop_sub(batch_finish_unpack)
796 end subroutine batch_finish_unpack
797
798 ! ----------------------------------------------------
800 subroutine batch_write_unpacked_to_device(this)
801 class(batch_t), intent(inout) :: this
802
803 integer :: ist, ist2
804 integer(int64) :: unroll
805 type(accel_mem_t) :: tmp
806 type(accel_kernel_t), pointer :: kernel
807
809
810 call profiling_in("BATCH_WRT_UNPACK_ACCEL")
811 if (this%nst_linear == 1) then
812 ! we can copy directly
813 if (this%type() == type_float) then
814 call accel_write_buffer(this%ff_device, ubound(this%dff_linear, dim=1), this%dff_linear(:, 1))
815 else if (this%type() == type_cmplx) then
816 call accel_write_buffer(this%ff_device, ubound(this%zff_linear, dim=1), this%zff_linear(:, 1))
817 else
818 assert(.false.)
819 end if
820
821 else
822 ! we copy to a temporary array and then we re-arrange data
823
824 if (this%type() == type_float) then
825 kernel => dpack
826 else
827 kernel => zpack
828 end if
829
830 unroll = min(int(cl_pack_max_buffer_size, int64), this%pack_size(1))
831
832 call accel_create_buffer(tmp, accel_mem_read_only, this%type(), unroll*this%pack_size(2))
833
834 do ist = 1, this%nst_linear, int(unroll, int32)
835
836 ! copy a number 'unroll' of states to the buffer
837 do ist2 = ist, min(ist + int(unroll, int32) - 1, this%nst_linear)
838
839 if (this%type() == type_float) then
840 call accel_write_buffer(tmp, ubound(this%dff_linear, dim=1, kind=int64), this%dff_linear(:, ist2), &
841 offset = (ist2 - ist)*this%pack_size(2))
842 else
843 call accel_write_buffer(tmp, ubound(this%zff_linear, dim=1, kind=int64), this%zff_linear(:, ist2), &
844 offset = (ist2 - ist)*this%pack_size(2))
845 end if
846 end do
847
848 ! now call an opencl kernel to rearrange the data
849 call accel_set_kernel_arg(kernel, 0, int(this%pack_size(1), int32))
850 call accel_set_kernel_arg(kernel, 1, int(this%pack_size(2), int32))
851 call accel_set_kernel_arg(kernel, 2, ist - 1)
852 call accel_set_kernel_arg(kernel, 3, tmp)
853 call accel_set_kernel_arg(kernel, 4, this%ff_device)
854
855 call profiling_in("CL_PACK")
856 call accel_kernel_run(kernel, (/this%pack_size(2), unroll/), (/accel_max_workgroup_size()/unroll, unroll/))
857
858 if (this%type() == type_float) then
859 call profiling_count_transfers(unroll*this%pack_size(2), m_one)
860 else
861 call profiling_count_transfers(unroll*this%pack_size(2), m_zi)
862 end if
863
864 call accel_finish()
865 call profiling_out("CL_PACK")
866
867 end do
868
869 call accel_release_buffer(tmp)
870
871 end if
872
873 call profiling_out("BATCH_WRT_UNPACK_ACCEL")
875 end subroutine batch_write_unpacked_to_device
876
877 ! ------------------------------------------------------------------
878
879 subroutine batch_read_device_to_unpacked(this)
880 class(batch_t), intent(inout) :: this
882 integer :: ist, ist2
883 integer(int64) :: unroll
884 type(accel_mem_t) :: tmp
885 type(accel_kernel_t), pointer :: kernel
886
888 call profiling_in("BATCH_READ_UNPACKED_ACCEL")
889
890 if (this%nst_linear == 1) then
891 ! we can copy directly
892 if (this%type() == type_float) then
893 call accel_read_buffer(this%ff_device, ubound(this%dff_linear, dim=1), this%dff_linear(:, 1))
894 else
895 call accel_read_buffer(this%ff_device, ubound(this%zff_linear, dim=1), this%zff_linear(:, 1))
896 end if
897 else
898
899 unroll = min(int(cl_pack_max_buffer_size, int64), this%pack_size(1))
900
901 ! we use a kernel to move to a temporary array and then we read
902 call accel_create_buffer(tmp, accel_mem_write_only, this%type(), unroll*this%pack_size(2))
903
904 if (this%type() == type_float) then
905 kernel => dunpack
906 else
907 kernel => zunpack
908 end if
909
910 do ist = 1, this%nst_linear, int(unroll, int32)
911 call accel_set_kernel_arg(kernel, 0, int(this%pack_size(1), int32))
912 call accel_set_kernel_arg(kernel, 1, int(this%pack_size(2), int32))
913 call accel_set_kernel_arg(kernel, 2, ist - 1)
914 call accel_set_kernel_arg(kernel, 3, this%ff_device)
915 call accel_set_kernel_arg(kernel, 4, tmp)
916
917 call profiling_in("CL_UNPACK")
918 call accel_kernel_run(kernel, (/unroll, this%pack_size(2)/), (/unroll, accel_max_workgroup_size()/unroll/))
919
920 if (this%type() == type_float) then
921 call profiling_count_transfers(unroll*this%pack_size(2), m_one)
922 else
923 call profiling_count_transfers(unroll*this%pack_size(2), m_zi)
924 end if
925
926 call accel_finish()
927 call profiling_out("CL_UNPACK")
928
929 ! copy a number 'unroll' of states from the buffer
930 do ist2 = ist, min(ist + int(unroll, int32) - 1, this%nst_linear)
931
932 if (this%type() == type_float) then
933 call accel_read_buffer(tmp, ubound(this%dff_linear, dim=1, kind=int64), this%dff_linear(:, ist2), &
934 offset = (ist2 - ist)*this%pack_size(2))
935 else
936 call accel_read_buffer(tmp, ubound(this%zff_linear, dim=1, kind=int64), this%zff_linear(:, ist2), &
937 offset = (ist2 - ist)*this%pack_size(2))
938 end if
939 end do
940
941 end do
942
943 call accel_release_buffer(tmp)
944 end if
945
946 call profiling_out("BATCH_READ_UNPACKED_ACCEL")
948 end subroutine batch_read_device_to_unpacked
949
950 ! ------------------------------------------------------------------
951 subroutine batch_write_packed_to_device(this, async)
952 class(batch_t), intent(inout) :: this
953 logical, optional, intent(in) :: async
954
955
957
958 call profiling_in("BATCH_WRITE_PACKED_ACCEL")
959 if (this%type() == type_float) then
960 call accel_write_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%dff_pack, async=async)
961 else
962 call accel_write_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%zff_pack, async=async)
963 end if
964 call profiling_out("BATCH_WRITE_PACKED_ACCEL")
965
967 end subroutine batch_write_packed_to_device
968
969 ! ------------------------------------------------------------------
970 subroutine batch_read_device_to_packed(this, async)
971 class(batch_t), intent(inout) :: this
972 logical, optional, intent(in) :: async
973
976
977 call profiling_in("BATCH_READ_PACKED_ACCEL")
978 if (this%type() == type_float) then
979 call accel_read_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%dff_pack, async=async)
980 else
981 call accel_read_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%zff_pack, async=async)
982 end if
983 call profiling_out("BATCH_READ_PACKED_ACCEL")
984
986 end subroutine batch_read_device_to_packed
987
988 ! ------------------------------------------------------
993 integer function batch_inv_index(this, cind) result(index)
994 class(batch_t), intent(in) :: this
995 integer, intent(in) :: cind(:)
996
997 do index = 1, this%nst_linear
998 if (all(cind(1:this%ndims) == this%ist_idim_index(index, 1:this%ndims))) exit
999 end do
1000
1001 assert(index <= this%nst_linear)
1002
1003 end function batch_inv_index
1004
1005 ! ------------------------------------------------------
1009 !
1010 integer pure function batch_ist_idim_to_linear(this, cind) result(index)
1011 class(batch_t), intent(in) :: this
1012 integer, intent(in) :: cind(:)
1013
1014 if (ubound(cind, dim = 1) == 1) then
1015 index = cind(1)
1016 else
1017 index = (cind(1) - 1)*this%dim + cind(2)
1018 end if
1019
1020 end function batch_ist_idim_to_linear
1021
1022 ! ------------------------------------------------------
1027 !
1028 integer pure function batch_linear_to_ist(this, linear_index) result(ist)
1029 class(batch_t), intent(in) :: this
1030 integer, intent(in) :: linear_index
1031
1032 ist = this%ist_idim_index(linear_index, 1)
1033
1034 end function batch_linear_to_ist
1035
1036 ! ------------------------------------------------------
1038 !
1039 integer pure function batch_linear_to_idim(this, linear_index) result(idim)
1040 class(batch_t), intent(in) :: this
1041 integer, intent(in) :: linear_index
1042
1043 idim = this%ist_idim_index(linear_index, 2)
1044
1045 end function batch_linear_to_idim
1047 ! ------------------------------------------------------
1056 !
1057 subroutine batch_remote_access_start(this, mpi_grp, rma_win)
1058 class(batch_t), intent(inout) :: this
1059 type(mpi_grp_t), intent(in) :: mpi_grp
1060 type(mpi_win), intent(out) :: rma_win
1061
1063
1064 if (mpi_grp%size > 1) then
1066 assert(.not. accel_is_enabled())
1067
1068 call this%do_pack()
1069
1070 if (this%type() == type_cmplx) then
1071#ifdef HAVE_MPI
1072 call mpi_win_create(this%zff_pack(1, 1), int(product(this%pack_size)*types_get_size(this%type()), mpi_address_kind), &
1073 types_get_size(this%type()), mpi_info_null, mpi_grp%comm, rma_win)
1074#endif
1075 else if (this%type() == type_float) then
1076#ifdef HAVE_MPI
1077 call mpi_win_create(this%dff_pack(1, 1), int(product(this%pack_size)*types_get_size(this%type()), mpi_address_kind), &
1078 types_get_size(this%type()), mpi_info_null, mpi_grp%comm, rma_win)
1079#endif
1080 else
1081 message(1) = "Internal error: unknown batch type in batch_remote_access_start."
1082 call messages_fatal(1)
1083 end if
1084
1085 else
1086 rma_win = mpi_win_null
1087 end if
1090 end subroutine batch_remote_access_start
1091
1092 ! ------------------------------------------------------
1098 !
1099 subroutine batch_remote_access_stop(this, rma_win)
1100 class(batch_t), intent(inout) :: this
1101 type(mpi_win), intent(inout) :: rma_win
1102
1103 push_sub(batch_remote_access_stop)
1104
1105 if (rma_win /= mpi_win_null) then
1106#ifdef HAVE_MPI
1107 call mpi_win_free(rma_win)
1108#endif
1109 call this%do_unpack()
1110 end if
1111
1113 end subroutine batch_remote_access_stop
1114
1115 ! --------------------------------------------------------------
1117 !
1118 subroutine batch_copy_data_to(this, np, dest, async)
1119 class(batch_t), intent(in) :: this
1120 integer, intent(in) :: np
1121 class(batch_t), intent(inout) :: dest
1122 logical, optional, intent(in) :: async
1124 integer(int64) :: localsize, dim2, dim3
1125 integer :: ist, ip
1126
1127 push_sub(batch_copy_data_to)
1128 call profiling_in("BATCH_COPY_DATA_TO")
1129
1130 ! this routine can be used to copy data between batches of different type
1131 call this%check_compatibility_with(dest, type_check=.false.)
1132
1133 if (this%type() == dest%type()) then
1134 select case (this%status())
1135 case (batch_device_packed)
1136 call accel_set_kernel_arg(kernel_copy, 0, np)
1137 call accel_set_kernel_arg(kernel_copy, 1, this%ff_device)
1138 call accel_set_kernel_arg(kernel_copy, 2, log2(int(this%pack_size_real(1), int32)))
1139 call accel_set_kernel_arg(kernel_copy, 3, dest%ff_device)
1140 call accel_set_kernel_arg(kernel_copy, 4, log2(int(dest%pack_size_real(1), int32)))
1141
1142 localsize = accel_kernel_workgroup_size(kernel_copy)/dest%pack_size_real(1)
1143
1144 dim3 = np/(accel_max_size_per_dim(2)*localsize) + 1
1145 dim2 = min(accel_max_size_per_dim(2)*localsize, pad(int(np, int64), localsize))
1146
1147 call accel_kernel_run(kernel_copy, (/dest%pack_size_real(1), dim2, dim3/), (/dest%pack_size_real(1), localsize, 1_int64/))
1148
1149 if(.not. optional_default(async, .false.)) call accel_finish()
1150
1151 case (batch_packed)
1152 if (np*this%pack_size(1) > huge(0_int32)) then
1153 ! BLAS cannot handle 8-byte integers, so we need a special version here
1154 do ip = 1, np
1155 if (dest%type() == type_float) then
1156 call blas_copy(int(this%pack_size(1), int32), this%dff_pack(1, ip), 1, dest%dff_pack(1, ip), 1)
1157 else
1158 call blas_copy(int(this%pack_size(1), int32), this%zff_pack(1, ip), 1, dest%zff_pack(1, ip), 1)
1159 end if
1160 end do
1161 else
1162 if (dest%type() == type_float) then
1163 call blas_copy(int(this%pack_size(1)*np, int32), this%dff_pack(1, 1), 1, dest%dff_pack(1, 1), 1)
1164 else
1165 call blas_copy(int(this%pack_size(1)*np, int32), this%zff_pack(1, 1), 1, dest%zff_pack(1, 1), 1)
1166 end if
1167 end if
1168
1169 case (batch_not_packed)
1170 do ist = 1, dest%nst_linear
1171 if (dest%type() == type_cmplx) then
1172 call blas_copy(np, this%zff_linear(1, ist), 1, dest%zff_linear(1, ist), 1)
1173 else
1174 call blas_copy(np, this%dff_linear(1, ist), 1, dest%dff_linear(1, ist), 1)
1175 end if
1176 end do
1177
1178 end select
1179 else if (this%type() == type_cmplx) then
1180 ! copy complex -> real
1181 select case (this%status())
1182 case (batch_device_packed)
1183 call accel_set_kernel_arg(kernel_copy_complex_to_real, 0, np)
1184 call accel_set_kernel_arg(kernel_copy_complex_to_real, 1, this%ff_device)
1185 call accel_set_kernel_arg(kernel_copy_complex_to_real, 2, log2(int(this%pack_size_real(1), int32)))
1186 call accel_set_kernel_arg(kernel_copy_complex_to_real, 3, dest%ff_device)
1187 call accel_set_kernel_arg(kernel_copy_complex_to_real, 4, log2(int(dest%pack_size_real(1), int32)))
1188
1189 localsize = accel_kernel_workgroup_size(kernel_copy_complex_to_real)/dest%pack_size_real(1)
1190
1191 dim3 = np/(accel_max_size_per_dim(2)*localsize) + 1
1192 dim2 = min(accel_max_size_per_dim(2)*localsize, pad(int(np, int64), localsize))
1193
1194 call accel_kernel_run(kernel_copy_complex_to_real, &
1195 (/dest%pack_size_real(1), dim2, dim3/), (/dest%pack_size_real(1), localsize, 1_int64/))
1196
1197 if(.not. optional_default(async, .false.)) call accel_finish()
1198
1199 case (batch_packed)
1200 !$omp parallel do private(ist, ip)
1201 do ip = 1, np
1202 !$omp simd
1203 do ist = 1, dest%nst_linear
1204 dest%dff_pack(ist, ip) = real(this%zff_pack(ist, ip), real64)
1205 end do
1206 end do
1207 !$omp end parallel do
1208 case (batch_not_packed)
1209 !$omp parallel private(ist, ip)
1210 do ist = 1, dest%nst_linear
1211 !$omp do
1212 do ip = 1, np
1213 dest%dff_linear(ip, ist) = real(this%zff_linear(ip, ist), real64)
1214 end do
1215 !$omp end do nowait
1216 end do
1217 !$omp end parallel
1218 end select
1219 else if (this%type() == type_float) then
1220 ! copy real -> complex
1221 select case (this%status())
1222 case (batch_device_packed)
1223 call accel_set_kernel_arg(kernel_copy_real_to_complex, 0, np)
1224 call accel_set_kernel_arg(kernel_copy_real_to_complex, 1, this%ff_device)
1225 call accel_set_kernel_arg(kernel_copy_real_to_complex, 2, log2(int(this%pack_size_real(1), int32)))
1226 call accel_set_kernel_arg(kernel_copy_real_to_complex, 3, dest%ff_device)
1227 call accel_set_kernel_arg(kernel_copy_real_to_complex, 4, log2(int(dest%pack_size_real(1), int32)))
1228
1229 localsize = accel_kernel_workgroup_size(kernel_copy_real_to_complex)/this%pack_size_real(1)
1230
1231 dim3 = np/(accel_max_size_per_dim(2)*localsize) + 1
1232 dim2 = min(accel_max_size_per_dim(2)*localsize, pad(int(np, int64), localsize))
1233
1234 call accel_kernel_run(kernel_copy_real_to_complex, &
1235 (/this%pack_size_real(1), dim2, dim3/), (/this%pack_size_real(1), localsize, 1_int64/))
1236
1237 if(.not. optional_default(async, .false.)) call accel_finish()
1238
1239 case (batch_packed)
1240 !$omp parallel do private(ist, ip)
1241 do ip = 1, np
1242 !$omp simd
1243 do ist = 1, dest%nst_linear
1244 dest%zff_pack(ist, ip) = cmplx(this%dff_pack(ist, ip), m_zero, real64)
1245 end do
1246 end do
1247 !$omp end parallel do
1248 case (batch_not_packed)
1249 !$omp parallel private(ist, ip)
1250 do ist = 1, dest%nst_linear
1251 !$omp do
1252 do ip = 1, np
1253 dest%zff_linear(ip, ist) = cmplx(this%dff_linear(ip, ist), m_zero, real64)
1254 end do
1255 !$omp end do nowait
1256 end do
1257 !$omp end parallel
1258 end select
1259 else
1260 message(1) = "Error! This should not happen."
1261 call messages_fatal(1)
1262 end if
1263
1264 call profiling_out("BATCH_COPY_DATA_TO")
1265 pop_sub(batch_copy_data_to)
1266 end subroutine batch_copy_data_to
1267
1268 ! --------------------------------------------------------------
1270 !
1271 subroutine batch_check_compatibility_with(this, target, only_check_dim, type_check)
1272 class(batch_t), intent(in) :: this
1273 class(batch_t), intent(in) :: target
1274 logical, optional, intent(in) :: only_check_dim
1275 logical, optional, intent(in) :: type_check
1276
1278
1279 if (optional_default(type_check, .true.)) then
1280 assert(this%type() == target%type())
1281 end if
1282 if (.not. optional_default(only_check_dim, .false.)) then
1283 assert(this%nst_linear == target%nst_linear)
1284 end if
1285 assert(this%status() == target%status())
1286 assert(this%dim == target%dim)
1287
1289
1290 end subroutine batch_check_compatibility_with
1291
1292!--------------------------------------------------------------
1295 subroutine batch_build_indices(this, st_start, st_end)
1296 class(batch_t), intent(inout) :: this
1297 integer, intent(in) :: st_start
1298 integer, intent(in) :: st_end
1299
1300 integer :: idim, ii, ist
1301
1302 push_sub(batch_build_indices)
1303
1304 do ist = st_start, st_end
1305 ! now we also populate the linear array
1306 do idim = 1, this%dim
1307 ii = this%dim*(ist - st_start) + idim
1308 this%ist_idim_index(ii, 1) = ist
1309 this%ist_idim_index(ii, 2) = idim
1310 end do
1311 this%ist(ist - st_start + 1) = ist
1312 end do
1313
1314 ! compute packed sizes
1315 this%pack_size(1) = pad_pow2(this%nst_linear)
1316 this%pack_size(2) = this%np
1317 if (accel_is_enabled()) this%pack_size(2) = accel_padded_size(this%pack_size(2))
1318
1319 this%pack_size_real = this%pack_size
1320 if (type_is_complex(this%type())) this%pack_size_real(1) = 2*this%pack_size_real(1)
1321
1322 pop_sub(batch_build_indices)
1323 end subroutine batch_build_indices
1324
1325
1326#include "real.F90"
1327#include "batch_inc.F90"
1328#include "undef.F90"
1329
1330#include "complex.F90"
1331#include "batch_inc.F90"
1332#include "undef.F90"
1333
1334end module batch_oct_m
1335
1336!! Local Variables:
1337!! mode: f90
1338!! coding: utf-8
1339!! End:
initialize a batch with existing memory
Definition: batch.F90:277
double log2(double __x) __attribute__((__nothrow__
integer, parameter, public accel_mem_read_write
Definition: accel.F90:195
subroutine, public accel_release_buffer(this, async)
Definition: accel.F90:918
This module contains interfaces for routines in allocate_hardware_aware.c.
subroutine, public deallocate_hardware_aware(array, size)
This module implements batches of mesh functions.
Definition: batch.F90:135
type(type_t) pure function batch_type(this)
return the type of a batch
Definition: batch.F90:637
subroutine zbatch_pack_copy(this)
copy data from the unpacked to the packed arrays
Definition: batch.F90:1954
integer, parameter, public batch_not_packed
functions are stored in CPU memory, unpacked order
Definition: batch.F90:286
integer, parameter, public batch_device_packed
functions are stored in device memory in packed order
Definition: batch.F90:286
subroutine zbatch_init_with_memory_3(this, dim, st_start, st_end, psi)
initialize a batch with an rank-3 array of TYPE_CMPLX valued mesh functions psi.
Definition: batch.F90:1778
subroutine batch_check_compatibility_with(this, target, only_check_dim, type_check)
check whether two batches have compatible dimensions (and type)
Definition: batch.F90:1367
integer, parameter cl_pack_max_buffer_size
this value controls the size (in number of wave-functions) of the buffer used to copy states to the o...
Definition: batch.F90:291
logical pure function batch_is_packed(this)
Definition: batch.F90:671
subroutine dbatch_unpack_copy(this)
copy data from the packed to the unpacked arrays
Definition: batch.F90:1679
subroutine dbatch_init_with_memory_1(this, psi)
initialize a batch with an rank-1 array of TYPE_FLOAT valued mesh functions psi.
Definition: batch.F90:1539
subroutine batch_write_unpacked_to_device(this)
Definition: batch.F90:896
subroutine batch_do_unpack(this, copy, force, async)
unpack a batch
Definition: batch.F90:800
subroutine batch_finish_unpack(this)
finish the unpacking if do_unpack() was called with async=.true.
Definition: batch.F90:882
subroutine zbatch_allocate_unpacked_host(this)
allocate host (CPU) memory for unpacked data of type TYPE_CMPLX
Definition: batch.F90:1865
subroutine batch_deallocate_packed_device(this)
release packed device memory
Definition: batch.F90:399
integer pure function batch_type_as_integer(this)
For debuging purpose only.
Definition: batch.F90:646
subroutine batch_do_pack_generic(this, copy, async)
pack the data in a batch
Definition: batch.F90:695
integer function batch_inv_index(this, cind)
inverse index lookup
Definition: batch.F90:1089
subroutine dbatch_init_with_memory_2(this, dim, st_start, st_end, psi)
initialize a batch with an rank-2 array of TYPE_FLOAT valued mesh functions psi.
Definition: batch.F90:1510
subroutine batch_allocate_packed_host(this)
allocate host (CPU) memory for packed data
Definition: batch.F90:433
subroutine, public zbatch_init(this, dim, st_start, st_end, np, special, packed)
initialize a TYPE_CMPLX valued batch to given size without providing external memory
Definition: batch.F90:1915
subroutine zbatch_allocate_packed_host(this)
allocate host (CPU) memory for packed data of type TYPE_CMPLX
Definition: batch.F90:1891
subroutine batch_clone_to(this, dest, pack, copy_data, new_np, special, dest_type)
clone a batch to a new batch
Definition: batch.F90:510
subroutine batch_remote_access_stop(this, rma_win)
stop the remote access to the batch
Definition: batch.F90:1195
subroutine batch_read_device_to_unpacked(this)
Definition: batch.F90:975
subroutine zbatch_init_with_memory_1(this, psi)
initialize a batch with an rank-1 array of TYPE_CMPLX valued mesh functions psi.
Definition: batch.F90:1844
subroutine dbatch_allocate_packed_host(this)
allocate host (CPU) memory for packed data of type TYPE_FLOAT
Definition: batch.F90:1586
subroutine batch_clone_to_array(this, dest, n_batches, pack, copy_data, new_np, special, dest_type)
Definition: batch.F90:538
subroutine batch_allocate_packed_device(this)
allocate device (GPU) memory for packed data
Definition: batch.F90:452
subroutine batch_build_indices(this, st_start, st_end)
build the index ist(:) and ist_idim_index(:,:) and set pack_size
Definition: batch.F90:1391
integer pure function batch_ist_idim_to_linear(this, cind)
direct index lookup
Definition: batch.F90:1106
subroutine batch_do_pack_target(this, target, copy, async, cpu_only)
pack the data in a batch
Definition: batch.F90:726
integer pure function batch_linear_to_ist(this, linear_index)
get state index ist from linear (combined dim and nst) index
Definition: batch.F90:1124
subroutine batch_copy_to(this, dest, pack, copy_data, new_np, special, dest_type)
make a copy of a batch
Definition: batch.F90:574
subroutine, public batch_read_device_to_packed(this, async)
Definition: batch.F90:1066
subroutine batch_write_packed_to_device(this, async)
Definition: batch.F90:1047
subroutine dbatch_init_with_memory_3(this, dim, st_start, st_end, psi)
initialize a batch with an rank-3 array of TYPE_FLOAT valued mesh functions psi.
Definition: batch.F90:1473
subroutine batch_allocate_unpacked_host(this)
allocate host (CPU) memory for unpacked data
Definition: batch.F90:414
subroutine batch_init_empty(this, dim, nst, np)
initialize an empty batch
Definition: batch.F90:470
subroutine, public dbatch_init(this, dim, st_start, st_end, np, special, packed)
initialize a TYPE_FLOAT valued batch to given size without providing external memory
Definition: batch.F90:1610
subroutine zbatch_init_with_memory_2(this, dim, st_start, st_end, psi)
initialize a batch with an rank-2 array of TYPE_CMPLX valued mesh functions psi.
Definition: batch.F90:1815
integer pure function batch_linear_to_idim(this, linear_index)
extract idim from linear index
Definition: batch.F90:1135
subroutine batch_remote_access_start(this, mpi_grp, rma_win)
start remote access to a batch on another node
Definition: batch.F90:1153
subroutine batch_copy_data_to(this, np, dest, async)
copy data to another batch.
Definition: batch.F90:1214
subroutine dbatch_allocate_unpacked_host(this)
allocate host (CPU) memory for unpacked data of type TYPE_FLOAT
Definition: batch.F90:1560
subroutine dbatch_pack_copy(this)
copy data from the unpacked to the packed arrays
Definition: batch.F90:1649
integer pure function batch_status(this)
return the status of a batch
Definition: batch.F90:663
subroutine batch_deallocate_unpacked_host(this)
release unpacked host memory
Definition: batch.F90:343
integer, parameter, public batch_packed
functions are stored in CPU memory, in transposed (packed) order
Definition: batch.F90:286
subroutine batch_deallocate_packed_host(this)
release packed host memory
Definition: batch.F90:374
integer(int64) function batch_pack_total_size(this)
Definition: batch.F90:679
subroutine batch_end(this, copy)
finalize a batch and release allocated memory, if necessary
Definition: batch.F90:305
subroutine zbatch_unpack_copy(this)
copy data from the packed to the unpacked arrays
Definition: batch.F90:1984
This module contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:120
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:416
type(type_t), public type_float
Definition: types.F90:135
type(type_t), public type_cmplx
Definition: types.F90:136
type(type_t), public type_none
Definition: types.F90:134
Class defining batches of mesh functions.
Definition: batch.F90:161
int true(void)