!> @file
!> pvetc() computes potential vorticity, etc.
!>
!> This subprogram computes
!> computation | equation
!> -----------------|------------
!> Montgomery streamfunction       | hm=cp*t+g*z
!> Specific entropy                | s=cp*log(t/t0)-r*log(p/p0)
!> Brunt-Vaisala frequency squared | bvf2=g/cp*ds/dz
!> Potential vorticity             | pvn=(av*ds/dz-dv/dz*ds/dx+du/dz*ds/dy)/rho/cp
!> Potential temperature           | theta=t0*exp(s/cp)
!> Static stability                | sigma=t/g*bvf2
!> Potential vorticity in PV units | pvu=10**-6*theta*pvn
!>
!> @param[in] km integer number of levels.
!> @param[in] p real (km) pressure (Pa).
!> @param[in] px real (km) pressure x-gradient (Pa/m).
!> @param[in] py real (km) pressure y-gradient (Pa/m).
!> @param[in] t real (km) (virtual) temperature (K).
!> @param[in] tx real (km) (virtual) temperature x-gradient (K/m).
!> @param[in] ty real (km) (virtual) temperature y-gradient (K/m).
!> @param[in] h real (km) height (m).
!> @param[in] u real (km) x-component wind (m/s).
!> @param[in] v real (km) y-component wind (m/s).
!> @param[in] av real (km) absolute vorticity (1/s).
!> @param[out] hm real (km) Montgomery streamfunction (m**2/s**2).
!> @param[out] s real (km) specific entropy (J/K/kg).
!> @param[out] bvf2 real (km) Brunt-Vaisala frequency squared (1/s**2).
!> @param[out] pvn real (km) potential vorticity (m**2/kg/s).
!> @param[out] theta real (km) (virtual) potential temperature (K).
!> @param[out] sigma real (km) static stability (K/m).
!> @param[out] pvu real (km) potential vorticity (10**-6*K*m**2/kg/s).
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1999-10-18 | Mark Iredell | Initial
!>
!> @author Mark Iredell np23 @date 1999-10-18
    subroutine pvetc(km,p,px,py,t,tx,ty,h,u,v,av,hm,s,bvf2,pvn,theta,sigma,pvu)

    use physcons_post, only: con_cp, con_g, con_rd, con_rocp
!
    implicit none
    integer,intent(in):: km
    real,intent(in), dimension(km):: p,px,py,t,tx,ty,h,u,v,av
    real,intent(out),dimension(km):: hm,s,bvf2,pvn,theta,sigma,pvu
!   real,parameter:: hhmin=500.,t0=2.e2,p0=1.e5
    real,parameter:: hhmin=5.,t0=2.e2,p0=1.e5
    integer k,kd,ku,k2(2)
    real cprho,sx,sy,sz,uz,vz
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    do k=1,km
      hm(k) = con_cp*t(k) + con_g*h(k)
      s(k)  = con_cp*log(t(k)/t0) - con_rd*log(p(k)/p0)
    enddo
    do k=1,km
      call rsearch1(km,h,2,(/h(k)-hhmin,h(k)+hhmin/),k2)
!     kd = max(k2(1),1)
!     ku = min(k2(2)+1,km)
!     kd = min(k2(1),km)   ! Chuang: post counts from top down, redefine lower bound
      kd = min(k2(1)+1,km) ! Chuang: post counts from top down,
