FUNCTION make_xrt_emiss_model, modelname, wave, temp, spec, abund_model, $
                   ioneq_model, dens_model, wlength=wlength,             $
                   tlength=tlength, data_files=data_files,               $
                   comments=comments, outfile=outfile, verbose=verbose,  $
                   quiet=quiet, qabort=qabort, qstop=qstop

; =========================================================================
;+
; PROJECT:
;       Solar-B / XRT 
;
; NAME:
;       
;       MAKE_XRT_EMISS_MODEL
;
; CATEGORY:
;       
;       Instrument response
;
; PURPOSE:
;
;       This program helps users put a spectral emission model into a
;       structure format that other XRT routines will expect. The benefit
;       is that the routines which calculate the XRT x-ray responses may be
;       used in a modular manner with the user's choice of spectral
;       emission codes.
;       (This routine deprecates, and provides extended functionality
;       of, the older routines <mk_xrt_spec_genx.pro> and 
;       <get_xrt_spec_genx.pro>.)
;
; CALLING SEQUENCE:
;
;       Result = MAKE_XRT_EMISS_MODEL( modelname, wave, temp, spec, 
;                  abund_model, ioneq_model, dens_model [,wlength=wlength]
;                  [,tlength=tlength] [,data_files=data_files]
;                  [,comments=comments] [,outfile=outfile] [,/verbose]
;                  [,/quiet] [,qabort=qabort] [,/qstop] )
;       
; INPUTS:
;       
;       MODELNAME   - [Mandatory, param] (string scalar)
;                     This will be the name/ID given to this spectral model.
;                     It should be sufficiently distinctive to be 
;                     searched on.
;       WAVE        - [Mandatory, param] (float array, [Nwavelengths])
;                     This is a 1D array of monotonically 
;                     increasing wavelengths. Units = 'Angstroms'. Must 
;                     correlate to one dimension of the SPEC array. 
;                     (See "WLENGTH".)
;       TEMP        - [Mandatory, param] (float array, [Ntemperatures])
;                     This is a 1D array of monotonically 
;                     increasing temperatures. Units = 'degrees Kelvin'.
;                     Must correlate to one dimension of the SPEC array.
;                     (See "TLENGTH".)
;       SPEC        - [Mandatory, param] 
;                     (float array, [Nwavelengths, Ntemperatures])
;                     This is a 2D array of a spectral emission model.
;                     Units = 'ph cm^3 s^-1 sr^-1 A^-1'. This variable
;                     is dependent on WAVE and TEMP. (See "WLENGTH" and
;                     "TLENGTH".)
;       ABUND_MODEL - [Mandatory, param] (string scalar)
;                     This is a brief description or reference for the
;                     abundance model that was used to calculate the 
;                     spectra.
;       IONEQ_MODEL - [Mandatory, param] (string scalar)
;                     This is a brief description or reference for the
;                     ionization equilibrium model that was used to 
;                     calculate the spectra.
;       DENS_MODEL  - [Mandatory, param] (string scalar)
;                     This is a brief description or reference for the
;                     density or emission measure model that was used to 
;                     calculate the spectra.
;       WLENGTH     - [Optional, keyword] (long scalar)
;                     0 < WLENGTH =< n_elements(WAVE)
;                     Indicates sublength of WAVE array that contains 
;                     valid values, starting at the zero-th index. Only the
;                     range [0:WLENGTH-1] of WAVE and of the corresponding
;                     dimension of SPEC will be utilized. Values outside
;                     this range may be zeroed. Default behavior is to set
;                     this value equal to the length of the WAVE input
;                     array.
;       TLENGTH     - [Optional, keyword] (long scalar)
;                     0 < TLENGTH =< n_elements(TEMP)
;                     Indicates sublength of TEMP array that contains 
;                     valid values, starting at the zero-th index. Only the
;                     range [0:TLENGTH-1] of TEMP and of the corresponding
;                     dimension of SPEC will be utilized. Values outside
;                     this range may be zeroed. Default behavior is to set
;                     this value equal to the length of the TEMP input
;                     array.
;       DATA_FILES  - [Optional, keyword] 
;                     (string scalar or array, [N le 5])
;                     These are the source files for the emission model.
;                     It is up to the user whether they wish to list 
;                     provide them.
;       COMMENTS    - [Optional, keyword] 
;                     (string scalar or array, [N le 5])
;                     There is a field in the generated structure to 
;                     store any relevant comments.
;       OUTFILE     - [Optional] (string scalar)
;                     Write the constructed spectral emission model
;                     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:
;
;       /VERBOSE    - [Optional] (Boolean) If set, print out extra
;                     information. Overrides "/quiet" (see Note #2).
;       /QUIET      - [Optional] (Boolean) If set, suppress messages
;                     (see Note #2).
;       /QSTOP      - [Optional] (Boolean) For debugging.
;
; OUTPUTS:
;
;       Return      - (structure scalar, type=anonymous)
;       (OUTVAR)      Returns the constructed spectral emission model
;                     structure. E.g.:
;            TYPE             STRING    'XRT_emiss_model'
;            EMS_STR_VERSION: STRING    (anonymous)
;            EMS_STR_DESCR:   STRING    'Solar spectral emission model
;                                       in XRT-compatible format.'
;            NAME:            STRING    'XRT default (APED/APEC)'
;            WAVE:            FLOAT     Array[5000]
;            WAVE_UNITS:      STRING    'Angstroms'
;            TEMP:            FLOAT     Array[50]
;            TEMP_UNITS:      STRING    'K'
;            SPEC:            FLOAT     Array[5000,50]
;            SPEC_UNITS:      STRING    'ph cm^3 s^-1 sr^-1 A^-1'
;            WLENGTH:         LONG      5000
;            TLENGTH:         LONG      50
;            ABUND_MODEL:     STRING    'Photospheric abundances'
;            IONEQ_MODEL:     STRING    'Mazotta et al. (1998)'
;            DENS_MODEL:      STRING    '1e10 g cm^-3'
;            DATA_FILES:      STRING    Array[5]
;            HISTORY:         STRING    Array[3]
;            COMMENTS:        STRING    Array[5]
;
;       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:
;      
;
; COMMON BLOCKS:
;
; 	none 
;
; NOTES:
;
;       1) This routine is part of a modular approach to calculating
;          the XRT response functions. A user may use this routine
;          to put a spectral emission code into a standardized format
;          that related XRT routines will understand. Most spectral model
;          codes/atomic databases can generate the required
;          inputs in some defined file format and structure. 
;
;       2) 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")
;
;       3) This routine deprecates, and provides extended functionality
;          of, the older routines <mk_xrt_spec_genx.pro> and
;          <get_xrt_spec_genx.pro>.
;
; 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-05' ;--- (M.Weber) Created <make_xrt_emiss_model.pro>
;                             from <mk_xrt_spec_genx.pro>, v2007-May-16. 
;                             All of the response codes were redesigned to 
;                             provide more information and to work 
;                             together better.
progver = 'v2008-Oct-01' ;--- (M.Weber) Reviewed version.
;                      
;-
; =========================================================================


