!
!= 2 ã¤ã®å¤‰æ•°ã®æ¬¡å…ƒæ§‹æˆã®å…±é€šåŒ–
!
! Authors::   Eizi TOYODA, Yasuhiro MORIKAWA
! Version::   $Id: gtvarlimitbinary.f90,v 1.3 2009-05-25 09:55:57 morikawa Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2000-2005. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]
!
! ä»¥ä¸‹ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã€é–¢æ•°ã¯ gtdata_generic ã‹ã‚‰ gtdata_generic#Transform
! ã¨ã—ã¦æä¾›ã•ã‚Œã¾ã™ã€‚

subroutine GTVarXformBinary(var1, var2, err)
  !
  !== 2 ã¤ã®å¤‰æ•°ã®æ¬¡å…ƒé…ç½®ã®å…±é€šåŒ–
  !
  ! å¤‰æ•° <b>var1</b> ã®æ¬¡å…ƒæ§‹æˆãŒ <b>var2</b> ã®æ¬¡å…ƒæ§‹æˆã¨åŒã˜ã«ãªã‚‹ã‚ˆã†ã«
  ! ç¯„å›²æ‹˜æŸã‚’è¡Œã„ã¾ã™ã€‚éŽå‰°ãªæ¬¡å…ƒãŒ <b>var1</b> ã«ã‚ã‚‹å ´åˆã€éš è”½
  ! ã‚’è¡Œã„ã¾ã™ã€‚(è¿½åŠ ã‚‚ã§ãã‚‹ã‚ˆã†ã«ã™ã‚‹äºˆå®šã§ã™)ã€‚
  !
  ! ã‚¨ãƒ©ãƒ¼ãŒç”Ÿã˜ãŸå ´åˆã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’å‡ºåŠ›
  ! ã—ã¦ãƒ—ãƒã‚°ãƒ©ãƒ ã¯å¼·åˆ¶çµ‚äº†ã—ã¾ã™ã€‚*err* ã‚’ä¸Žãˆã¦ã‚ã‚‹å ´åˆã«ã¯
  ! ã®å¼•æ•°ã« .true. ãŒè¿”ã‚Šã€ãƒ—ãƒã‚°ãƒ©ãƒ ã¯çµ‚äº†ã—ã¾ã›ã‚“ã€‚
  !
  !--
  ! äºŒã¤ã®å¤‰æ•° var1, var2 ã«å…¥å‡ºåŠ›ç¯„å›²æ‹˜æŸã‚’åŠ ãˆã¦æ¬¡å…ƒé…ç½®ã‚’å…±é€šåŒ–ã™ã‚‹ã€‚
  ! çµæžœã®æ¬¡å…ƒæ§‹æˆã¯ã¨ã‚Šã‚ãˆãšãƒ¢ãƒ‡ãƒ«ã§ä½¿ãˆã‚‹ã‚ˆã†ã«æ±ºã‚ãŸã€‚
  !    var2 ã®ç©ºé–“ã‚’ä¿æŒã™ã‚‹ã€‚var1 ã‚’å¤‰å½¢ã™ã‚‹ã€‚
  !    var2 ã®æ¬¡å…ƒã¯ (æœ‰å¹…ãƒ»ç¸®é€€ã¨ã‚‚ã«) var2 ã«ãŠã‘ã‚‹å¹…ãŒã¨ã‚‰ã‚Œã‚‹ã€‚
  !    ã—ãŸãŒã£ã¦ var1 ã«ãŠã„ã¦ã¯å˜åœ¨ã—ãªã„ã‹ var2 ã‚’ã‚«ãƒãƒ¼ã™ã‚‹å¹…ã§
  !    ãªã‘ã‚Œã°ãªã‚‰ãªã„ã€‚
  !    var2 ã«ãªã„ var1 ã®æ¬¡å…ƒã¯è¦‹ãˆãªã„ã‚ˆã†ã«ãªã‚‹ã®ã§ç¸®é€€ã—ã¦ã„ã‚‹ã‹
  !    å˜åœ¨ã—ãªã„ã®ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„ã€‚
  !++
  use gtdata_types, only: gt_variable
  use gtdata_generic, only: inquire, get_slice
  use gtdata_internal_map, only: map_allocate, map_apply, gt_dimmap, gtvar_dump
  use dc_error, only: StoreError, GT_ENOMATCHDIM, GT_EFAKE, DC_NOERR
  use dc_trace, only: beginsub, endsub, DbgMessage
  implicit none
  type(GT_VARIABLE), intent(inout):: var1, var2
  logical, intent(out), optional:: err
  integer:: ndim1, ndim2, ndimo
  integer, allocatable:: map1(:), map2(:)
  type(GT_DIMMAP), pointer:: newmap(:)
  integer:: i, j, stat
  character(*), parameter:: subnam = "GTVarXformBinary"