!     ku = max(k2(2)-1,1)
      ku = max(k2(2),1)
      if(ku==1) kd=2       ! Chuang: make sure ku ne kd at model top
      cprho    = p(k)/(con_rocp*t(k))
      sx       = con_cp*tx(k)  / t(k)-con_rd*px(k)/p(k)
      sy       = con_cp*ty(k)  / t(k)-con_rd*py(k)/p(k)
      sz       = (s(ku)-s(kd)) / (h(ku)-h(kd))
      uz       = (u(ku)-u(kd)) / (h(ku)-h(kd))
      vz       = (v(ku)-v(kd)) / (h(ku)-h(kd))
      bvf2(k)  = con_g/con_cp*sz
      pvn(k)   = (av(k)*sz - vz*sx + uz*sy) / cprho
      theta(k) = t0*exp(s(k)/con_cp)
      sigma(k) = t(k)/con_g*bvf2(k)
      pvu(k)   = 1.e6*theta(k)*pvn(k)
    enddo
  end subroutine
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!> p2th() interpolates to isentropic level.
!>
!> This subprogram interpolates fields to given isentropic levels.
!> The interpolation is linear in entropy.
!> Outside the domain the bitmap is set to false.
!>
!> @param[in] km integer number of levels.
!> @param[in] theta real (km) potential temperature (K).
!> @param[in] u real (km) x-component wind (m/s).
!> @param[in] v real (km) y-component wind (m/s).
!> @param[in] h real (km) height (m).
!> @param[in] t real (km) temperature (K).
!> @param[in] pvu real (km) potential vorticity in PV units (10**-6*K*m**2/kg/s).
!> @param[in] kth integer number of isentropic levels.
!> @param[in] th real (kth) isentropic levels (K).
!> @param[out] lpv logical*1 (kth) bitmap.
!> @param[out] uth real (kth) x-component wind (m/s).
!> @param[out] vth real (kth) y-component wind (m/s).
!> @param[out] hth real (kth) height (m).
!> @param[out] tth real (kth) temperature (K).
!> @param[out] zth real (kth) potential vorticity in PV units (10**-6*K*m**2/kg/s).
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1999-10-18 | Mark Iredell | Initial
!>
!> @author Mark Iredell np23 @date 1999-10-18
    subroutine p2th(km,theta,u,v,h,t,pvu,sigma,rh,omga,kth,th &
                 ,lth,uth,vth,hth,tth,zth,sigmath,rhth,oth)
    implicit none
    integer,intent(in):: km,kth
    real,intent(in),dimension(km):: theta,u,v,h,t,pvu,sigma,rh,omga
    real,intent(in):: th(kth)
    logical*1,intent(out),dimension(kth):: lth
    real,intent(out),dimension(kth):: uth,vth,hth,tth,zth &
                                     ,sigmath,rhth,oth
    real w
    integer loc(kth),l
    integer k
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    call rsearch1(km,theta(1),kth,th(1),loc(1))
    do k=1,kth
      l = loc(k)
      lth(k) = l > 0 .and.l < km
      if(lth(k)) then
        w = log(th(k)/theta(l)) / log(theta(l+1)/theta(l))
        uth(k)     = u(l)     + w*(u(l+1)-u(l))
        vth(k)     = v(l)     + w*(v(l+1)-v(l))
        hth(k)     = h(l)     + w*(h(l+1)-h(l))
        tth(k)     = t(l)     + w*(t(l+1)-t(l))
        zth(k)     = pvu(l)   + w*(pvu(l+1)-pvu(l))
        sigmath(k) = sigma(l) + w*(sigma(l+1)-sigma(l))
        rhth(k)    = rh(l)    + w*(rh(l+1)-rh(l))
!	pth(k)     = p(l)     + w*(p(l+1)-p(l))
        oth(k)     = omga(l)  + w*(omga(l+1)-omga(l))
      endif
    enddo
  end subroutine
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!> p2pv() interpolates to potential vorticity level.
!>
!> This subprogram interpolates fields to given potential vorticity
!> levels within given pressure limits.
!> The output level is the first  encountered from the top pressure limit.
!> If the given potential vorticity level is not found, the outputs are zero
!> and the bitmap is false. The interpolation is linear in potential vorticity.
!>
!> @param[in] km integer number of levels.
!> @param[in] pvu real (km) potential vorticity in PV units (10**-6*K*m**2/kg/s).
!> @param[in] h real (km) height (m).
!> @param[in] t real (km) temperature (K).
!> @param[in] p real (km) pressure (Pa).
!> @param[in] u real (km) x-component wind (m/s).
!> @param[in] v real (km) y-component wind (m/s).
!> @param[in] kpv integer number of potential vorticity levels.
!> @param[in] pv real (kpv) potential vorticity levels (10**-6*K*m**2/kg/s).
!> @param[in] pvpt real (kpv) top pressures for PV search (Pa).
!> @param[in] pvpb real (kpv) bottom pressures for PV search (Pa).
!> @param[out] lpv logical*1 (kpv) bitmap.
!> @param[out] upv real (kpv) x-component wind (m/s).
!> @param[out] vpv real (kpv) y-component wind (m/s).
!> @param[out] hpv real (kpv) temperature (K).
!> @param[out] tpv real (kpv) temperature (K).
!> @param[out] ppv real (kpv) pressure (Pa).
!> @param[out] spv real (kpv) wind speed shear (1/s).
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1999-10-18 | Mark Iredell  | Initial
!> 2021-08-31 | Hui-ya Chuang | Increase depth criteria for identifying PV layer from 25 to 50 to avoid finding shallow high level PV layer in high latitudes
!>
!> @author Mark Iredell np23 @date 1999-10-18
    subroutine p2pv(km,pvu,h,t,p,u,v,kpv,pv,pvpt,pvpb,&
                  lpv,upv,vpv,hpv,tpv,ppv,spv)
    use physcons_post, only: con_rog
    implicit none
    integer,intent(in):: km,kpv
    real,intent(in),dimension(km):: pvu,h,t,p,u,v
    real,intent(in):: pv(kpv),pvpt(kpv),pvpb(kpv)
    logical*1,intent(out),dimension(kpv):: lpv
    real,intent(out),dimension(kpv):: upv,vpv,hpv,tpv,ppv,spv
