!
! $Header$
!
SUBROUTINE advn(q,masse,w,pbaru,pbarv,pdt,mode)
  !
  ! Auteur : F. Hourdin
  !
  !    ********************************************************************
  ! Shema  d'advection " pseudo amont " .
  !    ********************************************************************
  ! q,pbaru,pbarv,w sont des arguments d'entree  pour le s-pg ....
  !
  !   pbaru,pbarv,w flux de masse en u ,v ,w
  !   pdt pas de temps
  !
  !   --------------------------------------------------------------------
  USE iniprint_mod_h
  USE comgeom_mod_h
  USE dimensions_mod, ONLY: iim, jjm, llm, ndm
USE paramet_mod_h
IMPLICIT NONE
  !



  !
  !   Arguments:
  !   ----------
  integer :: mode
  real :: masse(ip1jmp1,llm)
  REAL :: pbaru( ip1jmp1,llm ),pbarv( ip1jm,llm)
  REAL :: q(ip1jmp1,llm)
  REAL :: w(ip1jmp1,llm),pdt
  !
  !  Local
  !   ---------
  !
  INTEGER :: i,ij,l,j,ii
  integer :: ijlqmin,iqmin,jqmin,lqmin
  integer :: ismin
  !
  real :: zm(ip1jmp1,llm),newmasse
  real :: mu(ip1jmp1,llm)
  real :: mv(ip1jm,llm)
  real :: mw(ip1jmp1,llm+1)
  real :: zq(ip1jmp1,llm),zz,qpn,qps
  real :: zqg(ip1jmp1,llm),zqd(ip1jmp1,llm)
  real :: zqs(ip1jmp1,llm),zqn(ip1jmp1,llm)
  real :: zqh(ip1jmp1,llm),zqb(ip1jmp1,llm)
  real :: temps0,temps1,temps2,temps3
  real :: ztemps1,ztemps2,ztemps3,ssum
  logical :: testcpu
  save testcpu
  save temps1,temps2,temps3
  real :: zzpbar,zzw

#ifdef CRAY
  real :: second
#endif

  real :: qmin,qmax
  data qmin,qmax/0.,1./
  data testcpu/.false./
  data temps1,temps2,temps3/0.,0.,0./

  zzpbar = 0.5 * pdt
  zzw    = pdt

  DO l=1,llm
    DO ij = iip2,ip1jm
        mu(ij,l)=pbaru(ij,l) * zzpbar
     ENDDO
     DO ij=1,ip1jm
        mv(ij,l)=pbarv(ij,l) * zzpbar
     ENDDO
     DO ij=1,ip1jmp1
        mw(ij,l)=w(ij,l) * zzw
     ENDDO
  ENDDO

  DO ij=1,ip1jmp1
     mw(ij,llm+1)=0.
  ENDDO

  do l=1,llm
     qpn=0.
     qps=0.
     do ij=1,iim
        qpn=qpn+q(ij,l)*masse(ij,l)
        qps=qps+q(ip1jm+ij,l)*masse(ip1jm+ij,l)
     enddo
     qpn=qpn/ssum(iim,masse(1,l),1)
     qps=qps/ssum(iim,masse(ip1jm+1,l),1)
     do ij=1,iip1
        q(ij,l)=qpn
        q(ip1jm+ij,l)=qps
     enddo
  enddo

  do ij=1,ip1jmp1
     mw(ij,llm+1)=0.
  enddo
  do l=1,llm
     do ij=1,ip1jmp1
        zq(ij,l)=q(ij,l)
        zm(ij,l)=masse(ij,l)
     enddo
  enddo

  ! call minmaxq(zq,qmin,qmax,'avant vlx     ')
  call advnqx(zq,zqg,zqd)
  call advnx(zq,zqg,zqd,zm,mu,mode)
  call advnqy(zq,zqs,zqn)
  call advny(zq,zqs,zqn,zm,mv)
  call advnqz(zq,zqh,zqb)
  call advnz(zq,zqh,zqb,zm,mw)
  ! call vlz(zq,0.,zm,mw)
  call advnqy(zq,zqs,zqn)
  call advny(zq,zqs,zqn,zm,mv)
  call advnqx(zq,zqg,zqd)
  call advnx(zq,zqg,zqd,zm,mu,mode)
  ! call minmaxq(zq,qmin,qmax,'apres vlx     ')

#ifdef CRAY
  if(testcpu) then
     ztemps1=second(0.)
     temps1=temps1+ztemps1-ztemps2
        print*,'VLSPLT X:',temps1,'   Y:',temps2,'   Z:',temps3
  endif
