ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/flatfield/pzt_flat_IDL/mrdfits.pro
Revision: 1.1
Committed: Tue Feb 22 04:26:53 2011 UTC (12 years, 7 months ago) by richard
Branch: MAIN
CVS Tags: Ver_6-0, Ver_6-1, Ver_6-2, Ver_6-3, Ver_6-4, Ver_9-1, Ver_5-14, Ver_5-13, Ver_LATEST, Ver_9-3, Ver_9-41, Ver_9-2, Ver_8-8, Ver_8-2, Ver_8-3, Ver_8-0, Ver_8-1, Ver_8-6, Ver_8-7, Ver_8-4, Ver_8-5, Ver_7-1, Ver_7-0, Ver_9-5, Ver_9-4, Ver_8-10, Ver_8-11, Ver_8-12, Ver_9-0, HEAD
Log Message:
2011.02.21
fixed issues with fits library.

File Contents

# Content
1 ;+
2 ; NAME:
3 ; MRDFITS
4 ;
5 ; PURPOSE:
6 ; Read all standard FITS data types into arrays or structures.
7 ;
8 ; EXPLANATION:
9 ; Further information on MRDFITS is available at
10 ; http://idlastro.gsfc.nasa.gov/mrdfits.html
11 ;
12 ; CALLING SEQUENCE:
13 ; Result = MRDFITS( Filename/FileUnit,[Exten_no/Exten_name, Header],
14 ; /FSCALE , /DSCALE , /UNSIGNED,
15 ; ALIAS=strarr[2,n], /USE_COLNUM,
16 ; /NO_TDIM, ROWS = [a,b,...], $
17 ; /POINTER_VAR, /FIXED_VAR, EXTNUM=
18 ; RANGE=[a,b], COLUMNS=[a,b,...]), ERROR_ACTION=x,
19 ; COMPRESS=comp_prog, STATUS=status, /VERSION )
20 ;
21 ; INPUTS:
22 ; Filename = String containing the name of the file to be read or
23 ; file number of an open unit. If a unit is specified
24 ; if will be left open positioned to read the next HDU.
25 ; If the file name ends in .gz (or .Z on Unix systems)
26 ; the file will be dynamically decompressed.
27 ; FiluUnit = An integer file unit which has already been
28 ; opened for input. Data will be read from this
29 ; unit and the unit will be left pointing immediately
30 ; after the HDU that is read. Thus to read a compressed
31 ; file with many HDU's a user might do something like:
32 ; lun=fxposit(filename, 3) ; Skip the first three HDU's
33 ; repeat begin
34 ; thisHDU = mrdfits(lun, 0, hdr, status=status)
35 ; ... process the HDU ...
36 ; endrep until status lt 0
37 ;
38 ; Exten_no= Extension number to be read, 0 for primary array.
39 ; Assumed 0 if not specified.
40 ; If a unit rather than a filename
41 ; is specified in the first argument, this is
42 ; the number of HDU's to skip from the current position.
43 ; Exten_name - Name of the extension to read (as stored in the EXTNAME
44 ; keyword). This is a slightly slower method then specifying
45 ; the extension number.
46 ; OUTPUTS:
47 ; Result = FITS data array or structure constructed from
48 ; the designated extension. The format of result depends
49 ; upon the type of FITS data read.
50 ; Non-group primary array or IMAGE extension:
51 ; A simple multidimensional array is returned with the
52 ; dimensions given in the NAXISn keywords.
53 ; Grouped image data with PCOUNT=0.
54 ; As above but with GCOUNT treated as NAXIS(n+1).
55 ; Grouped image data with PCOUNT>0.
56 ; The data is returned as an array of structures. Each
57 ; structure has two elements. The first is a one-dimensional
58 ; array of the group parameters, the second is a multidimensional
59 ; array as given by the NAXIS2-n keywords.
60 ; ASCII and BINARY tables.
61 ; The data is returned as a structure with one column for
62 ; each field in the table. The names of the columns are
63 ; normally taken from the TTYPE keywords (but see USE_COLNUM).
64 ; Bit field columns
65 ; are stored in byte arrays of the minimum necessary
66 ; length. Spaces and invalid characters are replaced by
67 ; underscores, and other invalid tag names are converted using
68 ; the IDL_VALIDNAME(/CONVERT_ALL) function.
69 ; Columns specified as variable length columns are stored
70 ; with a dimension equal to the largest actual dimension
71 ; used. Extra values in rows are filled with 0's or blanks.
72 ; If the size of the variable length column is not
73 ; a constant, then an additional column is created giving the
74 ; size used in the current row. This additional column will
75 ; have a tag name of the form L#_"colname" where # is the column
76 ; number and colname is the column name of the variable length
77 ; column. If the length of each element of a variable length
78 ; column is 0 then the column is deleted.
79 ;
80 ;
81 ; OPTIONAL OUTPUT:
82 ; Header = String array containing the header from the FITS extension.
83 ;
84 ; OPTIONAL INPUT KEYWORDS:
85 ; ALIAS The keyword allows the user to specify the column names
86 ; to be created when reading FITS data. The value of
87 ; this keyword should be a 2xn string array. The first
88 ; value of each pair of strings should be the desired
89 ; tag name for the IDL column. The second should be
90 ; the FITS TTYPE value. Note that there are restrictions
91 ; on valid tag names. The order of the ALIAS keyword
92 ; is compatible with MWRFITS.
93 ; COLUMNS - This keyword allows the user to specify that only a
94 ; subset of columns is to be returned. The columns
95 ; may be specified either as number 1,... n or by
96 ; name or some combination of these two.
97 ; If USE_COLNUM is specified names should be C1,...Cn.
98 ; The use of this keyword will not save time or internal
99 ; memory since the extraction of specified columns
100 ; is done after all columns have been retrieved from the
101 ; FITS file.
102 ; COMPRESS - This keyword allows the user to specify a
103 ; decompression program to use to decompress a file that
104 ; will not be automatically recognized based upon
105 ; the file name.
106 ; /DSCALE - As with FSCALE except that the resulting data is
107 ; stored in doubles.
108 ; ERROR_ACTION - Set the on_error action to this value (defaults
109 ; to 2).
110 ; /FIXED_VAR- Translate variable length columns into fixed length columns
111 ; and provide a length column for truly varying columns.
112 ; This was only behavior prior to V2.5 for MRDFITS and remains
113 ; the default (see /POINTER_VAR)
114 ; /FSCALE - If present and non-zero then scale data to float
115 ; numbers for arrays and columns which have either
116 ; non-zero offset or non-unity scale.
117 ; If scaling parameters are applied, then the corresponding
118 ; FITS scaling keywords will be modified.
119 ; NO_TDIM - Disable processing of TDIM keywords. If NO_TDIM
120 ; is specified MRDFITS will ignore TDIM keywords in
121 ; binary tables.
122 ; /POINTER_VAR- Use pointer arrays for variable length columns.
123 ; In addition to changing the format in which
124 ; variable length arrays are stored, if the pointer_var
125 ; keyword is set to any value other than 1 this also disables
126 ; the deletion of variable length columns. (See /FIXED_VAR)
127 ; Note that because pointers may be present in the output
128 ; structure, the user is responsible for memory management
129 ; when deleting or reassigning the structure (e.g. use HEAP_FREE
130 ; first).
131 ; RANGE - A scalar or two element vector giving the start
132 ; and end rows to be retrieved. For ASCII and BINARY
133 ; tables this specifies the row number. For GROUPed data
134 ; this will specify the groups. For array images, this
135 ; refers to the last non-unity index in the array. E.g.,
136 ; for a 3 D image with NAXIS* values = [100,100,1], the
137 ; range may be specified as 0:99, since the last axis
138 ; is suppressed. Note that the range uses IDL indexing
139 ; So that the first row is row 0.
140 ; If only a single value, x, is given in the range,
141 ; the range is assumed to be [0,x-1].
142 ; ROWS - A scalar or vector specifying a specific row or rows to read
143 ; (first row is 0). For example to read rows 0,
144 ; 12 and 23 only, set ROWS=[0,12,23]. Valid for images, ASCII
145 ; and binary tables, but not GROUPed data. For images
146 ; the row numbers refer to the last non-unity index in the array.
147 ; Cannot be used at the same time as the RANGE keyword
148 ; /SILENT - Suppress informative messages.
149 ; STRUCTYP - The structyp keyword specifies the name to be used
150 ; for the structure defined when reading ASCII or binary
151 ; tables. Generally users will not be able to conveniently
152 ; combine data from multiple files unless the STRUCTYP
153 ; parameter is specified. An error will occur if the
154 ; user specifies the same value for the STRUCTYP keyword
155 ; in calls to MRDFITS in the same IDL session for extensions
156 ; which have different structures.
157 ; /UNSIGNED - For integer data with appropriate zero points and scales
158 ; read the data into unsigned integer arrays.
159 ; /USE_COLNUM - When creating column names for binary and ASCII tables
160 ; MRDFITS attempts to use the appropriate TTYPE keyword
161 ; values. If USE_COLNUM is specified and non-zero then
162 ; column names will be generated as 'C1, C2, ... 'Cn'
163 ; for the number of columns in the table.
164 ; /VERSION Print the current version number
165 ;
166 ; OPTIONAL OUTPUT KEYWORDS:
167 ; EXTNUM - the number of the extension actually read. Useful if the
168 ; user specified the extension by name.
169 ; OUTALIAS - This is a 2xn string array where the first column gives the
170 ; actual structure tagname, and the second gives the
171 ; corresponding FITS keyword name (e.g. in the TTYPE keyword).
172 ; This array can be passed directly to
173 ; the alias keyword of MWRFITS to recreate the file originally
174 ; read by MRDFITS.
175 ; STATUS - A integer status indicating success or failure of
176 ; the request. A status of >=0 indicates a successful read.
177 ; Currently
178 ; 0 -> successful completion
179 ; -1 -> error
180 ; -2 -> end of file
181 ;
182 ; EXAMPLES:
183 ; (1) Read a FITS primary array:
184 ; a = mrdfits('TEST.FITS') or
185 ; a = mrdfits('TEST.FITS', 0, header)
186 ; The second example also retrieves header information.
187 ;
188 ; (2) Read rows 10-100 of the second extension of a FITS file.
189 ; a = mrdfits('TEST.FITS', 2, header, range=[10,100])
190 ;
191 ; (3) Read a table and ask that any scalings be applied and the
192 ; scaled data be converted to doubles. Use simple column names,
193 ; suppress outputs.
194 ; a = mrdfits('TEST.FITS', 1, /dscale, /use_colnum, /silent)
195 ;
196 ; (4) Read rows 3, 34 and 52 of a binary table and request that
197 ; variable length columns be stored as a pointer variable in the
198 ; output structure
199 ; a = mrdfits('TEST.FITS',1,rows=[3,34,52],/POINTER)
200
201 ; RESTRICTIONS:
202 ; (1) Cannot handle data in non-standard FITS formats.
203 ; (2) Doesn't do anything with BLANK or NULL values or
204 ; NaN's. They are just read in. They may be scaled
205 ; if scaling is applied.
206 ; NOTES:
207 ; This multiple format FITS reader is designed to provide a
208 ; single, simple interface to reading all common types of FITS data.
209 ; MRDFITS DOES NOT scale data by default. The FSCALE or DSCALE
210 ; parameters must be used.
211 ;
212 ; MRDFITS support 64 bit integer data types, which are tentatively
213 ; included in the FITS standard.
214 ; http://fits.gsfc.nasa.gov/fits_64bit.html
215 ;
216 ;
217 ; PROCEDURES USED:
218 ; The following procedures are contained in the main MRDFITS program.
219 ; MRD_IMAGE -- Generate array/structure for images.
220 ; MRD_READ_IMAGE -- Read image data.
221 ; MRD_ASCII -- Generate structure for ASCII tables.
222 ; MRD_READ_ASCII -- Read an ASCII table.
223 ; MRD_TABLE -- Generate structure for Binary tables.
224 ; MRD_READ_TABLE -- Read binary table info.
225 ; MRD_READ_HEAP -- Read variable length record info.
226 ; MRD_SCALE -- Apply scaling to data.
227 ; MRD_COLUMNS -- Extract columns.
228 ;
229 ; Other ASTRON Library routines used
230 ; FXPAR(), FXADDPAR, FXPOSIT, FXMOVE(), MRD_STRUCT(), MRD_SKIP,
231 ;
232 ; MODIfICATION HISTORY:
233 ; V1.0 November 9, 1994 ---- Initial release.
234 ; Creator: Thomas A. McGlynn
235 ; V1.1 January 20, 1995 T.A. McGlynn
236 ; Fixed bug in variable length records.
237 ; Added TDIM support -- new routine mrd_tdim in MRD_TABLE.
238 ; V1.2
239 ; Added support for dynamic decompression of files.
240 ; Fixed further bugs in variable length record handling.
241 ; V1.2a
242 ; Added NO_TDIM keyword to turn off TDIM processing for
243 ; those who don't want it.
244 ; Bug fixes: Handle one row tables correctly, use BZERO rather than
245 ; BOFFSET. Fix error in scaling of images.
246 ; V1.2b
247 ; Changed MRD_HREAD to handle null characters in headers.
248 ; V2.0 April 1, 1996
249 ; -Handles FITS tables with an arbitrary number of columns.
250 ; -Substantial changes to MRD_STRUCT to allow the use of
251 ; substructures when more than 127 columns are desired.
252 ; -All references to table columns are now made through the
253 ; functions MRD_GETC and MRD_PUTC. See description above.
254 ; -Use of SILENT will now eliminate compilation messages for
255 ; temporary functions.
256 ; -Bugs in handling of variable length columns with either
257 ; a single row in the table or a maximum of a single element
258 ; in the column fixed.
259 ; -Added support for DCOMPLEX numbers in binary tables (M formats) for
260 ; IDL versions above 4.0.
261 ; -Created regression test procedure to check in new versions.
262 ; -Added error_action parameter to allow user to specify
263 ; on_error action. This should allow better interaction with
264 ; new CHECK facility. ON_ERROR statements deleted from
265 ; most called routines.
266 ; - Modified MRDFITS to read in headers containing null characters
267 ; with a warning message printed.
268 ; V2.0a April 16, 1996
269 ; - Added IS_IEEE_BIG() checks (and routine) so that we don't
270 ; worry about IEEE to host conversions if the machine's native
271 ; format is IEEE Big-endian.
272 ; V2.1 August 24, 1996
273 ; - Use resolve_routine for dynamically defined functions
274 ; for versions > 4.0
275 ; - Fix some processing in random groups format.
276 ; - Handle cases where the data segment is--legally--null.
277 ; In this case MRDFITS returns a scalar 0.
278 ; - Fix bugs with the values for BSCALE and BZERO (and PSCAL and
279 ; PZERO) parameters set by MRDFITS.
280 ; V2.1a April 24, 1997 Handle binary tables with zero length columns
281 ; V2.1b May 13,1997 Remove whitespace from replicate structure definition
282 ; V2.1c May 28,1997 Less strict parsing of XTENSION keyword
283 ; V2.1d June 16, 1997 Fixed problem for >32767 entries introduced 24-Apr
284 ; V2.1e Aug 12, 1997 Fixed problem handling double complex arrays
285 ; V2.1f Oct 22, 1997 IDL reserved words can't be structure tag names
286 ; V2.1g Nov 24, 1997 Handle XTENSION keywords with extra blanks.
287 ; V2.1h Jul 26, 1998 More flexible parsing of TFORM characters
288 ; V2.2 Dec 14, 1998 Allow fields with longer names for
289 ; later versions of IDL.
290 ; Fix handling of arrays in scaling routines.
291 ; Allow >128 fields in structures for IDL >4.0
292 ; Use more efficient structure copying for
293 ; IDL>5.0
294 ; V2.2b June 17, 1999 Fix bug in handling case where
295 ; all variable length columns are deleted
296 ; because they are empty.
297 ; V2.3 March 7, 2000 Allow user to supply file handle rather
298 ; than file name.
299 ; Added status field.
300 ; Now needs FXMOVE routine
301 ; V2.3b April 4, 2000
302 ; Added compress option (from D. Palmer)
303 ; V2.4 July 4, 2000 Added STATUS=-1 for "File access error" (Zarro/GSFC)
304 ; V2.4a May 2, 2001 Trim binary format string (W. Landsman)
305 ; V2.5 December 5, 2001 Add unsigned, alias, 64 bit integers. version, $
306 ; /pointer_val, /fixed_var.
307 ; V2.5a Fix problem when both the first and the last character
308 ; in a TTYPEnn value are invalid structure tag characters
309 ; V2.6 February 15, 2002 Fix error in handling unsigned numbers, $
310 ; and 64 bit unsigneds. (Thanks to Stephane Beland)
311 ; V2.6a September 2, 2002 Fix possible conflicting data structure for
312 ; variable length arrays (W. Landsman)
313 ; V2.7 July, 2003 Added Rows keyword (W. Landsman)
314 ; V2.7a September 2003 Convert dimensions to long64 to handle huge files
315 ; V2.8 October 2003 Use IDL_VALIDNAME() function to ensure valid tag names
316 ; Removed OLD_STRUCT and TEMPDIR keywords W. Landsman
317 ; V2.9 February 2004 Added internal MRD_FXPAR procedure for faster
318 ; processing of binary table headers E. Sheldon
319 ; V2.9a March 2004 Restore ability to read empty binary table W. Landsman
320 ; Swallow binary tables with more columns than given in TFIELDS
321 ; V2.9b Fix to ensure order of TFORMn doesn't matter
322 ; V2.9c Check if extra degenerate NAXISn keyword are present W.L. Oct 2004
323 ; V2.9d Propagate /SILENT to MRD_HREAD, more LONG64 casting W. L. Dec 2004
324 ; V2.9e Add typarr[good] to fix a problem reading zero-length columns
325 ; A.Csillaghy, csillag@ssl.berkeley.edu (RHESSI)
326 ; V2.9f Fix problem with string variable binary tables, possible math
327 ; overflow on non-IEEE machines WL Feb. 2005
328 ; V2.9g Fix problem when setting /USE_COLNUM WL Feb. 2005
329 ; V2.10 Use faster keywords to BYTEORDER WL May 2006
330 ; V2.11 Add ON_IOERROR, CATCH, and STATUS keyword to MRD_READ_IMAGE to
331 ; trap EOF in compressed files DZ Also fix handling of unsigned
332 ; images when BSCALE not present K Chu/WL June 2006
333 ; V2.12 Allow extension to be specified by name, added EXTNUM keyword
334 ; WL December 2006
335 ; V2.12a Convert ASCII table column to DOUBLE if single precision is
336 ; insufficient
337 ; V2.12b Fixed problem when both /fscale and /unsigned are set
338 ; C. Markwardt Aug 2007
339 ; V2.13 Use SWAP_ENDIAN_INPLACE instead of IEEE_TO_HOST and IS_IEEE_BIG
340 ; W. Landsman Nov 2007
341 ; V2.13a One element vector allowed for file name W.L. Dec 2007
342 ; V2.13b More informative error message when EOF found W.L. Jun 2008
343 ; V2.14 Use vector form of VALID_NUM(), added OUTALIAS keyword
344 ; W.L. Aug 2008
345 ;-
346 PRO mrd_fxpar, hdr, xten, nfld, nrow, rsize, fnames, fforms, scales, offsets
347 ;
348 ; Check for valid header. Check header for proper attributes.
349 ;
350 S = SIZE(HDR)
351 IF ( S[0] NE 1 ) OR ( S[2] NE 7 ) THEN $
352 MESSAGE,'FITS Header (first parameter) must be a string array'
353
354 xten = fxpar(hdr, 'XTENSION')
355 nfld = fxpar(hdr, 'TFIELDS')
356 nrow = long64(fxpar(hdr, 'NAXIS2'))
357 rsize = long64(fxpar(hdr, 'NAXIS1'))
358
359 ;; will extract these for each
360 names = ['TTYPE','TFORM', 'TSCAL', 'TZERO']
361 nnames = n_elements(names)
362
363 ; Start by looking for the required TFORM keywords. Then try to extract it
364 ; along with names (TTYPE), scales (TSCAL), and offsets (TZERO)
365
366 keyword = STRMID( hdr, 0, 8)
367
368 ;
369 ; Find all instances of 'TFORM' followed by
370 ; a number. Store the positions of the located keywords in mforms, and the
371 ; value of the number field in n_mforms
372 ;
373
374 mforms = WHERE(STRPOS(keyword,'TFORM') GE 0, n_mforms)
375 if n_mforms GT nfld then begin
376 message,/CON, $
377 'WARNING - More columns found in binary table than specified in TFIELDS'
378 n_mforms = nfld
379 mforms = mforms[0:nfld-1]
380 endif
381
382
383 IF ( n_mforms GT 0 ) THEN BEGIN
384 numst= STRMID(hdr[mforms], 5 ,3)
385
386 igood = WHERE(VALID_NUM(numst,/INTEGER), n_mforms)
387 IF n_mforms GT 0 THEN BEGIN
388 mforms = mforms[igood]
389 number = fix( numst[igood])
390 numst = numst[igood]
391 ENDIF
392
393 ENDIF ELSE RETURN ;No fields in binary table
394
395 ;; The others
396 fnames = strarr(n_mforms)
397 fforms = strarr(n_mforms)
398 scales = dblarr(n_mforms)
399 offsets = dblarr(n_mforms)
400
401 ;;comments = strarr(n_mnames)
402
403 fnames_names = 'TTYPE'+numst
404 scales_names = 'TSCAL'+numst
405 offsets_names = 'TZERO'+numst
406 number = number -1 ;Make zero-based
407
408
409 match, keyword, fnames_names, mkey_names, mnames, count = N_mnames
410
411 match, keyword, scales_names, mkey_scales, mscales, count = N_mscales
412
413 match, keyword, offsets_names, mkey_offsets, moffsets,count = N_moffsets
414
415 FOR in=0L, nnames-1 DO BEGIN
416
417 CASE names[in] OF
418 'TTYPE': BEGIN
419 tmatches = mnames
420 matches = mkey_names
421 nmatches = n_mnames
422 result = fnames
423 END
424 'TFORM': BEGIN
425 tmatches = lindgen(n_mforms)
426 matches = mforms
427 nmatches = n_mforms
428 result = fforms
429 END
430 'TSCAL': BEGIN
431 tmatches = mscales
432 matches = mkey_scales
433 nmatches = n_mscales
434 result = scales
435 END
436 'TZERO': BEGIN
437 tmatches = moffsets
438 matches = mkey_offsets
439 nmatches = n_moffsets
440 result = offsets
441 END
442 ELSE: message,'What?'
443 ENDCASE
444
445 ;;help,matches,nmatches
446
447 ;
448 ; Extract the parameter field from the specified header lines. If one of the
449 ; special cases, then done.
450 ;
451 IF nmatches GT 0 THEN BEGIN
452
453 ;; "matches" is a subscript for hdr and keyword.
454 ;; get just the matches in line
455
456 line = hdr[matches]
457 svalue = STRTRIM( STRMID(line,9,71),2)
458
459 FOR i = 0, nmatches-1 DO BEGIN
460 IF ( STRMID(svalue[i],0,1) EQ "'" ) THEN BEGIN
461
462 ;; Its a string
463 test = STRMID( svalue[i],1,STRLEN( svalue[i] )-1)
464 next_char = 0
465 off = 0
466 value = ''
467 ;
468 ; Find the next apostrophe.
469 ;
470 NEXT_APOST:
471 endap = STRPOS(test, "'", next_char)
472 IF endap LT 0 THEN MESSAGE, $
473 'WARNING: Value of '+nam+' invalid in '+ " (no trailing ')", /info
474 value = value + STRMID( test, next_char, endap-next_char )
475 ;
476 ; Test to see if the next character is also an apostrophe. If so, then the
477 ; string isn't completed yet. Apostrophes in the text string are signalled as
478 ; two apostrophes in a row.
479 ;
480 IF STRMID( test, endap+1, 1) EQ "'" THEN BEGIN
481 value = value + "'"
482 next_char = endap+2
483 GOTO, NEXT_APOST
484 ENDIF
485
486
487 ;
488 ; If not a string, then separate the parameter field from the comment field.
489 ;
490 ENDIF ELSE BEGIN
491 ;; not a string
492 test = svalue[I]
493 slash = STRPOS(test, "/")
494 IF slash GT 0 THEN test = STRMID(test, 0, slash)
495
496 ;
497 ; Find the first word in TEST. Is it a logical value ('T' or 'F')?
498 ;
499 test2 = test
500 value = GETTOK(test2,' ')
501 test2 = STRTRIM(test2,2)
502 IF ( value EQ 'T' ) THEN BEGIN
503 value = 1
504 END ELSE IF ( value EQ 'F' ) THEN BEGIN
505 value = 0
506 END ELSE BEGIN
507 ;
508 ; Test to see if a complex number. It's a complex number if the value and the
509 ; next word, if any, both are valid numbers.
510 ;
511 IF STRLEN(test2) EQ 0 THEN GOTO, NOT_COMPLEX
512 test2 = GETTOK(test2,' ')
513 IF VALID_NUM(value,val1) AND VALID_NUM(value2,val2) $
514 THEN BEGIN
515 value = COMPLEX(val1,val2)
516 GOTO, GOT_VALUE
517 ENDIF
518 ;
519 ; Not a complex number. Decide if it is a floating point, double precision,
520 ; or integer number. If an error occurs, then a string value is returned.
521 ; If the integer is not within the range of a valid long value, then it will
522 ; be converted to a double.
523 ;
524 NOT_COMPLEX:
525 ON_IOERROR, GOT_VALUE
526 value = test
527 IF NOT VALID_NUM(value) THEN GOTO, GOT_VALUE
528
529 IF (STRPOS(value,'.') GE 0) OR (STRPOS(value,'E') $
530 GE 0) OR (STRPOS(value,'D') GE 0) THEN BEGIN
531 IF ( STRPOS(value,'D') GT 0 ) OR $
532 ( STRLEN(value) GE 8 ) THEN BEGIN
533 value = DOUBLE(value)
534 END ELSE value = FLOAT(value)
535 ENDIF ELSE BEGIN
536 lmax = long64(2)^31 - 1
537 lmin = -long64(2)^31
538 value = long64(value)
539 if (value GE lmin) and (value LE lmax) THEN $
540 value = LONG(value)
541 ENDELSE
542
543 ;
544 GOT_VALUE:
545 ON_IOERROR, NULL
546 ENDELSE
547 ENDELSE ; if string
548 ;
549 ; Add to vector if required.
550 ;
551
552 result[tmatches[i]] = value
553
554 ENDFOR
555
556 CASE names[in] OF
557 'TTYPE': fnames[number] = strtrim(result, 2)
558 'TFORM': fforms[number] = strtrim(result, 2)
559 'TSCAL': scales[number] = result
560 'TZERO': offsets[number] = result
561 ELSE: message,'What?'
562 ENDCASE
563
564 ;
565 ; Error point for keyword not found.
566 ;
567 ENDIF
568 ;
569
570
571
572 ENDFOR
573 END
574
575
576 ; Get a tag name give the column name and index
577 function mrd_dofn, name, index, use_colnum, alias=alias
578
579 ; Check if the user has specified an alias.
580
581 if n_elements(name) eq 0 then name = 'C'+strtrim(index, 2)
582 name = strtrim(name)
583 if keyword_set(alias) then begin
584 sz = size(alias)
585
586 if (sz[0] eq 1 or sz[0] eq 2) and sz[1] eq 2 and sz[sz[0]+1] eq 7 then begin
587 w=where(name eq alias[1,*])
588 if (w[0] ne -1) then begin
589 name = alias[0,w[0]];
590 endif
591 endif
592 endif
593 ; Convert the string name to a valid variable name. If name
594 ; is not defined generate the string Cnn when nn is the index
595 ; number.
596
597 table = 0
598 sz = size(name)
599 nsz = n_elements(sz)
600 if not use_colnum and (sz[nsz-2] ne 0) then begin
601 if sz[nsz-2] eq 7 then begin
602 str = name[0]
603 endif else begin
604 str = 'C'+strtrim(index,2)
605 endelse
606 endif else begin
607 str = 'C'+strtrim(index,2)
608 endelse
609
610 return, IDL_VALIDNAME(str,/CONVERT_ALL)
611
612 end
613
614 ;***************************************************************
615
616
617
618 ; Parse the TFORM keyword and return the type and dimension of the
619 ; data.
620 pro mrd_doff, form, dim, type
621
622 ; Find the first non-numeric character.
623
624 len = strlen(form)
625
626 if len le 0 then return
627
628 for i=0, len-1 do begin
629
630 c = strmid(form, i, 1)
631 if c lt '0' or c gt '9' then goto, not_number
632
633 endfor
634
635 not_number:
636
637 if i ge len then return ;Modified from len-1 on 26-Jul-1998
638
639 if i gt 0 then begin
640 dim = long(strmid(form, 0, i))
641 if dim EQ 0l then dim = -1l
642 endif else begin
643 dim = 0
644 endelse
645
646 type = strmid(form, i, 1)
647 end
648
649
650
651 ;*********************************************************************
652
653 ; Check that this name is unique with regard to other column names.
654
655 function mrd_chkfn, name, namelist, index
656
657 ;
658 ;
659
660 maxlen = 127
661
662 if strlen(name) gt maxlen then name = strmid(name, 0, maxlen)
663 w = where(name eq strmid(namelist, 0, maxlen) )
664 if w[0] ne -1 then begin
665 ; We have found a name conflict.
666 ;
667 name = 'gen$name_'+strcompress(string(index+1),/remove_all)
668 endif
669
670 return, name
671
672 end
673
674 ; Find the appropriate offset for a given unsigned type.
675 ; The type may be given as the bitpix value or the IDL
676 ; variable type.
677
678 function mrd_unsigned_offset, type
679
680 if (type eq 12 or type eq 16) then begin
681 return, uint(32768)
682 endif else if (type eq 13 or type eq 32) then begin
683 return, ulong('2147483648')
684 endif else if (type eq 15 or type eq 64) then begin
685 return, ulong64('9223372036854775808');
686 endif
687 return, 0
688 end
689
690
691
692 ; Can we treat this data as unsigned?
693
694 function mrd_chkunsigned, bitpix, scale, zero, unsigned=unsigned
695
696 if not keyword_set(unsigned) then return, 0
697
698 ; This is correct but we should note that
699 ; FXPAR returns a double rather than a long.
700 ; Since the offset is a power of two
701 ; it is an integer that is exactly representable
702 ; as a double. However, if a user were to use
703 ; 64 bit integers and an offset close to but not
704 ; equal to 2^63, we would erroneously assume that
705 ; the dataset was unsigned...
706
707
708 if scale eq 1 then begin
709 if (bitpix eq 16 and zero eq 32768L) or $
710 (bitpix eq 32 and zero eq ulong('2147483648')) or $
711 (bitpix eq 64 and zero eq ulong64('9223372036854775808')) then begin
712 return, 1
713 endif
714 endif
715 return, 0
716 end
717
718 ; Is this one of the IDL unsigned types?
719 function mrd_unsignedtype, data
720
721 type = size(data,/ type)
722 if (type eq 12) or (type eq 13) or (type eq 15) then return, type $
723 else return, 0
724
725 end
726
727 ; Return the currrent version string for MRDFITS
728 function mrd_version
729 return, '2.14'
730 end
731 ;=====================================================================
732 ; END OF GENERAL UTILITY FUNCTIONS ===================================
733 ;=====================================================================
734
735
736 ; Parse the TFORM keyword and return the type and dimension of the
737 ; data.
738 pro mrd_atype, form, type, slen
739
740
741 ; Find the first non-numeric character.
742
743
744 ; Get rid of blanks.
745 form = strcompress(form,/remove_all)
746 len = strlen(form)
747 if len le 0 then return
748
749 type = strmid(form, 0,1)
750 length = strmid(form,1,len-1)
751 ;
752 ; Ignore the number of decimal places. We assume that there
753 ; is a decimal point.
754 ;
755 p = strpos(length, '.')
756 if p gt 0 then length = strmid(length,0,p)
757
758 if strlen(length) gt 0 then slen = fix(length) else slen = 1
759 if (type EQ 'F') or (type EQ 'E') then $ ;Updated April 2007
760 if (slen GE 8) then type = 'D'
761
762 end
763
764
765 ; Read in the table information.
766 pro mrd_read_ascii, unit, range, nbytes, nrows, nfld, typarr, posarr, $
767 lenarr, nullarr, table, old_struct=old_struct, rows=rows
768
769 ;
770 ; Unit Unit to read data from.
771 ; Range Range of to be read
772 ; Nbytes Number of bytes per row.
773 ; Nrows Number of rows.
774 ; Nfld Number of fields in structure.
775 ; Typarr Array indicating type of variable.
776 ; Posarr Starting position of fields (first char at 0)
777 ; Lenarr Length of fields
778 ; Nullarr Array of null values
779 ; Table Table to read information into.
780 ; Old_struct Should recursive structure format be used?
781
782 bigstr = bytarr(nbytes, range[1]-range[0]+1)
783
784 if range[0] gt 0 then mrd_skip, unit, nbytes*range[0]
785 readu,unit, bigstr
786 if N_elements(rows) GT 0 then bigstr = bigstr[*,rows-range[0]]
787
788 ; Skip to the end of the data area.
789
790 nSkipRow = nrows - range[1] - 1
791 nskipB = 2880 - (nbytes*nrows) mod 2880
792 if nskipB eq 2880 then nskipB = 0
793
794 mrd_skip, unit, nskipRow*nbytes+nskipB
795
796 s1 = posarr-1
797 s2 = s1 + lenarr - 1
798 for i=0, nfld-1 do begin
799
800 flds = strtrim( bigstr[s1[i]:s2[i],* ] )
801
802 if strtrim(nullarr[i]) ne '' then begin
803
804 curr_col = table.(i)
805
806 w = where(flds ne strtrim(nullarr[i]))
807 if w[0] ne -1 then begin
808 if N_elements(w) EQ 1 then w = w[0]
809 if typarr[i] eq 'I' then begin
810 curr_col[w] = long(flds[w])
811 endif else if typarr[i] eq 'E' or typarr[i] eq 'F' then begin
812 curr_col[w] = float(flds[w])
813 endif else if typarr[i] eq 'D' then begin
814 curr_col[w] = double(flds[w])
815 endif else if typarr[i] eq 'A' then begin
816 curr_col[w] = flds[w]
817 endif
818 endif
819
820 table.(i) = curr_col
821
822 endif else begin
823
824
825
826 if typarr[i] eq 'I' then begin
827 table.(i) = long(flds)
828 endif else if typarr[i] eq 'E' or typarr[i] eq 'F' then begin
829 table.(i) = float(flds)
830 endif else if typarr[i] eq 'D' then begin
831 table.(i) = double(flds)
832 endif else if typarr[i] eq 'A' then begin
833 table.(i) = flds
834 endif
835 endelse
836 endfor
837
838 end
839
840
841 ; Define a structure to hold a FITS ASCII table.
842 pro mrd_ascii, header, structyp, use_colnum, $
843 range, table, $
844 nbytes, nrows, nfld, typarr, posarr, lenarr, nullarr, $
845 fnames, fvalues, scales, offsets, scaling, status, rows = rows, $
846 silent=silent, columns=columns, alias=alias, outalias=outalias
847
848 ;
849 ; Header FITS header for table.
850 ; Structyp IDL structure type to be used for
851 ; structure.
852 ; Use_colnum Use column numbers not names.
853 ; Range Range of rows of interest
854 ; Table Structure to be defined.
855 ; Nbytes Bytes per row
856 ; Nrows Number of rows in table
857 ; Nfld Number of fields
858 ; Typarr Array of field types
859 ; Posarr Array of field offsets
860 ; Lenarr Array of field lengths
861 ; Nullarr Array of field null values
862 ; Fname Column names
863 ; Fvalues Formats for columns
864 ; Scales/offsets Scaling factors for columns
865 ; Scaling Do we need to scale?
866 ; Status Return status.
867
868 table = 0
869
870 types = ['I', 'E', 'F', 'D', 'A']
871 sclstr = ['0l', '0.0', '0.0', '0.0d0', ' ']
872 status = 0
873
874 if strmid(fxpar(header, 'XTENSION'),0,8) ne 'TABLE ' then begin
875 message, 'ERROR - Header is not from ASCII table.',/CON
876 status = -1;
877 return
878 endif
879
880 nfld = fxpar(header, 'TFIELDS')
881 nrows = long64( fxpar(header, 'NAXIS2'))
882 nbytes = long64( fxpar(header, 'NAXIS1'))
883
884 if range[0] ge 0 then begin
885 range[0] = range[0] < (nrows-1)
886 range[1] = range[1] < (nrows-1)
887 endif else begin
888 range[0] = 0
889 range[1] = nrows-1
890 endelse
891
892 if N_elements(rows) EQ 0 then nrows = range[1] - range[0] + 1 else begin
893 bad = where(rows GT nrows, Nbad)
894 if Nbad GT 0 then begin
895 message,/CON,'ERROR: Row numbers must be between 0 and ' + $
896 strtrim(nrows-1,2)
897 status = -1
898 return
899 endif
900 nrows = N_elements(rows)
901 endelse
902
903 if nrows le 0 then begin
904 if not keyword_set(silent) then begin
905 print,'MRDFITS: ASCII table. ',strcompress(string(nfld)), $
906 ' columns, no rows'
907 endif
908 return
909 endif
910
911 ;
912 ; Loop over the columns
913
914 typarr = strarr(nfld)
915 lenarr = intarr(nfld)
916 posarr = intarr(nfld)
917 nullarr = strarr(nfld)
918 fnames = strarr(nfld)
919 fvalues = strarr(nfld)
920 scales = dblarr(nfld)
921 offsets = dblarr(nfld)
922 tname = strarr(nfld)
923
924 for i=0, nfld-1 do begin
925 suffix = strcompress(string(i+1), /remove_all)
926 fname = fxpar(header, 'TTYPE' + suffix, count=cnt)
927 tname[i] = fname
928 if cnt eq 0 then xx = temporary(fname)
929 fform = fxpar(header, 'TFORM' + suffix)
930 fpos = fxpar(header, 'TBCOL' + suffix)
931 fnull = fxpar(header, 'TNULL' + suffix, count=cnt)
932 if cnt eq 0 then fnull = ''
933 scales[i] = fxpar(header, 'TSCAL' + suffix)
934 if scales[i] eq 0.0d0 then scales[i] = 1.0d0
935 offsets[i] = fxpar(header, 'TZERO'+suffix)
936
937 fname = mrd_dofn(fname,i+1, use_colnum, alias=alias)
938 fnames[i] = fname
939
940 fname = mrd_chkfn(fname, fnames, i)
941
942 mrd_atype, fform, ftype, flen
943 typarr[i] = ftype
944 lenarr[i] = flen
945 posarr[i] = fpos
946 nullarr[i] = fnull
947
948 for j=0, n_elements(types) - 1 do begin
949 if ftype eq types[j] then begin
950 if ftype ne 'A' then begin
951 val = sclstr[j]
952 endif else begin
953 val = 'string(replicate(32b,'+strtrim(flen,2)+'))'
954 endelse
955
956 fvalues[i] = val
957
958 goto, next_col
959 endif
960 endfor
961
962 print, 'MRDFITS: Invalid format code:',ftype, ' for column ', i+1
963 status = -1
964 return
965 next_col:
966 endfor
967
968 if scaling then begin
969 w = where(scales ne 1.0d0 or offsets ne 0.0d0)
970 if w[0] eq -1 then scaling = 0
971 endif
972
973 if not scaling and not keyword_set(columns) then begin
974 table = mrd_struct(fnames, fvalues, nrows, structyp=structyp, $
975 silent=silent)
976 endif else begin
977 table = mrd_struct(fnames, fvalues, nrows, silent=silent)
978 endelse
979
980 if not keyword_set(silent) then begin
981 print,'MRDFITS: ASCII table. ',strcompress(string(nfld)), $
982 ' columns by ',strcompress(string(nrows)), ' rows.'
983 endif
984
985 outalias = transpose([ [tag_names(table)],[tname] ] )
986 status = 0
987 return
988
989 end
990
991
992 ; Eliminate columns from the table that do not match the
993 ; user specification.
994 pro mrd_columns, table, columns, fnames, fvalues, $
995 vcls, vtpes, scales, offsets, scaling, $
996 structyp=structyp, silent=silent
997
998
999
1000 sz = size(columns)
1001
1002 type = sz[sz[0]+1]
1003 nele = sz[sz[0]+2]
1004 if type eq 8 or type eq 6 or type eq 0 then return ; Can't use structs
1005 ; or complex.
1006
1007 if type eq 4 or type eq 5 then tcols = fix(columns)
1008 if type eq 1 or type eq 2 or type eq 3 then tcols = columns
1009
1010 ; Convert strings to uppercase and compare with column names.
1011
1012 if type eq 7 then begin
1013 for i=0, nele-1 do begin
1014 cname = strupcase(columns[i])
1015 w = where(cname eq strupcase(fnames))
1016 if w[0] ne -1 then begin
1017 if n_elements(tcols) eq 0 then begin
1018 tcols = w[0]+1
1019 endif else begin
1020 tcols = [tcols, w[0]+1]
1021 endelse
1022 endif
1023 endfor
1024 endif
1025
1026 ; Subtract one from column indices and check that all indices >= 0.
1027 if n_elements(tcols) gt 0 then begin
1028 tcols = tcols-1
1029 w = where(tcols ge 0)
1030 if w[0] eq -1 then begin
1031 dummy = temporary(tcols)
1032 endif
1033 endif
1034
1035 if n_elements(tcols) le 0 then begin
1036 print, 'MRDFITS: No columns match'
1037
1038 ; Undefine variables. First ensure they are defined, then
1039 ; use temporary() to undefine them.
1040 table = 0
1041 fnames = 0
1042 fvalues = 0
1043 vcls = 0
1044 vtpes = 0
1045 scales = 0
1046 offsets = 0
1047 dummy = temporary(fnames)
1048 dummy = temporary(fvalues)
1049 dummy = temporary(vcls)
1050 dummy = temporary(vtpes)
1051 dummy = temporary(scales)
1052 dummy = temporary(offsets)
1053 scaling = 0
1054
1055 endif else begin
1056
1057 ; Replace arrays with only desired columns.
1058
1059 fnames = fnames[tcols]
1060 fvalues = fvalues[tcols]
1061
1062 ; Check if there are still variable length columns.
1063 if n_elements(vcls) gt 0 then begin
1064 vcls = vcls[tcols]
1065 vtpes = vtpes[tcols]
1066 w = where(vcls eq 1)
1067 if w[0] eq -1 then begin
1068 dummy = temporary(vcls)
1069 dummy = temporary(vtpes)
1070 endif
1071 endif
1072
1073 ; Check if there are still columns that need scaling.
1074 if n_elements(scales) gt 0 then begin
1075 scales = scales[tcols]
1076 offsets = offsets[tcols]
1077 w = where(scales ne 1.0d0 or offsets ne 0.0d0)
1078 if w[0] eq -1 then scaling = 0
1079 endif
1080
1081
1082 ndim = n_elements(table)
1083
1084 if scaling or n_elements(vcls) gt 0 then begin
1085 tabx = mrd_struct(fnames, fvalues, ndim, silent=silent )
1086 endif else begin
1087 tabx = mrd_struct(fnames, fvalues, ndim, structyp=structyp, silent=silent )
1088 endelse
1089
1090 for i=0, n_elements(tcols)-1 do begin
1091 tabx.(i) = table.(tcols[i]);
1092 endfor
1093
1094 table = tabx
1095 endelse
1096
1097 end
1098
1099
1100 ; Read in the image information.
1101 pro mrd_read_image, unit, range, maxd, rsize, table, rows = rows,status=status
1102
1103 ;
1104 ; Unit Unit to read data from.
1105 ; Table Table/array to read information into.
1106 ;
1107
1108 error=0
1109 catch,error
1110 if error ne 0 then begin
1111 catch,/cancel
1112 status=-2
1113 return
1114 endif
1115
1116 ; If necessary skip to beginning of desired data.
1117
1118 if range[0] gt 0 then mrd_skip, unit, range[0]*rsize
1119
1120 status=-2
1121 if rsize eq 0 then return
1122
1123 on_ioerror,done
1124 readu, unit, table
1125
1126 if N_elements(rows) GT 0 then begin
1127 row1 = rows- range[0]
1128 case size(table,/n_dimen) of
1129 1: table = table[row1]
1130 2: table = table[*,row1]
1131 3: table = table[*,*,row1]
1132 4: table = table[*,*,*,row1]
1133 5: table = table[*,*,*,*,row1]
1134 6: table = table[*,*,*,*,*,row1]
1135 7: table = table[*,*,*,*,*,*,row1]
1136 8: table = table[*,*,*,*,*,*,*,row1]
1137 else: begin
1138 print,'MRDFITS: Subscripted image must be between 1 and 8 dimensions'
1139 status = -1
1140 return
1141 end
1142 endcase
1143 endif
1144
1145 ; Skip to the end of the data
1146
1147 skipB = 2880 - (maxd*rsize) mod 2880
1148 if skipB eq 2880 then skipB = 0
1149
1150 if range[1] lt maxd-1 then begin
1151 skipB = skipB + (maxd-range[1]-1)*rsize
1152 endif
1153
1154 mrd_skip, unit, skipB
1155 swap_endian_inplace, table,/swap_if_little
1156
1157 ; Fix offset for unsigned data
1158 type = mrd_unsignedtype(table)
1159 if type gt 0 then begin
1160 table = table - mrd_unsigned_offset(type)
1161 endif
1162
1163 status=0
1164 done:
1165
1166 ;-- probably an EOF
1167
1168 if status ne 0 then begin
1169 message,!ERROR_STATE.MSG,/CON
1170 free_lun,unit
1171 endif
1172 return
1173 end
1174
1175 ; Truncate superfluous axes.
1176
1177 pro mrd_axes_trunc,naxis, dims, silent
1178
1179 mysilent = silent
1180 for i=naxis-1,1,-1 do begin
1181
1182 if dims[i] eq 1 then begin
1183 if not mysilent then begin
1184 print, 'MRDFITS: Truncating unused dimensions'
1185 mysilent = 1
1186 endif
1187 dims = dims[0:i-1]
1188 naxis = naxis - 1
1189
1190 endif else return
1191
1192 endfor
1193
1194 return
1195 end
1196
1197 ; Define structure/array to hold a FITS image.
1198 pro mrd_image, header, range, maxd, rsize, table, scales, offsets, scaling, $
1199 status, silent=silent, unsigned=unsigned, rows = rows
1200
1201 ;
1202 ; Header FITS header for table.
1203 ; Range Range of data to be retrieved.
1204 ; Rsize Size of a row or group.
1205 ; Table Structure to be defined.
1206 ; Status Return status
1207 ; Silent=silent Suppress info messages?
1208
1209 table = 0
1210
1211 ; type 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1212 lens = [ 0, 1, 2, 4, 4, 8, 0, 0, 0, 0, 0, 0, 2, 4, 8, 8]
1213 typstrs=['', 'Byte', 'Int*2', 'Int*4', 'Real*4', 'Real*8','','','','','','', 'UInt*2', 'Uint*4', 'Int*8', 'Uint*8']
1214 typarr= ['', 'bytarr', 'intarr', 'lonarr', 'fltarr', 'dblarr','','','','','','','uintarr', 'ulonarr', 'lon64arr', 'ulon64arr']
1215
1216 status = 0
1217
1218
1219 naxis = fxpar(header, 'NAXIS')
1220 bitpix= fxpar(header, 'BITPIX')
1221 if naxis gt 0 then begin
1222 dims = long64(fxpar(header, 'NAXIS*', Count = N_axis))
1223 if N_axis GT naxis then begin
1224 ; Check if extra NAXISn keywords are present (though this is not legal FITS)
1225 nextra = N_axis - naxis
1226 dim_extra = dims[naxis:N_axis-1]
1227 if total(dim_extra) EQ nextra then $
1228 dims = dims[0:naxis-1] else $
1229 message,'ERROR - NAXIS = ' + strtrim(naxis,2) + $
1230 ' but NAXIS' + strtrim(N_axis,2) + ' keyword present'
1231 endif
1232 endif else dims = 0
1233
1234 gcount = fxpar(header, 'GCOUNT')
1235 pcount = fxpar(header, 'PCOUNT')
1236 isgroup = fxpar(header, 'GROUPS')
1237 gcount = long(gcount)
1238
1239 xscale = fxpar(header, 'BSCALE', count=cnt)
1240 if cnt eq 0 then xscale = 1 ;Corrected 06/29/06
1241
1242 xunsigned = mrd_chkunsigned(bitpix, xscale, $
1243 fxpar(header, 'BZERO'), unsigned=unsigned)
1244 ; Note that type is one less than the type signifier returned in the size call.
1245 type = -1
1246
1247 if not xunsigned then begin
1248
1249 if bitpix eq 8 then type = 1 $
1250 else if bitpix eq 16 then type = 2 $
1251 else if bitpix eq 32 then type = 3 $
1252 else if bitpix eq -32 then type = 4 $
1253 else if bitpix eq -64 then type = 5 $
1254 else if bitpix eq 64 then type = 14
1255
1256 endif else begin
1257
1258 if bitpix eq 16 then type = 12 $
1259 else if bitpix eq 32 then type = 13 $
1260 else if bitpix eq 64 then type = 15
1261
1262 endelse
1263
1264 if type eq -1 then begin
1265 print,'MRDFITS: Error: Invalid BITPIX: '+strtrim(bitpix)
1266 table = 0
1267 return
1268 endif
1269
1270 ; Note that for random groups data we must ignore the first NAXISn keyword.
1271 if isgroup GT 0 then begin
1272
1273
1274 range[0] = range[0] > 0
1275 if (range[1] eq -1) then begin
1276 range[1] = gcount-1
1277 endif else begin
1278 range[1] = range[1] < gcount - 1
1279 endelse
1280
1281 maxd = gcount
1282
1283 if (n_elements(dims) gt 1) then begin
1284 dims = dims[1:*]
1285 naxis = naxis-1
1286 endif else begin
1287 print, 'MRDFITS: Warning: No data specified for group data.'
1288 dims = [0]
1289 naxis = 0
1290 endelse
1291
1292 ; The last entry is the scaling for the sample data.
1293
1294 if (pcount gt 0) then begin
1295 scales = dblarr(pcount+1)
1296 offsets = dblarr(pcount+1)
1297 endif
1298
1299 values = strarr(2)
1300
1301
1302 mrd_axes_trunc, naxis, dims, keyword_set(silent)
1303
1304 values[0] = typarr[type] + "("+string(pcount)+")"
1305 rsize = dims[0]
1306 sarr = "(" + strcompress(string(dims[0]), /remo )
1307
1308 for i=1, naxis-1 do begin
1309
1310 sarr = sarr + "," + strcompress(string(dims[i]),/remo)
1311 rsize = rsize*dims[i]
1312
1313 endfor
1314
1315 sarr = sarr + ")"
1316
1317 if not keyword_set(silent) then print,'MRDFITS--Image with groups:', $
1318 ' Ngroup=',strcompress(string(gcount)),' Npar=', $
1319 strcompress(string(pcount),/remo), ' Group=', sarr, ' Type=',typstrs[type]
1320
1321 sarr = typarr[type] + sarr
1322 values[1] = sarr
1323 rsize = (rsize + pcount)*lens[type]
1324
1325 table = mrd_struct(['params','array'], values, range[1]-range[0]+1, $
1326 silent=silent)
1327
1328 if xunsigned then begin
1329 fxaddpar,header, 'BZERO', 0, 'Reset by MRDFITS v'+mrd_version()
1330 endif
1331
1332
1333 for i=0, pcount-1 do begin
1334
1335 istr = strcompress(string(i+1),/remo)
1336
1337 scales[i] = fxpar(header, 'PSCAL'+istr)
1338 if scales[i] eq 0.0d0 then scales[i] =1.0d0
1339
1340 offsets[i] = fxpar(header, 'PZERO'+istr)
1341
1342 scales[pcount] = fxpar(header, 'BSCALE')
1343 if scales[pcount] eq 0.0d0 then scales[pcount] = 1.0d0
1344 offsets[pcount] = fxpar(header, 'BZERO')
1345
1346 endfor
1347
1348 if scaling then begin
1349 w = where(scales ne 1.0d0 or offsets ne 0.0d0)
1350 if w[0] eq -1 then scaling = 0
1351 endif
1352
1353 endif else begin
1354
1355 if naxis eq 0 then begin
1356
1357 rsize = 0
1358 table = 0
1359 if not keyword_set(silent) then begin
1360 print, 'MRDFITS: Null image, NAXIS=0'
1361 endif
1362 return
1363
1364 endif
1365
1366 if gcount gt 1 then begin
1367 dims = [dims, gcount]
1368 naxis = naxis + 1
1369 endif
1370
1371 mrd_axes_trunc, naxis, dims, keyword_set(silent)
1372
1373
1374 maxd = dims[naxis-1]
1375
1376 if range[0] ne -1 then begin
1377 range[0] = range[0]<(maxd-1)
1378 range[1] = range[1]<(maxd-1)
1379 endif else begin
1380 range[0] = 0
1381 range[1] = maxd - 1
1382 endelse
1383
1384 Nlast = dims[naxis-1]
1385 dims[naxis-1] = range[1]-range[0]+1
1386 pdims = dims
1387 if N_elements(rows) GT 0 then begin
1388 if max(rows) GE Nlast then begin
1389 print, 'MRDFITS: Row numbers must be between 0 and ' + $
1390 strtrim(Nlast-1,2)
1391 status = -1 & rsize = 0
1392 return
1393 endif
1394 pdims[naxis-1] = N_elements(rows)
1395 endif
1396
1397 if not keyword_set(silent) then begin
1398 str = '('
1399 for i=0, naxis-1 do begin
1400 if i ne 0 then str = str + ','
1401 str = str + strcompress(string(pdims[i]),/remo)
1402 endfor
1403 str = str+')'
1404 print, 'MRDFITS: Image array ',str, ' Type=', typstrs[type]
1405 endif
1406
1407 rsize = 1
1408
1409 if naxis gt 1 then for i=0, naxis - 2 do rsize=rsize*dims[i]
1410 rsize = rsize*lens[type]
1411 sz = lonarr(naxis+3)
1412 sz[0] = naxis
1413 sz[1:naxis] = dims
1414 nele = 1l
1415
1416 for i=0, naxis-1 do begin
1417 nele = nele*dims[i]
1418 endfor
1419
1420 sz[naxis+1] = type
1421 sz[naxis+2] = nele
1422
1423 if nele gt 0 then begin
1424 table = make_array(size=sz)
1425 endif else begin
1426 table = 0
1427 endelse
1428
1429 scales = dblarr(1)
1430 offsets = dblarr(1)
1431
1432 if xunsigned then begin
1433 fxaddpar,header, 'BZERO', 0, 'Updated by MRDFITS v'+mrd_version()
1434 endif
1435
1436 scales[0] = fxpar(header, 'BSCALE')
1437 offsets[0] = fxpar(header, 'BZERO')
1438
1439 if scales[0] eq 0.0d0 then scales[0] = 1.0d0
1440 if scaling and scales[0] eq 1.0d0 and offsets[0] eq 0.0d0 then scaling = 0
1441 endelse
1442
1443 status = 0
1444 return
1445
1446 end
1447
1448 ; Scale an array of pointers
1449 pro mrd_ptrscale, array, scale, offset
1450
1451 for i=0, n_elements(array)-1 do begin
1452 if ptr_valid(array[i]) then begin
1453 array[i] = ptr_new(*array[i] * scale + offset)
1454 endif
1455 endfor
1456 end
1457
1458 ; Scale a FITS array or table.
1459 pro mrd_scale, type, scales, offsets, table, header, $
1460 fnames, fvalues, nrec, dscale = dscale, structyp=structyp, silent=silent
1461 ;
1462 ; Type: FITS file type, 0=image/primary array
1463 ; 1=ASCII table
1464 ; 2=Binary table
1465 ;
1466 ; scales: An array of scaling info
1467 ; offsets: An array of offset information
1468 ; table: The FITS data.
1469 ; header: The FITS header.
1470 ; dscale: Should data be scaled to R*8?
1471 ; fnames: Names of table columns.
1472 ; fvalues: Values of table columns.
1473 ; nrec: Number of records used.
1474 ; structyp: Structure name.
1475
1476 w = where(scales ne 1.d0 or offsets ne 0.d0)
1477 if w[0] eq -1 then return
1478 ww = where(scales eq 1.d0 and offsets eq 0.d0)
1479
1480 ; First do ASCII and Binary tables.
1481 if type ne 0 then begin
1482
1483 if type eq 1 then begin
1484 if keyword_set(dscale) then begin
1485 fvalues[w] = '0.0d0'
1486 endif else begin
1487 fvalues[w] = '0.0'
1488 endelse
1489 endif else if type eq 2 then begin
1490
1491 if keyword_set(dscale) then begin
1492 sclr = '0.d0'
1493 vc = 'dblarr'
1494 endif else begin
1495 sclr = '0.0'
1496 vc = 'fltarr'
1497 endelse
1498
1499 for i=0, n_elements(w)-1 do begin
1500 col = w[i]
1501 sz = size(table[0].(col))
1502
1503 ; Handle pointer columns
1504 if sz[sz[0]+1] eq 10 then begin
1505 fvalues[col] = 'ptr_new()'
1506
1507 ; Scalar columns
1508 endif else if sz[0] eq 0 then begin
1509 fvalues[col] = sclr
1510
1511 ; Vectors
1512 endif else begin
1513 str = vc + '('
1514 for j=0, sz[0]-1 do begin
1515 if j ne 0 then str = str + ','
1516 str = str + strtrim(sz[j+1],2)
1517 endfor
1518 str = str + ')'
1519 fvalues[col] = str
1520
1521 endelse
1522
1523 endfor
1524 endif
1525
1526 tabx = mrd_struct(fnames, fvalues, nrec, structyp=structyp, silent=silent )
1527
1528 ; Just copy the unscaled columns
1529 if ww[0] ne -1 then begin
1530
1531 for i=0, n_elements(ww)-1 do begin
1532 tabx.(ww[i]) = table.(ww[i])
1533 endfor
1534 endif
1535
1536 for i=0, n_elements(w)-1 do begin
1537
1538
1539 sz = size(tabx.(w[i]))
1540 if sz[sz[0]+1] eq 10 then begin
1541 mrd_ptrscale, table.(w[i]), scales[w[i]], offsets[w[i]]
1542 endif
1543 tabx.(w[i]) = table.(w[i])*scales[w[i]] + offsets[w[i]]
1544
1545 istr = strcompress(string(w[i]+1), /remo)
1546 fxaddpar, header, 'TSCAL'+istr, 1.0, 'Set by MRD_SCALE'
1547 fxaddpar, header, 'TZERO'+istr, 0.0, 'Set by MRD_SCALE'
1548 endfor
1549
1550 table = temporary(tabx)
1551
1552 endif else begin
1553 ; Now process images and random groups.
1554
1555 sz = size(table[0])
1556 if sz[sz[0]+1] ne 8 then begin
1557 ; Not a structure so we just have an array of data.
1558 if keyword_set(dscale) then begin
1559 table = table*scales[0]+offsets[0]
1560 endif else begin
1561 table = table*float(scales[0]) + float(offsets[0])
1562 endelse
1563 fxaddpar, header, 'BSCALE', 1.0, 'Set by MRD_SCALE'
1564 fxaddpar, header, 'BZERO', 0.0, 'Set by MRD_SCALE'
1565
1566 endif else begin
1567 ; Random groups. Get the number of parameters by looking
1568 ; at the first element in the table.
1569 nparam = n_elements(table[0].(0))
1570 if keyword_set(dscale) then typ = 'dbl' else typ='flt'
1571 s1 = typ+'arr('+string(nparam)+')'
1572 ngr = n_elements(table)
1573 sz = size(table[0].(1))
1574 if sz[0] eq 0 then dims = [1] else dims=sz[1:sz[0]]
1575 s2 = typ + 'arr('
1576 for i=0, n_elements(dims)-1 do begin
1577 if i ne 0 then s2 = s2+ ','
1578 s2 = s2+string(dims[i])
1579 endfor
1580 s2 = s2+')'
1581 tabx = mrd_struct(['params', 'array'],[s1,s2],ngr, silent=silent)
1582
1583 for i=0, nparam-1 do begin
1584 istr = strcompress(string(i+1),/remo)
1585 fxaddpar, header, 'PSCAL'+istr, 1.0, 'Added by MRD_SCALE'
1586 fxaddpar, header, 'PZERO'+istr, 0.0, 'Added by MRD_SCALE'
1587 tabx.(0)[i] = table.(0)[i]*scales[i]+offsets[i]
1588 endfor
1589
1590 tabx.(1) = table.(1)*scales[nparam] + offsets[nparam]
1591 fxaddpar, header, 'BSCALE', 1.0, 'Added by MRD_SCALE'
1592 fxaddpar, header, 'BZERO', 0.0, 'Added by MRD_SCALE'
1593 table = temporary(tabx)
1594 endelse
1595 endelse
1596
1597 end
1598
1599 ; Read a variable length column into a pointer array.
1600 pro mrd_varcolumn, vtype, array, heap, off, siz
1601
1602 ; Guaranteed to have at least one non-zero length column
1603 w = where(siz gt 0)
1604 nw = n_elements(w)
1605
1606 if vtype eq 'X' then siz = 1 + (siz-1)/8
1607
1608 siz = siz[w]
1609 off = off[w]
1610
1611 unsigned = 0
1612 if vtype eq '1' then begin
1613 unsigned = 12
1614 endif else if vtype eq '2' then begin
1615 unsigned = 13
1616 endif else if vtype eq '3' then begin
1617 unsigned = 15;
1618 endif
1619 unsigned = mrd_unsigned_offset(unsigned)
1620
1621
1622 for j=0, nw-1 do begin
1623
1624 case vtype of
1625
1626 'L': array[w[j]] = ptr_new( byte(heap,off[j],siz[j]) )
1627 'X': array[w[j]] = ptr_new( byte(heap,off[j],siz[j]) )
1628 'B': array[w[j]] = ptr_new( byte(heap,off[j],siz[j]) )
1629
1630 'I': array[w[j]] = ptr_new( fix(heap, off[j], siz[j]) )
1631 'J': array[w[j]] = ptr_new( long(heap, off[j], siz[j]) )
1632 'K': array[w[j]] = ptr_new( long64(heap, off[j], siz[j]) )
1633
1634 'E': array[w[j]] = ptr_new( float(heap, off[j], siz[j]) )
1635 'D': array[w[j]] = ptr_new( double(heap, off[j], siz[j]) )
1636
1637 'C': array[w[j]] = ptr_new( complex(heap, off[j], siz[j]) )
1638 'M': array[w[j]] = ptr_new( dcomplex(heap, off[j], siz[j]) )
1639
1640 '1': array[w[j]] = ptr_new( uint(heap, off[j], siz[j]) )
1641 '2': array[w[j]] = ptr_new( ulong(heap, off[j], siz[j]) )
1642 '3': array[w[j]] = ptr_new( ulong64(heap, off[j], siz[j]) )
1643
1644 endcase
1645
1646 ; Fix endianness.
1647 if vtype ne 'B' and vtype ne 'X' and vtype ne 'L' then begin
1648 swap_endian_inplace, *array[w[j]],/swap_if_little
1649 endif
1650
1651 ; Scale unsigneds.
1652 if unsigned gt 0 then *array[w[j]] = *array[w[j]] - unsigned
1653
1654 endfor
1655 end
1656
1657 ; Read a variable length column into a fixed length array.
1658 pro mrd_fixcolumn, vtype, array, heap, off, siz
1659
1660 w = where(siz gt 0)
1661 if w[0] eq -1 then return
1662
1663 nw = n_elements(w)
1664
1665
1666 if vtype eq 'X' then siz = 1 + (siz-1)/8
1667
1668 siz = siz[w]
1669 off = off[w]
1670
1671 for j=0, nw-1 do begin
1672 case vtype of
1673 'L': array[0:siz[j]-1,w[j]] = byte(heap,off[j],siz[j])
1674 'X': array[0:siz[j]-1,w[j]] = byte(heap,off[j],siz[j])
1675 'B': array[0:siz[j]-1,w[j]] = byte(heap,off[j],siz[j])
1676
1677 'I': array[0:siz[j]-1,w[j]] = fix(heap, off[j], siz[j])
1678 'J': array[0:siz[j]-1,w[j]] = long(heap, off[j], siz[j])
1679 'K': array[0:siz[j]-1,w[j]] = long64(heap, off[j], siz[j])
1680
1681 'E': begin ;Delay conversion until after byteswapping to avoid possible math overflow Feb 2005
1682 temp = heap[off[j]: off[j] + 4*siz[j]-1 ]
1683 byteorder, temp, /LSWAP, /SWAP_IF_LITTLE
1684 array[0:siz[j]-1,w[j]] = float(temp,0,siz[j])
1685 end
1686 'D': begin
1687 temp = heap[off[j]: off[j] + 8*siz[j]-1 ]
1688 byteorder, temp, /L64SWAP, /SWAP_IF_LITTLE
1689 array[0:siz[j]-1,w[j]] = double(temp,0,siz[j])
1690 end
1691 'C': array[0:siz[j]-1,w[j]] = complex(heap, off[j], siz[j])
1692 'M': array[0:siz[j]-1,w[j]] = dcomplex(heap, off[j], siz[j])
1693
1694 'A': array[w[j]] = string(byte(heap,off[j],siz[j]))
1695
1696 '1': array[0:siz[j]-1,w[j]] = uint(heap, off[j], siz[j])
1697 '2': array[0:siz[j]-1,w[j]] = ulong(heap, off[j], siz[j])
1698 '3': array[0:siz[j]-1,w[j]] = ulong64(heap, off[j], siz[j])
1699
1700 endcase
1701
1702 endfor
1703
1704 ; Fix endianness
1705 if (vtype ne 'A') and (vtype ne 'B') and (vtype ne 'X') and (vtype ne 'L') and $
1706 (vtype NE 'D') and (vtype NE 'E') then begin
1707 swap_endian_inplace, array, /swap_if_little
1708 endif
1709
1710 ; Scale unsigned data
1711 unsigned = 0
1712 if vtype eq '1' then begin
1713 unsigned = 12
1714 endif else if vtype eq '2' then begin
1715 unsigned = 13
1716 endif else if vtype eq '3' then begin
1717 unsigned = 15;
1718 endif
1719
1720 if unsigned gt 0 then begin
1721 unsigned = mrd_unsigned_offset(unsigned)
1722 endif
1723
1724 if unsigned gt 0 then begin
1725 for j=0, nw-1 do begin
1726 array[0:siz[j]-1,w[j]] = array[0:siz[j]-1,w[j]] - unsigned
1727 endfor
1728 endif
1729
1730
1731 end
1732
1733 ; Read the heap area to get the actual values of variable
1734 ; length arrays.
1735 pro mrd_read_heap, unit, header, range, fnames, fvalues, vcls, vtpes, table, $
1736 structyp, scaling, scales, offsets, status, silent=silent, $
1737 columns=columns, rows = rows, pointer_var=pointer_var, fixed_var=fixed_var
1738
1739 ;
1740 ; Unit: FITS unit number.
1741 ; header: FITS header.
1742 ; fnames: Column names.
1743 ; fvalues: Column values.
1744 ; vcols: Column numbers of variable length columns.
1745 ; vtypes: Actual types of variable length columns
1746 ; table: Table of data from standard data area, on output
1747 ; contains the variable length data.
1748 ; structyp: Structure name.
1749 ; scaling: Is there going to be scaling of the data?
1750 ; status: Set to -1 if an error occurs.
1751 ;
1752 typstr = 'LXBIJKAEDCM123'
1753 prefix = ['bytarr(', 'bytarr(', 'bytarr(', 'intarr(', $
1754 'lonarr(', 'lon64arr(', 'string(bytarr(', 'fltarr(', $
1755 'dblarr(', 'cmplxarr(', 'dblarr(2,', $
1756 'uintarr(', 'ulonarr(', 'ulon64arr(']
1757
1758 status = 0
1759
1760 ; Convert from a list of indicators of whether a column is variable
1761 ; length to pointers to only the variable columns.
1762
1763 vcols = where(vcls eq 1)
1764 vtypes = vtpes[vcols]
1765
1766 nv = n_elements(vcols)
1767
1768 ; Find the beginning of the heap area.
1769
1770 heapoff = long64(fxpar(header, 'THEAP'))
1771 sz = fxpar(header, 'NAXIS1')*fxpar(header, 'NAXIS2')
1772
1773 if heapoff ne 0 and heapoff lt sz then begin
1774 print, 'MRDFITS: ERROR Heap begins within data area'
1775 status = -1
1776 return
1777 endif
1778
1779 ; Skip to beginning.
1780 if (heapoff > sz) then begin
1781 mrd_skip, unit, heapoff-sz
1782 endif
1783
1784 ; Get the size of the heap.
1785 pc = long64(fxpar(header, 'PCOUNT'))
1786 if heapoff eq 0 then heapoff = sz
1787 hpsiz = pc - (heapoff-sz)
1788
1789 if (hpsiz gt 0) then heap = bytarr(hpsiz)
1790
1791
1792 ; Read in the heap
1793 readu, unit, heap
1794
1795 ; Skip to the end of the data area.
1796 skipB = 2880 - (sz+pc) mod 2880
1797 if skipB ne 2880 then begin
1798 mrd_skip, unit, skipB
1799 endif
1800
1801 ; Find the maximum dimensions of the arrays.
1802 ;
1803 ; Note that the variable length column currently has fields which
1804 ; are I*4 2-element arrays where the first element is the
1805 ; length of the field on the current row and the second is the
1806 ; offset into the heap.
1807
1808 vdims = lonarr(nv)
1809 for i=0, nv-1 do begin
1810 col = vcols[i]
1811 curr_col = table.(col)
1812 vdims[i] = max(curr_col[0,*])
1813 w = where(curr_col[0,*] ne vdims[i])
1814 if w[0] ne -1 then begin
1815 if n_elements(lencols) eq 0 then begin
1816 lencols = [col]
1817 endif else begin
1818 lencols=[lencols,col]
1819 endelse
1820 endif
1821
1822 if vtypes[i] eq 'X' then vdims[i]=(vdims[i]+7)/8
1823 ind = strpos(typstr, vtypes[i])
1824
1825 ; Note in the following that we ensure that the array is
1826 ; at least one element long.
1827
1828 fvalues[col] = prefix[ind] + string((vdims[i] > 1)) + ')'
1829 if vtypes[i] eq 'A' then fvalues[col] = fvalues[col] + ')'
1830
1831 endfor
1832
1833 nfld = n_elements(fnames)
1834
1835 ; Get rid of columns which have no actual data.
1836 w= intarr(nfld)
1837 w[*] = 1
1838 corres = indgen(nfld)
1839
1840
1841 ; Should we get rid of empty columns?
1842 delete = 1
1843 if keyword_set(pointer_var) then delete = pointer_var eq 1
1844
1845 if delete then begin
1846
1847 ww = where(vdims eq 0)
1848 if ww[0] ne -1 then begin
1849 w[vcols[ww]] = 0
1850 if not keyword_set(silent) then begin
1851 print, 'MRDFITS: ', strcompress(string(n_elements(ww))), $
1852 ' unused variable length columns deleted'
1853 endif
1854 endif
1855
1856 ; Check if all columns have been deleted...
1857 wx = where(w gt 0)
1858 if (wx[0] eq -1) then begin
1859 if not keyword_set(silent) then begin
1860 print, 'MRDFITS: All columns have been deleted'
1861 endif
1862 table = 0
1863 return
1864 endif
1865
1866
1867 ; Get rid of unused columns.
1868 corres = corres[wx]
1869 fnames = fnames[wx]
1870 fvalues = fvalues[wx]
1871 scales = scales[wx]
1872 offsets = offsets[wx]
1873
1874 wx = where(vdims gt 0)
1875
1876 if (wx[0] eq -1) then begin
1877 vcols=[-9999]
1878 x=temporary(vtypes)
1879 x=temporary(vdims)
1880 endif else begin
1881 vcols = vcols[wx]
1882 vtypes = vtypes[wx]
1883 vdims = vdims[wx]
1884 endelse
1885 endif
1886
1887 if not keyword_set(pointer_var) then begin
1888 ; Now add columns for lengths of truly variable length records.
1889 if n_elements(lencols) gt 0 then begin
1890 if not keyword_set(silent) then begin
1891 print, 'MRDFITS: ', strcompress(string(n_elements(lencols))), $
1892 ' length column[s] added'
1893 endif
1894
1895
1896 for i=0, n_elements(lencols)-1 do begin
1897 col = lencols[i]
1898 w = where(col eq corres)
1899 ww = where(col eq vcols)
1900 w = w[0]
1901 ww = ww[0]
1902 fvstr = '0L' ; <-- Originally, '0l'; breaks under the virtual machine!
1903 fnstr = 'L'+strcompress(string(col),/remo)+'_'+fnames[w]
1904 nf = n_elements(fnames)
1905
1906 ; Note that lencols and col refer to the index of the
1907 ; column before we started adding in the length
1908 ; columns.
1909
1910 if w eq nf-1 then begin
1911 ; Subtract -1 for the length columns so 0 -> -1 and
1912 ; we can distinguish this column.
1913
1914 corres = [corres, -col-1 ]
1915 fnames = [fnames, fnstr ]
1916 fvalues = [fvalues, fvstr ]
1917 scales = [scales, 1.0d0 ]
1918 offsets = [offsets, 0.0d0 ]
1919
1920 endif else begin
1921
1922 corres = [corres[0:w],-col-1,corres[w+1:nf-1] ]
1923 fnames = [fnames[0:w],fnstr,fnames[w+1:nf-1] ]
1924 fvalues = [fvalues[0:w],fvstr,fvalues[w+1:nf-1] ]
1925 scales = [scales[0:w], 1.0d0, scales[w+1:nf-1] ]
1926 offsets = [offsets[0:w],0.0d0, offsets[w+1:nf-1] ]
1927 endelse
1928 endfor
1929 endif
1930
1931 endif else begin
1932
1933 ; We'll just read data into pointer arrays.
1934 for i=0,n_elements(lencols)-1 do begin
1935 col = lencols[i]
1936 if vtpes[col] eq 'A' then begin
1937 fvalues[col] = '" "'
1938 endif else begin
1939 fvalues[col] = 'ptr_new()'
1940 endelse
1941 endfor
1942
1943 endelse
1944
1945
1946
1947 ; Generate a new table with the appropriate structure definitions
1948 if not scaling and not keyword_set(columns) then begin
1949 tablex = mrd_struct(fnames, fvalues, n_elements(table), structyp=structyp, $
1950 silent=silent)
1951 endif else begin
1952 tablex = mrd_struct(fnames, fvalues, n_elements(table), silent=silent)
1953 endelse
1954
1955
1956 if N_elements(rows) EQ 0 then nrow = range[1]-range[0]+1 $
1957 else nrow = N_elements(rows)
1958
1959 ; I loops over the new table columns, col loops over the old table.
1960 ; When col is negative, it is a length column.
1961 for i=0, n_elements(fnames)-1 do begin
1962
1963 col = corres[i]
1964
1965 if col ge 0 then begin
1966
1967 w = where(vcols eq col)
1968
1969 ; First handle the case of a column that is not
1970 ; variable length -- just copy the column.
1971
1972 if w[0] eq -1 then begin
1973
1974 tablex.(i) = table.(col)
1975
1976 endif else begin
1977
1978 vc = w[0]
1979 ; Now handle the variable length columns
1980
1981 ; If only one row in table, then
1982 ; IDL will return curr_col as one-dimensional.
1983 ; Since this is a variable length pointer column we
1984 ; know that the dimension of the column is 2.
1985 curr_col = table.(col)
1986
1987 if (nrow eq 1) then curr_col = reform(curr_col,2,1)
1988 siz = curr_col[0,*]
1989 off = curr_col[1,*]
1990
1991 ; Now process each type.
1992 curr_colx = tablex.(i)
1993 sz = size(curr_colx)
1994 if (sz[0] lt 2) then begin
1995 curr_colx = reform(curr_colx, 1, n_elements(curr_colx), /overwrite)
1996 endif
1997
1998
1999 ; As above we have to worry about IDL truncating
2000 ; dimensions. This can happen if either
2001 ; nrow=1 or the max dimension of the column is 1.
2002
2003
2004 sz = size(tablex.(i))
2005
2006 nel = sz[sz[0]+2]
2007 if nrow eq 1 and nel eq 1 then begin
2008 curr_colx = make_array(1,1,value=curr_colx)
2009 endif else if nrow eq 1 then begin
2010 curr_colx = reform(curr_colx,[nel, 1], /overwrite)
2011 endif else if nel eq 1 then begin
2012 curr_colx = reform(curr_colx,[1, nrow], /overwrite)
2013 endif
2014
2015 vtype = vtypes[vc]
2016 varying = 0
2017 if n_elements(lencols) gt 0 then begin
2018 varying = where(lencols eq col)
2019 if varying[0] eq -1 then varying=0 else varying=1
2020 endif
2021
2022 if varying and keyword_set(pointer_var) and vtype ne 'A' then begin
2023 mrd_varcolumn, vtype, curr_colx, heap, off, siz
2024 endif else begin
2025 mrd_fixcolumn, vtype, curr_colx, heap, off, siz
2026 endelse
2027
2028
2029
2030 if nel eq 1 and nrow eq 1 then begin
2031 curr_colx = curr_colx[0]
2032 endif else if nrow eq 1 then begin
2033 curr_colx = reform(curr_colx, nel, /overwrite)
2034 endif else if nel eq 1 then begin
2035 curr_colx = reform(curr_colx, nrow, /overwrite)
2036 endif
2037
2038 sz = size(curr_colx)
2039 if sz[1] eq 1 then begin
2040 sz_tablex = size(tablex.(i))
2041 sdimen = sz_tablex[1:sz_tablex[0]]
2042 tablex.(i) = reform(curr_colx,sdimen)
2043 endif else begin
2044 tablex.(i) = curr_colx
2045 endelse
2046
2047 endelse
2048
2049 endif else begin
2050 ; Now handle the added columns which hold the lengths
2051 ; of the variable length columns.
2052
2053 ncol = -col - 1 ; Remember we subtracted an extra one.
2054 xx = table.(ncol)
2055 tablex.(i) = reform(xx[0,*])
2056 endelse
2057 endfor
2058
2059 ; Finally get rid of the initial table and return the table with the
2060 ; variable arrays read in.
2061 ;
2062 table = temporary(tablex)
2063 return
2064 end
2065
2066 ; Read in the binary table information.
2067 pro mrd_read_table, unit, range, rsize, structyp, nrows, nfld, typarr, table, rows = rows
2068
2069 ;
2070 ;
2071 ; Unit Unit to read data from.
2072 ; Range Desired range
2073 ; Rsize Size of row.
2074 ; structyp Structure type.
2075 ; Nfld Number of fields in structure.
2076 ; Typarr Field types
2077 ; Table Table to read information into.
2078 ;
2079
2080 if range[0] gt 0 then mrd_skip, unit, rsize*range[0]
2081 readu,unit, table
2082 if N_elements(rows) GT 0 then table = table[rows- range[0]]
2083
2084 ; Move to the beginning of the heap -- we may have only read some rows of
2085 ; the data.
2086 if range[1] lt nrows-1 then begin
2087 skip_dist = (nrows-range[1]-1)*rsize
2088 mrd_skip, unit, skip_dist
2089 endif
2090
2091
2092
2093 ; If necessary then convert to native format.
2094 if byte(1L, 0,1) EQ 1 then begin
2095
2096 for i=0, nfld-1 do begin
2097
2098 typ = typarr[i]
2099 if typ eq 'B' or typ eq 'A' or typ eq 'X' or typ eq 'L' $
2100 then goto, nxtfld
2101 fld = table.(i)
2102 if typ eq 'I' then byteorder, fld, /htons
2103 if typ eq 'J' or typ eq 'P' then byteorder, fld, /htonl
2104 if typ eq 'K' then byteorder, fld, /l64swap
2105 if typ eq 'E' or typarr[i] eq 'C' then $
2106 byteorder, fld, /LSWAP
2107
2108 if typ eq 'D' or typarr[i] eq 'M' then byteorder, fld, /L64SWAP
2109
2110 if n_elements(fld) gt 1 then begin
2111
2112 table.(i) = fld
2113 endif else begin
2114 table.(i) = fld[0]
2115 endelse
2116 nxtfld:
2117 endfor
2118 endif
2119
2120 ; Handle unsigned fields.
2121 for i=0, nfld-1 do begin
2122
2123
2124 type = mrd_unsignedtype(table.(i))
2125
2126 if type gt 0 then begin
2127 table.(i) = table.(i) - mrd_unsigned_offset(type)
2128 endif
2129
2130
2131 endfor
2132
2133 end
2134
2135
2136 ; Check the values of TDIM keywords to see that they have valid
2137 ; dimensionalities. If the TDIM keyword is not present or valid
2138 ; then the a one-dimensional array with a size given in the TFORM
2139 ; keyword is used.
2140
2141 pro mrd_tdim, header, index, flen, arrstr, no_tdim=no_tdim
2142
2143 ; HEADER Current header array.
2144 ; Index Index of current parameter
2145 ; flen Len given in TFORM keyword
2146 ; arrstr String returned to be included within paren's in definition.
2147 ; no_tdim Disable TDIM processing
2148
2149 arrstr = strcompress(string(flen),/remo)
2150
2151 if keyword_set(no_tdim) then return
2152
2153 tdstr = fxpar(header, 'TDIM'+strcompress(string(index),/remo))
2154 if tdstr eq '' then return
2155
2156 ;
2157 ; Parse the string. It should be of the form '(n1,n2,...nx)' where
2158 ; all of the n's are positive integers and the product equals flen.
2159 ;
2160 tdstr = strcompress(tdstr,/remo)
2161 len = strlen(tdstr)
2162 if strmid(tdstr,0,1) ne '(' and strmid(tdstr,len-1,1) ne ')' or len lt 3 then begin
2163 print, 'MRDFITS: Error: invalid TDIM for column', index
2164 return
2165 endif
2166
2167 ; Get rid of parens.
2168 tdstr = strmid(tdstr,1,len-2)
2169 len = len-2
2170
2171 nind = 0
2172 cnum = 0
2173
2174 for nchr=0, len-1 do begin
2175 c = strmid(tdstr,nchr, 1)
2176
2177 if c ge '0' and c le '9' then begin
2178 cnum = 10*cnum + long(c)
2179
2180 endif else if c eq ',' then begin
2181
2182 if cnum le 0 then begin
2183 print,'MRDFITS: Error: invalid TDIM for column', index
2184 return
2185 endif
2186
2187 if n_elements(numbs) eq 0 then $
2188 numbs = cnum $
2189 else numbs = [numbs,cnum]
2190
2191 cnum = 0
2192
2193 endif else begin
2194
2195 print,'MRDFITS: Error: invalid TDIM for column', index
2196 return
2197
2198 endelse
2199
2200 endfor
2201
2202 ; Handle the last number.
2203 if cnum le 0 then begin
2204 print,'MRDFITS: Error: invalid TDIM for column', index
2205 return
2206 endif
2207
2208 if n_elements(numbs) eq 0 then numbs = cnum else numbs = [numbs,cnum]
2209
2210 prod = 1
2211
2212 for i=0, n_elements(numbs)-1 do prod = prod*numbs[i]
2213
2214 if prod ne flen then begin
2215 print,'MRDFITS: Error: TDIM/TFORM dimension mismatch'
2216 return
2217 endif
2218
2219 arrstr = tdstr
2220 end
2221
2222 ; Define a structure to hold a FITS binary table.
2223 pro mrd_table, header, structyp, use_colnum, $
2224 range, rsize, table, nrows, nfld, typarr, fnames, fvalues, $
2225 vcls, vtpes, scales, offsets, scaling, status, rows = rows, $
2226 silent=silent, columns=columns, no_tdim=no_tdim, $
2227 alias=alias, unsigned=unsigned, outalias=outalias
2228
2229 ;
2230 ; Header FITS header for table.
2231 ; Structyp IDL structure type to be used for
2232 ; structure.
2233 ; N_call Number of times this routine has been called.
2234 ; Table Structure to be defined.
2235 ; Status Return status.
2236 ; No_tdim Disable TDIM processing.
2237
2238 table = 0
2239
2240 types = ['L', 'X', 'B', 'I', 'J', 'K', 'A', 'E', 'D', 'C', 'M', 'P']
2241 arrstr = ['bytarr(', 'bytarr(', 'bytarr(', 'intarr(', 'lonarr(', 'lon64arr(', $
2242 'string(replicate(32b,', 'fltarr(', 'dblarr(', 'complexarr(', $
2243 'dcomplexarr(', 'lonarr(2*']
2244 bitpix = [ 0, 0, 0, 16, 32, 64, 0, 0, 0, 0, 0, 0]
2245
2246 sclstr = ["'T'", '0B', '0B', '0', '0L', '0LL', '" "', '0.', '0.d0', 'complex(0.,0.)', $
2247 'dcomplex(0.d0,0.d0)', 'lonarr(2)']
2248
2249 unsarr = ['', '', '', 'uintarr(', 'ulonarr(', 'ulon64arr('];
2250 unsscl = ['', '', '', '0U', '0UL', '0ULL']
2251
2252
2253 status = 0
2254
2255 ; NEW WAY: E.S.S.
2256
2257 ;; get info from header. Using vectors is much faster
2258 ;; when there are many columns
2259
2260 mrd_fxpar, header, xten, nfld, nrow, rsize, fnames, fforms, scales, offsets
2261 nnames = n_elements(fnames)
2262
2263 tname = fnames
2264 ;; nrow will change later
2265 nrows = nrow
2266
2267 ;; Use scale=1 if not found
2268 if nnames GT 0 then begin
2269 wsc=where(scales EQ 0.0d,nwsc)
2270 IF nwsc NE 0 THEN scales[wsc] = 1.0d
2271 endif
2272
2273 xten = strtrim(xten,2)
2274 if xten ne 'BINTABLE' and xten ne 'A3DTABLE' then begin
2275 print, 'MRDFITS: ERROR - Header is not from binary table.'
2276 nfld = 0 & status = -1
2277 return
2278 endif
2279
2280 if range[0] ge 0 then begin
2281 range[0] = range[0] < (nrow-1)
2282 range[1] = range[1] < (nrow-1)
2283 endif else begin
2284 range[0] = 0
2285 range[1] = nrow - 1
2286 endelse
2287
2288 nrow = range[1] - range[0] + 1
2289 if nrow le 0 then begin
2290 if not keyword_set(silent) then begin
2291 print, 'MRDFITS: Binary table. ', $
2292 strcompress(string(nfld)), ' columns, no rows.'
2293 endif
2294 return
2295 endif
2296
2297 if N_elements(rows) EQ 0 then nrowp = nrow else begin
2298 bad = where((rows LT range[0]) or (rows GT range[1]), Nbad)
2299 if Nbad GT 0 then begin
2300 print,'MRDFITS: Row numbers must be between 0 and ' + $
2301 strtrim(nrow-1,2)
2302 status = -1
2303 return
2304 endif
2305 nrowp = N_elements(rows)
2306 endelse
2307 ; rsize = fxpar(header, 'NAXIS1')
2308
2309 ;
2310 ; Loop over the columns
2311
2312 typarr = strarr(nfld)
2313
2314 fvalues = strarr(nfld)
2315 dimfld = strarr(nfld)
2316
2317 vcls = intarr(nfld)
2318 vtpes = strarr(nfld)
2319
2320 fnames2 = strarr(nfld)
2321
2322 for i=0, nfld-1 do begin
2323
2324 istr = strcompress(string(i+1), /remo)
2325
2326 fname = fnames[i]
2327
2328 ;; check for a name conflict
2329 fname = mrd_dofn(fname, i+1, use_colnum, alias=alias)
2330
2331 ;; check for a name conflict
2332 fname = mrd_chkfn(fname, fnames2, i)
2333
2334 ;; copy in the valid name
2335 fnames[i] = fname
2336 ;; for checking conflicts
2337 fnames2[i] = fname
2338
2339 fform = fforms[i]
2340
2341 mrd_doff, fform, dim, ftype
2342
2343 ; Treat arrays of length 1 as scalars.
2344 if dim eq 1 then begin
2345 dim = 0
2346 endif else if dim EQ -1 then begin
2347 dimfld[i] = -1
2348 endif else begin
2349 mrd_tdim, header, i+1, dim, str, no_tdim=no_tdim
2350 dimfld[i] = str
2351 endelse
2352
2353 typarr[i] = ftype
2354
2355
2356 ; Find the number of bytes in a bit array.
2357
2358 if ftype eq 'X' and dim gt 0 then begin
2359 dim = (dim+7)/8
2360 dimfld[i] = strtrim(string(dim),2)
2361 endif
2362
2363 ; Add in the structure label.
2364 ;
2365
2366 ; Handle variable length columns.
2367 if ftype eq 'P' then begin
2368
2369 if dim ne 0 and dim ne 1 then begin
2370 print, 'MRDFITS: Invalid dimension for variable array column '+string(i+1)
2371 status = -1
2372 return
2373 endif
2374
2375 ppos = strpos(fform, 'P')
2376 vf = strmid(fform, ppos+1, 1);
2377 if strpos('LXBIJKAEDCM', vf) eq -1 then begin
2378 print, 'MRDFITS: Invalid type for variable array column '+string(i+1)
2379 status = -1
2380 return
2381 endif
2382
2383 vcls[i] = 1
2384
2385
2386 xunsigned = mrd_chkunsigned(bitpix[ppos], scales[i], $
2387 offsets[i], $
2388 unsigned=unsigned)
2389
2390 if (xunsigned) then begin
2391
2392 if vf eq 'I' then vf = '1' $
2393 else if vf eq 'J' then vf = '2' $
2394 else if vf eq 'K' then vf = '3'
2395
2396 endif
2397
2398 vtpes[i] = vf
2399 dim = 0
2400
2401 endif
2402
2403
2404 for j=0, n_elements(types) - 1 do begin
2405
2406 if ftype eq types[j] then begin
2407
2408 ; xscale = fxpar(header, 'TSCAL'+istr, count=cnt)
2409 ; if cnt eq 0 then xscale = 1
2410
2411 ; xunsigned = mrd_chkunsigned(bitpix[j], xscale, $
2412 ; fxpar(header, 'TZERO'+istr), $
2413 ; unsigned=unsigned)
2414
2415 xunsigned = mrd_chkunsigned(bitpix[j], scales[i], $
2416 offsets[i], $
2417 unsigned=unsigned)
2418
2419 if xunsigned then begin
2420 fxaddpar, header, 'TZERO'+istr, 0, 'Modified by MRDFITS V'+mrd_version()
2421 offsets[i] = 0 ;; C. Markwardt Aug 2007 - reset to zero so offset is not applied twice'
2422 endif
2423
2424 if dim eq 0 then begin
2425
2426 if xunsigned then begin
2427 fvalues[i] = unsscl[j]
2428 endif else begin
2429 fvalues[i] = sclstr[j]
2430 endelse
2431
2432 endif else begin
2433
2434 if xunsigned then begin
2435 line = unsarr[j]
2436 endif else begin
2437 line = arrstr[j]
2438 endelse
2439
2440 line = line + dimfld[i] + ')'
2441 if ftype eq 'A' then line = line + ')'
2442 fvalues[i] = line
2443
2444 endelse
2445
2446 goto, next_col
2447
2448 endif
2449
2450 endfor
2451
2452 print, 'MRDFITS: Invalid format code:',ftype, ' for column ', i+1
2453 status = -1
2454 return
2455 next_col:
2456 endfor
2457
2458 ; Check if there are any variable length columns. If not then
2459 ; undefine vcls and vtpes
2460 w = where(vcls eq 1)
2461 if w[0] eq -1 then begin
2462 dummy = temporary(vcls)
2463 dummy = temporary(vtpes)
2464 dummy = 0
2465 endif
2466
2467 if scaling then begin
2468 w = where(scales ne 1.0d0 or offsets ne 0.0d0)
2469 if w[0] eq -1 then scaling = 0
2470 endif
2471
2472 zero = where(long(dimfld) LT 0L, N_zero)
2473 if N_zero GT 0 then begin
2474
2475 if N_zero Eq nfld then begin
2476 print,'MRDFITS: Error - All fields have zero length'
2477 return
2478 endif
2479
2480 for i=0, N_zero-1 do begin
2481 print,'MRDFITS: Table column ' + fnames[zero[i]] + ' has zero length'
2482 endfor
2483
2484 nfld = nfld - N_zero
2485 good = where(dimfld GE 0)
2486 fnames = fnames[good]
2487 fvalues = fvalues[good]
2488 typarr = typarr[good] ;Added 2005-1-6 (A.Csillaghy)
2489 tname = tname[good]
2490
2491 endif
2492
2493 if n_elements(vcls) eq 0 and (not scaling) and not keyword_set(columns) then begin
2494
2495 table = mrd_struct(fnames, fvalues, nrow, structyp=structyp, silent=silent )
2496
2497 endif else begin
2498
2499 table = mrd_struct(fnames, fvalues, nrow, silent=silent )
2500
2501 endelse
2502
2503 if not keyword_set(silent) then begin
2504 print, 'MRDFITS: Binary table. ',strcompress(string(nfld)), ' columns by ', $
2505 strcompress(string(nrowp)), ' rows.'
2506 if n_elements(vcls) gt 0 then begin
2507 print, 'MRDFITS: Uses variable length arrays'
2508 endif
2509 endif
2510
2511 outalias = transpose([[tag_names(table)],[tname] ])
2512 status = 0
2513 return
2514
2515 end
2516
2517 function mrdfits, file, extension, header, $
2518 structyp = structyp, $
2519 use_colnum = use_colnum, $
2520 range = range, $
2521 dscale = dscale, fscale=fscale, $
2522 silent = silent, $
2523 columns = columns, $
2524 no_tdim = no_tdim, $
2525 error_action = error_action, $
2526 compress=compress, $
2527 alias=alias, $
2528 rows = rows, $
2529 unsigned=unsigned, $
2530 version=version, $
2531 pointer_var=pointer_var, $
2532 fixed_var=fixed_var, $
2533 outalias = outalias, $
2534 status=status, extnum = extnum
2535
2536 compile_opt idl2
2537 ; Let user know version if MRDFITS being used.
2538 if keyword_set(version) then begin
2539 print,'MRDFITS: Version '+mrd_version()+' Aug 7, 2008'
2540 endif
2541
2542 ;
2543 ; Can't use keyword_set since default is 2, not 0.
2544
2545 if n_elements(error_action) eq 0 then begin
2546 error_action = 2
2547 endif
2548
2549 on_error, error_action
2550
2551
2552
2553 ; Check positional arguments.
2554
2555 if n_params() le 0 or n_params() gt 3 then begin
2556 if keyword_set(version) then return, 0
2557 print, 'MRDFITS: Usage'
2558 print, ' a=mrdfits(file/unit, [exten_no/exten_name, header], /version $'
2559 print, ' /fscale, /dscale, /unsigned, /use_colnum, /silent $'
2560 print, ' range=, rows= , structyp=, columns=, $'
2561 print, ' /pointer_var, /fixed_var, error_action=, status= )'
2562 return, 0
2563 endif
2564
2565 if n_params() eq 1 then extension = 0
2566
2567 ; Check optional arguments.
2568 ;
2569 ; *** Structure name ***
2570
2571 if keyword_set(structyp) then begin
2572 sz = size(structyp)
2573 if sz[0] ne 0 then begin
2574 ; Use first element of array
2575 structyp = structyp[0]
2576 sz = size(structyp[0])
2577 endif
2578
2579 if sz[1] ne 7 then begin
2580 print, 'MRDFITS: stucture type must be a string'
2581 return, 0
2582 endif
2583 endif
2584
2585 ; *** Use column numbers not names?
2586 if not keyword_set(use_colnum) then use_colnum = 0
2587
2588 ; *** Get only a part of the FITS file.
2589 if N_elements(rows) GT 0 then begin
2590 range1 = min(rows,max=range2)
2591 range = [range1,range2]
2592 endif
2593 if keyword_set(range) then begin
2594 if n_elements(range) eq 2 then arange = range $
2595 else if n_elements(range) eq 1 then arange = [0,range[0]-1] $
2596 else if n_elements(range) gt 2 then arange = range[0:1] $
2597 else if n_elements(range) eq 0 then arange = [-1,-1]
2598
2599 endif else begin
2600 arange = [-1,-1]
2601 endelse
2602
2603 arange = long(arange)
2604
2605 ; Open the file and position to the appropriate extension then read
2606 ; the header.
2607
2608 if (N_elements(file) GT 1 ) then begin
2609 print, 'MRDFITS: Vector input not supported'
2610 return, 0
2611 endif
2612
2613 inputUnit = 0
2614
2615 dtype = size(file,/type)
2616 if dtype gt 0 and dtype lt 4 then begin ;File unit number specified
2617
2618 inputUnit = 1
2619 unit = file
2620
2621 if fxmove(unit,extension) lt 0 then begin
2622 return, -1
2623 endif
2624
2625 endif else begin ;File name specified
2626 unit = fxposit(file, extension, compress=compress, $
2627 /readonly,extnum=extnum, errmsg= errmsg)
2628
2629 if unit lt 0 then begin
2630 message, 'File access error',/CON
2631 if errmsg NE '' then message,errmsg,/CON
2632 status = -1
2633 return, 0
2634 endif
2635 endelse
2636
2637 if eof(unit) then begin
2638 message,'ERROR - Extension past EOF',/CON
2639 if inputUnit eq 0 then free_lun,unit
2640 status = -2
2641 return, 0
2642 endif
2643
2644 mrd_hread, unit, header, status, SILENT = silent
2645
2646 if status lt 0 then begin
2647 message, 'ERROR - Unable to read header for extension',/CON
2648 if inputUnit eq 0 then free_lun,unit
2649 return, 0
2650 endif
2651
2652 ; If this is primary array then XTENSION will have value
2653 ; 0 which will be converted by strtrim to '0'
2654
2655 xten = strtrim( fxpar(header,'XTENSION'), 2)
2656 if xten eq '0' or xten eq 'IMAGE' then type = 0 $
2657 else if xten eq 'TABLE' then type = 1 $
2658 else if xten eq 'BINTABLE' or xten eq 'A3DTABLE' then type = 2 $
2659 else begin
2660 message, 'Unable to process extension type:' + strtrim(xten,2),/CON
2661 if inputUnit eq 0 then free_lun,unit
2662 status = -1
2663 return, 0
2664 endelse
2665
2666 scaling = keyword_set(fscale) or keyword_set(dscale)
2667
2668 if type eq 0 then begin
2669
2670 ;*** Images/arrays
2671
2672 mrd_image, header, arange, maxd, rsize, table, scales, offsets, $
2673 scaling, status, silent=silent, unsigned=unsigned, $
2674 rows= rows
2675 if status ge 0 and rsize gt 0 then begin
2676 mrd_read_image, unit, arange, maxd, rsize, table, rows = rows,$
2677 status=status
2678 endif
2679 size = rsize
2680 endif else if type eq 1 then begin
2681
2682 ;*** ASCII tables.
2683
2684 mrd_ascii, header, structyp, use_colnum, $
2685 arange, table, nbytes, nrows, nfld, rows=rows, $
2686 typarr, posarr, lenarr, nullarr, fnames, fvalues, $
2687 scales, offsets, scaling, status, silent=silent, $
2688 columns=columns, alias=alias, outalias=outalias
2689 size = nbytes*nrows
2690
2691 if status ge 0 and size gt 0 then begin
2692
2693 ;*** Read data.
2694 mrd_read_ascii, unit, arange, nbytes, nrows, $
2695 nfld, typarr, posarr, lenarr, nullarr, table, rows= rows
2696
2697 ;*** Extract desired columns.
2698 if status ge 0 and keyword_set(columns) then $
2699 mrd_columns, table, columns, fnames, fvalues, vcls, vtps, $
2700 scales, offsets, scaling, structyp=structyp, silent=silent
2701 endif
2702
2703 endif else begin
2704
2705 ; *** Binary tables.
2706
2707 mrd_table, header, structyp, use_colnum, $
2708 arange, rsize, table, nrows, nfld, typarr, $
2709 fnames, fvalues, vcls, vtpes, scales, offsets, scaling, status, $
2710 silent=silent, columns=columns, no_tdim=no_tdim, $
2711 alias=alias, unsigned=unsigned, rows = rows, outalias = outalias
2712
2713 size = nfld*(arange[1] - arange[0] + 1)
2714 if status ge 0 and size gt 0 then begin
2715
2716 ;*** Read data.
2717 mrd_read_table, unit, arange, rsize, rows = rows, $
2718 structyp, nrows, nfld, typarr, table
2719
2720 if status ge 0 and keyword_set(columns) then begin
2721
2722 ;*** Extract desired columns.
2723 mrd_columns, table, columns, fnames, fvalues, $
2724 vcls, vtpes, scales, offsets, scaling, structyp=structyp, $
2725 silent=silent
2726
2727 endif
2728
2729
2730 if status ge 0 and n_elements(vcls) gt 0 then begin
2731
2732 ;*** Get variable length columns
2733 mrd_read_heap, unit, header, arange, fnames, fvalues, $
2734 vcls, vtpes, table, structyp, scaling, scales, offsets, status, $
2735 silent=silent, pointer_var=pointer_var, fixed_var=fixed_var, rows= rows
2736
2737 endif else begin
2738
2739 ; Skip remainder of last data block
2740 sz = long64(fxpar(header, 'NAXIS1'))* $
2741 long64(fxpar(header,'NAXIS2')) + $
2742 long64(fxpar(header, 'PCOUNT'))
2743 skipB = 2880 - sz mod 2880
2744 if (skipB ne 2880) then mrd_skip, unit, skipB
2745 endelse
2746
2747 endif
2748
2749 endelse
2750
2751
2752 ; Don't tie up a unit number that we allocated in this routine.
2753 if unit gt 0 and inputUnit eq 0 then begin
2754 free_lun, unit
2755 endif
2756
2757 if status ge 0 and scaling and size gt 0 then begin
2758 w = where(scales ne 1.d0 or offsets ne 0.0d0)
2759
2760 ;*** Apply scalings.
2761 if w[0] ne -1 then mrd_scale, type, scales, offsets, table, header, $
2762 fnames, fvalues, 1+arange[1]-arange[0], structyp=structyp, $
2763 dscale=dscale, silent=silent
2764 endif
2765
2766 ; All done. Check the status to see if we ran into problems on the way.
2767
2768 if status ge 0 then return, table else return,0
2769
2770 end