next up previous contents index
Next: E. Deglitching in OLP Up: cam_hb Previous: C. ISOCAM Data Products


D. AAC FORTRAN Code Showing CAL-G Selection Rules

When an exact match to an observer's data is absent from the set of CAL-G files, AAC choses an alternative based on minimising a penalty function calculated by the fragment of code listed below. The penalty function is made up of distances in selection parameter space weighted by factors which include parameter priority order.


C++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C.IDENTIFIER  CCD_PENALTY
C.PURPOSE     Returns value of best-fit penalty function.
C.VERSION 1  Steve 03-05-1995 Original
C.VERSION 2   Andy 24-07-1996 cam$penalty report
C.VERSION 3   Andy 30-07-1996 cfo_ccd_names & cfo_ccd_values
C.VERSION 4   Andy 02-02-2000 cfo_ccd_values key_id
C.CALLS       CCD_GET_MULTS
C             CCD_DIFF
C             CAM_REPORT
C             CAM_INFO
C------------------------------------------------------------------------
      subroutine ccd_penalty (new_keys, deid, n_key, key_id, val1, val2,
     &                        penalty, status)
* Global constants:
      include 'aac_inc:aac_ccd_constants.inc'
      include 'aac_inc:aac_cam_codes.inc'
* Import:
      logical new_keys           !  in: new set of keys?
      integer deid               !  in: detector id
      integer n_key              !  in: number of keys
      character*(*) key_id(*)    !  in: names of keys
      real val1(*)               !  in: set of values, each key
      real val2(*)               !  in: set of values, each key
      real penalty               ! out: calculated penalty value
* Status:
      integer status
* Locals variables:
      real*4 pen_mult(ccd$maxkeys)
      integer*4 i_key
      real*4 diff
* External references:
      real*4 ccd_diff
      character*(cam$lo) cfo_ccd_names
      character*(cam$lo) cfo_ccd_values
      character*(cam$lc) cam_channel
*-
      if(status.ne.cam$normal)return

* Derive the penalty multipliers.
      if (new_keys) call ccd_get_mults (n_key, key_id, pen_mult, status)

* Initialise.
      penalty = 0.0

* Use these to sum the penalty function.
      do i_key = 1, n_key
          ! find absolute 'distance' between the values
          diff = ccd_diff (deid, key_id(i_key),
     &                     val1(i_key), val2(i_key))

          if (diff.ge.0.0) then
              penalty = penalty + diff*pen_mult(i_key)
          else
              status=cam$penalty
              call cam_report(' ',key_id(i_key),status)
          endif
      end do

* Report more details of any failure
      if(status.ne.cam$normal)then
         call cam_info(cfo_ccd_names(cam_channel(deid),n_key,key_id))
         call cam_info(cfo_ccd_values('Tried: ',n_key,key_id,val1))
         call cam_info(cfo_ccd_values('Failed:',n_key,key_id,val2))
      endif

      return

      end

C++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C.IDENTIFIER  CCD_GET_MULTS
C.PURPOSE     Returns penalty multipliers for each key.
C.VERSION 1  Steve 03-05-1995 Original
C.VERSION 2   Andy 24-07-1996 cam$multiplier report
C.CALLS       CCD_MAXKEY
C             CAM_REPORT
C------------------------------------------------------------------------
      subroutine ccd_get_mults (n_key, key_id, pen_mult, status)
      implicit none

* Arguments:
      integer n_key              !  in: number of keys
      character*(*) key_id(*)    !  in: names of keys
      real pen_mult(*)           ! out: penalty multiplier, each key
      integer status             ! i/o: status value

* Include files.
      include 'aac_inc:aac_cam_codes.inc'

* Locals.
      real maxval                ! returned by ccd_maxkey
      integer i_key              ! key index

* Functions.
      real ccd_maxkey            ! returns maximum value of key

* Inherited status.
      if (status.ne.cam$normal) return

* Muliplier for the last key is one by definition.
      pen_mult(n_key) = 1.0

* Construct the other multipliers as the product of the maximum values of the
* ones that follow it ie pen_mult(i) = product(pen_mult(i+1)...pen_mult(n))
      do i_key = n_key-1, 1, -1
          maxval = ccd_maxkey(key_id(i_key+1))

          if (maxval.ge.0.0) then
              pen_mult(i_key) = pen_mult(i_key+1) * maxval
          else
              status=cam$multiplier
              call cam_report(' ',key_id(i_key+1),status)
          endif
      end do

      return

      end

C++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C.IDENTIFIER  CCD_MAXKEY
C.PURPOSE     Returns maximum value of a key; -1 if none.
C.VERSION 1  Steve 03-05-1995 Original
C.VERSION 2  Steve 09-05-1996 Use pixel fraction in PSF selection
C.VERSION 3   Andy 16-02-2000 ccd$proc & ccd$rev
C------------------------------------------------------------------------
      real function ccd_maxkey (key_id)
      implicit none

* Arguments:
      character*(*) key_id             ! in: name of the key

* Include files:
      include 'aac_inc:aac_ccd_constants.inc'