#endif
  do l=1,llm
     do ij=1,ip1jmp1
       q(ij,l)=zq(ij,l)
     enddo
     do ij=1,ip1jm+1,iip1
        q(ij+iim,l)=q(ij,l)
     enddo
  enddo

  RETURN
END SUBROUTINE advn

SUBROUTINE advnqx(q,qg,qd)
  !
  ! Auteurs:   Calcul des valeurs de q aux point u.
  !
  !   --------------------------------------------------------------------
  USE iniprint_mod_h
  USE dimensions_mod, ONLY: iim, jjm, llm, ndm
  USE paramet_mod_h
IMPLICIT NONE
  !
  !
  !
  !   Arguments:
  !   ----------
  real :: q(ip1jmp1,llm),qg(ip1jmp1,llm),qd(ip1jmp1,llm)
  !
  !  Local
  !   ---------
  !
  INTEGER :: ij,l
  !
  real :: dxqu(ip1jmp1),zqu(ip1jmp1)
  real :: zqmax(ip1jmp1),zqmin(ip1jmp1)
  logical :: extremum(ip1jmp1)

  integer :: mode
  save mode
  data mode/1/

  !   calcul des pentes en u:
  !   -----------------------
  if (mode.eq.0) then
     do l=1,llm
        do ij=1,ip1jm
           qd(ij,l)=q(ij,l)
           qg(ij,l)=q(ij,l)
        enddo
     enddo
  else
  do l = 1, llm
     do ij=iip2,ip1jm-1
        dxqu(ij)=q(ij+1,l)-q(ij,l)
        zqu(ij)=0.5*(q(ij+1,l)+q(ij,l))
     enddo
     do ij=iip1+iip1,ip1jm,iip1
        dxqu(ij)=dxqu(ij-iim)
        zqu(ij)=zqu(ij-iim)
     enddo
     do ij=iip2,ip1jm-1
        zqu(ij)=zqu(ij)-dxqu(ij+1)/12.
     enddo
     do ij=iip1+iip1,ip1jm,iip1
        zqu(ij)=zqu(ij-iim)
     enddo
     do ij=iip2+1,ip1jm
        zqu(ij)=zqu(ij)+dxqu(ij-1)/12.
     enddo
     do ij=iip1+iip1,ip1jm,iip1
        zqu(ij-iim)=zqu(ij)
     enddo

  !   calcul des valeurs max et min acceptees aux interfaces

     do ij=iip2,ip1jm-1
        zqmax(ij)=max(q(ij+1,l),q(ij,l))
        zqmin(ij)=min(q(ij+1,l),q(ij,l))
     enddo
     do ij=iip1+iip1,ip1jm,iip1
        zqmax(ij)=zqmax(ij-iim)
        zqmin(ij)=zqmin(ij-iim)
     enddo
     do ij=iip2+1,ip1jm
        extremum(ij)=dxqu(ij)*dxqu(ij-1).le.0.
     enddo
     do ij=iip1+iip1,ip1jm,iip1
        extremum(ij-iim)=extremum(ij)
     enddo
     do ij=iip2,ip1jm
        zqu(ij)=min(max(zqmin(ij),zqu(ij)),zqmax(ij))
     enddo
     do ij=iip2+1,ip1jm
        if(extremum(ij)) then
           qg(ij,l)=q(ij,l)
           qd(ij,l)=q(ij,l)
        else
           qd(ij,l)=zqu(ij)
           qg(ij,l)=zqu(ij-1)
        endif
     enddo
     do ij=iip1+iip1,ip1jm,iip1
        qd(ij-iim,l)=qd(ij,l)
        qg(ij-iim,l)=qg(ij,l)
     enddo

     goto 8888

     do ij=iip2+1,ip1jm
        if(extremum(ij).and..not.extremum(ij-1)) &
              qd(ij-1,l)=q(ij,l)
     enddo

     do ij=iip1+iip1,ip1jm,iip1
        qd(ij-iim,l)=qd(ij,l)
     enddo
     do ij=iip2,ip1jm-1
        if (extremum(ij).and..not.extremum(ij+1)) &
              qg(ij+1,l)=q(ij,l)
     enddo

     do ij=iip1+iip1,ip1jm,iip1
        qg(ij,l)=qg(ij-iim,l)
     enddo
8888   continue
  enddo
  endif
  RETURN
