C     path:      /stormrc1/aer_lblrtm/src/SCCS/s.fftscn.f
C     revision:  5.5
C     created:   8/13/99  15:28:00
C     presently: 8/13/99  15:28:51

      Subroutine FFTSCN (IFILE,JFILE) 1,21
C**********************************************************************
C     FFTSCN and its associated subroutines convolve an LBLRTM spectrum
C     with an instrument response function (scanning function) using
C     Fourier Transforms.  The program transforms the spectrum to the
C     Fourier domain, multiplies it by the Fourier transform of the
C     scanning function, and transforms it back to the frequency domain
C     Compared to convolving in the spectral domain, this technique
C     has the advantages that it is more accurate and more efficient
C     for large spectral regions.
C
C     For further details, see:
C         FFTSCN: A Program for Spectral Scanning Using Fourier
C                  Transforms
C         By: William Gallery
C             S. A. Clough
C             AER, Inc., Cambridge, MA
C         Technical Report, Phillips Lab, Geophysics Directorate,
C            PL-TR-92-2131
C
C         (Phillips Lab was formerly the Air Force Geophysics Lab [AFGL])
C
C     Created December, 1989 by:
C                               William Gallery
C                               OptiMetrics, Inc.
C     Current address:          AER, Inc.
C                               Cambridge, MA
C
C     Version 1.0: Dec, 1992
C
C     Version 1.1: June, 1993
C         Changes in Version 1.1:
C         1. No longer is the minimum size of an FFT equal to LPTSMX,
C            rather it is the smallest power of 2 greater than the
C            number of data points.  LPTSMX (set in file fftparm.inc)
C            can now be set to a large value consistent with real (not
C            virtual) memory.
C         2. Fixed a bug in HARM1D.  The variables NT, NTV2, and MT were
C            set in one call to HARM1D but were not preserved for subsequent
C            calls.  The problem only occured on some platforms, notably
C            Silicon Graphics workstations.  The problem was solved with a
C            SAVE statement.
C         3. Added Norton-Beer, Brault, and Kaiser-Bessel Scanning Functions
C
C     Version 1.2: November, 1993
C         Changes in Version 1.2
C         1. Added option to interpolate the final result onto a user-
C            specified grid.
C         2. If the DV of the input spectrum is greater than HWHM/6, then
C            the input spectrum is first interpolated onto a frequency grid
C            where DV <= HWHM/6.
C         3. Fixed bug in Norton-Beer functions: it always returned the weak
C            function.
C         4. Fixed bug: IFILE is now closed after each scanning function
C            request.  On some machines (Convex), not doing this and requesting
C            another operation on IFILE generated an error.
C         5. Fixed bug: the output spectral grid was sometimes off by
C            one dv.
C
C     Program instructions:
C     The program commands are contained on a single input record plus
C     up to 3 additional records, depending upon the case.  Multiple
C     commands may be contained on successive records.  A zero or
C     negative number in the first field terminates the sequence.
C
C     The format of a command is as follows:
C
C     Field:     HWHM      V1      V2   JEMIT   JFNIN  MRATIN   DVOUT
C     Column:	 1-10	11-20   21-30   31-35	36-40   41-45   46-55
C     Field:	IUNIT    IFIL    NFIL   JUNIT     IVX   NOFIX
C     Column:   56-60   61-65   66-70   71-75   76-78   79-80
C
C     Format(3F10.3,3I5,F10.3,4I5,I3,I2)
C
C     HWHM    Half Width at Half Maximum of the scanning function, or
C             if JFN < 0, then maximum optical path difference of an
C             equivalent interferometer. If HWHW <= 0, then exit FFTSCN
C     V1      Initial wavenumer for the scanned result
C     V2      Final wavenumber for the scanned result
C     JEMIT   = 0:  convolve with transmittance
C             = 1:  convolve with radiance
C     JFNIN   Selects the Scanning Function
C             = 0: Boxcar.  Halfwidth is truncated to M du/2,
C                  where M is an integer
C             = 1: Triangle
C             = 2: Gauss
C             = 3: Sinc2
C             = 4: Sinc
C             = 5: Beer
C             = 6: Hamming
C             = 7: Hanning
C             = 8: Norton-Beer, Weak
C             = 9: Norton-Beer, Moderate
C             =10: norton-Beer, Strong
C             =11: Brault (needs input parameter PARM)
C             =12: Kaiser-Bessel (needs input parameter PARM)
C             =13: Kiruna (asymetric, c1*sinc(u)+c2*sinc(u-u1)
C             If JFN < 0, then HWHM is the maximum optical path
C             difference of an equivalent interfereometer, apodized to
C             give the scanning function given by |JFN|.
C     MRAT    For prescanning with a boxcar, the ratio of HWHM of the
C             scanning function to the halfwidth of the boxcar,
C             default = MRATDF (=12). If MRAT < 0, no boxcaring is
C             performed.
C     DVOUT   If DVOUT > 0, then the scanned spectral file is interpolated
C             onto the grid defined by V1, V2, and DV
C     IUNIT   Unit number of the file containing the spectrum to be
C             scanned.
C             = 0: use file on UNIT = IFILE (from LBLRTM, default=12)
C             > 0: use file on UNIT = IUNIT
C             < 0: read a filename from the next record, 20 characters max,
C                  and open this file on UNIT = -IUNIT
C     IFILST  Sequential number of the first LBLRTM file on IUNIT to
C             be scanned
C     NIFILS  Number of LBLRTM files on IUNIT to be scanned,
C             beginning with IFILST
C     JUNIT   Unit number of the file containing the output spectrum.
C             = 0: UNIT = IFILE (from LBLRTM default = 11),
C                   filename=TAPExx, where xx = IFILE
C             > 0: UNIT = IUNIT, filename = TAPExx, where xx = IUNIT
C             < 0: read in a filename from the next record, 60 characters max,
C                  and open this file on UNIT = -JUNIT
C     IVX     = -1:  Scanning function is calculated as the FFT of the
C                    Apodization function
C             =  0:  Program decides how to calculate the scanning
C                    function using the value of CR(JFN).
C             =  1:  Scanning function is calculated analytically
C
C     NOFIX   For prescanning with a boxcar: if non-zero, then do not
C             deconvolve the scanned spectrum with the boxcar
C
C     Record 2 (For JFN > 10, )
C         PARM (F10.3) parameter defining the scanning function
C
C     Record 3 (for IUNIT < 0)
C         INFILE (A60) Name (including path) of the input spectral file
C
C     Record 4 (for JUNIT < 0)
C         OUTFILE (A60) Name (including path) of the spectral output file
C**********************************************************************

C***********************************************************************
C     LPTSMX is the size of a data block for the FFT.  If the number of
C     data points is LPTSMX or less, the FFT is done in memory.  If it
C     is larger, then a disk based FFT is performed, and LPTSMX is the
C     size in words of each record of the file. The in-memory routine is
C     about 20 percent more efficient than the disk-based routine, for
C     same number of points.  For efficiency, LPTSMX should be made
C     as large a possible so that the computation can be done in memory.
C     However, on virtual memory machines (e.g. VAX), if LPTSMX is too
C     large, then the computation will be done in VIRTUAL memory.  Since
C     the in-memory routine uses widely scattered points, operating
C     system will spend a great deal of time swapping data in and out
C     (thrashing) and the efficiency will be very poor.
C
C     The following problem has been corrected (May, 1993).  The minimum
C     size of an FFT is now the smallest power of 2 greater than the
C     of data points.  LPTSMX should be set to the larges value consistant
C     with real memory.
C
C*    However, LPTSMX is also the minimum size of an FFT (this is a
C*    design flaw of this program).  If LPTSMX is much larger than the
C*    number of points in the spectrum, computational time is wasted.
C*
C*    Therefore, LPTSMX should be set to a value somewhat larger than
C*    the size of the smallest typical spectrum, but no larger than the
C*    largest value possible without thrashing.
C
C     IBLKSZ is the record length in the OPEN statement, and may be
C     in bytes or words,  depending on the operating system.  For VAX
C     and CDC, it is in words.  For MicroSoft FORTRAN, it is in bytes.
C***********************************************************************
      PARAMETER (LSIZE = 65536)
C*****Following line for computers where the blocksize is measured
C*****in words, e.g. VAX, CDC/NOS/VE
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX,LPTSM8=LPTSMX/8)

C*****Following line for computers where the blocksize is measured
C***** in bytes, e.g. MS FORTRAN, SUN, Alliant
      PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*4,LPTSM8=LPTSMX/8)

C*****Following line for computers with 64 bit words where the blocksize is
C*****measured in bytes, e.g. CRAY
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*8,LPTSM8=LPTSMX/8)

      Parameter (JFNMAX = 13)
C*****Computers with 32 bit words need the Double Precision Statements
C*****Computers with 64 bit words (e.g. Cyber) do not.
C*****Frequency variables start with V
      Implicit Real*8           (V)
      Character*8      XID,       HMOLID,      YID
      Real*8               SECANT,       XALTZ

C*****Blank Common carries the spectral data
      COMMON S(2450),R1(2650),XF(251)

C*****HVERSN carries the module SCCS version numbers
      COMMON /HVERSN/  HVRLBL,HVRCNT,HVRFFT,HVRATM,HVRLOW,HVRNCG,
     *                HVROPR,HVRPST,HVRPLT,HVRTST,HVRUTL,HVRXMR

C*****SCNHRD carries the header information for the scanned file
      COMMON /SCNHDR/ XID(10),SECANT,PAVE,TAVE,HMOLID(60),XALTZ(4),
     *                WK(60),PZL,PZU,TZL,TZU,WBROAD,DV ,V1C,V2C,TBOUND,
     *                EMISIV,FSCDID(17),NMOL,LAYER ,YI1,YID(10),LSTWDF
      DIMENSION FILHDR(2),IFSDID(17)
      EQUIVALENCE (FILHDR(1),XID(1))
      EQUIVALENCE (FSCDID(1),IFSDID(1),IHIRAC),(FSCDID(2),ILBLF4),
     C (FSCDID(3),IXSCNT),(FSCDID(4 ),IAERSL ),(FSCDID(5),IEMIT),
     C (FSCDID(6),ISCHDR ),(FSCDID(7 ),IPLOT  ),(FSCDID(8),IPATHL),
     C (FSCDID(9),JRAD  ),(FSCDID(10),ITEST  ),(FSCDID(11),IMRG),
     C (FSCDID(12),XSCID),(FSCDID(13),XHWHM  ),(FSCDID(14),IDABS),
     C (FSCDID(15),IATM ),(FSCDID(16),LAYR1  ),(FSCDID(17),NLAYFS),
     C (YID(1)    ,HDATE),(YID(2),      HTIME),(YI1,IMULT)

C*****PANL carries the information from the panel header
      COMMON /PANL/ V1P,V2P,DVP,NP
      DIMENSION PNLHDR(1)
      EQUIVALENCE (PNLHDR(1),V1P)


C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN


      Character*8 HVRLBL,HVRCNT,HVRFFT,HVRATM,HVRLOW,HVRNCG,HVROPR,
     *            HVRPLT,HVRPST,HVRTST,HVRUTL,HVRXMR
      Character*16 SFNAME,ANAMES(0:JFNMAX)
      Dimension C(0:JFNMAX),CRATIO(0:JFNMAX),CLIMIT(0:JFNMAX)

C*****FUNCT1 and FUNCT2 are used to store the spectrum, the Fourier
C*****transforms, the scanning function and the results
      Dimension FUNCT1(LPTSMX),FUNCT2(LPTSMX)

C*****JFNMAX is number of scanning functions currently defined
C*****ANAMES are their names
C*****SFNAME is the name of the scanning function
      Data ANAMES/'BOXCAR','TRIANGLE','GAUSSIAN','SINC**2','SINC',
     1           'BEER','HAMMING','HANNING','NB - WEAK','NB - MEDIUM',
     2           'NB - STRONG','BRAULT','KAISER-BESSEL','Kurina'/

C*****Ci's are constants = A/ HWHM, where A is the "natural" width
C*****parameter for each function, A = 1/L, where L is the maximum
C*****optical path difference for an equivalent interferometer.
C*****If C < 0, Abs(C) is approximate.
C*****Function -1 is special.  It is a very broad sinc which
C*****is the apodization function corresponding a narrow rectangular
C*****scanning function used to pre-scan the spectrum.
      Data C/     0.0,     2.0,0.849322,2.257609,3.314800,2.100669,
     1       2.195676,     2.0,2.570274,2.367714,2.071759, -3.3, -2.5,
     2       3.314800 /

C*****CRATIO is the critical value of the ratio of the frequency range
C*****to the half width at half maximum of the scanning function.
C*****If this ratio is greater than CRATIO, then the apodization
C*****function is calculated analytically, otherwise it is calculated
C*****as the FFT of the scanning function.  The values given here are
C*****educated guesses and may need to be revised. If CRATIO < 0,
c*****apodization is always calculated as the FFT of the scanning
C*****function
      Data CRATIO/0., 40., 10., 40., 160., 20., 20. ,20.,
     1   40., 40., 20., 100., 10., -1./

C*****CLIMIT: the limits of the scanned spectrum are expanded by
C*****HWHM*CLIMIT(JFN) to allow for the wrap around effect at V1 and
C*****V2 (effectively, V2 wraps around to V1).  Like CRATIO, these
C*****values are educated guesses (except for the triangle, where the
C*****bound of the scanning function is exactly 2*HWHM.)
      Data CLIMIT/0., 2., 3., 40., 160., 20., 20., 20.,
     1   40., 40., 20., 100., 10., 160/

C*****Note: the values of C, CRATIO, and CLIMIT for JFN=11 (Brault)
C*****corespond to a value of PARM of about .9, in which case the
C*****scanning function is very near a sinc.

C*****MRATIO is the minimum ratio of the HWHM of the scanning function
C*****to the width of the boxcar used to prescan the spectrum.  MRATDF
C*****is the default value of this parameter.
      Data MRATDF/12/

C*****MDVHW  is the minimum allowed value of the input dv to the hwhm
C*****If hwhm/dv is less than MDVHW/2, then the spectrum is first
C*****interpolated onto a grid with dv' = 2*hwhm/MDVHW.  Note: MDVHW
C*****and MRATIO are coupled: if MDVHW > MRATIO, then the program
C*****will interpolate onto a fine grid but then boxcar back onto a
C*****coarser grid
      Data MDVHW /12/

C*****Assign SCCS version number to module fftscn.f
      HVRFFT = '5.5'

      Write(IPR,'(''1FFTSCN: SPECTRAL SMOOTHING IN THE '',
     1            ''FOURIER DOMAIN*****'')')

C*****Read in scan commands until HWHM .le. 0.
  100 Continue
      PARM1 = 0.0
      PARM2 = 0.0
      PARM3 = 0.0

      Read(IRD,10,End=120) HWHM, V1, V2, JEMIT, JFNIN, MRATIN,
     1     DVOUT,IUNIT,IFILST,NIFILS, JUNIT, IVX, NOFIX
   10 Format(3F10.3,3I5,F10.5,4I5,I3,I2)

      Write(IPR,15)  HWHM, V1, V2, JEMIT, JFNIN, MRATIN, DVOUT, IUNIT,
     1     IFILST, NIFILS, JUNIT, IVX, NOFIX
   15 Format(/,'       HWHM        V1        V2   JEMIT   JFNIN',
     1   '  MRATIN', /,1X,3F10.4,3I8,12X,//,
     2   '      DVOUT   IUNIT  IFILST  NIFILS   JUNIT     IVX   NOFIX',
     3    /,(1X,F10.4,6I8))

      If(HWHM .LE. 0) Goto 115

      If(ABS(JFNIN) .ge. 11) Then
C*****    Functions 11 and above require further parameters
          Read(IRD,'(3F10.4)',End=120,Err=122) PARM1,PARM2,PARM3
          WRITE(IPR,16) PARM1,PARM2,PARM3
  16      Format(/,'     PARM1     PARM2     PARM3',/,' ',3F10.4)
      Endif

C*****Check whether JEMIT, JFNIN are within bounds
      If(JEMIT .LT. 0 .OR. JEMIT .GT. 1) THEN
          WRITE(IPR,'('' JEMIT is out of range: STOP'')')
          Goto 125
      Endif

      JFN = ABS(JFNIN)
      If(JFN .GT. JFNMAX) THEN
         Write(IPR,'('' JFN is out of range, max is '',I5,
     1               '':STOP'')') JFNMAX
         Goto 125
      Endif

