ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/Development/ray/src/util/rcomb.c
(Generate patch)

Comparing ray/src/util/rcomb.c (file contents):
Revision 2.4 by greg, Tue Dec 19 16:09:20 2023 UTC vs.
Revision 2.35 by greg, Thu Oct 30 16:46:49 2025 UTC

# Line 3 | Line 3 | static const char RCSid[] = "$Id$";
3   #endif
4   /*
5   * General component matrix combiner, operating on a row at a time.
6 + *
7 + * Multi-processing mode under Unix creates children that each work
8 + * on one input row at a time, fed by the original process.  Final conversion
9 + * and output to stdout is sorted by last child while its siblings send it
10 + * their record calculations.
11   */
12  
8 #include <errno.h>
13   #include <math.h>
14   #include "platform.h"
15 + #include "rtprocess.h"
16   #include "rtio.h"
12 #include "resolu.h"
17   #include "rmatrix.h"
18   #include "calcomp.h"
15 #include "paths.h"
19  
20   #ifndef M_PI
21   #define M_PI    3.14159265358979323846
22   #endif
23  
21 #define MAXCOMP         MAXCSAMP        /* #components we support */
22
24   /* Unary matrix operation(s) */
25   typedef struct {
26          double          cmat[MAXCOMP*MAXCOMP];  /* component transformation */
# Line 55 | Line 56 | int            cur_row;                        /* current input/output row */
56   int             cur_col;                        /* current input/output column */
57   int             cur_chan;                       /* if we're looping channels */
58  
59 < static int      checksymbolic(ROPMAT *rop);
59 > SUBPROC         *cproc = NULL;                  /* child process array */
60 > int             nchildren = 0;                  /* # of child processes */
61 > int             inchild = -1;                   /* our child ID (-1: parent) */
62  
63 < static int
63 > extern int      checksymbolic(ROPMAT *rop);
64 >
65 > /* Split input matrices to allow for certain operations */
66 > int
67   split_input(ROPMAT *rop)
68   {
69          if (rop->rmp == &rop->imx && !(rop->rmp = rmx_copy(&rop->imx))) {
# Line 69 | Line 75 | split_input(ROPMAT *rop)
75   }
76  
77   /* Check/set transform based on a reference input file */
78 < static int
78 > int
79   checkreffile(ROPMAT *rop)
80   {
81          static const char       *curRF = NULL;
# Line 132 | Line 138 | checkreffile(ROPMAT *rop)
138   }
139  
140   /* Compute conversion row from spectrum to one channel of RGB */
141 < static void
141 > void
142   rgbrow(ROPMAT *rop, int r, int p)
143   {
144          const int       nc = rop->imx.ncomp;
# Line 149 | Line 155 | rgbrow(ROPMAT *rop, int r, int p)
155   }
156  
157   /* Compute conversion row from spectrum to one channel of XYZ */
158 < static void
158 > void
159   xyzrow(ROPMAT *rop, int r, int p)
160   {
161          const int       nc = rop->imx.ncomp;
# Line 166 | Line 172 | xyzrow(ROPMAT *rop, int r, int p)
172   }
173  
174   /* Use the spectral sensitivity function to compute matrix coefficients */
175 < static void
176 < sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, int ncs, const float wlpt[4]))
175 > void
176 > sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
177   {
178          const int       nc = rop->imx.ncomp;
179          int             i;
# Line 181 | Line 187 | sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, in
187   }
188  
189   /* Check/set symbolic transform */
190 < static int
190 > int
191   checksymbolic(ROPMAT *rop)
192   {
193          const int       nc = rop->imx.ncomp;
# Line 189 | Line 195 | checksymbolic(ROPMAT *rop)
195          double          cf = 1;
196          int             i, j;
197                                          /* check suffix => reference file */
198 <        if (strchr(rop->preop.csym, '.') > rop->preop.csym)
198 >        if (strchr(rop->preop.csym, '.') != NULL)
199                  return(checkreffile(rop));
200  
201          if (nc < 3) {
# Line 295 | Line 301 | checksymbolic(ROPMAT *rop)
301          return(1);
302   }
303  
304 < static int
304 > /* Set up color transform for matrix */
305 > int
306   get_component_xfm(ROPMAT *rop)
307   {
308          int     i, j;
# Line 378 | Line 385 | get_component_xfm(ROPMAT *rop)
385          return(1);
386   }
387  
388 < static int
388 > /* Apply the given color transform and/or scaling operation */
389 > int
390   apply_op(RMATRIX *dst, const RMATRIX *src, const RUNARYOP *ro)
391   {
392          if (ro->clen > 0) {
# Line 391 | Line 399 | apply_op(RMATRIX *dst, const RMATRIX *src, const RUNAR
399                          return(0);
400                  rmx_free(res);
401          } else if (dst != src)
402 <                memcpy(dst->mtx, src->mtx,
395 <                                sizeof(double)*dst->ncomp*dst->ncols*dst->nrows);
402 >                memcpy(dst->mtx, src->mtx, rmx_array_size(dst));
403          if (ro->nsf == dst->ncomp)
404                  rmx_scale(dst, ro->sca);
405          return(1);
406   }
407  
408 < static int
408 > /* Open the associated input file and load/check header */
409 > int
410   open_input(ROPMAT *rop)
411   {
412          int     outtype;
# Line 411 | Line 419 | open_input(ROPMAT *rop)
419                  rop->infp = popen(rop->inspec+1, "r");
420          else
421                  rop->infp = fopen(rop->inspec, "rb");
422 <
422 >        
423 >        if (!rop->infp) {
424 >                fprintf(stderr, "Cannot open for reading: %s\n",
425 >                                rop->inspec);
426 >                return(0);
427 >        }
428          if (!rmx_load_header(&rop->imx, rop->infp)) {
429                  fprintf(stderr, "Bad header from: %s\n", rop->inspec);
430                  return(0);
# Line 420 | Line 433 | open_input(ROPMAT *rop)
433   }
434  
435   /* Return nominal wavelength associated with input component (return nm) */
436 < static double
436 > double
437   l_wavelength(char *nam)
438   {
439          double  comp = argument(1);
# Line 444 | Line 457 | l_wavelength(char *nam)
457   }
458  
459   /* Return ith input with optional channel selector */
460 < static double
460 > double
461   l_chanin(char *nam)
462   {
463          double  inp = argument(1);
# Line 469 | Line 482 | l_chanin(char *nam)
482          return(mop[mi].rmp->mtx[cur_col*in_ncomp + chan]);
483   }
484  
485 < static int
485 > /* Set up our operations and check consistency */
486 > int
487   initialize(RMATRIX *imp)
488   {
489          int     i;
# Line 482 | Line 496 | initialize(RMATRIX *imp)
496                  restype = mop[i].rmp->dtype;
497                  if (!imp->dtype || (restype = rmx_newtype(restype, imp->dtype)) > 0)
498                          imp->dtype = restype;
499 <                else
499 >                else if (!nowarn)
500                          fprintf(stderr, "%s: warning - data type mismatch\n",
501                                          mop[i].inspec);
502                  if (!i) {
# Line 516 | Line 530 | initialize(RMATRIX *imp)
530          return(1);
531   }
532  
533 < static void
533 > /* Copy input header information to output header, indented */
534 > void
535   output_headinfo(FILE *fp)
536   {
537          int     i;
# Line 539 | Line 554 | output_headinfo(FILE *fp)
554          }
555   }
556  
557 < static int
558 < combine_input(ROPMAT *res, FILE *fout)
557 > /* Spawn the indicated number of children and return 1 in parent */
558 > int
559 > spawned_children(int np)
560   {
561 <        int     set_r, set_c;
562 <        RMATRIX *tmp = NULL;
563 <        int     co_set;
564 <        int     i;
565 <                                        /* allocate input row buffers */
561 >        int     i, rv;
562 >
563 > #if defined(_WIN32) || defined(_WIN64)
564 >        if (np > 1) {
565 >                if (!nowarn)
566 >                        fputs("Warning: only one process under Windows\n", stderr);
567 >                np = 1;
568 >        } else
569 > #endif
570 >        if ((in_nrows > 0) & (np*4 > in_nrows))
571 >                np = in_nrows/4;
572 >                                /* we'll be doing a row at a time */
573          for (i = 0; i < nmats; i++) {
574 <                mop[i].imx.nrows = 1;   /* we'll be doing a row at a time */
574 >                mop[i].imx.nrows = 1;
575                  if (!rmx_prepare(&mop[i].imx))
576                          goto memerror;
577                  if (mop[i].rmp != &mop[i].imx) {
# Line 557 | Line 580 | combine_input(ROPMAT *res, FILE *fout)
580                                  goto memerror;
581                  }
582          }
583 <                                        /* prep output row buffers */
584 <        if (mcat || res->preop.clen > 0) {
585 <                if (!split_input(res))  /* need separate buffer */
563 <                        return(0);
564 <                if (res->preop.clen > 0)
565 <                        res->rmp->ncomp = res->preop.clen / res->imx.ncomp;
566 <                res->rmp->nrows = 1;
567 <                if (!mcat | !mcat_last && !rmx_prepare(res->rmp))
583 >                                /* prep output row buffer(s) */
584 >        if (mop[nmats].preop.clen > 0) {
585 >                if (!split_input(&mop[nmats]))  /* need separate buffer */
586                          goto memerror;
587 +                mop[nmats].rmp->ncomp = mop[nmats].preop.clen /
588 +                                        mop[nmats].imx.ncomp;
589          }
590 <        if (mcat && mcat_last &&
591 <                        !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp)))
590 >        mop[nmats].imx.nrows = 1;
591 >        if (!rmx_prepare(&mop[nmats].imx))
592                  goto memerror;
593 <        res->imx.nrows = 1;
594 <        if (!rmx_prepare(&res->imx))
593 >        if (mop[nmats].rmp != &mop[nmats].imx) {
594 >                mop[nmats].rmp->nrows = 1;
595 >                if (!rmx_prepare(mop[nmats].rmp))
596 >                        goto memerror;
597 >        }
598 >        if (np <= 1) {          /* single process return */
599 > #ifdef getc_unlocked
600 >                for (i = 0; i < nmats; i++)
601 >                        flockfile(mop[i].infp);
602 >                flockfile(stdout);
603 > #endif
604 >                return(0);
605 >        }
606 >        fflush(stdout);         /* flush header & spawn children */
607 >        nchildren = np + 1;     /* extra child to sequence output */
608 >        cproc = (SUBPROC *)malloc(sizeof(SUBPROC)*nchildren);
609 >        if (!cproc)
610                  goto memerror;
611 +        for (i = nchildren; i--; ) cproc[i] = sp_inactive;
612 +        cproc[nchildren-1].flags |= PF_FILT_OUT;
613 +                                /* start each child from parent */
614 +        for (i = 0; i < nchildren; i++)
615 +                if ((rv = open_process(&cproc[i], NULL)) <= 0)
616 +                        break;  /* child breaks here */
617 +        if (rv < 0) {
618 +                perror("fork"); /* WTH? */
619 +                close_processes(cproc, i);
620 +                exit(1);
621 +        }
622 +        if (i != nchildren-1) { /* last child is sole reader */
623 +                int     j = i;
624 +                while (j-- > 0) {
625 +                        close(cproc[j].r);
626 +                        cproc[j].r = -1;
627 +                }
628 +        }
629 +        if (rv > 0)
630 +                return(1);      /* parent return value */
631 +
632 +        inchild = i;            /* else set our child index */
633 +        while (i-- > 0)         /* only parent writes siblings */
634 +                close(cproc[i].w);
635 +
636 +        i = nmats;              /* close matrix streams (carefully) */
637 +        while (i-- > 0) {
638 +                if (mop[i].infp != stdin) {
639 +                        close(fileno(mop[i].infp));     /* avoid lseek() */
640 +                        fclose(mop[i].infp);            /* ! pclose() */
641 +                }
642 +                mop[i].infp = NULL;
643 +        }
644 +        fpurge(stdin);          /* discard previously buffered input */
645 +
646 +        if (inchild == nchildren-1)
647 +                return(-1);     /* output process return value */
648 +
649 +        i = nmats;              /* get matrix rows from parent */
650 +        while (i-- > 0) {
651 +                mop[i].infp = stdin;
652 +                mop[i].imx.dtype = DTrmx_native;
653 +                mop[i].imx.pflags &= ~RMF_SWAPIN;
654 +        }
655 + #ifdef getc_unlocked
656 +        flockfile(stdin);
657 + #endif
658 +        mop[nmats].rmp->dtype = DTrmx_native;
659 +        return(0);              /* worker child return value */
660 + memerror:
661 +        fputs("Out of memory in spawned_children()\n", stderr);
662 +        exit(1);
663 + }
664 +
665 + /* Run parental feeder loop */
666 + int
667 + parent_loop(void)
668 + {
669 +        int     i;
670 +
671 +        rmx_reset(&mop[nmats].imx);             /* not touching output side */
672 +        if (mop[nmats].rmp != &mop[nmats].imx) {
673 +                rmx_free(mop[nmats].rmp);
674 +                mop[nmats].rmp = &mop[nmats].imx;
675 +        }
676 + #ifdef getc_unlocked
677 +        for (i = 0; i < nmats; i++)             /* we handle matrix inputs */
678 +                flockfile(mop[i].infp);
679 + #endif
680 +                                                /* load & send rows to kids */
681 +        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
682 +            int         wfd = cproc[cur_row % (nchildren-1)].w;
683 +            for (i = 0; i < nmats; i++)
684 +                if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
685 +                        if (cur_row > in_nrows) /* unknown #input rows? */
686 +                                break;
687 +                        fprintf(stderr, "%s: load error at row %d\n",
688 +                                        mop[i].inspec, cur_row);
689 +                        return(0);
690 +                }
691 +            if (i < nmats)
692 +                break;
693 +            for (i = 0; i < nmats; i++)
694 +                if (writebuf(wfd, mop[i].imx.mtx, rmx_array_size(&mop[i].imx))
695 +                                        != rmx_array_size(&mop[i].imx)) {
696 +                        fprintf(stderr, "%s: write error at row %d\n",
697 +                                        mop[i].inspec, cur_row);
698 +                        return(0);
699 +                }
700 +        }
701 +        i = close_processes(cproc, nchildren);  /* collect family */
702 +        free(cproc); cproc = NULL; nchildren = 0;
703 +        if (i < 0) {
704 +                if (!nowarn)
705 +                        fputs("Warning: lost child process\n", stderr);
706 +                return(1);
707 +        }
708 +        if (i > 0) {
709 +                fprintf(stderr, "Child exited with status %d\n", i);
710 +                return(0);
711 +        }
712 +        return(1);                              /* return success! */
713 + }
714 +
715 + /* Main operation loop, may be run in each child */
716 + int
717 + combine_input(void)
718 + {
719 +        const int       row0 = (inchild >= 0)*inchild;
720 +        const int       rstep = nchildren ? nchildren-1 : 1;
721 +        ROPMAT          *res = &mop[nmats];
722 +        int             set_r, set_c;
723 +        RMATRIX         *tmp = NULL;
724 +        int             co_set;
725 +        int             i;
726 +
727 +        if (mcat_last && !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp))) {
728 +                fputs("Out of buffer space in combine_input()\n", stderr);
729 +                return(0);
730 +        }
731                                          /* figure out what the user set */
732          co_set = fundefined("co");
733          if (!co_set)
# Line 588 | Line 743 | combine_input(ROPMAT *res, FILE *fout)
743          } else                          /* save a little time */
744                  set_r = set_c = 0;
745                                          /* read/process row-by-row */
746 <        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
746 >        for (cur_row = row0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row += rstep) {
747              RMATRIX     *mres = NULL;
748 <            for (i = 0; i < nmats; i++) {
748 >            for (i = 0; i < nmats; i++)
749                  if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
750 <                        if (in_nrows <= 0)      /* normal end? */
751 <                                goto loop_exit;
752 <                        fprintf(stderr, "%s: read error at row %d\n",
750 >                        if (cur_row > in_nrows) /* unknown #input rows? */
751 >                                break;
752 >                        fprintf(stderr, "%s: load error at row %d\n",
753                                          mop[i].inspec, cur_row);
754                          return(0);
755                  }
756 +            if (i < nmats)
757 +                break;
758 +            for (i = 0; i < nmats; i++)
759                  if (!apply_op(mop[i].rmp, &mop[i].imx, &mop[i].preop))
760                          return(0);
603            }
761              if (set_r) varset("r", '=', cur_row);
762              for (cur_col = 0; cur_col < in_ncols; cur_col++) {
763                  if (set_c) varset("c", '=', cur_col);
# Line 638 | Line 795 | combine_input(ROPMAT *res, FILE *fout)
795              }
796              rmx_free(mres); mres = NULL;
797              if (!rmx_write_data(res->rmp->mtx, res->rmp->ncomp,
798 <                                res->rmp->ncols, res->rmp->dtype, fout))
798 >                                res->rmp->ncols, res->rmp->dtype, stdout) ||
799 >                                 (inchild >= 0 && fflush(stdout) == EOF)) {
800 >                fprintf(stderr, "Conversion/write error at row %d\n",
801 >                                cur_row);
802                  return(0);
803 +            }
804          }
805 < loop_exit:
806 < #if 0           /* we're about to exit, so who cares? */
807 <        rmx_free(tmp);                  /* clean up */
808 <        rmx_reset(res->rmp);
809 <        rmx_reset(&res->imx);
810 <        for (i = 0; i < nmats; i++) {
811 <                rmx_reset(mop[i].rmp);
805 >        return(inchild >= 0 || fflush(stdout) != EOF);
806 > multerror:
807 >        fputs("Unexpected matrix multiply error\n", stderr);
808 >        return(0);
809 > }
810 >
811 > /* Run output process loop when #processes > 1 */
812 > int
813 > output_loop(void)
814 > {
815 >        const size_t    row_size = rmx_array_size(mop[nmats].rmp);
816 >        int             cur_child = 0;
817 >        int             i = nmats;
818 >
819 >        while (i-- > 0) {                               /* free input buffers */
820                  rmx_reset(&mop[i].imx);
821 <                if (mop[i].inspec[0] == '!')
822 <                        pclose(mop[i].infp);
823 <                else if (mop[i].inspec != stdin_name)
824 <                        fclose(mop[i].infp);
656 <                mop[i].infp = NULL;
821 >                if (mop[i].rmp != &mop[i].imx) {
822 >                        rmx_free(mop[i].rmp);
823 >                        mop[i].rmp = &mop[i].imx;
824 >                }
825          }
826 +        if (mop[nmats].rmp != &mop[nmats].imx)          /* output is split? */
827 +                rmx_reset(&mop[nmats].imx);
828 + #ifdef getc_unlocked
829 +        flockfile(stdout);                              /* we own this, now */
830   #endif
831 <        return(fflush(fout) != EOF);
832 < memerror:
833 <        fputs("Out of buffer space in combine_input()\n", stderr);
834 <        return(0);
835 < multerror:
836 <        fputs("Unexpected matrix multiply error in combine_input()\n", stderr);
837 <        return(0);
831 >        for ( ; ; ) {                                   /* loop until no more */
832 >                ssize_t         rv;
833 >                rv = readbuf(cproc[cur_child].r, mop[nmats].rmp->mtx, row_size);
834 >                if (!rv)                                /* out of rows? */
835 >                        break;
836 >                if (rv != row_size) {
837 >                        fputs("Read error\n", stderr);
838 >                        return(0);
839 >                }                                       /* do final conversion */
840 >                if (!rmx_write_data(mop[nmats].rmp->mtx, mop[nmats].rmp->ncomp,
841 >                                mop[nmats].rmp->ncols, mop[nmats].rmp->dtype, stdout)) {
842 >                        fputs("Conversion/write error\n", stderr);
843 >                        return(0);
844 >                }
845 >                cur_child++;
846 >                cur_child *= (cur_child < inchild);     /* loop over workers */
847 >        }
848 >        return(fflush(stdout) != EOF);
849   }
850  
851 < static int
851 > /* Check/convert floating-point arguments following this */
852 > int
853   get_factors(double da[], int n, char *av[])
854   {
855          int     ac;
# Line 675 | Line 859 | get_factors(double da[], int n, char *av[])
859          return(ac);
860   }
861  
862 < static void
862 > /* Resize/reallocate the input array as requested */
863 > void
864   resize_inparr(int n2alloc)
865   {
866          int     i;
867  
868 <        for (i = nmats; i > n2alloc; i--) {
868 >        if (n2alloc == nall)
869 >                return;
870 >        for (i = nall; i-- > n2alloc; ) {
871                  rmx_reset(&mop[i].imx);
872                  if (mop[i].rmp != &mop[i].imx)
873                          rmx_free(mop[i].rmp);
# Line 690 | Line 877 | resize_inparr(int n2alloc)
877                  fputs("Out of memory in resize_inparr()\n", stderr);
878                  exit(1);
879          }
880 <        if (n2alloc > nmats)
881 <                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
880 >        if (n2alloc > nall)
881 >                memset(mop+nall, 0, (n2alloc-nall)*sizeof(ROPMAT));
882          nall = n2alloc;
883   }
884  
# Line 704 | Line 891 | main(int argc, char *argv[])
891          const char      *defCsym = NULL;
892          int             echoheader = 1;
893          int             stdin_used = 0;
894 +        int             nproc = 1;
895          const char      *mcat_spec = NULL;
896 +        int             transpose_mcat = 0;
897          int             n2comp = 0;
898          uby8            comp_ndx[128];
899          int             i;
# Line 731 | Line 920 | main(int argc, char *argv[])
920                          case 'h':
921                                  echoheader = !echoheader;
922                                  break;
923 +                        case 'n':
924 +                                nproc = atoi(argv[++i]);
925 +                                if (nproc <= 0)
926 +                                        goto userr;
927 +                                break;
928                          case 'e':
929                                  if (!n) goto userr;
930                                  comp_ndx[n2comp++] = i++;
# Line 769 | Line 963 | main(int argc, char *argv[])
963                                  }
964                                  break;
965                          case 'C':
966 +                                mcat_last = 0;
967                                  if (!n || isflt(argv[i+1]))
968                                          goto userr;
969                                  defCsym = mop[nmats].preop.csym = argv[++i];
970                                  mop[nmats].preop.clen = 0;
776                                mcat_last = 0;
971                                  break;
972                          case 'c':
973 +                                mcat_last = 0;
974                                  if (n && !isflt(argv[i+1])) {
975                                          mop[nmats].preop.csym = argv[++i];
976                                          mop[nmats].preop.clen = 0;
# Line 791 | Line 986 | main(int argc, char *argv[])
986                                          goto userr;
987                                  }
988                                  mop[nmats].preop.csym = NULL;
794                                mcat_last = 0;
989                                  break;
990                          case 'm':
991                                  if (!n) goto userr;
992 +                                mcat_last = 1;
993 +                                transpose_mcat = (argv[i][2] == 't');
994                                  if (argv[++i][0] == '-' && !argv[i][1]) {
995                                          if (stdin_used++) goto stdin_error;
996                                          mcat_spec = stdin_name;
997                                  } else
998                                          mcat_spec = argv[i];
803                                mcat_last = 1;
999                                  break;
1000                          default:
1001                                  fprintf(stderr, "%s: unknown option '%s'\n",
# Line 814 | Line 1009 | main(int argc, char *argv[])
1009          }
1010          resize_inparr(nmats+1);         /* extra matrix at end for result */
1011          mop[nmats].inspec = "trailing_ops";
1012 <                                        /* load final concatenation matrix */
1013 <        if (mcat_spec && !(mcat = rmx_load(mcat_spec, RMPnone))) {
1014 <                fprintf(stderr, "%s: error loading concatenation matrix: %s\n",
1015 <                                argv[0], mcat_spec);
1016 <                return(1);
1012 >
1013 >        if (mcat_spec) {                /* load final concatenation matrix? */
1014 >                mcat = rmx_load(mcat_spec);
1015 >                if (!mcat) {
1016 >                        fprintf(stderr, "%s: error loading concatenation matrix: %s\n",
1017 >                                        argv[0], mcat_spec);
1018 >                        return(1);
1019 >                }
1020 >                if (transpose_mcat && !rmx_transpose(mcat)) {
1021 >                        fprintf(stderr, "%s: error transposing concatenation matrix: %s\n",
1022 >                                        argv[0], mcat_spec);
1023 >                        return(1);
1024 >                }
1025          }
1026                                          /* get/check inputs, set constants */
1027          if (!initialize(&mop[nmats].imx))
# Line 858 | Line 1061 | main(int argc, char *argv[])
1061                          return(1);
1062                  mop[nmats].rmp->ncols = mcat->ncols;
1063          }
1064 + #if DTrmx_native==DTfloat
1065 +        if (outfmt == DTdouble)
1066 +                fprintf(stderr, "%s: warning - writing float result as double\n", argv[0]);
1067 + #endif
1068          newheader("RADIANCE", stdout);  /* write output header */
1069          if (echoheader)
1070                  output_headinfo(stdout);
# Line 868 | Line 1075 | main(int argc, char *argv[])
1075                  fprintf(stderr, "%s: unsupported output format\n", argv[0]);
1076                  return(1);
1077          }
1078 <                                        /* process & write rows */
1079 <        return(combine_input(&mop[nmats], stdout) ? 0 : 1);
1078 >        doptimize(1);                   /* optimize definitions */
1079 >        i = spawned_children(nproc);    /* create multiple processes if requested */
1080 >        if (i > 0)                      /* running in parent process? */
1081 >                return(parent_loop() ? 0 : 1);
1082 >        if (i < 0)                      /* running in output process? */
1083 >                return(output_loop() ? 0 : 1);
1084 >                                        /* else we are a worker process */
1085 >        return(combine_input() ? 0 : 1);
1086   stdin_error:
1087          fprintf(stderr, "%s: %s used for more than one input\n",
1088                          argv[0], stdin_name);
1089          return(1);
1090   userr:
1091          fprintf(stderr,
1092 <        "Usage: %s [-h][-f{adfc}][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1092 >        "Usage: %s [-h][-f{adfc}][-n nproc][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1093                          argv[0]);
1094          return(1);
1095   }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)