1 /**
2  *  @file    mergedx.c
3  *  @author  Stephen Bond and Nathan Baker
4  *  @brief   Program that merges OpenDX files
5  *  @version $Id$
6  */
7 
8 #include "apbs.h"
9 
10 #define SHORTINT short
11 #define IJK(i,j,k)  (((k)*(nx)*(ny))+((j)*(nx))+(i))
12 #define INTERVAL(x,a,b) (((x) >= (a)) && ((x) <= (b)))
13 
14 VEMBED(rcsid="$Id$")
15 
16 VPRIVATE int Vgrid_readDXhead(Vgrid *thee,
17   const char *iodev, const char *iofmt, const char *thost, const char *fname);
18 VPRIVATE int Vgrid_value2(Vgrid *thee, double pt[3], double *value);
19 VPRIVATE int Char_parseARGV(int argc, char **argv, int *nx, int *ny, int *nz,
20   int *pad, char ***fnams, int *numfnams, char *outname, int *vflag);
21 
22 VPRIVATE char *MCwhiteChars = " =,;\t\n";
23 VPRIVATE char *MCcommChars  = "#%";
24 
main(int argc,char ** argv)25 int main(int argc, char **argv) {
26 
27     /* *************** VARIABLES ******************* */
28     int i, j, k, vlev = 1, vvlev = 0, vflag = 1;
29     int nx, ny, nz, count, numfnams;
30     double pt[3],value;
31     double xmin, ymin, zmin, xmax, ymax, zmax;
32     char **fnams = VNULL;
33     SHORTINT *carray = VNULL;
34     char *usage0 = "[FLAGS] nx ny nz file1.dx [file2.dx ...]\n";
35     char *req0  = "nx ny nz        Grid points on the merged grid";
36     char *req1  = "file1.dx        Names of unmerged grid files";
37     char *flag0 = "-v               Verbose                  (default: off)";
38     char *flag1 = "-quiet           Silent                   (default: off)";
39     char *flag2 = "-pad integer     Num. of pad grid points  (default: 1  )";
40     char *flag3 = "-o filename.dx   Output file    (default: gridmerged.dx)";
41     char *note0 = "Each subgrid is extended by the number of pad points,";
42     char *note1 = "which is often necessary to fill gaps between the grids.";
43     char *note2 = "Any overlap between subgrids is resolved by averaging.";
44     char *snam = "# main:  ";
45     char outname[80];
46     Vgrid *grid, *mgrid;
47     int pad = 1;
48 
49     Vio_start();
50     sprintf(outname,"gridmerged.dx");
51 
52     /* **************** OBSOLETE WARNING ***************** */
53     printf("WARNING: mergedx is deprecated. Please consider using mergedx2\n");
54 
55     /* **************** PARSE INPUT ARGS ***************** */
56 
57     if ( Char_parseARGV(argc, argv, &nx, &ny, &nz, &pad,
58                         &fnams, &numfnams, outname, &vflag) != 0 ) {
59         Vnm_print(2,"\nImproper or Unrecognized Switches?\nUsage: ");
60         Vnm_print(2,"%s %s\n",argv[0],usage0);
61         Vnm_print(2,"Input:\t\t%s\n\t\t%s\n\n", req0, req1);
62         Vnm_print(2,"Flags:\t\t%s\n\t\t%s\n\t\t%s\n\t\t%s\n\n",
63                   flag0, flag1, flag2, flag3);
64         Vnm_print(2,"Notes:\t\t%s\n\t\t%s\n\t\t%s\n",
65                   note0, note1, note2);
66         return -1;
67     }
68 
69     if (vflag == 1) {
70     vlev = 1;
71     vvlev = 0;
72     } else if (vflag) {
73         vlev = 2;
74         vvlev = 2;
75     } else {
76         vlev = 0;
77         vvlev = 0;
78     }
79 
80     /* *********** PREPARE MERGED GRID OBJECT ************* */
81     mgrid = Vgrid_ctor(nx, ny, nz, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, VNULL);
82     mgrid->xmin = VLARGE; mgrid->xmax = -VLARGE;
83     mgrid->ymin = VLARGE; mgrid->ymax = -VLARGE;
84     mgrid->zmin = VLARGE; mgrid->zmax = -VLARGE;
85 
86     /* *************** GET FILE HEADERS ******************* */
87     Vnm_print(vlev, "%s Reading Headers...\n",snam);
88     grid = Vgrid_ctor(0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, VNULL);
89     for(count=0; count<numfnams; count++) {
90         Vnm_print(vvlev, "%s  Reading header from %s...\n",snam,
91                   fnams[count]);
92         Vnm_tstart(26, "HEADER READ");
93         Vgrid_readDXhead(grid, "FILE", "ASC", VNULL, fnams[count]);
94         Vnm_tstop(26, "HEADER READ");
95         /* set the merged grid bounds to include all the subgrids */
96         if( grid->xmin < mgrid->xmin ) mgrid->xmin = grid->xmin;
97         if( grid->xmax > mgrid->xmax ) mgrid->xmax = grid->xmax;
98         if( grid->ymin < mgrid->ymin ) mgrid->ymin = grid->ymin;
99         if( grid->ymax > mgrid->ymax ) mgrid->ymax = grid->ymax;
100         if( grid->zmin < mgrid->zmin ) mgrid->zmin = grid->zmin;
101         if( grid->zmax > mgrid->zmax ) mgrid->zmax = grid->zmax;
102     }
103 
104     /* set the grid increment for the merged grid */
105     mgrid->hx   = (mgrid->xmax - mgrid->xmin)/(mgrid->nx - 1);
106     mgrid->hy   = (mgrid->ymax - mgrid->ymin)/(mgrid->ny - 1);
107     mgrid->hzed = (mgrid->zmax - mgrid->zmin)/(mgrid->nz - 1);
108 
109     /* print out the dimensions of the merged grid */
110     Vnm_print(vlev, "%s Dimensions of the merged grid\n",snam);
111     Vnm_print(vlev, "%s nx = %d, ny = %d, nz = %d\n",snam,
112               mgrid->nx, mgrid->ny, mgrid->nz);
113     Vnm_print(vlev, "%s hx = %g, hy = %g, hz = %g\n",snam,
114               mgrid->hx, mgrid->hy, mgrid->hzed);
115     Vnm_print(vlev, "%s xmin = %g, ymin = %g, zmin = %g\n",snam,
116               mgrid->xmin, mgrid-> ymin, mgrid->zmin);
117     Vnm_print(vlev, "%s xmax = %g, ymax = %g, zmax = %g\n",snam,
118               mgrid->xmax, mgrid-> ymax, mgrid->zmax);
119 
120     mgrid->data = (double *)
121        Vmem_malloc(mgrid->mem,(mgrid->nx*mgrid->ny*mgrid->nz),sizeof(double));
122     mgrid->ctordata = 1;
123     carray = (SHORTINT *)
124        Vmem_malloc(VNULL, (mgrid->nx*mgrid->ny*mgrid->nz), sizeof(SHORTINT) );
125 
126     /* initialize the data of the merged grid with zeros */
127     nx = mgrid->nx;
128     ny = mgrid->ny;
129     nz = mgrid->nz;
130     for (i=0; i<nx; i++) {
131         for (j=0; j<ny; j++) {
132             for (k=0; k<nz; k++) {
133                 (mgrid->data)[IJK(i,j,k)] = 0.0;
134                 carray[IJK(i,j,k)] = 0;
135             }
136         }
137     }
138 
139     /* ************** MERGE THE GRID FILES **************** */
140     Vnm_print(vlev, "%s Reading and Merging...\n",snam);
141     for (count=0; count<numfnams; count++) {
142         Vnm_print(vvlev, "%s  Reading data from %s...\n",snam,fnams[count]);
143         Vnm_tstart(26, "DATA READ");
144         Vgrid_readDX(grid, "FILE", "ASC", VNULL, fnams[count]);
145         Vnm_tstop(26, "DATA READ");
146         Vnm_print(vvlev, "%s  Merging data from %s...\n",snam,fnams[count]);
147         Vnm_tstart(26, "MERGING");
148         xmin = grid->xmin - pad*grid->hx   - VSMALL;
149         ymin = grid->ymin - pad*grid->hy   - VSMALL;
150         zmin = grid->zmin - pad*grid->hzed - VSMALL;
151         xmax = grid->xmax + pad*grid->hx   + VSMALL;
152         ymax = grid->ymax + pad*grid->hy   + VSMALL;
153         zmax = grid->zmax + pad*grid->hzed + VSMALL;
154         Vnm_print(vvlev, "%s  MIN (%g,%g,%g) IMIN (%g,%g,%g)\n",snam,
155                           grid->xmin,grid->ymin,grid->zmin,xmin,ymin,zmin);
156         Vnm_print(vvlev, "%s  MAX (%g,%g,%g) IMAX (%g,%g,%g)\n",snam,
157                           grid->xmax,grid->ymax,grid->zmax,xmax,ymax,zmax);
158         for (i=0; i<nx; i++) {
159             pt[0] = mgrid->xmin + i*mgrid->hx;
160             if(INTERVAL(pt[0],xmin,xmax)) {
161                 for (j=0; j<ny; j++) {
162                     pt[1] = mgrid->ymin + j*mgrid->hy;
163                     if(INTERVAL(pt[1],ymin,ymax)) {
164                         for (k=0; k<nz; k++) {
165                             pt[2] = mgrid->zmin + k*mgrid->hzed;
166                             if(INTERVAL(pt[2],zmin,zmax)) {
167                                 if (Vgrid_value2(grid, pt, &value)) {
168                                     (mgrid->data)[IJK(i,j,k)] += value;
169                                     carray[IJK(i,j,k)] += 1;
170                                 }
171                             }
172                         }
173                     }
174                 }
175             }
176         }
177         Vnm_tstop(26, "MERGING");
178         Vmem_free(grid->mem,(grid->nx*grid->ny*grid->nz), sizeof(double),
179                   (void **)&(grid->data));
180         grid->readdata = 0;
181         grid->ctordata = 0;
182     }
183     Vgrid_dtor( &grid );
184 
185     mgrid->readdata = 1;
186 
187     /* Check for skipped points, and account for overlap */
188     nx = mgrid->nx;
189     ny = mgrid->ny;
190     nz = mgrid->nz;
191     for (i=0; i<nx; i++) {
192         for (j=0; j<ny; j++) {
193             for (k=0; k<nz; k++) {
194                 if ( carray[IJK(i,j,k)] >= 1 ) {
195                     (mgrid->data)[IJK(i,j,k)] /= carray[IJK(i,j,k)];
196                 } else {
197                     Vnm_print(2,"%s %s %s (%g,%g,%g)\n",snam,
198                               "Warning: ",
199                               "Gap in subgrids at point",
200                               mgrid->xmin + i*mgrid->hx,
201                               mgrid->ymin + j*mgrid->hy,
202                               mgrid->zmin + k*mgrid->hzed );
203                 }
204             }
205         }
206     }
207 
208     /* ************** WRITE THE MERGED GRID **************** */
209     Vnm_print(vlev, "%s Writing...\n",snam);
210     Vnm_print(vvlev, "%s  Writing merged data to %s...\n",snam,outname);
211     Vgrid_writeDX(mgrid, "FILE", "ASC", VNULL, outname,"mergedx",VNULL);
212 
213     Vmem_free(VNULL,(mgrid->nx*mgrid->ny*mgrid->nz), sizeof(SHORTINT),
214               (void **)&(carray));
215     Vgrid_dtor( &mgrid );
216 
217     if ( vflag > 1 ) {
218         Vnm_print(2,"%s Memory Profiling Information\n",snam);
219         Vnm_print(2,"# --------------------------------------"
220                   "--------------------------------------\n");
221         Vnm_print(2,"#  Footprint        Areas       Malloc         Free"
222                   "    Highwater   Class\n");
223         Vnm_print(2,"# --------------------------------------"
224                   "--------------------------------------\n");
225         Vmem_print(VNULL);
226         Vmem_printTotal();
227         Vnm_print(2,"# --------------------------------------"
228                   "--------------------------------------\n");
229     }
230 
231     return 0;
232 }
233 
234 /* ///////////////////////////////////////////////////////////////////////////
235 // Routine:  Vgrid_readDXhead
236 //
237 // Author:   Nathan Baker and Stephen Bond
238 /////////////////////////////////////////////////////////////////////////// */
Vgrid_readDXhead(Vgrid * thee,const char * iodev,const char * iofmt,const char * thost,const char * fname)239 VPRIVATE int Vgrid_readDXhead(Vgrid *thee,
240   const char *iodev, const char *iofmt, const char *thost, const char *fname) {
241 
242     int itmp;
243     double dtmp;
244     char tok[VMAX_BUFSIZE];
245     char *snam = "Vgrid_readDXhead:";
246     Vio *sock;
247 
248     /* Check to see if the existing data is null and, if not, clear it out */
249     if (thee->data != VNULL) {
250         Vnm_print(1, "%s  destroying existing data!\n",snam);
251         Vmem_free(thee->mem, (thee->nx*thee->ny*thee->nz), sizeof(double),
252           (void **)&(thee->data)); }
253     thee->readdata = 0;
254     thee->ctordata = 0;
255 
256     /* Set up the virtual socket */
257     sock = Vio_ctor(iodev,iofmt,thost,fname,"r");
258     if (sock == VNULL) {
259         Vnm_print(2, "%s Problem opening virtual socket %s\n",snam,fname);
260         return 0;
261     }
262     if (Vio_accept(sock, 0) < 0) {
263         Vnm_print(2, "%s Problem accepting virtual socket %s\n",snam,fname);
264         return 0;
265     }
266 
267     Vio_setWhiteChars(sock, MCwhiteChars);
268     Vio_setCommChars(sock, MCcommChars);
269 
270     /* Read in the DX regular positions */
271     /* Get "object" */
272     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
273     VJMPERR1(!strcmp(tok, "object"));
274     /* Get "1" */
275     VJMPERR2(1 == Vio_scanf(sock, "%d", &itmp));
276     /* Get "class" */
277     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
278     VJMPERR1(!strcmp(tok, "class"));
279     /* Get "gridpositions" */
280     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
281     VJMPERR1(!strcmp(tok, "gridpositions"));
282     /* Get "counts" */
283     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
284     VJMPERR1(!strcmp(tok, "counts"));
285     /* Get nx */
286     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
287     VJMPERR1(1 == sscanf(tok, "%d", &(thee->nx)));
288     /* Get ny */
289     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
290     VJMPERR1(1 == sscanf(tok, "%d", &(thee->ny)));
291     /* Get nz */
292     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
293     VJMPERR1(1 == sscanf(tok, "%d", &(thee->nz)));
294     Vnm_print(0, "%s  Grid dimensions %d x %d x %d grid\n",snam,
295               thee->nx, thee->ny, thee->nz);
296     /* Get "origin" */
297     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
298     VJMPERR1(!strcmp(tok, "origin"));
299     /* Get xmin */
300     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
301     VJMPERR1(1 == sscanf(tok, "%lf", &(thee->xmin)));
302     /* Get ymin */
303     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
304     VJMPERR1(1 == sscanf(tok, "%lf", &(thee->ymin)));
305     /* Get zmin */
306     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
307     VJMPERR1(1 == sscanf(tok, "%lf", &(thee->zmin)));
308     Vnm_print(0, "%s  Grid origin = (%g, %g, %g)\n",snam,
309               thee->xmin, thee->ymin, thee->zmin);
310     /* Get "delta" */
311     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
312     VJMPERR1(!strcmp(tok, "delta"));
313     /* Get hx */
314     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
315     VJMPERR1(1 == sscanf(tok, "%lf", &(thee->hx)));
316     /* Get 0.0 */
317     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
318     VJMPERR1(1 == sscanf(tok, "%lf", &dtmp));
319     VJMPERR1(dtmp == 0.0);
320     /* Get 0.0 */
321     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
322     VJMPERR1(1 == sscanf(tok, "%lf", &dtmp));
323     VJMPERR1(dtmp == 0.0);
324     /* Get "delta" */
325     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
326     VJMPERR1(!strcmp(tok, "delta"));
327     /* Get 0.0 */
328     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
329     VJMPERR1(1 == sscanf(tok, "%lf", &dtmp));
330     VJMPERR1(dtmp == 0.0);
331     /* Get hy */
332     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
333     VJMPERR1(1 == sscanf(tok, "%lf", &(thee->hy)));
334     /* Get 0.0 */
335     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
336     VJMPERR1(1 == sscanf(tok, "%lf", &dtmp));
337     VJMPERR1(dtmp == 0.0);
338     /* Get "delta" */
339     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
340     VJMPERR1(!strcmp(tok, "delta"));
341     /* Get 0.0 */
342     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
343     VJMPERR1(1 == sscanf(tok, "%lf", &dtmp));
344     VJMPERR1(dtmp == 0.0);
345     /* Get 0.0 */
346     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
347     VJMPERR1(1 == sscanf(tok, "%lf", &dtmp));
348     VJMPERR1(dtmp == 0.0);
349     /* Get hz */
350     VJMPERR2(1 == Vio_scanf(sock, "%s", tok));
351     VJMPERR1(1 == sscanf(tok, "%lf", &(thee->hzed)));
352     Vnm_print(0, "%s  Grid spacings = (%g, %g, %g)\n",snam,
353               thee->hx, thee->hy, thee->hzed);
354     /* calculate grid maxima */
355     thee->xmax = thee->xmin + (thee->nx-1)*thee->hx;
356     thee->ymax = thee->ymin + (thee->ny-1)*thee->hy;
357     thee->zmax = thee->zmin + (thee->nz-1)*thee->hzed;
358 
359     /* Close off the socket */
360     Vio_acceptFree(sock);
361     Vio_dtor(&sock);
362 
363     return 1;
364 
365   VERROR1:
366     Vio_dtor(&sock);
367     Vnm_print(2, "%s  Format problem with input file <%s>\n",snam,fname);
368     return 0;
369 
370   VERROR2:
371     Vio_dtor(&sock);
372     Vnm_print(2, "%s  I/O problem with input file <%s>\n",snam,fname);
373     return 0;
374 }
375 
376 /* ///////////////////////////////////////////////////////////////////////////
377 // Routine:  Vgrid_value2
378 //
379 // Author:   Nathan Baker and Stephen Bond
380 /////////////////////////////////////////////////////////////////////////// */
Vgrid_value2(Vgrid * thee,double pt[3],double * value)381 VPUBLIC int Vgrid_value2(Vgrid *thee, double pt[3], double *value) {
382 
383     int nx, ny, nz, ihi, jhi, khi, ilo, jlo, klo;
384     double hx, hy, hzed, xmin, ymin, zmin, ifloat, jfloat, kfloat;
385     double u, dx, dy, dz;
386 
387     VASSERT(thee != VNULL);
388     VASSERT(thee->ctordata || thee->readdata);
389 
390     nx = thee->nx;
391     ny = thee->ny;
392     nz = thee->nz;
393     hx = thee->hx;
394     hy = thee->hy;
395     hzed = thee->hzed;
396     xmin = thee->xmin;
397     ymin = thee->ymin;
398     zmin = thee->zmin;
399 
400     u = 0;
401 
402     ifloat = (pt[0] - xmin)/hx;
403     jfloat = (pt[1] - ymin)/hy;
404     kfloat = (pt[2] - zmin)/hzed;
405     ihi = (int)ceil(ifloat);
406     jhi = (int)ceil(jfloat);
407     khi = (int)ceil(kfloat);
408     ilo = (int)floor(ifloat);
409     jlo = (int)floor(jfloat);
410     klo = (int)floor(kfloat);
411 
412     /* If the point is outside the mesh, push it to the mesh */
413     if ( ilo < 0 ) {
414         ilo = 0;
415         ihi = ilo + 1;
416         ifloat = (double)(ilo);
417     } else if ( ihi >= nx ) {
418         ihi = nx - 1;
419         ilo = ihi - 1;
420         ifloat = (double)(ihi);
421     }
422     if ( jlo < 0 ) {
423         jlo = 0;
424         jhi = jlo + 1;
425         jfloat = (double)(jlo);
426     } else if ( jhi >= ny ) {
427         jhi = ny - 1;
428         jlo = jhi - 1;
429         jfloat = (double)(jhi);
430     }
431     if ( klo < 0 ) {
432         klo = 0;
433         khi = klo + 1;
434         kfloat = (double)(klo);
435     } else if ( khi >= nz ) {
436         khi = nz - 1;
437         klo = khi - 1;
438         kfloat = (double)(khi);
439     }
440 
441     /* See if we're on the mesh */
442     if ((ihi<nx) && (jhi<ny) && (khi<nz) &&
443         (ilo>=0) && (jlo>=0) && (klo>=0)) {
444         dx = ifloat - (double)(ilo);
445         dy = jfloat - (double)(jlo);
446         dz = kfloat - (double)(klo);
447         u = dx      *dy      *dz      *(thee->data[IJK(ihi,jhi,khi)])
448           + dx      *(1.0-dy)*dz      *(thee->data[IJK(ihi,jlo,khi)])
449           + dx      *dy      *(1.0-dz)*(thee->data[IJK(ihi,jhi,klo)])
450           + dx      *(1.0-dy)*(1.0-dz)*(thee->data[IJK(ihi,jlo,klo)])
451           + (1.0-dx)*dy      *dz      *(thee->data[IJK(ilo,jhi,khi)])
452           + (1.0-dx)*(1.0-dy)*dz      *(thee->data[IJK(ilo,jlo,khi)])
453           + (1.0-dx)*dy      *(1.0-dz)*(thee->data[IJK(ilo,jhi,klo)])
454           + (1.0-dx)*(1.0-dy)*(1.0-dz)*(thee->data[IJK(ilo,jlo,klo)]);
455 
456         *value = u;
457         return 1;
458 
459     }
460 
461     *value = 0.0;
462     return 0;
463 }
464 
Char_parseARGV(int argc,char ** argv,int * nx,int * ny,int * nz,int * pad,char *** fnams,int * numfnams,char * outname,int * vflag)465 VPRIVATE int Char_parseARGV(int argc, char **argv,
466   int *nx, int *ny, int *nz, int *pad, char ***fnams, int *numfnams,
467   char *outname, int *vflag)
468 {
469     int i, j, hflag, nflags, sflag;
470 
471     i = 1;
472     hflag = 0;
473     nflags = 0;
474     while( i < argc ) {
475         if( argv[i][0] == '-' ) {
476             nflags++;
477             if (!strcmp(argv[i],"-v")) {
478                 (*vflag) = 2;
479             } else if (!strcmp(argv[i],"-quiet")) {
480                 (*vflag) = 0;
481             } else if (!strcmp(argv[i],"-o")) {
482                 i++;
483                 if( i < argc ) {
484                     nflags++;
485                     sprintf(outname,"%s",argv[i]);
486                 }
487             } else if (!strcmp(argv[i],"-pad")) {
488                 i++;
489                 if( i < argc ) {
490                     nflags++;
491                     (*pad) = atoi(argv[i]);
492                 }
493             } else {
494                 hflag = 1;
495             }
496         }
497         i++;
498     }
499 
500     /* *************** CHECK INVOCATION ******************* */
501     if ((argc - nflags) < 5 || hflag) {
502         return 1;
503     }
504 
505     /* ************* PARSE REMAINING ARGS ****************** */
506     i = 1;
507     j = 0;
508     hflag = 0;
509     sflag = 1;
510     while(i<argc && sflag) {
511         if( argv[i][0] == '-' ) {
512             j++;
513             if (!strcmp(argv[i],"-o")) {
514                 i++;
515                 j++;
516             } else if (!strcmp(argv[i],"-pad")) {
517                 i++;
518                 j++;
519             }
520         } else {
521             if( (i+2) < argc && nflags == j) {
522                 (*nx) = atoi(argv[i]);
523                 (*ny) = atoi(argv[i+1]);
524                 (*nz) = atoi(argv[i+2]);
525                 i += 2;
526             } else {
527                 hflag = 1;
528             }
529             sflag = 0;
530         }
531         i++;
532     }
533 
534     if (hflag) {
535         return 1;
536     }
537 
538     (*fnams) = &(argv[i]);
539     (*numfnams) = argc - i;
540 
541     return 0;
542 }
543 
544