module clean_arrays
  use clean_def
  use image_def
  !
  ! Static variables first, allocatable next.
  !
  type (gildas), save, target :: hview  ! VIEWER DATA header
  !
  type (uvmap_par), save :: themap      ! UV_MAP parameters
  type (clean_par), target :: method    ! CLEAN Method
  type (gildas), save, target :: hbeam  ! Synthesized beam Header
  type (gildas), save, target :: hdirty ! Dirty image Header
  type (gildas), save, target :: hclean ! Clean image Header
  type (gildas), save, target :: hresid ! Residual image Header
  type (gildas), save, target :: hatten ! Field weights header
  type (gildas), save, target :: hprim  ! Primary beams Header
  type (gildas), save :: hfields        ! Fields Header
  type (gildas), save, target :: hcct   ! Clean component table Header
  type (gildas), save, target :: hmask  ! Mask Header
  type (gildas), save, target :: hsky   ! Sky brightness image Header
  type (gildas), save, target :: hcont  ! Continuum image (Clean or Sky)
  type (gildas), save :: hpv            ! Position-Velocity data
  !
  ! Self-calibration headers
  type (gildas), save :: hraw           ! Raw (non self-calibrated) UV header
  type (gildas), save :: hself          ! Self-calibrated UV header
  type (gildas), save :: hagain         ! Antenna-based gain Header
  type (gildas), save :: hbgain         ! Baseline-based gain Header
  !
  ! Short spacings
  type (gildas), save :: hsingle        ! Single Dish Cube or Table
  type (gildas), save :: hshort         ! Short spacing Cube 
  !
  ! These are UV data
  type (gildas), save, target :: huvi   ! Initial UV data Header
  type (gildas), save, target :: huv    ! Current UV data Header 
  type (gildas), save, target :: huvt   ! Transposed UV data Header
  type (gildas), save, target :: huvc   ! Continuum UV data Header
  type (gildas), save :: huvm           ! Model UV data Header
  type (gildas), save :: huvf           ! Fit residual UV data Header
  !
  ! For the Multi-Primary beams Mosaic deconvolution
  ! C_ stands for "Compact Array"
  type (clean_par), target :: c_method, cuse_method
  type (gildas), save :: c_hbeam, c_hdirty, c_hresid, c_hclean
  type (gildas), save :: c_hprim
  !
  real, allocatable, save :: g_weight(:)  ! UV weights
  real, allocatable, save :: g_v(:)       ! V values
  logical, save :: do_weig                ! Optimization of weight computing
  !
  ! Viewer data 
  real, allocatable, target, save :: dview(:,:,:)     ! VIEWER DATA area 
  ! Imaging and deconvolution arrays
  real, allocatable, target, save :: dbeam(:,:,:,:)   ! 4-D
  real, allocatable, target, save :: ddirty(:,:,:)    ! Dirty 3-D 
  real, allocatable, target, save :: dclean(:,:,:)    ! Clean 3-D
  real, allocatable, target, save :: dresid(:,:,:)    ! Residual 3-D
  real, allocatable, target, save :: dprim(:,:,:,:)   ! Primary beam 4-D
  real, allocatable, target, save :: datten(:,:,:)    ! Mosaic weights 3-D
  real, allocatable, target, save :: dsky(:,:,:)      ! Primary beam corrected 3-D
  real, allocatable, target, save :: dfields(:,:,:,:) ! Mosaic fields 4-D
  real, allocatable, target, save :: dcont(:,:)       ! Continuum image 2-D + 1 dummy ?
  real, allocatable, target, save :: dsmooth(:,:,:,:)         ! Spectrally Smoothed array UNDER TEST ONLY
  !
  ! Deconvolution arrays
  real, allocatable, target, save :: dmask(:,:,:)     ! Input 3-D 0, #0 mask
  integer, allocatable, target, save :: d_list(:)     ! List of selected pixels
  logical, allocatable, target, save :: d_mask(:,:)   ! Logical mask for pixel selection
  real, allocatable, target, save :: dcct(:,:,:)      ! Clean component values
  type (cct_par), allocatable, save :: tcc(:)         ! Clean component list
  !
  ! Channel flag list
  integer, allocatable, target, save :: dchanflag(:)  ! Per channel flag status
  !
  ! These are UV data-like arrays
  real, pointer :: duv(:,:)                        ! Current UV data
  real, allocatable, target, save :: duvi(:,:)     ! Original UV data
  real, pointer :: duvr(:,:)                       ! "Resampled" UV data
  real, pointer :: duvs(:,:)                       ! "Sorted" UV data
  real, allocatable, target, save :: duvc(:,:)     ! Sorted or Unsorted Continuum UV data
  real, allocatable, target, save :: duvt(:,:)     ! Time-Baseline sorted UV data, for UV_FLAG
  real, allocatable, target, save :: duvm(:,:)     ! Model UV data
  real, allocatable, target, save :: duvf(:,:)     ! Fit residual UV data  
  real, allocatable, target, save :: duvbg(:,:)    ! Baseline Gains (UV data like)
  real, allocatable, target, save :: duvraw(:,:)   ! Raw UV data for Self calibration
  real, allocatable, target, save :: duvself(:,:)  ! Self calibrated UV data
  real, allocatable, target, save :: dagain(:,:)   ! Antenna based gain
  !
  ! Short spacing data array
  real, allocatable, target, save :: dsingle(:,:,:)   ! Short spacing data (Table or Cube)
  !! real, allocatable, target, save :: dshort(:,:,:)    ! Short spacing 3-D cube
  ! The above one is actually accessible by hshort%r3d only
  !
  ! For the Multi-Primary beams Mosaic deconvolution
  ! C_ stands for "Compact Array"
  real, allocatable, target, save :: c_dbeam(:,:,:)
  real, allocatable, target, save :: c_ddirty(:,:,:)
  real, allocatable, target, save :: c_dclean(:,:,:)
  real, allocatable, target, save :: c_dresid(:,:,:)
  real, allocatable, target, save :: c_dprim(:,:,:)
  logical, allocatable, target, save :: c_mask(:,:)
  integer, allocatable, target, save :: c_list(:)
  real, allocatable, target, save :: c_atten(:,:,:)  ! 3-D
  !
  integer :: niter_listsize=0
  integer, allocatable :: niter_list(:)
  integer :: ares_listsize=0
  real, allocatable :: ares_list(:)
  ! List of selected fields in UV_MAP (used for UV_RESTORE and
  ! also for SHOW FIELDS)
  integer :: selected_fieldsize=0
  integer, allocatable :: selected_fields(:)
