Beispiel #1
0
def omfCalibrate(workDir, feederPath, scadaPath, simStartDate, simLength, simLengthUnits, solver="FBS", calibrateError=(0.05,5), trim=5):
	'''calibrates a feeder and saves the calibrated tree at a location.
	Note: feeders with cap banks should be calibrated with cap banks OPEN.
	We have seen cap banks throw off calibration.'''
	with open(feederPath, "r") as jsonIn:
		feederJson = json.load(jsonIn)
		tree = feederJson.get("tree", {})
	simLength = simLength + trim
	# Process scada data.
	scadaSubPower = _processScadaData(pJoin(workDir,"gridlabD"),scadaPath, simStartDate, simLengthUnits)
	# Load specified solver.
	for key in tree:
		if tree[key].get("module","").lower() == "powerflow":
			tree[key] = {"module":"powerflow","solver_method":solver}	
	# Attach player.
	classOb = {'omftype':'class player','argument':'{double value;}'}
	playerOb = {"object":"player", "property":"value", "name":"scadaLoads", "file":"subScada.player", "loop":"0"}
	maxKey = feeder.getMaxKey(tree)
	playerKey = maxKey + 2
	tree[maxKey+1] = classOb
	tree[playerKey] = playerOb
	# Make loads reference player.
	loadTemplate = {"object": "triplex_load",
		"power_pf_12": "0.95",
		"impedance_pf_12": "0.98",
		"power_pf_12": "0.90",
		"impedance_fraction_12": "0.7",
		"power_fraction_12": "0.3"}
	loadTemplateR = {"object": "load",
		"impedance_pf_A": "0.98",
		"impedance_pf_B": "0.98",
		"impedance_pf_C": "0.98",
		"power_pf_A": "0.90",
		"power_pf_B": "0.90",
		"power_pf_C": "0.90",
		"impedance_fraction_A": "0.7",
		"impedance_fraction_B": "0.7",
		"impedance_fraction_C": "0.7",
		"power_fraction_A": "0.3",
		"power_fraction_B": "0.3",
		"power_fraction_C": "0.3"}		
	for key in tree:
		ob = tree[key]
		if ob.get("object","") == "triplex_node" and ob.get("power_12","") != "":
			# Add to triplex_nodes.
			newOb = dict(loadTemplate)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			oldPow = ob.get("power_12","").replace("j","d")
			pythagPower = gridlabd._strClean(oldPow)
			newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
			tree[key] = newOb
		elif ob.get("object","") == "load":
			# Add to residential_loads too.
			newOb = dict(loadTemplateR)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["load_class"] = ob.get("load_class", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			try:
				oldPow = ob.get("constant_power_A","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_A"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_B","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_B"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_C","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_C"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			tree[key] = newOb
	# Convert swing bus to a meter.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing' and tree[key].get('object','') != 'meter':
			swingName = tree[key].get('name')
			regIndex = key
			tree[key]['object'] = 'meter'	
	# Search for the substation meter and attach a recorder there.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing':
			swingName = tree[key].get('name')
	recOb = {"object": "recorder",
		"parent": swingName,
		"property": "measured_real_power,measured_reactive_power,measured_power",
		"file": "caliSub.csv",
		"interval": "900"}
	outputRecorderKey = maxKey + 3
	tree[outputRecorderKey] = recOb
	feeder.adjustTime(tree, simLength, simLengthUnits, simStartDate['Date'].strftime("%Y-%m-%d %H:%M:%S"))
	# Run Gridlabd, calculate scaling constant.
	def runPowerflowIter(tree,scadaSubPower):
		'''Runs powerflow once, then iterates.'''
		# Run initial powerflow to get power.
		print "Starting calibration."
		print "Goal of calibration: Error: %s, Iterations: <%s, trim: %s"%(calibrateError[0], calibrateError[1], trim)		
		output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=pJoin(workDir,"gridlabD"))
		outRealPow = output["caliSub.csv"]["measured_real_power"][trim:simLength]
		outImagPower = output["caliSub.csv"]["measured_reactive_power"][trim:simLength]
		outAppPowerKw = [(x[0]**2 + x[1]**2)**0.5/1000 for x in zip(outRealPow, outImagPower)]
		lastFile = "subScada.player"
		nextFile = "subScadaCalibrated.player"
		nextPower = outAppPowerKw
		error = (sum(outRealPow)/1000-sum(scadaSubPower))/sum(scadaSubPower)
		iteration = 1
		print "First error:", error
		while abs(error)>calibrateError[0] and iteration<calibrateError[1]:
			# Run calibration and iterate up to 5 times.
			SCAL_CONST = sum(scadaSubPower)/sum(nextPower)
			print "Calibrating & running again... Error: %s, Iteration: %s, SCAL_CONST: %s"%(str(round(abs(error*100),2)), str(iteration), round(SCAL_CONST,2))
			newPlayData = []
			with open(pJoin(pJoin(workDir,"gridlabD"), lastFile), "r") as playerFile:
				for line in playerFile:
					(key,val) = line.split(',')
					newPlayData.append(str(key) + ',' + str(float(val)*SCAL_CONST) + "\n")
			with open(pJoin(pJoin(workDir,"gridlabD"), nextFile), "w") as playerFile:
				for row in newPlayData:
					playerFile.write(row)
			tree[playerKey]["file"] = nextFile
			tree[outputRecorderKey]["file"] = "caliSubCheck.csv"
			nextOutput = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=pJoin(workDir,"gridlabD"))
			outRealPowIter = nextOutput["caliSubCheck.csv"]["measured_real_power"][trim:simLength]
			outImagPowerIter = nextOutput["caliSubCheck.csv"]["measured_reactive_power"][trim:simLength]
			nextAppKw = [(x[0]**2 + x[1]**2)**0.5/1000
				for x in zip(outRealPowIter, outImagPowerIter)]
			lastFile = nextFile
			nextFile = "subScadaCalibrated"+str(iteration)+".player"
			nextPower = nextAppKw
			# Compute error and iterate.
			error = (sum(outRealPowIter)/1000-sum(scadaSubPower))/sum(scadaSubPower)
			iteration+=1
		else:
			if iteration==1: outRealPowIter = outRealPow
		print "Calibration done: Error: %s, Iteration: %s, SCAL_CONST: %s"%(str(round(abs(error*100),2)), str(iteration), round(SCAL_CONST,2))		
		return outRealPow, outRealPowIter, lastFile, iteration
	outRealPow, outRealPowIter, lastFile, iteration = runPowerflowIter(tree,scadaSubPower[trim:simLength])
	caliPowVectors = [[float(element) for element in scadaSubPower[trim:simLength]], [float(element)/1000 for element in outRealPow], [float(element)/1000 for element in outRealPowIter]]
	labels = ["scadaSubPower","initialGuess","finalGuess"]
	colors = ['red','lightblue','blue']
	chartData = {"Title":"Substation Calibration Check (Iterated "+str(iteration+1)+"X)", "fileName":"caliCheckPlot", "colors":colors,"labels":labels, "timeZone":simStartDate['timeZone']}
	print "Len:", len(caliPowVectors[0]), len(caliPowVectors[1]), len(caliPowVectors[2])
	plotLine(workDir, caliPowVectors, chartData, simStartDate['Date']+dt.timedelta(hours=trim), simLengthUnits)
	# Write the final output.
	with open(pJoin(workDir,"calibratedFeeder.omd"),"w") as outJson:
		playerString = open(pJoin(pJoin(workDir,"gridlabD"),lastFile)).read()
		feederJson["attachments"][lastFile] = playerString
		feederJson["tree"] = tree
		json.dump(feederJson, outJson, indent=4)
	return
