module gms_position
  use datatype
  use mem_manager
  implicit none
  interface pos_x
    module procedure pos_x_x
    module procedure pos_x_xy
    module procedure pos_x_xz
    module procedure pos_x_xyz
end interface

  interface pos_y
    module procedure pos_y_y
    module procedure pos_y_xy
    module procedure pos_y_yz
    module procedure pos_y_xyz
end interface

  interface pos_z
    module procedure pos_z_z
    module procedure pos_z_xz
    module procedure pos_z_yz
    module procedure pos_z_xyz
end interface

  interface pos_var_x
    module procedure pos_var_x_x
    module procedure pos_var_x_xy
    module procedure pos_var_x_xz
    module procedure pos_var_x_xyz
end interface

  interface pos_var_y
    module procedure pos_var_y_y
    module procedure pos_var_y_xy
    module procedure pos_var_y_yz
    module procedure pos_var_y_xyz
end interface

  interface pos_var_z
    module procedure pos_var_z_z
    module procedure pos_var_z_xz
    module procedure pos_var_z_yz
    module procedure pos_var_z_xyz
end interface

contains
  function pos_x_x(input) result(output)
    type(var_x), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub1 - plb1 - input%grid(1)) :: output

    if ( input%grid(1) == 0 ) then 
      do i = 0, pub1 - plb1 
        output(i) = x_minimum + dx * i 
      end do 
    else  
      do i = 0, pub1- plb1 - 1 
        output(i) = x_minimum + dx * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_x_x

  function pos_var_x_x(input) result(output)
    type(var_x), intent(in) :: input
    integer :: i, new_id 
     type(var_x):: output

     call get_new_id_x(new_id)
     output%id = new_id
     output%grid(1) = input%grid(1)
     output%grid(2) = -1
     output%grid(3) = -1
      do i = plb1+input%grid(1), pub1 
        work_x(i,1,1,new_id) = x_minimum + dx * (i - plb1 - input%grid(1) * 0.5D0)
      end do 
  end function pos_var_x_x

  function pos_x_xy(input) result(output)
    type(var_xy), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub1 - plb1 - input%grid(1)) :: output

    if ( input%grid(1) == 0 ) then 
      do i = 0, pub1 - plb1 
        output(i) = x_minimum + dx * i 
      end do 
    else  
      do i = 0, pub1- plb1 - 1 
        output(i) = x_minimum + dx * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_x_xy

  function pos_var_x_xy(input) result(output)
    type(var_xy), intent(in) :: input
    integer :: i, new_id 
     type(var_x):: output

     call get_new_id_x(new_id)
     output%id = new_id
     output%grid(1) = input%grid(1)
     output%grid(2) = -1
     output%grid(3) = -1
      do i = plb1+input%grid(1), pub1 
        work_x(i,1,1,new_id) = x_minimum + dx * (i - plb1 - input%grid(1) * 0.5D0)
      end do 
  end function pos_var_x_xy

  function pos_x_xz(input) result(output)
    type(var_xz), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub1 - plb1 - input%grid(1)) :: output

    if ( input%grid(1) == 0 ) then 
      do i = 0, pub1 - plb1 
        output(i) = x_minimum + dx * i 
      end do 
    else  
      do i = 0, pub1- plb1 - 1 
        output(i) = x_minimum + dx * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_x_xz

  function pos_var_x_xz(input) result(output)
    type(var_xz), intent(in) :: input
    integer :: i, new_id 
     type(var_x):: output

     call get_new_id_x(new_id)
     output%id = new_id
     output%grid(1) = input%grid(1)
     output%grid(2) = -1
     output%grid(3) = -1
      do i = plb1+input%grid(1), pub1 
        work_x(i,1,1,new_id) = x_minimum + dx * (i - plb1 - input%grid(1) * 0.5D0)
      end do 
  end function pos_var_x_xz

  function pos_x_xyz(input) result(output)
    type(var_xyz), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub1 - plb1 - input%grid(1)) :: output

    if ( input%grid(1) == 0 ) then 
      do i = 0, pub1 - plb1 
        output(i) = x_minimum + dx * i 
      end do 
    else  
      do i = 0, pub1- plb1 - 1 
        output(i) = x_minimum + dx * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_x_xyz

  function pos_var_x_xyz(input) result(output)
    type(var_xyz), intent(in) :: input
    integer :: i, new_id 
     type(var_x):: output

     call get_new_id_x(new_id)
     output%id = new_id
     output%grid(1) = input%grid(1)
     output%grid(2) = -1
     output%grid(3) = -1
      do i = plb1+input%grid(1), pub1 
        work_x(i,1,1,new_id) = x_minimum + dx * (i - plb1 - input%grid(1) * 0.5D0)
      end do 
  end function pos_var_x_xyz

  function pos_y_y(input) result(output)
    type(var_y), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub2 - plb2 - input%grid(2)) :: output

    if ( input%grid(2) == 0 ) then 
      do i = 0, pub2 - plb2 
        output(i) = y_minimum + dy * i 
      end do 
    else  
      do i = 0, pub2- plb2 - 1 
        output(i) = y_minimum + dy * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_y_y

  function pos_var_y_y(input) result(output)
    type(var_y), intent(in) :: input
    integer :: i, new_id 
     type(var_y):: output

     call get_new_id_y(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = input%grid(2)
     output%grid(3) = -1
      do i = plb2+input%grid(2), pub2 
        work_y(1,i,1,new_id) = y_minimum + dy * (i - plb2 - input%grid(2) * 0.5D0)
      end do 
  end function pos_var_y_y

  function pos_y_xy(input) result(output)
    type(var_xy), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub2 - plb2 - input%grid(2)) :: output

    if ( input%grid(2) == 0 ) then 
      do i = 0, pub2 - plb2 
        output(i) = y_minimum + dy * i 
      end do 
    else  
      do i = 0, pub2- plb2 - 1 
        output(i) = y_minimum + dy * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_y_xy

  function pos_var_y_xy(input) result(output)
    type(var_xy), intent(in) :: input
    integer :: i, new_id 
     type(var_y):: output

     call get_new_id_y(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = input%grid(2)
     output%grid(3) = -1
      do i = plb2+input%grid(2), pub2 
        work_y(1,i,1,new_id) = y_minimum + dy * (i - plb2 - input%grid(2) * 0.5D0)
      end do 
  end function pos_var_y_xy

  function pos_y_yz(input) result(output)
    type(var_yz), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub2 - plb2 - input%grid(2)) :: output

    if ( input%grid(2) == 0 ) then 
      do i = 0, pub2 - plb2 
        output(i) = y_minimum + dy * i 
      end do 
    else  
      do i = 0, pub2- plb2 - 1 
        output(i) = y_minimum + dy * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_y_yz

  function pos_var_y_yz(input) result(output)
    type(var_yz), intent(in) :: input
    integer :: i, new_id 
     type(var_y):: output

     call get_new_id_y(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = input%grid(2)
     output%grid(3) = -1
      do i = plb2+input%grid(2), pub2 
        work_y(1,i,1,new_id) = y_minimum + dy * (i - plb2 - input%grid(2) * 0.5D0)
      end do 
  end function pos_var_y_yz

  function pos_y_xyz(input) result(output)
    type(var_xyz), intent(in) :: input
    integer :: i 
    real(8), dimension(0:pub2 - plb2 - input%grid(2)) :: output

    if ( input%grid(2) == 0 ) then 
      do i = 0, pub2 - plb2 
        output(i) = y_minimum + dy * i 
      end do 
    else  
      do i = 0, pub2- plb2 - 1 
        output(i) = y_minimum + dy * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_y_xyz

  function pos_var_y_xyz(input) result(output)
    type(var_xyz), intent(in) :: input
    integer :: i, new_id 
     type(var_y):: output

     call get_new_id_y(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = input%grid(2)
     output%grid(3) = -1
      do i = plb2+input%grid(2), pub2 
        work_y(1,i,1,new_id) = y_minimum + dy * (i - plb2 - input%grid(2) * 0.5D0)
      end do 
  end function pos_var_y_xyz

  function pos_z_z(input) result(output)
    type(var_z), intent(in) :: input
    integer :: i 
    real(8),dimension(0:pub3 - plb3 - input%grid(3)) :: output

    if ( input%grid(3) == 0 ) then 
      do i = 0, pub3 - plb3 
        output(i) = z_minimum + dz * i 
      end do 
    else  
      do i = 0, pub3- plb3 - 1 
        output(i) = z_minimum + dz * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_z_z

  function pos_var_z_z(input) result(output)
    type(var_z), intent(in) :: input
    integer :: i, new_id 
     type(var_z):: output

     call get_new_id_z(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = -1
     output%grid(3) = input%grid(3)
      do i = plb3+input%grid(3), pub3 
        work_z(1,1,i,new_id) = z_minimum + dz * (i - plb3 - input%grid(3) * 0.5D0)
      end do 
  end function pos_var_z_z

  function pos_z_xz(input) result(output)
    type(var_xz), intent(in) :: input
    integer :: i 
    real(8),dimension(0:pub3 - plb3 - input%grid(3)) :: output

    if ( input%grid(3) == 0 ) then 
      do i = 0, pub3 - plb3 
        output(i) = z_minimum + dz * i 
      end do 
    else  
      do i = 0, pub3- plb3 - 1 
        output(i) = z_minimum + dz * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_z_xz

  function pos_var_z_xz(input) result(output)
    type(var_xz), intent(in) :: input
    integer :: i, new_id 
     type(var_z):: output

     call get_new_id_z(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = -1
     output%grid(3) = input%grid(3)
      do i = plb3+input%grid(3), pub3 
        work_z(1,1,i,new_id) = z_minimum + dz * (i - plb3 - input%grid(3) * 0.5D0)
      end do 
  end function pos_var_z_xz

  function pos_z_yz(input) result(output)
    type(var_yz), intent(in) :: input
    integer :: i 
    real(8),dimension(0:pub3 - plb3 - input%grid(3)) :: output

    if ( input%grid(3) == 0 ) then 
      do i = 0, pub3 - plb3 
        output(i) = z_minimum + dz * i 
      end do 
    else  
      do i = 0, pub3- plb3 - 1 
        output(i) = z_minimum + dz * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_z_yz

  function pos_var_z_yz(input) result(output)
    type(var_yz), intent(in) :: input
    integer :: i, new_id 
     type(var_z):: output

     call get_new_id_z(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = -1
     output%grid(3) = input%grid(3)
      do i = plb3+input%grid(3), pub3 
        work_z(1,1,i,new_id) = z_minimum + dz * (i - plb3 - input%grid(3) * 0.5D0)
      end do 
  end function pos_var_z_yz

  function pos_z_xyz(input) result(output)
    type(var_xyz), intent(in) :: input
    integer :: i 
    real(8),dimension(0:pub3 - plb3 - input%grid(3)) :: output

    if ( input%grid(3) == 0 ) then 
      do i = 0, pub3 - plb3 
        output(i) = z_minimum + dz * i 
      end do 
    else  
      do i = 0, pub3- plb3 - 1 
        output(i) = z_minimum + dz * ( i + 0.5 ) 
      end do 
    end if 
  end function pos_z_xyz

  function pos_var_z_xyz(input) result(output)
    type(var_xyz), intent(in) :: input
    integer :: i, new_id 
     type(var_z):: output

     call get_new_id_z(new_id)
     output%id = new_id
     output%grid(1) = -1
     output%grid(2) = -1
     output%grid(3) = input%grid(3)
      do i = plb3+input%grid(3), pub3 
        work_z(1,1,i,new_id) = z_minimum + dz * (i - plb3 - input%grid(3) * 0.5D0)
      end do 
  end function pos_var_z_xyz

end module gms_position
