!-------------------------------------------------------------------------
!  NASA/GFSC, SIVO, Code 610.3
!-------------------------------------------------------------------------
!BOP
!
! !MODULE:  FastJX53cCoreScattering_mod
!
! !INTERFACE:
!

      module FastJX53cCoreScattering_mod 1
!
      implicit none
!
! !PUBLIC MEMBER FUNCTIONS:
!
      private
      public  :: MIESCT
!
! !DESCRIPTION:
!  Contains core scattering routines.
!
! !AUTHOR:
!  Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
      CONTAINS
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: MIESCT
!
! !INTERFACE:
!

      subroutine MIESCT(FJ,FJT,FJB,POMEGA,FZ,ZTAU,ZFLUX,ZREFL,ZU0,MFIT,ND) 3,14
!
! !USES:
      use FastJX53cMIEparameters_mod, only : M_, N_
!
      implicit none
!
! !INPUT PARAMETERS:
      integer, intent(in)  :: MFIT
      integer, intent(in)  :: ND
      real*8 , intent(in)  :: POMEGA(2*M_,N_)
      real*8 , intent(in)  :: FZ(N_)
      real*8 , intent(in)  :: ZTAU(N_)
      real*8 , intent(in)  :: ZREFL, ZU0, ZFLUX
!
! !OUTPUT PARAMETERS:
      real*8 , intent(out) :: FJ(N_), FJT,FJB
!
! !DESCRIPTION:
! \begin{verbatim}
!-----------------------------------------------------------------------
!   This is an adaption of the Prather radiative transfer code, (mjp, 10/95)
!     Prather, 1974, Astrophys. J. 192, 787-792.
!         Sol_n of inhomogeneous Rayleigh scattering atmosphere. 
!         (original Rayleigh w/ polarization)
!     Cochran and Trafton, 1978, Ap.J., 219, 756-762.
!         Raman scattering in the atmospheres of the major planets.
!         (first use of anisotropic code)
!     Jacob, Gottlieb and Prather, 1989, J.Geophys.Res., 94, 12975-13002.
!         Chemistry of a polluted cloudy boundary layer,
!         (documentation of extension to anisotropic scattering)
!
!    takes atmospheric structure and source terms from std J-code
!    ALSO limited to 4 Gauss points, only calculates mean field!
!
!   mean rad. field ONLY (M=1)
! \end{verbatim}
!
! !LOCAL VARIABLES:
      real*8  WT(M_),EMU(M_),PM(M_,2*M_),PM0(2*M_),CMEQ1
      integer I, ID, IM, M, N
!
! !AUTHOR:
! Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
!BOC
!-----------------------------------------------------------------------
!---fix scattering to 4 Gauss pts = 8-stream
      call GAUSSP (N,EMU,WT)

!---calc in OPMIE:  ZFLUX = (ZU0*FZ(ND)*ZREFL)/(1.0d0+ZREFL)
      M = 1
      do I = 1,N
        call LEGND0 (EMU(I),PM0,MFIT)
        do IM = M,MFIT
          PM(I,IM) = PM0(IM)
        enddo
      enddo
!
      CMEQ1 = 0.25d0
      call LEGND0 (-ZU0,PM0,MFIT)
      do IM=M,MFIT
        PM0(IM) = CMEQ1*PM0(IM)
      enddo
!
      call BLKSLV(FJ,POMEGA,FZ,ZTAU,ZFLUX,ZREFL,WT,EMU,PM,PM0 &
     &           ,FJT,FJB,M,N,MFIT,ND)
!
      do ID=1,ND,2
        FJ(ID) = 4.0d0*FJ(ID) + FZ(ID)
      enddo

      return
      end subroutine MIESCT
!EOC
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: BLKSLV
!
! !INTERFACE:
!

      subroutine BLKSLV(FJ,POMEGA,FZ,ZTAU,ZFLUX,ZREFL,WT,EMU,PM,PM0 & 3,20
     &                 ,FJTOP,FJBOT, M,N,MFIT,ND)
!
! !USES:
      use FastJX53cMIEparameters_mod, only : M_, N_
!
      implicit none
!
! !INPUT PARAMETERS:
      integer, intent(in)  :: M, N, MFIT, ND
      real*8 , intent(in)  :: POMEGA(2*M_,N_)
      real*8 , intent(in)  :: FZ(N_)
      real*8 , intent(in)  :: ZTAU(N_) 
      real*8 , intent(in)  :: WT(M_)
      real*8 , intent(in)  :: EMU(M_)
      real*8 , intent(in)  :: PM(M_,2*M_)
      real*8 , intent(in)  :: PM0(2*M_)
      real*8 , intent(in)  :: ZFLUX
      real*8 , intent(in)  :: ZREFL