!    real,parameter:: pd=2500.
! Increase depth criteria for identifying PV layer from 25 to 50
! to avoid finding shallow high level PV layer in high latitudes
    real,parameter:: pd=5000.
    real w,spdu,spdd
    integer k,l1,l2,lu,ld,l
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    do k=1,kpv
      call rsearch1(km,p,1,pvpb(k),l1)
      call rsearch1(km,p,1,pvpt(k),l2)
!     l1=l1+1
      l = 0
      if(pv(k) >= 0.) then
!       do lu=l2-1,l1,-1
!       do lu=l2,l1-1 ! Chuang: post counts top down	
        do lu=l2+2,l1 ! Chuang: post counts top down
!         if(pv(k)<pvu(lu+1).and.pv(k)>=pvu(lu)) then
          if(pv(k) >= pvu(lu+1).and.pv(k) < pvu(lu)) then
            call rsearch1(km,p,1,p(lu)+pd,ld)
!           if(all(pv(k)>=pvu(ld:lu-1))) then
            if(all(pv(k) >= pvu(lu+1:ld))) then
              l = lu
              exit
            endif
          endif
        enddo
      else
!       do lu=l2-1,l1,-1
!       do lu=l2,l1-1 ! Chuang: post counts top down	
        do lu=l2+2,l1 ! Chuang: post counts top down
!         if(pv(k)>pvu(lu+1).and.pv(k)<=pvu(lu)) then
          if(pv(k) <= pvu(lu+1).and.pv(k) > pvu(lu)) then
            call rsearch1(km,p,1,p(lu)+pd,ld)
!           if(all(pv(k)<=pvu(ld:lu-1))) then
            if(all(pv(k) <= pvu(lu+1:ld))) then
              l = lu
              exit
            endif
          endif
        enddo
      endif
      lpv(k) = l > 0
      if(lpv(k)) then
        w = (pv(k)-pvu(l))/(pvu(l+1)-pvu(l))
        upv(k) = u(l) + w*(u(l+1)-u(l))
        vpv(k) = v(l) + w*(v(l+1)-v(l))
        hpv(k) = h(l) + w*(h(l+1)-h(l))
        tpv(k) = t(l) + w*(t(l+1)-t(l))
        ppv(k) = p(l)*exp((h(l)-hpv(k))*(1-0.5*(tpv(k)/t(l)-1))/(con_rog*t(l)))

        spdu   = sqrt(u(l+1)*u(l+1) + v(l+1)*v(l+1))
        spdd   = sqrt(u(l)*u(l)     + v(l)*v(l))
        spv(k) = (spdu-spdd) / (h(l+1)-h(l))
      endif
    enddo
  end subroutine
!-------------------------------------------------------------------------------

