subroutine misspack(fld,ndpts,idrsnum,idrstmpl,cpack,lcpack) !$$$ SUBPROGRAM DOCUMENTATION BLOCK ! . . . . ! SUBPROGRAM: misspack ! PRGMMR: Gilbert ORG: W/NP11 DATE: 2000-06-21 ! ! ABSTRACT: This subroutine packs up a data field using a complex ! packing algorithm as defined in the GRIB2 documention. It ! supports GRIB2 complex packing templates with or without ! spatial differences (i.e. DRTs 5.2 and 5.3). ! It also fills in GRIB2 Data Representation Template 5.2 or 5.3 ! with the appropriate values. ! This version assumes that Missing Value Management is being used and that ! 1 or 2 missing values appear in the data. ! ! PROGRAM HISTORY LOG: ! 2000-06-21 Gilbert ! 2004-12-29 Gilbert - Corrected bug when encoding secondary missing values. ! 2012-05-10 Boi Vuong Added variable rmin4 for 4 byte real ! ! USAGE: CALL misspack(fld,ndpts,idrsnum,idrstmpl,cpack,lcpack) ! INPUT ARGUMENT LIST: ! fld() - Contains the data values to pack ! ndpts - The number of data values in array fld() ! idrsnum - Data Representation Template number 5.N ! Must equal 2 or 3. ! idrstmpl - Contains the array of values for Data Representation ! Template 5.2 or 5.3 ! (1) = Reference value - ignored on input ! (2) = Binary Scale Factor ! (3) = Decimal Scale Factor ! . ! . ! (7) = Missing value management ! (8) = Primary missing value ! (9) = Secondary missing value ! . ! . ! (17) = Order of Spatial Differencing ( 1 or 2 ) ! . ! . ! ! OUTPUT ARGUMENT LIST: ! idrstmpl - Contains the array of values for Data Representation ! Template 5.3 ! (1) = Reference value - set by misspack routine. ! (2) = Binary Scale Factor - unchanged from input ! (3) = Decimal Scale Factor - unchanged from input ! . ! . ! cpack - The packed data field (character*1 array) ! lcpack - length of packed field cpack(). ! ! REMARKS: None ! ! ATTRIBUTES: ! LANGUAGE: XL Fortran 90 ! MACHINE: IBM SP ! !$$$ integer,intent(in) :: ndpts,idrsnum real,intent(in) :: fld(ndpts) character(len=1),intent(out) :: cpack(*) integer,intent(inout) :: idrstmpl(*) integer,intent(out) :: lcpack real(4) :: ref, rmin4 integer(4) :: iref integer,allocatable :: ifld(:),ifldmiss(:),jfld(:) integer,allocatable :: jmin(:),jmax(:),lbit(:) integer,parameter :: zero=0 integer,allocatable :: gref(:),gwidth(:),glen(:) integer :: glength,grpwidth logical :: simple_alg = .false. alog2=alog(2.0) bscale=2.0**real(-idrstmpl(2)) dscale=10.0**real(idrstmpl(3)) missopt=idrstmpl(7) if ( missopt.ne.1 .AND. missopt.ne.2 ) then print *,'misspack: Unrecognized option.' lcpack=-1 return else ! Get missing values call rdieee(idrstmpl(8),rmissp,1) if (missopt.eq.2) call rdieee(idrstmpl(9),rmisss,1) endif ! ! Find min value of non-missing values in the data, ! AND set up missing value mapping of the field. ! allocate(ifldmiss(ndpts)) c rmin=huge(rmin) if (missopt.eq.1 .and. fld(1).ne.rmissp) then rmin=huge(rmin) endif if ( missopt.eq.2 .and. fld(1).ne.rmisss) then rmin=huge(rmin) endif if ( missopt .eq. 1 ) then ! Primary missing value only do j=1,ndpts if (fld(j).eq.rmissp) then ifldmiss(j)=1 else ifldmiss(j)=0 if (fld(j).lt.rmin) rmin=fld(j) endif enddo endif if ( missopt .eq. 2 ) then ! Primary and secondary missing values do j=1,ndpts if (fld(j).eq.rmissp) then ifldmiss(j)=1 elseif (fld(j).eq.rmisss) then ifldmiss(j)=2 else ifldmiss(j)=0 if (fld(j).lt.rmin) rmin=fld(j) endif enddo endif ! ! Allocate work arrays: ! Note: -ifldmiss(j),j=1,ndpts is a map of original field indicating ! which of the original data values ! are primary missing (1), sencondary missing (2) or non-missing (0). ! -jfld(j),j=1,nonmiss is a subarray of just the non-missing values from ! the original field. ! !if (rmin.ne.rmax) then iofst=0 allocate(ifld(ndpts)) allocate(jfld(ndpts)) allocate(gref(ndpts)) allocate(gwidth(ndpts)) allocate(glen(ndpts)) ! ! Scale original data ! nonmiss=0 if (idrstmpl(2).eq.0) then ! No binary scaling imin=nint(rmin*dscale) !imax=nint(rmax*dscale) rmin=real(imin) do j=1,ndpts if (ifldmiss(j).eq.0) then nonmiss=nonmiss+1 jfld(nonmiss)=nint(fld(j)*dscale)-imin endif enddo else ! Use binary scaling factor rmin=rmin*dscale !rmax=rmax*dscale do j=1,ndpts if (ifldmiss(j).eq.0) then nonmiss=nonmiss+1 jfld(nonmiss)=nint(((fld(j)*dscale)-rmin)*bscale) endif enddo endif ! ! Calculate Spatial differences, if using DRS Template 5.3 ! if (idrsnum.eq.3) then ! spatial differences if (idrstmpl(17).ne.1.and.idrstmpl(17).ne.2) idrstmpl(17)=2 if (idrstmpl(17).eq.1) then ! first order ival1=jfld(1) do j=nonmiss,2,-1 jfld(j)=jfld(j)-jfld(j-1) enddo jfld(1)=0 elseif (idrstmpl(17).eq.2) then ! second order ival1=jfld(1) ival2=jfld(2) do j=nonmiss,3,-1 jfld(j)=jfld(j)-(2*jfld(j-1))+jfld(j-2) enddo jfld(1)=0 jfld(2)=0 endif ! ! subtract min value from spatial diff field ! isd=idrstmpl(17)+1 minsd=minval(jfld(isd:nonmiss)) do j=isd,nonmiss jfld(j)=jfld(j)-minsd enddo ! ! find num of bits need to store minsd and add 1 extra bit ! to indicate sign ! temp=alog(real(abs(minsd)+1))/alog2 nbitsd=ceiling(temp)+1 ! ! find num of bits need to store ifld(1) ( and ifld(2) ! if using 2nd order differencing ) ! maxorig=ival1 if (idrstmpl(17).eq.2.and.ival2.gt.ival1) maxorig=ival2 temp=alog(real(maxorig+1))/alog2 nbitorig=ceiling(temp)+1 if (nbitorig.gt.nbitsd) nbitsd=nbitorig ! increase number of bits to even multiple of 8 ( octet ) if (mod(nbitsd,8).ne.0) nbitsd=nbitsd+(8-mod(nbitsd,8)) ! ! Store extra spatial differencing info into the packed ! data section. ! if (nbitsd.ne.0) then ! pack first original value if (ival1.ge.0) then call sbyte(cpack,ival1,iofst,nbitsd) iofst=iofst+nbitsd else call sbyte(cpack,1,iofst,1) iofst=iofst+1 call sbyte(cpack,iabs(ival1),iofst,nbitsd-1) iofst=iofst+nbitsd-1 endif if (idrstmpl(17).eq.2) then ! pack second original value if (ival2.ge.0) then call sbyte(cpack,ival2,iofst,nbitsd) iofst=iofst+nbitsd else call sbyte(cpack,1,iofst,1) iofst=iofst+1 call sbyte(cpack,iabs(ival2),iofst,nbitsd-1) iofst=iofst+nbitsd-1 endif endif ! pack overall min of spatial differences if (minsd.ge.0) then call sbyte(cpack,minsd,iofst,nbitsd) iofst=iofst+nbitsd else call sbyte(cpack,1,iofst,1) iofst=iofst+1 call sbyte(cpack,iabs(minsd),iofst,nbitsd-1) iofst=iofst+nbitsd-1 endif endif !print *,'SDp ',ival1,ival2,minsd,nbitsd endif ! end of spatial diff section ! ! Expand non-missing data values to original grid. ! miss1=minval(jfld(1:nonmiss))-1 miss2=miss1-1 n=0 do j=1,ndpts if ( ifldmiss(j).eq.0 ) then n=n+1 ifld(j)=jfld(n) elseif ( ifldmiss(j).eq.1 ) then ifld(j)=miss1 elseif ( ifldmiss(j).eq.2 ) then ifld(j)=miss2 endif enddo ! ! Determine Groups to be used. ! if ( simple_alg ) then ! set group length to 10 : calculate number of groups ! and length of last group ngroups=ndpts/10 glen(1:ngroups)=10 itemp=mod(ndpts,10) if (itemp.ne.0) then ngroups=ngroups+1 glen(ngroups)=itemp endif else ! Use Dr. Glahn's algorithm for determining grouping. ! kfildo=6 minpk=10 inc=1 maxgrps=(ndpts/minpk)+1 allocate(jmin(maxgrps)) allocate(jmax(maxgrps)) allocate(lbit(maxgrps)) call pack_gp(kfildo,ifld,ndpts,missopt,minpk,inc,miss1,miss2, & jmin,jmax,lbit,glen,maxgrps,ngroups,ibit,jbit, & kbit,novref,lbitref,ier) !print *,'SAGier = ',ier,ibit,jbit,kbit,novref,lbitref do ng=1,ngroups glen(ng)=glen(ng)+novref enddo deallocate(jmin) deallocate(jmax) deallocate(lbit) endif ! ! For each group, find the group's reference value (min) ! and the number of bits needed to hold the remaining values ! n=1 do ng=1,ngroups ! how many of each type? num0=count(ifldmiss(n:n+glen(ng)-1) .EQ. 0) num1=count(ifldmiss(n:n+glen(ng)-1) .EQ. 1) num2=count(ifldmiss(n:n+glen(ng)-1) .EQ. 2) if ( num0.eq.0 ) then ! all missing values if ( num1.eq.0 ) then ! all secondary missing gref(ng)=-2 gwidth(ng)=0 elseif ( num2.eq.0 ) then ! all primary missing gref(ng)=-1 gwidth(ng)=0 else ! both primary and secondary gref(ng)=0 gwidth(ng)=1 endif else ! contains some non-missing data ! find max and min values of group gref(ng)=huge(n) imax=-1*huge(n) j=n do lg=1,glen(ng) if ( ifldmiss(j).eq.0 ) then if (ifld(j).lt.gref(ng)) gref(ng)=ifld(j) if (ifld(j).gt.imax) imax=ifld(j) endif j=j+1 enddo if (missopt.eq.1) imax=imax+1 if (missopt.eq.2) imax=imax+2 ! calc num of bits needed to hold data if ( gref(ng).ne.imax ) then temp=alog(real(imax-gref(ng)+1))/alog2 gwidth(ng)=ceiling(temp) else gwidth(ng)=0 endif endif ! Subtract min from data j=n mtemp=2**gwidth(ng) do lg=1,glen(ng) if (ifldmiss(j).eq.0) then ! non-missing ifld(j)=ifld(j)-gref(ng) elseif (ifldmiss(j).eq.1) then ! primary missing ifld(j)=mtemp-1 elseif (ifldmiss(j).eq.2) then ! secondary missing ifld(j)=mtemp-2 endif j=j+1 enddo ! increment fld array counter n=n+glen(ng) enddo ! ! Find max of the group references and calc num of bits needed ! to pack each groups reference value, then ! pack up group reference values ! !write(77,*)'GREFS: ',(gref(j),j=1,ngroups) igmax=maxval(gref(1:ngroups)) if (missopt.eq.1) igmax=igmax+1 if (missopt.eq.2) igmax=igmax+2 if (igmax.ne.0) then temp=alog(real(igmax+1))/alog2 nbitsgref=ceiling(temp) ! restet the ref values of any "missing only" groups. mtemp=2**nbitsgref do j=1,ngroups if (gref(j).eq.-1) gref(j)=mtemp-1 if (gref(j).eq.-2) gref(j)=mtemp-2 enddo call sbytes(cpack,gref,iofst,nbitsgref,0,ngroups) itemp=nbitsgref*ngroups iofst=iofst+itemp ! Pad last octet with Zeros, if necessary, if (mod(itemp,8).ne.0) then left=8-mod(itemp,8) call sbyte(cpack,zero,iofst,left) iofst=iofst+left endif else nbitsgref=0 endif ! ! Find max/min of the group widths and calc num of bits needed ! to pack each groups width value, then ! pack up group width values ! !write(77,*)'GWIDTHS: ',(gwidth(j),j=1,ngroups) iwmax=maxval(gwidth(1:ngroups)) ngwidthref=minval(gwidth(1:ngroups)) if (iwmax.ne.ngwidthref) then temp=alog(real(iwmax-ngwidthref+1))/alog2 nbitsgwidth=ceiling(temp) do i=1,ngroups gwidth(i)=gwidth(i)-ngwidthref enddo call sbytes(cpack,gwidth,iofst,nbitsgwidth,0,ngroups) itemp=nbitsgwidth*ngroups iofst=iofst+itemp ! Pad last octet with Zeros, if necessary, if (mod(itemp,8).ne.0) then left=8-mod(itemp,8) call sbyte(cpack,zero,iofst,left) iofst=iofst+left endif else nbitsgwidth=0 gwidth(1:ngroups)=0 endif ! ! Find max/min of the group lengths and calc num of bits needed ! to pack each groups length value, then ! pack up group length values ! !write(77,*)'GLENS: ',(glen(j),j=1,ngroups) ilmax=maxval(glen(1:ngroups-1)) nglenref=minval(glen(1:ngroups-1)) nglenlast=glen(ngroups) if (ilmax.ne.nglenref) then temp=alog(real(ilmax-nglenref+1))/alog2 nbitsglen=ceiling(temp) do i=1,ngroups-1 glen(i)=glen(i)-nglenref enddo call sbytes(cpack,glen,iofst,nbitsglen,0,ngroups) itemp=nbitsglen*ngroups iofst=iofst+itemp ! Pad last octet with Zeros, if necessary, if (mod(itemp,8).ne.0) then left=8-mod(itemp,8) call sbyte(cpack,zero,iofst,left) iofst=iofst+left endif else nbitsglen=0 glen(1:ngroups)=0 endif ! ! For each group, pack data values ! !write(77,*)'IFLDS: ',(ifld(j),j=1,ndpts) n=1 ij=0 do ng=1,ngroups glength=glen(ng)+nglenref if (ng.eq.ngroups ) glength=nglenlast grpwidth=gwidth(ng)+ngwidthref !write(77,*)'NGP ',ng,grpwidth,glength,gref(ng) if ( grpwidth.ne.0 ) then call sbytes(cpack,ifld(n),iofst,grpwidth,0,glength) iofst=iofst+(grpwidth*glength) endif do kk=1,glength ij=ij+1 !write(77,*)'SAG ',ij,fld(ij),ifld(ij),gref(ng),bscale,rmin,dscale enddo n=n+glength enddo ! Pad last octet with Zeros, if necessary, if (mod(iofst,8).ne.0) then left=8-mod(iofst,8) call sbyte(cpack,zero,iofst,left) iofst=iofst+left endif lcpack=iofst/8 ! if ( allocated(ifld) ) deallocate(ifld) if ( allocated(jfld) ) deallocate(jfld) if ( allocated(ifldmiss) ) deallocate(ifldmiss) if ( allocated(gref) ) deallocate(gref) if ( allocated(gwidth) ) deallocate(gwidth) if ( allocated(glen) ) deallocate(glen) !else ! Constant field ( max = min ) ! nbits=0 ! lcpack=0 ! nbitsgref=0 ! ngroups=0 !endif ! ! Fill in ref value and number of bits in Template 5.2 ! rmin4 = rmin call mkieee(rmin4,ref,1) ! ensure reference value is IEEE format ! call gbyte(ref,idrstmpl(1),0,32) iref=transfer(ref,iref) idrstmpl(1)=iref idrstmpl(4)=nbitsgref idrstmpl(5)=0 ! original data were reals idrstmpl(6)=1 ! general group splitting idrstmpl(10)=ngroups ! Number of groups idrstmpl(11)=ngwidthref ! reference for group widths idrstmpl(12)=nbitsgwidth ! num bits used for group widths idrstmpl(13)=nglenref ! Reference for group lengths idrstmpl(14)=1 ! length increment for group lengths idrstmpl(15)=nglenlast ! True length of last group idrstmpl(16)=nbitsglen ! num bits used for group lengths if (idrsnum.eq.3) then idrstmpl(18)=nbitsd/8 ! num bits used for extra spatial ! differencing values endif return end