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 |