; === 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_EMISS_MODEL'
  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.
  qwlength  = keyword_set(wlength)
  qtlength  = keyword_set(tlength)
  qdatafil  = keyword_set(data_files)
  qcommnts  = keyword_set(comments)
  qoutfile  = keyword_set(outfile)
  qstop     = keyword_set(qstop)
  qabort    = 0B

  if (not keyword_set(comments)) then comments = ''

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


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

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

  ;=== Abort if the mandatory number of inputs are not provided.
  if (n_params() ne 7) then begin
    if (not q_qt) then box_message, prognam+': Missing inputs.' $
                                   + 'See program header. Aborting...'
    qabort = 1B
    return, 0
  endif

  if ((datatype(modelname) ne 'STR') $
      or (n_elements(modelname) ne 1)) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input MODELNAME has wrong type. ', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif

  if ((is_number(wave[0]) eq 0B) or (n_dimensions(wave) ne 1)) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input WAVE has wrong type. ', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif

  if ((is_number(temp[0]) eq 0B) or (n_dimensions(temp) ne 1)) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input TEMP has wrong type. ', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif

  if ((is_number(spec[0]) eq 0B) or (n_dimensions(spec) ne 2)) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input SPEC has wrong type. ', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif else begin
    if ((n_elements(spec[*,0]) ne n_elements(wave)) $
        or (n_elements(spec[0,*]) ne n_elements(temp))) then begin
          if (not q_qt) then box_message, $
             [prognam+': Input SPEC dimensions do not match [WAVE,TEMP].', $
              prognul+'  See program header. Aborting...']
      qabort = 1B
      return, 0
    endif
  endelse

  if ((datatype(abund_model) ne 'STR') $
      or (n_elements(abund_model) ne 1)) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input ABUND_MODEL has wrong type. ', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif else begin
    if (abund_model eq '') then begin
      if (not q_qt) then box_message, $
          [prognam+': Input ABUND_MODEL is empty. ', $
           prognul+'  See program header. Aborting...']
      qabort = 1B
      return, 0
    endif
  endelse

  if ((datatype(ioneq_model) ne 'STR') $
      or (n_elements(ioneq_model) ne 1)) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input IONEQ_MODEL has wrong type. ', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif else begin
    if (ioneq_model eq '') then begin
      if (not q_qt) then box_message, $
          [prognam+': Input IONEQ_MODEL is empty. ', $
           prognul+'  See program header. Aborting...']
      qabort = 1B
      return, 0
    endif
  endelse

  if ((datatype(dens_model) ne 'STR') $
      or (n_elements(dens_model) ne 1)) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input DENS_MODEL has wrong type. ', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif else begin
    if (dens_model eq '') then begin
      if (not q_qt) then box_message, $
          [prognam+': Input DENS_MODEL is empty. ', $
           prognul+'  See program header. Aborting...']
      qabort = 1B
      return, 0
    endif
  endelse

  ;=== Make sure WLENGTH has the right type.
  if qwlength then begin
    if (is_number(wlength)) then begin
      if ((datatype(wlength) ne 'INT') and (datatype(wlength) ne 'LON')) $
         then qabort = 1B
      if (n_elements(wlength) ne 1) then qabort = 1B
    endif else begin
      qabort = 1B
    endelse
  endif else wlength = n_elements(wave)
  if qabort then begin
    if (not q_qt) then box_message, $
        [prognam+': Input WLENGTH has wrong type. ', $
         prognul+'  See program header. Aborting...']
    return, 0
  endif

  ;=== Make sure WLENGTH has the right size.
  if ((wlength lt 1) or (wlength gt n_elements(wave))) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input WLENGTH is too small or too big', $
         prognul+'  compared to the size of WAVE.', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif

  ;=== Make sure TLENGTH has the right type.
  if qtlength then begin
    if (is_number(tlength)) then begin
      if ((datatype(tlength) ne 'INT') and (datatype(tlength) ne 'LON')) $
         then qabort = 1B
      if (n_elements(tlength) ne 1) then qabort = 1B
    endif else begin
      qabort = 1B
    endelse
  endif else tlength = n_elements(temp)
  if qabort then begin
    if (not q_qt) then box_message, $
        [prognam+': Input TLENGTH has wrong type. ', $
         prognul+'  See program header. Aborting...']
    return, 0
  endif

  ;=== Make sure TLENGTH has the right size.
  if ((tlength lt 1) or (tlength gt n_elements(temp))) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input TLENGTH is too small or too big', $
         prognul+'  compared to the size of TEMP.', $
         prognul+'  See program header. Aborting...']
    qabort = 1B
    return, 0
  endif

  wave_temp = wave[0:wlength-1]
  wdeltas = shift(wave_temp,-1) - wave_temp
  ss = where(wdeltas le 0.0, wcount)
  ;; A legitimate (always monotonically increasing) WAVE_TEMP will have a 
  ;; single negative value at the end for the wraparound. 
  if (wcount gt 1) then begin
    if (not q_qt) then box_message, $
        [prognam+': Input WAVE[0:WLENGTH-1] does not montonically', $
         prognul+'  increase. See program header. Aborting...']
    qabort = 1B
    return, 0
  endif

  ;=== Make sure DATA_FILES has the right type.
  if qdatafil then begin
    if ((datatype(data_files) ne 'STR') $
        or (n_elements(data_files) gt 5)) then begin
      if (not q_qt) then box_message, $
          [prognam+': Input DATA_FILES has wrong type. ', $
           prognul+'  See program header. Aborting...']
      qabort = 1B
      return, 0
    endif
  endif else data_files = strarr(5)

  ;=== Make sure COMMENTS has the right type.
  if qcommnts then begin
    if ((datatype(comments) ne 'STR') $
        or (n_elements(comments) gt 5)) then begin
      if (not q_qt) then box_message, $
          [prognam+': Input COMMENTS has wrong type. ', $
           prognul+'  See program header. Aborting...']
      qabort = 1B
      return, 0
    endif
  endif else comments = strarr(5)

  if qoutfile then begin
    if ((datatype(outfile) ne 'STR') $
        or (n_elements(outfile) ne 1)) 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
      return, 0
    endif
  endif

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


