/******************************************************************************
*
    PROGRAM:  GETMAT.C
    USAGE:    GETMAT [-r[s]] <dbname> <blk> <prf> [nprf]
                                   [nbin] [seq_flag] [refstart] [refend]
                or   [-t[r[s]]] <dbname> <yr> <start_dd> <interval>
                                   [nbin] [seq_flag] [refstart] [refend]

               -r option causes raw amplitude output.
               -s option causes spectral width output.

       This program accepts as command line arguments a CODAS database name,
       and the block # and profile # of a key profile to search for.
       The user may also specify:
          1) the no. of profiles to retrieve in addition to the key profile,
          2) the maximum no. of bins to retrieve for each of those profiles,
          3) the setting for the seq_flag:
                0 => retrieve nprf profiles before and after the key
                1 => retrieve nprf profiles after the key
               -1 => retrieve nprf profiles before the key
       in place of the default values provided below.

       It then searches the specified CODAS database for the key profile,
       and retrieves the U, V, W, error velocity, time, percent good &
       amplitude data for that profile and for nprf profiles before or after,
       if the seq_flag is set to +1 or -1, or for nprf profiles before and after,
       if the seq_flag is 0.

       The profile data are then written as two-dimensional arrays
       to .MAT files--U.MAT, V.MAT, W.MAT, E.MAT, PG.MAT, AMP.MAT, and
       OTHER.MAT--which can then be loaded from PC-Matlab for plotting.

       J. Ranada - 03/15/88 - University of Hawaii JIMAR

       9/22/89 - JR - modified to also retrieve error velocity, and to write
                      output to different .MAT files to avoid running out of
                      memory when retrieving many profiles at a time;
                      the U, V, W, error velocity, percent good and amplitude
                      data are now stored in double precision and de-meaned
                      using the mean over bins 5 to 20 or nbin, whichever
                      is smaller.  Bad values are already set to NaN.

       8/29/90 - JR - modified to use PROFILE_FLAGS with flag mask = 0xFF.

       9/09/91 - JR - inserted space in nsteps=-1 (HP Unix compiler needs it)
      12/17/91 - JR - now retrieves navigation info also
       4/30/92 - JR - added -1 seq_flag for retrieving nprf profiles before
                      the key
      10/19/93 - JR - removed code to de-mean U, V, and W;
                    - added command line options [refstart] and [refend]
                      to specify reference layer bins to use in
                      U_MEAN, V_MEAN and W_MEAN calculations;
                      set both to 0 to not bother;
                      leaving them out defaults to bins 5 to 20
      96/10/02 - EF - added -r and -t options.
      2000/03/29 - EF - changed to make the DAYS array use the specified
                      yearbase with the -t option, or the year of the first
                      profile retrieved otherwise.  Previously it always
                      used the year of each profile, so DAYS was not
                      monotonic.

      2000/05/19 - EF - Added -s option (spectral width).

      2000/09/20 - EF - Added U_SHIP, V_SHIP to u.mat, v.mat.  This is
                      U_ship_absolute or U_absolute from access variables.

      2000/10/16 - EF - Added HEADING (ancillary_1.mn_heading) to
                      other.mat.
                                          *
******************************************************************************/

#include "geninc.h"
#include "adcp.h"                   /* NAVIGATION_TYPE                       */
#include "data_id.h"                /* CODAS variable names and IDs          */
#include "matfile.h"                /* savemat(), tonan_f()                  */
#include "ioserv.h"                 /* check_fopen(), check_error()          */
#include "use_db.h"                 /* db*_cnf()                             */
#include "vector.h"                 /* subtract_reference()                  */

#define DEF_NBIN 128                /* default max. no. of bins in a profile */
#define SEQUENTIAL 1                /* default = get nprf profiles after key */
#define DEF_NPRF 5                  /* default no. of profiles to retrieve   */
                                    /* BEFORE & AFTER key if seq_flag is 0,  */
                                    /* or default no. of profiles to retrieve*/
                                    /* BEFORE key if seq_flag is -1,         */
                                    /* or default no. of profiles to retrieve*/
                                    /* AFTER key if seq_flag is +1           */
