c
c *************************************************************************
c
c  standard SIR file write routine
c
      subroutine writesir3(fname,iu_in,ierr,nhead,ndes,nhtype,idatatype,
     *     nsx,nsy,xdeg,ydeg,ascale,bscale,a0,b0,iopt,ioff,iscale,
     *     ixdeg_off,iydeg_off,ideg_sc,iscale_sc,ia0_off,ib0_off,i0_sc,
     *     iyear,isday,ismin,ieday,iemin,iregion,itype,
     *     ipol,ifreqhm,ispare1,anodata,vmin,vmax,
     *     sensor,title,type,tag,crproc,crtime,
     *     stval,descrip,ldes,iaopt,nia)
c
c     Version 3 standard SIR image format write routine
c
c     written by D.G. Long  28 Oct. 2000
c
c
c inputs:
c     fname    file name to write to
c              note: may overwrite an existing file of the same name
c     iu_in    fortran logical unit to use
c     idatatype file data type code (0,2=i*2,1=i*1,4=i*4) def=i*2
c     nsx,nsy image dimensions
c     xdeg..b0 projection factors
c     iopt    projection type
c     ioff,iscale image storage scale factors
c     ixdeg_off..i0_sc projection offset and scale storage factors (see below)
c     iyear,isday,ismin  year,day,minute of start of data used in image
c     ieday,iemin day,minute of end of data used in image
c     iregion study region id number
c     itype   image type code (=0 none or unknown)
c     ispare1 spare integer
c     sensor  20 character string: describes sensor
c     title   80 character string: image title
c     type    80 character string: description of image type
c     tag     creator byline
c     crproc  100 character string: name and version of creating program
c     crtime  40 character string: date and time of creation
c     stval   image array (floats)
c     descrip variable length character string: description and annontation
c     ldes    number of characters in descrip
c     iaopt   array of optional integers
c       by convention, first value iaopt is a code telling how to interpret
c       the rest of the array if nia>0
c     nia     number of integers in extra iaopt header
c
c outputs:
c     ierr   file write error code
c             set to 0 for successful write
c             set to -1 for open error
c             set to -2 for write error
c             set to -3 for invalid image size
c     nhead  number of 512 byte blocks in header
c     nhtype file header type code
c
c     SIR files have headers which are multiples of 512 bytes followed by
c     image data stored as 2 byte integers zero padded to be a multiple
c     of 512 bytes.
c
        implicit none
c
	character*(*) 	fname
	integer		iu_in,ierr,nhead,ndes,nhtype,idatatype
	integer 	nsx,nsy,iopt
	real		xdeg,ydeg,ascale,bscale,a0,b0
        integer         ixdeg_off,iydeg_off,ideg_sc,iscale_sc
        integer         ia0_off,ib0_off,i0_sc
	integer		ioff,iscale,iyear,isday,ismin,ieday,iemin
        integer		iregion,itype,ipol,ifreqhm,ispare1,ldes,nia
	real            anodata,vmin,vmax
	real            stval(*)
	character*(*)	sensor,title,type,tag,crproc,crtime,descrip
	integer		iaopt(*)
c
c     working variables
c
	integer(kind=1),dimension(512) :: tempb    ! integer*1 (-127 .. 128)
	integer*2	temp(256)
	real            tempf(128)
	equivalence     (temp,tempb)  ! used only to save space
	equivalence     (temp,tempf)  ! used only to save space
	integer*2       i2(2)
	real            f2
	equivalence     (f2,i2)       ! used in i*2 to float mapping
	character	sens1*41,tit1*81,type1*139
        character       tag1*41,crp1*101,crt1*29
        integer         iu,minv,maxv,i,ii,j,k,ntot,nrec
        integer         irec,icnt,imax,iocnt,iucnt
