Omaha #3756 Add configurable precipitation accumulation grib post processor.

Change-Id: I8cf2a4f3e06f0645fc2348e1a8068f0ef8ce63a8

Former-commit-id: d731f3e21b9c1eac5659ac44de90cfab1013b71b
This commit is contained in:
Nathan Bowler 2015-10-06 13:43:24 -04:00
parent e198c9a4e0
commit d686433642
34 changed files with 1663 additions and 1494 deletions

View file

@ -32,6 +32,7 @@ fi
let "MAX_MEM = GRIB_DECODE_THREADS * 128" # in Meg
let "GRIB_MAX_GRID_POINTS = GRIB_DECODE_THREADS * 25000000"
let "GRID_PERSIST_THREADS = GRIB_DECODE_THREADS / 2"
let "GRID_POSTPROCESS_THREADS = 1"
let "GRID_MAX_PERSIST_MEMORY_IN_MB = GRID_PERSIST_THREADS * 50"
export INIT_MEM=128 # in Meg
@ -39,6 +40,7 @@ export MAX_MEM
export GRIB_DECODE_THREADS
export GRIB_MAX_GRID_POINTS
export GRID_PERSIST_THREADS
export GRID_POSTPROCESS_THREADS
export GRID_MAX_PERSIST_MEMORY_IN_MB
export METADATA_POOL_MAX=10

View file

