dustem_write_fits_table.pro 15.3 KB
PRO dustem_write_fits_table,filename=filename,help=help

;+
; NAME:
;    dustem_write_fits_table
;
; PURPOSE:
;    Write a FITS table with content of current DustEMWrap system variables
;
; CATEGORY:
;    DustEMWrap, Distributed, High-Level, User Convenience
;
; CALLING SEQUENCE:
;    dustem_write_fits_table,file[,/help]
;
; INPUTS:
;    file      = File name to be written (default='./dustemwrap_results.fits')
;
; OPTIONAL INPUT PARAMETERS:
;    None
;
; OUTPUTS:
;    None
;
; OPTIONAL OUTPUT PARAMETERS:
;    None
;
; ACCEPTED KEY-WORDS:
;    help      = If set, print this help
;
; COMMON BLOCKS:
;    None
;
; SIDE EFFECTS:
;    Output FITS file is written to disk.
;
; RESTRICTIONS:
;    The DustEMWrap IDL code must be installed
;
; PROCEDURE:
;    None
;
; EXAMPLES
;    
; MODIFICATION HISTORY:
;    Written by J.-Ph. Bernard July 2022
;    Evolution details on the DustEMWrap gitlab.
;    See http://dustemwrap.irap.omp.eu/ for FAQ and help.  
;-


IF keyword_set(help) THEN BEGIN
  doc_library,'dustem_write_fits_table'
  goto,the_end
ENDIF

used_model=!dustem_model

emission_sed_present=ptr_valid((*!dustem_data).sed)
extinction_sed_present=ptr_valid((*!dustem_data).ext)
;dustem_activate_plugins,p_dim/(*(*!dustem_fit).param_init_values),st=st  
;fact = 1.e4*(*!dustem_HCD)/(4.*!pi)/(3.e8/1.e-6/st.sed.wav)*1.e20/1.e7 ;this is correct despite the way it is presented (1.e4/1e.7*1e.20=1.e17 which is the factor to convert from ergs to Mega Janskys)
;SED_spec = st.sed.em_tot * fact

;===== run dustem to get predicted spectrum and sed
IF emission_sed_present THEN BEGIN
	dustem_predicted_sed=dustem_compute_sed(*(*!dustem_fit).current_param_values,st=dustem_st)
	IF !run_pol THEN BEGIN
	;This is needed to compute Q,U of both SED and spectra
	   dustem_predicted_polsed=dustem_compute_stokes(*(*!dustem_fit).current_param_values, $
	                                                 Q_spec=dustem_predicted_Q_spec,U_spec=dustem_predicted_U_spec,PSI_spec=dustem_predicted_PSI_spec, $
	                                                 dustem_psi_em=dustem_psi_em)
	   dustem_predicted_Qsed=dustem_predicted_polsed[0]
	   dustem_predicted_Used=dustem_predicted_polsed[1]
	ENDIF

	;===== define structures containing results
	one_str_input_SED={FILTER:'',Wavelength:la_undef(4),I:la_undef(5),Q:la_undef(5),U:la_undef(5),varianceII:la_undef(5),varianceQQ:la_undef(5),varianceUU:la_undef(5)}
	one_str_predicted_SED={FILTER:'',Wavelength:la_undef(4),I:la_undef(5),Q:la_undef(5),U:la_undef(5)}
	;one_str_predicted_spectrum_tot={Wavelength:0.,I:0.,Q:0.,U:0.}
	;one_str_predicted_spectrum_grain1={Wavelength:0.,I:0.,Q:0.,U:0.}

	Nsed=n_elements((*(*!dustem_data).sed).filt_names)
	str_input_SED=replicate(one_str_input_SED,Nsed)
	str_input_SED.FILTER=(*(*!dustem_data).sed).filt_names
	str_input_SED.Wavelength=(*(*!dustem_data).sed).wav
	str_input_SED.I=(*(*!dustem_data).sed).values
	str_input_SED.varianceII=(*(*!dustem_data).sed).sigma   ;should it be squared ??

	N_predicted_sed=n_elements(dustem_predicted_sed)
	str_predicted_SED=replicate(one_str_predicted_SED,N_predicted_sed)
	;str_predicted_EXT=replicate(one_str_predicted_SED,N_predicted_sed)
	fully_undefined_sed=str_predicted_SED
	str_predicted_SED.FILTER=(*(*!dustem_data).sed).filt_names    ;taken from input SED
	str_predicted_SED.Wavelength=(*(*!dustem_data).sed).wav       ;taken from input SED
	str_predicted_SED.I=dustem_predicted_sed    
	;stop
	IF !run_pol THEN BEGIN
		str_predicted_SED.Q=dustem_predicted_Qsed
		str_predicted_SED.U=dustem_predicted_Used
		;str_predicted_EXT.Q=dustem_predicted_Qext
		;str_predicted_EXT.U=dustem_predicted_Uext
	ENDIF ELSE BEGIN
		str_predicted_SED.Q=fully_undefined_sed.Q
		str_predicted_SED.U=fully_undefined_sed.U
		;str_predicted_EXT.Q=fully_undefined_sed.Q
		;str_predicted_EXT.U=fully_undefined_sed.U
	ENDELSE
