001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 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 visad.Data; 032import visad.FlatField; 033import visad.Set; 034import visad.Gridded1DSet; 035import visad.CoordinateSystem; 036import visad.RealType; 037import visad.RealTupleType; 038import visad.SetType; 039import visad.Linear1DSet; 040import visad.Linear2DSet; 041import visad.Unit; 042import visad.FunctionType; 043import visad.VisADException; 044import visad.QuickSort; 045import java.rmi.RemoteException; 046 047import java.util.Hashtable; 048import java.util.HashMap; 049import java.util.Map; 050import java.util.StringTokenizer; 051 052import java.io.BufferedReader; 053import java.io.FileInputStream; 054import java.io.IOException; 055import java.io.InputStream; 056import java.io.InputStreamReader; 057 058 059public abstract class ProfileAlongTrack extends MultiDimensionAdapter { 060 061 private FunctionType mathtype; 062 063 int TrackLen; 064 int VertLen; 065 066 private float[] vertLocs = null; 067 private float[] trackTimes = null; 068 private float[] trackLongitude = null; 069 private float[] trackLatitude = null; 070 071 public static String longitude_name = "Longitude"; 072 public static String latitude_name = "Latitude"; 073 public static String trackDim_name = "TrackDim"; 074 public static String vertDim_name = "VertDim"; 075 public static String array_name = "array_name"; 076 public static String profileTime_name = "ProfileTime"; 077 public static String profileTime_unit = "ProfileTime_unit"; 078 public static String altitude_unit = "altitude_unit"; 079 public static String sfcElev_name = "SurfaceElev"; 080 public static String range_name = "range_name"; 081 public static String scale_name = "scale_name"; 082 public static String offset_name = "offset_name"; 083 public static String fill_value_name = "fill_value_name"; 084 public static String valid_range = "valid_range"; 085 public static String ancillary_file_name = "ancillary_file"; 086 static String product_name = "product_name"; 087 088 String[] rangeName_s = null; 089 Class[] arrayType_s = null; 090 Unit[] rangeUnit_s = new Unit[] {null}; 091 092 RealType track = RealType.getRealType(trackDim_name); 093 RealType vert = RealType.getRealType(vertDim_name); 094 RealType[] domainRealTypes = new RealType[2]; 095 096 RealType vertLocType; 097 RealType trackTimeType; 098 099 int track_idx = -1; 100 int vert_idx = -1; 101 int range_rank = -1; 102 103 int track_tup_idx; 104 int vert_tup_idx; 105 106 boolean isVertDimAlt = true; 107 108 CoordinateSystem cs = null; 109 110 public static Map<String, double[]> getEmptySubset() { 111 Map<String, double[]> subset = new HashMap<>(); 112 subset.put(trackDim_name, new double[3]); 113 subset.put(vertDim_name, new double[3]); 114 return subset; 115 } 116 117 public static Map<String, Object> getEmptyMetadataTable() { 118 Map<String, Object> metadata = new HashMap<>(); 119 metadata.put(array_name, null); 120 metadata.put(trackDim_name, null); 121 metadata.put(vertDim_name, null); 122 metadata.put(longitude_name, null); 123 metadata.put(latitude_name, null); 124 metadata.put(profileTime_name, null); 125 metadata.put(profileTime_unit, null); 126 metadata.put(altitude_unit, null); 127 metadata.put(sfcElev_name, null); 128 metadata.put(scale_name, null); 129 metadata.put(offset_name, null); 130 metadata.put(fill_value_name, null); 131 /* 132 metadata.put(range_name, null); 133 metadata.put(range_unit, null); 134 metadata.put(valid_range, null); 135 */ 136 return metadata; 137 } 138 139 public ProfileAlongTrack() { 140 } 141 142 public ProfileAlongTrack(MultiDimensionReader reader, Map<String, Object> metadata) { 143 this(reader, metadata, true); 144 } 145 146 public ProfileAlongTrack(MultiDimensionReader reader, Map<String, Object> metadata, boolean isVertDimAlt) { 147 super(reader, metadata); 148 this.isVertDimAlt = isVertDimAlt; 149 this.init(); 150 } 151 152 153 private void init() { 154 for (int k=0; k<array_rank;k++) { 155 if ( ((String)metadata.get(trackDim_name)).equals(array_dim_names[k]) ) { 156 track_idx = k; 157 } 158 if ( ((String)metadata.get(vertDim_name)).equals(array_dim_names[k]) ) { 159 vert_idx = k; 160 } 161 } 162 163 int[] lengths = new int[2]; 164 165 if (track_idx < vert_idx) { 166 domainRealTypes[0] = vert; 167 domainRealTypes[1] = track; 168 track_tup_idx = 1; 169 vert_tup_idx = 0; 170 lengths[0] = array_dim_lengths[vert_idx]; 171 lengths[1] = array_dim_lengths[track_idx]; 172 } 173 else { 174 domainRealTypes[0] = track; 175 domainRealTypes[1] = vert; 176 track_tup_idx = 0; 177 vert_tup_idx = 1; 178 lengths[0] = array_dim_lengths[track_idx]; 179 lengths[1] = array_dim_lengths[vert_idx]; 180 } 181 182 TrackLen = array_dim_lengths[track_idx]; 183 VertLen = array_dim_lengths[vert_idx]; 184 185 String rangeName = null; 186 if (metadata.get("range_name") != null) { 187 rangeName = (String)metadata.get("range_name"); 188 } 189 else { 190 rangeName = (String)metadata.get("array_name"); 191 } 192 rangeType = RealType.getRealType(rangeName, rangeUnit_s[0]); 193 194 try { 195 rangeProcessor = RangeProcessor.createRangeProcessor(reader, metadata); 196 } 197 catch (Exception e) { 198 System.out.println("RangeProcessor failed to create"); 199 e.printStackTrace(); 200 } 201 202 try { 203 if (isVertDimAlt) { 204 vertLocs = getVertBinAltitude(); 205 } 206 vertLocType = makeVertLocType(); 207 trackTimes = getTrackTimes(); 208 trackTimeType = makeTrackTimeType(); 209 trackLongitude = getTrackLongitude(); 210 trackLatitude = getTrackLatitude(); 211 } 212 catch (Exception e) { 213 System.out.println(e); 214 } 215 216 } 217 218 public int getTrackLength() { 219 return TrackLen; 220 } 221 222 public int getVertLength() { 223 return VertLen; 224 } 225 226 public int getVertIdx() { 227 return vert_idx; 228 } 229 230 public int getTrackIdx() { 231 return track_idx; 232 } 233 234 public int getVertTupIdx() { 235 return vert_tup_idx; 236 } 237 238 public int getTrackTupIdx() { 239 return track_tup_idx; 240 } 241 242 public Set makeDomain(Map<String, double[]> subset) throws Exception { 243 double[] first = new double[2]; 244 double[] last = new double[2]; 245 int[] length = new int[2]; 246 247 Map<String, double[]> domainSubset = new HashMap<>(); 248 domainSubset.put(trackDim_name, (double[]) ((HashMap)subset).get(trackDim_name)); 249 domainSubset.put(vertDim_name, (double[]) ((HashMap)subset).get(vertDim_name)); 250 251 for (int kk=0; kk<2; kk++) { 252 RealType rtype = domainRealTypes[kk]; 253 double[] coords = (double[]) ((HashMap)subset).get(rtype.getName()); 254 first[kk] = coords[0]; 255 last[kk] = coords[1]; 256 length[kk] = (int) ((last[kk] - first[kk])/coords[2] + 1); 257 last[kk] = first[kk]+coords[2]*(length[kk]-1); 258 } 259 Linear2DSet domainSet = new Linear2DSet(first[0], last[0], length[0], first[1], last[1], length[1]); 260 final Linear1DSet[] lin1DSet_s = new Linear1DSet[] {domainSet.getLinear1DComponent(0), 261 domainSet.getLinear1DComponent(1)}; 262 263 float[] new_altitudes = new float[length[vert_tup_idx]]; 264 float[] new_times = new float[length[track_tup_idx]]; 265 266 int track_start = (int) first[track_tup_idx]; 267 int vert_start = (int) first[vert_tup_idx]; 268 int vert_skip = (int) ((double[]) ((HashMap)subset).get(vertDim_name))[2]; 269 int track_skip = (int) ((double[]) ((HashMap)subset).get(trackDim_name))[2]; 270 for (int k=0; k<new_altitudes.length; k++) { 271 new_altitudes[k] = vertLocs[vert_start+(k*vert_skip)]; 272 } 273 274 for (int k=0; k<new_times.length; k++) { 275 new_times[k] = trackTimes[track_start+(k*track_skip)]; 276 } 277 278 final Gridded1DSet alt_set = new Gridded1DSet(vertLocType, new float[][] {new_altitudes}, new_altitudes.length); 279 final Gridded1DSet time_set = new Gridded1DSet(trackTimeType, new float[][] {new_times}, new_times.length); 280 final float vert_offset = (float) first[vert_tup_idx]; 281 final float track_offset = (float) first[track_tup_idx]; 282 283 RealTupleType reference = new RealTupleType(vertLocType, trackTimeType); 284 285 CoordinateSystem cs = null; 286 287 try { 288 cs = new CoordinateSystem(reference, null) { 289 public float[][] toReference(float[][] vals) throws VisADException { 290 int[] indexes = lin1DSet_s[0].valueToIndex(new float[][] {vals[0]}); 291 for (int k=0; k<vals[0].length;k++) { 292 //-indexes[k] = (int) (vals[vert_tup_idx][k] - vert_offset); ? 293 } 294 float[][] alts = alt_set.indexToValue(indexes); 295 296 indexes = lin1DSet_s[1].valueToIndex(new float[][] {vals[1]}); 297 for (int k=0; k<vals[0].length;k++) { 298 //-indexes[k] = (int) (vals[track_tup_idx][k] - track_offset); ? 299 } 300 float[][] times = time_set.indexToValue(indexes); 301 302 return new float[][] {alts[0], times[0]}; 303 } 304 public float[][] fromReference(float[][] vals) throws VisADException { 305 int[] indexes = alt_set.valueToIndex(new float[][] {vals[vert_tup_idx]}); 306 float[][] vert_coords = lin1DSet_s[vert_tup_idx].indexToValue(indexes); 307 indexes = time_set.valueToIndex(new float[][] {vals[track_tup_idx]}); 308 float[][] track_coords = lin1DSet_s[track_tup_idx].indexToValue(indexes); 309 return new float[][] {vert_coords[0], track_coords[0]}; 310 } 311 public double[][] toReference(double[][] vals) throws VisADException { 312 return Set.floatToDouble(toReference(Set.doubleToFloat(vals))); 313 } 314 public double[][] fromReference(double[][] vals) throws VisADException { 315 return Set.floatToDouble(fromReference(Set.doubleToFloat(vals))); 316 } 317 public boolean equals(Object obj) { 318 return true; 319 } 320 }; 321 } 322 catch (Exception e) { 323 } 324 325 RealTupleType domainTupType = new RealTupleType(domainRealTypes[0], domainRealTypes[1], cs, null); 326 domainSet = new Linear2DSet(domainTupType, first[0], last[0], length[0], first[1], last[1], length[1]); 327 328 return domainSet; 329 } 330 331 public FunctionType getMathType() { 332 return null; 333 } 334 335 public RealType[] getDomainRealTypes() { 336 return domainRealTypes; 337 } 338 339 public Map<String, double[]> getDefaultSubset() { 340 Map<String, double[]> subset = ProfileAlongTrack.getEmptySubset(); 341 342 double[] coords = (double[])subset.get("TrackDim"); 343 coords[0] = 20000.0; 344 coords[1] = (TrackLen - 15000.0) - 1; 345 //-coords[2] = 30.0; 346 coords[2] = 5.0; 347 subset.put("TrackDim", coords); 348 349 coords = (double[])subset.get("VertDim"); 350 coords[0] = 98.0; 351 coords[1] = (VertLen) - 1; 352 coords[2] = 2.0; 353 subset.put("VertDim", coords); 354 return subset; 355 } 356 357 public int[] getTrackRangeInsideLonLatRect(double minLat, double maxLat, double minLon, double maxLon) { 358 int nn = 100; 359 int skip = TrackLen/nn; 360 double lon; 361 double lat; 362 363 int idx = 0; 364 while (idx < TrackLen) { 365 lon = (double)trackLongitude[idx]; 366 lat = (double)trackLatitude[idx]; 367 if (((lon > minLon) && (lon < maxLon)) && ((lat > minLat)&&(lat < maxLat))) break; 368 idx += skip; 369 } 370 if (idx > TrackLen-1) idx = TrackLen-1; 371 if (idx == TrackLen-1) return new int[] {-1,-1}; 372 373 int low_idx = idx; 374 while (low_idx > 0) { 375 lon = (double)trackLongitude[low_idx]; 376 lat = (double)trackLatitude[low_idx]; 377 if (((lon > minLon) && (lon < maxLon)) && ((lat > minLat)&&(lat < maxLat))) { 378 low_idx -= 1; 379 continue; 380 } 381 else { 382 break; 383 } 384 } 385 386 int hi_idx = idx; 387 while (hi_idx < TrackLen-1) { 388 lon = (double)trackLongitude[hi_idx]; 389 lat = (double)trackLatitude[hi_idx]; 390 if (((lon > minLon) && (lon < maxLon)) && ((lat > minLat)&&(lat < maxLat))) { 391 hi_idx += 1; 392 continue; 393 } 394 else { 395 break; 396 } 397 } 398 return new int[] {low_idx, hi_idx}; 399 } 400 401 public Map<String, double[]> getSubsetFromLonLatRect(Map<String, double[]> subset, double minLat, double maxLat, double minLon, double maxLon) { 402 double[] coords = subset.get("TrackDim"); 403 int[] idxs = getTrackRangeInsideLonLatRect(minLat, maxLat, minLon, maxLon); 404 coords[0] = (double) idxs[0]; 405 coords[1] = (double) idxs[1]; 406 if ((coords[0] == -1) || (coords[1] == -1)) return null; 407 return subset; 408 } 409 410 public Map<String, double[]> getSubsetFromLonLatRect(Map<String, double[]> subset, double minLat, double maxLat, double minLon, double maxLon, 411 int xStride, int yStride, int zStride) { 412 413 double[] coords = subset.get("TrackDim"); 414 int[] idxs = getTrackRangeInsideLonLatRect(minLat, maxLat, minLon, maxLon); 415 coords[0] = (double) idxs[0]; 416 coords[1] = (double) idxs[1]; 417 if ((coords[0] == -1) || (coords[1] == -1)) return null; 418 if (xStride > 0) { 419 coords[2] = xStride; 420 } 421 422 coords = subset.get("VertDim"); 423 if (yStride > 0) { 424 coords[2] = yStride; 425 } 426 return subset; 427 } 428 429 public Map<String, double[]> getSubsetFromLonLatRect(double minLat, double maxLat, double minLon, double maxLon) { 430 return getSubsetFromLonLatRect(getDefaultSubset(), minLat, maxLat, minLon, maxLon); 431 } 432 433 public Map<String, double[]> getSubsetFromLonLatRect(double minLat, double maxLat, double minLon, double maxLon, 434 int xStride, int yStride, int zStride) { 435 436 return getSubsetFromLonLatRect(getDefaultSubset(), minLat, maxLat, minLon, maxLon, xStride, yStride, zStride); 437 } 438 439 public abstract float[] getVertBinAltitude() throws Exception; 440 public abstract float[] getTrackTimes() throws Exception; 441 public abstract RealType makeVertLocType() throws Exception; 442 public abstract RealType makeTrackTimeType() throws Exception; 443 public abstract float[] getTrackLongitude() throws Exception; 444 public abstract float[] getTrackLatitude() throws Exception; 445 446 public static float[] medianFilter(float[] A, int lenx, int leny, int window_lenx, int window_leny) 447 throws VisADException { 448 float[] result = new float[A.length]; 449 float[] window = new float[window_lenx*window_leny]; 450 float[] new_window = new float[window_lenx*window_leny]; 451 int[] sort_indexes = new int[window_lenx*window_leny]; 452 453 int a_idx; 454 int w_idx; 455 456 int w_lenx = window_lenx/2; 457 int w_leny = window_leny/2; 458 459 int lo; 460 int hi; 461 int ww_jj; 462 int ww_ii; 463 int cnt; 464 465 for (int j=0; j<leny; j++) { 466 for (int i=0; i<lenx; i++) { 467 a_idx = j*lenx + i; 468 cnt = 0; 469 for (int w_j=-w_leny; w_j<w_leny; w_j++) { 470 for (int w_i=-w_lenx; w_i<w_lenx; w_i++) { 471 ww_jj = w_j + j; 472 ww_ii = w_i + i; 473 w_idx = (w_j+w_leny)*window_lenx + (w_i+w_lenx); 474 if ((ww_jj >= 0) && (ww_ii >=0) && (ww_jj < leny) && (ww_ii < lenx)) { 475 window[cnt] = A[ww_jj*lenx+ww_ii]; 476 cnt++; 477 } 478 } 479 } 480 System.arraycopy(window, 0, new_window, 0, cnt); 481 //-sort_indexes = QuickSort.sort(new_window, sort_indexes); 482 sort_indexes = QuickSort.sort(new_window); 483 result[a_idx] = new_window[cnt/2]; 484 } 485 } 486 return result; 487 } 488 489}