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 */
028
029package edu.wisc.ssec.mcidasv.data.hydra;
030
031import java.util.ArrayList;
032import java.util.HashMap;
033import java.util.List;
034import java.util.Map;
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 Map<String, Object> getEmptyMetadataTable() {
064    Map<String, Object> metadata = new HashMap<>();
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 Map<String, double[]> getEmptySubset() {
088    Map<String, double[]> subset = new HashMap<>();
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  List<String> bandNameList = new ArrayList<>();
104  String[] bandNameArray = null;
105  Map<String, Float> bandNameMap = null;
106  boolean hasBandNames = false;
107
108  public SpectrumAdapter(MultiDimensionReader reader, Map<String, Object> 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 List<String> getBandNames() {
151    return bandNameList;
152  }
153
154  public Map<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(Map<String, double[]> 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<>();
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  public Map<String, double[]> getDefaultSubset() {
238    Map<String, double[]> subset = SpectrumAdapter.getEmptySubset();
239    
240    double[] coords = (double[])subset.get(y_dim_name);
241    coords[0] = 1.0;
242    coords[1] = 1.0;
243    coords[2] = 1.0;
244    subset.put(y_dim_name, coords);
245                                                                                                                                     
246    coords = (double[])subset.get(x_dim_name);
247    coords[0] = 1.0;
248    coords[1] = 1.0;
249    coords[2] = 1.0;
250    subset.put(x_dim_name, coords);
251
252    coords = (double[])subset.get(channelIndex_name);
253    coords[0] = 0.0;
254    coords[1] = (double) (numChannels - 1);
255    coords[2] = 1.0;
256    subset.put(channelIndex_name, coords);
257
258    return subset;
259  }
260
261  public int getChannelIndexFromWavenumber(float wavenumber) throws Exception {
262    int idx = (domainSet.valueToIndex(new float[][] {{wavenumber}}))[0];
263    return channel_sort[idx];
264  }
265
266  public float getWavenumberFromChannelIndex(int index) throws Exception {
267    int idx = channel_sort[index];
268    return (domainSet.indexToValue(new int[] {idx}))[0][0];
269  }
270
271  public int getNumChannels() {
272    return numChannels;
273  }
274}