END SUBROUTINE advnqx
SUBROUTINE advnqy(q,qs,qn)
  !
  ! Auteurs:   Calcul des valeurs de q aux point v.
  !
  !   --------------------------------------------------------------------
  USE dimensions_mod, ONLY: iim, jjm, llm, ndm
  USE paramet_mod_h
  USE iniprint_mod_h
IMPLICIT NONE

  !
  !
  !   Arguments:
  !   ----------
  real :: q(ip1jmp1,llm),qs(ip1jmp1,llm),qn(ip1jmp1,llm)
  !
  !  Local
  !   ---------
  !
  INTEGER :: ij,l
  !
  real :: dyqv(ip1jm),zqv(ip1jm,llm)
  real :: zqmax(ip1jm),zqmin(ip1jm)
  logical :: extremum(ip1jmp1)

  integer :: mode
  save mode
  data mode/1/

  if (mode.eq.0) then
     do l=1,llm
        do ij=1,ip1jmp1
           qn(ij,l)=q(ij,l)
           qs(ij,l)=q(ij,l)
        enddo
     enddo
  else

  !   calcul des pentes en u:
  !   -----------------------
  do l = 1, llm
     do ij=1,ip1jm
        dyqv(ij)=q(ij,l)-q(ij+iip1,l)
     enddo

     do ij=iip2,ip1jm-iip1
        zqv(ij,l)=0.5*(q(ij+iip1,l)+q(ij,l))
        zqv(ij,l)=zqv(ij,l)+(dyqv(ij+iip1)-dyqv(ij-iip1))/12.
     enddo

     do ij=iip2,ip1jm
        extremum(ij)=dyqv(ij)*dyqv(ij-iip1).le.0.
     enddo

  ! Pas de pentes aux poles
     do ij=1,iip1
        zqv(ij,l)=q(ij,l)
        zqv(ip1jm-iip1+ij,l)=q(ip1jm+ij,l)
        extremum(ij)=.true.
        extremum(ip1jmp1-iip1+ij)=.true.
     enddo

  !   calcul des valeurs max et min acceptees aux interfaces
     do ij=1,ip1jm
        zqmax(ij)=max(q(ij+iip1,l),q(ij,l))
        zqmin(ij)=min(q(ij+iip1,l),q(ij,l))
     enddo

     do ij=1,ip1jm
        zqv(ij,l)=min(max(zqmin(ij),zqv(ij,l)),zqmax(ij))
     enddo

     do ij=iip2,ip1jm
        if(extremum(ij)) then
           qs(ij,l)=q(ij,l)
           qn(ij,l)=q(ij,l)
           ! if (.not.extremum(ij-iip1)) qs(ij-iip1,l)=q(ij,l)
           ! if (.not.extremum(ij+iip1)) qn(ij+iip1,l)=q(ij,l)
        else
           qs(ij,l)=zqv(ij,l)
           qn(ij,l)=zqv(ij-iip1,l)
        endif
     enddo

     do ij=1,iip1
        qs(ij,l)=q(ij,l)
        qn(ij,l)=q(ij,l)
        qs(ip1jm+ij,l)=q(ip1jm+ij,l)
        qn(ip1jm+ij,l)=q(ip1jm+ij,l)
     enddo

  enddo
  endif
  RETURN
END SUBROUTINE advnqy

SUBROUTINE advnqz(q,qh,qb)
  !
  ! Auteurs:   Calcul des valeurs de q aux point v.
  !
  !   --------------------------------------------------------------------
  USE dimensions_mod, ONLY: iim, jjm, llm, ndm
  USE paramet_mod_h
  USE iniprint_mod_h
