001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2017 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029package edu.wisc.ssec.mcidasv.data.hydra; 030 031import java.util.HashMap; 032import java.util.Map; 033import java.util.Objects; 034 035import visad.CoordinateSystem; 036import visad.Gridded2DDoubleSet; 037import visad.Gridded2DSet; 038import visad.Linear2DSet; 039import visad.RealTupleType; 040 041public class SwathNavigation implements Navigation { 042 043 public static SwathNavigation createNavigation(SwathAdapter swathAdapter) throws Exception { 044 String product_name = null; 045 SwathNavigation swathNav = null; 046 047 product_name = (String)swathAdapter.getMetadata().get(SwathAdapter.product_name); 048 049 if (product_name == null) { 050 swathNav = new SwathNavigation(swathAdapter); 051 } 052 else if (Objects.equals(product_name, "IASI_L1C_xxx")) { 053 swathNav = new IASI_L1C_LonLatNavigation(swathAdapter); 054 } 055 else if (Objects.equals(product_name, "CrIS_SDR")) { 056 swathNav = new CrIS_SDR_LonLatNavigation(swathAdapter); 057 } 058 else { 059 swathNav = new SwathNavigation(swathAdapter); 060 } 061 062 return swathNav; 063 } 064 065 int geo_track_idx; 066 int geo_xtrack_idx; 067 int geoTrackLen; 068 int geoXTrackLen; 069 070 SwathAdapter swathAdapter; 071 MultiDimensionReader reader; 072 String lon_array_name; 073 String lat_array_name; 074 int[] idx_order = new int[2]; 075 float ratio = 1; 076 float track_ratio = 1; 077 float xtrack_ratio = 1; 078 double track_offset = 0; 079 double xtrack_offset = 0; 080 int track_idx; 081 int xtrack_idx; 082 int[] geo_stride = new int[2]; 083 int[] geo_count = new int[2]; 084 int[] geo_start = new int[2]; 085 086 String scale_name = "SCALE_NAME"; 087 String offset_name = "OFFSET_NAME"; 088 String fillValue_name = "_FILLVALUE"; 089 090 int numDims = 2; 091 092 Class type; 093 094 public SwathNavigation(SwathAdapter swathAdapter) throws Exception { 095 096 Map<String, Object> metadata = swathAdapter.getMetadata(); 097 reader = swathAdapter.getReader(); 098 this.swathAdapter = swathAdapter; 099 track_idx = swathAdapter.track_idx; 100 xtrack_idx = swathAdapter.xtrack_idx; 101 102 lon_array_name = (String)metadata.get(SwathAdapter.lon_array_name); 103 lat_array_name = (String)metadata.get(SwathAdapter.lat_array_name); 104 105 String[] lon_dim_names = null; 106 107 String[] lonDimNames = (String[])metadata.get(SwathAdapter.lon_array_dimension_names); 108 109 if (lonDimNames != null) { 110 lon_dim_names = lonDimNames; 111 } 112 else { 113 lon_dim_names = reader.getDimensionNames(lon_array_name); 114 } 115 116 int[] lon_dim_lengths = reader.getDimensionLengths(lon_array_name); 117 118 numDims = lon_dim_lengths.length; 119 geo_stride = new int[numDims]; 120 geo_count = new int[numDims]; 121 geo_start = new int[numDims]; 122 123 124 String geo_track_name = (String)metadata.get(SwathAdapter.geo_track_name); 125 String geo_xtrack_name = (String)metadata.get(SwathAdapter.geo_xtrack_name); 126 127 for (int k=0; k<numDims;k++) { 128 if ( geo_track_name.equals(lon_dim_names[k]) ) { 129 geo_track_idx = k; 130 } 131 if ( geo_xtrack_name.equals(lon_dim_names[k]) ) { 132 geo_xtrack_idx = k; 133 } 134 } 135 136 if (geo_track_idx < geo_xtrack_idx) { 137 idx_order[0] = geo_xtrack_idx; 138 idx_order[1] = geo_track_idx; 139 } 140 else { 141 idx_order[0] = geo_track_idx; 142 idx_order[1] = geo_xtrack_idx; 143 } 144 145 geoTrackLen = lon_dim_lengths[geo_track_idx]; 146 geoXTrackLen = lon_dim_lengths[geo_xtrack_idx]; 147 148 String str = (String)metadata.get(SwathAdapter.geo_track_skip_name); 149 150 if (str != null) { 151 track_ratio = (float) Double.parseDouble(str); 152 ratio = track_ratio; 153 } 154 str = (String)metadata.get(SwathAdapter.geo_xtrack_skip_name); 155 if (str != null) { 156 xtrack_ratio = (float) Double.parseDouble(str); 157 } 158 str = (String)metadata.get(SwathAdapter.geo_track_offset_name); 159 if (str != null) { 160 track_offset = Double.parseDouble(str); 161 } 162 str = (String)metadata.get(SwathAdapter.geo_xtrack_offset_name); 163 if (str != null) { 164 xtrack_offset = Double.parseDouble(str); 165 } 166 167 str = (String)metadata.get(SwathAdapter.geo_scale_name); 168 if (str != null) { 169 scale_name = str; 170 } 171 172 str = (String)metadata.get(SwathAdapter.geo_offset_name); 173 if (str != null) { 174 offset_name = str; 175 } 176 177 str = (String)metadata.get(SwathAdapter.geo_fillValue_name); 178 if (str != null) { 179 fillValue_name = str; 180 } 181 182 type = reader.getArrayType(lon_array_name); 183 } 184 185 public CoordinateSystem getVisADCoordinateSystem(Linear2DSet domainSet, Map<String, double[]> domainSubset) throws Exception 186 { 187 Subset select = swathAdapter.getIndexes(domainSubset); 188 189 double[] track_coords = domainSubset.get(SwathAdapter.track_name); 190 double[] xtrack_coords = domainSubset.get(SwathAdapter.xtrack_name); 191 192 int[] stride = new int[numDims]; 193 stride[geo_track_idx] = (int) track_coords[2]; 194 stride[geo_xtrack_idx] = (int) xtrack_coords[2]; 195 196 197 if (numDims > 2) { // initialize geo arrays, then recompute xtrack/track dimensions below 198 if (numDims == select.getRank()) { 199 int[] start = select.getStart(); 200 int[] count = select.getCount(); 201 stride = select.getStride(); 202 for (int i=0; i<numDims; i++) { 203 geo_start[i] = start[i]; 204 geo_count[i] = count[i]; 205 geo_stride[i] = stride[i]; 206 } 207 } 208 else { 209 geo_start[geo_track_idx] = (int) track_coords[0]; 210 geo_start[geo_xtrack_idx] = (int) xtrack_coords[0]; 211 geo_count[geo_track_idx] = (int) ((track_coords[1] - track_coords[0])/track_coords[2] + 1f); 212 geo_count[geo_xtrack_idx] = (int) ((xtrack_coords[1] - xtrack_coords[0])/xtrack_coords[2] + 1f); 213 } 214 } 215 216 217 if (ratio/(float)stride[0] <= 1) { 218 geo_stride[geo_track_idx] = Math.round((1f/(track_ratio/((float)stride[geo_track_idx])))); 219 geo_stride[geo_xtrack_idx] = Math.round((1f/(xtrack_ratio/((float)stride[geo_xtrack_idx])))); 220 } 221 else { 222 geo_stride[geo_track_idx] = 1; 223 geo_stride[geo_xtrack_idx] = 1; 224 } 225 226 int geo_track_start = (int) Math.ceil((track_coords[0] - track_offset)/track_ratio); 227 int geo_xtrack_start = (int) Math.ceil((xtrack_coords[0] - xtrack_offset)/xtrack_ratio); 228 229 int geo_track_end = (int) ((track_coords[1] - track_offset)/((double)track_ratio)); 230 int geo_xtrack_end = (int) ((xtrack_coords[1] - xtrack_offset)/((double)xtrack_ratio)); 231 232 geo_count[geo_track_idx] = (int) ((geo_track_end - geo_track_start)/geo_stride[geo_track_idx]) + 1; 233 geo_count[geo_xtrack_idx] = (int) ((geo_xtrack_end - geo_xtrack_start)/geo_stride[geo_xtrack_idx]) + 1; 234 235 geo_track_end = geo_track_start + (geo_count[geo_track_idx]-1)*geo_stride[geo_track_idx]; 236 geo_xtrack_end = geo_xtrack_start + (geo_count[geo_xtrack_idx]-1)*geo_stride[geo_xtrack_idx]; 237 238 geo_start[geo_track_idx] = geo_track_start; 239 geo_start[geo_xtrack_idx] = geo_xtrack_start; 240 241 //-- convert back track/xtrack coords: 242 int new_track_start = (int) (geo_track_start*track_ratio + (float)track_offset); 243 int new_xtrack_start = (int) (geo_xtrack_start*xtrack_ratio + (float)xtrack_offset); 244 int new_track_end = (int) (geo_track_end*track_ratio + (float)track_offset); 245 int new_xtrack_end = (int) (geo_xtrack_end*xtrack_ratio + (float)xtrack_offset); 246 247 248 //- these must be only 2D (Swath dimensions) 249 double[] first = new double[2]; 250 double[] last = new double[2]; 251 int[] length = new int[2]; 252 253 int track_idx; 254 int xtrack_idx; 255 if (geo_track_idx < geo_xtrack_idx) { 256 track_idx = 1; 257 xtrack_idx = 0; 258 } else { 259 track_idx = 0; 260 xtrack_idx = 1; 261 } 262 263 first[track_idx] = new_track_start; 264 first[xtrack_idx] = new_xtrack_start; 265 last[track_idx] = new_track_end; 266 last[xtrack_idx] = new_xtrack_end; 267 length[track_idx] = (int) ((last[track_idx] - first[track_idx])/stride[geo_track_idx] + 1); 268 length[xtrack_idx] = (int) ((last[xtrack_idx] - first[xtrack_idx])/stride[geo_xtrack_idx] + 1); 269 270 domainSet = new Linear2DSet(first[0], last[0], length[0], first[1], last[1], length[1]); 271 272 Gridded2DSet gset = null; 273 274 gset = createInterpSet(); 275 276 CoordinateSystem cs = new LongitudeLatitudeCoordinateSystem(domainSet, gset); 277 278 return cs; 279 } 280 281 Gridded2DSet createInterpSet() throws Exception { 282 Gridded2DSet gset = null; 283 if (type == Float.TYPE) { 284 float[] lonValues = reader.getFloatArray(lon_array_name, geo_start, geo_count, geo_stride); 285 float[] latValues = reader.getFloatArray(lat_array_name, geo_start, geo_count, geo_stride); 286 287 gset = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple, 288 new float[][] {lonValues, latValues}, 289 geo_count[idx_order[0]], geo_count[idx_order[1]], 290 null, null, null, false, false); 291 } 292 else if (type == Double.TYPE) { 293 double[] lonValues = reader.getDoubleArray(lon_array_name, geo_start, geo_count, geo_stride); 294 double[] latValues = reader.getDoubleArray(lat_array_name, geo_start, geo_count, geo_stride); 295 296 gset = new Gridded2DDoubleSet(RealTupleType.SpatialEarth2DTuple, 297 new double[][] {lonValues, latValues}, 298 geo_count[idx_order[0]], geo_count[idx_order[1]], 299 null, null, null, false); 300 } 301 else if (type == Short.TYPE) { 302 short[] values = reader.getShortArray(lon_array_name, geo_start, geo_count, geo_stride); 303 Map<String, Object> metadata = new HashMap<>(); 304 metadata.put(SwathAdapter.array_name, lon_array_name); 305 metadata.put(SwathAdapter.scale_name, scale_name); 306 metadata.put(SwathAdapter.offset_name, offset_name); 307 metadata.put(SwathAdapter.fill_value_name, fillValue_name); 308 RangeProcessor rangeProcessor = RangeProcessor.createRangeProcessor(reader, metadata); 309 float[] lonValues = rangeProcessor.processRange(values, null); 310 311 values = reader.getShortArray(lat_array_name, geo_start, geo_count, geo_stride); 312 metadata = new HashMap<>(); 313 metadata.put(SwathAdapter.array_name, lat_array_name); 314 metadata.put(SwathAdapter.scale_name, scale_name); 315 metadata.put(SwathAdapter.offset_name, offset_name); 316 metadata.put(SwathAdapter.fill_value_name, fillValue_name); 317 rangeProcessor = RangeProcessor.createRangeProcessor(reader, metadata); 318 float[] latValues = rangeProcessor.processRange(values, null); 319 320 321 gset = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple, 322 new float[][] {lonValues, latValues}, 323 geo_count[idx_order[0]], geo_count[idx_order[1]], 324 null, null, null, false, false); 325 326 } 327 return gset; 328 } 329 330 331 332 public static Linear2DSet getNavigationDomain(double data_x_start, double data_x_stop, double data_x_stride, 333 double data_y_start, double data_y_stop, double data_y_stride, 334 double ratio_x, double ratio_y, 335 double offset_x, double offset_y, 336 int[] geo_start, int[] geo_count, int[] geo_stride) 337 throws Exception { 338 339 int geo_track_idx = 1; 340 int geo_xtrack_idx = 0; 341 double track_ratio = ratio_y; 342 double xtrack_ratio = ratio_x; 343 double track_offset = offset_y; 344 double xtrack_offset = offset_x; 345 346 double[] track_coords = new double[3]; 347 double[] xtrack_coords = new double[3]; 348 349 xtrack_coords[0] = data_x_start; 350 xtrack_coords[1] = data_x_stop; 351 track_coords[0] = data_y_start; 352 track_coords[1] = data_y_stop; 353 354 double[] stride = new double[2]; 355 stride[geo_track_idx] = data_y_stride; 356 stride[geo_xtrack_idx] = data_x_stride; 357 358 if (track_ratio/(float)stride[0] <= 1) { 359 geo_stride[geo_track_idx] = (int) Math.round((1/(track_ratio/(stride[1])))); 360 geo_stride[geo_xtrack_idx] = (int) Math.round((1/(xtrack_ratio/(stride[0])))); 361 } 362 else { 363 geo_stride[0] = 1; 364 geo_stride[1] = 1; 365 } 366 367 int geo_track_start = (int) Math.ceil((track_coords[0] - track_offset)/track_ratio); 368 int geo_xtrack_start = (int) Math.ceil((xtrack_coords[0] - xtrack_offset)/xtrack_ratio); 369 370 int geo_track_end = (int) ((track_coords[1] - track_offset)/((double)track_ratio)); 371 int geo_xtrack_end = (int) ((xtrack_coords[1] - xtrack_offset)/((double)xtrack_ratio)); 372 373 geo_count[geo_track_idx] = (int) ((geo_track_end - geo_track_start)/geo_stride[geo_track_idx]) + 1; 374 geo_count[geo_xtrack_idx] = (int) ((geo_xtrack_end - geo_xtrack_start)/geo_stride[geo_xtrack_idx]) + 1; 375 376 geo_track_end = geo_track_start + (geo_count[geo_track_idx]-1)*geo_stride[geo_track_idx]; 377 geo_xtrack_end = geo_xtrack_start + (geo_count[geo_xtrack_idx]-1)*geo_stride[geo_xtrack_idx]; 378 379 geo_start[geo_track_idx] = geo_track_start; 380 geo_start[geo_xtrack_idx] = geo_xtrack_start; 381 382 //-- convert back track/xtrack coords: 383 int new_track_start = (int) (geo_track_start*track_ratio + (float)track_offset); 384 int new_xtrack_start = (int) (geo_xtrack_start*xtrack_ratio + (float)xtrack_offset); 385 int new_track_end = (int) (geo_track_end*track_ratio + (float)track_offset); 386 int new_xtrack_end = (int) (geo_xtrack_end*xtrack_ratio + (float)xtrack_offset); 387 388 389 double[] first = new double[2]; 390 double[] last = new double[2]; 391 int[] length = new int[2]; 392 first[geo_track_idx] = new_track_start; 393 first[geo_xtrack_idx] = new_xtrack_start; 394 last[geo_track_idx] = new_track_end; 395 last[geo_xtrack_idx] = new_xtrack_end; 396 length[geo_track_idx] = (int) ((last[geo_track_idx] - first[geo_track_idx])/stride[geo_track_idx] + 1); 397 length[geo_xtrack_idx] = (int) ((last[geo_xtrack_idx] - first[geo_xtrack_idx])/stride[geo_xtrack_idx] + 1); 398 399 return new Linear2DSet(first[0], last[0], length[0], first[1], last[1], length[1]); 400 401 } 402 403 404}