C*****Calculate the parameter A = 1/L, where L is the maximum optical
C*****length of an equivalent interferometer (JFNIN > 0) or HWHM =
C*****half width at half height of the scanning function (JFNIIN < 0)
      SFNAME = ANAMES(JFN)
      If (JFNIN .GT. 0) Then
          If (              A = C(JFN)*HWHM
              PATHL = 1.0/A
          Else
              Write(IPR,*) ' Error: for this scanning function, you ',
     1            'must specify the interferometer optical ',
     2            'path difference'
              Goto 125
          Endif
      Elseif (JFNIN .LT. 0) Then
          If (              Write(IPR,*) ' Note: for this scanning function, the ',
     1            'calculated halfwidth is only approximate'
          Endif
          PATHL = HWHM
          A = 1./PATHL
          HWHM = A/ABS(      Elseif (JFNIN .EQ. 0) Then
          A = 0.
          PATHL = 0.
      Endif

      Write(IPR,17) SFNAME,HWHM,PATHL,A
  17  FORMAT(/,' Scanning function selected is:           ',A,/,
     1         ' Halfwidth at Half Height is:           ',G14.6,/,
     2         ' Length of equivalent interferometer is:',G14.6,/,
     3         ' Parameter A = 1/Length is:             ',G14.6)

C*****Decode boxcaring parameter MRATIN
      If(MRATIN .LT. 0) Then
         NOBOX = 1
      Elseif( MRATIN .EQ. 0) Then
         NOBOX = 0
         MRATIO = MRATDF
      Else
         NOBOX = 0
         MRATIO = MRATIN
      Endif

C*****Check the status of the input and output spectra files, and read
C*****in the filenames if necessary
      Call Ckfile(IFILE,IUNIT,0,IERR)
      If(IERR .NE. 0) Goto 125

      Call Ckfile(JFILE,JUNIT,1,IERR)
      If(IERR .NE. 0) Goto 125

      If(IFILST .LE. 0) IFILST = 1
      If(NIFILS .EQ. 0) NIFILS = 1
      If(NIFILS .LT. 0) NIFILS = 99

C*****Loop over NIFILS on IFILE
      Rewind IFILE
      If(IFILST .GT. 1) Then
          Call Skipfl(IFILST-1, IFILE, IEOF)
          If(IEOF .EQ. 0) Then
              WRITE(IPR,'('' EOF encountered skipping files: STOP'')')
              Goto 125
          Endif
      Endif

      Do 105 I=1,NIFILS

C*****Read in file header
      Call Gethdr(IFILE,1,JDATA,IEOFSC)
      If(IEOFSC .EQ. 0) Then
          Write(IPR,'('' EOF encountered reading file: STOP'')')
          Goto 125
      Endif

C*****Check the data in the header against the scan request and
C*****determine the data conversion.
C*****JCONVT   action
C*****     0   single panel, no conversion (scanned trans or rad)
C*****     1   single panel, optical depth to transmittance (mono.)
C*****     2   two panels, get first (mono. radiance)
C*****     3   two panels, set second (mono. transmittance)

      JCONVT = -1
      If(JEMIT .EQ. 0) Then
          If(JDATA .EQ. 0) JCONVT = 1
          If(JDATA .EQ. 1) JCONVT = 0
          If(JDATA .EQ. 2) JCONVT = 3
      Elseif(JEMIT .EQ. 1) Then
          If(JDATA .EQ. 2) JCONVT = 2
          If(JDATA .EQ. 3) JCONVT = 0
      Endif

      If(JCONVT .EQ. -1) Then
          Write(IPR,*) ' Data on file not compatible with scan: STOP'
          Goto 125
      Endif


C*****Check frequency limits and adjust, if necessary.  V1 and V2 are
C*****the requested limits, V1C and V2C are the limits of the input
C*****data, V1Z and V2Z are the actual limits of the of the scanned
C*****data and V1S and V2S are the limits of the data as output,
C*****adjusted from V1 and V2 for several effects:
C*****1.  gridding: V1S and V2S must be on the frequency grid of the
C*****    output spectrum
C*****2.  edge effects: V1Z and V2Z are expanded from V1 and V2
C*****    by HWHM*CLIMIT(JFN) so that edge effects do not contaminate
C*****    the scanned spectrum
C*****3.  regridding: prescanning with the boxcar resamples onto a new
C*****    frequency grid
C*****4.  interpolation: V2S is adjusted to fall on the interpolated
C*****    grid

      If(V1 .ge. V2) Then
          Write(IPR,*) ' FFTSCN - input error: Initial V >= final V:',
     1      'STOP'
          Goto 125
      Elseif(V1 .ge. V2C  .or.  V2 .le. V1C) Then
          Write(IPR,*) ' FFTSCN -input error: V1 to V2 is outside the',
     1      ' data range: STOP'
          Goto 125
      Endif

      V1Z = V1-HWHM*CLIMIT(JFN)
      V2Z = V2+HWHM*CLIMIT(JFN)
C*****Adjust V1Z, V2Z to fall on current frequency grid
      V1Z = V1C+DBLE(INT((V1Z-V1C)/DV+1.01))*DV
      V2Z = V1C+DBLE(INT((V2Z-V1C)/DV+1.01))*DV

      If (V1Z .LT. V1C) Then
          V1Z = V1C
          Write(IPR,*) ' First data point used: beginning of spectrum',
     1         ' may suffer from wraparound effects'
      Endif
      If (V2Z .GT. V2C) Then
          V2Z = V2C
          Write(IPR,*) ' Last data point used: end of spectrum may',
     1         ' suffer from wraparound effects'
      Endif

      Write(IPR,'(/,A,F12.5,A,F12.5)')
     1   ' Frequency limits of internal scanning calculation:',
     2   V1Z,' to',V2Z

      If ((V2Z-V1Z)/HWHM .lt. CLIMIT(JFN)) Then
          Write(IPR,*) ' FFTSCN - error: Insufficient Data for an',
     1         'accurate calculation: STOP'
          Goto 125
      Endif

C*****If the frequency grid is too coarse compared to the HWHM,
C*****then interpolate the spectrum onto a new, finer frequency grid.
C*****The new DV must be <= 2*HWHM/MDVHW, where the parameter MDVHW
C*****is nominally 12 (educated guess.)
      DVN = 2.*HWHM/MDVHW
      If (DV .gt. DVN) Then
          Write(IPR,*) ' FFTSCN: input grid too coarse. ',
     1        'Interpolating onto a grid with dv = ',DVN

C*****    The interpolated file will be on UNIT = KFILE
          Call Getunt(KFILE)
          Open(KFILE,Status='Scratch',Form='Unformatted')

C*****    Interpolate onto new grid.
          Call Intpdr(IFILE,KFILE,V1Z,V2Z,DVN,IFILST,JEMIT,IERR)
          If (IERR .ne. 0) Then
              Write(IPR,*) 'FFTSCN - error: Error in interpolation:',
     1             ' STOP'
              Goto 125
          Endif

C*****    Need to reposition KFILE to just after the file header
          Rewind KFILE

          Call Gethdr(KFILE,0,JDATA,IEOFSC)
C*****    Following statement correct ??? (have interpolated to the
C*****    desired parameter??)
          JCONVT = 0
      Else
          KFILE = IFILE
      Endif

C*****Decide whether to calculate the apodization function
C*****analytically (IVX = 1) or as the fft of the scanning
C*****function (IVX = -1). The input value of IVX (if not 0)
C*****overides.
      If( IVX .LT. -1  .OR.  IVX .GT. 1) Then
          Write(IPR,*) ' FFTSCN - error: IVX is out of range, = ',
     1       IVX,': STOP'
          Goto 125
      Endif
      If(IVX .EQ. 0) Then
          If(              IVX = 1
          Else
              IVX = -1
          Endif
      Endif
      If(JFN .EQ. 0) IVX = 0

      If(IVX .EQ. 1) Then
          Write(IPR,'(/,A,A)') ' Apodization function will be ',
     1         'calculated analytically'
      Elseif (IVX .EQ. -1) Then
          Write(IPR,'(/,A,A)') ' Apodization function will be ',
     1         'calculated as the fft of the scanning function'
      Endif

C*****Parmameters checked, are OK.

C*****Load spectrum from V1Z to V2Z into FUNCT1 (or file on LFILE1
C*****if there are more than LPTSMX points). V1Z and V2Z will be
C*****adjusted to fall on the input frequency grid. Total points
C*****is LTOTAL, the total records (including zeroed records) is LREC
C*****Both LTOTAL and LREC must be a power of 2 (LREC can be 1).
C*****If LREC = 1, then a memory based FFT is used.  If LREC>1, then
C*****a disk based FFT is used.

C*****Get free file unit number for LFILE1
      Call Getunt(LFILE1)

      Call Loadsp(KFILE,LFILE1,JCONVT,JEMIT,V1Z,V2Z,LREC,LTOTAL,
     1            FUNCT1,IERROR)
      If(IERROR .NE. 0) Then
           Write(IPR,'(2A)') ' LOADSP detected an error: STOP'
           Goto 125
      Endif

      M = 1
      If(JFN .EQ. 0) Then
C*****     Rectangular scanning function (boxcar)
           M = INT(2.0*HWHM/DV)
           If(M .LT. 2) Then
               Write(IPR,*) ' Error - width of rectangular scanning ',
     1               'function is less than 2*DV: STOP'
               Goto 125
           Endif
      Elseif (NOBOX .EQ. 0) Then
C*****     If the scanning function is wide enough compared to the DV,
C*****     it is possible to pre-scan the data with a rectanglar
C*****     function (boxcar) before the convolution.  This procedure
C*****     reduces the number of points in the spectrum, saving
C*****     computer time and reducing storage space.  The effect of
C*****     the rectangular smoothing can be eliminated by deconvolving
C*****     after smoothing with the regular scanning function.  This
C*****     procedure is disabled if MRATIN < 0.

C*****     The value of M, the number of points to average, is based
C*****     on the criterion that the full width of the boxcar (M*DV) be
C*****     no more than 2*HWHM/MRATIO.
           M = 2.0*HWHM/(MRATIO*DV)
           If(M .lt. 2) Write(IPR,*) ' Boxcaring not possible--M lt 2'
      Endif
      If((M .GE. 2) .AND. (NOBOX .EQ. 0)) Then
C*****    Adjust V1, V2, and DV
          V1Z = V1Z+DV*(M-1)/2.0
          KTOTAL = LTOTAL/M
          DV  = M*DV
          V2Z = V1Z+DV*(KTOTAL-1)
          Write(IPR,25) ' Prescanning the spectrum with the BOXCAR ',
     1       'instrument function',
     2       ' Ratio of boxcar to HWHM (MRATIO) = ',MRATIO,
     3       ' Shrink ratio (M) = ',M,
     4       ' New DV = ',DV
   25     Format(/,A,A,/,A,I4,/,A,I4,/,A,F12.5)

C*****    Perform the averaging
          Call Boxcar(M,LFILE1,FUNCT1,LREC,LTOTAL,JEMIT)
      Endif

C*****If JFN = 0, then the smoothing (boxcar) is complete.
      If(JFN .EQ. 0) Goto 95

C*****If the FFT can be performed in memory (LREC = 1), then find the
C*****smallest sized FFT possible = LPTFFT = smallest power of 2 > LTOTAL
C*****and < LPTSMX
      If(LREC .eq. 1) Then
          POWER = ALOG(FLOAT(LTOTAL))/ALOG(2.0)
          If(POWER-INT(POWER) .EQ. 0) Then
              LPTFFT = 2**INT(POWER)
          Else
              LPTFFT = 2**(INT(POWER)+1)
          Endif

          Write(IPR,*) ' In-memory FFT: points, FFT points = ',
     1       LTOTAL,', ',LPTFFT
      Else
          LPTFFT = -1
          Write(IPR,*) ' Disk-based FFT: points,  FFT records = ',
     1       LTOTAL,', ',LREC
      Endif

C*****Take FFT of spectrum, store in FUNCT1 if LTOTAL > LPTSMX, else
C*****put on file on unit LFILE1
      Call Fourtr(LREC,LPTFFT,LFILE1,FUNCT1,1)

C*****Calculate apodization and store in FUNCT2 or on LFILE2
      Call Getunt(LFILE2)
      Call Scntrn(JFN,A,IVX,DV,LREC,LPTFFT,LFILE2,FUNCT2,
     1            PARM1,PARM2,PARM3)

C*****Multiply FUNCT1 and FUNCT2 and store the result in FUNCT1 or
C*****on LFILE1
      Call Multrn(LREC,LFILE2,LFILE1,FUNCT2,FUNCT1)

C*****If the spectrum has been pre-scanned with a rectangle, remove the
C*****effects of the rectangle by deconvolving, i.e. divide the
C*****transform of the scanned spectrum by the transform of the
C*****rectangle.  This later function is a very broad sinc.
      If(M .GE. 2 .AND. NOBOX.EQ.0 .AND. NOFIX .EQ. 0) Then

C*****    Calculate transform of the boxcar which is a rectangle of
C*****    HWHM = DV/2, where DV is the new DV. The parameter A =< HWHM
          Write(IPR,*) ' Deconvolving'
          Call Scntrn(-1,DV/2.0,1,DV,LREC,LPTFFT,LFILE2,FUNCT2,
     *         0.0,0.0,0.0)
          Call Multrn(LREC,LFILE2,LFILE1,FUNCT2,FUNCT1)
      Endif

C*****Transform FUNCT1 back to spectral domain, store in FUNCT1 or on
C*****LFILE1
      Call Fourtr(LREC,LPTFFT,LFILE1,FUNCT1,-1)

   95 Continue

C*****Adjust V1S and V2S to fit the current spectral grid
C*****Actually, let V1S be one DV less than the largest VZ <= V1
C*****and let V2S be one DV larger than the smallest VZ >= V2
C*****This procedure gives two points beyond V1 and V2, as required for
C*****4 point interpolation
      N1 = INT((V1-V1Z)/DV)
      V1S = V1Z+(N1-1)*DV
      If (V1S .LT. V1Z) Then
          N1 = 1
          V1S = V1Z
      Endif

      N2 = INT((V2-V1Z)/DV+3.01)
      V2S = V1Z+(N2-1)*DV
      If (V2S .GT. V2Z) Then
          N2 = (V2Z-V1Z)/DV+1.01
          V2S = V1Z+(N2-1)*DV
      Endif

      NTOTAL = N2-N1+1

      Write(IPR,'(/,A,/A,F12.5,/,A,F12.5,/,A,F12.5,/,A,I7)')
     1    ' Adjusted Limits of Scanned Spectrum:',
     2    ' V1 = ',V1S,' V2 = ',V2S,' DV = ',DV,' N  =',NTOTAL

C*****Write FUNCT1 = scanned spectrum out to a file on JUNIT in LBLRTM
C*****format.  First, modify the header.
      V1C = V1S
      V2C = V2S
      JVAR = 0
      XSCID = JVAR + 10*(JFN + 10*(JEMIT))
      XHWHM = HWHM

      ISCHDR = ISCHDR+1

C*****If DVOUT > 0, then write the spectral file to a temporary file,
C*****and interpolate it to JFILE
      If (DVOUT .gt. 0) Then
          Call Getunt(NFILE)
          Open(NFILE,Status='Scratch',Form='Unformatted')
          Rewind IFILE
      Else
          NFILE = JFILE
      Endif

      Call BUFOUT(NFILE,FILHDR(1),NFHDRF)
      Call Wrtspc(N1,NTOTAL,LREC,LFILE1,FUNCT1,NFILE)

C*****Interpolate the spectrum onto the desired grid
      If (DVOUT .gt. 0) Then

          Write(IPR,'(/,A,2F12.4,F12.6)') ' Interpolating the '//
     1        'spectrum to the grid definded by:', V1,V2,DVOUT

          Call Intpdr(NFILE,JFILE,V1,V2,DVOUT,1,JEMIT,IERR)
          If (IERR .ne. 0) Then
              Write(IPR,*) 'FFTSCN - error: Error in interpolation:',
     1             ' STOP'
              Goto 125
          Endif
          Close(NFILE)
      Endif

C*****End of convolution for this scan request

      Close(LFILE1)
      If (LFILE2.NE.0) Close(LFILE2)

C*****End of file loop for this scan request
  105 Continue

C*****Read next scan request
      Goto 100

  115 Continue
      Write(IPR,*) ' End of scan function requests'
      Return

  120 Continue
      Write(IPR,*) ' FFTSCN: End of file detected on unit ',IRD
      Stop 'Stopped in FFTSCN'

  122 Continue

      Write(IPR,*) ' FFTSCN: Error in reading scan fn parameters'
      Stop 'Stopped in FFTSCN'

  125 Continue
      Write(IPR,*) ' Stopped in FFTSCN due to error'
      Stop ' Stopped in FFTSCN: See TAPE6'
      End

      Subroutine Boxcar(M,LFILE,FUNCT,LREC,LTOTAL,JEMIT) 1
C************************************************************************
C     This subroutine performs the "BOXCAR" smoothing of the spectrum.
C     This smoothing simply averages M adjacent points together, reducing
C     the number of output points by a factor of M. (It is not a running
C     average where the number of input and output points are the same.)
C     The spectrum is stored either on the file LFILE, if the number of
C     records LREC > 1, or in the array FUNCT if LREC = 1.  LTOTAL is
C     the total number of output points after smoothing.
C     The smoothed spectrum is stored in the array FUNCT if LTOTAL <
C     LPTSMX, or is written back to the file on unit LFILE, in which
C     LREC becomes the new number of records. (The old records for L >
C     LREC will still exist but will be ignored.)
C     LREC must still be a power of 2, and zeroed records will be added
C     as necessary. JEMIT flags transmittance (0) or radiance (1)
C************************************************************************

C***********************************************************************
C     LPTSMX is the size of a data block for the FFT.  If the number of
C     data points is LPTSMX or less, the FFT is done in memory.  If it
C     is larger, then a disk based FFT is performed, and LPTSMX is the
C     size in words of each record of the file. The in-memory routine is
C     about 20 percent more efficient than the disk-based routine, for
C     same number of points.  For efficiency, LPTSMX should be made
C     as large a possible so that the computation can be done in memory.
C     However, on virtual memory machines (e.g. VAX), if LPTSMX is too
C     large, then the computation will be done in VIRTUAL memory.  Since
C     the in-memory routine uses widely scattered points, operating
C     system will spend a great deal of time swapping data in and out
C     (thrashing) and the efficiency will be very poor.
C
C     The following problem has been corrected (May, 1993).  The minimum
C     size of an FFT is now the smallest power of 2 greater than the
C     of data points.  LPTSMX should be set to the larges value consistant
C     with real memory.
C
C*    However, LPTSMX is also the minimum size of an FFT (this is a
C*    design flaw of this program).  If LPTSMX is much larger than the
C*    number of points in the spectrum, computational time is wasted.
C*
C*    Therefore, LPTSMX should be set to a value somewhat larger than
C*    the size of the smallest typical spectrum, but no larger than the
C*    largest value possible without thrashing.
C
C     IBLKSZ is the record length in the OPEN statement, and may be
C     in bytes or words,  depending on the operating system.  For VAX
C     and CDC, it is in words.  For MicroSoft FORTRAN, it is in bytes.
C***********************************************************************
      PARAMETER (LSIZE = 65536)
C*****Following line for computers where the blocksize is measured
C*****in words, e.g. VAX, CDC/NOS/VE
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX,LPTSM8=LPTSMX/8)

C*****Following line for computers where the blocksize is measured
C***** in bytes, e.g. MS FORTRAN, SUN, Alliant
      PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*4,LPTSM8=LPTSMX/8)

C*****Following line for computers with 64 bit words where the blocksize is
C*****measured in bytes, e.g. CRAY
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*8,LPTSM8=LPTSMX/8)
C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN
      Dimension FUNCT(LPTSMX),BOX(LPTSMX)

C*****Calculate the number of points and records after smoothing
C*****KRDATA is the number of output points (including partial
C*****records) which include real data (not just FILL).
      KTOTAL = LTOTAL/M
      ARDATA = FLOAT(KTOTAL)/FLOAT(LPTSMX)
      If((ARDATA-INT(ARDATA)) .EQ. 0.0) Then
          KRDATA = INT(ARDATA)
      Else
          KRDATA = INT(ARDATA)+1
      Endif
C*****Find KREC = smallest power of 2 .GE. KRDATA
      POWER = ALOG(FLOAT(KRDATA))/ALOG(2.0)
      If((POWER-INT(POWER)) .EQ. 0) Then
          KREC = 2**INT(POWER)
      Else
          KREC = 2**INT(POWER+1)
      Endif

C*****Get the first record from LFILE, if necessary
      If(LREC .GT. 1) Then
          IREC = 1
          Read(LFILE,rec=IREC,err=900) (FUNCT(I),I=1,LPTSMX)
      Endif

C*****I is index for input points, J is index for output points within
C*****a record. IREC is index for input records, JREC is for
C*****output records.
      I = 0
      J = 0
      JREC = 0

C*****Loop over output points
      Do 210 K=1,KTOTAL

C*****    Loop over the M elements for each output point
          SUM = 0.0
          DO 200 MM=1,M
              If(I .EQ. LPTSMX) Then
C*****            Get another record from LFILE
                  IREC = IREC+1
                  Read(LFILE,rec=IREC,err=900) (FUNCT(II),II=1,LPTSMX)
                  I = 0
              Endif
              I = I+1
              SUM = SUM + FUNCT(I)
  200     Continue

          J = J+1
          BOX(J) = SUM/Float(M)

          If(J .EQ. LPTSMX) Then
C*****        Write out a record
              JREC = JREC+1
              Write(LFILE,rec=JREC,err=910) (BOX(JJ),JJ=1,LPTSMX)
              J = 0
          Endif

  210 Continue

C*****If necessary, fill out the end of the last record with
C*****0's (radiance) or 1's (transmittance)
      If(J .GT. 0) Then
          If(JEMIT .EQ. 0) THEN
              FILL = 1.0
          Else
              FILL = 0.0
          Endif
          Do 220 JJ=J+1,LPTSMX
              BOX(JJ) = FILL
  220     Continue
      Endif

C*****If only one record, copy BOX to FUNCT
      If (KREC .EQ. 1) Then
          Do 300 JJ=1,LPTSMX
              FUNCT(JJ) = BOX(JJ)
  300     Continue
C*****Else if there is an unwritten partial record, write it
      Elseif (J .GT. 0) Then
          JREC = JREC+1
          Write(LFILE,rec=JREC,err=910) (BOX(J),J=1,LPTSMX)
      Else
      Endif

C*****Write empty records if necessary.
      If(KREC .GT. KRDATA) Then
          Do 310 J=1,LPTSMX
              BOX(J) = FILL
  310     Continue
          Do 320 K=KRDATA+1,KREC
              JREC = JREC+1
              Write(LFILE,rec=JREC,err=910) (BOX(J),J=1,LPTSMX)
  320     Continue
      Endif

C*****At this point JREC should equal KREC
      If(KREC .GT. 1  .AND.  JREC .NE. KREC) Then
          Write(IPR,'(/,2A,I4,A,I4)') ' BOXCAR-ERROR: JREC .NE.',
     1       ' KREC,  JREC = ',JREC,' AND KREC = ',KREC
          Stop 'Stopped in BOXCAR'
      Endif

C*****Reset the total number of records
      LREC = KREC
      LTOTAL = KTOTAL

      Return

  900 Continue
      Write(IPR,*) ' BOXCAR: error reading data from unit ',LFILE,
     1    '   record = ',IREC
      Stop 'Stopped in BOXCAR'

  910 Continue
      Write(IPR,*) ' BOXCAR: error writing data to unit ',LFILE,
     1    '   record = ',KREC
      Stop 'Stopped in BOXCAR'

      End

      Subroutine Ckfile(IFILE,IUNIT,IDIR,IERR) 2,2
C***********************************************************************
C     This subroutine checks the status of a file and opens one if
C     if necessary.
C     IFILE is the default unit number.
C     The user specifies a file on IUNIT.  If IUNIT = 0, then the file
C     on IFILE is used.  If IUNIT < 0, then a file name (20 characters
C     max) is read in, and IFILE = -IUNIT
C     IDIR specifies the direction: 0 = Input, 1 = Output.
C     IERR is an error flag: 0 = no error, 1 = error
C
C     Input:
C     If IUNIT GE 0, Then
C        If IUNIT = 0 Then IFILE = IFILE Else IFILE = IUNIT
C        If a file is not open on IFILE, Then
C            Look for a file of the name TAPExx, where xx = IFILE
C            If TAPExx does not exist, then ERR = 1, Return
C            Open TAPExx on IFILE
C        Return
C     If IUNIT LT 0, Then
C        IFILE = -IUNIT
C        Read in FILENAME
C        If FILENAME does not exist, Then IERR = 1, Return
C        Open FILENAME on IFILE
C        Return
C
C     Output:
C     If IUNIT GE 0, Then
C         If IUNIT = 0 Then IFILE = IFILE Else IFILE = IUNIT
C         IF a file is not open on IFILE, Then
C             Set FILENAME to 'TAPExx' where xx is IFILE
C             If FILENAME exists Then
C                overwrite FILENAME
C             Else
C                Open FILENAME
C         Return
C
C     If IUNIT < 0, Then
C         IFILE = -IUNIT
C         Read in FILENAME
C         IF FILENAME exists, Then IERR = 1, Return
C         Open FILENAME on IFILE
C     Return
C***********************************************************************

C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

      Logical OP,EX
      Character FILNAM*60,CTAPE*4

C*****CTAPEdefines the default prefix for LBLRTM FILENAMEs, e.g. TAPE12
      Data FILNAM/' '/,CTAPE/'TAPE'/

      IERR = 0
      If(IDIR .EQ. 0) Then
C*****    File for input
          If(IUNIT .GE. 0) Then
              If(IUNIT .GT. 0) IFILE = IUNIT
              Inquire(UNIT=IFILE,OPENED=OP)
              If(.NOT.OP) Then
                  Write(FILNAM,'(A,I2.2)') CTAPE,IFILE
                  Write(IPR,'(/,A,A)') ' Input file name is: ',FILNAM
                  Inquire(FILE=FILNAM,EXIST=EX)
                  If (EX) Then
                      Open(IFILE,FILE=FILNAM,STATUS='OLD',
     1                    FORM='UNFORMATTED')
                  Else
                      Write(IPR,'(/,A,A)') ' Error: Input file does ',
     1                    'not exist'
                      IERR=1
                      Return
                  Endif
              Endif
          Else
              Read(IRD,'(A)') FILNAM
              Write(IPR,'(A,A)') ' Input  file name is: ',FILNAM
              Inquire(FILE=FILNAM,EXIST=EX)
              If(.NOT. EX) Then
                  Write(IPR,'(3A)') ' Error: input file does not ',
     1                'exist'
                  IERR = 1
                  Return
              Endif
C*****        Get a free file unit number
              Call Getunt(IFILE)
              Open(UNIT=IFILE,FILE=FILNAM,STATUS='OLD',
     1            FORM='UNFORMATTED')
          Endif

      Else
C*****    File for output
          If(IUNIT .GE. 0) Then
              If(IUNIT .GT. 0) IFILE = IUNIT
C*****        Use this file even if it already exists
              Inquire(UNIT=IFILE,OPENED=OP)
              If(OP) Then
                  Rewind IFILE
              Else
                  Write(FILNAM,'(A,I2.2)') CTAPE,IFILE
                  Write(IPR,'(/,A,A)') ' Output file name is: ',FILNAM
                  Open(IFILE,FILE=FILNAM,STATUS='UNKNOWN',
     1                FORM='UNFORMATTED')
              Endif
          Else
              Read(IRD,'(A)') FILNAM
              Write(IPR,'(2A)') ' Output file name is: ',FILNAM
C*****        Get a free file unit number
              Call Getunt(IFILE)
              OPEN(UNIT=IFILE,FILE=FILNAM,STATUS='UNKNOWN',
     1            FORM='UNFORMATTED')
          Endif
      Endif

      Return
      End

      Subroutine Fourtr(LREC,LPTFFT,LFILE,SPECT,IDIR) 3,2
C***********************************************************************
C     Fourtr computes the Fourier transform of a data set.
C     If LREC = 1,then the input data is in the array SPECT and the
C     result is returned in SPECT. LPTFFT is the size of the FFT, and
C     must be less or equal to than LPTSMX.
C     If LREC > 1, then the input data is on file LFILE in blocks of
C     LPTSMX and the result is written to LFILE.  IDIR is 0 for going
C     from the time domain to the spectral domain, 1 for the other
C     direction.
C***********************************************************************

C***********************************************************************
C     LPTSMX is the size of a data block for the FFT.  If the number of
C     data points is LPTSMX or less, the FFT is done in memory.  If it
C     is larger, then a disk based FFT is performed, and LPTSMX is the
C     size in words of each record of the file. The in-memory routine is
C     about 20 percent more efficient than the disk-based routine, for
C     same number of points.  For efficiency, LPTSMX should be made
C     as large a possible so that the computation can be done in memory.
C     However, on virtual memory machines (e.g. VAX), if LPTSMX is too
C     large, then the computation will be done in VIRTUAL memory.  Since
C     the in-memory routine uses widely scattered points, operating
C     system will spend a great deal of time swapping data in and out
C     (thrashing) and the efficiency will be very poor.
C
C     The following problem has been corrected (May, 1993).  The minimum
C     size of an FFT is now the smallest power of 2 greater than the
C     of data points.  LPTSMX should be set to the larges value consistant
C     with real memory.
C
C*    However, LPTSMX is also the minimum size of an FFT (this is a
C*    design flaw of this program).  If LPTSMX is much larger than the
C*    number of points in the spectrum, computational time is wasted.
C*
C*    Therefore, LPTSMX should be set to a value somewhat larger than
C*    the size of the smallest typical spectrum, but no larger than the
C*    largest value possible without thrashing.
C
C     IBLKSZ is the record length in the OPEN statement, and may be
C     in bytes or words,  depending on the operating system.  For VAX
C     and CDC, it is in words.  For MicroSoft FORTRAN, it is in bytes.
C***********************************************************************
      PARAMETER (LSIZE = 65536)
C*****Following line for computers where the blocksize is measured
C*****in words, e.g. VAX, CDC/NOS/VE
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX,LPTSM8=LPTSMX/8)

