MESSENGER MASCS UVVS CDR TO SURFACE DDR PROCEDURES Version 1, 12/4/2013 Document Review William McClintock, MESSENGER Cognizant Co-Investigator/MASCS, has reviewed and approved this document. Noam Izenberg, MESSENGER MASCS Instrument Scientist, has reviewed and approved this document. Document Change History Version 1, 12/3/2013, C. Mauceri, ACT Version submitted for first Surface DDR delivery (PDS Delivery 11). MASCS UVVS CDR to Surface DDR pseudocode. This document describes high level "pseudocode" and tables which define the procedures used to convert MASCS UVVS Calibrated Data Records (CDRs) to Surface Derived Data Records (DDRs). This pseudocode follows logic and language structures that make it easily adaptable to a number of programming languages, but is not considered to be functional code in and of itself. It will be updated by the MASCS team as the calibrations are refined, but it is not supported, deliverable code. The PROCEDURES that are included; ;----------------------------------------------------------------------------- ; * batch_calibrate_uvvs_surf_ddrs - opens each of the kickoff files passed ; in cdr_files and runs the calibration algorithm on them. For each one ; it writes a CSV file for the Science DDR and a CSV file for the Header ; DDR. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * find_uvvs_surf_ddr_kickoff_files - find UVVS surface reflectance DDR ; kickoff files. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * init_mascs_cdr_templates_5 - initializes data structure definitions ; for MASCS telemetry packets. This is one way to handle the data ; structures for MASCS. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * mascs_normalize_photometry - returns data normalization factor. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * read_mascs_cdr_5 - reads data from a MASCS binary calibrated data ; record, returning an array of data structures that match the table ; structure defined in the CDR SIS documents for UVVS and VIRS. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * uvvs_cdr_2_ddr_surf_batch - searches an incoming directory for files ; that contain paths to UVVS obs cdr files. CDR kickoff files will then ; be processed and data needed for the DDR are then written out to an ; ascii file for further processing into binary DDRs. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * uvvs_derive_muv_reflectance - derives surface reflectance from surface ; observations by the UVVS-MUV channel. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * uvvsddr_surf_hdr_2_ascii - writes the UVVS Surface Reflectance DDR ; header structure into a csv file. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * uvvsddr_surf_sci_2_ascii - writes the UVVS Surface Reflectance DDR ; science structure into a csv file ;----------------------------------------------------------------------------- ;***************************************************************************** ; U V V S P R O C E D U R E S ;***************************************************************************** ;----------------------------------------------------------------------------- ; * batch_calibrate_uvvs_surf_ddrs - opens each of the kickoff files passed ; in cdr_files and runs the calibration algorithm on them. For each one ; it writes a CSV file for the Science DDR and a CSV file for the Header ; DDR. ;----------------------------------------------------------------------------- pro batch_calibrate_uvvs_surf_ddrs,kickoff_files,finalhdr_path,finalsci_path ;this idl program will open each of the kickoff files passed in edr_files ;and run the calibration algorithm on them. For each one it will write a CSV file for the ;Science DDR and a CSV file for the Header DDR ;Science DDR is written to the finalsci_path, Header DDR is written to the finalhdr_path print, 'running batch_calibrate_uvvs_surf_ddrs\n' n_kickoff_files = n_elements(kickoff_files) max_kickoff_files = 5000000 if n_kickoff_files gt max_kickoff_files then begin n_kickoff_files = max_kickoff_files print, 'n_kickoff_files:',n_kickoff_files print,' > max. will only process up to:',max_kickoff_files endif for file_i=0,n_kickoff_files-1 do begin ;the kickoff files contain two lines. First line is the complete path and filename to a given UVVS Header CDR .DAT FILE! ;Second line is the complete path and filename to the given UVVS Science CDR .DAT file! ;The kickoff files should be the complete path to the filename! i_kickoff_file = kickoff_files[file_i] ;open and read the kickoff file. print, 'count:',file_i print, 'opening kickoff file',i_kickoff_file cdr_header_file = '' cdr_science_file = '' openr,runit,i_kickoff_file,/get_lun readf,runit,cdr_header_file readf,runit,cdr_science_file close,runit free_lun,runit ;retrieve the CDR base filename for header and science CDRs. ;NOTE! This assumes that the CDR file naming convention has a fixed length. ;THIS IS HARDCODED! IF THE FILE NAMING CONVENTION CHANGES THEN THIS NEEDS TO BE UPDATED path_len = STRLEN(cdr_header_file) file_start = path_len-31 header_base_name = STRMID(cdr_header_file,file_start,28) science_base_name = STRMID(cdr_science_file,file_start,28) ;run the calibration routines on this edr. print, 'working on header cdr:',cdr_header_file print, 'working on science cdr:',cdr_science_file uvvs_derive_muv_reflectance, cdr_science_file,cdr_header_file, ddr_sci,ddr_hdr ;write to the DDR Header CSV file in the Incoming path designated for the Header DDR header_csv_file = header_base_name + 'csv' ddr_hdr_fname = finalhdr_path+header_csv_file print, 'writing DDR header data to ',ddr_hdr_fname ;copy the method in uvvsddr_surf_sci_2_ascii.pro. Use the uvvs_cdr_ddr_sis_for_review.doc ;to see what columns need to be written to the csv file ;use init_mascs_cdr_temmplates_5.pro to see what the column names are in the ddr_hdr structure. uvvsddr_surf_hdr_2_ascii,ddr_hdr,ddr_sci,ddr_hdr_fname ;write to the DDR Science CSV file in the Incoming path designated for the Science DDR science_csv_file = science_base_name + 'csv' ddr_sci_fname = finalsci_path+science_csv_file print, 'writing DDR science data to ',ddr_sci_fname uvvsddr_surf_sci_2_ascii,ddr_sci,ddr_sci_fname ;delete the kickoff file from the old location ;NOTE: delete file here in order to keep it in case the calibration fails print, ' deleting kickoff file:',i_kickoff_file FILE_DELETE,i_kickoff_file endfor end ;----------------------------------------------------------------------------- ; * find_uvvs_surf_ddr_kickoff_files - find UVVS surface reflectance DDR ; kickoff files. ;----------------------------------------------------------------------------- pro find_uvvs_surf_ddr_kickoff_files,kickoff_path,detector,kickoff_files,num_kickoff_files ;need to find UVVS surface reflectance DDR kickoff files if detector eq 'MUV' then begin print,'Searching for UVVS MUV kickoff files...' kickoff_files=file_search(kickoff_path+'*.kddr',count=num_kickoff_files) if num_kickoff_files gt 0 then begin ;open each kickoff file to see if the CDR is still valid. It may have been deleted because it was replaced by ;a CDR w/ a different filename. ;this can happen if new data arrives which changes the start UTC time of the CDR, because the start UTC time ;is part of the filename. print, 'checking for stale files...' deleted_files = 0 for file_i=0,num_kickoff_files-1 do begin i_kickoff_file = kickoff_files[file_i] ;open and read the kickoff file. should be a pointer to a UVVS HDR and SCI CDR print, 'opening kickoff file',i_kickoff_file sci_cdr_file = '' hdr_cdr_file = '' openr,runit,i_kickoff_file,/get_lun readf,runit,hdr_cdr_file readf,runit,sci_cdr_file close,runit free_lun,runit ;check if header cdr file still exists print, 'checking existence of ',hdr_cdr_file file_exists = file_test(hdr_cdr_file) if (file_exists eq 0) then begin ;delete the file from the old location print, ' deleting kickoff file:',i_kickoff_file FILE_DELETE,i_kickoff_file deleted_files = 1 endif else begin ;now check if science cdr file still exists print, 'checking existence of ',sci_cdr_file file_exists = file_test(sci_cdr_file) if (file_exists eq 0) then begin ;delete the file from the old location print, ' deleting kickoff file:',i_kickoff_file FILE_DELETE,i_kickoff_file deleted_files = 1 endif endelse endfor if deleted_files eq 1 then begin ;redo the search for the kickoff files because we deleted 1 or more stale ones print,'Searching for UVVS MUV kickoff files AGAIN' kickoff_files=file_search(kickoff_path+'*.kddr',count=num_kickoff_files) endif endif endif if (num_kickoff_files eq 0) then begin print, 'Could not find any uvvs surf ddr kickoff files. Done processing.' return endif return end ;----------------------------------------------------------------------------- ; * init_mascs_cdr_templates_5 - initializes data structure definitions ; for MASCS telemetry packets. This is one way to handle the data ; structures for MASCS. ;----------------------------------------------------------------------------- pro init_mascs_cdr_templates_5 ; Run this to set up the data structures for MASCS CDR files. ; ; v1.0 10/10/09 mrl ; v1.1 4/19/10 mrl Updated: changed spare_1 (double) to SC_time (ulong) ; to match revised SOC template for CDRs ; ; V2 8/2011 AWM Renamed to init_mascs_cdr_templates_4 to be consistent with read_mascs_cdr4 ; Updated to replace SPARE_2 (double) with PMT_Temperature (float) ; Moved the location of PMT_Temperature in the Structure allocation. ; Changed name of Radiance Uncertainty to STEP_RADIANCE_SIGNAL_TO_NOISE ; v3.0 5/9/12 mrl Updated to remove 4 fields of pointing information that ; no one is using. (Saves 96 bytes per record.) ; Re-named with a '5' on the end to make it easier to ; identify it as a MASCS CDR Reader v5 file. uvvs_cdr_hdr = { $ cdr_hdr, $ SEQ_COUNTER:UINT(0), $ SC_TIME:ULONG(0), $ PACKET_SUBSECONDS:UINT(0), $ START_POS:UINT(0), $ STEP_COUNT:UINT(0), $ INT_TIME:UINT(0), $ STEP_TIME:UINT(0), $ PHASE_OFFSET:UINT(0), $ SCAN_CYCLES:UINT(0), $ ZIGZAG:UINT(0), $ COMPRESSION:UINT(0), $ SLIT_MASK_POS:UINT(0), $ FUV_ON:UINT(0), $ MUV_ON:UINT(0), $ VIS_ON:UINT(0), $ BUFFER_OVERFLOW:UINT(0), $ SPARE_BITS:UINT(0), $ GD_SETTLE_CTR:UINT(0), $ NUM_SCAN_VALUES:UINT(0), $ STEP_SIZE:UINT(0), $ PAD_BYTE:UINT(0), $ COADD:UINT(0), $ CALIBRATION_SOFTWARE_VERSION:FLOAT(0) $ } uvvs_cdr_sci = { $ cdr_sci, $ STEP_NUMBER:UINT(0), $ ;PLANET_SUN_VECTOR_J2:DBLARR(3), $ ; v3.0 set of J2000 fields deleted ;PLANET_SC_VECTOR_J2:DBLARR(3), $ ;SPACECRAFT_POSITION_VECTOR_J2:DBLARR(3), $ ;SUN_POSITION_VECTOR_J2:DBLARR(3), $ ;TARGET_BODY_VECTOR_J2:DBLARR(3), $ ;BORESIGHT_UNIT_VECTOR_CENTER_J2:DBLARR(3), $ ;BORESIGHT_UNIT_VECTOR_C1_J2:DBLARR(3), $ ;BORESIGHT_UNIT_VECTOR_C2_J2:DBLARR(3), $ ;BORESIGHT_UNIT_VECTOR_C3_J2:DBLARR(3), $ ;BORESIGHT_UNIT_VECTOR_C4_J2:DBLARR(3), $ PLANET_SUN_VECTOR_TG:DBLARR(3), $ PLANET_SC_VECTOR_TG:DBLARR(3), $ BORESIGHT_UNIT_VECTOR_CENTER_TG:DBLARR(3), $ BORESIGHT_UNIT_VECTOR_C1_TG:DBLARR(3), $ BORESIGHT_UNIT_VECTOR_C2_TG:DBLARR(3), $ BORESIGHT_UNIT_VECTOR_C3_TG:DBLARR(3), $ BORESIGHT_UNIT_VECTOR_C4_TG:DBLARR(3), $ SURFACE_TANGENT_VECTOR_CENTER:DBLARR(3), $ SURFACE_TANGENT_VECTOR_C1:DBLARR(3), $ SURFACE_TANGENT_VECTOR_C2:DBLARR(3), $ SURFACE_TANGENT_VECTOR_C3:DBLARR(3), $ SURFACE_TANGENT_VECTOR_C4:DBLARR(3), $ RA_SET:DBLARR(5), $ DEC_SET:DBLARR(5), $ TARGET_LATITUDE_SET:DBLARR(5), $ TARGET_LONGITUDE_SET:DBLARR(5), $ TARGET_ALTITUDE_SET:DBLARR(5), $ SLIT_ROTATION_ANGLE:double(0), $ ALONG_TRACK_FOOTPRINT_SIZE:double(0), $ ACROSS_TRACK_FOOTPRINT_SIZE:double(0), $ FOOTPRINT_AZIMUTH:double(0), $ INCIDENCE_ANGLE:double(0), $ EMISSION_ANGLE:double(0), $ PHASE_ANGLE:double(0), $ SLANT_RANGE_TO_CENTER:double(0), $ SUBSPACECRAFT_LATITUDE:double(0), $ SUBSPACECRAFT_LONGITUDE:double(0), $ NADIR_ALTITUDE:double(0), $ SUBSOLAR_LATITUDE:double(0), $ SUBSOLAR_LONGITUDE:double(0), $ SOLAR_DISTANCE:double(0), $ PLANET_TRUE_ANOMALY:double(0), $ MIDSTEP_TIME:double(0), $ STEP_UTC_TIME:bytarr(17), $ GRATING_OFFSET:float(0), $ STEP_POSITION:long(0), $ STEP_WAVELENGTH:float(0), $ RAW_STEP_DATA:uint(0), $ COUNT_RATE:float(0), $ DEAD_CORRECTED_COUNT_RATE:float(0), $ DARK_RATE:float(0), $ SCATTERED_LIGHT_RATE:float(0), $ FULLY_CORRECTED_COUNT_RATE:float(0), $ FULLY_CORRECTED_COUNT_RATE_UNCERTAINTY:float(0), $ STEP_RADIANCE_KR:float(0), $ STEP_RADIANCE_W:float(0), $ STEP_RADIANCE_SIGNAL_TO_NOISE:float(0), $ PMT_TEMPERATURE:float(0), $ DATA_QUALITY_INDEX:bytarr(21), $ SC_TIME:ulong(0), $ ; v1.1 spare_1 changed to SC_TIME, was double, now ulong OBSERVATION_TYPE:bytarr(30), $ ; v3.0 SPARE_2:double(0) $ ; v3.0 Actually the only spare now. } virs_vis_cdr = { $ vis_cdr, $ SEQ_COUNTER:UINT(0), $ SC_TIME:ulong(0), $ PACKET_SUBSECONDS:UINT(0), $ INT_TIME:UINT(0), $ INT_COUNT:UINT(0), $ PERIOD:UINT(0), $ DARK_FREQ:UINT(0), $ TEMP_1:float(0), $ TEMP_2:float(0), $ NIR_GAIN:UINT(0), $ OTHER_CHANNEL_ON:UINT(0), $ NIR_LAMP_ON:UINT(0), $ VIS_LAMP_ON:UINT(0), $ BINNING:UINT(0), $ START_PIXEL:UINT(0), $ END_PIXEL:UINT(0), $ SPECTRUM_NUMBER:UINT(0), $ SPECTRUM_MET:ulong(0), $ SPECTRUM_SUBSECONDS:UINT(0), $ RAW_SPECTRUM_DATA:intarr(512), $ SPECTRUM_UTC_TIME:bytarr(17), $ CORRECTED_COUNTS_SPECTRUM_DATA:fltarr(512), $ CALIBRATED_RADIANCE_SPECTRUM_DATA:fltarr(512), $ NOISE_SPECTRUM_DATA:fltarr(512), $ CALIBRATION_SOFTWARE_VERSION:float(0), $ CHANNEL_WAVELENGTHS:fltarr(512), $ HK_DATA_FLAG:long(0), $ DATA_QUALITY_INDEX:bytarr(19), $ VIRS_GRATING_TEMP:float(0), $ ;SPACECRAFT_POSITION_VECTOR:dblarr(3), $ These 4 fields deleted for v3.0 ;SUN_POSITION_VECTOR:dblarr(3), $ ;TARGET_BODY_VECTOR:dblarr(3), $ ;INSTRUMENT_BORESIGHT_VECTOR:dblarr(3), $ TARGET_LATITUDE_SET:dblarr(5), $ TARGET_LONGITUDE_SET:dblarr(5), $ ALONG_TRACK_FOOTPRINT_SIZE:double(0), $ ACROSS_TRACK_FOOTPRINT_SIZE:double(0), $ FOOTPRINT_AZIMUTH:double(0), $ INCIDENCE_ANGLE:double(0), $ EMISSION_ANGLE:double(0), $ PHASE_ANGLE:double(0), $ SLANT_RANGE_TO_CENTER:double(0), $ SUBSPACECRAFT_LATITUDE:double(0), $ SUBSPACECRAFT_LONGITUDE:double(0), $ NADIR_ALTITUDE:double(0), $ SUBSOLAR_LATITUDE:double(0), $ SUBSOLAR_LONGITUDE:double(0), $ SOLAR_DISTANCE:double(0), $ PLANET_TRUE_ANOMALY:double(0), $ SPARE_1:float(0), $ RIGHT_ASCENSION:double(0), $ DECLINATION:double(0), $ SPARE_2:long(0), $ SPARE_3:long(0), $ SPARE_4:long(0), $ SPARE_5:long(0), $ SPARE_6:long(0), $ SPARE_7:long(0), $ SPARE_8:long(0), $ SPARE_9:long(0), $ SPARE_10:long(0), $ SPARE_11:long(0) $ } virs_nir_cdr = { $ nir_cdr, $ SEQ_COUNTER:UINT(0), $ SC_TIME:ulong(0), $ PACKET_SUBSECONDS:UINT(0), $ INT_TIME:UINT(0), $ INT_COUNT:UINT(0), $ PERIOD:UINT(0), $ DARK_FREQ:UINT(0), $ TEMP_1:float(0), $ TEMP_2:float(0), $ NIR_GAIN:UINT(0), $ OTHER_CHANNEL_ON:UINT(0), $ NIR_LAMP_ON:UINT(0), $ VIS_LAMP_ON:UINT(0), $ BINNING:UINT(0), $ START_PIXEL:UINT(0), $ END_PIXEL:UINT(0), $ SPECTRUM_NUMBER:UINT(0), $ SPECTRUM_MET:ulong(0), $ SPECTRUM_SUBSECONDS:UINT(0), $ RAW_SPECTRUM_DATA:intarr(256), $ SPECTRUM_UTC_TIME:bytarr(17), $ CORRECTED_COUNTS_SPECTRUM_DATA:fltarr(256), $ CALIBRATED_RADIANCE_SPECTRUM_DATA:fltarr(256), $ NOISE_SPECTRUM_DATA:fltarr(256), $ CALIBRATION_SOFTWARE_VERSION:float(0), $ CHANNEL_WAVELENGTHS:fltarr(256), $ HK_DATA_FLAG:long(0), $ DATA_QUALITY_INDEX:bytarr(19), $ VIRS_GRATING_TEMP:float(0), $ ;SPACECRAFT_POSITION_VECTOR:dblarr(3), $ These 4 fields deleted for v3.0 ;SUN_POSITION_VECTOR:dblarr(3), $ ;TARGET_BODY_VECTOR:dblarr(3), $ ;INSTRUMENT_BORESIGHT_VECTOR:dblarr(3), $ TARGET_LATITUDE_SET:dblarr(5), $ TARGET_LONGITUDE_SET:dblarr(5), $ ALONG_TRACK_FOOTPRINT_SIZE:double(0), $ ACROSS_TRACK_FOOTPRINT_SIZE:double(0), $ FOOTPRINT_AZIMUTH:double(0), $ INCIDENCE_ANGLE:double(0), $ EMISSION_ANGLE:double(0), $ PHASE_ANGLE:double(0), $ SLANT_RANGE_TO_CENTER:double(0), $ SUBSPACECRAFT_LATITUDE:double(0), $ SUBSPACECRAFT_LONGITUDE:double(0), $ NADIR_ALTITUDE:double(0), $ SUBSOLAR_LATITUDE:double(0), $ SUBSOLAR_LONGITUDE:double(0), $ SOLAR_DISTANCE:double(0), $ PLANET_TRUE_ANOMALY:double(0), $ SPARE_1:float(0), $ RIGHT_ASCENSION:double(0), $ DECLINATION:double(0), $ SPARE_2:long(0), $ SPARE_3:long(0), $ SPARE_4:long(0), $ SPARE_5:long(0), $ SPARE_6:long(0), $ SPARE_7:long(0), $ SPARE_8:long(0), $ SPARE_9:long(0), $ SPARE_10:long(0), $ SPARE_11:long(0) $ } end ;----------------------------------------------------------------------------- ; * mascs_normalize_photometry - returns data normalization factor. ;----------------------------------------------------------------------------- ; ; inputs: ; inc: incidence angle (degrees) ; emis: emission angle (degrees) ; phase: phase angle (degrees) ; output: ; fac (the factor to apply to the data to normalize it to a phase angle of 90deg) ; optional keyword inputs: ; inc_norm: default is 45deg ; emis_norm: default is 45deg ; phase_norm: default is 90deg ; the value for the phase curve was obtained by photometric fitting using the routine uvvs_surface_orbit_analysis5.pro ; pro mascs_normalize_photometry, inc, emis, phase, fac, inc_norm=inc_norm, emis_norm=emis_norm, phase_norm=phase_norm if keyword_set(inc_norm) eq 0 then inc_norm = 45. if keyword_set(emis_norm) eq 0 then emis_norm = 45. if keyword_set(phase_norm) eq 0 then phase_norm = 90. ;p = [0.0305246, -0.000192598] p = [0.0576184, -0.000352463] fac1 = (cos(inc_norm*!dtor)/(cos(inc_norm*!dtor)+cos(emis_norm*!dtor))) / (cos(inc*!dtor)/(cos(inc*!dtor)+cos(emis*!dtor))) ; Lommel-Seeliger term fac2 = (p[0] + phase_norm*p[1]) / (p[0] + phase*p[1]) ; linear phase function of the range 75-105deg fac = fac1 * fac2 ; inc_norm = 45. ; emis_norm = 45. ; phase_norm = 90. ; print, (cos(inc_norm*!dtor)/(cos(inc_norm*!dtor)+cos(emis_norm*!dtor))) * (p[0] + phase_norm*p[1]) end ;----------------------------------------------------------------------------- ; * read_mascs_cdr_5 - reads data from a MASCS binary calibrated data ; record, returning an array of data structures that match the table ; structure defined in the CDR SIS documents for UVVS and VIRS. ;----------------------------------------------------------------------------- function read_mascs_cdr_5, filename ; v1.0 mrl 10/10/09 Read data from a MASCS binary Calibrated Data Record, ; returning an array of data structures that match the ; table structure defined in the CDR SIS documents for ; UVVS and VIRS ; Works on all 4 flavors of CDR: UVVS header, UVVS data, ; VIRS VIS, and VIRS NIR. ; Reworked from the original to avoid the used of binary ; templates, which seem to be causing problems with ; MacOS implementation on 10.6.x and IDL7.1 (at least). ; ; v1.1 mrl 5/25/10 Changed loop counters to longs to handle large files. ; ; v1.2 mrl 8/19/10 Renamed to read_mascs_cdr3.pro. Major change to improve ; speed: space for the entire array of structures is now ; allocated at the start. Much, much faster. ; V2 8/2011 AWM Renamed to read_mascs_cdr4.pro ; Updated to replace SPARE_2 (double) with PMT_Temperature (float) ; Moved the location of PMT_Temperature in the Structure allocation ; Changed name of Radiance Uncertainty to STEP_RADIANCE_SIGNAL_TO_NOISE ; ; v3.0 mrl 5/11/12 Changed name again to "read_mascs_cdr_5.pro to signal ; revisions to the CDR format. Subprograms have also been ; updated; use the ones with a '5' in the name. ; ; Developer contact information: ; Mark Lankton ; University of Colorado/LASP ; mark.lankton@lasp.colorado.edu ; 303-492-7915 office ; 720-272-6555 cell if n_params() ne 1 then filename = dialog_pickfile() if filename eq '' then return, -1 init_mascs_cdr_templates_5 ; Key text from CDR file names, to identify the type of data in file visname = 'VIRSVC*.DAT' nirname = 'VIRSNC*.DAT' uvvshdrname = '*HDR.DAT' uvvssciname = '*SCI.DAT' ; Constants derived from UVVS and VIRS CDR formats nirsize = 4954 ; was 5050 in previous version vissize = 9562 ; was 9658 in previous version uvvshdrsize = 50 uvvsscisize = 752 ; Was 970 in previous version ; These will come in handy below. isUVVSSci = 1 isUVVSHdr = 2 isVISSci = 3 isNIRSci = 4 whichType = 0 justname = strupcase(file_basename(filename)) info = file_info(filename) openr, theLUN, filename, /get_LUN if strmatch(justname, visname) then begin num_data = info.size / vissize whichType = isVISSCI dummy = {vis_cdr} endif else if strmatch(justname, nirname) then begin num_data = info.size / nirsize whichType = isNIRSci dummy = {nir_cdr} endif else if strmatch(justname, uvvshdrname) then begin num_data = info.size / uvvshdrsize whichType = isUVVSHdr dummy = {cdr_hdr} endif else if strmatch(justname, uvvssciname) then begin num_data = info.size / uvvsscisize whichType = isUVVSSci dummy = {cdr_sci} endif else begin print, 'Unknown file type' return, -1 endelse ;print, 'number of items:', num_data result = replicate(dummy, num_data) case whichType of isUVVSHdr: begin for i = long(0), num_data -1 do begin result[i] = read_uvvs_cdr_hdr(theLUN) endfor end isUVVSSci: begin for i = long(0), num_data -1 do begin result[i] = read_uvvs_cdr_sci_5(theLUN) endfor end isVISSCI: begin for i = long(0), num_data -1 do begin result[i] = read_virs_vis_cdr_5(theLUN) endfor end isNIRSci: begin for i = long(0), num_data -1 do begin result[i] = read_virs_nir_cdr_5(theLUN) endfor end else: print, 'second CASE statement got surprised' endcase free_lun, theLUN return, result end ;----------------------------------------------------------------------------- ; * uvvs_cdr_2_ddr_surf_batch - searches an incoming directory for files ; that contain paths to UVVS obs cdr files. CDR kickoff files will then ; be processed and data needed for the DDR are then written out to an ; ascii file for further processing into binary DDRs. ;----------------------------------------------------------------------------- pro uvvs_cdr_2_ddr_surf_batch ;this idl program will search an incoming directory for files that contain paths ;to UVVS obs CDR files. These are CDR files meeting the criteria needed for generating a surface ;reflectance DDR. One critical criteria is that the CDR needs to be composed of records where the FOV intersects the ;surface of Mercury and thus composed of measurements of the Mercury surface reflectance. ; ;Hence the name - SURFACE REFLECTANCE DDR. ; ;CDR kickoff files will then be processed and DDR csv files created. ;Wipe Dispatch will then take the DDR csv files and turn them into DDR data and labels. print, 'running uvvs_cdr_2_ddr_surf_batch\n' ;look for incoming files in the uvvs_obs/ddr_storage path!. Also create any intermediate products here storage_path = '/project/messenger/SOC/pipe/data/uvvs_obs/ddr_storage/' ;paths for the Wipe_Dispatch portion of DDR processing here ;for uvvs sci hdr ddrs: finalhdr_path = '/project/messenger/SOC/pipe/data/incoming/pipesoc/uvvs_surf_hdr_ddr/' ;for uvvs science ddrs: finalsci_path = '/project/messenger/SOC/pipe/data/incoming/pipesoc/uvvs_surf_sci_ddr/' ;search for MUV kickoff files. Look directly in the storage path. No need to pretend to be like PIPE ;Only MUV detector will be turned into DDR for now. detector = 'MUV' find_uvvs_surf_ddr_kickoff_files,storage_path,detector,kickoff_files,num_kickoff_files if num_kickoff_files gt 0 then begin print, 'found uvvs muv kickoff files:',num_kickoff_files ;run the calibration routines batch_calibrate_uvvs_surf_ddrs,kickoff_files,finalhdr_path,finalsci_path endif exit end ;----------------------------------------------------------------------------- ; * uvvs_derive_muv_reflectance - derives surface reflectance from surface ; observations by the UVVS-MUV channel. ;----------------------------------------------------------------------------- pro UVVS_DERIVE_MUV_REFLECTANCE, filename_dat, filename_hdr, ddr_sci_arr,ddr_hdr_arr ; ;+ ; NAME: ; UVVS_DERIVE_MUV_REFLECTANCE ; ; PURPOSE: ; This procedure will derive surface reflectance from surface observations by the UVVS-MUV channel. ; ; CALLING SEQUENCE: ; UVVS_DERIVE_MUV_REFLECTANCE, Filename_dat, Filename_hdr, Arr ; ; INPUTS: ; Filename_dat: Filename of a UVVS MUV CDR science data file. ; Filename_hdr: Filename of a UVVS MUV CDR science header file. ; ; OUTPUTS: ; ddr_sci_arr: UVVS Science DDR as an array of structures containing derived reflectance and anciallary data. ; ddr_hdr_arr: UVVS Header DDR as an array of structures containing the data from the UVVS CDR header file ; ; RESTRICTIONS: ; required subroutines: ; mascs_normalize_photometry.pro: Routine to normalize photometric variation. ; ; required files: ; uvvs_sensitivity_2_1_2008.sav: Original UVVS sensitivity, an IDL save file. ; solar_irradiance_composite_for_uvvs_surface_reflectance.sav: Solar irradiance spectrum, an IDL save file. ; ; EXAMPLE: ; EXAMPLE1 ; ; filename_dat = '/ORB/MASCS20110422/UVVS/MUV/UMC_ORB_48_11112_111324_SCI.DAT ; filename_hdr = '/ORB/MASCS20110422/UVVS/MUV/UMC_ORB_48_11112_111324_HDR.DAT ; UVVS_DERIVE_MUV_REFLECTANCE, filename_dat, filename_hdr, arr ; ; MODIFICATION HISTORY: ; Written by: Greg Holsclaw, May 23, 2013 ; Modified by: Ray Espiritu, June 25, 2013 to be generalized and work within a cron job ;1 Astronomical Unit = 149 598 000 kilometers au = 149598000.d ;initialize base APL path where MASCS IDL code and supplementary files are stored APL_base_path = '/project/messenger/SOC/pipe/data/cdr_rdr_execs/mascs_idl' ; files with APL paths fsave_solar_spectrum = APL_base_path + '/uvvs_ddr_surf/solar_irradiance_composite_for_uvvs_surface_reflectance.sav' fsave_uvvs_sensitivity = APL_base_path + '/uvvs/uvvs_sensitivity_2_1_2008.sav' ; files with LASP paths ;fsave_solar_spectrum = '/Users/holsclaw/data_resources/Sun/LISIRD/solar_irradiance_composite_for_uvvs_surface_reflectance.sav' ;fsave_uvvs_sensitivity = '/Users/holsclaw/IDL_utilities/UVVS sensitivity/uvvs_sensitivity_2_1_2008.sav' ; ; offset wavelength - all signal below this wavelength is considered scattered light, and subtracted ; wl_offset = 200. ;NOTE: this only works at LASP, not at APL SOC. If you want to test at APL SOC then write a wrapper script that ;calls this procedure with arguments! ;if n_params() eq 0 then begin ; wdir_data = '/Users/holsclaw/MESSENGER/wget/bronte.jhuapl.edu/' ; filename_dat = wdir_data + 'cdr_rdr_products/mascs/data/ORB/MASCS20110422/UVVS/MUV/UMC_ORB_48_11112_111324_SCI.DAT ; filename_hdr = wdir_data + 'cdr_rdr_products/mascs/data/ORB/MASCS20110422/UVVS/MUV/UMC_ORB_48_11112_111324_HDR.DAT ;endif ; ; read in the data and the header ; print, 'reading filename_dat',filename_dat data = read_mascs_cdr_5(filename_dat) print, 'reading filename_hdr',filename_hdr hdr = read_mascs_cdr_5(filename_hdr) ; ; sometimes it appears that the surface observation starts over again ; for example, consider the following pair of files ; /ORB/MASCS20110511/UVVS/MUV/UMC_ORB_49_11131_210736_HDR.DAT ; /ORB/MASCS20110511/UVVS/MUV/UMC_ORB_49_11131_210736_SCI.DAT ; the first of two header elements indicates a 660-step scan and contains 660 values ; the second header also indicates a 660-step scan, but only contains 18 values ; the data file contains 678 values, and the wavelength scale starts over at index 661 ; therefore, the solution will be to restrict the reflectance to the data indicated by the first header. ; data = data[0:hdr[0].num_scan_values-1] hdr = hdr[0] ddr_hdr_arr = hdr ; ; define header and data DDR structures ; uvvs_ddr_surf_sci = { $ ; ddr_surf_sci, $ BIN_NUMBER:UINT(0), $ TARGET_LATITUDE_SET:DBLARR(5), $ TARGET_LONGITUDE_SET:DBLARR(5), $ SLIT_ROTATION_ANGLE:double(0), $ ALONG_TRACK_FOOTPRINT_SIZE:double(0), $ ACROSS_TRACK_FOOTPRINT_SIZE:double(0), $ INCIDENCE_ANGLE:double(0), $ EMISSION_ANGLE:double(0), $ PHASE_ANGLE:double(0), $ SOLAR_DISTANCE:double(0), $ MIDBIN_TIME:double(0), $ BIN_UTC_TIME:bytarr(17), $ BIN_WAVELENGTH:float(0), $ IOF_BIN_DATA:float(0), $ PHOTOM_IOF_BIN_DATA:float(0), $ IOF_BIN_UNCERTAINTY_DATA:float(0), $ PHOTOM_IOF_BIN_UNCERTAINTY_DATA:float(0), $ FULLY_CORRECTED_COUNT_RATE:float(0), $ STEP_RADIANCE_W:float(0), $ PMT_TEMPERATURE:float(0), $ DATA_QUALITY_INDEX:bytarr(21), $ OBSERVATION_TYPE:bytarr(30), $ ; v3.0 SPARE_2:double(0) $ ; v3.0 Actually the only spare now. } ; ; create a composite solar spectrum consisting of SOLSTICE (115-310nm) and Thuillier (>310nm) ; ;get_solar_irradiance_composite_for_uvvs, wlsun, sun_irr, jd=jd restore,fsave_solar_spectrum,/ver ; ; adjust the solar irradiance at 1AU to the orbital distance of Mercury at the time of the observation ; sun_irr_merc = sun_irr / (data[0].SOLAR_DISTANCE/au)^2 ; ; set up wavelength vector and binning ; binsize = 2. ; width of each bin in nm min_wl = 210. max_wl = 300. num_wl = (max_wl-min_wl)/binsize + 1 wl_bin_center = findgen(num_wl)*binsize + min_wl ; center wavelength of the bins wl_bin_start = wl_bin_center - binsize/2. wl_bin_stop = wl_bin_center + binsize/2. ; ; derive the sensitivity used to calibrate the data ; sens = data.step_radiance_w / data.fully_corrected_count_rate ; ; restore the original UVVS sensitivity restore, fsave_uvvs_sensitivity ; ;LASP plotting. Not needed for APL window,10 ;plot, muv_wavelength, muv_sensitivity, yr=[0,max(muv_sensitivity)] ; ; identify wavelengths beyond the valid range and set the sensitivity to NaN ; ndx = where( data.step_wavelength lt min(muv_wavelength) or data.step_wavelength gt max(muv_wavelength), count ) if count gt 0 then sens[ndx] = !values.f_nan ; ; estimate a scattered light offset ; ndx_offset = where( data.step_wavelength lt wl_offset ) offset = mean( data[ndx_offset].fully_corrected_count_rate ) fully_corrected_count_rate = data.fully_corrected_count_rate - offset ; ; re-derive the radiance after subtracting the offset ; step_radiance_w = fully_corrected_count_rate * sens ; ; derive reflectance and bin all fields ; STEP_RADIANCE_W is in units of W/(m^2 steradian micron) ; ddr_sci_arr = replicate(uvvs_ddr_surf_sci,num_wl) inc_norm = 45. emis_norm = 45. phase_norm = 90. for i = 0, num_wl - 1 do begin ; ; select readout elements within each wavelength bin ; ndx = where( data.step_wavelength ge wl_bin_start[i] and data.step_wavelength lt wl_bin_stop[i], count ) ndx_sun = where( wlsun ge wl_bin_start[i] and wlsun lt wl_bin_stop[i], count_sun ) if count ge 1 then begin ddr_sci_arr[i].IOF_BIN_DATA = mean(STEP_RADIANCE_W[ndx]) / ( mean(sun_irr_merc[ndx_sun] ) / !pi) ; ; derive the fractional error from photon shot noise ; frac_error = sqrt( total( float(data[ndx].RAW_STEP_DATA) ) ) / (float(hdr.int_time)/3000.) / total( fully_corrected_count_Rate[ndx] ) ; ddr_sci_arr[i].IOF_BIN_UNCERTAINTY_DATA = ddr_sci_arr[i].IOF_BIN_DATA * frac_error for j = 0, 4 do begin ddr_sci_arr[i].TARGET_LATITUDE_SET[j] = mean(data[ndx].TARGET_LATITUDE_SET[j]) ddr_sci_arr[i].TARGET_LONGITUDE_SET[j] = mean(data[ndx].TARGET_LONGITUDE_SET[j]) endfor ddr_sci_arr[i].SLIT_ROTATION_ANGLE = mean( data[ndx].SLIT_ROTATION_ANGLE ) ddr_sci_arr[i].ALONG_TRACK_FOOTPRINT_SIZE = mean( data[ndx].ALONG_TRACK_FOOTPRINT_SIZE ) ddr_sci_arr[i].ACROSS_TRACK_FOOTPRINT_SIZE = mean( data[ndx].ACROSS_TRACK_FOOTPRINT_SIZE ) ddr_sci_arr[i].INCIDENCE_ANGLE = mean( data[ndx].INCIDENCE_ANGLE ) ddr_sci_arr[i].EMISSION_ANGLE = mean( data[ndx].EMISSION_ANGLE ) ddr_sci_arr[i].PHASE_ANGLE = mean( data[ndx].PHASE_ANGLE ) ddr_sci_arr[i].SOLAR_DISTANCE = mean( data[ndx].SOLAR_DISTANCE ) ddr_sci_arr[i].MIDBIN_TIME = mean( data[ndx].MIDSTEP_TIME ) ddr_sci_arr[i].BIN_UTC_TIME = data[ndx[count/2]].STEP_UTC_TIME ; this is not quite correct - should derive UTC based on the MIDBIN_TIME calculated above ddr_sci_arr[i].PMT_TEMPERATURE = mean( data[ndx].PMT_TEMPERATURE ) ddr_sci_arr[i].STEP_RADIANCE_W = mean( STEP_RADIANCE_W[ndx] ) ddr_sci_arr[i].DATA_QUALITY_INDEX = data[ndx[count/2]].DATA_QUALITY_INDEX ; should we average some of the DQI values? ddr_sci_arr[i].OBSERVATION_TYPE = data[ ndx[count/2] ].OBSERVATION_TYPE ddr_sci_arr[i].FULLY_CORRECTED_COUNT_RATE = mean( FULLY_CORRECTED_COUNT_RATE[ndx] ) ; ; normlize the derived reflectance to a common geometry ; inc = ddr_sci_arr[i].INCIDENCE_ANGLE emis = ddr_sci_arr[i].EMISSION_ANGLE phase = ddr_sci_arr[i].PHASE_ANGLE mascs_normalize_photometry, inc, emis, phase, photom_fac, inc_norm=inc_norm, emis_norm=emis_norm, phase_norm=phase_norm ddr_sci_arr[i].PHOTOM_IOF_BIN_DATA = ddr_sci_arr[i].IOF_BIN_DATA * photom_fac ddr_sci_arr[i].PHOTOM_IOF_BIN_UNCERTAINTY_DATA = ddr_sci_arr[i].PHOTOM_IOF_BIN_DATA * frac_error endif endfor ddr_sci_arr.BIN_WAVELENGTH = wl_bin_center ;LASP debugging code only. Not needed for APL ;if n_params() eq 0 then begin ; ;@idl_startup ; ; ;fplot=wdir_plots+'uvvs_surface_reflectance.eps' ; ;printeps,fplot,/start ; !p.multi=[0,1,3] ; window,0,xs=1200,ys=1000 ; xtitle = 'wavelength (nm)' ; yr = [100,max(data.FULLY_CORRECTED_COUNT_RATE)] ; xr = [ min(data.step_wavelength), max(data.step_wavelength) ] ; plot, data.step_wavelength, data.FULLY_CORRECTED_COUNT_RATE, yr=yr, /ylog, xtitle=xtitle, title='FULLY_CORRECTED_COUNT_RATE', ytitle='counts/second', xr=xr ; oplot, wlsun, sun_irr, linestyle=1 ; oplot, wlsun, sun_irr*10., linestyle=1 ; oplot, wlsun, sun_irr*100., linestyle=1 ; ;marker, y = offset, linestyle=2 ; ;marker, x = wl_offset, by=yr, linestyle=2 ; txt = ['solar irradiance (scaled)'] ; legend,txt,line=1,box=0,charsize=1.5 ; plot, data.step_wavelength, data.step_radiance_w, yr=[0.01,100],/ylog, xtitle=xtitle, title='step_radiance_w', ytitle='W/(m^2 micron)', xr=xr ; oplot, data.step_wavelength, step_radiance_w, linestyle=2 ; txt = 'with offset subtraction' ; legend,txt,line=2,box=0,charsize=1.5 ; plot, wl_bin_center, ddr_sci_arr.IOF_BIN_DATA, yr=[0,0.02], xtitle=xtitle, title='reflectance', xr=xr ; oploterror, wl_bin_center, ddr_sci_arr.IOF_BIN_DATA, ddr_sci_arr.IOF_BIN_UNCERTAINTY_DATA ; ;oplot, wl_bin_center, refl, color=colors.red ; txt = 'with offset subtraction' ; ;legend,txt,line=0,box=0,color=colors.red,charsize=1.5 ; !p.multi=0 ; ;printeps,fplot,/stop ; ; wdir_save = '/users/holsclaw/messenger/' ; fsave = wdir_save + 'uvvs_surface_ddr.sav' ; save,filename=fsave,ddr_sci_arr ; ; stop ;endif end ;----------------------------------------------------------------------------- ; * uvvsddr_surf_hdr_2_ascii - writes the UVVS Surface Reflectance DDR ; header structure into a csv file. ;----------------------------------------------------------------------------- pro uvvsddr_surf_hdr_2_ascii,hdr_arr,sci_arr,ddrascii_fname ;writes the UVVS Surface Reflectance DDR header structure into a csv file ;hdr_arr is the UVVS Surface Reflectance DDR header structure ;sci_arr is the UVVS Surface Reflectance DDR science structure ;ddrascii_fname is the output csv file (full path) ;created by Calogero Mauceri 6/28/2013 ;format of the output surfformat = '(i10,",",14(i5,","),f5.1,",",2(f20.6,:,","))' ;need to extract specific items from the structure sc_time = hdr_arr.sc_time pkt_subseconds = hdr_arr.packet_subseconds start_pos = hdr_arr.start_pos step_count = hdr_arr.step_count int_time = hdr_arr.int_time step_time = hdr_arr.step_time phase_offset = hdr_arr.phase_offset scan_cycles = hdr_arr.scan_cycles zigzag = hdr_arr.zigzag compression = hdr_arr.compression slit_mask_pos = hdr_arr.slit_mask_pos gd_settle_ctr = hdr_arr.gd_settle_ctr num_scan_values = hdr_arr.num_scan_values step_size = hdr_arr.step_size coadd = hdr_arr.coadd ; do not use the calibration version number from the CDR. That is the CDR software version. Use this hardcoded number ;remember to increment it whenever the DDR software is updated. ;cal_sw_ver = hdr_arr.calibration_software_version cal_sw_ver = 1.0 ;determine size of a given variable in the uvvs header. We assume that all other uvvs header variables have ;same number of elements num_records = n_elements(sc_time) print, 'total elements:',num_records ;use the sci array to get the start and stop met ;those information will be stored in the CSV file because needed by the PIPE script converting the ASCII file to the binary version n_sci_records = n_elements(sci_arr) midbin_time = sci_arr.midbin_time start_met = midbin_time(0) stop_met = midbin_time(n_sci_records-1) ;open the file for writing openw,wunit,ddrascii_fname,/get_lun print, 'writing DDR Surface HDR values to ',ddrascii_fname for i = 0, num_records - 1 do begin sc_time_i = sc_time(i) pkt_subseconds_i = pkt_subseconds(i) start_pos_i = start_pos(i) step_count_i = step_count(i) int_time_i = int_time(i) step_time_i = step_time(i) phase_offset_i = phase_offset(i) scan_cycles_i = scan_cycles(i) zigzag_i = zigzag(i) compression_i = compression(i) slit_mask_pos_i = slit_mask_pos(i) gd_settle_ctr_i = gd_settle_ctr(i) num_scan_values_i = num_scan_values(i) step_size_i = step_size(i) coadd_i = coadd(i) cal_sw_ver_i = cal_sw_ver(i) printf,wunit, sc_time_i, pkt_subseconds_i, start_pos_i, step_count_i, int_time_i, $ step_time_i, phase_offset_i, scan_cycles_i, zigzag_i, compression_i, slit_mask_pos_i, $ gd_settle_ctr_i, num_scan_values_i, step_size_i, coadd_i, cal_sw_ver_i, start_met, stop_met, $ format = surfformat endfor close,wunit free_lun,wunit end ;----------------------------------------------------------------------------- ; * uvvsddr_surf_sci_2_ascii - writes the UVVS Surface Reflectance DDR ; science structure into a csv file ;----------------------------------------------------------------------------- pro uvvsddr_surf_sci_2_ascii,arr,ddrascii_fname ;writes the UVVS Surface Reflectance DDR science structure into a csv file ;arr is the UVVS Surface Reflectance DDR science structure ;ddrascii_fname is the output csv file (full path) ;created by Ray Espiritu 6/25/2013 ;format of the output surfformat = '(i8,",",5(f20.6,:,","),5(f20.6,:,","),7(f15.6,:,","),f20.6,",",a17,",",8(f20.10,:,","),a21,",",a30,",",3(f15.6,:,","))' spare1 = 0.0 spare2 = 0.0 spare3 = 0.0 ;need to extract specific items from the structure bin_number = arr.bin_number tar_lat = arr.target_latitude_set tar_lon = arr.target_longitude_set slit_rot = arr.slit_rotation_angle along_track = arr.along_track_footprint_size across_track = arr.across_track_footprint_size inc = arr.incidence_angle emi = arr.emission_angle phase = arr.phase_angle solar_dist = arr.solar_distance midbin_met = arr.midbin_time utc_time = arr.bin_utc_time wavel = arr.bin_wavelength iof_bin = arr.iof_bin_data photom_iof_bin = arr.photom_iof_bin_data iof_noise = arr.iof_bin_uncertainty_data photom_iof_noise = arr.photom_iof_bin_uncertainty_data full_ccr = arr.fully_corrected_count_rate step_w = arr.step_radiance_w pmt_temp = arr.pmt_temperature dqi = arr.data_quality_index obs_type = arr.observation_type num_records = n_elements(bin_number) print, 'writing to ',ddrascii_fname openw,wunit,ddrascii_fname,/get_lun ;need to print a header line because PIPE expects it header = 'UVVS DDR Surf Reflect SCI csv file header' printf, wunit, header for i = 0, num_records - 1 do begin bin_num_i = bin_number[i] tar_lat_i = tar_lat[*,i] tar_lon_i = tar_lon[*,i] slit_rot_i = slit_rot[i] along_track_i = along_track[i] across_track_i = across_track[i] inc_i = inc[i] emi_i = emi[i] phase_i = phase[i] solar_dist_i = solar_dist[i] midbin_met_i = midbin_met[i] utc_time_i = utc_time[*,i] utc_string = string([utc_time_i]) wavel_i = wavel[i] iof_bin_i = iof_bin[i] photom_iof_bin_i = photom_iof_bin[i] iof_noise_i = iof_noise[i] photom_iof_noise_i = photom_iof_noise[i] full_ccr_i = full_ccr[i] step_w_i = step_w[i] pmt_temp_i = pmt_temp[i] dqi_i = dqi[*,i] dqi_string = string([dqi_i]) obs_i = obs_type[*,i] obs_string = string([obs_i]) printf,wunit, bin_num_i, tar_lat_i, tar_lon_i, slit_rot_i, along_track_i, across_track_i,$ inc_i, emi_i, phase_i, solar_dist_i, midbin_met_i, utc_string, wavel_i, iof_bin_i, $ photom_iof_bin_i, iof_noise_i, photom_iof_noise_i, full_ccr_i, step_w_i, pmt_temp_i, $ dqi_string, obs_string, spare1, spare2, spare3, $ format = surfformat endfor close,wunit free_lun,wunit return ;exit end