Merge branch 'master_13.5.2' (13.5.2-2) into omaha_13.5.2

Conflicts:
	msi/VizLauncher/VizLauncher.suo
	msi/VizLauncher/VizLauncher/com/raytheon/viz/launcher/process/AbstractProcessLauncher.cs
	msi/build/A2Staging/VisualStudio/VizLauncher.exe

Former-commit-id: b6df6f2aaa [formerly 4a0604f28c] [formerly 866885e3eb] [formerly b6df6f2aaa [formerly 4a0604f28c] [formerly 866885e3eb] [formerly 347d1eaef4 [formerly 866885e3eb [formerly c3a0913f289df802c65015686f877ca9c5e42bf5]]]]
Former-commit-id: 347d1eaef4
Former-commit-id: b800b32b9e [formerly 539b51afc9] [formerly 3fd03f9ee6b9805b2ebcb1741513edfb88c0e02f [formerly 9a6a2561fc]]
Former-commit-id: 787b21002c060468c496b24a83315fa2608c04a8 [formerly 29e2e0a01c]
Former-commit-id: db663043c7
This commit is contained in:
Steve Harris 2013-08-29 14:19:17 -05:00
commit d4ac47d817
5 changed files with 1686 additions and 703 deletions

View file

@ -47,697 +47,123 @@ import com.raytheon.viz.mpe.util.DailyQcUtils.Station;
public class RenderPcp {
private static boolean first = true;
Pcp pcp = DailyQcUtils.pcp;
/*
* QC codes
*/
private static final int MISSING = -1;
private static final int STANDARD = 0;
private static final int FAILED = 1;
private static final int MANUAL = 2;
private static final int QUESTIONABLE = 3;
private static final int PARTIAL = 4;
private static final int ESTIMATED = 5;
private static final int TIMEDISTRIBUTED = 6;
private static final int VERIFIED = 8;
/**
* Converts point precipitation data in struct pdata to hrap grid. The 20
* closest stations are precalculated for each grid point - this speeds
* computations for data sets with many precipitation points. If there are
* no good precipitation points for a grid point, then a recalculation is
* made using all precipitation points. 1/R**2 interpolation is used. If
* requested, the final interpolation is scaled using seasonal isohyets. The
* grid is saved as a disk file and used later for a raster or vector (HRAP)
* plot.
*
* @param m
* @param k
* @param mk
* @param numPstations
* @param precip_stations
* @param hrap_grid
* @param pdata
* @param pcp_in_use
*/
public void render_pcp(int pcpn_day, int pcpn_time, int pcpn_time_step,
int numPstations, ArrayList<Station> precip_stations,
Hrap_Grid hrap_grid, Pdata[] pdata, int[] pcp_in_use) {
int isom = DailyQcUtils.isom;
int method = DailyQcUtils.method;
int mpe_dqc_max_precip_neighbors = DailyQcUtils.mpe_dqc_max_precip_neighbors;
int i, j, h, hh, time_pos, htotal;
double distance, dist1, dist2, dist, value;
double temp;
int totals[] = new int[5];
for (i = 0; i < 5; i++) {
totals[i] = 0;
}
/*
* pcpn_time_step is a function parameter. It specifies whether to
* interpolate 6hr or 24hr HRAP grid
*/
/*
* pcpn_time is a function parameter. It specifies which 6hr HRAP grid
* to generate. It takes 0,1,2,or 3 to represent different 6hr period of
* a day.
*/
/*
* time_pos is assigned a value of 0,1,2,or 3 (for 6hr data) or 4 (for
* 24hr data). This value is used in
* pdata[pcpn_day].stn[hh].frain[time_pos].data to control whether to
* retrieve 6hr data or 24hr data.
*/
if (pcpn_time_step == 0) {
time_pos = pcpn_time; // for 6 hour data: 0,1,2,3.
} else {
time_pos = 4; // for 24 hour data
/*
* in case the 24hr grid rendering is required, we check
* 24hr_grid_gen_method_token() to determine how to generate the
* grid. New Post OB9.2
*/
if (getTokenValue24hrGridGenMeth() == 1) {
render24hrPcpUsingFour6hr(pcpn_day, pcpn_time, numPstations,
precip_stations, hrap_grid, pdata, pcp_in_use);
return;
}
}
/* begin to interpolate value for each bin in the HRAP grid */
/*
* to interpolate, two quantities are needed first: value and distance.
* They are calculated by using the neighboring stations.
*/
for (i = 0; i < hrap_grid.maxi; i++) {
for (j = 0; j < hrap_grid.maxj; j++) {
/*
* Check if the grid cell is covered by an HSA. If not, then do
* not estimate precipitation for it.
*/
if (hrap_grid.owner[i][j] == -1) {
pcp.value[i][j] = 0;
continue;
}
value = 0.0;
distance = 0.0;
htotal = 0;
/*
* the following for loop is to calculate two quantities: value
* and distance, which later on, are used to interpret the HRAP
* grid.
*/
/*
* It uses neighbor stations of a HRAP grid bin to calculate
* value and distance.
*/
/* for each neighbor station of the grid bin, do the following */
/* For each of the closest stations. */
for (h = 0; h < mpe_dqc_max_precip_neighbors; h++) {
hh = hrap_grid.gage[i][j].index[h];
// hh is index of stations
if (pdata[pcpn_day].stn[hh].frain[time_pos].data < 0) {
/* No precip data. */
continue;
} // frain refers to level 2 data; rrain refers to level 1
if (method == 2 && precip_stations.get(hh).isoh[isom] <= 0) {
continue;
}
if (pdata[pcpn_day].stn[hh].frain[time_pos].qual != 0
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 8
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 6
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 3
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 4
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 2) {
/* The station has a bad qc flag. Do not use it. */
continue;
}
/*
* Convert the coordinates of the grid and station in
* lat/lon into distance.
*/
dist1 = (i + (hrap_grid.hrap_minx - precip_stations.get(hh).hrap_x));
dist2 = (j + (hrap_grid.hrap_miny - precip_stations.get(hh).hrap_y));
dist = Math.pow(dist1, 2) + Math.pow(dist2, 2);
if (dist < .00001) {
dist = .00001;
}
dist = 1 / dist;
temp = pdata[pcpn_day].stn[hh].frain[time_pos].data * dist;
if (method == 2 && precip_stations.get(hh).isoh[isom] > 0) {
temp = temp * hrap_grid.isoh[isom][i][j]
/ (precip_stations.get(hh).isoh[isom] * 25.4);
}
value = value + temp;
distance = distance + dist;
htotal++;
if (htotal == 10) {
break;
}
}
/*
* end for loop (h = 0; h < mpe_dqc_max_precip_neighbors;h++)
* the above for loop is for each neighbor station.
*/
/*
* the above for loop is to calculate value and distance, which
* later on, are used to interpret the HRAP grid
*/
/*
* the resulting htotal is the valid number of neighbor stations
* that are used to calculate value and distance, which later
* on, are used to interpret the HRAP grid
*/
/*
* if there is not enough valid neighbor station, such as htotal
* <4, the code below handle this situation. Basically, the code
* recalculate the value and distance using all the stations --
* see the for (h = 0; h < max_stations; h++) loop below.
*/
if (htotal < 4) {
value = 0.0;
distance = 0.0;
htotal = 0;
for (h = 0; h < numPstations; h++) {
if (pdata[pcpn_day].stn[h].frain[time_pos].data < 0) {
continue;
}
if (pdata[pcpn_day].stn[h].frain[time_pos].qual != 0
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 8
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 6
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 3
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 4
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 2) {
continue;
}
if (method == 2
&& precip_stations.get(h).isoh[isom] <= 0) {
continue;
}
dist1 = (i + (hrap_grid.hrap_minx - precip_stations
.get(h).hrap_x));
dist2 = (j + (hrap_grid.hrap_miny - precip_stations
.get(h).hrap_y));
dist = Math.pow(dist1, 2) + Math.pow(dist2, 2);
/*
* if distance from grid box to station is >
* mpe_dqc_grid_max_distbins,
*/
/* then do not use station */
if (dist < .00001) {
dist = .00001;
}
else if (Math.sqrt(dist) > DailyQcUtils.mpe_dqc_grid_max_dist) {
continue;
}
dist = 1 / dist;
temp = pdata[pcpn_day].stn[h].frain[time_pos].data
* dist;
if (method == 2
&& precip_stations.get(h).isoh[isom] > 0) {
temp = temp
* hrap_grid.isoh[isom][i][j]
/ (precip_stations.get(h).isoh[isom] * 25.4);
}
value = value + temp;
distance = distance + dist;
htotal++;
}
}/* end the handling of special case : if (htotal < 4), */
/* which means there is no enough neighboring stations */
if (htotal == 0) {
pcp.value[i][j] = 0;
} else {
pcp.value[i][j] = (int) (value / distance * 100.0);
}
// if (htotal != 0) {
// pcp.value[i][j] += (int) (value / distance * 100);
// }
if (pcp.value[i][j] < .01) {
pcp.value[i][j] = 0;
}
}
} // end of the ( k = 0; k<4; k++) loop, which interpolates 4 6hr HRAP
// grid.
/* final adjustment of the pcp->value */
// for (i = 0; i < hrap_grid.maxi; i++) {
// hrap_grid comes from the function parameter
// for (j = 0; j < hrap_grid.maxj; j++) {
//
// if (pcp.value[i][j] < .01) {
// pcp.value[i][j] = 0;
// }
// }
// }
if (pcpn_time_step == 0) {
time_pos = pcpn_day * 4 + 3 - pcpn_time;
} else {
time_pos = 40 + pcpn_day;
}
// notice that time_pos is a variable defined inside the function, and
// its value do not need to be limited as 0,1,2,3,or 4. Here it is
// assigned with bigger numbers.
// time_pos = 40 + pcpn_day;
// pcp_in_use[i] = 1 -- grids rendered via Render button OR Save Level2
// option
// = -1 --grids for this time period not rendered (initialization value)
pcp_in_use[time_pos] = 1;
ReadQPFGrids rqp = new ReadQPFGrids();
rqp.write_file("pcp", time_pos, pcp);
}
/*
* get the token value of token mpe_24hr_grid_gen_method. This token will
* determine how we generate the 24hr grid. We can either use the 24hr gage
* values, which is the old way, or we can use four 6hr gage values and add
* them together.
*/
/* there is some problem with the static */
/**
* @param pcpn_day
* @param pcpn_time
* @param numPstations
* @param precip_stations
* @param hrap_grid
* @param pdata
* @param pcp_in_use
*/
private void render24hrPcpUsingFour6hr(int pcpn_day, int pcpn_time,
int numPstations, ArrayList<Station> precip_stations,
Hrap_Grid hrap_grid, Pdata[] pdata, int[] pcp_in_use) {
int i, j, k, h, hh, time_pos, htotal;
double distance, dist1, dist2, dist, value;
double temp;
int isom = DailyQcUtils.isom;
int method = DailyQcUtils.method;
int totals[] = new int[5];
int all_total = 0;
int neighbor_total = 0;
for (i = 0; i < 5; i++) {
totals[i] = 0;
}
/*
* pcpn_time_step is function parameter. It specifies whether to
* interpolate 6hr or 24hr HRAP grid
*/
/*
* pcpn_time is a function parameter. It specifies which 6hr HRAP grid
* to generate. It takes 0,1,2,or 3 to represent different 6hr period of
* a day.
*/
/*
* time_pos is assigned a value of 0,1,2,or 3 (for 6hr data) or 4 (for
* 24hr data). This value is used in
* pdata[pcpn_day].stn[hh].frain[time_pos].data to control whether to
* retrieve 6hr data or 24hr data.
*/
/* initialization of the pcp->value */
for (i = 0; i < hrap_grid.maxi; i++) { /*
* hrap_grid comes from the
* function parameter
*/
for (j = 0; j < hrap_grid.maxj; j++) {
pcp.value[i][j] = 0;
}
}
/*
* begin to interpolate 4 6hr grids. At the end of each iteration, the
* calculated interpolation value is added to pcp->value[i][j].
*/
/*
* time_pos is assigned a value of 0,1,2,or 3 (for four 6hr data). This
* value is used in pdata[pcpn_day].stn[hh].frain[time_pos].data to
* retrieve 6hr data.
*/
for (k = 0; k < 4; k++) {
time_pos = k; /* for 6 hour data: 0, 1,2,3. */
/* begin to interpolate value for each bin in the HRAP grid */
/*
* to interpolate, two quantities are needed first: value and
* distance. They are calculated by using the neighboring stations.
*/
for (i = 0; i < hrap_grid.maxi; i++) { /*
* hrap_grid comes from the
* function parameter
*/
for (j = 0; j < hrap_grid.maxj; j++) {
/*
* Check if the grid cell is covered by an HSA. If not, then
* do not estimate precipitation for it.
*/
if (hrap_grid.owner[i][j] == -1) {
pcp.value[i][j] = 0;
continue;
}
value = 0.0;
distance = 0.0;
htotal = 0;
/*
* the following for loop is to calculate two quantities:
* value and distance, which later on, are used to interpret
* the HRAP grid.
*/
/*
* It uses neighbor stations of a HRAP grid bin to calculate
* value and distance.
*/
/*
* for each neighbor station of the grid bin, do the
* following
*/
int mpe_dqc_max_precip_neighbors = DailyQcUtils.mpe_dqc_max_precip_neighbors;
for (h = 0; h < mpe_dqc_max_precip_neighbors; h++) {
hh = hrap_grid.gage[i][j].index[h];/*
* hh is index of
* stations
*/
if (pdata[pcpn_day].stn[hh].frain[time_pos].data < 0) {
/* No precip data. */
continue;
} /*
* frain refers to level 2 data; rain refers to level
* 1
*/
/*
* generate something for output later on if in debug
* mode
*/
// if (debug_level >= 1) {
// if (pdata[pcpn_day].stn[hh].frain[time_pos].qual
// == MISSING)
// {
// missing_total++;
// }
//
// if (pdata[pcpn_day].stn[hh].frain[time_pos].qual
// == ESTIMATED)
// {
// estimated_total++;
// }
//
// if (pdata[pcpn_day].stn[hh].frain[time_pos].qual
// == FAILED)
// {
// failed_total++;
// }
//
// if (method == 2 && station[hh].isoh[isom] <= 0)
// {
// climo_total++;
// }
// } /* end if (debug_level >= 1) */
if (DailyQcUtils.method == 2
&& precip_stations.get(hh).isoh[isom] <= 0) {
continue;
}
if (pdata[pcpn_day].stn[hh].frain[time_pos].qual != 0
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 8
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 6
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 3
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 4
&& pdata[pcpn_day].stn[hh].frain[time_pos].qual != 2) {
/* The station has a bad qc flag. Do not use it. */
continue;
}
/*
* Convert the coordinates of the grid and station in
* lat/lon into distance.
*/
dist1 = (i + hrap_grid.hrap_minx - precip_stations
.get(hh).hrap_x);
dist2 = (j + hrap_grid.hrap_miny - precip_stations
.get(hh).hrap_y);
dist = Math.pow(dist1, 2) + Math.pow(dist2, 2);
if (dist < .00001) {
dist = .00001;
}
dist = 1 / dist;
temp = pdata[pcpn_day].stn[hh].frain[time_pos].data
* dist;
if (method == 2
&& precip_stations.get(hh).isoh[isom] > 0) {
temp = temp
* hrap_grid.isoh[isom][i][j]
/ (precip_stations.get(hh).isoh[isom] * 25.4);
}
value = value + temp;
distance = distance + dist;
htotal++;
if (htotal == 10) {
break;
}
}
/*
* end for loop (h = 0; h <
* mpe_dqc_max_precip_neighbors;h++)
*/
/* the above for loop is for each neighbor station. */
/*
* the above for loop is to calculate value and distance,
* which later on, are used to interpret the HRAP grid
*/
/*
* the resulting htotal is the valid number of neighbor
* stations that are used to calculate value and distance,
* which later on, are used to interpret the HRAP grid
*/
/*
* if there is not enough valid neighbor station, such as
* htotal <4, the code below handle this situation.
* Basically, the code recalculate the value and distance
* using all the stations -- see the for (h = 0; h <
* max_stations; h++) loop below.
*/
if (htotal < 4) {
value = 0.0;
distance = 0.0;
htotal = 0;
for (h = 0; h < numPstations; h++) {
if (pdata[pcpn_day].stn[h].frain[time_pos].data < 0) {
continue;
}
if (pdata[pcpn_day].stn[h].frain[time_pos].qual != 0
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 8
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 6
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 3
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 4
&& pdata[pcpn_day].stn[h].frain[time_pos].qual != 2) {
continue;
}
if (method == 2
&& precip_stations.get(h).isoh[isom] <= 0) {
continue;
}
dist1 = (i + hrap_grid.hrap_minx - precip_stations
.get(h).hrap_x);
dist2 = (j + hrap_grid.hrap_miny - precip_stations
.get(h).hrap_y);
dist = Math.pow(dist1, 2) + Math.pow(dist2, 2);
if (dist < .00001) {
dist = .00001;
}
dist = 1 / dist;
temp = pdata[pcpn_day].stn[h].frain[time_pos].data
* dist;
if (method == 2
&& precip_stations.get(h).isoh[isom] > 0) {
temp = temp
* hrap_grid.isoh[isom][i][j]
/ (precip_stations.get(h).isoh[isom] * 25.4);
}
value = value + temp;
distance = distance + dist;
htotal++;
}
neighbor_total++;
} /* end the handling of special case : if (htotal < 4), */
/* which means there is no enough neighboring stations */
/*
* add the interpreted value for the bin of the HRAP_grid
*/
/*
* if (htotal == 0) { pcp->value[i][j] += 0; } else {
* pcp->value[i][j] += (int) (value / distance * 100); }
*/
if (htotal != 0) {
pcp.value[i][j] += (int) (value / distance * 100);
}
/*
* if (pcp->value[i][j] < .01) { pcp->value[i][j] = 0; }
*/
all_total++;
} /* end of for loop (j = 0; j < hrap_grid->maxj; j++) */
} /* end of for loop (i = 0; i < hrap_grid->maxi; i++) */
/* At this moment, the interpretation of HRAP grid is done */
}/*
* end of the ( k = 0; k<4; k++) loop, which interpolates 4 6hr HRAP
* grid.
*/
/* final adjustment of the pcp->value */
for (i = 0; i < hrap_grid.maxi; i++) { /*
* hrap_grid comes from the
* function parameter
*/
for (j = 0; j < hrap_grid.maxj; j++) {
if (pcp.value[i][j] < .01) {
pcp.value[i][j] = 0;
}
}
}
/* time_pos = pcpn_day * 4 + 3 - pcpn_time; */
time_pos = 40 + pcpn_day;
/*
* pcp_in_use[i] = 1 -- grids rendered via Render button OR Save Level2
* option = -1 --grids for this time period not rendered (initialization
* value)
*/
pcp_in_use[time_pos] = 1;
/*
* results of grid rendering routines (render_t, render_t6, render_pcp,
* render_z) are written to scratch files using the write_file routine.
* scratch file is stored in the scratch directory.
*/
ReadQPFGrids rqp = new ReadQPFGrids();
rqp.write_file("pcp", time_pos, pcp);
}
int getTokenValue24hrGridGenMeth() {
int token_of_24hr_grid_gen_method = 0;
/* int token_of_24hr_grid_gen_method = 0; */
if (first == true) {
String token_name_of_24hr_grid_gen_method_token = "mpe_dqc_24hr_precip_grid_meth";
/* char strTokenValue[50] = { '\0' }; */
String DQC24hrPrecipMeth;
// char message[GAGEQC_MESSAGE_LEN] = { '\0' };
AppsDefaults appsDefaults = AppsDefaults.getInstance();
DQC24hrPrecipMeth = appsDefaults
.getToken(token_name_of_24hr_grid_gen_method_token);
// sprintf(message, "\nSTATUS: token value of \"%s\" : %s\n",
// token_name_of_24hr_grid_gen_method_token, strTokenValue);
// logMessage(message);
if (DQC24hrPrecipMeth != null && DQC24hrPrecipMeth.length() > 0) {
/* we use the token ACCUM_6HR and USE_24HR */
if (DQC24hrPrecipMeth.equalsIgnoreCase("ACCUM_6HR")) {
token_of_24hr_grid_gen_method = 1;
}
}
first = false;
}
return token_of_24hr_grid_gen_method;
}
}
private static boolean first = true;
Pcp pcp = DailyQcUtils.pcp;
/*
* QC codes
*/
private static final int MISSING = -1;
private static final int STANDARD = 0;
private static final int SCREENED = 0;
private static final int FAILED = 1;
private static final int MANUAL = 2;
private static final int QUESTIONABLE = 3;
private static final int PARTIAL = 4;
private static final int ESTIMATED = 5;
private static final int TIMEDISTRIBUTED = 6;
private static final int VERIFIED = 8;
private static final String MPE_DQC_GRID_RENDERING_METHOD_TOKEN = "mpe_dqc_grid_render_method";
private static final int maxDistSquared = DailyQcUtils.mpe_dqc_grid_max_dist
* DailyQcUtils.mpe_dqc_grid_max_dist;
/**
* Converts point precipitation data in struct pdata to hrap grid. The 20
* closest stations are precalculated for each grid point - this speeds
* computations for data sets with many precipitation points. If there are
* no good precipitation points for a grid point, then a recalculation is
* made using all precipitation points. 1/R**2 interpolation is used. If
* requested, the final interpolation is scaled using seasonal isohyets. The
* grid is saved as a disk file and used later for a raster or vector (HRAP)
* plot.
*
* @param m
* @param k
* @param mk
* @param numPstations
* @param
* @param hrap_grid
* @param pdata
* @param pcp_in_use
*/
// mpe_dqc_grid_render_method
// ---------------------------------------------------------------------------------------
public void render_pcp(int pcpn_day, int pcpn_time, int pcpn_time_step,
int numPstations, ArrayList<Station> precip_stations,
Hrap_Grid hrap_grid, Pdata[] pdata, int[] pcp_in_use) {
String header = "RenderPcp.render_pcp(): ";
AppsDefaults appsDefaults = AppsDefaults.getInstance();
String tokenValue = appsDefaults
.getToken(MPE_DQC_GRID_RENDERING_METHOD_TOKEN);
// System.out.println(header + "tokenValue = " + tokenValue);
// tokenValue = "BLOCKING";
// tokenValue = "DISTANCE_SQUARED";
System.out.println(header + "now tokenValue = " + tokenValue);
if (tokenValue != null && tokenValue.equalsIgnoreCase("BLOCKING")) {
RenderPcpBlocking renderer = new RenderPcpBlocking();
renderer.render_pcp(pcpn_day, pcpn_time, pcpn_time_step,
numPstations, precip_stations, hrap_grid, pdata, pcp_in_use);
}
else {
RenderPcpStandard renderer = new RenderPcpStandard();
renderer.render_pcp(pcpn_day, pcpn_time, pcpn_time_step,
numPstations, precip_stations, hrap_grid, pdata, pcp_in_use);
}
determineMaxPrecip(hrap_grid);
}
private int determineMaxPrecip(Hrap_Grid hrap_grid) {
// TODO Auto-generated method stub
String header = "RenderPcp.determineMaxPrecip(): ";
int value = 0;
int maxValue = -1;
for (int col = 0; col < hrap_grid.maxi; col++) {
for (int row = 0; row < hrap_grid.maxj; row++) {
value = pcp.value[row][col];
if (value > maxValue) {
maxValue = value;
}
}
}
System.out.println(header + "maxValue = " + maxValue);
return maxValue;
} // end determineMaxPrecip()
// ---------------------------------------------------------------------------------------
} // end class RenderPcp