!
! !OUTPUT PARAMETERS:
      real*8 , intent(out) :: FJ(N_),FJTOP,FJBOT
!
! !DESCRIPTION:
!  Solves the block tri-diagonal system:
!  \begin{verbatim}
!               A(I)*X(I-1) + B(I)*X(I) + C(I)*X(I+1) = H(I)
!  \end{verbatim}
!
! !LOCAL VARIABLES:
      real*8, dimension(M_)    :: A, C1, H
      real*8, dimension(M_,M_) :: B, AA, CC
      real*8                      DD(M_,M_,N_), RR(M_,N_)
      real*8  SUMM
      integer I, J, K, ID
!
! !AUTHOR:
! Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
!BOC
!
!-----------UPPER BOUNDARY ID=1
      call GEN(POMEGA,FZ,ZTAU,ZFLUX,ZREFL,WT,EMU,PM,PM0 &
     &        ,B,CC,AA,A,H,C1,M,N,MFIT,ND,1)
      call MATIN4 (B)
      do I = 1,N
         RR(I,1) = 0.0d0
        do J = 1,N
          SUMM = 0.0d0
         do K = 1,N
          SUMM = SUMM - B(I,K)*CC(K,J)
         enddo
         DD(I,J,1) = SUMM
         RR(I,1) = RR(I,1) + B(I,J)*H(J)
        enddo
      enddo
!----------CONTINUE THROUGH ALL DEPTH POINTS ID=2 TO ID=ND-1
      do ID = 2,ND-1
        call GEN(POMEGA,FZ,ZTAU,ZFLUX,ZREFL,WT,EMU,PM,PM0 &
     &          ,B,CC,AA,A,H,C1,M,N,MFIT,ND,ID)
        do I = 1,N
          do J = 1,N
          B(I,J) = B(I,J) + A(I)*DD(I,J,ID-1)
          enddo
          H(I) = H(I) - A(I)*RR(I,ID-1)
        enddo
        call MATIN4 (B)
        do I = 1,N
          RR(I,ID) = 0.0d0
          do J = 1,N
          RR(I,ID) = RR(I,ID) + B(I,J)*H(J)
          DD(I,J,ID) = - B(I,J)*C1(J)
          enddo
        enddo
      enddo
!---------FINAL DEPTH POINT: ND
      call GEN(POMEGA,FZ,ZTAU,ZFLUX,ZREFL,WT,EMU,PM,PM0 &
     &        ,B,CC,AA,A,H,C1,M,N,MFIT,ND,ND)
      do I = 1,N
        do J = 1,N
          SUMM = 0.0d0
          do K = 1,N
          SUMM = SUMM + AA(I,K)*DD(K,J,ND-1)
          enddo
        B(I,J) = B(I,J) + SUMM
        H(I) = H(I) - AA(I,J)*RR(J,ND-1)
        enddo
      enddo
      call MATIN4 (B)
      do I = 1,N
        RR(I,ND) = 0.0d0
        do J = 1,N
        RR(I,ND) = RR(I,ND) + B(I,J)*H(J)
        enddo
      enddo
!-----------BACK SOLUTION
      do ID = ND-1,1,-1
       do I = 1,N
        do J = 1,N
         RR(I,ID) = RR(I,ID) + DD(I,J,ID)*RR(J,ID+1)
        enddo
       enddo
      enddo
!----------MEAN J & H
      do ID = 1,ND,2
        FJ(ID) = 0.0d0
       do I = 1,N
        FJ(ID) = FJ(ID) + RR(I,ID)*WT(I)
       enddo
      enddo
      do ID = 2,ND,2
        FJ(ID) = 0.0d0
       do I = 1,N
        FJ(ID) = FJ(ID) + RR(I,ID)*WT(I)*EMU(I)
       enddo
      enddo

        FJTOP = 0.0d0
        FJBOT = 0.0d0
       do I = 1,N
        FJTOP = FJTOP + RR(I,1)*WT(I)*EMU(I)
!       FJBOT = FJBOT + RR(I,1)*WT(I)*EMU(I) !this is not correct, includes up+down
       enddo
        FJTOP = 4.d0*FJTOP

      return
      end subroutine BLKSLV
