FUNCTION xrt_cvfact, te, fw1, fw2, time, $
         cal = cal, $
         index=index, $
         error=error, datapoint=datapoint, $
         contamination_thickness=contamination_thickness, $
         info=info, message=message, $
         lambda_spectrum = lambda_spectrum, te_spectrum = te_spectrum, spectrum = spectrum, $
         apac_spectrum = apac_spectrum, eff_area = eff_area

; =========================================================================
;+
; PROJECT:
;
;       Solar-B / XRT 
;
; NAME:
;       
;       XRT_CVFACT
;
; CATEGORY:
;       
;       XRT RESPONSE
;
; PURPOSE:
;       
;       Get factor to convert "photon number" to "DN".
;
;       In default, this program use the solar spectrum
;       calculated with CHIANTI database ver. 6.0.1
;       (density: 10^9 [cm^-3], ionization equilibrium: chianti.ioneq, abundance: sun_coronal_ext).
;
; CALLING SEQUENCE:
;
;       result = XRT_CVFACT(te, fw1, fw2, time, [index=index], [/error], [datapoint=datapoint], $
;                           [contamination_thickness=contamination_thickness], [/info], $
;                           [lambda_spectrum = lambda_spectrum, te_spectrum = te_spectrum, spectrum = spectrum], $
;                           [/apac_spectrum], [eff_area = eff_area])
;       
; INPUTS:
;       
;       TE     - (float array) log Temperature with a range from 5.0 to 8.0.
;       FW1       - (long) Filter No. on filter wheel 1.
;       FW2       - (long) Filter No. on filter wheel 2.
;       TIME      - (string) Time when you want to calcurate the XRT conversion factor,
;                   because XRT conversion factor influenced by contamination is a function of time.
;                   This time is used to derive the thickness of contaminant.
;                   If you directly give the contamination thickness with CONTAMINATION_THICKNESS
;                   keyword, you should omit this TIME input.
;
; KEYWORDS:
;       
;       CAL        - [Optional input] If set as "cal = 1", the factor is calculated based on the calibration in Narukage et al. (2011).
;                                     If set as "cal = 2", the factor is calculated based on the calibration in Narukage et al. (2013).
;                                     Default is "cal = 2" to use the latest calibration result of Narukage et al. (2013).
;       INDEX      - [Optional input] (structure) If set, you can omit the inputs of FW1, FW2 and TIME.
;       /ERROR     - [Optional] (Boolean) If set, you can get factor to convert "DN" to "DN error" caused by photon noise.
;       /DATAPOINT - [Optional] (Boolean)
;                    If set, result is calculated at the data point of temperature and
;                    the data point is inputed into "te" parameter.
;                    The data point of temperature is from 10^5.0 to 10^8.0 [K] with 10^0.05 [K] resolution.
;       CONTAMINATION_THICKNESS - [Optional input] (float)
;                    You can directly give the contamination thickness.
;                    When you use this keyword, you should omit the input of TIME.
;       /INFO                   - [Optional] (Boolean) If set, information is shown.
;       LAMBDA_SPECTRUM         - [Optional input] (float array) wavelength for SPECTRUM in an unit of [A].
;       TE_SPECTRUM             - [Optional input] (float array) temperature for SPECTRUM in an unit of [log K].
;       SPECTRUM                - [Optional input] (2-dim float array, [lambda_spectrum, te_spectrum]) photon number spectrum from solar plasma in an unit of [cm^3 s^-1 sr^-1].
;                                   We recommend that
;                                     (1) The data point of wavelength is from 1 to 400 [A] with 0.1 [A] resolution.
;                                     (2) The data point of temperature is from 10^5.0 to 10^8.0 [K] with 10^0.05 [K] resolution.
;       /APAC_SPECTRUM - [Optional] (Boolean) If set, solar spectrum calculated with APAC database is used. (in default, solar spectrum is calculated with CHIANTI database.)
;       EFF_AREA       - [Optional] (Structure) You can input the output (effective area) from MAKE_XRT_WAVE_RESP.PRO.
;
; OUTPUTS:
;       
;       return - (float array) conversion factor.
;
; EXAMPLES:
;      
;       Using this function, you can get the photon number from DN at 11-Mar-2007 00:55:00.
;       IDL> te = 5.+findgen(61)*0.05
;       IDL> cf = xrt_cvfact(te, 1, 0, '11-Mar-2007 00:55:00')
;       IDL> DN = 100.
;       IDL> print, DN/cf ; <- photon number at a temperature of "te"
;
;       Using this function with /ERROR keyword, you can get "DN error" at 11-Mar-2007 00:55:00
;       caused by photon noise from DN.
;       IDL> te = 5.+findgen(61)*0.05
;       IDL> cf = xrt_cvfact(te, 1, 0, '11-Mar-2007 00:55:00', /error)
;       IDL> DN = 100.
;       IDL> print, sqrt(DN*cf) ; <- DN error at a temperature of "te"
;
; COMMON BLOCKS:
;
;       none 
;
; NOTES:
;
;       filter on filter wheel 1
;         0: open
;         1: thin-Al-poly
;         2: C-poly
;         3: thin-Be
;         4: med-Be
;         5: med-Al
;
;       filter on filter wheel 2
;         0: open
;         1: thin-Al-mesh
;         2: Ti-poly
;         3: G-band (optical)
;         4: thick-Al
;         5: thick-Be
;
;       The detail of calibrated conversion factor of the Hinode/XRT is described in
;         Narukage et al. 2011, Solar Phys., 269, 169.
;         http://adsabs.harvard.edu/doi/10.1007/s11207-010-9685-2
;       and
;         Narukage et al. 2013, Solar Phys., in press
;         http://adsabs.harvard.edu/doi/10.1007/s11207-013-0368-7
;       These two papers are the reference papers of this program.
;
; CONTACT:
;
;       Comments, feedback, and bug reports regarding this routine may be 
;       directed to this email address: 
;                noriyuki.narukage ~at~ nao.ac.jp 
;       
; MODIFICATION HISTORY:
;
progver = 'v2007-May-18' ;--- (N.Narukage (ISAS/JAXA)) Written.
progver = 'v2009-Jul-27' ;--- (N.Narukage (NAOJ)) Updated to consider the contamination on focal-plane analysis filters and CCD.
progver = 'v2010-Jul-30' ;--- (N.Narukage (NAOJ)) Updated to input the solar spectrum.
;                                                 And added the option to select the APAC database.
progver = 'v2010-Aug-04' ;--- (N.Narukage (NAOJ)) Updated to input the output from MAKE_XRT_WAVE_RESP.PRO.
progver = 'v2011-Feb-17' ;--- (N.Narukage (NAOJ)) Added the information on the reference paper.
progver = 'v2013-Nov-04' ;--- (N.Narukage (NAOJ)) Updated to use the calibration result of Narukage et al. (2013).
;                                                 Added the keyword of "cal" to select the calibration result.
;                                                 And modified for the message from the program.
progver = 'v2015-Oct-09' ;--- (N.Narukage (NAOJ)) Bug fix, namely, added the definition of "file_prefix".
;
;-
; =========================================================================

  ps = path_sep()
  file_prefix = get_logenv('$SSW_XRT') + ps + 'idl' + ps + 'response' + ps + 'j' + ps