#define REF_BIN_RANGE ref0, min_val(nbin - 1, refn)

int allocate_arrays(int totprf, int nbin);
int reallocate_arrays(int totprf);
int move_back(int *nfails);
int move_forward(int *ierr);
int get_data(int i, int nbin);

static int   *iblkprf, ref0 = 4, refn = 19;
static FLOAT *fdata;
static DOUBLE *ddata, *U_mean, *V_mean, *W_mean, *lon, *lat, *days, *heading;
static DOUBLE *U_ship, *V_ship;
static SHORT  *time, *lgb, *mab;
static MAT_ARRAY_FP_TYPE *U_mat_ptr, *V_mat_ptr, *W_mat_ptr, *E_mat_ptr,
                  *PG_mat_ptr,
                  *AMP_mat_ptr, *RAW_AMP_mat_ptr, *DEP_mat_ptr, *PF_mat_ptr,
                  *SW_mat_ptr;
static char dbname[128];
static    int   write_raw_amp = 0;
static    int   write_spectral_width = 0;
static    int   year_base = 0;


int main(int argc, char *argv[])
{
   int   nprf = DEF_NPRF,
         seq_flag = SEQUENTIAL,
         nbin = DEF_NBIN;
   int   ierr, nfails, totprf, i, k;
   int   finished;
   int   iarg;
   unsigned int nbyte, n;
   int   time_key = 0;
   int   key_bp[2];
   double key_day, start_day, end_day;
   double duration;
   YMDHMS_TIME_TYPE this_time, key_time, start_time, end_time;

   FILE  *fp_U, *fp_V, *fp_W, *fp_E, *fp_AMP, *fp_RAW_AMP, *fp_SW,
          *fp_DEP, *fp_PG, *fp_PF, *fp_OTHER;

   /* The following print statement gives getp.m a string to
   search for in the output, so that it can figure out
   whether getmat was found; if not, there must be a path
   problem, as usual.
   */
   printf("\nStarting getmat ...\n");
   if ( (argc < 4)  )
   {
      printf("\n ERROR: Invalid number of parameters on command line.");
      printf("\n USAGE: getmat [-r] <dbname> <blk> <prf> [nprf]");
      printf("\n    or");
      printf("\n        getmat -t[r] <dbname> <year> <start_dd> <interval_dd>");
      printf("\n    to either of the above, optional arguments may be appended:");
      printf("\n        [nbin] [seq_flag] [ref0] [refn]");
      printf("\n    the -r option causes output of raw amplitude\n\n");
      exit(-1);
   }

   iarg = 1;
   while (argv[iarg][0] == '-')
   {
      if (strchr(argv[iarg], 'r') )
         write_raw_amp = 1;
      if (strchr(argv[iarg], 's') )
         write_spectral_width = 1;
      if (strchr(argv[iarg], 't') )
         time_key = 1;
      iarg++;
   }
   strcpy(dbname, argv[iarg++]);
   if (dbopen_cnf(1, dbname, READ_ONLY, DIR_IN_MEMORY)) exit(-1);

   if (time_key)
   {
      year_base = atoi(argv[iarg++]);
      key_day = atof(argv[iarg++]);
      duration  = atof(argv[iarg++]);
      yd_to_ymdhms_time(key_day,  year_base, &key_time);
      print_ymdhms_time(stdout, &key_time);
      dbsrch_cnf(TIME_SEARCH, (char *) &key_time);
      nbyte = 2*sizeof(int);
      if (dbget_cnf(BLOCK_PROFILE_INDEX, (char *) &key_bp[0],
            &nbyte, "getting key_bp from time")) goto close;
      nprf = 100;
   }
   else
   {
      key_bp[0] = atoi(argv[iarg++]);         /* block no. of key                    */
      key_bp[1] = atoi(argv[iarg++]);         /* profile no. of key                  */
      if (argc > iarg)                     /* optional command line argument      */
         nprf = atoi(argv[iarg++]);           /* no. of add'l profiles to retrieve   */
      if (dbsrch_cnf(BLOCK_PROFILE_SEARCH, (char *) key_bp)) goto close;
   }
   if (argc > iarg)
      nbin = atoi(argv[iarg++]);           /* max. no. of profile bins            */
   if (argc > iarg)
      seq_flag = atoi(argv[iarg++]);       /* type of retrieval                   */
   if (argc > iarg + 1)                      /* alternative/no reference layer      */
   {
      ref0 = atoi(argv[iarg++]) - 1;
      if (ref0 > -1)
      {
         refn = atoi(argv[iarg++]) - 1;
         if (refn < ref0)
         {
            fprintf(stderr, "\n ERROR:  Invalid reference layer %d to %d\n\n", ref0, refn);
            exit(-1);
         }
      }
   }


   switch(seq_flag)
   {
      case 0:
         totprf = nprf * 2 + 1;       /* key + nprf profiles before & after  */
         break;
      case -1:
      case 1:
         totprf = nprf + 1;           /* key + nprf profiles before or after */
         break;
   }

   printf("\n\n Searching CODAS database ==> %s", dbname);
   printf("\n for block %d profile %d", key_bp[0], key_bp[1]);
   printf("\n Max no. of profiles ==> %d", totprf);
   printf("\n Max no. of bins ==> %d\n", nbin);

   fp_U     = check_fopen("u.mat"    , "wb");
   fp_V     = check_fopen("v.mat"    , "wb");
   fp_W     = check_fopen("w.mat"    , "wb");
   fp_E     = check_fopen("e.mat"    , "wb");
   fp_PG    = check_fopen("pg.mat"   , "wb");
   fp_AMP   = check_fopen("amp.mat"  , "wb");
   if (write_raw_amp)
      fp_RAW_AMP   = check_fopen("raw_amp.mat"  , "wb");
   if (write_spectral_width)
      fp_SW   = check_fopen("sw.mat"  , "wb");

   fp_DEP   = check_fopen("depth.mat", "wb");
   fp_OTHER = check_fopen("other.mat", "wb");
   fp_PF    = check_fopen("pf.mat"   , "wb");


   /*------------------------------------------------------------------------
       Check how many bins are available for the key profile.
     ------------------------------------------------------------------------*/
   nbyte = 0;
   if (dbget_cnf(U, (char *) NULL, &nbyte, "checking number of bins")) goto close;
   nbin = min_val(nbin, (nbyte / sizeof(SHORT)));

   /*------------------------------------------------------------------------
       For non-SEQUENTIAL retrieval, we move backward nprf profiles in
       the database, a profile at a time in order to keep track of the
       actual no. of SEARCH_BEFORE_BEGINNING failures in case the key is
       at or near the beginning of the database so we can accordingly
       adjust the actual no. of profiles retrieved by this no. of
       failures.
     -----------------------------------------------------------------------*/

   if (time_key)
   {
      if (seq_flag == 0 || seq_flag == -1)   /* must retrieve profiles before key */
      {
         start_day = key_day - duration;
      }
      else
      {
         start_day = key_day;
      }
      if (seq_flag == -1)
         end_day = key_day;
      else
         end_day = key_day + duration;
      yd_to_ymdhms_time(start_day,  year_base, &start_time);
      yd_to_ymdhms_time(end_day,  year_base, &end_time);
      if (dbsrch_cnf(TIME_SEARCH, (char *) &start_time) ==  SEARCH_BEYOND_END)
         goto close;
   }
   else
   {
      if (seq_flag == 0 || seq_flag == -1)   /* must retrieve profiles before key */
      {
         nfails = 0;
         for (k = 0; k < nprf && nfails == 0; k++)   /* move nprf profiles backward           */
            if (move_back(&nfails)) goto close;
         totprf -= (nprf-k + nfails);   /* adjust total no. of profiles & key    */
      }
   }

   if (error_found(allocate_arrays(totprf, nbin), "allocating memory for arrays"))
      goto close;

   /*------------------------------------------------------------------------
       Start building .MAT arrays.
     -----------------------------------------------------------------------*/

   U_mat_ptr    = start_mat_array(fp_U   , 'd', "U"      , 'c', nbin);
   V_mat_ptr    = start_mat_array(fp_V   , 'd', "V"      , 'c', nbin);
   W_mat_ptr    = start_mat_array(fp_W   , 'd', "W"      , 'c', nbin);
   E_mat_ptr    = start_mat_array(fp_E   , 'd', "E"      , 'c', nbin);
   PG_mat_ptr   = start_mat_array(fp_PG  , 'd', "PGOOD"  , 'c', nbin);
   AMP_mat_ptr  = start_mat_array(fp_AMP , 'd', "AMP"    , 'c', nbin);
   if (write_raw_amp)
      RAW_AMP_mat_ptr  = start_mat_array(fp_RAW_AMP , 'd', "RAW_AMP"    , 'c', 4*nbin);
   if (write_spectral_width)
      SW_mat_ptr  = start_mat_array(fp_SW , 'd', "SPECTRAL_WIDTH"    , 'c', nbin);
   DEP_mat_ptr  = start_mat_array(fp_DEP , 'd', "DEPTH"  , 'c', nbin);
   PF_mat_ptr   = start_mat_array(fp_PF  , 'd', "PFLAG"  , 'c', nbin);

   i =  0;                         /* i is row index */
   finished = 0;
   do
   {
      if (get_data(i, nbin)) goto close;
      if (move_forward(&ierr)) goto close;
      i++;
      if (ierr == SEARCH_BEYOND_END)
         finished = 1;
      if (time_key)
      {
         n = sizeof(YMDHMS_TIME_TYPE);
         if (dbget_cnf(TIME, (char *) &this_time, &n, "getting time")) goto close;
         if ( TIMDIF( &end_time, &this_time ) > 0 )
            finished = 1;
         if (!finished && i == totprf)
         {
            totprf += nprf;
            if (reallocate_arrays(totprf) == 1)
            {
               finished = 1;
               printf("Out of memory; use a shorter time range.\n");
               goto close;
            }
         }
      }
      else
      {
         if (i >= totprf)
            finished = 1;
      }
   } while (!finished);

   end_mat_array(U_mat_ptr);
   end_mat_array(V_mat_ptr);
   end_mat_array(W_mat_ptr);
   end_mat_array(E_mat_ptr);
   end_mat_array(PG_mat_ptr);
   end_mat_array(AMP_mat_ptr);
   if (write_raw_amp)
      end_mat_array(RAW_AMP_mat_ptr);
   if (write_spectral_width)
      end_mat_array(SW_mat_ptr);
   end_mat_array(DEP_mat_ptr);
   end_mat_array(PF_mat_ptr);

   printf("\n Retrieved %d profiles, %d bins\n", i, nbin);

   /*------------------------------------------------------------------------
       Save other pertinent information.
       The array IBLKPRF is used as a record of the block and profile nos.
       of the profiles included in the matrices.
     ------------------------------------------------------------------------*/
   /* savemat(fp_OTHER, 'i', "KEY_BP" , 1, 2, REAL_ROWS, (char *)key_bp , (char *)NULL); */
   savemat(fp_OTHER, 'i', "NBINS"  , 1, 1, REAL_ROWS, (char *)&nbin  , (char *)NULL);
   savemat(fp_OTHER, 'i', "NPRFS"  , 1, 1, REAL_ROWS, (char *)&i     , (char *)NULL);
   savemat(fp_OTHER, 'i', "IBLKPRF", i, 2, REAL_ROWS, (char *)iblkprf, (char *)NULL);
   savemat(fp_OTHER, 's', "TIME"   , i, 6, REAL_ROWS, (char *)time   , (char *)NULL);
   savemat(fp_OTHER, 'd', "DAYS"   , i, 1, REAL_ROWS, (char *)days   , (char *)NULL);
   savemat(fp_OTHER, 'd', "LON"    , i, 1, REAL_ROWS, (char *)lon    , (char *)NULL);
   savemat(fp_OTHER, 'd', "LAT"    , i, 1, REAL_ROWS, (char *)lat    , (char *)NULL);
   savemat(fp_OTHER, 's', "LGB"    , i, 1, REAL_ROWS, (char *)lgb    , (char *)NULL);
   savemat(fp_OTHER, 's', "MAB"    , i, 1, REAL_ROWS, (char *)mab    , (char *)NULL);
   savemat(fp_OTHER, 'd', "HEADING", i, 1, REAL_ROWS, (char *)heading, (char *)NULL);
   savemat(fp_U    , 'd', "U_MEAN" , 1, i, REAL_ROWS, (char *)U_mean , (char *)NULL);
   savemat(fp_V    , 'd', "V_MEAN" , 1, i, REAL_ROWS, (char *)V_mean , (char *)NULL);
   savemat(fp_U    , 'd', "U_SHIP" , 1, i, REAL_ROWS, (char *)U_ship  , (char *)NULL);
   savemat(fp_V    , 'd', "V_SHIP" , 1, i, REAL_ROWS, (char *)V_ship  , (char *)NULL);
   savemat(fp_W    , 'd', "W_MEAN" , 1, i, REAL_ROWS, (char *)W_mean , (char *)NULL);

close:
   fclose(fp_U);
   fclose(fp_V);
   fclose(fp_W);
   fclose(fp_E);
   fclose(fp_PG);
   fclose(fp_AMP);
   if (write_raw_amp)
      fclose(fp_RAW_AMP);
   if (write_spectral_width)
      fclose(fp_SW);
   fclose(fp_DEP);
   fclose(fp_OTHER);
   fclose(fp_PF);
   dbclose_cnf();
   return(0);
}

