package mil.nga.giat.geowave.analytic.mapreduce.kde.compare; import java.awt.image.WritableRaster; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.vecmath.Point2d; import mil.nga.giat.geowave.adapter.raster.RasterUtils; import mil.nga.giat.geowave.analytic.mapreduce.kde.KDEJobRunner; import mil.nga.giat.geowave.core.geotime.ingest.SpatialDimensionalityTypeProvider; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.mapreduce.JobContextIndexStore; import mil.nga.giat.geowave.mapreduce.output.GeoWaveOutputKey; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.mapreduce.Reducer; import org.opengis.coverage.grid.GridCoverage; public class ComparisonAccumuloStatsReducer extends Reducer<ComparisonCellData, LongWritable, GeoWaveOutputKey, GridCoverage> { public static final int NUM_BANDS = 4; protected static final String[] NAME_PER_BAND = new String[] { "Summer", "Winter", "Combined", "Combined Percentile" }; protected static final double[] MINS_PER_BAND = new double[] { 0, 0, -1, 0 }; protected static final double[] MAXES_PER_BAND = new double[] { 1, 1, 1, 1 }; private static final int TILE_SIZE = 1; private long totalKeys = 0; private long currentKey; private int minLevels; private int maxLevels; private int numLevels; private int level; private int numXPosts; private int numYPosts; private String coverageName; protected List<ByteArrayId> indexList; @Override protected void reduce( final ComparisonCellData key, final Iterable<LongWritable> values, final Context context ) throws IOException, InterruptedException { // for consistency give all cells with matching weight the same // percentile final double percentile = (currentKey + 1.0) / totalKeys; // calculate weights for this key for (final LongWritable v : values) { final long cellIndex = v.get() / numLevels; final Point2d[] bbox = fromIndexToLL_UR(cellIndex); final WritableRaster raster = RasterUtils.createRasterTypeDouble( NUM_BANDS, TILE_SIZE); raster.setSample( 0, 0, 0, key.getSummerPercentile()); raster.setSample( 0, 0, 1, key.getWinterPercentile()); raster.setSample( 0, 0, 2, key.getCombinedPercentile()); raster.setSample( 0, 0, 3, percentile); context.write( new GeoWaveOutputKey( new ByteArrayId( coverageName), indexList), RasterUtils.createCoverageTypeDouble( coverageName, bbox[0].x, bbox[1].x, bbox[0].y, bbox[1].y, MINS_PER_BAND, MAXES_PER_BAND, NAME_PER_BAND, raster)); currentKey++; } } private Point2d[] fromIndexToLL_UR( final long index ) { final double llLon = ((Math.floor(index / (double) numYPosts) * 360.0) / numXPosts) - 180.0; final double llLat = (((index % numYPosts) * 180.0) / numYPosts) - 90.0; final double urLon = llLon + (360.0 / numXPosts); final double urLat = llLat + (180.0 / numYPosts); return new Point2d[] { new Point2d( llLon, llLat), new Point2d( urLon, urLat) }; } @Override protected void setup( final Context context ) throws IOException, InterruptedException { super.setup(context); minLevels = context.getConfiguration().getInt( KDEJobRunner.MIN_LEVEL_KEY, 1); maxLevels = context.getConfiguration().getInt( KDEJobRunner.MAX_LEVEL_KEY, 25); coverageName = context.getConfiguration().get( KDEJobRunner.COVERAGE_NAME_KEY, ""); numLevels = (maxLevels - minLevels) + 1; level = context.getConfiguration().getInt( "mapred.task.partition", 0) + minLevels; numXPosts = (int) Math.pow( 2, level + 1); numYPosts = (int) Math.pow( 2, level); totalKeys = context.getConfiguration().getLong( "Entries per level.level" + level, 10); final PrimaryIndex[] indices = JobContextIndexStore.getIndices(context); indexList = new ArrayList<ByteArrayId>(); if ((indices != null) && (indices.length > 0)) { for (final PrimaryIndex index : indices) { indexList.add(index.getId()); } } else { indexList.add(new SpatialDimensionalityTypeProvider.SpatialIndexBuilder().createIndex().getId()); } } }