! ------------------------------------------------------------------------------- subroutine cyclic_ppm_massadvx1(im,imf,lev,nvars,delt,uc,qq,mass) ! ! compute local positive advection with mass conservation ! qq is advected by uc from past to next position ! ! author: hann-ming henry juang 2008 ! use physcons use layout1 ! implicit none ! integer im,imf,lev,nvars,mass real delt real uc(imf,lev) real qq(imf,lev,nvars) ! real past(im,nvars),next(im,nvars),da(im,nvars) real dxfact(im) real xreg(im+1),xpast(im+1),xnext(im+1) real uint(im+1) real dist(im+1),sc,ds real, parameter :: fa1 = 9./16. real, parameter :: fa2 = 1./16. integer i,k,n,nv sc = 2.0 * con_pi ds = sc / float(im) do i=1,im+1 xreg(i) = (i-1.5)*ds enddo nv = nvars ! do k=1,lev ! ! 4th order interpolation from mid point to cell interfaces ! do i=3,im-1 uint(i)=fa1*(uc(i,k)+uc(i-1,k))-fa2*(uc(i+1,k)+uc(i-2,k)) enddo uint(2)=fa1*(uc(2,k)+uc(1 ,k))-fa2*(uc(3,k)+uc(im ,k)) uint(1)=fa1*(uc(1,k)+uc(im,k))-fa2*(uc(2,k)+uc(im-1,k)) uint(im+1)=uint(1) uint(im )=fa1*(uc(im,k)+uc(im-1,k)) & & -fa2*(uc(1,k)+uc(im-2,k)) ! ! compute past and next positions of cell interfaces ! do i=1,im+1 dist(i) = uint(i) * delt enddo call def_cfl(im+1,dist,ds) do i=1,im+1 xpast(i) = xreg(i) - dist(i) xnext(i) = xreg(i) + dist(i) enddo if( mass.eq.1 ) then do i=1,im dxfact(i) = (xpast(i+1)-xpast(i)) / (xnext(i+1)-xnext(i)) enddo endif ! ! mass positive advection ! do n=1,nv past(1:im,n) = qq(1:im,k,n) enddo call cyclic_cell_ppm_intp(xreg,past,xpast,da,im,nv,im,im,sc) if( mass.eq.1) then do n=1,nv da(1:im,n) = da(1:im,n) * dxfact(1:im) enddo endif call cyclic_cell_ppm_intp(xnext,da,xreg,next,im,nv,im,im,sc) do n=1,nv qq(1:im,k,n) = next(1:im,n) enddo enddo return end subroutine cyclic_ppm_massadvx1 ! !------------------------------------------------------------------- ! ------------------------------------------------------------------------------- subroutine cyclic_ppm_massadvx(im,lev,nvars,delt,uc,qq,mass) ! ! compute local positive advection with mass conservation ! qq is advected by uc from past to next position ! ! author: hann-ming henry juang 2008 ! use physcons use layout1 ! implicit none ! integer im,lev,nvars,mass real delt real uc(im,lev) real qq(im,lev,nvars) ! real past(im,nvars),next(im,nvars),da(im,nvars) real dxfact(im) real xpast(im+1),xnext(im+1) real uint(im+1) real dist(im+1),sc,ds real, parameter :: fa1 = 9./16. real, parameter :: fa2 = 1./16. integer i,k,n,nv sc = ggloni(im+1)-ggloni(1) ds = sc / float(im) nv = nvars ! do k=1,lev ! ! 4th order interpolation from mid point to cell interfaces ! do i=3,im-1 uint(i)=fa1*(uc(i,k)+uc(i-1,k))-fa2*(uc(i+1,k)+uc(i-2,k)) enddo uint(2)=fa1*(uc(2,k)+uc(1 ,k))-fa2*(uc(3,k)+uc(im ,k)) uint(1)=fa1*(uc(1,k)+uc(im,k))-fa2*(uc(2,k)+uc(im-1,k)) uint(im+1)=uint(1) uint(im )=fa1*(uc(im,k)+uc(im-1,k)) & & -fa2*(uc(1,k)+uc(im-2,k)) ! ! compute past and next positions of cell interfaces ! do i=1,im+1 dist(i) = uint(i) * delt enddo call def_cfl(im+1,dist,ds) do i=1,im+1 xpast(i) = ggloni(i) - dist(i) xnext(i) = ggloni(i) + dist(i) enddo if( mass.eq.1 ) then do i=1,im dxfact(i) = (xpast(i+1)-xpast(i)) / (xnext(i+1)-xnext(i)) enddo endif ! ! mass positive advection ! do n=1,nv past(1:im,n) = qq(1:im,k,n) enddo call cyclic_cell_ppm_intp(ggloni,past,xpast,da,im,nv,im,im,sc) if( mass.eq.1) then do n=1,nv da(1:im,n) = da(1:im,n) * dxfact(1:im) enddo endif call cyclic_cell_ppm_intp(xnext,da,ggloni,next,im,nv,im,im,sc) do n=1,nv qq(1:im,k,n) = next(1:im,n) enddo enddo return end subroutine cyclic_ppm_massadvx ! !------------------------------------------------------------------- subroutine cyclic_ppm_massadvy(jm,lev,nvars,delt,vc,qq,mass) ! ! compute local positive advection with mass conserving ! qq will be advect by vc from past to next location with 2*delt ! ! author: hann-ming henry juang 2007 ! use physcons use layout1 ! implicit none ! integer jm,lev,nvars,mass real delt real vc(jm,lev) real qq(jm,lev,nvars) ! real var(jm) real past(jm,nvars),da(jm,nvars),next(jm,nvars) real dyfact(jm) real ypast(jm+1),ynext(jm+1) real dist (jm+1) real sc,ds real, parameter :: fa1 = 9./16. real, parameter :: fa2 = 1./16. integer n,k,j,jmh,nv ! ! preparations --------------------------- ! jmh = jm / 2 sc = gglati(jm+1)-gglati(1) ds = sc / float(jm) nv = nvars ! do k=1,lev ! do j=1,jmh var(j) = -vc(j ,k) * delt var(j+jmh) = vc(j+jmh,k) * delt enddo do j=3,jm-1 dist(j)=fa1*(var(j)+var(j-1))-fa2*(var(j+1)+var(j-2)) enddo dist(2)=fa1*(var(2)+var(1 ))-fa2*(var(3)+var(jm )) dist(1)=fa1*(var(1)+var(jm))-fa2*(var(2)+var(jm-1)) dist(jm+1)=dist(1) dist(jm )=fa1*(var(jm)+var(jm-1))-fa2*(var(1)+var(jm-2)) call def_cfl(jm+1,dist,ds) do j=1,jm+1 ypast(j) = gglati(j) - dist(j) ynext(j) = gglati(j) + dist(j) enddo if( mass.eq.1 ) then do j=1,jm dyfact(j) = (ypast(j+1)-ypast(j)) / (ynext(j+1)-ynext(j)) enddo endif ! ! advection all in y ! do n=1,nv past(1:jm,n) = qq(1:jm,k,n) enddo call cyclic_cell_ppm_intp(gglati,past,ypast,da,jm,nv,jm,jm,sc) if( mass.eq.1 ) then do n=1,nv da(1:jm,n) = da(1:jm,n) * dyfact(1:jm) enddo endif call cyclic_cell_ppm_intp(ynext,da,gglati,next,jm,nv,jm,jm,sc) do n=1,nv qq(1:jm,k,n) = next(1:jm,n) enddo ! enddo return end subroutine cyclic_ppm_massadvy ! !------------------------------------------------------------------------------- subroutine cyclic_ppm_intpx(lev,imp,imf,qq) ! ! do mass conserving interpolation from different grid at given latitude ! ! author: hann-ming henry juang 2008 ! use physcons use layout1 implicit none ! integer lev, imp, imf real qq(lonfull,lev) ! real old(lonfull,lev),new(lonfull,lev) real xpast(lonfull+1),xnext(lonfull+1) real two_pi,dxp,dxf,hfdxp,hfdxf,sc ! integer i,im ! im = lonfull ! .................................. if( imp.ne.imf ) then ! .................................. two_pi = 2.0 * con_pi dxp = two_pi / imp dxf = two_pi / imf hfdxp = 0.5 * dxp hfdxf = 0.5 * dxf do i=1,imp+1 xpast(i) = (i-1) * dxp - hfdxp enddo do i=1,imf+1 xnext(i) = (i-1) * dxf - hfdxf enddo sc=two_pi old(1:imp,1:lev)=qq(1:imp,1:lev) call cyclic_cell_ppm_intp(xpast,old,xnext,new,im,lev,imp,imf,sc) qq(1:imf,1:lev)=new(1:imf,1:lev) ! ................. endif ! ................. return end subroutine cyclic_ppm_intpx ! ! ------------------------------------------------------------------------- subroutine cyclic_cell_ppm_intp(pp,qq,pn,qn,lons,nv,lonp,lonn,sc) ! ! mass conservation in cyclic bc interpolation: interpolate a group ! of grid point coordiante call pp at interface with quantity qq at ! cell averaged to a group of new grid point coordinate call pn at ! interface with quantity qn at cell average with ppm spline. ! in horizontal with mass conservation is under the condition that ! variable value at pp(1)= pp(lons+1)=pn(lons+1) ! ! pp location at interfac point as input ! qq quantity at averaged-cell as input ! pn location at interface of new grid structure as input ! qn quantity at averaged-cell as output ! lons numer of cells for dimension ! lonp numer of cells for input ! lonn numer of cells for output ! levs number of vertical layers ! mono monotonicity o:no, 1:yes ! ! author : henry.juang@noaa.gov ! use physcons use layout1 ! implicit none ! real pp(lons+1) real qq(lons ,nv) real pn(lons+1) real qn(lons ,nv) integer lons,lonp,lonn,nv real sc ! real locs (3*lonp) real mass (3*lonp,nv) real hh (3*lonp) real fm (3*lonp) real fn (3*lonp) real dqmono(3*lonp,nv) real qmi (3*lonp,nv) real qpi (3*lonp,nv) real cyclic_length integer kstr,kend real pnmin,pnmax real dqi,dqimax,dqimin real tl,tl2,tl3,tlp,tlm,tlc real th,th2,th3,thp,thm,thc real dql(nv),dqh(nv) real dpp,dqq,c1,c2,cc,r3,r6 integer i,kl, kh, kk, kkl, kkh, n integer, parameter :: mono=1 ! ! cyclic_length = pp(lonp+1) - pp(1) cyclic_length = sc ! ! arrange input array cover output location with cyclic boundary condition ! locs(lonp+1:2*lonp) = pp(1:lonp) do i=1,lonp locs(i) = locs(i+lonp) - cyclic_length locs(i+2*lonp) = locs(i+lonp) + cyclic_length enddo mass(1 : lonp,1:nv) = qq(1:lonp,1:nv) mass(1+ lonp:2*lonp,1:nv) = qq(1:lonp,1:nv) mass(1+2*lonp:3*lonp,1:nv) = qq(1:lonp,1:nv) pnmin = pn(1) pnmax = pn(lonn+1) do i=2,lonn pnmin = min( pnmin, pn(i) ) pnmax = max( pnmax, pn(i) ) enddo if( pnmin.lt.locs(lonp+1) ) then do i=lonp,1,-1 if( pnmin.ge.locs(i) .and. pnmin.lt.locs(i+1) ) then kstr = i go to 10 endif enddo else do i=lonp+1,2*lonp if( pnmin.ge.locs(i) .and. pnmin.lt.locs(i+1) ) then kstr = i go to 10 endif enddo endif print *,' error: can not find kstr: pnmin locs(1) locs(2*lonp) ', & pnmin,locs(1),locs(2*lonp) print *,' error: pn(1) pn(2) pn(3) ',pn(1),pn(2),pn(3) 10 kstr=max(3,kstr) if( pnmax.lt.locs(2*lonp+1) ) then do i=2*lonp,lonp,-1 if( pnmax.ge.locs(i) .and. pnmax.lt.locs(i+1) ) then kend = i+1 go to 20 endif enddo else do i=2*lonp+1,3*lonp-1 if( pnmax.ge.locs(i) .and. pnmax.lt.locs(i+1) ) then kend = i+1 go to 20 endif enddo endif print *,' error: cannot get kend: pnmax locs(lonp) locs(3*lonp) ', & kend, pnmax,locs(lonp),locs(3*lonp) print *,' error: pn(lonn-1) pn(lonn) pn(lonn+1) ', & pn(lonn-1),pn(lonn),pn(lonn+1) 20 kend=min(3*lonp-2,kend) ! ! prepare grid spacing ! do i=kstr-2,kend+2 hh(i) = locs(i+1)-locs(i) enddo do i=kstr-1,kend+2 cc = 1./(hh(i)+hh(i-1)) fm(i) = hh(i ) * cc fn(i) = hh(i-1) * cc enddo ! ! prepare location with monotonic concerns ! do n=1,nv do i=kstr-2,kend+2 dqi = 0.25*(mass(i+1,n)-mass(i-1,n)) dqimax = max(mass(i-1,n),mass(i,n),mass(i+1,n)) - mass(i,n) dqimin = mass(i,n) - min(mass(i-1,n),mass(i,n),mass(i+1,n)) dqmono(i,n) = sign( min( abs(dqi), dqimin, dqimax ), dqi) enddo enddo ! ! compute value at interface with monotone ! r3 = 1./3. do n=1,nv do i=kstr-1,kend+2 qmi(i,n)=mass(i-1,n)*fm(i)+mass(i,n)*fn(i) & & +(dqmono(i-1,n)-dqmono(i,n))*r3 enddo enddo qpi(kstr:kend+1,1:nv) = qmi(kstr+1:kend+2,1:nv) ! ! do less diffusive ! ! do n=1,nv ! do i=kstr-1,kend+2 ! qmi(i,n)=mass(i,n)-sign(min(abs(2.*dqmono(i,n)), & ! & abs(qmi(i,n)-mass(i,n))), & ! & 2.*dqmono(i,n)) ! qpi(i,n)=mass(i,n)+sign(min(abs(2.*dqmono(i,n)), & ! & abs(qpi(i,n)-mass(i,n))), & ! & 2.*dqmono(i,n)) ! enddo ! enddo ! ! do monotonicity within cell ! r6 = 1./6. if( mono.eq.1 ) then do n=1,nv do i=kstr-1,kend+1 c1=qpi(i,n)-mass(i,n) c2=mass(i,n)-qmi(i,n) if( c1*c2.le.0.0 ) then qmi(i,n)=mass(i,n) qpi(i,n)=mass(i,n) else cc=qpi(i,n)-qmi(i,n) c1=cc*(mass(i,n)-0.5*(qpi(i,n)+qmi(i,n))) c2=cc*cc*r6 if( c1.gt.c2 ) then qmi(i,n)=3.*mass(i,n)-2.*qpi(i,n) else if( c1.lt.-c2 ) then qpi(i,n)=3.*mass(i,n)-2.*qmi(i,n) endif endif enddo enddo endif ! ! start interpolation by integral of ppm ! kkl = kstr tl=(pn(1)-locs(kkl))/hh(kkl) tl2=tl*tl tl3=tl2*tl tlp = tl3-tl2 tlm = tl3-2.*tl2+tl tlc = -2.*tl3+3.*tl2 do n=1,nv dql(n)=tlp*qpi(kkl,n)+tlm*qmi(kkl,n)+tlc*mass(kkl,n) enddo do i=1,lonn kl = i kh = i + 1 ! find kkh do kk=kkl+1,kend+2 if( pn(kh).lt.locs(kk) ) then kkh = kk-1 go to 100 endif enddo print *,' error in cyclic_cell_ppm_intp location not found ' print *,' lons=',lons,' lonp=',lonp,' lonn=',lonn print *,' pnmin=',pnmin,' pnmax=',pnmax print *,' pn(1)=',pn(1),' pn(lonn+1)=',pn(lonn+1) print *,' kstr =',kstr ,' kend =',kend print *,' kh=',kh,' pn(kh)=',pn(kh) print *,' kkl +1=',kkl +1,' locs(kkl +1)=',locs(kkl +1) print *,' kend+1=',kend+1,' locs(kend+1)=',locs(kend+1) call abort 100 continue ! mass interpolate th=(pn(kh)-locs(kkh))/hh(kkh) th2=th*th th3=th2*th thp = th3-th2 thm = th3-2.*th2+th thc = -2.*th3+3.*th2 do n=1,nv dqh(n)=thp*qpi(kkh,n)+thm*qmi(kkh,n)+thc*mass(kkh,n) enddo if( kkh.eq.kkl ) then do n=1,nv qn(i,n) = (dqh(n)-dql(n))/(th-tl) enddo else if( kkh.gt.kkl ) then dpp = (1.-tl)*hh(kkl) + th*hh(kkh) do kk=kkl+1,kkh-1 dpp = dpp + hh(kk) enddo do n=1,nv dql(n) = mass(kkl,n)-dql(n) dqq = dql(n)*hh(kkl) + dqh(n)*hh(kkh) do kk=kkl+1,kkh-1 dqq = dqq + mass(kk,n)*hh(kk) enddo qn(i,n) = dqq / dpp enddo else print *,' error in cyclic_cell_ppm_intp location messed up ' print *,' kkl=',kkl,' kkh=',kkh print *,' kh=',kh,' pn(kh)=',pn(kh) print *,' kkl-1=',kkl-1,' locs(kkl-1)=',locs(kkl-1) call abort endif ! next one kkl = kkh tl = th do n=1,nv dql(n) = dqh(n) enddo enddo ! return end subroutine cyclic_cell_ppm_intp !