PRO read_airmisr_v3 ;================================================================================= ; Program: read_airmisr.pro ; ; Version: 3.0 ; ; Date: March 2004 ; ; Function: Open and read AIRMISR L1B2 GP (Georectified Radiance ; Product) or Level 2 AS (Aerosol/Surface) HDF-EOS data files. ; ; Write file information and the values of selected parameter(s) ; to an output text file. The output file is created in the ; current default directory with the same name as the input ; file but with the '.hdf' suffix replaced with '_output.txt'. ; ; Compute radiance for a given band from the scaled radiance ; and the scale factor for that band. ; ; A call to the IDL DIALOG_PICKFILE function is used to create ; a dialog box for filename choice. This routine assumes those ; files are in the current directory. The PATH Keyword may ; added to specify the directory location of the input ; files. ; ; ; *** Please see the README file for further details *** ; ; Parameters: none ; ; Algorithm: Radiances are computed by multiplying the integer scaled ; value by the appropriate scale factor for the band. ; ; Invocation: idl> .compile read_airmisr ; idl> read_airmisr ; ; External Routines: none ; ; Language/Compiler Version: Tested with IDL 6.0 ; (Uses some routines and functionality new in IDL 6.0) ; ; Point of Contact: Comments or questions should be directed to: ; ; Langley Atmospheric Science Data Center ; NASA Langley Research Center ; Mail Code 157D, 2 South Wright Street ; Hampton, Virginia 23681-2199 ; U.S.A. ; ; E-mail: larc@eos.nasa.gov ; Phone: (757)864-8656 ; FAX: (757)864-8807 ; ; Modifications: Updated March 2004 to work with Level 2AS files. ; Removed print statements and transformed messages ; to DIALOG_MESSAGE GUI boxes so program would work ; as an IDL VM application. Added hourglass cursor ; while working since it can take some time to read/write ; the requested data. ;================================================================================= ; if running via the IDL Virtual Machine, set the default directory to ; the directory where this routine is located (otherwise it will default ; to the ITT VIS IDL binary directory) ; if not running the IDL VM, the default directory will be determined ; by the user's IDL preferences or current setting if LMGR(/VM) then begin info = ROUTINE_INFO('read_airmisr_v3',/source) vmdir = FILE_DIRNAME(info.path) cd,vmdir endif device,decomposed=1 vmbase = WIDGET_BASE(/COL,TITLE="read_airmisr") vmlabel = WIDGET_BUTTON(vmbase,VALUE="read_airmisr.bmp",/BITMAP) WIDGET_CONTROL,vmbase,/REALIZE ; NOTE: modify the PATH keyword value in the DIALOG_PICKFILE ; command to specify a directory location for input files. filename = DIALOG_PICKFILE(FILTER='*hdf',TITLE='Select AirMISR file',/READ) ; extract file name from path, without the '.hdf' suffix for use in ; output file name fname = FILE_BASENAME(filename,'*.hdf') ; --- open output file openw,out_lun,fname+'_output.txt',/get_lun ; --- CHECK FOR VALID HDF FILE if (HDF_ISHDF(filename) ne 1) then begin response = DIALOG_MESSAGE("Not a valid HDF file " + filename,/ERROR) goto, exit endif ; --- Select parameters to output to file MAKE_LIST,filename,var_list selectTool,var_list,selected_vars,title="Select parameters to output" selected_names = var_list[selected_vars] WIDGET_CONTROL,/HOURGLASS WRITE_OUTPUT,out_lun,/INIT,FILENAME=filename ; determine file type nameparts = strsplit(fname,'_',/EXTRACT) case nameparts[1] of 'GP' : begin GET_FILE_INFO,filename,strmet,image_time,RAD_SCALES end 'AS' : begin GET_FILE_INFO,filename,strmet,image_time end else: begin response = DIALOG_MESSAGE("Not an AirMISR L1B2 or L2AS file",/ERROR) goto, exit end endcase info_start = STRPOS(strmet,"GridName") info_end = STRPOS(strmet,"GROUP",info_start) if ((info_start eq -1) or (info_end eq -1)) then begin grid_info = strmet endif else begin grid_info = STRMID(strmet,info_start,info_end-info_start) endelse WRITE_OUTPUT,out_lun,/GRIDINFO,IMAGE_TIME=image_time,GRID_INFO=grid_info GET_METADATA,filename,selected_names,selected_vars,out_lun GET_GRID_FIELDS,filename,out_lun,selected_names,selected_vars,RAD_SCALES ; --- CLOSE OUTPUT FILE close,out_lun response = DIALOG_MESSAGE("THE PROGRAM HAS RUN TO COMPLETION.",/INFO) exit: WIDGET_CONTROL,vmbase,/DESTROY END function read_global_attr,filename,attrname,attrdata ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; this routine reads the named global attribute from the specified ; file and returns the attribute value(s) in the attrdata parameter ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; sdid = HDF_SD_START(filename, /READ) if (sdid lt 0) then begin msg_text = "Problem opening data file " + filename goto, error endif attrindex = HDF_SD_ATTRFIND(sdid,attrname) if (attrindex lt 0) then begin msg_text = "Problem getting attribute index for " + attrname goto, error endif HDF_SD_ATTRINFO, sdid, attrindex, data=attrdata HDF_SD_END,sdid return,0 error: status = DIALOG_MESSAGE(msg_text,/INFORMATION,TITLE='read_global_attr message') return,-1 end function read_grid_attr,filename,gridname,attrname,attrdata ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; this function reads the named grid attribute from the specified ; file and grid and returns the attribute value(s) in the attrdata ; parameter ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fid = EOS_GD_OPEN(filename,/READ) if (fid lt 0) then begin msg_text = "Problem opening HDF-EOS file " + filename goto, error endif gid = EOS_GD_ATTACH(fid,gridname) if (gid lt 0) then begin msg_text = "Problem attaching grid " + gridname goto, error endif status = EOS_GD_ATTRINFO(gid, attrname, attrtype, attrcount) if (status lt 0) then begin msg_text = "Problem getting attribute info for " + attrname goto, error endif status = EOS_GD_READATTR(gid,attrname,attrdata) if (status lt 0) then begin msg_text = "Problem reading attribute " + attrname goto, error endif ; account for bug in HDF-EOS attributes that makes data array length = number of bytes ; rather than number of data items case attrtype of 3 : ; unsigned character 4 : ; charcter (string) 5 : attrdata = attrdata[0:(attrcount/4)-1]; float 32 6 : attrdata = attrdata[0:(attrcount/8)-1]; float 64 (double) 20 : ; int8 21 : ; uint8 22 : attrdata = attrdata[0:(attrcount/2)-1]; int16 23 : attrdata = attrdata[0:(attrcount/2)-1]; uint16 24 : attrdata = attrdata[0:(attrcount/4)-1]; int32 25 : attrdata = attrdata[0:(attrcount/4)-1]; uint32 else : ;unknown so treat as 1 byte length endcase status = EOS_GD_DETACH(gid) if (status lt 0) then begin msg_text = "Problem detaching grid " + gridname goto, error endif status = EOS_GD_CLOSE(fid) if (status lt 0) then begin msg_text = "Problem closing HDF-EOS file " + filename goto, error endif return,0 error: status = DIALOG_MESSAGE(msg_text,/INFORMATION,TITLE='read_grid_attr message') return,-1 end PRO GET_METADATA,filename,selected_names,selected_vars,out_lun ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Function: This routine reads the selected grid attribues (or file ; attribute, in the case of structural metadata) and writes ; the data values to the output file ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; first_met = 1 fid = EOS_GD_OPEN (filename,/READ) numgrid = EOS_GD_INQGRID(filename,gridlist) if (numgrid ne 1) then begin response = DIALOG_MESSAGE("Unexpected number of grids in file: " +$ strtrim(string(numgrid),2)+string(10B)+"Grid names: "+gridlist,$ /ERROR) return end gid = EOS_GD_ATTACH(fid,gridlist[0]) if (gid lt 0) then begin response = DIALOG_MESSAGE("Can't find AirMISR grid in file "+filename,$ /ERROR) return end num_fields = EOS_GD_INQFIELDS(gid,field_list,rank,num_type) sel_attr = where(selected_vars ge num_fields,attr_count) ; indices into selected_names for attributes, ; since fields are first in the list for i=0,attr_count-1 do begin status = 0 attr_name = selected_names[sel_attr[i]] if (attr_name eq 'HDF-EOS Structural Metadata') then begin status = read_global_attr(filename,'StructMetadata.0',data) data = strtrim(data,2) endif else begin ; get the grid attribute data status = read_grid_attr(filename,gridlist[0],attr_name,data) endelse if (status lt 0) then begin response = DIALOG_MESSAGE('Problem getting data value(s) for '+attr_name,$ /WARN) endif else begin WRITE_OUTPUT,out_lun,/METADATA,FIRST_MET=first_met,NAME=attr_name,DATA=data first_met = 0 endelse endfor status = EOS_GD_DETACH(gid) status = EOS_GD_CLOSE(fid) END PRO GET_GRID_FIELDS,filename,out_lun,selected_names,selected_vars,RAD_SCALES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Function: This routine reads the data fields for the ; AIRMISR data set and returns the selected parameters. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; first_gf = 1 scale = 0 fid = EOS_GD_OPEN (filename,/READ) if (fid lt 0) then begin response = DIALOG_MESSAGE("Problem opening file "+filename,/ERROR) return end numgrid = EOS_GD_INQGRID(filename,gridlist) if (numgrid ne 1) then begin response = DIALOG_MESSAGE("Unexpected number of grids in file: " +$ strtrim(string(numgrid),2)+string(10B)+"Grid names: "+gridlist,$ /ERROR) return end gid = EOS_GD_ATTACH(fid,gridlist[0]) if (gid lt 0) then begin response = DIALOG_MESSAGE("Can't find AirMISR grid in file "+filename,$ /ERROR) return end num_fields = EOS_GD_INQFIELDS(gid,field_list,rank,num_type) sel_fields = where(selected_vars lt num_fields,field_count) ; indices into selected_names for fields, ; since fields are first in the list for i=0,field_count -1 do begin field_name = selected_names[sel_fields[i]] status = EOS_GD_FIELDINFO(gid,field_name,rank,dims,numtype,dimlist) if (status lt 0) then begin response = DIALOG_MESSAGE('Problem getting info for field '+field_name,/WARN) endif dimnames = strsplit(dimlist,',',/EXTRACT) status = EOS_GD_READFIELD(gid,field_name,data) if (status lt 0) then begin response = DIALOG_MESSAGE('Problem getting data values for field '+field_name,$ /WARN) endif else begin status = EOS_GD_GETFILLVALUE(gid,field_name,data_fill) if (status lt 0) then begin response = DIALOG_MESSAGE('Problem getting fill value for field '+field_name,$ /WARN) data_fill = 'Undefined' ; should never need this since AirMISR fields all have ; fill values specified endif ; scale radiance data case strtrim(field_name,2) of 'Terrain Blue': begin data = data * ((data ne data_fill) * RAD_SCALES[0] + (data eq data_fill)) scale = RAD_SCALES[0] end 'Terrain Green': begin data = data * ((data ne data_fill) * RAD_SCALES[1] + (data eq data_fill)) scale = RAD_SCALES[1] end 'Terrain Red': begin data = data * ((data ne data_fill) * RAD_SCALES[2] + (data eq data_fill)) scale = RAD_SCALES[2] end 'Terrain Infrared': begin data = data * ((data ne data_fill) * RAD_SCALES[3] + (data eq data_fill)) scale = RAD_SCALES[3] end 'Ellipsoid Blue': begin data = data * ((data ne data_fill) * RAD_SCALES[0] + (data eq data_fill)) scale = RAD_SCALES[0] end 'Ellipsoid Green': begin data = data * ((data ne data_fill) * RAD_SCALES[1] + (data eq data_fill)) scale = RAD_SCALES[1] end 'Ellipsoid Red': begin data = data * ((data ne data_fill) * RAD_SCALES[2] + (data eq data_fill)) scale = RAD_SCALES[2] end 'Ellipsoid Infrared': begin data = data * ((data ne data_fill) * RAD_SCALES[3] + (data eq data_fill)) scale = RAD_SCALES[3] end else: begin ; no adjustment needed for other variables end endcase init = 0 WRITE_OUTPUT,out_lun,/GRIDFIELD,FIRST_GF=first_gf,NAME=field_name,DATA=data,$ FILL=data_fill,SCALE=scale,DIMNAMES=dimnames,DIMS=dims first_gf = 0 endelse endfor ; iteration through selected fieldds status = EOS_GD_DETACH(gid) status = EOS_GD_CLOSE(fid) END PRO MAKE_LIST,filename,var_list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Function: This routine builds the list of AIRMISR grid fields and grid ; attributes for the selection list and adds structural ; metadata to the list ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; var_list = '' fid = EOS_GD_OPEN (filename,/READ) if (fid lt 0) then begin response = DIALOG_MESSAGE("Problem opening file "+filename,/ERROR) return end numgrid = EOS_GD_INQGRID(filename,gridlist) if (numgrid ne 1) then begin response = DIALOG_MESSAGE("Unexpected number of grids in file: " +$ strtrim(string(numgrid),2)+string(10B)+"Grid names: "+gridlist,$ /ERROR) return end gid = EOS_GD_ATTACH(fid,gridlist[0]) if (gid lt 0) then begin response = DIALOG_MESSAGE("Can't find AirMISR grid in file "+filename,$ /ERROR) return end num_fields = EOS_GD_INQFIELDS(gid,field_list,rank,num_type) num_attrs = EOS_GD_INQATTRS(gid,attr_list) fields = strsplit(field_list,',',/EXTRACT) attrs = strsplit(attr_list,',',/EXTRACT) var_list = strarr(num_fields+num_attrs+1) var_list[0:num_fields-1] = fields var_list[num_fields:num_fields+num_attrs-1] = attrs var_list[num_fields+num_attrs] = 'HDF-EOS Structural Metadata' status = EOS_GD_DETACH(gid) status = EOS_GD_CLOSE(fid) return END PRO WRITE_OUTPUT,out_lun, $ INIT=init,FILENAME=filename,GRIDINFO=gridinfo,IMAGE_TIME=image_time,GRID_INFO=grid_info,$ METADATA=metadata,FIRST_MET=first_met,NAME=name,DATA=data, $ GRIDFIELD=gridfield,FIRST_GF=first_gf,FILL=data_fill,SCALE=scale,$ DIMNAMES=dimnames,DIMS=dims ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Function: This routine writes data selected from the ; AIRMISR file to the output file. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if KEYWORD_SET(INIT) then begin printf,out_lun,' ' printf,out_lun,'File: ',filename printf,out_lun,' ' endif if KEYWORD_SET(GRIDINFO) then begin if (image_time[0] ne '') then begin printf,out_lun,'Image Start Time = ',image_time[0] printf,out_lun,'Image End Time = ',image_time[1] printf,out_lun,' ' endif printf,out_lun,grid_info printf,out_lun,' ' endif if KEYWORD_SET(METADATA) then begin if KEYWORD_SET(FIRST_MET) then begin printf,out_lun,' VALUES for Metadata' printf,out_lun,'================================================================================' endif printf,out_lun,'Name = ',name printf,out_lun,' ' printf,out_lun,'Data =' printf,out_lun,data printf,out_lun,'--------------------------------------------------------------------------------' endif if KEYWORD_SET(GRIDFIELD) then begin if KEYWORD_SET(FIRST_GF) then begin printf,out_lun,' ' printf,out_lun,' VALUES for Grid Fields' printf,out_lun,'================================================================================' endif printf,out_lun,'Name = ',name if (scale ne 0) then printf,out_lun,'Scale Value = ',scale printf,out_lun,'Dimensions:' for i=0,n_elements(dimnames)-1 do $ printf,out_lun,format="(3x,A10,' = ',I5)",dimnames[i],dims[i] printf,out_lun,'Fill Value = ',data_fill printf,out_lun,' ' printf,out_lun,'Data =' printf,out_lun,data printf,out_lun,'--------------------------------------------------------------------------------' printf,out_lun,' ' endif return END PRO GET_FILE_INFO,filename,grid_info,image_time,RAD_SCALES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Function: This routine obtains the image time, grid info, and radiance ; scale factors from an AirMISR L1B2 (GP) file or just grid_info ; from a Level 2AS file ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; numgrid = EOS_GD_INQGRID(filename,gridlist) if (numgrid ne 1) then begin response = DIALOG_MESSAGE("Unexpected number of grids in file: " +$ strtrim(string(numgrid),2)+string(10B)+"Grid names: "+gridlist,$ /ERROR) return end image_time = strarr(2) image_time[*] = '' if N_PARAMS() eq 4 then begin status = read_grid_attr(filename,gridlist[0],'Minimum_image_time',attrdata) image_time[0] = attrdata status = read_grid_attr(filename,gridlist[0],'Maximum_image_time',attrdata) image_time[1] = attrdata status = read_grid_attr(filename,"AirMisr",'Rad_scale_factor (1=Blue;2=Green;3=Red;4=Nir)',RAD_SCALES) endif status = read_global_attr(filename,'StructMetadata.0',grid_info) END ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; Routines to implement the variable selection GUI ; ; pro selectTool,list_items,selected_items,title=title ;=============================================================================== ; Program: selectTool ; ; Version: 2.0 ; ; Date: March 2004 ; ; Purpose/Function: ; This procedure creates a list selection GUI ; and returns the indices of the selected list items ; ; Parameters: ; input list_items strarr items to display in selection list ; output selected_items intarr indices of list items chosen ; ; Keywords: ; title string title/prompt string for the GUI ; ; Invocation: idl> selectTool, parameter_list,index_list ; ; ; Language/Compiler Version: ; This routine has been tested on the systems listed below. ; Computer Operating System IDL Version ; --------------- ---------------- ----------- ; PC Windows 2000 6.0 ; ; ; Updates: generalized to make it a useful utility GUI item, cleaned up ; code and logic ; ;=============================================================================== common selectblock,selected ; create a GUI base base = widget_base(/column,title=title) ; create function buttons buttonBase = widget_base(base,/ROW) b1 = widget_button(buttonBase,value='Select All',UVALUE="selectall") b2 = widget_button(buttonBase,value='Help',UVALUE="help") b3 = widget_button(buttonBase,value='Selection Complete',UVALUE="complete") ; create the selection list listBase = widget_base(base,/row) listID = widget_list(listBase,value=list_items,ysize=20,/multiple,UVALUE="list") widget_control,base,/realize ; initialize the state structure state={listID:listID} widget_control,base,set_uvalue=state xmanager,'selectTool',base ; control returns here when GUI is destroyed selected_items = selected return end PRO selectTool_event,event ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This procedure manages events generated by the selectTool GUI ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; common selectblock,selected_items widget_control,event.top,get_uvalue=state widget_control,event.id,GET_UVALUE=uvalue case uvalue of 'help' : begin nl = string(10B) msg = "Select items from the list" + nl if (!d.name eq 'X') then begin msg = msg + nl + 'Holding down the Shift key and clicking an item selects the range ' msg = msg + nl + 'from the previously selected item to the current item.' msg = msg + nl + nl + 'Holding down the mouse button when selecting items' msg = msg + nl + 'also selects a range.' msg = msg +nl + nl + 'Holding down the Control key and clicking an item' msg = msg + nl + 'toggles that item between the selected and unselected state' msg = msg + nl + 'the selected and unselected state.' endif else if (!d.name eq 'WIN') or (!d.name eq 'MAC') then begin msg = msg + nl + 'Holding down the Shift key and clicking an item selects the range ' msg = msg + nl + 'from the previously selected item to the current item. ' msg = msg + nl + nl + 'Holding down the Control key and clicking an item' msg = msg + nl + 'toggles that item between the selected and unselected state.' endif response = DIALOG_MESSAGE(msg,title="Help",/INFO) end 'list' : 'selectall' : begin num_items = WIDGET_INFO(state.listID,/LIST_NUMBER) widget_control,state.listID,set_list_select=lindgen(num_items) end 'complete' : begin selected_items = WIDGET_INFO(state.listID,/LIST_SELECT) sz = size(selected_items) if (sz[0] eq 0) then begin; if scalar if (selected_items eq -1) then begin response = DIALOG_MESSAGE("No items were selected. Exit from program?",/QUESTION) if (strupcase(response) eq "YES") then begin WIDGET_CONTROL,event.top,/DESTROY retall endif endif else WIDGET_CONTROL,event.top,/DESTROY endif else WIDGET_CONTROL,event.top,/DESTROY end else: endcase return end