* Local constants.
      real bad_val
      parameter (bad_val = -1.0)

      if (key_id.eq.ccd$ewhl) then
          ccd_maxkey = 8.0

      else if (key_id.eq.ccd$swhl) then
          ccd_maxkey = 5.0

      else if (key_id.eq.ccd$tint) then
          ccd_maxkey = 431.0

      else if (key_id.eq.ccd$gain) then
          ccd_maxkey = 5.0

      else if (key_id.eq.ccd$pfov) then
          ccd_maxkey = 8.0

      else if (key_id.eq.ccd$proc) then
          ccd_maxkey = 2.0

      else if (key_id.eq.ccd$signal) then
          ccd_maxkey = 5001.0

      ! do nothing for y - treat as null key and wait for z
      else if (key_id.eq.ccd$ys) then
          ccd_maxkey = 1.0

      ! maximum is corner-to-corner distance + an allowance of 3 times
      ! that for the fractional pixel weighting
      else if (key_id.eq.ccd$zs) then
          ccd_maxkey =  4.0 * sqrt(2.0) * cam$ny

      ! maximum is in wavelength
      else if (key_id.eq.ccd$fcvf) then
          ccd_maxkey = 18.0

      else if (key_id.eq.ccd$rev) then
          ccd_maxkey = 907.0

      else
          ccd_maxkey = bad_val
      endif

      return

      end

C++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C.IDENTIFIER  CCD_DIFF
C.PURPOSE     Returns 'difference' between values; -1 if undefined.
C.VERSION 1   Steve 03-05-1995 Original
C.VERSION 2   Steve 08-01-1996 don't allow diff=0 unless val1=val2;
C                              penalise CVF/non-CVF pairs
C------------------------------------------------------------------------
      real*4 function ccd_diff(deid, key_id, val1, val2)
* Global constants:
      include 'aac_inc:aac_ccd_constants.inc'
* Import:
      integer*4 deid
      character*(*) key_id
      real*4 val1
      real*4 val2
* Local constants:
      real bad_val
      parameter (bad_val = -1.0)
      real epsilon
      parameter (epsilon = 1.0e-6)     ! arbitrary small value
* Local variables:
      real*4 trans_val1
      real*4 trans_val2
* External references:
      real    ccd_transval       ! translates raw values to 'difference system'
      real    ccd_maxkey         ! returns maximum value of key
      logical ccd_iscvf          ! check if CVF position
*-

* Translate the values to our 'difference weighting system'.
      trans_val1 = ccd_transval (deid, key_id, val1)
      trans_val2 = ccd_transval (deid, key_id, val2)

* If OK, return the absolute value, -1 otherwise.
      if (trans_val1.ge.0.0 .and. trans_val2.ge.0.0) then
          ccd_diff = abs (trans_val1 - trans_val2)

          ! don't allow diff=0 unless the inputs were the same
          ! instead return difference between inputs multiplied by
          ! some (small) arbitrary value
          if (ccd_diff.le.0.0 .and. val1.ne.val2)
     &        ccd_diff = epsilon * abs(val1 - val2)

          ! for filter wheels, penalise CVF/non-CVF pairs
          if (key_id.eq.ccd$fcvf) then
              if (ccd_iscvf(deid,nint(val1)) .xor.
     &            ccd_iscvf(deid,nint(val2)))
     &            ccd_diff = ccd_diff + ccd_maxkey(key_id)
          endif

      else
          ccd_diff = bad_val
      endif

      return

      end

C++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C.IDENTIFIER  CCD_TRANSVAL
C.PURPOSE     Returns value in 'difference' system; -1 if undefined.
C.VERSION 1  Steve 03-05-1995 Original
C.VERSION 2  Steve 09-05-1996 Use pixel fraction in PSF selection
C.VERSION 3   Andy 10-02-1998 Alpha tidy up
C.CALLS       None.
C------------------------------------------------------------------------
      real*4 function ccd_transval(deid,key_id,val)
* Include files:
      include 'aac_inc:aac_ccd_constants.inc'
      include 'aac_inc:aac_cam_codes.inc'
* Import:
      integer*4 deid
      character*(*) key_id
      real*4 val
* Local constants:
      real*4 bad_val
      parameter (bad_val=-1.0)
      real*4 val_undef
      parameter (val_undef=-1.0)
* Local variables:
      integer*4 ival
      real*4 dist
      real*4 frac
      real*4 yval1
      real*4 yval2
      real*4 zval1
      real*4 bandwidth
      integer*4 status
* Local data:
      data yval1 /val_undef/
      data yval2 /val_undef/
      data zval1 /val_undef/
* Saved variables:
      save yval1, yval2, zval1
* External references:
      real*4 ccd_wavelength
