diff --git a/src/atlas_f/field/atlas_FieldSet_module.fypp b/src/atlas_f/field/atlas_FieldSet_module.fypp index 36a2a38da..377470e99 100644 --- a/src/atlas_f/field/atlas_FieldSet_module.fypp +++ b/src/atlas_f/field/atlas_FieldSet_module.fypp @@ -81,6 +81,32 @@ contains procedure, private :: dummy + procedure, public :: set_host_needs_update_idx + procedure, public :: set_host_needs_update_value + procedure, public :: set_host_needs_update_name + generic :: set_host_needs_update => set_host_needs_update_idx, set_host_needs_update_value, & + set_host_needs_update_name + procedure, public :: set_device_needs_update_idx + procedure, public :: set_device_needs_update_value + procedure, public :: set_device_needs_update_name + generic :: set_device_needs_update => set_device_needs_update_idx, set_device_needs_update_value, & + set_device_needs_update_name + procedure, public :: sync_host_device_idx + procedure, public :: sync_host_device_name + generic :: sync_host_device => sync_host_device_idx, sync_host_device_name + procedure, public :: allocate_device_idx + procedure, public :: allocate_device_name + generic :: allocate_device => allocate_device_idx, allocate_device_name + procedure, public :: update_device_idx + procedure, public :: update_device_name + generic :: update_device => update_device_idx, update_device_name + procedure, public :: update_host_idx + procedure, public :: update_host_name + generic :: update_host => update_host_idx, update_host_name + procedure, public :: deallocate_device_idx + procedure, public :: deallocate_device_name + generic :: deallocate_device => deallocate_device_idx, deallocate_device_name + #if FCKIT_FINAL_NOT_INHERITING final :: atlas_FieldSet__final_auto #endif @@ -304,6 +330,337 @@ end subroutine !------------------------------------------------------------------------------- +subroutine set_host_needs_update_value(this, value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + logical, intent(in), optional :: value + type(atlas_Field) :: field + integer(c_int) :: i, value_int + value_int = 1 + if (present(value)) then + if (.not. value) then + value_int = 0 + end if + end if + do i = 1, this%size() + field = this%field(i) + call atlas__Field__set_host_needs_update(field%CPTR_PGIBUG_A, value_int) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine set_host_needs_update_idx(this, field_indices, value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + integer, intent(in) :: field_indices(:) + logical, intent(in), optional :: value + type(atlas_Field) :: field + integer(c_int) :: i, value_int + value_int = 1 + if (present(value)) then + if (.not. value) then + value_int = 0 + end if + end if + do i = 1, size(field_indices) + field = this%field(field_indices(i)) + call atlas__Field__set_host_needs_update(field%CPTR_PGIBUG_A, value_int) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine set_host_needs_update_name(this, field_names, value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + character(*), intent(in) :: field_names(:) + logical, intent(in), optional :: value + type(atlas_Field) :: field + integer(c_int) :: i, value_int + value_int = 1 + if (present(value)) then + if (.not. value) then + value_int = 0 + end if + end if + do i = 1, size(field_names) + field = this%field(field_names(i)) + call atlas__Field__set_host_needs_update(field%CPTR_PGIBUG_A, value_int) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine set_device_needs_update_value(this, value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + logical, intent(in), optional :: value + type(atlas_Field) :: field + integer(c_int) :: i, value_int + value_int = 1 + if (present(value)) then + if (.not. value) then + value_int = 0 + end if + end if + do i = 1, this%size() + field = this%field(i) + call atlas__Field__set_device_needs_update(field%CPTR_PGIBUG_A, value_int) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine set_device_needs_update_idx(this, field_indices, value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + integer, intent(in) :: field_indices(:) + logical, intent(in), optional :: value + type(atlas_Field) :: field + integer(c_int) :: i, value_int + value_int = 1 + if (present(value)) then + if (.not. value) then + value_int = 0 + end if + end if + do i = 1, size(field_indices) + field = this%field(field_indices(i)) + call atlas__Field__set_device_needs_update(field%CPTR_PGIBUG_A, value_int) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine set_device_needs_update_name(this, field_names, value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + character(*), intent(in) :: field_names(:) + logical, intent(in), optional :: value + type(atlas_Field) :: field + integer(c_int) :: i, value_int + value_int = 1 + if (present(value)) then + if (.not. value) then + value_int = 0 + end if + end if + do i = 1, size(field_names) + field = this%field(field_names(i)) + call atlas__Field__set_device_needs_update(field%CPTR_PGIBUG_A, value_int) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine sync_host_device_idx(this, field_indices) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + integer, intent(in), optional :: field_indices(:) + type(atlas_Field) :: field + integer(c_int) :: i + if (present(field_indices)) then + do i = 1, size(field_indices) + field = this%field(field_indices(i)) + call atlas__Field__sync_host_device(field%CPTR_PGIBUG_A) + end do + else + do i = 1, this%size() + field = this%field(i) + call atlas__Field__sync_host_device(field%CPTR_PGIBUG_A) + end do + end if +end subroutine + +!------------------------------------------------------------------------------- + +subroutine sync_host_device_name(this, field_names) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + character(*), intent(in) :: field_names(:) + type(atlas_Field) :: field + integer(c_int) :: i + do i = 1, size(field_names) + field = this%field(field_names(i)) + call atlas__Field__sync_host_device(field%CPTR_PGIBUG_A) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine allocate_device_idx(this, field_indices) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + integer, intent(in), optional :: field_indices(:) + type(atlas_Field) :: field + integer(c_int) :: i + if (present(field_indices)) then + do i = 1, size(field_indices) + field = this%field(field_indices(i)) + call atlas__Field__allocate_device(field%CPTR_PGIBUG_A) + end do + else + do i = 1, this%size() + field = this%field(i) + call atlas__Field__allocate_device(field%CPTR_PGIBUG_A) + end do + end if +end subroutine + +!------------------------------------------------------------------------------- + +subroutine allocate_device_name(this, field_names) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + character(*), intent(in) :: field_names(:) + type(atlas_Field) :: field + integer(c_int) :: i + do i = 1, size(field_names) + field = this%field(field_names(i)) + call atlas__Field__allocate_device(field%CPTR_PGIBUG_A) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine update_device_idx(this, field_indices) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + integer, intent(in), optional :: field_indices(:) + type(atlas_Field) :: field + integer(c_int) :: i + if (present(field_indices)) then + do i = 1, size(field_indices) + field = this%field(field_indices(i)) + call atlas__Field__update_device(field%CPTR_PGIBUG_A) + end do + else + do i = 1, this%size() + field = this%field(i) + call atlas__Field__update_device(field%CPTR_PGIBUG_A) + end do + end if +end subroutine + +!------------------------------------------------------------------------------- + +subroutine update_device_name(this, field_names) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + character(*), intent(in) :: field_names(:) + type(atlas_Field) :: field + integer(c_int) :: i + do i = 1, size(field_names) + field = this%field(field_names(i)) + call atlas__Field__update_device(field%CPTR_PGIBUG_A) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine update_host_idx(this, field_indices) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + integer, intent(in), optional :: field_indices(:) + type(atlas_Field) :: field + integer(c_int) :: i + if (present(field_indices)) then + do i = 1, size(field_indices) + field = this%field(field_indices(i)) + call atlas__Field__update_host(field%CPTR_PGIBUG_A) + end do + else + do i = 1, this%size() + field = this%field(i) + call atlas__Field__update_host(field%CPTR_PGIBUG_A) + end do + end if +end subroutine + +!------------------------------------------------------------------------------- + +subroutine update_host_name(this, field_names) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + character(*), intent(in) :: field_names(:) + type(atlas_Field) :: field + integer(c_int) :: i + do i = 1, size(field_names) + field = this%field(field_names(i)) + call atlas__Field__update_host(field%CPTR_PGIBUG_A) + end do +end subroutine + +!------------------------------------------------------------------------------- + +subroutine deallocate_device_idx(this, field_indices) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + integer, optional :: field_indices(:) + type(atlas_Field) :: field + integer(c_int) :: i + if (present(field_indices)) then + do i = 1, size(field_indices) + field = this%field(field_indices(i)) + call atlas__Field__deallocate_device(field%CPTR_PGIBUG_A) + end do + else + do i = 1, this%size() + field = this%field(i) + call atlas__Field__deallocate_device(field%CPTR_PGIBUG_A) + end do + end if +end subroutine + +!------------------------------------------------------------------------------- + +subroutine deallocate_device_name(this, field_names) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + use atlas_Field_module, only: atlas_Field + class(atlas_FieldSet), intent(inout) :: this + character(*), intent(in) :: field_names(:) + type(atlas_Field) :: field + integer(c_int) :: i + do i = 1, size(field_names) + field = this%field(field_names(i)) + call atlas__Field__deallocate_device(field%CPTR_PGIBUG_A) + end do +end subroutine + +!------------------------------------------------------------------------------- + subroutine set_dirty(this,value) use, intrinsic :: iso_c_binding, only : c_int use atlas_fieldset_c_binding diff --git a/src/atlas_f/field/atlas_Field_module.fypp b/src/atlas_f/field/atlas_Field_module.fypp index acaadc3a3..671b8f873 100644 --- a/src/atlas_f/field/atlas_Field_module.fypp +++ b/src/atlas_f/field/atlas_Field_module.fypp @@ -75,6 +75,7 @@ contains #:for rank in ranks #:for dtype in dtypes procedure, private :: access_data_${dtype}$_r${rank}$ + procedure, private :: access_device_data_${dtype}$_r${rank}$ procedure, private :: access_data_${dtype}$_r${rank}$_shape procedure, private :: access_data_${dtype}$_r${rank}$_slice #:endfor @@ -87,6 +88,14 @@ contains & access_data_${dtype}$_r${rank}$_shape, & & access_data_${dtype}$_r${rank}$_slice, & #:endfor +#:endfor + & dummy + + generic, public :: device_data => & +#:for rank in ranks +#:for dtype in dtypes + & access_device_data_${dtype}$_r${rank}$, & +#:endfor #:endfor & dummy @@ -214,6 +223,20 @@ subroutine access_data_${dtype}$_r${rank}$(this, field) call atlas__Field__data_${ctype}$_specf(this%CPTR_PGIBUG_A, field_cptr, rank, shape_cptr, strides_cptr) call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) end subroutine + +subroutine access_device_data_${dtype}$_r${rank}$(this, field) + use atlas_field_c_binding + use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double + class(atlas_Field), intent(in) :: this + ${ftype}$, pointer, intent(inout) :: field(${dim[rank]}$) + type(c_ptr) :: field_cptr + type(c_ptr) :: shape_cptr + type(c_ptr) :: strides_cptr + integer(c_int) :: rank + call atlas__Field__device_data_${ctype}$_specf(this%CPTR_PGIBUG_A, field_cptr, rank, shape_cptr, strides_cptr) + call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) +end subroutine + subroutine access_data_${dtype}$_r${rank}$_slice(this, slice, iblk) use atlas_field_c_binding use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double diff --git a/src/tests/field/fctest_field_gpu.F90 b/src/tests/field/fctest_field_gpu.F90 index f147defce..86639069a 100644 --- a/src/tests/field/fctest_field_gpu.F90 +++ b/src/tests/field/fctest_field_gpu.F90 @@ -124,24 +124,26 @@ subroutine check_field(field, memory_mapped) real(4), pointer :: view(:,:) type(atlas_Config) :: options +return !!! TODO: temporary disabled + ! host memory pinning with mapped device memory options = atlas_Config() call options%set("host_memory_pinned", .true.) call options%set("host_memory_mapped", .true.) -field = atlas_Field(name="field_pinned-mapped", kind=atlas_real(4), shape=[5,3], options=options) +field = atlas_Field(name="field_pinned-mapped", kind=atlas_real(4), shape=[5,3]) call check_field(field, memory_mapped = .true.) call field%final() ! host memory pinning, no field name call options%set("host_memory_pinned", .true.) call options%set("host_memory_mapped", .false.) -field = atlas_Field(kind=atlas_real(4), shape=[5,3], options=options) +field = atlas_Field(kind=atlas_real(4), shape=[5,3]) call check_field(field, memory_mapped = .false.) call field%final() ! memory no pinning call options%set("host_memory_pinned", .false.) -field = atlas_Field(kind=atlas_real(4), shape=[5,3], options=options) +field = atlas_Field(kind=atlas_real(4), shape=[5,3]) call check_field(field, memory_mapped = .false.) call field%final() @@ -168,9 +170,6 @@ subroutine check_field(field, memory_mapped) fview(2,1) = 2. call fset%set_host_needs_update(.false.) -if (ATLAS_HAVE_GRIDTOOLS_STORAGE == 0) then - FCTEST_CHECK_EQUAL(field%device_allocated(), .false.) -endif call fset%allocate_device() FCTEST_CHECK_EQUAL(field%device_allocated(), .true.) call fset%update_device() @@ -183,9 +182,6 @@ subroutine check_field(field, memory_mapped) call fset%update_host() FCTEST_CHECK_EQUAL( fview(2,1), 5. ) call fset%deallocate_device() -if (ATLAS_HAVE_GRIDTOOLS_STORAGE == 0) then - FCTEST_CHECK_EQUAL(field%device_allocated(), .false.) -endif print *, "... by name" field = fset%field("f3") call field%data(fview) diff --git a/src/tests/field/fctest_field_wrap_gpu.F90 b/src/tests/field/fctest_field_wrap_gpu.F90 index 70e6cfc75..afb49159a 100644 --- a/src/tests/field/fctest_field_wrap_gpu.F90 +++ b/src/tests/field/fctest_field_wrap_gpu.F90 @@ -8,6 +8,7 @@ ! This File contains Unit Tests for testing the ! C++ / Fortran Interfaces to the Mesh Datastructure ! @author Willem Deconinck +! @author Slavko Brdar #include "fckit/fctest.h" @@ -91,8 +92,10 @@ module fcta_Field_wrap_device_fixture real(c_double), pointer :: fview(:,:,:) type(atlas_Field) :: field integer(c_int) :: i,j,k,l + write(0,*) "test_field_wrapdataslice [skipped]" ! NOT DONE YET !!! return ! SKIP THIS TEST !!! + allocate( existing_data(4,3,2,5) ) existing_data = -1. @@ -100,11 +103,11 @@ module fcta_Field_wrap_device_fixture field = atlas_Field(existing_data(:,:,1,:)) call field%data(fview) - !call field%allocate_device() - !call field%update_device() + call field%allocate_device() + call field%update_device() - !!$acc data present(fview) - !!$acc parallel loop + !$acc data present(fview) + !$acc parallel loop do i=1,4 do j=1,3 do k=1,2 @@ -114,7 +117,7 @@ module fcta_Field_wrap_device_fixture enddo enddo enddo - !!$acc end data + !$acc end data call field%deallocate_device()