001/*
002 * $Id: SpectrumAdapter.java,v 1.18 2011/03/24 16:06:33 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
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
031package edu.wisc.ssec.mcidasv.data.hydra;
032
033import java.util.ArrayList;
034import java.util.HashMap;
035
036import visad.FunctionType;
037import visad.Gridded1DSet;
038import visad.QuickSort;
039import visad.RealTupleType;
040import visad.RealType;
041import visad.SampledSet;
042import visad.Set;
043import visad.SingletonSet;
044
045public 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.processAlongBandDim(range);
248  }
249
250  public float[] processRange(byte[] range, Object subset) {
251     return rangeProcessor.processAlongBandDim(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}