C+ C NAME: C smei_cal_build C PURPOSE: C Calculates engineering mode pattern from selection of 'closed shutter' data. C CATEGORY: C ucsd/camera/for/lib C CALLING SEQUENCE: subroutine smei_cal_build(bMask,rmask,nfrm,cfrm,cdest,pattern_cut, & pattern,pattern_dark,dark_pixs,ncr_count,ped_aux) C INPUTS: C bMask logical .FALSE.: do not try to apply a "bad pixel" mask C .TRUE. : try to apply a "bad pixel" mask C rmask(*) real onboard mask (used only if bMask=.TRUE.) C cdest(*) character destination for rebinned frames C (see PROCEDURE) C nfrm integer # frames C cfrm(nfrm) character*(*) fully-qualified file names of SMEI data frame C pattern_cut real C ped_aux(*) real C OUTPUTS: C pattern_dark(2) real pattern dark current C mean of all nfrm dark currents C pattern(*) real eng mode frame pattern C dark_pixs(SMEI__DRK_NPIX,nfrm) C real all the individual dark current pixels C CALLS: C smei_frm_read, Say, smei_frm_clean, smei_frm_ped, smei_frm_dark C smei_cal_add, ArrR4PlusArrR4, ArrR4AddConstant, smei_frm_mode C BadR4, ArrR4Zero, ArrR4DivideByArrR4, iArrR4ValuePresent C Str2Str, Int2Str, Flt2Str, ArrR4TimesArrR4 C INCLUDE: include 'openfile.h' include 'filparts.h' include 'smei_frm_layout.h' include 'smei_frm_basepar.h' include 'smei_frm_hdr.h' C PROCEDURE: C The pattern is calculated in pedestal, dark current and covered pixels. C Only pixels that are consistently flagged as bad (probably by smei_frm_clean) C will not receive a pattern value. C Currently (Jun-2004) these are the four leading columns in the eng mode frames C and 8 pixels at the top right of the CCD, for a total of 4*256+8=1032 pixels C with no pattern. C C A check is made to ensure that all dark current and uncovered pixels are C actually filled with something (i.e. are not returned as zero). Excluded from C this check are four dark current pixels in the top row at the right of the CCD C which are flagged as bad in smei_frm_clean, and will be zero in the pattern C calculated here. C C In all dark current output the pedestals have been subtracted already. C C If bMask is .TRUE. on input then the "bad pixel" mask (rmask) is applied C to each of the frames in cfrm. The "bad pixel" mask is only active during C certain time periods (see href=smei_frm_mask=) for camera 3 only. C C If cDest is not a blank string, it should contain an existing directory C (usually the same directory the calibration patterns are written to). C cDest should contain subdirectories 'mask_out' and 'mask_in'. C If bMask=.FALSE. and 'mask_out' exists the mode 0 frames are rebinned C for all three modes (mode 0: 1x1, mode 1: 2x2 and mode 2: 4x4), and C these 'pseudo frames' are written to subdirectories 'c1','c2','c3' C in 'mask_out', depending on camera). If bMask=.TRUE. and 'mask_in' the frames C go to 'mask_in' instead. The 'mask_out' directory contains frames 'as is' C 'mask_in' contains frames with the appropriate "bad-pixel" mask C folded in (i.e. with "bad pixels" that are removed from the real science C mode data blanked out prior to binning). Note that only camera 3 has a C "bad-pixel" mask. C C So the directory structure is: C |- c1 (cam 1, mode 0,1,2 pseudo frames C |-- mask_out -|- c2 (cam 2, mode 0,1,2 pseudo frames C | |- c3 (cam 3, mode 0,1,2 pseudo frames C --| C |-- mask_in ---- c3 (cam 3, mode 0,1,2 pseudo frames C C In these frames header entries related to pedestal and dark current C are set to 0, and can be filled in by running href=smei_base=. C MODIFICATION HISTORY: C JUN-2004, Paul Hick (UCSD/CASS) C FEB-2007, Paul Hick (UCSD/CASS) C Added bMask argument to allow creation of patterns with C the "bad pixel" mask for camera 3 applied. C JUN-2008, Paul Hick (UCSD/CASS) C Added code to write out rebinned "science mode" frames for each C of the frames used to create the calibration pattern. C JUL-2008, Paul Hick (UCSD/CASS) C Changed from function to subroutine. Extra keyword pattern_dark C returns median and mean pattern dark current. C NOV-2008, Paul Hick (UCSD/CASS; pphick@ucsd.edu) C Modified to accomodate new arg to smei_frm_ped C- logical bMask real rmask (*) integer nfrm character cfrm (*)*(*) character cdest*(*) real pattern_cut real pattern_dark(2) real pattern (*) real dark_pixs(*) real ped_aux (*) character cSay*14 /'smei_cal_build'/ logical smei_frm_read integer Flt2Str integer Str2Str integer smei_frm_clean integer smei_frm_ped integer smei_frm_dark integer smei_frm_mode real dark_aux (SMEI__DRK_NUM) real frame (SMEI__FRM_NPIX) real frame_(SMEI__FRM_NPIX) real count (SMEI__FRM_NPIX) double precision hdr (SMEI__HDR_N) double precision hdr_ (SMEI__HDR_N) character cDir *(FIL__LENGTH) character cFile*(FIL__LENGTH) character cStr *(FIL__LENGTH) parameter (iAct = OPN__REOPEN+OPN__STOP) if (itrim(cDest) .ne. 0) then if (bMask) then j = iFilePath(cDest,0,' ','mask_in' ,cDir) else j = iFilePath(cDest,0,' ','mask_out',cDir) end if if (iCheckDirectory(cDir) .eq. 0) cDir = '' else cDir = '' end if bad = BadR4() ! Initialize output variables ! ncr_count = -1 is used to initialize smei_cal_add. Then it is set to zero. pattern_dark(1) = 0.0 pattern_dark(2) = 0.0 call ArrR4Zero(SMEI__FRM_NPIX, pattern) call ArrR4Zero(SMEI__FRM_NPIX, count ) ncr_count = -1 ! Set to zero in first call to smei_cal_add nbad = SMEI__FRM_NPIX+1 do ifrm=1,nfrm ! Process all pattern frames ! Read data into frame. Quit on error. if (.not. smei_frm_read(iAct,cfrm(ifrm),SMEI__FRM_NPIX,nx,ny,nb,frame,hdr,headroom)) stop if (smei_frm_mode(nx,nbin) .ne. 0) call Say(cSay,'E','#'//cfrm(ifrm),'not in engineering mode') if (nint(hdr(SMEI__HDR_FLAT_ENABLED)) .eq. 1) call Say(cSay,'E','#'//cfrm(ifrm),'SSFF enabled') if (bMask) call ArrR4TimesArrR4(-SMEI__FRM_NPIX,frame,rmask,frame) i = smei_frm_clean(nx,ny,frame,frame) ! Massage data (mostly set zero to bad) nbad = min(i,nbad) ! Write out pseudo-"science mode" data ! These frames are written to subdirectories ! mask_in or mask_out depending on whether ! bMask is true or false. if (itrim(cDir) .ne. 0) then i = iSetFileSpec(cfrm(ifrm)) i = iGetFileSpec(FIL__NAME,FIL__NAME,cFile) cFile(i+1:) = '.fts.gz' ! gzip output do imode=0,2 call smei_cal_bin(imode,hdr,frame,hdr_,frame_) nx_ = nint(hdr_(SMEI__HDR_NAXES )) ny_ = nint(hdr_(SMEI__HDR_NAXES+1)) do i=1,nx_*ny_ if (frame_(i) .eq. bad) frame_(i) = 0.0 end do write (cFile(4:4),'(I1)') imode ! Update mode char i = iFilePath(cDir,1,cFile(:2),cFile,cStr) ! Into subdir c# call smei_frm_fts(cStr,nx_,ny_,2,frame_,hdr_) end do end if i = smei_frm_ped(cfrm(ifrm),nx,ny,frame,0.0,ped_val,ped_aux) if (ped_val .eq. bad) then i = 0 i = i+Str2Str('bad pedestal=',cStr(i+1:)) i = i+Flt2Str(ped_aux(SMEI__PED_NAIVE_MEAN),3,cStr(i+1:)) call Say(cSay,'E','#'//cfrm(ifrm),cStr) end if ! Calculate dark current. The pattern array is not accessed or modified here. ! A bad dark current happens only if all dark current pixels are bad, ! so probably never. npos = (ifrm-1)*SMEI__DRK_NPIX+1 dark_aux(SMEI__DRK_HEADROOM) = 1.0 dark_aux(SMEI__DRK_PEDESTAL) = ped_val dark_aux(SMEI__DRK_RATIO ) = bad ! Don't access pattern n = smei_frm_dark(.TRUE.,nx,ny,frame,0.0,dark_val,dark_pixs(npos),dark_aux) ! Quit on bad dark current (all pixs bad; never happens?) if (dark_val .eq. bad) & call Say(cSay,'E','#'//cfrm(ifrm),'bad dark current') ! Subtract pedestal from frame data call ArrR4AddConstant(-SMEI__FRM_NPIX, frame, -ped_val, frame) ! Accumulate dark currents for pattern ! (ped_val was substracted in smei_frm_drk). pattern_dark(1) = pattern_dark(1)+dark_aux(SMEI__DRK_MEDIAN) ! = dark_val pattern_dark(2) = pattern_dark(2)+dark_aux(SMEI__DRK_MEAN ) ! Accumulate pattern information in pattern and count. ! Also return a count on rejected pixels (presumably cosmic rays). call smei_cal_add(pattern_cut, nx, ny, frame, pattern, count, ncr_count) end do i = 0 i = i+Int2Str(ncr_count , cStr(i+1:)) i = i+Str2Str(' (' , cStr(i+1:)) i = i+Flt2Str( 100.0*ncr_count/(nx*ny), 2, cStr(i+1:)) i = i+Str2Str(' %)' , cStr(i+1:))+1 i = i+Str2Str('outlier pixels ignored',cStr(i+1:)) call Say(cSay,'I','pattern',cStr) ! Make sure the pattern is completely filled. ! nbad is the minimum return value from smei_frm_clean for the nfrm processed frames. ! A warning is displayed if empty pixels are found. n = iArrR4ValuePresent(nx*ny, count, 0.0)-nbad if (n .ne. 0) then i = 0 i = i+Int2Str(n, cStr(i+1:))+1 i = i+Str2Str('unexpected pixels with no pattern',cStr(i+1:)) call Say(cSay, 'W', 'pattern', cStr) end if ! Calculate averages for accumulated pattern data pattern_dark(1) = pattern_dark(1)/float(nfrm) ! Median-based pattern_dark(2) = pattern_dark(2)/float(nfrm) ! Mean-based call ArrR4DivideByArrR4(-nx*ny, pattern, count, pattern) return end