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