Merge branch 'omaha_16.2.1' into omaha_16.2.1-lx

Conflicts:
	cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/TextEditorDialog.java


Former-commit-id: 50282f22b76f6d393c1918652a9e0da8696847f0
This commit is contained in:
Steve Harris 2016-02-29 13:18:08 -06:00
commit bbd0a34445
23 changed files with 600 additions and 285 deletions

View file

@ -54,7 +54,7 @@ def start(queue, append, sites, climateDir):
#mythread.start()
# Process Data button
def process(queue, stnPickle):
def process(queue, stnPickle, append, sites, climateDir):
import ClimateDataUpdate
import cPickle as pickle
o = pickle.loads(stnPickle)

View file

@ -112,6 +112,8 @@ import com.vividsolutions.jts.geom.LineString;
* 09-09-2014 RM #657 Qinglu Lin handle StormTrackState.trackType is null.
* 09-25-2014 ASM #16773 D. Friedman Fix NPE.
* 10-10-2014 ASM #16844 D. Friedman Prevent some errors when moving track.
* 02-09-2016 ASM #18421 D. Friedman Don't call ToolsDataManager.setStormTrackData
* if there is no storm motion.
* </pre>
*
* @author mschenke
@ -1454,6 +1456,9 @@ public class StormTrackDisplay implements IRenderable {
}
private void postData(StormTrackState state) {
if (!(state.speed > 0)) {
return;
}
StormTrackData data = new StormTrackData();
Coordinate[] coords = new Coordinate[state.timePoints.length];
for (int i = 0; i < coords.length; ++i) {

View file

@ -3,7 +3,7 @@
# support, and with no warranty, express or implied, as to its usefulness for
# any purpose.
#
# CoastalThreat
# StormSurgeThreat
#
# Author: Tom LeFebvre/Pablo Santos
# April 20, 2012 - To use gridded MSL TO NAVD and MSL to MLLW
@ -19,13 +19,13 @@
# Sept 18, 2014: Added code to pull grids from NHC via ISC if PHISH not
# Available on time. Left inactive (commented out) for the moment until that can be fully tested later
# in 2014 or in 2015.
# May 22, 2015 (LEFebvre/Santos): Added option to create null grids and manual grids when
# PSURGE not available. Added checks for current guidance for PHISH and ISC options.
#
# Last Modified: LeFebvre/Santos, July 27, 2015: Expanded Manual options to include Replace and Add options.
# This allows sites to specify manually different threat levels across different edit areas and time ranges.
# See 2015HTIUserGuide for details.
#
# Feb 11, 2016 LeFebvre (16.1.2): Added code to create zero grids and manual grids when
# PSURGE not available. Added checks for current guidance for PHISH and ISC options.
# ----------------------------------------------------------------------------
# The MenuItems list defines the GFE menu item(s) under which the
# Procedure is to appear.
@ -179,12 +179,16 @@ class Procedure (SmartScript.SmartScript):
weName = "Surge" + pctStr + "Pctincr"
#print "Attempting to retrieve: ", weName, level
trList = self.getWEInventory(dbName, weName, level)
if len(trList) == 0:
self.statusBarMsg("No grids available for model:" + dbName, "S")
return None
# get the StormSurgeProb inventory
surgeTRList = self.getWEInventory(dbName, weName, level)
if len(surgeTRList) == 0:
self.statusBarMsg("No PHISH grid found.", "U")
return
# Make timeRanges for all 13 grids. Start with the beginning of the first Phish grid
baseTime = int(surgeTRList[0].startTime().unixTime() / (6 * 3600)) * (6 * 3600) #snap to 6 hour period
trList = self.makeTimingTRs(baseTime)
n = 1
for tr in trList:
start = tr.startTime().unixTime() - 6*3600
@ -197,7 +201,13 @@ class Procedure (SmartScript.SmartScript):
end = tr.startTime().unixTime()
tr6 = TimeRange.TimeRange(AbsTime.AbsTime(start),
AbsTime.AbsTime(end))
phishGrid = self.getGrids(dbName, weName, level, tr)
surgeTR = TimeRange.TimeRange(tr.startTime(), AbsTime.AbsTime(tr.startTime().unixTime() + 3600))
if surgeTR in surgeTRList:
phishGrid = self.getGrids(dbName, weName, level, surgeTR)
else:
phishGrid = np.zeros(self.getGridShape(), 'f')
#
# For consistency we need to add smoothing here too as we do in execute.
#
@ -208,7 +218,7 @@ class Procedure (SmartScript.SmartScript):
if smoothThreatGrid is "Yes":
phishGrid = np.where(np.greater(phishGrid, 0.0), self.smoothGrid(phishGrid,3), phishGrid)
grid = np.where(phishGrid>-100,phishGrid*3.28, np.float32(-80.0))
grid = np.where(phishGrid>-100, phishGrid*3.28, np.float32(-80.0)) # Convert units from meters to feet
self.createGrid(mutableID, "InundationTiming", "SCALAR", grid, tr6, precision=1)
return
@ -600,7 +610,7 @@ class Procedure (SmartScript.SmartScript):
print "Timing grid not found at:", trList[i]
if (start - baseTime) / 3600 >= inunStartHour and (end - baseTime) / 3600 <= inunEndHour:
timingGrids[i][modifyMask] = inundationHeight # populate where needed
timingGrids[i][modifyMask] = inundationHeight # populate only where needed
self.createGrid(mutableID, "InundationTiming", "SCALAR", timingGrids[i], trList[i])

View file

@ -5,7 +5,7 @@
# TCV_Dictionary
# TCV_Dictionary file
# Author: GFE Installation Script
# Last Modified: Feb 13, 2015
# Last Modified: Jan 26, 2016
# ----------------------------------------------------------------------------
# Needed to prevent an error from the SmartTool module
WeatherElementEdited = None
@ -16,7 +16,7 @@ ThreatStatements = {
"check plans": {
"planning": "Emergency planning should include a reasonable threat for major hurricane force wind greater than 110 MPH of equivalent Category 3 intensity or higher.",
"preparation": "To be safe, aggressively prepare for the potential of devastating to catastrophic wind impacts. Efforts should now be underway to secure all properties.",
"action": "Extremely Dangerous and life threatening wind is possible. Failure to adequately shelter may result in serious injury, loss of life, or immense human suffering.",
"action": "Extremely dangerous and life threatening wind is possible. Failure to adequately shelter may result in serious injury, loss of life, or immense human suffering.",
},
"complete preparations": {
"planning": "Emergency plans should include a reasonable threat for major hurricane force wind greater than 110 MPH of equivalent Category 3 intensity or higher.",

View file

@ -79,6 +79,7 @@ import com.raytheon.viz.ui.dialogs.ICloseCallback;
* 29 June 2015 14630 xwei Fixed : Not able to import basins.dat with apostrophe and incorrect data posted
* 30 June 2015 17360 xwei Fixed : basins.dat import failed if the first line does not have Lat Lon
* Dec 18, 2015 5217 mduff Changes to fix importing geo files.
* Feb 15, 2016 5217 mduff convert longitude back to hydro's "View value" of being positive
*
* </pre>
*
@ -835,7 +836,8 @@ public class ArealDefinitionsDlg extends CaveSWTDialog {
geoData.setBoundaryType(HydroConstants.GEOAREA_DATANAMES[listCbo
.getSelectionIndex()]);
geoData.setInteriorLat(intLat);
geoData.setInteriorLon(intLon);
// Convert back to hydro format of positive longitude values
geoData.setInteriorLon(intLon * -1);
geoData.setLon(lonPoints);
geoData.setLat(latPoints);
geoData.setNumberPoints(nPts);

View file

@ -96,8 +96,6 @@ import com.vividsolutions.jts.geom.GeometryFactory;
* Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap
* parameters, disable colormap interpolation
* by default.
* Nov 19, 2015 18105 lbousaidi Removed time and PrecipField legend on the right
* side of cave to give space to basin info.
*
* </pre>
*
@ -899,8 +897,16 @@ public class MPELegendResource extends
} else if (rsc.getStatus() != ResourceStatus.INITIALIZED) {
continue;
} else {
legend.label="";
legend.label = rsc.getName();
legend.resource = resourcePair;
if (rsc.isTimeAgnostic() == false) {
DataTime date = frameInfo.getTimeForResource(rsc);
String time = " No Data Available";
if (date != null) {
time = " - " + date.getLegendString();
}
legend.label += time;
}
}
if (!vis) {

View file

@ -30,7 +30,8 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.viz.mpe.util.DailyQcUtils.Station;
/**
* TODO Add Description
* This routine will estimate 6 hourly periods when 24 hour rain exists. Based on:
* ohd/pproc_lib/src/GageQCEngine/TEXT/estimate_daily_stations.c in AWIPS I.
*
* <pre>
*
@ -38,6 +39,8 @@ import com.raytheon.viz.mpe.util.DailyQcUtils.Station;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 10, 2009 snaples Initial creation
* Jan 11, 2016 5173 bkowal Do not estimate a station that has been forced
* good. Eliminated warnings.
*
* </pre>
*
@ -55,8 +58,8 @@ public class EstDailyStations {
public void estimate_daily_stations(int j,
ArrayList<Station> precip_stations, int numPstations) {
int dqc_neig = dqc.mpe_dqc_max_precip_neighbors;
int isom = dqc.isom;
int dqc_neig = DailyQcUtils.mpe_dqc_max_precip_neighbors;
int isom = DailyQcUtils.isom;
int isohyets_used = dqc.isohyets_used;
int method = dqc.method;
int m, k, i, l, ii;
@ -83,18 +86,18 @@ public class EstDailyStations {
int details = dqc.mpe_td_details_set;
int mpe_td_new_algorithm_set = dqc.mpe_td_new_algorithm_set;
if (dqc.pdata[j].data_time == null) {
if (DailyQcUtils.pdata[j].data_time == null) {
return;
}
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTime(dqc.pdata[j].data_time);
cal.setTime(DailyQcUtils.pdata[j].data_time);
/* this routine will estimate 6 hourly periods when 24 hour rain exists */
for (m = 0; m < max_stations; m++) {
/* dont estimate missing 24 hour stations */
if (dqc.pdata[j].stn[m].frain[4].data < 0
|| dqc.pdata[j].stn[m].frain[4].qual == 4) {
if (DailyQcUtils.pdata[j].stn[m].frain[4].data < 0
|| DailyQcUtils.pdata[j].stn[m].frain[4].qual == 4) {
continue;
}
@ -102,17 +105,17 @@ public class EstDailyStations {
for (k = 0; k < 4; k++) {
if (dqc.pdata[j].stn[m].frain[k].data >= 0
&& dqc.pdata[j].stn[m].frain[k].qual == 2) {
if (DailyQcUtils.pdata[j].stn[m].frain[k].data >= 0
&& DailyQcUtils.pdata[j].stn[m].frain[k].qual == 2) {
continue;
}
if (dqc.pdata[j].stn[m].frain[k].qual == 1) {
if (DailyQcUtils.pdata[j].stn[m].frain[k].qual == 1) {
break;
}
if (dqc.pdata[j].stn[m].rrain[k].data < 0
&& dqc.pdata[j].stn[m].frain[k].qual != 2) {
if (DailyQcUtils.pdata[j].stn[m].rrain[k].data < 0
&& DailyQcUtils.pdata[j].stn[m].frain[k].qual != 2) {
break;
}
@ -124,8 +127,9 @@ public class EstDailyStations {
/* dont estimate stations forced good, bad or estimated */
if (dqc.pdata[j].stn[m].frain[4].qual == 1
|| dqc.pdata[j].stn[m].frain[4].qual == 5) {
if (DailyQcUtils.pdata[j].stn[m].frain[4].qual == 0
|| DailyQcUtils.pdata[j].stn[m].frain[4].qual == 1
|| DailyQcUtils.pdata[j].stn[m].frain[4].qual == 5) {
continue;
}
@ -154,16 +158,16 @@ public class EstDailyStations {
/* dont estimate unless good or forced good */
if (dqc.pdata[j].stn[i].frain[k].qual != 0
&& dqc.pdata[j].stn[i].frain[k].qual != 8
&& dqc.pdata[j].stn[i].frain[k].qual != 3
&& dqc.pdata[j].stn[i].frain[k].qual != 2) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].qual != 0
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 8
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 3
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 2) {
continue;
}
/* dont use missing stations */
if (dqc.pdata[j].stn[i].frain[k].data < 0) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].data < 0) {
continue;
}
@ -186,10 +190,10 @@ public class EstDailyStations {
testdist = 1 / testdist;
if (method == 2 && isoh > 0 && isoh1 > 0) {
padj = dqc.pdata[j].stn[i].frain[k].data
padj = DailyQcUtils.pdata[j].stn[i].frain[k].data
* isoh1 / isoh;
} else {
padj = dqc.pdata[j].stn[i].frain[k].data;
padj = DailyQcUtils.pdata[j].stn[i].frain[k].data;
}
fdist = testdist + fdist;
@ -229,14 +233,14 @@ public class EstDailyStations {
continue;
}
if (dqc.pdata[j].stn[i].frain[k].qual != 0
&& dqc.pdata[j].stn[i].frain[k].qual != 8
&& dqc.pdata[j].stn[i].frain[k].qual != 3
&& dqc.pdata[j].stn[i].frain[k].qual != 2) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].qual != 0
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 8
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 3
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 2) {
continue;
}
if (dqc.pdata[j].stn[i].frain[k].data < 0) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].data < 0) {
continue;
}
@ -257,10 +261,10 @@ public class EstDailyStations {
testdist = 1 / testdist;
if (method == 2 && isoh > 0 && isoh1 > 0) {
padj = dqc.pdata[j].stn[i].frain[k].data
padj = DailyQcUtils.pdata[j].stn[i].frain[k].data
* isoh1 / isoh;
} else {
padj = dqc.pdata[j].stn[i].frain[k].data;
padj = DailyQcUtils.pdata[j].stn[i].frain[k].data;
}
fdist = testdist + fdist;
@ -293,27 +297,26 @@ public class EstDailyStations {
if (i == m) {
continue;
}
if (dqc.pdata[j].stn[i].frain[k].qual != 0
&& dqc.pdata[j].stn[i].frain[k].qual != 8
&& dqc.pdata[j].stn[i].frain[k].qual != 3
&& dqc.pdata[j].stn[i].frain[k].qual != 2) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].qual != 0
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 8
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 3
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 2) {
continue;
}
if (dqc.pdata[j].stn[i].frain[k].data < 0) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].data < 0) {
continue;
}
buf = String
.format(" %s(%f,%f)",
precip_stations.get(i).hb5,
dqc.pdata[j].stn[i].frain[k].data,
DailyQcUtils.pdata[j].stn[i].frain[k].data,
precip_stations.get(i).isoh[isom]);
dqc.td_fpwr.write(buf);
dqc.td_fpwr.newLine();
}
// fvalue[k] = fdata / fdist;
} catch (IOException e) {
statusHandler.handle(Priority.PROBLEM,
@ -340,8 +343,8 @@ public class EstDailyStations {
dqc.td_fpwr.write(buf);
dqc.td_fpwr.newLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
@ -352,14 +355,14 @@ public class EstDailyStations {
continue;
}
if (dqc.pdata[j].stn[i].frain[k].qual != 0
&& dqc.pdata[j].stn[i].frain[k].qual != 8
&& dqc.pdata[j].stn[i].frain[k].qual != 3
&& dqc.pdata[j].stn[i].frain[k].qual != 2) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].qual != 0
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 8
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 3
&& DailyQcUtils.pdata[j].stn[i].frain[k].qual != 2) {
continue;
}
if (dqc.pdata[j].stn[i].frain[k].data < 0) {
if (DailyQcUtils.pdata[j].stn[i].frain[k].data < 0) {
continue;
}
@ -385,7 +388,7 @@ public class EstDailyStations {
.format(" %s(%f,%f)",
precip_stations
.get(closest_good_gage_index).hb5,
dqc.pdata[j].stn[closest_good_gage_index].frain[k].data,
DailyQcUtils.pdata[j].stn[closest_good_gage_index].frain[k].data,
precip_stations
.get(closest_good_gage_index).isoh[isom]);
@ -393,8 +396,8 @@ public class EstDailyStations {
dqc.td_fpwr.write(buf);
dqc.td_fpwr.newLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
}
}
}
@ -405,7 +408,7 @@ public class EstDailyStations {
fvalue[k] = -9999;
} else {
if (closest_good_gage_index != -9999) {
fvalue[k] = dqc.pdata[j].stn[closest_good_gage_index].frain[k].data;
fvalue[k] = DailyQcUtils.pdata[j].stn[closest_good_gage_index].frain[k].data;
} else {
fvalue[k] = -9999;
}
@ -418,8 +421,8 @@ public class EstDailyStations {
for (k = 0; k < 4; k++) {
dqc.pdata[j].stn[m].frain[k].qual = 6;
dqc.pdata[j].stn[m].frain[k].data = dqc.pdata[j].stn[m].frain[4].data / 4;
DailyQcUtils.pdata[j].stn[m].frain[k].qual = 6;
DailyQcUtils.pdata[j].stn[m].frain[k].data = DailyQcUtils.pdata[j].stn[m].frain[4].data / 4;
}
@ -433,10 +436,10 @@ public class EstDailyStations {
for (k = 0; k < 4; k++) {
if ((dqc.pdata[j].stn[m].rrain[k].data >= 0 && dqc.pdata[j].stn[m].frain[k].qual != 1)
|| (dqc.pdata[j].stn[m].frain[k].qual == 2)) {
if ((DailyQcUtils.pdata[j].stn[m].rrain[k].data >= 0 && DailyQcUtils.pdata[j].stn[m].frain[k].qual != 1)
|| (DailyQcUtils.pdata[j].stn[m].frain[k].qual == 2)) {
stotal = stotal
+ dqc.pdata[j].stn[m].frain[k].data;
+ DailyQcUtils.pdata[j].stn[m].frain[k].data;
} else {
num_missing++;
@ -447,7 +450,7 @@ public class EstDailyStations {
}
stotal = dqc.pdata[j].stn[m].frain[4].data - stotal;
stotal = DailyQcUtils.pdata[j].stn[m].frain[4].data - stotal;
if (stotal < 0) {
stotal = 0;
@ -461,22 +464,22 @@ public class EstDailyStations {
for (k = 0; k < 4; k++) {
if ((dqc.pdata[j].stn[m].rrain[k].data >= 0 && dqc.pdata[j].stn[m].frain[k].qual != 1)
|| (dqc.pdata[j].stn[m].frain[k].qual == 2)) {
if ((DailyQcUtils.pdata[j].stn[m].rrain[k].data >= 0 && DailyQcUtils.pdata[j].stn[m].frain[k].qual != 1)
|| (DailyQcUtils.pdata[j].stn[m].frain[k].qual == 2)) {
continue;
}
if (ftotal != 0) {
dqc.pdata[j].stn[m].frain[k].data = (float) (fvalue[k] * fmult);
dqc.pdata[j].stn[m].frain[k].qual = 6;
DailyQcUtils.pdata[j].stn[m].frain[k].data = (float) (fvalue[k] * fmult);
DailyQcUtils.pdata[j].stn[m].frain[k].qual = 6;
}
else {
dqc.pdata[j].stn[m].frain[k].data = (float) (stotal / num_missing);
dqc.pdata[j].stn[m].frain[k].qual = 6;
DailyQcUtils.pdata[j].stn[m].frain[k].data = (float) (stotal / num_missing);
DailyQcUtils.pdata[j].stn[m].frain[k].qual = 6;
}

View file

@ -35,6 +35,7 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@ -45,6 +46,7 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.xml.bind.JAXB;
import javax.xml.bind.JAXBException;
@ -135,6 +137,7 @@ import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.localization.exception.LocalizationException;
import com.raytheon.uf.common.serialization.JAXBManager;
import com.raytheon.uf.common.serialization.comm.IServerRequest;
import com.raytheon.uf.common.site.SiteMap;
@ -361,7 +364,8 @@ import com.raytheon.viz.ui.simulatedtime.SimulatedTimeOperations;
* 19Nov2015 5141 randerso Replace commas with ellipses if product not enabled for
* mixed case transmission
* 10Dec2015 5206 randerso Replace commas with ellipses only in WarnGen products
* 11Dec2015 RM14752 mgamazaychikov Fix problems with wrapping in the impact section.
* 11Dec2015 RM14752 mgamazaychikov Fix problems with wrapping in the impact section, generalized
* the approach to padding paragraphs.
* 06Jan2016    RM18452  mgamazaychikov Fix NPE for null product in enterEditor
* 06Jan2016 5225 randerso Fix problem with mixed case not getting converted to upper case
* when multiple text editors are open on the same product.
@ -503,16 +507,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
*/
private static final String PARAGRAPH_DELIMITERS = "*$.-/^#";
/**
* String to delimit padded paragraphs.
*/
private static final String PADDED_PARAGRAPH_DELIMITERS = "*";
/**
* Expression for start of an obs.
*/
private static final String METAR_PARAGRAPH = "(METAR|SPECI)\\b.*";
// Pattern no long used but keeping it here for just in case not using
// it breaks being compatialbe with A1.
@ -1419,6 +1413,10 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
/** Highlight background color. */
private Color highlightBackgroundClr;
private static List<Pattern> paddingPatternList = new ArrayList<Pattern>();
private static final String PARAGRAPH_PADDING_PATTERN_FILENAME = "textws/gui/ParagraphPaddingPattern.txt";
/**
* Constructor with additional cave style rules
*
@ -8004,7 +8002,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
private void rewrapInternal(int lineNumber) {
boolean inLocations = false;
boolean inPathcast = false;
String padding = "";
// get contents of line
String line = textEditor.getLine(lineNumber);
// check for special paragraph cases
@ -8028,21 +8025,8 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
inPathcast = true;
}
// is this the impact paragraph?
if (paragraphStart.startsWith(" IMPACT...")
|| paragraphStart.startsWith(" HAZARD...")
|| paragraphStart.startsWith(" SOURCE...")) {
padding = " ";
}
if (paragraphStart.matches(METAR_PARAGRAPH)) {
padding = " ";
} else if (checkParagraphPadding(paragraphStart)) {
// do we need to add or remove padding when we manipulate lines (
// two
// spaces )
padding = " ";
}
// get the padding for the paragraph
String padding = getParagraphPadding(paragraphStart);
if ((inLocations || inPathcast)
&& paragraphStartLineNumber == lineNumber) {
@ -8388,23 +8372,6 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
}
/**
* checks if the paragraph starting at the line passed in uses two space
* padding for subsequent lines
*
* @param firstLine
* @return
*/
private boolean checkParagraphPadding(String firstLine) {
boolean rval = false;
if (firstLine.length() > 0
&& PADDED_PARAGRAPH_DELIMITERS.contains(firstLine.substring(0,
1))) {
rval = true;
}
return rval;
}
/**
* find and return the line number that is the start of the paragraph
* containing the line number passed in
@ -8830,4 +8797,75 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
public void timechanged() {
validateTime();
}
/**
* Reads the contents of PARAGRAPH_PADDING_PATTERN_FILENAME into
* paddingPatternList.
*/
private void loadPaddingPattern() {
IPathManager pathMgr = PathManagerFactory.getPathManager();
LocalizationFile lf = pathMgr.getStaticLocalizationFile(
LocalizationType.CAVE_STATIC,
PARAGRAPH_PADDING_PATTERN_FILENAME);
if ((lf != null) && lf.exists()) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(
lf.openInputStream()))) {
String line = null;
List<Pattern> patternList = new ArrayList<Pattern>();
while ((line = br.readLine()) != null) {
if (!line.startsWith("#")) {
try {
Pattern ptrn = Pattern.compile(line);
patternList.add(ptrn);
} catch (PatternSyntaxException e) {
statusHandler.handle(Priority.PROBLEM,
"Could not compile regex for line " + line
+ " from Padding Pattern file "
+ lf.toString(), e);
}
}
}
paddingPatternList = patternList;
} catch (IOException e) {
statusHandler.handle(Priority.PROBLEM,
"Could not read Padding Pattern file "
+ PARAGRAPH_PADDING_PATTERN_FILENAME, e);
} catch (LocalizationException e) {
statusHandler.handle(Priority.PROBLEM,
"Could not find Padding Pattern file "
+ PARAGRAPH_PADDING_PATTERN_FILENAME, e);
}
}
}
/**
* Sets the padding:
* - according to padding pattern
* - to empty string
*
* @param paragraphStart
*/
private String getParagraphPadding(String paragraphStart) {
String defaultParagraphPadding = "";
for (Pattern paddingPtrn : getPaddingPatternList()) {
Matcher m = paddingPtrn.matcher(paragraphStart);
if (m.matches()) {
int paragraphOffset = m.group(1).toString().length();
StringBuilder sb = new StringBuilder(paragraphOffset);
for (int i = 0; i < paragraphOffset; i++) {
sb.append(" ");
}
return sb.toString();
}
}
return defaultParagraphPadding;
}
private List<Pattern> getPaddingPatternList() {
// load padding pattern file
if (paddingPatternList.isEmpty()){
loadPaddingPattern();
}
return paddingPatternList;
}
}

View file

@ -0,0 +1,37 @@
#
# This file contains the regex for paragraphs in text product
# that requires special padding. The padding for impact paragraphs
# is set in WarnGen templates. Whenever it is changed there, the
# change needs to be reflected in this file as well. The regex must match the
# entire line and must include parentheses to capture the desired prefix that
# will define the indentation level of the paragraph.
#
# Software History.
#
# Date Ticket Engineer Description
# ------------ ---------- ---------- --------------------------
# 31Jan2016 RM18503 mgamazaychikov Created.
#
# Paragraph that starts with spaces followed by one of
#
# "IMPACT..."
# "HAZARD..."
# "SOURCE..."
#
(\s*IMPACT\.\.\.).*
(\s*HAZARD\.\.\.).*
(\s*SOURCE\.\.\.).*
#
# Paragraph that starts with one of:
#
# "METAR"
# "SPECI"
#
(METAR).*
(SPECI).*
#
# Paragraph that start with
#
# "* "
#
(\*\s+).*

View file

@ -50,4 +50,14 @@
<contribute xsi:type="menuItem" menuText="24hr 95th Percentile Total Precipitation" key="TP95pct24hr" indentText="false" />
</contribute>
<contribute xsi:type="toolbarSubMenu" menuText="72hr">
<contribute xsi:type="menuItem" menuText="72hr 5th Percentile Total Precipitation" key="TP5pct72hr" indentText="false" />
<contribute xsi:type="menuItem" menuText="72hr 10th Percentile Total Precipitation" key="TP10pct72hr" indentText="false" />
<contribute xsi:type="menuItem" menuText="72hr 25th Percentile Total Precipitation" key="TP25pct72hr" indentText="false" />
<contribute xsi:type="menuItem" menuText="72hr 50th Percentile Total Precipitation" key="TP50pct72hr" indentText="false" />
<contribute xsi:type="menuItem" menuText="72hr 75th Percentile Total Precipitation" key="TP75pct72hr" indentText="false" />
<contribute xsi:type="menuItem" menuText="72hr 90th Percentile Total Precipitation" key="TP90pct72hr" indentText="false" />
<contribute xsi:type="menuItem" menuText="72hr 95th Percentile Total Precipitation" key="TP95pct72hr" indentText="false" />
</contribute>
</menuTemplate>

View file

@ -255,6 +255,7 @@ import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
* 12/21/2015 DCS 17942 D. Friedman Support "extension area": polygon can extend past normal features into WFO's marine/land areas.
* Show preview of redrawn polygon when developer mode property is set.
* 01/06/2016 ASM #18453 D. Friedman Cache extension areas so they are not regenerated on Restart or (limited) template changes.
* 02/23/2016 ASM #18669 D. Friedman Improve speed and reduce memory usage of extension area generation.
* </pre>
*
* @author mschenke
@ -1016,30 +1017,83 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
private Geometry createExtensionArea() throws Exception {
long t0 = System.currentTimeMillis();
GeospatialData[] features = primaryGDA.geoData.getFeatures(false); // Never uses cwaStretch feactures.
Geometry[] g = new Geometry[features.length];
for (int i = 0; i < g.length; ++i) {
/*
* Pre-simplify as an optmization. Makes it possible to
* change the static extension distance in real time.
*/
g[i] = extensionSimplify(
convertGeom(features[i].geometry, primaryGDA.geoData.latLonToLocal),
options.getSimplificationTolerance()).
buffer(options.getDistance());
// Pre-simplify and extend each feature.
g[i] = simplifyAndExtendFeature(
convertGeom(features[i].geometry,
primaryGDA.geoData.latLonToLocal),
options.getSimplificationTolerance(),
options.getDistance());
}
Geometry r = GeometryUtil.union(g);
r = createExtensionAreaFromLocal(r);
Geometry vis = extensionGDA.buildArea(r, false);
perfLog.logDuration("Extension area", System.currentTimeMillis() - t0);
extensionAreaManager.cacheArea(primaryGDA, extensionGDA, options, r, vis);
extensionAreaVis = vis;
issueRefresh();
return r;
}
private Geometry simplifyAndExtendFeature(Geometry geom, double tolerance, double dist) {
ArrayList<Geometry> parts = new ArrayList<Geometry>();
GeometryUtil.buildGeometryList(parts, geom);
ArrayList<Geometry> outParts = new ArrayList<Geometry>(parts.size());
for (Geometry g : parts) {
g = extensionSimplify(g, tolerance);
if (dist > 0) {
g = g.buffer(dist);
}
outParts.add(g);
}
GeometryFactory gf = new GeometryFactory();
/*
* All parts should be Polygons and this should return a
* MultiPolygon or single Polygon.
*/
return gf.buildGeometry(outParts);
}
private static final int BUFFER_GEOMETRY_BATCH_SIZE = 100;
/*
* Geometry.buffer() can run the VM out of memory if the geometry is too
* complicated (e.g., a MultiPolygon with thousands of component
* Polygons.) The following code limits the number of components that
* are buffered at one time.
*/
private Geometry createExtensionAreaFromLocal(Geometry geom) {
// geom should be simlified so that the following ops are not painful.
Geometry r = geom;
if (r.getNumGeometries() > BUFFER_GEOMETRY_BATCH_SIZE) {
GeometryFactory gf = new GeometryFactory();
Geometry[] ga = new Geometry[BUFFER_GEOMETRY_BATCH_SIZE];
while (r.getNumGeometries() > BUFFER_GEOMETRY_BATCH_SIZE) {
Geometry[] batches = new Geometry[
(r.getNumGeometries() + (BUFFER_GEOMETRY_BATCH_SIZE - 1))
/ BUFFER_GEOMETRY_BATCH_SIZE];
int si = 0;
int bi = 0;
while (si < r.getNumGeometries()) {
int gai = 0;
while (si < r.getNumGeometries() && gai < ga.length) {
ga[gai++] = r.getGeometryN(si++);
}
/* Note that ga is being reused every pass so the
* GeometryCollection created here must not continue
* to be referenced.
*/
Geometry batch = gf.createGeometryCollection(
gai == BUFFER_GEOMETRY_BATCH_SIZE ?
ga : Arrays.copyOf(ga, gai));
batch = batch.buffer(0);
batches[bi++] = batch;
}
r = gf.createGeometryCollection(batches);
}
}
r = r.buffer(0);
r = extensionSimplify(r, options.getSimplificationTolerance());
r = convertGeom(r, primaryGDA.geoData.localToLatLon);

View file

@ -152,6 +152,7 @@ import com.vividsolutions.jts.io.WKTReader;
* May 29, 2015 4440 randerso Fix resource leak (file not closed)
* Jul 15, 2015 DR17716 mgamazaychikov Change to Geometry class in total intersection calculations.
* Oct 21, 2105 5021 randerso Fix issue with CORs for mixed case
* Feb 9, 2016 DR18421 D. Friedman Don't call ToolsDataManager.setStormTrackData if there is no storm motion.
* </pre>
*
* @author njensen
@ -555,10 +556,12 @@ public class TemplateRunner {
stormLocs[i].y);
}
context.put("eventLocation", coords);
t0 = System.currentTimeMillis();
ToolsDataManager.getInstance().setStormTrackData(std);
perfLog.logDuration("Save storm track data",
System.currentTimeMillis() - t0);
if (std.getMotionSpeed() > 0) {
t0 = System.currentTimeMillis();
ToolsDataManager.getInstance().setStormTrackData(std);
perfLog.logDuration("Save storm track data",
System.currentTimeMillis() - t0);
}
} else {
// Retrieve the old Warning
// Example: s[0-5] = T.CON-KLWX.SV.W.0123
@ -612,10 +615,12 @@ public class TemplateRunner {
std.setDate(simulatedTime);
std.setMotionDirection(motionDirection);
std.setMotionSpeed(oldWarn.getMotspd());
t0 = System.currentTimeMillis();
ToolsDataManager.getInstance().setStormTrackData(std);
perfLog.logDuration("Save storm track data",
System.currentTimeMillis() - t0);
if (std.getMotionSpeed() > 0) {
t0 = System.currentTimeMillis();
ToolsDataManager.getInstance().setStormTrackData(std);
perfLog.logDuration("Save storm track data",
System.currentTimeMillis() - t0);
}
}
}

View file

@ -122,6 +122,7 @@ import com.raytheon.uf.edex.database.DataAccessLayerException;
* 06/29/2015 #4537 rferrel Allow for durations less then 1 hour.
* 07/13/2015 #4537 randerso Additional changes to allow D2DParms with sub-hourly durations/intervals
* 12/03/2015 #5168 randerso Added flag to use database time range if valid
* 01/27/2016 #5290 randerso Do not put null time ranges in the grid inventory.
*
* </pre>
*
@ -653,7 +654,9 @@ public class D2DGridDatabase extends VGridDatabase {
+ dataTime.getFcstTime());
}
}
invSet.add(tr);
if (tr != null) {
invSet.add(tr);
}
}
inventory = new ArrayList<TimeRange>(invSet);
} else {

View file

@ -301,12 +301,13 @@ rfc.groupName = 'ISC'
# NHA ISC area
domain = ShapeTable('nhadomain')
#segment.name = "AllCWA"
domain.name = "TropicalISC"
domain.groupName = "ISC"
domain.editAreaName = "ISC_NHA"
# Storm Surge Watch/Warning Area
stormsurgeww = ShapeTable('stormsurgeww')
stormsurgeww.name = "StormSurgeWW"
stormsurgeww.groupName = "SurgeCollab"
stormsurgeww.editAreaName = "StormSurgeWW_EditArea"

View file

@ -1,4 +1,4 @@
# Version 2015.8.27-0
# Version 2016.02.24-0
import GenericHazards
import string, time, os, re, types, copy, LogStream, collections
@ -549,21 +549,16 @@ class TextProduct(HLSTCV_Common.TextProduct):
productDict['stormInformation'] = stormInfoDict
def _situationOverview(self, productDict, productSegmentGroup, productSegment):
overviewSectionTitle = ".Situation Overview...\n"
# Get the WRKHLS product that has the situation overview we want
wrkhlsProduct = self.getPreviousProduct("WRKHLS")
# Try finding the situation overview
overviewSearch = re.search("(?ism).*^%s(.+?)^\." % (overviewSectionTitle), wrkhlsProduct)
# Use generic text for the situation overview
productDict['situationOverview'] = self._frame("Succinctly describe the expected evolution of the event for the cwa; which hazards are of greater (or lesser) concern, forecast focus, etc.")
# Get the WRKHLS product minus header that has the situation overview we want
wrkhlsProduct = self.getPreviousProduct("WRKHLS")[40:]
# If we found the overview
if overviewSearch is not None:
# Clean it up
productDict['situationOverview'] = self._cleanText(overviewSearch.group(1).strip())
else:
# Use generic text for the situation overview
productDict['situationOverview'] = self._frame("Succinctly describe the expected evolution of the event for the cwa; which hazards are of greater (or lesser) concern, forecast focus, etc.")
if len(wrkhlsProduct) > 0:
# Clean and frame the imported overview and use it instead of the generic text
productDict['situationOverview'] = self._frame(self._cleanText(wrkhlsProduct.strip()))
def _windSection(self, productDict, productSegmentGroup, productSegment):
sectionDict = dict()
@ -2101,7 +2096,7 @@ class TextProduct(HLSTCV_Common.TextProduct):
for label, latLon in refList:
lat, lon = latLon
localRef = self._calcReference(lat0, lon0, lat, lon)
localRef = localRef + " OF " + label
localRef = localRef + " of " + label
localRef = localRef.replace(",","")
localRefs.append(localRef)
return localRefs
@ -2592,7 +2587,7 @@ class LegacyFormatter():
else:
text = ""
for headline in headlinesList:
text += self._textProduct.indentText("**" + headline + "**\n",
text += self._textProduct.indentText("**" + headline + "** ",
maxWidth=self._textProduct._lineLength)
text = self._textProduct._frame(text) + "\n\n"
@ -2678,7 +2673,7 @@ class LegacyFormatter():
title = "Situation Overview"
text = title + "\n" + "-"*len(title) + "\n\n"
text += self._textProduct.indentText(overviewText, maxWidth=self._textProduct._lineLength)
text += self._textProduct.endline(overviewText, linelength=self._textProduct._lineLength)
text += "\n"
return text
@ -2754,4 +2749,3 @@ class LegacyFormatter():
self._textProduct.debug_print("subpart newtext = '%s'" % (self._pp.pformat(newtext)))
text += newtext
return text

View file

@ -1,4 +1,4 @@
# Version 2015.11.19-0
# Version 2016.02.24-0
import GenericHazards
import JsonSupport
@ -469,14 +469,14 @@ class TextProduct(HLSTCV_Common.TextProduct):
if len(self._segmentList) == 0:
return "No hazards to report"
# Determine time ranges
self._determineTimeRanges(argDict)
# Make sure we have all of the necessary grids before continuing
error = self._performGridChecks(argDict)
if error is not None:
return error
# Determine time ranges
self._determineTimeRanges(argDict)
# Sample the data
self._sampleData(argDict)
@ -513,14 +513,14 @@ class TextProduct(HLSTCV_Common.TextProduct):
gridChecks += [(self._isCorrectNumGrids, "WindThreat", 1, argDict),
(self._isContinuousDuration, "Wind", 120, argDict),
(self._isContinuousDuration, "WindGust", 120, argDict),
(self._isContinuousDuration, "pws34int", 120, argDict),
(self._isContinuousDuration, "pws64int", 120, argDict),
(self._isCombinedContinuousDuration, "pwsD34", "pwsN34", 96, argDict),
(self._isCombinedContinuousDuration, "pwsD64", "pwsN64", 96, argDict),]
(self._isContinuousDuration, "pws34int", 114, argDict),
(self._isContinuousDuration, "pws64int", 114, argDict),
(self._isCombinedContinuousDuration, "pwsD34", "pwsN34", 102, argDict),
(self._isCombinedContinuousDuration, "pwsD64", "pwsN64", 102, argDict),]
if self._PopulateSurge and len(self._coastalAreas()) != 0:
gridChecks += [(self._isCorrectNumGrids, "InundationMax", 1, argDict),
(self._isCorrectNumGrids, "InundationTiming", 13, argDict),]
(self._isCorrectNumGrids, "InundationTiming", 12, argDict),]
missingGridErrors = []
for gridCheck in gridChecks:
@ -530,9 +530,9 @@ class TextProduct(HLSTCV_Common.TextProduct):
error = ""
if gridCheck[0] == self._isCorrectNumGrids:
if gridCheck[2] == 1:
error = "%s needs exactly 1 grid" % (gridCheck[1])
error = "%s needs at least 1 grid" % (gridCheck[1])
else:
error = "%s needs exactly %s grids" % (gridCheck[1], gridCheck[2])
error = "%s needs at least %s grids" % (gridCheck[1], gridCheck[2])
elif gridCheck[0] == self._isContinuousDuration:
error = "%s needs at least %s continuous hours worth of data" % (gridCheck[1], gridCheck[2])
else:
@ -556,13 +556,28 @@ class TextProduct(HLSTCV_Common.TextProduct):
ifpClient = argDict["ifpClient"]
dbId = argDict["databaseID"]
parmId = ParmID(weatherElement, dbId)
gridTimes = ifpClient.getGridInventory(parmId)
times = ifpClient.getGridInventory(parmId)
self.debug_print("Element being tested: %s" % (self._pp.pformat(weatherElement)), 1)
self.debug_print("Expected number of grids: %s" % (self._pp.pformat(expectedNumGrids)), 1)
self.debug_print("Length of grid times: %s" % (self._pp.pformat(len(gridTimes))), 1)
return len(gridTimes) == expectedNumGrids
gridTimes = []
for index in range(len(times)):
gridTime = TimeRange.TimeRange(times[index])
if (gridTime.endTime() <= self._timeRange.startTime() or
gridTime.startTime() >= self._timeRange.endTime()):
prettyStartTime = self._pp.pformat(str(gridTime.startTime()))
prettyEndTime = self._pp.pformat(str(gridTime.endTime()))
self.debug_print("skipping grid %s (%s - %s): outside of time range"
% (index, prettyStartTime, prettyEndTime), 1)
else:
gridTimes.append(gridTime)
self.debug_print("Actual number of grids: %s" % (self._pp.pformat(len(gridTimes))), 1)
return len(gridTimes) >= expectedNumGrids
def _isContinuousDuration(self, weatherElement, minimumNumHours, argDict):
return self._checkContinuousDuration([weatherElement], minimumNumHours, argDict)
@ -592,11 +607,28 @@ class TextProduct(HLSTCV_Common.TextProduct):
gridTimes = sorted(gridTimes, key= lambda gridTime: gridTime.startTime())
totalHours = 0
previousEndTime = gridTimes[0].startTime()
previousEndTime = None
for gridTime in gridTimes:
self.debug_print("previous end time: %s" % (self._pp.pformat(str(previousEndTime))), 1)
self.debug_print("current start time: %s" % (self._pp.pformat(str(gridTime.startTime()))), 1)
if gridTime.endTime() <= self._timeRange.startTime():
prettyEndTime = self._pp.pformat(str(gridTime.endTime()))
prettyStartTime = self._pp.pformat(str(self._timeRange.startTime()))
self.debug_print("skipping: grid end time (%s) before time range start time (%s)"
% (prettyEndTime, prettyStartTime), 1)
continue
if gridTime.startTime() >= self._timeRange.endTime():
prettyStartTime = self._pp.pformat(str(gridTime.startTime()))
prettyEndTime = self._pp.pformat(str(self._timeRange.endTime()))
self.debug_print("done: grid start time (%s) after time range end time (%s)"
% (prettyStartTime, prettyEndTime), 1)
break
if previousEndTime is None:
previousEndTime = gridTime.startTime()
if previousEndTime != gridTime.startTime():
# Not continuous
return False
@ -674,10 +706,6 @@ class TextProduct(HLSTCV_Common.TextProduct):
self.debug_print("vtecRecord = %s" % (self._pp.pformat(vtecRecord)), 1)
if vtecRecord["phen"] == "SS":
# Temporary? Change the vtec mode for SS hazards to be experimental
vstr = vstr[0] + 'X' + vstr[2:]
self.debug_print("final vstr = %s" % vstr, 1)
records.append(vstr)
segmentDict['vtecRecords'] = records
@ -1066,13 +1094,15 @@ class TextProduct(HLSTCV_Common.TextProduct):
def _initializeSegmentZoneData(self, segment):
# The current advisory will be populated when getting a section's stats
self._currentAdvisory['ZoneData'][segment] = {
"WindThreat": None,
"WindForecast": None,
"StormSurgeThreat": None,
"StormSurgeForecast": None,
"FloodingRainThreat": None,
"FloodingRainForecast": None,
"TornadoThreat": None,
"WindThreat": None,
"WindForecast": None,
"WindHighestPhaseReached": None,
"StormSurgeThreat": None,
"StormSurgeForecast": None,
"StormSurgeHighestPhaseReached": None,
"FloodingRainThreat": None,
"FloodingRainForecast": None,
"TornadoThreat": None,
}
def _getPreviousAdvisories(self):
@ -1299,6 +1329,11 @@ class SectionCommon():
def _isThreatNoneForEntireStorm(self, threatName):
previousAdvisories = self._textProduct._getPreviousAdvisories()
# For the first advisory, this needs to be false otherwise
# potential impacts could be wrong
if len(previousAdvisories) == 0:
return False
for advisory in previousAdvisories:
if advisory["ZoneData"][self._segment][threatName] != "None":
@ -1385,7 +1420,8 @@ class SectionCommon():
elif self._isThreatIncreasing(shorterTermTrendDifference, longerTermTrendDifference):
self._textProduct.debug_print("threat is increasing", 1)
threatTrendValue = "INCREASING"
elif currentThreat == "Extreme" and \
# NOTE: Modified so more threat levels can be classified as increasing when forecast has increased
elif currentThreat in ["Mod", "High", "Extreme"] and \
self._isMagnitudeIncreasing(forecastKey, magnitudeIncreaseThreshold):
self._textProduct.debug_print("Increasing based on magnitude", 1)
threatTrendValue = "INCREASING"
@ -1480,20 +1516,27 @@ class SectionCommon():
elif (onsetHour <= 6) and (endHour is not None) and (endHour > 0):
tr = "hunker down"
self._textProduct.debug_print("tr is currently -> '%s'" % (tr), 1)
self._textProduct.debug_print("Before default section. %s tr is currently -> %s for %s" % (section, tr, self._segment), 1)
# Will need to redo this logic when SS hazards are used
if section == "Wind":
threatGrid = "WindThreat"
elif section == "Surge":
threatGrid = "StormSurgeThreat"
if tr == "default":
records = self._textProduct._getVtecRecords(self._segment)
for record in records:
if record["phen"] in ["HU", "TR"] and record["sig"] == "W":
if record["act"] == "CAN":
if self._textProduct._currentAdvisory['ZoneData'][self._segment][threatGrid] in \
["Elevated", "Mod", "High", "Extreme"]:
tr = "hunker down"
break
if self._textProduct._currentAdvisory['ZoneData'][self._segment][threatGrid] not in \
["Elevated", "Mod", "High", "Extreme"]:
if section == "Wind":
tr = "recovery"
break
# This is just for 2015
elif record["act"] == "CON" and \
section == "Surge" and \
self._textProduct._currentAdvisory['ZoneData'][self._segment]["StormSurgeThreat"] == "None" and \
self._pastSurgeThreatsNotNone():
elif section == "Surge" and self._pastSurgeThreatsNotNone():
tr = "recovery"
break
@ -1501,7 +1544,45 @@ class SectionCommon():
section == "Wind" and \
self._pastWindHazardWasCAN():
tr = "recovery"
self._textProduct.debug_print("After default section. %s tr is -> %s for %s" % (section, tr, self._segment), 1)
# ---------------------------------------------------------------------
# Don't allow the event to regress to an earlier phase for this section
# "default" isn't ordered because it can occur at multiple points before the recovery phase
phaseOrder = [None, "check plans", "complete preparations", "hunker down", "recovery"]
if self._sectionHeaderName == "Storm Surge":
highestPhaseReachedField = "StormSurgeHighestPhaseReached"
else: # Flooding Rain and Tornado are tied to Wind so that's why they use Wind's phase
highestPhaseReachedField = "WindHighestPhaseReached"
previousHighestPhaseReached = self._textProduct._previousAdvisory['ZoneData'][self._segment][highestPhaseReachedField]
currentHighestPhaseReached = self._textProduct._currentAdvisory['ZoneData'][self._segment][highestPhaseReachedField]
if phaseOrder.index(currentHighestPhaseReached) >= phaseOrder.index(previousHighestPhaseReached):
highestPhaseReached = currentHighestPhaseReached
else:
highestPhaseReached = previousHighestPhaseReached
if tr == "default":
if highestPhaseReached == "recovery":
tr = "recovery"
else:
highestPhaseIndex = phaseOrder.index(highestPhaseReached)
self._textProduct.debug_print("highestPhaseReached so far for %s is -> '%s' for '%s" \
% (self._sectionHeaderName, highestPhaseReached, self._segment), 1)
currentPhaseIndex = phaseOrder.index(tr)
if currentPhaseIndex < highestPhaseIndex:
tr = highestPhaseReached
elif currentPhaseIndex > highestPhaseIndex:
self._textProduct._currentAdvisory['ZoneData'][self._segment][highestPhaseReachedField] = tr
self._textProduct.debug_print("End of method. %s tr is -> %s for %s" % (section, tr, self._segment), 1)
return tr
def _pastWindHazardWasCAN(self):
@ -1524,6 +1605,8 @@ class SectionCommon():
return False
def _pastSurgeThreatsNotNone(self):
# Will need to modify this to be both Wind and Surge once SS codes are added
previousAdvisories = self._textProduct._getPreviousAdvisories()
# If there are NOT any advisories to process - no need to continue
@ -1563,7 +1646,7 @@ class SectionCommon():
with open("/awips2/cave/etc/gfe/userPython/utilities/TCVDictionary.py", 'r') as pythonFile:
fileContents = pythonFile.read()
exec(fileContents)
# ThreatStatements comes from TCVDictionary.py when it is exec'ed
threatStatements = ThreatStatements
@ -1587,7 +1670,7 @@ class SectionCommon():
self._setProductPartValue(segmentDict, 'potentialImpactsSummary', summary)
def _getPotentialImpactsSummaryText(self, maxThreat):
if not self.isThreatNoneForEntireStorm:
if self.isThreatNoneForEntireStorm:
return "Potential Impacts: Little to None"
if self._tr is not None and self._sectionHeaderName in ["Wind", "Storm Surge"]:
if self._tr == "hunker down":
@ -1855,11 +1938,11 @@ class WindSection(SectionCommon):
# Dictionary representing wind thresholds in kts
# for category 1, 2, 3, 4 or 5 hurricanes.
return {
'CAT 5 Hurricane': (157, 999),
'CAT 4 Hurricane': (130, 157),
'CAT 3 Hurricane': (111, 130),
'CAT 2 Hurricane': ( 96, 111),
'CAT 1 Hurricane': ( 74, 96),
'Cat 5 Hurricane': (157, 999),
'Cat 4 Hurricane': (130, 157),
'Cat 3 Hurricane': (111, 130),
'Cat 2 Hurricane': ( 96, 111),
'Cat 1 Hurricane': ( 74, 96),
'Strong Tropical Storm': ( 58, 73),
'Tropical Storm': ( 39, 58),
}
@ -2108,7 +2191,7 @@ class FloodingRainSection(SectionCommon):
words = self._rainRange(int(self._stats._sumAccum + 0.5))
# If we have previous rainfall
if self._stats._prevAccum not in [0.0, None]:
if self._stats._prevAccum not in [0.0, None] and (int(self._stats._sumAccum + 0.5)) != 0:
words = "Additional " + words
self._setProductPartValue(segmentDict, 'peakRain', "Peak Rainfall Amounts: " + words)
@ -2116,7 +2199,9 @@ class FloodingRainSection(SectionCommon):
minAccum = 0
maxAccum = 0
if sumAccum == 0:
if sumAccum == 0 and self._stats._prevAccum not in [0.0, None]:
return "No additional significant rainfall forecast"
elif sumAccum == 0 and self._stats._prevAccum in [0.0, None]:
return "No significant rainfall forecast"
elif sumAccum == 1:
return "around 1 inch"
@ -2187,14 +2272,6 @@ class FloodingRainSection(SectionCommon):
if len(subsectionDict) > 0:
self._setProductPartValue(segmentDict, 'impactsSubsection', subsectionDict)
def _specialImpactsStatements(self):
return {"hunker down": ["Potential impacts from flooding rain are still unfolding.",
"The extent of realized impacts will depend on actual rainfall amounts as received at particular locations.",
],
"recovery": ["For additional information on impacts being caused by flooding rain, refer to the local hazardous weather outlook or hurricane local statement.",
],
}
def _potentialImpactsSummary(self, segmentDict, productSegmentGroup, productSegment):
if not self._textProduct._WSPGridsAvailable:
self._setProductPartValue(segmentDict, 'potentialImpactsSummary',
@ -2315,14 +2392,6 @@ class TornadoSection(SectionCommon):
if len(subsectionDict) > 0:
self._setProductPartValue(segmentDict, 'impactsSubsection', subsectionDict)
def _specialImpactsStatements(self):
return {"hunker down": ["Potential impacts from tropical tornadoes are still unfolding.",
"The extent of realized impacts will depend on the severity of actual tornado occurrence as experienced at particular locations.",
],
"recovery": ["For additional information on impacts being caused by tropical tornadoes, refer to the local hazardous weather outlook or hurricane local statement.",
],
}
def _potentialImpactsSummary(self, segmentDict, productSegmentGroup, productSegment):
if not self._textProduct._WSPGridsAvailable:
self._setProductPartValue(segmentDict, 'potentialImpactsSummary',
@ -2825,18 +2894,16 @@ class StormSurgeSectionStats(SectionCommonStats):
self._setStats(intersectStatList, timeRangeList)
def _setStats(self, statList, timeRangeList):
windows = []
phishStartTime = None
phishEndTime = None
possibleStop = 0
possibleStart = 0
# If this is an inland area, just move on
if statList == "InlandArea":
return
self._textProduct.debug_print("*"*100, 1)
self._textProduct.debug_print("phishStartTime = %s phishEndTime = %s possibleStop = %d possibleStart = %d" %
(str(phishStartTime), str(phishEndTime), possibleStop, possibleStart), 1)
self._textProduct.debug_print("Setting Surge Section stats for %s" % self._segment, 1)
statDict = statList[0]
self._inundationMax = self._textProduct._getStatValue(statDict, "InundationMax", "Max")
@ -2844,55 +2911,107 @@ class StormSurgeSectionStats(SectionCommonStats):
self._inundationMax = round(self._inundationMax)
self._textProduct.debug_print("self._inundationMax = %s" % (self._inundationMax), 1)
self._textProduct.debug_print("%s" % (self._textProduct._pp.pformat(statList)), 1)
self._textProduct.debug_print("length of statList = %s" % (len(statList)), 1)
for period in range(len(statList)):
tr, _ = timeRangeList[period]
statDict = statList[period]
self._textProduct.debug_print("-"*50, 1)
self._textProduct.debug_print("tr = %s" % (self._textProduct._pp.pformat(tr)), 1)
self._textProduct.debug_print("statDict = %s" % (self._textProduct._pp.pformat(statDict)), 1)
curPhish = self._textProduct._getStatValue(statDict, "InundationTiming", "Max")
self._textProduct.debug_print("tr = %s" % (self._textProduct._pp.pformat(tr)), 1)
self._textProduct.debug_print("curPhish = '%s' possibleStop = %d possibleStart = %d" %
(str(curPhish), possibleStop, possibleStart), 1)
self._textProduct.debug_print("phishStartTime = %s phishEndTime = %s" %
self._textProduct.debug_print("curPhish = '%s'" % (str(curPhish)), 1)
self._textProduct.debug_print("phishStartTime = %s phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1)
if (curPhish is None) or (curPhish == 'None'):
self._textProduct.debug_print("Done: Reached end of grids (curPhish was None)", 1)
break
if self._inundationMax >= 3:
if curPhish >= 1:
if possibleStop != 0:
possibleStop = 0
possibleStart += 1
if phishStartTime is None:
phishStartTime = tr.startTime()
elif curPhish < 1 and possibleStart < 2:
possibleStart = 0
phishStartTime = None
elif phishStartTime is not None and curPhish is not None: # Only checking if valid grid
possibleStop += 1
if possibleStop < 2:
phishEndTime = tr.startTime()
else: # possibleStop == 2
break
else: # curPhish is None so out of grids
break
# For start time:
# If inundationMax >= 3:
# Looking for 2 consecutive grids with a surge height >= 1
# Start will be the start time of the FIRST of the 2 consecutive grids
# If 1 <= inundationMax < 3:
# Looking for 1 grid with a surge height >= 1
# Start will be the start time of this grid
#
# For end time:
# Looking for 2 consecutive grids with a surge height < 1
# End will be the start time of the FIRST of the 2 consecutive grids
# If we have another period after this one, we may need to look at the two
# consecutive periods for start and end time conditions
isLastPeriod = True
if period < len(statList) - 1:
isLastPeriod = False
nextTr, _ = timeRangeList[period+1]
nextStatDict = statList[period+1]
nextPhish = self._textProduct._getStatValue(nextStatDict, "InundationTiming", "Max")
self._textProduct.debug_print("nextTr = %s" % (self._textProduct._pp.pformat(nextTr)), 1)
self._textProduct.debug_print("nextStatDict = %s" % (self._textProduct._pp.pformat(nextStatDict)), 1)
self._textProduct.debug_print("nextPhish = '%s'" % (str(nextPhish)), 1)
# Set what the condition is for determining the start time
if (self._inundationMax >= 3) and (not isLastPeriod):
startCondition = (curPhish >= 1) and (nextPhish >= 1)
self._textProduct.debug_print("startCondition looking at 2 periods", 1)
elif 1 <= self._inundationMax < 3:
if curPhish >= 1:
if possibleStop != 0:
possibleStop = 0
if phishStartTime is None:
phishStartTime = tr.startTime()
elif phishStartTime is not None and curPhish is not None: # Only checking if valid grid
possibleStop += 1
if possibleStop < 2:
phishEndTime = tr.startTime()
else: # possibleStop == 2
break
else: # curPhish is None so out of grids
break
startCondition = curPhish >= 1
self._textProduct.debug_print("startCondition looking at 1 period", 1)
else:
startCondition = False
self._textProduct.debug_print("no startCondition, done", 1)
break
# Set what the condition is for determining the end time
if not isLastPeriod:
endCondition = (curPhish < 1) and (nextPhish < 1)
self._textProduct.debug_print("endCondition looking at 2 periods", 1)
else:
endCondition = False
self._textProduct.debug_print("this is the last period, no endCondition possible", 1)
if startCondition and (phishStartTime is None):
phishStartTime = tr.startTime()
elif endCondition and (phishStartTime is not None) and (phishEndTime is None):
phishEndTime = tr.startTime()
# We found a new window, save it, reset and look for any additional windows
self._textProduct.debug_print("Found a new window:", 1)
self._textProduct.debug_print("window phishStartTime = %s window phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1)
windows.append((phishStartTime, phishEndTime))
phishStartTime = None
phishEndTime = None
self._textProduct.debug_print("Looking for additional windows", 1)
self._textProduct.debug_print("new phishStartTime = %s new phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1)
# Check for the case where a window doesn't end
if (phishStartTime is not None) and (phishEndTime is None):
self._textProduct.debug_print("Found a never-ending window:", 1)
self._textProduct.debug_print("window phishStartTime = %s window phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1)
windows.append((phishStartTime, None))
# Create the final window
if len(windows) == 0:
phishStartTime = None
phishEndTime = None
else:
phishStartTime = windows[0][0] # Start time of first window
phishEndTime = windows[-1][1] # End time of last window
self._textProduct.debug_print("Constructed the final window:", 1)
self._textProduct.debug_print("final phishStartTime = %s final phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1)
self._windowSurge = "Window of concern: "
@ -2907,7 +3026,7 @@ class StormSurgeSectionStats(SectionCommonStats):
self._textProduct.debug_print("surge startTime = %s self._onsetSurgeHour = %s " %
(self._textProduct._pp.pformat(startTime), self._onsetSurgeHour), 1)
if phishEndTime is not None and possibleStop >= 2:
if phishEndTime is not None:
self._endSurgeHour = self._calculateHourOffset(phishEndTime)
endTime = AbsTime(self._textProduct._issueTime_secs + self._endSurgeHour*60*60)
windowPeriod = self._textProduct.makeTimeRange(startTime, endTime)
@ -2917,18 +3036,12 @@ class StormSurgeSectionStats(SectionCommonStats):
startTimeDescriptor = self._textProduct._formatPeriod(windowPeriod)
# Modified to handle case where last grid is zero but did not have two grids
if phishEndTime is None or possibleStop == 1:
if phishEndTime is None:
self._windowSurge += "Begins " + startTimeDescriptor
elif phishStartTime == phishEndTime:
self._windowSurge += startTimeDescriptor
else:
endTimeDescriptor = self._textProduct._formatPeriod(windowPeriod, useEndTime = True)
if self._onsetSurgeHour > 12:
# self._windowSurge += startTimeDescriptor +\
# " through " +\
# endTimeDescriptor
self._windowSurge += startTimeDescriptor +\
" until " +\
endTimeDescriptor
@ -2936,17 +3049,22 @@ class StormSurgeSectionStats(SectionCommonStats):
self._windowSurge += "through " + endTimeDescriptor
if self._inundationMax is not None:
# Round so we don't store values like 1.600000023841858
# inundationMax is already rounded but should be stored as an int and not a float
self._currentAdvisory["StormSurgeForecast"] = int(self._inundationMax)
self._textProduct.debug_print("+"*60, 1)
self._textProduct.debug_print("In StormSurgeSectionStats._setStats", 1)
self._textProduct.debug_print("Done in StormSurgeSectionStats._setStats:", 1)
self._textProduct.debug_print("self._inundationMax = '%s'" %
(self._inundationMax), 1)
self._textProduct.debug_print("self._onsetSurgeHour = '%s'" %
(self._onsetSurgeHour), 1)
self._textProduct.debug_print("self._endSurgeHour = '%s'" %
(self._endSurgeHour), 1)
self._textProduct.debug_print("self._windowSurge = '%s'" %
(self._windowSurge), 1)
self._textProduct.debug_print("self._maxThreat = '%s'" %
(self._maxThreat), 1)
self._textProduct.debug_print("+"*60, 1)
class FloodingRainSectionStats(SectionCommonStats):

View file

@ -56,6 +56,8 @@ import com.raytheon.uf.edex.decodertools.core.DecoderTools;
* Jan 30, 2010 15779 lbousaidi added 4 letter to station id for ACR
* Aug 08, 2013 16408 wkwock Use different metar.cfg file and options
* May 14, 2014 2536 bclement moved WMO Header to common, removed TimeTools usage
* Feb 12, 2016 18665 snaples/bkowal Update MetarToShef transformer to use options from token or config file.
*
* </pre>
*
* @author jkorman
@ -457,28 +459,34 @@ public class MetarToShefTransformer extends
throws TransformerException {
ObsToSHEFOptions tmpOptions = null;
MetarToShefRun mtsr = mtsrList.get(report.getId());
String optionsToUse = null;
if (mtsr == null) {
tmpOptions = defaultOptions;
optionsToUse = this.metar2ShefOptions;
} else {
optionsToUse = (mtsr.getMetarToShefOptions() == null) ? this.metar2ShefOptions
: mtsr.getMetarToShefOptions();
tmpOptions = optionsList.get(mtsr.getConfigFileName()
+ mtsr.getMetarToShefOptions());
+ optionsToUse);
if (tmpOptions == null) {
// just to prevent t memory leak
if (optionsList.size() > MAX_LIST) {
optionsList.clear();
}
tmpOptions = new ObsToSHEFOptions(mtsr.getConfigFileName(),
mtsr.getMetarToShefOptions(), true);
optionsToUse, true);
optionsList
.put(mtsr.getConfigFileName()
+ mtsr.getMetarToShefOptions(), tmpOptions);
+ optionsToUse, tmpOptions);
}
mtsrList.remove(report.getId());
}
options = tmpOptions;
logger.info("Metar to SHEF for " + report.getStationId()
+ " use config file: " + options.getCfgFileName()
+ " with options:" + mtsr.getMetarToShefOptions());
+ " with options:" + optionsToUse);
configureArchiveDir();
return transformReport(report, headers);
@ -496,4 +504,4 @@ public class MetarToShefTransformer extends
mtsrList.putAll(matchLst);
}
}
}

View file

@ -83,7 +83,13 @@
<parameter>TP75pct24hr</parameter>
<parameter>TP90pct24hr</parameter>
<parameter>TP95pct24hr</parameter>
<parameter>TP5pct72hr</parameter>
<parameter>TP10pct72hr</parameter>
<parameter>TP25pct72hr</parameter>
<parameter>TP50pct72hr</parameter>
<parameter>TP75pct72hr</parameter>
<parameter>TP90pct72hr</parameter>
<parameter>TP95pct72hr</parameter>
</paramLevelMatches>
<contourStyle>
<displayUnits>in</displayUnits>

View file

@ -88,6 +88,13 @@
<parameter>TP75pct24hr</parameter>
<parameter>TP90pct24hr</parameter>
<parameter>TP95pct24hr</parameter>
<parameter>TP5pct72hr</parameter>
<parameter>TP10pct72hr</parameter>
<parameter>TP25pct72hr</parameter>
<parameter>TP50pct72hr</parameter>
<parameter>TP75pct72hr</parameter>
<parameter>TP90pct72hr</parameter>
<parameter>TP95pct72hr</parameter>
</paramLevelMatches>
<imageStyle>

View file

@ -139,7 +139,7 @@ Must be paired with proper vm code (also commented out in flashFloodWarning.vm)!
<bullet bulletName="rain3" bulletText="Three inches so far" bulletGroup="rainAmt" parseString="THREE INCHES OF RAIN HAVE ALREADY FALLEN"/>
<bullet bulletName="rainEdit" bulletText="User defined amount" bulletGroup="rainAmt" parseString="INCHES OF RAIN HAVE FALLEN"/>
<bullet bulletText="*********** ADDITIONAL INFO ***********" bulletType="title"/>
<bullet bulletName="listofcities" bulletDefault="true" bulletText="Select for a list of cities" bulletGroup="pcast" parseSting="&quot;LOCATIONS&quot;,&quot;INCLUDE...&quot;"/>
<bullet bulletName="listofcities" bulletDefault="true" bulletText="Select for a list of cities" bulletGroup="pcast" parseString="&quot;LOCATIONS&quot;,&quot;INCLUDE...&quot;"/>
<!-- <bullet bulletName="pathcast" bulletText="Generate Pathcast " bulletGroup="pcast" parseString="THE FOLLOWING LOCATIONS..."/>
-->
<bullet bulletName="addRainfall" bulletText="Additional rainfall of XX inches expected" parseString="ADDITIONAL RAINFALL"/>

View file

@ -5,6 +5,7 @@
Mike Dangelo 1/23/2014 added blankStatement bullet
Mike Rega 5/23/14 DR 17380 svr wx watch logic OB14.3.1
Mike Dangelo 6/24/2014 removed unnecessary example bullets
Evan Bookbinder 6/21/2015 fixed bad parse strings (thunderstorms) on two winter weather CTAs.
Phil Kurimski 10-20-2015 added campers CTA
-->
<warngenConfig>
@ -117,8 +118,8 @@ turned on unless the corresponding .vm file is turned on in a given template's .
<bullet bulletName="includeTorWatches" bulletText="Include Tornado Watches" parseString=""/>
<bullet bulletName="includeSvrWatches" bulletText="Include Severe Thunderstorm Watches" parseString=""/>
<bullet bulletText="******** WINTER WX CALLS TO ACTION (CHOOSE 1 OR MORE) *********" bulletType="title"/>
<bullet bulletName="advisoryCTA" bulletText="Advisory may be required" bulletGroup="toggle3" parseString="STORMS MAY INTENSIFY...MONITOR TV"/>
<bullet bulletName="advisoryEffectCTA" bulletText="Advisory in effect" bulletGroup="toggle3" parseString="FREQUENT CLOUD TO GROUND LIGHTNING IS OCCURRING"/>
<bullet bulletName="advisoryCTA" bulletText="Advisory may be required" bulletGroup="toggle3" parseString="WINTER WEATHER ADVISORY MAY BECOME NECESSARY"/>
<bullet bulletName="advisoryEffectCTA" bulletText="Advisory in effect" bulletGroup="toggle3" parseString="WINTER WEATHER ADVISORY IS IN EFFECT"/>
<bullet bulletName="snowSquallCTA" bulletText="Snow Squall" parseString="TORRENTIAL RAINFALL IS ALSO OCCURRING"/>
<bullet bulletName="freezingDrizzleCTA" bulletText="Freezing Drizzle/Rain" parseString="CONTACT YOUR NEAREST LAW ENFORCEMENT"/>
<bullet bulletName="flashFreezeCTA" bulletText="Flash Freeze" parseString="RAPID DROP IN TEMPERATURES"/>
@ -169,8 +170,8 @@ turned on unless the corresponding .vm file is turned on in a given template's .
<bullet bulletName="includeTorWatches" bulletText="Include Tornado Watches" parseString=""/>
<bullet bulletName="includeSvrWatches" bulletText="Include Severe Thunderstorm Watches" parseString=""/>
<bullet bulletText="******** WINTER WX CALLS TO ACTION (CHOOSE 1 OR MORE) *********" bulletType="title"/>
<bullet bulletName="advisoryCTA" bulletText="Advisory may be required" bulletGroup="toggle3" parseString="STORMS MAY INTENSIFY...MONITOR TV"/>
<bullet bulletName="advisoryEffectCTA" bulletText="Advisory in effect" bulletGroup="toggle3" parseString="FREQUENT CLOUD TO GROUND LIGHTNING IS OCCURRING"/>
<bullet bulletName="advisoryCTA" bulletText="Advisory may be required" bulletGroup="toggle3" parseString="WINTER WEATHER ADVISORY MAY BECOME NECESSARY"/>
<bullet bulletName="advisoryEffectCTA" bulletText="Advisory in effect" bulletGroup="toggle3" parseString="WINTER WEATHER ADVISORY IS IN EFFECT"/>
<bullet bulletName="snowSquallCTA" bulletText="Snow Squall" parseString="TORRENTIAL RAINFALL IS ALSO OCCURRING"/>
<bullet bulletName="freezingDrizzleCTA" bulletText="Freezing Drizzle/Rain" parseString="CONTACT YOUR NEAREST LAW ENFORCEMENT"/>
<bullet bulletName="flashFreezeCTA" bulletText="Flash Freeze" parseString="RAPID DROP IN TEMPERATURES"/>

View file

@ -13,6 +13,7 @@
Richard Barnhill 10-28-2013 Changed/added torEMER bulletGroup to keep it locked on followups
Mike Dangelo 1-23-2014 Changed parseStrings for default safety rules CTAs and law enf CTA
Evan Bookbinder 9-5-2014 Fixed law enf CTA parse strings to match
Evan Bookbinder 6-15-15 Fixed incorrect softball and grapefruit hail sizes
Evan Bookbinder 12-7-2015 Added TOR EMER CTA back into cta1 bullet group (undid 1/23/2014 change)
-->
@ -109,8 +110,8 @@ turned on unless the corresponding .vm file is turned on in a given template's .
<bullet bulletName="tennisBallHail" bulletText="Tennis ball hail (2 1/2&quot;)" bulletGroup="hailThreat" parseString="TENNIS BALL SIZE"/>
<bullet bulletName="baseballHail" bulletText="Baseball size hail (2 3/4&quot;)" bulletGroup="hailThreat" parseString="BASEBALL SIZE"/>
<bullet bulletName="threeinchHail" bulletText="Three inch hail (3&quot;)" bulletGroup="hailThreat" parseString="THREE INCHES IN DIAMETER"/>
<bullet bulletName="grapefruitHail" bulletText="Grapefruit size hail (4&quot;)" bulletGroup="hailThreat" parseString="GRAPEFRUIT SIZE"/>
<bullet bulletName="softballHail" bulletText="Softball size hail (4 1/4&quot;)" bulletGroup="hailThreat" parseString="SOFTBALL SIZE"/>
<bullet bulletName="softballHail" bulletText="Softball size hail (4&quot;)" bulletGroup="hailThreat" parseString="SOFTBALL SIZE"/>
<bullet bulletName="grapefruitHail" bulletText="Grapefruit size hail (4 1/2&quot;)" bulletGroup="hailThreat" parseString="GRAPEFRUIT SIZE"/>
-->
<bullet bulletText="" bulletType="title"/>
<bullet bulletText="****** ADDITIONAL REPORTS *******" bulletType="title"/>
@ -173,8 +174,8 @@ turned on unless the corresponding .vm file is turned on in a given template's .
<bullet bulletName="tennisBallHail" bulletText="Tennis ball hail (2 1/2&quot;)" bulletGroup="hailThreat" parseString="TENNIS BALL SIZE"/>
<bullet bulletName="baseballHail" bulletText="Baseball size hail (2 3/4&quot;)" bulletGroup="hailThreat" parseString="BASEBALL SIZE"/>
<bullet bulletName="threeinchHail" bulletText="Three inch hail (3&quot;)" bulletGroup="hailThreat" parseString="THREE INCHES IN DIAMETER"/>
<bullet bulletName="grapefruitHail" bulletText="Grapefruit size hail (4&quot;)" bulletGroup="hailThreat" parseString="GRAPEFRUIT SIZE"/>
<bullet bulletName="softballHail" bulletText="Softball size hail (4 1/4&quot;)" bulletGroup="hailThreat" parseString="SOFTBALL SIZE"/>
<bullet bulletName="softballHail" bulletText="Softball size hail (4&quot;)" bulletGroup="hailThreat" parseString="SOFTBALL SIZE"/>
<bullet bulletName="grapefruitHail" bulletText="Grapefruit size hail (4 1/2&quot;)" bulletGroup="hailThreat" parseString="GRAPEFRUIT SIZE"/>
-->
<bullet bulletText="" bulletType="title"/>
<bullet bulletText="****** ADDITIONAL REPORTS *******" bulletType="title"/>

View file

@ -73,6 +73,9 @@ HDS ^(YEI.[89]8) KWNH (..)(..)(..)[^!]*!(grib|grib2)/ncep/([^/]*)/#([^/]*)/([0-9
# ZETA98 KWNE 311200 /mRFC_QPE !grib/ncep/RFC_QPE/#240/201101311200/F006/APCP/sfc/
HDS ^(ZETA98) (K[NW][EN][ES]) (..)(..)(..)([^!]*)!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})/([^/]*)/([^/]*)
FILE -overwrite -log -close -edex /data_store/\7/(\3:yyyy)(\3:mm)\3/\4/\8/GRID\9/\(11)Z_\(12)_\(13)-\1_\2_\3\4\5_(seq).\7.%Y%m%d%H
# DR 18644 - Pattern to account for change to grib2
ANY ^(ZETA98) (K[NW][EN][ES]) (..)(..)(..)([^!]*)!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})(F[0-9]{3})/([^/]*)
FILE -overwrite -log -close -edex /data_store/\7/(\3:yyyy)(\3:mm)\3/\4/\8/GRID\9/\(11)Z_\(12)_\(13)-\1_\2_\3\4\5_(seq).\7.%Y%m%d%H
# AWIPS 1 GRID ^ZEGA98.*KNES /img/SBN/Raw
#
@ -887,7 +890,10 @@ ANY ^(FEAK[45][7-9]|FOAK5[7-9]|FECN[35]0|FOCN30|FEPA[45]0|FOPA50|FEUS5[1-6]|F[EO
EXP (.*ecmwf_mos_decrypted.*)
FILE -overwrite -log -close -edex \1
# DR 18637: PQPF data
NGRID ^(HEN[A-KXY][0-9][0-9]) (KWNH) (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/([0-9]{8})([0-9]{4})(F[0-9]{3})/([^/]*)
FILE -overwrite -log -close -edex /data_store/\6/(\3:yyyy)(\3:mm)\3/\4/\7/GRID\8/\(10)Z_\(11)-\1_\2_\3\4\5_(seq).\6.%Y%m%d%H
# This separate pattern necessary because some pqpf data cause ldm grib2 errors and it doesn't parse entire grib record
NGRID ^(HEN[A-KXY][0-9][0-9]) (KWNH) (..)(..)(..)[^!]*!(grib|grib2)/[^/]*/([^/]*)/#([^/]*)/FHRS/([^/]*)
FILE -overwrite -log -close -edex /data_store/\6/(\3:yyyy)(\3:mm)\3/\4/\7/GRID\8/\1_\2_\3\4\5_(seq).\6.%Y%m%d%H