c
c	header mapping (see code for scaling of <= variables)
c       note that character strings do not have to be null terminated
c
c	temp(1)	= nsx			! pixels in x direction
c	temp(2) = nsy			! pixels in y direction
c       temp(3) <= xdeg			! span of x
c	temp(4) <= ydeg			! span of y
c	temp(5) = nhtype                ! header type (old<15,20,30)
c	temp(6) <= ascale               ! x scaling
c	temp(7) <= bscale               ! y scaling
c	temp(8) <= a0                   ! x (or lon) origin
c         note: longitudes should be in the range -180 to 180
c	temp(9) <= b0                   ! y (or lat) origin
c         note: latitudes should be in the range -90 to 90
c
c     scaling for prorjection parameters are generally:
c
c        temp(3) = nint((xdeg + float(ixdeg_off)) * float(ideg_sc))
c        temp(4) = nint((ydeg + float(iydeg_off)) * float(ideg_sc))
c        temp(6) = nint(ascale * float(iscale_sc))
c        temp(7) = nint(bscale * float(iscale_sc))
c        temp(8) = nint((a0 + float(ia0_off)) * float(i0_sc))
c        temp(9) = nint((b0 + float(ib0_off)) * float(i0_sc))
c
c     with the following projection specific exceptions:
c
c	if (iopt.eq.1.or.iopt.eq.2) then		! lambert
c           temp(6) = nint(float(iscale_sc)/ascale)
c           temp(7) = nint(float(iscale_sc)/bscale)
c	if (iopt.eq.11.or.iopt.eq.12.or.iopt.eq.13) then ! EASE grid
c           temp(6) = nint(float(iscale_sc)*anint(10.*ascale*
c     *                         25.067525/6371.228)*0.05)
c           temp(7) = nint(float(iscale_sc)*anint(10.*bscale/
c     *                         25.067525)*0.05)
c
c	temp(10) = ioff			! offset to be added to scale val
c	temp(11) = iscale		! scale factor ival=(val-ioff)/iscale
c	temp(12) = iyear		! year for data used
c	temp(13) = isday		! starting JD
c	temp(14) = ismin		! time of day for first data (in min)
c	temp(15) = ieday		! ending JD
c	temp(16) = iemin		! time of day for last data (in min)
c	temp(17) = iopt			! projection type
c					!  -1 = no projection, image only
c					!   0 = rectalinear lat/lon
c					!   1 = lambert equal area
c					!   2 = lambert equal area (local rad)
c					!   5 = polar stereographic
c					!  11 = EASE north equal area grid
c					!  12 = EASE south equal area grid
c					!  13 = EASE cylindrical grid
c	temp(18) = iregion		! region id code
c	temp(19) = itype		! image type code
c                                       ! some standard values: (0=unknown)
c                                       ! 1 = scatterometer A (dB)
c                                       ! 2 = scatterometer B (dB/deg)
c                                       ! 3 = radiometer Tb (K)
c                                       ! 9 = topography (m)
c	temp(20)-temp(39) 40 chars of sensor
c       temp(40) = iscale_sc            ! ascale/bscale scale factor
c       temp(41) = nhead                ! number of 512 byte header blocks
c       temp(42) = ndes                 ! number of 512 byte blocks description
c       temp(43) = ldes                 ! number of bytes of description
c       temp(44) = nia                  ! number of optional integers
c       temp(45) = ipol                 ! polarization (0=n/a,1=H,2=V)
c       temp(46) = ifreqhm              ! frequency in 100's MHz (0 if n/a)
c       temp(47) = ispare1              ! spare
c       temp(48) = idatatype            ! data type code 0,2=i*2,1=i*1,4=float
c
c       the value of idata type determines how data is stored and how
c       anodata, vmin, and vmax are stored.
c
c       if idatatype = 1 data is stored as bytes (minv=128)
c       if idatatype = 2 data is stored as 2 byte integers (minv=32766)
c       if idatatype = 4 data is stored as IEEE floating point
c
c       if idatatype = 1,2 anodata,vmin,vmax are stored as 2 byte integers
c         in temp(49)..temp(51)  minv, ioff and iscal used to convert
c         integers or bytes into floating point values
c         nodata, vmin, and vmax must be representable with ioff and iscale
c            temp(*) = (value-ioff)*iscale-minv
c            value = float(temp(*)+minv)/float(iscale)+ioff
c       idatatype=2 is considered the SIR standard format
c
c       if idatatype = f anodata,vmin,vmax are stored as floating points
c         in temp(42)..temp(57) and minv, ioff and iscale are ignored here
c         and when reading the file.
c         floating point numbers are NOT standard across platforms and
c         are therefore not recommended
c
c       temp(49) <= anodata           ! value representing no data
c       temp(50) <= vmin              ! minimum useful value from creator prg
c       temp(51) <= vmax              ! maximum useful value from creator prg
c       temp(52,53) = anodata         ! IEEE floating value of no data
c       temp(54,55) = vmin            ! IEEE floating minimum useful value
c       temp(56,57) = vmax            ! IEEE floating maximum useful value
c
c	temp(58)-temp(126) 150 chars of type
c       temp(127) = ixdeg_off         ! xdeg offset
c       temp(128) = iydeg_off         ! ydeg offset
c	temp(129)-temp(168) 80 chars of title
c       temp(169) = ideg_sc           ! xdeg,ydeg scale factor
c	temp(170)-temp(189) 40 chars of tag
c       temp(190) = ia0_off           ! b0 offset 
c	temp(191)-temp(240) 100 chars of crproc
c       temp(241) = ib0_off           ! b0 offset 
c	temp(242)-temp(255) 28 chars of crtime
c       temp(256) = i0_sc             ! a0,b0 scale factor
c
c     optional header blocks:
c
c	ndes header blocks of 512 bytes: chars of description
c	nhead-ndes-1 header blocks of 512 bytes: values of iaopt
c       by convention, first value iaopt is a code telling how to interpret
c       the rest of the array if nia>0.  Usage of additional blocks is
c       user dependent and non-standard.
c
c       remainder of file is image data in a multiple of 512 byte blocks
c
c       one,two byte integer scaling (idatatype=1,2) is
c          intval = (fvalue-ioff)*iscale-minv
c          fvalue = float(intval+minv)/float(iscale)+ioff
c       no scaling of float values for (idatatype=4)
c
c *******************************************************************
c
c     get platform-dependent parameters
c
        include 'SIR.inc'
