/*-------------------------------------------------------------------------------*
 * Plane-parallel discrete ordinates radiative transfer program                  *
 * C version                                                                     *
 * Fortran ftp site: ftp://climate.gsfc.nasa.gov/pub/wiscombe/Multiple_Scatt/    *
 *-------------------------------------------------------------------------------*

  Calling Tree (omitting calls to c_errmsg, c_dbl_vector, c_int_vector, c_free_dbl_vector):

  c_disort-+-c_self_test-+-c_disort_state_alloc
         |               +-c_disort_out_alloc
         |               +-c_disort_state_free
         |               +-c_disort_out_free
         +-c_check_inputs-+-(c_write_bad_var)
         |                +-c_dref
         +-c_disort_set-+-c_gaussian_quadrature
         +-c_print_inputs
         +-c_albtrans-+-c_legendre_poly
         |            +-c_solve_eigen-+-c_asymmetric_matrix
         |            +-c_interp_eigenvec
         |            +-c_set_matrix
         |            +-(c_sgbco)
         |            +-c_solve1-+-(c_sgbsl)
         |            +-c_atltrin
         |            +-c_albtrans_spherical
         |            +-c_print_albtrans
         +-c_planck_func1
         +-c_legendre_poly
         +-c_surface_bidir-+-c_gaussian_quadrature
         |                 +-c_bidir_reflectivity
         +-c_solve_eigen-+-c_asymmetric_matrix
	 +-c_set_coefficients_beam_source
	 +-c_interp_coefficients_beam_source
         +-c_upbeam_pseudo_spherical-+-(c_sgeco)
         |                           +-(c_sgesl)
         +-c_upbeam-+-(c_sgeco)
         |          +-(c_sgesl)
         +-c_upisot-+-(c_sgeco)
         |          +-(c_sgesl)
         +-c_interp_eigenvec
         +-c_interp_source
         +-c_set_matrix
         +-c_solve0-+-(c_sgbco)
         |          +-(c_sgbsl)
         +-c_fluxes
         +-c_user_intensities
         +-c_intensity_components
         +-c_print_avg_intensities
         +-c_ratio
         +-c_intensity_correction-+-c_single_scat
         |                        +-c_secondary_scat-+-c_xi_func
         +-c_new_intensity_correction-+-c_single_scat
         |                            +-prep_double_scat_integr
         |                            +-c_new_secondary_scat-+-c_xi_func
         |                            +-calc_phase_squared
         +-c_print_intensities

 +-------------------------------------------------------------------+

  Index conventions (for all loops and all variable descriptions):

  iu       :  for user polar angles
  iq,jq,kq :  for computational polar angles ('quadrature angles')
  iq/2     :  for half the computational polar angles (just the ones in either 0-90 degrees, or 90-180 degrees)
  j        :  for user azimuthal angles
  k,l      :  for Legendre expansion coefficients or, alternatively, subscripts of associated Legendre polynomials
  lu       :  for user levels
  lc       :  for computational layers (each having a different single-scatter albedo and/or phase function)
  lev      :  for computational levels
  mazim    :  for azimuthal components in Fourier cosine expansion of intensity and phase function

 +------------------------------------------------------------------+

               I N T E R N A L    V A R I A B L E S

   AMB(iq/2,iq/2)....First  matrix factor in reduced eigenvalue problem of eqs. SS(12), STWJ(8E), STWL(23f) (used only in solve_eigen);
                     ab[].zero (see cdisort.h)
   APB(iq/2,iq/2)....Second matrix factor in reduced eigenvalue problem of eqs. SS(12), STWJ(8E), STWL(23f) (used only in solve_eigen);
                     ab[].one (see cdisort.h)
   ARRAY(iq,iq)......Scratch matrix for solve_eigen(), upbeam() and upisot()
                     (see each subroutine for definition)
   B()...............Right-hand side vector of eq. SC(5) going into SOLVE0,1;
                     returns as solution vector vector  L, the constants of integration
   BDR(iq/2,0:iq/2)..Bottom-boundary bidirectional reflectivity for a given azimuthal component.  First index always
                     refers to a computational angle.  Second index: if zero, refers to incident beam angle UMU0;
                     if non-zero, refers to a computational angle.
   BEM(iq/2).........Bottom-boundary directional emissivity at computational angles.
   bplanck...........Intensity emitted from bottom boundary
   callnum...........Number of surface calls
   CBAND()...........Matrix of left-hand side of the linear system eq. SC(5), scaled by eq. SC(12);
                     in banded form required by LINPACK solution routines
   CC(iq,iq).........C-sub-IJ in eq. SS(5)
   CH(lc)............The Chapman-factor to correct for pseudo-spherical geometry in the direct beam.
   CHTAU(lc).........The optical depth in spherical geometry.
   CMU(iq)...........Computational polar angles (Gaussian)
   CWT(iq)...........Quadrature weights corresponding to CMU
   corint............When set TRUE, correct intensities for delta-scaling effects (see Nakajima and Tanaka, 1988).
                     When FALSE, intensities are not corrected. In general, CORINT should be set true when beam
                     source is present (FBEAM is not zero) and DELTAM is TRUE in a problem including scattering.
                     However, execution is faster when CORINT is FALSE, and intensities outside the aureole may still be
                     accurate enough.  When CORINT is TRUE, it is important to have a sufficiently high order of
                     Legendre approximation of the phase function. This is because the intensities are corrected by
                     calculating the single-scattered radiation, for which an adequate representation of the phase
                     function is crucial.  In case of a low order Legendre approximation of an otherwise highly
                     anisotropic phase function, the intensities might actually be more accurate when corint is FALSE.
                     When only fluxes are calculated (ds->flag.onlyfl is TRUE), or there is no beam source (FBEAM=0.0), or there
                     is no scattering (SSALB =0. for all layers) corint is set FALSE by the code.
   delm0.............Kronecker delta, delta-sub-M0, where M = MAZIM is the number of the Fourier component in the
                     azimuth cosine expansion
   deltam............TRUE,  use delta-M method ( see Wiscombe, 1977 );
                     FALSE, do not use delta-M method.
                     In general, for a given number of streams, intensities and fluxes will be more accurate for phase functions
                     with a large forward peak if DELTAM is set true. Intensities close to the forward scattering
                     direction are often less accurate, however, when the delta-M method is applied. The intensity deltam
                     correction of Nakajima and Tanaka is used to improve the accuracy of the intensities.
   dither............Small quantity subtracted from single-scattering albedos of unity, in order to avoid using special
                     case formulas;  prevents an eigenvalue of exactly zero from occurring, which would cause an immediate overflow
   DTAUCPR(lc).......Computational-layer optical depths (delta-M-scaled if DELTAM = TRUE, otherwise equal to DTAUC)
   EMU(iu)...........Bottom-boundary directional emissivity at user angles.
   EVAL(iq)..........Temporary storage for eigenvalues of eq. SS(12)
   EVECC(iq,iq)......Complete eigenvectors of SS(7) on return from solve_eigen; stored permanently in  GC
   EXPBEA(lc)........Transmission of direct beam in delta-M optical depth coordinates
   FLYR(lc)..........Separated fraction in delta-M method
   GL(k,lc)..........Phase function Legendre polynomial expansion coefficients, calculated from PMOM by
                     including single-scattering albedo, factor 2K+1, and (if DELTAM=TRUE) the delta-M scaling
   GC(iq,iq,lc)......Eigenvectors at polar quadrature angles, g in eq. SC(1)
   GU(iu,iq,lc)......Eigenvectors interpolated to user polar angles (g  in eqs. SC(3) and S1(8-9), i.e. g without the l factor)
   IPVT(lc*iq).......Integer vector of pivot indices for LINPACK routines
   KK(iq,lc).........Eigenvalues of coeff. matrix in eq. SS(7)
   kconv.............Counter in azimuth convergence test
   LAYRU(lu).........Computational layer in which user output level UTAU(LU) is located
   LL(iq,lc).........Constants of integration L in eq. SC(1), obtained by solving scaled version of eq. SC(5)
   lyrcut............TRUE, radiation is assumed zero below layer ncut because of almost complete absorption
   naz...............Number of azimuthal components considered
   ncut..............Computational layer number in which absorption optical depth first exceeds ABSCUT
   OPRIM(lc).........Single scattering albedo after delta-M scaling
   pass1.............TRUE on first entry, FALSE thereafter
   PKAG(0:lc)........Integrated Planck function for internal emission
   PRNTU0(l).........logical flag to trigger printing of azimuthally-averaged intensities:
                       l    quantities printed
                      --    ------------------
                       0    azimuthally-averaged intensities at user
                               levels and computational polar angles
                       1    azimuthally-averaged intensities at user
                               levels and user polar angles
   PSI0(iq)..........Sum just after square bracket in  eq. SD(9); psi[].zero (see cdisort.h)
   PSI1(iq)..........Sum in  eq. STWL(31d); psi[].one
   RMU(iu,0:iq)......Bottom-boundary bidirectional reflectivity for a given azimuthal component.  First index always
                     refers to a user angle.  Second index: if zero, refers to incident beam angle UMU0;
                     if non-zero, refers to a computational angle.
   scat_yes..........int, TRUE if scattering, FALSE if not (added to C version)
   TAUC(0:lc)........Cumulative optical depth (un-delta-M-scaled)
   TAUCPR(0:lc)......Cumulative optical depth (delta-M-scaled if DELTAM = TRUE, otherwise equal to TAUC)
   tplanck...........Intensity emitted from top boundary
   UUM(iu,lu)........Expansion coefficients when the intensity (u-super-M) is expanded in Fourier cosine series
                     in azimuth angle
   U0C(iq,lu)........Azimuthally-averaged intensity at quadrature angle
   U0U(iu,lu)........If ds->flag.onlyfl = FALSE, azimuthally-averaged intensity at user angles and user levels
                     If ds->flag.onlyfl = TRUE, azimuthally-averaged intensity at computational
                     (Gaussian quadrature) angles and user levels; the corresponding quadrature angle cosines are
                     returned in UMU.
   UTAUPR(lu)........Optical depths of user output levels in delta-M coordinates; equal to UTAU(LU) if no delta-M
   WK(iq)............Scratch array
   XR0(lc)...........X-sub-zero in expansion of thermal source function preceding eq. SS(14)(has no mu-dependence); b-sub-zero in eq. STWL(24d)
   XR1(lc)...........X-sub-one in expansion of thermal source function; see eqs. SS(14-16); b-sub-one in STWL(24d)
   YLM0(l)...........Normalized associated Legendre polynomial of subscript L at the beam angle (not saved
                     as function of superscipt M)
   YLMC(l,iq)........Normalized associated Legendre polynomial of subscript L at the computational angles
                     (not saved as function of superscipt M)
   YLMU(l,iu)........Normalized associated Legendre polynomial of subscript L at the user angles
                     (not saved as function of superscipt M)
   Z()...............scratch array used in solve0(), albtrans() to solve a linear system for the constants of integration
   Z0(iq)............Solution vectors Z-sub-zero of eq. SS(16); zee[].zero (see cdisort.h)
   Z1(iq)............Solution vectors Z-sub-one  of eq. SS(16); zee[].one
   Z0U(iu,lc)........Z-sub-zero in eq. SS(16) interpolated to user angles from an equation derived from SS(16); zu[].zero (see cdisort.h)
   Z1U(iu,lc)........Z-sub-one  in eq. SS(16) interpolated to user angles from an equation derived from SS(16); zu[].one
   ZBEAM(iu,lc)......Particular solution for beam source
   ZJ(iq)............Right-hand side vector  X-sub-zero in eq. SS(19), also the solution vector
                     Z-sub-zero after solving that system
   ZZ(iq,lc).........Permanent storage for the beam source vectors ZJ
   ZPLK0(iq,lc)......Permanent storage for the thermal source vectors plk[].zero obtained by solving eq. SS(16)
   ZPLK1(iq,lc)......Permanent storage for the thermal source vectors plk[].one  obtained by solving eq. SS(16)

*/