!-------------------------------------------------------------------------------
!> rsearch1() searches for a surrounding real interval.
!>
!> This subprogram searches a monotonic sequences of real numbers
!> for intervals that surround a given search set of real numbers.
!> the sequences may be monotonic in either direction; the real numbers
!> may be single or double precision.
!>
!> @param[in] km1 integer number of points in the sequence.
!> @param[in] z1 real (km1) sequence values to search. (z1 must be monotonic in either direction)
!> @param[in] km2 integer number of points to search for.
!> @param[in] z2 real (km2) set of values to search for. (z2 need not be monotonic)
!> @param[out] l2 integer (km2) interval locations from 0 to km1. (z2 will be between z1(l2) and z1(l2+1))
!>
!> @note
!>  * Returned values of 0 or km1 indicate that the given search value is outside the range of the sequence.
!>  * If a search value is identical to one of the sequence values then the location returned points to the identical value.
!>  * If the sequence is not strictly monotonic and a search value is identical to more than one of the sequence values, then the location returned may point to any of the identical values.
!>  * If l2(k)=0, then z2(k) is less than the start point z1(1) for ascending sequences (or greater than for descending sequences).
!>  * If l2(k)=km1, then z2(k) is greater than or equal to the end point z1(km1) for ascending sequences (or less than or equal to for descending sequences).  Otherwise z2(k) is between the values z1(l2(k)) and z1(l2(k+1)) and may equal the former.
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1998-05-01 | Mark Iredell  | Initial
!>
!> @author Mark Iredell w/nmc23 @date 1998-05-01
    subroutine rsearch1(km1,z1,km2,z2,l2)
  implicit none
  integer,intent(in):: km1,km2
  real,intent(in):: z1(km1),z2(km2)
  integer,intent(out):: l2(km2)
  integer k1,k2
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  find the surrounding input interval for each output point.
  if(z1(1) <= z1(km1)) then
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  input coordinate is monotonically ascending.
    do k2=1,km2
      if (z1(1) >= z2(k2)) then
        l2(k2) = 1
      else
      l2(k2)=km1
      do k1=1,km1-1
        if(z1(k1) <= z2(k2) .and. z1(k1+1) > z2(k2)) then
          l2(k2) = k1
          exit
        endif
      enddo
     endif
    enddo
  else
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  input coordinate is monotonically descending.
    do k2=1,km2
     if (z1(1) <= z2(k2)) then
        l2(k2) = 1
      else
      l2(k2)=km1
      do k1=km1,2,-1
        if(z2(k2) >= z1(k1) .and. z2(k2) < z1(k1-1)) then
          l2(k2) = k1-1
          exit
        endif
      enddo
     endif
    enddo
  endif
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
end subroutine
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!> tpause() computes tropopause level fields.
!>
!> This subprogram finds the tropopause level and computes fields
!> at the tropopause level.  The tropopause is defined as the lowest level
!> above 500 mb which has a temperature lapse rate of less than 2 K/km.
!> The lapse rate must average less than 2 K/km over a 2 km depth.
!> If no such level is found below 50 mb, the tropopause is set to 50 mb.
!> The tropopause fields are interpolated linearly in lapse rate.
!> The tropopause pressure is found hydrostatically.
!> The tropopause wind shear is computed as the partial derivative
!> of wind speed with respect to height at the tropopause level.
!>
!> @param[in] km integer number of levels.
!> @param[in] p real (km) pressure (Pa).
!> @param[in] u real (km) x-component wind (m/s).
!> @param[in] v real (km) y-component wind (m/s).
!> @param[in] t real (km) temperature (K).
!> @param[in] h real (km) height (m).
!> @param[out] ptp real tropopause pressure (Pa).
!> @param[out] utp real tropopause x-component wind (m/s).
!> @param[out] vtp real tropopause y-component wind (m/s).
!> @param[out] ttp real tropopause temperature (K).
!> @param[out] htp real tropopause height (m).
!> @param[out] shrtp real tropopause wind shear (1/s).
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1999-10-18 | Mark Iredell  | Initial
!>
!> @author Mark Iredell np23 @date 1999-10-18
    subroutine tpause(km,p,u,v,t,h,ptp,utp,vtp,ttp,htp,shrtp)
    use physcons_post, only: con_rog
    implicit none
    integer,intent(in):: km
    real,intent(in),dimension(km):: p,u,v,t,h
    real,intent(out):: ptp,utp,vtp,ttp,htp,shrtp
    real,parameter:: ptplim(2)=(/500.e+2,50.e+2/),gamtp=2.e-3,hd=2.e+3
    real gamu,gamd,td,gami,wtp,spdu,spdd
    integer klim(2),k,kd,ktp
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  find tropopause level
    call rsearch1(km-2,p(2),2,ptplim,klim)
    klim(1)=klim(1)+1
    klim(2)=klim(2)+2
    ! klim(1) > klim(2) or loops does not run ; klim(2) has a
    ! minimum value of 3 to insure k-2 != 0 in called subprogram
    gamd=1.e+9
    ktp=klim(2)
    wtp=0