c
c *******************************************************************
c
c     error check other input values
c
        iu=iu_in
        if (iu.lt.1) then
           iu=2
           write (*,*) '*** writesir3 error: invalid iu, using ',iu
        endif
c
        if (nsx.lt.1.or.nsy.lt.1.or.nsx.gt.32767
     *       .or.nsy.gt.32767) then
           write (*,*) '*** writesir3 error: invalid nsx,nsy ',nsx,nsy
           ierr=-3
           return
        endif
c
c     check projection scale and offset parameters
c
        if (nhtype.lt.30.or.
     *      ideg_sc.le.0.or.iscale_sc.le.0.or.i0_sc.le.0) then
           if (nhtype.ge.30.and.
     *          (ideg_sc.le.0.or.iscale_sc.le.0.or.i0_sc.le.0))
     *       write(*,*) '*** writsir3 warning: projection scale error'
     *          ,ideg_sc,iscale_sc,i0_sc,ixdeg_off,iydeg_off,
     *          ia0_off,ib0_off
c
c     set parameters to header version 2.0 defaults
c
           if (iopt.eq.-1) then ! image only
              ideg_sc=10
              iscale_sc=1000
              i0_sc=100
              ixdeg_off=0
              iydeg_off=0
              ia0_off=0
              ib0_off=0
           else if (iopt.eq.0) then ! rectalinear lat/lon
              ideg_sc=100
              iscale_sc=1000
              i0_sc=100
              ixdeg_off=-100
              iydeg_off=0
              ia0_off=0
              ib0_off=0
           else if (iopt.eq.1.or.iopt.eq.2) then ! lambert
              ideg_sc=100
              iscale_sc=1000
              i0_sc=1
              ixdeg_off=0
              iydeg_off=0
              ia0_off=0
              ib0_off=0
           else if (iopt.eq.5) then ! polar stereographic
              ideg_sc=100
              iscale_sc=100
              i0_sc=1
              ixdeg_off=-100
              iydeg_off=0
              ia0_off=0
              ib0_off=0
           else if (iopt.eq.11.or.iopt.eq.12.or.iopt.eq.13) then ! EASE grid
              ideg_sc=10
              iscale_sc=1000
              i0_sc=10
              ixdeg_off=0
              iydeg_off=0
              ia0_off=0
              ib0_off=0
           else ! unknown default scaling
              ideg_sc=100
              iscale_sc=1000
              i0_sc=100
              ixdeg_off=0
              iydeg_off=0
              ia0_off=0
              ib0_off=0
           endif
           if (nhtype.lt.30) nhtype=30  ! can only write new headers
