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