continue
  call beginsub(subnam, 'mapid=[%d, %d]', i=(/var1%mapid, var2%mapid/))
  call gtvar_dump(var1)
  call gtvar_dump(var2)
  !
  ! äºŒã¤ã®å¤‰æ•° var1, var2 ã‹ã‚‰å…±æœ‰æ¬¡å…ƒã‚’èª¿ã¹ã€å¯¾å¿œè¡¨ map1, map2 ã‚’ã¤ãã‚‹ã€‚
  !
  if (present(err)) err = .false.
  call inquire(var1, alldims=ndim1)
  call inquire(var2, alldims=ndim2)
  ndimo = max(ndim1, ndim2, 0)
  allocate(map1(1:ndim1), map2(1:ndim2))
  call getmatch(var1, var2, ndim1, ndim2, map1, map2)
  call DbgMessage('map1=%*d map2=%*d', i=(/map1(1:ndim1), map2(1:ndim2)/), n=(/ndim1, ndim2/))
  if (all(map2(1:ndim2) == 0)) then
    stat = gt_enomatchdim
    goto 999
  endif
  !
  ! å†é…ç½®ãƒ†ãƒ¼ãƒ–ãƒ«ä½œæˆé–‹å§‹
  !
  ndimo = ndim2 + count(map1(1:ndim1) == 0)
  call map_allocate(newmap, ndimo)
  !
  ! 1..ndim2 ã¯ map2 ã«ã‚ˆã£ã¦ var2 ã®æ¬¡å…ƒãŸã¡ã«ãƒžãƒƒãƒ—ã™ã‚‹
  !
  newmap(1:ndim2)%dimno = map2(1:ndim2)
  call inquire(var2, allcount=newmap(1:ndim2)%allcount)
  call get_slice(var2, count=newmap(1:ndim2)%count)
  do, j = 1, ndim2
    if (map2(j) == 0) then
      newmap(j)%start = 1
      newmap(j)%stride = 1
      call inquire(var2, j, url=newmap(j)%url)
    else
      ! ä½ç½®å¯¾å¿œã«ã‚ˆã£ã¦ var1 å´ã§ã®é–‹å§‹ä½ç½®ã‚’æ±ºå®šã™ã‚‹
      call adjust_slice(var1, var2, map2(j), j, &
        & newmap(j)%start, newmap(j)%stride)
    endif
  enddo
  !
  ! ndim2+1.. ndimo ã¯ var2 ã«å¯¾å¿œã•ã›ã‚‰ã‚Œãªã„ var1 ã®æ¬¡å…ƒã‚’ãŠã
  !
  j = 0
  loop1: do, i = ndim2 + 1, ndimo
    do
      j = j + 1
      if (j > ndim1) exit loop1
      if (map1(j) <= 0) exit
    enddo
    newmap(i)%dimno = j
    call inquire(var1, dimord=j, allcount=newmap(i)%allcount)
    call get_slice(var1, dimord=j, start=newmap(i)%start, &
      & count=newmap(i)%count, stride=newmap(i)%stride)
  end do loop1
  !
  call map_apply(var1, map=newmap)
  !
  stat = dc_noerr
999 continue
  call StoreError(stat, subnam, err)
  call endsub(subnam, 'stat=%d', i=(/stat/))
  deallocate(map1, map2)
  return