ENDIF


IF extinction_sed_present THEN BEGIN
	;stop
	dustem_predicted_ext=dustem_compute_ext(*(*!dustem_fit).current_param_values,st=dustem_st)
	IF !run_pol THEN BEGIN
	;This is needed to compute Q,U of both SED and spectra
	   dustem_predicted_polext=dustem_compute_stokext((*!dustem_fit).current_param_values,st=dustem_st)
	   ;dustem_predicted_polext=dustem_compute_polext(*(*!dustem_fit).current_param_values,st=dustem_st, $
	   ;                                              POLEXT_spec=POLEXT_spec,SPEXT_spec=SPEXT_spec,dustem_fpolext=dustem_fpolext,dustem_ext=dustem_ext)
	   dustem_predicted_Qext=dustem_predicted_polext[0]
	   dustem_predicted_Uext=dustem_predicted_polext[1]
	ENDIF

	;===== define structures containing results
	;one_str_input_EXT=dustem_initialize_internal_sed(1)
	one_str_input_EXT={FILTER:'',Wavelength:la_undef(4),I:la_undef(5),Q:la_undef(5),U:la_undef(5),varianceII:la_undef(5),varianceQQ:la_undef(5),varianceUU:la_undef(5)}
	one_str_predicted_EXT={FILTER:'',Wavelength:la_undef(4),I:la_undef(5),Q:la_undef(5),U:la_undef(5)}
	;one_str_predicted_spectrum_tot={Wavelength:0.,I:0.,Q:0.,U:0.}
	;one_str_predicted_spectrum_grain1={Wavelength:0.,I:0.,Q:0.,U:0.}

	Next=n_elements((*(*!dustem_data).ext).filt_names)
	str_input_EXT=replicate(one_str_input_EXT,Next)
	str_input_EXT.FILTER=(*(*!dustem_data).ext).filt_names
	str_input_EXT.Wavelength=(*(*!dustem_data).ext).wav
	str_input_EXT.I=(*(*!dustem_data).ext).values
	str_input_EXT.varianceII=(*(*!dustem_data).ext).sigma   ;should it be squared ??

	N_predicted_ext=n_elements(dustem_predicted_polext[0])
	str_predicted_EXT=replicate(one_str_predicted_EXT,N_predicted_EXT)
	fully_undefined_ext=str_predicted_ext
	str_predicted_EXT.FILTER=(*(*!dustem_data).ext).filt_names    ;taken from input SED
	str_predicted_EXT.Wavelength=(*(*!dustem_data).ext).wav       ;taken from input SED
	str_predicted_EXT.I=dustem_predicted_ext   
	IF !run_pol THEN BEGIN
		str_predicted_EXT.Q=dustem_predicted_Qext
		str_predicted_EXT.U=dustem_predicted_Uext
	ENDIF ELSE BEGIN
		str_predicted_EXT.Q=fully_undefined_ext.Q
		str_predicted_EXT.U=fully_undefined_ext.U
	ENDELSE
ENDIF

Ngrains=n_tags(dustem_st.sed)-2

;stop

;N_predicted_spectra=n_elements(dustem_spectra_st.sed)

