int uf_into_radar(UF_buffer uf, Radar **the_radar)
{
  
/* Missing data flag : -32768 when a signed short. */
#define UF_NO_DATA 0X8000
  
  /* Any convensions may be observed, however, Radial Velocity must be VE. */
  /* Typically:
   *    DM = Reflectivity (dB(mW)).
   *    DZ = Reflectivity (dBZ).
   *    VR = Radial Velocity.
   *    CZ = Corrected Reflectivity. (Quality controlled: AP removed, etc.)
   *    SW = Spectrum Width.
   *    DR = Differential Reflectivity.
   *    XZ = X-band Reflectivity.
   *
   * These fields may appear in any order in the UF file.
   *
   * RETURN:
   *   UF_DONE if we're done with the UF ingest.
   *   UF_MORE if we need more UF data.
   */
  
  /* These are pointers to various locations within the UF buffer 'uf'.
   * They are used to index the different components of the UF structure in
   * a manor consistant with the UF documentation.  For instance, uf_ma[1]
   * will be equivalenced to the second word (2 bytes/each) of the UF
   * buffer.
   */
  short *uf_ma;  /* Mandatory header block. */
  short *uf_lu;  /* Local Use header block.  */
  short *uf_dh;  /* Data header.  */
  short *uf_fh;  /* Field header. */
  short *uf_data; /* Data. */
  
  /* The length of each header. */
  int len_data, len_lu;
  
  int current_fh_index; 
  float scale_factor;
  
  int nfields, isweep, ifield, iray, i, m;
  static int pulled_time_from_first_ray = 0;
  char *field_type; /* For printing the field type upon error. */
	short proj_name[4];
  Ray *ray;
  Sweep *sweep;
  Radar *radar;
  float x;
  short missing_data;
  Volume *new_volume;
  int nbins;
  extern int rsl_qfield[];
  extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */
  extern int rsl_qsweep_max;

  radar = *the_radar;

/*
 * The organization of the Radar structure is by volumes, then sweeps, then
 * rays, then gates.  This is different from the UF file organization.
 * The UF format is sweeps, rays, then gates for all field types (volumes).
 */


/* Set up all the UF pointers. */
  uf_ma = uf;
  uf_lu = uf + uf_ma[3] - 1;
  uf_dh = uf + uf_ma[4] - 1;

  nfields =  uf_dh[0];
  isweep = uf_ma[9] - 1;

  if (rsl_qsweep != NULL) {
	if (isweep > rsl_qsweep_max) return UF_DONE;
	if (rsl_qsweep[isweep] == 0) return UF_MORE;
  }


/* Here is a sticky part.  We must make sure that if we encounter any
 * additional fields that were not previously present, that we are able
 * to load them.  This will require us to copy the entire radar structure
 * and whack off the old one.  But, we must be sure that it really is a
 * new field.  This is not so trivial as a couple of lines of code; I will
 * have to think about this a little bit more.  See STICKYSOLVED below.
 */
#ifdef STICKYSOLVED
  if (radar == NULL) radar = RSL_new_radar(nfields);
  /* Sticky solution here. */
#else
  if (radar == NULL) {
	radar = RSL_new_radar(MAX_RADAR_VOLUMES);
	*the_radar = radar;
	pulled_time_from_first_ray = 0;
	for (i=0; i<MAX_RADAR_VOLUMES; i++)
	  if (rsl_qfield[i]) /* See RSL_select_fields in volume.c */
		radar->v[i] = RSL_new_volume(20);
  }
  
#endif
/* For LITTLE ENDIAN:
 * WE "UNSWAP" character strings.  Because there are so few of them,
 * it is easier to catch them here.  The entire UF buffer is swapped prior
 * to entry to here, therefore, undo-ing these swaps; sets the
 * character strings right.
 */

  for (i=0; i<nfields; i++) {
	if (little_endian()) swap_2_bytes(&uf_dh[3+2*i]); /* Unswap. */
	if (strncmp((char *)&uf_dh[3+2*i], "DZ", 2) == 0) ifield = DZ_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "VR", 2) == 0) ifield = VR_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "SW", 2) == 0) ifield = SW_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "CZ", 2) == 0) ifield = CZ_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "UZ", 2) == 0) ifield = ZT_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "ZT", 2) == 0) ifield = ZT_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "DR", 2) == 0) ifield = DR_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "ZD", 2) == 0) ifield = ZD_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "DM", 2) == 0) ifield = DM_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "RH", 2) == 0) ifield = RH_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "PH", 2) == 0) ifield = PH_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "XZ", 2) == 0) ifield = XZ_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "CD", 2) == 0) ifield = CD_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "MZ", 2) == 0) ifield = MZ_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "MD", 2) == 0) ifield = MD_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "ZE", 2) == 0) ifield = ZE_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "VE", 2) == 0) ifield = VE_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "KD", 2) == 0) ifield = KD_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "TI", 2) == 0) ifield = TI_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "DX", 2) == 0) ifield = DX_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "CH", 2) == 0) ifield = CH_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "AH", 2) == 0) ifield = AH_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "CV", 2) == 0) ifield = CV_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "AV", 2) == 0) ifield = AV_INDEX;
	else if (strncmp((char *)&uf_dh[3+2*i], "SQ", 2) == 0) ifield = SQ_INDEX;
	else { /* etc.  DON'T know how to handle this yet. */
	  field_type = (char *)&uf_dh[3+2*i];
	  fprintf(stderr, "Unknown field type %c%c\n", (char)field_type[0], (char)field_type[1]);
	  continue;
	}
	switch (ifield) {
	case DZ_INDEX: f = DZ_F; invf = DZ_INVF; break;
	case VR_INDEX: f = VR_F; invf = VR_INVF; break;
	case SW_INDEX: f = SW_F; invf = SW_INVF; break;
	case CZ_INDEX: f = CZ_F; invf = CZ_INVF; break;
	case ZT_INDEX: f = ZT_F; invf = ZT_INVF; break;
	case DR_INDEX: f = DR_F; invf = DR_INVF; break;
	case ZD_INDEX: f = ZD_F; invf = ZD_INVF; break;
	case DM_INDEX: f = DM_F; invf = DM_INVF; break;
	case RH_INDEX: f = RH_F; invf = RH_INVF; break;
	case PH_INDEX: f = PH_F; invf = PH_INVF; break;
	case XZ_INDEX: f = XZ_F; invf = XZ_INVF; break;
	case CD_INDEX: f = CD_F; invf = CD_INVF; break;
	case MZ_INDEX: f = MZ_F; invf = MZ_INVF; break;
	case MD_INDEX: f = MD_F; invf = MD_INVF; break;
	case ZE_INDEX: f = ZE_F; invf = ZE_INVF; break;
	case VE_INDEX: f = VE_F; invf = VE_INVF; break;
	case KD_INDEX: f = KD_F; invf = KD_INVF; break;
	case TI_INDEX: f = TI_F; invf = TI_INVF; break;
	case DX_INDEX: f = DX_F; invf = DX_INVF; break;
	case CH_INDEX: f = CH_F; invf = CH_INVF; break;
	case AH_INDEX: f = AH_F; invf = AH_INVF; break;
	case CV_INDEX: f = CV_F; invf = CV_INVF; break;
	case AV_INDEX: f = AV_F; invf = AV_INVF; break;
	case SQ_INDEX: f = SQ_F; invf = SQ_INVF; break;
	default: f = DZ_F; invf = DZ_INVF; break;
	}

	/* Do we place the data into this volume? */
	if (radar->v[ifield] == NULL) continue; /* Nope. */

	if (isweep >= radar->v[ifield]->h.nsweeps) { /* Exceeded sweep limit.
						      * Allocate more sweeps.
						      * Copy all previous sweeps.
						      */
	  if (radar_verbose_flag)
		fprintf(stderr,"Exceeded sweep allocation of %d. Adding 20 more.\n", isweep);
	  new_volume = RSL_new_volume(radar->v[ifield]->h.nsweeps+20);
	  new_volume = copy_sweeps_into_volume(new_volume, radar->v[ifield]);
	  radar->v[ifield] = new_volume;
	}

	if (radar->v[ifield]->sweep[isweep] == NULL) {
	  if (radar_verbose_flag)
		fprintf(stderr,"Allocating new sweep for field %d, isweep %d\n", ifield, isweep);
	  radar->v[ifield]->sweep[isweep] = RSL_new_sweep(1000);
	  radar->v[ifield]->sweep[isweep]->h.nrays = 0; /* Increment this for each
							 * ray encountered.
							 */
	  radar->v[ifield]->h.f = f;
	  radar->v[ifield]->h.invf = invf;
	  radar->v[ifield]->sweep[isweep]->h.f = f;
	  radar->v[ifield]->sweep[isweep]->h.invf = invf;
		radar->v[ifield]->sweep[isweep]->h.sweep_num = uf_ma[9];
		radar->v[ifield]->sweep[isweep]->h.elev = uf_ma[35] / 64.0;
	}
	
	

	current_fh_index = uf_dh[4+2*i];
	uf_fh = uf + current_fh_index - 1;
	sweep =	radar->v[ifield]->sweep[isweep];
	iray = 	sweep->h.nrays;
	nbins = uf_fh[5];
	radar->v[ifield]->sweep[isweep]->ray[iray] = RSL_new_ray(nbins);
	ray   =	radar->v[ifield]->sweep[isweep]->ray[iray];
	sweep->h.nrays += 1;


	if (ray) {
		/* 
		 * ---- Beginning of MANDATORY HEADER BLOCK.
		 */
	  ray->h.ray_num = uf_ma[7];
	  if (little_endian()) swap2(&uf_ma[10], 8);
	  memcpy(radar->h.radar_name, &uf_ma[10], 8);
	  if (little_endian()) swap2(&uf_ma[10], 8/2);
	  memcpy(radar->h.name, &uf_ma[14], 8);
	  if (little_endian()) swap2(&uf_ma[14], 8/2);
		
      /* All components of lat/lon are the same sign.  If not, then
       * what ever wrote the UF was in error.  A simple RSL program
       * can repair the damage, however, not here.
       */
	  ray->h.lat = uf_ma[18] + uf_ma[19]/60.0 + uf_ma[20]/64.0/3600;
	  ray->h.lon = uf_ma[21] + uf_ma[22]/60.0 + uf_ma[23]/64.0/3600;
	  ray->h.alt      = uf_ma[24];
	  ray->h.year     = uf_ma[25];
	  if (ray->h.year < 1900) {
	    ray->h.year += 1900;
	    if (ray->h.year < 1980) ray->h.year += 100; /* Year >= 2000. */
	  }
	  ray->h.month    = uf_ma[26];
	  ray->h.day      = uf_ma[27];
	  ray->h.hour     = uf_ma[28];
	  ray->h.minute   = uf_ma[29];
	  ray->h.sec      = uf_ma[30];
	  ray->h.azimuth  = uf_ma[32] / 64.0;

	  /* If Local Use Header is present and contains azimuth, use that
	   * azimuth for VR and SW. This is for WSR-88D, which runs separate
	   * scans for DZ and VR/SW at the lower elevations, which means DZ
	   * VR/SW and have different azimuths in the "same" ray.
	   */
	  len_lu = uf_ma[4] - uf_ma[3];
	  if (len_lu == 2 && (ifield == VR_INDEX || ifield == SW_INDEX)) {
	      if (strncmp(uf_lu,"ZA",2) == 0 || strncmp(uf_lu,"AZ",2) == 0)
		  ray->h.azimuth = uf_lu[1] / 64.0;
	  }
	  if (ray->h.azimuth < 0.) ray->h.azimuth += 360.; /* make it 0 to 360. */
	  ray->h.elev     = uf_ma[33] / 64.0;
	  ray->h.elev_num = sweep->h.sweep_num;
	  ray->h.fix_angle  = sweep->h.elev = uf_ma[35] / 64.0;
	  ray->h.azim_rate  = uf_ma[36] / 64.0;
	  ray->h.sweep_rate = ray->h.azim_rate * (60.0/360.0);
	  missing_data      = uf_ma[44];

	  if (pulled_time_from_first_ray == 0) {
	    radar->h.height = uf_ma[24];
		radar->h.latd = uf_ma[18];
		radar->h.latm = uf_ma[19];
		radar->h.lats = uf_ma[20] / 64.0;
		radar->h.lond = uf_ma[21];
		radar->h.lonm = uf_ma[22];
		radar->h.lons = uf_ma[23] / 64.0;
		radar->h.year  = ray->h.year;
		radar->h.month = ray->h.month;
		radar->h.day   = ray->h.day;
		radar->h.hour  = ray->h.hour;
		radar->h.minute = ray->h.minute;
		radar->h.sec    = ray->h.sec;
		strcpy(radar->h.radar_type, "uf");
		pulled_time_from_first_ray = 1;
	  }
	  /*
	   * ---- End of MANDATORY HEADER BLOCK.
	   */
	  
	  /* ---- Optional header used for MCTEX files. */
		/* If this is a MCTEX file, the first 4 words following the
			 mandatory header contain the string 'MCTEX'. */
	  memcpy(proj_name, (short *)(uf + uf_ma[2] - 1), 8);
	  if (little_endian()) swap2(proj_name, 4);


	  /* ---- Local Use Header (if present) was checked during Mandatory
	   *      Header processing above.
	   */
	  
	  /* ---- Begining of FIELD HEADER. */
	  uf_fh = uf+current_fh_index - 1;
	  scale_factor      = uf_fh[1];
	  ray->h.range_bin1 = uf_fh[2] * 1000.0 + uf_fh[3]; 
	  ray->h.gate_size  = uf_fh[4];

	  ray->h.nbins      = uf_fh[5];
	  ray->h.pulse_width  = uf_fh[6]/(RSL_SPEED_OF_LIGHT/1.0e6);

		if (strncmp((char *)proj_name, "MCTEX", 5) == 0)  /* MCTEX? */
		{
			/* The beamwidth values are not correct in Mctex UF files. */
			ray->h.beam_width = 1.0;
			sweep->h.beam_width = ray->h.beam_width;
			sweep->h.horz_half_bw = ray->h.beam_width/2.0;
			sweep->h.vert_half_bw = ray->h.beam_width/2.0;
		}
		else  /* Not MCTEX */
		{
			ray->h.beam_width = uf_fh[7] / 64.0;
			sweep->h.beam_width = uf_fh[7]  / 64.0;
			sweep->h.horz_half_bw = uf_fh[7] / 128.0; /* DFF 4/4/95 */
			sweep->h.vert_half_bw = uf_fh[8] / 128.0; /* DFF 4/4/95 */
		}			
		/*		fprintf (stderr, "uf_fh[7] = %d, [8] = %d\n", (int)uf_fh[7], (int)uf_fh[8]); */
		if((int)uf_fh[7] == -32768) {
			ray->h.beam_width     = 1;
			sweep->h.beam_width   = 1;
			sweep->h.horz_half_bw = .5;
			sweep->h.vert_half_bw = .5;
		}
		  
	  ray->h.frequency    = uf_fh[9]  / 64.0;
	  ray->h.wavelength   = uf_fh[11] / 64.0 / 100.0;  /* cm to m. */
	  ray->h.pulse_count  = uf_fh[12];
	  if (ifield == DZ_INDEX || ifield == ZT_INDEX) {
	    radar->v[ifield]->h.calibr_const  = uf_fh[16] / 100.0;
						    /* uf value scaled by 100 */
	  }
	  else {
	    radar->v[ifield]->h.calibr_const  = 0.0;
	  }
	  if (uf_fh[17] == (short)UF_NO_DATA) x = 0;
	  else x = uf_fh[17] / 1000000.0;  /* PRT in seconds. */
	  if (x != 0) {
	    ray->h.prf = 1/x;
	    ray->h.unam_rng = RSL_SPEED_OF_LIGHT / (2.0 * ray->h.prf * 1000.0);
	  }
	  else {
	    ray->h.prf = 0.0;
	    ray->h.unam_rng = 0.0;
	  }

	  if (VR_INDEX == ifield || VE_INDEX == ifield) {
		ray->h.nyq_vel = uf_fh[19] / scale_factor;
	  }
	  
	  /* ---- End of FIELD HEADER. */
	  
	  ray->h.f = f;
	  ray->h.invf = invf;

	  /* ---- Begining of FIELD DATA. */
	  uf_data = uf+uf_fh[0] - 1;

	  len_data = ray->h.nbins;  /* Known because of RSL_new_ray. */
	  for (m=0; m<len_data; m++) {
		if (uf_data[m] == (short)UF_NO_DATA)
		  ray->range[m] = invf(BADVAL); /* BADVAL */
		else {
		  if(uf_data[m] == missing_data)
			ray->range[m] = invf(NOECHO); /* NOECHO */
		  else
			ray->range[m] = invf((float)uf_data[m]/scale_factor);
		}
	  }
	}
  }
  return UF_MORE;
}
Radar *RSL_wsr88d_to_radar(char *infile, char *call_or_first_tape_file)
/*
 * Gets all volumes from the nexrad file.  Input file is 'infile'.
 * Site information is extracted from 'call_or_first_tape_file'; this
 * is typically a disk file called 'nex.file.1'.
 *
 *  -or-
 *
 * Uses the string in 'call_or_first_tape_file' as the 4 character call sign
 * for the sight.  All UPPERCASE characters.  Normally, this call sign
 * is extracted from the file 'nex.file.1'.
 *
 * Returns a pointer to a Radar structure; that contains the different
 * Volumes of data.
 */
{
  Radar *radar;
  Volume *new_volume;
  Wsr88d_file *wf;
  Wsr88d_sweep wsr88d_sweep;
  Wsr88d_file_header wsr88d_file_header;
  Wsr88d_tape_header wsr88d_tape_header;
  int n;
  int nsweep;
  int i;
  int iv;
  int nvolumes;
  int volume_mask[] = {WSR88D_DZ, WSR88D_VR, WSR88D_SW};
  char *field_str[] = {"Reflectivity", "Velocity", "Spectrum width"};
  Wsr88d_site_info *sitep;
  char site_id_str[5];
  char *the_file;
  int expected_msgtype = 0;
  char version[8];

  extern int rsl_qfield[]; /* See RSL_select_fields in volume.c */
  extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */
  extern int rsl_qsweep_max;

  Radar *load_wsr88d_m31_into_radar(Wsr88d_file *wf);

  sitep = NULL;
/* Determine the site quasi automatically.  Here is the procedure:
 *    1. Determine if we have a call sign.
 *    2. Try reading 'call_or_first_tape_file' from disk.  This is done via
 *       wsr88d_read_tape_header.
 *    3. If no valid site info, abort.
 */
  if (call_or_first_tape_file == NULL) {
	fprintf(stderr, "wsr88d_to_radar: No valid site ID info provided.\n");
	return(NULL);
  }	else if (strlen(call_or_first_tape_file) == 4)
	sitep =  wsr88d_get_site(call_or_first_tape_file);
  else if (strlen(call_or_first_tape_file) == 0) {
	fprintf(stderr, "wsr88d_to_radar: No valid site ID info provided.\n");
	return(NULL);
  }  

  if (sitep == NULL)
	if (wsr88d_read_tape_header(call_or_first_tape_file, &wsr88d_tape_header) > 0) {
	  memcpy(site_id_str, wsr88d_tape_header.site_id, 4);
	  sitep  = wsr88d_get_site(site_id_str);
	}
  if (sitep == NULL) {
	  fprintf(stderr,"wsr88d_to_radar: No valid site ID info found.\n");
		return(NULL);
  }
	if (radar_verbose_flag)
	  fprintf(stderr,"SITE: %c%c%c%c\n", sitep->name[0], sitep->name[1],
			 sitep->name[2], sitep->name[3]);

  
  memset(&wsr88d_sweep, 0, sizeof(Wsr88d_sweep)); /* Initialize to 0 a 
												   * heavily used variable.
												   */

/* 1. Open the input wsr88d file. */
  if (infile == NULL) the_file = "stdin";  /* wsr88d.c understands this to
											* mean read from stdin.
											*/
  else the_file = infile;

  if ((wf = wsr88d_open(the_file)) == NULL) {
	wsr88d_perror(the_file);
	return NULL;
  }



/* 2. Read wsr88d headers. */
  /* Return # bytes, 0 or neg. on fail. */
  n = wsr88d_read_file_header(wf, &wsr88d_file_header);
  /*
   * Get the expected digital radar message type based on version string
   * from the Archive II header.  The message type is 31 for Build 10, and 1
   * for prior builds.  Note that we consider AR2V0001 to be message type 1,
   * because it has been in the past, but with Build 10 this officially
   * becomes the version number for Evansville (KVWX), which will use message
   * type 31.  This could be a problem if RSL is used to process KVWX.
   */
  if (n > 0) {
      strncpy(version, wsr88d_file_header.title.filename, 8);
      if (strncmp(version,"AR2V0004",8) == 0 ||
	      strncmp(version,"AR2V0003",8) ==0 ||
	      strncmp(version,"AR2V0002",8) == 0) {
	  expected_msgtype = 31;
      }
      else if (strncmp(version,"ARCHIVE2",8) == 0 ||
	      strncmp(version,"AR2V0001",8) == 0) {
	  expected_msgtype = 1;
      }
  }

  if (n <= 0 || expected_msgtype == 0) {
      fprintf(stderr,"RSL_wsr88d_to_radar: ");
      if (n <= 0)
	  fprintf(stderr,"wsr88d_read_file_header failed\n");
      else
	  fprintf(stderr,"Archive II header contains unknown version "
		  ": '%s'\n", version);
      wsr88d_close(wf);
      free(radar);
      return NULL;
  }

  if (radar_verbose_flag)
	print_head(wsr88d_file_header);


  if (expected_msgtype == 31) {

      /* Get radar for message type 31. */
      nvolumes = 6;
      radar = load_wsr88d_m31_into_radar(wf);
      if (radar == NULL) return NULL;
  }
  else {
      /* Get radar for message type 1. */
      nvolumes = 3;
      /* Allocate all Volume pointers. */
      radar = RSL_new_radar(MAX_RADAR_VOLUMES);
      if (radar == NULL) return NULL;

    /* Clear the sweep pointers. */
      clear_sweep(&wsr88d_sweep, 0, MAX_RAYS_IN_SWEEP);

    /* Allocate a maximum of 30 sweeps for the volume. */
    /* Order is important.  WSR88D_DZ, WSR88D_VR, WSR88D_SW, is 
     * assigned to the indexes DZ_INDEX, VR_INDEX and SW_INDEX respectively.
     */ 

      for (iv=0; iv<nvolumes; iv++)
	    if (rsl_qfield[iv]) radar->v[iv] = RSL_new_volume(20);


    /* LOOP until EOF */
      nsweep = 0;
      for (;(n = wsr88d_read_sweep(wf, &wsr88d_sweep)) > 0; nsweep++) {
	    if (rsl_qsweep != NULL) {
	      if (nsweep > rsl_qsweep_max) break;
	      if (rsl_qsweep[nsweep] == 0) continue;
	    }
	    if (radar_verbose_flag)  
	    fprintf(stderr,"Processing for SWEEP # %d\n", nsweep);

	      /*  wsr88d_print_sweep_info(&wsr88d_sweep); */
	    
	    for (iv=0; iv<nvolumes; iv++) {
	      if (rsl_qfield[iv]) {
		    /* Exceeded sweep limit.
		     * Allocate more sweeps.
		     * Copy all previous sweeps.
		     */
		    if (nsweep >= radar->v[iv]->h.nsweeps) {
		      if (radar_verbose_flag)
			    fprintf(stderr,"Exceeded sweep allocation of %d. "
				    "Adding 20 more.\n", nsweep);
		      new_volume = RSL_new_volume(radar->v[iv]->h.nsweeps+20);
		      new_volume = copy_sweeps_into_volume(new_volume, radar->v[iv]);
		      radar->v[iv] = new_volume;
		    }
		    if (wsr88d_load_sweep_into_volume(wsr88d_sweep,
			   radar->v[iv], nsweep, volume_mask[iv]) != 0) {
		      RSL_free_radar(radar);
		      return NULL;
		    }
	      }
	    }
	    if (nsweep == 0) {
		  /* Get Volume Coverage Pattern number for radar header. */
		  i=0;
		  while (i < MAX_RAYS_IN_SWEEP && wsr88d_sweep.ray[i] == NULL) i++;
		  if (i < MAX_RAYS_IN_SWEEP) radar->h.vcp = wsr88d_get_volume_coverage(
		    wsr88d_sweep.ray[i]);
		}

	    free_and_clear_sweep(&wsr88d_sweep, 0, MAX_RAYS_IN_SWEEP);
      }

      for (iv=0; iv<nvolumes; iv++) {
	    if (rsl_qfield[iv]) {
	      radar->v[iv]->h.type_str = strdup(field_str[iv]);
	      radar->v[iv]->h.nsweeps = nsweep;
	    }
      }
  }
  wsr88d_close(wf);

/*
 * Here we will assign the Radar_header information.  Take most of it
 * from an existing volume's header.  
 */
  radar_load_date_time(radar);  /* Magic :-) */

	radar->h.number = sitep->number;
	memcpy(&radar->h.name, sitep->name, sizeof(sitep->name));
	memcpy(&radar->h.radar_name, sitep->name, sizeof(sitep->name)); /* Redundant */
	memcpy(&radar->h.city, sitep->city, sizeof(sitep->city));
	memcpy(&radar->h.state, sitep->state, sizeof(sitep->state));
	strcpy(radar->h.radar_type, "wsr88d");
	radar->h.latd = sitep->latd;
	radar->h.latm = sitep->latm;
	radar->h.lats = sitep->lats;
	if (radar->h.latd < 0) { /* Degree/min/sec  all the same sign */
	  radar->h.latm *= -1;
	  radar->h.lats *= -1;
	}
	radar->h.lond = sitep->lond;
	radar->h.lonm = sitep->lonm;
	radar->h.lons = sitep->lons;
	if (radar->h.lond < 0) { /* Degree/min/sec  all the same sign */
	  radar->h.lonm *= -1;
	  radar->h.lons *= -1;
	}
	radar->h.height = sitep->height;
	radar->h.spulse = sitep->spulse;
	radar->h.lpulse = sitep->lpulse;
		
  radar = RSL_prune_radar(radar);
  return radar;
}
Radar *RSL_wsr88d_to_radar(char *infile, char *call_or_first_tape_file)
/*
 * Gets all volumes from the nexrad file.  Input file is 'infile'.
 * Site information is extracted from 'call_or_first_tape_file'; this
 * is typically a disk file called 'nex.file.1'.
 *
 *  -or-
 *
 * Uses the string in 'call_or_first_tape_file' as the 4 character call sign
 * for the sight.  All UPPERCASE characters.  Normally, this call sign
 * is extracted from the file 'nex.file.1'.
 *
 * Returns a pointer to a Radar structure; that contains the different
 * Volumes of data.
 */
{
  Radar *radar;
  Volume *new_volume;
  Wsr88d_file *wf;
  Wsr88d_sweep wsr88d_sweep;
  Wsr88d_file_header wsr88d_file_header;
  Wsr88d_tape_header wsr88d_tape_header;
  int n;
  int nsweep;
  int iv;
  int nvolumes;
  int volume_mask[] = {WSR88D_DZ, WSR88D_VR, WSR88D_SW};
  char *field_str[] = {"Reflectivity", "Velocity", "Spectrum width"};
  Wsr88d_site_info *sitep;
  char site_id_str[5], failid[]="KFTG";
  char *the_file;

  extern int rsl_qfield[]; /* See RSL_select_fields in volume.c */
  extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */
  extern int rsl_qsweep_max;

  /* initialize site id to a failsafe value */
 wsr88d_set_station_id(failid, -9999.0, -9999.0, -9999.0);

  sitep = NULL;
/* Determine the site quasi automatically.  Here is the procedure:
 *    1. Determine if we have a call sign.
 *    2. Try reading 'call_or_first_tape_file' from disk.  This is done via
 *       wsr88d_read_tape_header.
 *    3. If no valid site info, abort.
 */
  if (call_or_first_tape_file == NULL) {
	fprintf(stderr, "wsr88d_to_radar: No valid site ID info provided.\n");
	return(NULL);
  }	else if (strlen(call_or_first_tape_file) == 4)
	sitep =  wsr88d_get_site(call_or_first_tape_file);
  else if (strlen(call_or_first_tape_file) < 3) {
	/*fprintf(stderr, "wsr88d_to_radar: No valid site ID info provided, using default.\n");
	strcpy(site_id_str,failid);
        sitep = wsr88d_get_site(site_id_str); -*enough for now. Message 31 contains ICAO and lat/lon */
	/*return(NULL);*/
  }  

  if (sitep == NULL)
	if (wsr88d_read_tape_header(call_or_first_tape_file, &wsr88d_tape_header) > 0) {
	  memcpy(site_id_str, wsr88d_tape_header.site_id, 4);
	  sitep  = wsr88d_get_site(site_id_str);
	}
  /*if (sitep == NULL) {
	  fprintf(stderr,"wsr88d_to_radar: No valid site ID info found.\n");
		return(NULL);
  }
	if (radar_verbose_flag)
	  fprintf(stderr,"SITE: %c%c%c%c\n", sitep->name[0], sitep->name[1],
			 sitep->name[2], sitep->name[3]);*/

  
  memset(&wsr88d_sweep, 0, sizeof(Wsr88d_sweep)); /* Initialize to 0 a 
												   * heavily used variable.
												   */

/* 1. Open the input wsr88d file. */
  if (infile == NULL) the_file = "stdin";  /* wsr88d.c understands this to
											* mean read from stdin.
											*/
  else the_file = infile;

  if ((wf = wsr88d_open(the_file)) == NULL) {
	wsr88d_perror(the_file);
	return NULL;
  }

  nvolumes = 3;
  radar = RSL_new_radar(MAX_RADAR_VOLUMES); /* Allocate all Volume pointers. */
  if (radar == NULL) return NULL;



/* 2. Read wsr88d headers. */
  /* Return # bytes, 0 or neg. on fail. */
  n = wsr88d_read_file_header(wf, &wsr88d_file_header);
  if (n <= 0 ||
	  (strncmp(wsr88d_file_header.title.filename, "ARCHIVE2.", 9) != 0 &&
	   strncmp(wsr88d_file_header.title.filename, "AR2V000", 7) != 0))
  {
	wsr88d_close(wf);
	free(radar);
	return NULL;
  }


  if (radar_verbose_flag)
	print_head(wsr88d_file_header);

/* Clear the sweep pointers. */
  clear_sweep(&wsr88d_sweep, 0, MAX_RAYS_IN_SWEEP);

/* Allocate a maximum of 30 sweeps for the volume. */
/* Order is important.  WSR88D_DZ, WSR88D_VR, WSR88D_SW, is 
 * assigned to the indexes DZ_INDEX, VR_INDEX and SW_INDEX respectively.
 */ 

  for (iv=0; iv<nvolumes; iv++)
	if (rsl_qfield[iv]) radar->v[iv] = RSL_new_volume(20);


/* LOOP until EOF */
  nsweep = 0;
  for (;(n = wsr88d_read_sweep(wf, &wsr88d_sweep)) > 0; nsweep++) {
	if (rsl_qsweep != NULL) {
	  if (nsweep > rsl_qsweep_max) break;
	  if (rsl_qsweep[nsweep] == 0) continue;
	}
	if (radar_verbose_flag)  
	fprintf(stderr,"Processing for SWEEP # %d\n", nsweep);

	  /*  wsr88d_print_sweep_info(&wsr88d_sweep); */
	
	for (iv=0; iv<nvolumes; iv++) {
	  if (rsl_qfield[iv]) {
		if (nsweep >= radar->v[iv]->h.nsweeps) { /* Exceeded sweep limit.
												  * Allocate more sweeps.
												  * Copy all previous sweeps.
												  */
		  if (radar_verbose_flag)
			fprintf(stderr,"Exceeded sweep allocation of %d. Adding 20 more.\n", nsweep);
		  new_volume = RSL_new_volume(radar->v[iv]->h.nsweeps+20);
		  new_volume = copy_sweeps_into_volume(new_volume, radar->v[iv]);
		  radar->v[iv] = new_volume;
		}
		if (wsr88d_load_sweep_into_volume(wsr88d_sweep,
										  radar->v[iv], nsweep,
										  volume_mask[iv] ) != 0) {
		  RSL_free_radar(radar);
		  return NULL;
		}
	  }
	}
	free_and_clear_sweep(&wsr88d_sweep, 0, MAX_RAYS_IN_SWEEP);
  }

  for (iv=0; iv<nvolumes; iv++) {
	if (rsl_qfield[iv]) {
	  radar->v[iv]->h.type_str = strdup(field_str[iv]);
	  radar->v[iv]->h.nsweeps = nsweep;
	}
  }
  wsr88d_close(wf);

/*
 * Here we will assign the Radar_header information.  Take most of it
 * from an existing volume's header.  
 */
  /* set the sitep info from level2 info, message31 if present (TODO) */
  if ( sitep == NULL ) {
     float mess31_lat, mess31_lon, mess31_elev;
     float dms;
     wsr88d_get_station_id(site_id_str, &mess31_lat, &mess31_lon, &mess31_elev);
     sitep = wsr88d_get_site(site_id_str);
     mess31_lon = mess31_lon * -1.0;
     if ( sitep == NULL ) {
        printf("setting site information to ID %s lat %f lon %f elev %f\n",
		site_id_str, mess31_lat, mess31_lon, mess31_elev);
        sitep = (Wsr88d_site_info *)malloc(sizeof(Wsr88d_site_info));
        sitep->number = -9999;
        sprintf(sitep->name,"%s\0",site_id_str); 
        sprintf(sitep->city,"--\0");
        sprintf(sitep->state,"--\0");
        dms = fabs(mess31_lat);
        sitep->latd = floor(dms);
        dms = (dms - (float)sitep->latd)*60;
        sitep->latm = floor(dms);
        dms = (dms - (float)sitep->latm)*60;
        sitep->lats = floor(dms);
        dms = fabs(mess31_lon);
        sitep->lond = floor(dms);
        dms = (dms - (float)sitep->lond)*60;
        sitep->lonm = floor(dms);
        dms = (dms - (float)sitep->lonm)*60;
        sitep->lons = floor(dms);
        if ( mess31_lat < 0 ) {
           sitep->latd *= -1;
           sitep->latm *= -1;
           sitep->lats *= -1;
        }
        if ( mess31_lon < 0 ) {
           sitep->lond *= -1;
           sitep->lonm *= -1;
           sitep->lons *= -1;
        }
        sitep->height = (int)mess31_elev;
        sitep->bwidth = -9999;
	sitep->spulse = 1530;
        sitep->lpulse = 4630;
        
     }
  }

  radar_load_date_time(radar);  /* Magic :-) */

	radar->h.number = sitep->number;
	memcpy(&radar->h.name, sitep->name, sizeof(sitep->name));
	memcpy(&radar->h.radar_name, sitep->name, sizeof(sitep->name)); /* Redundant */
	memcpy(&radar->h.city, sitep->city, sizeof(sitep->city));
	memcpy(&radar->h.state, sitep->state, sizeof(sitep->state));
	strcpy(radar->h.radar_type, "wsr88d");
	radar->h.latd = sitep->latd;
	radar->h.latm = sitep->latm;
	radar->h.lats = sitep->lats;
	if (radar->h.latd < 0) { /* Degree/min/sec  all the same sign */
	  radar->h.latm *= -1;
	  radar->h.lats *= -1;
	}
	radar->h.lond = sitep->lond;
	radar->h.lonm = sitep->lonm;
	radar->h.lons = sitep->lons;
	if (radar->h.lond < 0) { /* Degree/min/sec  all the same sign */
	  radar->h.lonm *= -1;
	  radar->h.lons *= -1;
	}
	radar->h.height = sitep->height;
	radar->h.spulse = sitep->spulse;
	radar->h.lpulse = sitep->lpulse;

	free(sitep);
		
  radar = RSL_prune_radar(radar);
  return radar;
}