!!******************************************************************************
!!
!! module: problem - handling the initial problem definition
!!
!! Copyright (C) 2008-2010 Grzegorz Kowal <grzegorz@gkowal.info>
!!
!!******************************************************************************
!!
!!  This file is part of Godunov-AMR.
!!
!!  Godunov-AMR is free software; you can redistribute it and/or modify
!!  it under the terms of the GNU General Public License as published by
!!  the Free Software Foundation; either version 3 of the License, or
!!  (at your option) any later version.
!!
!!  Godunov-AMR is distributed in the hope that it will be useful,
!!  but WITHOUT ANY WARRANTY; without even the implied warranty of
!!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
!!  GNU General Public License for more details.
!!
!!  You should have received a copy of the GNU General Public License
!!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
!!
!!******************************************************************************
!!
!
module problem

  implicit none

  contains
!
!===============================================================================
!
! init_domain: subroutine initializes the domain for a given problem
!
!===============================================================================
!
  subroutine init_domain

    use config, only : problem
!
!-------------------------------------------------------------------------------
!
    select case(trim(problem))
#if NDIMS == 2
    case("blast")
      call domain_blast()
#endif /* NDIMS == 2 */
    case default
      call domain_default()
    end select

!-------------------------------------------------------------------------------
!
  end subroutine init_domain
!
!===============================================================================
!
! init_problem: subroutine initializes the variables according to
!               the studied problem
!
!===============================================================================
!
  subroutine init_problem(pblock)

    use blocks, only : block_data
    use config, only : problem

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock

! local arguments
!
    type(block_data), pointer :: pb
!
!-------------------------------------------------------------------------------
!
    pb => pblock

    select case(trim(problem))
    case("blast")
      call init_blast(pb)
    case("implosion")
      call init_implosion(pb)
    case("binaries")
      call init_binaries(pb)
    case("reconnection")
      call init_reconnection(pb)
    end select

    nullify(pb)

!-------------------------------------------------------------------------------
!
  end subroutine init_problem
#ifdef SHAPE
!
!===============================================================================
!
! shapes: subroutine resets the update for a give shape
!
!===============================================================================
!
  subroutine update_shapes(pblock, du)

    use blocks, only : block_data
    use config, only : problem

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock
    real, dimension(:,:,:,:) , intent(inout) :: du

! local arguments
!
    type(block_data), pointer :: pb
!
!-------------------------------------------------------------------------------
!
    pb => pblock

    select case(trim(problem))
    case("binaries")
      call shape_binaries(pb, du)
    case default
    end select

    nullify(pb)

!-------------------------------------------------------------------------------
!
  end subroutine update_shapes
#endif /* SHAPE */
!
!===============================================================================
!
! domain_default: subroutine initializes the default domain of 2x2 blocks in
!                'N' configuration
!
!===============================================================================
!
  subroutine domain_default

    use blocks, only : block_meta, block_data, append_metablock                &
                     , append_datablock, associate_blocks, metablock_setleaf   &
                     , metablock_setconfig, metablock_setlevel                 &
                     , metablock_set_coord, metablock_setbounds                &
                     , nsides, nfaces
    use config, only : xlbndry, xubndry, ylbndry, yubndry, zlbndry, zubndry    &
                     , xmin, xmax, ymin, ymax, zmin, zmax

    implicit none

! local variables
!
    integer :: i, j

! local pointers
!
    type(block_meta), pointer :: pmeta
    type(block_data), pointer :: pdata
!
!-------------------------------------------------------------------------------
!
! create root meta blocks
!
    call append_metablock(pmeta)

! mark block as a leaf
!
    call metablock_setleaf(pmeta)

! set block config flag
!
    call metablock_setconfig(pmeta, 12)

! set block level
!
    call metablock_setlevel(pmeta, 1)

! set block coordinates
!
    call metablock_set_coord(pmeta, 0, 0, 0)

! set block bounds
!
    call metablock_setbounds(pmeta, xmin, xmax, ymin, ymax, zmin, zmax)

! if periodic boundary conditions set all neighbors to itself
!
    if (xlbndry .eq. 'periodic' .and. xubndry .eq. 'periodic') then
      do j = 1, nfaces
        do i = 1, nsides
          pmeta%neigh(1,i,j)%ptr => pmeta
        end do
      end do
    end if
    if (ylbndry .eq. 'periodic' .and. yubndry .eq. 'periodic') then
      do j = 1, nfaces
        do i = 1, nsides
          pmeta%neigh(2,i,j)%ptr => pmeta
        end do
      end do
    end if
#if NDIMS == 3
    if (zlbndry .eq. 'periodic' .and. zubndry .eq. 'periodic') then
      do j = 1, nfaces
        do i = 1, nsides
          pmeta%neigh(3,i,j)%ptr => pmeta
        end do
      end do
    end if
#endif /* NDIMS == 3 */

! create root data block
!
    call append_datablock(pdata)

! associate root blocks
!
    call associate_blocks(pmeta, pdata)
!
!-------------------------------------------------------------------------------
!
  end subroutine domain_default
