miriad 4.1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+