miriad 4.1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +103 -0
- data/Rakefile +82 -0
- data/ext/bug.c +341 -0
- data/ext/dio.c +317 -0
- data/ext/extconf.rb +49 -0
- data/ext/headio.c +835 -0
- data/ext/hio.c +1515 -0
- data/ext/hio.h +48 -0
- data/ext/interface.c +74 -0
- data/ext/io.h +56 -0
- data/ext/key.c +934 -0
- data/ext/maskio.c +398 -0
- data/ext/maxdimc.h.in +9 -0
- data/ext/miriad.h +371 -0
- data/ext/miriad.i +464 -0
- data/ext/miriad_ruby.c +602 -0
- data/ext/miriad_ruby.i +443 -0
- data/ext/miriad_wrap.c +4210 -0
- data/ext/narray_ruby.swg +59 -0
- data/ext/pack.c +639 -0
- data/ext/scrio.c +132 -0
- data/ext/sysdep.h +185 -0
- data/ext/uvio.c +4934 -0
- data/ext/xyio.c +476 -0
- data/ext/xyzio.c +2020 -0
- data/lib/miriad.rb +564 -0
- metadata +93 -0
data/ext/xyzio.c
ADDED
@@ -0,0 +1,2020 @@
|
|
1
|
+
/*******************************************************************************
|
2
|
+
|
3
|
+
Routines to read and write an image dataset in arbitrary XYZ mode
|
4
|
+
|
5
|
+
History:
|
6
|
+
|
7
|
+
bpw 19-apr-91 Created
|
8
|
+
bpw 01-may-91 Algorithm ready
|
9
|
+
bpw 03-may-91 Ready
|
10
|
+
bpw 19-may-91 Add reverse
|
11
|
+
bpw 20-may-91 Include dummy masking scheme
|
12
|
+
bpw 21-jun-91 Installed
|
13
|
+
bpw 25-jun-91 Created get_buflen function
|
14
|
+
bpw 27-jun-91 Moved FORTRAN-C conversion to xyziowrap.h
|
15
|
+
pjt/mjs 28jul91 Renamed internal variable "max" to "themax" to eliminate
|
16
|
+
conflict with max function.
|
17
|
+
bpw 29-jul-91 Got rid of themax, and made it into sizeof
|
18
|
+
bpw 09-aug-91 Added '-start' to bufend in zero(2)
|
19
|
+
bpw 08-sep-92 Made ndata indeed output variable for xyzread
|
20
|
+
rjs 22-dec-92 Delete inclusion of xyziowrap.h in xyzio.h
|
21
|
+
rjs 23-feb-93 Include maxdimc.h, which includes definition of MAXNAX
|
22
|
+
and MAXBUF. Use MAXBUF. Get rid of xyzio.h
|
23
|
+
bpw 2-mar-93 Add real masking
|
24
|
+
bpw 9-jul-93 Added xyzflush_c and xyzmkbuf_c, and changed buffer
|
25
|
+
allocation scheme to avoid unnecessary allocations
|
26
|
+
bpw 27-jul-93 Fixed allocation bug introduced in previous update
|
27
|
+
(problems for 1-plane datasets)
|
28
|
+
rjs 4-sep-94 Change "word" to "words" to satisfy Cray compiler.
|
29
|
+
rjs 6-nov-94 Change item handle to an integer.
|
30
|
+
bpw 8-dec-94 Adapt two loop in bufferalloc for the fact that since
|
31
|
+
6 nov image handles are no longer in sequence.
|
32
|
+
bpw 12-feb-96 follow rjs to eliminate nested comments (without using
|
33
|
+
tabs)
|
34
|
+
bpw 12-jun-98 for zero(1,tno) set whole cube mask to FALSE
|
35
|
+
pjt 16-nov-00 Fixed a pretty serious problem of bpw mixing up | w/ ||
|
36
|
+
and & w/ &&.
|
37
|
+
Also forced initialized of mask due, there were some
|
38
|
+
side-effects here too if no mask was present
|
39
|
+
(note xyzio writes a mask, even if full mask ok)
|
40
|
+
pjt 11-jun-01 added rjs' 10-jan-96 code changes that seemed lost
|
41
|
+
"Correct comparision bug in bufferallocation routine."
|
42
|
+
pjt 20-jun-02 prototypes for MIR4, made most local stuff now static,
|
43
|
+
largely thanks to Amtrak for a long boring ride NYC-NCR
|
44
|
+
pjt 14-jan-03 cleared up some more prototypes, fixed bug in
|
45
|
+
*s[ITEM_HDR_SIZE] declaration (no pointer, just char)
|
46
|
+
jwr 18-may-05 print address using %p instead of %d
|
47
|
+
|
48
|
+
|
49
|
+
*******************************************************************************/
|
50
|
+
|
51
|
+
/******************************************************************************/
|
52
|
+
/* */
|
53
|
+
/* Declarations */
|
54
|
+
/* */
|
55
|
+
/******************************************************************************/
|
56
|
+
|
57
|
+
#include <stdio.h>
|
58
|
+
#include <string.h>
|
59
|
+
#include <stdlib.h>
|
60
|
+
#include "maxdimc.h"
|
61
|
+
#include "io.h"
|
62
|
+
#include "miriad.h"
|
63
|
+
|
64
|
+
#define check(x) if(x)bugno_c('f',x)
|
65
|
+
|
66
|
+
/* There is only one buffer array, of a length determined at run-time by
|
67
|
+
get_buflen.
|
68
|
+
buffersize is size of the virtual buffer for a particular image,
|
69
|
+
which varies with the number of images handled */
|
70
|
+
static int buffersize;
|
71
|
+
static int allocatebuffer, currentallocation=0, neverfree=FALSE;
|
72
|
+
static float *buffer = NULL;
|
73
|
+
static int *mbuffr = NULL;
|
74
|
+
|
75
|
+
|
76
|
+
/* Most of the code for reading and writing is exactly the same. Where a
|
77
|
+
difference exists MODE (values GET and PUT) is used to discriminate.
|
78
|
+
UP and DOWN are used for copying or reverse copying.
|
79
|
+
ALL is used to see if all axes are reversed. */
|
80
|
+
static int MODE;
|
81
|
+
|
82
|
+
#define GET 0
|
83
|
+
#define PUT 1
|
84
|
+
#define UP 1
|
85
|
+
#define DOWN 2
|
86
|
+
#define ALL 2
|
87
|
+
|
88
|
+
|
89
|
+
/* MAXNAX: maximum number of axes that this can handle.
|
90
|
+
ARRSIZ = MAXNAX+1, so that element 1<->x, 2<->y, etc */
|
91
|
+
#define ARRSIZ MAXNAX+1
|
92
|
+
|
93
|
+
|
94
|
+
/* imgs: dataset info; bufs: buffers info
|
95
|
+
.itno: image handle for hio routines
|
96
|
+
.number: counter of how many datasets were opened before
|
97
|
+
.naxis, .axlen, .cubesize, .blc, .trc: you know
|
98
|
+
.lower, .upper: lower and upper coordval of elements currently in buffer
|
99
|
+
.filfir, .fillas: first and last element from cube currently in buffer
|
100
|
+
.bufstart: abbreviation for -.filfir+tno*buffersize
|
101
|
+
.lastwritten: to see if old data must be read in before writing buffer
|
102
|
+
.nocopy: true if no transposition or region present
|
103
|
+
axnum: relation between axes: i-th axis used to be axis axnum(i)
|
104
|
+
reverse: tells if output data array must be reversed
|
105
|
+
written: to see if buffer must be flushed on a close or new read to same
|
106
|
+
newbuffer: to allow a check if xyzsetup is called more often for a dataset
|
107
|
+
ntno: number of datasets currently opened
|
108
|
+
*/
|
109
|
+
static struct { int itno; char *mask; int number;
|
110
|
+
int naxis, axlen[ARRSIZ], cubesize[ARRSIZ];
|
111
|
+
int blc[ARRSIZ], trc[ARRSIZ];
|
112
|
+
int lower[ARRSIZ], upper[ARRSIZ];
|
113
|
+
int filfir, fillas, bufstart;
|
114
|
+
int lastwritten, nocopy;
|
115
|
+
} imgs[MAXOPEN], bufs[MAXOPEN];
|
116
|
+
static int axnum[MAXOPEN][ARRSIZ];
|
117
|
+
static int reverse[MAXOPEN][ARRSIZ];
|
118
|
+
static int written[MAXOPEN];
|
119
|
+
static int ntno = 0;
|
120
|
+
|
121
|
+
/* loop variables (dim and d) and dimension of subcube */
|
122
|
+
static int dim, d, dimsub[MAXOPEN];
|
123
|
+
|
124
|
+
/* arrays used to limit number of pointer calculations inside big loop
|
125
|
+
in loop_inpbuffer (i.e. remove index [tno]) and to improve readability
|
126
|
+
of the code */
|
127
|
+
static int naxes;
|
128
|
+
static int imgsblc[ARRSIZ], imgstrc[ARRSIZ];
|
129
|
+
static int imgslower[ARRSIZ], imgsupper[ARRSIZ];
|
130
|
+
static int imgsaxlen[ARRSIZ], imgscubesize[ARRSIZ], imgscsz[ARRSIZ];
|
131
|
+
static int bufsblc[ARRSIZ], bufstrc[ARRSIZ];
|
132
|
+
static int bufsaxlen[ARRSIZ], bufscubesize[ARRSIZ], bufscsz[ARRSIZ];
|
133
|
+
static int axnumr[ARRSIZ], inv_axnumr[ARRSIZ], reverses[ARRSIZ];
|
134
|
+
|
135
|
+
|
136
|
+
/* Some variables not used, but left in for the (hopefully never occuring)
|
137
|
+
case that an error occurred and debugging is needed.
|
138
|
+
Most if(.test) statements have been left active. Some, the ones in inner
|
139
|
+
loops, are disabled. They can be found by searching for '/ * $ $' (without spaces) */
|
140
|
+
|
141
|
+
static int itest = 0; /* Information on buffers and datasets */
|
142
|
+
static int otest = 0; /* Information on subcubes */
|
143
|
+
static int rtest = 0; /* Information on each array element */
|
144
|
+
static int vtest = 0; /* Puts numbers in buffer without reading a dataset */
|
145
|
+
static int tcoo[ARRSIZ];
|
146
|
+
static int nfound, i;
|
147
|
+
static char *words[4] = { "get", "put", "filled", "emptied" };
|
148
|
+
static int nio=0;
|
149
|
+
|
150
|
+
/* static functions */
|
151
|
+
static void get_test(int interactive);
|
152
|
+
static int putnio(int x);
|
153
|
+
static void ferr(char *string, int arg);
|
154
|
+
static void get_put_data(int tno, int virpix_off, float *data, int *mask, int *ndata, int dim_sub);
|
155
|
+
static void do_copy(float *bufptr, float *bufend, int DIR, float *data, int *mask);
|
156
|
+
static void manage_buffer(int tno, int virpix_off);
|
157
|
+
static void manage_the_buffer(int tno, int virpix_off);
|
158
|
+
static void get_buflen(void);
|
159
|
+
static int bufferallocation(int n);
|
160
|
+
static void copy_to_one_d(int tno);
|
161
|
+
static void set_bufs_limits(int tno, int virpix_off);
|
162
|
+
static int get_last(int start, int finis);
|
163
|
+
static int check_do_io(int tno, int start, int last);
|
164
|
+
static void find_block(int start, int last, int lower[], int upper[], int axlen[], int cubesize[], int blc[], int trc[], int naxis);
|
165
|
+
static int transform_back(int pix_off);
|
166
|
+
static int c2p(int coords[], int cubesize[], int naxis);
|
167
|
+
static void p2c(int pix_off, int axlen[], int cubesize[], int naxis, int coords[]);
|
168
|
+
static void fill_buffer(int tno, int start, int last);
|
169
|
+
static void empty_buffer(int tno, int start, int last);
|
170
|
+
static void loop_buffer(int tno, int start, int last, int *newstart);
|
171
|
+
static void zero(int bl_tr, int tno);
|
172
|
+
static void testprint(int tno, int virpix_off, int virpix_lst);
|
173
|
+
static void limprint(char *string, int lower[], int upper[]);
|
174
|
+
static void testsearch(int callnr, int coords[], int filoff, int viroff);
|
175
|
+
|
176
|
+
static void get_test(int interactive)
|
177
|
+
{
|
178
|
+
if(interactive)printf("iTest >"); scanf("%d",&itest);
|
179
|
+
if(interactive)printf("rTest >"); scanf("%d",&rtest);
|
180
|
+
if(interactive)printf("oTest >"); scanf("%d",&otest);
|
181
|
+
if(interactive)printf("vTest >"); scanf("%d",&vtest);
|
182
|
+
}
|
183
|
+
|
184
|
+
static int putnio(int x)
|
185
|
+
{
|
186
|
+
return nio;
|
187
|
+
}
|
188
|
+
|
189
|
+
|
190
|
+
/******************************************************************************/
|
191
|
+
/* */
|
192
|
+
/* The FORTRAN-callable routines */
|
193
|
+
/* */
|
194
|
+
/******************************************************************************/
|
195
|
+
|
196
|
+
/** xyzopen -- Open an image file. */
|
197
|
+
/*& bpw */
|
198
|
+
/*: image-i/o */
|
199
|
+
/*+
|
200
|
+
subroutine xyzopen( tno, name, status, naxis, axlen )
|
201
|
+
integer tno
|
202
|
+
character*(*) name
|
203
|
+
character*(*) status
|
204
|
+
integer naxis
|
205
|
+
integer axlen(naxis)
|
206
|
+
|
207
|
+
This opens an image file. For an old file, the number of axes is returned in
|
208
|
+
naxis and the size of each axis in axlen. For a new file, this information is
|
209
|
+
used to define the dataset.
|
210
|
+
Input:
|
211
|
+
name The name of the file to be opened
|
212
|
+
status Either 'old' or 'new'
|
213
|
+
Output:
|
214
|
+
tno The image-file handle
|
215
|
+
Input or Output:
|
216
|
+
naxis For 'old' datasets: in input dimension of array axlen, on
|
217
|
+
output dimension of datacube; for 'new' datasets: dimension
|
218
|
+
of new dataset
|
219
|
+
axlen The length of the axes, output for 'old' datasets, 'input'
|
220
|
+
for 'new' datasets */
|
221
|
+
/*-- */
|
222
|
+
|
223
|
+
void xyzopen_c( int *handle, Const char *name, Const char *status,
|
224
|
+
int *naxis, int *axlen )
|
225
|
+
{
|
226
|
+
/* This accesses the image data (hopen and haccess). Then it checks whether
|
227
|
+
this was an OLD dataset. If so, the naxis. items are read from the header
|
228
|
+
and a check is made on the size of the image file. For a new dataset the
|
229
|
+
information is written out and the file initialized with the "binary item"
|
230
|
+
sequence. Finally the information is stored in the imgs structure for later
|
231
|
+
use.
|
232
|
+
*/
|
233
|
+
#define OLD 1
|
234
|
+
#define NEW 2
|
235
|
+
int access, cubesize, n_axis, tno, iostat;
|
236
|
+
char s[ITEM_HDR_SIZE], axes[8], *mode;
|
237
|
+
static int first=TRUE;
|
238
|
+
|
239
|
+
if(first) { for(tno=0;tno<MAXOPEN;tno++) imgs[tno].itno=0; first=FALSE; }
|
240
|
+
|
241
|
+
if(itest)printf("Open %s; %s; naxis %d\n",name,status,*naxis);
|
242
|
+
n_axis = *naxis;
|
243
|
+
if( !strcmp( "old", status ) ) { access = OLD; mode = "read"; }
|
244
|
+
else if( !strcmp( "new", status ) ) { access = NEW; mode = "write"; }
|
245
|
+
else { bug_c( 'f', "xyzopen: Unrecognised status" ); printf("bug\n"); }
|
246
|
+
|
247
|
+
hopen_c( &tno, name, status, &iostat ); check(iostat);
|
248
|
+
haccess_c( tno, &imgs[tno].itno, "image", mode, &iostat ); check(iostat);
|
249
|
+
imgs[tno].mask = (char *)mkopen_c( tno, "mask", (char *) status );
|
250
|
+
|
251
|
+
strcpy( axes, "naxis0" );
|
252
|
+
if( access == OLD ) {
|
253
|
+
rdhdi_c( tno, "naxis", naxis, 0 );
|
254
|
+
if( *naxis > n_axis ) bug_c('f',"xyzopen: Too many axes for this task");
|
255
|
+
if( *naxis<=0||*naxis>MAXNAX ) bug_c('f',"xyzopen: Bad number of axes");
|
256
|
+
for( cubesize=1, d=0; d<*naxis; d++ ) {
|
257
|
+
axes[5]++; rdhdi_c( tno, axes, &axlen[d], 0 );
|
258
|
+
if( axlen[d] <= 0 ) bug_c( 'f', "xyzopen: Bad image dimension" );
|
259
|
+
cubesize = cubesize * axlen[d];
|
260
|
+
}
|
261
|
+
if( hsize_c( imgs[tno].itno ) < H_REAL_SIZE*cubesize+ITEM_HDR_SIZE )
|
262
|
+
bug_c( 'f', "xyzopen: Image file appears too small" );
|
263
|
+
hreadb_c( imgs[tno].itno, s,0,ITEM_HDR_SIZE, &iostat );
|
264
|
+
check(iostat);
|
265
|
+
if( memcmp( s, real_item, ITEM_HDR_SIZE ) )
|
266
|
+
bug_c( 'f', "xyzopen: Bad image file" );
|
267
|
+
} else {
|
268
|
+
wrhdi_c( tno, "naxis", *naxis );
|
269
|
+
for( d=0; d<*naxis; d++ ) {
|
270
|
+
axes[5]++; wrhdi_c( tno, axes, axlen[d] );
|
271
|
+
}
|
272
|
+
hwriteb_c( imgs[tno].itno, real_item,0,ITEM_HDR_SIZE, &iostat );
|
273
|
+
check(iostat);
|
274
|
+
}
|
275
|
+
|
276
|
+
imgs[tno].naxis = *naxis;
|
277
|
+
imgs[tno].cubesize[0] = 1;
|
278
|
+
imgs[tno].axlen[0] = 1;
|
279
|
+
for( d=1; d<=*naxis; d++ ) {
|
280
|
+
imgs[tno].axlen[d] = axlen[d-1];
|
281
|
+
imgs[tno].cubesize[d] = imgs[tno].cubesize[d-1] * imgs[tno].axlen[d];
|
282
|
+
}
|
283
|
+
if( access == OLD ) imgs[tno].lastwritten = imgs[tno].cubesize[*naxis];
|
284
|
+
else imgs[tno].lastwritten = -1;
|
285
|
+
|
286
|
+
*handle = tno;
|
287
|
+
ntno++;
|
288
|
+
imgs[tno].number = ntno;
|
289
|
+
dimsub[tno] = -1;
|
290
|
+
}
|
291
|
+
|
292
|
+
|
293
|
+
|
294
|
+
/** xyzclose - Close an image file */
|
295
|
+
/*& bpw */
|
296
|
+
/*: image-i/o */
|
297
|
+
/*+
|
298
|
+
subroutine xyzclose( tno )
|
299
|
+
integer tno
|
300
|
+
|
301
|
+
This closes an image file.
|
302
|
+
|
303
|
+
Input:
|
304
|
+
tno: The image-file handle */
|
305
|
+
/*--*/
|
306
|
+
|
307
|
+
void xyzclose_c( int tno )
|
308
|
+
{
|
309
|
+
int iostat;
|
310
|
+
xyzflush_c( tno );
|
311
|
+
hdaccess_c( imgs[tno].itno, &iostat ); check(iostat);
|
312
|
+
if( imgs[tno].mask ) mkclose_c( imgs[tno].mask );
|
313
|
+
hclose_c( tno );
|
314
|
+
ntno--;
|
315
|
+
if( ntno == 0 && !neverfree ) {
|
316
|
+
free( buffer ); buffer = NULL;
|
317
|
+
free( mbuffr ); mbuffr = NULL;
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
/** xyzflush - Force output buffer to be written to disk */
|
322
|
+
/*& bpw */
|
323
|
+
/*: image-i/o */
|
324
|
+
/*+
|
325
|
+
subroutine xyzflush( tno )
|
326
|
+
integer tno
|
327
|
+
|
328
|
+
This flushes the output buffer to disk, just like when closing a dataset.
|
329
|
+
However, the dataset remains open. This is intended for usage where there
|
330
|
+
is a limit on the number of open datasets, so that one cannot have them
|
331
|
+
open all at the same time, and then do all setups once.
|
332
|
+
|
333
|
+
Input:
|
334
|
+
tno: The image-file handle */
|
335
|
+
/*--*/
|
336
|
+
|
337
|
+
void xyzflush_c( int tno )
|
338
|
+
{
|
339
|
+
if( written[tno] ) { MODE=PUT; manage_buffer( tno, -1 ); }
|
340
|
+
written[tno] = FALSE;
|
341
|
+
if( imgs[tno].lastwritten<imgs[tno].cubesize[imgs[tno].naxis] ) zero(2,tno);
|
342
|
+
}
|
343
|
+
|
344
|
+
|
345
|
+
/******************************************************************************/
|
346
|
+
/******************************************************************************/
|
347
|
+
/******************************************************************************/
|
348
|
+
|
349
|
+
/** xyzsetup - Set up arbitrary subcube */
|
350
|
+
/*& bpw */
|
351
|
+
/*: image-i/o */
|
352
|
+
/*+
|
353
|
+
subroutine xyzsetup( tno, subcube, blc, trc, viraxlen, vircubesize )
|
354
|
+
integer tno
|
355
|
+
character*(*) subcube
|
356
|
+
integer blc(*), trc(*)
|
357
|
+
integer viraxlen(*), vircubesize(*)
|
358
|
+
|
359
|
+
This routine does the definitions necessary to allow reading or writing
|
360
|
+
an arbitrary subcube in a n-dimensional datacube. It is used to define
|
361
|
+
which part of an input datacube should be read or which part of an
|
362
|
+
output datacube should be written.
|
363
|
+
|
364
|
+
The variable subcube is used to define the axes of the subcubes to be
|
365
|
+
read or written. The axes of a datacube are called 'x', 'y', 'z', 'a',
|
366
|
+
'b', ... 'subcube' consists of any non-redundant combination of these.
|
367
|
+
Zero-dimensional subcubes, i.e. single pixels, are specified by setting
|
368
|
+
'subcube' to ' '. 'subcube' can be e.g. 'z' to read/write lines in the
|
369
|
+
z-direction, 'xy' to read/write image planes or 'xyz' to read/write a
|
370
|
+
3-d subcube. Permutations (like 'zx') are also permitted. These will be
|
371
|
+
reflected in the ordering of the output array produced by subroutine
|
372
|
+
xyzread. Axis reversals are also possible, and are set up by preceding
|
373
|
+
the axis name with a '-'. Again, this will be reflected in the ordering
|
374
|
+
of elements in the output array of xyzread.
|
375
|
+
If xyzsetup is used to define an output cube, the subcube variable
|
376
|
+
should be interpreted as giving the names of the axes in the virtual
|
377
|
+
cube. E.g., for subcube='z', the first axis in the virtual cube is the
|
378
|
+
z-axis of the output cube. The second axis then is the 'x' axis, etc.
|
379
|
+
|
380
|
+
blc and trc give the bottom left and top right corner of the total
|
381
|
+
region of the input cube that needs to be worked on (in absolute pixels,
|
382
|
+
i.e. the bottom left of the original cube is 1,1,...), or the total
|
383
|
+
region of the output cube that should be written. If the output cube
|
384
|
+
did not yet exist and the region is smaller than the defined size of
|
385
|
+
the cube, the pixels outside the region are set to zero automatically.
|
386
|
+
|
387
|
+
viraxlen and vircubesize are provided for the convenience of the
|
388
|
+
programmer. They correspond to a virtual cube, whose axes are permuted
|
389
|
+
according to the specification of 'subcube', and whose axislengths are
|
390
|
+
given by the differences of blc and trc. This virtual (intermediate)
|
391
|
+
cube contains all the pixels on which the calling program should work,
|
392
|
+
sorted in the order in which they are needed.
|
393
|
+
|
394
|
+
With a call to xyzsetup all previous buffers are irrevocably lost; but
|
395
|
+
output buffers are flushed before that. However, all calls to xyzsetup
|
396
|
+
should be done before working on the data.
|
397
|
+
|
398
|
+
Input:
|
399
|
+
tno image file handle
|
400
|
+
subcube a character variable defining the subcube type
|
401
|
+
blc, trc arrays giving the bottom left and top right corner
|
402
|
+
of the region in the input/output cube to work on/
|
403
|
+
write; the number of elements used equals the
|
404
|
+
dimension of the input/output cube
|
405
|
+
Output:
|
406
|
+
viraxlen: length of axes of virtual cube
|
407
|
+
vircubesize: size of subcubes:
|
408
|
+
vircubesize(d) = Prod(i=1->d) viraxlen(i) */
|
409
|
+
/*--*/
|
410
|
+
|
411
|
+
void xyzsetup_c( int tno, Const char *subcube, Const int *blc, Const int *trc,
|
412
|
+
int *viraxlen, int *vircubesize )
|
413
|
+
{
|
414
|
+
/* This initializes some information needed later. It keeps separate values
|
415
|
+
for each tno that was opened.
|
416
|
+
dimsub: dimension of subcube
|
417
|
+
axnum: relation between axes
|
418
|
+
imgs.blc, imgs.trc: lower left and upper right used from input or
|
419
|
+
written to output
|
420
|
+
bufs.axlen: length of virtual axes
|
421
|
+
imgs/bufs.cubesize: cs(i) = (Prod)(d<i) axlen(d): # pix in line/plane etc
|
422
|
+
viraxlen, vircubesize: info returned to caller
|
423
|
+
*/
|
424
|
+
|
425
|
+
int axisuse[ARRSIZ]; char *axisnames = { "xyzabcdefghij" };
|
426
|
+
char *sub_cube; int reversal;
|
427
|
+
int naxes;
|
428
|
+
|
429
|
+
/* Because a new call to xyzsetup redefines all buffers, they are flushed
|
430
|
+
before the redefinition is done */
|
431
|
+
for( i=0; i<MAXOPEN; i++ ) {
|
432
|
+
if( written[i] ) { MODE=PUT; manage_buffer( i, -1 ); }
|
433
|
+
written[i] = FALSE;
|
434
|
+
}
|
435
|
+
|
436
|
+
/* Intermediate variable for easier reading */
|
437
|
+
naxes = imgs[tno].naxis;
|
438
|
+
|
439
|
+
/* Decode subcube argument into dimsub, and axnum and reverse arrays */
|
440
|
+
dim=0;
|
441
|
+
for( d=1;d<=MAXNAX;d++ ) axisuse[d]=FALSE;
|
442
|
+
reversal=FALSE;
|
443
|
+
sub_cube=(char *)subcube;
|
444
|
+
while( *subcube ) {
|
445
|
+
if( *subcube == ' ' ) { ;
|
446
|
+
} else if( *subcube == '-' ) {
|
447
|
+
if( reversal ) bug_c( 'f', "xyzsetup: Bad syntax for subcube arg" );
|
448
|
+
reversal=TRUE; if(itest)printf("reversal");
|
449
|
+
} else {
|
450
|
+
d=1;
|
451
|
+
while( *subcube != *(axisnames+d-1) && d<=naxes && *axisnames ) d++;
|
452
|
+
if( d>naxes || !*axisnames )
|
453
|
+
ferr( "xyzsetup: Axis outside cube", *subcube );
|
454
|
+
if(axisuse[d])ferr("xyzsetup: Axis given more than once",*subcube);
|
455
|
+
dim++;
|
456
|
+
axisuse[d]=TRUE; reverse[tno][dim]=reversal; axnum[tno][dim]=d;
|
457
|
+
reversal=FALSE;
|
458
|
+
}
|
459
|
+
subcube++;
|
460
|
+
}
|
461
|
+
dimsub[tno] = dim;
|
462
|
+
subcube = sub_cube;
|
463
|
+
/* Fill out the arrays axnum and reverse, so that all elements are defined */
|
464
|
+
for( reverse[tno][0]=FALSE, d=0, dim=1; dim<=dimsub[tno]; dim++ ) {
|
465
|
+
if( reverse[tno][dim] ) { reverse[tno][0]=TRUE; d++; } }
|
466
|
+
if( d == dimsub[tno] ) reverse[tno][0]=ALL;
|
467
|
+
for( d=1; d<=MAXNAX; d++ ) { if( !axisuse[d] ) {
|
468
|
+
axnum[tno][dim]=d; reverse[tno][dim]=FALSE; dim++; } }
|
469
|
+
|
470
|
+
/* Save blc and trc */
|
471
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
472
|
+
if( ( blc[dim-1] < 1 ) || ( trc[dim-1] > imgs[tno].axlen[dim] ) )
|
473
|
+
bug_c( 'f', "xyzsetup: Subcube blc and/or trc outside range" );
|
474
|
+
imgs[tno].blc[dim] = blc[dim-1]-1;
|
475
|
+
imgs[tno].trc[dim] = trc[dim-1]-1;
|
476
|
+
}
|
477
|
+
|
478
|
+
/* Save axislengths and cubesizes */
|
479
|
+
bufs[tno].naxis = naxes;
|
480
|
+
bufs[tno].axlen[0] = 1;
|
481
|
+
bufs[tno].cubesize[0] = 1;
|
482
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
483
|
+
bufs[tno].axlen[dim] = imgs[tno].trc[ axnum[tno][dim] ] -
|
484
|
+
imgs[tno].blc[ axnum[tno][dim] ] + 1;
|
485
|
+
}
|
486
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
487
|
+
bufs[tno].cubesize[dim]=bufs[tno].cubesize[dim-1]*bufs[tno].axlen[dim];
|
488
|
+
}
|
489
|
+
|
490
|
+
/* More initializations:
|
491
|
+
pointers to window in file that is in buffer;
|
492
|
+
variable indicating if write buffer was filled;
|
493
|
+
variable indicating if any transposition must be done; */
|
494
|
+
for( d=0; d<MAXOPEN; d++ ) { bufs[d].filfir = -1; bufs[d].fillas = -1; }
|
495
|
+
written[tno] = FALSE;
|
496
|
+
imgs[tno].nocopy = TRUE;
|
497
|
+
for( dim=1; dim<=naxes; dim++ )
|
498
|
+
if( dim != axnum[tno][dim] ) imgs[tno].nocopy = FALSE;
|
499
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
500
|
+
if( blc[dim-1] != 1 || trc[dim-1] != imgs[tno].axlen[dim] )
|
501
|
+
imgs[tno].nocopy = FALSE;
|
502
|
+
}
|
503
|
+
|
504
|
+
/* Some info for the caller */
|
505
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
506
|
+
viraxlen[dim-1] = bufs[tno].axlen[dim];
|
507
|
+
vircubesize[dim-1] = bufs[tno].cubesize[dim];
|
508
|
+
}
|
509
|
+
|
510
|
+
/* Set flag so that manage_buffer knows it has to (re)calculate the
|
511
|
+
buffersize */
|
512
|
+
allocatebuffer = TRUE;
|
513
|
+
|
514
|
+
/* Testoutput only */
|
515
|
+
if(itest){
|
516
|
+
printf("tno %d\n",tno);
|
517
|
+
printf("d incsz vircsz inaxlen viraxlen axnum\n");
|
518
|
+
for( dim=1; dim<=naxes; dim++ )
|
519
|
+
printf("%d %10d %10d %10d %10d %10d\n",
|
520
|
+
dim, imgs[tno].cubesize[dim],bufs[tno].cubesize[dim],
|
521
|
+
imgs[tno].axlen[dim], viraxlen[dim-1], axnum[tno][dim]);
|
522
|
+
}
|
523
|
+
|
524
|
+
}
|
525
|
+
|
526
|
+
static void ferr( char *string, int arg )
|
527
|
+
{
|
528
|
+
char message[80]; char *msg;
|
529
|
+
msg = &message[0];
|
530
|
+
while( *string != '\0' ) *msg++ = *string++;
|
531
|
+
*msg++ = ':'; *msg++ = ' '; *msg++ = arg; *msg = '\0';
|
532
|
+
bug_c( 'f', message );
|
533
|
+
}
|
534
|
+
|
535
|
+
|
536
|
+
/******************************************************************************/
|
537
|
+
/******************************************************************************/
|
538
|
+
/******************************************************************************/
|
539
|
+
|
540
|
+
/** xyzmkbuf - create the i/o buffer (only once) */
|
541
|
+
/*& bpw */
|
542
|
+
/*: image-i/o */
|
543
|
+
/*++
|
544
|
+
subroutine xyzmkbuf
|
545
|
+
|
546
|
+
Usually, xyzio tries to be smart about allocating its own buffer and tries
|
547
|
+
to minimize its memory use. This works well if all calls to xyzsetup can
|
548
|
+
be done before any reading or writing is done. However, it may allocate
|
549
|
+
too much memory if calls to xyzsetup are followed by calls to xyzclose so
|
550
|
+
that all datasets are closed, and then more opens and setups are done. To
|
551
|
+
circumvent this, xyzmkbuf creates an i/o buffer of maximum size, and makes
|
552
|
+
sure it is never deallocated. */
|
553
|
+
/*--*/
|
554
|
+
|
555
|
+
void xyzmkbuf_c()
|
556
|
+
{
|
557
|
+
int i;
|
558
|
+
i = bufferallocation( MAXBUF );
|
559
|
+
neverfree = TRUE;
|
560
|
+
}
|
561
|
+
|
562
|
+
/******************************************************************************/
|
563
|
+
/******************************************************************************/
|
564
|
+
/******************************************************************************/
|
565
|
+
|
566
|
+
/** xyzs2c - Get the fixed coordinates for a given subcube */
|
567
|
+
/*& bpw */
|
568
|
+
/*: image-i/o */
|
569
|
+
/*++
|
570
|
+
subroutine xyzs2c( tno, subcubenr, coords )
|
571
|
+
integer tno
|
572
|
+
integer subcubenr
|
573
|
+
integer coords(*)
|
574
|
+
|
575
|
+
This routine, xyzsetup and xyzread/xyzwrite work together to allow
|
576
|
+
reading/writing an arbitrary subcube in a n-dimensional datacube.
|
577
|
+
xyzs2c calculates the fixed coordinates of a particular subcube.
|
578
|
+
xyzsetup defines a particular type of subcube in a datacube, e.g. line
|
579
|
+
profiles in the z-direction. For a given subcube there are varying (z
|
580
|
+
in the example) and fixed coordinates. The subcubes are ordered along
|
581
|
+
the fixed-coordinate axes: the first subcube has (x=1,y=1), the second
|
582
|
+
has (x=2,y=1), etc. xyzs2c returns the values of the fixed coordinates
|
583
|
+
for a given subcubenumber. These can then be used as input to xyzread
|
584
|
+
or xyzwrite.
|
585
|
+
|
586
|
+
Input:
|
587
|
+
tno The handle of the dataset
|
588
|
+
subcubenr Identification of the subcube
|
589
|
+
Output:
|
590
|
+
coords Coordinates of the blc of the subcube */
|
591
|
+
/*--*/
|
592
|
+
|
593
|
+
void xyzs2c_c( int tno, int subcubenr, int *coords )
|
594
|
+
{
|
595
|
+
/* Calculates fixed coordinates of subcubenr:
|
596
|
+
first calculate pixeloffset of lower left of subcube; convert to
|
597
|
+
coordinates using virtual cube specifications; then add appropriate
|
598
|
+
lower left offset of input and shift so that first element is first
|
599
|
+
fixed axis.
|
600
|
+
*/
|
601
|
+
int dim_sub, naxes, offset;
|
602
|
+
int coo[ARRSIZ];
|
603
|
+
|
604
|
+
dim_sub = dimsub[tno];
|
605
|
+
naxes = bufs[tno].naxis;
|
606
|
+
offset = subcubenr * bufs[tno].cubesize[dim_sub];
|
607
|
+
if( offset < 0 || offset >= bufs[tno].cubesize[naxes] )
|
608
|
+
bug_c( 'f', "xyzs2c: Subcube lies outside cube" );
|
609
|
+
p2c( offset, bufs[tno].axlen, bufs[tno].cubesize, naxes, coo );
|
610
|
+
dim = dim_sub+1;
|
611
|
+
while( dim<=naxes ) {
|
612
|
+
coords[dim-dim_sub-1] = coo[dim] + imgs[tno].blc[axnum[tno][dim]] + 1;
|
613
|
+
dim++; }
|
614
|
+
|
615
|
+
if(otest) {
|
616
|
+
printf( "\nsubcubenr %d starts at vircube coords:", subcubenr );
|
617
|
+
for( dim=1; dim<=naxes; dim++ ) printf(" %d",coo[dim]);
|
618
|
+
printf( "; orig. cube coords:" );
|
619
|
+
for( dim=0; dim<naxes-dim_sub; dim++ ) printf( " %d", coords[dim]-1 );
|
620
|
+
printf( "\nvir filfir %d fillas %d virpix_off %d\n",
|
621
|
+
bufs[tno].filfir, bufs[tno].fillas, offset );
|
622
|
+
}
|
623
|
+
}
|
624
|
+
|
625
|
+
|
626
|
+
/******************************************************************************/
|
627
|
+
|
628
|
+
/** xyzc2s - Get the subcubenr at a fixed coordinate */
|
629
|
+
/*& bpw */
|
630
|
+
/*: image-i/o */
|
631
|
+
/*++
|
632
|
+
subroutine xyzc2s( tno, coords, subcubenr )
|
633
|
+
integer tno
|
634
|
+
integer coords(*)
|
635
|
+
integer subcubenr
|
636
|
+
|
637
|
+
This routine does the inverse of xyzs2c: it calculates the subcubenr
|
638
|
+
from a list of coordinates for a previously opened dataset after a
|
639
|
+
call to xyzsetup to define a particular type of subcube in a datacube.
|
640
|
+
|
641
|
+
Input:
|
642
|
+
tno The handle of the dataset
|
643
|
+
coords Coordinates of the blc of the subcube
|
644
|
+
Output:
|
645
|
+
subcubenr Identification of the subcube */
|
646
|
+
/*--*/
|
647
|
+
|
648
|
+
void xyzc2s_c(int tno, Const int *coords, int *subcubenr )
|
649
|
+
{
|
650
|
+
/* Calculates subcubenr at fixed coordinates:
|
651
|
+
Convert coordinates to virtual-cube coordinates, then calculate
|
652
|
+
virtual-cube offset and divide by subcubelength.
|
653
|
+
*/
|
654
|
+
int dim_sub, naxes, offset;
|
655
|
+
int coo[ARRSIZ];
|
656
|
+
|
657
|
+
dim_sub = dimsub[tno];
|
658
|
+
naxes = bufs[tno].naxis;
|
659
|
+
for( dim=1; dim<=dim_sub; dim++ ) coo[dim] = 0;
|
660
|
+
dim = 0;
|
661
|
+
while( dim < naxes-dim_sub ) {
|
662
|
+
coo[axnum[tno][dim+dim_sub+1]] = coords[dim] - imgs[tno].blc[dim] - 1;
|
663
|
+
dim++; }
|
664
|
+
offset = c2p( coo, bufs[tno].cubesize, naxes );
|
665
|
+
if( offset < 0 || offset >= bufs[tno].cubesize[naxes] )
|
666
|
+
bug_c( 'f', "xyzc2s: Coordinates lie outside cube" );
|
667
|
+
*subcubenr = offset / bufs[tno].cubesize[dim_sub];
|
668
|
+
|
669
|
+
if(itest) {
|
670
|
+
printf( "\ncoords" );
|
671
|
+
for( dim=1; dim<=naxes; dim++ ) printf(" %d",coo[dim]);
|
672
|
+
printf( " are for subcubenr %d:", *subcubenr );
|
673
|
+
printf( "; orig. cube coords:" );
|
674
|
+
for( dim=0; dim<naxes-dim_sub; dim++ ) printf( " %d", coords[dim]-1 );
|
675
|
+
printf( "\nvir filfir %d fillas %d virpix_off %d\n",
|
676
|
+
bufs[tno].filfir, bufs[tno].fillas, offset );
|
677
|
+
}
|
678
|
+
}
|
679
|
+
|
680
|
+
|
681
|
+
/******************************************************************************/
|
682
|
+
/******************************************************************************/
|
683
|
+
/******************************************************************************/
|
684
|
+
|
685
|
+
/** xyzread - Read arbitrary subcube */
|
686
|
+
/*& bpw */
|
687
|
+
/*: image-i/o */
|
688
|
+
/*+
|
689
|
+
subroutine xyzread( tno, coords, data, mask, ndata )
|
690
|
+
integer tno
|
691
|
+
integer coords(*)
|
692
|
+
real data(*)
|
693
|
+
logical mask(*)
|
694
|
+
integer ndata
|
695
|
+
|
696
|
+
This routine, xyzsetup and xyzs2c work together to allow reading an
|
697
|
+
arbitrary subcube in a n-dimensional datacube. xyzread reads a subcube
|
698
|
+
from the datacube, as defined by xyzsetup at coordinates calculated by
|
699
|
+
xyzs2c.
|
700
|
+
|
701
|
+
The array coords gives the coordinates of the axes complementary to the
|
702
|
+
subcube axes. E.g., if 'subcube' in the call to xyzsetup was 'y' and
|
703
|
+
the datacube is 3-dimensional, coords(1) and coords(2) give the 'x' and
|
704
|
+
'z' coordinate of the requested line profile, respectively. Or, if
|
705
|
+
'subcube' was 'xz', coords(1) gives the 'y'-coordinate of the plane.
|
706
|
+
For a datacube of dimension 'd', only the first 'd - dimsub' elements
|
707
|
+
of the array coords will be used (where 'dimsub' is the dimension of
|
708
|
+
the subcube).
|
709
|
+
|
710
|
+
The array data (of dimension ndata) will hold the requested information.
|
711
|
+
If the subcube was 0-dimensional, the result is the pixel value. For a
|
712
|
+
1-d subcube the profile is returned in data. The number of returned
|
713
|
+
elements is vircubesize(1), as returned by xyzsetup. For a 2-d subcube
|
714
|
+
the array data gives the requested plane, as a 1-d array of length
|
715
|
+
vircubesize(2). Etc.
|
716
|
+
|
717
|
+
The mask array indicates if pixels in the data array were undefined
|
718
|
+
(a TRUE value means the pixel is OK). Element 1 corresponds to data(1),
|
719
|
+
etc.
|
720
|
+
(this is not yet implemented, so all elements are returned as TRUE).
|
721
|
+
|
722
|
+
N.B.: to scan a datacube pixel by pixel it is more efficient to use
|
723
|
+
subroutine xyzpixrd instead of xyzread, as the conversion from offset to
|
724
|
+
coordinates to offset that xyzs2c and xyzread do then is superfluous and
|
725
|
+
time-consuming.
|
726
|
+
|
727
|
+
Input:
|
728
|
+
tno image file handle
|
729
|
+
coords array of which the first (dim cube)-(dim subcube)
|
730
|
+
elements are used, giving the coordinate values
|
731
|
+
along the complementary axes
|
732
|
+
Output:
|
733
|
+
data array containing data read in
|
734
|
+
mask FALSE values indicate undefined pixels
|
735
|
+
ndata number of elements read */
|
736
|
+
/*--*/
|
737
|
+
|
738
|
+
void xyzread_c(int tno, Const int *coords, float *data, int *mask, int *ndata )
|
739
|
+
{
|
740
|
+
/* The calculation first needs the pixeloffset of the input coordinate.
|
741
|
+
For the varying axes the pixelnumber is 0, for the fixed axes of the
|
742
|
+
subcube, the pixelnumber is the input minus the lower left offset.
|
743
|
+
The input array had the first fixed coordinate as element 0, so a
|
744
|
+
shift of -1 is necessary. After finding the pixelnumber in the virtual
|
745
|
+
cube get_put_data is used.
|
746
|
+
*/
|
747
|
+
int virpix_off;
|
748
|
+
int dim_sub, naxes;
|
749
|
+
dim_sub = dimsub[tno];
|
750
|
+
naxes = bufs[tno].naxis;
|
751
|
+
virpix_off = 0;
|
752
|
+
dim = dim_sub+1;
|
753
|
+
while( dim <= naxes ) {
|
754
|
+
virpix_off += bufs[tno].cubesize[dim-1] *
|
755
|
+
( coords[dim-dim_sub-1]-1 - imgs[tno].blc[ axnum[tno][dim] ] );
|
756
|
+
dim++; }
|
757
|
+
MODE=GET; get_put_data( tno, virpix_off, data, mask, ndata, dim_sub );
|
758
|
+
}
|
759
|
+
|
760
|
+
|
761
|
+
|
762
|
+
/** xyzpixrd - Get a pixel from a dataset */
|
763
|
+
/*& bpw */
|
764
|
+
/*: image-i/o */
|
765
|
+
/*+
|
766
|
+
subroutine xyzpixrd( tno, pixelnr, value, mask )
|
767
|
+
integer tno
|
768
|
+
integer pixelnr
|
769
|
+
logical mask
|
770
|
+
real value
|
771
|
+
|
772
|
+
This routine provides a faster version of calls to xyzs2c and xyzread
|
773
|
+
for the case that the calling program needs single pixels. It should
|
774
|
+
be used after a call to xyzsetup was used to set up zero-dimensional
|
775
|
+
subcubes. The calling program can then loop over all pixels (from 1 to
|
776
|
+
vircubesize(naxis)). xyzpixrd takes care of reading the datacube.
|
777
|
+
Using this routine instead of xyzs2c and xyzread reduces the overhead
|
778
|
+
by more than a factor 10.
|
779
|
+
|
780
|
+
Input:
|
781
|
+
tno image file handle
|
782
|
+
pixelnr pixelnr to be read from virtual cube
|
783
|
+
|
784
|
+
Output:
|
785
|
+
value pixel value
|
786
|
+
mask FALSE if pixel was undefined */
|
787
|
+
/*--*/
|
788
|
+
|
789
|
+
void xyzpixrd_c(int tno, int pixelnr, float *data, int *mask)
|
790
|
+
{
|
791
|
+
int virpix_off;
|
792
|
+
#ifdef XYZ_DEBUG
|
793
|
+
if(otest) xyzs2c_c( tno, pixelnr-1, tcoo );
|
794
|
+
#endif
|
795
|
+
virpix_off = pixelnr - 1;
|
796
|
+
if( virpix_off < bufs[tno].filfir || virpix_off > bufs[tno].fillas ) {
|
797
|
+
MODE=GET; manage_buffer( tno, virpix_off );
|
798
|
+
}
|
799
|
+
*data = *( buffer + bufs[tno].bufstart + virpix_off );
|
800
|
+
*mask = *( mbuffr + bufs[tno].bufstart + virpix_off );
|
801
|
+
#ifdef XYZ_DEBUG
|
802
|
+
if(otest) testprint( tno, virpix_off, virpix_off );
|
803
|
+
#endif
|
804
|
+
}
|
805
|
+
|
806
|
+
|
807
|
+
|
808
|
+
/** xyzprfrd - Get a profile from a dataset */
|
809
|
+
/*& bpw */
|
810
|
+
/*: image-i/o */
|
811
|
+
/*+
|
812
|
+
subroutine xyzprfrd( tno, profilenr, profile, mask, ndata )
|
813
|
+
integer tno
|
814
|
+
integer profilenr
|
815
|
+
real profile(*)
|
816
|
+
logical mask(*)
|
817
|
+
integer ndata
|
818
|
+
|
819
|
+
This routine provides a (little) faster version for calls to xyzs2c and
|
820
|
+
xyzread for the case that the calling program needs profiles. It should
|
821
|
+
be used after a call to xyzsetup was used to set up one-dimensional
|
822
|
+
subcubes. The calling program can then loop over all profiles (from 1 to
|
823
|
+
vircubesize(naxis)/vircubesize(1)). xyzprfrd takes care of reading the
|
824
|
+
datacube. Using this routine instead of xyzs2c and xyzread reduces the
|
825
|
+
overhead by 10% (for 256-long profiles) to 30% (for 64-long profiles).
|
826
|
+
|
827
|
+
Input:
|
828
|
+
tno image file handle
|
829
|
+
profilenr profile nr to be read from virtual cube
|
830
|
+
Output:
|
831
|
+
profile will contain the profile
|
832
|
+
mask FALSE values indicate undefined pixels
|
833
|
+
ndata number of elements read */
|
834
|
+
/*--*/
|
835
|
+
|
836
|
+
void xyzprfrd_c(int tno, int profilenr, float *data, int *mask, int *ndata )
|
837
|
+
{
|
838
|
+
int virpix_off;
|
839
|
+
#ifdef XYZ_DEBUG
|
840
|
+
if(otest) xyzs2c_c( tno, profilenr-1, tcoo );
|
841
|
+
#endif
|
842
|
+
virpix_off = (profilenr-1) * bufs[tno].cubesize[1];
|
843
|
+
MODE=GET; get_put_data( tno, virpix_off, data, mask, ndata, 1 );
|
844
|
+
}
|
845
|
+
|
846
|
+
|
847
|
+
|
848
|
+
/** xyzplnrd - Get a plane from a dataset */
|
849
|
+
/*& bpw */
|
850
|
+
/*: image-i/o */
|
851
|
+
/*+
|
852
|
+
subroutine xyzplnrd( tno, planenr, plane, mask, ndata )
|
853
|
+
integer tno
|
854
|
+
integer planenr
|
855
|
+
real plane(*)
|
856
|
+
logical mask(*)
|
857
|
+
integer ndata
|
858
|
+
|
859
|
+
This routine provides a more convenient version of calls to xyzs2c and
|
860
|
+
xyzread for the case that the calling program needs planes. It should
|
861
|
+
be used after a call to xyzsetup was used to set up two-dimensional
|
862
|
+
subcubes. The calling program can then loop over all planes (from 1 to
|
863
|
+
vircubesize(naxis)/vircubesize(2)). xyzplnrd takes care of reading the
|
864
|
+
datacube. The caveat is that the calling program should have an array
|
865
|
+
that is large enough to contain the complete plane.
|
866
|
+
Using this routine instead of xyzs2c and xyzread reduces the overhead
|
867
|
+
by 1% (for 64**2 cubes) or less.
|
868
|
+
|
869
|
+
Input:
|
870
|
+
tno image file handle
|
871
|
+
planenr plane nr to be read from virtual-cube
|
872
|
+
Output:
|
873
|
+
plane will contain the plane as a 1-d array
|
874
|
+
mask FALSE values indicate undefined pixels
|
875
|
+
ndata number of elements read */
|
876
|
+
/*--*/
|
877
|
+
|
878
|
+
void xyzplnrd_c(int tno, int planenr, float *data, int *mask, int *ndata)
|
879
|
+
{
|
880
|
+
int virpix_off;
|
881
|
+
#ifdef XYZ_DEBUG
|
882
|
+
if(otest) xyzs2c_c( tno, planenr-1, tcoo );
|
883
|
+
#endif
|
884
|
+
virpix_off = (planenr-1) * bufs[tno].cubesize[2];
|
885
|
+
MODE=GET; get_put_data( tno, virpix_off, data, mask, ndata, 2 );
|
886
|
+
}
|
887
|
+
|
888
|
+
/******************************************************************************/
|
889
|
+
/******************************************************************************/
|
890
|
+
/******************************************************************************/
|
891
|
+
|
892
|
+
/** xyzwrite - Write arbitrary subcube */
|
893
|
+
/*& bpw */
|
894
|
+
/*: image-i/o */
|
895
|
+
/*+
|
896
|
+
subroutine xyzwrite( tno, coords, data, mask, ndata )
|
897
|
+
integer tno
|
898
|
+
integer coords(*)
|
899
|
+
real data(*)
|
900
|
+
logical mask(*)
|
901
|
+
integer ndata
|
902
|
+
|
903
|
+
This routine, xyzsetup and xyzs2c work together to allow writing an
|
904
|
+
arbitrary subcube in a n-dimensional datacube. xyzwrite writes a subcube
|
905
|
+
to the datacube, as defined by xyzsetup at coordinates calculated by
|
906
|
+
xyzs2c.
|
907
|
+
|
908
|
+
The array coords gives the coordinates of the axes complementary to
|
909
|
+
the subcube axes. E.g., if 'subcube' in the call to xyzsetup was 'y'
|
910
|
+
and the datacube is 3-dimensional, coords(1) and coords(2) give the
|
911
|
+
'x' and 'z' coordinate of the requested line profile, respectively. Or,
|
912
|
+
if 'subcube' was 'xz', coords(1) gives the 'y'-coordinate of the plane.
|
913
|
+
For a datacube of dimension 'd', only the first 'd - dimsub' elements
|
914
|
+
of the array coords will be used (where 'dimsub' is the dimension of the
|
915
|
+
subcube).
|
916
|
+
|
917
|
+
The array data (of dimension ndata) holds the information to be written.
|
918
|
+
If the subcube was 0-dimensional, the first element of data is written.
|
919
|
+
For a 1-d subcube a profile is written. The first vircubesize(1) (as
|
920
|
+
returned by xyzsetup) elements of data are used. For a 2-d subcube the
|
921
|
+
array data gives the requested plane, as a 1-d array of length
|
922
|
+
vircubesize(2). Etc.
|
923
|
+
|
924
|
+
The mask array indicates if pixels in the data array must be set to
|
925
|
+
"undefined". A TRUE value means the data is OK, FALSE means it is
|
926
|
+
undefined. Element 1 corresponds to data 1, etc.
|
927
|
+
(this is not yet implemented, so ignored)
|
928
|
+
|
929
|
+
N.B.: to write a datacube pixel by pixel it is more efficient to use
|
930
|
+
subroutine xyzpixwr instead of xyzwrite, as the conversion from
|
931
|
+
offset to coordinates to offset that xyzs2c and xyzwrite do then is
|
932
|
+
superfluous and time-consuming.
|
933
|
+
|
934
|
+
Input:
|
935
|
+
tno image file handle
|
936
|
+
coords array of which the first (dim cube)-(dim subcube)
|
937
|
+
elements are used, giving the coordinate values
|
938
|
+
along the complementary axes
|
939
|
+
data array containing data to be written
|
940
|
+
mask FALSE values indicate undefined pixel
|
941
|
+
ndata number of elements to write */
|
942
|
+
/*--*/
|
943
|
+
|
944
|
+
void xyzwrite_c(int tno, Const int *coords, Const float *data,
|
945
|
+
Const int *mask, Const int *ndata )
|
946
|
+
{
|
947
|
+
/* The calculation first needs the pixeloffset of the input coordinate.
|
948
|
+
For the varying axes the pixelnumber is 0, for the fixed axes of the
|
949
|
+
subcube, the pixelnumber is the input minus the lower left offset.
|
950
|
+
The input array had the first fixed coordinate as element 0, so a
|
951
|
+
shift of -1 is necessary. After finding the pixelnumber in the
|
952
|
+
virtual cube get_put_data is used.
|
953
|
+
*/
|
954
|
+
int virpix_off;
|
955
|
+
int dim_sub, naxes;
|
956
|
+
dim_sub = dimsub[tno];
|
957
|
+
naxes = bufs[tno].naxis;
|
958
|
+
virpix_off = 0;
|
959
|
+
dim = dim_sub+1;
|
960
|
+
while( dim <= naxes ) {
|
961
|
+
virpix_off += bufs[tno].cubesize[dim-1] *
|
962
|
+
( coords[dim-dim_sub-1]-1 - imgs[tno].blc[ axnum[tno][dim] ] );
|
963
|
+
dim++; }
|
964
|
+
MODE=PUT;
|
965
|
+
get_put_data( tno, virpix_off, (float *)data, (int *)mask, (int *)ndata, dim_sub );
|
966
|
+
}
|
967
|
+
|
968
|
+
|
969
|
+
|
970
|
+
/** xyzpixwr - Write a pixel to a dataset */
|
971
|
+
/*& bpw */
|
972
|
+
/*: image-i/o */
|
973
|
+
/*+
|
974
|
+
subroutine xyzpixwr( tno, pixelnr, value, mask )
|
975
|
+
integer tno
|
976
|
+
integer pixelnr
|
977
|
+
real value
|
978
|
+
logical mask
|
979
|
+
|
980
|
+
This routine provides a faster version of calls to xyzs2c and xyzwrite
|
981
|
+
for the case that the calling program provides single pixels. It should
|
982
|
+
be used after a call to xyzsetup was used to set up zero-dimensional
|
983
|
+
subcubes. The calling program can then loop over all pixels (from 1 to
|
984
|
+
vircubesize(naxis)). xyzpixwr takes care of writing the datacube.
|
985
|
+
Using this routine instead of xyzs2c and xyzwrite reduces the overhead
|
986
|
+
by more than a factor 10.
|
987
|
+
|
988
|
+
Input:
|
989
|
+
tno image file handle
|
990
|
+
pixelnr pixelnr to be read from virtual cube
|
991
|
+
value pixel value
|
992
|
+
mask FALSE indicates pixel is undefined */
|
993
|
+
/*--*/
|
994
|
+
|
995
|
+
void xyzpixwr_c(int tno, int pixelnr, Const float *data, Const int *mask )
|
996
|
+
{
|
997
|
+
int virpix_off;
|
998
|
+
#ifdef XYZ_DEBUG
|
999
|
+
if(otest) xyzs2c_c( tno, pixelnr-1, tcoo );
|
1000
|
+
#endif
|
1001
|
+
virpix_off = pixelnr - 1;
|
1002
|
+
if( virpix_off < bufs[tno].filfir || virpix_off > bufs[tno].fillas ) {
|
1003
|
+
MODE=PUT; manage_buffer( tno, virpix_off );
|
1004
|
+
}
|
1005
|
+
*( buffer + bufs[tno].bufstart + virpix_off ) = *data;
|
1006
|
+
*( mbuffr + bufs[tno].bufstart + virpix_off ) = *mask;
|
1007
|
+
written[tno] = TRUE;
|
1008
|
+
#ifdef XYZ_DEBUG
|
1009
|
+
if(otest) testprint( tno, virpix_off, virpix_off );
|
1010
|
+
#endif
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
|
1014
|
+
|
1015
|
+
/** xyzprfwr - Write a profile to a dataset */
|
1016
|
+
/*& bpw */
|
1017
|
+
/*: image-i/o */
|
1018
|
+
/*+
|
1019
|
+
subroutine xyzprfwr( tno, profilenr, profile, mask, ndata )
|
1020
|
+
integer tno
|
1021
|
+
integer profilenr
|
1022
|
+
real profile(*)
|
1023
|
+
logical mask(*)
|
1024
|
+
integer ndata
|
1025
|
+
|
1026
|
+
This routine provides a (little) faster version for calls to xyzs2c and
|
1027
|
+
xyzwrite for the case that the calling program provides profiles. It
|
1028
|
+
should be used after a call to xyzsetup was used to set up 1-dimensional
|
1029
|
+
subcubes. The calling program can then loop over all profiles (from 1 to
|
1030
|
+
vircubesize(naxis)/vircubesize(1)). xyzprfwr takes care of writing the
|
1031
|
+
datacube. Using this routine instead of xyzs2c and xyzwrite reduces the
|
1032
|
+
overhead by 10% (for 256-long profiles) to 30% (for 64-long profiles).
|
1033
|
+
|
1034
|
+
Input:
|
1035
|
+
tno image file handle
|
1036
|
+
profilenr profile nr to be read from virtual cube
|
1037
|
+
profile contains the profile to be written
|
1038
|
+
mask FALSE values indicate undefined pixels
|
1039
|
+
ndata number of elements to write */
|
1040
|
+
/*--*/
|
1041
|
+
|
1042
|
+
void xyzprfwr_c(int tno, int profilenr, Const float *data,
|
1043
|
+
Const int *mask, Const int *ndata )
|
1044
|
+
{
|
1045
|
+
int virpix_off;
|
1046
|
+
#ifdef XYZ_DEBUG
|
1047
|
+
if(otest) xyzs2c_c( tno, profilenr-1, tcoo );
|
1048
|
+
#endif
|
1049
|
+
virpix_off = (profilenr-1) * bufs[tno].cubesize[1];
|
1050
|
+
MODE=PUT;
|
1051
|
+
get_put_data( tno, virpix_off, (float *)data, (int *)mask, (int *)ndata, 1 );
|
1052
|
+
written[tno] = TRUE;
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
|
1056
|
+
|
1057
|
+
/** xyzplnwr - Write a plane to a dataset */
|
1058
|
+
/*& bpw */
|
1059
|
+
/*: image-i/o */
|
1060
|
+
/*+
|
1061
|
+
subroutine xyzplnwr( tno, planenr, plane, mask, ndata )
|
1062
|
+
integer tno
|
1063
|
+
integer planenr
|
1064
|
+
real plane(*)
|
1065
|
+
logical mask(*)
|
1066
|
+
integer ndata
|
1067
|
+
|
1068
|
+
This routine provides a more convenient version of calls to xyzs2c and
|
1069
|
+
xyzwrite for the case that the calling program provides planes. It
|
1070
|
+
should be used after a call to xyzsetup was used to set up 2-dimensional
|
1071
|
+
subcubes. The calling program can then loop over all planes (from 1 to
|
1072
|
+
vircubesize(naxis)/vircubesize(2)). xyzplnwr takes care of writing the
|
1073
|
+
datacube. The caveat is that the calling program should have an array
|
1074
|
+
that is large enough to contain the complete plane.
|
1075
|
+
Using this routine instead of xyzs2c and xyzwrite reduces the overhead
|
1076
|
+
by 1% (for 64**2 cubes) or less.
|
1077
|
+
|
1078
|
+
Input:
|
1079
|
+
tno image file handle
|
1080
|
+
planenr plane nr to be read from virtual-cube
|
1081
|
+
plane contains the plane to be written as a 1-d array
|
1082
|
+
mask FALSE values indicate undefined pixels
|
1083
|
+
ndata number of elements to write */
|
1084
|
+
/*--*/
|
1085
|
+
|
1086
|
+
void xyzplnwr_c(int tno, int planenr, Const float *data,
|
1087
|
+
Const int *mask, Const int *ndata )
|
1088
|
+
{
|
1089
|
+
int virpix_off;
|
1090
|
+
#ifdef XYZ_DEBUG
|
1091
|
+
if(otest) xyzs2c_c( tno, planenr-1, tcoo );
|
1092
|
+
#endif
|
1093
|
+
virpix_off = (planenr-1) * bufs[tno].cubesize[2];
|
1094
|
+
MODE=PUT;
|
1095
|
+
get_put_data( tno, virpix_off, (float *)data, (int *)mask, (int *)ndata, 2 );
|
1096
|
+
written[tno] = TRUE;
|
1097
|
+
}
|
1098
|
+
|
1099
|
+
/******************************************************************************/
|
1100
|
+
/******************************************************************************/
|
1101
|
+
/******************************************************************************/
|
1102
|
+
|
1103
|
+
/******************************************************************************/
|
1104
|
+
/* */
|
1105
|
+
/* The routine that figures out if i-o must be done */
|
1106
|
+
/* */
|
1107
|
+
/******************************************************************************/
|
1108
|
+
|
1109
|
+
static void get_put_data( int tno, int virpix_off, float *data, int *mask, int *ndata, int dim_sub )
|
1110
|
+
{
|
1111
|
+
/* This checks if the needed subcube is in the buffer. If so, a piece
|
1112
|
+
of the buffer is copied. If not, manage_buffer is called to fill or
|
1113
|
+
empty the buffer and then the copy is done.
|
1114
|
+
*/
|
1115
|
+
int virpix_lst;
|
1116
|
+
float *bufptr, *bufend, *bufsta;
|
1117
|
+
int i, coo[ARRSIZ], next;
|
1118
|
+
|
1119
|
+
|
1120
|
+
virpix_lst = virpix_off + bufs[tno].cubesize[dim_sub] - 1;
|
1121
|
+
if( MODE==GET ) *ndata = bufs[tno].cubesize[dim_sub];
|
1122
|
+
if( MODE==PUT && *ndata < bufs[tno].cubesize[dim_sub] ) {
|
1123
|
+
bug_c( 'f', "xyzio: Input array too small to hold subcube" );
|
1124
|
+
}
|
1125
|
+
if( virpix_off < bufs[tno].filfir || virpix_lst > bufs[tno].fillas ) {
|
1126
|
+
if(itest)printf("\nNew buffer starts at %d MODE %d\n",virpix_off,MODE);
|
1127
|
+
if( virpix_off >= bufs[tno].cubesize[bufs[tno].naxis] ) bug_c( 'f',
|
1128
|
+
"xyzio: Caller tries to access pixel outside datacube");
|
1129
|
+
if( dimsub[tno] == -1 ) bug_c( 'f',
|
1130
|
+
"xyzio: xyzsetup was never called for dataset" );
|
1131
|
+
manage_buffer( tno, virpix_off );
|
1132
|
+
}
|
1133
|
+
|
1134
|
+
/* Plain copy */
|
1135
|
+
if( !reverse[tno][0] ) {
|
1136
|
+
bufptr = buffer + bufs[tno].bufstart + virpix_off;
|
1137
|
+
bufend = buffer + bufs[tno].bufstart + virpix_lst;
|
1138
|
+
do_copy( bufptr, bufend, UP, data, mask );
|
1139
|
+
/* Reverse copy */
|
1140
|
+
} else if( reverse[tno][0] == ALL ) {
|
1141
|
+
bufptr = buffer + bufs[tno].bufstart + virpix_lst;
|
1142
|
+
bufend = buffer + bufs[tno].bufstart + virpix_off;
|
1143
|
+
do_copy( bufptr, bufend, DOWN, data, mask );
|
1144
|
+
/* Some axes reversed */
|
1145
|
+
} else {
|
1146
|
+
copy_to_one_d( tno );
|
1147
|
+
/* Apply a trick to avoid a very strange error on the Cray */
|
1148
|
+
/* bufsta = buffer + bufs[tno].bufstart + virpix_off; */
|
1149
|
+
i = bufs[tno].bufstart + virpix_off;
|
1150
|
+
for( d=1; d<=dim_sub; d++ ) {
|
1151
|
+
if( !reverses[d] ) coo[d] = 0; else coo[d] = bufsaxlen[d] - 1;
|
1152
|
+
/* bufsta += coo[d] * bufscubesize[d-1]; } */
|
1153
|
+
i += coo[d] * bufscubesize[d-1]; } bufsta = buffer + i;
|
1154
|
+
for( i=1; i<=bufscubesize[dim_sub]/bufscubesize[1]; i++ ) {
|
1155
|
+
if( !reverses[1] ) {
|
1156
|
+
bufptr = bufsta;
|
1157
|
+
bufend = bufsta + bufsaxlen[1] - 1;
|
1158
|
+
do_copy( bufptr, bufend, UP, data, mask );
|
1159
|
+
} else {
|
1160
|
+
bufptr = bufsta;
|
1161
|
+
bufend = bufsta - bufsaxlen[1] + 1;
|
1162
|
+
do_copy( bufptr, bufend, DOWN, data, mask );
|
1163
|
+
}
|
1164
|
+
data += bufsaxlen[1]; mask += bufsaxlen[1];
|
1165
|
+
next=TRUE; d=2; while( d<=dim_sub && next ) {
|
1166
|
+
if( !reverses[d] ) {
|
1167
|
+
coo[d]++; bufsta += bufscubesize[d-1];
|
1168
|
+
next = ( coo[d] == bufsaxlen[d] );
|
1169
|
+
if(next) {coo[d]=0; bufsta -= bufscubesize[d];}
|
1170
|
+
} else {
|
1171
|
+
coo[d]--; bufsta -= bufscubesize[d-1];
|
1172
|
+
next = ( coo[d] == -1 );
|
1173
|
+
if(next) {coo[d]=bufsaxlen[d]-1; bufsta += bufscubesize[d];}
|
1174
|
+
}
|
1175
|
+
}
|
1176
|
+
}
|
1177
|
+
}
|
1178
|
+
#ifdef XYZ_DEBUG
|
1179
|
+
if(otest) testprint( tno, virpix_off, virpix_lst );
|
1180
|
+
#endif
|
1181
|
+
}
|
1182
|
+
|
1183
|
+
|
1184
|
+
static void do_copy( float *bufptr, float *bufend, int DIR, float *data, int *mask )
|
1185
|
+
{
|
1186
|
+
int *mbufpt;
|
1187
|
+
|
1188
|
+
mbufpt = mbuffr + (int)(bufptr-buffer);
|
1189
|
+
|
1190
|
+
if( DIR == UP ) {
|
1191
|
+
if( MODE==GET ) {
|
1192
|
+
while( bufptr<=bufend ) { *data++ = *bufptr++; *mask++ = *mbufpt++; }}
|
1193
|
+
if( MODE==PUT ) {
|
1194
|
+
while( bufptr<=bufend ) { *bufptr++ = *data++; *mbufpt++ = *mask++; }}
|
1195
|
+
} else if( DIR == DOWN ) {
|
1196
|
+
if( MODE==GET ) {
|
1197
|
+
while( bufptr>=bufend ) { *data++ = *bufptr--; *mask++ = *mbufpt--; }}
|
1198
|
+
if( MODE==PUT ) {
|
1199
|
+
while( bufptr>=bufend ) { *bufptr-- = *data++; *mbufpt-- = *mask++; }}
|
1200
|
+
}
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
/******************************************************************************/
|
1204
|
+
/******************************************************************************/
|
1205
|
+
/******************************************************************************/
|
1206
|
+
|
1207
|
+
/******************************************************************************/
|
1208
|
+
/* */
|
1209
|
+
/* Buffer control, figures out how to call loop_buffer */
|
1210
|
+
/* */
|
1211
|
+
/******************************************************************************/
|
1212
|
+
|
1213
|
+
static void manage_buffer( int tno, int virpix_off )
|
1214
|
+
{
|
1215
|
+
/* This controls the buffer. It tries to do the absolute minimum number
|
1216
|
+
of disk-i/o's, using the array buffer, whose total length is determined
|
1217
|
+
by get_buflen xyzsetup. The array divided into sections, each
|
1218
|
+
corresponding to a particular opened image dataset. The first section is
|
1219
|
+
used to collect data read in or to write. The size of the sections varies
|
1220
|
+
with the number of opened datasets and is xyziobuflen/(nopened+1). When
|
1221
|
+
elements are copied from or to the buffer, they come form or go into the
|
1222
|
+
appropriate section. If a request is made for a pixel outside the section,
|
1223
|
+
manage_buffer is called and the parameters of the section will change.
|
1224
|
+
manage_buffer takes care that all elements of the image section are
|
1225
|
+
read/written. Disk-i/o uses the first section. After reading into it,
|
1226
|
+
each pixel is checked and if it is in range it is copied to the
|
1227
|
+
appropriate element in the section corresponding to the image. The
|
1228
|
+
reading and checking is repeated until the whole section is filled.
|
1229
|
+
For writing, all pixels in the first section are checked and the ones
|
1230
|
+
that are the range of the section for the image, are copied to the first
|
1231
|
+
section. This is continued until all elements in the image-section
|
1232
|
+
have been written. A special case occurs when the subcube specification
|
1233
|
+
was such that no transposition or region was given. Then the read/write
|
1234
|
+
is done directly to the image section, and the loops are skipped.
|
1235
|
+
|
1236
|
+
There is one extra stage for the case where reading and writing is done
|
1237
|
+
to the same dataset. If a new read is done, the old buffer is first
|
1238
|
+
flushed, if it was ever written into.
|
1239
|
+
|
1240
|
+
copy_to_one_d makes 1-d arrays of some arrays, to reduce the number
|
1241
|
+
of pointer calculations and to improve code-readability.
|
1242
|
+
|
1243
|
+
For reading data, some buffer parameters are obtained first, then
|
1244
|
+
the buffer is filled. For writing, the current buffer is first
|
1245
|
+
flushed and then the buffer parameters are set up for the next
|
1246
|
+
buffer.
|
1247
|
+
|
1248
|
+
set_bufs_limits figures out the virtual-cube pixeloffsets of the
|
1249
|
+
first and last element in the buffer and the range in x, y, z etc
|
1250
|
+
in the virtual-cube buffer and the input/output cube. This allows
|
1251
|
+
shortcuts to be taken.
|
1252
|
+
Further it defines bufs[tno].bufstart, which gives the first element
|
1253
|
+
in the buffer corresponding to this image. Before leaving manage_buffer
|
1254
|
+
this is changed into a number that can be used to convert a virpix_off
|
1255
|
+
to a bufferelement. So, inside this routine bufs[tno].bufstart points
|
1256
|
+
to the buffer, outside it points to the buffer index of the first
|
1257
|
+
element of the virtual-cube.
|
1258
|
+
|
1259
|
+
For output writing, on the very first pass the buffer was still
|
1260
|
+
empty, not full, so all that is done is to initialize it. Only at
|
1261
|
+
the second and all later passes is it written to disk.
|
1262
|
+
|
1263
|
+
After all this the first and last pixel of the virtual cube are
|
1264
|
+
converted to the corresponding offsets in the input cube. All
|
1265
|
+
required pixels lie within that range.
|
1266
|
+
|
1267
|
+
Then a loop is done over all pixels in the input/output buffer and
|
1268
|
+
elements of the virtual cube are copied. This is done in stages, as
|
1269
|
+
the full range of input/output pixels may be larger than the size
|
1270
|
+
of the buffer. So, in each stage a range from start to last is
|
1271
|
+
searched, until the finish is reached. Sometimes it is not necessary
|
1272
|
+
to really do the i/o, so then it is skipped.
|
1273
|
+
*/
|
1274
|
+
if( MODE==GET && written[tno] ) {
|
1275
|
+
if(itest) printf("Flush previous output buffer\n");
|
1276
|
+
MODE=PUT; manage_the_buffer( tno, -1 ); MODE=GET;
|
1277
|
+
if(itest) printf("Set up new input buffer\n");
|
1278
|
+
}
|
1279
|
+
manage_the_buffer( tno, virpix_off );
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
static void manage_the_buffer( int tno, int virpix_off )
|
1283
|
+
{
|
1284
|
+
int start, finis, last, newstart;
|
1285
|
+
|
1286
|
+
if( allocatebuffer ) get_buflen();
|
1287
|
+
|
1288
|
+
copy_to_one_d( tno );
|
1289
|
+
|
1290
|
+
if( imgs[tno].lastwritten == -1 ) zero( 1, tno );
|
1291
|
+
|
1292
|
+
if( MODE==GET ) {
|
1293
|
+
set_bufs_limits( tno, virpix_off );
|
1294
|
+
written[tno] = FALSE;
|
1295
|
+
}
|
1296
|
+
if( MODE==PUT ) {
|
1297
|
+
if( bufs[tno].filfir == -1 ) {
|
1298
|
+
set_bufs_limits( tno, virpix_off );
|
1299
|
+
bufs[tno].bufstart = - bufs[tno].filfir + bufs[tno].bufstart;
|
1300
|
+
return;
|
1301
|
+
}
|
1302
|
+
bufs[tno].bufstart = bufs[tno].bufstart + bufs[tno].filfir;
|
1303
|
+
if(otest) printf("\n");
|
1304
|
+
}
|
1305
|
+
|
1306
|
+
start = transform_back( bufs[tno].filfir );
|
1307
|
+
finis = transform_back( bufs[tno].fillas );
|
1308
|
+
if(itest) printf( "%s %d values: from %d to %d\n",
|
1309
|
+
words[MODE], finis-start+1, start, finis );
|
1310
|
+
|
1311
|
+
if(itest||rtest){nfound=0;if(imgs[tno].nocopy)nfound=finis-start+1;}
|
1312
|
+
while( start <= finis ) {
|
1313
|
+
last = get_last( start, finis );
|
1314
|
+
if( check_do_io( tno, start, last ) ) {
|
1315
|
+
if( MODE==GET ) {
|
1316
|
+
fill_buffer( tno, start, last );
|
1317
|
+
loop_buffer( tno, start, last, &newstart );
|
1318
|
+
}
|
1319
|
+
if( MODE==PUT ) {
|
1320
|
+
loop_buffer( tno, start, last, &newstart );
|
1321
|
+
empty_buffer( tno, start, last );
|
1322
|
+
}
|
1323
|
+
} else {
|
1324
|
+
if(itest) printf( "Did not %s %d values: from %d to %d\n",
|
1325
|
+
words[MODE], last-start+1, start, last );
|
1326
|
+
}
|
1327
|
+
start = newstart;
|
1328
|
+
}
|
1329
|
+
if(itest) printf( "virbuffer %s\n", words[MODE+2] );
|
1330
|
+
if( MODE==PUT ) set_bufs_limits( tno, virpix_off );
|
1331
|
+
bufs[tno].bufstart = - bufs[tno].filfir + bufs[tno].bufstart;
|
1332
|
+
}
|
1333
|
+
|
1334
|
+
/******************************************************************************/
|
1335
|
+
/* */
|
1336
|
+
/* Find the length of a buffer that fits in memory */
|
1337
|
+
/* */
|
1338
|
+
/******************************************************************************/
|
1339
|
+
|
1340
|
+
static void get_buflen(void)
|
1341
|
+
{
|
1342
|
+
int tno;
|
1343
|
+
int try, maxsize, size;
|
1344
|
+
int *mbufpt, cnt;
|
1345
|
+
if(itest)printf("# bytes per real %d\n",sizeof(float));
|
1346
|
+
|
1347
|
+
maxsize = 0;
|
1348
|
+
for( tno=1; tno<=MAXOPEN; tno++ ) {
|
1349
|
+
if( imgs[tno].itno != 0 ) {
|
1350
|
+
size = bufs[tno].cubesize[bufs[tno].naxis];
|
1351
|
+
maxsize = ( (maxsize<size) ? size : maxsize );
|
1352
|
+
}
|
1353
|
+
}
|
1354
|
+
try = (ntno+1) * maxsize;
|
1355
|
+
if( (buffer==NULL) || (try>currentallocation) ) try = bufferallocation(try);
|
1356
|
+
allocatebuffer = FALSE;
|
1357
|
+
|
1358
|
+
buffersize = try / (ntno+1);
|
1359
|
+
|
1360
|
+
for( tno=0; tno<MAXOPEN; tno++ ) {
|
1361
|
+
if( imgs[tno].itno != 0 ) {
|
1362
|
+
if( bufs[tno].cubesize[dimsub[tno]] > buffersize )
|
1363
|
+
bug_c( 'f', "xyzsetup: Requested subcube too big for buffer" );
|
1364
|
+
}
|
1365
|
+
}
|
1366
|
+
|
1367
|
+
/* set combined masking buffer to true, just in case no real mask
|
1368
|
+
is read in */
|
1369
|
+
mbufpt = mbuffr; cnt=0;
|
1370
|
+
while( cnt++ < try ) *mbufpt++ = FORT_TRUE;
|
1371
|
+
}
|
1372
|
+
|
1373
|
+
static int bufferallocation( int n )
|
1374
|
+
{
|
1375
|
+
if( buffer != NULL ) { free( buffer ); buffer = NULL; }
|
1376
|
+
if( mbuffr != NULL ) { free( mbuffr ); mbuffr = NULL; }
|
1377
|
+
|
1378
|
+
n = ( (n < MAXBUF) ? n : MAXBUF );
|
1379
|
+
n *= 2;
|
1380
|
+
while( ( (buffer == NULL) || (mbuffr == NULL) ) && (n>1) ) {
|
1381
|
+
if( buffer != NULL ) { free( buffer ); buffer = NULL; }
|
1382
|
+
if( mbuffr != NULL ) { free( mbuffr ); mbuffr = NULL; }
|
1383
|
+
n /= 2;
|
1384
|
+
if(itest)printf("try %d\n",n);
|
1385
|
+
buffer = (float *)malloc((unsigned)(n*sizeof(float)));
|
1386
|
+
mbuffr = (int *)malloc((unsigned)(n*sizeof(int) ));
|
1387
|
+
}
|
1388
|
+
if( n == 1 ) bug_c( 'f', "xyzsetup: Failed to allocate any memory" );
|
1389
|
+
|
1390
|
+
if(itest)printf("Allocated %d reals @ %p\n",n,buffer);
|
1391
|
+
if(itest)printf("Allocated %d ints @ %p\n",n,mbuffr);
|
1392
|
+
|
1393
|
+
currentallocation = n;
|
1394
|
+
return( n );
|
1395
|
+
}
|
1396
|
+
|
1397
|
+
/******************************************************************************/
|
1398
|
+
|
1399
|
+
static void copy_to_one_d( int tno )
|
1400
|
+
{
|
1401
|
+
/* All this does is make one-d arrays of some 2-d arrays, so that the
|
1402
|
+
number of pointer calculations is reduced. And also it makes the
|
1403
|
+
routines below manage_buffer more readable.
|
1404
|
+
*/
|
1405
|
+
naxes = bufs[tno].naxis;
|
1406
|
+
for( d=0; d<=naxes; d++ ) {
|
1407
|
+
imgsaxlen[d] =imgs[tno].axlen[d]; bufsaxlen[d] =bufs[tno].axlen[d];
|
1408
|
+
imgscubesize[d]=imgs[tno].cubesize[d];bufscubesize[d]=bufs[tno].cubesize[d];
|
1409
|
+
imgsblc[d] =imgs[tno].blc[d]; bufsblc[d] =0;
|
1410
|
+
imgstrc[d] =imgs[tno].trc[d]; bufstrc[d] =bufs[tno].axlen[d]-1;
|
1411
|
+
imgscsz[d] =imgscubesize[d-1]; bufscsz[d] =bufscubesize[d-1];
|
1412
|
+
imgslower[d] =imgs[tno].lower[d];
|
1413
|
+
imgsupper[d] =imgs[tno].upper[d];
|
1414
|
+
axnumr[d] =axnum[tno][d];
|
1415
|
+
reverses[d] =reverse[tno][d];
|
1416
|
+
}
|
1417
|
+
for( d=1; d<=naxes; d++ ) inv_axnumr[ axnumr[d] ] = d;
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
static void set_bufs_limits( int tno, int virpix_off )
|
1421
|
+
{
|
1422
|
+
/* This gets some information about the virtual-cube buffer and the ranges
|
1423
|
+
of coordinates.
|
1424
|
+
First it figures out which range of pixeloffsets from the virtual cube
|
1425
|
+
fits in the buffer (from bufs[tno].filfir to bufs[tno].fillas).
|
1426
|
+
bufs[tno].fillas is found by figuring out what the pixeloffset of the
|
1427
|
+
last complete subcube was. It is limited by the size of the virtual cube.
|
1428
|
+
It also finds a pointer to the element in the buffer that will
|
1429
|
+
correspond to the first element of the virtual cube that is present
|
1430
|
+
(bufs[tno].bufstart).
|
1431
|
+
Next it finds the lower and upper limits that will ever be found for
|
1432
|
+
each coordinate: bufs.lower and bufs.upper. This is used later to limit
|
1433
|
+
the number of transformations by skipping over ranges where no buffer
|
1434
|
+
pixels will be found. Its main use is to be able to take shortcuts, to
|
1435
|
+
reduce the overhead.
|
1436
|
+
*/
|
1437
|
+
if( virpix_off == -1 ) return;
|
1438
|
+
|
1439
|
+
bufs[tno].filfir = virpix_off;
|
1440
|
+
bufs[tno].bufstart = imgs[tno].number*buffersize;
|
1441
|
+
bufs[tno].fillas =
|
1442
|
+
(int)( (bufs[tno].filfir+buffersize) / bufscubesize[dimsub[tno]] )
|
1443
|
+
* bufscubesize[dimsub[tno]] - 1;
|
1444
|
+
if( bufs[tno].fillas > bufscubesize[ naxes ] - 1 )
|
1445
|
+
bufs[tno].fillas = bufscubesize[ naxes ] - 1;
|
1446
|
+
|
1447
|
+
find_block( bufs[tno].filfir, bufs[tno].fillas,
|
1448
|
+
bufs[tno].lower, bufs[tno].upper,
|
1449
|
+
bufsaxlen, bufscubesize, bufsblc, bufstrc, naxes );
|
1450
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
1451
|
+
imgs[tno].lower[axnumr[dim]]=bufs[tno].lower[dim]+imgsblc[axnumr[dim]];
|
1452
|
+
imgs[tno].upper[axnumr[dim]]=bufs[tno].upper[dim]+imgsblc[axnumr[dim]];
|
1453
|
+
}
|
1454
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
1455
|
+
imgslower[dim] = imgs[tno].lower[dim];
|
1456
|
+
imgsupper[dim] = imgs[tno].upper[dim];
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
if(itest) { printf( "fill %s buffer; will be full after %d pixels\n",
|
1460
|
+
words[MODE], bufs[tno].fillas - bufs[tno].filfir + 1 );
|
1461
|
+
limprint( "vircub", bufs[tno].lower, bufs[tno].upper ); }
|
1462
|
+
}
|
1463
|
+
|
1464
|
+
static int get_last( int start, int finis )
|
1465
|
+
{
|
1466
|
+
/* This routine figures out how many elements will fit into the buffer:
|
1467
|
+
the lower of the amount needed and the size of the buffer. It returns
|
1468
|
+
the fileoffset of the last element that fits.
|
1469
|
+
*/
|
1470
|
+
int allocate;
|
1471
|
+
if( finis-start+1 > buffersize ) { allocate = buffersize; }
|
1472
|
+
else { allocate = finis-start+1; }
|
1473
|
+
return( start + allocate - 1 );
|
1474
|
+
}
|
1475
|
+
|
1476
|
+
static int check_do_io( int tno, int start, int last )
|
1477
|
+
{
|
1478
|
+
/*
|
1479
|
+
This routine checks if it is really necessary to read or write data
|
1480
|
+
from/to disk.
|
1481
|
+
It calculates the lowest and highest coordinate value that will ever
|
1482
|
+
be encountered. A comparison is done with the lowest and highest that
|
1483
|
+
might go into the buffer. If at least part of "the subcube selected
|
1484
|
+
from the inputcube" and "the subcube from the virtual cube that will
|
1485
|
+
fit into the buffer" overlap, a disk-i/o is required, as there will be
|
1486
|
+
at least one element of the virtual-cube-buffer read or written. This
|
1487
|
+
mainly comes into play when the buffer is smaller than an image plane
|
1488
|
+
and z-profiles must be read/written.
|
1489
|
+
*/
|
1490
|
+
int imgslow[ARRSIZ], imgsupp[ARRSIZ];
|
1491
|
+
int do_io;
|
1492
|
+
|
1493
|
+
find_block( start, last, imgslow, imgsupp,
|
1494
|
+
imgsaxlen, imgscubesize, imgsblc, imgstrc, naxes );
|
1495
|
+
do_io = FALSE;
|
1496
|
+
for( dim=1; dim<=naxes && !do_io; dim++ ) {
|
1497
|
+
do_io = ( bufs[tno].lower[ dim ] <= imgsupp[ axnumr[dim] ] ) ||
|
1498
|
+
( bufs[tno].upper[ dim ] >= imgslow[ axnumr[dim] ] );
|
1499
|
+
}
|
1500
|
+
if(itest) limprint( "i-ocub", imgslow, imgsupp );
|
1501
|
+
return do_io;
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
static void find_block( int start, int last, int *lower, int *upper,
|
1505
|
+
int *axlen, int *cubesize, int *blc, int *trc, int naxis )
|
1506
|
+
{
|
1507
|
+
/* Figures out from the first and last pixeloffset what the lowest and
|
1508
|
+
highest coordinate value are that could possibly be encountered. To do
|
1509
|
+
this it calculates the first coordinate value in the 'plane' (e.g. how
|
1510
|
+
many lines fit into z*(#lines/plane) and subtracts this from the
|
1511
|
+
non-modulo calculated coordinate value of the last pixeloffset. Then
|
1512
|
+
it checks if the next 'plane' was reached. If not, the coordinate
|
1513
|
+
limits are determined by the coordinate values themselves, else they
|
1514
|
+
are the lower/upper ends of the ranges.
|
1515
|
+
*/
|
1516
|
+
int bot, top;
|
1517
|
+
int strcoo[ARRSIZ], fincoo[ARRSIZ];
|
1518
|
+
p2c( start, axlen, cubesize, naxis, strcoo );
|
1519
|
+
p2c( last, axlen, cubesize, naxis, fincoo );
|
1520
|
+
for( dim=1; dim<=naxis; dim++ ) {
|
1521
|
+
bot = (int)( start / cubesize[dim] ) * axlen[dim];
|
1522
|
+
top = (int)( last / cubesize[dim-1] ) - bot;
|
1523
|
+
( ( top > trc[dim] ) ? ( lower[dim] = blc[dim] )
|
1524
|
+
: ( lower[dim] = strcoo[dim] ) );
|
1525
|
+
( ( top >= trc[dim] ) ? ( upper[dim] = trc[dim] )
|
1526
|
+
: ( upper[dim] = fincoo[dim] ) );
|
1527
|
+
}
|
1528
|
+
}
|
1529
|
+
|
1530
|
+
static int transform_back( int pix_off )
|
1531
|
+
{
|
1532
|
+
/* Transforms an virtual-cube pixeloffset into an input pixeloffset.
|
1533
|
+
*/
|
1534
|
+
int inpcoo, vircoo;
|
1535
|
+
int result, axnr;
|
1536
|
+
result = 0;
|
1537
|
+
for( dim=1; dim<=naxes; dim++ ) {
|
1538
|
+
axnr = axnumr[dim];
|
1539
|
+
vircoo = ( pix_off / bufscubesize[ dim-1 ] ) % bufsaxlen[ dim ];
|
1540
|
+
inpcoo = vircoo + imgsblc[ axnr ];
|
1541
|
+
result += imgscubesize[axnr-1] * inpcoo;
|
1542
|
+
}
|
1543
|
+
return ( result );
|
1544
|
+
}
|
1545
|
+
|
1546
|
+
static int c2p( int *coords, int *cubesize, int naxis )
|
1547
|
+
{
|
1548
|
+
/* Converts a pixeloffset into a list of coordinates
|
1549
|
+
*/
|
1550
|
+
int pix_off; pix_off=0;
|
1551
|
+
for( d=1; d<=naxis; d++ ) pix_off += cubesize[d-1] * coords[d];
|
1552
|
+
return ( pix_off );
|
1553
|
+
}
|
1554
|
+
static void p2c( int pix_off, int *axlen, int *cubesize, int naxis, int *coords )
|
1555
|
+
{
|
1556
|
+
/* Converts a list of coordinates into a pixeloffset
|
1557
|
+
*/
|
1558
|
+
for( d=1; d<=naxis; d++ ) coords[d] = ( pix_off/cubesize[d-1] ) % axlen[d];
|
1559
|
+
}
|
1560
|
+
|
1561
|
+
/******************************************************************************/
|
1562
|
+
/* */
|
1563
|
+
/* The routines that do the i-o */
|
1564
|
+
/* */
|
1565
|
+
/******************************************************************************/
|
1566
|
+
|
1567
|
+
static void fill_buffer( int tno, int start, int last )
|
1568
|
+
{
|
1569
|
+
int length, begin;
|
1570
|
+
int bufstart, *buf;
|
1571
|
+
int i,iostat;
|
1572
|
+
|
1573
|
+
nio++;
|
1574
|
+
if(itest) printf( "Read %d values: %d to %d\n", last-start+1, start, last );
|
1575
|
+
|
1576
|
+
if( !imgs[tno].nocopy ) bufstart=0; else bufstart=bufs[tno].bufstart;
|
1577
|
+
length = H_REAL_SIZE * ( last - start + 1 );
|
1578
|
+
begin = H_REAL_SIZE * start + ITEM_HDR_SIZE;
|
1579
|
+
/* hgrab_c( imgs[tno].itno,(char *)(buffer+bufstart),begin,length,&iostat );*/
|
1580
|
+
hreadr_c( imgs[tno].itno,(char *)(buffer+bufstart),begin,length,&iostat );
|
1581
|
+
check(iostat);
|
1582
|
+
length = last - start + 1;
|
1583
|
+
begin = start;
|
1584
|
+
if( imgs[tno].mask ) {
|
1585
|
+
mkread_c( imgs[tno].mask,1,mbuffr+bufstart,begin,length,length );
|
1586
|
+
} else {
|
1587
|
+
buf = mbuffr+bufstart;
|
1588
|
+
for (i=0; i<length; i++)
|
1589
|
+
buf[i] = FORT_TRUE;
|
1590
|
+
}
|
1591
|
+
|
1592
|
+
if(vtest){ for( i=0; i<last-start+1; i++ ) {
|
1593
|
+
p2c( i+start, imgsaxlen, imgscubesize, naxes, tcoo );
|
1594
|
+
*(buffer+i) = (float)( tcoo[1] + 1000*tcoo[2] + 1000000*tcoo[3] ); }}
|
1595
|
+
}
|
1596
|
+
|
1597
|
+
static void empty_buffer( int tno, int start, int last )
|
1598
|
+
{
|
1599
|
+
int length, begin;
|
1600
|
+
int bufstart;
|
1601
|
+
int iostat;
|
1602
|
+
|
1603
|
+
nio++;
|
1604
|
+
if(itest) printf( "Write %d values: %d to %d\n", last-start+1,start,last );
|
1605
|
+
|
1606
|
+
if( !imgs[tno].nocopy ) bufstart=0; else bufstart=bufs[tno].bufstart;
|
1607
|
+
length = H_REAL_SIZE * ( last - start + 1 );
|
1608
|
+
begin = H_REAL_SIZE * start + ITEM_HDR_SIZE;
|
1609
|
+
/* hdump_c( imgs[tno].itno,(char *)(buffer+bufstart),begin,length,&iostat );*/
|
1610
|
+
hwriter_c(imgs[tno].itno,(char *)(buffer+bufstart),begin,length,&iostat );
|
1611
|
+
if( imgs[tno].lastwritten < last ) imgs[tno].lastwritten = last;
|
1612
|
+
check(iostat);
|
1613
|
+
if( imgs[tno].mask ) {
|
1614
|
+
length = last - start + 1;
|
1615
|
+
begin = start;
|
1616
|
+
mkwrite_c( imgs[tno].mask,1,mbuffr+bufstart,begin,length,length);
|
1617
|
+
}
|
1618
|
+
|
1619
|
+
}
|
1620
|
+
|
1621
|
+
/******************************************************************************/
|
1622
|
+
/* */
|
1623
|
+
/* Copy from the i-o buffer to the xyzio-buffer, the core of the routine */
|
1624
|
+
/* */
|
1625
|
+
/******************************************************************************/
|
1626
|
+
|
1627
|
+
static void loop_buffer( int tno, int start, int last, int *newstart )
|
1628
|
+
{
|
1629
|
+
/* This routine checks all pixels in the in/out buffer and puts them at
|
1630
|
+
the appropriate place in the virtual-cube buffer, or it takes them out
|
1631
|
+
of the virtual-cube buffer.
|
1632
|
+
In principle, for each pixel the input/output-pixeloffset is converted
|
1633
|
+
into a virtual-pixeloffset and this is checked against the range of
|
1634
|
+
elements in the virtual-cube buffer. For efficiency the conversion is
|
1635
|
+
not done explicitly. What is done is to loop over the x-coordinate of
|
1636
|
+
the in/out buffer and increment x, the pointer to the x-axis of the
|
1637
|
+
in/out buffer, and the virtual-cube offset until x flows over its
|
1638
|
+
maximum. This limits the number of operations in the innermost loop to
|
1639
|
+
only 11. Meanwhile the virtual-cube-offset is checked and data is
|
1640
|
+
copied as found. If x flowed over, the coordinates are recalculated
|
1641
|
+
and x is set to its lower limit. The other coordinates are either
|
1642
|
+
increased by one or, if they reached their upper limit, set to their
|
1643
|
+
lower limit. This allows for shortcuts to be taken if a region was
|
1644
|
+
specified and does not give a substantial overhead if no region was
|
1645
|
+
specified. From the new coordinates the pointer to the in/out buffer
|
1646
|
+
(bufptr) and virtual-cube-buffer (bufoff) are recalculated. All this
|
1647
|
+
continues until the in/out buffer is exhausted.
|
1648
|
+
Before starting to work on filling a buffer to write, a check is made
|
1649
|
+
whether is is necessary to set all elements to zero (if the output
|
1650
|
+
region is smaller than the output cube and the output cube did not
|
1651
|
+
yet exist) or to put the old values in the buffer (if the output cube
|
1652
|
+
existed and a transposition or region-selection was done).
|
1653
|
+
The speed of this algorithm is the limiting factor in the speed of
|
1654
|
+
filling/emptying buffers. Even more so than the size of the buffers.
|
1655
|
+
So anyone who can come up with a faster method of doing the same
|
1656
|
+
(transposing cubes) will be able to improve efficiency.
|
1657
|
+
*/
|
1658
|
+
int buffir, buflas, bufoff;
|
1659
|
+
float *bufptr, *bufend;
|
1660
|
+
int *mbufpt;
|
1661
|
+
int to_in;
|
1662
|
+
int filoff, coords[ARRSIZ];
|
1663
|
+
|
1664
|
+
*newstart = last + 1;
|
1665
|
+
if( imgs[tno].nocopy ) return;
|
1666
|
+
|
1667
|
+
buffir = bufs[tno].bufstart;
|
1668
|
+
buflas = bufs[tno].fillas - bufs[tno].filfir + buffir;
|
1669
|
+
|
1670
|
+
bufptr = buffer;
|
1671
|
+
bufend = buffer + last - start;
|
1672
|
+
mbufpt = mbuffr;
|
1673
|
+
|
1674
|
+
if( MODE==PUT ) {
|
1675
|
+
if( imgs[tno].lastwritten <= last ) {
|
1676
|
+
if( imgs[tno].lastwritten >= start ) {
|
1677
|
+
fill_buffer( tno, start, imgs[tno].lastwritten );
|
1678
|
+
bufptr = buffer + imgs[tno].lastwritten - start + 1;
|
1679
|
+
mbufpt = mbuffr + imgs[tno].lastwritten - start + 1;
|
1680
|
+
}
|
1681
|
+
if(itest) printf("zero buffer 0\n");
|
1682
|
+
while( bufptr <= bufend ) { *bufptr++ = 0; *mbufpt++ = FORT_TRUE; }
|
1683
|
+
} else {
|
1684
|
+
fill_buffer( tno, start, last );
|
1685
|
+
}
|
1686
|
+
bufptr = buffer;
|
1687
|
+
mbufpt = mbuffr;
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
p2c( start, imgsaxlen, imgscubesize, naxes, coords );
|
1691
|
+
bufoff = -bufs[tno].filfir + bufs[tno].bufstart;
|
1692
|
+
for( d=1; d<=naxes; d++ )
|
1693
|
+
bufoff += bufscsz[inv_axnumr[d]] * ( coords[d] - imgsblc[d] );
|
1694
|
+
|
1695
|
+
to_in = ( MODE==GET );
|
1696
|
+
|
1697
|
+
while( bufptr <= bufend ) {
|
1698
|
+
if( coords[1] <= imgsupper[1] ) {
|
1699
|
+
#ifdef XYZ_DEBUG
|
1700
|
+
if(rtest)testsearch(1,coords,start+bufptr-buffer,bufoff-buffir);
|
1701
|
+
#endif
|
1702
|
+
if( buffir <= bufoff && bufoff <= buflas ) {
|
1703
|
+
if( to_in ) { *(buffer+bufoff) = *bufptr;
|
1704
|
+
*(mbuffr+bufoff) = *mbufpt; }
|
1705
|
+
else { *bufptr = *(buffer+bufoff);
|
1706
|
+
*mbufpt = *(mbuffr+bufoff); }
|
1707
|
+
#ifdef XYZ_DEBUG
|
1708
|
+
if(itest||rtest)nfound++;
|
1709
|
+
if(rtest)
|
1710
|
+
printf(" found element %d; value %f %d",bufoff,*bufptr,*mbufpt);
|
1711
|
+
#endif
|
1712
|
+
}
|
1713
|
+
#ifdef XYZ_DEBUG
|
1714
|
+
if(rtest) printf("\n");
|
1715
|
+
#endif
|
1716
|
+
coords[1]++;
|
1717
|
+
bufoff += bufscsz[inv_axnumr[1]];
|
1718
|
+
bufptr++; mbufpt++;
|
1719
|
+
}
|
1720
|
+
if( coords[1] > imgsupper[1] ) {
|
1721
|
+
#ifdef XYZ_DEBUG
|
1722
|
+
if(rtest) testsearch(0,coords,0,0);
|
1723
|
+
#endif
|
1724
|
+
coords[1] = imgslower[1];
|
1725
|
+
d=2; while( d<=naxes ) {
|
1726
|
+
if( coords[d] == imgsupper[d] || coords[d] == imgstrc[d] )
|
1727
|
+
{ coords[d] = imgslower[d]; }
|
1728
|
+
else { coords[d]++; break; }
|
1729
|
+
d++;
|
1730
|
+
}
|
1731
|
+
if( d > naxes ) break;
|
1732
|
+
#ifdef XYZ_DEBUG
|
1733
|
+
if(rtest) testsearch(2,coords,0,0);
|
1734
|
+
#endif
|
1735
|
+
filoff = -start;
|
1736
|
+
bufoff = -bufs[tno].filfir + bufs[tno].bufstart;
|
1737
|
+
for( d=1; d<=naxes; d++ ) {
|
1738
|
+
filoff += imgscsz[d] * coords[d];
|
1739
|
+
bufoff += bufscsz[inv_axnumr[d]] * ( coords[d] - imgsblc[d] );
|
1740
|
+
}
|
1741
|
+
bufptr = buffer + filoff;
|
1742
|
+
mbufpt = mbuffr + filoff;
|
1743
|
+
}
|
1744
|
+
}
|
1745
|
+
if(itest||rtest) printf( "found %d elements\n", nfound );
|
1746
|
+
*newstart = bufptr - buffer + start;
|
1747
|
+
}
|
1748
|
+
|
1749
|
+
/******************************************************************************/
|
1750
|
+
|
1751
|
+
static void zero( int bl_tr, int tno )
|
1752
|
+
{
|
1753
|
+
/* This initializes parts of an output datacube that were not accessed
|
1754
|
+
because the new dataset has a blc and trc inside the full cube.
|
1755
|
+
It is called with bl_tr==1 just before the put buffer is first set up,
|
1756
|
+
and with bl_tr==2 just before the close.
|
1757
|
+
*/
|
1758
|
+
int start, last, finis;
|
1759
|
+
float *bufptr, *bufend;
|
1760
|
+
int *mbufpt;
|
1761
|
+
|
1762
|
+
if( bl_tr == 1 ) {
|
1763
|
+
start = 0;
|
1764
|
+
finis = c2p( imgsblc, imgscubesize, naxes ) - 1;
|
1765
|
+
finis = imgscubesize[naxes] - 1;
|
1766
|
+
} else if( bl_tr == 2 ) {
|
1767
|
+
start = c2p( imgstrc, imgscubesize, naxes ) + 1;
|
1768
|
+
finis = imgscubesize[naxes] - 1;
|
1769
|
+
}
|
1770
|
+
while( start <= finis ) {
|
1771
|
+
last = get_last( start, finis );
|
1772
|
+
bufptr = buffer;
|
1773
|
+
bufend = buffer + last - start;
|
1774
|
+
mbufpt = mbuffr;
|
1775
|
+
if(itest) printf("zero part of buffer 0\n");
|
1776
|
+
while( bufptr <= bufend ) { *bufptr++ = 0.; *mbufpt++ = FORT_FALSE; }
|
1777
|
+
empty_buffer( tno, start, last );
|
1778
|
+
start = bufptr - buffer + start;
|
1779
|
+
}
|
1780
|
+
}
|
1781
|
+
|
1782
|
+
/******************************************************************************/
|
1783
|
+
/******************************************************************************/
|
1784
|
+
|
1785
|
+
static void testprint( int tno, int virpix_off, int virpix_lst )
|
1786
|
+
{
|
1787
|
+
int vircoo[ARRSIZ];
|
1788
|
+
int inpix_off;
|
1789
|
+
int naxes;
|
1790
|
+
naxes=imgs[tno].naxis;
|
1791
|
+
p2c( virpix_off, bufs[tno].axlen, bufs[tno].cubesize, naxes, vircoo );
|
1792
|
+
for( dim=1; dim<=naxes; dim++ )
|
1793
|
+
tcoo[dim] = vircoo[ inv_axnumr[dim] ] + imgs[tno].blc[dim];
|
1794
|
+
inpix_off = c2p( tcoo, imgs[tno].cubesize, naxes );
|
1795
|
+
printf( "coo: " );
|
1796
|
+
for( dim=1; dim<=naxes; dim++) printf( "%4d ", tcoo[dim] );
|
1797
|
+
printf( " offset: %10d\n", inpix_off );
|
1798
|
+
printf( "vircoo: " );
|
1799
|
+
for( dim=1; dim<=naxes; dim++) printf( "%4d ", vircoo[dim] );
|
1800
|
+
printf( " offset: %20d\n", virpix_off );
|
1801
|
+
if( virpix_off == virpix_lst ) {
|
1802
|
+
printf( "%s copied element %d\n", words[MODE],
|
1803
|
+
virpix_off+bufs[tno].bufstart );
|
1804
|
+
} else {
|
1805
|
+
printf( "%s copied %d elements starting at %d\n", words[MODE],
|
1806
|
+
virpix_lst-virpix_off+1, virpix_off+bufs[tno].bufstart );
|
1807
|
+
}
|
1808
|
+
}
|
1809
|
+
|
1810
|
+
static void limprint( char *string, int *lower, int *upper )
|
1811
|
+
{
|
1812
|
+
printf( "%s:", string );
|
1813
|
+
printf( " lower" ); for( d=1; d<=naxes; d++ ) printf( " %d", lower[d] );
|
1814
|
+
printf( ": upper" ); for( d=1; d<=naxes; d++ ) printf( " %d", upper[d] );
|
1815
|
+
printf( "\n");
|
1816
|
+
}
|
1817
|
+
|
1818
|
+
static void testsearch( int callnr, int *coords, int filoff, int viroff )
|
1819
|
+
{
|
1820
|
+
if( callnr == 2 ) printf( " -> " );
|
1821
|
+
for( d=1; d<=naxes; d++ ) printf("%d ", coords[d] );
|
1822
|
+
if( callnr == 1 ) printf( " filoff %d viroff %d", filoff, viroff );
|
1823
|
+
if( callnr == 2 ) printf( "\n" );
|
1824
|
+
}
|
1825
|
+
|
1826
|
+
|
1827
|
+
|
1828
|
+
/******************************************************************************/
|
1829
|
+
/******************************************************************************/
|
1830
|
+
/******************************************************************************/
|
1831
|
+
/* Text for the userguide */
|
1832
|
+
/*
|
1833
|
+
To read or write a MIRIAD dataset the following set of routines can be used.
|
1834
|
+
|
1835
|
+
xyzopen( tno, name, status, naxis, axlen )
|
1836
|
+
xyzclose( tno )
|
1837
|
+
xyzsetup( tno, subcube, blc, trc, viraxlen, vircubesize )
|
1838
|
+
xyzs2c( tno, subcubnr, coords )
|
1839
|
+
xyzc2s( tno, coords, subcubenr )
|
1840
|
+
xyzread( tno, coords, data, mask, dimdata )
|
1841
|
+
xyzpixrd( tno, pixelnr, data, mask )
|
1842
|
+
xyzprfrd( tno, profinr, data, mask, dimdata )
|
1843
|
+
xyzplnrd( tno, planenr, data, mask, dimdata )
|
1844
|
+
xyzwrite( tno, coords, data, mask, dimdata )
|
1845
|
+
xyzpixwr( tno, pixelnr, data, mask )
|
1846
|
+
xyzprfwr( tno, profinr, data, mask, dimdata )
|
1847
|
+
xyzplnwr( tno, planenr, data, mask, dimdata )
|
1848
|
+
|
1849
|
+
xyzopen opens the dataset and readies it for reading/writing. 'name' is the
|
1850
|
+
name of the dataset. 'status' can be either "old" or "new", depending on
|
1851
|
+
whether an existing dataset is opened or a new one must be created. For old
|
1852
|
+
datasets naxis gives the dimension of array axlen on input and the dimension
|
1853
|
+
of the dataset on output. On output axlen contains the length of the axes.
|
1854
|
+
For new datasets naxis and axlen specify the number of axes and their length.
|
1855
|
+
|
1856
|
+
xyzclose closes the dataset.
|
1857
|
+
|
1858
|
+
The rest of the xyz routines can be used to read or write an arbitrary
|
1859
|
+
subcube in the dataset in a manner that minimizes disk-i/o. To do this,
|
1860
|
+
the datacube axes are named 'x', 'y', 'z', 'a', 'b', etc. 'x' may be RA
|
1861
|
+
or DEC or velocity or anything else, but it is the first axis.
|
1862
|
+
|
1863
|
+
The xyzsetup subroutine is used to define a subcube in the dataset. There are
|
1864
|
+
many subcubes in a dataset. They have axes with "varying coordinates" and axes
|
1865
|
+
with "fixed coordinates". With n "varying coordinates" the subcube is
|
1866
|
+
n-dimensional, and its position in the original cube is given by the "fixed
|
1867
|
+
coordinates". The subcubes are also ordered, along the "fixed coordinates".
|
1868
|
+
E.g., for profiles in the 'z' direction, the first subcube has (x=1,y=1), the
|
1869
|
+
second has (x=2,y=1), on to (x=axlen(1),y=1) and then (x=1,y=2) etc, etc.
|
1870
|
+
|
1871
|
+
For datasets that must be read, the 'subcube' variable of xyzsetup specifies
|
1872
|
+
which axes from the original cube have "varying coordinates"; e.g. 'z' for
|
1873
|
+
profiles the z-direction, or 'xy' for image planes. It is also allowed to
|
1874
|
+
transpose axes: e.g. 'zx' (which would usually correspond to making a vel-RA
|
1875
|
+
plane). To understand the meaning of 'subcube' for datasets that must be written
|
1876
|
+
a little explanation is in order: the xyz routines produce a "virtual cube",
|
1877
|
+
one that never actually is written on disk or resides in memory, but which is
|
1878
|
+
conceptually useful. In this virtual cube the axes are ordered such that the
|
1879
|
+
ones with "varying coordinates" become the 'x', 'y' etc axes, and the ones with
|
1880
|
+
"fixed coordinates" form the rest. So, if 'subcube' was 'z', a profile along
|
1881
|
+
the 'x'-axis of the virtual cube contains the datavalues on a profile along the
|
1882
|
+
'z'-axis of the input cube. The 'y' and 'z' axes of the virtual cube were the
|
1883
|
+
'x' and 'y' axes of the original cube, respectively. For writing a dataset, the
|
1884
|
+
'subcube' variable gives the correspondence between the axes of the virtual
|
1885
|
+
cube and the output cube. E.g., if 'subcube' is 'z', this means that the first
|
1886
|
+
('x') axis of the virtual cube is the 'z'-axis of the output cube, and the 'y'
|
1887
|
+
and 'z' axes of the virtual cube correspond to the 'x' and 'y' axes of the
|
1888
|
+
output cube, respectively.
|
1889
|
+
|
1890
|
+
Preceding an axisname with a '-' results in mirror-imaging the input or output
|
1891
|
+
data for that axis.
|
1892
|
+
|
1893
|
+
The blc and trc variables of xyzsetup give the bottom left and top right
|
1894
|
+
corner of the part of the image cube to be worked on. The first naxis
|
1895
|
+
elements of blc and trc are used. For reading, this is the region to be read,
|
1896
|
+
for writing it is the region to be written. In the latter case, if the output
|
1897
|
+
dataset did not yet exist and the region is smaller than the total cubesize
|
1898
|
+
given in xyzopen, the outside-region is automatically set to zero.
|
1899
|
+
|
1900
|
+
The viraxlen and vircubesize variables of xyzsetup give some information
|
1901
|
+
about the virtual cube: the axis lengths and the 'cubesizes'. 'cubesize(1)' is
|
1902
|
+
the number of pixels in a profile, 'cubesize(2)' is the number of pixels in a
|
1903
|
+
plane, 'cubesize(3)' is the number of pixels in a cube, etc. So, for a 3-d
|
1904
|
+
input cube, 'cubesize(3)' gives the total number of pixels to work on.
|
1905
|
+
|
1906
|
+
The subroutine xyzs2c can be used to obtain the values of the "fixed
|
1907
|
+
coordinates" for a given subcube number. The first element of the array coords
|
1908
|
+
then corresponds to the first "fixed coordinate" value, etc. E.g., for profiles
|
1909
|
+
in the 'z'-direction, coords(1) is the 'x'-position, coords(2) the 'y'-position.
|
1910
|
+
Subroutine xyzc2s does the inverse operation.
|
1911
|
+
|
1912
|
+
xyzread, xyzpixrd, xyzprfrd and xyzplnrd do the actual reading of data. xyzread
|
1913
|
+
takes as input the "fixed coordinate" values and returns the subcube in the
|
1914
|
+
1-dimensional array data. The other 3 routines read a single pixel, a single
|
1915
|
+
profile and a single plane, respectively. In each case the array data (whose
|
1916
|
+
dimension is transferred to the subroutines in the variable dimdata) should be
|
1917
|
+
large enough to hold the entire requested subcube. The logical array mask is
|
1918
|
+
used to indicate if datapixels were undefined (this is not yet implemented).
|
1919
|
+
mask=TRUE means the pixel is OK; FALSE means it is undefined.
|
1920
|
+
The write routine works in the same manner.
|
1921
|
+
If the program wants to loop over pixels or profiles, use of xyzs2c and xyzread
|
1922
|
+
becomes less efficient than use of xyzpixrd or xyzprfrd. In fact, for looping
|
1923
|
+
over pixels, the xyzs2c-xyzread combination is about 10 times less efficient
|
1924
|
+
than xyzpixrd. This is because with xyzs2c and xyzread the pixelnumber is first
|
1925
|
+
converted to a coordinate with xyzs2c and then converted back to a pixelnr in
|
1926
|
+
xyzread, while xyzpixrd avoids this overhead.
|
1927
|
+
|
1928
|
+
A typical call sequence using the xyz routines to work on profiles in the
|
1929
|
+
z-direction would be:
|
1930
|
+
|
1931
|
+
call xyzopen( tno1, name1, 'old', naxis, axlen )
|
1932
|
+
call xyzopen( tno2, name2, 'new', naxis, axlen )
|
1933
|
+
call headcopy( tno1, tno2, axnum, naxis ) ! axnum(i)=i
|
1934
|
+
call boxinput( 'region', name, boxes, maxboxes )
|
1935
|
+
call boxinfo( boxes, naxis, blc, trc )
|
1936
|
+
call xyzsetup( tno1, 'z', blc, trc, viraxlen, vircubesize )
|
1937
|
+
call xyzsetup( tno2, 'z', blc, trc, viraxlen, vircubesize )
|
1938
|
+
nprofiles = = vircubesize(naxis) / viraxlen(1)
|
1939
|
+
do profile = 1, nprofiles
|
1940
|
+
call xyzprfrd( tno1, profile, data, mask, dimdata )
|
1941
|
+
call work_on_profile( data, mask, dimdata )
|
1942
|
+
call xyzprfwr( tno2, profile, data, mask, dimdata )
|
1943
|
+
enddo
|
1944
|
+
|
1945
|
+
A warning is in order: each call to xyzsetup causes all internal buffers to be
|
1946
|
+
lost completely, so xyzsetup should be called for all datasets before starting
|
1947
|
+
to work on them. Output buffers are flushed before the buffers are lost,
|
1948
|
+
however.
|
1949
|
+
|
1950
|
+
The overhead introduced by the calculations done by the xyz routines is shown
|
1951
|
+
below. These were calculated using a testprogram that was complete but for
|
1952
|
+
actually doing something with the data and reading them from disk. The first
|
1953
|
+
number gives the times when using xyzpixrd, xyzprfrd and xyzplnrd, the second
|
1954
|
+
when using xyzs2c and xyzread. The overhead does not change with changing
|
1955
|
+
buffersize, but the number of disk-i/o's does. In a test using xyzprfrd and
|
1956
|
+
xyzprfwr on a 128^3 cube, with a 4Mb buffer, it took 120s to copy the input
|
1957
|
+
file using these routines, and 80s with a unix cp. With a 2Mb buffer the copy
|
1958
|
+
took 120s too, even though the number of i-o's increased from 12 to 22.
|
1959
|
+
|
1960
|
+
buffer of 524288 (2Mb): 1/2th of 128^3 cube; 1/16th of 256^3 cube
|
1961
|
+
cubesize 32^3 64^3 128^3 256^3
|
1962
|
+
pixels time(s) 0.3( 2.6) 1.6( 20.6) 12.4(170.2) 98.2(1396.6)
|
1963
|
+
n_i/o 1 2 13 97
|
1964
|
+
x profiles time(s) 0.1( 0.2) 0.6( 0.9) 4.2( 5.2) 31.2( 35.5)
|
1965
|
+
n_i/o 1 1 2 16
|
1966
|
+
y profiles time(s) 0.4( 0.4) 2.2( 2.5) 16.8( 17.9) 129.8(134.0)
|
1967
|
+
n_i/o 1 1 2 16
|
1968
|
+
z profiles time(s) 0.4( 0.4) 2.4( 2.5) 16.7( 17.7) 129.5(133.7)
|
1969
|
+
n_i/o 1 1 4 256
|
1970
|
+
xy planes time(s) 0.2( 0.1) 0.6( 0.5) 3.9( 4.0) 30.1( 30.1)
|
1971
|
+
n_i/o 1 1 2 16
|
1972
|
+
yx planes time(s) 0.4( 0.4) 2.2( 2.2) 16.4( 16.5) 128.6(128.7)
|
1973
|
+
n_i/o 1 1 2 16
|
1974
|
+
xz planes time(s) 0.3( 0.3) 2.2( 2.1) 16.4( 16.4) 128.4(128.4)
|
1975
|
+
n_i/o 1 1 4 256
|
1976
|
+
zx planes time(s) 0.3( 0.4) 2.2( 2.2) 16.5( 16.4) 128.2(128.3)
|
1977
|
+
n_i/o 1 1 4 256
|
1978
|
+
yz planes time(s) 0.4( 0.3) 2.1( 2.2) 16.9( 16.8) 157.4(157.4)
|
1979
|
+
n_i/o 1 1 4 256
|
1980
|
+
zy planes time(s) 0.4( 0.4) 2.2( 2.1) 16.9( 16.8) 157.4(157.3)
|
1981
|
+
n_i/o 1 1 4 256
|
1982
|
+
|
1983
|
+
cubesize 128*128*112 256*256*64
|
1984
|
+
z profiles time(s) 15.1 34.5
|
1985
|
+
n_i/o 8 32
|
1986
|
+
|
1987
|
+
*/
|
1988
|
+
|
1989
|
+
|
1990
|
+
/*
|
1991
|
+
Number of operations per call to xyz routines, 3-d cube:
|
1992
|
+
|
1993
|
+
xyzs2c: 82
|
1994
|
+
xyzr/w: 82+3n
|
1995
|
+
xyzpix: 15
|
1996
|
+
xyzprf: 36+3n
|
1997
|
+
xyzpln: 36+3n
|
1998
|
+
|
1999
|
+
pix/prf/pln xyzs2c & read ratio
|
2000
|
+
pixels (15)N^3 (164)N^3 15/164
|
2001
|
+
profiles (36+3N)N^2 (164+3N)N^2 (36+3N)/(164+3N)
|
2002
|
+
planes (36+3N^2)N (164+3N^2)N (36+3N^2)/(164+3N^2)
|
2003
|
+
|
2004
|
+
32^3 64^3 128^3 256^3 512^3
|
2005
|
+
pixels 0.091
|
2006
|
+
profiles 0.508 0.640 0.766 0.863 0.925
|
2007
|
+
planes 0.960 0.990 0.997 0.999 1.000
|
2008
|
+
|
2009
|
+
*/
|
2010
|
+
|
2011
|
+
|
2012
|
+
/******************************************************************************/
|
2013
|
+
/******************************************************************************/
|
2014
|
+
/******************************************************************************/
|
2015
|
+
|
2016
|
+
|
2017
|
+
|
2018
|
+
|
2019
|
+
|
2020
|
+
|