!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! We first setup the input files of the different tasks that will be used
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin data gag_scratch:uv-average.init
  task\character "Input UV table"         UV_INPUT$  'myself%input'
  task\character "Output UV table"        UV_OUTPUT$ 'myself%average'
  task\values    "First and last values of each valid range" RANGES$ 'myself%first' 'myself%last'
  task\character "Type of values"         CTYPE$  CHANNEL
  task\go
end data gag_scratch:uv-average.init
!
begin data gag_scratch:uv-fcct.init
  task\file "Input UV Sample Table"                     UVSAMPLE$ 'myself%input'
  task\file "Input .CCT List "                          IMAGE$ 'myself%model'
  task\file "Output UV Model Table"                     UVMODEL$ 'myself%model'
  task\real "UV Model Table frequency"                  FREQUENCY$ 0
  task\logical "Accurate (YES) or rough (NO) precision" LARGE$ YES
  task\integer "Number of clean components retained"    CLEAN$ 'myself%niter'
  task\go
end data gag_scratch:uv-fcct.init
!
begin data gag_scratch:uv-gain.init
  task\character  "UV data table"              UVDATA$  'myself%input'
  task\character  "UV model table"             UVMODEL$ 'myself%model'
  task\character  "UV gain table"              UVGAIN$  'myself%gain'
  task\character  "UV calibrated table"        UVCAL$   'myself%output'
  task\real    "Integration time (s)"          TINTEG$  'myself%time'
  task\real    "Minimum SNR "                  SNR$     'myself%snr'
  task\logical "Flag uncalibrated data"        FLAG$    'myself%flag'
  task\integer "Chan. num. in UVDATA"          CHANNEL$ 1
  task\logical "Calibrate amplitudes"          DO_AMP$ NO
  task\logical "Calibrate phases"              DO_PHA$ YES
  task\logical "Antenna based"                 ANTENNA_BASED$ YES
  task\integer "Reference antenna (0==>guess)" REFERENCE_A$ 'myself%refant'
  task\character  "Phase solution table"       UVSOL$ 'myself%phasol'
  task\go
end data gag_scratch:uv-gain.init
!
begin data gag_scratch:uv-cal.init
  task\character  "UV data table "      UVDATA$ 'myself%input'
  task\character  "UV gain table "      UVGAIN$ 'myself%gain'
  task\character  "UV calibrated table" UVCAL$  'myself%output'
  task\real       "Amplitude gain"      AMPLI_GAIN$ 0
  task\real       "Phase gain"          PHASE_GAIN$ 1
  task\logical "Flag uncalibrated data" FLAG$   'myself%flag'
  task\go
end data gag_scratch:uv-cal.init
!
begin data gag_scratch:selfcal.hlp
1 Self-calibration widget

     This is the main interface to do self-calibration of single field
     UV tables, mosaics are not supported.  A pseudo-continuum data set
     is created by averaging the channels in the specified channel
     range, to provide improved sensitivity to find a solution.

     In the end the solution is applied to the original spectral line
     data set.

2 SELF%INPUT
     Name of the input uv table (without extension, no default)

2 MAP_CELL
     Pixel size in arcseconds. This should be smaller than one
     third of the minor axis of the synthesized beam. Default is 0
     meaning that mapping will find an appropriate value to correctly
     sample the synthesize beam.

2 MAP_SIZE
     Map size in pixels. Default is 0, meaning a power of two which gives
     about twice the size of the primary beam size.  For efficiency of FFT,
     it is better to pick a power of two.

2 WEIGHT_MODE
     Kind of weighting. Default is NATURAL weighting to maximize the point
     source sensitivity.

2 UV_CELL[2]
     Threshold for the robust weighting

2 SELF%CHANNEL
     Channel range used to produce the pseudo-continuum. 0 0 means all
     channels.

2 SELF%METHOD
     Selection of the CLEAN algorithm used for the
     deconvolution. HOGBOM works even in the presence of strong
     sidelobes. CLARK is faster than HOGBOM. Only HOGBOM, CLARK or SDI
     can be used for self-calibration, as they rely on the notion of
     clean components.

2 SELF%NITER%INIT

     Number of clean components used to deconvolve the pseudo-continuum
     before and after the self-calibration process to evaluate its success.

2 SELF%NLOOP
     Number of self-calibration loops to be executed.

2 SELF%TIMES
     List of integration times (in seconds) to be used for each
     self-calibration loop.

     At NOEMA, 45 sec is the normal minimum integration time. Depending
     on Signal to Noise, you may need to have this longer, e.g. 120 sec.
     For several loops, start with a longer value, and decrease only
     at the end.

     At ALMA, the minimum integration time is 6 sec. At VLA, this may
     be as small as 1 sec.

2 SELF%NITERS
     List of number of iterations to be used for each self-calibration
     step.

     For simple structures, 10 may be enough. For more complex ones,
     be sure to include enough Clean components in the model.  More
     components can be taken at each step, although the better
     knowledge of phase errors often allow the source to be
     represented with a smaller number of components after
     self-calibration than before.

2 SELF%SNR
     Minimum SNR to consider a solution for an antenna.

