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 java.util.ArrayList;
032    import java.util.HashMap;
033    
034    import visad.FunctionType;
035    import visad.Gridded1DSet;
036    import visad.QuickSort;
037    import visad.RealTupleType;
038    import visad.RealType;
039    import visad.SampledSet;
040    import visad.Set;
041    import visad.SingletonSet;
042    
043    public class SpectrumAdapter extends MultiDimensionAdapter {
044    
045      public static String channels_name = "Channels";
046      public static String channelIndex_name = "channelIndex";
047      public static String FOVindex_name = "FOVindex";
048      public static String channelUnit = "cm";
049      public static String channelType = "wavenumber";
050      public static String array_name  = "array_name";
051      public static String array_dimension_names = "array_dimension_names";
052      public static String range_name = "range_name";
053      public static String x_dim_name  = "x_dim"; //- 2 spatial dimensions, x fastest varying
054      public static String y_dim_name  = "y_dim"; //-----------------------------------------
055      public static String time_dim_name = "time_dim";
056      public static String ancillary_file_name = "ancillary_file";
057      public static String channelValues = "channelValues";
058      public static String bandNames = "bandNames";
059    
060    
061      public static HashMap getEmptyMetadataTable() {
062        HashMap<String, String> metadata = new HashMap<String, String>();
063        metadata.put(array_name, null);
064        metadata.put(range_name, null);
065        metadata.put(channelIndex_name, null);
066        metadata.put(ancillary_file_name, null);
067        metadata.put(x_dim_name, null);
068        metadata.put(y_dim_name, null);
069        metadata.put(time_dim_name, null);
070        metadata.put(channelUnit, null);
071        metadata.put(channelType, "wavenumber");
072        metadata.put(channelValues, null);
073        metadata.put(bandNames, null);
074    
075        /*
076        metadata.put(scale_name, null);
077        metadata.put(offset_name, null);
078        metadata.put(fill_value_name, null);
079        metadata.put(range_unit, null);
080        metadata.put(valid_range, null);
081        */
082        return metadata;
083      }
084    
085      public static HashMap<String, double[]> getEmptySubset() {
086        HashMap<String, double[]> subset = new HashMap<String, double[]>();
087        subset.put(x_dim_name, new double[3]);
088        subset.put(y_dim_name, new double[3]);
089        subset.put(channelIndex_name, new double[3]);
090        return subset;
091      }
092    
093      int numChannels;
094      int channelIndex = -1;
095      int[] channel_sort;
096      SampledSet domainSet;
097      RealType channelRealType;
098      RealType spectrumRangeType;
099      FunctionType spectrumType;
100    
101      ArrayList<String> bandNameList = new ArrayList<String>();
102      String[] bandNameArray = null;
103      HashMap<String, Float> bandNameMap = null;
104      boolean hasBandNames = false;
105    
106      public SpectrumAdapter(MultiDimensionReader reader, HashMap metadata) {
107        super(reader, metadata);
108        this.init();
109      }
110    
111      private void init() {
112        for (int k=0; k<array_rank;k++) {
113          String name = (String) metadata.get(channelIndex_name);
114          if (name != null) {
115            if ( name.equals(array_dim_names[k]) ) {
116              channelIndex = k;
117            }
118          }
119        }
120    
121        numChannels = computeNumChannels();
122    
123        String[] names = (String[]) metadata.get(bandNames);
124        if (names != null) {
125          hasBandNames = true;
126          bandNameArray = new String[names.length];
127          for (int k=0; k<names.length;k++) {
128            bandNameList.add(names[k]);
129            bandNameArray[k] = names[k];
130          }
131        }
132    
133        try {
134          domainSet = makeDomainSet();
135          rangeType = makeSpectrumRangeType();
136          spectrumType = new FunctionType(channelRealType, spectrumRangeType);
137        } catch (Exception e) {
138          e.printStackTrace();
139          System.out.println("cannot create spectrum domain");
140        }
141      
142      }
143    
144      public boolean hasBandNames() {
145         return hasBandNames;
146      }
147    
148      public ArrayList<String> getBandNames() {
149        return bandNameList;
150      }
151    
152      public HashMap<String, Float> getBandNameMap() {
153        return bandNameMap;
154      }
155    
156      public int computeNumChannels() {
157        if (channelIndex == -1) {
158          return 1;
159        } 
160        else {
161          return array_dim_lengths[channelIndex];
162        }
163      }
164    
165      public Set makeDomain(Object subset) throws Exception {
166        return domainSet;
167      }
168    
169      public SampledSet getDomainSet() throws Exception {
170        return domainSet;
171      }
172    
173      private SampledSet makeDomainSet() throws Exception {
174        RealType domainType = makeSpectrumDomainType();
175        float[] channels = getChannels();
176        channel_sort = QuickSort.sort(channels);
177        if (numChannels == 1) {
178          domainSet = new SingletonSet(new RealTupleType(domainType), new double[] {(double)channels[0]}, null, null, null);
179        }
180        else {
181          domainSet = new Gridded1DSet(domainType, new float[][] {channels}, numChannels);
182        }
183        return domainSet;
184      }
185    
186      public float[] getChannels() throws Exception {
187        float[] channels = null;
188        if (metadata.get(channelValues) == null) {
189          channels = reader.getFloatArray((String)metadata.get(channels_name),
190                                                new int[] {0}, new int[] {numChannels}, new int[] {1});
191        } 
192        else {
193          channels = (float[]) metadata.get(channelValues);
194        }
195    
196        if (hasBandNames) {
197          bandNameMap = new HashMap<String, Float>();
198          for (int k=0; k<numChannels; k++) {
199            bandNameMap.put(bandNameArray[k], new Float(channels[k]));
200          }
201        }
202        return channels;
203      }
204    
205      public RealType makeSpectrumDomainType() throws Exception {
206        /**
207        if ( ((String)metadata.get(channelType)).equals("wavenumber") ) {
208          ScaledUnit centimeter = new ScaledUnit(0.01, CommonUnit.meter, "cm");
209          Unit tmp_unit = centimeter.pow(-1);
210          ScaledUnit inv_centimeter = new ScaledUnit(1.0, tmp_unit, "cm^-1");
211          channelRealType = RealType.getRealType("wavenumber", null);
212        }
213        **/
214        channelRealType = RealType.getRealType((String)metadata.get(channelType), null);
215        return channelRealType;
216      }
217    
218      public RealType makeSpectrumRangeType() throws Exception {
219        spectrumRangeType = RealType.getRealType("Radiance");
220        return spectrumRangeType;
221      }
222    
223      float[] sortRange(float[] range) {
224        float[] sorted_range = new float[numChannels];
225        for (int k=0; k<numChannels; k++) sorted_range[k] = range[channel_sort[k]];
226        return sorted_range;
227      }
228    
229      double[] sortRange(double[] range) {
230        double[] sorted_range =  new double[numChannels];
231        for (int k=0; k<numChannels; k++) sorted_range[k] = range[channel_sort[k]];
232        return sorted_range;
233      }
234    
235    
236      public float[] processRange(float[] range, Object subset) {
237        return range;
238      }
239    
240      public double[] processRange(double[] range, Object subset) {
241        return range;
242      }
243    
244      public float[] processRange(short[] range, Object subset) {
245         return rangeProcessor.processAlongMultiScaleDim(range);
246      }
247    
248      public float[] processRange(byte[] range, Object subset) {
249         return rangeProcessor.processAlongMultiScaleDim(range);
250      }
251    
252      public HashMap getDefaultSubset() {
253        HashMap<String, double[]> subset = SpectrumAdapter.getEmptySubset();
254        
255        double[] coords = (double[])subset.get(y_dim_name);
256        coords[0] = 1.0;
257        coords[1] = 1.0;
258        coords[2] = 1.0;
259        subset.put(y_dim_name, coords);
260                                                                                                                                         
261        coords = (double[])subset.get(x_dim_name);
262        coords[0] = 1.0;
263        coords[1] = 1.0;
264        coords[2] = 1.0;
265        subset.put(x_dim_name, coords);
266    
267        coords = (double[])subset.get(channelIndex_name);
268        coords[0] = 0.0;
269        coords[1] = (double) (numChannels - 1);
270        coords[2] = 1.0;
271        subset.put(channelIndex_name, coords);
272    
273        return subset;
274      }
275    
276      public int getChannelIndexFromWavenumber(float wavenumber) throws Exception {
277        int idx = (domainSet.valueToIndex(new float[][] {{wavenumber}}))[0];
278        return channel_sort[idx];
279      }
280    
281      public float getWavenumberFromChannelIndex(int index) throws Exception {
282        int idx = channel_sort[index];
283        return (domainSet.indexToValue(new int[] {idx}))[0][0];
284      }
285    
286      public int getNumChannels() {
287        return numChannels;
288      }
289    }