contains

  !
  ! äºŒã¤ã®æ¬¡å…ƒå¤‰æ•°ã‚’èª¿ã¹ã€è»¸ä¸Šä½ç½®ãŒå¯¾å¿œã™ã‚‹ã‚ˆã†ã«
  ! start ã‚·ãƒ•ãƒˆæ•°ã¨ stride ãƒ•ã‚¡ã‚¯ã‚¿ã‚’æ±ºå®šã™ã‚‹
  !
  subroutine adjust_slice(var1, var2, idim1, idim2, offset, stepfact)
    use gtdata_generic, only: get, open, close
    type(GT_VARIABLE), intent(in):: var1, var2
    integer, intent(in):: idim1, idim2
    integer, intent(out):: offset, stepfact
    type(GT_VARIABLE):: var_d
    integer:: n, buf(1)
    real, allocatable:: val1(:), val2(:)
  continue
    call beginsub('adjust_slice')
    call open(var_d, source_var=var1, dimord=idim1, count_compact=.true.)
    call inquire(var_d, size=n)
    allocate(val1(n))
    call get(var_d, val1, n)
    call close(var_d)
    !
    call open(var_d, source_var=var2, dimord=idim2, count_compact=.true.)
    call inquire(var_d, size=n)
    allocate(val2(n))
    call get(var_d, val2, n)
    call close(var_d)
    !
    buf(1:1) = minloc(abs(val1(:) - val2(1)))
    offset = buf(1) - 1
    if (size(val2) < 2 .or. size(val1) < 2) then
      stepfact = 1
    else
      buf(1:1) = minloc(abs(val1(:) - val2(2)))
      stepfact = buf(1) - (offset + 1)
    endif
    !
    deallocate(val1, val2)
    call endsub('adjust_slice')
  end subroutine adjust_slice

  !
  ! äºŒã¤ã®å¤‰æ•°ã‹ã‚‰å…±æœ‰æ¬¡å…ƒã‚’èª¿ã¹ã€å¯¾å¿œè¡¨ map1, map2 ã‚’ä½œã‚‹ã€‚
  ! ã™ãªã‚ã¡ã€ãã‚Œãžã‚Œã®æ¬¡å…ƒç•ªå·ã‹ã‚‰ç›¸æ–¹ã®æ¬¡å…ƒç•ªå·ã‚’å¾—ã‚‹è¡¨ã§ã‚ã‚‹ã€‚
  !
  subroutine getmatch(var1, var2, ndim1, ndim2, map1, map2)
    use dc_types, only: STRING
    use dc_units, only: UNITS, add_okay, assignment(=), clear, deallocate
    use gtdata_generic, only: get_attr, open, close
    type(GT_VARIABLE), intent(in):: var1, var2
    integer, intent(in):: ndim1, ndim2
    integer, intent(out):: map1(:), map2(:)
    type(GT_VARIABLE):: var_d
    integer, allocatable:: map(:, :)
    integer:: i, j
    character(STRING):: su1, su2
    type(UNITS), allocatable:: u1(:), u2(:)
  continue
    call beginsub('getmatch')
    ! è¿”å´å€¤ã¯ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆ 0
    map1(:) = 0
    map2(:) = 0
    ! è¡¨ã®æ§‹ç¯‰: åˆæœŸå€¤ã¯æ¶ˆåŽ»æ³•ã‚’ã¨ã‚‹ã“ã¨ã‚’ç¤ºã™
    allocate(map(ndim1, ndim2))
    map(:, :) = 1

    ! å˜ä½ã«ã‚ˆã‚‹å¯¾å¿œ --- åŠ ç®—å¯èƒ½ã§ãªã‘ã‚Œã°å¯¾ã«ã—ãªã„
    ! å˜ä½ã®æ§‹æˆ
    allocate(u1(ndim1), u2(ndim2))
    do, i = 1, ndim1
      call open(var_d, var1, i, count_compact=.true.)
      call get_attr(var_d, 'units', su1)
      call close(var_d)
      call clear(u1(i))
      u1(i) = su1
    enddo
    do, j = 1, ndim2
      call open(var_d, var2, j, count_compact=.true.)
      call get_attr(var_d, 'units', su2)
      call close(var_d)
      call clear(u2(j))
      u2(j) = su2
    enddo
    ! å‡¦ç†
    do, i = 1, ndim1
      do, j = 1, ndim2
        if (.not. add_okay(u1(i), u2(j))) &
          & map(i, j) = 0
      enddo
    enddo
    ! å˜ä½ã®å»ƒæ£„
    do, i = 1, ndim1
      call deallocate(u1(i))
    enddo
    do, j = 1, ndim2
      call deallocate(u2(j))
    enddo
    deallocate(u1, u2)

    if (map_finished(map)) goto 1000

    ! --- it fails ---
    call endsub('getmatch', 'fail')
    return

1000 continue
    do, i = 1, ndim1
      call DbgMessage('map(%d, :)=%*d', i=(/i, map(i,:)/), n=(/ndim2/))
    enddo
    do, i = 1, ndim1
      if (all(map(i, :) <= 0)) then
        map1(i) = 0
      else
        map1(i:i) = maxloc(map(i, :))
      endif
    enddo
    do, j = 1, ndim2
      if (all(map(:, j) <= 0)) then
        map2(j) = 0
      else
        map2(j:j) = maxloc(map(:, j), dim=1)
      endif
    enddo
    call endsub('getmatch', 'okay')
  end subroutine getmatch

  logical function map_finished(map) result(result)
    integer:: map(:, :)
    integer:: i, j, ni
  continue
    call beginsub('map_finished')
    ni = size(map, dim=1)
    do, i = 1, ni
      if (count(map(i, :) > 0) > 1) then
        result = .false.
        goto 999
      endif
    enddo
    do, j = 1, ni
      if (count(map(j, :) > 0) > 1) then
        result = .false.
        goto 999
      endif
    enddo
    result = .true.
999 continue
    call endsub('map_finished')
  end function map_finished

end subroutine GTVarXformBinary