2 SELF%REFANT
     The reference antenna number. If 0, the program will pick the one
     with the shortest average baselines.

2 SELF%FLAG
     Flag visilibities that can not be self-calibrated. Possible
     values are yes or no or * (* means yes).

2 SELF%OTHER
     Name of a second uv table over which the gain computed from SELF%INPUT
     are to be applied. Default is *, i.e. gains are transferred onto
     the UV table used to produce the pseudo continuum.

2 SELF%NITER%EXIT
     Number of clean components used to deconvolve the final uv table and
     evaluate the gain in image quality.

2 MYSELF%CURRENT
     Name of the last imaged uv table (without extension, this is
     updated automatically)

2 SELF%SCALE
     Minimum and maximum intensities used when plotting the residuals,
     clean components, and final results.

end data gag_scratch:selfcal.hlp
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! We then defined the different engines that will be used during the
! selfcalibration process
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin procedure selfcal-init
  !---------------------------------------------------------------------------
  ! structure, intent(out) :: self
  ! structure, intent(out) :: myself
  !
  ! This procedure defines the global variables that will be used during
  ! the selfcal process:
  !   - The SELF structure contains user control variables. In this control
  !     structure, a value of zero means that the program has to find a
  !     clever default.
  !   - The MYSELF structure contains script defined variables. Some of
  !     them may be set by the user by use of an API. For instance,
  !     the number of selfcal loop is defined through
  !     MAPPING> @ selfcal-set-loop 1
  !---------------------------------------------------------------------------
  if (exist(self)) then
     if (.not.self%v20) delete /var self
  endif
  if .not.exist(self) then
     define structure self /global
     define character*256 self%input self%other /global
     define double self%snr self%times[1] self%scale[2] /global
     define structure self%niter /global
     define integer self%niter%init self%niter%exit /global
     define integer self%nloop self%niters[1] /global
     define integer self%channel[2] self%refant self%naver /global
     define logical self%display self%v20 /global
     define character self%flag*3 /global
     define character self%method*16 /global
     define character self%dir*256 /global
     !
     define command SELFCAL "@ selfcal-main"
  endif
  let self%channel 0
  let self%refant 0
  let self%snr 6
  let self%naver 0
  let self%nloop 1
  let self%niter%init 50
  let self%niter%exit self%niter%init
  let self%niters 10
  let self%times 45 ! [sec]
  let self%method "HOGBOM"
  let self%flag "*"
  let self%display yes
  let self%scale 0
  let self%v20 yes
  let self%dir "./selfcal/"
  let self%other "*"
  !
  if .not.exist(myself) then
     define structure myself /global
     define character*256 myself%usage /global
     define character*256 myself%input myself%output myself%average myself%current /global
     define character*256 myself%model myself%gain myself%phasol myself%selfcal /global
     define real myself%time myself%snr /global
     define integer myself%nloop myself%iloop myself%niter /global
     define integer myself%first myself%last myself%refant /global
     define integer myself%nchan /global
     define logical myself%flag /global
     define character myself%subdir*256 /global
     let myself%usage "Usage: SELFCAL EXAMPLE|STATUS|PSEUDO-CONT|SET-NLOOP|SET-NITERS|SET-TIMES|START|ITERATE|STOP|TRANSFER-GAIN"
  endif
  ! Other default values
  @ selfcal-set-loop-parameters
end procedure selfcal-init
!
begin procedure selfcal-example
  say ""
  say "! Fix all imaging and deconvolution parameters, except the number of iterations"
  say "MAPPING> let map_size 1024 1024  ! Number of pixel in images"
  say "MAPPING> let map_cell 0.18 0.18  ! Size of pixel in arcsec"
  say "MAPPING> let weight_mode robust  ! Weighting mode"
  say "MAPPING> let uv_cell 7.5 1.0     ! Weighting parameters"
  say "MAPPING> let method ""HOGBOM""     ! Deconvolution method"
  say "!"
  say "! Define the self-calibration strategy"
  say "MAPPING> let self%input example1 ! Basename of uv table to be self-calibrated"
  say "MAPPING> let self%channel 0 0    ! Channels to use to form the pseudo-continuum"
  say "MAPPING> let self%snr 6          ! Minimum signal-to-noise ratio to compute the gains"
  say "MAPPING> let self%refant 0       ! 0 means: please choose the best reference antenna"
  say "MAPPING> selfcal set-flag yes    ! Flag visilibities that can not be self-calibrated"
  say "Visibilities that can not be self-calibrated will be flagged"
  say "MAPPING> selfcal set-nloop 3     ! Number of self-calibration loops set to 3"
  say "Please update the number of integration times and clean iterations accordingly"
  say "If a self-calibration is under way, restart it"
  say "MAPPING> selfcal set-times 45 45 45 ! Integration time for the 3 iterations"
  say "Integration times set to"
  say "Loop #1: 45 s"
  say "Loop #2: 45 s"
  say "Loop #3: 45 s"
  say "MAPPING> selfcal set-niters 100 200 400 ! Number of clean components for the 3 iterations"
  say "Number of clean iterations set to"
  say "Loop #1: 100"
  say "Loop #2: 200"
  say "Loop #3: 400"
  say "!"
  say "! Compute pseudo-continuum uv table"
  say "MAPPING> selfcal pseudo-cont ! Here it is the continuum uv table itself!"
  say "MAPPING> selfcal start 1000  ! Image raw table with 1000 components"
  say "MAPPING> selfcal iterate     ! Iterate once and display the result"
  say "MAPPING> selfcal iterate     ! Iterate once more and display the result"
  say "MAPPING> selfcal iterate     ! Iterate once more and display the result"
  say "MAPPING> selfcal stop 1000   ! Image selfcal table with 1000 components"
  say "!"
  say "Transfer the phase calibration gain and compare results before/after selfcal"
  say "MAPPING> selfcal transfer-gain      ! Transfer gains from pseudo-continuum to input table"
  say "MAPPING> selfcal image-raw 4000     ! Image raw table with 4000 components"
  say "MAPPING> selfcal image-selfcal 4000 ! Image selfcal table with 4000 components"
  say "MAPPING> selfcal compare-snr        ! Compare raw and selfcalibrated results"
  say "MAPPING> selfcal status             ! Resume all parameters used during selfcal"
  say ""
