001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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}