PRO mk_xrt_spec_genx, specname, wave, temp, spec, data_files,            $
                      comments=comments, infile=infile, outfile=outfile, $
                      outvar=outvar, apec=apec, verbose=verbose,         $
                      quiet=quiet, qabort=qabort, qstop=qstop

; =========================================================================
;+
; PROJECT:
;       Solar-B / XRT 
;
; NAME:
;       
;       MK_XRT_SPEC_GENX
;
; 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.
;
; CALLING SEQUENCE:
;
;       MK_XRT_SPEC_GENX, specname, wave, temp, spec, data_files, 
;         [,infile=infile] [,outfile=outfile] [,outvar=outvar]
;         [,/apec] [,/verbose] [,/quiet] [,qabort=qabort] [,/qstop]
;       
; INPUTS:
;       
;       SPECNAME   - [Mandatory, param or INFILE] (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 or INFILE] (float array, 
;                    [Nwavelengths]) This is a 1D array of monotonically 
;                    increasing wavelengths. Units = 'Angstroms'. Must 
;                    correlate to the SPEC array. Maximum length is 5000.
;       TEMP       - [Mandatory, param or INFILE] (float array, 
;                    [Ntemperatures]) This is a 1D array of monotonically 
;                    increasing temperatures. Units = 'log K'. Must 
;                    correlate to the SPEC array. Maximum length is 50.
;       SPEC       - [Mandatory, param or INFILE] 
;                    (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. Therefore, it has
;                    the same restrictions on dimension lengths 
;                    (Nwave le 5000, Ntemp le 50).
;       DATA_FILES - [Mandatory, param or INFILE] 
;                    (string scalar or array, [N le 5])
;                    These are the source files for the model. If INFILE
;                    is used, then DATA_FILES = INFILE.
;       COMMENTS   - [Optional, param or INFILE] 
;                    (string scalar or array, [N le 5])
;                    There is a field in the generated structure to 
;                    store comments.
;
; KEYWORDS:
;
;       INFILE     - [Optional] (string scalar)
;                    The mandatory inputs may be passed in as a file.
;                    The file format should be 'genx', such that the
;                    file may be read with the <restgenx> command.
;                    The mandatory inputs (except DATA_FILES) must be 
;                    stored in a specific order. Here is the command used 
;                    to read this file:
;                    IDL> restgenx, file=infile, specname, wave, temp, spec
;                    The stored inputs must still match the units
;                    given above. By default for this option, 
;                    DATA_FILES = INFILE. See Note #2.
;       /APEC      - [Optional] (Boolean) Indicates a special INFILE case
;                    for APEC models. See Note #2.
;       /VERBOSE   - [Optional] (Boolean) If set, print out extra
;                    information. Overrides "/quiet" (see Note #3).
;       /QUIET     - [Optional] (Boolean) If set, suppress messages
;                    (see Note #3).
;       /QSTOP     - [Optional] (Boolean) For debugging.
;
; OUTPUTS:
;
;       OUTFILE    - [Optional] (string scalar)
;                    (NB: Either OUTFILE or OUTVAR should be used in 
;                    order to catch the result.)
;                    Write the constructed spectral emission model
;                    structure to a specified "genx" file. The extension
;                    ".geny" will be automatically appended to the 
;                    filename. See OUTVAR for structure description.
;       OUTVAR     - [Optional] (named variable)
;                    (NB: Either OUTFILE or OUTVAR should be used in 
;                    order to catch the result.)
;                    Return the constructed spectral emission model
;                    structure. 
;                      TYPE            STRING    'spectrum'
;                      NAME            STRING    
;                      WAVE            FLOAT     Array[5000]
;                      WAVE_UNITS      STRING    'Angstroms'
;                      WLENGTH         LONG     
;                      TEMP            FLOAT     Array[50]
;                      TEMP_UNITS      STRING    'log K'
;                      TLENGTH         LONG    
;                      SPEC            FLOAT     Array[5000, 50]
;                      SPEC_UNITS      STRING    'ph cm^3 s^-1 sr^-1 A^-1'
;                      DATA_FILES      STRING    Array[5]
;                      HISTORY         STRING    Array[5]
;                      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:
;      
;       Provide inputs directly, get output immediately:
;       IDL> spec_str = 1
;       IDL> mk_xrt_spec_genx, specname, wave, temp, spec, data_files, $
;       IDL>                   outvar=spec_str
;
;       Provide inputs in a file, write output to a file:
;       IDL> mk_xrt_spec_genx, infile='my_input.genx', outfile='the_output'
;       IDL> $ls the_output.geny
;
; COMMON BLOCKS:
;
; 	none 
;
; NOTES:
;
;       1) APEC spectra are generated with an implicit column EM of 
;          3.1437917e+27 [cm^-5]. The units of spec are correctly given as
;          'ph cm^-2 s^-1 sr^-1 A^-1'. This factor is taken out in this
;          program to generalize the spectral emission model.
;
;       2) 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. If the file
;          format, contents, and corrections are defined for a given
;          code/database, then these can be added to this code as a 
;          special case. See the usage of the APEC keyword as an example.
;          Contact the XRT team to nominate additional cases which would
;          be of common benefit.
;
;       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")
;
; 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-16' ;--- (M.Weber) Written. (Based on heavily on
;                             earlier work, though.)
;                      
;-
; =========================================================================


