MODULE  module_force_scm (docs)   1

! AUTHOR: Josh Hacker (NCAR/RAL)
! Forces a single-column (3x3) version of WRF

CONTAINS


   SUBROUTINE  force_scm (docs)  (itimestep, dt, scm_force, dx, num_force_layers       & 1,16
                             , scm_th_adv, scm_qv_adv                        &
                             , scm_wind_adv, scm_vert_adv                    &
                             , u_base, v_base, z_base                        &
                             , z_force, u_g, v_g                             &
                             , u_g_tend, v_g_tend                            &
                             , w_subs, w_subs_tend                           &
                             , th_upstream_x, th_upstream_x_tend             &
                             , th_upstream_y, th_upstream_y_tend             &
                             , qv_upstream_x, qv_upstream_x_tend             &
                             , qv_upstream_y, qv_upstream_y_tend             &
                             , u_upstream_x, u_upstream_x_tend               &
                             , u_upstream_y, u_upstream_y_tend               &
                             , v_upstream_x, v_upstream_x_tend               &
                             , v_upstream_y, v_upstream_y_tend               &
                             , z, z_at_w, th, qv, u, v                       &
                             , thten, qvten, uten, vten                      &
                             , ids, ide, jds, jde, kds, kde                  &
                             , ims, ime, jms, jme, kms, kme                  &
                             , ips, ipe, jps, jpe, kps, kpe                  &
                             , kts, kte                                      &
                            )

! adds forcing to bl tendencies and also to base state/geostrophic winds.

   USE module_init_utilities, ONLY : interp_0
   IMPLICIT NONE


   INTEGER,    INTENT(IN   )                 :: itimestep
   INTEGER,    INTENT(IN   )                 :: num_force_layers, scm_force
   REAL,       INTENT(IN   )                 :: dt,dx
   LOGICAL,    INTENT(IN   )                 :: scm_th_adv, &
                                                scm_qv_adv, &
                                                scm_wind_adv, &
                                                scm_vert_adv

   REAL, DIMENSION(ims:ime,kms:kme,jms:jme), INTENT(IN   ) :: z, th, qv
   REAL, DIMENSION(ims:ime,kms:kme,jms:jme), INTENT(IN   ) :: u, v
   REAL, DIMENSION(ims:ime,kms:kme,jms:jme), INTENT(IN   ) :: z_at_w
   REAL, DIMENSION(ims:ime,kms:kme,jms:jme), INTENT(INOUT) :: thten, qvten
   REAL, DIMENSION(ims:ime,kms:kme,jms:jme), INTENT(INOUT) :: uten, vten
   REAL, DIMENSION( kms:kme ), INTENT(INOUT)               :: u_base, v_base
   REAL, DIMENSION( kms:kme ), INTENT(INOUT)               :: z_base
   REAL, DIMENSION(num_force_layers), INTENT (IN)          :: z_force
   REAL, DIMENSION(num_force_layers), INTENT (INOUT)       :: u_g,v_g

   REAL, DIMENSION(num_force_layers), INTENT (IN) :: u_g_tend,v_g_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: w_subs_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: th_upstream_x_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: th_upstream_y_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: qv_upstream_x_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: qv_upstream_y_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: u_upstream_x_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: u_upstream_y_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: v_upstream_x_tend
   REAL, DIMENSION(num_force_layers), INTENT (IN) :: v_upstream_y_tend

   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: th_upstream_x
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: th_upstream_y
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: u_upstream_x
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: u_upstream_y
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: v_upstream_x
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: v_upstream_y
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: qv_upstream_x
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: qv_upstream_y
   REAL, DIMENSION(num_force_layers), INTENT (INOUT) :: w_subs

   INTEGER,    INTENT(IN   )    ::     ids,ide, jds,jde, kds,kde, &
                                       ims,ime, jms,jme, kms,kme, &
                                       ips,ipe, jps,jpe, kps,kpe, &
                                       kts,kte
   
! Local
   INTEGER                      :: i,j,k
   LOGICAL                      :: debug = .false.
   REAL                         :: t_x, t_y, qv_x, qv_y 
   REAL                         :: u_x, u_y, v_x, v_y
   REAL, DIMENSION(kms:kme)     :: tau_u, tau_v
   REAL, DIMENSION(kms:kme)     :: th_adv_tend, qv_adv_tend
   REAL, DIMENSION(kms:kme)     :: u_adv_tend, v_adv_tend
   REAL, DIMENSION(kms:kme)     :: dthdz, dudz, dvdz, dqvdz
   REAL                         :: w
   REAL, DIMENSION(kms:kme)     :: w_dthdz, w_dudz, w_dvdz, w_dqvdz
   CHARACTER*256                :: message

   IF ( scm_force .EQ. 0 ) return
 
! NOTES
! z is kts:kte
! z_at_w is kms:kme

     ! this is a good place for checks on the configuration
     if ( z_force(1) > z(ids,1,jds) ) then
        CALL wrf_message("First forcing level must be lower than first WRF half-level")
        WRITE( message , * ) 'z forcing = ',z_force(1), 'z = ',z(ids,1,jds)
