(4);
+ argMap.put("filePath", message.getFileName());
+ argMap.put("startPosition", message.getStartPosition());
+ argMap.put("messageLength", message.getMessageLength());
+ try {
+ PluginDataObject[] pdos = decode(argMap);
+ GridRecord[] records = new GridRecord[pdos.length];
+ for (int i = 0; i < pdos.length; i++) {
+ records[i] = (GridRecord) pdos[i];
+ }
+ return records;
+ } catch (Exception e) {
+ throw new GribException("Failed to decode file: ["
+ + message.getFileName() + "]", e);
+ }
+
+ }
+}
diff --git a/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribDecodeMessage.java b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribDecodeMessage.java
new file mode 100644
index 0000000000..0d4553b552
--- /dev/null
+++ b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribDecodeMessage.java
@@ -0,0 +1,111 @@
+/**
+ * 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;
+
+import java.io.Serializable;
+
+import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
+import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
+
+/**
+ * Message used to describe a portion of the grib file that can be decoded
+ * individually.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Oct 03, 2013 2041 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ * @see GribSplitter
+ */
+@DynamicSerialize
+public class GribDecodeMessage implements Serializable {
+
+ private static final long serialVersionUID = -8088823527599617780L;
+
+ @DynamicSerializeElement
+ private String fileName;
+
+ @DynamicSerializeElement
+ private long startPosition;
+
+ @DynamicSerializeElement
+ private long messageLength;
+
+ @DynamicSerializeElement
+ private byte gribEdition;
+
+ public GribDecodeMessage() {
+
+ }
+
+ public GribDecodeMessage(String str) {
+ String[] parts = str.split("::");
+ startPosition = Long.valueOf(parts[0]);
+ messageLength = Long.valueOf(parts[1]);
+ gribEdition = Byte.valueOf(parts[2]);
+ fileName = parts[3];
+
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public long getStartPosition() {
+ return startPosition;
+ }
+
+ public void setStartPosition(long startPosition) {
+ this.startPosition = startPosition;
+ }
+
+ public long getMessageLength() {
+ return messageLength;
+ }
+
+ public void setMessageLength(long messageLength) {
+ this.messageLength = messageLength;
+ }
+
+ public byte getGribEdition() {
+ return gribEdition;
+ }
+
+ public void setGribEdition(byte gribEdition) {
+ this.gribEdition = gribEdition;
+ }
+
+ public String toString() {
+ return startPosition + "::" + messageLength + "::" + gribEdition + "::"
+ + fileName;
+ }
+}
diff --git a/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribDecoder.java b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribDecoder.java
index 59b58a9d80..8043b0db66 100644
--- a/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribDecoder.java
+++ b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribDecoder.java
@@ -19,40 +19,32 @@
**/
package com.raytheon.edex.plugin.grib;
-import java.io.File;
-import java.io.IOException;
import java.util.Map;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
-import ucar.grib.GribChecker;
-import ucar.unidata.io.RandomAccessFile;
-
import com.raytheon.edex.plugin.grib.exception.GribException;
-import com.raytheon.uf.common.dataplugin.PluginDataObject;
-import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.status.IPerformanceStatusHandler;
-import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.PerformanceStatus;
-import com.raytheon.uf.common.status.UFStatus;
-import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.util.ITimer;
import com.raytheon.uf.common.time.util.TimeUtil;
-import com.raytheon.uf.edex.python.decoder.PythonDecoder;
/**
* Generic decoder for decoding grib files
*
*
* SOFTWARE HISTORY
- * Date Ticket# Engineer Description
- * ------------ ---------- ----------- --------------------------
- * 3/12/10 4758 bphillip Initial creation
- * 02/12/2013 1615 bgonzale public decode method to a Processor exchange method.
- * Mar 19, 2013 1785 bgonzale Added performance status handler and added status
- * to process.
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Mat 12, 2010 4758 bphillip Initial creation
+ * Feb 12, 2013 1615 bgonzale public decode method to a Processor
+ * exchange method.
+ * Mar 19, 2013 1785 bgonzale Added performance status handler and
+ * added status to process.
+ * Oct 07, 2013 2042 bsteffen Decode GribDecodeMessage instead of
+ * files.
*
*
* @author njensen
@@ -60,10 +52,6 @@ import com.raytheon.uf.edex.python.decoder.PythonDecoder;
*/
public class GribDecoder implements Processor {
- private static final transient IUFStatusHandler statusHandler = UFStatus
- .getHandler(GribDecoder.class);
-
- private static final String[] DecoderNames = { "Grib1", "Grib2" };
private final IPerformanceStatusHandler perfLog = PerformanceStatus
.getHandler("");
@@ -72,38 +60,27 @@ public class GribDecoder implements Processor {
* @see org.apache.camel.Processor.process(Exchange)
*/
@Override
- public void process(Exchange exchange) throws Exception {
- final String DATA_TYPE = "dataType";
- final String GRIB = "grib";
-
- File file = (File) exchange.getIn().getBody();
+ public void process(Exchange exchange) throws GribException {
Map headers = exchange.getIn().getHeaders();
+ GribDecodeMessage inMessage = (GribDecodeMessage) exchange.getIn()
+ .getBody();
+ byte gribEdition = inMessage.getGribEdition();
+ exchange.getIn().setHeader("dataType", "grib" + gribEdition);
- RandomAccessFile raf = null;
- int edition = 0;
- GridRecord[] records = null;
- try {
ITimer timer = TimeUtil.getTimer();
- String decoderName;
-
- raf = new RandomAccessFile(file.getAbsolutePath(), "r");
- raf.order(RandomAccessFile.BIG_ENDIAN);
- edition = GribChecker.getEdition(raf);
- exchange.getIn().setHeader(DATA_TYPE, GRIB + edition);
-
+ GridRecord[] records = null;
timer.start();
- switch (edition) {
+ switch (gribEdition) {
case 1:
- decoderName = DecoderNames[0];
- records = new Grib1Decoder().decode(file.getAbsolutePath());
+ records = new Grib1Decoder().decode(inMessage);
break;
case 2:
- decoderName = DecoderNames[1];
- records = decodeGrib2(file);
+ records = new Grib2Decoder().decode(inMessage);
break;
default:
throw new GribException("Unknown grib version detected ["
- + edition + "]");
+ + gribEdition + "] in file: [" + inMessage.getFileName()
+ + "]");
}
String datasetId = (String) headers.get("datasetid");
@@ -122,56 +99,13 @@ public class GribDecoder implements Processor {
record.setEnsembleId(ensembleId);
}
record.setDataURI(null);
- record.constructDataURI();
}
}
timer.stop();
- perfLog.logDuration(decoderName + ": Time to Decode",
+ perfLog.logDuration("Grib" + gribEdition + ": Time to Decode",
timer.getElapsedTime());
- } catch (Exception e) {
- statusHandler.handle(Priority.ERROR, "Failed to decode file: ["
- + file.getAbsolutePath() + "]", e);
- records = new GridRecord[0];
- } finally {
- try {
- if (raf != null) {
- raf.close();
- }
- } catch (IOException e) {
- statusHandler.handle(Priority.ERROR,
- "Unable to close RandomAccessFile!", e);
- }
- }
- exchange.getIn().setBody(records);
+ exchange.getIn().setBody(records);
+
}
- /**
- * Decode a grib 2 file.
- *
- * @param file
- * Grib 2 file
- * @return Array of GribRecords parsed from the file.
- * @throws PluginException
- */
- private GridRecord[] decodeGrib2(File file)
- throws PluginException {
- GridRecord[] records = null;
- PythonDecoder pythonDecoder = new PythonDecoder();
-
- pythonDecoder.setPluginName("grib");
- pythonDecoder.setPluginFQN("com.raytheon.edex.plugin.grib");
- pythonDecoder.setModuleName("GribDecoder");
- pythonDecoder.setRecordClassname(GridRecord.class.toString());
- pythonDecoder.setCache(true);
- try {
- PluginDataObject[] pdos = pythonDecoder.decode(file);
- records = new GridRecord[pdos.length];
- for (int i = 0; i < pdos.length; i++) {
- records[i] = (GridRecord) pdos[i];
- }
- } catch (Exception e) {
- throw new GribException("Error decoding grib file!", e);
- }
- return records;
- }
}
diff --git a/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribLargeFileChecker.java b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribLargeFileChecker.java
index 6ce9abf59a..9c92747674 100644
--- a/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribLargeFileChecker.java
+++ b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribLargeFileChecker.java
@@ -56,10 +56,12 @@ import com.raytheon.uf.edex.database.cluster.ClusterTask;
*
* SOFTWARE HISTORY
*
- * Date Ticket# Engineer Description
- * ------------ ---------- ----------- --------------------------
- * Oct 15, 2010 6644 bphillip Initial Creation
- * Jul 18, 2013 2194 bsteffen Fix site override.
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Oct 15, 2010 6644 bphillip Initial Creation
+ * Jul 18, 2013 2194 bsteffen Fix site override.
+ * Oct 07, 2013 2042 bsteffen Decode GribDecodeMessage instead of
+ * files.
*
*
*
@@ -111,7 +113,9 @@ public class GribLargeFileChecker implements Processor {
if (basePatterns == null) {
loadPatterns();
}
- File gribFile = (File) exchange.getIn().getBody();
+ GribDecodeMessage message = (GribDecodeMessage) exchange.getIn()
+ .getBody();
+ File gribFile = new File(message.getFileName());
String header = (String) exchange.getIn().getHeader("header");
if (header == null) {
// No header entry so will try and use the filename instead
@@ -157,6 +161,8 @@ public class GribLargeFileChecker implements Processor {
} else {
exchange.getIn().setHeader(LARGE_FILE_HEADER, false);
}
+ exchange.getIn().setHeader("dequeueTime", System.currentTimeMillis());
+
}
/**
diff --git a/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribSplitter.java b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribSplitter.java
index fde36580e2..8368fe53b1 100644
--- a/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribSplitter.java
+++ b/edexOsgi/com.raytheon.edex.plugin.grib/src/com/raytheon/edex/plugin/grib/GribSplitter.java
@@ -20,204 +20,83 @@
package com.raytheon.edex.plugin.grib;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.regex.Pattern;
-import ucar.grib.GribChecker;
-import ucar.grib.grib1.Grib1Input;
-import ucar.grib.grib1.Grib1Record;
import ucar.grib.grib2.Grib2IndicatorSection;
-import ucar.grib.grib2.Grib2Input;
-import ucar.grib.grib2.Grib2Record;
+import ucar.unidata.io.KMPMatch;
import ucar.unidata.io.RandomAccessFile;
-import com.raytheon.edex.esb.Headers;
+import com.raytheon.edex.plugin.grib.exception.GribException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
-import com.raytheon.uf.edex.core.EdexException;
/**
- * TODO Add Description
+ *
+ * Split a single grib file into one or more {@link GribDecodeMessage}.
*
*
*
* SOFTWARE HISTORY
*
- * Date Ticket# Engineer Description
- * ------------ ---------- ----------- --------------------------
- * Mar 7, 2012 bsteffen Initial creation
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Oct 07, 2013 2402 bsteffen Rewritten to output GribDecodeMessage.
*
*
*
* @author bsteffen
- * @version 1.0
+ * @version 2.0
*/
-
public class GribSplitter {
+
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(GribSplitter.class);
- private static final long TEN_MEGABYTES = 10485760;
+ private static final KMPMatch matcher = new KMPMatch("GRIB".getBytes());
- private static final String suffixFormat = "%s_record_%d";
-
- private static final Pattern suffixPattern = Pattern
- .compile(".*_record_\\d+$");
-
- private final File tmpFileDirectory;
-
- public GribSplitter(String tmpFileLocation) {
- this.tmpFileDirectory = new File(tmpFileLocation);
- if (!tmpFileDirectory.exists()) {
- tmpFileDirectory.mkdirs();
- }
- }
-
- public void clean(Headers headers) {
- String ingestFileName = (String) headers.get("ingestfilename");
- File file = new File(ingestFileName);
- if (tmpFileDirectory.equals(file.getParentFile())
- && suffixPattern.matcher(file.getName()).find()) {
- file.delete();
- }
- }
-
- public List split(String fileName) {
- File file = new File(fileName);
- if (file.length() > TEN_MEGABYTES) {
- RandomAccessFile raf = null;
+ public List split(File file) throws GribException {
+ List messages = new ArrayList();
+ RandomAccessFile raf = null;
+ try {
+ raf = new RandomAccessFile(file.getAbsolutePath(), "r", 1024);
+ raf.order(RandomAccessFile.BIG_ENDIAN);
+ while (raf.searchForward(matcher, Integer.MAX_VALUE)) {
+ GribDecodeMessage message = new GribDecodeMessage();
+ message.setFileName(file.getAbsolutePath());
+ long startPosition = raf.getFilePointer();
+ message.setStartPosition(startPosition);
+ raf.skipBytes(4);
+ Grib2IndicatorSection is = new Grib2IndicatorSection(raf);
+ message.setGribEdition((byte) is.getGribEdition());
+ long length = is.getGribLength();
+ message.setMessageLength(length);
+ messages.add(message);
+ raf.seek(startPosition + length);
+ /*
+ * A significant amount of files contain one grib record with
+ * several bytes of gibberish on the end. This prevents us from
+ * reading the gibberish if it is too small to be a grib record
+ * anyway.
+ */
+ if (raf.length() - raf.getFilePointer() < 24) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ throw new GribException("Unable to split file: "
+ + file.getAbsolutePath(), e);
+ } finally {
try {
- raf = new RandomAccessFile(file.getAbsolutePath(), "r");
- raf.order(RandomAccessFile.BIG_ENDIAN);
- int edition = GribChecker.getEdition(raf);
- raf.seek(0);
- List recordLengths = new ArrayList();
- if (edition == 1) {
- Grib1Input g1i = new Grib1Input(raf);
- g1i.scan(false, false);
- List gribRecords = g1i.getRecords();
- for (int i = 0; i < gribRecords.size(); i++) {
- recordLengths.add(gribRecords.get(i).getIs()
- .getGribLength());
- }
- } else if (edition == 2) {
- Grib2Input g2i = new Grib2Input(raf);
-
- g2i.scan(false, false);
- List gribRecords = g2i.getRecords();
-
- Grib2IndicatorSection lastIs = null;
- for (int i = 0; i < gribRecords.size(); i++) {
- // 2 records with the same indicator section cannot be
- // split, this occurs with uW and vW that are encoded
- // together.
- Grib2IndicatorSection is = gribRecords.get(i).getIs();
- if (lastIs != is) {
- lastIs = is;
- recordLengths.add(is.getGribLength());
- }
- }
- // If there was more than one grib record in this file, we
- // split the file up into individual records and send them
- // back through the manual ingest endpoint
- if (recordLengths.size() > 1) {
- raf.seek(0);
- return splitFile(file.getName(), raf, recordLengths);
- }
- }
- } catch (Exception e) {
- statusHandler.handle(Priority.ERROR,
- "Error splitting grib file", e);
- } finally {
- try {
- if (raf != null) {
- raf.close();
- }
- } catch (IOException e) {
- statusHandler.handle(Priority.ERROR,
- "Unable to close RandomAccessFile!", e);
- }
+ raf.close();
+ } catch (Throwable e) {
+ statusHandler.handle(Priority.DEBUG, "Cannot close grib file: "
+ + file.getAbsolutePath(), e);
}
}
- return Arrays.asList(file.getAbsolutePath());
+ return messages;
}
- /**
- * Splits a collective file into individual records.
- *
- * @param fileName
- * The name of the file being split
- * @param raf
- * The Random Access File object
- * @param sizes
- * The sizes of the individual records inside the collection
- * @throws IOException
- * @throws EdexException
- */
- private List splitFile(String fileName, RandomAccessFile raf,
- List sizes) throws IOException, EdexException {
- FileOutputStream out = null;
- byte[] transfer = null;
- List result = new ArrayList(sizes.size());
- for (int i = 0; i < sizes.size(); i++) {
- transfer = new byte[(int) sizes.get(i).longValue()];
- raf.seek(seekRecordStart(raf, raf.length()));
- raf.read(transfer);
-
- try {
-
- File tmpFile = new File(tmpFileDirectory, String.format(
- suffixFormat, fileName, i));
- out = new FileOutputStream(tmpFile);
- out.write(transfer);
- out.close();
- result.add(tmpFile.getPath());
- } finally {
- if (out != null) {
- out.close();
- }
- }
- }
- return result;
- }
-
- /**
- * Moves the filepointer on the random access file to the beginning of the
- * next grib record in the file
- *
- * @param raf
- * The random access file
- * @param fileLength
- * The total length of the file
- * @return The index to the next grib record in the collection. -1 is
- * returned if there are no more records in the file
- * @throws IOException
- */
- private long seekRecordStart(RandomAccessFile raf, long fileLength)
- throws IOException {
- int matches = 0;
- while (raf.getFilePointer() < fileLength) {
- char c = (char) raf.readByte();
- if (c == 'G') {
- matches = 1;
- } else if ((c == 'R') && (matches == 1)) {
- matches = 2;
- } else if ((c == 'I') && (matches == 2)) {
- matches = 3;
- } else if ((c == 'B') && (matches == 3)) {
- matches = 4;
- // Subtract 4 because we want the absolute beginning of the grib
- // file
- return raf.getFilePointer() - 4;
- } else {
- matches = 0;
- }
- }
- return -1;
- }
}
diff --git a/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_getfld.c b/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_getfld.c
index baf54663e3..aeb88c784d 100755
--- a/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_getfld.c
+++ b/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_getfld.c
@@ -395,6 +395,7 @@ g2int g2_getfld(unsigned char *cgrib,g2int ifldnum,g2int unpack,g2int expand,
lgfld->numoct_opt=igds[2];
lgfld->interp_opt=igds[3];
lgfld->igdtnum=igds[4];
+ free(igds);
}
else {
ierr=10;
diff --git a/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_unpack3.c b/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_unpack3.c
index 44ba01069c..5d5cbf8eef 100755
--- a/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_unpack3.c
+++ b/nativeLib/ncep_grib2module/dependencies/src/g2clib-1.1.8/g2_unpack3.c
@@ -212,6 +212,5 @@ g2int g2_unpack3(unsigned char *cgrib,g2int *iofst,g2int **igds,g2int **igdstmpl
*idefnum=0;
*ideflist=0; // NULL
}
- free(ligds);
return(ierr); // End of Section 3 processing
}
diff --git a/nativeLib/ncep_grib2module/src/grib2module.c b/nativeLib/ncep_grib2module/src/grib2module.c
index c61246e5c4..72eb830f1e 100644
--- a/nativeLib/ncep_grib2module/src/grib2module.c
+++ b/nativeLib/ncep_grib2module/src/grib2module.c
@@ -19,22 +19,28 @@
******************************************************************************************/
/*
- * Thin wrapper around the NCEP decoder. This implementation pulls the raw values from the file
- * to be processed by the python
+ * Thin wrapper around the NCEP decoder. Provides a single decode method that
+ * can be used to extract all of the data from a grib message. The return value
+ * is a list of dict with one list entry for each field in the grib
+ * file(usually 1). Each dict contains keys for each field in the gribfield
+ * struct. Detailed documentation for this structure can be found in the file
+ * dependencies/src/g2clib-1.1.8/grib2c.doc. All g2int fields are converted to
+ * python integer types and all data pointers are converted to numpy arrays of
+ * the appropriate type.
*
*
*
* SOFTWARE HISTORY
*
- * Date Ticket# Engineer Description
- * ------------ ---------- ----------- --------------------------
- * 4/7/09 1994 bphillip Initial Creation
- * Mar 25, 2013 1821 bsteffen Make grib2 decoding more multithreaded
+ * Date Ticket# Engineer Description
+ * ------------- -------- ----------- --------------------------
+ * Oct 07, 2013 2402 bsteffen Rewritten to work on file extents and
+ * more closely mirror C api
*
*
*
- * @author bphillip
- * @version 1
+ * @author bsteffen
+ * @version 2
*/
#include
@@ -46,400 +52,256 @@
static PyObject *Grib2FileError;
-int getRecord(FILE * fptr, gribfield ** gfld, int recordNumber,
- g2int fieldNumber, g2int unpack) {
+/////////////////////////////////////////////////////////////////////////
+// Helper method to add a g2int to a PyDict object.
+//
+// INPUT ARGUMENTS:
+// dp - PyDict object to be added too.
+// key - Key to put item into the dict.
+// item - the g2int item to place in the dict.
+//
+/////////////////////////////////////////////////////////////////////////
+static void PyDict_SetIntItemString(PyObject *dp, const char *key, g2int item) {
+ PyObject* pyitem = PyInt_FromLong(item);
+ PyDict_SetItemString(dp, key, pyitem);
+ Py_DECREF(pyitem);
+}
- unsigned char *cgrib;
+/////////////////////////////////////////////////////////////////////////
+// Translates a gribfield into a PyDict.
+//
+// INPUT ARGUMENTS:
+// gfld - A single decoded gribfield.
+//
+// RETURN VALUE: A PyDict containing all fields from gfld, the caller is
+// responsible for decrementing the ref count of the returned
+// object.
+//
+/////////////////////////////////////////////////////////////////////////
+static PyObject* translateField(gribfield *gfld) {
+ PyObject* result;
+ PyObject* section;
+ npy_intp sectionSize[1];
+
+ result = PyDict_New();
+
+ /* version */
+ PyDict_SetIntItemString(result, "version", gfld->version);
+ /* discipline */
+ PyDict_SetIntItemString(result, "discipline", gfld->discipline);
+
+ /* idsect */
+ sectionSize[0] = gfld->idsectlen;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_INT);
+ memcpy(((PyArrayObject *) section)->data, gfld->idsect,
+ gfld->idsectlen * sizeof(g2int));
+ PyDict_SetItemString(result, "idsect", section);
+ Py_DECREF(section);
+ /* idsectlen */
+ PyDict_SetIntItemString(result, "idsectlen", gfld->idsectlen);
+
+ /* local */
+ sectionSize[0] = gfld->locallen;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_UBYTE);
+ memcpy(((PyArrayObject *) section)->data, gfld->local,
+ gfld->locallen * sizeof(unsigned char));
+ PyDict_SetItemString(result, "local", section);
+ Py_DECREF(section);
+ /* locallen */
+ PyDict_SetIntItemString(result, "locallen", gfld->locallen);
+
+ /* ifldnum */
+ PyDict_SetIntItemString(result, "ifldnum", gfld->ifldnum);
+ /* griddef */
+ PyDict_SetIntItemString(result, "griddef", gfld->griddef);
+ /* ngrdpts */
+ PyDict_SetIntItemString(result, "ngrdpts", gfld->ngrdpts);
+
+ /* numoct_opt */
+ PyDict_SetIntItemString(result, "numoct_opt", gfld->numoct_opt);
+ /* interp_opt */
+ PyDict_SetIntItemString(result, "interp_opt", gfld->interp_opt);
+ /* num_opt */
+ PyDict_SetIntItemString(result, "num_opt", gfld->num_opt);
+ /* interp_opt */
+ PyDict_SetIntItemString(result, "interp_opt", gfld->interp_opt);
+ /* list_opt */
+ sectionSize[0] = gfld->num_opt;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_INT);
+ memcpy(((PyArrayObject *) section)->data, gfld->list_opt,
+ gfld->num_opt * sizeof(g2int));
+ PyDict_SetItemString(result, "list_opt", section);
+ Py_DECREF(section);
+
+ /* igdtnum */
+ PyDict_SetIntItemString(result, "igdtnum", gfld->igdtnum);
+ /* igdtlen */
+ PyDict_SetIntItemString(result, "igdtlen", gfld->igdtlen);
+ /* igdtmpl */
+ sectionSize[0] = gfld->igdtlen;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_INT);
+ memcpy(((PyArrayObject *) section)->data, gfld->igdtmpl,
+ gfld->igdtlen * sizeof(g2int));
+ PyDict_SetItemString(result, "igdtmpl", section);
+ Py_DECREF(section);
+
+ /* ipdtnum */
+ PyDict_SetIntItemString(result, "ipdtnum", gfld->ipdtnum);
+ /* ipdtlen */
+ PyDict_SetIntItemString(result, "ipdtlen", gfld->ipdtlen);
+ /* ipdtmpl */
+ sectionSize[0] = gfld->ipdtlen;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_INT);
+ memcpy(((PyArrayObject *) section)->data, gfld->ipdtmpl,
+ gfld->ipdtlen * sizeof(g2int));
+ PyDict_SetItemString(result, "ipdtmpl", section);
+ Py_DECREF(section);
+
+ /* num_coord */
+ PyDict_SetIntItemString(result, "num_coord", gfld->num_coord);
+ /* coord_list */
+ sectionSize[0] = gfld->num_coord;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_FLOAT);
+ memcpy(((PyArrayObject *) section)->data, gfld->coord_list,
+ gfld->num_coord * sizeof(g2float));
+ PyDict_SetItemString(result, "coord_list", section);
+ Py_DECREF(section);
+
+ /* ndpts */
+ PyDict_SetIntItemString(result, "ndpts", gfld->ndpts);
+ /* idrtnum */
+ PyDict_SetIntItemString(result, "idrtnum", gfld->idrtnum);
+ /* idrtlen */
+ PyDict_SetIntItemString(result, "idrtlen", gfld->idrtlen);
+ /* idrtmpl */
+ sectionSize[0] = gfld->idrtlen;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_INT);
+ memcpy(((PyArrayObject *) section)->data, gfld->idrtmpl,
+ gfld->idrtlen * sizeof(g2int));
+ PyDict_SetItemString(result, "idrtmpl", section);
+ Py_DECREF(section);
+
+ /* unpacked */
+ PyDict_SetIntItemString(result, "unpacked", gfld->unpacked);
+ /* expanded */
+ PyDict_SetIntItemString(result, "expanded", gfld->expanded);
+
+ /* ibmap */
+ PyDict_SetIntItemString(result, "ibmap", gfld->ibmap);
+ /* bmap */
+ if (gfld->ibmap == 0 || gfld->ibmap == 254) {
+ sectionSize[0] = gfld->ngrdpts;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_INT);
+ memcpy(((PyArrayObject *) section)->data, gfld->bmap,
+ gfld->ngrdpts * sizeof(g2int));
+ PyDict_SetItemString(result, "bmap", section);
+ Py_DECREF(section);
+ }
+
+ /* fld */
+ sectionSize[0] = gfld->ngrdpts;
+ section = PyArray_SimpleNew(1, sectionSize, NPY_FLOAT);
+ memcpy(((PyArrayObject *) section)->data, gfld->fld,
+ gfld->ngrdpts * sizeof(g2float));
+ PyDict_SetItemString(result, "fld", section);
+ Py_DECREF(section);
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////
+// Extracts the data from a grib record already in memory.
+//
+// INPUT ARGUMENTS:
+// rawData - An array of raw bytes from a grib file.
+//
+// RETURN VALUE: A PyList of PyDicts, one PyDict for each field in the grib
+// message. The caller is responsible for decrementing the ref
+// count of the returned object.
+//
+/////////////////////////////////////////////////////////////////////////
+static PyObject* decodeData(unsigned char* rawData) {
+ PyObject* result = NULL;
g2int listsec0[3], listsec1[13];
- g2int iseek = 0;
- g2int lskip;
- g2int lgrib = 1;
g2int numfields;
g2int numlocal;
- g2int ierr, expand = 1;
- int ret = 1;
- size_t lengrib;
-
- // Seek to the correct position in the file
- int i = 0;
- for (i = 0; i <= recordNumber; i++) {
- seekgb(fptr, iseek, 32000, &lskip, &lgrib);
- iseek = lskip + lgrib;
- }
-
- // No more data
- if (lgrib == 0) {
- return -1;
- }
-
- // Pull out the data
- cgrib = (unsigned char *) malloc(lgrib);
- if (cgrib == NULL) {
- printf("getRecord: failed to malloc cgrib\n");
- return -1;
- }
- ret = fseek(fptr, lskip, SEEK_SET);
- lengrib = fread(cgrib, sizeof(unsigned char), lgrib, fptr);
- iseek = lskip + lgrib;
- ierr = g2_info(cgrib, listsec0, listsec1, &numfields, &numlocal);
+ g2int ierr;
+ g2int fieldIndex;
+ gribfield *gfld;
+ ierr = g2_info(rawData, listsec0, listsec1, &numfields, &numlocal);
if (ierr != 0) {
- free(cgrib);
- return -1;
+ PyErr_SetString(Grib2FileError, "Failed to get grib info.\n");
+ return NULL;
}
-
- ierr = g2_getfld(cgrib, fieldNumber, unpack, expand, gfld);
-
- // Detected a grib1
- if (ierr != 0) {
- free(cgrib);
- return -2;
- }
-
- free(cgrib);
- return numfields;
-}
-
-/////////////////////////////////////////////////////////////////////////
-// Extracts the data values from the grib file
-//
-// INPUT ARGUMENTS:
-// fptr - The pointer to the file being decoded
-// recordNumber - The number of the record being decoded
-// fieldNumber - The number of the field being decoded
-//
-// OUTPUT ARGUMENTS:
-// idSection - An array to hold the ID section
-// localUseSection - An array to hold the Local Use Section
-// gdsTemplate - An array to hold the GDS Template values
-// pdsTemplate - An array to hold the PDS Template values
-// data - An array to hold the data values
-// bitMap - An array to hold the bitmap values
-//
-// RETURN VALUE: The number of fields associated with this record
-//
-/////////////////////////////////////////////////////////////////////////
-static PyObject * grib2_getData(PyObject *self, PyObject* args)
-/*FILE * fptr, int recordNumber, int fieldNumber, int idSection[],
- int localUseSection[], int gdsTemplate[],int pdsTemplate[],float data[],
- int bitMap[], int list_opt[], float coord_list[]) */{
-
- PyObject * fileInfo;
- FILE * fptr;
- int recordNumber;
- g2int fieldNumber;
- Py_ssize_t sizeSection = 0;
- int sectionCounter = 0;
-
- PyArg_ParseTuple(args, "Oii", &fileInfo, &recordNumber, &fieldNumber);
-
- fptr = PyFile_AsFile(fileInfo);
-
- gribfield * gfld;
- long numfields;
- npy_intp dimSize[1];
- PyObject *response = PyDict_New();
- Py_BEGIN_ALLOW_THREADS
- numfields = getRecord(fptr, &gfld, recordNumber, fieldNumber, 1);
- Py_END_ALLOW_THREADS
-
- PyObject * numberOfFields = PyInt_FromLong(numfields);
- PyDict_SetItemString(response, "numFields", numberOfFields);
- //Py_DECREF(numberOfFields);
-
- // Copy the ID Section
- PyObject * idSection;
- sizeSection = gfld->idsectlen;
- idSection = PyList_New(sizeSection);
- for (sectionCounter = 0; sectionCounter < gfld->idsectlen; sectionCounter++) {
- PyList_SetItem(idSection, sectionCounter, Py_BuildValue("i",
- gfld->idsect[sectionCounter]));
- }
- PyDict_SetItemString(response, "idSection", idSection);
- Py_DECREF(idSection);
- // Copy the Local Section if exists
- if (gfld->locallen > 0) {
- PyObject * localSection;
- sizeSection = gfld->locallen;
- localSection = PyList_New(sizeSection);
- for(sectionCounter = 0; sectionCounter < gfld->locallen; sectionCounter++) {
- PyList_SetItem(localSection, sectionCounter, Py_BuildValue("i",gfld->local[sectionCounter]));
+ result = PyList_New(numfields);
+ for (fieldIndex = 0; fieldIndex < numfields; fieldIndex++) {
+ Py_BEGIN_ALLOW_THREADS
+ ierr = g2_getfld(rawData, fieldIndex + 1, 1, 1, &gfld);
+ Py_END_ALLOW_THREADS
+ if (ierr != 0) {
+ Py_DECREF(result);
+ PyErr_SetString(Grib2FileError, "Failed to get grib field.\n");
+ return NULL;
}
- PyDict_SetItemString(response, "localSection", localSection);
- Py_DECREF(localSection);
- }
-
- // Copy the number of points per row for quasi-regular grids
- if (gfld->num_opt > 0) {
- PyObject * listOps;
- sizeSection = gfld->num_opt;
- listOps = PyList_New(sizeSection);
- for(sectionCounter = 0; sectionCounter < gfld->num_opt; sectionCounter++) {
- PyList_SetItem(listOps, sectionCounter, Py_BuildValue("i",gfld->list_opt[sectionCounter]));
- }
- PyDict_SetItemString(response, "listOps", listOps);
- Py_DECREF(listOps);
- }
-
- // Copy the vertical discretisation values for hybrid coordinate vertical levels
- if (gfld->num_coord > 0) {
- PyObject * coordList;
- sizeSection = gfld->num_coord;
- coordList = PyList_New(sizeSection);
- for(sectionCounter = 0; sectionCounter < gfld->num_coord; sectionCounter++) {
- PyList_SetItem(coordList, sectionCounter, Py_BuildValue("f",gfld->coord_list[sectionCounter]));
- }
- PyDict_SetItemString(response, "coordList", coordList);
- Py_DECREF(coordList);
- }
-
- // Copy the GDS Template
- PyObject * gdsTemplate;
- sizeSection = gfld->igdtlen;
- gdsTemplate = PyList_New(sizeSection);
- for(sectionCounter = 0; sectionCounter < gfld->igdtlen; sectionCounter++) {
- PyList_SetItem(gdsTemplate, sectionCounter, Py_BuildValue("i",gfld->igdtmpl[sectionCounter]));
- }
- PyDict_SetItemString(response, "gdsTemplate", gdsTemplate);
- Py_DECREF(gdsTemplate);
-
- // Copy the PDS Template
- PyObject * pdsTemplate;
- sizeSection = gfld->ipdtlen;
- pdsTemplate = PyList_New(sizeSection);
- for(sectionCounter = 0; sectionCounter < gfld->ipdtlen; sectionCounter++) {
- PyList_SetItem(pdsTemplate, sectionCounter, Py_BuildValue("i",gfld->ipdtmpl[sectionCounter]));
- }
- PyDict_SetItemString(response, "pdsTemplate", pdsTemplate);
- Py_DECREF(pdsTemplate);
-
- // Copy the data
- PyObject * npyData;
- dimSize[0] = gfld->ngrdpts;
- npyData = PyArray_SimpleNew(1, dimSize, NPY_FLOAT);
- memcpy(((PyArrayObject *) npyData)->data, gfld->fld, gfld->ngrdpts
- * sizeof(float));
- PyDict_SetItemString(response, "data", npyData);
- Py_DECREF(npyData);
-
- // Copy the bitmap if exists
- if (gfld->ibmap == 0 || gfld->ibmap == 254) {
- PyObject * npyBitmap;
- dimSize[0] = gfld->ngrdpts;
- npyBitmap = PyArray_SimpleNew(1, dimSize, NPY_INT);
- memcpy(((PyArrayObject *) npyBitmap)->data, gfld->bmap, gfld->ngrdpts
- * sizeof(int));
- PyDict_SetItemString(response, "bitmap", npyBitmap);
- Py_DECREF(npyBitmap);
- }
-
- // Copy the Data Representation Section
- PyObject * drsTemplate;
- sizeSection = gfld->idrtlen;
- drsTemplate = PyList_New(sizeSection);
- for(sectionCounter = 0; sectionCounter < gfld->idrtlen; sectionCounter++) {
- PyList_SetItem(drsTemplate, sectionCounter, Py_BuildValue("i",gfld->idrtmpl[sectionCounter]));
- }
- PyDict_SetItemString(response, "drsTemplate", drsTemplate);
- Py_DECREF(drsTemplate);
-
- g2_free(gfld);
- return response;
-}
-
-/////////////////////////////////////////////////////////////////////////
-// Extracts the metadata values from the grib file.
-// The metadata is an array containing the values in the gribfield
-// structure
-//
-// INPUT ARGUMENTS:
-// fptr - The pointer to the file being decoded
-// recordNumber - The number of the record being decoded
-// fieldNumber - The number of the field being decoded
-//
-// OUTPUT ARGUMENTS:
-// metadata - An array holding the gribfield values
-//
-// RETURN VALUE: The number of fields associated with this record
-//
-/////////////////////////////////////////////////////////////////////////
-static PyObject * grib2_getMetadata(PyObject *self, PyObject* args)
-/* FILE * fptr, int recordNumber,int fieldNumber, int metadata[]) */{
-
- PyObject * fileInfo;
- FILE * fptr;
- int recordNumber;
- int fieldNumber;
- int debug;
- Py_ssize_t sizeSection = 0;
- int sectionCounter = 0;
-
- PyArg_ParseTuple(args, "Oiii", &fileInfo, &recordNumber, &fieldNumber,
- &debug);
- fptr = PyFile_AsFile(fileInfo);
-
- gribfield * gfld;
- long numfields;
- //int metadata[21];
- numfields = getRecord(fptr, &gfld, recordNumber, fieldNumber, 0);
- PyObject *response = PyDict_New();
-
- PyObject * numberOfFields = PyInt_FromLong(numfields);
- PyDict_SetItemString(response, "numFields", numberOfFields);
- //Py_DECREF(numberOfFields);
-
- if (numfields == -1) {
- return response;
- } else if (numfields == -2) {
+ PyList_SET_ITEM(result, fieldIndex, translateField(gfld));
g2_free(gfld);
- return response;
}
-
-
- int metadata[21];
-
- // Length of array containing ID section values
- metadata[0] = gfld->idsectlen;
-
- // Length of array containing local section values
- metadata[1] = gfld->locallen;
-
- // Field number within GRIB message
- metadata[2] = gfld->ifldnum;
-
- // Source of grid definition
- metadata[3] = gfld->griddef;
-
- // Number of grid points in the defined grid
- metadata[4] = gfld->ngrdpts;
-
- // Number of octets needed for each additional grid points definition
- metadata[5] = gfld->numoct_opt;
-
- // Interpretation of list for optional points definition (Table 3.11)
- metadata[6] = gfld->interp_opt;
-
- // Grid Definition Template Number
- metadata[7] = gfld->igdtnum;
-
- // Length of array containing GDS Template values
- metadata[8] = gfld->igdtlen;
-
- // The number of entries in array ideflist(Used if numoct_opt != 0)
- metadata[9] = gfld->num_opt;
-
- // Product Definition Template Number
- metadata[10] = gfld->ipdtnum;
-
- // Length of array containing PDS Template values
- metadata[11] = gfld->ipdtlen;
-
- // Number of values in array gfld->coord_list[]
- metadata[12] = gfld->num_coord;
-
- // Number of data points unpacked and returned
- metadata[13] = gfld->ndpts;
-
- // Data Representation Template Number
- metadata[14] = gfld->idrtnum;
-
- // Length of array containing DRT template values
- metadata[15] = gfld->idrtlen;
-
- // Logical value indicating whether the bitmap and data values were unpacked
- metadata[16] = gfld->unpacked;
-
- // Logical value indicating whether the data field was expanded to the grid in
- // the case where a bit-map is present
- metadata[17] = gfld->expanded;
-
- // Bitmap indicator
- metadata[18] = gfld->ibmap;
-
- // Parameter Discipline
- metadata[19] = gfld->discipline;
-
- metadata[20] = sizeof(gfld->list_opt);
-
- PyObject * metadataList;
- sizeSection = 21;
- metadataList = PyList_New(sizeSection);
- for (sectionCounter = 0; sectionCounter < 21; sectionCounter++) {
- PyList_SetItem(metadataList, sectionCounter, Py_BuildValue("i",
- metadata[sectionCounter]));
- }
- PyDict_SetItemString(response, "metadata", metadataList);
- Py_DECREF(metadataList);
- if(debug) {
- int j = 0;
- printf("Metadata Values: ");
- for(j = 0; j < 21; j++) {
- printf(" %d",metadata[j]);
- }
- printf(".\n");
- }
-
- g2_free(gfld);
- return response;
+ return result;
}
-static PyObject * grib2_checkVersion(PyObject *self, PyObject* args) {
- char * inputFile;
- long gribversion = 2;
- if (!PyArg_ParseTuple(args, "s", &inputFile)) {
- return NULL;
- }
- FILE * gribFile = fopen(inputFile, "rb");
- if (!gribFile) {
- PyErr_SetString(Grib2FileError,
- "Could not open the GRIB file specified.");
- return NULL;
- }
- //Search for grib header
- char header[100];
- fread(header, 1, 100, gribFile);
- int gCounter = 0;
- int foundHeader = 0;
- for (gCounter = 0; gCounter < 100; gCounter++) {
- if (header[gCounter] == 'G' && header[gCounter + 1] == 'R'
- && header[gCounter + 2] == 'I' && header[gCounter + 3] == 'B') {
- foundHeader = 1;
- break;
- }
- }
+/////////////////////////////////////////////////////////////////////////
+// Extracts the data from the specified portion of a grib file.
+//
+// INPUT ARGUMENTS:
+// self - The grib2 module object
+// fileInfo - The PyFile for an open grib file.
+// startPosition - The start position of the file portion to decode.
+// messageLength - The length of the file portion to decode.
+//
+// RETURN VALUE: A PyList of PyDicts, one PyDict for each field in the grib
+// message. The caller is responsible for decrementing the ref
+// count of the returned object.
+//
+/////////////////////////////////////////////////////////////////////////
+static PyObject* grib2_decode(PyObject* self, PyObject* args) {
+ PyObject* result = NULL;
+ PyObject* fileInfo;
+ int startPosition;
+ int messageLength;
+ FILE * fptr;
+ int ierr;
+ unsigned char* rawData;
- //char * start = strstr(header, "GRIB");
- if (!foundHeader) {
- PyErr_SetString(Grib2FileError, "Invalid Grib file detected.");
- fclose(gribFile);
- return NULL;
- }
- fclose(gribFile);
- if (header[gCounter + 7] == 0x01) { // GRIB 1 data
- gribversion = 1;
- } else if (header[gCounter + 7] != 0x02) {
- PyErr_SetString(Grib2FileError, "Unrecognized GRIB version.");
+ PyArg_ParseTuple(args, "Oii", &fileInfo, &startPosition, &messageLength);
+
+ fptr = PyFile_AsFile(fileInfo);
+ ierr = fseek(fptr, startPosition, SEEK_SET);
+ if (ierr != 0) {
+ PyErr_SetString(Grib2FileError, "Failed to seek to start position.\n");
return NULL;
}
- return PyInt_FromLong(gribversion);
+ rawData = (unsigned char *) malloc(messageLength);
+ if (rawData == NULL) {
+ PyErr_SetString(Grib2FileError, "Failed to malloc rawData.\n");
+ return NULL;
+ }
+ ierr = fread(rawData, sizeof(unsigned char), messageLength, fptr);
+ if (ierr != messageLength) {
+ free(rawData);
+ PyErr_SetString(Grib2FileError, "Failed to read full grib message.\n");
+ return NULL;
+ }
+
+ result = decodeData(rawData);
+ free(rawData);
+ return result;
}
-static PyObject * grib2_grib1Togrib2(PyObject *self, PyObject* args) {
- char * inputFile;
- char * outputFile;
- PyArg_ParseTuple(args, "ss", &inputFile, &outputFile);
- return PyInt_FromLong(1);
-}
-
-static PyMethodDef grib2_methods[] = { { "getMetadata", grib2_getMetadata,
- METH_VARARGS, "Returns the metadata for the grib file." }, { "getData",
- grib2_getData, METH_VARARGS,
- "Returns the data values for the grib file." }, { "checkVersion",
- grib2_checkVersion, METH_VARARGS,
- "Returns a file handle to a grib record." }, { "oneTotwo",
- grib2_grib1Togrib2, METH_VARARGS, "Converts grib1 files to grib2." }, {
- NULL, NULL, 0, NULL } /* sentinel */
+static PyMethodDef grib2_methods[] = { { "decode", grib2_decode, METH_VARARGS,
+ "Returns grib data for a range within a file." },
+ { NULL, NULL, 0, NULL } /* sentinel */
};
void initgrib2(void) {
diff --git a/rpms/awips2.core/Installer.python/component.spec b/rpms/awips2.core/Installer.python/component.spec
index 2113a3d3b3..e489a6cac9 100644
--- a/rpms/awips2.core/Installer.python/component.spec
+++ b/rpms/awips2.core/Installer.python/component.spec
@@ -7,7 +7,7 @@
Name: awips2-python
Summary: AWIPS II Python Distribution
Version: 2.7.1
-Release: 8
+Release: 9
Group: AWIPSII
BuildRoot: %{_build_root}
BuildArch: %{_build_arch}
diff --git a/rpms/awips2.core/Installer.python/nativeLib/x86_64/grib2.so b/rpms/awips2.core/Installer.python/nativeLib/x86_64/grib2.so
index ae7d6bef37..447249b515 100644
Binary files a/rpms/awips2.core/Installer.python/nativeLib/x86_64/grib2.so and b/rpms/awips2.core/Installer.python/nativeLib/x86_64/grib2.so differ