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.awt.geom.Rectangle2D;
032import java.rmi.RemoteException;
033import java.util.ArrayList;
034import java.util.HashMap;
035import java.util.Iterator;
036import java.util.List;
037import java.util.Map;
038import java.util.Objects;
039
040import visad.CoordinateSystem;
041import visad.FlatField;
042import visad.FunctionType;
043import visad.Gridded2DSet;
044import visad.Linear1DSet;
045import visad.Linear2DSet;
046import visad.Real;
047import visad.RealTuple;
048import visad.RealTupleType;
049import visad.RealType;
050import visad.SampledSet;
051import visad.Set;
052import visad.SetType;
053import visad.VisADException;
054
055public class MultiSpectralData extends MultiDimensionAdapter {
056
057  SwathAdapter swathAdapter = null;
058  SpectrumAdapter spectrumAdapter = null;
059  CoordinateSystem cs = null;
060
061  Map<String, double[]> spectrumSelect = null;
062  Map swathSelect = null;
063
064  String sensorName = null;
065  String platformName = null;
066  String paramName = null;
067  String inputParamName = null;
068  String name = null;
069
070  public float init_wavenumber = 919.50f;
071  public String init_bandName = null;
072
073  float[] dataRange = new float[] {180f, 320f};
074
075  boolean hasBandNames = false;
076  List<String> bandNameList = null;
077  Map<String, Float> bandNameMap = null;
078
079  
080  public MultiSpectralData(SwathAdapter swathAdapter, SpectrumAdapter spectrumAdapter,
081                           String inputParamName, String paramName, String sensorName, String platformName) {
082    this.swathAdapter = swathAdapter;
083    this.spectrumAdapter = spectrumAdapter;
084    this.paramName = paramName;
085    this.inputParamName = inputParamName;
086    this.name = swathAdapter.getArrayName();
087
088    if (spectrumAdapter != null) {
089      this.spectrumSelect = spectrumAdapter.getDefaultSubset();
090      if (spectrumAdapter.hasBandNames()) {
091        hasBandNames = true;
092        bandNameList = spectrumAdapter.getBandNames();
093        bandNameMap = spectrumAdapter.getBandNameMap();
094      }
095      try {
096        setInitialWavenumber(getWavenumberFromChannelIndex(0));
097      } 
098      catch (Exception e) {
099        e.printStackTrace();
100        System.out.println("could not initialize initial wavenumber");
101      }
102    }
103
104    setSpectrumAdapterProcessor();
105
106    this.sensorName = sensorName;
107    this.platformName = platformName;
108  }
109
110  public MultiSpectralData(SwathAdapter swathAdapter, SpectrumAdapter spectrumAdapter,
111                           String sensorName, String platformName) {
112    this(swathAdapter, spectrumAdapter, "Radiance", "BrightnessTemp", sensorName, platformName);
113  }
114
115  public MultiSpectralData(SwathAdapter swathAdapter, SpectrumAdapter spectrumAdapter) {
116    this(swathAdapter, spectrumAdapter, null, null);
117  }
118
119  public MultiSpectralData() {
120    this(null, null, null, null);
121  }
122
123  void setSpectrumAdapterProcessor() {
124     if (swathAdapter != null) {
125        if (spectrumAdapter != null) {
126          spectrumAdapter.setRangeProcessor(swathAdapter.getRangeProcessor());
127        }
128     }
129  }
130
131  public FlatField getSpectrum(int[] coords) 
132      throws Exception, VisADException, RemoteException {
133    if (coords == null) return null;
134    if (spectrumAdapter == null) return null;
135    spectrumSelect.put(SpectrumAdapter.x_dim_name, new double[] {(double)coords[0], (double)coords[0], 1.0});
136    spectrumSelect.put(SpectrumAdapter.y_dim_name, new double[] {(double)coords[1], (double)coords[1], 1.0});
137
138    FlatField spectrum = spectrumAdapter.getData(spectrumSelect);
139    return convertSpectrum(spectrum, paramName);
140  }
141
142  public FlatField getSpectrum(RealTuple location) 
143      throws Exception, VisADException, RemoteException {
144    if (spectrumAdapter == null) return null;
145    int[] coords = getSwathCoordinates(location, cs);
146    if (coords == null) return null;
147    spectrumSelect.put(SpectrumAdapter.x_dim_name, new double[] {(double)coords[0], (double)coords[0], 1.0});
148    spectrumSelect.put(SpectrumAdapter.y_dim_name, new double[] {(double)coords[1], (double)coords[1], 1.0});
149
150    FlatField spectrum = spectrumAdapter.getData(spectrumSelect);
151    return convertSpectrum(spectrum, paramName);
152  }
153
154  public FlatField getImage(Map<String, double[]> subset)
155    throws Exception, VisADException, RemoteException {
156    FlatField image = swathAdapter.getData(subset);
157    cs = ((RealTupleType) ((FunctionType)image.getType()).getDomain()).getCoordinateSystem();
158
159    int channelIndex = (int) ((double[])subset.get(SpectrumAdapter.channelIndex_name))[0];
160    float channel = spectrumAdapter.getWavenumberFromChannelIndex(channelIndex);
161
162    return convertImage(image, channel, paramName);
163  }
164
165  public FlatField getImage(float channel, Map<String, double[]> subset)
166      throws Exception, VisADException, RemoteException {
167    if (spectrumAdapter == null) return getImage(subset);
168    int channelIndex = spectrumAdapter.getChannelIndexFromWavenumber(channel);
169    subset.put(SpectrumAdapter.channelIndex_name, new double[] {(double)channelIndex, (double)channelIndex, 1.0});
170    FlatField image = swathAdapter.getData(subset);
171    cs = ((RealTupleType) ((FunctionType)image.getType()).getDomain()).getCoordinateSystem();
172
173    return convertImage(image, channel, paramName);
174  }
175
176  public FlatField getData(Map<String, double[]> subset) throws Exception {
177    return getImage(subset);
178  }
179
180  public Set makeDomain(Map<String, double[]> subset) throws Exception {
181    throw new Exception("makeDomain unimplented");
182  } 
183
184
185  FlatField convertImage(FlatField image, float channel, String param) 
186            throws Exception {
187    FlatField new_image = null;
188    FunctionType f_type = (FunctionType)image.getType();
189    if (param.equals("BrightnessTemp")) { //- convert radiance to BrightnessTemp
190      FunctionType new_type = new FunctionType(f_type.getDomain(), RealType.getRealType("BrightnessTemp"));
191      new_image = new FlatField(new_type, image.getDomainSet());
192      float[][] values = image.getFloats(false);
193      float[] bt_values = values[0];
194      if (Objects.equals(inputParamName, "Radiance")) {
195        bt_values = radianceToBrightnessTemp(values[0], channel, platformName, sensorName);
196      }
197      new_image.setSamples(new float[][] {bt_values}, false);
198    }
199    else if (param.equals("Reflectance")) {
200      FunctionType new_type = new FunctionType(f_type.getDomain(), RealType.getRealType("Reflectance"));
201      new_image = new FlatField(new_type, image.getDomainSet());
202      new_image.setSamples(image.getFloats(false), false);
203    }
204    else {
205      new_image = image;
206    }
207    return new_image;
208  }
209
210
211  FlatField convertSpectrum(FlatField spectrum, String param) throws Exception {
212    FlatField new_spectrum = null;
213    FunctionType f_type = (FunctionType) spectrum.getType();
214
215    if (param.equals("BrightnessTemp")) {
216      FunctionType new_type = new FunctionType(f_type.getDomain(), RealType.getRealType("BrightnessTemp"));
217      float[][] channels = ((SampledSet)spectrum.getDomainSet()).getSamples(false);
218      float[][] values = spectrum.getFloats(false);
219      float[] bt_values = values[0];
220      if (Objects.equals(inputParamName, "Radiance")) {
221        bt_values = radianceToBrightnessTempSpectrum(values[0], channels[0], platformName, sensorName);
222      }
223      new_spectrum = new FlatField(new_type, spectrum.getDomainSet());
224      new_spectrum.setSamples(new float[][] {bt_values}, true);
225    }
226    else if (param.equals("Reflectance")) {
227      FunctionType new_type = new FunctionType(f_type.getDomain(), RealType.getRealType("Reflectance"));
228      new_spectrum = new FlatField(new_type, spectrum.getDomainSet());
229      new_spectrum.setSamples(spectrum.getFloats(false), false);
230    }
231    else {
232      new_spectrum = spectrum;
233    }
234    return new_spectrum;
235  }
236
237  protected void setDataRange(float[] range) {
238    dataRange = range;
239  }
240
241  public float[] getDataRange() {
242    return dataRange;
243  }
244
245  public String getParameter() {
246    return paramName;
247  }
248
249  /**
250   * @return the paramName
251   */
252  public String getParamName() {
253          return paramName;
254  }
255
256  /**
257   * @param paramName the paramName to set
258   */
259  public void setParamName(String paramName) {
260          this.paramName = paramName;
261  }
262
263  public String getName() {
264          return name;
265  }
266
267  public CoordinateSystem getCoordinateSystem() {
268    return cs;
269  }
270
271  public void setCoordinateSystem(CoordinateSystem cs) {
272    this.cs = cs;
273  }
274
275  public boolean hasBandNames() {
276    return hasBandNames;
277  }
278
279  public List<String> getBandNames() {
280    return bandNameList;
281  }
282
283  public Map<String, Float> getBandNameMap() {
284    return bandNameMap;
285  }
286
287  public String getBandNameFromWaveNumber(float channel) {
288    String bandName = null;
289    Iterator iter = bandNameMap.keySet().iterator();
290    while (iter.hasNext()) {
291       String key = (String) iter.next();
292       float mapVal = ((Float)bandNameMap.get(key)).floatValue();
293       if (channel == mapVal) {
294         bandName = key;
295         break;
296       }
297    }
298    return bandName;
299  }
300
301  public void setInitialWavenumber(float val) {
302    init_wavenumber = val;
303    if (hasBandNames) {
304      init_bandName = getBandNameFromWaveNumber(init_wavenumber);
305    }
306  }
307
308  public int[] getSwathCoordinates(RealTuple location, CoordinateSystem cs) 
309      throws VisADException, RemoteException {
310    if (location == null) return null;
311    if (cs == null) return null;
312    Real[] comps = location.getRealComponents();
313    //- trusted: latitude:0, longitude:1
314    float lon = (float) comps[1].getValue();
315    float lat = (float) comps[0].getValue();
316    if (lon < -180) lon += 360f;
317    if (lon > 180) lon -= 360f;
318    float[][] xy = cs.fromReference(new float[][] {{lon}, {lat}});
319    if ((Float.isNaN(xy[0][0])) || Float.isNaN(xy[1][0])) return null;
320    Set domain = swathAdapter.getSwathDomain();
321    int[] idx = domain.valueToIndex(xy);
322    xy = domain.indexToValue(idx);
323    int[] coords = new int[2];
324    coords[0] = (int) xy[0][0];
325    coords[1] = (int) xy[1][0];
326    if ((coords[0] < 0)||(coords[1] < 0)) return null;
327    return coords;
328  }
329
330  public RealTuple getEarthCoordinates(float[] xy)
331      throws VisADException, RemoteException {
332    float[][] tup = cs.toReference(new float[][] {{xy[0]}, {xy[1]}});
333    return new RealTuple(RealTupleType.SpatialEarth2DTuple, new double[] {(double)tup[0][0], (double)tup[1][0]});
334  }
335
336  public int getChannelIndexFromWavenumber(float channel) throws Exception {
337    return spectrumAdapter.getChannelIndexFromWavenumber(channel);
338  }
339
340  public float getWavenumberFromChannelIndex(int index) throws Exception {
341    return spectrumAdapter.getWavenumberFromChannelIndex(index);
342  }
343
344  public Rectangle2D getLonLatBoundingBox(CoordinateSystem cs) {
345    return null;
346  }
347
348  public Rectangle2D getLonLatBoundingBox(Map<String, double[]> subset)
349      throws Exception {
350    Set domainSet = swathAdapter.makeDomain(subset);
351    return getLonLatBoundingBox(domainSet);
352  }
353
354  public static Rectangle2D getLonLatBoundingBox(FlatField field) {
355    Set domainSet = field.getDomainSet();
356    return getLonLatBoundingBox(domainSet);
357  }
358
359  public static float[][] getLonLatBoundingCorners(Set domainSet) {
360    CoordinateSystem cs =
361      ((SetType)domainSet.getType()).getDomain().getCoordinateSystem();
362
363    float start0, stop0, start1, stop1;
364    int len0, len1;
365    float minLon = Float.MAX_VALUE;
366    float minLat = Float.MAX_VALUE;
367    float maxLon = -Float.MAX_VALUE;
368    float maxLat = -Float.MAX_VALUE;
369
370    float[][] corners = null;
371
372    if (domainSet instanceof Linear2DSet) {
373      Linear1DSet lset = ((Linear2DSet)domainSet).getLinear1DComponent(0);
374      start0 = (float) lset.getFirst();
375      stop0 = (float) lset.getLast();
376      len0 = lset.getLengthX();
377      lset = ((Linear2DSet)domainSet).getLinear1DComponent(1);
378      start1 = (float) lset.getFirst();
379      stop1 = (float) lset.getLast();
380      len1 = lset.getLengthX();
381
382      float x, y, del_x, del_y;
383      float lonA = Float.NaN;
384      float lonB = Float.NaN;
385      float lonC = Float.NaN;
386      float lonD = Float.NaN;
387      float latA = Float.NaN;
388      float latB = Float.NaN;
389      float latC = Float.NaN;
390      float latD = Float.NaN;
391
392      int nXpts = len0/1;
393      int nYpts = len1/1;
394
395      del_x = (stop0 - start0)/nXpts;
396      del_y = (stop1 - start1)/nYpts;
397      x = start0;
398      y = start1;
399      try {
400        for (int j=0; j<nYpts; j++) {
401          y = start1+j*del_y;
402          for (int i=0; i<nXpts; i++) {
403            x = start0 + i*del_x;
404            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
405            float lon = lonlat[0][0];
406            float lat = lonlat[1][0];
407            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
408              lonA = lon;
409              latA = lat;
410              break;
411            }
412          }
413          for (int i=0; i<nXpts; i++) {
414            x = stop0 - i*del_x;
415            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
416            float lon = lonlat[0][0];
417            float lat = lonlat[1][0];
418            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
419              lonB = lon;
420              latB = lat;
421              break;
422            }
423          }
424          if (!Float.isNaN(lonA) && !Float.isNaN(lonB)) {
425            break;
426          }
427        }
428
429        for (int j=0; j<nYpts; j++) {
430          y = stop1-j*del_y;
431          for (int i=0; i<nXpts; i++) {
432            x = start0 + i*del_x;
433            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
434            float lon = lonlat[0][0];
435            float lat = lonlat[1][0];
436            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
437              lonC = lon;
438              latC = lat;
439              break;
440            }
441          }
442          for (int i=0; i<nXpts; i++) {
443            x = stop0 - i*del_x;
444            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
445            float lon = lonlat[0][0];
446            float lat = lonlat[1][0];
447            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
448              lonD = lon;
449              latD = lat;
450              break;
451            }
452          }
453          if (!Float.isNaN(lonC) && !Float.isNaN(lonD)) {
454            break;
455          }
456         }
457         // TJJ - should these be validated? See history, lost some dead code here
458         corners = new float[][] {{lonA,lonB,lonC,lonD},{latA,latB,latC,latD}};
459       } catch (Exception e) {
460       }
461    }
462    else if (domainSet instanceof Gridded2DSet) {
463      int[] lens = ((Gridded2DSet)domainSet).getLengths();
464      start0 = 0f;
465      start1 = 0f;
466      stop0 = (float) lens[0];
467      stop1 = (float) lens[1];
468
469      float x, y, del_x, del_y;
470      del_x = (stop0 - start0)/10;
471      del_y = (stop1 - start1)/10;
472      x = start0;
473      y = start1;
474      try {
475        for (int j=0; j<11; j++) {
476          y = start1+j*del_y;
477          for (int i=0; i<11; i++) {
478            x = start0+i*del_x;
479            float[][] lonlat = ((Gridded2DSet)domainSet).gridToValue(new float[][] {{x}, {y}});
480            float lon = lonlat[0][0];
481            float lat = lonlat[1][0];
482            if ((lon > 180 || lon < -180) || (lat > 90 || lat < -90)) continue;
483            if (lon < minLon) minLon = lon;
484            if (lat < minLat) minLat = lat;
485            if (lon > maxLon) maxLon = lon;
486            if (lat > maxLat) maxLat = lat;
487          }
488        }
489      } catch (Exception e) {
490      }
491    }
492
493    return corners;
494  }
495
496  public static Rectangle2D getLonLatBoundingBox(Set domainSet) {
497    CoordinateSystem cs = 
498      ((SetType)domainSet.getType()).getDomain().getCoordinateSystem();
499
500    float start0, stop0, start1, stop1;
501    int len0, len1;
502    float minLon = Float.MAX_VALUE;
503    float minLat = Float.MAX_VALUE;
504    float maxLon = -Float.MAX_VALUE;
505    float maxLat = -Float.MAX_VALUE;
506
507
508    if (domainSet instanceof Linear2DSet) {
509      Linear1DSet lset = ((Linear2DSet)domainSet).getLinear1DComponent(0);
510      start0 = (float) lset.getFirst();
511      stop0 = (float) lset.getLast();
512      len0 = lset.getLengthX();
513      lset = ((Linear2DSet)domainSet).getLinear1DComponent(1);
514      start1 = (float) lset.getFirst();
515      stop1 = (float) lset.getLast();
516      len1 = lset.getLengthX();
517
518      float x, y, del_x, del_y;
519      float lonA = Float.NaN;
520      float lonB = Float.NaN;
521      float lonC = Float.NaN;
522      float lonD = Float.NaN;
523      float latA = Float.NaN;
524      float latB = Float.NaN;
525      float latC = Float.NaN;
526      float latD = Float.NaN;
527
528      int nXpts = len0/8;
529      int nYpts = len1/8;
530
531      del_x = (stop0 - start0)/nXpts;
532      del_y = (stop1 - start1)/nYpts;
533
534      x = start0;
535      y = start1;
536      try {
537        for (int j=0; j<nYpts; j++) {
538          y = start1+j*del_y;
539          for (int i=0; i<nXpts; i++) {
540            x = start0 + i*del_x;
541            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
542            float lon = lonlat[0][0];
543            float lat = lonlat[1][0];
544            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
545              lonA = lon;
546              latA = lat;
547              break;
548            }
549          }
550          for (int i=0; i<nXpts; i++) {
551            x = stop0 - i*del_x;
552            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
553            float lon = lonlat[0][0];
554            float lat = lonlat[1][0];
555            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
556              lonB = lon;
557              latB = lat;
558              break;
559            }
560          }
561          if (!Float.isNaN(lonA) && !Float.isNaN(lonB)) {
562            break;
563          }
564        }
565
566        for (int j=0; j<nYpts; j++) {
567          y = stop1-j*del_y;
568          for (int i=0; i<nXpts; i++) {
569            x = start0 + i*del_x;
570            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
571            float lon = lonlat[0][0];
572            float lat = lonlat[1][0];
573            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
574              lonC = lon;
575              latC = lat;
576              break;
577            }
578          }
579          for (int i=0; i<nXpts; i++) {
580            x = stop0 - i*del_x;
581            float[][] lonlat = cs.toReference(new float[][] {{x}, {y}});
582            float lon = lonlat[0][0];
583            float lat = lonlat[1][0];
584            if (!Float.isNaN(lon) && !Float.isNaN(lat)) {
585              lonD = lon;
586              latD = lat;
587              break;
588            }
589          }
590          if (!Float.isNaN(lonC) && !Float.isNaN(lonD)) {
591            break;
592          }
593         }
594         float[][] corners = {{lonA,lonB,lonC,lonD},{latA,latB,latC,latD}};
595         for (int k=0; k<corners[0].length; k++) {
596            float lon = corners[0][k];
597            float lat = corners[1][k];
598            if (lon < minLon) minLon = lon;
599            if (lat < minLat) minLat = lat;
600            if (lon > maxLon) maxLon = lon;
601            if (lat > maxLat) maxLat = lat;
602         }
603       } catch (Exception e) {
604       }
605    }
606    else if (domainSet instanceof Gridded2DSet) {
607      int[] lens = ((Gridded2DSet)domainSet).getLengths();
608      start0 = 0f;
609      start1 = 0f;
610      stop0 = (float) lens[0];
611      stop1 = (float) lens[1];
612
613      float x, y, del_x, del_y;
614      del_x = (stop0 - start0)/10;
615      del_y = (stop1 - start1)/10;
616      x = start0;
617      y = start1;
618      try {
619        for (int j=0; j<11; j++) {
620          y = start1+j*del_y;
621          for (int i=0; i<11; i++) {
622            x = start0+i*del_x;
623            float[][] lonlat = ((Gridded2DSet)domainSet).gridToValue(new float[][] {{x}, {y}});
624            float lon = lonlat[0][0];
625            float lat = lonlat[1][0];
626            if ((lon > 180 || lon < -180) || (lat > 90 || lat < -90)) continue;
627            if (lon < minLon) minLon = lon;
628            if (lat < minLat) minLat = lat;
629            if (lon > maxLon) maxLon = lon;
630            if (lat > maxLat) maxLat = lat;
631          }
632        }
633      } catch (Exception e) {
634      }
635    }
636    
637
638    float del_lon = maxLon - minLon;
639    float del_lat = maxLat - minLat;
640
641    return new Rectangle2D.Float(minLon, minLat, del_lon, del_lat);
642  }
643
644  public float[] radianceToBrightnessTemp(float[] values, float channelValue) {
645    float c1=1.191066E-5f;           //- mW/m2/ster/cm^-4
646    float c2=1.438833f;              //- K*cm
647    float nu = channelValue;         //- nu: wavenumber
648    float B, K, BT;
649
650    int n_values = values.length;
651    float[] new_values = new float[n_values];
652    for (int i=0; i<n_values;i++) {
653      B = values[i];
654      K = (c1*nu*nu*nu)/B;
655      if (K == 0.0) {
656        BT = B;
657      } 
658      else {
659        BT = c2*nu/((float) (Math.log((double)((c1*nu*nu*nu)/B)+1.0f)) );
660      }
661      if (BT < 0.01) BT = Float.NaN;
662      new_values[i] = BT;
663    }
664    return new_values;
665  }
666
667  public float[] radianceToBrightnessTemp(float[] values, float channelValue, String platformName, String sensorName) 
668     throws Exception {
669    float[] new_values = null;
670
671    if (sensorName == null) {
672      new_values = radianceToBrightnessTemp(values, channelValue);
673    }
674    else if (Objects.equals(sensorName, "MODIS")) {
675      int channelIndex = spectrumAdapter.getChannelIndexFromWavenumber(channelValue);
676      int band_number = MODIS_L1B_Utility.emissive_indexToBandNumber(channelIndex);
677      new_values = MODIS_L1B_Utility.modis_radiance_to_brightnessTemp(platformName, band_number, values);
678    }
679    return new_values;
680  }
681
682  public float[] radianceToBrightnessTempSpectrum(float[] values, float[] channelValues) {
683    //- Converts radiances [mW/ster/m2/cm^-1] to BT [K]
684    //-  Input: nu  array of wavenmbers [cm^-1]
685    //-          B   radiances [mW/ster/m2/cm^-1]
686    //-  Output: bt brightness temperature in [K]
687    //-   Paolo Antonelli
688    //-   Wed Feb 25 16:43:05 CST 1998
689
690    float c1=1.191066E-5f;           //- mW/m2/ster/cm^-4
691    float c2=1.438833f;              //- K*cm
692
693    float nu;                        //- wavenumber
694    float B, BT;
695
696    int n_values = values.length;
697    float[] new_values = new float[n_values];
698    for (int i=0; i<n_values; i++) {
699      nu = channelValues[i];
700      B = values[i];
701      BT = c2*nu/((float) (Math.log(((c1*nu*nu*nu)/B)+1.0f)) );
702      new_values[i] = BT;
703    }
704    return new_values;
705  }
706
707
708  public float[] radianceToBrightnessTempSpectrum(float[] values, float[] channelValues,
709                                 String platformName, String sensorName) 
710     throws Exception
711  {
712    float[] new_values = null;
713
714    if (sensorName == null) {
715      new_values =  radianceToBrightnessTempSpectrum(values, channelValues);
716    }
717    else if (Objects.equals(sensorName, "MODIS")) {
718      new_values = new float[values.length];
719      for (int k=0; k<new_values.length; k++) {
720        int channelIndex = spectrumAdapter.getChannelIndexFromWavenumber(channelValues[k]);
721        int band_number = MODIS_L1B_Utility.emissive_indexToBandNumber(channelIndex);
722        float[] tmp = new float[1];
723        tmp[0] = values[k];
724        new_values[k] = (MODIS_L1B_Utility.modis_radiance_to_brightnessTemp(platformName, band_number, tmp))[0];
725      }
726    }
727
728    return new_values;
729  }
730
731  public Map<String, double[]> getDefaultSubset() {
732    Map<String, double[]> subset = swathAdapter.getDefaultSubset();
733    double chanIdx=0;
734
735    try {
736       chanIdx = spectrumAdapter.getChannelIndexFromWavenumber(init_wavenumber);
737    }
738    catch (Exception e) {
739      System.out.println("couldn't get chanIdx, using zero");
740    }
741      
742    subset.put(SpectrumAdapter.channelIndex_name, new double[] {chanIdx, chanIdx, 1});
743    return subset;
744  }
745 
746
747  public SpectrumAdapter getSpectrumAdapter() {
748    return spectrumAdapter;
749  }
750}