Beispiel #2
0
def runModel(modelDir,localTree,inData):
	'''This reads a glm file, changes the method of powerflow and reruns'''
	try:
		os.remove(pJoin(modelDir,"allOutputData.json"))
	except:
		pass
	allOutput = {}
	if not os.path.isdir(modelDir):
		os.makedirs(modelDir)
		inData["created"] = str(datetime.now())
	with open(pJoin(modelDir,"allInputData.json"),"w") as inputFile:
		json.dump(inData, inputFile, indent=4)
	binaryName = "gridlabd"
	for key in localTree:
		if "solver_method" in localTree[key].keys():
			print "current solver method", localTree[key]["solver_method"] 
			localTree[key]["solver_method"] = 'FBS'
	#find the swing bus and recorder attached to substation
	for key in localTree:
		if localTree[key].get('bustype','').lower() == 'swing':
			swingIndex = key
			swingName = localTree[key].get('name')
		if localTree[key].get('object','') == 'regulator' and localTree[key].get('from','') == swingName:
			regIndex = key
			regConfName = localTree[key]['configuration']
	#find the regulator and capacitor names and combine to form a string for volt-var control object
	regKeys = []
	accum_reg = ""
	for key in localTree:
		if localTree[key].get("object","") == "regulator":
			accum_reg += localTree[key].get("name","ERROR") + ","
			regKeys.append(key)
	regstr = accum_reg[:-1]
	print regKeys
	capKeys = []
	accum_cap = ""
	for key in localTree:
		if localTree[key].get("object","") == "capacitor":
			accum_cap += localTree[key].get("name","ERROR") + ","
			capKeys.append(key)
			if localTree[key].get("control","").lower() == "manual":
				localTree[key]['control'] = "VOLT"
				print "changing capacitor control from manual to volt"
	capstr = accum_cap[:-1]
	print capKeys
	# Attach recorders relevant to CVR.
	recorders = [
			{'object': 'collector',
			'file': 'ZlossesTransformer.csv',
			'group': 'class=transformer',
			'limit': '0',
			'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
			{'object': 'collector',
			'file': 'ZlossesUnderground.csv',
			'group': 'class=underground_line',
			'limit': '0',
			'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
			{'object': 'collector',
			'file': 'ZlossesOverhead.csv',
			'group': 'class=overhead_line',
			'limit': '0',
			'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
			{'object': 'recorder',
			'file': 'Zregulator.csv',
			'limit': '0',
			'parent': localTree[regIndex]['name'],
			'property': 'tap_A,tap_B,tap_C,power_in.real,power_in.imag'},
			{'object': 'collector',
			'file': 'ZvoltageJiggle.csv',
			'group': 'class=triplex_meter',
			'limit': '0',
			'property': 'min(voltage_12.mag),mean(voltage_12.mag),max(voltage_12.mag),std(voltage_12.mag)'},
			{'object': 'recorder',
			'file': 'ZsubstationTop.csv',
			'limit': '0',
			'parent': localTree[swingIndex]['name'],
			'property': 'voltage_A,voltage_B,voltage_C'},
			{'object': 'recorder',
			'file': 'ZsubstationBottom.csv',
			'limit': '0',
			'parent': localTree[regIndex]['to'],
			'property': 'voltage_A,voltage_B,voltage_C'}]
	#recorder object for capacitor switching - if capacitors exist
	if capKeys != []:
		for key in capKeys:
			recorders.append({'object': 'recorder',
			'file': 'ZcapSwitch' + str(key) + '.csv',
			'limit': '0',
			'parent': localTree[key]['name'],
			'property': 'switchA,switchB,switchC'})
	#attach recorder process
	biggest = 1 + max([int(k) for k in localTree.keys()])
	for index, rec in enumerate(recorders):
		localTree[biggest + index] = rec
	#run a reference load flow
	HOURS = float(100)
	year_lp = False   #leap year
	feeder.adjustTime(localTree,HOURS,"hours","2011-01-01")	
	output = gridlabd.runInFilesystem(localTree,keepFiles=False,workDir=modelDir)
	os.remove(pJoin(modelDir,"PID.txt"))
	p = output['Zregulator.csv']['power_in.real']
	q = output['Zregulator.csv']['power_in.imag']
	#time delays from configuration files
	time_delay_reg = '30.0'  
	time_delay_cap = '300.0'
	for key in localTree:
		if localTree[key].get('object','') == "regulator_configuration":
			time_delay_reg = localTree[key]['time_delay']
			print "time_delay_reg",time_delay_reg
		# if localTree[key].get('object','') == "capacitor":
		# 	time_delay_cap = localTree[key]['time_delay']
		# 	print "time_delay_cap",time_delay_cap
	#change the recorder names
	for key in localTree:
		if localTree[key].get('object','') == "collector" or localTree[key].get('object','') == "recorder":
			if localTree[key].get('file','').startswith('Z'):
				localTree[key]['file'] = localTree[key].get('file','').replace('Z','NewZ')
	#create volt-var control object
	max_key = max([int(key) for key in localTree.keys()])
	print max_key
	localTree[max_key+1] = {'object' : 'volt_var_control',
	'name' : 'IVVC1',
	'control_method' : 'ACTIVE',
	'capacitor_delay' : str(time_delay_cap),
	'regulator_delay' : str(time_delay_reg),
	'desired_pf' : '0.99',
	'd_max' : '0.6',
	'd_min' : '0.1',
	'substation_link' : str(localTree[regIndex]['name']),
	'regulator_list' : regstr,
	'capacitor_list': capstr} 
	#running powerflow analysis via gridalab after attaching a regulator
	feeder.adjustTime(localTree,HOURS,"hours","2011-01-01")	
	output1 = gridlabd.runInFilesystem(localTree,keepFiles=True,workDir=modelDir)
	os.remove(pJoin(modelDir,"PID.txt"))
	pnew = output1['NewZregulator.csv']['power_in.real']
	qnew = output1['NewZregulator.csv']['power_in.imag']
	#total real and imaginary losses as a function of time
	realLoss = []
	imagLoss = []
	realLossnew = []
	imagLossnew = []
	for element in range(int(HOURS)):
		r = 0.0
		i = 0.0
		rnew = 0.0
		inew = 0.0
		for device in ['ZlossesOverhead.csv','ZlossesTransformer.csv','ZlossesUnderground.csv']:
			for letter in ['A','B','C']:
				r += output[device]['sum(power_losses_' + letter + '.real)'][element]
				i += output[device]['sum(power_losses_' + letter + '.imag)'][element]
				rnew += output1['New'+device]['sum(power_losses_' + letter + '.real)'][element]
				inew += output1['New'+device]['sum(power_losses_' + letter + '.imag)'][element]
		realLoss.append(r)
		imagLoss.append(i)
		realLossnew.append(rnew)
		imagLossnew.append(inew)
	#voltage calculations and tap calculations
	lowVoltage = []
	meanVoltage = []
	highVoltage = []
	lowVoltagenew = []
	meanVoltagenew = []
	highVoltagenew = []
	tap = {'A':[],'B':[],'C':[]}
	tapnew = {'A':[],'B':[],'C':[]}
	volt = {'A':[],'B':[],'C':[]}
	voltnew = {'A':[],'B':[],'C':[]}
	switch = {'A':[],'B':[],'C':[]}
	switchnew = {'A':[],'B':[],'C':[]}
	for element in range(int(HOURS)):
		for letter in ['A','B','C']:
			tap[letter].append(output['Zregulator.csv']['tap_' + letter][element])
			tapnew[letter].append(output1['NewZregulator.csv']['tap_' + letter][element])
			#voltage real, imag
			vr, vi = sepRealImag(output['ZsubstationBottom.csv']['voltage_'+letter][element])
			volt[letter].append(math.sqrt(vr**2+vi**2)/60)
			vrnew, vinew = sepRealImag(output1['NewZsubstationBottom.csv']['voltage_'+letter][element])
			voltnew[letter].append(math.sqrt(vrnew**2+vinew**2)/60)
			if capKeys != []:
				switch[letter].append(output['ZcapSwitch' + str(int(capKeys[0])) + '.csv']['switch'+ letter][element])
				switchnew[letter].append(output1['NewZcapSwitch' + str(int(capKeys[0])) + '.csv']['switch'+ letter][element])
		lowVoltage.append(float(output['ZvoltageJiggle.csv']['min(voltage_12.mag)'][element])/2.0)
		meanVoltage.append(float(output['ZvoltageJiggle.csv']['mean(voltage_12.mag)'][element])/2.0)
		highVoltage.append(float(output['ZvoltageJiggle.csv']['max(voltage_12.mag)'][element])/2.0)
		lowVoltagenew.append(float(output1['NewZvoltageJiggle.csv']['min(voltage_12.mag)'][element])/2.0)
		meanVoltagenew.append(float(output1['NewZvoltageJiggle.csv']['mean(voltage_12.mag)'][element])/2.0)
		highVoltagenew.append(float(output1['NewZvoltageJiggle.csv']['max(voltage_12.mag)'][element])/2.0)
	#energy calculations
	whEnergy = []
	whLosses = []
	whLoads = []
	whEnergy.append(sum(p)/10**6)
	whLosses.append(sum(realLoss)/10**6)
	whLoads.append((sum(p)-sum(realLoss))/10**6)
	whEnergy.append(sum(pnew)/10**6)
	whLosses.append(sum(realLossnew)/10**6)
	whLoads.append((sum(pnew)-sum(realLossnew))/10**6)
	indices = ['No IVVC', 'With IVVC']
	# energySalesRed = (whLoads[1]-whLoads[0])*(inData['wholesaleEnergyCostPerKwh'])*1000
	# lossSav = (whLosses[0]-whLosses[1])*inData['wholesaleEnergyCostPerKwh']*1000
	# print energySalesRed, lossSav
	#plots
	ticks = []
	plt.clf()
	plt.title("total energy")
	plt.ylabel("total load and losses (MWh)")
	for element in range(2):
		ticks.append(element)
		bar_loss = plt.bar(element, whLosses[element], 0.15, color= 'red')
		bar_load = plt.bar(element+0.15, whLoads[element], 0.15, color= 'orange')
	plt.legend([bar_load[0],bar_loss[0]],['total load', 'total losses'],bbox_to_anchor=(0., 0.915, 1., .102), loc=3,
		       ncol=2, mode="expand", borderaxespad=0.1)
	plt.xticks([t+0.15 for t in ticks],indices)
	plt.savefig(pJoin(modelDir,"total energy.png"))
	#real and imaginary power
	plt.figure("real power")
	plt.title("Real Power at substation")
	plt.ylabel("substation real power (MW)")
	pMW = [element/10**6 for element in p]
	pMWn = [element/10**6 for element in pnew]
	pw = plt.plot(pMW)
	npw = plt.plot(pMWn)
	plt.legend([pw[0], npw[0]], ['NO IVVC','WITH IVVC'],bbox_to_anchor=(0., 0.915, 1., .102), loc=3,
		ncol=2, mode="expand", borderaxespad=0.1)
	plt.savefig(pJoin(modelDir,"real power.png"))
	plt.figure("Reactive power")
	plt.title("Reactive Power at substation")
	plt.ylabel("substation reactive power (MVAR)")
	qMVAR = [element/10**6 for element in q]
	qMVARn = [element/10**6 for element in qnew]
	iw = plt.plot(qMVAR)
	niw = plt.plot(qMVARn)
	plt.legend([iw[0], niw[0]], ['NO IVVC','WITH IVVC'],bbox_to_anchor=(0., 0.915, 1., .102), loc=3,
		ncol=2, mode="expand", borderaxespad=0.1)
	plt.savefig(pJoin(modelDir,"imaginary power.png"))
	#voltage plots
	plt.figure("voltages as a function of time")
	f,ax = plt.subplots(2,sharex=True)
	f.suptitle("Voltages high and low")
	lv = ax[0].plot(lowVoltage,color = 'cadetblue')
	mv = ax[0].plot(meanVoltage,color = 'blue')
	hv = ax[0].plot(highVoltage, color = 'cadetblue')
	ax[0].legend([lv[0], mv[0], hv[0]], ['low voltage','mean voltage','high voltage'],bbox_to_anchor=(0., 0.915, 1., .1), loc=3,
		ncol=3, mode="expand", borderaxespad=0.1)
	ax[0].set_ylabel('NO IVVC')
	nlv = ax[1].plot(lowVoltagenew,color = 'cadetblue')
	nmv = ax[1].plot(meanVoltagenew,color = 'blue')
	nhv = ax[1].plot(highVoltagenew, color = 'cadetblue')
	ax[1].set_ylabel('WITH IVVC')
	plt.savefig(pJoin(modelDir,"Voltages.png"))
	#tap positions
	plt.figure("TAP positions NO IVVC")
	f,ax = plt.subplots(6,sharex=True)
	f.set_size_inches(18.5,12.0)
	#f.suptitle("Regulator Tap positions")
	ax[0].plot(tap['A'])
	ax[0].set_title("Regulator Tap positions NO IVVC")
	ax[0].set_ylabel("TAP A")
	ax[1].plot(tap['B'])
	ax[1].set_ylabel("TAP B")
	ax[2].plot(tap['C'])
	ax[2].set_ylabel("TAP C")
	ax[3].plot(tapnew['A'])
	ax[3].set_title("WITH IVVC")
	ax[3].set_ylabel("TAP A")
	ax[4].plot(tapnew['B'])
	ax[4].set_ylabel("TAP B")
	ax[5].plot(tapnew['C'])
	ax[5].set_ylabel("TAP C")
	for subplot in range(6):
		ax[subplot].set_ylim(-20,20)
	f.tight_layout()
	plt.savefig(pJoin(modelDir,"Regulator TAP positions.png"))
	#substation voltages
	plt.figure("substation voltage as a function of time")
	f,ax = plt.subplots(6,sharex=True)
	f.set_size_inches(18.5,12.0)
	#f.suptitle("voltages at substation NO IVVC")
	ax[0].plot(volt['A'])
	ax[0].set_title('Substation voltages NO IVVC')
	ax[0].set_ylabel('voltage A')
	ax[1].plot(volt['B'])
	ax[1].set_ylabel('voltage B')
	ax[2].plot(volt['C'])
	ax[2].set_ylabel('voltage C')
	ax[3].plot(voltnew['A'])
	ax[3].set_title("WITH IVVC")
	ax[3].set_ylabel('voltage A')
	ax[4].plot(voltnew['B'])
	ax[4].set_ylabel('voltage B')
	ax[5].plot(voltnew['C'])
	ax[5].set_ylabel('voltage C')
	f.tight_layout()
	plt.savefig(pJoin(modelDir,"substation voltages.png"))
	#cap switches - plotted if capacitors are present
	if capKeys != []:
		plt.figure("capacitor switch state as a function of time")
		f,ax = plt.subplots(6,sharex=True)
		f.set_size_inches(18.5,12.0)
		#f.suptitle("Capacitor switch state NO IVVC")
		ax[0].plot(switch['A'])
		ax[0].set_title("Capacitor switch state NO IVVC")
		ax[0].set_ylabel("switch A")
		ax[1].plot(switch['B'])
		ax[1].set_ylabel("switch B")
		ax[2].plot(switch['C'])
		ax[2].set_ylabel("switch C")
		ax[3].plot(switchnew['A'])
		ax[3].set_title("WITH IVVC")
		ax[3].set_ylabel("switch A")
		ax[4].plot(switchnew['B'])
		ax[4].set_ylabel("switch B")
		ax[5].plot(switchnew['C'])
		ax[5].set_ylabel("switch C")
		for subplot in range(6):
			ax[subplot].set_ylim(-2,2)
		f.tight_layout()
		plt.savefig(pJoin(modelDir,"capacitor switch.png"))
	#plt.show()
	#monetization
	monthNames = ["January", "February", "March", "April", "May", "June", "July", "August",
		"September", "October", "November", "December"]
	monthToSeason = {'January':'Winter','February':'Winter','March':'Spring','April':'Spring',
		'May':'Spring','June':'Summer','July':'Summer','August':'Summer',
		'September':'Fall','October':'Fall','November':'Fall','December':'Winter'}
	if year_lp == True:
		febDays = 29
	else:
		febDays = 28
	monthHours = [int(31*24),int(febDays*24),int(31*24),int(30*24),int(31*24),int(30*24),int(31*24),int(31*24),int(30*24),int(31*24),int(30*24),int(31*24)]
	#find simulation months
	temp = 0
	cumulHours = []
	for x in range(12):
		temp += monthHours[x]
		cumulHours.append(temp)
	for i in range(12):
		if i == 0:
			lowval = 0
		else:
			lowval = cumulHours[i-1]
		if HOURS<=cumulHours[i] and HOURS>=lowval:
			hourMonth = monthNames[i]
			hourIndex = i
	#calculate peaks for the number of months in simulation
	previndex = 0
	monthPeak = {}
	monthPeakNew = {}
	peakSaveDollars = {}
	energyLostDollars = {}
	lossRedDollars = {}
	for month in range(hourIndex+1):
		index1 = int(previndex)
		index2 = int(min((index1 + int(monthHours[month])), HOURS))
		monthPeak[monthNames[month]] = max(p[index1:index2])/1000.0
		monthPeakNew[monthNames[month]] = max(pnew[index1:index2])/1000.0
		peakSaveDollars[monthNames[month]] = (monthPeak[monthNames[month]]-monthPeakNew[monthNames[month]])*inData['peakDemandCost'+str(monthToSeason[monthNames[month]])+'PerKw']
		lossRedDollars[monthNames[month]] = (sum(realLoss[index1:index2])/1000.0 - sum(realLossnew[index1:index2])/1000.0)*(inData['wholesaleEnergyCostPerKwh'])
		energyLostDollars[monthNames[month]] = (sum(p[index1:index2])/1000.0  - sum(pnew[index1:index2])/1000.0  - sum(realLoss[index1:index2])/1000.0  
			+ sum(realLossnew[index1:index2])/1000.0 )*(inData['wholesaleEnergyCostPerKwh'] - inData['retailEnergyCostPerKwh'])
		previndex = index2
	#money charts
	simMonths = monthNames[:hourIndex+1]
	fig = plt.figure("cost benefit barchart",figsize=(10,8))
	ticks = range(len(simMonths))
	ticks1 = [element+0.15 for element in ticks]
	ticks2 = [element+0.30 for element in ticks]
	print ticks
	eld = [energyLostDollars[month] for month in simMonths]
	lrd = [lossRedDollars[month] for month in simMonths]
	psd = [peakSaveDollars[month] for month in simMonths]
	bar_eld = plt.bar(ticks,eld,0.15,color='red') 
	bar_psd = plt.bar(ticks1,psd,0.15,color='blue')
	bar_lrd = plt.bar(ticks2,lrd,0.15,color='green')
	plt.legend([bar_eld[0], bar_psd[0], bar_lrd[0]], ['energyLostDollars','peakReductionDollars','lossReductionDollars'],bbox_to_anchor=(0., 1.015, 1., .102), loc=3,
		ncol=2, mode="expand", borderaxespad=0.1)
	monShort = [element[0:3] for element in simMonths]
	plt.xticks([t+0.15 for t in ticks],monShort)
	plt.ylabel('Utility Savings ($)')
	plt.savefig(pJoin(modelDir,"spendChart.png"))
	with open(pJoin(modelDir,"spendChart.png"),"rb") as inFile:
		allOutput["spendChart"] = inFile.read().encode("base64")
	#cumulative savings graphs
	fig = plt.figure("cost benefit barchart",figsize=(10,5))
	annualSavings = sum(eld) + sum(lrd) + sum(psd)
	annualSave = lambda x:(annualSavings - inData['omCost']) * x - inData['capitalCost']
	simplePayback = inData['capitalCost']/(annualSavings - inData['omCost'])
	plt.xlabel('Year After Installation')
	plt.xlim(0,30)
	plt.ylabel('Cumulative Savings ($)')
	plt.plot([0 for x in range(31)],c='gray')
	plt.axvline(x=simplePayback, ymin=0, ymax=1, c='gray', linestyle='--')
	plt.plot([annualSave(x) for x in range(31)], c='green')
	plt.savefig(pJoin(modelDir,"savingsChart.png"))
	with open(pJoin(modelDir,"savingsChart.png"),"rb") as inFile:
		allOutput["savingsChart"] = inFile.read().encode("base64")
	# Update the runTime in the input file.
	# endTime = datetime.now()
	# inDat["runTime"] = str(timedelta(seconds=int((endTime - startTime).total_seconds())))
	with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
		json.dump(inData, inFile, indent=4)
	with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile:
		json.dump(allOutput, outFile, indent=4)
	print "DONE RUNNING", modelDir
Beispiel #3
0
    'generator_mode': 'SUPPLY_DRIVEN',
    'name': 'solar172879',
    'parent': 'solEngInverter',
    'area': '30000 sf',
    'generator_status': 'ONLINE',
    'object': 'solar',
    'efficiency': '0.14',
    'panel_type': 'SINGLE_CRYSTAL_SILICON'
}
# myTree[oldMax + 7] = { 'interval':'3600',
# 	'parent':'solEngInverter',
# 	'limit':'0',
# 	'file':'Inverter_solEngInverter.csv',
# 	'property':'power_A,power_B,power_C',
# 	'object': 'recorder'}
feeder.adjustTime(myTree, 240, 'hours', '2014-01-01')

# Run here to test.
rawOut = runInFilesystem(myTree,
                         attachments=myFeed['attachments'],
                         keepFiles=True,
                         workDir='.',
                         glmName='Orville Tree Pond Calibrated.glm')

# # Show some output.
# print 'Output Keys:', rawOut.keys()
# plt.plot([abs(complex(x)) for x in rawOut['Inverter_solEngInverter.csv']['power_A']])
# plt.show()

# Write back the full feeder.
outJson = dict(myFeed)
Beispiel #4
0
def attachVolts(workDir, feederPath, voltVectorA, voltVectorB, voltVectorC,
                simStartDate, simLength, simLengthUnits):
    '''read voltage vectors of 3 different phases, run gridlabd, and attach output to the feeder.'''
    try:
        timeStamp = [simStartDate['Date']]
        for x in range(1, 8760):
            timeStamp.append(timeStamp[x - 1] + dt.timedelta(hours=1))
        firstDateTime = timeStamp[1]
        with open(pJoin(pJoin(workDir, "gridlabD"), "phaseAVoltage.player"),
                  "w") as voltFile:
            for x in range(0, 8760):
                timestamp = timeStamp[x]
                voltage = str("%0.2f" % float(voltVectorA[x])) + "+0j"
                line = timestamp.strftime(
                    "%Y-%m-%d %H:%M:%S"
                ) + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
                voltFile.write(line)
        with open(pJoin(pJoin(workDir, "gridlabD"), "phaseBVoltage.player"),
                  "w") as voltFile:
            for x in range(0, 8760):
                timestamp = timeStamp[x]
                voltage = str("%0.2f" % float(voltVectorB[x])) + "-" + str(
                    "%0.4f" % float(random.uniform(6449, 6460))) + "j"
                line = timestamp.strftime(
                    "%Y-%m-%d %H:%M:%S"
                ) + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
                voltFile.write(line)
        with open(pJoin(pJoin(workDir, "gridlabD"), "phaseCVoltage.player"),
                  "w") as voltFile:
            for x in range(0, 8760):
                timestamp = timeStamp[x]
                voltage = str("%0.2f" % float(voltVectorC[x])) + "+" + str(
                    "%0.4f" % float(random.uniform(6449, 6460))) + "j"
                line = timestamp.strftime(
                    "%Y-%m-%d %H:%M:%S"
                ) + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
                voltFile.write(line)
        with open(feederPath, "r") as jsonIn:
            feederJson = json.load(jsonIn)
            tree = feederJson.get("tree", {})
        # Find swingNode name.
        for key in tree:
            if tree[key].get('bustype', '').lower() == 'swing':
                swingName = tree[key].get('name')
        # Attach player.
        classOb = {'omftype': 'class player', 'argument': '{double value;}'}
        voltageObA = {
            "object": "player",
            "property": "voltage_A",
            "file": "phaseAVoltage.player",
            "loop": "0",
            "parent": swingName
        }
        voltageObB = {
            "object": "player",
            "property": "voltage_B",
            "file": "phaseBVoltage.player",
            "loop": "0",
            "parent": swingName
        }
        voltageObC = {
            "object": "player",
            "property": "voltage_C",
            "file": "phaseCVoltage.player",
            "loop": "0",
            "parent": swingName
        }
        maxKey = feeder.getMaxKey(tree)
        voltplayerKeyA = maxKey + 2
        voltplayerKeyB = maxKey + 3
        voltplayerKeyC = maxKey + 4
        tree[maxKey + 1] = classOb
        tree[voltplayerKeyA] = voltageObA
        tree[voltplayerKeyB] = voltageObB
        tree[voltplayerKeyC] = voltageObC
        # Adjust time and run output.
        feeder.adjustTime(tree, simLength, simLengthUnits,
                          firstDateTime.strftime("%Y-%m-%d %H:%M:%S"))
        output = gridlabd.runInFilesystem(tree,
                                          keepFiles=True,
                                          workDir=pJoin(workDir, "gridlabD"))
        # Write the output.
        with open(pJoin(workDir, "calibratedFeeder.omd"), "w") as outJson:
            playerStringA = open(
                pJoin(pJoin(workDir, "gridlabD"),
                      "phaseAVoltage.player")).read()
            playerStringB = open(
                pJoin(pJoin(workDir, "gridlabD"),
                      "phaseBVoltage.player")).read()
            playerStringC = open(
                pJoin(pJoin(workDir, "gridlabD"),
                      "phaseCVoltage.player")).read()
            feederJson["attachments"]["phaseAVoltage.player"] = playerStringA
            feederJson["attachments"]["phaseBVoltage.player"] = playerStringB
            feederJson["attachments"]["phaseCVoltage.player"] = playerStringC
            feederJson["tree"] = tree
            json.dump(feederJson, outJson, indent=4)
        return pJoin(workDir, "calibratedFeeder.omd"), True
    except:
        print "Failed to run gridlabD with voltage players."
        return "", False
Beispiel #5
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)
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)
Beispiel #7
0
def omfCalibrate(workDir, feederPath, scadaPath, simStartDate, simLength):
	'''calibrates a feeder and saves the calibrated tree at a location'''
	with open(feederPath, "r") as jsonIn:
		feederJson = json.load(jsonIn)
		tree = feederJson.get("tree", {})
	# Process scada data.
	gridlabdDir = pJoin(workDir,"gridlabD")
	scadaSubPower = _processScadaData(gridlabdDir,scadaPath, simStartDate)
	# Force FBS powerflow, because NR fails a lot.
	for key in tree:
		if tree[key].get("module","").lower() == "powerflow":
			tree[key] = {"module":"powerflow","solver_method":"FBS"}
	# Attach player.
	classOb = {'omftype':'class player','argument':'{double value;}'}
	playerOb = {"object":"player", "property":"value", "name":"scadaLoads", "file":"subScada.player", "loop":"0"}
	maxKey = feeder.getMaxKey(tree)
	playerKey = maxKey + 2
	tree[maxKey+1] = classOb
	tree[playerKey] = playerOb
	# Make loads reference player.
	loadTemplate = {"object": "triplex_load",
		"power_pf_12": "0.95",
		"impedance_pf_12": "0.98",
		"power_pf_12": "0.90",
		"impedance_fraction_12": "0.7",
		"power_fraction_12": "0.3"}
	loadTemplateR = {"object": "load",
		"impedance_pf_A": "0.98",
		"impedance_pf_B": "0.98",
		"impedance_pf_C": "0.98",
		"power_pf_A": "0.90",
		"power_pf_B": "0.90",
		"power_pf_C": "0.90",
		"impedance_fraction_A": "0.7",
		"impedance_fraction_B": "0.7",
		"impedance_fraction_C": "0.7",
		"power_fraction_A": "0.3",
		"power_fraction_B": "0.3",
		"power_fraction_C": "0.3"}		
	for key in tree:
		ob = tree[key]
		if ob.get("object","") == "triplex_node" and ob.get("power_12","") != "":
			# Add to triplex_nodes.
			newOb = dict(loadTemplate)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			oldPow = ob.get("power_12","").replace("j","d")
			pythagPower = gridlabd._strClean(oldPow)
			newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
			tree[key] = newOb
		elif ob.get("object","") == "load":
			# Add to residential_loads too.
			newOb = dict(loadTemplateR)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["load_class"] = ob.get("load_class", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			try:
				oldPow = ob.get("constant_power_A","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_A"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_B","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_B"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_C","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_C"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			tree[key] = newOb
	# Convert swing bus to a meter.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing' and tree[key].get('object','') != 'meter':
			swingName = tree[key].get('name')
			regIndex = key
			tree[key]['object'] = 'meter'	
	# Search for the substation meter and attach a recorder there.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing':
			swingName = tree[key].get('name')
	recOb = {"object": "recorder",
		"parent": swingName,
		"property": "measured_real_power,measured_reactive_power,measured_power",
		"file": "caliSub.csv",
		"interval": "900"}
	outputRecorderKey = maxKey + 3
	tree[outputRecorderKey] = recOb
	feeder.adjustTime(tree, simLength, "hours", simStartDate['Date'].strftime("%Y-%m-%d %H:%M:%S"))
	# Run Gridlabd, calculate scaling constant.
	def runPowerflowIter(tree,scadaSubPower, iterationTimes):
		'''Runs powerflow once, then iterates.'''
		print "Running calibration powerflow #1."
		output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=gridlabdDir)
		outRealPow = output["caliSub.csv"]["measured_real_power"]
		outImagPower = output["caliSub.csv"]["measured_reactive_power"]
		outAppPowerKw = [(x[0]**2 + x[1]**2)**0.5/1000 for x in zip(outRealPow, outImagPower)]
		lastFile = "subScada.player"
		nextFile = "subScadaCalibrated.player"
		nextPower = outAppPowerKw
		for i in range(1, iterationTimes+1):
			SCAL_CONST = sum(scadaSubPower[1:simLength])/sum(nextPower[1:simLength])
			print "Running calibration powerflow (iteration", str(i+1), "of", iterationTimes+1,") (SCAL_CONST: ", SCAL_CONST,")"
			newPlayData = []
			with open(pJoin(gridlabdDir, lastFile), "r") as playerFile:
				for line in playerFile:
					(key,val) = line.split(',')
					newPlayData.append(str(key) + ',' + str(float(val)*SCAL_CONST) + "\n")
			with open(pJoin(gridlabdDir, nextFile), "w") as playerFile:
				for row in newPlayData:
					playerFile.write(row)
			tree[playerKey]["file"] = nextFile
			tree[outputRecorderKey]["file"] = "caliSubCheck.csv"
			nextOutput = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=gridlabdDir)
			outRealPow2nd = nextOutput["caliSubCheck.csv"]["measured_real_power"]
			outImagPower2nd = nextOutput["caliSubCheck.csv"]["measured_reactive_power"]
			nextAppKw = [(x[0]**2 + x[1]**2)**0.5/1000
				for x in zip(outRealPow2nd, outImagPower2nd)]
			lastFile = nextFile
			nextFile = "subScadaCalibrated"+str(i)+".player"
			nextPower = outAppPowerKw
		return outRealPow, outRealPow2nd, lastFile
	iterationTimes = 1
	outRealPow, outRealPow2nd, lastFile = runPowerflowIter(tree,scadaSubPower,iterationTimes)
	caliPowVectors = [[float(element) for element in scadaSubPower[1:simLength]], [float(element)/1000 for element in outRealPow[1:simLength]], [float(element)/1000 for element in outRealPow2nd[1:simLength]]]
	labels = ["scadaSubPower","initialGuess","finalGuess"]
	colors = ['red','lightblue','blue']
	chartData = {"Title":"Substation Calibration Check (Iterated "+str(iterationTimes+1)+"X)", "fileName":"caliCheckPlot", "colors":colors,"labels":labels, "timeZone":simStartDate['timeZone']}
	plotLine(workDir, caliPowVectors, chartData, simStartDate['Date']+dt.timedelta(hours=1), 'hours')
	# Write the final output.
	with open(pJoin(workDir,"calibratedFeeder.json"),"w") as outJson:
		playerString = open(pJoin(gridlabdDir,lastFile)).read()
		feederJson["attachments"][lastFile] = playerString
		feederJson["tree"] = tree
		json.dump(feederJson, outJson, indent=4)
	return
Beispiel #8
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
    feederDir, feederName = inputDict["feederName"].split("___")
    shutil.copy(
        pJoin(__metaModel__._omfDir, "data", "Feeder", feederDir,
              feederName + ".json"), pJoin(modelDir, "feeder.json"))
    shutil.copy(
        pJoin(__metaModel__._omfDir, "data", "Climate",
              inputDict["climateName"] + ".tmy2"),
        pJoin(modelDir, "gldContainer", "climate.tmy2"))
    try:
        startTime = datetime.datetime.now()
        feederJson = json.load(open(pJoin(modelDir, "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)
        # 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:
        print "MODEL CRASHED", e
        # Cancel to get rid of extra background processes.
        try:
            os.remove(pJoin(modelDir, 'PPID.txt'))
        except:
            pass
        thisErr = traceback.format_exc()
        inputDict['stderr'] = thisErr
        with open(os.path.join(modelDir, 'stderr.txt'), 'w') as errorFile:
            errorFile.write(thisErr)
        # Dump input with error included.
        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
Beispiel #9
0
def runForeground(modelDir,inData):
	'''This reads a glm file, changes the method of powerflow and reruns'''
	try:
		startTime = datetime.now()
		#calibrate and run cvrdynamic	
		feederPath = pJoin(__metaModel__._omfDir,"data", "Feeder", inData["feederName"].split("___")[0], inData["feederName"].split("___")[1]+'.json')
		scadaPath = pJoin(__metaModel__._omfDir,"uploads",(inData["scadaFile"]+'.tsv'))
		calibrate.omfCalibrate(modelDir,feederPath,scadaPath)
		allOutput = {}
		print "here"
		with open(pJoin(modelDir,"calibratedFeeder.json"), "r") as jsonIn:
			feederJson = json.load(jsonIn)
			localTree = feederJson.get("tree", {})
		for key in localTree:
			if "solver_method" in localTree[key].keys():
				print "current solver method", localTree[key]["solver_method"] 
				localTree[key]["solver_method"] = 'FBS'
		#find the swing bus and recorder attached to substation
		for key in localTree:
			if localTree[key].get('bustype','').lower() == 'swing':
				swingIndex = key
				swingName = localTree[key].get('name')
			if localTree[key].get('object','') == 'regulator' and localTree[key].get('from','') == swingName:
				regIndex = key
				regConfName = localTree[key]['configuration']
		#find the regulator and capacitor names and combine to form a string for volt-var control object
		regKeys = []
		accum_reg = ""
		for key in localTree:
			if localTree[key].get("object","") == "regulator":
				accum_reg += localTree[key].get("name","ERROR") + ","
				regKeys.append(key)
		regstr = accum_reg[:-1]
		print regKeys
		capKeys = []
		accum_cap = ""
		for key in localTree:
			if localTree[key].get("object","") == "capacitor":
				accum_cap += localTree[key].get("name","ERROR") + ","
				capKeys.append(key)
				if localTree[key].get("control","").lower() == "manual":
					localTree[key]['control'] = "VOLT"
					print "changing capacitor control from manual to volt"
		capstr = accum_cap[:-1]
		print capKeys
		# Attach recorders relevant to CVR.
		recorders = [
				{'object': 'collector',
				'file': 'ZlossesTransformer.csv',
				'group': 'class=transformer',
				'limit': '0',
				'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
				{'object': 'collector',
				'file': 'ZlossesUnderground.csv',
				'group': 'class=underground_line',
				'limit': '0',
				'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
				{'object': 'collector',
				'file': 'ZlossesOverhead.csv',
				'group': 'class=overhead_line',
				'limit': '0',
				'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
				{'object': 'recorder',
				'file': 'Zregulator.csv',
				'limit': '0',
				'parent': localTree[regIndex]['name'],
				'property': 'tap_A,tap_B,tap_C,power_in.real,power_in.imag'},
				{'object': 'collector',
				'file': 'ZvoltageJiggle.csv',
				'group': 'class=triplex_meter',
				'limit': '0',
				'property': 'min(voltage_12.mag),mean(voltage_12.mag),max(voltage_12.mag),std(voltage_12.mag)'},
				{'object': 'recorder',
				'file': 'ZsubstationTop.csv',
				'limit': '0',
				'parent': localTree[swingIndex]['name'],
				'property': 'voltage_A,voltage_B,voltage_C'},
				{'object': 'recorder',
				'file': 'ZsubstationBottom.csv',
				'limit': '0',
				'parent': localTree[regIndex]['to'],
				'property': 'voltage_A,voltage_B,voltage_C'}]
		#recorder object for capacitor switching - if capacitors exist
		if capKeys != []:
			for key in capKeys:
				recorders.append({'object': 'recorder',
				'file': 'ZcapSwitch' + str(key) + '.csv',
				'limit': '0',
				'parent': localTree[key]['name'],
				'property': 'switchA,switchB,switchC'})
		#attach recorder process
		biggest = 1 + max([int(k) for k in localTree.keys()])
		for index, rec in enumerate(recorders):
			localTree[biggest + index] = rec
		#run a reference load flow
		HOURS = float(inData['simLengthHours'])
		simStartDate = inData['simStart']
		feeder.adjustTime(localTree,HOURS,"hours",simStartDate)	
		output = gridlabd.runInFilesystem(localTree,keepFiles=False,workDir=modelDir)
		os.remove(pJoin(modelDir,"PID.txt"))
		p = output['Zregulator.csv']['power_in.real']
		q = output['Zregulator.csv']['power_in.imag']
		#calculating length of simulation because it migth be different from the simulation input HOURS
		simRealLength = int(len(p))
		#time delays from configuration files
		time_delay_reg = '30.0'  
		time_delay_cap = '300.0'
		for key in localTree:
			if localTree[key].get('object','') == "regulator_configuration":
				time_delay_reg = localTree[key]['time_delay']
				print "time_delay_reg",time_delay_reg
			# if localTree[key].get('object','') == "capacitor":
			# 	time_delay_cap = localTree[key]['time_delay']
			# 	print "time_delay_cap",time_delay_cap
		#change the recorder names
		for key in localTree:
			if localTree[key].get('object','') == "collector" or localTree[key].get('object','') == "recorder":
				if localTree[key].get('file','').startswith('Z'):
					localTree[key]['file'] = localTree[key].get('file','').replace('Z','NewZ')
		#create volt-var control object
		max_key = max([int(key) for key in localTree.keys()])
		print max_key
		localTree[max_key+1] = {'object' : 'volt_var_control',
		'name' : 'IVVC1',
		'control_method' : 'ACTIVE',
		'capacitor_delay' : str(time_delay_cap),
		'regulator_delay' : str(time_delay_reg),
		'desired_pf' : '0.99',
		'd_max' : '0.6',
		'd_min' : '0.1',
		'substation_link' : str(localTree[regIndex]['name']),
		'regulator_list' : regstr,
		'capacitor_list': capstr} 
		#running powerflow analysis via gridalab after attaching a regulator
		feeder.adjustTime(localTree,HOURS,"hours",simStartDate)	
		output1 = gridlabd.runInFilesystem(localTree,keepFiles=True,workDir=modelDir)
		os.remove(pJoin(modelDir,"PID.txt"))
		pnew = output1['NewZregulator.csv']['power_in.real']
		qnew = output1['NewZregulator.csv']['power_in.imag']
		#total real and imaginary losses as a function of time
		def vecSum(u,v):
			''' Add vectors u and v element-wise. Return has len <= len(u) and <=len(v). '''
			return map(sum, zip(u,v))
		def zeroVec(length):
			''' Give a zero vector of input length. '''
			return [0 for x in xrange(length)]
		(realLoss, imagLoss, realLossnew, imagLossnew) = (zeroVec(int(HOURS)) for x in range(4))
		for device in ['ZlossesOverhead.csv','ZlossesTransformer.csv','ZlossesUnderground.csv']:
			for letter in ['A','B','C']:
				realLoss = vecSum(realLoss, output[device]['sum(power_losses_' + letter + '.real)'])
				imagLoss = vecSum(imagLoss, output[device]['sum(power_losses_' + letter + '.imag)'])
				realLossnew = vecSum(realLossnew, output1['New'+device]['sum(power_losses_' + letter + '.real)'])
				imagLossnew = vecSum(imagLossnew, output1['New'+device]['sum(power_losses_' + letter + '.imag)'])
		#voltage calculations and tap calculations
		def divby2(u):
			'''divides by 2'''
			return u/2
		lowVoltage = []
		meanVoltage = []
		highVoltage = []
		lowVoltagenew = []
		meanVoltagenew = []
		highVoltagenew = []
		tap = {'A':[],'B':[],'C':[]}
		tapnew = {'A':[],'B':[],'C':[]}
		volt = {'A':[],'B':[],'C':[]}
		voltnew = {'A':[],'B':[],'C':[]}
		switch = {'A':[],'B':[],'C':[]}
		switchnew = {'A':[],'B':[],'C':[]}
		for letter in ['A','B','C']:
			tap[letter] = output['Zregulator.csv']['tap_' + letter]
			tapnew[letter] = output1['NewZregulator.csv']['tap_' + letter]
			if capKeys != []:
				switch[letter] = output['ZcapSwitch' + str(int(capKeys[0])) + '.csv']['switch'+ letter]
				switchnew[letter] = output1['NewZcapSwitch' + str(int(capKeys[0])) + '.csv']['switch'+ letter]
			volt[letter] = map(returnMag,output['ZsubstationBottom.csv']['voltage_'+letter])
			voltnew[letter] = map(returnMag,output1['NewZsubstationBottom.csv']['voltage_'+letter])
		lowVoltage = map(divby2,output['ZvoltageJiggle.csv']['min(voltage_12.mag)'])
		lowVoltagenew = map(divby2,output1['NewZvoltageJiggle.csv']['min(voltage_12.mag)'])
		meanVoltage = map(divby2,output['ZvoltageJiggle.csv']['mean(voltage_12.mag)'])
		meanVoltagenew = map(divby2,output1['NewZvoltageJiggle.csv']['mean(voltage_12.mag)'])
		highVoltage = map(divby2,output['ZvoltageJiggle.csv']['max(voltage_12.mag)'])
		highVoltagenew = map(divby2,output1['NewZvoltageJiggle.csv']['max(voltage_12.mag)'])
		#energy calculations
		whEnergy = []
		whLosses = []
		whLoads = []
		whEnergy.append(sum(p)/10**6)
		whLosses.append(sum(realLoss)/10**6)
		whLoads.append((sum(p)-sum(realLoss))/10**6)
		whEnergy.append(sum(pnew)/10**6)
		whLosses.append(sum(realLossnew)/10**6)
		whLoads.append((sum(pnew)-sum(realLossnew))/10**6)
		indices = ['No IVVC', 'With IVVC']
		# energySalesRed = (whLoads[1]-whLoads[0])*(inData['wholesaleEnergyCostPerKwh'])*1000
		# lossSav = (whLosses[0]-whLosses[1])*inData['wholesaleEnergyCostPerKwh']*1000
		# print energySalesRed, lossSav
		#plots
		ticks = []
		plt.clf()
		plt.title("total energy")
		plt.ylabel("total load and losses (MWh)")
		for element in range(2):
			ticks.append(element)
			bar_loss = plt.bar(element, whLosses[element], 0.15, color= 'red')
			bar_load = plt.bar(element+0.15, whLoads[element], 0.15, color= 'orange')
		plt.legend([bar_load[0],bar_loss[0]],['total load', 'total losses'],bbox_to_anchor=(0., 0.915, 1., .102), loc=3,
			       ncol=2, mode="expand", borderaxespad=0.1)
		plt.xticks([t+0.15 for t in ticks],indices)
		plt.savefig(pJoin(modelDir,"totalEnergy.png"))
		#real and imaginary power
		plt.figure("real power")
		plt.title("Real Power at substation")
		plt.ylabel("substation real power (MW)")
		pMW = [element/10**6 for element in p]
		pMWn = [element/10**6 for element in pnew]
		pw = plt.plot(pMW)
		npw = plt.plot(pMWn)
		plt.legend([pw[0], npw[0]], ['NO IVVC','WITH IVVC'],bbox_to_anchor=(0., 0.915, 1., .102), loc=3,
			ncol=2, mode="expand", borderaxespad=0.1)
		plt.savefig(pJoin(modelDir,"realPower.png"))
		plt.figure("Reactive power")
		plt.title("Reactive Power at substation")
		plt.ylabel("substation reactive power (MVAR)")
		qMVAR = [element/10**6 for element in q]
		qMVARn = [element/10**6 for element in qnew]
		iw = plt.plot(qMVAR)
		niw = plt.plot(qMVARn)
		plt.legend([iw[0], niw[0]], ['NO IVVC','WITH IVVC'],bbox_to_anchor=(0., 0.915, 1., .102), loc=3,
			ncol=2, mode="expand", borderaxespad=0.1)
		plt.savefig(pJoin(modelDir,"imaginaryPower.png"))
		#voltage plots
		plt.figure("voltages as a function of time")
		f,ax = plt.subplots(2,sharex=True)
		f.suptitle("Min and Max voltages on the feeder")
		lv = ax[0].plot(lowVoltage,color = 'cadetblue')
		mv = ax[0].plot(meanVoltage,color = 'blue')
		hv = ax[0].plot(highVoltage, color = 'cadetblue')
		ax[0].legend([lv[0], mv[0], hv[0]], ['low voltage','mean voltage','high voltage'],bbox_to_anchor=(0., 0.915, 1., .1), loc=3,
			ncol=3, mode="expand", borderaxespad=0.1)
		ax[0].set_ylabel('NO IVVC')
		nlv = ax[1].plot(lowVoltagenew,color = 'cadetblue')
		nmv = ax[1].plot(meanVoltagenew,color = 'blue')
		nhv = ax[1].plot(highVoltagenew, color = 'cadetblue')
		ax[1].set_ylabel('WITH IVVC')
		plt.savefig(pJoin(modelDir,"Voltages.png"))
		#tap positions
		plt.figure("TAP positions NO IVVC")
		f,ax = plt.subplots(6,sharex=True)
		f.set_size_inches(10,12.0)
		#f.suptitle("Regulator Tap positions")
		ax[0].plot(tap['A'])
		ax[0].set_title("Regulator Tap positions NO IVVC")
		ax[0].set_ylabel("TAP A")
		ax[1].plot(tap['B'])
		ax[1].set_ylabel("TAP B")
		ax[2].plot(tap['C'])
		ax[2].set_ylabel("TAP C")
		ax[3].plot(tapnew['A'])
		ax[3].set_title("WITH IVVC")
		ax[3].set_ylabel("TAP A")
		ax[4].plot(tapnew['B'])
		ax[4].set_ylabel("TAP B")
		ax[5].plot(tapnew['C'])
		ax[5].set_ylabel("TAP C")
		for subplot in range(6):
			ax[subplot].set_ylim(-20,20)
		f.tight_layout()
		plt.savefig(pJoin(modelDir,"RegulatorTAPpositions.png"))
		#substation voltages
		plt.figure("substation voltage as a function of time")
		f,ax = plt.subplots(6,sharex=True)
		f.set_size_inches(10,12.0)
		#f.suptitle("voltages at substation NO IVVC")
		ax[0].plot(volt['A'])
		ax[0].set_title('Substation voltages NO IVVC')
		ax[0].set_ylabel('voltage A')
		ax[1].plot(volt['B'])
		ax[1].set_ylabel('voltage B')
		ax[2].plot(volt['C'])
		ax[2].set_ylabel('voltage C')
		ax[3].plot(voltnew['A'])
		ax[3].set_title("WITH IVVC")
		ax[3].set_ylabel('voltage A')
		ax[4].plot(voltnew['B'])
		ax[4].set_ylabel('voltage B')
		ax[5].plot(voltnew['C'])
		ax[5].set_ylabel('voltage C')
		f.tight_layout()
		plt.savefig(pJoin(modelDir,"substationVoltages.png"))
		#cap switches
		plt.figure("capacitor switch state as a function of time")
		f,ax = plt.subplots(6,sharex=True)
		f.set_size_inches(10,12.0)
		#f.suptitle("Capacitor switch state NO IVVC")
		ax[0].plot(switch['A'])
		ax[0].set_title("Capacitor switch state NO IVVC")
		ax[0].set_ylabel("switch A")
		ax[1].plot(switch['B'])
		ax[1].set_ylabel("switch B")
		ax[2].plot(switch['C'])
		ax[2].set_ylabel("switch C")
		ax[3].plot(switchnew['A'])
		ax[3].set_title("WITH IVVC")
		ax[3].set_ylabel("switch A")
		ax[4].plot(switchnew['B'])
		ax[4].set_ylabel("switch B")
		ax[5].plot(switchnew['C'])
		ax[5].set_ylabel("switch C")
		for subplot in range(6):
			ax[subplot].set_ylim(-2,2)
		f.tight_layout()
		plt.savefig(pJoin(modelDir,"capacitorSwitch.png"))
		#plt.show()
		#monetization
		monthNames = ["January", "February", "March", "April", "May", "June", "July", "August",
			"September", "October", "November", "December"]
		monthToSeason = {'January':'Winter','February':'Winter','March':'Spring','April':'Spring',
			'May':'Spring','June':'Summer','July':'Summer','August':'Summer',
			'September':'Fall','October':'Fall','November':'Fall','December':'Winter'}
		#calculate the month and hour of simulation start and month and hour of simulation end
		simStartTimestamp = simStartDate + " 00:00:00"
		simFormattedDate = datetime.strptime(simStartTimestamp,"%Y-%m-%d %H:%M:%S")
		simStartMonthNum = int(simFormattedDate.strftime('%m'))
		simstartMonth = monthNames[simStartMonthNum-1]
		simStartDay = int(simFormattedDate.strftime('%d'))
		if calendar.isleap(int(simFormattedDate.strftime('%Y'))):
			febDays = 29
		else:
			febDays = 28
		monthHours = [int(31*24),int(febDays*24),int(31*24),int(30*24),int(31*24),int(30*24),int(31*24),int(31*24),int(30*24),int(31*24),int(30*24),int(31*24)]
		simStartIndex = int(sum(monthHours[:(simStartMonthNum-1)])+(simStartDay-1)*24)
		temp = 0
		cumulHours = [0]
		for x in range(12):
			temp += monthHours[x]
			cumulHours.append(temp)
		for i in range((simStartMonthNum),13):
			if int(simStartIndex+simRealLength)<=cumulHours[i] and int(simStartIndex+simRealLength)>cumulHours[i-1]:
				simEndMonthNum = i-1
				simEndMonth = monthNames[simEndMonthNum]
		print simstartMonth,simEndMonth
		#calculate peaks for the number of months in simulation
		previndex = 0
		monthPeak = {}
		monthPeakNew = {}
		peakSaveDollars = {}
		energyLostDollars = {}
		lossRedDollars = {}
		simMonthList = monthNames[monthNames.index(simstartMonth):(monthNames.index(simEndMonth)+1)] 
		print simMonthList
		for monthElement in simMonthList:
			print monthElement
			month = monthNames.index(monthElement)
			index1 = int(previndex)
			index2 = int(min((index1 + int(monthHours[month])), simRealLength))
			monthPeak[monthElement] = max(p[index1:index2])/1000.0
			monthPeakNew[monthElement] = max(pnew[index1:index2])/1000.0
			peakSaveDollars[monthElement] = (monthPeak[monthElement]-monthPeakNew[monthElement])*float(inData['peakDemandCost'+str(monthToSeason[monthElement])+'PerKw'])
			lossRedDollars[monthElement] = (sum(realLoss[index1:index2])/1000.0 - sum(realLossnew[index1:index2])/1000.0)*(float(inData['wholesaleEnergyCostPerKwh']))
			energyLostDollars[monthElement] = (sum(p[index1:index2])/1000.0  - sum(pnew[index1:index2])/1000.0  - sum(realLoss[index1:index2])/1000.0  
				+ sum(realLossnew[index1:index2])/1000.0 )*(float(inData['wholesaleEnergyCostPerKwh']) - float(inData['retailEnergyCostPerKwh']))
			previndex = index2
		#money charts
		fig = plt.figure("cost benefit barchart",figsize=(10,8))
		ticks = range(len(simMonthList))
		ticks1 = [element+0.15 for element in ticks]
		ticks2 = [element+0.30 for element in ticks]
		print ticks
		eld = [energyLostDollars[month] for month in simMonthList]
		lrd = [lossRedDollars[month] for month in simMonthList]
		psd = [peakSaveDollars[month] for month in simMonthList]
		bar_eld = plt.bar(ticks,eld,0.15,color='red') 
		bar_psd = plt.bar(ticks1,psd,0.15,color='blue')
		bar_lrd = plt.bar(ticks2,lrd,0.15,color='green')
		plt.legend([bar_eld[0], bar_psd[0], bar_lrd[0]], ['energyLostDollars','peakReductionDollars','lossReductionDollars'],bbox_to_anchor=(0., 1.015, 1., .102), loc=3,
			ncol=2, mode="expand", borderaxespad=0.1)
		monShort = [element[0:3] for element in simMonthList]
		plt.xticks([t+0.15 for t in ticks],monShort)
		plt.ylabel('Utility Savings ($)')
		plt.savefig(pJoin(modelDir,"spendChart.png"))
		#cumulative savings graphs
		fig = plt.figure("cost benefit barchart",figsize=(10,5))
		annualSavings = sum(eld) + sum(lrd) + sum(psd)
		annualSave = lambda x:(annualSavings - float(inData['omCost'])) * x - float(inData['capitalCost'])
		simplePayback = float(inData['capitalCost'])/(annualSavings - float(inData['omCost']))
		plt.xlabel('Year After Installation')
		plt.xlim(0,30)
		plt.ylabel('Cumulative Savings ($)')
		plt.plot([0 for x in range(31)],c='gray')
		plt.axvline(x=simplePayback, ymin=0, ymax=1, c='gray', linestyle='--')
		plt.plot([annualSave(x) for x in range(31)], c='green')
		plt.savefig(pJoin(modelDir,"savingsChart.png"))
		#get exact time stamps from the CSV files generated by Gridlab-D
		timeWithZone =  output['Zregulator.csv']['# timestamp']
		timestamps = [element[:19] for element in timeWithZone]
		#data for highcharts
		allOutput["timeStamps"] = timestamps
		allOutput["noCVRPower"] = p
		allOutput["withCVRPower"] = pnew
		allOutput["noCVRLoad"] = whLoads[0]
		allOutput["withCVRLoad"] = whLoads[1]
		allOutput["noCVRLosses"] = whLosses[0]
		allOutput["withCVRLosses"] = whLosses[1]
		allOutput["noCVRTaps"] = tap
		allOutput["withCVRTaps"] = tapnew
		allOutput["noCVRSubVolts"] = volt
		allOutput["withCVRSubVolts"] = voltnew
		allOutput["noCVRCapSwitch"] = switch
		allOutput["withCVRCapSwitch"] = switchnew
		allOutput["noCVRHighVolt"] = highVoltage
		allOutput["withCVRHighVolt"] = highVoltagenew
		allOutput["noCVRLowVolt"] = lowVoltage
		allOutput["withCVRLowVolt"] = lowVoltagenew
		allOutput["noCVRMeanVolt"] = meanVoltage
		allOutput["withCVRMeanVolt"] = meanVoltagenew
		#monetization
		allOutput["simMonthList"] = monShort
		allOutput["energyLostDollars"] = energyLostDollars
		allOutput["lossRedDollars"] = lossRedDollars
		allOutput["peakSaveDollars"] = peakSaveDollars
		allOutput["annualSave"] = [annualSave(x) for x in range(31)]
		# Update the runTime in the input file.
		endTime = datetime.now()
		inData["runTime"] = str(timedelta(seconds=int((endTime - startTime).total_seconds())))
		with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
			json.dump(inData, inFile, indent=4)
		with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile:
			json.dump(allOutput, outFile, indent=4)
		# For autotest, there won't be such file.
		try:
			os.remove(pJoin(modelDir, "PPID.txt"))
		except:
			pass
		print "DONE RUNNING", modelDir
	except Exception as e:
		print "Oops, Model Crashed!!!" 
		cancel(modelDir)
		print e
Beispiel #10
0
def runForeground(modelDir, inData):
    '''This reads a glm file, changes the method of powerflow and reruns'''
    print "STARTING TO RUN", modelDir
    try:
        startTime = datetime.now()
        if not os.path.isdir(modelDir):
            os.makedirs(modelDir)
            inData["created"] = str(startTime)
        #read pre-calibrated feeder and run cvrdynamic
        feederName = inData.get('feederName1', 'feeder1')
        feederPath = pJoin(modelDir, feederName + '.omd')
        # Reads a pre-calibrated feeder.
        allOutput = {}
        with open(feederPath, "r") as jsonIn:
            feederJson = json.load(jsonIn)
            localTree = feederJson.get("tree", {})
            attachments = feederJson.get("attachments", {})
        for key in localTree:
            if "solver_method" in localTree[key].keys():
                # print "current solver method", localTree[key]["solver_method"]
                localTree[key]["solver_method"] = 'FBS'
        #find the swing bus and recorder attached to substation
        try:
            for key in localTree:
                if localTree[key].get('bustype', '').lower() == 'swing':
                    swingIndex = key
                    swingName = localTree[key].get('name')
                if localTree[key].get(
                        'object', '') == 'regulator' and localTree[key].get(
                            'from', '') == swingName:
                    regIndex = key
                    regConfName = localTree[key]['configuration']
        except:
            raise ValueError('Invalid feeder selected:',
                             str(inData["feederName1"]))
        #find the regulator and capacitor names and combine to form a string for volt-var control object
        regKeys = []
        accum_reg = ""
        for key in localTree:
            if localTree[key].get("object", "") == "regulator":
                accum_reg += localTree[key].get("name", "ERROR") + ","
                regKeys.append(key)
        regstr = accum_reg[:-1]
        # print regKeys
        capKeys = []
        accum_cap = ""
        for key in localTree:
            if localTree[key].get("object", "") == "capacitor":
                accum_cap += localTree[key].get("name", "ERROR") + ","
                capKeys.append(key)
                if localTree[key].get("control", "").lower() == "manual":
                    localTree[key]['control'] = "VOLT"
                    # print "changing capacitor control from manual to volt"
        capstr = accum_cap[:-1]
        # print capKeys
        # Attach recorders relevant to CVR.
        recorders = [{
            'object':
            'collector',
            'file':
            'ZlossesTransformer.csv',
            'group':
            'class=transformer',
            'limit':
            '0',
            'property':
            'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
        }, {
            'object':
            'collector',
            'file':
            'ZlossesUnderground.csv',
            'group':
            'class=underground_line',
            'limit':
            '0',
            'property':
            'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
        }, {
            'object':
            'collector',
            'file':
            'ZlossesOverhead.csv',
            'group':
            'class=overhead_line',
            'limit':
            '0',
            'property':
            'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
        }, {
            'object':
            'recorder',
            'file':
            'Zregulator.csv',
            'limit':
            '0',
            'parent':
            localTree[regIndex]['name'],
            'property':
            'tap_A,tap_B,tap_C,power_in.real,power_in.imag'
        }, {
            'object':
            'collector',
            'file':
            'ZvoltageJiggle.csv',
            'group':
            'class=triplex_meter',
            'limit':
            '0',
            'property':
            'min(voltage_12.mag),mean(voltage_12.mag),max(voltage_12.mag),std(voltage_12.mag)'
        }, {
            'object': 'recorder',
            'file': 'ZsubstationTop.csv',
            'limit': '0',
            'parent': localTree[swingIndex]['name'],
            'property': 'voltage_A,voltage_B,voltage_C'
        }, {
            'object': 'recorder',
            'file': 'ZsubstationBottom.csv',
            'limit': '0',
            'parent': localTree[regIndex]['to'],
            'property': 'voltage_A,voltage_B,voltage_C'
        }]
        #recorder object for capacitor switching - if capacitors exist
        if capKeys != []:
            for key in capKeys:
                recorders.append({
                    'object': 'recorder',
                    'file': 'ZcapSwitch' + str(key) + '.csv',
                    'limit': '0',
                    'parent': localTree[key]['name'],
                    'property': 'switchA,switchB,switchC'
                })
        #attach recorder process
        biggest = 1 + max([int(k) for k in localTree.keys()])
        for index, rec in enumerate(recorders):
            localTree[biggest + index] = rec
        #run a reference load flow
        HOURS = float(inData['simLengthHours'])
        simStartDate = inData['simStart']
        feeder.adjustTime(localTree, HOURS, "hours", simStartDate)
        output = gridlabd.runInFilesystem(localTree,
                                          attachments,
                                          keepFiles=False,
                                          workDir=modelDir)
        try:
            os.remove(pJoin(modelDir, "PID.txt"))
        except:
            pass
        p = output['Zregulator.csv']['power_in.real']
        q = output['Zregulator.csv']['power_in.imag']
        #calculating length of simulation because it migth be different from the simulation input HOURS
        simRealLength = int(len(p))
        #time delays from configuration files
        time_delay_reg = '30.0'
        time_delay_cap = '300.0'
        for key in localTree:
            if localTree[key].get('object', '') == "regulator_configuration":
                time_delay_reg = localTree[key]['time_delay']
                # print "time_delay_reg",time_delay_reg
            # if localTree[key].get('object','') == "capacitor":
            # 	time_delay_cap = localTree[key]['time_delay']
            # 	print "time_delay_cap",time_delay_cap
        #change the recorder names
        for key in localTree:
            if localTree[key].get('object',
                                  '') == "collector" or localTree[key].get(
                                      'object', '') == "recorder":
                if localTree[key].get('file', '').startswith('Z'):
                    localTree[key]['file'] = localTree[key].get(
                        'file', '').replace('Z', 'NewZ')
        #create volt-var control object
        max_key = max([int(key) for key in localTree.keys()])
        # print max_key
        localTree[max_key + 1] = {
            'object': 'volt_var_control',
            'name': 'IVVC1',
            'control_method': 'ACTIVE',
            'capacitor_delay': str(time_delay_cap),
            'regulator_delay': str(time_delay_reg),
            'desired_pf': '0.99',
            'd_max': '0.6',
            'd_min': '0.1',
            'substation_link': str(localTree[regIndex]['name']),
            'regulator_list': regstr,
            'capacitor_list': capstr,
            'voltage_measurements': str(inData.get("voltageNodes", 0)),
        }
        #running powerflow analysis via gridalab after attaching a regulator
        feeder.adjustTime(localTree, HOURS, "hours", simStartDate)
        output1 = gridlabd.runInFilesystem(localTree,
                                           attachments,
                                           keepFiles=True,
                                           workDir=modelDir)
        os.remove(pJoin(modelDir, "PID.txt"))
        pnew = output1['NewZregulator.csv']['power_in.real']
        qnew = output1['NewZregulator.csv']['power_in.imag']

        #total real and imaginary losses as a function of time
        def vecSum(u, v):
            ''' Add vectors u and v element-wise. Return has len <= len(u) and <=len(v). '''
            return map(sum, zip(u, v))

        def zeroVec(length):
            ''' Give a zero vector of input length. '''
            return [0 for x in xrange(length)]

        (realLoss, imagLoss, realLossnew, imagLossnew) = (zeroVec(int(HOURS))
                                                          for x in range(4))
        for device in [
                'ZlossesOverhead.csv', 'ZlossesTransformer.csv',
                'ZlossesUnderground.csv'
        ]:
            for letter in ['A', 'B', 'C']:
                realLoss = vecSum(
                    realLoss,
                    output[device]['sum(power_losses_' + letter + '.real)'])
                imagLoss = vecSum(
                    imagLoss,
                    output[device]['sum(power_losses_' + letter + '.imag)'])
                realLossnew = vecSum(
                    realLossnew, output1['New' + device]['sum(power_losses_' +
                                                         letter + '.real)'])
                imagLossnew = vecSum(
                    imagLossnew, output1['New' + device]['sum(power_losses_' +
                                                         letter + '.imag)'])
        #voltage calculations and tap calculations
        def divby2(u):
            '''divides by 2'''
            return u / 2

        lowVoltage = []
        meanVoltage = []
        highVoltage = []
        lowVoltagenew = []
        meanVoltagenew = []
        highVoltagenew = []
        tap = {'A': [], 'B': [], 'C': []}
        tapnew = {'A': [], 'B': [], 'C': []}
        volt = {'A': [], 'B': [], 'C': []}
        voltnew = {'A': [], 'B': [], 'C': []}
        switch = {'A': [], 'B': [], 'C': []}
        switchnew = {'A': [], 'B': [], 'C': []}
        for letter in ['A', 'B', 'C']:
            tap[letter] = output['Zregulator.csv']['tap_' + letter]
            tapnew[letter] = output1['NewZregulator.csv']['tap_' + letter]
            if capKeys != []:
                switch[letter] = output['ZcapSwitch' + str(int(capKeys[0])) +
                                        '.csv']['switch' + letter]
                switchnew[letter] = output1['NewZcapSwitch' +
                                            str(int(capKeys[0])) +
                                            '.csv']['switch' + letter]
            volt[letter] = map(
                returnMag,
                output['ZsubstationBottom.csv']['voltage_' + letter])
            voltnew[letter] = map(
                returnMag,
                output1['NewZsubstationBottom.csv']['voltage_' + letter])
        lowVoltage = map(divby2,
                         output['ZvoltageJiggle.csv']['min(voltage_12.mag)'])
        lowVoltagenew = map(
            divby2, output1['NewZvoltageJiggle.csv']['min(voltage_12.mag)'])
        meanVoltage = map(divby2,
                          output['ZvoltageJiggle.csv']['mean(voltage_12.mag)'])
        meanVoltagenew = map(
            divby2, output1['NewZvoltageJiggle.csv']['mean(voltage_12.mag)'])
        highVoltage = map(divby2,
                          output['ZvoltageJiggle.csv']['max(voltage_12.mag)'])
        highVoltagenew = map(
            divby2, output1['NewZvoltageJiggle.csv']['max(voltage_12.mag)'])
        #energy calculations
        whEnergy = []
        whLosses = []
        whLoads = []
        whEnergy.append(sum(p) / 10**6)
        whLosses.append(sum(realLoss) / 10**6)
        whLoads.append((sum(p) - sum(realLoss)) / 10**6)
        whEnergy.append(sum(pnew) / 10**6)
        whLosses.append(sum(realLossnew) / 10**6)
        whLoads.append((sum(pnew) - sum(realLossnew)) / 10**6)
        indices = ['No IVVC', 'With IVVC']
        # energySalesRed = (whLoads[1]-whLoads[0])*(inData['wholesaleEnergyCostPerKwh'])*1000
        # lossSav = (whLosses[0]-whLosses[1])*inData['wholesaleEnergyCostPerKwh']*1000
        # print energySalesRed, lossSav
        #plots
        ticks = []
        plt.clf()
        plt.title("total energy")
        plt.ylabel("total load and losses (MWh)")
        for element in range(2):
            ticks.append(element)
            bar_loss = plt.bar(element, whLosses[element], 0.15, color='red')
            bar_load = plt.bar(element + 0.15,
                               whLoads[element],
                               0.15,
                               color='orange')
        plt.legend([bar_load[0], bar_loss[0]], ['total load', 'total losses'],
                   bbox_to_anchor=(0., 0.915, 1., .102),
                   loc=3,
                   ncol=2,
                   mode="expand",
                   borderaxespad=0.1)
        plt.xticks([t + 0.15 for t in ticks], indices)
        plt.savefig(pJoin(modelDir, "totalEnergy.png"))
        #real and imaginary power
        plt.figure("real power")
        plt.title("Real Power at substation")
        plt.ylabel("substation real power (MW)")
        pMW = [element / 10**6 for element in p]
        pMWn = [element / 10**6 for element in pnew]
        pw = plt.plot(pMW)
        npw = plt.plot(pMWn)
        plt.legend([pw[0], npw[0]], ['NO IVVC', 'WITH IVVC'],
                   bbox_to_anchor=(0., 0.915, 1., .102),
                   loc=3,
                   ncol=2,
                   mode="expand",
                   borderaxespad=0.1)
        plt.savefig(pJoin(modelDir, "realPower.png"))
        plt.figure("Reactive power")
        plt.title("Reactive Power at substation")
        plt.ylabel("substation reactive power (MVAR)")
        qMVAR = [element / 10**6 for element in q]
        qMVARn = [element / 10**6 for element in qnew]
        iw = plt.plot(qMVAR)
        niw = plt.plot(qMVARn)
        plt.legend([iw[0], niw[0]], ['NO IVVC', 'WITH IVVC'],
                   bbox_to_anchor=(0., 0.915, 1., .102),
                   loc=3,
                   ncol=2,
                   mode="expand",
                   borderaxespad=0.1)
        plt.savefig(pJoin(modelDir, "imaginaryPower.png"))
        #voltage plots
        plt.figure("voltages as a function of time")
        f, ax = plt.subplots(2, sharex=True)
        f.suptitle("Min and Max voltages on the feeder")
        lv = ax[0].plot(lowVoltage, color='cadetblue')
        mv = ax[0].plot(meanVoltage, color='blue')
        hv = ax[0].plot(highVoltage, color='cadetblue')
        ax[0].legend([lv[0], mv[0], hv[0]],
                     ['low voltage', 'mean voltage', 'high voltage'],
                     bbox_to_anchor=(0., 0.915, 1., .1),
                     loc=3,
                     ncol=3,
                     mode="expand",
                     borderaxespad=0.1)
        ax[0].set_ylabel('NO IVVC')
        nlv = ax[1].plot(lowVoltagenew, color='cadetblue')
        nmv = ax[1].plot(meanVoltagenew, color='blue')
        nhv = ax[1].plot(highVoltagenew, color='cadetblue')
        ax[1].set_ylabel('WITH IVVC')
        plt.savefig(pJoin(modelDir, "Voltages.png"))
        #tap positions
        plt.figure("TAP positions NO IVVC")
        f, ax = plt.subplots(6, sharex=True)
        f.set_size_inches(10, 12.0)
        #f.suptitle("Regulator Tap positions")
        ax[0].plot(tap['A'])
        ax[0].set_title("Regulator Tap positions NO IVVC")
        ax[0].set_ylabel("TAP A")
        ax[1].plot(tap['B'])
        ax[1].set_ylabel("TAP B")
        ax[2].plot(tap['C'])
        ax[2].set_ylabel("TAP C")
        ax[3].plot(tapnew['A'])
        ax[3].set_title("WITH IVVC")
        ax[3].set_ylabel("TAP A")
        ax[4].plot(tapnew['B'])
        ax[4].set_ylabel("TAP B")
        ax[5].plot(tapnew['C'])
        ax[5].set_ylabel("TAP C")
        for subplot in range(6):
            ax[subplot].set_ylim(-20, 20)
        f.tight_layout()
        plt.savefig(pJoin(modelDir, "RegulatorTAPpositions.png"))
        #substation voltages
        plt.figure("substation voltage as a function of time")
        f, ax = plt.subplots(6, sharex=True)
        f.set_size_inches(10, 12.0)
        #f.suptitle("voltages at substation NO IVVC")
        ax[0].plot(volt['A'])
        ax[0].set_title('Substation voltages NO IVVC')
        ax[0].set_ylabel('voltage A')
        ax[1].plot(volt['B'])
        ax[1].set_ylabel('voltage B')
        ax[2].plot(volt['C'])
        ax[2].set_ylabel('voltage C')
        ax[3].plot(voltnew['A'])
        ax[3].set_title("WITH IVVC")
        ax[3].set_ylabel('voltage A')
        ax[4].plot(voltnew['B'])
        ax[4].set_ylabel('voltage B')
        ax[5].plot(voltnew['C'])
        ax[5].set_ylabel('voltage C')
        f.tight_layout()
        plt.savefig(pJoin(modelDir, "substationVoltages.png"))
        #cap switches
        plt.figure("capacitor switch state as a function of time")
        f, ax = plt.subplots(6, sharex=True)
        f.set_size_inches(10, 12.0)
        #f.suptitle("Capacitor switch state NO IVVC")
        ax[0].plot(switch['A'])
        ax[0].set_title("Capacitor switch state NO IVVC")
        ax[0].set_ylabel("switch A")
        ax[1].plot(switch['B'])
        ax[1].set_ylabel("switch B")
        ax[2].plot(switch['C'])
        ax[2].set_ylabel("switch C")
        ax[3].plot(switchnew['A'])
        ax[3].set_title("WITH IVVC")
        ax[3].set_ylabel("switch A")
        ax[4].plot(switchnew['B'])
        ax[4].set_ylabel("switch B")
        ax[5].plot(switchnew['C'])
        ax[5].set_ylabel("switch C")
        for subplot in range(6):
            ax[subplot].set_ylim(-2, 2)
        f.tight_layout()
        plt.savefig(pJoin(modelDir, "capacitorSwitch.png"))
        #plt.show()
        #monetization
        monthNames = [
            "January", "February", "March", "April", "May", "June", "July",
            "August", "September", "October", "November", "December"
        ]
        monthToSeason = {
            'January': 'Winter',
            'February': 'Winter',
            'March': 'Spring',
            'April': 'Spring',
            'May': 'Spring',
            'June': 'Summer',
            'July': 'Summer',
            'August': 'Summer',
            'September': 'Fall',
            'October': 'Fall',
            'November': 'Fall',
            'December': 'Winter'
        }
        #calculate the month and hour of simulation start and month and hour of simulation end
        simStartTimestamp = simStartDate + " 00:00:00"
        simFormattedDate = datetime.strptime(simStartTimestamp,
                                             "%Y-%m-%d %H:%M:%S")
        simStartMonthNum = int(simFormattedDate.strftime('%m'))
        simstartMonth = monthNames[simStartMonthNum - 1]
        simStartDay = int(simFormattedDate.strftime('%d'))
        if calendar.isleap(int(simFormattedDate.strftime('%Y'))):
            febDays = 29
        else:
            febDays = 28
        monthHours = [
            int(31 * 24),
            int(febDays * 24),
            int(31 * 24),
            int(30 * 24),
            int(31 * 24),
            int(30 * 24),
            int(31 * 24),
            int(31 * 24),
            int(30 * 24),
            int(31 * 24),
            int(30 * 24),
            int(31 * 24)
        ]
        simStartIndex = int(
            sum(monthHours[:(simStartMonthNum - 1)]) + (simStartDay - 1) * 24)
        temp = 0
        cumulHours = [0]
        for x in range(12):
            temp += monthHours[x]
            cumulHours.append(temp)
        for i in range((simStartMonthNum), 13):
            if int(simStartIndex + simRealLength) <= cumulHours[i] and int(
                    simStartIndex + simRealLength) > cumulHours[i - 1]:
                simEndMonthNum = i - 1
                simEndMonth = monthNames[simEndMonthNum]
        # print simstartMonth,simEndMonth
        #calculate peaks for the number of months in simulation
        previndex = 0
        monthPeak = {}
        monthPeakNew = {}
        peakSaveDollars = {}
        energyLostDollars = {}
        lossRedDollars = {}
        simMonthList = monthNames[monthNames.index(simstartMonth):(
            monthNames.index(simEndMonth) + 1)]
        # print simMonthList
        for monthElement in simMonthList:
            # print monthElement
            month = monthNames.index(monthElement)
            index1 = int(previndex)
            index2 = int(min((index1 + int(monthHours[month])), simRealLength))
            monthPeak[monthElement] = max(p[index1:index2]) / 1000.0
            monthPeakNew[monthElement] = max(pnew[index1:index2]) / 1000.0
            peakSaveDollars[monthElement] = (
                monthPeak[monthElement] - monthPeakNew[monthElement]) * float(
                    inData['peakDemandCost' +
                           str(monthToSeason[monthElement]) + 'PerKw'])
            lossRedDollars[monthElement] = (
                sum(realLoss[index1:index2]) / 1000.0 -
                sum(realLossnew[index1:index2]) / 1000.0) * (float(
                    inData['wholesaleEnergyCostPerKwh']))
            energyLostDollars[monthElement] = (
                sum(p[index1:index2]) / 1000.0 - sum(pnew[index1:index2]) /
                1000.0 - sum(realLoss[index1:index2]) / 1000.0 +
                sum(realLossnew[index1:index2]) / 1000.0) * (
                    float(inData['wholesaleEnergyCostPerKwh']) -
                    float(inData['retailEnergyCostPerKwh']))
            previndex = index2
        #money charts
        fig = plt.figure("cost benefit barchart", figsize=(10, 8))
        ticks = range(len(simMonthList))
        ticks1 = [element + 0.15 for element in ticks]
        ticks2 = [element + 0.30 for element in ticks]
        # print ticks
        eld = [energyLostDollars[month] for month in simMonthList]
        lrd = [lossRedDollars[month] for month in simMonthList]
        psd = [peakSaveDollars[month] for month in simMonthList]
        bar_eld = plt.bar(ticks, eld, 0.15, color='red')
        bar_psd = plt.bar(ticks1, psd, 0.15, color='blue')
        bar_lrd = plt.bar(ticks2, lrd, 0.15, color='green')
        plt.legend([bar_eld[0], bar_psd[0], bar_lrd[0]], [
            'energyLostDollars', 'peakReductionDollars', 'lossReductionDollars'
        ],
                   bbox_to_anchor=(0., 1.015, 1., .102),
                   loc=3,
                   ncol=2,
                   mode="expand",
                   borderaxespad=0.1)
        monShort = [element[0:3] for element in simMonthList]
        plt.xticks([t + 0.15 for t in ticks], monShort)
        plt.ylabel('Utility Savings ($)')
        plt.savefig(pJoin(modelDir, "spendChart.png"))
        #cumulative savings graphs
        fig = plt.figure("cost benefit barchart", figsize=(10, 5))
        annualSavings = sum(eld) + sum(lrd) + sum(psd)
        annualSave = lambda x: (annualSavings - float(inData['omCost'])
                                ) * x - float(inData['capitalCost'])
        simplePayback = float(
            inData['capitalCost']) / (annualSavings - float(inData['omCost']))
        plt.xlabel('Year After Installation')
        plt.xlim(0, 30)
        plt.ylabel('Cumulative Savings ($)')
        plt.plot([0 for x in range(31)], c='gray')
        plt.axvline(x=simplePayback, ymin=0, ymax=1, c='gray', linestyle='--')
        plt.plot([annualSave(x) for x in range(31)], c='green')
        plt.savefig(pJoin(modelDir, "savingsChart.png"))
        #get exact time stamps from the CSV files generated by Gridlab-D
        timeWithZone = output['Zregulator.csv']['# timestamp']
        timestamps = [element[:19] for element in timeWithZone]
        #data for highcharts
        allOutput["timeStamps"] = timestamps
        allOutput["noCVRPower"] = p
        allOutput["withCVRPower"] = pnew
        allOutput["noCVRLoad"] = whLoads[0]
        allOutput["withCVRLoad"] = whLoads[1]
        allOutput["noCVRLosses"] = whLosses[0]
        allOutput["withCVRLosses"] = whLosses[1]
        allOutput["noCVRTaps"] = tap
        allOutput["withCVRTaps"] = tapnew
        allOutput["noCVRSubVolts"] = volt
        allOutput["withCVRSubVolts"] = voltnew
        allOutput["noCVRCapSwitch"] = switch
        allOutput["withCVRCapSwitch"] = switchnew
        allOutput["noCVRHighVolt"] = highVoltage
        allOutput["withCVRHighVolt"] = highVoltagenew
        allOutput["noCVRLowVolt"] = lowVoltage
        allOutput["withCVRLowVolt"] = lowVoltagenew
        allOutput["noCVRMeanVolt"] = meanVoltage
        allOutput["withCVRMeanVolt"] = meanVoltagenew
        #monetization
        allOutput["simMonthList"] = monShort
        allOutput["energyLostDollars"] = energyLostDollars
        allOutput["lossRedDollars"] = lossRedDollars
        allOutput["peakSaveDollars"] = peakSaveDollars
        allOutput["annualSave"] = [annualSave(x) for x in range(31)]
        # Generate warnings
        #TODO: Timezone adjustment
        try:
            # Check if times for simulation and scada match.
            scadaDates = []
            with open(pJoin(modelDir, "subScadaCalibrated1.player"),
                      "r") as scadaFile:
                for line in scadaFile:
                    (date, val) = line.split(',')
                    scadaDates.append(str(date))
            simFormattedEndDate = simFormattedDate + timedelta(hours=HOURS)
            scadaStartDate = datetime.strptime(scadaDates[0].split(' PST')[0],
                                               "%Y-%m-%d %H:%M:%S")
            scadaEndDate = datetime.strptime(
                scadaDates[len(scadaDates) - 1].split(' PST')[0],
                "%Y-%m-%d %H:%M:%S")
            beginRange = (scadaStartDate - simFormattedDate).total_seconds()
            endRange = (scadaEndDate - simFormattedEndDate).total_seconds()
            # Check if houses exist.
            housesExist, voltageNodeExists = False, False
            for key in localTree:
                if localTree[key].get('object', '') == 'house':
                    housesExist = True
                if localTree[key].get('name',
                                      '') == str(inData.get("voltageNodes",
                                                            0)):
                    voltageNodeExists = True
            if (beginRange > 0.0 or endRange < 0.0) and not housesExist:
                allOutput[
                    "warnings"] = "<strong>WARNING:</strong> The simulation dates entered are not compatible with the scada curve in the feeder."
            # Check if voltage node exists.
            if not voltageNodeExists:
                if allOutput.get('warnings', '') != "":
                    previousWarning = allOutput["warnings"]
                    allOutput[
                        "warnings"] = previousWarning + " The voltage node: " + str(
                            inData.get("voltageNodes",
                                       0)) + " does not exist in the feeder."
                else:
                    allOutput[
                        "warnings"] = "<strong>WARNING:</strong> The voltage node <i>" + str(
                            inData.get(
                                "voltageNodes",
                                0)) + "</i> does not exist in the feeder."
        except:
            pass
        # Update the runTime in the input file.
        endTime = datetime.now()
        inData["runTime"] = str(
            timedelta(seconds=int((endTime - startTime).total_seconds())))
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inData, inFile, indent=4)
        with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
            json.dump(allOutput, outFile, indent=4)
        # For autotest, there won't be such file.
        try:
            os.remove(pJoin(modelDir, "PPID.txt"))
        except Exception, e:
            pass
        print "DONE RUNNING", modelDir
	'generator_mode':'CONSTANT_PF' }
myTree[oldMax + 6] = {'generator_mode':'SUPPLY_DRIVEN', 
	'name':'solar172879', 
	'parent':'solEngInverter', 
	'area':'30000 sf', 
	'generator_status':'ONLINE', 
	'object':'solar', 
	'efficiency':'0.14', 
	'panel_type':'SINGLE_CRYSTAL_SILICON' }
# myTree[oldMax + 7] = { 'interval':'3600',
# 	'parent':'solEngInverter',
# 	'limit':'0',
# 	'file':'Inverter_solEngInverter.csv',
# 	'property':'power_A,power_B,power_C',
# 	'object': 'recorder'}
feeder.adjustTime(myTree, 240, 'hours', '2014-01-01')

# Run here to test.
rawOut = runInFilesystem(myTree, attachments=myFeed['attachments'], keepFiles=True, workDir='.', glmName='Orville Tree Pond Calibrated.glm')

# # Show some output.
# print 'Output Keys:', rawOut.keys()
# plt.plot([abs(complex(x)) for x in rawOut['Inverter_solEngInverter.csv']['power_A']])
# plt.show()

# Write back the full feeder.
outJson = dict(myFeed)
with open('mspWeather.csv','r') as weatherFile:
	weatherString = weatherFile.read()
outJson['attachments']['mspWeather.csv'] = weatherString
outJson['tree'] = myTree
Beispiel #12
0
def omfCalibrate(workDir, feederPath, scadaPath, simStartDate, simLength, calibrateError=0.05):
	'''calibrates a feeder and saves the calibrated tree at a location'''
	with open(feederPath, "r") as jsonIn:
		feederJson = json.load(jsonIn)
		tree = feederJson.get("tree", {})
	# Process scada data.
	gridlabdDir = pJoin(workDir,"gridlabD")
	scadaSubPower = _processScadaData(gridlabdDir,scadaPath, simStartDate)
	# Force FBS powerflow, because NR fails a lot.
	for key in tree:
		if tree[key].get("module","").lower() == "powerflow":
			tree[key] = {"module":"powerflow","solver_method":"FBS"}
	# Attach player.
	classOb = {'omftype':'class player','argument':'{double value;}'}
	playerOb = {"object":"player", "property":"value", "name":"scadaLoads", "file":"subScada.player", "loop":"0"}
	maxKey = feeder.getMaxKey(tree)
	playerKey = maxKey + 2
	tree[maxKey+1] = classOb
	tree[playerKey] = playerOb
	# Make loads reference player.
	loadTemplate = {"object": "triplex_load",
		"power_pf_12": "0.95",
		"impedance_pf_12": "0.98",
		"power_pf_12": "0.90",
		"impedance_fraction_12": "0.7",
		"power_fraction_12": "0.3"}
	loadTemplateR = {"object": "load",
		"impedance_pf_A": "0.98",
		"impedance_pf_B": "0.98",
		"impedance_pf_C": "0.98",
		"power_pf_A": "0.90",
		"power_pf_B": "0.90",
		"power_pf_C": "0.90",
		"impedance_fraction_A": "0.7",
		"impedance_fraction_B": "0.7",
		"impedance_fraction_C": "0.7",
		"power_fraction_A": "0.3",
		"power_fraction_B": "0.3",
		"power_fraction_C": "0.3"}		
	for key in tree:
		ob = tree[key]
		if ob.get("object","") == "triplex_node" and ob.get("power_12","") != "":
			# Add to triplex_nodes.
			newOb = dict(loadTemplate)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			oldPow = ob.get("power_12","").replace("j","d")
			pythagPower = gridlabd._strClean(oldPow)
			newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
			tree[key] = newOb
		elif ob.get("object","") == "load":
			# Add to residential_loads too.
			newOb = dict(loadTemplateR)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["load_class"] = ob.get("load_class", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			try:
				oldPow = ob.get("constant_power_A","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_A"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_B","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_B"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_C","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_C"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			tree[key] = newOb
	# Convert swing bus to a meter.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing' and tree[key].get('object','') != 'meter':
			swingName = tree[key].get('name')
			regIndex = key
			tree[key]['object'] = 'meter'	
	# Search for the substation meter and attach a recorder there.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing':
			swingName = tree[key].get('name')
	recOb = {"object": "recorder",
		"parent": swingName,
		"property": "measured_real_power,measured_reactive_power,measured_power",
		"file": "caliSub.csv",
		"interval": "900"}
	outputRecorderKey = maxKey + 3
	tree[outputRecorderKey] = recOb
	feeder.adjustTime(tree, simLength, "hours", simStartDate['Date'].strftime("%Y-%m-%d %H:%M:%S"))
	# Run Gridlabd, calculate scaling constant.
	def runPowerflowIter(tree,scadaSubPower):
		'''Runs powerflow once, then iterates.'''
		# Run initial powerflow to get power.
		print "Running initial calibration powerflow."
		output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=gridlabdDir)
		outRealPow = output["caliSub.csv"]["measured_real_power"]
		outImagPower = output["caliSub.csv"]["measured_reactive_power"]
		outAppPowerKw = [(x[0]**2 + x[1]**2)**0.5/1000 for x in zip(outRealPow, outImagPower)]
		lastFile = "subScada.player"
		nextFile = "subScadaCalibrated.player"
		nextPower = outAppPowerKw
		error = (sum(outRealPow[1:simLength])/1000-sum(scadaSubPower[1:simLength]))/sum(scadaSubPower[1:simLength])
		iteration = 1
		while abs(error)>calibrateError and iteration<5:
			# Run calibration and iterate up to 5 times.
			SCAL_CONST = sum(scadaSubPower[1:simLength])/sum(nextPower[1:simLength])
			print "Calibrating loads, running powerflow again. Our SCAL_CONST is: ", SCAL_CONST
			newPlayData = []
			with open(pJoin(gridlabdDir, lastFile), "r") as playerFile:
				for line in playerFile:
					(key,val) = line.split(',')
					newPlayData.append(str(key) + ',' + str(float(val)*SCAL_CONST) + "\n")
			with open(pJoin(gridlabdDir, nextFile), "w") as playerFile:
				for row in newPlayData:
					playerFile.write(row)
			tree[playerKey]["file"] = nextFile
			tree[outputRecorderKey]["file"] = "caliSubCheck.csv"
			nextOutput = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=gridlabdDir)
			outRealPowIter = nextOutput["caliSubCheck.csv"]["measured_real_power"]
			outImagPowerIter = nextOutput["caliSubCheck.csv"]["measured_reactive_power"]
			nextAppKw = [(x[0]**2 + x[1]**2)**0.5/1000
				for x in zip(outRealPowIter, outImagPowerIter)]
			lastFile = nextFile
			nextFile = "subScadaCalibrated"+str(iteration)+".player"
			nextPower = nextAppKw
			# Compute error and iterate.
			error = (sum(outRealPowIter[1:simLength])/1000-sum(scadaSubPower[1:simLength]))/sum(scadaSubPower[1:simLength])
			iteration+=1
			print "Error:", abs(error*100), "% Iteration:", iteration
		return outRealPow, outRealPowIter, lastFile, iteration
	outRealPow, outRealPowIter, lastFile, iteration = runPowerflowIter(tree,scadaSubPower)
	caliPowVectors = [[float(element) for element in scadaSubPower[1:simLength]], [float(element)/1000 for element in outRealPow[1:simLength]], [float(element)/1000 for element in outRealPowIter[1:simLength]]]
	labels = ["scadaSubPower","initialGuess","finalGuess"]
	colors = ['red','lightblue','blue']
	chartData = {"Title":"Substation Calibration Check (Iterated "+str(iteration+1)+"X)", "fileName":"caliCheckPlot", "colors":colors,"labels":labels, "timeZone":simStartDate['timeZone']}
	plotLine(workDir, caliPowVectors, chartData, simStartDate['Date']+dt.timedelta(hours=1), 'hours')
	# Write the final output.
	with open(pJoin(workDir,"calibratedFeeder.json"),"w") as outJson:
		playerString = open(pJoin(gridlabdDir,lastFile)).read()
		feederJson["attachments"][lastFile] = playerString
		feederJson["tree"] = tree
		json.dump(feederJson, outJson, indent=4)
	return
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
Beispiel #14
0
def runModel(modelDir, localTree, inData):
    '''This reads a glm file, changes the method of powerflow and reruns'''
    try:
        os.remove(pJoin(modelDir, "allOutputData.json"))
    except:
        pass
    allOutput = {}
    if not os.path.isdir(modelDir):
        os.makedirs(modelDir)
        inData["created"] = str(datetime.now())
    with open(pJoin(modelDir, "allInputData.json"), "w") as inputFile:
        json.dump(inData, inputFile, indent=4)
    binaryName = "gridlabd"
    for key in localTree:
        if "solver_method" in localTree[key].keys():
            print "current solver method", localTree[key]["solver_method"]
            localTree[key]["solver_method"] = 'FBS'
    #find the swing bus and recorder attached to substation
    for key in localTree:
        if localTree[key].get('bustype', '').lower() == 'swing':
            swingIndex = key
            swingName = localTree[key].get('name')
        if localTree[key].get('object',
                              '') == 'regulator' and localTree[key].get(
                                  'from', '') == swingName:
            regIndex = key
            regConfName = localTree[key]['configuration']
    #find the regulator and capacitor names and combine to form a string for volt-var control object
    regKeys = []
    accum_reg = ""
    for key in localTree:
        if localTree[key].get("object", "") == "regulator":
            accum_reg += localTree[key].get("name", "ERROR") + ","
            regKeys.append(key)
    regstr = accum_reg[:-1]
    print regKeys
    capKeys = []
    accum_cap = ""
    for key in localTree:
        if localTree[key].get("object", "") == "capacitor":
            accum_cap += localTree[key].get("name", "ERROR") + ","
            capKeys.append(key)
            if localTree[key].get("control", "").lower() == "manual":
                localTree[key]['control'] = "VOLT"
                print "changing capacitor control from manual to volt"
    capstr = accum_cap[:-1]
    print capKeys
    # Attach recorders relevant to CVR.
    recorders = [{
        'object':
        'collector',
        'file':
        'ZlossesTransformer.csv',
        'group':
        'class=transformer',
        'limit':
        '0',
        'property':
        'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
    }, {
        'object':
        'collector',
        'file':
        'ZlossesUnderground.csv',
        'group':
        'class=underground_line',
        'limit':
        '0',
        'property':
        'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
    }, {
        'object':
        'collector',
        'file':
        'ZlossesOverhead.csv',
        'group':
        'class=overhead_line',
        'limit':
        '0',
        'property':
        'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
    }, {
        'object': 'recorder',
        'file': 'Zregulator.csv',
        'limit': '0',
        'parent': localTree[regIndex]['name'],
        'property': 'tap_A,tap_B,tap_C,power_in.real,power_in.imag'
    }, {
        'object':
        'collector',
        'file':
        'ZvoltageJiggle.csv',
        'group':
        'class=triplex_meter',
        'limit':
        '0',
        'property':
        'min(voltage_12.mag),mean(voltage_12.mag),max(voltage_12.mag),std(voltage_12.mag)'
    }, {
        'object': 'recorder',
        'file': 'ZsubstationTop.csv',
        'limit': '0',
        'parent': localTree[swingIndex]['name'],
        'property': 'voltage_A,voltage_B,voltage_C'
    }, {
        'object': 'recorder',
        'file': 'ZsubstationBottom.csv',
        'limit': '0',
        'parent': localTree[regIndex]['to'],
        'property': 'voltage_A,voltage_B,voltage_C'
    }]
    #recorder object for capacitor switching - if capacitors exist
    if capKeys != []:
        for key in capKeys:
            recorders.append({
                'object': 'recorder',
                'file': 'ZcapSwitch' + str(key) + '.csv',
                'limit': '0',
                'parent': localTree[key]['name'],
                'property': 'switchA,switchB,switchC'
            })
    #attach recorder process
    biggest = 1 + max([int(k) for k in localTree.keys()])
    for index, rec in enumerate(recorders):
        localTree[biggest + index] = rec
    #run a reference load flow
    HOURS = float(100)
    year_lp = False  #leap year
    feeder.adjustTime(localTree, HOURS, "hours", "2011-01-01")
    output = gridlabd.runInFilesystem(localTree,
                                      keepFiles=False,
                                      workDir=modelDir)
    os.remove(pJoin(modelDir, "PID.txt"))
    p = output['Zregulator.csv']['power_in.real']
    q = output['Zregulator.csv']['power_in.imag']
    #time delays from configuration files
    time_delay_reg = '30.0'
    time_delay_cap = '300.0'
    for key in localTree:
        if localTree[key].get('object', '') == "regulator_configuration":
            time_delay_reg = localTree[key]['time_delay']
            print "time_delay_reg", time_delay_reg
        # if localTree[key].get('object','') == "capacitor":
        # 	time_delay_cap = localTree[key]['time_delay']
        # 	print "time_delay_cap",time_delay_cap
    #change the recorder names
    for key in localTree:
        if localTree[key].get('object',
                              '') == "collector" or localTree[key].get(
                                  'object', '') == "recorder":
            if localTree[key].get('file', '').startswith('Z'):
                localTree[key]['file'] = localTree[key].get('file',
                                                            '').replace(
                                                                'Z', 'NewZ')
    #create volt-var control object
    max_key = max([int(key) for key in localTree.keys()])
    print max_key
    localTree[max_key + 1] = {
        'object': 'volt_var_control',
        'name': 'IVVC1',
        'control_method': 'ACTIVE',
        'capacitor_delay': str(time_delay_cap),
        'regulator_delay': str(time_delay_reg),
        'desired_pf': '0.99',
        'd_max': '0.6',
        'd_min': '0.1',
        'substation_link': str(localTree[regIndex]['name']),
        'regulator_list': regstr,
        'capacitor_list': capstr
    }
    #running powerflow analysis via gridalab after attaching a regulator
    feeder.adjustTime(localTree, HOURS, "hours", "2011-01-01")
    output1 = gridlabd.runInFilesystem(localTree,
                                       keepFiles=True,
                                       workDir=modelDir)
    os.remove(pJoin(modelDir, "PID.txt"))
    pnew = output1['NewZregulator.csv']['power_in.real']
    qnew = output1['NewZregulator.csv']['power_in.imag']
    #total real and imaginary losses as a function of time
    realLoss = []
    imagLoss = []
    realLossnew = []
    imagLossnew = []
    for element in range(int(HOURS)):
        r = 0.0
        i = 0.0
        rnew = 0.0
        inew = 0.0
        for device in [
                'ZlossesOverhead.csv', 'ZlossesTransformer.csv',
                'ZlossesUnderground.csv'
        ]:
            for letter in ['A', 'B', 'C']:
                r += output[device]['sum(power_losses_' + letter +
                                    '.real)'][element]
                i += output[device]['sum(power_losses_' + letter +
                                    '.imag)'][element]
                rnew += output1['New' + device]['sum(power_losses_' + letter +
                                                '.real)'][element]
                inew += output1['New' + device]['sum(power_losses_' + letter +
                                                '.imag)'][element]
        realLoss.append(r)
        imagLoss.append(i)
        realLossnew.append(rnew)
        imagLossnew.append(inew)
    #voltage calculations and tap calculations
    lowVoltage = []
    meanVoltage = []
    highVoltage = []
    lowVoltagenew = []
    meanVoltagenew = []
    highVoltagenew = []
    tap = {'A': [], 'B': [], 'C': []}
    tapnew = {'A': [], 'B': [], 'C': []}
    volt = {'A': [], 'B': [], 'C': []}
    voltnew = {'A': [], 'B': [], 'C': []}
    switch = {'A': [], 'B': [], 'C': []}
    switchnew = {'A': [], 'B': [], 'C': []}
    for element in range(int(HOURS)):
        for letter in ['A', 'B', 'C']:
            tap[letter].append(output['Zregulator.csv']['tap_' +
                                                        letter][element])
            tapnew[letter].append(
                output1['NewZregulator.csv']['tap_' + letter][element])
            #voltage real, imag
            vr, vi = sepRealImag(
                output['ZsubstationBottom.csv']['voltage_' + letter][element])
            volt[letter].append(math.sqrt(vr**2 + vi**2) / 60)
            vrnew, vinew = sepRealImag(
                output1['NewZsubstationBottom.csv']['voltage_' +
                                                    letter][element])
            voltnew[letter].append(math.sqrt(vrnew**2 + vinew**2) / 60)
            if capKeys != []:
                switch[letter].append(
                    output['ZcapSwitch' + str(int(capKeys[0])) +
                           '.csv']['switch' + letter][element])
                switchnew[letter].append(
                    output1['NewZcapSwitch' + str(int(capKeys[0])) +
                            '.csv']['switch' + letter][element])
        lowVoltage.append(
            float(output['ZvoltageJiggle.csv']['min(voltage_12.mag)'][element])
            / 2.0)
        meanVoltage.append(
            float(
                output['ZvoltageJiggle.csv']['mean(voltage_12.mag)'][element])
            / 2.0)
        highVoltage.append(
            float(output['ZvoltageJiggle.csv']['max(voltage_12.mag)'][element])
            / 2.0)
        lowVoltagenew.append(
            float(output1['NewZvoltageJiggle.csv']['min(voltage_12.mag)']
                  [element]) / 2.0)
        meanVoltagenew.append(
            float(output1['NewZvoltageJiggle.csv']['mean(voltage_12.mag)']
                  [element]) / 2.0)
        highVoltagenew.append(
            float(output1['NewZvoltageJiggle.csv']['max(voltage_12.mag)']
                  [element]) / 2.0)
    #energy calculations
    whEnergy = []
    whLosses = []
    whLoads = []
    whEnergy.append(sum(p) / 10**6)
    whLosses.append(sum(realLoss) / 10**6)
    whLoads.append((sum(p) - sum(realLoss)) / 10**6)
    whEnergy.append(sum(pnew) / 10**6)
    whLosses.append(sum(realLossnew) / 10**6)
    whLoads.append((sum(pnew) - sum(realLossnew)) / 10**6)
    indices = ['No IVVC', 'With IVVC']
    # energySalesRed = (whLoads[1]-whLoads[0])*(inData['wholesaleEnergyCostPerKwh'])*1000
    # lossSav = (whLosses[0]-whLosses[1])*inData['wholesaleEnergyCostPerKwh']*1000
    # print energySalesRed, lossSav
    #plots
    ticks = []
    plt.clf()
    plt.title("total energy")
    plt.ylabel("total load and losses (MWh)")
    for element in range(2):
        ticks.append(element)
        bar_loss = plt.bar(element, whLosses[element], 0.15, color='red')
        bar_load = plt.bar(element + 0.15,
                           whLoads[element],
                           0.15,
                           color='orange')
    plt.legend([bar_load[0], bar_loss[0]], ['total load', 'total losses'],
               bbox_to_anchor=(0., 0.915, 1., .102),
               loc=3,
               ncol=2,
               mode="expand",
               borderaxespad=0.1)
    plt.xticks([t + 0.15 for t in ticks], indices)
    plt.savefig(pJoin(modelDir, "total energy.png"))
    #real and imaginary power
    plt.figure("real power")
    plt.title("Real Power at substation")
    plt.ylabel("substation real power (MW)")
    pMW = [element / 10**6 for element in p]
    pMWn = [element / 10**6 for element in pnew]
    pw = plt.plot(pMW)
    npw = plt.plot(pMWn)
    plt.legend([pw[0], npw[0]], ['NO IVVC', 'WITH IVVC'],
               bbox_to_anchor=(0., 0.915, 1., .102),
               loc=3,
               ncol=2,
               mode="expand",
               borderaxespad=0.1)
    plt.savefig(pJoin(modelDir, "real power.png"))
    plt.figure("Reactive power")
    plt.title("Reactive Power at substation")
    plt.ylabel("substation reactive power (MVAR)")
    qMVAR = [element / 10**6 for element in q]
    qMVARn = [element / 10**6 for element in qnew]
    iw = plt.plot(qMVAR)
    niw = plt.plot(qMVARn)
    plt.legend([iw[0], niw[0]], ['NO IVVC', 'WITH IVVC'],
               bbox_to_anchor=(0., 0.915, 1., .102),
               loc=3,
               ncol=2,
               mode="expand",
               borderaxespad=0.1)
    plt.savefig(pJoin(modelDir, "imaginary power.png"))
    #voltage plots
    plt.figure("voltages as a function of time")
    f, ax = plt.subplots(2, sharex=True)
    f.suptitle("Voltages high and low")
    lv = ax[0].plot(lowVoltage, color='cadetblue')
    mv = ax[0].plot(meanVoltage, color='blue')
    hv = ax[0].plot(highVoltage, color='cadetblue')
    ax[0].legend([lv[0], mv[0], hv[0]],
                 ['low voltage', 'mean voltage', 'high voltage'],
                 bbox_to_anchor=(0., 0.915, 1., .1),
                 loc=3,
                 ncol=3,
                 mode="expand",
                 borderaxespad=0.1)
    ax[0].set_ylabel('NO IVVC')
    nlv = ax[1].plot(lowVoltagenew, color='cadetblue')
    nmv = ax[1].plot(meanVoltagenew, color='blue')
    nhv = ax[1].plot(highVoltagenew, color='cadetblue')
    ax[1].set_ylabel('WITH IVVC')
    plt.savefig(pJoin(modelDir, "Voltages.png"))
    #tap positions
    plt.figure("TAP positions NO IVVC")
    f, ax = plt.subplots(6, sharex=True)
    f.set_size_inches(18.5, 12.0)
    #f.suptitle("Regulator Tap positions")
    ax[0].plot(tap['A'])
    ax[0].set_title("Regulator Tap positions NO IVVC")
    ax[0].set_ylabel("TAP A")
    ax[1].plot(tap['B'])
    ax[1].set_ylabel("TAP B")
    ax[2].plot(tap['C'])
    ax[2].set_ylabel("TAP C")
    ax[3].plot(tapnew['A'])
    ax[3].set_title("WITH IVVC")
    ax[3].set_ylabel("TAP A")
    ax[4].plot(tapnew['B'])
    ax[4].set_ylabel("TAP B")
    ax[5].plot(tapnew['C'])
    ax[5].set_ylabel("TAP C")
    for subplot in range(6):
        ax[subplot].set_ylim(-20, 20)
    f.tight_layout()
    plt.savefig(pJoin(modelDir, "Regulator TAP positions.png"))
    #substation voltages
    plt.figure("substation voltage as a function of time")
    f, ax = plt.subplots(6, sharex=True)
    f.set_size_inches(18.5, 12.0)
    #f.suptitle("voltages at substation NO IVVC")
    ax[0].plot(volt['A'])
    ax[0].set_title('Substation voltages NO IVVC')
    ax[0].set_ylabel('voltage A')
    ax[1].plot(volt['B'])
    ax[1].set_ylabel('voltage B')
    ax[2].plot(volt['C'])
    ax[2].set_ylabel('voltage C')
    ax[3].plot(voltnew['A'])
    ax[3].set_title("WITH IVVC")
    ax[3].set_ylabel('voltage A')
    ax[4].plot(voltnew['B'])
    ax[4].set_ylabel('voltage B')
    ax[5].plot(voltnew['C'])
    ax[5].set_ylabel('voltage C')
    f.tight_layout()
    plt.savefig(pJoin(modelDir, "substation voltages.png"))
    #cap switches - plotted if capacitors are present
    if capKeys != []:
        plt.figure("capacitor switch state as a function of time")
        f, ax = plt.subplots(6, sharex=True)
        f.set_size_inches(18.5, 12.0)
        #f.suptitle("Capacitor switch state NO IVVC")
        ax[0].plot(switch['A'])
        ax[0].set_title("Capacitor switch state NO IVVC")
        ax[0].set_ylabel("switch A")
        ax[1].plot(switch['B'])
        ax[1].set_ylabel("switch B")
        ax[2].plot(switch['C'])
        ax[2].set_ylabel("switch C")
        ax[3].plot(switchnew['A'])
        ax[3].set_title("WITH IVVC")
        ax[3].set_ylabel("switch A")
        ax[4].plot(switchnew['B'])
        ax[4].set_ylabel("switch B")
        ax[5].plot(switchnew['C'])
        ax[5].set_ylabel("switch C")
        for subplot in range(6):
            ax[subplot].set_ylim(-2, 2)
        f.tight_layout()
        plt.savefig(pJoin(modelDir, "capacitor switch.png"))
    #plt.show()
    #monetization
    monthNames = [
        "January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"
    ]
    monthToSeason = {
        'January': 'Winter',
        'February': 'Winter',
        'March': 'Spring',
        'April': 'Spring',
        'May': 'Spring',
        'June': 'Summer',
        'July': 'Summer',
        'August': 'Summer',
        'September': 'Fall',
        'October': 'Fall',
        'November': 'Fall',
        'December': 'Winter'
    }
    if year_lp == True:
        febDays = 29
    else:
        febDays = 28
    monthHours = [
        int(31 * 24),
        int(febDays * 24),
        int(31 * 24),
        int(30 * 24),
        int(31 * 24),
        int(30 * 24),
        int(31 * 24),
        int(31 * 24),
        int(30 * 24),
        int(31 * 24),
        int(30 * 24),
        int(31 * 24)
    ]
    #find simulation months
    temp = 0
    cumulHours = []
    for x in range(12):
        temp += monthHours[x]
        cumulHours.append(temp)
    for i in range(12):
        if i == 0:
            lowval = 0
        else:
            lowval = cumulHours[i - 1]
        if HOURS <= cumulHours[i] and HOURS >= lowval:
            hourMonth = monthNames[i]
            hourIndex = i
    #calculate peaks for the number of months in simulation
    previndex = 0
    monthPeak = {}
    monthPeakNew = {}
    peakSaveDollars = {}
    energyLostDollars = {}
    lossRedDollars = {}
    for month in range(hourIndex + 1):
        index1 = int(previndex)
        index2 = int(min((index1 + int(monthHours[month])), HOURS))
        monthPeak[monthNames[month]] = max(p[index1:index2]) / 1000.0
        monthPeakNew[monthNames[month]] = max(pnew[index1:index2]) / 1000.0
        peakSaveDollars[monthNames[month]] = (
            monthPeak[monthNames[month]] - monthPeakNew[monthNames[month]]
        ) * inData['peakDemandCost' + str(monthToSeason[monthNames[month]]) +
                   'PerKw']
        lossRedDollars[
            monthNames[month]] = (sum(realLoss[index1:index2]) / 1000.0 -
                                  sum(realLossnew[index1:index2]) / 1000.0) * (
                                      inData['wholesaleEnergyCostPerKwh'])
        energyLostDollars[monthNames[month]] = (
            sum(p[index1:index2]) / 1000.0 - sum(pnew[index1:index2]) / 1000.0
            - sum(realLoss[index1:index2]) / 1000.0 +
            sum(realLossnew[index1:index2]) / 1000.0) * (
                inData['wholesaleEnergyCostPerKwh'] -
                inData['retailEnergyCostPerKwh'])
        previndex = index2
    #money charts
    simMonths = monthNames[:hourIndex + 1]
    fig = plt.figure("cost benefit barchart", figsize=(10, 8))
    ticks = range(len(simMonths))
    ticks1 = [element + 0.15 for element in ticks]
    ticks2 = [element + 0.30 for element in ticks]
    print ticks
    eld = [energyLostDollars[month] for month in simMonths]
    lrd = [lossRedDollars[month] for month in simMonths]
    psd = [peakSaveDollars[month] for month in simMonths]
    bar_eld = plt.bar(ticks, eld, 0.15, color='red')
    bar_psd = plt.bar(ticks1, psd, 0.15, color='blue')
    bar_lrd = plt.bar(ticks2, lrd, 0.15, color='green')
    plt.legend(
        [bar_eld[0], bar_psd[0], bar_lrd[0]],
        ['energyLostDollars', 'peakReductionDollars', 'lossReductionDollars'],
        bbox_to_anchor=(0., 1.015, 1., .102),
        loc=3,
        ncol=2,
        mode="expand",
        borderaxespad=0.1)
    monShort = [element[0:3] for element in simMonths]
    plt.xticks([t + 0.15 for t in ticks], monShort)
    plt.ylabel('Utility Savings ($)')
    plt.savefig(pJoin(modelDir, "spendChart.png"))
    with open(pJoin(modelDir, "spendChart.png"), "rb") as inFile:
        allOutput["spendChart"] = inFile.read().encode("base64")
    #cumulative savings graphs
    fig = plt.figure("cost benefit barchart", figsize=(10, 5))
    annualSavings = sum(eld) + sum(lrd) + sum(psd)
    annualSave = lambda x: (annualSavings - inData['omCost']) * x - inData[
        'capitalCost']
    simplePayback = inData['capitalCost'] / (annualSavings - inData['omCost'])
    plt.xlabel('Year After Installation')
    plt.xlim(0, 30)
    plt.ylabel('Cumulative Savings ($)')
    plt.plot([0 for x in range(31)], c='gray')
    plt.axvline(x=simplePayback, ymin=0, ymax=1, c='gray', linestyle='--')
    plt.plot([annualSave(x) for x in range(31)], c='green')
    plt.savefig(pJoin(modelDir, "savingsChart.png"))
    with open(pJoin(modelDir, "savingsChart.png"), "rb") as inFile:
        allOutput["savingsChart"] = inFile.read().encode("base64")
    # Update the runTime in the input file.
    # endTime = datetime.now()
    # inDat["runTime"] = str(timedelta(seconds=int((endTime - startTime).total_seconds())))
    with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
        json.dump(inData, inFile, indent=4)
    with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
        json.dump(allOutput, outFile, indent=4)
    print "DONE RUNNING", modelDir
Beispiel #15
0
def attachVolts(workDir, feederPath, voltVectorA, voltVectorB, voltVectorC, simStartDate, simLength, simLengthUnits):
	'''read voltage vectors of 3 different phases, run gridlabd, and attach output to the feeder.'''
	try:
		timeStamp = [simStartDate['Date']]
		for x in range (1, 8760):
			timeStamp.append(timeStamp[x-1] + dt.timedelta(hours=1))
		firstDateTime = timeStamp[1]
		with open(pJoin(pJoin(workDir,"gridlabD"),"phaseAVoltage.player"),"w") as voltFile:
			for x in range(0, 8760):
				timestamp = timeStamp[x]
				voltage = str("%0.2f"%float(voltVectorA[x]))+"+0j"
				line = timestamp.strftime("%Y-%m-%d %H:%M:%S") + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
				voltFile.write(line)
		with open(pJoin(pJoin(workDir,"gridlabD"),"phaseBVoltage.player"),"w") as voltFile:
			for x in range(0, 8760):
				timestamp = timeStamp[x]
				voltage = str("%0.2f"%float(voltVectorB[x]))+"-"+str("%0.4f"%float(random.uniform(6449,6460)))+"j"
				line = timestamp.strftime("%Y-%m-%d %H:%M:%S") + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
				voltFile.write(line)
		with open(pJoin(pJoin(workDir,"gridlabD"),"phaseCVoltage.player"),"w") as voltFile:
			for x in range(0, 8760):
				timestamp = timeStamp[x]
				voltage = str("%0.2f"%float(voltVectorC[x]))+"+"+str("%0.4f"%float(random.uniform(6449,6460)))+"j"
				line = timestamp.strftime("%Y-%m-%d %H:%M:%S") + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
				voltFile.write(line)
		with open(feederPath, "r") as jsonIn:
			feederJson = json.load(jsonIn)
			tree = feederJson.get("tree", {})
		# Find swingNode name.
		for key in tree:
			if tree[key].get('bustype','').lower() == 'swing':
				swingName = tree[key].get('name')
		# Attach player.
		classOb = {'omftype':'class player','argument':'{double value;}'}
		voltageObA = {"object":"player", "property":"voltage_A", "file":"phaseAVoltage.player", "loop":"0", "parent":swingName}
		voltageObB = {"object":"player", "property":"voltage_B", "file":"phaseBVoltage.player", "loop":"0", "parent":swingName}
		voltageObC = {"object":"player", "property":"voltage_C", "file":"phaseCVoltage.player", "loop":"0", "parent":swingName}
		maxKey = feeder.getMaxKey(tree)
		voltplayerKeyA = maxKey + 2
		voltplayerKeyB = maxKey + 3
		voltplayerKeyC = maxKey + 4
		tree[maxKey+1] = classOb
		tree[voltplayerKeyA] = voltageObA
		tree[voltplayerKeyB] = voltageObB
		tree[voltplayerKeyC] = voltageObC
		# Adjust time and run output.
		feeder.adjustTime(tree, simLength, simLengthUnits, firstDateTime.strftime("%Y-%m-%d %H:%M:%S"))
		output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=pJoin(workDir,"gridlabD"))
		# Write the output.
		with open(pJoin(workDir,"calibratedFeeder.omd"),"w") as outJson:
			playerStringA = open(pJoin(pJoin(workDir,"gridlabD"),"phaseAVoltage.player")).read()
			playerStringB = open(pJoin(pJoin(workDir,"gridlabD"),"phaseBVoltage.player")).read()
			playerStringC = open(pJoin(pJoin(workDir,"gridlabD"),"phaseCVoltage.player")).read()
			feederJson["attachments"]["phaseAVoltage.player"] = playerStringA
			feederJson["attachments"]["phaseBVoltage.player"] = playerStringB
			feederJson["attachments"]["phaseCVoltage.player"] = playerStringC
			feederJson["tree"] = tree
			json.dump(feederJson, outJson, indent=4)
		return pJoin(workDir,"calibratedFeeder.omd"), True
	except:
		print "Failed to run gridlabD with voltage players."
		return "", False
Beispiel #16
0
def comparesol(modelDir, localTree):
    '''This reads a glm file, changes the method of powerflow and reruns'''
    print "Testing GridlabD solver."

    startTime = datetime.now()

    binaryName = "gridlabd"

    for key in localTree:
        if "solver_method" in localTree[key].keys():
            solvmeth = localTree[key]["solver_method"]
            print "success", solvmeth
            if solvmeth == 'NR':
                localTree[key]["solver_method"] = 'FBS'
            else:
                localTree[key]["solver_method"] = 'NR'

    # feeder.attachRecorders(localTree, "Regulator", "object", "regulator")
    # feeder.attachRecorders(localTree, "CollectorVoltage", None, None)

    # last_key = len(localTree)

    # print last_key

    for key in localTree:
        if localTree[key].get('bustype', '').lower() == 'swing':
            swingIndex = key
            swingName = localTree[key].get('name')

    print swingIndex, swingName

    for key in localTree:
        if localTree[key].get('object',
                              '') == 'regulator' and localTree[key].get(
                                  'from', '') == swingName:
            regIndex = key
            regConfName = localTree[key]['configuration']

    print regIndex

    # Attach recorders relevant to CVR.
    recorders = [{
        'object':
        'collector',
        'file':
        'ZlossesTransformer.csv',
        'group':
        'class=transformer',
        'limit':
        '0',
        'property':
        'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
    }, {
        'object':
        'collector',
        'file':
        'ZlossesUnderground.csv',
        'group':
        'class=underground_line',
        'limit':
        '0',
        'property':
        'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
    }, {
        'object':
        'collector',
        'file':
        'ZlossesOverhead.csv',
        'group':
        'class=overhead_line',
        'limit':
        '0',
        'property':
        'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'
    }, {
        'object': 'recorder',
        'file': 'Zregulator.csv',
        'limit': '0',
        'parent': localTree[regIndex]['name'],
        'property': 'tap_A,tap_B,tap_C,power_in.real,power_in.imag'
    }, {
        'object':
        'collector',
        'file':
        'ZvoltageJiggle.csv',
        'group':
        'class=triplex_meter',
        'limit':
        '0',
        'property':
        'min(voltage_12.mag),mean(voltage_12.mag),max(voltage_12.mag),std(voltage_12.mag)'
    }, {
        'object': 'recorder',
        'file': 'ZsubstationTop.csv',
        'limit': '0',
        'parent': localTree[swingIndex]['name'],
        'property': 'voltage_A,voltage_B,voltage_C'
    }, {
        'object': 'recorder',
        'file': 'ZsubstationBottom.csv',
        'limit': '0',
        'parent': localTree[regIndex]['to'],
        'property': 'voltage_A,voltage_B,voltage_C'
    }]

    biggest = 1 + max([int(k) for k in localTree.keys()])
    for index, rec in enumerate(recorders):
        localTree[biggest + index] = rec

    max_key = max([int(key) for key in localTree.keys()])
    print max_key

    regKeys = []
    accum = ""

    for key in localTree:
        if localTree[key].get("object", "") == "regulator":
            accum += localTree[key].get("name", "ERROR") + ","
            regKeys.append(key)

    regstr = accum[:-1]

    print regKeys
    print regstr, type(regstr)

    localTree[max_key + 1] = {
        'object': 'volt_var_control',
        'name': 'volt_var_control',
        'control_method': 'ACTIVE',
        'capacitor_delay': '30.0',
        'regulator_delay': '30.0',
        'desired_pf': '0.99',
        'd_max': '0.6',
        'd_min': '0.1',
        'substation_link': 'substation_transformer',
        'regulator_list': regstr
    }

    feeder.adjustTime(tree=localTree,
                      simLength=float("8760"),
                      simLengthUnits="hours",
                      simStartDate="2012-01-01")

    output = gridlabd.runInFilesystem(localTree,
                                      keepFiles=True,
                                      workDir=modelDir)
    os.remove(pJoin(modelDir, "PID.txt"))

    p = output['Zregulator.csv']['power_in.real']
    q = output['Zregulator.csv']['power_in.imag']

    xtime = {}

    for key in output:
        if '# timestamp' in output[key]:
            xtime['timeStamps'] = output[key]['# timestamp']

    #print type(xtime['timeStamps'][0])
    #print len(p)

    #xaxtick = str(xtime['timeStamps'])

    # plt.plot(range(8760),p)
    # plt.show()

    # print "p=" , p
    # print "q=" , q
    print "DONE RUNNING", modelDir
Beispiel #17
0
def omfCalibrate(workDir, feederPath, scadaPath):
    '''calibrates a feeder and saves the calibrated tree at a location'''
    with open(feederPath, "r") as jsonIn:
        feederJson = json.load(jsonIn)
        tree = feederJson.get("tree", {})
    scadaSubPower = _processScadaData(workDir, scadaPath)
    # Force FBS powerflow, because NR fails a lot.
    for key in tree:
        if tree[key].get("module", "").lower() == "powerflow":
            tree[key] = {"module": "powerflow", "solver_method": "FBS"}
    # Attach player.
    classOb = {
        "class": "player",
        "variable_names": ["value"],
        "variable_types": ["double"]
    }
    playerOb = {
        "object": "player",
        "property": "value",
        "name": "scadaLoads",
        "file": "subScada.player",
        "loop": "0"
    }
    maxKey = feeder.getMaxKey(tree)
    tree[maxKey + 1] = classOb
    tree[maxKey + 2] = playerOb
    # Make loads reference player.
    loadTemplate = {
        "object": "triplex_load",
        "power_pf_12": "0.95",
        "impedance_pf_12": "0.98",
        "power_pf_12": "0.90",
        "impedance_fraction_12": "0.7",
        "power_fraction_12": "0.3"
    }
    for key in tree:
        ob = tree[key]
        if ob.get("object",
                  "") == "triplex_node" and ob.get("power_12", "") != "":
            newOb = dict(loadTemplate)
            newOb["name"] = ob.get("name", "")
            newOb["parent"] = ob.get("parent", "")
            newOb["phases"] = ob.get("phases", "")
            newOb["nominal_voltage"] = ob.get("nominal_voltage", "")
            newOb["latitude"] = ob.get("latitude", "0")
            newOb["longitude"] = ob.get("longitude", "0")
            oldPow = ob.get("power_12", "").replace("j", "d")
            pythagPower = gridlabd._strClean(oldPow)
            newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
            tree[key] = newOb
    # Search for the substation regulator and attach a recorder there.
    for key in tree:
        if tree[key].get('bustype', '').lower() == 'swing':
            swingName = tree[key].get('name')
    for key in tree:
        if tree[key].get('object', '') == 'regulator' and tree[key].get(
                'from', '') == swingName:
            regIndex = key
            SUB_REG_NAME = tree[key]['name']
    recOb = {
        "object": "recorder",
        "parent": SUB_REG_NAME,
        "property": "power_in.real,power_in.imag",
        "file": "caliSub.csv",
        "interval": "900"
    }
    tree[maxKey + 3] = recOb
    HOURS = 100
    feeder.adjustTime(tree, HOURS, "hours", "2011-01-01")
    # Run Gridlabd.
    output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=workDir)
    # Calculate scaling constant.
    outRealPow = output["caliSub.csv"]["power_in.real"]
    outImagPower = output["caliSub.csv"]["power_in.imag"]
    outAppPowerKw = [(x[0]**2 + x[1]**2)**0.5 / 1000
                     for x in zip(outRealPow, outImagPower)]
    # HACK: ignore first time step in output and input because GLD sometimes breaks the first step.
    SCAL_CONST = sum(scadaSubPower[1:HOURS]) / sum(outAppPowerKw[1:HOURS])
    # Rewrite the subScada.player file so all the power values are multiplied by the SCAL_CONSTANT.
    newPlayData = []
    with open(pJoin(workDir, "subScada.player"), "r") as playerFile:
        for line in playerFile:
            (key, val) = line.split(',')
            newPlayData.append(
                str(key) + ',' + str(float(val) * SCAL_CONST) + "\n")
    with open(pJoin(workDir, "subScadaCalibrated.player"), "w") as playerFile:
        for row in newPlayData:
            playerFile.write(row)
    # Test by running a glm with subScadaCalibrated.player and caliSub.csv2.
    tree[maxKey + 2]["file"] = "subScadaCalibrated.player"
    tree[maxKey + 3]["file"] = "caliSubCheck.csv"
    secondOutput = gridlabd.runInFilesystem(tree,
                                            keepFiles=True,
                                            workDir=workDir)
    plt.plot(outAppPowerKw[1:HOURS], label="initialGuess")
    plt.plot(scadaSubPower[1:HOURS], label="scadaSubPower")
    secondAppKw = [
        (x[0]**2 + x[1]**2)**0.5 / 1000
        for x in zip(secondOutput["caliSubCheck.csv"]["power_in.real"],
                     secondOutput["caliSubCheck.csv"]["power_in.imag"])
    ]
    plt.plot(secondAppKw[1:HOURS], label="finalGuess")
    plt.legend(loc=3)
    plt.savefig(pJoin(workDir, "caliCheckPlot.png"))
    # Write the final output.
    with open(pJoin(workDir, "calibratedFeeder.json"), "w") as outJson:
        playerString = open(pJoin(workDir, "subScadaCalibrated.player")).read()
        feederJson["attachments"]["subScadaCalibrated.player"] = playerString
        feederJson["tree"] = tree
        json.dump(feederJson, outJson, indent=4)
    return
Beispiel #18
0
def omfCalibrate(workDir,
                 feederPath,
                 scadaPath,
                 simStartDate,
                 simLength,
                 simLengthUnits,
                 solver="FBS",
                 calibrateError=(0.05, 5),
                 trim=5):
    '''calibrates a feeder and saves the calibrated tree at a location.
	Note: feeders with cap banks should be calibrated with cap banks OPEN.
	We have seen cap banks throw off calibration.'''
    with open(feederPath, "r") as jsonIn:
        feederJson = json.load(jsonIn)
        tree = feederJson.get("tree", {})
    simLength = simLength + trim
    # Process scada data.
    scadaSubPower = _processScadaData(pJoin(workDir, "gridlabD"), scadaPath,
                                      simStartDate, simLengthUnits)
    # Load specified solver.
    for key in tree:
        if tree[key].get("module", "").lower() == "powerflow":
            tree[key] = {"module": "powerflow", "solver_method": solver}
    # Attach player.
    classOb = {'omftype': 'class player', 'argument': '{double value;}'}
    playerOb = {
        "object": "player",
        "property": "value",
        "name": "scadaLoads",
        "file": "subScada.player",
        "loop": "0"
    }
    maxKey = feeder.getMaxKey(tree)
    playerKey = maxKey + 2
    tree[maxKey + 1] = classOb
    tree[playerKey] = playerOb
    # Make loads reference player.
    loadTemplate = {
        "object": "triplex_load",
        "power_pf_12": "0.95",
        "impedance_pf_12": "0.98",
        "power_pf_12": "0.90",
        "impedance_fraction_12": "0.7",
        "power_fraction_12": "0.3"
    }
    loadTemplateR = {
        "object": "load",
        "impedance_pf_A": "0.98",
        "impedance_pf_B": "0.98",
        "impedance_pf_C": "0.98",
        "power_pf_A": "0.90",
        "power_pf_B": "0.90",
        "power_pf_C": "0.90",
        "impedance_fraction_A": "0.7",
        "impedance_fraction_B": "0.7",
        "impedance_fraction_C": "0.7",
        "power_fraction_A": "0.3",
        "power_fraction_B": "0.3",
        "power_fraction_C": "0.3"
    }
    for key in tree:
        ob = tree[key]
        if ob.get("object", "") in ("triplex_node", "triplex_load") and (
                ob.get("power_12") or ob.get("base_power_12")):
            # Add to triplex_nodes.
            newOb = dict(loadTemplate)
            newOb["name"] = ob.get("name", "")
            newOb["parent"] = ob.get("parent", "")
            newOb["phases"] = ob.get("phases", "")
            newOb["nominal_voltage"] = ob.get("nominal_voltage", "")
            newOb["latitude"] = ob.get("latitude", "0")
            newOb["longitude"] = ob.get("longitude", "0")
            oldPow = ob.get("power_12", "").replace("j", "d")
            if not oldPow:
                oldPow = ob.get("base_power_12")
                if "scadaloads.value*" in oldPow:
                    oldPow = oldPow[17:]
            pythagPower = gridlabd._strClean(oldPow)
            newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
            tree[key] = newOb
        elif ob.get("object", "") == "load":
            # Add to residential_loads too.
            newOb = dict(loadTemplateR)
            newOb["name"] = ob.get("name", "")
            newOb["parent"] = ob.get("parent", "")
            newOb["phases"] = ob.get("phases", "")
            newOb["load_class"] = ob.get("load_class", "")
            newOb["nominal_voltage"] = ob.get("nominal_voltage", "")
            newOb["latitude"] = ob.get("latitude", "0")
            newOb["longitude"] = ob.get("longitude", "0")
            try:
                oldPow = ob.get("constant_power_A", "").replace("j", "d")
                pythagPower = gridlabd._strClean(oldPow)
                newOb["base_power_A"] = "scadaLoads.value*" + str(pythagPower)
            except:
                pass
            try:
                oldPow = ob.get("constant_power_B", "").replace("j", "d")
                pythagPower = gridlabd._strClean(oldPow)
                newOb["base_power_B"] = "scadaLoads.value*" + str(pythagPower)
            except:
                pass
            try:
                oldPow = ob.get("constant_power_C", "").replace("j", "d")
                pythagPower = gridlabd._strClean(oldPow)
                newOb["base_power_C"] = "scadaLoads.value*" + str(pythagPower)
            except:
                pass
            tree[key] = newOb
    # Convert swing bus to a meter.
    for key in tree:
        if tree[key].get('bustype', '').lower() == 'swing' and tree[key].get(
                'object', '') != 'meter':
            swingName = tree[key].get('name')
            regIndex = key
            tree[key]['object'] = 'meter'
    # Search for the substation meter and attach a recorder there.
    for key in tree:
        if tree[key].get('bustype', '').lower() == 'swing':
            swingName = tree[key].get('name')
    recOb = {
        "object": "recorder",
        "parent": swingName,
        "property":
        "measured_real_power,measured_reactive_power,measured_power",
        "file": "caliSub.csv",
        "interval": "3600"
    }
    outputRecorderKey = maxKey + 3
    tree[outputRecorderKey] = recOb
    feeder.adjustTime(tree, simLength, simLengthUnits,
                      simStartDate['Date'].strftime("%Y-%m-%d %H:%M:%S"))

    # Run Gridlabd, calculate scaling constant.
    def runPowerflowIter(tree, scadaSubPower):
        '''Runs powerflow once, then iterates.'''
        # Run initial powerflow to get power.
        print "Starting calibration."
        print "Goal of calibration: Error: %s, Iterations: <%s, trim: %s" % (
            calibrateError[0], calibrateError[1], trim)
        output = gridlabd.runInFilesystem(tree,
                                          keepFiles=True,
                                          workDir=pJoin(workDir, "gridlabD"))
        outRealPow = output["caliSub.csv"]["measured_real_power"][
            trim:simLength]
        outImagPower = output["caliSub.csv"]["measured_reactive_power"][
            trim:simLength]
        outAppPowerKw = [(x[0]**2 + x[1]**2)**0.5 / 1000
                         for x in zip(outRealPow, outImagPower)]
        lastFile = "subScada.player"
        nextFile = "subScadaCalibrated.player"
        nextPower = outAppPowerKw
        error = (sum(outRealPow) / 1000 -
                 sum(scadaSubPower)) / sum(scadaSubPower)
        iteration = 1
        print "First error:", error
        while abs(error) > calibrateError[0] and iteration < calibrateError[1]:
            # Run calibration and iterate up to 5 times.
            SCAL_CONST = sum(scadaSubPower) / sum(nextPower)
            print "Calibrating & running again... Error: %s, Iteration: %s, SCAL_CONST: %s" % (
                str(round(abs(error * 100),
                          6)), str(iteration), round(SCAL_CONST, 6))
            newPlayData = []
            with open(pJoin(pJoin(workDir, "gridlabD"), lastFile),
                      "r") as playerFile:
                for line in playerFile:
                    (key, val) = line.split(',')
                    newPlayData.append(
                        str(key) + ',' + str(float(val) * SCAL_CONST) + "\n")
            with open(pJoin(pJoin(workDir, "gridlabD"), nextFile),
                      "w") as playerFile:
                for row in newPlayData:
                    playerFile.write(row)
            tree[playerKey]["file"] = nextFile
            tree[outputRecorderKey]["file"] = "caliSubCheck.csv"
            nextOutput = gridlabd.runInFilesystem(tree,
                                                  keepFiles=True,
                                                  workDir=pJoin(
                                                      workDir, "gridlabD"))
            outRealPowIter = nextOutput["caliSubCheck.csv"][
                "measured_real_power"][trim:simLength]
            outImagPowerIter = nextOutput["caliSubCheck.csv"][
                "measured_reactive_power"][trim:simLength]
            nextAppKw = [(x[0]**2 + x[1]**2)**0.5 / 1000
                         for x in zip(outRealPowIter, outImagPowerIter)]
            lastFile = nextFile
            nextFile = "subScadaCalibrated" + str(iteration) + ".player"
            nextPower = nextAppKw
            # Compute error and iterate.
            error = (sum(outRealPowIter) / 1000 -
                     sum(scadaSubPower)) / sum(scadaSubPower)
            iteration += 1
        else:
            if iteration == 1: outRealPowIter = outRealPow
            SCAL_CONST = 1.0
        print "Calibration done: Error: %s, Iteration: %s, SCAL_CONST: %s" % (
            str(round(abs(error * 100),
                      2)), str(iteration), round(SCAL_CONST, 2))
        return outRealPow, outRealPowIter, lastFile, iteration

    outRealPow, outRealPowIter, lastFile, iteration = runPowerflowIter(
        tree, scadaSubPower[trim:simLength])
    caliPowVectors = [[
        float(element) for element in scadaSubPower[trim:simLength]
    ], [float(element) / 1000 for element in outRealPow],
                      [float(element) / 1000 for element in outRealPowIter]]
    labels = ["scadaSubPower", "initialGuess", "finalGuess"]
    colors = ['red', 'lightblue', 'blue']
    chartData = {
        "Title":
        "Substation Calibration Check (Iterated " + str(iteration + 1) + "X)",
        "fileName": "caliCheckPlot",
        "colors": colors,
        "labels": labels,
        "timeZone": simStartDate['timeZone']
    }
    # Trimming vectors to make them all the same length as the smallest vector
    minCaliPowVecLen = min(len(caliPowVectors[0]), len(caliPowVectors[1]),
                           len(caliPowVectors[2]))
    caliPowVectors[0] = caliPowVectors[0][:minCaliPowVecLen]
    caliPowVectors[1] = caliPowVectors[1][:minCaliPowVecLen]
    caliPowVectors[2] = caliPowVectors[2][:minCaliPowVecLen]
    print "Len:", len(caliPowVectors[0]), len(caliPowVectors[1]), len(
        caliPowVectors[2])
    plotLine(workDir, caliPowVectors, chartData,
             simStartDate['Date'] + dt.timedelta(hours=trim), simLengthUnits)
    # Write the final output.
    with open(pJoin(workDir, "calibratedFeeder.omd"), "w") as outJson:
        playerString = open(pJoin(pJoin(workDir, "gridlabD"), lastFile)).read()
        feederJson["attachments"][lastFile] = playerString
        feederJson["tree"] = tree
        json.dump(feederJson, outJson, indent=4)
    return
Beispiel #19
0
def omfCalibrate(workDir, feederPath, scadaPath):
	'''calibrates a feeder and saves the calibrated tree at a location'''
	with open(feederPath, "r") as jsonIn:
		feederJson = json.load(jsonIn)
		tree = feederJson.get("tree", {})
	scadaSubPower = _processScadaData(workDir,scadaPath)
	# Force FBS powerflow, because NR fails a lot.
	for key in tree:
		if tree[key].get("module","").lower() == "powerflow":
			tree[key] = {"module":"powerflow","solver_method":"FBS"}
	# Attach player.
	classOb = {"class":"player", "variable_names":["value"], "variable_types":["double"]}
	playerOb = {"object":"player", "property":"value", "name":"scadaLoads", "file":"subScada.player", "loop":"0"}
	maxKey = feeder.getMaxKey(tree)
	tree[maxKey+1] = classOb
	tree[maxKey+2] = playerOb
	# Make loads reference player.
	loadTemplate = {"object": "triplex_load",
		"power_pf_12": "0.95",
		"impedance_pf_12": "0.98",
		"power_pf_12": "0.90",
		"impedance_fraction_12": "0.7",
		"power_fraction_12": "0.3"}
	for key in tree:
		ob = tree[key]
		if ob.get("object","") == "triplex_node" and ob.get("power_12","") != "":
			newOb = dict(loadTemplate)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			oldPow = ob.get("power_12","").replace("j","d")
			pythagPower = gridlabd._strClean(oldPow)
			newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
			tree[key] = newOb
	# Search for the substation regulator and attach a recorder there.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing':
			swingName = tree[key].get('name')
	for key in tree:
		if tree[key].get('object','') == 'regulator' and tree[key].get('from','') == swingName:
			regIndex = key
			SUB_REG_NAME = tree[key]['name']
	recOb = {"object": "recorder",
		"parent": SUB_REG_NAME,
		"property": "power_in.real,power_in.imag",
		"file": "caliSub.csv",
		"interval": "900"}
	tree[maxKey + 3] = recOb
	HOURS = 100
	feeder.adjustTime(tree, HOURS, "hours", "2011-01-01")
	# Run Gridlabd.
	output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=workDir)
	# Calculate scaling constant.
	outRealPow = output["caliSub.csv"]["power_in.real"]
	outImagPower = output["caliSub.csv"]["power_in.imag"]
	outAppPowerKw = [(x[0]**2 + x[1]**2)**0.5/1000 for x in zip(outRealPow, outImagPower)]
	# HACK: ignore first time step in output and input because GLD sometimes breaks the first step.
	SCAL_CONST = sum(scadaSubPower[1:HOURS])/sum(outAppPowerKw[1:HOURS])
	# Rewrite the subScada.player file so all the power values are multiplied by the SCAL_CONSTANT.
	newPlayData = []
	with open(pJoin(workDir, "subScada.player"), "r") as playerFile:
		for line in playerFile:
			(key,val) = line.split(',')
			newPlayData.append(str(key) + ',' + str(float(val)*SCAL_CONST) + "\n")
	with open(pJoin(workDir, "subScadaCalibrated.player"), "w") as playerFile:
		for row in newPlayData:
			playerFile.write(row)
	# Test by running a glm with subScadaCalibrated.player and caliSub.csv2.
	tree[maxKey+2]["file"] = "subScadaCalibrated.player"
	tree[maxKey + 3]["file"] = "caliSubCheck.csv"
	secondOutput = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=workDir)
	plt.plot(outAppPowerKw[1:HOURS], label="initialGuess")
	plt.plot(scadaSubPower[1:HOURS], label="scadaSubPower")
	secondAppKw = [(x[0]**2 + x[1]**2)**0.5/1000
		for x in zip(secondOutput["caliSubCheck.csv"]["power_in.real"], secondOutput["caliSubCheck.csv"]["power_in.imag"])]
	plt.plot(secondAppKw[1:HOURS], label="finalGuess")
	plt.legend(loc=3)
	plt.savefig(pJoin(workDir,"caliCheckPlot.png"))
	# Write the final output.
	with open(pJoin(workDir,"calibratedFeeder.json"),"w") as outJson:
		playerString = open(pJoin(workDir,"subScadaCalibrated.player")).read()
		feederJson["attachments"]["subScadaCalibrated.player"] = playerString
		feederJson["tree"] = tree
		json.dump(feederJson, outJson, indent=4)
	return