!
!===============================================================================
!
! domain_default: subroutine initializes the default domain of 2x2 blocks in
!                'N' configuration
!
!===============================================================================
!
  subroutine domain_blast

    use blocks, only : block_meta, block_data, pointer_meta, append_metablock  &
                     , append_datablock, associate_blocks, metablock_setleaf   &
                     , metablock_setconfig, metablock_setlevel                 &
                     , metablock_setbounds, metablock_set_coord                &
                     , nsides, nfaces, res
    use config, only : xlbndry, xubndry, ylbndry, yubndry, zlbndry, zubndry    &
                     , xmin, xmax, ymin, ymax, zmin, zmax, rdims, maxlev, ncells

    implicit none

! local variables
!
    integer :: i, j, ih, jl, ju
    real    :: xm, yl, yu

! local pointers
!
    type(block_meta), pointer :: pmeta
    type(block_data), pointer :: pdata

! local pointer array
!
    type(pointer_meta)        :: block_array(2,3)
!
!-------------------------------------------------------------------------------
!
!! TO DO:
!!
!! create a general way to initiate NxM blocks at level 1
!!
!!
! create root meta blocks
!
    call append_metablock(block_array(1,1)%ptr)
    call append_metablock(block_array(2,1)%ptr)
    call append_metablock(block_array(2,2)%ptr)
    call append_metablock(block_array(1,2)%ptr)
    call append_metablock(block_array(1,3)%ptr)
    call append_metablock(block_array(2,3)%ptr)

! mark block as a leaf
!
    call metablock_setleaf(block_array(1,1)%ptr)
    call metablock_setleaf(block_array(2,1)%ptr)
    call metablock_setleaf(block_array(2,2)%ptr)
    call metablock_setleaf(block_array(1,2)%ptr)
    call metablock_setleaf(block_array(1,3)%ptr)
    call metablock_setleaf(block_array(2,3)%ptr)

! set block config flag
!
    call metablock_setconfig(block_array(1,1)%ptr, 12)
    call metablock_setconfig(block_array(2,1)%ptr, 13)
    call metablock_setconfig(block_array(2,2)%ptr, 13)
    call metablock_setconfig(block_array(1,2)%ptr, 43)
    call metablock_setconfig(block_array(1,3)%ptr, 12)
    call metablock_setconfig(block_array(2,3)%ptr, 12)

! set block level
!
    call metablock_setlevel(block_array(1,1)%ptr, 1)
    call metablock_setlevel(block_array(2,1)%ptr, 1)
    call metablock_setlevel(block_array(2,2)%ptr, 1)
    call metablock_setlevel(block_array(1,2)%ptr, 1)
    call metablock_setlevel(block_array(1,3)%ptr, 1)
    call metablock_setlevel(block_array(2,3)%ptr, 1)