C*****Following line for computers where the blocksize is measured
C***** in bytes, e.g. MS FORTRAN, SUN, Alliant
      PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*4,LPTSM8=LPTSMX/8)

C*****Following line for computers with 64 bit words where the blocksize is
C*****measured in bytes, e.g. CRAY
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*8,LPTSM8=LPTSMX/8)
C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

C*****For LREC = 1, SPECT contains the function to be transformed.
      DIMENSION SPECT(*)

C*****A, B, and IWORK are work spaces used for REALBG. If REALBG
C*****is used, then SPECT is also used as work space.
      DIMENSION A(LPTSMX),B(LPTSMX),IWORK(LPTSM8)

C*****SPECT and IWORK are never needed at the same time
C     EQUIVALENCE (SPECT,IWORK)

      If(LREC .EQ. 1) Then
C*****    Use FFT from Numerical Recipies.  REALFT(DATA,N,IDIR)  expects
C*****    DATA to be dimensioned 2*N.
          If(LPTFFT .gt. LPTSMX) Goto 900
          Call REALFT(SPECT,LPTFFT/2,IDIR)
      Else
C*****    Use file based FFT from M. Esplin

          Call REALBG(LFILE,IDIR,LREC,LPTSMX,A,B,SPECT,IWORK)

      Endif

      Return

  900 Continue
      Write(IPR,*) ' Fourtr: Error-LPRFFT > LPRSMX'
      Write(IPR,*) ' LPTFFT = ',LPTFFT, ' LPTSMX = ',LPTSMX
      Stop

      End

      Subroutine Gethdr (IFILE,IPRNT,JDATA,IEOFSC) 3,1
C************************************************************************
C     This subroutine reads the first record an LBLRTM file (the file
C     header) from unit IFILE.  It determines what data is on the file
C     according to the following scheme:
C     Determine what quantity is on the file (i.e., Optical depth,
C     Transmittance, Transmittance and Radiance, Radiance)
C     JDATA    IFILE contains
C         0    optical depth  (monochromatic)
C         1    transmittance  (previously scanned)
C         2    radiance and transmittance  (monochromatic)
C         3    radiance  (previously scanned)
C
C     If IPRNT = 1, then the contents of the file header are printed.
C************************************************************************

C*****Computers with 32 bit words need the Double Precision Statements
C*****Computers with 64 bit words (e.g. Cyber) do not.
C*****Frequency variables start with V
      Implicit Real*8           (V)
      Character*8      XID,       HMOLID,      YID
      Real*8               SECANT,       XALTZ

C*****Blank Common carries the spectral data
      COMMON S(2450),R1(2650),XF(251)

C*****SCNHRD carries the header information for the scanned file
      COMMON /SCNHDR/ XID(10),SECANT,PAVE,TAVE,HMOLID(60),XALTZ(4),
     *                WK(60),PZL,PZU,TZL,TZU,WBROAD,DV ,V1C,V2C,TBOUND,
     *                EMISIV,FSCDID(17),NMOL,LAYER ,YI1,YID(10),LSTWDF
      DIMENSION FILHDR(2),IFSDID(17)
      EQUIVALENCE (FILHDR(1),XID(1))
      EQUIVALENCE (FSCDID(1),IFSDID(1),IHIRAC),(FSCDID(2),ILBLF4),
     C (FSCDID(3),IXSCNT),(FSCDID(4 ),IAERSL ),(FSCDID(5),IEMIT),
     C (FSCDID(6),ISCHDR ),(FSCDID(7 ),IPLOT  ),(FSCDID(8),IPATHL),
     C (FSCDID(9),JRAD  ),(FSCDID(10),ITEST  ),(FSCDID(11),IMRG),
     C (FSCDID(12),XSCID),(FSCDID(13),XHWHM  ),(FSCDID(14),IDABS),
     C (FSCDID(15),IATM ),(FSCDID(16),LAYR1  ),(FSCDID(17),NLAYFS),
     C (YID(1)    ,HDATE),(YID(2),      HTIME),(YI1,IMULT)

C*****PANL carries the information from the panel header
      COMMON /PANL/ V1P,V2P,DVP,NP
      DIMENSION PNLHDR(4)
      EQUIVALENCE (PNLHDR(1),V1P)


C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

C*****Read in the file header
      Call BUFIN(IFILE,IEOFSC,FILHDR(1),NFHDRF)

      If(IEOFSC .le. 0) Then
          Write(IPR,*) ' GETHDR: EOF on File ',IFILE,
     1       '  IEOFSC = ',IEOFSC
          Return
      Endif

C*****Determine what data is on the file
      JDATA = -1
      If(XSCID .le. 0) Then
          ISCAN = 0
      Else
          ISCAN = ISCHDR
      Endif
      If(IEMIT .EQ. 0) Then
          If(ISCAN .LE. 0) Then
              JDATA = 0
          Else
              JDATA = 1
          Endif
      Else
          If(ISCAN .LE. 0) Then
              JDATA = 2
          Else
              JDATA = 3
          Endif
      Endif

      If(JDATA .EQ. -1) Then
          Write(IPR,10) ' GETHDR: error, JDATA = -1, type of data '//
     c       'cannot be determined'
      Endif

      If(IPRNT .EQ. 1 .OR. JDATA .EQ. -1) Then

      Write(IPR,10) IFILE
   10 FORMAT(/,' File Header for file on unit',I3)

      WRITE(IPR,20) XID,(YID(M),M=1,2)
   20 FORMAT(' ',10A8,2X,2(1X,A8,1X))

      WRITE(IPR,30) LAYR1,NLAYFS
   30 FORMAT(/,' Initial Layer = ',I4,',  Final Layer =',I4)

      WRITE(IPR,40) SECANT,PAVE,TAVE,DV,V1C,V2C,JDATA
   40 FORMAT(/,' Secant     =',F12.5,/ ' Press (mb) =',F12.5 /,
     1         ' Temp (K)   =',F9.2 ,/,' DV (cm-1)  =',F15.8,/,
     2         ' V1 (cm-1)  =',F13.6,/ ' V2 (cm-1)  =',F13.6,//,
     3         ' JDATA      =',I6)

      WRITE(IPR,50) WBROAD,(HMOLID(M),WK(M),M=1,NMOL)
   50 FORMAT(/,' Column Density (molecules/cm**2)',
     1   /, '      Wbroad = ',1PE10.3,
     2   /,(A12,       ' = ',1PE10.3))

      Endif

      Return
      End

      Subroutine Getpnl(IFILE,JCONVT,IEOFSC) 2,4
C***********************************************************************
C     This subroutine gets one panel of data from the file on IFILE in
C     LBLRTM format. A panel consists of a header plus one or two data
C     records.  The header contains the  the initial and final
C     wavenumbers, wavenumber increment, and number of points in the
C     record. The data contained in the record(s) depends upon the
C     initial calculation and whether the file has been scanned
C     previously.
C         Initial Calculation   record
C            transmittance      one record, optical depth
C            radiance           two records, radiance then transmittance
C     If the file has been scanned previously, then there is only one
C     record, either transmittance or radiance.
C
C     JCONVT determins which data is to be extracted and whether it is
C     to be converted.
C
C     JCONVT   action
C          0   single record, no conversion (scanned trans or rad)
C          1   single record  optical depth to transmittance (mono.)
C          2   two records, get first (mono. radiance)
C          3   two records, get second (mono. transmittance)
C
C     IEOFSC equals 0 if a hardware end of file is encountered, equals
C      -99 for the end of an LBLRTM file, otherwise it is 1.
C
C     V1P, V2P, DVP, NP are the initial and final wavenumbers, the
C     wavenumber increment and the number of points in the record(s).
C     They are carried in COMMON /PANL/
C
C     The spectral data is returned in S carried in blank common.
C
C***********************************************************************

C*****Computers with 32 bit words need the Double Precision Statements
C*****Computers with 64 bit words (e.g. Cyber) do not.
C*****Frequency variables start with V
      Implicit Real*8           (V)
      Character*8      XID,       HMOLID,      YID
      Real*8               SECANT,       XALTZ

C*****Blank Common carries the spectral data
      COMMON S(2450),R1(2650),XF(251)

C*****SCNHRD carries the header information for the scanned file
      COMMON /SCNHDR/ XID(10),SECANT,PAVE,TAVE,HMOLID(60),XALTZ(4),
     *                WK(60),PZL,PZU,TZL,TZU,WBROAD,DV ,V1C,V2C,TBOUND,
     *                EMISIV,FSCDID(17),NMOL,LAYER ,YI1,YID(10),LSTWDF
      DIMENSION FILHDR(2),IFSDID(17)
      EQUIVALENCE (FILHDR(1),XID(1))
      EQUIVALENCE (FSCDID(1),IFSDID(1),IHIRAC),(FSCDID(2),ILBLF4),
     C (FSCDID(3),IXSCNT),(FSCDID(4 ),IAERSL ),(FSCDID(5),IEMIT),
     C (FSCDID(6),ISCHDR ),(FSCDID(7 ),IPLOT  ),(FSCDID(8),IPATHL),
     C (FSCDID(9),JRAD  ),(FSCDID(10),ITEST  ),(FSCDID(11),IMRG),
     C (FSCDID(12),XSCID),(FSCDID(13),XHWHM  ),(FSCDID(14),IDABS),
     C (FSCDID(15),IATM ),(FSCDID(16),LAYR1  ),(FSCDID(17),NLAYFS),
     C (YID(1)    ,HDATE),(YID(2),      HTIME),(YI1,IMULT)

C*****PANL carries the information from the panel header
      COMMON /PANL/ V1P,V2P,DVP,NP
      DIMENSION PNLHDR(4)
      EQUIVALENCE (PNLHDR(1),V1P)


C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

      DIMENSION DUMMY(1)

C*****Read the panel header
      Call BUFIN(IFILE,IEOFSC,PNLHDR(1),NPHDRF)
      If(IEOFSC .LE. 0) Go to 200

C*****Read in the spectral data and convert if necessary

      Call BUFIN(IFILE,IEOFSC,S(1),NP)
      If(IEOFSC .LE. 0) Go to 210
      If(JCONVT .EQ. 3) Call BUFIN(IFILE,IEOFSC,S(1),NP)
      If(IEOFSC .LE. 0) Go to 210
      If(JCONVT .EQ. 1) Then
          Do 100 N=1,NP
              If(                 S(N) = 1.0
              Elseif(                 S(N) = EXPMIN
              Else
                 S(N) = EXP(-S(N))
              Endif
  100     Continue
      Endif
      If(JCONVT .EQ. 2) Then
          Call BUFIN(IFILE,IEOFSC,DUMMY(1),1)
          If(IEOFSC .LE. 0) Go to 210

      Endif

  200 Continue

      Return

  210 Continue
      Write(IPR,10) 'GETPNL: error, end of file encountered after'//
     c   ' panel header'
   10 Format(1x,A)
      Stop 'Stopped in GETPNL'
      End

      Subroutine Getunt(IFILE) 6
C**********************************************************************
C     This subroutine gets the first free file unit number > 60
C     If there are none, stop with error message
C**********************************************************************

C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

      Logical OP

      Do 100 I=61,99
          Inquire(UNIT=i,OPENED=OP)
          If(.NOT. OP) Then
              IFILE = I
              Return
          Endif
  100 Continue

      Write(IPR,'(2A)') ' Error: no free file unit numbers 61 to 99, ',
     1   'Stop'
      Stop
      End



      Subroutine Loadsp(IFILE,LFILE,JCONVT,JEMIT,V1,V2,LREC,LTOTAL, 1,2
     1                  SPECT,IERROR)
C***********************************************************************
C     This subroutine loads the spectral data between V1 and V2 from
C     the file on IFILE into the array SPECT, if the total number of
C     points LTOTAL < LPTSMX, (ie 1 record) or else writes it to the
C     direct access file on unit LFILE in records of LPTSMX.  LREC is
C     the number of records.  Both LPTSMX and LREC must be powers of 2
C     (LREC may be 1).  Partial records will be completed with zero's
C     (radiance) or 1's (transmittance) and records of all zero's or
C     1's  will be added as needed.  JCONVT indicates how the data
C     is to be extracted from the LBLRTM file. JEMIT flags transmittance
C     (0) or radiance(1).
C***********************************************************************

C*****Computers with 32 bit words need the Double Precision Statements
C*****Computers with 64 bit words (e.g. Cyber) do not.
C*****Frequency variables start with V
      Implicit Real*8           (V)
      Character*8      XID,       HMOLID,      YID
      Real*8               SECANT,       XALTZ

C*****Blank Common carries the spectral data
      COMMON S(2450),R1(2650),XF(251)

C*****SCNHRD carries the header information for the scanned file
      COMMON /SCNHDR/ XID(10),SECANT,PAVE,TAVE,HMOLID(60),XALTZ(4),
     *                WK(60),PZL,PZU,TZL,TZU,WBROAD,DV ,V1C,V2C,TBOUND,
     *                EMISIV,FSCDID(17),NMOL,LAYER ,YI1,YID(10),LSTWDF
      DIMENSION FILHDR(2),IFSDID(17)
      EQUIVALENCE (FILHDR(1),XID(1))
      EQUIVALENCE (FSCDID(1),IFSDID(1),IHIRAC),(FSCDID(2),ILBLF4),
     C (FSCDID(3),IXSCNT),(FSCDID(4 ),IAERSL ),(FSCDID(5),IEMIT),
     C (FSCDID(6),ISCHDR ),(FSCDID(7 ),IPLOT  ),(FSCDID(8),IPATHL),
     C (FSCDID(9),JRAD  ),(FSCDID(10),ITEST  ),(FSCDID(11),IMRG),
     C (FSCDID(12),XSCID),(FSCDID(13),XHWHM  ),(FSCDID(14),IDABS),
     C (FSCDID(15),IATM ),(FSCDID(16),LAYR1  ),(FSCDID(17),NLAYFS),
     C (YID(1)    ,HDATE),(YID(2),      HTIME),(YI1,IMULT)

C*****PANL carries the information from the panel header
      COMMON /PANL/ V1P,V2P,DVP,NP
      DIMENSION PNLHDR(4)
      EQUIVALENCE (PNLHDR(1),V1P)


C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN
C***********************************************************************
C     LPTSMX is the size of a data block for the FFT.  If the number of
C     data points is LPTSMX or less, the FFT is done in memory.  If it
C     is larger, then a disk based FFT is performed, and LPTSMX is the
C     size in words of each record of the file. The in-memory routine is
C     about 20 percent more efficient than the disk-based routine, for
C     same number of points.  For efficiency, LPTSMX should be made
C     as large a possible so that the computation can be done in memory.
C     However, on virtual memory machines (e.g. VAX), if LPTSMX is too
C     large, then the computation will be done in VIRTUAL memory.  Since
C     the in-memory routine uses widely scattered points, operating
C     system will spend a great deal of time swapping data in and out
C     (thrashing) and the efficiency will be very poor.
C
C     The following problem has been corrected (May, 1993).  The minimum
C     size of an FFT is now the smallest power of 2 greater than the
C     of data points.  LPTSMX should be set to the larges value consistant
C     with real memory.
C
C*    However, LPTSMX is also the minimum size of an FFT (this is a
C*    design flaw of this program).  If LPTSMX is much larger than the
C*    number of points in the spectrum, computational time is wasted.
C*
C*    Therefore, LPTSMX should be set to a value somewhat larger than
C*    the size of the smallest typical spectrum, but no larger than the
C*    largest value possible without thrashing.
C
C     IBLKSZ is the record length in the OPEN statement, and may be
C     in bytes or words,  depending on the operating system.  For VAX
C     and CDC, it is in words.  For MicroSoft FORTRAN, it is in bytes.
C***********************************************************************
      PARAMETER (LSIZE = 65536)
C*****Following line for computers where the blocksize is measured
C*****in words, e.g. VAX, CDC/NOS/VE
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX,LPTSM8=LPTSMX/8)

C*****Following line for computers where the blocksize is measured
C***** in bytes, e.g. MS FORTRAN, SUN, Alliant
      PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*4,LPTSM8=LPTSMX/8)

