!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! This file contains the luminosity_total_tool and luminosity_labeled_tool
! modules before implementing the LUMINOSITY command.
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! *** JP: This command requires double thinking before parallelize it!
!
! *** JP: It should be ported to subcube when the question of double cube access
! *** JP: will be sorted out
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubemain_luminosity_total_tool
  use cubetools_parameters
  use cube_types
  use cubemain_messaging
  use cubemain_windowing
  !
  public :: luminosity_total_prog_t
  private
  !
  type luminosity_total_prog_t
     type(window_array_t)  :: wind   ! Window(s) over which to compute luminosity 
     type(cube_t), pointer :: cube   ! Brightness cube
     type(cube_t), pointer :: noise  ! Noise cube
     real(kind=real_k) :: xco        ! [H2/cm^2/(K.km/s)] xco conversion factor
     real(kind=real_k) :: distance   ! [pc              ] Distance to the source
     real(kind=dble_k) :: lumi       ! [K.km/s.pc^2     ] Source Luminosity 
     real(kind=dble_k) :: dlumi      ! [K.km/s.pc^2     ] luminosity error
     real(kind=dble_k) :: tvolu      ! [km/s.pc^2       ] Total Volume
     !
   contains
     procedure, public  :: total_header => cubemain_luminosity_total_prog_header
     procedure, public  :: total_data   => cubemain_luminosity_total_prog_data
     procedure, private :: total_list   => cubemain_luminosity_total_prog_list
  end type luminosity_total_prog_t
  !
