#if defined( UNICOSMP ) || defined ( NEC_SX )
#define VECTORIZE
#endif
module tp_core 3,1
!BOP
!
! !MODULE: tp_core --- Utilities for the transport core
!
! !USES:
use shr_kind_mod
, only : r8 => shr_kind_r8
!
! !PUBLIC MEMBER FUNCTIONS:
public tp2c, tp2d, xtp, xtpv, fxppm, xmist, steepx, lmppm
public huynh, ytp, ymist, fyppm, tpcc, ycc
!
! !DESCRIPTION:
!
! This module provides
!
! \begin{tabular}{|l|l|} \hline \hline
! tp2c & \\ \hline
! tp2d & \\ \hline
! xtp & \\ \hline
! fxppm & \\ \hline
! xmist & \\ \hline
! steepx & \\ \hline
! lmppm & \\ \hline
! huynh & \\ \hline
! ytp & \\ \hline
! ymist & \\ \hline
! fyppm & \\ \hline
! tpcc & \\ \hline
! ycc & \\ \hline
! \hline
! \end{tabular}
!
! !REVISION HISTORY:
! 01.01.15 Lin Routines coalesced into this module
! 01.03.26 Sawyer Additional ProTeX documentation
! 03.11.19 Sawyer Merged in CAM changes by Mirin
! 04.10.07 Sawyer ompinner now from dynamics_vars
! 05.03.25 Todling shr_kind_r8 can only be referenced once (MIPSpro-7.4.2)
! 05.05.25 Sawyer Merged CAM and GEOS5 versions (mostly CAM)
! 06.09.06 Sawyer Turned "magic numbers" into F90 parameters
!
!EOP
!-----------------------------------------------------------------------
! Magic numbers used in this module
private
real(r8), parameter :: D0_0 = 0.0_r8
real(r8), parameter :: D0_05 = 0.05_r8
real(r8), parameter :: D0_25 = 0.25_r8
real(r8), parameter :: D0_5 = 0.5_r8
real(r8), parameter :: D1_0 = 1.0_r8
real(r8), parameter :: D2_0 = 2.0_r8
real(r8), parameter :: D3_0 = 3.0_r8
real(r8), parameter :: D4_0 = 4.0_r8
real(r8), parameter :: D8_0 = 8.0_r8
real(r8), parameter :: D12_0 = 12.0_r8
real(r8), parameter :: D24_0 = 24.0_r8
CONTAINS
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: tp2c --- Perform transport on a C grid
!
! !INTERFACE:
subroutine tp2c(dh, va, h, crx, cry, im, jm, & 5,1
iord, jord, ng, fx, fy, ffsl, &
rcap, acosp, xfx, yfx, cosp, id, jfirst, jlast)
!-----------------------------------------------------------------------
implicit none
! !INPUT PARAMETERS:
integer im, jm ! Dimensions
integer jfirst, jlast ! Latitude strip
integer iord, jord ! Interpolation order in x,y
integer ng ! Max. NS dependencies
integer id ! density (0) (mfx = C)
real (r8) rcap ! Ask S.-J. (polar constant?)
real (r8) acosp(jm) ! Ask S.-J. (difference to cosp??)
logical ffsl(jm) ! Use flux-form semi-Lagrangian trans.?
! (N*NG S*NG)
real (r8) cosp(jm) ! Critical angle
real (r8) va(im,jfirst:jlast) ! Courant (unghosted)
real (r8) h(im,jfirst-ng:jlast+ng) ! Pressure ( N*NG S*NG )
real (r8) crx(im,jfirst-ng:jlast+ng) ! Ask S.-J. ( N*NG S*NG )
real (r8) cry(im,jfirst:jlast+1) ! Ask S.-J. ( N like FY )
real (r8) xfx(im,jfirst:jlast) ! Ask S.-J. ( unghosted like FX )
real (r8) yfx(im,jfirst:jlast+1) ! Ask S.-J. ( N like FY )
! !OUTPUT PARAMETERS:
real (r8) dh(im,jfirst:jlast) ! Ask S.-J. ( unghosted )
real (r8) fx(im,jfirst:jlast) ! Flux in x ( unghosted )
real (r8) fy(im,jfirst:jlast+1) ! Flux in y ( N, see tp2c )
! !DESCRIPTION:
! Perform transport on a C grid. The number of ghost
! latitudes (NG) depends on what method (JORD) will be used
! subsequentally. NG is equal to MIN(ABS(JORD),3).
! Ask S.-J. how exactly this differs from TP2C.
!
! !REVISION HISTORY:
!
!EOP
!-----------------------------------------------------------------------
!BOC
integer i, j, js2g0, jn2g0
real (r8) sum1
js2g0 = max(2,jfirst) ! No ghosting
jn2g0 = min(jm-1,jlast) ! No ghosting
call tp2d
(va, h, crx, cry, im, jm, iord, jord, ng,fx, fy, ffsl, &
xfx, yfx, cosp, id, jfirst, jlast)
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js2g0,jn2g0
do i=1,im-1
dh(i,j) = fx(i,j) - fx(i+1,j) + (fy(i,j)-fy(i,j+1))*acosp(j)
enddo
dh(im,j) = fx(im,j) - fx(1,j) + (fy(im,j)-fy(im,j+1))*acosp(j)
enddo
! Poles
if ( jfirst == 1 ) then
! sum1 = - SUM( fy(1:im, 2) ) * rcap
sum1 = D0_0
do i=1,im
sum1 = sum1 + fy(i,2)
enddo
sum1 = -sum1*rcap
do i=1,im
dh(i, 1) = sum1
enddo
endif
if ( jlast == jm ) then
! sum1 = SUM( fy(1:im,jm) ) * rcap
sum1 = D0_0
do i=1,im
sum1 = sum1 + fy(i,jm)
enddo
sum1 = sum1*rcap
do i=1,im
dh(i,jm) = sum1
enddo
endif
return
!EOC
end subroutine tp2c
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: tp2d --- Perform transport on a D grid
!
! !INTERFACE:
subroutine tp2d(va, q, crx, cry, im, jm, iord, jord, ng, fx, fy, & 2,3
ffsl, xfx, yfx, cosp, id, jfirst, jlast)
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im, jm ! Dimensions
integer jfirst, jlast ! Latitude strip
integer iord, jord ! Interpolation order in x,y
integer ng ! Max. NS dependencies
integer id ! density (0) (mfx = C)
! mixing ratio (1) (mfx = mass flux)
logical ffsl(jm) ! Use flux-form semi-Lagrangian trans.?
! ghosted N*ng S*ng
real (r8) cosp(jm) ! Critical angle
real (r8) va(im,jfirst:jlast) ! Courant (unghosted)
real (r8) q(im,jfirst-ng:jlast+ng) ! transported scalar ( N*NG S*NG )
real (r8) crx(im,jfirst-ng:jlast+ng) ! Ask S.-J. ( N*NG S*NG )
real (r8) cry(im,jfirst:jlast+1) ! Ask S.-J. ( N like FY )
real (r8) xfx(im,jfirst:jlast) ! Ask S.-J. ( unghosted like FX )
real (r8) yfx(im,jfirst:jlast+1) ! Ask S.-J. ( N like FY )
! !OUTPUT PARAMETERS:
real (r8) fx(im,jfirst:jlast) ! Flux in x ( unghosted )
real (r8) fy(im,jfirst:jlast+1) ! Flux in y ( N, see tp2c )
! !DESCRIPTION:
! Perform transport on a D grid. The number of ghost
! latitudes (NG) depends on what method (JORD) will be used
! subsequentally. NG is equal to MIN(ABS(JORD),3).
!
!
! !REVISION HISTORY:
! WS 99.04.13: Added jfirst:jlast concept
! 99.04.21: Removed j1 and j2 (j1=2, j2=jm-1 consistently)
! 99.04.27: Removed dc, wk2 as arguments (local to YTP)
! 99.04.27: Removed adx as arguments (local here)
! SJL 99.07.26: ffsl flag added
! WS 99.09.07: Restructuring, cleaning, documentation
! WS 99.10.22: NG now argument; arrays pruned
! WS 00.05.14: Renamed ghost indices as per Kevin's definitions
!
!EOP
!---------------------------------------------------------------------
!BOC
! Local:
integer i, j, iad, jp, js2g0, js2gng, jn2g0, jn2gng
real (r8) adx(im,jfirst-ng:jlast+ng)
real (r8) wk1v(im,jfirst-ng:jlast+ng)
real (r8) dm(-im/3:im+im/3)
real (r8) qtmpv(-im/3:im+im/3,jfirst-ng:jlast+ng)
real (r8) al(-im/3:im+im/3)
real (r8) ar(-im/3:im+im/3)
real (r8) a6(-im/3:im+im/3)
! Number of ghost latitudes
js2g0 = max(2,jfirst) ! No ghosting
js2gng = max(2,jfirst-ng) ! Number needed on S
jn2g0 = min(jm-1,jlast) ! No ghosting
jn2gng = min(jm-1,jlast+ng) ! Number needed on N
iad = 1
call xtpv
(im, ffsl, wk1v, q, crx, iad, crx, &
cosp, 0, dm, qtmpv, al, ar, a6, &
jfirst, jlast, js2gng, jn2gng, jm, &
1, jm, jfirst-ng, jlast+ng, &
jfirst-ng, jlast+ng, jfirst-ng, jlast+ng, &
jfirst-ng, jlast+ng, jfirst-ng, jlast+ng)
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js2gng,jn2gng ! adx needed on N*ng S*ng
do i=1,im-1
adx(i,j) = q(i,j) + D0_5 * &
(wk1v(i,j)-wk1v(i+1,j) + q(i,j)*(crx(i+1,j)-crx(i,j)))
enddo
adx(im,j) = q(im,j) + D0_5 * &
(wk1v(im,j)-wk1v(1,j) + q(im,j)*(crx(1,j)-crx(im,j)))
enddo
! WS 99.09.07 : Split up north and south pole
if ( jfirst-ng <= 1 ) then
do i=1,im
adx(i, 1) = q(i,1)
enddo
endif
if ( jlast+ng >= jm ) then
do i=1,im
adx(i,jm) = q(i,jm)
enddo
endif
call ytp
(im,jm,fy, adx,cry,yfx,ng,jord,0,jfirst,jlast)
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,jp)
#endif
do j=js2g0,jn2g0
do i=1,im
jp = j-va(i,j)
wk1v(i,j) = q(i,j) +D0_5*va(i,j)*(q(i,jp)-q(i,jp+1))
enddo
enddo
call xtpv
(im, ffsl, fx, wk1v, crx, iord, xfx, &
cosp, id, dm, qtmpv, al, ar, a6, &
jfirst, jlast, js2g0, jn2g0, jm, &
1, jm, jfirst, jlast, &
jfirst-ng, jlast+ng, jfirst-ng, jlast+ng, &
jfirst, jlast, jfirst-ng, jlast+ng)
return
!EOC
end subroutine tp2d
!-----------------------------------------------------------------------
#ifndef VECTORIZE
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: xtpv
!
! !INTERFACE:
subroutine xtpv(im, ffslv, fxv, qv, cv, iord, mfxv, & 6,6
cosav, id, dmw, qtmpv, alw, arw, a6w, &
jfirst, jlast, jlow, jhigh, jm, &
jl2, jh2, jl3, jh3, &
jl4, jh4, jl5, jh5, &
jl7, jh7, jl11, jh11)
!-----------------------------------------------------------------------
implicit none
! !INPUT PARAMETERS:
integer id ! ID = 0: density (mfx = C)
! ID = 1: mixing ratio (mfx is mass flux)
integer im ! Total longitudes
integer iord
integer jfirst, jlast, jlow, jhigh, jm
integer jl2, jh2, jl3, jh3, jl4, jh4, jl5, jh5
integer jl7, jh7, jl11, jh11
real (r8) cv(im,jl5:jh5) ! Courant numbers
real (r8) qv(im,jl4:jh4)
real (r8) mfxv(im,jl7:jh7)
logical ffslv(jl2:jh2)
real (r8) cosav(jm)
! !INPUT/OUTPUT PARAMETERS:
real (r8) qtmpv(-im/3:im+im/3,jl11:jh11) ! Input work arrays:
real (r8) dmw(-im/3:im+im/3)
real (r8) alw(-im/3:im+im/3)
real (r8) arw(-im/3:im+im/3)
real (r8) a6w(-im/3:im+im/3)
! !OUTPUT PARAMETERS:
real (r8) fxv(im,jl3:jh3)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
! Local:
real (r8) cos_upw !critical cosine for upwind
real (r8) cos_van !critical cosine for van Leer
real (r8) cos_ppm !critical cosine for ppm
parameter (cos_upw = D0_05) !roughly at 87 deg.
parameter (cos_van = D0_25) !roughly at 75 deg.
parameter (cos_ppm = D0_25)
integer i, imp, j
real (r8) qmax, qmin
real (r8) rut, tmp
integer iu, itmp, ist
integer isave(im)
integer iuw, iue
real (r8) dm(-im/3:im+im/3)
real (r8) al(-im/3:im+im/3)
real (r8) ar(-im/3:im+im/3)
real (r8) a6(-im/3:im+im/3)
imp = im + 1
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,iuw,iue,iu,itmp,isave,tmp,qmax,qmin,dm,rut,ist,al,ar,a6)
#endif
do j = jlow, jhigh
do i=1,im
qtmpv(i,j) = qv(i,j)
enddo
if( ffslv(j) ) then
! Flux-Form Semi-Lagrangian transport
! Figure out ghost zone for the western edge:
iuw = -cv(1,j)
iuw = min(0, iuw)
do i=iuw, 0
qtmpv(i,j) = qv(im+i,j)
enddo
! Figure out ghost zone for the eastern edge:
iue = im - cv(im,j)
iue = max(imp, iue)
do i=imp, iue
qtmpv(i,j) = qv(i-im,j)
enddo
if( iord == 1 .or. cosav(j) < cos_upw) then
do i=1,im
iu = cv(i,j)
if(cv(i,j) .le. D0_0) then
itmp = i - iu
isave(i) = itmp - 1
else
itmp = i - iu - 1
isave(i) = itmp + 1
endif
fxv(i,j) = (cv(i,j)-iu) * qtmpv(itmp,j)
enddo
else
do i=1,im
! 2nd order slope
tmp = D0_25*(qtmpv(i+1,j) - qtmpv(i-1,j))
qmax = max(qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j)) - qtmpv(i,j)
qmin = qtmpv(i,j) - min(qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j))
dm(i) = sign(min(abs(tmp),qmax,qmin), tmp)
enddo
do i=iuw, 0
dm(i) = dm(im+i)
enddo
do i=imp, iue
dm(i) = dm(i-im)
enddo
if(iord .ge. 3 .and. cosav(j) .gt. cos_ppm) then
call fxppm
(im, cv(:,j), mfxv(:,j), qtmpv(:,j), dm, fxv(:,j), iord, al, ar, a6, &
iuw, iue, ffslv(j), isave)
else
do i=1,im
iu = cv(i,j)
rut = cv(i,j) - iu
if(cv(i,j) .le. D0_0) then
itmp = i - iu
isave(i) = itmp - 1
fxv(i,j) = rut*(qtmpv(itmp,j)-dm(itmp)*(D1_0+rut))
else
itmp = i - iu - 1
isave(i) = itmp + 1
fxv(i,j) = rut*(qtmpv(itmp,j)+dm(itmp)*(D1_0-rut))
endif
enddo
endif
endif
do i=1,im
if(cv(i,j) .ge. D1_0) then
do ist = isave(i),i-1
fxv(i,j) = fxv(i,j) + qtmpv(ist,j)
enddo
elseif(cv(i,j) .le. -D1_0) then
do ist = i,isave(i)
fxv(i,j) = fxv(i,j) - qtmpv(ist,j)
enddo
endif
enddo
if(id .ne. 0) then
do i=1,im
fxv(i,j) = fxv(i,j)*mfxv(i,j)
enddo
endif
else
! Regular PPM (Eulerian without FFSL extension)
qtmpv(imp,j) = qv(1,j)
qtmpv( 0,j) = qv(im,j)
if(iord == 1 .or. cosav(j) < cos_upw) then
do i=1,im
iu = real(i,r8) - cv(i,j)
fxv(i,j) = mfxv(i,j)*qtmpv(iu,j)
enddo
else
qtmpv(-1,j) = qv(im-1,j)
qtmpv(imp+1,j) = qv(2,j)
if(iord > 0 .or. cosav(j) < cos_van) then
call xmist
(im, qtmpv(:,j), dm, 2)
else
call xmist
(im, qtmpv(:,j), dm, iord)
endif
dm(0) = dm(im)
if( abs(iord).eq.2 .or. cosav(j) .lt. cos_van ) then
do i=1,im
iu = real(i,r8) - cv(i,j)
fxv(i,j) = mfxv(i,j)*(qtmpv(iu,j)+dm(iu)*(sign(D1_0,cv(i,j))-cv(i,j)))
! if(cv(i,j) .le. 0.) then
! fxv(i,j) = qtmpv(i,j) - dm(i)*(1.+cv(i,j))
! else
! fxv(i,j) = qtmpv(i-1,j) + dm(i-1)*(1.-cv(i,j))
! endif
! fxv(i,j) = fxv(i,j)*mfxv(i,j)
enddo
else
call fxppm
(im, cv(:,j), mfxv(:,j), qtmpv(:,j), dm, fxv(:,j), iord, al, ar, a6, &
iuw, iue, ffslv(j), isave)
endif
endif
endif
enddo
return
!EOC
end subroutine xtpv
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: xmist
!
! !INTERFACE:
subroutine xmist(im, q, dm, id) 2
!-----------------------------------------------------------------------
implicit none
! !INPUT PARAMETERS:
integer im ! Total number of longitudes
integer id ! ID = 0: density (mfx = C)
! ID = 1: mixing ratio (mfx is mass flux)
real(r8) q(-im/3:im+im/3) ! Input latitude
! !OUTPUT PARAMETERS:
real(r8) dm(-im/3:im+im/3) !
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
real(r8) r24
parameter( r24 = D1_0/D24_0)
integer i
real(r8) qmin, qmax
if(id .le. 2) then
do i=1,im
dm(i) = r24*(D8_0*(q(i+1) - q(i-1)) + q(i-2) - q(i+2))
enddo
else
do i=1,im
dm(i) = D0_25*(q(i+1) - q(i-1))
enddo
endif
if( id < 0 ) return
! Apply monotonicity constraint (Lin et al. 1994, MWR)
do i=1,im
qmax = max( q(i-1), q(i), q(i+1) ) - q(i)
qmin = q(i) - min( q(i-1), q(i), q(i+1) )
dm(i) = sign( min(abs(dm(i)), qmax, qmin), dm(i) )
enddo
return
!EOC
end subroutine xmist
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: fxppm
!
! !INTERFACE:
subroutine fxppm(im, c, mfx, p, dm, fx, iord, al, ar, a6, & 2,3
iuw, iue, ffsl, isave)
!-----------------------------------------------------------------------
!
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im, iord
real (r8) c(im)
real (r8) p(-im/3:im+im/3)
real (r8) dm(-im/3:im+im/3)
real (r8) mfx(im)
integer iuw, iue
logical ffsl
integer isave(im)
! !INPUT/OUTPUT PARAMETERS:
real (r8) al(-im/3:im+im/3)
real (r8) ar(-im/3:im+im/3)
real (r8) a6(-im/3:im+im/3)
! !OUTPUT PARAMETERS:
real (r8) fx(im)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
real (r8) r3, r23
parameter ( r3 = D1_0/D3_0, r23 = D2_0/D3_0 )
integer i, lmt
integer iu, itmp
real (r8) ru
logical steep
if( iord == 6 ) then
steep = .true.
else
steep = .false.
endif
do i=1,im
al(i) = D0_5*(p(i-1)+p(i)) + (dm(i-1) - dm(i))*r3
enddo
if( steep ) call steepx
( im, p, al(1), dm )
do i=1,im-1
ar(i) = al(i+1)
enddo
ar(im) = al(1)
if(iord == 7) then
call huynh
(im, ar(1), al(1), p(1), a6(1), dm(1))
else
if(iord .eq. 3 .or. iord .eq. 5) then
do i=1,im
a6(i) = D3_0*(p(i)+p(i) - (al(i)+ar(i)))
enddo
endif
lmt = iord - 3
call lmppm
( dm(1), a6(1), ar(1), al(1), p(1), im, lmt )
endif
if( ffsl ) then
do i=iuw, 0
al(i) = al(im+i)
ar(i) = ar(im+i)
a6(i) = a6(im+i)
enddo
do i=im+1, iue
al(i) = al(i-im)
ar(i) = ar(i-im)
a6(i) = a6(i-im)
enddo
do i=1,im
iu = c(i)
ru = c(i) - iu
if(c(i) .gt. D0_0) then
itmp = i - iu - 1
isave(i) = itmp + 1
fx(i) = ru*(ar(itmp)+D0_5*ru*(al(itmp)-ar(itmp) + &
a6(itmp)*(D1_0-r23*ru)) )
else
itmp = i - iu
isave(i) = itmp - 1
fx(i) = ru*(al(itmp)-D0_5*ru*(ar(itmp)-al(itmp) + &
a6(itmp)*(D1_0+r23*ru)) )
endif
enddo
else
al(0) = al(im)
ar(0) = ar(im)
a6(0) = a6(im)
do i=1,im
if(c(i) .gt. D0_0) then
fx(i) = ar(i-1) + D0_5*c(i)*(al(i-1) - ar(i-1) + &
a6(i-1)*(D1_0-r23*c(i)) )
else
fx(i) = al(i) - D0_5*c(i)*(ar(i) - al(i) + &
a6(i)*(D1_0+r23*c(i)))
endif
fx(i) = mfx(i) * fx(i)
enddo
endif
return
!EOC
end subroutine fxppm
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: steepx
!
! !INTERFACE:
subroutine steepx(im, p, al, dm) 1
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im
real (r8) p(-im/3:im+im/3)
real (r8) dm(-im/3:im+im/3)
! !INPUT/OUTPUT PARAMETERS:
real (r8) al(im)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
integer i
real (r8) r3
parameter ( r3 = D1_0/D3_0 )
real (r8) dh(0:im)
real (r8) d2(0:im+1)
real (r8) eta(0:im)
real (r8) xxx, bbb, ccc
do i=0,im
dh(i) = p(i+1) - p(i)
enddo
! Needs dh(0:im)
do i=1,im
d2(i) = dh(i) - dh(i-1)
enddo
d2(0) = d2(im)
d2(im+1) = d2(1)
! needs p(-1:im+2), d2(0:im+1)
do i=1,im
if( d2(i+1)*d2(i-1).lt.D0_0 .and. p(i+1).ne.p(i-1) ) then
xxx = D1_0 - D0_5 * ( p(i+2) - p(i-2) ) / ( p(i+1) - p(i-1) )
eta(i) = max(D0_0, min(xxx, D0_5) )
else
eta(i) = D0_0
endif
enddo
eta(0) = eta(im)
! needs eta(0:im), dh(0:im-1), dm(0:im)
do i=1,im
bbb = ( D2_0*eta(i ) - eta(i-1) ) * dm(i-1)
ccc = ( D2_0*eta(i-1) - eta(i ) ) * dm(i )
al(i) = al(i) + D0_5*( eta(i-1) - eta(i)) * dh(i-1) + (bbb - ccc) * r3
enddo
return
!EOC
end subroutine steepx
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: lmppm
!
! !INTERFACE:
subroutine lmppm(dm, a6, ar, al, p, im, lmt) 2
!-----------------------------------------------------------------------
implicit none
! !INPUT PARAMETERS:
integer im ! Total longitudes
integer lmt ! LMT = 0: full monotonicity
! LMT = 1: Improved and simplified full monotonic constraint
! LMT = 2: positive-definite constraint
! LMT = 3: Quasi-monotone constraint
real(r8) p(im)
real(r8) dm(im)
! !OUTPUT PARAMETERS:
real(r8) a6(im)
real(r8) ar(im)
real(r8) al(im)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
real (r8) r12
parameter ( r12 = D1_0/D12_0 )
real (r8) da1, da2, fmin, a6da
real (r8) dr, dl
integer i
! LMT = 0: full monotonicity
! LMT = 1: Improved and simplified full monotonic constraint
! LMT = 2: positive-definite constraint
! LMT = 3: Quasi-monotone constraint
if( lmt == 0 ) then
! Full constraint
do i=1,im
if(dm(i) .eq. D0_0) then
ar(i) = p(i)
al(i) = p(i)
a6(i) = D0_0
else
da1 = ar(i) - al(i)
da2 = da1**2
a6da = a6(i)*da1
if(a6da .lt. -da2) then
a6(i) = D3_0*(al(i)-p(i))
ar(i) = al(i) - a6(i)
elseif(a6da .gt. da2) then
a6(i) = D3_0*(ar(i)-p(i))
al(i) = ar(i) - a6(i)
endif
endif
enddo
elseif( lmt == 1 ) then
! Improved (Lin 2001?) full constraint
do i=1,im
da1 = dm(i) + dm(i)
dl = sign(min(abs(da1),abs(al(i)-p(i))), da1)
dr = sign(min(abs(da1),abs(ar(i)-p(i))), da1)
ar(i) = p(i) + dr
al(i) = p(i) - dl
a6(i) = D3_0*(dl-dr)
enddo
elseif( lmt == 2 ) then
! Positive definite constraint
do 250 i=1,im
if(abs(ar(i)-al(i)) .ge. -a6(i)) go to 250
fmin = p(i) + D0_25*(ar(i)-al(i))**2/a6(i) + a6(i)*r12
if(fmin.ge.D0_0) go to 250
if(p(i).lt.ar(i) .and. p(i).lt.al(i)) then
ar(i) = p(i)
al(i) = p(i)
a6(i) = D0_0
elseif(ar(i) .gt. al(i)) then
a6(i) = D3_0*(al(i)-p(i))
ar(i) = al(i) - a6(i)
else
a6(i) = D3_0*(ar(i)-p(i))
al(i) = ar(i) - a6(i)
endif
250 continue
elseif(lmt .eq. 3) then
! Quasi-monotone constraint
do i=1,im
da1 = D4_0*dm(i)
dl = sign(min(abs(da1),abs(al(i)-p(i))), da1)
dr = sign(min(abs(da1),abs(ar(i)-p(i))), da1)
ar(i) = p(i) + dr
al(i) = p(i) - dl
a6(i) = D3_0*(dl-dr)
enddo
endif
return
!EOC
end subroutine lmppm
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: huynh --- Enforce Huynh's 2nd constraint in 1D periodic domain
!
! !INTERFACE:
subroutine huynh(im, ar, al, p, d2, d1) 1
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im
real(r8) p(im)
! !OUTPUT PARAMETERS:
real(r8) ar(im)
real(r8) al(im)
real(r8) d2(im)
real(r8) d1(im)
! !DESCRIPTION:
!
! Enforce Huynh's 2nd constraint in 1D periodic domain
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
integer i
real(r8) pmp
real(r8) lac
real(r8) pmin
real(r8) pmax
! Compute d1 and d2
d1(1) = p(1) - p(im)
do i=2,im
d1(i) = p(i) - p(i-1)
enddo
do i=1,im-1
d2(i) = d1(i+1) - d1(i)
enddo
d2(im) = d1(1) - d1(im)
! Constraint for AR
! i = 1
pmp = p(1) + D2_0 * d1(1)
lac = p(1) + D0_5 * (d1(1)+d2(im)) + d2(im)
pmin = min(p(1), pmp, lac)
pmax = max(p(1), pmp, lac)
ar(1) = min(pmax, max(ar(1), pmin))
do i=2, im
pmp = p(i) + D2_0*d1(i)
lac = p(i) + D0_5*(d1(i)+d2(i-1)) + d2(i-1)
pmin = min(p(i), pmp, lac)
pmax = max(p(i), pmp, lac)
ar(i) = min(pmax, max(ar(i), pmin))
enddo
! Constraint for AL
do i=1, im-1
pmp = p(i) - D2_0*d1(i+1)
lac = p(i) + D0_5*(d2(i+1)-d1(i+1)) + d2(i+1)
pmin = min(p(i), pmp, lac)
pmax = max(p(i), pmp, lac)
al(i) = min(pmax, max(al(i), pmin))
enddo
! i=im
i = im
pmp = p(im) - D2_0*d1(1)
lac = p(im) + D0_5*(d2(1)-d1(1)) + d2(1)
pmin = min(p(im), pmp, lac)
pmax = max(p(im), pmp, lac)
al(im) = min(pmax, max(al(im), pmin))
! compute A6 (d2)
do i=1, im
d2(i) = D3_0*(p(i)+p(i) - (al(i)+ar(i)))
enddo
return
!EOC
end subroutine huynh
!-----------------------------------------------------------------------
#endif
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: ytp
!
! !INTERFACE:
subroutine ytp(im, jm, fy, q, c, yfx, ng, jord, iv, jfirst, jlast) 2,2
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im, jm ! Dimensions
integer jfirst, jlast ! Latitude strip
integer ng ! Max. NS dependencies
integer jord ! order of subgrid dist
integer iv ! Scalar=0, Vector=1
real (r8) q(im,jfirst-ng:jlast+ng) ! advected scalar N*jord S*jord
real (r8) c(im,jfirst:jlast+1) ! Courant N (like FY)
real (r8) yfx(im,jfirst:jlast+1) ! Backgrond mass flux
! !OUTPUT PARAMETERS:
real (r8) fy(im,jfirst:jlast+1) ! Flux N (see tp2c)
! !DESCRIPTION:
! This routine calculates the flux FX. The method chosen
! depends on the order of the calculation JORD (currently
! 1, 2 or 3).
!
! !CALLED FROM:
! cd_core
! tp2d
!
! !REVISION HISTORY:
!
! SJL 99.04.13: Delivery
! WS 99.04.13: Added jfirst:jlast concept
! WS 99.04.21: Removed j1 and j2 (j1=2, j2=jm-1 consistently)
! removed a6,ar,al from argument list
! WS 99.04.27: DM made local to this routine
! WS 99.09.09: Documentation; indentation; cleaning
! WS 99.10.22: Added NG as argument; pruned arrays
! SJL 99.12.24: Revised documentation; optimized for better cache usage
! WS 00.05.14: Renamed ghost indices as per Kevin's definitions
!
!EOP
!---------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
integer i, j, jt
integer js2g0, jn1g1
! work arrays (should pass in eventually for performance enhancement):
real (r8) dm(im,jfirst-ng:jlast+ng)
! real (r8) ar(im,jfirst-1:jlast+1) ! AR needs to be ghosted on NS
! real (r8) al(im,jfirst-1:jlast+2) ! AL needs to be ghosted on N2S
! real (r8) a6(im,jfirst-1:jlast+1) ! A6 needs to be ghosted on NS
js2g0 = max(2,jfirst) ! No ghosting
jn1g1 = min(jm,jlast+1) ! Ghost N*1
if(jord == 1) then
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,jt)
#endif
do j=js2g0,jn1g1
do i=1,im
jt = real(j,r8) - c(i,j)
fy(i,j) = q(i,jt)
enddo
enddo
else
!
! YMIST requires q on NS; Only call to YMIST here
!
call ymist
(im, jm, q, dm, ng, jord, iv, jfirst, jlast)
if( abs(jord) .ge. 3 ) then
call fyppm
(c,q,dm,fy,im,jm,ng,jord,iv,jfirst,jlast)
else
!
! JORD can either have the value 2 or -2 at this point
!
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,jt)
#endif
do j=js2g0,jn1g1
do i=1,im
jt = real(j,r8) - c(i,j)
fy(i,j) = q(i,jt) + (sign(D1_0,c(i,j))-c(i,j))*dm(i,jt)
enddo
enddo
endif
endif
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js2g0,jn1g1
do i=1,im
fy(i,j) = fy(i,j)*yfx(i,j)
enddo
enddo
return
!EOC
end subroutine ytp
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: ymist
!
! !INTERFACE:
subroutine ymist(im, jm, q, dm, ng, jord, iv, jfirst, jlast) 1
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im, jm ! Dimensions
integer jfirst, jlast ! Latitude strip
integer ng ! NS dependencies
integer jord ! order of subgrid distribution
integer iv ! Scalar (==0) Vector (==1)
real (r8) q(im,jfirst-ng:jlast+ng) ! transported scalar N*ng S*ng
! !OUTPUT PARAMETERS:
real (r8) dm(im,jfirst-ng:jlast+ng) ! Slope only N*(ng-1) S*(ng-1) used
! !DESCRIPTION:
! Calculate the slope of the pressure. The number of ghost
! latitudes (NG) depends on what method (JORD) will be used
! subsequentally. NG is equal to MIN(ABS(JORD),3).
!
! !CALLED FROM:
! ytp
!
! !REVISION HISTORY:
!
! SJL 99.04.13: Delivery
! WS 99.04.13: Added jfirst:jlast concept
! WS 99.09.09: Documentation; indentation; cleaning
! SJL 00.01.06: Documentation
! WS 00.05.14: Renamed ghost indices as per Kevin's definitions
!
!EOP
!---------------------------------------------------------------------
!BOC
! Local variables
integer i, j, jm1, im2, js2gng1, jn2gng1
real (r8) qmax, qmin, tmp
js2gng1 = max(2, jfirst-ng+1) ! Number needed on S
jn2gng1 = min(jm-1,jlast+ng-1) ! Number needed on N
jm1 = jm - 1
im2 = im / 2
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js2gng1,jn2gng1
do i=1,im
dm(i,j) = D0_25*(q(i,j+1) - q(i,j-1))
enddo
enddo
if( iv == 0 ) then
if ( jfirst-ng <= 1 ) then
! S pole
do i=1,im2
tmp = D0_25*(q(i,2)-q(i+im2,2))
qmax = max(q(i,2),q(i,1), q(i+im2,2)) - q(i,1)
qmin = q(i,1) - min(q(i,2),q(i,1), q(i+im2,2))
dm(i,1) = sign(min(abs(tmp),qmax,qmin),tmp)
enddo
do i=im2+1,im
dm(i, 1) = - dm(i-im2, 1)
enddo
endif
if ( jlast+ng >= jm ) then
! N pole
do i=1,im2
tmp = D0_25*(q(i+im2,jm1)-q(i,jm1))
qmax = max(q(i+im2,jm1),q(i,jm), q(i,jm1)) - q(i,jm)
qmin = q(i,jm) - min(q(i+im2,jm1),q(i,jm), q(i,jm1))
dm(i,jm) = sign(min(abs(tmp),qmax,qmin),tmp)
enddo
do i=im2+1,im
dm(i,jm) = - dm(i-im2,jm)
enddo
endif
else
if ( jfirst-ng <= 1 ) then
! South
do i=1,im2
tmp = D0_25*(q(i,2)+q(i+im2,2))
qmax = max(q(i,2),q(i,1), -q(i+im2,2)) - q(i,1)
qmin = q(i,1) - min(q(i,2),q(i,1),-q(i+im2,2))
dm(i,1) = sign(min(abs(tmp),qmax,qmin),tmp)
enddo
do i=im2+1,im
dm(i, 1) = dm(i-im2, 1)
enddo
endif
if ( jlast+ng >= jm ) then
! North
do i=1,im2
tmp = -D0_25*(q(i+im2,jm1)+q(i,jm1))
qmax = max(-q(i+im2,jm1),q(i,jm), q(i,jm1)) - q(i,jm)
qmin = q(i,jm) - min(-q(i+im2,jm1),q(i,jm), q(i,jm1))
dm(i,jm) = sign(min(abs(tmp),qmax,qmin),tmp)
enddo
do i=im2+1,im
dm(i,jm) = dm(i-im2,jm)
enddo
endif
endif
if( jord > 0 ) then
!
! Applies monotonic slope constraint (off if jord less than zero)
!
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,qmax,qmin)
#endif
do j=js2gng1,jn2gng1
do i=1,im
qmax = max(q(i,j-1),q(i,j),q(i,j+1)) - q(i,j)
qmin = q(i,j) - min(q(i,j-1),q(i,j),q(i,j+1))
dm(i,j) = sign(min(abs(dm(i,j)),qmin,qmax),dm(i,j))
enddo
enddo
endif
return
!EOC
end subroutine ymist
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: fyppm
!
! !INTERFACE:
subroutine fyppm(c, q, dm, flux, im, jm, ng, jord, iv, jfirst, jlast) 1,2
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im, jm ! Dimensions
integer jfirst, jlast ! Latitude strip
integer ng ! Max. NS dependencies
integer jord ! Approximation order
integer iv ! Scalar=0, Vector=1
real (r8) q(im,jfirst-ng:jlast+ng) ! mean value needed only N*2 S*2
real (r8) dm(im,jfirst-ng:jlast+ng) ! Slope needed only N*2 S*2
real (r8) c(im,jfirst:jlast+1) ! Courant N (like FLUX)
! !INPUT/OUTPUT PARAMETERS:
real (r8) ar(im,jfirst-1:jlast+1) ! AR needs to be ghosted on NS
real (r8) al(im,jfirst-1:jlast+2) ! AL needs to be ghosted on N2S
real (r8) a6(im,jfirst-1:jlast+1) ! A6 needs to be ghosted on NS
! !OUTPUT PARAMETERS:
real (r8) flux(im,jfirst:jlast+1) ! Flux N (see tp2c)
! !DESCRIPTION:
!
! NG is passed from YTP for convenience -- it is actually 1 more in NS
! than the actual number of latitudes needed here. But in the shared-memory
! case it becomes 0, which is much cleaner.
!
! !CALLED FROM:
! ytp
!
! !REVISION HISTORY:
!
! SJL 99.04.13: Delivery
! WS 99.04.19: Added jfirst:jlast concept; FYPPM only called from YTP
! WS 99.04.21: Removed j1, j2 (j1=2, j2=jm-1 consistently)
! removed a6,ar,al from argument list
! WS 99.09.09: Documentation; indentation; cleaning
! WS 99.10.22: Added ng as argument; Pruned arrays
! WS 00.05.14: Renamed ghost indices as per Kevin's definitions
!
!EOP
!---------------------------------------------------------------------
!BOC
real (r8) r3, r23
parameter ( r3 = D1_0/D3_0, r23 = D2_0/D3_0 )
integer i, j, imh, jm1, lmt
integer js1g1, js2g0, js2g1, jn1g2, jn1g1, jn2g1
integer jan, jlow, jhigh, ilow, ihigh
integer ja(jlast-jfirst+3)
! logical steep
! if(jord .eq. 6) then
! steep = .true.
! else
! steep = .false.
! endif
imh = im / 2
jm1 = jm - 1
js1g1 = max(1,jfirst-1) ! Ghost S*1
js2g0 = max(2,jfirst) ! No ghosting
js2g1 = max(2,jfirst-1) ! Ghost S*1
jn1g1 = min(jm,jlast+1) ! Ghost N*1
jn1g2 = min(jm,jlast+2) ! Ghost N*2
jn2g1 = min(jm-1,jlast+1) ! Ghost N*1
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js2g1,jn1g2 ! AL needed N2S
do i=1,im ! P, dm ghosted N2S2 (at least)
al(i,j) = D0_5*(q(i,j-1)+q(i,j)) + r3*(dm(i,j-1) - dm(i,j))
enddo
enddo
! Yeh's steepening procedure; to be implemented
! if(steep) call steepy(im, jm, jfirst, jlast, &
! ng, q, al, dm )
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js1g1,jn2g1 ! AR needed NS
do i=1,im
ar(i,j) = al(i,j+1) ! AL ghosted N2S
enddo
enddo
! WS 990726 : Added condition to decide if poles are on this processor
! Poles:
if( iv == 0 ) then
if ( jfirst == 1 ) then
do i=1,imh
al(i, 1) = al(i+imh,2)
al(i+imh,1) = al(i, 2)
enddo
endif
if ( jlast == jm ) then
do i=1,imh
ar(i, jm) = ar(i+imh,jm1)
ar(i+imh,jm) = ar(i, jm1)
enddo
endif
else
if ( jfirst == 1 ) then
do i=1,imh
al(i, 1) = -al(i+imh,2)
al(i+imh,1) = -al(i, 2)
enddo
endif
if ( jlast == jm ) then
do i=1,imh
ar(i, jm) = -ar(i+imh,jm1)
ar(i+imh,jm) = -ar(i, jm1)
enddo
endif
endif
if( jord == 3 .or. jord == 5 ) then
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js1g1,jn1g1 ! A6 needed NS
do i=1,im
a6(i,j) = D3_0*(q(i,j)+q(i,j) - (al(i,j)+ar(i,j)))
enddo
enddo
endif
lmt = jord - 3
! do j=js1g1,jn1g1 ! A6, AR, AL needed NS
! call lmppm(dm(1,j),a6(1,j),ar(1,j),al(1,j),q(1,j),im,lmt)
! enddo
#ifdef VECTORIZE
jan = 1
ja(1) = 1
ilow = 1
ihigh = im*(jn1g1-js1g1+1)
jlow = 1
jhigh = 1
call lmppmv
(dm(1,js1g1), a6(1,js1g1), ar(1,js1g1), &
al(1,js1g1), q(1,js1g1), im*(jn1g1-js1g1+1), lmt, &
jan, ja, ilow, ihigh, jlow, jhigh, jlow, jhigh)
#else
call lmppm
(dm(1,js1g1), a6(1,js1g1), ar(1,js1g1), &
al(1,js1g1), q(1,js1g1), im*(jn1g1-js1g1+1), lmt)
#endif
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js2g0,jn1g1 ! flux needed N
do i=1,im
if(c(i,j).gt.D0_0) then
flux(i,j) = ar(i,j-1) + D0_5*c(i,j)*(al(i,j-1) - ar(i,j-1) + &
a6(i,j-1)*(D1_0-r23*c(i,j)) )
else
flux(i,j) = al(i,j) - D0_5*c(i,j)*(ar(i,j) - al(i,j) + &
a6(i,j)*(D1_0+r23*c(i,j)))
endif
enddo
enddo
return
!EOC
end subroutine fyppm
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: tpcc
!
! !INTERFACE:
subroutine tpcc(va, ymass, q, crx, cry, im, jm, ng_c, ng_d, & 1,3
iord, jord, fx, fy, ffsl, cose, jfirst, jlast, &
dm, qtmp, al, ar, a6 )
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im, jm ! Dimensions
integer ng_c !
integer ng_d !
integer jfirst, jlast ! Latitude strip
integer iord, jord ! Interpolation order in x,y
logical ffsl(jm) ! Flux-form semi-Lagrangian transport?
real (r8) cose(jm) ! Critical cosine (replicated)
real (r8) va(im,jfirst:jlast) ! Courant (unghosted like FX)
real (r8) q(im,jfirst-ng_d:jlast+ng_d) !
real (r8) crx(im,jfirst-ng_c:jlast+ng_c)
real (r8) cry(im,jfirst:jlast) ! Courant # (ghosted like FY)
real (r8) ymass(im,jfirst:jlast) ! Background y-mass-flux (ghosted like FY)
! Input 1D work arrays:
real (r8) dm(-im/3:im+im/3)
real (r8) qtmp(-im/3:im+im/3)
real (r8) al(-im/3:im+im/3)
real (r8) ar(-im/3:im+im/3)
real (r8) a6(-im/3:im+im/3)
! !OUTPUT PARAMETERS:
real (r8) fx(im,jfirst:jlast) ! Flux in x (unghosted)
real (r8) fy(im,jfirst:jlast) ! Flux in y (unghosted since iv==0)
! !DESCRIPTION:
! In this routine the number
! of north ghosted latitude min(abs(jord),2), and south ghosted
! latitudes is XXXX
!
! !CALLED FROM:
! cd_core
!
! !REVISION HISTORY:
! SJL 99.04.13: Delivery
! WS 99.04.13: Added jfirst:jlast concept
! WS 99.05.10: Replaced JNP with JM, JMR with JM-1, IMR with IM
! WS 99.05.10: Removed fvcore.h and JNP, IMH, IML definitions
! WS 99.10.20: Pruned arrays
! WS 00.05.14: Renamed ghost indices as per Kevin's definitions
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
real (r8) adx(im,jfirst-1:jlast+2)
integer north, south
integer i, j, jp, im2, js2g0, js2gs, jn2g0, jn1g0, jn1gn
real (r8) wk1v(im,jfirst-1:jlast+2)
real (r8) fx1(im)
real (r8) qtmpv(-im/3:im+im/3,jfirst-1:jlast+2)
im2 = im/2
north = min(2,abs(jord)) ! north == 1 or 2
south = north-1 ! south == 0 or 1
js2g0 = max(2,jfirst)
js2gs = max(2,jfirst-south)
jn2g0 = min(jm-1,jlast)
jn1gn = min(jm,jlast+north)
jn1g0 = min(jm,jlast)
! This loop must be ghosted N*NG, S*NG
call xtpv
( im, ffsl, wk1v, q, crx, 1, crx, &
cose, 0, dm, qtmpv, al, ar, a6, &
jfirst, jlast, js2gs, jn1gn, jm, &
1, jm, jfirst-1, jlast+2, &
jfirst-ng_d, jlast+ng_d, jfirst-ng_c, jlast+ng_c, &
jfirst-ng_c, jlast+ng_c, jfirst-1, jlast+2)
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js2gs,jn1gn
do i=1,im-1
adx(i,j) = q(i,j) + D0_5 * &
(wk1v(i,j)-wk1v(i+1,j) + q(i,j)*(crx(i+1,j)-crx(i,j)))
enddo
adx(im,j) = q(im,j) + D0_5 * &
(wk1v(im,j)-wk1v(1,j) + q(im,j)*(crx(1,j)-crx(im,j)))
enddo
call ycc
(im, jm, fy, adx, cry, ymass, jord, 0,jfirst,jlast)
! For Scalar only!!!
if ( jfirst == 1 ) then ! ( jfirst -ng_d <= 1 ) fails when
! ng_d=3, ng_c=2, jlast-jfirst+1 = 3
do i=1,im2
q(i,1) = q(i+im2, 2)
enddo
do i=im2+1,im
q(i,1) = q(i-im2, 2)
enddo
endif
if ( jlast == jm ) then
do i=1,im2
fx1(i) = q(i+im2,jm)
enddo
do i=im2+1,im
fx1(i) = q(i-im2,jm)
enddo
do i=1,im
if(va(i,jm) .gt. D0_0) then
adx(i,jm) = q(i,jm) + D0_5*va(i,jm)*(q(i,jm-1)-q(i,jm))
else
adx(i,jm) = q(i,jm) + D0_5*va(i,jm)*(q(i,jm)-fx1(i))
endif
enddo
endif
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,jp)
#endif
do j=js2g0,jn2g0
do i=1,im
jp = j-va(i,j)
! jp = j if va < 0
! jp = j -1 if va < 0
! q needed max(1, jfirst-1)
adx(i,j) = q(i,j) + D0_5*va(i,j)*(q(i,jp)-q(i,jp+1))
enddo
enddo
call xtpv
( im, ffsl, fx, adx, crx, iord, crx, &
cose, 0, dm, qtmpv, al, ar, a6, &
jfirst, jlast, js2g0, jn1g0, jm, &
1, jm, jfirst, jlast, &
jfirst-1, jlast+2,jfirst-ng_c, jlast+ng_c, &
jfirst-ng_c, jlast+ng_c, jfirst-1, jlast+2)
return
!EOC
end subroutine tpcc
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: ycc
!
! !INTERFACE:
subroutine ycc(im, jm, fy, q, vc, ymass, jord, iv, jfirst, jlast) 2
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im, jm ! Dimensions
integer jfirst, jlast ! Latitude strip
integer jord ! Approximation order
integer iv ! Scalar=0, Vector=1
real (r8) q(im,jfirst-1-iv:jlast+2) ! Field (N*2 S*(iv+1))
real (r8) vc(im,jfirst-iv:jlast) ! Courant (like FY)
real (r8) ymass(im,jfirst-iv:jlast) ! background mass flux
! !OUTPUT PARAMETERS:
real (r8) fy(im,jfirst-iv:jlast) ! Flux (S if iv=1)
! !DESCRIPTION:
! Will Sawyer's note: In this routine the number
! of ghosted latitudes NG is min(abs(jord),2). The scalar/vector
! flag determines whether the flux FY needs to be ghosted on the
! south. If called from CD\_CORE (iv==1) then it does, if called
! from TPCC (iv==0) it does not.
!
! !CALLED FROM:
! cd_core
! tpcc
!
! !REVISION HISTORY:
!
! SJL 99.04.13: Delivery
! WS 99.04.19: Added jfirst:jlast concept
! WS 99.04.27: DC removed as argument (local to this routine); DC on N
! WS 99.05.10: Replaced JNP with JM, JMR with JM-1, IMR with IM
! WS 99.05.10: Removed fvcore.h
! WS 99.07.27: Built in tests for SP or NP
! WS 99.09.09: Documentation; indentation; cleaning; pole treatment
! WS 99.09.14: Loop limits
! WS 00.05.14: Renamed ghost indices as per Kevin's definitions
!
!EOP
!---------------------------------------------------------------------
!BOC
! !LOCAL VARIABLES:
real (r8) dc(im,jfirst-iv:jlast+1)
real (r8) qmax, qmin
integer i, j, jt, im2, js2giv, js3giv, jn2g1, jn2g0
im2 = im/2
js2giv = max(2,jfirst-iv)
js3giv = max(3,jfirst-iv)
jn2g1 = min(jm-1,jlast+1)
jn2g0 = min(jm-1,jlast)
if(jord == 1) then
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,jt)
#endif
do j=js2giv,jn2g0 ! FY needed on S*iv
do i=1,im
! jt=j if vc > 0; jt=j+1 if vc <=0
jt = real(j+1,r8) - vc(i,j) ! VC ghosted like fy
fy(i,j) = q(i,jt)*ymass(i,j) ! ymass ghosted like fy
enddo ! q ghosted N*1, S*iv
enddo
else
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i)
#endif
do j=js3giv,jn2g1 ! dc needed N*1, S*iv
do i=1,im
dc(i,j) = D0_25*(q(i,j+1)-q(i,j-1)) ! q ghosted N*2, S*(iv+1)
enddo
enddo
if(iv.eq.0) then
! Scalar.
! WS 99.07.27 : Split loops in SP and NP regions, added SP/NP tests
if ( jfirst-iv <= 2 ) then
do i=1,im2
dc(i, 2) = D0_25 * ( q(i,3) - q(i+im2,2) )
enddo
do i=im2+1,im
dc(i, 2) = D0_25 * ( q(i,3) - q(i-im2,2) )
enddo
endif
if ( jlast == jm ) then
do i=1,im2
dc(i,jm) = D0_25 * ( q(i+im2,jm) - q(i,jm-1) )
enddo
do i=im2+1,im
dc(i,jm) = D0_25 * ( q(i-im2,jm) - q(i,jm-1) )
enddo
endif
else
! Vector winds
! WS 99.07.27 : Split loops in SP and NP regions, added SP/NP tests
if ( jfirst-iv <= 2 ) then
do i=1,im2
dc(i, 2) = D0_25 * ( q(i,3) + q(i+im2,2) )
enddo
do i=im2+1,im
dc(i, 2) = D0_25 * ( q(i,3) + q(i-im2,2) )
enddo
endif
if ( jlast == jm ) then
do i=1,im2
dc(i,jm) = -D0_25 * ( q(i,jm-1) + q(i+im2,jm) )
enddo
do i=im2+1,im
dc(i,jm) = -D0_25 * ( q(i,jm-1) + q(i-im2,jm) )
enddo
endif
endif
if( jord > 0 ) then
! Monotonic constraint
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,qmax,qmin)
#endif
do j=js3giv,jn2g1 ! DC needed N*1, S*iv
do i=1,im ! P ghosted N*2, S*(iv+1)
qmax = max(q(i,j-1),q(i,j),q(i,j+1)) - q(i,j)
qmin = q(i,j) - min(q(i,j-1),q(i,j),q(i,j+1))
dc(i,j) = sign(min(abs(dc(i,j)),qmin,qmax),dc(i,j))
enddo
enddo
!
! WS 99.08.03 : Following loop split into SP and NP part
!
if ( jfirst-iv <= 2 ) then
do i=1,im
dc(i, 2) = D0_0
enddo
endif
if ( jlast == jm ) then
do i=1,im
dc(i,jm) = D0_0
enddo
endif
endif
#if defined(INNER_OMP)
!$omp parallel do default(shared) private(j,i,jt)
#endif
do j=js2giv,jn2g0 ! fy needed S*iv
do i=1,im
jt = real(j+1,r8) - vc(i,j) ! vc, ymass ghosted like fy
fy(i,j) = (q(i,jt)+(sign(D1_0,vc(i,j))-vc(i,j))*dc(i,jt))*ymass(i,j)
enddo
enddo
endif
return
!EOC
end subroutine ycc
!-----------------------------------------------------------------------
#ifdef VECTORIZE
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: xtpv
!
! !INTERFACE:
subroutine xtpv(im, ffslv, fxv, qv, cv, iord, mfxv, & 6,6
cosav, id, dm, qtmpv, al, ar, a6, &
jfirst, jlast, jlow, jhigh, jm, &
jl2, jh2, jl3, jh3, &
jl4, jh4, jl5, jh5, &
jl7, jh7, jl11, jh11)
!-----------------------------------------------------------------------
implicit none
! !INPUT PARAMETERS:
integer id ! ID = 0: density (mfx = C)
! ID = 1: mixing ratio (mfx is mass flux)
integer im ! Total longitudes
real (r8) cv(im,jl5:jh5) ! Courant numbers
real (r8) qv(im,jl4:jh4)
real (r8) mfxv(im,jl7:jh7)
logical ffslv(jl2:jh2)
integer iord
integer jfirst, jlast, jlow, jhigh, jm
integer jl2, jh2, jl3, jh3, jl4, jh4, jl5, jh5
integer jl7, jh7, jl11, jh11
real (r8) cosav(jm)
! !INPUT/OUTPUT PARAMETERS:
real (r8) qtmpv(-im/3:im+im/3,jl11:jh11) ! Input work arrays:
real (r8) dm(-im/3:im+im/3)
real (r8) al(-im/3:im+im/3)
real (r8) ar(-im/3:im+im/3)
real (r8) a6(-im/3:im+im/3)
! !OUTPUT PARAMETERS:
real (r8) fxv(im,jl3:jh3)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
! Local:
real (r8) cos_upw !critical cosine for upwind
real (r8) cos_van !critical cosine for van Leer
real (r8) cos_ppm !critical cosine for ppm
parameter (cos_upw = D0_05) !roughly at 87 deg.
parameter (cos_van = D0_25) !roughly at 75 deg.
parameter (cos_ppm = D0_25)
real (r8) r24
parameter (r24 = D1_0/D24_0)
integer i, imp, j
real (r8) qmax, qmin
real (r8) rut, tmp
real (r8) dmv(-im/3:im+im/3,jlow:jhigh)
integer iu, itmp, ist
integer isave(im,jlow:jhigh)
integer iuwv(jlow:jhigh), iuev(jlow:jhigh)
integer jatn, jafn, ja
integer jat(jhigh-jlow+1), jaf(jhigh-jlow+1)
integer jattn, jatfn, jaftn, jaffn
integer jatt(jhigh-jlow+1), jatf(jhigh-jlow+1)
integer jaft(jhigh-jlow+1), jaff(jhigh-jlow+1)
integer jatftn, jatffn
integer jatft(jhigh-jlow+1), jatff(jhigh-jlow+1)
integer jafftn1, jafffn1
integer jafft1(jhigh-jlow+1), jafff1(jhigh-jlow+1)
integer jafftn2, jafffn2
integer jafft2(jhigh-jlow+1), jafff2(jhigh-jlow+1)
real (r8) qsum((-im/3)-1:im+im/3,jlow:jhigh) ! work arrays
jatn = 0
jafn = 0
jattn = 0
jatfn = 0
jaftn = 0
jaffn = 0
jatftn = 0
jatffn = 0
jafftn1 = 0
jafffn1 = 0
jafftn2 = 0
jafffn2 = 0
!call ftrace_region_begin("xtpv_1")
do j = jlow, jhigh
if (ffslv(j)) then
jatn = jatn + 1
jat(jatn) = j
if( iord == 1 .or. cosav(j) < cos_upw) then
jattn = jattn + 1
jatt(jattn) = j
else
jatfn = jatfn + 1
jatf(jatfn) = j
if(iord .ge. 3 .and. cosav(j) .gt. cos_ppm) then
jatftn = jatftn + 1
jatft(jatftn) = j
else
jatffn = jatffn + 1
jatff(jatffn) = j
endif
endif
else
jafn = jafn + 1
jaf(jafn) = j
if( iord == 1 .or. cosav(j) < cos_upw) then
jaftn = jaftn + 1
jaft(jaftn) = j
else
jaffn = jaffn + 1
jaff(jaffn) = j
if(iord > 0 .or. cosav(j) < cos_van) then
jafftn1 = jafftn1 + 1
jafft1(jafftn1) = j
else
jafffn1 = jafffn1 + 1
jafff1(jafffn1) = j
endif
if( abs(iord).eq.2 .or. cosav(j) .lt. cos_van ) then
jafftn2 = jafftn2 + 1
jafft2(jafftn2) = j
else
jafffn2 = jafffn2 + 1
jafff2(jafffn2) = j
endif
endif
endif
enddo
!call ftrace_region_end("xtpv_1")
imp = im + 1
do j = jlow, jhigh
do i=1,im
qtmpv(i,j) = qv(i,j)
enddo
enddo
! Flux-Form Semi-Lagrangian transport
!call ftrace_region_begin("xtpv_2")
!dir$ concurrent
do ja = 1, jatn
j = jat(ja)
! Figure out ghost zone for the western edge:
iuwv(j) = -cv(1,j)
iuwv(j) = min(0, iuwv(j))
do i=iuwv(j), 0
qtmpv(i,j) = qv(im+i,j)
enddo
! Figure out ghost zone for the eastern edge:
iuev(j) = im - cv(im,j)
iuev(j) = max(imp, iuev(j))
do i=imp, iuev(j)
qtmpv(i,j) = qv(i-im,j)
enddo
enddo
!call ftrace_region_end("xtpv_2")
!dir$ concurrent
!call ftrace_region_begin("xtpv_3")
do ja = 1, jattn
j = jatt(ja)
do i=1,im
iu = cv(i,j)
if(cv(i,j) .le. D0_0) then
itmp = i - iu
isave(i,j) = itmp - 1
else
itmp = i - iu - 1
isave(i,j) = itmp + 1
endif
fxv(i,j) = (cv(i,j)-iu) * qtmpv(itmp,j)
enddo
enddo
!call ftrace_region_end("xtpv_3")
!dir$ concurrent
!call ftrace_region_begin("xtpv_4")
do ja = 1, jatfn
j = jatf(ja)
do i=1,im
! 2nd order slope
tmp = D0_25*(qtmpv(i+1,j) - qtmpv(i-1,j))
qmax = max(qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j)) - qtmpv(i,j)
qmin = qtmpv(i,j) - min(qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j))
dmv(i,j) = sign(min(abs(tmp),qmax,qmin), tmp)
enddo
do i=iuwv(j), 0
dmv(i,j) = dmv(im+i,j)
enddo
do i=imp, iuev(j)
dmv(i,j) = dmv(i-im,j)
enddo
enddo
!call ftrace_region_end("xtpv_4")
call fxppmv
(im, cv, mfxv, qtmpv, dmv, fxv, iord, &
iuwv, iuev, ffslv, isave, jatftn, jatft, jlow, jhigh, &
jl2, jh2, jl3, jh3, jl5, jh5, jl7, jh7, jl11, jh11)
!dir$ concurrent
!call ftrace_region_begin("xtpv_5")
do ja = 1, jatffn
j = jatff(ja)
do i=1,im
iu = cv(i,j)
rut = cv(i,j) - iu
if(cv(i,j) .le. D0_0) then
itmp = i - iu
isave(i,j) = itmp - 1
fxv(i,j) = rut*(qtmpv(itmp,j)-dmv(itmp,j)*(D1_0+rut))
else
itmp = i - iu - 1
isave(i,j) = itmp + 1
fxv(i,j) = rut*(qtmpv(itmp,j)+dmv(itmp,j)*(D1_0-rut))
endif
enddo
enddo
!call ftrace_region_end("xtpv_5")
!dir$ concurrent
!call ftrace_region_begin("xtpv_6")
do ja = 1, jatn
j = jat(ja)
qsum(iuwv(j)-1,j) = D0_0
do i = iuwv(j), iuev(j)
qsum(i,j) = qsum(i-1,j) + qtmpv(i,j)
end do
!
! The boolean terms:
! a) .and. (isave(i,j) < i)
! b) .and. (i <= isave(i,j))
! are needed in the IF statements below because I cannot prove to myself
! that the relationship between i and isave are such to guarantee that
! there is always at least one term from qsum (qtmpv,j) contributed to fxv.
!
do i=1,im
if(cv(i,j) >= D1_0 .and. (isave(i,j) < i) ) then
fxv(i,j) = fxv(i,j) + (qsum(i-1,j) - qsum(isave(i,j) - 1,j))
else if (cv(i,j) <= -D1_0 .and. (i <= isave(i,j)) ) then
fxv(i,j) = fxv(i,j) - (qsum(isave(i,j),j) - qsum(i-1,j))
end if
end do
if(id .ne. 0) then
do i=1,im
fxv(i,j) = fxv(i,j)*mfxv(i,j)
enddo
endif
enddo
!call ftrace_region_end("xtpv_6")
! Regular PPM (Eulerian without FFSL extension)
!call ftrace_region_begin("xtpv_7")
!dir$ concurrent
!cdir nodep
do ja = 1, jafn
j = jaf(ja)
qtmpv(imp,j) = qv(1,j)
qtmpv( 0,j) = qv(im,j)
enddo
!dir$ concurrent
do ja = 1, jaftn
j = jaft(ja)
do i=1,im
iu = real(i,r8) - cv(i,j)
fxv(i,j) = mfxv(i,j)*qtmpv(iu,j)
enddo
enddo
!dir$ concurrent
!cdir nodep
do ja = 1, jaffn
j = jaff(ja)
qtmpv(-1,j) = qv(im-1,j)
qtmpv(imp+1,j) = qv(2,j)
enddo
!call ftrace_region_end("xtpv_7")
!dir$ concurrent
!call ftrace_region_begin("xtpv_8")
do ja = 1, jafftn1
j = jafft1(ja)
! In-line xmist
do i=1,im
dmv(i,j) = r24*(D8_0*(qtmpv(i+1,j) - qtmpv(i-1,j)) + qtmpv(i-2,j) - qtmpv(i+2,j))
enddo
! Apply monotonicity constraint (Lin et al. 1994, MWR)
do i=1,im
qmax = max( qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j) ) - qtmpv(i,j)
qmin = qtmpv(i,j) - min( qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j) )
dmv(i,j) = sign( min(abs(dmv(i,j)), qmax, qmin), dmv(i,j) )
enddo
enddo
!call ftrace_region_end("xtpv_8")
!dir$ concurrent
!call ftrace_region_begin("xtpv_9")
do ja = 1, jafffn1
j = jafff1(ja)
! In-line xmist
if(iord .le. 2) then
do i=1,im
dmv(i,j) = r24*(D8_0*(qtmpv(i+1,j) - qtmpv(i-1,j)) + qtmpv(i-2,j) - qtmpv(i+2,j))
enddo
else
do i=1,im
dmv(i,j) = D0_25*(qtmpv(i+1,j) - qtmpv(i-1,j))
enddo
endif
if( iord >= 0 ) then
! Apply monotonicity constraint (Lin et al. 1994, MWR)
do i=1,im
qmax = max( qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j) ) - qtmpv(i,j)
qmin = qtmpv(i,j) - min( qtmpv(i-1,j), qtmpv(i,j), qtmpv(i+1,j) )
dmv(i,j) = sign( min(abs(dmv(i,j)), qmax, qmin), dmv(i,j) )
enddo
endif
enddo
!call ftrace_region_end("xtpv_9")
!call ftrace_region_begin("xtpv_10")
!dir$ concurrent
!cdir nodep
do ja = 1, jaffn
j = jaff(ja)
dmv(0,j) = dmv(im,j)
enddo
!call ftrace_region_end("xtpv_10")
!dir$ concurrent
!call ftrace_region_begin("xtpv_11")
do ja = 1, jafftn2
j = jafft2(ja)
do i=1,im
iu = real(i,r8) - cv(i,j)
fxv(i,j) = mfxv(i,j)*(qtmpv(iu,j)+dmv(iu,j)*(sign(D1_0,cv(i,j))-cv(i,j)))
enddo
enddo
!call ftrace_region_end("xtpv_11")
call fxppmv
(im, cv, mfxv, qtmpv, dmv, fxv, iord, &
iuwv, iuev, ffslv, isave, jafffn2, jafff2, jlow, jhigh, &
jl2, jh2, jl3, jh3, jl5, jh5, jl7, jh7, jl11, jh11)
return
!EOC
end subroutine xtpv
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: fxppmv
!
! !INTERFACE:
subroutine fxppmv(im, c, mfx, p, dm, fx, iord, & 2,3
iuw, iue, ffsl, isave, jan, ja, jlow, jhigh, &
jl2, jh2, jl3, jh3, jl5, jh5, jl7, jh7, jl11, jh11)
!-----------------------------------------------------------------------
!
! !USES:
implicit none
! !INPUT PARAMETERS:
integer jan, ja(jan), jlow, jhigh, jj, j
integer jl2, jh2, jl3, jh3, jl5, jh5, jl7, jh7, jl11, jh11
integer im, iord
real (r8) c(im,jl5:jh5)
real (r8) p(-im/3:im+im/3,jl11:jh11)
real (r8) dm(-im/3:im+im/3,jlow:jhigh)
real (r8) mfx(im,jl7:jh7)
integer iuw(jlow:jhigh), iue(jlow:jhigh)
logical ffsl(jl2:jh2)
integer isave(im,jlow:jhigh)
! !OUTPUT PARAMETERS:
real (r8) fx(im,jl3:jh3)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
real (r8) r3, r23
parameter ( r3 = D1_0/D3_0, r23 = D2_0/D3_0 )
integer i, lmt
integer iu, itmp
real (r8) ru
logical steep
real (r8) al(-im/3:im+im/3,jlow:jhigh)
real (r8) ar(-im/3:im+im/3,jlow:jhigh)
real (r8) a6(-im/3:im+im/3,jlow:jhigh)
integer jbtn, jbfn
integer jbt(jan), jbf(jan)
integer ilow, ihigh
ilow = -im/3
ihigh = im + im/3
if( iord == 6 ) then
steep = .true.
else
steep = .false.
endif
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=1,im
al(i,j) = D0_5*(p(i-1,j)+p(i,j)) + (dm(i-1,j) - dm(i,j))*r3
enddo
enddo
if (steep) then
call steepxv
( im, p, al, dm, jan, ja, jlow, jhigh, jl11, jh11 )
endif
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=1,im-1
ar(i,j) = al(i+1,j)
enddo
ar(im,j) = al(1,j)
enddo
if(iord == 7) then
call huynhv
(im, ar, al, p, a6, dm, jan, ja, jlow, jhigh, jl11, jh11 )
else
if(iord .eq. 3 .or. iord .eq. 5) then
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=1,im
a6(i,j) = D3_0*(p(i,j)+p(i,j) - (al(i,j)+ar(i,j)))
enddo
enddo
endif
lmt = iord - 3
call lmppmv
( dm, a6, ar, al, p, im, lmt, jan, ja, ilow, ihigh, &
jlow, jhigh, jl11, jh11 )
endif
jbtn = 0
jbfn = 0
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
if( ffsl(j) ) then
jbtn = jbtn + 1
jbt(jbtn) = j
else
jbfn = jbfn + 1
jbf(jbfn) = j
endif
enddo
!dir$ concurrent
do jj = 1, jbtn
j = jbt(jj)
do i=iuw(j), 0
al(i,j) = al(im+i,j)
ar(i,j) = ar(im+i,j)
a6(i,j) = a6(im+i,j)
enddo
do i=im+1, iue(j)
al(i,j) = al(i-im,j)
ar(i,j) = ar(i-im,j)
a6(i,j) = a6(i-im,j)
enddo
do i=1,im
iu = c(i,j)
ru = c(i,j) - iu
if(c(i,j) .gt. D0_0) then
itmp = i - iu - 1
isave(i,j) = itmp + 1
fx(i,j) = ru*(ar(itmp,j)+D0_5*ru*(al(itmp,j)-ar(itmp,j) + &
a6(itmp,j)*(D1_0-r23*ru)) )
else
itmp = i - iu
isave(i,j) = itmp - 1
fx(i,j) = ru*(al(itmp,j)-D0_5*ru*(ar(itmp,j)-al(itmp,j) + &
a6(itmp,j)*(D1_0+r23*ru)) )
endif
enddo
enddo
!dir$ concurrent
do jj = 1, jbfn
j = jbf(jj)
al(0,j) = al(im,j)
ar(0,j) = ar(im,j)
a6(0,j) = a6(im,j)
do i=1,im
if(c(i,j) .gt. D0_0) then
fx(i,j) = ar(i-1,j) + D0_5*c(i,j)*(al(i-1,j) - ar(i-1,j) + &
a6(i-1,j)*(D1_0-r23*c(i,j)) )
else
fx(i,j) = al(i,j) - D0_5*c(i,j)*(ar(i,j) - al(i,j) + &
a6(i,j)*(D1_0+r23*c(i,j)))
endif
fx(i,j) = mfx(i,j) * fx(i,j)
enddo
enddo
return
!EOC
end subroutine fxppmv
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: steepxv
!
! !INTERFACE:
subroutine steepxv(im, p, al, dm, jan, ja, jlow, jhigh, jl11, jh11 ) 1
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im
integer jan, ja(jan), jlow, jhigh, jl11, jh11
real (r8) p(-im/3:im+im/3,jl11:jh11)
real (r8) dm(-im/3:im+im/3,jlow:jhigh)
! !INPUT/OUTPUT PARAMETERS:
real (r8) al(im,jlow:jhigh)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
integer i, jj, j
real (r8) r3
parameter ( r3 = D1_0/D3_0 )
real (r8) dh(0:im,jlow:jhigh)
real (r8) d2(0:im+1,jlow:jhigh)
real (r8) eta(0:im,jlow:jhigh)
real (r8) xxx, bbb, ccc
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=0,im
dh(i,j) = p(i+1,j) - p(i,j)
enddo
! Needs dh(0:im,j)
do i=1,im
d2(i,j) = dh(i,j) - dh(i-1,j)
enddo
d2(0,j) = d2(im,j)
d2(im+1,j) = d2(1,j)
! needs p(-1:im+2,j), d2(0:im+1,j)
do i=1,im
if( d2(i+1,j)*d2(i-1,j).lt.D0_0 .and. p(i+1,j).ne.p(i-1,j) ) then
xxx = D1_0 - D0_5 * ( p(i+2,j) - p(i-2,j) ) / ( p(i+1,j) - p(i-1,j) )
eta(i,j) = max(D0_0, min(xxx, D0_5) )
else
eta(i,j) = D0_0
endif
enddo
eta(0,j) = eta(im,j)
! needs eta(0:im,j), dh(0:im-1,j), dm(0:im,j)
do i=1,im
bbb = ( D2_0*eta(i,j ) - eta(i-1,j) ) * dm(i-1,j)
ccc = ( D2_0*eta(i-1,j) - eta(i,j ) ) * dm(i,j )
al(i,j) = al(i,j) + D0_5*( eta(i-1,j) - eta(i,j)) * dh(i-1,j) + (bbb - ccc) * r3
enddo
enddo
return
!EOC
end subroutine steepxv
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: huynhv --- Enforce Huynh's 2nd constraint in 1D periodic domain
!
! !INTERFACE:
subroutine huynhv(im, ar, al, p, d2, d1, jan, ja, jlow, jhigh, jl11, jh11) 1
!-----------------------------------------------------------------------
! !USES:
implicit none
! !INPUT PARAMETERS:
integer im
integer jan, ja(jan), jlow, jhigh, jl11, jh11
real(r8) p(im,jl11:jh11)
! !OUTPUT PARAMETERS:
real(r8) ar(im,jlow:jhigh)
real(r8) al(im,jlow:jhigh)
real(r8) d2(im,jlow:jhigh)
real(r8) d1(im,jlow:jhigh)
! !DESCRIPTION:
!
! Enforce Huynh's 2nd constraint in 1D periodic domain
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
integer i, jj, j
real(r8) pmp
real(r8) lac
real(r8) pmin
real(r8) pmax
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
! Compute d1 and d2
d1(1,j) = p(1,j) - p(im,j)
do i=2,im
d1(i,j) = p(i,j) - p(i-1,j)
enddo
do i=1,im-1
d2(i,j) = d1(i+1,j) - d1(i,j)
enddo
d2(im,j) = d1(1,j) - d1(im,j)
! Constraint for AR
! i = 1
pmp = p(1,j) + D2_0 * d1(1,j)
lac = p(1,j) + D0_5 * (d1(1,j)+d2(im,j)) + d2(im,j)
pmin = min(p(1,j), pmp, lac)
pmax = max(p(1,j), pmp, lac)
ar(1,j) = min(pmax, max(ar(1,j), pmin))
do i=2, im
pmp = p(i,j) + D2_0*d1(i,j)
lac = p(i,j) + D0_5*(d1(i,j)+d2(i-1,j)) + d2(i-1,j)
pmin = min(p(i,j), pmp, lac)
pmax = max(p(i,j), pmp, lac)
ar(i,j) = min(pmax, max(ar(i,j), pmin))
enddo
! Constraint for AL
do i=1, im-1
pmp = p(i,j) - D2_0*d1(i+1,j)
lac = p(i,j) + D0_5*(d2(i+1,j)-d1(i+1,j)) + d2(i+1,j)
pmin = min(p(i,j), pmp, lac)
pmax = max(p(i,j), pmp, lac)
al(i,j) = min(pmax, max(al(i,j), pmin))
enddo
! i=im
i = im
pmp = p(im,j) - D2_0*d1(1,j)
lac = p(im,j) + D0_5*(d2(1,j)-d1(1,j)) + d2(1,j)
pmin = min(p(im,j), pmp, lac)
pmax = max(p(im,j), pmp, lac)
al(im,j) = min(pmax, max(al(im,j), pmin))
! compute A6 (d2)
do i=1, im
d2(i,j) = D3_0*(p(i,j)+p(i,j) - (al(i,j)+ar(i,j)))
enddo
enddo
return
!EOC
end subroutine huynhv
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: lmppmv
!
! !INTERFACE:
subroutine lmppmv(dm, a6, ar, al, p, im, lmt, jan, ja, & 2
ilow, ihigh, jlow, jhigh, jl11, jh11)
!-----------------------------------------------------------------------
implicit none
! !INPUT PARAMETERS:
integer im ! Total longitudes
integer jan, ja(jan), ilow, ihigh, jlow, jhigh, jl11, jh11
integer lmt ! LMT = 0: full monotonicity
! LMT = 1: Improved and simplified full monotonic constraint
! LMT = 2: positive-definite constraint
! LMT = 3: Quasi-monotone constraint
real(r8) p(ilow:ihigh,jl11:jh11)
real(r8) dm(ilow:ihigh,jlow:jhigh)
! !OUTPUT PARAMETERS:
real(r8) a6(ilow:ihigh,jlow:jhigh)
real(r8) ar(ilow:ihigh,jlow:jhigh)
real(r8) al(ilow:ihigh,jlow:jhigh)
! !DESCRIPTION:
!
!
! !REVISION HISTORY:
! 99.01.01 Lin Creation
! 01.03.27 Sawyer Additional ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
real (r8) r12
parameter ( r12 = D1_0/D12_0 )
real (r8) da1, da2, fmin, a6da
real (r8) dr, dl
integer i, jj, j
! LMT = 0: full monotonicity
! LMT = 1: Improved and simplified full monotonic constraint
! LMT = 2: positive-definite constraint
! LMT = 3: Quasi-monotone constraint
if( lmt == 0 ) then
! Full constraint
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=1,im
if(dm(i,j) .eq. D0_0) then
ar(i,j) = p(i,j)
al(i,j) = p(i,j)
a6(i,j) = D0_0
else
da1 = ar(i,j) - al(i,j)
da2 = da1**2
a6da = a6(i,j)*da1
if(a6da .lt. -da2) then
a6(i,j) = D3_0*(al(i,j)-p(i,j))
ar(i,j) = al(i,j) - a6(i,j)
elseif(a6da .gt. da2) then
a6(i,j) = D3_0*(ar(i,j)-p(i,j))
al(i,j) = ar(i,j) - a6(i,j)
endif
endif
enddo
enddo
elseif( lmt == 1 ) then
! Improved (Lin 2001?) full constraint
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=1,im
da1 = dm(i,j) + dm(i,j)
dl = sign(min(abs(da1),abs(al(i,j)-p(i,j))), da1)
dr = sign(min(abs(da1),abs(ar(i,j)-p(i,j))), da1)
ar(i,j) = p(i,j) + dr
al(i,j) = p(i,j) - dl
a6(i,j) = D3_0*(dl-dr)
enddo
enddo
elseif( lmt == 2 ) then
! Positive definite constraint
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=1,im
if(abs(ar(i,j)-al(i,j)) .lt. -a6(i,j)) then
fmin = p(i,j) + D0_25*(ar(i,j)-al(i,j))**2/a6(i,j) + a6(i,j)*r12
if(fmin.lt.D0_0) then
if(p(i,j).lt.ar(i,j) .and. p(i,j).lt.al(i,j)) then
ar(i,j) = p(i,j)
al(i,j) = p(i,j)
a6(i,j) = D0_0
elseif(ar(i,j) .gt. al(i,j)) then
a6(i,j) = D3_0*(al(i,j)-p(i,j))
ar(i,j) = al(i,j) - a6(i,j)
else
a6(i,j) = D3_0*(ar(i,j)-p(i,j))
al(i,j) = ar(i,j) - a6(i,j)
endif
endif
endif
enddo
enddo
elseif(lmt .eq. 3) then
! Quasi-monotone constraint
!dir$ concurrent
do jj = 1, jan
j = ja(jj)
do i=1,im
da1 = D4_0*dm(i,j)
dl = sign(min(abs(da1),abs(al(i,j)-p(i,j))), da1)
dr = sign(min(abs(da1),abs(ar(i,j)-p(i,j))), da1)
ar(i,j) = p(i,j) + dr
al(i,j) = p(i,j) - dl
a6(i,j) = D3_0*(dl-dr)
enddo
enddo
endif
return
!EOC
end subroutine lmppmv
!-----------------------------------------------------------------------
#endif
end module tp_core