subroutine hybgen(m,n) use mod_xc ! HYCOM communication interface use mod_pipe ! HYCOM debugging interface c c --- hycom version 1.0 implicit none c include 'common_blocks.h' c integer m,n c c --- --------------------- c --- hybrid grid generator c --- --------------------- c logical, parameter :: lpipe_hybgen=.false. !for debugging c integer i,j,k,l character text*12 c 103 format (i9,2i5,a/(33x,i3,2f8.3,f8.3,f9.3,f9.2)) cdiag if (itest.gt.0 .and. jtest.gt.0) then cdiag write (lp,103) nstep,itest+i0,jtest+j0, cdiag. ' entering hybgen: temp saln dens thkns dpth', cdiag. (k,temp(itest,jtest,k,n),saln(itest,jtest,k,n), cdiag. th3d(itest,jtest,k,n)+thbase,dp(itest,jtest,k,n)*qonem, cdiag. p(itest,jtest,k+1)*qonem,k=1,kk) cdiag endif c call xctilr(dpmixl( 1-nbdy,1-nbdy, n),1, 1, 1,1, halo_ps) c margin = 0 ! no horizontal derivatives c !$OMP PARALLEL DO PRIVATE(j) !$OMP& SHARED(m,n) !$OMP& SCHEDULE(STATIC,jblk) do j=1-margin,jj+margin call hybgenaj(m,n, j) enddo !$OMP END PARALLEL DO c c --- vertical momentum flux across moving interfaces (the s-dot term in the c --- momentum equation) - required to locally conserve momentum when hybgen c --- moves vertical coordinates first, store old interface pressures in c --- -pu-, -pv- c !$OMP PARALLEL DO PRIVATE(j,l,i,k) !$OMP& SCHEDULE(STATIC,jblk) do j=1-margin,jj+margin do l=1,isu(j) do i=max(1-margin,ifu(j,l)),min(ii+margin,ilu(j,l)) pu(i,j,1)=0.0 pu(i,j,2)=dpu(i,j,1,n) enddo !i do k=2,kk do i=max(1-margin,ifu(j,l)),min(ii+margin,ilu(j,l)) pu(i,j,k+1)=pu(i,j,k)+dpu(i,j,k,n) enddo !i enddo !k enddo !l do l=1,isv(j) do i=max(1-margin,ifv(j,l)),min(ii+margin,ilv(j,l)) pv(i,j,1)=0.0 pv(i,j,2)=dpv(i,j,1,n) enddo !i do k=2,kk do i=max(1-margin,ifv(j,l)),min(ii+margin,ilv(j,l)) pv(i,j,k+1)=pv(i,j,k)+dpv(i,j,k,n) enddo !i enddo !k enddo !l enddo !j !$OMP END PARALLEL DO c c --- 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, margin) ! p's halo extended by dpudpv c if (lpipe .and. lpipe_hybgen) then c --- 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,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 endif c !$OMP PARALLEL DO PRIVATE(j) !$OMP& SHARED(m,n) !$OMP& SCHEDULE(STATIC,jblk) do j=1-margin,jj+margin call hybgenbj(m,n, j) enddo !$OMP END PARALLEL DO c return end subroutine hybgen subroutine hybgenaj(m,n,j ) use mod_xc ! HYCOM communication interface implicit none c include 'common_blocks.h' c integer m,n, j c c --- -------------------------------------------- c --- hybrid grid generator, single j-row (part A). c --- -------------------------------------------- c logical, parameter :: lunmix=.true. !unmix a too light deepest layer logical, parameter :: lconserve=.false. !explicitly conserve each column c double precision asum( mxtrcr+4,3) real offset(mxtrcr+4) c 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,qtr,qts,thkbop, & zthk,dpthin integer i,k,ka,kp,ktr,l,fixlay,nums1d character*12 cinfo c double precision, parameter :: dsmll=1.0d-8 double precision, parameter :: zp5=0.5 !for sign function c c --- c u s h i o n function (from Bleck & Benjamin, 1992): c --- if delp >= qqmx*dp0 >> dp0, -cushn- returns -delp- c --- if delp <= qqmn*dp0 << -dp0, -cushn- returns -dp0- c 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) c 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)) c dpthin = 0.001*onemm thkbop = thkbot*onem hybrlx = 1.0/qhybrlx c if (mxlmy) then nums1d = ntracr + 4 else nums1d = ntracr + 2 endif c if (.not.isopcm) then 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 c do l=1,isp(j) do i=max(1-margin,ifp(j,l)),min(ii+margin,ilp(j,l)) c dp0cum(1)=0.0 qhrlx( 1)=1.0 !no relaxation in top layer dp0ij( 1)=min( dp0k(1), max( ds0k(1), dssk(1)*depths(i,j) ) ) 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 c --- q is dp0k(k) when in surface fixed coordinates c --- 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,max( ds0k(k), dssk(k)*depths(i,j) ) ) dp0cum(k+1)=dp0cum(k)+dp0ij(k) p(i,j, k+1)=p(i,j,k)+dp(i,j,k,n) enddo !k c c --- 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 qhrlx(k+1)=1.0 !no relaxation in fixed layers fixlay = fixlay+1 enddo !k cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i3)') cdiag & 'hybgen, always-fixed coordinate layers: 1 to ', cdiag & fixlay cdiag call flush(lp) cdiag endif !debug c cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write (lp,'(a/(i6,1x,2f8.3,2f9.3,f9.3))') cdiag . 'hybgen: thkns minthk dpth mindpth hybrlx', cdiag . (k,dp(i,j,k,n)*qonem, dp0ij(k)*qonem, cdiag . p(i,j,k+1)*qonem,dp0cum(k+1)*qonem, cdiag . 1.0/qhrlx(k+1), cdiag . k=1,kk) cdiag endif !debug c c --- identify the deepest layer kp with significant thickness (> dpthin) c 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 c k=kp !at least 2 c cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i3)') cdiag & 'hybgen, deepest inflated layer:',k cdiag call flush(lp) cdiag endif !debug c ka = max(k-2,1) !k might be 2 if (k.gt.fixlay+1 .and. & 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 c c --- water in the deepest inflated layer with significant thickness c --- (kp) is too light, and it is lighter than the two layers above. c --- c --- this should only occur when relaxing or nudging layer thickness c --- and is a bug (bad interaction with tsadvc) even in those cases c --- c --- entrain the entire layer into the one above c--- 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 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 (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 c --- 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 cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i3,f6.3,5f8.3)') cdiag & 'hybgen, 11(+):', cdiag & k-1,q,temp(i,j,k-1,n),saln(i,j,k-1,n), cdiag & th3d(i,j,k-1,n)+thbase,theta(i,j,k-1)+thbase cdiag call flush(lp) cdiag endif !debug endif c if (lunmix .and. !usually .true. & k.gt.fixlay+1 .and. & 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 c c --- water in the deepest inflated layer with significant thickness c --- (kp) is too light, with the layer above near-isopycnal c --- c --- split layer into 2 sublayers, one near the desired density c --- and one exactly matching the T&S properties of layer k-1. c --- To prevent "runaway" T or S, the result satisfies either c --- abs(T.k - T.k-1) <= abs(T.k-2 - T.k-1) or c --- abs(S.k - S.k-1) <= abs(S.k-2 - S.k-1) c --- It is also limited to a 50% change in layer thickness. c cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i3)') cdiag & 'hybgen, deepest inflated layer too light (stable):',k cdiag call flush(lp) cdiag endif !debug c delsm=abs(saln(i,j,k-2,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,k-2,n)-temp(i,j,k-1,n)) delt =abs(temp(i,j,k-1,n)-temp(i,j,k, n)) c --- sanity check on deltm and delsm q=min(temp(i,j,k-2,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 c --- 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 qtr=p_hat/max(p_hat,p(i,j,k)-p(i,j,k-1)) !ok because <1.0 and >0.0 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)) cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i4,i3,5e12.3)') cdiag & 'hybgen, 10(+):', cdiag & k,ktr,p_hat,p(i,j,k),p(i,j,k-1), cdiag & qtr,tracer(i,j,k-1,n,ktr) cdiag call flush(lp) cdiag endif !debug endif !trcflg enddo !ktr endif !tracers if (mxlmy .and. p_hat.ne.0.0) then qtr=p_hat/(p(i,j,k)-p(i,j,k-1)) !ok because <1.0 and >0.0 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)) cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i4,i3,6e12.3)') cdiag & 'hybgen, 10(+):', cdiag & k,0,p_hat,p(i,j,k)-p(i,j,k-1),p(i,j,k+1)-p(i,j,k), cdiag & qtr,q2(i,j,k-1,n),q2l(i,j,k-1,n) cdiag call flush(lp) cdiag endif !debug endif cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i3,f6.3,5f8.3)') cdiag & 'hybgen, 10(+):', cdiag & k,q,temp(i,j,k,n),saln(i,j,k,n), cdiag & th3d(i,j,k,n)+thbase,theta(i,j,k)+thbase cdiag call flush(lp) cdiag endif !debug cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i3,f6.3,5f8.3)') cdiag & 'hybgen, 10(-):', cdiag & k,0.0,temp(i,j,k,n),saln(i,j,k,n), cdiag & th3d(i,j,k,n)+thbase,theta(i,j,k)+thbase cdiag call flush(lp) cdiag endif !debug endif !too light c c --- massless or near-massless (thickness < dpthin) layers c do k=kp+1,kk if (k.le.nhybrd) then c --- 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 c --- 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 c --- 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 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 c c --- store one-dimensional arrays of -temp-, -saln-, and -p- for the 'old' c --- 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 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) c if (isopcm) then if (k.le.fixlay) then lcm(k) = .false. !fixed layers are never PCM else c --- 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 c c --- try to restore isopycnic conditions by moving layer interfaces c --- qhrlx(k) are relaxation coefficients (inverse baroclinic time steps) c if (fixlay.ge.1) then c c --- maintain constant thickness, layer k = 1 k=1 p_hat=p(i,j,k)+dp0ij(k) p(i,j,k+1)=min(p_hat,p(i,j,k+2)) endif c do k=2,nhybrd c cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(cinfo,'(a9,i2.2,1x)') ' do 88 k=',k cdiag 109 format (i9,2i5,a,a/(i9,8x,a,a,i3,f9.2,f8.2,f9.2,f8.2)) cdiag write(lp,109) nstep,itest+i0,jtest+j0, cdiag. cinfo,': othkns odpth nthkns ndpth', cdiag. (nstep,cinfo,':',ka, cdiag. (pres(ka+1)- cdiag. pres(ka) )*qonem, cdiag. pres(ka+1) *qonem, cdiag. (p(itest,jtest,ka+1)- cdiag. p(itest,jtest,ka) )*qonem, cdiag. p(itest,jtest,ka+1) *qonem,ka=1,kk) cdiag call flush(lp) cdiag endif !debug c if (k.le.fixlay) then c c --- 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 c --- 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 c cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,i3.2,f8.2)') 'hybgen, fixlay :', cdiag& k+1,p(i,j,k+1)*qonem cdiag call flush(lp) cdiag endif !debug else c c --- do not maintain constant thickness, k > fixlay c if (th3d(i,j,k,n).gt.theta(i,j,k)+epsil .and. & k.gt.fixlay+1) then c c --- water in layer k is too dense c --- try to dilute with water from layer k-1 c --- do not move interface if k = fixlay + 1 c 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 c c --- if layer k-1 is too light, thicken the thinner of the two, c --- i.e. skip this layer if it is thicker. c cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write(lp,'(a,3x,i2.2,1pe13.5)') cdiag& 'hybgen, too dense:',k,th3d(i,j,k,n)-theta(i,j,k) cdiag call flush(lp) cdiag endif !debug c if ((theta(i,j,k)-th3d(i,j,k-1,n)).le.epsil) then c layer k-1 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 c c --- if layer k+1 does not touch the bottom then maintain minimum c --- thicknesses of layers k and k+1 as much as possible, c --- but permit layers to collapse to zero thickness at the bottom c if (p(i,j,k+2).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 c c --- vertical momentum flux across moving interfaces (the s-dot term in the c --- momentum equation) - required to locally conserve momentum when hybgen c --- moves vertical coordinates. c dpthin = 0.001*onemm c c --- always use high order remapping for velocity do k=1,kk lcm(k) = .false. !use same remapper for all layers enddo !k c do l=1,isu(j) do i=max(1-margin,ifu(j,l)),min(ii+margin,ilu(j,l)) c c --- 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,n) pres(k+1)=pu(i,j,k+1) dprs(k) =pres(k+1)-pres(k) dpi( k) =max(dprs(k),dpthin) enddo !k c c --- remap -u- profiles from the 'old' vertical grid onto the c --- 'new' vertical grid. c prsf(1) = pu(i,j,1) do k=1,kk pu(i,j,k+1) = pu(i,j,k) + dpu(i,j,k,n) !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,n) = f1d(k) else * --- thin near-bottom layer, zero total current u(i,j,k,n) = -ubavg(i,j,n) endif enddo !k c 104 format (i9,2i5,a/(33x,i3,f8.3,f9.3,f9.2)) cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write (lp,104) nstep,itest+i0,jtest+j0, cdiag& ' hybgen, do 412: u thkns dpth', cdiag& (k,s1d(k,1), cdiag& (pres(k+1)-pres(k))*qonem,pres(k+1)*qonem, cdiag& k,u(i,j,k,n), cdiag& dpu(i,j,k,n)*qonem,pu(i,j,k+1)*qonem, cdiag& k=1,kk) cdiag endif !debug c enddo !i enddo !l c do l=1,isv(j) do i=max(1-margin,ifv(j,l)),min(ii+margin,ilv(j,l)) c c --- 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,n) pres(k+1)=pv(i,j,k+1) dprs(k) =pres(k+1)-pres(k) dpi( k) =max(dprs(k),dpthin) enddo !k c c --- remap -v- profiles from the 'old' vertical grid onto the c --- 'new' vertical grid. c prsf(1) = pv(i,j,1) do k=1,kk pv(i,j,k+1) = pv(i,j,k) + dpv(i,j,k,n) !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,n) = f1d(k) else * --- thin near-bottom layer, zero total current v(i,j,k,n) = -vbavg(i,j,n) endif enddo !k c cdiag if (i.eq.itest .and. j.eq.jtest) then cdiag write (lp,104) nstep,itest+i0,jtest+j0, cdiag& ' hybgen, do 512: v thkns dpth', cdiag& (k,s1d(k,1), cdiag& (pres(k+1)-pres(k))*qonem,pres(k+1)*qonem, cdiag& k,v(i,j,k,n), cdiag& dpv(i,j,k,n)*qonem,pv(i,j,k+1)*qonem, cdiag& k=1,kk) cdiag endif !debug c enddo !i enddo !l c return end subroutine hybgenbj subroutine hybgen_pcm_remap(si,pi,dpi, & so,po,ki,ko,ks,thin) implicit none c integer ki,ko,ks real si(ki,ks),pi(ki+1),dpi(ki), & so(ko,ks),po(ko+1),thin c c----------------------------------------------------------------------- c 1) remap from one set of vertical cells to another. c method: piecewise constant across each input cell c the output is the average of the interpolation c profile across each output cell. c c PCM (donor cell) is the standard 1st order upwind method. c c 2) input arguments: c si - initial scalar fields in pi-layer space c pi - initial layer interface depths (non-negative) c pi( 1) is the surface c pi(ki+1) is the bathymetry c pi(k+1) >= pi(k) c dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k)) c ki - number of input layers c ko - number of output layers c ks - number of fields c po - target interface depths (non-negative) c po( 1) is the surface c po(ko+1) is the bathymetry (== pi(ki+1)) c po(k+1) >= po(k) c thin - layer thickness (>0) that can be ignored c c 3) output arguments: c so - scalar fields in po-layer space c c 4) Tim Campbell, Mississippi State University, October 2002. c Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007. c----------------------------------------------------------------------- c 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) c c --- inforce minval(si(:,i)) <= minval(so(:,i)) and c --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks c --- in particular this inforces non-negativity, e.g. of tracers c --- only required due to finite precision c do i= 1,ks si_min(i) = minval(si(:,i)) si_max(i) = maxval(si(:,i)) enddo !i c 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 c c --- thin or bottomed layer, values taken from layer above c 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 c c form layer averages. c use PPM-like logic (may not have minimum operation count) c * 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 c integer kk,ks logical lc(kk) real si(kk,ks),dpi(kk),ci(kk,ks),thin c c----------------------------------------------------------------------- c 1) coefficents for remaping from one set of vertical cells to another. c method: piecewise linear across each input cell with c monotonized central-difference limiter. c c van Leer, B., 1977, J. Comp. Phys., 23 276-299. c c 2) input arguments: c si - initial scalar fields in pi-layer space c dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k)) c lc - use PCM for selected layers c kk - number of layers c ks - number of fields c thin - layer thickness (>0) that can be ignored c c 3) output arguments: c ci - coefficents (slopes) for hybgen_plm_remap c profile(y)=si+ci*(y-1), 0<=y<=1 c c 4) Tim Campbell, Mississippi State University, October 2002. c Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007. c----------------------------------------------------------------------- c integer k,i real qcen,zbot,zcen,ztop c 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 c --- 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 c --- PLM (non-zero slope, but no new extrema) c --- layer value is si-0.5*ci at top interface, c --- and si+0.5*ci at bottom interface. c c --- monotonized central-difference limiter (van Leer, 1977, c --- JCP 23 pp 276-299). For a discussion of PLM limiters, see c --- 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 c integer ki,ko,ks real si(ki,ks),pi(ki+1),dpi(ki),ci(ki,ks), & so(ko,ks),po(ko+1),thin c c----------------------------------------------------------------------- c 1) remap from one set of vertical cells to another. c method: piecewise linear across each input cell c the output is the average of the interpolation c profile across each output cell. c c van Leer, B., 1977, J. Comp. Phys., 23 276-299. c c 2) input arguments: c si - initial scalar fields in pi-layer space c pi - initial layer interface depths (non-negative) c pi( 1) is the surface c pi(ki+1) is the bathymetry c pi(k+1) >= pi(k) c dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k)) c ci - coefficents (slopes) from hybgen_plm_coefs c profile(y)=si+ci*(y-1), 0<=y<=1 c ki - number of input layers c ko - number of output layers c ks - number of fields c po - target interface depths (non-negative) c po( 1) is the surface c po(ko+1) is the bathymetry (== pi(ki+1)) c po(k+1) >= po(k) c thin - layer thickness (>0) that can be ignored c c 3) output arguments: c so - scalar fields in po-layer space c c 4) Tim Campbell, Mississippi State University, October 2002. c Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007. c----------------------------------------------------------------------- c 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) c c --- inforce minval(si(:,i)) <= minval(so(:,i)) and c --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks c --- in particular this inforces non-negativity, e.g. of tracers c --- only required due to finite precision c do i= 1,ks si_min(i) = minval(si(:,i)) si_max(i) = maxval(si(:,i)) enddo !i c 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 c c --- thin or bottomed layer, values taken from layer above c 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 c c form layer averages. c use PPM-like logic (may not have minimum operation count) c * 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 c integer kk,ks logical lc(kk) real s(kk,ks),dp(kk),ci(kk,ks,3),thin c c----------------------------------------------------------------------- c 1) coefficents for remaping from one set of vertical cells to another. c method: monotonic piecewise parabolic across each input cell c c Colella, P. & P.R. Woodward, 1984, J. Comp. Phys., 54, 174-201. c c 2) input arguments: c s - initial scalar fields in pi-layer space c dp - initial layer thicknesses (>=thin) c lc - use PCM for selected layers c kk - number of layers c ks - number of fields c thin - layer thickness (>0) that can be ignored c c 3) output arguments: c ci - coefficents for hybgen_ppm_remap c profile(y)=ci.1+ci.2*y+ci.3*y^2, 0<=y<=1 c c 4) Tim Campbell, Mississippi State University, October 2002. c Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007. c----------------------------------------------------------------------- c 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) c !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 c 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 c integer ki,ko,ks real si(ki,ks),pi(ki+1),dpi(ki),ci(ki,ks,3), & so(ko,ks),po(ko+1),thin c c----------------------------------------------------------------------- c 1) remap from one set of vertical cells to another. c method: monotonic piecewise parabolic across each input cell c the output is the average of the interpolation c profile across each output cell. c Colella, P. & P.R. Woodward, 1984, J. Comp. Phys., 54, 174-201. c c 2) input arguments: c si - initial scalar fields in pi-layer space c pi - initial layer interface depths (non-negative) c pi( 1) is the surface c pi(ki+1) is the bathymetry c pi(k+1) >= pi(k) c dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k)) c ci - coefficents from hybgen_ppm_coefs c profile(y)=ci.1+ci.2*y+ci.3*y^2, 0<=y<=1 c ki - number of input layers c ko - number of output layers c ks - number of fields c po - target interface depths (non-negative) c po( 1) is the surface c po(ko+1) is the bathymetry (== pi(ki+1)) c po(k+1) >= po(k) c thin - layer thickness (>0) that can be ignored c c 3) output arguments: c so - scalar fields in po-layer space c c 4) Tim Campbell, Mississippi State University, October 2002. c Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007. c----------------------------------------------------------------------- c 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) c c --- inforce minval(si(:,i)) <= minval(so(:,i)) and c --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks c --- in particular this inforces non-negativity, e.g. of tracers c --- only required due to finite precision c do i= 1,ks si_min(i) = minval(si(:,i)) si_max(i) = maxval(si(:,i)) enddo !i c 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 c c --- thin or bottomed layer, values taken from layer above c 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 c c form layer averages. c * 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 c integer kk,ks logical lc(kk) real s(kk,ks),dp(kk),ci(kk,ks,2),thin c c----------------------------------------------------------------------- c 1) coefficents for remaping from one set of vertical cells to another. c method: monotonic WENO-like alternative to PPM across each input cell c a second order polynomial approximation of the profiles c using a WENO reconciliation of the slopes to compute the c interfacial values c c REFERENCE? c c 2) input arguments: c s - initial scalar fields in pi-layer space c dp - initial layer thicknesses (>=thin) c lc - use PCM for selected layers c kk - number of layers c ks - number of fields c thin - layer thickness (>0) that can be ignored c c 3) output arguments: c ci - coefficents for hybgen_weno_remap c ci.1 is value at interface above c ci.2 is value at interface below c c 4) Laurent Debreu, Grenoble. c Alan J. Wallcraft, Naval Research Laboratory, July 2008. c----------------------------------------------------------------------- c real, parameter :: dsmll=1.0e-8 c 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)) c 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 c integer ki,ko,ks real si(ki,ks),pi(ki+1),dpi(ki),ci(ki,ks,2), & so(ko,ks),po(ko+1),thin c c----------------------------------------------------------------------- c 1) remap from one set of vertical cells to another. c method: monotonic WENO-like alternative to PPM across each input cell c a second order polynomial approximation of the profiles c using a WENO reconciliation of the slopes to compute the c interfacial values c the output is the average of the interpolation c profile across each output cell. c c REFERENCE? c c 2) input arguments: c si - initial scalar fields in pi-layer space c pi - initial layer interface depths (non-negative) c pi( 1) is the surface c pi(ki+1) is the bathymetry c pi(k+1) >= pi(k) c dpi - initial layer thicknesses (dpi(k)=pi(k+1)-pi(k)) c ci - coefficents from hybgen_weno_coefs c ci.1 is value at interface above c ci.2 is value at interface below c ki - number of input layers c ko - number of output layers c ks - number of fields c po - target interface depths (non-negative) c po( 1) is the surface c po(ko+1) is the bathymetry (== pi(ki+1)) c po(k+1) >= po(k) c thin - layer thickness (>0) that can be ignored c c 3) output arguments: c so - scalar fields in po-layer space c c 4) Laurent Debreu, Grenoble. c Alan J. Wallcraft, Naval Research Laboratory, Aug. 2007. c----------------------------------------------------------------------- c 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) c c --- inforce minval(si(:,i)) <= minval(so(:,i)) and c --- maxval(si(:,i)) >= maxval(so(:,i)) for i=1:ks c --- in particular this inforces non-negativity, e.g. of tracers c --- only required due to finite precision c do i= 1,ks si_min(i) = minval(si(:,i)) si_max(i) = maxval(si(:,i)) enddo !i c 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 c c --- thin or bottomed layer, values taken from layer above c 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 c c form layer averages. c * 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 c c c> Revision history: c> c> Feb. 2000 -- total rewrite to convert to 'newzp' approach c> Jul. 2000 -- added hybgenj for OpenMP parallelization c> Oct. 2000 -- added hybgenbj to simplify OpenMP logic c> Nov. 2000 -- fill massless layers on sea floor with salinity from above c> Nov. 2000 -- unmixing of deepest inflated layer uses th&T&S from above c> Nov. 2000 -- ignored isopycnic variance is now 0.002 c> Nov. 2000 -- iterate to correct for cabbeling c> Nov. 2000 -- allow for "blocking" interior layers c> Nov. 2000 -- hybflg selects conserved fields (any two of T/S/th) c> Nov. 2002 -- replace PCM remapping with PLM when non-isopycnal c> Apr. 2003 -- added dp00i for thinner minimum layers away from the surface c> Dec. 2003 -- fixed tracer bug when deepest inflated layer is too light c> Dec. 2003 -- improved water column conservation c> Dec. 2003 -- compile time option for explicit water column conservation c> Dec. 2003 -- ignored isopycnic variance is now 0.0001 c> Jan. 2004 -- shifted qqmn,qqmx range now used in cushion function c> Mar. 2004 -- minimum thickness no longer enforced in near-bottom layers c> Mar. 2004 -- ignored isopycnic variance is now epsil (i.e. very small) c> Mar. 2004 -- relaxation to isopycnic layers controled via hybrlx c> Mar. 2004 -- relaxation removes the need to correct for cabbeling c> Mar. 2004 -- modified unmixing selection criteria c> Mar. 2004 -- added isotop (topiso) for isopycnal layer minimum depths c> Jun. 2005 -- hybrlx (qhybrlx) now input via blkdat.input c> Jan. 2007 -- hybrlx now only active below "fixed coordinate" surface layers c> Aug. 2007 -- removed mxlkta logic c> Sep. 2007 -- added hybmap and hybiso for PCM,PLM,PPM remaper selection c> Jan. 2008 -- updated logic for two layers (one too dense, other too light) c> Jul. 2008 -- Added WENO-like, and bugfix to PPM for lcm==.true. c> Aug. 2008 -- Use WENO-like (vs PPM) for most velocity remapping c> Aug. 2008 -- Switch more thin near-isopycnal layers to PCM remapping c> May 2009 -- New action when deepest inflated layer is very light c> Oct 2010 -- updated test for deepest inflated layer too light c> Oct 2010 -- updated sanity check on deltm c> Jul 2010 -- Maintain vertical minval and maxval in remapping