end module clean_arrays
!
module moment_arrays
  use image_def
  ! Moment Images
  type(gildas), save :: hpeak, hmean, hvelo, hwidth
  real, allocatable, target, save :: dmean(:,:), dpeak(:,:), dvelo(:,:), dwidth(:,:)
  ! Flux spectra
  integer, target, save :: flux_nf=0
  integer, target, save :: flux_nc=0
  real(4), target, save, allocatable :: flux_velo(:)
  real(8), target, save, allocatable :: flux_freq(:)
  real(4), target, save, allocatable :: flux_values(:,:)
  real(4), target, save, allocatable :: flux_errors(:,:)
end module moment_arrays
!
module uvsplit_mod
  ! Module for the UV_SPLIT command
  use image_def
  !
  integer, parameter :: opt_chan=1
  integer, parameter :: opt_file=2
  integer, parameter :: opt_freq=3
  integer, parameter :: opt_range=4
  integer, parameter :: opt_velo=5
  integer, parameter :: opt_width=6
  integer, parameter :: opt_reset=7
  integer, parameter :: opt_zero=8
  !
  character(len=filename_length) :: in_file
  character(len=filename_length) :: ou_file
  !
  type(gildas) :: hiuv
  type(gildas) :: houv
  type(gildas) :: hfuv
  integer :: nblock        ! Blocking factor
  integer :: ncompr        ! Channel compression factor
  logical :: use_file      ! /FILE option
  real :: edge_drop=0.05   ! Fraction of bandwidth dropped at edges for continuum
  !
end module uvsplit_mod
!
module clean_support
  use gkernel_types
  ! CLEAN\SUPPORT polygon, mapped on SUPPORT%
  type(polygon_t), save :: supportpol
  integer, save :: support_type  
  integer, parameter :: support_mask = 1 
  integer, parameter :: support_poly = -1
  integer, parameter :: support_none = 0
  character(len=varname_length), parameter :: supportvar='SUPPORT'
