/*
 *
 * screen_time_filter_gti.c
 * make time corrections to hrc times (i.e., slip time one event) (default)
 * filter on  delta-time < test_value (default no filter)
 * filter event times against the good time intervals
   from a Level 1 "flt1" file
 * screen events using "standard" HRC processes
 * save good events in a FITS extenstion (events extension), 
 * save the good time intervals (gti extension)
 * the output is a FITS file that has the Level 1 structure but is
   in reality a Level 2 file in that it contains only selected events
 *
 */
/*** include files ***/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <funtools.h>

#include "nhrc.flt.h"

#define MAXROW 8192

extern char *optarg;
extern int optind;

int getopt();
int atoi();
long atol();
double fabs();

typedef struct Evstruct{
  double time;
  int amp_sf;
  int av1, av2, av3, au1, au2, au3;
  int pha, sumamps;
  short screen_status;
} *Event, EventRec;

typedef struct Gtistruct{
  double start, stop;
} *GTI, GTIRec;

int debug = 0;
/*================================================================*/
int main (argc, argv)
int argc;
char *argv[];
{
  int c, i, got, pgot;

  char infile[64], outfile[64], gtifile[64], tmpfile[64];
  char *prev_raw, *cur_raw;
  char *null=NULL;
  int det_id;
  int gstat;
  int total_cnt, out_cnt, delta_cnt;
  int gti_flag;
  int time_flag, filt_stat;
  double delta_time;
  double hyper_fit();
  Fun ifun, gfun, ofun;


  Event ebuf=NULL, pebuf=NULL, evt, evt_next, evt_prev, evt_2_prev, evt_2_next;
  GTI gbuf=NULL, gti;

  struct Process_parm *procparm;
  struct SFparm *sfparm;

  procparm = CALLOC(1, struct Process_parm);
  sfparm = CALLOC(1, struct SFparm);

  procparm->finh[0][0] = 1.058;
  procparm->finh[0][1] = 1.100;
  procparm->finhd[0][0] = 0.035;
  procparm->finhd[0][1] = 0.035;
  procparm->fina[0][0] = 0.3110;
  procparm->fina[0][1] = 0.3050;
  procparm->finb[0][0] = 0.3030;
  procparm->finb[0][1] = 0.2730;
  procparm->finh[1][0] = 1.018;
  procparm->finh[1][1] = 1.071;
  procparm->finhd[1][0] = 0.035;
  procparm->finhd[1][1] = 0.035;
  procparm->fina[1][0] = 0.2706;
  procparm->fina[1][1] = 0.2706;
  procparm->finb[1][0] = 0.2620;
  procparm->finb[1][1] = 0.2480;


  strcpy(infile,"NULL");
  strcpy(outfile,"NULL");
  strcpy(gtifile,"NULL");
  sfparm->phal = 20;
  sfparm->phau = 255;
  sfparm->amp_test = 2;
  sfparm->amp_min = 20;
  sfparm->amp_max = 3550;
  sfparm->flat_test = 0.75;
  sfparm->amp_gain = 74.0;
  sfparm->pha_tol1 = 20;
  sfparm->delta = 100.0;
  sfparm->gti_cnt = 0;
  sfparm->finposu_cnt = 0;
  sfparm->finposv_cnt = 0;
  total_cnt = 0;
  out_cnt = 0;
  delta_cnt = 0;
  sfparm->finposu_only = 0;
  sfparm->finposv_only = 0;
  sfparm->finposu_and_v = 0;
  sfparm->finpos_total = 0;
  sfparm->pha_cnt = 0;
  sfparm->amp_cnt = 0;
  sfparm->ampsf_cnt = 0;
  sfparm->fixampsf_cnt = 0;
  sfparm->flat_cnt = 0;
  det_id = 0;
  delta_time = 0.0;
  time_flag = FALSE;
  debug = 0;

  while ((c = getopt(argc, argv,
     "I:i:O:o:G:g:P:p:d:D:s:S:t:T:f:F:H:a:b:h?")) != EOF) {
    switch (c) {
    case 'I':
    case 'i':
      strcpy(infile, optarg);
      break;
    case 'O':
    case 'o':
      strcpy(outfile, optarg);
      break;
    case 'G':
    case 'g':
      strcpy(gtifile, optarg);
      break;
    case 'p':
      sfparm->phal = atoi(optarg);
      break;
    case 'P':
      sfparm->phau = atoi(optarg);
      break;
    case 'd':
      procparm->finhd[0][0] = atof(optarg);
      procparm->finhd[0][1] = procparm->finhd[0][0];
      procparm->finhd[1][0] = procparm->finhd[0][0];
      procparm->finhd[1][1] = procparm->finhd[0][0];
      break;
    case 'H':
      det_id = atoi(optarg);
      sfparm->amp_gain = 35.0;
      sfparm->pha_tol1 = 100.0;
      break;
    case 's':
      sfparm->amp_min = atoi(optarg);
      break;
    case 'S':
      sfparm->amp_max = atoi(optarg);
      break;
    case 't':
      sfparm->amp_test = atoi(optarg);
      break;
    case 'T':
      sfparm->pha_tol1 = atoi(optarg);
      break;
    case 'f':
      sfparm->flat_test = atof(optarg);
      break;
    case 'F':
      if( atoi(optarg) == 1 ) time_flag = TRUE;
      break;
    case 'D':
      sfparm->delta = atof(optarg);
      break;
    case 'a':
      sfparm->amp_gain = atof(optarg);
      break;
    case 'b':
      debug = atoi(optarg);
      break;
    case 'h':
    case '?':
      fprintf(stderr, "\nuse:screen_evt1 -[iogpPD]");
      fprintf(stderr, "\n\ti[NULL}: Input File Name");
      fprintf(stderr, "\n\to[NULL]: Output File Name");
      fprintf(stderr, "\n\tg[NULL]: GTI File Name, SKIP=> no gti");
      fprintf(stderr, "\n\tp[20]: Low PHA Limit");
      fprintf(stderr, "\n\tP[255]: High PHA Limit");
      fprintf(stderr, "\n\tH[0]: HRC Detector ID 0=> HRC-I, 1=> HRC-S");
      fprintf(stderr, "\n\td[0.035]: Tolerance in Hyper_fit");
      fprintf(stderr, "\n\ts[20]: Lower Tap Amplifier Limit");
      fprintf(stderr, "\n\tS[3550]: Upper Tap Amplifier Limit");
      fprintf(stderr, "\n\tt[2]: Minimum Number of Taps");
      fprintf(stderr, "\n\tT[5]: PHA tolerance for Scale Factor");
      fprintf(stderr, "\n\tf[0.75]: Flatness test value");
      fprintf(stderr, "\n\tF[0]: Fix time flag 1=> FIX ,0=>No Action");
      fprintf(stderr, "\n\tD[100.0]: Delta time test");
      fprintf(stderr, "\n\ta[74.0]: Amplifier gain");
      fprintf(stderr, "\n\tb[0]: Debug level");
      fprintf(stderr, "\n");
      exit(0);
      break;
    }
  }

  procparm->blow[0][0] = procparm->finh[0][0] - procparm->finhd[0][0] -
    procparm->fina[0][0];
  procparm->blow[0][1] = procparm->finh[0][1] - procparm->finhd[0][1] -
    procparm->fina[0][1];
  procparm->bhigh[0][0] = procparm->finh[0][0] + procparm->finhd[0][0] -
    procparm->fina[0][0];
  procparm->bhigh[0][1] = procparm->finh[0][1] + procparm->finhd[0][1] -
    procparm->fina[0][1];
  procparm->blow[1][0] = procparm->finh[1][0] - procparm->finhd[1][0] -
    procparm->fina[1][0];
  procparm->blow[1][1] = procparm->finh[1][1] - procparm->finhd[1][1] -
    procparm->fina[1][1];
  procparm->bhigh[1][0] = procparm->finh[1][0] + procparm->finhd[1][0] -
    procparm->fina[1][0];
  procparm->bhigh[1][1] = procparm->finh[1][1] + procparm->finhd[1][1] -
    procparm->fina[1][1];
  
  sfparm->ufinh = procparm->finh[det_id][0];
  sfparm->ufinhd = procparm->finhd[det_id][0];
  sfparm->ufina = procparm->fina[det_id][0];
  sfparm->ufinb=procparm->finb[det_id][0];
  sfparm->ublow = procparm->blow[det_id][0];
  sfparm->ubhigh=procparm->bhigh[det_id][0];
  sfparm->vfinh = procparm->finh[det_id][1];
  sfparm->vfinhd = procparm->finhd[det_id][1];
  sfparm->vfina = procparm->fina[det_id][1];
  sfparm->vfinb=procparm->finb[det_id][1];
  sfparm->vblow = procparm->blow[det_id][1];
  sfparm->vbhigh=procparm->bhigh[det_id][1];
  sfparm->pha_tol2 = sfparm->pha_tol1;
  sfparm->pha_tol3 = sfparm->pha_tol1;
  gti_flag = TRUE;

  /* exit on gio errors */
  setgerror(2);

  /* make sure we have minimal arguments */
  if( strcmp(infile, "NULL") == 0 ) 
    gerror(stderr, "usage: need an input file name!\n");
  if( strcmp(outfile, "NULL") == 0 ) 
    gerror(stderr, "usage: need an output file name!\n");
  if( strcmp(gtifile, "NULL") == 0 )
    gerror(stderr, "usage: need a gtifile file name!\n");
  if( (strcmp(gtifile, "SKIP") == 0) || (strcmp(gtifile, "skip") == 0) )
    gti_flag = FALSE;

  /* open the new output FITS file */
  if( !(ofun = FunOpen(outfile, "w", NULL)) )
    gerror(stderr, "could not FunOpen output file: %s\n", outfile);

  /* open the primary extension of the event input file
     and output it to the output file */
  strcpy(tmpfile, infile);
  strcat(tmpfile,"[0]");
  if( !(ifun = FunOpen(tmpfile, "r", NULL)) )
    gerror(stderr, "could not FunOpen primary extension of input file: %s\n",
	   infile);
  /* make this extension the reference handle for the output file */
  FunInfoPut(ofun, FUN_IFUN, &ifun, 0);
  /* By flushing, we force a write of the primary extension to the output */
  FunFlush(ofun, "copy=reference");
  /* Close the input event file (for the moment) */
  FunClose(ifun);

  if( gti_flag == TRUE ) {
    /* Open the GTI file to the gti extension */
    strcpy(tmpfile, gtifile);
    strcat(tmpfile, "[gti]");
    if( !(gfun = FunOpen(tmpfile, "r", NULL)) ) {
      fprintf(stderr, "Warning: no gti extension of filter file: %s\n",
	      gtifile);
      fprintf(stderr,"Warning: no gti extension in output file\n");
      /* fake gti record but set gti flag to FALSE*/
      gti_flag = FALSE;
      sfparm->gti_got = 1;
      sfparm->ngti = 0;
      gbuf = CALLOC(1, struct Gtistruct);
      gbuf->start = 0.0;
      gbuf->stop = LARGE;
    } else {
      /* select the columns that are needed from gti rows */
      FunColumnSelect(gfun, sizeof(GTIRec), NULL,
		      "start", "D", "r", FUN_OFFSET(GTI, start),
		      "stop", "D", "r", FUN_OFFSET(GTI, stop),
		      NULL);
      /* now read and store the entire set of gti rows */
      /* Now let Funtools do all the hard work and read in all of the
	 gti records (rows) in one call */
      gbuf = FunEventsGet(gfun, NULL, MAXROW, NULL, &got);
      /* check to make sure that got is less than MAXROW */
      if (got >= MAXROW)
	gerror(stderr, "too many gti records max=MAXROW got=%d\n", got);
      sfparm->gti_got = got;
      sfparm->ngti = 0;
    }
  } else {
    sfparm->gti_got = 1;
    sfparm->ngti = 0;
    gbuf = CALLOC(1, struct Gtistruct);
    gbuf->start = 0.0;
    gbuf->stop = LARGE;
  }

  /* Open the events extension of the first input file */
  strcpy(tmpfile, infile);
  strcat(tmpfile, "[events]");
  if( !(ifun = FunOpen(tmpfile, "r", NULL)) )
    gerror(stderr, "could not FunOpen the input event extension: %s\n",
	   infile);
  /* Set up the columns used in this program */
  FunColumnSelect(ifun, sizeof(EventRec), "merge=update",
		  "time", "D", "rw", FUN_OFFSET(Event,time),
		  "amp_sf", "J", "rw", FUN_OFFSET(Event,amp_sf),
		  "av1", "J", "r", FUN_OFFSET(Event,av1),
		  "av2", "J", "r", FUN_OFFSET(Event,av2),
		  "av3", "J", "r", FUN_OFFSET(Event,av3),
		  "au1", "J", "r", FUN_OFFSET(Event,au1),
		  "au2", "J", "r", FUN_OFFSET(Event,au2),
		  "au3", "J", "r", FUN_OFFSET(Event,au3),
		  "pha", "J", "r", FUN_OFFSET(Event,pha),
		  "sumamps", "J", "rw", FUN_OFFSET(Event,sumamps),
		  "screen_status", "I", "rw", FUN_OFFSET(Event,screen_status),
		  NULL);
  /* Make the events extension the reference handle for the output file */
  FunInfoPut(ofun, FUN_IFUN, &ifun, 0);
  /* get events -- let routine allocate the event array */
  while( (ebuf = (Event)FunEventsGet(ifun, NULL, MAXROW, NULL, &got)) ){
    /* process the last two events from the previous batch,
       if there were some */
    if( pebuf != NULL ) {
      /* fix the second to last event of previous batch */
      /* pointer to the second last event of the previous batch,
       and last event of previous batch */
      evt_2_prev = pebuf + (pgot - 2);
      evt_prev = pebuf + (pgot - 1);
      /* pointer to the first event of this batch */
      evt = ebuf;
      /* if fixing time, do it */
      filt_stat = GOOD;
      if( time_flag == TRUE ) {
	evt_2_prev->time = evt_prev->time;
	delta_time = evt->time - evt_prev->time;
	if( delta_time > sfparm->delta ) {
	  filt_stat = BAD; 
	  delta_cnt++;
	}
      }
     
      /* screen and filter this old event */
      if( filt_stat == GOOD )
	filt_stat = screen_filter(sfparm, evt_2_prev, gbuf);
      if (filt_stat == GOOD) {
	out_cnt++;
	/* save pointer to the current raw data */
	FunInfoGet(ifun, FUN_RAWBUF, &cur_raw, 0);
	/* put back the previous raw pointer to grab all of the event data */
	FunInfoPut(ifun, FUN_RAWBUF, &prev_raw, 0);
	/* output the event */
	FunTableRowPut(ofun, evt_prev, 1, (pgot - 1), NULL);
	/* restore the pointer to the current raw data */
	FunInfoPut(ifun, FUN_RAWBUF, &cur_raw, 0);
      }
      /* fix the time of the last event of the previous batch */
      filt_stat = GOOD;
      if( time_flag == TRUE ) {
	evt_prev->time = evt->time;
	delta_time = (evt + 1)->time - evt->time;
	if( delta_time > sfparm->delta ) {
	  filt_stat = BAD;
	  delta_cnt++;
	}
      }
      /* now screen and filter this old event */
      if( filt_stat == GOOD )
	filt_stat = screen_filter(sfparm, evt_prev, gbuf);
      if (filt_stat == GOOD) {
	out_cnt++;
	/* save pointer to the current raw data */
	FunInfoGet(ifun, FUN_RAWBUF, &cur_raw, 0);
	/* put back the previous raw pointer to grab all of the event data */
	FunInfoPut(ifun, FUN_RAWBUF, &prev_raw, 0);
	/* output the event */
	FunTableRowPut(ofun, evt_prev, 1, (pgot - 1), NULL);
	/* restore the pointer to the current raw data */
	FunInfoPut(ifun, FUN_RAWBUF, &cur_raw, 0);
      }
      /* free up the previous data buffers, raw and user */
      if(prev_raw) free(prev_raw);
      if(pebuf) free(pebuf);
    }
    /* process all events from current batch, except the last two*/
    for(i=0; i<(got-2); i++){
      /* point to the i'th event, and increment total counts */
      evt = ebuf + i;
      evt_next = ebuf + (i + 1);
      evt_2_next = ebuf + (i + 2);
      total_cnt++;
      filt_stat = GOOD;
      if( time_flag == TRUE) {
	/* fix the event time by slipping one event */
	evt->time = evt_next->time;
	delta_time = evt_2_next->time - evt_next->time;
	if( delta_time > sfparm->delta ) {
	  filt_stat = BAD;
	  delta_cnt++;
	}
      }
      if( filt_stat == GOOD )
	filt_stat = screen_filter(sfparm, evt, gbuf);
      if( filt_stat == GOOD) {
	out_cnt++;
	FunTableRowPut(ofun, evt, 1, i, NULL);
      }
    }
    /* save the raw and user data */
    pebuf = ebuf;
    FunInfoGet(ifun, FUN_RAWBUF, &prev_raw, 0);
    /* Null out the rawbuffer pointer to prevent Funtools from
       automatically freeing this buffer on next read */
    FunInfoPut(ifun, FUN_RAWBUF, &null, 0);
    pgot = got;
  }
  /* clean up the last saved buffers */
  if( prev_raw) free(prev_raw);
  if(pebuf) free(pebuf);
  /* Flush the output extension */
  FunFlush(ofun, NULL);

  if( gti_flag == TRUE ) {
  /* Next write out the gti extension */
  /* reset the reference handle to the gti extension */
  FunInfoPut(ofun, FUN_IFUN, &gfun, 0);
  /* select the columns that are needed from gti rows */
  FunColumnSelect(ofun, sizeof(GTIRec), NULL,
		  "start", "D", "w", FUN_OFFSET(GTI, start),
		  "stop", "D", "w", FUN_OFFSET(GTI, stop),
		  NULL);
  /* write the get gti rows */
  FunEventsPut(ofun, (char *)gbuf, sfparm->gti_got, 0, NULL);
  /* flush the extension */
  FunFlush(ofun, NULL);
  }

  /* clean up */
  FunClose(ofun);
  FunClose(ifun);
  if( gti_flag == TRUE )
    FunClose(gfun);
  free(gbuf);

  /* Output statistics of screening */
  fprintf(stderr, "\nResults of Level 1 Event Screening:");
  fprintf(stderr, "\n\t%8d input events", total_cnt);
  fprintf(stderr, "\n\t%8d events where delta time was too long", delta_cnt);
  fprintf(stderr, "\n\t%8d not in good time intervals", sfparm->gti_cnt);
  fprintf(stderr, "\n\t%8d outside the PHA range (%03d-%03d)",
	  sfparm->pha_cnt, sfparm->phal, sfparm->phau);
  fprintf(stderr, "\n\t%8d had uncorrectable amplifier scale factor",
	  sfparm->ampsf_cnt);
  fprintf(stderr, "\n\t%8d had amplifier scale factor fixed",
	  sfparm->fixampsf_cnt);
  fprintf(stderr, "\n\t%8d outside of tap amplifier range", sfparm->amp_cnt);
  fprintf(stderr," (%04d-%04d [%1d] )", sfparm->amp_min, sfparm->amp_max,
	  sfparm->amp_test);
  fprintf(stderr, "\n\t%8d events failed the flatness test", sfparm->flat_cnt);
  fprintf(stderr, "\n\t\t (%f) or had a zeo central amplifier",
	  sfparm->flat_test);
  fprintf(stderr, "\n\t%8d failed the (u,v) hyper_test",sfparm->finpos_total);
  fprintf(stderr, "\n\t\t(U-axis: %f %f %f %f %f %f)",
	  sfparm->ufinh, sfparm->ufinhd, sfparm->ufina, sfparm->ufinb,
	  sfparm->ublow, sfparm->ubhigh);
  fprintf(stderr, "\n\t\t\(V-axis: %f %f %f %f %f %f)",
	  sfparm->vfinh, sfparm->vfinhd, sfparm->vfina, sfparm->vfinb,
	  sfparm->vblow, sfparm->vbhigh);
  fprintf(stderr, "\n\t%8d output events", out_cnt);
  fprintf(stderr, "\n\t\tDetails: %8d finposu_only", sfparm->finposu_only);
  fprintf(stderr, "\n\t\tDetails: %8d finposv_only", sfparm->finposv_only);
  fprintf(stderr, "\n\t\tDetails: %8d finposuv", sfparm->finposu_and_v);
  fprintf(stderr, "\n");

}