;===== Fill in header with parameter values
parameters_desc=*(*!dustem_fit).PARAM_DESCS
parameters_init_values=*(*!dustem_fit).PARAM_INIT_VALUES
best_parameters=*(*!dustem_fit).CURRENT_PARAM_VALUES
best_parameters_uncertainties=*(*!dustem_fit).CURRENT_PARAM_ERRORS
best_fit_chi2=(*!dustem_fit).CHI2
best_fit_rchi2=(*!dustem_fit).RCHI2
parameters_func_values=*(*!dustem_fit).PARAM_FUNC

Nparams=n_elements(parameters_desc)

;stop
;This is what will be saved
;help,str_input_SED,/str
;help,str_predicted_SED,/str
;help,dustem_spectra_st.sed,/str
;help,dustem_spectra_st.ext,/str

file='./dustemwrap_tmp.fits'
;==== Write the observed SED in extension 1
unit=1L
;Yes, toto does not exist. This is just to write a dummy input to allow for a general header
mwrfits,toto,file,/create
IF emission_sed_present THEN BEGIN
	;==== add the input emission SED
	mwrfits,str_input_SED,file
	unit_input_sed=unit
	unit=unit+1
	;==== add the predicted emission SED
	mwrfits,str_predicted_SED,file
	unit_predicted_sed=unit
	unit=unit+1
ENDIF ELSE BEGIN
	unit_input_sed=-1
	unit_predicted_sed=-1
ENDELSE
IF extinction_sed_present THEN BEGIN
	;stop
	mwrfits,str_input_EXT,file
	unit_input_ext=unit
	unit=unit+1
	;==== add the predicted emission SED
	mwrfits,str_predicted_EXT,file
	unit_predicted_ext=unit
	unit=unit+1
ENDIF ELSE BEGIN
	unit_input_ext=-1
	unit_predicted_ext=-1
ENDELSE
;==== add the predicted per-grain emission spectrum
mwrfits,dustem_st.sed,file
unit_predicted_spectra=unit
unit=unit+1
;==== add the predicted per-grain extinction spectrum
mwrfits,dustem_st.ext,file
unit_predicted_extinctions=unit
unit=unit+1
IF !run_pol EQ 1 THEN BEGIN
	mwrfits,dustem_st.polsed,file
	unit_predicted_spectra_pol=unit
	unit=unit+1
	mwrfits,dustem_st.polext,file
	unit_predicted_extinctions_pol=unit
	unit=unit+1
ENDIF ELSE BEGIN
	unit_predicted_spectra_pol=-1
	unit_predicted_extinctions_pol=-1
ENDELSE

extension_numbers=[unit_input_sed,unit_predicted_sed, $
				   unit_input_ext,unit_predicted_ext, $
				   unit_predicted_spectra,unit_predicted_extinctions, $
				   unit_predicted_spectra_pol,unit_predicted_extinctions_pol]
extensions_strs=['INPUT_EMISSION_SED','DUSTEM_PREDICTED_SED', $
				 'INPUT_EXTINCTION_SED','DUSTEM_PREDICTED_EXTINCTION_SED', $
				 'DUSTEM_PREDICTED_EMISSION_SPECTRA','DUSTEM_PREDICTED_EXTINCTION_SPECTRA', $
				 'DUSTEM_PREDICTED_EMISSION_SPECTRA_POL','DUSTEM_PREDICTED_EXTINCTION_SPECTRA_POL']

ind=where(extension_numbers NE -1,count)
extension_numbers=extension_numbers[ind]
extensions_strs=extensions_strs[ind]
order=sort(extension_numbers)
extension_numbers=extension_numbers[order]
extensions_strs=extensions_strs[order]
Nextensions=n_elements(extension_numbers)
;print,unit_input_sed,unit_predicted_sed,unit_predicted_spectra,unit_predicted_extinctions
;stop

;stop

