C+ C NAME: C iHOSRead C PURPOSE: C Read single record from Helios data file C CATEGORY: C I/O: Helios C CALLING SEQUENCE: function iHOSRead(iD,iU,iRecl,iR,TT,PP,CC,FF,RR,LL,NN,ZZ) C INPUTS: C iD integer identifies data properties C each bit identifies a property defined in include file hos_e9.h C Bits are set by summing parameters defined in the include file. C C Bits set for input are for: C - HOS__P_*: photometer selection C - HOS__C_*: color selection C - HOS__F_*: filter selection C If any one of these bits is set then the first record following record C iR matching the selection criteria is returned. C If none of these bits is set then record iR is returned. C C - HOS__NOT: negates the photometer/color/filter selection C C - HOS__OS_*: only one of the architecture bits should be set to identify C the OS used to write the file. If none is set then iHOSArch is called C to try to identify the architecture. C C iU integer logical unit number for data file C iRecl integer record length in (4-byte) long words C The calling program usually sets these by a call to href=bOpenFile= C C iR integer Selection criteria set: starting point for search for next record is iR+1 C No selection criteria: record number to be read C NN integer # sectors to be returned in Z C MUST BE EVEN. UNEVEN VALUES WILL BE ROUNDED DOWN TO AN EVEN VALUE C Sectors 1..N/2 will be put in Z(1)..Z(N/2) C Sectors 33-N/2..32 will be put in Z(N/2+1)..Z(N) C SPECIAL CASE: N=1 C Can be used to pull out the intensity only for photometer 3 C (in this case ONLY the photometer 3 bit in iD should be set) C OUTPUTS: C iD integer HOS__OS_*: if no architecture bit was set on input, then iHOSArch will C try to find the appropriate architecture bit If it fails all architecture C bits are cleared. C HOS__AA or HOS__BB: iHOSArch also sets or clears the spacecraft bit C HOS__NONORM: is cleared or set if the color value is smaller or larger C than 100, respectively C C iR integer Selection criteria set: On read error (or EOF), iR will be the record C number of the last successfully read record. If read was OK, then iR C will be the number of the record read successfully. C No selection criteria: Same as the input value. C C TT real time (doy) C PP integer photometer (1/2/3) C CC integer color (1/2/3) C FF integer filter (1..5) (if P=3 then F=4)(4=Clear,5=pB) C RR real heliocentric distance (AU) C LL real topocentric ecliptic longitude (deg) of the Sun C ZZ(NN) real intensities C IP=3: ZZ(1) = intensity, ZZ(2) = pB C CALLS: C iGetSymbol, BadR4, cInt2Str, iwhitespace, itrim, Say, iHOSArch, CvR4 C ArrR4Mask, ArrR4Copy, ArrR4Bad C INCLUDE: include 'hos_e9.h' include 'dirspec.h' C RESTRICTIONS: C > Sectors are stored in Z in the same order as they are found in the file C (consisten with normal sector numbers). Swapping sector ordering to modified C sector numbers is done in HOSRead. C > iHOSRead always returns a color value of 1,2, or 3. If the record is read from C an unnormalized file (as indicated by a color value > 100) then the no-normaliation C bit in iD is set and the color value is adjusted. C PROCEDURE: C Records for the 90 degree photometers store data as follows: C Day of year real*4 C Photometer integer*2 C Color integer*2 C Distance real*4 C Longitude Sun real*4 C Intensities real*4 array (2: intensity and pB) C A 90 deg record is always 6 words long. C C Records for the 16 and 31 degree photometers store data as follows: C Day of year real*4 C Photometer integer*2 C Color integer*2 C Filter integer*2 C Distance real*4 C Longitude Sun real*4 C Intensities real*4 array (2,4,6,..,32) C In the old days these data were stored in a structure, which was then written to file. C Depending on how the program was compiled the structure may or may not be aligned on C longword boundaries. If it is then a 2-byte word is inserted after the color entry. C The default for the Helios data has always been to work with unaligned structures. C Should a file be encountered containing aligned structures then the file can still be C read by setting the symbol HOS_ALIGN. C C The first time iHOSRead or href=iHOSWrite= is called, it checks for the existence of C the symbol HOS_ALIGN. If found and HOS_ALIGN='1', then the records for the 16 and 31 C degree photometer are assumed to be aligned, i.e. a 2-byte dummy variable is inserted C after the filter entry. C MODIFICATION HISTORY: C SEP-1998, Paul Hick (UCSD/CASS) C MAY-2000, Paul Hick (UCSD/CASS), improved check for architecture C DEC-2001, Paul Hick (UCSD/CASS; pphick@ucsd.edu) C Fixed minor problem with checking error status of read statements C The error check is now immediately after the read statement, rather C than following the architecture check using the photometer value. C- integer iD integer iU integer iRecl integer iR real TT integer PP integer CC integer FF real RR real LL integer NN real ZZ(*) character cOp*3 integer*2 P integer*2 C integer*2 F integer*2 B ! Used to read/write file parameter (nS=32) real Z(nS) real L character cStr*100 character cInt2Str*14 character cSay*8 /'iHOSRead'/ real BadHOS /-1E7/ integer*2 POld /3/ save POld integer kPP(3) /HOS__P_1, HOS__P_2, HOS__P_3/ integer kCC(3) /HOS__C_1, HOS__C_2, HOS__C_3/ integer kFF(5) /HOS__F_1, HOS__F_2, HOS__F_3, HOS__F_4, HOS__F_5/ logical bAutoIncr logical bRead logical bWrongType logical bNegate logical bAlign logical bFirst /.TRUE./ logical bWrongArch save bFirst, bAlign bWrongArch(P) = P .lt. 1 .or. P .gt. 3 if (bFirst) then bAlign = iGetSymbol('HOS_ALIGN',cStr) .ne. 0 if (bAlign) bAlign = cStr(:1) .eq. '1' bFirst = .FALSE. end if Bad = BadR4() if (iRecl .eq. 6) POld = 3 ! Force reading of phot 3 record (iS=0) iS = (iRecl-4.5)/2 ! Half # Sectors in phot 1 or 2 record !------- ! If no data selection is specified (bAutoIncr = .FALSE.) then read the record specified in record iR. ! Otherwise look for the next record matching (or negating) the selection criteria. bAutoIncr = iand(iD,HOS__PCF_ALL) .ne. 0 if (bAutoIncr) then ! Auto-Increment record counter bNegate = iand(iD,HOS__NOT) .ne. 0 ! Negate selection ! No 16/31 deg records on 90 deg file if (iand(iD,HOS__P_3) .eq. 0 .and. iRecl .eq. 6) then iHOSRead = -1 ! Simulate read error (note that iR is not incremented) return end if iR = iR+1 ! Increment counter end if bRead = .TRUE. do while (bRead) if (POld .eq. 3) then read (iU,rec=iR,iostat=iHOSRead) T,P,C, R,L,(Z(I),I=1,2) F = 4 else if (bAlign) then read (iU,rec=iR,iostat=iHOSRead) T,P,C,F,B,R,L,(Z(I),I=1,iS),(Z(I),I=nS+1-iS,nS) else read (iU,rec=iR,iostat=iHOSRead) T,P,C,F, R,L,(Z(I),I=1,iS),(Z(I),I=nS+1-iS,nS) end if if (iHOSRead .ne. 0) then ! Read error if (iR .eq. 1) then cStr = 'error '//cInt2Str(iHOSRead)//' on record '//cInt2Str(iR)//' of' I = iwhitespace(cStr) inquire (iU, name=cStr(I+2:)) if (itrim(cStr(I+2:)) .gt. 0) call Say(cSay,'W','Read',cStr) end if ! If error is EOF then IR becomes # records on file if (bAutoIncr) iR = iR-1 ! Decrement record counter return ! Return on read error end if !------- ! Before we can use P,C,F for data selection we need to check that there are no problems ! with the architecture origin. If P is not equal 1, 2, or 3 then probably we are reading ! a Unix file on a non-Unix architecture or v.v. We need to swap bytes before using P,C,F. ! If after byte swapping P still is not equal 1, 2, 3, then we have a problem. if (bWrongArch(P)) then call CvSwap(1,2,1,P) if (bWrongArch(P)) call Say(cSay,'E','Invalid','photometer; probably not a Helios file') call CvSwap(1,2,1,C) if (POld .ne. 3) call CvI2(1,2,1,F) end if bWrongType = (POld .eq. 3 .and. P .ne. 3) .or. (POld .ne. 3 .and. P .eq. 3) if (bAutoIncr) then ! Use selection criteria !------- ! Check whether the record just read passes the selection criteria on filter, color and photometer ! If it doesn't, set bRead = .TRUE. ! Note that if the record was read with the wrong type the filter F may not be available. In that ! case it is possible to positively reject the record if it doesn't fit the color and photometer ! selection, but it is not possible to determine whether it completely fits the selection. ! Unnormalized data have C=101,102,103 bRead = iand(iD,kPP(P)) .eq. 0 .or. iand(iD,kCC(mod(1*C,100))) .eq. 0 ! 1*C to force int*4 ! F is not available if wrong record type was read if (.not. bRead .and. .not. bWrongType) bRead = & (P .ne. 3 .and. iand(iD,kFF(F)) .eq. 0) .or. & (P .eq. 3 .and. iand(iD,HOS__F_CLRPB) .eq. 0) if (bRead) then ! Record did not fit selection criteria if (bNegate) then ! If negating .. bRead = bWrongType ! .. accept, or read same record again if wrong type if (bRead) POld = P else ! If regular selection .. iR = iR+1 ! .. reject record and read next one end if else if (bWrongType) then ! Record was read with wrong type, so read again bRead = .TRUE. POld = P ! This time with proper photometer setting else if (bNegate) then ! Record fit the selection criteria bRead = .TRUE. iR = iR+1 ! If negating reject record and read next one end if else ! Read single record and return bRead = bWrongType if (bRead) POld = P ! Read same record if wrong type end if end do !------- ! Check whether an architecture bit is set. If not (usually this only happens for the first record ! read from a file) then call iHOSArch and try to determine the architecture. If this fails return ! with a read error; if it succeeds set the proper bit in the output value of iD. kO = iand(iD,HOS__OS_ALL) if (kO .eq. HOS__NULL) then ! No architecture specified kO = iHOSArch(T,R,L) ! Determine architecture if (kO .eq. HOS__NULL) then ! Failed !! iHOSRead = -1 ! Indeterminate architecture: simulate read error cStr = 'error on record '//cInt2Str(iR)//' of' I = iwhitespace(cStr) inquire (iU,name=cStr(I+2:)) if (itrim(cStr(I+2:)) .gt. 0) call Say(cSay,'W','Read',cStr) ! If error is EOF then IR becomes # records on file if (bAutoIncr) iR = iR-1 ! Decrement record counter return end if ! Set proper architecture and spacecraft bit iD = iD-iand(iD,HOS__OS_ALL)-iand(iD,HOS__AB)+kO end if !------- ! Now that the architecture is known, decide whether any conversions are needed kO = iand(iD,HOS__OS_ALL) cOp = OS__VMS if (kO .eq. HOS__OS_DOS ) then cOp = OS__DOS else if (kO .eq. HOS__OS_UNIX) then cOp = OS__UNIX end if if (cOp .ne. cOpSys) then ! Real*4 conversion needed call CvR4(cOp,1,T) call CvR4(cOp,1,R) call CvR4(cOp,1,L) if (P .eq. 3) then call CvR4(cOp, 2,Z) else call CvR4(cOp,iS,Z) call CvR4(cOp,iS,Z(nS+1-iS)) end if end if !------- ! Set up the output arrays if (P .eq. 3) then F = 4 call ArrR4Mask( -2,Z,BadHOS,Bad,0.,0.,1.,Z) ! Flag -1E7 (old Helios files) N = NN iS = min(N,2) call ArrR4Copy(iS,Z,ZZ) ! Copy into output array call ArrR4Bad (N-iS,ZZ(iS+1)) ! Flag unused elements in output array else call ArrR4Bad (nS-2*iS,Z(iS+1)) ! Flag sectors which are not in file call ArrR4Mask(-nS,Z,BadHOS,Bad,0.,0.,1.,Z) ! Flag -1E7 (old Helios files) N = NN/2*2 ! Round down to even number if (N .eq. 0) call Say(cSay,'E','Zero','number of sectors requested') iS = N/2 call ArrR4Copy(iS,Z,ZZ) ! Copy sectors 1..iS call ArrR4Copy(iS,Z(nS+1-iS),ZZ(N+1-iS)) ! Copy sectors 33-iS..32 end if iD = iD-iand(iD,HOS__NONORM) ! Clear no-normalization bit if (C .gt. 100) then iD = iD+HOS__NONORM ! Set no-normalization bit C = mod(1*C,100) ! 1*C to force int*4 end if TT = T PP = P ! Integer*4 output CC = C FF = F RR = R LL = L return C+ C NAME: C iHOSWrite C PURPOSE: C Write a single record from Helios data file (entry point in iHOSRead) C CATEGORY: C I/O: Helios C CALLING SEQUENCE: entry iHOSWrite(iD,iU,iRecl,iR,TT,PP,CC,FF,RR,LL,NN,ZZ) C INPUTS: C iD integer identifies data properties C each bit identifies a property defined in include file hos_e9.h C Bits are set by summing parameters defined in the include file. C C Bits used are for: C - HOS__P_*: photometer selection (ignored if nS=1) C - HOS__C_*: color selection C - HOS__F_*: filter selection (ignored if nS=1) C If any one of these bits is set then the record iR+1 is written. C If none of these bits is set then record iR is written. C - HOS__NONORM: 100 is added to the color if this bit is set C C iU integer logical unit number for data file C iRecl integer record length in (4-byte) long words (iRecl MUST be >=6) C The record length determines how many sectors are written to file for C the 16 and 31 deg photometers: if iRecl >= 7 then M = iRecl-5 sectors C (sectors 1..,M/2 and sectors 33-M/2..32) are written. C I.e. if iRecl = 37 then all 32 sectors are written. C For the 90 deg photometer 2 'sectors' (intensity and pB) are written. C If iRecl = 6 then a 90 deg photometer record should be specified (i.e. C P = 3, since 16 and 31 deg photometer records won't fit. C C iR integer Selection criterion set: record number iR+1 is written C No selection criterion: record number iR is written C C N integer # sectors in Z to be written to file C MUST BE EVEN. UNEVEN VALUES WILL BE ROUNDED DOWN TO AN EVEN VALUE C The first N entries in Z are written to file. C Entries 1..N/2 correspond to sectors 1..N/2 C Entries N/2..N correspond to sectors 33-N/2..32 C These are fitted into the record consisten with the record length C specified in iRecl (missing sectors will be padded with BadR4() values). C OUTPUTS: C iHOSWrite integer = 0: write was succesfull C Otherwise, the write error code is returned (unequal 0) C C iR integer Selection criteria set: On write error, iR will be the same as the C input value. If write was OK, then iR will be incremented by 1. C No selection criteria: Same as the input value. C CALLS: C iGetSymbol, ArrR4Copy, ArrR4Bad, cInt2Str, iwhitespace, itrim, Say, CvSwap C SEE ALSO: C iHOSRead C RESTRICTIONS: C > Records are always written in the native format. C > Sectors are written in the same order as found in the Z-array. This ordering C should be consistent with regular sector numbers. Swapping sectors from modified C sector numbering to regular sector numbering is done in HOSWrite. C > If the no-normalization bit is set then the color value is set to 101,102 or 103. C If not the value 1,2, or 3 is written into the file. C PROCEDURE: C The first time href=iHOSRead= or iHOSWrite is called, it checks for the existence C of the symbol HOS_ALIGN. If found and HOS_ALIGN='1', then the records for the 16 and C 31 degree photometer are assumed to be aligned, i.e. a 2-byte dummy variable is C inserted after the filter entry. C MODIFICATION HISTORY: C SEP-1998, Paul Hick (UCSD/CASS) C MAY-2000, Paul Hick (UCSD/CASS), update C DEC-2001, Paul Hick (UCSD/CASS; pphick@ucsd.edu) C Modified the write statements so that bytes on each record not containing C data are explicitly set to zero. This should elimate potential differences C between files created on different operating systems. Especially Linux C is inclined to write garbage if not explicitly told otherwise. This would C not compromise the data, but is confusing when differencing files. C- if (bFirst) then bAlign = iGetSymbol('HOS_ALIGN',cStr) .ne. 0 if (bAlign) bAlign = cStr(:1) .eq. '1' bFirst = .FALSE. end if N = NN/2*2 ! Round down to even number T = TT P = PP ! Integer*4 input C = mod(CC,100) F = FF R = RR L = LL if (iand(iD,HOS__NONORM) .ne. 0) C = 100+C if (P .eq. 3) then call ArrR4Copy(2,ZZ,Z) ! Copy into output array else iS = N/2 call ArrR4Copy(iS,ZZ,Z) ! Copy sectors 1..iS call ArrR4Copy(iS,ZZ(N+1-iS),Z(nS+1-iS)) ! Copy sectors 33-iS..32 call ArrR4Bad(nS-2*iS,Z(iS+1)) ! Flag sectors which are not present end if iS = (iRecl-4.5)/2 ! Half # Sectors in phot 1 or 2 record !------- ! If no data selection is specified (bAutoIncr = .FALSE.) then write at the record specified ! in record iR. Otherwise increment the record counter by one. bAutoIncr = iand(iD,HOS__PCF_ALL) .ne. 0 if (bAutoIncr) iR = iR+1 ! Increment record counter ! We explicitly write iRecl words, if necessary by inserting a zero byte if bAlign is .TRUE. ! or by padding to the full record size. We could leave this up to the operating system ! but probably better not. B = 0 if (P .eq. 3) then if (iRecl .eq. 6) then write (iU,rec=iR,iostat=iostat) T,P,C, R,L,(Z(I),I=1,2) ! Exactly 6 words else ! Pad record with zeros write (iU,rec=iR,iostat=iostat) T,P,C, R,L,(Z(I),I=1,2), (B,I=1,(iRecl-6)*2) end if else if (bAlign) then write (iU,rec=iR,iostat=iostat) T,P,C,F,B,R,L,(Z(I),I=1,iS),(Z(I),I=nS+1-iS,nS) else ! Pad record with two zero bytes write (iU,rec=iR,iostat=iostat) T,P,C,F, R,L,(Z(I),I=1,iS),(Z(I),I=nS+1-iS,nS),B end if if (iostat .ne. 0) then ! Write error cStr = 'error '//cInt2Str(iostat)//' on record '//cInt2Str(iR)//' of' I = iwhitespace(cStr) inquire (iU, name=cStr(I+2:)) if (itrim(cStr(I+2:)) .gt. 0) call Say('iHOSWrite','W','Write', cStr) if (bAutoIncr) iR = iR-1 ! Decrement record counter end if iHOSWrite = iostat return end