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