;===== read back fits file to get proper extension headers
file='./dustemwrap_tmp.fits'
toto=mrdfits(file,0,hdr)      ;this would be to get the main header
;stop
IF unit_input_sed NE -1 THEN sst_input_sed=mrdfits(file,unit_input_sed,header_input_sed)
IF unit_predicted_sed NE -1 THEN sst_predicted_SED=mrdfits(file,unit_predicted_sed,header_predicted_SED)
IF unit_input_ext NE -1 THEN sst_input_ext=mrdfits(file,unit_input_ext,header_input_ext)
IF unit_predicted_ext NE -1 THEN sst_predicted_ext=mrdfits(file,unit_predicted_ext,header_predicted_ext)
;sst_predicted_spectrum_tot=mrdfits(file,3,header_predicted_spectrum_tot)
dustem_st.sed=mrdfits(file,unit_predicted_spectra,header_predicted_spectra)
dustem_st.ext=mrdfits(file,unit_predicted_extinctions,header_predicted_extinctions)
IF !run_pol EQ 1 THEN BEGIN
	dustem_st.polsed=mrdfits(file,unit_predicted_spectra_pol,header_predicted_spectra)
	dustem_st.polext=mrdfits(file,unit_predicted_extinctions_pol,header_predicted_extinctions)
ENDIF
;===== write content of extensions in main header
FOR i=0L,Nextensions-1 DO BEGIN
	sxaddpar,hdr,'EXT'+strtrim(i+1,2),extensions_strs[i],'fits file extension'
ENDFOR

;====== write dustem wrap parameter best fit values
sxaddpar,hdr,'COMMENT','======= Dustemwrap dust model used ======',after='COMMENT'
sxaddpar,hdr,'MODEL',used_model,'Dust model used'
sxaddpar,hdr,'WRAP_V',!dustem_version.version,'Dustwrap version used'
sxaddpar,hdr,'COMMENT','===================================================',after='MODEL'
sxaddpar,hdr,'CHI2',best_fit_chi2,'Dustemwrap best fit chi2 [-]'
sxaddpar,hdr,'RCHI2',best_fit_rchi2,'Dustemwrap best fit reduced chi2 [-]'
sxaddpar,hdr,'NGRAINS',Ngrains,'Number of grain species'
;====== write dustem wrap parameter names
sxaddpar,hdr,'COMMENT','======= Dustemwrap parameter names ======',after='RCHI2'
sxaddpar,hdr,'NPARAMS',Nparams,' Number of DustemWrap free parameters'
FOR i=0L,Nparams-1 DO BEGIN
	sxaddpar,hdr,'PARN'+strtrim(i+1,2),parameters_desc[i],' DustemWrap parameter name'
ENDFOR
sxaddpar,hdr,'COMMENT','===================================================',after='PARN'+strtrim(i,2)
sxaddpar,hdr,'COMMENT','======= Dustemwrap dust model used in polarisation ? ======',after='COMMENT'
sxaddpar,hdr,'POL',!run_pol,'1 if pol was used, 0 otherwise'
sxaddpar,hdr,'COMMENT','===================================================',after='POL'
;====== write dustem wrap parameter best fit values
sxaddpar,hdr,'COMMENT','======= Dustemwrap parameter best fit values ======',after='COMMENT'
FOR i=0L,Nparams-1 DO BEGIN
	sxaddpar,hdr,'PARV'+strtrim(i+1,2),best_parameters[i],'Param. '+parameters_desc[i]
ENDFOR
sxaddpar,hdr,'COMMENT','===================================================',after='PARV'+strtrim(i,2)

;====== write dustem wrap parameter best fit values uncertainties
sxaddpar,hdr,'COMMENT','======= Dustemwrap best fit parameter uncertainties ======',after='COMMENT'
FOR i=0L,Nparams-1 DO BEGIN
	sxaddpar,hdr,'PARU'+strtrim(i+1,2),best_parameters_uncertainties[i],'Param. '+parameters_desc[i]
ENDFOR
sxaddpar,hdr,'COMMENT','===================================================',after='PARU'+strtrim(i,2)

;====== write dustem wrap parameter initial fit values
sxaddpar,hdr,'COMMENT','======= Dustemwrap parameter initial fit values ======',after='COMMENT'
FOR i=0L,Nparams-1 DO BEGIN
	sxaddpar,hdr,'PARI'+strtrim(i+1,2),parameters_init_values[i],'Param. '+parameters_desc[i]
ENDFOR
sxaddpar,hdr,'COMMENT','===================================================',after='PARI'+strtrim(i,2)

