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