;Helper function to calculate electron/ion density for bisection
Function Density_fraction, scp, expected_fraction = expected_fraction, $
                           _extra = _extra

  em0 = moments_3d(_extra.edat,sc_pot=scp,/dens_only)
  im0 = moments_3d(_extra.idat,sc_pot=scp,/dens_only)
  If(em0.density Gt 0 And im0.density Gt 0) Then Begin
     fraction = em0.density/im0.density
  Endif Else Begin
     fraction = 0.0
  Endelse
  If(keyword_set(expected_fraction)) Then expd = expected_fraction $
  Else expd = 1.75
  Return, fraction-expd ;Zero is the good answer here
End
;Helper function to calculate electron/ion density for bisection
;Uses n_3d_new.pro for density calculations
Function Density_fraction_n3dnew, scp, expected_fraction = expected_fraction, $
                                  _extra = _extra


;for using n_3d_new, the scpot value has to be set in the input
;structure
  ee = _extra.edat & ee.sc_pot = scp
  em0 = n_3d_new(ee)
  ie = _extra.idat & ie.sc_pot = scp
  im0 = n_3d_new(ie)

  If(em0 Gt 0 And im0 Gt 0) Then Begin
     fraction = em0/im0
  Endif Else Begin
     fraction = 0.0
  Endelse
  If(keyword_set(expected_fraction)) Then expd = expected_fraction $
  Else expd = 1.75
  Return, fraction-expd ;Zero is the good answer here
End
  
;+
;NAME:
; rtbis
;PURPOSE:
; Simple bisection routine, 
;CALLING SEQUENCE:
; x = rtbis(func_in, x1, x2, xacc=xacc, jmax=jmax)
;INPUT:
; func_in = an input function -- the answer will give func_in(x) = 0.0
; x1 = a lower limit
; x2 = an upper limit
;KEYWORDS:
; xacc = the accuracy, default is 1.0e-6
; jmax = max. number of iterations, the default is 40
;HISTORY:
; Copied from Numerical Recipies, 12-feb-2015, jmm,
; jimm@ssl.berkeley.edu
;-
Function rtbis, func_in, x1, x2, xacc=xacc, jmax=jmax, _extra = _extra

  If(keyword_set(xacc)) Then xacc0 = xacc Else xacc0 = 1.0e-6
  If(keyword_set(jmax)) Then jmax0 = jmax Else jmax0 = 400

  fmid = call_function(func_in, x2, _extra=_extra)
  f = call_function(func_in, x1, _extra=_extra)

  If(f*fmid Gt 0) Then Begin
     message, /info, 'Zero Value not Bracketed'
     Return, !values.f_nan
  Endif

  If(f lt 0) Then Begin
     x = x1 & dx = x2-x1
  Endif Else Begin
     x = x2 & dx = x1-x2
  Endelse
  
  For j = 0, jmax0-1 Do Begin
     dx = dx*0.5
     xmid = x+dx
     fmid = call_function(func_in, xmid, _extra=_extra)
;     print, xmid, fmid
     If(fmid le 0) Then x = xmid
     If(abs(dx) lt xacc0 Or fmid Eq 0) Then Return, x
  Endfor

  message, /info, 'Used: '+string(jmax0)+' Bisections; DX='+string(dx)
  Return, x
End
;+
;NAME:
; thm_esa_dfrac2scpot
;CALLING SEQUENCE:
; scpot = thm_esa_dfrac2scpot(edat, idat)
;PURPOSE:
; Estimates the SC potential from electrona and ions, by choosing the
; potential that gives ion density = electron density
;INPUT:
; edat = 3d data electron structure filled by themis routines get_th?_p???
; idat = 3d data ion structure filled by themis routines get_th?_p???
; use_n3dnew = if set, use n_3d_new.pro to get densities
; expected_fraction = if set, this is the value of electron density
; divided by ion density expected. The default is 1.75, that is we
; expect the electron density to be about 1,75 times the ion density.
;KEYWORDS:
;HISTORY:
; 2023-02-01, jmm, jimm@ssl.berkeley.edu
; $LastChangedBy: jimm $
; $LastChangedDate: 2025-03-11 13:52:33 -0700 (Tue, 11 Mar 2025) $
; $LastChangedRevision: 33164 $
; $URL: $
;
;-
Function thm_esa_dfrac2scpot, edat, idat, use_n3dnew = use_n3dnew, $
                              expected_fraction = expected_fraction, _extra = _extra
  
  If(~is_struct(edat) || edat.valid eq 0) Then Begin
     dprint, dlevel = 4, 'Invalid Electron Data'
     Return, -1
  Endif

  If(~is_struct(idat) || idat.valid eq 0) Then Begin
     dprint, dlevel = 4, 'Invalid Ion Data'
     Return, -1
  Endif

  scplo = min(edat.energy[where(edat.energy Gt 0)])
  scphi = 100.0
;If ion density is higher than electron density, then use the lower
;limit, or if we get a bad result
  If(keyword_set(use_n3dnew)) Then Begin
     tmp_dens_lo = density_fraction_n3dnew(scplo, expected_fraction = expected_fraction, $
                                           _extra = {edat:edat, idat:idat})
     If(tmp_dens_lo Lt 0.0) Then Return, scplo
;If Electron density is higher even at 100 V, then return scphi
     tmp_dens_hi = density_fraction_n3dnew(scphi, expected_fraction = expected_fraction, $
                                           _extra = {edat:edat, idat:idat})
     If(tmp_dens_hi Ge 0.0) Then Return, scphi
;Bisect for sc_potential 
     sc_pot_est = rtbis('density_fraction_n3dnew', scplo, scphi, expected_fraction = expected_fraction, $
                        _extra = {edat:edat, idat:idat})
  Endif Else Begin
     tmp_dens_lo = density_fraction(scplo, expected_fraction = expected_fraction, $
                                    _extra = {edat:edat, idat:idat})
     If(tmp_dens_lo Lt 0.0) Then Return, scplo
;If Electron density is higher even at 100 V, then return scphi
     tmp_dens_hi = density_fraction(scphi, expected_fraction = expected_fraction, $
                                    _extra = {edat:edat, idat:idat})
     If(tmp_dens_hi Ge 0.0) Then Return, scphi
;Bisect for sc_potential 
     sc_pot_est = rtbis('density_fraction', scplo, scphi, expected_fraction = expected_fraction, $
                        _extra = {edat:edat, idat:idat})
  Endelse
;A bad value will be NaN, return scplo
  If(~finite(sc_pot_est)) Then sc_pot_est = scplo
  
  Return, sc_pot_est

End