/*
  Supplies surface bi-directional reflectivity.

  NOTE 1: Bidirectional reflectivity in DISORT is defined by eq. 39 in STWL.
  NOTE 2: Both MU and MU0 (cosines of reflection and incidence angles) are positive.

  Translated from fortran to C by Robert Buras; original name BDREF

  INPUT:

    wvnmlo    : Lower wavenumber (inv cm) of spectral interval
    wvnmhi    : Upper wavenumber (inv cm) of spectral interval
    mu        : Cosine of angle of reflection (positive)
    mup       : Cosine of angle of incidence (positive)
    dphi      : Difference of azimuth angles of incidence and reflection
                (radians)
    brdf_type : BRDF type
    brdf      : BRDF input
    callnum   : number of surface calls

  LOCAL VARIABLES:

    ans       :  Return variable
    badmu     :  minimally allowed value for mu1 and mu2
    flxalb    :
    irmu      :
    rmu       :
    swvnmlo   : value of wvnmlo from last call of this routine
    swvnmhi   : value of wvnmhi from last call of this routine
    srho0     : value of rho0   from last call of this routine
    sk        : value of k      from last call of this routine
    stheta    : value of theta  from last call of this routine
    ssigma    : value of sigma  from last call of this routine
    st1       : value of t1     from last call of this routine
    st2       : value of t2     from last call of this routine
    sscale    : value of scale  from last call of this routine
    siso      : value of iso    from last call of this routine
    svol      : value of vol    from last call of this routine
    sgeo      : value of geo    from last call of this routine
    su10      : value of u10    from last call of this routine
    spcl      : value of pcl    from last call of this routine
    ssal      : value of sal    from last call of this routine

   Called by- c_dref, c_surface_bidir
   Calls- c_dref, c_bidir_reflectivity_hapke,
          c_bidir_reflectivity_rpv, ocean_brdf, ambrals_brdf
-------------------------------------------------------------------------*/


/*
 * Hapke's BRDF model (times Pi/Mu0):
 *   Hapke, B., Theory of reflectance and emittance spectroscopy, Cambridge University Press, 1993,
 * eq. 8.89 on page 233. Parameters are from Fig. 8.15 on page 231, except for w.

  INPUT:

    wvnmlo : Lower wavenumber (inv cm) of spectral interval
    wvnmhi : Upper wavenumber (inv cm) of spectral interval
    mu     : Cosine of angle of reflection (positive)
    mup    : Cosine of angle of incidence (positive)
    dphi   : Difference of azimuth angles of incidence and reflection
                (radians)

  LOCAL VARIABLES:

    iref   : bidirectional reflectance options; 1 - Hapke's BDR model
    b0     : empirical factor to account for the finite size of particles in Hapke's BDR model
    b      : term that accounts for the opposition effect (retroreflectance, hot spot) in Hapke's BDR model
    ctheta : cosine of phase angle in Hapke's BDR model
    gamma  : albedo factor in Hapke's BDR model
    h0     : H(mu0) in Hapke's BDR model
    h      : H(mu) in Hapke's BDR model
    hh     : angular width parameter of opposition effect in Hapke's BDR model
    p      : scattering phase function in Hapke's BDR model
    theta  : phase angle (radians); the angle between incidence and reflection directions in Hapke's BDR model
    w      : single scattering albedo in Hapke's BDR model

   Called by- c_bidir_reflectivity
-------------------------------------------------------------------------*/


/*
  Computes the Rahman, Pinty, Verstraete BRDF.  The incident
  and outgoing cosine zenith angles are MU1 and MU2, respectively,
  and the relative azimuthal angle is PHI.  In this case the incident
  direction is where the radiation is coming from, so MU1>0 and
  the hot spot is MU2=MU1 and PHI=180 (the azimuth convention is
  different from the original Frank Evans code).
  The reference is:
  Rahman, Pinty, Verstraete, 1993: Coupled Surface-Atmosphere
  Reflectance (CSAR) Model. 2. Semiempirical Surface Model Usable
  With NOAA Advanced Very High Resolution Radiometer Data,
  J. Geophys. Res., 98, 20791-20801.

  Translated from fortran to C by Robert Buras; original name RPV_REFLECTION

  INPUT:

    rho0   :  BRDF rpv: rho0
    k      :  BRDF rpv: k
    theta  :  BRDF rpv: theta
    sigma  :  BRDF rpv snow: sigma
    t1     :  BRDF rpv snow: t1
    t2     :  BRDF rpv snow: t2
    scale  :  BRDF rpv: scale
    mu1    :  Cosine of angle of reflection (positive)
    mu2    :  Cosine of angle of incidence (positive)
    phi    :  Difference of azimuth angles of incidence and reflection
                 (radians)
    badmu  :  minimally allowed value for mu1 and mu2

  LOCAL VARIABLES:

    ans    :  Return value

   Called by- c_bidir_reflectivity
-------------------------------------------------------------------------*/


/*
 * Calculate phase function Legendre expansion coefficients in various special cases.
 *
 *  INPUT
 *    iphas  Phase function options
 *                       ISOTROPIC: Isotropic
 *                        RAYLEIGH: Rayleigh
 *               HENYEY_GREENSTEIN: Henyey-Greenstein with asymmetry factor GG
 *             HAZE_GARCIA_SIEWART: Haze L as specified by Garcia/Siewert
 *            CLOUD_GARCIA_SIEWART: Cloud C.1 as specified by Garcia/Siewert
 *    gg      Asymmetry factor for Henyey-Greenstein case
 *    nmom    Index of highest Legendre coefficient needed (number of streams 'nstr'
 *            chosen for the discrete ordinate method). Set to -1 for no scattering.
 *  OUTPUT
 *    PMOM(k) Legendre expansion coefficients (k = 0 to nmom)
 *
 * Reference:  Garcia, R. and C. Siewert, 1985: Benchmark Results in Radiative Transfer,
 *               Transp. Theory and Stat. Physics 14, 437-484, Tables 10 And 17
 */


/*
  Solves eigenfunction problem for real asymmetric matrix for which it
  is known a priori that the eigenvalues are real. This is an adaptation
  of a subroutine EIGRF in the IMSL library to use real instead of complex
  arithmetic, accounting for the known fact that the eigenvalues and
  eigenvectors in the discrete ordinate solution are real.

  EIGRF is based primarily on EISPACK routines.  The matrix is first
  balanced using the Parlett-Reinsch algorithm.  Then the Martin-Wilkinson
  algorithm is applied. There is a statement 'j = wk(i)' that converts a
  double precision variable to an integer variable; this seems dangerous
  to us in principle, but seems to work fine in practice.

  References:

  Dongarra, J. and C. Moler, EISPACK -- A Package for Solving Matrix
      Eigenvalue Problems, in Cowell, ed., 1984: Sources and Development of
      Mathematical Software, Prentice-Hall, Englewood Cliffs, NJ
  Parlett and Reinsch, 1969: Balancing a Matrix for Calculation of
      Eigenvalues and Eigenvectors, Num. Math. 13, 293-304
  Wilkinson, J., 1965: The Algebraic Eigenvalue Problem, Clarendon Press,
      Oxford

   I N P U T    V A R I A B L E S:

       aa    :  input asymmetric matrix, destroyed after solved
        m    :  order of aa
       ia    :  first dimension of aa
    ievec    :  first dimension of evec

   O U T P U T    V A R I A B L E S:

       evec  :  (unnormalized) eigenvectors of aa (column j corresponds to EVAL(J))
       eval  :  (unordered) eigenvalues of aa (dimension m)
       ier   :  if != 0, signals that EVAL(ier) failed to converge;
                   in that case eigenvalues ier+1,ier+2,...,m  are
                   correct but eigenvalues 1,...,ier are set to zero.

   S C R A T C H   V A R I A B L E S:

       wk    :  work area (dimension at least 2*m)

   Called by- c_solve_eigen
   Calls- c_errmsg
 -------------------------------------------------------------------*/


/*
    Calculates the Fourier intensity components at the quadrature
    angles for azimuthal expansion terms (mazim) in eq. SD(2),STWL(6)

    I N P U T    V A R I A B L E S:

       ds      :  Disort state variables
       kk      :  Eigenvalues of coeff. matrix in eq. SS(7), STWL(23b)
       gc      :  Eigenvectors at polar quadrature angles in eq. SC(1)
       ll      :  Constants of integration in eq. SC(1), obtained by solving scaled version of eq. SC(5);
                  exponential term of eq. SC(12) not included
       lyrcut  :  Logical flag for truncation of computational layer
       mazim   :  Order of azimuthal component
       ncut    :  Number of computational layer where absorption optical depth exceeds ABSCUT
       nn      :  Order of double-Gauss quadrature (NSTR/2)
       taucpr  :  Cumulative optical depth (delta-M-scaled)
       utaupr  :  Optical depths of user output levels in delta-M coordinates;  equal to UTAU if no delta-M
       zz      :  Beam source vectors in eq. SS(19), STWL(24b)
       plk     :  Thermal source vectors z0,z1 by solving eq. SS(16), Y-sub-zero, Y-sub-one in STWL(26ab);
                  plk[].zero, plk[].one (see cdisort.h)

    O U T P U T   V A R I A B L E S:

       uum     :  Fourier components of the intensity in eq. SD(12) (at polar quadrature angles)

    I N T E R N A L   V A R I A B L E S:

       fact    :  exp(-utaupr/umu0)
       zint    :  intensity of m=0 case, in eq. SC(1)

   Called by- c_disort
 -------------------------------------------------------------------*/


/*
    Calculates the radiative fluxes, mean intensity, and flux
    derivative with respect to optical depth from the m=0 intensity
    components (the azimuthally-averaged intensity)

    I N P U T    V A R I A B L E S:

       ds       :  Disort state variables
       cmu      :  Abscissae for Gauss quadrature over angle cosine
       cwt      :  Weights for Gauss quadrature over angle cosine
       gc       :  Eigenvectors at polar quadrature angles, SC(1)
       kk       :  Eigenvalues of coeff. matrix in eq. SS(7), STWL(23b)
       layru    :  Layer number of user level UTAU
       ll       :  Constants of integration in eq. SC(1), obtained by solving scaled version of eq. SC(5);
                   exponential term of eq. SC(12) not included
       lyrcut   :  Logical flag for truncation of comput. layer
       ncut     :  Number of computational layer where absorption optical depth exceeds ABSCUT
       nn       :  Order of double-Gauss quadrature (NSTR/2)
       prntu0   :  TRUE, print azimuthally-averaged intensity at quadrature angles
       taucpr   :  Cumulative optical depth (delta-M-scaled)
       utaupr   :  Optical depths of user output levels in delta-M coordinates;  equal to UTAU if no delta-M
       xr       :  Expansion of thermal source function in eq. SS(14,16), STWL(24c); xr[].zero, xr[].one (see cdisort.h)
       zz       :  Beam source vectors in eq. SS(19), STWL(24b)
       plk      :  Thermal source vectors z0,z1 by solving eq. SS(16), Y0,Y1 in STWL(26b,a);
                   plk[].zero, plk[].one (see cdisort.h)

    O U T P U T    V A R I A B L E S:

       out      : Disort output variables
       u0c      :  Azimuthally averaged intensities (at polar quadrature angles)

    I N T E R N A L    V A R I A B L E S:

       dirint   :  Direct intensity attenuated
       fdntot   :  Total downward flux (direct + diffuse)
       fl       :  fl[].zero: 'fldir' = direct-beam flux (delta-M scaled), fl[].one 'fldn' = diffuse down-flux (delta-M scaled)
       fnet     :  Net flux (total_down-diffuse_up)
       fact     :  EXP(- UTAUPR/UMU0)
       plsorc   :  Planck source function (thermal)
       zint     :  Intensity of m = 0 case, in eq. SC(1)

   Called by- c_disort
 -------------------------------------------------------------------*/


