!
      module n4s_module
      use params_module,only: nlevp1,nlonp4,nlat
      implicit none
!
! Boundary conditions, production and loss for N4S are defined
! by comp_n4s, and referenced by minor_n4s. Comp_n4s is called
! from a latitude loop in dynamics. After comp_n4s, dynamics calls
! minor_n4s, which passes this module data to sub minor. Sub 
! minor contains 3d mpi calls and its own latitude loops.
!
!     real,dimension(nlonp4,nlat)   :: n4s_ubc ! upper boundary
!     real,dimension(nlonp4,3,nlat) :: n4s_lbc ! lower boundary
!     real,dimension(nlevp1,nlonp4,nlat) ::
!    |  n4s_prod,     ! production of n4s
!    |  n4s_loss      ! loss of n4s
!
! Boundary conditions and production and loss terms are allocated
! subdomains by sub alloc_n4s (called from allocdata.F).
!
      real,allocatable,dimension(:,:)   :: n4s_ubc ! upper boundary (i,j)
      real,allocatable,dimension(:,:,:) :: n4s_lbc ! lower boundary (i,3,j)
      real,allocatable,dimension(:,:,:) ::
     |  n4s_prod,     ! production of n4s (k,i,j)
     |  n4s_loss      ! loss of n4s       (k,i,j)
      real :: phi_n4s(3) = (/0.651, 0.731, 0.741/)
      real,parameter :: alfa_n4s = 0. ! thermal diffusion coefficient
!
      contains
!-----------------------------------------------------------------------
      subroutine alloc_n4s(lon0,lon1,lat0,lat1)
!
! Allocate subdomains (without ghost cells) to module data for boundary 
! conditions and production and loss terms. This is called once per run 
! from sub allocdata (allocdata.F).
!
! Args:
      integer,intent(in) :: lon0,lon1,lat0,lat1
!
! Local:
      integer :: istat
!
! Allocate subdomains to boundary conditions:
      allocate(n4s_ubc(lon0:lon1,lat0:lat1),stat=istat)
      if (istat /= 0) write(6,"('>>> alloc_n4s: error allocating',
     |  ' n4s_ubc: stat=',i3)") istat
      allocate(n4s_lbc(lon0:lon1,3,lat0:lat1),stat=istat)
      if (istat /= 0) write(6,"('>>> alloc_n4s: error allocating',
     |  ' n4s_lbc: stat=',i3)") istat
!
! Allocate subdomains to production and loss:
      allocate(n4s_prod(nlevp1,lon0:lon1,lat0:lat1),stat=istat)
      if (istat /= 0) write(6,"('>>> alloc_n4s: error allocating',
     |  ' n4s_prod: stat=',i3)") istat
      allocate(n4s_loss(nlevp1,lon0:lon1,lat0:lat1),stat=istat)
      if (istat /= 0) write(6,"('>>> alloc_n4s: error allocating',
     |  ' n4s_prod: stat=',i3)") istat

!     write(6,"('alloc_n4s: allocated module data')")
!
      end subroutine alloc_n4s
!-----------------------------------------------------------------------
      subroutine comp_n4s(tn,o2,o1,barm,xnmbarm,no,n2d,ne,o2p,op,n2p,
     |  nplus,nop,lev0,lev1,lon0,lon1,lat)
!
! Advance n4s by one time step. This is called from dynamics at
! each subdomain latitude.
!
      use qrj_module,only: qtef
      use cons_module,only: brn2d,p0,expz,expzmid_inv,boltz,
     |  rmass_n4s,rmassinv_n2d,rmassinv_o2,rmassinv_o1,
     |  rmassinv_n2,rmassinv_no
      use chemrates_module,only: beta1,beta3,beta4,beta5,beta7,
     |  beta8,beta17,ra1,ra3,rk2,rk4,rk6,rk8
