diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.radar/src/com/raytheon/uf/common/dataplugin/radar/dataaccess/RadarGridFactory.java b/edexOsgi/com.raytheon.uf.common.dataplugin.radar/src/com/raytheon/uf/common/dataplugin/radar/dataaccess/RadarGridFactory.java index 28a6fe0b8f..bd5f0c3386 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.radar/src/com/raytheon/uf/common/dataplugin/radar/dataaccess/RadarGridFactory.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.radar/src/com/raytheon/uf/common/dataplugin/radar/dataaccess/RadarGridFactory.java @@ -20,6 +20,7 @@ package com.raytheon.uf.common.dataplugin.radar.dataaccess; import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -63,19 +64,19 @@ import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; /** - * + * * A data factory for getting radar data from the metadata database. There are * currently not any required identifiers. - * + * * Radar does not return subgrids for request envelopes like other gridded * types. Instead data for only icaos within the request envelope are returned * and all data for the product is used. This is done because subgridding radial * products is complex and this is not often what a caller actually wants. - * + * *
- * 
+ *
  * SOFTWARE HISTORY
- * 
+ *
  * Date          Ticket#  Engineer    Description
  * ------------- -------- ----------- --------------------------
  * Jan 23, 2013           bsteffen    Initial creation
@@ -86,9 +87,13 @@ import com.vividsolutions.jts.geom.Envelope;
  * Oct 28, 2014  3755     nabowle     Implement getAvailableParameters, handle
  *                                    empty parameters, fix error message, and
  *                                    handle dataless radial radars.
- * 
+ * Dec 18, 2014  3600     nabowle     Implement getAvailableLevels and add
+ *                                    optional identifiers to indicate what
+ *                                    fields are used for the level one and two
+ *                                    values.
+ *
  * 
- * + * * @author bsteffen * @version 1.0 */ @@ -99,6 +104,10 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements private static final String PRIMARY_ANGLE = "primaryElevationAngle"; + private static final String TRUE_ANGLE = "trueElevationAngle"; + + private static final String ELEVATION_NUMBER = "elevationNumber"; + private static final String ICAO = "icao"; private static final String LONGITUDE = "longitude"; @@ -111,9 +120,19 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements private static final String RASTER_FORMAT = "Raster"; + private static final String LEVEL_ONE = "level.one.field"; + + private static final String LEVEL_TWO = "level.two.field"; + private static final List SUPPORTED_FORMATS = Arrays.asList( RADIAL_FORMAT, RASTER_FORMAT); + private static final List SUPPORTED_LEVELS = Arrays.asList( + PRIMARY_ANGLE, TRUE_ANGLE, ELEVATION_NUMBER); + + private static final String LEVEL_ERROR = " must be " + PRIMARY_ANGLE + + ", " + TRUE_ANGLE + ", or " + ELEVATION_NUMBER; + private static RadarInfoDict radarInfo = null; private static MasterLevel tiltLevel = null; @@ -144,8 +163,7 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements .toString()); } defaultGridData.setUnit(radarRecord.getDataUnit()); - defaultGridData.setLevel(getTiltLevel(radarRecord - .getPrimaryElevationAngle())); + defaultGridData.setLevel(getLevel(radarRecord, request)); defaultGridData.setLocationName(generateLocationName(radarRecord)); Map attributes = new HashMap(); @@ -157,6 +175,51 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements return defaultGridData; } + /** + * Get the level for the radar record. If the request specifies + * {@value #LEVEL_ONE} or {@value #LEVEL_TWO} identifiers, those fields will + * be used. If {@value #LEVEL_ONE} is not specified, {@value #PRIMARY_ANGLE} + * will be used. + * + * @param radarRecord + * The radar record. + * @param request + * The request. + * @return The created level. + */ + private Level getLevel(RadarRecord radarRecord, IDataRequest request) { + Map identifiers = request.getIdentifiers(); + String levelOneField = (String) identifiers.get(LEVEL_ONE); + String levelTwoField = (String) identifiers.get(LEVEL_TWO); + + if (levelOneField == null) { + levelOneField = PRIMARY_ANGLE; + } + + Level level; + if (PRIMARY_ANGLE.equals(levelOneField)) { + level = getTiltLevel(radarRecord.getPrimaryElevationAngle()); + } else if (TRUE_ANGLE.equals(levelOneField)) { + level = getTiltLevel(radarRecord.getTrueElevationAngle()); + } else { // elevationNumber + level = new Level(); + level.setMasterLevel(new MasterLevel("OSEQD")); + level.setLevelonevalue(radarRecord.getElevationNumber()); + } + + if (levelTwoField != null) { + if (PRIMARY_ANGLE.equals(levelTwoField)) { + level.setLeveltwovalue(radarRecord.getPrimaryElevationAngle()); + } else if (TRUE_ANGLE.equals(levelTwoField)) { + level.setLeveltwovalue(radarRecord.getTrueElevationAngle()); + } else { // elevationNumber + level.setLeveltwovalue(radarRecord.getElevationNumber()); + } + } + + return level; + } + /** * Get a unique name describing the location of the radar data. The name * always includes icao, elevation angle, num bins and num radials. For @@ -335,11 +398,29 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements if (levels != null && levels.length > 0) { RequestConstraint angleConstraint = new RequestConstraint(null, ConstraintType.IN); + RequestConstraint levelTwoConstraint = new RequestConstraint(null, + ConstraintType.IN); + + Map identifiers = request.getIdentifiers(); + String levelOneField = (String) identifiers.get(LEVEL_ONE); + String levelTwoField = (String) identifiers.get(LEVEL_TWO); + + if (levelOneField == null) { + levelOneField = PRIMARY_ANGLE; + } for (Level level : levels) { angleConstraint.addToConstraintValueList(level .getLevelOneValueAsString()); + if (levelTwoField != null + && level.getLeveltwovalue() != Level.INVALID_VALUE) { + levelTwoConstraint.addToConstraintValueList(level + .getLevelTwoValueAsString()); + } + } + constraints.put(levelOneField, angleConstraint); + if (levelTwoConstraint.getConstraintValue() != null) { + constraints.put(levelTwoField, levelTwoConstraint); } - constraints.put(PRIMARY_ANGLE, angleConstraint); } String[] locations = request.getLocationNames(); @@ -456,9 +537,83 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements return parameters.toArray(new String[0]); } + /** + * Get the available levels. The optional identifiers, {@value #LEVEL_ONE} + * and {@value #LEVEL_TWO} can be supplied to choose which level fields are + * returned, otherwise {@value #PRIMARY_ANGLE} will be returned as the level + * one value. + */ + @Override + public Level[] getAvailableLevels(IDataRequest request) { + DbQueryRequest dbQueryRequest = buildDbQueryRequest(request); + dbQueryRequest.setDistinct(Boolean.TRUE); + + Map identifiers = request.getIdentifiers(); + String levelOneField = (String) identifiers.get(LEVEL_ONE); + String levelTwoField = (String) identifiers.get(LEVEL_TWO); + + if (levelOneField == null) { + levelOneField = PRIMARY_ANGLE; + } + dbQueryRequest.addRequestField(levelOneField); + if (levelTwoField != null) { + dbQueryRequest.addRequestField(levelTwoField); + } + + DbQueryResponse dbQueryResponse = this.executeDbQueryRequest( + dbQueryRequest, request.toString()); + Level level; + List levels = new ArrayList<>(); + for (Map result : dbQueryResponse.getResults()) { + if (PRIMARY_ANGLE.equals(levelOneField) + || TRUE_ANGLE.equals(levelTwoField)) { + level = getTiltLevel(Double.valueOf(result.get(levelOneField) + .toString())); + } else { + level = new Level(); + level.setMasterLevel(new MasterLevel("OSEQD")); + level.setLevelonevalue(Double.valueOf(result.get(levelOneField) + .toString())); + } + if (levelTwoField != null) { + level.setLeveltwovalue(Double.valueOf(result.get(levelTwoField) + .toString())); + } + levels.add(level); + } + + return levels.toArray(new Level[0]); + } + @Override public String[] getOptionalIdentifiers() { - return new String[] { ICAO }; + return new String[] { ICAO, LEVEL_ONE, LEVEL_TWO }; + } + + @Override + protected DbQueryRequest buildDbQueryRequest(IDataRequest request) { + validateLevelIdentifiers(request); + return super.buildDbQueryRequest(request); + } + + /** + * Validates that, if specified, the {@value #LEVEL_ONE} and + * {@value #LEVEL_TWO} identifier values are supported. + * + * @param request + */ + private void validateLevelIdentifiers(IDataRequest request) { + Map identifiers = request.getIdentifiers(); + String levelOneField = (String) identifiers.get(LEVEL_ONE); + String levelTwoField = (String) identifiers.get(LEVEL_TWO); + + if (levelOneField != null && !SUPPORTED_LEVELS.contains(levelOneField)) { + throw new DataRetrievalException(LEVEL_ONE + LEVEL_ERROR); + } + + if (levelTwoField != null && !SUPPORTED_LEVELS.contains(levelTwoField)) { + throw new DataRetrievalException(LEVEL_TWO + LEVEL_ERROR); + } } /** diff --git a/pythonPackages/msaslaps/radar/a2invradStub.py b/pythonPackages/msaslaps/radar/a2invradStub.py index d7395e8138..15738b1490 100644 --- a/pythonPackages/msaslaps/radar/a2invradStub.py +++ b/pythonPackages/msaslaps/radar/a2invradStub.py @@ -27,6 +27,7 @@ # Date Ticket# Engineer Description # ------------ ---------- ----------- -------------------------- # 2014-10-27 3600 nabowle Initial modification. Convert to DAF. +# 2014-12-18 3600 nabowle Use new getAvailableLevels() to speed up retrieval. # import argparse @@ -102,20 +103,37 @@ def main(): if timeRange: tr = timeRange else: - tr = [] + tr = None lines = set() - radars = DataAccessLayer.getGridData(req, tr) - for radar in radars: - line = "" - if user_args.outputDate: - line = str(radar.getDataTime()) + ".0" - if user_args.outputAngle: - line += " " - if user_args.outputAngle == "true": - line += "%.1f"%float(radar.getLocationName().split("_")[1]) - elif user_args.outputAngle == "primary": - line += radar.getLevel()[0:3] #Trim "TILT" - lines.add(line) + + if user_args.outputAngle: + levels = DataAccessLayer.getAvailableLevels(req) + for level in levels: + line = "" + req.setLevels(level) + if user_args.outputDate: + times = DataAccessLayer.getAvailableTimes(req) + for time in times: + if not tr or tr.contains(time.getValidPeriod()): + line = str(time) + ".0" + line += " " + if user_args.outputAngle == "true": + line += "%.1f"%level.getLeveltwovalue() + else: + line += "%.1f"%level.getLevelonevalue() + lines.add(line) + else: + if not tr or data_in_time_range(req, tr): + if user_args.outputAngle == "true": + line = "%.1f"%level.getLeveltwovalue() + else: + line = "%.1f"%level.getLevelonevalue() + lines.add(line) + else : # just output time + times = DataAccessLayer.getAvailableTimes(req) + for time in times: + if not tr or tr.contains(time.getValidPeriod()): + lines.add(str(time) + ".0") msg = "\n".join(lines) else: #retrieve available product codes unfiltered = DataAccessLayer.getAvailableParameters(req) @@ -158,6 +176,11 @@ def create_request(user_args): level = Level() level.setLevelonevalue(user_args.angle) req.setLevels(level) + # Indicate that when providing or requesting levels, the Levelonevalue + # is the primaryElevationAngle and the Leveltwovalue value is the + # trueElevationAngle + req.addIdentifier("level.one.field", "primaryElevationAngle") + req.addIdentifier("level.two.field", "trueElevationAngle") return req