@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import com.raytheon.edex.plugin.grib.decoderpostprocessors.IDecoderPostProcessor;
import com.raytheon.edex.plugin.grib.decoderpostprocessors.DecoderPostProcessor;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
@ -24,6 +24,7 @@ import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
* Date Ticket# Engineer Description
* ------------- -------- ------------- --------------------------
* Sep 05, 2014 M. Foster Initial creation
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
@ -32,7 +33,7 @@ import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
*
*/
public abstract class OneHrPrecipGridProcessor implements IDecoderPostProcessor {
public abstract class OneHrPrecipGridProcessor extends DecoderPostProcessor {
/** The number of seconds in 1 hour */
protected static final int SECONDS_IN_1_HR = 3600;

View file

@ -0,0 +1,38 @@
#!/bin/bash
# AWIPS2 #3756
#
# Updates the non-base postProcessedModels.xml localization files to replace
# precipitation post-processors that have been removed from the baseline with
# the configurable PrecipAccumPostProcessor.
#
#
for file in `find /awips2/edex/data/utility/edex_static/ -name postProcessedModels.xml`
do
level=`echo $file | cut -f 7 -d '/'`
if [ $level != 'base' ] # base is assumed to be correct as deployed.
then
checkForUpdate=`grep PrecipAccumPostProcessor $file`
if [ "${checkForUpdate}" == "" ]
then
echo "Updating $file"
# create a copy of the file with the changes in a temporary file
newFile="${file}_`date +%s`.dr3756"
cat $file | sed 's/com.raytheon.edex.plugin.grib.decoderpostprocessors.//g' | sed -r 's/Nam80PostProcessor|CanadianNHPostProcessor|CanadianRegPostProcessor|gov.noaa.nws.crh.edex.grib.decoderpostprocessor.GFS20PostProcessor/PrecipAccumPostProcessor/g' | sed 's/<processorName>ECMWFHiResProcessor<\/processorName>/<processorName>ECMWFHiResProcessor<\/processorName>\n <processorName>PrecipAccumPostProcessor<\/processorName>/g' > $newFile
if [ -s $newFile ]
then
chmod --reference=$file $newFile
chown --reference=$file $newFile
mv $newFile $file
else
echo "Failed to update $file"
if [ -e $newFile ]
then
rm $newFile
fi
fi
else
echo "$file has already been updated and will be skipped."
fi
fi
done

View file

@ -25,23 +25,20 @@
<list>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.ARIPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.CPCoutlookGribPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.CanadianNHPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.CanadianRegPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.ECMWFHiResProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.EnsembleGridAssembler</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.FFGGribPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.GFSProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.HPCqpfPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.HWRFPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.LapsPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.LiftedIndexPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.MSASPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.Nam80PostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.OverwriteGribPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.RTMAGribPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.RUC130GribPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.RUC236GribPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.TemperatureCorrectionPostProcessor</value>
<value>com.raytheon.edex.plugin.grib.decoderpostprocessors.precipitation.PrecipAccumPostProcessor</value>
</list>
</property>
</bean>
@ -75,6 +72,7 @@
<endpoint id="gribSplitJmsEndpoint" uri="jms-durable:queue:Ingest.GribSplit?concurrentConsumers=${GRIB_SPLIT_THREADS}"/>
<endpoint id="gribDecodeJmsEndpoint" uri="jms-durable:queue:Ingest.GribDecode?concurrentConsumers=${GRIB_DECODE_THREADS}"/>
<endpoint id="gridPostProcessesJmsEndpoint" uri="jms-durable:queue:Grid.PostProcess?concurrentConsumers=${GRID_POSTPROCESS_THREADS}"/>
<!-- Begin Grib Decode Route -->
<route id="gribSplitIngestRoute">
@ -139,5 +137,25 @@
</split>
</multicast>
</route>
<!--
Does a second round of post processing to generate new records
derived from recently persisted records.
-->
<route id="gridPostProcessRoute">
<from ref="gridPostProcessesJmsEndpoint" />
<doTry>
<pipeline>
<bean ref="serializationUtil" method="transformFromThrift" />
<!-- send for processing -->
<bean ref="gribPostProcessor" method="processPersisted" />
<bean ref="gridPersister" method="persist"/>
</pipeline>
<doCatch>
<exception>java.lang.Throwable</exception>
<to uri="log:grib?level=ERROR"/>
</doCatch>
</doTry>
</route>
</camelContext>
</beans>

View file

@ -34,6 +34,7 @@ import com.raytheon.uf.common.dataplugin.grid.GridRecord;
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Sep 21, 2015 4756 dhladky Initial Creation
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
@ -41,7 +42,7 @@ import com.raytheon.uf.common.dataplugin.grid.GridRecord;
* @version 1
* */
public class ARIPostProcessor implements IDecoderPostProcessor {
public class ARIPostProcessor extends DecoderPostProcessor {
/** name of extraAttribute variable from GribDecoder.py */
private static final String FORECAST_INTERVAL = "forecastInterval";
@ -168,5 +169,4 @@ public class ARIPostProcessor implements IDecoderPostProcessor {
return record;
}
}

View file

@ -49,13 +49,14 @@ import com.raytheon.uf.common.time.DataTime;
* Mar 09, 2011 4243 porricel Initial Creation
* Aug 30, 2013 2298 rjpeter Make getPluginName abstract
* Oct 15, 2013 2473 bsteffen Removed deprecated and unused code.
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
* @author
* @version
*/
public class CPCoutlookGribPostProcessor implements IDecoderPostProcessor {
public class CPCoutlookGribPostProcessor extends DecoderPostProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {

View file

@ -1,183 +0,0 @@
/**
* 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.grib.decoderpostprocessors;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.edex.database.DataAccessLayerException;
import com.raytheon.uf.edex.database.query.DatabaseQuery;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Grib post processor implementation to generate 6-hr precipitation grids from
* run accumulated total precipitation
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Jan 18, 2012 porricel Initial Creation
* Oct 15, 2013 2473 bsteffen Removed unused method argument.
*
* </pre>
*
* @author bphillip
* @version 1
*/
public class CanadianNHPostProcessor extends SixHrPrecipGridProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {
// Post process the data if this is a Total Precipitation grid
if (record.getParameter().getAbbreviation().equals("TPrun")) {
return super.process(record);
}
return new GridRecord[] { record };
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
protected List<GridRecord> getPrecipInventory(Date refTime)
throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, "TPrun");
query.addQueryParam(GridConstants.DATASET_ID, "Canadian-NH");
query.addQueryParam("dataTime.refTime", refTime);
query.addOrder("dataTime.fcstTime", true);
try {
return (List<GridRecord>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for Canadian-NH!", e);
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
protected List<Integer> getPrecip6hrInventory(Date refTime)
throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, "TP6hr");
query.addQueryParam(GridConstants.DATASET_ID, "Canadian-NH");
query.addQueryParam("dataTime.refTime", refTime);
query.addReturnedField("dataTime.fcstTime");
try {
return (List<Integer>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for Canadian-NH!", e);
}
}
/**
* Generates the 6 hour accumulated grid from the run accumulated
* precipitation grids. This function will look in the inventory and
* generate any 6 hr grids that can be generated.
*
* @param record
* The grib record for which to generate the 6 hour accumulated
* precipitation grid
* @return The generated 6-hr precipitation grids
* @throws GribException
*/
protected synchronized GridRecord[] generate6hrPrecipGrids(GridRecord record)
throws GribException {
// The current run accumulated precipitation grid inventory in the
// database
List<GridRecord> precipInventory = getPrecipInventory(record
.getDataTime().getRefTime());
// The current 6-hr precipitation grid inventory in the database
List<Integer> precip6hrInventory = getPrecip6hrInventory(record
.getDataTime().getRefTime());
// Adds the current record to the precip inventory
float[] currentData = (float[]) record.getMessageData();
record.setMessageData(currentData);
precipInventory.add(record);
// Examine each grid in the inventory and generate the 6hr precipitation
// grid if possible
List<GridRecord> generatedRecords = new ArrayList<GridRecord>();
for (int i = 0; i < precipInventory.size(); i++) {
// Check if the 6hr precipitation grid has already been produced
if (!precip6hrInventory.contains(precipInventory.get(i)
.getDataTime().getFcstTime())) {
// If the precipitation grid has not been produced, generate it
List<GridRecord> generated6hrPrecips = generate6hrPrecip(
precipInventory.get(i), precipInventory);
for (GridRecord newRecord : generated6hrPrecips) {
// Add the generated grid to the current inventory
if (newRecord != null) {
precip6hrInventory.add(newRecord.getDataTime()
.getFcstTime());
generatedRecords.add(newRecord);
}
}
}
}
return generatedRecords.toArray(new GridRecord[] {});
}
/**
* Calculates the new data by subtracting the previous inventory data from
* the current data
*
* @param inventoryData
* The data from the previous precipitation record
* @param newData
* The data from the current precipitation record
*/
protected void calculatePrecipValues(float[] inventoryData, float[] newData) {
for (int i = 0; i < inventoryData.length; i++) {
newData[i] = newData[i] - inventoryData[i];
if (newData[i] < 0) {
newData[i] = 0;
}
}
}
}

View file

@ -1,184 +0,0 @@
/**
* 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.grib.decoderpostprocessors;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.edex.database.DataAccessLayerException;
import com.raytheon.uf.edex.database.query.DatabaseQuery;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Grib post processor implementation to generate 3-hr precipitation grids from
* run accumulated total precipitation
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Jan 18, 2012 porricel Initial Creation
* Oct 15, 2013 2473 bsteffen Removed unused method argument.
*
*
* </pre>
*
* @author bphillip
* @version 1
*/
public class CanadianRegPostProcessor extends ThreeHrPrecipGridProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {
// Post process the data if this is a Total Precipitation grid
if (record.getParameter().getAbbreviation().equals("TPrun")) {
return super.process(record);
}
return new GridRecord[] { record };
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
protected List<GridRecord> getPrecipInventory(Date refTime)
throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, "TPrun");
query.addQueryParam(GridConstants.DATASET_ID, "Canadian-Reg");
query.addQueryParam("dataTime.refTime", refTime);
query.addOrder("dataTime.fcstTime", true);
try {
return (List<GridRecord>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for Canadian-Reg!", e);
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
protected List<Integer> getPrecip3hrInventory(Date refTime)
throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, "TP3hr");
query.addQueryParam(GridConstants.DATASET_ID, "Canadian-Reg");
query.addQueryParam("dataTime.refTime", refTime);
query.addReturnedField("dataTime.fcstTime");
try {
return (List<Integer>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for Canadian-Reg!", e);
}
}
/**
* Generates the 3 hour accumulated grid from the run accumulated
* precipitation grids. This function will look in the inventory and
* generate any 3 hr grids that can be generated.
*
* @param record
* The grib record for which to generate the 3 hour accumulated
* precipitation grid
* @return The generated 3-hr precipitation grids
* @throws GribException
*/
protected synchronized GridRecord[] generate3hrPrecipGrids(GridRecord record)
throws GribException {
// The current run accumulated precipitation grid inventory in the
// database
List<GridRecord> precipInventory = getPrecipInventory(record
.getDataTime().getRefTime());
// The current 3-hr precipitation grid inventory in the database
List<Integer> precip3hrInventory = getPrecip3hrInventory(record
.getDataTime().getRefTime());
// Adds the current record to the precip inventory
float[] currentData = (float[]) record.getMessageData();
record.setMessageData(currentData);
precipInventory.add(record);
// Examine each grid in the inventory and generate the 3hr precipitation
// grid if possible
List<GridRecord> generatedRecords = new ArrayList<GridRecord>();
for (int i = 0; i < precipInventory.size(); i++) {
// Check if the 3hr precipitation grid has already been produced
if (!precip3hrInventory.contains(precipInventory.get(i)
.getDataTime().getFcstTime())) {
// If the precipitation grid has not been produced, generate it
List<GridRecord> generated3hrPrecips = generate3hrPrecip(
precipInventory.get(i), precipInventory);
for (GridRecord newRecord : generated3hrPrecips) {
// Add the generated grid to the current inventory
if (newRecord != null) {
precip3hrInventory.add(newRecord.getDataTime()
.getFcstTime());
generatedRecords.add(newRecord);
}
}
}
}
return generatedRecords.toArray(new GridRecord[] {});
}
/**
* Calculates the new data by subtracting the previous inventory data from
* the current data
*
* @param inventoryData
* The data from the previous precipitation record
* @param newData
* The data from the current precipitation record
*/
protected void calculatePrecipValues(float[] inventoryData, float[] newData) {
for (int i = 0; i < inventoryData.length; i++) {
newData[i] = newData[i] - inventoryData[i];
if (newData[i] < 0) {
newData[i] = 0;
}
}
}
}

View file

@ -0,0 +1,114 @@
/**
* 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.grib.decoderpostprocessors;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Grib decoder post processor interface
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 8/30/10 5875 bphillip Initial Creation
* Oct 07, 2015 3756 nabowle Switch interface to abstract class,
* rename from IDecoderPostProcessor, add
* getMessageData(), getType(), and
* relevant enum,
*
* </pre>
*
* @author bphillip
* @version 1
*/
public abstract class DecoderPostProcessor {
/**
* Processes the provided record to see if it needs to be post processed
*
* @param record
* The record to examine to determine if it needs to be post
* processed
* @return The array of grib records including any created during post
* processing
* @throws GribException
*/
public abstract GridRecord[] process(GridRecord record)
throws GribException;
/** Get the type of post processor. Defaults to {@link #PRE_PERSIST}. */
public PostProcessorType getType() {
return PostProcessorType.PRE_PERSIST;
}
/**
* Gets the message data for a record. If the record's messagedata is null,
* the data will be retrieved from the data store, set on the record, and
* returned.
*
* @param record
* The record to get the message data for.
* @return
* @throws GribException
*/
protected float[] getMessageData(GridRecord record) throws GribException {
float[] data = (float[]) record.getMessageData();
if (data == null) {
GridDao dao = null;
try {
dao = new GridDao();
record.setMessageData(((FloatDataRecord) dao.getHDF5Data(
record, -1)[0]).getFloatData());
data = (float[]) record.getMessageData();
} catch (PluginException e) {
throw new GribException("Error populating grib data", e);
}
}
return data;
}
/**
* Defines the types of IDecoderPostProcessors.
*
* It is expected that {@link #POST_PERSIST} processors do not return the
* input record.
*/
public static enum PostProcessorType {
/**
* Processors that process a GridRecord that was just decoded and before
* being persisted.
*/
PRE_PERSIST,
/**
* Processors that process a GridRecord after it was persisted. It is
* expected these processors do not return the input record.
*/
POST_PERSIST
}
}

View file

@ -20,21 +20,11 @@
package com.raytheon.edex.plugin.grib.decoderpostprocessors;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.edex.database.DataAccessLayerException;
import com.raytheon.uf.edex.database.query.DatabaseQuery;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Grib post processor implementation to generate 6-hr precipitation grids from
* run accumulated total precipitation
* Grib post processor implementation to scale TP-ECMWF data to the proper unit.
*
* <pre>
*
@ -44,6 +34,8 @@ import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
* ------------- -------- ----------- --------------------------
* Aug 30, 2010 5875 bphillip Initial Creation
* Oct 15, 2013 2473 bsteffen Removed unused method argument.
* Oct 07, 2015 3756 nabowle Changed to only do data scaling. Extends
* DecoderPostProcessor.
*
*
* </pre>
@ -51,137 +43,17 @@ import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
* @author bphillip
* @version 1
*/
public class ECMWFHiResProcessor extends SixHrPrecipGridProcessor {
public class ECMWFHiResProcessor extends DecoderPostProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {
// Post process the data if this is a Total Precipitation grid
if (record.getParameter().getAbbreviation().equals("TP-ECMWF")) {
return super.process(record);
float[] data = getMessageData(record);
for (int i = 0; i < data.length; i++) {
data[i] = data[i] * 1000;
}
}
return new GridRecord[] { record };
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
protected List<GridRecord> getPrecipInventory(Date refTime)
throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, "TP-ECMWF");
query.addQueryParam(GridConstants.DATASET_ID, "ECMWF-HiRes");
query.addQueryParam("dataTime.refTime", refTime);
query.addOrder("dataTime.fcstTime", true);
try {
return (List<GridRecord>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for ECMWF!", e);
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
protected List<Integer> getPrecip6hrInventory(Date refTime)
throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, "TP6hr");
query.addQueryParam(GridConstants.DATASET_ID, "ECMWF-HiRes");
query.addQueryParam("dataTime.refTime", refTime);
query.addReturnedField("dataTime.fcstTime");
try {
return (List<Integer>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for ECMWF!", e);
}
}
/**
* Generates the 6 hour accumulated grid from the run accumulated
* precipitation grids. This function will look in the inventory and
* generate any 6 hr grids that can be generated.
*
* @param record
* The grib record for which to generate the 6 hour accumulated
* precipitation grid
* @return The generated 6-hr precipitation grids
* @throws GribException
*/
protected synchronized GridRecord[] generate6hrPrecipGrids(GridRecord record)
throws GribException {
// The current run accumulated precipitation grid inventory in the
// database
List<GridRecord> precipInventory = getPrecipInventory(record
.getDataTime().getRefTime());
// The current 6-hr precipitation grid inventory in the database
List<Integer> precip6hrInventory = getPrecip6hrInventory(record
.getDataTime().getRefTime());
// Adds the current record to the precip inventory
float[] currentData = (float[]) record.getMessageData();
for (int i = 0; i < currentData.length; i++) {
currentData[i] = currentData[i] * 1000;
}
record.setMessageData(currentData);
precipInventory.add(record);
// Examine each grid in the inventory and generate the 6hr precipitation
// grid if possible
List<GridRecord> generatedRecords = new ArrayList<GridRecord>();
for (int i = 0; i < precipInventory.size(); i++) {
// Check if the 6hr precipitation grid has already been produced
if (!precip6hrInventory.contains(precipInventory.get(i)
.getDataTime().getFcstTime())) {
// If the precipitation grid has not been produced, generate it
List<GridRecord> generated6hrPrecips = generate6hrPrecip(
precipInventory.get(i), precipInventory);
for (GridRecord newRecord : generated6hrPrecips) {
// Add the generated grid to the current inventory
if (newRecord != null) {
precip6hrInventory.add(newRecord.getDataTime()
.getFcstTime());
generatedRecords.add(newRecord);
}
}
}
}
return generatedRecords.toArray(new GridRecord[] {});
}
/**
* Calculates the new data by subtracting the previous inventory data from
* the current data
*
* @param inventoryData
* The data from the previous precipitation record
* @param newData
* The data from the current precipitation record
*/
protected void calculatePrecipValues(float[] inventoryData, float[] newData) {
for (int i = 0; i < inventoryData.length; i++) {
newData[i] = newData[i] - inventoryData[i];
if (newData[i] < 0) {
newData[i] = 0;
}
}
}
}

View file

@ -70,12 +70,13 @@ import com.raytheon.uf.edex.plugin.grid.PartialGrid;
* Jul 21, 2014 3373 bclement JAXB manager api changes
* Aug 18, 2014 4360 rferrel Set secondaryId in {@link #createAssembledRecord(GridRecord, CompositeModel)}
* Sep 09, 2015 4868 rjpeter Updated to be stored in partial grids as part of normal route.
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
* </pre>
*
* @author bphillip
* @version 1
*/
public class EnsembleGridAssembler implements IDecoderPostProcessor {
public class EnsembleGridAssembler extends DecoderPostProcessor {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(EnsembleGridAssembler.class);
@ -216,7 +217,7 @@ public class EnsembleGridAssembler implements IDecoderPostProcessor {
pGrid.setxOffset((nx * modIndex) - modIndex);
pGrid.setyOffset(0);
assembledRecord.addExtraAttribute(PartialGrid.KEY, pGrid);
assembledRecord.setMessageData(recordToAssemble.getMessageData());
assembledRecord.setMessageData(getMessageData(recordToAssemble));
return checkWorldWrap(assembledRecord);
}
@ -278,5 +279,4 @@ public class EnsembleGridAssembler implements IDecoderPostProcessor {
return Util.resizeDataTo1D(rval, ny, nx);
}
}

View file

@ -43,13 +43,14 @@ import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
* Mar 26, 2013 1821 bsteffen Optimize FFG version query.
* Oct 15, 2013 2473 bsteffen Remove deprecated method calls.
* Apr 25, 2014 2060 njensen Remove dependency on grid dataURI column
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
* @author bphillip
* @version 1
*/
public class FFGGribPostProcessor implements IDecoderPostProcessor {
public class FFGGribPostProcessor extends DecoderPostProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {

View file

@ -1,226 +0,0 @@
/**
* 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.grib.decoderpostprocessors;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.dataquery.db.QueryParam.QueryOperand;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
import com.raytheon.uf.common.parameter.Parameter;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.edex.database.DataAccessLayerException;
import com.raytheon.uf.edex.database.query.DatabaseQuery;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Used to generate 6hr record from 12hr intervals.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Apr 25, 2011 rgeorge Initial creation
* Aug 30, 2013 2298 rjpeter Make getPluginName abstract
* Oct 15, 2013 2473 bsteffen Remove deprecated method calls.
*
* </pre>
*
* @author rgeorge
* @version 1.0
*/
public class GFSProcessor extends SixHrPrecipGridProcessor {
private static final int SECONDS_IN_12_HRS = 43200;
@Override
public GridRecord[] process(GridRecord record) throws GribException {
// Post process the data if this is a Total Precipitation grid
if (record.getParameter().getAbbreviation().equals("TP12hr")
&& ((record.getDataTime().getFcstTime() / 3600) > 180)) {
return super.process(record);
}
return new GridRecord[] { record };
}
/**
* Generates the 6 hour accumulated grid from the run accumulated
* precipitation grids. This function will look in the inventory and
* generate any 6 hr grids that can be generated.
*
* @param record
* The grib record for which to generate the 6 hour accumulated
* precipitation grid
* @return The generated 6-hr precipitation grids
* @throws GribException
*/
@Override
protected synchronized GridRecord[] generate6hrPrecipGrids(GridRecord record)
throws GribException {
List<GridRecord> generated6hrPrecips = new ArrayList<GridRecord>();
// Get all 6hr records 180Hrs and greater
List<GridRecord> precipInventory = getPrecipInventory(record
.getDataTime().getRefTime());
List<GridRecord> generatedRecords = new ArrayList<GridRecord>();
// convert current record to 6hr and add it
GridRecord transformed = transForm12to6(record);
generated6hrPrecips.add(transformed);
precipInventory.add(transformed);
Comparator<GridRecord> comparator = new Comparator<GridRecord>() {
@Override
public int compare(GridRecord o1, GridRecord o2) {
int retValue = 0;
if (o1 != o2) {
retValue = Double.compare(o1.getDataTime().getFcstTime(),
o2.getDataTime().getFcstTime());
}
return retValue;
}
};
Collections.sort(precipInventory, comparator);
// loop through set, find twelve hour gaps and create new 6hr records.
for (int i = 0; i < (precipInventory.size() - 1); i++) {
GridRecord sequence1Record = precipInventory.get(i);
GridRecord sequence2Record = precipInventory.get(i + 1);
if (sequence1Record.getDataTime().getFcstTime() == (sequence2Record
.getDataTime().getFcstTime() - SECONDS_IN_12_HRS)) {
// we have a 12Hr gap
generated6hrPrecips.add(calculate6hrPrecip(sequence1Record,
sequence2Record));
}
}
for (GridRecord newRecord : generated6hrPrecips) {
// Add the generated grid to the current inventory
if (newRecord != null) {
generatedRecords.add(newRecord);
}
}
return generatedRecords.toArray(new GridRecord[] {});
}
@SuppressWarnings("unchecked")
protected List<GridRecord> getPrecipInventory(Date refTime)
throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, "TP6hr",
QueryOperand.IN);
query.addQueryParam(GridConstants.DATASET_ID, "GFS213");
query.addQueryParam("dataTime.refTime", refTime);
query.addQueryParam("dataTime.fcstTime", 648000,
QueryOperand.GREATERTHANEQUALS);
query.addOrder("dataTime.fcstTime", true);
try {
return (List<GridRecord>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for ECMWF!", e);
}
}
private GridRecord transForm12to6(GridRecord currentRecord)
throws GribException {
// Clone the current record and set the ID to 0 so Hibernate will
// recognize it as a new record
GridRecord tp6hrRecord = new GridRecord(currentRecord);
tp6hrRecord.setId(0);
if (currentRecord.getMessageData() == null) {
GridDao dao = null;
try {
dao = new GridDao();
currentRecord.setMessageData(((FloatDataRecord) dao
.getHDF5Data(currentRecord, -1)[0]).getFloatData());
} catch (PluginException e) {
throw new GribException("Error populating grib data!", e);
}
}
// Copy the data to the new record so the data from the original record
// does not get modified
float[] currentData = (float[]) currentRecord.getMessageData();
currentRecord.setMessageData(currentData);
float[] newData = new float[currentData.length];
System.arraycopy(currentData, 0, newData, 0, currentData.length);
tp6hrRecord.setMessageData(newData);
// Assign the new parameter abbreviation and cache it if necessary
Parameter param = new Parameter("TP6hr", "Precip Accum 6 hr",
currentRecord.getParameter().getUnit());
tp6hrRecord.setParameter(param);
tp6hrRecord.getInfo().setId(null);
// Change the data time to include the 6-hr time range
super.modifyDataTime(tp6hrRecord);
return tp6hrRecord;
}
/**
* {@inheritDoc}
*/
@Override
protected void calculatePrecipValues(float[] inventoryData, float[] newData) {
for (int i = 0; i < inventoryData.length; i++) {
newData[i] = (newData[i] + inventoryData[i]) / 2;
if (newData[i] < 0) {
newData[i] = 0;
}
}
}
@Override
protected void modifyDataTime(GridRecord record) {
Calendar refTime = record.getDataTime().getRefTimeAsCalendar();
int fcstTime = record.getDataTime().getFcstTime();
// Calculate the start time by subtracting 6 hours from the reference
// time + forecast time
Calendar startTime = (Calendar) refTime.clone();
startTime.add(Calendar.SECOND, fcstTime - SECONDS_IN_6_HRS);
// Calculate the end time by adding the reference time + forecast time
Calendar endTime = (Calendar) refTime.clone();
endTime.add(Calendar.SECOND, fcstTime);
TimeRange validPeriod = new TimeRange(startTime, endTime);
DataTime newDataTime = new DataTime(refTime, fcstTime
- SECONDS_IN_6_HRS, validPeriod);
// Reset the datauri since the datauri contains the DataTime
record.setDataTime(newDataTime);
record.setDataURI(null);
}
}

View file

@ -24,15 +24,22 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.JAXBException;
import org.apache.camel.Headers;
import com.raytheon.edex.plugin.grib.decoderpostprocessors.DecoderPostProcessor.PostProcessorType;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.edex.plugin.grib.util.GribModelLookup;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.annotations.DataURIUtil;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.dataplugin.message.DataURINotificationMessage;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.localization.exception.LocalizationException;
@ -57,6 +64,8 @@ import com.raytheon.uf.common.status.UFStatus;
* Oct 15, 2013 2473 bsteffen Rewrite deprecated and unused code.
* Sep 24, 2015 3731 nabowle Allow pre-registering shortnames and
* require fully qualified names otherwise.
* Oct 07, 2015 3756 nabowle Add separate post-processing after the
* decoded record is persisted.
*
* </pre>
*
@ -64,6 +73,8 @@ import com.raytheon.uf.common.status.UFStatus;
* @version 1
*/
public class GribPostProcessor {
private static final GridRecord[] EMPTY_ARR = new GridRecord[] {};
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(GribPostProcessor.class);
@ -71,7 +82,7 @@ public class GribPostProcessor {
private static GribPostProcessor instance;
/** The map containing the currently registered grib post processors */
private Map<String, List<IDecoderPostProcessor>> processorMap;
private Map<String, List<DecoderPostProcessor>> processorMap;
private Map<String, String> knownProcessors = new HashMap<>();
@ -110,7 +121,7 @@ public class GribPostProcessor {
}
}
List<IDecoderPostProcessor> processors;
List<DecoderPostProcessor> processors;
GridRecord[] results = null;
List<GridRecord> additionalGrids = null;
for (int i = 0; i < records.length; i++) {
@ -118,9 +129,11 @@ public class GribPostProcessor {
// which post processing is necessary
processors = processorMap.get(records[i].getDatasetId());
if (processors != null) {
for (IDecoderPostProcessor processor : processors) {
for (DecoderPostProcessor processor : processors) {
// Post processing is not necessary, so we continue
if (processor == null) {
if (processor == null
|| PostProcessorType.POST_PERSIST.equals(processor
.getType())) {
continue;
}
@ -147,12 +160,83 @@ public class GribPostProcessor {
for (int i = 0; i < records.length; i++) {
additionalGrids.add(records[i]);
}
return additionalGrids.toArray(new GridRecord[] {});
return additionalGrids.toArray(EMPTY_ARR);
}
}
/**
* Registers the IDecoderPostProcessor classes for the supplied
* Processes the GridRecords to determine if they need post processing
*
* @param notif
* A notification of datauri's that have been persisted.
* @return Only grid records created by the post processors. The records
* matching the uri's will not be returned.
* @throws GribException
*/
public GridRecord[] processPersisted(DataURINotificationMessage notif,
@Headers
Map<String, Object> headers) throws GribException {
headers.put("dequeueTime", System.currentTimeMillis());
String[] dataURIs = notif.getDataURIs();
if (dataURIs == null || dataURIs.length == 0) {
return EMPTY_ARR;
}
synchronized (this) {
if (this.processorMap == null) {
initProcessorMap();
}
}
List<DecoderPostProcessor> processors;
GridRecord[] recordResults;
Set<GridRecord> newGrids = new HashSet<>();
GridRecord record;
for (String uri : dataURIs) {
try {
record = (GridRecord) DataURIUtil.createPluginDataObject(uri);
} catch (PluginException e) {
throw new GribException(
"Could not create plugin data object for " + uri, e);
}
processors = processorMap.get(record.getDatasetId());
if (processors != null) {
for (DecoderPostProcessor processor : processors) {
if (processor == null
|| PostProcessorType.PRE_PERSIST.equals(processor
.getType())) {
continue;
}
recordResults = processor.process(record);
if (recordResults != null) {
for (GridRecord rec : recordResults) {
if (!uri.equals(rec.getDataURI())) {
newGrids.add(rec);
} else {
statusHandler
.warn(uri
+ " will not be re-persisted to prevent an infinite post-processing loop. "
+ processor.getClass()
.getName()
+ " should be of type "
+ PostProcessorType.PRE_PERSIST
.name()
+ " or should not include the post-processed record in the results.");
}
}
}
}
}
}
return newGrids.toArray(EMPTY_ARR);
}
/**
* Registers the DecoderPostProcessor classes for the supplied
* fully-qualified classnames.
*
* @param fqClassNames
@ -160,7 +244,7 @@ public class GribPostProcessor {
*/
public synchronized void register(String... fqClassNames) {
String retClass;
IDecoderPostProcessor newProc;
DecoderPostProcessor newProc;
Object newObj;
for (String className : fqClassNames) {
if (className == null || className.trim().isEmpty()) {
@ -177,22 +261,22 @@ public class GribPostProcessor {
continue;
}
if (!(newObj instanceof IDecoderPostProcessor)) {
if (!(newObj instanceof DecoderPostProcessor)) {
statusHandler.warn(className
+ " is not an IDecoderPostProcessor");
+ " is not an DecoderPostProcessor");
continue;
}
newProc = (IDecoderPostProcessor) newObj;
newProc = (DecoderPostProcessor) newObj;
statusHandler.debug("Registering grib post processor for "
+ className);
retClass = knownProcessors.put(newProc.getClass()
.getSimpleName(), className);
retClass = knownProcessors.put(newProc.getClass().getSimpleName(),
className);
/* Warn if two registered classes share the same simple class name. */
if (retClass != null && !retClass.equals(className)) {
statusHandler.warn(retClass
+ " has been replaced by " + className);
statusHandler.warn(retClass + " has been replaced by "
+ className);
}
}
}
@ -221,7 +305,7 @@ public class GribPostProcessor {
statusHandler.info(String.format("Using postProcessorFile [%s]",
processorFile));
Map<String, List<IDecoderPostProcessor>> newMap = new HashMap<>();
Map<String, List<DecoderPostProcessor>> newMap = new HashMap<>();
/*
* Iterate over post processed models. Determine which models apply
@ -232,10 +316,10 @@ public class GribPostProcessor {
for (PostProcessedModel ppModel : ppModelSet.getModels()) {
for (String modelName : modelNames) {
if (modelName.matches(ppModel.getModelName())) {
List<IDecoderPostProcessor> processorInstances = newMap
List<DecoderPostProcessor> processorInstances = newMap
.get(modelName);
if (processorInstances == null) {
processorInstances = new ArrayList<IDecoderPostProcessor>();
processorInstances = new ArrayList<DecoderPostProcessor>();
newMap.put(modelName, processorInstances);
}
@ -249,7 +333,7 @@ public class GribPostProcessor {
try {
processorInstances
.add((IDecoderPostProcessor) Class
.add((DecoderPostProcessor) Class
.forName(classToLoad)
.newInstance());
} catch (Exception e) {

View file

@ -36,11 +36,12 @@ import com.raytheon.uf.common.dataplugin.grid.GridRecord;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 6/11/2015 4542 bphillip Initial creation
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* @author bphillip
* @version 1.0
*/
public class HPCqpfPostProcessor implements IDecoderPostProcessor {
public class HPCqpfPostProcessor extends DecoderPostProcessor {
/** Parameter abbreviation patter for perecent probability grids */
private static final String PCT_PROB_PATTERN = "ProbTP\\dp\\d{2}in\\d{1,2}hr";
@ -51,7 +52,7 @@ public class HPCqpfPostProcessor implements IDecoderPostProcessor {
// Check to see if this is a grid we are looking for
if (parameterAbbreviation.matches(PCT_PROB_PATTERN)) {
// If so, multiply the data by 100 to obtain a percent
float[] data = (float[]) record.getMessageData();
float[] data = getMessageData(record);
for (int i = 0; i < data.length; i++) {
if (data[i] >= 0.0 && data[i] <= 1.0) {
data[i] *= 100;

View file

@ -53,14 +53,15 @@ import com.vividsolutions.jts.geom.Geometry;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 10, 2015 4819 rferrel Initial Creation
* Sep 10, 2015 4819 rferrel Initial Creation
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
* @author rferrel
* @version 1
*/
public class HWRFPostProcessor implements IDecoderPostProcessor {
public class HWRFPostProcessor extends DecoderPostProcessor {
/**
* Format for datasetId prefix <model>-<dx><spacingUnit>-.

View file

@ -1,55 +0,0 @@
/**
* 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.grib.decoderpostprocessors;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
/**
* Grib decoder post processor interface
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 8/30/10 5875 bphillip Initial Creation
*
* </pre>
*
* @author bphillip
* @version 1
*/
public interface IDecoderPostProcessor {
/**
* Processes the provided record to see if it needs to be post processed
*
* @param record
* The record to examine to determine if it needs to be post
* processed
* @return The array of grib records including any created during post
* processing
* @throws GribException
*/
public GridRecord[] process(GridRecord record) throws GribException;
}

View file

@ -38,13 +38,14 @@ import com.raytheon.uf.common.parameter.Parameter;
* Apr 07, 2011 6619 bphillip Initial creation
* Oct 15, 2013 2473 bsteffen Remove deprecated method calls.
* Sep 09, 2014 3356 njensen Remove CommunicationException
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
* @author bphillip
* @version 1.0
*/
public class LapsPostProcessor implements IDecoderPostProcessor {
public class LapsPostProcessor extends DecoderPostProcessor {
private static final String FHAG = "FHAG";

View file

@ -37,6 +37,7 @@ import com.raytheon.uf.common.parameter.Parameter;
* ------------- -------- ----------- --------------------------
* Aug 18, 2011 bphillip Initial creation
* Oct 15, 2013 2473 bsteffen Remove deprecated method calls.
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
*
* </pre>
@ -45,7 +46,7 @@ import com.raytheon.uf.common.parameter.Parameter;
* @version 1.0
*/
public class MSASPostProcessor implements IDecoderPostProcessor {
public class MSASPostProcessor extends DecoderPostProcessor {
private static final String TSLSA = "TSLSA";

View file

@ -1,215 +0,0 @@
/**
* 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.grib.decoderpostprocessors;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
import com.raytheon.uf.common.parameter.Parameter;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.edex.database.DataAccessLayerException;
import com.raytheon.uf.edex.database.query.DatabaseQuery;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Post processor for the NAM80 (ETA) model. This post processor generates the
* missing 6 hour total and convective precipitation grids.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Nov 17, 2011 bphillip Initial creation
* Aug 30, 2013 2298 rjpeter Make getPluginName abstract
* Oct 15, 2013 2473 bsteffen Remove deprecated method calls.
*
* </pre>
*
* @author bphillip
* @version 1.0
*/
public class Nam80PostProcessor implements IDecoderPostProcessor {
/** The number of seconds in 6 hours */
private static final int SECONDS_IN_6_HRS = 21600;
/** Parameter abbreviation for 12 hr total precipitation accumulation */
private static final String TP_12HR = "TP12hr";
/** Parameter abbreviation for 6 hr total precipitation accumulation */
private static final String TP_6HR = "TP6hr";
/** Parameter abbreviation for 12 hr convective precipitation accumulation */
private static final String CP_12HR = "CP12hr";
/** Parameter abbreviation for 6 hr convective precipitation accumulation */
private static final String CP_6HR = "CP6hr";
/*
* (non-Javadoc)
*
* @see
* com.raytheon.edex.plugin.grib.decoderpostprocessors.IDecoderPostProcessor
* #process(com.raytheon.uf.common.dataplugin.grib.GridRecord)
*/
@Override
public GridRecord[] process(GridRecord record) throws GribException {
/*
* Determine if this record is a 6 or 12 hour total precipitation
* accumulation grid
*/
if (record.getParameter().getAbbreviation().equals(TP_12HR)) {
return generate6HrGrids(record, false, TP_6HR, TP_12HR);
} else if (record.getParameter().getAbbreviation().equals(TP_6HR)) {
return generate6HrGrids(record, true, TP_6HR, TP_12HR);
} else if (record.getParameter().getAbbreviation().equals(CP_12HR)) {
return generate6HrGrids(record, false, CP_6HR, CP_12HR);
} else if (record.getParameter().getAbbreviation().equals(CP_6HR)) {
return generate6HrGrids(record, true, CP_6HR, CP_12HR);
}
return new GridRecord[] { record };
}
@SuppressWarnings("unchecked")
private GridRecord[] generate6HrGrids(GridRecord currentRecord,
boolean sixHr, String parameter6hr, String parameter12hr)
throws GribException {
// The 12 hr accumulation grid to use in the calculations
GridRecord tp12record = null;
// The 6 hr accumulation grid to use in the calculations
GridRecord tp6record = null;
Date refTime = currentRecord.getDataTime().getRefTime();
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating Grib Dao!", e);
}
/*
* If the current record is a 6 hr accumulation grid, get the 12 hr grid
* and vice versa
*/
DatabaseQuery dbQuery = new DatabaseQuery(GridRecord.class);
dbQuery.addQueryParam(GridConstants.DATASET_ID, "ETA");
dbQuery.addQueryParam("dataTime.refTime", refTime);
if (sixHr) {
tp6record = currentRecord;
dbQuery.addQueryParam(GridConstants.PARAMETER_ABBREVIATION,
parameter12hr);
dbQuery.addQueryParam("dataTime.fcstTime", currentRecord
.getDataTime().getFcstTime() + SECONDS_IN_6_HRS);
} else {
tp12record = currentRecord;
dbQuery.addQueryParam(GridConstants.PARAMETER_ABBREVIATION,
parameter6hr);
dbQuery.addQueryParam("dataTime.fcstTime", currentRecord
.getDataTime().getFcstTime() - SECONDS_IN_6_HRS);
}
try {
List<GridRecord> results = (List<GridRecord>) dao
.queryByCriteria(dbQuery);
if (results.isEmpty()) {
return new GridRecord[] { currentRecord };
}
if (sixHr) {
tp12record = results.get(0);
} else {
tp6record = results.get(0);
}
} catch (DataAccessLayerException e) {
throw new GribException("Error querying for 12 hr precip records!",
e);
}
Set<GridRecord> retVal = new HashSet<GridRecord>();
retVal.add(currentRecord);
retVal.add(generateGrid(tp12record, tp6record, dao, parameter6hr));
return retVal.toArray(new GridRecord[] {});
}
private GridRecord generateGrid(GridRecord tp12HrRecord,
GridRecord tp6HrRecord, GridDao dao, String parameter)
throws GribException {
GridRecord newRecord = new GridRecord();
try {
float[] newData = null;
float[] tp6Data = null;
if (tp12HrRecord.getMessageData() == null) {
newData = ((FloatDataRecord) dao.getHDF5Data(tp12HrRecord, -1)[0])
.getFloatData();
} else {
newData = (float[]) tp12HrRecord.getMessageData();
}
if (tp6HrRecord.getMessageData() == null) {
tp6Data = ((FloatDataRecord) dao.getHDF5Data(tp6HrRecord, -1)[0])
.getFloatData();
} else {
tp6Data = (float[]) tp6HrRecord.getMessageData();
}
for (int i = 0; i < newData.length; i++) {
newData[i] -= tp6Data[i];
}
newRecord.setMessageData(newData);
} catch (PluginException e) {
throw new GribException("Error retrieving precipitation data", e);
}
newRecord.setLocation(tp6HrRecord.getLocation());
newRecord.setDatasetId(tp6HrRecord.getDatasetId());
newRecord.setLevel(tp6HrRecord.getLevel());
Parameter param = new Parameter(parameter, tp6HrRecord.getParameter()
.getUnit());
newRecord.setParameter(param);
Calendar refTime = tp12HrRecord.getDataTime().getRefTimeAsCalendar();
Date start = new Date(tp12HrRecord.getDataTime().getValidPeriod()
.getEnd().getTime()
- (SECONDS_IN_6_HRS * 1000));
DataTime newDataTime = new DataTime(refTime, tp12HrRecord.getDataTime()
.getFcstTime(), new TimeRange(start, tp12HrRecord.getDataTime()
.getValidPeriod().getEnd()));
// Reset the datauri since the datauri contains the DataTime
newRecord.setDataTime(newDataTime);
newRecord.getInfo().setId(null);
newRecord.setDataURI(null);
newRecord.setOverwriteAllowed(true);
return newRecord;
}
}

View file

@ -34,18 +34,18 @@ import com.raytheon.uf.common.dataplugin.grid.GridRecord;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 11/12/10 4524 bphillip Initial Creation
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
* @author bphillip
* @version 1
*/
public class OverwriteGribPostProcessor implements IDecoderPostProcessor {
public class OverwriteGribPostProcessor extends DecoderPostProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {
record.setOverwriteAllowed(true);
return new GridRecord[] { record };
}
}

View file

@ -39,6 +39,7 @@ import com.raytheon.uf.common.time.TimeRange;
* ------------- -------- ----------- --------------------------
* Feb 01, 2011 6320 bphillip Initial Creation
* Oct 15, 2013 2473 bsteffen Remove deprecated method calls.
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
*
* </pre>
@ -46,7 +47,7 @@ import com.raytheon.uf.common.time.TimeRange;
* @author bphillip
* @version 1
*/
public class RTMAGribPostProcessor implements IDecoderPostProcessor {
public class RTMAGribPostProcessor extends DecoderPostProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {

View file

@ -34,13 +34,14 @@ import com.raytheon.uf.common.dataplugin.grid.GridRecord;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 9/9/10 #4419 bphillip Initial Creation
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
* @author bphillip
* @version 1
*/
public class RUC130GribPostProcessor implements IDecoderPostProcessor {
public class RUC130GribPostProcessor extends DecoderPostProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {

View file

@ -34,13 +34,13 @@ import com.raytheon.uf.common.dataplugin.grid.GridRecord;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 1/24/2012 DR 14263 M. Porricelli Initial Creation
*
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
* </pre>
*
* @author porricel
* @version 1
*/
public class RUC236GribPostProcessor implements IDecoderPostProcessor {
public class RUC236GribPostProcessor extends DecoderPostProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {

View file

@ -1,214 +0,0 @@
/**
* 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.grib.decoderpostprocessors;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
import com.raytheon.uf.common.parameter.Parameter;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Abstract class to generate 6hr records
*
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Apr 25, 2011 rgeorge Initial creation
* Aug 30, 2013 2298 rjpeter Make getPluginName abstract
* Oct 15, 2013 2473 bsteffen Removed deprecated and unused code.
*
* </pre>
*
* @author rgeorge
* @version 1.0
*/
public abstract class SixHrPrecipGridProcessor implements IDecoderPostProcessor {
/** The number of seconds in 6 hours */
protected static final int SECONDS_IN_6_HRS = 21600;
@Override
public GridRecord[] process(GridRecord record) throws GribException {
// Post process the data if this is a Total Precipitation grid
GridRecord[] newRecords = generate6hrPrecipGrids(record);
GridRecord[] retVal = new GridRecord[newRecords.length + 1];
retVal[0] = record;
for (int i = 1; i < retVal.length; i++) {
retVal[i] = newRecords[i - 1];
}
return retVal;
}
protected abstract GridRecord[] generate6hrPrecipGrids(GridRecord record)
throws GribException;
/**
* Generates the 6hr precipitation grid
*
* @param record
* The current record to clone and modify to produce the new 6hr
* grid
* @param precipInventory
* The current run accumulated grid inventory
* @return The generated 6hr precipitation grid
* @throws GribException
*/
protected List<GridRecord> generate6hrPrecip(GridRecord record,
List<GridRecord> precipInventory)
throws GribException {
List<GridRecord> tp6hrRecords = new ArrayList<GridRecord>();
int currentFcstTime = record.getDataTime().getFcstTime();
// If this is the first grid (the 6 hr grid), the 6hr precip
// accumulation is the same as the 6hr run accumulated grid
if (currentFcstTime == SECONDS_IN_6_HRS) {
tp6hrRecords.add(calculate6hrPrecip(null, record));
}
// If this is not the first grid, generate the new grid using the
// previous grid
else {
for (GridRecord rec : precipInventory) {
if (rec.getDataTime().getFcstTime() == (currentFcstTime - SECONDS_IN_6_HRS)) {
tp6hrRecords.add(calculate6hrPrecip(rec, record));
}
}
}
return tp6hrRecords;
}
/**
* Generates the 6hr precipitation grid from the current grid and the
* previous grid
*
* @param inventoryRecord
* The previous grid from the inventory
* @param currentRecord
* The current grid
* @return The generated 6hr precipitation grid
* @throws GribException
*/
protected GridRecord calculate6hrPrecip(GridRecord inventoryRecord,
GridRecord currentRecord) throws GribException {
// Clone the current record and set the ID to 0 so Hibernate will
// recognize it as a new record
GridRecord tp6hrRecord = new GridRecord(currentRecord);
tp6hrRecord.setId(0);
if (currentRecord.getMessageData() == null) {
GridDao dao = null;
try {
dao = new GridDao();
currentRecord.setMessageData(((FloatDataRecord) dao
.getHDF5Data(currentRecord, -1)[0]).getFloatData());
} catch (PluginException e) {
throw new GribException("Error populating grib data!", e);
}
}
// Copy the data to the new record so the data from the original record
// does not get modified
float[] currentData = (float[]) currentRecord.getMessageData();
currentRecord.setMessageData(currentData);
float[] newData = new float[currentData.length];
System.arraycopy(currentData, 0, newData, 0, currentData.length);
tp6hrRecord.setMessageData(newData);
// Assign the new parameter abbreviation and cache it if necessary
Parameter param = new Parameter("TP6hr", "Precip Accum 6 hr",
currentRecord.getParameter().getUnit());
tp6hrRecord.setParameter(param);
tp6hrRecord.getInfo().setId(null);
// Change the data time to include the 6-hr time range
modifyDataTime(tp6hrRecord);
// Calculate the new data values
if (inventoryRecord != null) {
if (inventoryRecord.getMessageData() == null) {
GridDao dao = null;
try {
dao = new GridDao();
inventoryRecord
.setMessageData(((FloatDataRecord) dao.getHDF5Data(
inventoryRecord, 0)[0]).getFloatData());
} catch (PluginException e) {
throw new GribException("Error populating grib data!", e);
}
}
calculatePrecipValues((float[]) inventoryRecord.getMessageData(),
(float[]) tp6hrRecord.getMessageData());
}
return tp6hrRecord;
}
/**
* Calculates the new data by subtracting the previous inventory data from
* the current data
*
* @param inventoryData
* The data from the previous precipitation record
* @param newData
* The data from the current precipitation record
*/
protected abstract void calculatePrecipValues(float[] messageData,
float[] messageData2);
/**
* Modifies the DataTime of the provided record to include a 6hr time range
*
* @param record
* The record to modify the datatime for
*/
protected void modifyDataTime(GridRecord record) {
Calendar refTime = record.getDataTime().getRefTimeAsCalendar();
int fcstTime = record.getDataTime().getFcstTime();
// Calculate the start time by subtracting 6 hours from the reference
// time + forecast time
Calendar startTime = (Calendar) refTime.clone();
startTime.add(Calendar.SECOND, fcstTime - SECONDS_IN_6_HRS);
// Calculate the end time by adding the reference time + forecast time
Calendar endTime = (Calendar) refTime.clone();
endTime.add(Calendar.SECOND, fcstTime);
TimeRange validPeriod = new TimeRange(startTime, endTime);
DataTime newDataTime = new DataTime(refTime, fcstTime, validPeriod);
// Reset the datauri since the datauri contains the DataTime
record.setDataTime(newDataTime);
record.setDataURI(null);
}
}

View file

@ -61,6 +61,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* ------------- -------- ----------- --------------------------
* Mar 28, 2010 2874 bsteffen Initial creation
* Apr 25, 2014 2060 njensen Use JAXB instead of JAXBManager
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
*
* </pre>
@ -68,8 +69,8 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* @author bsteffen
* @version 1.0
*/
public class TemperatureCorrectionPostProcessor implements
IDecoderPostProcessor, ILocalizationFileObserver {
public class TemperatureCorrectionPostProcessor extends DecoderPostProcessor
implements ILocalizationFileObserver {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(TemperatureCorrectionPostProcessor.class);
@ -208,5 +209,4 @@ public class TemperatureCorrectionPostProcessor implements
}
}
}

View file

@ -34,7 +34,11 @@ import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Abstract class to generate 3hr records
* Abstract class to generate 3hr records.
*
* Note: This class has been replaced by PrecipAccumPostProcessor and only
* remains for
* gov.noaa.nws.crh.edex.grib.decoderpostprocessor.GFS20PostProcessor
*
*
* <pre>
@ -46,14 +50,15 @@ import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
* Jan 24, 2012 14299 M. Porricelli Initial creation
* Aug 30, 2013 2298 rjpeter Make getPluginName abstract
* Oct 15, 2013 2473 bsteffen Removed deprecated and unused code.
* Oct 07, 2015 3756 nabowle Extends DecoderPostProcessor.
*
* </pre>
*
* @author porricel
* @version 1.0
*/
public abstract class ThreeHrPrecipGridProcessor implements
IDecoderPostProcessor {
public abstract class ThreeHrPrecipGridProcessor extends
DecoderPostProcessor {
/** The number of seconds in 3 hours */
protected static final int SECONDS_IN_3_HRS = 10800;

View file

@ -0,0 +1,228 @@
/**
* 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.grib.decoderpostprocessors.precipitation;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
/**
* Stores a list of models and a list of AccumulationCreationConfigs to apply
* for those models.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 28, 2015 3756 nabowle Initial creation
*
* </pre>
*
* @author nabowle
* @version 1.0
*/
@XmlAccessorType(XmlAccessType.NONE)
public class AccumulationConfig {
@XmlElement(name = "model")
private List<String> models;
@XmlElement(name = "create")
private List<AccumulationCreationConfig> creations;
/**
* Constructor
*/
public AccumulationConfig() {
super();
}
/**
* Constructor.
*
* @param models
* The list of models to match.
* @param creations
* The list of accumulations to create.
*/
public AccumulationConfig(List<String> models,
List<AccumulationCreationConfig> creations) {
super();
this.models = models;
this.creations = creations;
}
/**
* @return the models
*/
public List<String> getModels() {
return models;
}
/**
* @param models
* the models to set
*/
public void setModels(List<String> models) {
this.models = models;
}
public boolean addModel(String model) {
if (this.models == null) {
this.models = new ArrayList<>();
}
return this.models.add(model);
}
/**
* @return the creations
*/
public List<AccumulationCreationConfig> getCreations() {
return creations;
}
/**
* @param creations
* the creations to set
*/
public void setCreations(List<AccumulationCreationConfig> creations) {
this.creations = creations;
}
/**
* Convenience method to determine if this configuration matches a given
* model.
*
* @param model
* The model to check for.
* @return True if the model matches one of the configured models, false
* otherwise.
*/
public boolean modelMatches(String model) {
if (this.models == null) {
return false;
}
for (String mod : this.models) {
if (model.matches(mod)) {
return true;
}
}
return false;
}
/**
* Gets the subset of creation configs whose minuend's or subtrahend's
* parameter matches the given parameter, if any.
*
* @param parameter
* The parameter to match.
* @param matchMinuend
* If true, parameter will be matched to the minuends'
* parameters. If false, it will be match to the subtrahends'
* parameters.
* @return the subset of creation configs whose minuend's or subtrahend's
* parameter matches the given parameter, if any. An empty list is
* returned if no matches are found.
*/
public List<AccumulationCreationConfig> getCreations(String parameter,
boolean matchMinuend) {
List<AccumulationCreationConfig> matchedCreations = new ArrayList<>();
if (this.creations != null) {
String param;
for (AccumulationCreationConfig creation : this.creations) {
param = matchMinuend ? creation.getMinuendParam() : creation
.getSubtrahendParam();
if (param.equals(parameter)) {
matchedCreations.add(creation);
}
}
}
return matchedCreations;
}
/**
* Merges the list of creations of this config with the creations of the
* other config. If this config already contains a creation, the duplicate
* will not be added into this config.
*
* @param otherConfig
* The accumulation config that's creations will be merged into
* this config's creations.
*/
public void mergeCreations(AccumulationConfig otherConfig) {
if (otherConfig == null) {
return;
}
if (this.creations == null) {
this.creations = otherConfig.getCreations();
} else if (otherConfig.getCreations() != null) {
boolean dupe;
for (AccumulationCreationConfig toMerge : otherConfig
.getCreations()) {
if (toMerge == null) {
continue;
}
dupe = false;
for (AccumulationCreationConfig local : this.creations) {
if (local.equals(toMerge)) {
dupe = true;
break;
}
}
if (!dupe) {
this.creations.add(toMerge);
}
}
}
}
/**
* Determines if this AccumulationConfig has an equivalent collection of
* models to the other AccumulationConfig. This collections are considered
* equivalent if both are null or empty, or both contain the same models,
* even if in different orders.
*
* This will not handle cases where a model-regex lists models in different
* orders, e.g. {@code <model>GFS215|GFS217</model>} and
* {@code <model>GFS217|GFS215</model>} are not considered equivalent,
* though in practice they are.
*/
public boolean modelsEqual(AccumulationConfig other) {
if (other == null) {
return false;
}
if (other.getModels() == null || other.getModels().isEmpty()) {
return this.models == null || this.getModels().isEmpty();
}
return other.getModels().containsAll(this.getModels())
&& this.getModels().containsAll(other.getModels());
}
}

View file

@ -0,0 +1,134 @@
/**
* 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.grib.decoderpostprocessors.precipitation;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Container for multiple AccumulationConfig instances.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 28, 2015 3756 nabowle Initial creation
*
* </pre>
*
* @author nabowle
* @version 1.0
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class AccumulationConfigs {
@XmlElement(name = "accumulation")
private List<AccumulationConfig> accumulations;
/**
* Constructor.
*/
public AccumulationConfigs() {
super();
}
/**
* Constructor.
*
* @param accums
* The list of accumulations.
*/
public AccumulationConfigs(List<AccumulationConfig> accums) {
this.accumulations = accums;
}
/**
* @return the accumulations
*/
public List<AccumulationConfig> getAccumulations() {
return accumulations;
}
/**
* @param accumulations
* the accumulations to set
*/
public void setAccumulations(List<AccumulationConfig> accumulations) {
this.accumulations = accumulations;
}
/**
* Gets a list of {@link AccumulationConfig}s that match the given model, if
* any. If no matches are found, an empty list is returned.
*
* @param model
* The model to match.
* @return A list containing all matching accumulation configs. If no
* matches are found, and empty list is returned.
*/
public List<AccumulationConfig> getAccumulations(String model) {
List<AccumulationConfig> accums = new ArrayList<>();
for (AccumulationConfig accum : this.accumulations) {
if (accum.modelMatches(model)) {
accums.add(accum);
}
}
return accums;
}
/**
* Merges the AccumulationConfigs with this one. Any configs with equivalent
* model lists will be merged, otherwise the config will be added into the
* list of configs.
*
* @param configs
* The configs to merge. If null, nothing is done.
*/
public void merge(AccumulationConfigs configs) {
if (configs == null) {
return;
}
boolean merged;
for (AccumulationConfig toMerge : configs.getAccumulations()) {
if (toMerge == null) {
continue;
}
merged = false;
for (AccumulationConfig local : this.accumulations) {
if (local.modelsEqual(toMerge)) {
local.mergeCreations(toMerge);
merged = true;
}
}
if (!merged) {
this.accumulations.add(toMerge);
}
}
}
}

View file

@ -0,0 +1,210 @@
/**
* 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.grib.decoderpostprocessors.precipitation;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import com.raytheon.uf.common.time.util.TimeUtil;
/**
* Describes the parameters used in an accumulation calculation.
*
* <pre>
*
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 28, 2015 3756 nabowle Initial creation
*
* </pre>
*
* @author nabowle
* @version 1.0
*/
@XmlAccessorType(XmlAccessType.NONE)
public class AccumulationCreationConfig {
@XmlAttribute(required = true)
private int forecastPeriodHours;
@XmlAttribute(required = true)
private String accumulationParam;
@XmlAttribute(required = true)
private String minuendParam;
@XmlAttribute(required = true)
private String subtrahendParam;
/**
* Constructor.
*/
public AccumulationCreationConfig() {
super();
}
/**
* Constructor.
*
*
* @param forecastPeriod
* The forecast period in hours.
* @param accumulation
* The parameter to use for the calculated accumulation.
* @param minuend
* The parameter subtracted from in calculating accumulation.
* @param subtrahend
* The parameter being subtracted.
*/
public AccumulationCreationConfig(int forecastPeriod, String accumulation,
String minuend, String subtrahend) {
super();
this.forecastPeriodHours = forecastPeriod;
this.accumulationParam = accumulation;
this.minuendParam = minuend;
this.subtrahendParam = subtrahend;
}
/**
* @return the forecastPeriod
*/
public int getForecastPeriodHours() {
return forecastPeriodHours;
}
/**
* @param forecastPeriod
* the forecastPeriod to set
*/
public void setForecastPeriodHours(int forecastPeriod) {
this.forecastPeriodHours = forecastPeriod;
}
/**
* @return the forecastPeriod in seconds.
*/
public int getForecastPeriodSeconds() {
return forecastPeriodHours * TimeUtil.SECONDS_PER_HOUR;
}
/**
* @return the accumulation
*/
public String getAccumulationParam() {
return accumulationParam;
}
/**
* @param accumulation
* the accumulation to set
*/
public void setAccumulationParam(String accumulation) {
this.accumulationParam = accumulation;
}
/**
* @return the minuend
*/
public String getMinuendParam() {
return minuendParam;
}
/**
* @param minuend
* the minuend to set
*/
public void setMinuendParam(String minuend) {
this.minuendParam = minuend;
}
/**
* @return the subtrahend
*/
public String getSubtrahendParam() {
return subtrahendParam;
}
/**
* @param subtrahend
* the subtrahend to set
*/
public void setSubtrahendParam(String subtrahend) {
this.subtrahendParam = subtrahend;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((accumulationParam == null) ? 0 : accumulationParam
.hashCode());
result = prime * result + forecastPeriodHours;
result = prime * result
+ ((minuendParam == null) ? 0 : minuendParam.hashCode());
result = prime * result
+ ((subtrahendParam == null) ? 0 : subtrahendParam.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AccumulationCreationConfig other = (AccumulationCreationConfig) obj;
if (accumulationParam == null) {
if (other.accumulationParam != null) {
return false;
}
} else if (!accumulationParam.equals(other.accumulationParam)) {
return false;
}
if (forecastPeriodHours != other.forecastPeriodHours) {
return false;
}
if (minuendParam == null) {
if (other.minuendParam != null) {
return false;
}
} else if (!minuendParam.equals(other.minuendParam)) {
return false;
}
if (subtrahendParam == null) {
if (other.subtrahendParam != null) {
return false;
}
} else if (!subtrahendParam.equals(other.subtrahendParam)) {
return false;
}
return true;
}
}

View file

@ -0,0 +1,479 @@
/**
* 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.grib.decoderpostprocessors.precipitation;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.JAXBException;
import com.raytheon.edex.plugin.grib.decoderpostprocessors.DecoderPostProcessor;
import com.raytheon.edex.plugin.grib.decoderpostprocessors.GribPostProcessor;
import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.localization.exception.LocalizationException;
import com.raytheon.uf.common.parameter.Parameter;
import com.raytheon.uf.common.parameter.lookup.ParameterLookup;
import com.raytheon.uf.common.serialization.JAXBManager;
import com.raytheon.uf.common.serialization.SerializationException;
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.database.DataAccessLayerException;
import com.raytheon.uf.edex.database.query.DatabaseQuery;
import com.raytheon.uf.edex.plugin.grid.dao.GridDao;
/**
* Configurable grib post processor for accumulating precipitation.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 28, 2015 3756 nabowle Initial creation
*
* </pre>
*
* @author nabowle
* @version 1.0
*/
public class PrecipAccumPostProcessor extends DecoderPostProcessor {
private static final GridRecord[] EMPTY_ARR = new GridRecord[0];
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(GribPostProcessor.class);
/**
* The configured set of Accumulation Configurations. Note: This is not
* thread safe if modified.
*/
private static final AccumulationConfigs configs = initConfigs();
/**
* Constructor.
*
* @throws JAXBException
*/
public PrecipAccumPostProcessor() {
super();
}
@Override
public GridRecord[] process(GridRecord record) throws GribException {
if (configs == null) {
return EMPTY_ARR;
}
return generatePrecipGrids(record);
}
/**
* Generates precipitation grids for a record. If no records can be
* generated, an empty array is returned.
*
* @param record
* The record.
* @return The generated precipitation grids, if any.
* @throws GribException
*/
private GridRecord[] generatePrecipGrids(GridRecord record)
throws GribException {
List<GridRecord> retRecords = new ArrayList<>();
List<AccumulationConfig> accumConfigs = configs.getAccumulations(record
.getDatasetId());
for (AccumulationConfig accumConfig : accumConfigs) {
retRecords.addAll(generatePrecipGrids(record, accumConfig));
}
return retRecords.toArray(EMPTY_ARR);
}
/**
* Generates precipitation grids for a record and an accumulation config. An
* empty collection is returned if no grids were created.
*
* @param record
* The record.
* @param accumConfig
* An accumulation config who's model matches the record's
* dataset id.
* @return The created records, if any.
* @throws GribException
*/
private Collection<GridRecord> generatePrecipGrids(GridRecord record,
AccumulationConfig accumConfig) throws GribException {
List<GridRecord> retRecords = new ArrayList<>();
List<AccumulationCreationConfig> creations = accumConfig.getCreations(
record.getParameter().getAbbreviation(), true);
for (AccumulationCreationConfig creation : creations) {
retRecords.addAll(generatePrecipGrids(record, creation, true));
}
// look for out-of-order creations where this is the subtrahend
creations = accumConfig.getCreations(record.getParameter()
.getAbbreviation(), false);
for (AccumulationCreationConfig creation : creations) {
retRecords.addAll(generatePrecipGrids(record, creation, false));
}
return retRecords;
}
/**
* Generates precipitation grids for a record and accumulation creation
* config. An empty collection is returned if no grids were created.
*
* @param record
* The record.
* @param creation
* The accumulation creation config.
* @param isMinuend
* If true, the record will is used as the minuend. If false, the
* record is used as the subtrahend.
* @return The created records, if any.
* @throws GribException
*/
private Collection<? extends GridRecord> generatePrecipGrids(
GridRecord record, AccumulationCreationConfig creation,
boolean isMinuend) throws GribException {
List<GridRecord> minuendInv = new ArrayList<>();
List<GridRecord> subtrahendInv = new ArrayList<>();
Set<Integer> targetForecastInv = new HashSet<>();
initInventories(record, isMinuend, creation, minuendInv, subtrahendInv,
targetForecastInv);
List<GridRecord> retRecords = new ArrayList<>();
int targetForecast = creation.getForecastPeriodSeconds();
int minFcst;
for (GridRecord minRec : minuendInv) {
minFcst = minRec.getDataTime().getFcstTime();
if (!targetForecastInv.contains(minFcst)) {
targetForecastInv.add(minFcst);
if (isMinuend && minFcst == targetForecast) {
/*
* this record matches the target forecast period. create a
* copy of it with the desired parameter.
*/
retRecords.add(createRecord(creation, minRec, null));
} else {
for (GridRecord subRec : subtrahendInv) {
if (minFcst - subRec.getDataTime().getFcstTime() == targetForecast) {
retRecords.add(createRecord(creation, minRec,
subRec));
}
}
}
}
}
return retRecords;
}
/**
* Initializes minuendInv, subtrahendInv, and targetForecastInv.
*
* @throws GribException
*/
private void initInventories(GridRecord record, boolean isMinuend,
AccumulationCreationConfig create, List<GridRecord> minuendInv,
List<GridRecord> subtrahendInv, Set<Integer> targetForecastInv)
throws GribException {
String datasetId = record.getDatasetId();
Date refTime = record.getDataTime().getRefTime();
if (isMinuend) {
minuendInv.add(record);
subtrahendInv.addAll(getPrecipInventory(refTime,
create.getSubtrahendParam(), datasetId));
} else {
minuendInv.addAll(getPrecipInventory(refTime,
create.getMinuendParam(), datasetId));
subtrahendInv.add(record);
}
targetForecastInv.addAll(getPrecipForecastTimes(refTime,
create.getAccumulationParam(), datasetId));
}
/**
* @param creation
* The accumulation creation config.
* @param minRec
* The minuend record.
* @param subRec
* The subtrahend record. Can be null if the minRec's forecast
* time matches the desired forecast period, skipping the need
* to calculate the precipitation values.
* @return
* @throws GribException
*/
protected GridRecord createRecord(AccumulationCreationConfig creation,
GridRecord minRec, GridRecord subRec) throws GribException {
GridRecord created = createAccumRecord(creation, minRec);
if (subRec != null) {
calculatePrecipValues(subRec, created);
}
return created;
}
/**
* Calculates the accumulation values. In general, this is the difference
* between the created record's value (which is currently a copy from the
* minuend record's value) and the subtrahend record's value, i.e.
* createdValue[i] = minuendValue[i] - subtrahendValue[i], capped to 0 on
* the low end.
*
* @param subRec
* The subtrahend record.
* @param created
* The record that was created. It's expected that it's current
* data is a copy of the minuend record's data.
* @throws GribException
*/
protected void calculatePrecipValues(GridRecord subRec, GridRecord created)
throws GribException {
float[] subData = getMessageData(subRec);
float[] accumData = (float[]) created.getMessageData();
float newVal;
for (int i = 0; i < accumData.length; i++) {
newVal = accumData[i] - subData[i];
accumData[i] = newVal < 0F ? 0F : newVal;
}
}
/**
* Creates the record for the accumulation based on the accumulation
* creation config and base record.
*
* @param creation
* The accumulation creation config.
* @param baseRec
* The record to base the accumulation off of.
* @return
* @throws GribException
*/
protected GridRecord createAccumRecord(AccumulationCreationConfig creation,
GridRecord baseRec) throws GribException {
GridRecord createdRec = new GridRecord(baseRec);
createdRec.setId(0);
createdRec.getInfo().setId(null);
createdRec.setDataURI(null);
float[] data = getMessageData(baseRec);
float[] dataCopy = Arrays.copyOf(data, data.length);
createdRec.setMessageData(dataCopy);
updateParameter(creation, baseRec, createdRec);
updateRefTime(creation, createdRec);
return createdRec;
}
/**
* Updates the created record's datatime.
*
* @param creation
* @param createdRec
*/
private void updateRefTime(AccumulationCreationConfig creation,
GridRecord createdRec) {
Calendar refTime = createdRec.getDataTime().getRefTimeAsCalendar();
int fcstTime = createdRec.getDataTime().getFcstTime();
// Calculate the end time by adding the reference time + forecast time
Calendar endTime = (Calendar) refTime.clone();
endTime.add(Calendar.SECOND, fcstTime);
// Start time is endTime - forecast period
Calendar startTime = (Calendar) refTime.clone();
startTime.add(Calendar.SECOND,
fcstTime - creation.getForecastPeriodSeconds());
TimeRange validPeriod = new TimeRange(startTime, endTime);
DataTime newDataTime = new DataTime(refTime, fcstTime, validPeriod);
createdRec.setDataTime(newDataTime);
}
/**
* Updates the created record's parameter.
*
* @param creation
* @param base
* @param createdRec
*/
private void updateParameter(AccumulationCreationConfig creation,
GridRecord base, GridRecord createdRec) {
Parameter param = ParameterLookup.getInstance().getParameter(
creation.getAccumulationParam());
Parameter createdParam;
if (param == null) {
createdParam = new Parameter(creation.getAccumulationParam(),
"Precipitation Accumulation", base.getParameter().getUnit());
} else {
createdParam = new Parameter(param.getAbbreviation(),
param.getName(), base.getParameter().getUnit());
}
createdRec.setParameter(createdParam);
}
/**
* Retrieves an inventory of GridRecords for the reftime, parameter
* abbreviation, and datasetId
*
* @param refTime
* The reftime.
* @param param
* The parameter abbreviation.
* @param datasetId
* The datasetId.
* @return
* @throws GribException
*/
@SuppressWarnings("unchecked")
private List<GridRecord> getPrecipInventory(Date refTime, String param,
String datasetId) throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao.", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, param);
query.addQueryParam(GridConstants.DATASET_ID, datasetId);
query.addQueryParam("dataTime.refTime", refTime);
query.addOrder("dataTime.fcstTime", true);
try {
return (List<GridRecord>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException("Error getting " + param
+ " inventory for " + datasetId, e);
}
}
/**
* Retrieves an inventory of forecast times for the refTime, parameter
* abbreviation, and datasetId.
*
* @param refTime
* The reftime.
* @param param
* The parameter abbreviation.
* @param datasetId
* The datasetId.
* @return
* @throws GribException
*/
@SuppressWarnings("unchecked")
private List<Integer> getPrecipForecastTimes(Date refTime, String param,
String datasetId) throws GribException {
GridDao dao = null;
try {
dao = new GridDao();
} catch (PluginException e) {
throw new GribException("Error instantiating grib dao!", e);
}
DatabaseQuery query = new DatabaseQuery(GridRecord.class);
query.addQueryParam(GridConstants.PARAMETER_ABBREVIATION, param);
query.addQueryParam(GridConstants.DATASET_ID, datasetId);
query.addQueryParam("dataTime.refTime", refTime);
query.addReturnedField("dataTime.fcstTime");
try {
return (List<Integer>) dao.queryByCriteria(query);
} catch (DataAccessLayerException e) {
throw new GribException("Error getting " + param
+ " forecast inventory for " + datasetId, e);
}
}
/**
* Initializes the configuration.
*/
private static AccumulationConfigs initConfigs() {
AccumulationConfigs retConfigs = null;
IPathManager pathMgr = PathManagerFactory.getPathManager();
LocalizationLevel[] levels = new LocalizationLevel[] {
LocalizationLevel.BASE, LocalizationLevel.REGION,
LocalizationLevel.CONFIGURED, LocalizationLevel.SITE };
LocalizationFile locFile;
Map<LocalizationLevel, LocalizationFile> files = pathMgr
.getTieredLocalizationFile(LocalizationType.EDEX_STATIC,
"/grib/postProcessModels/precipitationAccumulation.xml");
AccumulationConfigs configs = null;
for (LocalizationLevel level : levels) {
locFile = files.get(level);
if (locFile == null) {
continue;
}
try (InputStream is = locFile.openInputStream()) {
JAXBManager manager = new JAXBManager(AccumulationConfigs.class);
configs = (AccumulationConfigs) manager
.unmarshalFromInputStream(is);
} catch (IOException | LocalizationException | JAXBException
| SerializationException e) {
statusHandler
.fatal("Could not initialize the precipitation accumulation config.",
e);
}
if (retConfigs == null) {
retConfigs = configs;
} else {
retConfigs.merge(configs);
}
}
return retConfigs;
}
@Override
public PostProcessorType getType() {
return PostProcessorType.POST_PERSIST;
}
}

View file

@ -0,0 +1,14 @@
<pluginNotificationList>
<pluginNotification>
<endpointName>Grid.PostProcess</endpointName>
<format>DATAURI</format>
<endpointType>QUEUE</endpointType>
<durable>true</durable>
<timeToLive>120000</timeToLive>
<metadataMap>
<mapping key="pluginName">
<constraint constraintValue="grid" constraintType="EQUALS"/>
</mapping>
</metadataMap>
</pluginNotification>
</pluginNotificationList>

View file

@ -1,128 +1,130 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<postProcessedModels>
<!-- Post Processor definitions for models containing grids needing to be
stitched together -->
<postProcessedModel>
<modelName>UKMET[0-9]{2}|ECMF[0-9]|ENSEMBLE[0-9]{2}|AVN[0-9]{2}
</modelName>
<processorName>EnsembleGridAssembler</processorName>
</postProcessedModel>
<!-- Post Processor definitions for models containing grids needing to be
stitched together -->
<postProcessedModel>
<modelName>UKMET[0-9]{2}|ECMF[0-9]|ENSEMBLE[0-9]{2}|AVN[0-9]{2}
</modelName>
<processorName>EnsembleGridAssembler</processorName>
</postProcessedModel>
<!-- Post processor definitions for models which disseminate updated grids
containing identical metadata. This data is primarily from RFCs. The overwrite
post processor is used to prevent updated data from being discarded as duplicates. -->
<postProcessedModel>
<modelName>HPCqpfNDFD</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definitions for models which disseminate updated grids
containing identical metadata. This data is primarily from RFCs. The overwrite
post processor is used to prevent updated data from being discarded as duplicates. -->
<postProcessedModel>
<modelName>HPCqpfNDFD</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>RFCqpf</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>RFCqpf</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>HPCqpf</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>HPCqpf</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>MPE-.*|QPE-.*</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>MPE-.*|QPE-.*</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>URMA25</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>URMA25</modelName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for FFG grids. Similar to the models using
the overwrite post processor, FFG gridded data is also updated without changing
the associated metadata. In this case, the previous updates need to be retained. -->
<postProcessedModel>
<modelName>FFG-[A-Z]{3}</modelName>
<processorName>FFGGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for FFG grids. Similar to the models using
the overwrite post processor, FFG gridded data is also updated without changing
the associated metadata. In this case, the previous updates need to be retained. -->
<postProcessedModel>
<modelName>FFG-[A-Z]{3}</modelName>
<processorName>FFGGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definitions for models using the temperature correction
post processor. These models may have some parameters which are incorrectly
labeled Celsius vs. Kelvin. The list of parameters to correct is in temperatureCorrectionParameters.xml -->
<postProcessedModel>
<modelName>ETA218|GFS212|GFS213|ETA242|RTOFS-.*</modelName>
<processorName>TemperatureCorrectionPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definitions for models using the temperature correction
post processor. These models may have some parameters which are incorrectly
labeled Celsius vs. Kelvin. The list of parameters to correct is in temperatureCorrectionParameters.xml -->
<postProcessedModel>
<modelName>ETA218|GFS212|GFS213|ETA242|RTOFS-.*</modelName>
<processorName>TemperatureCorrectionPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the RTMA model -->
<postProcessedModel>
<modelName>RTMA</modelName>
<processorName>RTMAGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the RTMA model -->
<postProcessedModel>
<modelName>RTMA</modelName>
<processorName>RTMAGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the ECMWF-HiRes model -->
<postProcessedModel>
<modelName>ECMWF-HiRes</modelName>
<processorName>ECMWFHiResProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the ECMWF-HiRes model -->
<postProcessedModel>
<modelName>ECMWF-HiRes</modelName>
<processorName>ECMWFHiResProcessor</processorName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the MSAS model -->
<postProcessedModel>
<modelName>MSAS</modelName>
<processorName>MSASPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the MSAS model -->
<postProcessedModel>
<modelName>MSAS</modelName>
<processorName>MSASPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the ETA (NAM80) model -->
<postProcessedModel>
<modelName>ETA</modelName>
<processorName>Nam80PostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the ETA (NAM80) model -->
<postProcessedModel>
<modelName>ETA</modelName>
<processorName>PrecipAccumPostProcessor</processorName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the RUC236 model -->
<postProcessedModel>
<modelName>RUC236</modelName>
<processorName>RUC236GribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the RUC236 model -->
<postProcessedModel>
<modelName>RUC236</modelName>
<processorName>RUC236GribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the CPCoutlook211 model -->
<postProcessedModel>
<modelName>CPCoutlook211</modelName>
<processorName>CPCoutlookGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the CPCoutlook211 model -->
<postProcessedModel>
<modelName>CPCoutlook211</modelName>
<processorName>CPCoutlookGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definitions for the Canadian models -->
<postProcessedModel>
<modelName>Canadian-NH</modelName>
<processorName>CanadianNHPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definitions for the Canadian models -->
<postProcessedModel>
<modelName>Canadian-NH</modelName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>Canadian-Reg</modelName>
<processorName>CanadianRegPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>Canadian-Reg</modelName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the LAPS model -->
<postProcessedModel>
<modelName>LAPS</modelName>
<processorName>LapsPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the LAPS model -->
<postProcessedModel>
<modelName>LAPS</modelName>
<processorName>LapsPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the RUC130 model -->
<postProcessedModel>
<modelName>RUC130</modelName>
<processorName>RUC130GribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the RUC130 model -->
<postProcessedModel>
<modelName>RUC130</modelName>
<processorName>RUC130GribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for HPCqpfNDFD -->
<postProcessedModel>
<modelName>HPCqpfNDFD</modelName>
<!-- Post processor definition for HPCqpfNDFD -->
<postProcessedModel>
<modelName>HPCqpfNDFD</modelName>
<processorName>HPCqpfPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the GFS20 model -->
<postProcessedModel>
<modelName>GFS215|GFS217|GFS20-*</modelName>
<processorName>gov.noaa.nws.crh.edex.grib.decoderpostprocessor.GFS20PostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the GFS20 model -->
<postProcessedModel>
<modelName>GFS215|GFS217|GFS20-.*</modelName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the HWRF model -->
<!-- This breaks GFE and volume browser. The post processing
@ -137,11 +139,11 @@
</postProcessedModel>
-->
<!-- Post Processor for ARI grids (FFG source for FFMP) -->
<postProcessedModel>
<modelName>ARI</modelName>
<processorName>ARIPostProcessor</processorName>
</postProcessedModel>
<!-- Post Processor for ARI grids (FFG source for FFMP) -->
<postProcessedModel>
<modelName>ARI</modelName>
<processorName>ARIPostProcessor</processorName>
</postProcessedModel>
</postProcessedModels>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accumulationConfigs>
<accumulation>
<model>Canadian-Reg</model>
<create forecastPeriodHours="3" accumulationParam="TP3hr" minuendParam="TPrun" subtrahendParam="TPrun" />
</accumulation>
<accumulation>
<model>Canadian-NH</model>
<create forecastPeriodHours="6" accumulationParam="TP6hr" minuendParam="TPrun" subtrahendParam="TPrun" />
</accumulation>
<accumulation>
<model>ECMWF-HiRes</model>
<create forecastPeriodHours="6" accumulationParam="TP6hr" minuendParam="TP-ECMWF" subtrahendParam="TP-ECMWF" />
</accumulation>
<accumulation>
<model>GFS215|GFS217|GFS20-.*</model>
<create forecastPeriodHours="3" accumulationParam="TP3hr" minuendParam="TP6hr" subtrahendParam="TP3hr" />
</accumulation>
<accumulation>
<model>ETA</model>
<create forecastPeriodHours="6" accumulationParam="TP6hr" minuendParam="TP12hr" subtrahendParam="TP6hr" />
<create forecastPeriodHours="6" accumulationParam="CP6hr" minuendParam="CP12hr" subtrahendParam="CP6hr" />
</accumulation>
<!-- NamNestPostProcessor equivalent. -->
<!--
<accumulation>
<model></model>
<create forecastPeriodHours="1" accumulationParam="TP1hr" minuendParam="TP3hr" subtrahendParam="TP2hr" />
<create forecastPeriodHours="1" accumulationParam="TP1hr" minuendParam="TP2hr" subtrahendParam="TP1hr" />
</accumulation>
-->
</accumulationConfigs>