;+
;Procedure: minvar_matrix_make
;
;Purpose: tplot wrapper for minvar.pro.  This routine generates a
;matrix or set of matrices from a time series of 3-d vector data that
;will transform three dimensional data into a minimum variance
;coordinate system.  This routine takes a tplot variable that stores 3 
;dimensional vector data as an argument and produces a tplot variable
;storing the transformation matrix or matrices.
;
;The minimum variance coordinate system is taken by generating the covariance
;matrix for an interval of data.  This matrix is then diagonalized to
;identify the eigenvalues and eigenvectors of the covariance matrix.
;The eigenvector with the smallest eigenvalue will form the direction
;of the z component of the new coordinate system.  The eigenvector
;with the largest eigenvalue will form the direction of the x
;component of the new coordinate system.  The third eigenvector will
;form the y direction of the coordinate system.
;
;Warning:  The resulting transformation matrices will only correctly
;transform data from the coordinate system of the input variable to
;the minimum variance coordinate system.  So if in_var_name is in gse 
;coordinates then you should only use the output matrices to transform
;other data in gse coordinates.
;
;Arguments:
;       in_var_name: the name of the tplot variable holding the input
;       data, can be any sort of timeseries 3-d data
;
;       tstart(optional): the start time of the data you'd like to
;       consider for generating the transformation matrix(defaults to
;       minimum time of in_var timeseries)
;
;       tstop(optional): the stop time of the data you'd like to
;       consider for generating the transformation matrix(defaults to
;       maximum time of in_var timeseries)
;
;       twindow(optional): the size of the window(in seconds) you'd like to
;       consider when using a moving boxcar average to generate
;       multiple transformations. (defaults to the entire time series)
;
;       tslide(optional):  the number of seconds the boxcar should
;       slide forward after each average.(defaults to twindow/2)
;       set tslide=0 to cause the program to generate only a single
;       matrix
;
;       newname(optional): the name of the tplot variable in which to
;       store the transformation matrix(matrices) (defaults to
;       in_var_name+'_mva_mat'
;
;       evname(optional): the name of the tplot variable in which to
;       store the eigenvalues of the mva matrix(matrices) (defaults to
;       nowhere, ie if unset doesn't store them
;
;       error(optional): named variable that holds the error state of
;       the computation, 1=success 0 = failure
;
;       tminname(optional): name of a tplot variable in which you would
;       like to store the minimum variance direction vectors this
;       vector will be represented in the original coordinate system
;
;       tmidname(optional):  name of a tplot variable in which you would
;       like to store the intermediate variance direction vectors this
;       vector will be represented in the original coordinate system
;
;       tmaxname(optional): name of a tplot variable in which you would
;       like to store the minimum variance direction vectors this
;       vector will be represented in the original coordinate system
;
;
;  SEE ALSO:
;     minvar.pro
;     tvector_rotate.pro
;     thm_crib_mva.pro (THEMIS project) 
;
; $LastChangedBy: jwl $
; $LastChangedDate: 2025-03-15 12:13:20 -0700 (Sat, 15 Mar 2025) $
; $LastChangedRevision: 33187 $
; $URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/trunk/general/cotrans/special/minvar/minvar_matrix_make.pro $
;-

pro minvar_matrix_make,in_var_name,tstart=tstart,tstop=tstop,twindow=twindow,tslide=tslide,newname=newname,evname=evname,error=error,tminname=tminname,tmidname=tmidname,tmaxname=tmaxname

error = 0

if not keyword_set(in_var_name) then begin
    dprint,'minvar_matrix_make requires in_var_name to be set'
    return
endif

if tnames(in_var_name) eq '' then begin
    dprint,'minvar_matrix_make: input variable ' + in_var_name + ' not found.'
    return
endif

get_data,in_var_name,data=d,limits=l,dlimits=dl

d_s = size(d.y,/dimensions)

if n_elements(d_s) ne 2 then begin
    dprint,'minvar_matrix_make requires in_var_name.y to have 2 dimensions'
    return
endif

if d_s[1] ne 3 then begin
    dprint,'minvar_matrix_make requires cardinality of the second dimensions of in_var_name.y to equal 3'
    return
endif

if not keyword_set(tstart) then start_d = d.x[0] $
else start_d = time_double(tstart)

if not keyword_set(tstop) then stop_d = d.x[n_elements(d.x)-1L] $
else stop_d = time_double(tstop)

if(start_d ge stop_d) then begin
  dprint, 'minvar_matrix_make requires tstart to be greater than or equal to tstop'
  return
endif

if not keyword_set(twindow) then twindow = stop_d - start_d
if twindow le 0 then twindow = stop_d - start_d
if twindow gt (stop_d - start_d) then twindow = stop_d - start_d 

;sets it to something large enough that it will only generate one
;matrix in the default case
if not keyword_set(tslide) then tslide = twindow/2
if tslide le 0 then tslide=twindow/2

if not keyword_set(newname) then newname = in_var_name+'_mva_mat'

current_d = start_d

; Exact number of windows: always at least one, plus however many tslides fit in the space after the first window
o_num = 1 + floor((stop_d - start_d - twindow)/tslide)



o_times = dindgen(o_num)  ;allocate output storage space

o_lams = dindgen(o_num, 3)

o_eigs = dindgen(o_num, 3, 3)

i =  0

while(current_d + twindow le stop_d) do begin ;loop over time windows

  if(i ge o_num) then begin ;output storage should never exceed allocated space
    dprint, ' fx output array index out of bounds'
    return
  endif

  o_times[i] = current_d + twindow/2 ;output time for the mva matrix is the midpoint time for the interval

  idx = where(d.x ge current_d and d.x le current_d + twindow)

  if(size(idx, /n_dim) eq 0 && idx eq -1L) then begin
  
    ;non-fatal, this prevents output spam
    ;dprint, 'fx had where index error'
    
    current_d += tslide
    i++
    continue

  endif

  in_data = transpose(d.y[idx, *]) ;minvar takes dimensions transposed from tplot storage convention

  minvar, in_data, o_eig, lambdas2 = o_lam

  o_lam = reform(o_lam) ;minvar returns a 1x3 array instead of just a 3-d array

;the conditionals below should never fail, but it doesn't hurt to test
  if not array_equal(size(o_eig, /dimensions), [3, 3]) then begin
    dprint, 'minvar produced transformation matrix with wrong dimensions'
    return
  endif

  if not array_equal(size(o_lam, /dimensions), [3]) then begin
    dprint, 'minvar produced lambda matrix with wrong dimensions'
    return
  endif

  ;o_eigs[i, *, *] = o_eig
  o_eigs[i, *, *] = transpose(o_eig)


  o_lams[i, *] = o_lam

  i++ ;increment output storage index

  current_d += tslide          ;increment loop variable 

  if(tslide eq 0) then break
  
endwhile


str_element,d,'v',SUCCESS=s

if(s) then $
  o_d = {x:o_times[0:i-1L], y:o_eigs[0:i-1L, *, *], v:d.v} $
else $
  o_d = {x:o_times[0:i-1L], y:o_eigs[0:i-1L, *, *]}

if keyword_set(dl) then begin
o_dl = dl
e_dl = dl
str_element,e_dl,'data_att.coord_sys','minvar', /add
endif else begin

datt = {coord_sys:'unknown'}
o_dl = {data_att:datt}
; Prevent crash setting evname variable coordinate system, if input dl is empty  JWL 2021-12-08
e_datt={coord_sys:'minvar'}
e_dl = {data_att:e_datt}
endelse

str_element,o_dl,'data_att.coord_sys',success=s

if s eq 1 then begin
  str_element,o_dl,'data_att.source_sys',o_dl.data_att.coord_sys,/add_replace
endif

str_element,o_dl,'data_att.coord_sys','minvar',/add_replace

str_element,o_dl,'labels',SUCCESS=s

if s then begin
  o_dl.labels = ['maxvar','midvar','minvar'] 
endif else begin
  str_element,o_dl,'labels',['maxvar','midvar','minvar'],/add
endelse
  
str_element,o_dl,'labflag',SUCCESS=s

if s then begin 
  o_dl.labflag = 1 
endif else begin
  str_element,o_dl,'labflag',1,/add
endelse

str_element,o_dl,'colors',SUCCESS=s

if s then begin 
  o_dl.colors = [2,4,6] 
endif else begin
  str_element,o_dl,'colors',[2,4,6],/add
endelse

store_data, newname, data = o_d, limits = l, dlimits = o_dl

if keyword_set(evname) then begin


    str_element,d,'v',SUCCESS=s

    if(s) then $
      e_d = {x:o_times[0:i-1L], y:o_lams[0:i-1L, *], v:d.v} $
    else $
      e_d = {x:o_times[0:i-1L], y:o_lams[0:i-1L, *]}



  store_data, evname, data = e_d, limits = l, dlimits = e_dl

endif

if keyword_set(tminname) then begin

    
    str_element,d,'v',SUCCESS=s

    if(s) then $
      tm_d = {x:o_times[0:i-1L], y:reform(o_eigs[0:i-1L, 2, *],i,3), v:d.v} $
    else $
      tm_d = {x:o_times[0:i-1L], y:reform(o_eigs[0:i-1L, 2, *],i,3)}

  store_data, tminname, data = tm_d, limits = l, dlimits = dl

endif

if keyword_set(tmidname) then begin


    str_element,d,'v',SUCCESS=s

    if(s) then $
      tm_d = {x:o_times[0:i-1L], y:reform(o_eigs[0:i-1L, 1, *],i,3), v:d.v} $
    else $
      tm_d = {x:o_times[0:i-1L], y:reform(o_eigs[0:i-1L, 1, *],i,3)}

  store_data, tmidname, data = tm_d, limits = l, dlimits = dl

endif

if keyword_set(tmaxname) then begin

    
    str_element,d,'v',SUCCESS=s

    if(s) then $
      tm_d = {x:o_times[0:i-1L], y:reform(o_eigs[0:i-1L, 0, *],i,3), v:d.v} $
    else $
      tm_d = {x:o_times[0:i-1L], y:reform(o_eigs[0:i-1L, 0, *],i,3)}

  store_data, tmaxname, data = tm_d, limits = l, dlimits = dl

endif

;if we make it all the way to the end success!!!
error = 1

end
