; docformat = 'rst'

;+
;
; This is an example testing the uniqueness of a number of randomly
; generated PAH emission spectra , built around the functionality
; provided by the AmesPAHdbIDLSuite and should help confirm that the
; it has been properly installed. The source code is annotated to
; guide users and developers in the inner workings of the suite.
;
; Updated versions of the NASA Ames PAH IR Spectroscopic Database and
; more information can be found at: `www.astrochemistry.org/pahdb <https://www.astrochemistry.org/pahdb>`.
;
; :Examples:
;   Call the procedure directly::
;
;     IDL> test_uniqueness
;
; :Author:
;   Dr. Christiaan Boersma
;
; :Copyright:
;   BSD licensed
;
; :History:
;   Changes::
;
;     08-19-2019
;     Documentation added. Christiaan Boersma.
;-


;+
; Procedure for testing the uniqueness of a number of randomly
; generate PAH emission spectra.
;
; :Categories:
;   Example
;-
PRO TEST_UNIQUENESS

  COMPILE_OPT IDL2

  ; avoid underflow messages
  !EXCEPT = 0

  ; set number of spectra to co-add, the FWHM to be applied when
  ; convolving and spectral range
  nspectra = 40

  fwhm = 15D

  xrange = [15D, 2.5D]

  ; read in the default database defined by the environement variable
  ; !AMESPAHDEFAULTDB or the system variable AMESPAHDEFAULTDB. use the
  ; keyword FILENAME if these have not been set
  pahdb = OBJ_NEW('AmesPAHdbIDLSuite')

  ; retrieve all the transitions from the database
  transitions = pahdb->getTransitionsByUID( -1 )

  ; retrieve all unique identifiers
  uids = transitions->getUIDs(nuids)

  ; have every PAH absorb 6 eV
  transitions->Cascade,6D * 1.6021765D-12

  ; convolve the transitions into a spectrum
  spectrum = transitions->Convolve( $
             Xrange=1D4/xrange, $
             FWHM=fwhm, $
             /Gaussian)

  OBJ_DESTROY,transitions

  spectrum_s = spectrum->Get()

  ; run uniqueness test
  niterations = 1000L

  store = REPLICATE({norm: 0D, $
                     anion: 0D, $
                     neutral: 0D, $
                     cation:0D, $
                     small:0D, $
                     large:0D, $
                     pure:0D, $
                     nitrogen: 0D,$
                     solo: 0D, $
                     duo: 0D, $
                     trio: 0D, $
                     quartet: 0D, $
                     quintet: 0D}, niterations)

  ntags = N_TAGS(store)

  selected_weights = REPLICATE({uid:0L, weight:0D}, nspectra)

  indices = LONARR(nspectra, /NOZERO)

  FOR i = 0, niterations - 1 DO BEGIN

     ; print progress
     PRINT,"========================================================="
     PRINT,"        ITERATION: " + STRTRIM(STRING(FORMAT='(I0)', i + 1), 2) + "/" + STRTRIM(STRING(FORMAT='(I0)',  niterations), 2)
     PRINT,"========================================================="

     ; create random selection of unique identifiers and avoid doubles
     n = nspectra

     WHILE n GT 0 DO BEGIN

        indices[nspectra - n] = LONG(RANDOMU(seed, n) * nuids)

        indices = indices[SORT(indices)]

        u = UNIQ(indices)

        n = nspectra - N_ELEMENTS(u)

        indices[0] = indices[u]
     ENDWHILE

     selected_uids = uids[indices]

     ; intersect
     spectrum->Intersect,selected_uids

     ; store data
     data = (spectrum->Get()).data

     ; create random weights
     selected_weights.uid = selected_uids

     selected_weights.weight = 1D14 * RANDOMU(LONG(SYSTIME(1)), nspectra, /DOUBLE)

     ; co-add the spectra using the random weights
     coadd = spectrum->Coadd(Weights=selected_weights)

     ; reset spectrum
     spectrum->Set,spectrum_s

     ; difference
     spectrum->Difference,selected_uids

     ; fit the spectrum
     fit = spectrum->Fit((coadd.Get()).data.intensity)

     OBJ_DESTROY,coadd

     IF OBJ_VALID(fit) THEN BEGIN

       ; breakdown of the fit
       bd_fit = fit->getBreakdown()

       store[i].norm = fit->getNorm()

       ; breakdown of the original spectrum
       FOR j = 0, nspectra - 1 DO BEGIN

          sel1 = WHERE(selected_weights.uid EQ selected_uids[j])

          sel2 = WHERE(data.uid EQ selected_uids[j])

          data[sel2].intensity *= selected_weights[sel1].weight
       ENDFOR

       fit->Set,Data=data,Weights=selected_weights,UIDs=selected_uids

       bd_org = fit->getBreakdown()

       ; store breakdown fractional difference
       FOR j = 0, ntags - 2 DO store[i].(j + 1) = DOUBLE(bd_fit.(j)) / DOUBLE(bd_org.(j))

       ; clean up fit
       OBJ_DESTROY,fit

    ENDIF

    ; reset spectrum
    spectrum->Set,spectrum_s

  ENDFOR

  ; clean up
  OBJ_DESTROY,[spectrum, pahdb]

  ; plot distribution anion
  h = HISTOGRAM(store.anion, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction anion correct',YTITLE='frequency [#]',PSYM=10

  key = ''
  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution neutral
  h = HISTOGRAM(store.neutral, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction neutral correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution cation
  h = HISTOGRAM(store.cation, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction cation correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution small
  h = HISTOGRAM(store.small, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction small correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution large
  h = HISTOGRAM(store.large, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction large correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution nitrogen
  h = HISTOGRAM(store.nitrogen, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction nitrogen correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution solo
  h = HISTOGRAM(store.solo, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction solo correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution duo
  h = HISTOGRAM(store.duo, LOCATIONS=l, BINSIZE=0.05)

  PLOT,l,h,XTITLE='fraction duo correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

  ; plot distribution trio
  h = HISTOGRAM(store.trio, LOCATIONS=l, BINSIZE=0.05, /NAN)

  PLOT,l,h,XTITLE='fraction trio correct',YTITLE='frequency [#]',PSYM=10

  IF !D.NAME EQ 'X' THEN READ,key,PROMPT="Press <enter> to continue..."

END
