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