/*---------------------------------------------------------------------------
    This function calls DBMOVE to move one step backward in the database.
    If DBMOVE returns with a SEARCH_BEFORE_BEGINNING error, the counter
    nfails is incremented.
  ---------------------------------------------------------------------------*/
int move_back(int *nfails)
{
   int ierr, nsteps = -1;

   DBMOVE(&nsteps, &ierr);
   switch (ierr)
   {
      case 0:  return(0);
      case SEARCH_BEFORE_BEGINNING:
         (*nfails)++;
         printf("\n%% WARNING: Cannot move before first profile in database\n");
         return(0);
      default:
         DBERROR(&ierr, " in DBMOVE\n\n");
         return(1);
   }
}

/*---------------------------------------------------------------------------
    This function calls DBMOVE to move one step forward in the database.
    It updates ierr and also returns 1 only if an error other than
    SEARCH_BEYOND_END has been encountered, 0 otherwise.
  ---------------------------------------------------------------------------*/
int move_forward(int *ierr)
{
   int nsteps = 1;

   DBMOVE(&nsteps, ierr);
   if (*ierr == 0)  return(0);

   if (*ierr == SEARCH_BEYOND_END)
   {
      printf("\n%% WARNING: Reached end of database\n");
      return(0);
   }
   else
   {
      DBERROR(ierr, " in DBMOVE\n\n");
      return(*ierr);
   }
}