; --- setting for message -------------------------------------------------

  if not keyword_set(message) then message = ['XRT_CVFACT']

; --- read filter config data ---------------------------------------------

  config = xrt_config(cal = cal)

; --- process of option ---------------------------------------------------

  if keyword_set(index) then begin
    time = anytim(index.date_obs, /ecs)
    fw1 = index.ec_fw1
    fw2 = index.ec_fw2
  endif

; --- read solar spectrum -------------------------------------------------

  if not(keyword_set(lambda_spectrum) and keyword_set(te_spectrum) and keyword_set(spectrum)) then begin

    if keyword_set(apac_spectrum) then begin

      temp = get_xrt_spec_genx()

      nl = max(where(temp.wave ne 0))
      dl = temp.wave[1] - temp.wave[0]
      nt = max(where(temp.temp ne 0))

      lambda_spectrum = temp.wave[0:nl]
      te_spectrum     = temp.temp[0:nt]
      spectrum        = temp.spec[0:nl, 0:nt] * dl

    endif else begin

      solar_spe_file = 'XRT_solar_spe-chianti_6.0.1-edensity_1e9-chianti.ioneq-sun_coronal_ext.abund'

      restgenx, te_spectrum, lambda_spectrum, spectrum, file = file_prefix + 'database' + ps + 'solar_spe' + ps + solar_spe_file
       ; spectrum : photon number spectrum from solar plasma (n = 10^9 [cm^-3]) [cm^3 s^-1 sr^-1]

    endelse

  endif