end procedure selfcal-example
!
begin procedure selfcal-status
  say ""
  say "Bookkeeping parameters"
  say "  Directory for intermediate products (default = ./selfcal/): self%dir        = "'self%dir'
  say "  Input uv table name                 (no default)          : self%input      = "'self%input'
  say ""
  say "Imaging and deconvolution parameters"
  say "  Pixel size                 [arcsec] (default: 0 0)        : map_cell        = "'map_cell[1]'" x "'map_cell[2]'
  say "  Map size                   [pixel ] (default: 0 0)        : map_size        = "'map_size[1]'" x "'map_size[2]'
  say "  Weighting mode             [------] (default: NATURAL)    : weight_mode     = "'weight_mode'
  say "  Robust weighting parameter [------] (default: 1)          : uv_cell[2]      = "'uv_cell[2]'
  say "  Deconvolution method       [------] (default: HOGBOM)     : self%method     = "'self%method'
  say "  # of clean components for pseudo-continuum    (no default): self%niter%init = "'self%niter%init'
  say "  # of clean components for final deconvolution (no default): self%niter%exit = "'self%niter%exit'
  say ""
  say "Parameters to produce the pseudo-continuum uv table"
  say "  Channel range              [------] (default: 0 0)        : self%channel    = "'self%channel[1]'" - "'self%channel[2]'
  say ""
  say "Parameters to self-calibration the pseudo-continuum uv table"
  say "  Min SNR to self-calibrate  [------] (default: 6)          : self%snr        = "'self%snr'
  say "  Number of selfcal loops    [------] (default: 1)          :                   "'myself%nloop'
  for iloop 1 to myself%nloop
     say "  Loop #"'iloop'
     say "    Integration time         [second] (default: 45)         :                   "'myself%times[iloop]'
     say "    # of selfcal components  [------] (default: 10)         :                   "'myself%niters[iloop]'
  next ! iloop
  say ""
  say "Parameters to transfer the gain solution"
  say "  uv table used for the transfer      (default = *)         : self%other      = "'self%other'
  say ""
end procedure selfcal-status
!
begin procedure selfcal-make-subdir
  let myself%subdir 'self%dir'
  sic mkdir 'myself%subdir'
end procedure selfcal-make-subdir
!
begin procedure selfcal-check-name
  !---------------------------------------------------------------------------
  ! character, intent(in) :: self%input
  !
  ! This procedure checks whether self%input has been setup and the
  ! associated uv table exists. Else it returns with an error.
  ! ---------------------------------------------------------------------------
  if (self%input.eq." ") then
     message e selfcal "Empty input basename."
     message e selfcal "Set the SELF%INPUT variable"
     return base
  else
     define character filename*256
     let filename 'self%input'".uvt"
     if .not.file(filename) then
        message e selfcal "Unknown input uv table: "'filename'
        message e selfcal "Reset the SELF%INPUT variable"
        return base
     endif
  endif
end procedure selfcal-check-name
!
begin procedure selfcal-pseudo-cont
  !---------------------------------------------------------------------------
  ! character,  intent(in)  :: self%input
  ! character,  intent(out) :: self%input
  ! character,  intent(out) :: self%average
  ! character,  intent(out) :: self%current
  ! integer,    intent(in)  :: self%channel[2]
  ! integer,    intent(out) :: myself%first
  ! integer,    intent(out) :: myself%last
  !
  ! This procedure:
  !    1. averages the uv table channels from myself%first to
  !       myself%last. These variables are defined either by the user
  !       defined self%channel or default to 1 and nchan.
  !    2. sets different file basenames.
  !---------------------------------------------------------------------------
  @ selfcal-check-name
  define header myuv 'self%input'.uvt read
  if (self%channel[1].eq.0) then
     let myself%first 1
  else
     let myself%first self%channel[1]
  endif
  if (self%channel[2].eq.0) then
     let myself%last myuv%nchan
  else
     let myself%last self%channel[2]
  endif
  let myself%nchan myuv%nchan
  delete /var myuv
  @ selfcal-make-subdir
  let myself%input 'self%input'
  let myself%average 'myself%subdir''self%input'"-ave"
  read uv 'myself%input'
  if (self%naver.eq.0) then
     uv_continuum
  else if (self%naver.lt.0) then
     message e selfcal-pseudo-cont "self%naver must be >= 0."
     return base
  else
     uv_continuum 'self%naver'
  endif
  write uv 'myself%average'
  let myself%current 'myself%average'
  !pause