; === Reform inputs to desired shape ===================

  if q_vb then print, prognam+': Cleaning and padding the inputs...'

  ;=== Make sure unused areas of WAVE, TEMP, and SPEC are zeroed out,
  ;=== as specified.
  if (q_vb eq 1) then print, prognam+': Zeroing unused addresses of ' $
                             + 'WAVE, TEMP, and SPEC.'
  if (wlength lt n_elements(wave)) then wave[wlength:*] = 0.0
  if (tlength lt n_elements(temp)) then temp[tlength:*] = 0.0
  if ( (wlength lt n_elements(wave)) and (tlength lt n_elements(temp)) ) $
    then spec[wlength:*,tlength:*] = 0.0


  ;=== Add empty strings to DATA_FILES to make it strarr(5).
  data_files_temp = strarr(5)
  data_files_temp[0:(n_elements(data_files)-1)] = data_files
  data_files = data_files_temp
  if (q_vb eq 1) then print, prognam+': Padding DATA_FILES up to strarr(5).'

  ;=== Add empty strings to COMMENTS to make it strarr(5).
  comments_temp = strarr(5)
  comments_temp[0:(n_elements(comments)-1)] = comments
  comments = comments_temp
  if (q_vb eq 1) then print, prognam+': Padding COMMENTS up to strarr(5).'

  if q_vb then print, prognam+': Cleaning and padding the inputs...OK'