end module clean_support
!
module clean_types
  use gkernel_types
  integer, parameter :: mtype=31
  integer, parameter :: ptype=11
  integer :: ftype(1:mtype) = (/0,0,1,1,1,1,1,1,0,0,1,0,0,0,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1, 0,1/)
  character(len=12) :: vtype(1:mtype) = (/ &
  &  'COVERAGE    ',  &     ! 1
  &  'UV_DATA     ',  &     ! 2
  &  'BEAM        ',  &     ! 3
  &  'DIRTY       ',  &     ! 4
  &  'CLEAN       ',  &     ! 5
  &  'PRIMARY     ',  &     ! 6
  &  'RESIDUAL    ',  &     ! 7
  &  'MASK        ',  &     ! 8
  &  'SUPPORT     ',  &     ! 9
  &  'CCT         ',  &     ! 10
  &  'SKY         ',  &     ! 11      ! Up to PTYPE, allowed Images (FITS support allowed)
  &  'MODEL       ',  &     ! 12
  &  'FIELDS      ',  &     ! 13
  &  'CGAINS      ',  &     ! 14
  &  'SELFCAL     ',  &     ! 15
  &  'SHORT       ',  &     ! 16
  &  'SINGLEDISH  ',  &     ! 17
  &  'NOISE       ',  &     !
  &  'SNR         ',  &     ! NOISE and SNR are special, just for SHOW NOISE  
  &  'MOMENTS     ',  &     ! special, just for SHOW MOMENTS
  &  'COMPOSITE   ',  &     ! special, Moments + Flux on one plot
  &  'KEPLER      ',  &     ! special, for SHOW KEPLER
  &  'FLUX        ',  &     ! special, for SHOW FLUX and WRITE FLUX    
  &  'SOURCES     ',  &     ! special, for SHOW SOURCES
  &  'SPECTRA     ',  &     ! special, for SHOW SPECTRA 
  &  'UV_FIT      ',  &
  &  'CONTINUUM   ',  &     ! Continuum Image (if any)
  &  'SED         ',  &     ! Special, for SHOW SED
  &  'PV          ',  &     ! special, for SHOW PV
  &  'POLYGON     ',  &     ! To avoid issues with WRITE POLY
  &  'DATA        '   /)    ! DATA, must be the last one 
  !
  character(len=12) :: etype(1:mtype) = (/ &
  & '            ',  &
  & '.uvt        ',  &
  & '.beam       ',  &
  & '.lmv        ',  &
  & '.lmv-clean  ',  &
  & '.lobe       ',  &
  & '.lmv-res    ',  &
  & '.msk        ',  &
  & '.pol        ',  &
  & '.cct        ',  &
  & '.lmv-sky    ',  &
  & '.uvt        ',  &
  & '.fields     ',  &
  & '.uvt        ',  &      
  & '.tab        ',  &
  & '.lmv-sky    ',  &
  & '.tab        ',  &
  & '            ',  &
  & '            ',  &
  & '            ',  &
  & '            ',  &
  & '            ',  &
  & '.tab        ',  &
  & '            ',  &
  & '            ',  &
  & '.uvfit      ',  &
  & '.lmv-clean  ',  &
  & '.txt        ',  &
  & '            ',  &
  & '.pol        ',  &
  & '            ' /)    ! DATA, no genering extension       
  !
  integer, parameter :: mbuffer=27+1
  character(len=12) :: cbuffer(1:mbuffer) = (/ &
  &  'AGAINS      ',  &
  &  'BEAM        ',  &
  &  'CCT         ',  &
  &  'CGAINS      ',  &
  &  'CLEAN       ',  &
  &  'CLIPPED     ',  &  
  &  'CONTINUUM   ',  &
  &  'DATA        ',  &
  &  'DIRTY       ',  &
  &  'EXTRACTED   ',  &
  &  'MASK        ',  &
  &  'M_AREA      ',  &
  &  'M_PEAK      ',  &
  &  'M_VELO      ',  &
  &  'M_WIDTH     ',  &
!  &  'MODEL       ',  &
  &  'PRIMARY     ',  &
  &  'RESIDUAL    ',  &
  &  'WEIGHT      ',  &
  &  'FIELDS      ',  &
  &  'SHORT       ',  &
  &  'SINGLE      ',  &
  &  'SKY         ',  &
  &  'SLICE       ',  &
  &  'SPECTRUM    ',  &
  &  'UV          ',  &
  &  'UV_FIT      ',  &
  &  'UVCONT      ',  &
  &  'UVRADIAL    '  /)  
  character(len=36) :: sbuffer(1:mbuffer) = (/ &
!     123456789 12345678 123456789 12
  &  'Self-Cal Antenna Gains             ',  &
  &  'Synthesized Dirty Beam             ',  &
  &  'Clean Component Table              ',  &
  &  'Self-Calibration Complex Gains     ',  &
  &  'Clean-ed data cube                 ',  &
  &  'Clipped Spectrum from UV_PREVIEW   ',  &  
  &  'Continuum image from MAP_CONTINUUM ',  &
  &  'Generic VIEWER data area           ',  &        
  &  'Dirty Image                        ',  &
  &  'Image extracted by EXTRACT         ',  &
  &  'Current Mask                       ',  &
  &  'Integrated Area from MOMENTS       ',  &
  &  'Peak flux from MOMENTS             ',  &
  &  'Mean Velocity from MOMENTS         ',  &
  &  'Line Width from MOMENTS            ',  &
!  &  'MODEL       ',  &
  &  'Primary Beam                       ',  &
  &  'Residual UV table                  ',  &  
  &  'Mosaic Weight Image                ',  &
  &  'Mosaic Fields                      ',  &
  &  'Short Spacing Image                ',  &
  &  'Single-Dish Data                   ',  &
  &  'Sky Brightness (PB corrected)      ',  &
  &  'Image extracted by SLICE           ',  &
  &  'Initial Spectrum from UV_PREVIEW   ',  &
  &  'UV data                            ',  &
  &  'UV Fit results binary table        ',  &
  &  'Continuum UV data                  ',  &
  &  'Azimutally averaged UV data        '  /)  
  
  character(len=12) display_type
  !
  integer, parameter :: code_save_uv=2
  integer, parameter :: code_save_beam=3
  integer, parameter :: code_save_dirty=4
  integer, parameter :: code_save_clean=5
  integer, parameter :: code_save_primary=6
  integer, parameter :: code_save_resid=7
  integer, parameter :: code_save_mask=8
  integer, parameter :: code_save_support=9
  integer, parameter :: code_save_cct=10
  integer, parameter :: code_save_sky=11
  integer, parameter :: code_save_model=12
  integer, parameter :: code_save_fields=13
  integer, parameter :: code_save_gains=14
  integer, parameter :: code_save_short=16
  integer, parameter :: code_save_single=17
  integer, parameter :: code_save_cont=26 
  logical :: save_data(mtype)
  !
  ! Read / Write optimization
  type readop_t
    type(mfile_t) :: modif
    integer :: lastnc(2) = 0
    integer :: change = 0
  end type
  !
  type (readop_t), save :: optimize(mtype)
  !
  integer :: rw_optimize
  logical :: fits_format=.false.
