001/* 002 * Copyright (c) 2016 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2016-02-18 00:30:35 +0000 (Thu, 18 Feb 2016) $' 007 * '$Revision: 34440 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029package org.kepler.gis.actor.farsite; 030 031import java.io.File; 032import java.io.FileWriter; 033import java.io.IOException; 034 035import ptolemy.actor.TypedAtomicActor; 036import ptolemy.actor.TypedIOPort; 037import ptolemy.actor.parameters.PortParameter; 038import ptolemy.data.IntToken; 039import ptolemy.data.StringToken; 040import ptolemy.data.Token; 041import ptolemy.data.type.BaseType; 042import ptolemy.data.type.Type; 043import ptolemy.kernel.CompositeEntity; 044import ptolemy.kernel.util.Attribute; 045import ptolemy.kernel.util.IllegalActionException; 046import ptolemy.kernel.util.NameDuplicationException; 047 048/** Generate a wind file for FARSITE. The file contains a list 049 * of observations for the wind speed, direction, and cloud cover. 050 * 051 * @author Daniel Crawl 052 * @version $Id: GenerateWindFile.java 34440 2016-02-18 00:30:35Z crawl $ 053 */ 054public class GenerateWindFile extends TypedAtomicActor { 055 056 public GenerateWindFile(CompositeEntity container, String name) 057 throws IllegalActionException, NameDuplicationException { 058 super(container, name); 059 060 speed = new PortParameter(this, "speed"); 061 speed.setTypeEquals(BaseType.INT); 062 speed.getPort().setTypeEquals(BaseType.INT); 063 new Attribute(speed.getPort(), "_showName"); 064 065 direction = new PortParameter(this, "direction"); 066 direction.setTypeEquals(BaseType.INT); 067 direction.getPort().setTypeEquals(BaseType.INT); 068 new Attribute(direction.getPort(), "_showName"); 069 070 cloudCover = new PortParameter(this, "cloudCover"); 071 cloudCover.setTypeEquals(BaseType.INT); 072 cloudCover.getPort().setTypeEquals(BaseType.INT); 073 new Attribute(cloudCover.getPort(), "_showName"); 074 075 observationIncrement = new PortParameter(this, "observationIncrement"); 076 observationIncrement.setTypeEquals(BaseType.INT); 077 observationIncrement.getPort().setTypeEquals(BaseType.INT); 078 new Attribute(observationIncrement.getPort(), "_showName"); 079 080 startMonth = new PortParameter(this, "startMonth"); 081 startMonth.setTypeEquals(BaseType.INT); 082 startMonth.getPort().setTypeEquals(BaseType.INT); 083 new Attribute(startMonth.getPort(), "_showName"); 084 085 /* 086 endMonth = new PortParameter(this, "endMonth"); 087 endMonth.setTypeEquals(BaseType.INT); 088 endMonth.getPort().setTypeEquals(BaseType.INT); 089 new Attribute(endMonth.getPort(), "_showName"); 090 */ 091 092 startDay = new PortParameter(this, "startDay"); 093 startDay.setTypeEquals(BaseType.INT); 094 startDay.getPort().setTypeEquals(BaseType.INT); 095 new Attribute(startDay.getPort(), "_showName"); 096 097 /* 098 endDay = new PortParameter(this, "endDay"); 099 endDay.setTypeEquals(BaseType.INT); 100 endDay.getPort().setTypeEquals(BaseType.INT); 101 new Attribute(endDay.getPort(), "_showName"); 102 */ 103 104 startHour = new PortParameter(this, "startHour"); 105 startHour.setTypeEquals(BaseType.INT); 106 startHour.getPort().setTypeEquals(BaseType.INT); 107 new Attribute(startHour.getPort(), "_showName"); 108 109 endHour = new PortParameter(this, "endHour"); 110 endHour.setTypeEquals(BaseType.INT); 111 endHour.getPort().setTypeEquals(BaseType.INT); 112 new Attribute(endHour.getPort(), "_showName"); 113 114 file = new PortParameter(this, "file"); 115 file.setTypeEquals(BaseType.STRING); 116 file.setStringMode(true); 117 file.getPort().setTypeEquals(BaseType.STRING); 118 new Attribute(file.getPort(), "_showName"); 119 120 out = new TypedIOPort(this, "out", false, true); 121 out.setTypeEquals(BaseType.STRING); 122 } 123 124 @Override 125 public void attributeChanged(Attribute attribute) throws IllegalActionException { 126 127 if(attribute == direction) { 128 Token token = direction.getToken(); 129 if(token != null) { 130 int val = ((IntToken)token).intValue(); 131 if(val < -2 || val > 360) { 132 throw new IllegalActionException(this, 133 "Wind direction must be between 0 and 360, or -1 or -2."); 134 } 135 } 136 } else { 137 super.attributeChanged(attribute); 138 } 139 } 140 141 @Override 142 public void fire() throws IllegalActionException { 143 144 super.fire(); 145 146 int startMonthVal = ((Integer) _readPortParameter(startMonth)).intValue(); 147 if(startMonthVal < 1 || startMonthVal > 12) { 148 throw new IllegalActionException(this, "startMonth must be between 1 and 12."); 149 } 150 151 /* 152 int endMonthVal = ((Integer) _readPortParameter(endMonth)).intValue(); 153 if(endMonthVal < 1 || endMonthVal > 12) { 154 throw new IllegalActionException(this, "endMonth must be between 1 and 12."); 155 } 156 157 if(startMonthVal > endMonthVal) { 158 throw new IllegalActionException(this, "startMonth must be <= endMonth."); 159 } 160 */ 161 162 int startDayVal = ((Integer) _readPortParameter(startDay)).intValue(); 163 if(startDayVal < 1 || startDayVal > 31) { 164 throw new IllegalActionException(this, "startDay must be between 1 and 31."); 165 } 166 167 /* 168 int endDayVal = ((Integer) _readPortParameter(endDay)).intValue(); 169 if(endDayVal < 1 || endDayVal > 31) { 170 throw new IllegalActionException(this, "endDay must be between 1 and 31."); 171 } 172 173 if(startDayVal > endDayVal) { 174 throw new IllegalActionException(this, "startDay must be <= endDay."); 175 } 176 */ 177 178 int startHourVal = ((Integer) _readPortParameter(startHour)).intValue(); 179 if(startHourVal < 0 || startHourVal > 2400) { 180 throw new IllegalActionException(this, "startHour must be between 0 and 2400."); 181 } 182 183 int endHourVal = ((Integer) _readPortParameter(endHour)).intValue(); 184 if(endHourVal < 0 || endHourVal > 2400) { 185 throw new IllegalActionException(this, "endHour must be between 0 and 2400."); 186 } 187 188 if(startHourVal > endHourVal) { 189 throw new IllegalActionException(this, "startHour must be <= endHour"); 190 } 191 192 /* 193 // FIXME 194 if(startMonthVal != endMonthVal) { 195 throw new IllegalActionException("startMonth must be same as endMonth"); 196 } 197 198 // FIXME 199 if(startDayVal != endDayVal) { 200 throw new IllegalActionException("startDay must be same as endDay"); 201 } 202 */ 203 204 205 int speedVal = ((Integer) _readPortParameter(speed)).intValue(); 206 if(speedVal < 0) { 207 throw new IllegalActionException(this, "Wind speed must be >= 0."); 208 } 209 210 int directionVal = ((Integer) _readPortParameter(direction)).intValue(); 211 if(directionVal < -2 || directionVal > 360) { 212 throw new IllegalActionException(this, 213 "Wind direction must be between 0 and 360, or -1 or -2."); 214 } 215 216 int cloudCoverVal = ((Integer) _readPortParameter(cloudCover)).intValue(); 217 if(cloudCoverVal < 0 || cloudCoverVal > 100) { 218 throw new IllegalActionException(this, 219 "Cloud cover must be between 0 and 100."); 220 } 221 222 int incVal = ((Integer) _readPortParameter(observationIncrement)).intValue(); 223 if(incVal < 0) { 224 throw new IllegalActionException(this, 225 "Observation increment must be >= 0."); 226 } 227 228 int startHourOnly = startHourVal / 100; 229 int startMin = startHourVal % 100; 230 231 String outputFileName = (String) _readPortParameter(file); 232 File outputFile = new File(outputFileName); 233 try(FileWriter writer = new FileWriter(outputFile)) { 234 235 writer.write("ENGLISH\n"); 236 237 int curHour = startHourOnly; 238 int curMin = startMin; 239 // the time is HHMM 240 int curTime = curHour * 100 + curMin; 241 while(curTime <= endHourVal) { 242 243 StringBuilder buf = new StringBuilder(); 244 buf.append(startMonthVal); 245 buf.append(" "); 246 buf.append(startDayVal); 247 buf.append(" "); 248 buf.append(curTime); 249 buf.append(" "); 250 buf.append(speedVal); 251 buf.append(" "); 252 buf.append(directionVal); 253 buf.append(" "); 254 buf.append(cloudCoverVal); 255 buf.append("\n"); 256 257 writer.write(buf.toString()); 258 259 // increment the minutes 260 curMin += incVal; 261 262 // if minutes is > 60, increment hour and wrap remaining minutes 263 curHour += curMin / 60; 264 curMin = curMin % 60; 265 266 // calculate the new time (HHMM) 267 curTime = curHour * 100 + curMin; 268 } 269 270 271 } catch (IOException e) { 272 throw new IllegalActionException(this, e, 273 "Error writing to " + outputFileName); 274 } 275 276 out.broadcast(new StringToken(outputFileName)); 277 } 278 279 /** Read the value in a PortParameter. */ 280 private Object _readPortParameter(PortParameter pp) throws IllegalActionException { 281 282 pp.update(); 283 Token token = pp.getToken(); 284 if(token == null) { 285 throw new IllegalActionException(this, "Missing value for " + pp.getName()); 286 } 287 288 Type type = pp.getType(); 289 if(type == BaseType.INT) { 290 return Integer.valueOf(((IntToken)token).intValue()); 291 } else if(type == BaseType.STRING) { 292 return ((StringToken)token).stringValue(); 293 } else { 294 throw new IllegalActionException(this, 295 "Unexpected type " + type + " for " + pp.getName()); 296 } 297 } 298 299 /** The start month. */ 300 public PortParameter startMonth; 301 302 //public PortParameter endMonth; 303 304 /** The start day. */ 305 public PortParameter startDay; 306 307 //public PortParameter endDay; 308 309 /** The start hour and minutes, e.g., 1230. */ 310 public PortParameter startHour; 311 312 /** The end hour and minutes, e.g., 1845. */ 313 public PortParameter endHour; 314 315 /** The number of minutes between observations. */ 316 public PortParameter observationIncrement; 317 318 /** The 20ft wind speed in mph. */ 319 public PortParameter speed; 320 321 /** The wind direction, specified in degrees clockwise from north. Set to 322 * -1 to indicate up slope, -2 to indicate down slope. 323 */ 324 public PortParameter direction; 325 326 /** Percentage of cloud cover. */ 327 public PortParameter cloudCover; 328 329 /** The name of the output file. */ 330 public PortParameter file; 331 332 /** The name of the output file. */ 333 public TypedIOPort out; 334}