!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubetemplate_two2one_template
  !----------------------------------------------------------------------
  ! Commands that take two input cubes and produce one output cube
  !
  ! Syntax: "COMMAND cubeid1 cubeid2"
  !----------------------------------------------------------------------
  use cubetools_structure
  use cube_types
  use cubedag_flag
  use cubeadm_cubeid_types
  use cubeadm_cubeprod_types
  use cubetemplate_messaging
  !
  public :: two2one_comm_t,two2one_user_t,two2one_prog_t
  private
  !
  type :: two2one_comm_t
     type(option_t),     pointer :: comm
     type(cubeid_arg_t), pointer :: incube1
     type(cubeid_arg_t), pointer :: incube2
     type(cube_prod_t),  pointer :: oucube
   contains
     procedure, public  :: parse   => cubetemplate_two2one_parse
     procedure, public  :: command => cubetemplate_two2one_command
     procedure, private :: main    => cubetemplate_two2one_main
  end type two2one_comm_t
  !
  type two2one_user_t
     type(cubeid_user_t) :: cubeids
   contains
     procedure, public :: toprog => cubetemplate_two2one_user_toprog
  end type two2one_user_t
  !
  type two2one_prog_t
     type(cube_t), pointer :: incube1
     type(cube_t), pointer :: incube2
     type(cube_t), pointer :: oucube
   contains
     procedure, public  :: header => cubetemplate_two2one_prog_header
     procedure, private :: data   => cubetemplate_two2one_prog_data
     procedure, private :: loop   => cubetemplate_two2one_prog_loop
  end type two2one_prog_t
  !
contains
  !
  !----------------------------------------------------------------------
  !
  subroutine cubetemplate_two2one_parse(comm,line,user,error)
    !----------------------------------------------------------------------
    ! COMMAND cubeid
    !----------------------------------------------------------------------
    class(two2one_comm_t), intent(in)    :: comm
    character(len=*),      intent(in)    :: line
    class(two2one_user_t), intent(out)   :: user
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='TWO2ONE>PARSE'
    !
    call cubetemplate_message(templateseve%trace,rname,'Welcome')
    !
    call cubeadm_cubeid_parse(line,comm%comm,user%cubeids,error)
    if (error) return
  end subroutine cubetemplate_two2one_parse
  !
  subroutine cubetemplate_two2one_command(comm,line,user,prog,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(two2one_comm_t), intent(in)    :: comm
    character(len=*),      intent(in)    :: line
    class(two2one_user_t), intent(inout) :: user
    class(two2one_prog_t), intent(inout) :: prog
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='TWO2ONE>MAIN'
    !
    call cubetemplate_message(templateseve%trace,rname,'Welcome')
    !
    call comm%parse(line,user,error)
    if (error) return
    call comm%main(user,prog,error)
    if (error) continue
  end subroutine cubetemplate_two2one_command
  !
  subroutine cubetemplate_two2one_main(comm,user,prog,error)
    use cubeadm_timing
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(two2one_comm_t), intent(in)    :: comm
    class(two2one_user_t), intent(in)    :: user
    class(two2one_prog_t), intent(inout) :: prog
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='TWO2ONE>MAIN'
    !
    call cubetemplate_message(templateseve%trace,rname,'Welcome')
    !
    call user%toprog(comm,prog,error)
    if (error) return
    call prog%header(comm,error)
    if (error) return
    call cubeadm_timing_prepro2process()
    call prog%data(error)
    if (error) return
    call cubeadm_timing_process2postpro()
  end subroutine cubetemplate_two2one_main
  !
  !----------------------------------------------------------------------
  !
  subroutine cubetemplate_two2one_user_toprog(user,comm,prog,error)
    use cubeadm_get
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(two2one_user_t), intent(in)    :: user
    class(two2one_comm_t), intent(in)    :: comm
    class(two2one_prog_t), intent(inout) :: prog
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='TWO2ONE>USER>TOPROG'
    !
    call cubetemplate_message(templateseve%trace,rname,'Welcome')
    !
    call cubeadm_get_header(comm%incube1,user%cubeids,prog%incube1,error)
    if (error) return
    call cubeadm_get_header(comm%incube2,user%cubeids,prog%incube2,error)
    if (error) return
  end subroutine cubetemplate_two2one_user_toprog
  !
  !----------------------------------------------------------------------
  !
  subroutine cubetemplate_two2one_prog_header(prog,comm,error)
    use cubeadm_clone
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(two2one_prog_t), intent(inout) :: prog
    class(two2one_comm_t), intent(in)    :: comm
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='TWO2ONE>PROG>HEADER'
    !
    call cubetemplate_message(templateseve%trace,rname,'Welcome')
    !
    call cubeadm_clone_header(comm%oucube,prog%incube1,prog%oucube,error)
    if (error) return
  end subroutine cubetemplate_two2one_prog_header
  !
  subroutine cubetemplate_two2one_prog_data(prog,error)
    use cubeadm_opened
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(two2one_prog_t), intent(inout) :: prog
    logical,               intent(inout) :: error
    !
    type(cubeadm_iterator_t) :: iter
    character(len=*), parameter :: rname='TWO2ONE>PROG>DATA'
    !
    call cubetemplate_message(templateseve%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 cubetemplate_two2one_prog_data
  !
  subroutine cubetemplate_two2one_prog_loop(prog,iter,error)
    use cubeadm_taskloop
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(two2one_prog_t),    intent(inout) :: prog
    type(cubeadm_iterator_t), intent(inout) :: iter
    logical,                  intent(inout) :: error
    !
    character(len=*), parameter :: rname='TWO2ONE>PROG>LOOP'
    !
    call cubetemplate_message(templateseve%trace,rname,'Welcome')
  end subroutine cubetemplate_two2one_prog_loop
end module cubetemplate_two2one_template
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