; === Generate emission model structure ================

  if q_vb then print, prognam+': Generating emission model structure...'

  outvar = {type:            '',                       $
            ems_str_version: '',                       $
            ems_str_descr:   '',                       $
            name:            '',                       $
            wave:            fltarr(n_elements(wave)), $
            wave_units:      '',                       $
            temp:            fltarr(n_elements(temp)), $
            temp_units:      '',                       $
            spec:            fltarr(n_elements(wave),n_elements(temp)), $
            spec_units:      '',                       $
            wlength:         0L,                       $
            tlength:         0L,                       $
            abund_model:     '',                       $
            ioneq_model:     '',                       $
            dens_model:      '',                       $
            data_files:      strarr(5),                $
            history:         strarr(3),                $
            comments:        strarr(5)                  }

  outvar.type            = 'XRT_EMISS_MODEL'
  outvar.ems_str_version = '<Anonymous>'
  outvar.ems_str_descr   = 'Specifies a spectral emission model in ' $
                                +'XRT-compatible format.'
  outvar.name            = string(modelname[0])
  outvar.wave            = float(wave)
  outvar.wave_units      = 'Angstroms'
  outvar.temp            = float(temp)
  outvar.temp_units      = 'K'
  outvar.spec            = float(spec)
  outvar.spec_units      = 'ph cm^3 s^-1 sr^-1 A^-1'
  outvar.wlength         = long(wlength[0])
  outvar.tlength         = long(tlength[0])
  outvar.abund_model     = string(abund_model[0])
  outvar.ioneq_model     = string(ioneq_model[0])
  outvar.dens_model      = string(dens_model[0])
  outvar.data_files      = string(data_files[0:4])
  outvar.comments        = string(comments[0:4])


  if q_vb then print, prognam+': Generating emission model structure...OK'


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

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

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

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

  if qstop then stop

  return, outvar


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