; --- calculate conversion factor -----------------------------------------

  gain = config.ccd.gain

  if keyword_set(eff_area) then begin
    temp = fltarr(6,6)
    temp[*,*] = -1.
    temp[0,1] =  0. ; Al-mesh
    temp[1,0] =  1. ; Al-poly
    temp[2,0] =  2. ; C-poly
    temp[0,2] =  3. ; Ti-poly
    temp[3,0] =  4. ; Be-thin
    temp[4,0] =  5. ; Be-med
    temp[5,0] =  6. ; Al-med
    temp[0,4] =  7. ; Al-thick
    temp[0,5] =  8. ; Be-thick
    temp[1,1] =  9. ; Al-poly/Al-mesh
    temp[1,2] = 10. ; Al-poly/Ti-poly
    temp[1,4] = 11. ; Al-poly/Al-thick
    temp[1,5] = 12. ; Al-poly/Be-thick
    temp[2,2] = 13. ; C-poly/Ti-poly
    temp[2,4] = 14. ; C-poly/Al-thick

    if temp[fw1, fw2] ne -1 then begin
      temp = eff_area[temp[fw1, fw2]].effar
      ea = interpol(temp.eff_area[0:temp.length-1], temp.wave[0:temp.length-1], lambda_spectrum) > 0.
      if keyword_set(info) and n_elements(temp.name) ne 0 then begin
        print
        print, temp.name
        print
      endif
    endif else begin
      ea = fltarr(n_elements(lambda_spectrum))
      ea[*] = 0.

      message = [message, '']
      message = [message, '*****  WARNING from XRT_CVFACT.PRO  ***************************************']
      message = [message, 'Your inputted EFF_AREA as a keyword does not contain']
      message = [message, '  the effective area information about']
      message = [message, '    '+config.filter1[fw1].name+' (FW1) / '+config.filter2[fw2].name+' (FW2).']
      message = [message, '***************************************  WARNING from XRT_CVFACT.PRO  *****']

	endelse
  endif else begin
    ea = xrt_eff_area(lambda_spectrum, fw1, fw2, time, cal=cal, index=index, contamination_thickness=contamination_thickness, info=info, message=message)
  endelse

  ea = rebin( ea, n_elements(lambda_spectrum), n_elements(te_spectrum) ) ; effective area [cm ^ 2]

  h = 6.6261e-27 ; plank constant
  c = 2.9979e10 ; speed of light [cm/s]

  E2DN = ( h * c / (lambda_spectrum*1.e-8) ) /  ( (3.65*1.602*1.e-12) * gain )
  E2DN = rebin( E2DN, n_elements(lambda_spectrum), n_elements(te_spectrum) )

  K1 = total(spectrum * ea * E2DN, 1)    / total(spectrum * ea, 1)
  K2 = total(spectrum * ea * E2DN^2., 1) / total(spectrum * ea * E2DN, 1)

  cf = K1
  if keyword_set(error) then cf = K2

  if keyword_set(datapoint) then te = te_spectrum else cf = INTERPOL( cf, te_spectrum, te )


; --- show message ------------------------------------------------------------

  if n_elements(message) ge 2 then begin
    if message[0] eq 'XRT_CVFACT' then hprint, [message[1:*], '']
  endif


  return, cf

END
