001    /*
002     * $Id: SwathNavigation.java,v 1.17 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.Set;
034    import visad.Gridded2DSet;
035    import visad.Gridded2DDoubleSet;
036    import visad.Linear2DSet;
037    import visad.CoordinateSystem;
038    import visad.GridCoordinateSystem;
039    import visad.RealTupleType;
040    import java.util.HashMap;
041    
042    public class SwathNavigation implements Navigation  {
043    
044      public static SwathNavigation createNavigation(SwathAdapter swathAdapter) throws Exception {
045        String product_name = null;
046        SwathNavigation swathNav = null;
047        
048        product_name = (String) ((HashMap)swathAdapter.getMetadata()).get(SwathAdapter.product_name);
049    
050        if (product_name == null) {
051          swathNav = new SwathNavigation(swathAdapter);
052        }
053        else if (product_name == "IASI_L1C_xxx") {
054          swathNav = new IASI_L1C_LonLatNavigation(swathAdapter);
055        }
056        else if (product_name == "CrIS_SDR") {
057          swathNav = new CrIS_SDR_LonLatNavigation(swathAdapter);
058        }
059        else {
060          swathNav = new SwathNavigation(swathAdapter);
061        }
062        
063        return swathNav;
064      }
065    
066      int geo_track_idx;
067      int geo_xtrack_idx;
068      int geoTrackLen;
069      int geoXTrackLen;
070    
071      SwathAdapter swathAdapter;
072      MultiDimensionReader reader;
073      String lon_array_name;
074      String lat_array_name;
075      int[] idx_order = new int[2];
076      float ratio = 1;
077      float track_ratio = 1;
078      float xtrack_ratio = 1;
079      double track_offset = 0;
080      double xtrack_offset = 0;
081      int track_idx;
082      int xtrack_idx;
083      int[] geo_stride = new int[2];
084      int[] geo_count = new int[2];
085      int[] geo_start = new int[2];
086    
087      String scale_name = "SCALE_NAME";
088      String offset_name = "OFFSET_NAME";
089      String fillValue_name = "_FILLVALUE";
090    
091    
092      int numDims = 2;
093    
094      Class type;
095    
096      public SwathNavigation(SwathAdapter swathAdapter) throws Exception {
097    
098        HashMap metadata = (HashMap) swathAdapter.getMetadata();
099        reader = swathAdapter.getReader();
100        this.swathAdapter = swathAdapter;
101        track_idx = swathAdapter.track_idx;
102        xtrack_idx = swathAdapter.xtrack_idx;
103    
104        lon_array_name = (String)metadata.get(SwathAdapter.lon_array_name);
105        lat_array_name = (String)metadata.get(SwathAdapter.lat_array_name);
106    
107        String[] lon_dim_names = null;
108        String[] lat_dim_names = null;
109    
110        String[] lonDimNames = (String[]) metadata.get(SwathAdapter.lon_array_dimension_names); 
111        String[] latDimNames = (String[]) metadata.get(SwathAdapter.lat_array_dimension_names); 
112    
113        if (lonDimNames != null) {
114          lon_dim_names = lonDimNames;
115          lat_dim_names = latDimNames;
116        }
117        else {
118          lon_dim_names = reader.getDimensionNames(lon_array_name);
119          lat_dim_names = reader.getDimensionNames(lat_array_name);
120        }
121    
122        int[] lon_dim_lengths = reader.getDimensionLengths(lon_array_name);
123        int[] lat_dim_lengths = reader.getDimensionLengths(lat_array_name);
124    
125        numDims = lon_dim_lengths.length;
126        geo_stride = new int[numDims];
127        geo_count = new int[numDims];
128        geo_start = new int[numDims];
129    
130    
131        String geo_track_name = (String) metadata.get(SwathAdapter.geo_track_name);
132        String geo_xtrack_name = (String) metadata.get(SwathAdapter.geo_xtrack_name);
133    
134        for (int k=0; k<numDims;k++) {
135          if ( geo_track_name.equals(lon_dim_names[k]) ) {
136             geo_track_idx = k;
137          }
138          if ( geo_xtrack_name.equals(lon_dim_names[k]) ) {
139             geo_xtrack_idx = k;
140          }
141        }
142    
143        if (geo_track_idx < geo_xtrack_idx) {
144          idx_order[0] = geo_xtrack_idx;
145          idx_order[1] = geo_track_idx;
146        }
147        else {
148          idx_order[0] = geo_track_idx;
149          idx_order[1] = geo_xtrack_idx;
150        }
151    
152        geoTrackLen  = lon_dim_lengths[geo_track_idx];
153        geoXTrackLen = lon_dim_lengths[geo_xtrack_idx];
154    
155        String str = (String) metadata.get(SwathAdapter.geo_track_skip_name);
156    
157        if (str != null) {
158          track_ratio = (float) Double.parseDouble(str);
159          ratio = track_ratio;
160        }
161        str = (String) metadata.get(SwathAdapter.geo_xtrack_skip_name);
162        if (str != null) {
163          xtrack_ratio = (float) Double.parseDouble(str);
164        }
165        str = (String) metadata.get(SwathAdapter.geo_track_offset_name);
166        if (str != null) {
167          track_offset = Double.parseDouble(str);
168        }
169        str = (String) metadata.get(SwathAdapter.geo_xtrack_offset_name);
170        if (str != null) {
171          xtrack_offset = Double.parseDouble(str);
172        }
173    
174        str = (String) metadata.get(SwathAdapter.geo_scale_name);
175        if (str != null) {
176          scale_name = str;
177        }
178    
179        str = (String) metadata.get(SwathAdapter.geo_offset_name);
180        if (str != null) {
181          offset_name = str;
182        }
183    
184        str = (String) metadata.get(SwathAdapter.geo_fillValue_name);
185        if (str != null) {
186          fillValue_name = str;
187        }
188     
189        type = reader.getArrayType(lon_array_name);
190      }
191    
192      public CoordinateSystem getVisADCoordinateSystem(Linear2DSet domainSet, Object domainSubset) throws Exception
193      {
194          Subset select = swathAdapter.getIndexes((HashMap)domainSubset);
195    
196          double[] track_coords = (double[]) ((HashMap)domainSubset).get(SwathAdapter.track_name);
197          double[] xtrack_coords = (double[]) ((HashMap)domainSubset).get(SwathAdapter.xtrack_name);
198          
199          int[] stride = new int[numDims];
200          stride[geo_track_idx] = (int) track_coords[2];
201          stride[geo_xtrack_idx] = (int) xtrack_coords[2]; 
202    
203    
204          if (numDims > 2) { // initialize geo arrays, then recompute xtrack/track dimensions below
205            if (numDims == select.getRank()) {
206              int[] start = select.getStart();
207              int[] count = select.getCount();
208              stride = select.getStride();
209              for (int i=0; i<numDims; i++) {
210                geo_start[i] = start[i];
211                geo_count[i] = count[i];
212                geo_stride[i] = stride[i];
213              }
214            }
215            else {
216              geo_start[geo_track_idx] = (int) track_coords[0];
217              geo_start[geo_xtrack_idx] = (int) xtrack_coords[0];
218              geo_count[geo_track_idx] = (int) ((track_coords[1] - track_coords[0])/track_coords[2] + 1f);
219              geo_count[geo_xtrack_idx] = (int) ((xtrack_coords[1] - xtrack_coords[0])/xtrack_coords[2] + 1f);
220            }
221          }
222    
223    
224          if (ratio/(float)stride[0] <= 1) {
225            geo_stride[geo_track_idx] = Math.round((1f/(track_ratio/((float)stride[geo_track_idx]))));
226            geo_stride[geo_xtrack_idx] = Math.round((1f/(xtrack_ratio/((float)stride[geo_xtrack_idx]))));
227          }
228          else {
229            geo_stride[geo_track_idx] = 1;
230            geo_stride[geo_xtrack_idx] = 1;
231          }
232    
233          int geo_track_start  = (int) Math.ceil((track_coords[0] - track_offset)/track_ratio);
234          int geo_xtrack_start = (int) Math.ceil((xtrack_coords[0] - xtrack_offset)/xtrack_ratio);
235    
236          int geo_track_end  = (int) ((track_coords[1] - track_offset)/((double)track_ratio));
237          int geo_xtrack_end = (int) ((xtrack_coords[1] - xtrack_offset)/((double)xtrack_ratio));
238    
239          geo_count[geo_track_idx]  = (int) ((geo_track_end - geo_track_start)/geo_stride[geo_track_idx]) + 1;
240          geo_count[geo_xtrack_idx] = (int) ((geo_xtrack_end - geo_xtrack_start)/geo_stride[geo_xtrack_idx]) + 1;
241    
242          geo_track_end = geo_track_start + (geo_count[geo_track_idx]-1)*geo_stride[geo_track_idx];
243          geo_xtrack_end = geo_xtrack_start + (geo_count[geo_xtrack_idx]-1)*geo_stride[geo_xtrack_idx];
244         
245          geo_start[geo_track_idx]  = geo_track_start;
246          geo_start[geo_xtrack_idx] = geo_xtrack_start;
247    
248          //-- convert back track/xtrack coords:
249          int new_track_start  = (int) (geo_track_start*track_ratio + (float)track_offset);
250          int new_xtrack_start = (int) (geo_xtrack_start*xtrack_ratio + (float)xtrack_offset);
251          int new_track_end  = (int) (geo_track_end*track_ratio + (float)track_offset);
252          int new_xtrack_end = (int) (geo_xtrack_end*xtrack_ratio + (float)xtrack_offset);
253    
254    
255          //- these must be only 2D (Swath dimensions)
256          double[] first = new double[2];
257          double[] last  = new double[2];
258          int[] length   = new int[2];
259    
260          int track_idx;
261          int xtrack_idx;
262          if (geo_track_idx < geo_xtrack_idx) {
263            track_idx = 1;
264            xtrack_idx = 0;
265          } else {
266            track_idx = 0;
267            xtrack_idx = 1;
268          }
269    
270          first[track_idx]  = new_track_start;
271          first[xtrack_idx] = new_xtrack_start;
272          last[track_idx]   = new_track_end;
273          last[xtrack_idx]  = new_xtrack_end;
274          length[track_idx]  = (int) ((last[track_idx] - first[track_idx])/stride[geo_track_idx] + 1);
275          length[xtrack_idx] = (int) ((last[xtrack_idx] - first[xtrack_idx])/stride[geo_xtrack_idx] + 1);
276    
277          domainSet = new Linear2DSet(first[0], last[0], length[0], first[1], last[1], length[1]);
278       
279          Gridded2DSet gset = null;
280    
281          gset = createInterpSet();
282    
283          CoordinateSystem cs = new LongitudeLatitudeCoordinateSystem(domainSet, gset);
284    
285          return cs;
286      }
287    
288      Gridded2DSet createInterpSet() throws Exception {
289        Gridded2DSet gset = null;
290        if (type == Float.TYPE) {
291          float[] lonValues = reader.getFloatArray(lon_array_name, geo_start, geo_count, geo_stride);
292          float[] latValues = reader.getFloatArray(lat_array_name, geo_start, geo_count, geo_stride);
293                                                                                                                                                 
294          gset = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple,
295                         new float[][] {lonValues, latValues},
296                             geo_count[idx_order[0]], geo_count[idx_order[1]],
297                                null, null, null, false, false);
298        }
299        else if (type == Double.TYPE) {
300          double[] lonValues = reader.getDoubleArray(lon_array_name, geo_start, geo_count, geo_stride);
301          double[] latValues = reader.getDoubleArray(lat_array_name, geo_start, geo_count, geo_stride);
302                                                                                                                                                 
303          gset = new Gridded2DDoubleSet(RealTupleType.SpatialEarth2DTuple,
304                        new double[][] {lonValues, latValues},
305                           geo_count[idx_order[0]], geo_count[idx_order[1]],
306                               null, null, null, false);
307        }
308        else if (type == Short.TYPE) {
309          short[] values = reader.getShortArray(lon_array_name, geo_start, geo_count, geo_stride);
310          HashMap metadata = new HashMap();
311          metadata.put(SwathAdapter.array_name, lon_array_name);
312          metadata.put(SwathAdapter.scale_name, scale_name);
313          metadata.put(SwathAdapter.offset_name, offset_name);
314          metadata.put(SwathAdapter.fill_value_name, fillValue_name);
315          RangeProcessor rangeProcessor = RangeProcessor.createRangeProcessor(reader, metadata);
316          float[] lonValues = rangeProcessor.processRange(values, null);
317          
318          values = reader.getShortArray(lat_array_name, geo_start, geo_count, geo_stride);
319          metadata = new HashMap();
320          metadata.put(SwathAdapter.array_name, lat_array_name);
321          metadata.put(SwathAdapter.scale_name, scale_name);
322          metadata.put(SwathAdapter.offset_name, offset_name);
323          metadata.put(SwathAdapter.fill_value_name, fillValue_name);
324          rangeProcessor = RangeProcessor.createRangeProcessor(reader, metadata);
325          float[] latValues = rangeProcessor.processRange(values, null);
326    
327    
328          gset = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple,
329                         new float[][] {lonValues, latValues},
330                             geo_count[idx_order[0]], geo_count[idx_order[1]],
331                                null, null, null, false, false);
332    
333        }
334        return gset;
335      }
336    
337    
338    
339      public static Linear2DSet getNavigationDomain(double data_x_start, double data_x_stop, double data_x_stride,
340                                             double data_y_start, double data_y_stop, double data_y_stride,
341                                             double ratio_x, double ratio_y,
342                                             double offset_x, double offset_y,
343                                             int[] geo_start, int[] geo_count, int[] geo_stride)
344          throws Exception {
345    
346          int geo_track_idx = 1;
347          int geo_xtrack_idx = 0;
348          double track_ratio = ratio_y;
349          double xtrack_ratio = ratio_x;
350          double track_offset = offset_y;
351          double xtrack_offset = offset_x;
352     
353          double[] track_coords = new double[3];
354          double[] xtrack_coords = new double[3];
355    
356          xtrack_coords[0] = data_x_start;
357          xtrack_coords[1] = data_x_stop;
358          track_coords[0] = data_y_start;
359          track_coords[1] = data_y_stop;
360    
361          double[] stride =  new double[2];
362          stride[geo_track_idx] = data_y_stride;
363          stride[geo_xtrack_idx] = data_x_stride;
364    
365          if (track_ratio/(float)stride[0] <= 1) {
366            geo_stride[geo_track_idx] = (int) Math.round((1/(track_ratio/(stride[1]))));
367            geo_stride[geo_xtrack_idx] = (int) Math.round((1/(xtrack_ratio/(stride[0]))));
368          }
369          else {
370            geo_stride[0] = 1;
371            geo_stride[1] = 1;
372          }
373    
374          int geo_track_start  = (int) Math.ceil((track_coords[0] - track_offset)/track_ratio);
375          int geo_xtrack_start = (int) Math.ceil((xtrack_coords[0] - xtrack_offset)/xtrack_ratio);
376    
377          int geo_track_end  = (int) ((track_coords[1] - track_offset)/((double)track_ratio));
378          int geo_xtrack_end = (int) ((xtrack_coords[1] - xtrack_offset)/((double)xtrack_ratio));
379    
380          geo_count[geo_track_idx]  = (int) ((geo_track_end - geo_track_start)/geo_stride[geo_track_idx]) + 1;
381          geo_count[geo_xtrack_idx] = (int) ((geo_xtrack_end - geo_xtrack_start)/geo_stride[geo_xtrack_idx]) + 1;
382    
383          geo_track_end = geo_track_start + (geo_count[geo_track_idx]-1)*geo_stride[geo_track_idx];
384          geo_xtrack_end = geo_xtrack_start + (geo_count[geo_xtrack_idx]-1)*geo_stride[geo_xtrack_idx];
385    
386          geo_start[geo_track_idx]  = geo_track_start;
387          geo_start[geo_xtrack_idx] = geo_xtrack_start;
388    
389          //-- convert back track/xtrack coords:
390          int new_track_start  = (int) (geo_track_start*track_ratio + (float)track_offset);
391          int new_xtrack_start = (int) (geo_xtrack_start*xtrack_ratio + (float)xtrack_offset);
392          int new_track_end  = (int) (geo_track_end*track_ratio + (float)track_offset);
393          int new_xtrack_end = (int) (geo_xtrack_end*xtrack_ratio + (float)xtrack_offset);
394    
395    
396          double[] first = new double[2];
397          double[] last  = new double[2];
398          int[] length   = new int[2];
399          first[geo_track_idx]  = new_track_start;
400          first[geo_xtrack_idx] = new_xtrack_start;
401          last[geo_track_idx]   = new_track_end;
402          last[geo_xtrack_idx]  = new_xtrack_end;
403          length[geo_track_idx]  = (int) ((last[geo_track_idx] - first[geo_track_idx])/stride[geo_track_idx] + 1);
404          length[geo_xtrack_idx] = (int) ((last[geo_xtrack_idx] - first[geo_xtrack_idx])/stride[geo_xtrack_idx] + 1);
405    
406          return new Linear2DSet(first[0], last[0], length[0], first[1], last[1], length[1]);
407    
408      }
409    
410    
411    }