#include <misc.h> #include <preproc.h> module surfrdMod 1,15 !----------------------------------------------------------------------- !BOP ! ! !MODULE: surfrdMod ! ! !DESCRIPTION: ! Contains methods for reading in surface data file and determining ! two-dimensional subgrid weights as well as writing out new surface ! dataset. When reading in the surface dataset, determines array ! which sets the PFT for each of the [maxpatch] patches and ! array which sets the relative abundance of the PFT. ! Also fills in the PFTs for vegetated portion of each grid cell. ! Fractional areas for these points pertain to "vegetated" ! area not to total grid area. Need to adjust them for fraction of grid ! that is vegetated. Also fills in urban, lake, wetland, and glacier patches. ! ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use abortutils , only : endrun use clm_varpar , only : lsmlon, lsmlat use clm_varpar , only : nlevsoi, numpft, & maxpatch_pft, numcft, maxpatch, & npatch_urban, npatch_lake, npatch_wet, npatch_glacier, & maxpatch_urb use clm_varpar , only : npatch_glacier_mec use clm_varctl , only : create_glacier_mec_landunit use clm_varsur , only : wtxy, vegxy use clm_varsur , only : topoxy use clm_varsur , only : pctspec use clm_varctl , only : iulog use ncdio use clmtype use spmdMod use clm_varctl, only : scmlat, scmlon, single_column use decompMod , only : get_proc_bounds,gsMap_lnd_gdc2glo,ldecomp ! ! !PUBLIC TYPES: implicit none save ! ! !PUBLIC MEMBER FUNCTIONS: public :: surfrd ! Read surface dataset and determine subgrid weights public :: surfrd_get_grid ! Read surface dataset into domain public :: surfrd_get_latlon ! Read surface dataset into domain public :: surfrd_get_frac ! Read land fraction into domain public :: surfrd_get_topo ! Read topography into domain ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein ! Updated by T Craig ! ! ! !PRIVATE MEMBER FUNCTIONS: private :: surfrd_wtxy_special private :: surfrd_wtxy_veg_rank private :: surfrd_wtxy_veg_all private :: surfrd_wtxy_veg_dgvm private :: surfrd_mkrank !EOP !----------------------------------------------------------------------- contains !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd ! ! !INTERFACE: ! subroutine surfrd(vegxy, wtxy, lfsurdat, domain) subroutine surfrd(lfsurdat, domain) 1,14 ! ! !DESCRIPTION: ! Read the surface dataset and create subgrid weights. ! The model's surface dataset recognizes 6 basic land cover types within a grid ! cell: lake, wetland, urban, glacier, glacier_mec and vegetated. The vegetated ! portion of the grid cell is comprised of up to [maxpatch_pft] PFTs. These ! subgrid patches are read in explicitly for each grid cell. This is in ! contrast to LSMv1, where the PFTs were built implicitly from biome types. ! o real edges of grid ! o integer number of longitudes per latitude ! o real latitude of grid cell (degrees) ! o real longitude of grid cell (degrees) ! o integer surface type: 0 = ocean or 1 = land ! o integer soil color (1 to 20) for use with soil albedos ! o real soil texture, %sand, for thermal and hydraulic properties ! o real soil texture, %clay, for thermal and hydraulic properties ! o real % of cell covered by lake for use as subgrid patch ! o real % of cell covered by wetland for use as subgrid patch ! o real % of cell that is urban for use as subgrid patch ! o real % of cell that is glacier for use as subgrid patch ! o real % of cell that is glacier_mec for use as subgrid patch ! o integer PFTs ! o real % abundance PFTs (as a percent of vegetated area) ! ! !USES: use clm_varctl , only : allocate_all_vegpfts, create_crop_landunit use pftvarcon , only : noveg use fileutils , only : getfil use domainMod , only : domain_type ! ! !ARGUMENTS: implicit none include 'netcdf.inc' ! integer , intent(out) :: vegxy(:,:) ! PFT ! real(r8), intent(out) :: wtxy(:,:) ! subgrid weights character(len=*), intent(in) :: lfsurdat ! surf filename type(domain_type),intent(in) :: domain ! domain associated with wtxy ! ! !CALLED FROM: ! subroutine initialize in module initializeMod ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan ! ! ! !LOCAL VARIABLES: !EOP character(len=256) :: locfn ! local file name integer :: ncid,dimid,varid ! netCDF id's integer :: begg,endg logical :: found ! temporary for error check integer :: iindx, jindx ! temporary for error check integer :: ier ! error status character(len=32) :: subname = 'surfrd' ! subroutine name !----------------------------------------------------------------------- call get_proc_bounds(begg,endg) allocate(pctspec(begg:endg)) vegxy(:,:) = noveg wtxy(:,:) = 0._r8 pctspec(:) = 0._r8 if (allocated(topoxy)) topoxy(:,:) = 0._r8 if (masterproc) then write(iulog,*) 'Attempting to read surface boundary data .....' if (lfsurdat == ' ') then write(iulog,*)'lfsurdat must be specified'; call endrun() endif endif ! Read surface data if (masterproc) then call getfil( lfsurdat, locfn, 0 ) call check_ret( nf_open(locfn, 0, ncid), subname ) end if ! Obtain surface dataset special landunit info call surfrd_wtxy_special(ncid, domain) ! Obtain surface dataset vegetated landunit info #if (defined CNDV) if (create_crop_landunit) then ! CNDV means allocate_all_vegpfts = .true. call surfrd_wtxy_veg_all(ncid, domain) end if call surfrd_wtxy_veg_dgvm(domain) #else if (allocate_all_vegpfts) then call surfrd_wtxy_veg_all(ncid, domain) else call surfrd_wtxy_veg_rank(ncid, domain) end if #endif if ( masterproc )then call check_ret(nf_close(ncid), subname) write(iulog,*) 'Successfully read surface boundary data' write(iulog,*) end if end subroutine surfrd !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_get_grid ! ! !INTERFACE: subroutine surfrd_get_grid(domain,filename,beg,end,clmlevel) 2,19 ! ! !DESCRIPTION: ! Read the surface dataset grid related information: ! o real edges of grid ! o integer number of longitudes per latitude ! o real latitude of grid cell (degrees) ! o real longitude of grid cell (degrees) ! If grid is read in from dataset, grid is assumed to be global but ! does not have to be regular. ! If grid is generated by model, grid does not have to be global but ! must then define the north, east, south, and west edges: ! ! o edges(1) = northern edge of grid (degrees): > -90 and <= 90 ! o edges(2) = eastern edge of grid (degrees) : see following notes ! o edges(3) = southern edge of grid (degrees): >= -90 and < 90 ! o edges(4) = western edge of grid (degrees) : see following notes ! ! For partial grids, northern and southern edges are any latitude ! between 90 (North Pole) and -90 (South Pole). Western and eastern ! edges are any longitude between -180 and 180, with longitudes ! west of Greenwich negative. That is, western edge >= -180 and < 180; ! eastern edge > western edge and <= 180. ! ! For global grids, northern and southern edges are 90 (North Pole) ! and -90 (South Pole). The western and eastern edges depend on ! whether the grid starts at Dateline or Greenwich. Regardless, ! these edges must span 360 degrees. Examples: ! ! West edge East edge ! -------------------------------------------------- ! (1) Dateline : -180 to 180 (negative W of Greenwich) ! (2) Greenwich (centered): 0 - dx/2 to 360 - dx/2 ! ! Grid 2 is the grid for cam and ccsm mode since the NCAR CAM ! starts at Greenwich, centered on Greenwich ! ! !USES: use clm_varcon, only : spval use domainMod , only : domain_type,domain_init use fileutils , only : getfil ! ! !ARGUMENTS: implicit none include 'netcdf.inc' type(domain_type),intent(inout) :: domain ! domain to init character(len=*) ,intent(in) :: filename ! grid filename integer ,intent(in) :: beg ! local beg index integer ,intent(in) :: end ! local end index character(len=*) ,intent(in) :: clmlevel ! type of grid ! ! !CALLED FROM: ! subroutine surfrd in this module ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein ! ! ! !LOCAL VARIABLES: !EOP integer :: ni,nj ! size of grid on file integer :: ncid,dimid,varid ! netCDF id's integer :: ier ! error status character(len=256) :: locfn ! local file name integer :: ret character(len=32) :: subname = 'surfrd_get_grid' ! subroutine name !----------------------------------------------------------------------- if (masterproc) then if (filename == ' ') then write(iulog,*) trim(subname),' ERROR: filename must be specified ' call endrun() endif call getfil( filename, locfn, 0 ) call check_ret( nf_open(locfn, 0, ncid), subname ) if (single_column) then ni = lsmlon nj = lsmlat else call check_ret(nf_inq_dimid (ncid, 'lsmlon', dimid), subname) call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname) call check_ret(nf_inq_dimid (ncid, 'lsmlat', dimid), subname) call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname) endif endif call mpi_bcast (ni, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (nj, 1, MPI_INTEGER, 0, mpicom, ier) call domain_init(domain,ni,nj,beg,end,clmlevel) call ncd_iolocal(ncid, 'AREA', 'read', domain%area, clmlevel, status=ret) if (ret == 0) domain%areaset = .true. call ncd_iolocal(ncid, 'LONGXY', 'read', domain%lonc, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY NOT on file' ) call ncd_iolocal(ncid, 'LATIXY', 'read', domain%latc, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LATIXY NOT on file' ) ! set mask to 1 everywhere by default, override if LANDMASK exists ! if landmask exists, use it to set pftm (for older datasets) ! pftm should be overwritten below for newer datasets domain%mask = 1 call ncd_iolocal(ncid, 'LANDMASK', 'read', domain%mask, clmlevel, status=ret) domain%pftm = domain%mask where (domain%mask <= 0) domain%pftm = -1 endwhere call ncd_iolocal(ncid, 'PFTDATA_MASK', 'read', domain%pftm, clmlevel, status=ret) !tcx fix, this or a test/abort should be added so overlaps can be computed !tcx fix, this is demonstrated not bfb in cam bl311 test. !tcx fix, see also lat_o_local in areaMod.F90 #if (defined TCX_REMOVE_SEE_NOTES_ABOVE) ! Check lat limited to -90,90 if (minval(domain%latc) < -90.0_r8 .or. & maxval(domain%latc) > 90.0_r8) then write(iulog,*) trim(subname),' Limiting lat/lon to [-90/90] from ', & minval(domain%latc),maxval(domain%latc) where (domain%latc < -90.0_r8) domain%latc = -90.0_r8 where (domain%latc > 90.0_r8) domain%latc = 90.0_r8 endif #endif if (masterproc) call check_ret(nf_close(ncid), subname) end subroutine surfrd_get_grid !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_get_latlon ! ! !INTERFACE: subroutine surfrd_get_latlon(latlon,filename,mask,mfilename,pftmflag) 2,31 ! ! !DESCRIPTION: ! Read the surface dataset grid related information: ! ! !USES: use clm_varcon, only : spval use domainMod , only : latlon_type, latlon_init use fileutils , only : getfil ! ! !ARGUMENTS: implicit none include 'netcdf.inc' type(latlon_type) ,intent(inout) :: latlon ! domain to init character(len=*) ,intent(in) :: filename ! grid filename integer,pointer ,optional :: mask(:) character(len=*) ,optional,intent(in) :: mfilename ! grid filename logical ,optional,intent(in) :: pftmflag ! is mask pft mask? ! ! !CALLED FROM: ! subroutine surfrd in this module ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein ! ! ! !LOCAL VARIABLES: !EOP integer :: ni,nj ! size of grid on file integer :: n ! index integer :: ncid,dimid,varid ! netCDF id's integer :: ncidm ! mask file netCDF id's integer :: ier ! error status character(len=256) :: locfn ! local file name integer :: ret, time_index real(r8),pointer :: rdata(:,:) ! temporary data logical :: NSEWset ! true if lat/lon NSEW read from grid file logical :: EDGEset ! true if EDGE NSEW read from grid file logical :: lpftmflag ! is mask a pft mask, local copy logical :: readv ! read variable in or not character(len=32) :: subname = 'surfrd_get_latlon' ! subroutine name !----------------------------------------------------------------------- NSEWset = .false. EDGEset = .false. lpftmflag = .false. ni = 0 nj = 0 if (present(pftmflag)) then lpftmflag = pftmflag endif if (masterproc) then if (filename == ' ') then write(iulog,*) trim(subname),' ERROR: filename must be specified ' call endrun() endif call getfil( filename, locfn, 0 ) call check_ret( nf_open(locfn, 0, ncid), subname ) if (single_column) then ni = lsmlon nj = lsmlat else ier = nf_inq_dimid (ncid, 'lon', dimid) if (ier == NF_NOERR) then call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname) endif ier = nf_inq_dimid (ncid, 'lat', dimid) if (ier == NF_NOERR) then call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname) endif ier = nf_inq_dimid (ncid, 'lsmlon', dimid) if (ier == NF_NOERR) then call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname) endif ier = nf_inq_dimid (ncid, 'lsmlat', dimid) if (ier == NF_NOERR) then call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname) endif endif if (ni == 0 .or. nj == 0) then write(iulog,*) trim(subname),' ERROR: ni or nj not set',ni,nj call endrun() endif endif call mpi_bcast (ni, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (nj, 1, MPI_INTEGER, 0, mpicom, ier) call latlon_init(latlon,ni,nj) if (present(mask)) then allocate(mask(ni*nj)) mask = 1 endif if (masterproc) then allocate(rdata(ni,nj)) call ncd_ioglobal('LONGXY',rdata,'read',ncid,readvar=readv) if ( .not. readv ) call endrun( trim(subname)//' ERROR: LONGXY NOT on file' ) latlon%lonc(:) = rdata(:,1) call ncd_ioglobal('LATIXY',rdata,'read',ncid,readvar=readv) if ( .not. readv ) call endrun( trim(subname)//' ERROR: LONGXY NOT on file' ) latlon%latc(:) = rdata(1,:) if (single_column) then EDGEset = .true. latlon%edges(1) = 90.0_r8 latlon%edges(2) = latlon%lonc(1) + 180._r8 latlon%edges(3) = -90.0_r8 latlon%edges(4) = latlon%lonc(1) - 180._r8 else latlon%edges(:) = spval ier = nf_inq_varid (ncid, 'EDGEN', varid) if (ier == NF_NOERR) then EDGEset = .true. call ncd_ioglobal('EDGEN',latlon%edges(1),'read',ncid,readvar=readv) call ncd_ioglobal('EDGEE',latlon%edges(2),'read',ncid,readvar=readv) call ncd_ioglobal('EDGES',latlon%edges(3),'read',ncid,readvar=readv) call ncd_ioglobal('EDGEW',latlon%edges(4),'read',ncid,readvar=readv) if (maxval(latlon%edges) > 1.0e35) EDGEset = .false. !read garbage endif endif ier = nf_inq_varid (ncid, 'LATN', varid) if (ier == NF_NOERR) then NSEWset = .true. call ncd_ioglobal('LATN',rdata,'read',ncid) latlon%latn(:) = rdata(1,:) call ncd_ioglobal('LONE',rdata,'read',ncid) latlon%lone(:) = rdata(:,1) call ncd_ioglobal('LATS',rdata,'read',ncid) latlon%lats(:) = rdata(1,:) call ncd_ioglobal('LONW',rdata,'read',ncid) latlon%lonw(:) = rdata(:,1) endif if (present(mask)) then if (present(mfilename)) then if (mfilename == ' ') then write(iulog,*) trim(subname),' ERROR: mfilename must be specified ' call endrun() endif call getfil( mfilename, locfn, 0 ) call check_ret( nf_open(locfn, 0, ncidm), subname ) else ncidm = ncid endif mask = 1 ier = nf_inq_varid(ncidm, 'LANDMASK', varid) if (ier == NF_NOERR) then call ncd_ioglobal('LANDMASK',mask,'read',ncidm) endif !--- if this is a pft mask, then modify and look for pftdata_mask array on dataset --- if (lpftmflag) then do n = 1,ni*nj if (mask(n) <= 0) mask(n) = -1 enddo ier = nf_inq_varid (ncidm, 'PFTDATA_MASK', varid) if (ier == NF_NOERR) then call ncd_ioglobal('PFTDATA_MASK',mask,'read',ncidm) endif endif if (present(mfilename)) then call check_ret(nf_close(ncidm), subname) endif endif deallocate(rdata) !tcx fix, this or a test/abort should be added so overlaps can be computed !tcx fix, this is demonstrated not bfb in cam bl311 test. !tcx fix, see also lat_o_local in areaMod.F90 #if (defined TCX_REMOVE_SEE_NOTES_ABOVE) ! Check lat limited to -90,90 if (minval(latlon%latc) < -90.0_r8 .or. & maxval(latlon%latc) > 90.0_r8) then write(iulog,*) trim(subname),' Limiting lat/lon to [-90/90] from ', & minval(latlon%latc),maxval(latlon%latc) where (latlon%latc < -90.0_r8) latlon%latc = -90.0_r8 where (latlon%latc > 90.0_r8) latlon%latc = 90.0_r8 endif #endif call check_ret(nf_close(ncid), subname) end if ! end of if-masterproc block call mpi_bcast (latlon%latc , size(latlon%latc) , MPI_REAL8 , 0, mpicom, ier) call mpi_bcast (latlon%lonc , size(latlon%lonc) , MPI_REAL8 , 0, mpicom, ier) call mpi_bcast (latlon%lats , size(latlon%lats) , MPI_REAL8 , 0, mpicom, ier) call mpi_bcast (latlon%latn , size(latlon%latn) , MPI_REAL8 , 0, mpicom, ier) call mpi_bcast (latlon%lonw , size(latlon%lonw) , MPI_REAL8 , 0, mpicom, ier) call mpi_bcast (latlon%lone , size(latlon%lone) , MPI_REAL8 , 0, mpicom, ier) call mpi_bcast (latlon%edges, size(latlon%edges), MPI_REAL8 , 0, mpicom, ier) if (present(mask)) then call mpi_bcast(mask , size(mask) , MPI_INTEGER, 0, mpicom, ier) endif end subroutine surfrd_get_latlon !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_get_frac ! ! !INTERFACE: subroutine surfrd_get_frac(domain,filename,glcfilename) 2,26 ! ! !DESCRIPTION: ! Read the landfrac dataset grid related information: ! Assume domain has already been initialized and read ! ! !USES: use domainMod , only : domain_type use fileutils , only : getfil ! ! !ARGUMENTS: implicit none include 'netcdf.inc' type(domain_type),intent(inout) :: domain ! domain to init character(len=*) ,intent(in) :: filename ! grid filename character(len=*) ,optional, intent(in) :: glcfilename ! glc mask filename ! ! !CALLED FROM: ! subroutine initialize ! ! !REVISION HISTORY: ! Created by T Craig ! ! ! !LOCAL VARIABLES: !EOP integer :: n ! indices integer :: ni,nj,ns ! size of grid on file integer :: ncid,dimid,varid ! netCDF id's integer :: ncidg ! netCDF id for glcmask integer :: ier ! error status real(r8):: eps = 1.0e-12_r8 ! lat/lon error tolerance integer :: beg,end ! local beg,end indices character(len=8) :: clmlevel ! grid type real(r8),pointer :: lonc(:),latc(:) ! local lat/lon character(len=256) :: locfn ! local file name integer :: ret, time_index character(len=32) :: subname = 'surfrd_get_frac' ! subroutine name !----------------------------------------------------------------------- if (masterproc) then if (filename == ' ') then write(iulog,*) trim(subname),' ERROR: filename must be specified ' call endrun() endif call getfil( filename, locfn, 0 ) call check_ret( nf_open(locfn, 0, ncid), subname ) if (single_column) then ni = lsmlon nj = lsmlat else call check_ret(nf_inq_dimid (ncid, 'lsmlon', dimid), subname) call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname) call check_ret(nf_inq_dimid (ncid, 'lsmlat', dimid), subname) call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname) endif ns = ni*nj if (domain%ni /= ni .or. domain%nj /= nj .or. domain%ns /= ns) then write(iulog,*) trim(subname),' ERROR: landfrac file mismatch ni,nj',domain%ni,ni,domain%nj,nj,domain%ns,ns call endrun() endif endif ni = domain%ni nj = domain%nj beg = domain%nbeg end = domain%nend clmlevel = domain%clmlevel allocate(latc(beg:end),lonc(beg:end)) call ncd_iolocal(ncid, 'LONGXY', 'read', lonc, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY NOT on fracdata file' ) call ncd_iolocal(ncid, 'LATIXY', 'read', latc, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LATIXY NOT on fracdata file' ) do n = beg,end if (abs(latc(n)-domain%latc(n)) > eps .or. & abs(lonc(n)-domain%lonc(n)) > eps) then write(iulog,*) trim(subname),' ERROR: landfrac file mismatch lat,lon',latc(n),domain%latc(n),lonc(n),domain%lonc(n),eps call endrun() endif enddo call ncd_iolocal(ncid, 'LANDMASK', 'read', domain%mask, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LANDMASK NOT on fracdata file' ) call ncd_iolocal(ncid, 'LANDFRAC', 'read', domain%frac, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LANDFRAC NOT on fracdata file' ) deallocate(latc,lonc) if (masterproc) call check_ret(nf_close(ncid), subname) if (present(glcfilename)) then if (masterproc) then if (glcfilename == ' ') then write(iulog,*) trim(subname),' ERROR: glc filename must be specified ' call endrun() endif call getfil( glcfilename, locfn, 0 ) call check_ret( nf_open(locfn, 0, ncidg), subname ) endif ! masterproc domain%glcmask = 0 call ncd_iolocal(ncid, 'GLCMASK', 'read', domain%glcmask, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: GLCMASK NOT in file' ) if (masterproc) call check_ret(nf_close(ncidg), subname) endif ! present(glcfilename) end subroutine surfrd_get_frac !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_get_topo ! ! !INTERFACE: subroutine surfrd_get_topo(domain,filename) 2,18 ! ! !DESCRIPTION: ! Read the topo dataset grid related information: ! Assume domain has already been initialized and read ! ! !USES: use domainMod , only : domain_type use fileutils , only : getfil ! ! !ARGUMENTS: implicit none include 'netcdf.inc' type(domain_type),intent(inout) :: domain ! domain to init character(len=*) ,intent(in) :: filename ! grid filename ! ! !CALLED FROM: ! subroutine initialize ! ! !REVISION HISTORY: ! Created by T Craig ! ! ! !LOCAL VARIABLES: !EOP integer :: n ! indices integer :: ni,nj,ns ! size of grid on file integer :: ncid,dimid,varid ! netCDF id's integer :: ier ! error status real(r8):: eps = 1.0e-12_r8 ! lat/lon error tolerance integer :: beg,end ! local beg,end indices character(len=8) :: clmlevel ! grid type real(r8),pointer :: lonc(:),latc(:) ! local lat/lon character(len=256) :: locfn ! local file name integer :: ret, time_index character(len=32) :: subname = 'surfrd_get_topo' ! subroutine name !----------------------------------------------------------------------- if (masterproc) then if (filename == ' ') then write(iulog,*) trim(subname),' ERROR: filename must be specified ' call endrun() endif call getfil( filename, locfn, 0 ) call check_ret( nf_open(locfn, 0, ncid), subname ) if (single_column) then ni = lsmlon nj = lsmlat else call check_ret(nf_inq_dimid (ncid, 'lsmlon', dimid), subname) call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname) call check_ret(nf_inq_dimid (ncid, 'lsmlat', dimid), subname) call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname) endif ns = ni*nj if (domain%ni /= ni .or. domain%nj /= nj .or. domain%ns /= ns) then write(iulog,*) trim(subname),' ERROR: topo file mismatch ni,nj',domain%ni,ni,domain%nj,nj,domain%ns,ns call endrun() endif endif ni = domain%ni nj = domain%nj beg = domain%nbeg end = domain%nend clmlevel = domain%clmlevel allocate(latc(beg:end),lonc(beg:end)) call ncd_iolocal(ncid, 'LONGXY', 'read', lonc, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY NOT on topodata file' ) call ncd_iolocal(ncid, 'LATIXY', 'read', latc, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY NOT on topodata file' ) do n = beg,end if (abs(latc(n)-domain%latc(n)) > eps .or. & abs(lonc(n)-domain%lonc(n)) > eps) then write(iulog,*) trim(subname),' ERROR: topo file mismatch lat,lon',latc(n),domain%latc(n),lonc(n),domain%lonc(n),eps call endrun() endif enddo call ncd_iolocal(ncid, 'TOPO', 'read', domain%topo, clmlevel, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY NOT on topodata file' ) deallocate(latc,lonc) if (masterproc) call check_ret(nf_close(ncid), subname) end subroutine surfrd_get_topo !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_wtxy_special ! ! !INTERFACE: ! subroutine surfrd_wtxy_special(ncid, pctspec, vegxy, wtxy, domain) subroutine surfrd_wtxy_special(ncid, domain) 1,25 ! ! !DESCRIPTION: ! Determine weight with respect to gridcell of all special "pfts" as well ! as soil color and percent sand and clay ! ! !USES: use pftvarcon , only : noveg use UrbanInputMod , only : urbinp use domainMod , only : domain_type use clm_varctl , only : glc_nec, glc_topomax ! ! !ARGUMENTS: implicit none include 'netcdf.inc' integer , intent(in) :: ncid ! netcdf file id ! real(r8), intent(inout) :: pctspec(:)! percent wrt gcell special lunits ! integer , intent(inout) :: vegxy(:,:) ! PFT ! real(r8), intent(inout) :: wtxy(:,:) ! subgrid weights type(domain_type),intent(in) :: domain ! domain associated with wtxy ! ! !CALLED FROM: ! subroutine surfrd in this module ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan ! ! ! !LOCAL VARIABLES: !EOP integer :: n,nl,ns,nurb,g ! indices integer :: begg,endg ! gcell beg/end integer :: dimid,varid ! netCDF id's integer :: ret real(r8) :: nlevsoidata(nlevsoi) logical :: found ! temporary for error check integer :: nindx ! temporary for error check integer :: ier ! error status integer :: nlev ! level integer :: npatch real(r8),pointer :: pctgla(:) ! percent of grid cell is glacier real(r8),pointer :: pctlak(:) ! percent of grid cell is lake real(r8),pointer :: pctwet(:) ! percent of grid cell is wetland real(r8),pointer :: pcturb(:) ! percent of grid cell is urbanized real(r8),pointer :: pctglc_mec(:,:) ! percent of grid cell is glacier_mec (in each elev class) real(r8),pointer :: pctglc_mec_tot(:) ! percent of grid cell is glacier (sum over classes) real(r8),pointer :: topoglc_mec(:,:) ! surface elevation in each elev class logical :: readv ! read variable in or not character(len=32) :: subname = 'surfrd_wtxy_special' ! subroutine name real(r8) closelat,closelon !!----------------------------------------------------------------------- ns = domain%ns call get_proc_bounds(begg,endg) allocate(pctgla(begg:endg),pctlak(begg:endg)) allocate(pctwet(begg:endg),pcturb(begg:endg)) if (create_glacier_mec_landunit) then allocate(pctglc_mec(begg:endg,glc_nec)) allocate(pctglc_mec_tot(begg:endg)) allocate(topoglc_mec(begg:endg,glc_nec)) endif if (masterproc) then call check_dim(ncid, 'nlevsoi', nlevsoi) end if ! end of if-masterproc ! Obtain non-grid surface properties of surface dataset other than percent pft call ncd_iolocal(ncid, 'PCT_WETLAND', 'read', pctwet, grlnd, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_WETLAND NOT on surfdata file' ) call ncd_iolocal(ncid, 'PCT_LAKE' , 'read', pctlak, grlnd, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_LAKE NOT on surfdata file' ) call ncd_iolocal(ncid, 'PCT_GLACIER', 'read', pctgla, grlnd, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_GLACIER NOT on surfdata file' ) call ncd_iolocal(ncid, 'PCT_URBAN' , 'read', pcturb, grlnd, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_URBAN NOT on surfdata file' ) if (create_glacier_mec_landunit) then ! call ncd_iolocal_gs_int2d call check_dim(ncid, 'nglcec', glc_nec ) call check_dim(ncid, 'nglcecp1', glc_nec+1 ) call ncd_ioglobal('GLC_MEC', glc_topomax, 'read', ncid, readvar=readv, bcast=.true.) if ( .not. readv) call endrun( trim(subname)//'ERROR: GLC_MEC was NOT on the input surfdata file' ) call ncd_iolocal(ncid, 'PCT_GLC_MEC', 'read', pctglc_mec, grlnd, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_GLC_MEC NOT on surfdata file' ) call ncd_iolocal(ncid, 'TOPO_GLC_MEC', 'read', topoglc_mec, grlnd, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: TOPO_GLC_MEC NOT on surfdata file' ) pctglc_mec_tot(:) = 0._r8 do n = 1, glc_nec do nl = begg,endg pctglc_mec_tot(nl) = pctglc_mec_tot(nl) + pctglc_mec(nl,n) enddo enddo ! Make sure sum of pctglc_mec = pctgla, then zero out pctgla ! (assumes glc_mec values are double precision) do nl = begg,endg if (abs(pctgla(nl) - pctglc_mec_tot(nl)) > 1.0e-11) then write(iulog,*) ' ' write(iulog,*) 'surfrd error: pctgla not equal to sum of pctglc_mec for nl=', nl write(iulog,*) 'pctgla =', pctgla(nl) write(iulog,*) 'pctglc_mec_tot =', pctglc_mec_tot(nl) call endrun() endif pctgla(nl) = 0._r8 enddo ! If pctglc_mec_tot is very close to 100%, round to 100% do nl = begg,endg if (abs(pctglc_mec_tot(nl) - 100._r8) < 1.0e-8) then pctglc_mec(nl,:) = pctglc_mec(nl,:) * 100._r8 / pctglc_mec_tot(nl) pctglc_mec_tot(nl) = 100._r8 endif enddo pctspec = pctwet + pctlak + pcturb + pctglc_mec_tot if ( masterproc ) write(iulog,*) ' elevation limits = ', glc_topomax else pctspec = pctwet + pctlak + pcturb + pctgla endif ! Error check: glacier, lake, wetland, urban sum must be less than 100 found = .false. do nl = begg,endg if (pctspec(nl) > 100._r8+1.e-04_r8) then found = .true. nindx = nl exit end if if (found) exit end do if ( found ) then write(iulog,*)'surfrd error: PFT cover>100 for nl=',nindx call endrun() end if ! Determine veg and wtxy for special landunits do nl = begg,endg vegxy(nl,npatch_lake) = noveg wtxy(nl,npatch_lake) = pctlak(nl)/100._r8 vegxy(nl,npatch_wet) = noveg wtxy(nl,npatch_wet) = pctwet(nl)/100._r8 vegxy(nl,npatch_glacier)= noveg wtxy(nl,npatch_glacier) = pctgla(nl)/100._r8 ! Initialize urban weights do nurb = npatch_urban, npatch_lake-1 vegxy(nl,nurb) = noveg wtxy(nl,nurb) = pcturb(nl) / 100._r8 end do if ( pcturb(nl) > 0.0_r8 )then wtxy(nl,npatch_urban) = wtxy(nl,npatch_urban)*urbinp%wtlunit_roof(nl) wtxy(nl,npatch_urban+1) = wtxy(nl,npatch_urban+1)*(1 - urbinp%wtlunit_roof(nl))/3 wtxy(nl,npatch_urban+2) = wtxy(nl,npatch_urban+2)*(1 - urbinp%wtlunit_roof(nl))/3 wtxy(nl,npatch_urban+3) = wtxy(nl,npatch_urban+3)*(1 - urbinp%wtlunit_roof(nl))/3 * (1.-urbinp%wtroad_perv(nl)) wtxy(nl,npatch_urban+4) = wtxy(nl,npatch_urban+4)*(1 - urbinp%wtlunit_roof(nl))/3 * urbinp%wtroad_perv(nl) end if end do ! Check to make sure we have valid urban data for each urban patch found = .false. do nl = begg,endg if ( pcturb(nl) > 0.0_r8 )then if (urbinp%canyon_hwr(nl) .le. 0._r8 .or. & urbinp%em_improad(nl) .le. 0._r8 .or. & urbinp%em_perroad(nl) .le. 0._r8 .or. & urbinp%em_roof(nl) .le. 0._r8 .or. & urbinp%em_wall(nl) .le. 0._r8 .or. & urbinp%ht_roof(nl) .le. 0._r8 .or. & urbinp%thick_roof(nl) .le. 0._r8 .or. & urbinp%thick_wall(nl) .le. 0._r8 .or. & urbinp%t_building_max(nl) .le. 0._r8 .or. & urbinp%t_building_min(nl) .le. 0._r8 .or. & urbinp%wind_hgt_canyon(nl) .le. 0._r8 .or. & urbinp%wtlunit_roof(nl) .le. 0._r8 .or. & urbinp%wtroad_perv(nl) .le. 0._r8 .or. & any(urbinp%alb_improad_dir(nl,:) .le. 0._r8) .or. & any(urbinp%alb_improad_dif(nl,:) .le. 0._r8) .or. & any(urbinp%alb_perroad_dir(nl,:) .le. 0._r8) .or. & any(urbinp%alb_perroad_dif(nl,:) .le. 0._r8) .or. & any(urbinp%alb_roof_dir(nl,:) .le. 0._r8) .or. & any(urbinp%alb_roof_dif(nl,:) .le. 0._r8) .or. & any(urbinp%alb_wall_dir(nl,:) .le. 0._r8) .or. & any(urbinp%alb_wall_dif(nl,:) .le. 0._r8) .or. & any(urbinp%tk_roof(nl,:) .le. 0._r8) .or. & any(urbinp%tk_wall(nl,:) .le. 0._r8) .or. & any(urbinp%cv_roof(nl,:) .le. 0._r8) .or. & any(urbinp%cv_wall(nl,:) .le. 0._r8)) then found = .true. nindx = nl exit else if (urbinp%nlev_improad(nl) .gt. 0) then nlev = urbinp%nlev_improad(nl) if (any(urbinp%tk_improad(nl,1:nlev) .le. 0._r8) .or. & any(urbinp%cv_improad(nl,1:nlev) .le. 0._r8)) then found = .true. nindx = nl exit end if end if end if if (found) exit end if end do if ( found ) then write(iulog,*)'surfrd error: no valid urban data for nl=',nindx write(iulog,*)'canyon_hwr: ',urbinp%canyon_hwr(nindx) write(iulog,*)'em_improad: ',urbinp%em_improad(nindx) write(iulog,*)'em_perroad: ',urbinp%em_perroad(nindx) write(iulog,*)'em_roof: ',urbinp%em_roof(nindx) write(iulog,*)'em_wall: ',urbinp%em_wall(nindx) write(iulog,*)'ht_roof: ',urbinp%ht_roof(nindx) write(iulog,*)'thick_roof: ',urbinp%thick_roof(nindx) write(iulog,*)'thick_wall: ',urbinp%thick_wall(nindx) write(iulog,*)'t_building_max: ',urbinp%t_building_max(nindx) write(iulog,*)'t_building_min: ',urbinp%t_building_min(nindx) write(iulog,*)'wind_hgt_canyon: ',urbinp%wind_hgt_canyon(nindx) write(iulog,*)'wtlunit_roof: ',urbinp%wtlunit_roof(nindx) write(iulog,*)'wtroad_perv: ',urbinp%wtroad_perv(nindx) write(iulog,*)'alb_improad_dir: ',urbinp%alb_improad_dir(nindx,:) write(iulog,*)'alb_improad_dif: ',urbinp%alb_improad_dif(nindx,:) write(iulog,*)'alb_perroad_dir: ',urbinp%alb_perroad_dir(nindx,:) write(iulog,*)'alb_perroad_dif: ',urbinp%alb_perroad_dif(nindx,:) write(iulog,*)'alb_roof_dir: ',urbinp%alb_roof_dir(nindx,:) write(iulog,*)'alb_roof_dif: ',urbinp%alb_roof_dif(nindx,:) write(iulog,*)'alb_wall_dir: ',urbinp%alb_wall_dir(nindx,:) write(iulog,*)'alb_wall_dif: ',urbinp%alb_wall_dif(nindx,:) write(iulog,*)'tk_roof: ',urbinp%tk_roof(nindx,:) write(iulog,*)'tk_wall: ',urbinp%tk_wall(nindx,:) write(iulog,*)'cv_roof: ',urbinp%cv_roof(nindx,:) write(iulog,*)'cv_wall: ',urbinp%cv_wall(nindx,:) if (urbinp%nlev_improad(nindx) .gt. 0) then nlev = urbinp%nlev_improad(nindx) write(iulog,*)'tk_improad: ',urbinp%tk_improad(nindx,1:nlev) write(iulog,*)'cv_improad: ',urbinp%cv_improad(nindx,1:nlev) end if call endrun() end if ! Initialize glacier_mec weights if (create_glacier_mec_landunit) then do n = 1, glc_nec npatch = npatch_glacier_mec - glc_nec + n do nl = begg, endg vegxy (nl,npatch) = noveg wtxy (nl,npatch) = pctglc_mec(nl,n)/100._r8 topoxy(nl,npatch) = topoglc_mec(nl,n) enddo ! nl enddo ! glc_nec deallocate(pctglc_mec, pctglc_mec_tot, topoglc_mec) endif ! create_glacier_mec_landunit deallocate(pctgla,pctlak,pctwet,pcturb) end subroutine surfrd_wtxy_special !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_wtxy_veg_rank ! ! !INTERFACE: ! subroutine surfrd_wtxy_veg_rank(ncid, pctspec, vegxy, wtxy, domain) subroutine surfrd_wtxy_veg_rank(ncid, domain) 1,16 ! ! !DESCRIPTION: ! Determine wtxy and veg arrays for non-dynamic landuse mode ! ! !USES: use clm_varctl, only : create_crop_landunit use pftvarcon , only : crop, noveg use domainMod , only : domain_type ! ! !ARGUMENTS: implicit none include 'netcdf.inc' integer , intent(in) :: ncid ! netcdf file id ! real(r8), intent(in) :: pctspec(:) ! percent wrt gcell of spec lunits ! integer , intent(inout) :: vegxy(:,:) ! PFT ! real(r8), intent(inout) :: wtxy(:,:) ! subgrid weights type(domain_type),intent(in) :: domain ! domain associated with wtxy ! ! !CALLED FROM: ! subroutine surfrd in this module ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan ! ! ! !LOCAL VARIABLES: !EOP integer :: k,m,k1,k2,n,nl,ns ! indices integer :: begg,endg ! beg/end gcell index integer :: dimid,varid ! netCDF id's integer :: start(3),count(3) ! netCDF start/count arrays integer :: cropcount ! temporary counter real(r8),allocatable :: sumvec(:) ! temporary vector sum logical :: found ! temporary for error check integer :: nindx ! temporary for error check integer :: miss = 99999 ! missing data indicator real(r8) :: wst(0:numpft) ! as pft at specific i, j integer ,allocatable :: wsti(:) ! ranked indices largest wst values real(r8) :: wst_sum ! sum of %pft real(r8) :: sumpct ! sum of %pft over maxpatch_pft real(r8) :: diff ! the difference (wst_sum - sumpct) real(r8) :: rmax ! maximum patch cover integer ,allocatable :: pft(:,:) ! PFT integer ,allocatable :: cft(:,:) ! CFT real(r8),allocatable :: pctcft_lunit(:,:) ! % of crop lunit area for CFTs real(r8),allocatable :: pctpft_lunit(:,:) ! % of vegetated lunit area PFTs integer :: ier ! error status real(r8),allocatable :: pctpft(:,:) ! percent of vegetated gridcell area for PFTs real(r8),pointer :: arrayl(:) ! local array integer ,pointer :: irrayg(:) ! global array integer :: ret real(r8),allocatable :: rmaxpatchdata(:) integer ,allocatable :: imaxpatchdata(:) real(r8) :: numpftp1data(0:numpft) character(len=32) :: subname = 'surfrd_wtxy_veg_rank' ! subroutine name !----------------------------------------------------------------------- ns = domain%ns call get_proc_bounds(begg,endg) allocate(sumvec(begg:endg)) allocate(cft(begg:endg,numcft)) allocate(pft(begg:endg,maxpatch_pft)) allocate(pctcft_lunit(begg:endg,numcft)) allocate(pctpft_lunit(begg:endg,maxpatch_pft)) allocate(pctpft(begg:endg,0:numpft)) allocate(wsti(maxpatch_pft)) if (masterproc) then call check_dim(ncid, 'lsmpft', numpft+1) end if allocate(arrayl(begg:endg)) do n = 0,numpft start(1) = 1 count(1) = domain%ni start(2) = 1 count(2) = domain%nj start(3) = n+1 ! dataset is 1:numpft+1, not 0:numpft count(3) = 1 call ncd_iolocal(ncid, 'PCT_PFT', 'read', arrayl, grlnd, start, count, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_PFT NOT on surfdata file' ) pctpft(begg:endg,n) = arrayl(begg:endg) enddo deallocate(arrayl) ! 1. pctpft must go back to %vegetated landunit instead of %gridcell ! 2. pctpft bare = 100 when landmask = 1 and 100% special landunit ! NB: (1) and (2) do not apply to crops. ! For now keep all cfts instead of most dominant cfts do nl = begg,endg cft(nl,:) = 0 pctcft_lunit(nl,:) = 0._r8 cropcount = 0 if (pctspec(nl) < 100._r8) then do m = 0, numpft if (create_crop_landunit) then ! Separate crop landunit is to be created if (crop(m) == 1._r8 .and. pctpft(nl,m) > 0._r8) then cropcount = cropcount + 1 if (cropcount > numcft) then write(iulog,*) 'ERROR surfrdMod: cropcount>numcft' call endrun() end if cft(nl,cropcount) = m pctcft_lunit(nl,cropcount) = pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl)) pctpft(nl,m) = 0.0_r8 else if (crop(m) == 0._r8) then pctpft(nl,m) = pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl)) end if else ! Separate crop landunit is not created pctpft(nl,m) = pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl)) end if end do else if (pctspec(nl) == 100._r8) then pctpft(nl,0) = 100._r8 pctpft(nl,1:numpft) = 0._r8 else write(iulog,*)subname, 'error: pcturb+pctgla+pctlak+pctwet = ',pctspec(nl), & ' must be less than or equal to 100' call endrun() end if end do ! Find pft and pct arrays ! Save percent cover by PFT [wst] and total percent cover [wst_sum] do nl = begg,endg wst_sum = 0._r8 sumpct = 0 do m = 0, numpft wst(m) = pctpft(nl,m) wst_sum = wst_sum + pctpft(nl,m) end do if (domain%pftm(nl) >= 0) then ! Rank [wst] in ascendg order to obtain the top [maxpatch_pft] PFTs call surfrd_mkrank (numpft, wst, miss, wsti, maxpatch_pft) ! Fill in [pft] and [pctpft] with data for top [maxpatch_pft] PFTs. ! If land model grid cell is ocean, set to no PFTs. ! If land model grid cell is land then: ! 1. If [pctlnd_o] = 0, there is no PFT data from the input grid. ! Since need land data, use bare ground. ! 2. If [pctlnd_o] > 0, there is PFT data from the input grid but: ! a. use the chosen PFT so long as it is not a missing value ! b. missing value means no more PFTs with cover > 0 do m = 1, maxpatch_pft if (wsti(m) /= miss) then pft(nl,m) = wsti(m) pctpft_lunit(nl,m) = wst(wsti(m)) else pft(nl,m) = noveg pctpft_lunit(nl,m) = 0._r8 end if sumpct = sumpct + pctpft_lunit(nl,m) end do else ! model grid wants ocean do m = 1, maxpatch_pft pft(nl,m) = 0 pctpft_lunit(nl,m) = 0._r8 end do end if ! Correct for the case of more than [maxpatch_pft] PFTs present if (sumpct < wst_sum) then diff = wst_sum - sumpct sumpct = 0._r8 do m = 1, maxpatch_pft pctpft_lunit(nl,m) = pctpft_lunit(nl,m) + diff/maxpatch_pft sumpct = sumpct + pctpft_lunit(nl,m) end do end if ! Error check: make sure have a valid PFT do m = 1,maxpatch_pft if (pft(nl,m) < 0 .or. pft(nl,m) > numpft) then write(iulog,*)'surfrd error: invalid PFT at gridcell nl=',nl,pft(nl,m) call endrun() end if end do ! As done in mksrfdatMod.F90 for other percentages, truncate pctpft to ! ensure that weight relative to landunit is not nonzero ! (i.e. a very small number such as 1e-16) where it really should be zero ! The following if-block is here to preserve roundoff level differences ! between the call to surfrd_wtxy_veg_all and surfrd_wtxy_veg_rank if (maxpatch_pft < numpft+1) then do m=1,maxpatch_pft pctpft_lunit(nl,m) = float(nint(pctpft_lunit(nl,m))) end do do m=1,numcft pctcft_lunit(nl,m) = float(nint(pctcft_lunit(nl,m))) end do end if ! Make sure sum of PFT cover == 100 for land points. If not, ! subtract excess from most dominant PFT. rmax = -9999._r8 k1 = -9999 k2 = -9999 sumpct = 0._r8 do m = 1, maxpatch_pft sumpct = sumpct + pctpft_lunit(nl,m) if (pctpft_lunit(nl,m) > rmax) then k1 = m rmax = pctpft_lunit(nl,m) end if end do do m = 1, numcft sumpct = sumpct + pctcft_lunit(nl,m) if (pctcft_lunit(nl,m) > rmax) then k2 = m rmax = pctcft_lunit(nl,m) end if end do if (k1 == -9999 .and. k2 == -9999) then write(iulog,*)'surfrd error: largest PFT patch not found' call endrun() else if (domain%pftm(nl) >= 0) then if (sumpct < 95 .or. sumpct > 105._r8) then write(iulog,*)'surfrd error: sum of PFT cover =',sumpct,' at nl=',nl call endrun() else if (sumpct /= 100._r8 .and. k2 /= -9999) then pctcft_lunit(nl,k2) = pctcft_lunit(nl,k2) - (sumpct-100._r8) else if (sumpct /= 100._r8) then pctpft_lunit(nl,k1) = pctpft_lunit(nl,k1) - (sumpct-100._r8) end if end if ! Error check: make sure PFTs sum to 100% cover sumpct = 0._r8 do m = 1, maxpatch_pft sumpct = sumpct + pctpft_lunit(nl,m) end do do m = 1, numcft sumpct = sumpct + pctcft_lunit(nl,m) end do if (domain%pftm(nl) >= 0) then if (abs(sumpct - 100._r8) > 0.000001_r8) then write(iulog,*)'surfrdMod error: sum(pct) over maxpatch_pft is not = 100.' write(iulog,*)sumpct, nl call endrun() end if if (sumpct < -0.000001_r8) then write(iulog,*)'surfrdMod error: sum(pct) over maxpatch_pft is < 0.' write(iulog,*)sumpct, nl call endrun() end if end if end do ! end of latitude loop ! Determine array [veg], which sets the PFT type for each of the [maxpatch] ! patches and array [wtxy], which sets the relative abundance of the PFT. ! Fill in PFTs for vegetated portion of grid cell. Fractional areas for ! these points [pctpft] pertain to "vegetated" area not to total grid area. ! So need to adjust them for fraction of grid that is vegetated. ! Next, fill in urban, lake, wetland, and glacier patches. do nl = begg,endg if (domain%pftm(nl) >= 0) then ! Naturally vegetated landunit do m = 1, maxpatch_pft vegxy(nl,m) = pft(nl,m) wtxy(nl,m) = pctpft_lunit(nl,m) * (100._r8-pctspec(nl))/10000._r8 end do ! Crop landunit if (create_crop_landunit) then do m = 1,numcft vegxy(nl,npatch_glacier_mec+m) = cft(nl,m) wtxy(nl,npatch_glacier_mec+m) = pctcft_lunit(nl,m) * (100._r8-pctspec(nl))/10000._r8 end do end if end if end do ! Error check found = .false. sumvec(:) = abs(sum(wtxy,dim=2)-1._r8) do nl = begg,endg if (sumvec(nl) > 1.e-06_r8 .and. domain%pftm(nl)>=0) then found = .true. nindx = nl exit endif end do if ( found ) then write(iulog,*)'surfrd error: WTXY > 1 occurs at nl= ',nindx; call endrun() end if deallocate(sumvec,cft,pft) deallocate(pctcft_lunit,pctpft_lunit,pctpft) deallocate(wsti) end subroutine surfrd_wtxy_veg_rank !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_wtxy_veg_all ! ! !INTERFACE: ! subroutine surfrd_wtxy_veg_all(ncid, pctspec, vegxy, wtxy, domain) subroutine surfrd_wtxy_veg_all(ncid, domain) 2,7 ! ! !DESCRIPTION: ! Determine wtxy and veg arrays for non-dynamic landuse mode ! ! !USES: use domainMod , only : domain_type ! ! !ARGUMENTS: implicit none include 'netcdf.inc' integer , intent(in) :: ncid ! netcdf file id ! real(r8), intent(in) :: pctspec(:) ! percent wrt gcell of spec lunits ! integer , intent(inout) :: vegxy(:,:) ! PFT ! real(r8), intent(inout) :: wtxy(:,:) ! subgrid weights type(domain_type),intent(in) :: domain ! domain associated with wtxy ! ! !CALLED FROM: ! subroutine surfrd in this module ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan ! ! ! !LOCAL VARIABLES: !EOP integer :: m,mp7,mp8,mp11,n,nl,ns ! indices integer :: begg,endg ! beg/end gcell index integer :: dimid,varid ! netCDF id's integer :: start(3),count(3) ! netcdf start/count arrays integer :: ier ! error status real(r8) :: sumpct ! sum of %pft over maxpatch_pft real(r8),allocatable :: pctpft(:,:) ! percent of vegetated gridcell area for PFTs real(r8),pointer :: arrayl(:) ! local array integer :: ret real(r8) :: numpftp1data(0:numpft) character(len=32) :: subname = 'surfrd_wtxy_veg_all' ! subroutine name !----------------------------------------------------------------------- ns = domain%ns call get_proc_bounds(begg,endg) allocate(pctpft(begg:endg,0:numpft)) if (masterproc) then call check_dim(ncid, 'lsmpft', numpft+1) endif allocate(arrayl(begg:endg)) do n = 0,numpft start(1) = 1 count(1) = domain%ni start(2) = 1 count(2) = domain%nj start(3) = n+1 ! dataset is 1:numpft+1, not 0:numpft count(3) = 1 call ncd_iolocal(ncid, 'PCT_PFT', 'read', arrayl, grlnd, start, count, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_PFT NOT on surfdata file' ) pctpft(begg:endg,n) = arrayl(begg:endg) enddo deallocate(arrayl) do nl = begg,endg if (domain%pftm(nl) >= 0) then ! Error check: make sure PFTs sum to 100% cover for vegetated landunit ! (convert pctpft from percent with respect to gridcel to percent with ! respect to vegetated landunit) if (pctspec(nl) < 100._r8) then sumpct = 0._r8 do m = 0,numpft sumpct = sumpct + pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl)) end do if (abs(sumpct - 100._r8) > 0.1e-4_r8) then write(iulog,*)'surfrdMod error: sum(pct) over numpft+1 is not = 100.' write(iulog,*) sumpct, sumpct-100._r8, nl call endrun() end if if (sumpct < -0.000001_r8) then write(iulog,*)'surfrdMod error: sum(pct) over numpft+1 is < 0.' write(iulog,*) sumpct, nl call endrun() end if end if ! Set weight of each pft wrt gridcell (note that maxpatch_pft = numpft+1 here) do m = 1,numpft+1 vegxy(nl,m) = m - 1 ! 0 (bare ground) to numpft wtxy(nl,m) = pctpft(nl,m-1) / 100._r8 end do end if end do deallocate(pctpft) end subroutine surfrd_wtxy_veg_all !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: surfrd_wtxy_veg_dgvm ! ! !INTERFACE: subroutine surfrd_wtxy_veg_dgvm(domain) 1,5 ! ! !DESCRIPTION: ! Determine wtxy and vegxy for CNDV mode. ! ! !USES: use domainMod, only : domain_type use pftvarcon, only : noveg, crop use clm_varctl, only : create_crop_landunit ! ! !ARGUMENTS: implicit none type(domain_type),intent(in) :: domain ! domain associated with wtxy ! ! !CALLED FROM: ! subroutine surfrd in this module ! ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein 12/04 ! ! ! !LOCAL VARIABLES: !EOP integer :: m,nl ! indices integer :: begg,endg ! beg/end gcell index !----------------------------------------------------------------------- call get_proc_bounds(begg,endg) do nl = begg,endg do m = 1, maxpatch_pft ! CNDV means allocate_all_vegpfts = .true. if (create_crop_landunit) then ! been through surfrd_wtxy_veg_all if (crop(m-1) == 0) then ! so update natural vegetation only wtxy(nl,m) = 0._r8 ! crops should have values >= 0. end if else ! not been through surfrd_wtxy_veg_all wtxy(nl,m) = 0._r8 ! so update all vegetation vegxy(nl,m) = m - 1 ! 0 (bare ground) to maxpatch_pft-1 (= 16) end if end do ! bare ground weights wtxy(nl,noveg+1) = max(0._r8, 1._r8 - sum(wtxy(nl,:))) if (abs(sum(wtxy(nl,:)) - 1._r8) > 1.e-5_r8) then write(iulog,*) 'all wtxy =', wtxy(nl,:) call endrun() end if ! error check end do end subroutine surfrd_wtxy_veg_dgvm !----------------------------------------------------------------------- !BOP ! ! !ROUTINE: surfrd_mkrank ! ! !INTERFACE: subroutine surfrd_mkrank (n, a, miss, iv, num) 1,3 ! ! !DESCRIPTION: ! Return indices of largest [num] values in array [a] ! ! !USES: use shr_kind_mod, only: r8 => shr_kind_r8 use abortutils, only : endrun ! ! !ARGUMENTS: implicit none integer , intent(in) :: n ! array length real(r8), intent(in) :: a(0:n) ! array to be ranked integer , intent(in) :: miss ! missing data value integer , intent(in) :: num ! number of largest values requested integer , intent(out):: iv(num) ! index to [num] largest values in array [a] ! ! !CALLED FROM: ! ! subroutine surfrd_wtxy_veg_rank in this module ! ! !REVISION HISTORY: ! Author: Gordon Bonan ! ! ! !LOCAL VARIABLES: !EOP real(r8) :: a_max ! maximum value in array integer :: i ! array index real(r8) :: delmax ! tolerance for finding if larger value integer :: m ! do loop index integer :: k ! do loop index logical :: exclude ! true if data value has already been chosen !----------------------------------------------------------------------- delmax = 1.e-06_r8 ! Find index of largest non-zero number iv(1) = miss a_max = -9999._r8 do i = 0, n if (a(i)>0._r8 .and. (a(i)-a_max)>delmax) then a_max = a(i) iv(1) = i end if end do ! iv(1) = miss indicates no values > 0. this is an error if (iv(1) == miss) then write(iulog,*) 'surfrd_mkrank error: iv(1) = missing' call endrun end if ! Find indices of the next [num]-1 largest non-zero number. ! iv(m) = miss if there are no more values > 0 do m = 2, num iv(m) = miss a_max = -9999._r8 do i = 0, n ! exclude if data value has already been chosen exclude = .false. do k = 1, m-1 if (i == iv(k)) exclude = .true. end do ! if not already chosen, see if it is the largest of ! the remaining values if (.not. exclude) then if (a(i)>0._r8 .and. (a(i)-a_max)>delmax) then a_max = a(i) iv(m) = i end if end if end do end do end subroutine surfrd_mkrank end module surfrdMod