diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.classpath b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.classpath
new file mode 100644
index 0000000000..ad32c83a78
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.project b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.project
new file mode 100644
index 0000000000..aae180a2b7
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.project
@@ -0,0 +1,28 @@
+
+
+ com.raytheon.uf.common.dataplugin.grid
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..3f00c1463d
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Fri Feb 03 13:18:16 CST 2012
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..9f1e0aafde
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/META-INF/MANIFEST.MF
@@ -0,0 +1,33 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Grid
+Bundle-SymbolicName: com.raytheon.uf.common.dataplugin.grid
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: RAYTHEON
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Eclipse-RegisterBuddy: com.raytheon.uf.common.serialization
+Eclipse-BuddyPolicy: registered, ext, global
+Import-Package: com.raytheon.uf.common.dataplugin,
+ com.raytheon.uf.common.dataplugin.annotations,
+ com.raytheon.uf.common.dataplugin.level,
+ com.raytheon.uf.common.dataplugin.persist,
+ com.raytheon.uf.common.datastorage.records,
+ com.raytheon.uf.common.geospatial,
+ com.raytheon.uf.common.gridcoverage,
+ com.raytheon.uf.common.localization,
+ com.raytheon.uf.common.parameter,
+ com.raytheon.uf.common.serialization,
+ com.raytheon.uf.common.serialization.annotations,
+ com.raytheon.uf.common.serialization.comm,
+ com.raytheon.uf.common.status,
+ com.raytheon.uf.common.time,
+ com.vividsolutions.jts.geom,
+ javax.measure.unit,
+ javax.persistence,
+ org.hibernate.annotations,
+ org.opengis.metadata.spatial
+Export-Package: com.raytheon.uf.common.dataplugin.grid,
+ com.raytheon.uf.common.dataplugin.grid.dataset,
+ com.raytheon.uf.common.dataplugin.grid.request,
+ com.raytheon.uf.common.dataplugin.grid.units,
+ com.raytheon.uf.common.dataplugin.grid.util
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject
new file mode 100644
index 0000000000..bdc0a8ab06
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject
@@ -0,0 +1,4 @@
+com.raytheon.uf.common.dataplugin.grid.GridRecord
+com.raytheon.uf.common.dataplugin.grid.GridInfoRecord
+com.raytheon.uf.common.dataplugin.grid.dataset.DatasetInfo
+com.raytheon.uf.common.dataplugin.grid.dataset.DatasetInfoSet
\ No newline at end of file
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/build.properties b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/build.properties
new file mode 100644
index 0000000000..5791d48d5f
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ res/
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/res/scripts/grid_indices.sql b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/res/scripts/grid_indices.sql
new file mode 100644
index 0000000000..4c067488e1
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/res/scripts/grid_indices.sql
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ **/
+
+CREATE INDEX "gridDatasetReftime_idx"
+ ON grid
+ USING btree
+ (info_id, reftime, forecasttime);
+
+CREATE INDEX "gridinfoNameParamLevel_idx"
+ ON grid_info
+ USING btree
+ (datasetid, parameter_abbreviation, level_id);
+
+CREATE INDEX "gridinfoSecondryId_idx"
+ ON grid_info
+ USING btree
+ (secondaryid);
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridConstants.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridConstants.java
new file mode 100644
index 0000000000..55ff4ae309
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridConstants.java
@@ -0,0 +1,91 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid;
+
+/**
+ *
+ * Contains some useful constants for dealing with grid data, mostly just
+ * hibernate names of attributes.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 11, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+public class GridConstants {
+
+ public static final String GRID = "grid";
+
+ public static final String PLUGIN_NAME = "pluginName";
+
+ public static final String INFO = "info";
+
+ public static final String INFO_ID = INFO + "." + GridInfoConstants.ID;
+
+ public static final String DATASET_ID = INFO + "."
+ + GridInfoConstants.DATASET_ID;
+
+ public static final String SECONDARY_ID = INFO + "."
+ + GridInfoConstants.SECONDARY_ID;
+
+ public static final String ENSEMBLE_ID = INFO + "."
+ + GridInfoConstants.ENSEMBLE_ID;
+
+ public static final String LOCATION = INFO + "."
+ + GridInfoConstants.LOCATION;
+
+ public static final String LOCATION_ID = INFO + "."
+ + GridInfoConstants.LOCATION_ID;
+
+ public static final String PARAMETER = INFO + "."
+ + GridInfoConstants.PARAMETER;
+
+ public static final String PARAMETER_ABBREVIATION = INFO + "."
+ + GridInfoConstants.PARAMETER_ABBREVIATION;
+
+ public static final String PARAMETER_NAME = INFO + "."
+ + GridInfoConstants.PARAMETER_NAME;
+
+ public static final String PARAMETER_UNIT = INFO + "."
+ + GridInfoConstants.PARAMETER_UNIT;
+
+ public static final String LEVEL = INFO + "." + GridInfoConstants.LEVEL;
+
+ public static final String LEVEL_ID = INFO + "."
+ + GridInfoConstants.LEVEL_ID;
+
+ public static final String MASTER_LEVEL_NAME = INFO + "."
+ + GridInfoConstants.MASTER_LEVEL_NAME;
+
+ public static final String LEVEL_ONE = INFO + "."
+ + GridInfoConstants.LEVEL_ONE;
+
+ public static final String LEVEL_TWO = INFO + "."
+ + GridInfoConstants.LEVEL_TWO;
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridInfoConstants.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridInfoConstants.java
new file mode 100644
index 0000000000..8f0f9d6b2a
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridInfoConstants.java
@@ -0,0 +1,73 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid;
+
+/**
+ *
+ * Contains some useful constants for dealing with grid info objects, mostly
+ * just hibernate names of attributes.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 11, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+public class GridInfoConstants {
+
+ public static final String ID = "id";
+
+ public static final String DATASET_ID = "datasetId";
+
+ public static final String SECONDARY_ID = "secondaryId";
+
+ public static final String ENSEMBLE_ID = "ensembleId";
+
+ public static final String LOCATION = "location";
+
+ public static final String LOCATION_ID = LOCATION + ".id";
+
+ public static final String PARAMETER = "parameter";
+
+ public static final String PARAMETER_ABBREVIATION = PARAMETER
+ + ".abbreviation";
+
+ public static final String PARAMETER_NAME = PARAMETER + ".name";
+
+ public static final String PARAMETER_UNIT = PARAMETER + ".unitString";
+
+ public static final String LEVEL = "level";
+
+ public static final String LEVEL_ID = LEVEL + ".id";
+
+ public static final String MASTER_LEVEL_NAME = LEVEL + ".masterLevel.name";
+
+ public static final String LEVEL_ONE = LEVEL + ".levelonevalue";
+
+ public static final String LEVEL_TWO = LEVEL + ".leveltwovalue";
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridInfoRecord.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridInfoRecord.java
new file mode 100644
index 0000000000..5b6f3c02b7
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridInfoRecord.java
@@ -0,0 +1,248 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+
+import com.raytheon.uf.common.dataplugin.annotations.DataURI;
+import com.raytheon.uf.common.dataplugin.level.Level;
+import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject;
+import com.raytheon.uf.common.gridcoverage.GridCoverage;
+import com.raytheon.uf.common.parameter.Parameter;
+import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
+import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
+
+/**
+ * Contains all attributes of a grid record except time. This is done to save
+ * space in the db since across time most grid data has the same
+ * level/parameter/etc so having all other information in a separate table saves
+ * space and improves theoretical performance.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * May 21, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+@Entity
+@Table(name = "grid_info")
+@SequenceGenerator(name = "GRIDINFO_GENERATOR", sequenceName = "gridinfo_seq", allocationSize = 1)
+@DynamicSerialize
+public class GridInfoRecord extends PersistableDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ /** The id */
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "GRIDINFO_GENERATOR")
+ @DynamicSerializeElement
+ private Integer id;
+
+ @Column
+ @DataURI(position = 0)
+ @DynamicSerializeElement
+ private String datasetId;
+
+ /**
+ * Any string which can differentiate this record from other records with
+ * the same datasetId, examples of this would be for different versions of
+ * the same grid or for different events from the same model.
+ */
+ @Column
+ @DataURI(position = 1)
+ @DynamicSerializeElement
+ private String secondaryId;
+
+ @Column
+ @DynamicSerializeElement
+ @DataURI(position = 2)
+ private String ensembleId;
+
+ /** The spatial information */
+ @ManyToOne
+ @PrimaryKeyJoinColumn
+ @DataURI(position = 3)
+ @DynamicSerializeElement
+ private GridCoverage location;
+
+ @ManyToOne
+ @PrimaryKeyJoinColumn
+ @DataURI(position = 4, embedded = true)
+ @DynamicSerializeElement
+ private Parameter parameter;
+
+ @ManyToOne
+ @PrimaryKeyJoinColumn
+ @DynamicSerializeElement
+ @DataURI(position = 5, embedded = true)
+ private Level level;
+
+ public GridInfoRecord() {
+
+ }
+
+ public GridInfoRecord(GridInfoRecord record) {
+ this.datasetId = record.getDatasetId();
+ this.level = record.getLevel();
+ this.location = record.getLocation();
+ this.parameter = record.getParameter();
+ this.ensembleId = record.getEnsembleId();
+ this.secondaryId = record.getSecondaryId();
+ this.id = record.getId();
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getDatasetId() {
+ return datasetId;
+ }
+
+ public void setDatasetId(String datasetId) {
+ this.datasetId = datasetId;
+ }
+
+ public String getSecondaryId() {
+ return secondaryId;
+ }
+
+ public void setSecondaryId(String secondaryId) {
+ this.secondaryId = secondaryId;
+ }
+
+ public String getEnsembleId() {
+ return ensembleId;
+ }
+
+ public void setEnsembleId(String ensembleId) {
+ this.ensembleId = ensembleId;
+ }
+
+ public GridCoverage getLocation() {
+ return location;
+ }
+
+ public void setLocation(GridCoverage location) {
+ this.location = location;
+ }
+
+ public Parameter getParameter() {
+ return parameter;
+ }
+
+ public void setParameter(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ public Level getLevel() {
+ return level;
+ }
+
+ public void setLevel(Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public String toString() {
+ return "/" + datasetId + "/" + secondaryId + "/" + ensembleId + "/"
+ + location + "/" + parameter + "/" + level;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((datasetId == null) ? 0 : datasetId.hashCode());
+ result = prime * result
+ + ((ensembleId == null) ? 0 : ensembleId.hashCode());
+ result = prime * result + ((level == null) ? 0 : level.hashCode());
+ result = prime * result
+ + ((location == null) ? 0 : location.hashCode());
+ result = prime * result
+ + ((parameter == null) ? 0 : parameter.hashCode());
+ result = prime * result
+ + ((secondaryId == null) ? 0 : secondaryId.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;
+ GridInfoRecord other = (GridInfoRecord) obj;
+ if (datasetId == null) {
+ if (other.datasetId != null)
+ return false;
+ } else if (!datasetId.equals(other.datasetId))
+ return false;
+ if (ensembleId == null) {
+ if (other.ensembleId != null)
+ return false;
+ } else if (!ensembleId.equals(other.ensembleId))
+ return false;
+ if (level == null) {
+ if (other.level != null)
+ return false;
+ } else if (!level.equals(other.level))
+ return false;
+ if (location == null) {
+ if (other.location != null)
+ return false;
+ } else if (!location.equals(other.location))
+ return false;
+ if (parameter == null) {
+ if (other.parameter != null)
+ return false;
+ } else if (!parameter.equals(other.parameter))
+ return false;
+ if (secondaryId == null) {
+ if (other.secondaryId != null)
+ return false;
+ } else if (!secondaryId.equals(other.secondaryId))
+ return false;
+ return true;
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridPathProvider.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridPathProvider.java
new file mode 100644
index 0000000000..52ade9b034
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridPathProvider.java
@@ -0,0 +1,128 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+
+package com.raytheon.uf.common.dataplugin.grid;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.raytheon.uf.common.dataplugin.persist.DefaultPathProvider;
+import com.raytheon.uf.common.dataplugin.persist.IPersistable;
+
+/**
+ * Path provider for storing gridded data to HDF5
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * 4/24/09 1994 bphillip Initial Creation
+ *
+ *
+ *
+ * @author bphillip
+ * @version 1
+ */
+public class GridPathProvider extends DefaultPathProvider {
+
+ private static final DecimalFormat forecastHourFormat = new DecimalFormat(
+ "000");
+
+ private static final int SECONDS_PER_HOUR = 3600;
+
+ public static final String FORECAST_HR_TOKEN = "-FH-";
+
+ private static GridPathProvider instance = new GridPathProvider();
+
+ public static final List STATIC_PARAMETERS;
+
+ static {
+ STATIC_PARAMETERS = new ArrayList();
+ STATIC_PARAMETERS.add("staticTopo");
+ STATIC_PARAMETERS.add("staticXspacing");
+ STATIC_PARAMETERS.add("staticYspacing");
+ STATIC_PARAMETERS.add("staticCoriolis");
+ STATIC_PARAMETERS.add("staticSpacing");
+ }
+
+ public static GridPathProvider getInstance() {
+ return instance;
+ }
+
+ protected GridPathProvider() {
+
+ }
+
+ @Override
+ public String getHDFFileName(String pluginName, IPersistable persistable) {
+
+ if (persistable == null) {
+ throw new IllegalArgumentException(
+ "Expected argument persistable is null");
+ }
+
+ if (!(persistable instanceof GridRecord)) {
+ throw new IllegalArgumentException(
+ "Argument persistable is of wrong type. Expected "
+ + GridRecord.class + " but got "
+ + persistable.getClass());
+ } else if (pluginName == null) {
+ throw new IllegalArgumentException(
+ "Expected argument pluginName not set on object "
+ + persistable.toString());
+ }
+
+ GridRecord pdo = (GridRecord) persistable;
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(pdo.getDatasetId());
+ Date refTime = pdo.getDataTime().getRefTime();
+ String refTimeString = null;
+ synchronized (fileNameFormat) {
+ refTimeString = fileNameFormat.format(refTime);
+ }
+ sb.append(refTimeString);
+ sb.append(FORECAST_HR_TOKEN);
+ if (STATIC_PARAMETERS.contains(pdo.getParameter().getAbbreviation())) {
+ sb.append("000");
+ } else {
+ long number = pdo.getDataTime().getFcstTime() / SECONDS_PER_HOUR;
+ String numberString = null;
+ synchronized (forecastHourFormat) {
+ numberString = forecastHourFormat.format(number);
+ }
+ sb.append(numberString);
+ }
+ sb.append(".h5");
+
+ return sb.toString();
+ }
+
+ public String formatTime(Date date) {
+ String retVal = null;
+ synchronized (fileNameFormat) {
+ retVal = fileNameFormat.format(date);
+ }
+ return retVal;
+ }
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridRecord.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridRecord.java
new file mode 100644
index 0000000000..a1db9909dc
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/GridRecord.java
@@ -0,0 +1,239 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+
+import com.raytheon.uf.common.dataplugin.IDecoderGettable;
+import com.raytheon.uf.common.dataplugin.annotations.DataURI;
+import com.raytheon.uf.common.dataplugin.level.Level;
+import com.raytheon.uf.common.dataplugin.persist.IHDFFilePathProvider;
+import com.raytheon.uf.common.dataplugin.persist.PersistablePluginDataObject;
+import com.raytheon.uf.common.geospatial.ISpatialEnabled;
+import com.raytheon.uf.common.geospatial.ISpatialObject;
+import com.raytheon.uf.common.gridcoverage.GridCoverage;
+import com.raytheon.uf.common.parameter.Parameter;
+import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
+import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
+
+/**
+ *
+ * Record for storing generic gridded data. Everything interesting is stored in
+ * the info object since it allows us to reuse the info object for identical
+ * records at different times which saves db and improves theoretical
+ * performance.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * May 21, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+@Entity
+@Table(name = "grid", uniqueConstraints = { @UniqueConstraint(columnNames = { "dataURI" }) })
+@DynamicSerialize
+public class GridRecord extends PersistablePluginDataObject implements
+ ISpatialEnabled {
+
+ private static final long serialVersionUID = 1L;
+
+ @ManyToOne(cascade = { CascadeType.REFRESH })
+ @PrimaryKeyJoinColumn
+ @DataURI(position = 1, embedded = true)
+ @DynamicSerializeElement
+ private GridInfoRecord info;
+
+ /**
+ * Holds any extra attributes which may be specific to this data. These are
+ * not stored to the database or to hdf5 but they can be useful for passing
+ * additional parameters from a decoder to a post processor.
+ */
+ @Transient
+ private Map extraAttributes;
+
+ public GridRecord() {
+ super();
+ }
+
+ public GridRecord(GridRecord record) {
+ this.pluginName = record.getPluginName();
+ this.dataTime = record.getDataTime();
+ this.info = new GridInfoRecord(record.getInfoNotNull());
+ if (record.getExtraAttributes() != null) {
+ this.extraAttributes = new HashMap(
+ record.getExtraAttributes());
+ }
+ }
+
+ public GridRecord(String uri) {
+ super(uri);
+ }
+
+ public GridInfoRecord getInfo() {
+
+ return info;
+ }
+
+ public void setInfo(GridInfoRecord info) {
+ this.info = info;
+ }
+
+ protected GridInfoRecord getInfoNotNull() {
+ if (info == null) {
+ info = new GridInfoRecord();
+ }
+ return info;
+ }
+
+ public String getDatasetId() {
+ return getInfoNotNull().getDatasetId();
+ }
+
+ public void setDatasetId(String datasetId) {
+ getInfoNotNull().setDatasetId(datasetId);
+ }
+
+ public String getSecondaryId() {
+ return getInfoNotNull().getSecondaryId();
+ }
+
+ public void setSecondaryId(String secondaryId) {
+ getInfoNotNull().setSecondaryId(secondaryId);
+ }
+
+ public GridCoverage getLocation() {
+ return getInfoNotNull().getLocation();
+ }
+
+ public void setLocation(GridCoverage location) {
+ getInfoNotNull().setLocation(location);
+ }
+
+ public Parameter getParameter() {
+ return getInfoNotNull().getParameter();
+ }
+
+ public void setParameter(Parameter parameter) {
+ getInfoNotNull().setParameter(parameter);
+ }
+
+ public Level getLevel() {
+ return getInfoNotNull().getLevel();
+ }
+
+ public void setLevel(Level level) {
+ getInfoNotNull().setLevel(level);
+ }
+
+ public String getEnsembleId() {
+ return getInfoNotNull().getEnsembleId();
+ }
+
+ public void setEnsembleId(String ensembleId) {
+ getInfoNotNull().setEnsembleId(ensembleId);
+ }
+
+ @Override
+ public IDecoderGettable getDecoderGettable() {
+ return null;
+ }
+
+ @Override
+ public ISpatialObject getSpatialObject() {
+ return getLocation();
+ }
+
+ @Override
+ public IHDFFilePathProvider getHDFPathProvider() {
+ return GridPathProvider.getInstance();
+ }
+
+ public Map getExtraAttributes() {
+ return extraAttributes;
+ }
+
+ public void setExtraAttributes(Map extraAttributes) {
+ this.extraAttributes = extraAttributes;
+ }
+
+ /**
+ * Add an attribute to the data, if there are no attributes then the
+ * attribute map is created.
+ *
+ * @param key
+ * @param value
+ * @return the previous value of the attribute or null if there was none.
+ */
+ public Object addExtraAttribute(String key, Object value) {
+ if (extraAttributes == null) {
+ extraAttributes = new HashMap();
+ }
+ return extraAttributes.put(key, value);
+ }
+
+ public Object getExtraAttribute(String key) {
+ if (extraAttributes == null) {
+ return null;
+ }
+ return extraAttributes.get(key);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((info == null) ? 0 : info.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ GridRecord other = (GridRecord) obj;
+ if (info == null) {
+ if (other.info != null)
+ return false;
+ } else if (!info.equals(other.info))
+ return false;
+ return true;
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfo.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfo.java
new file mode 100644
index 0000000000..669c916f84
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfo.java
@@ -0,0 +1,95 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid.dataset;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ *
+ * Contains static information about a grid dataset.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 27, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+@XmlAccessorType(XmlAccessType.NONE)
+public class DatasetInfo {
+
+ /** The title of the model */
+ @XmlElement
+ private String title;
+
+ /** The model name */
+ @XmlElement
+ private String datasetId;
+
+ @XmlElement
+ private String alias;
+
+ /**
+ * The intrinsic temporal resolution of the data.
+ */
+ @XmlElement
+ private Integer dt;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDatasetId() {
+ return datasetId;
+ }
+
+ public void setDatasetId(String datasetId) {
+ this.datasetId = datasetId;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public Integer getDt() {
+ return dt;
+ }
+
+ public void setDt(Integer dt) {
+ this.dt = dt;
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfoLookup.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfoLookup.java
new file mode 100644
index 0000000000..cb7721df58
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfoLookup.java
@@ -0,0 +1,117 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid.dataset;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.bind.JAXBException;
+
+import com.raytheon.uf.common.localization.IPathManager;
+import com.raytheon.uf.common.localization.LocalizationContext;
+import com.raytheon.uf.common.localization.LocalizationFile;
+import com.raytheon.uf.common.localization.PathManagerFactory;
+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;
+
+/**
+ *
+ * Provides logic to read datasetInfo files from localization and provide lookup
+ * by datasetId.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 27, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+public class DatasetInfoLookup {
+ private static final transient IUFStatusHandler statusHandler = UFStatus
+ .getHandler(DatasetInfoLookup.class);
+
+ private static DatasetInfoLookup instance;
+
+ public static DatasetInfoLookup getInstance() {
+ if (instance == null) {
+ instance = new DatasetInfoLookup();
+ }
+ return instance;
+ }
+
+ private Map infoMap = new HashMap();
+
+ private DatasetInfoLookup() {
+ init();
+ }
+
+ private void init() {
+ JAXBManager manager = null;
+ try {
+ manager = new JAXBManager(DatasetInfoSet.class);
+ } catch (JAXBException e) {
+ statusHandler
+ .error("Error loading context for DatasetInfo, no datasetInfo will be loaded.",
+ e);
+ }
+ IPathManager pathMgr = PathManagerFactory.getPathManager();
+ LocalizationContext commonStaticBase = pathMgr.getContext(
+ LocalizationContext.LocalizationType.COMMON_STATIC,
+ LocalizationContext.LocalizationLevel.BASE);
+
+ LocalizationContext commonStaticSite = pathMgr.getContext(
+ LocalizationContext.LocalizationType.COMMON_STATIC,
+ LocalizationContext.LocalizationLevel.SITE);
+
+ LocalizationFile[] files = pathMgr.listFiles(new LocalizationContext[] {
+ commonStaticSite, commonStaticBase }, "grid"
+ + IPathManager.SEPARATOR + "datasetInfo",
+ new String[] { ".xml" }, true, true);
+ for (LocalizationFile file : files) {
+ if (file == null || !file.exists()) {
+ return;
+ }
+ try {
+ Object obj = manager.jaxbUnmarshalFromXmlFile(file.getFile());
+ DatasetInfoSet set = (DatasetInfoSet) obj;
+ for (DatasetInfo info : set.getInfos()) {
+ infoMap.put(info.getDatasetId(), info);
+ }
+ } catch (SerializationException e) {
+ statusHandler.error(
+ "Error reading dataset info: " + file.getName()
+ + " has been ignored.", e);
+ }
+ }
+
+ }
+
+ public DatasetInfo getInfo(String datasetId) {
+ return infoMap.get(datasetId);
+ }
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfoSet.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfoSet.java
new file mode 100644
index 0000000000..f7559b7bb3
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/dataset/DatasetInfoSet.java
@@ -0,0 +1,62 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid.dataset;
+
+import java.util.ArrayList;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ * JAXB compatible root element for a list of datasetInfo objects
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 27, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class DatasetInfoSet {
+
+ @XmlElements({ @XmlElement(name = "info", type = DatasetInfo.class) })
+ private ArrayList infos;
+
+ public ArrayList getInfos() {
+ return infos;
+ }
+
+ public void setInfos(ArrayList infos) {
+ this.infos = infos;
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/request/GetGridTreeRequest.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/request/GetGridTreeRequest.java
new file mode 100644
index 0000000000..235fb8504b
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/request/GetGridTreeRequest.java
@@ -0,0 +1,45 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid.request;
+
+import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
+import com.raytheon.uf.common.serialization.comm.IServerRequest;
+
+/**
+ *
+ * Request for the Grid DataTree.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 5, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+@DynamicSerialize
+public class GetGridTreeRequest implements IServerRequest {
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/units/GridUnits.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/units/GridUnits.java
new file mode 100644
index 0000000000..6b2e05e6fd
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/units/GridUnits.java
@@ -0,0 +1,66 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid.units;
+
+import javax.measure.unit.NonSI;
+import javax.measure.unit.SI;
+import javax.measure.unit.UnitFormat;
+
+/**
+ * Provide alias for common units used in grid.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 20, 2009 mschenke Initial creation
+ *
+ *
+ *
+ * @author mschenke
+ * @version 1.0
+ */
+
+public class GridUnits {
+
+ public static boolean register() {
+ UnitFormat.getInstance().alias(SI.METER, "gpm");
+ UnitFormat.getUCUMInstance().alias(SI.METER, "gpm");
+ UnitFormat.getInstance().alias(SI.MILLI(NonSI.BAR), "mb");
+ UnitFormat.getUCUMInstance().alias(SI.MILLI(NonSI.BAR), "mb");
+ UnitFormat.getInstance().alias(SI.CELSIUS, "C");
+ UnitFormat.getUCUMInstance().alias(SI.CELSIUS, "C");
+ UnitFormat.getInstance().alias(NonSI.FAHRENHEIT, "F");
+ UnitFormat.getUCUMInstance().alias(NonSI.FAHRENHEIT, "F");
+ UnitFormat.getInstance().alias(NonSI.DEGREE_ANGLE, "deg");
+ UnitFormat.getUCUMInstance().alias(NonSI.DEGREE_ANGLE, "deg");
+ UnitFormat.getInstance().alias(NonSI.DEGREE_ANGLE, "Degree");
+ UnitFormat.getUCUMInstance().alias(NonSI.DEGREE_ANGLE, "Degree");
+ UnitFormat.getInstance().alias(NonSI.KNOT, "kt");
+ UnitFormat.getUCUMInstance().alias(NonSI.KNOT, "kt");
+ UnitFormat.getInstance().alias(SI.SECOND, "sec");
+ UnitFormat.getUCUMInstance().alias(SI.SECOND, "sec");
+ UnitFormat.getInstance().alias(SI.METER, "meters");
+ UnitFormat.getUCUMInstance().alias(SI.METER, "meters");
+ return true;
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/util/StaticGridData.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/util/StaticGridData.java
new file mode 100644
index 0000000000..fb4d813f72
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/util/StaticGridData.java
@@ -0,0 +1,169 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opengis.metadata.spatial.PixelOrientation;
+
+import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
+import com.raytheon.uf.common.geospatial.MapUtil;
+import com.raytheon.uf.common.gridcoverage.GridCoverage;
+import com.vividsolutions.jts.geom.Coordinate;
+
+/**
+ * A class for calculating and caching static data for grids.
+ *
+ *
+ * SOFTWARE HISTORY
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 24, 2008 brockwoo Initial creation
+ *
+ *
+ *
+ * @author brockwoo
+ * @version 1.0
+ */
+
+public class StaticGridData {
+ private static Map instanceMap = new HashMap();
+
+ private static final double R_EARTH = 6370.0;
+
+ private FloatDataRecord dx;
+
+ private FloatDataRecord dy;
+
+ private FloatDataRecord coriolis;
+
+ private StaticGridData(GridCoverage gridCoverage) {
+ initStaticData(gridCoverage);
+ }
+
+ public static synchronized StaticGridData getInstance(
+ GridCoverage gridCoverage) {
+ StaticGridData rval = instanceMap.get(gridCoverage);
+
+ if (rval == null) {
+ rval = new StaticGridData(gridCoverage);
+ instanceMap.put(gridCoverage, rval);
+ }
+
+ return rval;
+ }
+
+ public FloatDataRecord getCoriolis() {
+ return this.coriolis;
+ }
+
+ public FloatDataRecord getDx() {
+ return this.dx;
+ }
+
+ public FloatDataRecord getDy() {
+ return this.dy;
+ }
+
+ private void initStaticData(GridCoverage gridCoverage) {
+ int nx = gridCoverage.getNx();
+ int ny = gridCoverage.getNy();
+ int n = nx * ny;
+ float[] _coriolis = new float[n];
+ float[] dxPtr = new float[n];
+ float[] dyPtr = new float[n];
+ float[] avgPtr = new float[n];
+ double[] xx = new double[n];
+ double[] yy = new double[n];
+ double[] zz = new double[n];
+ int i, j, k;
+
+ for (j = k = 0; j < ny; j++) {
+ for (i = 0; i < nx; i++, k++) {
+ Coordinate location = new Coordinate(i, j);
+ Coordinate latLon = MapUtil.gridCoordinateToLatLon(location,
+ PixelOrientation.CENTER, gridCoverage);
+ latLon.x = Math.toRadians(latLon.x);
+ latLon.y = Math.toRadians(latLon.y);
+ xx[k] = Math.cos(latLon.y);
+ yy[k] = xx[k] * Math.sin(latLon.x);
+ xx[k] *= Math.cos(latLon.x);
+ zz[k] = Math.sin(latLon.y);
+ _coriolis[k] = (float) (zz[k] * 1.458e-4);
+ }
+ }
+
+ this.coriolis = newRecord(_coriolis, nx, ny);
+
+ int up, dn, lft, rgt;
+ long _nxm = nx - 1;
+ double d;
+ double icomp, jcomp, kcomp;
+ double dmax = 0.0;
+ dn = 0;
+ up = nx;
+ for (j = k = 0; j < ny; j++) {
+ if (up >= n) {
+ up -= nx;
+ }
+ lft = k;
+ for (i = 0; i < nx; i++, k++) {
+ rgt = (i < _nxm ? k + 1 : k);
+ icomp = yy[lft] * zz[rgt] - zz[lft] * yy[rgt];
+ jcomp = zz[lft] * xx[rgt] - xx[lft] * zz[rgt];
+ kcomp = xx[lft] * yy[rgt] - yy[lft] * xx[rgt];
+ d = Math.sqrt(icomp * icomp + jcomp * jcomp + kcomp * kcomp);
+ dxPtr[k] = (float) (Math.asin(d) * 1000.0 * R_EARTH / (rgt - lft));
+ icomp = yy[dn] * zz[up] - zz[dn] * yy[up];
+ jcomp = zz[dn] * xx[up] - xx[dn] * zz[up];
+ kcomp = xx[dn] * yy[up] - yy[dn] * xx[up];
+ d = Math.sqrt(icomp * icomp + jcomp * jcomp + kcomp * kcomp);
+ dyPtr[k] = (float) (Math.asin(d) * 1000.0 * R_EARTH * nx / (up - dn));
+ avgPtr[k] = (dxPtr[k] + dyPtr[k]) / 2.0f;
+ d = dxPtr[k] - dyPtr[k];
+ if (d < 0) {
+ d = -d;
+ }
+ d /= avgPtr[k];
+ if (d > dmax) {
+ dmax = d;
+ }
+ dn++;
+ up++;
+ lft = k;
+ }
+ if (j == 0) {
+ dn = 0;
+ }
+ }
+ if (dmax > 0.01) {
+ this.dx = newRecord(dxPtr, nx, ny);
+ this.dy = newRecord(dyPtr, nx, ny);
+ } else {
+ this.dx = this.dy = newRecord(avgPtr, nx, ny);
+ }
+ }
+
+ private FloatDataRecord newRecord(float[] data, int nx, int ny) {
+ return new FloatDataRecord("DATA", "", data, 2, new long[] { nx, ny });
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/util/StaticGridDataType.java b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/util/StaticGridDataType.java
new file mode 100644
index 0000000000..9259e3e57c
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin.grid/src/com/raytheon/uf/common/dataplugin/grid/util/StaticGridDataType.java
@@ -0,0 +1,56 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin.grid.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The static grid data types are the same values for a coverage and can be
+ * calculated based off the coverage/model.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 17, 2010 rjpeter Initial creation
+ *
+ *
+ *
+ * @author rjpeter
+ * @version 1.0
+ */
+
+public enum StaticGridDataType {
+ dx, dy, coriolis, _dt;
+
+ private static List stringValues;
+
+ public static List getStringValues() {
+ if (stringValues == null) {
+ stringValues = new ArrayList(values().length);
+ for (StaticGridDataType type : values()) {
+ stringValues.add(type.toString());
+ }
+ }
+ return stringValues;
+ }
+}
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/.classpath b/edexOsgi/com.raytheon.uf.edex.plugin.grid/.classpath
new file mode 100644
index 0000000000..f77c5c56bb
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/.project b/edexOsgi/com.raytheon.uf.edex.plugin.grid/.project
new file mode 100644
index 0000000000..8b4643dc92
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/.project
@@ -0,0 +1,28 @@
+
+
+ com.raytheon.uf.edex.plugin.grid
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.edex.plugin.grid/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..5718e24147
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Fri Feb 03 13:25:55 CST 2012
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.grid/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..024752f577
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/META-INF/MANIFEST.MF
@@ -0,0 +1,66 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Grid
+Bundle-SymbolicName: com.raytheon.uf.edex.plugin.grid
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: RAYTHEON
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Import-Package: com.raytheon.edex.site,
+ com.raytheon.uf.common.dataplugin,
+ com.raytheon.uf.common.dataplugin.grid,
+ com.raytheon.uf.common.dataplugin.grid.dataset,
+ com.raytheon.uf.common.dataplugin.grid.request,
+ com.raytheon.uf.common.dataplugin.level,
+ com.raytheon.uf.common.dataplugin.persist,
+ com.raytheon.uf.common.dataquery.db,
+ com.raytheon.uf.common.datastorage,
+ com.raytheon.uf.common.datastorage.records,
+ com.raytheon.uf.common.derivparam.tree,
+ com.raytheon.uf.common.geospatial,
+ com.raytheon.uf.common.geospatial.interpolation,
+ com.raytheon.uf.common.gridcoverage,
+ com.raytheon.uf.common.gridcoverage.lookup,
+ com.raytheon.uf.common.parameter,
+ com.raytheon.uf.common.parameter.mapping,
+ com.raytheon.uf.common.serialization,
+ com.raytheon.uf.common.serialization.comm,
+ com.raytheon.uf.common.status,
+ com.raytheon.uf.common.util,
+ com.raytheon.uf.common.util.registry,
+ com.raytheon.uf.edex.core,
+ com.raytheon.uf.edex.core.dataplugin,
+ com.raytheon.uf.edex.core.props,
+ com.raytheon.uf.edex.database,
+ com.raytheon.uf.edex.database.cluster,
+ com.raytheon.uf.edex.database.dao,
+ com.raytheon.uf.edex.database.plugin,
+ com.raytheon.uf.edex.database.query,
+ com.raytheon.uf.edex.parameter,
+ com.vividsolutions.jts.geom,
+ javax.measure.converter,
+ javax.measure.unit,
+ org.apache.commons.logging,
+ org.geotools.coverage,
+ org.geotools.coverage.grid,
+ org.geotools.factory,
+ org.geotools.geometry,
+ org.geotools.geometry.jts,
+ org.geotools.referencing,
+ org.geotools.referencing.operation,
+ org.geotools.referencing.operation.builder,
+ org.geotools.referencing.operation.transform,
+ org.hibernate,
+ org.hibernate.criterion,
+ org.opengis.coverage.grid,
+ org.opengis.geometry,
+ org.opengis.metadata.spatial,
+ org.opengis.parameter,
+ org.opengis.referencing,
+ org.opengis.referencing.crs,
+ org.opengis.referencing.datum,
+ org.opengis.referencing.operation,
+ org.springframework.dao.support,
+ org.springframework.orm.hibernate3.support
+Export-Package: com.raytheon.uf.edex.plugin.grid.dao,
+ com.raytheon.uf.edex.plugin.grid.handler,
+ com.raytheon.uf.edex.plugin.grid.topo
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/build.properties b/edexOsgi/com.raytheon.uf.edex.plugin.grid/build.properties
new file mode 100644
index 0000000000..73974cda80
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ res/,\
+ utility/
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/res/spring/grid-common.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grid/res/spring/grid-common.xml
new file mode 100644
index 0000000000..2c946935c5
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/res/spring/grid-common.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+ com.raytheon.uf.common.dataplugin.level
+ com.raytheon.uf.common.parameter
+ com.raytheon.uf.common.gridcoverage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.raytheon.uf.common.dataplugin.grid.units.GridUnits
+
+
+ register
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/res/spring/grid-request.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grid/res/spring/grid-request.xml
new file mode 100644
index 0000000000..73238581bf
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/res/spring/grid-request.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/dao/GridDao.java b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/dao/GridDao.java
new file mode 100644
index 0000000000..c934b773d7
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/dao/GridDao.java
@@ -0,0 +1,406 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+
+package com.raytheon.uf.edex.plugin.grid.dao;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.measure.converter.UnitConverter;
+
+import com.raytheon.uf.common.dataplugin.PluginDataObject;
+import com.raytheon.uf.common.dataplugin.PluginException;
+import com.raytheon.uf.common.dataplugin.grid.GridConstants;
+import com.raytheon.uf.common.dataplugin.grid.GridPathProvider;
+import com.raytheon.uf.common.dataplugin.grid.GridRecord;
+import com.raytheon.uf.common.dataplugin.level.Level;
+import com.raytheon.uf.common.dataplugin.level.LevelFactory;
+import com.raytheon.uf.common.dataplugin.level.MasterLevel;
+import com.raytheon.uf.common.dataplugin.persist.IPersistable;
+import com.raytheon.uf.common.dataquery.db.QueryResult;
+import com.raytheon.uf.common.datastorage.IDataStore;
+import com.raytheon.uf.common.datastorage.Request;
+import com.raytheon.uf.common.datastorage.StorageException;
+import com.raytheon.uf.common.datastorage.StorageProperties;
+import com.raytheon.uf.common.datastorage.StorageStatus;
+import com.raytheon.uf.common.datastorage.records.AbstractStorageRecord;
+import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
+import com.raytheon.uf.common.datastorage.records.IDataRecord;
+import com.raytheon.uf.common.gridcoverage.GridCoverage;
+import com.raytheon.uf.common.gridcoverage.lookup.GridCoverageLookup;
+import com.raytheon.uf.common.parameter.Parameter;
+import com.raytheon.uf.edex.core.EDEXUtil;
+import com.raytheon.uf.edex.core.EdexException;
+import com.raytheon.uf.edex.core.dataplugin.PluginRegistry;
+import com.raytheon.uf.edex.database.DataAccessLayerException;
+import com.raytheon.uf.edex.database.plugin.PluginDao;
+import com.raytheon.uf.edex.parameter.ParameterLookup;
+
+/**
+ * Data access object for accessing Grid records from the database
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * 4/7/09 1994 bphillip Initial Creation
+ *
+ *
+ *
+ * @author bphillip
+ * @version 1
+ */
+public class GridDao extends PluginDao {
+
+ private static String purgeModelCacheTopic = null;
+
+ public static String setPurgeModelCacheTopic(String purgeModelCacheTopic) {
+ GridDao.purgeModelCacheTopic = purgeModelCacheTopic;
+ return purgeModelCacheTopic;
+ }
+
+ public GridDao() throws PluginException {
+ super(GridConstants.GRID);
+ }
+
+ public GridDao(String pluginName) throws PluginException {
+ super(pluginName);
+ }
+
+ @Override
+ protected IDataStore populateDataStore(IDataStore dataStore,
+ IPersistable obj) throws Exception {
+ GridRecord gridRec = (GridRecord) obj;
+ Object messageData = gridRec.getMessageData();
+ GridCoverage location = gridRec.getLocation();
+ if (location != null && messageData instanceof float[]) {
+ long[] sizes = new long[] { location.getNx(), location.getNy() };
+ String abbrev = gridRec.getParameter().getAbbreviation();
+ String group = gridRec.getDataURI();
+ if (GridPathProvider.STATIC_PARAMETERS.contains(abbrev)) {
+ group = "/" + location.getName();
+ }
+ AbstractStorageRecord storageRecord = new FloatDataRecord("Data",
+ group, (float[]) messageData, 2, sizes);
+
+ storageRecord.setCorrelationObject(gridRec);
+ StorageProperties sp = new StorageProperties();
+ String compression = PluginRegistry.getInstance()
+ .getRegisteredObject(pluginName).getCompression();
+ if (compression != null) {
+ sp.setCompression(StorageProperties.Compression
+ .valueOf(compression));
+ }
+ sp.setChunked(true);
+ dataStore.addDataRecord(storageRecord, sp);
+ } else {
+ throw new Exception("Cannot create data record, spatialData = "
+ + location + " and messageData = " + messageData);
+ }
+ return dataStore;
+ }
+
+ @Override
+ public void persistRecords(PluginDataObject... records)
+ throws PluginException {
+ List toPersist = new ArrayList(
+ records.length);
+ for (PluginDataObject record : records) {
+ GridRecord rec = (GridRecord) record;
+ if (rec.getParameter() == null
+ || rec.getParameter().getName() == null
+ || rec.getParameter().getName().equals("Missing")) {
+ logger.info("Discarding record due to missing or unknown parameter mapping: "
+ + record);
+ } else {
+ boolean validLevel = false;
+ Level level = rec.getLevel();
+
+ if (level != null) {
+ MasterLevel ml = level.getMasterLevel();
+
+ if (ml != null
+ && !LevelFactory.UNKNOWN_LEVEL.equals(ml.getName())) {
+ validLevel = true;
+ }
+ }
+
+ if (validLevel) {
+ toPersist.add(rec);
+ } else {
+ logger.info("Discarding record due to missing or unknown level mapping: "
+ + record);
+ }
+ }
+ }
+
+ super.persistRecords(toPersist.toArray(new PluginDataObject[toPersist
+ .size()]));
+ }
+
+ @Override
+ public PluginDataObject[] persistToDatabase(PluginDataObject... records) {
+ return super.persistToDatabase(verifyRecords(records));
+ }
+
+ @Override
+ public StorageStatus persistToHDF5(PluginDataObject... records)
+ throws PluginException {
+ return super.persistToHDF5(verifyRecords(records));
+ }
+
+ @Override
+ public List getHDF5Data(List objects,
+ int tileSet) throws PluginException {
+
+ List retVal = new ArrayList(
+ objects.size());
+
+ for (PluginDataObject rec : objects) {
+ if (rec instanceof GridRecord) {
+ try {
+ GridRecord obj = (GridRecord) rec;
+ IDataStore dataStore = getDataStore(obj);
+ String abbrev = obj.getParameter().getAbbreviation();
+ if (GridPathProvider.STATIC_PARAMETERS.contains(abbrev)) {
+ IDataRecord[] record = new IDataRecord[4];
+ record[0] = dataStore.retrieve("/"
+ + obj.getLocation().getName(), abbrev,
+ Request.ALL);
+ retVal.add(record);
+ } else {
+ /* connect to the data store and retrieve the data */
+ IDataRecord[] record = new IDataRecord[4];
+ record[0] = dataStore.retrieve(obj.getDataURI(),
+ "Data", Request.ALL);
+
+ retVal.add(record);
+ }
+ } catch (StorageException e) {
+ throw new PluginException("Error getting HDF5 data", e);
+ } catch (FileNotFoundException e) {
+ throw new PluginException("Error getting HDF5 data", e);
+ }
+ }
+ }
+
+ return retVal;
+ }
+
+ private PluginDataObject[] verifyRecords(PluginDataObject... records) {
+ List toPersist = new ArrayList(
+ records.length);
+ for (PluginDataObject record : records) {
+ GridRecord rec = (GridRecord) record;
+ if (validateDataset(rec)) {
+ toPersist.add(rec);
+ }
+ }
+ return toPersist.toArray(new GridRecord[toPersist.size()]);
+ }
+
+ private boolean validateDataset(GridRecord record) {
+ if (!validateParameter(record)) {
+ return false;
+ }
+ if (!validateLevel(record)) {
+ return false;
+ }
+ if (!validateCoverage(record)) {
+ return false;
+ }
+ record.setInfo(GridInfoCache.getInstance()
+ .getGridInfo(record.getInfo()));
+ return true;
+
+ }
+
+ private boolean validateParameter(GridRecord record) {
+ Parameter parameter = record.getParameter();
+ boolean result = true;
+ if (parameter == null) {
+ result = false;
+ } else if (parameter.getName() == null) {
+ result = false;
+ } else if (parameter.getName().equals("Missing")) {
+ result = false;
+ } else {
+ Parameter dbParameter = ParameterLookup.getInstance()
+ .lookupParameter(parameter, true);
+ if (!parameter.equals(dbParameter)) {
+ // This check is for debugging purposes
+ // if (!parameter.getName().equals(dbParameter.getName())) {
+ // logger.info("Record parameter name(" + parameter.getName()
+ // + ") does not match database("
+ // + dbParameter.getName() + ") "
+ // + record.getDataURI());
+ // }
+ UnitConverter converter = Parameter.compareUnits(parameter,
+ dbParameter);
+ // if (converter == null) {
+ // logger.info("Record parameter unit("
+ // + parameter.getUnitString()
+ // + ") does not match database("
+ // + dbParameter.getUnitString() + ") "
+ // + record.getDataURI());
+ // // For absolute accuracy we should abort if units don't
+ // // match, but currently we will persist it anyway.
+ // // result = false;
+ // } else
+ if (converter != null && converter != UnitConverter.IDENTITY) {
+ Object messageData = record.getMessageData();
+ if (messageData instanceof float[]) {
+ float[] data = (float[]) messageData;
+ for (int i = 0; i < data.length; i++) {
+ data[i] = (float) converter.convert(data[i]);
+ }
+ } else {
+ logger.info("Unable to convert grid data to correct units: "
+ + record.getDataURI());
+ }
+ }
+ }
+ record.setParameter(dbParameter);
+ }
+ if (!result) {
+ logger.info("Discarding record due to missing or unknown parameter mapping: "
+ + record);
+ }
+ return result;
+ }
+
+ private boolean validateCoverage(GridRecord record) {
+ GridCoverage coverage = record.getLocation();
+ if (coverage == null) {
+ logger.info("Discarding record due to missing location: " + record);
+ return false;
+ }
+ GridCoverage dbCoverage = GridCoverageLookup.getInstance().getCoverage(
+ coverage, false);
+ if (coverage == dbCoverage) {
+ return true;
+ }
+ if (dbCoverage == null) {
+ dbCoverage = GridCoverageLookup.getInstance().getCoverage(coverage,
+ true);
+ logger.error("Unable to persist " + record
+ + " because storing the location failed.");
+ if (dbCoverage == null) {
+ return false;
+ }
+ }
+ record.setLocation(dbCoverage);
+ if (!coverage.getId().equals(dbCoverage.getId())) {
+ record.setDataURI(null);
+ try {
+ record.constructDataURI();
+ } catch (PluginException e) {
+ logger.info("Error constructing dataURI: " + record);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean validateLevel(GridRecord record) {
+ boolean result = false;
+ Level level = record.getLevel();
+
+ if (level != null) {
+ MasterLevel ml = level.getMasterLevel();
+
+ if (ml != null && !LevelFactory.UNKNOWN_LEVEL.equals(ml.getName())) {
+ result = true;
+ }
+ }
+
+ if (!result) {
+ logger.info("Discarding record due to missing or unknown level mapping: "
+ + record);
+ }
+ return result;
+ }
+
+ /**
+ * Overridden to clean up orphan GridInfoRecords.
+ */
+ @Override
+ public void delete(List objs) {
+ super.delete(objs);
+ Set orphanedIds = new HashSet(objs.size());
+ StringBuilder sqlString = new StringBuilder(objs.size() * 15 + 80);
+ sqlString
+ .append("select distinct info_id from awips.grid where info_id in (");
+ for (PluginDataObject pdo : objs) {
+ if (pdo instanceof GridRecord) {
+ Integer id = ((GridRecord) pdo).getInfo().getId();
+ if (orphanedIds.add(id)) {
+ if (orphanedIds.size() > 1) {
+ sqlString.append(", ");
+ }
+ sqlString.append(id);
+ }
+ }
+ }
+ sqlString.append(");");
+ try {
+ QueryResult result = (QueryResult) this.executeNativeSql(sqlString
+ .toString());
+ for (int i = 0; i < result.getResultCount(); i++) {
+ orphanedIds.remove((Integer) result.getRowColumnValue(i, 0));
+ }
+ if (!orphanedIds.isEmpty()) {
+ sqlString = new StringBuilder(orphanedIds.size() * 15 + 60);
+ sqlString.append("delete from awips.grid_info where id in (");
+ boolean first = true;
+ for (Integer id : orphanedIds) {
+ if (!first) {
+ sqlString.append(", ");
+ } else {
+ first = false;
+ }
+ sqlString.append(id);
+ }
+ sqlString.append(");");
+ if (purgeModelCacheTopic != null) {
+ this.executeNativeSql(sqlString.toString());
+ EDEXUtil.getMessageProducer().sendAsyncUri(
+ purgeModelCacheTopic, orphanedIds);
+ } else {
+ GridInfoCache.getInstance().purgeCache(
+ new ArrayList(orphanedIds));
+ statusHandler
+ .warn("Unable to purge model cache of clustered edices");
+ }
+ }
+ } catch (DataAccessLayerException e1) {
+ statusHandler.error("Error purging orphaned grid info entries", e1);
+ } catch (EdexException e) {
+ statusHandler.error(
+ "Error sending message to purge grid info topic", e);
+ }
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/dao/GridInfoCache.java b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/dao/GridInfoCache.java
new file mode 100644
index 0000000000..ad4e8bab16
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/dao/GridInfoCache.java
@@ -0,0 +1,112 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.edex.plugin.grid.dao;
+
+import java.lang.ref.SoftReference;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import com.raytheon.uf.common.dataplugin.grid.GridInfoRecord;
+import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject;
+import com.raytheon.uf.edex.database.dao.CoreDao;
+import com.raytheon.uf.edex.database.dao.DaoConfig;
+
+/**
+ * Cache the gridInfo objects from the database to avoid repeated lookups.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * May 21, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+
+public class GridInfoCache {
+
+ private static GridInfoCache instance = new GridInfoCache();
+
+ public static GridInfoCache getInstance() {
+ return instance;
+ }
+
+ private CoreDao dao;
+
+ // A weak hashmap of soft references is used as a SoftSet.
+ private Map> cache = null;
+
+ private GridInfoCache() {
+ cache = Collections
+ .synchronizedMap(new WeakHashMap>());
+ dao = new CoreDao(DaoConfig.forClass(GridInfoRecord.class));
+ }
+
+ public GridInfoRecord getGridInfo(GridInfoRecord record) {
+ GridInfoRecord result = checkLocalCache(record);
+ if (result == null) {
+ synchronized (this) {
+ // It is possible that this query will return multiple results,
+ // for example if the record we are looking for has a null
+ // secondaryId but some db entries have a secondaryId set then
+ // this query will return all matching models ignoring
+ // secondaryId. In general these cases should be rare and small.
+ // So we handle it by caching everything returned and then
+ // double checking the cache.
+ List dbList = dao.queryByExample(record);
+ if (dbList != null && !dbList.isEmpty()) {
+ for (PersistableDataObject pdo : dbList) {
+ GridInfoRecord gir = (GridInfoRecord) pdo;
+ cache.put(gir, new SoftReference(gir));
+ }
+ }
+ result = checkLocalCache(record);
+ if (result == null) {
+ dao.saveOrUpdate(record);
+ result = record;
+ }
+ }
+ }
+ return result;
+ }
+
+ private GridInfoRecord checkLocalCache(GridInfoRecord record) {
+ GridInfoRecord result = null;
+ SoftReference ref = cache.get(record);
+ if (ref != null) {
+ result = ref.get();
+ }
+ return result;
+ }
+
+ public void purgeCache(List modelKeys) {
+ for (Integer key : modelKeys) {
+ cache.remove(key);
+ }
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/handler/GridTreeHandler.java b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/handler/GridTreeHandler.java
new file mode 100644
index 0000000000..8ca65f1f5f
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/handler/GridTreeHandler.java
@@ -0,0 +1,107 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.edex.plugin.grid.handler;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.raytheon.uf.common.dataplugin.grid.GridInfoConstants;
+import com.raytheon.uf.common.dataplugin.grid.GridInfoRecord;
+import com.raytheon.uf.common.dataplugin.grid.dataset.DatasetInfo;
+import com.raytheon.uf.common.dataplugin.grid.dataset.DatasetInfoLookup;
+import com.raytheon.uf.common.dataplugin.grid.request.GetGridTreeRequest;
+import com.raytheon.uf.common.derivparam.tree.DataTree;
+import com.raytheon.uf.common.serialization.comm.IRequestHandler;
+import com.raytheon.uf.edex.database.dao.CoreDao;
+import com.raytheon.uf.edex.database.dao.DaoConfig;
+import com.raytheon.uf.edex.database.query.DatabaseQuery;
+
+/**
+ * Build a DataTree representing all the grid data in the db.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 5, 2012 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+
+public class GridTreeHandler implements IRequestHandler {
+
+ private static final String[] GRIDFIELDS = { GridInfoConstants.DATASET_ID,
+ GridInfoConstants.PARAMETER_ABBREVIATION,
+ GridInfoConstants.PARAMETER_NAME, GridInfoConstants.PARAMETER_UNIT,
+ GridInfoConstants.LEVEL_ID };
+
+ @Override
+ public DataTree handleRequest(GetGridTreeRequest request) throws Exception {
+ DataTree gridTree = null;
+ CoreDao gribDao = null;
+ List> queryResults = null;
+ gribDao = new CoreDao(DaoConfig.forClass(GridInfoRecord.class));
+
+ // if we do not get a table back, just return an empty list
+ gridTree = new DataTree();
+ DatabaseQuery query = new DatabaseQuery(GridInfoRecord.class.getName());
+
+ List distinctFields = Arrays.asList(GRIDFIELDS);
+
+ query.addOrder(distinctFields.get(0), true);
+ query.addDistinctParameter(distinctFields);
+ queryResults = gribDao.queryByCriteria(query);
+ if (queryResults.size() > 0) {
+ for (Object gridField : queryResults) {
+ if (gridField.getClass().isArray()) {
+ ArrayList gridFields = new ArrayList(
+ Arrays.asList((Object[]) gridField));
+ String model = gridFields.get(0).toString();
+ gridTree.addBranch(model, getDt(model), gridFields.get(1)
+ .toString(), gridFields.get(2).toString(),
+ gridFields.get(3).toString(), gridFields.get(4)
+ .toString());
+ }
+ }
+ }
+ return gridTree;
+ }
+
+ private int getDt(String modelName) {
+ DatasetInfo info = DatasetInfoLookup.getInstance().getInfo(modelName);
+ if (info != null && info.getDt() != null) {
+ int dTinSeconds = info.getDt();
+
+ // dT <= 24 is in hours, need to convert to seconds
+ if (Math.abs(dTinSeconds) <= 24) {
+ dTinSeconds *= 3600;
+ }
+ return dTinSeconds;
+ }
+ return -1;
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/topo/StaticTopoData.java b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/topo/StaticTopoData.java
new file mode 100644
index 0000000000..2753f73d24
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/topo/StaticTopoData.java
@@ -0,0 +1,1117 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+
+package com.raytheon.uf.edex.plugin.grid.topo;
+
+import java.awt.Point;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.media.jai.JAI;
+
+import org.geotools.coverage.grid.GeneralGridEnvelope;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridCoverageFactory;
+import org.geotools.coverage.grid.GridGeometry2D;
+import org.geotools.factory.Hints;
+import org.geotools.geometry.DirectPosition2D;
+import org.geotools.geometry.GeneralEnvelope;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.ReferencingFactoryFinder;
+import org.geotools.referencing.operation.AbstractCoordinateOperationFactory;
+import org.geotools.referencing.operation.builder.GridToEnvelopeMapper;
+import org.geotools.referencing.operation.transform.IdentityTransform;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.metadata.spatial.PixelOrientation;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.datum.PixelInCell;
+import org.opengis.referencing.operation.CoordinateOperationFactory;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.TransformException;
+
+import com.raytheon.edex.site.SiteUtil;
+import com.raytheon.uf.common.datastorage.DataStoreFactory;
+import com.raytheon.uf.common.datastorage.IDataStore;
+import com.raytheon.uf.common.datastorage.IDataStore.StoreOp;
+import com.raytheon.uf.common.datastorage.Request;
+import com.raytheon.uf.common.datastorage.StorageException;
+import com.raytheon.uf.common.datastorage.StorageProperties;
+import com.raytheon.uf.common.datastorage.StorageProperties.Compression;
+import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
+import com.raytheon.uf.common.geospatial.CRSCache;
+import com.raytheon.uf.common.geospatial.MapUtil;
+import com.raytheon.uf.common.gridcoverage.GridCoverage;
+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.status.UFStatus.Priority;
+import com.raytheon.uf.common.util.RunProcess;
+import com.raytheon.uf.edex.core.props.PropertiesFactory;
+import com.raytheon.uf.edex.database.cluster.ClusterLockUtils;
+import com.raytheon.uf.edex.database.cluster.ClusterLockUtils.LockState;
+import com.raytheon.uf.edex.database.cluster.ClusterTask;
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * Class used for accessing static topography information for GFE smart inits
+ *
+ *
+ * SOFTWARE HISTORY
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * 09/27/2010 6394 bphillip Initial creation
+ * 10/08/2010 6394 bphillip Rewrote sections for optimal reading and writing performance
+ * 09/19/2011 10955 rferrel Use RunProcess
+ * 04/18/2012 DR 14694 D. Friedman Fixes for static topography generation
+ * 05/09/2012 DR 14939 D. Friedman Fix errors in DR 14694
+ *
+ *
+ *
+ * @author bphillip
+ * @version 1.0
+ */
+public class StaticTopoData {
+ private static final transient IUFStatusHandler statusHandler = UFStatus
+ .getHandler(StaticTopoData.class);
+
+ private static final float DATA_FILL = -9999;
+
+ private static final float TOPO_FILL = -999999;
+
+ /** The HDF5 data store used for accessing the topo data */
+ private IDataStore sTopoDataStore;
+
+ /** The HDF5 data store used for storing the site static topo data */
+ private IDataStore siteDataStore;
+
+ private static final String[] TOPO_FILES = new String[] { "us", "ak",
+ "carib", "pac", "world" };
+
+ private static final String TASK_NAME = "initStaticTopo";
+
+ /** The HDF dataset name for the static topo information for gfe */
+ private static final String STOPO_DATASET = "Topo";
+
+ /** The .dat.gz suffix */
+ private static final String DAT_GZ_SUFFIX = ".dat.gz";
+
+ /**
+ * Margin of extra data to retrieve when requesting the data slab from the
+ * data store
+ */
+ private static final int DATA_MARGIN = 2;
+
+ /** The base directory in which the topo files reside */
+ private static final String FILE_PREFIX = PropertiesFactory.getInstance()
+ .getEnvProperties().getEnvValue("HDF5DIR")
+ + "/topo/";
+
+ /** The file containing the complete static topo data sets */
+ private static final File topoFile = new File(FILE_PREFIX + "staticTopo.h5");
+
+ /** The file containing the site specific static topo data sets */
+ private static final File siteTopoFile = new File(FILE_PREFIX
+ + "modelStaticTopo.h5");
+
+ /** A GridCoverageFactory instance for creating grid coverages */
+ private GridCoverageFactory factory;
+
+ /** HDF5 storage properties used for enabling compression */
+ private static final StorageProperties sp;
+
+ /** The singleton instance */
+ private static StaticTopoData instance;
+
+ // Initializes the storage properties
+ static {
+ sp = new StorageProperties();
+ sp.setCompression(Compression.LZF);
+ sp.setChunked(true);
+ }
+
+ /**
+ * Gets the singleton instance of StaticTopoData
+ *
+ * @return The singleton instance
+ */
+ public static synchronized StaticTopoData getInstance() {
+ if (instance == null) {
+ instance = new StaticTopoData();
+ }
+ return instance;
+ }
+
+ /**
+ * Creates a new StaticTopoData instance
+ */
+ private StaticTopoData() {
+ this.sTopoDataStore = DataStoreFactory.getDataStore(topoFile);
+ this.siteDataStore = DataStoreFactory.getDataStore(siteTopoFile);
+
+ this.factory = new GridCoverageFactory();
+ initStopoData();
+ }
+
+ /**
+ * Initializes the static topo data from the raw data
+ */
+ private void initStopoData() {
+ statusHandler.handle(Priority.INFO, "Initializing static topo data");
+
+ try {
+ ClusterTask ct = null;
+ do {
+ ct = ClusterLockUtils.lock(TASK_NAME, "unpack", 300000, true);
+ } while (!LockState.SUCCESSFUL.equals(ct.getLockState()));
+
+ try {
+ if (!topoFileExists()) {
+ // TODO: This will fail in a clustered server environment
+ // since
+ // static topo isn't installed to dx3/4
+ statusHandler.handle(Priority.INFO,
+ "Static Topo file not found. Creating it...");
+
+ // Initializes the World topo data
+ statusHandler.handle(Priority.INFO,
+ "Initializing World Topo Data...");
+ // DR#10955
+ RunProcess
+ .getRunProcess()
+ .exec("gunzip " + FILE_PREFIX + "worldTopo"
+ + DAT_GZ_SUFFIX).waitFor();
+ readTopoFile("world");
+ statusHandler.handle(Priority.INFO,
+ "World Topo Data Initialized!");
+
+ // Initializes the US topo data
+ statusHandler.handle(Priority.INFO,
+ "Initializing US Topo Data...");
+ // DR#10955
+ RunProcess
+ .getRunProcess()
+ .exec("gunzip " + FILE_PREFIX + "usTopo"
+ + DAT_GZ_SUFFIX).waitFor();
+ readTopoFile("us");
+ statusHandler.handle(Priority.INFO,
+ "US Topo Data Initialized!");
+
+ // Initializes the Carribean topo data
+ statusHandler.handle(Priority.INFO,
+ "Initializing Carribean Topo Data...");
+ // DR#10955
+ RunProcess
+ .getRunProcess()
+ .exec("gunzip " + FILE_PREFIX + "caribTopo"
+ + DAT_GZ_SUFFIX).waitFor();
+ readTopoFile("carib");
+ statusHandler.handle(Priority.INFO,
+ "Carribean Topo Data Initialized!");
+
+ // Initializes the Alaska topo data
+ statusHandler.handle(Priority.INFO,
+ "Initializing Alaska Topo Data...");
+ // DR#10955
+ RunProcess
+ .getRunProcess()
+ .exec("gunzip " + FILE_PREFIX + "akTopo"
+ + DAT_GZ_SUFFIX).waitFor();
+ readTopoFile("ak");
+ statusHandler.handle(Priority.INFO,
+ "Alaska Topo Data Initialized!");
+
+ // Initializes the Pacific topo data
+ statusHandler.handle(Priority.INFO,
+ "Initializing Pacific Topo Data...");
+ // DR#10955
+ RunProcess
+ .getRunProcess()
+ .exec("gunzip " + FILE_PREFIX + "pacTopo"
+ + DAT_GZ_SUFFIX).waitFor();
+ readTopoFile("pac");
+ statusHandler.handle(Priority.INFO,
+ "Pacific Topo Data Initialized!");
+ splitPacific();
+ }
+ } finally {
+ if (ct != null) {
+ ClusterLockUtils.unlock(ct, false);
+ }
+ }
+
+ initAttributes();
+ } catch (Exception e) {
+ statusHandler.handle(Priority.CRITICAL,
+ "Error initializing static topo data!", e);
+ }
+ statusHandler.handle(Priority.INFO, "Static topo data initialized");
+ }
+
+ /**
+ * Splits the Pacific grid into east and west hemisphere chunks to reduce
+ * memory usage
+ *
+ * @throws Exception
+ */
+ private void splitPacific() throws Exception {
+ Map pacAttributes = TopoAttributes.getAttributes("pac");
+ int nx = (Integer) pacAttributes.get(TopoAttributes.NX);
+ int ny = (Integer) pacAttributes.get(TopoAttributes.NY);
+
+ Map attributes = new HashMap();
+ attributes.putAll(pacAttributes);
+ attributes.put(TopoAttributes.NX, nx / 2);
+ attributes.put(TopoAttributes.UR_LON, new Float(180.0f));
+ float[] floatData = this.getSlab("pac", 0, 0, nx / 2, ny);
+ FloatDataRecord eastRecord = new FloatDataRecord("pac_east", "/",
+ floatData, 2, new long[] { nx / 2, ny });
+ sTopoDataStore.addDataRecord(eastRecord, sp);
+
+ FloatDataRecord attributeSet = new FloatDataRecord("attr" + "pac_east",
+ "/", new float[] { 0 });
+ attributeSet.setDataAttributes(attributes);
+ sTopoDataStore.addDataRecord(attributeSet, sp);
+ sTopoDataStore.store();
+
+ attributes = new HashMap();
+ attributes.putAll(pacAttributes);
+ attributes.put(TopoAttributes.NX, nx / 2);
+ attributes.put(TopoAttributes.LL_LON, new Float(-180.0f));
+ floatData = this.getSlab("pac", nx / 2, 0, nx, ny);
+ FloatDataRecord westRecord = new FloatDataRecord("pac_west", "/",
+ floatData, 2, new long[] { nx / 2, ny });
+ attributeSet = new FloatDataRecord("attr" + "pac_west", "/",
+ new float[] { 0 });
+ attributeSet.setDataAttributes(attributes);
+ sTopoDataStore.addDataRecord(attributeSet, sp);
+ sTopoDataStore.addDataRecord(westRecord, sp);
+ sTopoDataStore.store();
+ sTopoDataStore.delete("pac");
+ sTopoDataStore.delete("attrpac");
+
+ }
+
+ /**
+ * Checks to see if the topo file exists
+ *
+ * @return True if the file exists
+ */
+ private boolean topoFileExists() {
+ try {
+ String[] modelArray = sTopoDataStore.getDatasets("/");
+ if (modelArray.length == 0) {
+ return false;
+ }
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Initializes the attributes so they can be easily retrieved
+ *
+ * @throws Exception
+ */
+ private void initAttributes() throws Exception {
+ TopoAttributes.attributeMap.remove("world");
+ TopoAttributes.attributeMap.remove("pac");
+ String[] dataSets = sTopoDataStore.getDatasets("/");
+
+ for (String dataset : dataSets) {
+ if (dataset.startsWith("attr")) {
+ TopoAttributes.attributeMap.put(
+ dataset.replace("attr", ""),
+ sTopoDataStore.retrieve("/", dataset,
+ Request.buildPointRequest(new Point(0, 0)))
+ .getDataAttributes());
+ }
+ }
+ }
+
+ /**
+ * Initializes the topography data for the given site. The data is extracted
+ * from the static topo file and resampled according to the site location
+ * information
+ *
+ * @param modelName
+ * The site for which to initalize the topo data
+ * @param config
+ * The site's configuration information
+ * @throws StorageException
+ * @throws SerializationException
+ * If the topography data cannot be initialized for the given
+ * site
+ */
+ public void initStopoData(GridCoverage coverage) throws StorageException,
+ SerializationException {
+ if (coverage.getNx() < 0 || coverage.getNy() < 0) {
+ statusHandler.handle(Priority.PROBLEM, coverage.getName()
+ + " is not applicable to " + SiteUtil.getSite()
+ + ". Skipping.");
+ return;
+ }
+ GridGeometry2D inGeom = MapUtil.getGridGeometry(coverage);
+
+ // Gets the location data and extracts it from the static topo file
+ float[] finalData = null;
+ finalData = getTopoData(inGeom, coverage.getCrs(), coverage.getNx(),
+ coverage.getNy());
+
+ // Create an HDF5 data record and store it
+ FloatDataRecord outRecord = new FloatDataRecord(STOPO_DATASET,
+ coverage.spatialKey(), finalData, 2, new long[] {
+ inGeom.getGridRange().getHigh(0) + 1,
+ inGeom.getGridRange().getHigh(1) + 1 });
+ siteDataStore.addDataRecord(outRecord, sp);
+ siteDataStore.store(StoreOp.REPLACE);
+
+ statusHandler
+ .handle(Priority.INFO,
+ "Stopo data successfully initialized for "
+ + coverage.getName());
+ }
+
+ /**
+ * Private method used by the initialization code to see if the static topo
+ * data for a coverage has been initialized
+ */
+ public boolean checkModelTopo(GridCoverage coverage) {
+ ClusterTask ct = ClusterLockUtils.lock(TASK_NAME,
+ coverage.spatialKey(), 120000, false);
+
+ if (LockState.SUCCESSFUL.equals(ct.getLockState())) {
+ // set processed to true regardless of successfully
+ // update coverage so we don't infinite loop
+ try {
+ if (!topoExists(coverage)) {
+ statusHandler.handle(
+ Priority.INFO,
+ "Initializing static topo for grid "
+ + coverage.getName());
+ initStopoData(coverage);
+ }
+ } catch (Exception e) {
+ statusHandler.handle(
+ Priority.INFO,
+ "Error storing static topo data for "
+ + coverage.getName(), e);
+ } finally {
+ ClusterLockUtils.unlock(ct, false);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Chekcs if the static topo data for a model exists in the file
+ *
+ * @param modelName
+ * The model to check
+ * @return True if the data exists, else false
+ * @throws GribException
+ */
+ private boolean topoExists(GridCoverage coverage) {
+
+ List dataSets = null;
+ try {
+ String[] modelArray = siteDataStore.getDatasets(coverage
+ .spatialKey());
+ dataSets = Arrays.asList(modelArray);
+ } catch (Exception e) {
+ return false;
+ }
+
+ if (dataSets.contains(STOPO_DATASET)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieves the static topo data for the given site
+ *
+ * @param modelName
+ * The site for which to get the static topo data
+ * @return The static topo data
+ * @throws GribException
+ * If an error occurs while retrieving the topo data
+ */
+ public FloatDataRecord getStopoData(GridCoverage coverage) {
+ if (!topoExists(coverage)) {
+ while (!checkModelTopo(coverage)) {
+ }
+ }
+ FloatDataRecord record = null;
+ try {
+ record = (FloatDataRecord) siteDataStore.retrieve(
+ coverage.spatialKey(), STOPO_DATASET, Request.ALL);
+
+ } catch (Exception e) {
+ statusHandler.handle(
+ Priority.INFO,
+ "Static topo data does not exist for grid "
+ + coverage.getName());
+ return null;
+ }
+ return record;
+ }
+
+ /**
+ * Extracts the the topo data from each of the topo data sets.
+ *
+ * @param inGeom
+ * The geometry of the data to be requested
+ * @param inCrs
+ * The coordinate reference system of the desired data
+ * @return A float array containing the extracted topo data
+ * @throws GribException
+ * If the data cannot be extracted
+ */
+ private float[] getTopoData(GridGeometry2D inGeom,
+ CoordinateReferenceSystem inCrs, int coverageNx, int coverageNy) {
+
+ /*
+ * Iterate through each of the data sets until the returned data set is
+ * fully populated
+ */
+ float[] finalData = null;
+
+ for (String topoData : TOPO_FILES) {
+ for (String dataSet : TopoAttributes.attributeMap.keySet()) {
+ if (dataSet.startsWith(topoData)) {
+ try {
+ finalData = extractTopoData(finalData, inCrs, inGeom,
+ coverageNx, coverageNy, dataSet);
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+ if (isPopulated(finalData)) {
+ break;
+ }
+ }
+
+ for (int i = 0; i < finalData.length; i++) {
+ float v = finalData[i];
+ if (Float.isNaN(v))
+ finalData[i] = TOPO_FILL;
+ else if (v == DATA_FILL || (v > -0.5 && v < 0.5))
+ finalData[i] = 0.0f;
+ else
+ finalData[i] = v;
+ }
+ return finalData;
+
+ }
+
+ /**
+ * Checks the provided array to see if it has been fully populated
+ *
+ * @param data
+ * The data to check
+ * @return True if the data is fully populated (i.e. There are not NaN
+ * values in the array)
+ */
+ private boolean isPopulated(float[] data) {
+ if (data == null) {
+ return false;
+ }
+ for (int i = 0; i < data.length; i++) {
+ if (Float.isNaN(data[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Extracts the topo data from the specified data set. The data is populated
+ * into the returned array
+ *
+ * @param finalData
+ * The topo data to be returned
+ * @param inCrs
+ * The CRS of the requested location
+ * @param inGeom
+ * The geometry of the requested location
+ * @param name
+ * The name of the data set from which to get the data
+ * @return The populated array of topo data
+ * @throws Exception
+ * If the data cannot be read
+ */
+ private float[] extractTopoData(float[] finalData,
+ CoordinateReferenceSystem inCrs, GridGeometry2D inGeom,
+ int coverageNx, int coverageNy, String name) throws Exception {
+ String suffix = "";
+ String[] tokens = name.split("-");
+ if (tokens.length == 2) {
+ name = tokens[0];
+ suffix = tokens[1];
+ }
+ statusHandler.handle(Priority.INFO, "Extracting topo data from " + name
+ + suffix);
+
+ // Gets the attributes for the data set
+ Map attributes = TopoAttributes.getAttributes(name);
+ int nx = (Integer) attributes.get(TopoAttributes.NX);
+ int ny = (Integer) attributes.get(TopoAttributes.NY);
+ double llLat = MapUtil.correctLat((Float) attributes
+ .get(TopoAttributes.LL_LAT));
+ double llLon = MapUtil.correctLon((Float) attributes
+ .get(TopoAttributes.LL_LON));
+ double urLat = MapUtil.correctLat((Float) attributes
+ .get(TopoAttributes.UR_LAT));
+ double urLon = MapUtil.correctLon((Float) attributes
+ .get(TopoAttributes.UR_LON));
+
+ // Create the CRS of the topo data
+ CoordinateReferenceSystem topoCrs = CRSCache.getInstance()
+ .getCoordinateReferenceSystem(
+ (String) attributes.get(TopoAttributes.CRS));
+
+ // Create the geometry of the topo data
+ GridGeometry2D topoGeom = createGridGeometry(topoCrs, new Coordinate(
+ llLon, llLat), new Coordinate(urLon, urLat), nx, ny);
+
+ ReferencedEnvelope refEnv = new ReferencedEnvelope(
+ inGeom.getEnvelope2D(), inCrs);
+ refEnv = refEnv.transform(topoCrs, true);
+
+ DirectPosition upperCorner = topoGeom.getCRSToGrid2D(
+ PixelOrientation.UPPER_LEFT).transform(refEnv.getUpperCorner(),
+ null);
+ DirectPosition lowerCorner = topoGeom.getCRSToGrid2D(
+ PixelOrientation.UPPER_LEFT).transform(refEnv.getLowerCorner(),
+ null);
+
+ int minx = (int) Math.floor(Math.min(lowerCorner.getOrdinate(0),
+ upperCorner.getOrdinate(0)));
+ int maxx = (int) Math.ceil(Math.max(upperCorner.getOrdinate(0),
+ lowerCorner.getOrdinate(0)));
+ int miny = (int) Math.floor(Math.min(upperCorner.getOrdinate(1),
+ lowerCorner.getOrdinate(1)));
+ int maxy = (int) Math.ceil(Math.max(lowerCorner.getOrdinate(1),
+ upperCorner.getOrdinate(1)));
+
+ if ("world".equals(name)) {
+ if (minx - DATA_MARGIN < 0 || miny - DATA_MARGIN < 0
+ || maxx + DATA_MARGIN >= nx || maxy + DATA_MARGIN >= ny) {
+ /*
+ * TODO: Have to do quite a bit more for minimal world
+ * projection subset. Just load the whole thing for now.
+ */
+ minx = miny = 0;
+ maxx = nx;
+ maxy = ny;
+ }
+ } else {
+ if (minx - DATA_MARGIN >= 0) {
+ minx -= DATA_MARGIN;
+ } else {
+ minx = 0;
+ }
+
+ if (miny - DATA_MARGIN >= 0) {
+ miny -= DATA_MARGIN;
+ } else {
+ miny = 0;
+ }
+
+ if (maxx + DATA_MARGIN <= nx) {
+ maxx += DATA_MARGIN;
+ } else {
+ maxx = nx;
+ }
+
+ if (maxy + DATA_MARGIN <= ny) {
+ maxy += DATA_MARGIN;
+ } else {
+ maxy = ny;
+ }
+ }
+
+ double[] input = new double[] { minx, miny, maxx, maxy };
+ double[] output = new double[input.length];
+
+ topoGeom.getGridToCRS(PixelInCell.CELL_CORNER).transform(input, 0,
+ output, 0, input.length / 2);
+
+ DirectPosition dpUpper = new DirectPosition2D(Math.max(output[0],
+ output[2]), Math.max(output[1], output[3]));
+ DirectPosition dpLower = new DirectPosition2D(Math.min(output[0],
+ output[2]), Math.min(output[1], output[3]));
+
+ Coordinate upperCoordinate = new Coordinate(dpUpper.getCoordinate()[0],
+ dpUpper.getCoordinate()[1]);
+ Coordinate lowerCoordinate = new Coordinate(dpLower.getCoordinate()[0],
+ dpLower.getCoordinate()[1]);
+
+ Envelope tempEnv = new Envelope(upperCoordinate, lowerCoordinate);
+ ReferencedEnvelope correctedRefEnv = new ReferencedEnvelope(tempEnv,
+ topoCrs);
+
+ int slabNx = maxx - minx;
+ int slabNy = maxy - miny;
+
+ // The topo data does not intersect the desired region, so return
+ if (slabNx < 0 || slabNy < 0) {
+ if (finalData == null) {
+ finalData = new float[coverageNx * coverageNy];
+ Arrays.fill(finalData, Float.NaN);
+ }
+ return finalData;
+ }
+
+ // Add one to each of the maxx and maxy since getting slab is exclusive
+ // of the final point
+ float[][] slabData = this.to2DArray(slabNx, slabNy,
+ this.getSlab(name, minx, miny, maxx, maxy));
+
+ // Create the coverage object from the data and the geometry
+ GridCoverage2D topoCoverage = factory.create("coverage", slabData,
+ correctedRefEnv);
+ // Reproject the data into the requested CRS and geometry
+ float[] f1 = null;
+ try {
+ f1 = simpleResample(topoCoverage, slabData, inGeom, name, minx,
+ miny);
+ } catch (Exception e) {
+ statusHandler.error("rasample failed", e);
+ throw e;
+ }
+
+ if (finalData == null) {
+ finalData = f1;
+ } else {
+ for (int idx = 0; idx < f1.length; idx++) {
+ if (Float.isNaN(finalData[idx]) || finalData[idx] <= DATA_FILL) {
+ finalData[idx] = f1[idx];
+ }
+ }
+ }
+ JAI.getDefaultInstance().getTileCache().flush();
+ return finalData;
+ }
+
+ float[] simpleResample(GridCoverage2D sourceGC, float[][] sourceData,
+ GridGeometry2D targetGG, String pfx, int minx, int miny) {
+ int sourceWidth = sourceGC.getGridGeometry().getGridRange2D()
+ .getSpan(0);
+ int sourceHeight = sourceGC.getGridGeometry().getGridRange2D()
+ .getSpan(1);
+ int targetWidth = targetGG.getGridRange2D().getSpan(0);
+ int targetHeight = targetGG.getGridRange2D().getSpan(1);
+ float[] output = new float[targetWidth * targetHeight];
+ Arrays.fill(output, Float.NaN);
+
+ ArrayList transforms = new ArrayList();
+ ArrayList toGeoXforms = new ArrayList();
+ ArrayList sourceToGeoXforms = new ArrayList();
+
+ MathTransform targetGtoCRS = targetGG
+ .getGridToCRS(PixelInCell.CELL_CENTER);
+ MathTransform sourceCRStoG = sourceGC.getGridGeometry().getCRSToGrid2D(
+ PixelOrientation.CENTER);
+ CoordinateReferenceSystem targetCRS = targetGG
+ .getCoordinateReferenceSystem();
+ CoordinateReferenceSystem sourceCRS = sourceGC
+ .getCoordinateReferenceSystem();
+
+ transforms.add(targetGtoCRS);
+ if (!CRS.equalsIgnoreMetadata(sourceCRS, targetCRS)) {
+ GeographicCRS sourceGeoCRS = null;
+ GeographicCRS targetGeoCRS = null;
+ if (sourceCRS instanceof ProjectedCRS) {
+ sourceGeoCRS = ((ProjectedCRS) sourceCRS).getBaseCRS();
+ }
+ if (targetCRS instanceof ProjectedCRS) {
+ targetGeoCRS = ((ProjectedCRS) targetCRS).getBaseCRS();
+ }
+ try {
+ transforms.add(CRS.findMathTransform(targetCRS, targetGeoCRS,
+ true));
+ toGeoXforms.addAll(transforms);
+ if (CRS.equalsIgnoreMetadata(sourceGeoCRS, targetGeoCRS)) {
+ // nothing...
+ } else {
+ transforms.add(CRS.findMathTransform(targetGeoCRS,
+ sourceGeoCRS));
+ }
+ transforms.add(CRS.findMathTransform(sourceGeoCRS, sourceCRS,
+ true));
+ sourceToGeoXforms.add(0,
+ CRS.findMathTransform(sourceCRS, sourceGeoCRS));
+ } catch (FactoryException e) {
+ // TODO: log
+ return output;
+ }
+ }
+ transforms.add(sourceCRStoG);
+ sourceToGeoXforms.add(0,
+ sourceGC.getGridGeometry()
+ .getGridToCRS(PixelInCell.CELL_CENTER));
+
+ MathTransform mt;
+ try {
+ mt = concatenateTransforms(transforms);
+ } catch (FactoryException e1) {
+ // TODO: log
+ return output;
+ }
+
+ double[] coord = new double[2];
+
+ /*
+ * Output index. Assumes we iterate top-left to bottom-right in
+ * row-major order.
+ */
+ int oi = 0;
+ for (int y = 0; y < targetHeight; ++y) {
+ for (int x = 0; x < targetWidth; ++x, ++oi) {
+ coord[0] = x;
+ coord[1] = y;
+ try {
+ mt.transform(coord, 0, coord, 0, 1);
+ } catch (TransformException e) {
+ continue;
+ }
+
+ // Integer cell coordinates of upper-left cell of the 2x2 cell
+ // sample area
+ int sulx = (int) coord[0];
+ int suly = (int) coord[1];
+
+ double fx = coord[0] - sulx;
+ double fy = coord[1] - suly;
+
+ double tv = 0; // sum of weighted valid values
+ double tw = 0; // sum of valid weights
+ float v0;
+ double w0;
+ if (sulx >= 0 && suly >= 0 && sulx < sourceWidth - 1
+ && suly < sourceHeight - 1) {
+ if (valid(v0 = fix(sourceData[suly][sulx]))) {
+ w0 = (1 - fx) * (1 - fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ if (valid(v0 = fix(sourceData[suly][sulx + 1]))) {
+ w0 = (fx) * (1 - fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ if (valid(v0 = fix(sourceData[suly + 1][sulx]))) {
+ w0 = (1 - fx) * (fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ if (valid(v0 = fix(sourceData[suly + 1][sulx + 1]))) {
+ w0 = (fx) * (fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ } else {
+ if (isValidCoord(sulx, suly, sourceWidth, sourceHeight)
+ && valid(v0 = fix(sourceData[suly][sulx]))) {
+ w0 = (1 - fx) * (1 - fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ if (isValidCoord(sulx + 1, suly, sourceWidth, sourceHeight)
+ && valid(v0 = fix(sourceData[suly][sulx + 1]))) {
+ w0 = (fx) * (1 - fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ if (isValidCoord(sulx, suly + 1, sourceWidth, sourceHeight)
+ && valid(v0 = fix(sourceData[suly + 1][sulx]))) {
+ w0 = (1 - fx) * (fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ if (isValidCoord(sulx + 1, suly + 1, sourceWidth,
+ sourceHeight)
+ && valid(v0 = fix(sourceData[suly + 1][sulx + 1]))) {
+ w0 = (fx) * (fy);
+ tv += v0 * w0;
+ tw += w0;
+ }
+ }
+ if (tw != 0) {
+ output[oi] = (float) (tv / tw);
+ }
+ }
+ }
+
+ return output;
+
+ }
+
+ private static final boolean isValidCoord(int ulx, int uly, int nx, int ny) {
+ return ulx >= 0 && uly >= 0 && ulx < nx && uly < ny;
+ }
+
+ private static final boolean valid(float v) {
+ return !Float.isNaN(v) && v > DATA_FILL;
+ }
+
+ // A1: passes N -9999 to test_grhi_remap, setting
+ // all source -9999 values to 0.
+ private static float fix(float v) {
+ return v > DATA_FILL ? v : 0;
+ }
+
+ private MathTransform concatenateTransforms(
+ ArrayList transforms) throws FactoryException {
+ Hints hints = new Hints();
+ final CoordinateOperationFactory factory = ReferencingFactoryFinder
+ .getCoordinateOperationFactory(hints);
+ final MathTransformFactory mtFactory;
+ if (factory instanceof AbstractCoordinateOperationFactory) {
+ mtFactory = ((AbstractCoordinateOperationFactory) factory)
+ .getMathTransformFactory();
+ } else {
+ mtFactory = ReferencingFactoryFinder.getMathTransformFactory(hints);
+ }
+
+ MathTransform mt = null;
+ for (MathTransform mti : transforms/*
+ * int i = 0; i < transforms.size();
+ * ++i
+ */) {
+ if (mt == null)
+ mt = mti;
+ else {
+ mt = mtFactory.createConcatenatedTransform(mt, mti);
+ }
+ }
+
+ return mt != null ? mt : IdentityTransform.create(2);
+ }
+
+ /**
+ * Reads the raw data from the topo files
+ *
+ * @param name
+ * The name of the topo data set
+ * @param llLat
+ * The lower left latitude
+ * @param llLon
+ * The lower left longitude
+ * @param urLat
+ * The upper right latitude
+ * @param urLon
+ * The upper right longitude
+ * @param latCenter
+ * The central latitude
+ * @param lonCenter
+ * The central longitude
+ * @param nx
+ * The number of x axis points
+ * @param ny
+ * The number of y axis points
+ * @throws Exception
+ * If the data cannot be read
+ */
+ private void readTopoFile(String name) throws Exception {
+
+ Map dataAttributes = TopoAttributes.getAttributes(name);
+ int nx = (Integer) dataAttributes.get(TopoAttributes.NX);
+ int ny = (Integer) dataAttributes.get(TopoAttributes.NY);
+ long[] sizes = new long[] { nx, ny };
+
+ // Store the data
+ FloatDataRecord dataRec = new FloatDataRecord(name, "/", null, 2, sizes);
+ dataRec.setFillValue(Float.NaN);
+
+ sTopoDataStore.createDataset(dataRec);
+
+ // Create the new input stream from which to read
+ FileInputStream in = new FileInputStream(FILE_PREFIX + name
+ + "Topo.dat");
+
+ // Create a byte buffer to store the read data
+ ByteBuffer bb = ByteBuffer.allocate(2);
+ bb.order(ByteOrder.BIG_ENDIAN);
+
+ byte[] bbuf = new byte[nx * 2];
+ int index = 0;
+ int rowIndex = 0;
+
+ // Create an array to hold the data read
+ float[] rawData = new float[nx];
+
+ sizes[1] = 1;
+ // Read in the data
+ while (in.available() > 0) {
+ if (in.read(bbuf) == -1) {
+ break;
+ }
+ for (int i = 0; i < nx * 2; i += 2) {
+ bb.clear();
+ bb.put(bbuf[i]);
+ bb.put(bbuf[i + 1]);
+ rawData[index] = bb.getShort(0);
+
+ index++;
+ if (index == nx) {
+ FloatDataRecord row = new FloatDataRecord(name, "/",
+ rawData, 2, sizes);
+ row.setMinIndex(new long[] { 0, rowIndex });
+ sTopoDataStore.addDataRecord(row, sp);
+ sTopoDataStore.store();
+ index = 0;
+ rowIndex++;
+ }
+ }
+ }
+
+ FloatDataRecord attributeSet = new FloatDataRecord("attr" + name, "/",
+ new float[] { 0 });
+ attributeSet.setDataAttributes(dataAttributes);
+ sTopoDataStore.addDataRecord(attributeSet, sp);
+ sTopoDataStore.store();
+ in.close();
+ }
+
+ /**
+ * Creates a grid geometry object from the provided information
+ *
+ * @param crs
+ * The coordinate reference system
+ * @param llCoord
+ * The lower left coordinate
+ * @param urCoord
+ * The upper right coordinate
+ * @param nx
+ * The x axis points
+ * @param ny
+ * The y axis points
+ * @return The generated geometry
+ * @throws TransformException
+ * @throws MismatchedDimensionException
+ * @throws FactoryException
+ * @throws GribException
+ * If the geometry cannot be created
+ */
+ private GridGeometry2D createGridGeometry(CoordinateReferenceSystem crs,
+ Coordinate llCoord, Coordinate urCoord, int nx, int ny)
+ throws MismatchedDimensionException, TransformException,
+ FactoryException {
+ MathTransform WGS84toPROJCRS = MapUtil.getTransformFromLatLon(crs);
+
+ GeneralEnvelope envelope = new GeneralEnvelope(2);
+
+ DirectPosition ll = WGS84toPROJCRS.transform(new DirectPosition2D(
+ llCoord.x, llCoord.y), null);
+
+ DirectPosition ur = WGS84toPROJCRS.transform(new DirectPosition2D(
+ urCoord.x, urCoord.y), null);
+
+ envelope.setRange(0, Math.min(ll.getOrdinate(0), ur.getOrdinate(0)),
+ Math.max(ll.getOrdinate(0), ur.getOrdinate(0)));
+ envelope.setRange(1, Math.min(ll.getOrdinate(1), ur.getOrdinate(1)),
+ Math.max(ll.getOrdinate(1), ur.getOrdinate(1)));
+
+ envelope.setCoordinateReferenceSystem(crs);
+
+ GridToEnvelopeMapper mapper = new GridToEnvelopeMapper();
+ mapper.setEnvelope(envelope);
+ mapper.setGridRange(new GeneralGridEnvelope(new int[] { 1, 1 },
+ new int[] { nx, ny }, false));
+ mapper.setPixelAnchor(PixelInCell.CELL_CENTER);
+ mapper.setReverseAxis(new boolean[] { false, true });
+ MathTransform mt = mapper.createTransform();
+
+ return new GridGeometry2D(PixelInCell.CELL_CORNER, mt, envelope, null);
+ }
+
+ /**
+ * Retrieves a slab of data from a data set and returns a float array
+ * containing the data
+ *
+ * @param name
+ * The name of the data set to get the data slab from
+ * @param minX
+ * The starting x offset
+ * @param minY
+ * The starting y offset
+ * @param maxX
+ * The ending x offset
+ * @param maxY
+ * The endgin y offset
+ * @return The extracted slab of data
+ * @throws StorageException
+ * @throws FileNotFoundException
+ * If the data slab cannot be read
+ */
+ private float[] getSlab(String name, int minX, int minY, int maxX, int maxY)
+ throws FileNotFoundException, StorageException {
+ return ((FloatDataRecord) sTopoDataStore.retrieve(
+ "/",
+ name,
+ Request.buildSlab(new int[] { minX, minY }, new int[] { maxX,
+ maxY }))).getFloatData();
+
+ }
+
+ /**
+ * Utility method to flip a 1-D array into a 2-D array
+ *
+ * @param nx
+ * The x axis points
+ * @param ny
+ * The y axis points
+ * @param data
+ * The 1-D data array
+ * @return The 2-D data array
+ */
+ private float[][] to2DArray(int nx, int ny, float[] data) {
+ float[][] matrix = new float[ny][nx];
+
+ for (int i = 0; i < nx; i++) {
+ for (int j = 0; j < ny; j++) {
+ matrix[j][i] = data[j * nx + i];
+ }
+ }
+ return matrix;
+ }
+
+}
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/topo/TopoAttributes.java b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/topo/TopoAttributes.java
new file mode 100644
index 0000000000..ffe6468b68
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/src/com/raytheon/uf/edex/plugin/grid/topo/TopoAttributes.java
@@ -0,0 +1,189 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+
+package com.raytheon.uf.edex.plugin.grid.topo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.geotools.referencing.operation.DefaultMathTransformFactory;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import com.raytheon.uf.common.geospatial.MapUtil;
+import com.raytheon.uf.common.status.IUFStatusHandler;
+import com.raytheon.uf.common.status.UFStatus;
+import com.raytheon.uf.common.status.UFStatus.Priority;
+
+/**
+ * Static class used for holding the attributes of the static topo data
+ *
+ *
+ * SOFTWARE HISTORY
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * 11/09/2010 6394 bphillip Initial creation
+ *
+ *
+ * @author bphillip
+ * @version 1.0
+ */
+public class TopoAttributes {
+ private static final transient IUFStatusHandler statusHandler = UFStatus
+ .getHandler(TopoAttributes.class);
+
+ /** Lower left latitude attribute name */
+ public static final String LL_LAT = "llLat";
+
+ /** Lower left longitude attribute name */
+ public static final String LL_LON = "llLon";
+
+ /** Upper right latitude attribute name */
+ public static final String UR_LAT = "urLat";
+
+ /** Upper right longitude attribute name */
+ public static final String UR_LON = "urLon";
+
+ /** Nx attribute name */
+ public static final String NX = "nx";
+
+ /** Ny attribute name */
+ public static final String NY = "ny";
+
+ /** Central meridian attribute name */
+ public static final String CENTRAL_MERIDIAN = "central_meridian";
+
+ /** Latitude of origin attribute name */
+ public static final String LAT_OF_ORIGIN = "latOfOrigin";
+
+ /** CRS attribute name */
+ public static final String CRS = "CRS";
+
+ /** Map containing the attributes for the static topo data */
+ public static Map> attributeMap = new HashMap>();
+
+ static {
+ createAttributeMap("ak", 61.968945f, 150.32922f, 47.7384f, -128.74811f,
+ 4270, 2800, -150f, 90f);
+ createAttributeMap("carib", 26.831362f, -75.716293f, 8.909350f,
+ -56.794250f, 2271, 2151, 0f, 0f);
+ createAttributeMap("us", 16.114336f, -127.13067f, 51.825356f,
+ -49.03707f, 6138, 4610, -100f, 45f);
+ createAttributeMap("pac", -34.99583f, 120.004166f, 39.995834f,
+ -120.004166f, 14400, 9000, 0f, 0f);
+ createAttributeMap("world", -89.979164f, -180.0f, 89.979164f, 180.0f,
+ 8642, 4320, 0f, 0f);
+
+ }
+
+ /**
+ * Retrieves the attributes for a static topo data set
+ *
+ * @param name
+ * The name of the static topo data set
+ * @return The attribute for the requested data set
+ */
+ public static Map getAttributes(String name) {
+ return attributeMap.get(name);
+ }
+
+ /**
+ * Creates an attribute map with the provided parameters
+ *
+ * @param name
+ * The name of the static topo data set
+ * @param llLat
+ * The lower left latitude
+ * @param llLon
+ * The lower left longitude
+ * @param urLat
+ * The upper right latitude
+ * @param urLon
+ * The upper right longitude
+ * @param nx
+ * Number of points on the x axis
+ * @param ny
+ * Number of points on the y axis
+ * @param central_meridian
+ * The central meridian
+ * @param latOfOrigin
+ * The latitude of origin
+ */
+ private static void createAttributeMap(String name, float llLat,
+ float llLon, float urLat, float urLon, int nx, int ny,
+ float central_meridian, float latOfOrigin) {
+
+ Map attributes = new HashMap();
+ attributes.put(LL_LAT, new Float(llLat));
+ attributes.put(LL_LON, new Float(llLon));
+ attributes.put(UR_LAT, new Float(urLat));
+ attributes.put(UR_LON, new Float(urLon));
+ attributes.put(NX, new Integer(nx));
+ attributes.put(NY, new Integer(ny));
+ attributes.put(CENTRAL_MERIDIAN, new Float(central_meridian));
+ attributes.put(LAT_OF_ORIGIN, new Float(latOfOrigin));
+ if (name.equals("us")) {
+ try {
+ attributes.put(
+ CRS,
+ initUSProjectionData("US", latOfOrigin,
+ central_meridian).toWKT());
+ } catch (Exception e) {
+ statusHandler.handle(Priority.INFO, "Error creating US CRS");
+ }
+ } else if (name.equals("ak")) {
+ attributes.put(
+ CRS,
+ MapUtil.constructStereographic(6371200.0, 6371200.0,
+ latOfOrigin, central_meridian).toWKT());
+ } else {
+ attributes.put(
+ CRS,
+ MapUtil.constructEquidistantCylindrical(6371200.0,
+ 6371200.0, 0, 0).toWKT());
+ }
+
+ attributeMap.put(name, attributes);
+
+ }
+
+ /**
+ * Initializes the CRS for the us data set
+ *
+ * @param name
+ * The name
+ * @param latCenter
+ * The central latitude
+ * @param lonCenter
+ * The central longitude
+ * @return The constructed CRS
+ * @throws Exception
+ */
+ private static CoordinateReferenceSystem initUSProjectionData(String name,
+ float latCenter, float lonCenter) throws Exception {
+ ParameterValueGroup parameters = new DefaultMathTransformFactory()
+ .getDefaultParameters("Lambert_Azimuthal_Equal_Area");
+ parameters.parameter("semi_major").setValue(6371200.0);
+ parameters.parameter("semi_minor").setValue(6371200.0);
+ parameters.parameter("latitude_of_center").setValue(latCenter);
+ parameters.parameter("longitude_of_center").setValue(lonCenter);
+ return MapUtil.constructProjection(name, parameters);
+ }
+}
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/utility/common_static/base/path/gridPathKeys.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grid/utility/common_static/base/path/gridPathKeys.xml
new file mode 100644
index 0000000000..5e7905ca42
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/utility/common_static/base/path/gridPathKeys.xml
@@ -0,0 +1,7 @@
+
+
+
+ info.datasetId
+ 0
+
+
\ No newline at end of file
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.grid/utility/common_static/base/purge/gridPurgeRules.xml b/edexOsgi/com.raytheon.uf.edex.plugin.grid/utility/common_static/base/purge/gridPurgeRules.xml
new file mode 100644
index 0000000000..94ca1d220a
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.grid/utility/common_static/base/purge/gridPurgeRules.xml
@@ -0,0 +1,1246 @@
+
+
+
+
+
+
+ grid
+ default
+
+ 2
+
+
+
+
+
+
+ grid
+ info.datasetId=ETA
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=RUC
+
+ 8
+
+
+
+
+
+ grid
+ info.datasetId=AVN
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=LAPS
+
+ 30
+
+
+
+
+
+ grid
+ info.datasetId=NGM
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=MRF
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=MSAS
+
+ 24
+
+
+
+
+
+ grid
+ info.datasetId=GFS201
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=mrfNH
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=GFS213
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=NGM213
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=NGM202
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=AVN211
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=mesoEta212
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=mesoEta215
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=ENSEMBLE
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE37
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE38
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE39
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE40
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE41
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE42
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE43
+
+ 2
+
+
+
+ grid
+ info.datasetId=ENSEMBLE44
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=ETA212
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=MRF203
+
+ 3
+
+
+
+
+
+ grid
+ info.datasetId=AVN203
+
+ 3
+
+
+
+
+
+ grid
+ info.datasetId=MRF204
+
+ 3
+
+
+
+
+
+ grid
+ info.datasetId=MRF205
+
+ 3
+
+
+
+
+
+ grid
+ info.datasetId=NGM207
+
+ 3
+
+
+
+
+
+ grid
+ info.datasetId=NAM207
+
+ 3
+
+
+
+
+
+ grid
+ info.datasetId=ECMF-NorthernHemisphere
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF1
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF2
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF3
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF4
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF5
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF6
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF7
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF8
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF9
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF10
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF11
+
+ 2
+
+
+
+ grid
+ info.datasetId=ECMF12
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=UKMET-NorthernHemisphere
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET37
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET38
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET39
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET40
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET41
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET42
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET43
+
+ 2
+
+
+
+ grid
+ info.datasetId=UKMET44
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=AVN-NorthernHemisphere
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN37
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN38
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN39
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN40
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN41
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN42
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN43
+
+ 2
+
+
+
+ grid
+ info.datasetId=AVN44
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=GWW233
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=RFCqpf
+
+ 5
+
+
+
+
+
+ grid
+ info.datasetId=RUC236
+
+ 8
+
+
+
+
+
+ grid
+ info.datasetId=AVN225
+
+ 3
+
+
+
+
+
+ grid
+ info.datasetId=WNAWAVE238
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=mesoEta216
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=mesoEta217
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=ETA218
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=ETA242
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HPCqpf
+
+ 5
+
+
+
+
+
+ grid
+ info.datasetId=ENPWAVE253
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HPCdelta
+
+ 4
+
+
+
+
+
+ grid
+ info.datasetId=HurWind226
+
+ 4
+
+
+
+
+
+ grid
+ info.datasetId=CPCoutlook211
+
+ 14
+
+
+
+
+
+ grid
+ info.datasetId=RTGSSTHR
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=NICICE
+
+ 2
+
+
+
+
+
+ grid
+ info.datasetId=DGEX185
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HPCGuide
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GFSGuide
+
+ 8
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GFS212
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GFS160
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GFS254
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GFS161
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=MPE-Local
+
+ 72
+
+
+
+
+
+ grid
+ info.datasetId=TPCWindProb
+
+ 8
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=MOSGuide
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=QPE
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-TUA
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-ACR
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-STR
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-RSA
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-ORN
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-RHA
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-KRF
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-MSR
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-TAR
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-PTR
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-TIR
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-ALR
+
+ 72
+
+
+
+ grid
+ info.datasetId=QPE-FWR
+
+ 72
+
+
+
+
+
+
+
+ grid
+ info.datasetId=OPCWave180
+
+ 8
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=OPCWave181
+
+ 8
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=OPCWave182
+
+ 8
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=RTMA
+
+ 24
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=SREF212
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=RTGSST
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GFSLAMPTstorm
+
+ 24
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=ECMWF-HiRes
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HPCqpfNDFD
+
+ 42
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=NamDNG5
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=TPCSurgeProb
+
+ 3
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HPE
+
+ 00-12:00:00
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=BHPE
+
+ 00-12:00:00
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GlobalWave
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=AKWave10
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=AKWave4
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=EPWave10
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=WCWave10
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=WCWave4
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=WNAWave10
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=WNAWave4
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=MOSGuide-AK
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HI_RTMA
+
+ 24
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-ARW-East
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-ARW-West
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-ARW-AK
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-ARW-HI
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-ARW-SJU
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-NMM-East
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-NMM-West
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-NMM-AK
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-NMM-HI
+
+ 2
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=HiRes-NMM-SJU
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=GRLKwave
+
+ 1
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=CPCoutlook-Short
+
+ 5
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=CPCoutlook-Medium
+
+ 7
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=CPCoutlook-Short-AK
+
+ 5
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=CPCoutlook-Medium-AK
+
+ 7
+ 00-00:15:00
+
+
+
+
+
+ grid
+ info.datasetId=SPCGuide
+
+ 5
+ 00-00:15:00
+
+