!
! Input args:
      integer,intent(in) :: lev0,lev1,lon0,lon1,lat
      real,dimension(lev0:lev1,lon0-2:lon1+2),intent(in) ::
     |  tn,      ! neutral temperature (deg K)
     |  o2,      ! molecular oxygen (mmr)
     |  o1,      ! atomic oxygen (mmr)
     |  barm,    ! mean molecular weight
     |  xnmbarm, ! p0*e(-z)*barm/kT
     |  no,      ! nitric oxide (mmr)
     |  n2d,     ! N2D (mmr) (from sub comp_n2d)
     |  ne,      ! N2D (mmr)
     |  o2p,     ! O2+ ion
     |  op,      ! O+ ion
     |  n2p,     ! N2+ ion
     |  nplus,   ! N+ ion
     |  nop      ! NO+ ion
!
! Local:
      integer :: k,i
      integer ::i0,i1,nk,nkm1 ! for addfsech
      real :: xnmbar_lbc
      real,dimension(lev0:lev1,lon0:lon1) :: xn2, ! n2 (mmr)
     |        n4seq
!
!     write(6,"('enter comp_n4s: lat=',i2)") lat
      i0 = lon0
      i1 = lon1
      nk = lev1-lev0+1
      nkm1 = nk-1
!
! Lower boundary:
! n4s_lbc(:,1)=A, n4s_lbc(:,2)=B, n4s_lbc(:,3)=C define lower boundary 
!   condition where A*DPSX/DZ + B*PSX + C = 0.
! Note tn(lev1,i) assumes tn bottom boundary is stored in top slot.
!
      do i=lon0,lon1
        xnmbar_lbc = p0*expz(1)*expzmid_inv*barm(lev0,i)/
     |    (boltz*tn(lev1,i))
!
! Value at bottom given by photochemical equilibrium.
        n4s_lbc(i,1,lat) = 0.
        n4s_lbc(i,2,lat) = 1.
        n4s_lbc(i,3,lat) = -rmass_n4s/xnmbar_lbc*
     |   (qtef(lev0,i,lat)*(1.-brn2d)/xnmbar_lbc+
     |    n2d(lev0,i)*rmassinv_n2d*
     |    (beta4*xnmbar_lbc*o1(lev0,i)*rmassinv_o1+
     |     beta5(lev0,i,lat)*ne(lev0,i)+beta7)+
     |    beta8(lev0,i,lat)*no(lev0,i)*rmassinv_no)/
!
     |   (beta1(lev0,i,lat)*o2(lev0,i)*rmassinv_o2+
     |    beta3(lev0,i,lat)*no(lev0,i)*rmassinv_no+
     |    xnmbar_lbc*beta17(lev0,i,lat)*
     |    o1(lev0,i)*rmassinv_o1*
     |    (1.-o2(lev0,i)-o1(lev0,i))*rmassinv_n2)
!
! Zero diffusive flux at top:
        n4s_ubc(i,lat) = 0.
      enddo ! i=lon0,lon1
!
! Sources:
      do i=lon0,lon1
        do k=lev0,lev1-1
          xn2(k,i) = 1.-o2(k,i)-o1(k,i)
!
          n4s_prod(k,i,lat) = (.5*(qtef(k,i,lat)+qtef(k+1,i,lat))*
     |      (1.-brn2d))+xnmbarm(k,i)*(n2d(k,i)*rmassinv_n2d*
     |      (xnmbarm(k,i)*beta4*o1(k,i)*rmassinv_o1+
     |      beta5(k,i,lat)*.5*(ne(k,i)+ne(k+1,i))+beta7)+
     |      .5*(beta8(k,i,lat)+beta8(k+1,i,lat))*no(k,i)*rmassinv_no)+
     |      xnmbarm(k,i)*(rk2(k,i,lat)*op(k,i)*xn2(k,i)*rmassinv_n2+
     |      rk6*nplus(k,i)*o2(k,i)*rmassinv_o2+
     |      rk8*nplus(k,i)*o1(k,i)*rmassinv_o1)+
     |      sqrt(ne(k,i)*ne(k+1,i))*(ra1(k,i,lat)*nop(k,i)*0.15+
     |      ra3(k,i,lat)*n2p(k,i)*1.1)