/*
       Corrects intensity field by using Nakajima-Tanaka algorithm
       (1988). For more details, see Section 3.6 of STWL NASA report.
                I N P U T   V A R I A B L E S

       ds      Disort state variables
       dither  small multiple of machine precision
       flyr    separated fraction in delta-M method
       layru   index of UTAU in multi-layered system
       lyrcut  logical flag for truncation of computational layer
       ncut    total number of computational layers considered
       oprim   delta-M-scaled single-scatter albedo
       phirad  azimuthal angles in radians
       tauc    optical thickness at computational levels
       taucpr  delta-M-scaled optical thickness
       utaupr  delta-M-scaled version of UTAU

                O U T P U T   V A R I A B L E S

       out->UU  corrected intensity field; UU(IU,LU,J)
                 iu=1,ds->numu; lu=1,ds->ntau; j=1,ds->nphi

                I N T E R N A L   V A R I A B L E S

       ctheta  cosine of scattering angle
       dtheta  angle (degrees) to define aureole region as
                    direction of beam source +/- DTHETA
       phasa   actual (exact) phase function
       phasm   delta-M-scaled phase function
       phast   phase function used in TMS correction; actual phase
                    function divided by (1-FLYR*SSALB)
       pl      ordinary Legendre polynomial of degree l, P-sub-l
       plm1    ordinary Legendre polynomial of degree l-1, P-sub-(l-1)
       plm2    ordinary Legendre polynomial of degree l-2, P-sub-(l-2)
       theta0  incident zenith angle (degrees)
       thetap  emergent angle (degrees)
       ussndm  single-scattered intensity computed by using exact
                   phase function and scaled optical depth
                   (first term in STWL(68a))
       ussp    single-scattered intensity from delta-M method
                   (second term in STWL(68a))
       duims   intensity correction term from IMS method
                   (delta-I-sub-IMS in STWL(A.19))

   Called by- c_disort
   Calls- c_single_scat, c_secondary_scat
 -------------------------------------------------------------------*/


/*
   Calculates secondary scattered intensity of eq. STWL (A7)

                I N P U T   V A R I A B L E S

        ds      Disort state variables
        iu      index of user polar angle
        lu      index of user level
        ctheta  cosine of scattering angle
        flyr    separated fraction f in Delta-M method
        layru   index of utau in multi-layered system
        tauc    cumulative optical depth at computational layers

                I N T E R N A L   V A R I A B L E S

        pspike  2*p"-p"*p", where p" is the residual phase function
        wbar    mean value of single scattering albedo
        fbar    mean value of separated fraction f
        dtau    layer optical depth
        stau    sum of layer optical depths between top of atmopshere and layer layru

   Called by- c_intensity_correction
   Calls- c_xi_func
 -------------------------------------------------------------------*/


/*
       Corrects intensity field by using alternative Buras-Emde algorithm
       (201X).

                I N P U T   V A R I A B L E S

       ds      Disort state variables
       dither  small multiple of machine precision
       flyr    separated fraction in delta-M method
       layru   index of UTAU in multi-layered system
       lyrcut  logical flag for truncation of computational layer
       ncut    total number of computational layers considered
       oprim   delta-M-scaled single-scatter albedo
       phirad  azimuthal angles in radians
       tauc    optical thickness at computational levels
       taucpr  delta-M-scaled optical thickness
       utaupr  delta-M-scaled version of UTAU

                O U T P U T   V A R I A B L E S

       out->UU  corrected intensity field; UU(IU,LU,J)
                 iu=1,ds->numu; lu=1,ds->ntau; j=1,ds->nphi

                I N T E R N A L   V A R I A B L E S

       ctheta    cosine of scattering angle
       dtheta    angle (degrees) to define aureole region as
                      direction of beam source +/- DTHETA
       phasa     actual (exact) phase function
       phasm     delta-M-scaled phase function
       phast     phase function used in TMS correction; actual phase
                      function divided by (1-FLYR*SSALB)
       pl        ordinary Legendre polynomial of degree l, P-sub-l
       plm1      ordinary Legendre polynomial of degree l-1, P-sub-(l-1)
       plm2      ordinary Legendre polynomial of degree l-2, P-sub-(l-2)
       theta0    incident zenith angle (degrees)
       thetap    emergent angle (degrees)
       ussndm    single-scattered intensity computed by using exact
                     phase function and scaled optical depth
                     (first term in STWL(68a))
       ussp      single-scattered intensity from delta-M method
                     (second term in STWL(68a))
       duims     intensity correction term from IMS method
                     (delta-I-sub-IMS in STWL(A.19))
       nf        number of angular phase integration grid point
                     (zenith angle, theta)
       np        number of angular phase integration grid point
                     (azimuth angle, phi)
       nphase    number of angles for which original phase function
                     (ds->phase) is defined
       mu_eq     cos(theta) phase integration grid points,
                     equidistant in abs(f_phas2)
       norm_phas normalization factor for phase integration
       norm      normalization factor for preparation of phas2
       neg_phas  index whether phas2 is negative
       phas2     residual phase function
       phasr     delta-M scaled phase function
       f_phas2   cumulative integrated phase function phas2
       fbar      mean value of separated fraction f

   Called by- c_disort
   Calls- c_single_scat, c__new_secondary_scat,
          prep_double_scat_integr, c_dbl_vector
 -------------------------------------------------------------------*/


/*
       Prepares double scattering integration according to alternative
       Buras-Emde algorithm(201X).

                I N P U T   V A R I A B L E S

       nphase    number of angles for which original phase function
                     (ds->phase) is defined
       ntau
       nf        number of angular phase integration grid point
                     (zenith angle, theta)
       mu_phase  cos(theta) grid of phase function
       phas2     residual phase function

                O U T P U T   V A R I A B L E S

       mu_eq     cos(theta) phase integration grid points,
                     equidistant in abs(f_phas2)
       neg_phas  index whether phas2 is negative
       norm_phas normalization factor for phase integration

                I N T E R N A L   V A R I A B L E S

       f_phas2_abs absolute value of integrated phase function
                      phas2
       f_phas2     cumulative integrated phase function phas2
       df          step length for calculating mu_eq

   Called by- c_new_intensity_correction
   Calls- c_dbl_vector, locate
 -------------------------------------------------------------------*/


/*
   Calculates secondary scattered intensity, new method (see BDE)

                I N P U T   V A R I A B L E S

        ds        Disort state variables
        iu        index of user polar angle
        lu        index of user level
	it	  index where ctheta contained in mu grid of exact
	             phase function
        ctheta    cosine of scattering angle
        flyr      separated fraction f in Delta-M method
        layru     index of utau in multi-layered system
        tauc      cumulative optical depth at computational layers
        nf        number of angular phase integration grid point
                     (zenith angle, theta)
        phas2     residual phase function
        mu_eq     cos(theta) phase integration grid points,
                     equidistant in abs(f_phas2)
        neg_phas  index whether phas2 is negative
        norm_phas normalization factor for phase integration

                I N T E R N A L   V A R I A B L E S

        pspike  2*p"-p"*p", where p" is the residual phase function
        pspike1 2*p", where p" is the residual phase function
        pspike2 p"*p", where p" is the residual phase function
        wbar    mean value of single scattering albedo
        fbar    mean value of separated fraction f
        dtau    layer optical depth
        stau    sum of layer optical depths between top of atmopshere and layer layru
	umu0p
        nphase  number of angles for which original phase function
                   (ds->phase) is defined

   Called by- c_new_intensity_correction
   Calls- calc_phase_squared, c_xi_func
 -------------------------------------------------------------------*/


/*
   Calculates squared phase function (see BDE)

                I N P U T   V A R I A B L E S

        nphase  number of angles for which original phase function
                   (ds->phase) is defined
        lu        index of user level
        ctheta  cosine of scattering angle
        nf        number of angular phase integration grid point
                     (zenith angle, theta)
        mu_phase  cos(theta) grid of phase function
        phas2     residual phase function
        mu_eq     cos(theta) phase integration grid points,
                     equidistant in abs(f_phas2)
        neg_phas  index whether phas2 is negative
        norm_phas normalization factor for phase integration

                I N T E R N A L   V A R I A B L E S

        pspike2  p"*p", where p" is the residual phase function; return value
	mu1arr
	stheta   corresponding sin of ctheta
	smueq    corresponding sin of mu_eq
	phint    phase function integrated over phi
	scr

   Called by- c_new_secondary_scat
 -------------------------------------------------------------------*/


/*
    Perform miscellaneous setting-up operations

    I N P U T  V A R I A B L E S

       ds         Disort state variables
       deltam
       tauc

    O U T P U T     V A R I A B L E S:

       If ds->flag.usrtau is FALSE
       ds->ntau
       ds->utau

       If ds->flag.usrang is FALSE
       ds->numu
       ds->umu

       cmu,cwt     computational polar angles and corresponding quadrature weights
       dtaucpr
       expbea      transmission of direct beam
       flyr        separated fraction in delta-m method
       gl          phase function legendre coefficients multiplied by (2l+1) and single-scatter albedo
       layru       computational layer in which utau falls
       lyrcut      flag as to whether radiation will be zeroed below layer ncut
       ncut        computational layer where absorption optical depth first exceeds  abscut
       nn          ds->nstr/2
       oprim       delta-m-scaled single-scatter albedo
       taucpr      delta-m-scaled optical depth
       utaupr      delta-m-scaled version of  utau

   Called by- c_disort
   Calls- c_gaussian_quadrature, c_errmsg

 ---------------------------------------------------------------------*/


/*
    Calculate coefficient matrix for the set of equations obtained from the
    boundary conditions and the continuity-of-intensity-at-layer-interface equations.

    Store in the special banded-matrix format required by LINPACK routines

    I N P U T      V A R I A B L E S:

       ds       :  Disort state variables
       bdr      :  surface bidirectional reflectivity
       cmu,cwt  :  abscissae, weights for Gauss quadrature over angle cosine
       delm0    :  Kronecker delta, delta-sub-m0
       gc       :  Eigenvectors at polar quadrature angles, SC(1)
       kk       :  Eigenvalues of coeff. matrix in eq. SS(7), STWL(23b)
       lyrcut   :  Logical flag for truncation of computational layers
       nn       :  Number of streams in a hemisphere (NSTR/2)
       ncut     :  Total number of computational layers considered
       taucpr   :  Cumulative optical depth (delta-M-scaled)

   O U T P U T     V A R I A B L E S:

       cband    :  Left-hand side matrix of linear system eq. SC(5), scaled by eq. SC(12);
                   in banded form required by LINPACK solution routines
       ncol     :  Number of columns in cband

   I N T E R N A L    V A R I A B L E S:

       irow     :  Points to row in CBAND
       jcol     :  Points to position in layer block
       lda      :  Row dimension of CBAND
       ncd      :  Number of diagonals below or above main diagonal
       nshift   :  For positioning number of rows in band storage
       wk       :  Temporary storage for EXP evaluations

   BAND STORAGE

      LINPACK requires band matrices to be input in a special
      form where the elements of each diagonal are moved up or
      down (in their column) so that each diagonal becomes a row.
      (The column locations of diagonal elements are unchanged.)

      Example:  if the original matrix is

          11 12 13  0  0  0
          21 22 23 24  0  0
           0 32 33 34 35  0
           0  0 43 44 45 46
           0  0  0 54 55 56
           0  0  0  0 65 66

      then its LINPACK input form would be:

           *  *  *  +  +  +  , * = not used
           *  * 13 24 35 46  , + = used for pivoting
           * 12 23 34 45 56
          11 22 33 44 55 66
          21 32 43 54 65  *

      If A is a band matrix, the following program segment
      will convert it to the form (ABD) required by LINPACK
      band-matrix routines:

        n  = (column dimension of a, abd)
        ml = (band width below the diagonal)
        mu = (band width above the diagonal)
        m = ml+mu+1;
        for (j = 1; j <= n; j++) {
          i1 = IMAX(1,j-mu);
          i2 = IMIN(n,j+ml);
          for (i = i1; i <= i2; i++) {
            k = i-j+m;
            ABD(k,j) = A(i,j);
          }
        }

      This uses rows  ml+1 through  2*ml+mu+1  of ABD.
      The total number of rows needed in ABD is 2*ml+mu+1.
      In the example above, n = 6, ml = 1, mu = 2, and the
      row dimension of ABD must be >= 5.

   Called by- c_disort, c_albtrans
 -------------------------------------------------------------------*/


