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