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