c           if (nhtype.ge.30.and.
c     *          (ideg_sc.le.0.0.or.iscale_sc.le.0.0.or.i0_sc.le.0)
c     *       write(*,*) '*** values used:',ideg_sc,iscale_sc,i0_sc,
c     *          ixdeg_off,iydeg_off,ia0_off,ib0_off
        endif
c
c	make first header block
c
        ierr = 0
	temp(1)	= nsx				! image dimensions
	temp(2) = nsy
        if (nhtype.lt.30) nhtype = 31 ! nhtype=30 reserved for version 2.0
	temp(5) = nhtype		       ! version 3.0 header code
c
c       scale projection variables based on transform option
c
        temp(3) = nint((xdeg + float(ixdeg_off)) * float(ideg_sc))
        temp(4) = nint((ydeg + float(iydeg_off)) * float(ideg_sc))
        temp(6) = nint(ascale * float(iscale_sc))
        temp(7) = nint(bscale * float(iscale_sc))
        temp(8) = nint((a0 + float(ia0_off)) * float(i0_sc))
        temp(9) = nint((b0 + float(ib0_off)) * float(i0_sc))
c
	if (iopt.eq.-1)	then			! image only
	else if (iopt.eq.0) then		! rectalinear lat/lon
	else if (iopt.eq.1.or.iopt.eq.2) then		! lambert
           temp(6) = nint(float(iscale_sc)/ascale)
           temp(7) = nint(float(iscale_sc)/bscale)
	else if (iopt.eq.5) then		! polar stereographic
	else if (iopt.eq.11.or.iopt.eq.12.or.iopt.eq.13) then ! EASE grid
           temp(6) = nint(float(iscale_sc)*anint(10.*ascale*
     *                         25.067525/6371.228)*0.05)
           temp(7) = nint(float(iscale_sc)*anint(10.*bscale/
     *                         25.067525)*0.05)
	else
           write (*,*) '*** Unrecognized SIR option in writesir3 ***'
	endif
c
c     store projection parameters offset and scale factors
c
        temp( 40) = iscale_sc
        temp(127) = ixdeg_off
        temp(128) = iydeg_off
        temp(169) = ideg_sc
        temp(190) = ia0_off
        temp(241) = ib0_off
        temp(256) = i0_sc
c
c	store scale factors, time, option, region, and image type
c
	temp(10) = ioff
	temp(11) = iscale
	if (iscale.eq.0) temp(11)=1
	temp(12) = iyear
	temp(13) = isday
	temp(14) = ismin
	temp(15) = ieday
	temp(16) = iemin
	temp(17) = iopt
	temp(18) = iregion
	temp(19) = itype
c
	nhead=1
	ndes=0
	if (ldes.gt.0) then
	   ndes=ldes/512
	   if (mod(ldes,512).gt.0) ndes=ndes+1
c	   write (*,*) 'extra descriptor',ldes,ndes
	   nhead=nhead+ndes
	endif
	if (nia.gt.0) then
c	   write (*,*) 'extra integers',nia
	   nhead=nhead+nia/256
	   if (mod(nia,256).gt.0) nhead=nhead+1
	endif
c
	temp(41) = nhead
	temp(42) = ndes
	temp(43) = ldes
	temp(44) = nia
	temp(45) = ipol
	temp(46) = ifreqhm
	temp(47) = ispare1
	temp(48) = idatatype
c
	if (idatatype.eq.1) then
	   maxv=127
	   minv=128
	else
	   maxv=32767
	   minv=32767
	endif
c
	if (idatatype.ne.4) then
	   k = nint(iscale*(anodata-ioff))-minv
	   if (k.gt.maxv) then
	      k=maxv
	      write (*,*) '*** WRITESIR: overflow in "anodata"',
     *             anodata,ioff,iscale
	   endif
	   if (k.lt.-minv) then
	      k=-minv
	      write (*,*) '*** WRITESIR: underflow in "anodata"',
     *             anodata,ioff,iscale
	   endif
	   temp(49) = k
	   k = nint(iscale*(vmin-ioff))-minv
	   if (k.gt.maxv) then
	      k=maxv
	      write (*,*) '*** WRITESIR: overflow in "vmin"',
     *             vmin,ioff,iscale
	   endif
	   if (k.lt.-minv) then
	      k=-minv
	      write (*,*) '*** WRITESIR: underflow in "vmin"',
     *             vmin,ioff,iscale
	   endif
	   temp(50) = k
	   k = nint(iscale*(vmax-ioff))-minv
	   if (k.gt.maxv) then
	      k=maxv
	      write (*,*) '*** WRITESIR: overflow in "vmax"',
     *             vmax,ioff,iscale
	   endif
	   if (k.lt.-minv) then
	      k=-minv
	      write (*,*) '*** WRITESIR: underflow in "vmax"',
     *             vmax,ioff,iscale
	   endif
	   temp(51) = k
	endif
c
	f2=anodata
	temp(52)=i2(1)
	temp(53)=i2(2)
	f2=vmin
	temp(54)=i2(1)
	temp(55)=i2(2)
	f2=vmax
	temp(56)=i2(1)
	temp(57)=i2(2)
c
c	write character variables
c
	sens1=' '  ! initially make them blank
	tit1 =' '
        type1=' '
        tag1 =' '
        crp1 =' '
        crt1 =' '
	sens1=sensor
	do i=1,20
		j=(i-1)*2+1
		temp(i+19)=ichar(sens1(j:j))+256*ichar(sens1(j+1:j+1))
	end do

	type1=type
	do i=1,69
		j=(i-1)*2+1
		temp(i+57)=ichar(type1(j:j))+256*ichar(type1(j+1:j+1))
	end do

	tit1=title
	do i=1,40
		j=(i-1)*2+1
		temp(i+128)=ichar(tit1(j:j))+256*ichar(tit1(j+1:j+1))
	end do

	tag1=tag
	do i=1,20
		j=(i-1)*2+1
		temp(i+169)=ichar(tag1(j:j))+256*ichar(tag1(j+1:j+1))
	end do

	crp1=crproc
	do i=1,50
		j=(i-1)*2+1
		temp(i+190)=ichar(crp1(j:j))+256*ichar(crp1(j+1:j+1))
	end do

	crt1=crtime
	do i=1,14
		j=(i-1)*2+1
		temp(i+241)=ichar(crt1(j:j))+256*ichar(crt1(j+1:j+1))
	end do
c
c	open output file
c
        if (VMS) then
	  open(unit=iu,file=fname,status='new',      ! for vax/vms
     *          form='formatted',err=999,
     *		recl=ISIRRECLENGTH)
c     *          ,recordtype='fixed',carriagecontrol='none')
        else
	  open(unit=iu,file=fname,status='unknown',  ! generally portable
     *          form='unformatted',err=999,          ! unix file open
     *		recl=ISIRRECLENGTH,access='direct')
        endif
