! SHOW SELFCAL    or  SELFCAL SHOW
!
! Show the phase or amplitude correction evolution between 2 iterations
! of the problem
!
define logical my_error my_help
define character chain*64
let my_error no
let my_help no
define character arg2*4
let arg2 &2+++
if (arg2.eq."?+++") then
  my_help = yes
else if .not.exist(self_sname) then
  Message E "SHOW SELF" "Solution name SELF_SNAME is not defined"
  SAY       "            Use ""SELFCAL ?""   before"
  return error
else if (len_trim(self_sname).eq.0) then
  chain = "Solution name SELF_SNAME is not defined"
  my_error = yes
else if .not.file('self_sname'".gdf") then
  if .not.file(self_sname) then
    chain = "No such solution "'self_sname'".gdf"
    my_error = yes
  else
    SAY "Using "'self_sname'" as input file"
  endif
endif
!
if (my_error.or.my_help) then
  !
  SAY " "
  SAY "   SELFCAL SHOW [LastLoop [PreviousLoop]]"
  SAY " "
  SAY " Display phase corrections from Self calibration loops"
  SAY " With no argument, display correction between last and previous loops"
  SAY " With two arguments, display correction between specified loops"
  SAY " With one argument, display total correction at that loop"
  SAY " "
  SAY "SELFCAL SHOW Parameters: "
  SAY "  Mode                              "'ansi%blue'"SELF_MODE"'ansi%none'"     ["'ansi%red''self_mode''ansi%none'"]"
  if (exist(self_sname)) then
    SAY "  Solution table                    "'ansi%blue'"SELF_SNAME"'ansi%none'"     ["'ansi%red''self_sname''ansi%none'"]  (no solution yet)   "
  else
    SAY "  Solution table                    "'ansi%blue'"SELF_SNAME"'ansi%none'"     ["'ansi%red'" (undefined) "'ansi%none'"] "
  endif
  SAY "  Amplitude gain Time range         "'ansi%blue'"SELF_ARANGE"'ansi%none'"    ["'bold''self_arange[1]'" "'self_arange[2]''norm'"]"
  SAY "  Phase correction range (°)        "'ansi%blue'"SELF_PRANGE"'ansi%none'"    ["'bold''self_prange[1]'" "'self_prange[2]''norm'"] "
  SAY "  Time range (s)                    "'ansi%blue'"SELF_TRANGE"'ansi%none'"    ["'bold''self_trange[1]'" "'self_trange[2]''norm'"]"
  SAY " "
  if my_error MESSAGE E SHOW 'CHAIN'
  return
endif
!
!
begin procedure set_view_selfcal
  !
  ! @ sub_view Variable  Antenna  CODE
  !
  def integer pself%nt pself%na pself%nd pself%void /global
  def integer dims[8]
  let pself%nt size(&1,1)
  let pself%na (size(&1,2)-4)/3
  def real bx /like &1[1]
  def real count cmax
  def real pself%rms[pself%na] /global
  !
  compute dates gather &1[2]
  compute dims dimof dates
  let pself%nd dims[1]
  define integer pself%iref pself%dates pself%idate /like dates /global
  let pself%dates dates
  del /var dates
  !
  ! Locate best reference antenna
  ! Below, pself%iref is the maximum number of antennas for each date.
  ! This makes no real sense, as it could change from time to time
  for j 1 to pself%nd
    let cmax 0
    for i 1 to pself%na
      let bx &1[4]
      let bx 0 /where bx.ne.i.or.&1[2].ne.pself%dates[j]
      compute count sum bx
      if (count.gt.cmax) then
        let pself%iref[j] i
        let cmax count
      endif
    next
  next
  !
  ! Reset the dates as consecutive numbers
  for i 1 to pself%nd
    let &1[2] i-1 /where &1[2].eq.pself%dates[i]
    let pself%idate[i] i-1
  next
  !
  ! Round to nearest 1000
  defi real toto
  compute toto max &1[1]
  let pself%void 1000*nint((0.25*toto+999)/1000)
  let bx &1[1]+pself%void*&1[2]
  !
  define real my_range[2] dma dmb dm
  dma = 0
  if (&2.eq.1) then
    !
    ! PHASE
    if any(self_prange.ne.0) then
      my_range = self_prange
    else
      comput my_range[1] min dphase /blank 360 0
      comput my_range[2] max dphase /blank 360 0
      dma = 0.1
    endif
  else
    if any(self_arange.ne.0) then
      my_range = self_arange
    else
      comput my_range[1] min dampli /blank 0 0
      comput my_range[2] max dampli /blank 0 0
      dma = 0.05
    endif
    if (dma.ne.0) then
      dma = dma*(my_range[2]-my_range[1])
      comput dmb max dnoise
      dmb = 1.25*dmb
      dm = max(dma,dmb)
      my_range[1] = my_range[1]-dm
      my_range[2] = my_range[2]+dm
    endif
  endif
  !
  if (any(self_trange.ne.0)) then
    greg1\limits self_trange[1] self_trange[2] my_range[1] my_range[2]
  else
    greg1\limits * * my_range[1] my_range[2] /var bx bx
  endif
