Newer
Older
pro metis_l1_prep
; start the log
journal,'output/metis_l1_prep_log.txt'
; some definitions
metis_datatype = list( $
'vl-image', $ ; 0
'uv-image', $ ; 1
'pcu-accumul', $ ; 2
'vl-temp-matrix', $ ; 3
'uv-temp-matrix', $ ; 4
'vl-c-ray-mat', $ ; 5
'uv-c-ray-mat', $ ; 6
'pcu-event-list', $ ; 7
'pcu-test-event-list', $ ; 8
'light-curve' $ ; 9
)
metis_obj_size = list( $
2048L, $ ; 0
1024L, $ ; 1
1024L, $ ; 2
2048L, $ ; 3
1024L, $ ; 4
2048L, $ ; 5
1024L $ ; 6
)
input = json_parse('input/contents.json', /toarray, /tostruct)
; prepare the spice kernels
kernels = [ $
input.tls_file_name, $
input.tsc_file_name $
]
; load the spice kernels
cspice_furnsh, kernels
; read l0 fits structure
fits_info, input.file_name, n_ext = n_ext, extname = extname, /silent
image = mrdfits(input.file_name, ext_no, primary_header, /silent)
; if the data is not an image, read the data binary-table extension
if fxpar(primary_header, 'NAXIS') eq 0 then begin
ext_no += 1
data_bin_table = mrdfits(input.file_name, ext_no, data_extension_header, /silent)
endif else data_bin_table = !null
; read the metadata extension
ext_no += 1
metadata_bin_table = mrdfits(input.file_name, ext_no, metadata_extension_header, /silent)
; identify the data product and its nominal size
datatype = fxpar(metadata_extension_header, 'DATATYPE')
if datatype le 6 then begin
naxis = 2
naxis1 = metis_obj_size[datatype]
naxis2 = naxis1
bitpix = 16
data_size = naxis1 * naxis2
data_volume = (data_size * bitpix) / 8.
endif else begin
naxis = 0
bitpix = 8
data_size = 0
data_volume = 0
endelse
; if the data product is an accumulation matrix, look for the accumulation vector extension and read it if it exists
if datatype eq 2 then begin
if fxpar(metadata_extension_header, 'M') eq 256 then begin
ext_no += 1
accumul_vector = mrdfits(input.file_name, ext_no, vector_extension_header, /silent)
endif else accumul_vector = !null
endif
; NOTE - the radialization extension is ignored
; read the planning data
planning_data = json_parse(input.planning_file_name, /toarray, /tostruct)
; definitions for the primary header
; version of the fits file
version = string(input.l1_version + 1, format = '(I02)')
; creation and acquisition times in utc
obt_beg = fxpar(primary_header, 'OBT_BEG')
obt_end = fxpar(primary_header, 'OBT_END')
obt_avg = (obt_beg + obt_end) / 2.0D
date_beg = solo_obt2utc(decode_obt(obt_beg, /from_double))
date_end = solo_obt2utc(decode_obt(obt_end, /from_double))
date_avg = solo_obt2utc(decode_obt(obt_avg, /from_double))
date_beg_string = strreplace(strreplace(strmid(date_beg, 0, 19), '-', ''), ':', '')
; name of the fits file
file_name_fields = strsplit(fxpar(primary_header, 'FILENAME'), '_', /extract)
file_name = 'solo_l1_' + file_name_fields[2] + '_' + date_beg_string + '_v' + version + '.fits'
out_file_name = 'output/' + file_name
; exposure times
dit = fxpar(metadata_extension_header, 'DIT')
telapse = obt_end - obt_beg
xposure = dit/1000.
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
; instrument keywords
; TODO - complete with filter information
if datatype eq 0 or datatype eq 3 or datatype eq 5 or datatype eq 9 then begin
filter = 'VL'
wavelnth = 0.0
wavemin = 0.0
wavemax = 0.0
waveband = 'Visible light 580-640 nm'
endif else begin
filter = 'UV'
wavelnth = 1215.67
wavemin = 0.0
wavemax = 0.0
waveband = 'H I Lyman-alpha 121.6 nm'
endelse
detector = filter + 'DA'
telescope = 'SOLO/Metis/' + detector
; campaign keywords
obs_id_fields = strsplit(planning_data.obs_id, '_', /extract)
soop_type = obs_id_fields[2]
obs_type = obs_id_fields[4]
; build the fits file extensions
; join the metadata extension header to the primary header removing unwanted keywords
j = where(strmid(metadata_extension_header, 0, 8) eq 'EXTNAME ')
k = where(strmid(metadata_extension_header, 0, 8) eq 'TFORM1 ')
primary_header[0 : i - 1], $
metadata_extension_header[j + 1 : k - 1], $
primary_header[i : *] $
]
; adjust the primary header (it is almost the same for all data product types)
fxaddpar, primary_header, 'PARENT', file_basename(input.file_name), 'Name of the parent file that got processed to the current one', before = 'APID'
fxaddpar, primary_header, 'DATE', date, 'Date and time of FITS file creation', before = 'OBT_BEG'
fxaddpar, primary_header, 'DATE-OBS', date_beg, 'Same as DATE-BEG', before = 'OBT_BEG'
fxaddpar, primary_header, 'DATE-BEG', date_beg, 'Start time of observation', before = 'OBT_BEG'
fxaddpar, primary_header, 'DATE-AVG', date_avg, 'Average time of observation', before = 'OBT_BEG'
fxaddpar, primary_header, 'DATE-END', date_end, 'End time of observation', before = 'OBT_BEG'
fxaddpar, primary_header, 'TIMESYS', 'UTC', 'System used for time keywords', before = 'OBT_BEG'
fxaddpar, primary_header, 'TIMRDER', 0.0, 'Estimated random error in time values', before = 'OBT_BEG'
fxaddpar, primary_header, 'TIMSYER', 0.0, 'Estimated systematic error in time values', before = 'OBT_BEG'
fxaddpar, primary_header, 'LEVEL', 'L1'
fxaddpar, primary_header, 'CREATOR', 'metis_l1_prep.pro'
fxaddpar, primary_header, 'OBSRVTRY', 'Solar Orbiter', 'Satellite name', before = 'INSTRUME'
fxaddpar, primary_header, 'TELESCOP', telescope, 'Telescope that took the measurement', before = 'INSTRUME'
fxaddpar, primary_header, 'DETECTOR', detector, 'Subunit/sensor', before = 'DATAMIN'
fxaddpar, primary_header, 'OBJECT', 'TBD', 'The use of the keyword OBJECT is [TBD]', before = 'DATAMIN'
fxaddpar, primary_header, 'OBS_MODE', planning_data.obs_mode, 'Observation mode or study that has been used to acquire this image', before = 'DATAMIN'
fxaddpar, primary_header, 'OBS_TYPE', obs_type, 'Subfield of OBS_ID that only contains an encoded version of OBS_MODE', before = 'DATAMIN'
fxaddpar, primary_header, 'FILTER', filter, 'Filter used to acquire this image', before = 'DATAMIN'
fxaddpar, primary_header, 'WAVELNTH', wavelnth, 'Characteristic wavelength at which the observation was taken', before = 'DATAMIN'
fxaddpar, primary_header, 'WAVEMIN', wavemin, 'The shortest wavelength at which the net (approximate) response function becomes 0.05 times the maximum response. ', before = 'DATAMIN'
fxaddpar, primary_header, 'WAVEMAX', wavemax, 'The longest wavelength at which the net (approximate) response function becomes 0.05 times the maximum response', before = 'DATAMIN'
fxaddpar, primary_header, 'WAVEBAND', waveband, 'Description of the wavelength band', before = 'DATAMIN'
fxaddpar, primary_header, 'XPOSURE', xposure, 'Total effective exposure time of the observation, in seconds', before = 'DATAMIN'
fxaddpar, primary_header, 'NSUMEXP', 1, 'Number of images summed together to form the observation', before = 'DATAMIN'
fxaddpar, primary_header, 'TELAPSE', telapse, 'Total elapsed time between the beginning and end of the complete observation in seconds, including any dead times between exposures', before = 'DATAMIN'
fxaddpar, primary_header, 'SOOPNAME', planning_data.soop_name, 'SOOP(s) that this observation belongs to', before = 'DATAMIN'
fxaddpar, primary_header, 'SOOPTYPE', soop_type, before = 'DATAMIN'
fxaddpar, primary_header, 'OBS_ID', planning_data.obs_id, 'Unique identifier for the observation that is associated with the data acquisition', before = 'DATAMIN'
fxaddpar, primary_header, 'TARGET', 'TBD', 'Taget as defined in the SOOP description', before = 'DATAMIN'
fxaddpar, primary_header, 'BSCALE', 1.0, before = 'DATAMIN'
fxaddpar, primary_header, 'BZERO', 0, before = 'DATAMIN'
fxaddpar, primary_header, 'BTYPE', strupcase(metis_datatype[datatype]), 'Science data object type', before = 'DATAMIN'
fxaddpar, primary_header, 'BUNIT', 'DN', 'Units of physical value, after application of BSCALE and BZERO', before = 'DATAMIN'
if datatype le 6 then begin
fxaddpar, primary_header, 'PXBEG1', 1, 'First pixel that has been read out in dimension 1', before = 'COMPRESS'
fxaddpar, primary_header, 'PXBEG2', 1, 'First pixel that has been read out in dimension 2', before = 'COMPRESS'
fxaddpar, primary_header, 'PXEND1', naxis1, 'Last pixel that has been read out in dimension 1', before = 'COMPRESS'
fxaddpar, primary_header, 'PXEND2', naxis2, 'Last pixel that has been read out in dimension 2', before = 'COMPRESS'
endif
fxaddpar, primary_header, 'NBIN1', 1, 'Binning factor in the dimension 1', before = 'COMPRESS'
fxaddpar, primary_header, 'NBIN2', 1, 'Binning factor in the dimension 2', before = 'COMPRESS'
fxaddpar, primary_header, 'NBIN', 1, 'Product of all NBIN values above', before = 'COMPRESS'
fxaddpar, primary_header, 'IDB_VERS', input.idb_version, '', before = 'HDR_VERS'
fxaddpar, primary_header, 'INFO_URL', 'http://metis.oato.inaf.it', 'Link to more information on the instrument data', before = 'HISTORY'
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
hk_table = json_parse(input.hk_file_name, /toarray, /tostruct)
; replace raw values with calibrated values in the primary header
; WARN - must be done here?
if datatype eq 0 or datatype eq 3 or datatype eq 5 then begin
; WARN - DACPOL parameters are not calibrated since a calibration curve does not exist in the IDB. Their calibration in physical units (e.g., voltages or angles) should be done later
; fxaddpar, primary_header, 'DAC1POL1', interpol_param(hk_table, 'NIT0E061', date_avg, empty_param = empty_param)
; fxaddpar, primary_header, 'DAC2POL1', interpol_param(hk_table, 'NIT0E062', date_avg, empty_param = empty_param)
; fxaddpar, primary_header, 'DAC1POL2', interpol_param(hk_table, 'NIT0E064', date_avg, empty_param = empty_param)
; fxaddpar, primary_header, 'DAC2POL2', interpol_param(hk_table, 'NIT0E065', date_avg, empty_param = empty_param)
; fxaddpar, primary_header, 'DAC1POL3', interpol_param(hk_table, 'NIT0E067', date_avg, empty_param = empty_param)
; fxaddpar, primary_header, 'DAC2POL3', interpol_param(hk_table, 'NIT0E068', date_avg, empty_param = empty_param)
; fxaddpar, primary_header, 'DAC1POL4', interpol_param(hk_table, 'NIT0E06A', date_avg, empty_param = empty_param)
; fxaddpar, primary_header, 'DAC2POL4', interpol_param(hk_table, 'NIT0E06B', date_avg, empty_param = empty_param)
fxaddpar, primary_header, 'TSENSOR ', interpol_param(hk_table, 'NIT0E0E0', date_avg, empty_params = empty_params)
fxaddpar, primary_header, 'PMPTEMP ', interpol_param(hk_table, 'NIT0L00D', date_avg, empty_params = empty_params)
endif
if datatype eq 1 or datatype eq 4 or datatype eq 6 then begin
fxaddpar, primary_header, 'HVU_SCR ', interpol_param(hk_table, 'NIT0E070', date_avg, empty_params = empty_params)
fxaddpar, primary_header, 'HVU_MCP ', interpol_param(hk_table, 'NIT0E071', date_avg, empty_params = empty_params)
fxaddpar, primary_header, 'TSENSOR ', interpol_param(hk_table, 'NIT0E050', date_avg, empty_params = empty_params)
endif
if ~ isa(empty_params) then empty_params = ''
; remove unused keywords
sxdelpar, primary_header, 'CAD_BEG'
sxdelpar, primary_header, 'CAD_END'
sxdelpar, primary_header, 'WIDTH'
sxdelpar, primary_header, 'HEIGHT'
sxdelpar, primary_header, 'NB_IMG'
sxdelpar, primary_header, 'N'
sxdelpar, primary_header, 'X_SIZE'
sxdelpar, primary_header, 'Y_SIZE'
sxdelpar, primary_header, 'Z_SIZE'
sxdelpar, primary_header, 'P_BANDS'
sxdelpar, primary_header, 'N_BANDS'
sxdelpar, primary_header, 'ORIG_X'
sxdelpar, primary_header, 'ORIG_Y'
sxdelpar, primary_header, 'FIRSTROW'
; add checksum and datasum to the fits header
; WARN - should this be done at the end? i don't know
fits_add_checksum, primary_header, image
mwrfits, image, out_file_name, primary_header, /no_comment, /create, /silent
; if applicable, save the data binary-table extension as it is
if isa(data_bin_table) then mwrfits, data_bin_table, 'output/' + file_name, data_extension_header, /no_comment, /silent
; build the telemetry extension
hk_extension_header = !null
fxaddpar, hk_extension_header, 'XTENSION', 'BINTABLE', 'Extension type'
fxaddpar, hk_extension_header, 'BITPIX', 8, 'Number of bits per data pixel'
fxaddpar, hk_extension_header, 'NAXIS', 2, 'Number of data axes'
fxaddpar, hk_extension_header, 'NAXIS1', 0, 'Number of pixels along axis 1'
fxaddpar, hk_extension_header, 'NAXIS2', 0, 'Number of pixels along axis 2'
fxaddpar, hk_extension_header, 'PCOUNT', 0, 'Parameter count'
fxaddpar, hk_extension_header, 'GCOUNT', 1, 'Group count'
fxaddpar, hk_extension_header, 'EXTNAME', 'House-keeping', 'Extension name'
for i = 0, n_elements(hk_table.par_name) - 1 do begin
param = create_struct( $
'PAR_NAME', hk_table.par_name[i], $
'PACKET', hk_table.packet[i], $
'GEN_TIME', hk_table.gen_time[i], $
'REC_TIME', hk_table.rec_time[i], $
'RAW_VAL', hk_table.raw_val[i], $
'ENG_VAL', hk_table.eng_val[i], $
'UNIT', hk_table.unit[i], $
'DESCR', hk_table.desc[i] $
)
if ~ isa(hk_bin_table) then hk_bin_table = param else hk_bin_table = [hk_bin_table, param]
endfor
mwrfits, hk_bin_table, out_file_name, hk_extension_header, /no_comment, /silent
; write the auxiliary information file
output = { $
file_name: out_file_name, $
log_file_name: 'output/metis_l1_prep_log.txt', $
empty_params : empty_params[uniq(empty_params)] $
}