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