contains
  !
  subroutine cubemain_luminosity_total_prog_header(prog,error)
    !----------------------------------------------------------------------
    ! 
    !----------------------------------------------------------------------
    class(luminosity_total_prog_t), intent(inout) :: prog
    logical,                        intent(inout) :: error
    !
    character(len=*), parameter :: rname='LUMINOSITY>TOTAL>PROG>HEADER'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
  end subroutine cubemain_luminosity_total_prog_header
  !
  subroutine cubemain_luminosity_total_prog_data(prog,error)
    use cubetools_nan
    use cubeadm_opened
    use cubeadm_image_types
    !----------------------------------------------------------------------
    ! 
    !----------------------------------------------------------------------
    class(luminosity_total_prog_t), intent(inout) :: prog
    logical,                        intent(inout) :: error
    !
    integer(kind=wind_k) :: iw
    integer(kind=pixe_k) :: ix,iy
    integer(kind=long_k) :: ngood
    type(image_t) :: brightness,noise
    type(cubeadm_iterator_t) :: iter
    character(len=*), parameter :: rname='LUMINOSITY>TOTAL>PROG>DATA'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    prog%tvolu = 0d0
    prog%lumi = 0d0
    prog%dlumi = 0d0
    !
    call cubeadm_datainit_all(iter,error)
    if (error) return
    call brightness%associate('brightness',prog%cube,iter,error)
    if (error) return
    call noise%associate('noise',prog%noise,iter,error)
    if (error) return
    do while (cubeadm_dataiterate_all(iter,error))
       if (error) return
       do while (iter%iterate_entry(error))
          do iw=1,prog%wind%n
             if ((prog%wind%val(iw)%o(1).le.iter%ie).and.(iter%ie.le.prog%wind%val(iw)%o(2))) then
                call brightness%get(iter%ie,error)
                if (error) return
                call noise%get(iter%ie,error)
                if (error) return
                ngood = 0
                do iy=1,brightness%ny
                   do ix=1,brightness%nx
                      if ((.not.ieee_is_nan(noise%val(ix,iy))).and.(.not.ieee_is_nan(brightness%val(ix,iy)))) then
                         ngood = ngood+1
                         prog%lumi = prog%lumi+brightness%val(ix,iy)
                         prog%dlumi = prog%dlumi+noise%val(ix,iy)
                      endif
                   enddo ! ix
                enddo ! iy
                if (ngood.ge.1) then
                   prog%tvolu = prog%tvolu+real(ngood)
                endif
             endif ! Not NaN?
          enddo ! iw
       enddo ! ie
    enddo ! iter
    !
    call prog%total_list(error)
    if (error) return
  end subroutine cubemain_luminosity_total_prog_data
  !
  subroutine cubemain_luminosity_total_prog_list(prog,error)
    use phys_const
    use cubetools_header_methods
    use cubetools_beam_types
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(luminosity_total_prog_t), intent(inout) :: prog
    logical,                        intent(inout) :: error
    !
    integer(kind=chan_k) :: nf
    integer(kind=wind_k) :: iw
    real(kind=8) :: pixel_volume,total_surface,total_volume
    real(kind=8) :: xco_msolpspc,pc_per_sec,points_per_beam
    real(kind=8) :: luminosity,mass
    real(kind=8) :: dluminosity,dmass
    real(kind=coor_k) :: xres,yres,vres,vrange(2)
    real(kind=8), parameter :: sec_per_pc_per_dist = 206265
    type(beam_t) :: beam
    character(len=mess_l) :: mess
    character(len=*), parameter :: rname='LUMINOSITY>TOTAL>PROG>LIST'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    xres = prog%cube%head%spa%l%inc
    yres = prog%cube%head%spa%m%inc
    vres = prog%cube%head%spe%inc%v
    !
    call cubetools_header_get_spabeam(prog%cube%head,beam,error)
    if (error) return
    !
    pixel_volume = abs(xres*yres*vres)
    if (pixel_volume.eq.0d0) then
       call cubemain_message(seve%e,rname,'Pixel volume is zero valued')
       error=.true.
       return
    endif
    !
    pc_per_sec = prog%distance/sec_per_pc_per_dist ! pc
    pixel_volume = pixel_volume*(pc_per_sec*sec_per_rad)**2 ! km/s.pc^2
    !
    xco_msolpspc = prog%xco/4.6e19 ! Msol pc^-2 / (K.km/s)
    points_per_beam = abs((2*pi*beam%major*beam%minor)/(8d0*log(2d0)*xres*yres))
    !
    total_volume = prog%tvolu*pixel_volume
    luminosity = prog%lumi*pixel_volume
    dluminosity = sqrt(prog%dlumi/points_per_beam)*pixel_volume
    mass = luminosity*xco_msolpspc
    dmass = dluminosity*xco_msolpspc
    !
    write(mess,'(a,1pg12.4)')   '  Points per beam:      ',points_per_beam
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a)') '  X factor:             ',prog%xco,' (H2/cm^2) / (K.km/s)'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a)') '  X factor:             ',xco_msolpspc,' (Msol/pc^2) / (K.km/s)'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a)') '  Distance:             ',prog%distance,' pc'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a)') '  Linear size:          ',pc_per_sec,' pc/arcsec'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a,1pg12.4,a,1pg12.4,a)') '  Pixel volume:         ',  &
         abs(xres)*sec_per_rad,'" x ',abs(yres)*sec_per_rad,'" x ',&
         abs(vres),'km/s'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a)') '  Pixel volume:         ',pixel_volume,' km/s.pc^2'
    call cubemain_message(seve%r,rname,mess)
    nf = 0
    do iw=1,prog%wind%n
       nf = nf+prog%wind%val(iw)%nc
       call prog%wind%val(iw)%chan2velo(vrange,error)
       if (error) return
       write(mess,'(a,i0,a,f9.2,a,f9.2,a)') '  Velocity range #',iw,':      [',vrange(1),',',vrange(2),'] km/s'
       call cubemain_message(seve%r,rname,mess)
    enddo ! iw
    total_surface = total_volume/abs(nf*vres)
    write(mess,'(a,1pg12.4,a,1pg12.4,a)') '  Total volume:         ',total_volume,&
         ' km/s.pc^2 or ',total_volume/pixel_volume,' voxels'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a,1pg12.4,a)') '  Total surface:        ',total_surface,' pc^2      or ',  &
         total_surface/(pc_per_sec*60)**2,' arcmin^2'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a,1pg12.4,a)') '  Total luminosity:     ',luminosity,' +/- ',&
         dluminosity,' K.km/s.pc^2'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a,1pg12.4,a)') '  Total mass:           ',mass,' +/- ',dmass,' Msol'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a,1pg12.4,a)') '  Mean brightness:      ',luminosity/total_surface,' +/- ',  &
         dluminosity/total_surface,' K.km/s'
    call cubemain_message(seve%r,rname,mess)
    write(mess,'(a,1pg12.4,a,1pg12.4,a)') '  Mass surface density: ',mass/total_surface,&
         ' +/- ',dmass/total_surface,' Msol/pc^2'
    call cubemain_message(seve%r,rname,mess)
  end subroutine cubemain_luminosity_total_prog_list
