!
! here are the all FORTRAN packing routines from
! NCAR. they should work on all machines
!
! note: we are using the slowest version of these routines.
! min and max values are determined and the numbers packed
! between these values. (we're using packaf, see the NCAR routines).
!
! installed into the interface: 5 MAY 1992, wcs
!
! first, our local interface (wrlcm, rdlcm) to the NCAR routines
!
SUBROUTINE wrlcm (arr,apr,nw,npack) 5,3
INCLUDE 'agricpu.inc'
!
!
! ON INPUT:
! ARR(NW) AN ARRAY OF REAL NUMBERS
! NW ITS LENGTH
!
! ON OUTPUT:
! APR(1) MINIMUM OF ARR.
! APR(2) THE SCALE FACTOR=S(NPACK-1)/(2*MAX(ABS(ARR)))
! APR(.) THE PACKED DATA
!
DIMENSION arr(nw),apr(*)
! print*,' npack in wrlcm =' , npack
IF( npack < 1 .OR. npack > 4 ) THEN
PRINT*,' wrong value of npack'
STOP
END IF
!
IF (npack == 1) THEN
DO i=1,nw
apr(i) = arr(i)
END DO
ELSE
cpu0 = f_cputime
()
CALL packaf
( arr,nw,apr,npack,sca1,sca2 )
cpu_pack = cpu_pack + f_cputime
() - cpu0
END IF
RETURN
END SUBROUTINE wrlcm
!
SUBROUTINE rdlcm (arr,apr,nw,npack) 5,2
INCLUDE 'agricpu.inc'
!
!
! ON INPUT:
! APR(.) THE PACKED ARRAY PRODUCED BY WRLCM
! NW THE NUMBER OF ELEMENTS WANTED
!
! ON EXIT:
! ARR(NW) THE ARRAY OF REAL NUMBERS
!
!
DIMENSION arr(nw),apr(*)
!
IF (npack == 1) THEN
DO i=1,nw
arr(i) = apr(i)
END DO
ELSE
cpu0 = f_cputime
()
CALL unpkaf( arr,nw,apr,npack,sca1,sca2 )
cpu_unpack = cpu_unpack + f_cputime
() - cpu0
END IF
!
RETURN
END SUBROUTINE rdlcm
!
! here are the NCAR routines.
!
!***********************************************************************
!
! latest revision September, 1991. See "purpose" section
! immediately below, and "revision history"
! comments at the end of these routines for
! more details.
!
! purpose This version of the packing/unpacking routines
! was written in Fortran 77, to be used on CRAY
! machines, including XMP, YMP, and CRAY-2 series.
! It is intended that this version will replace
! the mixed Fortran/Cal version that has been
! traditional on NCAR's XMP/YMP machines.
!
! This all-Fortran version produces slightly
! different results than the FORTRAN/CAL version
! unless rounding is turned off on the YMP compiler
! cf77 (option"r"). This option is not available
! on CRAY-2 machines, which is the reason that the
! two sets of routines produce different results.
!
! Historically, the purpose of these routines is
! to reduce the data volume and possibly the core
! requirements associated with a user program by
! packing/unpacking several values per Cray word.
! See the "algorithm" section below for details.
!
! usage call packaf (arn,nrn,apn,npk,amn,amx)
! call packbf (arn,nrn,apn,npk,amn,amx)
! call packcf (arn,nrn,apn,npk,amn,amx)
! call unpkaf (arn,nrn,apn,npk,amn,amx)
! call unpkbf (arn,nrn,apn,npk,amn,amx)
! call unpkcf (arn,nrn,apn,npk,amn,amx)
!
! arguments All of the packing and unpacking routines
! have the same calling sequence, with
! arguments arn, nrn, apn, npk, amn, and amx,
! the last two of which may be omitted
! except in calls to packcf. The arguments
! may be described as follows:
!
! on input arn(i),i=1,nrn
!
! an array of real numbers - input to the
! packers, output from the unpacker
!
! nrn the length of arn - input
!
! apn(1) minimum value - amn
! apn(2) scale factor -
! (2**(64/npk)-1)/(amx-amn)
!
!
! npk
!
! packing density - number of data to be packed
! in one output word (2, 3, or 4) - input
!
! amn
!
! minimum - input to packcf, output from others
! (may be omitted from all except packcf calls)
!
! amx
!
! maximum - input to packcf, output from others
! (may be omitted from all except packcf calls)
!
! on output apn(j) , j=3,4,...n
!
! the packed data - npk integers per word -
! n = 2+(nrn+npk-1)/npk - output from the
! packers, input to the unpacker
!
! special conditions There are three packing routines to
! choose from - packaf, packbf, and packcf.
! They differ only in the way in which
! amn and amx are computed.
!
! Packaf is the safest, but the slowest.
! amn and amx are computed by the routine
! itself. Initially, amn is the actual
! minimum and amx is the actual maximum.
! then, if amn = amx, the values are
! adjusted outwards to avoid division by zero.
! further, if amn amx differ in sign,
! amx is adjusted outwards a little to
! ensure that zeroes in the original array
! will be returned by the unpacker as zeroes
! (mathematically, at least - hardware
! round-off makes it impossible to ensure
! the return of exact zeroes without
! seriously degrading the speed of the
! routine - however, the value returned should
! never be greater than 1.e-14*abs(amn) ).
!
! Packbf is the intermediate choice, faster
! but not as safe. amn and amx are computed
! by the routine itself.
! Initially, amx is set equal to the maximum
! absolute value and amn to the negative
! of that. Then, amn and amx are adjusted
! as for packaf. This routine should probably
! be used only for data which is known to have
! a distribution which is roughly symmetric
! around zero.
!
! Packcf is the fastest, but most dangerous,
! of the three. the user must supply the
! initial values of amn and amx. These values
! are not adjusted in any way.
! No test is made to ensure that data
! values lie between amn and amx - errors may
! result.
!
! Routines 'unpkaf', 'unpkbf', and 'unpkcf'
! are used for the unpacking process.
! Actually, they are all synonymns, provided
! for the sake of consistency if and when
! planned extensions are added to this package.
!
! Note that, in any case, these routines
! must be used with care. One wildly
! out-of-range datum can destroy the precision
! of the rest. Moreover, data sets with
! unlike ranges should be packed separately.
!
! i/o none
!
! precision see algorithm discussion below
!
! required library none
! files
!
! language fortran
!
! history 1979: Written by Vince Wayland of Cray Research,
! Inc, and made available to NCAR in the same year.
! 1991: (September) Re-written entirely in fortran
! for use on CRAY-2 machines, and also XMP/YMP
! machines if desired. The two versions produce
! different results on the XMP/YMP series, as
! explained above in the "purpose" section.
!
! algorithm Given an array of real numbers
! (arn(i), i=1,nrn), a packing density
! npk (with value 2, 3, or 4), and real numbers
! amn and amx (the former less than or equal
! to any datum in arn and the latter greater
! than or equal to any datum in arn), one can
! reduce each element of arn to a positive
! integer less than or equal to
! 2**(64/npk)-1 by means of the
! following formula:
!
! int(i) = ifix( (arn(i)-amn) *
! (2**(64/npk)-1) / (amx-amn) + .5 )
!
! the numbers amn and (2**(64/npk)-1) / (amx-amn)
! may then be stored as apn(1) and apn(2), followed
! by the integers (int(i),i=1,nrn), packed npk per
! word in apn(3) through apn(2+(nrn+npk-1)/npk)).
! The original (arn(i),i=1,nrn) may subsequently
! be reconstructed from the contents of the packed
! array apn by means of the following formula:
!
! arn(i) = amn + int(i) * (amx-amn) /
! (2**(64/npk)-1)
!
! Note that the relative error of the reconstructed
! values is a function of the packing density.
! The error being 1. / (2**(64/npk)-1), i.e.
! 2.3 e-9, 4.8 e-7, 1.5 e-5 for npk 2, 3, 4
! respectively.
!
! portability not portable.
!
! timing as of September, 1992 the following timings
! obtained on a Cray-YMP8/864.
!
! each time given is the time required
! to pack or unpack 100,000 numbers, in milliseconds.
!
! routine npk=2 npk=3 npk=4
! ------- ----- ----- -----
!
! packaf 4.97 5.03 5.11
! packbf 3.60 3.67 3.76
! packcf 2.06 2.12 2.21
! unpkbf 1.79 1.46 1.30
!
!***********************************************************************
SUBROUTINE packaf (arn,nrn,apn,npk,amn,amx) 1,3
DIMENSION arn(nrn),apn(*),po2(3)
DATA po2 / 4294967295.,2097151.,65535. /
!
! check for certain errors in the arguments.
!
noa=numarg()
IF (noa < 4 .OR. noa > 6) GO TO 901
!
IF (nrn <= 0) GO TO 902
!
IF (npk < 2 .OR. npk > 4) GO TO 903
!
xmn=0577777777777777777777B
xmx=1577777777777777777777B
!
DO i = 1, nrn
xmn=MIN(xmn,arn(i))
xmx=MAX(xmx,arn(i))
END DO
!
! adjust the values of xmn and xmx - make sure they are not equal.
!
102 IF (xmn /= xmx) GO TO 104
xmn=xmn-.5*ABS(xmn)
xmx=xmx+.5*ABS(xmx)
IF (xmn /= xmx) GO TO 104
xmn=-1.
xmx=+1.
!
! if xmn and xmx differ in sign, further adjust them so that zero will
! be a possible output from the unpacker.
!
104 IF (xmn*xmx >= 0.) GO TO 105
IF (ABS(xmn) < ABS(xmx)) THEN
xmn=xmx-xmx*po2(npk-1)/FLOAT(IFIX( xmx*po2(npk-1)/(xmx-xmn)))
ELSE
xmx=xmn-xmn*po2(npk-1)/FLOAT(IFIX(-xmn*po2(npk-1)/(xmx-xmn)))
END IF
!
! return the computed values of xmn and xmx to the user, if appropriate.
!
105 IF (noa >= 5) amn=xmn
IF (noa >= 6) amx=xmx
!
! store the minimum and the scale factor in the output array.
!
apn(1)=xmn
apn(2)=po2(npk-1)/(xmx-xmn)
!
! call an appropriate routine to do the actual packing
!
IF (npk == 2) THEN
CALL pack2f
(arn, nrn, apn)
ELSE IF (npk == 3) THEN
CALL pack3f
(arn, nrn, apn)
ELSE
CALL pack4f
(arn, nrn, apn)
END IF
!
RETURN
!
! error exits.
!
901 PRINT 9001
STOP
!
902 PRINT 9002
STOP
!
903 PRINT 9003
STOP
!
! formats.
!
9001 FORMAT (' packaf - wrong number of arguments - stop ')
9002 FORMAT (' packaf - array length .le. 0 - stop ')
9003 FORMAT (' packaf - packing density .ne. 2, 3, or 4 - stop ')
!
END SUBROUTINE packaf
SUBROUTINE packbf (arn,nrn,apn,npk,amn,amx),3
DIMENSION arn(nrn),apn(*),po2(3)
DATA po2 / 4294967295.,2097151.,65535. /
!
! check for certain errors in the arguments.
!
noa=numarg()
IF (noa < 4 .OR. noa > 6) GO TO 901
!
IF (nrn <= 0) GO TO 902
!
! print*,' npk =', npk
IF (npk < 2 .OR. npk > 4) GO TO 903
!
xmx=1577777777777777777777B
!
DO i = 1, nrn
xmx=MAX(xmx,arn(i))
END DO
!
102 xmn=-xmx
!
! adjust the values of xmn and xmx - make sure they are not equal.
!
IF (xmn /= xmx) GO TO 103
xmn=-1.
xmx=+1.
!
! xmn and xmx differ in sign. further adjust them so that zero will
! be a possible output from the unpacker.
!
103 xmx=xmn-xmn*po2(npk-1)/FLOAT(IFIX(-xmn*po2(npk-1)/(xmx-xmn)))
!
! return the computed values of xmn and xmx to the user, if appropriate.
!
104 IF (noa >= 5) amn=xmn
IF (noa >= 6) amx=xmx
!
! store the minimum and the scale factor in the output array.
!
apn(1)=xmn
apn(2)=po2(npk-1)/(xmx-xmn)
!
! call an appropriate routine to do the actual packing
!
IF (npk == 2) THEN
CALL pack2f
(arn, nrn, apn)
ELSE IF (npk == 3) THEN
CALL pack3f
(arn, nrn, apn)
ELSE
CALL pack4f
(arn, nrn, apn)
END IF
!
RETURN
! error exits.
!
901 PRINT 9001
STOP
!
902 PRINT 9002
STOP
!
903 PRINT 9003
STOP
!
! formats.
!
9001 FORMAT (' packbf - wrong number of arguments - stop ')
9002 FORMAT (' packbf - array length .le. 0 - stop ')
9003 FORMAT (' packbf - packing density .ne. 2, 3, or 4 - stop ')
!
END SUBROUTINE packbf
SUBROUTINE packcf (arn,nrn,apn,npk,amn,amx),3
!
! this is the subroutine packcf.
!
DIMENSION arn(nrn),apn(*),po2(3)
DATA po2 / 4294967295.,2097151.,65535. /
!
! check for certain errors in the arguments.
!
noa=numarg()
IF (noa /= 6) GO TO 901
!
IF (nrn <= 0) GO TO 902
!
IF (npk < 2 .OR. npk > 4) GO TO 903
!
IF (amn >= amx) GO TO 904
!
! store the minimum and the scale factor in the output array.
!
apn(1)=amn
apn(2)=po2(npk-1)/(amx-amn)
!
! call an appropriate routine to do the actual packing
!
IF (npk == 2) THEN
CALL pack2f
(arn, nrn, apn)
ELSE IF (npk == 3) THEN
CALL pack3f
(arn, nrn, apn)
ELSE
CALL pack4f
(arn, nrn, apn)
END IF
!
RETURN
!
! error exits.
!
901 PRINT 9001
STOP
!
902 PRINT 9002
STOP
!
903 PRINT 9003
STOP
!
904 PRINT 9004
STOP
!
! formats.
!
9001 FORMAT (' packcf - wrong number of arguments - stop ')
9002 FORMAT (' packcf - array length .le. 0 - stop ')
9003 FORMAT (' packcf - packing density .ne. 2, 3, or 4 - stop ')
9004 FORMAT (' packcf - minimum .ge. maximum - stop ')
!
END SUBROUTINE packcf
SUBROUTINE pack2f (arn, nrn, apn) 3
!
! This routine packs 2 floats to the word
!
DIMENSION arn (nrn), apn (*)
npc = nrn / 2
xsf = apn(1)
xsc = apn(2)
DO j = 1, npc
i = j * 2 - 1
ih = (arn(i ) - xsf) * xsc + 0.5
il = (arn(i+1) - xsf) * xsc + 0.5
apn(j+2) = OR (shiftl (ih, 32), il)
END DO
!
! Pack up any left-overs
!
IF (npc * 2 /= nrn) THEN
j = npc + 1
i = j * 2 - 1
ih = (arn(i ) - xsf) * xsc + 0.5
apn(j+2) = OR (shiftl (ih, 32), 0)
END IF
END SUBROUTINE pack2f
SUBROUTINE pack3f (arn, nrn, apn) 3
!
! This routine packs 3 floats to the word
!
DIMENSION arn (nrn), apn (*)
npc = nrn / 3
xsf = apn(1)
xsc = apn(2)
DO j = 1, npc
i = j * 3 - 2
ih = (arn(i ) - xsf) * xsc + 0.5
im = (arn(i+1) - xsf) * xsc + 0.5
il = (arn(i+2) - xsf) * xsc + 0.5
apn(j+2) = OR (shiftl (ih, 42), &
OR (shiftl (im, 21), il))
END DO
!
! Pack up any left-overs
!
m = nrn - (npc * 3)
IF (m /= 0) THEN
j = npc + 1
i = j * 3 - 2
ih = (arn(i ) - xsf) * xsc + 0.5
IF (m == 1) THEN
im = 0
ELSE
im = (arn(i+1) - xsf) * xsc + 0.5
END IF
apn(j+2) = OR (shiftl (ih, 42), &
shiftl (im, 21))
END IF
END SUBROUTINE pack3f
SUBROUTINE pack4f (arn, nrn, apn) 3
!
! This routine packs 4 floats to the word
!
DIMENSION arn (nrn), apn (*)
npc = nrn / 4
xsf = apn(1)
xsc = apn(2)
DO j = 1, npc
i = j * 4 - 3
ihh = (arn(i ) - xsf) * xsc + 0.5
ihl = (arn(i+1) - xsf) * xsc + 0.5
ilh = (arn(i+2) - xsf) * xsc + 0.5
ill = (arn(i+3) - xsf) * xsc + 0.5
apn(j+2) = OR (shiftl (ihh, 48), &
OR (shiftl (ihl, 32), &
OR (shiftl (ilh, 16), ill)))
END DO
!
! Pack up any left-overs
!
m = nrn - (npc * 4)
IF (m > 0) THEN
j = npc + 1
i = j * 4 - 3
ihh = (arn(i ) - xsf) * xsc + 0.5
ilh = 0
ihl = 0
GO TO (112, 111, 110) M
110 ilh = (arn(i+2) - xsf) * xsc + 0.5
111 ihl = (arn(i+1) - xsf) * xsc + 0.5
112 CONTINUE
apn(j+2) = OR (shiftl (ihh, 48), &
OR (shiftl (ihl, 32), shiftl (ilh, 16)))
END IF
END SUBROUTINE pack4f
SUBROUTINE unpack2f (arn, nrn, apn) 1
!
! This routine unpacks 2 floats from each word
!
DIMENSION arn (nrn), apn (*)
npc = nrn / 2
xsf = apn(1)
xsc = 1.0 / apn(2)
DO j = 1, npc
i = j * 2 - 1
ih = shiftr (apn(j+2), 32)
il = AND ( apn(j+2), 4294967295)
arn(i ) = ih * xsc + xsf
arn(i+1) = il * xsc + xsf
END DO
!
! Unpack any left-overs
!
m = nrn - (npc * 2)
IF (m > 0) THEN
j = npc + 1
i = j * 2 - 1
ih = shiftr (apn(j+2), 32)
arn(i) = ih * xsc + xsf
END IF
END SUBROUTINE unpack2f
SUBROUTINE unpack3f (arn, nrn, apn) 1
!
! This routine unpacks 3 floats from each word
!
DIMENSION arn (nrn), apn (*)
npc = nrn / 3
xsf = apn(1)
xsc = 1.0 / apn(2)
DO j = 1, npc
i = j * 3 - 2
ih = shiftr (apn(j+2), 42)
im = AND (shiftr (apn(j+2), 21), 2097151)
il = AND ( apn(j+2), 2097151)
arn(i ) = ih * xsc + xsf
arn(i+1) = im * xsc + xsf
arn(i+2) = il * xsc + xsf
END DO
!
! Unpack any left-overs
!
m = nrn - (npc * 3)
IF (m > 0) THEN
j = npc + 1
i = j * 3 - 2
ih = shiftr (apn(j+2), 42)
arn(i) = ih * xsc + xsf
IF (m > 1) THEN
im = AND (shiftr (apn(j+2), 21), 2097151)
arn(i+1) = im * xsc + xsf
END IF
END IF
END SUBROUTINE unpack3f
SUBROUTINE unpack4f (arn, nrn, apn) 1
!
! This routine unpacks 4 floats from each word
!
DIMENSION arn (nrn), apn (*)
npc = nrn / 4
xsf = apn(1)
xsc = 1.0 / apn(2)
DO j = 1, npc
i = j * 4 - 3
ihh = shiftr (apn(j+2), 48)
ihl = AND (shiftr (apn(j+2), 32), 65535)
ilh = AND (shiftr (apn(j+2), 16), 65535)
ill = AND ( apn(j+2), 65535)
arn(i ) = ihh * xsc + xsf
arn(i+1) = ihl * xsc + xsf
arn(i+2) = ilh * xsc + xsf
arn(i+3) = ill * xsc + xsf
END DO
!
! Unpack any left-overs
!
m = nrn - (npc * 4)
IF (m > 0) THEN
j = npc + 1
i = j * 4 - 3
ihh = shiftr (apn(j+2), 48)
ihl = AND (shiftr (apn(j+2), 32), 65535)
ilh = AND (shiftr (apn(j+2), 16), 65535)
GO TO (112, 111, 110) M
110 arn(i+2) = ilh * xsc + xsf
111 arn(i+1) = ihl * xsc + xsf
112 arn(i ) = ihh * xsc + xsf
END IF
END SUBROUTINE unpack4f
SUBROUTINE unpkbf (arn,nrn,apn,npk,amn,amx),3
!
! this is the subroutine unpkbf.
!
DIMENSION arn(nrn),apn(*),msk(3)
DATA msk / 4294967295 , 2097151 , 65535 /
!
! 'unpkaf', and 'unpkcf' are all synonyms for 'unpkbf'.
!
ENTRY unpkaf (arn,nrn,apn,npk,amn,amx)
ENTRY unpkcf (arn,nrn,apn,npk,amn,amx)
!
! check for errors in the input.
!
noa=numarg()
IF (noa < 4 .OR. noa > 6) GO TO 901
!
IF (nrn <= 0) GO TO 902
!
IF (npk < 2 .OR. npk > 4) GO TO 903
!
! return the values of amn and amx, if appropriate.
!
IF (noa >= 5) amn=apn(1)
IF (noa >= 6) amx=apn(1)+FLOAT(msk(npk-1))/apn(2)
!
! call an appropriate routine to do the actual unpacking
!
IF (npk == 2) THEN
CALL unpack2f
(arn, nrn, apn)
ELSE IF (npk == 3) THEN
CALL unpack3f
(arn, nrn, apn)
ELSE
CALL unpack4f
(arn, nrn, apn)
END IF
!
106 RETURN
!
! error exits.
!
901 PRINT 9001
STOP
!
902 PRINT 9002
STOP
!
903 PRINT 9003
STOP
!
! formats.
!
9001 FORMAT (' unpkf(abc) - wrong number of arguments - stop ')
9002 FORMAT (' unpkf(abc) - array length .le. 0 - stop ')
9003 FORMAT (' unpkf(abc) - packing density .ne. 2, 3, or 4 - stop ')
!
! revision history -----------------------------------------------------
!
! september, 1991 Rewrote these routines in Fortran, for use on CRAY-2
! machines. This version does not produce results which
! are identical to results produced by the mixed Fortran
! /Cal routines used on the YMP machines. The reason is
! stated above in the "purpose" section of the package
! documentation.
! ----------------------------------------------------------------------
END SUBROUTINE unpkbf