end procedure selfcal-pseudo-cont
!
begin procedure selfcal-set-flag
  !---------------------------------------------------------------------------
  ! integer, intent(in)  :: &1 or self%flag
  ! integer, intent(out) :: myself%flag
  !
  ! This procedure updates the behavior of uv_gain and uv_cal with respect
  ! to un-self-calibrated data (ie, flag or keep).
  !---------------------------------------------------------------------------
  define character flag*3
  if (pro%narg.eq.1) then
     let flag "&1" /upper
  else
     let flag 'self%flag' /upper
  endif
  if (flag.eq."*") then
     let myself%flag yes
  else if (flag.eq."YES") then
     let myself%flag yes
  else if (flag.eq."NO") then
     let myself%flag no
  else
     message e selfcal-set-flag "Unknown flag status: "'flag'
     message e selfcal-set-flag "Widget usage: Set the self%flag variable"
     message e selfcal-set-flag "Command line usage: SELFCAL SET-FLAG YES|NO|*"
     return base
  endif
  if (myself%flag) then
     message r selfcal-set-flag "Visibilities that can not be self-calibrated will be flagged"
  else
     message r selfcal-set-flag "Visibilities that can not be self-calibrated will be kept as they are"
  endif
  message r selfcal-set-flag ""
end procedure selfcal-set-flag
!
begin procedure selfcal-set-nloop
  !---------------------------------------------------------------------------
  ! integer, intent(in)  :: &1 or self%nloop
  ! integer, intent(out) :: myself%nloop
  ! integer, intent(out) :: myself%iloop
  !
  ! This procedure update the number of self-calibration loop and reset the
  ! loop counter to -1
  !---------------------------------------------------------------------------
  if ((pro%narg.eq.0).and.(self%nloop.le.0)) then
     message e selfcal-set-nloop "Missing number of loops"
     message e selfcal-set-nloop "Widget usage: Set the myself%nloop variable"
     message e selfcal-set-nloop "Command line usage: SELFCAL SET-NLOOP nloop"
     return base
  else if (pro%narg.ge.1) then
     let myself%nloop &1
  else
     let myself%nloop self%nloop
  endif
  if (myself%nloop.le.0) then
     message e selfcal-set-nloop "Negative or zero number of selfcal iteration"
     return base
  endif
  let myself%iloop -1
  message r selfcal-set-nloop "Number of self-calibration loops set to "'myself%nloop'
  message r selfcal-set-nloop "Please update the number of integration times and clean iterations accordingly"
  message r selfcal-set-nloop "If a self-calibration is under way, restart it"
  message r selfcal-set-nloop ""
end procedure selfcal-set-nloop
!
begin procedure selfcal-set-times
  !---------------------------------------------------------------------------
  ! double,  intent(in)  :: self%times
  ! integer, intent(in)  :: myself%nloop
  ! double,  intent(out) :: myself%times
  !
  ! This procedure resizes the myself%times array according to the number
  ! of selfcal loop.
  !---------------------------------------------------------------------------
  if (exist(myself%times)) then
     if (size(myself%times).ne.myself%nloop) then
        delete /var myself%times
        define double myself%times[myself%nloop] /global
     endif
  else
     define double myself%times[myself%nloop] /global
  endif
  define integer nloop
  if (pro%narg.eq.0) then
     let nloop size(self%times)
     if (nloop.gt.myself%nloop) then
        let myself%times self%times[1:myself%nloop]
	message w selfcal-set-times "Times for loops "'myself%nloop+1'"-"'nloop'" ignored"
     else if (nloop.eq.myself%nloop) then
	let myself%times self%times
     else
        let myself%times[1:nloop] self%times
	if (myself%nloop.gt.1) then
           let myself%times['nloop+1':myself%nloop] self%times[nloop]
	endif
     endif
  else
     let nloop pro%narg
     if (nloop.ge.myself%nloop) then
        for iloop 1 to myself%nloop
           let myself%times[iloop] 'pro%arg[iloop]'
        next iloop
	if (nloop.gt.myself%nloop) then
	   message w selfcal-set-times "times for loops "'myself%nloop+1'"-"'nloop'" ignored"
        endif
     else
        for iloop 1 to nloop
           let myself%times[iloop] 'pro%arg[iloop]'
        next iloop
        let myself%times['nloop+1':myself%nloop] 'pro%arg[pro%narg]'
     endif
  endif
  message r selfcal-set-times "Integration times set to"
  for iloop 1 to myself%nloop
     if (iloop.le.nloop) then
	message r selfcal-set-times "  Loop #"'iloop'": "'myself%times[iloop]'" s"
     else
	message r selfcal-set-times "  Loop #"'iloop'": "'myself%times[iloop]'" s (extrapolated from loop "'nloop'")"
     endif
  next iloop
  message r selfcal-set-times ""