!EOC
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: GEN
!
! !INTERFACE:
!

      subroutine GEN(POMEGA,FZ,ZTAU,ZFLUX,ZREFL,WT,EMU,PM,PM0 & 9,2
     &              ,B,CC,AA,A,H,C1,M,N,MFIT,ND,ID)
!
! !USES:
      use FastJX53cMIEparameters_mod, only : M_, N_
!
      implicit none
!
! !INPUT PARAMETERS:
      integer, intent(in)  :: M
      integer, intent(in)  :: N
      integer, intent(in)  :: MFIT
      integer, intent(in)  :: ND
      integer, intent(in)  :: ID
      real*8 , intent(in)  :: POMEGA(2*M_,N_)
      real*8 , intent(in)  :: FZ(N_)
      real*8 , intent(in)  :: ZTAU(N_)
      real*8 , intent(in)  :: WT(M_)
      real*8 , intent(in)  :: EMU(M_)
      real*8 , intent(in)  :: PM(M_,2*M_)
      real*8 , intent(in)  :: PM0(2*M_)
      real*8 , intent(in)  :: ZFLUX
      real*8 , intent(in)  :: ZREFL
!
! !OUTPUT PARAMETERS:
      real*8 , intent(out) :: B (M_,M_)
      real*8 , intent(out) :: AA(M_,M_)
      real*8 , intent(out) :: CC(M_,M_)
      real*8 , intent(out) :: A (M_)
      real*8 , intent(out) :: C1(M_)
      real*8 , intent(out) :: H (M_)
!
! !DESCRIPTION:
!  Generates coefficient matrices for the block tri-diagonal system:
! \begin{verbatim}
!               A(I)*X(I-1) + B(I)*X(I) + C(I)*X(I+1) = H(I)
! \end{verbatim}
!
! !LOCAL VARIABLES:
      integer ID0, ID1, IM, I, J, K, MSTART
      real*8  SUM0, SUM1, SUM2, SUM3
      real*8  DELTAU, D1, D2, SURFAC
!
      real*8  S(M_,M_), W(M_,M_), U1(M_,M_), V1(M_)
!
! !AUTHOR:
! Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
!BOC
      if (ID.eq.1 .or. ID.eq.ND) then
!---------calculate generic 2nd-order terms for boundaries
       ID0 = ID
       ID1 = ID+1
       if (ID .ge. ND) ID1 = ID-1

       do I = 1,N
          SUM0 = 0.0d0
          SUM1 = 0.0d0
          SUM2 = 0.0d0
          SUM3 = 0.0d0
        do IM = M,MFIT,2
          SUM0 = SUM0 + POMEGA(IM,ID0)*PM(I,IM)*PM0(IM)
          SUM2 = SUM2 + POMEGA(IM,ID1)*PM(I,IM)*PM0(IM)
        enddo
        do IM = M+1,MFIT,2
          SUM1 = SUM1 + POMEGA(IM,ID0)*PM(I,IM)*PM0(IM)
          SUM3 = SUM3 + POMEGA(IM,ID1)*PM(I,IM)*PM0(IM)
        enddo
         H(I) = 0.5d0*(SUM0*FZ(ID0) + SUM2*FZ(ID1))
         A(I) = 0.5d0*(SUM1*FZ(ID0) + SUM3*FZ(ID1))
        do J = 1,I
          SUM0 = 0.0d0
          SUM1 = 0.0d0
          SUM2 = 0.0d0
          SUM3 = 0.0d0
         do IM = M,MFIT,2
          SUM0 = SUM0 + POMEGA(IM,ID0)*PM(I,IM)*PM(J,IM)
          SUM2 = SUM2 + POMEGA(IM,ID1)*PM(I,IM)*PM(J,IM)
         enddo
         do IM = M+1,MFIT,2
          SUM1 = SUM1 + POMEGA(IM,ID0)*PM(I,IM)*PM(J,IM)
          SUM3 = SUM3 + POMEGA(IM,ID1)*PM(I,IM)*PM(J,IM)
         enddo
         S(I,J) = - SUM2*WT(J)
         S(J,I) = - SUM2*WT(I)
         W(I,J) = - SUM1*WT(J)
         W(J,I) = - SUM1*WT(I)
         U1(I,J) = - SUM3*WT(J)
         U1(J,I) = - SUM3*WT(I)
          SUM0 = 0.5d0*(SUM0 + SUM2)
         B(I,J) = - SUM0*WT(J)
         B(J,I) = - SUM0*WT(I)
        enddo
         S(I,I) = S(I,I) + 1.0d0
         W(I,I) = W(I,I) + 1.0d0
         U1(I,I) = U1(I,I) + 1.0d0
         B(I,I) = B(I,I) + 1.0d0
       enddo

       do I = 1,N
         SUM0 = 0.0d0
        do J = 1,N
         SUM0 = SUM0 + S(I,J)*A(J)/EMU(J)
        enddo
        C1(I) = SUM0
       enddo
       do I = 1,N
        do J = 1,N
          SUM0 = 0.0d0
          SUM2 = 0.0d0
         do K = 1,N
          SUM0 = SUM0 + S(J,K)*W(K,I)/EMU(K)
          SUM2 = SUM2 + S(J,K)*U1(K,I)/EMU(K)
         enddo
         A(J) = SUM0
         V1(J) = SUM2
        enddo
        do J = 1,N
         W(J,I) = A(J)
         U1(J,I) = V1(J)
        enddo
       enddo
       if (ID .eq. 1) then