C*****Following line for computers with 64 bit words where the blocksize is
C*****measured in bytes, e.g. CRAY
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*8,LPTSM8=LPTSMX/8)

      DIMENSION SPECT(LPTSMX)
      IERROR = 0

C*****Skip over panels until the V1 is reached
  100 Continue
      Call GETPNL(IFILE,JCONVT,IEOFSC)
C*****Check for EOF
      If(IEOFSC .lt. 0) Then
          Write(IPR,10) '  LOADSP: end of file encountered on file'//
     c       'LFILE = ',LFILE,', skipping to next scan request'
   10     Format(A,I4,A)
          IERROR = 1
          Return
      Endif

C*****If V1P .GT. V1, then error
      If(V1P .GT. V1) Then
          Write(IPR,20) '  LOADSP: error, first data freq = ',V1P,
     c       ' is greater than requested V1 = ',V1
   20     Format(A,F12.4,A,F12.4)
          IERROR = 1
          Return
      Endif

C*****If V2P .LT. V1 then V1 has not been reached yet.  Get another panel.
      If(V2P .LT. V1) Go to 100

C*****Begin to accumulate the spectrum in SPECT
C*****Variables beginning with L refer to SPECT, with N refer to
C*****the input data in the array S
C*****LTOTAL = total number of points needed from input spectrum
C*****LRDATA = number of records containing real spectral data,
C*****         including partial records (which will be 0 or 1 filled.)
C*****LREC   = smallest power of 2 .GE. LRDATA = total number of
C*****         records on LFILE. Records in excess of LRDATA are all
C*****         0's or 1's
C*****LSLAST  = number of valid points in record LRDATA.
C*****Note: there is a potential roundoff problem using n = (v2-v1)/dv
C*****when n reaches 7 digits, the limit of single precision.
      LTOTAL = (V2-V1)/DV+1.1
C*****Recompute V2, in case of round off errors
      V2 = V1+DV*(LTOTAL-1)

      ARDATA = FLOAT(LTOTAL)/FLOAT(LPTSMX)
      If((ARDATA-INT(ARDATA)) .EQ. 0.0) Then
          LRDATA = INT(ARDATA)
      Else
          LRDATA = INT(ARDATA+1)
      Endif

      POWER = ALOG(FLOAT(LRDATA))/ALOG(2.0)
      If(POWER-INT(POWER) .EQ. 0) Then
          LREC = 2**INT(POWER)
      Else
          LREC = 2**(INT(POWER)+1)
      Endif

      LSLAST = MOD(LTOTAL,LPTSMX)
      If(LSLAST .EQ. 0) Then
          LSLAST = LPTSMX
      Endif

C*****LTOTAL = cululative total points
C*****LS = cumulative total points currently in SPECT
      LTOTAL = 0
      LS = 0

C*****N1 = index of next point in S to go into SPECT
C*****From first panel, N1 will in general not be 1
C*****NN = number of unused points available from S = NP-N1+1
C*****This is a correction from the original fftscn for a
C*****potential roundoff problem that occurs when the total
C*****number of points needed reaches 7 digits, the limit
C*****of single precision
      N1 = (V1 - V1P)/DV+1.00001
      NN = NP-N1+1

C*****Load S into SPECT for a total of LRDATA blocks
      DO 200 L = 1,LRDATA

C*****    LRECMX = total points needed for this record
          If(L .EQ. LRDATA) Then
              LRECMX = LSLAST
          Else
              LRECMX = LPTSMX
          Endif

C*****    While SPECT not full, put S into SPECT
  110     Continue
          If((LRECMX-LS) .EQ. 0) GO TO 180

C*****    If more points are needed from S, get them
          If(N1 .GT. NP) Then
              Call GETPNL(IFILE,JCONVT,IEOFSC)
              If(IEOFSC .LE. 0) Then
                  Write(IPR,*) '  LOADSP: error, ran out of data',
     1          ' before V1, skipping to next scan request'
              IERROR = 1
              Return
              Endif
              N1 = 1
              NN = NP
          Endif

C*****    SPECT has LS points already.  LMAX more points are
C*****    needed.
          LMAX = LRECMX - LS

C*****    NMAX is lesser of LMAX = space available in SPECT
C*****    and NN = points available from S
          NMAX = MIN(LMAX,NN)

C*****    Put points NMAX points from S, starting at N1,
C*****    into SPECT, starting at LS+1
          Do 120 N = N1,N1+NMAX-1
              LS = LS+1
              SPECT(LS) = S(N)
  120     Continue
          LTOTAL = LTOTAL+NMAX
          N1 = N1+NMAX
          NN = NN-NMAX

          Go To 110

C*****    SPECT is full
  180     Continue

          If(LS .GT. LPTSMX) Then
              Write(IPR,*) 'LOADSP: logic error, overfilled SPECT; ',
     1        ' LS, LPTSMX = ', LS,LPTSMX
              Stop 'Stopped in LOADSP'
          Endif

C*****    If this is the last record and it is not full, then fill
C*****        with 0's if radiance, or 1's if transmittance
          If(JEMIT .EQ. 0) Then
             FILL = 1.0
          Else
             FILL = 0.0
          Endif
          If((L .EQ. LRDATA) .AND. (LS .LT. LPTSMX)) Then
              Do 190 I=LS+1,LPTSMX
                 SPECT(I) = FILL
  190         Continue
          Endif

C*****    If LREC = 1, break out
          If(LREC .EQ. 1) Go To 300

C*****    If LREC > 1 and this is the first record
          If(L .EQ. 1) Then
              Open(LFILE,access='DIRECT',err=420,recl=IBLKSZ,
     1            status='SCRATCH')
          Endif
          WRITE(LFILE,rec=L) SPECT

C*****    End of write block.  Start new SPECT.
          LS = 0

C*****End of loop over data records
  200 Continue

C*****Add dummy records as needed
      If(LREC .GT. LRDATA) Then
          DO 210 I=1,LPTSMX
              SPECT(I) = FILL
  210     Continue

          Do 220 L=LRDATA+1,LREC
              WRITE(LFILE,rec=L,err=430) SPECT
  220     Continue
      Endif

C*****All done.
  300 Continue
      Return

  420 Continue
      Write(IPR,40) 'LOADSP: error in opening direct access file LFILE',
     1   LFILE
   40 Format(1X,A,I4)
      Stop 'Stopped in LOADSP'

  430 Write(IPR,50) ' LOADSP: error in writing to LFILE, record = ',
     1   LREC
   50 Format(A,I5)
      Stop 'Stopped in LOADSP'

      End

      Subroutine Multrn(LREC,LFILE1,LFILE2,FNCT1,FNCT2) 2
C***********************************************************************
C     This subroutine multiplies two functions FNCT1 and FNCT2 point
C     by point.  If LREC = 1 then the functions are entirely
C     contained in the arrays FNCT1 and FNCT2.  If LREC > 1
C     then the two functions stored on the files on units LFILE1 and
C     LFILE2. The result is stored either in FNCT2 or on file LFILE2.
C     It is assumed that the data is in full blocks of LPTSMX.
C***********************************************************************
C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN
C***********************************************************************
C     LPTSMX is the size of a data block for the FFT.  If the number of
C     data points is LPTSMX or less, the FFT is done in memory.  If it
C     is larger, then a disk based FFT is performed, and LPTSMX is the
C     size in words of each record of the file. The in-memory routine is
C     about 20 percent more efficient than the disk-based routine, for
C     same number of points.  For efficiency, LPTSMX should be made
C     as large a possible so that the computation can be done in memory.
C     However, on virtual memory machines (e.g. VAX), if LPTSMX is too
C     large, then the computation will be done in VIRTUAL memory.  Since
C     the in-memory routine uses widely scattered points, operating
C     system will spend a great deal of time swapping data in and out
C     (thrashing) and the efficiency will be very poor.
C
C     The following problem has been corrected (May, 1993).  The minimum
C     size of an FFT is now the smallest power of 2 greater than the
C     of data points.  LPTSMX should be set to the larges value consistant
C     with real memory.
C
C*    However, LPTSMX is also the minimum size of an FFT (this is a
C*    design flaw of this program).  If LPTSMX is much larger than the
C*    number of points in the spectrum, computational time is wasted.
C*
C*    Therefore, LPTSMX should be set to a value somewhat larger than
C*    the size of the smallest typical spectrum, but no larger than the
C*    largest value possible without thrashing.
C
C     IBLKSZ is the record length in the OPEN statement, and may be
C     in bytes or words,  depending on the operating system.  For VAX
C     and CDC, it is in words.  For MicroSoft FORTRAN, it is in bytes.
C***********************************************************************
      PARAMETER (LSIZE = 65536)
C*****Following line for computers where the blocksize is measured
C*****in words, e.g. VAX, CDC/NOS/VE
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX,LPTSM8=LPTSMX/8)

C*****Following line for computers where the blocksize is measured
C***** in bytes, e.g. MS FORTRAN, SUN, Alliant
      PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*4,LPTSM8=LPTSMX/8)

C*****Following line for computers with 64 bit words where the blocksize is
C*****measured in bytes, e.g. CRAY
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*8,LPTSM8=LPTSMX/8)

      COMPLEX FNCT1(LPTSMX/2),FNCT2(LPTSMX/2)

C*****FNCT1 and FNCT2  are actually arrays of complex numbers of length
C*****LPTSMX/2, stored as arrays of real numbers of length LPTSMX.
C*****Since FNCTn is the FFT of a real array, only the positive
C*****frequencies are stored.  The imaginary part of FNCTn(1) is zero.
C*****For the in-memory routines, the real part of FNCTn(LPTSMX/2+1)
C*****(=V_MAX) is stored there.  Since the first element of FNCTn
C*****actually contains two REAL numbers, complex multiplication
C*****cannot be used.


      If(LREC .EQ. 1) Then
          FNCT2(1) = REAL(FNCT1(1))*REAL(FNCT2(1))+
     1               SQRT(CMPLX(-1.0))*AIMAG(FNCT1(1))*AIMAG(FNCT2(1))
          Do 100 I = 2,LPTSMX/2
              FNCT2(I) = FNCT1(I)*FNCT2(I)
  100     Continue

      Else
          I1 = 2
          Do 300 J = 1,LREC
               Read(LFILE1,rec=J,err=900) FNCT1
               Read(LFILE2,rec=J,err=910) FNCT2

               If(J .EQ. 1) THEN
                   FNCT2(1) = REAL(FNCT1(1))*REAL(FNCT2(1))+
     1                 SQRT(CMPLX(-1.0))*AIMAG(FNCT1(1))*AIMAG(FNCT2(1))
               Endif

               Do 200 I = I1,LPTSMX/2
                  FNCT2(I) = FNCT1(I)*FNCT2(I)
  200          Continue

               Write(LFILE2,rec=J,err=920) FNCT2
               I1 = 1
  300     Continue

       Endif

       Return

  900 Write(IPR,10) 'MULTRN: error in reading file LFILE1 = ',LFILE1
   10 Format(1X,A,I3)
      Stop 'Stopped in MULTRN'

  910 Write(IPR,10) 'MULTRN: error in reading file LFILE2 = ',LFILE2
      Stop 'Stopped in MULTRN'

  920 Write(IPR,20) 'MULTRAN: error in writing file LFILE2 = ',LFILE2
   20 Format(1X,'A',I3)
      Stop 'Stopped in MULTRN'

      End

      Subroutine Scnfnt(JFN,A,IAPSC,X,DX,LPTS,FUNCT,PARM1,PARM2,PARM3) 6,2
