/* SIMPMAIN.C */
/*-
control of input, output & simplex fitting 	= main()
  
J.A. Rupley, Tucson, Arizona
rupley!local@megaron.arizona.edu
*/

#define SIMPMAIN

#include "simpdefs.h"

/*-
MAIN
	MAIN PROGRAM FOR CONTROL OF:
	SETUP FOR INPUT OF DATA FROM FILE GIVEN AS COMMAND LINE OPTION
	SETUP FOR WRITE OF OUTPUT TO FILE GIVEN AS COMMAND LINE OPTION
	SIMPLEX FITTING
	QUADRATIC FIT FOR EXTRACTION OF STANDARD DEVIATIONS
	OUTPUT TO CONSOLE AND TO FILE, ACCORDING TO COMMAND LINE OPTIONS
*/

/*-
one must initialize the following, by a call to <read_data()>:
double exit_test, quad_test
int prt_cycle, maxquad_skip
int iter, maxiter, nparm, nvert, nfree, ndatval, ndata
char title[80]
struct pstruct p[nvert] = the starting simplex
struct dat data[ndata]	= the data array, used in <func()> and <fdatprint()>
FILE *fp_disk = optional output file
  
on return from <read_data()>:
zero nquad_skip 
set quad_cycle = quad_test for use if quad_test >1
  
in loop calling <simpfit()> and <simpdev()>:
reset maxiter to iter+prt_cycle
test and reset as appropriate nquad_skip and quad_test
as appropriate execute options altering flow or test values
  
on return from <simpfit()>:
the structure <p[nvert]> has the current simplex and <pcent> the centroid,
the variables mean_func, rms_func, test, and rms_data contain the mnemonically 
indicated information.
  
on return from <simpdev()>:
the array <qmat[nfree][nfree]> contains the variance-covariance matrix, 
the elements of structures <q> and <pmin> and variables yzero, ymin, ypmin,
and mse contain the mnemonically indicated information.
*/

/* mnemonics for output to terminal or file */
#define ALL	3	/* maximum output - track each iteration */
#define CYCLE	2	/* output summary values on maxiter/quad_test cycle */
#define LAST	1	/* output summary values on last (exit) cycle only */
#define NONE	0	/* all output to /dev/null */

