!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubecompute_ratio
  use cube_types
  use cubetools_parameters
  use cubetools_structure
  use cubeadm_cubeid_types
  use cubetemplate_cuberegion_types
  use cubecompute_messaging
  !
  public :: ratio
  public :: cubecompute_ratio_command
  private
  !
  type ratio_comm_t
     type(option_t), pointer :: comm
     type(cuberegion_comm_t) :: region
   contains
     procedure, public  :: register => cubecompute_ratio_register
     procedure, private :: parse    => cubecompute_ratio_parse
     procedure, private :: main     => cubecompute_ratio_main
  end type ratio_comm_t
  type(ratio_comm_t) :: ratio  
  !
  integer(kind=4), parameter :: inumcube = 1 ! Numerator
  integer(kind=4), parameter :: idencube = 2 ! Denominator
  type ratio_user_t
     type(cubeid_user_t)     :: cubeids
     type(cuberegion_user_t) :: region
   contains
     procedure, private :: toprog => cubecompute_ratio_user_toprog
  end type ratio_user_t
  !
  type ratio_prog_t
     type(cuberegion_prog_t) :: region
     type(cube_t), pointer :: numerator
     type(cube_t), pointer :: denominator
     type(cube_t), pointer :: ratio
   contains
     procedure, private :: header => cubecompute_ratio_prog_header
     procedure, private :: data   => cubecompute_ratio_prog_data
     procedure, private :: loop   => cubecompute_ratio_prog_loop
     procedure, private :: act    => cubecompute_ratio_prog_act
  end type ratio_prog_t
  !
