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.rmi.RemoteException;
032import java.util.ArrayList;
033import java.util.HashMap;
034import java.util.Map;
035
036import visad.FlatField;
037import visad.FunctionType;
038import visad.Gridded1DSet;
039import visad.QuickSort;
040import visad.RealTuple;
041import visad.RealTupleType;
042import visad.SampledSet;
043import visad.VisADException;
044
045public class MultiSpectralAggr extends MultiSpectralData {
046
047  Gridded1DSet aggrDomain = null;
048
049  MultiSpectralData[] adapters = null;
050
051  int[] sort_indexes = null;
052
053  float[] aggrValues = null;
054
055  float[] aggrSamples = null;
056
057  int numAdapters;
058
059  int numBands;
060
061  int[] offset;
062
063  public MultiSpectralAggr(MultiSpectralData[] adapters)
064         throws Exception {
065    super(adapters[0].swathAdapter, null);
066    this.adapters = adapters;
067    paramName = adapters[0].getParameter();
068
069    numAdapters = adapters.length;
070    int[] numBandsAdapter = new int[numAdapters];
071    offset = new int[numAdapters];
072    SampledSet[] spectrumDomains = new SampledSet[numAdapters];
073
074    if (adapters[0].spectrumAdapter.hasBandNames()) {
075      hasBandNames = true;
076      bandNameList = new ArrayList<>();
077      bandNameMap = new HashMap<>();
078      for (int k=0; k<numAdapters; k++) {
079        bandNameList.addAll(adapters[k].spectrumAdapter.getBandNames());
080        bandNameMap.putAll(adapters[k].spectrumAdapter.getBandNameMap());
081      }
082    }
083
084    numBands = 0;
085    for (int k=0; k<numAdapters; k++) {
086      SampledSet set = adapters[k].spectrumAdapter.getDomainSet();
087      spectrumDomains[k] = set;
088      numBandsAdapter[k] = set.getLength();
089      offset[k] = numBands;
090      numBands += numBandsAdapter[k];
091    }
092   
093    aggrSamples = new float[numBands];
094    aggrValues  = new float[numBands];
095
096    for (int k=0; k<numAdapters; k++) {
097      float[][] samples = spectrumDomains[k].getSamples(false);
098      System.arraycopy(samples[0], 0, aggrSamples, offset[k], samples[0].length);
099    }
100
101    sort_indexes = QuickSort.sort(aggrSamples);
102    SpectrumAdapter specAdapt = adapters[0].spectrumAdapter;
103    aggrDomain = new Gridded1DSet(specAdapt.getDomainSet().getType(), 
104                        new float[][] {aggrSamples}, aggrSamples.length); 
105
106    init_wavenumber = getWavenumberFromChannelIndex(0);
107  }
108
109  public FlatField getSpectrum(int[] coords) throws Exception {
110    FlatField spectrum = null;
111    for (int k=0; k<numAdapters; k++) {
112      spectrum = adapters[k].getSpectrum(coords);
113      if (spectrum == null) {
114        return null;
115      }
116      float[][] values = spectrum.getFloats(false);
117      System.arraycopy(values[0], 0, aggrValues, offset[k], values[0].length);
118    }
119
120    for (int t=0; t<numBands; t++) {
121      aggrValues[t] = aggrValues[sort_indexes[t]];
122    }
123
124    spectrum = new FlatField((FunctionType)spectrum.getType(), aggrDomain);
125    spectrum.setSamples(new float[][] {aggrValues});
126
127    return spectrum;
128  }
129
130  public FlatField getSpectrum(RealTuple location) throws Exception {
131    FlatField spectrum = null;
132    for (int k=0; k<numAdapters; k++) {
133      spectrum = adapters[k].getSpectrum(location);
134      if (spectrum == null) {
135        return null;
136      }
137      float[][] values = spectrum.getFloats(false);
138      System.arraycopy(values[0], 0, aggrValues, offset[k], values[0].length);
139    }
140
141    for (int t=0; t<numBands; t++) {
142      aggrValues[t] = aggrValues[sort_indexes[t]];
143    }
144
145    spectrum = new FlatField((FunctionType)spectrum.getType(), aggrDomain);
146    spectrum.setSamples(new float[][] {aggrValues});
147
148    return spectrum;
149  }
150
151  public FlatField getImage(Map<String, double[]> subset) throws Exception {
152    int channelIndex = (int) ((double[])subset.get(SpectrumAdapter.channelIndex_name))[0];
153    
154    int idx = sort_indexes[channelIndex];
155    
156    int swathAdapterIndex = numAdapters-1;
157    for (int k=0; k<numAdapters-1;k++) {
158      if (idx >= offset[k] && idx < offset[k+1]) swathAdapterIndex = k;
159    }
160    float channel = aggrSamples[channelIndex];
161    FlatField image = adapters[swathAdapterIndex].getImage(channel, subset);
162    cs = ((RealTupleType) ((FunctionType)image.getType()).getDomain()).getCoordinateSystem();
163    for (int k=0; k<numAdapters;k++) {
164      if (k != swathAdapterIndex) adapters[k].setCoordinateSystem(cs);
165    }
166    return image;
167  }
168
169  public FlatField getImage(float channel, Map<String, double[]> subset) throws Exception {
170    int channelIndex = aggrDomain.valueToIndex(new float[][] {{channel}})[0];
171
172    int idx = sort_indexes[channelIndex];
173
174    int swathAdapterIndex = numAdapters-1;
175    for (int k=0; k<numAdapters-1;k++) {
176      if (idx >= offset[k] && idx < offset[k+1]) swathAdapterIndex = k;
177    }
178    channel = aggrSamples[channelIndex];
179    FlatField image = adapters[swathAdapterIndex].getImage(channel, subset);
180    cs = ((RealTupleType) ((FunctionType)image.getType()).getDomain()).getCoordinateSystem();
181    for (int k=0; k<numAdapters;k++) {
182      if (k != swathAdapterIndex) adapters[k].setCoordinateSystem(cs);
183    }
184    return image;
185  }
186
187  public int getChannelIndexFromWavenumber(float channel) throws VisADException, RemoteException {
188    int idx = (aggrDomain.valueToIndex(new float[][] {{channel}}))[0];
189    return idx;
190  }
191
192  public float getWavenumberFromChannelIndex(int index) throws Exception {
193    return (aggrDomain.indexToValue(new int[] {index}))[0][0];
194  }
195
196  public Map<String, double[]> getDefaultSubset() {
197    Map<String, double[]> subset = adapters[0].getDefaultSubset();
198    double chanIdx = 0;
199    try {
200      chanIdx = getChannelIndexFromWavenumber(init_wavenumber);
201    }
202    catch (Exception e) {
203      System.out.println("couldn't get chanIdx, using zero");
204    }
205    subset.put(SpectrumAdapter.channelIndex_name, new double[] {chanIdx, chanIdx, 1});
206    return subset;
207  }
208
209}