VLab Issue #4848 - Initial commit of CRH NAM Nest GRIB post-processor; fixes #4848

Change-Id: I75e7a4442b305f73758500da41e2c1943fd7eba1

Former-commit-id: 775fdd9a57 [formerly 01859a86ed] [formerly 775fdd9a57 [formerly 01859a86ed] [formerly 689af6042d [formerly 35b0c0c81b3aeb99330a54a263c0dcfafc14bf6b]]]
Former-commit-id: 689af6042d
Former-commit-id: cf7bca2541 [formerly 732508f606]
Former-commit-id: a0ef5636dd
This commit is contained in:
Matthew Foster 2014-11-14 11:28:29 -06:00
parent fc74bce6b8
commit 89221c8701
6 changed files with 446 additions and 0 deletions

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>gov.noaa.nws.crh.edex.grib.decoderpostprocessor</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,15 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Gribpostprocessor
Bundle-SymbolicName: gov.noaa.nws.crh.edex.grib.decoderpostprocessor
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: CRH
Require-Bundle: com.raytheon.edex.common,
com.raytheon.edex.plugin.grib,
com.raytheon.uf.common.dataplugin,
com.raytheon.uf.common.dataplugin.grid,
com.raytheon.uf.common.parameter,
com.raytheon.uf.edex.plugin.grid,
com.raytheon.uf.common.datastorage,
javax.measure
Bundle-RequiredExecutionEnvironment: JavaSE-1.6

View file

@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.

View file

