📄 fxbwritm.pro
字号:
IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN ERRMSG = MESSAGE RETURN END ELSE MESSAGE, MESSAGE END ENDCASE ROW1 = LONG(ROW[0]);; If ROW represents a range, then make sure that the row range is legal, and; that reading row ranges is allowed (i.e., the column is not variable length.; IF ROW1 NE ROW2 THEN BEGIN MAXROW = NAXIS2[ILUN] IF (ROW1 LT 1) OR (ROW1 GT MAXROW) THEN BEGIN MESSAGE = 'ROW[0] must be between 1 and ' + $ STRTRIM(MAXROW,2) IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN ERRMSG = MESSAGE RETURN END ELSE MESSAGE, MESSAGE END ELSE IF (ROW2 LT ROW1) OR (ROW2 GT MAXROW) THEN BEGIN MESSAGE = 'ROW[1] must be between ' + $ STRTRIM(ROW1,2) + ' and ' + STRTRIM(MAXROW,2) IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN ERRMSG = MESSAGE RETURN END ELSE MESSAGE, MESSAGE ENDIF;; Otherwise, if ROW is a single number, then just make sure it's valid.; END ELSE BEGIN IF (ROW1 LT 1) OR (ROW1 GT NAXIS2[ILUN]) THEN BEGIN MESSAGE = 'ROW must be between 1 and ' + $ STRTRIM(NAXIS2[ILUN],2) IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN ERRMSG = MESSAGE RETURN END ELSE MESSAGE, MESSAGE ENDIF ENDELSE;; Check the type of the data against that defined for this column.; COLNDIM = LONARR(NUMCOLS) COLDIM = LONARR(NUMCOLS, 8) ;; Maximum of 8 dimensions in output COLTYPE = LONARR(NUMCOLS) BOFF1 = LONARR(NUMCOLS) BOFF2 = LONARR(NUMCOLS) NOUTPUT = LONARR(NUMCOLS) NROWS = ROW2-ROW1+1 MESSAGE = '' DTYPENAMES = [ 'BAD TYPE', 'BYTE', 'FIX', 'LONG', $ 'FLOAT', 'DOUBLE', 'COMPLEX', 'STRING', $ 'BAD TYPE', 'DCOMPLEX', $ 'BAD TYPE', 'BAD TYPE', 'BAD TYPE', 'BAD TYPE', 'LONG64' ] FOR I = 0L, NUMCOLS-1 DO BEGIN IF NOT FOUND[I] THEN GOTO, LOOP_END_DIMS ;; Data type of the input. COLTYPE[I] = IDLTYPE[ICOL[I],ILUN] SZ = 0 IF PASS EQ 'ARGUMENT' THEN BEGIN RESULT = EXECUTE('SZ = SIZE('+COLNAMES[I]+')') IF RESULT EQ 0 THEN BEGIN MESSAGE = MESSAGE + '; Could not extract type info (column '+$ STRTRIM(MYCOL[I],2)+')' FOUND[I] = 0 ENDIF ENDIF ELSE SZ = SIZE(*(POINTERS[I])) TSCAL1 = TSCAL[ICOL[I],ILUN] TZERO1 = TZERO[ICOL[I],ILUN] TYPE = SZ[SZ[0]+1] TYPE_BAD = TYPE NE COLTYPE[I] ;; Handle case of scaled data being stored in an ;; integer column IF NOT KEYWORD_SET(NOSCALE) AND $ (TSCAL1 NE 0) AND (TSCAL1 NE 1) AND $ (TYPE EQ 4 OR TYPE EQ 5) AND $ (COLTYPE[I] EQ 2 OR COLTYPE[I] EQ 3 OR COLTYPE[I] EQ 14) THEN $ TYPE_BAD = 0 ;; Unsigned types are OK IF TSCAL1 EQ 1 AND $ ((COLTYPE[I] EQ 2 AND TZERO1 EQ 32768) OR $ (COLTYPE[I] EQ 3 AND TZERO1 EQ 2147483648D)) AND $ (TYPE EQ 1 OR TYPE EQ 2 OR TYPE EQ 3 OR $ TYPE EQ 12 OR TYPE EQ 13 OR TYPE EQ 14) THEN BEGIN TYPE_BAD = 0 ENDIF IF TYPE_BAD THEN BEGIN CASE COLTYPE[I] OF 1: STYPE = 'byte' 2: STYPE = 'short integer' 3: STYPE = 'long integer' 4: STYPE = 'floating point' 5: STYPE = 'double precision' 6: STYPE = 'complex' 7: STYPE = 'string' 9: STYPE = 'double complex' 12: STYPE = 'unsigned integer' 13: STYPE = 'unsigned long integer' 14: STYPE = 'long64 integer' ENDCASE FOUND[I] = 0 MESSAGE = '; Data type (column '+STRTRIM(MYCOL[I],2)+$ ') should be ' + STYPE ENDIF DIMS = N_DIMS[*,ICOL[I],ILUN] NDIMS = DIMS[0] DIMS = DIMS[1:NDIMS] IF NDIMS EQ 1 AND DIMS[0] EQ 1 THEN BEGIN ;; Case of only one output element, try to return a ;; scalar. Otherwise, it is a vector equal to the ;; number of rows to be read COLNDIM[I] = 1L COLDIM[I,0] = NROWS ENDIF ELSE BEGIN COLNDIM[I] = NDIMS COLDIM[I,0:(NDIMS-1)] = DIMS IF NROWS GT 1 THEN BEGIN COLDIM[I,NDIMS] = NROWS COLNDIM[I] = COLNDIM[I]+1 ENDIF ENDELSE;; Check the number of elements in the input; NOUTP = ROUND(PRODUCT(COLDIM[I,0:COLNDIM[I]-1])) IF SZ[SZ[0]+1] EQ 7 THEN BEGIN NOUTP = NOUTP / COLDIM[I,0] IF NOUTP NE SZ[SZ[0]+2] THEN GOTO, ERR_NELEM NOUTPUT[I] = NOUTP ENDIF ELSE IF SZ[SZ[0]+2] NE NOUTP THEN BEGIN ERR_NELEM: MESSAGE = MESSAGE+'; Data array (column '+STRTRIM(MYCOL[I],2)+$ ') should have ' + STRTRIM(LONG(NOUTP),2) + ' elements' FOUND[I] = 0 ENDIF ELSE NOUTPUT[I] = NOUTP ;; Byte offsets BOFF1[I] = BYTOFF[ICOL[I],ILUN] IF ICOL[I] EQ TFIELDS[ILUN]-1 THEN BOFF2[I] = NAXIS1[ILUN]-1 $ ELSE BOFF2[I] = BYTOFF[ICOL[I]+1,ILUN]-1 LOOP_END_DIMS: ENDFOR;; Check to be sure that there are columns to be written; W = WHERE(FOUND EQ 1, COUNT) IF COUNT EQ 0 THEN BEGIN STRPUT, MESSAGE, ':', 0 MESSAGE = 'ERROR: No requested columns could be written'+MESSAGE IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN ERRMSG = MESSAGE RETURN END ELSE MESSAGE, MESSAGE ENDIF ELSE IF MESSAGE NE '' THEN BEGIN STRPUT, MESSAGE, ':', 0 MESSAGE = 'WARNING: Some columns could not be written'+MESSAGE IF N_ELEMENTS(WARNMSG) NE 0 THEN WARNMSG = MESSAGE $ ELSE MESSAGE, MESSAGE, /INFO ENDIF ;; I construct a list of unique column names here. Why? ;; Because if *all* the columns are named, then there is no ;; need to read the data from disk first. Since columns can ;; be given more than once in MYCOL, we need to uniq-ify it. CC = MYCOL[UNIQ(MYCOL, SORT(MYCOL))] NC = N_ELEMENTS(CC);; Find the position of the first byte of the data array in the file.; OFFSET0 = NHEADER[ILUN] + NAXIS1[ILUN]*(ROW1-1) POS = 0L NROWS0 = NROWS J = 0L ;; Here, we constrain the buffer to be at least 16 rows long. ;; If we fill up 32 kB with fewer than 16 rows, then there ;; must be a lot of (big) columns in this table. It's ;; probably a candidate for using FXBREAD instead. BUFFROWS = LONG((BUFFERSIZE/NAXIS1[ILUN]) > 16L) IF BUFFERSIZE LE 0 THEN BUFFROWS = NROWS0;; Loop through the data in chunks; WHILE NROWS GT 0 DO BEGIN J = J + 1 NR = NROWS < BUFFROWS OFFSET1 = NAXIS1[ILUN]*POS;; Proceed by reading a byte array from the input data file; FXBREADM reads all columns from the specified rows, and; sorts out the details of which bytes belong to which columns; in the next FOR loop.; BB = BYTARR(NAXIS1[ILUN], NR); If *all* columns are being filled, then there is no reason to ; read from the file IF NC LT TFIELDS[ILUN] THEN BEGIN POINT_LUN,UNIT,OFFSET0+OFFSET1 READU, UNIT, BB ENDIF;; Now select out the desired columns to write; FOR I = 0, NUMCOLS-1 DO BEGIN IF NOT FOUND[I] THEN GOTO, LOOP_END_WRITE ;; Copy data into DD IF PASS EQ 'ARGUMENT' THEN BEGIN RESULT = EXECUTE('DD = '+COLNAMES[I]) IF RESULT EQ 0 THEN GOTO, LOOP_END_WRITE ENDIF ELSE DD = *(POINTERS[I]); ENDIF IF N_ELEMENTS(DD) EQ 1 THEN DD = [DD] DD = REFORM(DD, NOUTPUT[I]/NROWS0, NROWS0, /OVERWRITE) IF POS GT 0 OR NR LT NROWS0 THEN $ DD = DD[*,POS:(POS+NR-1)] ;; Now any conversions to FITS format must be done COUNT = 0L CT = COLTYPE[I] ;; Perform data scaling, if scaling values are available IF NOT KEYWORD_SET(NOSCALE) THEN BEGIN TSCAL1 = TSCAL[ICOL[I],ILUN] TZERO1 = TZERO[ICOL[I],ILUN] IF TSCAL1 EQ 0 THEN TSCAL1 = 1 ;; Handle special unsigned cases IF TZERO1 EQ 32768 AND TSCAL1 EQ 1 AND CT EQ 2 THEN $ ;; Unsigned integer DD = UINT(DD) - UINT(TZERO1) $ ELSE IF TZERO1 EQ 2147483648D AND TSCAL1 EQ 1 AND CT EQ 3 THEN $ ;; Unsigned long integer DD = ULONG(DD) - ULONG(TZERO1) $ ELSE IF TZERO1 NE 0 THEN DD = DD - TZERO1 IF TSCAL1 NE 1 THEN DD = DD / TSCAL1 ENDIF SZ = SIZE(DD) TP = SZ[SZ[0]+1] CASE 1 OF ;; Integer types (CT EQ 1): BEGIN ;; Type-cast may be needed if we used TSCAL/TZERO IF TP NE 1 THEN DD = BYTE(DD) END (CT EQ 2): BEGIN ;; Type-cast may be needed if we used TSCAL/TZERO IF TP NE 2 THEN DD = FIX(DD) IF NOT KEYWORD_SET(NOIEEE) THEN $ SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE END (CT EQ 3): BEGIN ;; Type-cast may be needed if we used TSCAL/TZERO IF TP NE 3 THEN DD = LONG(DD) IF NOT KEYWORD_SET(NOIEEE) THEN $ SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE END (ct eq 14): begin ;; Type-cast may be needed if we used TSCAL/TZERO IF TP NE 14 THEN DD = LONG(DD) IF NOT KEYWORD_SET(NOIEEE) THEN $ SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE end ;; Floating and complex types (CT GE 4 AND CT LE 6 OR CT EQ 9): BEGIN IF NOT KEYWORD_SET(NOIEEE) THEN BEGIN IF N_ELEMENTS(NANVALUE) EQ 1 THEN BEGIN W=WHERE(DD EQ NANVALUE,COUNT) NAN = REPLICATE('FF'XB,16) NAN = CALL_FUNCTION(DTYPENAMES,NAN,0,1) ENDIF SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE IF COUNT GT 0 THEN DD[W] = NAN ENDIF END ;; String type, needs to be padded with spaces (CT EQ 7): BEGIN N_CHAR = N_DIMS[1,ICOL[I],ILUN] ;; Largest string determines size of array MAXLEN = MAX(STRLEN(DD)) > 1 ;; Convert to bytes DD = BYTE(TEMPORARY(DD)) IF N_ELEMENTS(DD) EQ 1 THEN DD = [DD] DD = REFORM(DD, MAXLEN, NR, /OVERWRITE) ;; Put it into the output array IF MAXLEN GT N_CHAR THEN BEGIN DD = DD[0:(N_CHAR-1),*] ENDIF ELSE BEGIN DB = BYTARR(N_CHAR, NR) DB[0:(MAXLEN-1),*] = TEMPORARY(DD) DD = TEMPORARY(DB) ENDELSE ;; Pad any zeroes with spaces WB = WHERE(DD EQ 0b, WCOUNT) IF WCOUNT GT 0 THEN DD[WB] = 32B ;; Pretend that it is a byte array CT = 1 END ENDCASE IF CT NE 1 THEN $ DD = BYTE(TEMPORARY(DD),0,(BOFF2[I]-BOFF1[I]+1),NR) IF N_ELEMENTS(DD) EQ 1 THEN DD = [DD] DD = REFORM(DD, BOFF2[I]-BOFF1[I]+1, NR, /OVERWRITE) ;; Now place the data into the byte array BB[BOFF1[I],0] = DD OUTSTATUS[I] = 1 LOOP_END_WRITE: END ;; Finally, write byte array to output file POINT_LUN, UNIT, OFFSET0+OFFSET1 BB = REFORM(BB, N_ELEMENTS(BB), /OVERWRITE) WRITEU, UNIT, BB NROWS = NROWS - NR POS = POS + NR ENDWHILE; IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = '' RETURN END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -