FUNCTION make_xrt_wave_resp, index=index,                          $
                             contam_thick=contam_thick,            $
                             contam_time=contam_time,              $
                             chn_filename=chn_filename,            $
                             outfile=outfile, el_units=el_units,   $
                             verbose=verbose, quiet=quiet,         $
                             qabort=qabort, qstop=qstop

; =========================================================================
;+
; PROJECT:
;       Solar-B / XRT 
;
; NAME:
;       
;       MAKE_XRT_WAVE_RESP
;
; CATEGORY:
;       
;       Instrument response
;
; PURPOSE:
;
;       Produce the effective areas and spectral responses for a
;       set of XRT x-ray channels, accounting for some thickness
;       of the CCD contamination layer. The spectral response is
;       directly calculated from the effective area, and both are
;       functions of wavelength.
;
; CALLING SEQUENCE:
;
;       Result = MAKE_XRT_WAVE_RESP( { [index=index] OR
;                  [contam_thick=contam_thick] OR 
;                  [contam_time=contam_time] }
;                  [,chn_filename=chn_filename] [,outfile=outfile] 
;                  [,/el_units] [,/verbose] [,/quiet] [,qabort=qabort] 
;                  [,/qstop] )
;
; INPUTS:
;
;       INDEX        - [Optional*] (structure array, [Nimages])
;                      (*) ONE (and only one) of these three inputs MUST
;                      be specified: {INDEX, CONTAM_THICK, CONTAM_TIME}.
;                      This structure must be a standard XRT data
;                      "index" array, such as is produced by the
;                      Level-1 reformatter (<xrt_prep.pro>). (See
;                      the XRT Analysis Guide for a more detailed
;                      description of this structure.) If input is
;                      provided through this choice of keyword,
;                      then the image times will be used to determine
;                      contamination thicknesses and x-ray channels.
;                      (See the description of the "Return" output
;                      and Note #1.)
;       CONTAM_THICK - [Optional*] (two element vector) [CCD,filter1+2]
;                      (*) ONE (and only one) of these three inputs MUST
;                      be specified: {INDEX, CONTAM_THICK, CONTAM_TIME}.
;                      This input keyword may be used to specify a
;                      single pair of contamination layer thicknesses (in
;                      Angstroms). Thicknesses must be given as 
;                      [CCD thickness, combined filter1+2 thickness],
;                      where filter1+2 indicates the filters in filter
;                      wheel 1 and 2. The "Return" output will provide
;                      the responses for all of the XRT x-ray
;                      channels using this thickness. (See the
;                      description of the "Return" output and Note #1.)
;       CONTAM_TIME  - [Optional*] (string scalar)
;                      (*) ONE (and only one) of these three inputs MUST
;                      be specified: {INDEX, CONTAM_THICK, CONTAM_TIME}.
;                      This input must be in a time format that is
;                      recognizable by the SSWIDL program
;                      <anytim2utc.pro>. This input keyword may
;                      be used to specify a single "mission time",
;                      which will be used to specify a unique
;                      contamination thickness. The "Return" output
;                      will provide the responses for all of the
;                      XRT x-ray channels using this thickness.
;                      (See the description of the "Return" output
;                      and Note #1.)
;       CHN_FILENAME - [Optional] (string scalar)
;                      A filename of the form "xrt_channels_vNNNN.geny",
;                      where NNNN is a 4-digit version number. These
;                      files are the XRT channel configuration files
;                      distributed by the XRT Team.  The default
;                      behavior (i.e., if CHN_FILENAME is not used)
;                      will be to get the latest, most correct file.
;                      (Older versions are distributed in case
;                      earlier analysis must be recreated.) The
;                      input may be a full or relative pathname.
;                      If it is a relative pathname, the program
;                      will first look in $SSW_XRT/idl/response/channels/,
;                      and then look in the current working directory.
;       OUTFILE      - [Optional] (string scalar)
;                      Write the constructed wave response structure
;                      to the specified file, using <savegenx.pro>.
;                      The extension ".geny" will be automatically
;                      appended to the filename. See "Return" output
;                      for structure description.
;
; KEYWORDS:
;
;       /EL_UNITS    - [Optional] (Boolean) If set, then the units of
;                      the spectral response (in the SPEC_RESP array
;                      output) will be [el cm^2 sr ph^-1 pix^-1]. 
;                      Otherwise, the default is to produce the
;                      the response in units of [DN cm^2 sr ph^-1 pix^-1].
;       /VERBOSE     - [Optional] (Boolean) If set, print out extra
;                      information. Overrides "/quiet" (see Note #4).
;       /QUIET       - [Optional] (Boolean) If set, suppress messages
;                      (see Note #4).
;       /QSTOP       - [Optional] (Boolean) For debugging.
;
;
; OUTPUTS:
;
;       Return      - [Mandatory] (structure array,
;       (WAVE_RESP)                {XRT_wave_resp_vNNNN} [Nchannels])
;                     This structure contains data and information about
;                     the effective areas and spectral response functions
;                     for a set of XRT x-ray channels. This is the input
;                     that describes the instrument response.
;
;                     Here is a listing of the fields of the {XRT_wave_resp}
;                     structure. Descriptions are provided further down.:
;
;                    WAVE_RESP {XRT_wave_resp_vNNNN}
;                    - TYPE            (string scalar)
;                    - WRS_STR_VERSION (string scalar)
;                    - WRS_STR_DESCR   (string scalar)
;                    - NAME            (string scalar)
;                    - CONFG  (structure scalar, {XRT_chn_config_ref_vNNNN})
;                    - CONTAM (structure scalar, {XRT_contam_ref_vNNNN})
;                    - FCONTAM (structure scalar, {XRT_filt_contam_ref_vNNNN})
;                    - EFFAR  (structure scalar, {XRT_eff_area_vNNNN})
;                    - SPRSP  (structure scalar, {XRT_spec_resp_vNNNN})
;                    - HISTORY         (string array, [3])
;                    - COMMENTS        (string array, [5])
;
;                     Here are descriptions of the fields in the
;                     {XRT_wave_resp} structure.:
;
;                     TYPE: (string scalar)
;                          [Default value = 'XRT_wave_resp'.]
;                          This is the generic name of the structure
;                          that contains the wavelength response
;                          functions and information. The version
;                          of the structure definition might evolve,
;                          but the TYPE should remain constant. See
;                          WRS_STR_VERSION. This field should NOT
;                          be changed.
;                     WRS_STR_VERSION: (string scalar)
;                          [Default value = 'XRT_wave_resp_vNNNN',
;                          where NNNN is a 4-digit number.] This
;                          is the version number of the "XRT_wave_resp"
;                          structure definition. In addition to
;                          being recorded in this field, this is
;                          also the "unique structure name" in the
;                          IDL sense. This field should NOT be changed.
;                     WRS_STR_DESCR: (string scalar)
;                          This is a sentence or two that describes
;                          the purpose of this structure type. This
;                          field should NOT be changed.
;                     NAME: (string scalar)
;                          This is a name for these wavelength
;                          responses for this channel and contamination
;                          thickness. On creation, it inherits the
;                          name of the EFF_AREA structure that was
;                          used to create it. This string concisely
;                          identifies these dependent wavelength
;                          responses (although it may not be unique).
;                          This field MAY be changed, but the default
;                          is recommended.
;                     CONFG: (structure scalar, {XRT_chn_config_ref_vNNNN})
;                          This structure contains information about
;                          the instrument components and the history
;                          of their role in the processing that has
;                          been performed on this channel to produce
;                          this temperature response function. 
;                          Large arrays (such as the
;                          channel transmission function) have been
;                          abridged, but there should be sufficient
;                          information in this structure to recover
;                          or reproduce the corresponding full
;                          channel structure (of type "XRT_chn_config").
;                          For a more complete description of this
;                          complicated structure, see the XRT
;                          Analysis Guide. The base set of channels
;                          is provided in the XRT SSWIDL tree by a
;                          file with a pathname like this:
;       $SSW_XRT/idl/response/channels/xrt_channels_vNNNN.geny .
;
;                          Here is a listing of the top-level fields
;                          of the "XRT_chn_config" structure.
;
;                        CONFG {XRT_chn_config_ref_vNNNN}
;                         - TYPE            (string scalar)
;                         - CHN_STR_VERSION (string scalar)
;                         - CHN_STR_DESCR   (string scalar)
;                         - NAME            (string scalar)
;                         - LONG_NAME       (string scalar)
;                         - OBSERVATORY     (string scalar)
;                         - INSTRUMENT      (string scalar)
;                         - GEOM     (structure scalar,{XRT_geometry_vNNNN})
;                         - EN_FILTER (structure scalar,{XRT_filter_ref_vNNNN})
;                         - MIRROR1   (structure scalar,{XRT_mirror_ref_vNNNN})
;                         - MIRROR2   (structure scalar,{XRT_mirror_ref_vNNNN})
;                         - FP_FILTER1 (structure scalar,{XRT_filter_ref_vNNNN})
;                         - FP_FILTER2 (structure scalar,{XRT_filter_ref_vNNNN})
;                         - CCD        (structure scalar,{XRT_ccd_ref_vNNNN})
;                         - CONFIG_FILENAME (string scalar)
;                         - HISTORY         (string array, [3])
;                         - COMMENTS        (string array, [5])
;
;                     CONTAM: (structure scalar, {XRT_contam_ref_vNNNN})
;                          This structure contains information about
;                          the particular thickness of the CCD
;                          contamination layer (which affects the
;                          response of the channel) and the history
;                          of its processing.  Large arrays (such
;                          as the contamination's transmission
;                          function) have been abridged, but there
;                          should be sufficient information in this
;                          structure to recover or reproduce the
;                          corresponding full contamination structure
;                          (of type "XRT_contam"). More information
;                          about the content of this "XRT_contam_ref"
;                          type of structure may be found in the
;                          XRT Analysis Guide or in the program
;                          header of <make_xrt_ea.pro>.
;
;                          Here is a listing of the fields of the
;                          "XRT_contam_ref" structure.
;
;                          CONTAM {XRT_contam_ref_vNNNN}
;                          - TYPE            (string scalar)
;                          - CTM_STR_VERSION (string scalar)
;                          - CTM_STR_DESCR   (string scalar)
;                          - NAME            (string scalar)
;                          - LONG_NAME       (string scalar)
;                          - MATERIAL        (string scalar)
;                          - DENS            (float scalar)
;                          - DENS_UNITS      (string scalar)
;                          - THICK           (float scalar)
;                          - THICK_UNITS     (string scalar)
;                          - THICK_TIME      (string scalar)
;                          - DATA_FILES      (string array, [5])
;                          - HISTORY         (string array, [3])
;                          - COMMENTS        (string array, [5])
;                    FCONTAM: (structure scalar, {XRT_filt_contam_ref_vNNNN})
;                          This structure contains information about
;                          the particular thickness of the combined filter 
;                          contamination layer (which affects the
;                          response of the channel) and the history
;                          of its processing.  Large arrays (such
;                          as the contamination's transmission
;                          function) have been abridged, but there
;                          should be sufficient information in this
;                          structure to recover or reproduce the
;                          corresponding full contamination structure
;                          (of type "XRT_filt_contam"). More information
;                          about the content of this "XRT_filt_contam_ref"
;                          type of structure may be found in the
;                          XRT Analysis Guide or in the program
;                          header of <make_xrt_ea.pro>.
;
;                          Here is a listing of the fields of the
;                          "XRT_filt_contam_ref" structure.
;
;                          FCONTAM {XRT_filt_contam_ref_vNNNN}
;                          - TYPE            (string scalar)
;                          - FCTM_STR_VERSION (string scalar)
;                          - FCTM_STR_DESCR   (string scalar)
;                          - FILTER1         (string scalar)
;                          - FILTER2         (string scalar)
;                          - NAME            (string scalar)
;                          - LONG_NAME       (string scalar)
;                          - MATERIAL        (string scalar)
;                          - DENS            (float scalar)
;                          - DENS_UNITS      (string scalar)
;                          - THICK           (float scalar)
;                          - THICK_UNITS     (string scalar)
;                          - THICK_TIME      (string scalar)
;                          - DATA_FILES      (string array, [5])
;                          - HISTORY         (string array, [3])
;                          - COMMENTS        (string array, [5])
;
;                     EFFAR: (structure scalar, {XRT_eff_area_vNNNN})
;                          This structure contains information about
;                          the channel's effective area and about
;                          the history of its processing. More
;                          information about the content of this
;                          "XRT_eff_area" type of structure may be
;                          found in the XRT Analysis Guide or in
;                          the program header of <make_xrt_ea.pro>.
;
;                          Here is a listing of the fields of the
;                          "XRT_eff_area" structure. 
;
;                          EFF_AREAS {XRT_eff_area_vNNNN}
;                          - TYPE            (string scalar)
;                          - EFF_STR_VERSION (string scalar)
;                          - EFF_STR_DESCR   (string scalar)
;                          - NAME            (string scalar)
;                          - WAVE            (float array, [Nwave])
;                          - WAVE_UNITS      (string scalar)
;                          - EFF_AREA        (float array, [Nwave])
;                          - EFF_AREA_UNITS  (string scalar)
;                          - LENGTH          (long scalar)
;                          - HISTORY         (string array, [3])
;                          - COMMENTS        (string array, [5])
;
;                     SPRSP: (structure scalar, {XRT_spec_resp_vNNNN})
;                          This structure contains information about 
;                          the channel's spectral response and about
;                          the history of its processing. More
;                          information about the content of this
;                          "XRT_spec_resp" type of structure may be
;                          found in the XRT Analysis Guide or in
;                          the program header of <make_xrt_sr.pro>.
;
;                          Here is a listing of the fields of the
;                          "XRT_spec_resp" structure.
;
;                          SPEC_RESP {XRT_spec_resp_vNNNN}
;                          - TYPE            (string scalar)
;                          - SRS_STR_VERSION (string scalar)
;                          - SRS_STR_DESCR   (string scalar)
;                          - NAME            (string scalar)
;                          - WAVE            (float array, [Nwave])
;                          - WAVE_UNITS      (string scalar)
;                          - SPEC_RESP       (float array, [Nwave])
;                          - SPEC_RESP_UNITS (string scalar)
;                          - LENGTH          (long scalar)
;                          - GAIN_USED       (float scalar)
;                          - HISTORY         (string array, [3])
;                          - COMMENTS        (string array, [5])
;
;                     HISTORY: (string array, [3])
;                          This text array is for XRT programs to
;                          record any instance in which they have
;                          modified the content of the "XRT_temp_resp"
;                          structure for this particular channel.
;                          On creation, a line is added for the
;                          creation of the "XRT_temp_resp" structure
;                          in <make_xrt_temp_resp.pro>.  An entry
;                          string is composed of (a) a program name,
;                          (b) the program's version/date, (c) colon
;                          separator, (d) Timestamp (in parentheses)
;                          of when the program completed the described
;                          action, and (e) a summation of what the
;                          program created or modified in the
;                          "XRT_temp_resp" structure. Values are
;                          inserted starting at the lowest address
;                          of this array. Remaining unused addresses
;                          are filled with the empty string. Filled
;                          strings should NOT be overwritten. Users
;                          should use the COMMENTS field to add
;                          their own notations to this structure.
;                     COMMENTS: (string array, [5])
;                          A tag for adding notations regarding the
;                          temperature response described for this
;                          XRT channel. Users and programs are
;                          encouraged to put content in the lower
;                          addresses, and assign empty strings {''}
;                          to the higher, unused addresses.
;
;       QABORT      - [Optional] (Boolean) Indicates whether 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 #1 (for a datacube INDEX, DATA):
;       IDL> help, data, index
;       IDL> w_resp = make_xrt_wave_resp(index=index)
;       IDL> help, w_resp
;       IDL> help, w_resp, w_resp.effar, w_resp.sprsp, /st
;
;       Basic usage #2 (for all channels with single pair of contamination 
;                       thicknesses):
;       IDL> w_resp = make_xrt_wave_resp(contam_thick=[1000,500.])  ;; Angstroms
;       IDL> help, w_resp
;       IDL> help, w_resp, w_resp.effar, w_resp.sprsp, /st
;
;       Basic usage #3 (for all channels at single mission time):
;       IDL> ctime = '2007-May-25 10:00:00'
;       IDL> w_resp = make_xrt_wave_resp(contam_time=ctime) 
;       IDL> help, w_resp
;       IDL> help, w_resp, w_resp.effar, w_resp.sprsp, /st
;
;       Plotting the effective area for the 3rd image:
;       IDL> ichn = 2
;       IDL> print, w_resp[ichn].effar.name
;       IDL> wlen = w_resp[ichn].effar.length
;       IDL> plot,  w_resp[ichn].effar.wave[0:wlen-1], $
;       IDL>        w_resp[ichn].effar.eff_area[0:wlen-1]
;
;       Check the x-ray channel ID and contamination thickness:
;       (This info should be in w_resp[ichn].name, too.)
;       IDL> print, w_resp[ichn].confg.name
;       IDL> print, w_resp[ichn].contam.thick, $
;       IDL>        w_resp[ichn].contam.thick_units
;
; COMMON BLOCKS:
;
;       none
;
; NOTES:
;
;       1) A discussion of the input and output modalities.
;
;          One (and only one) of the following three input keywords
;          MUST be used: {INDEX, CONTAM_THICK, CONTAM_TIME}. These
;          are used to input information about the contamination
;          thicknesses and x-ray channels for which the effective
;          areas and spectral responses will be calculated. This
;          choice also affects the "Return" output.
;
;          Input modes:
;
;          A) Contamination time: INDEX or CONTAM_TIME may be used
;             to indicate times during the mission which may be
;             correlated to specific contamination thicknesses.
;
;          B) Contamination thickness: CONTAM_THICK may be used to
;             indicate an explicit contamination thicknesses, without
;             reference to any mission time.
;
;          Output modes:
;
;          C) "Image series": If INDEX is used to specify a sequence
;             (of length Nimages) of image times paired to x-ray
;             channels, then the "Return" output will be an array
;             (of length Nimages) of "XRT_wave_resp" structures
;             corresponding to those images. For example, if INDEX
;             represents 100 "Al-poly" images, then the output array
;             will represent the "Al-poly" response functions for
;             those 100 contamination times.
;
;          D) "All channels": If CONTAM_THICK is used to specify a
;             single pair [CCD,filter1+2] of contamination thicknesses, or 
;             if CONTAM_TIME is used to specify a single contamination time, 
;             then the "Return" output will be an array (of length Nchannel)
;             of "XRT_wave_resp" structures corresponding to the
;             set of XRT x-ray channels, all using that single
;             contamination thickness pair. For example, there are 9
;             "single filter" x-ray channels, so the output array
;             will represent all 9 channels with a single contamination
;             thickness  pair applied.  
;
;          Please note that it is NOT possible to generate an "all
;          channels" output array for more than one contamination
;          thickness. In other words, it is not currently possible
;          to directly create a 2-dim output array of lengths
;          [Nimages, Nchannels]. (That functionality might be
;          implemented in the future.) However, this can easily be
;          created by the user by calling <make_xrt_wave_resp.pro>
;          in a loop. However, the output structures have several
;          arrays of size fltarr(5000), so one should be careful
;          about calculating responses for very large datasets.
;
;
;       2) This version of the program assumes the pixel size is
;          that of a "full-resolution" XRT CCD pixel. It does not yet
;          account for any pixel summing ("image binning").
;
;       3) 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")
;
;       4) This routine replaces and deprecates <calc_xrt_effarea.pro> and 
;          <calc_xrt_spec_resp.pro>. Those older routines can not account 
;          for recent updates to the calibrations, including the 
;          CCD and filter contamination layers in particular.
;
; 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 = 'v2008-Sep-01' ;--- (M.Weber) Written. Takes over calculations
;                             previously performed by <calc_xrt_effarea.pro>
;                             and <calc_xrt_spec_resp.pro>--- those
;                             routines are deprecated.
progver = 'v2008-Oct-01' ;--- (M.Weber) Reviewed version.
progver = 'v2008-Nov-21' ;--- (M.Weber) Changed path separator from 
;                             forward slash to path_sep().
progver = 'v2009-Nov-20' ;--- (S.Saar) Updated program to include filter
;                             contamination.
;
progver = 'v2012-March-16' ;--- (K. Reeves) Added channel filename to output if verbose is set.
;
;
;-
; =========================================================================


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

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


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


  ;=== Announce version of program.
  if q_vb then box_message, prognam+': Running ' + progver + '.'
  if q_vb then print, prognam+': Performing initial setup...'


  ;=== Set some keyword Booleans.
  qindex   = keyword_set(index)
  qctthick = keyword_set(contam_thick)
  qcttime  = keyword_set(contam_time)
  qchnfile = keyword_set(chn_filename)
  qoutfile = keyword_set(outfile)
  qelunits = keyword_set(el_units)
  qstop    = keyword_set(qstop)
  qabort   = 0B
  
  intype = qctthick + qcttime*2


  ;=== Some basic program values.
  ps = path_sep()
  chn_dir = get_logenv('$SSW_XRT') + ps + 'idl' + ps + 'response' $
            + ps + 'channels' + ps
  chn_pattern = 'xrt_channels_v[0-9][0-9][0-9][0-9].geny'

  ;=== Identify some tagnames that will need to exist 
  ;=== in some input structures. BE CAREFUL about redefining
  ;=== this program's output structures ==> these arrays
  ;=== might need to be updated.
  idx_tagnames = ['DATE_OBS', 'EC_FW1_', 'EC_FW2_']
  geo_tagnames = ['type', 'geo_str_version', 'geo_str_descr', 'name', $
                  'long_name', 'foc_len', 'foc_len_units',            $
                  'aperture_area', 'aperture_area_units',             $
                  'data_files', 'history', 'comments'                  ]
  chn_tagnames = ['type', 'chn_str_version', 'chn_str_descr', 'name', $
                 'long_name', 'observatory', 'instrument', 'geom',    $
                 'en_filter', 'mirror1', 'mirror2', 'fp_filter1',     $
                 'fp_filter2', 'ccd', 'config_filename',              $
                 'history', 'comments'                                 ]



  ;; In this next bit, we define some structure templates
  ;; that will be used further on.


  ;=== Define the {XRT_filter_ref} stucture.
  flt_str_version = 'XRT_FILTER_REF_V0001'
  flt_ref = create_struct(name=flt_str_version,                         $
                        'type', 'XRT_FILTER_REF',                       $
             'flt_str_version', flt_str_version,                        $
               'flt_str_descr', 'Specifies a filter configuration, '    $
                                + 'without the transmission function.', $
                        'name', '',                                     $
                   'long_name', '',                                     $
                    'material', strarr(4),                              $
                       'thick', fltarr(4),                              $
                 'thick_units', '',                                     $
                        'dens', fltarr(4),                              $
                  'dens_units', '',                                     $
                   'substrate', '',                                     $
                  'mesh_trans', 0.0,                                    $
                  'data_files', strarr(5),                              $
                     'history', strarr(3),                              $
                    'comments', strarr(5)                                )
  flt_tagnames = tag_names(flt_ref)


  ;=== Define the {XRT_mirror_ref} stucture.
  mir_str_version = 'XRT_MIRROR_REF_V0001'
  mir_ref = create_struct(name=mir_str_version,                         $
                          'type', 'XRT_MIRROR_REF',                     $
               'mir_str_version', mir_str_version,                      $
                 'mir_str_descr', 'Specifies a mirror configuration, '  $
                                  + 'without the reflection function.', $
                          'name', '',                                   $
                     'long_name', '',                                   $
                      'material', '',                                   $
                          'dens', 0.0,                                  $
                    'dens_units', '',                                   $
                   'graze_angle', 0.0,                                  $
             'graze_angle_units', '',                                   $
                    'data_files', strarr(5),                            $
                       'history', strarr(3),                            $
                      'comments', strarr(5)                              )
  mir_tagnames = tag_names(mir_ref)


  ;=== Define the {XRT_ccd_ref} stucture.
  ccd_str_version = 'XRT_CCD_REF_V0001'
  ccd_ref = create_struct(name=ccd_str_version,                    $
                         'type', 'XRT_CCD_REF',                    $
              'ccd_str_version', ccd_str_version,                  $
                'ccd_str_descr', 'Specifies a CCD configuration, ' $
                                 + 'without the Q.E. function.',   $
                         'name', '',                               $
                    'long_name', '',                               $
                    'ev_per_el', 0.0,                              $
              'ev_per_el_units', '',                               $
                    'full_well', 0.0,                              $
              'full_well_units', '',                               $
                       'gain_l', 0.0,                              $
                       'gain_r', 0.0,                              $
                   'gain_units', '',                               $
                   'pixel_size', 0.0,                              $
             'pixel_size_units', '',                               $
                   'data_files', strarr(5),                        $
                      'history', strarr(3),                        $
                     'comments', strarr(5)                          )
  ccd_tagnames = tag_names(ccd_ref)


  ;; NOTE: The {XRT_chn_config_ref} structure gets defined later
  ;; in this program, because it must inherit a substructure from 
  ;; a variable that doesn't exist at this point.


  if q_vb then print, prognam+': Performing initial setup... OK'


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

  if q_vb then print, prognam+': Checking inputs...'

  ;=== Check that some input has been given
  ;=== to determine the contamination.
  if ( (qindex + qctthick + qcttime) ne 1) then begin
    if (not q_qt) then box_message,                                      $
        [prognam+': One (and only one) of these keywords must be input:',$
         prognul+'  INDEX, CONTAM_THICK, or CONTAM_TIME.',               $
         prognul+'  See program header. Aborting...'                      ]
    qabort = 1B
    return, 0
  endif


  ;=== Check type of INDEX.
  if qindex then begin

    if (datatype(index) ne 'STC') then begin
      if (not q_qt) then box_message,                   $
        [prognam+': Input INDEX must be a structure. ', $ 
         prognul+'  See program header. Aborting...'     ]
      qabort = 1B
      return, 0 

    endif else begin

      if not required_tags(index[0], idx_tagnames) then begin
        if (not q_qt) then box_message,                          $
          [prognam+': Input INDEX does not have required tags:', $
           prognul+'  ' + idx_tagnames,                          $
           prognul+'  See program header. Aborting...'            ]
        qabort = 1B
        return, 0
      endif

    endelse
  endif

  ;=== Check type of CONTAM_THICK.
  if qctthick then begin
    if ( (n_elements(contam_thick) ne 2) or           $
         (is_number(contam_thick[0]) ne 1) ) then begin
      if (not q_qt) then box_message,                             $
        [prognam+': Input CONTAM_THICK must be an array of two numbers.', $
         prognul+'  See program header. Aborting...'               ]
      qabort = 1B
      return, 0
    endif
  endif

  ;=== Check type of CONTAM_TIME.
  if qcttime then begin
    if ( (n_elements(contam_time) ne 1) or              $
         (datatype(contam_time[0]) ne 'STR') ) then begin
      if (not q_qt) then box_message,                            $  
        [prognam+': Input CONTAM_TIME must be a scalar string.', $
         prognul+'  See program header. Aborting...'              ]
      qabort = 1B
      return, 0 
    endif
  endif

  ;=== Check type of CHN_FILENAME.
  if qchnfile then begin
    if ( (n_elements(chn_filename) ne 1) or              $
         (datatype(chn_filename[0]) ne 'STR') ) then begin
      if (not q_qt) then box_message,                             $
        [prognam+': Input CHN_FILENAME must be a scalar string.', $
         prognul+'  See program header. Aborting...'               ]
      qabort = 1B
      return, 0
    endif
  endif

  ;=== Check type of OUTFILE.
  if qoutfile then begin
    if ( (n_elements(outfile) ne 1) or              $
         (datatype(outfile[0]) ne 'STR') ) then begin
      if (q_qt eq 0) then box_message,                            $
          [prognam+': Output OUTFILE has wrong type. ',           $
           prognul+'  See program header.',                       $
           prognul+'  Proceeding, but will not write to OUTFILE...']
      qoutfile = 0B
    endif
  endif


  if q_vb then print, prognam+': Checking inputs... OK'


; === Find the channels file. ========================

  if q_vb then print, prognam+': Looking for channels file...'

  ;; If a channel filename was passed in...
  if qchnfile then begin

    ;; If a full pathname was passed in...
    if (strmid(chn_filename,0,1) eq '/') then begin
      search1 = file_search(chn_filename+'.geny', count=count1)
      if (count1 eq 1) then begin
        actual_filename = chn_filename

      ;; If cannot find the file...
      endif else begin
        if (not q_qt) then box_message,                         $
          [prognam+': Cannot find file in input CHN_FILENAME:', $
           chn_filename+'.geny',                                $
           prognul+'  Check file location. Aborting...'          ]
        qabort = 1B
        return, 0
      endelse


    ;; Else if a relative pathname was passed in...
    endif else begin

      ;; Look first in default channels directory...
      search2 = file_search(chn_dir + chn_filename+'.geny', count=count2)
      if (count2 eq 1) then begin
        actual_filename = chn_dir + chn_filename

      ;; Look second in pwd.
      endif else begin
        search3 = file_search(chn_filename+'.geny', count=count3)
        if (count3 eq 1) then begin
          actual_filename = chn_filename

        ;; Else if cannot find file in either location...
        endif else begin
          if (not q_qt) then box_message,                             $
            [prognam+': Cannot find file in input CHN_FILENAME',      $
             prognul+'  in either of these locations:',               $
             chn_dir + chn_filename+'.geny',                          $  
             './' + chn_filename+'.geny',                             $
             prognul+'  See program header and check file location.', $
             prognul+'  Aborting...'                                   ]
          qabort = 1B
          return, 0
        endelse

      endelse
    endelse

  ;; Else if a channel filename was NOT passed in...
  endif else begin

    ;; Look for files in default channels directory...
    search4 = file_search(chn_dir + chn_pattern, count=count4)

    ;; If cannot find expected files...
    if (count4 eq 0) then begin
      if (not q_qt) then box_message, $ 
        [prognam+': Cannot find any expected files of this type:',       $
         chn_pattern, $
         prognul+'  in the expected location:',                          $  
         '$SSW_XRT/idl/response/channels/',                              $
         prognul+'  See program header and check that your XRT tree',    $
         prognul+'  has this directory and these files, or use the',     $
         prognul+'  CHN_FILENAME input to specify an XRT channel file.', $
         prognul+'  Aborting...'                                          ]
        qabort = 1B
        return, 0 

    ;; Else if can find expected files, then identify latest version.
    endif else begin
      namestart = rstrpos(search4, '/')
      version_nos = long(strmid(search4,namestart[0]+16,4))
      ss_max = where(version_nos eq max(version_nos))
      actual_filename = search4[ss_max[0]]
    endelse
  endelse


  if q_vb then begin 
     print, prognam+': Looking for channels file... OK '
     print, prognam+': channel file: ' + actual_filename
  endif

; === Read the channels file =========================
; === and check the contents. ========================

  if q_vb then print, prognam+': Reading the channels file...'

  restgenx, file=actual_filename, channels, /quiet

  ;; If CHANNELS isn't a structure...
  if (datatype(channels[0]) ne 'STC') then begin
    if (not q_qt) then begin
      box_message, [prognam+': This channel file does not contain the '  $
                           +'expected fields:']
      print, actual_filename
      box_message,[prognam+': See program header & check the file contents. ', $
                    prognul+'The CHN_FILENAME input may be used to specify',   $
                    prognul+'  an alternate XRT channel file. Aborting...'   ]
    endif
    qabort = 1B
    return, 0
  endif 

  ;; If CHANNELS doesn't have the necessary content...
  ;; Only checking for tagnames. Not worrying whether all
  ;; the tags and substructures have the right type of
  ;; content. Can add those checks if it becomes a problem.

  ;; If the channels structure doesn't have required fields...
  if not required_tags(channels[0], chn_tagnames) then begin
    qabort = 1B

  ;; Else if the channels substructures don't have required fields...
  endif else begin
    if ( (not required_tags(channels[0].geom,       geo_tagnames)) or $
         (not required_tags(channels[0].en_filter,  flt_tagnames)) or $
         (not required_tags(channels[0].mirror1,    mir_tagnames)) or $
         (not required_tags(channels[0].mirror2,    mir_tagnames)) or $
         (not required_tags(channels[0].fp_filter1, flt_tagnames)) or $
         (not required_tags(channels[0].fp_filter2, flt_tagnames)) or $
         (not required_tags(channels[0].ccd,        ccd_tagnames))    $
       ) then qabort = 1B
  endelse

  ;; If any of the channel tagnames aren't correct, then abort...
  if qabort then begin
    if (not q_qt) then begin
      box_message, [prognam+': This channel file does not contain the '  $
                           +'expected fields:']
      print, actual_filename
      box_message, [prognam+': See program header and check the file contents.', $
                    prognul+'  The CHN_FILENAME input may be used to specify', $
                    prognul+'  an alternate XRT channel file. Aborting...']
    endif
    return, 0
  endif


  if q_vb then print, prognam+': Reading the channels file... OK'


; === Sort channels. ===========================

  ;; If a single contamination thickness or time was input,
  ;; then there will be "Nchannels" effective areas calculated---
  ;; one for each XRT channel. The result is a response for 
  ;; every XRT channel with that single contamination thickness.

  ;; If, instead, a datacube's index of length "Ndata" was input,
  ;; then the result will match each image's time to a thickness,
  ;; and the result will be one response matched to each image's channel.

  ;; These three inputs have already been tested to be mutually exclusive:
  ;; INDEX, CONTAM_TIME, CONTAM_THICK.


  if q_vb then print, prognam+': Sorting the channels...'

  case 1 of

    qcttime:  begin
        nchn = n_elements(channels)
        input1 = replicate(contam_time, nchn)
      end

    qctthick: begin
        nchn = n_elements(channels)
        input1 = rebin(contam_thick, 2, nchn)
      end

    qindex:   begin
        nchn = n_elements(index)
        input1 = index

        ;; Re-sort CHANNELS to match INDEX array.
        chn_filts = channels.fp_filter1.name + channels.fp_filter2.name
        idx_filts = repchar(index.ec_fw1_ + index.ec_fw2_, '_', '-')
        ss_match = lonarr(nchn)
        for ii = 0,(nchn-1) do begin
          ss_match[ii] = (where(chn_filts eq idx_filts[ii]))[0]
        endfor
        channels = (temporary(channels))[ss_match]
      end

  endcase


  if q_vb then print, prognam+': Sorting the channels... OK'


; === Get effective areas. ===========================

  if q_vb then print, prognam+': Getting effective areas...'

  effar = make_xrt_ea(input1, channels, intype=intype,       $
                      contam=contam, fcontam=fcontam, verbose=verbose, $
                      quiet=quiet, qabort=qabort, qstop=qstop      )

  ;; Check whether subroutine succeeded.
  if qabort then begin
    if (not q_qt) then box_message,                         $
      [prognam+': The subroutine MAKE_XRT_EA.PRO aborted.', $
       prognul+'  Aborting...'                               ]
    qabort = 1B
    return, 0
  endif

  if q_vb then print, prognam+': Getting effective areas... OK'


; === Get spectral responses. ========================

  if q_vb then print, prognam+': Getting spectral responses...'

  sprsp = make_xrt_sr(effar, channels,              $
                      verbose=verbose, quiet=quiet, $
                      qabort=qabort, qstop=qstop     )

  ;; Check whether subroutine succeeded.
  if qabort then begin
    if (not q_qt) then box_message,                         $
      [prognam+': The subroutine MAKE_XRT_SR.PRO aborted.', $
       prognul+'  Aborting...'                               ]
    qabort = 1B
    return, 0
  endif

  if q_vb then print, prognam+': Getting spectral responses... OK'


; === Finish defining and initializing the =========
; === structure definitions for the output. ========

  if q_vb then print, prognam+': Initializing output substructures...'


  ;=== Define the {XRT_chn_config_ref} stucture.
  ccr_str_version = 'XRT_CHN_CONFIG_REF_V0001'
  ccr_ref = create_struct(name=ccr_str_version,                 $
                        'type', 'XRT_CHN_CONFIG_REF',           $
             'ccr_str_version', ccr_str_version,                $
               'ccr_str_descr', 'Specifies an XRT instrument '  $
                                + 'configuration, without the ' $
                                + 'transmission function.',     $
                        'name', '',                             $
                   'long_name', '',                             $
                 'observatory', '',                             $
                  'instrument', '',                             $
                        'geom', channels[0].geom,               $
                   'en_filter', flt_ref,                        $
                     'mirror1', mir_ref,                        $
                     'mirror2', mir_ref,                        $
                  'fp_filter1', flt_ref,                        $
                  'fp_filter2', flt_ref,                        $
                         'ccd', ccd_ref,                        $
             'config_filename', '',                             $
                     'history', strarr(3),                      $
                    'comments', strarr(5)                        )


  ;=== Define the {XRT_wave_resp} stucture.   **** added fcontam tag
  wrs_str_version = 'XRT_WAVE_RESP_V0002'
  wrs_ref = create_struct(name=wrs_str_version,                            $
                        'type', 'XRT_WAVE_RESP',                           $
             'wrs_str_version', wrs_str_version,                           $
               'wrs_str_descr', 'Provides effective area and spectral '    $
                                + 'response function for an XRT channel, ' $
                                + 'for given thicknesses of the CCD '      $
                                + 'and filter contamination layers.',      $
                        'name', '',                                        $
                       'confg', ccr_ref,                                   $
                      'contam', contam[0],                                 $
                      'fcontam', fcontam[0],                               $
                       'effar', effar[0],                                  $
                       'sprsp', sprsp[0],                                  $
                     'history', strarr(3),                                 $
                    'comments', strarr(5)                                   )


  ;=== Prepare the {XRT_wave_resp} stucture array.
  wave_resp = replicate(wrs_ref, nchn)

  wave_resp.name                  = channels.name

  confg = wave_resp.confg
  confg.name            = channels.name
  confg.long_name       = channels.long_name
  confg.observatory     = channels.observatory
  confg.instrument      = channels.instrument
  confg.config_filename = channels.config_filename
  confg.history         = channels.history
  confg.comments        = channels.comments
  copy_struct, channels.geom,       confg, select='geom', /recur_to
  copy_struct, channels.en_filter,  confg, select='en_filter', /recur_to
  copy_struct, channels.mirror1,    confg, select='mirror1', /recur_to
  copy_struct, channels.mirror2,    confg, select='mirror2', /recur_to
  copy_struct, channels.fp_filter1, confg, select='fp_filter1', /recur_to
  copy_struct, channels.fp_filter2, confg, select='fp_filter2', /recur_to
  copy_struct, channels.ccd,        confg, select='ccd', /recur_to

  copy_struct, confg, wave_resp, select='confg', /recur_to

  copy_struct, contam,                wave_resp, select='contam', /recur_to
  copy_struct, fcontam,                wave_resp, select='fcontam', /recur_to
  copy_struct, effar,                 wave_resp, select='effar',  /recur_to
  copy_struct, sprsp,                 wave_resp, select='sprsp',  /recur_to


  if q_vb then print, prognam+': Initializing output substructures... OK'


; === Deal with units ============================

  ;; If there was no request to maintain "el..." units,
  ;; then convert to "DN..." units for the SPEC_RESP.
  if (qelunits eq 0) then begin

    if q_vb then print, prognam+': Converting units...'

    ;; The gain choices for each channel structure...
    gain_options = [[channels.ccd.gain_r],[channels.ccd.gain_l]]

    ;; If there's an INDEX, then use that to figure out
    ;; which gains to use.
    if qindex then begin

      ;; Use index.ccd_read to pick an option for each channel structure.
      ;; This leaves a 1D array of gains.
      gain_choices = index.ccd_read  ;; 0=R, 1=L readout port.

    ;; Else if there's no INDEX, then just assume default port.
    endif else begin

      ;; Just assume default port, which is the Right port.
      gain_choices = lonarr(nchn)  ;; 0=R readout port
    endelse

    ;; Make the 1D list of gain values to use.
    gains = gain_options[lindgen(nchn), gain_choices]

    ;; Apply gain values to SPEC_RESP.
    for ii = 0,(nchn-1) do begin
      wave_resp[ii].sprsp.spec_resp = wave_resp[ii].sprsp.spec_resp $
                                      / gains[ii]
    endfor

    ;; Record gain values used.
    wave_resp.sprsp.gain_used = gains

    ;; Adjust units strings.
    wave_resp.sprsp.spec_resp_units = 'DN cm^2 sr ph^-1 pix^-1'


    if q_vb then print, prognam+': Converting units... OK'

  endif


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

  get_utc, utc, /stime
  hist_string = prognam+' '+progver+': ('+utc+' UTC) Generated {' $
                + wave_resp.type+'} structure with name "'        $
                + wave_resp.name+'".'
  wave_resp.history[0] = hist_string

  if qoutfile then begin
    if q_vb then print, prognam+': Writing OUTFILE...'
      savegenx, file=outfile, wave_resp
    if q_vb then print, prognam+': Writing OUTFILE...OK'
  endif

  if q_vb then box_message, prognam+': ... Finished.'

  if qstop then stop

  return, wave_resp


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