IMPLICIT NONE
  !
  !
  !   Arguments:
  !   ----------
  real :: q(ip1jmp1,llm),qh(ip1jmp1,llm),qb(ip1jmp1,llm)
  !
  !  Local
  !   ---------
  !
  INTEGER :: ij,l
  !
  real :: dzqw(ip1jmp1,llm+1),zqw(ip1jmp1,llm+1)
  real :: zqmax(ip1jmp1,llm),zqmin(ip1jmp1,llm)
  logical :: extremum(ip1jmp1,llm)

  integer :: mode
  save mode

  data mode/1/

  !   calcul des pentes en u:
  !   -----------------------

  if (mode.eq.0) then
     do l=1,llm
        do ij=1,ip1jmp1
           qb(ij,l)=q(ij,l)
           qh(ij,l)=q(ij,l)
        enddo
     enddo
  else
  do l = 2, llm
     do ij=1,ip1jmp1
        dzqw(ij,l)=q(ij,l-1)-q(ij,l)
        zqw(ij,l)=0.5*(q(ij,l-1)+q(ij,l))
     enddo
  enddo
  do ij=1,ip1jmp1
     dzqw(ij,1)=0.
     dzqw(ij,llm+1)=0.
  enddo
  do l=2,llm
     do ij=1,ip1jmp1
        zqw(ij,l)=zqw(ij,l)+(dzqw(ij,l+1)-dzqw(ij,l-1))/12.
     enddo
  enddo
  do l=2,llm-1
     do ij=1,ip1jmp1
        extremum(ij,l)=dzqw(ij,l)*dzqw(ij,l+1).le.0.
     enddo
  enddo

  ! Pas de pentes en bas et en haut
     do ij=1,ip1jmp1
        zqw(ij,2)=q(ij,1)
        zqw(ij,llm)=q(ij,llm)
        extremum(ij,1)=.true.
        extremum(ij,llm)=.true.
     enddo

  !   calcul des valeurs max et min acceptees aux interfaces
  do l=2,llm
     do ij=1,ip1jmp1
        zqmax(ij,l)=max(q(ij,l-1),q(ij,l))
        zqmin(ij,l)=min(q(ij,l-1),q(ij,l))
     enddo
  enddo

  do l=2,llm
     do ij=1,ip1jmp1
        zqw(ij,l)=min(max(zqmin(ij,l),zqw(ij,l)),zqmax(ij,l))
     enddo
  enddo

  do l=2,llm-1
     do ij=1,ip1jmp1
        if(extremum(ij,l)) then
           qh(ij,l)=q(ij,l)
           qb(ij,l)=q(ij,l)
        else
           qh(ij,l)=zqw(ij,l+1)
           qb(ij,l)=zqw(ij,l)
        endif
     enddo
  enddo
  ! do l=2,llm-1
  !    do ij=1,ip1jmp1
  !       if(extremum(ij,l)) then
  !          if (.not.extremum(ij,l-1)) qh(ij,l-1)=q(ij,l)
  !          if (.not.extremum(ij,l+1)) qb(ij,l+1)=q(ij,l)
  !       endif
  !    enddo
  ! enddo

  do ij=1,ip1jmp1
     qb(ij,1)=q(ij,1)
     qh(ij,1)=q(ij,1)
     qb(ij,llm)=q(ij,llm)
     qh(ij,llm)=q(ij,llm)
  enddo

  endif

  RETURN
END SUBROUTINE advnqz

SUBROUTINE advnx(q,qg,qd,masse,u_m,mode)
  !
  ! Auteur : F. Hourdin
  !
  !    ********************************************************************
  ! Shema  d'advection " pseudo amont " .
  !    ********************************************************************
  ! nq,iq,q,pbaru,pbarv,w sont des arguments d'entree  pour le s-pg ....
  !
  !
  !   --------------------------------------------------------------------
  USE dimensions_mod, ONLY: iim, jjm, llm, ndm
  USE paramet_mod_h
  USE iniprint_mod_h
IMPLICIT NONE
  !


  !
  !
  !   Arguments:
  !   ----------
  integer :: mode
  real :: masse(ip1jmp1,llm)
  real :: u_m( ip1jmp1,llm )
  real :: q(ip1jmp1,llm),qd(ip1jmp1,llm),qg(ip1jmp1,llm)
  !
  !  Local
  !   ---------
  !
  INTEGER :: i,j,ij,l,indu(ip1jmp1),niju,iju,ijq
  integer :: n0,nl(llm)
  !
  real :: new_m,zu_m,zdq,zz
  real :: zsigg(ip1jmp1,llm),zsigd(ip1jmp1,llm),zsig
  real :: u_mq(ip1jmp1,llm)

  real :: zm,zq,zsigm,zsigp,zqm,zqp,zu

  logical :: ladvplus(ip1jmp1,llm)

  real :: prec
  save prec

#ifdef CRAY
  data prec/1.e-24/
#else
  data prec/1.e-15/
