/******************************************************************************
*
    PROGRAM:  flag.c
    USAGE:    flag <control-filename>

       This program implements four algorithms for detecting bad data in
       an ADCP profile.

          1) The first algorithm determines if bottom interference is
             present by scanning the amplitude array for any rise in the
             amplitude and comparing the value at that point with the lowest
             found so far.  If the difference exceeds some defined threshold,
             it concludes that bottom interference has occurred and flags
             the profile.  It proceeds to find the maximum among the
             remaining amplitude values to identify the bin whose depth will
             be recorded as the actual bottom depth for that profile.

          2) The second algorithm flags as bad those profiles with too large
             a variance in the w velocity component.  It calculates the
             variance of the w velocity over bins with a percent good >=
             a set threshold.  If this variance exceeds the threshold for
             the w variance, the profile is logged as being bad.

          3) The third algorithm detects glitches by examining the second
             difference of the w velocity component for those bins that
             meet the pgood threshold.  If the second difference exceeds the
             set threshold, the second differences of the u or v velocity
             components are similarly examined at those same bins in order 
             to confirm the presence of a glitch.  If confirmed, the profile
             is logged as bad.

          4) The fourth algorithm checks the absolute value of the error
             velocities, if present, against some threshold for those bins
             that satisfy the percent good threshold.  If any of those
             error velocities exceed the error velocity threshold, the
             profile is logged as bad, and the largest absolute error
             velocity is recorded in the log file together with the bin
             number.  An auxiliary file (.EV) is also created as a separate
             record of the time and block-profile number of each flagged
             profile, together with the total number of bins found to
             exceed the threshold and a listing of those bin numbers.  This
             file may be used directly with the BADBIN.EXE program to set
             those bins to BAD in the database.

       The control file must specify the following:

               database name, e.g., A601
               start_bin for w variance calculation
               thresholds for:
                  amplitude, 
                  percent good,
                  w variance,                  in (m/s)^2
                  second difference of w,      in m/s
                  second difference of u/v     in m/s
                  error velocity               in m/s
               time range(s) of profiles to be examined

       The program produces a log file listing all profiles flagged as bad 
       and indicating by which of the four algorithms:

               A = amplitude
               V = variance
               D = second difference
               E = error velocity

       The log file can then be compared against plots of the data to
       confirm/reject/extend its results.

    05/26/89 - Modified to comment out header lines with '%'
    11/09/89 - Modified to check W variance and W difference only over
               those W < ADJ_BADFLOAT
    11/22/89 - Modified to work with velocities and thresholds expressed
               in any user-specified length unit
             - Added fourth algorithm (error velocity criterion) as
               described in (4) above
             - Removed log filename parameter from control file: log file
               will automatically have the database name and extension
               .flg; the error velocity auxiliary file will have the
               database name and .ev extension
             - Added LENGTH_UNIT parameter to control file so user can
               indicate in what units the velocity-based threshold
               parameters are expressed.
    12/14/89 - Fixed bug in error velocity algorithm - missing abs() so
               that only positive error velocities > threshold were being
               flagged

               J. Ranada - University of Hawaii JIMAR
                                                                              *
******************************************************************************/

#include "geninc.h"
#include <math.h>      /* for fabs function */
#include "data_id.h"   /* for oceanographic data variable names & ids */
#include "use_db.h"    /* db*_cnf(), get_time_range(), check_time(), print_time_range() */
#include "ioserv.h"    /* check_error(), error_found(), main(), check_fopen() */
#include "adcpflag.h"

#define MAX_NBINS 128       /* maximum no. of bins in database profile */
#define FLAG_LENGTH 5       /* maximum of 'AVDE\0' */
#define diff2(v,i) (v[i+1] + v[i-1] - 2 * v[i])
                            /* second difference of v at i */

typedef struct
{
   char   flag[FLAG_LENGTH];
   SHORT  min_amp_bin, max_amp_bin;  /* SHORT to coincide w/ ADCP max_amp_bin */
   SHORT  bottom_depth;
   UBYTE  min_amp, max_amp;
   double w_variance;
   SHORT  glitch_bin;
   LONG   d2w, d2uv;
   SHORT  max_ev, max_ev_bin;
} log_struct;                      /* information to be logged in output file */

FILE_NAME_TYPE   dbname, logname, evname, flag_name, root;
int              start_bin, amp_threshold, pg_threshold, retrieved_bp;
UBYTE            flag_mask = 0;
double           d2w_threshold, d2uv_threshold, wvar_threshold, ev_threshold,
                 length_unit;
