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;
030import visad.Set;
031
032
033public class MODIS_L1B_Utility {
034 /**
035 Emissive bands
036 taken from pfm-in-band-rsr.pdf (Aqua)
037
038 band center width (m*10E6)
039 begin end
040------------------------------------
041 20 3.799 3.660 3.840
042 21 3.992 3.929 3.989
043 22 3.968 3.929 3.989
044 23 4.070 4.020 4.080
045 24 4.476 4.433 4.498
046 25 4.549 4.482 4.549
047 27 6.784 6.535 6.895
048 28 7.345 7.175 7.475
049 29 8.503 8.400 8.700
050 30 9.700 9.580 9.880
051 31 11.000 10.780 11.280
052 32 12.005 11.770 12.270
053 33 13.351 13.185 13.485
054 34 13.717 13.485 13.785
055 35 13.908 13.785 14.085
056 36 14.205 14.085 14.385
057**/
058
059 //... Effective central wavelengths (micrometers)
060   static double[] cwl_aqua = {
061           3.799, 3.992, 3.968, 4.070, 4.476, 4.549, 6.784,
062           7.345, 8.503, 9.700, 11.000, 12.005, 13.351, 13.717, 13.908, 14.205};
063
064 //... Effective central wavenumbers (inverse centimeters)
065   static double[] cwn_terra = {
066       2.641767E+03, 2.505274E+03, 2.518031E+03, 2.465422E+03,
067       2.235812E+03, 2.200345E+03, 1.478026E+03, 1.362741E+03,
068       1.173198E+03, 1.027703E+03, 9.081998E+02, 8.315149E+02,
069       7.483224E+02, 7.309089E+02, 7.188677E+02, 7.045309E+02};
070                                                                                                                                                     
071 //... Temperature correction slopes (no units)
072   static double[]  tcs_terra = {
073       9.993487E-01,  9.998699E-01,  9.998604E-01,  9.998701E-01,
074       9.998825E-01,  9.998849E-01,  9.994942E-01,  9.994937E-01,
075       9.995643E-01,  9.997499E-01,  9.995880E-01,  9.997388E-01,
076       9.999192E-01,  9.999171E-01,  9.999174E-01,  9.999264E-01};
077                                                                                                                                                     
078 //... Temperature correction intercepts (Kelvin)
079   static double[]  tci_terra = {
080       4.744530E-01,  9.091094E-02,  9.694298E-02,  8.856134E-02,
081       7.287017E-02,  7.037161E-02,  2.177889E-01,  2.037728E-01,
082       1.559624E-01,  7.989879E-02,  1.176660E-01,  6.856633E-02,
083       1.903625E-02,  1.902709E-02,  1.859296E-02,  1.619453E-02};
084                                                                                                                                                     
085 //... Effective central wavenumbers (inverse centimeters)
086   static double[]  cwn_aqua = {
087       2.647418E+03, 2.511763E+03, 2.517910E+03, 2.462446E+03,
088       2.248296E+03, 2.209550E+03, 1.474292E+03, 1.361638E+03,
089       1.169637E+03, 1.028715E+03, 9.076808E+02, 8.308397E+02,
090       7.482977E+02, 7.307761E+02, 7.182089E+02, 7.035020E+02};
091                                                                                                                                                     
092 //... Temperature correction slopes (no units)
093   static double[]  tcs_aqua = {
094       9.993438E-01, 9.998680E-01, 9.998649E-01, 9.998729E-01,
095       9.998738E-01, 9.998774E-01, 9.995732E-01, 9.994894E-01,
096       9.995439E-01, 9.997496E-01, 9.995483E-01, 9.997404E-01,
097       9.999194E-01, 9.999071E-01, 9.999176E-01, 9.999211E-01};
098                                                                                                                                                     
099 //... Temperature correction intercepts (Kelvin)
100  static double[]  tci_aqua = {
101       4.792821E-01, 9.260598E-02, 9.387793E-02, 8.659482E-02,
102       7.854801E-02, 7.521532E-02, 1.833035E-01, 2.053504E-01,
103       1.628724E-01, 8.003410E-02, 1.290129E-01, 6.810679E-02,
104       1.895925E-02, 2.128960E-02, 1.857071E-02, 1.733782E-02};
105
106// Constants are from "The Fundamental Physical Constants",
107// Cohen, E. R. and B. N. Taylor, Physics Today, August 1993.
108                                                                                                                                                     
109// Planck constant (Joule second)
110  static double h = 6.6260755e-34;
111                                                                                                                                                     
112// Speed of light in vacuum (meters per second)
113 static double c = 2.9979246e+8;
114                                                                                                                                                     
115// Boltzmann constant (Joules per Kelvin)
116 static double k = 1.380658e-23;
117                                                                                                                                                     
118// Derived constants
119 static double c1 = 2.0 * h * c * c;
120 static double c2 = (h * c) / k;
121                                                                                                                                                     
122  public static float[]  modis_radiance_to_brightnessTemp(String platformName, int band_number, float[] values)
123         throws Exception
124  {
125    return (Set.doubleToFloat(
126       new double[][] {modis_radiance_to_brightnessTemp(platformName,band_number,(Set.floatToDouble(new float[][] {values}))[0])}))[0];
127  }
128
129  public static double[] modis_radiance_to_brightnessTemp(String platformName, int band_number,  double[] values)
130         throws Exception
131  {
132                                                                                                                                                     
133    if ((band_number < 20) || (band_number > 36) || (band_number == 26)) {
134      throw new Exception("bad band number: "+band_number+" band 20-36 but not 26");
135    }
136                                                                                                                                                     
137    int index;
138                                                                                                                                                     
139    if (band_number <= 25) {
140      index = band_number - 19;
141    }
142    else {
143      index = band_number - 20;
144    }
145    index -= 1;
146                                                                                                                                                     
147    double cwn;
148    double tcs;
149    double tci;
150
151    if (platformName.equals("Terra")) {
152      cwn = cwn_terra[index];
153      tcs = tcs_terra[index];
154      tci = tci_terra[index];
155    }
156    else if (platformName.equals("Aqua")) {
157      cwn = cwn_aqua[index];
158      tcs = tcs_aqua[index];
159      tci = tci_aqua[index];
160    }
161    else {
162      throw new Exception("platformName must equal: Terra or Aqua");
163    }
164
165    //... Compute Planck radiance - MODIS units
166    //... Watts per square meter per steradian per micron
167                                                                                                                                                     
168    //... Convert wavelength to meters
169    double ws = 1.0E-6 * (1.0E+4 / cwn);
170                                                                                                                                                     
171    //... Compute brightness temperature
172    int len = values.length;
173    double[] new_values = new double[len];
174    for (int kk = 0; kk < len; kk++) {
175      double rad = values[kk];
176      double BT = ( c2 / (ws * Math.log(c1 /(1.0E+6*rad*(ws*ws*ws*ws*ws)) + 1.0))-tci)/tcs;
177      new_values[kk] = BT;
178    }
179
180    return new_values;
181  }
182
183  public static int emissive_indexToBandNumber(int channelIndex) {
184    int[] bandNumbers = new int[] {20,21,22,23,24,25,27,28,29,30,31,32,33,34,35,36};
185    return bandNumbers[channelIndex];
186  }
187
188  public static float[][] brightnessTemp_to_radiance(float[][] values, int band_number) 
189          throws Exception {
190    int index = getIndexFromBandNumber(band_number);
191    return new float[][] {brightnessTemp_to_radiance(values[0], (float) cwl_aqua[index])};
192  }
193
194  public static float[] brightnessTemp_to_radiance(float[] values, float wavelength) {
195
196   // Constants are from "The Fundamental Physical Constants",
197   // Cohen, E. R. and B. N. Taylor, Physics Today, August 1993.
198
199   double w = (double) wavelength;
200
201   // Planck constant (Joule second)
202   double h = 6.6260755e-34;
203
204   // Speed of light in vacuum (meters per second)
205   double c = 2.9979246e8;
206
207   // Boltzmann constant (Joules per Kelvin)
208   double k = 1.380658e-23;
209
210   // Derived constants
211   double c1 = 2.0 * h * c * c;
212   double c2 = (h * c) / k;
213
214   // Convert wavelength to meters
215   double ws = 1.0e-6 * w;
216
217   // Compute brightness temperature
218   float[] new_values = new float[values.length];
219   for (int i=0; i<values.length; i++) {
220     double t = (double) values[i];
221     new_values[i] = (float) ((1.0e-6*(c1/(ws*ws*ws*ws*ws)))/(Math.exp(c2/(ws * t)) - 1.0));
222   }
223
224   return new_values;
225  }
226
227  public static int getIndexFromBandNumber(int band_number) throws Exception {
228
229    if ((band_number < 20) || (band_number > 36) || (band_number == 26)) {
230      throw new Exception("bad band number: "+band_number+" band 20-36 but not 26");
231    }
232
233    int index;
234
235    if (band_number <= 25) {
236      index = band_number - 19;
237    }
238    else {
239      index = band_number - 20;
240    }
241    index -= 1;
242
243    return index;
244  }
245
246}