001 /** 002 * 003 */ 004 package org.wdssii.dualpol.icing; 005 006 import java.io.File; 007 import java.io.FileWriter; 008 import java.io.IOException; 009 import java.io.PrintWriter; 010 import java.util.ArrayList; 011 import java.util.Date; 012 import java.util.List; 013 014 import org.apache.commons.logging.Log; 015 import org.apache.commons.logging.LogFactory; 016 import org.wdssii.core.DataType; 017 import org.wdssii.core.LatLonGrid; 018 import org.wdssii.core.NetcdfDataEncoder; 019 import org.wdssii.core.WDSSII; 020 import org.wdssii.core.LatLonGrid.Pixel; 021 import org.wdssii.dualpol.IDLNetcdfGridReader; 022 023 024 /** 025 * @author lakshman 026 * 027 */ 028 public class Statistics { 029 private static Log log = LogFactory.getLog(Statistics.class); 030 public static void main(String[] args) throws IOException { 031 WDSSII.getInstance(); // sets timezone etc. 032 if ( args.length < 3 ){ 033 System.err.println("Usage: java " + Statistics.class.getCanonicalName() + " in_pireps_dir in_icing_dir output_dir"); 034 return; 035 } 036 037 Statistics stats = new Statistics(); 038 stats.writeOutputs(args[0], args[1], args[2]); 039 } 040 041 public void writeOutputs(String pireps_dir, String icing_dir, String output_dir) throws IOException { 042 PilotReport[] pireps = new PirepsReader().readReports(pireps_dir, "150km"); 043 IcingFile[] icings = IcingFile.getAllFiles(icing_dir, "KOUN"); 044 new File(output_dir).mkdirs(); 045 046 final long maxTimeDifferenceMsecs = 30 * 60 * 60 * 1000; // 30 minutes 047 int num_written = 0; 048 for (PilotReport r : pireps){ 049 IcingFile nearest_icing = getClosestInTime(icings, r.getTime(), maxTimeDifferenceMsecs ); 050 if (log.isInfoEnabled()){ 051 log.info(r + "->" + nearest_icing); 052 } 053 if ( nearest_icing != null ){ 054 String outName = "stat_" + NetcdfDataEncoder.getFormattedDate(r.getTime()) + "_" + num_written + ".txt"; 055 File f = new File(output_dir, outName); 056 IcingGrids icingGrids = new IcingGrids( new IDLNetcdfGridReader().fromNetcdfFile(nearest_icing.file) ); 057 writeStatsFile( r, icingGrids , f ); 058 ++num_written; 059 } 060 } 061 } 062 063 064 private void writeStatsFile(PilotReport report, IcingGrids grid, File outFile ) throws IOException { 065 StringBuilder comment = new StringBuilder("#"); 066 StringBuilder data = new StringBuilder(); 067 String sep = "\t"; 068 069 comment.append("Time").append(sep); 070 data.append( NetcdfDataEncoder.getFormattedDate(report.getTime())).append(sep); 071 072 comment.append("Lat").append(sep); 073 data.append( report.getLocation().getLatitude() ).append(sep); 074 075 comment.append("Lon").append(sep); 076 data.append( report.getLocation().getLongitude() ).append(sep); 077 078 comment.append("Ht").append(sep); 079 data.append( report.getLocation().getHeightKms() ).append(sep); 080 081 comment.append("Icing").append(sep); 082 data.append( report.getIcingIntensity() ).append(sep); 083 084 for (int i=0; i < IcingGrids.gridTypes.length; ++i){ 085 LatLonGrid[] grids = grid.getGrids(i); 086 // get closest grid-point in space 087 LatLonGrid curr= getClosestGrid( report.getLocation().getHeightKms(), grids, 1.0 ); 088 if ( curr == null ){ 089 log.warn("Skipping " + report + " as it is above/below target area"); 090 return; 091 } 092 LatLonGrid.Pixel pixel = curr.getPixel(report.getLocation()); 093 if ( pixel == null ){ 094 log.warn("Skipping " + report + " as it is outside target area"); 095 return; 096 } 097 098 // grids above & below this grid point 099 LatLonGrid above = getAboveGrid( report.getLocation().getHeightKms(), grids ); 100 LatLonGrid below = getBelowGrid( report.getLocation().getHeightKms(), grids ); 101 if ( above == null ){ 102 above = curr; 103 } 104 if ( below == null ){ 105 below = curr; 106 } 107 108 // stats 109 addTextureStatistics(comment, data, sep, pixel, curr); 110 addVerticalDifferenceStatistics(comment, data, sep, pixel, curr, above, below); 111 addVerticalColumnStatistics(comment, data, sep, pixel, grids); 112 } 113 114 // now write the stuff out 115 PrintWriter writer = new PrintWriter(new FileWriter(outFile)); 116 writer.println(comment.toString()); 117 writer.println(data.toString()); 118 writer.close(); 119 } 120 121 private void addTextureStatistics(StringBuilder comment, 122 StringBuilder data, String sep, Pixel pixel, LatLonGrid curr) { 123 float max = 0; 124 float min = 999; 125 float sumx = 0; 126 float sumx2 = 0; 127 int N = 0; 128 129 for (int i = pixel.x - 2; i <= pixel.x + 2; ++i) for (int j = pixel.y - 2; j <= pixel.y + 2; ++j){ 130 try { 131 float value = curr.getValues()[i][j]; 132 if ( value == DataType.MissingData ){ 133 continue; 134 } 135 if ( value > max ){ 136 value = max; 137 } 138 if ( value < min ){ 139 value = min; 140 } 141 sumx += value; 142 sumx2 += (value*value); 143 N ++; 144 } catch (Exception e){ 145 // continue 146 } 147 } 148 149 float mean = (N > 0)? (sumx / N) : DataType.MissingData; 150 float var = (N > 1)? ((sumx2 - (sumx*sumx)/N)/(N-1)) : 0; 151 if ( N == 0 ){ 152 min = mean = max = DataType.MissingData; 153 } 154 String typeName = curr.getTypeName(); 155 comment.append("hor_avg" + typeName).append(sep); 156 data.append( mean ).append(sep); 157 comment.append("hor_max" + typeName).append(sep); 158 data.append( max ).append(sep); 159 comment.append("hor_min" + typeName).append(sep); 160 data.append( min ).append(sep); 161 comment.append("hor_var" + typeName).append(sep); 162 data.append( var ).append(sep); 163 comment.append("hor_N" + typeName).append(sep); 164 data.append( N ).append(sep); 165 } 166 167 private void addVerticalColumnStatistics(StringBuilder comment, 168 StringBuilder data, String sep, LatLonGrid.Pixel loc, 169 LatLonGrid[] grids) { 170 float max = 0; 171 float min = 999; 172 float sumx = 0; 173 float sumx2 = 0; 174 int N = 0; 175 176 for (int g=0; g < grids.length; ++g){ 177 float value = grids[g].getValue(loc); 178 if ( value == DataType.MissingData ){ 179 continue; 180 } 181 if ( value > max ){ 182 value = max; 183 } 184 if ( value < min ){ 185 value = min; 186 } 187 sumx += value; 188 sumx2 += (value*value); 189 N ++; 190 } 191 192 float mean = (N > 0)? (sumx / N) : DataType.MissingData; 193 float var = (N > 1)? ((sumx2 - (sumx*sumx)/N)/(N-1)) : 0; 194 if ( N == 0 ){ 195 min = mean = max = DataType.MissingData; 196 } 197 String typeName = grids[0].getTypeName(); 198 comment.append("vert_avg" + typeName).append(sep); 199 data.append( mean ).append(sep); 200 comment.append("vert_max" + typeName).append(sep); 201 data.append( max ).append(sep); 202 comment.append("vert_min" + typeName).append(sep); 203 data.append( min ).append(sep); 204 comment.append("vert_var" + typeName).append(sep); 205 data.append( var ).append(sep); 206 comment.append("vert_N" + typeName).append(sep); 207 data.append( N ).append(sep); 208 } 209 210 private static float diff(float a, float b){ 211 if ( a == DataType.MissingData ){ 212 a = 0; 213 } 214 if ( b == DataType.MissingData ){ 215 b = 0; 216 } 217 return (a - b); 218 } 219 220 private void addVerticalDifferenceStatistics(StringBuilder comment, StringBuilder data, String sep, 221 LatLonGrid.Pixel loc, LatLonGrid curr, LatLonGrid above, LatLonGrid below) { 222 223 // data 224 comment.append(curr.getTypeName()).append(sep); 225 float value = curr.getValue(loc); 226 data.append( value ).append(sep); 227 228 // deltaabove 229 comment.append("d" + curr.getTypeName() + "_up").append(sep); 230 float aboveValue = above.getValue(loc); 231 data.append( diff(aboveValue,value) ).append(sep); 232 233 // deltabelow 234 comment.append("d" + curr.getTypeName() + "_down").append(sep); 235 float belowValue = above.getValue(loc); 236 data.append( diff(value,belowValue) ).append(sep); 237 238 } 239 240 private LatLonGrid getClosestGrid(double ht, LatLonGrid[] grids, double max_diff){ 241 LatLonGrid best = null; 242 double best_diff = max_diff; 243 for (LatLonGrid grid : grids){ 244 double diff = Math.abs(grid.getLocation().getHeightKms() - ht); 245 if ( diff < best_diff ){ 246 best = grid; 247 best_diff = diff; 248 } 249 } 250 return best; 251 } 252 253 private LatLonGrid getAboveGrid(double ht, LatLonGrid[] grids){ 254 LatLonGrid best = null; 255 double best_diff = Double.MAX_VALUE; 256 for (LatLonGrid grid : grids){ 257 double diff = (grid.getLocation().getHeightKms() - ht); 258 if ( diff > 0.001 && diff < best_diff ){ 259 best = grid; 260 best_diff = diff; 261 } 262 } 263 return best; 264 } 265 266 private LatLonGrid getBelowGrid(double ht, LatLonGrid[] grids){ 267 LatLonGrid best = null; 268 double best_diff = Double.MAX_VALUE; 269 for (LatLonGrid grid : grids){ 270 double diff = (ht - grid.getLocation().getHeightKms()); 271 if ( diff > 0.001 && diff < best_diff ){ 272 best = grid; 273 best_diff = diff; 274 } 275 } 276 return best; 277 } 278 279 private IcingFile getClosestInTime(IcingFile[] candidates, Date time, long maxTimeDiffMsecs ){ 280 if ( candidates.length == 0 ){ 281 return null; 282 } 283 284 // find closest in time 285 IcingFile best = candidates[0]; 286 long bestTimeDiff = Math.abs(best.time.getTime() - time.getTime()); 287 for (IcingFile f : candidates){ 288 long timeDiff = Math.abs(f.time.getTime() - time.getTime()); 289 if ( timeDiff < bestTimeDiff ){ 290 bestTimeDiff = timeDiff; 291 best = f; 292 } 293 } 294 295 // check against threshold 296 if ( bestTimeDiff < maxTimeDiffMsecs ){ 297 return best; 298 } else { 299 return null; 300 } 301 } 302 303 public static class IcingFile { 304 public final File file; 305 public final Date time; 306 public IcingFile(File f, Date time) { 307 this.file = f; 308 this.time = time; 309 } 310 public static IcingFile[] getAllFiles(String dir, String pattern){ 311 File[] icing_files = new File(dir).listFiles(); 312 List<IcingFile> result = new ArrayList<IcingFile>(); 313 for (File f : icing_files){ 314 if (f.getName().contains(pattern)){ 315 IcingFile file = new IcingFile(f, IDLNetcdfGridReader.getTimeFromFileName(f.getName())); 316 result.add(file); 317 } 318 } 319 return result.toArray(new IcingFile[0]); 320 } 321 @Override 322 public String toString(){ 323 return file.getName() + " at " + time; 324 } 325 } 326 }