1 |
greg |
2.1 |
#ifndef lint |
2 |
greg |
2.4 |
static const char RCSid[] = "$Id: pvsum.c,v 2.3 2025/03/28 21:36:31 greg Exp $"; |
3 |
greg |
2.1 |
#endif |
4 |
|
|
/* |
5 |
|
|
* pvsum.c - add together spectral and/or float pictures |
6 |
|
|
* based on vector or matrix, similar to dctimestep |
7 |
|
|
*/ |
8 |
|
|
|
9 |
|
|
#include <math.h> |
10 |
|
|
#include "rtio.h" |
11 |
|
|
#include "resolu.h" |
12 |
|
|
#include "platform.h" |
13 |
|
|
#include "paths.h" |
14 |
greg |
2.2 |
#include "random.h" |
15 |
greg |
2.1 |
#include "rmatrix.h" |
16 |
|
|
#if !defined(_WIN32) && !defined(_WIN64) |
17 |
|
|
#include <sys/mman.h> |
18 |
|
|
#endif |
19 |
|
|
|
20 |
|
|
int nprocs = 1; /* # of calculation processes (Unix) */ |
21 |
|
|
int in_type = DTfromHeader; /* input data type */ |
22 |
|
|
int out_type = DTfromHeader; /* output data type */ |
23 |
|
|
char *in_spec = NULL; /* input specification */ |
24 |
|
|
char *out_spec = NULL; /* output file specification */ |
25 |
|
|
|
26 |
|
|
int iswapped = 0; /* input data is byte-swapped? */ |
27 |
|
|
int ncomp = 3; /* # input components */ |
28 |
|
|
int xres=0, yres=0; /* input image dimensions */ |
29 |
|
|
|
30 |
|
|
RMATRIX *cmtx = NULL; /* coefficient matrix */ |
31 |
|
|
|
32 |
|
|
/* does the given spec contain integer format? */ |
33 |
|
|
int |
34 |
|
|
hasFormat(const char *s) |
35 |
|
|
{ |
36 |
|
|
restart: |
37 |
|
|
if (s) s = strchr(s, '%'); |
38 |
|
|
if (!s) return(0); |
39 |
|
|
if (s[1] == '%') { /* "%%" ? */ |
40 |
|
|
s += 2; |
41 |
|
|
goto restart; |
42 |
|
|
} |
43 |
|
|
while (*++s) { |
44 |
|
|
if (strchr("diouxX", *s)) |
45 |
|
|
return(1); /* integer format */ |
46 |
|
|
if (strchr("%fFeEgGaAcsb", *s)) |
47 |
|
|
break; /* non-integer format */ |
48 |
|
|
} |
49 |
|
|
return(0); |
50 |
|
|
} |
51 |
|
|
|
52 |
|
|
/* get first input header data we'll need */ |
53 |
|
|
int |
54 |
|
|
iheadline(char *s, void *p) |
55 |
|
|
{ |
56 |
|
|
char fmt[MAXFMTLEN]; |
57 |
|
|
int i; |
58 |
|
|
|
59 |
|
|
if (!strncmp(s, "NCOLS=", 6)) { |
60 |
|
|
xres = atoi(s+6); |
61 |
|
|
return(1); |
62 |
|
|
} |
63 |
|
|
if (!strncmp(s, "NROWS=", 6)) { |
64 |
|
|
yres = atoi(s+6); |
65 |
|
|
return(1); |
66 |
|
|
} |
67 |
|
|
if (isncomp(s)) { |
68 |
|
|
ncomp = ncompval(s); |
69 |
|
|
return(1); |
70 |
|
|
} |
71 |
|
|
if (formatval(fmt, s)) { |
72 |
|
|
for (in_type = DTend; --in_type > DTfromHeader; ) |
73 |
|
|
if (!strcmp(fmt, cm_fmt_id[in_type])) |
74 |
|
|
return(1); |
75 |
|
|
return(-1); |
76 |
|
|
} |
77 |
|
|
i = isbigendian(s); |
78 |
|
|
if (i >= 0) { |
79 |
|
|
iswapped = (i != nativebigendian()); |
80 |
|
|
return(1); |
81 |
|
|
} |
82 |
|
|
return(0); |
83 |
|
|
} |
84 |
|
|
|
85 |
|
|
/* open initial file and get relevant dimensions and type */ |
86 |
|
|
int |
87 |
|
|
get_iotypes(void) |
88 |
|
|
{ |
89 |
|
|
char fbuf[256]; |
90 |
|
|
FILE *fp; |
91 |
|
|
|
92 |
|
|
sprintf(fbuf, in_spec, 0); |
93 |
|
|
fp = fopen(fbuf, "rb"); |
94 |
|
|
if (!fp) { |
95 |
|
|
fprintf(stderr, "%s: cannot open for reading\n", fbuf); |
96 |
|
|
return(0); |
97 |
|
|
} |
98 |
|
|
if (getheader(fp, iheadline, NULL) < 0) { |
99 |
|
|
fprintf(stderr, "%s: bad header - wrong format?\n", fbuf); |
100 |
|
|
fclose(fp); |
101 |
|
|
return(0); |
102 |
|
|
} |
103 |
|
|
if ((xres <= 0) | (yres <= 0) && !fscnresolu(&xres, &yres, fp)) { |
104 |
|
|
fprintf(stderr, "%s: missing input resolution\n", fbuf); |
105 |
|
|
fclose(fp); |
106 |
|
|
return(0); |
107 |
|
|
} |
108 |
|
|
if (nprocs > 1 && (in_type==DTrgbe) | (in_type==DTxyze)) { |
109 |
|
|
long data_start = ftell(fp); /* make sure input flat */ |
110 |
|
|
off_t dend = lseek(fileno(fp), 0, SEEK_END); |
111 |
|
|
if (dend < data_start + 4L*xres*yres) { |
112 |
|
|
fputs("Warning - multi-processing requires flat input files\n", |
113 |
|
|
stderr); |
114 |
|
|
nprocs = 1; |
115 |
|
|
} |
116 |
|
|
} |
117 |
|
|
fclose(fp); |
118 |
|
|
if ((cmtx->ncomp == 1) & (ncomp != 1)) { |
119 |
|
|
double xfm[MAXCSAMP]; |
120 |
|
|
RMATRIX *nmtx; |
121 |
|
|
int i; |
122 |
|
|
for (i = ncomp; i--; ) |
123 |
|
|
xfm[i] = 1.; |
124 |
|
|
nmtx = rmx_transform(cmtx, ncomp, xfm); |
125 |
|
|
if (!nmtx) |
126 |
|
|
return(0); |
127 |
|
|
rmx_free(cmtx); |
128 |
|
|
cmtx = nmtx; |
129 |
|
|
} else if (cmtx->ncomp != ncomp) { |
130 |
|
|
fprintf(stderr, "operation %s needs %d components, has %d\n", |
131 |
|
|
cmtx->ncols == 1 ? "vector" : "matrix", |
132 |
|
|
ncomp, cmtx->ncomp); |
133 |
|
|
return(0); |
134 |
|
|
} |
135 |
|
|
if ((in_type != DTrgbe) & (in_type != DTxyze) & (in_type != DTspec) & |
136 |
|
|
(in_type != DTfloat)) { |
137 |
|
|
fprintf(stderr, "%s unsupported input data type: %s\n", |
138 |
|
|
fbuf, cm_fmt_id[in_type]); |
139 |
|
|
return(0); |
140 |
|
|
} |
141 |
|
|
if ((out_type == DTrgbe) & (ncomp > 3)) |
142 |
|
|
out_type = DTspec; |
143 |
|
|
else if (out_type == DTfromHeader || |
144 |
|
|
(out_type == DTrgbe) & (in_type != DTfloat)) |
145 |
|
|
out_type = in_type; |
146 |
|
|
return(1); |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
/* check subsequent headers match initial file */ |
150 |
|
|
int |
151 |
|
|
checkline(char *s, void *p) |
152 |
|
|
{ |
153 |
greg |
2.3 |
static int exposWarned = 0; |
154 |
|
|
int *xyres = (int *)p; |
155 |
|
|
char fmt[MAXFMTLEN]; |
156 |
greg |
2.1 |
|
157 |
|
|
if (!strncmp(s, "NCOLS=", 6)) { |
158 |
|
|
xyres[0] = atoi(s+6); |
159 |
|
|
if (xyres[0] <= 0) |
160 |
|
|
return(-1); |
161 |
|
|
return(1); |
162 |
|
|
} |
163 |
|
|
if (!strncmp(s, "NROWS=", 6)) { |
164 |
|
|
xyres[1] = atoi(s+6); |
165 |
|
|
if (xyres[1] <= 0) |
166 |
|
|
return(-1); |
167 |
|
|
return(1); |
168 |
|
|
} |
169 |
|
|
if (isncomp(s)) { |
170 |
|
|
if (ncompval(s) != ncomp) |
171 |
|
|
return(-1); |
172 |
|
|
return(1); |
173 |
|
|
} |
174 |
|
|
if (isexpos(s)) { |
175 |
greg |
2.3 |
if (!exposWarned && fabs(1. - exposval(s)) > 0.04) { |
176 |
|
|
fputs("Warning - ignoring EXPOSURE setting(s)\n", |
177 |
|
|
stderr); |
178 |
|
|
exposWarned++; |
179 |
|
|
} |
180 |
greg |
2.1 |
return(1); |
181 |
|
|
} |
182 |
|
|
if (formatval(fmt, s)) { |
183 |
|
|
if (strcmp(fmt, cm_fmt_id[in_type])) |
184 |
|
|
return(-1); |
185 |
|
|
return(1); |
186 |
|
|
} |
187 |
|
|
return(0); |
188 |
|
|
} |
189 |
|
|
|
190 |
|
|
/* open and check input file */ |
191 |
|
|
FILE * |
192 |
|
|
open_input(char *fname) |
193 |
|
|
{ |
194 |
|
|
int xyres[2]; |
195 |
|
|
FILE *fp = fopen(fname, "rb"); |
196 |
|
|
|
197 |
|
|
if (!fp) { |
198 |
|
|
fprintf(stderr, "%s: cannot open for reading\n", fname); |
199 |
|
|
return(NULL); |
200 |
|
|
} |
201 |
|
|
xyres[0] = xyres[1] = 0; |
202 |
|
|
if (getheader(fp, checkline, xyres) < 0) { |
203 |
|
|
fprintf(stderr, "%s: bad/inconsistent header\n", fname); |
204 |
|
|
fclose(fp); |
205 |
|
|
return(NULL); |
206 |
|
|
} |
207 |
|
|
if ((xyres[0] <= 0) | (xyres[1] <= 0) && |
208 |
|
|
!fscnresolu(&xyres[0], &xyres[1], fp)) { |
209 |
|
|
fprintf(stderr, "%s: missing resolution\n", fname); |
210 |
|
|
fclose(fp); |
211 |
|
|
return(NULL); |
212 |
|
|
} |
213 |
|
|
if ((xyres[0] != xres) | (xyres[1] != yres)) { |
214 |
|
|
fprintf(stderr, "%s: mismatched resolution\n", fname); |
215 |
|
|
fclose(fp); |
216 |
|
|
return(NULL); |
217 |
|
|
} |
218 |
|
|
return(fp); |
219 |
|
|
} |
220 |
|
|
|
221 |
|
|
/* open output file or command (if !NULL) and write info header */ |
222 |
|
|
FILE * |
223 |
|
|
open_output(char *ospec, int fno) |
224 |
|
|
{ |
225 |
|
|
FILE *fp; |
226 |
|
|
|
227 |
|
|
if (!ospec) { |
228 |
|
|
ospec = "<stdout>"; |
229 |
|
|
fp = stdout; |
230 |
|
|
} else if (ospec[0] == '!') { |
231 |
|
|
if (!(fp = popen(ospec+1, "w"))) { |
232 |
|
|
fprintf(stderr, "Cannot start: %s\n", ospec); |
233 |
|
|
return(NULL); |
234 |
|
|
} |
235 |
greg |
2.3 |
} else if (!(fp = fopen(ospec, "w"))) { |
236 |
greg |
2.1 |
fprintf(stderr, "%s: cannot open for writing\n", ospec); |
237 |
|
|
return(NULL); |
238 |
|
|
} |
239 |
greg |
2.3 |
SET_FILE_BINARY(fp); |
240 |
greg |
2.1 |
newheader("RADIANCE", fp); |
241 |
greg |
2.2 |
if (cmtx->info) /* prepend matrix metadata */ |
242 |
|
|
fputs(cmtx->info, fp); |
243 |
|
|
else |
244 |
|
|
fputnow(fp); |
245 |
greg |
2.1 |
if (fno >= 0) |
246 |
|
|
fprintf(fp, "FRAME=%d\n", fno); |
247 |
|
|
switch (out_type) { |
248 |
|
|
case DTfloat: |
249 |
|
|
case DTdouble: |
250 |
|
|
fprintf(fp, "NCOLS=%d\nNROWS=%d\n", xres, yres); |
251 |
|
|
fputncomp(ncomp, fp); |
252 |
|
|
fputendian(fp); |
253 |
|
|
fputformat(cm_fmt_id[out_type], fp); |
254 |
|
|
fputc('\n', fp); |
255 |
|
|
break; |
256 |
|
|
case DTrgbe: |
257 |
|
|
fputformat(COLRFMT, fp); |
258 |
|
|
fputc('\n', fp); |
259 |
|
|
fprtresolu(xres, yres, fp); |
260 |
|
|
break; |
261 |
|
|
case DTxyze: |
262 |
|
|
fputformat(CIEFMT, fp); |
263 |
|
|
fputc('\n', fp); |
264 |
|
|
fprtresolu(xres, yres, fp); |
265 |
|
|
break; |
266 |
|
|
case DTspec: |
267 |
|
|
fputncomp(ncomp, fp); |
268 |
|
|
fputwlsplit(cmtx->wlpart, fp); |
269 |
|
|
fputformat(SPECFMT, fp); |
270 |
|
|
fputc('\n', fp); |
271 |
|
|
fprtresolu(xres, yres, fp); |
272 |
|
|
break; |
273 |
|
|
default: |
274 |
|
|
fputs("Unsupported output type!\n", stderr); |
275 |
|
|
return(NULL); |
276 |
|
|
} |
277 |
|
|
if (fflush(fp) < 0) { |
278 |
|
|
fprintf(stderr, "%s: write error\n", ospec); |
279 |
|
|
fclose(fp); |
280 |
|
|
return(NULL); |
281 |
|
|
} |
282 |
|
|
return(fp); |
283 |
|
|
} |
284 |
|
|
|
285 |
|
|
/* run calculation from a single process */ |
286 |
|
|
int |
287 |
|
|
solo_process(void) |
288 |
|
|
{ |
289 |
|
|
float *osum = (float *)calloc((size_t)xres*yres, sizeof(float)*ncomp); |
290 |
|
|
COLORV *iscan = (COLORV *)malloc(sizeof(COLORV)*ncomp*xres); |
291 |
|
|
char fbuf[512]; |
292 |
|
|
int c; |
293 |
|
|
|
294 |
|
|
if (!osum | !iscan) { |
295 |
|
|
fprintf(stderr, "Cannot allocate %dx%d %d-component accumulator\n", |
296 |
|
|
xres, yres, ncomp); |
297 |
|
|
return(0); |
298 |
|
|
} |
299 |
|
|
if (sizeof(float) != sizeof(COLORV)) { |
300 |
|
|
fputs("Code Error 1 in solo_process()\n", stderr); |
301 |
|
|
return(0); |
302 |
|
|
} |
303 |
|
|
for (c = 0; c < cmtx->ncols; c++) { /* run through each column/output */ |
304 |
|
|
FILE *fout; |
305 |
|
|
int y; |
306 |
|
|
int rc = cmtx->nrows; |
307 |
|
|
if (c > 0) /* clear accumulator? */ |
308 |
|
|
memset(osum, 0, sizeof(float)*ncomp*xres*yres); |
309 |
|
|
while (rc-- > 0) { /* run through each input file */ |
310 |
|
|
const int r = c&1 ? rc : cmtx->nrows-1 - rc; |
311 |
|
|
const rmx_dtype *cval = rmx_val(cmtx, r, c); |
312 |
|
|
FILE *finp; |
313 |
|
|
int i, x; |
314 |
|
|
for (i = ncomp; i--; ) |
315 |
|
|
if (cval[i] != 0) break; |
316 |
|
|
if (i < 0) /* this coefficient is zero, skip */ |
317 |
|
|
continue; |
318 |
|
|
sprintf(fbuf, in_spec, r); |
319 |
|
|
finp = open_input(fbuf); |
320 |
|
|
if (!finp) |
321 |
|
|
return(0); |
322 |
|
|
for (y = 0; y < yres; y++) { |
323 |
|
|
float *dst = osum + y*xres*ncomp; |
324 |
|
|
if (in_type == DTfloat ? getbinary(iscan, sizeof(float)*ncomp, |
325 |
|
|
xres, finp) != xres |
326 |
|
|
: freadsscan(iscan, ncomp, xres, finp) < 0) |
327 |
|
|
goto readerr; |
328 |
|
|
if ((in_type == DTfloat) & iswapped) |
329 |
|
|
swap32((char *)iscan, ncomp*xres); |
330 |
|
|
for (x = 0; x < xres; x++, dst += ncomp) |
331 |
|
|
for (i = ncomp; i--; ) |
332 |
|
|
dst[i] += cval[i]*iscan[x*ncomp + i]; |
333 |
|
|
} |
334 |
|
|
fclose(finp); |
335 |
|
|
} /* write out accumulated column result... */ |
336 |
|
|
if (out_spec) { /* ...to file or command */ |
337 |
|
|
if (cmtx->ncols > 1 && !hasFormat(out_spec)) { |
338 |
|
|
fputs("Sequential result must go to stdout\n", stderr); |
339 |
|
|
return(0); |
340 |
|
|
} |
341 |
|
|
sprintf(fbuf, out_spec, c); |
342 |
|
|
fout = open_output(fbuf, c-(cmtx->ncols==1)); |
343 |
|
|
} else { /* ...to stdout */ |
344 |
|
|
if ((out_type == DTfloat) & (cmtx->ncols > 1)) { |
345 |
|
|
fputs("Float outputs must have separate destinations\n", |
346 |
|
|
stderr); |
347 |
|
|
return(0); |
348 |
|
|
} |
349 |
|
|
strcpy(fbuf, "<stdout>"); |
350 |
|
|
fout = open_output(NULL, c-(cmtx->ncols==1)); |
351 |
|
|
} |
352 |
|
|
if (!fout) |
353 |
|
|
return(0); /* assume error was reported */ |
354 |
|
|
if (out_type != DTfloat) { |
355 |
|
|
for (y = 0; y < yres; y++) |
356 |
|
|
if (fwritesscan(osum + (size_t)y*xres*ncomp, |
357 |
|
|
ncomp, xres, fout) < 0) |
358 |
|
|
goto writerr; |
359 |
|
|
} else if (fwrite(osum, sizeof(float)*ncomp, (size_t)xres*yres, fout) != |
360 |
|
|
(size_t)xres*yres) |
361 |
|
|
goto writerr; |
362 |
|
|
|
363 |
|
|
if (fbuf[0] == '!') { |
364 |
|
|
if (pclose(fout) != 0) { |
365 |
|
|
fprintf(stderr, "Bad status from: %s\n", fbuf); |
366 |
|
|
return(0); |
367 |
|
|
} |
368 |
|
|
} else if (fout != stdout && fclose(fout) == EOF) |
369 |
|
|
goto writerr; |
370 |
|
|
} |
371 |
|
|
free(osum); /* clean up on success */ |
372 |
|
|
free(iscan); |
373 |
|
|
return(1); |
374 |
|
|
readerr: |
375 |
|
|
fprintf(stderr, "%s: read error\n", fbuf); |
376 |
|
|
return(0); |
377 |
|
|
writerr: |
378 |
|
|
fprintf(stderr, "%s: write error\n", fbuf); |
379 |
|
|
return(0); |
380 |
|
|
} |
381 |
|
|
|
382 |
greg |
2.2 |
/* allocate a scrambled index array of the specified length */ |
383 |
|
|
int * |
384 |
|
|
scramble(int n) |
385 |
|
|
{ |
386 |
|
|
int *scarr = (int *)malloc(sizeof(int)*n); |
387 |
|
|
int i; |
388 |
|
|
|
389 |
|
|
if (!scarr) { |
390 |
|
|
fprintf(stderr, "Out of memory in scramble(%d)\n", n); |
391 |
|
|
exit(1); |
392 |
|
|
} |
393 |
|
|
for (i = n; i--; ) |
394 |
|
|
scarr[i] = i; |
395 |
|
|
/* perform Fisher-Yates shuffle */ |
396 |
|
|
for (i = 0; i < n-1; i++) { |
397 |
|
|
int ix = irandom(n-i) + i; |
398 |
|
|
int ndx = scarr[i]; |
399 |
|
|
scarr[i] = scarr[ix]; |
400 |
|
|
scarr[ix] = ndx; |
401 |
|
|
} |
402 |
|
|
return(scarr); |
403 |
|
|
} |
404 |
|
|
|
405 |
greg |
2.1 |
/* run calculation on multiple processes, using memory maps and fork() */ |
406 |
|
|
int |
407 |
|
|
multi_process(void) |
408 |
|
|
{ |
409 |
|
|
#if defined(_WIN32) || defined(_WIN64) |
410 |
|
|
fputs("Bad call to multi_process()\n", stderr); |
411 |
|
|
return(0); |
412 |
|
|
#else |
413 |
|
|
int coff = nprocs; |
414 |
|
|
int odd = 0; |
415 |
|
|
char fbuf[512]; |
416 |
|
|
float *osum; |
417 |
greg |
2.2 |
int *syarr; |
418 |
greg |
2.1 |
int c; |
419 |
|
|
/* sanity check */ |
420 |
|
|
if (sizeof(float) != sizeof(COLORV)) { |
421 |
|
|
fputs("Code Error 1 in multi_process()\n", stderr); |
422 |
|
|
return(0); |
423 |
|
|
} |
424 |
|
|
while (--coff > 0) { /* parent births children */ |
425 |
|
|
int pid = fork(); |
426 |
|
|
if (pid < 0) { |
427 |
|
|
fputs("fork() call failed!\n", stderr); |
428 |
|
|
return(0); |
429 |
|
|
} |
430 |
|
|
if (pid == 0) break; /* child gets to work */ |
431 |
|
|
} |
432 |
|
|
osum = (float *)calloc((size_t)xres*yres, sizeof(float)*ncomp); |
433 |
|
|
if (!osum) { |
434 |
|
|
fprintf(stderr, "Cannot allocate %dx%d %d-component accumulator\n", |
435 |
|
|
xres, yres, ncomp); |
436 |
|
|
return(0); |
437 |
|
|
} |
438 |
greg |
2.2 |
srandom(113*coff + 5669); /* randomize row access for this process */ |
439 |
|
|
syarr = scramble(yres); |
440 |
greg |
2.1 |
/* run through our unique set of columns */ |
441 |
|
|
for (c = coff; c < cmtx->ncols; c += nprocs) { |
442 |
|
|
FILE *fout; |
443 |
|
|
int y; |
444 |
|
|
int rc = cmtx->nrows; |
445 |
|
|
if (c > coff) /* clear accumulator? */ |
446 |
|
|
memset(osum, 0, sizeof(float)*ncomp*xres*yres); |
447 |
|
|
while (rc-- > 0) { /* map & sum each input file */ |
448 |
|
|
const int r = odd ? rc : cmtx->nrows-1 - rc; |
449 |
|
|
const rmx_dtype *cval = rmx_val(cmtx, r, c); |
450 |
greg |
2.2 |
long dstart; |
451 |
greg |
2.1 |
size_t maplen; |
452 |
|
|
void *imap; |
453 |
|
|
FILE *finp; |
454 |
|
|
float *dst; |
455 |
greg |
2.2 |
int i, x; |
456 |
greg |
2.1 |
for (i = ncomp; i--; ) |
457 |
|
|
if (cval[i] != 0) break; |
458 |
|
|
if (i < 0) /* this coefficient is zero, skip */ |
459 |
|
|
continue; |
460 |
|
|
sprintf(fbuf, in_spec, r); |
461 |
|
|
finp = open_input(fbuf); |
462 |
|
|
if (!finp) |
463 |
|
|
return(0); |
464 |
|
|
dstart = ftell(finp); |
465 |
|
|
if (dstart < 0) { |
466 |
|
|
fprintf(stderr, "%s: ftell() failed!\n", fbuf); |
467 |
|
|
return(0); |
468 |
|
|
} |
469 |
|
|
if (in_type == DTfloat && dstart%sizeof(float)) { |
470 |
|
|
fprintf(stderr, "%s: float header misalignment\n", fbuf); |
471 |
|
|
return(0); |
472 |
|
|
} |
473 |
|
|
i = in_type==DTfloat ? ncomp*(int)sizeof(float) : ncomp+1; |
474 |
|
|
maplen = dstart + yres*xres*i; |
475 |
|
|
imap = mmap(NULL, maplen, PROT_READ, |
476 |
|
|
MAP_FILE|MAP_SHARED, fileno(finp), 0); |
477 |
greg |
2.3 |
fclose(finp); /* will read from map (randomly) */ |
478 |
greg |
2.1 |
if (imap == MAP_FAILED) { |
479 |
|
|
fprintf(stderr, "%s: unable to map input file\n", fbuf); |
480 |
|
|
return(0); |
481 |
|
|
} |
482 |
greg |
2.2 |
if (in_type == DTfloat) |
483 |
|
|
for (y = yres; y-- > 0; ) { |
484 |
|
|
const float *fvp = (float *)((char *)imap + dstart) + |
485 |
|
|
(size_t)ncomp*xres*syarr[y]; |
486 |
|
|
dst = osum + (size_t)ncomp*xres*syarr[y]; |
487 |
|
|
for (x = xres; x-- > 0; dst += ncomp, fvp += ncomp) |
488 |
|
|
for (i = ncomp; i--; ) |
489 |
|
|
dst[i] += cval[i]*fvp[i]; |
490 |
|
|
} |
491 |
|
|
else |
492 |
|
|
for (y = yres; y-- > 0; ) { |
493 |
|
|
const COLRV *cvp = (COLRV *)((char *)imap + dstart) + |
494 |
|
|
(ncomp+1L)*xres*syarr[y]; |
495 |
|
|
dst = osum + (size_t)ncomp*xres*syarr[y]; |
496 |
|
|
for (x = xres; x-- > 0; dst += ncomp, cvp += ncomp+1) { |
497 |
|
|
const rmx_dtype fe = cxponent[cvp[ncomp]]; |
498 |
|
|
for (i = ncomp; i--; ) |
499 |
|
|
dst[i] += cval[i]*(cvp[i]+(rmx_dtype).5)*fe; |
500 |
|
|
} |
501 |
greg |
2.1 |
} |
502 |
|
|
munmap(imap, maplen); |
503 |
greg |
2.3 |
} /* write accumulated column picture/matrix */ |
504 |
greg |
2.1 |
sprintf(fbuf, out_spec, c); |
505 |
|
|
fout = open_output(fbuf, c); |
506 |
|
|
if (!fout) |
507 |
|
|
return(0); /* assume error was reported */ |
508 |
|
|
if (out_type != DTfloat) { |
509 |
|
|
for (y = 0; y < yres; y++) |
510 |
|
|
if (fwritesscan(osum + (size_t)y*xres*ncomp, |
511 |
|
|
ncomp, xres, fout) < 0) |
512 |
|
|
goto writerr; |
513 |
|
|
} else if (fwrite(osum, sizeof(float)*ncomp, (size_t)xres*yres, fout) != |
514 |
|
|
(size_t)xres*yres) |
515 |
|
|
goto writerr; |
516 |
|
|
|
517 |
|
|
if (fbuf[0] == '!') { |
518 |
|
|
if (pclose(fout) != 0) { |
519 |
|
|
fprintf(stderr, "Bad status from: %s\n", fbuf); |
520 |
|
|
return(0); |
521 |
|
|
} |
522 |
|
|
} else if (fclose(fout) == EOF) |
523 |
|
|
goto writerr; |
524 |
|
|
odd = !odd; /* go back & forth to milk page cache */ |
525 |
|
|
} |
526 |
|
|
free(osum); |
527 |
greg |
2.2 |
free(syarr); |
528 |
greg |
2.3 |
if (coff) /* child processes return here... */ |
529 |
greg |
2.1 |
return(1); |
530 |
|
|
c = 0; /* ...but parent waits for children */ |
531 |
|
|
while (++coff < nprocs) { |
532 |
|
|
int st; |
533 |
|
|
if (wait(&st) < 0) |
534 |
|
|
break; |
535 |
|
|
if (st) c = st; |
536 |
|
|
} |
537 |
|
|
return(c == 0); |
538 |
|
|
writerr: |
539 |
|
|
fprintf(stderr, "%s: write error\n", fbuf); |
540 |
|
|
return(0); |
541 |
|
|
#endif |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
int |
545 |
|
|
main(int argc, char *argv[]) |
546 |
|
|
{ |
547 |
|
|
int a; |
548 |
|
|
|
549 |
|
|
for (a = 1; a < argc-1 && argv[a][0] == '-'; a++) |
550 |
|
|
switch (argv[a][1]) { |
551 |
|
|
case 'o': /* output spec/format */ |
552 |
|
|
switch (argv[a][2]) { |
553 |
|
|
case '\0': |
554 |
|
|
out_spec = argv[++a]; |
555 |
|
|
break; |
556 |
|
|
case 'f': |
557 |
|
|
out_type = DTfloat; |
558 |
|
|
break; |
559 |
|
|
case 'c': |
560 |
|
|
out_type = DTrgbe; |
561 |
|
|
break; |
562 |
|
|
default: |
563 |
|
|
goto badopt; |
564 |
|
|
} |
565 |
|
|
break; |
566 |
|
|
case 'N': /* number of desired processes */ |
567 |
|
|
case 'n': /* quietly supported alternate */ |
568 |
|
|
nprocs = atoi(argv[++a]); |
569 |
|
|
if (nprocs <= 0) |
570 |
|
|
goto userr; |
571 |
|
|
break; |
572 |
|
|
default:; |
573 |
|
|
badopt: fprintf(stderr, "%s: bad option: %s\n", argv[0], argv[a]); |
574 |
|
|
goto userr; |
575 |
|
|
return(1); |
576 |
|
|
} |
577 |
|
|
if ((argc-a < 1) | (argc-a > 2) || argv[a][0] == '-') |
578 |
|
|
goto userr; |
579 |
|
|
in_spec = argv[a]; |
580 |
greg |
2.4 |
cmtx = rmx_load(argv[a+1]); /* loads from stdin if a+1==argc */ |
581 |
greg |
2.1 |
if (cmtx == NULL) |
582 |
|
|
return(1); /* error reported */ |
583 |
greg |
2.3 |
if (nprocs > cmtx->ncols) |
584 |
|
|
nprocs = cmtx->ncols; |
585 |
greg |
2.1 |
#if defined(_WIN32) || defined(_WIN64) |
586 |
|
|
if (nprocs > 1) { |
587 |
|
|
fprintf(stderr, "%s: warning - Windows only allows -N 1\n", argv[0]); |
588 |
|
|
nprocs = 1; |
589 |
|
|
} |
590 |
|
|
#else |
591 |
|
|
if ((nprocs > 1) & !out_spec) { |
592 |
|
|
fprintf(stderr, "%s: multi-processing result cannot go to stdout\n", |
593 |
|
|
argv[0]); |
594 |
|
|
nprocs = 1; |
595 |
|
|
} |
596 |
|
|
if ((nprocs > 1) & iswapped && (in_type==DTfloat) | (in_type==DTdouble)) { |
597 |
|
|
fprintf(stderr, "%s: multi-processing unsupported on swapped input\n", |
598 |
|
|
argv[0]); |
599 |
|
|
nprocs = 1; |
600 |
|
|
} |
601 |
|
|
#endif |
602 |
|
|
if (cmtx->nrows > 1 && !hasFormat(in_spec)) { |
603 |
|
|
fprintf(stderr, "%s: input specification '%s' needs %%d format\n", |
604 |
|
|
argv[0], in_spec); |
605 |
|
|
goto userr; |
606 |
|
|
} |
607 |
|
|
if (!get_iotypes()) |
608 |
|
|
return(1); |
609 |
|
|
if (!(nprocs == 1 ? solo_process() : multi_process())) |
610 |
|
|
return(1); |
611 |
|
|
return(0); |
612 |
|
|
userr: |
613 |
|
|
fprintf(stderr, "Usage: %s [-oc | -of][-o ospec][-N nproc] inpspec [mtx]\n", |
614 |
|
|
argv[0]); |
615 |
|
|
return(1); |
616 |
|
|
} |