FUNCTION xrt_dem2obs, demT, dem, dem_int=dem_int, tresp=tresp,     $
                      verbose=verbose, quiet=quiet, qabort=qabort, $
                      qstop=qstop

; =========================================================================
;+
; PROJECT:
;       Solar-B / XRT
;
; NAME:
;
;       XRT_DEM2OBS
;
; CATEGORY:
;
;       DEM (Differential Emission Measures)
;
; PURPOSE:
;
;       Given a DEM(T), a temperature range T_DEM, and a set of 
;       temperature responses R_i(T) over channels "i", solve
;       for the channel observations B_i. The equation is:
;
;            B_i = integral{ DEM(T) * R_i(T) * dT }
;
; CALLING SEQUENCE:
;
;       Result = XRT_DEM2OBS( demT, dem [,dem_int=dem_int] [,tresp=tresp]
;                             [,/verbose] [,/quiet] [,/qstop] 
;                             [,qabort=qabort]                           )
;
; INPUTS:
;
;       DEMT     - [Mandatory] (float array, [Ntemps])
;                  Units = 'log K'; however, the integrals are performed 
;                  over T. This is the temperature range corresponding to 
;                  the DEM input. The temperature bin-widths dT are
;                  are presumed to have boundaries halfway between
;                  adjacent values of DEMT. (I.e., DEMT and dT do not
;                  need to be regularly spaced in log T.) 
;                  The routine might crash or give spurious answers if
;                  the temp. range of DEMT goes beyond the range of the
;                  temp. responses. The default responses have a range of
;                      log T = 5.5 to 8.0.
;       DEM      - [Mandatory] (float array, [Ntemps])
;                  Units = 'cm^-5 K^-1'; the "line-of-sight" 
;                  (or "column") differential emission measure 
;                  corresponding to the values in DEMT.
;
; KEYWORDS:
;
;       TRESP    - [Mandatory] ("temp_resp" structure array, [Nchn])
;                  The user must provide the temperature response functions
;                  via this keyword.
;                  The default units are 'DN cm^5 s^-1 pix^-1'.
;                  (The standard XRT responses can be obtained using
;                  <make_xrt_wave_resp.pro>, followed by
;                  <make_xrt_temp_resp.pro>. Please refer to the header 
;                  documentation of those programs and the relevant section
;                  of the XRT Analysis Guide.)
;                  (See Note #2 regarding the evolution of this keyword.)
;       /VERBOSE - [Optional] (Boolean) If set, print out extra
;                  information. Overrides "/quiet" (see Note #1).
;       /QUIET   - [Optional] (Boolean) If set, suppress messages
;                  (see Note #1).
;       /QSTOP   - [Optional] (Boolean) For debugging.
;
; OUTPUTS:
;
;       Returns  - [Mandatory] (structure array, [Nchn])
;                  An array over all the XRT channels described in
;                  the default or provided temp. responses.
;                    CHANNEL_NAME    STRING   
;                    OBS             FLOAT   
;                    OBS_UNITS       STRING    'DN s^-1 pix^-1'
;                  (The units of OBS might depart from this if the provided
;                  temp. responses use non-standard units, although this 
;                  program is not yet smart enough to correct the value of 
;                  OBS_UNITS. The default responses will always give these
;                  units, though.)
;       DEM_INT  - [Optional] (float scalar)
;                  This is the integral of the inputs DEMT, DEM.
;                      DEM_INT = integral{ DEM(T) * dT }
;       QABORT   - [Optional] (Boolean) Indicates that the program
;                  exited gracefully without completing. (Might be
;                  useful for calling programs.)
;                  0: Program ran to completion.
;                  1: Program aborted before completion.
;
; EXAMPLES:
;
;       Basic usage:
;       IDL> help, demt, dem
;       DEMT            FLOAT     = Array[26]
;       DEM             FLOAT     = Array[26]
;       IDL> obs = xrt_dem2obs(demt, dem)
;       IDL> help, obs           ;; 14 default XRT channels
;       OBS             STRUCT    = -> <Anonymous> Array[14]
;       IDL> help, obs[3], /st
;       ** Structure <13736bc4>, 3 tags, length=28, data length=28, refs=2:
;          CHANNEL_NAME    STRING    'Ti-poly'
;          OBS             FLOAT           4109.93
;          OBS_UNITS       STRING    'DN s^-1 pix^-1'
;
; COMMON BLOCKS:
;
;       none
;
; NOTES:
;
;       1) There are three levels of verbosity.
;          a) "verbose" = highest priority. All errors and messages are
;                         displayed. ("if q_vb")
;          b) "quiet" = lower priority. No errors or messages are
;                       displayed. ("if q_qt")
;          c) neither = lowest priority. All errors and some messages are
;                       displayed. ("if not q_qt")
;
;       2) In the 'v2008-Jun-11' and earlier versions of this code, the
;          TRESP keyword had a default behavior wherein the default XRT
;          temperature responses would be automatically loaded via 
;          <calc_xrt_temp_resp.pro> if the user chose to not input their
;          own functions. In the 'v2015-Aug-29' version, this default
;          behavior was removed. The routine <calc_xrt_temp_resp.pro> has
;          been deprecated in favor of <make_xrt_wave_resp.pro> and 
;          <make_xrt_temp_resp.pro>. The former produces the effective 
;          areas, for which the user must consider the thickness of
;          the laminar contamination layers. The latter allows flexibility
;          in the selection of an emission model, which is a matrix of
;          spectra versus electron temperatures. Because of this increased
;          complexity of considerations in generating a set of instrument 
;          temperature response functions, the XRT managers have decided
;          that the user should explicitly make these choices, and should 
;          have to provide the set of functions via the TRESP keyword.
;          A user may learn more about producing XRT temperature responses
;          with <make_xrt_wave_resp.pro> and <make_xrt_temp_resp.pro> by
;          consulting the header documentation of those routines and by
;          referring to the relevant section of the XRT Analysis Guide.
;
; CONTACT:
;
;       Comments, feedback, and bug reports regarding this routine may be
;       directed to this email address:
;                xrt_manager ~at~ head.cfa.harvard.edu
;
; MODIFICATION HISTORY:
;
progver = 'v2007-May-22' ;--- (M.Weber) Written.
progver = 'v2008-Jun-11' ;--- (M.Weber) 'obs_units' determined by 
;                             'temp_resp_units'.
progver = 'v2015-Aug-29' ;--- (M.Weber) TRESP keyword functionality 
;                             modified such that it is now mandatory for
;                             the user to provide their own T response
;                             functions. Removed functionality whereby the
;                             routine <calc_xrt_temp_resp.pro> could be 
;                             used to retrieve default values of the XRT
;                             T responses, because that routine has since
;                             been deprecated in favor of 
;                             <make_xrt_temp_resp.pro>. Because of the
;                             complexity of selecting appropriate 
;                             contamination layers and emission models, it
;                             was deemed better to make those choices
;                             explicit for the user rather than relying on
;                             automatic assumptions.
;
;
;-
; =========================================================================


;=== Initial setup =======================================

  ;=== Set Booleans which control print statements.
  ;=== Keyword "verbose" overrules "quiet".
  q_vb = keyword_set(verbose)
  q_qt = keyword_set(quiet) and (not q_vb)

  ;=== Initialize program constants.
  prognam='XRT_DEM2OBS'
  prognul='           '

  ;=== Set some keyword Booleans.
  q_int   = keyword_set(dem_int)
  qtresp  = keyword_set(tresp)
  qstop   = keyword_set(qstop)
  qabort  = 0B


;=== Check inputs ========================================

  ;=== Check for number of inputs.
  if (n_params() ne 2) then begin
    if (q_qt eq 0) then box_message, $
      [prognam+': Must give two inputs: DEMT and DEM. Aborting.']
    qabort = 1B
    return, 0B
  endif

  ;=== DEM and DEMT have same length?
  ntemps = n_elements(demt)
  if (n_elements(dem) ne ntemps) then begin
    if (q_qt eq 0) then box_message, $
      [prognam+': DEMT and DEM must have same length. Aborting.']
    qabort = 1B
    return, 0B
  endif 

  ;=== Does TRESP have the right stuff?
  if qtresp then begin
    trtyp = datatype(tresp)
    q_recognized = 0B
    ;; Three successive conditions to be recognized:
    if (trtyp eq 'STC') then begin
      if required_tags(tresp, 'TYPE,CONFG,TEMP,TEMP_UNITS,' $
                       + 'TEMP_RESP,TEMP_RESP_UNITS,LENGTH') then begin
        if required_tags(tresp.confg, 'NAME') then q_recognized = 1B
      endif
    endif
    if not q_recognized then begin
      if (not q_qt) then box_message, [prognam+': Do not recognize' $
            + ' the TRESP structure. Aborting. (See', $
            prognul+'  header documentation for more info ' $
            + 'about this structure.)']
      qabort = 1B
      return, 0B
    endif
  endif else begin
    if (not q_qt) then print, $
      prognam+': Must provide T responses via TRESP keyword. Aborting.'
    qabort = 1B
    return, 0B
  endelse

  nchn = n_elements(tresp)


;=== Do work =============================================

  ;=== Define the output structure.
  str1 = ''
  if (tresp[0].temp_resp_units eq 'DN cm^5 s^-1 pix^-1') $
    then str1 = 'DN s^-1 pix^-1'
  if (tresp[0].temp_resp_units eq 'el cm^5 s^-1 pix^-1') $
    then str1 = 'el s^-1 pix^-1'
  obs_str = {channel_name:'', obs:1., obs_units:str1}
  obs_out = replicate(obs_str, nchn)

  ;=== Fill in the fields.
  obs_out.channel_name = tresp.confg.name

  for ii = 0,(nchn-1) do begin
    tlen = tresp[ii].length
    gfunc = interpol(tresp[ii].temp_resp[0:tlen-1], $
                     tresp[ii].temp[0:tlen-1], demT  )
    dT = (shift(demT,-1) - shift(demT,1)) * 0.5
    dT[0] = (demT[1] - demT[0])
    dT[ntemps-1] = (demT[ntemps-1] - demT[ntemps-2])
    obs_out[ii].obs = total(gfunc * dem * 10.^(demT) *alog(10.) * dT)
  endfor

  dem_int = total(dem * 10.^(demT) * dT)


;=== Finish ==============================================

  return, obs_out


END ;======================================================================