!    do k=klim(1),klim(2)
    do k=klim(1),klim(2),-1
!      gamu=(t(k-1)-t(k+1))/(h(k+1)-h(k-1))
      gamu=(t(k+1)-t(k-1))/(h(k-1)-h(k+1))
      if(gamu<=gamtp) then
!        call rsearch1(km-k-1,h(k+1),1,h(k)+hd,kd)
	call rsearch1(k-2,h(2),1,h(k)+hd,kd)
!        td=t(k+kd)+(h(k)+hd-h(k+kd))/(h(k+kd+1)-h(k+kd))*(t(k+kd+1)-t(k+kd))
        td=t(kd+2)+(h(k)+hd-h(2+kd))/(h(kd+1)-h(2+kd))*(t(kd+1)-t(2+kd))
        gami=(t(k)-td)/hd
        if(gami<=gamtp) then
          ktp=k
          wtp=(gamtp-gamu)/(max(gamd,gamtp+0.1e-3)-gamu)
          exit
        endif
      endif
      gamd=gamu
    enddo
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  compute tropopause level fields
    utp=u(ktp)-wtp*(u(ktp)-u(ktp-1))
    vtp=v(ktp)-wtp*(v(ktp)-v(ktp-1))
    ttp=t(ktp)-wtp*(t(ktp)-t(ktp-1))
    htp=h(ktp)-wtp*(h(ktp)-h(ktp-1))
    ptp=p(ktp)*exp((h(ktp)-htp)*(1-0.5*(ttp/t(ktp)-1))/(con_rog*t(ktp)))
    spdu=sqrt(u(ktp)**2+v(ktp)**2)
    spdd=sqrt(u(ktp-1)**2+v(ktp-1)**2)
    shrtp=(spdu-spdd)/(h(ktp)-h(ktp-1))
    
    utp=u(ktp)-wtp*(u(ktp)-u(ktp+1))
    vtp=v(ktp)-wtp*(v(ktp)-v(ktp+1))
    ttp=t(ktp)-wtp*(t(ktp)-t(ktp+1))
    htp=h(ktp)-wtp*(h(ktp)-h(ktp+1))
    ptp=p(ktp)*exp((h(ktp)-htp)*(1-0.5*(ttp/t(ktp)-1))/(con_rog*t(ktp)))
    spdu=sqrt(u(ktp)**2+v(ktp)**2)
    spdd=sqrt(u(ktp+1)**2+v(ktp+1)**2)
    shrtp=(spdu-spdd)/(h(ktp)-h(ktp+1))
  end subroutine
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!> mxwind() computes maximum wind level fields.
!>
!> This subprogram finds the maximum wind level and computes fields
!> at the maximum wind level. The maximum wind level is searched for
!> between 500 mb and 100 mb. The height and wind speed at the maximum wind
!> speed level is calculated by assuming the wind speed varies quadratically
!> in height in the neighborhood of the maximum wind level.  The other fields
!> are interpolated linearly in height to the maximum wind level.
!> The maximum wind level pressure is found hydrostatically.
!>
!> @param[in] km integer number of levels.
!> @param[in] p real (km) pressure (Pa).
!> @param[in] u real (km) x-component wind (m/s).
!> @param[in] v real (km) y-component wind (m/s).
!> @param[in] t real (km) temperature (K).
!> @param[in] h real (km) height (m).
!> @param[out] pmw real maximum wind level pressure (Pa).
!> @param[out] umw real maximum wind level x-component wind (m/s).
!> @param[out] vmw real maximum wind level y-component wind (m/s).
!> @param[out] tmw maximum wind level temperature (K).
!> @param[out] hmw real maximum wind level height (m).
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1999-10-18 | Mark Iredell | Initial
!> 2005-02-02 | Mark Iredell | Changed upper limit to 100 mb
!>
!> @author Mark Iredell np23 @date 1999-10-18
    subroutine mxwind(km,p,u,v,t,h,pmw,umw,vmw,tmw,hmw)
    use physcons_post, only: con_rog
    implicit none
    integer,intent(in):: km
    real,intent(in),dimension(km):: p,u,v,t,h
    real,intent(out):: pmw,umw,vmw,tmw,hmw
    real,parameter:: pmwlim(2)=(/500.e+2,100.e+2/)
    integer klim(2),k,kmw
    real spd(km),spdmw,wmw,dhd,dhu,shrd,shru,dhmw,ub,vb,spdb
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  find maximum wind level
    call rsearch1(km,p(1),2,pmwlim,klim)