end procedure set_view_selfcal
!
begin procedure sub_view_selfcal
  !
  !
  define real bx by bz bt /like &1[1]
  define integer iant
  define character*8 stra strb
  define real brms bmean
  !
  let iant &2
  ! Now plot the Phases or Amplitudes
  let bx &1[1]+pself%void*&1[2]  ! This is the time + date offet
  let bz &1['4+3*iant']          ! This is the SNR
  !
  if (&3.eq.1) then
    ! This is the Phase
    for j 1 to pself%nd
      !!
      !! Dates have changed, so can not be tested in this simple minded way
      !!    let by &1['3+2*iant']-&1['3+2*pself%iref[j]']  /where (&1[2].eq.pself%dates[j]).and.(bz.ne.0)
      !
      ! The test must be on the sequential number
      !With Ref Ant!
      let by &1['3+3*iant']-&1['3+3*pself%iref[j]']  /where (&1[2].eq.pself%idate[j]).and.(bz.ne.0)
      !Without Ref Ant!     let by &1['3+2*iant']  /where (&1[2].eq.pself%idate[j]).and.(bz.ne.0)
    next
    !
    let by mod(by+180.,360.)-180.
    let bz sqrt(2)*180/pi/bz /where bz.ne.0      ! This is the phase error
    !
    if (error_bars) then
      greg1\errorbar y bx by bz
      let bt by
      let bt 360 /where bz.eq.0      ! Do not plot no Solution
      greg1\points bx bt
      !
      greg1\pencil /col 1
      let bt by
      let bt 360 /where bz.gt.0
      greg1\errorbar y bx bt bz
      greg1\pencil /col 0
    else
      let by 360 /where bz.eq.0      ! Do not plot no Solution
      greg1\points bx by
    endif
    !
    ! Compute the true standard deviation (from Zero, not from Mean)
    let by by^2
    compute brms mean by /blank 360*360 0
    let brms sqrt(brms)
    let pself%rms[iant] brms
    !
    let stra brms /format F8.1
    greg1\draw text -1 -1 'stra'"^" 1 /char 9
  else
    ! This is the Amplitude
    let by &1['2+3*iant']
    if (error_bars)
      let bz by/bz /where bz.ne.0      ! This is the (uncorrected) amplitude error
      greg1\errorbar y bx by bz
    endif
    greg1\points bx by
    !
    ! Compute the usual standard deviation (from Mean)
    compute bmean mean by /blank 0 0
    compute brms rms by /blank 0 0
    let stra bmean /format F8.3
    let strb brms /forma F8.3
    !
    let pself%rms[iant] brms
    greg1\draw text -1 -1 'stra'" "'strb' 1 /char 9
  endif
  !
end procedure sub_view_selfcal
!
define character cr*5 cn*5
cr = 'ansi%red'
cn = 'ansi%none'
!
! "corrected" will handle the differences
if (exist(corrected)) delete /var corrected
!
! "cycles" handles the different iteration corrections
define image cycles  'self_sname' read /trim 3
define integer iloop jloop nloop
nloop = cycles%dim[3]
message I SELFCAL "Showing "'nloop'" iterations from "'self_sname'
!
! Arguments
defin integ code jfirst jnext
if (pro%narg.eq.0) then
  if self_mode.eq."PHASE" then
    let code = 1
  else
    let code = 2
  endif
  jfirst = 1
else
  jfirst = 2
  if (pro%arg[1].eq."PHASE") then
    let code 1
  else if (pro%arg[1].eq."AMPLI") then
    let code 2
  else if ('pro%arg[1]'.le.nloop) then
    jfirst = 1
    if self_mode.eq."PHASE" then
      let code = 1
    else
      let code = 2
    endif
  else
    message E SELFCAL "Invalid or out of bound argument "'pro%arg[1]'
    return error
  endif
endif
!
! Define the Loop numbers
! - Although the time steps may change between two subsequent
!   cycles, it is sufficient for the display to work that they
!   are identical between the 2 being displayed
! - Also, the absolute correction (difference with the initial
!   values) will always be correctly displayed.
!
if pro%narg.lt.jfirst then
  iloop = nloop
  jloop = iloop-1
else
  let iloop 'pro%arg[jfirst]'      ! First
  let jloop 0
  if (pro%narg.gt.jfirst) then
    jnext = jfirst+1
    let jloop 'pro%arg[jnext]'
  endif
  if (jloop.ge.iloop) then
    message E SELFCAL "Invalid iteration order"
    return error
  endif
endif
if (iloop.gt.nloop) then
  message W SELFCAL 'cr'"Only "'nloop'" iterations available"'cn'
  let iloop nloop
  ! ! return error
else if (iloop.lt.1).or.(jloop.lt.0) then
  message E SELFCAL 'cr'"Invalid iteration numbers"'cn'
  return error