! set boundary conditions
!
    block_array(1,1)%ptr%neigh(1,1,1)%ptr => block_array(2,1)%ptr
    block_array(1,1)%ptr%neigh(1,1,2)%ptr => block_array(2,1)%ptr
    block_array(1,1)%ptr%neigh(1,2,1)%ptr => block_array(2,1)%ptr
    block_array(1,1)%ptr%neigh(1,2,2)%ptr => block_array(2,1)%ptr
    block_array(1,1)%ptr%neigh(2,1,1)%ptr => block_array(1,3)%ptr
    block_array(1,1)%ptr%neigh(2,1,2)%ptr => block_array(1,3)%ptr
    block_array(1,1)%ptr%neigh(2,2,1)%ptr => block_array(1,2)%ptr
    block_array(1,1)%ptr%neigh(2,2,2)%ptr => block_array(1,2)%ptr

    block_array(1,2)%ptr%neigh(1,1,1)%ptr => block_array(2,2)%ptr
    block_array(1,2)%ptr%neigh(1,1,2)%ptr => block_array(2,2)%ptr
    block_array(1,2)%ptr%neigh(1,2,1)%ptr => block_array(2,2)%ptr
    block_array(1,2)%ptr%neigh(1,2,2)%ptr => block_array(2,2)%ptr
    block_array(1,2)%ptr%neigh(2,1,1)%ptr => block_array(1,1)%ptr
    block_array(1,2)%ptr%neigh(2,1,2)%ptr => block_array(1,1)%ptr
    block_array(1,2)%ptr%neigh(2,2,1)%ptr => block_array(1,3)%ptr
    block_array(1,2)%ptr%neigh(2,2,2)%ptr => block_array(1,3)%ptr

    block_array(1,3)%ptr%neigh(1,1,1)%ptr => block_array(2,3)%ptr
    block_array(1,3)%ptr%neigh(1,1,2)%ptr => block_array(2,3)%ptr
    block_array(1,3)%ptr%neigh(1,2,1)%ptr => block_array(2,3)%ptr
    block_array(1,3)%ptr%neigh(1,2,2)%ptr => block_array(2,3)%ptr
    block_array(1,3)%ptr%neigh(2,1,1)%ptr => block_array(1,2)%ptr
    block_array(1,3)%ptr%neigh(2,1,2)%ptr => block_array(1,2)%ptr
    block_array(1,3)%ptr%neigh(2,2,1)%ptr => block_array(1,1)%ptr
    block_array(1,3)%ptr%neigh(2,2,2)%ptr => block_array(1,1)%ptr

    block_array(2,1)%ptr%neigh(1,1,1)%ptr => block_array(1,1)%ptr
    block_array(2,1)%ptr%neigh(1,1,2)%ptr => block_array(1,1)%ptr
    block_array(2,1)%ptr%neigh(1,2,1)%ptr => block_array(1,1)%ptr
    block_array(2,1)%ptr%neigh(1,2,2)%ptr => block_array(1,1)%ptr
    block_array(2,1)%ptr%neigh(2,1,1)%ptr => block_array(2,3)%ptr
    block_array(2,1)%ptr%neigh(2,1,2)%ptr => block_array(2,3)%ptr
    block_array(2,1)%ptr%neigh(2,2,1)%ptr => block_array(2,2)%ptr
    block_array(2,1)%ptr%neigh(2,2,2)%ptr => block_array(2,2)%ptr

    block_array(2,2)%ptr%neigh(1,1,1)%ptr => block_array(1,2)%ptr
    block_array(2,2)%ptr%neigh(1,1,2)%ptr => block_array(1,2)%ptr
    block_array(2,2)%ptr%neigh(1,2,1)%ptr => block_array(1,2)%ptr
    block_array(2,2)%ptr%neigh(1,2,2)%ptr => block_array(1,2)%ptr
    block_array(2,2)%ptr%neigh(2,1,1)%ptr => block_array(2,1)%ptr
    block_array(2,2)%ptr%neigh(2,1,2)%ptr => block_array(2,1)%ptr
    block_array(2,2)%ptr%neigh(2,2,1)%ptr => block_array(2,3)%ptr
    block_array(2,2)%ptr%neigh(2,2,2)%ptr => block_array(2,3)%ptr

    block_array(2,3)%ptr%neigh(1,1,1)%ptr => block_array(1,3)%ptr
    block_array(2,3)%ptr%neigh(1,1,2)%ptr => block_array(1,3)%ptr
    block_array(2,3)%ptr%neigh(1,2,1)%ptr => block_array(1,3)%ptr
    block_array(2,3)%ptr%neigh(1,2,2)%ptr => block_array(1,3)%ptr
    block_array(2,3)%ptr%neigh(2,1,1)%ptr => block_array(2,2)%ptr
    block_array(2,3)%ptr%neigh(2,1,2)%ptr => block_array(2,2)%ptr
    block_array(2,3)%ptr%neigh(2,2,1)%ptr => block_array(2,1)%ptr
    block_array(2,3)%ptr%neigh(2,2,2)%ptr => block_array(2,1)%ptr

! prepare the coordinates
!
    ih = res(1)
    jl = res(1)
    ju = res(1) + jl

! set the coordinates
!
    call metablock_set_coord(block_array(1,1)%ptr,  0,  0, 0)
    call metablock_set_coord(block_array(2,1)%ptr, ih,  0, 0)
    call metablock_set_coord(block_array(1,2)%ptr,  0, jl, 0)
    call metablock_set_coord(block_array(2,2)%ptr, ih, jl, 0)
    call metablock_set_coord(block_array(1,3)%ptr,  0, ju, 0)
    call metablock_set_coord(block_array(2,3)%ptr, ih, ju, 0)

! calculate bounds
!
    xm = 0.5 * (xmin + xmax)
    yl = (ymax - ymin) / 3.0 + ymin
    yu = (ymax - ymin) / 3.0 + yl

! set block bounds
!
    call metablock_setbounds(block_array(1,1)%ptr, xmin, xm  , ymin, yl  , zmin, zmax)
    call metablock_setbounds(block_array(2,1)%ptr, xm  , xmax, ymin, yl  , zmin, zmax)
    call metablock_setbounds(block_array(2,2)%ptr, xm  , xmax, yl  , yu  , zmin, zmax)
    call metablock_setbounds(block_array(1,2)%ptr, xmin, xm  , yl  , yu  , zmin, zmax)
    call metablock_setbounds(block_array(1,3)%ptr, xmin, xm  , yu  , ymax, zmin, zmax)
    call metablock_setbounds(block_array(2,3)%ptr, xm  , xmax, yu  , ymax, zmin, zmax)

! create root data block
!
    call append_datablock(pdata)
    call associate_blocks(block_array(1,1)%ptr, pdata)
    call append_datablock(pdata)
    call associate_blocks(block_array(2,1)%ptr, pdata)
    call append_datablock(pdata)
    call associate_blocks(block_array(2,2)%ptr, pdata)
    call append_datablock(pdata)
    call associate_blocks(block_array(1,2)%ptr, pdata)
    call append_datablock(pdata)
    call associate_blocks(block_array(1,3)%ptr, pdata)
    call append_datablock(pdata)
    call associate_blocks(block_array(2,3)%ptr, pdata)

! set the block dimensions for the lowest level
!
    rdims(1) = 2
    rdims(2) = 3
!
!-------------------------------------------------------------------------------
!
  end subroutine domain_blast
