; wavetest_unix_times
; Convert fractional years from wavetest data set to Unix timestamps for making tplot variables
; 
function wavetest_unix_times, inp_times
  n = n_elements(inp_times)
  output_times = dblarr(n)
  for i = 0, n-1 do begin
    iyear = fix(inp_times[i])
    yearfrac = inp_times[i] - iyear
    unix_boy = time_double(string(iyear))
    unix_eoy = time_double(string(iyear+1))
    year_sec = unix_eoy - unix_boy
    output_times[i] = unix_boy + yearfrac*year_sec
  endfor
  return, output_times
end

 
; ;************************************************************** WAVETEST
;+
; NAME:   WAVETEST
;
; PURPOSE:   Example IDL program for WAVELET, using NINO3 SST dataset
;
; EXECUTION:
; 
;            IDL> .run wavetest
;
;
; See "http://paos.colorado.edu/research/wavelets/"
; Written January 1998 by C. Torrence
;
;-
;**************************************************************

pro wavetest
  compile_opt idl2

  data_dir=routine_dir()
  data_file=data_dir+path_sep()+'sst_nino3.dat'
	n = 504
	sst = FLTARR(n)
	OPENR,1,data_file   ; input SST time series
	READF,1,sst
	CLOSE,1

;------------------------------------------------------ Computation

