module areaMod 9,14
!-----------------------------------------------------------------------
!BOP
!
! !MODULE: areaMod
!
! !DESCRIPTION:
! Area averaging routines
! Thes routines are used for area-average mapping of a field from one
! grid to another.
!
! !USES:
use clm_varcon
, only : re
use clm_varpar
, only : numrad
use clm_varctl
, only : iulog
use domainMod
, only : domain_type, domain_setptrs, latlon_type
use shr_const_mod
, only : SHR_CONST_PI
use shr_kind_mod
, only : r8 => shr_kind_r8
use spmdMod
, only : iam,masterproc
use nanMod
use abortutils
, only : endrun
!
! !PUBLIC TYPES:
implicit none
private
type map_type
private
! lower level in hierarchy
character(len=32) :: name
character(len=16) :: type ! global, dst, src, etc
integer :: ni_i,nj_i ! size of src grid ni,nj
integer :: ni_o,nj_o ! size of dst grid ni,nj
integer :: nwts ! size of row, col, S (local)
integer ,pointer :: src(:) ! src index (COL)
integer ,pointer :: dst(:) ! dst index (ROW)
real(r8) ,pointer :: S(:) ! wt of overlap input cell
integer :: dstmo ! max num of overlaps of dst cell
end type map_type
public map_type
type(map_type),public :: map1dl_a2l ! a2l mapping 1d loc glo to gdc
type(map_type),public :: map1dl_l2a ! l2a mapping 1d loc gdc to glo
character(len=16),parameter,public :: map_typelocal = 'local'
character(len=16),parameter,public :: map_typeglobal = 'global'
!
! !PUBLIC MEMBER FUNCTIONS:
public :: map_init
public :: map_setptrs
public :: map_setmapsFM
public :: map_setmapsAR
interface map_maparrayl 5
module procedure map_maparrayl_arr
module procedure map_maparrayl_rev
module procedure map_maparrayl_av
end interface
public :: map_maparrayl
public :: map_maparrayg
public :: map_setgatm
interface celledge 1
module procedure latlon_celledge_regional
module procedure latlon_celledge_global
end interface
public :: celledge
public :: cellarea
!
! !REVISION HISTORY:
! Created by Sam Levis
! Updated to clm2.1 data structures by Mariana Vertenstein
! 2005.11.01 Updated and cleaned by T Craig
!
!
! !PRIVATE MEMBER FUNCTIONS:
!EOP
!-----------------------------------------------------------------------
contains
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_init
!
! !INTERFACE:
subroutine map_init(map,domain_i,domain_o,nwts,name,type) 2,1
!
! !DESCRIPTION:
! This subroutine initializes the map datatype
!
! !USES:
!
! !ARGUMENTS:
implicit none
type(map_type) , intent(inout) :: map
type(domain_type) , intent(in),target :: domain_i
type(domain_type) , intent(in),target :: domain_o
integer , intent(in) :: nwts ! number of wts
character(len=*) , intent(in),optional :: name
character(len=*) , intent(in),optional :: type
!
! !REVISION HISTORY:
! 2006.06.28 T Craig Creation.
!
!
! !LOCAL VARIABLES:
!EOP
integer ier ! error flag
!------------------------------------------------------------------------------
! map%domain_i => domain_i
! map%domain_o => domain_o
map%ni_i = domain_i%ni
map%nj_i = domain_i%nj
map%ni_o = domain_o%ni
map%nj_o = domain_o%nj
if (present(name)) then
map%name = trim(name)
else
map%name = 'unset'
endif
if (present(type)) then
map%type = trim(type)
else
map%type = 'unset'
endif
map%nwts = nwts
allocate(map%src(nwts),map%dst(nwts),map%S(nwts),stat=ier)
if (ier /= 0) then
write(iulog,*) 'map_init ERROR: allocate map'
call endrun
()
endif
map%src = -1
map%dst = -1
map%S = nan
end subroutine map_init
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setptrs
!
! !INTERFACE:
subroutine map_setptrs(map,name,type,ni_i,nj_i,ni_o,nj_o, & 10
nwts,src,dst,wts,dstmo)
!
! !DESCRIPTION:
! This subroutine sets external pointer arrays to arrays in map
!
! !USES:
!
! !ARGUMENTS:
implicit none
type(map_type) ,intent(in) :: map
character(len=*) ,optional :: name
character(len=*) ,optional :: type
integer ,optional :: ni_i,nj_i
integer ,optional :: ni_o,nj_o
integer ,optional :: nwts
integer ,optional,pointer :: src(:)
integer ,optional,pointer :: dst(:)
real(r8) ,optional,pointer :: wts(:)
integer ,optional :: dstmo
!
! !REVISION HISTORY:
! Created by T Craig
!
!
! !LOCAL VARIABLES:
!
!EOP
!------------------------------------------------------------------------------
if (present(name)) then
name = map%name
endif
if (present(type)) then
type = map%type
endif
if (present(ni_i)) then
ni_i = map%ni_i
endif
if (present(nj_i)) then
nj_i = map%nj_i
endif
if (present(ni_o)) then
ni_o = map%ni_o
endif
if (present(nj_o)) then
nj_o = map%nj_o
endif
if (present(nwts)) then
nwts = map%nwts
endif
if (present(src)) then
src => map%src
endif
if (present(dst)) then
dst => map%dst
endif
if (present(wts)) then
wts => map%S
endif
if (present(dstmo)) then
dstmo = map%dstmo
endif
end subroutine map_setptrs
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayl_arr
!
! !INTERFACE:
subroutine map_maparrayl_arr(begg_i, endg_i, begg_o, endg_o, nflds, & 1,2
fld_i, fld_o, map)
!
! !DESCRIPTION:
! This subroutine maps arrays, local 1d with 1d map type
!
! !USES:
!
! !ARGUMENTS:
implicit none
integer :: begg_i,endg_i !beg,end of input grid
integer :: begg_o,endg_o !beg,end of output grid
integer :: nflds !number of fields being mapped
real(r8), intent(in) :: fld_i(begg_i:endg_i,nflds)
real(r8), intent(out) :: fld_o(begg_o:endg_o,nflds)
type(map_type), intent(in) :: map
!
! !REVISION HISTORY:
! 2005.11.15 T Craig Creation.
! 2006.3.30 P Worley Restructuring for improved vector performance
!
! !LOCAL VARIABLES:
!EOP
integer :: g_o ,g_i ! gridcell indices
integer :: n,ifld ! loop counters
real(r8):: wtx ! wt for map
!
!------------------------------------------------------------------------------
if (trim(map%type) /= trim(map_typelocal)) then
write(iulog,*) 'map_maparrayl_arr WARNING: map type not correct, ', &
map%name,map%type
endif
! check for errors in overlap
if (minval(map%src) < begg_i .or. maxval(map%src) > endg_i) then
write(iulog,*) 'map_maparrayl_arr ERROR: src out of bounds:', &
minval(map%src),maxval(map%src),begg_i,endg_i
call endrun
()
endif
if (minval(map%dst) < begg_o .or. maxval(map%dst) > endg_o) then
write(iulog,*) 'map_maparrayl_arr ERROR: dst out of bounds:', &
minval(map%dst),maxval(map%dst),begg_o,endg_o
call endrun
()
endif
! initialize field on output grid to zero everywhere
fld_o(:,:) = 0._r8
! map flds
do ifld = 1,nflds
do n = 1,map%nwts
g_i = map%src(n)
g_o = map%dst(n)
wtx = map%S(n)
fld_o(g_o,ifld) = fld_o(g_o,ifld) + wtx * fld_i(g_i,ifld)
enddo
enddo
end subroutine map_maparrayl_arr
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayl_rev
!
! !INTERFACE:
subroutine map_maparrayl_rev(begg_i, endg_i, begg_o, endg_o, nflds, & 1,3
fld_i, fld_o, map, reverse_order)
!
! !DESCRIPTION:
! This subroutine maps arrays, local 1d with 1d map type
!
! !USES:
use mct_mod
!
! !ARGUMENTS:
implicit none
integer :: begg_i,endg_i !beg,end of input grid
integer :: begg_o,endg_o !beg,end of output grid
integer :: nflds !number of fields being mapped
real(r8), intent(in) :: fld_i(nflds,endg_i-begg_i+1)
real(r8), intent(out) :: fld_o(nflds,endg_o-begg_o+1)
type(map_type), intent(in) :: map
logical, intent(in) :: reverse_order
!
! !REVISION HISTORY:
! 2005.11.15 T Craig Creation.
! 2006.3.30 P Worley Restructuring for improved vector performance
! 2010.5.1 M Vertenstein Added new interfaces
!
! !LOCAL VARIABLES:
!EOP
integer :: g_o ,g_i ! gridcell indices
integer :: n,ifld ! loop counters
real(r8):: wtx ! wt for map
!
!------------------------------------------------------------------------------
if (trim(map%type) /= trim(map_typelocal)) then
write(iulog,*) 'map_maparrayl_rev WARNING: map type not correct, ', &
map%name,map%type
endif
! check for errors in overlap
if (minval(map%src) < begg_i .or. maxval(map%src) > endg_i) then
write(iulog,*) 'map_maparrayl_rev ERROR: src out of bounds:', &
minval(map%src),maxval(map%src),begg_i,endg_i
call endrun
()
endif
if (minval(map%dst) < begg_o .or. maxval(map%dst) > endg_o) then
write(iulog,*) 'map_maparrayl_rev ERROR: dst out of bounds:', &
minval(map%dst),maxval(map%dst),begg_o,endg_o
call endrun
()
endif
! initialize field on output grid to zero everywhere
fld_o(:,:) = 0._r8
! map flds
do n = 1,map%nwts
g_i = map%src(n) - begg_i + 1
g_o = map%dst(n) - begg_o + 1
wtx = map%S(n)
do ifld = 1,nflds
fld_o(ifld,g_o) = fld_o(ifld,g_o) + wtx * fld_i(ifld,g_i)
enddo
enddo
end subroutine map_maparrayl_rev
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayl_av
!
! !INTERFACE:
subroutine map_maparrayl_av(begg_i, endg_i, begg_o, endg_o, nflds, & 1,3
fld_i, fld_o, map)
!
! !DESCRIPTION:
! This subroutine maps arrays, local 1d with 1d map type
!
! !USES:
use mct_mod
!
! !ARGUMENTS:
implicit none
integer :: begg_i,endg_i !beg,end of input grid
integer :: begg_o,endg_o !beg,end of output grid
integer :: nflds !number of fields being mapped
type(mct_aVect), intent(inout) :: fld_i !land model import and export states
type(mct_aVect), intent(inout) :: fld_o !land model import and export states
type(map_type), intent(in) :: map
!
! !REVISION HISTORY:
! 2005.11.15 T Craig Creation.
! 2006.3.30 P Worley Restructuring for improved vector performance
!
! !LOCAL VARIABLES:
!EOP
integer :: g_o ,g_i ! gridcell indices
integer :: n,ifld ! loop counters
real(r8):: wtx ! wt for map
!
!------------------------------------------------------------------------------
if (trim(map%type) /= trim(map_typelocal)) then
write(iulog,*) 'map_maparrayl_av WARNING: map type not correct, ', &
map%name,map%type
endif
! check for errors in overlap
if (minval(map%src) < begg_i .or. maxval(map%src) > endg_i) then
write(iulog,*) 'map_maparrayl_av ERROR: src out of bounds:', &
minval(map%src),maxval(map%src),begg_i,endg_i
call endrun
()
endif
if (minval(map%dst) < begg_o .or. maxval(map%dst) > endg_o) then
write(iulog,*) 'map_maparrayl_av ERROR: dst out of bounds:', &
minval(map%dst),maxval(map%dst),begg_o,endg_o
call endrun
()
endif
! initialize field on output grid to zero everywhere
call mct_aVect_zero(fld_o)
! map flds
do n = 1,map%nwts
g_i = map%src(n) - begg_i + 1
g_o = map%dst(n) - begg_o + 1
wtx = map%S(n)
do ifld = 1,nflds
fld_o%rAttr(ifld,g_o) = fld_o%rAttr(ifld,g_o) + wtx * fld_i%rAttr(ifld,g_i)
enddo
enddo
end subroutine map_maparrayl_av
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayg
!
! !INTERFACE:
subroutine map_maparrayg(fld_i, fld_o, map)
!
! !DESCRIPTION:
! This subroutine maps arrays, global 1d with 1d map type
!
! !USES:
!
! !ARGUMENTS:
implicit none
real(r8), intent(in) :: fld_i(:,:)
real(r8), intent(out) :: fld_o(:,:)
type(map_type), intent(in) :: map
!
! !REVISION HISTORY:
! 2005.11.15 T Craig Creation.
! 2006.3.30 P Worley Restructuring for improved vector performance
!
! !LOCAL VARIABLES:
!EOP
integer :: g_o ,g_i ! gridcell indices
integer :: n,ifld,nflds ! loop counters
real(r8):: wtx ! wt for map
!
!------------------------------------------------------------------------------
if (trim(map%type) /= trim(map_typeglobal)) then
write(iulog,*) 'map_maparrayg WARNING: map type not correct, ', &
map%name,map%type
endif
nflds = size(fld_i,dim=2)
! initialize field on output grid to zero everywhere
fld_o(:,:) = 0._r8
! map flds
do ifld = 1,nflds
do n = 1,map%nwts
g_i = map%src(n)
g_o = map%dst(n)
wtx = map%S(n)
fld_o(g_o,ifld) = fld_o(g_o,ifld) + wtx * fld_i(g_i,ifld)
enddo
enddo
end subroutine map_maparrayg
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setgatm
!
! !INTERFACE:
subroutine map_setgatm(gatm, alatlon, llatlon, amask, pftm) 1,6
!
! !DESCRIPTION:
! Set gatm index in ldomain. unique for finemesh.
!
! !USES:
!
use domainMod
, only : latlon_type
!
! !ARGUMENTS:
implicit none
integer, pointer :: gatm(:)
type(latlon_type), intent(in) :: alatlon
type(latlon_type), intent(in) :: llatlon
integer , intent(in) :: amask(:)
integer , intent(in) :: pftm(:)
!
! !REVISION HISTORY:
! 2006.06.28 T Craig Creation.
! 2006.08.23 P Worley Performance optimizations
!
!
! !LOCAL VARIABLES:
!EOP
integer :: nlon_a !input grid: max number of longitude pts
integer :: nlat_a !input grid: number of latitude points
integer :: ns_a !input grid: total number of cells
! integer ,pointer :: mask_a(:) !input grid: mask
real(r8),pointer :: lon_a(:) !input grid: longitude (degrees)
real(r8),pointer :: lat_a(:) !input grid: latitude (degrees)
real(r8),pointer :: lone_a(:) !input grid: longitude, E edge (degrees)
real(r8),pointer :: lonw_a(:) !input grid: longitude, W edge (degrees)
real(r8),pointer :: latn_a(:) !input grid: latitude , N edge (degrees)
real(r8),pointer :: lats_a(:) !input grid: latitude , S edge (degrees)
integer :: nlon_l !output grid: max number of longitude pts
integer :: nlat_l !output grid: number of latitude points
integer :: ns_l !output grid: total number of cells
! integer ,pointer :: gatm_l(:) !output grid: atm grid cell overlapping
real(r8),pointer :: lon_l(:) !output grid: longitude (degrees)
real(r8),pointer :: lat_l(:) !output grid: latitude (degrees)
real(r8),pointer :: lone_l(:) !output grid: longitude, E edge (degrees)
real(r8),pointer :: lonw_l(:) !output grid: longitude, W edge (degrees)
real(r8),pointer :: latn_l(:) !output grid: latitude , N edge (degrees)
real(r8),pointer :: lats_l(:) !output grid: latitude , S edge (degrees)
! integer ,pointer :: pftm_l(:) !output grid: cell frac
integer :: n !loop counters
integer :: ia,ja,na !indices for atm grid
integer :: il,jl,nl !indices for lnd grid
integer :: if,jf,nf !found indices
integer :: noffset=1 !noffset
real(r8) :: doffset =360_r8 !offset value
real(r8) :: offset !offset*n_offset
logical :: found !local logical
logical :: overlapgrid !are atm and lnd grids 1:1
logical :: latlongrid !are atm and lnd grids regular lat/lon
real(r8),parameter :: relerr = 1.0e-6 ! error limit
integer :: cnt,cnt0,cmax !counters
!tcx fix, lat_l_local should be removed when limit no longer needed
real(r8) :: lat_l_local !local copy of lat_l(il,jl), adjusted
real(r8),parameter:: eps = 1.0e-8 ! eps for check
integer, pointer :: ilfound(:) ! list over overlap i indices
integer, pointer :: jlfound(:) ! list over overlap j indices
integer, pointer :: nocnt(:) ! lnd cell count per atm cell
integer, pointer :: nooff(:) ! atm cell offset in nomap
integer, pointer :: nomap(:) ! map from atm cell to lnd cells
integer :: noidx
!
!------------------------------------------------------------------------
!--- set pointers into domains, initialize gridmap a2l gridmap ---
ns_a = alatlon%ns
nlon_a = alatlon%ni
nlat_a = alatlon%nj
lat_a => alatlon%latc
lon_a => alatlon%lonc
latn_a => alatlon%latn
lats_a => alatlon%lats
lone_a => alatlon%lone
lonw_a => alatlon%lonw
ns_l = llatlon%ns
nlon_l = llatlon%ni
nlat_l = llatlon%nj
lat_l => llatlon%latc
lon_l => llatlon%lonc
latn_l => llatlon%latn
lats_l => llatlon%lats
lone_l => llatlon%lone
lonw_l => llatlon%lonw
allocate(gatm(ns_l))
!--- search for the overlap, input to output, 1:1 "disaggregation" ---
!--- this is the coarse to fine map where there should be exactly
!--- one coarse overlap point for each fine point
!--- three possible search algorithms, overlapgrid, latlongrid, neither
!--- figure out which search scheme to use
!--- overlapgrid means both grids are identical to relerr
overlapgrid = .false.
if (nlon_a == nlon_l .and. nlat_a == nlat_l) then
overlapgrid = .true.
do jl = 1, nlat_l
if (abs( lat_l(jl)- lat_a(jl)) > relerr .or. &
abs(latn_l(jl)-latn_a(jl)) > relerr .or. &
abs(lats_l(jl)-lats_a(jl)) > relerr) then
overlapgrid = .false.
endif
enddo
do il = 1, nlon_l
if (abs( lon_l(il)- lon_a(il)) > relerr .or. &
abs(lone_l(il)-lone_a(il)) > relerr .or. &
abs(lonw_l(il)-lonw_a(il)) > relerr) then
overlapgrid = .false.
endif
enddo
endif
!--- latlongrid means atm grid is regular latlon grid
!--- always true for now, may not be in the future
latlongrid = .true.
if (masterproc) write(iulog,*) 'setgatm overlapgrid,latlongrid = ',overlapgrid,latlongrid
!pw major restructuring follows
if (overlapgrid) then
gatm = -1
do nl = 1,ns_l
if (pftm(nl) >= 0) then ! only real or fake points
if (amask(nl) /= 0) then
gatm(nl)=nl
endif
endif
enddo
elseif (latlongrid) then
!pw Still need restructuring for vectorization.
allocate(ilfound(nlon_l),jlfound(nlat_l))
ilfound = 0
jlfound = 0
do jl = 1, nlat_l
found = .false.
lat_l_local = min(max(lat_l(jl),-90.0_r8),90.0_r8) !limit [-90,90]
do ja = 1,nlat_a
if ((ja == 1 .and. lat_l_local <= latn_a(ja) .and. &
lat_l_local >= lats_a(ja)) .or. &
(ja > 1 .and. lat_l_local <= latn_a(ja) .and. &
lat_l_local > lats_a(ja))) then
if (found) then
write(iulog,*) 'map_setgatm WARNING: found > 1 pt j ', &
jl,ja,jlfound(jl),lat_l(jl),lat_l_local
call endrun
()
endif
jlfound(jl) = ja
found = .true.
endif
enddo ! ja
enddo !jl
do il = 1, nlon_l
found = .false.
do ia = 1,nlon_a
do n = -noffset,noffset
offset = n*doffset
if ((ia == 1 .and. lon_l(il)+offset <= lone_a(ia) .and. &
lon_l(il)+offset > lonw_a(ia)) .or. &
(ia > 1 .and. lon_l(il)+offset <= lone_a(ia) .and. &
lon_l(il)+offset > lonw_a(ia))) then
if (found) then
write(iulog,*) 'map_setgatm WARNING: found > 1 pt i ', &
il,ia,ilfound(il),lon_l(il)+offset
call endrun
()
endif
ilfound(il) = ia
found = .true.
endif
enddo ! n, offset
enddo ! ia
enddo
gatm = -1
do jl = 1,nlat_l
do il = 1,nlon_l
nl = (jl-1)*nlon_l + il
if (pftm(nl) >= 0) then ! only real or fake points
if = ilfound(il)
jf = jlfound(jl)
nf = (jf-1)*nlon_a + if
if (if == 0 .or. jf == 0) then
write(iulog,*) 'map_setgatm ERROR: pt not found, ', &
il,lon_l(il), '_l', &
minval(lon_l),maxval(lon_l), &
minval(lat_l),maxval(lat_l),'_awe', &
minval(lonw_a),maxval(lonw_a), &
minval(lone_a),maxval(lone_a),'_asn', &
minval(lats_a),maxval(lats_a), &
minval(latn_a),maxval(latn_a)
call endrun
()
endif
if (amask(nf) /= 0) then
gatm(nl)=nf
endif
endif
enddo
enddo
deallocate(ilfound,jlfound)
else
!pw Still need restructuring for vectorization
write(iulog,*) 'map_setgatm ERROR: irregular lat lon grid not supported'
call endrun
()
endif
!pw major restructuring ends
!--- remove fake land if there is at least one real land overlap point ---
allocate(nocnt(ns_a),nooff(ns_a),nomap(ns_l))
nocnt = 0
do nl = 1,ns_l
na = gatm(nl)
if (na > 0) then
nocnt(na) = nocnt(na) + 1
endif
enddo
nooff(1) = 1
do na = 2,ns_a
nooff(na) = nooff(na-1) + nocnt(na-1)
enddo
nocnt = 0
nomap = -1
do nl = 1,ns_l
na = gatm(nl)
if (na > 0) then
nomap(nooff(na)+nocnt(na)) = nl
nocnt(na) = nocnt(na) + 1
endif
enddo
do na = 1,ns_a
found = .false. ! check if any points are real land
do noidx = 0,nocnt(na)-1
nl = nomap(nooff(na)+noidx)
if (pftm(nl) > 0 ) then
found = .true.
endif
enddo
if (found) then ! if so, keep only real land points
do noidx = 0,nocnt(na)-1
nl = nomap(nooff(na)+noidx)
if (pftm(nl) <= 0 ) then
gatm(nl) = -1
endif
enddo
endif
enddo
!--- check that valid fine grid points have coarse mapping gridpoints
if (masterproc) then
nocnt = 0
do nl = 1,ns_l
na = gatm(nl)
if (na > 0) then
nocnt(na) = nocnt(na) + 1
endif
enddo
found = .true.
do na = 1,ns_a
if ((amask(na) /= 0) .and. (nocnt(na) == 0)) then
found = .false.
endif
enddo
if (.not. found) then
do na = 1,ns_a
if ((amask(na) /= 0) .and. (nocnt(na) == 0)) then
write(iulog,*) 'map_setgatm ERROR: invalid f->c index ', &
na,amask(na)
call endrun
()
endif
enddo
endif
endif
deallocate(nocnt,nooff,nomap)
end subroutine map_setgatm
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setmapsFM
!
! !INTERFACE:
subroutine map_setmapsFM(domain_a, domain_l, gatm_l, map1dl_a2l, map1dl_l2a, name) 1,31
!
! !DESCRIPTION:
! Set course to fine mesh maps and reverse. domain_a should be coarse
! (atm) mesh, domain_l is fine (land) mesh.
! Simple overlap algorithm
! - Find every fine gridcell within coarse gridcell
! - Keep "real" cells unless there are none
! - Weights based on areas of cells used, sum(weights)==1
! - Use a2l mapping to set l2a mapping
!
! !USES:
use decompMod
, only : ldecomp, adecomp
use decompMod
, only : get_proc_bounds, get_proc_bounds_atm
use clm_varsur
, only : wtxy
!
! !ARGUMENTS:
implicit none
type(domain_type),intent(in) :: domain_a
type(domain_type),intent(in) :: domain_l
integer ,intent(in) :: gatm_l(:)
type(map_type) ,intent(inout) :: map1dl_a2l
type(map_type) ,intent(inout) :: map1dl_l2a
character(len=*) ,optional,intent(in) :: name
!
! !REVISION HISTORY:
! 2005.12.01 T Craig Creation.
!
!
! !LOCAL VARIABLES:
!EOP
integer :: ns_a
integer :: ns_l
integer :: na,nag
integer :: nl,nlg
real(r8),pointer :: area_a(:) !input grid: cell area
real(r8),pointer :: topo_a(:) !input grid: cell topo/elevation
real(r8),pointer :: frac_a(:) !input grid: cell frac
integer ,pointer :: mask_l(:) !output grid: cell mask
real(r8),pointer :: area_l(:) !output grid: cell area
real(r8),pointer :: nara_l(:) !output grid: cell equiv upscale area
real(r8),pointer :: topo_l(:) !output grid: cell topo/elevation
real(r8),pointer :: ntop_l(:) !output grid: cell equiv downscale topo
real(r8),pointer :: frac_l(:) !output grid: cell frac
integer :: n_a2l !a2l nwts
integer :: mo_a2l !a2l dstmo
integer ,pointer :: src_a2l(:) !a2l src indices
integer ,pointer :: dst_a2l(:) !a2l dst indices
real(r8),pointer :: wts_a2l(:) !a2l wts indices
integer :: n_l2a !l2a nwts
integer :: mo_l2a !l2a dstmo
integer ,pointer :: src_l2a(:) !l2a src indices
integer ,pointer :: dst_l2a(:) !l2a dst indices
real(r8),pointer :: wts_l2a(:) !l2a wts indices
integer :: na2l,nl2a
integer :: begg,endg
integer :: abegg,aendg
integer ,pointer :: ncnta(:) !number of overlap points in l2a
integer ,pointer :: cnta(:) !number of overlap points in l2a
real(r8),pointer :: asum(:) !number of overlap points in l2a
real(r8),pointer :: tsum(:) !number of overlap points in l2a
real(r8),parameter:: eps = 1.0e-8 ! eps for check
!
!------------------------------------------------------------------------
!--- get local beg/end
call get_proc_bounds
( begg, endg)
call get_proc_bounds_atm
(abegg, aendg)
!--- set pointers into domains, initialize gridmap a2l gridmap ---
call domain_setptrs
(domain_a,ns=ns_a,area=area_a, &
frac=frac_a, topo=topo_a)
call domain_setptrs
(domain_l,ns=ns_l, &
area=area_l, mask=mask_l, frac=frac_l, &
nara=nara_l,topo=topo_l,ntop=ntop_l)
!--- allocate temporaries
allocate(ncnta(abegg:aendg),asum(abegg:aendg),tsum(abegg:aendg),cnta(abegg:aendg))
!--- count local number of wts needed, na2l, nl2a
!--- also set global arrays ncnta and asum for later computations
na2l = 0
nl2a = 0
ncnta = 0
asum = 0.0_r8
do nl = begg,endg
nlg = ldecomp%gdc2glo(nl)
nag = gatm_l(nlg)
if (nag <= 0) then
write(iulog,*) 'map_setmapsFM ERROR nag0 <= 0',nl,nlg,nag
call endrun
()
endif
na = adecomp%glo2gdc(nag)
if (nlg < 1 .or. nlg > ns_l .or. &
nag < 1 .or. nag > ns_a .or. &
na < abegg .or. na > aendg) then
write(iulog,*) 'map_setmapsFM ERROR in index0 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
call endrun
()
endif
ncnta(na) = ncnta(na) + 1
asum(na) = asum(na) + area_l(nl)
na2l = na2l + 1
nl2a = nl2a + 1
enddo
!--- initialize and allocate maps
call map_init
(map1dl_a2l,domain_a,domain_l,na2l,name='setmapsFM_a2l', &
type=map_typelocal)
call map_init
(map1dl_l2a,domain_l,domain_a,nl2a,name='setmapsFM_l2a', &
type=map_typelocal)
!--- set pointers to the maps
call map_setptrs
(map1dl_a2l,src=src_a2l,dst=dst_a2l,wts=wts_a2l, &
nwts=n_a2l,dstmo=mo_a2l)
call map_setptrs
(map1dl_l2a,src=src_l2a,dst=dst_l2a,wts=wts_l2a, &
nwts=n_l2a,dstmo=mo_l2a)
!--- set dstmo in maps
map1dl_a2l%dstmo = 1
map1dl_l2a%dstmo = maxval(ncnta)
!--- set src,dst,wts in maps
na2l = 0
nl2a = 0
cnta = 0
do nl = begg,endg
nlg = ldecomp%gdc2glo(nl)
nag = gatm_l(nlg)
if (nag <= 0) then
write(iulog,*) 'map_setmapsFM ERROR nag1 <= 0',nl,nlg,nag
call endrun
()
endif
na = adecomp%glo2gdc(nag)
if (nlg < 1 .or. nlg > ns_l .or. &
nag < 1 .or. nag > ns_a .or. &
na < abegg .or. na > aendg) then
write(iulog,*) 'map_setmapsFM ERROR in index1 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
call endrun
()
endif
na2l = na2l + 1
if (na2l > n_a2l) then
write(iulog,*) 'map_setmapsFM ERROR na2l > n_a2l ',na2l,n_a2l
call endrun
()
endif
src_a2l(na2l) = na
dst_a2l(na2l) = nl
wts_a2l(na2l) = 1.0_r8
nl2a = nl2a + 1
cnta(na) = cnta(na) + 1
if (nl2a > n_l2a .or. cnta(na) > ncnta(na)) then
write(iulog,*) 'map_setmapsFM ERROR nl2a > n_l2a ',nl2a,n_l2a,cnta(na),ncnta(na)
call endrun
()
endif
src_l2a(nl2a) = nl
dst_l2a(nl2a) = na
if (ncnta(na) == 1) then
wts_l2a(nl2a) = 1.0_r8
else
if (asum(na) <= 0.0_r8) then
write(iulog,*) 'map_setmapsFM ERROR asum <= 0 ',nlg,nag,asum(na)
call endrun
()
endif
wts_l2a(nl2a) = (area_l(nl)/asum(na))
endif
enddo
!--- update ldomain arrays based on upscale/downscale stuff
tsum = 0.0_r8
do nl = begg,endg
nlg = ldecomp%gdc2glo(nl)
nag = gatm_l(nlg)
if (nag <= 0) then
write(iulog,*) 'map_setmapsFM ERROR nag2 <= 0',nl,nlg,nag
call endrun
()
endif
na = adecomp%glo2gdc(nag)
if (nlg < 1 .or. nlg > ns_l .or. &
nag < 1 .or. nag > ns_a .or. &
na < abegg .or. na > aendg) then
write(iulog,*) 'map_setmapsFM ERROR in index2 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
call endrun
()
endif
if (frac_l(nl) > 0.0_r8) then
ntop_l(nl) = topo_l(nl) ! set topo ovr lnd
else
ntop_l(nl) = max(0.0_r8,topo_l(nl)) ! set topo ovr ocn
endif
tsum(na) = tsum(na) + ntop_l(nl)*area_l(nl) ! area wt topo avg
enddo
do nl = begg,endg
nlg = ldecomp%gdc2glo(nl)
nag = gatm_l(nlg)
if (nag <= 0) then
write(iulog,*) 'map_setmapsFM ERROR nag3 <= 0',nl,nlg,nag
call endrun
()
endif
na = adecomp%glo2gdc(nag)
if (nlg < 1 .or. nlg > ns_l .or. &
nag < 1 .or. nag > ns_a .or. &
na < abegg .or. na > aendg) then
write(iulog,*) 'map_setmapsFM ERROR in index3 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
call endrun
()
endif
if (ncnta(na) == 1) then
nara_l(nl) = area_a(na)
ntop_l(nl) = topo_a(na)
else
if (asum(na) <= 0.0_r8) then
write(iulog,*) 'map_setmapsFM ERROR2 asum <= 0 ',nl,na,asum(na)
call endrun
()
endif
if (tsum(na) < 0.0_r8) then
write(iulog,*) 'map_setmapsFM ERROR2 tsum < 0 ',nl,na,tsum(na)
call endrun
()
endif
nara_l(nl) = (area_l(nl)/asum(na))*area_a(na)
! DOWNSCALING
!-v-v-v-v-v- land topo elevation adjustment for downscaling -v-v-v-v-
!----------- want avg land topo to be equal to atm topo and want the
!----------- variability in finemesh land topo to be preserved
if (tsum(na) == 0.) then
ntop_l(nl) = ntop_l(nl)+topo_a(na)
elseif (topo_a(na) > 0.) then
ntop_l(nl) = (ntop_l(nl)/(tsum(na)/asum(na)))*topo_a(na)
else
ntop_l(nl) = (ntop_l(nl)-(tsum(na)/asum(na)))+topo_a(na)
endif
!-^-^-^-^-^- land topo elevation adjustment for downscaling -^-^-^-^-
endif
enddo
!--- check that areas and topos match up
asum = 0.0_r8
tsum = 0.0_r8
do nl = begg,endg
nlg = ldecomp%gdc2glo(nl)
nag = gatm_l(nlg)
if (nag <= 0) then
write(iulog,*) 'map_setmapsFM ERROR nag4 <= 0',nl,nlg,nag
call endrun
()
endif
na = adecomp%glo2gdc(nag)
if (nlg < 1 .or. nlg > ns_l .or. &
nag < 1 .or. nag > ns_a .or. &
na < abegg .or. na > aendg) then
write(iulog,*) 'map_setmapsFM ERROR in index4 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
call endrun
()
endif
asum(na) = asum(na) + nara_l(nl)
tsum(na) = tsum(na) + nara_l(nl)*ntop_l(nl)
enddo
do na = abegg, aendg
if (asum(na) > 0.0_r8) then
if (abs(asum(na)-area_a(na)) > eps .or. &
abs(tsum(na)/area_a(na) - topo_a(na)) > eps) then
write(iulog,*) ' map_setmapsFM ERROR: ERROR in nara,ntop, ',asum(na),area_a(na),tsum(na),topo_a(na),eps
call endrun
()
endif
endif
enddo
!--- clean up
deallocate(ncnta,cnta,asum,tsum)
call map_checkmap
(map1dl_a2l)
call map_checkmap
(map1dl_l2a)
! Set ldomain mask and frac based on adomain and mapping.
! Want ldomain%frac to match adomain%frac but scale by effective area.
! so the implied area of an ldomain cell is the actual area *
! scaled frac which aggregated over all land cells under an atm cell,
! will match the area associated with the atm cell.
do nl = begg,endg
nlg = ldecomp%gdc2glo(nl)
nag = gatm_l(nlg)
if (nag <= 0) then
write(iulog,*) 'initialize2 nag <= 0 ERROR ',nl,nlg,nag
call endrun
()
endif
na = adecomp%glo2gdc(nag)
if (nlg < 1 .or. nlg > ns_l .or. &
nag < 1 .or. nag > ns_a .or. &
na < abegg .or. na > aendg) then
write(iulog,*) 'initialize2 index ERROR ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
call endrun
()
endif
mask_l(nl) = 1
frac_l(nl) = frac_a(na)* (nara_l(nl)/area_l(nl))
enddo
end subroutine map_setmapsFM
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setmapsAR
!
! !INTERFACE:
subroutine map_setmapsAR (latlon_i, latlon_o, sMat, & 1,2
fracin, fracout)
!
! !DESCRIPTION:
! area averaging initialization
! This subroutine is used for area-average mapping of a field from one
! grid to another.
!
! !USES:
use clm_mct_mod
!
! !ARGUMENTS:
implicit none
type(latlon_type) ,intent(in) :: latlon_i ! input domain
type(latlon_type) ,intent(in) :: latlon_o ! output domain
type(mct_sMat) ,intent(inout) :: sMat ! mct sparse matrix plux
real(r8), intent(in),target :: fracin(:)
real(r8), intent(in),target :: fracout(:)
!
! !REVISION HISTORY:
! Created by Gordon Bonan
! 2005.11.20 Updated by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
integer :: nlon_i !input grid: max number of longitude pts
integer :: nlat_i !input grid: number of latitude points
real(r8),pointer :: dx_i(:) !input grid: dx length
real(r8),pointer :: dy_i(:) !input grid: dy length
real(r8),pointer :: fland_i(:) !input grid: cell frac
real(r8),pointer :: lone_i(:) !input grid: longitude, E edge (degrees)
real(r8),pointer :: lonw_i(:) !input grid: longitude, W edge (degrees)
real(r8),pointer :: latn_i(:) !input grid: latitude, N edge (degrees)
real(r8),pointer :: lats_i(:) !input grid: latitude, S edge (degrees)
integer :: nlon_o !output grid: max number of longitude pts
integer :: nlat_o !output grid: number of latitude points
real(r8),pointer :: dx_o(:) !output grid: dx length
real(r8),pointer :: dy_o(:) !output grid: dy length
real(r8),pointer :: fland_o(:) !output grid: cell frac
real(r8),pointer :: lone_o(:) !output grid: longitude, E edge (degrees)
real(r8),pointer :: lonw_o(:) !output grid: longitude, W edge (degrees)
real(r8),pointer :: latn_o(:) !output grid: latitude, N edge (degrees)
real(r8),pointer :: lats_o(:) !output grid: latitude, S edge (degrees
integer :: nwts !local num of weights
integer :: n,ns,nw,k !loop counters
integer nb,na !grid sizes
integer i,j !loop indices
integer io,jo,no !output grid loop index
integer ii,ji,ni !input grid loop index
integer nji, njilap !counter and number of j overlaps
integer,pointer :: jilap(:) ! j overlap indices
integer,pointer :: iilaps(:),iilape(:) ! i start/end overlap indices
real(r8) lonw !west longitudes of overlap
real(r8) lone !east longitudes of overlap
real(r8) dx !difference in longitudes
real(r8) lats !south latitudes of overlap
real(r8) latn !north latitudes of overlap
real(r8) dy !difference in latitudes
real(r8) deg2rad !pi/180
real(r8) a_ovr !area of overlap
integer noffsetl !local, number of offsets to test, 0=none, default=1
real(r8) offset !value of offset used to shift x-grid 360 degrees
real(r8) :: sum !local sum of wts
integer :: igrow,igcol,iwgt ! mct smat field indices
integer :: nr !mct field index
real(r8) :: wt !mct weight
real(r8),pointer :: fld_i(:), fld_o(:) !dummy fields for testing
real(r8) :: sum_fldi !global sum of dummy input field
real(r8) :: sum_fldo !global sum of dummy output field
real(r8) :: sum_areo !global sum of dummy output field
real(r8) :: sum_arei !global sum of dummy input field
real(r8) :: relerr = 0.001_r8 !relative error for error checks
real(r8) :: sdx_i !input grid longitudinal range
real(r8) :: sdy_i !input grid latitudinal range
real(r8) :: sdx_o !output grid longitudinal range
real(r8) :: sdy_o !output grid latitudinal range
integer :: ier !error status
!------------------------------------------------------------------------
nlon_i = latlon_i%ni
nlat_i = latlon_i%nj
latn_i => latlon_i%latn
lats_i => latlon_i%lats
lonw_i => latlon_i%lonw
lone_i => latlon_i%lone
fland_i => fracin
nlon_o = latlon_o%ni
nlat_o = latlon_o%nj
latn_o => latlon_o%latn
lats_o => latlon_o%lats
lonw_o => latlon_o%lonw
lone_o => latlon_o%lone
fland_o => fracout
! Dynamically allocate memory
na = nlon_i*nlat_i
nb = nlon_o*nlat_o
noffsetl = 1
! Get indices and weights for mapping from input grid to output grid
allocate(jilap(nlat_i))
allocate(iilaps(nlon_o),iilape(nlon_o))
! Find start/end indices for i overlap to save time later, set default never
iilaps = nlon_i
iilape = 1
do io = 1, nlon_o
!------ offset -------
do n = 0,noffsetl ! loop through offsets
if (lonw_i(1) < lonw_o(1)) then
offset = (n*360)
else
offset = -(n*360)
end if
do ii = 1, nlon_i
!--- lons overlap ---
if (lonw_i(ii)+offset < lone_o(io) .and. &
lone_i(ii)+offset > lonw_o(io)) then
if (ii < iilaps(io)) iilaps(io) = ii
if (ii > iilape(io)) iilape(io) = ii
endif
enddo
enddo
enddo
do k = 1,2 ! k = 1 compute num of wts, k = 2 set wts
if (k == 2) then
call mct_sMat_init(sMat, nb, na, nwts)
igrow = mct_sMat_indexIA(sMat,'grow')
igcol = mct_sMat_indexIA(sMat,'gcol')
iwgt = mct_sMat_indexRA(sMat,'weight')
endif
nw = 0
deg2rad = SHR_CONST_PI / 180._r8
!------ output grid -------
do jo = 1, nlat_o
njilap = 0
do ji = 1, nlat_i
!--- lats overlap ---
if ( lats_i(ji)<latn_o(jo) .and. &
latn_i(ji)>lats_o(jo)) then
njilap = njilap + 1
jilap(njilap) = ji
endif
enddo
do io = 1, nlon_o
ns = nw + 1
!------ input grid -------
sum = 0._r8
do nji = 1, njilap
ji = jilap(nji)
!------ offset -------
do n = 0,noffsetl ! loop through offsets
if (lonw_i(1) < lonw_o(1)) then
offset = (n*360)
else
offset = -(n*360)
end if
! do ii = 1, nlon_i
do ii = iilaps(io),iilape(io)
ni = (ji-1)*nlon_i + ii
no = (jo-1)*nlon_o + io
!--- lons overlap ---
if (k == 1) then
if (lonw_i(ii)+offset < lone_o(io) .and. &
lone_i(ii)+offset > lonw_o(io)) then
!------- found overlap ------
if (fland_i(ni) > 0._r8 .and. fland_o(no) > 0._r8 ) then
nw = nw + 1
endif
endif
elseif (k == 2) then
if (lonw_i(ii)+offset < lone_o(io) .and. &
lone_i(ii)+offset > lonw_o(io)) then
! determine area of overlap
lone = min(lone_o(io),lone_i(ii)+offset)*deg2rad
lonw = max(lonw_o(io),lonw_i(ii)+offset)*deg2rad
dx = max(0.0_r8,(lone-lonw))
latn = min(latn_o(jo),latn_i(ji))*deg2rad
lats = max(lats_o(jo),lats_i(ji))*deg2rad
dy = max(0.0_r8,(sin(latn)-sin(lats)))
a_ovr = dx*dy*re*re
sum = sum + a_ovr
!------- found overlap ------
if (fland_i(ni) > 0._r8 .and. fland_o(no) > 0._r8 ) then
nw = nw + 1
! make sure nw <= nwts
if (nw > nwts) then
write(iulog,*) 'AREAOVR error: nw= ', &
nw,' exceeded nwts ceiling = ', &
nwts,' for output lon,lat = ',io,jo
call endrun
end if
! save cell indices, area
sMat%data%iAttr(igrow,nw) = no
sMat%data%iAttr(igcol,nw) = ni
sMat%data%rAttr(iwgt ,nw) = a_ovr
endif
endif
end if ! found overlap lon
end do ! ii
enddo ! offset loop
end do ! ji
!--- normalize ---
if (k == 2) then
do n = ns,nw
if (sum > 0._r8) then
sMat%data%rAttr(iwgt,n) = sMat%data%rAttr(iwgt,n) / sum
else
sMat%data%rAttr(iwgt,n) = 0._r8
endif
enddo
endif
end do ! io
end do ! jo
nwts = nw
enddo ! k loop
deallocate(jilap)
deallocate(iilaps,iilape)
! Error check: global sum fld_o = global sum fld_i.
! This true only if both grids span the same domain.
sdx_i = lone_i(nlon_i) - lonw_i(1)
sdx_o = lone_o(nlon_o) - lonw_o(1)
sdy_i = max(abs(latn_i(nlat_i)-lats_i(1)),abs(lats_i(nlat_i)-latn_i(1)))
sdy_o = max(abs(latn_o(nlat_o)-lats_o(1)),abs(lats_o(nlat_o)-latn_o(1)))
if (abs(sdx_i-sdx_o)>relerr .or. abs(sdy_i-sdy_o)>relerr) then
if (masterproc) then
write(iulog,*) 'MAP_SETMAPSAR warning: lats/lons not overlapping'
write(iulog,*) ' input grid of ',nlon_i,' x ',nlat_i,' dx,dy= ',sdx_i,sdy_i
write(iulog,*) ' output grid of ',nlon_o,' x ',nlat_o,' dx,dy= ',sdx_o,sdy_o
endif
return
end if
! Compute dx,dy for checking areas later
allocate(dx_i(nlon_i),dy_i(nlat_i),dx_o(nlon_o),dy_o(nlat_o))
do i = 1,nlon_i
dx_i(i) = (lone_i(i) - lonw_i(i))*deg2rad
enddo
do j = 1,nlat_i
dy_i(j) = sin(latn_i(j)*deg2rad) - sin(lats_i(j)*deg2rad)
enddo
do i = 1,nlon_o
dx_o(i) = (lone_o(i) - lonw_o(i))*deg2rad
enddo
do j = 1,nlat_o
dy_o(j) = sin(latn_o(j)*deg2rad) - sin(lats_o(j)*deg2rad)
enddo
! check for conservation
allocate(fld_i(na),fld_o(nb))
sum_fldi = 0._r8
sum_arei = 0._r8
do j = 1,nlat_i
do i = 1,nlon_i
ni = (j-1)*nlon_i + i
fld_i(ni) = ni
sum_fldi = sum_fldi + fld_i(ni)*dx_i(i)*dy_i(j)*fland_i(ni)
sum_arei = sum_arei + dx_i(i)*dy_i(j)*fland_i(ni)
end do
end do
fld_o = 0._r8
do n = 1,mct_sMat_lsize(sMat)
no = sMat%data%iAttr(igrow,n)
ni = sMat%data%iAttr(igcol,n)
wt = sMat%data%rAttr(iwgt ,n)
fld_o(no) = fld_o(no) + wt*fld_i(ni)
enddo
sum_fldo = 0._r8
sum_areo = 0._r8
do j = 1,nlat_o
do i = 1,nlon_o
no = (j-1)*nlon_o + i
sum_fldo = sum_fldo + dx_o(i)*dy_o(j)*fld_o(no)
sum_areo = sum_areo + dx_o(i)*dy_o(j)*fland_o(no)
end do
end do
if ( abs(sum_fldo/sum_fldi-1._r8) > relerr ) then
if ( abs(sum_arei-sum_areo)/(sum_arei+sum_areo) > relerr ) then
if (masterproc) then
write(iulog,*) 'MAP_SETMAPSAR: no conservation check done, mask incompatable'
write(iulog,'(a30,e20.10)') 'global sum input field = ',sum_arei
write(iulog,'(a30,e20.10)') 'global sum output field = ',sum_areo
endif
else
if (masterproc) then
write(iulog,*) 'MAP_SETMAPSAR error: conservation check fail'
write(iulog,'(a30,e20.10)') 'global sum input field = ',sum_fldi
write(iulog,'(a30,e20.10)') 'global sum output field = ',sum_fldo
endif
endif
else
if (masterproc) then
write(iulog,*) 'MAP_SETMAPSAR: conservation check passed'
write(iulog,'(a30,e20.10)') 'global sum input field = ',sum_fldi
write(iulog,'(a30,e20.10)') 'global sum output field = ',sum_fldo
endif
endif
deallocate(dx_i,dy_i,dx_o,dy_o)
deallocate(fld_i,fld_o)
end subroutine map_setmapsAR
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_checkmap
!
! !INTERFACE:
subroutine map_checkmap(map) 2,5
!
! !DESCRIPTION:
! Checks the map for consistency
!
! !USES:
use spmdMod
use decompMod
, only : get_proc_bounds, get_proc_bounds_atm
!
! !ARGUMENTS:
implicit none
type(map_type),intent(in) :: map
!
! !REVISION HISTORY:
! 2005.12.01 T Craig Creation.
!
!
! !LOCAL VARIABLES:
!EOP
integer :: nlon_i !input grid: max number of longitude pts
integer :: nlat_i !input grid: number of latitude points
integer :: nlon_o !output grid: max number of longitude pts
integer :: nlat_o !output grid: number of latitude points
integer :: nwts !local num of weights
integer :: dstmo !max num of overlapping cells
integer ,pointer :: src(:) !src index
integer ,pointer :: dst(:) !dst index
real(r8),pointer :: wts(:) !weight
integer :: n !loop counters
real(r8),pointer :: rsum(:) !local array for deriving values
real(r8) :: rmin,rmax !local min/max values
real(r8) :: smin,smax !local min/max values
integer :: imin,imax !local min/max values
integer :: nmin,nmax,nsum !local min/max/sum values
integer :: ier ! error flag
!
!------------------------------------------------------------------------
!--- get general info ---
call map_setptrs
(map,ni_i=nlon_i,nj_i=nlat_i, &
ni_o=nlon_o,nj_o=nlat_o)
call map_setptrs
(map,nwts=nwts,src=src,dst=dst,wts=wts,dstmo=dstmo)
if (masterproc) then
write(iulog,*) ' '
write(iulog,*) 'map_checkmap name = ',trim(map%name)
write(iulog,*) 'map_checkmap type = ',trim(map%type)
write(iulog,*) 'map_checkmap src grid = ',nlon_i,nlat_i
write(iulog,*) 'map_checkmap dst grid = ',nlon_o,nlat_o
write(iulog,*) 'map_checkmap dstmo = ',dstmo
endif
call mpi_reduce(nwts,nmin,1,MPI_INTEGER,MPI_MIN,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce nwts error: ',ier
endif
call mpi_reduce(nwts,nmax,1,MPI_INTEGER,MPI_MAX,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce nwts error: ',ier
endif
call mpi_reduce(nwts,nsum,1,MPI_INTEGER,MPI_SUM,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce nwts error: ',ier
endif
if (masterproc) then
write(iulog,*) 'map_checkmap nwts gmin/max = ',nmin,nmax
write(iulog,*) 'map_checkmap nwts gsum = ',nsum
endif
imin = minval(src)
imax = maxval(src)
call mpi_reduce(imin,nmin,1,MPI_INTEGER,MPI_MIN,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce src min error: ',ier
endif
call mpi_reduce(imax,nmax,1,MPI_INTEGER,MPI_MAX,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce src max error: ',ier
endif
if (masterproc) then
write(iulog,*) 'map_checkmap src gmin/max = ',nmin,nmax
endif
imin = minval(dst)
imax = maxval(dst)
call mpi_reduce(imin,nmin,1,MPI_INTEGER,MPI_MIN,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce dst min error: ',ier
endif
call mpi_reduce(imax,nmax,1,MPI_INTEGER,MPI_MAX,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce dst max error: ',ier
endif
if (masterproc) then
write(iulog,*) 'map_checkmap dst gmin/max = ',nmin,nmax
endif
rmin = minval(wts)
rmax = maxval(wts)
call mpi_reduce(rmin,smin,1,MPI_REAL8,MPI_MIN,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce wts min error: ',ier
endif
call mpi_reduce(rmax,smax,1,MPI_REAL8,MPI_MAX,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce wts max error: ',ier
endif
if (masterproc) then
write(iulog,*) 'map_checkmap wts gmin/max = ',smin,smax
endif
imin = minval(dst)
imax = maxval(dst)
allocate(rsum(imin:imax))
rsum = 0.0_r8
do n = 1,nwts
if (dst(n) < imin .or. dst(n) > imax) then
write(iulog,*) 'map_checkmap dst index error ',n,dst(n),imin,imax
call endrun
()
endif
rsum(dst(n)) = rsum(dst(n)) + wts(n)
enddo
rmin = minval(rsum)
rmax = maxval(rsum)
deallocate(rsum)
call mpi_reduce(rmin,smin,1,MPI_REAL8,MPI_MIN,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce swts min error: ',ier
endif
call mpi_reduce(rmax,smax,1,MPI_REAL8,MPI_MAX,0,mpicom,ier)
if (ier /= 0) then
write(iulog,*)'mpi_reduce swts max error: ',ier
endif
if (masterproc) then
write(iulog,*) 'map_checkmap swts gmin/max = ',smin,smax
endif
end subroutine map_checkmap
!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: cellarea
!
! !INTERFACE:
real(r8) function cellarea(latlon,i,j) 2
!
! !DESCRIPTION:
! Comute area of grid cells (square kilometers)
! Verify total area from grid cells is same as area of grid
! as defined by its edges
!
! !USES:
!
! !ARGUMENTS:
implicit none
type(latlon_type), intent(in ) :: latlon ! latlon datatype
integer , intent(in) :: i,j ! latlon index to compute
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
!
!
! !LOCAL VARIABLES:
!EOP
integer :: nbeg
integer :: nend
integer :: ni
integer :: nj
real(r8) deg2rad !pi/180
real(r8) dx !cell width: E-W
real(r8) dy !cell width: N-S
!------------------------------------------------------------------------
deg2rad = SHR_CONST_PI / 180._r8
dx = (latlon%lone(i) - latlon%lonw(i)) * deg2rad
dy = sin(latlon%latn(j)*deg2rad) - sin(latlon%lats(j)*deg2rad)
cellarea = dx*dy*re*re
return
end function cellarea
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: latlon_celledge_regional
!
! !INTERFACE:
subroutine latlon_celledge_regional (latlon, edgen, edgee, edges, edgew) 1
!
! !DESCRIPTION:
! Southern and western edges of grid cells - regional grid
! (can become global as special case)
! Latitudes -- southern/northern edges for each latitude strip.
! For grids oriented South to North, the southern
! and northern edges of latitude strip [j] are:
! southern = lats(j )
! northern = lats(j+1)
! For grids oriented North to South: the southern
! and northern edges of latitude strip [j] are:
! northern = lats(j )
! southern = lats(j+1)
! In both cases, [lats] must be dimensioned lats(lat+1)
! Longitudes -- western edges. Longitudes for the western edge of the
! cells must increase continuously and span 360 degrees. Assume that
! grid starts at Dateline with western edge on Dateline Western edges
! correspond to [lonc] (longitude at center of cell) and range from
! -180 to 180 with negative longitudes west of Greenwich.
! Partial grids that do not span 360 degrees are allowed so long as they
! have the convention of Grid 1 with
! western edge of grid: >= -180 and < 180
! eastern edge of grid: > western edge and <= 180
! [lonw] must be dimensioned lonw(lon+1,lat) because each latitude
! strip can have variable longitudinal resolution
!
! !USES:
!
! !ARGUMENTS:
implicit none
type(latlon_type),intent(inout) :: latlon
real(r8), intent(in) :: edgen !northern edge of grid (degrees)
real(r8), intent(in) :: edgee !eastern edge of grid (degrees)
real(r8), intent(in) :: edges !southern edge of grid (degrees)
real(r8), intent(in) :: edgew !western edge of grid (degrees)
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! 2005.11.20 Updated to latlon datatype by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
integer :: nlon
integer :: nlat
real(r8),pointer :: lonc(:)
real(r8),pointer :: latc(:)
real(r8),pointer :: lats(:)
real(r8),pointer :: latn(:)
real(r8),pointer :: lonw(:)
real(r8),pointer :: lone(:)
integer i,j !indices
real(r8) dx !cell width
!------------------------------------------------------------------------
nlon = latlon%ni
nlat = latlon%nj
lonc => latlon%lonc
latc => latlon%latc
lats => latlon%lats
latn => latlon%latn
lonw => latlon%lonw
lone => latlon%lone
! Latitudes
! Assumes lats are constant on an i line
if (nlat == 1) then ! single latitude
lats(:) = edges
latn(:) = edgen
elseif (latc(2) > latc(1)) then ! South to North grid
lats(:) = edges
latn(:) = edgen
do j = 2, nlat
lats(j) = (latc(j-1) + latc(j)) / 2._r8
latn(j-1) = lats(j)
end do
else ! North to South grid
lats(:) = edges
latn(:) = edgen
do j = 2, nlat
latn(j) = (latc(j-1) + latc(j)) / 2._r8
lats(j-1) = latn(j)
end do
end if
! Longitudes
! Western edge of first grid cell -- since grid starts with western
! edge on Dateline, lonw(1,j)=-180. This is the same as [edgew].
lonw(:) = edgew
lone(:) = edgee
dx = (edgee - edgew) / nlon
do i = 2, nlon
lonw(i) = lonw(i) + (i-1)*dx
lone(i-1) = lonw(i)
end do
latlon%regional = .true.
latlon%edges(1) = edgen
latlon%edges(2) = edgee
latlon%edges(3) = edges
latlon%edges(4) = edgew
return
end subroutine latlon_celledge_regional
!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: latlon_celledge_global
!
! !INTERFACE:
subroutine latlon_celledge_global (latlon) 1,1
!
! !DESCRIPTION:
!
! !USES:
!
! !ARGUMENTS:
implicit none
type(latlon_type),intent(inout) :: latlon
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! 2005.11.20 Updated to latlon datatype by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
integer :: nlon
integer :: nlat
real(r8),pointer :: lonc(:)
real(r8),pointer :: latc(:)
real(r8),pointer :: lats(:)
real(r8),pointer :: latn(:)
real(r8),pointer :: lonw(:)
real(r8),pointer :: lone(:)
integer i,j !indices
real(r8) dx !cell width
!------------------------------------------------------------------------
nlon = latlon%ni
nlat = latlon%nj
lonc => latlon%lonc
latc => latlon%latc
lats => latlon%lats
latn => latlon%latn
lonw => latlon%lonw
lone => latlon%lone
! Latitudes
lats(:) = -90._r8
latn(:) = 90._r8
do j = 2, nlat
lats(j) = (latc(j-1) + latc(j)) / 2._r8
latn(j-1) = lats(j)
end do
! Longitudes
if (lonc(1) >= 0._r8) then
dx = 360._r8/(nlon)
lonw(:) = -dx/2._r8
lone(:) = -dx/2._r8 + (nlon)*dx
do i = 2, nlon
lonw(i) = -dx/2._r8 + (i-1)*dx
lone(i-1) = lonw(i)
end do
else
write(iulog,*)'global non-regional grids currently only supported ', &
'for grids starting at greenwich and centered on Greenwich'
call endrun
endif
return
end subroutine latlon_celledge_global
!-----------------------------------------------------------------------
end module areaMod