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, &
64
67 type batch_t
68 private
69 integer, public :: nst
70 integer, public :: dim
71 integer :: np
72 integer :: ndims
73 integer, allocatable :: ist_idim_index(:, :)
74
78 integer, allocatable, public :: ist(:)
84
85 logical :: is_allocated
86 logical :: own_memory
87 ! We also need a linear array with the states in order to calculate derivatives, etc.
88 integer, public :: nst_linear
89
90 integer :: status_of
94 integer :: status_host
103 type(type_t) :: type_of
104 integer :: device_buffer_count
105 integer :: host_buffer_count
106 logical :: special_memory
107 logical :: needs_finish_unpack
108
109
110 ! unpacked variables; linear variables are pointers with different shapes
111 real(real64), pointer, contiguous, public :: dff(:, :, :)
112 ! !! indices are (1:np, 1:dim, 1:nst)
113 complex(real64), pointer, contiguous, public :: zff(:, :, :)
114 ! !! indices are (1:np, 1:dim, 1:nst)
115 real(real64), pointer, contiguous, public :: dff_linear(:, :)
116 ! !! indices are (1:np, 1:nst_linear)
117 complex(real64), pointer, contiguous, public :: zff_linear(:, :)
118 ! !! indices are (1:np, 1:nst_linear)
119
120 ! packed variables; only rank-2 arrays due to padding to powers of 2
121 real(real64), pointer, contiguous, public :: dff_pack(:, :)
122 ! !! indices are (1:nst_linear, 1:np)
123 complex(real64), pointer, contiguous, public :: zff_pack(:, :)
124 ! !! indices are (1:nst_linear, 1:np)
125
126 integer(int64), public :: pack_size(1:2)
128 integer(int64), public :: pack_size_real(1:2)
131
132 type(accel_mem_t), public :: ff_device
133
134 contains
135 procedure :: check_compatibility_with => batch_check_compatibility_with
136 procedure :: clone_to => batch_clone_to
137 procedure :: clone_to_array => batch_clone_to_array
138 procedure :: copy_to => batch_copy_to
139 procedure :: copy_data_to => batch_copy_data_to
140 procedure :: do_pack_generic => batch_do_pack_generic
141 procedure :: do_pack_target => batch_do_pack_target
142 generic :: do_pack => do_pack_generic, do_pack_target
143 procedure :: do_unpack => batch_do_unpack
144 procedure :: finish_unpack => batch_finish_unpack
145 procedure :: end => batch_end
146 procedure :: inv_index => batch_inv_index
147 procedure :: is_packed => batch_is_packed
148 procedure :: ist_idim_to_linear => batch_ist_idim_to_linear
149 procedure :: linear_to_idim => batch_linear_to_idim
150 procedure :: linear_to_ist => batch_linear_to_ist
151 procedure :: pack_total_size => batch_pack_total_size
152 procedure :: remote_access_start => batch_remote_access_start
153 procedure :: remote_access_stop => batch_remote_access_stop
154 procedure :: status => batch_status
155 procedure :: type => batch_type
156 procedure :: type_as_int => batch_type_as_integer
157 procedure, private :: dallocate_unpacked_host => dbatch_allocate_unpacked_host
158
159 procedure, private :: zallocate_unpacked_host => zbatch_allocate_unpacked_host
160
161 procedure, private :: allocate_unpacked_host => batch_allocate_unpacked_host
163 procedure, private :: dallocate_packed_host => dbatch_allocate_packed_host
165 procedure, private :: zallocate_packed_host => zbatch_allocate_packed_host
167 procedure, private :: allocate_packed_host => batch_allocate_packed_host
169 procedure, private :: allocate_packed_device => batch_allocate_packed_device
170
171 procedure, private :: deallocate_unpacked_host => batch_deallocate_unpacked_host
172
173 procedure, private :: deallocate_packed_host => batch_deallocate_packed_host
174
175 procedure, private :: deallocate_packed_device => batch_deallocate_packed_device
176
177 end type batch_t
178
179 !--------------------------------------------------------------
183 interface batch_init
184 module procedure dbatch_init_with_memory_3
186 module procedure dbatch_init_with_memory_2
187 module procedure zbatch_init_with_memory_2
188 module procedure dbatch_init_with_memory_1
190 end interface batch_init
191
192 integer, public, parameter :: &
193 batch_not_packed = 0, & !< functions are stored in CPU memory, unpacked order
194 batch_packed = 1, &
196
197 integer, parameter :: gpu_pack_max_buffer_size = 4
200contains
202 !--------------------------------------------------------------
209 !
210 subroutine batch_end(this, copy)
211 class(batch_t), intent(inout) :: this
212 logical, optional, intent(in) :: copy
214
215 push_sub(batch_end)
217 if (this%own_memory .and. this%is_packed()) then
218 !deallocate directly to avoid unnecessary copies
219 if (this%status() == batch_device_packed) then
220 call this%deallocate_packed_device()
221 end if
222 if (this%status() == batch_packed .or. this%status_host == batch_packed) then
223 call this%deallocate_packed_host()
224 end if
225 this%status_of = batch_not_packed
226 this%status_host = batch_not_packed
227 this%host_buffer_count = 0
228 this%device_buffer_count = 0
229 end if
230 if (this%status() == batch_device_packed) call this%do_unpack(copy, force = .true.)
231 if (this%status() == batch_packed) call this%do_unpack(copy, force = .true.)
233 if (this%is_allocated) then
234 call this%deallocate_unpacked_host()
235 end if
237 safe_deallocate_a(this%ist_idim_index)
238 safe_deallocate_a(this%ist)
240 pop_sub(batch_end)
241 end subroutine batch_end
243 !--------------------------------------------------------------
249 class(batch_t), intent(inout) :: this
253 this%is_allocated = .false.
255 if (this%special_memory) then
256 if (associated(this%dff)) then
257 call deallocate_hardware_aware(c_loc(this%dff(1,1,1)), int(this%np, int64)*this%dim*this%nst*8)
258 end if
259 if (associated(this%zff)) then
260 call deallocate_hardware_aware(c_loc(this%zff(1,1,1)), int(this%np, int64)*this%dim*this%nst*16)
261 end if
262 else
263 safe_deallocate_p(this%dff)
264 safe_deallocate_p(this%zff)
265 end if
266 nullify(this%dff)
267 nullify(this%dff_linear)
268 nullify(this%zff)
269 nullify(this%zff_linear)
272 end subroutine batch_deallocate_unpacked_host
273
274 !--------------------------------------------------------------
279 subroutine batch_deallocate_packed_host(this)
280 class(batch_t), intent(inout) :: this
281
283
284 if (this%special_memory) then
285 if (associated(this%dff_pack)) then
286 call deallocate_hardware_aware(c_loc(this%dff_pack(1,1)), int(this%pack_size(1), int64)*this%pack_size(2)*8)
287 end if
288 if (associated(this%zff_pack)) then
289 call deallocate_hardware_aware(c_loc(this%zff_pack(1,1)), int(this%pack_size(1), int64)*this%pack_size(2)*16)
290 end if
291 else
292 safe_deallocate_p(this%dff_pack)
293 safe_deallocate_p(this%zff_pack)
294 end if
295 nullify(this%dff_pack)
296 nullify(this%zff_pack)
297
299 end subroutine batch_deallocate_packed_host
300
301 !--------------------------------------------------------------
303 !
304 subroutine batch_deallocate_packed_device(this)
305 class(batch_t), intent(inout) :: this
306
308
309 call accel_free_buffer(this%ff_device)
310
312 end subroutine batch_deallocate_packed_device
313
314 !--------------------------------------------------------------
318 !
319 subroutine batch_allocate_unpacked_host(this)
320 class(batch_t), intent(inout) :: this
321
323
324 if (this%type() == type_float) then
325 call this%dallocate_unpacked_host()
326 else if (this%type() == type_cmplx) then
327 call this%zallocate_unpacked_host()
328 end if
329
331 end subroutine batch_allocate_unpacked_host
332
333 !--------------------------------------------------------------
337 !
338 subroutine batch_allocate_packed_host(this)
339 class(batch_t), intent(inout) :: this
340
342
343 if (this%type() == type_float) then
344 call this%dallocate_packed_host()
345 else if (this%type() == type_cmplx) then
346 call this%zallocate_packed_host()
347 end if
348
350 end subroutine batch_allocate_packed_host
351
352 !--------------------------------------------------------------
356 !
357 subroutine batch_allocate_packed_device(this)
358 class(batch_t), intent(inout) :: this
359
361
362 call accel_create_buffer(this%ff_device, accel_mem_read_write, this%type(), &
363 product(this%pack_size))
364
366 end subroutine batch_allocate_packed_device
367
368 !--------------------------------------------------------------
375 subroutine batch_init_empty (this, dim, nst, np)
376 type(batch_t), intent(out) :: this
377 integer, intent(in) :: dim
378 integer, intent(in) :: nst
379 integer, intent(in) :: np
380
381 push_sub(batch_init_empty)
382
383 this%is_allocated = .false.
384 this%own_memory = .false.
385 this%special_memory = .false.
386 this%needs_finish_unpack = .false.
387 this%nst = nst
388 this%dim = dim
389 this%type_of = type_none
390
391 this%nst_linear = nst*dim
392
393 this%np = np
394 this%device_buffer_count = 0
395 this%host_buffer_count = 0
396 this%status_of = batch_not_packed
397 this%status_host = batch_not_packed
398
399 this%ndims = 2
400 safe_allocate(this%ist_idim_index(1:this%nst_linear, 1:this%ndims))
401 safe_allocate(this%ist(1:this%nst))
402
403 nullify(this%dff, this%zff, this%dff_linear, this%zff_linear)
404 nullify(this%dff_pack, this%zff_pack)
405
406 pop_sub(batch_init_empty)
407 end subroutine batch_init_empty
408
409 !--------------------------------------------------------------
415 subroutine batch_clone_to(this, dest, pack, copy_data, new_np, special, dest_type)
416 class(batch_t), intent(in) :: this
417 class(batch_t), allocatable, intent(out) :: dest
418 logical, optional, intent(in) :: pack
420 logical, optional, intent(in) :: copy_data
422 integer, optional, intent(in) :: new_np
423 logical, optional, intent(in) :: special
425 type(type_t), optional, intent(in) :: dest_type
426
427 push_sub(batch_clone_to)
428
429 if (.not. allocated(dest)) then
430 safe_allocate_type(batch_t, dest)
431 else
432 message(1) = "Internal error: destination batch in batch_clone_to has been previously allocated."
434 end if
435
436 call this%copy_to(dest, pack, copy_data, new_np, special, dest_type)
437
438 pop_sub(batch_clone_to)
439 end subroutine batch_clone_to
440
441 !--------------------------------------------------------------
442
443 subroutine batch_clone_to_array(this, dest, n_batches, pack, copy_data, new_np, special, dest_type)
444 class(batch_t), intent(in) :: this
445 class(batch_t), allocatable, intent(out) :: dest(:)
446 integer, intent(in) :: n_batches
447 logical, optional, intent(in) :: pack
449 logical, optional, intent(in) :: copy_data
451 integer, optional, intent(in) :: new_np
452 logical, optional, intent(in) :: special
454 type(type_t), optional, intent(in) :: dest_type
455
456 integer :: ib
457
458 push_sub(batch_clone_to_array)
459
460 if (.not. allocated(dest)) then
461 safe_allocate_type_array(batch_t, dest, (1:n_batches))
462 else
463 message(1) = "Internal error: destination batch in batch_clone_to_array has been previously allocated."
464 call messages_fatal(1)
465 end if
466
467 do ib = 1, n_batches
468 call this%copy_to(dest(ib), pack, copy_data, new_np, special, dest_type)
469 end do
471 pop_sub(batch_clone_to_array)
472 end subroutine batch_clone_to_array
473
474 !--------------------------------------------------------------
479 subroutine batch_copy_to(this, dest, pack, copy_data, new_np, special, dest_type)
480 class(batch_t), intent(in) :: this
481 class(batch_t), intent(out) :: dest
482 logical, optional, intent(in) :: pack
484 logical, optional, intent(in) :: copy_data
486 integer, optional, intent(in) :: new_np
487 logical, optional, intent(in) :: special
489 type(type_t), optional, intent(in) :: dest_type
490
491 logical :: host_packed, special_
492 integer :: np_
493 type(type_t) :: type_
494
495 push_sub(batch_copy_to)
496
497 np_ = optional_default(new_np, this%np)
498
499 host_packed = this%host_buffer_count > 0
500 ! use special memory here only for batches not on the GPU to avoid allocating
501 ! pinned memory for temporary batches because that leads to a severe performance
502 ! decrease for GPU runs (up to 20x)
503 if (present(special)) then
504 special_ = this%special_memory
505 else
506 special_ = this%special_memory .and. .not. this%device_buffer_count > 0
507 end if
508
509 if (present(dest_type)) then
510 type_ = dest_type
511 else
512 type_ = this%type()
513 end if
514
515 if (type_ == type_float) then
516 call dbatch_init(dest, this%dim, 1, this%nst, np_, packed=host_packed, special=special_)
517 else if (type_ == type_cmplx) then
518 call zbatch_init(dest, this%dim, 1, this%nst, np_, packed=host_packed, special=special_)
519 else
520 message(1) = "Internal error: unknown batch type in batch_copy_to."
521 call messages_fatal(1)
522 end if
523
524 if (this%status() /= dest%status() .and. optional_default(pack, this%is_packed())) call dest%do_pack(copy = .false.)
525
526 dest%ist_idim_index(1:this%nst_linear, 1:this%ndims) = this%ist_idim_index(1:this%nst_linear, 1:this%ndims)
527 dest%ist(1:this%nst) = this%ist(1:this%nst)
528
529 if (optional_default(copy_data, .false.)) then
530 assert(np_ == this%np)
531 call this%copy_data_to(min(this%np, np_), dest)
532 end if
533
534 pop_sub(batch_copy_to)
535 end subroutine batch_copy_to
536
537 ! ----------------------------------------------------
542 type(type_t) pure function batch_type(this) result(btype)
543 class(batch_t), intent(in) :: this
544
545 btype = this%type_of
546
547 end function batch_type
548
549 ! ----------------------------------------------------
551 integer pure function batch_type_as_integer(this) result(itype)
552 class(batch_t), intent(in) :: this
553
554 type(type_t) :: btype
555
556 itype = 0
557 btype = this%type()
558 if (btype == type_float) itype = 1
559 if (btype == type_cmplx) itype = 2
560
561 end function batch_type_as_integer
562
563 ! ----------------------------------------------------
568 integer pure function batch_status(this) result(bstatus)
569 class(batch_t), intent(in) :: this
570
571 bstatus = this%status_of
572 end function batch_status
573
574 ! ----------------------------------------------------
575
576 logical pure function batch_is_packed(this) result(in_buffer)
577 class(batch_t), intent(in) :: this
578
579 in_buffer = (this%device_buffer_count > 0) .or. (this%host_buffer_count > 0)
580 end function batch_is_packed
581
582 ! ----------------------------------------------------
583
584 integer(int64) function batch_pack_total_size(this) result(size)
585 class(batch_t), intent(inout) :: this
586
587 size = this%np
588 if (accel_is_enabled()) size = accel_padded_size(size)
589 size = size*pad_pow2(this%nst_linear)*types_get_size(this%type())
590
591 end function batch_pack_total_size
592
593 ! ----------------------------------------------------
594
600 subroutine batch_do_pack_generic(this, copy, async)
601 class(batch_t), intent(inout) :: this
602 logical, optional, intent(in) :: copy
603 logical, optional, intent(in) :: async
605
606 integer :: source, target
607
608 ! no push_sub, called too frequently
609
610 ! get source and target states for this batch
611 source = this%status()
612 select case (source)
614 if (accel_is_enabled()) then
615 target = batch_device_packed
616 else
617 target = batch_packed
618 end if
620 target = batch_device_packed
621 end select
622
623 call this%do_pack(target, copy, async)
624
625 end subroutine batch_do_pack_generic
626
631 subroutine batch_do_pack_target(this, target, copy, async, cpu_only)
632 class(batch_t), intent(inout) :: this
633 integer, intent(in) :: target
634 logical, optional, intent(in) :: copy
635 logical, optional, intent(in) :: async
637 logical, optional, intent(in) :: cpu_only
638
639 logical :: copy_
640 logical :: async_
641 integer :: source
642
643 ! no push_sub, called too frequently
644
645 call profiling_in("BATCH_DO_PACK")
647 copy_ = optional_default(copy, .true.)
648
649 async_ = optional_default(async, .false.)
650
651 ! get source state for this batch
652 source = this%status()
653
654 ! only do something if target is different from source
655 if (source /= target) then
656 select case (target)
658 call this%allocate_packed_device()
659 this%status_of = batch_device_packed ! Note that this%status_host remains untouched.
660
661 if (copy_) then
662 select case (source)
664 ! copy from unpacked host array to device
666 case (batch_packed)
667 ! copy from packed host array to device
668 call batch_write_packed_to_device(this, async_)
669 end select
670 end if
672 call this%allocate_packed_host()
673 this%status_of = batch_packed
674 this%status_host = batch_packed
675
676 if (copy_) then
677 if (this%type() == type_float) then
678 call dbatch_pack_copy(this)
679 else if (this%type() == type_cmplx) then
680 call zbatch_pack_copy(this)
681 end if
682 end if
683 if (this%own_memory) call this%deallocate_unpacked_host()
684 case (batch_not_packed)
685 call messages_not_implemented("Error: batch_do_pack called with BATCH_NOT_PACKED as target.")
686 end select
687 end if
688
689 select case (target)
691 this%device_buffer_count = this%device_buffer_count + 1
692 case (batch_packed)
693 this%host_buffer_count = this%host_buffer_count + 1
694 end select
696 call profiling_out("BATCH_DO_PACK")
697 end subroutine batch_do_pack_target
698
699
700 ! ----------------------------------------------------
705 subroutine batch_do_unpack(this, copy, force, async)
706 class(batch_t), intent(inout) :: this
707 logical, optional, intent(in) :: copy
708 logical, optional, intent(in) :: force
709 logical, optional, intent(in) :: async
711
712 logical :: copy_, force_, async_
713 integer :: source, target
714
715 push_sub(batch_do_unpack)
716
717 call profiling_in("BATCH_DO_UNPACK")
718
719 copy_ = optional_default(copy, .true.)
720
721 force_ = optional_default(force, .false.)
722
723 async_ = optional_default(async, .false.)
724
725 ! get source and target states for this batch
726 source = this%status()
727 select case (source)
728 case (batch_not_packed)
729 target = source
730 case (batch_packed)
731 target = batch_not_packed
733 target = this%status_host
734 end select
735
736 ! only do something if target is different from source
737 if (source /= target) then
738 select case (source)
739 case (batch_packed)
740 if (this%host_buffer_count == 1 .or. force_) then
741 if (this%own_memory) call this%allocate_unpacked_host()
742 ! unpack from packed_host to unpacked_host
743 if (copy_ .or. this%own_memory) then
744 if (this%type() == type_float) then
745 call dbatch_unpack_copy(this)
746 else if (this%type() == type_cmplx) then
747 call zbatch_unpack_copy(this)
748 end if
749 end if
750 call this%deallocate_packed_host()
751 this%status_host = target
752 this%status_of = target
753 this%host_buffer_count = 1
754 end if
755 this%host_buffer_count = this%host_buffer_count - 1
757 if (this%device_buffer_count == 1 .or. force_) then
758 if (copy_) then
759 select case (target)
760 ! unpack from packed_device to unpacked_host
761 case (batch_not_packed)
763 ! unpack from packed_device to packed_host
764 case (batch_packed)
765 call batch_read_device_to_packed(this, async_)
766 end select
767 end if
768 if (async_) then
769 this%needs_finish_unpack = .true.
770 else
771 call this%deallocate_packed_device()
772 end if
773 this%status_of = target
774 this%device_buffer_count = 1
775 end if
776 this%device_buffer_count = this%device_buffer_count - 1
777 end select
778 end if
779
780 call profiling_out("BATCH_DO_UNPACK")
781
782 pop_sub(batch_do_unpack)
783 end subroutine batch_do_unpack
784
785 ! ----------------------------------------------------
787 subroutine batch_finish_unpack(this)
788 class(batch_t), intent(inout) :: this
789
790 push_sub(batch_finish_unpack)
791 if (this%needs_finish_unpack) then
792 call accel_finish()
793 call this%deallocate_packed_device()
794 this%needs_finish_unpack = .false.
795 end if
796 pop_sub(batch_finish_unpack)
797 end subroutine batch_finish_unpack
798
799 ! ----------------------------------------------------
801 subroutine batch_write_unpacked_to_device(this)
802 class(batch_t), intent(inout) :: this
803
804 integer :: ist, ist2
805 integer(int64) :: unroll, bsize, gsize
806 type(accel_mem_t) :: tmp
807 type(accel_kernel_t), pointer :: kernel
808
810
811 call profiling_in("BATCH_WRT_UNPACK_ACCEL")
812 if (this%nst_linear == 1) then
813 ! we can copy directly
814 if (this%type() == type_float) then
815 call accel_write_buffer(this%ff_device, ubound(this%dff_linear, dim=1), this%dff_linear(:, 1))
816 else if (this%type() == type_cmplx) then
817 call accel_write_buffer(this%ff_device, ubound(this%zff_linear, dim=1), this%zff_linear(:, 1))
818 else
819 assert(.false.)
820 end if
821
822 else
823 ! we copy to a temporary array and then we re-arrange data
824
825 if (this%type() == type_float) then
826 kernel => dpack
827 else
828 kernel => zpack
829 end if
830
831 unroll = min(int(gpu_pack_max_buffer_size, int64), this%pack_size(1))
832
833 call accel_create_buffer(tmp, accel_mem_read_only, this%type(), unroll*this%pack_size(2))
834
835 do ist = 1, this%nst_linear, int(unroll, int32)
836
837 ! copy a number 'unroll' of states to the buffer
838 do ist2 = ist, min(ist + int(unroll, int32) - 1, this%nst_linear)
839
840 if (this%type() == type_float) then
841 call accel_write_buffer(tmp, ubound(this%dff_linear, dim=1, kind=int64), this%dff_linear(:, ist2), &
842 offset = (ist2 - ist)*this%pack_size(2))
843 else
844 call accel_write_buffer(tmp, ubound(this%zff_linear, dim=1, kind=int64), this%zff_linear(:, ist2), &
845 offset = (ist2 - ist)*this%pack_size(2))
846 end if
847 end do
848
849 ! now call a kernel to rearrange the data
850 call accel_set_kernel_arg(kernel, 0, int(this%pack_size(1), int32))
851 call accel_set_kernel_arg(kernel, 1, this%np)
852 call accel_set_kernel_arg(kernel, 2, this%nst_linear)
853 call accel_set_kernel_arg(kernel, 3, ist - 1)
854 call accel_set_kernel_arg(kernel, 4, tmp)
855 call accel_set_kernel_arg(kernel, 5, this%ff_device)
856
857 call profiling_in("GPU_PACK")
858
859 ! Compute the grid size
860 bsize = accel_max_block_size()/unroll
861 call accel_grid_size(this%pack_size(2), bsize, gsize)
862
863 call accel_kernel_run(kernel, (/gsize, 1_int64/), (/bsize, unroll/))
864
865 if (this%type() == type_float) then
866 call profiling_count_transfers(unroll*this%pack_size(2), m_one)
867 else
868 call profiling_count_transfers(unroll*this%pack_size(2), m_zi)
869 end if
870
871 call accel_finish()
872 call profiling_out("GPU_PACK")
873
874 end do
875
876 call accel_free_buffer(tmp)
877
878 end if
879
880 call profiling_out("BATCH_WRT_UNPACK_ACCEL")
883
884 ! ------------------------------------------------------------------
885
886 subroutine batch_read_device_to_unpacked(this)
887 class(batch_t), intent(inout) :: this
888
889 integer :: ist, ist2
890 integer(int64) :: unroll, bsize, gsize
891 type(accel_mem_t) :: tmp
892 type(accel_kernel_t), pointer :: kernel
893
895 call profiling_in("BATCH_READ_UNPACKED_ACCEL")
897 if (this%nst_linear == 1) then
898 ! we can copy directly
899 if (this%type() == type_float) then
900 call accel_read_buffer(this%ff_device, ubound(this%dff_linear, dim=1), this%dff_linear(:, 1))
901 else
902 call accel_read_buffer(this%ff_device, ubound(this%zff_linear, dim=1), this%zff_linear(:, 1))
903 end if
904 else
905
906 unroll = min(int(gpu_pack_max_buffer_size, int64), this%pack_size(1))
907
908 ! we use a kernel to move to a temporary array and then we read
909 call accel_create_buffer(tmp, accel_mem_write_only, this%type(), unroll*this%pack_size(2))
910
911 if (this%type() == type_float) then
912 kernel => dunpack
913 else
914 kernel => zunpack
915 end if
916
917 do ist = 1, this%nst_linear, int(unroll, int32)
918 call accel_set_kernel_arg(kernel, 0, int(this%pack_size(1), int32))
919 call accel_set_kernel_arg(kernel, 1, this%np)
920 call accel_set_kernel_arg(kernel, 2, this%nst_linear)
921 call accel_set_kernel_arg(kernel, 3, ist - 1)
922 call accel_set_kernel_arg(kernel, 4, this%ff_device)
923 call accel_set_kernel_arg(kernel, 5, tmp)
924
925 call profiling_in("GPU_UNPACK")
926
927 ! Compute the grid size
928 bsize = accel_max_block_size()/unroll
929 call accel_grid_size(this%pack_size(2), bsize, gsize)
930
931 call accel_kernel_run(kernel, (/1_int64, gsize/), (/unroll, bsize/))
932
933 if (this%type() == type_float) then
934 call profiling_count_transfers(unroll*this%pack_size(2), m_one)
935 else
936 call profiling_count_transfers(unroll*this%pack_size(2), m_zi)
937 end if
938
939 call accel_finish()
940 call profiling_out("GPU_UNPACK")
941
942 ! copy a number 'unroll' of states from the buffer
943 do ist2 = ist, min(ist + int(unroll, int32) - 1, this%nst_linear)
944
945 if (this%type() == type_float) then
946 call accel_read_buffer(tmp, ubound(this%dff_linear, dim=1, kind=int64), this%dff_linear(:, ist2), &
947 offset = (ist2 - ist)*this%pack_size(2))
948 else
949 call accel_read_buffer(tmp, ubound(this%zff_linear, dim=1, kind=int64), this%zff_linear(:, ist2), &
950 offset = (ist2 - ist)*this%pack_size(2))
951 end if
952 end do
953
954 end do
955
956 call accel_free_buffer(tmp)
957 end if
958
959 call profiling_out("BATCH_READ_UNPACKED_ACCEL")
961 end subroutine batch_read_device_to_unpacked
962
963 ! ------------------------------------------------------------------
964 subroutine batch_write_packed_to_device(this, async)
965 class(batch_t), intent(inout) :: this
966 logical, optional, intent(in) :: async
967
968
970
971 call profiling_in("BATCH_WRITE_PACKED_ACCEL")
972 if (this%type() == type_float) then
973 call accel_write_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%dff_pack, async=async)
974 else
975 call accel_write_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%zff_pack, async=async)
976 end if
977 call profiling_out("BATCH_WRITE_PACKED_ACCEL")
978
980 end subroutine batch_write_packed_to_device
982 ! ------------------------------------------------------------------
983 subroutine batch_read_device_to_packed(this, async)
984 class(batch_t), intent(inout) :: this
985 logical, optional, intent(in) :: async
986
987
989
990 call profiling_in("BATCH_READ_PACKED_ACCEL")
991 if (this%type() == type_float) then
992 call accel_read_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%dff_pack, async=async)
993 else
994 call accel_read_buffer(this%ff_device, this%pack_size(1), this%pack_size(2), this%zff_pack, async=async)
995 end if
996 call profiling_out("BATCH_READ_PACKED_ACCEL")
997
999 end subroutine batch_read_device_to_packed
1000
1001 ! ------------------------------------------------------
1006 integer function batch_inv_index(this, cind) result(index)
1007 class(batch_t), intent(in) :: this
1008 integer, intent(in) :: cind(:)
1009
1010 do index = 1, this%nst_linear
1011 if (all(cind(1:this%ndims) == this%ist_idim_index(index, 1:this%ndims))) exit
1012 end do
1013
1014 assert(index <= this%nst_linear)
1015
1016 end function batch_inv_index
1017
1018 ! ------------------------------------------------------
1022 !
1023 integer pure function batch_ist_idim_to_linear(this, cind) result(index)
1024 class(batch_t), intent(in) :: this
1025 integer, intent(in) :: cind(:)
1026
1027 if (ubound(cind, dim = 1) == 1) then
1028 index = cind(1)
1029 else
1030 index = (cind(1) - 1)*this%dim + cind(2)
1031 end if
1032
1033 end function batch_ist_idim_to_linear
1034
1035 ! ------------------------------------------------------
1040 !
1041 integer pure function batch_linear_to_ist(this, linear_index) result(ist)
1042 class(batch_t), intent(in) :: this
1043 integer, intent(in) :: linear_index
1044
1045 ist = this%ist_idim_index(linear_index, 1)
1046
1047 end function batch_linear_to_ist
1048
1049 ! ------------------------------------------------------
1051 !
1052 integer pure function batch_linear_to_idim(this, linear_index) result(idim)
1053 class(batch_t), intent(in) :: this
1054 integer, intent(in) :: linear_index
1055
1056 idim = this%ist_idim_index(linear_index, 2)
1057
1058 end function batch_linear_to_idim
1060 ! ------------------------------------------------------
1069 !
1070 subroutine batch_remote_access_start(this, mpi_grp, rma_win)
1071 class(batch_t), intent(inout) :: this
1072 type(mpi_grp_t), intent(in) :: mpi_grp
1073 type(mpi_win), intent(out) :: rma_win
1074
1076
1077 if (mpi_grp%size > 1) then
1079 assert(.not. accel_is_enabled())
1080
1081 call this%do_pack()
1082
1083 assert(int(product(this%pack_size)*types_get_size(this%type())) > 0) ! In case of overflow, this becomes negative
1084 if (this%type() == type_cmplx) then
1085#ifdef HAVE_MPI
1086 call mpi_win_create(this%zff_pack(1, 1), int(product(this%pack_size)*types_get_size(this%type()), mpi_address_kind), &
1087 types_get_size(this%type()), mpi_info_null, mpi_grp%comm, rma_win)
1088#endif
1089 else if (this%type() == type_float) then
1090#ifdef HAVE_MPI
1091 call mpi_win_create(this%dff_pack(1, 1), int(product(this%pack_size)*types_get_size(this%type()), mpi_address_kind), &
1092 types_get_size(this%type()), mpi_info_null, mpi_grp%comm, rma_win)
1093#endif
1094 else
1095 message(1) = "Internal error: unknown batch type in batch_remote_access_start."
1096 call messages_fatal(1)
1097 end if
1098
1099 else
1100 rma_win = mpi_win_null
1101 end if
1102
1104 end subroutine batch_remote_access_start
1105
1106 ! ------------------------------------------------------
1112 !
1113 subroutine batch_remote_access_stop(this, rma_win)
1114 class(batch_t), intent(inout) :: this
1115 type(mpi_win), intent(inout) :: rma_win
1116
1117 push_sub(batch_remote_access_stop)
1119 if (rma_win /= mpi_win_null) then
1120#ifdef HAVE_MPI
1121 call mpi_win_free(rma_win)
1122#endif
1123 call this%do_unpack()
1124 end if
1125
1127 end subroutine batch_remote_access_stop
1128
1129 ! --------------------------------------------------------------
1131 !
1132 subroutine batch_copy_data_to(this, np, dest, async)
1133 class(batch_t), intent(in) :: this
1134 integer, intent(in) :: np
1135 class(batch_t), intent(inout) :: dest
1136 logical, optional, intent(in) :: async
1137
1138 integer(int64), dimension(3) :: gsizes, bsizes
1139 integer :: ist, ip
1140
1141 push_sub(batch_copy_data_to)
1142 call profiling_in("BATCH_COPY_DATA_TO")
1143
1144 ! this routine can be used to copy data between batches of different type
1145 call this%check_compatibility_with(dest, type_check=.false.)
1146
1147 if (this%type() == dest%type()) then
1148 select case (this%status())
1149 case (batch_device_packed)
1150 call accel_set_kernel_arg(kernel_copy, 0, np)
1151 call accel_set_kernel_arg(kernel_copy, 1, this%ff_device)
1152 call accel_set_kernel_arg(kernel_copy, 2, log2(int(this%pack_size_real(1), int32)))
1153 call accel_set_kernel_arg(kernel_copy, 3, dest%ff_device)
1154 call accel_set_kernel_arg(kernel_copy, 4, log2(int(dest%pack_size_real(1), int32)))
1155
1156 ! Compute the grid (extend to another dimensions if the size of the problem is too big)
1157 call accel_grid_size_extend_dim(int(np, int64), dest%pack_size_real(1), gsizes, bsizes, kernel_copy)
1158
1159 call accel_kernel_run(kernel_copy, gsizes, bsizes)
1160
1161 if(.not. optional_default(async, .false.)) call accel_finish()
1162
1163 case (batch_packed)
1164 if (np*this%pack_size(1) > huge(0_int32)) then
1165 ! BLAS cannot handle 8-byte integers, so we need a special version here
1166 do ip = 1, np
1167 if (dest%type() == type_float) then
1168 call blas_copy(int(this%pack_size(1), int32), this%dff_pack(1, ip), 1, dest%dff_pack(1, ip), 1)
1169 else
1170 call blas_copy(int(this%pack_size(1), int32), this%zff_pack(1, ip), 1, dest%zff_pack(1, ip), 1)
1171 end if
1172 end do
1173 else
1174 if (dest%type() == type_float) then
1175 call blas_copy(int(this%pack_size(1)*np, int32), this%dff_pack(1, 1), 1, dest%dff_pack(1, 1), 1)
1176 else
1177 call blas_copy(int(this%pack_size(1)*np, int32), this%zff_pack(1, 1), 1, dest%zff_pack(1, 1), 1)
1178 end if
1179 end if
1180
1181 case (batch_not_packed)
1182 do ist = 1, dest%nst_linear
1183 if (dest%type() == type_cmplx) then
1184 call blas_copy(np, this%zff_linear(1, ist), 1, dest%zff_linear(1, ist), 1)
1185 else
1186 call blas_copy(np, this%dff_linear(1, ist), 1, dest%dff_linear(1, ist), 1)
1187 end if
1188 end do
1189
1190 end select
1191 else if (this%type() == type_cmplx) then
1192 ! copy complex -> real
1193 select case (this%status())
1194 case (batch_device_packed)
1195 call accel_set_kernel_arg(kernel_copy_complex_to_real, 0, np)
1196 call accel_set_kernel_arg(kernel_copy_complex_to_real, 1, this%ff_device)
1197 call accel_set_kernel_arg(kernel_copy_complex_to_real, 2, log2(int(this%pack_size_real(1), int32)))
1198 call accel_set_kernel_arg(kernel_copy_complex_to_real, 3, dest%ff_device)
1199 call accel_set_kernel_arg(kernel_copy_complex_to_real, 4, log2(int(dest%pack_size_real(1), int32)))
1200
1201 ! Compute the grid (extend to another dimensions if the size of the problem is too big)
1202 call accel_grid_size_extend_dim(int(np, int64), dest%pack_size_real(1), gsizes, bsizes, kernel_copy_complex_to_real)
1203
1204 call accel_kernel_run(kernel_copy_complex_to_real, gsizes, bsizes)
1205
1206 if(.not. optional_default(async, .false.)) call accel_finish()
1207
1209 !$omp parallel do private(ist, ip)
1210 do ip = 1, np
1211 !$omp simd
1212 do ist = 1, dest%nst_linear
1213 dest%dff_pack(ist, ip) = real(this%zff_pack(ist, ip), real64)
1214 end do
1215 end do
1216 !$omp end parallel do
1217 case (batch_not_packed)
1218 !$omp parallel private(ist, ip)
1219 do ist = 1, dest%nst_linear
1220 !$omp do
1221 do ip = 1, np
1222 dest%dff_linear(ip, ist) = real(this%zff_linear(ip, ist), real64)
1223 end do
1224 !$omp end do nowait
1225 end do
1226 !$omp end parallel
1227 end select
1228 else if (this%type() == type_float) then
1229 ! copy real -> complex
1230 select case (this%status())
1231 case (batch_device_packed)
1232 call accel_set_kernel_arg(kernel_copy_real_to_complex, 0, np)
1233 call accel_set_kernel_arg(kernel_copy_real_to_complex, 1, this%ff_device)
1234 call accel_set_kernel_arg(kernel_copy_real_to_complex, 2, log2(int(this%pack_size_real(1), int32)))
1235 call accel_set_kernel_arg(kernel_copy_real_to_complex, 3, dest%ff_device)
1236 call accel_set_kernel_arg(kernel_copy_real_to_complex, 4, log2(int(dest%pack_size_real(1), int32)))
1237
1238 ! Compute the grid (extend to another dimensions if the size of the problem is too big)
1239 call accel_grid_size_extend_dim(int(np, int64), this%pack_size_real(1), gsizes, bsizes, kernel_copy_real_to_complex)
1240
1241 call accel_kernel_run(kernel_copy_real_to_complex, gsizes, bsizes)
1242
1243 if(.not. optional_default(async, .false.)) call accel_finish()
1244
1245 case (batch_packed)
1246 !$omp parallel do private(ist, ip)
1247 do ip = 1, np
1248 !$omp simd
1249 do ist = 1, dest%nst_linear
1250 dest%zff_pack(ist, ip) = cmplx(this%dff_pack(ist, ip), m_zero, real64)
1251 end do
1252 end do
1253 !$omp end parallel do
1254 case (batch_not_packed)
1255 !$omp parallel private(ist, ip)
1256 do ist = 1, dest%nst_linear
1257 !$omp do
1258 do ip = 1, np
1259 dest%zff_linear(ip, ist) = cmplx(this%dff_linear(ip, ist), m_zero, real64)
1260 end do
1261 !$omp end do nowait
1262 end do
1263 !$omp end parallel
1264 end select
1265 else
1266 message(1) = "Error! This should not happen."
1267 call messages_fatal(1)
1268 end if
1269
1270 call profiling_out("BATCH_COPY_DATA_TO")
1271 pop_sub(batch_copy_data_to)
1272 end subroutine batch_copy_data_to
1273
1274 ! --------------------------------------------------------------
1276 !
1277 subroutine batch_check_compatibility_with(this, target, only_check_dim, type_check)
1278 class(batch_t), intent(in) :: this
1279 class(batch_t), intent(in) :: target
1280 logical, optional, intent(in) :: only_check_dim
1281 logical, optional, intent(in) :: type_check
1282
1284
1285 if (optional_default(type_check, .true.)) then
1286 assert(this%type() == target%type())
1287 end if
1288 if (.not. optional_default(only_check_dim, .false.)) then
1289 assert(this%nst_linear == target%nst_linear)
1290 end if
1291 assert(this%status() == target%status())
1292 assert(this%dim == target%dim)
1293
1295
1296 end subroutine batch_check_compatibility_with
1297
1298!--------------------------------------------------------------
1301 subroutine batch_build_indices(this, st_start, st_end)
1302 class(batch_t), intent(inout) :: this
1303 integer, intent(in) :: st_start
1304 integer, intent(in) :: st_end
1305
1306 integer :: idim, ii, ist
1307
1308 push_sub(batch_build_indices)
1309
1310 do ist = st_start, st_end
1311 ! now we also populate the linear array
1312 do idim = 1, this%dim
1313 ii = this%dim*(ist - st_start) + idim
1314 this%ist_idim_index(ii, 1) = ist
1315 this%ist_idim_index(ii, 2) = idim
1316 end do
1317 this%ist(ist - st_start + 1) = ist
1318 end do
1319
1320 ! compute packed sizes
1321 this%pack_size(1) = pad_pow2(this%nst_linear)
1322 this%pack_size(2) = this%np
1323 if (accel_is_enabled()) this%pack_size(2) = accel_padded_size(this%pack_size(2))
1324
1325 this%pack_size_real = this%pack_size
1326 if (type_is_complex(this%type())) this%pack_size_real(1) = 2*this%pack_size_real(1)
1327
1328 pop_sub(batch_build_indices)
1329 end subroutine batch_build_indices
1330
1331
1332#include "real.F90"
1333#include "batch_inc.F90"
1334#include "undef.F90"
1335
1336#include "complex.F90"
1337#include "batch_inc.F90"
1338#include "undef.F90"
1339
1340end module batch_oct_m
1341
1342!! Local Variables:
1343!! mode: f90
1344!! coding: utf-8
1345!! End:
initialize a batch with existing memory
Definition: batch.F90:278
double log2(double __x) __attribute__((__nothrow__
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:1006
integer, parameter, public accel_mem_read_write
Definition: accel.F90:186
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:638
subroutine zbatch_pack_copy(this)
copy data from the unpacked to the packed arrays
Definition: batch.F90:1964
subroutine, public batch_write_packed_to_device(this, async)
Definition: batch.F90:1060
integer, parameter, public batch_not_packed
functions are stored in CPU memory, unpacked order
Definition: batch.F90:287
integer, parameter, public batch_device_packed
functions are stored in device memory in packed order
Definition: batch.F90:287
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:1789
subroutine batch_check_compatibility_with(this, target, only_check_dim, type_check)
check whether two batches have compatible dimensions (and type)
Definition: batch.F90:1373
logical pure function batch_is_packed(this)
Definition: batch.F90:672
subroutine dbatch_unpack_copy(this)
copy data from the packed to the unpacked arrays
Definition: batch.F90:1687
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:1544
subroutine batch_write_unpacked_to_device(this)
Definition: batch.F90:897
subroutine batch_do_unpack(this, copy, force, async)
unpack a batch
Definition: batch.F90:801
subroutine batch_finish_unpack(this)
finish the unpacking if do_unpack() was called with async=.true.
Definition: batch.F90:883
subroutine zbatch_allocate_unpacked_host(this)
allocate host (CPU) memory for unpacked data of type TYPE_CMPLX
Definition: batch.F90:1875
subroutine batch_deallocate_packed_device(this)
release packed device memory
Definition: batch.F90:400
integer pure function batch_type_as_integer(this)
For debuging purpose only.
Definition: batch.F90:647
subroutine batch_do_pack_generic(this, copy, async)
pack the data in a batch
Definition: batch.F90:696
integer function batch_inv_index(this, cind)
inverse index lookup
Definition: batch.F90:1102
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:1515
subroutine batch_allocate_packed_host(this)
allocate host (CPU) memory for packed data
Definition: batch.F90:434
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:1925
subroutine zbatch_allocate_packed_host(this)
allocate host (CPU) memory for packed data of type TYPE_CMPLX
Definition: batch.F90:1901
subroutine batch_clone_to(this, dest, pack, copy_data, new_np, special, dest_type)
clone a batch to a new batch
Definition: batch.F90:511
subroutine batch_remote_access_stop(this, rma_win)
stop the remote access to the batch
Definition: batch.F90:1209
subroutine batch_read_device_to_unpacked(this)
Definition: batch.F90:982
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:1854
subroutine dbatch_allocate_packed_host(this)
allocate host (CPU) memory for packed data of type TYPE_FLOAT
Definition: batch.F90:1591
subroutine batch_clone_to_array(this, dest, n_batches, pack, copy_data, new_np, special, dest_type)
Definition: batch.F90:539
subroutine batch_allocate_packed_device(this)
allocate device (GPU) memory for packed data
Definition: batch.F90:453
subroutine batch_build_indices(this, st_start, st_end)
build the index ist(:) and ist_idim_index(:,:) and set pack_size
Definition: batch.F90:1397
integer pure function batch_ist_idim_to_linear(this, cind)
direct index lookup
Definition: batch.F90:1119
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:292
subroutine batch_do_pack_target(this, target, copy, async, cpu_only)
pack the data in a batch
Definition: batch.F90:727
integer pure function batch_linear_to_ist(this, linear_index)
get state index ist from linear (combined dim and nst) index
Definition: batch.F90:1137
subroutine batch_copy_to(this, dest, pack, copy_data, new_np, special, dest_type)
make a copy of a batch
Definition: batch.F90:575
subroutine, public batch_read_device_to_packed(this, async)
Definition: batch.F90:1079
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:1479
subroutine batch_allocate_unpacked_host(this)
allocate host (CPU) memory for unpacked data
Definition: batch.F90:415
subroutine batch_init_empty(this, dim, nst, np)
initialize an empty batch
Definition: batch.F90:471
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:1615
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:1825
integer pure function batch_linear_to_idim(this, linear_index)
extract idim from linear index
Definition: batch.F90:1148
subroutine batch_remote_access_start(this, mpi_grp, rma_win)
start remote access to a batch on another node
Definition: batch.F90:1166
subroutine batch_copy_data_to(this, np, dest, async)
copy data to another batch.
Definition: batch.F90:1228
subroutine dbatch_allocate_unpacked_host(this)
allocate host (CPU) memory for unpacked data of type TYPE_FLOAT
Definition: batch.F90:1565
subroutine dbatch_pack_copy(this)
copy data from the unpacked to the packed arrays
Definition: batch.F90:1654
integer pure function batch_status(this)
return the status of a batch
Definition: batch.F90:664
subroutine batch_deallocate_unpacked_host(this)
release unpacked host memory
Definition: batch.F90:344
integer, parameter, public batch_packed
functions are stored in CPU memory, in transposed (packed) order
Definition: batch.F90:287
subroutine batch_deallocate_packed_host(this)
release packed host memory
Definition: batch.F90:375
integer(int64) function batch_pack_total_size(this)
Definition: batch.F90:680
subroutine batch_end(this, copy)
finalize a batch and release allocated memory, if necessary
Definition: batch.F90:306
subroutine zbatch_unpack_copy(this)
copy data from the packed to the unpacked arrays
Definition: batch.F90:1997
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), parameter, public type_cmplx
Definition: types.F90:136
type(type_t), parameter, public type_float
Definition: types.F90:135
type(type_t), parameter, public type_none
Definition: types.F90:134
Class defining batches of mesh functions.
Definition: batch.F90:162
int true(void)