contains
  !
  subroutine cubecompute_ratio_command(line,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    character(len=*), intent(in)    :: line
    logical,          intent(inout) :: error
    !
    type(ratio_user_t) :: user
    character(len=*), parameter :: rname='RATIO>COMMAND'
    !
    call cubecompute_message(computeseve%trace,rname,'Welcome')
    !
    call ratio%parse(line,user,error)
    if (error) return
    call ratio%main(user,error)
    if (error) continue
  end subroutine cubecompute_ratio_command
  !
  !----------------------------------------------------------------------
  !
  subroutine cubecompute_ratio_register(comm,error)
    use cubedag_allflags
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(ratio_comm_t), intent(inout) :: comm
    logical,             intent(inout) :: error
    !
    type(cubeid_arg_t) :: cubearg
    character(len=*), parameter :: comm_abstract = 'Compute the ratio of two cubes'
    character(len=*), parameter :: comm_help = &
         'For the moment, input and output cubes must be real'
    character(len=*), parameter :: rname='RATIO>REGISTER'
    !
    call cubecompute_message(computeseve%trace,rname,'Welcome')
    !
    call cubetools_register_command(&
         'RATIO','numerator denominator',&
         comm_abstract,&
         comm_help,&
         cubecompute_ratio_command,&
         comm%comm,error)
    if (error) return
    call cubearg%register(&
         'NUMERATOR',&
         'Numerator cube',&
         strg_id,&
         code_arg_mandatory,&
         [flag_any],&
         error)
    if (error) return
    call cubearg%register(&
         'DENOMINATOR',&
         'Denominator cube',&
         strg_id,&
         code_arg_mandatory,&
         [flag_any],&
         error)
    if (error) return
    !
    call comm%region%register(error)
    if (error) return
  end subroutine cubecompute_ratio_register
  !
  subroutine cubecompute_ratio_parse(comm,line,user,error)
    !----------------------------------------------------------------------
    ! RATIO cubname
    ! /SIZE sx [sy]
    ! /CENTER xcen ycen
    ! /RANGE zfirst zlast
    !----------------------------------------------------------------------
    class(ratio_comm_t), intent(in)    :: comm
    character(len=*),    intent(in)    :: line
    type(ratio_user_t),  intent(out)   :: user
    logical,             intent(inout) :: error
    !
    character(len=*), parameter :: rname='RATIO>PARSE'
    !
    call cubecompute_message(computeseve%trace,rname,'Welcome')
    !
    call cubeadm_cubeid_parse(line,comm%comm,user%cubeids,error)
    if (error) return
    call comm%region%parse(line,user%region,error)
    if (error) return
  end subroutine cubecompute_ratio_parse
  !
  subroutine cubecompute_ratio_main(comm,user,error)
    use cubeadm_timing
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(ratio_comm_t), intent(in)    :: comm
    type(ratio_user_t),  intent(inout) :: user
    logical,             intent(inout) :: error
    !
    type(ratio_prog_t) :: prog
    character(len=*), parameter :: rname='RATIO>MAIN'
    !
    call cubecompute_message(computeseve%trace,rname,'Welcome')
    !
    call user%toprog(comm,prog,error)
    if (error) return
    call prog%header(error)
    if (error) return
    call cubeadm_timing_prepro2process()
    call prog%data(error)
    if (error) return
    call cubeadm_timing_process2postpro()
  end subroutine cubecompute_ratio_main
  !
  !----------------------------------------------------------------------
  !
  subroutine cubecompute_ratio_user_toprog(user,comm,prog,error)
    use cubetools_consistency_methods
    use cubeadm_get
    !----------------------------------------------------------------------
    ! Only the dimension of the cubes are checked here on purpose for
    ! this very basic command
    !----------------------------------------------------------------------
    class(ratio_user_t), intent(in)    :: user
    type(ratio_comm_t),  intent(in)    :: comm
    type(ratio_prog_t),  intent(out)   :: prog
    logical,             intent(inout) :: error
    !
    logical :: conspb
    character(len=*), parameter :: rname='RATIO>USER>TOPROG'
    !
    call cubecompute_message(computeseve%trace,rname,'Welcome')
    !
    call cubeadm_cubeid_get_header(comm%comm,inumcube,user%cubeids,&
         code_access_imaset,code_read,prog%numerator,error)
    if (error) return
    call cubeadm_cubeid_get_header(comm%comm,idencube,user%cubeids,&
         code_access_imaset,code_read,prog%denominator,error)
    if (error) return
    !
    conspb = .false.
    call cubetools_consistency_shape(&
         'Input cube #1',prog%numerator%head,&
         'Input cube #2',prog%denominator%head,&
         conspb,error)
    if (error) return
    if (cubetools_consistency_failed(rname,conspb,error)) return
    !
    call user%region%toprog(prog%numerator,prog%region,error)
    if (error) return
    call prog%region%list(error)
    if (error) return
  end subroutine cubecompute_ratio_user_toprog
  !
  !----------------------------------------------------------------------
  !
  subroutine cubecompute_ratio_prog_header(prog,error)
    use cubedag_allflags
    use cubeadm_clone
    use cubetools_header_methods
    !----------------------------------------------------------------------
    ! For the moment, the header of the numerator is copied. On the longer
    ! term, only the common part of the header could/should be copied. The
    ! other ones should stay to unknown, as the user would be able to get
    ! the information by listing the headers of the parent cubes.
    !----------------------------------------------------------------------
    class(ratio_prog_t), intent(inout) :: prog
    logical,             intent(inout) :: error
    !
    character(len=unit_l) :: numunit,denunit
    character(len=*), parameter :: rname='RATIO>PROG>HEADER'
    !
    call cubecompute_message(computeseve%trace,rname,'Welcome')
    !
    call cubeadm_clone_header(prog%numerator,flag_ratio,prog%ratio,error)
    if (error) return
    call prog%region%header(prog%ratio,error)
    if (error) return
    ! 
    call cubetools_header_get_array_unit(prog%numerator%head,numunit,error)
    if (error) return
    call cubetools_header_get_array_unit(prog%denominator%head,denunit,error)
    if (error) return
    call cubetools_header_put_array_unit(trim(numunit)//'/'//trim(denunit),&
         prog%ratio%head,error)
    if (error) return
  end subroutine cubecompute_ratio_prog_header
  !
  subroutine cubecompute_ratio_prog_data(prog,error)
    use cubeadm_opened
    !----------------------------------------------------------------------
    ! 
    !----------------------------------------------------------------------
    class(ratio_prog_t), intent(inout) :: prog
    logical,             intent(inout) :: error
    !
    type(cubeadm_iterator_t) :: iter
    character(len=*), parameter :: rname='RATIO>PROG>DATA'
    !
    call cubecompute_message(computeseve%trace,rname,'Welcome')
    !
    call cubeadm_datainit_all(iter,error)
    if (error) return
    !$OMP PARALLEL DEFAULT(none) SHARED(prog,error) FIRSTPRIVATE(iter)
    !$OMP SINGLE
    do while (cubeadm_dataiterate_all(iter,error))
       if (error) exit
       !$OMP TASK SHARED(prog,error) FIRSTPRIVATE(iter)
       if (.not.error) &
         call prog%loop(iter,error)
       !$OMP END TASK
    enddo ! iter
    !$OMP END SINGLE
    !$OMP END PARALLEL
  end subroutine cubecompute_ratio_prog_data
  !   
  subroutine cubecompute_ratio_prog_loop(prog,iter,error)
    use cubeadm_taskloop
    use cubeadm_image_types
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(ratio_prog_t),      intent(inout) :: prog
    type(cubeadm_iterator_t), intent(inout) :: iter
    logical,                  intent(inout) :: error
    !
    type(image_t) :: numerator,denominator,ratio
    character(len=*), parameter :: rname='RATIO>PROG>LOOP'
    !
    call numerator%associate('numerator',prog%numerator,iter,error)
    if (error) return
    call denominator%associate('denominator',prog%denominator,iter,error)
    if (error) return
    call ratio%allocate('ratio',prog%ratio,iter,error)
    if (error) return
    !
    do while (iter%iterate_entry(error))
       if ((prog%region%iz%first.le.iter%ie).and.(iter%ie.le.prog%region%iz%last)) then
          call prog%act(iter%ie,numerator,denominator,ratio,error)
          if (error) return
       endif
    enddo ! ie
  end subroutine cubecompute_ratio_prog_loop
  !   
  subroutine cubecompute_ratio_prog_act(prog,ie,numerator,denominator,ratio,error)
    use cubeadm_image_types
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(ratio_prog_t),  intent(inout) :: prog
    integer(kind=entr_k), intent(in)    :: ie
    type(image_t),        intent(inout) :: numerator
    type(image_t),        intent(inout) :: denominator
    type(image_t),        intent(inout) :: ratio
    logical,              intent(inout) :: error
    !
    integer(kind=pixe_k) :: ix,iy
    integer(kind=pixe_k) :: jx,jy
    character(len=*), parameter :: rname='RATIO>PROG>ACT'
    !
    call numerator%get(ie,error)
    if (error) return
    call denominator%get(ie,error)
    if (error) return
    do iy=prog%region%iy%first,prog%region%iy%last
       jy = iy-prog%region%iy%first+1
       do ix=prog%region%ix%first,prog%region%ix%last
          jx = ix-prog%region%ix%first+1
          ratio%val(jx,jy) = numerator%val(ix,iy)/denominator%val(ix,iy)
       enddo ! ix
    enddo ! iy
    call ratio%put(ie-prog%region%iz%first+1,error)
    if (error) return
  end subroutine cubecompute_ratio_prog_act
end module cubecompute_ratio
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
