awips2/ncep/gov.noaa.nws.ncep.ui.nsharp/BigNsharp/Sndglib/basics.c
Steve Harris fd2abfb6f1 12.8.1-5 baseline
Former-commit-id: 99fb675cc2e1b94825ccda1fe09b1be0c3c25b3f
2012-08-01 10:45:37 -05:00

961 lines
28 KiB
C

/***************************************************************/
/* SHARP-95 */
/* Advanced Interactive Sounding Analysis Program */
/* */
/* Basic Interpolation and Conversion Routines */
/* */
/* John A. Hart */
/* National Severe Storms Forecast Center */
/* Kansas City, Missouri */
/* -------------------------------------------------- */
/* List of Routines in this module: */
/* */
/* I_TEMP */
/* I_DWPT */
/* I_PRES */
/* I_HGHT */
/* I_VTMP */
/* I_WDIR */
/* I_WSPD */
/* I_WNDU */
/* I_WNDV */
/* I_OMEG */
/* VIRTEMP */
/* SFC */
/* TOP_PRES */
/* QC */
/* QC2 */
/* MTOF */
/* FTOM */
/* FTOC */
/* CTOF */
/* AGL */
/* MSL */
/* KT_TO_MPS */
/***************************************************************/
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "basics.h"
#include "sndglib.h"
int remove_sndg_level(int p);
/*
* General interpolation routine
*
* var is a variable name (TEMP, DWPT, etc.) in your data set
* var may also be SPED for wind speed or DRCT for wind direction
*
* Right now no other interpolation is done for derived parameters
*
* level is the level you wish to interpolate to
* itype is the interpolation type. Valid types are
* I_PRES for pressure
* I_HGHT for height
*
*/
float i_var(char *var, float level, short itype)
{
short idx1, idx2, idx3, idxabove1, idxbelow1, idxabove2, idxbelow2, levidx;
float u, v, dir, spd;
int debugx;
debugx=0;
if (!strcasecmp(var, "U"))
{
debugx = 0;
/* printf( "Interpolating %s\n", var); */
}
/* Make sure we don't work on NULL pointers */
if (!sndg)
return RMISSD;
/* Catch stupid stuff */
if ((!strcasecmp(var, "PRES") && itype == I_PRES) || (!strcasecmp(var, "HGHT") && itype == I_HGHT))
return level;
levidx = -1;
if (itype == I_PRES)
{ levidx = getParmIndex("PRES"); }
else if (itype == I_HGHT)
{ levidx = getParmIndex("HGHT"); }
if (levidx == -1) return RMISSD;
/* Handle wind speed and direction separately from the basic
parameters such as temp, dwpt, hght, etc. */
if (!strcasecmp(var, "DRCT") || !strcasecmp(var, "SPED"))
{
idx1 = getParmIndex("DRCT");
idx2 = getParmIndex("SPED");
if (idx1 == -1 || idx2 == -1) return RMISSD;
/* Get the array indices in the vertical for this data */
idxabove1 = getlevelindex(idx1, level, ABOVE, itype);
idxabove2 = getlevelindex(idx2, level, ABOVE, itype);
idxbelow1 = getlevelindex(idx1, level, BELOW, itype);
idxbelow2 = getlevelindex(idx2, level, BELOW, itype);
if (idxabove1 == -1 || idxbelow1 == -1) return RMISSD;
/* if they are the same return the data at that level */
if (idxabove1 == idxbelow1)
{
u = ucomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]);
v = vcomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]);
}
else
{
/* begin 12/04/06 edit by RLT to fix interpolation bug */
/*dir = interp_gen(sndg[idxabove1][idx1], sndg[idxbelow1][idx1],
level, sndg[idxabove1][levidx],
sndg[idxbelow1][levidx], itype);
spd = interp_gen(sndg[idxabove2][idx2], sndg[idxbelow2][idx2],
level, sndg[idxabove2][levidx],
sndg[idxbelow2][levidx], itype);
u = ucomp(dir, spd);
v = vcomp(dir, spd);*/
u = interp_gen(ucomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]),
ucomp(sndg[idxbelow1][idx1], sndg[idxbelow1][idx2]),
level, sndg[idxabove1][levidx],
sndg[idxbelow1][levidx], itype);
v = interp_gen(vcomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]),
vcomp(sndg[idxbelow1][idx1], sndg[idxbelow1][idx2]),
level, sndg[idxabove1][levidx],
sndg[idxbelow1][levidx], itype);
/* end 12/04/06 edit */
}
if (!strcasecmp(var, "DRCT"))
{ return angle(u, v); }
else
{ return sqrt((u * u) + (v * v)); }
}
else if (!strcasecmp(var, "PRES") && itype == I_HGHT)
{ return i_pres(level); }
else if (!strcasecmp(var, "U") || !strcasecmp(var, "V"))
{
idx1 = getParmIndex("DRCT");
idx2 = getParmIndex("SPED");
idx3 = getParmIndex("PRES");
if (idx1 == -1 || idx2 == -1) return RMISSD;
/* Get the array indices in the vertical for this data */
idxabove1 = getlevelindex(idx1, level, ABOVE, itype);
idxabove2 = getlevelindex(idx2, level, ABOVE, itype);
idxbelow1 = getlevelindex(idx1, level, BELOW, itype);
idxbelow2 = getlevelindex(idx2, level, BELOW, itype);
if (idxabove1 == -1 || idxbelow1 == -1) return RMISSD;
/* if they are the same return the data at that level */
if (idxabove1 == idxbelow1)
{
if (!strcasecmp(var, "U"))
{ return ucomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]); }
else
{ return vcomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]); }
}
else
{
dir = interp_gen(sndg[idxabove1][idx1], sndg[idxbelow1][idx1],
level, sndg[idxabove1][levidx],
sndg[idxbelow1][levidx], itype);
spd = interp_gen(sndg[idxabove2][idx2], sndg[idxbelow2][idx2],
level, sndg[idxabove2][levidx],
sndg[idxbelow2][levidx], itype);
if (debugx)
{ printf (" ABOVE: %7.1f %7.1f %7.1f\n ANSWER:%7.1f %7.1f %7.1f\n BELOW: %7.1f %7.1f %7.1f\n",
sndg[idxabove1][idx3], sndg[idxabove1][idx1], sndg[idxabove1][idx2],
level , dir , spd,
sndg[idxbelow1][idx3], sndg[idxbelow1][idx1], sndg[idxbelow1][idx2]);
}
if (!strcasecmp(var, "U"))
{ return ucomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]); }
else
{ return vcomp(sndg[idxabove1][idx1], sndg[idxabove1][idx2]); }
}
}
else
{
idx1 = getParmIndex(var);
if (idx1 == -1) return RMISSD;
/* Get the array indices in the vertical for this data */
idxabove1 = getlevelindex(idx1, level, ABOVE, itype);
idxbelow1 = getlevelindex(idx1, level, BELOW, itype);
if (idxabove1 == -1 || idxbelow1 == -1) return RMISSD;
if (idxabove1 == idxbelow1) return sndg[idxabove1][idx1];
return interp_gen(sndg[idxabove1][idx1], sndg[idxbelow1][idx1],
level, sndg[idxabove1][levidx],
sndg[idxbelow1][levidx], itype);
}
return RMISSD;
}
/*
* getlevelindex
*
* Helper routine for i_var() which finds the first level above
* or below the specified level
*
*
* Inputs:
* parmIndex - the index in the sndg array for the parameter of
* interest
* level - the baseline level you're interested in
* direction -above (1) or below (1) the baseline level. valid values
* are ABOVE and BELOW
* itype - Is this pressure or height you're talking about. values are
* I_PRES or I_HGHT
*/
short getlevelindex(short parmIndex, float level, short direction, short itype)
{
short i, idx, ok;
/* Make sure we don't work on NULL pointers */
if (!sndg)
return -1;
ok = 0;
if (itype == I_PRES) {
idx = getParmIndex("PRES");
if (idx == -1) return -1;
if (direction == ABOVE) {
/* Above the level */
for (i=0; i < numlvl; i++) {
if ((sndg[i][idx] <= level) && (qc(sndg[i][parmIndex])))
return i;
}
}
else {
/* Below the level */
for (i=numlvl-1; i >= 0; i--) {
if ((sndg[i][idx] >= level) && (qc(sndg[i][parmIndex])))
return i;
}
}
}
else if (itype == I_HGHT) {
idx = getParmIndex("HGHT");
if (idx == -1) return -1;
if (direction == ABOVE) {
/* Above the level */
for (i=0; i < numlvl; i++) {
if ((sndg[i][idx] >= level) && (qc(sndg[i][parmIndex])))
return i;
}
}
else {
/* Below the level */
for (i=numlvl-1; i >= 0; i--) {
if ((sndg[i][idx] <= level) && (qc(sndg[i][parmIndex])))
return i;
}
}
}
return -1;
}
/*
* General interpolation routine
*/
float interp_gen(float valueabove, float valuebelow, float level,
float levelabove, float levelbelow, short itype)
{
float nm1, nm2, nm3, val;
if (!qc(valueabove) || !qc(valuebelow) || !qc(levelabove) ||
!qc(levelbelow))
return RMISSD;
val = RMISSD;
if (itype == I_PRES) {
nm1 = valueabove - valuebelow;
nm2 = log(levelbelow / levelabove);
nm3 = log(levelbelow / level);
val = valuebelow + ((nm3 / nm2) * nm1);
}
else if (itype == I_HGHT) {
nm1 = level - levelbelow;
nm2 = levelabove - levelbelow;
val = valuebelow + ((nm1 / nm2) * (valueabove - valuebelow));
}
return val;
}
float i_pres(float hght)
/*************************************************************/
/* I_PRES */
/* John Hart NSSFC KCMO */
/* */
/* Interpolates the given data to calculate a pressure(mb) */
/* at height (hght). */
/* */
/* hght - Height(m) of level */
/*************************************************************/
{
short below, above, i, idxp, idxz, ok;
double nm1, nm2, nm3;
below = 0;
above = 0;
/* Make sure we don't work on NULL pointers */
if (!sndg)
return RMISSD;
idxp = getParmIndex("PRES");
idxz = getParmIndex("HGHT");
if (idxz == -1 || idxp == -1)
return RMISSD;
/* ----- Find Pressure Immediately Above level ----- */
ok = 0;
for (i=0; i < numlvl; i++) {
if ((sndg[i][idxz] >= hght) && qc(sndg[i][idxp])) {
above = i;
ok=1;
break;
}
}
if (!ok)
return RMISSD;
/* ----- Find Pressure Below level ----- */
ok = 0;
for (i=numlvl-1; i > -1; i--) {
if ((sndg[i][idxz] <= hght) && qc(sndg[i][idxp])) {
below = i;
ok=1;
break;
}
}
if (!ok)
return RMISSD;
/* ----- If both levels are the same, return them ---- */
if (above == below)
return sndg[above][idxp];
/* ----- Now we need to interpolate to get the Pressure ----- */
nm1 = hght - sndg[below][idxz];
nm2 = sndg[above][idxz] - sndg[below][idxz];
nm3 = log(sndg[above][idxp] / sndg[below][idxp]);
return (float)(sndg[below][idxp] * exp((nm1 / nm2) * nm3));
}
short sfc(void)
/*************************************************************/
/* SFC */
/* John Hart NSSFC KCMO */
/* */
/* Returns the array pointer to the Surface Level. */
/*************************************************************/
{
short i, j;
/* Make sure we don't work on NULL pointers */
if (!sndg)
return RMISSD;
/* Note: we qc on U and not on other fields. */
j = getParmIndex("TEMP");
if (j == -1)
return 0;
for (i=0; i < numlvl; i++)
if (qc(sndg[i][j]))
return i;
return 0;
}
/*NP*/
float top_pres(void)
/*************************************************************/
/* TOP_PRES */
/* John Hart NSSFC KCMO */
/* */
/* Returns the pressure(mb) of highest level in sounding. */
/*************************************************************/
{
short i, idx;
/* Make sure we don't work on NULL pointers */
if (!sndg)
return RMISSD;
idx = getParmIndex("PRES");
if (idx == -1)
return RMISSD;
for( i=numlvl-1; i>0; i--) {
if (qc(sndg[i][idx]))
return sndg[i][idx];
}
return RMISSD;
}
/*NP*/
short qc(float value)
/*************************************************************/
/* QC */
/* John Hart NSSFC KCMO */
/* */
/* Quality control of sndg data. Searches for missing */
/* data (-999) and returns (1 = OK), (0 = missing) */
/*************************************************************/
{
if (value < -998.0 || value > 2.0E+05)
return 0;
return 1;
}
char *qc2(float value, char *label, short prec)
/*************************************************************/
/* QC2 */
/* John Hart NSSFC KCMO */
/* */
/* Quality control of sndg data. Searches for missing */
/* data (-999) and returns (char = OK), (M = missing) */
/* Returns real numbers with (prec) decimal points. */
/*************************************************************/
{
char fmt[10], st2[10];
static char st1[40];
if (!qc(value)) {
strcpy(st1, "M");
}
else {
itoa(prec, st2, 10);
strcpy(fmt, "%.");
strcat(fmt, st2);
strcat(fmt, "f%s");
sprintf(st1, fmt, value, label);
}
return st1;
}
float ctof(float value)
/*************************************************************/
/* CTOF */
/* John Hart NSSFC KCMO */
/* */
/* Converts given temperature (c) to (f). */
/*************************************************************/
{
if (!qc(value))
return RMISSD;
else
return ((1.8 * value) + 32.0);
}
float ftoc(float value)
/*************************************************************/
/* FTOC */
/* John Hart NSSFC KCMO */
/* */
/* Converts given temperature (f) to (c). */
/*************************************************************/
{
if (!qc(value))
return RMISSD;
else
return ((5.0/9.0) * (value - 32.0));
}
float mtof(float value)
/*************************************************************/
/* MTOF */
/* John Hart NSSFC KCMO */
/* */
/* Converts given distance (m) to (ft). */
/* */
/* T. Lee 7/2012 Changed .3049 to .3048 */
/*************************************************************/
{
if (!qc(value))
return RMISSD;
else
return (value / 0.3048);
}
float ftom(float value)
/*************************************************************/
/* FTOM */
/* John Hart NSSFC KCMO */
/* */
/* Converts given distance (ft) to (m). */
/* */
/* T. Lee 7/2012 Changed .3049 to .3048 */
/*************************************************************/
{
if (!qc(value))
return RMISSD;
else
return (value * .3048);
}
float agl(float height)
/*************************************************************/
/* AGL */
/* John Hart NSSFC KCMO */
/* */
/* Converts height (meters) MSL to AGL. */
/*************************************************************/
{
short idx;
if (!sndg)
return RMISSD;
if (!qc(height))
return RMISSD;
else {
idx = getParmIndex("HGHT");
if (idx == -1)
return RMISSD;
else
return (height - sndg[sfc()][idx]);
}
}
float msl(float height)
/*************************************************************/
/* MSL */
/* John Hart NSSFC KCMO */
/* */
/* Converts height (meters) AGL to MSL. */
/*************************************************************/
{
short idx;
if (!sndg)
return RMISSD;
if (!qc(height))
return RMISSD;
else {
idx = getParmIndex("HGHT");
if (idx == -1)
return RMISSD;
else
return (sndg[sfc()][idx] + height);
}
}
float kt_to_mps(float spd)
/*************************************************************/
/* KT_TO_MPS */
/* John Hart NSSFC KCMO */
/* */
/* Converts speed (knots) to meters per second. */
/*************************************************************/
{
if (!qc(spd))
return RMISSD;
else
return (spd * 0.51479);
}
char *itoa(int value, char *st, int radx)
/*************************************************************/
/* ITOA */
/*************************************************************/
{
sprintf(st, "%d", value);
return st;
}
void xtnd_sndg(void)
/*************************************************************/
/* XTND_SNDG */
/* John Hart NSSFC KCMO */
/* */
/* This routine will extend a sounding to 50mb, if the */
/* sounding made it at least to 150mb. */
/* */
/* An isothermal/hydrostatic layer is assumed above the */
/* last observed level. */
/*************************************************************/
{
short i, p, above, below, idxp, idxz;
double nm1, nm2, nm4;
/* Make sure we don't work on NULL pointers */
if (!sndg || numlvl < 1)
return;
return;
/*
* If we don't have pressure data in the sounding then it
* makes no sense to extend it in this manner!
*/
idxp = getParmIndex("PRES");
idxz = getParmIndex("HGHT");
if (idxp == -1 || idxz == -1)
return;
/* Is the top level between 150 and 100 mb? */
if (sndg[numlvl-1][idxp] <= 150.0 && sndg[numlvl-1][idxp] >= 100.0) {
for (p=75; p >= 50; p-=25) {
sndg[numlvl][idxp] = (float)p;
/* Interpolate everything but pressure and height */
for (i=0; i< ndsetparms; i++) {
if (!strcasecmp(dsetparms[i], "PRES") ||
!strcasecmp(dsetparms[i], "HGHT"))
continue;
sndg[numlvl][i] = i_var(dsetparms[i], 150.0, I_PRES);
}
/*
* Compute height
*
* We have to do this separately as an extrapolation.
* That's why it's not in the loop above with the
* other parameters
*/
idxz = getParmIndex("HGHT");
if (idxz != -1) {
above = numlvl-1;
below = numlvl-2;
sndg[numlvl][idxz] = interp_gen(sndg[above][idxz],
sndg[below][idxz], sndg[numlvl][idxp],
sndg[above][idxp], sndg[below][idxp], I_PRES);
}
numlvl++;
}
}
}
void interp_sndg(void)
/*************************************************************/
/* INTERP_SNDG */
/* John Hart NSSFC KCMO */
/* */
/* This routine take the current sounding array and */
/* interpolate it to 25mb increments. */
/*************************************************************/
{
/* printf( "\nCurrent Parcel begin interp_sndg (Sndglib/basics.c): %d\n", lplvals.flag);
*/ float **newsndg = NULL;
float nsndg[200][7], sfclvl, pres, cint, p1;
short newnum, i, j, k, idx;
/* Make sure we don't work on NULL pointers */
if (!sndg || numlvl < 1)
return;
idx = getParmIndex("PRES");
if (idx == -1)
return;
/*
* Allocate space for new sounding. Let's assume the top of
* the sounding will be 25mb at most, and the bottom is 1050mb
* Let's add 2 as a bufr as well
*/
cint = 25.0;
i = (short)((1050.0 - 25.0) / cint) + 2;
newsndg = (float **)malloc(i * sizeof(float *));
if (!newsndg)
return;
newnum = 0;
newsndg[newnum] = (float *)malloc(ndsetparms * sizeof(float));
if (!newsndg[newnum])
return;
/* ----- Copy surface conditions to new array ----- */
sfclvl = sndg[sfc()][idx];
newsndg[newnum][idx] = sfclvl;
/* Copy everything but pressure */
for (j=0; j < ndsetparms; j++) {
if (strcasecmp(dsetparms[j], "PRES")) {
newsndg[newnum][j] = i_var(dsetparms[j], sfclvl, I_PRES);
}
}
/* ----- Determine first interpolated level above surface ----- */
pres = (float)((short)((sfclvl / cint) + 0) * cint);
if (pres == sfclvl)
pres -= cint;
/* ----- Interpolate NSNDG array to prescribed increments ----- */
for (p1=pres; p1 >= sndg[numlvl-1][idx]; p1-=cint) {
newnum++;
newsndg[newnum] = (float *)malloc(ndsetparms * sizeof(float));
if (!newsndg[newnum])
break;
newsndg[newnum][idx] = p1;
for (j=0; j < ndsetparms; j++) {
if (strcasecmp(dsetparms[j], "PRES")) {
newsndg[newnum][j] = i_var(dsetparms[j], p1, I_PRES);
}
}
}
/* ----- Copy NSNDG to SNDG array ----- */
for (i=0;i<globalsndg->nlev;i++)
free(globalsndg->data[i]);
free(globalsndg->data);
numlvl = newnum;
globalsndg->nlev = numlvl;
globalsndg->data = newsndg;
sndg = globalsndg->data;
}
void check_data()
/***********************************************************/
/* CHECK_DATA */
/* Routine to check the data array for "out of order" data */
/* or other items that might lead to a crash. */
/***********************************************************/
{
int idx_p, idx_h, idx_t, idx_td, idx_ws, idx_wd, idx_uv;
int i, j, i0, i1, ok;
float tmp, p0, p1;
printf ("Beginning CHECK_DATA\n");
idx_p = getParmIndex("PRES");
idx_h = getParmIndex("HGHT");
idx_t = getParmIndex("TEMP");
idx_td = getParmIndex("DWPT");
idx_ws = getParmIndex("SPED");
idx_wd = getParmIndex("DRCT");
idx_uv = getParmIndex("OMEG");
/* Fix bad height at 1000mb */
for(i=1; i<numlvl; i++)
{
if (sndg[i][idx_p] == 1000)
{
if ((sndg[i][idx_h] > 5000)) sndg[i][idx_h] = -9999.0;
break;
}
}
/* Check to make sure array is in ascending order */
/* Continue to loop through array until no swaps are required. */
ok=1;
while(ok==1)
{
p0 = sndg[0][idx_p];
i0 = 0;
ok = 0;
for(i=1; i<numlvl; i++)
{
p1 = sndg[i][idx_p];
i1 = i;
if (p1 > p0)
{
ok = 1;
/*printf("I=%d, NUMLVL = %d , idx_h=%d\n", i, numlvl, idx_h);
printf("Order error between item %d and item %d. Items swapped.\n", i0, i1);
printf("I0 = %d %7.2f %7.2f\n", i0, sndg[i0][idx_p], sndg[i0][idx_h]);
printf("I1 = %d %7.2f %7.2f\n", i1, sndg[i1][idx_p], sndg[i1][idx_h]);*/
for(j=0;j<7;j++)
{
tmp = sndg[i0][j];
sndg[i0][j] = sndg[i1][j];
sndg[i1][j] = tmp;
}
break;
}
if (qc(p1) && (p1 == p0))
{
/*printf("Duplicate level found.\n", i0, i1);
printf("I0 = %d %7.2f %7.2f\n", i0, sndg[i0][idx_p], sndg[i0][idx_h]);
printf("I1 = %d %7.2f %7.2f\n", i1, sndg[i1][idx_p], sndg[i1][idx_h]);
printf("Removing level #%d.\n", i0);*/
tmp = remove_sndg_level(i0);
idx_h = getParmIndex("HGHT");
i--;
p1 = sndg[i][idx_p];
}
p0=p1;
i0=i1;
}
}
/* Next, fill all levels that have missing data */
for(i=0; i<numlvl; i++)
{
if (!qc(sndg[i][idx_h])) sndg[i][idx_h] = i_hght(sndg[i][idx_p], I_PRES);
if (!qc(sndg[i][idx_t])) sndg[i][idx_t] = i_temp(sndg[i][idx_p], I_PRES);
if (!qc(sndg[i][idx_td])) sndg[i][idx_td] = i_dwpt(sndg[i][idx_p], I_PRES);
/* if (!qc(sndg[i][idx_wd])) sndg[i][idx_wd] = i_wdir(sndg[i][idx_p], I_PRES); */
/* if (!qc(sndg[i][idx_ws])) sndg[i][idx_ws] = i_wspd(sndg[i][idx_p], I_PRES); */
}
printf ("Finished CHECK_DATA\n");
/* ----- Copy to GLOBALSNDG array ----- */
globalsndg->nlev = numlvl;
globalsndg->data = sndg;
}
int remove_sndg_level(int p)
{
float nsndgx[200][6];
int i,j, inew, newnum;
/* Copy sounding to temporary array */
/*printf("Copying data into temporary array.\n");*/
inew=0;
for(i=0;i<numlvl;i++) {
if (i != p) {
for(j=0;j<6;j++) { nsndgx[inew][j] = sndg[i][j]; }
inew++;
}
/*printf("Finished writing #%d\n", i);*/
}
for(j=0;j<7;j++) nsndgx[inew][j] = -9999;
for (i=0;i<numlvl-1;i++) {
for (j=0;j<6;j++) {
sndg[i][j] = nsndgx[i][j]; }
}
for (i=0;i<numlvl;i++) {
/*printf( "Completing: %2.2d %6.0f %6.0f %6.0f %6.0f %6.0f %6.0f\n", i,
sndg[i][0], sndg[i][1], sndg[i][2], sndg[i][3], sndg[i][4], sndg[i][5]);*/
}
numlvl--;
globalsndg->data = sndg;
/*printf( "Finished removing data.\n" );*/
return 0;
}
float i_temp(float level, short itype)
{
return i_var("TEMP", level, itype);
}
float i_dwpt(float level, short itype)
{
return i_var("DWPT", level, itype);
}
float i_hght(float level, short itype)
{
return i_var("HGHT", level, itype);
}
float i_wndu(float level, short itype)
{
/* return i_var("U", level, itype); */
return ucomp(i_wdir(level, I_PRES), i_wspd(level, I_PRES));
}
float i_wndv(float level, short itype)
{
/* return i_var("V", level, itype); */
return vcomp(i_wdir(level, I_PRES), i_wspd(level, I_PRES));
}
float i_omeg(float level, short itype)
{
return i_var("OMEG", level, itype);
}
float i_wdir(float level, short itype)
{
return i_var("DRCT", level, itype);
}
float i_wspd(float level, short itype)
{
return i_var("SPED", level, itype);
}
float i_vtmp(float level, short itype)
{
double cta, eps, tk, w;
float t, td, pres;
pres = level;
t = i_temp(level, itype);
td = i_dwpt(level, itype);
/*
* Return temperature in those cases when we can't get the
* dewpoint temp
*/
if (!qc(td))
{
if (!qc(t))
{ return RMISSD; }
else
{ return t; }
}
cta = 273.15;
eps = 0.62197;
/*
* Note that if we're working with height data we need to
* compute the pressure at this height for use in the mixing
* ratio routine.
*/
/* if (itype == I_HGHT) pres = i_pres(level); */
if (!qc(pres)) return RMISSD;
tk = t + cta;
w = 0.001 * (double)mixratio(pres, td);
return (float)(tk * (1.0 + w / eps) / (1.0 + w) - cta);
}