66 use fms_mod
, only: file_exist, check_nml_error, &
67 open_namelist_file, close_file, stdlog, &
68 mpp_pe, mpp_root_pe, fatal, error_mesg
69 use mpp_mod
, only: get_unit, input_nml_file, mpp_error
70 use mpp_domains_mod
, only: mpp_update_domains, domain2d
71 use constants_mod
, only: grav, radius, pi=>pi_8
76 use fv_mp_mod, only: mp_stop, mp_reduce_min, mp_reduce_max, is_master
133 subroutine surfdrv(npx, npy, grid, agrid, area, dx, dy, dxa, dya, dxc, dyc, sin_sg, phis, &
134 stretch_fac, nested, npx_global, domain,grid_number, bd, regional)
137 #include <netcdf.inc> 138 integer,
intent(in):: npx, npy
142 real(kind=R_GRID),
intent(in)::area(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng)
143 real,
intent(in):: dx(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng+1)
144 real,
intent(in):: dy(bd%is-ng:bd%ie+ng+1, bd%js-ng:bd%je+ng)
145 real,
intent(in),
dimension(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng)::dxa, dya
146 real,
intent(in)::dxc(bd%is-ng:bd%ie+ng+1, bd%js-ng:bd%je+ng)
147 real,
intent(in)::dyc(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng+1)
149 real(kind=R_GRID),
intent(in):: grid(bd%is-ng:bd%ie+ng+1, bd%js-ng:bd%je+ng+1,2)
150 real(kind=R_GRID),
intent(in):: agrid(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng,2)
151 real,
intent(IN):: sin_sg(bd%isd:bd%ied,bd%jsd:bd%jed,9)
152 real(kind=R_GRID),
intent(IN):: stretch_fac
153 logical,
intent(IN) :: nested, regional
154 integer,
intent(IN) :: npx_global
155 type(domain2d),
intent(INOUT) :: domain
156 integer,
intent(IN) :: grid_number
159 real,
intent(out):: phis(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng)
161 real,
allocatable :: z2(:,:)
165 character(len=80) :: topoflnm
166 real(kind=4),
allocatable :: ft(:,:), zs(:,:)
167 real,
allocatable :: lon1(:), lat1(:)
168 real dx1, dx2, dy1, dy2, lats, latn, r2d
169 real(kind=R_GRID) da_max
170 real zmean, z2mean, delg, rgrav
172 integer i, j, n, mdim
174 integer ncid, lonid, latid, ftopoid, htopoid
175 integer jstart, jend, start(4), nread(4)
178 integer :: is, ie, js, je
179 integer :: isd, ied, jsd, jed
180 real phis_coarse(bd%isd:bd%ied, bd%jsd:bd%jed)
196 phis(i,j) = phis(i,j)*rgrav
202 phis_coarse(i,j) = phis(i,j)
215 if (grid_number > 1)
write(
grid_string,
'(A, I1)')
' g', grid_number
224 status = nf_open(
surf_file, nf_nowrite, ncid)
225 if (status .ne. nf_noerr)
call handle_err(status)
227 status = nf_inq_dimid(ncid,
'lon', lonid)
228 if (status .ne. nf_noerr)
call handle_err(status)
229 status = nf_inq_dimlen(ncid, lonid, londim)
230 if (status .ne. nf_noerr)
call handle_err(status)
233 status = nf_inq_dimid(ncid,
'lat', latid)
234 if (status .ne. nf_noerr)
call handle_err(status)
235 status = nf_inq_dimlen(ncid, latid, latdim)
236 if (status .ne. nf_noerr)
call handle_err(status)
239 if ( is_master() )
then 240 if (
nlon==43200 )
then 248 call error_mesg (
'surfdrv',
'Raw IEEE data format no longer supported !!!', fatal )
251 call error_mesg (
'surfdrv',
'surface file '//trim(
surf_file)//
' not found !', fatal )
254 allocate ( lat1(
nlat+1) )
255 allocate ( lon1(
nlon+1) )
261 dx1 = 2.*pi/
real(
nlon)
265 lon1(i) = dx1 *
real(i-1) 269 lat1(
nlat+1) = 0.5*pi
271 lat1(j) = -0.5*pi + dy1*(j-1)
286 lats = min( lats, grid(i,j,2), grid(i+1,j,2), grid(i,j+1,2), grid(i+1,j+1,2), agrid(i,j,2) )
287 latn = max( latn, grid(i,j,2), grid(i+1,j,2), grid(i,j+1,2), grid(i+1,j+1,2), agrid(i,j,2) )
298 if (min(je-js+1,ie-is+1) < 15)
then 299 delg = max( 0.4*(latn-lats), pi/
real(npx_global-1), 2.*pi/
real(nlat) )
301 delg = max( 0.2*(latn-lats), pi/
real(npx_global-1), 2.*pi/
real(nlat) )
303 lats = max( -0.5*pi, lats - delg )
304 latn = min( 0.5*pi, latn + delg )
308 if ( lats < lat1(j) )
then 313 jstart = max(jstart-1, 1)
317 if ( latn < lat1(j+1) )
then 322 jend = min(jend+1,
nlat)
324 jt = jend - jstart + 1
325 igh =
nlon/8 +
nlon/(2*(npx_global-1))
327 if (is_master())
write(*,*)
'Terrain dataset =',
nlon,
'jt=', jt
328 if (is_master())
write(*,*)
'igh (terrain ghosting)=', igh
330 status = nf_inq_varid(ncid,
'ftopo', ftopoid)
331 if (status .ne. nf_noerr)
call handle_err(status)
334 start(2) = jstart; nread(2) = jend - jstart + 1
336 allocate ( ft(-igh:
nlon+igh,jt) )
337 status = nf_get_vara_real(ncid, ftopoid, start, nread, ft(1:
nlon,1:jt))
338 if (status .ne. nf_noerr)
call handle_err(status)
342 ft(i,j) = ft(i+
nlon,j)
345 ft(i,j) = ft(i-
nlon,j)
349 status = nf_inq_varid(ncid,
'htopo', htopoid)
350 if (status .ne. nf_noerr)
call handle_err(status)
351 allocate ( zs(-igh:
nlon+igh,jt) )
352 status = nf_get_vara_real(ncid, htopoid, start, nread, zs(1:
nlon,1:jt))
353 if (status .ne. nf_noerr)
call handle_err(status)
354 status = nf_close(ncid)
355 if (status .ne. nf_noerr)
call handle_err(status)
359 zs(i,j) = zs(i+
nlon,j)
362 zs(i,j) = zs(i-
nlon,j)
374 allocate (
oro_g(isd:ied, jsd:jed) )
375 allocate (
sgh_g(isd:ied, jsd:jed) )
378 phis,
oro_g,
sgh_g, npx, npy, jstart, jend, stretch_fac, nested, npx_global, bd, regional)
379 if (is_master())
write(*,*)
'map_to_cubed_raw: master PE done' 387 allocate (
zs_g(is:ie, js:je) )
388 allocate ( z2(is:ie,js:je) )
391 zs_g(i,j) = phis(i,j)
392 z2(i,j) = phis(i,j)**2
398 call global_mx(
real(phis,kind=R_GRID), ng, da_min, da_max, bd)
399 zmean =
g_sum(domain,
zs_g(is:ie,js:je), is, ie, js, je, ng, area, 1)
400 z2mean =
g_sum(domain, z2(is:ie,js:je) , is, ie, js, je, ng, area, 1)
401 if ( is_master() )
then 402 write(*,*)
'Before filter ZS', trim(
grid_string),
' min=', da_min,
' Max=', da_max,
' Mean=',zmean
403 write(*,*)
'*** Mean variance', trim(
grid_string),
' *** =', z2mean
417 if (is_master())
write(*,*)
'Blending nested and coarse grid topography' 420 wt = max(0.,min(1.,
real(5 - min(i,j,npx-i,npy-j,5))/5. ))
421 phis(i,j) = (1.-wt)*phis(i,j) + wt*phis_coarse(i,j)
427 call global_mx(
real(oro_g,kind=R_GRID), ng, da_min, da_max, bd)
428 if ( is_master() )
write(*,*)
'ORO', trim(
grid_string),
' min=', da_min,
' Max=', da_max
430 call global_mx(area, ng, da_min, da_max, bd)
435 write(*,*)
'Applying terrain filters. zero_ocean is',
zero_ocean 437 call fv3_zs_filter (bd, isd, ied, jsd, jed, npx, npy, npx_global, &
438 stretch_fac, nested, domain, area, dxa, dya, dx, dy, dxc, dyc, grid, &
439 agrid, sin_sg, phis,
oro_g, regional)
440 call mpp_update_domains(phis, domain)
446 z2(i,j) = phis(i,j)**2
450 call global_mx(
real(phis,kind=R_GRID), ng, da_min, da_max, bd)
451 zmean =
g_sum(domain, phis(is:ie,js:je), is, ie, js, je, ng, area, 1)
452 z2mean =
g_sum(domain, z2, is, ie, js, je, ng, area, 1)
455 if ( is_master() )
then 456 write(*,*)
'After filter Phis', trim(
grid_string),
' min=', da_min,
' Max=', da_max,
'Mean=', zmean
457 write(*,*)
'*** Mean variance', trim(
grid_string),
' *** =', z2mean
481 phis(i,j) = grav * phis(i,j)
482 if (
sgh_g(i,j) <= 0. )
then 490 call global_mx(
real(sgh_g,kind=R_GRID), ng, da_min, da_max, bd)
491 if ( is_master() )
write(*,*)
'Before filter SGH', trim(
grid_string),
' min=', da_min,
' Max=', da_max
497 call global_mx(area, ng, da_min, da_max, bd)
499 if(
zs_filter)
call del4_cubed_sphere(npx, npy,
sgh_g, area, dx, dy, dxc, dyc, sin_sg, 1,
zero_ocean,
oro_g, nested, domain, bd, regional)
501 call global_mx(
real(sgh_g,kind=R_GRID), ng, da_min, da_max, bd)
502 if ( is_master() )
write(*,*)
'After filter SGH', trim(
grid_string),
' min=', da_min,
' Max=', da_max
511 subroutine fv3_zs_filter (bd, isd, ied, jsd, jed, npx, npy, npx_global, &
512 stretch_fac, nested, domain, area, dxa, dya, dx, dy, dxc, dyc, grid, &
513 agrid, sin_sg, phis, oro ,regional)
514 integer,
intent(in):: isd, ied, jsd, jed, npx, npy, npx_global
516 real(kind=R_GRID),
intent(in),
dimension(isd:ied,jsd:jed)::area
517 real,
intent(in),
dimension(isd:ied,jsd:jed)::dxa, dya
518 real,
intent(in),
dimension(isd:ied, jsd:jed+1):: dx, dyc
519 real,
intent(in),
dimension(isd:ied+1,jsd:jed):: dy, dxc
521 real(kind=R_GRID),
intent(in):: grid(isd:ied+1, jsd:jed+1,2)
522 real(kind=R_GRID),
intent(in):: agrid(isd:ied, jsd:jed, 2)
523 real,
intent(IN):: sin_sg(isd:ied,jsd:jed,9)
524 real(kind=R_GRID),
intent(IN):: stretch_fac
525 logical,
intent(IN) :: nested, regional
526 real,
intent(inout):: phis(isd:ied,jsd,jed)
527 real,
intent(inout):: oro(isd:ied,jsd,jed)
528 type(domain2d),
intent(INOUT) :: domain
530 real(kind=R_GRID) da_max
532 if (is_master()) print*,
' Calling FV3_zs_filter...' 537 mdim = nint(
real(npx_global) * min(10., stretch_fac) )
542 if ( npx_global<=97)
then 544 elseif ( npx_global<=193 )
then 553 call two_delta_filter(npx, npy, phis, area, dx, dy, dxa, dya, dxc, dyc, sin_sg,
cd2,
zero_ocean, &
558 if ( mdim<=193 )
then 560 elseif ( mdim<=1537 )
then 566 call del4_cubed_sphere(npx, npy, phis, area, dx, dy, dxc, dyc, sin_sg,
n_del4,
zero_ocean, oro, nested, domain, bd, regional)
569 call two_delta_filter(npx, npy, phis, area, dx, dy, dxa, dya, dxc, dyc, sin_sg,
cd2,
zero_ocean, &
570 .true., 1, oro, nested, domain, bd,
n_del2_weak, regional)
576 subroutine two_delta_filter(npx, npy, q, area, dx, dy, dxa, dya, dxc, dyc, sin_sg, cd, zero_ocean, &
577 check_slope, filter_type, oro, nested, domain, bd, ntmax, regional)
579 integer,
intent(in):: npx, npy
580 integer,
intent(in):: ntmax
581 integer,
intent(in):: filter_type
582 real,
intent(in):: cd
584 real(kind=R_GRID),
intent(in)::area(bd%isd:bd%ied, bd%jsd:bd%jed)
585 real,
intent(in):: dx(bd%isd:bd%ied, bd%jsd:bd%jed+1)
586 real,
intent(in):: dy(bd%isd:bd%ied+1,bd%jsd:bd%jed)
587 real,
intent(in):: dxa(bd%isd:bd%ied, bd%jsd:bd%jed)
588 real,
intent(in):: dya(bd%isd:bd%ied, bd%jsd:bd%jed)
589 real,
intent(in):: dxc(bd%isd:bd%ied+1,bd%jsd:bd%jed)
590 real,
intent(in):: dyc(bd%isd:bd%ied, bd%jsd:bd%jed+1)
591 real,
intent(in):: sin_sg(bd%isd:bd%ied,bd%jsd:bd%jed,9)
592 real,
intent(in):: oro(bd%isd:bd%ied, bd%jsd:bd%jed)
593 logical,
intent(in):: zero_ocean, check_slope
594 logical,
intent(in):: nested, regional
595 type(domain2d),
intent(inout) :: domain
597 real,
intent(inout):: q(bd%isd:bd%ied, bd%jsd:bd%jed)
599 real,
parameter:: p1 = 7./12.
600 real,
parameter:: p2 = -1./12.
601 real,
parameter:: c1 = -2./14.
602 real,
parameter:: c2 = 11./14.
603 real,
parameter:: c3 = 5./14.
604 real:: ddx(bd%is:bd%ie+1,bd%js:bd%je), ddy(bd%is:bd%ie,bd%js:bd%je+1)
605 logical:: extm(bd%is-1:bd%ie+1)
606 logical:: ext2(bd%is:bd%ie,bd%js-1:bd%je+1)
607 real:: a1(bd%is-1:bd%ie+2)
608 real:: a2(bd%is:bd%ie,bd%js-1:bd%je+2)
609 real(kind=R_GRID):: a3(bd%is:bd%ie,bd%js:bd%je)
610 real(kind=R_GRID):: smax, smin
613 integer:: is, ie, js, je
614 integer:: isd, ied, jsd, jed
615 integer:: is1, ie2, js1, je2
627 is1 = is-1; ie2 = ie+2
628 js1 = js-1; je2 = je+2
630 is1 = max(3,is-1); ie2 = min(npx-2,ie+2)
631 js1 = max(3,js-1); je2 = min(npy-2,je+2)
634 if ( check_slope )
then 642 call mpp_update_domains(q, domain)
645 if ( nt==1 .and. check_slope )
then 648 ddx(i,j) = (q(i,j) - q(i-1,j))/dxc(i,j)
649 ddx(i,j) = abs(ddx(i,j))
654 ddy(i,j) = (q(i,j) - q(i,j-1))/dyc(i,j)
655 ddy(i,j) = abs(ddy(i,j))
660 a3(i,j) = max( ddx(i,j), ddx(i+1,j), ddy(i,j), ddy(i,j+1) )
664 if ( is_master() )
write(*,*)
'Before filter: Max_slope=', smax
668 if ( .not. (nested .or. regional) .and. nt==1 )
then 669 if ( is==1 .and. js==1 )
then 670 q(1,1) = (q(1,1)*area(1,1)+q(0,1)*area(0,1)+q(1,0)*area(1,0)) &
671 / ( area(1,1)+ area(0,1)+ area(1,0) )
675 if ( (ie+1)==npx .and. js==1 )
then 676 q(ie, 1) = (q(ie,1)*area(ie,1)+q(npx,1)*area(npx,1)+q(ie,0)*area(ie,0)) &
677 / ( area(ie,1)+ area(npx,1)+ area(ie,0))
681 if ( is==1 .and. (je+1)==npy )
then 682 q(1, je) = (q(1,je)*area(1,je)+q(0,je)*area(0,je)+q(1,npy)*area(1,npy)) &
683 / ( area(1,je)+ area(0,je)+ area(1,npy))
687 if ( (ie+1)==npx .and. (je+1)==npy )
then 688 q(ie, je) = (q(ie,je)*area(ie,je)+q(npx,je)*area(npx,je)+q(ie,npy)*area(ie,npy)) &
689 / ( area(ie,je)+ area(npx,je)+ area(ie,npy))
693 call mpp_update_domains(q, domain)
700 a1(i) = p1*(q(i-1,j)+q(i,j)) + p2*(q(i-2,j)+q(i+1,j))
703 if ( .not. (nested .or. regional) )
then 705 a1(0) = c1*q(-2,j) + c2*q(-1,j) + c3*q(0,j)
706 a1(1) = 0.5*(((2.*dxa(0,j)+dxa(-1,j))*q(0,j)-dxa(0,j)*q(-1,j))/(dxa(-1,j)+dxa(0,j)) &
707 + ((2.*dxa(1,j)+dxa( 2,j))*q(1,j)-dxa(1,j)*q( 2,j))/(dxa(1, j)+dxa(2,j)))
708 a1(2) = c3*q(1,j) + c2*q(2,j) +c1*q(3,j)
710 if ( (ie+1)==npx )
then 711 a1(npx-1) = c1*q(npx-3,j) + c2*q(npx-2,j) + c3*q(npx-1,j)
712 a1(npx) = 0.5*(((2.*dxa(npx-1,j)+dxa(npx-2,j))*q(npx-1,j)-dxa(npx-1,j)*q(npx-2,j))/(dxa(npx-2,j)+dxa(npx-1,j)) &
713 + ((2.*dxa(npx, j)+dxa(npx+1,j))*q(npx, j)-dxa(npx, j)*q(npx+1,j))/(dxa(npx, j)+dxa(npx+1,j)))
714 a1(npx+1) = c3*q(npx,j) + c2*q(npx+1,j) + c1*q(npx+2,j)
718 if ( filter_type == 0 )
then 720 if( abs(3.*(a1(i)+a1(i+1)-2.*q(i,j))) > abs(a1(i)-a1(i+1)) )
then 728 if ( (a1(i)-q(i,j))*(a1(i+1)-q(i,j)) > 0. )
then 737 ddx(i,j) = (q(i-1,j)-q(i,j))/dxc(i,j)
738 if ( extm(i-1).and.extm(i) )
then 739 ddx(i,j) = 0.5*(sin_sg(i-1,j,3)+sin_sg(i,j,1))*dy(i,j)*ddx(i,j)
740 elseif ( abs(ddx(i,j)) > m_slope )
then 741 fac = min(1., max(0.1,(abs(ddx(i,j))-m_slope)/m_slope ) )
742 ddx(i,j) = fac*0.5*(sin_sg(i-1,j,3)+sin_sg(i,j,1))*dy(i,j)*ddx(i,j)
752 a2(i,j) = p1*(q(i,j-1)+q(i,j)) + p2*(q(i,j-2)+q(i,j+1))
755 if ( .not. (nested .or. regional) )
then 758 a2(i,0) = c1*q(i,-2) + c2*q(i,-1) + c3*q(i,0)
759 a2(i,1) = 0.5*(((2.*dya(i,0)+dya(i,-1))*q(i,0)-dya(i,0)*q(i,-1))/(dya(i,-1)+dya(i,0)) &
760 + ((2.*dya(i,1)+dya(i, 2))*q(i,1)-dya(i,1)*q(i, 2))/(dya(i, 1)+dya(i,2)))
761 a2(i,2) = c3*q(i,1) + c2*q(i,2) + c1*q(i,3)
764 if( (je+1)==npy )
then 766 a2(i,npy-1) = c1*q(i,npy-3) + c2*q(i,npy-2) + c3*q(i,npy-1)
767 a2(i,npy) = 0.5*(((2.*dya(i,npy-1)+dya(i,npy-2))*q(i,npy-1)-dya(i,npy-1)*q(i,npy-2))/(dya(i,npy-2)+dya(i,npy-1)) &
768 + ((2.*dya(i,npy)+dya(i,npy+1))*q(i,npy)-dya(i,npy)*q(i,npy+1))/(dya(i,npy)+dya(i,npy+1)))
769 a2(i,npy+1) = c3*q(i,npy) + c2*q(i,npy+1) + c1*q(i,npy+2)
774 if ( filter_type == 0 )
then 777 if( abs(3.*(a2(i,j)+a2(i,j+1)-2.*q(i,j))) > abs(a2(i,j)-a2(i,j+1)) )
then 787 if ( (a2(i,j)-q(i,j))*(a2(i,j+1)-q(i,j)) > 0. )
then 798 ddy(i,j) = (q(i,j-1)-q(i,j))/dyc(i,j)
799 if ( ext2(i,j-1) .and. ext2(i,j) )
then 800 ddy(i,j) = 0.5*(sin_sg(i,j-1,4)+sin_sg(i,j,2))*dx(i,j)*ddy(i,j)
801 elseif ( abs(ddy(i,j))>m_slope )
then 802 fac = min(1., max(0.1,(abs(ddy(i,j))-m_slope)/m_slope))
803 ddy(i,j) = fac*0.5*(sin_sg(i,j-1,4)+sin_sg(i,j,2))*dx(i,j)*ddy(i,j)
810 if ( zero_ocean )
then 814 ddx(i,j) = max(0., min(oro(i-1,j), oro(i,j))) * ddx(i,j)
819 ddy(i,j) = max(0., min(oro(i,j-1), oro(i,j))) * ddy(i,j)
826 q(i,j) = q(i,j) + cd/area(i,j)*(ddx(i,j)-ddx(i+1,j)+ddy(i,j)-ddy(i,j+1))
832 if ( check_slope )
then 833 call mpp_update_domains(q, domain)
836 ddx(i,j) = (q(i,j) - q(i-1,j))/dxc(i,j)
837 ddx(i,j) = abs(ddx(i,j))
842 ddy(i,j) = (q(i,j) - q(i,j-1))/dyc(i,j)
843 ddy(i,j) = abs(ddy(i,j))
848 a3(i,j) = max( ddx(i,j), ddx(i+1,j), ddy(i,j), ddy(i,j+1) )
852 if ( is_master() )
write(*,*)
'After filter: Max_slope=', smax
859 subroutine del2_cubed_sphere(npx, npy, q, area, dx, dy, dxc, dyc, sin_sg, nmax, cd, zero_ocean, oro, nested, domain, bd, regional)
861 integer,
intent(in):: npx, npy
862 integer,
intent(in):: nmax
863 real(kind=R_GRID),
intent(in):: cd
864 logical,
intent(in):: zero_ocean
866 real(kind=R_GRID),
intent(in)::area(bd%isd:bd%ied, bd%jsd:bd%jed)
867 real,
intent(in):: dx(bd%isd:bd%ied, bd%jsd:bd%jed+1)
868 real,
intent(in):: dy(bd%isd:bd%ied+1,bd%jsd:bd%jed)
869 real,
intent(in):: dxc(bd%isd:bd%ied+1,bd%jsd:bd%jed)
870 real,
intent(in):: dyc(bd%isd:bd%ied, bd%jsd:bd%jed+1)
871 real,
intent(IN):: sin_sg(bd%isd:bd%ied,bd%jsd:bd%jed,9)
872 real,
intent(in):: oro(bd%isd:bd%ied, bd%jsd:bd%jed)
873 logical,
intent(IN) :: nested, regional
874 type(domain2d),
intent(INOUT) :: domain
876 real,
intent(inout):: q(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng)
878 real ddx(bd%is:bd%ie+1,bd%js:bd%je), ddy(bd%is:bd%ie,bd%js:bd%je+1)
881 integer :: is, ie, js, je
882 integer :: isd, ied, jsd, jed
894 call mpp_update_domains(q,domain,whalo=ng,ehalo=ng,shalo=ng,nhalo=ng)
897 if ( is==1 .and. js==1 .and. .not. (nested .or. regional))
then 898 q(1,1) = (q(1,1)*area(1,1)+q(0,1)*area(0,1)+q(1,0)*area(1,0)) &
899 / ( area(1,1)+ area(0,1)+ area(1,0) )
903 if ( (ie+1)==npx .and. js==1 .and. .not. (nested .or. regional))
then 904 q(ie, 1) = (q(ie,1)*area(ie,1)+q(npx,1)*area(npx,1)+q(ie,0)*area(ie,0)) &
905 / ( area(ie,1)+ area(npx,1)+ area(ie,0))
909 if ( (ie+1)==npx .and. (je+1)==npy .and. .not. (nested .or. regional) )
then 910 q(ie, je) = (q(ie,je)*area(ie,je)+q(npx,je)*area(npx,je)+q(ie,npy)*area(ie,npy)) &
911 / ( area(ie,je)+ area(npx,je)+ area(ie,npy))
915 if ( is==1 .and. (je+1)==npy .and. .not. (nested .or. regional))
then 916 q(1, je) = (q(1,je)*area(1,je)+q(0,je)*area(0,je)+q(1,npy)*area(1,npy)) &
917 / ( area(1,je)+ area(0,je)+ area(1,npy))
924 if( n>1 )
call mpp_update_domains(q,domain,whalo=ng,ehalo=ng,shalo=ng,nhalo=ng)
927 ddx(i,j) = 0.5*(sin_sg(i-1,j,3)+sin_sg(i,j,1))*dy(i,j)*(q(i-1,j)-q(i,j))/dxc(i,j)
932 ddy(i,j) = dx(i,j)*(q(i,j-1)-q(i,j))/dyc(i,j) &
933 *0.5*(sin_sg(i,j-1,4)+sin_sg(i,j,2))
937 if ( zero_ocean )
then 941 ddx(i,j) = max(0., min(oro(i-1,j), oro(i,j))) * ddx(i,j)
946 ddy(i,j) = max(0., min(oro(i,j-1), oro(i,j))) * ddy(i,j)
953 q(i,j) = q(i,j) + cd/area(i,j)*(ddx(i,j)-ddx(i+1,j)+ddy(i,j)-ddy(i,j+1))
961 subroutine del4_cubed_sphere(npx, npy, q, area, dx, dy, dxc, dyc, sin_sg, nmax, zero_ocean, oro, nested, domain, bd, regional)
963 integer,
intent(in):: npx, npy, nmax
964 logical,
intent(in):: zero_ocean
965 real,
intent(in):: oro(bd%isd:bd%ied, bd%jsd:bd%jed)
966 real(kind=R_GRID),
intent(in)::area(bd%isd:bd%ied, bd%jsd:bd%jed)
967 real,
intent(in):: dx(bd%isd:bd%ied, bd%jsd:bd%jed+1)
968 real,
intent(in):: dy(bd%isd:bd%ied+1,bd%jsd:bd%jed)
969 real,
intent(in):: dxc(bd%isd:bd%ied+1,bd%jsd:bd%jed)
970 real,
intent(in):: dyc(bd%isd:bd%ied, bd%jsd:bd%jed+1)
971 real,
intent(IN):: sin_sg(bd%isd:bd%ied,bd%jsd:bd%jed,9)
972 real,
intent(inout):: q(bd%is-ng:bd%ie+ng, bd%js-ng:bd%je+ng)
973 logical,
intent(IN) :: nested, regional
974 type(domain2d),
intent(INOUT) :: domain
976 real :: diff(bd%is-3:bd%ie+2,bd%js-3:bd%je+2)
978 real :: fx1(bd%is:bd%ie+1,bd%js:bd%je), fy1(bd%is:bd%ie,bd%js:bd%je+1)
979 real :: fx2(bd%is:bd%ie+1,bd%js:bd%je), fy2(bd%is:bd%ie,bd%js:bd%je+1)
980 real :: fx4(bd%is:bd%ie+1,bd%js:bd%je), fy4(bd%is:bd%ie,bd%js:bd%je+1)
981 real,
dimension(bd%isd:bd%ied,bd%jsd:bd%jed):: d2, win, wou
982 real,
dimension(bd%is:bd%ie,bd%js:bd%je):: qlow, qmin, qmax, q0
983 real,
parameter:: esl = 1.e-20
986 integer :: is, ie, js, je
987 integer :: isd, ied, jsd, jed
1005 diff(i,j) =
cd4*area(i,j)
1016 call mpp_update_domains(q,domain)
1019 if ( is==1 .and. js==1 .and. .not. (nested .or. regional))
then 1020 q(1,1) = (q(1,1)*area(1,1)+q(0,1)*area(0,1)+q(1,0)*area(1,0)) &
1021 / ( area(1,1)+ area(0,1)+ area(1,0) )
1026 if ( (ie+1)==npx .and. js==1 .and. .not. (nested .or. regional))
then 1027 q(ie, 1) = (q(ie,1)*area(ie,1)+q(npx,1)*area(npx,1)+q(ie,0)*area(ie,0)) &
1028 / ( area(ie,1)+ area(npx,1)+ area(ie,0))
1033 if ( (ie+1)==npx .and. (je+1)==npy .and. .not. (nested .or. regional))
then 1034 q(ie, je) = (q(ie,je)*area(ie,je)+q(npx,je)*area(npx,je)+q(ie,npy)*area(ie,npy)) &
1035 / ( area(ie,je)+ area(npx,je)+ area(ie,npy))
1036 q(npx, je) = q(ie,je)
1037 q(ie, npy) = q(ie,je)
1038 q(npx,npy) = q(ie,je)
1040 if ( is==1 .and. (je+1)==npy .and. .not. (nested .or. regional))
then 1041 q(1, je) = (q(1,je)*area(1,je)+q(0,je)*area(0,je)+q(1,npy)*area(1,npy)) &
1042 / ( area(1,je)+ area(0,je)+ area(1,npy))
1050 qmin(i,j) = min(q0(i,j), q(i-1,j-1), q(i,j-1), q(i+1,j-1), &
1051 q(i-1,j ), q(i,j ), q(i+1,j ), &
1052 q(i-1,j+1), q(i,j+1), q(i+1,j+1) )
1053 qmax(i,j) = max(
peak_fac*q0(i,j), q(i-1,j-1), q(i,j-1), q(i+1,j-1), &
1054 q(i-1,j ), q(i,j ), q(i+1,j ), &
1055 q(i-1,j+1), q(i,j+1), q(i+1,j+1) )
1065 fx2(i,j) = 0.25*(diff(i-1,j)+diff(i,j))*dy(i,j)*(q(i-1,j)-q(i,j))/dxc(i,j) &
1066 *(sin_sg(i,j,1)+sin_sg(i-1,j,3))
1073 fy2(i,j) = 0.25*(diff(i,j-1)+diff(i,j))*dx(i,j)*(q(i,j-1)-q(i,j))/dyc(i,j) &
1074 *(sin_sg(i,j,2)+sin_sg(i,j-1,4))
1080 d2(i,j) = (fx2(i,j)-fx2(i+1,j)+fy2(i,j)-fy2(i,j+1)) / area(i,j)
1085 if ( zero_ocean )
then 1089 fx1(i,j) = max(0., min(oro(i-1,j), oro(i,j))) * fx2(i,j)
1094 fy1(i,j) = max(0., min(oro(i,j-1), oro(i,j))) * fy2(i,j)
1099 qlow(i,j) = q(i,j) + (fx1(i,j)-fx1(i+1,j)+fy1(i,j)-fy1(i,j+1)) / area(i,j)
1100 d2(i,j) = diff(i,j) * d2(i,j)
1106 qlow(i,j) = q(i,j) + d2(i,j)
1107 d2(i,j) = diff(i,j) * d2(i,j)
1112 call mpp_update_domains(d2,domain)
1120 fx4(i,j) = 0.5*(sin_sg(i-1,j,3)+sin_sg(i,j,1))*dy(i,j)*(d2(i,j)-d2(i-1,j))/dxc(i,j)-fx2(i,j)
1127 fy4(i,j) = dx(i,j)*(d2(i,j)-d2(i,j-1))/dyc(i,j) &
1128 *0.5*(sin_sg(i,j,2)+sin_sg(i,j-1,4))-fy2(i,j)
1137 win(i,j) = max(0.,fx4(i, j)) - min(0.,fx4(i+1,j)) + &
1138 max(0.,fy4(i, j)) - min(0.,fy4(i,j+1)) + esl
1139 wou(i,j) = max(0.,fx4(i+1,j)) - min(0.,fx4(i, j)) + &
1140 max(0.,fy4(i,j+1)) - min(0.,fy4(i, j)) + esl
1141 win(i,j) = max(0., qmax(i,j) - qlow(i,j)) / win(i,j)*area(i,j)
1142 wou(i,j) = max(0., qlow(i,j) - qmin(i,j)) / wou(i,j)*area(i,j)
1146 call mpp_update_domains(win,domain, complete=.false.)
1147 call mpp_update_domains(wou,domain, complete=.true.)
1151 if ( fx4(i,j) > 0. )
then 1152 fx4(i,j) = min(1., wou(i-1,j), win(i,j)) * fx4(i,j)
1154 fx4(i,j) = min(1., win(i-1,j), wou(i,j)) * fx4(i,j)
1160 if ( fy4(i,j) > 0. )
then 1161 fy4(i,j) = min(1., wou(i,j-1), win(i,j)) * fy4(i,j)
1163 fy4(i,j) = min(1., win(i,j-1), wou(i,j)) * fy4(i,j)
1169 if ( zero_ocean )
then 1173 fx4(i,j) = max(0., min(oro(i-1,j), oro(i,j))) * fx4(i,j)
1178 fy4(i,j) = max(0., min(oro(i,j-1), oro(i,j))) * fy4(i,j)
1186 q(i,j) = qlow(i,j) + (fx4(i,j)-fx4(i+1,j)+fy4(i,j)-fy4(i,j+1))/area(i,j)
1195 subroutine map_to_cubed_raw(igh, im, jt, lat1, lon1, zs, ft, grid, agrid, &
1196 q2, f2, h2, npx, npy, jstart, jend, stretch_fac, &
1197 nested, npx_global, bd, regional)
1201 integer,
intent(in):: igh, im, jt
1202 integer,
intent(in):: npx, npy, npx_global
1203 real,
intent(in):: lat1(jt+1)
1204 real,
intent(in):: lon1(im+1)
1205 real(kind=4),
intent(in),
dimension(-igh:im+igh,jt):: zs, ft
1206 real(kind=R_GRID),
intent(in):: grid(bd%isd:bd%ied+1, bd%jsd:bd%jed+1,2)
1207 real(kind=R_GRID),
intent(in):: agrid(bd%isd:bd%ied, bd%jsd:bd%jed, 2)
1208 integer,
intent(in):: jstart, jend
1209 real(kind=R_GRID),
intent(IN) :: stretch_fac
1210 logical,
intent(IN) :: nested, regional
1212 real,
intent(out):: q2(bd%isd:bd%ied,bd%jsd:bd%jed)
1213 real,
intent(out):: f2(bd%isd:bd%ied,bd%jsd:bd%jed)
1214 real,
intent(out):: h2(bd%isd:bd%ied,bd%jsd:bd%jed)
1216 real :: lon_g(-igh:im+igh)
1217 real lat_g(jt), cos_g(jt)
1218 real(kind=R_GRID) e2(2)
1219 real(kind=R_GRID) grid3(3, bd%isd:bd%ied+1, bd%jsd:bd%jed+1)
1220 real(kind=R_GRID),
dimension(3):: p1, p2, p3, p4, pc, pp
1221 real(kind=R_GRID),
dimension(3):: vp_12, vp_23, vp_34, vp_14
1223 integer ii, jj, i1, i2, j1, j2, min_pts
1224 real th1, aa, asum, qsum, fsum, hsum, lon_w, lon_e, lat_s, lat_n, r2d
1227 real delg, th0, tmp1, prod1, prod2, prod3, prod4
1232 integer :: is, ie, js, je
1233 integer :: isd, ied, jsd, jed
1249 lon_g(i) = 0.5*(lon1(i)+lon1(i+1))
1252 lon_g(i) = lon_g(i+im)
1255 lon_g(i) = lon_g(i-im)
1259 lat_g(j) = 0.5*(lat1(j)+lat1(j+1))
1260 cos_g(j) = cos( lat_g(j) )
1265 call latlon2xyz(
real(grid(i,j,1:2),kind=R_GRID), grid3(1,i,j))
1269 if(is_master())
write(*,*)
'surf_map: Search started ....' 1272 lat_crit = nint( stretch_fac*
real(
nlat)/
real(npx_global-1) )
1273 lat_crit = min( jt, max( 4, lat_crit ) )
1275 if ( jstart==1 )
then 1276 write(*,*) mpp_pe(),
'lat_crit=', r2d*lat_g(lat_crit)
1277 elseif ( jend==
nlat )
then 1284 iF ( jstart == 1 )
then 1293 qsum = qsum + zs(i,j)*aa
1294 fsum = fsum + ft(i,j)*aa
1304 hsum = hsum + (qsp-zs(i,j))**2
1307 hsp = hsum /
real(np)
1313 iF ( jend ==
nlat )
then 1318 do jp=jend-lat_crit+1, jend
1323 qsum = qsum + zs(i,j)*aa
1324 fsum = fsum + ft(i,j)*aa
1331 do jp=jend-lat_crit+1, jend
1335 hsum = hsum + (qnp-zs(i,j))**2
1338 hnp = hsum /
real(np)
1347 if (((i < is .and. j < js) .or. &
1348 (i < is .and. j > je) .or. &
1349 (i > ie .and. j < js) .or. &
1350 (i > ie .and. j > je)) .and. .not. (nested .or. regional))
then 1357 if ( agrid(i,j,2) < -pi5+stretch_fac*pi5/
real(npx_global-1) ) then
1363 elseif ( agrid(i,j,2) > pi5-stretch_fac*pi5/
real(npx_global-1) ) then
1371 lat_s = min( grid(i,j,2), grid(i+1,j,2), grid(i,j+1,2), grid(i+1,j+1,2), agrid(i,j,2) )
1372 lat_n = max( grid(i,j,2), grid(i+1,j,2), grid(i,j+1,2), grid(i+1,j+1,2), agrid(i,j,2) )
1374 delg = max( 0.2*(lat_n-lat_s), pi/
real(npx_global-1), pi2/
real(nlat) )
1375 lat_s = max(-pi5, lat_s - delg)
1376 lat_n = min( pi5, lat_n + delg)
1378 j1 = nint( (pi5+lat_s)/(pi/
real(
nlat)) ) - 1
1379 if ( lat_s*r2d < (-90.+90./
real(npx_global-1)) ) j1 = 1
1380 j1 = max(jstart, j1)
1382 j2 = nint( (pi5+lat_n)/(pi/
real(
nlat)) ) + 1
1383 if ( lat_n*r2d > (90.-90./
real(npx_global-1)) ) j2 =
nlat 1386 j1 = j1 - jstart + 1
1387 j2 = j2 - jstart + 1
1389 lon_w = min( grid(i,j,1), grid(i+1,j,1), grid(i,j+1,1), grid(i+1,j+1,1) )
1390 lon_e = max( grid(i,j,1), grid(i+1,j,1), grid(i,j+1,1), grid(i+1,j+1,1) )
1392 if ( (lon_e-lon_w) > pi )
then 1393 i1 = -nint( (pi2-lon_e)/pi2 *
real(im) ) - 1
1394 i2 = nint( lon_w/pi2 *
real(im) ) + 1
1396 i1 = nint( lon_w/pi2 *
real(im) ) - 1
1397 i2 = nint( lon_e/pi2 *
real(im) ) + 1
1401 ig_lon = max(1, (i2-i1)/8)
1402 i1 = max( -igh, i1 - ig_lon)
1403 i2 = min(im+igh, i2 + ig_lon)
1418 p1(k) = grid3(k,i, j)
1419 p2(k) = grid3(k,i+1,j)
1420 p3(k) = grid3(k,i+1,j+1)
1421 p4(k) = grid3(k,i,j+1)
1422 pc(k) = p1(k) + p2(k) + p3(k) + p4(k)
1424 call normalize_vect( pc )
1426 th0 = min( v_prod(p1,p3), v_prod(p2, p4) )
1427 th1 = min(
cos_grid, cos(0.25*acos(max(v_prod(p1,p3), v_prod(p2, p4)))))
1434 prod1 = v_prod(p3, vp_12)
1435 prod2 = v_prod(p1, vp_23)
1436 prod3 = v_prod(p1, vp_34)
1437 prod4 = v_prod(p2, vp_14)
1444 call latlon2xyz(e2, pp)
1446 tmp1 = v_prod(pp, pc)
1448 if ( tmp1 > th1 )
goto 1111
1450 if ( tmp1 < th0 )
goto 2222
1452 if ( v_prod(pp, vp_12)*prod1 < 0. )
goto 2222
1453 if ( v_prod(pp, vp_23)*prod2 < 0. )
goto 2222
1454 if ( v_prod(pp, vp_34)*prod3 < 0. )
goto 2222
1455 if ( v_prod(pp, vp_14)*prod4 < 0. )
goto 2222
1457 qsum = qsum + zs(ii,jj)*aa
1458 fsum = fsum + ft(ii,jj)*aa
1459 hsum = hsum + zs(ii,jj)**2
1466 q2(i,j) = qsum / asum
1467 f2(i,j) = fsum / asum
1468 h2(i,j) = hsum /
real(np) - q2(i,j)**2
1469 min_pts = min(min_pts, np)
1471 write(*,*)
'min and max lat_g is ', r2d*minval(lat_g), r2d*maxval(lat_g), mpp_pe()
1472 write(*,*)
'Surf_map failed for GID=', mpp_pe(), i,j,
'(lon,lat)=', r2d*agrid(i,j,1),r2d*agrid(i,j,2)
1473 write(*,*)
'[jstart, jend]', jstart, jend
1474 call mpp_error(fatal,
'Surf_map failed')
1480 if(is_master())
write(*,*)
'surf_map: minimum pts per cell (master PE)=', min_pts
1481 if ( min_pts <3 )
then 1482 if(is_master())
write(*,*)
'Warning: too few points used in creating the cell mean terrain !!!' 1489 logical function inside_p4(p1, p2, p3, p4, pp, th0)
1491 real,
intent(in):: p1(3), p2(3), p3(3), p4(3)
1492 real,
intent(in):: pp(3)
1493 real,
intent(in):: th0
1496 real(kind=R_GRID) v1(3), v2(3), vp(3)
1497 real(kind=R_GRID) tmp1
1504 vp(k) = p1(k) + p2(k) + p3(k) + p4(k)
1506 call normalize_vect( vp )
1508 tmp1 = v_prod(pp, vp)
1509 if ( tmp1 < th0 )
then 1515 if ( v_prod(pp, vp)*v_prod(p3, vp) < 0. )
return 1518 if ( v_prod(pp, vp)*v_prod(p1, vp) < 0. )
return 1521 if ( v_prod(pp, vp)*v_prod(p1, vp) < 0. )
return 1524 if ( v_prod(pp, vp)*v_prod(p2, vp) < 0. )
return 1534 #include <netcdf.inc> 1537 if (status .ne. nf_noerr)
then 1538 print *, nf_strerror(status)
1549 real(kind=R_GRID),
intent(in) :: lon(bd%isd:bd%ied,bd%jsd:bd%jed), lat(bd%isd:bd%ied,bd%jsd:bd%jed)
1550 real,
intent(inout) :: lfrac(bd%isd:bd%ied,bd%jsd:bd%jed)
1552 integer :: is, ie, js, je
1553 integer :: isd, ied, jsd, jed
1560 real :: dtr, phs, phn
1578 if ( lat(i,j) < phn )
then 1580 if ( lat(i,j) < phs )
then 1585 if ( sin(lon(i,j)) < 0. .and. cos(lon(i,j)) > 0.)
then 1597 integer :: unit, ierr, io
1603 #ifdef INTERNAL_FILE_NML 1604 read (input_nml_file, nml=surf_map_nml, iostat=io)
1605 ierr = check_nml_error(io,
'surf_map_nml')
1607 unit = open_namelist_file( )
1609 do while (ierr /= 0)
1610 read (unit, nml=surf_map_nml, iostat=io, end=10)
1611 ierr = check_nml_error(io,
'surf_map_nml')
1613 10
call close_file (unit)
1618 if (mpp_pe() == mpp_root_pe())
then 1620 write (unit, nml=surf_map_nml)
1629 integer,
intent(in):: im
1630 real(kind=4),
intent(inout):: p(im)
1631 real,
intent(out):: zmean
1636 zmean = zmean + p(i)
1638 zmean = zmean /
real(im)
subroutine, public del2_cubed_sphere(npx, npy, q, area, dx, dy, dxc, dyc, sin_sg, nmax, cd, zero_ocean, oro, nested, domain, bd, regional)
subroutine zonal_mean(im, p, zmean)
The sugroutine 'zonal_mean' replaces 'p' with its zonal mean.
real max_slope
max allowable terrain slope: 1 –> 45 deg 0.15 for C768 or lower; 0.25 C1536; 0.3 for C3072 ...
character(len=3) grid_string
subroutine remove_ice_sheets(lon, lat, lfrac, bd)
The module 'fv_mp_mod' is a single program multiple data (SPMD) parallel decompostion/communication m...
subroutine timing_off(blk_name)
The subroutine 'timing_off' stops a timer.
subroutine handle_err(status)
The subroutine 'handle_err' returns an error when it cannot find or correctly read in an external fil...
subroutine, public normalize_vect(e)
The subroutine 'normalize_vect' makes 'e' a unit vector.
real, dimension(:,:), allocatable, public zs_g
subroutine two_delta_filter(npx, npy, q, area, dx, dy, dxa, dya, dxc, dyc, sin_sg, cd, zero_ocean, check_slope, filter_type, oro, nested, domain, bd, ntmax, regional)
subroutine, public fv3_zs_filter(bd, isd, ied, jsd, jed, npx, npy, npx_global, stretch_fac, nested, domain, area, dxa, dya, dx, dy, dxc, dyc, grid, agrid, sin_sg, phis, oro, regional)
subroutine, public del4_cubed_sphere(npx, npy, q, area, dx, dy, dxc, dyc, sin_sg, nmax, zero_ocean, oro, nested, domain, bd, regional)
real function, public g_sum(domain, p, ifirst, ilast, jfirst, jlast, ngc, area, mode, reproduce)
The function 'g_sum' is the fast version of 'globalsum'.
integer, parameter, public r_grid
The module 'fv_timing' contains FV3 timers.
subroutine read_namelist
The subroutine 'read_namelis' reads the namelist file, writes the namelist to log file...
subroutine, public global_mx(q, n_g, qmin, qmax, bd)
The module 'fv_arrays' contains the 'fv_atmos_type' and associated datatypes.
real function, public great_circle_dist(q1, q2, radius)
character(len=6) surf_format
real(kind=r_grid) function, public v_prod(v1, v2)
real, dimension(:,:), allocatable, public sgh_g
subroutine, public vect_cross(e, p1, p2)
The subroutine 'vect_cross performs cross products of 3D vectors: e = P1 X P2.
subroutine timing_on(blk_name)
The subroutine 'timing_on' starts a timer.
integer, parameter, public ng
real cd4
Dimensionless coeff for del-4 diffusion (with FCT)
subroutine, public surfdrv(npx, npy, grid, agrid, area, dx, dy, dxa, dya, dxc, dyc, sin_sg, phis, stretch_fac, nested, npx_global, domain, grid_number, bd, regional)
logical function inside_p4(p1, p2, p3, p4, pp, th0)
The module 'fv_grid_utils' contains routines for setting up and computing grid-related quantities...
real, dimension(:,:), allocatable, public oro_g
subroutine map_to_cubed_raw(igh, im, jt, lat1, lon1, zs, ft, grid, agrid, q2, f2, h2, npx, npy, jstart, jend, stretch_fac, nested, npx_global, bd, regional)
character(len=128) surf_file
real cd2
Dimensionless coeff for del-2 diffusion (-1 gives resolution-determined value)
real peak_fac
overshoot factor for the mountain peak
subroutine, public latlon2xyz(p, e, id)
The subroutine 'latlon2xyz' maps (lon, lat) to (x,y,z)