!
! Copyright (C) 2021, MaX CoE
! Distributed under the MIT License 
! (license terms are at http://opensource.org/licenses/MIT).
!
!--
!
! Testing: devxlib_memcpy, devxlib_mapping, dev_auxfunc
!
!==================================================================
!==================================================================
! *DO NOT EDIT*: automatically generated from test_mapping.jf90
!==================================================================
!==================================================================
!
#include<devxlib_macros.h>
#include<devxlib_defs.h>
!
program test_mapping
  !
  ! This program tests the routines and interfaces related to
  ! device_memcpy and some device_auxfunc.
  !
  use iso_fortran_env, only : int32, int64, real32, real64
  use devxlib_memcpy
  use devxlib_mapping
  use devxlib_auxfunc

  implicit none

  integer(int64) :: cnt, count_max
  real(real64), parameter :: thr=1.0d-6
  integer,      parameter :: nranks={{dimensions}}
  integer(int64) :: ndim(nranks)
  integer(int64) :: bounds(2*nranks)
  real(real64):: t0, t1, count_rate
  logical :: is_mapped, lfail_mapping
  integer :: npass, nfail
  integer(int32) :: ierr
  integer :: nfail_mapping


{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
  {{t}}({{p.val}}), allocatable :: A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
  {{t}}({{p.val}}), allocatable :: A_hst2__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
  {{t}}({{p.val}}), allocatable :: A_hst3__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
  {{t}}({{p.val}}), allocatable DEV_ATTR :: A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
  {{t}}({{p.val}}), allocatable DEV_ATTR :: A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
  {% if t=="complex" or t=="integer" or t=="logical" %}
  real({{p.val}}), allocatable :: A_rtmp__{{p.name}}_{{d}}d({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
  {% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
  
  integer :: i
  character(256) :: arg, str

!
!============================
! get dims
!============================
!
  ! defaults
  ndim(:)=100
  do i=1,2*nranks,2
     bounds(i)   = 1
     bounds(i+1) = ndim((i+1)/2)
  enddo

  i=0
  do
    call get_command_argument(i, arg)
    if (len_trim(arg) == 0) exit
    !
    select case (trim(arg))
    case("-h","--help")
      write(6,"(a)") "Usage: "
      write(6,"(a)") "   ./test_mapping.x [--dims <vals>] [--bounds <vals>]"
      stop
    end select
    !
    i = i+1
    call get_command_argument(i, str)
    if (len_trim(str) == 0) exit
    !
    select case (trim(arg))
    case("-dims","--dims")
      read(str,*,iostat=ierr) ndim(:)
      if (ierr/=0) STOP "reading cmd-line args: dims"
    case("-bounds","--bounds")
      read(str,*,iostat=ierr) bounds(:)
      if (ierr/=0) STOP "reading cmd-line args: bounds"
    end select
  enddo
  !
  write(6,"(/,a,/)") "Running test with params: "
  write(6,"(3x,a,10i5)") "  ndim: ", ndim(:)
  write(6,"(3x,a,10i5)") "bounds: ", bounds(:)
  write(6,"()")
  !
  npass=0
  nfail=0
  nfail_mapping=0

!
!============================
! check memcpy
!============================
!

{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
  !
  !=====================
  write(6,"(/,3x,a)") "checking {{p.name}}_{{t[0]|lower}}{{d}}d ..." 
  call system_clock(cnt, count_rate, count_max)
  t0=cnt/count_rate
  lfail_mapping=.false.
  !
  is_mapped = devxlib_mapped( A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d ) .or. &
              devxlib_mapped( A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d )
  if (is_mapped) then
     nfail_mapping=nfail_mapping+1
     lfail_mapping=.true.
     write(6,"(3x,a)") "mem mapping check-pre FAILED" 
  endif
  !
  ! allocations
  allocate( A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(1,2*d,2)%}bounds({{dd}}):bounds({{dd+1}}){% if not loop.last %},{%- endif %}{%endfor%}) )
  allocate( A_hst2__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(1,2*d,2)%}bounds({{dd}}):bounds({{dd+1}}){% if not loop.last %},{%- endif %}{%endfor%}) )
  allocate( A_hst3__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(1,2*d,2)%}bounds({{dd}}):bounds({{dd+1}}){% if not loop.last %},{%- endif %}{%endfor%}) )
  allocate( A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(1,2*d,2)%}bounds({{dd}}):bounds({{dd+1}}){% if not loop.last %},{%- endif %}{%endfor%}) )
  allocate( A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d({% for dd in range(1,2*d,2)%}bounds({{dd}}):bounds({{dd+1}}){% if not loop.last %},{%- endif %}{%endfor%}) )
{%- if d == 1 %}
  call devxlib_map(A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d)
  call devxlib_map(A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d)
{%- else %}
  call devxlib_map(A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d)
  call devxlib_map(A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d)
{%- endif %}
  {%- if t=="complex" or t=="integer" or t=="logical" %}
  allocate( A_rtmp__{{p.name}}_{{d}}d({% for dd in range(1,2*d,2)%}bounds({{dd}}):bounds({{dd+1}}){% if not loop.last %},{%- endif %}{%endfor%}) )
  {%endif%}
  !
  is_mapped = devxlib_mapped( A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d )
  if (.not.is_mapped) then
    nfail_mapping=nfail_mapping+1
    lfail_mapping=.true.
    write(6,"(3x,a)") "mem mapping check-post FAILED" 
  endif
  !
  ! init
  {%- if t=="complex" %}
  call random_number( A_rtmp__{{p.name}}_{{d}}d )
  A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d=A_rtmp__{{p.name}}_{{d}}d
  call random_number( A_rtmp__{{p.name}}_{{d}}d )
  A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d=A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d+cmplx(0.0,1.0)*A_rtmp__{{p.name}}_{{d}}d
  {% elif t=="integer" %}
  call random_number( A_rtmp__{{p.name}}_{{d}}d )
  A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d=int( 1000*A_rtmp__{{p.name}}_{{d}}d )
  {% elif t=="logical" %}
  call random_number( A_rtmp__{{p.name}}_{{d}}d )
  A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d=( nint( A_rtmp__{{p.name}}_{{d}}d ) == 1 )
  {%else%}
  call random_number( A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d )
  {%endif%}
  !
  ! mem copy h2d
  call devxlib_memcpy_h2d(A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d, A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d)
  !
  ! mem copy
  call devxlib_memcpy_d2d(A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d, A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d )
  !
  {%- if t=="complex" %}
  ! make cmplx conjg
  call devxlib_conjg_d( A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d )
  {%endif%}
  !
  ! mem copy d2h
  call devxlib_memcpy_d2h(A_hst2__{{p.name}}_{{t[0]|lower}}{{d}}d, A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d)
  !
  {%- if t=="complex" %}
  ! retrieve conjg data
  call devxlib_conjg_h( A_hst2__{{p.name}}_{{t[0]|lower}}{{d}}d )
  {%endif%}
  !
  ! mem copy h2h
  call devxlib_memcpy_h2h(A_hst3__{{p.name}}_{{t[0]|lower}}{{d}}d, A_hst2__{{p.name}}_{{t[0]|lower}}{{d}}d)
  !
  ! check
  if (lfail_mapping) write(6,"(3x,a)") "Mapping FAILED" 
  !
  {%- if t=="logical" %}
  if ( any( A_hst3__{{p.name}}_{{t[0]|lower}}{{d}}d .neqv. A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d ) ) then
  {%- else %}
  if ( any(abs(A_hst3__{{p.name}}_{{t[0]|lower}}{{d}}d -A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d )> thr) ) then
  {%- endif %}
     !
     write(6,"(3x,a)") "FAILED" 
     nfail=nfail+1
  else
     write(6,"(3x,a)") "passed" 
     npass=npass+1
  endif
  !
  deallocate(A_hst1__{{p.name}}_{{t[0]|lower}}{{d}}d)
  deallocate(A_hst2__{{p.name}}_{{t[0]|lower}}{{d}}d)
  deallocate(A_hst3__{{p.name}}_{{t[0]|lower}}{{d}}d)
  !
  call devxlib_unmap(A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d, ierr)
  call devxlib_unmap(A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d, ierr)
  deallocate(A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d)
  deallocate(A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d)
  !
  is_mapped = devxlib_mapped( A_dev1__{{p.name}}_{{t[0]|lower}}{{d}}d ) .or. &
              devxlib_mapped( A_dev2__{{p.name}}_{{t[0]|lower}}{{d}}d )
  if (is_mapped) then
    nfail_mapping=nfail_mapping+1
    lfail_mapping=.true.
    write(6,"(3x,a)") "mem mapping check-post2 FAILED" 
  endif
  !
  call system_clock(cnt, count_rate, count_max)
  t1=cnt/count_rate
  write(6,"(3x,a,f12.6,' sec')") "Timing: ", t1-t0
  !
{% endfor %}
{% endfor %}
{% endfor %}

  !
  ! summary
  !
  write(6,"(/,a)") "# Test SUMMARY:"
  write(6,"(3x,a,i5)") "# passed: ", npass
  write(6,"(3x,a,i5)") "# failed: ", nfail
  write(6,"(3x,a,i5)") "# failed mapping ", nfail_mapping
  write(6,"()")

end program test_mapping

