001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
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 */
028package edu.wisc.ssec.mcidasv.data.hydra;
029
030import java.io.File;
031import java.rmi.RemoteException;
032import java.util.Enumeration;
033import java.util.HashMap;
034import java.util.Hashtable;
035import java.util.List;
036import java.util.Map;
037
038import javax.swing.JOptionPane;
039
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043import ucar.nc2.NetcdfFile;
044import ucar.nc2.Variable;
045import ucar.unidata.data.DataCategory;
046import ucar.unidata.data.DataChoice;
047import ucar.unidata.data.DataSelection;
048import ucar.unidata.data.DataSelectionComponent;
049import ucar.unidata.data.DataSourceDescriptor;
050import ucar.unidata.data.DirectDataChoice;
051import ucar.unidata.data.GeoLocationInfo;
052import ucar.unidata.data.GeoSelection;
053import ucar.unidata.util.Misc;
054
055import visad.Data;
056import visad.FlatField;
057import visad.GriddedSet;
058import visad.VisADException;
059
060import edu.wisc.ssec.mcidasv.data.HydraDataSource;
061import edu.wisc.ssec.mcidasv.data.PreviewSelection;
062
063/**
064 * A data source for Multi Dimension Data 
065 */
066
067public class MultiDimensionDataSource extends HydraDataSource {
068
069    private static final Logger logger = LoggerFactory.getLogger(MultiDimensionDataSource.class);
070
071    /** Sources file */
072    protected String filename;
073
074    protected MultiDimensionReader reader;
075
076    protected MultiDimensionAdapter[] adapters = null;
077    protected Map[] defaultSubsets = null;
078    private Map<String, MultiDimensionAdapter> adapterMap = new HashMap<>();
079    protected Hashtable[] propsArray = null;
080    protected List[] categoriesArray = null;
081
082    protected SpectrumAdapter spectrumAdapter;
083
084    private static final String DATA_DESCRIPTION = "Multi Dimension Data";
085
086    private Map<String, double[]> defaultSubset;
087    public TrackAdapter track_adapter;
088    private MultiSpectralData multiSpectData;
089
090    private List categories;
091    private boolean hasImagePreview = false;
092    private boolean hasTrackPreview = false;
093    
094    private TrackSelection trackSelection = null;
095
096    /**
097     * Zero-argument constructor for construction via unpersistence.
098     */
099    public MultiDimensionDataSource() {}
100
101    /**
102     * Construct a new HYDRA hdf data source.
103     * @param  descriptor  descriptor for this {@code DataSource}
104     * @param  fileName  name of the hdf file to read
105     * @param  properties  hashtable of properties
106     *
107     * @throws VisADException problem creating data
108     */
109    public MultiDimensionDataSource(DataSourceDescriptor descriptor,
110                                 String fileName, Hashtable properties)
111            throws VisADException {
112        this(descriptor, Misc.newList(fileName), properties);
113    }
114
115    /**
116     * Construct a new HYDRA hdf data source.
117     * @param  descriptor  descriptor for this {@code DataSource}
118     * @param  newSources  List of filenames
119     * @param  properties  hashtable of properties
120     *
121     * @throws VisADException problem creating data
122     */
123    public MultiDimensionDataSource(DataSourceDescriptor descriptor,
124                                 List newSources, Hashtable properties)
125            throws VisADException {
126        super(descriptor, newSources, DATA_DESCRIPTION, properties);
127
128        this.filename = (String) sources.get(0);
129
130        try {
131          setup();
132        } catch (Exception e) {
133          throw new VisADException("could not set up MultiDimensionDataSource", e);
134        }
135    }
136
137    public void setup() throws Exception {
138
139        try {
140          if (filename.contains("MYD02SSH")) { // get file union
141            String other = (String) sources.get(1);
142            if (filename.endsWith("nav.hdf")) {
143              String tmp = filename;
144              filename = other;
145              other = tmp;
146            }
147            reader = NetCDFFile.makeUnion(filename, other);
148          }
149          else {
150            reader = new NetCDFFile(filename);
151          }
152        } catch (Exception e) {
153          logger.error("Cannot create NetCDF reader for file: " + filename, e);
154        }
155
156        adapters = new MultiDimensionAdapter[2];
157        defaultSubsets = new HashMap[2]; 
158        Hashtable<String, String[]> properties = new Hashtable<>();
159        
160        String name = (new File(filename)).getName();
161
162        if (name.startsWith("MOD04") || name.startsWith("MYD04")) {
163          Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
164          table.put("array_name", "mod04/Data_Fields/Optical_Depth_Land_And_Ocean");
165          table.put("lon_array_name", "mod04/Geolocation_Fields/Longitude");
166          table.put("lat_array_name", "mod04/Geolocation_Fields/Latitude");
167          table.put("XTrack", "Cell_Across_Swath");
168          table.put("Track", "Cell_Along_Swath");
169          table.put("geo_Track", "Cell_Along_Swath");
170          table.put("geo_XTrack", "Cell_Across_Swath");
171          table.put("scale_name", "scale_factor");
172          table.put("offset_name", "add_offset");
173          table.put("fill_value_name", "_FillValue");
174          table.put("range_name", "Optical_Depth_Land_And_Ocean");
175          adapters[0] = new SwathAdapter(reader, table);
176          categories = DataCategory.parseCategories("2D grid;GRID-2D;");
177          defaultSubset = adapters[0].getDefaultSubset();
178          defaultSubsets[0] = defaultSubset;
179          hasImagePreview = true;
180        }
181        else if (name.startsWith("MOD06") || name.startsWith("MYD06")) {
182          hasImagePreview = true;
183          String path = "mod06/Data_Fields/";
184          String[] arrayNames = new String[] {"Cloud_Optical_Thickness", "Cloud_Effective_Radius", "Cloud_Water_Path"};
185          String[] arrayNames_5km = new String[] {"Cloud_Top_Pressure", "Cloud_Top_Temperature", "Cloud_Fraction"};
186  
187          adapters = new MultiDimensionAdapter[arrayNames.length+arrayNames_5km.length];
188          defaultSubsets = new HashMap[arrayNames.length+arrayNames_5km.length];
189          categoriesArray = new List[adapters.length];
190
191          
192          for (int k=0; k<arrayNames.length; k++) {
193            Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
194            table.put("array_name", path.concat(arrayNames[k]));
195            table.put("lon_array_name", "mod06/Geolocation_Fields/Longitude");
196            table.put("lat_array_name", "mod06/Geolocation_Fields/Latitude");
197            table.put("XTrack", "Cell_Across_Swath_1km");
198            table.put("Track", "Cell_Along_Swath_1km");
199            table.put("geo_Track", "Cell_Along_Swath_5km");
200            table.put("geo_XTrack", "Cell_Across_Swath_5km");
201            table.put("scale_name", "scale_factor");
202            table.put("offset_name", "add_offset");
203            table.put("fill_value_name", "_FillValue");
204            table.put("range_name", arrayNames[k]);
205
206            table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
207            table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
208            table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
209            table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0148148148));
210
211            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
212            swathAdapter.setDefaultStride(10);
213            defaultSubset = swathAdapter.getDefaultSubset();
214            adapters[k] = swathAdapter;
215            defaultSubsets[k] = defaultSubset;
216            categoriesArray[k] = DataCategory.parseCategories("1km swath;GRID-2D;");
217          }
218
219          for (int k=0; k<arrayNames_5km.length; k++) {
220            Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
221            table.put("array_name", path.concat(arrayNames_5km[k]));
222            table.put("lon_array_name", "mod06/Geolocation_Fields/Longitude");
223            table.put("lat_array_name", "mod06/Geolocation_Fields/Latitude");
224            table.put("XTrack", "Cell_Across_Swath_5km");
225            table.put("Track", "Cell_Along_Swath_5km");
226            table.put("geo_Track", "Cell_Along_Swath_5km");
227            table.put("geo_XTrack", "Cell_Across_Swath_5km");
228            table.put("scale_name", "scale_factor");
229            table.put("offset_name", "add_offset");
230            table.put("fill_value_name", "_FillValue");
231            table.put("range_name", arrayNames_5km[k]);
232
233            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
234            defaultSubset = swathAdapter.getDefaultSubset();
235            adapters[arrayNames.length+k] = swathAdapter;
236            defaultSubsets[arrayNames.length+k] = defaultSubset;
237            categoriesArray[arrayNames.length+k] = DataCategory.parseCategories("5km swath;GRID-2D;");
238          }
239       }
240       else if (name.startsWith("a1") && name.contains("mod06")) {
241          hasImagePreview = true;
242          String[] arrayNames = new String[] {"Cloud_Optical_Thickness", "Cloud_Effective_Radius", "Cloud_Water_Path"};
243          String[] arrayNames_5km = new String[] {"Cloud_Top_Pressure", "Cloud_Top_Temperature", "Cloud_Fraction"};
244
245          adapters = new MultiDimensionAdapter[arrayNames.length+arrayNames_5km.length];
246          defaultSubsets = new HashMap[arrayNames.length+arrayNames_5km.length];
247          categoriesArray = new List[adapters.length];
248
249
250          for (int k=0; k<arrayNames.length; k++) {
251            Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
252            table.put("array_name", arrayNames[k]);
253            table.put("lon_array_name", "Longitude");
254            table.put("lat_array_name", "Latitude");
255            table.put("array_dimension_names", new String[] {"Cell_Along_Swath_1km", "Cell_Across_Swath_1km"});
256            table.put("lon_array_dimension_names", new String[] {"Cell_Along_Swath_1km", "Cell_Across_Swath_1km"});
257            table.put("lat_array_dimension_names", new String[] {"Cell_Along_Swath_1km", "Cell_Across_Swath_1km"});
258            table.put("XTrack", "Cell_Across_Swath_1km");
259            table.put("Track", "Cell_Along_Swath_1km");
260            table.put("geo_Track", "Cell_Along_Swath_5km");
261            table.put("geo_XTrack", "Cell_Across_Swath_5km");
262            table.put("scale_name", "scale_factor");
263            table.put("offset_name", "add_offset");
264            table.put("fill_value_name", "_FillValue");
265            table.put("range_name", arrayNames[k]);
266
267            table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
268            table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
269            table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
270            table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0148148148));
271
272            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
273            swathAdapter.setDefaultStride(10);
274            defaultSubset = swathAdapter.getDefaultSubset();
275            adapters[k] = swathAdapter;
276            defaultSubsets[k] = defaultSubset;
277            categoriesArray[k] = DataCategory.parseCategories("1km swath;GRID-2D;");
278          }
279
280          for (int k=0; k<arrayNames_5km.length; k++) {
281            Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
282            table.put("array_name", arrayNames_5km[k]);
283            table.put("lon_array_name", "Longitude");
284            table.put("lat_array_name", "Latitude");
285            table.put("array_dimension_names", new String[] {"Cell_Along_Swath_5km", "Cell_Across_Swath_5km"});
286            table.put("lon_array_dimension_names", new String[] {"Cell_Along_Swath_5km", "Cell_Across_Swath_5km"});
287            table.put("lat_array_dimension_names", new String[] {"Cell_Along_Swath_5km", "Cell_Across_Swath_5km"});
288            table.put("XTrack", "Cell_Across_Swath_5km");
289            table.put("Track", "Cell_Along_Swath_5km");
290            table.put("geo_Track", "Cell_Along_Swath_5km");
291            table.put("geo_XTrack", "Cell_Across_Swath_5km");
292            table.put("scale_name", "scale_factor");
293            table.put("offset_name", "add_offset");
294            table.put("fill_value_name", "_FillValue");
295            table.put("range_name", arrayNames_5km[k]);
296
297            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
298            defaultSubset = swathAdapter.getDefaultSubset();
299            adapters[arrayNames.length+k] = swathAdapter;
300            defaultSubsets[arrayNames.length+k] = defaultSubset;
301            categoriesArray[arrayNames.length+k] = DataCategory.parseCategories("5km swath;GRID-2D;");
302          }
303       }
304       else if (name.startsWith("CAL_LID_L1")) {
305
306           // Make sure the variables we need are present. If not, this is not a valid
307           // L1 CALIPSO file McV can work with.
308           
309           if (! ((hasVariable("Latitude")) &&
310                          (hasVariable("Longitude")) &&
311                          (hasVariable("Surface_Elevation")) &&
312                          (hasVariable("Tropopause_Height")) &&
313                          (hasVariable("Total_Attenuated_Backscatter_532"))) 
314                  ) {
315                   // Pop up a dialog letting user know we can't work wit this data
316                        String msg = "McIDAS-V is unable to read this Level 1 CALIPSO file.\n" +
317                                        "If you believe this is a valid file which should be supported,\n" +
318                                        "please contact the MUG or post a message on the MUG Forum.";
319                        Object[] params = { msg };
320                        JOptionPane.showMessageDialog(null, params, "Data Validity Test Failure", JOptionPane.OK_OPTION);
321                        throw new Exception("Unable to load CALIPSO data");
322           }
323           
324         adapters = new MultiDimensionAdapter[4];
325         defaultSubsets = new HashMap[4];
326         propsArray = new Hashtable[4]; 
327         
328         Map<String, Object> table = ProfileAlongTrack.getEmptyMetadataTable();
329         table.put(ProfileAlongTrack.array_name, "Total_Attenuated_Backscatter_532");
330         table.put(ProfileAlongTrack.ancillary_file_name, "/edu/wisc/ssec/mcidasv/data/hydra/resources/calipso/altitude");
331         table.put(ProfileAlongTrack.trackDim_name, "dim0");
332         table.put(ProfileAlongTrack.vertDim_name, "dim1");
333         table.put(ProfileAlongTrack.profileTime_name, "Profile_Time");
334         table.put(ProfileAlongTrack.longitude_name, "Longitude");
335         table.put(ProfileAlongTrack.latitude_name, "Latitude");
336         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
337         ProfileAlongTrack adapter = new Calipso2D(reader, table);
338         ProfileAlongTrack3D adapter3D = new ProfileAlongTrack3D(adapter);
339         Map<String, double[]> subset = adapter.getDefaultSubset();
340         adapters[0] = adapter3D;
341         defaultSubset = subset;
342         defaultSubsets[0] = defaultSubset;
343         DataCategory.createCategory("ProfileAlongTrack");
344         categories = DataCategory.parseCategories("ProfileAlongTrack;ProfileAlongTrack;");
345
346         properties.put("medianFilter", new String[] {Double.toString(8), Double.toString(16)});
347         properties.put("setBelowSfcMissing", new String[] {"true"});
348         propsArray[0] = properties;
349
350         ArrayAdapter[] adapter_s = new ArrayAdapter[3];
351         table = ProfileAlongTrack.getEmptyMetadataTable();
352         table.put(ProfileAlongTrack.array_name, "Latitude");
353         table.put(ProfileAlongTrack.trackDim_name, "dim0");
354         table.put(ProfileAlongTrack.vertDim_name, "dim1");
355         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
356         adapter_s[0] = new ArrayAdapter(reader, table);
357
358         table = ProfileAlongTrack.getEmptyMetadataTable();
359         table.put(ProfileAlongTrack.array_name, "Surface_Elevation");
360         table.put(ProfileAlongTrack.trackDim_name, "dim0");
361         table.put(ProfileAlongTrack.vertDim_name, "dim1");
362         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
363         adapter_s[1] = new ArrayAdapter(reader, table);
364         adapter_s[1].setRangeProcessor(new RangeProcessor() { // Eventually handle unit conversions better.
365              public float[] processRange(float[] fvals, Map<String, double[]> subset) {
366                 for (int i=0; i<fvals.length; i++) {
367                    fvals[i] *= 1000; //km -> m 
368                 }
369                 return fvals;
370              }
371         });
372
373         table = ProfileAlongTrack.getEmptyMetadataTable();
374         table.put(ProfileAlongTrack.array_name, "Longitude");
375         table.put(ProfileAlongTrack.trackDim_name, "dim0");
376         table.put(ProfileAlongTrack.vertDim_name, "dim1");
377         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
378         adapter_s[2] = new ArrayAdapter(reader, table);
379
380         TrackDomain track_domain = new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]);
381         track_adapter = new TrackAdapter(track_domain, adapter_s[1]);
382
383         table = ProfileAlongTrack.getEmptyMetadataTable();
384         table.put(ProfileAlongTrack.array_name, "Tropopause_Height");
385         table.put(ProfileAlongTrack.trackDim_name, "dim0");
386         table.put(ProfileAlongTrack.vertDim_name, "dim1");
387         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
388         ArrayAdapter trop_height = new ArrayAdapter(reader, table);
389         track_domain = new TrackDomain(adapter_s[2], adapter_s[0], trop_height);
390         adapters[1] = new TrackAdapter(track_domain, trop_height);
391         defaultSubsets[1] = adapters[1].getDefaultSubset();
392
393         adapters[2] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]), adapter_s[1]);
394         ((TrackAdapter)adapters[2]).setName("Track3D");
395         defaultSubsets[2] = adapters[2].getDefaultSubset();
396
397         adapters[3] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0]), adapter_s[1]);
398         ((TrackAdapter)adapters[3]).setName("Track2D");
399         defaultSubsets[3] = adapters[3].getDefaultSubset();
400         
401
402         hasTrackPreview = true;
403       }
404       else if (name.startsWith("CAL_LID_L2")) {
405           
406           // Make sure the variables we need are present. If not, this is not a valid
407           // L2 CALIPSO file McV can work with.
408           
409           if (! ((hasVariable("Latitude")) &&
410                          (hasVariable("Longitude")) &&
411                          (hasVariable("DEM_Surface_Elevation")) &&
412                          (hasVariable("Layer_Top_Altitude"))) 
413                  ) {
414                   // Pop up a dialog letting user know we can't work wit this data
415                        String msg = "McIDAS-V is unable to read this Level 2 CALIPSO file.\n" +
416                                        "If you believe this is a valid file which should be supported,\n" +
417                                        "please contact the MUG or post a message on the MUG Forum.";
418                        Object[] params = { msg };
419                        JOptionPane.showMessageDialog(null, params, "Data Validity Test Failure", JOptionPane.OK_OPTION);
420                        throw new Exception("Unable to load CALIPSO data");
421           }
422           
423         adapters = new MultiDimensionAdapter[4];
424         defaultSubsets = new HashMap[4];
425         propsArray = new Hashtable[4];
426
427         ArrayAdapter[] adapter_s = new ArrayAdapter[3];
428
429         adapter_s[0] = createTrackVertArrayAdapter("Longitude");
430         adapter_s[1] = createTrackVertArrayAdapter("Latitude");
431         adapter_s[2] = createTrackVertArrayAdapter("DEM_Surface_Elevation");
432
433         TrackDomain track_domain = new TrackDomain(adapter_s[0], adapter_s[1], adapter_s[2]);
434         track_adapter = new TrackAdapter(track_domain, adapter_s[2]);
435         adapters[1] = track_adapter;
436         defaultSubsets[1] = track_adapter.getDefaultSubset();
437
438         ArrayAdapter layer_top_altitude = createTrackVertArrayAdapter("Layer_Top_Altitude");
439
440         RangeProcessor rngProcessor =
441             new RangeProcessor(1.0f, 0.0f, -Float.MAX_VALUE, Float.MAX_VALUE, -9999.0f);
442         layer_top_altitude.setRangeProcessor(rngProcessor);
443
444         track_domain = new TrackDomain(adapter_s[0], adapter_s[1], layer_top_altitude);
445         adapters[0] = new TrackAdapter(track_domain, layer_top_altitude);
446         defaultSubsets[0] = adapters[0].getDefaultSubset();
447
448         /** another layer, how to show all?
449         adapters[2] = new TrackAdapter(track_domain, layer_top_altitude);
450         ((TrackAdapter)adapters[2]).setListIndex(1);
451         defaultSubsets[2] = adapters[2].getDefaultSubset();
452         */
453
454         adapters[2] = new TrackAdapter(new TrackDomain(adapter_s[0], adapter_s[1]), adapter_s[2]);
455         ((TrackAdapter)adapters[2]).setName("Track2D");
456         defaultSubsets[2] = adapters[2].getDefaultSubset();
457
458         adapters[3] = new TrackAdapter(new TrackDomain(adapter_s[0], adapter_s[1], adapter_s[2]), adapter_s[2]);
459         ((TrackAdapter)adapters[3]).setName("Track3D");
460         defaultSubsets[3] = adapters[3].getDefaultSubset();
461
462         DataCategory.createCategory("ProfileAlongTrack");
463         categories = DataCategory.parseCategories("ProfileAlongTrack;ProfileAlongTrack;");
464
465         hasTrackPreview = true;
466       }
467       else if (name.indexOf("2B-GEOPROF") > 0) {
468         adapters = new MultiDimensionAdapter[4];
469         defaultSubsets = new HashMap[4];
470         propsArray = new Hashtable[4];
471
472         Map<String, Object> table = ProfileAlongTrack.getEmptyMetadataTable();
473         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Data_Fields/Radar_Reflectivity");
474         table.put(ProfileAlongTrack.range_name, "2B-GEOPROF_RadarReflectivity");
475         table.put(ProfileAlongTrack.scale_name, "factor");
476         table.put(ProfileAlongTrack.offset_name, "offset");
477         table.put(ProfileAlongTrack.fill_value_name, "_FillValue");
478         table.put(ProfileAlongTrack.valid_range, "valid_range");
479         table.put(ProfileAlongTrack.ancillary_file_name, "/edu/wisc/ssec/mcidasv/data/hydra/resources/cloudsat/altitude");
480         table.put(ProfileAlongTrack.trackDim_name, "nray");
481         table.put(ProfileAlongTrack.vertDim_name, "nbin");
482         table.put(ProfileAlongTrack.profileTime_name, "2B-GEOPROF/Geolocation_Fields/Profile_Time");
483         table.put(ProfileAlongTrack.longitude_name, "2B-GEOPROF/Geolocation_Fields/Longitude");
484         table.put(ProfileAlongTrack.latitude_name, "2B-GEOPROF/Geolocation_Fields/Latitude");
485         table.put(ProfileAlongTrack.product_name, "2B-GEOPROF");
486         ProfileAlongTrack adapter = new CloudSat2D(reader, table);
487         ProfileAlongTrack3D adapter3D = new ProfileAlongTrack3D(adapter);
488         Map<String, double[]> subset = adapter.getDefaultSubset();
489         adapters[0] = adapter3D;
490         defaultSubset = subset;
491         defaultSubsets[0] = defaultSubset;
492         DataCategory.createCategory("ProfileAlongTrack");
493         categories = DataCategory.parseCategories("ProfileAlongTrack;ProfileAlongTrack;");
494
495         ArrayAdapter[] adapter_s = new ArrayAdapter[3];
496         table = ProfileAlongTrack.getEmptyMetadataTable();
497         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Geolocation_Fields/Latitude");
498         table.put(ProfileAlongTrack.range_name, "Latitude");
499         table.put(ProfileAlongTrack.trackDim_name, "nray");
500         adapter_s[0] = new ArrayAdapter(reader, table);
501
502         table = ProfileAlongTrack.getEmptyMetadataTable();
503         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Geolocation_Fields/DEM_elevation");
504         table.put(ProfileAlongTrack.range_name, "DEM_elevation");
505         table.put(ProfileAlongTrack.trackDim_name, "nray");
506         adapter_s[1] = new ArrayAdapter(reader, table);
507         adapter_s[1].setRangeProcessor(new RangeProcessor() { // need this because we don't want -9999 mapped to NaN
508              public float[] processRange(short[] svals, Map<String, double[]> subset) {
509                  float[] fvals = new float[svals.length];
510                  for (int i=0; i<svals.length; i++) {
511                     short sval = svals[i];
512                     if (sval == -9999) {
513                        fvals[i] = 0f;
514                     }
515                     else {
516                       fvals[i] = sval;
517                     }
518                  }
519                  return fvals;
520               }
521         });
522
523         table = ProfileAlongTrack.getEmptyMetadataTable();
524         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Geolocation_Fields/Longitude");
525         table.put(ProfileAlongTrack.range_name, "Longitude");
526         table.put(ProfileAlongTrack.trackDim_name, "nray");
527         adapter_s[2] = new ArrayAdapter(reader, table);
528
529         TrackDomain track_domain = new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]);
530         track_adapter = new TrackAdapter(track_domain, adapter_s[1]);
531
532         adapters[2] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]), adapter_s[1]);
533         ((TrackAdapter)adapters[2]).setName("Track3D");
534         defaultSubsets[2] = adapters[2].getDefaultSubset();
535
536         adapters[1] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0]), adapter_s[1]);
537         ((TrackAdapter)adapters[1]).setName("Track2D");
538         defaultSubsets[1] = adapters[1].getDefaultSubset();
539
540
541         properties.put("medianFilter", new String[] {Double.toString(6), Double.toString(14)});
542         properties.put("setBelowSfcMissing", new String[] {"true"});
543         propsArray[0] = properties;
544         hasTrackPreview = true;
545       }
546       else if ( name.startsWith("MHSx_xxx_1B") && name.endsWith("h5")) {
547          Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
548          table.put("array_name", "U-MARF/EPS/MHSx_xxx_1B/DATA/Channel1");
549          table.put("lon_array_name", "U-MARF/EPS/IASI_xxx_1C/DATA/IMAGE_LON_ARRAY");
550          table.put("lat_array_name", "U-MARF/EPS/IASI_xxx_1C/DATA/IMAGE_LAT_ARRAY");
551          table.put("XTrack", "dim1");
552          table.put("Track", "dim0");
553          table.put("geo_XTrack", "dim1");
554          table.put("geo_Track", "dim0");
555          table.put("product_name", "MHSx_xxx_1B");
556          SwathAdapter swathAdapter = new SwathAdapter(reader, table);
557          adapters[0] = swathAdapter;
558          Map<String, double[]> subset = swathAdapter.getDefaultSubset();
559          defaultSubset = subset;
560          defaultSubsets[0] = defaultSubset;
561          categories = DataCategory.parseCategories("2D grid;GRID-2D;");
562       }
563       else if ( name.startsWith("MYD02SSH") ) {
564         String[] arrayNames = null;
565
566         if (name.endsWith("level2.hdf")) {
567           arrayNames = new String[] {"cld_press_acha", "cld_temp_acha", "cld_height_acha", "cloud_type",
568                                             "cloud_albedo_0_65um_nom", "cloud_transmission_0_65um_nom", "cloud_fraction"};
569         }
570         else if (name.endsWith("obs.hdf")) {
571           arrayNames = new String[] {"refl_0_65um_nom", "refl_0_86um_nom", "refl_3_75um_nom", "refl_1_60um_nom", "refl_1_38um_nom",
572                                      "temp_3_75um_nom", "temp_11_0um_nom", "temp_12_0um_nom", "temp_6_7um_nom",
573                                      "temp_8_5um_nom", "temp_13_3um_nom"};
574         }
575  
576         adapters = new MultiDimensionAdapter[arrayNames.length];
577         defaultSubsets = new HashMap[arrayNames.length];
578         propsArray = new Hashtable[arrayNames.length]; 
579
580         for (int k=0; k<arrayNames.length; k++) {
581           Map<String, Object> swthTable = SwathAdapter.getEmptyMetadataTable();
582           swthTable.put("array_name", arrayNames[k]);
583           swthTable.put("lon_array_name", "pixel_longitude");
584           swthTable.put("lat_array_name", "pixel_latitude");
585           swthTable.put("XTrack", "pixel_elements_along_scan_direction");
586           swthTable.put("Track", "scan_lines_along_track_direction");
587           swthTable.put("geo_Track", "scan_lines_along_track_direction");
588           swthTable.put("geo_XTrack", "pixel_elements_along_scan_direction");
589           swthTable.put("scale_name", "SCALE_FACTOR");
590           swthTable.put("offset_name", "ADD_OFFSET");
591           swthTable.put("fill_value_name", "_FILLVALUE");
592           swthTable.put("geo_scale_name", "SCALE_FACTOR");
593           swthTable.put("geo_offset_name", "ADD_OFFSET");
594           swthTable.put("geo_fillValue_name", "_FILLVALUE");
595           swthTable.put("range_name", arrayNames[k]);
596           swthTable.put("unpack", "unpack");
597
598           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
599           Map<String, double[]> subset = swathAdapter0.getDefaultSubset();
600           defaultSubset = subset;
601           adapters[k] = swathAdapter0;
602           defaultSubsets[k] = defaultSubset;
603         }
604         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
605         hasImagePreview = true;
606       }
607       else if (name.contains("AWG_OZONE") ) {
608         String[] arrayNames = new String[] {"ColumnOzone"};
609
610         adapters = new MultiDimensionAdapter[arrayNames.length];
611         defaultSubsets = new HashMap[arrayNames.length];
612         propsArray = new Hashtable[arrayNames.length];
613         
614         for (int k=0; k<arrayNames.length; k++) {
615           Map<String, Object> swthTable = SwathAdapter.getEmptyMetadataTable();
616           swthTable.put("array_name", arrayNames[k]);
617           swthTable.put("lon_array_name", "Longitude");
618           swthTable.put("lat_array_name", "Latitude");
619           swthTable.put("XTrack", "Columns");
620           swthTable.put("Track", "Rows");
621           swthTable.put("fill_value_name", "_FillValue");
622           swthTable.put("geo_Track", "Rows");
623           swthTable.put("geo_XTrack", "Columns");
624           swthTable.put("geo_fillValue_name", "_FillValue");
625           swthTable.put("range_name", arrayNames[k]);
626
627           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
628           swathAdapter0.setDefaultStride(5);
629           Map<String, double[]> subset = swathAdapter0.getDefaultSubset();
630           defaultSubset = subset;
631           adapters[k] = swathAdapter0;
632           defaultSubsets[k] = defaultSubset;
633         }
634
635         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
636         hasImagePreview = true;
637       }
638       else if (name.contains("AWG_CLOUD_MASK") ) {
639         String[] arrayNames = new String[] {"CloudMask"};
640
641         adapters = new MultiDimensionAdapter[arrayNames.length];
642         defaultSubsets = new HashMap[arrayNames.length];
643         propsArray = new Hashtable[arrayNames.length];
644
645         for (int k=0; k<arrayNames.length; k++) {
646           Map<String, Object> swthTable = SwathAdapter.getEmptyMetadataTable();
647           swthTable.put("array_name", arrayNames[k]);
648           swthTable.put("lon_array_name", "Longitude");
649           swthTable.put("lat_array_name", "Latitude");
650           swthTable.put("XTrack", "Columns");
651           swthTable.put("Track", "Rows");
652           swthTable.put("fill_value_name", "_FillValue");
653           swthTable.put("geo_Track", "Rows");
654           swthTable.put("geo_XTrack", "Columns");
655           swthTable.put("geo_fillValue_name", "_FillValue");
656           swthTable.put("range_name", arrayNames[k]);
657
658           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
659           swathAdapter0.setDefaultStride(5);
660           Map<String, double[]> subset = swathAdapter0.getDefaultSubset();
661           defaultSubset = subset;
662           adapters[k] = swathAdapter0;
663           defaultSubsets[k] = defaultSubset;
664         }
665
666         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
667         hasImagePreview = true;
668       }
669       else if (name.contains("AWG_CLOUD_HEIGHT")) {
670         String[] arrayNames = new String[] {"CldTopTemp", "CldTopPres", "CldTopHght"};
671
672         adapters = new MultiDimensionAdapter[arrayNames.length];
673         defaultSubsets = new HashMap[arrayNames.length];
674         propsArray = new Hashtable[arrayNames.length];
675
676         for (int k=0; k<arrayNames.length; k++) {
677           Map<String, Object> swthTable = SwathAdapter.getEmptyMetadataTable();
678           swthTable.put("array_name", arrayNames[k]);
679           swthTable.put("lon_array_name", "Longitude");
680           swthTable.put("lat_array_name", "Latitude");
681           swthTable.put("XTrack", "Columns");
682           swthTable.put("Track", "Rows");
683           swthTable.put("scale_name", "scale_factor");
684           swthTable.put("offset_name", "add_offset");
685           swthTable.put("fill_value_name", "_FillValue");
686           swthTable.put("geo_Track", "Rows");
687           swthTable.put("geo_XTrack", "Columns");
688           swthTable.put("geo_scale_name", "scale_factor");
689           swthTable.put("geo_offset_name", "add_offset");
690           swthTable.put("geo_fillValue_name", "_FillValue");
691           swthTable.put("range_name", arrayNames[k]);
692           swthTable.put("unpack", "unpack");
693
694           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
695           swathAdapter0.setDefaultStride(5);
696           Map<String, double[]> subset = swathAdapter0.getDefaultSubset();
697           defaultSubset = subset;
698           adapters[k] = swathAdapter0;
699           defaultSubsets[k] = defaultSubset;
700         }
701         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
702         hasImagePreview = true;
703       }
704       else if (name.startsWith("geocatL2") && name.endsWith("ci.hdf")) {
705         String[] arrayNames = new String[] {"box_average_11um_ctc", "box_average_11um_ctc_scaled", "conv_init", "cloud_type"};
706
707         adapters = new MultiDimensionAdapter[arrayNames.length];
708         defaultSubsets = new HashMap[arrayNames.length];
709         propsArray = new Hashtable[arrayNames.length];
710
711         for (int k=0; k<arrayNames.length; k++) {
712           Map<String, Object> swthTable = SwathAdapter.getEmptyMetadataTable();
713           swthTable.put("array_name", arrayNames[k]);
714           swthTable.put("lon_array_name", "lon");
715           swthTable.put("lat_array_name", "lat");
716           swthTable.put("XTrack", "Elements");
717           swthTable.put("Track", "Lines");
718           swthTable.put("geo_Track", "Lines");
719           swthTable.put("geo_XTrack", "Elements");
720           swthTable.put("range_name", arrayNames[k]);
721
722           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
723           swathAdapter0.setDefaultStride(1);
724           Map<String, double[]> subset = swathAdapter0.getDefaultSubset();
725           defaultSubset = subset;
726           adapters[k] = swathAdapter0;
727           defaultSubsets[k] = defaultSubset;
728         }
729         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
730         hasImagePreview = true;
731       } 
732       else {
733         String[] arrayNames = new String[] {"baseline_cmask_seviri_cloud_mask", "baseline_ctype_seviri_cloud_type",
734                                             "baseline_ctype_seviri_cloud_phase", "baseline_cld_hght_seviri_cloud_top_pressure",
735                                             "baseline_cld_hght_seviri_cloud_top_height"};
736
737         adapters = new MultiDimensionAdapter[arrayNames.length];
738         defaultSubsets = new HashMap[arrayNames.length];
739         propsArray = new Hashtable[arrayNames.length]; 
740
741         for (int k=0; k<arrayNames.length; k++) {
742           Map<String, Object> swthTable = SwathAdapter.getEmptyMetadataTable();
743           swthTable.put("array_name", arrayNames[k]);
744           swthTable.put("lon_array_name", "pixel_longitude");
745           swthTable.put("lat_array_name", "pixel_latitude");
746           swthTable.put("XTrack", "elements");
747           swthTable.put("Track", "lines");
748           swthTable.put("scale_name", "scale_factor");
749           swthTable.put("offset_name", "add_offset");
750           swthTable.put("fill_value_name", "_FillValue");
751           swthTable.put("geo_Track", "lines");
752           swthTable.put("geo_XTrack", "elements");
753           swthTable.put("geo_scale_name", "scale_factor");
754           swthTable.put("geo_offset_name", "add_offset");
755           swthTable.put("geo_fillValue_name", "_FillValue");
756           swthTable.put("range_name", arrayNames[k]);
757           swthTable.put("unpack", "unpack");
758
759           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
760           swathAdapter0.setDefaultStride(2);
761           Map<String, double[]> subset = swathAdapter0.getDefaultSubset();
762           defaultSubset = subset;
763           adapters[k] = swathAdapter0;
764           defaultSubsets[k] = defaultSubset;
765         }
766         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
767         hasImagePreview = true;
768       }
769
770       setProperties(properties);
771    }
772
773    public void initAfterUnpersistence() {
774      try {
775        setup();
776      } catch (Exception e) {
777        logger.error("could not set up after unpersisting", e);
778      }
779    }
780
781    /**
782     * Make and insert the {@link DataChoice DataChoices} for this {@code DataSource}.
783     */
784    public void doMakeDataChoices() {
785        DataChoice choice = null;
786        if (adapters != null) {
787          for (int idx=0; idx<adapters.length; idx++) {
788             try {
789               String arrayName = (adapters[idx] == null) ? "_     " : adapters[idx].getArrayName();
790               choice = doMakeDataChoice(idx, arrayName);
791               adapterMap.put(choice.getName(), adapters[idx]);
792             } catch (Exception e) {
793               logger.error("error making data choices", e);
794             }
795
796             if (choice != null) {
797               addDataChoice(choice);
798             }
799          }
800        }
801    }
802
803    private DataChoice doMakeDataChoice(int idx, String var) throws Exception {
804        String name = var;
805        DataSelection dataSel = (defaultSubsets[idx] == null) ? new MultiDimensionSubset() : new MultiDimensionSubset(defaultSubsets[idx]);
806        Hashtable props = new Hashtable();
807        props.put(new MultiDimensionSubset(), dataSel);
808
809        if (propsArray != null) {
810          if (propsArray[idx] != null) {
811            propsArray[idx].put(new MultiDimensionSubset(), dataSel);
812            props = propsArray[idx];
813          }
814        }
815        DirectDataChoice ddc = null;
816
817        if (categories != null) {
818           ddc = new DirectDataChoice(this, idx, name, name, categories, props);
819        }
820        else {
821           ddc = new DirectDataChoice(this, idx, name, name, categoriesArray[idx], props);
822        }
823
824        return ddc;
825    }
826
827    /**
828     * Check to see if this {@code HDFHydraDataSource} is equal to the object
829     * in question.
830     * @param o  object in question
831     * @return true if they are the same or equivalent objects
832     */
833    public boolean equals(Object o) {
834        if ( !(o instanceof MultiDimensionDataSource)) {
835            return false;
836        }
837        return (this == (MultiDimensionDataSource) o);
838    }
839
840    public MultiSpectralData getMultiSpectralData() {
841      return multiSpectData;
842    }
843
844    public String getDatasetName() {
845      return filename;
846    }
847
848    public void setDatasetName(String name) {
849      filename = name;
850    }
851
852    public Map<String, double[]> getSubsetFromLonLatRect(MultiDimensionSubset select, GeoSelection geoSelection) {
853      GeoLocationInfo ginfo = geoSelection.getBoundingBox();
854      logger.debug("ginfo0: " + ginfo);
855      return adapters[0].getSubsetFromLonLatRect(select.getSubset(), ginfo.getMinLat(), ginfo.getMaxLat(),
856                                        ginfo.getMinLon(), ginfo.getMaxLon());
857    }
858
859    public synchronized Data getData(DataChoice dataChoice, DataCategory category,
860                                DataSelection dataSelection, Hashtable requestProperties)
861                                throws VisADException, RemoteException {
862       return this.getDataInner(dataChoice, category, dataSelection, requestProperties);
863    }
864
865
866    protected Data getDataInner(DataChoice dataChoice, DataCategory category,
867                                DataSelection dataSelection, Hashtable requestProperties)
868                                throws VisADException, RemoteException {
869
870        MultiDimensionAdapter adapter = null;
871        adapter = adapterMap.get(dataChoice.getName());
872
873        Hashtable dataChoiceProps = dataChoice.getProperties();
874
875        //- this hack keeps the HydraImageProbe from doing a getData()
876        //- TODO: need to use categories?
877        if (requestProperties != null) {
878          if ((requestProperties.toString()).equals("{prop.requester=MultiSpectral}")) {
879            return null;
880          }
881        }
882
883        GeoLocationInfo ginfo = null;
884        GeoSelection geoSelection = null;
885        
886        if ((dataSelection != null) && (dataSelection.getGeoSelection() != null)) {
887
888          if (dataSelection.getGeoSelection().getBoundingBox() != null) {
889            geoSelection = dataSelection.getGeoSelection();
890          }
891          else { // no bounding box in the incoming DataSelection. Check the dataChoice.
892            DataSelection datSelFromChoice = dataChoice.getDataSelection();
893            if (datSelFromChoice != null) {
894              geoSelection = datSelFromChoice.getGeoSelection();
895            }
896          }
897        }
898
899        if (geoSelection != null) {
900          ginfo = geoSelection.getBoundingBox();
901        }
902
903        // Still no geo info so check for the lon/lat b.b. in this datasource (last set by DataSelectionComponent)
904        if (ginfo == null) {
905           DataSelection localDataSelection = getDataSelection();
906           if (localDataSelection != null) {
907              geoSelection = localDataSelection.getGeoSelection();
908              if (geoSelection != null) {
909                 ginfo = geoSelection.getBoundingBox();
910              }
911           }
912        }
913
914        Data data = null;
915        if (adapters == null) {
916          return data;
917        }
918
919        Map<String, double[]> subset = null;
920        MultiDimensionSubset select = null;
921
922        Hashtable table = dataChoice.getProperties();
923        Enumeration keys = table.keys();
924        while (keys.hasMoreElements()) {
925           Object key = keys.nextElement();
926           if (key instanceof MultiDimensionSubset) {
927              select = (MultiDimensionSubset) table.get(key);
928           }
929        }
930
931        try {
932            subset = null;
933            if (ginfo != null) {
934                if (trackSelection != null) {
935                        boolean trackStrideOk = trackSelection.setTrackStride();
936                        boolean verticalStrideOk = trackSelection.setVerticalStride();
937                        
938                        if (trackStrideOk && verticalStrideOk) {
939                        subset = adapter.getSubsetFromLonLatRect(ginfo.getMinLat(), ginfo.getMaxLat(),
940                                        ginfo.getMinLon(), ginfo.getMaxLon(),
941                                        trackSelection.trackStride,
942                                        trackSelection.verticalStride,
943                                        geoSelection.getZStride());
944                        } else {
945                                // one of the strides is not an integer, let user know
946                            String msg = "Either the Track or Vertical Stride is invalid.\n" +
947                                         "Stride values must be positive integers.\n";
948                                Object[] params = { msg };
949                                JOptionPane.showMessageDialog(null, params, "Invalid Stride", JOptionPane.OK_OPTION);
950                                return null;
951                        }
952                } else {
953                        subset = adapter.getSubsetFromLonLatRect(ginfo.getMinLat(), ginfo.getMaxLat(),
954                                        ginfo.getMinLon(), ginfo.getMaxLon(),
955                                        geoSelection.getXStride(),
956                                        geoSelection.getYStride(),
957                                        geoSelection.getZStride());
958                }
959              if (subset == null && select != null) {
960                subset = select.getSubset();
961              }
962            }
963            else { // no IDV incoming spatial selection info, so check for HYDRA specific via Properties
964              if (select != null) {
965                subset = select.getSubset();
966              }
967              
968              if (dataSelection != null) {
969                Hashtable props = dataSelection.getProperties();
970              }
971            }
972            
973            if (subset != null) {
974              data = adapter.getData(subset);
975              data = applyProperties(data, dataChoiceProps, subset);
976            }
977        } catch (Exception e) {
978            logger.error("getData exception", e);
979        }
980
981        return data;
982    }
983
984    protected Data applyProperties(Data data, Hashtable requestProperties, Map<String, double[]> subset)
985          throws VisADException, RemoteException, Exception {
986      Data new_data = data;
987
988      if (requestProperties == null) {
989        new_data = data;
990        return new_data;
991      }
992
993      if (requestProperties.containsKey("medianFilter")) {
994        String[] items = (String[]) requestProperties.get("medianFilter");
995        double window_lenx = Double.parseDouble(items[0]);
996        double window_leny = Double.parseDouble(items[1]);
997        GriddedSet domainSet = (GriddedSet) ((FlatField)data).getDomainSet();
998        int[] lens = domainSet.getLengths();
999        float[] range_values = (((FlatField)data).getFloats())[0];
1000        range_values =
1001           ProfileAlongTrack.medianFilter(range_values, lens[0], lens[1],
1002                               (int)window_lenx, (int)window_leny);
1003        ((FlatField)new_data).setSamples(new float[][] {range_values});
1004      }
1005      if (requestProperties.containsKey("setBelowSfcMissing")) {
1006        FlatField track = (FlatField) track_adapter.getData(subset);
1007        float[] sfcElev = (track.getFloats())[0];
1008        FlatField field = (FlatField) new_data;
1009        GriddedSet gset = (GriddedSet) field.getDomainSet();
1010        float[][] samples = gset.getSamples(false);
1011        int[] lens = gset.getLengths();
1012        float[] range_values = (field.getFloats())[0];
1013
1014        int trkIdx = ((ProfileAlongTrack3D)adapters[0]).adapter2D.getTrackTupIdx();
1015        int vrtIdx = ((ProfileAlongTrack3D)adapters[0]).adapter2D.getVertTupIdx();
1016
1017        int k = 0;
1018        for (int j=0; j<lens[trkIdx]; j++) {
1019          float val = sfcElev[j];
1020          for (int i=0; i<lens[vrtIdx]; i++) {
1021            if (vrtIdx < trkIdx) k = i + j*lens[0];
1022            if (trkIdx < vrtIdx) k = j + i*lens[0];
1023            if (samples[2][k] <= val || samples[2][k] < 0.0) {
1024              range_values[k] = Float.NaN;
1025            }
1026          }
1027        }
1028        field.setSamples(new float[][] {range_values});
1029      }
1030      return new_data;
1031    }
1032
1033    protected void initDataSelectionComponents(
1034         List<DataSelectionComponent> components,
1035             final DataChoice dataChoice) {
1036
1037      if (hasImagePreview) {
1038        try {
1039          FlatField image = (FlatField) getDataInner(dataChoice, null, null, null);
1040          components.add(new PreviewSelection(dataChoice, image, null));
1041          //components.add(new edu.wisc.ssec.mcidasv.data.PreviewSelectionNew(dataChoice, image));
1042        } catch (Exception e) {
1043          logger.error("cannot make preview selection", e);
1044        }
1045      }
1046      if (hasTrackPreview) {
1047        try {
1048          FlatField track = track_adapter.getData(track_adapter.getDefaultSubset());     
1049          trackSelection = new TrackSelection(dataChoice, track, this);
1050          components.add(trackSelection);
1051        } catch (Exception e) {
1052          logger.error("cannot make preview selection", e);
1053        }
1054      }
1055    }
1056
1057    private String getTrackDimensionName(String variableName) {
1058        return getVariableDimensionName(variableName, 0);
1059    }
1060
1061    private String getVerticalDimensionName(String variableName) {
1062        return getVariableDimensionName(variableName, 1);
1063    }
1064
1065    private String getVariableDimensionName(String variableName, int dimension) {
1066        NetcdfFile ncfile = ((NetCDFFile)reader).getNetCDFFile();
1067        Variable v = ncfile.findVariable(variableName);
1068        String name = null;
1069        if (v != null) {
1070            name = v.getDimension(dimension).getFullName();
1071        }
1072        return name;
1073    }
1074
1075    private boolean hasVariable(String variableName) {
1076        NetcdfFile ncfile = ((NetCDFFile) reader).getNetCDFFile();
1077        return ncfile.findVariable(variableName) != null;
1078    }
1079
1080    private ArrayAdapter createTrackVertArrayAdapter(String variableName) {
1081        Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
1082
1083        String trackDimName = getTrackDimensionName(variableName);
1084        String vertDimName = getVerticalDimensionName(variableName);
1085
1086        table.put(ProfileAlongTrack.array_name, variableName);
1087        table.put(ProfileAlongTrack.trackDim_name, trackDimName);
1088        table.put(ProfileAlongTrack.vertDim_name, vertDimName);
1089        table.put("array_dimension_names", new String[] { trackDimName, vertDimName });
1090
1091        return new ArrayAdapter(reader, table);
1092    }
1093}