!-------------upper boundary, 2nd-order, C-matrix is full (CC)
        DELTAU = ZTAU(2) - ZTAU(1)
        D2 = 0.25d0*DELTAU
        do I = 1,N
          D1 = EMU(I)/DELTAU
          do J = 1,N
           B(I,J) = B(I,J) + D2*W(I,J)
           CC(I,J) = D2*U1(I,J)
          enddo
          B(I,I) = B(I,I) + D1
          CC(I,I) = CC(I,I) - D1
!         H(I) = H(I) + 2.0d0*D2*C1(I) + D1*SISOTP
          H(I) = H(I) + 2.0d0*D2*C1(I)
          A(I) = 0.0d0
        enddo
       else
!-------------lower boundary, 2nd-order, A-matrix is full (AA)
        DELTAU = ZTAU(ND) - ZTAU(ND-1)
        D2 = 0.25d0*DELTAU
        SURFAC = 4.0d0*ZREFL/(1.0d0 + ZREFL)
        do I = 1,N
          D1 = EMU(I)/DELTAU
          H(I) = H(I) - 2.0d0*D2*C1(I)
           SUM0 = 0.0d0
          do J = 1,N
           SUM0 = SUM0 + W(I,J)
          enddo
           SUM0 = D1 + D2*SUM0
           SUM1 = SURFAC*SUM0
          do J = 1,N
           B(I,J) = B(I,J) + D2*W(I,J) - SUM1*EMU(J)*WT(J)
          enddo
          B(I,I) = B(I,I) + D1
          H(I) = H(I) + SUM0*ZFLUX
          do J = 1,N
           AA(I,J) = - D2*U1(I,J)
          enddo
           AA(I,I) = AA(I,I) + D1
           C1(I) = 0.0d0
        enddo
       endif
!------------intermediate points:  can be even or odd, A & C diagonal
      else
        DELTAU = ZTAU(ID+1) - ZTAU(ID-1)
        MSTART = M + MOD(ID+1,2)
        do I = 1,N
          A(I) = EMU(I)/DELTAU
          C1(I) = -A(I)
           SUM0 = 0.0d0
          do IM = MSTART,MFIT,2
           SUM0 = SUM0 + POMEGA(IM,ID)*PM(I,IM)*PM0(IM)
          enddo
          H(I) = SUM0*FZ(ID)
          do J=1,I
            SUM0 = 0.0d0
           do IM = MSTART,MFIT,2
            SUM0 = SUM0 + POMEGA(IM,ID)*PM(I,IM)*PM(J,IM)
           enddo
            B(I,J) =  - SUM0*WT(J)
            B(J,I) =  - SUM0*WT(I)
          enddo
          B(I,I) = B(I,I) + 1.0d0
        enddo
      endif
      return
      end subroutine GEN
!EOC
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: LEGND0
!
! !INTERFACE:
!

      subroutine LEGND0 (X,PL,N) 6
!
      implicit none
!
! !IMPUT PARAMETERS:
      integer, intent(in)  :: N
      real*8 , intent(in)  :: X
!
! !OUTPUT PARAMETERS:
      real*8 , intent(out) :: PL(N)

! !DESCRIPTION:
!  Calculates ORDINARY Legendre fns of X (real). 
!  \begin{verbatim}
!   from P[0] = PL(1) = 1,  P[1] = X, .... P[N-1] = PL(N)
!  \end{verbatim}
!
! !LOCAL VARIABLES:
      integer I
      real*8  DEN