end module cubemain_luminosity_total_tool
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubemain_luminosity_labeled_tool
  use cubetools_parameters
  use cubetools_array_types
  use cubeadm_cubeprod_types
  use cube_types
  use cubemain_messaging
  use cubeadm_ancillary_cube_types
  use cubemain_windowing
  use cubemain_luminosity_total_tool
  !
  public :: luminosity_labeled_comm_t,luminosity_labeled_user_t,luminosity_labeled_prog_t
  private
  !
  type, extends(ancillary_cube_comm_t) :: luminosity_labeled_comm_t
     type(cube_prod_t), pointer :: luminosity
   contains
     procedure, public  :: register => cubemain_luminosity_labeled_comm_register
  end type luminosity_labeled_comm_t
  !
  type, extends(ancillary_cube_user_t) :: luminosity_labeled_user_t
     ! Empty for the moment
  end type luminosity_labeled_user_t
  !
  type, extends(luminosity_total_prog_t) :: luminosity_labeled_prog_t
     type(ancillary_cube_prog_t)    :: labeled    ! Labeled cube
     type(cube_t), pointer          :: luminosity ! Luminosity per island
     type(real_1d_t),       private :: sum
   contains
     procedure, public  :: labeled_header => cubemain_luminosity_labeled_prog_header
     procedure, public  :: labeled_data   => cubemain_luminosity_labeled_prog_data
     procedure, private :: labeled_act    => cubemain_luminosity_labeled_prog_act
     procedure, private :: labeled_output => cubemain_luminosity_labeled_prog_output
  end type luminosity_labeled_prog_t
  !