int allocate_arrays(int totprf, int nbin)
{
   int nbeams = 1;  /* for averaged quantities */

   if (write_raw_amp)
      nbeams = 4;

   if ((iblkprf = (int *) calloc(totprf, 2 * sizeof(int))) == NULL)
      return(1);
                                             /* totprf x int blk# & prf #  */
   if ((time  = (SHORT  *) calloc(totprf, 6 * sizeof(SHORT))) == NULL) return(1);
   if ((days  = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);
   if ((lon   = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);
   if ((lat   = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);
   if ((lgb   = (SHORT  *) calloc(totprf, sizeof(SHORT)))  == NULL) return(1);
   if ((mab   = (SHORT  *) calloc(totprf, sizeof(SHORT)))  == NULL) return(1);
   if ((heading   = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);

   if ((U_mean = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);
   if ((V_mean = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);
   if ((U_ship  = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);
   if ((V_ship  = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);
   if ((W_mean = (DOUBLE *) calloc(totprf, sizeof(DOUBLE))) == NULL) return(1);

   if ((fdata  = (FLOAT *)  calloc(nbeams * nbin, sizeof(FLOAT)))  == NULL) return(1);
   if ((ddata  = (DOUBLE *) calloc(nbeams * nbin, sizeof(DOUBLE))) == NULL) return(1);
   return(0);
}
int reallocate_arrays(int totprf)
{

   if ((iblkprf = (int *) realloc(iblkprf, totprf * 2 * sizeof(int))) == NULL)
      return(1);
                                             /* totprf x int blk# & prf #  */
   if ((time  = (SHORT  *) realloc(time, totprf * 6 * sizeof(SHORT))) == NULL) return(1);
   if ((days  = (DOUBLE *) realloc(days, totprf * sizeof(DOUBLE))) == NULL) return(1);
   if ((lon   = (DOUBLE *) realloc(lon, totprf * sizeof(DOUBLE))) == NULL) return(1);
   if ((lat   = (DOUBLE *) realloc(lat, totprf * sizeof(DOUBLE))) == NULL) return(1);
   if ((lgb   = (SHORT  *) realloc(lgb, totprf * sizeof(SHORT)))  == NULL) return(1);
   if ((mab   = (SHORT  *) realloc(mab, totprf * sizeof(SHORT)))  == NULL) return(1);
   if ((heading = (DOUBLE *) realloc(heading, totprf * sizeof(DOUBLE))) == NULL) return(1);

   if ((U_mean = (DOUBLE *) realloc(U_mean, totprf * sizeof(DOUBLE))) == NULL) return(1);
   if ((V_mean = (DOUBLE *) realloc(V_mean, totprf * sizeof(DOUBLE))) == NULL) return(1);
   if ((U_ship  = (DOUBLE *) realloc(U_ship,  totprf * sizeof(DOUBLE))) == NULL) return(1);
   if ((V_ship  = (DOUBLE *) realloc(V_ship,  totprf * sizeof(DOUBLE))) == NULL) return(1);
   if ((W_mean = (DOUBLE *) realloc(W_mean, totprf * sizeof(DOUBLE))) == NULL) return(1);

   return(0);
}

/*---------------------------------------------------------------------------
    This function retrieves data from the database.  In the case of time and
    the block-profile index, the data are stored in row i of the appropriate
    global array.  In the case of U, V, and W, the data are de-meaned and
    bad values set to NaN prior to writing them to the appropriate .MAT file.
    In the case of error velocity, amplitude and percent good, bad values are
    set to Nan then immediately written to the appropriate .MAT file.
  ---------------------------------------------------------------------------*/
int get_data(int i, int nbin)
{
   int j;
   unsigned int n, npf;
   UBYTE profile_flags[DEF_NBIN];
   NAVIGATION_TYPE nav;
   ACCESS_VARIABLES_TYPE acc;
   ANCILLARY_2_TYPE ancil2;
   ANCILLARY_1_TYPE ancil1;
   union {double d; long l[2];} NaN;

   NaN.l[0] = NaN_d_0;
   NaN.l[1] = NaN_d_1;

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

   n = sizeof(YMDHMS_TIME_TYPE);
   if (dbget_cnf(TIME, (char *) (time+i*6), &n, "getting time")) return(1);
   if (!year_base) year_base = *(time+i*6);  /* year from first profile only */
   days[i] = year_day((YMDHMS_TIME_TYPE *) (time+i*6), year_base);

   n = sizeof(NAVIGATION_TYPE);
   if (dbget_cnf(NAVIGATION, (char *) &nav, &n,
      "getting navigation")) /* return(1); */
   {
      nav.longitude = 0.0;   /* Change by EF, 93/02/10, to work with LADCP data. */
      nav.latitude  = 0.0;
   }
   if (nav.longitude == 0.0 && nav.latitude == 0.0)
      lon[i] = lat[i] = NaN.d;
   else
   {
      lon[i] = (nav.longitude < ADJ_BADFLOAT) ? nav.longitude : NaN.d;
      lat[i] = (nav.latitude  < ADJ_BADFLOAT) ? nav.latitude  : NaN.d;
   }

   n = sizeof(ACCESS_VARIABLES_TYPE);
   if (dbget_cnf(ACCESS_VARIABLES, (char *) &acc, &n, "getting access variables")) return(1);
   lgb[i] = acc.last_good_bin;
   U_ship[i] = acc.U_ship_absolute;
   V_ship[i] = acc.V_ship_absolute;
   if (U_ship[i] >= ADJ_BADFLOAT) U_ship[i] = NaN.d;
   if (V_ship[i] >= ADJ_BADFLOAT) V_ship[i] = NaN.d;

   n = sizeof(ANCILLARY_2_TYPE);
   if (dbget_cnf(ANCILLARY_2, (char *) &ancil2, &n, "getting ancillary_2")) return(1);
   mab[i] = ancil2.max_amp_bin;

   n = sizeof(ANCILLARY_1_TYPE);
   if (dbget_cnf(ANCILLARY_1, (char *) &ancil1, &n, "getting ancillary_1")) return(1);
   heading[i] = ancil1.mn_heading;


   for (j = 0; j < nbin; j++) profile_flags[j] = 0;
   npf = check_dbget(PROFILE_FLAGS, (char *) profile_flags, nbin,
      "getting profile flags");
   if (npf > 0)
      for (j = 0; j < npf; j++) ddata[j] = (double) profile_flags[j];
   add_to_mat_array(PF_mat_ptr, (char *) ddata);

   for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
   n = check_dbget_f(DEPTH, fdata, nbin, "getting depth");
   tonan_f( ddata, fdata, nbin );
   add_to_mat_array(DEP_mat_ptr, (char *) ddata);

   for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
   n = check_dbget_f(U, fdata, nbin, "getting U velocity");
   /* if (npf > 0) flag_data(fdata, profile_flags, nbin, 0xFF); */
   tonan_f( ddata, fdata, nbin );  /* jr: interchanged 93/10 to keep "raw" */
   U_mean[i] = subtract_reference(fdata, n, REF_BIN_RANGE);
   if (U_mean[i] >= ADJ_BADFLOAT) U_mean[i] = NaN.d;
   add_to_mat_array(U_mat_ptr, (char *) ddata);

   for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
   n = check_dbget_f(V, fdata, nbin, "getting V velocity");
   /* if (npf > 0) flag_data(fdata, profile_flags, nbin, 0xFF); */
   tonan_f( ddata, fdata, nbin );
   V_mean[i] = subtract_reference(fdata, n, REF_BIN_RANGE);
   if (V_mean[i] >= ADJ_BADFLOAT) V_mean[i] = NaN.d;
   add_to_mat_array(V_mat_ptr, (char *) ddata);

   for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
   n = check_dbget_f(W, fdata, nbin, "getting W velocity");
   /* if (npf > 0) flag_data(fdata, profile_flags, nbin, 0xFF); */
   tonan_f( ddata, fdata, nbin );
   W_mean[i] = subtract_reference(fdata, n, REF_BIN_RANGE);
   if (W_mean[i] >= ADJ_BADFLOAT) W_mean[i] = NaN.d;
   add_to_mat_array(W_mat_ptr, (char *) ddata);

   for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
   n = check_dbget_f(ERROR_VEL, fdata, nbin, "getting error velocity");
   /* if (npf > 0) flag_data(fdata, profile_flags, nbin, 0xFF); */
   tonan_f( ddata, fdata, nbin);
   add_to_mat_array(E_mat_ptr, (char *) ddata);

   for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
   n = check_dbget_f(PERCENT_GOOD, fdata, nbin, "getting percent good");
   tonan_f( ddata, fdata, nbin );
   add_to_mat_array(PG_mat_ptr, (char *) ddata);

   for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
   n = check_dbget_f(AMP_SOUND_SCAT, fdata, nbin, "getting amplitude");
   tonan_f( ddata, fdata, nbin );
   add_to_mat_array(AMP_mat_ptr, (char *) ddata);

   if (write_spectral_width)
   {
      for (j = 0; j < nbin; j++) fdata[j] = BADFLOAT;
      n = check_dbget_f(SPECTRAL_WIDTH, fdata, nbin, "getting spectral width");
      tonan_f( ddata, fdata, nbin );
      add_to_mat_array(SW_mat_ptr, (char *) ddata);
   }

   if (write_raw_amp)
   {
      for (j = 0; j < 4*nbin; j++) fdata[j] = BADFLOAT;
      n = check_dbget_f(RAW_AMP, fdata, 4*nbin, "getting raw amplitude");
      tonan_f( ddata, fdata, 4*nbin );
      add_to_mat_array(RAW_AMP_mat_ptr, (char *) ddata);
   }

   return(0);
}