!    klim(1)=klim(1)+1
    klim(2)=klim(2)+1
!    spd(klim(1):klim(2))=sqrt(u(klim(1):klim(2))**2+v(klim(1):klim(2))**2)
    spd(klim(2):klim(1))=sqrt(u(klim(2):klim(1))**2+v(klim(2):klim(1))**2)
    spdmw=spd(klim(1))
    kmw=klim(1)
!    do k=klim(1)+1,klim(2)
    do k=klim(1)-1,klim(2),-1
      if(spd(k)>spdmw) then
        spdmw=spd(k)
        kmw=k
      endif
    enddo
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  find speed and height at the maximum wind level
    if(kmw==klim(1).or.kmw==klim(2)) then
      hmw=h(kmw)
      spdmw=spd(kmw)
      wmw=0.
    else
!      dhd=h(kmw)-h(kmw-1)
      dhd=h(kmw)-h(kmw+1) !post counts top down
!      dhu=h(kmw+1)-h(kmw)
      dhu=h(kmw-1)-h(kmw)
!      shrd=(spd(kmw)-spd(kmw-1))/(h(kmw)-h(kmw-1))
      shrd=(spd(kmw)-spd(kmw+1))/(h(kmw)-h(kmw+1))
!      shru=(spd(kmw)-spd(kmw+1))/(h(kmw+1)-h(kmw))
      shru=(spd(kmw)-spd(kmw-1))/(h(kmw-1)-h(kmw))
      dhmw=(shrd*dhu-shru*dhd)/(2*(shrd+shru))
      hmw=h(kmw)+dhmw
      spdmw=spd(kmw)+dhmw**2*(shrd+shru)/(dhd+dhu)
!      if(dhmw>0) kmw=kmw+1
      if(dhmw>0) kmw=kmw-1
!      wmw=(h(kmw)-hmw)/(h(kmw)-h(kmw-1))
      wmw=(h(kmw)-hmw)/(h(kmw)-h(kmw+1))
    endif
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  compute maximum wind level fields
!    ub=u(kmw)-wmw*(u(kmw)-u(kmw-1))
    ub=u(kmw)-wmw*(u(kmw)-u(kmw+1))
!    vb=v(kmw)-wmw*(v(kmw)-v(kmw-1))
    vb=v(kmw)-wmw*(v(kmw)-v(kmw+1))
    spdb=max(sqrt(ub**2+vb**2),1.e-6)
    umw=ub*spdmw/spdb
    vmw=vb*spdmw/spdb
!    tmw=t(kmw)-wmw*(t(kmw)-t(kmw-1))
    tmw=t(kmw)-wmw*(t(kmw)-t(kmw+1))
    pmw=p(kmw)*exp((h(kmw)-hmw)*(1-0.5*(tmw/t(kmw)-1))/(con_rog*t(kmw)))
  end subroutine 

! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!> mptgen() generates grid decomposition dimensions.
!>
!> This subprogram decomposes total dimensions of a problem
!> into smaller domains to be managed on a distributed memory system.
!> The last dimension given is decomposed first.  If more decompositions
!> are possible, the next to last dimension is decomposed next, and so on.
!> The transpositions between decompositions should be done by mptran*.
!>
!> @param[in] mpirank integer(kint_mpi) rank of the process (from mpi_comm_rank).
!> @param[in] mpisize integer(kint_mpi) size of the process (from mpi_comm_size).
!> @param[in] nd integer(kint_mpi) number of dimensions to decompose.
!> @param[in] jt1 integer(kint_mpi) (nd) lower bounds of total dimensions.
!> @param[in] jt2 integer(kint_mpi) (nd) upper bounds of total dimensions.
!> @param[out] j1 integer(kint_mpi) (nd) lower bounds of local decompositions.
!> @param[out] j2 integer(kint_mpi) (nd) upper bounds of local decompositions.
!> @param[out] jx integer(kint_mpi) (nd) local size of decompositions.
!> @param[out] jm integer(kint_mpi) (nd) maximum size of decompositions.
!> @param[out] jn integer(kint_mpi) (nd) number of decompositions.
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1999-02-12 | Mark Iredell | Initial
!>
!> @author Mark Iredell np23 @date 1999-02-12  
  subroutine mptgen(mpirank,mpisize,nd,jt1,jt2,j1,j2,jx,jm,jn)
  use machine_post,only:kint_mpi
  implicit none
  integer(kint_mpi),intent(in):: mpirank,mpisize,nd,jt1(nd),jt2(nd)
  integer(kint_mpi),intent(out):: j1(nd),j2(nd),jx(nd),jm(nd),jn(nd)
  integer msize,mrank,msn,mrn,n
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  msize=mpisize
  mrank=mpirank
  do n=nd,1,-1
    if(jt2(n)>=jt1(n)) then
      jm(n)=(jt2(n)-jt1(n))/msize+1
      msn=max(msize/(jt2(n)-jt1(n)+1),1)
      if(n==1) msn=1
      jn(n)=msize/msn
      mrn=mrank/msn
      j1(n)=min(jt1(n)+jm(n)*mrn,jt2(n)+1)
      j2(n)=min(jt1(n)+jm(n)*mrn+jm(n)-1,jt2(n))
      jx(n)=j2(n)-j1(n)+1
      msize=msn
      mrank=mod(mrank,msn)
      write(0,*)' mrank=',mrank,' j1=',j1(n),' j2=',j2(n),' jx=',jx(n),' jm=',jm(n)
    else
      jm(n)=0
      jn(n)=1
      j1(n)=jt1(n)
      j2(n)=jt2(n)
      jx(n)=0
    endif
  enddo
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
end subroutine
!-------------------------------------------------------------------------------
!> mptranr4() transposes grid decompositions.
!>
!> This subprogram transposes an array of data from one
!> grid decomposition to another by using message passing.
!> The grid decompositions should be generated by mptgen.
!>
!> @param[in] mpicomm  integer(kint_mpi) mpi communicator.
!> @param[in] mpisize  integer(kint_mpi) size of the process (from mpi_comm_size).
!> @param[in] im       integer(kint_mpi) undecomposed range.
!> @param[in] ida      integer(kint_mpi) undecomposed input dimension.
!> @param[in] idb      integer(kint_mpi) undecomposed output dimension.
!> @param[in] jm       integer(kint_mpi) output grid decomposition size.
!> @param[in] jma      integer(kint_mpi) input grid undecomposed range.
!> @param[in] jmb      integer(kint_mpi) output grid decomposed range.
!> @param[in] jda      integer(kint_mpi) input grid undecomposed dimension.
!> @param[in] km       integer(kint_mpi) input grid decomposition size.
!> @param[in] kma      integer(kint_mpi) input grid decomposed range.
!> @param[in] kmb      integer(kint_mpi) output grid undecomposed range.
!> @param[in] kdb      integer(kint_mpi) output grid undecomposed dimension.
!> @param[in] a        real(4) (ida,jda,kma) input array.
!> @param[out] b real(4) (idb,kdb,jmb) output array.
!> @param[out] ta,tb real(4) (im,jm,km,mpisize) work arrays.
!>
!> @note
!>   While this routine serves a wide variety of scalable transpose functions for multidimensional grids,
!>  * It does not work with nonrectanguloid grids;
!>  * It does not do any load balancing;
!>  * It does not do any communication hiding.
!>
!>   This subprogram must be used rather than mpi_alltoall in any of the following cases:
!>
!>  * The undecomposed range is less than the respective dimension (either im<ida or im<idb)
!>  * The decomposition size is greater than one (either km>1 or jm>1)
!>  * The decomposed range is ever zero (either kma==0 or jmb==0 for any process)
!>  * The output grid range is not the full extent (either kmb<mpisize or kmb<kda or jma<mpisize or jma<jda)
!>
!>   If none of these conditions apply, mpi_alltoall could be used directly rather than this subprogram and would be more efficient.
!> @note
!>  Example 1.  Transpose a 1000 x 10000 matrix.
!> <pre>
!>  include 'mpif.h'                                     ! use mpi
!>  parameter(jt=1000,kt=10000)                          ! set problem size
!>  real,allocatable:: a(:,:),b(:,:)                     ! declare arrays
!>  call mpi_init(ierr)                                  ! initialize mpi
!>  call mpi_comm_rank(MPI_COMM_WORLD,mpirank,ierr)      ! get mpi rank
!>  call mpi_comm_size(MPI_COMM_WORLD,mpisize,ierr)      ! get mpi size
!>  call mptgen(mpirank,mpisize,1,1,jt,j1,j2,jx,jm,jn)   ! decompose output
!>  call mptgen(mpirank,mpisize,1,1,kt,k1,k2,kx,km,kn)   ! decompose input
!>  allocate(a(jt,k1:k2),b(kt,j1:j2))                    ! allocate arrays
!>  a=reshape((/((j+k,j=1,jt),k=k1,k2)/),(/jt,k2-k1+1/)) ! initialize input
!>  call mptranr4(MPI_COMM_WORLD,mpisize,1,1,1,          ! transpose arrays
!>  &              jm,jt,j2-j1+1,jt,km,k2-k1+1,kt,kt,a,b)
!>  print '(2i8,f16.1)',((k,j,b(k,j),k=2000,kt,2000),    ! print some values
!>  &                    j=((j1-1)/200+1)*200,j2,200)
!>  call mpi_finalize(ierr)                              ! finalize mpi
!>  end
!> </pre>
!>  This transpose took 0.6 seconds on 4 2-way winterhawk nodes.
!> @note
!>  A 20000x10000 transpose took 3.4 seconds on 16 2-way winterhawk nodes.
!> @note
!>  Thus a transpose may take about 1 second for every 16 Mb per node.
!>
!> ### Program History Log
!> Date | Programmer | Comments
!> -----|------------|---------
!> 1999-02-12 | Mark Iredell | Initial
!>
!> @author Mark Iredell np23 @date 1999-02-12
  subroutine mptranr4(mpicomm,mpisize,im,ida,idb,&
                      jm,jma,jmb,jda,km,kma,kmb,kdb,a,b,ta,tb)
  use machine_post,only:kint_mpi
  implicit none
  include 'mpif.h'
  integer(kint_mpi),intent(in):: mpicomm,mpisize
  integer(kint_mpi),intent(in):: im,ida,idb
  integer(kint_mpi),intent(in):: jm,jma,jmb,jda
  integer(kint_mpi),intent(in):: km,kma,kmb,kdb
  real(4),dimension(ida,jda,kma),intent(in):: a
  real(4),dimension(idb,kdb,jmb),intent(out):: b
  real(4),dimension(im,jm,km,mpisize),intent(inout):: ta,tb
  integer(4) jmb1(1),jmbf(mpisize),kma1(1),kmaf(mpisize)
  integer(kint_mpi)::i,j,k,l,ierr,ja,kb
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  jmb1(1) = jmb
  call mpi_allgather(jmb1,1,MPI_INTEGER4,jmbf,1,MPI_INTEGER4,mpicomm,ierr)
  kma1(1) = kma
  call mpi_allgather(kma1,1,MPI_INTEGER4,kmaf,1,MPI_INTEGER4,mpicomm,ierr)
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  internally transpose input array
!$omp parallel do private(i,j,k,l,ja)
  do l=1,mpisize
    do k=1,kma
      do j=1,jm
        ja = j + sum(jmbf(1:l-1))
        if(ja <= jma) then
          do i=1,im
            ta(i,j,k,l) = a(i,ja,k)
          enddo
        endif
      enddo
    enddo
  enddo
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  externally transpose data
  call mpi_alltoall(ta,im*jm*km,MPI_REAL4,tb,im*jm*km,MPI_REAL4,mpicomm,ierr)
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  internally transpose output array
!$omp parallel do private(i,j,k,l,kb)
  do l=1,mpisize
    do k=1,km
      kb = k + sum(kmaf(1:l-1))
      if(kb <= kmb) then
        do j=1,jmb
          do i=1,im
            b(i,kb,j) = tb(i,j,k,l)
          enddo
        enddo
      endif
    enddo
  enddo
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
end subroutine
!-----------------------------------------------------------------------