endif
if (jloop.gt.0) then
  message I SELFCAL "Showing difference between "'iloop'" and "'jloop'
else
  message I SELFCAL "Showing correction at loop "'iloop'
endif
!
define real  b /like cycles[iloop]
define integer nb
let nb size(cycles,2)
let b cycles[iloop]
if (jloop.gt.0) then
  define real  a /like cycles[jloop]
  let a cycles[jloop]
else
  define real a /like b
  for i 5 to size(b,2) by 3
    let a[i] 1
  next
endif
!
! Temporary array to handle the Phase and Amplitude differences
define real corrected /like b /global
!
let corrected b
for i 5 to nb by 3
  let corrected[i] b[i]/a[i]
next
for i 6 to nb by 3
  let corrected[i] b[i]-a[i]
next
delete /var a b
!
! Number of antennas
define integer na nn nbxy
let na (size(corrected,2)-4)/3
let nn size(corrected,1)
let nbxy ceiling(sqrt(1.0*na))
! Phases per antenna
if exist(dphase) delete /var dphase dnoise dampli
define real dphase[nn,na] /global
define real dnoise dampli /like dphase /global
for i 1 to na
  let dampli[i] corrected['2+3*i']
  let dphase[i] corrected['3+3*i']
  let dnoise[i] corrected['4+3*i']    ! This is the SNR
next
let dphase mod(dphase+180.,360.)-180.
if (code.eq.1) then
  let dnoise sqrt(2)*180/pi/dnoise /where dnoise.ne.0      ! This is the phase error
else
  let dnoise 2./dnoise /where dnoise.ne.0
endif
!
@ window_tools
gtvl\clear
@ full_position
let my_aspect_ratio aspect_ratio /new log
let aspect_ratio no
!
greg1\set expand 1/sqrt(nbxy)
greg1\set mark 4 0 0.07
!
! Re-define the POPUP command behaviour
let PopupName SELF
!
! Remember the Channel selection
@ d_popup 1 'na' 1
!
if exist(pself) delete /var  pself
defin struc pself /global
@ set_view_selfcal corrected  'CODE'
!
for i 1 to na
  gtvl\create dir 'PopupName''i'
  gtvl\change dir 'PopupName''i'
  @ window_xy 'nbxy' 'nbxy' 'i'
  greg1\set expand 1/sqrt(nbxy)
  @ sub_view_selfcal corrected 'i' 'CODE'
  greg1\box n n
  if (mod(i,nbxy).eq.1) then
    greg1\axis yl /label o
  endif
  if (na-i.lt.nbxy) then
    greg1\axis xl /label p
  endif
  greg1\set expand min(1,1.25/sqrt(nbxy))
  greg1\draw text 1 -0.5 "A #"'i' 3 /char 7
  gtvl\change dir <greg
next
delete /var corrected
greg1\set expand 1.0
!
@ window_xy 1 1 1
greg1\label "Time (secs)" /X
if (code.eq.1) then
  greg1\label "Phase (^)  " /Y
else
  greg1\label "Amplitude  " /Y
endif
@ window_xy 'nbxy' 'nbxy' 1 1
let aspect_ratio my_aspect_ratio
!
@ selfcal_sum
if code.eq.1 then  ! Phase
  defi double phase_rms dyn_range
  defi char*12 cdyn
  compute phase_rms median pself%rms
  let phase_rms 0.1*nint(10*phase_rms)
  if phase_rms.gt.30 then
    message W SELFCAL 'cr'"Median rms ("'phase_rms'"°) is too large."'cn'
    let self_status -1
  else
    message I SELFCAL "Median rms is "'phase_rms'"°"
    let dyn_range 1.0/(1.0-exp(-(phase_rms*pi/180)^2/2))
    let cdyn dyn_range /format f11.1
    message I SELFCAL "Max Expected Dynamic range is "'cdyn'
  endif
else
  defi double ampli_rms
  defi char  cstr*12
  compute ampli_rms median pself%rms /blank 0 0 ! Avoid flagged data
  let cstr ampli_rms /format f10.5
  if ampli_rms.gt.0.2 then
    message W SELFCAL 'cr'"Median Amplitude rms ("'cstr'") is too large."'cn'
    let self_status -2
  else
    message I SELFCAL "Median Amplitude rms is "'cstr'
  endif
  delet /var cstr
endif
say "Use    POPUP #Number   to popup the specified antenna"
!
begin procedure pop_selfcal
  if pro%narg.ne.1 then
    message E POPUP "Missing argument"
    return error
  endif
  on error return
  if exist(last_popup_) then
    gtvl\change dir <greg<self'last_popup_'
    gtvl\destroy window
    delete /var last_popup_
  endif
  on error return base
  gtvl\change dir <greg<'PopupName'&1
  gtvl\create window name "Antenna &1" /POSITION 100% 100%
  gtvl\change dir <greg
  defi integer last_popup_ /global
  let last_popup_ &1
end procedure pop_selfcal