*-

      if (key_id.eq.ccd$ewhl) then
          ival = nint(val)
          if (ival.eq.cam$ewhl_pol1) then
              ccd_transval = 1.0
          else if (ival.eq.cam$ewhl_pol2) then
              ccd_transval = 2.0
          else if (ival.eq.cam$ewhl_pol3) then
              ccd_transval = 3.0
          else if (ival.eq.cam$ewhl_hole) then
              ccd_transval = 6.0
          else if (ival.eq.cam$ewhl_dark) then 
              ccd_transval = 7.0
          else
              ccd_transval = bad_val
          endif

      else if (key_id.eq.ccd$swhl) then
          ival = nint(val)
          if (deid.eq.cam$sw) then
              if (ival.eq.cam$swhl_sw_sm) then        ! SW small mirror
                  ccd_transval = 1.0
              else if (ival.eq.cam$swhl_sw_lm) then   ! SW large mirror
                  ccd_transval = 3.0
              else if (ival.eq.cam$swhl_sw_ics) then  ! SW ics
                  ccd_transval = 4.0
              else
                  ccd_transval = bad_val
              endif

          else if (deid.eq.cam$lw) then
              if (ival.eq.cam$swhl_lw_sm) then        ! LW small mirror
                  ccd_transval = 1.0
              else if (ival.eq.cam$swhl_lw_lm) then   ! LW large mirror
                  ccd_transval = 3.0
              else if (ival.eq.cam$swhl_lw_ics) then  ! LW ics
                  ccd_transval = 4.0
              else
                  ccd_transval = bad_val
              endif

          else
              ccd_transval = bad_val
          endif

      else if (key_id.eq.ccd$pfov) then
          ival = nint(val)
          if (deid.eq.cam$sw) then
              if (ival.eq.cam$sw_pfov1) then
                  ccd_transval = 1.0
              else if (ival.eq.cam$sw_pfov2) then
                  ccd_transval = 2.0
              else if (ival.eq.cam$sw_pfov3) then
                  ccd_transval = 4.0
              else if (ival.eq.cam$sw_pfov4) then
                  ccd_transval = 8.0
              else
                  ccd_transval = bad_val
              endif

          else if (deid.eq.cam$lw) then
              if (ival.eq.cam$lw_pfov1) then
                  ccd_transval = 1.0
              else if (ival.eq.cam$lw_pfov2) then
                  ccd_transval = 2.0
              else if (ival.eq.cam$lw_pfov3) then
                  ccd_transval = 4.0
              else if (ival.eq.cam$lw_pfov4) then
                  ccd_transval = 8.0
              else
                  ccd_transval = bad_val
              endif

          else
              ccd_transval = bad_val
          endif

      else if (key_id.eq.ccd$tint) then
          ccd_transval = val

      else if (key_id.eq.ccd$signal) then
          ccd_transval = val

      else if (key_id.eq.ccd$gain) then
          ival = nint(val)
          if (ival.eq.cam$gain1) then
              ccd_transval = 2.0
          else if (ival.eq.cam$gain2) then
              ccd_transval = 1.0
          else if (ival.eq.cam$gain4) then
              ccd_transval = 3.0
          else
              ccd_transval = bad_val
          endif

      ! do nothing for y - treat as null key and wait for z
      ! we always return the same number, so the difference will be 0
      else if (key_id.eq.ccd$ys) then
          ccd_transval = 1.0
          if (yval1.lt.0.0) then
              yval1 = val
          else if (yval2.lt.0.0) then
              yval2 = val
          else
              ccd_transval = bad_val
          endif

      ! now calculate distance between z & remembered y plus 96*sqrt(2) times
      ! the fractional distance (this assumes the PSFs are sampled at one
      ! third intervals) - the factor is sqrt(2) * 32 * sample rate. The
      ! point is that the fractional distance is always more important than
      ! the real distance.
      ! The first call will correspond to yval1. Return 0 for z1 and the
      ! calculated value for z2 so the difference will be correct.
      else if (key_id.eq.ccd$zs) then
          if (zval1.lt.0.0) then      ! z1
              zval1 = val
              ccd_transval = 0.0

          else if (yval1.ge.0.0 .and. yval2.ge.0) then ! z2
              dist = sqrt ((val   - zval1)**2 + 
     &                     (yval2 - yval1)**2)
              frac = sqrt ((val   - real(nint(val)) - 
     &                      zval1 + real(nint(zval1)))**2 +
     &                     (yval2 - real(nint(yval2)) -
     &                      yval1 + real(nint(yval1)))**2)
              ccd_transval = dist + frac * 96.0 * sqrt(2.0)

              yval1 = val_undef
              yval2 = val_undef
              zval1 = val_undef

          else
              ccd_transval = bad_val
          endif

      else if (key_id.eq.ccd$fcvf) then
          ival = nint(val)
          status=cam$normal
          ccd_transval=ccd_wavelength(deid,ival,bandwidth,status)
          if (ccd_transval.lt.0.0) ccd_transval = bad_val

      else if (key_id.eq.ccd$proc) then
          ccd_transval = val

      else if (key_id.eq.ccd$rev) then
          ccd_transval = val

      else
          ccd_transval = bad_val
      endif

      return

      end



ISO Handbook Volume II (CAM), Version 2.0, SAI/1999-057/Dc