Beispiel #20
0
def comparesol(modelDir,localTree):
	'''This reads a glm file, changes the method of powerflow and reruns'''
	print "Testing GridlabD solver."

	startTime = datetime.now()

	binaryName = "gridlabd"

	for key in localTree:
		if "solver_method" in localTree[key].keys():
			solvmeth = localTree[key]["solver_method"]
			print "success", solvmeth 
			if solvmeth == 'NR':
				localTree[key]["solver_method"] = 'FBS'
			else:
				localTree[key]["solver_method"] = 'NR'

	# feeder.attachRecorders(localTree, "Regulator", "object", "regulator")
	# feeder.attachRecorders(localTree, "CollectorVoltage", None, None)	

	# last_key = len(localTree)

	# print last_key



	for key in localTree:
		if localTree[key].get('bustype','').lower() == 'swing':
			swingIndex = key
			swingName = localTree[key].get('name')

	print swingIndex, swingName

	for key in localTree:
		if localTree[key].get('object','') == 'regulator' and localTree[key].get('from','') == swingName:
			regIndex = key
			regConfName = localTree[key]['configuration']

	print regIndex


	# Attach recorders relevant to CVR.
	recorders = [
			{'object': 'collector',
			'file': 'ZlossesTransformer.csv',
			'group': 'class=transformer',
			'limit': '0',
			'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
			{'object': 'collector',
			'file': 'ZlossesUnderground.csv',
			'group': 'class=underground_line',
			'limit': '0',
			'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
			{'object': 'collector',
			'file': 'ZlossesOverhead.csv',
			'group': 'class=overhead_line',
			'limit': '0',
			'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
			{'object': 'recorder',
			'file': 'Zregulator.csv',
			'limit': '0',
			'parent': localTree[regIndex]['name'],
			'property': 'tap_A,tap_B,tap_C,power_in.real,power_in.imag'},
			{'object': 'collector',
			'file': 'ZvoltageJiggle.csv',
			'group': 'class=triplex_meter',
			'limit': '0',
			'property': 'min(voltage_12.mag),mean(voltage_12.mag),max(voltage_12.mag),std(voltage_12.mag)'},
			{'object': 'recorder',
			'file': 'ZsubstationTop.csv',
			'limit': '0',
			'parent': localTree[swingIndex]['name'],
			'property': 'voltage_A,voltage_B,voltage_C'},
			{'object': 'recorder',
			'file': 'ZsubstationBottom.csv',
			'limit': '0',
			'parent': localTree[regIndex]['to'],
			'property': 'voltage_A,voltage_B,voltage_C'} ]
	
	biggest = 1 + max([int(k) for k in localTree.keys()])
	for index, rec in enumerate(recorders):
		localTree[biggest + index] = rec


	max_key = max([int(key) for key in localTree.keys()])
	print max_key

	regKeys = []
	accum = ""

	for key in localTree:
		if localTree[key].get("object","") == "regulator":
			accum += localTree[key].get("name","ERROR") + ","
			regKeys.append(key)

	regstr = accum[:-1]

	print regKeys
	print regstr, type(regstr)

	localTree[max_key+1] = {'object' : 'volt_var_control',
	'name' : 'volt_var_control',
	'control_method' : 'ACTIVE',
	'capacitor_delay' : '30.0',
	'regulator_delay' : '30.0',
	'desired_pf' : '0.99',
	'd_max' : '0.6',
	'd_min' : '0.1',
	'substation_link' : 'substation_transformer',
	'regulator_list' : regstr } 


	feeder.adjustTime(tree=localTree, simLength=float("8760"),
			simLengthUnits="hours", simStartDate="2012-01-01")	

	output = gridlabd.runInFilesystem(localTree,keepFiles=True,workDir=modelDir)
	os.remove(pJoin(modelDir,"PID.txt"))
	

	p = output['Zregulator.csv']['power_in.real']
	q = output['Zregulator.csv']['power_in.imag']

	xtime = {}

	for key in output:
		if '# timestamp' in output[key]:
			xtime['timeStamps'] = output[key]['# timestamp']

	#print type(xtime['timeStamps'][0])
	#print len(p)

	#xaxtick = str(xtime['timeStamps'])

	# plt.plot(range(8760),p)
	# plt.show()

	# print "p=" , p
	# print "q=" , q
	print "DONE RUNNING", modelDir