Home Download Tutorial 1 Tutorial 2 Tutorial 3 Tutorial 4 Tutorial 5
;+
; NAME:                 ULY_LSF
;
; PURPOSE:              Determine the line-spread function (LSF)
;
; USAGE:                uly_lsf, <spectrum>, <cmp>, <width>, <step>,   $
;                            FILE_OUT=file_out, /PLOT, /QUIET, /CLEAN, $
;                            KMOMENT=<kmoment>, DG=<dg>, DL=<dl>,      $
;                            KFIX=<kfix>, KPEN=<kpen>,                 $
;                            MDEGREE=<mdegree>, ADEGREE=<adegree>,     $
;                            VELSCALE=<velscale>
;
; ARGUMENTS:
;     <spectrum>       Filename or spectrum structure containing the spectrum
;                      to be analysed for the LSF.
;     <cmp>            Component structure containing the reference high
;                      resolution spectrum. The LSF of <spectrum> will be
;                      determined relatively to <cmp>
;                      In the simplest case, <cmp> can be a reference spectrum
;                      loaded with ULY_STAR, or it can be an interpolated
;                      stellar model (see ULY_TGM) or any other model, or even
;                      an array of several cmp.
;                      During the analysis, eventual non-linear parameters
;                      will be adjusted.
;     <width>, <step>  scalars, [Angstrom] 
;                      The LSF is measured in a succession of chunks of width 
;                      <width> separated by <step>.
;         
; KEYWORDS:
;     FILE_OUT         Name of the output file.
;                      Defaulted to 'output.lsf'
;     KMOMENT, DG, DL, KFIX, KPEN
;                      LOSVD parameters passed to ULySS.
;                      They are used to determine which terms of the LSF to fit.
;     MDEGREE, ADEGREE, VELSCALE
;                      Parameters passed to ULySS.
;                      Remember that MDEGREE (and ADEGREE) apply to the (small)
;                      chunks of spectra of width <width>, so, this parameters
;                      should be smaller than when the whole spectrum is
;                      analysed at once.
;     PLOT             Set this keyword if you want to display the
;                      losvd fit using the program ULY_SOLUT_SPLOT.
;     CLEAN
;                      Set this keyword to perform a kappa-sigma clipping
;                      of the outliers.
;     QUIET            Verbosity control
;
; EXAMPLE:
;   In the following example, we determine the relative LSF between a
;   spectrum to analyse and a model extracted from a grid.
;   Then we smooth this LSF and use it to analyse the spectrum.
;
;   filetest = uly_root+'/data/VazMiles_z-0.40t07.94.fits.fits'
;   model = uly_ssp_extr(filetest, uly_root+'/models/PHR_Elodie31.fits' ,[6000.,-0.4,0.], SIG=30)
;   cmp = uly_star(model)
;   uly_lsf, filetest, cmp, 200, 100, FIL='vaz.lsf', /QUIET
;   heap_free, cmp
;   uly_lsf_plot, 'vaz.lsf' 
;   uly_lsf_smooth, 'vaz.lsf', 'vazs.lsf'
;   uly_lsf_plot, 'vazs.lsf' 
;   cmp = uly_ssp(LSF='vazs.lsf')
;   ulyss, filetest, cmp, /PLOT
;
; LSF ANALYSIS AND INJECTION:
; 
;   A spectrum is characterized by its line spread function, LSF, ie. the 
;   instrumental broadening of the spectral lines. This is the analog of the 
;   PSF for images. The LSF can be modeled by a Gaussian or more generally 
;   by a Gauss-Hermite expansion of a Gaussian.
;   
;   For an observation, the LSF depends on the spectrograph and on the slit, 
;   it generally changes with the wavelength and, in the case of 2 or 3D 
;   spectra, with the position in the field. On the other side, the model
;   used to analyse this observation has also a finite resolution, i.e.
;   has a specific LSF hopefully finer than the one of the observation.
;   Therefore to analyse an observation we have to take into account the
;   relative LSF of the observation with respect to the model. This is of 
;   a primordial importance when studying the internal kinematics (physical 
;   broadening of the lines) of an astronomical source.  
;   
;   The process to properly take the LSF into consideration consists in 
;   two phases: (i) The determination of the relative LSF and (ii) its 
;   injection into the model, so that the result is comparable to an
;   observed spectrum.  
;   
;   Choice of the LSF standard
;   
;   In standard cases, the LSF can be considered as stable for a set of 
;   observations, for example for an observing run, or for a given setup of 
;   an instrument. In this case it is possible to determine it once using 
;   the calibration and standard stars observations. There are
;   different ways to determine the LSF.
;   
;   1) Using the arc spectrum used for the wavelength calibration. 
;   The profile of the lines can be determined at different wavelength 
;   and position in the field (sigma, h3, h4). 
;   This method is currently not implemented in ULySS and requires 
;   some precaution because of blends of the lines and limited sampling.  
;   
;   2) Using a twilight spectrum, and compare it with the solar spectrum 
;   having the same LSF as the model. The input aperture is uniformly
;   illuminated. This is the preferred method.
;   
;   3) Using a spectrum from a star for which a spectrum with the same LSF 
;   as the model is available. The critical aspect of this method is 
;   to be sure that the stellar light is uniformly distributed over
;   then entrance aperture or that the resultion is not determined by
;   the size and shape of the entrance aperture.
;   
;   4) Using a spectrum of a star of known atmospheric parameter,
;   and analyse it with the output of a library interpolator. Or use a
;   spectrum of a star with unknown atmospheric parameters and determine
;   first these parameters with ULySS (see ULY_TGM).
;   
;   Finally, if no stellar spectrum is available, the analysis can be done 
;   with an observation of a galaxy and the internal kinematics of all 
;   objects in the series will be determined relatively to this reference. 
;   (choose the galaxy with the smallest velocity dispersion or decrease 
;   the width of the measured LSF by a fixed amount (use the keyword SIGMA).
;
;   Caveat: To maximize the flux efficiency, some setups use a wide input 
;   aperture (slit) that may be eventually wider than the seeing and that 
;   the intrinsic resolution of the spectrograph. The result is that in 
;   case of good seeing the object may be resolved in the slit, and the 
;   measured broadening does not reflect the physical broadening. This is 
;   a poor practice, and such observations should not be used to study 
;   the internal kinematics.  
;   
;   Analysis of the LSF 
;
;   The analysis of the LSF is made with the program: ULY_LSF
;   which produce an ASCII file describing the LSF (see the
;   Description section in this article). 
;   This file may be viewed with ULY_LSF_PLOT, or smoothed with ULY_LSF_SMOOTH.
;
;   Injection of the LSF 
; 
;   The LSF injection is made by: ULY_SPECT_LSFCONVOL, normally called when
;   a component of the model is initialized or evaluated.
;   The principle of the injection of the LSF in the model is briefly 
;   introduced in Koleva et al. 2008.
;
; HISTORY:
;   Mina Koleva,       2008/03/11, created
;   Yue WU,            2009/03/05, updated
;   Philippe Prugniel, 2015/08/10, updated
;
;-
; CATEGORY:    ULY
;------------------------------------------------------------------------------
pro  uly_lsf, spectrum, cmp, width, step, $
              FILE_OUT=file_out, PLOT=plot, CLEAN=clean, $
              KMOMENT=kmoment, DG=dg, DL=dl, KFIX=kfix, KPEN=kpen, $
              MDEGREE=mdegree, ADEGREE=adegree, VELSCALE=velscale, $
              QUIET=quiet   

if n_elements(spectrum) eq 0 or n_elements(cmp) eq 0 or $
   n_elements(width) eq 0 or n_elements(step) eq 0 then $
  message, 'Usage: ULY_LSF, <spectrum>, <cmp>, <width>, <step>, [optional keyw]'

if n_elements(file_out) ne 1 then lsf_file = 'output.lsf' $
else lsf_file = file_out

; ----------------------------------------------------------------------------
; Read the observed spectrum from which to determine the LSF
if uly_spect_get(spectrum, /VALID) eq 1 then begin
   SignalLog = uly_spect_alloc(SPECT=spectrum)
endif else begin
   SignalLog = uly_spect_read (spectrum, QUIET=quiet) 
endelse

if size(*SignalLog.data, /N_DIM) gt 1 then $
  message, /INFO, 'The file array to process has ' + $
  strtrim(size(*SignalLog.data, /N_DIM),2) + ' dimensions ... we use only the first spectrum'

SignalLog = uly_spect_extract(SignalLog, ONED=0, STATUS=status, /OVER)
if status ne 0 then message, 'Could not extract 1D spectrum'

SignalLog = uly_spect_logrebin(SignalLog, velscale, /OVER)

possig = where((*SignalLog.data) gt 0, cnt)
if cnt eq 0 then $
  message, /INFO, 'The signal is everywhere null or negative in the spectrum to analyse'

velscale = SignalLog.step * 299792.458d
wr = uly_spect_get(SignalLog, /WAVERANGE)


; ----------------------------------------------------------------------------
; Read the LSF reference cmp (used as an LSF standard)
status = uly_fit_init(cmp, WAVERANGE=wr, VELSCALE=velscale, QUIET=quiet)
if status ne 0 then begin
    message, 'Fit initialization failed, abort', /CONT
    return
endif

model_range = exp(cmp[0].start + [0.5,cmp[0].npix-1.5] * cmp[0].step)

; re-cut the input spectrum to the range of the model
SignalLog = uly_spect_extract(SignalLog, WAVERANGE=model_range, /OVER)
wr = uly_spect_get(SignalLog, /WAVERANGE)


; ----------------------------------------------------------------------------
npix = n_elements(*SignalLog.data)
lamrange = wr
nlsf = floor((lamrange[1]-lamrange[0]-width)/step) + 1

;loadct, 2, /SILENT 

if file_test(lsf_file) then file_delete, lsf_file

;openw, lun, lsf_file, BUFSIZE=0, /GET_LUN
;printf, lun, '# lsf_format=1', FORMAT='(a)'
;printf, lun, '# chi2, cz[km/s], e_cz, sigma[km/s], e_sigma, h3, e_h3, h4, e_h4, wl_c[Angstroms], Wstart, Wend', FORMAT='(a)'

undefine, sol_lsf
for nn = 0, nlsf-1 do begin
    minWL = lamrange[0]+step*nn
    maxWL = min([minWL+width, lamrange[1]])
;    centrWL= fix((maxWL-minWL)/2.+minWL)
    s = uly_spect_extract(SignalLog, WAVERANGE=[minWL,maxWL])
    if not keyword_set(quiet) then print, 'LSF chunk: ', nn
    ulyss, s, cmp, $
           KMOMENT=kmoment, DG=dg, DL=dl, KFIX=kfix, KPEN=kpen, $
           MDEGREE=mdegree, ADEGREE=adegree, QUIET=quiet, PLOT=plot, CLEAN=clean, SOL=sol
    uly_spect_free, s

;   write the results in the output file
    if size(sol,/TYPE) ne 8 then begin
; we have a pb there ... we expect a fixed set of wavelengths for each 
; LSF, it is in particular important when we measure a series of LSFs
; that we want to average (but maybe the solution is to change the way
; we read and average the lsfs
       print, 'hum ... what do we do when a fit failed?'
    endif else begin
       uly_solut_twrite, sol, lsf_file, /HEAD
       heap_free, sol
    endelse

;;   write the results in the output file
;    if size(sol,/TYPE) ne 8 then begin
;        if not keyword_set(quiet) then message, /INFO, 'The fit failed for LSF segment '+ strtrim(centrWL,2)
;        printf, lun, 0., 0., 0., 0., 0., 0., 0., 0., 0.,centrWL, minWL, maxWL, $
;          FORMAT='(12e15.7)'
;    endif else begin
;        printf, lun, sol.chisq, $
;          sol.losvd[0], sol.e_losvd[0], sol.losvd[1], sol.e_losvd[1],$
;          0.,0.,0.,0.,centrWL, minWL, maxWL, $
;          FORMAT='(12e15.7)'
;;        heap_free, sol
;    endelse
endfor


;close, lun
;free_lun, lun

if not keyword_set(quiet) then print, 'The results are saved in ', lsf_file

uly_spect_free, SignalLog 

end

;#############################################################################
Part of ULySS package