Omaha #3226 added total lightning decoder

refactored binlightning to support pulse data
renamed strikeCount dataset to pulseCount
added initial cave support for total lightning

Change-Id: I67f8a0f26a615ddefb9ff7f7d7d78bb05f0877f3

Former-commit-id: c278000764 [formerly e2583481a77d08249030838ebd52eed6e54b2986]
Former-commit-id: f39896b2d1
This commit is contained in:
Brian Clements 2014-06-02 10:43:23 -05:00
parent dfd2f3d071
commit b98a3494fe
33 changed files with 1724 additions and 701 deletions

View file

@ -0,0 +1,37 @@
<?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.
-->
<menuTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<contribute xsi:type="bundleItem" file="bundles/LightningPlot60Min.xml"
menuText="1hr CG flash plot" id="1HrLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot15Min.xml"
menuText="15min CG flash plot" id="15MinLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot15MinPN.xml"
menuText="15min Pos/Neg CG flash plot" id="15MinPNLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot5Min.xml"
menuText="5min CG flash plot" id="5MinLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningSeq.xml"
menuText="1min Lgtng Seq CG flash" id="1MinLightningFlashSeq">
</contribute>
</menuTemplate>

View file

@ -20,27 +20,18 @@
-->
<menuTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<contribute xsi:type="bundleItem" file="bundles/LightningPlot60Min.xml"
menuText="1hr CG stroke plot" id="1HrLightningStrokePlot"
productInterval="3600">
<dataURI>/binlightning/%</dataURI>
menuText="1hr CG stroke plot" id="1HrLightningStrokePlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot15Min.xml"
menuText="15min CG stroke plot" id="15MinLightningStrokePlot"
productInterval="900">
<dataURI>/binlightning/%</dataURI>
menuText="15min CG stroke plot" id="15MinLightningStrokePlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot15MinPN.xml"
menuText="15min Pos/Neg CG stroke plot" id="15MinPNLightningStrokePlot"
productInterval="900">
<dataURI>/binlightning/%</dataURI>
menuText="15min Pos/Neg CG stroke plot" id="15MinPNLightningStrokePlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot5Min.xml"
menuText="5min CG stroke plot" id="5MinLightningStrokePlot"
productInterval="300">
<dataURI>/binlightning/%</dataURI>
menuText="5min CG stroke plot" id="5MinLightningStrokePlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningSeq.xml"
menuText="1min Lgtng Seq CG stroke" id="1MinLightningStrokeSeq">
<dataURI>/binlightning/%</dataURI>
</contribute>
</menuTemplate>

View file

@ -29,4 +29,9 @@
<substitute key="source" value="GLD"/>
</contribute>
</contribute>
<contribute xsi:type="subMenu" menuText="Total Lightning" id="ENTLNSubMenu">
<contribute xsi:type="subinclude" fileName="menus/lightning/entlnLightningBundleItems.xml">
<substitute key="source" value="ENTLN"/>
</contribute>
</contribute>
</menuTemplate>

View file

@ -20,27 +20,18 @@
-->
<menuTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<contribute xsi:type="bundleItem" file="bundles/LightningPlot60Min.xml"
menuText="1hr CG flash plot" id="1HrLightningFlashPlot"
productInterval="3600">
<dataURI>/binlightning/%</dataURI>
menuText="1hr CG flash plot" id="1HrLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot15Min.xml"
menuText="15min CG flash plot" id="15MinLightningFlashPlot"
productInterval="900">
<dataURI>/binlightning/%</dataURI>
menuText="15min CG flash plot" id="15MinLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot15MinPN.xml"
menuText="15min Pos/Neg CG flash plot" id="15MinPNLightningFlashPlot"
productInterval="900">
<dataURI>/binlightning/%</dataURI>
menuText="15min Pos/Neg CG flash plot" id="15MinPNLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningPlot5Min.xml"
menuText="5min CG flash plot" id="5MinLightningFlashPlot"
productInterval="300">
<dataURI>/binlightning/%</dataURI>
menuText="5min CG flash plot" id="5MinLightningFlashPlot">
</contribute>
<contribute xsi:type="bundleItem" file="bundles/LightningSeq.xml"
menuText="1min Lgtng Seq CG flash" id="1MinLightningFlashSeq">
<dataURI>/binlightning/%</dataURI>
</contribute>
</menuTemplate>

View file