/*
        Calculates single-scattered intensity from eqs. STWL (65b,d,e)

                I N P U T   V A R I A B L E S

        dither   small multiple of machine precision
        layru    index of utau in multi-layered system
        nlyr     number of sublayers
        phase    phase functions of sublayers
        omega    single scattering albedos of sublayers
        tau      optical thicknesses of sublayers
        umu      cosine of emergent angle
        umu0     cosine of incident zenith angle
        utau     user defined optical depth for output intensity
        fbeam   incident beam radiation at top

   Called by- c_intensity_correction
 -------------------------------------------------------------------*/


/*
        Construct right-hand side vector B for general boundary
        conditions STWJ(17) and solve system of equations obtained
        from the boundary conditions and the continuity-of-
        intensity-at-layer-interface equations.
        Thermal emission contributes only in azimuthal independence.

    I N P U T      V A R I A B L E S:

       ds       :  Disort input variables
       bdr      :  Surface bidirectional reflectivity
       bem      :  Surface bidirectional emissivity
       bplanck  :  Bottom boundary thermal emission
       cband    :  Left-hand side matrix of linear system eq. SC(5),
                   scaled by eq. SC(12); in banded form required
                   by LINPACK solution routines
       cmu,cwt  :  Abscissae, weights for Gauss quadrature
                   over angle cosine
       expbea   :  Transmission of incident beam, EXP(-TAUCPR/UMU0)
       lyrcut   :  Logical flag for truncation of computational layers
       mazim    :  Order of azimuthal component
       ncol     :  Number of columns in CBAND
       nn       :  Order of double-Gauss quadrature (NSTR/2)
       ncut     :  Total number of computational layers considered
       tplanck  :  Top boundary thermal emission
       taucpr   :  Cumulative optical depth (delta-M-scaled)
       zz       :  Beam source vectors in eq. SS(19), STWL(24b)
       plk      :  Thermal source vectors z0,z1 by solving eq. SS(16), Y0,Y1 in STWL(26b,a);
                   plk[].zero, plk[].one (see cdisort.h)

    O U T P U T     V A R I A B L E S:

       b        :  Right-hand side vector of eq. SC(5) going into
                   sgbsl; returns as solution vector of eq. SC(12),
                   constants of integration without exponential term
      ll        :  Permanent storage for B, but re-ordered

   I N T E R N A L    V A R I A B L E S:

       ipvt     :  Integer vector of pivot indices
       it       :  Pointer for position in  B
       ncd      :  Number of diagonals below or above main diagonal
       rcond    :  Indicator of singularity for cband
       z        :  Scratch array required by sgbco

   Called by- c_disort
   Calls- c_sgbco, c_errmsg, c_sgbsl
 +-------------------------------------------------------------------*/


/*
       Computes user's' surface bidirectional properties, STWL(41)

   I N P U T     V A R I A B L E S:

       ds     :  Disort input variables
       cmu    :  Computational polar angle cosines (Gaussian)
       delm0  :  Kronecker delta, delta-sub-m0
       mazim  :  Order of azimuthal component
       nn     :  Order of Double-Gauss quadrature (ds->nstr/2)
       callnum:  number of surface calls

    O U T P U T     V A R I A B L E S:

       bdr :  Fourier expansion coefficient of surface bidirectional
                 reflectivity (computational angles)
       rmu :  Surface bidirectional reflectivity (user angles)
       bem :  Surface directional emissivity (computational angles)
       emu :  Surface directional emissivity (user angles)

    I N T E R N A L     V A R I A B L E S:

       dref   :  Directional reflectivity
       gmu    :  The NMUG angle cosine quadrature points on (0,1)
                 NMUG is set in cdisort.h
       gwt    :  The NMUG angle cosine quadrature weights on (0,1)

   Called by- c_disort
   Calls- c_gaussian_quadrature, c_bidir_reflectivity
+---------------------------------------------------------------------*/


/*
   Interpolate eigenvectors to user angles; eq SD(8)

   Called by- c_disort, c_albtrans
 --------------------------------------------------------------------*/


/*
    Interpolates source functions to user angles, eq. STWL(30)

    I N P U T      V A R I A B L E S:

       ds     :  Disort state variables
       cwt    :  Weights for Gauss quadrature over angle cosine
       delm0  :  Kronecker delta, delta-sub-m0
       gl     :  Delta-M scaled Legendre coefficients of phase function
                 (including factors 2l+1 and single-scatter albedo)
       mazim  :  Order of azimuthal component
       oprim  :  Single scattering albedo
       xr     :  Expansion of thermal source function, eq. STWL(24d); xr[].zero, xr[].one (see cdisort.h)
       ylm0   :  Normalized associated Legendre polynomial at the beam angle
       ylmc   :  Normalized associated Legendre polynomial at the quadrature angles
       ylmu   :  Normalized associated Legendre polynomial at the user angles
       zbs0   :  Solution vectors z-sub-zero of Eq. KS(10-11), used if pseudo-spherical
       zbs1   :  Solution vectors z-sub-one  of Eq. KS(10-11), used if pseudo-spherical
       zbsa   :  Alfa coefficient in Eq. KS(7), used if pseudo-spherical
       zee    :  Solution vectors Z-sub-zero, Z-sub-one of eq. SS(16), STWL(26a,b)
       zj     :  Solution vector Z-sub-zero after solving eq. SS(19), STWL(24b)

    O U T P U T     V A R I A B L E S:

       zbeam  :  Incident-beam source function at user angles
       zu     :  Components 0 and 1 of a linear-in-optical-depth-dependent source (approximating the Planck emission source)

   I N T E R N A L    V A R I A B L E S:

       psi  :   psi[].zero: Sum just after square bracket in eq. SD(9)
                psi[].one:  Sum in eq. STWL(31d)

   Called by- c_disort
 -------------------------------------------------------------------*/


/*

    I N P U T      V A R I A B L E S:

       cmu    :   Computational polar angles
       chtau  :   The optical depth in spherical geometry.
       delmo  :   Kronecker delta, delta-sub-m0
       fbeam  :   incident beam radiation at top
       gl     :   Phase function Legendre coefficients multiplied by (2l+1) and single-scatter albedo
       lc:    :   layer index
       mazim  :   order of azimuthal component
       nstr   :   number of streams
       numu   :   number of user angles
       taucpr :   delta-m-scaled optical depth
       xba    :   alfa in eq. KS(7)
       ylmu   :   Normalized associated Legendre polynomial at the user angles -umu-
       ylm0   :   Normalized associated Legendre polynomial at the beam angle

    O U T P U T     V A R I A B L E S:

       zb0u   :   x-sub-zero in KS(7) at user angles -umu-
       zb1u   :   x-sub-one in KS(7) at user angles -umu-
       zju    :  Solution vector Z-sub-zero after solving eq. SS(19), STWL(24b), at user angles -umu-

   Called by- c_disort

*/


/*
       Set coefficients in ks(7) for beam source

    I N P U T      V A R I A B L E S:

       cmu    :   Computational polar angles
       ch     :   The Chapman-factor to correct for pseudo-spherical geometry in the direct beam.
       chtau  :   The optical depth in spherical geometry.
       delmo  :   Kronecker delta, delta-sub-m0
       fbeam  :   incident beam radiation at top
       gl     :   Phase function Legendre coefficients multiplied by (2l+1) and single-scatter albedo
       lc:    :   layer index
       mazim  :   order of azimuthal component
       nstr   :   number of streams
       taucpr :   delta-m-scaled optical depth
       ylmc   :   Normalized associated Legendre polynomial at the quadrature angles -cmu-
       ylm0   :   Normalized associated Legendre polynomial at the beam angle

    O U T P U T     V A R I A B L E S:

       xba    :   alfa in eq. KS(7)
       xb0    :   x-sub-zero in KS(7)
       xb1    :   x-sub-one in KS(7)
       zj     :  Solution vector Z-sub-zero after solving eq. SS(19), STWL(24b)

   Called by- c_disort
 -------------------------------------------------------------------*/


/*
   Computes intensity components at user output angles for azimuthal
   expansion terms in eq. SD(2), STWL(6)

   I N P U T    V A R I A B L E S:

       ds     :  Disort state variables
       bplanck:  Integrated Planck function for emission from
                 bottom boundary
       cmu    :  Abscissae for Gauss quadrature over angle cosine
       cwt    :  Weights for Gauss quadrature over angle cosine
       delm0  :  Kronecker delta, delta-sub-M0
       emu    :  Surface directional emissivity (user angles)
       expbea :  Transmission of incident beam, EXP(-TAUCPR/UMU0)
       gc     :  Eigenvectors at polar quadrature angles, SC(1)
       gu     :  Eigenvectors interpolated to user polar angles
                    (i.e., G in eq. SC(1) )
       kk     :  Eigenvalues of coeff. matrix in eq. SS(7), STWL(23b)
       layru  :  Layer number of user level UTAU
       ll     :  Constants of integration in eq. SC(1), obtained
                 by solving scaled version of eq. SC(5);
                 exponential term of eq. SC(12) not included
       lyrcut :  Logical flag for truncation of computational layer
       mazim  :  Order of azimuthal component
       ncut   :  Total number of computational layers considered
       nn     :  Order of double-Gauss quadrature (NSTR/2)
       rmu    :  Surface bidirectional reflectivity (user angles)
       taucpr :  Cumulative optical depth (delta-M-Scaled)
       tplanck:  Integrated Planck function for emission from
                 top boundary
       utaupr :  Optical depths of user output levels in delta-M
                 coordinates;  equal to UTAU if no delta-M
       zu     :  Z-sub-zero, Z-sub-one in eq. SS(16) interpolated to user angles from an equation derived from SS(16),
                 Y-sub-zero, Y-sub-one on STWL(26b,a); zu[].zero, zu[].one (see cdisort.h)
       zz     :  Beam source vectors in eq. SS(19), STWL(24b)
       plk    :  Thermal source vectors z0,z1 by solving eq. SS(16),
                 Y-sub-zero,Y-sub-one in STWL(26)
       zbeam  :  Incident-beam source vectors

    O U T P U T    V A R I A B L E S:

       uum    :  Azimuthal components of the intensity in eq. STWJ(5),
                 STWL(6)

    I N T E R N A L    V A R I A B L E S:

       bnddir :  Direct intensity down at the bottom boundary
       bnddfu :  Diffuse intensity down at the bottom boundary
       bndint :  Intensity attenuated at both boundaries, STWJ(25-6)
       dtau   :  Optical depth of a computational layer
       lyrend :  End layer of integration
       lyrstr :  Start layer of integration
       palint :  Intensity component from parallel beam
       plkint :  Intensity component from planck source
       wk     :  Scratch vector for saving exp evaluations

       All the exponential factors (exp1, expn,... etc.)
       come from the substitution of constants of integration in
       eq. SC(12) into eqs. S1(8-9).  They all have negative
       arguments so there should never be overflow problems.

   Called by- c_disort
 -------------------------------------------------------------------*/