contains
  !
  subroutine cubemain_luminosity_labeled_comm_register(comm,error)
    use cubedag_allflags
    !----------------------------------------------------------------------
    ! Register an optional "/SEGMENTS [segmentsid]" key
    !----------------------------------------------------------------------
    class(luminosity_labeled_comm_t), intent(inout) :: comm
    logical,                          intent(inout) :: error
    !
    type(cube_prod_t) :: oucube
    character(len=*), parameter :: rname='LUMINOSITY>LABELED>COMM>REGISTER'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    ! Syntax
    call comm%fully_register(&
         'SEGMENTS','[segmentsid]',&
         'Compute the luminosity per SNR segment',&
         'When /SEGMENTS is present, one luminosity value is computed&
         & per segment label. If omitted, use the last matching cube&
         & (segments flag) in the default index (DAG by default; see&
         & SET\INDEX).',&
         'SEGMENTSID','Cube of segment labels',&
         [flag_segments],&
         code_arg_optional,&
         code_read,&
         code_access_imaset,&
         error)
    if (error) return
    !
    ! Products
    call oucube%register(&
         'LUMINOSITY',&
         'Luminosity cube',&
         strg_emp,&
         [flag_luminosity],&
         comm%luminosity,&
         error,&
         access=code_cube_speset)
    if (error)  return    
  end subroutine cubemain_luminosity_labeled_comm_register
  !
  !------------------------------------------------------------------------
  !
  subroutine cubemain_luminosity_labeled_prog_header(prog,comm,error)
    use cubetools_unit
    use cubetools_axis_types
    use cubetools_arrelt_types
    use cubetools_header_methods
    use cubeadm_clone
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(luminosity_labeled_prog_t), intent(inout) :: prog
    type(luminosity_labeled_comm_t),  intent(in)    :: comm
    logical,                          intent(inout) :: error
    !
    type(axis_t) :: axis
    type(arrelt_t) :: min,max
    character(len=*), parameter :: rname='LUMINOSITY>LABELED>PROG>HEADER'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    call cubeadm_clone_header(comm%luminosity,prog%labeled%cube,prog%luminosity,error)
    if (error) return
    call cubetools_header_nullify_axset_l(prog%luminosity%head,error)
    if (error) return
    call cubetools_header_nullify_axset_m(prog%luminosity%head,error)
    if (error) return
    call cubetools_header_get_array_minmax(prog%luminosity%head,min,max,error)
    if (error) return
    call cubetools_header_get_axis_head_c(prog%luminosity%head,axis,error)
    if (error) return
    axis%name = 'Label'
    axis%unit = 'Integer'
    axis%kind = code_unit_unk
    axis%genuine = .true.
    axis%regular = .true.
    axis%ref = 1.0
    axis%val = 1.0
    axis%inc = 1.0
    axis%n = max%val
    call cubetools_header_update_axset_c(axis,prog%luminosity%head,error)
    if (error) return
  end subroutine cubemain_luminosity_labeled_prog_header
  !
  subroutine cubemain_luminosity_labeled_prog_data(prog,error)
    use cubetools_shape_types
    use cubetools_header_methods
    use cubeadm_opened
    use cubeadm_image_types
    !----------------------------------------------------------------------
    ! Unclear whether this operation can be easily parallelized
    !----------------------------------------------------------------------
    class(luminosity_labeled_prog_t), intent(inout) :: prog
    logical,                          intent(inout) :: error
    !
    type(shape_t) :: n
    type(image_t) :: brightness,label
    type(cubeadm_iterator_t) :: iter
    character(len=*), parameter :: rname='LUMINOSITY>LABELED>PROG>DATA'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    call brightness%associate('brightness',prog%cube,iter,error)
    if (error) return
    call label%associate('label',prog%labeled%cube,iter,error)
    if (error) return
    call cubetools_header_get_array_shape(prog%luminosity%head,n,error)
    if (error) return
    call prog%sum%reallocate('sum',n%c,error)
    if (error) return
    call prog%sum%set(0.0,error)
    if (error) return
    !
    call cubeadm_datainit_all(iter,error)
    if (error) return
    do while (cubeadm_dataiterate_all(iter,error))
       do while (iter%iterate_entry(error))
          call prog%labeled_act(iter%ie,brightness,label,prog%sum,error)
          if (error) return
       enddo ! ie
    enddo ! iter
    !
    call prog%labeled_output(error)
    if (error) return
  end subroutine cubemain_luminosity_labeled_prog_data
  !   
  subroutine cubemain_luminosity_labeled_prog_act(prog,ie,brightness,label,sum,error)
    use cubetools_nan
    use cubeadm_image_types
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(luminosity_labeled_prog_t), intent(inout) :: prog
    integer(kind=entr_k),             intent(in)    :: ie
    type(image_t),                    intent(inout) :: brightness
    type(image_t),                    intent(inout) :: label
    type(real_1d_t),                  intent(inout) :: sum
    logical,                          intent(inout) :: error
    !
    integer(kind=indx_k) :: il,nl
    integer(kind=pixe_k) :: ix,iy
    character(len=*), parameter :: rname='LUMINOSITY>LABELED>PROG>ACT'
    !
    nl = sum%n
    call brightness%get(ie,error)
    if (error) return
    call label%get(ie,error)
    if (error) return
    do iy=1,brightness%ny
       do ix=1,brightness%nx
          if (.not.ieee_is_nan(brightness%val(ix,iy))) then
             il = label%val(ix,iy)
             if ((0.lt.il).and.(il.le.nl)) then
                sum%val(il) = sum%val(il)+brightness%val(ix,iy)
             else
                print *,ix,iy,il,nl
             endif ! Inside [1,nl]?
          endif ! Not NaN?
       enddo ! ix
    enddo ! iy
  end subroutine cubemain_luminosity_labeled_prog_act
  !
  subroutine cubemain_luminosity_labeled_prog_output(prog,error)
    use cubeadm_ioloop
    use cubeadm_spectrum_types
    use cubeadm_taskloop
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(luminosity_labeled_prog_t), intent(inout) :: prog
    logical,                          intent(inout) :: error
    !
    type(spectrum_t) :: luminosity
    integer(kind=indx_k) :: il,nl
    integer(kind=chan_k), parameter :: one = 1
    type(cubeadm_iterator_t) :: iter
    character(len=*), parameter :: rname='LUMINOSITY>LABELED>OUTPUT'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    call luminosity%allocate('luminosity',prog%luminosity,iter,error)
    if (error) return
    call cubeadm_io_iterate(one,one,prog%luminosity,error)
    if (error) return
    nl = prog%sum%n
    luminosity%y%val(1) = prog%sum%val(nl)
    do il=1,nl-1
       luminosity%y%val(il+1) = luminosity%y%val(il)+prog%sum%val(nl-il)
    enddo ! il
    call luminosity%put(one,error)
    if (error) return
  end subroutine cubemain_luminosity_labeled_prog_output
