コード例 #1
0
def run(modelDir, inputDict):
	try:
		''' Run the model in its directory. '''
		# Check whether model exist or not
		if not os.path.isdir(modelDir):
			os.makedirs(modelDir)
			inputDict["created"] = str(dt.now())
		# MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
		with open(pJoin(modelDir, "allInputData.json"),"w") as inputFile:
			json.dump(inputDict, inputFile, indent = 4)
		# Copy spcific climate data into model directory
		inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"])
		shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
			pJoin(modelDir, "climate.tmy2"))
		# Ready to run
		startTime = dt.now()
		# Set up SAM data structures.
		ssc = nrelsam2013.SSCAPI()
		dat = ssc.ssc_data_create()
		# Required user inputs.
		ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
		ssc.ssc_data_set_number(dat, "system_size", float(inputDict["SystemSize"]))
		# SAM options where we take defaults.
		ssc.ssc_data_set_number(dat, "derate", 0.97)
		ssc.ssc_data_set_number(dat, "track_mode", 0)
		ssc.ssc_data_set_number(dat, "azimuth", 180)
		ssc.ssc_data_set_number(dat, "tilt_eq_lat", 1)
		# Run PV system simulation.
		mod = ssc.ssc_module_create("pvwattsv1")
		ssc.ssc_module_exec(mod, dat)
		# Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html
		startDateTime = "2013-01-01 00:00:00 UTC"
		# Timestamp output.
		outData = {}
		outData["timeStamps"] = [dt.strftime(
			dt.strptime(startDateTime[0:19],"%Y-%m-%d %H:%M:%S") +
			td(**{"hours":x}),"%Y-%m-%d %H:%M:%S") + " UTC" for x in range(int(8760))]
		# HACK: makes it easier to calculate some things later.
		outData["pythonTimeStamps"] = [dt(2012,1,1,0) + x*td(hours=1) for x in range(8760)]
		# Geodata output.
		outData["city"] = ssc.ssc_data_get_string(dat, "city")
		outData["state"] = ssc.ssc_data_get_string(dat, "state")
		outData["lat"] = ssc.ssc_data_get_number(dat, "lat")
		outData["lon"] = ssc.ssc_data_get_number(dat, "lon")
		outData["elev"] = ssc.ssc_data_get_number(dat, "elev")
		# Weather output.
		outData["climate"] = {}
		outData["climate"]["Global Horizontal Radiation (W/m^2)"] = ssc.ssc_data_get_array(dat, "gh")
		outData["climate"]["Plane of Array Irradiance (W/m^2)"] = ssc.ssc_data_get_array(dat, "poa")
		outData["climate"]["Ambient Temperature (F)"] = ssc.ssc_data_get_array(dat, "tamb")
		outData["climate"]["Cell Temperature (F)"] = ssc.ssc_data_get_array(dat, "tcell")
		outData["climate"]["Wind Speed (m/s)"] = ssc.ssc_data_get_array(dat, "wspd")
		# Power generation.
		outData["powerOutputAc"] = ssc.ssc_data_get_array(dat, "ac")

		# TODO: INSERT TJ CODE BELOW
		tjCode(inputDict, outData)
		del outData["pythonTimeStamps"]
		# TODO: INSERT TJ CODE ABOVE

		# Stdout/stderr.
		outData["stdout"] = "Success"
		outData["stderr"] = ""
		# Write the output.
		with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile:
			json.dump(outData, outFile, indent=4)
		# Update the runTime in the input file.
		endTime = dt.now()
		inputDict["runTime"] = str(td(seconds=int((endTime - startTime).total_seconds())))
		with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
			json.dump(inputDict, inFile, indent=4)
	except:
		# If input range wasn't valid delete output, write error to disk.
		cancel(modelDir)
		thisErr = traceback.format_exc()
		print 'ERROR IN MODEL', modelDir, thisErr
		inputDict['stderr'] = thisErr
		with open(os.path.join(modelDir,'stderr.txt'),'w') as errorFile:
			errorFile.write(thisErr)
		with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
			json.dump(inputDict, inFile, indent=4)
コード例 #2
0
ファイル: pvWatts.py プロジェクト: pgtariq/omf
	''' Run the model in its directory. '''
	# Delete output file every run if it exists
	try:
		os.remove(pJoin(modelDir,"allOutputData.json"))	
	except Exception, e:
		pass
	# Check whether model exist or not
	try:
		if not os.path.isdir(modelDir):
			os.makedirs(modelDir)
			inputDict["created"] = str(datetime.datetime.now())
		# MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
		with open(pJoin(modelDir, "allInputData.json"),"w") as inputFile:
			json.dump(inputDict, inputFile, indent = 4)
		# Copy spcific climate data into model directory
		inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"])
		shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"), 
			pJoin(modelDir, "climate.tmy2"))
		# Ready to run
		startTime = datetime.datetime.now()
		# Set up SAM data structures.
		ssc = nrelsam2013.SSCAPI()
		dat = ssc.ssc_data_create()
		# Required user inputs.
		ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
		ssc.ssc_data_set_number(dat, "system_size", float(inputDict["systemSize"]))
		ssc.ssc_data_set_number(dat, "derate", 0.01 * float(inputDict["nonInverterEfficiency"]))
		ssc.ssc_data_set_number(dat, "track_mode", float(inputDict["trackingMode"]))
		ssc.ssc_data_set_number(dat, "azimuth", float(inputDict["azimuth"]))
		# Advanced inputs with defaults.
		if (inputDict.get("tilt",0) == "-"):
