#if defined(ROW_LAND)
#define SEA_P .true.
#define SEA_U .true.
#define SEA_V .true.
#elif defined(ROW_ALLSEA)
#define SEA_P allip(j).or.ip(i,j).ne.0
#define SEA_U alliu(j).or.iu(i,j).ne.0
#define SEA_V alliv(j).or.iv(i,j).ne.0
#else
#define SEA_P ip(i,j).ne.0
#define SEA_U iu(i,j).ne.0
#define SEA_V iv(i,j).ne.0
#endif
subroutine hybgen(m,n, hybgen_raflag)
use mod_xc ! HYCOM communication interface
use mod_cb_arrays ! HYCOM saved arrays
use mod_pipe ! HYCOM debugging interface
!
! --- hycom version 1.0
implicit none
!
logical hybgen_raflag
integer m,n
!
! --- ---------------------
! --- hybrid grid generator
! --- ---------------------
!
logical, parameter :: lpipe_hybgen=.false. !for debugging
!
integer i,j,k
character text*12
!
103 format (i9,2i5,a/(33x,i3,2f8.3,f8.3,f9.3,f9.2))
!diag if (itest.gt.0 .and. jtest.gt.0) then
!diag write (lp,103) nstep,itest+i0,jtest+j0, &
!diag ' entering hybgen: temp saln dens thkns dpth', &
!diag (k,temp(itest,jtest,k,n),saln(itest,jtest,k,n), &
!diag th3d(itest,jtest,k,n)+thbase,dp(itest,jtest,k,n)*qonem, &
!diag p(itest,jtest,k+1)*qonem,k=1,kk)
!diag endif
!
call xctilr(dpmixl( 1-nbdy,1-nbdy, n),1, 1, 1,1, halo_ps)
!
!$OMP PARALLEL DO PRIVATE(j) &
!$OMP SHARED(m,n) &
!$OMP SCHEDULE(STATIC,jblk)
do j=1,jj
call hybgenaj(m,n, j)
enddo
!$OMP END PARALLEL DO
!
! --- vertical momentum flux across moving interfaces (the s-dot term in the
! --- momentum equation) - required to locally conserve momentum when hybgen
! --- moves vertical coordinates first, store old interface pressures in
! --- -pu-, -pv-
!
!$OMP PARALLEL DO PRIVATE(j,i,k) &
!$OMP SCHEDULE(STATIC,jblk)
do j=1,jj
do i=1,ii
if (SEA_U) then
pu(i,j,1)=0.0
pu(i,j,2)=dpu(i,j,1,n)
endif !iu
if (SEA_V) then
pv(i,j,1)=0.0
pv(i,j,2)=dpv(i,j,1,n)
endif !iv
enddo !i
do k=2,kk
do i=1,ii
if (SEA_U) then
pu(i,j,k+1)=pu(i,j,k)+dpu(i,j,k,n)
endif !iu
if (SEA_V) then
pv(i,j,k+1)=pv(i,j,k)+dpv(i,j,k,n)
endif !iv
enddo !i
enddo !k
enddo !j
!$OMP END PARALLEL DO
!
! --- update layer thickness at -u,v- points.
call dpudpv(dpu(1-nbdy,1-nbdy,1,n), &
dpv(1-nbdy,1-nbdy,1,n), &
p,depthu,depthv, 0,0)
!
if (lpipe .and. lpipe_hybgen) then
! --- compare two model runs.
! --- exit (if any) in next call to pipe_compare_all
!
call pipe_fatal_off
do k= 1,kk+1
write (text,'(a9,i3)') 'p k=',k
call pipe_compare(p( 1-nbdy,1-nbdy,k),ip,text)
write (text,'(a9,i3)') 'pu k=',k
call pipe_compare(pu(1-nbdy,1-nbdy,k),iu,text)
write (text,'(a9,i3)') 'pv k=',k
call pipe_compare(pv(1-nbdy,1-nbdy,k),iv,text)
enddo
do k= 1,kk
write (text,'(a9,i3)') 'dp k=',k
call pipe_compare(dp( 1-nbdy,1-nbdy,k,n),ip,text)
write (text,'(a9,i3)') 'dpu k=',k
call pipe_compare(dpu(1-nbdy,1-nbdy,k,n),iu,text)
write (text,'(a9,i3)') 'dpv k=',k
call pipe_compare(dpv(1-nbdy,1-nbdy,k,n),iv,text)
enddo
call pipe_fatal_on
endif
!
!$OMP PARALLEL DO PRIVATE(j) &
!$OMP SHARED(n) &
!$OMP SCHEDULE(STATIC,jblk)
do j=1,jj
call hybgenbj(n, j) !update velocity at time level t+1
enddo
!$OMP END PARALLEL DO
!
if (hybgen_raflag) then
!
! --- Apply Robert-Asselin update to layer thickness at time level t
!
!$OMP PARALLEL DO PRIVATE(j) &
!$OMP SHARED(m,n) &
!$OMP SCHEDULE(STATIC,jblk)
do j=1,jj
call hybgencj(m,n, j)
enddo
!$OMP END PARALLEL DO
!
!$OMP PARALLEL DO PRIVATE(j,i,k) &
!$OMP SCHEDULE(STATIC,jblk)
do j=1,jj
do i=1,ii
if (SEA_U) then
pu(i,j,1)=0.0
pu(i,j,2)=dpu(i,j,1,m)
endif !iu
if (SEA_V) then
pv(i,j,1)=0.0
pv(i,j,2)=dpv(i,j,1,m)
endif !iv
enddo !i
do k=2,kk
do i=1,ii
if (SEA_U) then
pu(i,j,k+1)=pu(i,j,k)+dpu(i,j,k,m)
endif !iu
if (SEA_V) then
pv(i,j,k+1)=pv(i,j,k)+dpv(i,j,k,m)
endif !iv
enddo !i
enddo !k
enddo !j
!$OMP END PARALLEL DO
!
call dpudpv(dpu(1-nbdy,1-nbdy,1,m), &
dpv(1-nbdy,1-nbdy,1,m), &
p,depthu,depthv, 0,0)
!
if (lpipe .and. lpipe_hybgen) then
! --- compare two model runs.
do k= 1,kk+1
write (text,'(a9,i3)') 'p k=',k
call pipe_compare(p( 1-nbdy,1-nbdy,k),ip,text)
write (text,'(a9,i3)') 'pu k=',k
call pipe_compare(pu(1-nbdy,1-nbdy,k),iu,text)
write (text,'(a9,i3)') 'pv k=',k
call pipe_compare(pv(1-nbdy,1-nbdy,k),iv,text)
enddo
do k= 1,kk
write (text,'(a9,i3)') 'dp k=',k
call pipe_compare(dp( 1-nbdy,1-nbdy,k,m),ip,text)
write (text,'(a9,i3)') 'dpu k=',k
call pipe_compare(dpu(1-nbdy,1-nbdy,k,m),iu,text)
write (text,'(a9,i3)') 'dpv k=',k
call pipe_compare(dpv(1-nbdy,1-nbdy,k,m),iv,text)
enddo
endif
!
!$OMP PARALLEL DO PRIVATE(j) &
!$OMP SHARED(m) &
!$OMP SCHEDULE(STATIC,jblk)
do j=1,jj
call hybgenbj(m, j) !update velocity at time level t
enddo
!$OMP END PARALLEL DO
endif !hybgen_raflag
!
return
end subroutine hybgen
subroutine hybgenaj(m,n,j )
use mod_xc ! HYCOM communication interface
use mod_cb_arrays ! HYCOM saved arrays
implicit none
!
integer m,n, j
!
! --- --------------------------------------------
! --- hybrid grid generator, single j-row (part A).
! --- --------------------------------------------
!
logical, parameter :: lunmix=.true. !unmix a too light deepest layer
logical, parameter :: lconserve=.false. !explicitly conserve each column
integer, parameter :: ndebug_tracer=0 !tracer to debug, usually 0 (off)
!
double precision asum( mxtrcr+4,3)
real offset(mxtrcr+4)
!
logical lcm(kdm) !use PCM for some layers?
real s1d(kdm,mxtrcr+4), & !original scalar fields
f1d(kdm,mxtrcr+4), & !final scalar fields
c1d(kdm,mxtrcr+4,3), & !interpolation coefficients
dpi( kdm), & !original layer thicknesses, >= dpthin
dprs(kdm), & !original layer thicknesses
pres(kdm+1), & !original layer interfaces
prsf(kdm+1), & !final layer interfaces
qhrlx( kdm+1), & !relaxation coefficient, from qhybrlx
dp0ij( kdm), & !minimum layer thickness
dp0cum(kdm+1) !minimum interface depth
real p_hat,p_hat0,p_hat2,p_hat3,hybrlx, &
delt,deltm,dels,delsm,q,qdep,qtr,qts,thkbop, &
zthk,dpthin
integer i,k,ka,kp,ktr,fixall,fixlay,nums1d
character*12 cinfo
!
double precision, parameter :: zp5=0.5 !for sign function
!
! --- c u s h i o n function (from Bleck & Benjamin, 1992):
! --- if delp >= qqmx*dp0 >> dp0, -cushn- returns -delp-
! --- if delp <= qqmn*dp0 << -dp0, -cushn- returns -dp0-
!
real qqmn,qqmx,cusha,cushb
parameter (qqmn=-4.0, qqmx=2.0) ! shifted range
! parameter (qqmn=-2.0, qqmx=4.0) ! traditional range
! parameter (qqmn=-4.0, qqmx=6.0) ! somewhat wider range
parameter (cusha=qqmn**2*(qqmx-1.0)/(qqmx-qqmn)**2)
parameter (cushb=1.0/qqmn)
!
real qq,cushn,delp,dp0
# include "stmt_fns.h"
qq( delp,dp0)=max(qqmn, min(qqmx, delp/dp0))
cushn(delp,dp0)=dp0* &
(1.0+cusha*(1.0-cushb*qq(delp,dp0))**2)* &
max(1.0, delp/(dp0*qqmx))
!
dpthin = 0.001*onemm
thkbop = thkbot*onem
hybrlx = 1.0/qhybrlx
!
if (mxlmy) then
nums1d = ntracr + 4
else
nums1d = ntracr + 2
endif
!
if (.not.isopcm) then
! --- lcm the same for all points
do k=1,nhybrd
lcm(k) = .false. !use same remapper for all layers
enddo !k
do k=nhybrd+1,kk
lcm(k) = .true. !purely isopycnal layers use PCM
enddo !k
endif
!
do i=1,ii
if (SEA_P) then
!
! --- terrain following starts at depth dpns and ends at depth dsns
qdep = max( 0.0, min( 1.0, &
(depths(i,j) - dsns)/ &
(dpns - dsns) ) )
!
if (qdep.lt.1.0) then
! --- terrain following, qhrlx=1 and ignore dp00
p(i,j, 1)=0.0
dp0cum(1)=0.0
qhrlx( 1)=1.0
dp0ij( 1)=qdep*dp0k(1) + (1.0-qdep)*ds0k(1)
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag k=1
!diag write (lp,*) 'qdep = ',qdep
!diag write (lp,'(a/i6,1x,4f9.3/a)') &
!diag ' k dp0ij ds0k dp0k p', &
!diag k,dp0ij(k)*qonem,ds0k(1)*qonem,dp0k(1)*qonem, &
!diag p(i,j,k)*qonem, &
!diag ' k dp0ij p-cum p dp0cum'
!diag endif !debug
dp0cum(2)=dp0cum(1)+dp0ij(1)
qhrlx( 2)=1.0
p(i,j, 2)=p(i,j,1)+dp(i,j,1,n)
do k=2,kk
qhrlx( k+1)=1.0
dp0ij( k) =qdep*dp0k(k) + (1.0-qdep)*ds0k(k)
dp0cum(k+1)=dp0cum(k)+dp0ij(k)
p(i,j, k+1)=p(i,j,k)+dp(i,j,k,n)
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write (lp,'(i6,1x,4f9.3)') &
!diag k,dp0ij(k)*qonem,p(i,j,k)*qonem-dp0cum(k)*qonem, &
!diag p(i,j,k)*qonem,dp0cum(k)*qonem
!diag endif !debug
enddo !k
else
! --- not terrain following
p(i,j, 1)=0.0
dp0cum(1)=0.0
qhrlx( 1)=1.0 !no relaxation in top layer
dp0ij( 1)=dp0k(1)
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag k=1
!diag write (lp,*) 'qdep = ',qdep
!diag write (lp,'(a/i6,1x,f9.3)') &
!diag ' k dp0ij dp0k q p-cum p dp0cum', &
!diag k,dp0ij(k)*qonem
!diag endif !debug
dp0cum(2)=dp0cum(1)+dp0ij(1)
qhrlx( 2)=1.0 !no relaxation in top layer
p(i,j, 2)=p(i,j,1)+dp(i,j,1,n)
do k=2,kk
! --- q is dp0k(k) when in surface fixed coordinates
! --- q is dp00i when much deeper than surface fixed coordinates
if (dp0k(k).le.dp00i) then
q = dp0k(k)
qts= 0.0 !0 at dp0k
else
q = max( dp00i, &
dp0k(k) * dp0k(k)/ &
max( dp0k( k), &
p(i,j,k)-dp0cum(k) ) )
qts= 1.0 - (q-dp00i)/(dp0k(k)-dp00i) !0 at dp0k, 1 at dp00i
endif
qhrlx( k+1)=1.0/(1.0 + qts*(hybrlx-1.0)) !1 at dp0k, qhybrlx at dp00i
dp0ij( k) =min( q, dp0k(k) )
dp0cum(k+1)=dp0cum(k)+dp0ij(k)
p(i,j, k+1)=p(i,j,k)+dp(i,j,k,n)
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write (lp,'(i6,1x,6f9.3)') &
!diag k,dp0ij(k)*qonem,dp0k(k)*qonem,q*qonem, &
!diag p(i,j,k)*qonem-dp0cum(k)*qonem, &
!diag p(i,j,k)*qonem,dp0cum(k)*qonem
!diag endif !debug
enddo !k
endif !qdep<1:else
!
! --- identify the current fixed coordinate layers
fixlay = 1 !layer 1 always fixed
do k= 2,nhybrd
if (dp0cum(k).ge.topiso(i,j)) then
exit !layers k to nhybrd might be isopycnal
endif
! --- top of layer is above topiso, i.e. always fixed coordinate layer
qhrlx(k+1) = 1.0 !no relaxation in fixed layers
fixlay = fixlay+1
enddo !k
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3)') &
!diag 'hybgen, always-fixed coordinate layers: 1 to ', &
!diag fixlay
!diag call flush(lp)
!diag endif !debug
!
fixall = fixlay
do k= fixall+1,nhybrd
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write (lp,'(i6,1x,2f9.3)') &
!diag k,p(i,j,k+1)*qonem,dp0cum(k+1)*qonem
!diag call flush(lp)
!diag endif !debug
if (p(i,j,k+1).gt.dp0cum(k+1)+0.1*dp0ij(k)) then
if (fixlay.gt.fixall) then
! --- should the previous layer remain fixed?
if (p(i,j,k).gt.dp0cum(k)) then
fixlay = fixlay-1
endif
endif
exit !layers k to nhybrd might be isopycnal
endif
! --- sometimes fixed coordinate layer
qhrlx(k) = 1.0 !no relaxation in fixed layers
fixlay = fixlay+1
enddo !k
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3)') &
!diag 'hybgen, fixed coordinate layers: 1 to ', &
!diag fixlay
!diag call flush(lp)
!diag endif !debug
!
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write (lp,'(a/(i6,1x,2f8.3,2f9.3,f9.3))') &
!diag 'hybgen: thkns minthk dpth mindpth hybrlx', &
!diag (k,dp(i,j,k,n)*qonem, dp0ij(k)*qonem, &
!diag p(i,j,k+1)*qonem,dp0cum(k+1)*qonem, &
!diag 1.0/qhrlx(k+1), &
!diag k=1,kk)
!diag endif !debug
!
! --- identify the deepest layer kp with significant thickness (> dpthin)
!
kp = 2 !minimum allowed value
do k=kk,3,-1
if (p(i,j,k+1)-p(i,j,k).ge.dpthin) then
kp=k
exit
endif
enddo !k
!
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3)') &
!diag 'hybgen, deepest inflated layer:',kp
!diag call flush(lp)
!diag endif !debug
!
k = kp !at least 2
ka = max(k-2,1) !k might be 2
!
if (k.gt.fixlay+1 .and. qdep.eq.1.0 .and. & !layer not fixed depth
p(i,j,k)-p(i,j,k-1).ge.dpthin .and. & !layer above not too thin
theta(i,j,k)-epsil.gt.th3d(i,j,k,n) .and. &
th3d(i,j,k-1,n) .gt.th3d(i,j,k,n) .and. &
th3d(i,j,ka, n) .gt.th3d(i,j,k,n) ) then
!
! --- water in the deepest inflated layer with significant thickness
! --- (kp) is too light, and it is lighter than the two layers above.
! ---
! --- this should only occur when relaxing or nudging layer thickness
! --- and is a bug (bad interaction with tsadvc) even in those cases
! ---
! --- entrain the entire layer into the one above
!--- note the double negative in T=T-q*(T-T'), equiv. to T=T+q*(T'-T)
q = (p(i,j,k+1)-p(i,j,k))/(p(i,j,k+1)-p(i,j,k-1))
if (hybflg.eq.0) then !T&S
temp(i,j,k-1,n)=temp(i,j,k-1,n)-q*(temp(i,j,k-1,n) - &
temp(i,j,k, n) )
saln(i,j,k-1,n)=saln(i,j,k-1,n)-q*(saln(i,j,k-1,n) - &
saln(i,j,k, n) )
th3d(i,j,k-1,n)=sig(temp(i,j,k-1,n),saln(i,j,k-1,n))-thbase
elseif (hybflg.eq.1) then !th&S
th3d(i,j,k-1,n)=th3d(i,j,k-1,n)-q*(th3d(i,j,k-1,n) - &
th3d(i,j,k, n) )
saln(i,j,k-1,n)=saln(i,j,k-1,n)-q*(saln(i,j,k-1,n) - &
saln(i,j,k, n) )
temp(i,j,k-1,n)=tofsig(th3d(i,j,k-1,n)+thbase,saln(i,j,k-1,n))
elseif (hybflg.eq.2) then !th&T
th3d(i,j,k-1,n)=th3d(i,j,k-1,n)-q*(th3d(i,j,k-1,n) - &
th3d(i,j,k, n) )
temp(i,j,k-1,n)=temp(i,j,k-1,n)-q*(temp(i,j,k-1,n) - &
temp(i,j,k, n) )
saln(i,j,k-1,n)=sofsig(th3d(i,j,k-1,n)+thbase,temp(i,j,k-1,n))
endif
if (ndebug_tracer.gt.0 .and. ndebug_tracer.le.ntracr .and. &
i.eq.itest .and. j.eq.jtest) then
ktr = ndebug_tracer
write(lp,'(a,i3,f6.3,f9.4)') &
'hybgen, 11(+):', &
k-1,0.0,tracer(i,j,k-1,n,ktr)
call flush(lp)
endif !debug_tracer
do ktr= 1,ntracr
tracer(i,j,k-1,n,ktr)=tracer(i,j,k-1,n,ktr)- &
q*(tracer(i,j,k-1,n,ktr) - &
tracer(i,j,k, n,ktr) )
enddo !ktr
if (ndebug_tracer.gt.0 .and. ndebug_tracer.le.ntracr .and. &
i.eq.itest .and. j.eq.jtest) then
ktr = ndebug_tracer
write(lp,'(a,i3,f6.3,f9.4)') &
'hybgen, 11(+):', &
k-1,q,tracer(i,j,k-1,n,ktr)
write(lp,'(a,i3,f6.3,f9.4)') &
'hybgen, 11(+):', &
k,q,tracer(i,j,k,n,ktr)
write(lp,'(a,i3)') &
'hybgen, deepest inflated layer:',kp
call flush(lp)
endif !debug_tracer
if (mxlmy) then
q2( i,j,k-1,n)=q2( i,j,k-1,n)- &
q*(q2( i,j,k-1,n)-q2( i,j,k,n))
q2l(i,j,k-1,n)=q2l(i,j,k-1,n)- &
q*(q2l(i,j,k-1,n)-q2l(i,j,k,n))
endif
! --- entrained the entire layer into the one above, so now kp=kp-1
p(i,j,k) = p(i,j,k+1)
kp = k-1
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3,f6.3,5f8.3)') &
!diag 'hybgen, 11(+):', &
!diag k-1,q,temp(i,j,k-1,n),saln(i,j,k-1,n), &
!diag th3d(i,j,k-1,n)+thbase,theta(i,j,k-1)+thbase
!diag write(lp,'(a,i3)') &
!diag 'hybgen, deepest inflated layer:',kp
!diag call flush(lp)
!diag endif !debug
elseif (k.gt.fixlay+1 .and. qdep.eq.1.0 .and. & !layer not fixed depth
p(i,j,k)-p(i,j,k-1).ge.dpthin .and. & !layer above not too thin
theta(i,j,k)-epsil.gt.th3d(i,j,k,n) .and. &
th3d(i,j,k-1,n) .gt.th3d(i,j,k,n) ) then
!
! --- water in the deepest inflated layer with significant thickness
! --- (kp) is too light, and it is lighter than the layer above.
! ---
! --- swap the entire layer with the one above.
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3,f8.5,5f10.5)') &
!diag 'hybgen, original:', &
!diag k-1,0.0,temp(i,j,k-1,n),saln(i,j,k-1,n), &
!diag th3d(i,j,k-1,n)+thbase,theta(i,j,k-1)+thbase
!diag write(lp,'(a,i3,f8.5,5f10.5)') &
!diag 'hybgen, original:', &
!diag k,0.0,temp(i,j,k, n),saln(i,j,k, n), &
!diag th3d(i,j,k, n)+thbase,theta(i,j,k )+thbase
!diag endif !debug
if (p(i,j,k+1)-p(i,j,k).le.p(i,j,k)-p(i,j,k-1)) then
! --- bottom layer is thinner, take entire bottom layer
!--- note the double negative in T=T-q*(T-T'), equiv. to T=T+q*(T'-T)
s1d(k-1,1) = temp(i,j,k-1,n)
s1d(k-1,2) = saln(i,j,k-1,n)
s1d(k-1,3) = th3d(i,j,k-1,n)
q = (p(i,j,k+1)-p(i,j,k))/(p(i,j,k)-p(i,j,k-1)) !<=1.0
if (hybflg.eq.0) then !T&S
temp(i,j,k-1,n)=temp(i,j,k-1,n)-q*(temp(i,j,k-1,n) - &
temp(i,j,k, n) )
saln(i,j,k-1,n)=saln(i,j,k-1,n)-q*(saln(i,j,k-1,n) - &
saln(i,j,k, n) )
th3d(i,j,k-1,n)=sig(temp(i,j,k-1,n),saln(i,j,k-1,n))-thbase
elseif (hybflg.eq.1) then !th&S
th3d(i,j,k-1,n)=th3d(i,j,k-1,n)-q*(th3d(i,j,k-1,n) - &
th3d(i,j,k, n) )
saln(i,j,k-1,n)=saln(i,j,k-1,n)-q*(saln(i,j,k-1,n) - &
saln(i,j,k, n) )
temp(i,j,k-1,n)=tofsig(th3d(i,j,k-1,n)+thbase, &
saln(i,j,k-1,n))
elseif (hybflg.eq.2) then !th&T
th3d(i,j,k-1,n)=th3d(i,j,k-1,n)-q*(th3d(i,j,k-1,n) - &
th3d(i,j,k, n) )
temp(i,j,k-1,n)=temp(i,j,k-1,n)-q*(temp(i,j,k-1,n) - &
temp(i,j,k, n) )
saln(i,j,k-1,n)=sofsig(th3d(i,j,k-1,n)+thbase, &
temp(i,j,k-1,n))
endif
temp(i,j,k,n) = s1d(k-1,1)
saln(i,j,k,n) = s1d(k-1,2)
th3d(i,j,k,n) = s1d(k-1,3)
do ktr= 1,ntracr
s1d(k-1,2+ktr) = tracer(i,j,k-1,n,ktr)
tracer(i,j,k-1,n,ktr) = tracer(i,j,k-1,n,ktr)- &
q*(tracer(i,j,k-1,n,ktr) - &
tracer(i,j,k, n,ktr) )
tracer(i,j,k, n,ktr) = s1d(k-1,2+ktr)
enddo !ktr
if (mxlmy) then
s1d(k-1,ntracr+3) = q2( i,j,k-1,n)
s1d(k-1,ntracr+4) = q2l(i,j,k-1,n)
q2( i,j,k-1,n) = q2( i,j,k-1,n)- &
q*(q2( i,j,k-1,n)-q2( i,j,k,n))
q2l(i,j,k-1,n) = q2l(i,j,k-1,n)- &
q*(q2l(i,j,k-1,n)-q2l(i,j,k,n))
q2( i,j,k, n) = s1d(k-1,ntracr+3)
q2l(i,j,k, n) = s1d(k-1,ntracr+4)
endif
else
! --- bottom layer is thicker, take entire layer above
s1d(k,1) = temp(i,j,k,n)
s1d(k,2) = saln(i,j,k,n)
s1d(k,3) = th3d(i,j,k,n)
q = (p(i,j,k)-p(i,j,k-1))/(p(i,j,k+1)-p(i,j,k)) !<1.0
if (hybflg.eq.0) then !T&S
temp(i,j,k,n)=temp(i,j,k,n)+q*(temp(i,j,k-1,n) - &
temp(i,j,k, n) )
saln(i,j,k,n)=saln(i,j,k,n)+q*(saln(i,j,k-1,n) - &
saln(i,j,k, n) )
th3d(i,j,k,n)=sig(temp(i,j,k,n),saln(i,j,k,n))-thbase
elseif (hybflg.eq.1) then !th&S
th3d(i,j,k,n)=th3d(i,j,k,n)+q*(th3d(i,j,k-1,n) - &
th3d(i,j,k, n) )
saln(i,j,k,n)=saln(i,j,k,n)+q*(saln(i,j,k-1,n) - &
saln(i,j,k, n) )
temp(i,j,k,n)=tofsig(th3d(i,j,k,n)+thbase,saln(i,j,k,n))
elseif (hybflg.eq.2) then !th&T
th3d(i,j,k,n)=th3d(i,j,k,n)+q*(th3d(i,j,k-1,n) - &
th3d(i,j,k, n) )
temp(i,j,k,n)=temp(i,j,k,n)+q*(temp(i,j,k-1,n) - &
temp(i,j,k, n) )
saln(i,j,k,n)=sofsig(th3d(i,j,k,n)+thbase,temp(i,j,k,n))
endif
temp(i,j,k-1,n) = s1d(k,1)
saln(i,j,k-1,n) = s1d(k,2)
th3d(i,j,k-1,n) = s1d(k,3)
do ktr= 1,ntracr
s1d(k,2+ktr) = tracer(i,j,k,n,ktr)
tracer(i,j,k, n,ktr) = tracer(i,j,k,n,ktr)+ &
q*(tracer(i,j,k-1,n,ktr) - &
tracer(i,j,k, n,ktr) )
tracer(i,j,k-1,n,ktr) = s1d(k,2+ktr)
enddo !ktr
if (mxlmy) then
s1d(k,ntracr+3) = q2( i,j,k,n)
s1d(k,ntracr+4) = q2l(i,j,k,n)
q2( i,j,k, n) = q2( i,j,k,n)- &
q*(q2( i,j,k-1,n)-q2( i,j,k,n))
q2l(i,j,k, n) = q2l(i,j,k,n)- &
q*(q2l(i,j,k-1,n)-q2l(i,j,k,n))
q2( i,j,k-1,n) = s1d(k,ntracr+3)
q2l(i,j,k-1,n) = s1d(k,ntracr+4)
endif
endif !bottom too light
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3,f8.5,5f10.5)') &
!diag 'hybgen, overturn:', &
!diag k-1,q,temp(i,j,k-1,n),saln(i,j,k-1,n), &
!diag th3d(i,j,k-1,n)+thbase,theta(i,j,k-1)+thbase
!diag write(lp,'(a,i3,f8.5,5f10.5)') &
!diag 'hybgen, overturn:', &
!diag k, q,temp(i,j,k, n),saln(i,j,k, n), &
!diag th3d(i,j,k, n)+thbase,theta(i,j,k )+thbase
!diag call flush(lp)
!diag endif !debug
endif
!
k = kp !at least 2
ka = max(k-2,1) !k might be 2
!
if (lunmix .and. & !usually .true.
k.gt.fixlay+1 .and. qdep.eq.1.0 .and. & !layer not fixed depth
p(i,j,k)-p(i,j,k-1).ge.dpthin .and. & !layer above not too thin
theta(i,j,k)-epsil.gt.th3d(i,j,k, n) .and. &
theta(i,j,k-1) .lt.th3d(i,j,k, n) .and. &
abs(theta(i,j,k-1)- th3d(i,j,k-1,n)).lt.hybiso .and. &
( th3d(i,j,k,n)- th3d(i,j,k-1,n)).gt. &
(theta(i,j,k) - theta(i,j,k-1) )*0.001 ) then
!
! --- water in the deepest inflated layer with significant thickness
! --- (kp) is too light, with the layer above near-isopycnal
! ---
! --- split layer into 2 sublayers, one near the desired density
! --- and one exactly matching the T&S properties of layer k-1.
! --- To prevent "runaway" T or S, the result satisfies either
! --- abs(T.k - T.k-1) <= abs(T.k-N - T.k-1) or
! --- abs(S.k - S.k-1) <= abs(S.k-N - S.k-1) where
! --- th3d.k-1 - th3d.k-N is at least theta(k-1) - theta(k-2)
! --- It is also limited to a 50% change in layer thickness.
!
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3)') &
!diag 'hybgen, deepest inflated layer too light (stable):',k
!diag call flush(lp)
!diag endif !debug
!
ka = 1
do ktr= k-2,2,-1
if ( th3d(i,j,k-1,n)- th3d(i,j,ktr,n).ge. &
theta(i,j,k-1) -theta(i,j,k-2) ) then
ka = ktr !usually k-2
exit
endif
enddo !ktr
!
delsm=abs(saln(i,j,ka, n)-saln(i,j,k-1,n))
dels =abs(saln(i,j,k-1,n)-saln(i,j,k, n))
deltm=abs(temp(i,j,ka, n)-temp(i,j,k-1,n))
delt =abs(temp(i,j,k-1,n)-temp(i,j,k, n))
! --- sanity check on deltm and delsm
q=min(temp(i,j,ka, n),temp(i,j,k-1,n),temp(i,j,k,n))
if (q.gt. 6.0) then
deltm=min( deltm, 6.0*(theta(i,j,k)-theta(i,j,k-1)) )
else !(q.le. 6.0)
deltm=min( deltm, 10.0*(theta(i,j,k)-theta(i,j,k-1)) )
endif
delsm=min( delsm, 1.3*(theta(i,j,k)-theta(i,j,k-1)) )
qts=0.0
if (delt.gt.epsil) then
qts=max(qts, (min(deltm, 2.0*delt)-delt)/delt) ! qts<=1.0
endif
if (dels.gt.epsil) then
qts=max(qts, (min(delsm, 2.0*dels)-dels)/dels) ! qts<=1.0
endif
q=(theta(i,j,k)-th3d(i,j,k, n))/ &
(theta(i,j,k)-th3d(i,j,k-1,n))
q=min(q,qts/(1.0+qts)) ! upper sublayer <= 50% of total
q=qhrlx(k)*q
! --- qhrlx is relaxation coefficient (inverse baroclinic time steps)
p_hat=q*(p(i,j,k+1)-p(i,j,k))
p(i,j,k)=p(i,j,k)+p_hat
if (hybflg.eq.0) then !T&S
temp(i,j,k,n)=temp(i,j,k,n)+(q/(1.0-q))*(temp(i,j,k,n) - &
temp(i,j,k-1,n) )
saln(i,j,k,n)=saln(i,j,k,n)+(q/(1.0-q))*(saln(i,j,k,n) - &
saln(i,j,k-1,n) )
th3d(i,j,k,n)=sig(temp(i,j,k,n),saln(i,j,k,n))-thbase
elseif (hybflg.eq.1) then !th&S
th3d(i,j,k,n)=th3d(i,j,k,n)+(q/(1.0-q))*(th3d(i,j,k,n) - &
th3d(i,j,k-1,n) )
saln(i,j,k,n)=saln(i,j,k,n)+(q/(1.0-q))*(saln(i,j,k,n) - &
saln(i,j,k-1,n) )
temp(i,j,k,n)=tofsig(th3d(i,j,k,n)+thbase,saln(i,j,k,n))
elseif (hybflg.eq.2) then !th&T
th3d(i,j,k,n)=th3d(i,j,k,n)+(q/(1.0-q))*(th3d(i,j,k,n) - &
th3d(i,j,k-1,n) )
temp(i,j,k,n)=temp(i,j,k,n)+(q/(1.0-q))*(temp(i,j,k,n) - &
temp(i,j,k-1,n) )
saln(i,j,k,n)=sofsig(th3d(i,j,k,n)+thbase,temp(i,j,k,n))
endif
if (ntracr.gt.0 .and. p_hat.ne.0.0) then
if (ndebug_tracer.gt.0 .and. ndebug_tracer.le.ntracr .and. &
i.eq.itest .and. j.eq.jtest) then
ktr = ndebug_tracer
write(lp,'(a,i3,f6.3,f9.4)') &
'hybgen, 10(+):', &
k-1,0.0,tracer(i,j,k-1,n,ktr)
call flush(lp)
endif !debug_tracer
! --- fraction of new upper layer from old lower layer
qtr=p_hat/max(p_hat,p(i,j,k)-p(i,j,k-1)) !between 0 and 1
do ktr= 1,ntracr
if (trcflg(ktr).eq.2) then !temperature tracer
tracer(i,j,k,n,ktr)=tracer(i,j,k,n,ktr)+ &
(q/(1.0-q))*(tracer(i,j,k, n,ktr)- &
tracer(i,j,k-1,n,ktr))
else !standard tracer - not split into two sub-layers
tracer(i,j,k-1,n,ktr)=tracer(i,j,k-1,n,ktr)+ &
qtr*(tracer(i,j,k, n,ktr)- &
tracer(i,j,k-1,n,ktr))
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i4,i3,5e12.3)') &
!diag 'hybgen, 10(+):', &
!diag k,ktr,p_hat,p(i,j,k),p(i,j,k-1), &
!diag qtr,tracer(i,j,k-1,n,ktr)
!diag call flush(lp)
!diag endif !debug
endif !trcflg
enddo !ktr
if (ndebug_tracer.gt.0 .and. ndebug_tracer.le.ntracr .and. &
i.eq.itest .and. j.eq.jtest) then
ktr = ndebug_tracer
write(lp,'(a,i3,f6.3,f9.4)') &
'hybgen, 10(+):', &
k-1,qtr,tracer(i,j,k-1,n,ktr)
write(lp,'(a,i3,f6.3,f9.4)') &
'hybgen, 10(+):', &
k,qtr,tracer(i,j,k,n,ktr)
write(lp,'(a,i3)') &
'hybgen, deepest inflated layer:',kp
call flush(lp)
endif !debug_tracer
endif !tracers
if (mxlmy .and. p_hat.ne.0.0) then
! --- fraction of new upper layer from old lower layer
qtr=p_hat/max(p_hat,p(i,j,k)-p(i,j,k-1)) !between 0 and 1
q2( i,j,k-1,n)=q2( i,j,k-1,n)+ &
qtr*(q2( i,j,k,n)-q2( i,j,k-1,n))
q2l(i,j,k-1,n)=q2l(i,j,k-1,n)+ &
qtr*(q2l(i,j,k,n)-q2l(i,j,k-1,n))
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i4,i3,6e12.3)') &
!diag 'hybgen, 10(+):', &
!diag k,0,p_hat,p(i,j,k)-p(i,j,k-1),p(i,j,k+1)-p(i,j,k), &
!diag qtr,q2(i,j,k-1,n),q2l(i,j,k-1,n)
!diag call flush(lp)
!diag endif !debug
endif
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3,f6.3,5f8.3)') &
!diag 'hybgen, 10(+):', &
!diag k,q,temp(i,j,k,n),saln(i,j,k,n), &
!diag th3d(i,j,k,n)+thbase,theta(i,j,k)+thbase
!diag call flush(lp)
!diag endif !debug
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3,f6.3,5f8.3)') &
!diag 'hybgen, 10(-):', &
!diag k,0.0,temp(i,j,k,n),saln(i,j,k,n), &
!diag th3d(i,j,k,n)+thbase,theta(i,j,k)+thbase
!diag call flush(lp)
!diag endif !debug
endif !too light
!
! --- massless or near-massless (thickness < dpthin) layers
!
do k=kp+1,kk
if (k.le.nhybrd) then
! --- fill thin and massless layers on sea floor with fluid from above
th3d(i,j,k,n)=th3d(i,j,k-1,n)
saln(i,j,k,n)=saln(i,j,k-1,n)
temp(i,j,k,n)=temp(i,j,k-1,n)
elseif (th3d(i,j,k,n).ne.theta(i,j,k)) then
if (hybflg.ne.2) then
! --- fill with saln from above
th3d(i,j,k,n)=max(theta(i,j,k), th3d(i,j,k-1,n))
saln(i,j,k,n)=saln(i,j,k-1,n)
temp(i,j,k,n)=tofsig(th3d(i,j,k,n)+thbase,saln(i,j,k,n))
saln(i,j,k,n)=sofsig(th3d(i,j,k,n)+thbase,temp(i,j,k,n))
else
! --- fill with temp from above
th3d(i,j,k,n)=max(theta(i,j,k), th3d(i,j,k-1,n))
temp(i,j,k,n)=temp(i,j,k-1,n)
saln(i,j,k,n)=sofsig(th3d(i,j,k,n)+thbase,temp(i,j,k,n))
endif
endif
do ktr= 1,ntracr
tracer(i,j,k,n,ktr)=tracer(i,j,k-1,n,ktr)
enddo !ktr
if (ndebug_tracer.gt.0 .and. ndebug_tracer.le.ntracr .and. &
i.eq.itest .and. j.eq.jtest) then
ktr = ndebug_tracer
write(lp,'(a,i3,f9.4)') &
'hybgen, massless:', &
k,tracer(i,j,k,n,ktr)
call flush(lp)
endif !debug_tracer
if (mxlmy) then
q2 (i,j,k,n)=q2( i,j,k-1,n)
q2l(i,j,k,n)=q2l(i,j,k-1,n)
endif
enddo !k
!
! --- store one-dimensional arrays of -temp-, -saln-, and -p- for the 'old'
! --- vertical grid before attempting to restore isopycnic conditions
pres(1)=p(i,j,1)
do k=1,kk
if (hybflg.eq.0) then !T&S
s1d(k,1) = temp(i,j,k,n)
s1d(k,2) = saln(i,j,k,n)
elseif (hybflg.eq.1) then !th&S
s1d(k,1) = th3d(i,j,k,n)
s1d(k,2) = saln(i,j,k,n)
elseif (hybflg.eq.2) then !th&T
s1d(k,1) = th3d(i,j,k,n)
s1d(k,2) = temp(i,j,k,n)
endif
do ktr= 1,ntracr
s1d(k,2+ktr) = tracer(i,j,k,n,ktr)
enddo !ktr
if (mxlmy) then
s1d(k,ntracr+3) = q2( i,j,k,n)
s1d(k,ntracr+4) = q2l(i,j,k,n)
endif
pres(k+1)=p(i,j,k+1)
dprs(k) =pres(k+1)-pres(k)
dpi( k) =max(dprs(k),dpthin)
!
if (isopcm) then
if (k.le.fixlay) then
lcm(k) = .false. !fixed layers are never PCM
else
! --- thin and isopycnal layers remapped with PCM.
lcm(k) = k.gt.nhybrd &
.or. dprs(k).le.dpthin &
.or. abs(th3d(i,j,k,n)-theta(i,j,k)).lt.hybiso
endif !k<=fixlay:else
endif !isopcm
enddo !k
!
! --- try to restore isopycnic conditions by moving layer interfaces
! --- qhrlx(k) are relaxation coefficients (inverse baroclinic time steps)
!
if (fixlay.ge.1) then
!
! --- maintain constant thickness, layer k = 1
k=1
p_hat=p(i,j,k)+dp0ij(k)
p(i,j,k+1)=p_hat
do k=2,kk
if (p(i,j,k+1).ge.p_hat) then
exit ! usually get here quickly
endif
p(i,j,k+1)=p_hat
enddo !k
endif
!
do k=2,nhybrd
!
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(cinfo,'(a9,i2.2,1x)') ' do 88 k=',k
!diag write(lp,'(i9,2i5,a,a)') nstep,itest+i0,jtest+j0, &
!diag cinfo,': othkns odpth nthkns ndpth'
!diag do ka=1,kk
!diag if (pres(ka+1).eq.p(itest,jtest,ka+1) .and. &
!diag pres(ka ).eq.p(itest,jtest,ka ) ) then
!diag write(lp,'(i9,8x,a,a,i3,f10.3,f9.3)') &
!diag nstep,cinfo,':',ka, &
!diag (pres(ka+1)- &
!diag pres(ka) )*qonem, &
!diag pres(ka+1) *qonem
!diag else
!diag write(lp,'(i9,8x,a,a,i3,f10.3,f9.3,f10.3,f9.3)') &
!diag nstep,cinfo,':',ka, &
!diag (pres(ka+1)- &
!diag pres(ka) )*qonem, &
!diag pres(ka+1) *qonem, &
!diag (p(itest,jtest,ka+1)- &
!diag p(itest,jtest,ka) )*qonem, &
!diag p(itest,jtest,ka+1) *qonem
!diag endif
!diag enddo !ka
!diag call flush(lp)
!diag endif !debug
!
if (k.le.fixlay) then
!
! --- maintain constant thickness, k <= fixlay
if (k.lt.kk) then !p.kk+1 not changed
p(i,j,k+1)=min(dp0cum(k+1),p(i,j,kk+1))
if (k.eq.fixlay) then
! --- enforce interface order (may not be necessary).
do ka= k+2,kk
if (p(i,j,ka).ge.p(i,j,k+1)) then
exit ! usually get here quickly
else
p(i,j,ka) = p(i,j,k+1)
endif
enddo !ka
endif !k.eq.fixlay
endif !k.lt.kk
!
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,i3.2,f8.2)') 'hybgen, fixlay :', &
!diag k+1,p(i,j,k+1)*qonem
!diag call flush(lp)
!diag endif !debug
else
!
! --- do not maintain constant thickness, k > fixlay
!
if (th3d(i,j,k,n).gt.theta(i,j,k)+epsil .and. &
k.gt.fixlay+1) then
!
! --- water in layer k is too dense
! --- try to dilute with water from layer k-1
! --- do not move interface if k = fixlay + 1
!
if (th3d(i,j,k-1,n).ge.theta(i,j,k-1) .or. &
p(i,j,k).le.dp0cum(k)+onem .or. &
p(i,j,k+1)-p(i,j,k).le.p(i,j,k)-p(i,j,k-1)) then
!
! --- if layer k-1 is too light, thicken the thinner of the two,
! --- i.e. skip this layer if it is thicker.
!
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write(lp,'(a,3x,i2.2,1pe13.5)') &
!diag 'hybgen, too dense:',k,th3d(i,j,k,n)-theta(i,j,k)
!diag call flush(lp)
!diag endif !debug
!
if ((theta(i,j,k)-th3d(i,j,k-1,n)).le.epsil) then
! layer k-1 much too dense, take entire layer
p_hat=p(i,j,k-1)+dp0ij(k-1)
else
q=(theta(i,j,k)-th3d(i,j,k, n))/ &
(theta(i,j,k)-th3d(i,j,k-1,n)) ! -1 <= q < 0
p_hat0=p(i,j,k)+q*(p(i,j,k+1)-p(i,j,k)) !
p(i,j,k+1)
endif
!
! --- if layer k+1, or layer k+2, does not touch the bottom
! --- then maintain minimum thicknesses of layers k and k+1 as
! --- much as possible. otherwise, permit layers to collapse
! --- to zero thickness at the bottom.
!
if (p(i,j,min(k+3,kk+1)).lt.p(i,j,kk+1)) then
if (p(i,j,kk+1)-p(i,j,k).gt. &
dp0ij(k)+dp0ij(k+1) ) then
p_hat=p(i,j,k+2)-cushn(p(i,j,k+2)-p_hat,dp0ij(k+1))
endif
p_hat=p(i,j,k)+max(p_hat-p(i,j,k),dp0ij(k))
p_hat=min(p_hat, &
max(0.5*(p(i,j,k+1)+p(i,j,k+2)), &
p(i,j,k+2)-dp0ij(k+1)))
else
p_hat=min(p(i,j,k+2),p_hat)
endif !p.k+2
= dpthin
dprs(kdm), & !original layer thicknesses
pres(kdm+1), & !original layer interfaces
prsf(kdm+1) !final layer interfaces
real dpthin
!
! --- vertical momentum flux across moving interfaces (the s-dot term in the
! --- momentum equation) - required to locally conserve momentum when hybgen
! --- moves vertical coordinates.
!
dpthin = 0.001*onemm
!
! --- always use high order remapping for velocity
do k=1,kk
lcm(k) = .false. !use same remapper for all layers
enddo !k
!
do i=1,ii
if (SEA_U) then
!
! --- store one-dimensional arrays of -u- and -p- for the 'old' vertical grid
pres(1)=pu(i,j,1)
do k=1,kk
s1d(k) =u(i,j,k,nl)
pres(k+1)=pu(i,j,k+1)
dprs(k) =pres(k+1)-pres(k)
dpi( k) =max(dprs(k),dpthin)
enddo !k
!
! --- remap -u- profiles from the 'old' vertical grid onto the
! --- 'new' vertical grid.
!
prsf(1) = pu(i,j,1)
do k=1,kk
pu(i,j,k+1) = pu(i,j,k) + dpu(i,j,k,nl) !new vertical grid
prsf(k+1) = pu(i,j,k+1)
enddo
if (hybmap.eq.0) then !PCM
call hybgen_pcm_remap(s1d,pres,dprs, &
f1d,prsf,kk,kk,1, dpthin)
elseif (hybmap.eq.1 .and. hybiso.gt.2.0) then !PLM (as in 2.1.08)
call hybgen_plm_coefs(s1d, dprs,lcm,c1d, &
kk, 1, dpthin)
call hybgen_plm_remap(s1d,pres,dprs, c1d, &
f1d,prsf,kk,kk,1, dpthin)
else !WENO-like (even if scalar fields are PLM or PPM)
call hybgen_weno_coefs(s1d, dpi, lcm,c1d, &
kk, 1, dpthin)
call hybgen_weno_remap(s1d,pres,dprs, c1d, &
f1d,prsf,kk,kk,1, dpthin)
endif !hybmap
do k=1,kk
if (dpi(k).gt.dpthin .or. &
prsf(k).le.prsf(kk+1)-onemm) then
u(i,j,k,nl) = f1d(k)
else
! --- thin near-bottom layer, zero total current
u(i,j,k,nl) = -ubavg(i,j,nl)
endif
enddo !k
!
104 format (i9,2i5,a/(33x,i3,f8.3,f9.3,f9.2))
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write (lp,104) nstep,itest+i0,jtest+j0, &
!diag ' hybgen, do 412: u thkns dpth', &
!diag (k,s1d(k,1), &
!diag (pres(k+1)-pres(k))*qonem,pres(k+1)*qonem, &
!diag k,u(i,j,k,nl), &
!diag dpu(i,j,k,nl)*qonem,pu(i,j,k+1)*qonem, &
!diag k=1,kk)
!diag endif !debug
!
endif !iu
enddo !i
!
do i=1,ii
if (SEA_V) then
!
! --- store one-dimensional arrays of -v- and -p- for the 'old' vertical grid
pres(1)=pv(i,j,1)
do k=1,kk
s1d(k) =v(i,j,k,nl)
pres(k+1)=pv(i,j,k+1)
dprs(k) =pres(k+1)-pres(k)
dpi( k) =max(dprs(k),dpthin)
enddo !k
!
! --- remap -v- profiles from the 'old' vertical grid onto the
! --- 'new' vertical grid.
!
prsf(1) = pv(i,j,1)
do k=1,kk
pv(i,j,k+1) = pv(i,j,k) + dpv(i,j,k,nl) !new vertical grid
prsf(k+1) = pv(i,j,k+1)
enddo !k
if (hybmap.eq.0) then !PCM
call hybgen_pcm_remap(s1d,pres,dprs, &
f1d,prsf,kk,kk,1, dpthin)
elseif (hybmap.eq.1 .and. hybiso.gt.2.0) then !PLM (as in 2.1.08)
call hybgen_plm_coefs(s1d, dprs,lcm,c1d, &
kk, 1, dpthin)
call hybgen_plm_remap(s1d,pres,dprs, c1d, &
f1d,prsf,kk,kk,1, dpthin)
else !WENO-like (even if scalar fields are PLM or PPM)
call hybgen_weno_coefs(s1d, dpi, lcm,c1d, &
kk, 1, dpthin)
call hybgen_weno_remap(s1d,pres,dprs, c1d, &
f1d,prsf,kk,kk,1, dpthin)
endif !hybmap
do k=1,kk
if (dpi(k).gt.dpthin .or. &
prsf(k).le.prsf(kk+1)-onemm) then
v(i,j,k,nl) = f1d(k)
else
! --- thin near-bottom layer, zero total current
v(i,j,k,nl) = -vbavg(i,j,nl)
endif
enddo !k
!
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag write (lp,104) nstep,itest+i0,jtest+j0, &
!diag ' hybgen, do 512: v thkns dpth', &
!diag (k,s1d(k,1), &
!diag (pres(k+1)-pres(k))*qonem,pres(k+1)*qonem, &
!diag k,v(i,j,k,nl), &
!diag dpv(i,j,k,nl)*qonem,pv(i,j,k+1)*qonem, &
!diag k=1,kk)
!diag endif !debug
!
endif !iv
enddo !i
!
return
end subroutine hybgenbj
subroutine hybgencj(m,n,j )
use mod_xc ! HYCOM communication interface
use mod_cb_arrays ! HYCOM saved arrays
implicit none
!
integer m,n, j
!
! --- ----------------------------------------------------
! --- hybrid grid generator, single j-row (part C).
! --- Robert-Asselin update to time level t scalar fields.
! --- ----------------------------------------------------
!
logical, parameter :: lconserve=.false. !explicitly conserve each column
!
double precision asum( mxtrcr+4,3)
real offset(mxtrcr+4)
!
logical lcm(kdm) !use PCM for some layers?
real s1d(kdm,mxtrcr+4), & !original scalar fields
f1d(kdm,mxtrcr+4), & !final scalar fields
c1d(kdm,mxtrcr+4,3), & !interpolation coefficients
dpi( kdm), & !original layer thicknesses, >= dpthin
dprs(kdm), & !original layer thicknesses
pres(kdm+1), & !original layer interfaces
prsf(kdm+1), & !final layer interfaces
dp0ij( kdm), & !minimum layer thickness
dp0cum(kdm+1) !minimum interface depth
real dpold,dpmid,dpnew,q,qdep,zthk,dpthin
integer i,k,ktr,fixlay,nums1d
character*12 cinfo
!
double precision, parameter :: zp5=0.5 !for sign function
!
# include "stmt_fns.h"
!
dpthin = 0.001*onemm
!
if (mxlmy) then
nums1d = ntracr + 4
else
nums1d = ntracr + 2
endif
!
if (.not.isopcm) then
! --- lcm the same for all points
do k=1,nhybrd
lcm(k) = .false. !use same remapper for all layers
enddo !k
do k=nhybrd+1,kk
lcm(k) = .true. !purely isopycnal layers use PCM
enddo !k
endif
!
do i=1,ii
if (SEA_P) then
!
! --- terrain following starts at depth dpns and ends at depth dsns
qdep = max( 0.0, min( 1.0, &
(depths(i,j) - dsns)/ &
(dpns - dsns) ) )
!
dp0cum(1)=0.0
dp0ij( 1)=qdep*dp0k(1) + (1.0-qdep)*ds0k(1)
dp0cum(2)=dp0cum(1)+dp0ij(1)
do k=2,kk
! --- q is dp0k(k) when in surface fixed coordinates
! --- q is dp00i when much deeper than surface fixed coordinates
if (dp0k(k).le.dp00i) then
q = dp0k(k)
else
q = max( dp00i, &
dp0k(k) * dp0k(k)/ &
max( dp0k( k), &
p(i,j,k)-dp0cum(k) ) )
endif
dp0ij( k) =min( q, qdep*dp0k(k) + (1.0-qdep)*ds0k(k) )
dp0cum(k+1)=dp0cum(k)+dp0ij(k)
enddo !k
!
! --- identify the always-fixed coordinate layers
fixlay = 1 !layer 1 always fixed
do k= 2,nhybrd
if (dp0cum(k).ge.topiso(i,j)) then
exit !layers k to nhybrd can be isopycnal
endif
fixlay = fixlay+1
enddo !k
!
! --- store one-dimensional arrays for the 'old' vertical grid,
! --- and the new pressures
pres(1)=0.0
prsf(1)=0.0
do k=1,kk
if (hybflg.eq.0) then !T&S
s1d(k,1) = temp(i,j,k,m)
s1d(k,2) = saln(i,j,k,m)
elseif (hybflg.eq.1) then !th&S
s1d(k,1) = th3d(i,j,k,m)
s1d(k,2) = saln(i,j,k,m)
elseif (hybflg.eq.2) then !th&T
s1d(k,1) = th3d(i,j,k,m)
s1d(k,2) = temp(i,j,k,m)
endif
do ktr= 1,ntracr
s1d(k,2+ktr) = tracer(i,j,k,m,ktr)
enddo !ktr
if (mxlmy) then
s1d(k,ntracr+3) = q2( i,j,k,m)
s1d(k,ntracr+4) = q2l(i,j,k,m)
endif
!
dprs(k) = dp(i,j,k,m) !t, after cnuity RA filter
dpi( k) = max(dprs(k),dpthin)
pres(k+1) = pres(k) + dp(i,j,k,m)
!
! --- Robert-Asselin time filter of thickness field after hybgenaj
! --- If hybgenaj left dp.n unchanged, then dp.m is also unchanged
dpold = dpo(i,j,k,n) !t-1
dpmid = dpo(i,j,k,m) !t, before cnuity RA filter
dpnew = dp( i,j,k,n) !t+1, after hybgenaj
q = 0.5*ra2fac*(dpold+dpnew-2.0*dpmid)
dp(i,j,k,m) = dpmid + q !t & hybgen RA
prsf(k+1) = prsf(k) + dp(i,j,k,m)
p(i,j,k+1) = prsf(k+1)
!
if (isopcm) then
if (k.le.fixlay) then
lcm(k) = .false. !fixed layers are never PCM
else
! --- thin and isopycnal layers remapped with PCM.
lcm(k) = k.gt.nhybrd &
.or. dprs(k).le.dpthin &
.or. abs(th3d(i,j,k,m)-theta(i,j,k)).lt.hybiso
endif !k<=fixlay:else
endif !isopcm
enddo !k
!
! --- remap scalar field profiles from the 'old' vertical
! --- grid onto the 'new' vertical grid.
!
if (lconserve) then !usually .false.
do ktr=1,nums1d
asum(ktr,1) = 0.d0
asum(ktr,2) = 0.d0
asum(ktr,3) = 0.d0
enddo !ktr
endif
if (hybmap.eq.0) then !PCM
call hybgen_pcm_remap(s1d,pres,dprs, &
f1d,prsf,kk,kk,nums1d,dpthin)
elseif (hybmap.eq.1) then !PLM (as in 2.1.08)
call hybgen_plm_coefs(s1d, dprs,lcm,c1d, &
kk, nums1d,dpthin)
call hybgen_plm_remap(s1d,pres,dprs, c1d, &
f1d,prsf,kk,kk,nums1d,dpthin)
elseif (hybmap.eq.2) then !PPM
call hybgen_ppm_coefs(s1d, dpi, lcm,c1d, &
kk, nums1d,dpthin)
call hybgen_ppm_remap(s1d,pres,dprs, c1d, &
f1d,prsf,kk,kk,nums1d,dpthin)
elseif (hybmap.eq.3) then !WENO-like
call hybgen_weno_coefs(s1d, dpi, lcm,c1d, &
kk, nums1d,dpthin)
call hybgen_weno_remap(s1d,pres,dprs, c1d, &
f1d,prsf,kk,kk,nums1d,dpthin)
endif
do k=1,kk
if (hybflg.eq.0) then !T&S
temp(i,j,k,m) = f1d(k,1)
saln(i,j,k,m) = f1d(k,2)
th3d(i,j,k,m)=sig(temp(i,j,k,m),saln(i,j,k,m))-thbase
elseif (hybflg.eq.1) then !th&S
th3d(i,j,k,m) = f1d(k,1)
saln(i,j,k,m) = f1d(k,2)
temp(i,j,k,m)=tofsig(th3d(i,j,k,m)+thbase, &
saln(i,j,k,m))
! saln(i,j,k,m)=sofsig(th3d(i,j,k,m)+thbase,
! & temp(i,j,k,m))
elseif (hybflg.eq.2) then !th&T
th3d(i,j,k,m) = f1d(k,1)
temp(i,j,k,m) = f1d(k,2)
saln(i,j,k,m)=sofsig(th3d(i,j,k,m)+thbase, &
temp(i,j,k,m))
endif
do ktr= 1,ntracr
tracer(i,j,k,m,ktr) = f1d(k,2+ktr)
enddo !ktr
if (mxlmy) then
q2( i,j,k,m) = f1d(k,ntracr+3)
q2l(i,j,k,m) = f1d(k,ntracr+4)
endif
!
if (lconserve) then !usually .false.
zthk = dp(i,j,k,m)
do ktr= 1,nums1d
asum(ktr,1) = asum(ktr,1) + s1d(k,ktr)*dprs(k)
asum(ktr,2) = asum(ktr,2) + f1d(k,ktr)*zthk
enddo !ktr
endif !lconserve
!
enddo !k
!
!diag if (i.eq.itest .and. j.eq.jtest) then
! write (lp,'(i9,3a/(i9,3f23.17))')
! & nstep,
! & ' dens',
! & ' thkns',
! & ' dpth',
! & (k,tthe(k,1), dprs(k)*qonem, pres(k+1)*qonem,
! & k,th3d(i,j,k,m),dp(i,j,k,m)*qonem,p(i,j,k+1)*qonem,
! & k=1,kk)
!diag write (lp,'(i9,3a/(i9,3f23.17))') &
!diag nstep, &
!diag ' tracer.1', &
!diag ' thkns', &
!diag ' dpth', &
!diag (k,ttrc( k,1,1), dprs(k)*qonem, pres(k+1)*qonem, &
!diag k,tracer(i,j,k,m,1),dp(i,j,k,m)*qonem,p(i,j,k+1)*qonem, &
!diag k=1,kk)
!diag call flush(lp)
!diag endif !debug
!
if (lconserve) then !usually .false.
!
! --- enforce water column conservation
!
do ktr=1,nums1d
q = asum(ktr,1)-asum(ktr,2)
if (q.eq.0.0) then
offset(ktr) = 0.0
elseif (abs(asum(ktr,2)).lt.2.0*abs(q)) then
offset(ktr) = sign(zp5,q*asum(ktr,2)) ! -0.5 or +0.5
else
offset(ktr) = q/asum(ktr,2) !between -0.5 and +0.5
endif
enddo !ktr
do k=1,kk
if (hybflg.eq.0) then !T&S
temp(i,j,k,m)=temp(i,j,k,m)*(1.0+offset(1))
saln(i,j,k,m)=saln(i,j,k,m)*(1.0+offset(2))
th3d(i,j,k,m)=sig(temp(i,j,k,m),saln(i,j,k,m))-thbase
elseif (hybflg.eq.1) then !th&S
th3d(i,j,k,m)=th3d(i,j,k,m)*(1.0+offset(1))
saln(i,j,k,m)=saln(i,j,k,m)*(1.0+offset(2))
temp(i,j,k,m)=tofsig(th3d(i,j,k,m)+thbase, &
saln(i,j,k,m))
elseif (hybflg.eq.2) then !th&T
th3d(i,j,k,m)=th3d(i,j,k,m)*(1.0+offset(1))
temp(i,j,k,m)=temp(i,j,k,m)*(1.0+offset(2))
saln(i,j,k,m)=sofsig(th3d(i,j,k,m)+thbase, &
temp(i,j,k,m))
endif
do ktr= 1,ntracr
tracer(i,j,k,m,ktr)=tracer(i,j,k,m,ktr)*(1.0+offset(ktr+2))
enddo !ktr
if (mxlmy) then
q2( i,j,k,m)=q2( i,j,k,m)*(1.0+offset(ntracr+3))
q2l(i,j,k,m)=q2l(i,j,k,m)*(1.0+offset(ntracr+4))
endif
!
if (.false.) then !debugging
zthk = dp(i,j,k,m)
if (hybflg.eq.0) then !T&S
asum(1,3) = asum(1,3) + temp(i,j,k,m)*zthk
asum(2,3) = asum(2,3) + saln(i,j,k,m)*zthk
elseif (hybflg.eq.1) then !th&S
asum(1,3) = asum(1,3) + th3d(i,j,k,m)*zthk
asum(2,3) = asum(2,3) + saln(i,j,k,m)*zthk
elseif (hybflg.eq.2) then !th&T
asum(1,3) = asum(1,3) + th3d(i,j,k,m)*zthk
asum(2,3) = asum(2,3) + temp(i,j,k,m)*zthk
endif
do ktr= 1,ntracr
asum(ktr+2,3) = asum(ktr+2,3) + tracer(i,j,k,m,ktr)*zthk
enddo !ktr
if (mxlmy) then
asum(ntracr+3,3) = asum(ntracr+3,3) + q2( i,j,k,m)*zthk
asum(ntracr+4,3) = asum(ntracr+4,3) + q2l(i,j,k,m)*zthk
endif
endif !debuging
enddo !k
!
if (.false. .and. & !debugging
i.eq.itest .and. j.eq.jtest) then
do ktr= 1,nums1d
write(lp,'(a,1p4e16.8,i3)') &
'hybgen,sum:', &
asum(ktr,1)/p(i,j,kk+1), &
asum(ktr,2)/p(i,j,kk+1), &
asum(ktr,3)/p(i,j,kk+1), &
offset(ktr),ktr
enddo !ktr
endif !debugging .and. i.eq.itest .and. j.eq.jtest
if (.false. .and. & !debugging
j.eq.jtest) then
ktr=1
! if (abs(offset(ktr)).gt.1.e-08) then
if (abs(offset(ktr)).gt.1.e-12) then
write(lp,'(a,1p4e16.8,i3)') &
'hybgen,sum:', &
asum(ktr,1)/p(i,j,kk+1), &
asum(ktr,2)/p(i,j,kk+1), &
asum(ktr,3)/p(i,j,kk+1), &
offset(ktr),i
endif !large offset
endif !debugging .and. j.eq.jtest
endif !lconserve
!
!diag if (i.eq.itest .and. j.eq.jtest) then
! write (lp,'(i9,3a/(i9,3f23.17))')
! & nstep,
! & ' dens',
! & ' thkns',
! & ' dpth',
! & (k,tthe(k,1), dprs(k)*qonem, pres(k+1)*qonem,
! & k,th3d(i,j,k,m),dp(i,j,k,m)*qonem,p(i,j,k+1)*qonem,
! & k=1,kk)
!diag write (lp,'(i9,3a/(i9,3f23.17))') &
!diag nstep, &
!diag ' tracer.1', &
!diag ' thkns', &
!diag ' dpth', &
!diag (k,ttrc( k,1,1), dprs(k)*qonem, pres(k+1)*qonem, &
!diag k,tracer(i,j,k,m,1),dp(i,j,k,m)*qonem,p(i,j,k+1)*qonem, &
!diag k=1,kk)
!diag call flush(lp)
!diag endif
!
!diag 103 format (i9,2i5,a/(33x,i3,2f8.3,f8.3,f9.3,f9.2))
!diag if (i.eq.itest .and. j.eq.jtest) then
!diag if (hybflg.eq.0) then !T&S
!diag write (lp,103) nstep,itest+i0,jtest+j0, &
!diag ' hybgen, do 22: temp saln dens thkns dpth', &
!diag (k,s1d(k,1),s1d(k,2),0.0, &
!diag (pres(k+1)-pres(k))*qonem,pres(k+1)*qonem, &
!diag k,temp(i,j,k,m),saln(i,j,k,m), &
!diag th3d(i,j,k,m)+thbase,dp(i,j,k,m)*qonem, &
!diag p(i,j,k+1)*qonem, &
!diag k=1,kk)
!diag elseif (hybflg.eq.1) then !th&S
!diag write (lp,103) nstep,itest+i0,jtest+j0, &
!diag ' hybgen, do 22: temp saln dens thkns dpth', &
!diag (k,0.0,s1d(k,2),s1d(k,1)+thbase, &
!diag (pres(k+1)-pres(k))*qonem,pres(k+1)*qonem, &
!diag k,temp(i,j,k,m),saln(i,j,k,m), &
!diag th3d(i,j,k,m)+thbase,dp(i,j,k,m)*qonem, &
!diag p(i,j,k+1)*qonem, &
!diag k=1,kk)
!diag elseif (hybflg.eq.2) then !th&T
!diag write (lp,103) nstep,itest+i0,jtest+j0, &
!diag ' hybgen, do 22: temp saln dens thkns dpth', &
!diag (k,s1d(k,2),0.0,s1d(k,1)+thbase, &
!diag (pres(k+1)-pres(k))*qonem,pres(k+1)*qonem, &
!diag k,temp(i,j,k,m),saln(i,j,k,m), &
!diag th3d(i,j,k,m)+thbase,dp(i,j,k,m)*qonem, &
!diag p(i,j,k+1)*qonem, &
!diag k=1,kk)
!diag endif
!diag call flush(lp)
!diag endif !debug
!
endif !ip
enddo !i
!
return
end subroutine hybgencj
subroutine hybgen_pcm_remap(si,pi,dpi, &
so,po,ki,ko,ks,thin)
implicit none
!
integer ki,ko,ks
real si(ki,ks),pi(ki+1),dpi(ki), &
so(ko,ks),po(ko+1),thin
!
!-----------------------------------------------------------------------
! 1) remap from one set of vertical cells to another.
! method: piecewise constant across each input cell
! the output is the average of the interpolation
! profile across each output cell.
!
! PCM (donor cell) is the standard 1st order upwind method.
!
! 2) input arguments:
! si - initial scalar fields in pi-layer space
! pi - initial layer interface depths (non-negative)
! pi( 1) is the surface
! pi(ki+1) is the bathymetry
! pi(k+1) >= pi(k)
! dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k))
! ki - number of input layers
! ko - number of output layers
! ks - number of fields
! po - target interface depths (non-negative)
! po( 1) is the surface
! po(ko+1) is the bathymetry (== pi(ki+1))
! po(k+1) >= po(k)
! thin - layer thickness (>0) that can be ignored
!
! 3) output arguments:
! so - scalar fields in po-layer space
!
! 4) Tim Campbell, Mississippi State University, October 2002.
! Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007.
!-----------------------------------------------------------------------
!
integer i,k,l,lb,lt
real dpb,dpt,xb,xt,zb,zt,zx,o
real*8 sz
real si_min(ks),si_max(ks)
!
! --- inforce minval(si(:,i)) <= minval(so(:,i)) and
! --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks
! --- in particular this inforces non-negativity, e.g. of tracers
! --- only required due to finite precision
!
do i= 1,ks
si_min(i) = minval(si(:,i))
si_max(i) = maxval(si(:,i))
enddo !i
!
zx=pi(ki+1) !maximum depth
zb=max(po(1),pi(1))
lb=1
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
do k= 1,ko !output layers
zt = zb
zb = min(po(k+1),zx)
! write(lp,*) 'k,zt,zb = ',k,zt,zb
lt=lb !top will always correspond to bottom of previous
!find input layer containing bottom output interface
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
if (zb-zt.le.thin .or. zt.ge.zx) then
if (k.ne.1) then
!
! --- thin or bottomed layer, values taken from layer above
!
do i= 1,ks
so(k,i) = so(k-1,i)
enddo !i
else !thin surface layer
do i= 1,ks
so(k,i) = si(k,i)
enddo !i
endif
else
!
! form layer averages.
! use PPM-like logic (may not have minimum operation count)
!
! if (pi(lb).gt.zt) then
! write(lp,*) 'bad lb = ',lb
! stop
! endif
if (lt.ne.lb) then !multiple layers
xt=(zt-pi(lt))/max(dpi(lt),thin)
xb=(zb-pi(lb))/max(dpi(lb),thin)
dpt=pi(lt+1)-zt
dpb=zb-pi(lb)
do i= 1,ks
o = si((lt+lb)/2,i) !offset to reduce round-off
sz = dpt*(si(lt,i)-o)
do l=lt+1,lb-1
sz = sz+dpi(l)*(si(l,i)-o)
enddo !l
sz = sz+dpb*(si(lb,i)-o)
so(k,i) = o + sz/(zb-zt) !zb-zt>=thin
so(k,i) = max( si_min(i), so(k,i) )
so(k,i) = min( si_max(i), so(k,i) )
enddo !i
else !single layer
do i= 1,ks
so(k,i) = si(lt,i)
enddo !i
endif
endif !thin:std layer
enddo !k
return
end subroutine hybgen_pcm_remap
subroutine hybgen_plm_coefs(si,dpi,lc,ci,kk,ks,thin)
implicit none
!
integer kk,ks
logical lc(kk)
real si(kk,ks),dpi(kk),ci(kk,ks),thin
!
!-----------------------------------------------------------------------
! 1) coefficents for remaping from one set of vertical cells to another.
! method: piecewise linear across each input cell with
! monotonized central-difference limiter.
!
! van Leer, B., 1977, J. Comp. Phys., 23 276-299.
!
! 2) input arguments:
! si - initial scalar fields in pi-layer space
! dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k))
! lc - use PCM for selected layers
! kk - number of layers
! ks - number of fields
! thin - layer thickness (>0) that can be ignored
!
! 3) output arguments:
! ci - coefficents (slopes) for hybgen_plm_remap
! profile(y)=si+ci*(y-1), 0<=y<=1
!
! 4) Tim Campbell, Mississippi State University, October 2002.
! Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007.
!-----------------------------------------------------------------------
!
integer k,i
real qcen,zbot,zcen,ztop
!
do i= 1,ks
ci(1, i) = 0.0
ci(kk,i) = 0.0
enddo !i
do k= 2,kk-1
if (lc(k) .or. dpi(k).le.thin) then !use PCM
do i= 1,ks
ci(k,i) = 0.0
enddo !i
else
! --- use qcen in place of 0.5 to allow for non-uniform grid
qcen = dpi(k)/(dpi(k)+0.5*(dpi(k-1)+dpi(k+1))) !dpi(k)>thin
do i= 1,ks
! --- PLM (non-zero slope, but no new extrema)
! --- layer value is si-0.5*ci at top interface,
! --- and si+0.5*ci at bottom interface.
!
! --- monotonized central-difference limiter (van Leer, 1977,
! --- JCP 23 pp 276-299). For a discussion of PLM limiters, see
! --- Finite Volume Methods for Hyperbolic Problems by R.J. Leveque.
ztop = 2.0*(si(k, i)-si(k-1,i))
zbot = 2.0*(si(k+1,i)-si(k, i))
zcen =qcen*(si(k+1,i)-si(k-1,i))
if (ztop*zbot.gt.0.0) then !ztop,zbot are the same sign
ci(k,i)=sign(min(abs(zcen),abs(zbot),abs(ztop)),zbot)
else
ci(k,i)=0.0 !local extrema, so no slope
endif
enddo !i
endif !PCM:PLM
enddo !k
return
end subroutine hybgen_plm_coefs
subroutine hybgen_plm_remap(si,pi,dpi,ci, &
so,po,ki,ko,ks,thin)
implicit none
!
integer ki,ko,ks
real si(ki,ks),pi(ki+1),dpi(ki),ci(ki,ks), &
so(ko,ks),po(ko+1),thin
!
!-----------------------------------------------------------------------
! 1) remap from one set of vertical cells to another.
! method: piecewise linear across each input cell
! the output is the average of the interpolation
! profile across each output cell.
!
! van Leer, B., 1977, J. Comp. Phys., 23 276-299.
!
! 2) input arguments:
! si - initial scalar fields in pi-layer space
! pi - initial layer interface depths (non-negative)
! pi( 1) is the surface
! pi(ki+1) is the bathymetry
! pi(k+1) >= pi(k)
! dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k))
! ci - coefficents (slopes) from hybgen_plm_coefs
! profile(y)=si+ci*(y-1), 0<=y<=1
! ki - number of input layers
! ko - number of output layers
! ks - number of fields
! po - target interface depths (non-negative)
! po( 1) is the surface
! po(ko+1) is the bathymetry (== pi(ki+1))
! po(k+1) >= po(k)
! thin - layer thickness (>0) that can be ignored
!
! 3) output arguments:
! so - scalar fields in po-layer space
!
! 4) Tim Campbell, Mississippi State University, October 2002.
! Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007.
!-----------------------------------------------------------------------
!
integer i,k,l,lb,lt
real c0,qb0,qb1,qt0,qt1,xb,xt,zb,zt,zx,o
real*8 sz
real si_min(ks),si_max(ks)
!
! --- inforce minval(si(:,i)) <= minval(so(:,i)) and
! --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks
! --- in particular this inforces non-negativity, e.g. of tracers
! --- only required due to finite precision
!
do i= 1,ks
si_min(i) = minval(si(:,i))
si_max(i) = maxval(si(:,i))
enddo !i
!
zx=pi(ki+1) !maximum depth
zb=max(po(1),pi(1))
lb=1
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
do k= 1,ko !output layers
zt = zb
zb = min(po(k+1),zx)
! write(lp,*) 'k,zt,zb = ',k,zt,zb
lt=lb !top will always correspond to bottom of previous
!find input layer containing bottom output interface
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
if (zb-zt.le.thin .or. zt.ge.zx) then
if (k.ne.1) then
!
! --- thin or bottomed layer, values taken from layer above
!
do i= 1,ks
so(k,i) = so(k-1,i)
enddo !i
else !thin surface layer
do i= 1,ks
so(k,i) = si(k,i)
enddo !i
endif
else
!
! form layer averages.
! use PPM-like logic (may not have minimum operation count)
!
! if (pi(lb).gt.zt) then
! write(lp,*) 'bad lb = ',lb
! stop
! endif
xt=(zt-pi(lt))/max(dpi(lt),thin)
xb=(zb-pi(lb))/max(dpi(lb),thin)
if (lt.ne.lb) then !multiple layers
qt0 = (1.0-xt)
qt1 = (1.0-xt**2)*0.5
qb0 = xb
qb1 = xb**2 *0.5
do i= 1,ks
o = si((lt+lb)/2,i) !offset to reduce round-off
c0 = si(lt,i) - o - 0.5*ci(lt,i)
sz= dpi(lt)*(c0*qt0 + ci(lt,i)*qt1)
do l=lt+1,lb-1
sz = sz+dpi(l)*(si(l,i) - o)
enddo !l
c0 = si(lb,i) - o - 0.5*ci(lb,i)
sz = sz+dpi(lb)*(c0*qb0 + ci(lb,i)*qb1)
so(k,i) = o + sz/(zb-zt) !zb-zt>=thin
so(k,i) = max( si_min(i), so(k,i) )
so(k,i) = min( si_max(i), so(k,i) )
enddo !i
else !single layer
qt1 = (xb**2-xt**2 - (xb-xt))*0.5
do i= 1,ks
sz = dpi(lt)*(ci(lt,i)*qt1)
so(k,i) = si(lt,i) + sz/(zb-zt) !zb-zt>=thin
so(k,i) = max( si_min(i), so(k,i) )
so(k,i) = min( si_max(i), so(k,i) )
enddo !i
endif
endif !thin:std layer
enddo !k
return
end subroutine hybgen_plm_remap
subroutine hybgen_ppm_coefs(s,dp,lc,ci,kk,ks,thin)
implicit none
!
integer kk,ks
logical lc(kk)
real s(kk,ks),dp(kk),ci(kk,ks,3),thin
!
!-----------------------------------------------------------------------
! 1) coefficents for remaping from one set of vertical cells to another.
! method: monotonic piecewise parabolic across each input cell
!
! Colella, P. & P.R. Woodward, 1984, J. Comp. Phys., 54, 174-201.
!
! 2) input arguments:
! s - initial scalar fields in pi-layer space
! dp - initial layer thicknesses (>=thin)
! lc - use PCM for selected layers
! kk - number of layers
! ks - number of fields
! thin - layer thickness (>0) that can be ignored
!
! 3) output arguments:
! ci - coefficents for hybgen_ppm_remap
! profile(y)=ci.1+ci.2*y+ci.3*y^2, 0<=y<=1
!
! 4) Tim Campbell, Mississippi State University, October 2002.
! Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007.
!-----------------------------------------------------------------------
!
integer j,i
real da,a6,slj,scj,srj
real as(kk),al(kk),ar(kk)
real dpjp(kk), dp2jp(kk), dpj2p(kk), &
qdpjp(kk),qdp2jp(kk),qdpj2p(kk),dpq3(kk),qdp4(kk)
!
!compute grid metrics
do j=1,kk-1
dpjp( j) = dp(j) + dp(j+1)
dp2jp(j) = dp(j) + dpjp(j)
dpj2p(j) = dpjp(j) + dp(j+1)
qdpjp( j) = 1.0/dpjp( j)
qdp2jp(j) = 1.0/dp2jp(j)
qdpj2p(j) = 1.0/dpj2p(j)
enddo !j
dpq3(2) = dp(2)/(dp(1)+dpjp(2))
do j=3,kk-1
dpq3(j) = dp(j)/(dp(j-1)+dpjp(j)) !dp(j)/ (dp(j-1)+dp(j)+dp(j+1))
qdp4(j) = 1.0/(dpjp(j-2)+dpjp(j)) !1.0/(dp(j-2)+dp(j-1)+dp(j)+dp(j+1))
enddo !j
!
do i= 1,ks
!Compute average slopes: Colella, Eq. (1.8)
as(1)=0.
do j=2,kk-1
if (lc(j) .or. dp(j).le.thin) then !use PCM
as(j) = 0.0
else
slj=s(j, i)-s(j-1,i)
srj=s(j+1,i)-s(j, i)
if (slj*srj.gt.0.) then
scj=dpq3(j)*( dp2jp(j-1)*srj*qdpjp(j) &
+dpj2p(j) *slj*qdpjp(j-1) )
as(j)=sign(min(abs(2.0*slj),abs(scj),abs(2.0*srj)),scj)
else
as(j)=0.
endif
endif !PCM:PPM
enddo !j
as(kk)=0.
!Compute "first guess" edge values: Colella, Eq. (1.6)
al(1)=s(1,i) !1st layer PCM
ar(1)=s(1,i) !1st layer PCM
al(2)=s(1,i) !1st layer PCM
do j=3,kk-1
al(j)=s(j-1,i)+dp(j-1)*(s(j,i)-s(j-1,i))*qdpjp(j-1) &
+qdp4(j)*( &
2.*dp(j)*dp(j-1)*qdpjp(j-1)*(s(j,i)-s(j-1,i))* &
( dpjp(j-2)*qdp2jp(j-1) &
-dpjp(j) *qdpj2p(j-1) ) &
-dp(j-1)*as(j) *dpjp(j-2)*qdp2jp(j-1) &
+dp(j) *as(j-1)*dpjp(j) *qdpj2p(j-1) &
)
ar(j-1)=al(j)
enddo !j
ar(kk-1)=s(kk,i) !last layer PCM
al(kk) =s(kk,i) !last layer PCM
ar(kk) =s(kk,i) !last layer PCM
!Impose monotonicity: Colella, Eq. (1.10)
do j=2,kk-1
if (lc(j) .or. dp(j).le.thin) then !use PCM
al(j)=s(j,i)
ar(j)=s(j,i)
elseif ((s(j+1,i)-s(j,i))*(s(j,i)-s(j-1,i)).le.0.) then !local extremum
al(j)=s(j,i)
ar(j)=s(j,i)
else
da=ar(j)-al(j)
a6=6.0*s(j,i)-3.0*(al(j)+ar(j))
if (da*a6 .gt. da*da) then !peak in right half of zone
al(j)=3.0*s(j,i)-2.0*ar(j)
elseif (da*a6 .lt. -da*da) then !peak in left half of zone
ar(j)=3.0*s(j,i)-2.0*al(j)
endif
endif
enddo !j
!Set coefficients
do j=1,kk
if (al(j).ne.ar(j)) then
ci(j,i,1)=al(j)
ci(j,i,2)=ar(j)-al(j)
ci(j,i,3)=6.0*s(j,i)-3.0*(al(j)+ar(j))
else !PCM
ci(j,i,1)=al(j)
ci(j,i,2)=0.0
ci(j,i,3)=0.0
endif
enddo !j
enddo !i
return
end subroutine hybgen_ppm_coefs
subroutine hybgen_ppm_remap(si,pi,dpi,ci, &
so,po,ki,ko,ks,thin)
implicit none
!
integer ki,ko,ks
real si(ki,ks),pi(ki+1),dpi(ki),ci(ki,ks,3), &
so(ko,ks),po(ko+1),thin
!
!-----------------------------------------------------------------------
! 1) remap from one set of vertical cells to another.
! method: monotonic piecewise parabolic across each input cell
! the output is the average of the interpolation
! profile across each output cell.
! Colella, P. & P.R. Woodward, 1984, J. Comp. Phys., 54, 174-201.
!
! 2) input arguments:
! si - initial scalar fields in pi-layer space
! pi - initial layer interface depths (non-negative)
! pi( 1) is the surface
! pi(ki+1) is the bathymetry
! pi(k+1) >= pi(k)
! dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k))
! ci - coefficents from hybgen_ppm_coefs
! profile(y)=ci.1+ci.2*y+ci.3*y^2, 0<=y<=1
! ki - number of input layers
! ko - number of output layers
! ks - number of fields
! po - target interface depths (non-negative)
! po( 1) is the surface
! po(ko+1) is the bathymetry (== pi(ki+1))
! po(k+1) >= po(k)
! thin - layer thickness (>0) that can be ignored
!
! 3) output arguments:
! so - scalar fields in po-layer space
!
! 4) Tim Campbell, Mississippi State University, October 2002.
! Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007.
!-----------------------------------------------------------------------
!
integer i,k,l,lb,lt
real qb0,qb1,qb2,qt0,qt1,qt2,xb,xt,zb,zt,zx,o
real*8 sz
real si_min(ks),si_max(ks)
!
! --- inforce minval(si(:,i)) <= minval(so(:,i)) and
! --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks
! --- in particular this inforces non-negativity, e.g. of tracers
! --- only required due to finite precision
!
do i= 1,ks
si_min(i) = minval(si(:,i))
si_max(i) = maxval(si(:,i))
enddo !i
!
zx=pi(ki+1) !maximum depth
zb=max(po(1),pi(1))
lb=1
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
do k= 1,ko !output layers
zt = zb
zb = min(po(k+1),zx)
! write(lp,*) 'k,zt,zb = ',k,zt,zb
lt=lb !top will always correspond to bottom of previous
!find input layer containing bottom output interface
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
if (zb-zt.le.thin .or. zt.ge.zx) then
if (k.ne.1) then
!
! --- thin or bottomed layer, values taken from layer above
!
do i= 1,ks
so(k,i) = so(k-1,i)
enddo !i
else !thin surface layer
do i= 1,ks
so(k,i) = si(k,i)
enddo !i
endif
else
!
! form layer averages.
!
! if (pi(lb).gt.zt) then
! write(lp,*) 'bad lb = ',lb
! stop
! endif
xt=(zt-pi(lt))/max(dpi(lt),thin)
xb=(zb-pi(lb))/max(dpi(lb),thin)
if (lt.ne.lb) then !multiple layers
qt0 = (1.0-xt)
qt1 = (1.-xt**2)*0.5
qt2 = (1.-xt**3)/3.0
qb0 = xb
qb1 = xb**2 *0.5
qb2 = xb**3 /3.0
do i= 1,ks
o = si((lt+lb)/2,i) !offset to reduce round-off
sz = dpi(lt)*( (ci(lt,i,1)-o)*qt0 &
+(ci(lt,i,2)+ &
ci(lt,i,3) ) *qt1 &
-ci(lt,i,3) *qt2 )
do l=lt+1,lb-1
sz = sz+dpi(l)*(si(l,i)-o)
enddo !l
sz = sz+dpi(lb)*( (ci(lb,i,1)-o)*qb0 &
+(ci(lb,i,2)+ &
ci(lb,i,3) ) *qb1 &
-ci(lb,i,3) *qb2 )
so(k,i) = o + sz/(zb-zt) !zb-zt>=thin
so(k,i) = max( si_min(i), so(k,i) )
so(k,i) = min( si_max(i), so(k,i) )
enddo !i
else !single layer
qt0 = (xb-xt)
qt1 = (xb**2-xt**2)*0.5
qt2 = (xb**3-xt**3)/3.0
do i= 1,ks
o = si( lt,i) !offset to reduce round-off
sz = dpi(lt)*( (ci(lt,i,1)-o)*qt0 &
+(ci(lt,i,2)+ &
ci(lt,i,3) ) *qt1 &
-ci(lt,i,3) *qt2 )
so(k,i) = o + sz/(zb-zt) !zb-zt>=thin
so(k,i) = max( si_min(i), so(k,i) )
so(k,i) = min( si_max(i), so(k,i) )
enddo !i
endif
endif !thin:std layer
enddo !k
return
end subroutine hybgen_ppm_remap
subroutine hybgen_weno_coefs(s,dp,lc,ci,kk,ks,thin)
implicit none
!
integer kk,ks
logical lc(kk)
real s(kk,ks),dp(kk),ci(kk,ks,2),thin
!
!-----------------------------------------------------------------------
! 1) coefficents for remaping from one set of vertical cells to another.
! method: monotonic WENO-like alternative to PPM across each input cell
! a second order polynomial approximation of the profiles
! using a WENO reconciliation of the slopes to compute the
! interfacial values
!
! REFERENCE?
!
! 2) input arguments:
! s - initial scalar fields in pi-layer space
! dp - initial layer thicknesses (>=thin)
! lc - use PCM for selected layers
! kk - number of layers
! ks - number of fields
! thin - layer thickness (>0) that can be ignored
!
! 3) output arguments:
! ci - coefficents for hybgen_weno_remap
! ci.1 is value at interface above
! ci.2 is value at interface below
!
! 4) Laurent Debreu, Grenoble.
! Alan J. Wallcraft, Naval Research Laboratory, July 2008.
!-----------------------------------------------------------------------
!
real, parameter :: dsmll=1.0e-8
!
integer j,i
real q,q01,q02,q001,q002
real qdpjm(kk),qdpjmjp(kk),dpjm2jp(kk)
real zw(kk+1,3)
!compute grid metrics
do j=2,kk-1
qdpjm( j) = 1.0/(dp(j-1) + dp(j))
qdpjmjp(j) = 1.0/(dp(j-1) + dp(j) + dp(j+1))
dpjm2jp(j) = dp(j-1) + 2.0*dp(j) + dp(j+1)
enddo !j
j=kk
qdpjm( j) = 1.0/(dp(j-1) + dp(j))
!
do i= 1,ks
do j=2,kk
zw(j,3) = qdpjm(j)*(s(j,i)-s(j-1,i))
enddo !j
j = 1 !PCM first layer
ci(j,i,1) = s(j,i)
ci(j,i,2) = s(j,i)
zw(j, 1) = 0.0
zw(j, 2) = 0.0
do j=2,kk-1
if (lc(j) .or. dp(j).le.thin) then !use PCM
ci(j,i,1) = s(j,i)
ci(j,i,2) = s(j,i)
zw(j, 1) = 0.0
zw(j, 2) = 0.0
else
q001 = dp(j)*zw(j+1,3)
q002 = dp(j)*zw(j, 3)
if (q001*q002 < 0.0) then
q001 = 0.0
q002 = 0.0
endif
q01 = dpjm2jp(j)*zw(j+1,3)
q02 = dpjm2jp(j)*zw(j, 3)
if (abs(q001) > abs(q02)) then
q001 = q02
endif
if (abs(q002) > abs(q01)) then
q002 = q01
endif
q = (q001-q002)*qdpjmjp(j)
q001 = q001-q*dp(j+1)
q002 = q002+q*dp(j-1)
ci(j,i,2) = s(j,i)+q001
ci(j,i,1) = s(j,i)-q002
zw( j,1) = (2.0*q001-q002)**2
zw( j,2) = (2.0*q002-q001)**2
endif !PCM:WEND
enddo !j
j = kk !PCM last layer
ci(j,i,1) = s(j,i)
ci(j,i,2) = s(j,i)
zw(j, 1) = 0.0
zw(j, 2) = 0.0
do j=2,kk
q002 = max(zw(j-1,2),dsmll)
q001 = max(zw(j, 1),dsmll)
zw(j,3) = (q001*ci(j-1,i,2)+q002*ci(j,i,1))/(q001+q002)
enddo !j
zw( 1,3) = 2.0*s( 1,i)-zw( 2,3) !not used?
zw(kk+1,3) = 2.0*s(kk,i)-zw(kk,3) !not used?
do j=2,kk-1
if (.not.(lc(j) .or. dp(j).le.thin)) then !don't use PCM
q01 = zw(j+1,3)-s(j,i)
q02 = s(j,i)-zw(j,3)
q001 = 2.0*q01
q002 = 2.0*q02
if (q01*q02 < 0.0) then
q01 = 0.0
q02 = 0.0
elseif (abs(q01) > abs(q002)) then
q01 = q002
elseif (abs(q02) > abs(q001)) then
q02 = q001
endif
ci(j,i,1) = s(j,i)-q02
ci(j,i,2) = s(j,i)+q01
endif !PCM:WEND
enddo !j
enddo !i
return
end subroutine hybgen_weno_coefs
subroutine hybgen_weno_remap(si,pi,dpi,ci, &
so,po,ki,ko,ks,thin)
implicit none
!
integer ki,ko,ks
real si(ki,ks),pi(ki+1),dpi(ki),ci(ki,ks,2), &
so(ko,ks),po(ko+1),thin
!
!-----------------------------------------------------------------------
! 1) remap from one set of vertical cells to another.
! method: monotonic WENO-like alternative to PPM across each input cell
! a second order polynomial approximation of the profiles
! using a WENO reconciliation of the slopes to compute the
! interfacial values
! the output is the average of the interpolation
! profile across each output cell.
!
! REFERENCE?
!
! 2) input arguments:
! si - initial scalar fields in pi-layer space
! pi - initial layer interface depths (non-negative)
! pi( 1) is the surface
! pi(ki+1) is the bathymetry
! pi(k+1) >= pi(k)
! dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k))
! ci - coefficents from hybgen_weno_coefs
! ci.1 is value at interface above
! ci.2 is value at interface below
! ki - number of input layers
! ko - number of output layers
! ks - number of fields
! po - target interface depths (non-negative)
! po( 1) is the surface
! po(ko+1) is the bathymetry (== pi(ki+1))
! po(k+1) >= po(k)
! thin - layer thickness (>0) that can be ignored
!
! 3) output arguments:
! so - scalar fields in po-layer space
!
! 4) Laurent Debreu, Grenoble.
! Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007.
!-----------------------------------------------------------------------
!
integer i,k,l,lb,lt
real dpb,dpt,qb0,qb1,qb2,qt0,qt1,qt2,xb,xt,zb,zt,zx,o
real*8 sz
real si_min(ks),si_max(ks)
!
! --- inforce minval(si(:,i)) <= minval(so(:,i)) and
! --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks
! --- in particular this inforces non-negativity, e.g. of tracers
! --- only required due to finite precision
!
do i= 1,ks
si_min(i) = minval(si(:,i))
si_max(i) = maxval(si(:,i))
enddo !i
!
zx=pi(ki+1) !maximum depth
zb=max(po(1),pi(1))
lb=1
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
do k= 1,ko !output layers
zt = zb
zb = min(po(k+1),zx)
! write(lp,*) 'k,zt,zb = ',k,zt,zb
lt=lb !top will always correspond to bottom of previous
!find input layer containing bottom output interface
do while (pi(lb+1).lt.zb .and. lb.lt.ki)
lb=lb+1
enddo
if (zb-zt.le.thin .or. zt.ge.zx) then
if (k.ne.1) then
!
! --- thin or bottomed layer, values taken from layer above
!
do i= 1,ks
so(k,i) = so(k-1,i)
enddo !i
else !thin surface layer
do i= 1,ks
so(k,i) = si(k,i)
enddo !i
endif
else
!
! form layer averages.
!
! if (pi(lb).gt.zt) then
! write(lp,*) 'bad lb = ',lb
! stop
! endif
xt=(zt-pi(lt))/max(dpi(lt),thin)
xb=(zb-pi(lb))/max(dpi(lb),thin)
if (lt.ne.lb) then !multiple layers
dpt = pi(lt+1)-zt
dpb = zb-pi(lb)
qt1 = xt*(xt-1.0)
qt2 = qt1+xt
qt0 = 1.0-qt1-qt2
qb1 = (xb-1.0)**2
qb2 = qb1-1.0+xb
qb0 = 1.0-qb1-qb2
do i= 1,ks
o = si((lt+lb)/2,i) !offset to reduce round-off
sz = dpt*(qt0*(si(lt,i) -o) + &
qt1*(ci(lt,i,1)-o) + &
qt2*(ci(lt,i,2)-o) )
do l=lt+1,lb-1
sz = sz+dpi(l)*(si(l,i) - o)
enddo !l
sz = sz + dpb*(qb0*(si(lb,i) -o) + &
qb1*(ci(lb,i,1)-o) + &
qb2*(ci(lb,i,2)-o) )
so(k,i) = o + sz/(zb-zt) !zb-zt>=thin
so(k,i) = max( si_min(i), so(k,i) )
so(k,i) = min( si_max(i), so(k,i) )
enddo !i
else !single layer
qt1 = xb**2 + xt**2 + xb*xt + 1.0 - 2.0*(xb+xt)
qt2 = qt1 - 1.0 + (xb+xt)
do i= 1,ks
o = si(lt,i) !offset to reduce round-off
sz=qt1*(ci(lt,i,1)-o) + &
qt2*(ci(lt,i,2)-o)
so(k,i) = o + sz
so(k,i) = max( si_min(i), so(k,i) )
so(k,i) = min( si_max(i), so(k,i) )
enddo !i
endif !layers
endif !thin:std layer
enddo !k
return
end subroutine hybgen_weno_remap
!
!
!> Revision history:
!>
!> Feb. 2000 -- total rewrite to convert to 'newzp' approach
!> Jul. 2000 -- added hybgenj for OpenMP parallelization
!> Oct. 2000 -- added hybgenbj to simplify OpenMP logic
!> Nov. 2000 -- fill massless layers on sea floor with salinity from above
!> Nov. 2000 -- unmixing of deepest inflated layer uses th&T&S from above
!> Nov. 2000 -- ignored isopycnic variance is now 0.002
!> Nov. 2000 -- iterate to correct for cabbeling
!> Nov. 2000 -- allow for "blocking" interior layers
!> Nov. 2000 -- hybflg selects conserved fields (any two of T/S/th)
!> Nov. 2002 -- replace PCM remapping with PLM when non-isopycnal
!> Apr. 2003 -- added dp00i for thinner minimum layers away from the surface
!> Dec. 2003 -- fixed tracer bug when deepest inflated layer is too light
!> Dec. 2003 -- improved water column conservation
!> Dec. 2003 -- compile time option for explicit water column conservation
!> Dec. 2003 -- ignored isopycnic variance is now 0.0001
!> Jan. 2004 -- shifted qqmn,qqmx range now used in cushion function
!> Mar. 2004 -- minimum thickness no longer enforced in near-bottom layers
!> Mar. 2004 -- ignored isopycnic variance is now epsil (i.e. very small)
!> Mar. 2004 -- relaxation to isopycnic layers controled via hybrlx
!> Mar. 2004 -- relaxation removes the need to correct for cabbeling
!> Mar. 2004 -- modified unmixing selection criteria
!> Mar. 2004 -- added isotop (topiso) for isopycnal layer minimum depths
!> Jun. 2005 -- hybrlx (qhybrlx) now input via blkdat.input
!> Jan. 2007 -- hybrlx now only active below "fixed coordinate" surface layers
!> Aug. 2007 -- removed mxlkta logic
!> Sep. 2007 -- added hybmap and hybiso for PCM,PLM,PPM remaper selection
!> Jan. 2008 -- updated logic for two layers (one too dense, other too light)
!> Jul. 2008 -- Added WENO-like, and bugfix to PPM for lcm==.true.
!> Aug. 2008 -- Use WENO-like (vs PPM) for most velocity remapping
!> Aug. 2008 -- Switch more thin near-isopycnal layers to PCM remapping
!> May 2009 -- New action when deepest inflated layer is very light
!> Oct 2010 -- updated test for deepest inflated layer too light
!> Oct 2010 -- updated sanity check on deltm
!> July 2010 -- Maintain vertical minval and maxval in remapping
!> Aug 2011 -- Option to apply Robert-Asselin filter to hybgen's updated dp
!> Mar 2012 -- Replaced dssk with dpns and dsns, see blkdat.F for info
!> July 2012 -- Bugfix for tracer in too-light deepest inflated layer
!> Sep 2012 -- Added ndebug_tracer for tracer debuging
!> Sep 2012 -- Don't unmix in terrain-following regime
!> Apr. 2013 -- Detect all fixed coordinate layers
!> Apr. 2013 -- bugfix for constant thickness layer k = 1
!> May 2014 - use land/sea masks (e.g. ip) to skip land
!> Feb. 2015 - when too light, include layer k+2 in "near bottom" logic
!> Apr. 2015 - fixed a k+3 for k=kk-1 (k+3=kk+2) bug
!> Aug. 2015 - changed k-2 to k-N in lowest layer "runaway" unmixing test
!> Aug. 2015 - overturn with the layer above if bottom layer is very light
!> Aug. 2015 - entrain into too dense layer (only move upper interface up)
!> Aug. 2015 - allow entrainment to increase fixlay by 1