@ -0,0 +1,208 @@
package gov.noaa.nws.crh.edex.grib.decoderpostprocessor;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
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.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 1-hr precipitation grids from
* the cycling (1-hr, 2-hr, 3-hr, 1-hr, 2-hr, 3-hr, etc.) precip grids in the
* NAM Nest output.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Sep 05, 2014 M. Foster Initial Creation
*
*
* </pre>
*
* @author matthew.foster
* @version 1.0
*/
public class NamNestPostProcessor extends OneHrPrecipGridProcessor {
@Override
public GridRecord[] process(GridRecord record) throws GribException {
// Post process the data if this is a Total Precipitation grid
if (record.getParameter().getAbbreviation().equals("TP2hr") ||
record.getParameter().getAbbreviation().equals("TP3hr")) {
return super.process(record);
}
return new GridRecord[] { record };
}
/**
* Retrieves a grid inventory for the provided datasetid and parameter
*
* @param datasetid
* The datasetid of the model being worked on
* @param parm
* The parameter being retrieved (e.g. TP3hr)
* @param refTime
* The refTime (cycle time) of the model
* @return A List of GridRecord
* @throws GribException
*/
@SuppressWarnings("unchecked")
protected List<GridRecord> getPrecipInventory(String datasetid,
String parm, 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, parm);
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(
String.format("Error getting Precip inventory for %s!",
datasetid), e);
}
}
/**
*
* @param refTime
* The reftime (cycle time) of the model being worked on
* @return List of Integer of the fcstTimes of the current 1hr precip
* inventory
* @throws GribException
*/
@SuppressWarnings("unchecked")
protected HashSet<Integer> getPrecip1hrInventory(String datasetId, 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, "TP1hr");
query.addQueryParam(GridConstants.DATASET_ID, datasetId,
QueryOperand.EQUALS);
query.addQueryParam("dataTime.refTime", refTime);
query.addReturnedField("dataTime.fcstTime");
query.setDistinct(true);
try {
return new HashSet<Integer>((List<Integer>) dao.queryByCriteria(query));
} catch (DataAccessLayerException e) {
throw new GribException(
"Error getting Precip inventory for NAMNest!", e);
}
}
/**
* Generates the 1 hour accumulated grid from the run accumulated
* precipitation grids. This function will look in the inventory and
* generate any 1 hr grids that can be generated.
*
* @param record
* The grib record for which to generate the 1 hour accumulated
* precipitation grid
* @return The generated 1-hr precipitation grids
* @throws GribException
*/
protected synchronized GridRecord[] generate1hrPrecipGrids(GridRecord record)
throws GribException {
List<GridRecord> currInventory;
List<GridRecord> prevInventory;
HashSet<Integer> precip1hrInventory;
if (record.getParameter().getAbbreviation().equals("TP3hr")) {
// Get an inventory of TP3hr grids
currInventory = getPrecipInventory(record.getDatasetId(), "TP3hr",
record.getDataTime().getRefTime());
// Get an inventory of TP2hr grids
prevInventory = getPrecipInventory(record.getDatasetId(), "TP2hr",
record.getDataTime().getRefTime());
// The current 1hr precip inventory
precip1hrInventory = getPrecip1hrInventory(record.getDatasetId(),
record.getDataTime().getRefTime());
} else if (record.getParameter().getAbbreviation().equals("TP2hr")) {
// Get an inventory of TP2hr grids
currInventory = getPrecipInventory(record.getDatasetId(), "TP2hr",
record.getDataTime().getRefTime());
// Get an inventory of TP1hr grids
prevInventory = getPrecipInventory(record.getDatasetId(), "TP1hr",
record.getDataTime().getRefTime());
precip1hrInventory = new HashSet<Integer>();
for (GridRecord rec : prevInventory) {
precip1hrInventory.add(rec.getDataTime().getFcstTime());
}
} else {
throw new GribException("Didn't get TP3hr or TP2hr grid");
}
// Adds the current record to the precip inventory
float[] currentData = (float[]) record.getMessageData();
record.setMessageData(currentData);
currInventory.add(record);
// Examine each grid in the inventory and generate the 1hr precipitation
// grid if possible
List<GridRecord> generatedRecords = new ArrayList<GridRecord>();
for (GridRecord currRecord : currInventory) {
// Check if the 1hr precipitation grid has already been produced
if (! precip1hrInventory.contains(currRecord.getDataTime()
.getFcstTime())) {
List<GridRecord> generated1hrPrecips = generate1hrPrecip(
currRecord, prevInventory);
for (GridRecord newRecord : generated1hrPrecips) {
// Add the generated grid to the current inventory
if (newRecord != null) {
precip1hrInventory.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,184 @@
package gov.noaa.nws.crh.edex.grib.decoderpostprocessor;
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.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 1-hour precip grids
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ------------- --------------------------
* Sep 05, 2014 M. Foster Initial creation
*
* </pre>
*
* @author matthew.foster
* @version 1.0
*
*/
public abstract class OneHrPrecipGridProcessor implements IDecoderPostProcessor {
/** The number of seconds in 1 hour */
protected static final int SECONDS_IN_1_HR = 3600;
public GridRecord[] process(GridRecord record) throws GribException {
// Post process the data if this is a 2hr or 3hr precip accumulation
GridRecord[] newRecords = generate1hrPrecipGrids(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[] generate1hrPrecipGrids(GridRecord record)
throws GribException;
/**
* Generates the 1hr precipitation grid
*
* @param record
* The current record to clone and modify to produce the new 1hr
* grid
* @param precipInventory
* The current run accumulated grid inventory
* @return The generated 1hr precipitation grid
* @throws GribException
*/
protected List<GridRecord> generate1hrPrecip(GridRecord record,
List<GridRecord> precipInventory)
throws GribException {
List<GridRecord> tp1hrRecords = new ArrayList<GridRecord>();
int currentFcstTime = record.getDataTime().getFcstTime();
for (GridRecord rec : precipInventory) {
if (rec.getDataTime().getFcstTime() == (currentFcstTime - SECONDS_IN_1_HR)) {
tp1hrRecords.add(calculate1hrPrecip(rec, record));
}
}
return tp1hrRecords;
}
/**
* Generates the 1hr 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 1hr precipitation grid
* @throws GribException
*/
protected GridRecord calculate1hrPrecip(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 tp1hrRecord = new GridRecord(currentRecord);
tp1hrRecord.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);
tp1hrRecord.setMessageData(newData);
// Assign the new parameter abbreviation and cache it if necessary
Parameter param = new Parameter("TP1hr", "Precip Accum 1 hr",
currentRecord.getParameter().getUnit());
tp1hrRecord.setParameter(param);
tp1hrRecord.getInfo().setId(null);
// Change the data time to include the 1-hr time range
modifyDataTime(tp1hrRecord);
// 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[]) tp1hrRecord.getMessageData());
}
return tp1hrRecord;
}
/**
* 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 1hr 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 1 hour from the reference
// time + forecast time
Calendar startTime = (Calendar) refTime.clone();
startTime.add(Calendar.SECOND, fcstTime - SECONDS_IN_1_HR);
// 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);
}
}