#endif

  do l=1,llm
        do ij=iip2,ip1jm
           zdq=qd(ij,l)-qg(ij,l)
           ! if((qd(ij,l)-q(ij,l))*(q(ij,l)-qg(ij,l)).lt.0.) then
           !    print*,'probleme au point ij=',ij,'  l=',l
           !    print*,qd(ij,l),q(ij,l),qg(ij,l)
           !    qd(ij,l)=q(ij,l)
           !    qg(ij,l)=q(ij,l)
           ! endif
           if(abs(zdq).gt.prec) then
              zsigd(ij,l)=(q(ij,l)-qg(ij,l))/zdq
              zsigg(ij,l)=1.-zsigd(ij,l)
              ! if(.not.(zsigd(ij,l).ge.0..and.zsigd(ij,l).le.1. .and.
  !    s               zsigg(ij,l).ge.0..or.zsigg(ij,l).le.1.) ) then
              !    print*,'probleme au point ij=',ij,'  l=',l
              !    print*,'sigg=',zsigg(ij,l),'  sigd=',zsigd(ij,l)
              !    print*,'q d,c,g ',qd(ij,l),q(ij,l),qg(ij,l),zdq
              !    stop
              ! endif
           else
              zsigd(ij,l)=0.5
              zsigg(ij,l)=0.5
              qd(ij,l)=q(ij,l)
              qg(ij,l)=q(ij,l)
           endif
        enddo
   enddo

  !   calcul de la pente maximum dans la maille en valeur absolue

   do l=1,llm
   do ij=iip2,ip1jm-1
      if (u_m(ij,l).ge.0.) then
         zsigp=zsigd(ij,l)
         zsigm=zsigg(ij,l)
         zqp=qd(ij,l)
         zqm=qg(ij,l)
         zm=masse(ij,l)
         zq=q(ij,l)
      else
         zsigm=zsigd(ij+1,l)
         zsigp=zsigg(ij+1,l)
         zqm=qd(ij+1,l)
         zqp=qg(ij+1,l)
         zm=masse(ij+1,l)
         zq=q(ij+1,l)
      endif
      zu=abs(u_m(ij,l))
      ladvplus(ij,l)=zu.gt.zm
      zsig=zu/zm
      if(zsig.eq.0.) zsigp=0.1
      if (mode.eq.1) then
         if (zsig.le.zsigp) then
             u_mq(ij,l)=u_m(ij,l)*zqp
         else if (mode.eq.1) then
             u_mq(ij,l)= &
                   sign(zm,u_m(ij,l))*(zsigp*zqp+(zsig-zsigp)*zqm)
         endif
      else
         if (zsig.le.zsigp) then
             u_mq(ij,l)=u_m(ij,l)*(zqp-0.5*zsig/zsigp*(zqp-zq))
         else
            zz=0.5*(zsig-zsigp)/zsigm
            u_mq(ij,l)=sign(zm,u_m(ij,l))*( 0.5*(zq+zqp)*zsigp &
                  +(zsig-zsigp)*(zq+zz*(zqm-zq)) )
         endif
      endif
      ! if(zsig.lt.0.) then
      !    print*,'au point ij=',ij,'  l=',l,'  sig=',zsig
      !    stop
      ! endif
  enddo
  enddo

  do l=1,llm
   do ij=iip1+iip1,ip1jm,iip1
      u_mq(ij,l)=u_mq(ij-iim,l)
      ladvplus(ij,l)=ladvplus(ij-iim,l)
   enddo
  enddo

  !=================================================================
  !   SCHEMA SEMI-LAGRAGIEN EN X DANS LES REGIONS POLAIRES
  !=================================================================
  !   tris des regions a traiter
  n0=0
  do l=1,llm
     nl(l)=0
     do ij=iip2,ip1jm
        if(ladvplus(ij,l)) then
           nl(l)=nl(l)+1
           u_mq(ij,l)=0.
        endif
     enddo
     n0=n0+nl(l)
  enddo

  if(n0.gt.1) then
  IF (prt_level > 9) WRITE(lunout,*) &
        'Nombre de points pour lesquels on advect plus que le' &
        ,'contenu de la maille : ',n0

     do l=1,llm
        if(nl(l).gt.0) then
           iju=0
  !   indicage des mailles concernees par le traitement special
           do ij=iip2,ip1jm
              if(ladvplus(ij,l).and.mod(ij,iip1).ne.0) then
                 iju=iju+1
                 indu(iju)=ij
              endif
           enddo
           niju=iju
           ! print*,'niju,nl',niju,nl(l)

  !  traitement des mailles
           do iju=1,niju
              ij=indu(iju)
              j=(ij-1)/iip1+1
              zu_m=u_m(ij,l)
              u_mq(ij,l)=0.
              if(zu_m.gt.0.) then
                 ijq=ij
                 i=ijq-(j-1)*iip1
  !   accumulation pour les mailles completements advectees
                 do while(zu_m.gt.masse(ijq,l))
                    u_mq(ij,l)=u_mq(ij,l)+q(ijq,l)*masse(ijq,l)
                    zu_m=zu_m-masse(ijq,l)
                    i=mod(i-2+iim,iim)+1
                    ijq=(j-1)*iip1+i
                 enddo
  !   MODIFS SPECIFIQUES DU SCHEMA
  !   ajout de la maille non completement advectee
         zsig=zu_m/masse(ijq,l)
         if(zsig.le.zsigd(ijq,l)) then
            u_mq(ij,l)=u_mq(ij,l)+zu_m*(qd(ijq,l) &
                  -0.5*zsig/zsigd(ijq,l)*(qd(ijq,l)-q(ijq,l)))
         else
            ! u_mq(ij,l)=u_mq(ij,l)+zu_m*q(ijq,l)
      ! goto 8888
            zz=0.5*(zsig-zsigd(ijq,l))/zsigg(ijq,l)
            if(.not.(zz.gt.0..and.zz.le.0.5)) then
                 WRITE(lunout,*)'probleme2 au point ij=',ij, &
                       '  l=',l
                 WRITE(lunout,*)'zz=',zz
                 stop
            endif
            u_mq(ij,l)=u_mq(ij,l)+masse(ijq,l)*( &
                  0.5*(q(ijq,l)+qd(ijq,l))*zsigd(ijq,l) &
                  +(zsig-zsigd(ijq,l))*(q(ijq,l)+zz*(qg(ijq,l)-q(ijq,l))) )
         endif
              else
                 ijq=ij+1
                 i=ijq-(j-1)*iip1
  !   accumulation pour les mailles completements advectees
                 do while(-zu_m.gt.masse(ijq,l))
                    u_mq(ij,l)=u_mq(ij,l)-q(ijq,l)*masse(ijq,l)
                    zu_m=zu_m+masse(ijq,l)
                    i=mod(i,iim)+1
                    ijq=(j-1)*iip1+i
                 enddo
  !   ajout de la maille non completement advectee
  ! 2eme MODIF SPECIFIQUE
         zsig=-zu_m/masse(ij+1,l)
         if(zsig.le.zsigg(ijq,l)) then
            u_mq(ij,l)=u_mq(ij,l)+zu_m*(qg(ijq,l) &
                  -0.5*zsig/zsigg(ijq,l)*(qg(ijq,l)-q(ijq,l)))
         else
            ! u_mq(ij,l)=u_mq(ij,l)+zu_m*q(ijq,l)
        ! goto 9999
            zz=0.5*(zsig-zsigg(ijq,l))/zsigd(ijq,l)
            if(.not.(zz.gt.0..and.zz.le.0.5)) then
                 WRITE(lunout,*)'probleme22 au point ij=',ij &
                       ,'  l=',l
                 WRITE(lunout,*)'zz=',zz
                 stop
            endif
            u_mq(ij,l)=u_mq(ij,l)-masse(ijq,l)*( &
                  0.5*(q(ijq,l)+qg(ijq,l))*zsigg(ijq,l) &
                  +(zsig-zsigg(ijq,l))* &
                  (q(ijq,l)+zz*(qd(ijq,l)-q(ijq,l))) )
         endif
  !   fin de la modif
              endif
           enddo
        endif
     enddo
  endif  ! n0.gt.0

  !   bouclage en latitude
  do l=1,llm
    do ij=iip1+iip1,ip1jm,iip1
       u_mq(ij,l)=u_mq(ij-iim,l)
    enddo
  enddo

  !=================================================================
  !   CALCUL DE LA CONVERGENCE DES FLUX
  !=================================================================

  do l=1,llm
     do ij=iip2+1,ip1jm
        new_m=masse(ij,l)+u_m(ij-1,l)-u_m(ij,l)
        q(ij,l)=(q(ij,l)*masse(ij,l)+ &
              u_mq(ij-1,l)-u_mq(ij,l)) &
              /new_m
        masse(ij,l)=new_m
     enddo
  !   Modif Fred 22 03 96 correction d'un bug (les scopy ci-dessous)
     do ij=iip1+iip1,ip1jm,iip1
        q(ij-iim,l)=q(ij,l)
        masse(ij-iim,l)=masse(ij,l)
     enddo
  enddo

  RETURN