end procedure selfcal-set-times
!
begin procedure selfcal-set-niters
   !---------------------------------------------------------------------------
   ! integer, intent(in)  :: self%niters
   ! integer, intent(in)  :: myself%nloop
   ! double,  intent(out) :: myself%niters
   !
   ! This procedure resizes the myself%niters array according to the number
   ! of selfcal loop.
   !---------------------------------------------------------------------------
   if (exist(myself%niters)) then
      if (size(myself%niters).ne.myself%nloop) then
         delete /var myself%niters
         define double myself%niters[myself%nloop] /global
      endif
   else
      define double myself%niters[myself%nloop] /global
   endif
   define integer nloop
   if (pro%narg.eq.0) then
      let nloop size(self%niters)
      if (nloop.gt.myself%nloop) then
         let myself%niters self%niters[1:myself%nloop]
	 message w selfcal-set-niters "Number of clean iterations for loops "'myself%nloop+1'"-"'nloop'" ignored"
      else if (nloop.eq.myself%nloop) then
	 let myself%niters self%niters
      else	
         let myself%niters[1:nloop] self%niters
	 if (myself%nloop.gt.1) then
	    let myself%niters['nloop+1':'myself%nloop'] self%niters[nloop]
	 endif
      endif
   else
      let nloop pro%narg
      if (nloop.ge.myself%nloop) then
         for iloop 1 to myself%nloop
            let myself%niters[iloop] 'pro%arg[iloop]'
         next iloop
	 if (nloop.gt.myself%nloop) then
	    message w selfcal-set-niters "Number of clean iterations for loops "'myself%nloop+1'"-"'nloop'" ignored"
         endif
      else
         for iloop 1 to nloop
            let myself%niters[iloop] 'pro%arg[iloop]'
         next iloop
         let myself%niters['nloop+1':myself%nloop] 'pro%arg[pro%narg]'
      endif
   endif
   message r selfcal-set-times "Number of clean iterations set to"
   for iloop 1 to myself%nloop
      if (iloop.le.nloop) then
	 message r selfcal-set-niters "  Loop #"'iloop'": "'myself%niters[iloop]'
      else
	 message r selfcal-set-niters "  Loop #"'iloop'": "'myself%niters[iloop]'" (extrapolated from loop "'nloop'")"
      endif
   next iloop
   message r selfcal-set-niters ""
end procedure selfcal-set-niters
!
begin procedure selfcal-set-loop-parameters
  !---------------------------------------------------------------------------
  ! This procedure sets the number of self-calibration loops and the associated
  ! integration times and number of clean iterations.
  !---------------------------------------------------------------------------
  @ selfcal-set-flag
  @ selfcal-set-nloop
  @ selfcal-set-times
  @ selfcal-set-niters
end procedure selfcal-set-loop-parameters
!
begin procedure selfcal-image-current
  !---------------------------------------------------------------------------
  ! logical,   intent(in)  :: self%display
  ! character, intent(in)  :: myself%current
  ! character, intent(out) :: name
  ! integer,   intent(in)  :: myself%niter
  ! integer,   intent(out) :: niter
  ! real,      intent(out) :: fres
  ! real,      intent(out) :: ares
  !
  ! This procedure images and deconvolves the current version of the uv
  ! table that is being selcalibrated (myself%current). The deconvolution
  ! stopping criterion is only the number of clean components. As a
  ! consequence, on output, fres and ares are set to zero, niter is set to
  ! myself%niter and name is set to myself%current.
  !
  ! The imaging and deconvolution results are exposed to the user only when
  ! self%display is set to .true.
  !---------------------------------------------------------------------------
  let name 'myself%current'
  let niter 'myself%niter'
  let fres 0
  let ares 0
  clean\read uv 'name'
  clean\uv_map
  clean\clean
  clean\write * 'name'
  if (self%display) then
     @ deconv-plot 'self%scale[1]' 'self%scale[2]'
  endif
end procedure selfcal-image-current
!
begin procedure selfcal-compute-gain
  !---------------------------------------------------------------------------
  ! integer,   intent(in)  :: &1 ! loop iteration number
  ! double,    intent(in)  :: myself%times[&1]
  ! double,    intent(out) :: myself%time
  ! integer,   intent(in)  :: myself%niters[&1]
  ! integer,   intent(out) :: myself%niter
  ! integer,   intent(in)  :: self%refant
  ! integer,   intent(out) :: myself%refant
  ! character, intent(in)  :: myself%average
  ! character, intent(in)  :: myself%current
  ! character, intent(out) :: myself%model
  ! character, intent(out) :: myself%gain
  ! character, intent(out) :: myself%output
  ! character, intent(out) :: myself%phasol
  !
  ! This procedure writes the current clean component table in the file
  ! myself%model, converts this table into a model uv table, and then
  ! computes the new gain table based on this model.
  !
  ! We have to restart from the initial uv table (myself%average) to be
  ! able to compute the gain from the initial uv table to the current model
  ! that is set to a number of clean components computed at the previous
  ! step.
  !---------------------------------------------------------------------------
  let myself%time    'myself%times[&1]'
  let myself%niter   'myself%niters[&1]'
  if (self%snr.gt.0) let myself%snr 'self%snr'
  let myself%refant  'self%refant'
  let myself%input   'myself%average'
  let myself%current 'myself%average'"-&1"
  let myself%model   'myself%current'"-model"
  let myself%gain    'myself%current'"-gain"
  let myself%output  'myself%current'
  let myself%phasol  'myself%current'"-phasol"
  ! Ensure that the current model comes from the CCT computed at the
  ! previous step.
  clean\write cct 'myself%model'
  vector\run uv_fcct gag_scratch:uv-fcct.init /NOWINDOW
  vector\run uv_gain gag_scratch:uv-gain.init /NOWINDOW
  say ""
  message r selfcal-compute-gain "Selfcal Loop #&1:"
  message r selfcal-compute-gain "  Input:   "'myself%input'
  message r selfcal-compute-gain "  Output:  "'myself%output'
  message r selfcal-compute-gain "  Current: "'myself%current'
