!/===========================================================================/ ! Copyright (c) 2007, The University of Massachusetts Dartmouth ! Produced at the School of Marine Science & Technology ! Marine Ecosystem Dynamics Modeling group ! All rights reserved. ! ! FVCOM has been developed by the joint UMASSD-WHOI research team. For ! details of authorship and attribution of credit please see the FVCOM ! technical manual or contact the MEDM group. ! ! ! This file is part of FVCOM. For details, see http://fvcom.smast.umassd.edu ! The full copyright notice is contained in the file COPYRIGHT located in the ! root directory of the FVCOM code. This original header must be maintained ! in all distributed versions. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ! THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ! PURPOSE ARE DISCLAIMED. ! !/---------------------------------------------------------------------------/ ! CVS VERSION INFORMATION ! $Id$ ! $Name$ ! $Revision$ !/===========================================================================/ !======================================================================= ! FVCOM Scalar Module ! ! contains methods: ! Adv_Scal => Advect a Scalar Quantity ! Vdif_Scal => Vertical Diffusion of Scalar Quantity ! Bcond_Scal_OBC => Open Boundary Condition for Scalar ! Bcond_Scal_PTsource => Point Sources of Scalar !======================================================================= Module Scalar logical, parameter :: debug = .true. contains !==============================================================================| ! Calculate Horizontal Advection and Diffusion For Scalar (f) | !==============================================================================| ! Subroutine Adv_Scal(f,fn,d_fdis,fdis,d_fflux,fflux_obc,deltat,source) !J. Ge for tracer advection Subroutine Adv_Scal(f,f0,f2,fn,d_fdis,fdis,d_fflux,fflux_obc,deltat,source) !J. Ge for tracer advection !------------------------------------------------------------------------------| use all_vars use lims, only: m,mt,n,nt,kbm1,kb use bcs use mod_obcs # if defined (MULTIPROCESSOR) use mod_par # endif # if defined (WET_DRY) use mod_wd # endif # if defined (THIN_DAM) use mod_dam, only : kdam,N_DAM_MATCH,IS_DAM # endif implicit none real(sp), intent(in ), dimension(0:mt,kb) :: f !J. Ge for tracer advection real(sp), intent(in ), dimension(0:mt,kb) :: f0,f2 !J. Ge for tracer advection real(sp), intent(out), dimension(0:mt,kb) :: fn integer , intent(in ) :: d_fdis real(sp), intent(in ), dimension(d_fdis) :: fdis integer , intent(in ) :: d_fflux real(sp), intent(out), dimension(d_fflux,kbm1) :: fflux_obc real(sp), intent(in ) :: deltat logical , intent(in ) :: source !----------------local-------------------------------------- real(sp), dimension(0:mt,kb) :: xflux,xflux_adv real(sp), dimension(m) :: pupx,pupy,pvpx,pvpy real(sp), dimension(m) :: pfpx,pfpy,pfpxd,pfpyd,viscoff real(sp), dimension(3*nt,kb) :: dtij real(sp), dimension(3*nt,kbm1) :: uvn real(sp), dimension(kb) :: vflux real(sp) :: utmp,vtmp,sitai,ffd,ff1,x11,y11,x22,y22,x33,y33 real(sp) :: tmp1,tmp2,xi,yi real(sp) :: dxa,dya,dxb,dyb,fij1,fij2,un real(sp) :: txx,tyy,fxx,fyy,viscof,exflux,temp,fpoint real(sp) :: fact,fm1,fmean integer :: i,i1,i2,ia,ib,j,j1,j2,k,jtmp,jj !J. Ge for tracer advectio real(sp),dimension(kb) :: ftmp !J. Ge for tracer advection # if defined (SPHERICAL) real(sp) :: ty,txpi,typi # else real(sp) :: da,db,ds # endif # if defined (THIN_DAM) INTEGER :: NX real(sp) :: tmpflx real(sp),dimension(kb) :: wvel # endif !------------------------------------------------------------------------------! !------------------------------------------------------- !Calculate Mean Values !------------------------------------------------------- fmean = sum(f(1:m,1:kbm1))/float(m*kbm1) !------------------------------------------------------- !Initialize Multipliers to Control Horizontal Diff !------------------------------------------------------- fact = 0.0_sp fm1 = 1.0_sp if(HORIZONTAL_MIXING_TYPE == 'closure') then fact = 1.0_sp fm1 = 0.0_sp end if !------------------------------------------------------- !Initialize Fluxes !------------------------------------------------------- xflux = 0.0_sp xflux_adv = 0.0_sp !------------------------------------------------------- !Calculate Normal Velocity on Control Volume Edges !------------------------------------------------------- !!# if !defined (WET_DRY) do i=1,ncv i1=ntrg(i) !dtij(i)=dt1(i1) do k=1,kbm1 dtij(i,k)=dt1(i1)*dz1(i1,k) uvn(i,k) = v(i1,k)*dltxe(i) - u(i1,k)*dltye(i) # if defined(PLBC) uvn(i,k) = - u(i1,k)*dltye(i) # endif end do end do !!# else !! do i=1,ncv !! i1=ntrg(i) !! dtij(i)=dt1(i1) !! do k=1,kbm1 !! uvn(i,k) = vs(i1,k)*dltxe(i) - us(i1,k)*dltye(i) !! end do !! end do !!# endif ! !--Calculate the Advection and Horizontal Diffusion Terms----------------------! ! do k=1,kbm1 pfpx = 0.0_sp pfpy = 0.0_sp pfpxd = 0.0_sp pfpyd = 0.0_sp do i=1,m do j=1,ntsn(i)-1 i1=nbsn(i,j) i2=nbsn(i,j+1) # if defined (WET_DRY) ! IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 1)THEN ! FFD=0.5_SP*(f(I,K)+f(I2,K)) ! FF1=0.5_SP*(f(I,K)+f(I2,K)) ! ELSE IF(ISWETN(I1) == 1 .AND. ISWETN(I2) == 0)THEN ! FFD=0.5_SP*(f(I1,K)+f(I,K)) ! FF1=0.5_SP*(f(I1,K)+f(I,K)) ! ELSE IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 0)THEN ! FFD=0.5_SP*(f(I,K)+f(I,K)) ! FF1=0.5_SP*(f(I,K)+f(I,K)) ! ELSE ! FFD=0.5_SP*(f(I1,K)+f(I2,K)) ! FF1=0.5_SP*(f(I1,K)+f(I2,K)) ! END IF !J. Ge for tracer advection IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 1)THEN FFD=0.5_SP*(f(I,K)+f(I2,K)) FF1=0.5_SP*(f(I,K)+f(I2,K)) ELSE IF(ISWETN(I1) == 1 .AND. ISWETN(I2) == 0)THEN FFD=0.5_SP*(f(I1,K)+f(I,K)) FF1=0.5_SP*(f(I1,K)+f(I,K)) ELSE IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 0)THEN FFD=0.5_SP*(f(I,K)+f(I,K)) FF1=0.5_SP*(f(I,K)+f(I,K)) ELSE FFD=0.5_SP*(f(I1,K)+f(I2,K)) FF1=0.5_SP*(f(I1,K)+f(I2,K)) END IF ELSE IF(BACKWARD_STEP==1)THEN IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 1)THEN FFD=0.5_SP*((f0(I,K)+f(I,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) FF1=0.5_SP*((f0(I,K)+f(I,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) ELSE IF(ISWETN(I1) == 1 .AND. ISWETN(I2) == 0)THEN FFD=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I,K)+f(I,K))*0.5) FF1=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I,K)+f(I,K))*0.5) ELSE IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 0)THEN FFD=0.5_SP*((f0(I,K)+f(I,K))*0.5+(f0(I,K)+f(I,K))*0.5) FF1=0.5_SP*((f0(I,K)+f(I,K))*0.5+(f0(I,K)+f(I,K))*0.5) ELSE FFD=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) FF1=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) END IF ELSEIF(BACKWARD_STEP==2)THEN IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 1)THEN FFD=0.5_SP*((f2(I,K)+f0(I,K)+f(I,K))/3.0_SP+(f2(I2,K)+f0(I2,K)+f(I2,K))/3.0_SP) FF1=0.5_SP*((f2(I,K)+f0(I,K)+f(I,K))/3.0_SP+(f2(I2,K)+f0(I2,K)+f(I2,K))/3.0_SP) ELSE IF(ISWETN(I1) == 1 .AND. ISWETN(I2) == 0)THEN FFD=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))/3.0_SP+(f2(I,K)+f0(I,K)+f(I,K))/3.0_SP) FF1=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))/3.0_SP+(f2(I,K)+f0(I,K)+f(I,K))/3.0_SP) ELSE IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 0)THEN FFD=0.5_SP*((f2(I,K)+f0(I,K)+f(I,K))/3.0_SP+(f2(I,K)+f0(I,K)+f(I,K))/3.0_SP) FF1=0.5_SP*((f2(I,K)+f0(I,K)+f(I,K))/3.0_SP+(f2(I,K)+f0(I,K)+f(I,K))/3.0_SP) ELSE FFD=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))/3.0_SP+(f2(I2,K)+f0(I2,K)+f(I2,K))/3.0_SP) FF1=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))/3.0_SP+(f2(I2,K)+f0(I2,K)+f(I2,K))/3.0_SP) END IF ENDIF END IF !J. Ge for tracer advection # else ! ffd=0.5_sp*(f(i1,k)+f(i2,k)) !-fmean1(i1,k)-fmean1(i2,k)) ! ff1=0.5_sp*(f(i1,k)+f(i2,k)) !J. Ge for tracer advection IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN FFD=0.5_SP*(f(I1,K)+f(I2,K)) !-SMEAN1(I1,K)-SMEAN1(I2,K)) FF1=0.5_SP*(f(I1,K)+f(I2,K)) ELSE IF(BACKWARD_STEP==1)THEN FFD=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) FF1=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) ELSEIF(BACKWARD_STEP==2)THEN FFD=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))*0.5+(f2(I2,K)+f0(I2,K)+f(I2,K))*0.5) FF1=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))*0.5+(f2(I2,K)+f0(I2,K)+f(I2,K))*0.5) ENDIF ENDIF !J. Ge for tracer advection # endif # if defined (SPHERICAL) ty=0.5_sp*(vy(i1)+vy(i2)) txpi=(vx(i2)-vx(i1))*tpi*cos(deg2rad*ty) typi=(vy(i1)-vy(i2))*tpi pfpx(i)=pfpx(i)+ff1*typi pfpy(i)=pfpy(i)+ff1*txpi pfpxd(i)=pfpxd(i)+ffd*typi pfpyd(i)=pfpyd(i)+ffd*txpi # else pfpx(i) = pfpx(i) +ff1*(vy(i1)-vy(i2)) pfpy(i) = pfpy(i) +ff1*(vx(i2)-vx(i1)) pfpxd(i)= pfpxd(i)+ffd*(vy(i1)-vy(i2)) pfpyd(i)= pfpyd(i)+ffd*(vx(i2)-vx(i1)) # endif end do ! gather all neighboring control volumes connecting at dam node # if defined (THIN_DAM) IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN DO NX=1,N_DAM_MATCH(I,1) DO J=1,NTSN(N_DAM_MATCH(I,NX+1))-1 I1=NBSN(N_DAM_MATCH(I,NX+1),J) I2=NBSN(N_DAM_MATCH(I,NX+1),J+1) ! FFD=0.5_SP*(f(I1,K)+f(I2,K)) !-SMEAN1(I1,K)-SMEAN1(I2,K)) ! FF1=0.5_SP*(f(I1,K)+f(I2,K)) !J. Ge for tracer advection IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN FFD=0.5_SP*(f(I1,K)+f(I2,K)) !-SMEAN1(I1,K)-SMEAN1(I2,K)) FF1=0.5_SP*(f(I1,K)+f(I2,K)) ELSE IF(BACKWARD_STEP==1)THEN FFD=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) FF1=0.5_SP*((f0(I1,K)+f(I1,K))*0.5+(f0(I2,K)+f(I2,K))*0.5) ELSEIF(BACKWARD_STEP==2)THEN FFD=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))/3.0_SP+(f2(I2,K)+f0(I2,K)+f(I2,K))/3.0_SP) FF1=0.5_SP*((f2(I1,K)+f0(I1,K)+f(I1,K))/3.0_SP+(f2(I2,K)+f0(I2,K)+f(I2,K))/3.0_SP) ENDIF ENDIF !J. Ge for tracer advection # if defined (SPHERICAL) ty=0.5_sp*(vy(i1)+vy(i2)) txpi=(vx(i2)-vx(i1))*tpi*cos(deg2rad*ty) typi=(vy(i1)-vy(i2))*tpi pfpx(i)=pfpx(i)+ff1*typi pfpy(i)=pfpy(i)+ff1*txpi pfpxd(i)=pfpxd(i)+ffd*typi pfpyd(i)=pfpyd(i)+ffd*txpi # else pfpx(i) = pfpx(i) +ff1*(vy(i1)-vy(i2)) pfpy(i) = pfpy(i) +ff1*(vx(i2)-vx(i1)) pfpxd(i)= pfpxd(i)+ffd*(vy(i1)-vy(i2)) pfpyd(i)= pfpyd(i)+ffd*(vx(i2)-vx(i1)) # endif END DO END DO END IF # endif # if !defined (THIN_DAM) pfpx(i) =pfpx(i )/art2(i) pfpy(i) =pfpy(i )/art2(i) pfpxd(i) =pfpxd(i)/art2(i) pfpyd(i) =pfpyd(i)/art2(i) # else IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN PFPX(I)=PFPX(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1))))) PFPY(I)=PFPY(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1))))) PFPXD(I)=PFPXD(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1))))) PFPYD(I)=PFPYD(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1))))) ELSE PFPX(I)=PFPX(I)/ART2(I) PFPY(I)=PFPY(I)/ART2(I) PFPXD(I)=PFPXD(I)/ART2(I) PFPYD(I)=PFPYD(I)/ART2(I) END IF # endif end do if(k == kbm1)then do i=1,m pfpxb(i) = pfpx(i) pfpyb(i) = pfpy(i) end do end if do i=1,m pupx(i)=0.0_sp pupy(i)=0.0_sp pvpx(i)=0.0_sp pvpy(i)=0.0_sp j=1 i1=nbve(i,j) jtmp=nbvt(i,j) j1=jtmp+1-(jtmp+1)/4*3 j2=jtmp+2-(jtmp+2)/4*3 x11=0.5_sp*(vx(i)+vx(nv(i1,j1))) y11=0.5_sp*(vy(i)+vy(nv(i1,j1))) x22=xc(i1) y22=yc(i1) x33=0.5_sp*(vx(i)+vx(nv(i1,j2))) y33=0.5_sp*(vy(i)+vy(nv(i1,j2))) # if defined (SPHERICAL) ty =0.5_sp*(y11+y33) txpi=(x33-x11)*tpi*cos(deg2rad*ty) typi=(y11-y33)*tpi pupx(i)=pupx(i)+u(i1,k)*typi pupy(i)=pupy(i)+u(i1,k)*txpi pvpx(i)=pvpx(i)+v(i1,k)*typi pvpy(i)=pvpy(i)+v(i1,k)*txpi # else pupx(i)=pupx(i)+u(i1,k)*(y11-y33) pupy(i)=pupy(i)+u(i1,k)*(x33-x11) pvpx(i)=pvpx(i)+v(i1,k)*(y11-y33) pvpy(i)=pvpy(i)+v(i1,k)*(x33-x11) # endif if(isonb(i) /= 0) then # if defined (SPHERICAL) ty=0.5_sp*(vy(i)+y11) txpi=(x11-vx(i))*tpi*cos(deg2rad*ty) typi=(vy(i)-y11)*tpi pupx(i)=pupx(i)+u(i1,k)*typi pupy(i)=pupy(i)+u(i1,k)*txpi pvpx(i)=pvpx(i)+v(i1,k)*typi pvpy(i)=pvpy(i)+v(i1,k)*txpi # else pupx(i)=pupx(i)+u(i1,k)*(vy(i)-y11) pupy(i)=pupy(i)+u(i1,k)*(x11-vx(i)) pvpx(i)=pvpx(i)+v(i1,k)*(vy(i)-y11) pvpy(i)=pvpy(i)+v(i1,k)*(x11-vx(i)) # endif end if do j=2,ntve(i)-1 i1=nbve(i,j) jtmp=nbvt(i,j) j1=jtmp+1-(jtmp+1)/4*3 j2=jtmp+2-(jtmp+2)/4*3 x11=0.5_sp*(vx(i)+vx(nv(i1,j1))) y11=0.5_sp*(vy(i)+vy(nv(i1,j1))) x22=xc(i1) y22=yc(i1) x33=0.5_sp*(vx(i)+vx(nv(i1,j2))) y33=0.5_sp*(vy(i)+vy(nv(i1,j2))) # if defined (SPHERICAL) ty=0.5_sp*(y11+y33) txpi=(x33-x11)*tpi*COS(deg2rad*TY) typi=(y11-y33)*tpi pupx(i)=pupx(i)+u(i1,k)*typi pupy(i)=pupy(i)+u(i1,k)*txpi pvpx(i)=pvpx(i)+v(i1,k)*typi pvpy(i)=pvpy(i)+v(i1,k)*txpi # else pupx(i)=pupx(i)+u(i1,k)*(y11-y33) pupy(i)=pupy(i)+u(i1,k)*(x33-x11) pvpx(i)=pvpx(i)+v(i1,k)*(y11-y33) pvpy(i)=pvpy(i)+v(i1,k)*(x33-x11) # endif end do j=ntve(i) i1=nbve(i,j) jtmp=nbvt(i,j) j1=jtmp+1-(jtmp+1)/4*3 j2=jtmp+2-(jtmp+2)/4*3 x11=0.5_sp*(vx(i)+vx(nv(i1,j1))) y11=0.5_sp*(vy(i)+vy(nv(i1,j1))) x22=xc(i1) y22=yc(i1) x33=0.5_sp*(vx(i)+vx(nv(i1,j2))) y33=0.5_sp*(vy(i)+vy(nv(i1,j2))) # if defined (SPHERICAL) ty=0.5*(Y11+Y33) txpi=(x33-x11)*tpi*cos(deg2rad*TY) typi=(y11-y33)*tpi pupx(i)=pupx(i)+u(i1,k)*typi pupy(i)=pupy(i)+u(i1,k)*txpi pvpx(i)=pvpx(i)+v(i1,k)*typi pvpy(i)=pvpy(i)+v(i1,k)*txpi # else pupx(i)=pupx(i)+u(i1,k)*(y11-y33) pupy(i)=pupy(i)+u(i1,k)*(x33-x11) pvpx(i)=pvpx(i)+v(i1,k)*(y11-y33) pvpy(i)=pvpy(i)+v(i1,k)*(x33-x11) # endif if(isonb(i) /= 0) then # if defined (SPHERICAL) ty=0.5*(Y11+VY(I)) txpi=(VX(I)-X11)*tpi*COS(deg2rad*ty) typi=(Y11-VY(I))*tpi pupx(i)=pupx(i)+u(i1,k)*typi pupy(i)=pupy(i)+u(i1,k)*txpi pvpx(i)=pvpx(i)+v(i1,k)*typi pvpy(i)=pvpy(i)+v(i1,k)*txpi # else pupx(i)=pupx(i)+u(i1,k)*(y11-vy(i)) pupy(i)=pupy(i)+u(i1,k)*(vx(i)-x11) pvpx(i)=pvpx(i)+v(i1,k)*(y11-vy(i)) pvpy(i)=pvpy(i)+v(i1,k)*(vx(i)-x11) # endif end if pupx(i)=pupx(i)/art1(i) pupy(i)=pupy(i)/art1(i) pvpx(i)=pvpx(i)/art1(i) pvpy(i)=pvpy(i)/art1(i) tmp1=pupx(i)**2+pvpy(i)**2 tmp2=0.5_sp*(pupy(i)+pvpx(i))**2 viscoff(i)=sqrt(tmp1+tmp2)*art1(i) end do ! if(k == kbm1) then ! ah_bottom(1:m) = horcon*(fact*viscoff(1:m) + fm1) ! end if do i=1,ncv_i ia=niec(i,1) ib=niec(i,2) xi=0.5_sp*(xije(i,1)+xije(i,2)) yi=0.5_sp*(yije(i,1)+yije(i,2)) # if defined (SPHERICAL) ty=0.5_sp*(yi+vy(ia)) dxa=(xi-vx(ia))*tpi*cos(deg2rad*ty) dya=(yi-vy(ia))*tpi ty=0.5*(YI+VY(IB)) DXB=(XI-VX(IB))*tpi*COS(deg2rad*ty) DYB=(YI-VY(IB))*tpi # else dxa=xi-vx(ia) dya=yi-vy(ia) dxb=xi-vx(ib) dyb=yi-vy(ib) # endif ! fij1=f(ia,k)+dxa*pfpx(ia)+dya*pfpy(ia) ! fij2=f(ib,k)+dxb*pfpx(ib)+dyb*pfpy(ib) !J. Ge for tracer advection IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN fij1=f(ia,k)+dxa*pfpx(ia)+dya*pfpy(ia) fij2=f(ib,k)+dxb*pfpx(ib)+dyb*pfpy(ib) ELSE IF(BACKWARD_STEP==1)THEN fij1=(f0(ia,k)+f(ia,k))*0.5+dxa*pfpx(ia)+dya*pfpy(ia) fij2=(f0(ib,k)+f(ib,k))*0.5+dxb*pfpx(ib)+dyb*pfpy(ib) ELSEIF(BACKWARD_STEP==2)THEN fij1=(f2(ia,k)+f0(ia,k)+f(ia,k))/3.0_SP+dxa*pfpx(ia)+dya*pfpy(ia) fij2=(f2(ib,k)+f0(ib,k)+f(ib,k))/3.0_SP+dxb*pfpx(ib)+dyb*pfpy(ib) ENDIF ENDIF !J. Ge for tracer advection un=uvn(i,k) ! viscof=horcon*(fact*(viscoff(ia)+viscoff(ib))*0.5_sp + fm1) VISCOF=(FACT*0.5_SP*(VISCOFF(IA)*NN_HVC(IA)+VISCOFF(IB)*NN_HVC(IB)) + FM1*0.5_SP*(NN_HVC(IA)+NN_HVC(IB))) !JQI NOV2021 # if defined (WET_DRY) !Added by Adi Nugraha !Allow no diffusive flux between a wet node and a dry node (Wen Long and Tarang Khangaonkar) IF(ISWETN(IA)==1.AND.ISWETN(IB)==1)THEN # endif txx=0.5_sp*(pfpxd(ia)+pfpxd(ib))*viscof tyy=0.5_sp*(pfpyd(ia)+pfpyd(ib))*viscof # if defined (WET_DRY) ELSE TXX = 0.0_SP TYY = 0.0_SP ENDIF # endif !JQI NOV2021 fxx=-dtij(i,k)*txx*dltye(i) fyy= dtij(i,k)*tyy*dltxe(i) # if defined (PLBC) fyy=0.0_SP # endif exflux=-un*dtij(i,k)* & ((1.0_sp+sign(1.0_sp,un))*fij2+(1.0_sp-sign(1.0_sp,un))*fij1)*0.5_sp+fxx+fyy ! --------- new: 14-02-2012 ,K.Lettmann ------ ! Limit the total flux according to the amount ! of mass within the respective neigbour control volumnes # if !defined (SPHERICAL) Da = dz(ia,k)*dt(ia) Db = dz(ib,k)*dt(ib) Ds = 0.5_sp*( dz(ia,k) + dz(ib,k) ) ! Approximation of water depth for segment in sigma units exflux = exflux / Ds ! trafo to old eflux unit (FVCOM 2.7) call limit_hor_flux_Scal(f(ia,k),f(ib,k),ia,ib,Da,Db,ntrg(i),deltat,exflux) exflux = exflux * Ds ! trafo back to new eflux unit (>FVCOM 3.1.4) # endif ! -------------------------------------------- xflux(ia,k)=xflux(ia,k)+exflux xflux(ib,k)=xflux(ib,k)-exflux xflux_adv(ia,k)=xflux_adv(ia,k)+(exflux-fxx-fyy) xflux_adv(ib,k)=xflux_adv(ib,k)-(exflux-fxx-fyy) # if defined (THIN_DAM) IF(K<=KDAM(IA).AND.IS_DAM(IA)==1)THEN IF(N_DAM_MATCH(IA,1)==1)THEN XFLUX(N_DAM_MATCH(IA,2),K) = XFLUX(N_DAM_MATCH(IA,2),K) + EXFLUX XFLUX_ADV(N_DAM_MATCH(IA,2),K) = XFLUX_ADV(N_DAM_MATCH(IA,2),K) +(EXFLUX-FXX-FYY) END IF IF(N_DAM_MATCH(IA,1)==2)THEN XFLUX(N_DAM_MATCH(IA,2),K) = XFLUX(N_DAM_MATCH(IA,2),K) + EXFLUX XFLUX(N_DAM_MATCH(IA,3),K) = XFLUX(N_DAM_MATCH(IA,3),K) + EXFLUX XFLUX_ADV(N_DAM_MATCH(IA,2),K) = XFLUX_ADV(N_DAM_MATCH(IA,2),K) +(EXFLUX-FXX-FYY) XFLUX_ADV(N_DAM_MATCH(IA,3),K) = XFLUX_ADV(N_DAM_MATCH(IA,3),K) +(EXFLUX-FXX-FYY) END IF IF(N_DAM_MATCH(IA,1)==3)THEN XFLUX(N_DAM_MATCH(IA,2),K) = XFLUX(N_DAM_MATCH(IA,2),K) + EXFLUX XFLUX(N_DAM_MATCH(IA,3),K) = XFLUX(N_DAM_MATCH(IA,3),K) + EXFLUX XFLUX(N_DAM_MATCH(IA,4),K) = XFLUX(N_DAM_MATCH(IA,4),K) + EXFLUX XFLUX_ADV(N_DAM_MATCH(IA,2),K) = XFLUX_ADV(N_DAM_MATCH(IA,2),K) +(EXFLUX-FXX-FYY) XFLUX_ADV(N_DAM_MATCH(IA,3),K) = XFLUX_ADV(N_DAM_MATCH(IA,3),K) +(EXFLUX-FXX-FYY) XFLUX_ADV(N_DAM_MATCH(IA,4),K) = XFLUX_ADV(N_DAM_MATCH(IA,4),K) +(EXFLUX-FXX-FYY) END IF END IF IF(K<=KDAM(IB).AND.IS_DAM(IB)==1)THEN IF(N_DAM_MATCH(IB,1)==1)THEN XFLUX(N_DAM_MATCH(IB,2),K) = XFLUX(N_DAM_MATCH(IB,2),K) - EXFLUX XFLUX_ADV(N_DAM_MATCH(IB,2),K) = XFLUX_ADV(N_DAM_MATCH(IB,2),K) - (EXFLUX-FXX-FYY) END IF IF(N_DAM_MATCH(IB,1)==2)THEN XFLUX(N_DAM_MATCH(IB,2),K) = XFLUX(N_DAM_MATCH(IB,2),K) - EXFLUX XFLUX(N_DAM_MATCH(IB,3),K) = XFLUX(N_DAM_MATCH(IB,3),K) - EXFLUX XFLUX_ADV(N_DAM_MATCH(IB,2),K) = XFLUX_ADV(N_DAM_MATCH(IB,2),K) - (EXFLUX-FXX-FYY) XFLUX_ADV(N_DAM_MATCH(IB,3),K) = XFLUX_ADV(N_DAM_MATCH(IB,3),K) - (EXFLUX-FXX-FYY) END IF IF(N_DAM_MATCH(IB,1)==3)THEN XFLUX(N_DAM_MATCH(IB,2),K) = XFLUX(N_DAM_MATCH(IB,2),K) - EXFLUX XFLUX(N_DAM_MATCH(IB,3),K) = XFLUX(N_DAM_MATCH(IB,3),K) - EXFLUX XFLUX(N_DAM_MATCH(IB,4),K) = XFLUX(N_DAM_MATCH(IB,4),K) - EXFLUX XFLUX_ADV(N_DAM_MATCH(IB,2),K) = XFLUX_ADV(N_DAM_MATCH(IB,2),K) - (EXFLUX-FXX-FYY) XFLUX_ADV(N_DAM_MATCH(IB,3),K) = XFLUX_ADV(N_DAM_MATCH(IB,3),K) - (EXFLUX-FXX-FYY) XFLUX_ADV(N_DAM_MATCH(IB,4),K) = XFLUX_ADV(N_DAM_MATCH(IB,4),K) - (EXFLUX-FXX-FYY) END IF END IF # endif end do end do !!sigma loop !--------------------------------------------------------------------------------- ! Accumulate Fluxes at Boundary Nodes !--------------------------------------------------------------------------------- # if defined (MULTIPROCESSOR) if(par)call node_match(0,nbn,bn_mlt,bn_loc,bnc,mt,kb,myid,nprocs,xflux,xflux_adv) # endif !--------------------------------------------------------------------------------- ! Store Advective Fluxes at the Boundary !--------------------------------------------------------------------------------- do k=1,kbm1 if(iobcn > 0) then do i=1,iobcn i1=i_obc_n(i) fflux_obc(i,k)=xflux_adv(i1,k) end do end if end do !--------------------------------------------------------------------------------- ! Calculate Vertical Advection Terms !--------------------------------------------------------------------------------- do i=1,m # if defined (WET_DRY) if(iswetn(i)*iswetnt(i) == 1) then # endif # if defined (THIN_DAM) if(IS_DAM(I)==1)then wvel(1:kb)=0.0_sp !YC call calc_vflux(kbm1,f(i,1:kbm1),wvel(1:kb),vflux) !J. Ge for tracer advection !w_tmp = wvel(1:kb) !dz_tmp= dz(i,1:kbm1) IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN ftmp = f(i,1:kbm1) !call calc_vflux(kbm1,ftmp,w_tmp,dz_tmp,vflux) call calc_vflux(kbm1,f(i,1:kbm1),wvel(1:kb),dz(i,1:kbm1),vflux) ELSE IF(BACKWARD_STEP==1)THEN ftmp=(f0(i,1:kbm1)+f(i,1:kbm1))*0.5 ELSEIF(BACKWARD_STEP==2)THEN ftmp=(f2(i,1:kbm1)+f0(i,1:kbm1)+f(i,1:kbm1))/3.0_SP ENDIF !call calc_vflux(kbm1,ftmp,w_tmp,dz_tmp,vflux) call calc_vflux(kbm1,ftmp,wvel(1:kb),dz(i,1:kbm1),vflux) ENDIF !J. Ge for tracer advection else !YC call calc_vflux(kbm1,f(i,1:kbm1),wts(i,1:kb),vflux) !J. Ge for tracer advection !w_tmp = wts(i,1:kb) !dz_tmp= dz(i,1:kbm1) IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN ftmp = f(i,1:kbm1) !call calc_vflux(kbm1,ftmp,w_tmp,dz_tmp,vflux) call calc_vflux(kbm1,f(i,1:kbm1),wts(i,1:kb),dz(i,1:kbm1),vflux) ELSE IF(BACKWARD_STEP==1)THEN ftmp=(f0(i,1:kbm1)+f(i,1:kbm1))*0.5 ELSEIF(BACKWARD_STEP==2)THEN ftmp=(f2(i,1:kbm1)+f0(i,1:kbm1)+f(i,1:kbm1))/3.0_SP ENDIF !call calc_vflux(kbm1,ftmp,w_tmp,dz_tmp,vflux) call calc_vflux(kbm1,ftmp,wts(i,1:kb),dz(i,1:kbm1),vflux) ENDIF !J. Ge for tracer advection end if # else !J. Ge for tracer advection !w_tmp = wts(i,1:kb) !dz_tmp= dz(i,1:kbm1) IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN !ftmp = f(i,1:kbm1) !call calc_vflux(kbm1,ftmp,w_tmp,dz_tmp,vflux) call calc_vflux(kbm1,f(i,1:kbm1),wts(i,1:kb),dz(i,1:kbm1),vflux) ELSE IF(BACKWARD_STEP==1)THEN ftmp=(f0(i,1:kbm1)+f(i,1:kbm1))*0.5 ELSEIF(BACKWARD_STEP==2)THEN ftmp=(f2(i,1:kbm1)+f0(i,1:kbm1)+f(i,1:kbm1))/3.0_SP ENDIF !call calc_vflux(kbm1,ftmp,w_tmp,dz_tmp,vflux) call calc_vflux(kbm1,ftmp,wts(i,1:kb),dz(i,1:kbm1),vflux) ENDIF !J. Ge for tracer advection !!! vflux = 0.0_SP # endif do k=1,kbm1 if(isonb(i) == 2) then xflux(i,k)= vflux(k)*art1(i) !/dz(i,k) !JQI xflux(i,k)= (vflux(k)-vflux(k+1))*art1(i)/dz(i,k) else !JQI xflux(i,k)=xflux(i,k)+ (vflux(k)-vflux(k+1))*art1(i)/dz(i,k) xflux(i,k)=xflux(i,k)+ vflux(k)*art1(i) !/dz(i,k) end if # if defined (THIN_DAM) IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN tmpflx = (vflux(k)-vflux(k+1))*art1(i)/dz(i,k) IF(N_DAM_MATCH(I,1)==1)THEN XFLUX(N_DAM_MATCH(I,2),K) = XFLUX(N_DAM_MATCH(I,2),K)+tmpflx END IF IF(N_DAM_MATCH(I,1)==2)THEN XFLUX(N_DAM_MATCH(I,2),K) = XFLUX(N_DAM_MATCH(I,2),K)+tmpflx XFLUX(N_DAM_MATCH(I,3),K) = XFLUX(N_DAM_MATCH(I,3),K)+tmpflx END IF IF(N_DAM_MATCH(I,1)==3)THEN XFLUX(N_DAM_MATCH(I,2),K) = XFLUX(N_DAM_MATCH(I,2),K)+tmpflx XFLUX(N_DAM_MATCH(I,3),K) = XFLUX(N_DAM_MATCH(I,3),K)+tmpflx XFLUX(N_DAM_MATCH(I,4),K) = XFLUX(N_DAM_MATCH(I,4),K)+tmpflx END IF END IF # endif end do # if defined (WET_DRY) end if # endif end do !------------------------------------------------------- !Point Source !------------------------------------------------------- if(source)then !!user specified if(RIVER_TS_SETTING == 'calculated') then if(RIVER_INFLOW_LOCATION == 'node') then do j=1,numqbc jj=inodeq(j) fpoint=fdis(j) do k=1,kbm1 xflux(jj,k)=xflux(jj,k) - qdis(j)*vqdist(j,k)*fpoint !/dz(jj,k) end do end do else if(RIVER_INFLOW_LOCATION == 'edge') then write(*,*)'scalar advection not setup for "edge" point source' stop end if end if else if(RIVER_TS_SETTING == 'calculated')then if(RIVER_INFLOW_LOCATION == 'node') then do j=1,numqbc jj=inodeq(j) do k=1,kbm1 fpoint = f(jj,k) !J. Ge for tracer advection IF(BACKWARD_ADVECTION .NEQV. .TRUE.)THEN fpoint = f(jj,k) ELSE IF(BACKWARD_STEP==1)THEN fpoint = (f0(jj,k)+f(jj,k))*0.5 ELSEIF(BACKWARD_STEP==2)THEN fpoint = (f2(jj,k)+f0(jj,k)+f(jj,k))/3.0_SP ENDIF ENDIF !J. Ge for tracer advection xflux(jj,k)=xflux(jj,k) - qdis(j)*vqdist(j,k)*fpoint! /dz(jj,k) end do end do else if(RIVER_INFLOW_LOCATION == 'edge') then write(*,*)'scalar advection not setup for "edge" point source' stop end if end if endif !------------------------------------------------------------------------ !Update Scalar Quantity !------------------------------------------------------------------------ do i=1,m # if defined (WET_DRY) if(iswetn(i)*iswetnt(i) == 1 )then # endif do k=1,kbm1 # if !defined (THIN_DAM) !fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/dt(i)))*(dt(i)/dtfa(i)) fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/(dt(i)*dz(i,k))))*(dt(i)/dtfa(i)) # else IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN fn(i,k)=(f(i,k)-xflux(i,k)/(ART1(I)& &+SUM(ART1(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1)))))*(deltat/dt(i)))*(dt(i)/dtfa(i)) ELSE !fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/dt(i)))*(dt(i)/dtfa(i)) fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/(dt(i)*dz(i,k))))*(dt(i)/dtfa(i)) END IF # endif end do # if defined (WET_DRY) else do k=1,kbm1 fn(i,k)=f(i,k) end do end if # endif end do return End Subroutine Adv_Scal !==============================================================================| !==============================================================================| ! Vertical Diffusion of Scalar | !==============================================================================| Subroutine Vdif_Scal(f,deltat) use mTridiagonal_scal use all_vars # if defined (THIN_DAM) use mod_dam,only : NODE_DAM1_N,NODE_DAM2_N,NODE_DAM3_N, & &I_NODE_DAM1_N,I_NODE_DAM2_N,I_NODE_DAM3_N, & &kdam # endif Implicit None Real(sp), intent(inout) :: f(0:mt,kb) Real(sp), intent(in ) :: deltat !--local-------------------- integer :: i,k,ll real(sp) :: dsqrd,dfdz,visb real(sp) :: fsol(0:kb) # if defined (THIN_DAM) real(sp) :: ftmp,stmp # endif call init_tridiagonal_scal(kb) Do i=1,m dsqrd = d(i)*d(i) !---------------------------------------------------------------- ! Set up Diagonals of Matrix (lower=au,diag=bu,upper=cu) !---------------------------------------------------------------- !Surface au(1) = 0.0 cu(1)= - deltat*(kh(i,2)+umol)/(dzz(i,1)*dz(i,1)*dsqrd) bu(1)= 1.0 - cu(1) !Interior do k=2,kbm1-1 au(k) = - deltat*(kh(i,k )+umol)/(dzz(i,k-1)*dz(i,k)*dsqrd) cu(k) = - deltat*(kh(i,k+1)+umol)/(dzz(i,k )*dz(i,k)*dsqrd) bu(k) = 1.0 - cu(k) - au(k) end do !Bottom au(kbm1) = - deltat*(kh(i,kbm1)+umol)/(dzz(i,kbm1-1)*dz(i,kbm1)*dsqrd) cu(kbm1) = 0.0 bu(kbm1) = 1.0 - au(kbm1) !---------------------------------------------------------------- ! Set up RHS forcing vector and boundary conditions !---------------------------------------------------------------- do k=1,kbm1 du(k) = f(i,k) end do !Free Surface: No flux !Bottom: No flux !---------------------------------------------------------------- ! Solve !---------------------------------------------------------------- call tridiagonal_scal(kb,1,kbm1,fsol) !Transfer f(i,1:kbm1) = fsol(1:kbm1) End Do # if defined (THIN_DAM) DO K=1,KBM1 DO I=1,NODE_DAM1_N IF(K<=KDAM(I_NODE_DAM1_N(I,1)).AND.K<=KDAM(I_NODE_DAM1_N(I,2)) )THEN FTMP=F(I_NODE_DAM1_N(I,1),K)*ART1(I_NODE_DAM1_N(I,1)) & & +F(I_NODE_DAM1_N(I,2),K)*ART1(I_NODE_DAM1_N(I,2)) STMP=ART1(I_NODE_DAM1_N(I,1))+ART1(I_NODE_DAM1_N(I,2)) F(I_NODE_DAM1_N(I,1),K)=FTMP/STMP F(I_NODE_DAM1_N(I,2),K)=FTMP/STMP END IF END DO DO I=1,NODE_DAM2_N IF(K<=KDAM(I_NODE_DAM2_N(I,1)).AND.K<=KDAM(I_NODE_DAM2_N(I,2)) & & .AND.K<=KDAM(I_NODE_DAM2_N(I,2)) )THEN FTMP= F(I_NODE_DAM2_N(I,1),K)*ART1(I_NODE_DAM2_N(I,1)) & & +F(I_NODE_DAM2_N(I,2),K)*ART1(I_NODE_DAM2_N(I,2)) & & +F(I_NODE_DAM2_N(I,3),K)*ART1(I_NODE_DAM2_N(I,3)) STMP=ART1(I_NODE_DAM2_N(I,1))+ART1(I_NODE_DAM2_N(I,2)) & & +ART1(I_NODE_DAM2_N(I,3)) F(I_NODE_DAM2_N(I,1),K)=FTMP/STMP F(I_NODE_DAM2_N(I,2),K)=FTMP/STMP F(I_NODE_DAM2_N(I,3),K)=FTMP/STMP END IF END DO DO I=1,NODE_DAM3_N IF(K<=KDAM(I_NODE_DAM3_N(I,1)).AND.K<=KDAM(I_NODE_DAM3_N(I,2)) & & .AND.K<=KDAM(I_NODE_DAM3_N(I,3)).AND.K<=KDAM(I_NODE_DAM3_N(I,4)) )THEN FTMP =F(I_NODE_DAM3_N(I,1),K)*ART1(I_NODE_DAM3_N(I,1)) & & +F(I_NODE_DAM3_N(I,2),K)*ART1(I_NODE_DAM3_N(I,2)) & & +F(I_NODE_DAM3_N(I,3),K)*ART1(I_NODE_DAM3_N(I,3)) & & +F(I_NODE_DAM3_N(I,4),K)*ART1(I_NODE_DAM3_N(I,4)) STMP =ART1(I_NODE_DAM3_N(I,1)) + ART1(I_NODE_DAM3_N(I,2)) & & + ART1(I_NODE_DAM3_N(I,3)) + ART1(I_NODE_DAM3_N(I,4)) F(I_NODE_DAM3_N(I,1),K)=FTMP/STMP F(I_NODE_DAM3_N(I,2),K)=FTMP/STMP F(I_NODE_DAM3_N(I,3),K)=FTMP/STMP F(I_NODE_DAM3_N(I,4),K)=FTMP/STMP END IF END DO END DO # endif End Subroutine Vdif_Scal !==============================================================================| ! Set Point Source Conditions for Scalar Function | !==============================================================================| Subroutine Bcond_Scal_PTsource(f,fn,fdis) !------------------------------------------------------------------------------| use all_vars use bcs use mod_obcs implicit none real(sp), intent(in ), dimension(0:mt,kb) :: f real(sp), intent(out), dimension(0:mt,kb) :: fn real(sp), intent(in ), dimension(numqbc ) :: fdis !--local------------------------------------------- integer :: i,j,k,j1,j11,j22 !------------------------------------------------------------------------------| !-------------------------------------------- ! Set Source Terms !-------------------------------------------- if(RIVER_TS_SETTING == 'specified') then if(numqbc > 0) then if(RIVER_INFLOW_LOCATION == 'node') then do i=1,numqbc j11=inodeq(i) do k=1,kbm1 fn(j11,k)=fdis(i) end do end do else if(RIVER_INFLOW_LOCATION == 'edge') then do i=1,numqbc j11=n_icellq(i,1) j22=n_icellq(i,2) do k=1,kbm1 fn(j11,k)=fdis(i) fn(j22,k)=fdis(i) end do end do end if end if end if return End Subroutine Bcond_Scal_PTSource !==============================================================================| !==============================================================================| !==============================================================================| ! Set Boundary Conditions for Scalar Function on Open Boundary | !==============================================================================| Subroutine Bcond_Scal_OBC(f,fn,fflux_obc,f_obc,deltat,alpha_nudge) !------------------------------------------------------------------------------| use all_vars use bcs use mod_obcs implicit none real(sp), intent(in ), dimension(0:mt,kb) :: f real(sp), intent(inout), dimension(0:mt,kb) :: fn !JQI NOV2021 real(sp), intent(in ), dimension(iobcn,kbm1) :: fflux_obc ! KURT GLAESEMANN - remove + 1 from dimension !JQI NOV2021 real(sp), intent(in ), dimension(iobcn ) :: f_obc real(sp), intent(in ) :: deltat real(sp), intent(in ) :: alpha_nudge !--local------------------------------------------- real(sp) :: f2d,f2d_next,f2d_obc,xflux2d,tmp integer :: i,j,k,j1,j11,j22 !------------------------------------------------------------------------------| !-------------------------------------------- ! Set Scalar Value on Open Boundary !-------------------------------------------- if(iobcn > 0) then do i=1,iobcn j=i_obc_n(i) j1=next_obc(i) f2d=0.0_sp f2d_next=0.0_sp xflux2d=0.0_sp do k=1,kbm1 f2d=f2d+f(j,k)*dz(j,k) f2d_next=f2d_next+fn(j1,k)*dz(j1,k) xflux2d=xflux2d+fflux_obc(i,k)*dz(j,k) end do if(uard_obcn(i) > 0.0_sp) then tmp=xflux2d+f2d*uard_obcn(i) f2d_obc=(f2d*dt(j)-tmp*deltat/art1(j))/d(j) do k=1,kbm1 fn(j,k)=fn(j1,k) !f2d_obc+(fn(j1,k)-f2d_next) end do else do k=1,kbm1 fn(j,k) = f(j,k)-alpha_nudge*(f(j,k)-f_obc(i)) end do end if end do endif return End Subroutine Bcond_Scal_OBC !==============================================================================| !==============================================================================| Subroutine fct_sed(f,fn) !==============================================================================| USE ALL_VARS USE MOD_UTILS USE BCS USE MOD_OBCS IMPLICIT NONE real(sp), intent(inout), dimension(0:mt,kb) :: fn real(sp), intent(in), dimension(0:mt,kb) :: f REAL(SP):: SMAX,SMIN INTEGER :: I,J,K,K1 !==============================================================================| IF(DBG_SET(DBG_SBR)) WRITE(IPT,*)"Start: fct_sed" nodes: DO I=1,M ! SKIP OPEN BOUNDARY NODES IF(IOBCN > 0)THEN DO J=1,IOBCN IF(I == I_OBC_N(J)) CYCLE nodes END DO END IF ! SKIP RIVER INFLOW POINTS IF(NUMQBC > 0)THEN DO J=1,NUMQBC IF(RIVER_INFLOW_LOCATION == 'node')THEN IF(I == INODEQ(J)) CYCLE nodes END IF IF(RIVER_INFLOW_LOCATION == 'edge')THEN IF(I == N_ICELLQ(J,1) .OR. I == N_ICELLQ(J,2)) CYCLE nodes END IF END DO END IF ! SKIP GROUND WATER INFLOW POINTS IF(BFWDIS(I) .GT. 0.0_SP .and. GROUNDWATER_SALT_ON) CYCLE nodes K1 = 1 IF(PRECIPITATION_ON) K1 = 2 ! DO K=1,KBM1 DO K=K1,KBM1 SMAX = MAXVAL(f(NBSN(I,1:NTSN(I)),K)) SMIN = MINVAL(f(NBSN(I,1:NTSN(I)),K)) IF(K == 1)THEN SMAX = MAX(SMAX,(f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K+1))) SMIN = MIN(SMIN,(f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K+1))) ELSE IF(K == KBM1)THEN SMAX = MAX(SMAX,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K-1))) SMIN = MIN(SMIN,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K-1))) ELSE SMAX = MAX(SMAX,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K-1)), & (f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K+1))) SMIN = MIN(SMIN,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K-1)), & (f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ & (DZ(I,K)+DZ(I,K+1))) END IF IF(SMIN-fn(I,K) > 0.0_SP)fn(I,K) = SMIN IF(fn(I,K)-SMAX > 0.0_SP)fn(I,K) = SMAX END DO END DO nodes WHERE(fn < 0.0_SP)fn=0.0_SP IF(DBG_SET(DBG_SBR)) WRITE(IPT,*)"End: fct_sed" End Subroutine fct_sed !========================================================================== ! Calculate Fluxes for Vertical Advection Equation ! n: number of cells ! c: scalar variable (1:n) ! w: velocity field at cell interfaces (1:n+1) ! note: we dont use face normals to construct inflow/outflow ! thus we add dissipation term instead of subtracting because ! positive velocity is up while computational coordinates increase ! down towards bottom. !========================================================================== Subroutine Calc_VFlux(n,c,w,zk,flux) use mod_prec use mod_utils, only : LIMLED2 implicit none integer , intent(in ) :: n real(sp), intent(in ) :: c(n) real(sp), intent(in ) :: w(n+1) real(sp), intent(in ) :: zk(n) real(sp), intent(out) :: flux(n+1) real(sp) :: conv(n+1),diss(n+1) real(sp) :: cin(0:n+1) real(sp) :: sl_h(0:n+1) real(sp) :: dis4,sl_u,sl_f integer :: i !transfer to working array cin(1:n) = c(1:n) sl_h(1:n) = zk(1:n) !surface bcs (no flux) cin(0) = -cin(1) ! cin(-1) = -cin(2) sl_h(0) = zk(1) !bottom bcs (no flux) cin(n+1) = -cin(n) ! cin(n+2) = -cin(n-1) sl_h(n+1) = zk(n) !flux computation do i=2,n dis4 = .5*abs(w(i)) conv(i) = w(i)*(cin(i)+cin(i-1))*0.5_SP sl_u = 2.0_SP*(cin(i)-cin(i+1))/(sl_h(i)+sl_h(i+1)) sl_f = 2.0_SP*(cin(i-2)-cin(i-1))/(sl_h(i-2)+sl_h(i-1)) diss(i) = dis4*(cin(i-1)-cin(i)-0.5_SP*LIMLED2(sl_u,sl_f,2.0_SP)*(sl_h(i-1)+sl_h(i))) !! flux(i) = conv(i)+diss(i) end do conv(1) = 0.0_SP diss(1) = 0.0_SP conv(n+1) = 0.0_SP diss(n+1) = 0.0_SP do i=1,n flux(i) = conv(i)-conv(i+1)+diss(i+1)-diss(i) end do End Subroutine Calc_VFlux !========================================================================== ! Calculate LED Limiter L(u,v) !========================================================================== Function Lim(a,b) use mod_prec real(sp) lim,a,b real(sp) q,R real(sp) eps eps = epsilon(eps) q = 0. !1st order q = 1. !minmod q = 2. !van leer R = abs( (a-b)/(abs(a)+abs(b)+eps) )**q lim = .5*(1-R)*(a+b) End Function Lim ! ============================================================================= ! K.lettmann, Feb 2012, lettmann@icbm.de ! ! Methods for flux limiting for problems witht the diffusion step ! to omit negative concentrations ! ============================================================================== ! !==============================================================================| ! Horizontal flux Limitation For Scalar (f) | ! ! K.lettmann, Feb 2012, lettmann@icbm.de !==============================================================================| Subroutine limit_hor_flux_Scal(fka,fkb,ia,ib,Da,Db,ele_num,delt,exflux) ! ! This subroutine limits the total flux about a control volume segment ! in case there is not enough tracer in the source element, ! the flux is coming from. !------------------------------------------------------------------------------| use all_vars use lims, only: m,mt,n,nt,kbm1,kb use bcs use mod_obcs # if defined (SPHERICAL) USE MOD_SPHERICAL # endif implicit none real(sp), intent(in ) :: fka ! scalar quantity on k-sigma level in cv a real(sp), intent(in ) :: fkb ! scalar quantity on k-sigma level in cv b integer , intent(in ) :: ele_num ! The element/triangle we are working integer , intent(in ) :: ia,ib ! Index of the left and right node to the SCV side S real(sp), intent(in ) :: delt ! time step for diffusion equation real(sp), intent(in ) :: Da ! water depth of sigma layer [m] on side a of interface real(sp), intent(in ) :: Db ! water depth of sigma layer [m] on side b of interface real(sp), intent(inout) :: exflux ! total flux over side S (diffusion + advection) [] !----------------local-------------------------------------- integer :: i_source real(sp) :: x_ce,xa,xb,y_ce,ya,yb !coordinates of triangle nodes real(sp) :: f_source !concentrations in source element real(sp) :: A_cv !area of part of control volume real(sp) :: delh !hight of sigma-layer real(sp) :: D_source !water depth of sigma layer [m] at source node real(sp) :: amount_source !amount of tracer in source node control volume real(sp) :: flux_max !maximal possible outflux of tracer from source node control volume # if defined (SPHERICAL) real(sp) :: side1,side2,side3 ! length of triangle sides for spherical triangle # endif !------------------------------------------------------------------------------! ! ----- the coordinates of the corner points of the double control volume --- x_ce = xc(ele_num) ; y_ce = yc(ele_num) ! center node xa = vx(ia) ; ya = vy(ia) ! left node xb = vx(ib) ; yb = vy(ib) ! right node !print*,'center node: ',x_ce,y_ce ! --------------------------------------------------------------------------- ! -------- calculate the area of the tracer control volume ------------------- ! it is only the small part of the total control volume / not art1 # if defined (SPHERICAL) ! see routine cell_area for an example ! how to calculate the area of triangles on a sphere CALL ARC(x_ce,y_ce,xa,ya,side1) CALL ARC(xa,ya,xb,yb,side2) CALL ARC(xb,yb,xa,ya,side3) ! calculate area of triangle from triangle sides CALL AREA(side1,side2,side3,A_cv) A_cv = 0.5_SP * abs(A_cv) # else ! area for cartesian triangle on a plane A_cv = 0.5* abs( 0.5*( (xb-xa)*(y_ce-ya) - (x_ce-xa)*(yb-ya) ) ) # endif ! ---------------------------------------------------------------------------- ! ------- find the source element, where the flux comes from ----------------- if (exflux >= 0.0) then i_source = ia f_source = fka D_source = Da else i_source = ib f_source = fkb D_source = Db end if !print*,'source node:',i_source ! ----------------------------------------------------------------------------- ! ------- calculate the maximal possible outflow from source element --------- ! it cannot flow out more tracer than being in the element !print*,'f_source',f_source !print*,'D:',Dn(ia),Dn(ib) amount_source = f_source * A_cv flux_max = amount_source*D_source/delt !print*,'flux_max:',flux_max ! ----------------------------------------------------------------------------- ! ------ limit the exflux if necessary ---------------------------------------- if (exflux >= 0.0) then exflux = min(flux_max,exflux) else exflux = max(-flux_max,exflux) end if ! ----------------------------------------------------------------------------- return End Subroutine limit_hor_flux_Scal !==============================================================================| End Module Scalar