log_struct       log_line;
int              iblkprf[2], cluster_gap;
YMDHMS_TIME_TYPE ptime;

#if PROTOTYPE_ALLOWED
void initialize_struct(void);
int amp_pass(UBYTE amp[], unsigned int namp);
void wvariance_pass(SHORT w_vel[], int start_bin, UBYTE pgood[],
   unsigned int nvalues);
int glitch_pass(SHORT w_vel[], UBYTE pgood[], unsigned int nvalues,
   UBYTE profile_flags[], unsigned int npf);
int ev_pass(SHORT e_vel[], UBYTE pgood[], unsigned int nvalues, FILE *fpev);
int retrieve_bp(void);
void rescale_parameters(double scale_factor);
void echo_parameters(FILE *fp);
#else
void initialize_struct();
int amp_pass();
void wvariance_pass();
int glitch_pass();
int ev_pass();
int retrieve_bp();
void rescale_parameters();
void echo_parameters();
#endif

/*---------------------------------------------------------------------------
   The main function is in the file MAIN_CNT.C which accepts the control
   file name on the command line, opens it, strips it of any comments and
   copies it to the file TEMP.CNT, and passes the pointer to TEMP.CNT to
   the processing routine do_it.  It closes the control files at the end.
  ---------------------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void do_it(FILE *fpcnt)
#else
void do_it(fpcnt)
FILE *fpcnt;
#endif
{
   int              ierr, bit_flag, i;
   SHORT            w_vel[MAX_NBINS], e_vel[MAX_NBINS];
   UBYTE            amp[MAX_NBINS], pgood[MAX_NBINS], profile_flags[MAX_NBINS];
   YMDHMS_TIME_TYPE start, end;
   FILE             *fplog, *fpev;
   unsigned int     nvel, nev, npf, npg, namp;
   char             proceed[2];
   int gap = 0;

   static PARAMETER_LIST_ENTRY_TYPE flagcnt[] =
   {
      " DB_NAME:"          , " %79s", dbname         , TYPE_STRING,
      " OUTPUT:"           , " %79s", root           , TYPE_STRING,
      " START_BIN:"        , " %d"  , &start_bin     , TYPE_INT,
      " AMP_THRESHOLD:"    , " %d"  , &amp_threshold , TYPE_CHAR,
      " PGOOD_THRESHOLD:"  , " %d"  , &pg_threshold  , TYPE_CHAR,
      " LENGTH_UNIT:"      , " %lf" , &length_unit   , TYPE_DOUBLE,
      " W_VAR_THRESHOLD:"  , " %lf" , &wvar_threshold, TYPE_DOUBLE,
      " D2W_THRESHOLD:"    , " %lf" , &d2w_threshold , TYPE_DOUBLE,
      " D2U&D2V_THRESHOLD:", " %lf" , &d2uv_threshold, TYPE_DOUBLE,
      " EV_THRESHOLD:"     , " %lf" , &ev_threshold  , TYPE_DOUBLE,
      " CLUSTER_GAP:"      , " %d"  , &cluster_gap   , TYPE_INT,
      " FLAG_MASK:"        , " %19s", flag_name      , TYPE_STRING,
      NULL                 , NULL   , NULL           , 0
   };

   sin(0.0);

   if (error_found(get_parameters(fpcnt, flagcnt, NULL),
      "reading flag control file parameters")) return;
   rescale_parameters(length_unit);
   while (strcmp(flag_name, "end"))
   {
      if (error_found(
         (BADINT == (bit_flag = get_code(adcp_profflags, flag_name))),
         "unrecognized flag_mask")) return;
      flag_mask |= (UBYTE) bit_flag;
      if (error_found(
         (fscanf(fpcnt, " %19s", flag_name) != 1),
         "scanning flag_mask")) return;
   }
   echo_parameters(stdout);
   if (ev_threshold < 5.0)
   {
      printf("\n\n%%%% WARNING: ev_threshold very small");
      printf("\n   CONTINUE (y/n)? ");
      scanf("%1s", proceed);
      if (toupper(proceed[0]) != 'Y') return;
   }

   check_dbopen(1, dbname, READ_ONLY, DIR_IN_MEMORY);
   new_extension(logname, root, ".flg");
   new_extension(evname , root, ".ev");
   fplog = check_fopen(logname, "w");
   fpev = check_fopen(evname, "w");
   set_msg_file(fplog);   /* echo all messages to log file */
   echo_parameters(fplog);

   start_bin--;                       /* adjust for C array indexing from 0 */

   fscanf(fpcnt, " TIME_RANGE:");
   while (get_time_range(fpcnt, &start, &end) == 1)
   {
      fprintf(fplog, "\n\n%% TIME_RANGE:  ");
      print_ymdhms_time(fplog, &start);
      fprintf(fplog, "  to  ");
      print_ymdhms_time(fplog, &end);
      print_time_range(stdout, &start, &end);
      fprintf(fplog, "\n%% G         ---Profile Time--- ---- ----Amplitude Pass----- ---W---- ---Glitch Pass--- --EV Pass--");                                                   
      fprintf(fplog, "\n%% A Blk Prf                    Flag   Min   Max Dep Min Max Variance Glitch Max    At");                                                   
      fprintf(fplog, "\n%% P No. No. yy/mm/dd  hh:mm:ss ----   Bin   Bin  th Amp Amp --Pass--   Bin   d2W  d2UV  |EV|   Bin");
      fprintf(fplog, "\n%%                                               (m) (*1e-3)           (*1e-3) (*1e-3)    ");

      ierr = dbsrch_cnf(TIME_SEARCH, (char *) &start);
      if (ierr && (ierr != SEARCH_BEFORE_BEGINNING) && (ierr != SEARCH_BEYOND_END))
         break;

      while (check_time(&ptime, &start, &end))
      {
         initialize_struct();
         retrieved_bp = 0;

         namp = MAX_NBINS * sizeof(UBYTE);
         if (dbget_cnf(AMP_SOUND_SCAT, (char *)amp, &namp, "getting amplitude"))
            goto close;
         if (amp_pass(amp, namp)) goto close;

         npg = MAX_NBINS * sizeof(UBYTE);
         if (dbget_cnf(PERCENT_GOOD, (char *)pgood, &npg, "getting percent good"))
            goto close;
         if (npg > 0)
         {
            nvel = npg * sizeof(SHORT); /* so nvel will be min{npg, nvel} */
            if (dbget_cnf(W, (char *) w_vel, &nvel, "getting W velocity"))
               goto close;
            nvel /= sizeof(SHORT);   /* convert from no. of bytes to no. of values */

            nev = npg * sizeof(SHORT);
            if (dbget_cnf(ERROR_VEL, (char *) e_vel, &nev, "getting error velocity"))
               goto close;
            nev /= sizeof(SHORT); 

            if (flag_mask)
            {
               npf = npg * sizeof(UBYTE);
               if (dbget_cnf(PROFILE_FLAGS, (char *) profile_flags, &npf,
                  "getting profile flags")) goto close;

               for (i = 0; i < npf; i++)
                  if (profile_flags[i] & flag_mask)
                  {
                     if (i < nvel) w_vel[i] = BADSHORT;
                     if (i < nev)  e_vel[i] = BADSHORT;
                  }
            }

            wvariance_pass(w_vel, start_bin, pgood, nvel);

            if (glitch_pass(w_vel, pgood, nvel, profile_flags, npf)) goto close;
            if (nev > 0)
               if (ev_pass(e_vel, pgood, nev, fpev)) goto close;
         }

         /*----------------------------------------------------------
             IF FLAG HAS BEEN "SET" LOG PROFILE DATA IN OUTPUT FILE
           ----------------------------------------------------------*/
         if (strncmp(log_line.flag, "    ", 4))
         {
	    if (gap > cluster_gap)
	    {
	       fprintf(fplog, "\n%%------ %d profiles passed ------", gap); 
	       gap = 0;
            }
            if (!retrieved_bp)
               if (retrieve_bp()) goto close;

            fprintf(fplog, "\n%3d %3d %3d ", gap, iblkprf[0], iblkprf[1]);
            write_ymdhms_time(fplog, &ptime);
            fprintf(fplog,
               " %4s %5d %5d %3d %3d %3d %8.1f %5d %5ld %5ld %5d %5d",
               log_line.flag, log_line.min_amp_bin, log_line.max_amp_bin,
               log_line.bottom_depth, log_line.min_amp, log_line.max_amp,
               log_line.w_variance, log_line.glitch_bin, log_line.d2w,
               log_line.d2uv, log_line.max_ev, log_line.max_ev_bin);
            gap = 0;
         }
	 else
	    gap++;
         if (dbmove_cnf(1)) goto close;
      }
      if (gap > 0)
      {
	 fprintf(fplog, "\n%%------ %d profiles passed ------", gap); 
	 gap = 0;
      }
   }
   puts("\n\n");
   report_msg("\n%% END OF CONTROL FILE\n");

   close:
      if (gap > 0)
      {
	 fprintf(fplog, "\n%%------ %d profiles passed ------", gap); 
	 fprintf(fplog, "\n%% last good block-profile is:");
	 retrieve_bp();
         fprintf(fplog, "\n%%   %3d %3d ", iblkprf[0], iblkprf[1]);
         write_ymdhms_time(fplog, &ptime);
         fprintf(fplog,
            " %4s %5d %5d %3d %3d %3d %8.1f %5d %5ld %5ld %5d %5d",
            log_line.flag, log_line.min_amp_bin, log_line.max_amp_bin,
            log_line.bottom_depth, log_line.min_amp, log_line.max_amp,
            log_line.w_variance, log_line.glitch_bin, log_line.d2w,
            log_line.d2uv, log_line.max_ev, log_line.max_ev_bin);
      }
      fclose(fplog);
      dbclose_cnf();
}