!
!===============================================================================
!
! init_blast: subroutine initializes the variables for the blast problem
!
!===============================================================================
!
  subroutine init_blast(pblock)

    use blocks   , only : block_data
    use config   , only : in, jn, kn, im, jm, km, ng                           &
                        , gamma, csnd2, rcut, dens, dnrat
    use scheme   , only : prim2cons
    use variables, only : nvr, nqt, idn, ivx, ivy, ivz
#ifdef ADI
    use variables, only : ipr
#endif /* ADI */
#ifdef MHD
    use variables, only : ibx, iby, ibz
#ifdef FLUXCT
    use variables, only : icx, icy, icz
#endif /* FLUXCT */
#ifdef GLM
    use variables, only : iph
#endif /* GLM */
#endif /* MHD */

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock

! local variables
!
    integer(kind=4), dimension(3) :: dm
    integer                       :: i, j, k
    real                          :: r, dx, dy, dz, pr

! local arrays
!
    real, dimension(im)     :: x
    real, dimension(jm)     :: y
    real, dimension(km)     :: z
    real, dimension(nvr,im) :: q, u
!
!-------------------------------------------------------------------------------
!
! calculate parameters
!
#ifdef ADI
    pr = dens * csnd2 / gamma
#endif /* ADI */

! calculate cell sizes
!
    dx = (pblock%meta%xmax - pblock%meta%xmin) / in
    dy = (pblock%meta%ymax - pblock%meta%ymin) / jn
#if NDIMS == 3
    dz = (pblock%meta%zmax - pblock%meta%zmin) / kn
#else /* NDIMS == 3 */
    dz = 1.0
#endif /* NDIMS == 3 */

! generate coordinates
!
    x(:) = ((/(i, i = 1, im)/) - ng - 0.5) * dx + pblock%meta%xmin
    y(:) = ((/(j, j = 1, jm)/) - ng - 0.5) * dy + pblock%meta%ymin
#if NDIMS == 3
    z(:) = ((/(k, k = 1, km)/) - ng - 0.5) * dz + pblock%meta%zmin
#else /* NDIMS == 3 */
    z(1) = 0.0
#endif /* NDIMS == 3 */

! set variables
!
    q(idn,:) = dens
    q(ivx,:) = 0.0d0
    q(ivy,:) = 0.0d0
    q(ivz,:) = 0.0d0
#ifdef MHD
    q(ibx,:) = 0.70710678118654752440
    q(iby,:) = 0.70710678118654752440
    q(ibz,:) = 0.0d0
#ifdef FLUXCT
    q(icx,:) = 0.70710678118654752440
    q(icy,:) = 0.70710678118654752440
    q(icz,:) = 0.0d0
#endif /* FLUXCT */
#ifdef GLM
    q(iph,:) = 0.0d0
#endif /* GLM */
#endif /* MHD */

! set initial pressure
!
    do k = 1, km
      do j = 1, jm

! fill out the pressure profile
!
        do i = 1, im

          r = sqrt(x(i)**2 + y(j)**2 + z(k)**2)

#ifdef ISO
          if (r .lt. rcut) then
            q(idn,i) = dens * dnrat
          else
            q(idn,i) = dens
          end if
#endif /* ISO */
#ifdef ADI
          if (r .lt. rcut) then
            q(ipr,i) = pr * dnrat
          else
            q(ipr,i) = pr
          end if
#endif /* ADI */

        end do

! convert primitive variables to conserved
!
        call prim2cons(im, q, u)

! copy conservative variables to the current block
!
        pblock%u(1:nqt,1:im,j,k) = u(1:nqt,1:im)

      end do
    end do
!
!-------------------------------------------------------------------------------
!
  end subroutine init_blast
!
!===============================================================================
!
! init_implosion: subroutine initializes variables for the implosion problem
!
!===============================================================================
!
  subroutine init_implosion(pblock)

    use blocks   , only : block_data
    use config   , only : in, jn, kn, im, jm, km, ng, dens, pres, rmid, gammam1i
    use variables, only : idn, imx, imy, imz
#ifdef ADI
    use variables, only : ien
#endif /* ADI */

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock

! local variables
!
    integer(kind=4), dimension(3) :: dm
    integer                       :: i, j, k
    real                          :: dx, dy, dxh, dyh, rc, rl, ru, ds, dl, dr

! local arrays
!
    real, dimension(:), allocatable :: x, y
!
!-------------------------------------------------------------------------------
!
! allocate coordinates
!
    allocate(x(im))
    allocate(y(jm))

! calculate cell sizes
!
    dx  = (pblock%meta%xmax - pblock%meta%xmin) / in
    dy  = (pblock%meta%ymax - pblock%meta%ymin) / jn
    dxh = 0.5d0 * dx
    dyh = 0.5d0 * dy
    ds  = dx * dy

! generate coordinates
!
    x(:) = ((/(i, i = 1, im)/) - ng) * dx - dxh + pblock%meta%xmin
    y(:) = ((/(j, j = 1, jm)/) - ng) * dy - dyh + pblock%meta%ymin