C************************************************************************
C     This function calculates the spectral scanning function (IAPSC=1) or
C     the equivalent apodization function (IAPSC=-1) corresponding to JFN,
C     characterized by the parameter A = 1/K, where K is the length of an
C     equivalent interferometer. PARM1, PARM2, and PARM3 are parameters
C     required to define some of the scanning functions.
C
C     The scanning functions and their corresponding apodization
C     functions are listed here. The constants Ci convert the half
C     width at half height to the "natural" measure of the width = a.
C     L = 1/a is typically the extent of the apodization function
C     and corresponds to the maximum path length difference of an
C     interferometer.
C
C     JFN  Scanning function
C      1   triangle= 1 - v/a, v < a,  a = C1*hwhm
C      2   Gaussian = exp(-.5*(v/a)**2), a = C2*hwhm
C      3   Sinc**2 = (sin(u)/u)**2, u = Pi*v/a, a = C3*hwhm
C      4   Sinc = sin(u)/u, u = 2*Pi*v/a, a = C4*hwhm
C      5   Beer = J(5/2,u)/u**(5/2) = ((3-u**2)sin(u)-3*u*cos(u))*u**-5
C          J(n,u) is Bessel fn of order n,augument u = 2*Pi*v/a, a=C5*hwhm
C      6   Hamming =sinc(u)+.428752(sinc(u+Pi)+sinc(u-Pi)),
C                     u = 2*Pi*v/a, a = C6*hwhm
C      7   Hanning = sinc(u)+.5*(sinc(u+Pi)+sinc(u-Pi)),
C                     u = 2*Pi*v/a, a = C7*hwhm
C      8   Norton-Beer: weak
C      9   Norton-Beer: moderate
c     10   Norton-Beer: strong
C     11   Brault
C     12   Kaiser-Bessel
C     13   Kiruna: c1*sinc(u)+c2*sinc(u-2*Pi*v_offset/a), u=2*Pi*v/a, a=1/L
C              This is an asymetric scanning function, the corresponding
C              apodization function is complex.
C
C     JFN  Apodization Function
C      1   Sinc**2 = (sin(z)/z)**2, z = Pi*x*a (a = C1*hwhm)
C      2   Gaussian = exp(-2*Pi*(a*x)**2)
C      3   Triangle, 1 @x=0, 0 @x= 1/a
C      4   Rectangle = 1, x:0 to 1/a; 0, x > 1/a
C      5   Beer = (1-(x*a)**2)**2
C      6   Hamming=(1+.857504*cos(x*a))/1.857504
C      7   Hanning=(1+cos(x*a))/2
C      8   Norton-Beer: weak
C      9   Norton-Beer: moderate
c     10   Norton-Beer: strong
C     11   Brault = 1, 0 < x < p1/a
C                 = (cos(0.5*PI*(x-p1/a)(1/a-p1/a)))**2, p1 <= x < 1/a
C     12   Kaiser-Bessel
C                 = I0(PI*p1*sqrt((1.-(x*a)**2))/I0(Pi*p1), where IO is
C                   zero-order modified Bessel function of the first kind,
C                   and p1 is a parameter (PARM1) from about 2 to 4
c     13   Kiruna: not implemented
C************************************************************************

C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

      Dimension FUNCT(LPTS)
C*****The functions are: triangle, gauss, sinc**2, sinc, Beer, Hamming,
C*****and Hanning.
C*****Function -1 is special.  It is a very broad sinc (only out to about
C*****to the first zero) which is the apodization function corresponding
C*****to a narrow rectangular scanning function used to pre-scan the spectrum.

      PI =2.0*ASIN(1.0)

      X0 = X

      If (JFN .EQ. -1) Go to 200
      Go to (10,20,30,40,50,60,70,80,80,80,90,100,110) JFN

      Write(IPR,*) 'Scnfnt - error: JFN out of range, = ', JFN
      Stop 'Stopped in Scnfnt'

   10 Continue
C*****Triangle
      If(IAPSC .EQ. -1) Then
C*****    Scanning function
          Do 15  L=1,LPTS
              If(X .GT. A) Then
                  FUNCT(L) = 0.0
              Else
                  FUNCT(L) = (1.0-X/A)
              Endif
              X = X0+L*DX
   15     Continue
      Else
C*****    Apodization function
          Do 16 L=1,LPTS-1,2
              If(X .EQ. 0) Then
                  FUNCT(L) = 1.0
              Else
                  FUNCT(L) = (SIN(Pi*X*A)/(Pi*X*A))**2
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
   16     Continue
      Endif
      Return

   20 Continue
C*****Gaussian,
C*****ARGMIN is largest argument x to exp(-x)
      If(IAPSC .EQ. -1) Then
C*****    Scanning function
          Do 25 L=1,LPTS
              FUNCT(L) = exp( -MIN( 0.5*(X/A)**2, ARGMIN))
              X = X0+L*DX
   25     Continue
      Else
C*****    Apodization function
          Do 26 L=1,LPTS-1,2
              FUNCT(L) = exp( -MIN( 2.0*(Pi*X*A)**2, ARGMIN))
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2
   26     Continue
      Endif
      Return

   30 Continue
C*****Sinc**2
      If(IAPSC .EQ. -1) Then
C*****    Scanning function
          Do 35 L=1,LPTS
              If(X .NE. 0) Then
                  FUNCT(L) = (SIN(Pi*X/A)/(Pi*X/A))**2
              Else
                  FUNCT(L) = 1.0
              Endif
              X = X0+L*DX
   35 Continue
      Else
C*****    Apodization function
          Do 36 L=1,LPTS-1,2
              If(X .LT. 1/A) Then
                  FUNCT(L) = 1.0-X*A
              Else
                  FUNCT(L) = 0.0
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2
   36     Continue
      Endif
      Return

   40 Continue
C*****Sinc
      If(IAPSC .EQ. -1) Then
C*****    Scanning function
          Do 45 L=1,LPTS
              If(X .NE. 0) Then
                  FUNCT(L) = SIN(2.0*Pi*X/A)/(2.0*Pi*X/A)
              Else
                  FUNCT(l) = 1.0
              Endif
              X = X0+L*DX
   45     Continue
      Else
C*****    Apodization function
C*****    This function is a rectangle of length L = 1/A.  Because the
C*****    function is defined on a discreet grid, the length cannot be
C*****    exactly L.  To truncate the function at N = FIX(1/A)/DX would
C*****    lead to a discreet set of rectangles.  To avoid this problem,
C*****    the last non-zero point is interpolated between 1 and 0 so that
C*****    the area under the rectangle is preserved. This procedure is at
C*****    best an approximation but at least it provides a continious set
C*****    of functions.
C*****    (By the way, the actual apodization function is the convolution of
C*****    a rectangle of length 1/A with a sinc(2*Pi*x*vmax), where vmax =
C*****    is (V2 - V1), or the frequency range of the scanning calculation.
C*****    The effect of the convolution with the sinc is seen only at the
C*****    step at x = L as ringing.)
          XSTART = X
          ALEN = 1.0/A
          Do 46 L=1,LPTS-1,2
              If(X .LT. ALEN) Then
                  FUNCT(L) = 1.0
              Else
                  FUNCT(L) = 0.0
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
   46     Continue
C*****    If the endpoint is in this block, correct it
C*****    ALEN = DX*(N+R), where 0.5 .LE. R .LT 1.5 and N is an integer
C*****    FUNCT(N+1) = NP-0.5
          N = Int((ALEN-XSTART)/DX)+1
          R = (ALEN-XSTART)/DX+1-N
          If (R .LE. 0.5) Then
              R = R+1.0
              N = N-1
          Endif
          If(N .GE. 1  .AND.  N .LE. LPTS/2-1) Then
              FUNCT(2*N+1) = R-0.5
          Endif
      Endif
      Return

   50 Continue
C*****Beer
      If(IAPSC .EQ. -1) Then
C*****    Scanning function
          Do 55 L=1,LPTS
              U = 2.0*Pi*X/A
              If(U .GE. 0.5) Then
                  FUNCT(L) = 15.*((3.0-U**2)*SIN(U) - 3.0*U*COS(U))
     1                       /(U**5)
              Else
C*****        small angle approximation
                  FUNCT(L) = (1.0-15.0/210*U**2)
              Endif
              X = X0+L*DX
   55     Continue
      Else
C*****    Apodization function
          Do 56 L=1,LPTS-1,2
              If(X .LT. 1/A) Then
                  FUNCT(L) = (1.0 - (X*A)**2)**2
              Else
                  FUNCT(L) = 0.0
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
   56     Continue
      Endif
      Return

   60 Continue
C*****Hamming
      If(IAPSC .EQ. -1) Then
C*****    Scanning function
          Do 65 L=1,LPTS
              U = 2.0*Pi*X/A
              If(U .NE. 0 .AND. ABS(U) .NE. Pi) Then
                  FUNCT(L) = (SIN(U)/U + 0.428752*
     1                       (SIN(U+Pi)/(U+Pi)+SIN(U-Pi)/(U-Pi)))
              Else If (U .EQ. 0) Then
                  FUNCT(L) = 1.0
              Else If (Abs(U) .EQ. Pi) Then
                  FUNCT(L) = 0.428752
              Endif
              X = X0+L*DX
   65     Continue
      Else
C*****    Apodization function
          Do 66 L=1,LPTS-1,2
              If(X .LT. 1/A) Then
                  FUNCT(L) = 0.53835685*(1.0+0.857504*COS(Pi*X*A))
              Else
                  FUNCT(L) = 0.0
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
   66     Continue
      Endif

      Return

   70 Continue
C*****Hanning
      If(IAPSC .EQ. -1) Then
C*****    Scanning function
          Do 75 L=1,LPTS
              U = 2.0*Pi*X/A
              If(U .NE. 0 .AND. ABS(U) .NE. Pi) Then
                  FUNCT(L) = (SIN(U)/U + 0.5*
     1                       (SIN(U+Pi)/(U+Pi)+SIN(U-Pi)/(U-Pi)))
              Else If (U .EQ. 0) Then
                  FUNCT(L) = 1.0
              Else If (ABS(U) .EQ. Pi) Then
                  FUNCT(L) = 0.5
               Endif
              X = X0+L*DX
   75     Continue
      Else
C*****    Apodization function
          Do 76 L=1,LPTS-1,2
              If(X .LT. 1./A) Then
                  FUNCT(L) = 0.5*(1.0+COS(Pi*X*A))
              Else
                  FUNCT(L) = 0.0
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
   76     Continue
      Endif
      Return

  80  Continue
C*****Norton-Beer
C     This is the generalized Norton-Beer function as described in:
C     R. H. Norton and R. Beer "New Apodizing Funcitons for Fourier
C     Spectroscopy", J. Opt. Soc. Am., #66, p259-264 (1976) (Corrected)

      If(IAPSC .EQ. -1) Then
C****     Scanning function
          Write(IPR,*) ' Scnfnt - error: Norton-Beer apodization',
     c        '  not yet implemented in spectral domain'
          Stop ' Stopped in Scnfnt'
          Do 85 l=1,LPTS

              X = X0+L*DX
  85      Continue
      Else
C****     Apodization Function
          Do 89 L=1,LPTS-1,2
              U = 1.0-(X*A)**2
              If(X .LT. 1./A) Then
                  Goto (86,87,88) JFN-7
  86              Continue
C                 Weak Apodization
                  FUNCT(L) = 0.384093-0.087577*U+0.703484*U**2
                  Goto 189

  87              Continue
C                 Medium Apodization
                  FUNCT(L) = 0.152442-0.136176*U+0.983734*U**2
                  Goto 189

  88              Continue
C                 Strong Apodization
                  FUNCT(L) = 0.045355+0.554883*U**2+0.399782*U**4
                  Goto 189
              Else
                  FUNCT(L) = 0.0
              Endif
  189         Continue
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
  89      Continue
      Endif
      Return

  90  Continue
C*****Brault
C*****This function requires the parameter P and is defined by:
C*****    X = 0 to P*L, F = 1
C*****    X = P*L to L, F = ((cos(2*PI*(X-P*L)/(L-P*L))+1)/2)**2
C*****    X > L,        F = 0
C*****The valid range of P is [0,1].  A typical value is 0.9.
C*****Note: a value of P = 0 gives cos**2 apodization.

      If(PARM1 .LT. 0.0 .OR. PARM1 .GE. 1.0) Then
          Write(IPR,*) ' SCNFNT - Error: Brault Apodization, ',
     1        'P = ',PARM1,'  Valid range of P is [0,1)'
          Stop 'Stopped in SCNFNT'
      ENDIF

      If(IAPSC .EQ. -1) Then
C****     Scanning function
          Write(IPR,*) ' SCNFNT - Error: Brault Apodization',
     c        '  not yet implemented in spectral domain'
          Stop ' Stopped in SCNFNT'

          Do 95 l=1,LPTS
C****         Insert code for scanning function here
              X = X0+L*DX
  95      Continue
      Else
C****     Apodization Function
          X1 = PARM1/A
          X2 = 1./A
          Do 99 L=1,LPTS-1,2
              If(X .LT. X1) Then
                  FUNCT(L) = 1.0
              Elseif (X .LT. X2) Then
                  FUNCT(L) = (COS(0.5*PI*(X-X1)/(X2-X1)))**2
              Else
                  FUNCT(L) = 0.0
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
  99      Continue
      Endif
      Return

 100  Continue
C*****Kaiser-Bessel
C*****This function requires the parameter P and is defined by:
C*****    Y = PI*P**Sqrt(1-(x*A)**2)
C*****    F = Bessel(0,y), where Bessel(0,y) is the zero-order
C*****        modified Bessel function of the first kind
C*****The valid range of P is [2,4].

      If(PARM1 .LT. 2.0 .OR. PARM1 .GT. 4.0) Then
          Write(IPR,*) ' SCNFNT - Error: Kaiser-Bessel Apodization, ',
     1        'P = ',PARM1,'  Valid range of P is [2,4]'
          Stop 'Stopped in SCNFNT'
      ENDIF

      If(IAPSC .EQ. -1) Then
C****     Scanning function
          Write(IPR,*) ' Scnfnt - error: Kaiser-Bessel Apodization',
     c        '  not yet implemented in spectral domain'
          Stop ' Stopped in Scnfnt'

          Do 105 l=1,LPTS

              X = X0+L*DX
 105      Continue
      Else
C****     Apodization Function
C****     Expansion for the Bessel function is from 'Numerical Recipies'
C****     Normalization factor: IO(X=0)
          FACTOR = BESSI0(PI*PARM1)
          Do 109 L=1,LPTS-1,2
              IF( X .LE. 1./A) Then
                  Y = PI*PARM1*SQRT(1.0-(X*A)**2)
                  FUNCT(L) = BESSI0(Y)/FACTOR
              Else
                  FUNCT(L) = 0.0
              Endif
              FUNCT(L+1) = 0.0
              X = X0+(L+1)*DX/2.
 109      Continue
      Endif
      Return

  110 Continue
C*****Kiruna (?)
C*****This is an asymetric scanning function consisting of a sinc at 0
C*****and another sinc at v_offset= PARM1. The magnitudes of the two sinc's
C*****are c1 = PARM2 and c2 = PARM3.

      IF(IAPSC .EQ. -1) Then
C*****    Scanning Function
          Do 115 L=1,LPTS
              U1 = 2.0*Pi*X/A
              If (U1 .EQ. 0.0) THEN
                  F1=1.0
              ELSE
                  F1 = SIN(U1)/U1
              ENDIF

              U2 = 2.0*PI*(X-PARM1)/A
              IF (U2 .EQ. 0.0) THEN
                  F2 = 1.0
              ELSE
                  F2 = SIN(U2)/U2
              ENDIF

              FUNCT(L) = PARM2*F1+PARM3*F2
              X = X0+L*DX
  115     Continue

      Else
C*****    Apodization Function
C*****    The apodization function for this scanning function is complex
C*****    and is not implemented here.
          Write(IPR,*) ' SCNFNT - ERROR: Kiruna Function: ',
     1        ' Apodization Function not defined'
              Stop 'Stopped in SCNFNT'

       Endif
       Return

  200 Continue
C*****Rectangle (Boxcar) and Sinc.
C*****This function corresponds to a broad sinc used to deconvolve
C*****the spectrum from the effect of pre-scanning with a boxcar.
C*****The transform of the smoothed, pre-scanned spectrum is divided
C*****by this function which is the transform of the narrow rectangle.
C*****The width of this rectangle is constrained so that at the
C*****value of X at which the apodization function reaches zero
C*****(i.e. X = length of an equivalent interferometer), the
C*****value of the sinc is 0.9.  The inverse of the sinc is returned
C*****since this function will divide the transform of the spectrum.

      Do 206 L=1,LPTS-1,2
          Z = 2.0*Pi*X*A
          If(Z .NE. 0) Then
              FUNCT(L) = Z/SIN(Z)
          Else
              FUNCT(L) = 1.0
          Endif
          FUNCT(L+1) = 0.0
          X = X0+(L+1)*DX/2.
  206 Continue
      If(Z .GT. Pi) Then
          Write(IPR,*) ' Scnfnt - error: Function -1, Z is too large',
     1    ' for this approximation.  Prescanning rectangle is too ',
     2    ' wide?'
          Write(IPR,*) ' Z = ',Z
c          Stop 'Stopped in Scnfnt'
      Endif
      Return

      End


      FUNCTION BESSI0(X) 2
      REAL*8           P1,P2,P3,P4,P5,P6,P7,
     *    Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9
      DATA P1,P2,P3,P4,P5,P6,P7/1.0D0,3.5156229D0,3.0899424D0,
     *    1.2067492D0,0.2659732D0,0.360768D-1,0.45813D-2/
      DATA Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9/0.39894228D0,0.1328592D-1,
     *    0.225319D-2,-0.157565D-2,0.916281D-2,-0.2057706D-1,
     *    0.2635537D-1,-0.1647633D-1,0.392377D-2/
      IF (ABS(X).LT.3.75) THEN
        Y=(X/3.75)**2
        BESSI0=P1+Y*(P2+Y*(P3+Y*(P4+Y*(P5+Y*(P6+Y*P7)))))
      ELSE
        AX=ABS(X)
        Y=3.75/AX
        BESSI0=(EXP(AX)/SQRT(AX))*(Q1+Y*(Q2+Y*(Q3+Y*(Q4
     *      +Y*(Q5+Y*(Q6+Y*(Q7+Y*(Q8+Y*Q9))))))))
      ENDIF
      RETURN
      END

      Subroutine Scntrn(JFN,A,IVX,DV,LREC,LPTFFT,LFILE,FUNCT, 2,7
     1    PARM1,PARM2,PARM3)
C***********************************************************************
C     This subroutine generates the Fourier transform of the spectral
C     scanning function (a.k.a. instrument response function,
C     apparatus function).  By analogy with Fourier transform spectro-
C     spopy, this function will be refered to as the apodization
C     function.  The apodization function can be generated in two ways:
C         a.  by first generating the spectral scanning function, and
C             taking the Fourier transform, or
C         b.  generating the apodization directly.
C     Approach b. is more efficient but there may be cases where a. is
C     preferable.  This subroutine is written to provide for both
C     approaches; the approach used is determined by IVX.
C
C     The parameters are as follows:
C     JFN specifies the shape of the spectral scanning function while
C     the parameter A = 1/K, where K is the length of an equivalent
C     interferometer, and determines the resolution.  A is related to
C     the halfwidth at half maximum by A = C(JFN)*HWHM.  If IVX = 1,
C     then the apodization function is calculated directly, if -1, the
C     scanning function is calculated then transformed. DV is the wavenumber
C     increment of the calculated spectrum, while LREC is the number of
C     records of length LPTSMX in the calculated spectrum. If LREC = 1,
C     then the apodization function is returned in the array spect,
C     otherwise it is written to the direct access file on LFILE in
C     blocks of LPSTMX.  PARM1, PARM2, and PARM3 are parameters used by
C     some of the scanning functions.
C
C     The organization of the arrays needs some explanation.  The scanning
C     function is a real function in the frequency domain, and is symmetric
C     around 0. Let it extend from V = -VMAX+DV to +VMAX in intervals
C     of DV, for a total of N = LREC*LPTSMX points, where VMAX = DV*N/2.
C     Since LPSTMX is a power of 2, N is even.  The positive and negative
C     frequencies of the scanning function are stored in the array FUNCT(I)
C     in the following manner.
C
C      I      V
C
C      1      0
C      2      DV
C      3      2*DV
C      .       .
C      N/2    (N/2-1)*DV
C      N/2+1  (N/2)*DV
C      N/2+2  -(N/2-1)*DV
C      N/2+3  -(N/2-3)*DV
C      .       .
C      N-1    -2*DV
C      N      -DV
C
C     Note that the scanning function is symmetric in V around 0.
C     FUNCT is symmetric around N/2+1 so that FUNCT(N+2-I) = FUNCT(I),
C     I = 2,N/2.  I = 1 corresponds to zero frequency, I=N/2+1 to VMAX.
C
C     The apodization function is the Fourier transform of the scanning
C     function so the it is a complex but Hermitan function in the space
C     domain.  Assume the space domain x extends from -Xmax to +Xmax.
C     The apodization function for negative x is the complex
C     conjugate of the apodization function for positive x.
C     Therefore, only the function for positive x need be stored, and
C     it is stored in a real array APOD(I) with the real parts in the
C     odd I's and the imaginary parts in the even.  APOD(0) is the real
C     value for x =0 and APOD(1) is the REAL value for Xmax (there is
C     no imaginary part for x = 0 or Xmax.)  If there are LPTSMX
C     real points in scanning function, then LPTSMX/2 complex points
C     are stored, so the total storage is the same.  The step size in
C     the space domain dX is 1/Vmax = 1/(LREC*LPTSMX*DV),
C     Xmax = 1/(2*DV).
C
C     The subroutine SCNFNT does the actual calculation of either the
C     scanning function or the apodization function, depending on the
C     value of IVX.
C
C     Note: 5/20/96
C     The capability of handling an asymetric scanning function has been
C     added, either by specifying scanning function 13 or by reading in
C     a scanning function.  The corresponding apodization function is
C     complex but Hermitan (for a symetric scanning function, it is
C     real.) The flag IASYM designates an asymetric scanning function.
C************************************************************************

C***********************************************************************
C     LPTSMX is the size of a data block for the FFT.  If the number of
C     data points is LPTSMX or less, the FFT is done in memory.  If it
C     is larger, then a disk based FFT is performed, and LPTSMX is the
C     size in words of each record of the file. The in-memory routine is
C     about 20 percent more efficient than the disk-based routine, for
C     same number of points.  For efficiency, LPTSMX should be made
C     as large a possible so that the computation can be done in memory.
C     However, on virtual memory machines (e.g. VAX), if LPTSMX is too
C     large, then the computation will be done in VIRTUAL memory.  Since
C     the in-memory routine uses widely scattered points, operating
C     system will spend a great deal of time swapping data in and out
C     (thrashing) and the efficiency will be very poor.
C
C     The following problem has been corrected (May, 1993).  The minimum
C     size of an FFT is now the smallest power of 2 greater than the
C     of data points.  LPTSMX should be set to the larges value consistant
C     with real memory.
C
C*    However, LPTSMX is also the minimum size of an FFT (this is a
C*    design flaw of this program).  If LPTSMX is much larger than the
C*    number of points in the spectrum, computational time is wasted.
C*
C*    Therefore, LPTSMX should be set to a value somewhat larger than
C*    the size of the smallest typical spectrum, but no larger than the
C*    largest value possible without thrashing.
C
C     IBLKSZ is the record length in the OPEN statement, and may be
C     in bytes or words,  depending on the operating system.  For VAX
C     and CDC, it is in words.  For MicroSoft FORTRAN, it is in bytes.
C***********************************************************************
      PARAMETER (LSIZE = 65536)
C*****Following line for computers where the blocksize is measured
C*****in words, e.g. VAX, CDC/NOS/VE
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX,LPTSM8=LPTSMX/8)

C*****Following line for computers where the blocksize is measured
C***** in bytes, e.g. MS FORTRAN, SUN, Alliant
      PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*4,LPTSM8=LPTSMX/8)

C*****Following line for computers with 64 bit words where the blocksize is
C*****measured in bytes, e.g. CRAY
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*8,LPTSM8=LPTSMX/8)

C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

      DIMENSION FUNCT(LPTSMX),FNEXT(1)

C*****IASYM flags asymetric scanning functions(=1)
      DIMENSION IASYM(13)
      DATA IASYM/12*0,1/

C*****Set LPTS equal to the  number of records per block.  For
C*****LREC = 1, this is LPTFFT which may be less than LPTSMX
      If(LREC .EQ. 1) Then
          LPTS = LPTFFT
      Else
          LPTS = LPTSMX
      Endif

      If(LREC .GT.1) Open(LFILE,access='DIRECT',err=900,recl=IBLKSZ,
     1    status='SCRATCH')

      If(IVX .EQ. -1) Then
C*****    Calculate the scanning function, then transform into the
C*****    apodization function.
C*****
C*****    Fill in FUNCT with the scanning function.
C*****    Loop over blocks.  FUNCT is symetric as described above.
C*****    If LREC is odd, then the point of symmetry is at the middle
C*****    of the middle block. If it is even, then the center of symmetry
C*****    is at the end of block LREC/2. If there is a middle block, it
C*****    must be treated separately.

C*****    First loop over full (not middle) blocks, JMAX of them. If JMAX
C*****    is 0 (ie, LREC = 1), skip this section.
          JMAX = LREC/2
          V = 0.0
          Do 120 J = 1,JMAX

              VSAVE = V
              Call Scnfnt(JFN,A,-1,V,DV,LPTS,FUNCT,PARM1,PARM2,PARM3)