View file

@ -0,0 +1,957 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.mpe.util;
import java.util.ArrayList;
import com.raytheon.uf.common.ohd.AppsDefaults;
import com.raytheon.viz.mpe.util.DailyQcUtils.Hrap_Grid;
import com.raytheon.viz.mpe.util.DailyQcUtils.Pcp;
import com.raytheon.viz.mpe.util.DailyQcUtils.Pdata;
import com.raytheon.viz.mpe.util.DailyQcUtils.Station;
/**
* DESCRIPTION: Maps precipitation station values to an HRAP grid. Produces the
* DailyQC version of the GageOnly analysis.
*
* <pre>
*
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 11, 2009 snaples Initial creation
* May 02, 2011 8962 snaples Added render24hrPcpUsingFour6hr() method
*
* </pre>
*
* @author snaples
* @version 1.0
*/
public class RenderPcpBlocking {
private static boolean first = true;
Pcp pcp = DailyQcUtils.pcp;
/*
* QC codes
*/
private static final int MISSING = -1;
private static final int STANDARD = 0;
private static final int SCREENED = 0;
private static final int FAILED = 1;
private static final int MANUAL = 2;
private static final int QUESTIONABLE = 3;
private static final int PARTIAL = 4;
private static final int ESTIMATED = 5;
private static final int TIMEDISTRIBUTED = 6;
private static final int VERIFIED = 8;
// private static final String MPE_DQC_GRID_RENDERING_METHOD_TOKEN =
// "mpe_dqc_grid_render_method";
private static final int maxDistSquared = DailyQcUtils.mpe_dqc_grid_max_dist
* DailyQcUtils.mpe_dqc_grid_max_dist;
// private static final int maxDistSquared = 400;
/**
* Converts point precipitation data in struct pdata to hrap grid. The 20
* closest stations are precalculated for each grid point - this speeds
* computations for data sets with many precipitation points. If there are
* no good precipitation points for a grid point, then a recalculation is
* made using all precipitation points. 1/R**2 interpolation is used. If
* requested, the final interpolation is scaled using seasonal isohyets. The
* grid is saved as a disk file and used later for a raster or vector (HRAP)
* plot.
*
* @param m
* @param k
* @param mk
* @param numPstations
* @param
* @param hrap_grid
* @param pdata
* @param pcp_in_use
*/
// mpe_dqc_grid_render_method
private boolean usingSingleDirectionCloseOutMode = true;
private static final int MIN_PREFERRED_USED_GRID_CELLS = 4;
private static final int MIN_REQUIRED_USED_GRID_CELLS = 1;
private SearchDirection north = new SearchDirection();
private SearchDirection south = new SearchDirection();
private SearchDirection east = new SearchDirection();
private SearchDirection west = new SearchDirection();
private int colMin;
private int colMax;
private int rowMin;
private int rowMax;
private int prevColMin;
private int prevColMax;
private int prevRowMin;
private int prevRowMax;
// weighting variables
private int usedGridCellCount = 0;
private double totalWeightedValue = 0;
private double totalDistanceWeight = 0;
// grid variables
private int binStationCount[][];
private int usableStationCount = 0;
private double valueGrid[][];
private double prismStationGrid[][];
private int isom = -1;
class SearchDirection {
private boolean isOpen;
private int level;
public SearchDirection() {
reset();
}
public void reset() {
setOpen(true);
setLevel(0);
}
public boolean isOpen() {
return isOpen;
}
public void setOpen(boolean isOpen) {
this.isOpen = isOpen;
}
public void close() {
setOpen(false);
}
void expandSearchIfAllowed() {
if (isOpen()) {
incrementLevel();
if (getLevel() > DailyQcUtils.mpe_dqc_grid_max_dist) {
setLevel(DailyQcUtils.mpe_dqc_grid_max_dist);
close();
}
}
}
public void incrementLevel() {
this.level++;
}
private void setLevel(int level) {
this.level = level;
}
public int getLevel() {
return level;
}
} // end inner class SearchDirection
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
int getTokenValue24hrGridGenMeth() {
int token_of_24hr_grid_gen_method = 0;
if (first == true) {
String tokenName = "mpe_dqc_24hr_precip_grid_meth";
String dqc24hrPrecipMeth;
// char message[GAGEQC_MESSAGE_LEN] = { '\0' };
AppsDefaults appsDefaults = AppsDefaults.getInstance();
dqc24hrPrecipMeth = appsDefaults.getToken(tokenName);
if (dqc24hrPrecipMeth != null) {
/* allowed token values: (ACCUM_6HR, USE_24HR) */
if (dqc24hrPrecipMeth.equalsIgnoreCase("ACCUM_6HR")) {
token_of_24hr_grid_gen_method = 1;
}
}
first = false;
}
return token_of_24hr_grid_gen_method;
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
public void render_pcp(int pcpn_day, int pcpn_time, int pcpn_time_step,
int numPstations, ArrayList<Station> stationList,
Hrap_Grid hrap_grid, Pdata[] pdata, int[] pcp_in_use) {
isom = DailyQcUtils.isom;
int time_pos;
if (pcpn_time_step == 0) {
time_pos = pcpn_time; // for 6 hour data: 0,1,2,3.
boolean save_grids = true;
boolean accumulate_grids = false;
render_pcp_internal(pcpn_day, pcpn_time, pcpn_time_step,
numPstations, stationList, hrap_grid, pdata, pcp_in_use,
save_grids, accumulate_grids);
} else {
time_pos = 4; // for 24 hour data
/*
* in case the 24hr grid rendering is required, we check
* 24hr_grid_gen_method_token() to determine how to generate the
* grid. New Post OB9.2
*/
// debug
// first = true;
if (getTokenValue24hrGridGenMeth() == 1) {
render24hrPcpUsingFour6hr(pcpn_day, pcpn_time, numPstations,
stationList, hrap_grid, pdata, pcp_in_use);
return;
} else // calculate 24-hour grids the regular way
{
boolean save_grids = true;
boolean accumulate_grids = false;
render_pcp_internal(pcpn_day, pcpn_time, pcpn_time_step,
numPstations, stationList, hrap_grid, pdata,
pcp_in_use, save_grids, accumulate_grids);
}
}
}
private void render_pcp_internal(int pcpn_day, int pcpn_time,
int pcpn_time_step, int numPstations,
ArrayList<Station> stationList, Hrap_Grid hrap_grid, Pdata[] pdata,
int[] pcp_in_use, boolean save_grids, boolean should_accumulate) {
// String header = "RenderPcpBlocking.render_pcp_internal(): ";
int isom = DailyQcUtils.isom;
double resultingPrecipValue = 0.0;
/*-----------------------------------------------------*/
allocateGrids(hrap_grid);
initializeGrids(hrap_grid, should_accumulate);
placeStationsInGrid(pcpn_day, pcpn_time, pcpn_time_step, numPstations,
stationList, hrap_grid, pdata);
// for every grid location, determine its estimated value
for (int col = 0; col < hrap_grid.maxi; col++) {
for (int row = 0; row < hrap_grid.maxj; row++) {
/*
* Check if the grid cell is covered by an HSA. If not, then do
* not estimate precipitation for it.
*/
if (hrap_grid.owner[col][row] == -1) {
pcp.value[row][col] = 0;
continue;
}
if (binStationCount[col][row] > 0) // if any station is in this
// grid bin
{
resultingPrecipValue = valueGrid[col][row];
// adjust grid bin with actual gage by the prism factor
if (prismStationGrid[col][row] > 0) {
double prismStationValue = prismStationGrid[col][row] * 25.4;
double prismGridValue = hrap_grid.isoh[isom][col][row];
double prismFactor = (double) prismGridValue
/ prismStationValue;
resultingPrecipValue *= prismFactor;
} else {
resultingPrecipValue = 0.0;
}
// pcp.value[row][col] is the value of grid,
// so we don't need to estimate a value for [row][col]
}
else // this grid location requires an estimate to be generated
{
resultingPrecipValue = estimateValue(isom, col, row,
hrap_grid);
}
if (resultingPrecipValue >= 0.0) {
int precipInHundredthsOfMm = (int) Math
.floor((resultingPrecipValue * 100.0));
if (should_accumulate) { // for case where we want to make
// 24 = 4 6hr periods added
// together
pcp.value[col][row] += precipInHundredthsOfMm;
} else {
pcp.value[col][row] = precipInHundredthsOfMm;
}
}
} /* end for (col = 0 ... */
} /* end for (row = 0 ... */
// System.out.println(header + "maxPrecip in hundredths of mm = " +
// maxPrecip);
int time_pos;
/*
* notice that time_pos is a variable defined inside the function, and
* its value do not need to be limited as 0,1,2,3,or 4. Here it is
* assigned with bigger numbers.
*/
if (pcpn_time_step == 0) // one of the 6-hr periods
{
time_pos = pcpn_day * 4 + 3 - pcpn_time;
} else // 24 hr
{
time_pos = 40 + pcpn_day;
}
if (save_grids) {
/*
* pcp_in_use[i] = 1 -- grids rendered via Render button OR Save
* Level2 option = -1 --grids for this time period not rendered
* (initialization value)
*/
pcp_in_use[time_pos] = 1;
/*
* results of grid rendering routines (render_t, render_t6,
* render_pcp, render_z) are written to scratch files using the
* write_file routine. scratch file is stored in the scratch
* directory.
*/
ReadQPFGrids rqp = new ReadQPFGrids();
rqp.write_file("pcp", time_pos, pcp);
}
} // end render_pcp_internal()
private double estimateValue(int isom, int col, int row, Hrap_Grid hrap_grid) {
// String header = "RenderPcpBlocking.estimateValue(): ";
int r;
int c;
double estimatedPrecipValue = 0.0;
if (hrap_grid.isoh[isom][col][row] < 0.01) {
estimatedPrecipValue = 0;
return estimatedPrecipValue; // can't do anything more, quit
}
// look through surrounding grid bins only for
// values to be used in the distance-weighted interpolation
// set to open and level = 0
north.reset();
south.reset();
east.reset();
west.reset();
// initialize
totalWeightedValue = 0.0;
totalDistanceWeight = 0.0;
usedGridCellCount = 0;
rowMax = row;
rowMin = row;
colMax = col;
colMin = col;
prevRowMax = rowMax;
prevRowMin = rowMin;
prevColMax = colMax;
prevColMin = colMin;
while (north.isOpen() || south.isOpen() || east.isOpen()
|| west.isOpen()) {
// expand search levels as appropriate
// changes rowMin, rowMax, colMin, colMax
expandGridSearch(col, row, hrap_grid);
if (rowMin < prevRowMin) // grew the top side
{
r = rowMin;
for (c = colMin; c <= colMax; c++) {
processGriddedStationValues(col, row, c, r, hrap_grid);
}
} else // didn't grow the top side
{
if (colMin < prevColMin) // still need to check top left corner
{
c = colMin;
r = rowMin;
processGriddedStationValues(col, row, c, r, hrap_grid);
}
if (colMax > prevColMax) // still need to check top right corner
{
c = colMax;
r = rowMin;
processGriddedStationValues(col, row, c, r, hrap_grid);
}
}
if (rowMax > prevRowMax) // grew the bottom side
{
r = rowMax;
for (c = colMin; c <= colMax; c++) {
processGriddedStationValues(col, row, c, r, hrap_grid);
}
} else // didn't grow the bottom side
{
if (colMin < prevColMin) // still need to check bottom left
// corner
{
c = colMin;
r = rowMax;
processGriddedStationValues(col, row, c, r, hrap_grid);
}
if (colMax > prevColMax) // still need to check bottom right
// corner
{
c = colMax;
r = rowMax;
processGriddedStationValues(col, row, c, r, hrap_grid);
}
}
if (colMin < prevColMin) // grew left side
{
c = colMin;
for (r = rowMin + 1; r < rowMax; r++) {
processGriddedStationValues(col, row, c, r, hrap_grid);
}
}
if (colMax > prevColMax) // grew right side
{
c = colMax;
for (r = rowMin + 1; r < rowMax; r++) {
processGriddedStationValues(col, row, c, r, hrap_grid);
}
}
if (usedGridCellCount >= MIN_PREFERRED_USED_GRID_CELLS) // have
// enough
// cells to
// look at,
// can quit
// now
{
north.close();
south.close();
east.close();
west.close();
// System.out.println(header +
// "met minimum cell preference, resultingPrecipValue = " +
// resultingPrecipValue);
}
} /* end while (northLevelOpen ... */
// set weighted value to the cell or set value to 0.0 if there is not
// enough data
if (usedGridCellCount >= MIN_REQUIRED_USED_GRID_CELLS) {
estimatedPrecipValue = totalWeightedValue / totalDistanceWeight;
// System.out.println(header +
// "met minimum cell requirement, resultingPrecipValue = " +
// resultingPrecipValue);
} else // set to zero precip
{
estimatedPrecipValue = 0.0;
}
return estimatedPrecipValue;
} // end estimateValue()
// *--------------------------------------------------------------------------
void processGriddedStationValues(int renderingCol, int renderingRow,
int gridCol, int gridRow, Hrap_Grid hrap_grid) {
String header = "RenderPcpBlocking.processGriddedStationValues(): ";
int usedCells = 0;
// sprintf(message,
// "renderingCol = %d, renderingRow = %d, gridCol = %d, gridRow = %d \n",
// renderingCol, renderingRow, gridCol, gridRow);
// logMessage(message);
if ((gridCol < 0) || (gridCol > hrap_grid.maxi) || (gridRow < 0)
|| (gridRow > hrap_grid.maxj)) {
System.out.println(header + "OUT OF RANGE gridCol = " + gridCol
+ " gridRow = " + gridRow);
}
double gageValue = valueGrid[gridCol][gridRow];
if (gageValue >= 0.0) // there is a gage
// located at (gridCol,gridRow)
// with a valid precip value
{
usedCells = adjustWeights(gageValue, gridRow, gridCol,
renderingRow, renderingCol, hrap_grid, isom,
prismStationGrid);
usedGridCellCount += usedCells;
// if data was found, close off a direction, usually 2 directions,
// such as north and west
if (usedCells > 0) {
determineDirectionFoundAndCloseOff(renderingCol, renderingRow,
gridCol, gridRow);
}
}
return;
} // end processGriddedStationValues()
// *--------------------------------------------------------------------------
void expandGridSearch(int col, int row, Hrap_Grid hrap_grid) {
// expand search levels as appropriate
north.expandSearchIfAllowed();
south.expandSearchIfAllowed();
east.expandSearchIfAllowed();
west.expandSearchIfAllowed();
// save previous values of row and col min and max
prevRowMax = rowMax;
prevRowMin = rowMin;
prevColMax = colMax;
prevColMin = colMin;
// determine nested for loop ranges
rowMax = row + north.getLevel();
if (rowMax >= hrap_grid.maxj) {
rowMax = hrap_grid.maxj - 1;
north.close();
}
rowMin = row - south.getLevel(); // row
if (rowMin < 0) {
rowMin = 0;
south.close();
}
colMin = col - west.getLevel();
if (colMin < 0) {
colMin = 0;
west.close();
}
colMax = col + east.getLevel();
if (colMax >= hrap_grid.maxi) {
colMax = hrap_grid.maxi - 1;
east.close();
}
return;
} // end expandGridSearch()
/*--------------------------------------------------------------------------*/
void determineDirectionFoundAndCloseOffSimpleVersion(int renderingCol,
int renderingRow, int stationCol, int stationRow) {
if (stationRow < renderingRow) {
south.close();
} else if (stationRow > renderingRow) {
north.close();
}
if (stationCol < renderingCol) {
west.close();
} else if (stationCol > renderingCol) {
east.close();
}
}
/*--------------------------------------------------------------------------*/
void determineDirectionFoundAndCloseOff(int renderingCol, int renderingRow,
int stationCol, int stationRow) {
final int closeEnoughToBeEqual = 2;
// String header =
// "RenderPcpBlocking.determineDirectionFoundAndCloseOff(): ";
// consider taking a diff and a point is considered in a straightline if
// its difference is < 3 from the grid bin to render
int northSouthDifference = Math.abs(stationRow - renderingRow);
int eastWestDifference = Math.abs(stationCol - renderingCol);
boolean isNorthOrSouth = false;
boolean isEastOrWest = false;
if (northSouthDifference - eastWestDifference <= closeEnoughToBeEqual) {
isNorthOrSouth = true;
isEastOrWest = true;
} else if (northSouthDifference > eastWestDifference) {
isNorthOrSouth = true;
} else {
isEastOrWest = true;
}
if (usingSingleDirectionCloseOutMode) {
// System.out.println(header +
// "Using usingSingleDirectionCloseOutMode difference-based close off.");
if (isNorthOrSouth) {
// this point functions as the north-south representative, since
// it is primarily north or south
if (stationRow < renderingRow) {
south.close();
} else if (stationRow > renderingRow) {
north.close();
}
}
if (isEastOrWest) {
if (stationCol < renderingCol) {
west.close();
} else if (stationCol > renderingCol) {
east.close();
}
}
}
else // in mode in which points represent 2 directions (unless directly
// North-south or east-west)
{
// System.out.println(header +
// "Using traditional difference cutoff.");
if (stationRow < renderingRow) {
south.close();
} else if (stationRow > renderingRow) {
north.close();
}
if (stationCol < renderingCol) {
west.close();
} else if (stationCol > renderingCol) {
east.close();
}
}
return;
} // determineDirectionFoundAndCloseOff()
/*--------------------------------------------------------------------------*/
void allocateGrids(Hrap_Grid hrap_grid) {
int maxI = hrap_grid.maxi;
int maxJ = hrap_grid.maxj;
binStationCount = new int[maxI][maxJ];
valueGrid = new double[maxI][maxJ];
prismStationGrid = new double[maxI][maxJ];
return;
}
/*--------------------------------------------------------------------------*/
void initializeGrids(Hrap_Grid hrap_grid, boolean should_accumulate) {
int i = 0;
int j = 0;
/* initialize grids */
for (i = 0; i < hrap_grid.maxi; i++) {
for (j = 0; j < hrap_grid.maxj; j++) {
binStationCount[i][j] = 0;
valueGrid[i][j] = DailyQcUtils.MOSAIC_DEFAULT; // precip in
// inches
prismStationGrid[i][j] = DailyQcUtils.MOSAIC_DEFAULT; // prism
// station
// value
// mapped
// to
// grid
// (this
// algorithm
// only)
if (!should_accumulate) {
// in special 24hr = sum of 4 6hr periods mode,
// we accumulate in this grid, so we don't reinit every time
pcp.value[i][j] = (int) DailyQcUtils.MOSAIC_DEFAULT; // final
// precip
// in
// hundredths
// of
// mm
}
}
}
}
/*--------------------------------------------------------------------------*/
void placeStationsInGrid(int pcpn_day, int pcpn_time, int pcpn_time_step,
int max_stations, ArrayList<Station> stationList,
Hrap_Grid hrap_grid, Pdata pdata[]) {
int method = DailyQcUtils.method;
String header = "RenderPcpBlocking.placeStationsInGrid(): ";
int time_pos;
if (pcpn_time_step == 0) {
time_pos = pcpn_time; // for 6 hour data: 0,1,2,3.
} else {
time_pos = 4; // for 24 hour data
}
int hx, hy;
int h = 0;
int noPrismCount = 0;
// System.out.println("max_stations = " + max_stations);
int maxPrecip = 0;
for (h = 0; h < max_stations; h++) {
Station station = stationList.get(h);
hx = (int) (station.hrap_x - hrap_grid.hrap_minx);
hy = (int) (station.hrap_y - hrap_grid.hrap_miny);
/* check that station is within the site's area */
if (hx >= hrap_grid.maxi || hy >= hrap_grid.maxj || (hx < 0)
|| (hy < 0)) {
// This station cannot be used, because its coordinates are out
// of range
continue;
}
// debug only
int stationCount = binStationCount[hx][hy];
double precipValue = pdata[pcpn_day].stn[h].frain[time_pos].data;
short qualCode = pdata[pcpn_day].stn[h].frain[time_pos].qual;
// skip if not an acceptable quality code
if (qualCode != SCREENED && qualCode != VERIFIED
&& qualCode != TIMEDISTRIBUTED && qualCode != QUESTIONABLE
&& qualCode != PARTIAL && qualCode != MANUAL) {
continue;
}
if ((method == 2) && (station.isoh[isom] <= 0)) // no prism data for
// the station
{
noPrismCount++;
continue;
}
/* if station value is missing, ignore */
if (precipValue >= 0.0) {
int precipIn_h_mm = (int) Math.floor(precipValue * 100.0);
if (precipIn_h_mm > maxPrecip) {
maxPrecip = precipIn_h_mm;
}
// we have data and no other station has been assigned to this
// bin yet
if (binStationCount[hx][hy] == 0) {
binStationCount[hx][hy] = 1;
valueGrid[hx][hy] = precipValue;
prismStationGrid[hx][hy] = station.isoh[isom];
usableStationCount++;
}
else if (stationCount > 0) // we have at least 1 value for this
// grid location
{
double valueGridTotalValue = (valueGrid[hx][hy] * stationCount)
+ precipValue;
double prismGridTotalValue = (prismStationGrid[hx][hy] * stationCount)
+ station.isoh[isom];
binStationCount[hx][hy]++;
stationCount++;
double newGridAvgValue = valueGridTotalValue / stationCount;
double newPrismAvgValue = prismGridTotalValue
/ stationCount;
valueGrid[hx][hy] = newGridAvgValue;
prismStationGrid[hx][hy] = newPrismAvgValue;
usableStationCount++;
} // end else
} // end if
} // end for (h = 0; h < max_stations; h++)
System.out.println(header + " maxPrecip in hundredths of mm = "
+ maxPrecip);
// System.out.println(header +
// " number of stations missing PRISM data = " + noPrismCount);
// System.out.println(header + " usableStationCount = " +
// usableStationCount);
}
// ---------------------------------------------------------------------------------------
/*
* get the token value of token mpe_24hr_grid_gen_method. This token will
* determine how we generate the 24hr grid. We can either use the 24hr gage
* values, which is the old way, or we can use four 6hr gage values and add
* them together.
*/
/* there is some problem with the static */
private void render24hrPcpUsingFour6hr(int pcpn_day, int pcpn_time,
int numPstations, ArrayList<Station> stationList,
Hrap_Grid hrap_grid, Pdata[] pdata, int[] pcp_in_use) {
/* initialization of the pcp.value */
for (int i = 0; i < hrap_grid.maxi; i++) {
for (int j = 0; j < hrap_grid.maxj; j++) {
pcp.value[i][j] = 0;
}
}
boolean save_grids = false;
boolean should_accumulate = true;
for (int k = 0; k < 4; k++) {
int pcpn_time_internal = k;
int pcpn_time_step = 0; // means it is one of the 6-hr periods
render_pcp_internal(pcpn_day, pcpn_time_internal, pcpn_time_step,
numPstations, stationList, hrap_grid, pdata, pcp_in_use,
save_grids, should_accumulate);
}
} // end render24hrPcpUsingFour6hr()
// --------------------------------------------------------------------------
int adjustWeights(double originalValue, int otherRow, int otherColumn,
int renderingRow, int renderingColumn, Hrap_Grid hrap_grid,
int monthIndex, double[][] prismStationGrid) {
String header = "RenderPcpBlocking.adjustWeights(): ";
final double MIN_DISTANCE = 0.00001;
int usedCount = 0;
double distanceWeight = 0.0;
double weightedValue = 0.0;
int rowDiff = otherRow - renderingRow;
int colDiff = otherColumn - renderingColumn;
double distanceSquared = (rowDiff * rowDiff) + (colDiff * colDiff);
// int maxDistSquared = DailyQcUtils.mpe_dqc_grid_max_dist *
// DailyQcUtils.mpe_dqc_grid_max_dist;
if (distanceSquared < MIN_DISTANCE) {
distanceSquared = MIN_DISTANCE;
}
/*
* mpe_dqc_grid_max_dist = max distance of influence of a gage in units
* of grid bins
*/
if (distanceSquared <= maxDistSquared) {
distanceWeight = 1.0 / distanceSquared;
weightedValue = originalValue * distanceWeight;
// adjust by PRISM factor
if (prismStationGrid[renderingColumn][renderingRow] > 0) {
double prismFactor = (double) hrap_grid.isoh[monthIndex][renderingColumn][renderingRow]
/ (prismStationGrid[renderingColumn][renderingRow] * 25.4);
weightedValue *= prismFactor;
System.out.println(header + " prismFactor > 0 " + prismFactor);
}
totalWeightedValue += weightedValue;
totalDistanceWeight += distanceWeight;
usedCount++;
}
return usedCount;
}
// ---------------------------------------------------------------------------------------
}

View file

@ -0,0 +1,603 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.mpe.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.raytheon.uf.common.ohd.AppsDefaults;
import com.raytheon.viz.mpe.util.DailyQcUtils.Hrap_Grid;
import com.raytheon.viz.mpe.util.DailyQcUtils.Pcp;
import com.raytheon.viz.mpe.util.DailyQcUtils.Pdata;
import com.raytheon.viz.mpe.util.DailyQcUtils.Station;
/**
* DESCRIPTION: Maps precipitation station values to an HRAP grid. Produces the
* DailyQC version of the GageOnly analysis.
*
* <pre>
*
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 11, 2009 snaples Initial creation
* May 02, 2011 8962 snaples Added render24hrPcpUsingFour6hr() method
*
* </pre>
*
* @author snaples
* @version 1.0
*/
public class RenderPcpStandard {
private static final int MINIMUM_NEAREST_NEIGHBOR_GAGES = 4;
private static final int SUFFICIENT_NEAREST_NEIGHBOR_GAGES = 10;
private static boolean first = true;
Pcp pcp = DailyQcUtils.pcp;
/*
* QC codes
*/
private static final int MISSING = -1;
private static final int STANDARD = 0;
private static final int SCREENED = 0;
private static final int FAILED = 1;
private static final int MANUAL = 2;
private static final int QUESTIONABLE = 3;
private static final int PARTIAL = 4;
private static final int ESTIMATED = 5;
private static final int TIMEDISTRIBUTED = 6;
private static final int VERIFIED = 8;
private static final String MPE_DQC_GRID_RENDERING_METHOD_TOKEN = "mpe_dqc_grid_render_method";
private static final int maxDistSquared = DailyQcUtils.mpe_dqc_grid_max_dist
* DailyQcUtils.mpe_dqc_grid_max_dist;
private static final double BOGUS_ESTIMATED_GRID_VALUE = -1.0;
// weighting variables
// consider making these members of a local variable of an inner class
private double totalWeightedValue = 0;
private double totalDistanceWeight = 0;
/**
* Converts point precipitation data in struct pdata to hrap grid. The 20
* closest stations are precalculated for each grid point - this speeds
* computations for data sets with many precipitation points. If there are
* no good precipitation points for a grid point, then a recalculation is
* made using all precipitation points. 1/R**2 interpolation is used. If
* requested, the final interpolation is scaled using seasonal isohyets. The
* grid is saved as a disk file and used later for a raster or vector (HRAP)
* plot.
*
* @param m
* @param k
* @param mk
* @param numPstations
* @param
* @param hrap_grid
* @param pdata
* @param pcp_in_use
*/
// ---------------------------------------------------------------------------------------
public void render_pcp(int pcpn_day, int pcpn_time, int pcpn_time_step,
int numPstations, ArrayList<Station> precip_stations,
Hrap_Grid hrap_grid, Pdata[] pdata, int[] pcp_in_use) {
// String header = "RenderPcpStandard.render_pcp_original(): ";
int isom = DailyQcUtils.isom;
int method = DailyQcUtils.method;
int mpe_dqc_max_precip_neighbors = DailyQcUtils.mpe_dqc_max_precip_neighbors;
int i, j, h, hh, time_pos;
int usedStationCount = 0;
int totals[] = new int[5];
for (i = 0; i < 5; i++) {
totals[i] = 0;
}
/*
* pcpn_time_step is a function parameter. It specifies whether to
* interpolate 6hr or 24hr HRAP grid
*/
/*
* pcpn_time is a function parameter. It specifies which 6hr HRAP grid
* to generate. It takes 0,1,2,or 3 to represent different 6hr period of
* a day.
*/
/*
* time_pos is assigned a value of 0,1,2,or 3 (for 6hr data) or 4 (for
* 24hr data). This value is used in
* pdata[pcpn_day].stn[hh].frain[time_pos].data to control whether to
* retrieve 6hr data or 24hr data.
*/
if (pcpn_time_step == 0) {
time_pos = pcpn_time; // for 6 hour data: 0,1,2,3.
} else {
time_pos = 4; // for 24 hour data
/*
* in case the 24hr grid rendering is required, we check
* 24hr_grid_gen_method_token() to determine how to generate the
* grid. New Post OB9.2
*/
if (getTokenValue24hrGridGenMeth() == 1) {
render24hrPcpUsingFour6hr(pcpn_day, pcpn_time, numPstations,
precip_stations, hrap_grid, pdata, pcp_in_use);
return;
}
}
/* begin to interpolate value for each bin in the HRAP grid */
/*
* to interpolate, two quantities are needed first: value and distance.
* They are calculated by using the neighboring stations.
*/
for (i = 0; i < hrap_grid.maxi; i++) {
for (j = 0; j < hrap_grid.maxj; j++) {
/*
* Check if the grid cell is covered by an HSA. If not, then do
* not estimate precipitation for it.
*/
if (hrap_grid.owner[i][j] == -1) {
pcp.value[i][j] = 0;
continue;
}
totalDistanceWeight = 0.0;
totalWeightedValue = 0.0;
usedStationCount = 0;
boolean usedStation = false;
/*
* the following for loop is to calculate two quantities: value
* and distance, which later on, are used to interpret the HRAP
* grid.
*/
/*
* It uses neighbor stations of a HRAP grid bin to calculate
* value and distance.
*/
/* for each neighbor station of the grid bin, do the following */
/* For each of the closest stations. */
for (h = 0; h < mpe_dqc_max_precip_neighbors; h++) {
// hh is index of stations
hh = hrap_grid.gage[i][j].index[h];
int gageIndex = hh;
usedStation = processStation(gageIndex, isom, i, j,
pcpn_day, pcpn_time, time_pos, method,
precip_stations, hrap_grid, pdata, pcp_in_use,
false);
if (usedStation) {
usedStationCount++;
}
if (usedStationCount == SUFFICIENT_NEAREST_NEIGHBOR_GAGES) {
break;
}
}
/*
* end for loop (h = 0; h < mpe_dqc_max_precip_neighbors;h++)
* the above for loop is for each neighbor station.
*/
/*
* the above for loop is to calculate value and distance, which
* later on, are used to interpret the HRAP grid
*/
/*
* the resulting htotal is the valid number of neighbor stations
* that are used to calculate value and distance, which later
* on, are used to interpret the HRAP grid
*/
/*
* if there is not enough valid neighbor station, such as
* usedStationCount < MINIMUM_NEAREST_NEIGHBOR_GAGES the code
* below handle this situation. Basically, the code recalculate
* the value and distance using all the stations -- see the for
* (h = 0; h < max_stations; h++) loop below.
*/
if (usedStationCount < MINIMUM_NEAREST_NEIGHBOR_GAGES) {
totalWeightedValue = 0.0;
totalDistanceWeight = 0.0;
usedStationCount = 0;
for (h = 0; h < numPstations; h++) {
int gageIndex = h;
usedStation = processStation(gageIndex, isom, i, j,
pcpn_day, pcpn_time, time_pos, method,
precip_stations, hrap_grid, pdata, pcp_in_use,
true);
if (usedStation) {
usedStationCount++;
}
}
}/*
* end the handling of special case : if (usedStationCount <
* MINIMUM_NEAREST_NEIGHBOR_GAGES),
*/
/* which means there are not enough neighboring stations */
// found no usable gages
if (usedStationCount == 0) {
pcp.value[i][j] = 0;
}
else {
pcp.value[i][j] = (int) (totalWeightedValue
/ totalDistanceWeight * 100.0);
}
if (pcp.value[i][j] < .01) {
pcp.value[i][j] = 0;
}
} // end for (j = 0; j < hrap_grid.maxj; j++) {
} // end for (i = 0; i < hrap_grid.maxi; i++) {
if (pcpn_time_step == 0) {
time_pos = pcpn_day * 4 + 3 - pcpn_time;
} else {
time_pos = 40 + pcpn_day;
}
// notice that time_pos is a variable defined inside the function, and
// its value do not need to be limited as 0,1,2,3,or 4. Here it is
// assigned with bigger numbers.
// time_pos = 40 + pcpn_day;
// pcp_in_use[i] = 1 -- grids rendered via Render button OR Save Level2
// option
// = -1 --grids for this time period not rendered (initialization value)
pcp_in_use[time_pos] = 1;
ReadQPFGrids rqp = new ReadQPFGrids();
rqp.write_file("pcp", time_pos, pcp);
}
private boolean processStation(int gageIndex, int isom, int col, int row,
int pcpn_day, int pcpn_time, int time_pos, int method,
ArrayList<Station> stationList, Hrap_Grid hrap_grid, Pdata[] pdata,
int[] pcp_in_use, boolean checkDistance) {
boolean usedStation = false;
Station station = stationList.get(gageIndex);
float value = pdata[pcpn_day].stn[gageIndex].frain[time_pos].data;
if (value < 0) {
return usedStation;// false
}
int qualityCode = pdata[pcpn_day].stn[gageIndex].frain[time_pos].qual;
if (qualityCode != 0 && qualityCode != 8 && qualityCode != 6
&& qualityCode != 3 && qualityCode != 4 && qualityCode != 2) {
return usedStation; // false
}
if (method == 2 && station.isoh[isom] <= 0) {
return usedStation; // false
}
/*
* determine distance between grid bin and the station in question of
* the grid and station in question
*/
double distanceX = (col + (hrap_grid.hrap_minx - station.hrap_x));
double distanceY = (row + (hrap_grid.hrap_miny - station.hrap_y));
double distanceSquared = (distanceX * distanceX)
+ (distanceY * distanceY);
if (distanceSquared < .00001) {
distanceSquared = .00001;
}
if (checkDistance) {
if (distanceSquared > maxDistSquared) // too far away, don't use the
// station
{
return usedStation; // false, bail out, don't adjust weight with
// this reading
}
}
double distanceWeight = 1 / distanceSquared;
double weightedValue = value * distanceWeight;
float prismValue = station.isoh[isom];
if (method == 2 && prismValue > 0) {
weightedValue = weightedValue * hrap_grid.isoh[isom][col][row]
/ (prismValue * 25.4);
}
totalWeightedValue += weightedValue;
totalDistanceWeight += distanceWeight;
usedStation = true;
return usedStation;
}
// ---------------------------------------------------------------------------------------
/*
* get the token value of token mpe_24hr_grid_gen_method. This token will
* determine how we generate the 24hr grid. We can either use the 24hr gage
* values, which is the old way, or we can use four 6hr gage values and add
* them together.
*/
/* there is some problem with the static */
/**
* @param pcpn_day
* @param pcpn_time
* @param numPstations
* @param precip_stations
* @param hrap_grid
* @param pdata
* @param pcp_in_use
*/
private void render24hrPcpUsingFour6hr(int pcpn_day, int pcpn_time,
int numPstations, ArrayList<Station> precip_stations,
Hrap_Grid hrap_grid, Pdata[] pdata, int[] pcp_in_use) {
int i, j, k, h, hh, time_pos;
boolean usedStation = false;
int isom = DailyQcUtils.isom;
int method = DailyQcUtils.method;
int totals[] = new int[5];
int all_total = 0;
int neighbor_total = 0;
int usedStationCount;
for (i = 0; i < 5; i++) {
totals[i] = 0;
}
/*
* pcpn_time_step is function parameter. It specifies whether to
* interpolate 6hr or 24hr HRAP grid
*/
/*
* pcpn_time is a function parameter. It specifies which 6hr HRAP grid
* to generate. It takes 0,1,2,or 3 to represent different 6hr period of
* a day.
*/
/*
* time_pos is assigned a value of 0,1,2,or 3 (for 6hr data) or 4 (for
* 24hr data). This value is used in
* pdata[pcpn_day].stn[hh].frain[time_pos].data to control whether to
* retrieve 6hr data or 24hr data.
*/
/* initialization of the pcp.value */
for (i = 0; i < hrap_grid.maxi; i++) {
for (j = 0; j < hrap_grid.maxj; j++) {
pcp.value[i][j] = 0;
}
}
/*
* begin to interpolate 4 6hr grids. At the end of each iteration, the
* calculated interpolation value is added to pcp.value[i][j].
*/
/*
* time_pos is assigned a value of 0,1,2,or 3 (for four 6hr data). This
* value is used in pdata[pcpn_day].stn[hh].frain[time_pos].data to
* retrieve 6hr data.
*/
for (k = 0; k < 4; k++) {
time_pos = k; /* for 6 hour data: 0, 1,2,3. */
/* begin to interpolate value for each bin in the HRAP grid */
/*
* to interpolate, two quantities are needed first: value and
* distance. They are calculated by using the neighboring stations.
*/
for (i = 0; i < hrap_grid.maxi; i++) {
for (j = 0; j < hrap_grid.maxj; j++) {
/*
* Check if the grid cell is covered by an HSA. If not, then
* do not estimate precipitation for it.
*/
if (hrap_grid.owner[i][j] == -1) {
pcp.value[i][j] = 0;
continue;
}
totalDistanceWeight = 0.0;
totalWeightedValue = 0.0;
usedStationCount = 0;
/*
* for each neighbor station of the grid bin, do the
* following
*/
int mpe_dqc_max_precip_neighbors = DailyQcUtils.mpe_dqc_max_precip_neighbors;
for (h = 0; h < mpe_dqc_max_precip_neighbors; h++) {
hh = hrap_grid.gage[i][j].index[h];/*
* hh is index of
* stations
*/
int gageIndex = hh;
usedStation = processStation(gageIndex, isom, i, j,
pcpn_day, pcpn_time, time_pos, method,
precip_stations, hrap_grid, pdata, pcp_in_use,
false);
if (usedStation) {
usedStationCount++;
}
if (usedStationCount == SUFFICIENT_NEAREST_NEIGHBOR_GAGES) {
break;
}
}
if (usedStationCount < MINIMUM_NEAREST_NEIGHBOR_GAGES) {
// not enough gages, so extend search to all gages
totalWeightedValue = 0.0;
totalDistanceWeight = 0.0;
usedStationCount = 0;
for (h = 0; h < numPstations; h++) {
int gageIndex = h;
usedStation = processStation(gageIndex, isom, i, j,
pcpn_day, pcpn_time, time_pos, method,
precip_stations, hrap_grid, pdata,
pcp_in_use, false);
if (usedStation) {
usedStationCount++;
}
}
neighbor_total++;
}
if (usedStationCount != 0) {
pcp.value[i][j] += (int) ((totalWeightedValue / totalDistanceWeight) * 100);
}
/*
* if (pcp.value[i][j] < .01) { pcp.value[i][j] = 0; }
*/
all_total++;
} /* end of for loop (j = 0; j < hrap_grid.maxj; j++) */
} /* end of for loop (i = 0; i < hrap_grid.maxi; i++) */
/* At this moment, the interpretation of HRAP grid is done */
}/*
* end of the ( k = 0; k<4; k++) loop, which interpolates 4 6hr HRAP
* grid.
*/
/* final adjustment of the pcp.value */
for (i = 0; i < hrap_grid.maxi; i++) {
for (j = 0; j < hrap_grid.maxj; j++) {
if (pcp.value[i][j] < .01) { // this doesn't really make sense,
// since this is an integer
pcp.value[i][j] = 0;
}
}
}
/* time_pos = pcpn_day * 4 + 3 - pcpn_time; */
time_pos = 40 + pcpn_day;
/*
* pcp_in_use[i] = 1 -- grids rendered via Render button OR Save Level2
* option = -1 --grids for this time period not rendered (initialization
* value)
*/
pcp_in_use[time_pos] = 1;
/*
* results of grid rendering routines (render_t, render_t6, render_pcp,
* render_z) are written to scratch files using the write_file routine.
* scratch file is stored in the scratch directory.
*/
ReadQPFGrids rqp = new ReadQPFGrids();
rqp.write_file("pcp", time_pos, pcp);
} // end render24hrPcpUsingFour6hr()
// ---------------------------------------------------------------------------------------
int getTokenValue24hrGridGenMeth() {
int token_of_24hr_grid_gen_method = 0;
if (first == true) {
String tokenName = "mpe_dqc_24hr_precip_grid_meth";
String dqc24hrPrecipMeth;
// char message[GAGEQC_MESSAGE_LEN] = { '\0' };
AppsDefaults appsDefaults = AppsDefaults.getInstance();
dqc24hrPrecipMeth = appsDefaults.getToken(tokenName);
if (dqc24hrPrecipMeth != null) {
/* allowed token values: (ACCUM_6HR, USE_24HR) */
if (dqc24hrPrecipMeth.equalsIgnoreCase("ACCUM_6HR")) {
token_of_24hr_grid_gen_method = 1;
}
}
first = false;
}
return token_of_24hr_grid_gen_method;
}
// -----------------------------------------------------------------------------------
}

View file

@ -24,7 +24,6 @@ Export-Package: gov.noaa.nws.ncep.viz.common,
gov.noaa.nws.ncep.viz.common.customprojection,
gov.noaa.nws.ncep.viz.common.dbQuery,
gov.noaa.nws.ncep.viz.common.display,
gov.noaa.nws.ncep.viz.common.gpdQuery,
gov.noaa.nws.ncep.viz.common.graphicUtil,
gov.noaa.nws.ncep.viz.common.preferences,
gov.noaa.nws.ncep.viz.common.soundingQuery,
@ -35,7 +34,5 @@ Import-Package: com.raytheon.uf.common.comm,
com.raytheon.uf.common.parameter,
com.raytheon.viz.pointdata,
com.vividsolutions.jts.geom,
gov.noaa.nws.ncep.common.dataplugin.gpd.product,
gov.noaa.nws.ncep.common.dataplugin.gpd.query,
javax.measure.unit

View file

@ -348,7 +348,7 @@ fi
if [ "${1}" = "-viz" ]; then
buildRPM "awips2"
# buildRPM "awips2-common-base"
buildRPM "awips2-common-base"
# buildRPM "awips2-rcm"
# buildRPM "awips2-hydroapps-shared"
# buildRPM "awips2-notification"
@ -366,11 +366,11 @@ if [ "${1}" = "-edex" ]; then
#buildRPM "awips2-common-base"
# buildRPM "awips2-adapt-native"
#buildRPM "awips2-python-qpid"
buildRPM "awips2-cli"
# buildRPM "awips2-gfesuite-client"
# buildRPM "awips2-gfesuite-server"
buildRPM "awips2-ncep-database"
buildRPM "awips2-python-dynamicserialize"
# buildRPM "awips2-cli"
buildRPM "awips2-gfesuite-client"
buildRPM "awips2-gfesuite-server"
# buildRPM "awips2-ncep-database"
# buildRPM "awips2-python-dynamicserialize"
buildEDEX
if [ $? -ne 0 ]; then
exit 1