end procedure selfcal-compute-gain
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! We finally define the iteration process
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin procedure selfcal-start
  !---------------------------------------------------------------------------
  ! integer, intent(in)  :: &1 or self%niter%init
  ! integer, intent(out) :: myself%niter
  ! integer, intent(out) :: myself%iloop
  !
  ! This procedure starts the selfcalibration process by imaging and
  ! deconvolving the input uv table up to myself%niter iterations. On
  ! output, the myself%iloop counter is initialized to zero.
  !---------------------------------------------------------------------------
  if ((pro%narg.eq.0).and.(self%niter%init.le.0)) then
     message e selfcal-start "Missing number of clean iterations"
     message e selfcal-start "Widget usage: Set the self%niter%init variable"
     message e selfcal-start "Command line usage: SELFCAL START niter"
     return base
  else if (pro%narg.ge.1) then
     let myself%niter &1
  else
     let myself%niter self%niter%init
  endif
  let myself%current 'myself%average'
  @ selfcal-image-current
  let myself%iloop 0
  say ""
  message r selfcal-compute-gain "Before self-calibration:"
  message r selfcal-compute-gain "  Current: "'myself%current'
end procedure selfcal-start
!
begin procedure selfcal-iterate
  !---------------------------------------------------------------------------
  ! intenger, intent(in)    :: myself%nloop
  ! intenger, intent(inout) :: myself%iloop
  !
  ! This procedure iterates the selfcalibration process by 1) finding a new
  ! gain solution using the model derived from the current clean component
  ! table, and 2) imaging and deconvolving the resulted selfcalibrated uv
  ! table. On output, the myself%iloop counter is incremented.
  !---------------------------------------------------------------------------
  if (myself%iloop.lt.0) then
     message e selfcal-iterate "Start the self-calibration process with SELFCAL START niter"
     return base
  else if (myself%iloop.ge.myself%nloop) then
     message e selfcal-iterate "Can't iterate anymore"
     message e selfcal-iterate "Either use SELFCAL STOP niter or increase the number of loops with SELFCAL SET-NLOOP nloop"
     return base
  endif
  let myself%iloop myself%iloop+1
  @ selfcal-compute-gain 'myself%iloop'
  @ selfcal-image-current
  say ""
  message r selfcal-compute-gain "Completed Selfcal Loop #"'myself%iloop'":"
  message r selfcal-compute-gain "  Input:   "'myself%input'
  message r selfcal-compute-gain "  Output:  "'myself%output'
  message r selfcal-compute-gain "  Current: "'myself%current'
end procedure selfcal-iterate
!
begin procedure selfcal-stop
  !---------------------------------------------------------------------------
  ! integer, intent(in)  :: &1 or self%niter%init
  ! integer, intent(out) :: myself%niter
  ! integer, intent(out) :: myself%iloop
  !
  ! This procedure stops the selfcalibration process by imaging and
  ! deconvolving the input uv table up to myself%niter iterations. On
  ! output, the myself%iloop counter is set to -1.
  !---------------------------------------------------------------------------
  define character*256 averagesc
  if (myself%iloop.lt.0) then
     message e selfcal-iterate "Start the self-calibration process with SELFCAL START niter"
     return base
  end if
  if ((pro%narg.eq.0).and.(self%niter%init.le.0)) then
     message e selfcal-stop "Missing number of clean iterations"
     message e selfcal-stop "Widget usage: Set the self%niter%init variable"
     message e selfcal-stop "Command line usage: SELFCAL STOP niter"
     return base
  else if (pro%narg.ge.1) then
     let myself%niter &1
  else
     let myself%niter self%niter%init
  endif
  let averagesc 'myself%average'"-selfcal"
  if (myself%current.ne.averagesc) then
     sic copy 'myself%current'".uvt" 'myself%average'"-selfcal.uvt"
     let myself%current 'myself%average'"-selfcal"
  endif
  @ selfcal-image-current
  say ""
  message r selfcal-compute-gain "After self-calibration:"
  message r selfcal-compute-gain "  Current: "'myself%current'
  let myself%iloop -1
