Omaha #3600 Implement getAvailableLevels() for radar to increase inventory performance.

Change-Id: I168bd135ae3ddd386761bb87b9160eb97f718642

Former-commit-id: 863ac95fef [formerly 863ac95fef [formerly 6f9709b43d307494dfa702030b961964ec8d2170]]
Former-commit-id: a674630b92
Former-commit-id: c7805340b5
This commit is contained in:
Nathan Bowler 2014-12-19 12:48:13 -05:00
parent 503e45d730
commit 7f68dff20a
2 changed files with 202 additions and 24 deletions

View file

@ -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.
*
*
* <pre>
*
*
* 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.
*
* </pre>
*
*
* @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<String> SUPPORTED_FORMATS = Arrays.asList(
RADIAL_FORMAT, RASTER_FORMAT);
private static final List<String> 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<String, Object> attributes = new HashMap<String, Object>();
@ -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<String, Object> 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<String, Object> 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<String, Object> 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<Level> levels = new ArrayList<>();
for (Map<String, Object> 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<String, Object> 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);
}
}
/**

View file

@ -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