#if PROTOTYPE_ALLOWED
void initialize_struct(void)      /* initialize fields to defaults */
#else
void initialize_struct()      /* initialize fields to defaults */
#endif
{
   strncpy(log_line.flag, "    ", 4);   
   log_line.min_amp_bin  = log_line.max_amp_bin = MAXSHORT;
   log_line.bottom_depth = -1;
   log_line.min_amp      = log_line.max_amp = MAXUBYTE;
   log_line.w_variance   = -1.0;
   log_line.glitch_bin   = MAXSHORT;
   log_line.d2w          = log_line.d2uv = 0L;
   log_line.max_ev       = 0;
   log_line.max_ev_bin   = 32767;
}

/*-------------------------------------------------------------
    AMPLITUDE PASS IMPLEMENTS FIRST ALGORITHM DESCRIBED ABOVE
  -------------------------------------------------------------*/
#if PROTOTYPE_ALLOWED
int amp_pass(UBYTE amp[], unsigned int namp)
#else
int amp_pass(amp, namp)
UBYTE        amp[];
unsigned int namp;
#endif
{
   int   minsofar, maxsofar, bottom_found, decreasing, i, j;
   SHORT depth[MAX_NBINS];
   unsigned int n;

   minsofar = bottom_found = 0;
   i = 1;
   /*----------------------------------------------------------------------
       SCAN AMPLITUDE ARRAY FOR RISE IN AMPLITUDE INDICATING BOTTOM FOUND
     ----------------------------------------------------------------------*/
   while ((i < namp) && (!bottom_found))
   {
      decreasing = 1;
      while (decreasing && (i < namp))
      {
         if (amp[i] > amp[i-1])
            decreasing = 0;
         else
            i++;
      }
      if (!decreasing)
      {
         maxsofar = i;
         if (amp[i-1] < amp[minsofar])
            minsofar = i - 1;  /* NEW MINIMUM AMPLITUDE */
         /*--------------------------------------------------------------
             IF RISE EXCEEDS THRESHOLD THEN BOTTOM DEPTH HAS BEEN FOUND
           --------------------------------------------------------------*/
         if (amp[maxsofar] - amp[minsofar] > amp_threshold)
         {
            bottom_found = 1;
            /*---------------------------------------------
                FIND MAXIMUM AMPLITUDE FOR REMAINING BINS
              ---------------------------------------------*/
            for (j = i+1; j < namp; j++)
               if (amp[j] >= amp[maxsofar]) maxsofar = j;
         }
         else
            i++;
      }
   }

   /*-----------------------------------------------------------------------
       IF BOTTOM IS FOUND, THEN SET APPROPRIATE VARIABLES IN LOG STRUCTURE
     -----------------------------------------------------------------------*/
   if (bottom_found)
   {
      n = MAX_NBINS * sizeof(SHORT);
      if (dbget_cnf(DEPTH, (char *) depth, &n, "getting depth")) return(1);

      log_line.flag[0] = 'A';
      log_line.min_amp_bin = minsofar + 1;   /* renumber bins as 1, 2, ... */
      log_line.max_amp_bin = maxsofar + 1;   /* rather than C's 0, 1, ...  */
      log_line.min_amp = amp[minsofar];
      log_line.max_amp = amp[maxsofar];
      log_line.bottom_depth = depth[maxsofar];
   }
   return(0);
}