! set variables
!
    pblock%u(idn,:,:,:) = dens
    pblock%u(imx,:,:,:) = 0.0d0
    pblock%u(imy,:,:,:) = 0.0d0
    pblock%u(imz,:,:,:) = 0.0d0

! set initial pressure
!
    do j = 1, jm
      do i = 1, im
        rc = x(i) + y(j)
        rl = rc - dxh - dyh
        ru = rc + dxh + dyh

        if (ru .le. rmid) then
          pblock%u(idn,i,j,:) = 0.125d0
#ifdef ADI
          pblock%u(ien,i,j,:) = gammam1i * 0.140d0
#endif /* ADI */
        else if (rl .ge. rmid) then
          pblock%u(idn,i,j,:) = 1.0d0
#ifdef ADI
          pblock%u(ien,i,j,:) = gammam1i
#endif /* ADI */
        else
          if (rc .ge. rmid) then
            dl = 0.125d0 * (rmid - rl)**2 / ds
            dr = 1.0d0 - dl
          else
            dr = 0.125d0 * (ru - rmid)**2 / ds
            dl = 1.0d0 - dr
          endif
          pblock%u(idn,i,j,:) = 0.125d0 * dl + dr
#ifdef ADI
          pblock%u(ien,i,j,:) = gammam1i * (0.140d0 * dl + dr)
#endif /* ADI */
        endif
      end do
    end do

! deallocate coordinates
!
    deallocate(x)
    deallocate(y)

!-------------------------------------------------------------------------------
!
  end subroutine init_implosion
!
!===============================================================================
!
! init_binaries: subroutine initializes the variables for the binary star
!                problem
!
!===============================================================================
!
  subroutine init_binaries(pblock)

    use blocks   , only : block_data
    use config   , only : ng, in, jn, kn, im, jm, km, dens, pres, dnfac, dnrat &
                        , x1c, y1c, z1c, r1c, x2c, y2c, z2c, r2c, v1ini, v2ini &
                        , csnd2, gamma, gammam1i
    use variables, only : idn, imx, imy, imz
#ifdef ADI
    use variables, only : ien
#endif /* ADI */

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock

! local variables
!
    integer :: i, j, k
    real    :: dx, dy, dz, dnamb, enamb, ekin
    real    :: dnstar1, enstar1, x1l, y1l, z1l, r1
    real    :: dnstar2, enstar2, x2l, y2l, z2l, r2

! local arrays
!
    real, dimension(:), allocatable :: x, y, z
!
!-------------------------------------------------------------------------------
!
! calculate pressure from sound speed
!
#ifdef ISO
    pres = csnd2 * dens
#endif /* ISO */
#ifdef ADI
    pres = csnd2 * dens / gamma
#endif /* ADI */

! calculate parameters
!
    dnamb   = dens
    dnstar2 = dnamb*dnfac
    dnstar1 = dnstar2*dnrat
    enamb   = gammam1i*pres
    enstar1 = enamb*dnfac
    enstar2 = enstar1/dnrat

! allocate coordinates
!
    allocate(x(im))
    allocate(y(jm))
    allocate(z(km))

! calculate cell sizes
!
    dx = (pblock%meta%xmax - pblock%meta%xmin) / in
    dy = (pblock%meta%ymax - pblock%meta%ymin) / jn
#if NDIMS == 3
    dz = (pblock%meta%zmax - pblock%meta%zmin) / kn
#else /* NDIMS == 3 */
    dz = 1.0
#endif /* NDIMS == 3 */

! generate coordinates
!
    x(:) = ((/(i, i = 1, im)/) - ng - 0.5) * dx + pblock%meta%xmin
    y(:) = ((/(j, j = 1, jm)/) - ng - 0.5) * dy + pblock%meta%ymin
#if NDIMS == 3
    z(:) = ((/(k, k = 1, km)/) - ng - 0.5) * dz + pblock%meta%zmin
#else /* NDIMS == 3 */
    z(1) = 0.0

    z1l  = 0.0
    z2l  = 0.0
#endif /* NDIMS == 3 */

! set variables
!
    pblock%u(idn,:,:,:) = dnamb
    pblock%u(imx,:,:,:) = 0.0d0
    pblock%u(imy,:,:,:) = 0.0d0
    pblock%u(imz,:,:,:) = 0.0d0
#ifdef ADI
    pblock%u(ien,:,:,:) = enamb
#endif /* ADI */

! set initial pressure
!
    do k = 1, km
#if NDIMS == 3
      z1l = z(k) - z1c
      z2l = z(k) - z2c
#endif /* NDIMS == 3 */

      do j = 1, jm
        y1l = y(j) - y1c
        y2l = y(j) - y2c

        do i = 1, im
          x1l = x(i) - x1c
          x2l = x(i) - x2c

          r1 = sqrt(x1l**2 + y1l**2 + z1l**2)
          r2 = sqrt(x2l**2 + y2l**2 + z2l**2)

          if (r1 .le. r1c) then
            pblock%u(idn,i,j,k) = dnstar1
            pblock%u(imx,i,j,k) = dnstar1*v1ini*x1l
            pblock%u(imy,i,j,k) = dnstar1*v1ini*y1l
