Radar *RSL_uf_to_radar_fp(FILE *fp) { union { char buf[6]; short sword; int word; } magic; Radar *radar; int nbytes; short sbytes; UF_buffer uf; enum UF_type uf_type; #define NEW_BUFSIZ 16384 radar = NULL; setvbuf(fp,NULL,_IOFBF,(size_t)NEW_BUFSIZ); /* Faster i/o? */ if (fread(magic.buf, sizeof(char), 6, fp) <= 0) return NULL; /* * Check for fortran record length delimeters, NCAR kludge. */ if (strncmp("UF", magic.buf, 2) == 0) uf_type = TRUE_UF; else if (strncmp("UF", &magic.buf[2], 2) == 0) uf_type = TWO_BYTE_UF; else if (strncmp("UF", &magic.buf[4], 2) == 0) uf_type = FOUR_BYTE_UF; else uf_type = NOT_UF; switch (uf_type) { case FOUR_BYTE_UF: if (radar_verbose_flag) fprintf(stderr,"UF file with 4 byte FORTRAN record delimeters.\n"); /* Handle first record specially, since we needed magic information. */ nbytes = magic.word; if (little_endian()) swap_4_bytes(&nbytes); memcpy(uf, &magic.buf[4], 2); (void)fread(&uf[1], sizeof(char), nbytes-2, fp); if (little_endian()) swap_uf_buffer(uf); (void)fread(&nbytes, sizeof(int), 1, fp); if (uf_into_radar(uf, &radar) == UF_DONE) break; /* Now the rest of the file. */ while(fread(&nbytes, sizeof(int), 1, fp) > 0) { if (little_endian()) swap_4_bytes(&nbytes); (void)fread(uf, sizeof(char), nbytes, fp); if (little_endian()) swap_uf_buffer(uf); (void)fread(&nbytes, sizeof(int), 1, fp); if (uf_into_radar(uf, &radar) == UF_DONE) break; } break; case TWO_BYTE_UF: if (radar_verbose_flag) fprintf(stderr,"UF file with 2 byte FORTRAN record delimeters.\n"); /* Handle first record specially, since we needed magic information. */ sbytes = magic.sword; if (little_endian()) swap_2_bytes(&sbytes); memcpy(uf, &magic.buf[2], 4); (void)fread(&uf[2], sizeof(char), sbytes-4, fp); if (little_endian()) swap_uf_buffer(uf); (void)fread(&sbytes, sizeof(short), 1, fp); uf_into_radar(uf, &radar); /* Now the rest of the file. */ while(fread(&sbytes, sizeof(short), 1, fp) > 0) { if (little_endian()) swap_2_bytes(&sbytes); (void)fread(uf, sizeof(char), sbytes, fp); if (little_endian()) swap_uf_buffer(uf); (void)fread(&sbytes, sizeof(short), 1, fp); if (uf_into_radar(uf, &radar) == UF_DONE) break; } break; case TRUE_UF: if (radar_verbose_flag) fprintf(stderr,"UF file with no FORTRAN record delimeters. Good.\n"); /* Handle first record specially, since we needed magic information. */ memcpy(&sbytes, &magic.buf[2], 2); /* Record length is in word #2. */ if (little_endian()) swap_2_bytes(&sbytes); /* # of 2 byte words. */ memcpy(uf, &magic.buf[0], 6); (void)fread(&uf[3], sizeof(short), sbytes-3, fp); if (little_endian()) swap_uf_buffer(uf); uf_into_radar(uf, &radar); /* Now the rest of the file. */ while(fread(uf, sizeof(short), 2, fp) > 0) { memcpy(&sbytes, &uf[1], 2); /* Record length is in word #2. */ if (little_endian()) swap_2_bytes(&sbytes); (void)fread(&uf[2], sizeof(short), sbytes-2, fp); /* Have words 1,2. */ if (little_endian()) swap_uf_buffer(uf); if (uf_into_radar(uf, &radar) == UF_DONE) break; } break; case NOT_UF: return NULL; break; } radar = reset_nsweeps_in_all_volumes(radar); radar = RSL_prune_radar(radar); return radar; }
void RSL_radar_to_uf_fp(Radar *r, FILE *fp) { /* * 1. Fill the UF buffers with data from the Radar structure. * 2. Write to a stream. Assume open and leave it so. */ UF_buffer uf; /* 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_op; /* Optional 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_ma, len_op, len_lu, len_dh, len_fh, len_data; /* Booleans to flag inclusion of headers. */ int q_op, q_lu, q_dh, q_fh; int current_fh_index; int scale_factor; int rec_len, save_rec_len; int nfield; float vr_az; int max_field_names; struct tm *tm; time_t the_time; int i,j,k,m; int degree, minute; float second; int uf_sweep_mode = 1; /* default PPI */ /* Here are the arrays for each field type. Each dimension is the number * of fields in the radar structure. I do this because the radar organization * is by volumes (field types) and the UF demands that each ray contain * all the field types. */ Volume **volume; Sweep **sweep; Ray *ray; int *nsweeps; int nvolumes, maxsweeps, nrays; int true_nvolumes; int sweep_num, ray_num, rec_num; float x; if (r == NULL) { fprintf(stderr, "radar_to_uf_fp: radar pointer NULL\n"); return; } /* Do all the headers first time around. Then, prune OP and LU. */ q_op = q_lu = q_dh = q_fh = 1; memset(&uf, 0, sizeof(uf)); /* Init to 0 or NULL for pointers. */ sweep_num = ray_num = rec_num = 0; true_nvolumes = nvolumes = maxsweeps = nrays = 0; /* PPI and RHI are enum constants defined in rsl.h */ if (r->h.scan_mode == PPI) uf_sweep_mode = 1; else if (r->h.scan_mode == RHI) uf_sweep_mode = 3; /* * 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 wants sweeps, rays, then gates for all field types (volumes). * So, we have to do a back flip, here. This is achieved by maintaining * an array of volume pointers and sweep pointers, each dimensioned by * 'nvolumes', which contains the data for the different field types; this * is our innermost loop. The variables are 'volume[i]' and 'sweep[i]' where * 'i' is the volume index. * * In other words, we are getting all the field types together, when we * are looping on the number of rays in a sweep, so we can load the UF_buffer * appropriately. */ nvolumes = r->h.nvolumes; volume = (Volume **) calloc(nvolumes, sizeof(Volume *)); sweep = (Sweep **) calloc(nvolumes, sizeof(Sweep *)); nsweeps = (int *) calloc(nvolumes, sizeof(int)); /* Get the the number of sweeps in the radar structure. This will be * the main controlling loop variable. */ for (i=0; i<nvolumes; i++) { volume[i] = r->v[i]; if(volume[i]) { nsweeps[i] = volume[i]->h.nsweeps; if (nsweeps[i] > maxsweeps) maxsweeps = nsweeps[i]; true_nvolumes++; } } if (radar_verbose_flag) { fprintf(stderr,"True number of volumes for UF is %d\n", true_nvolumes); fprintf(stderr,"Maximum # of volumes for UF is %d\n", nvolumes); } max_field_names = sizeof(RSL_ftype) / 4; /*-------- * LOOP for all sweeps (typically 11 or 16 for wsr88d data. * */ for (i=0; i<maxsweeps; i++) { /* Get the array of volume and sweep pointers; one for each field type. */ nrays = 0; for (k=0; k<nvolumes; k++) { if (volume[k]) sweep[k] = volume[k]->sweep[i]; /* Check if we really can access this sweep. Paul discovered that * if the actual number of sweeps is less than the maximum that we * could be chasing a bad pointer (a NON-NULL garbage pointer). */ if (i >= nsweeps[k]) sweep[k] = NULL; if (sweep[k]) if (sweep[k]->h.nrays > nrays) nrays = sweep[k]->h.nrays; } sweep_num++; /* I guess it will be ok to count NULL sweeps. */ ray_num = 0; if (radar_verbose_flag) fprintf(stderr,"Processing sweep %d for %d rays.", i, nrays); if (radar_verbose_flag) if (little_endian()) fprintf(stderr," ... On Little endian.\n"); else fprintf(stderr,"\n"); /* Now LOOP for all rays within this particular sweep (i). * Get all the field types together for the ray, see ray[k], and * fill the UF data buffer appropriately. */ for (j=0; j<nrays; j++) { memset(uf, 0, sizeof(uf)); nfield = 0; ray_num++; /* And counting, possibly, NULL rays. */ current_fh_index = 0; /* Find any ray for header information. It does not matter which * ray, since the information for the MANDITORY, OPTIONAL, and LOCAL * USE headers is common to any field type ray. */ ray = NULL; for (k=0; k<nvolumes; k++) { if (sweep[k]) if (j < sweep[k]->h.nrays) if (sweep[k]->ray) if ((ray = sweep[k]->ray[j])) break; } /* If there is no such ray, then continue on to the next ray. */ if (ray) { /* fprintf(stderr,"Ray: %.4d, Time: %2.2d:%2.2d:%f %.2d/%.2d/%.4d\n", ray_num, ray->h.hour, ray->h.minute, ray->h.sec, ray->h.month, ray->h.day, ray->h.year); */ /* * ---- Begining of MANDITORY HEADER BLOCK. */ uf_ma = uf; memcpy(&uf_ma[0], "UF", 2); if (little_endian()) memcpy(&uf_ma[0], "FU", 2); uf_ma[1] = 0; /* Not known yet. */ uf_ma[2] = 0; /* Not known yet. Really, I do. */ uf_ma[3] = 0; /* Not known yet. */ uf_ma[4] = 0; /* Not known yet. */ uf_ma[6] = 1; uf_ma[7] = ray_num; uf_ma[8 ] = 1; uf_ma[9 ] = sweep_num; memcpy(&uf_ma[10], r->h.radar_name, 8); if (little_endian()) swap2(&uf_ma[10], 8/2); memcpy(&uf_ma[14], r->h.name, 8); if (little_endian()) swap2(&uf_ma[14], 8/2); /* Convert decimal lat/lon to d:m:s */ if (ray->h.lat != 0.0) { degree = (int)ray->h.lat; minute = (int)((ray->h.lat - degree) * 60); second = (ray->h.lat - degree - minute/60.0) * 3600.0; } else { degree = r->h.latd; minute = r->h.latm; second = r->h.lats; } uf_ma[18] = degree; uf_ma[19] = minute; if (second > 0.0) uf_ma[20] = second*64 + 0.5; else uf_ma[20] = second*64 - 0.5; if (ray->h.lon != 0.0) { degree = (int)ray->h.lon; minute = (int)((ray->h.lon - degree) * 60); second = (ray->h.lon - degree - minute/60.0) * 3600.0; } else { degree = r->h.lond; minute = r->h.lonm; second = r->h.lons; } uf_ma[21] = degree; uf_ma[22] = minute; if (second > 0.0) uf_ma[23] = second*64 + 0.5; else uf_ma[23] = second*64 - 0.5; if (ray->h.alt != 0) uf_ma[24] = ray->h.alt; else uf_ma[24] = r->h.height; uf_ma[25] = ray->h.year % 100; /* By definition: not year 2000 compliant. */ uf_ma[26] = ray->h.month; uf_ma[27] = ray->h.day; uf_ma[28] = ray->h.hour; uf_ma[29] = ray->h.minute; uf_ma[30] = ray->h.sec; memcpy(&uf_ma[31], "UT", 2); if (little_endian()) memcpy(&uf_ma[31], "TU", 2); if (ray->h.azimuth > 0) uf_ma[32] = ray->h.azimuth*64 + 0.5; else uf_ma[32] = ray->h.azimuth*64 - 0.5; uf_ma[33] = ray->h.elev*64 + 0.5; uf_ma[34] = uf_sweep_mode; if (ray->h.fix_angle != 0.) uf_ma[35] = ray->h.fix_angle*64.0 + 0.5; else uf_ma[35] = sweep[k]->h.elev*64.0 + 0.5; uf_ma[36] = ray->h.sweep_rate*(360.0/60.0)*64.0 + 0.5; the_time = time(NULL); tm = gmtime(&the_time); uf_ma[37] = tm->tm_year % 100; /* Same format as data year */ uf_ma[38] = tm->tm_mon+1; uf_ma[39] = tm->tm_mday; memcpy(&uf_ma[40], "RSL" RSL_VERSION_STR, 8); if (little_endian()) swap2(&uf_ma[40], 8/2); uf_ma[44] = (signed short)UF_NO_DATA; len_ma = 45; uf_ma[2] = len_ma+1; /* * ---- End of MANDITORY HEADER BLOCK. */ /* ---- Begining of OPTIONAL HEADER BLOCK. */ len_op = 0; if (q_op) { q_op = 0; /* Only once. */ uf_op = uf+len_ma; memcpy(&uf_op[0], "TRMMGVUF", 8); if (little_endian()) swap2(&uf_op[0], 8/2); uf_op[4] = (signed short)UF_NO_DATA; uf_op[5] = (signed short)UF_NO_DATA; uf_op[6] = ray->h.hour; uf_op[7] = ray->h.minute; uf_op[8] = ray->h.sec; memcpy(&uf_op[9], "RADAR_UF", 8); if (little_endian()) swap2(&uf_op[9], 8/2); uf_op[13] = 2; len_op = 14; } /* ---- End of OPTIONAL HEADER BLOCK. */ /* ---- Begining of LOCAL USE HEADER BLOCK. */ q_lu = 0; /* Note: Code within "#ifdef LUHDR_VR_AZ" below is retained for testing * and is not normally compiled. It was used to deal with azimuth * differences between DZ and VR in WSR-88D split-cuts, now handled in * ingest routine. */ /* 5/18/2010 Temporarily define LUHDR_VR_AZ until merge_split_cuts is completed. */ #define LUHDR_VR_AZ #ifdef LUHDR_VR_AZ /* If DZ and VR azimuths are different, store VR azimuth in Local Use * Header. This is done for WSR-88D split cuts. */ if (sweep[DZ_INDEX] && sweep[VR_INDEX]) { if (sweep[DZ_INDEX]->ray[j] && sweep[VR_INDEX]->ray[j]) { vr_az = sweep[VR_INDEX]->ray[j]->h.azimuth; if (sweep[DZ_INDEX]->ray[j]->h.azimuth != vr_az) q_lu = 1; /* Set to use Local Use Header block. */ } } #endif len_lu = 0; if (q_lu) { /* Store azimuth for WSR-88D VR ray in Local Use Header. */ uf_lu = uf+len_ma+len_op; memcpy(&uf_lu[0], "AZ", 2); if (little_endian()) memcpy(&uf_lu[0], "ZA", 2); if (vr_az > 0) uf_lu[1] = vr_az*64 + 0.5; else uf_lu[1] = vr_az*64 - 0.5; len_lu = 2; } /* ---- End of LOCAL USE HEADER BLOCK. */ /* Here is where we loop on each field type. We need to keep * track of how many FIELD HEADER and FIELD DATA sections, one * for each field type, we fill. The variable that tracks this * index into 'uf' is 'current_fh_index'. It is bumped by * the length of the FIELD HEADER and FIELD DATA for each field * type encountered. Field types expected are: Reflectivity, * Velocity, and Spectrum width; this is a typicial list but it * is not restricted to it. */ for (k=0; k<nvolumes; k++) { if (sweep[k]) if (j < sweep[k]->h.nrays && sweep[k]->ray[j]) ray = sweep[k]->ray[j]; else ray = NULL; else ray = NULL; if (ray) { /* ---- Begining of DATA HEADER. */ nfield++; if (q_dh) { len_dh = 2*true_nvolumes + 3; uf_dh = uf+len_ma+len_op+len_lu; uf_dh[0] = nfield; uf_dh[1] = 1; uf_dh[2] = nfield; /* 'nfield' indexes the field number. * 'k' indexes the particular field from the volume. * RSL_ftype contains field names and is defined in rsl.h. */ if (k > max_field_names-1) { fprintf(stderr, "RSL_uf_to_radar: No field name for volume index %d\n", k); fprintf(stderr,"RSL_ftype must be updated in rsl.h for new field.\n"); fprintf(stderr,"Quitting now.\n"); return; } memcpy(&uf_dh[3+2*(nfield-1)], RSL_ftype[k], 2); if (little_endian()) swap2(&uf_dh[3+2*(nfield-1)], 2/2); if (current_fh_index == 0) current_fh_index = len_ma+len_op+len_lu+len_dh; uf_dh[4+2*(nfield-1)] = current_fh_index + 1; } /* ---- End of DATA HEADER. */ /* ---- Begining of FIELD HEADER. */ if (q_fh) { uf_fh = uf+current_fh_index; uf_fh[1] = scale_factor = 100; uf_fh[2] = ray->h.range_bin1/1000.0; uf_fh[3] = ray->h.range_bin1 - (1000*uf_fh[2]); uf_fh[4] = ray->h.gate_size; uf_fh[5] = ray->h.nbins; uf_fh[6] = ray->h.pulse_width*(RSL_SPEED_OF_LIGHT/1.0e6); uf_fh[7] = sweep[k]->h.beam_width*64.0 + 0.5; uf_fh[8] = sweep[k]->h.beam_width*64.0 + 0.5; uf_fh[9] = ray->h.frequency*64.0 + 0.5; /* Bandwidth (mHz). */ uf_fh[10] = 0; /* Horizontal polarization. */ uf_fh[11] = ray->h.wavelength*64.0*100.0; /* m to cm. */ uf_fh[12] = ray->h.pulse_count; memcpy(&uf_fh[13], " ", 2); uf_fh[14] = (signed short)UF_NO_DATA; uf_fh[15] = (signed short)UF_NO_DATA; if (k == DZ_INDEX || k == ZT_INDEX) { uf_fh[16] = volume[k]->h.calibr_const*100.0 + 0.5; } else { memcpy(&uf_fh[16], " ", 2); } if (ray->h.prf != 0) uf_fh[17] = 1.0/ray->h.prf*1000000.0; /* Pulse repetition time(msec) = 1/prf */ else uf_fh[17] = (signed short)UF_NO_DATA; /* Pulse repetition time = 1/prf */ uf_fh[18] = 16; if (VR_INDEX == k || VE_INDEX == k) { uf_fh[19] = scale_factor*ray->h.nyq_vel; uf_fh[20] = 1; len_fh = 21; } else { len_fh = 19; } uf_fh[0] = current_fh_index + len_fh + 1; /* ---- End of FIELD HEADER. */ /* ---- Begining of FIELD DATA. */ uf_data = uf+len_fh+current_fh_index; len_data = ray->h.nbins; for (m=0; m<len_data; m++) { x = ray->h.f(ray->range[m]); if (x == BADVAL || x == RFVAL || x == APFLAG || x == NOECHO) uf_data[m] = (signed short)UF_NO_DATA; else uf_data[m] = scale_factor * x; } current_fh_index += (len_fh+len_data); } } /* ---- End of FIELD DATA. */ } /* Fill in some infomation we didn't know. Like, buffer length, * record number, etc. */ rec_num++; uf_ma[1] = current_fh_index; uf_ma[3] = len_ma + len_op + 1; uf_ma[4] = len_ma + len_op + len_lu + 1; uf_ma[5] = rec_num; /* WRITE the UF buffer. */ rec_len =(int)uf_ma[1]*2; save_rec_len = rec_len; /* We destroy 'rec_len' when making it big endian on a little endian machine. */ if (little_endian()) swap_4_bytes(&rec_len); (void)fwrite(&rec_len, sizeof(int), 1, fp); if (little_endian()) swap_uf_buffer(uf); (void)fwrite(uf, sizeof(char), save_rec_len, fp); (void)fwrite(&rec_len, sizeof(int), 1, fp); } /* if (ray) */ } } }