/*
   Calculates Xi function of eq. STWL (72)

         I N P U T   V A R I A B L E S

   umu1,2    cosine of zenith angle_1, _2
   tau       optical thickness of the layer

   NOTE: Original Fortran version also had argument umu3, but was only
         called for the case umu2 == umu3, so these two arguments are
         fused together here to reduce conditional testing.

   Called by- c_secondary_scat
 -------------------------------------------------------------------*/


/*
 * Checks the input dimensions and variables
 *
 * Calls- c_write_bad_var, c_dref, c_errmsg
 * Called by- c_disort
 */


/*
  Flux albedo for given angle of incidence, given a bidirectional reflectivity.

  INPUTS
    wvnmlo    :  Lower wavenumber (inv-cm) of spectral interval
    wvnmhi    :  Upper wavenumber (inv-cm) of spectral interval
    mu        :  Cosine of incidence angle
    brdf_type :  BRDF type
    brdf      :  pointer to disort_brdf structure
    callnum   :  number of surface calls

  INTERNAL VARIABLES

    gmu    : The NMUG angle cosine quadrature points on (0,1)
             NMUG is set in cdisort.h
    gwt    : The NMUG angle cosine quadrature weights on (0,1)

   Called by- c_check_inputs
   Calls- c_gaussian_quadrature, c_errmsg, c_bidir_reflectivity
 --------------------------------------------------------------------*/


/*
       Computes the normalized associated Legendre polynomial, defined
       in terms of the associated Legendre polynomial Plm = P-sub-l-super-m as

          Ylm(MU) = sqrt( (l-m)!/(l+m)! ) * Plm(MU)

       for fixed order m and all degrees from l = m to TWONM1.
       When m.GT.0, assumes that Y-sub(m-1)-super(m-1) is available
       from a prior call to the routine.

       REFERENCE: Dave, J.V. and B.H. Armstrong, Computations of High-Order
                    Associated Legendre Polynomials, J. Quant. Spectrosc. Radiat. Transfer 10,
                    557-562, 1970. (hereafter D/A)

       METHOD: Varying degree recurrence relationship.

       NOTES:
       (1) The D/A formulas are transformed by setting m=n-1; l=k-1.
       (2) Assumes that routine is called first with  m = 0, then with
           m = 1, etc. up to  m = twonm1.

  I N P U T     V A R I A B L E S:

       nmu    :  Number of arguments of YLM
       m      :  Order of YLM
       maxmu  :
       twonm1 :  Max degree of YLM
       MU(i)  :  Arguments of YLM (i = 1 to nmu)

       If m > 0, YLM(m-1,i) for i = 1 to nmu is assumed to exist from a prior call.

  O U T P U T     V A R I A B L E:

       YLM(l,i) :  l = m to twonm1, normalized associated Legendre polynomials
                   evaluated at argument MU(i)

   Called by- c_disort, c_albtrans
 -------------------------------------------------------------------*/


/*
   Print azimuthally averaged intensities at user angles

   Called by- c_disort
 -------------------------------------------------------------------*/


/*
   Print values of input variables

   Called by- c_disort
 --------------------------------------------------------------------*/


/*
   Prints the intensity at user polar and azimuthal angles
   All arguments are disort state or output variables

   Called by- c_disort
 -------------------------------------------------------------------*/


/*
 * Calculate ratio a/b with overflow and underflow protection
 * (thanks to Prof. Jeff Dozier for some suggestions here).
 *
 * Modification in this C version: in the case b == 0., returns 1.+a.
 *
 * Called by: c_disort
 */


/*
 * Derived from fcmp(), version 1.2.2,
 * Copyright (c) 1998-2000 Theodore C. Belding
 * University of Michigan Center for the Study of Complex Systems
 * <mailto:Ted.Belding@umich.edu>
 * <http://fcmp.sourceforge.net>
 *
 * The major modification we have made is to remove the "epsilon" argument
 * and set epsilon inside the fcmp() function.
 *
 * Description:
 *   It is generally not wise to compare two floating-point values for
 *   exact equality, for example using the C == operator.  The function
 *   fcmp() implements Knuth's suggestions for safer floating-point
 *   comparison operators, from:
 *   Knuth, D. E. (1998). The Art of Computer Programming.
 *   Volume 2: Seminumerical Algorithms. 3rd ed. Addison-Wesley.
 *   Section 4.2.2, p. 233. ISBN 0-201-89684-2.
 *
 * Input parameters:
 *   x1, x2: numbers to be compared
 *
 * Returns:
 *   -1 if x1 < x2
 *    0 if x1 == x2
 *    1 if x1 > x2
 */


/*
   DISORT special case to get only albedo and transmissivity of entire medium as a function of incident beam angle
   (many simplifications because boundary condition is just isotropic illumination, there are no thermal sources, and
   particular solutions do not need to be computed).  See Ref. S2 and references therein for details.
   The basic idea is as follows.  The reciprocity principle leads to the following relationships for a plane-parallel,
   vertically inhomogeneous medium lacking thermal (or other internal) sources:

      albedo(theta) = u_0(theta) for unit-intensity isotropic
                       illumination at *top* boundary
       trans(theta) =  u_0(theta) for unit-intensity isotropic
                       illumination at *bottom* boundary
    where

       albedo(theta) = albedo for beam incidence at angle theta
       trans(theta)  = transmissivity for beam incidence at angle theta
       u_0(theta)    = upward azim-avg intensity at top boundary
                       at angle theta

   O U T P U T    V A R I A B L E S:

       ALBMED(iu)   Albedo of the medium as a function of incident
                    beam angle cosine UMU(IU)

       TRNMED(iu)   Transmissivity of the medium as a function of
                    incident beam angle cosine UMU(IU)

    I N T E R N A L   V A R I A B L E S:

       ncd         number of diagonals below/above main diagonal
       rcond       estimate of the reciprocal condition of matrix CBAND; for system  CBAND*X = B, relative
                   perturbations in CBAND and B of size epsilon may cause relative perturbations in X of size
                   epsilon/RCOND.  If RCOND is so small that
                          1.0 + RCOND .eq. 1.0
                   is true, then CBAND may be singular to working precision.
       cband       Left-hand side matrix of linear system eq. SC(5), scaled by eq. SC(12);
                   in banded form required by LINPACK solution routines
       ncol        number of columns in CBAND matrix
       ipvt        INTEGER vector of pivot indices (most others documented in DISORT)

   Called by- c_disort
   Calls- c_legendre_poly, c_sgbco, c_solve_eigen, c_interp_eigenvec, c_set_matrix, c_solve1,
          c_albtrans_intensity, c_albtrans_spherical, c_print_albtrans
 --------------------------------------------------------------------------------------*/


/*
   Computes azimuthally-averaged intensity at top and bottom of medium
   (related to albedo and transmission of medium by reciprocity principles;
   see Ref S2).  User polar angles are used as incident beam angles.
   (This is a very specializedversion of user_intensities)

   ** NOTE **  User input values of UMU (assumed positive) are temporarily in
               upper locations of  UMU  and corresponding negatives are in
               lower locations (this makes GU come out right); the contents
               of the temporary UMU array are:
                   -UMU(ds->numu),..., -UMU(1), UMU(1),..., UMU(ds->numu)

   I N P U T    V A R I A B L E S:

       ds     :  Disort state variables
       gu     :  Eigenvectors interpolated to user polar angles (i.e., g in eq. SC(1), STWL(31ab))
       kk     :  Eigenvalues of coeff. matrix in eq. SS(7), STWL(23b)
       ll     :  Constants of integration in eq. SC(1), obtained by solving scaled version of eq. SC(5);
                 exponential term of eq. SC(12) not included
       nn     :  Order of double-Gauss quadrature (NSTR/2)
       taucpr :  Cumulative optical depth (delta-M-scaled)

   O U T P U T    V A R I A B L E:

       out->u0u : Diffuse azimuthally-averaged intensity at top and bottom of medium (directly transmitted component,
                  corresponding to bndint in user_intensities, is omitted).

   I N T E R N A L    V A R I A B L E S:

       dtau   :  Optical depth of a computational layer
       palint :  Non-boundary-forced intensity component
       utaupr :  Optical depths of user output levels (delta-M scaled)
       wk     :  Scratch vector for saving 'EXP' evaluations
       All the exponential factors (i.e., exp1, expn,... etc.)
       come from the substitution of constants of integration in
       eq. SC(12) into eqs. S1(8-9).  All have negative arguments.

   Called by- c_albtrans
 -------------------------------------------------------------------*/


/*
   Print planar albedo and transmissivity of medium as a function of
   incident beam angle

   Called by- c_albtrans
 --------------------------------------------------------------------*/


/*
     Construct right-hand side vector -b- for isotropic incidence
     (only) on either top or bottom boundary and solve system
     of equations obtained from the boundary conditions and the
     continuity-of-intensity-at-layer-interface equations

     I N P U T      V A R I A B L E S:

       ds       :  Disort state variables
       cband    :  Left-hand side matrix of banded linear system
                   eq. SC(5), scaled by eq. SC(12); assumed already
                   in LU-decomposed form, ready for LINPACK solver
       ihom     :  Direction-of-illumination flag (TOP_ILLUM, top; BOT_ILLUM, bottom)
       ipvt     :
       ncol     :  Number of columns in CBAND
       ncut     :
       nn       :  Order of double-Gauss quadrature (NSTR/2)

    O U T P U T     V A R I A B L E S:

       b        :  Right-hand side vector of eq. SC(5) going into
                   sgbsl; returns as solution vector of eq.
                   SC(12), constants of integration without
                   exponential term
       ll       :  permanent storage for -b-, but re-ordered

    I N T E R N A L    V A R I A B L E S:

       ipvt     :  INTEGER vector of pivot indices
       ncd      :  Number of diagonals below or above main diagonal

   Called by- c_albtrans
   Calls- c_sgbsl
 +-------------------------------------------------------------------+
*/


/*
    Calculates spherical albedo and transmissivity for the entire medium
    from the m=0 intensity components (this is a specialized version of fluxes)

    I N P U T    V A R I A B L E S:

       ds      :  Disort state variables
       cmu,cwt :  Abscissae, weights for Gaussian quadrature over angle cosine
       kk      :  Eigenvalues of coeff. matrix in eq. SS(7)
       gc      :  Eigenvectors at polar quadrature angles, SC(1)
       ll      :  Constants of integration in eq. SC(1), obtained by solving
                  scaled version of eq. SC(5); exponential term of eq. SC(12) not incl.
       nn      :  Order of double-Gauss quadrature (NSTR/2)

    O U T P U T   V A R I A B L E S:

       sflup   :  Up-flux at top (equivalent to spherical albedo due to
                  reciprocity).  For illumination from below it gives
                  spherical transmissivity

       sfldn   :  Down-flux at bottom (for single layer, equivalent to
                  spherical transmissivity due to reciprocity)

    I N T E R N A L   V A R I A B L E S:

       zint    :  Intensity of m=0 case, in eq. SC(1)

   Called by- c_albtrans
 --------------------------------------------------------------------*/


/*
   Write name of erroneous variable and return TRUE; count and abort
   if too many errors.

   Input : quiet  = VERBOSE or QUIET
           varnam = name of erroneous variable to be written
 ----------------------------------------------------------------------*/


/*
    Write name of too-small symbolic dimension and the value it should be
    increased to;  return TRUE

    Input :  quiet  = VERBOSE or QUIET
             dimnam = name of symbolic dimension which is too small
             minval = value to which that dimension should be increased
 ----------------------------------------------------------------------*/