C*****        Write positive frequencies.
              IREC = J
              Write(LFILE,rec=IREC,err=910) (FUNCT(I),I=1,LPTS)

C*****        Write negative frequencies.
              IF (IASYM(JFN) .EQ. 0) Then
C*****            FNEXT is next value of FUNCT for positive frequencies
C*****            and is needed for the block with the negative components
                  VV = V
                  Call Scnfnt(JFN,A,-1,VV,DV,1,FNEXT,PARM1,PARM2,PARM3)
                  IREC = LREC+1-J
                  Write(LFILE,rec=IREC,err=910)
     1                 FNEXT(1),(FUNCT(I),I=LPTS,2,-1)
              Else
C*****            Asymetric Scanning function, negative frequncies
C*****            Start at -(VSAVE+DV)
                  VNEG = -(VSAVE+DV)
                  Call Scnfnt(JFN,A,-1,-VNEG,-DV,LPTS,FUNCT,PARM1,
     1                PARM2,PARM3)
                  IREC = LREC+1-J
                  Write(LFILE,rec=IREC,err=910)
     1                (FUNCT(I),I=LPTS,1,-1)

                  V = VV
              Endif
  120     Continue

C*****    Calculate FUNCT for the middle block, if there is one (LREC
C*****    is odd.) Includes LREC = 1.
          If(MOD(LREC,2) .EQ. 1) Then
              VSAVE = V
C*****        Calculate the positive frequencies.
              Call Scnfnt(JFN,A,-1,V,DV,LPTS/2+1,FUNCT,
     1                    PARM1,PARM2,PARM3)

C*****        Fill in the negative frequencies.
              If (IASYM(JFN) .EQ. 0) Then
                  Do 140 I=2,LPTS/2
                      FUNCT(LPTS+2-I) = FUNCT(I)
  140             Continue
                  IREC = JMAX+1
                  If(LREC .GT. 1) Write(LFILE,rec=IREC,err=910)
     1                (FUNCT(I),I=1,LPTS)
              Else
C*****        Need some fancy bookkeeping here. Fill in FUNCT from
C*****        LPTS/2+2 to LPTS, starting at V = -(LPTS/2-1)*DV
                  V1 = -VSAVE-DV*(LPTS/2-1)
                  Call Scnfnt(JFN,A,-1,V1,DV,LPTS/2-1,FUNCT(LPTS/2+2),
     1                        PARM1,PARM2,PARM3)

              Endif
          Endif

C*****    Take the Fourier transform of the scanning function to
C*****    get the apodization function.

          Call Fourtr(LREC,LPTFFT,LFILE,FUNCT,1)

C*****    Must normalize the scanning function to an area of 1.0.
C*****    The first coefficient of the apodization function is the
C*****    area of the scanning function.
          If(LREC .EQ. 1) Then
              FACTOR = FUNCT(1)
              Do 150 L=1,LPTS
                  FUNCT(L) = FUNCT(L)/FACTOR
  150         Continue
          Else
              Do 170 J=1,LREC
                  Read(LFILE,rec=J,err=920) (FUNCT(L),L=1,LPTS)
                  If(J .eq. 1) FACTOR = FUNCT(1)
                  Do 160 L=1,LPTS
                      FUNCT(L) = FUNCT(L)/FACTOR
  160             Continue
                  Write(LFILE,rec=J,err=910) (FUNCT(L),L=1,LPTS)
  170         Continue
          Endif

      Else If (IVX .EQ. 1) Then

C*****    Calculate the apodization function directly
C*****    X is in the space domain, Xmax = 1/dV, dX = 1/Vmax
          X= 0.0

          DX = 1.0/(LPTS*LREC*DV)
C*****    I think this is correct, but maybe it is the following?
C*****    DX = 1.0/((LPTS*LREC-1)*DV)

          Do 200 J=1,LREC
              Call Scnfnt(JFN,A,1,X,DX,LPTS,FUNCT,PARM1,PARM2,PARM3)
              IREC = J
              If(LREC .GT.1) Write(LFILE,rec=IREC,err=910)
     1                            (FUNCT(I),I=1,LPTS)
  200     Continue

      Else
          Write(IPR,*) 'Scntrn - error: IVX .NE. 1 or -1, = ',
     1                  IVX
          Stop 'Stopped in Scntrn'
      Endif
      Return

  900 Continue
      Write(IPR,*) 'Scntrn - error: error opening file: ',LFILE
      Stop 'Stopped in Scntrn'

  910 Continue
      Write(IPR,*) 'Scntrn - error: error writing to file ',LFILE,
     1             ', record number = ',IREC
      Stop 'Stopped in Scntrn'

  920 Continue
      Write(IPR,*) 'Scntrn - error: error reading file ',LFILE,
     1             ', record number = ',IREC
      Stop 'Stopped in Scntrn'


      End

      Subroutine Wrtspc(NV1,NTOTAL,LREC,LFILE,SPECT,JFILE) 1,3
C************************************************************************
C     This subroutine rewrites a spectral file from the direct access
C     format used by fftscn to the sequential LBLRTM format.
C     The input data is on file LFILE, which contains LREC
C     records in blocks of LPTSMX points, or in the array SPECT, if
C     LREC = 1. The output file starts at point NV1 of the input
c     file (corresponding to V1S) and contains a total of NTOTAL
C     points. NTOTAL may be less than LREC*LPTSMX because the
C     limits of the scanned spectrum have been expanded to allow
C     for edge effects and zero fill. If LREC = 1,  then the spectrum
C     is contained entirely in SPECT.  JFILE is the file number to
C     be written to.
C************************************************************************

C*****Computers with 32 bit words need the Double Precision Statements
C*****Computers with 64 bit words (e.g. Cyber) do not.
C*****Frequency variables start with V
      Implicit Real*8           (V)
      Character*8      XID,       HMOLID,      YID
      Real*8               SECANT,       XALTZ

C*****Blank Common carries the spectral data
      COMMON S(2450),R1(2650),XF(251)

C*****SCNHRD carries the header information for the scanned file
      COMMON /SCNHDR/ XID(10),SECANT,PAVE,TAVE,HMOLID(60),XALTZ(4),
     *                WK(60),PZL,PZU,TZL,TZU,WBROAD,DV ,V1C,V2C,TBOUND,
     *                EMISIV,FSCDID(17),NMOL,LAYER ,YI1,YID(10),LSTWDF
      DIMENSION FILHDR(2),IFSDID(17)
      EQUIVALENCE (FILHDR(1),XID(1))
      EQUIVALENCE (FSCDID(1),IFSDID(1),IHIRAC),(FSCDID(2),ILBLF4),
     C (FSCDID(3),IXSCNT),(FSCDID(4 ),IAERSL ),(FSCDID(5),IEMIT),
     C (FSCDID(6),ISCHDR ),(FSCDID(7 ),IPLOT  ),(FSCDID(8),IPATHL),
     C (FSCDID(9),JRAD  ),(FSCDID(10),ITEST  ),(FSCDID(11),IMRG),
     C (FSCDID(12),XSCID),(FSCDID(13),XHWHM  ),(FSCDID(14),IDABS),
     C (FSCDID(15),IATM ),(FSCDID(16),LAYR1  ),(FSCDID(17),NLAYFS),
     C (YID(1)    ,HDATE),(YID(2),      HTIME),(YI1,IMULT)

C*****PANL carries the information from the panel header
      COMMON /PANL/ V1P,V2P,DVP,NP
      DIMENSION PNLHDR(4)
      EQUIVALENCE (PNLHDR(1),V1P)


C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN
C***********************************************************************
C     LPTSMX is the size of a data block for the FFT.  If the number of
C     data points is LPTSMX or less, the FFT is done in memory.  If it
C     is larger, then a disk based FFT is performed, and LPTSMX is the
C     size in words of each record of the file. The in-memory routine is
C     about 20 percent more efficient than the disk-based routine, for
C     same number of points.  For efficiency, LPTSMX should be made
C     as large a possible so that the computation can be done in memory.
C     However, on virtual memory machines (e.g. VAX), if LPTSMX is too
C     large, then the computation will be done in VIRTUAL memory.  Since
C     the in-memory routine uses widely scattered points, operating
C     system will spend a great deal of time swapping data in and out
C     (thrashing) and the efficiency will be very poor.
C
C     The following problem has been corrected (May, 1993).  The minimum
C     size of an FFT is now the smallest power of 2 greater than the
C     of data points.  LPTSMX should be set to the larges value consistant
C     with real memory.
C
C*    However, LPTSMX is also the minimum size of an FFT (this is a
C*    design flaw of this program).  If LPTSMX is much larger than the
C*    number of points in the spectrum, computational time is wasted.
C*
C*    Therefore, LPTSMX should be set to a value somewhat larger than
C*    the size of the smallest typical spectrum, but no larger than the
C*    largest value possible without thrashing.
C
C     IBLKSZ is the record length in the OPEN statement, and may be
C     in bytes or words,  depending on the operating system.  For VAX
C     and CDC, it is in words.  For MicroSoft FORTRAN, it is in bytes.
C***********************************************************************
      PARAMETER (LSIZE = 65536)
C*****Following line for computers where the blocksize is measured
C*****in words, e.g. VAX, CDC/NOS/VE
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX,LPTSM8=LPTSMX/8)

C*****Following line for computers where the blocksize is measured
C***** in bytes, e.g. MS FORTRAN, SUN, Alliant
      PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*4,LPTSM8=LPTSMX/8)

C*****Following line for computers with 64 bit words where the blocksize is
C*****measured in bytes, e.g. CRAY
C     PARAMETER (LPTSMX=LSIZE,IBLKSZ=LPTSMX*8,LPTSM8=LPTSMX/8)

      Dimension SPECT(LPTSMX)
C*****NMAX is the maximum size of an LBLRTM panel
      Data NMAX/2400/

C*****Find the input record containing V1
C*****If LREC > 1, then read to record containing V1
      NREC = NV1/LPTSMX+1
      If(LREC .GT. 1) Then
           Read(LFILE,rec=NREC,err=900) (SPECT(L),L=1,LPTSMX)
      Endif

C*****LLAST was the last point taken from SPECT
C*****LMORE points are available from SPECT
      LLAST = NV1-(NREC-1)*LPTSMX -1
      LMORE = LPTSMX-LLAST
      NREC = NREC+1

C*****NP is the number of points to be written to this output panel S.
C*****NLAST is the last point currently in S
C*****NDONE is the total number of points written already
      NP = MIN(NMAX,NTOTAL)
      NLAST = 0
      NDONE = 0

C*****While more points remain to be written, loop over output panels.
  120 Continue
      If(NDONE .LT. NTOTAL) Then

C*****    NP is the points needed for the next panel.
          NP = MIN(NMAX,NTOTAL-NDONE)

C*****    While S not full, fill it up
  150     Continue
          If(NLAST .LT. NP) Then

C*****        If more points are needed from SPECT, get them.
              If(LMORE .EQ. 0) Then
                  Read(LFILE,rec=NREC,err=900) (SPECT(L),L=1,LPTSMX)
                  LMORE = LPTSMX
                  LLAST = 0
                  NREC = NREC+1
              Endif

C*****        Add available points from SPECT to S until S is full
              NN = MIN(LMORE,NMAX-NLAST)
              N1 = NLAST + 1
              N2 = N1 + NN - 1
              L = LLAST
              DO 200 N=N1,N2
                  L = L+1
                  S(N) = SPECT(L)
  200         Continue
              NLAST = N2
              LLAST = L
              LMORE = LMORE-NN
              Go To 150
          Endif

C*****    Write out a panel
          If(NDONE .EQ. 0) Then
              V1P = V1C
              DVP = DV
          Else
              V1P = V2P+DVP
          Endif

          V2P = V1P+DVP*(NP-1)

          Call Bufout(JFILE,V1P,NPHDRF)
          Call Bufout(JFILE,S(1),NP)

          NDONE = NDONE+NP
          NLAST = 0
          Go to 120
      Endif

      CALL ENDFIL(JFILE)

      Return

  900 Continue
      Write(IPR,*) 'Wrtspc - err: error reading LFILE = ',LFILE
      Stop 'Stopped in Wrtspc'

      End

      Subroutine INTPDR(IFILE,JFILE,VV1,VV2,DVV,IFILST,JEMIT,IERR) 2,6
C**********************************************************************
C     This subroutine is a driver for the subroutine INTERP, which
C     interpolates the spectral data on IFILE onto the wavenumber grid
C     VV1, VV2, and DVV and writes the result to JFILE.
C     JEMIT selects absorption (-1), transmittance (0), or radiance (1)
C     IERR is non-zero if an error occurs
C**********************************************************************

C*****Computers with 32 bit words need the Double Precision Statements
C*****Computers with 64 bit words (e.g. Cyber) do not.
C*****Frequency variables start with V
      Implicit Real*8           (V)
      Character*8      XID,       HMOLID,      YID
      Real*8               SECANT,       XALTZ

C*****Blank Common carries the spectral data
      COMMON S(2450),R1(2650),XF(251)

C*****SCNHRD carries the header information for the scanned file
      COMMON /SCNHDR/ XID(10),SECANT,PAVE,TAVE,HMOLID(60),XALTZ(4),
     *                WK(60),PZL,PZU,TZL,TZU,WBROAD,DV ,V1C,V2C,TBOUND,
     *                EMISIV,FSCDID(17),NMOL,LAYER ,YI1,YID(10),LSTWDF
      DIMENSION FILHDR(2),IFSDID(17)
      EQUIVALENCE (FILHDR(1),XID(1))
      EQUIVALENCE (FSCDID(1),IFSDID(1),IHIRAC),(FSCDID(2),ILBLF4),
     C (FSCDID(3),IXSCNT),(FSCDID(4 ),IAERSL ),(FSCDID(5),IEMIT),
     C (FSCDID(6),ISCHDR ),(FSCDID(7 ),IPLOT  ),(FSCDID(8),IPATHL),
     C (FSCDID(9),JRAD  ),(FSCDID(10),ITEST  ),(FSCDID(11),IMRG),
     C (FSCDID(12),XSCID),(FSCDID(13),XHWHM  ),(FSCDID(14),IDABS),
     C (FSCDID(15),IATM ),(FSCDID(16),LAYR1  ),(FSCDID(17),NLAYFS),
     C (YID(1)    ,HDATE),(YID(2),      HTIME),(YI1,IMULT)

C*****PANL carries the information from the panel header
      COMMON /PANL/ V1P,V2P,DVP,NP
      DIMENSION PNLHDR(4)
      EQUIVALENCE (PNLHDR(1),V1P)


C*****IFIL carries file information
      COMMON /IFIL/ IRD,IPR,IPU,NOPR,NFHDRF,NPHDRF,NFHDRL,NPHDRL,
     *              NLNGTH,KFILE,KPANEL,LINFIL,NFILE,IAFIL,IEXFIL,
     *              NLTEFL,LNFIL4,LNGTH4

C*****LAMCHN carries hardware specific parameters
      COMMON /LAMCHN/ ONEPL,ONEMI,EXPMIN,ARGMIN

C**********************************************************************
C*****THE INPUT DATA WILL BE PUT INTO S(5) = SS(1) WITH THE LAST
C*****4 POINTS OF THE PREVIOUS PANEL PUT INTO S(1 TO 4)
C*****THIS SCHEME PERMITS 6 POINT INTERPOLATION