/*-------------------------------------------------------------------
    W VARIANCE PASS IMPLEMENTS THE SECOND ALGORITHM DESCRIBED ABOVE
  -------------------------------------------------------------------*/
#if PROTOTYPE_ALLOWED
void wvariance_pass(SHORT w_vel[], int start_bin, UBYTE pgood[], unsigned int nvalues)
#else
void wvariance_pass(w_vel, start_bin, pgood, nvalues)
SHORT        w_vel[];
UBYTE        pgood[];
int          start_bin;
unsigned int nvalues;
#endif
{
   int    i, count = 0;
   SHORT  save_w;
   long   sum_w = 0L, sum_w_squared = 0L;
   double w_variance = 0.0;

   /*--------------------------------------------------
       SUMMATION OVER BINS WHICH MEET PGOOD THRESHOLD
     --------------------------------------------------*/
   for (i = start_bin; i < nvalues; i++)
   {
      if ( (pgood[i] >= pg_threshold) && (w_vel[i] != BADSHORT) )
      {
         save_w = w_vel[i];
         sum_w += save_w;
         sum_w_squared += (long) save_w * save_w;
         count++;
      }
   }

   /*--------------------------
       W VARIANCE CALCULATION
     --------------------------*/
   if (count > 2)
      w_variance = ((double) (count * sum_w_squared - sum_w * sum_w)) /
         (count * (count-1));
   else
   {
      if (count == 2)
         w_variance = fabs(save_w - (((double) sum_w) / count));
      else
         w_variance = 0;
   }

   /*-----------------------------------------------------------------------
       SET APPROPRIATE VARIABLES IN LOG STRUCTURE IF W VARIANCE IS TOO BIG
     -----------------------------------------------------------------------*/
   if (w_variance > wvar_threshold)
   {
      log_line.w_variance = w_variance;
      log_line.flag[1] = 'V';
   }
}