/*
     Factors a real band matrix by Gaussian elimination and estimates the
     condition of the matrix.
     Revision date:  8/1/82
     Author:  Moler, C.B. (Univ. of New Mexico)

     If  RCOND  is not needed, sgbfa is slightly faster.
     To solve  A*X = B , follow sbgco by sgbsl.

     Inputs:
        abd     double(LDA,N), contains the matrix in band storage.
                The columns of the matrix are stored in the columns of abd
                and the diagonals of the matrix are stored in rows
                ml+1 through 2*ml+mu+1 of  abd.
                See the comments below for details.
        lda     int, the leading dimension of the array abd.
                lda must be >= 2*ml+mu+1.
        n       int,the order of the original matrix.
        ml      int, number of diagonals below the main diagonal.
                0 <= ml < n.
        mu      int, number of diagonals above the main diagonal.
                0 <= mu < n.
                more efficient if  ml <= mu.

     Outputs:
        abd     an upper triangular matrix in band storage and
                the multipliers which were used to obtain it.
                The factorization can be written  A = L*U  where
                L  is a product of permutation and unit lower
                triangular matrices and  U  is upper triangular.
        ipvt    int[n], an integer vector of pivot indices.
        rcond   double, an estimate of the reciprocal condition of A.
                For the system  A*X = B, relative perturbations
                in A and B of size epsilon may cause relative
                perturbations in  X  of size  epsilon/rcond.
                If rcond  is so small that the logical expression
                   1.+RCOND == 1.
                is true, then  A  may be singular to working
                precision.  In particular, rcond is zero if exact
                singularity is detected or the estimate underflows.
        z       double[n], a work vector whose contents are usually
                unimportant. If A is close to a singular matrix, then
                z is an approximate null vector in the sense that
                norm(a*z) = rcond*norm(a)*norm(z).

     Band storage:
           If A is a band matrix, the following program segment
           will set up the input (with unit-offset arrays):
                   ml = (band width below the diagonal)
                   mu = (band width above the diagonal)
                   m = ml+mu+1
                   for (j = 1; j <= n; j++) {
                     i1 = IMAX(1,j-mu);
                     i2 = IMIN(n,j+ml);
                     for (i = i1; i <= i2; i++) {
                       k = i-j+m;
                       ABD(K,J) = A(I,J);
                     }
                   }
           This uses rows ml+1 through 2*ml+mu+1 of abd.
           In addition, the first ml rows in abd are used for
           elements generated during the triangularization.
           The total number of rows needed in abd is 2*ml+mu+1.
           The ml+mu by ml+mu upper left triangle and the
           ml by ml lower right triangle are not referenced.

     Example:  if the original matrix is

           11 12 13  0  0  0
           21 22 23 24  0  0
            0 32 33 34 35  0
            0  0 43 44 45 46
            0  0  0 54 55 56
            0  0  0  0 65 66

      then  n = 6, ml = 1, mu = 2, lda >= 5  and abd should contain
            *  *  *  +  +  +  , * = not used
            *  * 13 24 35 46  , + = used for pivoting
            * 12 23 34 45 56
           11 22 33 44 55 66
           21 32 43 54 65  *

 --------------------------------------------------------------------*/


/*
    Factors a real band matrix by elimination.
    Revision date:  8/1/82
    Author:  Moler, C. B. (U. of New Mexico)
    c_sgbfa is usually called by c_sbgco, but it can be called
    directly with a saving in time if rcond is not needed.

    Inputs:  same as c_sgbco
    Outputs:
        abd,ipvt    same as c_sgbco
        info    int,
                = 0  normal value.
                = k  if  u(k,k) == 0.  This is not an error
                     condition for this subroutine, but it does
                     indicate that sgbsl will divide by zero if
                     called.  Use  rcond  in c_sbgco for a reliable
                     indication of singularity.
    (see c_sgbco for description of band storage mode)

    NOTE: using memset() to zero columns in abd
 ----------------------------------------------------------------*/


/*
    Solves the real band system
       A * X = B  or  transpose(A) * X = B
    using the factors computed by sbgco or sgbfa.
    Revision date:  8/1/82
    Author:  Moler, C. B. (Univ. of New Mexico)

    Inputs:
        abd     double(lda, n), the output from sbgco or sgbfa.
        lda     int, the leading dimension of the array abd.
        n       int, the order of the original matrix.
        ml      int, number of diagonals below the main diagonal.
        mu      int, number of diagonals above the main diagonal.
        ipvt    int(n), the pivot vector from sbgco or sgbfa.
        b       double(n), the right hand side vector.
        job     int,
                = 0         to solve  A*X = B ,
                = nonzero   to solve  transpose(A)*X = B

     Outputs:
        b       the solution vector  X

     Error condition:
        A division by zero will occur if the input factor contains a
        zero on the diagonal.  Technically, this indicates singularity,
        but it is often caused by improper arguments or improper
        setting of lda.  It will not occur if the subroutines are
        called correctly and if c_sbgco has set rcond > 0.0
        or sgbfa has set info = 0 .
     To compute  inverse(a)*c  where c is a matrix
     with p columns
      c_sgbco(abd,lda,n,ml,mu,ipvt,&rcond,z)
      if (rcond is too small) ...
        for (j = 1; j <= p; j++) {
          c_sgbsl(abd,lda,n,ml,mu,ipvt,c(1,j),0)
        }
 --------------------------------------------------------*/


/*
   Factors a real matrix by Gaussian elimination
   and estimates the condition of the matrix.
   Revision date:  8/1/82
   Author:  Moler, C. B. (Univ. of New Mexico)
   If rcond is not needed, sgefa is slightly faster.
   To solve  A*X = B, follow sgeco by sgesl.

     Inputs:
        a       double(lda, n), the matrix to be factored.
        lda     int, the leading dimension of the array a.
        n       int, the order of the matrix a.

     Outputs:
        a       an upper triangular matrix and the multipliers
                which were used to obtain it.
                The factorization can be written  A = L*U , where
                L  is a product of permutation and unit lower
                triangular matrices and U is upper triangular.
        ipvt    int(n), an integer vector of pivot indices.
        rcond   double, an estimate of the reciprocal condition of a.
                For the system A*X = B, relative perturbations
                in A and B of size epsilon may cause relative
                perturbations in X of size epsilon/rcond.
                If rcond is so small that the logical expression
                  1.+rcond == 1.
                is true, then A may be singular to working precision.
                In particular, rcond is zero if exact singularity
                is detected or the estimate underflows.
        z       double(n), a work vector whose contents are usually
                unimportant. If A is close to a singular matrix, then z
                is an approximate null vector in the sense that
                norm(A*Z) = rcond*norm(A)*norm(Z) .
 ------------------------------------------------------------------*/


/*
   Factors a real matrix by Gaussian elimination.
   Revision date:  8/1/82
   Author:  Moler, C. B. (Univ. of New Mexico)
   c_sgefa is usually called by c_sgeco, but it can be called directly with a
   saving in time if rcond is not needed.
   (time for c_sgeco) = (1+9/n)*(time for c_sgefa).

   Inputs:  same as c_sgeco

   Outputs:
        a,ipvt  same as c_sgeco
        info    int,
                = 0  normal value.
                = k  if  u(k,k) = 0.  This is not an error condition for
                     this subroutine, but it does indicate that c_sgesl or
                     c_sgedi will divide by zero if called.  Use rcond in
                     c_sgeco for a reliable indication of singularity.
 ---------------------------------------------------------------------*/


/*
  Solves the real system
     A*X = B  or  transpose(A)*X = B
  using the factors computed by sgeco or sgefa.
  Revision date:  8/1/82
  Author:  Moler, C. B. (Univ. of New Mexico)

     Inputs:
        a       double(lda, n), the output from sgeco or sgefa.
        lda     int, the leading dimension of the array  A
        n       int, the order of the matrix  A
        ipvt    int(n), the pivot vector from sgeco or sgefa.
        b       double(n), the right hand side vector.
        job     int,
                = 0         to solve  A*X = B ,
                = nonzero   to solve  transpose(A)*X = B

     Outputs:
        b       the solution vector x

     Error condition:
        A division by zero will occur if the input factor contains a
        zero on the diagonal. Technically, this indicates singularity,
        but it is often caused by improper arguments or improper setting
        of lda. It will not occur if the subroutines are called correctly
        and if sgeco has set rcond > 0. or sgefa has set info = 0 .
     To compute  inverse(a)*c where c is a matrix with p columns
           c_sgeco(a,lda,n,ipvt,rcond,z);
           if (rcond is too small) ...
           for (j = 1; j <= p; j++) {
             c_sgesl(a,lda,n,ipvt,c(1,j),0);
           }
 ---------------------------------------------------------------------*/


/*
  Input--   n     Number of elements in vector to be summed
            sx    array, length n, containing vector

  OUTPUT--  ans   Sum from i = 1 to n of fabs(SX(i))

  NOTE: Fortran input incx removed because it is not used by
        disort or twostr
 ----------------------------------------------------------*/


/*
  y = a*x + y  (x, y = vectors, a = scalar)

  INPUT--
        n   Number of elements in input vectors x and y
       sa   Scalar multiplier a
       sx   Array containing vector x
       sy   Array containing vector Y

 OUTPUT--
       sy   For i = 1 to n, overwrite  SY(i) with sa*SX(i)+SY(i)

  NOTE: Fortran inputs incx, incy removed because they are not used
        by disort or twostr
 ------------------------------------------------------------*/


/*
  Dot product of vectors x and y

  INPUT--
        n  Number of elements in input vectors x and y
       sx  Array containing vector x
       sy  Array containing vector y

 OUTPUT--
      ans  Sum for i = 1 to n of  SX(i)*SY(i),

  NOTE: Fortran input arguments incx, incy removed because they
        are not used in disort or twostr
 ------------------------------------------------------------------*/


/*
  Multiply vector sx by scalar sa

  INPUT--  n  Number of elements in vector
          sa  Scale factor
          sx  Array, length n, containing vector

 OUTPUT-- sx  Replace SX(i) with sa*SX(i) for i = i to n

 NOTE: Fortran input argument incx removed since it is not used
       in disort or twostr

 ---------------------------------------------------------------------*/


/*
 INPUT--  n        Number of elements in vector of interest
          sx       Array, length n, containing vector

 OUTPUT-- ans      First i, i = 1 to n, to maximize fabs(SX(i))

 NOTE: Fortran input incx removed because it is not used by
       disort or twostr
 ---------------------------------------------------------------------*/


/*
 Calculates the Chapman factor.

 I n p u t       v a r i a b l e s:

      lc        : Computational layer
      taup      :
      tauc      :
      nlyr      : Number of layers in atmospheric model
      zd(lc)    : lc = 0, nlyr. zd(lc) is distance from bottom
                  surface to top of layer lc. zd(nlyr) = 0. km
      dtau_c    : Optical thickness of layer lc (un-delta-m-scaled)
      zenang    : Solar zenith angle as seen from bottom surface
      r         : Radial parameter, see Velinow & Kostov (2001). NOTE: Use the same dimension as zd,
                  for instance both in km.

 O u t p u t      v a r i a b l e s:

      ch        : Chapman-factor. In a pseudo-spherical atmosphere, replace exp(-tau/umu0) by exp(-ch(lc)) in the
                  beam source in

 I n t e r n a l     v a r i a b l e s:

      dhj       : delta-h-sub-j in eq. B2 (DS)
      dsj       : delta-s-sub-j in eq. B2 (DS)
      fact      : =1 for first  sum in eq. B2 (DS)
                  =2 for second sum in eq. B2 (DS)
      rj        : r-sub-j   in eq. B1 (DS)
      rjp1      : r-sub-j+1 in eq. B1 (DS)
      xpsinz    : The length of the line OG in Fig. 1, (DS)

 NOTE: Assumes a spherical planet. One might consider generalizing following
       Velinow YPI, Kostov VI, 2001, Generalization on Chapman Function for the Atmosphere of an Oblate Rotating Planet,
         Comptes Rendus de l'Academie Bulgare des Sciences 54, 29-34.
*/


