256 lines
14 KiB
Python
256 lines
14 KiB
Python
# ----------------------------------------------------------------------------
|
|
# This software is in the public domain, furnished "as is", without technical
|
|
# support, and with no warranty, express or implied, as to its usefulness for
|
|
# any purpose.
|
|
#
|
|
# Run_NWPS
|
|
# Description: AWIPS 2 Version 16.4.1
|
|
#
|
|
# This runs a Procedure within the GFE that builds NWPS
|
|
# forecast wind grids based on the operational wind forecast grids
|
|
# and then sends those Wind grids to the NWPS model.
|
|
#
|
|
# Authors: Pablo Santos, Alex Gibbs, and Joe Maloney.
|
|
#
|
|
# Last Modified: 01/23/15 by AG/PS for AWIPS Baseline.
|
|
# Last Modified: 09/10/15 by Joe Maloney/PS for mulitsite version of NWPS.
|
|
# Last Modified: 10/14/15 by Joe Maloney/PS to remove dependancy on cron. Totally on demand by user.
|
|
# This means baseline cron entry for nwps will be removed with 16.2.1
|
|
# Last Modified: 10/30/15 by Joe Maloney, added -q flags to scp/ssh at end.
|
|
# Last Modified: 11/25/15 by Tom LeFebvre, added switch to run tool from a cron or interactively.
|
|
# Last Modified: 11/29/15 by P. Santos, completed adding code to enable running Run_NWPS interactively or from a cron.
|
|
# Last modified: 03/18/16 by Joe Maloney, a minor tweak to runManualNWPS_OutsideAWIPS call.
|
|
# Last modified: 04/14/16 by T. LeFebvre/P. Santos, for wind inventory check.
|
|
# Last modified: 07/18/2016 by J. Maloney/P. Santos, post 16.4.1 code review.
|
|
#
|
|
# ----------------------------------------------------------------------------
|
|
#
|
|
# The MenuItems list defines the GFE menu item(s) under which the
|
|
# Procedure is to appear. Possible items are: Populate, Edit, Consistency,
|
|
# Verify, Hazards
|
|
|
|
MenuItems = ["Edit"]
|
|
import SmartScript, LogStream
|
|
import time, os, shutil, TimeRange, AbsTime
|
|
import ProcessVariableList
|
|
|
|
class Procedure (SmartScript.SmartScript):
|
|
def __init__(self, dbss):
|
|
SmartScript.SmartScript.__init__(self, dbss)
|
|
|
|
def fileNameFromIntTime(self, floatTime):
|
|
tupleTime = time.gmtime(floatTime)
|
|
# print "TUPLETIME IS: ", tupleTime
|
|
return time.strftime("%Y%m%d_%H00", tupleTime)
|
|
|
|
def getButtonNames(self):
|
|
|
|
#currentTime = int(time.time() / 3600) * 3600 # truncated to this hour
|
|
currentTime = (self._gmtime().unixTime()/3600)*3600
|
|
#print "currentTime: ", currentTime
|
|
|
|
if time.gmtime(currentTime).tm_hour % 6 != 0:
|
|
currentTime = currentTime + (6 * 3600) # add three hours
|
|
|
|
startTime = int(currentTime / (6 * 3600)) * (6 * 3600)
|
|
#print "StartTime from GUI is: ", startTime
|
|
|
|
timeStrs = []
|
|
timeList = []
|
|
|
|
for i in range(0, 8):
|
|
currentTime = startTime + (6 * i) * 3600 - 108000 # 30 hrs
|
|
strTime = self.fileNameFromIntTime(currentTime)
|
|
timeList.append(currentTime)
|
|
timeStrs.append(strTime)
|
|
|
|
return timeStrs,timeList
|
|
|
|
def getModelTimeRange(self, modelID, param):
|
|
#before = time.time() - (3000 * 24 * 3600) # 3000 days ago. Does not work with DRT
|
|
#later = time.time() + 100 * 24 * 3600 # 100 days from now. Does not work with DRT
|
|
before = self._gmtime().unixTime() - (7 * 24 * 3600) # 7 days ago
|
|
later = self._gmtime().unixTime() + 8 * 24 * 3600 # 8 days from now
|
|
timeRange = TimeRange.TimeRange(AbsTime.AbsTime(before), AbsTime.AbsTime(later))
|
|
#self.deleteCmd(weNames, timeRange)
|
|
gridInfo = self.getGridInfo(modelID, param, "SFC", timeRange)
|
|
#print "GRIDINFO IS: ", modelID, gridInfo
|
|
if len(gridInfo) == 0:
|
|
self.statusBarMsg("No grids available for model:" + modelID, "S")
|
|
return None
|
|
|
|
minTime = later
|
|
maxTime = before
|
|
for g in gridInfo:
|
|
start = g.gridTime().startTime().unixTime()
|
|
end = g.gridTime().endTime().unixTime()
|
|
minTime = min(minTime,start)
|
|
maxTime = max(maxTime,end)
|
|
|
|
modelTR = TimeRange.TimeRange(AbsTime.AbsTime(minTime), AbsTime.AbsTime(maxTime))
|
|
#print "MODELTR", modelTR, minTime, maxTime
|
|
return modelTR, minTime, maxTime
|
|
|
|
def getWEInventory(self, WEName, dbase="Fcst", level="SFC",
|
|
timeRange=TimeRange.allTimes()):
|
|
"""Return a list of time ranges with available data for a field from
|
|
a specific database and level.
|
|
Args:
|
|
string WEName: name of field to inventory
|
|
string dbase: name of database to search (default = 'Fcst')
|
|
string level: level of data to inventory (default = 'SFC')
|
|
Returns:
|
|
Python list of Python time range objects
|
|
"""
|
|
|
|
# print "Getting inventory of -> '%s' from '%s' at '%s'" % \
|
|
# (WEName, dbase, level)
|
|
|
|
trList = []
|
|
# getGridInfo will just die if the modelName or weName is not valid
|
|
# so wrap it in a try block and return [] if it fails
|
|
try:
|
|
gridInfo = self.getGridInfo(dbase, WEName, level, timeRange)
|
|
trList = [g.gridTime() for g in gridInfo]
|
|
except:
|
|
self.statusBarMsg("Problems retrieving wind grids", "S")
|
|
|
|
return trList
|
|
|
|
def execute(self, editArea, timeRange, varDict):
|
|
|
|
buttonList, timeList = self.getButtonNames()
|
|
GFEDomainname = self.getSiteID()
|
|
print "GFEDomain is: ", GFEDomainname
|
|
cron = True
|
|
|
|
if varDict is None: # This means the tool is being run interactively, so make the GUI.
|
|
|
|
variableList = [
|
|
("How Long Do You Want To Run NWPS:" , 102, "scale", [12, 102], 3),
|
|
#("NWPS Model Winds:", "ForecastWindGrids", "radio", ["ForecastWindGrids"]),
|
|
("Model Start Time:", buttonList[4], "radio", buttonList),
|
|
("Local, NCEP, or Both:", "NCEP", "radio", ["Local","NCEP","Both"]),
|
|
("Model Core:", "SWAN", "radio", ["SWAN","NWW","UNSWAN"]),
|
|
("Send Output to Web:", "Yes", "radio", ["Yes","No"]),
|
|
("Plot Output Only (No Web):", "No", "radio", ["Yes","No"]),
|
|
("Boundary Conditions:", "WNAWave", "radio", ["WNAWave", "TAFB-NWPS", "HURWave", "No"]),
|
|
("**Boundary Conditions: OPC/TAFB-NWPS: CHECK www.srh.noaa.gov/rtimages/nhc/wfo_boundary_conditions for up to date files for your SITE**\nNOTE: make sure there is a file time stamp online matching your selected Model Start Time","", "label"),
|
|
("Run Hi Res NEST:", "Yes", "radio", ["Yes","No"]),
|
|
("RTOFS Currents:", "Yes", "radio", ["Yes","No"]),
|
|
("Model Time Step:", "600", "radio", ["1200","900","600","300"]),
|
|
("Hotstart:", "True", "radio", ["True", "False"]),
|
|
("Waterlevels:", "ESTOFS", "radio", ["ESTOFS","PSURGE", "No"]),
|
|
("If PSURGE\n% Exceedance Hgt:", "10", "radio", ["10", "20", "30", "40", "50"]),
|
|
]
|
|
|
|
varDict = {}
|
|
processVarList = ProcessVariableList.ProcessVariableList("Run_NWPS", variableList, varDict, None)
|
|
status = processVarList.status()
|
|
if status != "OK":
|
|
return
|
|
|
|
fcst_length = processVarList.varDict()["How Long Do You Want To Run NWPS:"]
|
|
fcstlength = str(fcst_length)
|
|
wind="ForecastWindGrids"
|
|
modelstarttime = processVarList.varDict()["Model Start Time:"]
|
|
wheretorun = processVarList.varDict()["Local, NCEP, or Both:"]
|
|
model = processVarList.varDict()["Model Core:"]
|
|
web = processVarList.varDict()["Send Output to Web:"]
|
|
plot = processVarList.varDict()["Plot Output Only (No Web):"]
|
|
wna = processVarList.varDict()["Boundary Conditions:"]
|
|
nest = processVarList.varDict()["Run Hi Res NEST:"]
|
|
gstream = processVarList.varDict()["RTOFS Currents:"]
|
|
tstep = processVarList.varDict()["Model Time Step:"]
|
|
hotstart = processVarList.varDict()["Hotstart:"]
|
|
waterlevels = processVarList.varDict()["Waterlevels:"]
|
|
excd = processVarList.varDict()["If PSURGE\n% Exceedance Hgt:"]
|
|
cron = False
|
|
# end interactive GUI portion
|
|
|
|
else:
|
|
|
|
# This part of if else statement assumes procedure is being run from command
|
|
#line with variable list passed on using the -V option to runProcedure. This
|
|
#allows to run procedure from a cron. Example default for runProcedure would be:
|
|
# All variables shown below passed with -V option are required for procedure to run properly.
|
|
# /awips2/GFESuite/bin/runProcedure -n Run_NWPS -c gfeConfig
|
|
# -V '{"fcstlength":"102","wind":"ForecastWindGrids","wheretorun":"NCEP","model":"SWAN","web":"Yes","plot":"Yes","wna":"WNAWave","nest":"Yes","gstream":"Yes","tstep":"600","hotstart":"True","waterlevels":"ESTOFS","excd":"10"}'
|
|
# If running from a cron, you do not need to create a SITE level override of this baseline procedure if your input variables
|
|
# are different because you pass that on from the command line.
|
|
|
|
modelstarttime = buttonList[4]
|
|
fcstlength = varDict['fcstlength']
|
|
wind = varDict['wind']
|
|
wheretorun = varDict['wheretorun']
|
|
model = varDict['model']
|
|
web = varDict['web']
|
|
plot = varDict['plot']
|
|
wna = varDict['wna']
|
|
nest = varDict['nest']
|
|
gstream = varDict['gstream']
|
|
tstep = varDict['tstep']
|
|
hotstart = varDict['hotstart']
|
|
waterlevels = varDict['waterlevels']
|
|
excd = varDict['excd']
|
|
|
|
modelTR = self.getModelTimeRange("Fcst", "Wind")
|
|
startHour = modelTR[1]
|
|
endHour = modelTR[2]
|
|
timeRange = modelTR[0]
|
|
|
|
if (modelstarttime == buttonList[0]):
|
|
starttime=timeList[0]
|
|
elif (modelstarttime == buttonList[1]):
|
|
starttime=timeList[1]
|
|
elif (modelstarttime == buttonList[2]):
|
|
starttime=timeList[2]
|
|
elif (modelstarttime == buttonList[3]):
|
|
starttime=timeList[3]
|
|
elif (modelstarttime == buttonList[4]):
|
|
starttime=timeList[4]
|
|
elif (modelstarttime == buttonList[5]):
|
|
starttime=timeList[5]
|
|
elif (modelstarttime == buttonList[6]):
|
|
starttime=timeList[6]
|
|
else:
|
|
starttime=startHour # Model start Hour if all others empty
|
|
|
|
if (startHour > starttime):
|
|
starttime = startHour
|
|
|
|
timeRange1 = TimeRange.TimeRange(AbsTime.AbsTime(starttime - 7*24*3600), AbsTime.AbsTime(starttime + 8*24*3600))
|
|
timeRange2 = TimeRange.TimeRange(AbsTime.AbsTime(starttime), AbsTime.AbsTime(starttime + 8*24*3600))
|
|
|
|
self.deleteCmd(['NWPSwind'], timeRange1)
|
|
databaseID = self.findDatabase("Fcst")
|
|
self.copyToCmd([('Wind', 'NWPSwind')], databaseID, timeRange2)
|
|
self.fragmentCmd(['NWPSwind'], timeRange2)
|
|
self.saveElements(["NWPSwind"])
|
|
|
|
trList = self.getWEInventory("NWPSwind")
|
|
if len(trList) < 120:
|
|
self.statusBarMsg("Not enough Wind grids. You need at least 120 hours.", "S")
|
|
return
|
|
|
|
inp_args = fcstlength + ":" + wna + ":" + nest + ":" + gstream + ":" + wind + ":" + web + ":" + plot + ":" + tstep + ":" + hotstart + ":" + waterlevels + ":" + model + ":" + excd + ":" + wheretorun
|
|
|
|
try:
|
|
os.stat('/tmp/nwps/'+GFEDomainname)
|
|
except:
|
|
os.makedirs('/tmp/nwps/'+GFEDomainname)
|
|
os.chmod('/tmp/nwps/'+GFEDomainname,0o775)
|
|
|
|
with open('/tmp/nwps/'+GFEDomainname+'/inp_args', 'w') as f:
|
|
f.write(inp_args)
|
|
os.chmod('/tmp/nwps/'+GFEDomainname+'/inp_args',0o666)
|
|
|
|
os.system('ssh -q px2f mkdir -p /awips2/GFESuite/nwps/'+GFEDomainname+'_var')
|
|
os.system('ssh -q px2f chmod 775 /awips2/GFESuite/nwps/'+GFEDomainname+'_var')
|
|
os.system('scp -rpq /tmp/nwps/'+GFEDomainname+'/inp_args px2f:/awips2/GFESuite/nwps/'+GFEDomainname+'_var/')
|
|
if cron:
|
|
os.system('ssh -q px2f /awips2/GFESuite/nwps/bin/runManualNWPS_OutsideAWIPS.sh '+GFEDomainname)
|
|
else:
|
|
os.system('nohup xterm -iconic -e ssh -q px2f /awips2/GFESuite/nwps/bin/runManualNWPS_OutsideAWIPS.sh '+GFEDomainname+' &')
|
|
#ORIG#os.system('xterm -e ssh -q px2f /awips2/GFESuite/nwps/bin/runManualNWPS_OutsideAWIPS.sh '+GFEDomainname)
|
|
shutil.rmtree('/tmp/nwps/'+GFEDomainname)
|