@ -35,6 +35,7 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.raytheon.uf.common.dataplugin.HDF5Util;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
import com.raytheon.uf.common.dataplugin.binlightning.LightningConstants;
import com.raytheon.uf.common.datastorage.DataStoreFactory;
import com.raytheon.uf.common.datastorage.IDataStore;
import com.raytheon.uf.common.datastorage.Request;
@ -94,6 +95,7 @@ import com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability;
* fields when magnification set to 0
* Feb 27, 2013 DCS 152 jgerth/elau Support for WWLLN and multiple sources
* Jan 21, 2014 2667 bclement renamed record's lightSource field to source
* Jun 05, 2014 3226 bclement reference datarecords by LightningConstants
*
* </pre>
*
@ -637,7 +639,15 @@ public class LightningResource extends
recordList.add(rec);
}
List<IDataRecord> times = recordMap.get("obsTime");
List<IDataRecord> times = recordMap
.get(LightningConstants.TIME_DATASET);
List<IDataRecord> intensities = recordMap
.get(LightningConstants.INTENSITY_DATASET);
List<IDataRecord> lats = recordMap
.get(LightningConstants.LAT_DATASET);
List<IDataRecord> lons = recordMap
.get(LightningConstants.LON_DATASET);
int k = 0;
for (IDataRecord timeRec : times) {
@ -647,12 +657,13 @@ public class LightningResource extends
int numRecords = (int) time.getSizes()[0];
long[] timeData = time.getLongData();
int[] intensityData = ((IntegerDataRecord) recordMap.get(
"intensity").get(k)).getIntData();
float[] latitudeData = ((FloatDataRecord) recordMap.get(
"latitude").get(k)).getFloatData();
float[] longitudeData = ((FloatDataRecord) recordMap.get(
"longitude").get(k)).getFloatData();
int[] intensityData = ((IntegerDataRecord) intensities
.get(k)).getIntData();
float[] latitudeData = ((FloatDataRecord) lats.get(k))
.getFloatData();
float[] longitudeData = ((FloatDataRecord) lons.get(k))
.getFloatData();
for (int i = 0; i < numRecords; i++) {

View file

@ -0,0 +1,27 @@
#!/usr/bin/env python
import h5py
import os
import sys
# multiplicity was incorrectly interpreted as 'stike count' when
# it was the number of strokes (AKA pulses) in the strike (AKA flash)
LIGHTNING_H5_PATH = '/awips2/edex/data/hdf5/binlightning'
OLD_NAME = 'strikeCount'
NEW_NAME = 'pulseCount'
for file in os.listdir(LIGHTNING_H5_PATH):
if file.endswith('h5'):
h5file = None
try:
fileName = os.path.join(LIGHTNING_H5_PATH, file)
h5file = h5py.File(fileName, 'r+')
for g in h5file.values():
if NEW_NAME not in g and OLD_NAME in g:
g[NEW_NAME] = g[OLD_NAME]
except Exception, e:
print "Error renaming strikeCount in file", fileName, ":", e
finally:
if h5file:
h5file.close()

View file

@ -9,6 +9,7 @@ Export-Package: com.raytheon.edex.plugin.binlightning.dao
Import-Package: com.raytheon.edex.esb,
com.raytheon.edex.exception,
com.raytheon.edex.plugin,
com.raytheon.uf.common.numeric,
com.raytheon.uf.common.status,
com.raytheon.uf.common.wmo,
gov.noaa.nws.ost.edex.plugin.binlightning,

View file

@ -5,6 +5,8 @@
<bean id="binlightningDecoder"
class="com.raytheon.edex.plugin.binlightning.BinLightningDecoder" />
<bean id="totalLightningDecoder" class="com.raytheon.edex.plugin.binlightning.total.TotalLightningDecoder" />
<bean id="binlightningDistRegistry" factory-bean="distributionSrv"
factory-method="register">
@ -16,42 +18,37 @@
<constructor-arg ref="clusteredBinLightningRoutes" />
</bean>
<camelContext id="clusteredBinLightningRoutes"
xmlns="http://camel.apache.org/schema/spring"
errorHandlerRef="errorHandler">
<!--
<endpoint id="binlightningFileEndpoint"
uri="file:${edex.home}/data/sbn/binlightning?noop=true&amp;idempotent=false" />
<route id="binlightningFileConsumerRoute">
<from ref="binlightningFileEndpoint" />
<bean ref="fileToString" />
<setHeader headerName="pluginName">
<constant>binlightning</constant>
</setHeader>
<to uri="jms-durable:queue:Ingest.binlightning" />
</route>
-->
<camelContext id="clusteredBinLightningRoutes" xmlns="http://camel.apache.org/schema/spring"
errorHandlerRef="errorHandler">
<!-- Begin binlightning routes -->
<route id="binlightningIngestRoute">
<from uri="jms-durable:queue:Ingest.binlightning"/>
<setHeader headerName="pluginName">
<constant>binlightning</constant>
</setHeader>
<doTry>
<pipeline>
<bean ref="stringToFile" />
<bean ref="binlightningDecoder" method="decode" />
<to uri="direct-vm:persistIndexAlert" />
<route id="binlightningIngestRoute">
<from uri="jms-durable:queue:Ingest.binlightning" />
<setHeader headerName="pluginName">
<constant>binlightning</constant>
</setHeader>
<doTry>
<pipeline>
<bean ref="stringToFile" />
<choice>
<when>
<simple>${in.header.header} regex '^SFPA42 KWBC.*'</simple>
<bean ref="totalLightningDecoder" method="decode" />
</when>
<otherwise>
<bean ref="binlightningDecoder" method="decode" />
</otherwise>
</choice>
</pipeline>
<doCatch>
<exception>java.lang.Throwable</exception>
<to uri="log:binlightning?level=ERROR"/>
</doCatch>
</doTry>
<to uri="direct-vm:persistIndexAlert" />
</pipeline>
<doCatch>
<exception>java.lang.Throwable</exception>
<to uri="log:binlightning?level=ERROR" />
</doCatch>
</doTry>
<!-- bean ref="processUtil" method="delete" / -->
</route>
</camelContext>
</route>
</camelContext>
</beans>

View file

@ -47,8 +47,6 @@ import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.common.wmo.WMOHeader;
import com.raytheon.uf.common.wmo.WMOTimeParser;
@ -58,17 +56,6 @@ import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
/**
* AWIPS decoder adapter strategy for binary lightning data.<br/>
*
* Normal usage for this adapter is<br/>
* <code>
* BinLightningDecoder dec = new BinLightningDecoder();
* dec.setMessage(data);
* while(dec.hasNext())
* {
* BinLightningRecord r = dec.decode();
* // do something with record.
* }
* dec.dispose();
* </code>
*
* <pre>
*
@ -98,6 +85,7 @@ import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
* Jun 03, 2014 3226 bclement removed unused WMO patterns, switched to UFStatus
* removed TimeTools usage, removed constructDataURI() call
* added decodeBinLightningData() and decodeBitShiftedBinLightningData() from BinLightningDecoderUtil
* Jun 05, 2014 3226 bclement LightningStikePoint refactor, added extractPData()
*
* </pre>
*
@ -118,7 +106,7 @@ public class BinLightningDecoder extends AbstractDecoder {
* Default lightning strike type for FLASH messages. RT_FLASH documents
* indicate no default, but D2D code defaults to STRIKE_CG also.
*/
public LtgStrikeType DEFAULT_FLASH_TYPE = LtgStrikeType.STRIKE_CG;
public LtgStrikeType DEFAULT_FLASH_TYPE = LtgStrikeType.CLOUD_TO_GROUND;
private String traceId = null;
@ -153,30 +141,37 @@ public class BinLightningDecoder extends AbstractDecoder {
Calendar baseTime = WMOTimeParser.findDataTime(
wmoHdr.getYYGGgg(), fileName);
// Because binary nature of the encrypted data, the string created with its byte[] array may not have the same length of the byte[] array length
// So when DecoderTools.stripWMOHeader() assumes byte[] length == String length in its logic, it is observed that it may return a shorter byte[] than
// the real data array. (Looks like a bug???)
/*
* Because binary nature of the encrypted data, the string
* created with its byte[] array may not have the same length of
* the byte[] array length So when DecoderTools.stripWMOHeader()
* assumes byte[] length == String length in its logic, it is
* observed that it may return a shorter byte[] than the real
* data array. (Looks like a bug???)
*/
// byte[] pdata = DecoderTools.stripWMOHeader(data, SFUS_PATTERN);
// if (pdata == null) {
// pdata = DecoderTools.stripWMOHeader(data, SFPA_PATTERN);
// }
// instead the following is used to strip WMO header a little more safely.
byte[] pdata = null;
if (wmoHdr.isValid() && wmoHdr.getMessageDataStart() > 0) {
pdata = new byte[data.length - wmoHdr.getMessageDataStart()];
System.arraycopy(data, wmoHdr.getMessageDataStart(), pdata, 0, data.length - wmoHdr.getMessageDataStart());
}
/*
* instead the following is used to strip WMO header a little
* more safely.
*/
byte[] pdata = extractPData(wmoHdr, data);
if ((pdata == null) || (pdata.length == 0)) {
return new PluginDataObject[0];
}
//
// Modified by Wufeng Zhou to handle both legacy bit-shifted and new encryted data
//
// Preserved the legacy decoding in BinLigntningDecoderUtil.decodeBitShiftedBinLightningData(), and added logic to process
// both encrypted data and legacy data
//
/*
* Modified by Wufeng Zhou to handle both legacy bit-shifted and
* new encryted data
*
* Preserved the legacy decoding in
* BinLigntningDecoderUtil.decodeBitShiftedBinLightningData(),
* and added logic to process both encrypted data and legacy
* data
*/
List<LightningStrikePoint> strikes = decodeBinLightningData(
data, pdata, traceId, wmoHdr, baseTime.getTime());
@ -186,18 +181,14 @@ public class BinLightningDecoder extends AbstractDecoder {
return reports;
}
//
// Done MOD by Wufeng Zhou
//
/*
* Done MOD by Wufeng Zhou
*/
// post processing data - if not keep-alive record
BinLightningRecord report = null;
if (strikes.size() > 0) {
report = new BinLightningRecord(strikes.size());
for (LightningStrikePoint strike : strikes) {
report.addStrike(strike);
logger.debug(traceId + "-" + strike);
}
report = new BinLightningRecord(strikes);
} else {
return new PluginDataObject[0];
}
@ -215,18 +206,8 @@ public class BinLightningDecoder extends AbstractDecoder {
+ " at " + SDF.format(cStart.getTime()));
}
} else {
Calendar cStop = report.getStopTime();
TimeRange range = new TimeRange(cStart.getTimeInMillis(),
cStop.getTimeInMillis());
DataTime dataTime = new DataTime(cStart, range);
report.setDataTime(dataTime);
if (report != null) {
report.setTraceId(traceId);
reports = new PluginDataObject[] { report };
}
report.setTraceId(traceId);
reports = new PluginDataObject[] { report };
}
}
} else {
@ -235,6 +216,23 @@ public class BinLightningDecoder extends AbstractDecoder {
return reports;
}
/**
* Remove WMO header from data and return the remaining pdata
*
* @param wmoHdr
* @param data
* @return null if data is invalid
*/
public static byte[] extractPData(WMOHeader wmoHdr, byte[] data) {
byte[] pdata = null;
if (wmoHdr.isValid() && wmoHdr.getMessageDataStart() > 0) {
pdata = new byte[data.length - wmoHdr.getMessageDataStart()];
System.arraycopy(data, wmoHdr.getMessageDataStart(), pdata, 0,
data.length - wmoHdr.getMessageDataStart());
}
return pdata;
}
/**
* Decode bin lightning data, able to handle both legacy bit-shifted and new
* encryted data
@ -281,50 +279,52 @@ public class BinLightningDecoder extends AbstractDecoder {
boolean decodeDone = false;
EncryptedBinLightningCipher cipher = new EncryptedBinLightningCipher();
//
// Using different WMO headers to indicate whether the data is encrypted
// or not would be a nice option.
// However, that idea has been discussed but not adopted.
// If in the future, WMO header can be different for legacy and
// encrypted data, or some other metadata can be used to decide
// whether deceyption is needed, logic can be added here.
//
// Before that happens, we'll use hints and trial & error to decode the
// data
// Hints: Per lightning data format spec, there are 3 bytes in the WMO
// header starting line that indicates the size of the encrypted block
// or the ASCII sequence # for legacy bit-shifted data
// However, the starting line is optional and AWIPS decode may not see
// it at all because TG will strip that starting line away
// We'll try to use this hint first, if is is not found, then trial and
// error way to decrypt and decode
//
// As of 11/05/2013, There is change in data spec. that the 3-bytes will
// not be encoded as encrypted block size anymore (it will always be
// transmission sequence # if present)
// So there should have some minor changes in the logic below for
// decoding the data.
// However, as reading into the
// com.raytheon.edex.plugin.binlightning.impl.BinLightningFactory.getDecoder()
// and follow-on code, we see the following data patterns
// for legacy bit-shifted data, which could be used to reduce guess-work
// in data decryption:
// The bit-shifted data will have multiple groups of the following
// patterns:
// 1-byte (unsigned byte): for size count
// 1-byte (unsigned byte): for flash type:
// 0x96 for FLASH_RPT (message size is 6 bytes each)
// 0x97 for RT_FLASH_RPT (message size is 8 bytes each)
// 0xd0 for OTHER_RPT (The D2D decoders declare but do not define this
// message, so unimplemented decoder)
// 0xd1 for COMM_RPT (The D2D decoders declare but do not define this
// message, so unimplemented decoder)
// 4-bytes: date time
// multiple of 6 or 8 bytes (as determined by 2nd byte flash type) with
// count indicated in 1st byte
//
// So this is be used to determine whether the data need to be
// decrypted.
/*
* Using different WMO headers to indicate whether the data is encrypted
* or not would be a nice option.
* However, that idea has been discussed but not adopted.
* If in the future, WMO header can be different for legacy and
* encrypted data, or some other metadata can be used to decide
* whether deceyption is needed, logic can be added here.
*
* Before that happens, we'll use hints and trial & error to decode the
* data
* Hints: Per lightning data format spec, there are 3 bytes in the WMO
* header starting line that indicates the size of the encrypted block
* or the ASCII sequence # for legacy bit-shifted data
* However, the starting line is optional and AWIPS decode may not see
* it at all because TG will strip that starting line away
* We'll try to use this hint first, if is is not found, then trial and
* error way to decrypt and decode
*
* As of 11/05/2013, There is change in data spec. that the 3-bytes will
* not be encoded as encrypted block size anymore (it will always be
* transmission sequence # if present)
* So there should have some minor changes in the logic below for
* decoding the data.
* However, as reading into the
* com.raytheon.edex.plugin.binlightning.impl.BinLightningFactory.getDecoder
* ()
* and follow-on code, we see the following data patterns
* for legacy bit-shifted data, which could be used to reduce guess-work
* in data decryption:
* The bit-shifted data will have multiple groups of the following
* patterns:
* 1-byte (unsigned byte): for size count
* 1-byte (unsigned byte): for flash type:
* 0x96 for FLASH_RPT (message size is 6 bytes each)
* 0x97 for RT_FLASH_RPT (message size is 8 bytes each)
* 0xd0 for OTHER_RPT (The D2D decoders declare but do not define this
* message, so unimplemented decoder)
* 0xd1 for COMM_RPT (The D2D decoders declare but do not define this
* message, so unimplemented decoder)
* 4-bytes: date time
* multiple of 6 or 8 bytes (as determined by 2nd byte flash type) with
* count indicated in 1st byte
*
* So this is be used to determine whether the data need to be
* decrypted.
*/
/*
* // looks like previous assumption on block size bytes are not valid
@ -343,21 +343,23 @@ public class BinLightningDecoder extends AbstractDecoder {
if (needDecrypt) {
try {
// NOTE: 11/14/2013 WZ:
// encrypted test data on TNCF (got from Melissa Porricelli)
// seems to have extra 4 bytes (0x0d 0x0d 0x0a 0x03) at the end,
// making the data size not a multiple of 16. However, original
// test data do not have this trailing bytes. while NCEP test
// data has extra 8 trailing bytes.
// Brain Rapp's email on 11/13/2013 confirms that Unidata LDM
// software used by AWIPS II will strips off all SBN protocol
// headers
// that precede the WMO header and adds its own 11 byte header
// like this: "soh cr cr nl 2 5 4 sp cr cr nl". It
// also adds a four byte trailer consisting of "cr cr nl etx"
// (0x0d 0x0d 0x0a 0x03)
// So, it seems necessary to trim trailing bytes if it is not
// multiple of 16, warning messages will be logged though
/*
* NOTE: 11/14/2013 WZ:
* encrypted test data on TNCF (got from Melissa Porricelli)
* seems to have extra 4 bytes (0x0d 0x0d 0x0a 0x03) at the end,
* making the data size not a multiple of 16. However, original
* test data do not have this trailing bytes. while NCEP test
* data has extra 8 trailing bytes.
* Brain Rapp's email on 11/13/2013 confirms that Unidata LDM
* software used by AWIPS II will strips off all SBN protocol
* headers
* that precede the WMO header and adds its own 11 byte header
* like this: "soh cr cr nl 2 5 4 sp cr cr nl". It
* also adds a four byte trailer consisting of "cr cr nl etx"
* (0x0d 0x0d 0x0a 0x03)
* So, it seems necessary to trim trailing bytes if it is not
* multiple of 16, warning messages will be logged though
*/
int dataLengthToBeDecrypted = pdata.length;
if (pdata.length % 16 != 0) {
dataLengthToBeDecrypted = pdata.length
@ -382,8 +384,10 @@ public class BinLightningDecoder extends AbstractDecoder {
decodeDone = true;
return null;
}
// not keep-alive record, then check data validity and decode
// into an ArrayList<LightningStrikePoint> of strikes
/*
* not keep-alive record, then check data validity and decode
* into an ArrayList<LightningStrikePoint> of strikes
*/
if (BinLightningDecoderUtil
.isLightningDataRecords(decryptedData)) {
strikes = BinLightningDecoderUtil
@ -418,9 +422,11 @@ public class BinLightningDecoder extends AbstractDecoder {
if (decodeDone == false) { // not decoded through decrypt->decode
// process, try the legacy decoder
logger.info(traceId + " - decoding as bit-shifted data");
// bit-shifting data format check call here will get us some more
// information on the data, also can compare the strikes with the
// decoder result
/*
* bit-shifting data format check call here will get us some more
* information on the data, also can compare the strikes with the
* decoder result
*/
int estimatedStrikes = BinLightningDecoderUtil
.getBitShiftedDataStrikeCount(pdata);
strikes = decodeBitShiftedBinLightningData(pdata, wmoHdr);
@ -461,13 +467,15 @@ public class BinLightningDecoder extends AbstractDecoder {
switch (decoder.getError()) {
case IBinLightningDecoder.NO_ERROR: {
for (LightningStrikePoint strike : decoder) {
// use WMO Header to distinguish NLDN or GLD360 data because
// no bit-shifted data spec available for GLD360.
// 12/24/2013, WZ
// The WMO header start string is defined in
// BinLightningAESKey.properties file (normally, GLD360 data
// will have WMO header
// starts with SFPA41, or SFPA99 for test data.)
/*
* use WMO Header to distinguish NLDN or GLD360 data because
* no bit-shifted data spec available for GLD360.
* 12/24/2013, WZ
* The WMO header start string is defined in
* BinLightningAESKey.properties file (normally, GLD360 data
* will have WMO header
* starts with SFPA41, or SFPA99 for test data.)
*/
String gld360WMOHeaderString = BinLightningAESKey
.getProps().getProperty(
"binlightning.gld360WMOHeaderStartString",

View file

@ -20,11 +20,17 @@
package com.raytheon.edex.plugin.binlightning.dao;
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
import java.util.Map;
import java.util.Map.Entry;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
import com.raytheon.uf.common.dataplugin.binlightning.LightningConstants;
import com.raytheon.uf.common.dataplugin.persist.IPersistable;
import com.raytheon.uf.common.datastorage.DataStoreFactory;
import com.raytheon.uf.common.datastorage.IDataStore;
import com.raytheon.uf.common.datastorage.StorageException;
import com.raytheon.uf.common.datastorage.records.IDataRecord;
import com.raytheon.uf.edex.database.plugin.PluginDao;
@ -36,6 +42,7 @@ import com.raytheon.uf.edex.database.plugin.PluginDao;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 1/08/09 1674 bphillip Initial creation
* Jun 05, 2014 3226 bclement record now contains maps for data arrays
* </pre>
*
* @author bphillip
@ -61,15 +68,38 @@ public class BinLightningDao extends PluginDao {
protected IDataStore populateDataStore(IDataStore dataStore,
IPersistable obj) throws Exception {
BinLightningRecord binLightningRec = (BinLightningRecord) obj;
for (int i = 0; i < binLightningRec.getDataArrays().length; i++) {
IDataRecord record = DataStoreFactory.createStorageRecord(
binLightningRec.getDataNames()[i], binLightningRec
.getDataURI(), binLightningRec.getDataArrays()[i]);
record.setCorrelationObject(binLightningRec);
dataStore.addDataRecord(record);
}
Map<String, Object> strikeDataArrays = binLightningRec
.getStrikeDataArrays();
populateFromMap(dataStore, obj, binLightningRec.getDataURI(),
strikeDataArrays);
Map<String, Object> pulseDataArrays = binLightningRec
.getPulseDataArrays();
String pulseGroup = binLightningRec.getDataURI() + DataURI.SEPARATOR
+ LightningConstants.PULSE_HDF5_GROUP_SUFFIX;
populateFromMap(dataStore, obj, pulseGroup, pulseDataArrays);
return dataStore;
}
/**
* Adds each primitive data array object in map to the datastore using the
* provided group and the key of the map entry as the name
*
* @param dataStore
* @param obj
* @param group
* @param data
* @throws StorageException
*/
private void populateFromMap(IDataStore dataStore, IPersistable obj,
String group, Map<String, Object> data)
throws StorageException {
for (Entry<String, Object> e : data.entrySet()) {
String name = e.getKey();
Object dataArray = e.getValue();
IDataRecord record = DataStoreFactory.createStorageRecord(name,
group, dataArray);
record.setCorrelationObject(obj);
dataStore.addDataRecord(record);
}
}
}

View file

@ -26,7 +26,6 @@ import java.util.List;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.edex.decodertools.core.BasePoint;
import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
/**
@ -42,6 +41,7 @@ import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
* 20070810 379 jkorman Initial Coding from prototype.
* 20070912 379 jkorman Code review cleanup.
* May 14, 2014 2536 bclement removed TimeTools
* Jun 05, 2014 3226 bclement parseDate() now returns calendar
* </pre>
*
* @author jkorman
@ -87,13 +87,12 @@ abstract class BaseLightningDecoder implements IBinLightningDecoder
/**
* Parse the date field from a given data source. It is assumed that the
* data source is pointing to the current date/time data.
* @return A BasePoint object with the time fields set to the observation
* time.
*
* @return A Calendar object with the time fields set to the observation
* time.
*/
BasePoint parseDate(IBinDataSource msgData)
protected Calendar parseDate(IBinDataSource msgData)
{
BasePoint point = new BasePoint();
//********* Don't reorder these reads!!!
int b1 = msgData.getU8();
int b2 = msgData.getU8();
@ -103,22 +102,18 @@ abstract class BaseLightningDecoder implements IBinLightningDecoder
// number of days since BASE_TIME
int days = ((word1 & DAYS_MASK) >> DAYS_SHFT);
obsTime.add(Calendar.DAY_OF_MONTH, days);
point.setYear(obsTime.get(Calendar.YEAR));
//Increment month, Calendar returns 0..11
point.setMonth(obsTime.get(Calendar.MONTH) + 1);
point.setDay(obsTime.get(Calendar.DAY_OF_MONTH));
int hours = (word1 & HOURS_HI_BIT_MASK) << HOURS_HI_BIT_SHFT;
hours += (b2 & HOURS_LO_NYB_MASK) >>> HOURS_LO_NYB_SHFT;
point.setHour(hours);
obsTime.set(Calendar.HOUR, hours);
int minutes = (b2 & MIN_P1_MASK) << MIN_P1_SHFT;
minutes += (b1 & MIN_P2_MASK) >>> MIN_P2_SHFT;
point.setMinute(minutes);
obsTime.set(Calendar.MINUTE, minutes);
point.setSecond((b1 & SECONDS_MASK));
return point;
obsTime.set(Calendar.SECOND, (b1 & SECONDS_MASK));
obsTime.set(Calendar.MILLISECOND, 0);
return obsTime;
}
/**

View file

@ -19,9 +19,11 @@
**/
package com.raytheon.edex.plugin.binlightning.impl;
import java.util.Calendar;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgMsgType;
import com.raytheon.uf.edex.decodertools.core.BasePoint;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
/**
@ -30,13 +32,14 @@ import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
*
* <pre>
* SOFTWARE HISTORY
*
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 20070810 379 jkorman Initial Coding from prototype.
* Jun 05, 2014 3226 bclement LightningStikePoint refactor
*
* </pre>
*
*
* @author jkorman
* @version 1.0
*/
@ -62,7 +65,7 @@ public class FlashLightningDecoder extends BaseLightningDecoder
{
if(msgData.available(TIME_SIZE))
{
BasePoint base = parseDate(msgData);
Calendar baseTime = parseDate(msgData);
if(msgData.available(FLASH_MSG_SIZE * count))
{
@ -70,17 +73,23 @@ public class FlashLightningDecoder extends BaseLightningDecoder
{
double lon = getFlashLon(msgData);
double lat = getFlashLat(msgData);
// Create the strike record from the report info and base time information.
LightningStrikePoint strikeData = new LightningStrikePoint(base,lat,lon,LtgMsgType.STRIKE_MSG_FL);
strikeData.setStrikeStrength(msgData.getS8() * 2.0);
double strikeStrength = msgData.getS8() * 2.0;
// strike count and 1/10s seconds
int u8 = msgData.getU8();
strikeData.setStrikeCount(u8 & 0x0F);
strikeData.setMillis(((u8 & 0xF0) >> 4) * 100);
int flashCount = u8 & 0x0F;
Calendar obsTime = TimeUtil.newCalendar(baseTime);
obsTime.set(Calendar.MILLISECOND, ((u8 & 0xF0) >> 4) * 100);
// Create the strike record from the report info and base
// time information.
LightningStrikePoint strikeData = new LightningStrikePoint(
lat, lon, baseTime, LtgMsgType.STRIKE_MSG_FL);
strikeData.setType(DEFAULT_FLASH_TYPE);
strikeData.setStrikeStrength(strikeStrength);
strikeData.setPulseCount(flashCount);
addStrike(strikeData);
}
}

View file

@ -26,22 +26,24 @@ import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
* Declare the interface for binary lightning decoding. The decoders are
* expected to implement an Iterable interface. Data decoding will take place
* during construction of the element.
*
* <pre>
* the recommended constructor for this interface is
*
* @param data An IBinDataSource data source containing the data to be decoded.
* @param count The number of records that this decoder should see.
* <code>public X (IBinDataSource data, int count)</code>
*
*
* SOFTWARE HISTORY
*
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 20070810 379 jkorman Initial Coding from prototype.
* 20070912 379 jkorman Code review cleanup.
* Jun 05, 2014 3226 bclement LightningStikePoint refactor
*
* </pre>
*
*
* @author jkorman
* @version 1.0
*/
@ -59,7 +61,7 @@ public interface IBinLightningDecoder extends Iterable<LightningStrikePoint>
public static final int OTHER_RPT = 0xD0;
public static final int COMM_RPT = 0xD1;
public static final LtgStrikeType DEFAULT_FLASH_TYPE = LtgStrikeType.STRIKE_CG;
public static final LtgStrikeType DEFAULT_FLASH_TYPE = LtgStrikeType.CLOUD_TO_GROUND;
/*
*/

View file

@ -19,9 +19,10 @@
**/
package com.raytheon.edex.plugin.binlightning.impl;
import java.util.Calendar;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgMsgType;
import com.raytheon.uf.edex.decodertools.core.BasePoint;
import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
/**
@ -37,6 +38,7 @@ import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
* 20070810 379 jkorman Initial Coding from prototype.
* 20070821 379 jkorman Added default strike type.
* 20080823 379 jkorman getRTLat was using 24 bits instead of 23.
* Jun 05, 2014 3226 bclement LightningStikePoint refactor
* </pre>
*
* @author jkorman
@ -66,7 +68,7 @@ public class RTLightningDecoder extends BaseLightningDecoder {
*/
private void doDecode(IBinDataSource msgData, int count) {
if (msgData.available(TIME_SIZE + (RT_MSG_SIZE * count))) {
BasePoint base = parseDate(msgData);
Calendar baseTime = parseDate(msgData);
// for now just consume some data
for (int i = 0; i < count; i++) {
long part = msgData.getU32();
@ -79,11 +81,11 @@ public class RTLightningDecoder extends BaseLightningDecoder {
double lat = getRTLat(part);
int strikeCount = getMult(part);
LightningStrikePoint strikeData = new LightningStrikePoint(
base, lat, lon, LtgMsgType.STRIKE_MSG_RT);
LightningStrikePoint strikeData = new LightningStrikePoint(lat,
lon, baseTime, LtgMsgType.STRIKE_MSG_RT);
strikeData.setStrikeStrength(strength);
strikeData.setStrikeCount(strikeCount);
strikeData.setPulseCount(strikeCount);
// *****
// NCDC documents indicate that RT data can report both CC/CG
// but haven't seen any data nor is it in the D2D decoders. Set

View file

@ -0,0 +1,171 @@
/**
* 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.edex.plugin.binlightning.total;
import java.nio.ByteBuffer;
import com.raytheon.uf.common.numeric.UnsignedNumbers;
/**
* ByteBuffer wrapper that keeps track of checksums
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 3, 2014 3226 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ChecksumByteBuffer {
private static final int SHORT_SIZE = Short.SIZE / Byte.SIZE;
private static final int INT_SIZE = Integer.SIZE / Byte.SIZE;
private static final int LONG_SIZE = Integer.SIZE / Byte.SIZE;
private final ByteBuffer buff;
private long totalSum;
private long packetSum;
/**
* @see ByteBuffer#wrap(byte[])
* @param data
*/
public ChecksumByteBuffer(byte[] data) {
this.buff = ByteBuffer.wrap(data);
}
/**
* get the sum of the next numberOfBytes worth of data
*
* @param numberOfBytes
* @return
*/
private long getSum(int numberOfBytes) {
int start = buff.position();
int end = start + numberOfBytes;
long rval = 0;
for (int i = start; i < end; ++i) {
rval += UnsignedNumbers.ubyteToShort(buff.get(i));
}
return rval;
}
/**
* @see ByteBuffer#get()
* @return
*/
public byte get() {
byte rval = buff.get();
short unsignedRval = UnsignedNumbers.ubyteToShort(rval);
totalSum += unsignedRval;
packetSum += unsignedRval;
return rval;
}
/**
* @see ByteBuffer#getShort()
* @return
*/
public short getShort() {
long sum = getSum(SHORT_SIZE);
totalSum += sum;
packetSum += sum;
return buff.getShort();
}
/**
* @see ByteBuffer#getInt()
* @return
*/
public int getInt() {
long sum = getSum(INT_SIZE);
totalSum += sum;
packetSum += sum;
return buff.getInt();
}
/**
* @see ByteBuffer#getLong()
* @return
*/
public long getLong() {
long sum = getSum(LONG_SIZE);
totalSum += sum;
packetSum += sum;
return buff.getLong();
}
/**
* reset the current packet sum to zero
*/
public void resetPacketSum() {
packetSum = 0;
}
/**
* reset all sums to zero
*/
public void resetAllSums() {
resetPacketSum();
totalSum = 0;
}
/**
* @return the totalSum
*/
public long getTotalSum() {
return totalSum;
}
/**
* @return the packetSum
*/
public long getPacketSum() {
return packetSum;
}
/**
* @see ByteBuffer#limit()
* @return
*/
public int size() {
return buff.limit();
}
/**
* @see ByteBuffer#position()
* @return
*/
public int position() {
return buff.position();
}
}

View file

@ -0,0 +1,348 @@
/**
* 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.edex.plugin.binlightning.total;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import com.raytheon.edex.esb.Headers;
import com.raytheon.edex.exception.DecoderException;
import com.raytheon.edex.plugin.binlightning.BinLightningDecoder;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
import com.raytheon.uf.common.dataplugin.binlightning.impl.BaseLightningPoint;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningPulsePoint;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgMsgType;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgPulseType;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
import com.raytheon.uf.common.numeric.UnsignedNumbers;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.common.wmo.WMOHeader;
/**
* Decoder for Earth Networks Total Lightning data
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 30, 2014 3226 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class TotalLightningDecoder {
// flash types
public static final byte CLOUD_TO_GROUND_TYPE = 0x00;
public static final byte CLOUD_TO_CLOUD_TYPE = 0x01;
// pulse types
public static final byte RETURN_STROKE_TYPE = 0x00;
public static final byte NON_RETURN_STROKE_TYPE = 0x01;
public static final byte KEEP_ALIVE_TYPE = 0x09;
// conversions
public static final double LONLAT_SCALE_FACTOR = 0.0000001;
public static final double AMPS_PER_KILO_AMP = 1000.0;
public static final double METERS_PER_KILOMETER = 1000.0;
// constant metadata
public static final String DATA_SOURCE = "ENTLN";
private static final IUFStatusHandler log = UFStatus
.getHandler(TotalLightningDecoder.class);
/**
* Parse total lightning data into BinLightningRecords
*
* @param data
* @param headers
* @return
*/
public PluginDataObject[] decode(byte[] data, Headers headers) {
PluginDataObject[] rval;
WMOHeader wmoHdr = new WMOHeader(data);
String fileName = (String) headers.get(WMOHeader.INGEST_FILE_NAME);
if (wmoHdr.isValid()) {
byte[] pdata = BinLightningDecoder.extractPData(wmoHdr, data);
if (pdata != null) {
try {
rval = decodeInternal(fileName, pdata);
} catch (Exception e) {
error(e, headers, wmoHdr);
rval = new PluginDataObject[0];
}
} else {
warn("Unable to separate data from headers", fileName, wmoHdr);
rval = new PluginDataObject[0];
}
} else {
warn("Invalid WMO header", fileName, wmoHdr);
rval = new PluginDataObject[0];
}
return rval;
}
/**
* Display warning message with file and header names
*
* @param msg
* @param fileName
* @param wmoHdr
*/
private void warn(String msg, String fileName, WMOHeader wmoHdr) {
log.warn(msg + ". File: " + fileName + ", WMO Header: " + wmoHdr);
}
/**
* Display error message with file and header names
*
* @param e
* @param headers
* @param wmoHdr
*/
private void error(Exception e, Headers headers, WMOHeader wmoHdr) {
String fileName = (String) headers.get(WMOHeader.INGEST_FILE_NAME);
log.error(e.getLocalizedMessage() + ". File: " + fileName
+ ", WMO Header: " + wmoHdr, e);
}
/**
* @param fileName
* @param pdata
* data after WMO header is removed
* @return
* @throws DecoderException
*/
private PluginDataObject[] decodeInternal(String fileName, byte[] pdata)
throws DecoderException {
List<LightningStrikePoint> decodeStrikes = decodeStrikes(fileName,
pdata);
BinLightningRecord record = new BinLightningRecord(decodeStrikes);
return new PluginDataObject[] { record };
}
/**
* Extract strike data from raw binary
*
* @param fileName
* @param pdata
* @return
* @throws DecoderException
*/
private List<LightningStrikePoint> decodeStrikes(String fileName,
byte[] pdata) throws DecoderException {
List<LightningStrikePoint> rval = new ArrayList<LightningStrikePoint>();
ChecksumByteBuffer buff = new ChecksumByteBuffer(pdata);
while (buff.position() < buff.size()) {
int totalBytes = UnsignedNumbers.ushortToInt(buff.getShort());
if (totalBytes > (buff.size() - buff.position())) {
log.error("Truncated total lightning packet in file: "
+ fileName);
break;
}
/* start flash packet */
buff.resetPacketSum();
/* discard flash packet size byte */
buff.get();
LtgStrikeType flashType = getStrikeType(buff.get());
LightningStrikePoint strike = new LightningStrikePoint(null,
LtgMsgType.TOTAL_LIGHTNING);
strike.setLightSource(DATA_SOURCE);
strike.setType(flashType);
decodeCommonFields(strike, buff);
int pulseCount = UnsignedNumbers.ubyteToShort(buff.get());
strike.setPulseCount(pulseCount);
checkSum(buff, false);
List<LightningPulsePoint> pulses = new ArrayList<LightningPulsePoint>(
pulseCount);
for (int i = 0; i < pulseCount; ++i) {
/* discard size of pulse packet (always 26) */
buff.get();
LtgPulseType pulseType = getPulseType(buff.get());
LightningPulsePoint pulse = new LightningPulsePoint(null,
pulseType);
decodeCommonFields(pulse, buff);
/* discard pulse count (already set in strike) */
buff.get();
checkSum(buff, false);
pulses.add(pulse);
}
strike.setPulses(pulses);
checkSum(buff, true);
rval.add(strike);
}
return rval;
}
/**
* Extract fields common to both strikes and pulses
*
* @param point
* @param buff
*/
private static void decodeCommonFields(BaseLightningPoint point,
ChecksumByteBuffer buff) {
point.setTime(getTime(buff));
point.setLatitude(getDouble(buff, LONLAT_SCALE_FACTOR));
point.setLongitude(getDouble(buff, LONLAT_SCALE_FACTOR));
point.setStrikeStrength(getKiloAmps(buff.getInt()));
/* discard reserved byte */
buff.get();
point.setElevation(getMeters(buff.getShort()));
point.setSensorCount(UnsignedNumbers.ubyteToShort(buff.get()));
}
/**
* Create calendar from 4 byte UNIX time and 2 byte millisecond addition
*
* @param buff
* @return
*/
private static Calendar getTime(ChecksumByteBuffer buff) {
long unixTime = UnsignedNumbers.uintToLong(buff.getInt());
int additionalMillis = UnsignedNumbers.ushortToInt(buff.getShort());
long totalMillis = (unixTime * TimeUtil.MILLIS_PER_SECOND)
+ additionalMillis;
return TimeUtil.newGmtCalendar(new Date(totalMillis));
}
/**
* Ensure data integrity, resets appropriate sum(s) in buffer after check
*
* @param buff
* @param total
* true if total sum should be checked, otherwise checks packet
* sum
* @throws DecoderException
* if check fails
*/
private static void checkSum(ChecksumByteBuffer buff, boolean total)
throws DecoderException {
long rawsum = total ? buff.getTotalSum() : buff.getPacketSum();
/* convert to overflowed unsigned byte */
rawsum &= 0xFF;
/* checksum algorithm from total lightning spec */
long mungedSum = (256 - rawsum) & 0xFF;
/* get expected after sum so it is not reflected in sum */
long expected = UnsignedNumbers.ubyteToShort(buff.get());
if (mungedSum != expected) {
throw new DecoderException("Checksum failed: expected " + expected
+ " got " + mungedSum);
}
if (total) {
buff.resetAllSums();
} else {
buff.resetPacketSum();
}
}
/**
* Get scaled double from 4 byte integer field
*
* @param buff
* @param scaleFactor
* @return
*/
private static double getDouble(ChecksumByteBuffer buff, double scaleFactor) {
int raw = buff.getInt();
return raw * scaleFactor;
}
/**
* Convert amps to kiloamps
*
* @param amps
* @return
*/
private static double getKiloAmps(int amps) {
return amps / AMPS_PER_KILO_AMP;
}
/**
* Convert kilometers to meters
*
* @param kilometers
* @return
*/
private static double getMeters(short kilometers) {
return kilometers * METERS_PER_KILOMETER;
}
/**
* Map strike byte to internal enum
*
* @param type
* @return
* @throws DecoderException
*/
public static LtgStrikeType getStrikeType(byte type)
throws DecoderException {
switch (type) {
case CLOUD_TO_GROUND_TYPE:
return LtgStrikeType.CLOUD_TO_GROUND;
case CLOUD_TO_CLOUD_TYPE:
return LtgStrikeType.CLOUD_TO_CLOUD;
case KEEP_ALIVE_TYPE:
return LtgStrikeType.KEEP_ALIVE;
}
throw new DecoderException("Unknown flash type: " + type);
}
/**
* Map pulse byte to internal enum
*
* @param type
* @return
* @throws DecoderException
*/
public static LtgPulseType getPulseType(byte type) throws DecoderException {
switch (type) {
case RETURN_STROKE_TYPE:
return LtgPulseType.RETURN_STROKE;
case NON_RETURN_STROKE_TYPE:
return LtgPulseType.NON_RETURN_STROKE;
case KEEP_ALIVE_TYPE:
return LtgPulseType.KEEP_ALIVE;
}
throw new DecoderException("Unknown pulse type: " + type);
}
}

View file

@ -20,5 +20,5 @@
-->
<requestPatterns xmlns:ns2="group">
<regex>^SFUS41 KWBC.*</regex>
<regex>^SFPA41 KWBC.*</regex>
<regex>^SFPA4[12] KWBC.*</regex>
</requestPatterns>

View file

@ -29,11 +29,7 @@ import com.raytheon.edex.plugin.textlightning.impl.TextLightningParser;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.edex.decodertools.time.TimeTools;
import com.raytheon.uf.common.time.util.TimeUtil;
/**
* Decoder for text lightning data
@ -47,6 +43,7 @@ import com.raytheon.uf.edex.decodertools.time.TimeTools;
* Mar 25, 2010 jsanchez Initial creation
* Aug 30, 2013 2298 rjpeter Make getPluginName abstract
* Feb 12, 2014 2655 njensen Set source
* Jun 05, 2014 3226 bclement LightningStikePoint refactor
*
* </pre>
*
@ -57,9 +54,6 @@ import com.raytheon.uf.edex.decodertools.time.TimeTools;
public class TextLightningDecoder extends AbstractDecoder implements
IBinaryDecoder {
private static final IUFStatusHandler logger = UFStatus
.getHandler(TextLightningDecoder.class);
private String traceId = null;
/**
@ -92,37 +86,19 @@ public class TextLightningDecoder extends AbstractDecoder implements
BinLightningRecord report = null;
if (strikes.size() > 0) {
report = new BinLightningRecord(strikes.size());
for (LightningStrikePoint strike : strikes) {
report.addStrike(strike);
logger.debug(traceId + "-" + strike);
}
report = new BinLightningRecord(strikes);
} else {
return new PluginDataObject[0];
}
Calendar c = TimeTools.getSystemCalendar();
if (c == null) {
throw new DecoderException(traceId + "-Error decoding times");
}
Calendar c = TimeUtil.newGmtCalendar();
report.setInsertTime(c);
Calendar cStart = report.getStartTime();
Calendar cStop = report.getStopTime();
report.setTraceId(traceId);
TimeRange range = new TimeRange(cStart.getTimeInMillis(),
cStop.getTimeInMillis());
DataTime dataTime = new DataTime(cStart, range);
report.setDataTime(dataTime);
if (report != null) {
report.setTraceId(traceId);
// TODO anyone have any idea what the source should actually be
// named?
report.setSource("text");
}
// TODO anyone have any idea what the source should actually be
// named?
report.setSource("text");
return new PluginDataObject[] { report };
}

View file

@ -50,6 +50,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* lgtng intensities -999 to
* 999
* Feb 12, 2014 2655 njensen Use status handler for logging
* Jun 05, 2014 3226 bclement LightningStikePoint refactor
*
* </pre>
*
@ -177,7 +178,7 @@ public class TextLightningParser {
Double.parseDouble(latitude),
Double.parseDouble(longitude));
strike.setStrikeStrength(Double.parseDouble(strength));
strike.setStrikeCount(Integer.parseInt(count));
strike.setPulseCount(Integer.parseInt(count));
strike.setMonth(Integer.parseInt(month));
strike.setDay(Integer.parseInt(day));
strike.setYear(Integer.parseInt(year));
@ -186,7 +187,7 @@ public class TextLightningParser {
strike.setSecond(Integer.parseInt(sec));
strike.setMillis(0);
strike.setMsgType(LtgMsgType.STRIKE_MSG_FL);
strike.setType(LtgStrikeType.STRIKE_CG);
strike.setType(LtgStrikeType.CLOUD_TO_GROUND);
strike.setLightSource("UNKN");
reports.add(strike);
} else {
@ -214,7 +215,7 @@ public class TextLightningParser {
Double.parseDouble(latitude), lon);
strike.setStrikeStrength(Double
.parseDouble(strength));
strike.setStrikeCount(Integer.parseInt(count));
strike.setPulseCount(Integer.parseInt(count));
strike.setMonth(Integer.parseInt(month));
strike.setDay(Integer.parseInt(day));
strike.setYear(Integer.parseInt(year) + 2000);
@ -223,7 +224,7 @@ public class TextLightningParser {
strike.setSecond(Integer.parseInt(sec));
strike.setMillis(Integer.parseInt(msec) * 10);
strike.setMsgType(LtgMsgType.STRIKE_MSG_FL);
strike.setType(LtgStrikeType.STRIKE_CG);
strike.setType(LtgStrikeType.CLOUD_TO_GROUND);
strike.setLightSource("UNKN");
reports.add(strike);
} else {
@ -250,7 +251,7 @@ public class TextLightningParser {
Double.parseDouble(longitude));
strike.setStrikeStrength(Double
.parseDouble(strength));
strike.setStrikeCount(Integer.parseInt(count));
strike.setPulseCount(Integer.parseInt(count));
strike.setMonth(Integer.parseInt(month));
strike.setDay(Integer.parseInt(day));
strike.setYear(Integer.parseInt(year));
@ -259,7 +260,7 @@ public class TextLightningParser {
strike.setSecond(Integer.parseInt(sec));
strike.setMillis(Integer.parseInt(msec) * 10);
strike.setMsgType(LtgMsgType.STRIKE_MSG_FL);
strike.setType(LtgStrikeType.STRIKE_CG);
strike.setType(LtgStrikeType.CLOUD_TO_GROUND);
strike.setLightSource(sls);
reports.add(strike);
} else {

View file

@ -19,8 +19,13 @@
**/
package com.raytheon.uf.common.dataplugin.binlightning;
import java.io.FileNotFoundException;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.persistence.Access;
import javax.persistence.AccessType;
@ -35,18 +40,17 @@ import org.hibernate.annotations.Index;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningPulsePoint;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
import com.raytheon.uf.common.dataplugin.persist.IPersistable;
import com.raytheon.uf.common.dataplugin.persist.PersistablePluginDataObject;
import com.raytheon.uf.common.datastorage.IDataStore;
import com.raytheon.uf.common.datastorage.StorageException;
import com.raytheon.uf.common.datastorage.records.ByteDataRecord;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
import com.raytheon.uf.common.datastorage.records.IDataRecord;
import com.raytheon.uf.common.datastorage.records.IntegerDataRecord;
import com.raytheon.uf.common.datastorage.records.LongDataRecord;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.time.util.TimeUtil;
/**
@ -82,6 +86,8 @@ import com.raytheon.uf.common.time.util.TimeUtil;
* Oct 22, 2013 2361 njensen Removed XML annotations
* Jan 21, 2014 2667 bclement renamed record's lightSource field to source
* May 14, 2014 2536 bclement removed TimeTools usage
* Jun 05, 2014 3226 bclement moved data arrays into map for easier management
* replaced addStrike() with List constructor, added pulses
*
* </pre>
*
@ -106,43 +112,12 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
public static final String PLUGIN_NAME = "binlightning";
// Data store data items
@Transient
private long[] obsTimes = null;
private final Map<String, Object> strikeDataArrays = new TreeMap<String, Object>();
@Transient
private float[] latitudes = null;
@Transient
private float[] longitudes = null;
@Transient
private int[] intensities = null;
@Transient
private byte[] msgTypes = null;
@Transient
private byte[] strikeTypes = null;
@Transient
private byte[] strikeCounts = null;
@Transient
private Object[] dataArrays = null;
// Data store data item names
@Transient
private final String[] dataNames = { "obsTime", "latitude", "longitude",
"intensity", "msgType", "strikeType", "strikeCount", };
@Transient
private int insertIndex = 0;
@Transient
private long startTimeMillis = Long.MAX_VALUE;
@Transient
private long stopTimeMillis = Long.MIN_VALUE;
private final Map<String, Object> pulseDataArrays = new TreeMap<String, Object>();
// Persisted value - Earliest strike time in the collection.
@DataURI(position = 1)
@ -177,63 +152,148 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
*
* @param uri
* The dataURI
* @param tableDef
* The table definition associated with this class
*/
public BinLightningRecord(String uri) {
super(uri);
}
/**
* Construct an empty lightning record.
* Construct a lightning record from a list of strikes
*
* @param strikes
*/
public BinLightningRecord(int arraysSize) {
obsTimes = new long[arraysSize];
latitudes = new float[arraysSize];
longitudes = new float[arraysSize];
public BinLightningRecord(final List<LightningStrikePoint> strikes) {
final int arraysSize = strikes.size();
long[] obsTimes = new long[arraysSize];
float[] latitudes = new float[arraysSize];
float[] longitudes = new float[arraysSize];
int[] intensities = new int[arraysSize];
byte[] msgTypes = new byte[arraysSize];
byte[] strikeTypes = new byte[arraysSize];
byte[] pulseCounts = new byte[arraysSize];
int[] pulseIndexes = new int[arraysSize];
int[] heights = new int[arraysSize];
int[] sensorCounts = new int[arraysSize];
intensities = new int[arraysSize];
msgTypes = new byte[arraysSize];
strikeTypes = new byte[arraysSize];
strikeCounts = new byte[arraysSize];
dataArrays = new Object[] { obsTimes, latitudes, longitudes,
intensities, msgTypes, strikeTypes, strikeCounts, };
insertIndex = 0;
strikeDataArrays.put(LightningConstants.TIME_DATASET, obsTimes);
strikeDataArrays.put(LightningConstants.LAT_DATASET, latitudes);
strikeDataArrays.put(LightningConstants.LON_DATASET, longitudes);
strikeDataArrays.put(LightningConstants.INTENSITY_DATASET, intensities);
strikeDataArrays.put(LightningConstants.MSG_TYPE_DATASET, msgTypes);
strikeDataArrays.put(LightningConstants.STRIKE_TYPE_DATASET,
strikeTypes);
strikeDataArrays
.put(LightningConstants.PULSE_COUNT_DATSET, pulseCounts);
strikeDataArrays.put(LightningConstants.PULSE_INDEX_DATASET,
pulseIndexes);
strikeDataArrays.put(LightningConstants.HEIGHT_DATASET, heights);
strikeDataArrays.put(LightningConstants.SENSOR_COUNT_DATASET,
sensorCounts);
if (arraysSize > 0) {
LightningStrikePoint sample = strikes.get(0);
setDataSource(sample);
}
long startTimeMillis = Long.MAX_VALUE;
long stopTimeMillis = Long.MIN_VALUE;
int pulseDataCount = 0;
final Iterator<LightningStrikePoint> iter = strikes.iterator();
for (int i = 0; i < arraysSize; ++i) {
LightningStrikePoint strike = iter.next();
Calendar c = strike.getTime();
long obsTimeMillis = c.getTimeInMillis();
startTimeMillis = Math.min(startTimeMillis, obsTimeMillis);
stopTimeMillis = Math.max(stopTimeMillis, obsTimeMillis);
obsTimes[i] = obsTimeMillis;
latitudes[i] = (float) strike.getLatitude();
longitudes[i] = (float) strike.getLongitude();
intensities[i] = (int) Math.round(strike.getStrikeStrength());
msgTypes[i] = (byte) strike.getMsgType().getId();
strikeTypes[i] = (byte) strike.getType().getId();
/* some types have pulse counts but no pulse data */
pulseCounts[i] = (byte) strike.getPulseCount();
heights[i] = (int) Math.round(strike.getElevation());
sensorCounts[i] = strike.getSensorCount();
List<LightningPulsePoint> pulses = strike.getPulses();
if (pulses != null && !pulses.isEmpty()) {
pulseIndexes[i] = pulseDataCount;
pulseDataCount += pulses.size();
if (pulseCounts[i] != pulses.size()) {
pulseCounts[i] = (byte) pulses.size();
}
}
}
if (pulseDataCount > 0) {
/* at least one of the strikes had pulse data */
setPulseData(strikes, pulseDataCount);
}
startTime = TimeUtil.newGmtCalendar(new Date(startTimeMillis));
stopTime = TimeUtil.newGmtCalendar(new Date(stopTimeMillis));
TimeRange range = new TimeRange(startTime, stopTime);
setDataTime(new DataTime(startTime, range));
}
// /**
// * Construct an empty lightning record.
// *
// * @param message
// * Lightning data report.
// */
// public BinLightningRecord(String message) {
// super(message);
// }
/**
* Track the current persistence time for the data set.
* @param strikes
* @param pulseDataCount
* total number of pulses for all strikes
*/
@SuppressWarnings("unused")
private void updatePersistenceTime() {
if ((startTimeMillis != Long.MAX_VALUE)
&& (stopTimeMillis != Long.MIN_VALUE)) {
persistTime = (startTimeMillis + stopTimeMillis) / 2;
setPersistenceTime(new Date(persistTime));
} else {
setPersistenceTime(TimeUtil.newGmtCalendar().getTime());
persistTime = getInsertTime().getTimeInMillis();
private void setPulseData(final List<LightningStrikePoint> strikes,
final int pulseDataCount) {
long[] pulseTimes = new long[pulseDataCount];
float[] pulseLats = new float[pulseDataCount];
float[] pulseLons = new float[pulseDataCount];
int[] pulseIntensities = new int[pulseDataCount];
byte[] pulseTypes = new byte[pulseDataCount];
int[] pulseHeights = new int[pulseDataCount];
int[] pulseSensorCounts = new int[pulseDataCount];
pulseDataArrays.put(LightningConstants.TIME_DATASET, pulseTimes);
pulseDataArrays.put(LightningConstants.LAT_DATASET, pulseLats);
pulseDataArrays.put(LightningConstants.LON_DATASET, pulseLons);
pulseDataArrays.put(LightningConstants.INTENSITY_DATASET,
pulseIntensities);
pulseDataArrays.put(LightningConstants.PULSE_TYPE_DATASET, pulseTypes);
pulseDataArrays.put(LightningConstants.HEIGHT_DATASET, pulseHeights);
pulseDataArrays.put(LightningConstants.SENSOR_COUNT_DATASET,
pulseSensorCounts);
int index = 0;
for (LightningStrikePoint strike : strikes) {
List<LightningPulsePoint> pulses = strike.getPulses();
if (pulses != null && !pulses.isEmpty()) {
for (LightningPulsePoint pulse : pulses) {
pulseTimes[index] = pulse.getTime().getTimeInMillis();
pulseLats[index] = (float) pulse.getLatitude();
pulseLons[index] = (float) pulse.getLongitude();
pulseIntensities[index] = (int) Math.round(pulse
.getStrikeStrength());
pulseTypes[index] = pulse.getType().getId();
pulseHeights[index] = (int) Math
.round(pulse.getElevation());
pulseSensorCounts[index] = pulse.getSensorCount();
++index;
}
}
}
}
/**
* Add a strike report to the record collection.
* Extract data source from strike
*
* @param strike
* A strike report to add.
*/
public void addStrike(LightningStrikePoint strike) {
// jjg add
private void setDataSource(LightningStrikePoint strike) {
if (source == null) {
if (strike.getLightSource() == null) {
source = "NLDN";
@ -249,47 +309,6 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
source = "UNKN";
}
}
// end
if (insertIndex < obsTimes.length) {
long t1 = startTimeMillis;
Calendar c = TimeUtil.newGmtCalendar(strike.getYear(),
strike.getMonth(), strike.getDay());
c.set(Calendar.HOUR_OF_DAY, strike.getHour());
c.set(Calendar.MINUTE, strike.getMinute());
c.set(Calendar.SECOND, strike.getSecond());
c.set(Calendar.MILLISECOND, strike.getMillis());
long obsTimeMillis = c.getTimeInMillis();
startTimeMillis = Math.min(startTimeMillis, obsTimeMillis);
stopTimeMillis = Math.max(stopTimeMillis, obsTimeMillis);
obsTimes[insertIndex] = obsTimeMillis;
latitudes[insertIndex] = (float) strike.getLatitude();
longitudes[insertIndex] = (float) strike.getLongitude();
intensities[insertIndex] = Math.round((float) strike
.getStrikeStrength());
msgTypes[insertIndex] = (byte) strike.getMsgType().ordinal();
strikeTypes[insertIndex] = (byte) strike.getType().ordinal();
strikeCounts[insertIndex] = (byte) strike.getStrikeCount();
insertIndex++;
// only update the times if they have changed!
if (t1 != startTimeMillis) {
startTime = TimeUtil.newGmtCalendar(new Date(startTimeMillis));
}
if (t1 != stopTimeMillis) {
stopTime = TimeUtil.newGmtCalendar(new Date(stopTimeMillis));
}
// updatePersistenceTime();
} else {
throw new ArrayIndexOutOfBoundsException(String.format(
"index greater than length [%d]", insertIndex));
}
}
/**
@ -349,25 +368,14 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
setInsertTime(insert_time);
}
public String[] getDataNames() {
return dataNames;
}
public Object[] getDataArrays() {
return dataArrays;
}
public void setDataArrays(Object[] dataArrays) {
this.dataArrays = dataArrays;
}
/**
* gets the obsTimes
*
* @return
*/
public long[] getObsTimes() {
return obsTimes;
Object obj = strikeDataArrays.get(LightningConstants.TIME_DATASET);
return obj != null ? (long[]) obj : new long[0];
}
/**
@ -376,7 +384,8 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
* @return
*/
public float[] getLatitudes() {
return latitudes;
Object obj = strikeDataArrays.get(LightningConstants.LAT_DATASET);
return obj != null ? (float[]) obj : new float[0];
}
/**
@ -385,7 +394,8 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
* @return
*/
public float[] getLongitudes() {
return longitudes;
Object obj = strikeDataArrays.get(LightningConstants.LON_DATASET);
return obj != null ? (float[]) obj : new float[0];
}
/**
@ -394,7 +404,8 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
* @return
*/
public int[] getIntensities() {
return intensities;
Object obj = strikeDataArrays.get(LightningConstants.INTENSITY_DATASET);
return obj != null ? (int[]) obj : new int[0];
}
/**
@ -403,7 +414,8 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
* @return
*/
public byte[] getMsgTypes() {
return msgTypes;
Object obj = strikeDataArrays.get(LightningConstants.MSG_TYPE_DATASET);
return obj != null ? (byte[]) obj : new byte[0];
}
/**
@ -412,7 +424,9 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
* @return
*/
public byte[] getStrikeTypes() {
return strikeTypes;
Object obj = strikeDataArrays
.get(LightningConstants.STRIKE_TYPE_DATASET);
return obj != null ? (byte[]) obj : new byte[0];
}
/**
@ -420,8 +434,10 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
*
* @return
*/
public byte[] getStrikeCounts() {
return strikeCounts;
public byte[] getPulseCounts() {
Object obj = strikeDataArrays
.get(LightningConstants.PULSE_COUNT_DATSET);
return obj != null ? (byte[]) obj : new byte[0];
}
/**
@ -449,42 +465,55 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
*/
public void retrieveFromDataStore(IDataStore dataStore)
throws StorageException {
retrieveFromDataStore(dataStore, false);
}
/**
* Sets the data arrays from the store.
*
* @param dataStore
* @param includePulses
* extract pulse data if true
*/
public void retrieveFromDataStore(IDataStore dataStore,
boolean includePulses) throws StorageException {
try {
IDataRecord[] dataRec = dataStore.retrieve(getDataURI());
dataArrays = new Object[dataRec.length];
for (int i = 0; i < dataRec.length; i++) {
if (dataRec[i].getName().equals("obsTime")) {
obsTimes = ((LongDataRecord) dataRec[i]).getLongData();
dataArrays[i] = obsTimes;
}
if (dataRec[i].getName().equals("latitude")) {
latitudes = ((FloatDataRecord) dataRec[i]).getFloatData();
dataArrays[i] = latitudes;
} else if (dataRec[i].getName().equals("longitude")) {
longitudes = ((FloatDataRecord) dataRec[i]).getFloatData();
dataArrays[i] = longitudes;
} else if (dataRec[i].getName().equals("intensity")) {
intensities = ((IntegerDataRecord) dataRec[i]).getIntData();
dataArrays[i] = intensities;
} else if (dataRec[i].getName().equals("msgType")) {
msgTypes = ((ByteDataRecord) dataRec[i]).getByteData();
dataArrays[i] = msgTypes;
} else if (dataRec[i].getName().equals("strikeType")) {
strikeTypes = ((ByteDataRecord) dataRec[i]).getByteData();
dataArrays[i] = strikeTypes;
} else if (dataRec[i].getName().equals("strikeCount")) {
strikeCounts = ((ByteDataRecord) dataRec[i]).getByteData();
dataArrays[i] = strikeCounts;
IDataRecord[] dataRecs = dataStore.retrieve(getDataURI());
for (IDataRecord record : dataRecs) {
strikeDataArrays.put(record.getName(), record.getDataObject());
}
if (includePulses) {
String pulseGroup = getDataURI() + DataURI.SEPARATOR
+ LightningConstants.PULSE_HDF5_GROUP_SUFFIX;
try {
IDataRecord[] pulseRecords = dataStore.retrieve(pulseGroup);
for (IDataRecord record : pulseRecords) {
pulseDataArrays.put(record.getName(),
record.getDataObject());
}
} catch (Exception e) {
/* FIXME better way to find out if group doesn't exist */
}
}
setDataArrays(dataArrays);
} catch (Exception se) {
se.printStackTrace();
} catch (FileNotFoundException e) {
throw new StorageException(e.getLocalizedMessage(), null, e);
}
}
/**
* @return the strikeDataArrays
*/
public Map<String, Object> getStrikeDataArrays() {
return strikeDataArrays;
}
/**
* @return the pulseDataArrays
*/
public Map<String, Object> getPulseDataArrays() {
return pulseDataArrays;
}
@Override
@Column
@Access(AccessType.PROPERTY)

View file

@ -0,0 +1,66 @@
/**
* 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.common.dataplugin.binlightning;
/**
* Constants used for lightning data such as dataset names in HDF5
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 30, 2014 3226 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class LightningConstants {
public static final String PULSE_HDF5_GROUP_SUFFIX = "pulse";
// HDF5 dataset names
public static final String TIME_DATASET = "obsTime";
public static final String LAT_DATASET = "latitude";
public static final String LON_DATASET = "longitude";
public static final String INTENSITY_DATASET = "intensity";
public static final String MSG_TYPE_DATASET = "msgType";
public static final String STRIKE_TYPE_DATASET = "strikeType";
public static final String PULSE_COUNT_DATSET = "pulseCount";
public static final String PULSE_INDEX_DATASET = "pulseIndex";
public static final String PULSE_TYPE_DATASET = "pulseType";
public static final String HEIGHT_DATASET = "height";
public static final String SENSOR_COUNT_DATASET = "sensorCount";
}

View file

@ -0,0 +1,259 @@
/**
* 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.common.dataplugin.binlightning.impl;
import java.util.Calendar;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.vividsolutions.jts.geom.Coordinate;
/**
* Lightning information common to strikes and pulses
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 3, 2014 3226 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class BaseLightningPoint {
private final Coordinate point;
private Calendar time;
// Lightning strike strength and polarity
private double strikeStrength;
private int sensorCount;
/**
*
*/
public BaseLightningPoint() {
this(TimeUtil.newGmtCalendar());
}
/**
* @param time
*/
public BaseLightningPoint(Calendar time) {
this(new Coordinate(), time);
}
/**
* @param point
*/
public BaseLightningPoint(Coordinate point, Calendar time) {
this.point = point;
this.time = time;
}
/**
* @param latitude
* @param longitude
*/
public BaseLightningPoint(double latitude, double longitude, Calendar time) {
this(new Coordinate(longitude, latitude), time);
}
/**
* Set the year part of the date.
*
* @param year
* Year.
*/
public void setYear(int year) {
this.time.set(Calendar.YEAR, year);
}
/**
* Set the day of the month part of the date.
*
* @param day
* Day of month [1..12].
*/
public void setMonth(int month) {
this.time.set(Calendar.MONTH, month - 1);
}
/**
* Set the day of the month part of the date.
*
* @param day
* Day of month [1..12].
*/
public void setDay(int day) {
this.time.set(Calendar.DAY_OF_MONTH, day);
}
/**
* Set the hour part of the time.
*
* @param hour
* Hour of the day [0..23].
*/
public void setHour(int hour) {
this.time.set(Calendar.HOUR, hour);
}
/**
* Set the minute of the hour.
*
* @param minute
* The minute of the hour [0..59]
*/
public void setMinute(int minute) {
this.time.set(Calendar.MINUTE, minute);
}
/**
* Set the second of the minute.
*
* @param second
* The second of the minute [0..59]
*/
public void setSecond(int second) {
this.time.set(Calendar.SECOND, second);
}
/**
* Set the milliseconds part of the time.
*
* @param millis
* Milliseconds [0..999].
*/
public void setMillis(int millis) {
this.time.set(Calendar.MILLISECOND, millis);
}
/**
* @return the time
*/
public Calendar getTime() {
return time;
}
/**
* @param time
* the time to set
*/
public void setTime(Calendar time) {
this.time = time;
}
/**
* Get the strike strength.
*
* @return The strike strength.
*/
public double getStrikeStrength() {
return strikeStrength;
}
/**
* Set the strike strength.
*
* @return The strike strength.
*/
public void setStrikeStrength(double strikeStrength) {
this.strikeStrength = strikeStrength;
}
/**
* @return the sensorCount
*/
public int getSensorCount() {
return sensorCount;
}
/**
* @param sensorCount
* the sensorCount to set
*/
public void setSensorCount(int sensorCount) {
this.sensorCount = sensorCount;
}
/**
* Get the latitude of this point.
*
* @return The latitude.
*/
public double getLatitude() {
return point.y;
}
/**
* Set the latitude for this point.
*
* @param latitude
* The latitude.
*/
public void setLatitude(double latitude) {
this.point.y = latitude;
}
/**
* Get the longitude of this point.
*
* @return The longitude.
*/
public double getLongitude() {
return point.x;
}
/**
* Set the longitude for this point.
*
* @param longitude
* The longitude.
*/
public void setLongitude(double longitude) {
this.point.x = longitude;
}
/**
* Get the elevation of this point. No units are specified.
*
* @return The elevation of this point.
*/
public double getElevation() {
return this.point.z;
}
/**
* Set the elevation of this point. No units are specified.
*
* @param elevation
* The elevation of this point.
*/
public void setElevation(double elevation) {
this.point.z = elevation;
}
}

View file

@ -0,0 +1,67 @@
/**
* 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.common.dataplugin.binlightning.impl;
import java.util.Calendar;
/**
* Lightning pulse information
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 3, 2014 3226 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class LightningPulsePoint extends BaseLightningPoint {
private final LtgPulseType type;
public LightningPulsePoint(LtgPulseType type) {
super();
this.type = type;
}
public LightningPulsePoint(Calendar time, LtgPulseType type) {
super(time);
this.type = type;
}
public LightningPulsePoint(double latitude, double longitude,
Calendar time, LtgPulseType type) {
super(latitude, longitude, time);
this.type = type;
}
/**
* @return the type
*/
public LtgPulseType getType() {
return type;
}
}

View file

@ -19,53 +19,59 @@
**/
package com.raytheon.uf.common.dataplugin.binlightning.impl;
import com.raytheon.uf.edex.decodertools.core.BasePoint;
import java.util.Calendar;
import java.util.List;
import com.raytheon.uf.common.time.util.TimeUtil;
/**
* Record implementation for the Binary Lightning data decoder.
*
* <pre>
*
*
* SOFTWARE HISTORY
*
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 20070810 379 jkorman Initial Coding from prototype.
* 20130227 DCS 152 jgerth Support for WWLLN and multiple sources
* Jun 3, 2014 3226 bclement refactor to support pulse data
*
* </pre>
*
*
* @author jkorman
* @version 1.0
*/
public class LightningStrikePoint extends BasePoint
public class LightningStrikePoint extends BaseLightningPoint
{
private LtgStrikeType type;
private LtgMsgType msgType;
// Lightning strike strength and polarity
private double strikeStrength;
// Number of strikes for this record.
private int strikeCount;
// Number of pulses for this record.
private int pulseCount;
// JJG - Lightning data source
private String lightSource;
private List<LightningPulsePoint> pulses;
/**
* Construct a LightningStrikePoint using given data.
* @param base The base point which should contain a valid time.
* @param latitude The latitude of the strike.
* @param longitude The longitude of the strike.
* @param type The strike message type.
*
* @param latitude
* The latitude of the strike.
* @param longitude
* The longitude of the strike.
* @param time
* @param type
* The strike message type.
*/
public LightningStrikePoint(BasePoint base, double latitude, double longitude, LtgMsgType type)
public LightningStrikePoint(double latitude, double longitude,
Calendar time, LtgMsgType type)
{
super(base);
setLatitude(latitude);
setLongitude(longitude);
super(latitude, longitude, time);
setElevation(0);
this.msgType = type;
}
@ -77,44 +83,37 @@ public class LightningStrikePoint extends BasePoint
*/
public LightningStrikePoint(double latitude, double longitude)
{
super(latitude,longitude);
super(latitude, longitude, TimeUtil.newGmtCalendar());
setElevation(0);
}
/**
* Get the strike count.
* @return The strike count.
* @param time
* @param type
*/
public int getStrikeCount()
{
return strikeCount;
public LightningStrikePoint(Calendar time, LtgMsgType type) {
super(time);
this.msgType = type;
}
/**
* Set the strike count.
* @return The strike count.
* Get the pulse count.
*
* @return The pulse count.
*/
public void setStrikeCount(int strikeCount)
public int getPulseCount()
{
this.strikeCount = strikeCount;
return pulseCount;
}
/**
* Get the strike strength.
* @return The strike strength.
* Set the pulse count.
*
* @return The pulse count.
*/
public double getStrikeStrength()
public void setPulseCount(int pulseCount)
{
return strikeStrength;
}
/**
* Set the strike strength.
* @return The strike strength.
*/
public void setStrikeStrength(double strikeStrength)
{
this.strikeStrength = strikeStrength;
this.pulseCount = pulseCount;
}
/**
@ -189,13 +188,22 @@ public class LightningStrikePoint extends BasePoint
{
buffer = new StringBuilder();
}
buffer.append(String.format("%4d%02d%02d",getYear(),getMonth(),getDay()));
buffer.append(String.format("%02d%02d%02d",getHour(),getMinute(),getSecond()));
Calendar obsTime = getTime();
int year = obsTime.get(Calendar.YEAR);
int month = obsTime.get(Calendar.MONTH) + 1;
int day = obsTime.get(Calendar.DAY_OF_MONTH);
int hour = obsTime.get(Calendar.HOUR);
int minute = obsTime.get(Calendar.MINUTE);
int second = obsTime.get(Calendar.SECOND);
int millis = obsTime.get(Calendar.MILLISECOND);
buffer.append(String.format("%4d%02d%02d", year, month, day));
buffer.append(String.format("%02d%02d%02d", hour, minute, second));
buffer.append(String.format(" %9.5f %10.5f ",getLatitude(), getLongitude() ));
buffer.append(String.format("%2s %2s ",msgType.getType(),type.getType()));
buffer.append(String.format("%4.0f %02d %02d", strikeStrength,(getMillis() / 100),strikeCount));
buffer.append(String.format("%4.0f %02d %02d", getStrikeStrength(),
(millis / 100), pulseCount));
return buffer;
}
@ -213,5 +221,20 @@ public class LightningStrikePoint extends BasePoint
{
return toString(null).toString();
}
/**
* @return the pulses
*/
public List<LightningPulsePoint> getPulses() {
return pulses;
}
/**
* @param pulses
* the pulses to set
*/
public void setPulses(List<LightningPulsePoint> pulses) {
this.pulses = pulses;
}
}

View file

@ -23,32 +23,51 @@ package com.raytheon.uf.common.dataplugin.binlightning.impl;
* Enums for the lightning message type, Flash or RT Flash.
*
* <pre>
*
*
* SOFTWARE HISTORY
*
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 20070810 379 jkorman Initial Coding from prototype.
* Jun 3, 2014 3226 bclement added id, added TOTAL_LIGHTNING
*
* </pre>
*
*
* @author jkorman
* @version 1.0
*/
public enum LtgMsgType
{
STRIKE_MSG_FL("FL"),
STRIKE_MSG_RT("RT");
STRIKE_MSG_FL((byte) 0, "FL"), STRIKE_MSG_RT((byte) 1, "RT"), TOTAL_LIGHTNING(
(byte) 2, "TL");
private final String strikeType;
private final String msgType;
private final byte id;
/**
* Construct the type.
* @param type Lightning strike type.
*
* @param type
* Lightning message type.
*/
private LtgMsgType(String type)
private LtgMsgType(byte id, String type)
{
strikeType = type;
this.msgType = type;
this.id = id;
}
/**
* @param id
* @return null if no type found for id
*/
public static LtgMsgType getById(byte id) {
for (LtgMsgType type : LtgMsgType.values()) {
if (type.id == id) {
return type;
}
}
return null;
}
/**
@ -57,6 +76,13 @@ public enum LtgMsgType
*/
public String getType()
{
return strikeType;
return msgType;
}
/**
* @return unique id for type
*/
public byte getId() {
return this.id;
}
}

View file

@ -0,0 +1,71 @@
/**
* 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.common.dataplugin.binlightning.impl;
/**
* Stroke type enum for lightning pulses. Mainly categorizes between return and
* non-return strokes.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 3, 2014 3226 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public enum LtgPulseType {
RETURN_STROKE((byte) 0), NON_RETURN_STROKE((byte) 1), KEEP_ALIVE((byte) 9);
private final byte id;
/**
* @param id
*/
private LtgPulseType(byte id) {
this.id = id;
}
/**
* @param id
* @return null if no type is found for id
*/
public static LtgPulseType getById(byte id) {
for (LtgPulseType type : LtgPulseType.values()) {
if (type.id == id) {
return type;
}
}
return null;
}
/**
* @return unique id for this type
*/
public byte getId() {
return this.id;
}
}

View file

@ -23,34 +23,52 @@ package com.raytheon.uf.common.dataplugin.binlightning.impl;
* Enums for the lightning strike type, cloud-to-cloud or cloud-to-ground.
*
* <pre>
*
*
* SOFTWARE HISTORY
*
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 20070810 379 jkorman Initial Coding from prototype.
* 20130425 DCS 112 Wufeng Zhou Added STRIKE_TF (for Total Flash) in definition for Total Flash
* Jun 3, 2014 3226 bclement added id, changed to more descriptive names, added KEEP_ALIVE
*
* </pre>
*
*
* @author jkorman
* @version 1.0
*/
public enum LtgStrikeType
{
STRIKE_CC("CC"),
STRIKE_CG("CG"),
STRIKE_TF("TF");
CLOUD_TO_CLOUD((byte)0, "CC"), CLOUD_TO_GROUND((byte)1, "CG"), TOTAL_FLASH((byte)2, "TF"), KEEP_ALIVE((byte)9,
"");
private final String strikeType;
private final byte id;
/**
* Construct the type.
* @param id unique id for type
* @param type Lightning strike type.
*/
private LtgStrikeType(String type)
private LtgStrikeType(byte id, String type)
{
strikeType = type;
this.id = id;
this.strikeType = type;
}
/**
* @param id
* unique id for type
* @return null if no type is found for id
*/
public static LtgStrikeType getById(byte id) {
for (LtgStrikeType type : LtgStrikeType.values()) {
if (type.id == id) {
return type;
}
}
return null;
}
/**
@ -61,4 +79,11 @@ public enum LtgStrikeType
{
return strikeType;
}
/**
* @return id
*/
public int getId() {
return this.id;
}
}

View file

@ -76,6 +76,8 @@ import com.vividsolutions.jts.io.WKTWriter;
* 12/20/2013 DR 16894 gzhang Fixed getZRvalue2() bias issue.
* 05/12/2014 3133 njensen Extracted getLightningRecord
* 05/13/2014 3133 njensen Moved convertStrankValue here from ScanConfig
* Jun 05, 2014 3226 bclement BinLightning refactor
* compare lightning strike type by id instead of ordinal
* </pre>
*
* @author dhladky
@ -1292,7 +1294,7 @@ public class ScanUtils {
(double) rec.getLatitudes()[i],
(double) rec.getLongitudes()[i],
rec.getIntensities()[i], rec.getStrikeTypes()[i],
rec.getMsgTypes()[i], rec.getStrikeCounts()[i]);
rec.getMsgTypes()[i], rec.getPulseCounts()[i]);
strikeList.add(strike);
}
@ -1311,7 +1313,7 @@ public class ScanUtils {
if (ls.getIntensity() > 0) {
totalPosStrikes++;
}
if (ls.getStrikeType() == LtgStrikeType.STRIKE_CG.ordinal()) {
if (ls.getStrikeType() == LtgStrikeType.CLOUD_TO_GROUND.getId()) {
totalCGStrikes++;
}
totalStrikes++;

View file

@ -19,12 +19,14 @@
**/
package com.raytheon.uf.edex.decodertools.core;
import com.vividsolutions.jts.geom.Coordinate;
/**
* BasePoint provides a simple 4D (latitude, longitude, elevation, and time)
* base class for observation data. Sub-classes of BasePoint are responsible for
* adding additional checking or using specific units as required. An example
* would be adding a accessors for a Calendar to expose the date information.
* Most attributes of this class do not have units.
* BasePoint provides a simple 3D (latitude, longitude, elevation) base class
* for observation data. Sub-classes of BasePoint are responsible for adding
* additional checking or using specific units as required. Most attributes of
* this class do not have units.
*
* <pre>
*
@ -35,11 +37,14 @@ package com.raytheon.uf.edex.decodertools.core;
* 27 July 2007 411 jkorman Initial Development
* 20070911 379 jkorman Added comments.
* 20070912 379 jkorman Code review cleanup.
* Jun 05, 2014 3226 bclement deprecated class, removed time
* </pre>
*
* @deprecated use {@link Coordinate} instead
* @author jkorman
* @version 1
*/
@Deprecated
public class BasePoint {
private double latitude;
@ -47,20 +52,6 @@ public class BasePoint {
private double elevation;
private int year;
private int month;
private int day;
private int hour;
private int minute;
private int second;
private int millis;
/**
* Create an empty basepoint instance.
*/
@ -74,16 +65,9 @@ public class BasePoint {
* A basepoint to copy.
*/
public BasePoint(BasePoint point) {
latitude = point.latitude;
longitude = point.longitude;
elevation = point.elevation;
year = point.year;
month = point.month;
day = point.day;
hour = point.hour;
minute = point.minute;
second = point.second;
millis = point.millis;
this.latitude = point.latitude;
this.longitude = point.longitude;
this.elevation = point.elevation;
}
/**
@ -154,136 +138,4 @@ public class BasePoint {
this.elevation = elevation;
}
/**
* Get the year part of the date.
*
* @return The year.
*/
public int getYear() {
return year;
}
/**
* Set the year part of the date.
*
* @param year
* Year.
*/
public void setYear(int year) {
this.year = year;
}
/**
* Get the month part of the date.
*
* @return The month of the year.
*/
public int getMonth() {
return month;
}
/**
* Set the day of the month part of the date.
*
* @param day
* Day of month [1..12].
*/
public void setMonth(int month) {
this.month = month;
}
/**
* Get the day part of the month.
*
* @return The day of the month.
*/
public int getDay() {
return day;
}
/**
* Set the day of the month part of the date.
*
* @param day
* Day of month [1..12].
*/
public void setDay(int day) {
this.day = day;
}
/**
* Get the hours part of the day.
*
* @return The hours part of the day.
*/
public int getHour() {
return hour;
}
/**
* Set the hour part of the time.
*
* @param hour
* Hour of the day [0..23].
*/
public void setHour(int hour) {
this.hour = hour;
}
/**
* Get the minutes part of the hour.
*
* @return The minutes part of the hour.
*/
public int getMinute() {
return minute;
}
/**
* Set the minute of the hour.
*
* @param minute
* The minute of the hour [0..59]
*/
public void setMinute(int minute) {
this.minute = minute;
}
/**
* Get the seconds part of the minute.
*
* @return The seconds part of the minute.
*/
public int getSecond() {
return second;
}
/**
* Set the second of the minute.
*
* @param second
* The second of the minute [0..59]
*/
public void setSecond(int second) {
this.second = second;
}
/**
* Get the milliseconds part of the time.
*
* @return The milliseconds part of the time.
*/
public int getMillis() {
return millis;
}
/**
* Set the milliseconds part of the time.
*
* @param millis
* Milliseconds [0..999].
*/
public void setMillis(int millis) {
this.millis = millis;
}
}

View file

@ -56,6 +56,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Jan 10, 2013 1448 bgonzale Added app context check in runOnSchedule().
* Jan 18, 2013 1469 bkowal Removed the hdf5 data directory.
* Mar 28, 2014 2952 mpduff Changed to use UFStatus for logging.
* Jun 05, 2014 3226 bclement BinLightning refactor
*
* </pre>
*
@ -138,7 +139,7 @@ public class MpeLightningSrv {
float[] latitudes = ltngRec.getLatitudes();
float[] longitudes = ltngRec.getLongitudes();
long[] obstimes = ltngRec.getObsTimes();
byte[] strikes = ltngRec.getStrikeCounts();
byte[] strikes = ltngRec.getPulseCounts();
// convert latitude and longitude to grid coordinate
HRAP hrap = HRAP.getInstance();

View file

@ -58,6 +58,7 @@ import com.vividsolutions.jts.geom.GeometryFactory;
* ------------ ---------- ----------- --------------------------
* 05/07/2009 2037 dhladky Initial Creation.
* Apr 30, 2014 2060 njensen Updates for removal of grid dataURI column
* Jun 05, 2014 3226 bclement compare lightning strike type by id instead of ordinal
*
* </pre>
*
@ -292,7 +293,7 @@ public abstract class ScanProduct implements Serializable {
rec.getIntensities()[i],
rec.getStrikeTypes()[i],
rec.getMsgTypes()[i],
rec.getStrikeCounts()[i]);
rec.getPulseCounts()[i]);
strikeList.add(strike);
}
@ -310,8 +311,8 @@ public abstract class ScanProduct implements Serializable {
if (ls.getIntensity() > 0) {
totalPosStrikes++;
}
if (ls.getStrikeType() == LtgStrikeType.STRIKE_CG
.ordinal()) {
if (ls.getStrikeType() == LtgStrikeType.CLOUD_TO_GROUND
.getId()) {
totalCGStrikes++;
}
totalStrikes++;

View file

@ -3,8 +3,8 @@ package gov.noaa.nws.ncep.viz.rsc.lightning.rsc;
import gov.noaa.nws.ncep.viz.common.ui.NmapCommon;
import gov.noaa.nws.ncep.viz.resources.AbstractNatlCntrsResource;
import gov.noaa.nws.ncep.viz.resources.INatlCntrsResource;
import gov.noaa.nws.ncep.viz.resources.colorBar.ColorBarResourceData;
import gov.noaa.nws.ncep.viz.resources.colorBar.ColorBarResource;
import gov.noaa.nws.ncep.viz.resources.colorBar.ColorBarResourceData;
import gov.noaa.nws.ncep.viz.ui.display.ColorBar;
import gov.noaa.nws.ncep.viz.ui.display.NCMapDescriptor;
@ -18,6 +18,7 @@ import java.util.List;
import com.raytheon.uf.common.dataplugin.HDF5Util;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
import com.raytheon.uf.common.dataplugin.binlightning.LightningConstants;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
import com.raytheon.uf.common.datastorage.DataStoreFactory;
import com.raytheon.uf.common.datastorage.IDataStore;
@ -42,15 +43,14 @@ import com.raytheon.uf.viz.core.drawables.IWireframeShape;
import com.raytheon.uf.viz.core.drawables.PaintProperties;
import com.raytheon.uf.viz.core.drawables.ResourcePair;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.map.MapDescriptor;
import com.raytheon.uf.viz.core.rsc.LoadProperties;
import com.raytheon.uf.viz.core.rsc.ResourceProperties;
import com.raytheon.uf.viz.core.rsc.ResourceType;
/**
* LigntningResource - Display Lightning data.
* *
* LigntningResource - Display Lightning data. *
*
* <pre>
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
@ -65,10 +65,11 @@ import com.raytheon.uf.viz.core.rsc.ResourceType;
* 05/23/12 785 Q. Zhou Added getName for legend.
* 12/19/2012 #960 Greg Hull override propertiesChanged() to update colorBar.
* 05/07/2013 #993 Greg Hull change key for strikeMap from URI to the HDF5 group
*
* Jun 05, 2014 3226 bclement reference datarecords by LightningConstants
*
* </pre>
*
* @author ghull
* @author ghull
* @version 1.0
*/
public class LightningResource extends AbstractNatlCntrsResource<LightningResourceData, NCMapDescriptor>
@ -366,20 +367,17 @@ public class LightningResource extends AbstractNatlCntrsResource<LightningResour
for( int s=0 ; s<hdf5Rec.getSizes()[0] ; s++ ) {
LtngStrikeDataObj strikeInfo = strikeList.get(s);
if( hdf5Rec.getName().equals("intensity") ) {
String name = hdf5Rec.getName();
if (name.equals(LightningConstants.INTENSITY_DATASET)) {
strikeInfo.intensity = ((IntegerDataRecord) hdf5Rec).getIntData()[s];
} else if( hdf5Rec.getName().equals("latitude") ) {
} else if (name.equals(LightningConstants.LAT_DATASET)) {
strikeInfo.lat = ((FloatDataRecord) hdf5Rec).getFloatData()[s];
} else if( hdf5Rec.getName().equals("longitude") ) {
} else if (name.equals(LightningConstants.LON_DATASET)) {
strikeInfo.lon = ((FloatDataRecord) hdf5Rec).getFloatData()[s];
} else if( hdf5Rec.getName().equals("obsTime") ) {
} else if (name.equals(LightningConstants.TIME_DATASET)) {
strikeInfo.strikeTime = ((LongDataRecord) hdf5Rec).getLongData()[s];
// if( strikeInfo.obsTime > latestStrike ) {
// latestStrike = strikeInfo.obsTime;
// }
// } else if( hdf5Rec.getName().equals("strikeCount") ) {
// strikeInfo.lon = ((FloatDataRecord) hdf5Rec).getFloatData()[s];
} else if( hdf5Rec.getName().equals("msgType") ) {
} else if (name
.equals(LightningConstants.MSG_TYPE_DATASET)) {
// ignore
}
}

View file

@ -16,7 +16,6 @@ import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgMsgType;
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.edex.decodertools.core.BasePoint;
/**
* BinLigntningDecoderUtil
@ -38,6 +37,7 @@ import com.raytheon.uf.edex.decodertools.core.BasePoint;
* moved from com.raytheon.edex.plugin.binlightning to gov.noaa.nws.ost.edex.plugin.binlightning
* moved decodeBinLightningData() and decodeBitShiftedBinLightningData()
* to BinLightningDecoder to solve circular dependency
* Jun 05, 2014 3226 bclement LightningStrikePoint refactor
* </pre>
*
* @author Wufeng Zhou
@ -132,20 +132,16 @@ public class BinLightningDecoderUtil {
// int reserved = buffer.getShort() & 0xffff;
// Create the strike record from the report info and base time information.
BasePoint base = new BasePoint(lat, lon);
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(epochTime);
base.setYear(cal.get(Calendar.YEAR));
base.setMonth(cal.get(Calendar.MONTH) + 1);
base.setDay(cal.get(Calendar.DAY_OF_MONTH));
base.setHour(cal.get(Calendar.HOUR_OF_DAY));
base.setMinute(cal.get(Calendar.MINUTE));
base.setSecond(cal.get(Calendar.SECOND));
base.setMillis(cal.get(Calendar.MILLISECOND));
// new spec does not seem to have lightning message type indicator such as FL (Flash Lightning) or RT (Real Time flash lightning)
// The source of lightning data in the vendor specific data bytes (byte 16-17) may related to this (???),
// and it is used here for now. 04/182/013 Wufeng Zhou
/*
* new spec does not seem to have lightning message type indicator
* such as FL (Flash Lightning) or RT (Real Time flash lightning)
* The source of lightning data in the vendor specific data bytes
* (byte 16-17) may related to this (???),
* and it is used here for now. 04/182/013 Wufeng Zhou
*/
/** 05/02/2013, found DSI-9603 Spec (http://www1.ncdc.noaa.gov/pub/data/documentlibrary/tddoc/td9603.pdf) on NLDN lightning data format,
* on Message Type and Stroke Type:
* POS: 37-38 Message Type
@ -165,19 +161,24 @@ public class BinLightningDecoderUtil {
msgType = LtgMsgType.STRIKE_MSG_RT;
}
LightningStrikePoint lsp = new LightningStrikePoint(base, lat, lon, msgType);
LtgStrikeType ltgStrikeType = LtgStrikeType.STRIKE_CG; // default ??
LightningStrikePoint lsp = new LightningStrikePoint(lat, lon, cal,
msgType);
LtgStrikeType ltgStrikeType = LtgStrikeType.CLOUD_TO_GROUND; // default ??
if (strokeType == 0x0000) {
ltgStrikeType = LtgStrikeType.STRIKE_CG;
ltgStrikeType = LtgStrikeType.CLOUD_TO_GROUND;
} else if (strokeType == 0x00ff) {
ltgStrikeType = LtgStrikeType.STRIKE_CC;
ltgStrikeType = LtgStrikeType.CLOUD_TO_CLOUD;
} else if (strokeType == 0xffff) {
ltgStrikeType = LtgStrikeType.STRIKE_TF;
ltgStrikeType = LtgStrikeType.TOTAL_FLASH;
}
lsp.setType(ltgStrikeType);
// as of OB13.3 for World Wide Lightning Location Network (WWLLN) data (decoded by textlightning though, not this bin lightning decoder),
// added lightning source field in LightningStrikePoint, as well as column in binlightning database table defaults to NLDN
/*
* as of OB13.3 for World Wide Lightning Location Network (WWLLN)
* data (decoded by textlightning though, not this bin lightning
* decoder), added lightning source field in LightningStrikePoint,
* as well as column in binlightning database table defaults to NLDN
*/
if (vendor == ((short)0x0001)) { // CONUS source
lsp.setLightSource("NLDN");
} else if (vendor == ((short)0x0002)) { // long range source, i.e., GLD360.
@ -185,7 +186,7 @@ public class BinLightningDecoderUtil {
lsp.setLightSource("GLD");
}
lsp.setStrikeCount(strokeMultiplicity);
lsp.setPulseCount(strokeMultiplicity);
lsp.setStrikeStrength(strokeKiloAmps);
// stroke duration does not seem to be used