!       print*,"z forcing = ",z_force(1), "z = ",z(ids,1,jds)
        CALL wrf_error_fatal( message )
     endif

     u_g = u_g + dt*u_g_tend 
     v_g = v_g + dt*v_g_tend 

     if ( scm_th_adv ) then
       th_upstream_x = th_upstream_x + dt*th_upstream_x_tend
       th_upstream_y = th_upstream_y + dt*th_upstream_y_tend
     endif
     if ( scm_qv_adv) then
       qv_upstream_x = qv_upstream_x + dt*qv_upstream_x_tend
       qv_upstream_y = qv_upstream_y + dt*qv_upstream_y_tend
     endif
     if ( scm_wind_adv ) then
       u_upstream_x = u_upstream_x + dt*u_upstream_x_tend
       u_upstream_y = u_upstream_y + dt*u_upstream_y_tend
       v_upstream_x = v_upstream_x + dt*v_upstream_x_tend
       v_upstream_y = v_upstream_y + dt*v_upstream_y_tend
     endif
     if ( scm_vert_adv ) then
       w_subs = w_subs + dt*w_subs_tend
     endif

! 0 everything in case we don't set it later
     th_adv_tend = 0.0
     qv_adv_tend = 0.0
     u_adv_tend  = 0.0
     v_adv_tend  = 0.0
     w_dthdz     = 0.0
     w_dqvdz     = 0.0
     w_dudz      = 0.0
     w_dvdz      = 0.0

! now interpolate forcing to model vertical grid

!    if ( debug ) print*,' z u_base v_base '
     CALL wrf_debug(100,'z_base  u_base  v_base')
     do k = kms,kme-1
       z_base(k) = z(ids,k,jds)
       u_base(k) = interp_0(u_g,z_force,z_base(k),num_force_layers)
       v_base(k) = interp_0(v_g,z_force,z_base(k),num_force_layers)
!      if ( debug ) print*,z_base(k),u_base(k),v_base(k)
       WRITE( message, '(3f12.4)' ) z_base(k),u_base(k),v_base(k)
       CALL wrf_debug ( 100, message )
    enddo

    if ( scm_th_adv .or. scm_qv_adv .or. scm_wind_adv ) then
       do k = kms,kme-1

          u_x = interp_0(u_upstream_x,z_force,z(ids,k,jds),num_force_layers)
          u_y = interp_0(u_upstream_y,z_force,z(ids,k,jds),num_force_layers)

          v_x = interp_0(v_upstream_x,z_force,z(ids,k,jds),num_force_layers)
          v_y = interp_0(v_upstream_y,z_force,z(ids,k,jds),num_force_layers)

          tau_u(k) = dx/abs(u(ids,k,jds))
          tau_v(k) = dx/abs(v(ids,k,jds))

          if ( scm_wind_adv ) then
             u_adv_tend(k) = (u_x-u(ids,k,jds))/tau_u(k) + (u_y-u(ids,k,jds))/tau_v(k)
             v_adv_tend(k) = (v_x-v(ids,k,jds))/tau_u(k) + (v_y-v(ids,k,jds))/tau_v(k)
          endif

       enddo
    endif

    if ( scm_th_adv ) then
       do k = kms,kme-1
          t_x = interp_0(th_upstream_x,z_force,z(ids,k,jds),num_force_layers)
          t_y = interp_0(th_upstream_y,z_force,z(ids,k,jds),num_force_layers)

          th_adv_tend(k) = (t_x-th(ids,k,jds))/tau_u(k) + (t_y-th(ids,k,jds))/tau_v(k)
       enddo
    endif

    if ( scm_qv_adv ) then
       do k = kms,kme-1
          qv_x = interp_0(qv_upstream_x,z_force,z(ids,k,jds),num_force_layers)
          qv_y = interp_0(qv_upstream_y,z_force,z(ids,k,jds),num_force_layers)

          qv_adv_tend(k) = (qv_x-qv(ids,k,jds))/tau_u(k) + (qv_y-qv(ids,k,jds))/tau_v(k)
       enddo
    endif

! loops are set so that the top and bottom (w=0) are handled correctly
! vertical derivatives
    do k = kms+1,kme-1
       dthdz(k) = (th(2,k,2)-th(2,k-1,2))/(z(2,k,2)-z(2,k-1,2))
       dqvdz(k) = (qv(2,k,2)-qv(2,k-1,2))/(z(2,k,2)-z(2,k-1,2))
       dudz(k)  = (u(2,k,2)-u(2,k-1,2))/(z(2,k,2)-z(2,k-1,2))
       dvdz(k)  = (v(2,k,2)-v(2,k-1,2))/(z(2,k,2)-z(2,k-1,2))
    enddo

! w on full levels, then advect
    if ( scm_vert_adv ) then
       do k = kms+1,kme-1
          w = interp_0(w_subs,z_force,z_at_w(ids,k,jds),num_force_layers)
          w_dthdz(k) = w*dthdz(k)
          w_dqvdz(k) = w*dqvdz(k)
          w_dudz(k)  = w*dudz(k)
          w_dvdz(k)  = w*dvdz(k)
       enddo
    endif

! set tendencies for return
! vertical advection tendencies need to be interpolated back to half levels
    do j = jms,jme
    do k = kms,kme-1
    do i = ims,ime
       thten(i,k,j) = thten(i,k,j) + th_adv_tend(k) +              &
                      0.5*(w_dthdz(k) + w_dthdz(k+1))
       qvten(i,k,j) = qvten(i,k,j) + qv_adv_tend(k) +              &
                      0.5*(w_dqvdz(k) + w_dqvdz(k+1))
       uten(i,k,j)  = uten(i,k,j) + u_adv_tend(k) +                &
                      0.5*(w_dudz(k) + w_dudz(k+1))
       vten(i,k,j)  = vten(i,k,j) + v_adv_tend(k) +                &
                      0.5*(w_dvdz(k) + w_dvdz(k+1))
    enddo
    enddo
    enddo

    RETURN

   END SUBROUTINE force_scm

END MODULE module_force_scm