C*****SS IS NOMINALLY 2401 POINTS BUT MAY NEED TO BE EXTENDED BY
C*****2 POINTS TO PERMIT 4 POINT INTERPOLATION UP TO THE LAST
C*****DATA POINT.

      DIMENSION SS(2406)
      EQUIVALENCE (
C
C     Dimension RSTAT for use in INTERP
C
      DIMENSION RSTAT(3)


      COMMON /SSUBS/ VFT,VBOT,VTOP,V1,V2,DVO,NLIMF,NSHIFT,MAXF,ILO,IHI,   J04110
     *               NLO,NHI,RATIO,SUMIN,IRATSH,SRATIO,IRATM1,NREN,       J04120
     *               DVSC,XDUM,V1SHFT                                     J04130
      COMMON /CONTRL/ IEOFSC,IPANEL,ISTOP,IDATA,JVAR,JABS                 J04170
      COMMON /STIME/ TIME,TIMRDF,TIMCNV,TIMPNL                            J04180
      COMMON /INPNL/ V1I,V2I,DVI,NNI                                      J04190
      COMMON /OUTPNL/ V1J,V2J,DVJ,NNJ                                     J04200

      Logical OP


      IERR = 0
      IBOUND = 4
      NPTS = 0

      Inquire(IFILE,OPENED=OP)
            If (.NOT. OP) Then
          Write(IPR,*) 'INTPDR: error: IFILE not open. IFILE = ',IFILE
          IERR = 1
          Return
      Endif

      Rewind IFILE
      If (IFILST .gt. 1) Then
          Call SKIPFL(IFILST-1,IFILE,IEOF)

          If (IEOF .eq. 0) Then
              Write(IPR,*) ' INTPDR: error: EOF skipping files'
              IERR = 1
          Endif
      Endif

      CALL GETHDR(IFILE,0,JDATA,IEOFSC)

C*****Ensure that the requested interpolation limits VV1 and VV2 are within
C*****the limits of the spectral data.
      If (VV1 .lt. V1C) Then
          AN = (V1C-VV1)/DVV
          If (AN .eq. INT(AN)) Then
              VV1 = V1+DVV*INT(AN)
          Else
              VV1 = V1+DVV*(INT(AN)+1)
          Endif
      Endif

      If (VV2 .gt. V2C) Then
          AN = (VV2-V2C)/DVV
          If (AN .eq. INT(AN))Then
              VV2 = VV2-DVV*INT(AN)
          Else
              VV2 = VV2-DVV*(INT(AN)+1)
          Endif
      Endif

C*****Reset frequency parameters in the file header
      V1C = VV1
      V2C = VV2
      DV = DVV
C*****Set V1 and V2, although I am not sure of all the implications
      V1 = VV1
      V2 = VV2
      DVO = DVV

C*****The following code was lifted from scnint.f.
C*****It sets various parameters in the file header and initializes
C*****the spectral buffer S. Note: the variables have been renamed from
C*****scnint: T -> S, and S -> SS
      ISCAN = ISCHDR
      IF (ISCAN.LE.0.OR.XSCID.EQ.-99.) ISCAN = 0
      IF (ISCHDR.GE.1000.AND.ISCAN.EQ.0) ISCAN = ISCHDR
      ISCHDR = ISCAN+10
C     V1C = V1
C     V2C = V2
C     DV = DVO
C
      SCNID = 100*JEMIT
      XSCID = SCNID+0.01
C
      Call BUFOUT (JFILE,FILHDR(1),NFHDRF)
C
      JTREM = -1
      IF ((IEMIT.EQ.0).AND.(JEMIT.EQ.0)) JTREM = 0
      IF ((IEMIT.EQ.1).AND.(JEMIT.EQ.0)) JTREM = 2
      IF ((IEMIT.EQ.1).AND.(JEMIT.EQ.2)) JTREM = 2
      IF ((IEMIT.EQ.1).AND.(JEMIT.EQ.1)) JTREM = 1
      ISCANT = MOD(ISCAN,1000)
      IF ((ISCANT.GE.1).AND.(JEMIT.EQ.0)) JTREM = 2
      IF (JTREM.LT.0) THEN
         WRITE(IPR,*) ' JTREM.LT.0 AT I07570'
         STOP         ' JTREM.LT.0 AT I07570'
      ENDIF
C     WRITE (IPR,910) IFILE,IEMIT,JEMIT,JTREM,JABS
C
      IDATA = -1
C
C     NEED TO SAVE LAST IBOUND POINTS OF EACH PANEL TO ATTACH TO NEXT
C
      IBOUND = 4
C
C     VBOT IS LOWEST NEEDED WAVENUMBER, VTOP IS HIGHEST
C
      BOUND = FLOAT(IBOUND)*DV

C*****What if VBOT and VTOP are outside the limits of the data???

      VBOT = V1-BOUND
      VTOP = V2+BOUND

C
C     IF (JEMIT.EQ.0.AND.IDABS.EQ.0) BCD = HTRANS
C     IF (JEMIT.EQ.0.AND.IDABS.EQ.-1) BCD = HABSRB
C     IF (JEMIT.EQ.1) BCD = HRADIA
C     IF (NPTS.GT.0) WRITE (IPR,915) BCD
C
C     ZERO OUT T(1 TO IBOUND)
C
      DO 10 II = 1, IBOUND
         S(II) = 0.0
   10 CONTINUE
C
C     READ FROM IFILE UNTIL THE FIRST REQUIRED POINT IS REACHED
C     AND LOAD DATA INTO SS
C
      CALL RDPANL (SS,JTREM,IFILE,ISCAN,JEMIT,ICNVRT)
      IF (IEOFSC.LE.0) GO TO 20
C
C     DO INTERPOLATION
C     SET 4 POINT INTERPOLATION FLAG TO 1
C
      I4PT = 1
      CALL INTERP (IFILE,JFILE,I4PT,IBOUND,NPTS,JTREM,ISCAN,JEMIT,
     *             RSTAT,ICNVRT)
C
      Call ENDFIL(JFILE)

      Return

 20   Continue

      Write(IPR,*) 'INTPDR: error - EOF on input unit ',IFILE,
     1    ' before V1 was reached'
      IERR = 1

      Return

      End

      SUBROUTINE REALFT(DATA,N,ISIGN) 1,2
      REAL*8           WR,WI,WPR,WPI,WTEMP,THETA
      PARAMETER (PI2=6.28318530717959D0)
C*****PARAMETER (PI2=6.283185)
      DIMENSION DATA(*)

      THETA=PI2/(2.0*N)
      C1=0.5
      IF (ISIGN.EQ.1) THEN
          C2=-0.5
          CALL FOUR1(DATA,N,+1)
      ELSE
          C2=0.5
          THETA=-THETA
      ENDIF
      WPR=-2.0*SIN(0.5*THETA)**2
      WPI=SIN(THETA)
      WR=1.0+WPR
      WI=WPI
      N2P3=2*N+3
      DO 11 I=2,N/2+1
          I1=2*I-1
          I2=I1+1
          I3=N2P3-I2
          I4=I3+1
          WRS=WR
          WIS=WI
          H1R=C1*(DATA(I1)+DATA(I3))
          H1I=C1*(DATA(I2)-DATA(I4))
          H2R=-C2*(DATA(I2)+DATA(I4))
          H2I=C2*(DATA(I1)-DATA(I3))
          DATA(I1)=H1R+WRS*H2R-WIS*H2I
          DATA(I2)=H1I+WRS*H2I+WIS*H2R
          DATA(I3)=H1R-WRS*H2R+WIS*H2I
          DATA(I4)=-H1I+WRS*H2I+WIS*H2R
          WTEMP=WR
          WR=WR*WPR-WI*WPI+WR
          WI=WI*WPR+WTEMP*WPI+WI
  11  CONTINUE
      IF (ISIGN.EQ.1) THEN
          H1R=DATA(1)
          DATA(1)=H1R+DATA(2)
          DATA(2)=H1R-DATA(2)
      ELSE
          H1R=DATA(1)
          DATA(1)=C1*(H1R+DATA(2))
          DATA(2)=C1*(H1R-DATA(2))
          CALL FOUR1(DATA,N,-1)
C*****Normalize
          DO 20 I=1,2*N
              DATA(I) = DATA(I)/FLOAT(N)
  20      CONTINUE
      ENDIF
      RETURN
      END

      SUBROUTINE FOUR1(DATA,NN,ISIGN) 2
      REAL*8           WR,WI,WPR,WPI,WTEMP,THETA
      PARAMETER (PI2=6.28318530717959D0)
C*****PARAMETER (PI2=6.2831853)
      DIMENSION DATA(*)

      N=2*NN
      J=1
      DO 11 I=1,N,2
          IF(J.GT.I)THEN
              TEMPR=DATA(J)
              TEMPI=DATA(J+1)
              DATA(J)=DATA(I)
              DATA(J+1)=DATA(I+1)
              DATA(I)=TEMPR
              DATA(I+1)=TEMPI
          ENDIF
          M=N/2
  1       IF ((M.GE.2).AND.(J.GT.M)) THEN
              J=J-M
              M=M/2
              GO TO 1
          ENDIF
          J=J+M
  11  CONTINUE
      MMAX=2
  2   IF (N.GT.MMAX) THEN
          ISTEP=2*MMAX
          THETA=PI2/(ISIGN*MMAX)
          WPR=-2.*SIN(0.5*THETA)**2
          WPI=SIN(THETA)
          WR=1.
          WI=0.
          DO 13 M=1,MMAX,2
              DO 12 I=M,N,ISTEP
                  J=I+MMAX
                  TEMPR=(WR)*DATA(J)-(WI)*DATA(J+1)
                  TEMPI=(WR)*DATA(J+1)+(WI)*DATA(J)
                  DATA(J)=DATA(I)-TEMPR
                  DATA(J+1)=DATA(I+1)-TEMPI
                  DATA(I)=DATA(I)+TEMPR
                  DATA(I+1)=DATA(I+1)+TEMPI
  12          CONTINUE
              WTEMP=WR
              WR=WR*WPR-WI*WPI+WR
              WI=WI*WPR+WTEMP*WPI+WI
  13      CONTINUE
          MMAX=ISTEP
          GO TO 2
      ENDIF
      RETURN
      END

      SUBROUTINE REALBG(LFILE,ISIGN,NBLK,IBLKSZ,A,B,S,IWORK) 1,5
C***********************************************************************
C     Calculates the FFT of real data.  Also does the inverse transform.
C     The algorithm this routine uses is the same as program REALFT in
C     the book Numerical Recipes The Art of Scientific Computing except
C     that it uses disk swapping.  Some of the actual code from REALFT
C     is used.  Like the Numerical Recipes routine
C     the last point is in data(2).  Unlike REALFT the inverse routine
C     takes care of normalizing by dividing by 1/N.
C     S and IWORK are not used in this routine they are just passed
C     through to BIGFFT.
C     Note of interest: Subroutine REALFT in my Numerical Recipes book i
C     not quite the same as it is on my Numerical Recipes disk.
C
C     Mark P. Esplin
C     Stewart Radiance Lab.
C     139 The Great Rd.
C     Bedford Ma, 01730
C***********************************************************************
      Real*8           WR,WI,WPR,WPI,THETA
      DIMENSION A(*),B(*),S(*),IWORK(*)
      THETA=6.28318530717959D0/(NBLK*IBLKSZ)
      C1=0.5
      IF (ISIGN.EQ.1) THEN
          C2=-0.5
          CALL BIGFFT(LFILE,1,NBLK,IBLKSZ,A,B,S,IWORK)
      ELSE
          C2=0.5
          THETA=-THETA
      ENDIF
      IALK=1
      READ(LFILE,REC=IALK) (C     First point is a special case.
      IF (ISIGN.EQ.1) THEN
          H1R=A(1)
          A(1)=H1R+A(2)
          A(2)=H1R-A(2)
      ELSE
          H1R=A(1)
          A(1)=C1*(H1R+A(2))
          A(2)=C1*(H1R-A(2))
      ENDIF
C     Set complex coefficients
      WPR=-2.0D0*SIN(0.5D0*THETA)**2
      WPI=SIN(THETA)
      WR=1.0D0+WPR
      WI=WPI
C     Do the actual work now.
      LSTBLK=NBLK/2+1
      DO 20 IBLK=NBLK,LSTBLK,-1
          READ(LFILE,REC=IBLK) (          DO 10 IA=3,IBLKSZ,2
              IB=IBLKSZ-IA+2
              CALL PROSPN(  10      CONTINUE
          WRITE(LFILE,REC=IALK) (C     The last(first) point in each block is different
          IF(IBLK.EQ.LSTBLK) THEN
              CALL PROSPN(          ELSE
C     Finish block B with the first data from next block A.
              IALK=IALK+1
              READ(LFILE,REC=IALK) (              CALL PROSPN(          ENDIF
          WRITE(LFILE,REC=IBLK) (  20  CONTINUE
      IF(ISIGN.EQ.-1) THEN
          CALL BIGFFT(LFILE,-1,NBLK,IBLKSZ,A,B,S,IWORK)
      ENDIF
      RETURN
      END
C
C

      SUBROUTINE BIGFFT(LFILE,ISIGN,NBLK,IBLKSZ,A,B,S,IWORK) 2,4
C***********************************************************************
C     This routine preforms an in-place disk swapping complex FFT
C     on the data stored in a random access file on unit 4.
C     ISIGN = 1 for forward transform and ISIGN = -1 for inverse.
C     The data is stored in NBLK blocks of size IBLKSZ.
C     The data is stored such that the imaginary part of each complex
C     data point is followed by the real part.
C     The number of blocks of storage used on unit 4 = NBLK + NBLK/8.
C     The extra NBLK/8 blocks is used to store cosine sine tables.
C     A, B, S, and IWORK are work areas of size IBLKSZ.  S and IWORK
C     are not used at the same time, so they can share the same memory s
C     with an equivalence statement.
C
C     Mark P. Esplin
C     Stewart Radiance Lab.
C     139 The Great Rd.
C     Bedford Ma, 01730
C***********************************************************************
C
      DIMENSION A(*),B(*),S(*),IWORK(*)
      CALL SORTFF(LFILE,A,B,NBLK,IBLKSZ)
      CALL FFTBLK(LFILE,A,B,IWORK,ISIGN,NBLK,IBLKSZ)
C     Set sine-cosine table.
      CALL SCTABL(S,IBLKSZ)
      WRITE(LFILE,REC=NBLK+1) (      CALL RECONS(LFILE,A,B,S,ISIGN,NBLK,IBLKSZ)
C     Renormalize inverse transform
      IF(ISIGN.EQ.-1) THEN
          DO 20 IBLK=1,NBLK
              READ(LFILE,REC=IBLK) (              DO 10 I=1,IBLKSZ
                  A(I)=A(I)/NBLK
  10          CONTINUE
              WRITE(LFILE,REC=IBLK) (  20      CONTINUE
      ENDIF
      RETURN
      END
C
C
C
C
C


      SUBROUTINE PROSPN(A,B,WR,WI,WPR,WPI,C1,C2) 3
C     This routine processes a pair of complex points
C     and calculates the next complex coefficient.
      DIMENSION A(2),B(2)
      Real*8           WR,WI,WPR,WPI,WTEMP
      H1R=C1*(      H1I=C1*(      H2R=-C2*(      H2I=C2*(      WRS=WR
      WIS=WI
      A(1)=H1R+WRS*H2R-WIS*H2I
      A(2)=H1I+WRS*H2I+WIS*H2R
      B(1)=H1R-WRS*H2R+WIS*H2I
      B(2)=-H1I+WRS*H2I+WIS*H2R
      WTEMP=WR
      WR=WR*WPR-WI*WPI+WR
      WI=WI*WPR+WTEMP*WPI+WI
      RETURN
      END
C
C
C
C

      SUBROUTINE SORTFF(LFILE,A,B,NBLK,IBLKSZ) 1,2
      COMPLEX A(1),B(1),H
C     THIS SUBROUTINE SORTS DATA TO GET READY FOR AN FFT
C     EVERY NBLK'TH POINT IS SORTED OUT INTO A SEPARATE FILE THEN
C     THE FILES ARE PUT IN BIT INVERTED ORDER
C     NOTE MEMORY REQUIRED FOR A COMPLEX ARRAY IS TWICE THAT OF A REAL
C     ARRAY.
C     INPUT IS IN THE FIRST NBLK BLOCKS OF TAPE4 A RANDOM ACCESS FILE
C     WITH A TOTAL NUMBER OF BLOCKS = NBLK+NBLK/8+1
C     THE DATA IS ALWAYS REWRITTEN IN PLACE
C     IBLKSZ = NUMBER OF STORAGE LOCATIONS IN A BLOCK
C     ICOMSZ = IBLKSZ/2 = NUMBER OF COMPLEX POINTS
C     NBLK = NUMBER OF BLOCKS
C     ICSUBZ = SIZE OF SUB-BLOCKS (COMPLEX) WHICH IS ICOMSZ/NBLK AT STAR
C     NPASS = NUMBER OF PASSES OVER THE DATA
C     THIS SECTION OF CODE SORTS OUT EVER NBLK'TH POINT IN A BLOCK AND
C     AND PUTS THE SUB-BLOCKS IN BIT INVERTED ORDER
      ICOMSZ=IBLKSZ/2
      ICSUBZ=ICOMSZ/NBLK
      NPASS=LLOG2(NBLK)
      DO 20 IBLK=1,NBLK
          READ(LFILE,REC=IBLK) (          DO 10 ISUB=1,NBLK
              IP=ISUB-NBLK
              IB=INVER((ISUB-1),NPASS)*ICSUBZ
              DO 10 I=1,ICSUBZ
                  IP=NBLK+IP
  10          B(IB+I)=A(IP)
  20      WRITE(LFILE,REC=IBLK) (C     THIS SECTION OF CODE SORTS THE BLOCKS
C     NSUB = NUMBER OF SUB-BLOCKS
C     NBB = NUMBER OF BLOCKS IN EACH BUTTERFLY
C     NBUTTE = NUMBER OF BUTTERFLIES
C     IBU = WHICH BLOCK IN BUTTERFLY
C     IBUTT = WHICH BUTTERFLY
C     IBA = BLOCK A
C     IBB = BLOCK B
      NSUB=NBLK
      NBB=1
      DO 50 IPAS=1,NPASS
          NBUTTE=NSUB/2
          NBB2=NBB*2
          ICSUB2=ICSUBZ*2
          DO 40 IBU=1,NBB
              IBA=IBU-NBB2
              DO 40 IBUTT=1,NBUTTE
                  IBA=IBA+NBB2
                  IBB=IBA+NBB
C     OPERATE ON BLOCK A AND BLOCK B
                  READ(LFILE,REC=IBA) (                  READ(LFILE,REC=IBB) (                  J=-ICSUB2
                  DO 30 ISUB=1,NSUB,2
                      J=J+ICSUB2
                      JI=J
                      DO 30 I=1,ICSUBZ
                          JI=JI+1
                          JI2=JI+ICSUBZ
                          H=A(JI2)
                          A(JI2)=B(JI)
  30              B(JI)=H
                  WRITE(LFILE,REC=IBA) (  40      WRITE(LFILE,REC=IBB) (          NBB=NBB2
          ICSUBZ=ICSUB2
  50  NSUB=NSUB/2
      RETURN
      END
C
C
C


      FUNCTION INVER(IVER,N) 1
C     THIS FUNCTION TAKES "IVER" AND INVERTS THE BITS
C     N IS THE NUMBER OF BITS IN THE WORD
C     THE VALUES OF IVER AND N ARE UNCHANGED
C     THIS FUNCTION WILL NOT WORK FOR NEGATIVE NUMBERS
C     This version uses standard FORTRAN 77.  It would be easier to
C     use a SHIFT and OR function, but they are not standard FORTRAN 77.
      IVE=IVER
      INV=0
      DO 10 I=1,N
          INV=2*INV+MOD(IVE,2)
          IVE=IVE/2
  10  CONTINUE
      INVER=INV
      RETURN
      END
C
C

      FUNCTION LLOG2(N) 3
C     FINDS INTEGER LOG TO BASE TWO
      LLOG2=ALOG(FLOAT(N))/.69314718+.5
      RETURN
      END
C
C
C

      SUBROUTINE FFTBLK(LFILE,A,S,INV,ISIGN,NBLK,IBLKSZ) 1,3
C     THIS ROUTINE DOES AN FFT OF EACH BLOCK WITH THE USE OF HARM1D
      DIMENSION A(*),S(*),INV(*)
      M=LLOG2(IBLKSZ)-1
C     SET UP SIN AND INV TABLES
      CALL HARM1D(A,M,INV,S,0,IFERR)
      IS=2*ISIGN
      DO 10 I=1,NBLK
          READ(LFILE,REC=I) (          CALL HARM1D(A,M,INV,S,IS,IERR)
          WRITE(LFILE,REC=I) (  10  CONTINUE
      RETURN
      END
C
C
C
C
C

      SUBROUTINE SCTABL(S,IBLKSZ) 1
      DIMENSION S(*)
C     THIS ROUTINE GENERATES A SIN-COS TABLE
C     FROM THETA EQUAL ZERO TO 180 DEGREES
      IBLKS2=IBLKSZ/2
      IBLKS4=IBLKSZ/4
      DELT=4*ATAN(1.)/IBLKS2
      ROOT2=1./SQRT(2.)
      IAD2=IBLKS2+3
      IAD3=IBLKSZ+3
      S(1)=1.
      S(2)=0.
      S(IBLKS2+1)=0.
      S(IBLKS2+2)=1.
      DO 10 I=3,IBLKS4,2
          THA=DELT*(I/2)
          I2=I+1
          COST=COS(THA)
          SINT=SIN(THA)
          S(I)=COST
          S(I2)=SINT
          S(IAD2-I2)=SINT
          S(IAD2-I)=COST
          S(I+IBLKS2)=-SINT
          S(I2+IBLKS2)=COST
          S(IAD3-I2)=-COST
          S(IAD3-I)=SINT
  10  CONTINUE
      S(IBLKS4+1)=ROOT2
      S(IBLKS4+2)=ROOT2
      IBLKS34=IBLKS2+IBLKS4
      S(IBLKS34+1)=-ROOT2
      S(IBLKS34+2)=ROOT2
      RETURN
      END
C
C
C
C
C

      SUBROUTINE RECONS(LFILE,A,B,S,ISIGN,NBLK,IBLKSZ) 1,9
      COMPLEX A(*),B(*),S(*)
C     THIS ROUTINE RECONSTRUCTS THE BLOCKS THAT HAVE ALREADY BEEN TRANSF
C     SEE SUBROUTINE SORTFF FOR DEFINITIONS OF TERMS
C     INPUT IS IN THE FIRST "NBLK" BLOCKS IN TAPE4
C     BLOCK NBLK+1 MUST CONTAIN A COS-SIN TABLE
C     NSIN= NUMBER OF TIMES THE SIGN TABLE NEEDS TO BE READ
C     NBLSIN= NUMBER OF BLOCKS IN THE COS-SIN TABLE WHEN IT GETS FILLED
C     ISIN= WHICH SIN BLOCK TO READ
C     ISRE= ISIN-NBLK
      ICOMSZ=IBLKSZ/2
      NPASS=LLOG2(NBLK)
      DELTHA=4.*ATAN(1.)/ICOMSZ
      DELT=DELTHA
      NBB=1
      NBUTTE=NBLK/2
      NBLSIN=NBLK/8
      IF(NBLSIN.LE.0) NBLSIN=1
      DO 50 IPASS=1,NPASS
C     TAKE CARE OF COS-SIN TABLE
          NSIN=NBB/4
          IF(NSIN.LE.0) NSIN=1
          NOFSIN=NBLSIN/NSIN
          NOFSI2=NOFSIN/2
          ISIN=NBLK+1-NOFSIN
          DO 40 ISRE=1,NSIN
              ISIN=ISIN+NOFSIN
              READ(LFILE,REC=ISIN) (              IF(IPASS.EQ.NPASS) GO TO 10
C     GET TABLE FOR NEXT PASS
              DELTHA=DELTHA/2
              CALL EXPAN(A,B,S,DELTHA,IBLKSZ)
              WRITE(LFILE,REC=ISIN) (C     FOR THE FIRST TWO PASSES YOU CAN PUT ALL THE INFORMATION IN THE
C     COS-SIN TABLE IN ONE BLOCK
              IF(IPASS.LE.2) GO TO 10
              ISIN2=ISIN+NOFSI2
              WRITE(LFILE,REC=ISIN2) (C     DETERMINE WHICH BLOCKS TO WORK ON
C     THIS SHUFFLE IS TO MAKE IT SO ONLY ONE COS-SIN TABLE BLOCK IS
C     NEEDED TO WORK ON 8 DATA BLOCKS
  10         NBB2=NBB/2
             IBU=ISRE
             CALL HERFFT(LFILE,A,B,S,ISIGN,IBLKSZ,ICOMSZ,IBU,NBB,NBUTTE)
             IF(IPASS.LE.1) GO TO 40
             CALL ADDNIN(S,IBLKSZ)
             IBU=IBU+NBB2
             CALL HERFFT(LFILE,A,B,S,ISIGN,IBLKSZ,ICOMSZ,IBU,NBB,NBUTTE)
             IF(IPASS.LE.2) GO TO 40
             CALL COMPNIN(S,IBLKSZ,DELT)
             IBU=NBB2-ISRE+1
             CALL HERFFT(LFILE,A,B,S,ISIGN,IBLKSZ,ICOMSZ,IBU,NBB,NBUTTE)
             CALL ADDNIN(S,IBLKSZ)
             IBU=NBB-ISRE+1
             CALL HERFFT(LFILE,A,B,S,ISIGN,IBLKSZ,ICOMSZ,IBU,NBB,NBUTTE)
  40      CONTINUE
          NBB=NBB*2
          DELT=DELT/2
  50  NBUTTE=NBUTTE/2
      RETURN
      END
C

      SUBROUTINE HERFFT(LFILE,A,B,S,ISIGN,IBLKSZ,ICOMSZ,IBU,NBB, 4
     1    NBUTTE)
C     THIS IS THE HEART OF THE EXTENDED FFT
C     SEE SORTFF FOR DEFINITION OF TERMS
      COMPLEX A(*),B(*),S(*),H,T
      NBB2=NBB*2
      IBA=IBU-NBB2
      DO 40 IBUTT=1,NBUTTE
          IBA=IBA+NBB2
          IBB=IBA+NBB
C     THIS SECTION OF CODE OPERATES ON TWO BLOCKS
          READ(LFILE,REC=IBA) (          READ(LFILE,REC=IBB) (          IF(ISIGN.EQ.1) THEN
C     The inverse was put on after the fact.
              DO 30 I=1,ICOMSZ
                  H=A(I)
                  T=B(I)*S(I)
                  A(I)=H+T
  30          B(I)=H-T
          ELSE
              DO 35 I=1,ICOMSZ
                  H=A(I)
                  T=B(I)*CONJG(                  A(I)=H+T
  35          B(I)=H-T
          ENDIF
          WRITE(LFILE,REC=IBA) (          WRITE(LFILE,REC=IBB) (  40  CONTINUE
      RETURN
      END
C

      SUBROUTINE EXPAN(A,B,S,DELTHA,IBLKSZ) 1
      DIMENSION A(*),B(*),S(*)
C     THIS ROUTINE EXPANDS THE SIN-COS TABLE BY TWO.
C     THE EXPANDED TABLE GOES INTO A AND B FROM THE ORIGINAL IN S
      COSD=COS(DELTHA)
      SIND=SIN(DELTHA)
C     DO FIRST HALF
      J=-1
      DO 10 I=1,IBLKSZ,4
          J=J+2
          J2=J+1
          COSJ=S(J)
          SINJ=S(J2)
          A(I)=COSJ
          A(I+1)=SINJ
          A(I+2)=COSJ*COSD-SINJ*SIND
          A(I+3)=COSJ*SIND+SINJ*COSD
  10  CONTINUE
C     DO SECOND PART
      DO 20 I=1,IBLKSZ,4
          J=J+2
          J2=J+1
          COSJ=S(J)
          SINJ=S(J2)
          B(I)=COSJ
          B(I+1)=SINJ
          B(I+2)=COSJ*COSD-SINJ*SIND
  20  B(I+3)=COSJ*SIND+SINJ*COSD
      RETURN
      END
C

      SUBROUTINE ADDNIN(S,IBLKSZ) 2
      DIMENSION S(*)
C     THIS ROUTINE ADDS 90 TO THE ANGLE IN THE COS-SIN BLOCK
      DO 10 I=1,IBLKSZ,2
          I2=I+1
          T=S(I)
          S(I)=-S(I2)
  10  S(I2)=T
      RETURN
      END
C

      SUBROUTINE COMPNIN(S,IBLKSZ,DELTHA) 1
      DIMENSION S(*)
C     THIS ROUTINE SUBTRACTS 90 FROM THE ANGLE THEN TAKES THE COS-SIN TA
C     FROM THA TO 90 MINUS THA.
      IBSZ2=IBLKSZ/2
      IEND=IBSZ2+1
      J2=IBLKSZ
      DO 10 I=3,IBSZ2,2
          I2=I+1
          J=J2-1
          T=S(I)
          S(I)=-S(J)
          S(J)=-T
          T=S(I2)
          S(I2)=S(J2)
          S(J2)=T
  10  J2=J2-2
      S(IEND)=-S(IEND)
C     FIND COS-SIN FOR THE FIRST POINT (THE ONE NOT IN OLD BLOCK)
      COSD=COS(DELTHA)
      SIND=SIN(DELTHA)
      S(1)=S(3)*COSD+S(4)*SIND
      S(2)=S(4)*COSD-S(3)*SIND
      RETURN
      END


      SUBROUTINE HARM1D(A,M,INV,S,IFSET, IFERR) 2
C
C     ..................................................................
C
C     SUBROUTINE HARM1D
C
C     PURPOSE
C     PERFORMS DISCRETE COMPLEX FOURIER TRANSFORMS ON A COMPLEX
C     THREE DIMENSIONAL ARRAY
C
C     USAGE
C     CALL HARM1D(A,M,INV,S,IFSET,IFERR)
C
C     DESCRIPTION OF PARAMETERS
C     A     - AS INPUT, A CONTAINS THE COMPLEX, 1-DIMENSIONAL
C     ARRAY TO BE TRANSFORMED.  THE REAL PART OF
C     A(I1) IS STORED IN VECTOR FASHION IN A CELL
C     WITH INDEX 2*(I1) + 1 WHERE
C     NI = 2**MI AND I1 = 0,1,...,N1-1 ETC.
C     THE IMAGINARY PART IS IN THE CELL IMMEDIATELY
C     FOLLOWING.
C     THE NUMBER OF CORE LOCATIONS OF
C     ARRAY A IS 2*(N1)
C     M     - A ONE CELL VECTOR WHICH DETERMINES THE SIZES
C     OF THE DIMENSIONS OF THE ARRAY A.   THE SIZE,
C     NI, OF THE DIMENSION OF A IS 2**MI
C     INV   - A VECTOR WORK AREA FOR BIT AND INDEX MANIPULATION
C     OF DIMENSION ONE EIGHTH THE NUMBER OF CORE
C     LOCATIONS OF A, VIZ., (1/8)*2*N1
C     S     - A VECTOR WORK AREA FOR SINE TABLES WITH DIMENSION
C     THE SAME AS INV
C     IFSET - AN OPTION PARAMETER WITH THE FOLLOWING SETTINGS
C     0    SET UP SINE AND INV TABLES ONLY
C     1    SET UP SINE AND INV TABLES ONLY AND
C     CALCULATE FOURIER TRANSFORM
C     -1    SET UP SINE AND INV TABLES ONLY AND
C     CALCULATE INVERSE FOURIER TRANSFORM (FOR
C     THE MEANING OF INVERSE SEE THE EQUATIONS
C     UNDER METHOD BELOW)
C     2    CALCULATE FOURIER TRANSFORM ONLY (ASSUME
C     SINE AND INV TABLES EXIST)
C     -2    CALCULATE INVERSE FOURIER TRANSFORM ONLY
C     (ASSUME SINE AND INV TABLES EXIST)
C     IFERR - ERROR INDICATOR.   WHEN IFSET IS 0,+1,-1,
C     IFERR = 1 MEANS THE MAXIMUM M(I) IS LESS THAN 3
C     OR GREATER THAN 20, I=1,2,3  WHEN IFSET IS
C     +2,-2, IFERR = 1 MEANS THAT THE SINE AND INV
C     TABLES ARE NOT LARGE ENOUGH OR HAVE NOT BEEN
C     COMPUTED.  IF ON RETURN IFERR =0 THEN NONE OF
C     THE ABOVE CONDITIONS ARE PRESENT
C
C     REMARKS
C     THIS SUBROUTINE IS TO BE USED FOR COMPLEX, 1-DIMENSIONAL
C     ARRAYS IN WHICH EACH DIMENSION IS A POWER OF 2.  THE
C     MAXIMUM MI MUST NOT BE LESS THAN 3 OR GREATER THAN 20.
C
C     SUBROUTINES AND FUNCTION SUBPROGRAMS REQUIRED
C     NONE
C
C     THIS IS A 1-DIMENSIONAL MODIFICATION OF THE ORIGINAL
C     3-DIMENSIONAL PROGRAM MODIFIED BY MARK P. ESPLIN.
C
C
C     SEE J.W. COOLEY AND J.W. TUKEY, "AN ALGORITHM FOR THE
C     MACHINE CALCULATION OF COMPLEX FOURIER SERIES",
C     MATHEMATICS OF COMPUTATIONS, VOL. 19 (APR. 1965), P. 297.
C
C     ..................................................................
C
C     The following SAVE statement needed on some machines,
C     specificlly Silicon Graphics.
      SAVE NT,NTV2, MT
      DIMENSION A(1),INV(1),S(1),W(2),W2(2),W3(2)
  10  IF( IABS(IFSET) - 1) 900,900,12
  12  MTT=M-2
      ROOT2 = SQRT(2.)
      IF (MTT-MT ) 14,14,13
  13  IFERR=1
      RETURN
  14  IFERR=0
      M1=M
      N1=2**M1
  16  IF(IFSET) 18,18,20
  18  NX= N1
      FN = NX
      DO 19 I = 1,NX
          A(2*I-1) = A(2*I-1)/FN
  19  A(2*I) = -A(2*I)/FN
  20  NP=N1*2
      IL=0
      IL1=1
      MI=M1
  30  IDIF=NP
      KBIT=NP
      MEV = 2*(MI/2)
      IF (MI - MEV )60,60,40
C
C     M IS ODD. DO L=1 CASE
  40  KBIT=KBIT/2
      KLAST=KBIT-1
      DO 50 K=1,KLAST,2
          KD=K+KBIT
C
C     DO ONE STEP WITH L=1,J=0
C     A(K)=A(K)+A(KD)
C     A(KD)=A(K)-A(KD)
C
          T=A(KD)
          A(KD)=A(K)-T
          A(K)=A(K)+T
          T=A(KD+1)
          A(KD+1)=A(K+1)-T
  50  A(K+1)=A(K+1)+T
  52  LFIRST =3
C
C     DEF - JLAST = 2**(L-2) -1
      JLAST=1
      GO TO 70
C
C     M IS EVEN
  60  LFIRST = 2
      JLAST=0
  70  DO 240 L=LFIRST,MI,2
          JJDIF=KBIT
          KBIT=KBIT/4
          KL=KBIT-2
C
C     DO FOR J=0
          DO 80 I=1,IL1,IDIF
              KLAST=I+KL
              DO 80 K=I,KLAST,2
                  K1=K+KBIT
                  K2=K1+KBIT
                  K3=K2+KBIT
C
                  T=A(K2)
                  A(K2)=A(K)-T
                  A(K)=A(K)+T
                  T=A(K2+1)
                  A(K2+1)=A(K+1)-T
                  A(K+1)=A(K+1)+T
C
                  T=A(K3)
                  A(K3)=A(K1)-T
                  A(K1)=A(K1)+T
                  T=A(K3+1)
                  A(K3+1)=A(K1+1)-T
                  A(K1+1)=A(K1+1)+T
C
                  T=A(K1)
                  A(K1)=A(K)-T
                  A(K)=A(K)+T
                  T=A(K1+1)
                  A(K1+1)=A(K+1)-T
                  A(K+1)=A(K+1)+T
C
                  R=-A(K3+1)
                  T = A(K3)
                  A(K3)=A(K2)-R
                  A(K2)=A(K2)+R
                  A(K3+1)=A(K2+1)-T
  80      A(K2+1)=A(K2+1)+T
          IF (JLAST) 235,235,82
  82      JJ=JJDIF   +1
C
          ILAST= IL +JJ
          DO 85 I = JJ,ILAST,IDIF
              KLAST = KL+I
              DO 85 K=I,KLAST,2
                  K1 = K+KBIT
                  K2 = K1+KBIT
                  K3 = K2+KBIT
C
                  R =-A(K2+1)
                  T = A(K2)
                  A(K2) = A(K)-R
                  A(K) = A(K)+R
                  A(K2+1)=A(K+1)-T
                  A(K+1)=A(K+1)+T
C
                  AWR=A(K1)-A(K1+1)
                  AWI = A(K1+1)+A(K1)
                  R=-A(K3)-A(K3+1)
                  T=A(K3)-A(K3+1)
                  A(K3)=(AWR-R)/ROOT2
                  A(K3+1)=(AWI-T)/ROOT2
                  A(K1)=(AWR+R)/ROOT2
                  A(K1+1)=(AWI+T)/ROOT2
                  T= A(K1)
                  A(K1)=A(K)-T
                  A(K)=A(K)+T
                  T=A(K1+1)
                  A(K1+1)=A(K+1)-T
                  A(K+1)=A(K+1)+T
                  R=-A(K3+1)
                  T=A(K3)
                  A(K3)=A(K2)-R
                  A(K2)=A(K2)+R
                  A(K3+1)=A(K2+1)-T
  85          A(K2+1)=A(K2+1)+T
              IF(JLAST-1) 235,235,90
  90          JJ= JJ + JJDIF
C
C     NOW DO THE REMAINING J"S
              DO 230 J=2,JLAST
C
C     FETCH W"S
C     DEF- W=W**INV(J), W2=W**2, W3=W**3
  96              I=INV(J+1)
  98              IC=NT-I
                  W(1)=S(IC)
                  W(2)=S(I)
                  I2=2*I
                  I2C=NT-I2
                  IF(I2C)120,110,100
C
C     2*I IS IN FIRST QUADRANT
  100             W2(1)=S(I2C)
                  W2(2)=S(I2)
                  GO TO 130
  110             W2(1)=0.
                  W2(2)=1.
                  GO TO 130
C
C     2*I IS IN SECOND QUADRANT
  120             I2CC = I2C+NT
                  I2C=-I2C
                  W2(1)=-S(I2C)
                  W2(2)=S(I2CC)
  130             I3=I+I2
                  I3C=NT-I3
                  IF(I3C)160,150,140
C
C     I3 IN FIRST QUADRANT
  140             W3(1)=S(I3C)
                  W3(2)=S(I3)
                  GO TO 200
  150             W3(1)=0.
                  W3(2)=1.
                  GO TO 200
C
  160             I3CC=I3C+NT
                  IF(I3CC)190,180,170
C
C     I3 IN SECOND QUADRANT
  170             I3C=-I3C
                  W3(1)=-S(I3C)
                  W3(2)=S(I3CC)
                  GO TO 200
  180             W3(1)=-1.
                  W3(2)=0.
                  GO TO 200
C
C     3*I IN THIRD QUADRANT
  190             I3CCC=NT+I3CC
                  I3CC = -I3CC
                  W3(1)=-S(I3CCC)
                  W3(2)=-S(I3CC)
  200             ILAST=IL+JJ
                  DO 220 I=JJ,ILAST,IDIF
                      KLAST=KL+I
                      DO 220 K=I,KLAST,2
                          K1=K+KBIT
                          K2=K1+KBIT
                          K3=K2+KBIT
C
                          R=A(K2)*W2(1)-A(K2+1)*W2(2)
                          T=A(K2)*W2(2)+A(K2+1)*W2(1)
                          A(K2)=A(K)-R
                          A(K)=A(K)+R
                          A(K2+1)=A(K+1)-T
                          A(K+1)=A(K+1)+T
C
                          R=A(K3)*W3(1)-A(K3+1)*W3(2)
                          T=A(K3)*W3(2)+A(K3+1)*W3(1)
                          AWR=A(K1)*W(1)-A(K1+1)*W(2)
                          AWI=A(K1)*W(2)+A(K1+1)*W(1)
                          A(K3)=AWR-R
                          A(K3+1)=AWI-T
                          A(K1)=AWR+R
                          A(K1+1)=AWI+T
                          T=A(K1)
                          A(K1)=A(K)-T
                          A(K)=A(K)+T
                          T=A(K1+1)
                          A(K1+1)=A(K+1)-T
                          A(K+1)=A(K+1)+T
                          R=-A(K3+1)
                          T=A(K3)
                          A(K3)=A(K2)-R
                          A(K2)=A(K2)+R
                          A(K3+1)=A(K2+1)-T
  220                 A(K2+1)=A(K2+1)+T
C     END OF I AND K LOOPS
C
  230             JJ=JJDIF+JJ
C     END OF J-LOOP
C
  235             JLAST=4*JLAST+3
  240         CONTINUE
C     END OF  L  LOOP
C
C     WE NOW HAVE THE COMPLEX FOURIER SUMS BUT THEIR ADDRESSES ARE
C     BIT-REVERSED.  THE FOLLOWING ROUTINE PUTS THEM IN ORDER
              N1VNT=N1/NT
              JJD1=N1/(N1VNT*N1VNT)
              J=1
  800         JJ1=1
              DO 860 JPP1=1,N1VNT
                  IPP1=INV(JJ1)
                  DO 850 JP1=1,NT
  810                 IP1=INV(JP1)*N1VNT
  830                 I=2*(IPP1+IP1)+1
                      IF (J-I) 840,845,845
  840                 T=A(I)
                      A(I)=A(J)
                      A(J)=T
                      T=A(I+1)
                      A(I+1)=A(J+1)
                      A(J+1)=T
  845                 CONTINUE
  850             J=J+2
  860         JJ1=JJ1+JJD1
C     END OF JPP1 AND JP2
C
C
  890         IF(IFSET)891,895,895
  891         DO 892 I = 1,NX
  892         A(2*I) = -A(2*I)
  895         RETURN
C
C     THE FOLLOWING PROGRAM COMPUTES THE SIN AND INV TABLES.
C
  900         MT=M-2
              MT = MAX0(2,MT)
  904         IF (MT-20)906,906,905
  905         IFERR = 1
              GO TO 895
  906         IFERR=0
              NT=2**MT
              NTV2=NT/2
C
C     SET UP SIN TABLE
C     THETA=PIE/2**(L+1) FOR L=1
  910         THETA=.7853981634
C
C     JSTEP=2**(MT-L+1) FOR L=1
              JSTEP=NT
C
C     JDIF=2**(MT-L) FOR L=1
C     JDIF=2**(MT-L) FOR L=1
              JDIF=NTV2
              S(JDIF)=SIN(THETA)
              DO 950 L=2,MT
                  THETA=THETA/2.
                  JSTEP2=JSTEP
                  JSTEP=JDIF
                  JDIF=JSTEP/2
                  S(JDIF)=SIN(THETA)
                  JC1=NT-JDIF
                  S(JC1)=COS(THETA)
                  JLAST=NT-JSTEP2
                  IF(JLAST - JSTEP) 950,920,920
  920             DO 940 J=JSTEP,JLAST,JSTEP
                      JC=NT-J
                      JD=J+JDIF
  940             S(JD)=S(J)*S(JC1)+S(JDIF)*S(JC)
  950         CONTINUE
C
C     SET UP INV(J) TABLE
C
  960         MTLEXP=NTV2
C
C     MTLEXP=2**(MT-L). FOR L=1
              LM1EXP=1
C
C     LM1EXP=2**(L-1). FOR L=1
              INV(1)=0
                  DO 980 L=1,MT
                      INV(LM1EXP+1) = MTLEXP
                      DO 970 J=2,LM1EXP
                          JJ=J+LM1EXP
  970                 INV(JJ)=INV(J)+MTLEXP
                      MTLEXP=MTLEXP/2
  980             LM1EXP=LM1EXP*2
  982             IF(IFSET)12,895,12
                  END