;====== write dustem wrap parameter func values (not sure exactly what this is)
sxaddpar,hdr,'COMMENT','======= Dustemwrap parameter func values ======',after='COMMENT'
FOR i=0L,Nparams-1 DO BEGIN
	sxaddpar,hdr,'PARF'+strtrim(i+1,2),parameters_func_values[i],'Param. '+parameters_desc[i]
ENDFOR
sxaddpar,hdr,'COMMENT','===================================================',after='PARF'+strtrim(i,2)

;===== complement extension header for input SED
sxaddpar,header_input_sed,'TITLE','OBSERVED INPUT SED TO DUSTEMWRAP',before='COMMENT'
sxaddpar,header_input_sed,'TTYPE1','FILTER','Dustemwrap Filter name'
sxaddpar,header_input_sed,'TTYPE2','WAVELENGTH','Dustemwrap Filter reference wavelength [microns]'
sxaddpar,header_input_sed,'TTYPE3','I','Observed Total Stokes I Intensity [??]'
sxaddpar,header_input_sed,'TTYPE4','Q','Observed Stokes Q Intensity [??]'
sxaddpar,header_input_sed,'TTYPE5','U','Observed Stokes U Intensity [??]'
sxaddpar,header_input_sed,'TTYPE6','VARIANCEII','Observed Total Stokes I Variance [??]'
sxaddpar,header_input_sed,'TTYPE7','VARIANCEQQ','Observed Stokes Q Variance [??]'
sxaddpar,header_input_sed,'TTYPE8','VARIANCEUU','Observed Stokes U Variance [??]'

;===== complement extension header for predicted SED
sxaddpar,header_predicted_SED,'TITLE','OUTPUT BEST FIT SED BY DUSTEMWRAP'
sxaddpar,header_predicted_SED,'TTYPE1','FILTER','Dustemwrap Filter name'
sxaddpar,header_predicted_SED,'TTYPE2','WAVELENGTH','Dustemwrap Filter reference wavelength [microns]'
sxaddpar,header_predicted_SED,'TTYPE3','I','Observed Total Stokes I Intensity [??]'
sxaddpar,header_predicted_SED,'TTYPE4','Q','Observed Stokes Q Intensity [??]'
sxaddpar,header_predicted_SED,'TTYPE5','U','Observed Stokes U Intensity [??]'

;===== complement extension header for predicted spectrum total
sxaddpar,header_predicted_spectra,'TITLE','OUTPUT BEST FIT PER-GRAIN AND TOTAL EMISSION SPECTRA BY DUSTEMWRAP'
sxaddpar,header_predicted_extinctions,'TITLE','OUTPUT BEST FIT PER-GRAIN AND TOTAL EXTINCTION BY DUSTEMWRAP'

;============== write final fits file
IF keyword_set(filename) THEN BEGIN
	file=filename
ENDIF ELSE BEGIN
	file='./dustemwrap_results.fits'
ENDELSE

;==== Write the observed SED (if any)
mwrfits,0,file,hdr,create=1
IF unit_input_sed NE -1 THEN BEGIN
	mwrfits,str_input_SED,file,header_input_sed
ENDIF
;==== add the predicted SED (if any)
IF unit_input_sed NE -1 THEN BEGIN
	mwrfits,str_predicted_SED,file,header_predicted_SED
ENDIF
IF unit_input_ext NE -1 THEN BEGIN
	mwrfits,str_input_EXT,file,header_input_sed
ENDIF
;==== add the predicted SED (if any)
IF unit_predicted_ext NE -1 THEN BEGIN
	mwrfits,str_predicted_EXT,file,header_predicted_SED
ENDIF
;==== add the predicted per-grain emission spectra
mwrfits,dustem_st.sed,file,header_predicted_spectra
;==== add the predicted per-grain extinction
mwrfits,dustem_st.ext,file,header_predicted_extinctions
IF !run_pol EQ 1 THEN BEGIN
	mwrfits,dustem_st.polsed,file
	mwrfits,dustem_st.polext,file
ENDIF

message,'================================================',/info
message,'Wrote '+file,/info
message,'File extenssions are: ',/info
FOR i=0L,Nextensions-1 DO BEGIN
	message,'extenssion '+strtrim(extension_numbers[i],2)+' : '+strtrim(extensions_strs[i],2),/info
ENDFOR
message,'================================================',/info
;stop


the_end:

END