! Conformal Cubic Atmospheric Model
! Copyright 2015-2017 Commonwealth Scientific Industrial Research Organisation (CSIRO)
! This file is part of the Conformal Cubic Atmospheric Model (CCAM)
!
! CCAM is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! CCAM is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with CCAM. If not, see .
!------------------------------------------------------------------------------
! This subroutine is to extract (in memory) data from the IGBP dataset.
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine reads the sib, soil, albedo or urban data and maps
! it to a CC grid. Data is specified by datatype (e.g., datatype=land
! or datatype=soil).
!
Subroutine getdata(dataout,glonlat,grid,tlld,sibdim,num,sibsize,datatype,fastigbp,ozlaipatch,binlimit,month, &
datafilename,laifilename,class_num,mapjveg,mapwater)
Use ccinterp
Implicit None
Integer, intent(in) :: sibsize,num,binlimit,month,class_num
Integer, dimension(2), intent(in) :: sibdim
Integer, dimension(sibdim(1),sibdim(2)) :: countn
Integer, dimension(1:2) :: lldim,lldim_x,llstore,pxy
integer, dimension(class_num), intent(in) :: mapjveg
Integer nscale,nscale_x,nface,subsec,mode,tmp
Integer i,j,k,lci,lcj,nx,ny,imth,mthrng,netcount
Integer basesize,scalelimit,minscale
Character(len=*), intent(in) :: datatype, datafilename, laifilename
Real, dimension(sibdim(1),sibdim(2),0:num), intent(out) :: dataout
Real, dimension(sibdim(1),sibdim(2)), intent(in) :: grid
Real, dimension(sibdim(1),sibdim(2),2), intent(in) :: tlld
Real, dimension(sibdim(1),sibdim(2),2) :: rlld
Real, dimension(sibdim(1),sibdim(2)) :: zsum
Real, dimension(2), intent(in) :: glonlat
Real, dimension(:,:,:), allocatable :: coverout
Real, dimension(1:2) :: latlon
Real, dimension(1:2,1:2) :: sll
Real, dimension(1:2,1:2,0:num) :: covertemp
real, dimension(1:12) :: netlai
Real aglon,aglat,alci,alcj,serlon,serlat,slonn,slatx,elon,elat,tscale,baselon
Real ipol,callon,callat,indexlon,indexlat
Logical, intent(in) :: fastigbp,ozlaipatch
Logical, dimension(:,:), allocatable :: sermask,sermask2
logical, dimension(sibdim(1),sibdim(2)) :: ltest
logical, dimension(class_num), intent(in) :: mapwater
if ( month==0 ) then
mthrng=12
else
mthrng=1
end if
dataout=0.
countn=0
! Determine scale limits
nscale=999
baselon=real(int(glonlat(1)-180.))
rlld=tlld
Do While (Any(rlld(:,:,1)(baselon+360.)))
Where (rlld(:,:,1)>(baselon+360.))
rlld(:,:,1)=rlld(:,:,1)-360.
End where
End do
Select Case(datatype)
Case('land')
Write(6,*) 'Process USGS land-use and mod15_BU LAI datasets.'
scalelimit=1
Case('soil')
Write(6,*) 'Process HWSD soil dataset.'
scalelimit=4
Case('albvis')
Write(6,*) 'Process soil albedo (VIS) dataset.'
scalelimit=4
Case('albnir')
Write(6,*) 'Process soil albedo (NIR) dataset.'
scalelimit=4
Case DEFAULT
Write(6,*) 'ERROR: Cannot find data ',trim(datatype)
call finishbanner
Stop -1
End Select
If (fastigbp) then
! Step over scales
mode=0
Do While (Any(countn==0).AND.nscale>scalelimit)
latlon=(/ baselon, 90. /)
ltest=countn==0
Call findsmallscale(nscale,scalelimit,latlon,llstore,grid,ltest,rlld,subsec,sll,sibsize,sibdim)
slonn=sll(1,1)
slatx=sll(2,2)
minscale=nscale*binlimit
Write(6,*) 'Bin'
Write(6,*) 'nscale = ',nscale
Write(6,*) 'subsec = ',subsec
Write(6,*) 'sll = ',sll
Write(6,*) 'llstore = ',llstore
If (subsec/=0) then
Do nx=1,subsec
Do ny=1,subsec
Write(6,*) 'nx,ny,subsec = ',nx,ny,subsec
lldim=llstore
! Determine top corner lat/lon
Call latlonconvert(nscale,latlon,lldim,slonn,slatx,nx,ny)
Write(6,*) 'orig latlon = ',latlon
Write(6,*) 'orig lldim = ',lldim
! Check if there are any points of interest on this tile
ltest=countn==0
Call searchdim(mode,sll,nscale,real(nscale),latlon,lldim,grid,ltest,rlld,sibdim)
Call scaleconvert(nscale,tmp,lldim,sll,sibsize)
mode=2
latlon(1)=sll(1,1)
latlon(2)=sll(2,2)
Write(6,*) 'mod latlon = ',latlon
Write(6,*) 'mod lldim = ',lldim
! Bin
If (All(lldim>0)) then
Allocate(coverout(lldim(1),lldim(2),0:num))
Select Case(datatype)
Case('land')
Call igbpread(latlon,nscale,lldim,coverout,num,month,ozlaipatch,datafilename,laifilename,class_num,mapjveg)
Case('soil')
Call kmconvert(nscale,nscale_x,lldim,lldim_x,4)
Call soilread(latlon,nscale_x,lldim_x,coverout,datafilename)
Case('albvis','albnir')
Call kmconvert(nscale,nscale_x,lldim,lldim_x,4)
Call albedoread(latlon,nscale_x,lldim_x,coverout(:,:,0),datatype,datafilename)
Case DEFAULT
Write(6,*) 'ERROR: Cannot find data ',trim(datatype)
call finishbanner
Stop -1
End Select
write(6,*) 'Start bin'
if (datatype=='land') then
do j=1,lldim(2)
aglat=callat(latlon(2),j,nscale)
do i=1,lldim(1)
aglon=callon(latlon(1),i,nscale)
call lltoijmod(aglon,aglat,alci,alcj,nface)
lci = nint(alci)
lcj = nint(alcj)
lcj = lcj+nface*sibdim(1)
if (grid(lci,lcj)>=real(minscale)) then
if (sum(abs(coverout(i,j,0:class_num)))<0.001) then
if (countn(lci,lcj)==0) then
dataout(lci,lcj,0:num)=-1. ! Missing value?
countn(lci,lcj)=1
end if
else
if (dataout(lci,lcj,0)<0.) then
dataout(lci,lcj,0:num)=0. ! reset missing point after finding non-trival data
countn(lci,lcj)=0
end if
dataout(lci,lcj,0:class_num)=dataout(lci,lcj,0:class_num)+coverout(i,j,0:class_num)
where (coverout(i,j,class_num+1:num)==0..and.countn(lci,lcj)>0)
dataout(lci,lcj,class_num+1:num)=dataout(lci,lcj,class_num+1:num)*real(countn(lci,lcj)+1) &
/real(countn(lci,lcj))
elsewhere (dataout(lci,lcj,class_num+1:num)==0.)
dataout(lci,lcj,class_num+1:num)=coverout(i,j,class_num+1:num)*real(countn(lci,lcj)+1)
elsewhere
dataout(lci,lcj,class_num+1:num)=dataout(lci,lcj,class_num+1:num)+coverout(i,j,class_num+1:num)
end where
countn(lci,lcj)=countn(lci,lcj)+1
end if
end if
end do
end do
else
Do j=1,lldim(2)
aglat=callat(latlon(2),j,nscale)
Do i=1,lldim(1)
aglon=callon(latlon(1),i,nscale)
Call lltoijmod(aglon,aglat,alci,alcj,nface)
lci = nint(alci)
lcj = nint(alcj)
lcj = lcj+nface*sibdim(1)
If (grid(lci,lcj)>=real(minscale)) then
If (sum(abs(coverout(i,j,:)))<=0.01) then
If (countn(lci,lcj)==0) Then
dataout(lci,lcj,:)=-1. ! Missing value?
countn(lci,lcj)=1
End if
Else
If (dataout(lci,lcj,0)<0.) Then
dataout(lci,lcj,:)=0. ! reset missing point after finding non-trival data
countn(lci,lcj)=0
End If
dataout(lci,lcj,:)=dataout(lci,lcj,:)+coverout(i,j,:)
countn(lci,lcj)=countn(lci,lcj)+1
End if
End If
End Do
End Do
end if
Write(6,*) 'Bin complete'
Deallocate(coverout)
Else
Write(6,*) 'No points in valid range'
End If
End Do
End Do
Else
Write(6,*) 'Skip'
End If
End Do
Else
Select Case(datatype)
Case('land')
Call igbpstream(sibdim,dataout,countn,num,month,ozlaipatch,datafilename,laifilename,class_num,mapjveg)
Case('soil')
Call soilstream(sibdim,dataout,countn,datafilename)
Case('albvis','albnir')
Call albedostream(sibdim,dataout(:,:,0),countn,datatype,datafilename)
Case DEFAULT
Write(6,*) 'ERROR: Cannot find data ',trim(datatype)
call finishbanner
Stop -1
End Select
End If
! Fill
Write(6,*) 'Fill'
Allocate(sermask(1:2,1:2))
nscale=scalelimit
latlon=(/ baselon, 90. /)
llstore=(/ 43200/nscale , 21600/nscale /)
ltest=countn==0
Call searchdim(4,sll,nscale,0.,latlon,llstore,grid,ltest,rlld,sibdim)
Call scaleconvert(nscale,subsec,llstore,sll,sibsize)
slonn=sll(1,1)
slatx=sll(2,2)
Write(6,*) 'nscale = ',nscale
Write(6,*) 'subsec = ',subsec
Write(6,*) 'sll = ',sll
Write(6,*) 'llstore = ',llstore
If (subsec/=0) then
Do nx=1,subsec
Do ny=1,subsec
Write(6,*) 'nx,ny,subsec = ',nx,ny,subsec
lldim=llstore
Call latlonconvert(nscale,latlon,lldim,slonn,slatx,nx,ny)
Write(6,*) 'orig latlon = ',latlon
Write(6,*) 'orig lldim = ',lldim
! overlap tiles for interpolation
If (nx/=subsec) lldim(1)=lldim(1)+1
If (ny/=subsec) lldim(2)=lldim(2)+1
! Check if there are any points of interest on this tile
ltest=countn==0
Call searchdim(4,sll,nscale,0.,latlon,lldim,grid,ltest,rlld,sibdim)
Call scaleconvert(nscale,tmp,lldim,sll,sibsize)
If (Any(lldim(:)==1)) lldim=0
latlon(1)=sll(1,1)
latlon(2)=sll(2,2)
Write(6,*) 'mod latlon = ',latlon
Write(6,*) 'mod lldim = ',lldim
If (lldim(1)>0.AND.lldim(2)>0) then
Allocate(coverout(lldim(1),lldim(2),0:num))
Select Case(datatype)
Case('land')
Call igbpread(latlon,nscale,lldim,coverout,num,month,ozlaipatch,datafilename,laifilename,class_num,mapjveg)
Case('soil')
Call kmconvert(nscale,nscale_x,lldim,lldim_x,4)
Call soilread(latlon,nscale_x,lldim_x,coverout,datafilename)
Case('albvis','albnir')
Call kmconvert(nscale,nscale_x,lldim,lldim_x,4)
Call albedoread(latlon,nscale_x,lldim_x,coverout(:,:,0),datatype,datafilename)
Case DEFAULT
Write(6,*) 'ERROR: Cannot find data ',trim(datatype)
call finishbanner
Stop -1
End Select
Do lcj=1,sibdim(2)
Do lci=1,sibdim(1)
If (countn(lci,lcj)==0) then
aglon=rlld(lci,lcj,1)
aglat=rlld(lci,lcj,2)
serlon=indexlon(aglon,latlon(1),nscale)
serlat=indexlat(aglat,latlon(2),nscale)
i=nint(serlon)
j=nint(serlat)
if (i>0.and.i<=lldim(1).and.j>0.and.j<=lldim(2)) then
if (any(coverout(i,j,:)>0.)) then
dataout(lci,lcj,:)=coverout(i,j,:)
countn(lci,lcj)=1
else
! missing
dataout(lci,lcj,:)=-1.
countn(lci,lcj)=1
end if
end if
End If
End Do
End Do
Deallocate(coverout)
Else
Write(6,*) 'No points in valid range'
End If
End Do
End Do
Else
Write(6,*) 'Skip'
End If
Deallocate(sermask)
! clear missing values (e.g., ocean points)
! These values should be fixed in igbpveg.f90
countn=max(countn,1)
dataout=max(dataout,0.)
Do k=0,num
dataout(:,:,k)=dataout(:,:,k)/Real(countn)
End Do
if (datatype=='land') then
Allocate(sermask(1:sibdim(1),1:sibdim(2)),sermask2(1:sibdim(1),1:sibdim(2)))
!$OMP PARALLEL DO
do k=1,class_num
if ( .not.mapwater(k) ) then
sermask=dataout(:,:,k)>0.
sermask2=sermask
where ( sermask(:,:) .and. any(dataout(:,:,(k-1)*mthrng+class_num+1:k*mthrng+class_num)==0.,dim=3) )
sermask2(:,:) = .false.
elsewhere ( sermask(:,:) )
sermask(:,:) = .false.
end where
if (any(sermask)) then ! missing LAI data
Write(6,*) "Replace missing LAI for class ",k
if (any(sermask2)) then
call fill_cc_a_mask(dataout(:,:,(k-1)*mthrng+class_num+1:k*mthrng+class_num),sibdim(1),mthrng,sermask2,sermask)
else
sermask2=.false.
do lcj=1,sibdim(2)
do lci=1,sibdim(1)
i=1
do while(i<=class_num.or..not.sermask2(lci,lcj))
if ( .not.mapwater(i) ) then
if (all(dataout(lci,lcj,(i-1)*mthrng+class_num+1:i*mthrng+class_num)>0.)) then
sermask2(lci,lcj)=.true.
end if
end if
i=i+1
end do
end do
end do
if (any(sermask2)) then
write(6,*) "Extended replace for missing LAI class ",k
do lcj=1,sibdim(2)
do lci=1,sibdim(1)
if (sermask(lci,lcj)) then
call findnear(pxy,lci,lcj,sermask2,rlld,sibdim)
netlai=0.
netcount=0
do i=1,class_num
if ( .not.mapwater(i) ) then
if (all(dataout(pxy(1),pxy(2),(i-1)*mthrng+class_num+1:i*mthrng+class_num)>0.)) then
netlai(1:mthrng)=netlai(1:mthrng)+dataout(pxy(1),pxy(2),(i-1)*mthrng+class_num+1:i*mthrng+class_num)
netcount=netcount+1
end if
end if
end do
dataout(lci,lcj,(k-1)*mthrng+class_num+1:k*mthrng+class_num)=netlai(1:mthrng)/real(netcount)
end if
end do
end do
else
write(6,*) "Only trivial LAI found"
end if
end if
end if
else
dataout(:,:,class_num+(k-1)*mthrng+1:class_num+k*mthrng)=0.
end if
end do
!$OMP END PARALLEL DO
Deallocate(sermask,sermask2)
end if
Write(6,*) "Task complete"
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine reads sib data down to nscale=1km resolution
!
Subroutine igbpread(latlon,nscale,lldim,coverout,num,month,ozlaipatch,vegfilename,laifilename,class_num,mapjveg)
use netcdf_m
Implicit None
logical, intent(in) :: ozlaipatch
Integer, intent(in) :: nscale,num,month,class_num
Real, dimension(1:2), intent(in) :: latlon
Integer, dimension(1:2), intent(in) :: lldim
Real, dimension(lldim(1),lldim(2),0:num), intent(inout) :: coverout
Integer*1, dimension(43200) :: datatemp
integer, dimension(43200,nscale) :: databuffer
Integer, dimension(43200) :: ltemp2
integer, dimension(:,:,:), allocatable :: lbuff
integer, dimension(43200) :: i4datatemp
integer, dimension(0:num) :: ncount
Integer, dimension(2,2) :: jin,jout
integer, dimension(class_num), intent(in) :: mapjveg
Integer ilat,ilon,jlat,recpos,mthrng,imth,lrp,ctmp,ltmp,nlrp,k
integer i,j,ntmp,ix,iy,tiy,tix,vegtmp
Integer, dimension(2) :: llint
integer ierr
integer, dimension(0:12) :: ncid, varid
logical, dimension(0:12) :: ncfile
real, dimension(:,:,:), allocatable :: laiin
real bx,by,bdelta,tbx,tby,tbdelta
character*2 cmth
Character*10 fname
character(len=*), intent(in) :: vegfilename, laifilename
ierr = nf90_open(trim(vegfilename)//'.nc',nf90_nowrite,ncid(0))
if ( ierr==nf90_noerr ) then
ncfile(0) = .true.
write(6,*) "Found netcdf version ",trim(vegfilename)
ierr = nf90_inq_varid(ncid(0),"vegt",varid(0))
else
ierr = nf90_open(trim(vegfilename),nf90_nowrite,ncid(0))
if ( ierr==nf90_noerr ) then
ncfile(0) = .true.
write(6,*) "Found netcdf version ",trim(vegfilename)
ierr = nf90_inq_varid(ncid(0),"vegt",varid(0))
else
ncfile(0) = .false.
! Must be compiled using 1 byte record lengths
Open(10,FILE=vegfilename,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=43200,STATUS='OLD')
end if
end if
if (month==0) then
mthrng=12
do imth=1,mthrng
write(fname,'("slai",I2.2,".img")') imth
ierr = nf90_open(trim(trim(laifilename)//'/'//fname)//'.nc',nf90_nowrite,ncid(imth))
if ( ierr==nf90_noerr ) then
ncfile(imth) = .true.
write(6,*) "Found netcdf version ",trim(trim(laifilename)//'/'//fname)
ierr = nf90_inq_varid(ncid(imth),"LAI",varid(imth))
else
ierr = nf90_open(trim(trim(laifilename)//'/'//fname),nf90_nowrite,ncid(imth))
if ( ierr==nf90_noerr ) then
ncfile(imth) = .true.
write(6,*) "Found netcdf version ",trim(trim(laifilename)//'/'//fname)
ierr = nf90_inq_varid(ncid(imth),"LAI",varid(imth))
else
ncfile(imth) = .false.
open(10+imth,FILE=trim(laifilename)//'/'//fname,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
end do
else
mthrng=1
ierr = nf90_open(trim(laifilename)//'.nc',nf90_nowrite,ncid(1))
if ( ierr==nf90_noerr ) then
ncfile(1) = .true.
write(6,*) "Found netcdf version ",trim(laifilename)
ierr = nf90_inq_varid(ncid(1),"LAI",varid(1))
else
ierr = nf90_open(trim(laifilename),nf90_nowrite,ncid(1))
if ( ierr==nf90_noerr ) then
ncfile(1) = .true.
write(6,*) "Found netcdf version ",trim(laifilename)
ierr = nf90_inq_varid(ncid(1),"LAI",varid(1))
else
ncfile(1) = .false.
open(11,FILE=laifilename,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
end if
allocate(lbuff(43200,nscale,mthrng))
if (ozlaipatch) then
write(6,*) "CSIRO LAI dataset patch"
if (month==0) then
imth=1
else
imth=month
end if
write(cmth,'(I2.2)') imth
open(30,file='aus_lai.'//cmth,STATUS='OLD')
read(30,*) bx,by,bdelta,ix,iy
close(30)
allocate(laiin(ix,iy,mthrng))
if (month.eq.0) then
do imth=1,mthrng
write(cmth,'(I2.2)') imth
open(30,file='aus_lai.'//cmth,STATUS='OLD')
read(30,*) tbx,tby,tbdelta,tix,tiy
if ((tix.ne.ix).or.(tiy.ne.iy).or.(tbx.ne.bx).or.(tby.ne.by).or.(tbdelta.ne.bdelta)) then
write(6,*) "ERROR: LAI data has different dimensions for different months"
call finishbanner
stop -1
end if
read(30,*) laiin(:,:,imth)
close(30)
end do
else
write(cmth,'(I2.2)') imth
write(6,*) 'Open aus_lai.'//cmth
open(30,file='aus_lai.'//cmth,STATUS='OLD')
read(30,*) tbx,tby,tbdelta,tix,tiy
if ((tix.ne.ix).or.(tiy.ne.iy).or.(tbx.ne.bx).or.(tby.ne.by).or.(tbdelta.ne.bdelta)) then
write(6,*) "ERROR: LAI data has different dimensions for different months"
call finishbanner
stop -1
end if
read(30,*) laiin(:,:,1)
close(30)
end if
end if
! To speed-up the code, 43200x(nscale) blocks of the igbp file are read
! at a time. The data is then averaged in memory. This system speeds-up the
! code considerably. However, there are limitations as to the size of data
! that can be stored in memory.
Call solvejshift(latlon(1),jin,jout,120)
lrp=-1
coverout=0.
Do ilat=1,lldim(2)
if ((mod(ilat,50).eq.0).or.(ilat.eq.lldim(2))) then
Write(6,*) 'USGS + LAI - ',ilat,'/',lldim(2)
end if
! Read data
llint(2)=nint((90.-latlon(2))*120.)+(ilat-1)*nscale
Do jlat=1,nscale
recpos=llint(2)+jlat
if ( ncfile(0) ) then
ierr = nf90_get_var(ncid(0),varid(0),i4datatemp,start=(/1,recpos/),count=(/43200,1/))
else
Read(10,REC=recpos) datatemp
i4datatemp = datatemp
end if
! Shift lon to zero
databuffer(jin(1,1):jin(1,2),jlat)=i4datatemp(jout(1,1):jout(1,2))
databuffer(jin(2,1):jin(2,2),jlat)=i4datatemp(jout(2,1):jout(2,2))
End Do
do imth=1,mthrng
lrp=-1
Do jlat=1,nscale
recpos=llint(2)+jlat
! read corrosponding lai data and fill to 1km grid
nlrp=int(real(recpos+3)/4.)
if (lrp/=nlrp) then
lrp=nlrp
if ( ncfile(imth) ) then
ierr = nf90_get_var(ncid(imth),varid(imth),i4datatemp(1:10800), &
start=(/1,lrp/),count=(/10800,1/))
else
read(10+imth,REC=lrp) datatemp(1:10800)
i4datatemp(1:10800) = datatemp(1:10800)
end if
do k=1,10800
ltemp2(4*k-3:4*k)=i4datatemp(k)
end do
if (ozlaipatch) then
tiy=nint((by-90.+(real(llint(2)+jlat)-0.5)/120.)/bdelta+0.5)
if ( tiy>=1 .and. tiy<=iy ) then
do k=1,43200
tix=nint(((real(k)-0.5)/120.-180.-bx)/bdelta+0.5)
if ( tix>=1 .and. tix<=ix ) then
ltemp2(k)=laiin(tix,tiy,imth)
end if
end do
end if
end if
end if
lbuff(jin(1,1):jin(1,2),jlat,imth)=ltemp2(jout(1,1):jout(1,2))
lbuff(jin(2,1):jin(2,2),jlat,imth)=ltemp2(jout(2,1):jout(2,2))
End Do
end do
Do ilon=1,lldim(1)
llint(1)=(ilon-1)*nscale
ncount=0
do j=1,nscale
do i=llint(1)+1,llint(1)+nscale
vegtmp=mod(databuffer(i,j)+256,256)
if ( vegtmp==0 ) then
ctmp=0
else if ( mapjveg(max(min(vegtmp,class_num),1))==vegtmp ) then
ctmp=max(min(vegtmp,class_num),1)
else
ctmp = -1
do k = 1,class_num
if ( vegtmp==mapjveg(k) ) then
ctmp = k
exit
end if
end do
end if
if (ctmp>=0.and.ctmp<=class_num) then
coverout(ilon,ilat,ctmp)=coverout(ilon,ilat,ctmp)+1.
ncount(ctmp)=ncount(ctmp)+1
if ( ctmp>0 ) then
do imth=1,mthrng
ltmp=mod(lbuff(i,j,imth)+256,256)
if (ltmp>0.and.ltmp<100) then
coverout(ilon,ilat,class_num+(ctmp-1)*mthrng+imth)=coverout(ilon,ilat,class_num+(ctmp-1)*mthrng+imth)+real(ltmp)/10.
ncount(class_num+(ctmp-1)*mthrng+imth)=ncount(class_num+(ctmp-1)*mthrng+imth)+1
end if
end do
end if
end if
end do
end do
ncount(0:class_num)=sum(ncount(0:class_num))
coverout(ilon,ilat,:)=coverout(ilon,ilat,:)/real(max(ncount,1))
End Do
End Do
deallocate(lbuff)
if (ozlaipatch) deallocate(laiin)
if ( ncfile(0) ) then
ierr = nf90_close(ncid(0))
else
Close(10)
end if
do imth=1,mthrng
if ( ncfile(imth) ) then
ierr = nf90_close(ncid(imth))
else
close(10+imth)
end if
end do
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine reads soil data down to nscale_4=1
! (i.e., 4km) resolution.
!
Subroutine soilread(latlon,nscale_4,lldim_4,coverout,soildatafile)
use netcdf_m
Implicit None
Integer, intent(in) :: nscale_4
Real, dimension(2), intent(in) :: latlon
Integer, dimension(2), intent(in) :: lldim_4
Real, dimension(lldim_4(1),lldim_4(2),0:8), intent(out) :: coverout
real, dimension(0:13) :: faosoil
integer, dimension(nscale_4,nscale_4) :: dataslice
Integer, dimension(10800,1:nscale_4) :: databuffer
Integer*1, dimension(10800) :: datatemp
integer, dimension(10800) :: i4datatemp
Integer, dimension(2,2) :: jin,jout
Integer ilat,ilon,jlat,recpos,i
integer ncid, varid, ierr
Integer, dimension(2) :: llint_4
logical ncfile
real nsum
integer, dimension(0:13), parameter :: masmap=(/ 0, 1, 1, 4, 2, 4, 7, 2, 2, 5, 6, 3, 8, 9 /)
character(len=*), intent(in) :: soildatafile
ierr = nf90_open(trim(soildatafile)//'.nc',nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(soildatafile)
ierr = nf90_inq_varid(ncid,"soilt",varid)
else
ierr = nf90_open(trim(soildatafile),nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(soildatafile)
ierr = nf90_inq_varid(ncid,"soilt",varid)
else
ncfile = .false.
! Must be compiled using 1 byte record lengths
Open(20,FILE=soildatafile,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
! To speed-up the code, 43200x(nscale) blocks of the sib file are read
! at a time. The data is then averaged in memory. This system speeds-up the
! code considerably. However, there are limitations as to the size of data
! that can be stored in memory.
Call solvejshift(latlon(1),jin,jout,30)
Do ilat=1,lldim_4(2)
if ((mod(ilat,50).eq.0).or.(ilat.eq.lldim_4(2))) then
Write(6,*) 'HWSD - ',ilat,'/',lldim_4(2)
end if
! Read data
llint_4(2)=nint((90.-latlon(2))*30.)+(ilat-1)*nscale_4
Do jlat=1,nscale_4
recpos=llint_4(2)+jlat
if ( ncfile ) then
ierr = nf90_get_var(ncid,varid,i4datatemp,start=(/1,recpos/),count=(/10800,1/))
else
Read(20,REC=recpos) datatemp
i4datatemp = datatemp
end if
! Shift lon to zero
databuffer(jin(1,1):jin(1,2),jlat)=i4datatemp(jout(1,1):jout(1,2))
databuffer(jin(2,1):jin(2,2),jlat)=i4datatemp(jout(2,1):jout(2,2))
End Do
Do ilon=1,lldim_4(1)
llint_4(1)=(ilon-1)*nscale_4
dataslice(1:nscale_4,1:nscale_4) = databuffer(llint_4(1)+1:llint_4(1)+nscale_4,1:nscale_4)
Call dataconvert(dataslice(:,:),faosoil,nscale_4,13)
nsum=sum(faosoil(1:13))
if (nsum>0.) then
coverout(ilon,ilat,:)=0.
do i=1,13
coverout(ilon,ilat,masmap(i)-1)=coverout(ilon,ilat,masmap(i)-1)+faosoil(i)/nsum
end do
else
coverout(ilon,ilat,:)=0.
end if
End Do
End Do
if ( ncfile ) then
ierr = nf90_close(ncid)
else
Close(20)
end if
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine reads albedo data down to nscale_4=1
! (i.e., 4km) resolution.
!
Subroutine albedoread(latlon,nscale_4,lldim_4,dataout,datatype,albfilename)
use netcdf_m
Implicit None
Integer, intent(in) :: nscale_4
Integer, dimension(2), intent(in) :: lldim_4
Integer, dimension(10800,1:nscale_4) :: databuffer
Integer*1, dimension(10800) :: datatemp
integer, dimension(10800) :: i4datatemp
Integer, dimension(2) :: llint_4
Integer ilat,ilon,jlat,recpos,ncount
Integer, dimension(2,2) :: jin,jout
integer ncid, varid, ierr
Real, dimension(2), intent(in) :: latlon
Real, dimension(lldim_4(1),lldim_4(2)), intent(out) :: dataout
Character(len=*), intent(in) :: datatype
character(len=*), intent(in) :: albfilename
Character(len=20) :: cmsg
Logical, dimension(nscale_4,nscale_4) :: sermask
logical ncfile
Call solvejshift(latlon(1),jin,jout,30)
select case(datatype)
case ('albvis')
cmsg='Soil albedo (VIS) - '
case ('albnir')
cmsg='Soil albedo (NIR) - '
end select
write(6,*) 'Reading ',trim(albfilename)
ierr = nf90_open(trim(albfilename)//'.nc',nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(albfilename)
ierr = nf90_inq_varid(ncid,datatype,varid)
else
ierr = nf90_open(trim(albfilename),nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(albfilename)
ierr = nf90_inq_varid(ncid,datatype,varid)
else
ncfile = .false.
! Must be compiled using 1 byte record lengths
Open(40,FILE=albfilename,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
Do ilat=1,lldim_4(2)
if ( mod(ilat,50)==0 .or. ilat==lldim_4(2) ) then
Write(6,*) cmsg,ilat,'/',lldim_4(2)
end if
! Read data
llint_4(2)=nint((90.-latlon(2))*30.)+(ilat-1)*nscale_4
Do jlat=1,nscale_4
recpos=llint_4(2)+jlat
if ( ncfile ) then
ierr = nf90_get_var(ncid,varid,i4datatemp,start=(/1,recpos/),count=(/10800,1/))
else
Read(40,REC=recpos) datatemp
i4datatemp = datatemp
end if
! Shift lon to zero
databuffer(jin(1,1):jin(1,2),jlat)=i4datatemp(jout(1,1):jout(1,2))
databuffer(jin(2,1):jin(2,2),jlat)=i4datatemp(jout(2,1):jout(2,2))
End Do
where (databuffer<0)
databuffer=databuffer+256
end where
Do ilon=1,lldim_4(1)
llint_4(1)=(ilon-1)*nscale_4
sermask=(databuffer(llint_4(1)+1:llint_4(1)+nscale_4,1:nscale_4) > 0)
sermask=sermask.and.(databuffer(llint_4(1)+1:llint_4(1)+nscale_4,1:nscale_4) <= 100)
ncount = count(sermask)
if ( ncount > 0 ) then
dataout(ilon,ilat)=real(sum(databuffer(llint_4(1)+1:llint_4(1)+nscale_4,1:nscale_4),sermask)) &
/(real(ncount)*100.)
else
dataout(ilon,ilat)=0. ! missing value flag
end if
End Do
End Do
if ( ncfile ) then
ierr = nf90_close(ncid)
else
Close(40)
end if
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine reads sibsystems data at nscale=1km resolution
! (i.e., no storage, simply read and bin)
!
Subroutine igbpstream(sibdim,coverout,countn,num,month,ozlaipatch,vegfilename,laifilename,class_num,mapjveg)
Use ccinterp
use netcdf_m
Implicit None
logical, intent(in) :: ozlaipatch
integer, intent(in) :: num,month,class_num
Integer, dimension(2), intent(in) :: sibdim
Real, dimension(1:sibdim(1),1:sibdim(2),0:num), intent(out) :: coverout
real, dimension(:,:,:), allocatable :: laiin
Real aglon,aglat,alci,alcj,bx,by,bdelta,tbx,tby,tbdelta
Real callon,callat
Integer, dimension(1:sibdim(1),1:sibdim(2)), intent(out) :: countn
integer, dimension(class_num), intent(in) :: mapjveg
Integer*1, dimension(1:43200) :: databuffer
Integer*1, dimension(1:10800) :: datatemp
Integer*1, dimension(1:43200,1:12) :: lbuff
integer, dimension(43200) :: i4databuffer
integer, dimension(10800) :: i4datatemp
integer, dimension(1:sibdim(1),1:sibdim(2),0:num) :: ncount
Integer ilat,ilon,lci,lcj,nface,ctmp,ltmp,mthrng,imth,lrp,nlrp,k
integer ntmp,ix,iy,tix,tiy,vegtmp,i
integer ierr
integer, dimension(0:12) :: ncid, varid
logical, dimension(0:12) :: ncfile
character*2 cmth
Character*10 fname
character(len=*), intent(in) :: vegfilename, laifilename
coverout=0
countn=0
Write(6,*) "Read USGS + LAI data (stream)"
ierr = nf90_open(trim(vegfilename)//'.nc',nf90_nowrite,ncid(0))
if ( ierr==nf90_noerr ) then
ncfile(0) = .true.
write(6,*) "Found netcdf version ",trim(vegfilename)
ierr = nf90_inq_varid(ncid(0),"vegt",varid(0))
else
ierr = nf90_open(trim(vegfilename),nf90_nowrite,ncid(0))
if ( ierr==nf90_noerr ) then
ncfile(0) = .true.
write(6,*) "Found netcdf version ",trim(vegfilename)
ierr = nf90_inq_varid(ncid(0),"vegt",varid(0))
else
ncfile(0) = .false.
! Must be compiled using 1 byte record lengths
Open(10,FILE=vegfilename,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=43200,STATUS='OLD')
end if
end if
if (month==0) then
mthrng=12
do imth=1,mthrng
write(fname,'("slai",I2.2,".img")') imth
ierr = nf90_open(trim(trim(laifilename)//'/'//fname)//'.nc',nf90_nowrite,ncid(imth))
if ( ierr==nf90_noerr ) then
ncfile(imth) = .true.
write(6,*) "Found netcdf version ",trim(trim(laifilename)//'/'//fname)
ierr = nf90_inq_varid(ncid(imth),"LAI",varid(imth))
else
ierr = nf90_open(trim(laifilename)//'/'//fname,nf90_nowrite,ncid(imth))
if ( ierr==nf90_noerr ) then
ncfile(imth) = .true.
write(6,*) "Found netcdf version ",trim(trim(laifilename)//'/'//fname)
ierr = nf90_inq_varid(ncid(imth),"LAI",varid(imth))
else
ncfile(imth) = .false.
open(10+imth,FILE=trim(laifilename)//'/'//fname,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
end do
else
mthrng=1
ierr = nf90_open(trim(laifilename)//'.nc',nf90_nowrite,ncid(1))
if ( ierr==nf90_noerr ) then
ncfile(1) = .true.
write(6,*) "Found netcdf version ",trim(laifilename)
ierr = nf90_inq_varid(ncid(1),"LAI",varid(1))
else
ierr = nf90_open(trim(laifilename),nf90_nowrite,ncid(1))
if ( ierr==nf90_noerr ) then
ncfile(1) = .true.
write(6,*) "Found netcdf version ",trim(laifilename)
ierr = nf90_inq_varid(ncid(1),"LAI",varid(1))
else
ncfile(1) = .false.
open(11,FILE=laifilename,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
end if
if (ozlaipatch) then
write(6,*) "CSIRO LAI dataset patch"
if (month==0) then
imth=1
else
imth=month
end if
write(cmth,'(I2.2)') imth
open(30,file='aus_lai.'//cmth,STATUS='OLD')
read(30,*) bx,by,bdelta,ix,iy
close(30)
allocate(laiin(ix,iy,mthrng))
if (month.eq.0) then
do imth=1,mthrng
write(cmth,'(I2.2)') imth
open(30,file='aus_lai.'//cmth,STATUS='OLD')
read(30,*) tbx,tby,tbdelta,tix,tiy
if ((tix.ne.ix).or.(tiy.ne.iy).or.(tbx.ne.bx).or.(tby.ne.by).or.(tbdelta.ne.bdelta)) then
write(6,*) "ERROR: LAI data has different dimensions for different months"
call finishbanner
stop -1
end if
read(30,*) laiin(:,:,imth)
close(30)
end do
else
write(cmth,'(I2.2)') imth
write(6,*) 'Open aus_lai.'//cmth
open(30,file='aus_lai.'//cmth,STATUS='OLD')
read(30,*) tbx,tby,tbdelta,tix,tiy
if ((tix.ne.ix).or.(tiy.ne.iy).or.(tbx.ne.bx).or.(tby.ne.by).or.(tbdelta.ne.bdelta)) then
write(6,*) "ERROR: LAI data has different dimensions for different months"
call finishbanner
stop -1
end if
read(30,*) laiin(:,:,1)
close(30)
end if
end if
lrp=-1
Do ilat=1,21600
if (mod(ilat,50).eq.0) then
Write(6,*) 'USGS + LAI - ',ilat,'/ 21600'
end if
! Read data
if ( ncfile(0) ) then
ierr = nf90_get_var(ncid(0),varid(0),i4databuffer,start=(/1,ilat/),count=(/43200,1/))
else
Read(10,REC=ilat) databuffer
i4databuffer = databuffer
end if
aglat=callat(90.,ilat,1)
! read corrosponding lai data and fill to 1km grid
nlrp=int(real(ilat+3)/4.)
if (lrp/=nlrp) then
lrp=nlrp
do imth=1,mthrng
if ( ncfile(imth) ) then
ierr = nf90_get_var(ncid(imth),varid(imth),i4datatemp,start=(/1,lrp/),count=(/10800,1/))
else
read(10+imth,REC=lrp) datatemp
i4datatemp = datatemp
end if
do k=1,10800
lbuff(4*k-3:4*k,imth)=i4datatemp(k)
end do
if (ozlaipatch) then
tiy=nint((by-90.+(real(ilat)-0.5)/120.)/bdelta+0.5)
if ((tiy>=1).and.(tiy<=iy)) then
do k=1,43200
tix=nint(((real(k)-0.5)/120.-180.-bx)/bdelta+0.5)
if ((tix>=1).and.(tix<=ix)) then
lbuff(k,imth)=laiin(tix,tiy,imth)
end if
end do
end if
end if
end do
end if
Do ilon=1,43200
aglon=callon(-180.,ilon,1)
Call lltoijmod(aglon,aglat,alci,alcj,nface)
lci = nint(alci)
lcj = nint(alcj)
lcj = lcj+nface*sibdim(1)
vegtmp=mod(i4databuffer(ilon)+256,256)
if ( vegtmp==0 ) then
ctmp=0
else if ( mapjveg(max(min(vegtmp,class_num),1))==vegtmp ) then
ctmp=max(min(vegtmp,class_num),1)
else
ctmp = -1
do i = 1,class_num
if ( vegtmp==mapjveg(i) ) then
ctmp=i
exit
end if
end do
end if
if (ctmp>=0.and.ctmp<=class_num) then
coverout(lci,lcj,ctmp)=coverout(lci,lcj,ctmp)+1.
ncount(lci,lcj,ctmp)=ncount(lci,lcj,ctmp)+1
countn(lci,lcj)=1
if ( ctmp>0 ) then
do imth=1,mthrng
ltmp=mod(lbuff(ilon,imth)+256,256)
if (ltmp>0.and.ltmp<100) then
coverout(lci,lcj,class_num+(ctmp-1)*mthrng+imth)=coverout(lci,lcj,class_num+(ctmp-1)*mthrng+imth)+real(ltmp)/10.
ncount(lci,lcj,class_num+(ctmp-1)*mthrng+imth)=ncount(lci,lcj,class_num+(ctmp-1)*mthrng+imth)+1
end if
end do
end if
end if
End Do
End Do
do lcj=1,sibdim(2)
do lci=1,sibdim(1)
ncount(lci,lcj,0:class_num)=sum(ncount(lci,lcj,0:class_num))
end do
end do
coverout=coverout/real(max(ncount,1))
if (ozlaipatch) deallocate(laiin)
if ( ncfile(0) ) then
ierr = nf90_close(ncid(0))
else
Close(10)
end if
do imth=1,mthrng
if ( ncfile(imth) ) then
ierr = nf90_close(ncid(imth))
else
close(10+imth)
end if
end do
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine reads soil at nscale_4=1
! (i.e., 4km) resolution.
! (i.e., no storage, simply read and bin)
!
Subroutine soilstream(sibdim,coverout,countn,soilfilename)
Use ccinterp
use netcdf_m
Implicit None
Integer, dimension(2), intent(in) :: sibdim
Real, dimension(sibdim(1),sibdim(2),0:8), intent(out) :: coverout
Real aglon,aglat,alci,alcj
Real callon,callat
Integer, dimension(sibdim(1),sibdim(2)), intent(out) :: countn
Integer*1, dimension(10800) :: databuffer
Integer, dimension(10800) :: i4databuffer
Integer ilat,ilon,lci,lcj,nface,cpos,i
integer ncid, varid, ierr
integer, dimension(0:13), parameter :: masmap=(/ 0, 1, 1, 4, 2, 4, 7, 2, 2, 5, 6, 3, 8, 9 /)
logical ncfile
character(len=*), intent(in) :: soilfilename
coverout=0
countn=0
Write(6,*) "Read HWSD data (stream)"
ierr = nf90_open(trim(soilfilename)//'.nc',nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(soilfilename)
ierr = nf90_inq_varid(ncid,"soilt",varid)
else
ierr = nf90_open(trim(soilfilename),nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(soilfilename)
ierr = nf90_inq_varid(ncid,"soilt",varid)
else
ncfile = .false.
! Must be compiled using 1 byte record lengths
Open(20,FILE=soilfilename,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
Do ilat=1,5400
if (mod(ilat,50).eq.0) then
Write(6,*) 'HWSD - ',ilat,'/ 5400'
end if
! Read data
if ( ncfile ) then
ierr = nf90_get_var(ncid,varid,i4databuffer,start=(/1,ilat/),count=(/10800,1/))
else
Read(20,REC=ilat) databuffer
i4databuffer = databuffer
end if
aglat=callat(90.,ilat,1)
Do ilon=1,10800
aglon=callon(-180.,ilon,1)
Call lltoijmod(aglon,aglat,alci,alcj,nface)
lci = nint(alci)
lcj = nint(alcj)
lcj = lcj+nface*sibdim(1)
cpos=i4databuffer(ilon)
if ((cpos.ge.1).and.(cpos.le.13)) then
If (coverout(lci,lcj,0).LT.0.) then
coverout(lci,lcj,:)=0.
countn(lci,lcj)=0
End If
coverout(lci,lcj,masmap(cpos)-1)=coverout(lci,lcj,masmap(cpos)-1)+1.
countn(lci,lcj)=countn(lci,lcj)+1
else
If (countn(lci,lcj).EQ.0) then
coverout(lci,lcj,:)=-1.
countn(lci,lcj)=1
End if
end if
End Do
End Do
if ( ncfile ) then
ierr = nf90_close(ncid)
else
Close(20)
end if
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine reads albedo at nscale_4=1
! (i.e., 4km) resolution.
! (i.e., no storage, simply read and bin)
!
Subroutine albedostream(sibdim,coverout,countn,datatype,albfilename)
Use ccinterp
use netcdf_m
Implicit None
Integer, dimension(2), intent(in) :: sibdim
Integer, dimension(sibdim(1),sibdim(2)), intent(out) :: countn
Integer, dimension(10800) :: databuffer
Integer*1, dimension(10800) :: datatemp
Integer ilat,ilon,lci,lcj,nface
integer ncid, varid, ierr
Real, dimension(sibdim(1),sibdim(2)), intent(out) :: coverout
Real aglon,aglat,alci,alcj
Real callon,callat
logical ncfile
Character(len=*), intent(in) :: datatype
Character*20 cmsg
character(len=*), intent(in) :: albfilename
coverout=0
countn=0
select case(datatype)
case ('albvis')
cmsg='Soil albedo (VIS) - '
case ('albnir')
cmsg='Soil albedo (NIR) - '
end select
write(6,*) 'Reading (stream) ',trim(albfilename)
ierr = nf90_open(trim(albfilename)//'.nc',nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(albfilename)
ierr = nf90_inq_varid(ncid,datatype,varid)
else
ierr = nf90_open(trim(albfilename),nf90_nowrite,ncid)
if ( ierr==nf90_noerr ) then
ncfile = .true.
write(6,*) "Found netcdf version ",trim(albfilename)
ierr = nf90_inq_varid(ncid,datatype,varid)
else
ncfile = .false.
! Must be compiled using 1 byte record lengths
Open(40,FILE=albfilename,ACCESS='DIRECT',FORM='UNFORMATTED',RECL=10800,STATUS='OLD')
end if
end if
Do ilat=1,5400
aglat=callat(90.,ilat,4)
if (mod(ilat,50).eq.0) then
Write(6,*) cmsg,ilat,'/ 5400'
end if
! Read data
if ( ncfile ) then
ierr = nf90_get_var(ncid,varid,databuffer,start=(/1,ilat/),count=(/10800,1/))
else
Read(40,REC=ilat) datatemp
databuffer = datatemp
end if
where (databuffer<0)
databuffer=databuffer+256
end where
Do ilon=1,10800
aglon=callon(-180.,ilon,4)
Call lltoijmod(aglon,aglat,alci,alcj,nface)
lci = nint(alci)
lcj = nint(alcj)
lcj = lcj+nface*sibdim(1)
If (databuffer(ilon).LE.100) then
If (coverout(lci,lcj).LT.0.) then
coverout(lci,lcj)=0.
countn(lci,lcj)=0
End If
coverout(lci,lcj)=coverout(lci,lcj)+real(databuffer(ilon))/100.
countn(lci,lcj)=countn(lci,lcj)+1
Else
If (countn(lci,lcj).EQ.0) then
coverout(lci,lcj)=-1.
countn(lci,lcj)=1
End if
End if
End Do
End Do
if ( ncfile ) then
ierr = nf90_close(ncid)
else
Close(40)
end if
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine aligns the data with the requested lat/lon
!
Subroutine solvejshift(lonin,jin,jout,nscale)
Implicit None
Real, intent(in) :: lonin
Integer, intent(in) :: nscale
Integer, dimension(1:2,1:2), intent(out) :: jin,jout
Integer jshift
jshift=Mod(nint(lonin*real(nscale))+180*nscale,360*nscale)
If (jshift.LT.0) jshift=jshift+360*nscale
jin(1,1)=1
jout(1,1)=Mod(jin(1,1)+jshift,360*nscale)
If (jout(1,1).EQ.0) jout(1,1)=360*nscale
jout(1,2)=360*nscale
jin(1,2)=jout(1,2)-jout(1,1)+jin(1,1)
jin(2,1)=jin(1,2)+1
jin(2,2)=360*nscale
jout(2,1)=1
jout(2,2)=jout(1,1)-1
If (jin(2,1).GT.jin(2,2)) then
jin(2,:)=jin(1,:)
jout(2,:)=jout(1,:)
End if
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine groups tile data
!
Subroutine dataconvert(datain,raw,nscale,num)
Implicit None
Integer, intent(in) :: nscale,num
Integer, dimension(1:nscale,1:nscale), intent(in) :: datain
Real, dimension(0:num), intent(out) :: raw
Integer i,j,datatmp
! Aggregate land use
! Faster to step over grid once
raw=0.
Do j=1,nscale
Do i=1,nscale
datatmp=datain(i,j)
datatmp=mod(datatmp+256,256)
raw(datatmp)=raw(datatmp)+1.
End Do
End Do
raw=raw/real(nscale**2)
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine converts from 1km nscale to adj km nscale
!
Subroutine kmconvert(nscale,nscale_x,lldim,lldim_x,adj)
Implicit None
Integer, intent(in) :: nscale,adj
Integer, intent(out) :: nscale_x
Integer, dimension(1:2), intent(in) :: lldim
Integer, dimension(1:2), intent(out) :: lldim_x
Integer i
nscale_x=Int(nscale/adj)
If (nscale_x.LT.1) nscale_x=1
Do i=1,2
lldim_x(i)=Int(Real(lldim(i))*Real(nscale)/(Real(nscale_x)*real(adj)))
If (lldim_x(i).LT.1) lldim_x(i)=1
End Do
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine determines how many subsections (blocks) the data
! needs to be broken into so as to fit into memory (i.e., sibsize)
!
Subroutine scaleconvert(nscale,subsec,lldim,sll,sibsize)
Implicit None
Integer, intent(out) :: subsec
Integer, intent(in) :: nscale,sibsize
Integer, dimension(1:2), intent(out) :: lldim
Real, dimension(1:2,1:2), intent(in) :: sll
Integer i,j
i=nint((sll(1,2)-sll(1,1))*120./Real(nscale))
j=nint((sll(2,2)-sll(2,1))*120./Real(nscale))
subsec=int(sqrt(real(i)*real(j)/(real(sibsize)**2)))+1
subsec=max(subsec,1)
lldim(1)=nint(real(i)/real(subsec))
lldim(2)=nint(real(j)/real(subsec))
If ((real(lldim(1)*nscale*subsec)).LT.((sll(1,2)-sll(1,1))*120.)) lldim(1)=lldim(1)+1
If ((real(lldim(2)*nscale*subsec)).LT.((sll(2,2)-sll(2,1))*120.)) lldim(2)=lldim(2)+1
If ((nint((90.-sll(2,2))*120.)+lldim(2)*nscale).GT.21600) lldim(2)=(21600-nint((90.-sll(2,2))*120.))/nscale
If ((lldim(1)*nscale).GT.43200) lldim(1)=43200/nscale
If ((lldim(1).LT.1).OR.(lldim(2).LT.1)) Then
lldim=(/ 0, 0 /)
subsec=0
End If
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine adjusts the latlon array for a specified subsection
!
Subroutine latlonconvert(nscale,latlon,lldim,slonn,slatx,nx,ny)
Implicit None
Integer, intent(in) :: nscale
Real, dimension(1:2), intent(out) :: latlon
Integer, dimension(1:2), intent(in) :: lldim
Real, intent(in) :: slonn,slatx
Integer, intent(in) :: nx,ny
latlon=(/ slonn+Real((nx-1)*lldim(1)*nscale)/120., slatx-Real((ny-1)*lldim(2)*nscale)/120. /)
if (latlon(2).LT.-90.) latlon(2)=-90.
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This function calculates lon from an array index
!
Real function callon(latlon,i,nscale)
Implicit None
Real, intent(in) :: latlon
Integer, intent(in) :: i,nscale
callon=(Real(i-1)+0.5)*real(nscale)/120.+latlon
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This function rounds up
!
Integer Function rndup(x)
Implicit None
Real, intent(in) :: x
rndup=int(x)
if (x>real(rndup)) rndup=rndup+1
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This function calculates lat from an array index
!
Real function callat(latlon,i,nscale)
Implicit None
Real, intent(in) :: latlon
Integer, intent(in) :: i,nscale
callat=latlon-(Real(i-1)+0.5)*real(nscale)/120.
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This function calculates the array index for a specified lon
!
Real function indexlon(aglon,latlon,nscale)
Implicit None
Real, intent(in) :: aglon,latlon
Integer, intent(in) :: nscale
indexlon=(aglon-latlon)*120./real(nscale)+0.5
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This function calculates the array index for a specified lat
!
Real function indexlat(aglat,latlon,nscale)
Implicit None
Real, intent(in) :: aglat,latlon
Integer, intent(in) :: nscale
indexlat=(-aglat+latlon)*120./real(nscale)+0.5
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine determines the boundary of a subsection for a
! specified scale.
!
Subroutine searchdim(mode,sll,nscale,scalelimit,latlon,lldim,grid,maskn,rlld,sibdim)
Implicit None
Integer, intent(in) :: mode,nscale
Integer, dimension(1:2), intent(in) :: lldim,sibdim
Real, intent(in) :: scalelimit
Real, dimension(1:2,1:2), intent(out) :: sll
Real, dimension(1:2), intent(in) :: latlon
Real, dimension(1:sibdim(1),1:sibdim(2)), intent(in) :: grid
Real, dimension(1:sibdim(1),1:sibdim(2),1:2), intent(in) :: rlld
Real, dimension(1:sibdim(1),1:sibdim(2),1:2) :: tlld
Real, dimension(1:2,1:2) :: templl
Integer, dimension(1:2,1:2,1:2) :: posll
Integer i,j
Integer rndup
Logical, dimension(1:sibdim(1),1:sibdim(2)) :: sermask
Logical, dimension(1:sibdim(1),1:sibdim(2)), intent(in) :: maskn
tlld=rlld
templl(1,1)=latlon(1)
templl(1,2)=latlon(1)+real(lldim(1)*nscale)/120.
templl(2,2)=latlon(2)
templl(2,1)=latlon(2)-real(lldim(2)*nscale)/120.
Do i=1,2
If (templl(2,i).LT.-90.) templl(2,i)=-90.
If (templl(2,i).GT.90.) templl(2,i)=90.
End Do
sermask=(tlld(:,:,1).GE.templl(1,1)).AND.(tlld(:,:,1).LE.templl(1,2)) &
.AND.(tlld(:,:,2).GE.templl(2,1)).AND.(tlld(:,:,2).LE.templl(2,2))
sermask=sermask.AND.maskn
Select Case(mode)
Case(0)
! Use all grid points
sll=templl
Return
Case(1)
sermask=sermask.AND.(grid.LE.scalelimit)
Case(2)
sermask=sermask.AND.(grid.GE.scalelimit)
Case(3)
sermask=sermask.AND.(grid.EQ.scalelimit)
Case(4)
! Do nothing
Case Default
Write(6,*) 'ERROR: Internal error. Unsupported mode in searchdim'
call finishbanner
Stop -1
End Select
If (.NOT.Any(sermask)) then
sll=0.
Return
End if
sll(1,2)=Maxval(tlld(:,:,1),sermask)
sll(1,1)=Minval(tlld(:,:,1),sermask)
sll(2,2)=Maxval(tlld(:,:,2),sermask)
sll(2,1)=Minval(tlld(:,:,2),sermask)
posll(1,2,:)=Maxloc(tlld(:,:,1),sermask)
posll(1,1,:)=Minloc(tlld(:,:,1),sermask)
posll(2,2,:)=Maxloc(tlld(:,:,2),sermask)
posll(2,1,:)=Minloc(tlld(:,:,2),sermask)
Do i=1,2
Do j=1,2
! 1.6 is assumed to span from the centre to the corner (i.e., sqrt(2) if
! using a square grid)
sll(i,j)=sll(i,j)+Real(j*2-3)*grid(posll(i,j,1),posll(i,j,2))*1.6/240.
End Do
End Do
sll(1,1)=real(int((sll(1,1)-latlon(1))*120./real(nscale)))*real(nscale)/120.+latlon(1)
sll(1,2)=real(rndup((sll(1,2)-latlon(1))*120./real(nscale)))*real(nscale)/120.+latlon(1)
sll(2,1)=-real(rndup((latlon(2)-sll(2,1))*120./real(nscale)))*real(nscale)/120.+latlon(2)
sll(2,2)=-real(int((latlon(2)-sll(2,2))*120./real(nscale)))*real(nscale)/120.+latlon(2)
! Check bounds
Do i=1,2
sll(i,1)=max(sll(i,1),templl(i,1))
sll(i,2)=min(sll(i,2),templl(i,2))
End Do
! Consistancy check
If ((sll(1,1).GT.sll(1,2)).OR.(sll(2,1).GT.sll(2,2))) then
sll=0.
End If
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This subroutine calculates the next scale to load. The suboutine
! attempts to minimise the number of times the sibveg data is loaded.
!
Subroutine findsmallscale(nscale,scalelimit,latlon,llstore,grid,maskn,rlld,subsec,sll,sibsize,sibdim)
Implicit None
Integer, intent(in) :: sibsize,scalelimit
Integer, dimension(1:2), intent(in) :: sibdim
Integer, intent(inout) :: nscale
Integer, intent(out) :: subsec
Integer, dimension(1:2), intent(out) :: llstore
Real, dimension(1:sibdim(1),1:sibdim(2)), intent(in) :: grid
Real, dimension(1:sibdim(1),1:sibdim(2),1:2), intent(in) :: rlld
Real, dimension(1:2), intent(in) :: latlon
Real, dimension(1:2,1:2), intent(out) :: sll
Real tscale
Integer mode,maxscale,subsecmax
Integer findfact
Logical, dimension(1:sibdim(1),1:sibdim(2)), intent(in) :: maskn
tscale=Maxval(grid,maskn)
mode=1
If (nscale==999) mode=0
maxscale=Int(0.5*real(nscale)/Real(scalelimit))*scalelimit
maxscale=findfact(21600,maxscale,-scalelimit)
If (maxscale.LT.scalelimit) maxscale=scalelimit
llstore=(/ 43200/maxscale , 21600/maxscale /)
Call searchdim(mode,sll,maxscale,tscale,latlon,llstore,grid,maskn,rlld,sibdim)
Call scaleconvert(maxscale,subsecmax,llstore,sll,sibsize)
If (subsecmax<1) Then
Write(6,*) "WARN: Cannot locate unassigned points in findsmallscale"
mode=0
nscale=maxscale
Else
nscale=Int(Minval(grid,maskn)/Real(scalelimit))*scalelimit
nscale=findfact(21600,nscale,-scalelimit)
nscale=max(nscale,scalelimit)
subsec=subsecmax+1
Do While (subsec>subsecmax)
! Get estimate of array size
llstore=(/ 43200/nscale , 21600/nscale /)
! Calculate domain for search
Call searchdim(mode,sll,nscale,tscale,latlon,llstore,grid,maskn,rlld,sibdim)
! Define number of points in domain and subdivide into tiles if array is too big
Call scaleconvert(nscale,subsec,llstore,sll,sibsize)
If (subsec>subsecmax) Then
nscale=nscale+scalelimit
nscale=findfact(21600,nscale,scalelimit)
End If
End Do
End If
nscale=min(nscale,maxscale)
nscale=max(nscale,scalelimit)
llstore=(/ 43200/nscale , 21600/nscale /)
! Calculate domain for search
Call searchdim(mode,sll,nscale,tscale,latlon,llstore,grid,maskn,rlld,sibdim)
! Define number of points in domain and subdivide into tiles if array is too big
Call scaleconvert(nscale,subsec,llstore,sll,sibsize)
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! This function finds the nearest factor of an integer
!
Integer Function findfact(x,y,delta)
Implicit None
Integer, intent(in) :: x,y,delta
Integer z
z=y
If (z==0) Then
findfact=1
Return
End If
Do While (Mod(x,z)/=0.)
z=z+delta
z=max(z,1)
z=min(z,x)
End Do
findfact=z
Return
End
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Calculate zobler soil texture from FAO
!
subroutine calsoilnear(landdata,soildata,lsdata,sibdim,tdata,class_num,mapwater,mapice)
implicit none
integer, intent(in) :: class_num
integer, dimension(1:2), intent(in) :: sibdim
integer, dimension(1:sibdim(1),1:sibdim(2)), intent(out) :: tdata
real, dimension(1:sibdim(1),1:sibdim(2),0:17), intent(in) :: landdata
real, dimension(1:sibdim(1),1:sibdim(2),0:8), intent(in) :: soildata
real, dimension(1:sibdim(1),1:sibdim(2)), intent(in) :: lsdata
real testdata
integer ilon,ilat,pos(1),i
logical, dimension(class_num), intent(in) :: mapwater, mapice
do ilon=1,sibdim(1)
do ilat=1,sibdim(2)
pos=Maxloc(landdata(ilon,ilat,1:class_num),.not.mapwater)
if (1-nint(lsdata(ilon,ilat))==0) then
testdata=sum(landdata(ilon,ilat,1:class_num),mapwater)
if (landdata(ilon,ilat,0)>=testdata) then
tdata(ilon,ilat)=0 ! ocean
else
tdata(ilon,ilat)=-1 ! in-land water
end if
else if ( mapice(pos(1)) ) then
tdata(ilon,ilat)=9 ! ice
else
pos=Maxloc(soildata(ilon,ilat,:))
tdata(ilon,ilat)=pos(1)
end if
end do
end do
return
end
subroutine modifylanddata(dataout,glonlat,sibdim,num,month,datafilename,laifilename,class_num, &
mapjveg)
use ccinterp
use netcdf_m
implicit none
integer, intent(in) :: num, month, class_num
integer, dimension(2), intent(in) :: sibdim
integer, dimension(2) :: dimid, dimlen
integer, dimension(3) :: dimid_lai, dimlen_lai
integer, dimension(3) :: start, ncount
integer, dimension(sibdim(1),sibdim(2)) :: countlocal
integer, dimension(class_num), intent(in) :: mapjveg
integer ncid, ncidlai, varid, ierr
integer lci, lcj, nface, iveg, imonth
integer i, j, vegtmp, k, varndims
integer missing_int
real, dimension(sibdim(1),sibdim(2),0:num), intent(inout) :: dataout
real, dimension(sibdim(1),sibdim(2),0:num) :: datalocal
real, dimension(sibdim(1),sibdim(2),12) :: lailocal
real, dimension(2), intent(in) :: glonlat
real, dimension(:), allocatable :: lonin, latin, lonin_lai, latin_lai
real, dimension(:,:,:), allocatable :: laiin
real aglon, aglat, alci, alcj
real missing_real
integer, dimension(:,:), allocatable :: coverin
character(len=*), intent(in) :: datafilename, laifilename
character(len=1024), dimension(3) :: dimname
logical found_missing
missing_int = -1
missing_real = -1.
! Veg file parameters
if ( datafilename/='' ) then
ierr = nf_open(datafilename,nf_nowrite,ncid)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot open user veg file ",trim(datafilename)
call finishbanner
stop -1
end if
ierr = nf_inq_varid(ncid,'land_cover',varid)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot locate land_cover variable in veg file ",trim(datafilename)
call finishbanner
stop -1
end if
found_missing = .false.
ierr = nf_get_att_int(ncid,varid,"missing_value",missing_int)
if ( ierr==nf_noerr ) then
found_missing = .true.
else
ierr = nf_get_att_int(ncid,varid,"_FillValue",missing_int)
if ( ierr==nf_noerr ) then
found_missing = .true.
end if
end if
if ( found_missing ) then
write(6,*) "Found missing value ",missing_int
end if
ierr = nf_inq_vardimid(ncid,varid,dimid(1:2))
ierr = nf_inq_dim(ncid,dimid(1),dimname(1),dimlen(1))
ierr = nf_inq_dim(ncid,dimid(2),dimname(2),dimlen(2))
ierr = nf_inq_varndims(ncid,varid,varndims)
write(6,*) "Reading land_cover data from ",trim(datafilename)
write(6,*) "Found size ",dimlen(1:2)
allocate( coverin(dimlen(1),dimlen(2)), lonin(dimlen(1)), latin(dimlen(2)) )
select case(varndims)
case(2)
start(1:2) = 1
ncount(1:2) = dimlen(1:2)
ierr = nf_get_vara_int(ncid,varid,start(1:2),ncount(1:2),coverin)
case(3)
start(1:3) = 1
ncount(1:2) = dimlen(1:2)
ncount(3) = 1
ierr = nf_get_vara_int(ncid,varid,start(1:3),ncount(1:3),coverin)
case default
write(6,*) "ERROR: Cannot process land_cover data with ndims ",varndims
call finishbanner
stop -1
end select
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot read land_cover data"
write(6,*) nf_strerror(ierr)
call finishbanner
stop -1
end if
ierr = nf_inq_varid(ncid,trim(dimname(1)),varid)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot locate coordinate information for ",trim(dimname(1))
call finishbanner
stop -1
end if
ierr = nf_get_vara_real(ncid,varid,start(1:1),ncount(1:1),lonin)
ierr = nf_inq_varid(ncid,trim(dimname(2)),varid)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot locate coordinate information for ",trim(dimname(2))
call finishbanner
stop -1
end if
ierr = nf_get_vara_real(ncid,varid,start(2:2),ncount(2:2),latin)
! Process land-cover
write(6,*) "Processing land-cover data"
datalocal(:,:,:) = 0.
countlocal(:,:) = 0
do j = 1,dimlen(2)
aglat = latin(j)
do i = 1,dimlen(1)
aglon = lonin(i)
call lltoijmod(aglon,aglat,alci,alcj,nface)
lci = nint(alci)
lcj = nint(alcj)
lcj = lcj + nface*sibdim(1)
vegtmp = coverin(i,j)
if ( vegtmp==0 ) then
iveg=0
else if ( mapjveg(max(min(vegtmp,class_num),1))==vegtmp ) then
iveg=max(min(vegtmp,class_num),1)
else if ( found_missing .and. vegtmp==missing_int ) then
! missing
iveg = -1
else
iveg = -1
do k = 1,class_num
if ( mapjveg(k)==coverin(i,j) ) then
iveg = k
exit
end if
end do
if ( iveg==-1 ) then
write(6,*) "ERROR: land_cover data is not defined in mapping data"
write(6,*) "Invalid land_cover index ",coverin(i,j)," at lat,lon=",aglat,aglon
write(6,*) "Valid indices are ",mapjveg(1:class_num)
call finishbanner
stop -1
end if
end if
if ( iveg>=0 .and. iveg<=class_num ) then
datalocal(lci,lcj,iveg) = datalocal(lci,lcj,iveg) + 1.
countlocal(lci,lcj) = countlocal(lci,lcj) + 1
end if
end do
if ( mod(j,10)==0 .or. j==dimlen(2) ) then
write(6,*) "User land_cover ",j,"/",dimlen(2)
end if
end do
! Average LAI before redistributing vegetation classes
lailocal(:,:,:) = 0.
if ( month==0 ) then
do imonth = 1,12
do iveg = 1,class_num
lailocal(:,:,imonth) = lailocal(:,:,imonth) + dataout(:,:,iveg)*dataout(:,:,class_num+(iveg-1)*12+imonth)
end do
do iveg = 1,class_num
where ( countlocal(:,:)>0 )
dataout(:,:,class_num+(iveg-1)*12+imonth) = lailocal(:,:,imonth)
end where
end do
end do
else
do iveg = 1,class_num
lailocal(:,:,month) = lailocal(:,:,month) + dataout(:,:,iveg)*dataout(:,:,class_num+(iveg-1)+1)
end do
do iveg = 1,class_num
where ( countlocal(:,:)>0 )
dataout(:,:,class_num+(iveg-1)+1) = lailocal(:,:,month)
end where
end do
end if
! replace dataout with non-trival input data
do iveg = 0,class_num
where ( countlocal(:,:)>0 )
dataout(:,:,iveg) = datalocal(:,:,iveg)/real(countlocal(:,:))
end where
end do
deallocate( coverin, lonin, latin )
ierr = nf_close(ncid)
end if
! LAI file parameters
if ( laifilename/='' ) then
ierr = nf_open(laifilename,nf_nowrite,ncidlai)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot open user lai file ",trim(laifilename)
call finishbanner
stop -1
end if
ierr = nf_inq_varid(ncidlai,'LAI',varid)
if ( ierr/=nf_noerr ) ierr = nf_inq_varid(ncidlai,'lai',varid)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot locate LAI variable in lai file ",trim(laifilename)
call finishbanner
stop -1
end if
found_missing = .false.
ierr = nf_get_att_real(ncidlai,varid,"missing_value",missing_real)
if ( ierr==nf_noerr ) then
found_missing = .true.
else
ierr = nf_get_att_real(ncidlai,varid,"_FillValue",missing_real)
if ( ierr==nf_noerr ) then
found_missing = .true.
end if
end if
if ( found_missing ) then
write(6,*) "Found missing value ",missing_real
end if
ierr = nf_inq_vardimid(ncidlai,varid,dimid_lai(1:3))
ierr = nf_inq_dim(ncidlai,dimid_lai(1),dimname(1),dimlen_lai(1))
ierr = nf_inq_dim(ncidlai,dimid_lai(2),dimname(2),dimlen_lai(2))
ierr = nf_inq_dim(ncidlai,dimid_lai(3),dimname(3),dimlen_lai(3))
write(6,*) "Reading land_cover data from ",trim(laifilename)
write(6,*) "Found size ",dimlen_lai(1:3)
if ( month==0 ) then
if ( dimlen_lai(3)/=12 ) then
write(6,*) "ERROR: Require 12 months of LAI data when using month=0"
call finishbanner
stop -1
end if
start(3) = 1
ncount(3) = 12
else
if ( dimlen_lai(3)==12 ) then
start(3) = month
ncount(3) = 1
dimlen_lai(3) = 1
else
start(3) = 1
ncount(3) = 1
end if
end if
allocate( laiin(dimlen_lai(1),dimlen_lai(2),dimlen_lai(3)) )
allocate( lonin_lai(dimlen_lai(1)), latin_lai(dimlen_lai(2)) )
start(1:2) = 1
ncount(1:2) = dimlen_lai(1:2)
ierr = nf_get_vara_real(ncidlai,varid,start(1:3),ncount(1:3),laiin)
ierr = nf_inq_varid(ncidlai,trim(dimname(1)),varid)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot locate coordinate information for ",trim(dimname(1))
call finishbanner
stop -1
end if
ierr = nf_get_vara_real(ncidlai,varid,start(1:1),ncount(1:1),lonin_lai)
ierr = nf_inq_varid(ncidlai,trim(dimname(2)),varid)
if ( ierr/=nf_noerr ) then
write(6,*) "ERROR: Cannot locate coordinate information for ",trim(dimname(2))
call finishbanner
stop -1
end if
ierr = nf_get_vara_real(ncidlai,varid,start(2:2),ncount(2:2),latin_lai)
! Process user defined input data
write(6,*) "Processing LAI data"
lailocal(:,:,:) = 0.
countlocal(:,:) = 0
do j = 1,dimlen_lai(2)
aglat = latin_lai(j)
do i = 1,dimlen_lai(1)
aglon = lonin_lai(i)
call lltoijmod(aglon,aglat,alci,alcj,nface)
lci = nint(alci)
lcj = nint(alcj)
lcj = lcj+nface*sibdim(1)
if ( .not.found_missing .or. all( laiin(i,j,1:dimlen_lai(3))/=missing_real ) ) then
lailocal(lci,lcj,1:dimlen_lai(3)) = lailocal(lci,lcj,1:dimlen_lai(3)) + laiin(i,j,1:dimlen_lai(3))
countlocal(lci,lcj) = countlocal(lci,lcj) + 1
end if
end do
if ( mod(j,10)==0 .or. j==dimlen_lai(2) ) then
write(6,*) "User LAI ",j,"/",dimlen_lai(2)
end if
end do
! replace dataout with non-trival input data
if ( month==0 ) then
do iveg = 1,class_num
do imonth = 1,12
where ( countlocal(:,:)>0 )
dataout(:,:,class_num+(iveg-1)*12+imonth) = lailocal(:,:,imonth)/real(countlocal(:,:))
end where
end do
end do
else if ( dimlen_lai(3)==12 ) then
do iveg = class_num+1,num
where ( countlocal(:,:)>0 )
dataout(:,:,iveg) = lailocal(:,:,month)/real(countlocal(:,:))
end where
end do
else
do iveg = class_num+1,num
where ( countlocal(:,:)>0 )
dataout(:,:,iveg) = lailocal(:,:,1)/real(countlocal(:,:))
end where
end do
end if
deallocate( laiin, lonin_lai, latin_lai )
ierr = nf_close(ncidlai)
end if
write(6,*) "Finished reading user defined datasets"
return
end subroutine modifylanddata