;+ ; ; Laboratory for Atmospheric and Space Physics ; University of Colorado, Boulder, Colorado, USA ; ; FILENAME: ; analyze_cips_data.pro ; ; AUTHOR: ; Lon Riesberg ; ; DATE: May 5, 2006 ; ; PURPOSE: ; Preps and displays CIPS data in an interactive iTools viewer. ; ; BACKGROUND: ; ; ALGORITHM: ; ; REFERENCES: ; CIPS Algorithm Theoretical Basis Document ; CIPS Processing Requirements Document ; Conversations with CIPS Science and Engineering Teams(Dave Rusch, ; Scott Bailey) ; ; NOTES: ; ; CONSTRAINTS: ; ; OTHER SERVERS/MODULES USED: ; ; RELATED MODULES / CLASSES: ; ; SUPPORTING DATABASE TABLES OR FILES: ; ; USAGE EXAMPLE: ;- ; ---------------------------------------------------------------------- ; CONSTRUCTOR ; ---------------------------------------------------------------------- ; INPUT PARAMETERS: ; ; OUTPUT PARAMETERS: ; NONE ; ; RETURN VALUE: ; A value of 1 is returned if the initialization was successful ; ; KEYWORD ARGUMENTS: ; function cips_data_analyzer::INIT ;- return, 1 end ; -------------------------------------------------------------------------- ; Function create_thumbnail ; -------------------------------------------------------------------------- ; PURPOSE: ; Makes a thumbnail image from the provided image. ; ; INPUT PARAMETERS: ; image - image to create thumbnail from ; tile_x_dim - tile size of image in x dimension ; tile_y_dim - tile size of image in y dimensiion ; ; OUTPUT PARAMETERS: ; NONE ; ; RETURN VALUE: ; thumbnail_image - a 2D array that's a scaled down version of the provided image ; ; ALGORITH: ; 1) Make 'tiles' from the provided image that are tile_x_dim by tile_y_dim in size. ; 2) Average the values for that tile. ; 3) That tile's averaged value becomes the value for a single pixel in the ; corresponding thumbnail image. ; 4) Essentially, a tile size of 5x5 creates a thumbnail image that's 25 times ; smaller than the provided image. ; ; KEYWORD ARGUMENTS: ; NONE ; ; NOTES: ; Thumbnail images are created by averaging pixel values for each 'tile.' ; The size of the tiles are declared as tile_x_dim and tile_y_dim ; function cips_data_analyzer::create_thumbnail, image, tile_x_dim, tile_y_dim ; define thumbnail dimensions image_size = size(image, /dimensions) image_x_dim = image_size[0] image_y_dim = image_size[1] thumb_x_dim = ceil(image_x_dim / tile_x_dim) thumb_y_dim = ceil(image_y_dim / tile_y_dim) ; init thumbnail_image thumbnail_image = make_array(thumb_x_dim, thumb_y_dim, /float, value = 0.0) ; calculate each thumbnail_image pixel value for row=0, image_y_dim-1, tile_y_dim do begin for col=0, image_x_dim-1, tile_x_dim do begin ; determine average of each tile's pixels if col+tile_x_dim gt image_x_dim then max_x = image_x_dim-1 else max_x = col+tile_x_dim-1 if row+tile_y_dim gt image_y_dim then max_y = image_y_dim-1 else max_y = row+tile_y_dim-1 num_pixels_in_tile = (max_x + 1 - col) * (max_y + 1 - row) curr_tile_sum = total(image[col:max_x, row:max_y], /NAN) curr_tile_ave_val = curr_tile_sum / num_pixels_in_tile ; set thumbnail's pixel value for this tile thumb_x_pixel = ceil(col / tile_x_dim) thumb_y_pixel = ceil(row / tile_y_dim) if thumb_x_pixel ge thumb_x_dim then thumb_x_pixel = thumb_x_dim - 1 if thumb_y_pixel ge thumb_y_dim then thumb_y_pixel = thumb_y_dim - 1 thumbnail_image[thumb_x_pixel, thumb_y_pixel] = curr_tile_ave_val endfor endfor return, thumbnail_image end ; -------------------------------------------------------------------------- ; Function get_scenes, level_1A_images ; -------------------------------------------------------------------------- ; PURPOSE: ; Returns scenes that have been stitched together from the provided ; level 1A images. ; ; INPUT PARAMETERS: ; ; OUTPUT PARAMETERS: ; NONE ; ; RETURN VALUE: ; ; KEYWORD ARGUMENTS: ; NONE ; ; NOTES: ; function cips_data_analyzer::get_scenes, cam_px, cam_mx, cam_py, cam_my print, "building scenes..." ; ; init vars ; gap_between_images = 10 ; determine unique timetags for each scene in current orbit if n_elements(cam_px) gt 0 then begin all_timetags=cam_px.image_tlm_timestamp px_version = cam_px[0].version endif if n_elements(cam_py) gt 0 then begin if n_elements(all_timetags) gt 0 then all_timetags=[all_timetags, cam_py.image_tlm_timestamp] $ else all_timetags = cam_py.image_tlm_timestamp py_version = cam_py[0].version endif if n_elements(cam_mx) gt 0 then begin if n_elements(all_timetags) gt 0 then all_timetags=[all_timetags, cam_mx.image_tlm_timestamp] $ else all_timetags = cam_mx.image_tlm_timestamp mx_version = cam_mx[0].version endif if n_elements(cam_my) gt 0 then begin if n_elements(all_timetags) gt 0 then all_timetags=[all_timetags, cam_my.image_tlm_timestamp] $ else all_timetags = cam_my.image_tlm_timestamp my_version = cam_my[0].version endif scene_timetags = all_timetags[UNIQ(all_timetags, SORT(all_timetags))] n_scenes = n_elements(scene_timetags) message, 'number of scenes: ' + string(n_scenes, format='(i0)'), /info ; init return structure image_structure = create_struct('image', ptr_new(), $ 'thumbnail', ptr_new(), $ 'scattering_angle', ptr_new(), $ 'viewing_angle', ptr_new(), $ 'zenith_angle', ptr_new(), $ 'latitude', ptr_new(), $ 'longitude', ptr_new(), $ 'common_volume', ptr_new(), $ 'info', ' ') stitched_scenes = replicate(image_structure, n_scenes) curr_scene = create_struct('cam_px', ptr_new(), $ 'cam_mx', ptr_new(), $ 'cam_py', ptr_new(), $ 'cam_my', ptr_new()) ; stitch scenes together for scene_idx=0, n_scenes-1 do begin ; in case of message 'error', print message and skip to next scene catch, error_status if error_status eq -7 then begin print, !Error_State.Msg continue endif else if error_status ne 0 then begin catch,/cancel message,/reissue_last endif ; ; assemble image data from 4 cameras for current scene ; ; current scene timetag curr_timetag = scene_timetags[scene_idx] ; Note: generally the scene_idx and the image_index for all 4 cameras will be the same. This ; handles the case of missing images, in which case, the indexes won't match. ; cam_px if n_elements(cam_px) gt 0 then begin image_index = where(cam_px.image_tlm_timestamp eq curr_timetag, num_images) if (num_images eq 1) then begin curr_scene.cam_px = ptr_new(cam_px[image_index]) end else if (num_images gt 1) then begin ; shouldn't ever happen message, string(curr_timetag, num_images, format='(%"Camera px: too many images with timetag %d (%d, shouldnt be more than 1)")') endif else begin ; missing image should be null pointer curr_scene.cam_px = ptr_new() endelse level_1A_image_size = size(*(cam_px[0]).albedo, /dimensions) endif ; cam_mx if n_elements(cam_mx) gt 0 then begin image_index = where(cam_mx.image_tlm_timestamp eq curr_timetag, num_images) if (num_images eq 1) then begin curr_scene.cam_mx = ptr_new(cam_mx[image_index]) end else if (num_images gt 1) then begin ; shouldn't ever happen message, string(curr_timetag, num_images, format='(%"Camera mx: too many images with timetag %d (%d, shouldnt be more than 1)")') endif else begin ; missing image should be null pointer curr_scene.cam_mx = ptr_new() endelse level_1A_image_size = size(*(cam_mx[0]).albedo, /dimensions) endif ; cam_py if n_elements(cam_py) gt 0 then begin image_index = where(cam_py.image_tlm_timestamp eq curr_timetag, num_images) if (num_images eq 1) then begin curr_scene.cam_py = ptr_new(cam_py[image_index]) end else if (num_images gt 1) then begin ; shouldn't ever happen message, string(curr_timetag, num_images, format='(%"Camera py: too many images with timetag %d (%d, shouldnt be more than 1)")') endif else begin ; missing image should be null pointer curr_scene.cam_py = ptr_new() endelse level_1A_image_size = size(*(cam_py[0]).albedo, /dimensions) endif ; cam_my if n_elements(cam_my) gt 0 then begin image_index = where(cam_my.image_tlm_timestamp eq curr_timetag, num_images) if (num_images eq 1) then begin curr_scene.cam_my = ptr_new(cam_my[image_index]) end else if (num_images gt 1) then begin ; shouldn't ever happen message, string(curr_timetag, num_images, format='(%"Camera my: too many images with timetag %d (%d, shouldnt be more than 1)")') endif else begin ; missing image should be null pointer curr_scene.cam_my = ptr_new() endelse level_1A_image_size = size(*(cam_my[0]).albedo, /dimensions) endif ; get dimensions ; Note: assumes that all images to have the same dimensions image_x_dim = level_1A_image_size[0] image_y_dim = level_1A_image_size[1] scene_x_dim = (image_y_dim * 3) + (gap_between_images * 2) scene_y_dim = (image_x_dim * 2) + gap_between_images ; init coordinates to stitch scenes together ; px cam_px_start_x = 0 cam_px_end_x = cam_px_start_x + image_y_dim - 1 cam_px_start_y = ((image_x_dim + gap_between_images) / 2) - 1 cam_px_end_y = cam_px_start_y + image_x_dim - 1 ; my cam_my_start_x = image_y_dim + gap_between_images - 1 cam_my_end_x = cam_my_start_x + image_y_dim - 1 cam_my_start_y = 0 cam_my_end_y = cam_my_start_y + image_x_dim - 1 ; py cam_py_start_x = image_y_dim + gap_between_images - 1 cam_py_end_x = cam_my_start_x + image_y_dim - 1 cam_py_start_y = cam_my_end_y + gap_between_images cam_py_end_y = cam_py_start_y + image_x_dim - 1 ; mx cam_mx_start_x = (2 * image_y_dim) + (gap_between_images * 2) - 1 cam_mx_end_x = cam_mx_start_x + image_y_dim - 1 cam_mx_start_y = ((image_x_dim + gap_between_images) / 2) - 1 cam_mx_end_y = cam_px_start_y + image_x_dim - 1 ; ; assemble scene ; curr_cam_px = 0 curr_cam_mx = 0 curr_cam_py = 0 curr_cam_my = 0 stitched_scenes[scene_idx].image = ptr_new(make_array(scene_x_dim, scene_y_dim, /float, value=!VALUES.F_NAN)) stitched_scenes[scene_idx].scattering_angle = ptr_new(make_array(scene_x_dim, scene_y_dim, /float, value=!VALUES.F_NAN)) stitched_scenes[scene_idx].viewing_angle = ptr_new(make_array(scene_x_dim, scene_y_dim, /float, value=!VALUES.F_NAN)) stitched_scenes[scene_idx].zenith_angle = ptr_new(make_array(scene_x_dim, scene_y_dim, /float, value=!VALUES.F_NAN)) stitched_scenes[scene_idx].latitude = ptr_new(make_array(scene_x_dim, scene_y_dim, /float, value=!VALUES.F_NAN)) stitched_scenes[scene_idx].longitude = ptr_new(make_array(scene_x_dim, scene_y_dim, /float, value=!VALUES.F_NAN)) stitched_scenes[scene_idx].common_volume = ptr_new(make_array(scene_x_dim, scene_y_dim, /float, value=!VALUES.F_NAN)) if ptr_valid(curr_scene.cam_px) then begin curr_px_img = rotate((*(*curr_scene.cam_px).albedo)[*, *], 1) curr_px_ssa = rotate((*(*curr_scene.cam_px).scattering_angle)[*, *], 1) curr_px_lat = rotate((*(*curr_scene.cam_px).latitude)[*, *], 1) curr_px_lon = rotate((*(*curr_scene.cam_px).longitude)[*, *], 1) if ptr_valid((*curr_scene.cam_px).common_volume_map) then begin curr_px_cvo = rotate((*(*curr_scene.cam_px).common_volume_map)[*, *], 1) endif if px_version le 3.00 then begin curr_px_va = rotate((*(*curr_scene.cam_px).viewing_angle)[*, *], 1) curr_px_sza = rotate((*(*curr_scene.cam_px).zenith_angle)[*, *], 1) endif else begin curr_px_va = rotate((*(*curr_scene.cam_px).view_angle_ray_peak)[*, *], 1) curr_px_sza = rotate((*(*curr_scene.cam_px).zenith_angle_ray_peak)[*, *], 1) endelse (*stitched_scenes[scene_idx].image)[cam_px_start_x:cam_px_end_x, cam_px_start_y:cam_px_end_y] = curr_px_img (*stitched_scenes[scene_idx].scattering_angle)[cam_px_start_x:cam_px_end_x, cam_px_start_y:cam_px_end_y] = curr_px_ssa (*stitched_scenes[scene_idx].viewing_angle)[cam_px_start_x:cam_px_end_x, cam_px_start_y:cam_px_end_y] = curr_px_va (*stitched_scenes[scene_idx].zenith_angle)[cam_px_start_x:cam_px_end_x, cam_px_start_y:cam_px_end_y] = curr_px_sza (*stitched_scenes[scene_idx].latitude)[cam_px_start_x:cam_px_end_x, cam_px_start_y:cam_px_end_y] = curr_px_lat (*stitched_scenes[scene_idx].longitude)[cam_px_start_x:cam_px_end_x, cam_px_start_y:cam_px_end_y] = curr_px_lon if n_elements(curr_px_cvo) gt 0 then begin (*stitched_scenes[scene_idx].common_volume)[cam_px_start_x:cam_px_end_x, cam_px_start_y:cam_px_end_y] = curr_px_cvo endif endif if ptr_valid(curr_scene.cam_mx) then begin curr_mx_img = rotate((*(*curr_scene.cam_mx).albedo)[*, *], 1) curr_mx_ssa = rotate((*(*curr_scene.cam_mx).scattering_angle)[*, *], 1) curr_mx_lat = rotate((*(*curr_scene.cam_mx).latitude)[*, *], 1) curr_mx_lon = rotate((*(*curr_scene.cam_mx).longitude)[*, *], 1) if ptr_valid((*curr_scene.cam_mx).common_volume_map) then begin curr_mx_cvo = rotate((*(*curr_scene.cam_mx).common_volume_map)[*, *], 1) endif if mx_version le 3.00 then begin curr_mx_va = rotate((*(*curr_scene.cam_mx).viewing_angle)[*, *], 1) curr_mx_sza = rotate((*(*curr_scene.cam_mx).zenith_angle)[*, *], 1) endif else begin curr_mx_va = rotate((*(*curr_scene.cam_mx).view_angle_ray_peak)[*, *], 1) curr_mx_sza = rotate((*(*curr_scene.cam_mx).zenith_angle_ray_peak)[*, *], 1) endelse (*stitched_scenes[scene_idx].image)[cam_mx_start_x:cam_mx_end_x, cam_mx_start_y:cam_mx_end_y] = curr_mx_img (*stitched_scenes[scene_idx].scattering_angle)[cam_mx_start_x:cam_mx_end_x, cam_mx_start_y:cam_mx_end_y] = curr_mx_ssa (*stitched_scenes[scene_idx].viewing_angle)[cam_mx_start_x:cam_mx_end_x, cam_mx_start_y:cam_mx_end_y] = curr_mx_va (*stitched_scenes[scene_idx].zenith_angle)[cam_mx_start_x:cam_mx_end_x, cam_mx_start_y:cam_mx_end_y] = curr_mx_sza (*stitched_scenes[scene_idx].latitude)[cam_mx_start_x:cam_mx_end_x, cam_mx_start_y:cam_mx_end_y] = curr_mx_lat (*stitched_scenes[scene_idx].longitude)[cam_mx_start_x:cam_mx_end_x, cam_mx_start_y:cam_mx_end_y] = curr_mx_lon if n_elements(curr_px_cvo) gt 0 then begin (*stitched_scenes[scene_idx].common_volume)[cam_mx_start_x:cam_mx_end_x, cam_mx_start_y:cam_mx_end_y] = curr_mx_cvo endif endif if ptr_valid(curr_scene.cam_py) then begin curr_py_img = rotate((*(*curr_scene.cam_py).albedo)[*, *], 1) curr_py_ssa = rotate((*(*curr_scene.cam_py).scattering_angle)[*, *], 1) curr_py_lat = rotate((*(*curr_scene.cam_py).latitude)[*, *], 1) curr_py_lon = rotate((*(*curr_scene.cam_py).longitude)[*, *], 1) if ptr_valid ((*curr_scene.cam_py).common_volume_map) then begin curr_py_cvo = rotate((*(*curr_scene.cam_py).common_volume_map)[*, *], 1) endif if py_version le 3.00 then begin curr_py_va = rotate((*(*curr_scene.cam_py).viewing_angle)[*, *], 1) curr_py_sza = rotate((*(*curr_scene.cam_py).zenith_angle)[*, *], 1) endif else begin curr_py_va = rotate((*(*curr_scene.cam_py).view_angle_ray_peak)[*, *], 1) curr_py_sza = rotate((*(*curr_scene.cam_py).zenith_angle_ray_peak)[*, *], 1) endelse (*stitched_scenes[scene_idx].image)[cam_py_start_x:cam_py_end_x, cam_py_start_y:cam_py_end_y] = curr_py_img (*stitched_scenes[scene_idx].scattering_angle)[cam_py_start_x:cam_py_end_x, cam_py_start_y:cam_py_end_y] = curr_py_ssa (*stitched_scenes[scene_idx].viewing_angle)[cam_py_start_x:cam_py_end_x, cam_py_start_y:cam_py_end_y] = curr_py_va (*stitched_scenes[scene_idx].zenith_angle)[cam_py_start_x:cam_py_end_x, cam_py_start_y:cam_py_end_y] = curr_py_sza (*stitched_scenes[scene_idx].latitude)[cam_py_start_x:cam_py_end_x, cam_py_start_y:cam_py_end_y] = curr_py_lat (*stitched_scenes[scene_idx].longitude)[cam_py_start_x:cam_py_end_x, cam_py_start_y:cam_py_end_y] = curr_py_lon if n_elements(curr_py_cvo) gt 0 then begin (*stitched_scenes[scene_idx].common_volume)[cam_py_start_x:cam_py_end_x, cam_py_start_y:cam_py_end_y] = curr_py_cvo endif endif if ptr_valid(curr_scene.cam_my) then begin curr_my_img = rotate((*(*curr_scene.cam_my).albedo)[*, *], 1) curr_my_ssa = rotate((*(*curr_scene.cam_my).scattering_angle)[*, *], 1) curr_my_lat = rotate((*(*curr_scene.cam_my).latitude)[*, *], 1) curr_my_lon = rotate((*(*curr_scene.cam_my).longitude)[*, *], 1) if ptr_valid((*curr_scene.cam_my).common_volume_map) then begin curr_my_cvo = rotate((*(*curr_scene.cam_my).common_volume_map)[*, *], 1) endif if my_version le 3.00 then begin curr_my_va = rotate((*(*curr_scene.cam_my).viewing_angle)[*, *], 1) curr_my_sza = rotate((*(*curr_scene.cam_my).zenith_angle)[*, *], 1) endif else begin curr_my_va = rotate((*(*curr_scene.cam_my).view_angle_ray_peak)[*, *], 1) curr_my_sza = rotate((*(*curr_scene.cam_my).zenith_angle_ray_peak)[*, *], 1) endelse (*stitched_scenes[scene_idx].image)[cam_my_start_x:cam_my_end_x, cam_my_start_y:cam_my_end_y] = curr_my_img (*stitched_scenes[scene_idx].scattering_angle)[cam_my_start_x:cam_my_end_x, cam_my_start_y:cam_my_end_y] = curr_my_ssa (*stitched_scenes[scene_idx].viewing_angle)[cam_my_start_x:cam_my_end_x, cam_my_start_y:cam_my_end_y] = curr_my_va (*stitched_scenes[scene_idx].zenith_angle)[cam_my_start_x:cam_my_end_x, cam_my_start_y:cam_my_end_y] = curr_my_sza (*stitched_scenes[scene_idx].latitude)[cam_my_start_x:cam_my_end_x, cam_my_start_y:cam_my_end_y] = curr_my_lat (*stitched_scenes[scene_idx].longitude)[cam_my_start_x:cam_my_end_x, cam_my_start_y:cam_my_end_y] = curr_my_lon if n_elements(curr_my_cvo) gt 0 then begin (*stitched_scenes[scene_idx].common_volume)[cam_my_start_x:cam_my_end_x, cam_my_start_y:cam_my_end_y] = curr_my_cvo endif endif ; rotate stitched scenes horizontally *stitched_scenes[scene_idx].image = rotate((*stitched_scenes[scene_idx].image)[*, *], 2) *stitched_scenes[scene_idx].scattering_angle = rotate((*stitched_scenes[scene_idx].scattering_angle)[*, *], 2) *stitched_scenes[scene_idx].viewing_angle = rotate((*stitched_scenes[scene_idx].viewing_angle)[*, *], 2) *stitched_scenes[scene_idx].zenith_angle = rotate((*stitched_scenes[scene_idx].zenith_angle)[*, *], 2) *stitched_scenes[scene_idx].latitude = rotate((*stitched_scenes[scene_idx].latitude)[*, *], 2) *stitched_scenes[scene_idx].longitude = rotate((*stitched_scenes[scene_idx].longitude)[*, *], 2) if ptr_valid(stitched_scenes[scene_idx].common_volume) then begin *stitched_scenes[scene_idx].common_volume = rotate((*stitched_scenes[scene_idx].common_volume)[*, *], 2) endif ; ; create current scene's thumbnail image that gets displayed in analyzer tab ; ; create thumbnail tile_x_dim = 5 tile_y_dim = 5 stitched_scenes[scene_idx].thumbnail = ptr_new(self->create_thumbnail(*stitched_scenes[scene_idx].image, $ tile_x_dim, tile_y_dim)) ; ; 'caption' ; la_time = gps2la(curr_timetag/1E6) caption = la_time ; get nadir point lat/lon finite_idx = where(finite(*stitched_scenes[scene_idx].viewing_angle), num_finite) ; if there's no viewing angle (shouldn't happen) skip nadir lat/lon determination if num_finite gt 0 then begin nadir_idx = where(*stitched_scenes[scene_idx].viewing_angle eq min((*stitched_scenes[scene_idx].viewing_angle)[finite_idx]), num_pts) if num_pts gt 0 then begin ; since images overlap, it's likely that the nadir point shows up in more than 1 camera... so just pick one nadir_lat = (*stitched_scenes[scene_idx].latitude)[nadir_idx[0]] nadir_lon = (*stitched_scenes[scene_idx].longitude)[nadir_idx[0]] caption = la_time + ' Lat: ' + string(nadir_lat, format='(F0.2)') + ' Lon: ' + string(nadir_lon, format='(F0.2)') endif endif stitched_scenes[scene_idx].info = caption ; next scene endfor return, stitched_scenes end ; -------------------------------------------------------------------------- ; FUNCTION find_image_max ; -------------------------------------------------------------------------- ; PURPOSE: ; This function takes an array of pointers to images, then returns the ; maximum value found in all the images. function cips_data_analyzer::find_image_max, images maximum = 0 for i=1, N_ELEMENTS(images)-1 do begin new_max = max(*images[i],/NaN) if new_max gt maximum then maximum = new_max endfor return, maximum end ; -------------------------------------------------------------------------- ; PROCEDURE load_analyzer ; -------------------------------------------------------------------------- ; PURPOSE: ; Loads data into the cips_image_analyzer and opens CIPS Analyzer Application ; ; INPUT PARAMETERS: ; NONE ; ; OUTPUT PARAMETERS: ; NONE ; ; KEYWORD ARGUMENTS: ; retrieved_cloud_panel - tab for retrieved cloud data (level 1C) ; scenes_panel - tab for displaying scenes (level 1A) ; split_window1 - tab where each thumbnail is displayed in a split screen of ; 4 windows. Intended to provide flexibility to display ; various aspects of an image simulataneously ; panel1, panel2 - provides a tab of thumbnail images where clicking on an ; image brings that image up in the main window. ; ; surface - initializes the iTool into surface plot mode ; ; NOTES: ; panel structures are expected to include the following fields: ; panel1 = { images : [ {thumbnail, image, info} , ...] , ; panel_name : 'Panel Title' } ; pro cips_data_analyzer::load_analyzer, split_window1=split_window1, $ retrieved_cloud_panel=retrieved_cloud_panel, $ scenes_panel=scenes_panel, notes_panel=notes_panel, $ stack_panel=stack_panel, l1c_stack_panel=l1c_stack_panel, $ SURFACE=SURFACE, title=title ; if the user closes the analyzer before it's completely rendered, ; a null object error will occur. if that happens, ignore the error. catch, status if status ne 0 then begin if (status eq -754) then begin catch, /cancel return endif else begin if (get_debug_level() gt 1) then print, !Error_State.Msg return endelse endif void = itgetcurrent(tool=oTool) if(ptr_valid(oTool)) then begin result = oTool->FindIdentifiers('*EXIT*', /OPERATIONS) success = oTool->DoAction(result) endif ; Silence the various math warnings !EXCEPT = 0 ; color scale COMMON COLORS, R_orig, G_orig, B_orig, R_curr, G_curr, B_curr ; analyzer title if n_elements(title) eq 0 then title='CIPS Data Analyzer' COMMON CIPS_GLOBAL_STATE, cips_global_options cips_global_options = {curr_view: ' ', $ is_cloud: n_elements(retrieved_cloud_panel), $ is_scenes: n_elements(scenes_panel), $ is_stack: n_elements(stack_panel), $ is_l1c_stack: n_elements(l1c_stack_panel), $ black_bg: 0, $ colorbar: 0, $ stack_split: 0, $ l1c_stack_split:0, $ title:title } ; this should probably be moved or gotten another way ; initialize structure that keeps track of buttons on retrieved_cloud_panel COMMON CLOUD_WINDOW_STATE, cloud_window_options cloud_window_options = {view: 'albedo' , $ scaling_min: 0.0 , $ scaling_max: 100.0 , $ clouds_max: 0.0 , $ unc: 0 , $ surf_view: 0 , $ sza_contours: 0 , $ show_coast: 0 , $ latlon_contours:0 , $ black_bg: 0 , $ colorbar: 0 , $ xplot: ' ' , $ yplot: ' ' } ; Set up the parameter set for the scene_tool oParmSet = OBJ_NEW('IDLitParameterSet', $ NAME = 'CIPS PARAMETERS', $ DESCRIPTION = 'CIPS PARAMETERS') ; NOTE: change the ordering below to change the ordering of the tabs ; (e.g. this will create the default 'Images' tab, then 'Notes', ; 'Scenes', etc...) ; Create the notes panel if 'notes_panel' was provided if (n_elements(notes_panel) gt 0) then begin COMMON VIEW_CIPS_NOTES, notes notes = notes_panel ; Register the UI panel ITRegister, 'notes_panel', 'notes_panel', TYPES='CIPS', /UI_PANEL endif ; Create the scenes_panel if 'scenes_panel' was provided if (n_elements(scenes_panel) gt 0) then begin COMMON VIEW_CIPS_SCENES, panel_scenes, scenes_tvs, is_surface_scenes, $ distort, scenes_max COMMON SCENES_WINDOW_STATE, scenes_window_options scenes_window_options = {view: 'scene', $ scaling_max: 0.0,$ scaling_min: 0.0,$ colorbar: 0 , $ black_bg: 0 , $ surf_view: 0 , $ curr_image_idx: '', $ distorted: 0, $ sza_contours: 0, $ ssa_contours: 0, $ view_contours: 0, $ view_cvo: 0, $ xplot:'latitude', $ yplot:'albedo' $ } panel_scenes = scenes_panel distort = 0 large_array = ptrarr(N_ELEMENTS(scenes_panel.images)) for i=0, N_ELEMENTS(scenes_panel.images)-1 do $ large_array[i] = panel_scenes.images[i].thumbnail scenes_max = self->find_image_max(large_array) ; Register the UI panel ITRegister, 'scenes_panel', 'scenes_panel', TYPES='CIPS', /UI_PANEL endif ; Create the stack_panel if 'stack_panel' was provided if (n_elements(stack_panel) gt 0) then begin COMMON VIEW_CIPS_STACK, panel_stack, layers_tvs, is_surface_stack, layers_thumb_max, stack_max COMMON STACK_WINDOW_STATE, stack_window_options stack_window_options = {view: 'layer', $ scaling_max: 0.0,$ scaling_min: 0.0,$ show_coast: 0 , $ colorbar: 0 , $ black_bg: 0 , $ surf_view: 0 , $ view_cvo:0, $ curr_image_idx: 0, $ show_solar_zenith_angles: 0 , $ show_scattering_angles: 0 , $ show_view_angles: 0 , $ show_albedo_contours: 0, $ show_latlon_contours: 0, $ xplot:'zenith_angle', $ yplot:'albedo', $ n_rows: 1 } panel_stack = stack_panel layers_thumb_max = find_image_95th_percentile(panel_stack.layers.thumbnail) stack_max = self->find_image_max(panel_stack.layers.image) ; Register the UI panel ITRegister, 'stack_panel', 'stack_panel', TYPES='CIPS', /UI_PANEL endif ; Create the l1c_stack_panel if 'l1c_stack_panel' was provided if (n_elements(l1c_stack_panel) gt 0) then begin COMMON VIEW_CIPS_1C_STACK, l1c_panel_stack, l1c_layers_tvs, l1c_is_surface_stack, l1c_layers_thumb_max, l1c_stack_max COMMON L1C_STACK_WINDOW_STATE, l1c_stack_window_options l1c_stack_window_options = {view: 'layer', $ scaling_max: 0.0,$ scaling_min: 0.0,$ show_coast: 0 , $ colorbar: 0 , $ black_bg: 0 , $ surf_view: 0 , $ view_cvo:0, $ curr_image_idx: 0, $ show_solar_zenith_angles: 0 , $ show_scattering_angles: 0 , $ show_view_angles: 0 , $ show_albedo_contours: 0, $ show_latlon_contours: 0, $ xplot:'zenith_angle', $ yplot:'albedo', $ n_rows: 1 } l1c_panel_stack = l1c_stack_panel l1c_layers_thumb_max = find_image_95th_percentile(l1c_panel_stack.layers.thumbnail) l1c_stack_max = self->find_image_max(l1c_panel_stack.layers.image) ; Register the UI panel ITRegister, 'l1c_stack_panel', 'l1c_stack_panel', TYPES='CIPS', /UI_PANEL endif ; Create the retrieved cloud panel if (n_elements(retrieved_cloud_panel) gt 0) then begin COMMON VIEW_CIPS_CLOUD, cloud_images cloud_images = retrieved_cloud_panel ;large_array = ptrarr(N_ELEMENTS(.images)) ;for i=0, N_ELEMENTS(scenes_panel.images)-1 do $ ; large_array[i] = panel_scenes.images[i].thumbnail ;clouds_max = self->find_image_max(large_array) ; Register the UI panel ITRegister, 'retrieved_cloud_panel', 'retrieved_cloud_panel', TYPES='CIPS', /UI_PANEL endif ; Create the first panel with split views if (N_ELEMENTS(split_window1) gt 0) then begin COMMON VIEW_CIPS_SPLIT_WINDOW_1, split_window1_images, split_window1_tvs, $ is_surface_split_1, split1_max split_window1_images = split_window1 large_array = ptrarr(N_ELEMENTS(split_window1.thumbnails)) for i=0, N_ELEMENTS(split_window1.thumbnails)-1 do $ large_array[i] = split_window1.thumbnails[i] split1_max = self->find_image_max(large_array) ; Register the UI panel ITRegister, 'split_window_panel_1', 'split_window_panel_1', TYPES='CIPS', /UI_PANEL endif ; Sets iTool into surface plot mode if SURFACE is set if KEYWORD_SET(SURFACE) then begin is_surface_1=1 & is_surface_2=1 & is_surface_3=1 & is_surface_scenes=1 is_surface_split_1=1 & is_surface_cloud=1 & is_surface_stack=1 & l1c_is_surface_stack=1 endif else begin is_surface_1=0 & is_surface_2=0 & is_surface_3=0 & is_surface_scenes=0 is_surface_split_1=0 & is_surface_cloud=1 & is_surface_stack=0 & l1c_is_surface_stack=0 endelse ; Calculate which image will be the first in the main window based on which ; was the last panel to be added to the iTool registry. if (N_ELEMENTS(retrieved_cloud_panel) gt 0) then begin min_max = filter_sigma(*(retrieved_cloud_panel[0].cld_properties).cld_albedo, 5) oParmSet->Add, OBJ_NEW('IDLitDataIDLARRAY2D', $ 0 > *(retrieved_cloud_panel[0].cld_properties).cld_albedo < min_max[1], $ NAME='InitImage', _EXTRA=_extra), $ PARAMETER_NAME='INITIMAGE' dimensions = size(*(retrieved_cloud_panel[0].cld_properties).cld_albedo, /DIMENSIONS) endif else if (N_ELEMENTS(l1c_stack_panel) gt 0) then begin min_max = filter_sigma(*(l1c_stack_panel.layers[0].image), 5) oParmSet->Add, OBJ_NEW('IDLitDataIDLARRAY2D', $ min_max[0]> *(l1c_stack_panel.layers[0].image) Add, OBJ_NEW('IDLitDataIDLARRAY2D', $ min_max[0]> *(stack_panel.layers[0].image) Add, OBJ_NEW('IDLitDataIDLARRAY2D', $ min_max[0]> *(scenes_panel.images[0].image) Add, OBJ_NEW('IDLitDataIDLARRAY2D', $ min_max[0]> *(panel2.images[0].image) Add, OBJ_NEW('IDLitDataIDLARRAY2D', $ min_max[0]> *(panel1.images[0].image) Add, oPalette, PARAMETER_NAME = 'PALETTE' ; Set the delete mode on the parameter set if(obj_valid(oParmSet))then $ oParmSet->SetAutoDeleteMode, 1 ; Register scene_tool with the iTool system ITRegister, 'View Scenes', 'CIPS_TOOL' ; Create an instance of the iTool cips_analyzer_id = IDLITSYS_CREATETOOL('View Scenes', TITLE=title, $ VISUALIZATION_TYPE="CIPS_TOOL", $ NAME='IMAGE', $ DIMENSIONS=[main_x, main_y], $ IMAGE_DIMENSIONS=[400,400], $ INITIAL_DATA=oParmSet, /NO_SAVEPROMPT, $ /DISABLE_SPLASH_SCREEN, _EXTRA=_extra, /no_block) ; Set up the initial zoom factor void = ITGetCurrent(tool=oTool) if OBJ_VALID(oTool) then begin view_param = oTool->FindIdentifiers('*VIEW_1') oView = oTool->GetByIdentifier(view_param) oView->SetCurrentZoom, zoom_factor oView->GetProperty, DIMENSIONS=view_dims ; Set the tool properties layout_param = oTool->FindIdentifiers('*layout*') result = oTool->DoSetProperty(layout_param, 'VIRTUAL_WIDTH', view_dims[0]) result = oTool->DoSetProperty(layout_param, 'VIRTUAL_HEIGHT', view_dims[1]) result = oTool->DoSetProperty(layout_param, 'SHOW_EXECUTION_UI', 0) result = oTool->DoSetProperty(layout_param, 'AUTO_RESIZE', 1) result = oTool->DoAction(layout_param) oTool->CommitActions endif end ; -------------------------------------------------------------------------- ; Procedure analyze_data ; -------------------------------------------------------------------------- ; PURPOSE: ; Main procedure to read, prep, and analyze simulated CIPS images. ; ; INPUT PARAMETERS: ; ; OUTPUT PARAMETERS: ; NONE ; ; RETURN VALUE: ; ; KEYWORD ARGUMENTS: ; NONE ; ; NOTES: ; cam_mx is cam1 ; cam_px is cam2 ; cam_my is cam3 ; cam_py is cam4 ; function cips_data_analyzer::analyze_data, cam_mx=cam_mx, cam_px=cam_px, cam_my=cam_my, cam_py=cam_py, $ stack=stack, l1c=l1c, sim_retrievals=sim_retrievals, notes=notes, title=title, $ _EXTRA=_extra ; SCENES if (n_elements(cam_px) gt 0) or (n_elements(cam_py) gt 0) or (n_elements(cam_mx) gt 0) or (n_elements(cam_my) gt 0) then begin stitched_scenes = self->get_scenes(cam_px, cam_mx, cam_py, cam_my) self.scenes_panel = ptr_new(create_struct('images', stitched_scenes, 'panel_name', '1A: Scenes')) ; release individual cam data str_free, cam_mx str_free, cam_px str_free, cam_my str_free, cam_py endif ; STACK if (n_elements(stack) gt 0) then begin ; Note: stack is a structure that has pointers to arrays ; of pointers where each array element points to that ; field's data of a map projected scene (layer) n_layers = n_elements(*stack.albedo) message, 'number of stack layers: ' + string(n_layers, format='(i0)'), /info ; init return structure layer_image_structure = create_struct('image', ptr_new(), $ 'thumbnail', ptr_new(), $ 'info', ' ') layer_images = replicate(layer_image_structure, n_layers) thumb_x_tile_dim = 3 thumb_y_tile_dim = 3 for layer_idx=0, n_layers-1 do begin ; large images layer_images[layer_idx].image = (*stack.albedo)[layer_idx] ; thumbnails layer_images[layer_idx].thumbnail = ptr_new(self->create_thumbnail(*(layer_images[layer_idx].image), $ thumb_x_tile_dim, $ thumb_y_tile_dim)) ; caption ; time curr_timetag = (*stack.image_tlm_timestamp)[layer_idx] la_time = gps2la(curr_timetag/1E6) caption = la_time ; lat/lon if stack.version le 3.00 then finite_idx = where(finite(*(*stack.view_angle)[layer_idx]), num_finite) $ else finite_idx = where(finite(*(*stack.view_angle_ray_peak)[layer_idx]), num_finite) if num_finite gt 0 then begin if stack.version le 3.00 then begin nadir_idx = where((*(*stack.view_angle)[layer_idx])[finite_idx] eq min((*(*stack.view_angle)[layer_idx])[finite_idx]), num_pts) endif else begin nadir_idx = where((*(*stack.view_angle_ray_peak)[layer_idx])[finite_idx] eq min((*(*stack.view_angle_ray_peak)[layer_idx])[finite_idx]), num_pts) endelse if num_pts gt 0 then begin ; since camera images overlap, it's likely that the nadir point shows up in more than 1 pixel... so just pick one nadir_lat = (*(*stack.latitude)[layer_idx])[nadir_idx[0]] nadir_lon = (*(*stack.longitude)[layer_idx])[nadir_idx[0]] caption = la_time + ' Lat: ' + string(nadir_lat, format='(F0.2)') + ' Lon: ' + string(nadir_lon, format='(F0.2)') endif endif layer_images[layer_idx].info = caption endfor ; next stack layer self.stack_panel = ptr_new(create_struct('stack', stack, $ 'layers', layer_images, $ 'panel_name', '1B: Stack')) endif ; LEVEL 1C STACK if (n_elements(l1c) gt 0) then begin ; Note: l1c has the same structure of the 1B Stacks n_layers = n_elements(*l1c.albedo) message, 'number of 1C stack layers: ' + string(n_layers, format='(i0)'), /info ; init return structure layer_image_structure = create_struct('image', ptr_new(), $ 'thumbnail', ptr_new(), $ 'info', ' ') layer_images = replicate(layer_image_structure, n_layers) thumb_x_tile_dim = 3 thumb_y_tile_dim = 3 for layer_idx=0, n_layers-1 do begin ; large images layer_images[layer_idx].image = (*l1c.albedo)[layer_idx] ; thumbnails layer_images[layer_idx].thumbnail = ptr_new(self->create_thumbnail(*(layer_images[layer_idx].image), $ thumb_x_tile_dim, $ thumb_y_tile_dim)) ; caption ; time curr_timetag = (*l1c.image_tlm_timestamp)[layer_idx] la_time = gps2la(curr_timetag/1E6) caption = la_time ; lat/lon if l1c.version le 3.00 then finite_idx = where(finite(*(*l1c.view_angle)[layer_idx]), num_finite) $ else finite_idx = where(finite(*(*l1c.view_angle_ray_peak)[layer_idx]), num_finite) if num_finite gt 0 then begin if l1c.version le 3.00 then begin nadir_idx = where((*(*l1c.view_angle)[layer_idx])[finite_idx] eq min((*(*l1c.view_angle)[layer_idx])[finite_idx]), num_pts) endif else begin nadir_idx = where((*(*l1c.view_angle_ray_peak)[layer_idx])[finite_idx] eq min((*(*l1c.view_angle_ray_peak)[layer_idx])[finite_idx]), num_pts) endelse if num_pts gt 0 then begin ; since camera images overlap, it's likely that the nadir point shows up in more than 1 pixel... so just pick one nadir_lat = (*(*l1c.latitude)[layer_idx])[nadir_idx[0]] nadir_lon = (*(*l1c.longitude)[layer_idx])[nadir_idx[0]] caption = la_time + ' Lat: ' + string(nadir_lat, format='(F0.2)') + ' Lon: ' + string(nadir_lon, format='(F0.2)') endif endif layer_images[layer_idx].info = caption endfor ; next stack layer self.l1c_stack_panel = ptr_new(create_struct('stack', l1c, $ 'layers', layer_images, $ 'panel_name', '1C: Stack')) endif ; RETRIEVED CLOUD AREA if n_elements(sim_retrievals) then begin ; Don't really need to run this for lat and lon, but do for x and y level_4_lat_lon, sim_retrievals, lat=latitude, lon=longitude, $ x=x, y=y ; So, we just don't put away the lat and lon ; sim_retrievals.latitude = ptr_new(latitude) ; sim_retrievals.longitude = ptr_new(longitude) ; update retrievals with map projected x, y arrays ammended_retrievals = create_struct(sim_retrievals[0], $ 'map_proj_x', ptr_new(), $ 'map_proj_y', ptr_new()) ammended_retrievals.map_proj_x = ptr_new(x) ammended_retrievals.map_proj_y = ptr_new(y) self.cloud_panel = ptr_new(create_struct('cld_properties', ammended_retrievals, $ 'panel_name', '4: Clouds')) endif ; NOTES if (n_elements(notes) gt 0) then self.notes = ptr_new(notes) self.has_data = 1 ; DISPLAY IMAGES if ptr_valid(self.cloud_panel) then cloud_panel = *self.cloud_panel if ptr_valid(self.scenes_panel) then scenes_panel = *self.scenes_panel if ptr_valid(self.l1c_stack_panel) then l1c_stack_panel = *self.l1c_stack_panel if ptr_valid(self.stack_panel) then stack_panel = *self.stack_panel if ptr_valid(self.notes) then notes = *self.notes self->load_analyzer, retrieved_cloud_panel=cloud_panel, scenes_panel=scenes_panel, l1c_stack_panel=l1c_stack_panel, $ stack_panel=stack_panel, notes_panel=notes, title=title, _EXTRA=_extra return, 1 end ;-------------------------------------------------------------------------- ; HAS_VALID_ITOOL_HANDLE ; ; Purpose: checks if this cips_data_analyzer object has an ; iTool already associated for it. ; -------------------------------------------------------------------------- function cips_data_analyzer::has_valid_itool_handle tool_ref = itgetcurrent() if (tool_ref ne '') then return, 1 return, 0 end ;-------------------------------------------------------------------------- ; HAS_DATA ; ; Purpose: checks if this object has data assigned to memory ; -------------------------------------------------------------------------- function cips_data_analyzer::has_data return, self.has_data end ;-------------------------------------------------------------------------- ; RESET ; -------------------------------------------------------------------------- pro cips_data_analyzer::reset, debug_help=debug_help print, 'Resetting CIPS Analyzer...' ; re-register any previously open panels with an 'empty panel'. ; the effect is that any prior panels won't be displayed. ; alternatively, ITReset could be used but besides being an ; expensive operation, it would need to be called before the ; prior analyzer was closed. if ptr_valid(self.cloud_panel) then begin str_free, *self.cloud_panel ITRegister, 'retrieved_cloud_panel', 'empty_panel', TYPES='CIPS', /UI_PANEL endif if ptr_valid(self.scenes_panel) then begin str_free, *self.scenes_panel ITRegister, 'scenes_panel', 'empty_panel', TYPES='CIPS', /UI_PANEL endif if ptr_valid(self.stack_panel) then begin str_free, *self.stack_panel ITRegister, 'stack_panel', 'empty_panel', TYPES='CIPS', /UI_PANEL endif if ptr_valid(self.notes) then str_free, *self.notes ptr_free, self.cloud_panel ptr_free, self.scenes_panel ptr_free, self.stack_panel ptr_free, self.notes COMMON CIPS_GLOBAL_STATE, cips_global_options delete_var, cips_global_options ; memory leak? if get_debug_level() gt 1 then begin curr_mem = memory(/current) / 1E6 if ~ptr_valid(self.mem_history) then begin self.mem_history = ptr_new(curr_mem) endif else begin *self.mem_history = [*self.mem_history, curr_mem] plot, *self.mem_history, title='CIPS Analyzer Memory Use', xtitle='iteration', ytitle='MB', $ xticks=1, min_value=0 n_history = n_elements(*self.mem_history) ; if memory leak, what?.... heap_gc doesn't pick up anything ; that's not already being released... the leak must be within iTools... ; handle via popup warning after 50MB? other release mechanisms? mem_leak = (*self.mem_history)[n_history-1] - (*self.mem_history)[0] print, 'mem_leak: ', mem_leak, ' MB' endelse endif self.has_data = 0 LOADCT, 39 end ;-------------------------------------------------------------------------- ; CLEANUP ; -------------------------------------------------------------------------- pro cips_data_analyzer::cleanup self->reset end ; -------------------------------------------------------------------------- ; Object Data Structure Definition ; -------------------------------------------------------------------------- pro cips_data_analyzer__define self = {cips_data_analyzer, $ has_data:0, $ mem_history:ptr_new(), $ cloud_panel:ptr_new(), $ scenes_panel:ptr_new(), $ stack_panel:ptr_new(), $ l1c_stack_panel:ptr_new(), $ notes:ptr_new()} return end