!### macro's ##################################################### ! #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if ! #include "tm5.inc" ! !----------------------------------------------------------------------------- ! TM5 ! !----------------------------------------------------------------------------- !BOP ! ! !MODULE: ADVECTY ! ! !DESCRIPTION: !\\ !\\ ! !INTERFACE: ! MODULE ADVECTY ! ! !USES: ! USE GO, ONLY : gol, goPr, goErr USE TM5_DISTGRID, ONLY : DGRID, GET_DISTGRID, UPDATE_HALO, REDUCE IMPLICIT NONE PRIVATE ! ! !PUBLIC MEMBER FUNCTIONS: ! PUBLIC :: advectyzoom ! ! !REVISION HISTORY: ! 2 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! ! !REMARKS: ! !EOP !------------------------------------------------------------------------ CONTAINS !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: ADVECTYZOOM ! ! !DESCRIPTION: wrapper around DYNAMV !\\ !\\ ! !INTERFACE: ! SUBROUTINE ADVECTYZOOM( REGION ) ! ! !USES: ! use dims, only : lm use global_data, only : wind_dat, mass_dat use partools, only : isRoot #ifdef with_budgets use budget_global, only : sum_advection #endif ! ! !INPUT PARAMETERS: ! integer, intent(in) :: region ! ! !REVISION HISTORY: ! ! written by patrick berkvens and mike botchev, march-june 1999 ! updated and modified by MK, dec 2002 ! ! 2 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! !EOP !------------------------------------------------------------------------ !BOC integer :: istat real :: sum_old, sum_new ! ------ START #ifdef with_budgets ! total mass tracer #1 call REDUCE( dgrid(region), mass_dat(region)%rm(:,:,:,1), mass_dat(region)%halo, 'SUM', sum_old, istat) #endif CALL DYNAMV(region) #ifdef with_budgets call REDUCE( dgrid(region), mass_dat(region)%rm(:,:,:,1), mass_dat(region)%halo, 'SUM', sum_new, istat) if ( isRoot ) sum_advection(region) = sum_advection(region) + sum_new - sum_old #endif END SUBROUTINE ADVECTYZOOM !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: DYNAMV ! ! !DESCRIPTION: south-north tracer transport: calculate amount of tracer moved in a south-north ! advection substep. ! ! method : slopes scheme ! reference : Russel and Lerner, 1979 !\\ !\\ ! !INTERFACE: ! SUBROUTINE DYNAMV( region )!, is, ie, ls, le) ! ! !USES: ! use dims, only : im, jm, lm use dims, only : okdebug, xi, nxi use dims, only : limits, nloop_max, zero, one use global_data, only : wind_dat, mass_dat use meteodata , only : m_dat use toolbox, only : escape_tm #ifdef with_budgets use budget_global, only : budget_flux, jflux1, jflux2, apply_budget_global_flux #endif use partools , only : par_reduce use chem_param, only : ntracet, ra ! ! !INPUT PARAMETERS: ! integer,intent(in) :: region ! ! !REVISION HISTORY: ! programmed by : mh, mpi HH, feb-jun 1994 ! zoom version written by mike botchev, march-june 1999 ! 2 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! !EOP !------------------------------------------------------------------------ !BOC real, dimension(:,:,:,:), pointer :: rm, rxm, rym, rzm real, dimension(:,:,:), pointer :: m, bm, mx real, dimension(:,:), allocatable :: mnew real, dimension(:,:), allocatable :: f,pf,fx,fz integer :: i,j,l,n, is,ie, js,je, ls,le, iee,iss integer :: i1, i2, j1, j2, jss, jee, status integer :: imr,imr2,jmr,lmr real :: sfs,sfzs,sfn,sfzn real :: my_beta, beta,mxval integer,dimension(3) :: mxloc integer :: iloop, nloop(lm(region)), nglob, offsetn logical :: cfl_ok, SouthPole, NorthPole, SouthBorder, NorthBorder integer :: lrg, redfact, ixe, ixs real :: summ integer :: ns, ne, lss, lee real :: l_xi, g_xi, l_nxi, g_nxi, g_nl integer,parameter :: max_nloop = 6 !------ Start ! Indices CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2,& hasSouthPole=SouthPole, hasNorthPole=NorthPole, & hasSouthBorder=SouthBorder, hasNorthBorder=NorthBorder ) lmr = lm(region) jmr = jm(region) is=i1 ; ie=i2 ; js=j1 ; je=j2 ; ls=1 ; le=lmr ! Work arrays m => m_dat(region)%data ! halo = 2 rm => mass_dat(region)%rm ! halo = 2 rxm => mass_dat(region)%rxm ! halo = 2 rym => mass_dat(region)%rym ! halo = 2 rzm => mass_dat(region)%rzm ! halo = 2 bm => wind_dat(region)%bm ! halo = 1 CALL UPDATE_HALO( dgrid(region), bm, wind_dat(region)%halo, status) CALL UPDATE_HALO( dgrid(region), m, m_dat(region)%halo, status) CALL UPDATE_HALO( dgrid(region), rm, mass_dat(region)%halo, status) CALL UPDATE_HALO( dgrid(region), rxm, mass_dat(region)%halo, status) CALL UPDATE_HALO( dgrid(region), rym, mass_dat(region)%halo, status) CALL UPDATE_HALO( dgrid(region), rzm, mass_dat(region)%halo, status) ! Reduce work domain if border of zoom region, and take care of poles if (NorthBorder) then ! j2=jmr by design if (NorthPole) je=j2-1 endif if (SouthBorder) then ! j1=1 by design if (SouthPole) js=j1+1 endif ! indices for mass update jss=js jee=je if (SouthPole) jss=js-1 ! =j1=1 if (NorthPole) jee=je+1 ! =j2=jmr ! if requested limit meridional slopes such that no negative if (limits) then do n = 1, ntracet do l = ls, le do j = js - 1, je + 1 do i = is, ie rym(i,j,l,n) = max (min (rym(i,j,l,n), rm(i,j,l,n)), -rm(i,j,l,n)) end do end do end do end do end if g_nl = 0.0 l_xi = 0.0 l_nxi = 0.0 allocate ( f( i1-1:i2+1, j1-1:j2+1 )) ! halo=1 allocate ( pf( i1-1:i2+1, j1-1:j2+1 )) ! halo=1 allocate ( fx( i1-1:i2+1, j1-1:j2+1 )) ! halo=1 allocate ( fz( i1-1:i2+1, j1-1:j2+1 )) ! halo=1 allocate ( mnew( i1:i2, j1:j2 )) ! halo=0 allocate ( mx(i1-1:i2+1, j1-1:j2+1, ls:le)) ! halo=1 ! ================= Find number of iterations needed (per layer) LEVELS: do l=ls,le nloop(l) = 1 beta = 2.0 do while(abs(beta) >= one .and. nloop(l) < max_nloop) mx(is:ie,js-1:je+1,1) = m(is:ie,js-1:je+1,l) ! use 1st layer of max as a 2D work array xloop : do iloop = 1, nloop(l) cfl_ok = .true. IJ: do j=js,je+1 do i=is,ie if (bm(i,j,l)>=zero) then my_beta=bm(i,j,l)/mx(i,j-1,1) else my_beta=bm(i,j,l)/mx(i,j,1) end if if (abs(my_beta)>=one) exit IJ end do end do IJ my_beta = abs(my_beta) call Par_Reduce(my_beta, 'MAX', beta, status, all=.true.) if(status==1) then write(gol,*) "error par_reduce";call goPr end if if (abs(beta)>=one) then cfl_ok = .false. exit xloop end if ! else... if (cfl_ok.and.(iloop/=nloop(l))) then mx(is:ie,jss:jee,1) = mx(is:ie,jss:jee,1) + bm(is:ie,jss:jee,l) - bm(is:ie,jss+1:jee+1,l) CALL UPDATE_HALO( dgrid(region), mx(:,:,1), 1, status) end if end do xloop if ( .not. cfl_ok ) then beta = 2.0 bm(:,:,l) = bm(:,:,l)*nloop(l)/(nloop(l)+1) ! reduce mass flux if ( okdebug) print *,'dynamv: ', i,j,l, & 'nloop increased to', nloop(l) + 1, beta nloop(l) = nloop(l) + 1 if(nloop(l) == max_nloop) call escape_tm('nloop too high in dynamv') end if end do !while end do LEVELS ! advect info g_nl = max(g_nl, REAL(maxval(nloop))) ! ================= Loop over tracers and vertical layers to update masses ! Store init M, so we can get the loop over tracer outside the CFL. ! Thus we can limit the mpi comm, and switch Trac and levels loops => faster mx(i1-1:i2+1, j1-1:j2+1, ls:le) = m(i1-1:i2+1, j1-1:j2+1, ls:le) TRAC: do n=1,ntracet m(i1-1:i2+1, j1-1:j2+1, ls:le) = mx(i1-1:i2+1, j1-1:j2+1, ls:le) !reset LEV2: do l=ls,le CFL: DO iloop = 1,nloop(l) !-- calculate new air mass distribution mnew(is:ie,jss:jee) = m(is:ie,jss:jee,l) + & bm(is:ie,jss:jee,l) - bm(is:ie,jss+1:jee+1,l) !-- compute all inner fluxes ! f(*,j,*) is flux entering j-th cell from below?cmk do j=js+1,je do i=is,ie if (bm(i,j,l)>=zero) then beta=bm(i,j,l)/m(i,j-1,l) f(i,j)=beta*(rm(i,j-1,l,n)+(one-beta)*rym(i,j-1,l,n)) pf(i,j)=bm(i,j,l)*(beta*beta*rym(i,j-1,l,n)-3.*f(i,j)) fx(i,j)=beta*rxm(i,j-1,l,n) fz(i,j)=beta*rzm(i,j-1,l,n) else beta=bm(i,j,l)/m(i,j,l) f(i,j)=beta*(rm(i,j,l,n)-(one+beta)*rym(i,j,l,n)) pf(i,j)=bm(i,j,l)*(beta*beta*rym(i,j,l,n)-3.*f(i,j)) fx(i,j)=beta*rxm(i,j,l,n) fz(i,j)=beta*rzm(i,j,l,n) end if l_xi=max(l_xi,abs(beta)) if (abs(beta)>=one) then l_nxi=l_nxi+1 end if end do end do ! Case of JS if ( SouthPole ) then ! js=2 do i=is,ie ! this is the specific for js-1: fz(i,1)=zero fx(i,1)=zero pf(i,1)=zero f(i,1)=zero if (bm(i,2,l)>=zero) then ! this is the specific case beta=bm(i,2,l)/m(i,1,l) f(i,2)=beta*rm(i,1,l,n) pf(i,2)=-3.*bm(i,2,l)*f(i,2) fx(i,2)=zero fz(i,2)=beta*rzm(i,1,l,n) else ! like above beta=bm(i,2,l)/m(i,2,l) f(i,2)=beta*(rm(i,2,l,n)-(one+beta)*rym(i,2,l,n)) pf(i,2)=bm(i,2,l)*(beta*beta*rym(i,2,l,n)-3.*f(i,2)) fx(i,2)=beta*rxm(i,2,l,n) fz(i,2)=beta*rzm(i,2,l,n) end if l_xi=max(l_xi,abs(beta)) if (abs(beta)>=one) then l_nxi=l_nxi+1 end if end do else ! do like above j = js do i=is,ie !no reduced grid allowed if (bm(i,j,l)>=zero) then beta=bm(i,j,l)/m(i,j-1,l) f(i,j)=beta*(rm(i,j-1,l,n)+(one-beta)*rym(i,j-1,l,n)) pf(i,j)=bm(i,j,l)*(beta*beta*rym(i,j-1,l,n)-3.*f(i,j)) fx(i,j)=beta*rxm(i,j-1,l,n) fz(i,j)=beta*rzm(i,j-1,l,n) else beta=bm(i,j,l)/m(i,j,l) f(i,j)=beta*(rm(i,j,l,n)-(one+beta)*rym(i,j,l,n)) pf(i,j)=bm(i,j,l)*(beta*beta*rym(i,j,l,n)-3.*f(i,j)) fx(i,j)=beta*rxm(i,j,l,n) fz(i,j)=beta*rzm(i,j,l,n) end if l_xi=max(l_xi,abs(beta)) if (abs(beta)>=one) then l_nxi=l_nxi+1 end if end do end if ! compute boundary fluxes south pole... ! Case of JE+1 if ( NorthPole ) then ! je+1=jmr do i=is,ie if (bm(i,jmr,l)>=zero) then !like above beta=bm(i,jmr,l)/m(i,jmr-1,l) f(i,jmr)=beta*(rm(i,jmr-1,l,n)+(one-beta)*rym(i,jmr-1,l,n)) pf(i,jmr)=bm(i,jmr,l)*(beta*beta*rym(i,jmr-1,l,n) - & 3.*f(i,jmr)) fx(i,jmr)=beta*rxm(i,jmr-1,l,n) fz(i,jmr)=beta*rzm(i,jmr-1,l,n) else ! this is the specific case beta=bm(i,jmr,l)/m(i,jmr,l) ! for solid-body test and polar mixing f(i,jmr)=beta*rm(i,jmr,l,n) pf(i,jmr)=-3.*bm(i,jmr,l)*f(i,jmr) fx(i,jmr)=zero ! for solid-body test and polar mixing fz(i,jmr)=beta*rzm(i,jmr,l,n) end if l_xi=max(l_xi,abs(beta)) if (abs(beta)>=one) then l_nxi=l_nxi+1 end if end do else !zoom region not touching north pole j = je+1 do i=is,ie !no reduced grid allowed if (bm(i,j,l)>=zero) then beta=bm(i,j,l)/m(i,j-1,l) f(i,j)=beta*(rm(i,j-1,l,n)+(one-beta)*rym(i,j-1,l,n)) pf(i,j)=bm(i,j,l)*(beta*beta*rym(i,j-1,l,n)-3.*f(i,j)) fx(i,j)=beta*rxm(i,j-1,l,n) fz(i,j)=beta*rzm(i,j-1,l,n) else beta=bm(i,j,l)/m(i,j,l) f(i,j)=beta*(rm(i,j,l,n)-(one+beta)*rym(i,j,l,n)) pf(i,j)=bm(i,j,l)*(beta*beta*rym(i,j,l,n)-3.*f(i,j)) fx(i,j)=beta*rxm(i,j,l,n) fz(i,j)=beta*rzm(i,j,l,n) end if l_xi=max(l_xi,abs(beta)) if (abs(beta)>=one) then l_nxi=l_nxi+1 end if end do end if ! compute boundary fluxes north pole... #ifdef with_budgets ! ! Finished computing fluxes. Now apply ! !-- first compute INCOMING fluxes from the south... if (apply_budget_global_flux) then do i=is,ie if ((jflux1(region) <= j2 ) .and. (jflux1(region) >= j1 )) then budget_flux(region)%flux_y1(i,l,n) = budget_flux(region)%flux_y1(i,l,n) + & f(i,jflux1(region))*1e3/ra(n) end if if ((jflux2(region) <= j2 ) .and. (jflux2(region) >= j1 )) then budget_flux(region)%flux_y2(i,l,n) = budget_flux(region)%flux_y2(i,l,n) + & f(i,jflux2(region))*1e3/ra(n) end if enddo endif #endif ! !-- Calculate new tracer mass, and tracer mass slopes ! do j=js,je do i=is,ie rm(i,j,l,n) = rm(i,j,l,n)+(f(i,j)-f(i,j+1)) rym(i,j,l,n) = rym(i,j,l,n)+(pf(i,j)-pf(i,j+1) & - (bm(i,j,l)-bm(i,j+1,l))*rym(i,j,l,n) & + 3.*((bm(i,j,l)+bm(i,j+1,l))*rm(i,j,l,n) & - (f(i,j)+f(i,j+1))*m(i,j,l)))/mnew(i,j) if ( limits) rym(i,j,l,n) = max( min(rym(i,j,l,n), & rm(i,j,l,n)), -rm(i,j,l,n) ) rxm(i,j,l,n)=rxm(i,j,l,n)+(fx(i,j)-fx(i,j+1)) rzm(i,j,l,n)=rzm(i,j,l,n)+(fz(i,j)-fz(i,j+1)) end do end do !forall ! case of JS-1 if south pole (js=2) if ( SouthPole ) then rm (is:ie, 1,l,n) = rm(is:ie, 1,l,n) - f(is:ie,2) rzm(is:ie, 1,l,n) = rzm(is:ie, 1,l,n) - fz(is:ie,2) end if ! case of JE+1, only if north pole (je+1=jmr) if ( NorthPole ) then rm (is:ie,jmr,l,n) = rm(is:ie,jmr,l,n) + f(is:ie,jmr) rzm(is:ie,jmr,l,n) = rzm(is:ie,jmr,l,n) + fz(is:ie,jmr) end if ! store new air mass in m array m(is:ie,jss:jee,l) = mnew(is:ie,jss:jee) ! update anything that changes and may be used with +/- index shift, ! but only if not the last step if (iloop/=nloop(l)) then !print*, "PLS-test-halo" (FIXME: j_only is not yet implemented but should reduce comm by a factor of 2 here) CALL UPDATE_HALO( dgrid(region), m(:,:,l), m_dat(region)%halo, status, j_only=.true.) CALL UPDATE_HALO( dgrid(region), rm(:,:,l,n), mass_dat(region)%halo, status, j_only=.true.) CALL UPDATE_HALO( dgrid(region), rxm(:,:,l,n), mass_dat(region)%halo, status, j_only=.true.) CALL UPDATE_HALO( dgrid(region), rym(:,:,l,n), mass_dat(region)%halo, status, j_only=.true.) CALL UPDATE_HALO( dgrid(region), rzm(:,:,l,n), mass_dat(region)%halo, status, j_only=.true.) end if end do CFL ! iloop end do LEV2 ! end of l-loop over vertical layers.... end do TRAC ! n-loop ! restore old bm's do l=ls,le bm(:,:,l) = bm(:,:,l)*nloop(l) end do ! Gather more alorithm information CALL PAR_REDUCE( l_xi, 'max', g_xi, status, .true.) CALL PAR_REDUCE( l_nxi, 'sum', g_nxi, status, .true.) nloop_max(region,2) = max (nloop_max(region,2), nint (g_nl)) xi(region,2) = max (xi(region,2), g_xi) nxi(region,2) = nxi(region,2) + nint (g_nxi) ! Done deallocate (mx, mnew) deallocate (f) deallocate (pf) deallocate (fx) deallocate (fz) nullify(m) nullify(rm) nullify(rxm) nullify(rym) nullify(rzm) nullify(bm) END SUBROUTINE DYNAMV !EOC END MODULE ADVECTY