/*---------------------------------------------------------------
    GLITCH PASS IMPLEMENTS THE THIRD ALGORITHM DESCRIBED ABOVE
  ---------------------------------------------------------------*/
#if PROTOTYPE_ALLOWED
int glitch_pass(SHORT w_vel[], 
		UBYTE pgood[], unsigned int nvalues, 
		UBYTE profile_flags[], unsigned int npf)
#else
int glitch_pass(w_vel, pgood, nvalues, profile_flags, npf)
SHORT        w_vel[];
UBYTE        pgood[], profile_flags[];
unsigned int nvalues, npf;
#endif
{
   LONG  d2w, d2uv;
   BYTE  retrieved_u, retrieved_v, glitch_found;
   int   i, j;
   SHORT u_vel[MAX_NBINS], v_vel[MAX_NBINS];
   unsigned int n;

   retrieved_u = retrieved_v = glitch_found = 0;

   i = 1;
   while ((i < nvalues-1) && (!glitch_found))
   {
      /*-----------------------------------------------------------------
          CHECK SECOND DIFFERENCE OF W ONLY IF PGOOD >= PGOOD THRESHOLD
        -----------------------------------------------------------------*/
      if ( (pgood[i-1] >= pg_threshold) && (pgood[i] >= pg_threshold) &&
         (pgood[i+1] >= pg_threshold) && (w_vel[i-1] != BADSHORT) &&
         (w_vel[i] != BADSHORT) && (w_vel[i+1] != BADSHORT) )
      {
         if (labs((d2w = diff2(w_vel,i))) > (LONG) d2w_threshold)
         {
            /*---------------------------------------
                VERIFY USING SECOND DIFFERENCE OF U
              ---------------------------------------*/
            if (!retrieved_u)
            {
               n = MAX_NBINS * sizeof(SHORT);
               if (dbget_cnf(U, (char *) u_vel, &n, "getting U velocity"))
                  return(1);
               retrieved_u = 1;
               if (flag_mask && npf > 0)
                  for (j = 0; j < min_val(n, npf); j++)
                     if (profile_flags[j] & flag_mask) u_vel[j] = BADSHORT;
            }
            if ((labs(d2uv = diff2(u_vel,i))) > (LONG) d2uv_threshold)
               glitch_found = 1;
            else
            {
               /*---------------------------------------
                   VERIFY USING SECOND DIFFERENCE OF V
                 ---------------------------------------*/
               if (!retrieved_v)
               {
                  n = MAX_NBINS * sizeof(SHORT);
                  if (dbget_cnf(V, (char *) v_vel, &n, "getting V velocity"))
                     return(1);
                  retrieved_v = 1;
                  if (flag_mask && npf > 0)
                     for (j = 0; j < min_val(n, npf); j++)
                        if (profile_flags[j] & flag_mask) v_vel[j] = BADSHORT;
               }
               if (labs((d2uv = diff2(v_vel,i))) > (LONG) d2uv_threshold)
                  glitch_found = 1;
            }
         }
         if (!glitch_found)
            i++;
      }
      else
         i++;
   }

   if (glitch_found)
   {
      log_line.glitch_bin = i + 1;            /* renumber bins as 1, 2, ... */
      log_line.d2w = d2w;
      log_line.d2uv = d2uv;
      log_line.flag[2] = 'D';
   }
   return(0);
}

