MESSENGER MASCS VIRS CDR TO DDR PROCEDURES Version 3, 3/20/2017 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, 6/15/12 Version submitted for PDS peer review. Version 2, 12/3/2013, C. Mauceri, ACT Revised and added calibration procedures. * batch_calibrate_virs_cdrs (revised) * init_mascs_cdr_templates_6 (revised, formerly init_mascs_tm_structs) * read_mascs_cdr_6 (revised, formerly read_mascs_cdr4) * virs_cdr2ddr_batch (revised) * create_virs_ddr (revised) * define_virs_common_data (added) * virs_bin_data (added) Version 3, 3/20/2017, C. Mauceri, ACT Revised and added calibration procedures. * create_virs_ddr (revised) * mascs_normalize_photometry (added) * mascs_normalize_photometry_ks (added) MASCS VIRS CDR to DDR pseudocode. This document describes high level "pseudocode" and tables which define the procedures used to convert MASCS VIRS Calibrated Data Records (CDRs) to 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_virs_cdrs - opens each of the kickoff files passed in ; cdr_files and runs the calibration algorithm on them. For each one it ; writes a bunch of files to the storage_path and then saves the ; filenames to the output cal_files variable. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * init_mascs_cdr_templates_6 - initializes data structure definitions ; for MASCS telemetry packets. This is one way to handle the data ; structures for MASCS. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * read_mascs_cdr_6 - 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. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * virs_cdr2ddr_batch - searches an incoming directory for files that ; contain paths to VIRS cdr files. Loads the cdr spectra and then turns ; them into reflectance and photometrically corrected reflectance ; spectra. The calibrated spectra and all other columns needed for the ; DDR are then written out to an ascii file for further processing into ; binary DDRs. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * create_virs_ddr - VIRS CDR to DDR calibration code. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * define_virs_common_data - define paths and common blocks. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * virs_bin_data - returns virs data binned ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * mascs_normalize_photometry - returns factor to apply to the data to ; normalize it to a phase angle of 90deg ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; * mascs_normalize_photometry_ks - produces a wavelength-dependent ; photometric adjustment in order to normalize a spectrum obtained at ; some arbitrary geometry to a specified common geometry. ;----------------------------------------------------------------------------- ;***************************************************************************** ; V I R S P R O C E D U R E S ;***************************************************************************** ;----------------------------------------------------------------------------- ; * batch_calibrate_virs_cdrs - opens each of the kickoff files passed in ; cdr_files and runs the calibration algorithm on them. For each one it ; writes a bunch of files to the storage_path and then saves the ; filenames to the output cal_files variable. ;----------------------------------------------------------------------------- pro batch_calibrate_virs_cdrs,detector,kickoff_files,kickoff_path,ddr_files ;this idl program will open each of the kickoff files passed in cdr_files ;and run the calibration algorithm on them. For each one it will write a bunch of ;files to the storage_path and then save the filenames to the ;output cal_files variable. ; 2013-10-30 GMH: define paths and common blocks with define_virs_common_data user = 'Holsclaw' user = 'ACT' define_virs_common_data,user=user print, 'running batch_calibrate_virs_cdrs\n' n_kickoff_files = n_elements(kickoff_files) for i=0,n_kickoff_files-1 do begin ;the kickoff files contain the complete path and filename to a given VIRS cdr. i_kickoff_file = kickoff_files[i] ;open and read the kickoff file. should be a pointer to a VIRS cdr print, 'opening kickoff file',i_kickoff_file the_cdr_file = '' openr,runit,i_kickoff_file,/get_lun readf,runit,the_cdr_file close,runit free_lun,runit ;delete the file from the old location this will allow IDL code to skip past kickoff files which cause it to fail. print, 'deleting kickoff file:',i_kickoff_file FILE_DELETE,i_kickoff_file file_check = FILE_TEST(the_cdr_file, /READ) print, 'file check is',file_check if file_check eq 1 then begin ;run the calibration routines on this cdr. write the intermediate files to the kickoff path create_virs_ddr,the_cdr_file,kickoff_path,ddr_files ;copy the cal files to the final path then delete them from kickoff path if detector eq 'vis' then det_path = 'virsvis_ddrs/' else det_path = 'virsnir_ddrs/' final_path = '/project/messenger/SOC/pipe/data/incoming/pipesoc/' + det_path n_files = n_elements(ddr_files) ii = 0 while ii lt n_files do begin file_i = ddr_files[ii] print, 'ddr file created:', file_i file_copy, file_i, final_path, /OVERWRITE print, 'drr to ',final_path file_delete, file_i ii = ii + 1 endwhile endif else begin print, 'cdr file not found:',the_cdr_file endelse endfor end ;----------------------------------------------------------------------------- ; * init_mascs_cdr_templates_6 - initializes data structure definitions ; for MASCS telemetry packets. This is one way to handle the data ; structures for MASCS. ;----------------------------------------------------------------------------- pro init_mascs_cdr_templates_6 ; 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.) ; v5 Re-named with a '5' on the end to make it easier to ; identify it as a MASCS CDR Reader v5 file. ; v6 SPARE_2 is now used: ORBIT_NUMBER, and renamed to '6'. 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 ORBIT_NUMBER:double(0) $ ; v5.1 Using up the last spare field. } 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 ;----------------------------------------------------------------------------- ; * read_mascs_cdr_6 - 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_6, 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. ; v6 mrl 7/14/13 Last UVVS spare field is now used, for ORBIT_NUMBER ; v6.1 mrl 11/9/13 Fixed an error in function name on line 98. ; ; 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_6 ; 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_6(theLUN) ; v6.1 added '_6' to function name, thanks Greg. endfor end isUVVSSci: begin for i = long(0), num_data -1 do begin result[i] = read_uvvs_cdr_sci_6(theLUN) endfor end isVISSCI: begin for i = long(0), num_data -1 do begin result[i] = read_virs_vis_cdr_6(theLUN) endfor end isNIRSci: begin for i = long(0), num_data -1 do begin result[i] = read_virs_nir_cdr_6(theLUN) endfor end else: print, 'second CASE statement got surprised' endcase free_lun, theLUN return, result end ;----------------------------------------------------------------------------- ; * virs_cdr2ddr_batch - searches an incoming directory for files that ; contain paths to VIRS cdr files. Loads the cdr spectra and then turns ; them into reflectance and photometrically corrected reflectance ; spectra. The calibrated spectra and all other columns needed for the ; DDR are then written out to an ascii file for further processing into ; binary DDRs. ;----------------------------------------------------------------------------- pro virs_cdr2ddr_batch ;this idl program will search an incoming directory for files that contain paths ;to VIRS cdr files. These cdr files will have the spectra loaded into IDL and then ;turned into reflectance and photometrically corrected reflectance spectra. ;The calibrated spectra and all other columns needed for the DDR will then be written out to ;an ascii file for further processing by PIPE into binary DDRs print, 'running virs_cdr2ddr_batch\n' ;look for the kickoff files here. kickoff_path = '/project/messenger/SOC/pipe/data/virs_ddrs/Storage/' ;find the kickoff files. they will contain the full path to the virs cdr ;Do VIRS VIS first print,'Processing VIRS VIS...' print, 'looking in ',kickoff_path kickoff_files=file_search(kickoff_path+'*.virsv',count=num_kickoff_files) print, 'num kickoff files ',num_kickoff_files if num_kickoff_files gt 0 then begin ;run the calibration routines on the VIS cdrs detector = 'vis' batch_calibrate_virs_cdrs,detector,kickoff_files,kickoff_path,ddr_files endif ;Do VIRS NIR next kickoff_path = '/project/messenger/SOC/pipe/data/virs_ddrs/Storage/' print, 'looking in ',kickoff_path kickoff_files=file_search(kickoff_path+'*.virsn',count=num_kickoff_files) print, 'Processing VIRS NIR next...' print, 'num kickoff files ',num_kickoff_files if num_kickoff_files gt 0 then begin ;run the calibration routines on the NIR cdrs detector = 'nir' batch_calibrate_virs_cdrs,detector,kickoff_files,kickoff_path,ddr_files endif exit end ;----------------------------------------------------------------------------- ; * create_virs_ddr - VIRS CDR to DDR calibration code. ;----------------------------------------------------------------------------- pro create_virs_ddr,the_cdr_file,kickoff_path,ddr_files,virs_ddr,output_type_binary=output_type_binary ,photom_test=photom_test, file_save=file_save ; ; Inputs: ; the_cdr_file: full path filename of CDR file to process ; kickoff_path: output path for DDR ASCII file ; Outputs: ; ddr_files: ; ;VIRS CDR to DDR calibration code, courtesy of Noam Izenberg. Adapted for automated use by Ray Espiritu ;May 8, 2012 ;try to be as independent of the detector as possible with the variable names ;VC = read_mascs_cdr3('THE_VIS_CDR_FILENAME') ;NC = read_mascs_cdr3('THE_NIR_CDR_FILENAME') ;VIRS DDR CALIBRATION SOFTWARE VERSION. This will be incremented as software gets updated ;1.0 initial revision from Noam's code. Ray Espiritu ;2013-10-18: Greg Holsclaw ; Overhaul of the code to fix errors and improve efficiency. ; Use of COMMON blocks to improve efficiency. ;2013-10-18: Greg Holsclaw ; Fixed error in the calculation of the binned solar spectrum. ;2013-10-30: Greg Holsclaw ; Changed format code for writing floating point values to the ASCII file to F (single precision) and E (double precision). This will preserve the ; precision of these values. This corrects an issue where not enough precision was used, resulting in an apparent quantization of the reflectance data. ;2014-04-15: Greg Holsclaw ; New invalid_value of 1.e32. ; Renamed several variables for clarity. ; Now invalid detector ranges are flowed from the CDR data, rather than identifying these pixels and forcing values to be invalid. ;2017-02-03: Greg Holsclaw ; Changed the photometric normalization of the VIS channel to a different algorithm. ; ; Thuillier solar irradiance ; COMMON VIRS_DDR, wlt, sunt ; ; VIS and NIR wavelength vector, full-resolution ; COMMON VIRS_WAVELENGTH, wlvis_before, wlvis_after, wlnir_before_and_after swversion = 1.0 ;invalid_value_current = 1.e32 ;invalid_value = invalid_value_current ;invalid_value = -2.^15 invalid_value = 1.e32 ;current = 1 au = 149597871.d ; km per astronomical unit ; ; Photometric normalization geometry ; inc_norm = 45. emis_norm = 45. phase_norm = 90. ; ; determine whether this is VIS or NIR ; visname = 'VIRSVC*.DAT' nirname = 'VIRSNC*.DAT' isVISSci = 3 isNIRSci = 4 justname = strupcase(file_basename(the_cdr_file)) if strmatch(justname, visname) then begin whichType = isVISSci num_pixels = 512 endif if strmatch(justname, nirname) then begin whichType = isNIRSci num_pixels = 256 endif if whichType eq 0 then begin print, 'ERROR! Could not match on filename', justname print, 'stopping with error!' stop endif ; ; read the file ; virs_cdr = read_mascs_cdr_6(the_cdr_file) n_records = n_elements(virs_cdr) ; ; CDR wavelength vector ; wl_virs = virs_cdr[0].channel_wavelengths wl_virs[ where( wl_virs eq invalid_value, /null ) ] = !values.f_nan ; ; get binning and windowing data ; binning = virs_cdr[0].binning start_pixel = virs_cdr[0].start_pixel end_pixel = virs_cdr[0].end_pixel num_binned_pixels = floor( (end_pixel - start_pixel + 1) / binning ) ; ; identify indices of valid and invalid detector regions ; ;v = bytarr(num_pixels) ;v[0:num_binned_pixels-1] = 1 ;ndx_valid = where( v eq 1, count_valid, complement=ndx_invalid, ncomplement=count_invalid, /null ) ; ; replace pixels outside windowed region to NaN ; ;wl_virs[ndx_invalid] = !values.f_nan ; ; search for a defined invalid value and, if found, replace with NaN. ; cal_rad_spectra = virs_cdr.calibrated_radiance_spectrum_data corr_counts_spectra = virs_cdr.corrected_counts_spectrum_data cal_rad_spectra[ where( cal_rad_spectra eq invalid_value, /null ) ] = !values.f_nan corr_counts_spectra[ where( corr_counts_spectra eq invalid_value, /null ) ] = !values.f_nan ;virs_noise = (virs_cdr.NOISE_SPECTRUM_DATA / corr_counts_spectra) * cal_rad_spectra cal_rad_spectra_err = (virs_cdr.NOISE_SPECTRUM_DATA / corr_counts_spectra) * cal_rad_spectra ; ; ensure that detector regions outside the window are set to NaN for the calibrated, corrected counts, and noise arrays ; ;cal_rad_spectra[ ndx_invalid, * ] = !values.f_nan ;corr_counts_spectra[ ndx_invalid, * ] = !values.f_nan ;virs_noise[ ndx_invalid, * ] = !values.f_nan ; ; Thuillier solar irradiance spectrum is available through the common block and consists of variables: wlt, sunt ; interpolate to higher resolution 0.2nm vector ; stepsize = 0.2 wli = findgen((2500-200)/stepsize)*stepsize + 200. sunti = interpol( sunt, wlt, wli ) ; ; define boxcar smoothing width for a full-resolution wavelength vector ; case whichType of isVISSci: sm = 3.2 / stepsize isNIRSci: sm = 4.2 / stepsize endcase ; ; for a binning of 1, we can just use the CDR wavelength vector ; for a binning of 2, we need the full resolution wavelength vector, which is not contained in the CDR file ; Read in the appropriate wavelength vector ; Smooth the solar irradiance, interpolate to the full resolution vector, then bin by 2 ; case binning of 1: irrsuns = interpol( smooth(sunti,sm,/edge_truncate), wli, wl_virs ) 2: begin case whichType of isVISSci: begin temp = strsplit( file_basename(the_cdr_file), '_', /extract ) year = '20'+strmid(temp[2],0,2) doy = strmid(temp[2],2,3) date_int = long( year + doy ) if date_int lt 2011244 then begin wlvirs = wlvis_before endif else begin wlvirs = wlvis_after endelse end isNIRSci: begin wlvirs = wlnir_before_and_after end endcase irrsuns_nobin = interpol( smooth(sunti,sm,/edge_truncate), wli, wlvirs ) virs_bin_data, start_pixel, end_pixel, binning, irrsuns_nobin, irrsuns_bin ; ; the binned version of wlvirs (the full-resolution wavelength vector) should be identical to the wavelength vector from the CDR file (wl_virs) ; ;virs_bin_data, start_pixel, end_pixel, binning, wlvirs, wlvirs_bin ;wl_diff = wlvirs_bin - wl_virs[0:num_binned_pixels-1] ;n = where( wl_diff gt 0.001, countn ) ;if countn gt 0 then stop irrsuns = irrsuns_bin ;irrsuns[ndx_invalid] = !values.f_nan end endcase ; ; calculate reflectance (I/F) and photometrically normalized reflectance ; iof = cal_rad_spectra iof_err = cal_rad_spectra_err photom_iof = iof photom_iof_err = iof_err wave = wl_virs[0:num_binned_pixels-1] for i = 0L, n_records - 1 do begin iof[0:num_binned_pixels-1,i] = cal_rad_spectra[0:num_binned_pixels-1,i] / ( irrsuns[0:num_binned_pixels-1] / !pi / (virs_cdr[i].solar_distance/au)^2) iof_err[0:num_binned_pixels-1,i] = cal_rad_spectra_err[0:num_binned_pixels-1,i] / ( irrsuns[0:num_binned_pixels-1] / !pi / (virs_cdr[i].solar_distance/au)^2) ; ; 2017-02-03: New photometric normalization algorithm. GMH. ; inc = virs_cdr[i].INCIDENCE_ANGLE emis = virs_cdr[i].EMISSION_ANGLE phase = virs_cdr[i].PHASE_ANGLE case whichType of isVISSci: begin mascs_normalize_photometry_ks, wave, inc, emis, phase, fac, $ inc_norm=inc_norm, emis_norm=emis_norm, phase_norm=phase_norm end isNIRSci: begin mascs_normalize_photometry, inc, emis, phase, fac, $ inc_norm=inc_norm, emis_norm=emis_norm, phase_norm=phase_norm end endcase ; ; if the photometry test, use the old algorithm ; ; if keyword_set(photom_test) then begin ; mascs_normalize_photometry, inc, emis, phase, fac, $ ; inc_norm=inc_norm, emis_norm=emis_norm, phase_norm=phase_norm ; endif ; photom_iof[0:num_binned_pixels-1,i] = iof[0:num_binned_pixels-1,i] * fac photom_iof_err[0:num_binned_pixels-1,i] = iof_err[0:num_binned_pixels-1,i] * fac endfor ;!p.multi=[0,1,5] ;window,1 ;k = 20 ;plot, wl_virs, cal_rad_spectra[*,k], yr=[0,max(cal_rad_spectra[*,k],/nan)], xr=[200,400] ;plot, wl_virs, irrsuns ;plot, wl_virs, reflectance[*,k] ;plot, wlvirs, irrsuns_nobin ;plot, wl_virs, virs_cdr[10].CORRECTED_COUNTS_SPECTRUM_DATA ;!p.multi=0 ; ;window,2 ;plot, wl_virs, virs_cdr[k].CORRECTED_COUNTS_SPECTRUM_DATA, yr=[-10,1000] ; ;stop ; ; replace NaNs with invalid value ; iof[ where( finite(iof) eq 0, /null ) ] = invalid_value iof_err[ where( finite(iof_err) eq 0, /null ) ] = invalid_value photom_iof[ where( finite(photom_iof) eq 0, /null ) ] = invalid_value photom_iof_err[ where( finite(photom_iof_err) eq 0, /null ) ] = invalid_value wl_virs[ where( finite(wl_virs) eq 0, /null ) ] = invalid_value ;initialize spare variables spare1 = 0 spare2 = 0 spare3 = 0 spare4 = 0 spare5 = 0 ;write variables to an output ascii file cdr_filename = strupcase(file_basename(the_cdr_file)) ;NOTE: this assumes the CDR filename convention is fixed. If it changes then this may also need to be changed! cdr_basename = STRMID(cdr_filename,0,24) ; ; if this keyword is specified, export the data to an IDL save file ; ;if keyword_set(file_save) then begin ; save,filename=fsave,wl_virs,the_cdr_file,IOF,PHOTOM_IOF,PHOTOM_IOF_ERR ;,fac ;endif if keyword_set(output_type_binary) eq 0 then begin ; ddrascii_file = cdr_basename + 'ddr' ddrascii_fname = kickoff_path+ddrascii_file ; ; 2013-10-30 GMH - set floating point format code to 'E'. The default width and digits when unspecified are 15.7 for single precision float and 25.16 for double precision float. This will retain the precision of these values in the ASCII file. ; case whichType of isVISSci: outformat = '(I12,",",4(I5,","),E,",",4(i5,","),i12,",",i5,",",a17,",",512(E,:,","),512(E,:,","),512(E,:,","),512(E,:,","),f6.2,",",512(E,:,","),a19,",",15(E,:,","),E,",",5(i5,:,","))' isNIRSci: outformat = '(I12,",",4(I5,","),E,",",4(i5,","),i12,",",i5,",",a17,",",256(E,:,","),256(E,:,","),256(E,:,","),256(E,:,","),f6.2,",",256(E,:,","),a19,",",15(E,:,","),E,",",5(i5,:,","))' endcase ;print, 'writing to ',ddrascii_fname openw,wunit,ddrascii_fname,/get_lun ;need to print a header line because PIPE expects it header = 'csv file header' printf, wunit, header for i = 0, n_records - 1 do begin ; ;extract the other info from the VIRS CDR. This will be passed through to the VIRS DDR ; sc_time = virs_cdr[i].SC_TIME ; pkt_subsec = virs_cdr[i].PACKET_SUBSECONDS ; int_time = virs_cdr[i].INT_TIME ; int_count = virs_cdr[i].INT_COUNT ; dark_freq = virs_cdr[i].DARK_FREQ ; temp_2 = virs_cdr[i].TEMP_2 ; binning = virs_cdr[i].BINNING ; start_pix = virs_cdr[i].START_PIXEL ; end_pix = virs_cdr[i].END_PIXEL ; spec_num = virs_cdr[i].SPECTRUM_NUMBER ; spec_met = virs_cdr[i].SPECTRUM_MET ; spec_subsec= virs_cdr[i].SPECTRUM_SUBSECONDS ; temp = virs_cdr[i].SPECTRUM_UTC_TIME ; spec_utc = string(temp) ; ch_wl = virs_cdr[i].CHANNEL_WAVELENGTHS ; dqitemp = virs_cdr[i].DATA_QUALITY_INDEX ; dqi = string(dqitemp) ; lat_set = virs_cdr[i].TARGET_LATITUDE_SET ; lon_set = virs_cdr[i].TARGET_LONGITUDE_SET ; along_fp = virs_cdr[i].ALONG_TRACK_FOOTPRINT_SIZE ; across_fp = virs_cdr[i].ACROSS_TRACK_FOOTPRINT_SIZE ; ; printf,wunit, sc_time, pkt_subsec, int_time, int_count, dark_freq, temp_2, $ ; binning, start_pix, end_pix, spec_num, spec_met, spec_subsec, $ ; spec_utc, $ ; reflectance[*,i], photom_iof[*,i], noise[*,i], photom_iof_noise[*,i], $ ; swversion, ch_wl[*,0], dqi, lat_set, lon_set, $ ; along_fp, across_fp, incang[i], emiang[i], phaang[i], virs_cdr[i].solar_distance, $ ; spare1, spare2, spare3, spare4, spare5, format=outformat printf,wunit, $ virs_cdr[i].SC_TIME, $ virs_cdr[i].PACKET_SUBSECONDS, $ virs_cdr[i].INT_TIME, $ virs_cdr[i].INT_COUNT, $ virs_cdr[i].DARK_FREQ, $ virs_cdr[i].TEMP_2, $ virs_cdr[i].BINNING, $ virs_cdr[i].START_PIXEL, $ virs_cdr[i].END_PIXEL, $ virs_cdr[i].SPECTRUM_NUMBER, $ virs_cdr[i].SPECTRUM_MET, $ virs_cdr[i].SPECTRUM_SUBSECONDS, $ strtrim(virs_cdr[i].SPECTRUM_UTC_TIME,2), $ iof[*,i], $ photom_iof[*,i], $ iof_err[*,i], $ photom_iof_err[*,i], $ swversion,$ ; virs_cdr[i].CHANNEL_WAVELENGTHS, $ wl_virs, $ string(virs_cdr[i].DATA_QUALITY_INDEX), $ virs_cdr[i].TARGET_LATITUDE_SET, $ virs_cdr[i].TARGET_LONGITUDE_SET, $ virs_cdr[i].ALONG_TRACK_FOOTPRINT_SIZE, $ virs_cdr[i].ACROSS_TRACK_FOOTPRINT_SIZE, $ virs_cdr[i].INCIDENCE_ANGLE, $ virs_cdr[i].EMISSION_ANGLE, $ virs_cdr[i].PHASE_ANGLE, $ virs_cdr[i].solar_distance, $ spare1, $ spare2, $ spare3, $ spare4, $ spare5, $ format=outformat endfor close,wunit free_lun,wunit ddr_files = ddrascii_fname endif else begin ;*********************************************************************************************************** ; WRITE DATA TO BINARY FILE ;*********************************************************************************************************** init_mascs_ddr_templates case whichType of isVISSci: virs_ddr = replicate( {virs_vis_ddr},n_records) isNIRSci: virs_ddr = replicate( {virs_nir_ddr},n_records) endcase struct_assign, virs_cdr, virs_ddr virs_ddr.IOF_SPECTRUM_DATA = iof virs_ddr.IOF_NOISE_SPECTRUM_DATA = iof_err virs_ddr.PHOTOM_IOF_SPECTRUM_DATA = photom_iof virs_ddr.PHOTOM_IOF_NOISE_SPECTRUM_DATA = photom_iof_err ;f_ddr_base = file_basename(the_cdr_file) ;strput, f_ddr_base, 'D', strpos( file_basename(the_cdr_file), 'C' ) ;f_ddr = kickoff_path + f_ddr_base[0] ;write_mascs_ddr, f_ddr, virs_ddr ;ddr_files = f_ddr endelse ;print,'going back to calling script' end ;;*********************************************************************************************************** ;; WRITE DATA TO BINARY FILE ;;*********************************************************************************************************** ;init_mascs_ddr_templates ;case whichType of ;isVISSci: virs_ddr = replicate( {virs_vis_ddr},n_records) ;isNIRSci: virs_ddr = replicate( {virs_nir_ddr},n_records) ;endcase ;struct_assign, virs_cdr, virs_ddr ;virs_ddr.IOF_SPECTRUM_DATA = reflectance ;virs_ddr.PHOTOM_IOF_SPECTRUM_DATA = photom_iof ;virs_ddr.IOF_NOISE_SPECTRUM_DATA = noise ;virs_ddr.PHOTOM_IOF_NOISE_SPECTRUM_DATA = photom_iof_noise ;f_ddr_base = file_basename(the_cdr_file) ;strput, f_ddr_base, 'D', strpos( file_basename(the_cdr_file), 'C' ) ;f_ddr = kickoff_path + f_ddr_base[0] ;write_mascs_ddr, f_ddr, virs_ddr ;print,'going back to calling script' end ;----------------------------------------------------------------------------- ; * define_virs_common_data - define paths and common blocks. ;----------------------------------------------------------------------------- pro define_virs_common_data, user=user COMMON VIRS_FILENAMES, $ lab_sen_file, $ filename_vis_wavelength_2011_09_01_before, $ filename_vis_wavelength_2011_09_01_after, $ place, $ mission_phase_hk_path, $ BinnedSatTemps, $ filename_vis_noise_poly, $ filename_nir_noise_poly, $ polyfit_error_file_path, $ TempCorFile_VIS, $ TempCorFile_NIR, $ filename_solar_irradiance ;user = 'ACT' ;user = 'Klima' ;user = 'Holsclaw' ; ; set up required file paths ; case user of 'ACT': begin ;hardcode the path to the virs sensitivity file for now coreDir='/project/messenger/SOC/pipe/data/cdr_rdr_execs/mascs_idl/updated_virs/' lab_sen_file = coreDir + 'MASCS_VIRS_sensitivity.sav' filename_vis_wavelength_2011_09_01_before = coreDir + 'vis_wavelength_2011_09_01_before.sav' filename_vis_wavelength_2011_09_01_after = coreDir + 'vis_wavelength_2011_09_01_after.sav' ;place = strpos(the_edr_file,'mascs_volume_archive') ;mission_phase_hk_path = strmid(the_edr_file,0,place+29) BinnedSatTemps = coreDir + 'ir_binned_sat.csv' filename_vis_noise_poly = coreDir + 'vis_noise_poly.sav' filename_nir_noise_poly = coreDir + 'ir_noise_poly.sav' polyfit_error_file_path = '/project/messenger/SOC/pipe/data/virs_cdr/' TempCorFile_VIS = coreDir + 'VIS_Temp_Coeffs_base21.txt' TempCorFile_NIR = coreDir + 'NIR_Temp_Coeffs_base22.txt' filename_solar_irradiance = 'ThuillierReference.txt' end 'Klima': begin BinnedSatTemps = '/Users/klimarl1/Research/IDL_Programs/latest_set/ir_binned_sat.csv' filename_vis_noise_poly = '/Users/klimarl1/Research/IDL_Programs/latest_set/Vis_Noise_poly.sav' filename_nir_noise_poly = '/Users/klimarl1/Research/IDL_Programs/latest_set/ir_noise_poly.sav' polyfit_error_file_path = '/users/klimarl1/Desktop/' TempCorDir='/Users/klimarl1/Research/IDL_Programs/latest_set/' end 'Holsclaw': begin ;temp = get_login_info() ;if strmatch(temp.user_name,'holsclaw') then begin lab_sen_file = '/Users/holsclaw/MESSENGER/analysis/ACT_IDL_CODE/virs_cdr/MASCS_VIRS_sensitivity.sav' filename_vis_wavelength_2011_09_01_before = '/Users/holsclaw/MESSENGER/VIRS_data_save_files/wavelength_scale/vis_wavelength_2011_09_01_before.sav' filename_vis_wavelength_2011_09_01_after = '/Users/holsclaw/MESSENGER/VIRS_data_save_files/wavelength_scale/vis_wavelength_2011_09_01_after.sav' mission_phase_hk_path = '/Users/holsclaw/MESSENGER/wget/bronte.jhuapl.edu/edr_products/mascs/housekeeping/' BinnedSatTemps='/Users/holsclaw/MESSENGER/analysis/ACT_IDL_CODE/virs_cdr/ir_binned_sat.csv' filename_vis_noise_poly = '/Users/holsclaw/MESSENGER/analysis/ACT_IDL_CODE/virs_cdr/vis_noise_poly.sav' filename_nir_noise_poly = '/Users/holsclaw/MESSENGER/analysis/ACT_IDL_CODE/virs_cdr/ir_noise_poly.sav' polyfit_error_file_path = '/users/holsclaw/desktop/IDL_temp/' TempCorFile_VIS = '/Users/holsclaw/MESSENGER/analysis/ACT_IDL_CODE/virs_cdr/VIS_Temp_Coeffs_base21.txt' TempCorFile_NIR = '/Users/holsclaw/MESSENGER/analysis/ACT_IDL_CODE/virs_cdr/NIR_Temp_Coeffs_base22.txt' filename_solar_irradiance = '/Users/holsclaw/data_resources/Sun/Thuillier/ThuillierReference.txt' end else: begin print, 'unknown user' stop end endcase COMMON VIRS_WAVELENGTH, wlvis_before, wlvis_after, wlnir_before_and_after restore,filename_vis_wavelength_2011_09_01_before wlvis_before = wlvis restore,filename_vis_wavelength_2011_09_01_after wlvis_after = wlvis COMMON VIRS_SENSITIVITY, wlvis_lab, wlnir_lab, visr, nirr, visr_sdev, nirr_sdev, wls, rs ; wlvis, wlnir, visr, nirr, visr_sdev, nirr_sdev ;lab_sen_file = '/Users/holsclaw/MESSENGER/analysis/ACT_IDL_CODE/virs_cdr/MASCS_VIRS_sensitivity.sav' restore,lab_sen_file wlvis_lab = wlvis wlnir_lab = wlnir wlnir_before_and_after = wlnir ; wls, rs restore,file_dirname(lab_sen_file)+'/'+'VIRS_white_screen_reflectance.sav' COMMON HK_VIRS, file_list_hk, file_list_hk_basename ;file_list_hk = file_search( mission_phase_hk_path, '*.DAT' ) ;file_list_hk_basename = file_Basename(file_list_hk) COMMON VIRS_DDR, wlt, sunt d = (read_ascii(filename_solar_irradiance,data_start=1)).(0) wlt = reform(d[1,*]) sunt = reform(d[2,*]) * 1000. ; W/m^2/micron end ;----------------------------------------------------------------------------- ; * virs_bin_data - returns virs data binned ;----------------------------------------------------------------------------- pro virs_bin_data, start_pixel, end_pixel, binning, arr, arr_bin ; purpose: ; this routine will bin a vector or an array in the first (spectral) dimension assuming it is organized by [pixels,readouts] ; inputs: ; start_pixel - first pixel (zero-based) in window ; end_pixel - end pixel in window ; binning - binning value (exa: if 1, no binning; if 2; every 2 adjacent pixels are averaged) ; arr - input vector or array ; outputs: ; arr_bin - binned vector or array ; ; Version History: ; CREATED: 10/10/2013 GMH ; nrows = n_elements(arr[0,*]) num_binned_pixels = floor( (end_pixel - start_pixel + 1) / binning ) arr_bin = fltarr(num_binned_pixels,nrows) arr_bin[0:num_binned_pixels-1,*] = rebin( arr[ start_pixel : num_binned_pixels*binning-1 + start_pixel, *], num_binned_pixels, nrows ) end ;----------------------------------------------------------------------------- ; * mascs_normalize_photometry - returns factor to apply to the data to ; normalize it to a phase angle of 90deg ;----------------------------------------------------------------------------- ; 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 ;----------------------------------------------------------------------------- ; * mascs_normalize_photometry_ks - produces a wavelength-dependent ; photometric adjustment in order to normalize a spectrum obtained at ; some arbitrary geometry to a specified common geometry. ;----------------------------------------------------------------------------- ;+ ; Purpose: ; This routine produces a wavelength-dependent photometric adjustment in order ; to normalize (or "correct") a spectrum obtained at some arbitrary geometry ; to a specified common geometry. "KS" refers to the Kaasalainen-Shkuratov ; photometric model. ; ; Inputs: ; wave: wavelength of the observed spectrum in nanometers. ; inc: Incidence angle of the observation, degrees. ; emis: Emission angle of the observation, degrees. ; phase: Phase angle of the observation, degrees. ; ; Output: ; fac: The wavelength-dependent factor to apply to the data in order to adjust ; it to the normalization geometry. ; rs: Reflectance model at the standard (normalized) geometry. ; ro: Reflectance model at the observation geometry. ; ; Optional keyword inputs: ; inc_norm: Incidence angle of the normalized data, default is 45deg ; emis_norm: Emission angle of the normalized data, default is 45deg ; phase_norm: Phase angle of the normalized data, default is 90deg ; ; Notes: ; This algorithm was developed by Deborah Domingue in Jan, 2017. ;- pro mascs_normalize_photometry_ks, wave, inc, emis, phase, fac, rs, ro, $ 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. if n_params() eq 0 then begin wave = findgen(512)*2.33+200. inc = 30. emis = 60. phase = 120. endif incrad=inc*3.1415927/180.0 emsrad=emis*3.1415927/180.0 pharad=phase*3.1415927/180.0 cinc=inc_norm*3.1415927/180.0 cems=emis_norm*3.1415927/180.0 cpha=phase_norm*3.1415927/180.0 ; normal albedo a3a=double(7.733671331625e-10) a2a=double(-1.572053767872e-6) a1a=double(1.166651403367e-3) a0a=double(-1.853844104344e-1) ; surface roughness a4nu=double(1.043254596338e-11) a3nu=double(-2.499826739546e-8) a2nu=double(2.14764930037e-5) a1nu=double(-7.857207746864e-3) a0nu=double(1.538720601082) ; partition parameter a4cl=double(-6.200027666114e-12) a3cl=double(1.524282813852e-8) a2cl=double(-1.360387213932e-5) a1cl=double(5.119265226434e-3) a0cl=double(-3.24794175193e-1) an=(a3a*wave^3)+(a2a*wave^2)+(a1a*wave)+a0a nu=(a4nu*wave^4)+(a3nu*wave^3)+(a2nu*wave^2)+(a1nu*wave)+a0nu cl=(a4cl*wave^4)+(a3cl*wave^3)+(a2cl*wave^2)+(a1cl*wave)+a0cl ; ; calcs for standardization geometry ; expnu=exp(-1.0*cpha*nu) phasefunc=an*expnu dls=(2.0*cos(cinc)/(cos(cinc)+cos(cems))) dlsl=cl*dls+(1.0-cl)*cos(cinc) rs=phasefunc*dlsl ; ; calcs for observation geometry ; expnu=exp(-1.0*pharad*nu) phasefunc=an*expnu dls=(2.0*cos(incrad)/(cos(incrad)+cos(emsrad))) dlsl=cl*dls+(1.0-cl)*cos(incrad) ro=phasefunc*dlsl ; ; standardization factor ; cfact=rs/ro ; ; standardized reflection value ; ;corrected_ref=cfact*ref fac = cfact end