#if NDIMS == 3
            pblock%u(imz,i,j,k) = dnstar1*v1ini*z1l
#endif /* NDIMS == 3 */
            ekin = 0.5 * dnstar1 * v1ini**2 * (x1l**2 + y1l**2 + z1l**2)
#ifdef ADI
            pblock%u(ien,i,j,k) = enstar1 + ekin
#endif /* ADI */
          endif

          if (r2 .le. r2c) then
            pblock%u(idn,i,j,k) = dnstar2
            pblock%u(imx,i,j,k) = dnstar2*v2ini*x2l
            pblock%u(imy,i,j,k) = dnstar2*v2ini*y2l
#if NDIMS == 3
            pblock%u(imz,i,j,k) = dnstar2*v2ini*z2l
#endif /* NDIMS == 3 */
            ekin = 0.5 * dnstar2 * v2ini**2 * (x2l**2 + y2l**2 + z2l**2)
#ifdef ADI
            pblock%u(ien,i,j,k) = enstar2 + ekin
#endif /* ADI */
          endif
        end do
      end do
    end do

! deallocate coordinates
!
    deallocate(x)
    deallocate(y)
    deallocate(z)

!-------------------------------------------------------------------------------
!
  end subroutine init_binaries
!
!===============================================================================
!
! init_reconnection: subroutine initializes the variables for the reconnection
!                    problem
!
!===============================================================================
!
  subroutine init_reconnection(pblock)

    use blocks   , only : block_data
    use config   , only : in, jn, kn, im, jm, km, ng                           &
                        , xmin, xmax, dens, pres, bamp, bper, ydel, ycut
    use scheme   , only : prim2cons
    use variables, only : nvr, nqt
    use variables, only : idn, ivx, ivy, ivz
#ifdef ADI
    use variables, only : ipr
#endif /* ADI */
#ifdef MHD
    use variables, only : ibx, iby, ibz
#ifdef FLUXCT
    use variables, only : icx, icy, icz
#endif /* FLUXCT */
#ifdef GLM
    use variables, only : iph
#endif /* GLM */
#endif /* MHD */

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock

! local variables
!
    integer(kind=4), dimension(3) :: dm
    integer                       :: i, j, k
    real                          :: xlen, dx, dy, dz

! local arrays
!
    real, dimension(im)     :: x
    real, dimension(jm)     :: y
    real, dimension(km)     :: z
    real, dimension(nvr,im) :: q, u

! parameters
!
    real, parameter :: pi = 3.1415926535897931159979634685442d0
!
!-------------------------------------------------------------------------------
!
! calculate the length of the box
!
    xlen = xmax - xmin

! calculate the cell sizes
!
    dx = (pblock%meta%xmax - pblock%meta%xmin) / in
    dy = (pblock%meta%ymax - pblock%meta%ymin) / jn
#if NDIMS == 3
    dz = (pblock%meta%zmax - pblock%meta%zmin) / kn
#else /* NDIMS == 3 */
    dz = 1.0
#endif /* NDIMS == 3 */

! generate the coordinates
!
    x(:) = ((/(i, i = 1, im)/) - ng - 0.5) * dx + pblock%meta%xmin
    y(:) = ((/(j, j = 1, jm)/) - ng - 0.5) * dy + pblock%meta%ymin
#if NDIMS == 3
    z(:) = ((/(k, k = 1, km)/) - ng - 0.5) * dz + pblock%meta%zmin
#else /* NDIMS == 3 */
    z(1) = 0.0
#endif /* NDIMS == 3 */

! set variables
!
    q(idn,:) = dens
    q(ivx,:) = 0.0d0
    q(ivy,:) = 0.0d0
    q(ivz,:) = 0.0d0
#ifdef ADI
    q(ipr,:) = pres
#endif /* ADI */
#ifdef MHD
    q(ibx,:) = 0.0d0
    q(iby,:) = 0.0d0
    q(ibz,:) = 0.0d0
#ifdef FLUXCT
    q(ibx,:) = 0.0d0
    q(iby,:) = 0.0d0
    q(ibz,:) = 0.0d0
#endif /* FLUXCT */
#ifdef GLM
    q(iph,:) = 0.0d0
#endif /* GLM */
#endif /* MHD */

! set the initial profiles
!
    do k = 1, km
      do j = 1, jm

! initialize the magnetic field components
!
        do i = 1, im
          q(ibx,i) = bamp * tanh(y(j) / ydel)
          q(iby,i) = bper * sin(pi * x(i) / xlen)                              &
                          * exp(- 0.5d0 * (y(j) / ycut)**2)
        end do

! convert primitive variables to conserved
!
        call prim2cons(im, q(:,:), u(:,:))

! copy conservative variables to the current block
!
        pblock%u(1:nqt,1:im,j,k) = u(1:nqt,1:im)

      end do
    end do
!
!-------------------------------------------------------------------------------
!
  end subroutine init_reconnection