; === 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 = 'MK_XRT_SPEC_GENX'
  prognul = '                '
  apec_em_factor = (1.0D+44) / ((2.46*725.0*1.0E+5)^2.)
         ;; = 3.1437917e+27 [cm^-5] See Note #1.

  ;=== 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.
  qinfile  = keyword_set(infile)
  qoutfile = keyword_set(outfile)
  qapec    = keyword_set(apec)
  qstop    = keyword_set(qstop)
  qabort   = 0B

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

  if q_vb then print, prognul+'                          ...OK'


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

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

  if ((n_params() ne 5) and (qinfile eq 0)) then begin
    if (not q_qt) then box_message, prognam+': Insufficient inputs.' $
                                   + 'See program header. Aborting...'
    qabort = 1B
    return
  endif

  if ((n_params() eq 5) and (qinfile)) then begin
    if (q_qt eq 0) then box_message, [prognam+': Conflicting inputs. ' $
             + 'See program header.', prognul+'  Using the provided '  $
             + 'parameters...']
    qinfile = 0B
    return
  endif

  if qinfile then begin
    if ((datatype(infile) ne 'STR') or (n_elements(infile) ne 1)) then begin
      if (q_qt eq 0) then box_message, [prognam+': INFILE not a scalar ' $
                                                  + 'string. Aborting...']
      qabort = 1B
      return
    endif

    if (not file_exist(infile)) then begin
      if (q_qt eq 0) then box_message, [prognam+': Cannot find INFILE. ' $
                                                          + 'Aborting...']
      qabort = 1B
      return
    endif
  endif

  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+': OUTFILE not a scalar ' $
       + 'string.', prognul+'  Proceeding, but will not write to OUTFILE...']
      qoutfile = 0B
      return
    endif
  endif

  if q_vb then print, prognul+'                 ...OK'


; === Read infile, apply corrections =============

  if qinfile then begin

    if q_vb then print, prognam+': Reading INFILE...'

    ;=== This section provides a way to read in spectral models
    ;=== from the principal atomic databases. See Note #2.
    case 1 of
      qapec: begin  ;; APEC case.
               restgen, file=infile, wave, spec, spec_units, temp
               spec = spec / apec_em_factor ;; See Note #1.
               comments = ''
               wlen = n_elements(wave)
               tlen = n_elements(temp)
               clen = n_elements(comments)
               ;=== Extract base of filename for specname.
               pos1 = rstrpos(infile, '/')
               pos2 = rstrpos(infile, '.')
               specname = strmid(infile, pos1+1, pos2-pos1-1)
             end

      else:  begin ;; Generic case. Requires vars have correct units!
               restgenx, file=infile, wave, temp, spec, specname
               wlen = n_elements(wave)
               tlen = n_elements(temp)
             end
    endcase    

    data_files = infile

    if q_vb then print, prognul+'                ...OK'

  endif


; === Generate spectrum structure ================

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

  outvar = {type:'spectrum',      name:'',                               $
            wave:fltarr(5000),    wave_units:'Angstroms', wlength:1L,    $
            temp:fltarr(50),      temp_units:'log K',     tlength:1L,    $
            spec:fltarr(5000,50), spec_units:'ph cm^3 s^-1 sr^-1 A^-1', $
            data_files:strarr(5), history:strarr(5), comments:strarr(5)   }

  ndfil = n_elements(data_files)

  outvar.name                    = specname
  outvar.wave[0:wlen-1]          = wave
  outvar.wlength                 = wlen
  outvar.temp[0:tlen-1]          = temp
  outvar.tlength                 = tlen
  outvar.spec[0:wlen-1,0:tlen-1] = spec
  outvar.data_files[0:ndfil-1]   = data_files
  outvar.comments[0:clen-1]      = comments

  if q_vb then print, prognul+'                               ...OK'


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

  get_utc, utc, /stime
  outvar.history[0] = prognam+' (' + progver + '): Generated at ' + utc $
                      + ' UTC.'

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

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

  if qstop then stop


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