001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2017 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.adt; 030 031import java.io.IOException; 032import java.lang.Math; 033import java.lang.String; 034import java.rmi.RemoteException; 035import java.util.List; 036 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040import ucar.unidata.data.grid.GridUtil; 041import ucar.unidata.util.IOUtil; 042import ucar.unidata.util.StringUtil; 043import visad.FlatField; 044import visad.VisADException; 045 046public class ReadIRImage { 047 048 private static final Logger logger = LoggerFactory.getLogger(ReadIRImage.class); 049 050 public ReadIRImage() { 051 } 052 053 public static class ImgCoeffs { 054 String sat_id; 055 int sat_num; 056 int chan; 057 int det; 058 float scal_m; 059 float scal_b; 060 float side; 061 float conv_n; 062 float conv_a; 063 float conv_b; 064 float conv_g; 065 066 public ImgCoeffs(List<String> toks) { 067 sat_id = toks.get(0); 068 sat_num = Integer.parseInt(toks.get(1)); 069 chan = Integer.parseInt(toks.get(2)); 070 det = Integer.parseInt(toks.get(3)); 071 scal_m = Float.parseFloat(toks.get(4)); 072 scal_b = Float.parseFloat(toks.get(5)); 073 side = Float.parseFloat(toks.get(6)); 074 conv_n = Float.parseFloat(toks.get(7)); 075 conv_a = Float.parseFloat(toks.get(8)); 076 conv_b = Float.parseFloat(toks.get(9)); 077 conv_g = Float.parseFloat(toks.get(10)); 078 } 079 080 public String getSat_id() { 081 return sat_id; 082 } 083 } 084 085 public static void ReadIRDataFile(FlatField satgrid, 086 float cenlat, 087 float cenlon, 088 int SatelliteID, 089 int satChannel, 090 boolean isTemperature) 091 throws IOException, VisADException, RemoteException 092 { 093 // Retrieve temperatures from image. This to be done in IDV 094 GridUtil.Grid2D g2d = GridUtil.makeGrid2D(satgrid); 095 float[][] temps = null; 096 float[][][] satimage = null; 097 int numx = 200; 098 int numy = 200; 099 float[][] LocalLatitude = new float[200][200]; 100 float[][] LocalLongitude = new float[200][200]; 101 float[][] LocalTemperature = new float[200][200]; 102 103 // now spatial subset numx by numy 104 GridUtil.Grid2D g2d1 = spatialSubset(g2d, cenlat, cenlon, numx, numy); 105 106 satimage = g2d1.getvalues(); 107 float[][] temp0 = satimage[0]; 108 109 if (isTemperature) { 110 temps = temp0; 111 } else { 112 temps = im_gvtota(numx, numy, temp0, SatelliteID, satChannel); 113 } 114 115 Data.IRData_NumberRows = numy; 116 Data.IRData_NumberColumns = numx; 117 Data.IRData_CenterLatitude = cenlat; 118 Data.IRData_CenterLongitude = cenlon; 119 120 LocalTemperature = temps; 121 LocalLatitude = g2d1.getlats(); 122 LocalLongitude = g2d1.getlons(); 123 124 for(int XInc = 0; XInc < numx; XInc++) { 125 for(int YInc = 0; YInc < numy; YInc++) { 126 // must flip x/y to y/x for ADT automated routines 127 Data.IRData_Latitude[YInc][XInc] = LocalLatitude[XInc][YInc]; 128 Data.IRData_Longitude[YInc][XInc] = LocalLongitude[XInc][YInc]; 129 Data.IRData_Temperature[YInc][XInc] = LocalTemperature[XInc][YInc]; 130 } 131 } 132 int CenterXPos = Data.IRData_NumberColumns / 2; 133 int CenterYPos = Data.IRData_NumberRows / 2; 134 135 double LocalValue[] = 136 Functions.distance_angle( 137 Data.IRData_Latitude[CenterYPos][CenterXPos], 138 Data.IRData_Longitude[CenterYPos][CenterXPos], 139 Data.IRData_Latitude[CenterYPos+1][CenterXPos], 140 Data.IRData_Longitude[CenterYPos][CenterXPos], 141 1); 142 143 Data.IRData_ImageResolution = LocalValue[0]; 144 145 History.IRCurrentRecord.date = Data.IRData_JulianDate; 146 History.IRCurrentRecord.time = Data.IRData_HHMMSSTime; 147 History.IRCurrentRecord.latitude = Data.IRData_CenterLatitude; 148 History.IRCurrentRecord.longitude = Data.IRData_CenterLongitude; 149 History.IRCurrentRecord.sattype = SatelliteID; 150 151 int RetVal[] = Functions.adt_oceanbasin(Data.IRData_CenterLatitude, 152 Data.IRData_CenterLongitude); 153 Env.DomainID = RetVal[1]; 154 // System.out.printf("lat=%f lon=%f domainID=%d\n",Data.IRData_CenterLatitude,Data.IRData_CenterLongitude,Env.DomainID); 155 } 156 157 private static GridUtil.Grid2D spatialSubset(GridUtil.Grid2D g2d, 158 float cenlat, 159 float cenlon, 160 int numx, 161 int numy) 162 { 163 float[][] lats = g2d.getlats(); 164 float[][] lons = g2d.getlons(); 165 float[][][] values = g2d.getvalues(); 166 float[][] slats = new float[numx][numy]; 167 float[][] slons = new float[numx][numy]; 168 float[][][] svalues = new float[1][numx][numy]; 169 170 int ly = lats[0].length; 171 int ly0 = ly / 2; 172 int lx = lats.length; 173 logger.debug("lenx: {}, leny: {}", lx, ly); 174 int lx0 = lx / 2; 175 int ii = numx / 2, jj = numy / 2; 176 177 for (int j = 0; j < ly - 1; j++) { 178 if (Float.isNaN(lats[lx0][j])) { 179 continue; 180 } 181 if ((lats[lx0][j] > cenlat) && (lats[lx0][j + 1] < cenlat)) { 182 jj = j; 183 } 184 } 185 for (int i = 0; i < lx - 1; i++) { 186 if (Float.isNaN(lons[i][ly0])) { 187 continue; 188 } 189 if ((lons[i][ly0] < cenlon) && (lons[i + 1][ly0] > cenlon)) { 190 ii = i; 191 } 192 } 193 int startx = ii - (numx / 2 - 1); 194 int starty = jj - (numy / 2 - 1); 195 logger.debug("startx: {}, starty: {}", startx, starty); 196 logger.debug("numx: {}, numy: {}", numx, numy); 197 198 if (startx < 0) { 199 startx = 0; 200 } 201 if (starty < 0) { 202 starty = 0; 203 } 204 for (int i = 0; i < numx; i++) { 205 for (int j = 0; j < numy; j++) { 206 try { 207 slats[i][j] = lats[i + startx][j + starty]; 208 } catch (ArrayIndexOutOfBoundsException aioobe) { 209 slats[i][j] = Float.NaN; 210 } 211 try { 212 slons[i][j] = lons[i + startx][j + starty]; 213 } catch (ArrayIndexOutOfBoundsException aioobe) { 214 slats[i][j] = Float.NaN; 215 } 216 try { 217 svalues[0][i][j] = values[0][i + startx][j + starty]; 218 } catch (ArrayIndexOutOfBoundsException aioobe) { 219 slats[i][j] = Float.NaN; 220 } 221 } 222 } 223 return new GridUtil.Grid2D(slats, slons, svalues); 224 } 225 226 /** 227 * im_gvtota 228 * 229 * This subroutine converts GVAR counts to actual temperatures based on the 230 * current image set in IM_SIMG. 231 * 232 * im_gvtota ( int *nvals, unsigned int *gv, float *ta, int *iret ) 233 * 234 * Input parameters: *nvals int Number of values to convert *gv int Array of 235 * GVAR count values 236 * 237 * Output parameters: *ta float Array of actual temperatures *iret int 238 * Return value = -1 - could not open table = -2 - could not find match 239 * 240 * 241 * Log: D.W.Plummer/NCEP 02/03 D.W.Plummer/NCEP 06/03 Add coeff G for 2nd 242 * order poly conv T. Piper/SAIC 07/06 Added tmpdbl to eliminate warning 243 */ 244 private static float[][] im_gvtota(int nx, 245 int ny, 246 float[][] gv, 247 int imsorc, 248 int imtype) 249 { 250 double c1 = 1.191066E-5; 251 double c2 = 1.438833; 252 253 int ii; 254 int ip; 255 int chan; 256 int found; 257 double Rad; 258 double Teff; 259 double tmpdbl; 260 float[][] ta = new float[nx][ny]; 261 String fp = "/ucar/unidata/data/storm/ImgCoeffs.tbl"; 262 263 for (ii = 0; ii < nx; ii++) { 264 for (int jj = 0; jj < ny; jj++) { 265 ta[ii][jj] = Float.NaN; 266 } 267 } 268 269 // Read in coefficient table if necessary. 270 String s = null; 271 try { 272 s = IOUtil.readContents(fp); 273 } catch (Exception re) { 274 logger.warn("Failed to read coefficient table", re); 275 } 276 277 int i = 0; 278 ImgCoeffs[] ImageConvInfo = new ImgCoeffs[50]; 279 for (String line : StringUtil.split(s, "\n", true, true)) { 280 if (line.startsWith("!")) { 281 continue; 282 } 283 List<String> stoks = StringUtil.split(line, " ", true, true); 284 ImageConvInfo[i] = new ImgCoeffs(stoks); 285 i++; 286 } 287 int nImgRecs = i; 288 found = 0; 289 ii = 0; 290 while ((ii < nImgRecs) && (found == 0)) { 291 int tmp = ImageConvInfo[ii].chan - 1; 292 tmpdbl = (double)(tmp * tmp); 293 chan = G_NINT(tmpdbl); 294 if ((imsorc == ImageConvInfo[ii].sat_num) && (imtype == chan)) { 295 found = 1; 296 } else { 297 ii++; 298 } 299 } 300 301 if (found == 0) { 302 return null; 303 } else { 304 ip = ii; 305 for (ii = 0; ii < nx; ii++) { 306 for (int jj = 0; jj < ny; jj++) { 307 // Convert GVAR count (gv) to Scene Radiance 308 Rad = ((double) gv[ii][jj] - ImageConvInfo[ip].scal_b) / 309 // ------------------------------------- 310 ImageConvInfo[ip].scal_m; 311 312 Rad = Math.max(Rad, 0.0); 313 314 // Convert Scene Radiance to Effective Temperature 315 Teff = (c2 * ImageConvInfo[ip].conv_n) 316 / 317 /* 318 * -------------------------------------------------- 319 * ----- 320 */ 321 (Math.log(1.0 322 + (c1 * Math.pow(ImageConvInfo[ip].conv_n, 323 3.0)) / Rad)); 324 // Convert Effective Temperature to Temperature 325 ta[ii][jj] = (float) (ImageConvInfo[ip].conv_a 326 + ImageConvInfo[ip].conv_b * Teff + ImageConvInfo[ip].conv_g 327 * Teff * Teff); 328 } 329 } 330 } 331 return ta; 332 } 333 334 public static int G_NINT(double x) { 335 return (((x) < 0.0F) ? ((((x) - (float) ((int) (x))) <= -.5f) ? (int) ((x) - .5f) 336 : (int) (x)) 337 : ((((x) - (float) ((int) (x))) >= .5f) ? (int) ((x) + .5f) 338 : (int) (x))); 339 } 340}