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 java.util.HashMap;
032    
033    import visad.CoordinateSystem;
034    import visad.FunctionType;
035    import visad.Linear2DSet;
036    import visad.RealTupleType;
037    import visad.RealType;
038    import visad.Set;
039    import visad.Unit;
040    
041    public class SwathAdapter extends MultiDimensionAdapter {
042    
043          String nav_type = "Interp";
044          boolean lon_lat_trusted = true;
045    
046          private int TrackLen;
047          private int XTrackLen;
048    
049          static String longitude_name = "Longitude";
050          static String latitude_name  = "Latitude";
051          static String track_name  = "Track";
052          static String xtrack_name = "XTrack";
053          static String geo_track_name = "geo_Track";
054          static String geo_xtrack_name  = "geo_XTrack";
055          static String array_name = "array_name";
056          static String array_dimension_names = "array_dimension_names";
057          static String lon_array_name = "lon_array_name";
058          static String lat_array_name = "lat_array_name";
059          static String lon_array_dimension_names = "lon_array_dimension_names";
060          static String lat_array_dimension_names = "lat_array_dimension_names";
061          static String range_name = "range_name";
062          static String product_name = "product_name";
063          static String scale_name = "scale_name";
064          static String offset_name = "offset_name";
065          static String fill_value_name = "fill_value_name";
066          static String geo_track_offset_name  = "geoTrack_offset";
067          static String geo_xtrack_offset_name = "geoXTrack_offset";
068          static String geo_track_skip_name  = "geoTrack_skip";
069          static String geo_xtrack_skip_name = "geoXTrack_skip";
070          static String geo_scale_name = "geo_scale_name";
071          static String geo_offset_name = "geo_scale_name";
072          static String geo_fillValue_name = "geo_fillValue_name";
073          static String multiScaleDimensionIndex = "multiScaleDimensionIndex";
074    
075          String[] rangeName_s  = null;
076          Class[] arrayType_s = null;
077          Unit[] rangeUnit_s  = new Unit[] {null};
078    
079          String rangeName = null;
080    
081          RealType track  = RealType.getRealType(track_name);
082          RealType xtrack = RealType.getRealType(xtrack_name);
083          RealType[] domainRealTypes = new RealType[2];
084    
085          int track_idx      = -1;
086          int xtrack_idx     = -1;
087          int lon_track_idx  = -1;
088          int lon_xtrack_idx = -1;
089          int lat_track_idx  = -1;
090          int lat_xtrack_idx = -1;
091          int range_rank     = -1;
092    
093          int geo_track_offset = 0;
094          int geo_track_skip = 1;
095          int geo_xtrack_offset = 0;
096          int geo_xtrack_skip = 1;
097    
098          int track_tup_idx;
099          int xtrack_tup_idx;
100    
101          private SwathNavigation navigation;
102    
103          private Linear2DSet swathDomain;
104          private Linear2DSet domainSet_save;
105    
106          private Object last_subset;
107    
108          int default_stride = 1;
109    
110          public static HashMap getEmptySubset() {
111            HashMap<String, double[]> subset = new HashMap<String, double[]>();
112            subset.put(track_name, new double[3]);
113            subset.put(xtrack_name, new double[3]);
114            return subset;
115          }
116    
117          public static HashMap<String, Object> getEmptyMetadataTable() {
118              HashMap<String, Object> metadata = new HashMap<String, Object>();
119              metadata.put(array_name, null);
120              metadata.put(array_dimension_names, null);
121              metadata.put(track_name, null);
122              metadata.put(xtrack_name, null);
123              metadata.put(geo_track_name, null);
124              metadata.put(geo_xtrack_name, null);
125              metadata.put(lon_array_name, null);
126              metadata.put(lat_array_name, null);
127              metadata.put(lon_array_dimension_names, null);
128              metadata.put(lat_array_dimension_names, null);
129              metadata.put(scale_name, null);
130              metadata.put(offset_name, null);
131              metadata.put(fill_value_name, null);
132              metadata.put(range_name, null);
133              metadata.put(product_name, null);
134              metadata.put(geo_track_offset_name, null);
135              metadata.put(geo_xtrack_offset_name, null);
136              metadata.put(geo_track_skip_name, null);
137              metadata.put(geo_xtrack_skip_name, null);
138              metadata.put(multiScaleDimensionIndex, null);
139              return metadata;
140          }
141    
142          public SwathAdapter() {
143    
144          }
145    
146          public SwathAdapter(MultiDimensionReader reader, HashMap metadata) {
147            super(reader, metadata);
148            this.init();
149          }
150    
151          private void init() {
152            for (int k=0; k<array_rank;k++) {
153              if ( ((String)metadata.get(track_name)).equals(array_dim_names[k]) ) {
154                track_idx = k;
155              }
156              if ( ((String)metadata.get(xtrack_name)).equals(array_dim_names[k]) ) {
157                xtrack_idx = k;
158              }
159            }
160    
161            int[] lengths = new int[2];
162    
163            if (track_idx < xtrack_idx) {
164              domainRealTypes[0] = xtrack;
165              domainRealTypes[1] = track;
166              lengths[0] = array_dim_lengths[xtrack_idx];
167              lengths[1] = array_dim_lengths[track_idx];
168              track_tup_idx = 1;
169              xtrack_tup_idx = 0;
170            }
171            else {
172              domainRealTypes[0] = track;
173              domainRealTypes[1] = xtrack;
174              lengths[0] = array_dim_lengths[track_idx];
175              lengths[1] = array_dim_lengths[xtrack_idx];
176              track_tup_idx = 0;
177              xtrack_tup_idx = 1;
178            }
179    
180            TrackLen  = array_dim_lengths[track_idx];
181            XTrackLen = array_dim_lengths[xtrack_idx];
182            
183            setLengths();
184    
185            lengths[track_tup_idx]  = TrackLen;
186            lengths[xtrack_tup_idx] = XTrackLen;
187    
188            if (metadata.get(range_name) != null) {
189              rangeName = (String)metadata.get(range_name);
190            } 
191            else {
192              rangeName = (String)metadata.get(array_name);
193            }
194          
195            rangeType = RealType.getRealType(rangeName, rangeUnit_s[0]);
196    
197            /** TODO could be a mis-match between supplied unit, and default
198                unit of an existing RealType with same name. */
199            if (rangeType == null) {
200              rangeType = RealType.getRealType(rangeName);
201            }
202    
203            try {
204              RangeProcessor rangeProcessor = RangeProcessor.createRangeProcessor(reader, metadata);
205              if ( !(reader instanceof GranuleAggregation) ) {
206                setRangeProcessor(rangeProcessor);
207              }
208            } 
209            catch (Exception e) {
210              System.out.println("RangeProcessor failed to create");
211              e.printStackTrace();
212            }
213    
214            try {
215              navigation = SwathNavigation.createNavigation(this);
216              RealTupleType domainTupType = new RealTupleType(domainRealTypes[0], domainRealTypes[1]);
217              swathDomain = new Linear2DSet(domainTupType, 0, lengths[0]-1, lengths[0], 0, lengths[1]-1, lengths[1]);
218            }
219            catch (Exception e) {
220              System.out.println("Navigation failed to create");
221              e.printStackTrace();
222            }
223    
224            if (XTrackLen <= 256) {
225              default_stride = 1;
226            }
227            else {
228              default_stride = (int) XTrackLen/256;
229            }
230            
231            /* force default stride even */
232            if (default_stride > 1) {
233              default_stride = (default_stride/2)*2;
234            }
235    
236          }
237    
238          protected void setLengths() {
239          }
240    
241          public int getTrackLength() {
242            return TrackLen;
243          }
244    
245          public int getXTrackLength() {
246            return XTrackLen;
247          }
248    
249          public SwathNavigation getNavigation() {
250            return navigation;
251          }
252    
253          protected void setTrackLength(int len) {
254            TrackLen = len;
255          }
256    
257          protected void setXTrackLength(int len) {
258            XTrackLen = len;
259          }
260    
261          public Set makeDomain(Object subset) throws Exception {
262            if (last_subset != null) {
263              if (spatialEquals(last_subset, subset)) return domainSet_save;
264            }
265    
266            double[] first = new double[2];
267            double[] last = new double[2];
268            int[] length = new int[2];
269    
270            HashMap<String, double[]> domainSubset = new HashMap<String, double[]>();
271            domainSubset.put(track_name, (double[]) ((HashMap)subset).get(track_name));
272            domainSubset.put(xtrack_name, (double[]) ((HashMap)subset).get(xtrack_name));
273    
274            domainSubset.put(track_name, new double[] {0,0,0});
275            domainSubset.put(xtrack_name, new double[] {0,0,0});
276    
277            // compute coordinates for the Linear2D domainSet
278            for (int kk=0; kk<2; kk++) {
279              RealType rtype = domainRealTypes[kk];
280              String name = rtype.getName();
281              double[] coords = (double[]) ((HashMap)subset).get(name);
282              coords[0] = Math.ceil(coords[0]);
283              coords[1] = Math.floor(coords[1]);
284              first[kk] = coords[0];
285              last[kk] = coords[1];
286              length[kk] = (int) ((last[kk] - first[kk])/coords[2] + 1);
287              last[kk] = first[kk] + (length[kk]-1)*coords[2];
288    
289              double[] new_coords = domainSubset.get(name);
290              new_coords[0] = first[kk];
291              new_coords[1] = last[kk];
292              new_coords[2] = coords[2];
293            }
294            last_subset = subset;
295    
296            Linear2DSet domainSet = new Linear2DSet(first[0], last[0], length[0], first[1], last[1], length[1]);
297            //CoordinateSystem cs = navigation.getVisADCoordinateSystem(domainSet, domainSubset);
298            CoordinateSystem cs = navigation.getVisADCoordinateSystem(domainSet, subset);
299    
300            RealTupleType domainTupType = new RealTupleType(domainRealTypes[0], domainRealTypes[1], cs, null);
301            domainSet_save = new Linear2DSet(domainTupType, first[0], last[0], length[0], first[1], last[1], length[1]);
302    
303            return domainSet_save;
304          }
305    
306          public String getArrayName() {
307            return rangeName;
308          }
309    
310          public FunctionType getMathType() {
311            return null;
312          }
313    
314          public RealType[] getDomainRealTypes() {
315            return domainRealTypes;
316          }
317    
318          public Linear2DSet getSwathDomain() {
319            return swathDomain;
320          }
321          
322          public boolean spatialEquals(Object last_subset, Object subset) {
323            double[] last_coords = (double[]) ((HashMap)last_subset).get(track_name);
324            double[] coords = (double[]) ((HashMap)subset).get(track_name);
325    
326            for (int k=0; k<coords.length; k++) {
327              if (coords[k] != last_coords[k]) {
328                return false;
329              }
330            }
331    
332            last_coords = (double[]) ((HashMap)last_subset).get(xtrack_name);
333            coords = (double[]) ((HashMap)subset).get(xtrack_name);
334    
335            for (int k=0; k<coords.length; k++) {
336              if (coords[k] != last_coords[k]) { 
337                 return false;
338              }
339            }
340          
341            return true;
342          }
343    
344          public void setDefaultStride(int stride) {
345            default_stride = stride;
346          }
347    
348          public HashMap getDefaultSubset() {
349            HashMap subset = SwathAdapter.getEmptySubset();
350    
351            double[] coords = (double[])subset.get("Track");
352            coords[0] = 0.0;
353            coords[1] = TrackLen - 1;
354            coords[2] = (double)default_stride;
355            subset.put("Track", coords);
356    
357            coords = (double[])subset.get("XTrack");
358            coords[0] = 0.0;
359            coords[1] = XTrackLen - 1 ;
360            coords[2] = (double)default_stride;
361            subset.put("XTrack", coords);
362            return subset;
363          }
364    }