! $Id$
module o3_chem_m

  IMPLICIT none

  private o3_prod

contains

  subroutine o3_chem(julien, gmtime, t_seri, zmasse, pdtphys, rlat, rlon, q)

    ! This procedure evolves the ozone mass fraction through a time
    ! step taking only chemistry into account.

    ! All the 2-dimensional arrays are on the partial "physics" grid.
    ! Their shape is "(/klon, nbp_lev/)".
    ! Index "(i, :)" is for longitude "rlon(i)", latitude "rlat(i)".

    use assert_m, only: assert
    use dimphy, only: klon
    use regr_pr_comb_coefoz_m, only: c_Mob, a4_mass, a2, r_het_interm
    use mod_grid_phy_lmdz, only: nbp_lev
    use nrtype, only: pi

    integer, intent(in):: julien ! jour julien, 1 <= julien <= 360
    real, intent(in):: gmtime ! heure de la journee en fraction de jour
    real, intent(in):: t_seri(:, :) ! (klon, nbp_lev) temperature, in K

    real, intent(in):: zmasse(:, :) ! (klon, nbp_lev)
    ! (column-density of mass of air in a cell, in kg m-2)
    ! "zmasse(:, k)" is for layer "k".)

    real, intent(in):: pdtphys ! time step for physics, in s

    REAL, intent(in):: rlat(:), rlon(:)
    ! (longitude and latitude of each horizontal position, in degrees)

    real, intent(inout):: q(:, :) ! (klon, nbp_lev) mass fraction of ozone
    ! "q(:, k)" is at middle of layer "k".)

    ! Variables local to the procedure:
    ! (for "pi")
    integer k

    real c(klon, nbp_lev)
    ! (constant term during a time step in the net mass production
    ! rate of ozone by chemistry, per unit mass of air, in s-1)
    ! "c(:, k)" is at middle of layer "k".)

    real b(klon, nbp_lev)
    ! (coefficient of "q" in the net mass production
    ! rate of ozone by chemistry, per unit mass of air, in s-1)
    ! "b(:, k)" is at middle of layer "k".)

    real dq_o3_chem(klon, nbp_lev)
    ! (variation of ozone mass fraction due to chemistry during a time step)
    ! "dq_o3_chem(:, k)" is at middle of layer "k".)

    real earth_long
    ! (longitude vraie de la Terre dans son orbite solaire, par
    ! rapport au point vernal (21 mars), en degres)

    real pmu0(klon) ! mean of cosine of solar zenith angle during "pdtphys"
    real trash1
    real trash2(klon)

    !-------------------------------------------------------------

    call assert(klon == (/size(q, 1), size(t_seri, 1), size(zmasse, 1), &
         size(rlat), size(rlon)/), "o3_chem klon")
    call assert(nbp_lev == (/size(q, 2), size(t_seri, 2), size(zmasse, 2)/), &
         "o3_chem nbp_lev")

    c = c_Mob + a4_mass * t_seri

    ! Compute coefficient "b":

    ! Heterogeneous chemistry is only at low temperature:
    where (t_seri < 195.)
       b = r_het_interm
    elsewhere
       b = 0.
    end where

    ! Heterogeneous chemistry is only during daytime:
    call orbite(real(julien), earth_long, trash1)
    call zenang(earth_long, gmtime, 0., pdtphys, rlat, rlon, pmu0, trash2)
    forall (k = 1: nbp_lev)
       where (pmu0 <= cos(87. / 180. * pi)) b(:, k) = 0.
    end forall

    b = b + a2

    ! Midpoint method:

    ! Trial step to the midpoint:
    dq_o3_chem = o3_prod(q, zmasse, c, b) * pdtphys  / 2
    ! "Real" step across the whole interval:
    dq_o3_chem = o3_prod(q + dq_o3_chem, zmasse, c, b) * pdtphys
    q = q + dq_o3_chem

    ! Confine the mass fraction:
    q = min(max(q, 0.), .01)

  end subroutine o3_chem

  !*************************************************

  function o3_prod(q, zmasse, c, b)

    ! This function computes the production rate of ozone by chemistry.

    ! All the 2-dimensional arrays are on the partial "physics" grid.
    ! Their shape is "(/klon, nbp_lev/)".
    ! Index "(i, :)" is for longitude "rlon(i)", latitude "rlat(i)".

    use regr_pr_comb_coefoz_m, only: a6_mass
    use assert_m, only: assert
    use dimphy, only: klon
    use mod_grid_phy_lmdz, only: nbp_lev

    real, intent(in):: q(:, :) ! mass fraction of ozone
    ! "q(:, k)" is at middle of layer "k".)

    real, intent(in):: zmasse(:, :)
    ! (column-density of mass of air in a layer, in kg m-2)
    ! ("zmasse(:, k)" is for layer "k".)

    real, intent(in):: c(:, :)
    ! (constant term during a time step in the net mass production
    ! rate of ozone by chemistry, per unit mass of air, in s-1)
    ! "c(:, k)" is at middle of layer "k".)

    real, intent(in):: b(:, :)
    ! (coefficient of "q" in the net mass production rate of ozone by
    ! chemistry, per unit mass of air, in s-1)
    ! ("b(:, k)" is at middle of layer "k".)

    real o3_prod(klon, nbp_lev)
    ! (net mass production rate of ozone by chemistry, per unit mass
    ! of air, in s-1)
    ! ("o3_prod(:, k)" is at middle of layer "k".)

    ! Variables local to the procedure:

    real sigma_mass(klon, nbp_lev)
    ! (mass column-density of ozone above point, in kg m-2)
    ! ("sigma_mass(:, k)" is at middle of layer "k".)

    integer k

    !-------------------------------------------------------------------

    call assert(klon == (/size(q, 1), size(zmasse, 1), size(c, 1), &
         size(b, 1)/), "o3_prod 1")
    call assert(nbp_lev == (/size(q, 2), size(zmasse, 2), size(c, 2), &
         size(b, 2)/), "o3_prod 2")

    ! Compute the column-density above the base of layer
    ! "k", and, as a first approximation, take it as column-density
    ! above the middle of layer "k":
    sigma_mass(:, nbp_lev) = zmasse(:, nbp_lev) * q(:, nbp_lev) ! top layer
    do k =  nbp_lev - 1, 1, -1
       sigma_mass(:, k) = sigma_mass(:, k+1) + zmasse(:, k) * q(:, k)
    end do

    o3_prod = c + b * q + a6_mass * sigma_mass

  end function o3_prod

end module o3_chem_m
