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