Issue #2653. Corrected decoding of SNOW monitor data.

Former-commit-id: 5bbb774073 [formerly 714fd018ef] [formerly ab7fc816b4 [formerly 050f002ff7af3e68c31f5c1949ff5f82fa2e7a9b]]
Former-commit-id: ab7fc816b4
Former-commit-id: 0fb9810e91
This commit is contained in:
Slav Korolev 2014-01-06 15:59:59 -05:00
parent 1568132e22
commit eb5ec35275
3 changed files with 125 additions and 309 deletions

View file

@ -7,103 +7,116 @@ import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.fssobs.FSSObsRecord;
import com.raytheon.uf.common.monitor.data.ObConst;
import com.raytheon.uf.common.monitor.data.ObConst.ReportType;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.monitor.data.ObReport;
/**
* @author skorolev (initial creation)
* Generates FSSObs Report for tables.
*
* Change history:
* Date Ticket # Engineer Description
* ---------------------------------------------------
* May 15, 2012 14510 zhao Modified generateObReport()
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* skorolev Initial creation
* May 15, 2012 14510 zhao Modified generateObReport()
* Jan 06, 2014 2653 skorolev Included SNOW data into ObReport.
*
*
* </pre>
*
* @author skorolev
* @version 1.0
*/
public class GenerateFSSObReport {
private static IUFStatusHandler statusHandler = UFStatus
.getHandler(GenerateFSSObReport.class);
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.monitor.IObReportable#generateObReport(com.raytheon
* .uf.common.dataplugin.PluginDataObject,
* com.raytheon.uf.viz.monitor.data.ObReport,
* com.raytheon.uf.common.monitor.data.ObConst.ChosenAppKey)
*/
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.monitor.IObReportable#generateObReport(com.raytheon
* .uf.common.dataplugin.PluginDataObject,
* com.raytheon.uf.viz.monitor.data.ObReport,
* com.raytheon.uf.common.monitor.data.ObConst.ChosenAppKey)
*/
public static ObReport generateObReport(PluginDataObject report) {
// Generate the observation report.
ObReport obReport = new ObReport();
FSSObsRecord metar = (FSSObsRecord) report;
try {
obReport.setObservationTime(metar.getTimeObs().getTime());
obReport.setRefHour(metar.getRefHour().getTime());
} catch (Exception e) {
System.out.println("Warning: missing obsTime or refHour at getTimeObs() when processing obs data; " + e + "; trying to set obsTime and refHour from dataURI");
obReport.setTimesFromFssobDataURI(report.getDataURI());
}
obReport.setPlatformId(metar.getPlatformId());
obReport.setStationary(true);
obReport.setLatitude((float) metar.getLatitude());
obReport.setLongitude((float) metar.getLongitude());
// Table data:
obReport.setCeiling(metar.getCeiling());
obReport.setWindDir(metar.getWindDir());
obReport.setWindSpeed(metar.getWindSpeed());
obReport.setMaxWindSpeed(metar.getMaxWindSpeed());
obReport.setWindGust(metar.getWindGust());
obReport.setRelativeHumidity(metar.getRelativeHumidity());
try {
obReport.setVisibility(metar.getVisibility());
} catch (Exception e) {
obReport.setVisibility(0);
}
obReport.setDewpoint(metar.getDewpoint());
obReport.setTemperature(metar.getTemperature());
obReport.setDewpointDepr(metar.getDewpointDepr());
// Generate the observation report.
ObReport obReport = new ObReport();
FSSObsRecord metar = (FSSObsRecord) report;
try {
obReport.setObservationTime(metar.getTimeObs().getTime());
obReport.setRefHour(metar.getRefHour().getTime());
} catch (Exception e) {
statusHandler
.error("Warning: missing obsTime or refHour at getTimeObs() when processing obs data; "
+ e
+ "; trying to set obsTime and refHour from dataURI");
obReport.setTimesFromFssobDataURI(report.getDataURI());
}
obReport.setPlatformId(metar.getPlatformId());
obReport.setStationary(true);
obReport.setLatitude((float) metar.getLatitude());
obReport.setLongitude((float) metar.getLongitude());
// Table data:
obReport.setCeiling(metar.getCeiling());
obReport.setWindDir(metar.getWindDir());
obReport.setWindSpeed(metar.getWindSpeed());
obReport.setMaxWindSpeed(metar.getMaxWindSpeed());
obReport.setWindGust(metar.getWindGust());
obReport.setRelativeHumidity(metar.getRelativeHumidity());
try {
obReport.setVisibility(metar.getVisibility());
} catch (Exception e) {
obReport.setVisibility(0);
}
obReport.setDewpoint(metar.getDewpoint());
obReport.setTemperature(metar.getTemperature());
obReport.setDewpointDepr(metar.getDewpointDepr());
obReport.setPresentWx(getPrWX(metar.getPresWeather()));
obReport.setPresentWx(getPrWX(metar.getPresWeather()));
obReport.setHighResWaveHeight(ObConst.MISSING);
obReport.setWaveSteepness(metar.getWaveSteepness());
obReport.setHighResWaveHeight(ObConst.MISSING);
obReport.setWaveSteepness(metar.getWaveSteepness());
obReport.setSeaLevelPress(metar.getSeaLevelPress());
obReport.setWavePeriod(metar.getWavePeriod());
obReport.setWindGust(metar.getWindGust());
obReport.setPSwellHeight(metar.getPrimarySwellWaveHeight()
.floatValue());
obReport.setPSwellPeriod(metar.getPrimarySwellWavePeriod());
obReport.setPSwellDir(metar.getPrimarySwellWaveDir().floatValue());
obReport.setSSwellHeight(metar.getSecondarySwellWaveHeight()
.floatValue());
obReport.setSSwellPeriod(metar.getSecondarySwellWavePeriod());
obReport.setSSwellDir(metar.getSecondarySwellWaveDir().floatValue());
obReport.setPressure(metar.getPressureAltimeter());
obReport.setPressureChange(metar.getPressChange3Hour());
try {
obReport.setPressChangeChar(Short.parseShort(metar
.getPressChangeChar()));
} catch (NumberFormatException e) {
obReport.setPressChangeChar((short) 0);
}
obReport.setSeaLevelPress(metar.getSeaLevelPress());
obReport.setWavePeriod(metar.getWavePeriod());
obReport.setWindGust(metar.getWindGust());
obReport.setPSwellHeight(metar.getPrimarySwellWaveHeight().floatValue());
obReport.setPSwellPeriod(metar.getPrimarySwellWavePeriod());
obReport.setPSwellDir(metar.getPrimarySwellWaveDir().floatValue());
obReport.setSSwellHeight(metar.getSecondarySwellWaveHeight()
.floatValue());
obReport.setSSwellPeriod(metar.getSecondarySwellWavePeriod());
obReport.setSSwellDir(metar.getSecondarySwellWaveDir().floatValue());
obReport.setPressure(metar.getPressureAltimeter());
obReport.setPressureChange(metar.getPressChange3Hour());
try {
obReport.setPressChangeChar(Short.parseShort(metar
.getPressChangeChar()));
} catch (NumberFormatException e) {
obReport.setPressChangeChar((short) 0);
}
obReport.setHourlyPrecip(metar.getHourlyPrecip());
// obReport.setPresentWx(WeatherCondition.toCanonicalForm(metar.getWeatherCondition()));
obReport.setRawMessage(metar.getRawMessage());
// TODO: report type ???
obReport.setReportType(ReportType.METAR);
obReport.setHourlyPrecip(metar.getHourlyPrecip());
// if (chosenAppKey == ChosenAppKey.SNOW) {
// obReport = ObUtil.generateObReportSnow(obReport,
// metar.getMessageData());
// } else if (chosenAppKey == ChosenAppKey.FOG) {
// obReport = ObUtil.generateObReportFog(obReport,
// metar.getSkyCoverage(),
// metar.getVertVisibility());
// }
obReport.setSeaSurfaceTemp(metar.getSeaSurfaceTemp());
return obReport;
}
obReport.setRawMessage(metar.getRawMessage());
obReport.setReportType(ReportType.METAR);
obReport.setSnincrHourly(metar.getSnincrHourly());
obReport.setSnincrTotal(metar.getSnincrTotal());
obReport.setFrostbiteTime(metar.getFrostbiteTime());
obReport.setWindChill(metar.getWindChill());
obReport.setSnowDepth(metar.getSnowDepth());
obReport.setSeaSurfaceTemp(metar.getSeaSurfaceTemp());
return obReport;
}
/**
* Construct Present Weather string.
*
* @param presWeather
* @return
*/