/*
 * Checks the twostr input dimensions and variables
 *
 * Return value: FALSE, no scattering; SSALB = 0. everywhere in the vertical column
 *               TRUE,  scattering; SSALB > 0. somewhere in the vertical column
 */


/*
 Calculates the radiative fluxes, mean intensity, and flux derivative
 with respect to optical depth from the azimuthally-averaged intensity

 I n p u t     v a r i a b l e s:

   ds         :  'Disort' state variables
   ts         :  twostr_xyz structure variables (xp_0, yb_0d, zb_a...; see cdisort.h)
   ch         :  Chapman factor
   cmu        :  Abscissa for gauss quadrature over angle cosine
   kk         :  Eigenvalues
   layru      :  Layer numbers of user levels -utau-
   ll         :  Constants of integration in eqs. KST(42-43), obtaine by solving eqs. KST(38-41)
   lyrcut     :  Logical flag for truncation of comput. layer
   ncut       :  Number of computational layer where absorption optical depth exceeds -abscut-
   oprim      :  Delta-m scaled single scattering albedo
   rr         :  Eigenvectors at polar quadrature angles
   flag.spher :  TRUE turns on pseudo-spherical effects
   taucpr     :  Cumulative optical depth (delta-m-scaled)
   utaupr     :  Optical depths of user output levels in delta-m coordinates; equal to  -utau- if no delta-m

 O u t p u t     v a r i a b l e s:

   out      :  'Disort' output variables
   u0c      :  Azimuthally averaged intensities at polar quadrature angle cmu

 I n t e r n a l       v a r i a b l e s:

   dirint   :  direct intensity attenuated
   fdntot   :  total downward flux (direct + diffuse)
   fldir    :  fl[].zero, direct-beam flux (delta-m scaled)
   fldn     :  fl[].one, diffuse down-flux (delta-m scaled)
   fnet     :  net flux (total-down - diffuse-up)
   fact     :  EXP( - utaupr / ch ), where ch is the Chapman factor
   plsorc   :  Planck source function (thermal)
 ---------------------------------------------------------------------*/


/*
    Calculates the homogenous and particular solutions to the
    radiative transfer equation in the two-stream approximation,
    for each layer in the medium.

    I n p u t     v a r i a b l e s:

      ds         : 'Disort' state variables
      ch         : Chapman correction factor
      chtau      :
      cmu        : Abscissa for gauss quadrature over angle cosine
      ncut       : Number of computational layer where absorption optical depth exceeds -abscut-
      oprim      : Delta-m scaled single scattering albedo
      pkag,c     : Planck function in each layer
      flag.spher : spher = true => spherical geometry invoked
      taucpr     : Cumulative optical depth (delta-m-scaled)
      ggprim     :

   O u t p u t     v a r i a b l e s:

      kk         :  Eigenvalues
      rr         :  Eigenvectors at polar quadrature angles
      ts         :  twostr_xyz structure variables (see cdisort.h)
  ----------------------------------------------------------------------*/


/*
 * Print values of twostream input variables
 */


/*
 Perform miscellaneous setting-up operations

 Routines called: c_errmsg

 Input :  ds         'Disort' input variables
          scat_yes   TRUE for scattering case, FALSE for non-scattering case

 Output:  ntau,utau  If ds->flag.usrtau = FALSE
          bplanck    Intensity emitted from bottom boundary
          ch         The Chapman factor
          cmu        Computational polar angle
          expbea     Transmission of direct beam
          flyr       Truncated fraction in delta-m method
          layru      Computational layer in which utau falls
          lyrcut     Flag as to whether radiation will be zeroed below layer ncut
          ncut       Computational layer where absorption optical depth first exceeds abscut
          nn         nstr/2 = 1
          nstr       No.of streams (=2)
          oprim      Delta-m-scaled single-scatter albedo
          pkag,c     Planck function in each layer
          taucpr     Delta-m-scaled optical depth
          tplanck    Intensity emitted from top boundary
          utaupr     Delta-m-scaled version of utau

 Internal Variables
          abscut     Absorption optical depth, medium is cut off below this depth
          tempc      Temperature at center of layer, assumed to be average of
                     layer boundary temperatures
  ---------------------------------------------------------------------*/


/*
 Construct right-hand side vector -b- for general boundary conditions
 and solve system of equations obtained from the boundary conditions
 and the continuity-of-intensity-at-layer-interface equations.

 Routines called: c_sgbfa, c_sgbsl

 I n p u t      v a r i a b l e s:

       ds       : 'Disort' state variables
       ts       :  twostr_xyz structure variables (see cdisort.h)
       bplanck  :  Bottom boundary thermal emission
       cband    :  Left-hand side matrix of linear system eqs. KST(38-41)
                   in banded form required by linpack solution routines
       cmu      :  Abscissa for gauss quadrature over angle cosine
       expbea   :  Transmission of incident beam, EXP(-taucpr/ch)
       lyrcut   :  Logical flag for truncation of comput. layer
       ncol     :  Counts of columns in -cband-
       nn       :  Order of double-gauss quadrature (nstr/2)
       ncut     :  Total number of computational layers considered
       tplanck  :  Top boundary thermal emission
       taucpr   :  Cumulative optical depth (delta-m-scaled)
       kk       :
       rr       :
       ipvt     :

 O u t p u t     v a r i a b l e s:

       b        :  Right-hand side vector of eqs. KST(38-41) going into
                   sgbsl; returns as solution vector of eqs. KST(38-41)
                   constants of integration
       ll       :  Permanent storage for -b-, but re-ordered

 I n t e r n a l    v a r i a b l e s:

       diag     : diag[].super, diag[].on, diag[].sub

 ---------------------------------------------------------------------*/


/*
 * 3rd-order accurate integration of y = dz/dx on a non-staggered grid with
 * variable grid spacing (endpoints are 2nd-order accurate).
 *
 * Input:
 * table[0 to n-1].x: 	independent-variable, x
 * table[0 to n-1].y: 	derivative, y = dz/dx
 * table[0].z:		value of integral at starting position, z0
 *
 * Output:
 * table[0 to n-1].z: 	the integral of dz/dx
 *
 * This scheme is based on the one described and illustrated in Fig. 8(d) of
 *    Leslie LM,  Purser RJ, 1992, A comparative study of the performance of various
 *       vertical discretization schemes, Meteorol. Atmos. Phys. 50, 61-73.
 *
 * Adapted by T. Dowling, 2013
 */


/*
 * Dynamically allocate memory for disort input arrays, including
 * ones that the user can optionally ask disort() to calculate.
 */


/*
 *  Free memory allocated by disort_state_alloc()
 */


/*
 *   Dynamically allocate memory for disort output arrays
 */


/*
 * Free memory allocated by disort_out_alloc()
 */


/*
 * Dynamically allocate memory for twostr input arrays.
 */


/*
 *  Free memory allocated by twostr_state_alloc()
 */


/*
 *   Dynamically allocate memory for twostr output arrays
 */


/*
 * Free memory allocated by twostr_out_alloc()
 */


/*
 * Allocates memory for a 1D double-precision array with range [nl..nh].
 *
 * NOTE: calloc() zeros the memory it allocates.
 */


/*
 * Frees memory allocated by c_dbl_vector().
 *
 * NOTE: If the array is zero-offset, can just use free().
 * NOTE: Argument nh is not used, but kept to match c_dbl_vector().
 */


/*
 * Allocates memory for a 1D integer array with range [nl..nh].
 *
 * NOTE: calloc() zeros the memory it allocates.
 */


/*
 * Frees memory allocated by c_int_vector().
 *
 * NOTE: If the array is zero-offset, can just use free().
 * NOTE: Argument nh is not used, but kept to match c_dbl_vector().
 */


/*============================= c_dbl_triplet() =========================*/
/*
 * Allocates memory for a 1D dbl_triplet array with range [nl..nh].
 *
 * NOTE: calloc() zeros the memory it allocates.
 */


/*
 * Frees memory allocated by c_dbl_triplet().
 *
 * NOTE: If the array is zero-offset, can just use free().
 * NOTE: Argument nh is not used, but kept to match c_dbl_triplet().
 */


/*
 * Find place in table using bisection.
 * Adapted by Michael Sussman for the EPIC atmospheric model,
 * from Numerical Recipes in C, p. 118-119.
 * Incorporated into CDISORT by Tim Dowling, 2013.
 *
 * NOTE: Hunts place relative to the x component of the dbl_triplet table.
 *       Requires an initial guess (il) to location within table, which should be
 *       populated by the calling function as the value returned previously.
 */


/*
 *  Purpose:
 *
 *    Sign-testing routine.
 *    Called by c_spline_pchip().
 *
 *  Discussion:
 *
 *    This routine essentially computes the sign of arg1 * arg2.
 *
 *    The object is to do this without multiplying arg1 * arg2, to avoid
 *    possible over/underflow problems.
 *
 *  Modified:
 *
 *    25 August 2007
 *
 *  Author:
 *
 *    Fred Fritsch,
 *    Mathematics and Statistics Division,
 *    Lawrence Livermore National Laboratory.
 *
 *    C translation by John Burkardt.
 *
 *    Adapted to CDISORT by Tim Dowling, 2013.
 *
 *  Reference:
 *
 *    Fred Fritsch, Ralph Carlson,
 *    Monotone Piecewise Cubic Interpolation,
 *    SIAM Journal on Numerical Analysis,
 *    Volume 17, Number 2, April 1980, pages 238-246.
 *
 *  Parameters:
 *
 *    Input, double arg1, arg2, two values to check.
 *
 *    Output, double c_pchst,
 *    -1.0, if arg1 and arg2 are of opposite sign.
 *     0.0, if either argument is zero.
 *    +1.0, if arg1 and arg2 are of the same sign.
 */


/*
 *  Purpose:
 *
 *    Sets derivatives for a piecewise cubic Hermite interpolant.
 *
 *  Discussion:
 *
 *    This routine computes what would normally be called a Hermite
 *    interpolant.  However, the user is only required to supply function
 *    values, not derivative values as well.  This routine computes
 *    "suitable" derivative values, so that the resulting Hermite interpolant
 *    has desirable shape and monotonicity properties.
 *
 *    The interpolant will have an extremum at each point where
 *    monotonicity switches direction.
 *
 *    The resulting piecewise cubic Hermite function may be evaluated
 *    by c_splint_pchip().
 *
 *    This routine was originally called "PCHIM".
 *
 *    The acronym PCHIP means Piecewise Cubic Hermite Interpolating Polynomial.
 *
 *  Modified:
 *
 *    25 August 2007
 *
 *  Author:
 *
 *    Fred Fritsch,
 *    Mathematics and Statistics Division,
 *    Lawrence Livermore National Laboratory.
 *
 *    C translation by John Burkardt.
 *
 *    Adapted to CDISORT by Tim Dowling, 2013.
 *
 *  References:
 *
 *    Fred Fritsch, Ralph Carlson,
 *    Monotone Piecewise Cubic Interpolation,
 *    SIAM Journal on Numerical Analysis,
 *    Volume 17, Number 2, April 1980, pages 238-246.
 *
 *    Fred Fritsch, Judy Butland,
 *    A Method for Constructing Local Monotone Piecewise
 *    Cubic Interpolants,
 *    SIAM Journal on Scientific and Statistical Computing,
 *    Volume 5, Number 2, 1984, pages 300-304.
 *
 *  Parameters:
 *
 *    Input, int n, the number of data points; n must be at least 2.
 *
 *    Input,
 *      dbl_triplet table[n]:
 *      table[n].x are the strictly increasing independent variable values.
 *
 *      table[n].y are the dependent variable values to be interpolated.
 *      This routine is designed for monotonic data, but it will work for
 *      any data. It will force extrema at points where monotonicity switches
 *      direction.
 *
 *    Output,
 *      table[n].z are the derivative values at the data points.  If the
 *      data are monotonic, these values will determine a monotone cubic
 *      Hermite function.
 */


