!### macro's ##################################################### ! #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr #define IF_NOTOK_RETURN(action) if (test/=0) then; TRACEBACK; action; return; end if #define IF_ERROR_RETURN(action) if (test> 0) then; TRACEBACK; action; return; end if ! #include "tm5.inc" ! !----------------------------------------------------------------------------- ! TM5 ! !----------------------------------------------------------------------------- !BOP ! ! !MODULE: ADVECTX ! ! !DESCRIPTION: !\\ !\\ ! !INTERFACE: ! MODULE ADVECTX ! ! !USES: ! USE GO, ONLY : gol, goPr, goErr USE TM5_DISTGRID, ONLY : DGRID, GET_DISTGRID, REDUCE, UPDATE_HALO_JBAND USE PARTOOLS, ONLY : isRoot, npe_lon IMPLICIT NONE PRIVATE ! ! !PUBLIC MEMBER FUNCTIONS: ! PUBLIC :: advectxzoom ! ! !PRIVATE DATA MEMBERS: ! character(len=*), parameter :: mname='advectx' ! ! !REVISION HISTORY: ! 1 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! 9 Jan 2013 - P. Le Sager - works with reduced grid ! ! !REMARKS: ! !EOP !------------------------------------------------------------------------ CONTAINS !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: ADVECTXZOOM ! ! !DESCRIPTION: set parameters for advectx !\\ !\\ ! !INTERFACE: ! SUBROUTINE ADVECTXZOOM( REGION, TEST ) ! !USES: ! ! use dims, only : lm #ifdef with_budgets use budget_global, only : sum_advection #endif use global_data, only : mass_dat, wind_dat ! ! !INPUT PARAMETERS: ! integer, intent(in) :: region ! ! !OUTPUT PARAMETERS: ! integer, intent(out) :: test ! ! !REVISION HISTORY: ! written by patrick berkvens and mike botchev, march-june 1999 ! updated and modified by MK, dec 2002 ! 1 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! ! !REMARKS: ! !EOP !------------------------------------------------------------------------ !BOC character(len=*), parameter :: rname = mname//'/advectxzoom' integer :: i1, j1, i2, j2, istat, lmr real :: sum_old, sum_new !-------------- start CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 ) lmr = lm(region) #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 ADVECTX_WORK(region, j1, j2, 1, lmr, test) IF_NOTOK_RETURN(test=1) #ifdef with_budgets call REDUCE( dgrid(region), mass_dat(region)%rm(:,:,:,1), mass_dat(region)%halo, 'SUM', sum_new, istat) if( isRoot ) then sum_advection(region) = sum_advection(region) + sum_new - sum_old end if #endif test=0 END SUBROUTINE ADVECTXZOOM !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: ADVECTX_WORK ! ! !DESCRIPTION: makes reduced grid pre-/postprocessing, call dynamu !\\ !\\ ! !INTERFACE: ! SUBROUTINE ADVECTX_WORK( region, js, je, ls, le, test) ! ! !USES: ! use dims, only : im, jm, lm use redgridZoom, only : grid_reduced, nred, uni2red, uni2red_mf, red2uni, idle_xadv use global_data, only : wind_dat, mass_dat use meteodata , only : m_dat use chem_param, only : ntracet ! ! !INPUT PARAMETERS: ! integer,intent(in) :: region integer,intent(in) :: js integer,intent(in) :: je integer,intent(in) :: ls integer,intent(in) :: le ! ! !OUTPUT PARAMETERS: ! integer, intent(out) :: test ! ! !REVISION HISTORY: ! ! written by mike botchev, march-june 1999 ! 1 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! !EOP !------------------------------------------------------------------------ !BOC character(len=*), parameter :: rname = mname//'/advectx_work' real, dimension(:,:,:), pointer :: m real, dimension(:,:,:), pointer :: am real, dimension(:,:,:), allocatable :: m_uni ! for reduced grid... real, dimension(:,:,:), allocatable :: am_uni ! for reduced grid... real :: mxval integer,dimension(3) :: mxloc integer :: imr, jmr, lmr, i1, i2, j1, j2, halo ! --------- START #ifndef slopes test=1 TRACEBACK return #endif ! Transform to the reduced grid if ( grid_reduced ) then CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 ) lmr = lm(region) imr = im(region) halo = m_dat(region)%halo allocate( m_uni( i1-halo:i2+halo, j1-halo:j2+halo, lmr )) halo = wind_dat(region)%halo allocate(am_uni( i1-halo:i2+halo, j1-halo:j2+halo, 0:lmr+1)) am => wind_dat(region)%am m => m_dat(region)%data ! take care of BC for uniform am, so that am_uni is correct when ! updating m_uni after the call to dynamun if (npe_lon==1) then am(-1:0,j1:j2,:) = am(imr-1:imr,j1:j2,:) am(i2+1,j1:j2,:) = am( 1,j1:j2,:) else call UPDATE_HALO_JBAND(dgrid(region), am, halo, test ) IF_NOTOK_RETURN(test=1) endif ! save non-reduced m and am in m_uni and am_uni: m_uni = m am_uni = am ! reduce m call uni2red(region,i1,i2,j1,j2,test) IF_NOTOK_RETURN(test=1) ! reduce am (and update halo of reduced zonal bands) call uni2red_mf( region,i1,i2,j1,j2,test ) IF_NOTOK_RETURN(test=1) end if ! transport if (.not.idle_xadv) then CALL DYNAMU (region,js,je,ls,le, test) IF_NOTOK_RETURN(test=1) endif ! Transform from reduced to uniform grid if ( grid_reduced ) then ! advection on uniform grid m_uni(i1:i2,j1:j2,1:lmr) = m_uni(i1:i2,j1:j2,1:lmr) + & am_uni(i1-1:i2-1,j1:j2,1:lmr) - am_uni(i1:i2,j1:j2,1:lmr) ! redistribute rm,rxm,rym,rzm by using m_uni and m halo = m_dat(region)%halo call red2uni(region, i1, i2, j1, j2, halo, m_uni, test) ! recreate rm/rxm/rym/rzm by using equal masses (not m_uni) !call red2uni_em(region) ! recreate am: am = am_uni nullify(am) nullify(m) deallocate(am_uni) deallocate(m_uni) endif test=0 END SUBROUTINE ADVECTX_WORK !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: DYNAMU ! ! !DESCRIPTION: east-west tracer transport: calculate amount of tracer moved in an east-west ! advection substep ! ! method : slopes scheme ! reference : Russel and Lerner, 1979 !\\ !\\ ! !INTERFACE: ! SUBROUTINE DYNAMU( region, js, je, ls, le, test) ! ! !USES: ! use dims, only : okdebug, nregions, parent use dims, only : im, jm, lm, xref, yref, zref, tref use dims, only : zero, one, xi, nxi, nloop_max, limits, xcyc use redgridZoom, only : grid_reduced, nred, imredj use redgridZoom, only : mfl_alt1, m_alt1, rm_alt1, rxm_alt1, rym_alt1, rzm_alt1 use global_data, only : wind_dat, mass_dat use meteodata , only : m_dat #ifdef with_budgets use budget_global, only : budget_flux, apply_budget_global_flux use budget_global, only : iflux1, iflux2, jflux1, jflux2 #endif use chem_param, only : ntracet, ra use partools, only : par_reduce, isRowRoot ! ! !INPUT PARAMETERS: ! integer,intent(in) :: region integer,intent(in) :: js integer,intent(in) :: je integer,intent(in) :: ls integer,intent(in) :: le ! ! !OUTPUT PARAMETERS: ! integer, intent(out) :: test ! ! !REVISION HISTORY: ! programmed by mh, mpi HH 1994-1995 ! zoom version written by mike botchev, march-june 1999 ! 1 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! !EOP !------------------------------------------------------------------------ !BOC character(len=*), parameter :: rname = mname//'/dynamu' real, dimension(:,:,:,:), pointer :: rm, rxm, rym, rzm real, dimension(:,:,:), pointer :: m, am real, dimension(:), allocatable :: f, pf, fy, fz, mnew, mx real, dimension(:,:), allocatable :: wrk2 integer, allocatable :: ie(:) integer :: i, is, j, l, n, offsetn integer :: i1, i2, j1, j2 logical :: WestBorder, EastBorder integer :: imr, jmr, lmr, tref_, xref_, yref_, zref_, ic, iloop, iemax integer :: nloop(jm(region),lm(region)) real :: min_one, max_one, min_all, max_all real :: my_alpha, alpha, max_alpha, alphamax, x, rmold logical :: cfl_ok integer, parameter :: max_nloop = 50 integer :: ns, ne, jss, jee, iie real :: l_xi, g_xi, l_nl, g_nl character(len=2) :: sloop !------------- Start ! ------------ ! Bounds ! ------------ CALL GET_DISTGRID( dgrid(region), & I_STRT=i1, I_STOP=i2, & J_STRT=j1, J_STOP=j2, & hasWestBorder=WestBorder, hasEastBorder=EastBorder ) lmr = lm(region) imr = im(region) allocate(ie(j1:j2)) ! ------------ ! Work arrays ! ------------ if ( ( grid_reduced ) .and. (npe_lon /= 1) .and. (nred(region)/=0) ) then am => mfl_alt1 m => m_alt1 rm => rm_alt1 rxm => rxm_alt1 rym => rym_alt1 rzm => rzm_alt1 is=1 ie=imr iemax=maxval(imredj(j1:j2,region)) else am => wind_dat(region)%am m => m_dat(region)%data rm => mass_dat(region)%rm rxm => mass_dat(region)%rxm rym => mass_dat(region)%rym rzm => mass_dat(region)%rzm is=i1 ie=i2 iemax=i2 endif allocate( f( is-1:iemax+1 )) ! halo=1 allocate( pf( is-1:iemax+1 )) ! halo=1 allocate( fy( is-1:iemax+1 )) ! halo=1 allocate( fz( is-1:iemax+1 )) ! halo=1 allocate( mx( is-2:iemax+2 )) ! halo=2 (was 1) allocate(mnew( is-1:iemax+1 )) ! halo=1 (was 0) allocate(wrk2( is-2:iemax+2, ntracet )) ! halo=2 ! ------------ ! Reduced grid & halo ! -------------- if ( ( grid_reduced .and. npe_lon==1 ).or.(grid_reduced .and. npe_lon/=1.and.nred(region)>0)) then ie = imredj(j1:j2,region) do j=j1,j2 iie=ie(j) m( -1:0, j,:) = m(iie-1:iie,j,:) rm( -1:0, j,:,:) = rm(iie-1:iie,j,:,:) rxm( -1:0, j,:,:) = rxm(iie-1:iie,j,:,:) rym( -1:0, j,:,:) = rym(iie-1:iie,j,:,:) rzm( -1:0, j,:,:) = rzm(iie-1:iie,j,:,:) m(iie+1:iie+2, j,:) = m(1:2,j,:) rm(iie+1:iie+2, j,:,:) = rm(1:2,j,:,:) rxm(iie+1:iie+2, j,:,:) = rxm(1:2,j,:,:) rym(iie+1:iie+2, j,:,:) = rym(1:2,j,:,:) rzm(iie+1:iie+2, j,:,:) = rzm(1:2,j,:,:) end do ! halo of am is filled in advectx_work (thru uni2red_mf for reduced part) else CALL UPDATE_HALO_JBAND( dgrid(region), am, wind_dat(region)%halo, test) CALL UPDATE_HALO_JBAND( dgrid(region), m, m_dat(region)%halo, test) CALL UPDATE_HALO_JBAND( dgrid(region), rm, mass_dat(region)%halo, test) CALL UPDATE_HALO_JBAND( dgrid(region), rxm, mass_dat(region)%halo, test) CALL UPDATE_HALO_JBAND( dgrid(region), rym, mass_dat(region)%halo, test) CALL UPDATE_HALO_JBAND( dgrid(region), rzm, mass_dat(region)%halo, test) end if ! if requested limit zonal slopes such that no negative tracer masses ! should occur if ( limits ) then do n = 1, ntracet do l = ls, le do j = js, je do i = is - 1, ie(j) + 1 rxm(i,j,l,n) = max (min (rxm(i,j,l,n), rm(i,j,l,n)), -rm(i,j,l,n)) end do end do end do end do end if ! init stat holders l_nl = 0.0 l_xi = 0.0 ! max alpha ! ================= Find number of iterations needed LATBAND: DO l= ls, le ! work in 1D, so final nloop can differ with latitude and levels DO j = js, je iie = ie(j) ! Determine number of loops required to avoid CFLs... nloop(j,l) = 1 ! default run the loop one time! alpha = 2.0 max_alpha = 0.0 do while ( abs(alpha) >= one .and. nloop(j,l) < max_nloop ) ! copy initial mass to temp array mx(is-2:iie+2) = m(is-2:iie+2,j,l) xloop: do iloop = 1, nloop(j,l) cfl_ok = .true. indloop : do i=is-1,iie if (am(i,j,l)>=zero) then my_alpha=am(i,j,l)/mx(i) else my_alpha=am(i,j,l)/mx(i+1) end if max_alpha = max(max_alpha, abs(my_alpha)) if((abs(my_alpha)>=one)) exit indloop end do indloop ! sync if (grid_reduced .and. npe_lon/=1.and.nred(region)>0) then alpha=max_alpha else call Par_Reduce(max_alpha, 'MAX', alpha, test, all=.true., row=.true.) endif if (alpha>=one) then cfl_ok = .false. exit xloop end if ! cfl ok, then update mass for next iteration if any if(iloop/=nloop(j,l)) then ! is:iie updated ! is-1, iie+1 are BC, and also updated (assumption that ! xcyc(region)==1), so we do not need to call update halo ! every other iteration. mx(is-1:iie+1) = mx(is-1:iie+1) + am(is-2:iie,j,l) - am(is-1:iie+1,j,l) if (modulo(iloop,2)==0) then if ( ( grid_reduced .and. npe_lon==1 ).or.(grid_reduced .and. npe_lon/=1.and.nred(region)>0)) then mx( -1:0) = mx(iie-1:iie) mx(iie+1:iie+2) = mx( 1:2) else call UPDATE_HALO_JBAND( dgrid(region), mx, 2, test) end if end if end if end do xloop ! CLF not ok : reduce mass flux if(.not.cfl_ok) then am(is-2:iie+1,j,l) = am(is-2:iie+1,j,l)*nloop(j,l)/(nloop(j,l)+1) nloop(j,l) = nloop(j,l) + 1 max_alpha = 0.0 if (nloop(j,l) == max_nloop) then write(gol,*)'nloop too high'; call goErr test=1; TRACEBACK return end if end if end do !while alpha>1 l_xi = MAX (l_xi, alpha) end DO end DO LATBAND ! ================= UPDATE MASSES LATBAND2: DO l= ls, le DO j = js, je iie = ie(j) CFL: do iloop = 1,nloop(j,l) ! calculate new air mass distribution mnew(is-1:iie+1) = m(is-1:iie+1,j,l) + am(is-2:iie,j,l)-am(is-1:iie+1,j,l) ! loop over tracers TRAC: do n=1,ntracet ! calculate fluxes for rm,rxm,rym,rzm do i=is-1,iie if (am(i,j,l)>=zero) then alpha = am(i,j,l)/m(i,j,l) f(i) = alpha*(rm(i,j,l,n)+(one-alpha)*rxm(i,j,l,n)) pf(i) = am(i,j,l)*(alpha*alpha*rxm(i,j,l,n) - 3.*f(i)) fy(i) = alpha*rym(i,j,l,n) fz(i) = alpha*rzm(i,j,l,n) else alpha = am(i,j,l)/m(i+1,j,l) f(i) = alpha*(rm(i+1,j,l,n)-(one+alpha)*rxm(i+1,j,l,n)) pf(i) = am(i,j,l)*(alpha*alpha*rxm(i+1,j,l,n) - 3.*f(i)) fy(i) = alpha*rym(i+1,j,l,n) fz(i) = alpha*rzm(i+1,j,l,n) end if !xi(region,1)=max(xi(region,1),abs(alpha)) end do #ifdef with_budgets ! ! add up flux budget! ! FIXME: note that this woukd be wrong if grid is reduced, so set it to ! a quiet NaN (but possible only with F2003) ! if ( apply_budget_global_flux ) then if ( (iflux1(region)-1 >= is) .and. (iflux1(region)-1 <= iie) ) then budget_flux(region)%flux_x1(j,l,n) = budget_flux(region)%flux_x1(j,l,n) & + f(iflux1(region)-1)*1e3/ra(n) ! moles endif if ( (iflux2(region)-1 >= is) .and. (iflux2(region)-1 <= iie) ) then budget_flux(region)%flux_x2(j,l,n) = budget_flux(region)%flux_x2(j,l,n) & + f(iflux2(region)-1)*1e3/ra(n) endif end if #endif ! ! calculate new tracer mass, and tracer mass slopes ! do i=is, iie rm(i,j,l,n) = rm(i,j,l,n) + (f(i-1)-f(i)) rxm(i,j,l,n) = rxm(i,j,l,n) + (pf(i-1)-pf(i) & - (am(i-1,j,l)-am(i,j,l))*rxm(i,j,l,n) & + 3.*((am(i-1,j,l)+am(i,j,l))*rm(i,j,l,n) & - (f(i-1)+f(i))*m(i,j,l)))/mnew(i) !CMK: apply limits again: might be in nloop! if ( limits ) rxm(i,j,l,n) = & max(min(rxm(i,j,l,n),rm(i,j,l,n)),-rm(i,j,l,n)) rym(i,j,l,n) = rym(i,j,l,n) + (fy(i-1)-fy(i)) rzm(i,j,l,n) = rzm(i,j,l,n) + (fz(i-1)-fz(i)) end do end do TRAC ! end of n-loop ! store new air mass in m array m(is-1:iie+1,j,l)=mnew(is-1:iie+1) ! update anything that changes and may be used with +/- index shift in next iloop if(iloop/=nloop(j,l)) then if ( ( grid_reduced .and. npe_lon==1 ).or.(grid_reduced .and. npe_lon/=1.and.nred(region)>0)) then m( -1:0, j,:) = m(iie-1:iie,j,:) rm( -1:0, j,:,:) = rm(iie-1:iie,j,:,:) rxm( -1:0, j,:,:) = rxm(iie-1:iie,j,:,:) rym( -1:0, j,:,:) = rym(iie-1:iie,j,:,:) rzm( -1:0, j,:,:) = rzm(iie-1:iie,j,:,:) m(iie+1:iie+2, j,:) = m(1:2,j,:) rm(iie+1:iie+2, j,:,:) = rm(1:2,j,:,:) rxm(iie+1:iie+2, j,:,:) = rxm(1:2,j,:,:) rym(iie+1:iie+2, j,:,:) = rym(1:2,j,:,:) rzm(iie+1:iie+2, j,:,:) = rzm(1:2,j,:,:) else wrk2 = rm(:,j,l,:) CALL UPDATE_HALO_JBAND( dgrid(region), wrk2, mass_dat(region)%halo, test) rm(:,j,l,:) = wrk2 wrk2 = rxm(:,j,l,:) CALL UPDATE_HALO_JBAND( dgrid(region), wrk2, mass_dat(region)%halo, test) rxm(:,j,l,:) = wrk2 wrk2 = rym(:,j,l,:) CALL UPDATE_HALO_JBAND( dgrid(region), wrk2, mass_dat(region)%halo, test) rym(:,j,l,:) = wrk2 wrk2 = rzm(:,j,l,:) CALL UPDATE_HALO_JBAND( dgrid(region), wrk2, mass_dat(region)%halo, test) rzm(:,j,l,:) = wrk2 end if end if end do CFL ! iloop ! restore 'old' am am(is-2:iie+1,j,l) = am(is-2:iie+1,j,l)*nloop(j,l) enddo enddo LATBAND2 ! store algo info l_nl = REAL(maxval(nloop(js:je,ls:le))) if (grid_reduced .and. npe_lon/=1) then if (nred(region)==0) then call Par_Reduce(l_nl, 'MAX', g_nl, test, all=.false., row=.true.) l_nl=g_nl end if if(isRowRoot)then call Par_Reduce(l_nl, 'MAX', g_nl, test, all=.false., col=.true.) endif else call Par_Reduce(l_nl, 'MAX', g_nl, test, all=.false.) endif if (grid_reduced .and. npe_lon/=1) then if (nred(region)==0) then call Par_Reduce(l_xi, 'MAX', g_xi, test, all=.false., row=.true.) l_xi=g_xi end if if(isRowRoot)then call Par_Reduce(l_xi, 'MAX', g_xi, test, all=.false., col=.true.) endif else call Par_Reduce(l_xi, 'MAX', g_xi, test, all=.false.) endif deallocate(f) deallocate(pf) deallocate(fy) deallocate(fz) deallocate(mnew) deallocate(mx, wrk2) deallocate(ie) if ( isRoot ) then nloop_max(region,1) = max (nloop_max(region,1), nint (g_nl)) xi(region,1) = max (xi(region,1), g_xi) end if nullify(am) nullify(m) nullify(rm) nullify(rxm) nullify(rym) nullify(rzm) test=0 END SUBROUTINE DYNAMU !EOC END MODULE ADVECTX