double hyper_fit(fb, finh, fina, finb)
double fb;
double finh;
double fina;
double finb;
{
  double fph;

  fph = finb*sqrt(pow(((fb-finh)/fina),2.0) -1.0);
  
  return(fph);
}

int screen_filter(sfparm, evt, gbuf)
struct SFparm *sfparm;
Event evt;
GTI gbuf;

{
  int gi, gstat,sf;
  int amp_low, amp_high, amp_flag, flat_flag;
  int finposu_flag, finposv_flag;
  double gstart, gstop, sum_amps;
  int diff1, diff2, diff3;
  double top, bot, fp, fb;
  double hyper_fit();
  GTI gti;

  /* Check the event time against good time intervals, assume that
     events are time ordered and that the good times are also ordered */
  gstat = BAD;
  for( gi=sfparm->ngti; gi < sfparm->gti_got; gi++ ) {
    gti = gbuf + gi;
    gstart = gti->start;
    gstop = gti->stop;
    if ( (evt->time < gstart) ) {
      gstat = BAD;
      break;
    }
    if ( (evt->time >= gstart) && (evt->time <= gstop) ) {
      gstat = GOOD;
      break;
    }
  }
  sfparm->ngti = gi;
  if ( gstat == BAD ) {
    sfparm->gti_cnt++;
    return(BAD);
  }
  
  /* PHA Range Test */
  if ( (evt->pha < sfparm->phal) || (evt->pha > sfparm->phau) ) {
    sfparm->pha_cnt++;
    return(BAD);
  }
  
  /*AMP_SF Test and Fix */
  sum_amps = 0.5*( evt->au1 + evt->au2 + evt->au3 + evt->av1 +
		   evt->av2 + evt->av3 )/sfparm->amp_gain;
  if( evt->pha < 255 ) {
    diff1 = fabs(evt->pha - sum_amps);
    diff2 = fabs(evt->pha - 2.0*sum_amps);
    diff3 = fabs(evt->pha - 4.0*sum_amps);
    if( (diff1 <= diff2) && (diff1 <= diff3) &&
	(diff1 < sfparm->pha_tol1) ) {
      sf = 1;
    } else if( (diff2 <= diff1) && (diff2 <= diff3) &&
	       (diff2 < sfparm->pha_tol2) ) {
      sf = 2;
    } else if( (diff3 <= diff1) && (diff3 <= diff2) &&
	       (diff3 < sfparm->pha_tol3) ) {
      sf = 3;
    } else {
      sf = 0;
    }
    if( sf == 0 ) {
      sfparm->ampsf_cnt++;
      return(BAD);
    }
  } else {
    sf = 3;
  }
  if ( sf != evt->amp_sf ) {
    sfparm->fixampsf_cnt++;
    evt->amp_sf = sf;
  }
  
  
  /* Tap Amplifier Saturation Test */
  amp_flag = FALSE;
  amp_low = 0;
  amp_high = 0;
  if( evt->au1 < sfparm->amp_min ) amp_low++;
  if( evt->au1 > sfparm->amp_max ) amp_high++;
  if( evt->au2 < sfparm->amp_min ) amp_low++;
  if( evt->au2 > sfparm->amp_max ) amp_high++;
  if( evt->au3 < sfparm->amp_min ) amp_low++;
  if( evt->au3 > sfparm->amp_max ) amp_high++;
  if( ((amp_low >= sfparm->amp_test) || (amp_high >= sfparm->amp_test)) &&
      (evt->amp_sf >=3) ) amp_flag = TRUE;
  amp_low = 0;
  amp_high = 0;
  if( evt->av1 < sfparm->amp_min ) amp_low++;
  if( evt->av1 > sfparm->amp_max ) amp_high++;
  if( evt->av2 < sfparm->amp_min ) amp_low++;
  if( evt->av2 > sfparm->amp_max ) amp_high++;
  if( evt->av3 < sfparm->amp_min ) amp_low++;
  if( evt->av3 > sfparm->amp_max ) amp_high++;
  if( ((amp_low >= sfparm->amp_test) || (amp_high >= sfparm->amp_test)) &&
      (evt->amp_sf >= 3) ) amp_flag = TRUE;
  
  if( amp_flag == TRUE ) {
    sfparm->amp_cnt++;
    return(BAD);
  }
  
  /* Flatness Test */
  flat_flag = FALSE;
  if ( (evt->au2 == 0) || 
       (((double)evt->au1/(double)evt->au2 > sfparm->flat_test) &&
	((double)evt->au3/(double)evt->au2 > sfparm->flat_test))
       ) flat_flag = TRUE; 
  if ( (evt->av2 == 0) || 
       (((double)evt->av1/(double)evt->av2 > sfparm->flat_test) &&
	((double)evt->av3/(double)evt->av2 > sfparm->flat_test))
       ) flat_flag = TRUE;
  if( flat_flag == TRUE ) {
    sfparm->flat_cnt++;
    return(BAD);
  }
  
  
  finposu_flag = FALSE;
  top = evt->au3 - evt->au1;
  bot = evt->au1 + evt->au2 + evt->au3;
  fp = fabs(top/bot);
  fb = (double)evt->au2/bot;
  if( (fb > 0.0) && (fb <= sfparm->ublow) ) {
    if( (fp >= hyper_fit(fb, sfparm->ufinh+sfparm->ufinhd,
			 sfparm->ufina, sfparm->ufinb )) || 
	(fp <= hyper_fit(fb, sfparm->ufinh-sfparm->ufinhd,
			 sfparm->ufina, sfparm->ufinb )) ) {
      finposu_flag = TRUE;
    }
  } else if( (fb > sfparm->ublow) && (fb <= sfparm->ubhigh) ) {
    if( fp >= hyper_fit(fb, sfparm->ufinh+sfparm->ufinhd,
			sfparm->ufina, sfparm->ufinb ) ) {
      finposu_flag = TRUE;
    }
  } else if( fb > sfparm->ubhigh ) {
    finposu_flag = TRUE;
  }
  if( finposu_flag == TRUE ) {
    sfparm->finposu_cnt++;
  }
  
  finposv_flag = FALSE;
  top = evt->av3 - evt->av1;
  bot = evt->av1 + evt->av2 + evt->av3;
  fp = fabs(top/bot);
  fb = (double)evt->av2/bot;
  if( (fb > 0.0) && (fb <= sfparm->vblow) ) {
    if( (fp >= hyper_fit(fb, sfparm->vfinh+sfparm->vfinhd,
			 sfparm->vfina, sfparm->vfinb )) || 
	(fp <= hyper_fit(fb, sfparm->vfinh-sfparm->vfinhd,
			 sfparm->vfina, sfparm->vfinb )) ) {
      finposv_flag = TRUE;
    }
  } else if( (fb > sfparm->vblow) && (fb <= sfparm->vbhigh) ) {
    if( fp >= hyper_fit(fb, sfparm->vfinh+sfparm->vfinhd,
			sfparm->vfina, sfparm->vfinb ) ) {
      finposv_flag = TRUE;
    }
  } else if( fb > sfparm->vbhigh ) {
    finposv_flag = TRUE;
  }
  if( finposv_flag == TRUE ) {
    sfparm->finposv_cnt++;
  }
  if( (finposu_flag == TRUE) && (finposv_flag == FALSE) )
    sfparm->finposu_only++;
  if( (finposu_flag == FALSE) && (finposv_flag == TRUE) )
    sfparm->finposv_only++;
  if( (finposu_flag == TRUE) && (finposv_flag == TRUE) )
    sfparm->finposu_and_v++;
  if( (finposu_flag == TRUE) || (finposv_flag == TRUE) ) {
    sfparm->finpos_total++;
    return(BAD);
  }
  return(GOOD);
}
    