END SUBROUTINE advnx
SUBROUTINE advny(q,qs,qn,masse,v_m)
  !
  ! Auteur : F. Hourdin
  !
  !    ********************************************************************
  ! Shema  d'advection " pseudo amont " .
  !    ********************************************************************
  ! nq,iq,q,pbaru,pbarv,w sont des arguments d'entree  pour le s-pg ....
  !
  !
  !   --------------------------------------------------------------------
  USE iniprint_mod_h
  USE comgeom_mod_h
  USE dimensions_mod, ONLY: iim, jjm, llm, ndm
USE paramet_mod_h
IMPLICIT NONE
  !


  !
  !
  !   Arguments:
  !   ----------
  real :: masse(ip1jmp1,llm)
  real :: v_m( ip1jm,llm )
  real :: q(ip1jmp1,llm),qn(ip1jmp1,llm),qs(ip1jmp1,llm)
  !
  !  Local
  !   ---------
  !
  INTEGER :: ij,l
  !
  real :: new_m,zdq,zz
  real :: zsigs(ip1jmp1),zsign(ip1jmp1),zsig
  real :: v_mq(ip1jm,llm)
  real :: convpn,convps,convmpn,convmps,massen,masses
  real :: zm,zq,zsigm,zsigp,zqm,zqp
  real :: ssum
  real :: prec
  save prec