end module clean_types
!
module clean_default
  use gildas_def
  use clean_def
  !
  real d_min,d_max                   ! min max of dirty image, used by MRC plots only
  real beam_size(3)      ! Major, Minor (in ") and Angle (in °)
  !
  type(clean_par), save, target :: user_method ! CLEAN parameters
  type (uvmap_par), save :: default_map, old_map, save_map
  character(len=16), save :: current_uvdata = 'DATA_UV'
  logical, save :: uv_model_updated
  logical, save :: uv_resid_updated
  logical, save :: uv_data_updated
  !
  !
  ! Call Tree Debugging
  logical, save :: call_debug = .false.
  !
  ! Parameter to select the imaging tool version. Non zero means old
  ! non-optimized code.
  integer, save :: map_version = 0
  !
  ! Parameters for determining image size
  integer, save :: map_power = 2           ! Max exponent of powers of 3 and 5
  real, save :: map_rounding = 0.05        ! Tolerance for rounding to floor
  !
  logical, save :: MappingError = .false.  ! Error status from scripts
  !
  character(len=16), save :: last_shown=' '       ! CLEAN, DATA, DIRTY or SKY
  character(len=16), save :: last_resid=' '       ! CCT or UV_FIT
  character(len=filename_length), save :: last_temporary=' '  ! Last TEMPORARY data file
  character(len=16), save :: clean_stop(2) ! CLEAN_STOP criterium
  logical, save :: view_do_loop            ! Interactive mode for VIEW
  logical, save :: show_side               ! Side view for SHOW 
  logical, save :: do_cont                 ! Save the Continuum image ?
  integer, save :: iangle_unit=-3          ! Angle Unit code, default Second
  !
  integer, save :: sys_ramsize             ! RAM size in MBytes
  !
  real(8), save :: area_size(2)            ! SIZE[2]
  real(8), save :: area_center(2)          ! CENTER[2]
  !
  character(len=64) :: defmap_center       ! MAP_CENTER string
  !
  real(4), save :: recmap_field(2)
  integer, save :: recmap_size(2)
  real(4), save :: recmap_xycell(2)
  real(4), save :: recmap_uvcell
  !
  ! Remember MCOL (Mapping Channel Range) / WCOL (Weight Channel) 
  integer, save :: saved_mcol(2)=[0,0]
  integer, save :: saved_wcol=0
  integer, save :: uvmap_mcol(2)=[0,0]
  integer, save :: uvmap_wcol=0
  !
end module clean_default
!
module clean_beams
  real, allocatable, save :: beam_ranges(:,:)
  integer, save :: nbeam_ranges
  logical, save :: beam_defined=.false.
  ! Beam size in "convenient" units (user-readable)
  real, save, target :: beam_fitted(4) ! Major & Minor axis (arcsec), Position Angle (deg) and JvM factor
  integer, save, target :: beams_number=0, beams_field=0
  ! Array (4,nbeams,nfields), in same units
  real, allocatable, save, target :: beams_param(:,:,:) ! Major, Minor, Angle, JvM
end module clean_beams
!
module uvfit_data
  ! Support module for command UV_FIT
  use image_def
  integer, parameter :: mpar=70         ! Max number of parameters
  integer, parameter :: mf=10           ! Max number of functions
  integer, parameter :: mpin=7          ! Max number of parameters per function
  real(kind=8) :: pars(mpar)            ! Parameter values
  real(kind=8) :: sw
  real, allocatable :: uvriw(:,:)       ! Work space for visibilities
  integer :: nf                         ! number of functions
  integer :: ifunc(mf)                  ! Function codes
  integer :: npfunc(mf)                 ! number of parameters per function
  logical :: savef(mf)                  ! Subtract function
  integer :: npuvfit                    ! number of points
  integer :: npar                       ! Number of parameters
  integer :: nstart(mpar)               ! Number of starts per parameter
  integer :: ncall                      ! Number of function calls
  !
  real(kind=4) :: uvf_results(mpin,mf)  ! Results for each function
  real(kind=4) :: uvf_errors(mpin,mf)   ! Errors 
  !
  type (gildas) :: huvfit               ! Table of fitted parameters
  real, allocatable :: duvfit(:,:)      ! UV_FIT results
end module uvfit_data
!
module preview_mod
  use image_def
  type(gildas), save :: htab
  type(gildas), save :: hclip 
  integer, allocatable, save :: final_lines(:)
  ! Edge Frequencies
  real(kind=8), allocatable, save :: edge_freq(:,:) 
  integer, allocatable, save :: edge_chan(:,:) 
  integer, save :: number_of_channels = 0
  integer, save :: browse_last = -1
  !
  ! Control parameters
  integer, save :: utaper=3
  real,    save :: uclip=3.0
  integer, save :: uhist=0
  integer, save :: usmooth=3
  !
end module preview_mod
!
module omp_control
  ! OPEN-MP control parameters
  logical, save :: omp_compiled = .false.
  logical, save :: omp_uvmap = .false.
  integer, save :: omp_grid = 0
  logical, save :: omp_restore_fast = .true.
  logical, save :: omp_uvmap_lock = .true.
  integer, save :: omp_single_beam = 0
  logical, save :: omp_debug = .false.
  integer, save :: omp_outer_thread = 1   ! Number of Threads at outer stage
  integer, save :: omp_inner_thread = 1   ! Number of Threads at inner stage
  integer, save :: omp_outer_threadgoal = 4 !
end module omp_control
!
module grid_control
  integer, save :: grid_bigvisi=10000000  ! Threshold for Gridding weights
  integer, save :: grid_subcell=8         ! Sub-cell per Uniform cell 
  integer, save :: grid_weighting=0       ! Weighting mode
end module grid_control