c
c	write first header block
c
	irec=1
	if (BSWAP) call swapbuf(temp,256)
	if (VMS) then
          write(iu,414,err=1999) temp
        else
          write(iu,rec=1,err=1999) temp
        endif
c
c       write additional header records if needed
c
	if (ndes.gt.0) then
	   icnt=0
	   do ii=1,ndes
	      do i=1,256
		 k=0
		 icnt=icnt+1
		 if (icnt.le.ldes) then
		    k=ichar(descrip(icnt:icnt))
		    icnt=icnt+1
		    if (icnt.le.ldes) k=k+256*ichar(descrip(icnt:icnt))
		 endif
		 temp(i)=k
	      end do
	      if (BSWAP) call swapbuf(temp,256)
	      irec=irec+1
	      if (VMS) then
		 write(iu,414,err=1999) temp
	      else
		 write(iu,rec=irec,err=1999) temp
	      endif
	   end do
	endif
c
c	write extra header parameters
c
	if (nhead-ndes-1.gt.0) then
	   icnt=0
	   do ii=nhead-ndes+1,nhead
	      do i=1,256
		 icnt=icnt+1
		 if (icnt.le.nia) then
		    temp(i)=iaopt(icnt)
		 else
		    temp(i)=0
		 endif
	      end do
	      if (BSWAP) call swapbuf(temp,256)
	      irec=irec+1
	      if (VMS) then
		 write(iu,414,err=1999) temp
	      else
		 write(iu,rec=irec,err=1999) temp
	      endif
	   end do
	endif