end module cubemain_luminosity_labeled_tool
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubemain_luminosity
  use cubetools_parameters
  use cubetools_structure
  use cubetools_unit_arg
  use cubeadm_cubeid_types
  use cubemain_messaging
  use cubemain_range
  use cubemain_luminosity_labeled_tool
  !
  public :: luminosity
  private
  !
  real(kind=4), parameter :: galxco = 2e20
  !
  type :: luminosity_comm_t
     type(option_t),         pointer :: comm
     type(option_t),         pointer :: dist
     type(unit_arg_t),       pointer :: dist_unit
     type(option_t),         pointer :: xco
     type(cubeid_arg_t),     pointer :: cube
     type(cubeid_arg_t),     pointer :: noise
     type(luminosity_labeled_comm_t) :: labeled
     type(range_opt_t)               :: range
   contains
     procedure, public  :: register       => cubemain_luminosity_comm_register
     procedure, private :: parse          => cubemain_luminosity_comm_parse
     procedure, private :: parse_distance => cubemain_luminosity_comm_parse_distance
     procedure, private :: parse_xval     => cubemain_luminosity_comm_parse_xval
     procedure, private :: main           => cubemain_luminosity_comm_main
  end type luminosity_comm_t
  type(luminosity_comm_t) :: luminosity
  !
  type luminosity_user_t
     type(cubeid_user_t)             :: cubeids
     type(luminosity_labeled_user_t) :: labeled
     type(range_array_t)             :: range             ! Range(s) over which to compute luminosity 
     logical                         :: dorange = .false. ! Was option /RANGE present 
     real(kind=real_k)               :: xco = -1.         ! [---] User xco conversion factor    
     real(kind=real_k)               :: distance          ! [pc ] Distance to the source
   contains
     procedure, private :: toprog => cubemain_luminosity_user_toprog
  end type luminosity_user_t
  !