コード例 #3
0
def runForeground(modelDir, inputDict):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	# Check whether model exist or not
	if not os.path.isdir(modelDir):
		os.makedirs(modelDir)
		inputDict["created"] = str(datetime.datetime.now())
	print "STARTING TO RUN", modelDir
	beginTime = datetime.datetime.now()
	feederList = []
	# Get prepare of data and clean workspace if re-run, If re-run remove all the data in the subfolders
	for dirs in os.listdir(modelDir):
		if os.path.isdir(pJoin(modelDir, dirs)):
			shutil.rmtree(pJoin(modelDir, dirs))
	# Get each feeder, prepare data in separate folders, and run there.
	for key in sorted(inputDict, key=inputDict.get):
		if key.startswith("feederName"):
			feederName = inputDict[key]
			feederList.append(feederName)
			try:
				os.remove(pJoin(modelDir, feederName, "allOutputData.json"))
			except Exception, e:
				pass
			if not os.path.isdir(pJoin(modelDir, feederName)):
				os.makedirs(pJoin(modelDir, feederName)) # create subfolders for feeders
			shutil.copy(pJoin(modelDir, feederName + ".omd"),
				pJoin(modelDir, feederName, "feeder.omd"))
			inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"])
			shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
				pJoin(modelDir, feederName, "climate.tmy2"))
			try:
				startTime = datetime.datetime.now()
				feederJson = json.load(open(pJoin(modelDir, feederName, "feeder.omd")))
				tree = feederJson["tree"]
				# Set up GLM with correct time and recorders:
				feeder.attachRecorders(tree, "Regulator", "object", "regulator")
				feeder.attachRecorders(tree, "Capacitor", "object", "capacitor")
				feeder.attachRecorders(tree, "Inverter", "object", "inverter")
				feeder.attachRecorders(tree, "Windmill", "object", "windturb_dg")
				feeder.attachRecorders(tree, "CollectorVoltage", None, None)
				feeder.attachRecorders(tree, "Climate", "object", "climate")
				feeder.attachRecorders(tree, "OverheadLosses", None, None)
				feeder.attachRecorders(tree, "UndergroundLosses", None, None)
				feeder.attachRecorders(tree, "TriplexLosses", None, None)
				feeder.attachRecorders(tree, "TransformerLosses", None, None)
				feeder.groupSwingKids(tree)
				feeder.adjustTime(tree=tree, simLength=float(inputDict["simLength"]),
					simLengthUnits=inputDict["simLengthUnits"], simStartDate=inputDict["simStartDate"])
				# RUN GRIDLABD IN FILESYSTEM (EXPENSIVE!)
				rawOut = gridlabd.runInFilesystem(tree, attachments=feederJson["attachments"],
					keepFiles=True, workDir=pJoin(modelDir, feederName))
				cleanOut = {}
				# Std Err and Std Out
				cleanOut['stderr'] = rawOut['stderr']
				cleanOut['stdout'] = rawOut['stdout']
				# Time Stamps
				for key in rawOut:
					if '# timestamp' in rawOut[key]:
						cleanOut['timeStamps'] = rawOut[key]['# timestamp']
						break
					elif '# property.. timestamp' in rawOut[key]:
						cleanOut['timeStamps'] = rawOut[key]['# property.. timestamp']
					else:
						cleanOut['timeStamps'] = []
				# Day/Month Aggregation Setup:
				stamps = cleanOut.get('timeStamps',[])
				level = inputDict.get('simLengthUnits','hours')
				# Climate
				for key in rawOut:
					if key.startswith('Climate_') and key.endswith('.csv'):
						cleanOut['climate'] = {}
						cleanOut['climate']['Rain Fall (in/h)'] = hdmAgg(rawOut[key].get('rainfall'), sum, level)
						cleanOut['climate']['Wind Speed (m/s)'] = hdmAgg(rawOut[key].get('wind_speed'), avg, level)
						cleanOut['climate']['Temperature (F)'] = hdmAgg(rawOut[key].get('temperature'), max, level)
						cleanOut['climate']['Snow Depth (in)'] = hdmAgg(rawOut[key].get('snowdepth'), max, level)
						cleanOut['climate']['Direct Insolation (W/m^2)'] = hdmAgg(rawOut[key].get('solar_direct'), sum, level)
				# Voltage Band
				if 'VoltageJiggle.csv' in rawOut:
					cleanOut['allMeterVoltages'] = {}
					cleanOut['allMeterVoltages']['Min'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['min(voltage_12.mag)']], min, level)
					cleanOut['allMeterVoltages']['Mean'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['mean(voltage_12.mag)']], avg, level)
					cleanOut['allMeterVoltages']['StdDev'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['std(voltage_12.mag)']], avg, level)
					cleanOut['allMeterVoltages']['Max'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['max(voltage_12.mag)']], max, level)
				cleanOut['allMeterVoltages']['stdDevPos'] = [(x+y/2) for x,y in zip(cleanOut['allMeterVoltages']['Mean'], cleanOut['allMeterVoltages']['StdDev'])]
				cleanOut['allMeterVoltages']['stdDevNeg'] = [(x-y/2) for x,y in zip(cleanOut['allMeterVoltages']['Mean'], cleanOut['allMeterVoltages']['StdDev'])]
				# Total # of meters
				count = 0
				with open(pJoin(modelDir, feederName, "feeder.omd")) as f:
					for line in f:
						if "\"objectType\": \"triplex_meter\"" in line:
							count+=1
				print "count=", count
				cleanOut['allMeterVoltages']['triplexMeterCount'] = float(count)
				# Power Consumption
				cleanOut['Consumption'] = {}
				# Set default value to be 0, avoiding missing value when computing Loads
				cleanOut['Consumption']['Power'] = [0] * int(inputDict["simLength"])
				cleanOut['Consumption']['Losses'] = [0] * int(inputDict["simLength"])
				cleanOut['Consumption']['DG'] = [0] * int(inputDict["simLength"])
				for key in rawOut:
					if key.startswith('SwingKids_') and key.endswith('.csv'):
						oneSwingPower = hdmAgg(vecPyth(rawOut[key]['sum(power_in.real)'],rawOut[key]['sum(power_in.imag)']), avg, level)
						if 'Power' not in cleanOut['Consumption']:
							cleanOut['Consumption']['Power'] = oneSwingPower
						else:
							cleanOut['Consumption']['Power'] = vecSum(oneSwingPower,cleanOut['Consumption']['Power'])
					elif key.startswith('Inverter_') and key.endswith('.csv'):
						realA = rawOut[key]['power_A.real']
						realB = rawOut[key]['power_B.real']
						realC = rawOut[key]['power_C.real']
						imagA = rawOut[key]['power_A.imag']
						imagB = rawOut[key]['power_B.imag']
						imagC = rawOut[key]['power_C.imag']
						oneDgPower = hdmAgg(vecSum(vecPyth(realA,imagA),vecPyth(realB,imagB),vecPyth(realC,imagC)), avg, level)
						if 'DG' not in cleanOut['Consumption']:
							cleanOut['Consumption']['DG'] = oneDgPower
						else:
							cleanOut['Consumption']['DG'] = vecSum(oneDgPower,cleanOut['Consumption']['DG'])
					elif key.startswith('Windmill_') and key.endswith('.csv'):
						vrA = rawOut[key]['voltage_A.real']
						vrB = rawOut[key]['voltage_B.real']
						vrC = rawOut[key]['voltage_C.real']
						viA = rawOut[key]['voltage_A.imag']
						viB = rawOut[key]['voltage_B.imag']
						viC = rawOut[key]['voltage_C.imag']
						crB = rawOut[key]['current_B.real']
						crA = rawOut[key]['current_A.real']
						crC = rawOut[key]['current_C.real']
						ciA = rawOut[key]['current_A.imag']
						ciB = rawOut[key]['current_B.imag']
						ciC = rawOut[key]['current_C.imag']
						powerA = vecProd(vecPyth(vrA,viA),vecPyth(crA,ciA))
						powerB = vecProd(vecPyth(vrB,viB),vecPyth(crB,ciB))
						powerC = vecProd(vecPyth(vrC,viC),vecPyth(crC,ciC))
						# HACK: multiply by negative one because turbine power sign is opposite all other DG:
						oneDgPower = [-1.0 * x for x in hdmAgg(vecSum(powerA,powerB,powerC), avg, level)]
						if 'DG' not in cleanOut['Consumption']:
							cleanOut['Consumption']['DG'] = oneDgPower
						else:
							cleanOut['Consumption']['DG'] = vecSum(oneDgPower,cleanOut['Consumption']['DG'])
					elif key in ['OverheadLosses.csv', 'UndergroundLosses.csv', 'TriplexLosses.csv', 'TransformerLosses.csv']:
						realA = rawOut[key]['sum(power_losses_A.real)']
						imagA = rawOut[key]['sum(power_losses_A.imag)']
						realB = rawOut[key]['sum(power_losses_B.real)']
						imagB = rawOut[key]['sum(power_losses_B.imag)']
						realC = rawOut[key]['sum(power_losses_C.real)']
						imagC = rawOut[key]['sum(power_losses_C.imag)']
						oneLoss = hdmAgg(vecSum(vecPyth(realA,imagA),vecPyth(realB,imagB),vecPyth(realC,imagC)), avg, level)
						if 'Losses' not in cleanOut['Consumption']:
							cleanOut['Consumption']['Losses'] = oneLoss
						else:
							cleanOut['Consumption']['Losses'] = vecSum(oneLoss,cleanOut['Consumption']['Losses'])
				# Aggregate up the timestamps:
				if level=='days':
					cleanOut['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:10], 'days')
				elif level=='months':
					cleanOut['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:7], 'months')
				# Write the output.
				with open(pJoin(modelDir, feederName, "allOutputData.json"),"w") as outFile:
					json.dump(cleanOut, outFile, indent=4)
				# Update the runTime in the input file.
				endTime = datetime.datetime.now()
				inputDict["runTime"] = str(datetime.timedelta(seconds=int((endTime - startTime).total_seconds())))
				with open(pJoin(modelDir, feederName, "allInputData.json"),"w") as inFile:
					json.dump(inputDict, inFile, indent=4)
				# Clean up the PID file.
				os.remove(pJoin(modelDir, feederName,"PID.txt"))
				print "DONE RUNNING GRIDLABMULTI", modelDir, feederName
			except Exception as e:
				print "MODEL CRASHED GRIDLABMULTI", e, modelDir, feederName
				cancel(pJoin(modelDir, feederName))
				with open(pJoin(modelDir, feederName, "stderr.txt"), "a+") as stderrFile:
					traceback.print_exc(file = stderrFile)
コード例 #4
0
def runForeground(modelDir, inputDict):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	# Check whether model exist or not
	if not os.path.isdir(modelDir):
		os.makedirs(modelDir)
		inputDict["created"] = str(datetime.datetime.now())	
	print "STARTING TO RUN", modelDir
	beginTime = datetime.datetime.now()
	feederList = []
	# Get prepare of data and clean workspace if re-run, If re-run remove all the data in the subfolders
	for dirs in os.listdir(modelDir):
		if os.path.isdir(pJoin(modelDir, dirs)):
			shutil.rmtree(pJoin(modelDir, dirs))
	# Get each feeder, prepare data in separate folders, and run there.
	for key in sorted(inputDict, key=inputDict.get):
		if key.startswith("feederName"):
			feederDir, feederName = inputDict[key].split("___")
			feederList.append(feederName)
			try:
				os.remove(pJoin(modelDir, feederName, "allOutputData.json"))
			except Exception, e:
				pass
			if not os.path.isdir(pJoin(modelDir, feederName)):
				os.makedirs(pJoin(modelDir, feederName)) # create subfolders for feeders
			shutil.copy(pJoin(__metaModel__._omfDir, "data", "Feeder", feederDir, feederName + ".json"),
				pJoin(modelDir, feederName, "feeder.json"))
			inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"])			
			shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
				pJoin(modelDir, feederName, "climate.tmy2"))
			try:
				startTime = datetime.datetime.now()
				feederJson = json.load(open(pJoin(modelDir, feederName, "feeder.json")))
				tree = feederJson["tree"]
				# Set up GLM with correct time and recorders:
				feeder.attachRecorders(tree, "Regulator", "object", "regulator")
				feeder.attachRecorders(tree, "Capacitor", "object", "capacitor")
				feeder.attachRecorders(tree, "Inverter", "object", "inverter")
				feeder.attachRecorders(tree, "Windmill", "object", "windturb_dg")
				feeder.attachRecorders(tree, "CollectorVoltage", None, None)
				feeder.attachRecorders(tree, "Climate", "object", "climate")
				feeder.attachRecorders(tree, "OverheadLosses", None, None)
				feeder.attachRecorders(tree, "UndergroundLosses", None, None)
				feeder.attachRecorders(tree, "TriplexLosses", None, None)
				feeder.attachRecorders(tree, "TransformerLosses", None, None)
				feeder.groupSwingKids(tree)
				feeder.adjustTime(tree=tree, simLength=float(inputDict["simLength"]),
					simLengthUnits=inputDict["simLengthUnits"], simStartDate=inputDict["simStartDate"])
				# RUN GRIDLABD IN FILESYSTEM (EXPENSIVE!)
				rawOut = gridlabd.runInFilesystem(tree, attachments=feederJson["attachments"], 
					keepFiles=True, workDir=pJoin(modelDir, feederName))
				cleanOut = {}
				# Std Err and Std Out
				cleanOut['stderr'] = rawOut['stderr']
				cleanOut['stdout'] = rawOut['stdout']
				# Time Stamps
				for key in rawOut:
					if '# timestamp' in rawOut[key]:
						cleanOut['timeStamps'] = rawOut[key]['# timestamp']
						break
					elif '# property.. timestamp' in rawOut[key]:
						cleanOut['timeStamps'] = rawOut[key]['# property.. timestamp']
					else:
						cleanOut['timeStamps'] = []
				# Day/Month Aggregation Setup:
				stamps = cleanOut.get('timeStamps',[])
				level = inputDict.get('simLengthUnits','hours')
				# Climate
				for key in rawOut:
					if key.startswith('Climate_') and key.endswith('.csv'):
						cleanOut['climate'] = {}
						cleanOut['climate']['Rain Fall (in/h)'] = hdmAgg(rawOut[key].get('rainfall'), sum, level)
						cleanOut['climate']['Wind Speed (m/s)'] = hdmAgg(rawOut[key].get('wind_speed'), avg, level)
						cleanOut['climate']['Temperature (F)'] = hdmAgg(rawOut[key].get('temperature'), max, level)
						cleanOut['climate']['Snow Depth (in)'] = hdmAgg(rawOut[key].get('snowdepth'), max, level)
						cleanOut['climate']['Direct Insolation (W/m^2)'] = hdmAgg(rawOut[key].get('solar_direct'), sum, level)
				# Voltage Band
				if 'VoltageJiggle.csv' in rawOut:
					cleanOut['allMeterVoltages'] = {}
					cleanOut['allMeterVoltages']['Min'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['min(voltage_12.mag)']], min, level)
					cleanOut['allMeterVoltages']['Mean'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['mean(voltage_12.mag)']], avg, level)
					cleanOut['allMeterVoltages']['StdDev'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['std(voltage_12.mag)']], avg, level)
					cleanOut['allMeterVoltages']['Max'] = hdmAgg([(i / 2) for i in rawOut['VoltageJiggle.csv']['max(voltage_12.mag)']], max, level)
				cleanOut['allMeterVoltages']['stdDevPos'] = [(x+y/2) for x,y in zip(cleanOut['allMeterVoltages']['Mean'], cleanOut['allMeterVoltages']['StdDev'])]
				cleanOut['allMeterVoltages']['stdDevNeg'] = [(x-y/2) for x,y in zip(cleanOut['allMeterVoltages']['Mean'], cleanOut['allMeterVoltages']['StdDev'])]
				# Total # of meters
				count = 0
				with open(pJoin(modelDir, feederName, "feeder.json")) as f:
					for line in f:
						if "\"objectType\": \"triplex_meter\"" in line:
							count+=1
				print "count=", count
				cleanOut['allMeterVoltages']['triplexMeterCount'] = float(count)
				# Power Consumption
				cleanOut['Consumption'] = {}
				# Set default value to be 0, avoiding missing value when computing Loads
				cleanOut['Consumption']['Power'] = [0] * int(inputDict["simLength"])
				cleanOut['Consumption']['Losses'] = [0] * int(inputDict["simLength"])
				cleanOut['Consumption']['DG'] = [0] * int(inputDict["simLength"])
				for key in rawOut:
					if key.startswith('SwingKids_') and key.endswith('.csv'):
						oneSwingPower = hdmAgg(vecPyth(rawOut[key]['sum(power_in.real)'],rawOut[key]['sum(power_in.imag)']), avg, level)
						if 'Power' not in cleanOut['Consumption']:
							cleanOut['Consumption']['Power'] = oneSwingPower
						else:
							cleanOut['Consumption']['Power'] = vecSum(oneSwingPower,cleanOut['Consumption']['Power'])
					elif key.startswith('Inverter_') and key.endswith('.csv'):
						realA = rawOut[key]['power_A.real']
						realB = rawOut[key]['power_B.real']
						realC = rawOut[key]['power_C.real']
						imagA = rawOut[key]['power_A.imag']
						imagB = rawOut[key]['power_B.imag']
						imagC = rawOut[key]['power_C.imag']
						oneDgPower = hdmAgg(vecSum(vecPyth(realA,imagA),vecPyth(realB,imagB),vecPyth(realC,imagC)), avg, level)
						if 'DG' not in cleanOut['Consumption']:
							cleanOut['Consumption']['DG'] = oneDgPower
						else:
							cleanOut['Consumption']['DG'] = vecSum(oneDgPower,cleanOut['Consumption']['DG'])
					elif key.startswith('Windmill_') and key.endswith('.csv'):
						vrA = rawOut[key]['voltage_A.real']
						vrB = rawOut[key]['voltage_B.real']
						vrC = rawOut[key]['voltage_C.real']
						viA = rawOut[key]['voltage_A.imag']
						viB = rawOut[key]['voltage_B.imag']
						viC = rawOut[key]['voltage_C.imag']
						crB = rawOut[key]['current_B.real']
						crA = rawOut[key]['current_A.real']
						crC = rawOut[key]['current_C.real']
						ciA = rawOut[key]['current_A.imag']
						ciB = rawOut[key]['current_B.imag']
						ciC = rawOut[key]['current_C.imag']
						powerA = vecProd(vecPyth(vrA,viA),vecPyth(crA,ciA))
						powerB = vecProd(vecPyth(vrB,viB),vecPyth(crB,ciB))
						powerC = vecProd(vecPyth(vrC,viC),vecPyth(crC,ciC))
						# HACK: multiply by negative one because turbine power sign is opposite all other DG:
						oneDgPower = [-1.0 * x for x in hdmAgg(vecSum(powerA,powerB,powerC), avg, level)]
						if 'DG' not in cleanOut['Consumption']:
							cleanOut['Consumption']['DG'] = oneDgPower
						else:
							cleanOut['Consumption']['DG'] = vecSum(oneDgPower,cleanOut['Consumption']['DG'])
					elif key in ['OverheadLosses.csv', 'UndergroundLosses.csv', 'TriplexLosses.csv', 'TransformerLosses.csv']:
						realA = rawOut[key]['sum(power_losses_A.real)']
						imagA = rawOut[key]['sum(power_losses_A.imag)']
						realB = rawOut[key]['sum(power_losses_B.real)']
						imagB = rawOut[key]['sum(power_losses_B.imag)']
						realC = rawOut[key]['sum(power_losses_C.real)']
						imagC = rawOut[key]['sum(power_losses_C.imag)']
						oneLoss = hdmAgg(vecSum(vecPyth(realA,imagA),vecPyth(realB,imagB),vecPyth(realC,imagC)), avg, level)
						if 'Losses' not in cleanOut['Consumption']:
							cleanOut['Consumption']['Losses'] = oneLoss
						else:
							cleanOut['Consumption']['Losses'] = vecSum(oneLoss,cleanOut['Consumption']['Losses'])
				# Aggregate up the timestamps:
				if level=='days':
					cleanOut['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:10], 'days')
				elif level=='months':
					cleanOut['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:7], 'months')
				# Write the output.
				with open(pJoin(modelDir, feederName, "allOutputData.json"),"w") as outFile:
					json.dump(cleanOut, outFile, indent=4)
				# Update the runTime in the input file.
				endTime = datetime.datetime.now()
				inputDict["runTime"] = str(datetime.timedelta(seconds=int((endTime - startTime).total_seconds())))
				with open(pJoin(modelDir, feederName, "allInputData.json"),"w") as inFile:
					json.dump(inputDict, inFile, indent=4)
				# Clean up the PID file.
				os.remove(pJoin(modelDir, feederName,"PID.txt"))
				print "DONE RUNNING GRIDLABMULTI", modelDir, feederName
			except Exception as e:
				print "MODEL CRASHED GRIDLABMULTI", e, modelDir, feederName
				cancel(pJoin(modelDir, feederName))
				with open(pJoin(modelDir, feederName, "stderr.txt"), "a+") as stderrFile:
					traceback.print_exc(file = stderrFile)
コード例 #5
0
def run(modelDir, inputDict):
	try:
		''' Run the model in its directory. '''
		# Check whether model exist or not
		if not os.path.isdir(modelDir):
			os.makedirs(modelDir)
			inputDict["created"] = str(dt.datetime.now())
		# MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
		with open(pJoin(modelDir, "allInputData.json"),"w") as inputFile:
			json.dump(inputDict, inputFile, indent = 4)
		# Copy spcific climate data into model directory
		inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"])
		shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
			pJoin(modelDir, "climate.tmy2"))
		# Ready to run
		startTime = dt.datetime.now()
		# Set up SAM data structures.
		ssc = nrelsam2013.SSCAPI()
		dat = ssc.ssc_data_create()
		# Required user inputs.
		ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
		# TODO: FIX THIS!!!! IT SHOULD BE AVGSYS*PEN*RESCUSTOMERS
		ssc.ssc_data_set_number(dat, "system_size", float(inputDict["systemSize"]))
		# SAM options where we take defaults.
		ssc.ssc_data_set_number(dat, "derate", 0.97)
		ssc.ssc_data_set_number(dat, "track_mode", 0)
		ssc.ssc_data_set_number(dat, "azimuth", 180)
		ssc.ssc_data_set_number(dat, "tilt_eq_lat", 1)
		# Run PV system simulation.
		mod = ssc.ssc_module_create("pvwattsv1")
		ssc.ssc_module_exec(mod, dat)
		# Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html
		startDateTime = "2013-01-01 00:00:00 UTC"
		# Timestamp output.
		outData = {}
		outData["timeStamps"] = [dt.datetime.strftime(
			dt.datetime.strptime(startDateTime[0:19],"%Y-%m-%d %H:%M:%S") +
			dt.timedelta(**{"hours":x}),"%Y-%m-%d %H:%M:%S") + " UTC" for x in range(int(8760))]
		# Geodata output.
		outData["city"] = ssc.ssc_data_get_string(dat, "city")
		outData["state"] = ssc.ssc_data_get_string(dat, "state")
		outData["lat"] = ssc.ssc_data_get_number(dat, "lat")
		outData["lon"] = ssc.ssc_data_get_number(dat, "lon")
		outData["elev"] = ssc.ssc_data_get_number(dat, "elev")
		# Weather output.
		outData["climate"] = {}
		outData["climate"]["Global Horizontal Radiation (W/m^2)"] = ssc.ssc_data_get_array(dat, "gh")
		outData["climate"]["Plane of Array Irradiance (W/m^2)"] = ssc.ssc_data_get_array(dat, "poa")
		outData["climate"]["Ambient Temperature (F)"] = ssc.ssc_data_get_array(dat, "tamb")
		outData["climate"]["Cell Temperature (F)"] = ssc.ssc_data_get_array(dat, "tcell")
		outData["climate"]["Wind Speed (m/s)"] = ssc.ssc_data_get_array(dat, "wspd")
		# Power generation.
		outData["powerOutputAc"] = ssc.ssc_data_get_array(dat, "ac")
		# Monthly aggregation outputs.
		months = {"Jan":0,"Feb":1,"Mar":2,"Apr":3,"May":4,"Jun":5,"Jul":6,"Aug":7,"Sep":8,"Oct":9,"Nov":10,"Dec":11}
		totMonNum = lambda x:sum([z for (y,z) in zip(outData["timeStamps"], outData["powerOutputAc"]) if y.startswith(startDateTime[0:4] + "-{0:02d}".format(x+1))])
		outData["monthlyGeneration"] = [[a, roundSig(totMonNum(b),2)] for (a,b) in sorted(months.items(), key=lambda x:x[1])]
		monthlyNoConsumerServedSales = []
		monthlyKWhSold = []
		monthlyRevenue = []
		totalKWhSold = []
		totalRevenue = []
		for key in inputDict:
			# MAYBEFIX: data in list may not be ordered by month.
			if key.endswith("Sale"):
				monthlyNoConsumerServedSales.append([key[:3].title(),float(inputDict.get(key, 0))])
			elif key.endswith("KWh"):# the order of calculation matters
				monthlyKWhSold.append([key[:3].title(),float(inputDict.get(key, 0))])
			elif key.endswith("Rev"):
				monthlyRevenue.append([key[:3].title(),float(inputDict.get(key, 0))])
			elif key.endswith("KWhT"):
				totalKWhSold.append([key[:3].title(),float(inputDict.get(key, 0))])
			elif key.endswith("RevT"):
				totalRevenue.append([key[:3].title(),float(inputDict.get(key, 0))])
		outData["monthlyNoConsumerServedSales"] = sorted(monthlyNoConsumerServedSales, key=lambda x:months[x[0]])
		outData["monthlyKWhSold"] = sorted(monthlyKWhSold, key=lambda x:months[x[0]])
		outData["monthlyRevenue"] = sorted(monthlyRevenue, key=lambda x:months[x[0]])
		outData["totalKWhSold"] = sorted(totalKWhSold, key=lambda x:months[x[0]])
		outData["totalRevenue"] = sorted(totalRevenue, key=lambda x:months[x[0]])
		outData["totalGeneration"] = [[sorted(months.items(), key=lambda x:x[1])[i][0], outData["monthlyGeneration"][i][1]*outData["monthlyNoConsumerServedSales"][i][1]*(float(inputDict.get("resPenetration", 5))/100/1000)] for i in range(12)]
		outData["totalSolarSold"] = [[sorted(months.items(), key=lambda x:x[1])[i][0], outData["totalKWhSold"][i][1] - outData["totalGeneration"][i][1]] for i in range(12)]
		##################
		# TODO: add retailCost to the calculation.
		##################
		## Flow Diagram Calculations, and order of calculation matters
		# BAU case
		outData["BAU"] = {}
		# E23 = E11
		outData["BAU"]["totalKWhPurchased"] = float(inputDict.get("totalKWhPurchased", 1))
		# E24 = SUM(E19:P19)
		outData["BAU"]["totalKWhSales"] = sum([x[1] for x in totalKWhSold])
		# E25 = E23-E24
		outData["BAU"]["losses"] = float(inputDict.get("totalKWhPurchased", 0)) - sum([totalKWhSold[i][1] for i in range(12)])
		# E26 = E25/E23
		outData["BAU"]["effectiveLossRate"] = outData["BAU"]["losses"] / outData["BAU"]["totalKWhPurchased"]
		# E27 = 0
		outData["BAU"]["annualSolarGen"] = 0
		# E28 = SUM(E17:P17)
		outData["BAU"]["resNonSolarKWhSold"] = sum([monthlyKWhSold[i][1] for i in range(12)])
		# E29 = 0
		outData["BAU"]["solarResDemand"] = 0
		# E30 = 0
		outData["BAU"]["solarResSold"] = 0
		# E31 = E24-E28
		outData["BAU"]["nonResKWhSold"] = outData["BAU"]["totalKWhSales"] - outData["BAU"]["resNonSolarKWhSold"]
		# E32 = 0
		outData["BAU"]["costSolarGen"] = 0
		# E33 = SUM(E20:P20)-SUM(E18:P18)+E10
		outData["BAU"]["nonResRev"] = sum([totalRevenue[i][1] for i in range(12)]) - sum([monthlyRevenue[i][1] for i in range(12)]) + float(inputDict.get("otherElecRevenue"))
		# E34 = (SUM(E18:P18)-SUM(E16:P16)*E6)/SUM(E17:P17)
		outData["BAU"]["effectiveResRate"] = (sum ([monthlyRevenue[i][1] for i in range(12)]) - sum([monthlyNoConsumerServedSales[i][1] for i in range(12)])*float(inputDict.get("customServiceCharge", 0)))/sum([monthlyKWhSold[i][1] for i in range(12)])
		# E35 = E34*E28+SUM(E16:P16)*E6
		outData["BAU"]["resNonSolarRev"] = outData["BAU"]["effectiveResRate"] * outData["BAU"]["resNonSolarKWhSold"] + sum([monthlyNoConsumerServedSales[i][1] for i in range(12)])*float(inputDict.get("customServiceCharge", 0))
		# E36 = E30*E34
		outData["BAU"]["solarResRev"] = 0
		# E37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71), update after Form 7 model
		outData["BAU"]["nonPowerCosts"] = 0
		# E38 = E23-E25-E28-E30-E31
		outData["BAU"]["energyAllBal"] = 0
		# E39 = E36+E33+E35-E47-E72-E37
		outData["BAU"]["dollarAllBal"] = 0
		# E40 = 0
		outData["BAU"]["avgMonthlyBillSolarCus"] = 0
		# E41 = E35/SUM(E16:P16)
		avgCustomerCount = (sum([monthlyNoConsumerServedSales[i][1] for i in range(12)])/12)
		outData["BAU"]["avgMonthlyBillNonSolarCus"] = outData["BAU"]["resNonSolarRev"] / sum([monthlyNoConsumerServedSales[i][1] for i in range(12)])
		# E42 = E63/E24, update after Form 7 model
		outData["BAU"]["costofService"] = 0
		# Solar case
		outData["Solar"] = {}
		# F27 = SUM(E15:P15)
		outData["Solar"]["annualSolarGen"] = sum([outData["totalGeneration"][i][1] for i in range(12)])
		# F24 = E24-F27
		outData["Solar"]["totalKWhSales"] = sum([totalKWhSold[i][1] for i in range(12)]) - outData["Solar"]["annualSolarGen"]
		# F23 =F24/(1-E26)
		outData["Solar"]["totalKWhPurchased"] = outData["Solar"]["totalKWhSales"]/ (1-outData["BAU"]["effectiveLossRate"])
		outData["totalsolarmonthly"] = [[sorted(months.items(), key=lambda x:x[1])[i][0], outData["totalSolarSold"][i][1] / (1-outData["BAU"]["effectiveLossRate"])] for i in range(12)]
		# F25 = F23-F24
		outData["Solar"]["losses"] = (outData["Solar"]["totalKWhPurchased"] - outData["Solar"]["totalKWhSales"])
		# F26 = E26
		outData["Solar"]["effectiveLossRate"] = outData["BAU"]["effectiveLossRate"]
		# F28 = (1-E5)*E28
		outData["Solar"]["resNonSolarKWhSold"] = (1-float(inputDict.get("resPenetration", 0))/100)*outData["BAU"]["resNonSolarKWhSold"]
		# F29 = E5*E28
		outData["Solar"]["solarResDemand"] = float(inputDict.get("resPenetration", 0))/100*outData["BAU"]["resNonSolarKWhSold"]
		# F30 = F29-F27
		outData["Solar"]["solarResSold"] = outData["Solar"]["solarResDemand"] - outData["Solar"]["annualSolarGen"]
		# F31 = E31
		outData["Solar"]["nonResKWhSold"] = outData["BAU"]["nonResKWhSold"]
		# F32 = E9*F27
		outData["Solar"]["costSolarGen"] = float(inputDict.get("solarLCoE", 0.07))*outData["Solar"]["annualSolarGen"]
		# F33 = E33
		outData["Solar"]["nonResRev"] = outData["BAU"]["nonResRev"]
		# F34 = E34
		outData["Solar"]["effectiveResRate"] = outData["BAU"]["effectiveResRate"]
		# F35 = E35*(1-E5)
		outData["Solar"]["resNonSolarRev"] = outData["BAU"]["resNonSolarRev"] * (1 - float(inputDict.get("resPenetration", 0.05))/100)
		# F30*E34 = Solar revenue from selling at residential rate
		solarSoldRateRev = outData["Solar"]["solarResSold"] * outData["Solar"]["effectiveResRate"]
		# (E6+E7)*SUM(E16:P16)*E5 = Solar revenue from charges
		solarChargesRev = (float(inputDict.get("customServiceCharge", 0))+float(inputDict.get("solarServiceCharge", 0)))*sum([monthlyNoConsumerServedSales[i][1] for i in range(12)])*float(inputDict.get("resPenetration", 0.05))/100
		# F36 = F30*E34+(E6+E7)*SUM(E16:P16)*E5 = solarSoldRate + solarChargesRev
		outData["Solar"]["solarResRev"] = solarSoldRateRev + solarChargesRev
		# F37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71) = E37, update after Form 7 model
		outData["Solar"]["nonPowerCosts"] = 0
		# F38 = F23-F25-F28-F30-E31
		outData["Solar"]["energyAllBal"] = 0
		# F39 = F36+E33+F35-F47-F72-E37
		outData["Solar"]["dollarAllBal"] = 0
		if (float(inputDict.get("resPenetration", 0.05)) > 0):
			# F41 = (F35)/(SUM(E16:P16)*(1-E5))
			outData["Solar"]["avgMonthlyBillNonSolarCus"] = outData["Solar"]["resNonSolarRev"] / (sum([monthlyNoConsumerServedSales[i][1] for i in range(12)])* (1 - float(inputDict.get("resPenetration", 0.05))/100))
			# F42 = F30*E34/(SUM(E16:P16)*E5)+E6+E7
			outData["Solar"]["avgMonthlyBillSolarCus"] = outData["Solar"]["solarResSold"] * outData["BAU"]["effectiveResRate"] / (sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) * float(inputDict.get("resPenetration", 0.05))/100) + float(inputDict.get("customServiceCharge", 0))+float(inputDict.get("solarServiceCharge", 0))
			# F43 = (F27/(SUM(E16:P16)*E5))*E9
			outData["Solar"]["avgMonthlyBillSolarSolarCus"] = (outData["Solar"]["annualSolarGen"] / (sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) * float(inputDict.get("resPenetration", 0.05))/100)) * float(inputDict.get("solarLCoE", 0.07))
		else:
			outData["Solar"]["avgMonthlyBillNonSolarCus"] = 0
			outData["Solar"]["avgMonthlyBillSolarCus"] = 0
			outData["Solar"]["avgMonthlyBillSolarSolarCus"] = 0
		# Net Average Monthly Bill
		avgMonthlyBillSolarNet = outData["Solar"]["avgMonthlyBillSolarCus"] + outData["Solar"]["avgMonthlyBillSolarSolarCus"]
		outData["Solar"]["avgMonthlyBillSolarCus"] = avgMonthlyBillSolarNet
		# F45 = F63/F24, update after Form 7 model
		outData["Solar"]["costofService"] = 0
		## Form 7 Model
		# E46
		outData["Solar"]["powerProExpense"] = outData["BAU"]["powerProExpense"] = float(inputDict.get("powerProExpense", 0))
		# E47 != F47
		outData["BAU"]["costPurchasedPower"] = float(inputDict.get("costPurchasedPower", 0))
		# E48
		outData["Solar"]["transExpense"] = outData["BAU"]["transExpense"] = float(inputDict.get("transExpense", 0))
		# E49
		outData["Solar"]["distriExpenseO"] = outData["BAU"]["distriExpenseO"] = float(inputDict.get("distriExpenseO", 0))
		# E50
		outData["Solar"]["distriExpenseM"] = outData["BAU"]["distriExpenseM"] = float(inputDict.get("distriExpenseM", 0))
		# E51
		outData["Solar"]["customerAccountExpense"] = outData["BAU"]["customerAccountExpense"] = float(inputDict.get("customerAccountExpense", 0))
		# E52
		outData["Solar"]["customerServiceExpense"] = outData["BAU"]["customerServiceExpense"] = float(inputDict.get("customerServiceExpense", 0))
		# E53
		outData["Solar"]["salesExpense"] = outData["BAU"]["salesExpense"] = float(inputDict.get("salesExpense", 0))
		# E54
		outData["Solar"]["adminGeneralExpense"] = outData["BAU"]["adminGeneralExpense"] = float(inputDict.get("adminGeneralExpense", 0))
		# E56
		outData["Solar"]["depreAmortiExpense"] = outData["BAU"]["depreAmortiExpense"] = float(inputDict.get("depreAmortiExpense", 0))
		# E57
		outData["Solar"]["taxExpensePG"] = outData["BAU"]["taxExpensePG"] = float(inputDict.get("taxExpensePG", 0))
		# E58
		outData["Solar"]["taxExpense"] = outData["BAU"]["taxExpense"] = float(inputDict.get("taxExpense", 0))
		# E59
		outData["Solar"]["interestLongTerm"] = outData["BAU"]["interestLongTerm"] = float(inputDict.get("interestLongTerm", 0))
		# E60
		outData["Solar"]["interestConstruction"] = outData["BAU"]["interestConstruction"] = float(inputDict.get("interestConstruction", 0))
		# E61
		outData["Solar"]["interestExpense"] = outData["BAU"]["interestExpense"] = float(inputDict.get("interestExpense", 0))
		# E62
		outData["Solar"]["otherDeductions"] = outData["BAU"]["otherDeductions"] = float(inputDict.get("otherDeductions", 0))
		# E65
		outData["Solar"]["nonOpMarginInterest"] = outData["BAU"]["nonOpMarginInterest"] = float(inputDict.get("nonOpMarginInterest", 0))
		# E66
		outData["Solar"]["fundsUsedConstruc"] = outData["BAU"]["fundsUsedConstruc"] = float(inputDict.get("fundsUsedConstruc", 0))
		# E67
		outData["Solar"]["incomeEquityInvest"] = outData["BAU"]["incomeEquityInvest"] = float(inputDict.get("incomeEquityInvest", 0))
		# E68
		outData["Solar"]["nonOpMarginOther"] = outData["BAU"]["nonOpMarginOther"] = float(inputDict.get("nonOpMarginOther", 0))
		# E69
		outData["Solar"]["genTransCapCredits"] = outData["BAU"]["genTransCapCredits"] = float(inputDict.get("genTransCapCredits", 0))
		# E70
		outData["Solar"]["otherCapCreditsPatroDivident"] = outData["BAU"]["otherCapCreditsPatroDivident"] = float(inputDict.get("otherCapCreditsPatroDivident", 0))
		# E71
		outData["Solar"]["extraItems"] = outData["BAU"]["extraItems"] = float(inputDict.get("extraItems", 0))
		# Calculation
		# E45 = SUM(E20:P20)+E10
		outData["BAU"]["operRevPatroCap"] = sum([totalRevenue[i][1] for i in range(12)])+float(inputDict.get("otherElecRevenue", 0))
		# E55 = SUM(E46:E54)
		outData["BAU"]["totalOMExpense"] = float(inputDict.get("powerProExpense")) \
			+ float(inputDict.get("costPurchasedPower")) \
			+ float(inputDict.get("transExpense")) \
			+ float(inputDict.get("distriExpenseO")) \
			+ float(inputDict.get("distriExpenseM")) \
			+ float(inputDict.get("customerAccountExpense")) \
			+ float(inputDict.get("customerServiceExpense")) \
			+ float(inputDict.get("salesExpense"))  \
			+ float(inputDict.get("adminGeneralExpense"))
		# E63 = SUM(E55:E62)
		outData["BAU"]["totalCostElecService"] = outData["BAU"]["totalOMExpense"] \
			+ float(inputDict.get("depreAmortiExpense"))\
			+ float(inputDict.get("taxExpensePG"))\
			+ float(inputDict.get("taxExpense"))\
			+ float(inputDict.get("interestLongTerm"))\
			+ float(inputDict.get("interestExpense"))\
			+ float(inputDict.get("interestConstruction"))\
			+ outData["BAU"]["otherDeductions"]
		# E64 = E45-E63
		outData["BAU"]["patCapOperMargins"] = outData["BAU"]["operRevPatroCap"] - outData["BAU"]["totalCostElecService"]
		# E72 = SUM(E64:E71)
		outData["BAU"]["patCapital"] = outData["BAU"]["patCapOperMargins"]\
			+ float(inputDict.get("nonOpMarginInterest"))\
			+ float(inputDict.get("fundsUsedConstruc"))\
			+ float(inputDict.get("incomeEquityInvest"))\
			+ float(inputDict.get("nonOpMarginOther"))\
			+ float(inputDict.get("genTransCapCredits"))\
			+ float(inputDict.get("otherCapCreditsPatroDivident"))\
			+ float(inputDict.get("extraItems"))
		# F48 = E48-F27*E34+SUM(E16:P16)*E5*E7
		outData["Solar"]["operRevPatroCap"] = outData["BAU"]["operRevPatroCap"] - outData["BAU"]["effectiveResRate"]*outData["Solar"]["annualSolarGen"] + sum([monthlyNoConsumerServedSales[i][1] for i in range(12)])*float(inputDict.get("resPenetration", 0.05))/100*float(inputDict.get("solarServiceCharge", 0))
		# F47 = (F23)*E8
		inputDict["costofPower"] = float(inputDict.get("costPurchasedPower", 0)) /  float(inputDict.get("totalKWhPurchased", 0))
		outData["Solar"]["costPurchasedPower"] = outData["Solar"]["totalKWhPurchased"] * float(inputDict.get("costofPower", 0))
		inputDict["costofPower"] = round(inputDict["costofPower"],3)
		# F55 = SUM(F46:F54)
		outData["Solar"]["totalOMExpense"] = outData["Solar"]["powerProExpense"]\
			+ outData["Solar"]["costPurchasedPower"]\
			+ outData["Solar"]["transExpense"]\
			+ outData["Solar"]["distriExpenseO"]\
			+ outData["Solar"]["distriExpenseM"]\
			+ outData["Solar"]["customerAccountExpense"]\
			+ outData["Solar"]["customerServiceExpense"]\
			+ outData["Solar"]["salesExpense"]\
			+ outData["Solar"]["adminGeneralExpense"]
		# F63 = E63
		outData["Solar"]["totalCostElecService"] = outData["Solar"]["totalOMExpense"]\
			+ outData["Solar"]["depreAmortiExpense"]\
			+ outData["Solar"]["taxExpensePG"]\
			+ outData["Solar"]["taxExpense"]\
			+ outData["Solar"]["interestLongTerm"]\
			+ outData["Solar"]["interestConstruction"]\
			+ outData["Solar"]["interestExpense"]\
			+ outData["Solar"]["otherDeductions"]
		# F64 = F45 - F63
		outData["Solar"]["patCapOperMargins"] = outData["Solar"]["operRevPatroCap"] - outData["Solar"]["totalCostElecService"]
		# F72 = SUM(F64:F71)
		outData["Solar"]["patCapital"] = outData["Solar"]["patCapOperMargins"]\
			+ outData["Solar"]["nonOpMarginInterest"]\
			+ outData["Solar"]["fundsUsedConstruc"]\
			+ outData["Solar"]["incomeEquityInvest"]\
			+ outData["Solar"]["nonOpMarginOther"]\
			+ outData["Solar"]["genTransCapCredits"]\
			+ outData["Solar"]["otherCapCreditsPatroDivident"]\
			+ outData["Solar"]["extraItems"]
		# E37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71), update after Form 7 model
		outData["BAU"]["nonPowerCosts"] = outData["BAU"]["transExpense"] \
			+ outData["BAU"]["distriExpenseO"] \
			+ outData["BAU"]["distriExpenseM"] \
			+ outData["BAU"]["customerAccountExpense"] \
			+ outData["BAU"]["customerServiceExpense"] \
			+ outData["BAU"]["salesExpense"] \
			+ outData["BAU"]["adminGeneralExpense"] \
			+ outData["BAU"]["depreAmortiExpense"] \
			+ outData["BAU"]["taxExpensePG"] \
			+ outData["BAU"]["taxExpense"] \
			+ outData["BAU"]["interestLongTerm"] \
			+ outData["BAU"]["interestConstruction"] \
			+ outData["BAU"]["interestExpense"] \
			+ outData["BAU"]["otherDeductions"] \
			- (outData["BAU"]["nonOpMarginInterest"] \
			+ outData["BAU"]["fundsUsedConstruc"] \
			+ outData["BAU"]["incomeEquityInvest"] \
			+ outData["BAU"]["nonOpMarginOther"] \
			+ outData["BAU"]["genTransCapCredits"] \
			+ outData["BAU"]["otherCapCreditsPatroDivident"] \
			+ outData["BAU"]["extraItems"])
		# E42 = E63/E24, update after Form 7 model
		outData["BAU"]["costofService"] = outData["BAU"]["totalCostElecService"] / outData["BAU"]["totalKWhSales"]
		# F37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71) = E37, update after Form 7 model
		outData["Solar"]["nonPowerCosts"] = outData["BAU"]["nonPowerCosts"]
		# F42 = F63/F24, update after Form 7 model
		outData["Solar"]["costofService"] = outData["Solar"]["totalCostElecService"] / outData["Solar"]["totalKWhSales"]
		# Stdout/stderr.
		outData["stdout"] = "Success"
		outData["stderr"] = ""
		# Write the output.
		with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile:
			json.dump(outData, outFile, indent=4)
		# Update the runTime in the input file.
		endTime = dt.datetime.now()
		inputDict["runTime"] = str(dt.timedelta(seconds=int((endTime - startTime).total_seconds())))
		with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
			json.dump(inputDict, inFile, indent=4)
	except:
		# If input range wasn't valid delete output, write error to disk.
		cancel(modelDir)
		thisErr = traceback.format_exc()
		print 'ERROR IN MODEL', modelDir, thisErr
		inputDict['stderr'] = thisErr
		with open(os.path.join(modelDir,'stderr.txt'),'w') as errorFile:
			errorFile.write(thisErr)
		with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
			json.dump(inputDict, inFile, indent=4)