/*-------------------------------------------------------------------
    ERROR VELOCITY PASS IMPLEMENTS FOURTH ALGORITHM DESCRIBED ABOVE
  -------------------------------------------------------------------*/
#if PROTOTYPE_ALLOWED
int ev_pass(SHORT e_vel[], UBYTE pgood[], unsigned int nvalues, FILE *fpev)
#else
int ev_pass(e_vel, pgood, nvalues, fpev)
SHORT e_vel[];
UBYTE pgood[];
unsigned int nvalues;
FILE *fpev;
#endif
{
   SHORT maxsofar = 0;
   int maxbin = 32767, i, j = 0;
   int badbin[MAX_NBINS];

   for (i = 0; i < nvalues; i++)
   {
      if (pgood[i] >= pg_threshold)
         if ( (abs(e_vel[i]) > (SHORT) ev_threshold) && (e_vel[i] != BADSHORT) )
         {
            badbin[j] = i+1;        /* renumber bins from 1,... */
            j++;
            if (abs(e_vel[i]) > abs(maxsofar))
            {
               maxsofar = e_vel[i];
               maxbin = i;
            }
         }
   }
   if (j > 0)
   {
      log_line.max_ev = maxsofar;
      log_line.max_ev_bin = maxbin + 1;    /* renumber bins from 1,... */
      log_line.flag[3] = 'E'; 
      if (retrieve_bp()) return(1);
      write_ymdhms_time(fpev, &ptime);
      fprintf(fpev, "  %3d  %3d  %3d", iblkprf[0], iblkprf[1], j);
      for (i = 0; i < j; i++)
         fprintf(fpev, "  %3d", badbin[i]);
      fprintf(fpev, "\n");
   }
   return(0);
}

#if PROTOTYPE_ALLOWED
int retrieve_bp(void)
#else
int retrieve_bp()
#endif
{
   unsigned int n;

   n = 2 * sizeof(int);
   if (dbget_cnf(BLOCK_PROFILE_INDEX, (char *) iblkprf, &n,
      "getting block-profile index")) return(1);
   retrieved_bp = 1;
   return(0);
}

#if PROTOTYPE_ALLOWED
void rescale_parameters(double scale_factor)  /* from user units to mm/s */
#else
void rescale_parameters(scale_factor)  /* from user units to mm/s */
double scale_factor;
#endif
{
   scale_factor   /= .001;  /* from m to mm/s so velocities are whole nos. */
   wvar_threshold *= (scale_factor * scale_factor);
   d2w_threshold  *= scale_factor;
   d2uv_threshold *= scale_factor;
   ev_threshold   *= scale_factor;
}

void echo_parameters(fp)
FILE *fp;
{
   fprintf(fp, "%% DBNAME:            %5s\n", dbname);
   fprintf(fp, "%% OUTPUT:            %5s\n", root);
   fprintf(fp, "%% START_BIN:         %5d\n", start_bin);
   fprintf(fp, "%% AMP_THRESHOLD:     %5d\n", amp_threshold);
   fprintf(fp, "%% PGOOD_THRESHOLD:   %5d\n", pg_threshold);
   fprintf(fp, "%% LENGTH_UNIT:  %1.1e (m)\n", length_unit);
   fprintf(fp, "%% W_VAR_THRESHOLD:   %5.0f * (%1.1e m/s)^2\n", wvar_threshold, length_unit);
   fprintf(fp, "%% D2W_THRESHOLD:     %5.0f * %1.1e (m/s)\n", d2w_threshold, length_unit);
   fprintf(fp, "%% D2U&D2V_THRESHOLD: %5.0f * %1.1e (m/s)\n", d2uv_threshold, length_unit);
   fprintf(fp, "%% EV_THRESHOLD:      %5.0f * %1.1e (m/s)\n", ev_threshold, length_unit);
   fprintf(fp, "%% FLAG_MASK:         %5u", flag_mask);
}