!
! !AUTHOR:
! Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
!BOC
!---Always does PL(2) = P[1]
        PL(1) = 1.d0
        PL(2) = X
        do I = 3,N
         DEN = (I-1)
         PL(I) = PL(I-1)*X*(2.d0-1.0/DEN) - PL(I-2)*(1.d0-1.d0/DEN)
        enddo
      return
      end subroutine LEGND0
!EOC
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: MATIN4
!
! !INTERFACE:
!

      subroutine MATIN4 (A) 9
!
      implicit none
!
! !INPUT/OUTPUT PARAMETERS:
     real*8, intent(INout)  ::  A(4,4)
!
! !DESCRIPTION:
!  Invert $4 \times 4$ matrix A(4,4) in place with L-U decomposition (mjp, old...)
!
! !AUTHOR:
! Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
!BOC
!---SETUP L AND U
      A(2,1) = A(2,1)/A(1,1)
      A(2,2) = A(2,2)-A(2,1)*A(1,2)
      A(2,3) = A(2,3)-A(2,1)*A(1,3)
      A(2,4) = A(2,4)-A(2,1)*A(1,4)
      A(3,1) = A(3,1)/A(1,1)
      A(3,2) = (A(3,2)-A(3,1)*A(1,2))/A(2,2)
      A(3,3) = A(3,3)-A(3,1)*A(1,3)-A(3,2)*A(2,3)
      A(3,4) = A(3,4)-A(3,1)*A(1,4)-A(3,2)*A(2,4)
      A(4,1) = A(4,1)/A(1,1)
      A(4,2) = (A(4,2)-A(4,1)*A(1,2))/A(2,2)
      A(4,3) = (A(4,3)-A(4,1)*A(1,3)-A(4,2)*A(2,3))/A(3,3)
      A(4,4) = A(4,4)-A(4,1)*A(1,4)-A(4,2)*A(2,4)-A(4,3)*A(3,4)
!---INVERT L
      A(4,3) = -A(4,3)
      A(4,2) = -A(4,2)-A(4,3)*A(3,2)
      A(4,1) = -A(4,1)-A(4,2)*A(2,1)-A(4,3)*A(3,1)
      A(3,2) = -A(3,2)
      A(3,1) = -A(3,1)-A(3,2)*A(2,1)
      A(2,1) = -A(2,1)
!---INVERT U
      A(4,4) = 1.d0/A(4,4)
      A(3,4) = -A(3,4)*A(4,4)/A(3,3)
      A(3,3) = 1.d0/A(3,3)
      A(2,4) = -(A(2,3)*A(3,4)+A(2,4)*A(4,4))/A(2,2)
      A(2,3) = -A(2,3)*A(3,3)/A(2,2)
      A(2,2) = 1.d0/A(2,2)
      A(1,4) = -(A(1,2)*A(2,4)+A(1,3)*A(3,4)+A(1,4)*A(4,4))/A(1,1)
      A(1,3) = -(A(1,2)*A(2,3)+A(1,3)*A(3,3))/A(1,1)
      A(1,2) = -A(1,2)*A(2,2)/A(1,1)
      A(1,1) = 1.d0/A(1,1)
!---MULTIPLY (U-INVERSE)*(L-INVERSE)
      A(1,1) = A(1,1)+A(1,2)*A(2,1)+A(1,3)*A(3,1)+A(1,4)*A(4,1)
      A(1,2) = A(1,2)+A(1,3)*A(3,2)+A(1,4)*A(4,2)
      A(1,3) = A(1,3)+A(1,4)*A(4,3)
      A(2,1) = A(2,2)*A(2,1)+A(2,3)*A(3,1)+A(2,4)*A(4,1)
      A(2,2) = A(2,2)+A(2,3)*A(3,2)+A(2,4)*A(4,2)
      A(2,3) = A(2,3)+A(2,4)*A(4,3)
      A(3,1) = A(3,3)*A(3,1)+A(3,4)*A(4,1)
      A(3,2) = A(3,3)*A(3,2)+A(3,4)*A(4,2)
      A(3,3) = A(3,3)+A(3,4)*A(4,3)
      A(4,1) = A(4,4)*A(4,1)
      A(4,2) = A(4,4)*A(4,2)
      A(4,3) = A(4,4)*A(4,3)
      return
      end subroutine MATIN4
!EOC
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: GAUSSP
!
! !INTERFACE:
!

      subroutine GAUSSP (N,XPT,XWT) 3
!
      implicit none
