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

@ -54,13 +54,14 @@ import com.vividsolutions.jts.geom.Geometry;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 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

@ -63,6 +63,7 @@
<postProcessedModel>
<modelName>ECMWF-HiRes</modelName>
<processorName>ECMWFHiResProcessor</processorName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the MSAS model -->
@ -74,7 +75,8 @@
<!-- Post processor definition for the ETA (NAM80) model -->
<postProcessedModel>
<modelName>ETA</modelName>
<processorName>Nam80PostProcessor</processorName>
<processorName>PrecipAccumPostProcessor</processorName>
<processorName>OverwriteGribPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the RUC236 model -->
@ -92,12 +94,12 @@
<!-- Post processor definitions for the Canadian models -->
<postProcessedModel>
<modelName>Canadian-NH</modelName>
<processorName>CanadianNHPostProcessor</processorName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<postProcessedModel>
<modelName>Canadian-Reg</modelName>
<processorName>CanadianRegPostProcessor</processorName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the LAPS model -->
@ -120,8 +122,8 @@
<!-- Post processor definition for the GFS20 model -->
<postProcessedModel>
<modelName>GFS215|GFS217|GFS20-*</modelName>
<processorName>gov.noaa.nws.crh.edex.grib.decoderpostprocessor.GFS20PostProcessor</processorName>
<modelName>GFS215|GFS217|GFS20-.*</modelName>
<processorName>PrecipAccumPostProcessor</processorName>
</postProcessedModel>
<!-- Post processor definition for the HWRF model -->

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>