main(argc, argv)
	int             argc;
	char          **argv;
{
	int             c;
	int             nquad_skip, quad_cycle;
	int             diskmode, screenmode;

	FILE           *fp_input;
	FILE           *fp_disk;
	FILE           *fp_screen;
	FILE           *fp_null;

	extern void     use_mess();
	extern          read_data();
	extern          simpfit();
	extern          simpdev();
	extern void     ffitprint();
	extern void     fdatprint();
	extern void     fquadprint();
	extern void     enditall();

	extern void     exit();
	extern double   atof();
	extern FILE    *fopen();

	extern char    *optarg;
	extern int      optind, opterr;
	extern int      getopt();

	fp_input = stdin;
	fp_disk = NULL;
	fp_screen = stdout;
	diskmode = NONE;
	screenmode = ALL;

	while ((c = getopt(argc, argv, "zi:o:d:s:")) != EOF) {
		switch (c) {
		case 'i':
			if ((fp_input = fopen(optarg, "r")) == NULL) {
				printf("sorry, cannot open input file %s\n",
				       optarg);
				use_mess();
				exit(1);
			}
			break;
		case 'o':
			if ((fp_disk = fopen(optarg, "w")) == NULL) {
				printf("sorry, cannot open output file %s\n",
				       optarg);
				use_mess();
				exit(1);
			}
			if (diskmode == NONE)
				diskmode = CYCLE;
			break;
		case 'd':
			switch (*optarg) {
			case 'a':
			case 'c':
				diskmode = CYCLE;
				break;
			case 'l':
				diskmode = LAST;
				break;
			case 'n':
				diskmode = NONE;
				break;
			default:
				printf("bad option\n");
				use_mess();
				exit(1);
			}
			break;
		case 's':
			switch (*optarg) {
			case 'a':
				screenmode = ALL;
				break;
			case 'c':
				screenmode = CYCLE;
				break;
			case 'l':
				screenmode = LAST;
				break;
			case 'n':
				screenmode = NONE;
				break;
			default:
				printf("bad option\n");
				use_mess();
				exit(1);
			}
			break;
		case '?':
		case 'z':
		default:
			use_mess();
			exit(1);
		}
	}

	if ((optind < argc) && (fp_input == stdin)) {
		if ((fp_input = fopen(argv[optind], "r")) == NULL) {
			printf("sorry, cannot open input file %s\n",
			       argv[optind]);
			use_mess();
			exit(1);
		}
		optind++;
	}
	if ((optind < argc) && (fp_disk == NULL)) {
		if ((fp_disk = fopen(argv[optind], "w")) == NULL) {
			printf("sorry, cannot open output file %s\n",
			       argv[optind]);
			use_mess();
			exit(1);
		}
		optind++;
		if (diskmode == NONE)
			diskmode = CYCLE;
	}
	if (optind < argc) {
		use_mess();
		exit(1);
	}
	/* /dev/null may be needed as sink */
	if ((fp_null = fopen("/dev/null", "w")) == NULL) {
		fprintf(stderr, "\nCannot open /dev/null for output\n");
		exit(1);
	}
	if (screenmode == NONE) {
		screenmode = NONE;
		fp_screen = fp_null;
	}
	if ((diskmode == NONE) || (fp_disk == NULL)) {
		diskmode = NONE;
		fp_disk = fp_null;
	}
	if (screenmode == ALL)
		read_data(fp_screen, fp_input);
	else
		read_data(fp_null, fp_input);
	fclose(fp_input);

	quad_cycle = quad_test;
	nquad_skip = 0;

	/* If nvert == 1, then print simplex and calculated values, */
	/* and exit */
	if (nvert == 1) {
		pcopy(&pcent, &p[0]);
		if (fp_screen != NULL) {
			ffitprint(fp_screen);
			fdatprint(fp_screen);
		}
		if (fp_disk != NULL) {
			ffitprint(fp_disk);
			fdatprint(fp_disk);
			fclose(fp_disk);
		}
		enditall();
	}

	/* BEGIN LOOP */
	/* simplex minimization alternates with quadratic fit */
	while (TRUE) {
		maxiter = iter + prt_cycle;

		/* carry out simplex minimization */
		if (screenmode == ALL)
			simpfit(fp_screen);
		else
			simpfit(fp_null);

		/* print summary of simplex fitting */
		/* after page eject */
		if ((screenmode >= CYCLE) || (iter != maxiter))
			if (fp_screen != NULL)
				ffitprint(fp_screen);
		if ((diskmode >= CYCLE) || (iter != maxiter))
			if (fp_disk != NULL)
				ffitprint(fp_disk);

		/* if test vs quad_test false, */
		/* loop back to simpfit ; */
		if (iter == maxiter) {
			if (quad_test >= 1) {
				if (iter < quad_test)
					continue;
			} else if (test > quad_test)
				continue;
		}

		/* carry out quadratic fit */
		if (screenmode == ALL)
			simpdev(fp_screen);
		else
			simpdev(fp_null);

		/* print summary of results of quad fit */
		/* after page eject */
		if ((screenmode >= CYCLE) || (iter != maxiter))
			if (fp_screen != NULL)
				fquadprint(fp_screen);
		if ((diskmode >= CYCLE) || (iter != maxiter))
			if (fp_disk != NULL)
				fquadprint(fp_disk);

		/* print data array */
		/* after page eject */
		if ((screenmode >= CYCLE) || (iter != maxiter))
			if (fp_screen != NULL)
				fdatprint(fp_screen);
		if ((diskmode >= CYCLE) || (iter != maxiter))
			if (fp_disk != NULL)
				fdatprint(fp_disk);

		/* exit if done = return on exit test true */
		if (iter != maxiter) {
			break;
		}
		/* increment nquad_skip if ypmin >= yzero */
		if (ypmin < yzero)
			nquad_skip = 0;
		else if (nquad_skip < maxquad_skip)
			nquad_skip++;

		/* alter quad_test for next set of */
		/* fitting cycles according to */
		/* nquad_skip = the number of */
		/* quadratic fit failures and quad_test */
		/* greater or less than unity */
		if (quad_test >= 1) {
			if (iter >= quad_test)
				quad_test = iter +
					(nquad_skip + 1) * quad_cycle;
		} else if (test <= quad_test)
			quad_test = quad_test / 10;

	}			/* END OF LOOP */

	if (fp_disk != NULL)
		fclose(fp_disk);
	enditall();
				/* NOT REACHED*/
	return (0);
}				/* END OF MAIN */