end procedure selfcal-stop
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Transfer gain and compare results
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin procedure selfcal-transfer-gain
  !---------------------------------------------------------------------------
  ! character, intent(out) :: myself%input
  ! character, intent(out) :: myself%gain
  ! character, intent(out) :: myself%output
  ! character, intent(out) :: myself%current
  !
  ! This procedure applies the calibration gain table to a given uv table.
  !---------------------------------------------------------------------------
  if (self%other.eq."*") then
     let myself%input 'self%input'
  else
     let myself%input 'self%other'
  endif
  ! *** JP => Here we should check that the myself%input and myself%input-selfcal tables exist
  let myself%gain    'myself%gain'
  let myself%output  'myself%input'"-selfcal"
  vector\run uv_cal gag_scratch:uv-cal.init /nowind
  let myself%current 'myself%output'
  say ""
  message r selfcal-compute-gain "Gain transfered:"
  message r selfcal-compute-gain "  Gain:    "'myself%gain'
  message r selfcal-compute-gain "  Input:   "'myself%input'
  message r selfcal-compute-gain "  Output:  "'myself%output'
  message r selfcal-compute-gain "  Current: "'myself%current'
end procedure selfcal-transfer-gain
!
begin procedure selfcal-image-raw
  !---------------------------------------------------------------------------
  !
  ! This procedure image the input uv table
  !---------------------------------------------------------------------------
  if ((pro%narg.eq.0).and.(self%niter%exit.le.0)) then
     message e selfcal-start "Missing number of clean iterations"
     message e selfcal-start "Widget usage: Set the self%niter%exit variable"
     message e selfcal-start "Command line usage: SELFCAL IMAGE-RAW niter"
     return base
  else if (pro%narg.ge.1) then
     let niter &1
  else
     let niter self%niter%exit
  endif
  if (self%other.eq."*") then
     let name 'self%input'
  else
     let name 'self%other'
  endif
  let fres 0
  let ares 0
  clean\read uv 'name'
  clean\uv_map
  clean\clean
  clean\write * 'name'
  let myself%current 'name'
  say ""
  message r selfcal-compute-gain "Imaged raw:"
  message r selfcal-compute-gain "  Input:   "'name'
  message r selfcal-compute-gain "  Current: "'myself%current'
end procedure selfcal-image-raw
!
begin procedure selfcal-image-selfcal
  !---------------------------------------------------------------------------
  ! This procedure image the self-calibrated uv table
  !---------------------------------------------------------------------------
  if ((pro%narg.eq.0).and.(self%niter%exit.le.0)) then
     message e selfcal-start "Missing number of clean iterations"
     message e selfcal-start "Widget usage: Set the self%niter%exit variable"
     message e selfcal-start "Command line usage: SELFCAL IMAGE-SELFCAL niter"
     return base
  else if (pro%narg.ge.1) then
     let niter &1
  else
     let niter self%niter%exit
  endif
  if (self%other.eq."*") then
     let name 'self%input'"-selfcal"
  else
     let name 'self%other'"-selfcal"
  endif
  let fres 0
  let ares 0
  clean\read uv 'name'
  clean\uv_map
  clean\clean
  clean\write * 'name'
  let myself%current 'name'
  say ""
  message r selfcal-compute-gain "Imaged selfcal:"
  message r selfcal-compute-gain "  Input:   "'name'
  message r selfcal-compute-gain "  Current: "'myself%current'
end procedure selfcal-image-selfcal
!
begin procedure selfcal-compare-snr
  !---------------------------------------------------------------------------
  ! This procedure compares the statistics of the signal, noise, and
  ! signal-to-noise ratio of the imaged cubes before and after
  ! self-calibration.
  !---------------------------------------------------------------------------
  define integer mynchan
  if (self%other.eq."*") then
     define head uvhead 'self%input'"-selfcal.uvt" read
  else
     define head uvhead 'self%other'"-selfcal.uvt" read
  endif
  let mynchan uvhead%nchan
  delete /var uvhead
  if (mynchan.gt.1) then
     if (self%other.eq."*") then
        let name 'self%input'"-selfcal"
     else
        let name 'self%other'"-selfcal"
     endif
     @ snr-compute
     if (self%other.eq."*") then
        let name 'self%input'
     else
        let name 'self%other'
     endif
     @ snr-compute
     @ snr-plot
  else ! mynchan.eq.1
     define character*256 before after
     if (self%other.eq."*") then
        let after 'self%input'"-selfcal"
        let before 'self%input'
     else
        let after 'self%other'"-selfcal"
        let before 'self%other'
     endif
     @ deconv-compare-plot 'before' 'after'
  endif
end procedure selfcal-compare-snr
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Pipeline doing all the self-calibration actions, invoked by go button.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin procedure selfcal-pipe
   if (pro%narg.ge.1) then
      if (pro%arg[1].eq."widget") @ selfcal-set-loop-parameters
   endif
   @ selfcal-pseudo-cont
   @ selfcal-start
   pause "Please type c to continue"
   for iter 1 to myself%nloop
      @ selfcal-iterate
      pause "Please type c to continue"
   next iter
   @ selfcal-stop
   pause "Please type c to continue"
   @ selfcal-transfer-gain
   @ selfcal-image-raw
   @ selfcal-image-selfcal
   @ selfcal-compare-snr