#ifdef SHAPE
!
!===============================================================================
!
! shape_binaries: subroutine initializes the variables for the binary star
!                problem
!
!===============================================================================
!
  subroutine shape_binaries(pblock, du)

    use blocks   , only : block_data
    use config   , only : ng, in, jn, kn, im, jm, km, dens, pres, dnfac, dnrat &
                        , x1c, y1c, z1c, r1c, x2c, y2c, z2c, r2c               &
                        , csnd2, gamma, gammam1i
    use variables, only : idn, imx, imy, imz, ien

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock
    real, dimension(:,:,:,:) , intent(inout) :: du

! local variables
!
    integer :: i, j, k
    real    :: dx, dy, dz
    real    :: x1l, y1l, z1l, r1
    real    :: x2l, y2l, z2l, r2

! local arrays
!
    real, dimension(:), allocatable :: x, y, z
!
!-------------------------------------------------------------------------------
!
! allocate coordinates
!
    allocate(x(im))
    allocate(y(jm))
    allocate(z(km))

! calculate cell sizes
!
    dx = (pblock%meta%xmax - pblock%meta%xmin) / in
    dy = (pblock%meta%ymax - pblock%meta%ymin) / jn
#if NDIMS == 3
    dz = (pblock%meta%zmax - pblock%meta%zmin) / kn
#else /* NDIMS == 3 */
    dz = 1.0
#endif /* NDIMS == 3 */

! generate coordinates
!
    x(:) = ((/(i, i = 1, im)/) - ng - 0.5) * dx + pblock%meta%xmin
    y(:) = ((/(j, j = 1, jm)/) - ng - 0.5) * dy + pblock%meta%ymin
#if NDIMS == 3
    z(:) = ((/(k, k = 1, km)/) - ng - 0.5) * dz + pblock%meta%zmin
#else /* NDIMS == 3 */
    z(1) = 0.0

    z1l  = 0.0
    z2l  = 0.0
#endif /* NDIMS == 3 */

! reset update
!
    do k = 1, km
#if NDIMS == 3
      z1l = z(k) - z1c
      z2l = z(k) - z2c
#endif /* NDIMS == 3 */

      do j = 1, jm
        y1l = y(j) - y1c
        y2l = y(j) - y2c

        do i = 1, im
          x1l = x(i) - x1c
          x2l = x(i) - x2c

          r1 = sqrt(x1l**2 + y1l**2 + z1l**2)
          r2 = sqrt(x2l**2 + y2l**2 + z2l**2)

          if (r1 .le. r1c) then
            du(:,i,j,k) = 0.0
          endif

          if (r2 .le. r2c) then
            du(:,i,j,k) = 0.0
          endif
        end do
      end do
    end do

! deallocate coordinates
!
    deallocate(x)
    deallocate(y)
    deallocate(z)

!-------------------------------------------------------------------------------
!
  end subroutine shape_binaries
#endif /* SHAPE */
!
!===============================================================================
!
! check_ref: function checks refinement criterium and returns +1 if
!            the criterium fullfiled and block is selected for
!            refinement, 0 there is no need for refinement, and -1 if
!            block is selected for refinement
!
!===============================================================================
!
  function check_ref(pblock)

    use blocks   , only : block_data
    use config   , only : im, jm, km, ibl, ieu, jbl, jeu, kbl, keu             &
                        , crefmin, crefmax
    use scheme   , only : cons2prim
    use variables, only : nvr, nqt
    use variables, only : idn
#ifdef ADI
    use variables, only : ipr
#endif /* ADI */
#ifdef MHD
    use variables, only : ibx, iby, ibz
#endif /* MHD */

! input arguments
!
    type(block_data), pointer, intent(inout) :: pblock

! return variable
!
    integer(kind=1) :: check_ref

! local variables
!
    integer :: i, j, k
    real    :: dpmax
    real    :: dnl, dnr, ddndx, ddndy, ddndz, ddn
#ifdef ADI
    real    :: prl, prr, dprdx, dprdy, dprdz, dpr
#endif /* ADI */
#ifdef MHD
    real    :: bxl, bxr, dbxdx, dbxdy, dbxdz, dbx
    real    :: byl, byr, dbydx, dbydy, dbydz, dby
    real    :: bzl, bzr, dbzdx, dbzdy, dbzdz, dbz
#endif /* MHD */

! local arrays
!
    real, dimension(nvr,im)   :: u, q
    real, dimension(im,jm,km) :: dn
#ifdef ADI
    real, dimension(im,jm,km) :: pr
#endif /* ADI */
#ifdef MHD
    real, dimension(im,jm,km) :: bx, by, bz
#endif /* MHD */
!
!-------------------------------------------------------------------------------
!
! convert conserved variables to primitive ones
!
    do k = 1, km
      do j = 1, jm
        dn(1:im,j,k) = pblock%u(idn,1:im,j,k)
#ifdef ADI
        u(1:nqt,1:im) = pblock%u(1:nqt,1:im,j,k)

        call cons2prim(im, u(:,:), q(:,:))

        pr(1:im,j,k) = q(ipr,1:im)
#endif /* ADI */
#ifdef MHD
        bx(1:im,j,k) = pblock%u(ibx,1:im,j,k)
        by(1:im,j,k) = pblock%u(iby,1:im,j,k)
        bz(1:im,j,k) = pblock%u(ibz,1:im,j,k)
