pro metis_l2_prep_uv ; keyword defining if the detector reference frame must be used for the output ref_detector = 0 ; start the log journal,'output/metis_l2_prep_log.txt' ; read the auxiliary file - here we have all the inputs we need input = json_parse('input/contents.json', /toarray, /tostruct) journal, 'File ' + file_basename(input.file_name) ; load the spice kernels load_spice_kernels, input.spice_kernels, kernel_list = kernel_list, kernel_version = kernel_version journal, 'SPICE kernel files correctly loaded:' journal, ' SDK version= ' + kernel_version ; read the calibration package index cal_pack = json_parse(input.cal_pack_path + '/index.json', /toarray, /tostruct) ; include the calibration package path into the cal_pack structure cal_pack = create_struct('path', input.cal_pack_path + path_sep(), cal_pack) journal, 'Calibration package correctly imported:' journal, ' version = ' + cal_pack.version journal, ' validity range = ' + string(cal_pack.validity_range.start, cal_pack.validity_range._end, format = '(A, "-", A)') ; read the primary hdu data = mrdfits(input.file_name, 0, primary_header, /silent) ; read the quality matrix quality_matrix = mrdfits(input.file_name, 'quality matrix', /silent) ; convert the string header into an idl structure header = fits_hdr2struct(primary_header) journal, 'L1 FITS file correctly read:' journal, ' datatype = ' + string(header.datatype, format = '(I0)') journal, ' sess_num = ' + header.sess_num journal, ' nbin = ' + string(sqrt(header.nbin), format = '(I0)') ; error is the quadratic relative error error = 0. ; calibration block case header.datatype of 1 : begin data = double(data) ; ==================================== ; for old l1 data ; data = data * header.nbin * header.ndit1 * header.ndit2 ; header.xposure = header.dit/1000. * header.ndit1 * header.ndit2 ; header.nsumexp = header.ndit1 * header.ndit2 ; ==================================== data = metis_dark_uvda(data, header, cal_pack, error = error, quality_matrix = quality_matrix, history = history) ; ==================================== ; for data already subtracted of dark ; file = file_basename(header.parent, '.fits') + '_subdark.fits' ; data = mrdfits('UV subdark/' + file, 0, /silent) ; data = rebin(data, header.naxis1, header.naxis2) ; data = data * header.nbin * header.ndit1 * header.ndit2 ; history = ['Dark correction: ', ' ' + file] ; ==================================== data = metis_flat_field(data, header, cal_pack, error = error, quality_matrix = quality_matrix, history = history) data = metis_vignetting(data, header, cal_pack, error = error, quality_matrix = quality_matrix, history = history) data = metis_rad_cal(data, header, cal_pack, error = error, quality_matrix = quality_matrix, history = history) ; ==================================== ; for simple radiometric calibration ; cal_pack.uv_channel.cal_units = 'DN/s' ; ==================================== ; ==================================== ; temporary correction based on alfa-leo data ; data = data * 3.4 ; history = [history, ' additional cal. factor from stars = 3.4'] ; ==================================== btype = 'UV Lyman-alpha intensity' bunit = cal_pack.uv_channel.cal_units end 4 : begin ; calibration of temporal noise images btype = 'UV temporal standard deviation' bunit = 'DN' history = !null end 6 : begin ; calibration of cr/sep log matrices btype = 'UV cosmic-ray matrix' bunit = 'DN' history = !null end else : begin journal, 'Error 01: wrong input data product (expected data types 1, 4, or 6).' journal exit, status = 1 end endcase ; definitions for the primary header ; version of the fits file version = string(input.l2_version, format = '(I02)') ; fits creation date date = date_conv(systime(/julian, /utc), 'FITS') ; name of the fits file file_name_fields = strsplit(header.filename, '_', /extract) file_name = 'solo_L2_' + file_name_fields[2] + '_' + file_name_fields[3] + '_V' + version + '.fits' out_file_name = 'output/' + file_name ; adjust the primary header fxaddpar, primary_header, 'FILENAME', file_name fxaddpar, primary_header, 'PARENT', file_basename(input.file_name) fxaddpar, primary_header, 'LEVEL', 'L2' fxaddpar, primary_header, 'CREATOR', 'metis_l2_prep_uv.pro' fxaddpar, primary_header, 'VERS_SW', input.sw_version fxaddpar, primary_header, 'VERS_CAL', cal_pack.version fxaddpar, primary_header, 'VERSION', version fxaddpar, primary_header, 'BTYPE', btype fxaddpar, primary_header, 'BUNIT', bunit fxaddpar, primary_header, 'DATAMIN', min(data, /nan) fxaddpar, primary_header, 'DATAMAX', max(data, /nan) fxaddpar, primary_header, 'WAVEBAND', cal_pack.uv_channel.name fxaddpar, primary_header, 'XPOSURE', header.xposure fxaddpar, primary_header, 'NSUMEXP', header.nsumexp sxdelpar, primary_header, 'BLANK' ; fix planning info keywords if header.soopname.startswith('unknown') then soopname = 'none' else soopname = header.soopname if header.obs_mode.startswith('unknown') then obs_mode = 'METIS_GENERIC_OBS' else obs_mode = header.obs_mode if soopname eq 'none' then sooptype = 'none' else sooptype = header.sooptype if obs_mode eq 'none' then obs_type = 'none' else obs_type = header.obs_type if soopname eq 'none' and obs_mode eq 'none' then obs_id = 'none' else obs_id = header.obs_id fxaddpar, primary_header, 'SOOPNAME', soopname fxaddpar, primary_header, 'SOOPTYPE', sooptype fxaddpar, primary_header, 'OBS_MODE', obs_mode fxaddpar, primary_header, 'OBS_TYPE', obs_type fxaddpar, primary_header, 'OBS_ID', obs_id ; append wcs keywords wcs = metis_wcs(header, cal_pack, ref_detector = ref_detector) foreach element, wcs do fxaddpar, primary_header, element.name, element.value, element.comment, before = 'DATATYPE' ; append solar ephemeris keywords ephemeris = solo_get_ephemeris(header, cal_pack) foreach element, ephemeris do fxaddpar, primary_header, element.name, element.value, element.comment, before = 'DATATYPE' history = [history, 'Update WCS and solar ephemeris:', ' SKD version = ' + kernel_version] ; update the comment and history keywords fxaddpar, primary_header, 'COMMENT', 'WARNING: UV radiometric calibration is still preliminary.' fxaddpar, primary_header, 'COMMENT', 'Uncertainty matrix in the FITS extension is preliminary.' if ref_detector then begin fxaddpar, primary_header, 'COMMENT', 'Flip vertically and rotate CROTA degrees counter-clockwise' fxaddpar, primary_header, 'COMMENT', ' to have Solar North up.' endif else $ fxaddpar, primary_header, 'COMMENT', 'Rotate CROTA degrees counter-clockwise to have Solar North up.' for k = 0, n_elements(history) - 1 do $ fxaddpar, primary_header, 'HISTORY', history[k] fxaddpar, primary_header, 'HISTORY', 'L2 FITS file created on ' + date if not ref_detector then data = metis_rectify(data, 'UV') fits_add_checksum, primary_header, data mwrfits, float(data), out_file_name, primary_header, /no_comment, /create, /silent journal, 'Fits file created:' journal, ' file name = ' + file_basename(out_file_name) ; add the extension with the quality matrix base_header = primary_header sxdelpar, base_header, 'SIMPLE' sxdelpar, base_header, 'EXTEND' sxdelpar, base_header, 'DATASUM' sxdelpar, base_header, 'CHECKSUM' sxdelpar, base_header, 'COMMENT' sxdelpar, base_header, 'HISTORY' extension_header = base_header fxaddpar, extension_header, 'PCOUNT', 0, 'parameter count', before = 'LONGSTRN' fxaddpar, extension_header, 'GCOUNT', 1, 'group count', before = 'LONGSTRN' fxaddpar, extension_header, 'EXTNAME', 'Quality matrix', 'extension name', before = 'LONGSTRN' fxaddpar, extension_header, 'BTYPE', 'Pixel quality' fxaddpar, extension_header, 'BUNIT', 'None' fxaddpar, extension_header, 'DATAMIN', min(quality_matrix, /nan) fxaddpar, extension_header, 'DATAMAX', max(quality_matrix, /nan) fxaddpar, extension_header, 'COMMENT', 'Quality matrix values:' fxaddpar, extension_header, 'COMMENT', ' NaN = saturated or null L0 pixel counts' fxaddpar, extension_header, 'COMMENT', ' 0 = unreliable pixel value' fxaddpar, extension_header, 'COMMENT', ' 1 = good pixel' if not ref_detector then quality_matrix = metis_rectify(quality_matrix, 'UV') fits_add_checksum, extension_header, quality_matrix mwrfits, float(quality_matrix), out_file_name, extension_header, /no_comment, /silent journal, 'Quality-matrix extension correctly added.' ; add the extension with the error matrix if not ref_detector then error = metis_rectify(error, 'UV') error_matrix = data * sqrt(error) extension_header = base_header fxaddpar, extension_header, 'PCOUNT', 0, 'parameter count', before = 'LONGSTRN' fxaddpar, extension_header, 'GCOUNT', 1, 'group count', before = 'LONGSTRN' fxaddpar, extension_header, 'EXTNAME', 'Error matrix', 'extension name', before = 'LONGSTRN' fxaddpar, extension_header, 'BTYPE', 'Absolute error' fxaddpar, extension_header, 'DATAMIN', min(error_matrix, /nan) fxaddpar, extension_header, 'DATAMAX', max(error_matrix, /nan) fits_add_checksum, extension_header, float(error_matrix) mwrfits, float(error_matrix), out_file_name, extension_header, /no_comment, /silent journal, 'Error-matrix extension correctly added.' ; write the auxiliary information file output = { $ file_name: out_file_name, $ l1_file_name: input.file_name, $ log_file_name: 'output/metis_l2_prep_log.txt' $ } json_write, output, 'output/contents.json' ; unload the spice kernels load_spice_kernels, kernel_list = kernel_list, /unload journal, 'SPICE kernel files unloaded.' ; close the log journal, 'Exiting without errors.' journal exit, status = 0 end