#define _FILE 'physics/cam1/boundarydata.F90 '
module boundarydata 2,8
use shr_kind_mod
, only: r8 => shr_kind_r8
use spmd_utils
, only: masterproc
use ppgrid
, only: pcols, pver, begchunk, endchunk
use physics_types
, only: physics_state
use abortutils
, only: endrun
#if ( defined SPMD )
use mpishorthand
, only: mpicom, mpir8, mpiint
#endif
use netcdf
use error_messages
, only: handle_ncerr
use cam_logfile
, only: iulog
implicit none
private
integer, parameter :: ptrtim=12, ptrlon=1
type boundarydata_type
integer :: ncid
integer :: fieldcnt
integer :: nm
integer :: np
integer :: latsiz
integer :: levsiz
integer :: ncolsiz
integer :: timsiz
integer :: vertextrap
logical :: iszonal, isncol
integer :: ndims
integer :: thistimedim
integer :: psid
integer :: map(4)
integer :: dimids(4)
integer, pointer :: dataid(:)
integer, pointer :: columnmap(:)
integer, pointer :: start(:,:)
integer, pointer :: count(:,:)
real(r8), pointer :: lat(:)
real(r8), pointer :: zi(:)
real(r8), pointer :: pin(:)
real(r8), pointer :: cdates(:)
real(r8), pointer :: fields(:,:,:,:,:)
real(r8), pointer :: datainst(:,:,:,:)
real(r8), pointer :: hybi(:)
real(r8), pointer :: ps(:,:,:)
end type boundarydata_type
public boundarydata_init
public boundarydata_update
public boundarydata_vert_interp
public boundarydata_type
contains
subroutine boundarydata_init(bndyfilename,phys_state,fieldnames,fieldcnt,bndydata,vertextrap) 2,2
implicit none
character(len=*),intent(in) :: bndyfilename
type(physics_state), intent(in):: phys_state(begchunk:endchunk)
integer,intent(in) :: fieldcnt
character(len=*), intent(in) :: fieldnames(fieldcnt)
type(boundarydata_type),intent(out) :: bndydata
integer,intent(in), optional :: vertextrap ! if 0 set values outside output grid to 0
! if 1 set to boundary value
! if 2 set to cyclic boundaries
! if 3 leave on input data grid and extrapolate later
real(r8), pointer :: datain(:,:,:,:,:)
integer :: lchnk
bndydata%fieldcnt=fieldcnt
if(present(vertextrap)) then
bndydata%vertextrap=vertextrap
else
bndydata%vertextrap=0
end if
nullify(bndydata%fields)
call boundarydata_read
(phys_state,bndyfilename,fieldcnt,fieldnames,bndydata,datain)
if(bndydata%iszonal) then
call boundarydata_interpolate
(phys_state,datain,bndydata)
allocate(bndydata%datainst(size(bndydata%fields,1),size(bndydata%fields,2), &
begchunk:endchunk,bndydata%fieldcnt))
deallocate(datain)
end if
end subroutine boundarydata_init
subroutine boundarydata_update(phys_state, bndydata, update_out) 1,7
use interpolate_data
,only : get_timeinterp_factors
type(physics_state), intent(in) :: phys_state(begchunk:endchunk)
type(boundarydata_type), intent(inout) :: bndydata
logical, intent(out), optional :: update_out
real(r8) :: cdate
integer :: nm, np, lchnk, j, k, fld, cols, cole, ncol, ndims
real(r8) :: fact1, fact2
real(r8), allocatable :: datain(:,:,:,:,:)
logical :: update
integer :: latspan
integer :: kmax
integer :: count(4), start(4), ierr
call get_data_bounding_date_indices
(bndydata%cdates,bndydata%nm,bndydata%np,cdate,update)
if(present(update_out)) update_out=update
nm= bndydata%nm
np= bndydata%np
call get_timeinterp_factors
(.true., np, bndydata%cdates(nm), bndydata%cdates(np), &
cdate, fact1, fact2, _FILE)
if(size(bndydata%fields,5).eq.2) then
nm=1
np=2
if(update) then ! we need to read in the next month and interpolate
if(bndydata%isncol) then
bndydata%fields(:,:,:,:,nm)=bndydata%fields(:,:,:,:,np)
do lchnk=begchunk,endchunk
ncol=phys_state(lchnk)%ncol
cols=1
cole=cols+bndydata%count(cols,lchnk)-1
do while(cole<=ncol)
if(bndydata%levsiz==1) then
ndims=2
start=(/bndydata%start(cols,lchnk),bndydata%np,-1,-1/)
count=(/bndydata%count(cols,lchnk),1,-1,-1/)
else
ndims=3
start=(/bndydata%start(cols,lchnk),bndydata%levsiz,bndydata%np,-1/)
count=(/bndydata%count(cols,lchnk),1,1,-1/)
end if
do fld=1,bndydata%fieldcnt
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%dataid(fld) , &
bndydata%fields(cols:cole,:,lchnk,fld,np), &
start(1:ndims), count(1:ndims)),&
_FILE,__LINE__)
end do
if(cols==ncol) exit
cols=cols+bndydata%count(cols,lchnk)
cole=cols+bndydata%count(cols,lchnk)-1
end do
end do
else
allocate(datain(ptrlon,bndydata%levsiz,bndydata%latsiz,1,bndydata%fieldcnt))
if(masterproc) then
count(1)=ptrlon
count(2)=bndydata%levsiz
count(3)=bndydata%latsiz
count(4)=1
start(1)=1
start(2)=1
start(3)=1
start(4)=bndydata%np
write(iulog,*) 'boundarydata reading data for month: ',bndydata%np
do fld=1,bndydata%fieldcnt
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%dataid(fld), &
datain(:,:,:,:,fld), start, count),_FILE,__LINE__)
end do
end if
#ifdef SPMD
call mpibcast
(datain, bndydata%levsiz*bndydata%latsiz*1*bndydata%fieldcnt, mpir8, 0, mpicom, ierr)
#endif
bndydata%fields(:,:,:,:,nm) = bndydata%fields(:,:,:,:,np)
call boundarydata_interpolate
(phys_state,datain,bndydata)
deallocate(datain)
end if
end if
end if
kmax = size(bndydata%fields,2)
do fld=1,bndydata%fieldcnt
do lchnk=begchunk,endchunk
if(bndydata%isncol) then
latspan = phys_state(lchnk)%ncol
else
latspan=phys_state(lchnk)%ulatcnt
end if
do k=1,kmax
do j=1,latspan
bndydata%datainst(j,k,lchnk,fld)=bndydata%fields(j,k,lchnk,fld,nm)*fact1 + &
bndydata%fields(j,k,lchnk,fld,np)*fact2
end do
end do
end do
end do
end subroutine boundarydata_update
subroutine boundarydata_read(phys_state,bndyfilename,fieldcnt,fieldnames,bndydata,datain) 1,39
!-----------------------------------------------------------------------
!
! Purpose:
! Do initial read of time-variant boundary dataset, containing
! 12 monthly fields as a function of latitude and pressure. Determine the two
! consecutive months between which the current date lies.
!
! Method:
!
! Author: NCAR CMS
!-----------------------------------------------------------------------
use ioFileMod
, only : getfil
implicit none
type(physics_state), intent(in) :: phys_state(begchunk:endchunk)
character(len=*),intent(in) :: bndyfilename
integer,intent(in) :: fieldcnt
character(len=*), intent(in) :: fieldnames(fieldcnt)
type(boundarydata_type), intent(out) :: bndydata
real(r8), pointer :: datain(:,:,:,:,:) !
!
! Local variables
!
integer :: londimid
integer :: latdimid
integer :: ncoldimid
integer :: levdimid
integer :: ilevdimid
integer :: timdimid
integer :: ndims
integer :: dimlen
integer :: ilevsiz
integer :: ncolsiz
character(len=nf90_max_name) :: dimname
! integer :: ncid ! netcdf id for file
integer :: dateid ! netcdf id for date variable
integer :: secid ! netcdf id for seconds variable
integer :: lonid ! netcdf id for longitude variable
integer :: ncolid ! netcdf id for longitude variable
integer :: latid ! netcdf id for latitude variable
integer :: levid ! netcdf id for level variable
integer :: timid ! netcdf id for time variable
integer :: hybid
integer :: dataid ! netcdf id for data fields
integer :: lonsiz ! size of longitude dimension on tracer dataset
integer :: levsiz ! size of level dimension on tracer dataset
integer :: latsiz ! size of latitude dimension on tracer dataset
integer :: j,n,k,nt,id ! indices
integer :: ki,ko,ji,jo ! indices
integer :: date_tr(ptrtim), sec_tr(ptrtim)
integer :: dimids(4), start(4), count(4)
integer, pointer :: columnmap(:)
real(r8) :: calday ! current calendar day
real(r8), pointer :: pin(:)
real(r8), allocatable :: tmp_ps(:,:), tmp_fld(:,:,:)
integer :: mincid,maxcid
real(r8), allocatable, target:: lati(:)
integer :: cols, cole
integer :: ierr, dimcnt
integer :: i, ncol, lchnk
character(len=256) :: locfn ! netcdf local filename to open
!
!-----------------------------------------------------------------------
!
! SPMD: Master reads dataset and does broadcast. All subsequent interpolation is
! done in every process. This is not required, one could remove this conditional
! and read the dataset independently on each task.
!
if(masterproc) then
write(iulog,*)'boundarydata_read: Reading from: ', trim(bndyfilename)
#ifndef USE_MASTERPROC
end if
#endif
call getfil
(bndyfilename, locfn)
call handle_ncerr
( nf90_open(locfn, 0, bndydata%ncid),&
_FILE,__LINE__)
! write(iulog,*)'boundarydata_read: NCOPN returns id ',bndydata%ncid,' for file ',trim(locfn)
!
!------------------------------------------------------------------------
! Read tracer data
!------------------------------------------------------------------------
!
! Get dimension info
!
nullify(columnmap)
nullify(pin)
call handle_ncerr
( nf90_inquire(bndydata%ncid, bndydata%ndims, unlimiteddimid=timdimid), &
_FILE,__LINE__)
ncolsiz=-1
levsiz=-1
lonsiz=-1
latsiz=-1
do i=1,bndydata%ndims
call handle_ncerr
( nf90_inquire_dimension(bndydata%ncid, i, dimname, dimlen),&
_FILE,__LINE__)
if (dimname(1:3).eq.'lat') then
latdimid=i
latsiz=dimlen
else if (dimname(1:3) .eq.'lon') then
londimid=i
lonsiz=dimlen
else if (dimname(1:4) .eq. 'ncol') then
ncoldimid=i
ncolsiz=dimlen
bndydata%isncol=.true.
else if (dimname(1:3) .eq. 'lev') then
levdimid=i
levsiz=dimlen
else if (dimname(1:4) .eq. 'ilev') then
ilevdimid=i
ilevsiz=dimlen
else if (dimname(1:4) .eq. 'time') then
if(timdimid/=i) then
timdimid=i
end if
bndydata%timsiz=dimlen
else
write(iulog,*) 'Warning: do not know how to handle dimension ',&
trim(dimname), ' in boundarydata.F90:313'
end if
end do
if (latsiz>0 .and. lonsiz<=1) then
bndydata%iszonal=.true.
allocate(bndydata%lat(latsiz))
end if
if(bndydata%isncol) then
! allocate (columnmap(ncolsiz))
! call handle_ncerr( nf90_inq_varid(bndydata%ncid, 'ncol' , ncolid),&
! _FILE,__LINE__)
! call handle_ncerr( nf90_get_var(bndydata%ncid,ncolid,columnmap), &
! _FILE,__LINE__)
if(levsiz>0) then
allocate(bndydata%fields(pcols,levsiz,begchunk:endchunk,fieldcnt,2))
ierr = nf90_inq_varid(bndydata%ncid, 'PS', bndydata%psid)
if(ierr.eq.NF90_NOERR) then
allocate(bndydata%ps(pcols,begchunk:endchunk,2))
allocate(bndydata%hybi(levsiz+1))
call handle_ncerr
(nf90_inq_varid(bndydata%ncid,'hybi',hybid),&
_FILE,__LINE__)
call handle_ncerr
( nf90_get_var(bndydata%ncid, hybid, bndydata%hybi ),&
_FILE,__LINE__)
else
call endrun
('Did not recognize a vertical coordinate variable')
end if
else
levsiz=1
allocate(bndydata%fields(pcols,1,begchunk:endchunk,fieldcnt,2))
end if
else
allocate(datain(lonsiz,levsiz,latsiz,2,fieldcnt))
!
! Check dimension info
!
if (lonsiz/=ptrlon) then
call endrun
('BOUNDARYDATA_READ: longitude dependence not implemented')
endif
if (bndydata%timsiz /= ptrtim) then
write(iulog,*)'BOUNDARYDATA_READ: timsiz=',bndydata%timsiz,' must = ptrtim=',ptrtim
call endrun
end if
if( bndydata%vertextrap.lt.3) then
allocate(pin(levsiz))
else
allocate(bndydata%pin(levsiz))
pin => bndydata%pin
end if
allocate(bndydata%lat(latsiz))
allocate(datain(ptrlon,levsiz,latsiz,2,fieldcnt))
call handle_ncerr
( nf90_inq_varid(bndydata%ncid, 'lat' , latid),&
_FILE,__LINE__)
end if
!
! Determine necessary dimension and variable id's
!
allocate(bndydata%cdates(bndydata%timsiz))
call handle_ncerr
(nf90_inq_varid(bndydata%ncid, 'date' , dateid), &
_FILE,__LINE__)
call handle_ncerr
( nf90_get_var(bndydata%ncid, dateid, date_tr),&
_FILE,__LINE__)
ierr = nf90_inq_varid(bndydata%ncid, 'datesec', secid)
if(ierr==NF90_NOERR) then
call handle_ncerr
( nf90_get_var(bndydata%ncid, secid , sec_tr),&
_FILE,__LINE__)
else
sec_tr=0
end if
if (mod(date_tr(1),10000)/100 /= 1) then
call endrun
('(boundarydata_read): error when cycling data: 1st month must be 1')
end if
if (mod(date_tr(ptrtim),10000)/100 /= 12) then
call endrun
('(boundarydata_read): error when cycling data: last month must be 12')
end if
!
! return the calander dates of the file data
!
do n=1,ptrtim
call bnddyi
(date_tr(n), sec_tr(n), bndydata%cdates(n))
end do
! else
! call handle_ncerr( nf90_inq_varid(bndydata%ncid, 'time', dateid),&
! _FILE,__LINE__)
!
! call handle_ncerr( nf90_get_var(bndydata%ncid, dateid, bndydata%cdates),&
! _FILE,__LINE__)
!
! end if
#ifdef USE_MASTERPROC
else
allocate(bndydata%cdates(ptrtim))
end if
#ifdef SPMD
call mpibcast
(bndydata%cdates, ptrtim, mpir8, 0, mpicom, ierr)
#endif
#endif
bndydata%nm=12
bndydata%np=1
call get_data_bounding_date_indices
(bndydata%cdates,bndydata%nm,bndydata%np)
#ifdef USE_MASTERPROC
if(masterproc) then
#endif
!
! Obtain entire date and sec variables. Assume that will always
! cycle over 12 month data.
!
!
! Obtain input data latitude and level arrays.
!
if(bndydata%iszonal) then
call handle_ncerr
( nf90_get_var(bndydata%ncid, latid, bndydata%lat),&
_FILE,__LINE__)
ierr = nf90_inq_varid(bndydata%ncid, 'lev' , levid)
call handle_ncerr
( nf90_get_var(bndydata%ncid, levid, pin ),&
_FILE,__LINE__)
end if
allocate(bndydata%dataid(fieldcnt))
if(masterproc) then
write(iulog,*) 'boundarydata reading data for months: ',bndydata%nm,bndydata%np
end if
do i=1,fieldcnt
call handle_ncerr
( nf90_inq_varid(bndydata%ncid, fieldnames(i) , bndydata%dataid(i)),&
_FILE,__LINE__)
end do
if(bndydata%isncol) then
allocate(bndydata%start(pcols,begchunk:endchunk), &
bndydata%count(pcols,begchunk:endchunk))
!
! For i/o efficiency we read in a block of data which includes the data needed on this
! processor but which may in fact include data not needed here. physics cids are just the
! offset into the file.
!
bndydata%start=-1
bndydata%count=1
mincid=2147483647
maxcid=-1
do lchnk=begchunk,endchunk
ncol=phys_state(lchnk)%ncol
i=minval(phys_state(lchnk)%cid(1:ncol))
if(i < mincid) mincid = i
i=maxval(phys_state(lchnk)%cid(1:ncol))
if(i > maxcid) maxcid = i
end do
allocate(tmp_ps(mincid:maxcid,2))
start=(/mincid,bndydata%nm,1,-1/)
if(bndydata%np>bndydata%nm) then
count=(/maxcid-mincid+1,2,-1,-1/)
else
count=(/maxcid-mincid+1,1,-1,-1/)
end if
if(associated(bndydata%ps) ) then
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%psid , &
tmp_ps(:,1:count(2)), start(1:2), &
count(1:2)),&
_FILE,__LINE__)
if(bndydata%np<bndydata%nm) then
start(2)=bndydata%np
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%psid , &
tmp_ps(:,2:2), start(1:2), &
count(1:2)),&
_FILE,__LINE__)
end if
do lchnk=begchunk,endchunk
do n=1,phys_state(lchnk)%ncol
bndydata%ps(n ,lchnk,:) = tmp_ps(phys_state(lchnk)%cid(n),:)
end do
end do
deallocate(tmp_ps)
end if
if(levsiz>1) then
dimcnt=3
else
dimcnt=2
end if
start(2)=1
count(2)=levsiz
if(bndydata%np>bndydata%nm) then
count(dimcnt)=2
else
count(dimcnt)=1
end if
start(dimcnt)=bndydata%nm
allocate(tmp_fld(mincid:maxcid,count(2),2))
do i=1,fieldcnt
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%dataid(i) , &
tmp_fld(:,:,1:count(dimcnt)), &
start(1:dimcnt), count(1:dimcnt)),&
_FILE,__LINE__)
do lchnk=begchunk,endchunk
do n=1,phys_state(lchnk)%ncol
bndydata%fields(n,:,lchnk,i,1:count(dimcnt)) = tmp_fld(phys_state(lchnk)%cid(n),:,:)
end do
end do
end do
if(bndydata%np<bndydata%nm) then
start(dimcnt)=bndydata%np
do i=1,fieldcnt
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%dataid(i) , &
tmp_fld(:,:,2:2), &
start(1:dimcnt), count(1:dimcnt)),&
_FILE,__LINE__)
do lchnk=begchunk,endchunk
do n=1,phys_state(lchnk)%ncol
bndydata%fields(n,:,lchnk,i,1:count(dimcnt)) = tmp_fld(phys_state(lchnk)%cid(n),:,:)
end do
end do
end do
end if
deallocate(tmp_fld)
! deallocate(columnmap)
else
!
! get the dimension orientation info from the first variable assume but verify that
! all variables requested have the same orientation
!
allocate(bndydata%start(4,1),bndydata%count(4,1))
call handle_ncerr
( nf90_inquire_variable(bndydata%ncid,bndydata%dataid(1), &
ndims=bndydata%ndims,dimids=bndydata%dimids),_FILE,__LINE__)
bndydata%start=1
do id=1,bndydata%ndims
if(bndydata%dimids(id).eq.londimid) then
bndydata%map(id)=1
bndydata%count(id,1)=lonsiz
else if(bndydata%dimids(id).eq.levdimid) then
bndydata%map(id)=lonsiz
bndydata%count(id,1)=levsiz
else if(bndydata%dimids(id).eq.latdimid) then
bndydata%map(id)=lonsiz
if(any(bndydata%dimids.eq.levdimid)) bndydata%map(id)=bndydata%map(id)*levsiz
bndydata%count(id,1)=latsiz
else if(bndydata%dimids(id).eq.timdimid) then
bndydata%map(id)=lonsiz*latsiz
if(any(bndydata%dimids.eq.levdimid)) bndydata%map(id)=bndydata%map(id)*levsiz
bndydata%count(id,1)=2
bndydata%start(id,1)=bndydata%nm
bndydata%thistimedim=id
else
write(iulog,*) __LINE__,fieldnames(i),id,bndydata%dimids(id),londimid, &
levdimid,latdimid,timdimid
call endrun
(_FILE)
end if
end do
do i=1,fieldcnt
call handle_ncerr
( nf90_inq_varid(bndydata%ncid, fieldnames(i), bndydata%dataid(i)),&
_FILE,__LINE__)
call handle_ncerr
( nf90_inquire_variable(bndydata%ncid,bndydata%dataid(i), &
ndims=ndims,dimids=dimids),_FILE,__LINE__)
if(ndims/=bndydata%ndims .or. dimids(1)/=bndydata%dimids(1).or.&
dimids(2)/=bndydata%dimids(2) .or. dimids(3)/=bndydata%dimids(3)) then
call endrun
('Variable dims or order does not match')
end if
if(bndydata%np .gt. bndydata%nm) then
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%dataid(i), &
datain(:,:,:,:,i),bndydata%start(:,1), bndydata%count(:,1), &
map=bndydata%map),_FILE,__LINE__)
else
bndydata%count(bndydata%thistimedim,1)=1
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%dataid(i), &
datain(:,:,:,1:1,i), bndydata%start(:,1), bndydata%count(:,1), &
map=bndydata%map), _FILE,__LINE__)
bndydata%start(bndydata%thistimedim,1)=bndydata%np
call handle_ncerr
( nf90_get_var(bndydata%ncid, bndydata%dataid(i), &
datain(:,:,:,2:2,i), bndydata%start(:,1), bndydata%count(:,1), &
map=bndydata%map), _FILE,__LINE__)
endif
end do
end if
#ifdef USE_MASTERPROC
end if
#ifdef SPMD
call mpibcast
(levsiz, 1, mpiint, 0, mpicom, ierr)
call mpibcast
(latsiz, 1, mpiint, 0, mpicom, ierr)
#endif
#endif
bndydata%latsiz=latsiz
bndydata%levsiz=levsiz
#ifdef USE_MASTERPROC
if(.not. masterproc) then
if( bndydata%vertextrap.lt.3) then
allocate(pin(levsiz))
else
allocate(bndydata%pin(levsiz))
pin => bndydata%pin
end if
allocate(bndydata%lat(latsiz))
allocate(datain(ptrlon,levsiz,latsiz,2,fieldcnt))
endif
#ifdef SPMD
call mpibcast
(bndydata%lat, latsiz, mpir8, 0, mpicom, ierr)
call mpibcast
(pin, levsiz, mpir8, 0, mpicom, ierr)
call mpibcast
(datain, levsiz*latsiz*2*fieldcnt, mpir8, 0, mpicom, ierr)
#endif
#endif
! Convert input pressure from millibars to pascals.
if(associated(pin)) then
pin=pin*100._r8
if(bndydata%vertextrap.lt.3) then
allocate(bndydata%zi(levsiz))
!
!
! Convert input pressure levels to height (m).
!
do k=1,levsiz
bndydata%zi(k) = 7.0e3_r8 * log (1.0e5_r8 / pin(k))
end do
deallocate(pin)
end if
end if
end subroutine boundarydata_read
subroutine boundarydata_interpolate(phys_state, datain, bndydata) 2,10
use hycoef
, only : hypm
use interpolate_data
,only : interp_type, lininterp_init, &
lininterp_finish, lininterp
use physconst
, only: pi
use infnan
, only : nan
type(physics_state), intent(in) :: phys_state(begchunk:endchunk)
real(r8),intent(in) :: datain(:,:,:,:,:)
type(boundarydata_type), intent(inout) :: bndydata
type(interp_type) :: interp_wgts, lev_wgts
integer :: k, lchnk, nt, j, fcnt
real(r8) :: zo(pver)
real(r8) :: lato(pcols)
integer :: ulatcnt
integer :: maxlatcnt
integer :: timesize, tvalout
!------------------------------------------------------------------------
! Interpolate tracer data to model grid
!------------------------------------------------------------------------
!
! Loop over all input times.
!
timesize=2
maxlatcnt=1
do lchnk=begchunk,endchunk
maxlatcnt=max(maxlatcnt,phys_state(lchnk)%ulatcnt)
end do
if(bndydata%vertextrap.lt.3) then
!
! Convert approximate cam pressure levels to height (m).
!
do k=1,pver
zo (k) = 7.0e3_r8 * log (1.0e5_r8 / hypm(k))
end do
call lininterp_init
(bndydata%zi,size(bndydata%zi),zo,pver,bndydata%vertextrap,lev_wgts)
if(.not. associated(bndydata%fields)) then
allocate(bndydata%fields(maxlatcnt,pver,begchunk:endchunk,bndydata%fieldcnt,timesize))
bndydata%fields=0_r8
end if
else
if(.not. associated(bndydata%fields)) then
allocate(bndydata%fields(maxlatcnt,bndydata%levsiz,begchunk:endchunk,bndydata%fieldcnt,timesize))
bndydata%fields=0_r8
end if
endif
do lchnk=begchunk,endchunk
ulatcnt=phys_state(lchnk)%ulatcnt
!
! Convert cam model latitudes to degrees.
! Input model latitudes already in degrees.
!
do j=1,ulatcnt
lato(j) = phys_state(lchnk)%ulat(j)*180._r8/pi
end do
call lininterp_init
(bndydata%lat,size(bndydata%lat),lato(1:ulatcnt),ulatcnt,1,interp_wgts)
timesize = size(datain,4)
do fcnt=1,bndydata%fieldcnt
do nt = 1,timesize
if(timesize.gt.1) then
tvalout=nt
else
tvalout=2
end if
if(bndydata%vertextrap.lt.3) then
call lininterp
(transpose(datain(1,:,:,nt,fcnt)),bndydata%latsiz,bndydata%levsiz, &
bndydata%fields(1:ulatcnt,:,lchnk,fcnt,tvalout), ulatcnt, pver, interp_wgts, lev_wgts)
else
do k=1,bndydata%levsiz
call lininterp
(datain(1,k,:,nt,fcnt),bndydata%latsiz, &
bndydata%fields(1:ulatcnt,k,lchnk,fcnt,tvalout), ulatcnt, interp_wgts)
end do
end if
end do
end do ! end loop over time samples
call lininterp_finish
(interp_wgts)
end do
if(bndydata%vertextrap.lt.3) &
call lininterp_finish
(lev_wgts)
return
end subroutine boundarydata_interpolate
subroutine get_data_bounding_date_indices(cdates,nm,np, cdayout, update) 2,6
use time_manager
, only: get_curr_date, get_perp_date, get_curr_calday, &
is_perpetual
real(r8), intent(in) :: cdates(ptrtim)
real(r8), intent(out),optional :: cdayout
logical, intent(out) ,optional :: update
integer, intent(inout) :: nm, np
integer :: n, np1
real(r8) :: calday
integer :: yr, mon, day ! components of a date
integer :: ncdate ! current date in integer format [yyyymmdd]
integer :: ncsec ! current time of day [seconds]
calday = get_curr_calday
()
if(present(cdayout)) cdayout=calday
if(present(update)) update=.false. ! initialize output variable
if(min(nm,np) .ge. 1 .and. max(nm,np) .le. 12 .and. &
calday>cdates(nm) .and. calday<=cdates(np)) return
if((nm==12 .and. np==1) .and. (calday <= cdates(np) .or. &
calday > cdates(nm))) return
if(present(update)) update=.true.
if(calday <= cdates(1) .or. calday > cdates(12)) then
nm=12
np=1
else
nm=0
do n=1,ptrtim-1
if(calday>cdates(n) .and. calday<=cdates(n+1)) then
nm=n
np=n+1
end if
end do
if(nm .eq. 0) then
if ( is_perpetual
() ) then
call get_perp_date
(yr, mon, day, ncsec)
else
call get_curr_date
(yr, mon, day, ncsec)
end if
ncdate = yr*10000 + mon*100 + day
write(iulog,*)'model date:', ncdate, ncsec,'boundary data dates:', cdates
call endrun
('BOUNDARYDATA_READ: Failed to find dates bracketing dates')
end if
end if
end subroutine get_data_bounding_date_indices
!================================================================================================
subroutine boundarydata_vert_interp(lchnk, ncol, levsiz, fldcnt, pin, pmid, datain, dataout) 1,1
!-----------------------------------------------------------------------
!
! Purpose: Interpolate ozone from current time-interpolated values to model levels
!
! Method: Use pressure values to determine interpolation levels
!
! Author: Bruce Briegleb
!
!--------------------------------------------------------------------------
implicit none
! Arguments
!
integer, intent(in) :: lchnk ! chunk identifier
integer, intent(in) :: ncol ! number of atmospheric columns
integer, intent(in) :: levsiz
integer, intent(in) :: fldcnt
real(r8), intent(in) :: pin(levsiz)
real(r8), intent(in) :: pmid(pcols,pver) ! level pressures (mks)
real(r8), intent(in) :: datain(pcols,levsiz,fldcnt)
real(r8), intent(out) :: dataout(pcols,pver,fldcnt) ! ozone mass mixing ratio
!
! local storage
!
integer :: i ! longitude index
integer :: k, kk, kkstart ! level indices
integer :: kupper(pcols) ! Level indices for interpolation
integer :: kount ! Counter
integer :: fld
real(r8) dpu ! upper level pressure difference
real(r8) dpl ! lower level pressure difference
!--------------------------------------------------------------------------
!
! Initialize index array
!
do i=1,ncol
kupper(i) = 1
end do
do k=1,pver
!
! Top level we need to start looking is the top level for the previous k
! for all longitude points
!
kkstart = levsiz
do i=1,ncol
kkstart = min0(kkstart,kupper(i))
end do
kount = 0
!
! Store level indices for interpolation
!
do kk=kkstart,levsiz-1
do i=1,ncol
if (pin(kk).lt.pmid(i,k) .and. pmid(i,k).le.pin(kk+1)) then
kupper(i) = kk
kount = kount + 1
end if
end do
!
! If all indices for this level have been found, do the interpolation and
! go to the next level
!
if (kount.eq.ncol) then
do fld=1,fldcnt
do i=1,ncol
dpu = pmid(i,k) - pin(kupper(i))
dpl = pin(kupper(i)+1) - pmid(i,k)
dataout(i,k,fld) = (datain(i,kupper(i),fld )*dpl + &
datain(i,kupper(i)+1,fld)*dpu)/(dpl + dpu)
end do
end do
goto 35
end if
end do
!
! If we've fallen through the kk=1,levsiz-1 loop, we cannot interpolate and
! must extrapolate from the bottom or top data level for at least some
! of the longitude points.
!
do fld=1,fldcnt
do i=1,ncol
if (pmid(i,k) .lt. pin(1)) then
dataout(i,k,fld) = datain(i,1,fld)*pmid(i,k)/pin(1)
else if (pmid(i,k) .gt. pin(levsiz)) then
dataout(i,k,fld) = datain(i,levsiz,fld)
else
dpu = pmid(i,k) - pin(kupper(i))
dpl = pin(kupper(i)+1) - pmid(i,k)
dataout(i,k,fld) = (datain(i,kupper(i),fld )*dpl + &
datain(i,kupper(i)+1,fld)*dpu)/(dpl + dpu)
end if
end do
end do
if (kount.gt.ncol) then
call endrun
('ozone_data_vert_interp: Bad ozone data: non-monotonicity suspected')
end if
35 continue
end do
end subroutine boundarydata_vert_interp
#if 0
subroutine ncol_read_bracket(cid,columnmap,start,count,ncol)
integer, intent(in) :: cid(:), columnmap(:), ncol
integer, intent(out) :: start(:), count(:)
integer :: i, j, tcol
tcol = size(columnmap)
count=1
do i=1,ncol
#if 1
start(i)=cid(i)
count(i)=1
#else
do j=1,tcol
if(columnmap(j).eq.cid(i)) then
start(i)=j
count(i)=1
exit
end if
end do
#endif
end do
do i=1,ncol-1
do j=1,ncol-i
if(columnmap(start(i+j)).eq.columnmap(start(i)+j)) then
count(i)=count(i)+1
else
exit
end if
end do
end do
write(iulog,*) __LINE__,cid(1),cid(ncol),minval(cid(1:ncol)),maxval(cid(1:ncol))
end subroutine ncol_read_bracket
#endif
end module boundarydata