/*
 *  Purpose:
 *
 *    Evaluates a cubic polynomial given in Hermite form.
 *
 *  Discussion:
 *
 *    This routine evaluates a cubic polynomial given in Hermite form, and
 *    is designed to work with c_spline_pchip().
 *
 *    The cubic polynomial is determined by function values
 *    table[0].y, table[1].y and derivatives table[0].z, table[1].z
 *    on the interval [table[0].x,table[1].x].
 *
 *    This routine was originally called "CHFEV".
 *
 *  Modified:
 *
 *    25 August 2007
 *
 *  Author:
 *
 *    Fred Fritsch,
 *    Mathematics and Statistics Division,
 *    Lawrence Livermore National Laboratory.
 *
 *    C translation by John Burkardt.
 *
 *    Adapted to CDISORT by Tim Dowling, 2013.
 *
 *  References:
 *
 *    Fred Fritsch, Ralph Carlson,
 *    Monotone Piecewise Cubic Interpolation,
 *    SIAM Journal on Numerical Analysis,
 *    Volume 17, Number 2, April 1980, pages 238-246.
 *
 *    David Kahaner, Cleve Moler, Steven Nash,
 *    Numerical Methods and Software,
 *    Prentice Hall, 1989,
 *    ISBN: 0-13-627258-4,
 *    LC: TA345.K34.
 *
 *  Parameters:
 *
 *    Input, double xx, the position of the interpolation
 *
 *    Input, dbl_triplet *table:
 *       The use of the data type dbl_triplet facilitates
 *       cache-aware memory allocation.
 *
 *       NOTE: This function does not search the table,
 *             but assumes xx is between the given inputs as
 *             returned by c_hunt_place_in_table().
 *
 *       table[0].x and table[1].x are the endpoints of the interval of
 *       definition of the cubic; they must be distinct.
 *
 *       table[0].y and table[1].y are the corresponding values of the function.
 *
 *       table[0].z and table[1].z are the corresponding derivative values.
 *
 *    Input, h = dx, the x interval, as returned by c_hunt_place_in_table().
 *
 *    Returns the value of the cubic function at the point xx.
 */


/*
 * Evaluates linear interpolation using same arguments as c_splint_pchip(),
 * to make it easy to switch between the two.
 */


/*-------------------------------------------------------------------
 * Copyright (C) 1994 Arve Kylling
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * To obtain a copy of the GNU General Public License write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *-------------------------------------------------------------------
 * Linearly interpolate to get approximate tau corresponding to
 * altitude zout
 *
 * Input/output variables described in phodis.f
 *
 *
 * This code was translated to c from fortran by Robert Buras
 *
 */


/*-------------------------------------------------------------------
 * Copyright (C) 1994 Arve Kylling
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * To obtain a copy of the GNU General Public License write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *-------------------------------------------------------------------
 *
 *     Interpolates at the x-point arg from x-value array xarr and
 *     y-value array yarr. xarr and yarr are expected to have
 *     descending arguments, i.e. for atmospheric applications
 *     xarr typically holds the altitude and inter expects
 *     xarr(1) = altitude at top of atmosphere.
 *
 *     Input variables:
 *     dim       Array dimension of xarr and yarr
 *     npoints   No. points in arrays xarr and yarr
 *     itype     Interpolation type
 *     arg       Interpolation argument
 *     xarr      array of x values
 *     yarr      array of y values
 *
 *     Output variables:
 *     ynew      Interpolated function value at arg
 *     hh        gradient or scale height value
 *
 * This code was translated to c from fortran by Robert Buras
 *
 */


/*
 *  Sets up mpi bookkeeping.
 *  The mpispec structure para is defined globally in epic.h.
 */


/*
 * Adapted from an algorithm by Vishwas Garg.
 *   https://www.geeksforgeeks.org/print-all-prime-factors-of-a-given-number/
 *
 * Call initially as
 *   nf = prime_factors(num,NULL)
 * to count the number of factors, nf.
 * Allocate memory in the calling function for factors[], and call as
 *   prime_factors(num,factors)
 * to store the factors.
 *
 * NOTE: This replaces the original program factor(), which did not return
 *       correct results for many input values, including 5, 7, 10, 14, and 20.
 *
 * T. Dowling, 13 Feb 2019.
 */


/*
 * Apply hyperviscosity to layer K of a scalar field on the h-grid.
 */


/*
 *  Calculates the 2D Laplacian of an h-grid scalar field,
 *  multiplied by the input diffusion coefficient, DIFF_COEF(J,I).
 *
 *  The pointer hh should point to the appropriate JI plane.
 *
 *  Pointers to memory for two working JI-plane buffers
 *  are passed in as buff1 and buff2.
 */


/*
 *  Calculate the Laplacian of input 2D velocity vector (uu,vv)
 *  on the C-grid. See eq.(46) of Dowling et al. (1998).
 *
 *  The input viscosity coefficient is assumed to be a constant.
 *
 *  NOTE: If a spatially varying viscosity is needed, it is implemented
 *        in uv_horizontal_diffusion() in terms of the stress tensor,
 *        following Tannehill, Anderson, and Pletcher (1997), p. 269,
 *        and that approach could be implemented.
 *
 *  The input pointers uu and vv should point to the appropriate JI plane.
 *
 *  Pointers to memory for two working JI-plane buffers
 *  are passed in as buff1 and buff2.
 */


/*
 * In superadiabatic regions, N^2 < 0, relax the potential temperature towards N^2 = 0,
 * and relax any species towards the well-mixed state.
 *
 * The relaxtion rate is assumed to be proportional to 1/|N|, based on the local negative N^2,
 * but diluted as a subgrid process.
 *
 * NOTE: This algorithm is not applied to the isentropic coordinate or the isentropic part
 *       of the hybrid coordinate.
 */


/*
 * Add artificial damping of horizontal divergence to control
 * numerical instabilities associated with gravity waves.
 * See Skamarock and Klemp (1992, Mon. Wea. Rev. 120, 2109-2127).
 */


/*
 * The vertical-gradient diffusion terms for (u,v) are handled here using
 * an implicit timestep to avoid numerical instabilities arising from
 * relatively small dz values.  The horizontal-gradient terms are
 * handled in uv_horizontal_diffusion().
 *
 * The shallow-atmosphere approximation has been applied, which eliminates
 * terms involving the vertical velocity.
 *
 * NOTE: The timeplane for U and V is grid.it_uv rather than
 *       grid.it_uv_dis, because the implicit timestep does not need
 *       to be lagged.
 *
 * NOTE: Killworth (1989, On the Parameterization of Deep Convection in Ocean Models)
 *       concludes that convective-adjustment mixing is not necessary for U, V.
 */


/*
 * Wrapper for turbulence source-sink subroutine.
 * This allows flexibility in what turbulence model is used without
 * having to change the hook to the rest of the EPIC model.
 *
 * NOTE: There is a name conflict with "source_sink_subgrid" and
 *       LAM MPI, in the file lam_config_file.h.
 */


/*
 * Compute delta in (5.9) of Dowling et al (2006) for the Spalart-Allmaras
 * turbulence model.
 *
 * NOTE: We have changed the definition from the Dowling et al (2006) paper.
 */


/*
 * Calculate the shear stress at the surface.
 *
 * NOTE: Because of the call to get_kin, do not call this function
 *       from a pad position (like J=JLOPAD or I=IHIPAD).
 */


/*
 * Raymond P. LeBeau
 *
 * For the DES-type turbulence model there needs to be a boundary condition
 * placed on the value of the turbulent viscosity close to the wall.
 * Ideally, one gets close enough to the wall with the closest grid point
 * that the flow is effectively in the viscous sublayer, where the turbulent
 * viscosity is set at 0; however this requires a very small spacing.
 * Further out, one can use the law-of-the-wall correlation, which follows:
 *   u+ = (1/.41)*log(y+)+5.0, u+ = u/u_tau, y+ = y*u_tau/nu,
 * u being the tagential velocity over the surface.
 * The routine returns the value for the turbulent visocity in
 * t_vis_new on the bottom boundary.

 * Modified by Aaron Herrnstein on 03-13-06.  The extra argument "index"
 * is used to specify the h-grid, u-grid, or v-grid.
 *
 * Modified by Tim Dowling on 07-14-08. Added K argument.
 */


/*
 * Calculate nu_turb (nu_tilde) from DIFF_COEF (nu_t).
 */


/*
 * NOTE: To use the READ* macros in epic_io_macros.h, dummy
 *       io and fd variables are declared.
 */


/*
 * NOTE: To use the WRITE* macros in epic_io_macros.h, dummy
 *       io and fd variables are declared.
 */


/*
 *  Frees memory allocated by ivector().
 */


/*
 *  Frees memory allocated by fvector().
 */


/*
 *  Frees memory allocated by dvector().
 */


/*
 *  Frees memory allocated by ftriplet().
 */


/*
 * Cubic spline routine.
 * Adapted from Numerical Recipes in C, p. 115-116.
 * The tridiagonal system is solved with pivoting
 * to avoid numerical instability.
 * Assumes zero-offset arrays.
 *
 * NOTE: We stripe the data into one array with float_triplet to get
 *       a cache-aware memory layout.
 */


/*
 *  Evaluates cubic-spline interpolations.
 *  This version assumes you have already found the correct position
 *  in the tables, unlike the Numerical Recipes version.
 *  The function find_place_in_table() may be used to find the position.
 *
 *  NOTE: We stripe the data into one array with float_triplet to get
 *        a cache-aware memory layout.
 */


/*
 * Evaluates linear interpolation using same arguments as splint(),
 * to make it easy to switch between the two.
 */


/*
 *  Purpose:
 *
 *    Sets derivatives for a piecewise cubic Hermite interpolant.
 *
 *  Discussion:
 *
 *    This routine computes what would normally be called a Hermite
 *    interpolant.  However, the user is only required to supply function
 *    values, not derivative values as well.  This routine computes
 *    "suitable" derivative values, so that the resulting Hermite interpolant
 *    has desirable shape and monotonicity properties.
 *
 *    The interpolant will have an extremum at each point where
 *    monotonicity switches direction.
 *
 *    The resulting piecewise cubic Hermite function may be evaluated
 *    by splint_pchip().
 *
 *    This routine was originally called "PCHIM".
 *
 *    The acronym PCHIP means Piecewise Cubic Hermite Interpolating Polynomial.
 *
 *  Modified:
 *
 *    25 August 2007
 *
 *  Author:
 *
 *    Fred Fritsch,
 *    Mathematics and Statistics Division,
 *    Lawrence Livermore National Laboratory.
 *
 *    C translation by John Burkardt.
 *
 *    Adapted for EPIC by Tim Dowling.
 *
 *  References:
 *
 *    Fred Fritsch, Ralph Carlson,
 *    Monotone Piecewise Cubic Interpolation,
 *    SIAM Journal on Numerical Analysis,
 *    Volume 17, Number 2, April 1980, pages 238-246.
 *
 *    Fred Fritsch, Judy Butland,
 *    A Method for Constructing Local Monotone Piecewise
 *    Cubic Interpolants,
 *    SIAM Journal on Scientific and Statistical Computing,
 *    Volume 5, Number 2, 1984, pages 300-304.
 *
 *  Parameters:
 *
 *    Input, int n, the number of data points; n must be at least 2.
 *
 *    Input,
 *      float_triplet table[n]:
 *      table[n].x are the strictly increasing independent variable values.
 *
 *      table[n].y are the dependent variable values to be interpolated.
 *      This routine is designed for monotonic data, but it will work for
 *      any data. It will force extrema at points where monotonicity switches
 *      direction.
 *
 *    Output,
 *      table[n].z are the derivative values at the data points.  If the
 *      data are monotonic, these values will determine a monotone cubic
 *      Hermite function.
 */