c
c	write image data
c
	iucnt=0
	iocnt=0
	ntot = nsx*nsy
	nrec=256                      ! output values/record (I*2)
	if (idatatype.eq.1) nrec=512  ! output values/record (byte)
	if (idatatype.eq.4) nrec=128  ! output values/record (float)
	do j = 0,ntot,nrec
	   imax=min(nrec,ntot-j)
	   if (imax.gt.0) then
	      do i=1,imax
		 if (idatatype.eq.4) then
		    tempf(i)=stval(j+i)
		 else
		    k = nint(iscale*(stval(j+i)-ioff))-minv
		    if (k.gt.maxv) then
		       k=maxv
		       iocnt=iocnt+1
		    endif
		    if (k.lt.-minv) then
		       k=-minv
		       iucnt=iucnt+1
		    endif
		    if (idatatype.eq.1) then
		       tempb(i) = k
		    else
		       temp(i) = k
		    endif
		 endif
	      end do
	      if (imax.ne.nrec) then
		 do i=imax+1,nrec
		    if (idatatype.eq.1) then
		       tempb(i) = -minv
		    else if (idatatype.eq.4) then
		       tempf(i) = anodata
		    else
		       temp(i) = -minv
		    endif
		 end do
	      endif
	      irec=irec+1
	      if (idatatype.eq.1) then ! byte size
		 if (VMS) then
		    write(iu,413,err=1999) tempb
 413		    format(512a1)
		 else
		    write(iu,rec=irec,err=1999) tempb
		 endif
	      else if (idatatype.eq.4) then ! 4 byte float size
		 if (VMS) then
		    write(iu,412,err=1999) tempf
 412		    format(128a4)
		 else
		    write(iu,rec=irec,err=1999) tempf
		 endif
	      else		! integer*2 size
		 if (BSWAP) call swapbuf(temp,256)
		 if (VMS) then
		    write(iu,414,err=1999) temp
 414		    format(256a2)
		 else
		    write(iu,rec=irec,err=1999) temp
		 endif
	      endif
	   endif
	end do 
c
c	close file
c
	close(unit=iu)
c
c     summarize over/underflow stats
c
	if (iucnt.gt.0) write (*,50) iucnt,ntot
50	format(' *** WRITESIR3 Underflow count: ',I9,' of ',I9,' ***')
	if (iocnt.gt.0) write (*,60) iocnt,ntot
60	format(' *** WRITESIR3 Overflow count:  ',I9,' of ',I9,' ***')
	return
c
 999    continue
        write (*,5000)
 5000   format(' *** writesir3: ERROR OPENING OUTPUT FILE ***')
        ierr=-1
        return
 1999   continue
        write (*,5050)
 5050   format(' *** writesir3: ERROR WRITING OUTPUT FILE ***')
        ierr=-2
        return
	end