end procedure selfcal-pipe
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Plot current deconvolution products
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin procedure selfcal-plot
  let name 'myself%current'
  user\go plot &1
end procedure selfcal-plot
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Parsing routine
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin procedure selfcal-main
  if (pro%narg.lt.1) then
     message e selfcal-main "At least one argument required"
     message e selfcal-main 'myself%usage'
     return base
  endif
  define character filename*256
  let filename "gag_proc:selfcal-"'pro%arg[1]'".map" /lower
  if file(filename) then
     let filename "gag_proc:selfcal-"'pro%arg[1]'".map" /lower
     @ 'filename' &2 &3 &4 &5
  else
     message e selfcal-main "Unknown option: "'pro%arg[1]'
     message e selfcal-main 'myself%usage'
     return base
  endif
end procedure selfcal-main
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Widget
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
begin procedure selfcal-widget
  gui\panel "Phase self-calibration (Pety, de Souza, Bardeau)" gag_scratch:selfcal.hlp
     gui\menu "PSEUDO-CONTINUUM" /choices
        gui\button "@ selfcal-pseudo-cont" "Pseudo-continuum"
     gui\menu /close
     gui\menu "SELFCAL" /choices
        gui\button "@ selfcal-set-loop-parameters" "Set loop parameters"
        gui\button "@ selfcal-start" "Start"
        gui\button "@ selfcal-iterate" "Next iteration"
        gui\button "@ selfcal-stop" "Stop"
     gui\menu /close
     gui\menu "TRANSFER" /choices
        gui\button "@ selfcal-transfer-gain" "Transfer gain solution"
        gui\button "@ selfcal-image-raw" "Image the raw uv table"
        gui\button "@ selfcal-image-selfcal" "Image the self-calibrated uv table"
        gui\button "@ selfcal-compare-snr" "Compare signal-to-noise statistics"
     gui\menu /close
     gui\menu "CLEAN" /choices
        gui\button "@ selfcal-plot res"   "Plot RESIDUALS"
        gui\button "@ selfcal-plot clean" "Plot CLEAN"
        gui\button "@ selfcal-plot cct"   "Plot CCT"
        gui\button "@ selfcal-plot dirty" "Plot DIRTY"
        gui\button "@ selfcal-plot beam"  "Plot BEAM"
     gui\menu /close
     say "Bookkeeping parameters"
     let self%dir 'self%dir'  /prompt "Directory for intermediate products (default = ./selfcal)"
     let self%input 'self%input' /prompt "Name of the input uv table (without extension, no default)"
     say ""
     say "Imaging and deconvolution parameters"
     let map_cell 'map_cell[1]' 'map_cell[2]' /prompt "Map cell (default: 0 0) [arcsec]"
     let map_size 'map_size[1]' 'map_size[2]' /prompt "Map size (default: 0 0) [pixel ]"
     let weight_mode 'weight_mode' /prompt "Weight mode (default: NATURAL)" /choice natural robust
     let uv_cell[2]  'uv_cell[2]' /prompt "Robust weighting parameter (uv_cell[2])"
     let self%method 'self%method' /prompt "Deconvolution method (default: HOGBOM)" /choice hogbom clark sdi
     let self%niter%init 'self%niter%init' /prompt "Number of clean components used before self-calibration (no default)"
     say ""
     say "Production of the pseudo-continuum uv table"
     let self%channel 'self%channel[1]' 'self%channel[2]' /prompt "Channel ranges used (default: "'self%channel[1]'" "'self%channel[2]'")"
     say ""
     say "Self-calibration of the pseudo-continuum"
     let self%nloop 'self%nloop' /prompt "Number of self-calibration loop (default: "'self%nloop'")"
     let self%times 'self%times[1]' /prompt "List of integration times (default: "'self%times[1]'" s)" /resize
     let self%niters 'self%niters[1]' /prompt "List of number of iterations (default: "'self%niters[1]'")" /resize
     let self%snr 'self%snr' /prompt "Minimum signal-to-noise ratio to self-calibrate (default: "'self%snr'")"
     let self%refant 'self%refant' /prompt "Reference antenna number (default: "'self%refant'")"
     let self%flag 'self%flag' /prompt "Flag visibilities that can not be self-calibrated? (yes|no|*, default: "'self%flag'")"
     say ""
     say "Transfer gain solution to another uv table (default: input uv table)"
     let self%other 'self%other' /prompt "Name of the other uv table (without extension, default: *)"
     let self%niter%exit 'self%niter%exit' /prompt "Number of clean components used after gain transfer (no default)"
     say ""
     say "Check deconvolution"
     let myself%current 'myself%current' /prompt "Name of the last imaged uv table (without extension, this is updated automatically)"
     say ""
     say "Visualization"
     let self%scale 'self%scale[1]' 'self%scale[2]' /prompt "Minimum and maximum intensities for the residuals, clean components, and final result"
  gui\go "@ selfcal-pipe widget"
end procedure selfcal-widget
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Load dependencies and initialize
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
@ deconv-tools.map
@ snr-tools.map
@ selfcal-init
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