#endif /* MHD */
      end do
    end do

! reset indicators
!
    dpmax = 0.0d0
    ddn   = 0.0d0
#ifdef ADI
    dpr   = 0.0d0
#endif /* ADI */
#ifdef MHD
    dbx   = 0.0d0
    dby   = 0.0d0
    dbz   = 0.0d0
#endif /* MHD */


! check gradients of selected variables
!
    do k = kbl, keu
      do j = jbl, jeu
        do i = ibl, ieu

! density
!
          dnl = dn(i-1,j,k)
          dnr = dn(i+1,j,k)
          ddndx = abs(dnr - dnl) / (dnr + dnl)
          dnl = dn(i,j-1,k)
          dnr = dn(i,j+1,k)
          ddndy = abs(dnr - dnl) / (dnr + dnl)
#if NDIMS == 2

          ddn = sqrt(ddndx**2 + ddndy**2)
#else /* NDIMS == 2 */
          dnl = dn(i,j,k-1)
          dnr = dn(i,j,k+1)
          ddndz = abs(dnr - dnl) / (dnr + dnl)

          ddn = sqrt(ddndx**2 + ddndy**2 + ddndz**2)
#endif /* NDIMS == 2 */

! update the indicator
!
          dpmax = max(dpmax, ddn)

#ifdef ADI
! pressure
!
          prl = pr(i-1,j,k)
          prr = pr(i+1,j,k)
          dprdx = abs(prr - prl) / (prr + prl)
          prl = pr(i,j-1,k)
          prr = pr(i,j+1,k)
          dprdy = abs(prr - prl) / (prr + prl)
#if NDIMS == 2

          dpr = sqrt(dprdx**2 + dprdy**2)
#else /* NDIMS == 2 */
          prl = pr(i,j,k-1)
          prr = pr(i,j,k+1)
          dprdz = abs(prr - prl) / (prr + prl)

          dpr = sqrt(dprdx**2 + dprdy**2 + dprdz**2)
#endif /* NDIMS == 2 */

! update the indicator
!
          dpmax = max(dpmax, dpr)
#endif /* ADI */

#ifdef MHD
! X magnetic component
!
          bxl = bx(i-1,j,k)
          bxr = bx(i+1,j,k)
          dbxdx = abs(bxr - bxl) / max(1.0d-16, abs(bxr) + abs(bxl))
          bxl = bx(i,j-1,k)
          bxr = bx(i,j+1,k)
          dbxdy = abs(bxr - bxl) / max(1.0d-16, abs(bxr) + abs(bxl))
#if NDIMS == 2

          dbx = sqrt(dbxdx**2 + dbxdy**2)
#else /* NDIMS == 2 */
          bxl = bx(i,j,k-1)
          bxr = bx(i,j,k+1)
          dbxdz = abs(bxr - bxl) / max(1.0d-16, abs(bxr) + abs(bxl))

          dbx = sqrt(dbxdx**2 + dbxdy**2 + dbxdz**2)
#endif /* NDIMS == 2 */

! Y magnetic component
!
          byl = by(i-1,j,k)
          byr = by(i+1,j,k)
          dbydx = abs(byr - byl) / max(1.0d-16, abs(byr) + abs(byl))
          byl = by(i,j-1,k)
          byr = by(i,j+1,k)
          dbydy = abs(byr - byl) / max(1.0d-16, abs(byr) + abs(byl))
#if NDIMS == 2

          dby = sqrt(dbydx**2 + dbydy**2)
#else /* NDIMS == 2 */
          byl = by(i,j,k-1)
          byr = by(i,j,k+1)
          dbydz = abs(byr - byl) / max(1.0d-16, abs(byr) + abs(byl))

          dby = sqrt(dbydx**2 + dbydy**2 + dbydz**2)
#endif /* NDIMS == 2 */

! Z magnetic component
!
          bzl = bz(i-1,j,k)
          bzr = bz(i+1,j,k)
          dbzdx = abs(bzr - bzl) / max(1.0d-16, abs(bzr) + abs(bzl))
          bzl = bz(i,j-1,k)
          bzr = bz(i,j+1,k)
          dbzdy = abs(bzr - bzl) / max(1.0d-16, abs(bzr) + abs(bzl))
#if NDIMS == 2

          dbz = sqrt(dbzdx**2 + dbzdy**2)
#else /* NDIMS == 2 */
          bzl = bz(i,j,k-1)
          bzr = bz(i,j,k+1)
          dbzdz = abs(bzr - bzl) / max(1.0d-16, abs(bzr) + abs(bzl))

          dbz = sqrt(dbzdx**2 + dbzdy**2 + dbzdz**2)
#endif /* NDIMS == 2 */

! update the indicator
!
          dpmax = max(dpmax, dbx, dby, dbz)
#endif /* MHD */

        end do
      end do
    end do

! return the refinement flag depending on the condition value
!
    check_ref = 0

    if (dpmax .ge. crefmax) then
      check_ref =  1
    end if
    if (dpmax .le. crefmin) then
      check_ref = -1
    end if

    return

!-------------------------------------------------------------------------------
!
  end function check_ref

!===============================================================================
!
end module