コード例 #6
0
def heavyProcessing(modelDir, inputDict):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	print "STARTING TO RUN", modelDir
	beginTime = datetime.datetime.now()
	# Get feeder name and data in.
	try: os.mkdir(pJoin(modelDir,'gldContainer'))
	except: pass
	try:	
		feederName = inputDict["feederName1"]
		inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"])
		shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
			pJoin(modelDir, "gldContainer", "climate.tmy2"))
		startTime = datetime.datetime.now()
		feederJson = json.load(open(pJoin(modelDir, feederName+'.omd')))
		tree = feederJson["tree"]
		# Set up GLM with correct time and recorders:
		feeder.attachRecorders(tree, "Regulator", "object", "regulator")
		feeder.attachRecorders(tree, "Capacitor", "object", "capacitor")
		feeder.attachRecorders(tree, "Inverter", "object", "inverter")
		feeder.attachRecorders(tree, "Windmill", "object", "windturb_dg")
		feeder.attachRecorders(tree, "CollectorVoltage", None, None)
		feeder.attachRecorders(tree, "Climate", "object", "climate")
		feeder.attachRecorders(tree, "OverheadLosses", None, None)
		feeder.attachRecorders(tree, "UndergroundLosses", None, None)
		feeder.attachRecorders(tree, "TriplexLosses", None, None)
		feeder.attachRecorders(tree, "TransformerLosses", None, None)
		feeder.groupSwingKids(tree)
		# Attach recorders for system voltage map:
		stub = {'object':'group_recorder', 'group':'"class=node"', 'property':'voltage_A', 'interval':3600, 'file':'aVoltDump.csv'}
		for phase in ['A','B','C']:
			copyStub = dict(stub)
			copyStub['property'] = 'voltage_' + phase
			copyStub['file'] = phase.lower() + 'VoltDump.csv'
			tree[feeder.getMaxKey(tree) + 1] = copyStub
		feeder.adjustTime(tree=tree, simLength=float(inputDict["simLength"]),
			simLengthUnits=inputDict["simLengthUnits"], simStartDate=inputDict["simStartDate"])
		# RUN GRIDLABD IN FILESYSTEM (EXPENSIVE!)
		rawOut = gridlabd.runInFilesystem(tree, attachments=feederJson["attachments"], 
			keepFiles=True, workDir=pJoin(modelDir,'gldContainer'))
		cleanOut = {}
		# Std Err and Std Out
		cleanOut['stderr'] = rawOut['stderr']
		cleanOut['stdout'] = rawOut['stdout']
		# Time Stamps
		for key in rawOut:
			if '# timestamp' in rawOut[key]:
				cleanOut['timeStamps'] = rawOut[key]['# timestamp']
				break
			elif '# property.. timestamp' in rawOut[key]:
				cleanOut['timeStamps'] = rawOut[key]['# property.. timestamp']
			else:
				cleanOut['timeStamps'] = []
		# Day/Month Aggregation Setup:
		stamps = cleanOut.get('timeStamps',[])
		level = inputDict.get('simLengthUnits','hours')
		# Climate
		for key in rawOut:
			if key.startswith('Climate_') and key.endswith('.csv'):
				cleanOut['climate'] = {}
				cleanOut['climate']['Rain Fall (in/h)'] = hdmAgg(rawOut[key].get('rainfall'), sum, level)
				cleanOut['climate']['Wind Speed (m/s)'] = hdmAgg(rawOut[key].get('wind_speed'), avg, level)
				cleanOut['climate']['Temperature (F)'] = hdmAgg(rawOut[key].get('temperature'), max, level)
				cleanOut['climate']['Snow Depth (in)'] = hdmAgg(rawOut[key].get('snowdepth'), max, level)
				cleanOut['climate']['Direct Normal (W/sf)'] = hdmAgg(rawOut[key].get('solar_direct'), sum, level)
				#cleanOut['climate']['Global Horizontal (W/sf)'] = hdmAgg(rawOut[key].get('solar_global'), sum, level)	
				climateWbySFList= hdmAgg(rawOut[key].get('solar_global'), sum, level)
				#converting W/sf to W/sm
				climateWbySMList= [x*10.76392 for x in climateWbySFList]
				cleanOut['climate']['Global Horizontal (W/sm)']=climateWbySMList			
		# Voltage Band
		if 'VoltageJiggle.csv' in rawOut:
			cleanOut['allMeterVoltages'] = {}
			cleanOut['allMeterVoltages']['Min'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['min(voltage_12.mag)']], min, level)
			cleanOut['allMeterVoltages']['Mean'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['mean(voltage_12.mag)']], avg, level)
			cleanOut['allMeterVoltages']['StdDev'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['std(voltage_12.mag)']], avg, level)
			cleanOut['allMeterVoltages']['Max'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['max(voltage_12.mag)']], max, level)
		# Power Consumption
		cleanOut['Consumption'] = {}
		# Set default value to be 0, avoiding missing value when computing Loads
		cleanOut['Consumption']['Power'] = [0] * int(inputDict["simLength"])
		cleanOut['Consumption']['Losses'] = [0] * int(inputDict["simLength"])
		cleanOut['Consumption']['DG'] = [0] * int(inputDict["simLength"])
		for key in rawOut:
			if key.startswith('SwingKids_') and key.endswith('.csv'):
				oneSwingPower = hdmAgg(vecPyth(rawOut[key]['sum(power_in.real)'],rawOut[key]['sum(power_in.imag)']), avg, level)
				if 'Power' not in cleanOut['Consumption']:
					cleanOut['Consumption']['Power'] = oneSwingPower
				else:
					cleanOut['Consumption']['Power'] = vecSum(oneSwingPower,cleanOut['Consumption']['Power'])
			elif key.startswith('Inverter_') and key.endswith('.csv'): 	
				realA = rawOut[key]['power_A.real']
				realB = rawOut[key]['power_B.real']
				realC = rawOut[key]['power_C.real']
				imagA = rawOut[key]['power_A.imag']
				imagB = rawOut[key]['power_B.imag']
				imagC = rawOut[key]['power_C.imag']
				oneDgPower = hdmAgg(vecSum(vecPyth(realA,imagA),vecPyth(realB,imagB),vecPyth(realC,imagC)), avg, level)
				if 'DG' not in cleanOut['Consumption']:
					cleanOut['Consumption']['DG'] = oneDgPower
				else:
					cleanOut['Consumption']['DG'] = vecSum(oneDgPower,cleanOut['Consumption']['DG'])
			elif key.startswith('Windmill_') and key.endswith('.csv'):
				vrA = rawOut[key]['voltage_A.real']
				vrB = rawOut[key]['voltage_B.real']
				vrC = rawOut[key]['voltage_C.real']
				viA = rawOut[key]['voltage_A.imag']
				viB = rawOut[key]['voltage_B.imag']
				viC = rawOut[key]['voltage_C.imag']
				crB = rawOut[key]['current_B.real']
				crA = rawOut[key]['current_A.real']
				crC = rawOut[key]['current_C.real']
				ciA = rawOut[key]['current_A.imag']
				ciB = rawOut[key]['current_B.imag']
				ciC = rawOut[key]['current_C.imag']
				powerA = vecProd(vecPyth(vrA,viA),vecPyth(crA,ciA))
				powerB = vecProd(vecPyth(vrB,viB),vecPyth(crB,ciB))
				powerC = vecProd(vecPyth(vrC,viC),vecPyth(crC,ciC))
				oneDgPower = hdmAgg(vecSum(powerA,powerB,powerC), avg, level)
				if 'DG' not in cleanOut['Consumption']:
					cleanOut['Consumption']['DG'] = oneDgPower
				else:
					cleanOut['Consumption']['DG'] = vecSum(oneDgPower,cleanOut['Consumption']['DG'])
			elif key in ['OverheadLosses.csv', 'UndergroundLosses.csv', 'TriplexLosses.csv', 'TransformerLosses.csv']:
				realA = rawOut[key]['sum(power_losses_A.real)']
				imagA = rawOut[key]['sum(power_losses_A.imag)']
				realB = rawOut[key]['sum(power_losses_B.real)']
				imagB = rawOut[key]['sum(power_losses_B.imag)']
				realC = rawOut[key]['sum(power_losses_C.real)']
				imagC = rawOut[key]['sum(power_losses_C.imag)']
				oneLoss = hdmAgg(vecSum(vecPyth(realA,imagA),vecPyth(realB,imagB),vecPyth(realC,imagC)), avg, level)
				if 'Losses' not in cleanOut['Consumption']:
					cleanOut['Consumption']['Losses'] = oneLoss
				else:
					cleanOut['Consumption']['Losses'] = vecSum(oneLoss,cleanOut['Consumption']['Losses'])
			elif key.startswith('Regulator_') and key.endswith('.csv'):
				#split function to strip off .csv from filename and user rest of the file name as key. for example- Regulator_VR10.csv -> key would be Regulator_VR10
				regName=""
				regName = key
				newkey=regName.split(".")[0]
				cleanOut[newkey] ={}
				cleanOut[newkey]['RegTapA'] = [0] * int(inputDict["simLength"])
				cleanOut[newkey]['RegTapB'] = [0] * int(inputDict["simLength"])
				cleanOut[newkey]['RegTapC'] = [0] * int(inputDict["simLength"])
				cleanOut[newkey]['RegTapA'] = rawOut[key]['tap_A']
				cleanOut[newkey]['RegTapB'] = rawOut[key]['tap_B']
				cleanOut[newkey]['RegTapC'] = rawOut[key]['tap_C']
				cleanOut[newkey]['RegPhases'] = rawOut[key]['phases'][0]
			elif key.startswith('Capacitor_') and key.endswith('.csv'):
				capName=""
				capName = key
				newkey=capName.split(".")[0]
				cleanOut[newkey] ={}
				cleanOut[newkey]['Cap1A'] = [0] * int(inputDict["simLength"])
				cleanOut[newkey]['Cap1B'] = [0] * int(inputDict["simLength"])
				cleanOut[newkey]['Cap1C'] = [0] * int(inputDict["simLength"])
				cleanOut[newkey]['Cap1A'] = rawOut[key]['switchA']
				cleanOut[newkey]['Cap1B'] = rawOut[key]['switchB']
				cleanOut[newkey]['Cap1C'] = rawOut[key]['switchC']
				cleanOut[newkey]['CapPhases'] = rawOut[key]['phases'][0]
		# What percentage of our keys have lat lon data?
		latKeys = [tree[key]['latitude'] for key in tree if 'latitude' in tree[key]]
		latPerc = 1.0*len(latKeys)/len(tree)
		if latPerc < 0.25: doNeato = True
		else: doNeato = False
		# Generate the frames for the system voltage map time traveling chart.
		genTime = generateVoltChart(tree, rawOut, modelDir, neatoLayout=doNeato)
		cleanOut['genTime'] = genTime
		# Aggregate up the timestamps:
		if level=='days':
			cleanOut['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:10], 'days')
		elif level=='months':
			cleanOut['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:7], 'months')
		# Write the output.
		with open(pJoin(modelDir, "allOutputData.json"),"w") as outFile:
			json.dump(cleanOut, outFile, indent=4)
		# Update the runTime in the input file.
		endTime = datetime.datetime.now()
		inputDict["runTime"] = str(datetime.timedelta(seconds=int((endTime - startTime).total_seconds())))
		with open(pJoin(modelDir, "allInputData.json"),"w") as inFile:
			json.dump(inputDict, inFile, indent=4)
		# Clean up the PID file.
		os.remove(pJoin(modelDir, "gldContainer", "PID.txt"))
		print "DONE RUNNING", modelDir
	except Exception as e:
		# If input range wasn't valid delete output, write error to disk.
		cancel(modelDir)	
		thisErr = traceback.format_exc()
		print 'ERROR IN MODEL', modelDir, thisErr
		inputDict['stderr'] = thisErr
		with open(os.path.join(modelDir,'stderr.txt'),'w') as errorFile:
			errorFile.write(thisErr)
		with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
			json.dump(inputDict, inFile, indent=4)
	finishTime = datetime.datetime.now()
	inputDict["runTime"] = str(datetime.timedelta(seconds = int((finishTime - beginTime).total_seconds())))
	with open(pJoin(modelDir, "allInputData.json"),"w") as inFile:
		json.dump(inputDict, inFile, indent = 4)
	try:
		os.remove(pJoin(modelDir,"PPID.txt"))
	except:
		pass
コード例 #7
0
def run(modelDir, inputDict):
    try:
        ''' Run the model in its directory. '''
        # Check whether model exist or not
        if not os.path.isdir(modelDir):
            os.makedirs(modelDir)
            inputDict["created"] = str(dt.now())
        # MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
        with open(pJoin(modelDir, "allInputData.json"), "w") as inputFile:
            json.dump(inputDict, inputFile, indent=4)
        # Copy spcific climate data into model directory
        inputDict["climateName"], latforpvwatts = zipCodeToClimateName(
            inputDict["zipCode"])
        shutil.copy(
            pJoin(__metaModel__._omfDir, "data", "Climate",
                  inputDict["climateName"] + ".tmy2"),
            pJoin(modelDir, "climate.tmy2"))
        # Ready to run
        startTime = dt.now()
        # Set up SAM data structures.
        ssc = nrelsam2013.SSCAPI()
        dat = ssc.ssc_data_create()
        # Required user inputs.
        ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
        ssc.ssc_data_set_number(dat, "system_size",
                                float(inputDict["SystemSize"]))
        # SAM options where we take defaults.
        ssc.ssc_data_set_number(dat, "derate", 0.97)
        ssc.ssc_data_set_number(dat, "track_mode", 0)
        ssc.ssc_data_set_number(dat, "azimuth", 180)
        ssc.ssc_data_set_number(dat, "tilt_eq_lat", 1)
        # Run PV system simulation.
        mod = ssc.ssc_module_create("pvwattsv1")
        ssc.ssc_module_exec(mod, dat)
        # Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html
        startDateTime = "2013-01-01 00:00:00 UTC"
        # Timestamp output.
        outData = {}
        outData["timeStamps"] = [
            dt.strftime(
                dt.strptime(startDateTime[0:19], "%Y-%m-%d %H:%M:%S") +
                td(**{"hours": x}), "%Y-%m-%d %H:%M:%S") + " UTC"
            for x in range(int(8760))
        ]
        # HACK: makes it easier to calculate some things later.
        outData["pythonTimeStamps"] = [
            dt(2012, 1, 1, 0) + x * td(hours=1) for x in range(8760)
        ]
        # Geodata output.
        outData["city"] = ssc.ssc_data_get_string(dat, "city")
        outData["state"] = ssc.ssc_data_get_string(dat, "state")
        outData["lat"] = ssc.ssc_data_get_number(dat, "lat")
        outData["lon"] = ssc.ssc_data_get_number(dat, "lon")
        outData["elev"] = ssc.ssc_data_get_number(dat, "elev")
        # Weather output.
        outData["climate"] = {}
        outData["climate"][
            "Global Horizontal Radiation (W/m^2)"] = ssc.ssc_data_get_array(
                dat, "gh")
        outData["climate"][
            "Plane of Array Irradiance (W/m^2)"] = ssc.ssc_data_get_array(
                dat, "poa")
        outData["climate"]["Ambient Temperature (F)"] = ssc.ssc_data_get_array(
            dat, "tamb")
        outData["climate"]["Cell Temperature (F)"] = ssc.ssc_data_get_array(
            dat, "tcell")
        outData["climate"]["Wind Speed (m/s)"] = ssc.ssc_data_get_array(
            dat, "wspd")
        # Power generation.
        outData["powerOutputAc"] = ssc.ssc_data_get_array(dat, "ac")

        # TODO: INSERT TJ CODE BELOW
        tjCode(inputDict, outData)
        del outData["pythonTimeStamps"]
        # TODO: INSERT TJ CODE ABOVE

        # Stdout/stderr.
        outData["stdout"] = "Success"
        outData["stderr"] = ""
        # Write the output.
        with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
            json.dump(outData, outFile, indent=4)
        # Update the runTime in the input file.
        endTime = dt.now()
        inputDict["runTime"] = str(
            td(seconds=int((endTime - startTime).total_seconds())))
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inputDict, inFile, indent=4)
    except:
        # If input range wasn't valid delete output, write error to disk.
        cancel(modelDir)
        thisErr = traceback.format_exc()
        print 'ERROR IN MODEL', modelDir, thisErr
        inputDict['stderr'] = thisErr
        with open(os.path.join(modelDir, 'stderr.txt'), 'w') as errorFile:
            errorFile.write(thisErr)
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inputDict, inFile, indent=4)
コード例 #8
0
ファイル: solarRates.py プロジェクト: pgtariq/omf
def run(modelDir, inputDict):
    try:
        ''' Run the model in its directory. '''
        # Check whether model exist or not
        if not os.path.isdir(modelDir):
            os.makedirs(modelDir)
            inputDict["created"] = str(dt.datetime.now())
        # MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
        with open(pJoin(modelDir, "allInputData.json"), "w") as inputFile:
            json.dump(inputDict, inputFile, indent=4)
        # Copy spcific climate data into model directory
        inputDict["climateName"], latforpvwatts = zipCodeToClimateName(
            inputDict["zipCode"])
        shutil.copy(
            pJoin(__metaModel__._omfDir, "data", "Climate",
                  inputDict["climateName"] + ".tmy2"),
            pJoin(modelDir, "climate.tmy2"))
        # Ready to run
        startTime = dt.datetime.now()
        # Set up SAM data structures.
        ssc = nrelsam2013.SSCAPI()
        dat = ssc.ssc_data_create()
        # Required user inputs.
        ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
        # TODO: FIX THIS!!!! IT SHOULD BE AVGSYS*PEN*RESCUSTOMERS
        ssc.ssc_data_set_number(dat, "system_size",
                                float(inputDict["systemSize"]))
        # SAM options where we take defaults.
        ssc.ssc_data_set_number(dat, "derate", 0.97)
        ssc.ssc_data_set_number(dat, "track_mode", 0)
        ssc.ssc_data_set_number(dat, "azimuth", 180)
        ssc.ssc_data_set_number(dat, "tilt_eq_lat", 1)
        # Run PV system simulation.
        mod = ssc.ssc_module_create("pvwattsv1")
        ssc.ssc_module_exec(mod, dat)
        # Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html
        startDateTime = "2013-01-01 00:00:00 UTC"
        # Timestamp output.
        outData = {}
        outData["timeStamps"] = [
            dt.datetime.strftime(
                dt.datetime.strptime(startDateTime[0:19], "%Y-%m-%d %H:%M:%S")
                + dt.timedelta(**{"hours": x}), "%Y-%m-%d %H:%M:%S") + " UTC"
            for x in range(int(8760))
        ]
        # Geodata output.
        outData["city"] = ssc.ssc_data_get_string(dat, "city")
        outData["state"] = ssc.ssc_data_get_string(dat, "state")
        outData["lat"] = ssc.ssc_data_get_number(dat, "lat")
        outData["lon"] = ssc.ssc_data_get_number(dat, "lon")
        outData["elev"] = ssc.ssc_data_get_number(dat, "elev")
        # Weather output.
        outData["climate"] = {}
        outData["climate"][
            "Global Horizontal Radiation (W/m^2)"] = ssc.ssc_data_get_array(
                dat, "gh")
        outData["climate"][
            "Plane of Array Irradiance (W/m^2)"] = ssc.ssc_data_get_array(
                dat, "poa")
        outData["climate"]["Ambient Temperature (F)"] = ssc.ssc_data_get_array(
            dat, "tamb")
        outData["climate"]["Cell Temperature (F)"] = ssc.ssc_data_get_array(
            dat, "tcell")
        outData["climate"]["Wind Speed (m/s)"] = ssc.ssc_data_get_array(
            dat, "wspd")
        # Power generation.
        outData["powerOutputAc"] = ssc.ssc_data_get_array(dat, "ac")
        # Monthly aggregation outputs.
        months = {
            "Jan": 0,
            "Feb": 1,
            "Mar": 2,
            "Apr": 3,
            "May": 4,
            "Jun": 5,
            "Jul": 6,
            "Aug": 7,
            "Sep": 8,
            "Oct": 9,
            "Nov": 10,
            "Dec": 11
        }
        totMonNum = lambda x: sum([
            z
            for (y, z) in zip(outData["timeStamps"], outData["powerOutputAc"])
            if y.startswith(startDateTime[0:4] + "-{0:02d}".format(x + 1))
        ])
        outData["monthlyGeneration"] = [[a, roundSig(
            totMonNum(b),
            2)] for (a, b) in sorted(months.items(), key=lambda x: x[1])]
        monthlyNoConsumerServedSales = []
        monthlyKWhSold = []
        monthlyRevenue = []
        totalKWhSold = []
        totalRevenue = []
        for key in inputDict:
            # MAYBEFIX: data in list may not be ordered by month.
            if key.endswith("Sale"):
                monthlyNoConsumerServedSales.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("KWh"):  # the order of calculation matters
                monthlyKWhSold.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("Rev"):
                monthlyRevenue.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("KWhT"):
                totalKWhSold.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("RevT"):
                totalRevenue.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
        outData["monthlyNoConsumerServedSales"] = sorted(
            monthlyNoConsumerServedSales, key=lambda x: months[x[0]])
        outData["monthlyKWhSold"] = sorted(monthlyKWhSold,
                                           key=lambda x: months[x[0]])
        outData["monthlyRevenue"] = sorted(monthlyRevenue,
                                           key=lambda x: months[x[0]])
        outData["totalKWhSold"] = sorted(totalKWhSold,
                                         key=lambda x: months[x[0]])
        outData["totalRevenue"] = sorted(totalRevenue,
                                         key=lambda x: months[x[0]])
        outData["totalGeneration"] = [[
            sorted(months.items(), key=lambda x: x[1])[i][0],
            outData["monthlyGeneration"][i][1] *
            outData["monthlyNoConsumerServedSales"][i][1] *
            (float(inputDict.get("resPenetration", 5)) / 100 / 1000)
        ] for i in range(12)]
        outData["totalSolarSold"] = [[
            sorted(months.items(), key=lambda x: x[1])[i][0],
            outData["totalKWhSold"][i][1] - outData["totalGeneration"][i][1]
        ] for i in range(12)]
        ##################
        # TODO: add retailCost to the calculation.
        ##################
        ## Flow Diagram Calculations, and order of calculation matters
        # BAU case
        outData["BAU"] = {}
        # E23 = E11
        outData["BAU"]["totalKWhPurchased"] = float(
            inputDict.get("totalKWhPurchased", 1))
        # E24 = SUM(E19:P19)
        outData["BAU"]["totalKWhSales"] = sum([x[1] for x in totalKWhSold])
        # E25 = E23-E24
        outData["BAU"]["losses"] = float(inputDict.get(
            "totalKWhPurchased", 0)) - sum(
                [totalKWhSold[i][1] for i in range(12)])
        # E26 = E25/E23
        outData["BAU"]["effectiveLossRate"] = outData["BAU"][
            "losses"] / outData["BAU"]["totalKWhPurchased"]
        # E27 = 0
        outData["BAU"]["annualSolarGen"] = 0
        # E28 = SUM(E17:P17)
        outData["BAU"]["resNonSolarKWhSold"] = sum(
            [monthlyKWhSold[i][1] for i in range(12)])
        # E29 = 0
        outData["BAU"]["solarResDemand"] = 0
        # E30 = 0
        outData["BAU"]["solarResSold"] = 0
        # E31 = E24-E28
        outData["BAU"]["nonResKWhSold"] = outData["BAU"][
            "totalKWhSales"] - outData["BAU"]["resNonSolarKWhSold"]
        # E32 = 0
        outData["BAU"]["costSolarGen"] = 0
        # E33 = SUM(E20:P20)-SUM(E18:P18)+E10
        outData["BAU"]["nonResRev"] = sum([
            totalRevenue[i][1] for i in range(12)
        ]) - sum([monthlyRevenue[i][1] for i in range(12)]) + float(
            inputDict.get("otherElecRevenue"))
        # E34 = (SUM(E18:P18)-SUM(E16:P16)*E6)/SUM(E17:P17)
        outData["BAU"]["effectiveResRate"] = (
            sum([monthlyRevenue[i][1] for i in range(12)]) -
            sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) *
            float(inputDict.get("customServiceCharge", 0))) / sum(
                [monthlyKWhSold[i][1] for i in range(12)])
        # E35 = E34*E28+SUM(E16:P16)*E6
        outData["BAU"]["resNonSolarRev"] = outData["BAU"][
            "effectiveResRate"] * outData["BAU"]["resNonSolarKWhSold"] + sum([
                monthlyNoConsumerServedSales[i][1] for i in range(12)
            ]) * float(inputDict.get("customServiceCharge", 0))
        # E36 = E30*E34
        outData["BAU"]["solarResRev"] = 0
        # E37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71), update after Form 7 model
        outData["BAU"]["nonPowerCosts"] = 0
        # E38 = E23-E25-E28-E30-E31
        outData["BAU"]["energyAllBal"] = 0
        # E39 = E36+E33+E35-E47-E72-E37
        outData["BAU"]["dollarAllBal"] = 0
        # E40 = 0
        outData["BAU"]["avgMonthlyBillSolarCus"] = 0
        # E41 = E35/SUM(E16:P16)
        avgCustomerCount = (
            sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) / 12)
        outData["BAU"]["avgMonthlyBillNonSolarCus"] = outData["BAU"][
            "resNonSolarRev"] / sum(
                [monthlyNoConsumerServedSales[i][1] for i in range(12)])
        # E42 = E63/E24, update after Form 7 model
        outData["BAU"]["costofService"] = 0
        # Solar case
        outData["Solar"] = {}
        # F27 = SUM(E15:P15)
        outData["Solar"]["annualSolarGen"] = sum(
            [outData["totalGeneration"][i][1] for i in range(12)])
        # F24 = E24-F27
        outData["Solar"]["totalKWhSales"] = sum(
            [totalKWhSold[i][1]
             for i in range(12)]) - outData["Solar"]["annualSolarGen"]
        # F23 =F24/(1-E26)
        outData["Solar"]["totalKWhPurchased"] = outData["Solar"][
            "totalKWhSales"] / (1 - outData["BAU"]["effectiveLossRate"])
        outData["totalsolarmonthly"] = [[
            sorted(months.items(),
                   key=lambda x: x[1])[i][0], outData["totalSolarSold"][i][1] /
            (1 - outData["BAU"]["effectiveLossRate"])
        ] for i in range(12)]
        # F25 = F23-F24
        outData["Solar"]["losses"] = (outData["Solar"]["totalKWhPurchased"] -
                                      outData["Solar"]["totalKWhSales"])
        # F26 = E26
        outData["Solar"]["effectiveLossRate"] = outData["BAU"][
            "effectiveLossRate"]
        # F28 = (1-E5)*E28
        outData["Solar"]["resNonSolarKWhSold"] = (
            1 - float(inputDict.get("resPenetration", 0)) /
            100) * outData["BAU"]["resNonSolarKWhSold"]
        # F29 = E5*E28
        outData["Solar"]["solarResDemand"] = float(
            inputDict.get("resPenetration",
                          0)) / 100 * outData["BAU"]["resNonSolarKWhSold"]
        # F30 = F29-F27
        outData["Solar"]["solarResSold"] = outData["Solar"][
            "solarResDemand"] - outData["Solar"]["annualSolarGen"]
        # F31 = E31
        outData["Solar"]["nonResKWhSold"] = outData["BAU"]["nonResKWhSold"]
        # F32 = E9*F27
        outData["Solar"]["costSolarGen"] = float(
            inputDict.get("solarLCoE",
                          0.07)) * outData["Solar"]["annualSolarGen"]
        # F33 = E33
        outData["Solar"]["nonResRev"] = outData["BAU"]["nonResRev"]
        # F34 = E34
        outData["Solar"]["effectiveResRate"] = outData["BAU"][
            "effectiveResRate"]
        # F35 = E35*(1-E5)
        outData["Solar"][
            "resNonSolarRev"] = outData["BAU"]["resNonSolarRev"] * (
                1 - float(inputDict.get("resPenetration", 0.05)) / 100)
        # F30*E34 = Solar revenue from selling at residential rate
        solarSoldRateRev = outData["Solar"]["solarResSold"] * outData["Solar"][
            "effectiveResRate"]
        # (E6+E7)*SUM(E16:P16)*E5 = Solar revenue from charges
        solarChargesRev = (
            float(inputDict.get("customServiceCharge", 0)) +
            float(inputDict.get("solarServiceCharge", 0))) * sum([
                monthlyNoConsumerServedSales[i][1] for i in range(12)
            ]) * float(inputDict.get("resPenetration", 0.05)) / 100
        # F36 = F30*E34+(E6+E7)*SUM(E16:P16)*E5 = solarSoldRate + solarChargesRev
        outData["Solar"]["solarResRev"] = solarSoldRateRev + solarChargesRev
        # F37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71) = E37, update after Form 7 model
        outData["Solar"]["nonPowerCosts"] = 0
        # F38 = F23-F25-F28-F30-E31
        outData["Solar"]["energyAllBal"] = 0
        # F39 = F36+E33+F35-F47-F72-E37
        outData["Solar"]["dollarAllBal"] = 0
        if (float(inputDict.get("resPenetration", 0.05)) > 0):
            # F41 = (F35)/(SUM(E16:P16)*(1-E5))
            outData["Solar"]["avgMonthlyBillNonSolarCus"] = outData["Solar"][
                "resNonSolarRev"] / (sum([
                    monthlyNoConsumerServedSales[i][1] for i in range(12)
                ]) * (1 - float(inputDict.get("resPenetration", 0.05)) / 100))
            # F42 = F30*E34/(SUM(E16:P16)*E5)+E6+E7
            outData["Solar"]["avgMonthlyBillSolarCus"] = outData["Solar"][
                "solarResSold"] * outData["BAU"]["effectiveResRate"] / (sum(
                    [monthlyNoConsumerServedSales[i][1]
                     for i in range(12)]) * float(
                         inputDict.get("resPenetration", 0.05)) / 100) + float(
                             inputDict.get("customServiceCharge", 0)) + float(
                                 inputDict.get("solarServiceCharge", 0))
            # F43 = (F27/(SUM(E16:P16)*E5))*E9
            outData["Solar"]["avgMonthlyBillSolarSolarCus"] = (
                outData["Solar"]["annualSolarGen"] /
                (sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) *
                 float(inputDict.get("resPenetration", 0.05)) / 100)) * float(
                     inputDict.get("solarLCoE", 0.07))
        else:
            outData["Solar"]["avgMonthlyBillNonSolarCus"] = 0
            outData["Solar"]["avgMonthlyBillSolarCus"] = 0
            outData["Solar"]["avgMonthlyBillSolarSolarCus"] = 0
        # Net Average Monthly Bill
        avgMonthlyBillSolarNet = outData["Solar"][
            "avgMonthlyBillSolarCus"] + outData["Solar"][
                "avgMonthlyBillSolarSolarCus"]
        outData["Solar"]["avgMonthlyBillSolarCus"] = avgMonthlyBillSolarNet
        # F45 = F63/F24, update after Form 7 model
        outData["Solar"]["costofService"] = 0
        ## Form 7 Model
        # E46
        outData["Solar"]["powerProExpense"] = outData["BAU"][
            "powerProExpense"] = float(inputDict.get("powerProExpense", 0))
        # E47 != F47
        outData["BAU"]["costPurchasedPower"] = float(
            inputDict.get("costPurchasedPower", 0))
        # E48
        outData["Solar"]["transExpense"] = outData["BAU"][
            "transExpense"] = float(inputDict.get("transExpense", 0))
        # E49
        outData["Solar"]["distriExpenseO"] = outData["BAU"][
            "distriExpenseO"] = float(inputDict.get("distriExpenseO", 0))
        # E50
        outData["Solar"]["distriExpenseM"] = outData["BAU"][
            "distriExpenseM"] = float(inputDict.get("distriExpenseM", 0))
        # E51
        outData["Solar"]["customerAccountExpense"] = outData["BAU"][
            "customerAccountExpense"] = float(
                inputDict.get("customerAccountExpense", 0))
        # E52
        outData["Solar"]["customerServiceExpense"] = outData["BAU"][
            "customerServiceExpense"] = float(
                inputDict.get("customerServiceExpense", 0))
        # E53
        outData["Solar"]["salesExpense"] = outData["BAU"][
            "salesExpense"] = float(inputDict.get("salesExpense", 0))
        # E54
        outData["Solar"]["adminGeneralExpense"] = outData["BAU"][
            "adminGeneralExpense"] = float(
                inputDict.get("adminGeneralExpense", 0))
        # E56
        outData["Solar"]["depreAmortiExpense"] = outData["BAU"][
            "depreAmortiExpense"] = float(
                inputDict.get("depreAmortiExpense", 0))
        # E57
        outData["Solar"]["taxExpensePG"] = outData["BAU"][
            "taxExpensePG"] = float(inputDict.get("taxExpensePG", 0))
        # E58
        outData["Solar"]["taxExpense"] = outData["BAU"]["taxExpense"] = float(
            inputDict.get("taxExpense", 0))
        # E59
        outData["Solar"]["interestLongTerm"] = outData["BAU"][
            "interestLongTerm"] = float(inputDict.get("interestLongTerm", 0))
        # E60
        outData["Solar"]["interestConstruction"] = outData["BAU"][
            "interestConstruction"] = float(
                inputDict.get("interestConstruction", 0))
        # E61
        outData["Solar"]["interestExpense"] = outData["BAU"][
            "interestExpense"] = float(inputDict.get("interestExpense", 0))
        # E62
        outData["Solar"]["otherDeductions"] = outData["BAU"][
            "otherDeductions"] = float(inputDict.get("otherDeductions", 0))
        # E65
        outData["Solar"]["nonOpMarginInterest"] = outData["BAU"][
            "nonOpMarginInterest"] = float(
                inputDict.get("nonOpMarginInterest", 0))
        # E66
        outData["Solar"]["fundsUsedConstruc"] = outData["BAU"][
            "fundsUsedConstruc"] = float(inputDict.get("fundsUsedConstruc", 0))
        # E67
        outData["Solar"]["incomeEquityInvest"] = outData["BAU"][
            "incomeEquityInvest"] = float(
                inputDict.get("incomeEquityInvest", 0))
        # E68
        outData["Solar"]["nonOpMarginOther"] = outData["BAU"][
            "nonOpMarginOther"] = float(inputDict.get("nonOpMarginOther", 0))
        # E69
        outData["Solar"]["genTransCapCredits"] = outData["BAU"][
            "genTransCapCredits"] = float(
                inputDict.get("genTransCapCredits", 0))
        # E70
        outData["Solar"]["otherCapCreditsPatroDivident"] = outData["BAU"][
            "otherCapCreditsPatroDivident"] = float(
                inputDict.get("otherCapCreditsPatroDivident", 0))
        # E71
        outData["Solar"]["extraItems"] = outData["BAU"]["extraItems"] = float(
            inputDict.get("extraItems", 0))
        # Calculation
        # E45 = SUM(E20:P20)+E10
        outData["BAU"]["operRevPatroCap"] = sum(
            [totalRevenue[i][1]
             for i in range(12)]) + float(inputDict.get("otherElecRevenue", 0))
        # E55 = SUM(E46:E54)
        outData["BAU"]["totalOMExpense"] = float(inputDict.get("powerProExpense")) \
         + float(inputDict.get("costPurchasedPower")) \
         + float(inputDict.get("transExpense")) \
         + float(inputDict.get("distriExpenseO")) \
         + float(inputDict.get("distriExpenseM")) \
         + float(inputDict.get("customerAccountExpense")) \
         + float(inputDict.get("customerServiceExpense")) \
         + float(inputDict.get("salesExpense"))  \
         + float(inputDict.get("adminGeneralExpense"))
        # E63 = SUM(E55:E62)
        outData["BAU"]["totalCostElecService"] = outData["BAU"]["totalOMExpense"] \
         + float(inputDict.get("depreAmortiExpense"))\
         + float(inputDict.get("taxExpensePG"))\
         + float(inputDict.get("taxExpense"))\
         + float(inputDict.get("interestLongTerm"))\
         + float(inputDict.get("interestExpense"))\
         + float(inputDict.get("interestConstruction"))\
         + outData["BAU"]["otherDeductions"]
        # E64 = E45-E63
        outData["BAU"]["patCapOperMargins"] = outData["BAU"][
            "operRevPatroCap"] - outData["BAU"]["totalCostElecService"]
        # E72 = SUM(E64:E71)
        outData["BAU"]["patCapital"] = outData["BAU"]["patCapOperMargins"]\
         + float(inputDict.get("nonOpMarginInterest"))\
         + float(inputDict.get("fundsUsedConstruc"))\
         + float(inputDict.get("incomeEquityInvest"))\
         + float(inputDict.get("nonOpMarginOther"))\
         + float(inputDict.get("genTransCapCredits"))\
         + float(inputDict.get("otherCapCreditsPatroDivident"))\
         + float(inputDict.get("extraItems"))
        # F48 = E48-F27*E34+SUM(E16:P16)*E5*E7
        outData["Solar"]["operRevPatroCap"] = outData["BAU"][
            "operRevPatroCap"] - outData["BAU"]["effectiveResRate"] * outData[
                "Solar"]["annualSolarGen"] + sum(
                    [monthlyNoConsumerServedSales[i][1]
                     for i in range(12)]) * float(
                         inputDict.get("resPenetration", 0.05)) / 100 * float(
                             inputDict.get("solarServiceCharge", 0))
        # F47 = (F23)*E8
        inputDict["costofPower"] = float(inputDict.get(
            "costPurchasedPower", 0)) / float(
                inputDict.get("totalKWhPurchased", 0))
        outData["Solar"]["costPurchasedPower"] = outData["Solar"][
            "totalKWhPurchased"] * float(inputDict.get("costofPower", 0))
        inputDict["costofPower"] = round(inputDict["costofPower"], 3)
        # F55 = SUM(F46:F54)
        outData["Solar"]["totalOMExpense"] = outData["Solar"]["powerProExpense"]\
         + outData["Solar"]["costPurchasedPower"]\
         + outData["Solar"]["transExpense"]\
         + outData["Solar"]["distriExpenseO"]\
         + outData["Solar"]["distriExpenseM"]\
         + outData["Solar"]["customerAccountExpense"]\
         + outData["Solar"]["customerServiceExpense"]\
         + outData["Solar"]["salesExpense"]\
         + outData["Solar"]["adminGeneralExpense"]
        # F63 = E63
        outData["Solar"]["totalCostElecService"] = outData["Solar"]["totalOMExpense"]\
         + outData["Solar"]["depreAmortiExpense"]\
         + outData["Solar"]["taxExpensePG"]\
         + outData["Solar"]["taxExpense"]\
         + outData["Solar"]["interestLongTerm"]\
         + outData["Solar"]["interestConstruction"]\
         + outData["Solar"]["interestExpense"]\
         + outData["Solar"]["otherDeductions"]
        # F64 = F45 - F63
        outData["Solar"]["patCapOperMargins"] = outData["Solar"][
            "operRevPatroCap"] - outData["Solar"]["totalCostElecService"]
        # F72 = SUM(F64:F71)
        outData["Solar"]["patCapital"] = outData["Solar"]["patCapOperMargins"]\
         + outData["Solar"]["nonOpMarginInterest"]\
         + outData["Solar"]["fundsUsedConstruc"]\
         + outData["Solar"]["incomeEquityInvest"]\
         + outData["Solar"]["nonOpMarginOther"]\
         + outData["Solar"]["genTransCapCredits"]\
         + outData["Solar"]["otherCapCreditsPatroDivident"]\
         + outData["Solar"]["extraItems"]
        # E37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71), update after Form 7 model
        outData["BAU"]["nonPowerCosts"] = outData["BAU"]["transExpense"] \
         + outData["BAU"]["distriExpenseO"] \
         + outData["BAU"]["distriExpenseM"] \
         + outData["BAU"]["customerAccountExpense"] \
         + outData["BAU"]["customerServiceExpense"] \
         + outData["BAU"]["salesExpense"] \
         + outData["BAU"]["adminGeneralExpense"] \
         + outData["BAU"]["depreAmortiExpense"] \
         + outData["BAU"]["taxExpensePG"] \
         + outData["BAU"]["taxExpense"] \
         + outData["BAU"]["interestLongTerm"] \
         + outData["BAU"]["interestConstruction"] \
         + outData["BAU"]["interestExpense"] \
         + outData["BAU"]["otherDeductions"] \
         - (outData["BAU"]["nonOpMarginInterest"] \
         + outData["BAU"]["fundsUsedConstruc"] \
         + outData["BAU"]["incomeEquityInvest"] \
         + outData["BAU"]["nonOpMarginOther"] \
         + outData["BAU"]["genTransCapCredits"] \
         + outData["BAU"]["otherCapCreditsPatroDivident"] \
         + outData["BAU"]["extraItems"])
        # E42 = E63/E24, update after Form 7 model
        outData["BAU"]["costofService"] = outData["BAU"][
            "totalCostElecService"] / outData["BAU"]["totalKWhSales"]
        # F37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71) = E37, update after Form 7 model
        outData["Solar"]["nonPowerCosts"] = outData["BAU"]["nonPowerCosts"]
        # F42 = F63/F24, update after Form 7 model
        outData["Solar"]["costofService"] = outData["Solar"][
            "totalCostElecService"] / outData["Solar"]["totalKWhSales"]
        # Stdout/stderr.
        outData["stdout"] = "Success"
        outData["stderr"] = ""
        # Write the output.
        with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
            json.dump(outData, outFile, indent=4)
        # Update the runTime in the input file.
        endTime = dt.datetime.now()
        inputDict["runTime"] = str(
            dt.timedelta(seconds=int((endTime - startTime).total_seconds())))
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inputDict, inFile, indent=4)
    except:
        # If input range wasn't valid delete output, write error to disk.
        cancel(modelDir)
        thisErr = traceback.format_exc()
        print 'ERROR IN MODEL', modelDir, thisErr
        inputDict['stderr'] = thisErr
        with open(os.path.join(modelDir, 'stderr.txt'), 'w') as errorFile:
            errorFile.write(thisErr)
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inputDict, inFile, indent=4)