#ifdef CRAY
  data prec/1.e-24/
#else
  data prec/1.e-15/
#endif
  do l=1,llm
        do ij=1,ip1jmp1
           zdq=qn(ij,l)-qs(ij,l)
           ! if((qn(ij,l)-q(ij,l))*(q(ij,l)-qs(ij,l)).lt.0.) then
           !    print*,'probleme au point ij=',ij,'  l=',l,'  advnqx'
           !    print*,qn(ij,l),q(ij,l),qs(ij,l)
           !    qn(ij,l)=q(ij,l)
           !    qs(ij,l)=q(ij,l)
           ! endif
           if(abs(zdq).gt.prec) then
              zsign(ij)=(q(ij,l)-qs(ij,l))/zdq
              zsigs(ij)=1.-zsign(ij)
              ! if(.not.(zsign(ij).ge.0..and.zsign(ij).le.1. .and.
  !    s               zsigs(ij).ge.0..or.zsigs(ij).le.1.) ) then
              !    print*,'probleme au point ij=',ij,'  l=',l
              !    print*,'sigs=',zsigs(ij),'  sign=',zsign(ij)
              !    stop
              ! endif
           else
              zsign(ij)=0.5
              zsigs(ij)=0.5
           endif
        enddo

  !   calcul de la pente maximum dans la maille en valeur absolue

   do ij=1,ip1jm
      if (v_m(ij,l).ge.0.) then
         zsigp=zsign(ij+iip1)
         zsigm=zsigs(ij+iip1)
         zqp=qn(ij+iip1,l)
         zqm=qs(ij+iip1,l)
         zm=masse(ij+iip1,l)
         zq=q(ij+iip1,l)
      else
         zsigm=zsign(ij)
         zsigp=zsigs(ij)
         zqm=qn(ij,l)
         zqp=qs(ij,l)
         zm=masse(ij,l)
         zq=q(ij,l)
      endif
      zsig=abs(v_m(ij,l))/zm
      if(zsig.eq.0.) zsigp=0.1
      if (zsig.le.zsigp) then
          v_mq(ij,l)=v_m(ij,l)*(zqp-0.5*zsig/zsigp*(zqp-zq))
      else
          zz=0.5*(zsig-zsigp)/zsigm
          v_mq(ij,l)=sign(zm,v_m(ij,l))*( 0.5*(zq+zqp)*zsigp &
                +(zsig-zsigp)*(zq+zz*(zqm-zq)) )
      endif
   enddo
  enddo

  do l=1,llm
     do ij=iip2,ip1jm
        new_m=masse(ij,l) &
              +v_m(ij,l)-v_m(ij-iip1,l)
        q(ij,l)=(q(ij,l)*masse(ij,l)+v_mq(ij,l)-v_mq(ij-iip1,l)) &
              /new_m
        masse(ij,l)=new_m
     enddo
  !.-. ancienne version
     convpn=SSUM(iim,v_mq(1,l),1)
     convmpn=ssum(iim,v_m(1,l),1)
     massen=ssum(iim,masse(1,l),1)
     new_m=massen+convmpn
     q(1,l)=(q(1,l)*massen+convpn)/new_m
     do ij = 1,iip1
        q(ij,l)=q(1,l)
        masse(ij,l)=new_m*aire(ij)/apoln
     enddo

     convps=-SSUM(iim,v_mq(ip1jm-iim,l),1)
     convmps=-ssum(iim,v_m(ip1jm-iim,l),1)
     masses=ssum(iim,masse(ip1jm+1,l),1)
     new_m=masses+convmps
     q(ip1jm+1,l)=(q(ip1jm+1,l)*masses+convps)/new_m
     do ij = ip1jm+1,ip1jmp1
        q(ij,l)=q(ip1jm+1,l)
        masse(ij,l)=new_m*aire(ij)/apols
     enddo
  enddo

  RETURN