!
! !OUTPUT PARAMETERS:
      integer, intent(out) :: N
      real*8 , intent(out) :: XPT(*)
      real*8 , intent(out) :: XWT(*)
!
! !DESCRIPTION:
!  Loads in pre-set Gauss points for 4 angles from 0 to +1 in cos(theta)=mu
!
! !LOCAL VARIABLES:
      real*8   GPT4(4),GWT4(4)
      integer  I
      data GPT4/.06943184420297d0,.33000947820757d0,.66999052179243d0, &
     &          .93056815579703d0/
      data GWT4/.17392742256873d0,.32607257743127d0,.32607257743127d0, &
     &          .17392742256873d0/
!
! !AUTHOR:
! Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
!BOC
      N = 4
      do I = 1,N
        XPT(I) = GPT4(I)
        XWT(I) = GWT4(I)
      enddo
      return
      end subroutine GAUSSP
!EOC
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: EFOLD
!
! !INTERFACE:
!

      subroutine EFOLD (F0, F1, N, F)
!
      implicit none
!
! !INPUT PARAMETERS:
      integer, intent(in)  :: N
      real*8 , intent(in)  :: F0
      real*8 , intent(in)  :: F1
!
! !OUTPUT PARAMETERS:
      real*8 , intent(out) :: F(101)     !F(N+1)  
!
! !DESCRIPTION:
! \begin{verbatim}
!     ***not used in fast-J, part of original scattering code
!---Speciality subroutine for calculating consistent exp(-tau/mu0)
!---  values on the tau grid so that photons are conserved.
!---  ***only works for plane-parallel, NOT psuedo-spherical atmos
!
!---  calculate the e-fold between two boundaries, given the value
!---     at both boundaries F0(x=0) = top, F1(x=1) = bottom.
!---  presume that F(x) proportional to exp[-A*x] for x=0 to x=1
!---          d2F/dx2 = A*A*F  and thus expect F1 = F0 * exp[-A]
!---           alternatively, could define A = ln[F0/F1]
!---  let X = A*x, d2F/dX2 = F
!---  assume equal spacing (not necessary, but makes this easier)
!---      with N-1 intermediate points (and N layers of thickness dX = A/N)
!---
!---  2nd-order finite difference:  (F(i-1) - 2F(i) + F(i+1)) / dX*dX = F(i)
!---      let D = 1 / dX*dX:
!
!  1  |   1        0        0        0        0        0   |    | F0 |
!     |                                                    |    | 0  |
!  2  |  -D      2D+1      -D        0        0        0   |    | 0  |
!     |                                                    |    | 0  |
!  3  |   0       -D      2D+1      -D        0        0   |    | 0  |
!     |                                                    |    | 0  |
!     |   0        0       -D      2D+1      -D        0   |    | 0  |
!     |                                                    |    | 0  |
!  N  |   0        0        0       -D      2D+1      -D   |    | 0  |
!     |                                                    |    | 0  |
! N+1 |   0        0        0        0        0        1   |    | F1 |
!      
!-----------------------------------------------------------------------
!  Advantage of scheme over simple attenuation factor: conserves total
!  number of photons - very useful when using scheme for heating rates.
!  Disadvantage: although reproduces e-folds very well for small flux
!  differences, starts to drift off when many orders of magnitude are
!  involved.
!-----------------------------------------------------------------------
! \end{verbatim}
!
! !LOCAL VARIABLES:
      integer I
      real*8 A,DX,D,DSQ,DDP1, B(101),R(101)
!
! !AUTHOR:
! Michael Prather
!
! !REVISION HISTORY:
!  Initial code.
!
!EOP
!-------------------------------------------------------------------------
!BOC
!
      if (F0 .eq. 0.d0) then
        do I = 1,N
          F(I)=0.d0
        enddo
        return
      elseif (F1.eq.0.d0) then
        A = log(F0/1.d-250)
      else
        A = log(F0/F1)
      endif
      DX = float(N)/A
      D = DX*DX
      DSQ = D*D
      DDP1 = D+D+1.d0
      B(2) = DDP1
      R(2) = +D*F0
      do I = 3,N
        B(I) = DDP1 - DSQ/B(I-1)
        R(I) = +D*R(I-1)/B(I-1)
      enddo
      F(N+1) = F1
      do I = N,2,-1
        F(I) = (R(I) + D*F(I+1))/B(I)
      enddo
      F(1) = F0
      return
      end subroutine EFOLD
!EOC
!-------------------------------------------------------------------------

      end module FastJX53cCoreScattering_mod