contains
  !
  subroutine cubemain_luminosity_command(line,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    character(len=*), intent(in)    :: line
    logical,          intent(inout) :: error
    !
    type(luminosity_user_t) :: user
    character(len=*), parameter :: rname='LUMINOSITY>COMMAND'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    call luminosity%parse(line,user,error)
    if (error) return
    call luminosity%main(user,error)
    if (error) continue
  end subroutine cubemain_luminosity_command
  !
  !----------------------------------------------------------------------
  !
  subroutine cubemain_luminosity_comm_register(comm,error)
    use cubedag_allflags
    use cubetools_unit
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(luminosity_comm_t), intent(inout) :: comm
    logical,                  intent(inout) :: error
    !
    type(cubeid_arg_t) :: incube
    type(unit_arg_t) :: unitarg
    type(standard_arg_t) :: stdarg
    character(len=*), parameter :: rname='LUMINOSITY>COMM>REGISTER'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    ! Syntax
    call cubetools_register_command(&
         'LUMINOSITY','[signalid [noiseid]]',&
         'Compute luminosity diagnostics for a signal cube',&
         'Compute the total luminosity from a signal cube over the selected&
         & spectral range(s).'//strg_bl//&
         'Behavior:'//strg_cr//&
         '- /DISTANCE and /X control the physical scaling used for&
         & luminosity reporting.'//strg_cr//&
         '- /RANGE selects integration windows; if omitted, the full&
         & spectral axis is used.'//strg_cr//&
         '- /SEGMENTS switches from total-luminosity mode to per-segment&
         & luminosity mode.'//strg_bl//&
         'Examples:'//strg_cr//&
         'CUBE> LUMINOSITY 12co10:cube 12co10:noise /DISTANCE 8200 pc'//strg_cr//&
         'CUBE> LUMINOSITY 12co10:cube 12co10:noise /RANGE -5 15 km/s&
         & /DISTANCE 8200 pc /X 2.3e20'//strg_cr//&
         'CUBE> LUMINOSITY 12co10:cube 12co10:noise /SEGMENTS&
         & 12co10:segments /DISTANCE 8200 pc',&
         cubemain_luminosity_command,&
         comm%comm,error)
    if (error) return
    call incube%register(&
         'SIGNALID',&
         'Signal cube identifier',&
         'If omitted, use the last matching cube (cube flag) in&
         & the default index (DAG by default; see SET\INDEX).',&
         code_arg_optional, &
         [flag_cube],&
         code_read,&
         code_access_imaset,&
         comm%cube,&
         error)
    if (error) return
    call incube%register(&
         'NOISEID',&
         'Noise cube identifier',&
         'If omitted, use the last matching cube (noise flag) in&
         & the default index (DAG by default; see SET\INDEX).',&
         code_arg_optional, &
         [flag_noise],&
         code_read,&
         code_access_imaset,&
         comm%noise,&
         error)
    if (error) return
    !
    call comm%labeled%register(error)
    if (error) return
    !
    call comm%range%register('RANGE',&
         'Define the velocity range(s) over which to compute luminosity',&
         range_is_multiple,error)
    if (error) return
    !
    call cubetools_register_option(&
         'DISTANCE','dist [unit]',&
         'Define the distance to the source',&
         'This key is required. DISTANCE is converted to internal&
         & distance units before luminosity is computed.',&
         comm%dist,error)
    if (error) return
    call stdarg%register(&
         'dist', &
         'Distance to the source',&
         'Must be strictly positive.',&
         code_arg_mandatory,&
         error)
    if (error) return
    call unitarg%register(&
         'unit', &
         'Distance unit',&
         '"*" or "=" mean current distance unit is used',&
         code_arg_optional,&
         code_unit_dist,&
         comm%dist_unit,&
         error)
    if (error) return
    !
    call cubetools_register_option(&
         'X','val',&
         'Define the luminosity-to-mass conversion factor',&
         'Override the CO-to-H2 Galactic default conversion factor&
         & (2e20 (H2.cm-2)/(K.km/s)).',&
         comm%xco,&
         error)
    if (error) return
    call stdarg%register(&
         'val', &
         'Luminosity-to-mass conversion factor',&
         'Must be strictly positive.',&
         code_arg_mandatory,&
         error)
    if (error) return
  end subroutine cubemain_luminosity_comm_register
  !
  subroutine cubemain_luminosity_comm_parse(comm,line,user,error)
    !----------------------------------------------------------------------
    ! LUMINOSITY [signalid [noiseid]]
    ! [/SEGMENTS [segmentsid]]
    ! [/RANGE v11 v12 [... [vn1 vn2]] [unit]]
    ! /DISTANCE dist [unit]
    ! [/X xval]
    !----------------------------------------------------------------------
    class(luminosity_comm_t), intent(inout) :: comm
    character(len=*),         intent(in)    :: line
    type(luminosity_user_t),  intent(out)   :: user
    logical,                  intent(inout) :: error
    !
    character(len=*), parameter :: rname='LUMINOSITY>COMM>PARSE'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    call cubeadm_cubeid_parse(line,comm%comm,user%cubeids,error)
    if (error) return
    call comm%labeled%parse(line,user%labeled,error)
    if (error) return
    call comm%range%parse(line,user%dorange,user%range,error)
    if (error) return
    call comm%parse_distance(line,user,error)
    if (error) return
    call comm%parse_xval(line,user,error)
    if (error) return
  end subroutine cubemain_luminosity_comm_parse
  !
  subroutine cubemain_luminosity_comm_parse_distance(comm,line,user,error)
    use cubetools_unit
    !----------------------------------------------------------------------
    ! /DISTANCE dist [unit]
    !----------------------------------------------------------------------
    class(luminosity_comm_t), intent(in)    :: comm
    character(len=*),         intent(in)    :: line
    type(luminosity_user_t),  intent(inout) :: user
    logical,                  intent(inout) :: error
    !
    character(len=argu_l) :: userunit
    type(unit_user_t) :: unit
    logical :: present
    character(len=*), parameter :: rname='LUMINOSITY>COMM>PARSE>DISTANCE'
    !
    call comm%dist%present(line,present,error)
    if (error) return
    if (present) then
       call cubetools_getarg(line,comm%dist,1,user%distance,mandatory,error)
       if (error) return
       if (user%distance.le.0) then
          call cubemain_message(seve%e,rname,'Distance must be positive')
          error=.true.
          return
       endif
       !
       userunit = strg_star
       call cubetools_getarg(line,comm%dist,2,userunit,.not.mandatory,error)
       if (error) return
       call unit%get_from_name_for_code(userunit,code_unit_dist,error)
       if (error) return
       user%distance = user%distance*unit%prog_per_user
    else
       call cubemain_message(seve%e,rname,'The distance source-earth must be given')
       error=.true.
       return
    endif
  end subroutine cubemain_luminosity_comm_parse_distance
  !
  subroutine cubemain_luminosity_comm_parse_xval(comm,line,user,error)
    !----------------------------------------------------------------------
    ! /X xval
    !----------------------------------------------------------------------
    class(luminosity_comm_t), intent(in)    :: comm
    character(len=*),         intent(in)    :: line
    type(luminosity_user_t),  intent(inout) :: user
    logical,                  intent(inout) :: error
    !
    logical :: present
    character(len=*), parameter :: rname='LUMINOSITY>COMM>PARSE>XVAL'
    !
    call comm%xco%present(line,present,error)
    if (error) return
    if (present) then
       call cubetools_getarg(line,comm%xco,1,user%xco,mandatory,error)
       if (error) return
       if (user%xco.le.0) then
          call cubemain_message(seve%e,rname,'Xco must be positive')
          error=.true.
          return
       endif
    else
       call cubemain_message(seve%w,rname,'X not given => Assumes Galactic Xco factor')
       user%xco = galxco
    endif
  end subroutine cubemain_luminosity_comm_parse_xval
  !
  subroutine cubemain_luminosity_comm_main(comm,user,error)
    use cubeadm_timing
    use cubeadm_get
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(luminosity_comm_t), intent(in)    :: comm
    type(luminosity_user_t),  intent(in)    :: user
    logical,                  intent(inout) :: error
    ! 
    type(luminosity_labeled_prog_t) :: prog
    character(len=*), parameter :: rname='LUMINOSITY>COMM>MAIN'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    call user%toprog(comm,prog,error)
    if (error) return
    call cubeadm_timing_prepro2process()
    if (prog%labeled%do) then
       call prog%labeled_header(comm%labeled,error)
       if (error) return
       call prog%labeled_data(error)
       if (error) return
    else
       call prog%total_header(error)
       if (error) return
       call prog%total_data(error)
       if (error) return
    endif
    call cubeadm_timing_process2postpro()
  end subroutine cubemain_luminosity_comm_main
  !
  !----------------------------------------------------------------------
  !
  subroutine cubemain_luminosity_user_toprog(user,comm,prog,error)
    use cubetools_consistency_methods
    use cubeadm_get
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(luminosity_user_t),        intent(in)    :: user
    type(luminosity_comm_t),         intent(in)    :: comm
    type(luminosity_labeled_prog_t), intent(inout) :: prog
    logical,                         intent(inout) :: error
    !
    logical :: conspb
    character(len=*), parameter :: rname='LUMINOSITY>USER>TOPROG'
    !
    call cubemain_message(mainseve%trace,rname,'Welcome')
    !
    conspb = .false.
    !
    call cubeadm_get_header(comm%cube,user%cubeids,prog%cube,error)
    if (error) return
    !
    call cubeadm_get_header(comm%noise,user%cubeids,prog%noise,error)
    if (error) return
    call cubetools_consistency_signal_noise(&
         'Brightness cube',prog%cube%head,&
         'Noise',prog%noise%head,&
         conspb,error)
    if (error) return
    if (cubetools_consistency_failed(rname,conspb,error)) return
    !
    call user%labeled%toprog(comm%labeled,prog%labeled,error)
    if (error) return
    if (prog%labeled%do) then
       ! User requests to use a labeled cube
       call cubetools_consistency_spatial(&
            'Brightness cube',prog%cube%head,&
            'Labeled cube',prog%labeled%cube%head,&
            conspb,error)
       if (error) return
       if (cubetools_consistency_failed(rname,conspb,error)) return
    endif
    !
    call comm%range%user2prog(prog%cube,user%range,prog%wind,error)
    if (error) return
    prog%distance = user%distance
    prog%xco = user%xco
  end subroutine cubemain_luminosity_user_toprog
end module cubemain_luminosity
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