END SUBROUTINE advny
SUBROUTINE advnz(q,qh,qb,masse,w_m)
  !
  ! Auteurs:   F.Hourdin
  !
  !    ********************************************************************
  ! Shema  d'advection " pseudo amont " .
  ! b designe le bas et h le haut
  ! il y a une correspondance entre le b en z et le d en x
  !    ********************************************************************
  !
  !
  !   --------------------------------------------------------------------
  USE iniprint_mod_h
  USE comgeom_mod_h
  USE dimensions_mod, ONLY: iim, jjm, llm, ndm
USE paramet_mod_h
IMPLICIT NONE
  !


  !
  !
  !   Arguments:
  !   ----------
  real :: masse(ip1jmp1,llm)
  real :: w_m( ip1jmp1,llm+1)
  real :: q(ip1jmp1,llm),qb(ip1jmp1,llm),qh(ip1jmp1,llm)

  !
  !  Local
  !   ---------
  !
  INTEGER :: ij,l
  !
  real :: new_m,zdq,zz
  real :: zsigh(ip1jmp1,llm),zsigb(ip1jmp1,llm),zsig
  real :: w_mq(ip1jmp1,llm+1)
  real :: zm,zq,zsigm,zsigp,zqm,zqp
  real :: prec
  save prec

#ifdef CRAY
  data prec/1.e-24/
#else
  data prec/1.e-13/
#endif

  do l=1,llm
        do ij=1,ip1jmp1
           zdq=qb(ij,l)-qh(ij,l)
           ! if((qh(ij,l)-q(ij,l))*(q(ij,l)-qb(ij,l)).lt.0.) then
           !    print*,'probleme au point ij=',ij,'  l=',l
           !    print*,qh(ij,l),q(ij,l),qb(ij,l)
           !    qh(ij,l)=q(ij,l)
           !    qb(ij,l)=q(ij,l)
           ! endif

           if(abs(zdq).gt.prec) then
              zsigb(ij,l)=(q(ij,l)-qh(ij,l))/zdq
              zsigh(ij,l)=1.-zsigb(ij,l)
              zsigb(ij,l)=min(max(zsigb(ij,l),0.),1.)
           else
              zsigb(ij,l)=0.5
              zsigh(ij,l)=0.5
           endif
        enddo
   enddo

   ! print*,'ok1'
  !   calcul de la pente maximum dans la maille en valeur absolue
   do l=2,llm
   do ij=1,ip1jmp1
      if (w_m(ij,l).ge.0.) then
         zsigp=zsigb(ij,l)
         zsigm=zsigh(ij,l)
         zqp=qb(ij,l)
         zqm=qh(ij,l)
         zm=masse(ij,l)
         zq=q(ij,l)
      else
         zsigm=zsigb(ij,l-1)
         zsigp=zsigh(ij,l-1)
         zqm=qb(ij,l-1)
         zqp=qh(ij,l-1)
         zm=masse(ij,l-1)
         zq=q(ij,l-1)
      endif
      zsig=abs(w_m(ij,l))/zm
      if(zsig.eq.0.) zsigp=0.1
      if (zsig.le.zsigp) then
          w_mq(ij,l)=w_m(ij,l)*(zqp-0.5*zsig/zsigp*(zqp-zq))
      else
          zz=0.5*(zsig-zsigp)/zsigm
          w_mq(ij,l)=sign(zm,w_m(ij,l))*( 0.5*(zq+zqp)*zsigp &
                +(zsig-zsigp)*(zq+zz*(zqm-zq)) )
      endif
  enddo
  enddo

   do ij=1,ip1jmp1
      w_mq(ij,llm+1)=0.
      w_mq(ij,1)=0.
   enddo

  do l=1,llm
     do ij=1,ip1jmp1
        new_m=masse(ij,l)+w_m(ij,l+1)-w_m(ij,l)
        q(ij,l)=(q(ij,l)*masse(ij,l)+w_mq(ij,l+1)-w_mq(ij,l)) &
              /new_m
        masse(ij,l)=new_m
     enddo
  enddo
  ! print*,'ok3'
  RETURN
END SUBROUTINE advnz