; normalize by standard deviation (not necessary, but makes it easier
; to compare with plot on Interactive Wavelet page, at
; "http://paos.colorado.edu/research/wavelets/plot/"
	sst = (sst - TOTAL(sst)/n)

	dt = 0.25
	time = FINDGEN(n)*dt + 1871.0  ; construct time array
	xrange = [1870,2000]  ; plotting range
	pad = 1
	s0 = dt    ; this says start at a scale of 3 months
	dj = 0.25  ; this will do 4 sub-octaves per octave
	j1 = 9./dj  ; this says do 9 powers-of-two with dj sub-octaves each
	mother = 'Morlet'
	recon_sst = sst   ; save an extra copy, so we don't erase original sst

; estimate lag-1 autocorrelation, for red-noise significance tests
; Note that we actually use the global wavelet spectrum (GWS)
; for the significance tests, but if you wanted to use red noise,
; here's how you could calculate it...`
	lag1 = (A_CORRELATE(sst,1) + SQRT(A_CORRELATE(sst,2)))/2.
	
; Wavelet transform:
	wave = WAVELET(recon_sst,dt,PERIOD=period,SCALE=scale,S0=s0, $
		PAD=pad,COI=coi,DJ=dj,J=j1,MOTHER=mother,/RECON)
	power = (ABS(wave))^2  ; compute wavelet power spectrum
	global_ws = TOTAL(power,1)/n   ; global wavelet spectrum (GWS)
	J = N_ELEMENTS(scale) - 1
	
; Make a tplot variable for the power spectrum   JWL 2025-07-30

; Convert fractional years to Unix times
  unix_times = wavetest_unix_times(time)

  dl={spec: 1}
  
  store_data,'wavetest_powspec',data={x: unix_times, y: power, v: period}, dl=dl

; Significance levels, assuming the GWS as background spectrum:
	signif = WAVE_SIGNIF(sst,dt,scale,0, $
		GWS=global_ws,SIGLVL=0.90,MOTHER=mother)
	signif = REBIN(TRANSPOSE(signif),n,J+1)  ; expand signif --> (J+1)x(N) array
	signif = power/signif   ; where ratio > 1, power is significant

; GWS significance levels:
	dof = n - scale   ; the -scale corrects for padding at edges
	global_signif = WAVE_SIGNIF(sst,dt,scale,1, $
		LAG1=0.0,DOF=dof,MOTHER=mother,CDELTA=Cdelta,PSI0=psi0)

; check total variance (Parseval's theorem) [Eqn(14)]
	scale_avg = REBIN(TRANSPOSE(scale),n,J+1)  ; expand scale-->(J+1)x(N) array
	power_norm = power/scale_avg
	variance = (MOMENT(sst))[1]
	recon_variance = dj*dt/(Cdelta*n)*TOTAL(power_norm)  ; [Eqn(14)]
	
	IF (N_ELEMENTS(recon_sst) GT 1) THEN BEGIN
		recon_variance = (MOMENT(recon_sst))[1]
; RMS of Reconstruction [Eqn(11)]
		rms_error = SQRT(TOTAL((sst - recon_sst)^2)/n)
		PRINT
		DPRINT, '        ******** RECONSTRUCTION ********'
		DPRINT, 'original variance =',variance,' degC^2'
		DPRINT, 'reconstructed var =',FLOAT(recon_variance),' degC^2'
		DPRINT, 'Ratio = ',recon_variance/variance
		DPRINT, 'root-mean-square error of reconstructed sst = ',rms_error,' degC'
		PRINT
		IF (mother EQ 'DOG') THEN BEGIN
			DPRINT, 'Note: for better reconstruction with the DOG, you need'
			DPRINT, '      to use a very small s0.'
		ENDIF
		PRINT
	ENDIF
	
; Scale-average between El Nino periods of 2--8 years
	avg = WHERE((scale GE 2) AND (scale LT 8))
	scale_avg = dj*dt/Cdelta*TOTAL(power_norm[*,avg],2)  ; [Eqn(24)]
	scaleavg_signif = WAVE_SIGNIF(sst,dt,scale,2, $
		GWS=global_ws,SIGLVL=0.90,DOF=[2,7.9],MOTHER=mother)


;------------------------------------------------------ Plotting
printfile = 0

!P.FONT = -1
!P.CHARSIZE = 1
IF (printfile) THEN BEGIN
	SET_PLOT,'ps'
	DEVICE,/PORT,/INCH,XSIZE=6.5,XOFF=1,YSIZE=6,YOFF=3,/COLOR,BITS=8
	!P.FONT = 0
	!P.CHARSIZE = 0.75
ENDIF ELSE WINDOW,0,XSIZE=600,YSIZE=600
!P.MULTI = 0
!X.STYLE = 1
!Y.STYLE = 1
LOADCT,39

;--- Plot time series
	pos1 = [0.1,0.75,0.7,0.95]
	PLOT,time,sst,XRANGE=xrange, $
		XTITLE='Time (year)',YTITLE='NINO3 SST (!Uo!NC)', $
		TITLE='a) NINO3 Sea Surface Temperature (seasonal)', $
		POSITION=pos1
	IF (N_ELEMENTS(recon_sst) GT 1) THEN OPLOT,time,recon_sst,COLOR=144
	XYOUTS,0.85,0.9,/NORMAL,ALIGN=0.5, $
		'!5WAVELET ANALYSIS!X'+$
		'!C!CC. Torrence & G.P. Compo'+$
		'!C!Chttp://paos.colorado.edu/!Cresearch/wavelets/'

;--- Contour plot wavelet power spectrum
	yrange = [64,0.5]   ; years
	levels = [0.5,1,2,4]
	colors = [64,128,208,254]
	period2 = FIX(ALOG(period)/ALOG(2))   ; integer powers of 2 in period
	ytickv = 2.^(period2[UNIQ(period2)])  ; unique powers of 2
	pos2 = [pos1[0],0.35,pos1[2],0.65]

	CONTOUR,power,time,period,/NOERASE,POSITION=pos2, $
		XRANGE=xrange,YRANGE=yrange,/YTYPE, $
		YTICKS=N_ELEMENTS(ytickv)-1,YTICKV=ytickv, $
		LEVELS=levels,C_COLORS=colors,/FILL, $
		XTITLE='Time (year)',YTITLE='Period (years)', $
		TITLE='b) Wavelet Power Spectrum (contours at 0.5,1,2,4!Uo!NC!U2!N)'
; significance contour, levels at -99 (fake) and 1 (significant)
	CONTOUR,signif,time,period,/OVERPLOT,LEVEL=1,THICK=2, $
		C_LABEL=1,C_ANNOT='90%',C_CHARSIZE=1
; cone-of-influence, anything "below" is dubious
	x = [time[0],time,MAX(time)]
	y = [MAX(period),coi,MAX(period)]
	color = 4
	POLYFILL,x,y,ORIEN=+45,SPACING=0.5,COLOR=color,NOCLIP=0,THICK=1
	POLYFILL,x,y,ORIEN=-45,SPACING=0.5,COLOR=color,NOCLIP=0,THICK=1
	PLOTS,time,coi,COLOR=color,NOCLIP=0,THICK=1

;--- Plot global wavelet spectrum
	pos3 = [0.74,pos2[1],0.95,pos2[3]]
	blank = REPLICATE(' ',29)
	PLOT,global_ws,period,/NOERASE,POSITION=pos3, $
		THICK=2,XSTYLE=10,YSTYLE=9, $
		YRANGE=yrange,/YTYPE,YTICKLEN=-0.02, $
		XTICKS=2,XMINOR=2, $
		YTICKS=N_ELEMENTS(ytickv)-1,YTICKV=ytickv,YTICKNAME=blank, $
		XTITLE='Power (!Uo!NC!U2!N)',TITLE='c) Global'
	OPLOT,global_signif,period,LINES=1
	XYOUTS,1.7,60,'95%'
	
;--- Plot 2--8 yr scale-average time series
	pos4 = [pos1[0],0.05,pos1[2],0.25]
	PLOT,time,scale_avg,/NOERASE,POSITION=pos4, $
		XRANGE=xrange,YRANGE=[0,MAX(scale_avg)*1.25],THICK=2, $
		XTITLE='Time (year)',YTITLE='Avg variance (!Uo!NC!U2!N)', $
		TITLE='d) 2-8 yr Scale-average Time Series'
	OPLOT,xrange,scaleavg_signif+[0,0],LINES=1

IF (printfile) THEN DEVICE,/CLOSE
END
