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