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 :: gpu_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_free_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, bsize, gsize
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(gpu_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 a 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, this%np)
851 call accel_set_kernel_arg(kernel, 2, this%nst_linear)
852 call accel_set_kernel_arg(kernel, 3, ist - 1)
853 call accel_set_kernel_arg(kernel, 4, tmp)
854 call accel_set_kernel_arg(kernel, 5, this%ff_device)
855
856 call profiling_in("GPU_PACK")
857
858 ! Compute the grid size
859 bsize = accel_max_block_size()/unroll
860 call accel_grid_size(this%pack_size(2), bsize, gsize)
861
862 call accel_kernel_run(kernel, (/gsize, 1_int64/), (/bsize, unroll/))
863
864 if (this%type() == type_float) then
865 call profiling_count_transfers(unroll*this%pack_size(2), m_one)
866 else
867 call profiling_count_transfers(unroll*this%pack_size(2), m_zi)
868 end if
869
870 call accel_finish()
871 call profiling_out("GPU_PACK")
872
873 end do
874
875 call accel_free_buffer(tmp)
876
877 end if
878
879 call profiling_out("BATCH_WRT_UNPACK_ACCEL")
882
883 ! ------------------------------------------------------------------
884
885 subroutine batch_read_device_to_unpacked(this)
886 class(batch_t), intent(inout) :: this
887
888 integer :: ist, ist2
889 integer(int64) :: unroll, bsize, gsize
890 type(accel_mem_t) :: tmp
891 type(accel_kernel_t), pointer :: kernel
892
894 call profiling_in("BATCH_READ_UNPACKED_ACCEL")
896 if (this%nst_linear == 1) then
897 ! we can copy directly
898 if (this%type() == type_float) then
899 call accel_read_buffer(this%ff_device, ubound(this%dff_linear, dim=1), this%dff_linear(:, 1))
900 else
901 call accel_read_buffer(this%ff_device, ubound(this%zff_linear, dim=1), this%zff_linear(:, 1))
902 end if
903 else
904
905 unroll = min(int(gpu_pack_max_buffer_size, int64), this%pack_size(1))
906
907 ! we use a kernel to move to a temporary array and then we read
908 call accel_create_buffer(tmp, accel_mem_write_only, this%type(), unroll*this%pack_size(2))
909
910 if (this%type() == type_float) then
911 kernel => dunpack
912 else
913 kernel => zunpack
914 end if
915
916 do ist = 1, this%nst_linear, int(unroll, int32)
917 call accel_set_kernel_arg(kernel, 0, int(this%pack_size(1), int32))
918 call accel_set_kernel_arg(kernel, 1, this%np)
919 call accel_set_kernel_arg(kernel, 2, this%nst_linear)
920 call accel_set_kernel_arg(kernel, 3, ist - 1)
921 call accel_set_kernel_arg(kernel, 4, this%ff_device)
922 call accel_set_kernel_arg(kernel, 5, tmp)
923
924 call profiling_in("GPU_UNPACK")
925
926 ! Compute the grid size
927 bsize = accel_max_block_size()/unroll
928 call accel_grid_size(this%pack_size(2), bsize, gsize)
929
930 call accel_kernel_run(kernel, (/1_int64, gsize/), (/unroll, bsize/))
931
932 if (this%type() == type_float) then
933 call profiling_count_transfers(unroll*this%pack_size(2), m_one)
934 else
935 call profiling_count_transfers(unroll*this%pack_size(2), m_zi)
936 end if
937
938 call accel_finish()
939 call profiling_out("GPU_UNPACK")
940
941 ! copy a number 'unroll' of states from the buffer
942 do ist2 = ist, min(ist + int(unroll, int32) - 1, this%nst_linear)
943
944 if (this%type() == type_float) then
945 call accel_read_buffer(tmp, ubound(this%dff_linear, dim=1, kind=int64), this%dff_linear(:, ist2), &
946 offset = (ist2 - ist)*this%pack_size(2))
947 else
948 call accel_read_buffer(tmp, ubound(this%zff_linear, dim=1, kind=int64), this%zff_linear(:, ist2), &
949 offset = (ist2 - ist)*this%pack_size(2))
950 end if
951 end do
952
953 end do
954
955 call accel_free_buffer(tmp)
956 end if
957
958 call profiling_out("BATCH_READ_UNPACKED_ACCEL")
960 end subroutine batch_read_device_to_unpacked
961
962 ! ------------------------------------------------------------------
963 subroutine batch_write_packed_to_device(this, async)
964 class(batch_t), intent(inout) :: this
965 logical, optional, intent(in) :: async
966
967
969
970 call profiling_in("BATCH_WRITE_PACKED_ACCEL")
971 if (this%type() == type_float) then
972 call accel_write_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%dff_pack, async=async)
973 else
974 call accel_write_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%zff_pack, async=async)
975 end if
976 call profiling_out("BATCH_WRITE_PACKED_ACCEL")
977
979 end subroutine batch_write_packed_to_device
981 ! ------------------------------------------------------------------
982 subroutine batch_read_device_to_packed(this, async)
983 class(batch_t), intent(inout) :: this
984 logical, optional, intent(in) :: async
985
986
988
989 call profiling_in("BATCH_READ_PACKED_ACCEL")
990 if (this%type() == type_float) then
991 call accel_read_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%dff_pack, async=async)
992 else
993 call accel_read_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%zff_pack, async=async)
994 end if
995 call profiling_out("BATCH_READ_PACKED_ACCEL")
996
998 end subroutine batch_read_device_to_packed
999
1000 ! ------------------------------------------------------
1005 integer function batch_inv_index(this, cind) result(index)
1006 class(batch_t), intent(in) :: this
1007 integer, intent(in) :: cind(:)
1008
1009 do index = 1, this%nst_linear
1010 if (all(cind(1:this%ndims) == this%ist_idim_index(index, 1:this%ndims))) exit
1011 end do
1012
1013 assert(index <= this%nst_linear)
1014
1015 end function batch_inv_index
1016
1017 ! ------------------------------------------------------
1021 !
1022 integer pure function batch_ist_idim_to_linear(this, cind) result(index)
1023 class(batch_t), intent(in) :: this
1024 integer, intent(in) :: cind(:)
1025
1026 if (ubound(cind, dim = 1) == 1) then
1027 index = cind(1)
1028 else
1029 index = (cind(1) - 1)*this%dim + cind(2)
1030 end if
1031
1032 end function batch_ist_idim_to_linear
1033
1034 ! ------------------------------------------------------
1039 !
1040 integer pure function batch_linear_to_ist(this, linear_index) result(ist)
1041 class(batch_t), intent(in) :: this
1042 integer, intent(in) :: linear_index
1043
1044 ist = this%ist_idim_index(linear_index, 1)
1045
1046 end function batch_linear_to_ist
1047
1048 ! ------------------------------------------------------
1050 !
1051 integer pure function batch_linear_to_idim(this, linear_index) result(idim)
1052 class(batch_t), intent(in) :: this
1053 integer, intent(in) :: linear_index
1054
1055 idim = this%ist_idim_index(linear_index, 2)
1056
1057 end function batch_linear_to_idim
1059 ! ------------------------------------------------------
1068 !
1069 subroutine batch_remote_access_start(this, mpi_grp, rma_win)
1070 class(batch_t), intent(inout) :: this
1071 type(mpi_grp_t), intent(in) :: mpi_grp
1072 type(mpi_win), intent(out) :: rma_win
1073
1075
1076 if (mpi_grp%size > 1) then
1078 assert(.not. accel_is_enabled())
1079
1080 call this%do_pack()
1081
1082 if (this%type() == type_cmplx) then
1083#ifdef HAVE_MPI
1084 call mpi_win_create(this%zff_pack(1, 1), int(product(this%pack_size)*types_get_size(this%type()), mpi_address_kind), &
1085 types_get_size(this%type()), mpi_info_null, mpi_grp%comm, rma_win)
1086#endif
1087 else if (this%type() == type_float) then
1088#ifdef HAVE_MPI
1089 call mpi_win_create(this%dff_pack(1, 1), int(product(this%pack_size)*types_get_size(this%type()), mpi_address_kind), &
1090 types_get_size(this%type()), mpi_info_null, mpi_grp%comm, rma_win)
1091#endif
1092 else
1093 message(1) = "Internal error: unknown batch type in batch_remote_access_start."
1094 call messages_fatal(1)
1095 end if
1096
1097 else
1098 rma_win = mpi_win_null
1099 end if
1102 end subroutine batch_remote_access_start
1103
1104 ! ------------------------------------------------------
1110 !
1111 subroutine batch_remote_access_stop(this, rma_win)
1112 class(batch_t), intent(inout) :: this
1113 type(mpi_win), intent(inout) :: rma_win
1114
1115 push_sub(batch_remote_access_stop)
1116
1117 if (rma_win /= mpi_win_null) then
1118#ifdef HAVE_MPI
1119 call mpi_win_free(rma_win)
1120#endif
1121 call this%do_unpack()
1122 end if
1123
1125 end subroutine batch_remote_access_stop
1126
1127 ! --------------------------------------------------------------
1129 !
1130 subroutine batch_copy_data_to(this, np, dest, async)
1131 class(batch_t), intent(in) :: this
1132 integer, intent(in) :: np
1133 class(batch_t), intent(inout) :: dest
1134 logical, optional, intent(in) :: async
1136 integer(int64), dimension(3) :: gsizes, bsizes
1137 integer :: ist, ip
1138
1139 push_sub(batch_copy_data_to)
1140 call profiling_in("BATCH_COPY_DATA_TO")
1141
1142 ! this routine can be used to copy data between batches of different type
1143 call this%check_compatibility_with(dest, type_check=.false.)
1144
1145 if (this%type() == dest%type()) then
1146 select case (this%status())
1147 case (batch_device_packed)
1148 call accel_set_kernel_arg(kernel_copy, 0, np)
1149 call accel_set_kernel_arg(kernel_copy, 1, this%ff_device)
1150 call accel_set_kernel_arg(kernel_copy, 2, log2(int(this%pack_size_real(1), int32)))
1151 call accel_set_kernel_arg(kernel_copy, 3, dest%ff_device)
1152 call accel_set_kernel_arg(kernel_copy, 4, log2(int(dest%pack_size_real(1), int32)))
1153
1154 ! Compute the grid (extend to another dimensions if the size of the problem is too big)
1155 call accel_grid_size_extend_dim(int(np, int64), dest%pack_size_real(1), gsizes, bsizes, kernel_copy)
1156
1157 call accel_kernel_run(kernel_copy, gsizes, bsizes)
1158
1159 if(.not. optional_default(async, .false.)) call accel_finish()
1160
1161 case (batch_packed)
1162 if (np*this%pack_size(1) > huge(0_int32)) then
1163 ! BLAS cannot handle 8-byte integers, so we need a special version here
1164 do ip = 1, np
1165 if (dest%type() == type_float) then
1166 call blas_copy(int(this%pack_size(1), int32), this%dff_pack(1, ip), 1, dest%dff_pack(1, ip), 1)
1167 else
1168 call blas_copy(int(this%pack_size(1), int32), this%zff_pack(1, ip), 1, dest%zff_pack(1, ip), 1)
1169 end if
1170 end do
1171 else
1172 if (dest%type() == type_float) then
1173 call blas_copy(int(this%pack_size(1)*np, int32), this%dff_pack(1, 1), 1, dest%dff_pack(1, 1), 1)
1174 else
1175 call blas_copy(int(this%pack_size(1)*np, int32), this%zff_pack(1, 1), 1, dest%zff_pack(1, 1), 1)
1176 end if
1177 end if
1178
1179 case (batch_not_packed)
1180 do ist = 1, dest%nst_linear
1181 if (dest%type() == type_cmplx) then
1182 call blas_copy(np, this%zff_linear(1, ist), 1, dest%zff_linear(1, ist), 1)
1183 else
1184 call blas_copy(np, this%dff_linear(1, ist), 1, dest%dff_linear(1, ist), 1)
1185 end if
1186 end do
1187
1188 end select
1189 else if (this%type() == type_cmplx) then
1190 ! copy complex -> real
1191 select case (this%status())
1192 case (batch_device_packed)
1193 call accel_set_kernel_arg(kernel_copy_complex_to_real, 0, np)
1194 call accel_set_kernel_arg(kernel_copy_complex_to_real, 1, this%ff_device)
1195 call accel_set_kernel_arg(kernel_copy_complex_to_real, 2, log2(int(this%pack_size_real(1), int32)))
1196 call accel_set_kernel_arg(kernel_copy_complex_to_real, 3, dest%ff_device)
1197 call accel_set_kernel_arg(kernel_copy_complex_to_real, 4, log2(int(dest%pack_size_real(1), int32)))
1198
1199 ! Compute the grid (extend to another dimensions if the size of the problem is too big)
1200 call accel_grid_size_extend_dim(int(np, int64), dest%pack_size_real(1), gsizes, bsizes, kernel_copy_complex_to_real)
1201
1202 call accel_kernel_run(kernel_copy_complex_to_real, gsizes, bsizes)
1203
1204 if(.not. optional_default(async, .false.)) call accel_finish()
1205
1207 !$omp parallel do private(ist, ip)
1208 do ip = 1, np
1209 !$omp simd
1210 do ist = 1, dest%nst_linear
1211 dest%dff_pack(ist, ip) = real(this%zff_pack(ist, ip), real64)
1212 end do
1213 end do
1214 !$omp end parallel do
1215 case (batch_not_packed)
1216 !$omp parallel private(ist, ip)
1217 do ist = 1, dest%nst_linear
1218 !$omp do
1219 do ip = 1, np
1220 dest%dff_linear(ip, ist) = real(this%zff_linear(ip, ist), real64)
1221 end do
1222 !$omp end do nowait
1223 end do
1224 !$omp end parallel
1225 end select
1226 else if (this%type() == type_float) then
1227 ! copy real -> complex
1228 select case (this%status())
1229 case (batch_device_packed)
1230 call accel_set_kernel_arg(kernel_copy_real_to_complex, 0, np)
1231 call accel_set_kernel_arg(kernel_copy_real_to_complex, 1, this%ff_device)
1232 call accel_set_kernel_arg(kernel_copy_real_to_complex, 2, log2(int(this%pack_size_real(1), int32)))
1233 call accel_set_kernel_arg(kernel_copy_real_to_complex, 3, dest%ff_device)
1234 call accel_set_kernel_arg(kernel_copy_real_to_complex, 4, log2(int(dest%pack_size_real(1), int32)))
1235
1236 ! Compute the grid (extend to another dimensions if the size of the problem is too big)
1237 call accel_grid_size_extend_dim(int(np, int64), this%pack_size_real(1), gsizes, bsizes, kernel_copy_real_to_complex)
1238
1239 call accel_kernel_run(kernel_copy_real_to_complex, gsizes, bsizes)
1240
1241 if(.not. optional_default(async, .false.)) call accel_finish()
1242
1243 case (batch_packed)
1244 !$omp parallel do private(ist, ip)
1245 do ip = 1, np
1246 !$omp simd
1247 do ist = 1, dest%nst_linear
1248 dest%zff_pack(ist, ip) = cmplx(this%dff_pack(ist, ip), m_zero, real64)
1249 end do
1250 end do
1251 !$omp end parallel do
1252 case (batch_not_packed)
1253 !$omp parallel private(ist, ip)
1254 do ist = 1, dest%nst_linear
1255 !$omp do
1256 do ip = 1, np
1257 dest%zff_linear(ip, ist) = cmplx(this%dff_linear(ip, ist), m_zero, real64)
1258 end do
1259 !$omp end do nowait
1260 end do
1261 !$omp end parallel
1262 end select
1263 else
1264 message(1) = "Error! This should not happen."
1265 call messages_fatal(1)
1266 end if
1267
1268 call profiling_out("BATCH_COPY_DATA_TO")
1269 pop_sub(batch_copy_data_to)
1270 end subroutine batch_copy_data_to
1271
1272 ! --------------------------------------------------------------
1274 !
1275 subroutine batch_check_compatibility_with(this, target, only_check_dim, type_check)
1276 class(batch_t), intent(in) :: this
1277 class(batch_t), intent(in) :: target
1278 logical, optional, intent(in) :: only_check_dim
1279 logical, optional, intent(in) :: type_check
1280
1282
1283 if (optional_default(type_check, .true.)) then
1284 assert(this%type() == target%type())
1285 end if
1286 if (.not. optional_default(only_check_dim, .false.)) then
1287 assert(this%nst_linear == target%nst_linear)
1288 end if
1289 assert(this%status() == target%status())
1290 assert(this%dim == target%dim)
1291
1293
1294 end subroutine batch_check_compatibility_with
1295
1296!--------------------------------------------------------------
1299 subroutine batch_build_indices(this, st_start, st_end)
1300 class(batch_t), intent(inout) :: this
1301 integer, intent(in) :: st_start
1302 integer, intent(in) :: st_end
1303
1304 integer :: idim, ii, ist
1305
1306 push_sub(batch_build_indices)
1307
1308 do ist = st_start, st_end
1309 ! now we also populate the linear array
1310 do idim = 1, this%dim
1311 ii = this%dim*(ist - st_start) + idim
1312 this%ist_idim_index(ii, 1) = ist
1313 this%ist_idim_index(ii, 2) = idim
1314 end do
1315 this%ist(ist - st_start + 1) = ist
1316 end do
1317
1318 ! compute packed sizes
1319 this%pack_size(1) = pad_pow2(this%nst_linear)
1320 this%pack_size(2) = this%np
1321 if (accel_is_enabled()) this%pack_size(2) = accel_padded_size(this%pack_size(2))
1322
1323 this%pack_size_real = this%pack_size
1324 if (type_is_complex(this%type())) this%pack_size_real(1) = 2*this%pack_size_real(1)
1325
1326 pop_sub(batch_build_indices)
1327 end subroutine batch_build_indices
1328
1329
1330#include "real.F90"
1331#include "batch_inc.F90"
1332#include "undef.F90"
1333
1334#include "complex.F90"
1335#include "batch_inc.F90"
1336#include "undef.F90"
1337
1338end module batch_oct_m
1339
1340!! Local Variables:
1341!! mode: f90
1342!! coding: utf-8
1343!! End:
initialize a batch with existing memory
Definition: batch.F90:277
double log2(double __x) __attribute__((__nothrow__
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:1004
integer, parameter, public accel_mem_read_write
Definition: accel.F90:184
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:1958
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:1782
subroutine batch_check_compatibility_with(this, target, only_check_dim, type_check)
check whether two batches have compatible dimensions (and type)
Definition: batch.F90:1371
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:1683
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:1543
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:1869
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:1101
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:1514
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:1919
subroutine zbatch_allocate_packed_host(this)
allocate host (CPU) memory for packed data of type TYPE_CMPLX
Definition: batch.F90:1895
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:1207
subroutine batch_read_device_to_unpacked(this)
Definition: batch.F90:981
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:1848
subroutine dbatch_allocate_packed_host(this)
allocate host (CPU) memory for packed data of type TYPE_FLOAT
Definition: batch.F90:1590
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:1395
integer pure function batch_ist_idim_to_linear(this, cind)
direct index lookup
Definition: batch.F90:1118
integer, parameter gpu_pack_max_buffer_size
this value controls the size (in number of wave-functions) of the buffer used to copy states to the G...
Definition: batch.F90:291
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:1136
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:1078
subroutine batch_write_packed_to_device(this, async)
Definition: batch.F90:1059
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:1477
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:1614
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:1819
integer pure function batch_linear_to_idim(this, linear_index)
extract idim from linear index
Definition: batch.F90:1147
subroutine batch_remote_access_start(this, mpi_grp, rma_win)
start remote access to a batch on another node
Definition: batch.F90:1165
subroutine batch_copy_data_to(this, np, dest, async)
copy data to another batch.
Definition: batch.F90:1226
subroutine dbatch_allocate_unpacked_host(this)
allocate host (CPU) memory for unpacked data of type TYPE_FLOAT
Definition: batch.F90:1564
subroutine dbatch_pack_copy(this)
copy data from the unpacked to the packed arrays
Definition: batch.F90:1653
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:1988
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:410
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)