!
          n4s_loss(k,i,lat) = -xnmbarm(k,i)*(beta1(k,i,lat)*o2(k,i)*
     |      rmassinv_o2+beta3(k,i,lat)*no(k,i)*rmassinv_no+
     |      xnmbarm(k,i)*beta17(k,i,lat)*o1(k,i)*rmassinv_o1*
     |      xn2(k,i)*rmassinv_n2)-rk4*o2p(k,i)

! Update n4s in assumed photochemical equilibrium
!
!
	  n4seq(k,i)=rmass_n4s*n4s_prod(k,i,lat)/
     |                (n4s_loss(k,i,lat)*xnmbarm(k,i))
!
	enddo ! k=lev0,lev1-1
      enddo ! i=lon0,lon1

!     call addfsech('XNMBAR'  ,' ',' ',xnmbarm(:,i0:i1),
!    |  i0,i1,nk,nkm1,lat)
      call addfsech('N4S_PROD',' ',' ',n4s_prod(:,i0:i1,lat),
     |  i0,i1,nk,nkm1,lat)
      call addfsech('N4S_LOSS',' ',' ',n4s_loss(:,i0:i1,lat),
     |  i0,i1,nk,nkm1,lat)
      call addfsech('N4S_EQ',' ',' ',n4seq(:,i0:i1),
     |  i0,i1,nk,nkm1,lat)
!
!
      end subroutine comp_n4s
!-----------------------------------------------------------------------
      subroutine minor_n4s(tn,o2,o1,n4s,n4s_nm1,n4s_out,n4s_nm1_out,
     |  lev0,lev1,lon0,lon1,lat0,lat1)
      use cons_module,only: rmass_n4s
!
! Input args:
      integer,intent(in) :: lev0,lev1,lon0,lon1,lat0,lat1
      real,dimension(lev0:lev1,lon0-2:lon1+2,lat0-2:lat1+2),
     |  intent(in) ::
     |  tn,      ! neutral temperature (deg K)
     |  o2,      ! molecular oxygen (mmr)
     |  o1,      ! atomic oxygen (mmr)
     |  n4s,     ! N4S (mmr)
     |  n4s_nm1  ! N4S at time n-1 
!
! Output args:
      real,dimension(lev0:lev1,lon0-2:lon1+2,lat0-2:lat1+2),
     |  intent(out) ::
     |  n4s_out,    ! N4S output 
     |  n4s_nm1_out ! N4S output at time n-1
!
! Local:
      integer :: lat
      integer ::i0,i1,nk,nkm1 ! for addfsech
!
!     write(6,"('enter minor_n4s')")
      i0 = lon0
      i1 = lon1
      nk = lev1-lev0+1
      nkm1 = nk-1
!
! Minor returns n4s_out and n4s_nm1_out. Module data n4s_prod,
! n4s_loss, etc, were defined by comp_n4s.  
!
!     subroutine minor(tn,o2,o1,fcomp,fcomp_tm1,fcomp_out,fcomp_tm1_out,
!    |  sloss,sprod,flbc,fubc,rmx,phix,alfax,lev0,lev1,lon0,lon1,lat0,
!    |  lat1,idebug)
!
      call minor(tn,o2,o1,n4s,n4s_nm1,n4s_out,n4s_nm1_out,
     |  n4s_loss,n4s_prod,n4s_lbc,n4s_ubc,rmass_n4s,phi_n4s,
     |  alfa_n4s,lev0,lev1,lon0,lon1,lat0,lat1,0)

!     do lat=lat0,lat1
!       call addfsech('N4S_OUT' ,' ',' ',n4s_out(:,i0:i1,lat),
!    |    i0,i1,nk,nkm1,lat)
!       call addfsech('N4S_TM1' ,' ',' ',n4s_nm1_out(:,i0:i1,lat),
!    |    i0,i1,nk,nkm1,lat)
!     enddo ! lat=lat0,lat1
 
      end subroutine minor_n4s
!
      end module n4s_module
