Omaha #3229 added bufr buoy support
small bufr obs refactor fixed empty array issue in bufr parser Change-Id: Ie21ffdafed8b137264db4751c147ce1dd13eabd2 Former-commit-id:5be93b4084
[formerly99e86f95be
[formerly 763ea813523d2e6a6da3fb6a80c94939ce605f6c]] Former-commit-id:99e86f95be
Former-commit-id:2e0408ca10
This commit is contained in:
parent
29a997ba9a
commit
d840f27737
15 changed files with 460 additions and 122 deletions
|
@ -59,6 +59,7 @@ import com.raytheon.uf.common.status.UFStatus;
|
|||
* Apr 01, 2014 2905 bclement moved splitter functionality to separate utility
|
||||
* added scanForStructField()
|
||||
* Apr 29, 2014 2906 bclement added close()
|
||||
* Jun 12, 2014 3229 bclement fixed empty array in structure problem
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -496,8 +497,9 @@ public class BufrParser {
|
|||
Variable var, boolean charArrayAsString) {
|
||||
Array array = typedArray.array;
|
||||
DataType type = typedArray.type;
|
||||
long size = array.getSize();
|
||||
Object value;
|
||||
if (charArrayAsString && array.getSize() > 1
|
||||
if (charArrayAsString && size > 1
|
||||
&& type.equals(DataType.CHAR)) {
|
||||
int len = (int) array.getSize();
|
||||
StringBuilder builder = new StringBuilder(len);
|
||||
|
@ -505,8 +507,10 @@ public class BufrParser {
|
|||
builder.append(array.getChar(i));
|
||||
}
|
||||
value = builder.toString();
|
||||
} else {
|
||||
} else if (size == 1) {
|
||||
value = array.getObject(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return processValue(value, var);
|
||||
|
@ -635,7 +639,16 @@ public class BufrParser {
|
|||
StructureLevel level = structStack.peek();
|
||||
StructureData s = level.getStructData();
|
||||
Member m = level.getCurrentMember();
|
||||
rval = new TypedArray(s.getArray(m), m.getDataType());
|
||||
Array memberArray = m.getDataArray();
|
||||
/*
|
||||
* StructureData.getArray() doesn't handle if the member has an
|
||||
* empty array, skip structure access and return direct array
|
||||
*/
|
||||
if (memberArray != null && memberArray.getSize() < 1) {
|
||||
rval = new TypedArray(m.getDataArray(), m.getDataType());
|
||||
} else {
|
||||
rval = new TypedArray(s.getArray(m), m.getDataType());
|
||||
}
|
||||
} else if (currentVar != null) {
|
||||
rval = new TypedArray(currentVar.read(), currentVar.getDataType());
|
||||
}
|
||||
|
|
|
@ -10,8 +10,17 @@
|
|||
<constructor-arg ref="sfcobsPluginName" />
|
||||
</bean>
|
||||
|
||||
<bean factory-bean="bufrobsProcessor" factory-method="register">
|
||||
<constructor-arg ref="bufrobsSynopticLandDecoder" />
|
||||
<bean id="bufrobsBuoyDecoder" class="com.raytheon.uf.edex.plugin.bufrobs.buoy.BuoyBufrDecoder" depends-on="sfcObsRegistered">
|
||||
<constructor-arg ref="sfcobsPluginName" />
|
||||
</bean>
|
||||
|
||||
<bean factory-bean="bufrobsProcessor" factory-method="registerAll">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref bean="bufrobsSynopticLandDecoder" />
|
||||
<ref bean="bufrobsBuoyDecoder" />
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="bufrobsDistRegistry" factory-bean="distributionSrv" factory-method="register">
|
||||
|
|
|
@ -26,11 +26,13 @@ import java.util.Arrays;
|
|||
import java.util.Calendar;
|
||||
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 javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.NonSI;
|
||||
import javax.measure.unit.SI;
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
@ -59,6 +61,7 @@ import com.raytheon.uf.common.nc.bufr.tables.TranslationTableManager;
|
|||
import com.raytheon.uf.common.nc.bufr.time.BufrTimeFieldParser;
|
||||
import com.raytheon.uf.common.nc.bufr.time.TimeFieldParseException;
|
||||
import com.raytheon.uf.common.nc.bufr.util.BufrMapper;
|
||||
import com.raytheon.uf.common.nc.bufr.util.TranslationTableGenerator;
|
||||
import com.raytheon.uf.common.pointdata.ParameterDescription;
|
||||
import com.raytheon.uf.common.pointdata.PointDataContainer;
|
||||
import com.raytheon.uf.common.pointdata.PointDataDescription;
|
||||
|
@ -86,6 +89,9 @@ import com.raytheon.uf.edex.plugin.bufrobs.category.CategoryParser;
|
|||
* ------------ ---------- ----------- --------------------------
|
||||
* Mar 21, 2014 2906 bclement Initial creation
|
||||
* Apr 21, 2014 2906 bclement populated wmo header in record for consistency
|
||||
* Jun 12, 2014 3229 bclement default implementation for getTranslationFile() and createStationId()
|
||||
* moved processGeneralFields() and processPrecip() from synoptic land decoder
|
||||
*
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -94,6 +100,12 @@ import com.raytheon.uf.edex.plugin.bufrobs.category.CategoryParser;
|
|||
*/
|
||||
public abstract class AbstractBufrSfcObsDecoder {
|
||||
|
||||
public static final Set<String> DEFAULT_LOCATION_FIELDS = new HashSet<String>(
|
||||
Arrays.asList(SfcObsPointDataTransform.LATITUDE,
|
||||
SfcObsPointDataTransform.LONGITUDE,
|
||||
SfcObsPointDataTransform.STATION_ID,
|
||||
SfcObsPointDataTransform.ELEVATION));
|
||||
|
||||
public static final String localizationAliasDirectory = "bufrobs"
|
||||
+ File.separator + "alias";
|
||||
|
||||
|
@ -429,12 +441,15 @@ public abstract class AbstractBufrSfcObsDecoder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get obs-type specific translation table file name
|
||||
* Get translation table file name
|
||||
*
|
||||
* @param tableId
|
||||
* @return
|
||||
*/
|
||||
abstract protected String getTranslationFile(String tableId);
|
||||
protected String getTranslationFile(String tableId) {
|
||||
tableId = TranslationTableGenerator.replaceWhiteSpace(tableId, "_");
|
||||
return tableId + ".xml";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get obs-type specific parameter alias file name
|
||||
|
@ -539,7 +554,7 @@ public abstract class AbstractBufrSfcObsDecoder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Find and format WMO Index to stationId
|
||||
* Find and format stationId
|
||||
*
|
||||
* @param parser
|
||||
* @return null if no station id found
|
||||
|
@ -547,21 +562,13 @@ public abstract class AbstractBufrSfcObsDecoder {
|
|||
*/
|
||||
protected String createStationId(BufrParser parser)
|
||||
throws BufrObsDecodeException {
|
||||
/* WMO indexes have two parts, block and id */
|
||||
Number id = (Number) getFieldValue(parser, false);
|
||||
if (id == null) {
|
||||
log.debug("BUFR file " + parser.getFile()
|
||||
+ " missing station id field: " + parser.getFieldName());
|
||||
/* most subclasses will override this */
|
||||
Object obj = getFieldValue(parser, true);
|
||||
if (obj != null) {
|
||||
return obj.toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
Number block = getWMOBlock(parser);
|
||||
if (block == null) {
|
||||
log.debug("BUFR file " + parser.getFile()
|
||||
+ " missing station id field: " + WMO_BLOCK_FIELD);
|
||||
return null;
|
||||
}
|
||||
|
||||
return String.format(WMO_INDEX_FORMAT, block, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -859,6 +866,84 @@ public abstract class AbstractBufrSfcObsDecoder {
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if field is table lookup or direct and handles accordingly
|
||||
*
|
||||
* @param record
|
||||
* @param parser
|
||||
* @param baseName
|
||||
* @throws BufrObsDecodeException
|
||||
*/
|
||||
protected void processGeneralFields(ObsCommon record, BufrParser parser,
|
||||
String baseName) throws BufrObsDecodeException {
|
||||
String unitStr = parser.getFieldUnits();
|
||||
if (unitStr != null && isTableLookup(unitStr)) {
|
||||
processLookupTableField(record, parser, baseName);
|
||||
} else {
|
||||
processDirectField(record, parser, baseName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Precip doesn't have individual fields for different hour periods. One
|
||||
* structure contains the general precip field with a time period. This
|
||||
* method parses the time period to determine what field the precip data is
|
||||
* for.
|
||||
*
|
||||
* @param record
|
||||
* @param parser
|
||||
* @throws BufrObsDecodeException
|
||||
*/
|
||||
protected void processPrecip(ObsCommon record, BufrParser parser,
|
||||
String precipTimePeriodField) throws BufrObsDecodeException {
|
||||
Number precip = getInUnits(parser, SI.MILLIMETER);
|
||||
if (precip == null) {
|
||||
/* missing value */
|
||||
return;
|
||||
}
|
||||
BufrDataItem timeData = parser.scanForStructField(
|
||||
precipTimePeriodField, false);
|
||||
if (timeData == null || timeData.getValue() == null) {
|
||||
log.error("Found precipitation field missing time data. Field: "
|
||||
+ parser.getFieldName() + ", Table: "
|
||||
+ parser.getFieldUnits());
|
||||
return;
|
||||
}
|
||||
Number period = getInUnits(timeData.getVariable(), timeData.getValue(),
|
||||
NonSI.HOUR);
|
||||
PointDataView pdv = record.getPointDataView();
|
||||
switch (Math.abs(period.intValue())) {
|
||||
case 1:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP1_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 3:
|
||||
/* text synop obs doesn't have 3HR precip */
|
||||
log.debug("Received precip period not supported by point data view: "
|
||||
+ Math.abs(period.intValue()) + " HOUR");
|
||||
break;
|
||||
case 6:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP6_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 12:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP12_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 18:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP18_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 24:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP24_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
default:
|
||||
log.error("Unknown precipitation period '" + period.intValue()
|
||||
+ "' in BUFR file " + parser.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return set of category keys that this parser handles
|
||||
* @throws BufrObsDecodeException
|
||||
|
|
|
@ -22,6 +22,7 @@ package com.raytheon.uf.edex.plugin.bufrobs;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -46,6 +47,8 @@ import com.raytheon.uf.edex.plugin.bufrobs.category.CategoryKey;
|
|||
* ------------ ---------- ----------- --------------------------
|
||||
* Apr 01, 2014 2906 bclement Initial creation
|
||||
* Apr 29, 2014 2906 bclement close parser when finished
|
||||
* Jun 12, 2014 3229 bclement changed subcat attribute to use local to handle override
|
||||
* added registerAll()
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -59,7 +62,7 @@ public class BufrObsProcessor {
|
|||
|
||||
public static final String BUFR_CAT_ATTRIBUTE = "BUFR:category";
|
||||
|
||||
public static final String BUFR_SUBCAT_ATTRIBUTE = "BUFR:subCategory";
|
||||
public static final String BUFR_SUBCAT_ATTRIBUTE = "BUFR:localSubCategory";
|
||||
|
||||
private static final List<AbstractBufrSfcObsDecoder> decoders = new ArrayList<AbstractBufrSfcObsDecoder>();
|
||||
|
||||
|
@ -151,6 +154,19 @@ public class BufrObsProcessor {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #register(AbstractBufrSfcObsDecoder)
|
||||
* @param collection
|
||||
* @return
|
||||
*/
|
||||
public BufrObsProcessor registerAll(
|
||||
Collection<AbstractBufrSfcObsDecoder> collection) {
|
||||
synchronized (decoders) {
|
||||
decoders.addAll(collection);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first decoder that supports category key
|
||||
*
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* 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.uf.edex.plugin.bufrobs.buoy;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.sfcobs.ObsCommon;
|
||||
import com.raytheon.uf.common.nc.bufr.BufrDataItem;
|
||||
import com.raytheon.uf.common.nc.bufr.BufrParser;
|
||||
import com.raytheon.uf.common.nc.bufr.util.BufrMapper;
|
||||
import com.raytheon.uf.common.pointdata.spatial.SurfaceObsLocation;
|
||||
import com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrSfcObsDecoder;
|
||||
import com.raytheon.uf.edex.plugin.bufrobs.BufrObsDecodeException;
|
||||
|
||||
/**
|
||||
* Buoy decoder for BUFR formatted sea sfc obs.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 11, 2014 3229 bclement Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bclement
|
||||
* @version 1.0
|
||||
*/
|
||||
public class BuoyBufrDecoder extends AbstractBufrSfcObsDecoder {
|
||||
|
||||
public static final String BUOY_NAMESPACE = "buoy";
|
||||
|
||||
public static final String ALIAS_FILE_NAME = BUOY_NAMESPACE
|
||||
+ "-alias.xml";
|
||||
|
||||
public static final String CATEGORY_FILE_NAME = BUOY_NAMESPACE
|
||||
+ "-category.xml";
|
||||
|
||||
public static final String PRECIP_FIELD = "precip";
|
||||
|
||||
public static final String PRECIP_TIME_PERIOD_FIELD = "Time period or displacement-2";
|
||||
|
||||
public static final String FALLBACK_LAT_FIELD = "Latitude (high accuracy)";
|
||||
|
||||
public static final String FALLBACK_LON_FIELD = "Longitude (high accuracy)";
|
||||
|
||||
public static final String WMO_SUB_AREA_FIELD = "WMO Region sub-area";
|
||||
|
||||
public static final String BUOY_ID_FIELD = "Buoy/platform identifier";
|
||||
|
||||
public static final String STATION_ID_FORMAT = "%d%d%03d";
|
||||
|
||||
/**
|
||||
* @param pluginName
|
||||
* @throws BufrObsDecodeException
|
||||
*/
|
||||
public BuoyBufrDecoder(String pluginName) throws BufrObsDecodeException {
|
||||
super(pluginName);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrSfcObsDecoder#processField
|
||||
* (com.raytheon.uf.common.dataplugin.sfcobs.ObsCommon,
|
||||
* com.raytheon.uf.common.nc.bufr.BufrParser)
|
||||
*/
|
||||
@Override
|
||||
protected void processField(ObsCommon record, BufrParser parser)
|
||||
throws BufrObsDecodeException {
|
||||
BufrMapper mapper = getMapper();
|
||||
String bufrName = parser.getFieldName();
|
||||
Set<String> baseNames = mapper.lookupBaseNamesOrEmpty(bufrName,
|
||||
BUOY_NAMESPACE);
|
||||
if (baseNames.isEmpty()) {
|
||||
log.debug("Skipping unmapped field: " + bufrName);
|
||||
}
|
||||
for (String baseName : baseNames) {
|
||||
if (DEFAULT_LOCATION_FIELDS.contains(baseName)) {
|
||||
processLocationField(record.getLocation(), parser, baseName);
|
||||
} else if (PRECIP_FIELD.equalsIgnoreCase(baseName)) {
|
||||
processPrecip(record, parser, PRECIP_TIME_PERIOD_FIELD);
|
||||
} else {
|
||||
processGeneralFields(record, parser, baseName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrSfcObsDecoder#createStationId
|
||||
* (com.raytheon.uf.common.nc.bufr.BufrParser)
|
||||
*/
|
||||
@Override
|
||||
protected String createStationId(BufrParser parser)
|
||||
throws BufrObsDecodeException {
|
||||
/* WMO number is split into three parts */
|
||||
Number region = (Number) getFieldValue(parser, false);
|
||||
BufrDataItem subAreaData = parser.scanForStructField(
|
||||
WMO_SUB_AREA_FIELD, false);
|
||||
Number subArea = (Number) subAreaData.getValue();
|
||||
BufrDataItem buoyIdData = parser.scanForStructField(BUOY_ID_FIELD,
|
||||
false);
|
||||
Number bouyId = (Number) buoyIdData.getValue();
|
||||
if (region == null || subArea == null || bouyId == null) {
|
||||
String fields = parser.getFieldName() + ", " + WMO_SUB_AREA_FIELD
|
||||
+ ", or " + BUOY_ID_FIELD;
|
||||
throw new BufrObsDecodeException("BUFR file '" + parser.getFile()
|
||||
+ "' Missing one of the required station ID fields: "
|
||||
+ fields);
|
||||
}
|
||||
return String.format(STATION_ID_FORMAT, region.intValue(),
|
||||
subArea.intValue(), bouyId.intValue());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrSfcObsDecoder#finalizeRecord
|
||||
* (com.raytheon.uf.common.nc.bufr.BufrParser,
|
||||
* com.raytheon.uf.common.dataplugin.sfcobs.ObsCommon)
|
||||
*/
|
||||
@Override
|
||||
protected ObsCommon finalizeRecord(BufrParser parser, ObsCommon record)
|
||||
throws BufrObsDecodeException {
|
||||
record = super.finalizeRecord(parser, record);
|
||||
finalizeLocation(parser, record);
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parser
|
||||
* @param record
|
||||
* @throws BufrObsDecodeException
|
||||
*/
|
||||
private void finalizeLocation(BufrParser parser, ObsCommon record)
|
||||
throws BufrObsDecodeException {
|
||||
SurfaceObsLocation location = record.getLocation();
|
||||
if (location.getLocation() == null) {
|
||||
/* Argos not available, fallback to coarse lon/lat */
|
||||
BufrDataItem lonData = parser.scanForStructField(
|
||||
FALLBACK_LON_FIELD, false);
|
||||
Number lon = (Number) lonData.getValue();
|
||||
BufrDataItem latData = parser.scanForStructField(
|
||||
FALLBACK_LAT_FIELD, false);
|
||||
Number lat = (Number) latData.getValue();
|
||||
if (lon == null || lat == null) {
|
||||
throw new BufrObsDecodeException("BUFR file '"
|
||||
+ parser.getFile() + "' missing location information");
|
||||
}
|
||||
location.assignLocation(lat.doubleValue(), lon.doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrSfcObsDecoder#getAliasMapFile()
|
||||
*/
|
||||
@Override
|
||||
protected String getAliasMapFile() {
|
||||
return ALIAS_FILE_NAME;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrSfcObsDecoder#getCategoryFile()
|
||||
*/
|
||||
@Override
|
||||
protected String getCategoryFile() {
|
||||
return CATEGORY_FILE_NAME;
|
||||
}
|
||||
|
||||
}
|
|
@ -23,16 +23,11 @@ import java.util.Arrays;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.measure.unit.NonSI;
|
||||
import javax.measure.unit.SI;
|
||||
|
||||
import com.raytheon.edex.plugin.sfcobs.SfcObsPointDataTransform;
|
||||
import com.raytheon.uf.common.dataplugin.PluginException;
|
||||
import com.raytheon.uf.common.dataplugin.sfcobs.ObsCommon;
|
||||
import com.raytheon.uf.common.nc.bufr.BufrDataItem;
|
||||
import com.raytheon.uf.common.nc.bufr.BufrParser;
|
||||
import com.raytheon.uf.common.nc.bufr.util.BufrMapper;
|
||||
import com.raytheon.uf.common.nc.bufr.util.TranslationTableGenerator;
|
||||
import com.raytheon.uf.common.pointdata.PointDataView;
|
||||
import com.raytheon.uf.common.pointdata.spatial.ObStation;
|
||||
import com.raytheon.uf.common.pointdata.spatial.SurfaceObsLocation;
|
||||
|
@ -56,6 +51,9 @@ import com.vividsolutions.jts.geom.Point;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Mar 21, 2014 2906 bclement Initial creation
|
||||
* Jun 12, 2014 3229 bclement moved location fields to parent class
|
||||
* moved processGeneralFields() and processPrecip() to parent class
|
||||
* override parent createStationId(), removed getTranslationFile() override
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -64,12 +62,6 @@ import com.vividsolutions.jts.geom.Point;
|
|||
*/
|
||||
public class SynopticLandBufrDecoder extends AbstractBufrSfcObsDecoder {
|
||||
|
||||
public static final Set<String> LOCATION_FIELDS = new HashSet<String>(
|
||||
Arrays.asList(SfcObsPointDataTransform.LATITUDE,
|
||||
SfcObsPointDataTransform.LONGITUDE,
|
||||
SfcObsPointDataTransform.STATION_ID,
|
||||
SfcObsPointDataTransform.ELEVATION));
|
||||
|
||||
public static final Set<String> SUB_STRUCT_FIELDS = new HashSet<String>(
|
||||
Arrays.asList(SfcObsPointDataTransform.WIND_GUST));
|
||||
|
||||
|
@ -83,7 +75,7 @@ public class SynopticLandBufrDecoder extends AbstractBufrSfcObsDecoder {
|
|||
|
||||
public static final String PRECIP_FIELD = "precip";
|
||||
|
||||
public static final String TIME_PERIOD_FIELD = "Time period or displacement";
|
||||
public static final String PRECIP_TIME_PERIOD_FIELD = "Time period or displacement";
|
||||
|
||||
private final ObStationDao stationDao = new ObStationDao();
|
||||
|
||||
|
@ -120,7 +112,7 @@ public class SynopticLandBufrDecoder extends AbstractBufrSfcObsDecoder {
|
|||
for (String baseName : baseNames) {
|
||||
if (level == 1) {
|
||||
/* process top level fields */
|
||||
if (LOCATION_FIELDS.contains(baseName)) {
|
||||
if (DEFAULT_LOCATION_FIELDS.contains(baseName)) {
|
||||
processLocationField(record.getLocation(), parser, baseName);
|
||||
} else {
|
||||
processGeneralFields(record, parser, baseName);
|
||||
|
@ -128,7 +120,7 @@ public class SynopticLandBufrDecoder extends AbstractBufrSfcObsDecoder {
|
|||
} else if (level > 1) {
|
||||
/* process substructure fields */
|
||||
if (PRECIP_FIELD.equalsIgnoreCase(baseName)) {
|
||||
processPrecip(record, parser);
|
||||
processPrecip(record, parser, PRECIP_TIME_PERIOD_FIELD);
|
||||
} else if (SUB_STRUCT_FIELDS.contains(baseName)) {
|
||||
processGeneralFields(record, parser, baseName);
|
||||
}
|
||||
|
@ -136,82 +128,31 @@ public class SynopticLandBufrDecoder extends AbstractBufrSfcObsDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if field is table lookup or direct and handles accordingly
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @param record
|
||||
* @param parser
|
||||
* @param baseName
|
||||
* @throws BufrObsDecodeException
|
||||
* @see
|
||||
* com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrSfcObsDecoder#createStationId
|
||||
* (com.raytheon.uf.common.nc.bufr.BufrParser)
|
||||
*/
|
||||
protected void processGeneralFields(ObsCommon record, BufrParser parser,
|
||||
String baseName) throws BufrObsDecodeException {
|
||||
String unitStr = parser.getFieldUnits();
|
||||
if (unitStr != null && isTableLookup(unitStr)) {
|
||||
processLookupTableField(record, parser, baseName);
|
||||
} else {
|
||||
processDirectField(record, parser, baseName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Precip doesn't have individual fields for different hour periods. One
|
||||
* structure contains the general precip field with a time period. This
|
||||
* method parses the time period to determine what field the precip data is
|
||||
* for.
|
||||
*
|
||||
* @param record
|
||||
* @param parser
|
||||
* @throws BufrObsDecodeException
|
||||
*/
|
||||
protected void processPrecip(ObsCommon record, BufrParser parser)
|
||||
@Override
|
||||
protected String createStationId(BufrParser parser)
|
||||
throws BufrObsDecodeException {
|
||||
Number precip = getInUnits(parser, SI.MILLIMETER);
|
||||
if (precip == null) {
|
||||
/* missing value */
|
||||
return;
|
||||
/* WMO indexes have two parts, block and id */
|
||||
Number id = (Number) getFieldValue(parser, false);
|
||||
if (id == null) {
|
||||
log.debug("BUFR file " + parser.getFile()
|
||||
+ " missing station id field: " + parser.getFieldName());
|
||||
return null;
|
||||
}
|
||||
BufrDataItem timeData = parser.scanForStructField(TIME_PERIOD_FIELD,
|
||||
false);
|
||||
if (timeData == null || timeData.getValue() == null) {
|
||||
log.error("Found precipitation field missing time data. Field: "
|
||||
+ parser.getFieldName() + ", Table: "
|
||||
+ parser.getFieldUnits());
|
||||
return;
|
||||
}
|
||||
Number period = getInUnits(timeData.getVariable(), timeData.getValue(),
|
||||
NonSI.HOUR);
|
||||
PointDataView pdv = record.getPointDataView();
|
||||
switch (Math.abs(period.intValue())) {
|
||||
case 1:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP1_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 3:
|
||||
/* text synop obs doesn't have 3HR precip */
|
||||
log.debug("Received precip period not supported by point data view: "
|
||||
+ Math.abs(period.intValue()) + " HOUR");
|
||||
break;
|
||||
case 6:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP6_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 12:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP12_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 18:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP18_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
case 24:
|
||||
pdv.setFloat(SfcObsPointDataTransform.PRECIP24_HOUR,
|
||||
precip.intValue());
|
||||
break;
|
||||
default:
|
||||
log.error("Unknown precipitation period '" + period.intValue()
|
||||
+ "' in BUFR file " + parser.getFile());
|
||||
Number block = getWMOBlock(parser);
|
||||
if (block == null) {
|
||||
log.debug("BUFR file " + parser.getFile()
|
||||
+ " missing station id field: " + WMO_BLOCK_FIELD);
|
||||
return null;
|
||||
}
|
||||
|
||||
return String.format(WMO_INDEX_FORMAT, block, id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -237,8 +178,7 @@ public class SynopticLandBufrDecoder extends AbstractBufrSfcObsDecoder {
|
|||
* @param parser
|
||||
* @param record
|
||||
*/
|
||||
protected void finalizePresentWeather(BufrParser parser,
|
||||
ObsCommon record) {
|
||||
protected void finalizePresentWeather(BufrParser parser, ObsCommon record) {
|
||||
/* this code comes from the abstract synoptic text decoder */
|
||||
// Fixup the present weather string
|
||||
PointDataView pdv = record.getPointDataView();
|
||||
|
@ -310,19 +250,6 @@ public class SynopticLandBufrDecoder extends AbstractBufrSfcObsDecoder {
|
|||
return ALIAS_FILE_NAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.raytheon.uf.edex.plugin.bufrobs.AbstractBufrObsDecoder#getTranslationFile
|
||||
* (java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected String getTranslationFile(String tableId) {
|
||||
tableId = TranslationTableGenerator.replaceWhiteSpace(tableId, "_");
|
||||
return SYNOPTIC_LAND_NAMESPACE + "-" + tableId + ".xml";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<aliasList namespace="buoy">
|
||||
<!-- time not included since it is processed before anything else -->
|
||||
<alias base="stationId">WMO Region number/geographical area</alias>
|
||||
<!-- alternate lat/lon comes from Argos and is more accurate,
|
||||
decoder falls back to coarse lon/lat if not present -->
|
||||
<alias base="latitude">Alternate latitude (high accuracy)</alias>
|
||||
<alias base="longitude">Alternate longitude (high accuracy)</alias>
|
||||
<alias base="elevation">Height of station ground above mean sea level</alias>
|
||||
<alias base="temperature">Temperature/dry-bulb temperature</alias>
|
||||
<alias base="dewpoint">Dew-point temperature</alias>
|
||||
<alias base="windSpeed">Wind speed</alias>
|
||||
<alias base="windDir">Wind direction</alias>
|
||||
<alias base="windGust">Maximum wind gust speed</alias>
|
||||
<!-- following not available in buoy
|
||||
<alias base="peakWindSpeedTime"></alias>
|
||||
<alias base="peakWindSpeed"></alias>
|
||||
<alias base="peakWindDir"></alias>
|
||||
-->
|
||||
<alias base="seaLevelPress">Pressure reduced to mean sea level</alias>
|
||||
<!-- buoy does not contain altimeter data
|
||||
<alias base="altimeter"></alias>
|
||||
-->
|
||||
<alias base="stationPress">Pressure</alias>
|
||||
<!-- table lookup -->
|
||||
<alias base="pressChangeChar">Characteristic of pressure tendency</alias>
|
||||
<alias base="pressChange3Hour">3-hour pressure change</alias>
|
||||
<!-- following not available in buoy
|
||||
<alias base="totCloudAmount"></alias>
|
||||
<alias base="lowCloudHeight"></alias>
|
||||
<alias base="lowCloudAmount></alias>
|
||||
<alias base="lowCloudType"></alias>
|
||||
<alias base="midCloudType"></alias>
|
||||
<alias base="hiCloudType"></alias>
|
||||
<alias base="visibility"></alias>
|
||||
<alias base="wx_present"></alias>
|
||||
<alias base="presWeather"></alias>
|
||||
<alias base="wx_past_1"></alias>
|
||||
<alias base="wx_past_2"></alias>
|
||||
-->
|
||||
<!-- map all precip to same base, use associated time period in parser -->
|
||||
<alias base="precip">Total precipitation/total water equivalent</alias>
|
||||
<!-- following not available in buoy
|
||||
<alias base="precip24Hour">Total precipitation past 24 hours</alias>
|
||||
<alias base="equivWindSpeed10m"></alias>
|
||||
<alias base="equivWindSpeed20m"></alias>
|
||||
<alias base="iceCode"></alias>
|
||||
<alias base="wetBulb"></alias>
|
||||
-->
|
||||
<alias base="seaSurfaceTemp">Sea/water temperature</alias>
|
||||
<alias base="platformTrueDirection">Direction of motion of moving observing platform</alias>
|
||||
<alias base="platformTrueSpeed">Platform drift speed (high precision)</alias>
|
||||
<alias base="windWaveHeight">Height of wind waves</alias>
|
||||
<alias base="windWavePeriod">Period of wind waves</alias>
|
||||
<alias base="waveHeight">Height of waves</alias>
|
||||
<alias base="wavePeriod">Period of waves</alias>
|
||||
<!-- following not available in buoy
|
||||
<alias base="waveSteepness"></alias>
|
||||
<alias base="highResWaveHeight"></alias>
|
||||
<alias base="primarySwellWaveDir"></alias>
|
||||
<alias base="primarySwellWavePeriod"></alias>
|
||||
<alias base="primarySwellWaveHeight"></alias>
|
||||
<alias base="secondarySwellWaveDir"></alias>
|
||||
<alias base="secondarySwellWavePeriod"></alias>
|
||||
<alias base="secondarySwellWaveHeight"></alias>
|
||||
<alias base="numInterWinds"></alias>
|
||||
<alias base="interWindTime"></alias>
|
||||
-->
|
||||
</aliasList>
|
|
@ -0,0 +1,5 @@
|
|||
<categories>
|
||||
<category code="1" description="Surface data — sea">
|
||||
<subcategory code="25" description="Buoy observation (BUOY)" reportType="1006"/>
|
||||
</category>
|
||||
</categories>
|
|
@ -20,4 +20,5 @@
|
|||
-->
|
||||
<requestPatterns xmlns:ns2="group">
|
||||
<regex>^IS[IMN]</regex>
|
||||
<regex>^IOB</regex>
|
||||
</requestPatterns>
|
||||
|
|
Loading…
Add table
Reference in a new issue