View file

@ -22,7 +22,6 @@ package com.raytheon.uf.viz.monitor.util;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
import java.util.Set;
import java.util.TimeZone;
@ -46,6 +45,7 @@ import com.raytheon.uf.viz.monitor.data.ObReport;
* Jan 19, 2010 4240 zhao Modified generateObReportSnow method
* Aug 14, 2013 2262 dgilling Use new wxmath method for calcrh.
* Oct 23, 2013 2361 njensen Removed two unused methods
* Jan 06, 2014 2653 skorolev Removed not used methods.
*
* </pre>
*
@ -177,80 +177,6 @@ public final class ObUtil {
return ThreatLevel.GRAY;
}
/**
* This method supplements generation of an observation report for SNOW
*
* @param obReport
* -- the observation report
* @return -- the generated observation report
*/
public static ObReport generateObReportSnow(ObReport obReport,
String remarks) {
// Check parameters for wind chill/frostbite
// time calculation (upper limit for wind chill
// is set at 40F) :
if ((obReport.getTemperature() == ObConst.MISSING)
|| (obReport.getTemperature() > 277.6) // 40 F
|| (obReport.getWindSpeed() == ObConst.MISSING)
|| (obReport.getWindSpeed() > 1e36f)) {
obReport.setWindChill(ObConst.MISSING);
obReport.setFrostbiteTime(ObConst.MISSING);
} else {
// Kelvin to Celsius
// float tempC = obReport.getTemperature() - 273.15f;
// obReport.getTemperature() in Celsius already
// [Jan 19, 2010, zhao]
float tempC = obReport.getTemperature();
// mps to kph
// float speedKPH = obReport.getWindSpeed() * 3.6f;
// mph to kph
// [Jan 19, 2010, zhao]
float speedKPH = obReport.getWindSpeed() * 1.6f;
// Call AWIPS wind chill routine. Return units
// are in Celsius.
float windChillC = calcWindChill(tempC, speedKPH);
float windChillK = 273.15f;
// Check for too-warm default (default should come back
// as 1e37 if conditions are too warm, so we'll check one
// order of magnitude lower, for > 1e36.) Actual limit
// is 16C or ~61F. If the wind chill is valid, carry
// it through the active program as Fahrenheit, but store
// it in the NetCDF files as Kelvin (to match the other
// temperature parameters).
if (windChillC > 1e36f) {
obReport.setWindChill(ObConst.MISSING);
windChillK = ObConst.MISSING;
} else {
// Carry through the program in Fahrenheit...
obReport.setWindChill(1.8f * windChillC + 32.0f);
windChillK += windChillC;
}
// Calculate frostbite time.
float fbMinutes = calcFrostbiteTime(speedKPH, tempC);
obReport.setFrostbiteTime(fbMinutes);
}
// Check for Snow Increasing Rapidly (SNINCR) in the remarks.
// First, retrieve the current raw report (don't want to have
// to store it in the Report class).
// Call routine to get the hourly and total values, if present.
getSNINCR(remarks, obReport);
// Call routine to get snow depth, if present.
getSnowDepth(remarks, obReport);
return obReport;
}
/**
* This method supplements generation of an observation report for FOG
*
@ -306,140 +232,6 @@ public final class ObUtil {
return ceiling >= 1e20f ? ObConst.MISSING : ceiling;
}
/**
* This method calculates the windChill from temperature and windSpeed.
*
* @param temp
* -- temperature in degrees Celsius
* @param windSpd
* -- wind speed in kilometers per hour
* @return -- wind chill in degrees Celsius
*/
public static float calcWindChill(float temp, float windSpd) {
float spd;
/* arbitrarily do the calculation only for temps at or below 60F */
if (temp > 16.) {
return 1e37f;
}
/* no chilling if speed < 4 mph = 6.44km/h */
if (windSpd < 6.4) {
return temp;
}
/* peg speed at 80 mph (= 128.75 km/h) */
if (windSpd > 128.75) {
spd = 128.75f;
} else {
spd = windSpd;
}
spd = (float) Math.pow(spd, 0.16);
float windChillTemp = 13.12f + 0.6215f * temp - 11.37f * spd + 0.3965f
* temp * spd;
return windChillTemp;
}
/**
* This method calculates the amount of time needed for frostbite to occur
* on exposed skin.
*
* @param windspeedKPH
* -- wind speed in kilometers per hour
* @param temperatureC
* -- temperature in degrees Celsius
* @return -- time in minutes
*/
public static float calcFrostbiteTime(float windspeedKPH, float temperatureC) {
float fbMinutes = ObConst.MISSING;
// Temperature must be lower than -4.8C (23F) to avoid a calculation
// error (a negative number to -1.668 power is NAN)
if (temperatureC < -4.8) {
fbMinutes = ((-24.5f * ((0.667f * windspeedKPH) + 4.8f)) + 2111f)
* (float) Math.pow((-4.8 - temperatureC), -1.668);
} else {
return ObConst.MISSING;
}
// Check for frostbite boundaries
if (!(fbMinutes <= 30 && windspeedKPH > 25.0 && windspeedKPH <= 80.5)) {
fbMinutes = ObConst.MISSING;
}
return fbMinutes;
}
/**
* This method retrieves "snow increasing rapidly" parameters -- hourly and
* total snowfall in inches -- from a METAR's remarks section. This method
* update the observation report with the "snow increasing rapidly"
* parameters.
*
* @param remarks
* -- the METAR remarks
* @param obReport
* -- the observation report
* @return success
*/
public static boolean getSNINCR(String remarks, ObReport obReport) {
// New up a Scanner to use to parse the raw data for desired pattern.
Scanner sc = new Scanner(remarks);
String whatMatched;
whatMatched = sc.findWithinHorizon("REMARK_EXPR", 0);
if (whatMatched != null) {
whatMatched = sc.findWithinHorizon("SNINCR", 0);
if (whatMatched != null) {
sc.useDelimiter("/");
obReport.setSnincrHourly(sc.nextInt());
sc.reset();
obReport.setSnincrTotal(sc.nextInt());
} else {
obReport.setSnincrHourly(ObConst.MISSING);
obReport.setSnincrTotal(ObConst.MISSING);
}
} else {
obReport.setSnincrHourly(ObConst.MISSING);
obReport.setSnincrTotal(ObConst.MISSING);
}
return true;
}
/**
* This method retrieves "snow depth" parameters -- total snow depth in
* inches -- from a METAR's remarks section. This method update the
* observation report with the "snow depth" parameters.
*
* @param remarks
* -- the METAR remarks
* @param obReport
* -- the observation report
* @return success
*/
public static boolean getSnowDepth(String remarks, ObReport obReport) {
// New up a Scanner to use to parse the raw data for desired pattern.
Scanner sc = new Scanner(remarks);
String whatMatched;
whatMatched = sc.findWithinHorizon("REMARK_EXPR", 0);
if (whatMatched != null) {
whatMatched = sc.findWithinHorizon("4/", 0);
if (whatMatched != null) {
obReport.setSnowDepth(sc.nextInt());
} else {
obReport.setSnowDepth(ObConst.MISSING);
}
} else {
obReport.setSnowDepth(ObConst.MISSING);
}
return true;
}
/**
* This method determines the RH from temperature and dew point in degrees
* celsius.

View file

@ -54,6 +54,8 @@ import com.raytheon.uf.edex.pointdata.PointDataQuery;
* Nov 26, 2012 1297 skorolev Changed ArrayList to List.Clean code
* May 15, 2013 1869 bsteffen Remove DataURI column from ldadmesonet.
* May 16, 2013 1869 bsteffen Rewrite dataURI property mappings.
* Jan 02, 2014 2580 skorolev Fixed FSSObs error.
* Jan 06, 2014 2653 skorolev Corrected decoding of snincrHourly and snincrTotal.
*
* </pre>
*
@ -65,6 +67,9 @@ public class FSSObsUtils {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(FSSObsUtils.class);
/** Centigrade -> Kelvin */
public static final float TMCK = 273.15f;
/**
* Value of missed data.
*/
@ -348,14 +353,18 @@ public class FSSObsUtils {
* @return -- Snow data from METAR
*/
public static float[] getSnowData(FSSObsRecord tableRow) {
// Check parameters for wind chill in K/frostbite in minutes/snow
// increase and depth in inches
// Check parameters for wind chill in K
// frost bite in minutes
// snow increase and depth in inches
// time calculation (upper limit for wind chill
// is set at 40F and wind speed between 14 and 43 knts) :
float[] retVal = new float[5];
for (int i = 0; i < 5; i++) {
retVal[i] = MISSING;
}
float temp = tableRow.getTemperature();
float windspd = tableRow.getWindSpeed();
Scanner sc = new Scanner(tableRow.getRawMessage());
String whatMatched;
whatMatched = sc.findWithinHorizon("RMK", 0);
@ -363,31 +372,33 @@ public class FSSObsUtils {
whatMatched = sc.findWithinHorizon("SNINCR", 0);
if (whatMatched != null) {
sc.useDelimiter("/");
// last hour snow in inches
retVal[0] = sc.nextInt();
if (sc.hasNext()) {
// last hour snow in inches
retVal[0] = Float.parseFloat(sc.next());
}
sc.reset();
// total snow in inches
retVal[1] = sc.nextInt();
sc.findWithinHorizon("/", 0);
if (sc.hasNextInt()) {
// total snow in inches
retVal[1] = sc.nextInt();
}
}
whatMatched = sc.findWithinHorizon("4/", 0);
if (whatMatched != null) {
// snow depth on ground in inches
if (retVal.length >= 5) {
retVal[5] = sc.nextInt();
}
retVal[2] = sc.nextInt();
}
}
if ((tableRow.getTemperature() != MISSING)
&& (tableRow.getTemperature() < 4.4f)
// 277.6 K = 40 F = 4.44444 Celsium
&& (tableRow.getWindSpeed() != MISSING)
&& (tableRow.getWindSpeed() <= 43.0f && tableRow.getWindSpeed() >= 14.0f)) {
float speedKPH = tableRow.getWindSpeed() * 1.6f;
float t = tableRow.getTemperature();
sc.close();
if ((temp != MISSING) && (temp < 4.4f)
// 277.6 K = 40 F = 4.44444 C
&& (windspd != MISSING)
&& (windspd <= 43.0f && windspd >= 14.0f)) {
float speedKPH = windspd * 1.6f;
// in Kelvin
retVal[3] = calcWindChill(t, speedKPH) + 273.15f;
retVal[3] = calcWindChill(temp, speedKPH) + TMCK;
// in minutes
retVal[4] = calcFrostbiteTime(speedKPH, t);
retVal[4] = calcFrostbiteTime(speedKPH, temp);
}
return retVal;
}