001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2015
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
029package edu.wisc.ssec.mcidasv.data.hydra;
030
031import java.util.ArrayList;
032import java.util.HashMap;
033
034import visad.FunctionType;
035import visad.Gridded1DSet;
036import visad.QuickSort;
037import visad.RealTupleType;
038import visad.RealType;
039import visad.SampledSet;
040import visad.Set;
041import visad.SingletonSet;
042
043public 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}